Commit 58dbd2f4 authored by Matthieu Boutier's avatar Matthieu Boutier Committed by Juliusz Chroboczek

Refactor netlink: routes import.

parent d4273aa1
...@@ -94,11 +94,17 @@ struct timeval check_neighbours_timeout, check_interfaces_timeout; ...@@ -94,11 +94,17 @@ struct timeval check_neighbours_timeout, check_interfaces_timeout;
static volatile sig_atomic_t exiting = 0, dumping = 0, reopening = 0; static volatile sig_atomic_t exiting = 0, dumping = 0, reopening = 0;
static int accept_local_connections(fd_set *readfds); static int accept_local_connections(fd_set *readfds);
static int kernel_routes_callback(int changed, void *closure);
static void init_signals(void); static void init_signals(void);
static void dump_tables(FILE *out); static void dump_tables(FILE *out);
static int reopen_logfile(void); static int reopen_logfile(void);
static int
kernel_route_notify(struct kernel_route *route, void *closure)
{
kernel_routes_changed = 1;
return -1;
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
...@@ -588,8 +594,11 @@ main(int argc, char **argv) ...@@ -588,8 +594,11 @@ main(int argc, char **argv)
if(exiting) if(exiting)
break; break;
if(kernel_socket >= 0 && FD_ISSET(kernel_socket, &readfds)) if(kernel_socket >= 0 && FD_ISSET(kernel_socket, &readfds)) {
kernel_callback(kernel_routes_callback, NULL); struct kernel_filter filter = {0};
filter.route = kernel_route_notify;
kernel_callback(&filter);
}
if(FD_ISSET(protocol_socket, &readfds)) { if(FD_ISSET(protocol_socket, &readfds)) {
rc = babel_recv(protocol_socket, rc = babel_recv(protocol_socket,
...@@ -1108,17 +1117,3 @@ reopen_logfile() ...@@ -1108,17 +1117,3 @@ reopen_logfile()
return 1; return 1;
} }
static int
kernel_routes_callback(int changed, void *closure)
{
if(changed & CHANGE_LINK)
kernel_link_changed = 1;
if(changed & CHANGE_ADDR)
kernel_addr_changed = 1;
if(changed & CHANGE_ROUTE)
kernel_routes_changed = 1;
if(changed & CHANGE_RULE)
kernel_rules_changed = 1;
return 1;
}
...@@ -36,6 +36,12 @@ struct kernel_route { ...@@ -36,6 +36,12 @@ struct kernel_route {
unsigned char gw[16]; unsigned char gw[16];
}; };
struct kernel_filter {
/* return -1 to interrupt search. */
int (*route)(struct kernel_route *, void *);
void *route_closure;
};
#define ROUTE_FLUSH 0 #define ROUTE_FLUSH 0
#define ROUTE_ADD 1 #define ROUTE_ADD 1
#define ROUTE_MODIFY 2 #define ROUTE_MODIFY 2
...@@ -71,8 +77,8 @@ int kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -71,8 +77,8 @@ int kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *gate, int ifindex, unsigned int metric,
const unsigned char *newgate, int newifindex, const unsigned char *newgate, int newifindex,
unsigned int newmetric); unsigned int newmetric);
int kernel_routes(struct kernel_route *routes, int maxroutes); int kernel_dump(int operation, struct kernel_filter *filter);
int kernel_callback(int (*fn)(int, void*), void *closure); int kernel_callback(struct kernel_filter *filter);
int kernel_addresses(char *ifname, int ifindex, int ll, int kernel_addresses(char *ifname, int ifindex, int ll,
struct kernel_route *routes, int maxroutes); struct kernel_route *routes, int maxroutes);
int if_eui64(char *ifname, int ifindex, unsigned char *eui); int if_eui64(char *ifname, int ifindex, unsigned char *eui);
......
...@@ -89,6 +89,7 @@ static int dgram_socket = -1; ...@@ -89,6 +89,7 @@ static int dgram_socket = -1;
#define NO_ARPHRD #define NO_ARPHRD
#endif #endif
static int filter_netlink(struct nlmsghdr *nh, struct kernel_filter *filter);
static int find_table(const unsigned char *src, unsigned short src_plen); static int find_table(const unsigned char *src, unsigned short src_plen);
static void release_tables(void); static void release_tables(void);
...@@ -899,7 +900,7 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -899,7 +900,7 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
struct rtmsg *rtm; struct rtmsg *rtm;
struct rtattr *rta; struct rtattr *rta;
int len = sizeof(buf.raw); int len = sizeof(buf.raw);
int rc, ipv4, table, use_src = 0; int rc, ipv4, use_src = 0;
if(!nl_setup) { if(!nl_setup) {
fprintf(stderr,"kernel_route: netlink not initialized.\n"); fprintf(stderr,"kernel_route: netlink not initialized.\n");
...@@ -1170,34 +1171,15 @@ print_kernel_route(int add, int protocol, int type, ...@@ -1170,34 +1171,15 @@ print_kernel_route(int add, int protocol, int type,
} }
static int static int
filter_kernel_routes(struct nlmsghdr *nh, void *data) filter_kernel_routes(struct nlmsghdr *nh, struct kernel_route *route)
{ {
int rc; int rc, len;
struct kernel_route *current_route;
struct kernel_route route;
int maxroutes = 0;
struct kernel_route *routes = NULL;
int *found = NULL;
int len;
struct rtmsg *rtm; struct rtmsg *rtm;
if(data) {
void **args = (void**)data;
maxroutes = *(int*)args[0];
routes = (struct kernel_route *)args[1];
found = (int*)args[2];
}
len = nh->nlmsg_len; len = nh->nlmsg_len;
if(data && *found >= maxroutes)
return 0;
if(nh->nlmsg_type != RTM_NEWROUTE && if(nh->nlmsg_type != RTM_NEWROUTE &&
(data || nh->nlmsg_type != RTM_DELROUTE)) nh->nlmsg_type != RTM_DELROUTE)
return 0; return 0;
rtm = (struct rtmsg*)NLMSG_DATA(nh); rtm = (struct rtmsg*)NLMSG_DATA(nh);
...@@ -1210,50 +1192,35 @@ filter_kernel_routes(struct nlmsghdr *nh, void *data) ...@@ -1210,50 +1192,35 @@ filter_kernel_routes(struct nlmsghdr *nh, void *data)
if(rtm->rtm_flags & RTM_F_CLONED) if(rtm->rtm_flags & RTM_F_CLONED)
return 0; return 0;
if(data) rc = parse_kernel_route_rta(rtm, len, route);
current_route = &routes[*found];
else
current_route = &route;
rc = parse_kernel_route_rta(rtm, len, current_route);
if(rc < 0) if(rc < 0)
return 0; return 0;
if(martian_prefix(current_route->prefix, current_route->plen) ||
martian_prefix(current_route->src_prefix, current_route->src_plen))
return 0;
/* Ignore default unreachable routes; no idea where they come from. */ /* Ignore default unreachable routes; no idea where they come from. */
if(current_route->plen == 0 && current_route->metric >= KERNEL_INFINITY) if(route->plen == 0 && route->metric >= KERNEL_INFINITY)
return 0; return 0;
if(debug >= 2) { if(debug >= 2) {
if(rc >= 0) { if(rc >= 0) {
print_kernel_route(nh->nlmsg_type, rtm->rtm_protocol, print_kernel_route(nh->nlmsg_type, rtm->rtm_protocol,
rtm->rtm_type, current_route); rtm->rtm_type, route);
} }
} }
if(data) *found = (*found)+1;
return 1; return 1;
} }
/* This function should not return routes installed by us. */ /* This function should not return routes installed by us. */
int int
kernel_routes(struct kernel_route *routes, int maxroutes) kernel_dump(int operation, struct kernel_filter *filter)
{ {
int i, rc; int i, rc;
int maxr = maxroutes;
int found = 0;
void *data[3] = { &maxr, routes, &found };
int families[2] = { AF_INET6, AF_INET }; int families[2] = { AF_INET6, AF_INET };
char rule_exists[SRC_TABLE_NUM] = {0};
struct rtgenmsg g; struct rtgenmsg g;
if(!nl_setup) { if(!nl_setup) {
fprintf(stderr,"kernel_routes: netlink not initialized.\n"); fprintf(stderr,"kernel_dump: netlink not initialized.\n");
errno = EIO; errno = EIO;
return -1; return -1;
} }
...@@ -1261,7 +1228,7 @@ kernel_routes(struct kernel_route *routes, int maxroutes) ...@@ -1261,7 +1228,7 @@ kernel_routes(struct kernel_route *routes, int maxroutes)
if(nl_command.sock < 0) { if(nl_command.sock < 0) {
rc = netlink_socket(&nl_command, 0); rc = netlink_socket(&nl_command, 0);
if(rc < 0) { if(rc < 0) {
perror("kernel_routes: netlink_socket()"); perror("kernel_dump: netlink_socket()");
return -1; return -1;
} }
} }
...@@ -1269,28 +1236,32 @@ kernel_routes(struct kernel_route *routes, int maxroutes) ...@@ -1269,28 +1236,32 @@ kernel_routes(struct kernel_route *routes, int maxroutes)
for(i = 0; i < 2; i++) { for(i = 0; i < 2; i++) {
memset(&g, 0, sizeof(g)); memset(&g, 0, sizeof(g));
g.rtgen_family = families[i]; g.rtgen_family = families[i];
rc = netlink_send_dump(RTM_GETROUTE, &g, sizeof(g)); if(operation & CHANGE_ROUTE) {
if(rc < 0) rc = netlink_send_dump(RTM_GETROUTE, &g, sizeof(g));
return -1; if(rc < 0)
return -1;
rc = netlink_read(&nl_command, NULL, 1,
filter_kernel_routes, (void *)data);
if(rc < 0)
return -1;
rc = netlink_send_dump(RTM_GETRULE, &g, sizeof(g)); rc = netlink_read(&nl_command, NULL, 1,
if(rc < 0) filter_netlink, (void *)filter);
return -1; if(rc < 0)
return -1;
}
rc = netlink_read(&nl_command, NULL, 1, memset(&g, 0, sizeof(g));
filter_kernel_rules, rule_exists); g.rtgen_family = families[i];
if(rc < 0) if(operation & CHANGE_RULE) {
return -1; rc = netlink_send_dump(RTM_GETRULE, &g, sizeof(g));
if(rc < 0)
return -1;
install_missing_rules(rule_exists, families[i] == AF_INET); rc = netlink_read(&nl_command, NULL, 1,
filter_kernel_rules, rule_exists);
if(rc < 0)
return -1;
}
} }
return found; return 0;
} }
static char * static char *
...@@ -1450,18 +1421,21 @@ filter_addresses(struct nlmsghdr *nh, void *data) ...@@ -1450,18 +1421,21 @@ filter_addresses(struct nlmsghdr *nh, void *data)
} }
static int static int
filter_netlink(struct nlmsghdr *nh, void *data) filter_netlink(struct nlmsghdr *nh, struct kernel_filter *filter)
{ {
int rc; int rc;
int *changed = data; int *changed = data;
union {
struct kernel_route route;
} u;
switch(nh->nlmsg_type) { switch(nh->nlmsg_type) {
case RTM_NEWROUTE: case RTM_NEWROUTE:
case RTM_DELROUTE: case RTM_DELROUTE:
rc = filter_kernel_routes(nh, NULL); if(!filter->route) break;
if(changed && rc > 0) rc = filter_kernel_routes(nh, &u.route);
*changed |= CHANGE_ROUTE; if(rc <= 0) break;
return rc; return filter->route(&u.route, filter->route_closure);
case RTM_NEWLINK: case RTM_NEWLINK:
case RTM_DELLINK: case RTM_DELLINK:
rc = filter_link(nh, NULL); rc = filter_link(nh, NULL);
...@@ -1470,7 +1444,7 @@ filter_netlink(struct nlmsghdr *nh, void *data) ...@@ -1470,7 +1444,7 @@ filter_netlink(struct nlmsghdr *nh, void *data)
return rc; return rc;
case RTM_NEWADDR: case RTM_NEWADDR:
case RTM_DELADDR: case RTM_DELADDR:
rc = filter_addresses(nh, NULL); rc = filter_addresses(nh, &kernel_addr);
if(changed && rc > 0) if(changed && rc > 0)
*changed |= CHANGE_ADDR; *changed |= CHANGE_ADDR;
return rc; return rc;
...@@ -1529,10 +1503,9 @@ kernel_addresses(char *ifname, int ifindex, int ll, ...@@ -1529,10 +1503,9 @@ kernel_addresses(char *ifname, int ifindex, int ll,
} }
int int
kernel_callback(int (*fn)(int, void*), void *closure) kernel_callback(struct kernel_filter *filter)
{ {
int rc; int rc;
int changed = 0;
kdebugf("\nReceived changes in kernel tables.\n"); kdebugf("\nReceived changes in kernel tables.\n");
...@@ -1543,16 +1516,12 @@ kernel_callback(int (*fn)(int, void*), void *closure) ...@@ -1543,16 +1516,12 @@ kernel_callback(int (*fn)(int, void*), void *closure)
return -1; return -1;
} }
} }
rc = netlink_read(&nl_listen, &nl_command, 0, filter_netlink, &changed); rc = netlink_read(&nl_listen, &nl_command, 0, filter_netlink,
(void*) filter);
if(rc < 0 && nl_listen.sock < 0) if(rc < 0 && nl_listen.sock < 0)
kernel_setup_socket(1); kernel_setup_socket(1);
/* if netlink return 0 (found something interesting) */
/* or -1 (i.e. IO error), we call... back ! */
if(rc)
return fn(changed, closure);
return 0; return 0;
} }
......
...@@ -688,13 +688,13 @@ parse_kernel_route(const struct rt_msghdr *rtm, struct kernel_route *route) ...@@ -688,13 +688,13 @@ parse_kernel_route(const struct rt_msghdr *rtm, struct kernel_route *route)
} }
int int
kernel_routes(struct kernel_route *routes, int maxroutes) kernel_dump(int operation, struct kernel_filter *filter)
{ {
int mib[6]; int mib[6];
char *buf, *p; char *buf, *p;
size_t len; size_t len;
struct rt_msghdr *rtm; struct rt_msghdr *rtm;
int rc, i; int rc;
mib[0] = CTL_NET; mib[0] = CTL_NET;
mib[1] = PF_ROUTE; mib[1] = PF_ROUTE;
...@@ -721,21 +721,23 @@ kernel_routes(struct kernel_route *routes, int maxroutes) ...@@ -721,21 +721,23 @@ kernel_routes(struct kernel_route *routes, int maxroutes)
goto fail; goto fail;
} }
i = 0; for(p = buf; p < buf + len; p += rtm->rtm_msglen) {
for(p = buf; p < buf + len && i < maxroutes; p += rtm->rtm_msglen) { struct kernel_route route;
rtm = (struct rt_msghdr*)p; rtm = (struct rt_msghdr*)p;
rc = parse_kernel_route(rtm, &routes[i]); rc = parse_kernel_route(rtm, &route);
if(rc < 0) if(rc < 0)
continue; continue;
if(debug > 2) if(debug > 2)
print_kernel_route(1,&routes[i]); print_kernel_route(1, &route);
i++; rc = filter->route(&route, filter->route_closure);
if(rc < 0)
break;
} }
free(buf); free(buf);
return i; return 0;
fail: fail:
free(buf); free(buf);
...@@ -744,7 +746,7 @@ kernel_routes(struct kernel_route *routes, int maxroutes) ...@@ -744,7 +746,7 @@ kernel_routes(struct kernel_route *routes, int maxroutes)
} }
static int static int
socket_read(int sock) socket_read(int sock, struct kernel_filter *filter)
{ {
int rc; int rc;
struct { struct {
...@@ -774,6 +776,7 @@ socket_read(int sock) ...@@ -774,6 +776,7 @@ socket_read(int sock)
rc = parse_kernel_route(&buf.rtm, &route); rc = parse_kernel_route(&buf.rtm, &route);
if(rc < 0) if(rc < 0)
return 0; return 0;
filter->route(&route, filter->route_closure);
if(debug > 2) if(debug > 2)
print_kernel_route(1,&route); print_kernel_route(1,&route);
return 1; return 1;
...@@ -843,16 +846,12 @@ kernel_addresses(char *ifname, int ifindex, int ll, ...@@ -843,16 +846,12 @@ kernel_addresses(char *ifname, int ifindex, int ll,
} }
int int
kernel_callback(int (*fn)(int, void*), void *closure) kernel_callback(struct kernel_filter *filter)
{ {
int rc;
if(kernel_socket < 0) kernel_setup_socket(1); if(kernel_socket < 0) kernel_setup_socket(1);
kdebugf("Reading kernel table modification."); kdebugf("Reading kernel table modification.");
rc = socket_read(kernel_socket); socket_read(kernel_socket, filter);
if(rc)
return fn(~0, closure);
return 0; return 0;
......
...@@ -164,6 +164,40 @@ xroute_stream_done(struct xroute_stream *stream) ...@@ -164,6 +164,40 @@ xroute_stream_done(struct xroute_stream *stream)
free(stream); free(stream);
} }
static int
filter_route(struct kernel_route *route, void *data) {
void **args = (void**)data;
int maxroutes = *(int*)args[0];
struct kernel_route *routes = (struct kernel_route *)args[1];
int *found = (int*)args[2];
if(*found >= maxroutes)
return -1;
if(martian_prefix(route->prefix, route->plen) ||
martian_prefix(route->src_prefix, route->src_plen))
return 0;
routes[*found] = *route;
++ *found;
return 0;
}
static int
kernel_routes(struct kernel_route *routes, int maxroutes)
{
int found = 0;
void *data[3] = { &maxroutes, routes, &found };
struct kernel_filter filter = {0};
filter.route = filter_route;
filter.route_closure = data;
kernel_dump(CHANGE_ROUTE, &filter);
return found;
}
int int
check_xroutes(int send_updates) check_xroutes(int send_updates)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment