Commit 58dbd2f4 by Matthieu Boutier Committed by Juliusz Chroboczek

Refactor netlink: routes import.

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