Commit 87f55f5e authored by Matthieu Boutier's avatar Matthieu Boutier Committed by Juliusz Chroboczek

Refactor netlink: address import.

parent 58dbd2f4
......@@ -105,6 +105,13 @@ kernel_route_notify(struct kernel_route *route, void *closure)
return -1;
}
static int
kernel_addr_notify(struct kernel_addr *addr, void *closure)
{
kernel_addr_changed = 1;
return -1;
}
int
main(int argc, char **argv)
{
......@@ -597,6 +604,7 @@ main(int argc, char **argv)
if(kernel_socket >= 0 && FD_ISSET(kernel_socket, &readfds)) {
struct kernel_filter filter = {0};
filter.route = kernel_route_notify;
filter.addr = kernel_addr_notify;
kernel_callback(&filter);
}
......
......@@ -40,6 +40,7 @@ THE SOFTWARE.
#include "message.h"
#include "route.h"
#include "configuration.h"
#include "xroute.h"
struct interface *interfaces = NULL;
......@@ -186,7 +187,7 @@ check_link_local_addresses(struct interface *ifp)
free(ifp->ll);
ifp->numll = 0;
ifp->ll = NULL;
rc = kernel_addresses(ifp->name, ifp->ifindex, 1, ll, 32);
rc = kernel_addresses(ifp->ifindex, 1, ll, 32);
if(rc < 0) {
perror("kernel_addresses(link local)");
return -1;
......
......@@ -36,8 +36,15 @@ struct kernel_route {
unsigned char gw[16];
};
struct kernel_addr {
struct in6_addr addr;
unsigned int ifindex;
};
struct kernel_filter {
/* return -1 to interrupt search. */
int (*addr)(struct kernel_addr *, void *);
void *addr_closure;
int (*route)(struct kernel_route *, void *);
void *route_closure;
};
......@@ -79,8 +86,6 @@ int kernel_route(int operation, const unsigned char *dest, unsigned short plen,
unsigned int newmetric);
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);
int gettime(struct timeval *tv);
int read_random_bytes(void *buf, int len);
......
......@@ -1228,7 +1228,9 @@ kernel_dump(int operation, struct kernel_filter *filter)
if(nl_command.sock < 0) {
rc = netlink_socket(&nl_command, 0);
if(rc < 0) {
int save = errno;
perror("kernel_dump: netlink_socket()");
errno = save;
return -1;
}
}
......@@ -1261,6 +1263,18 @@ kernel_dump(int operation, struct kernel_filter *filter)
}
}
if(operation & CHANGE_ADDR) {
memset(&g, 0, sizeof(g));
g.rtgen_family = AF_UNSPEC;
rc = netlink_send_dump(RTM_GETADDR, &g, sizeof(g));
if(rc < 0)
return -1;
rc = netlink_read(&nl_command, NULL, 1, filter_netlink, (void*)filter);
if(rc < 0)
return -1;
}
return 0;
}
......@@ -1358,64 +1372,30 @@ filter_link(struct nlmsghdr *nh, void *data)
data[4]. */
static int
filter_addresses(struct nlmsghdr *nh, void *data)
filter_addresses(struct nlmsghdr *nh, struct kernel_addr *addr)
{
int rc;
int maxroutes = 0;
struct kernel_route *routes = NULL;
struct in6_addr addr;
int *found = NULL;
int len;
struct ifaddrmsg *ifa;
char ifname[IFNAMSIZ];
int ifindex = 0;
int ll = 0;
if(data) {
void **args = (void **)data;
maxroutes = *(int *)args[0];
routes = (struct kernel_route*)args[1];
found = (int *)args[2];
ifindex = args[3] ? *(int*)args[3] : 0;
ll = args[4] ? !!*(int*)args[4] : 0;
}
len = nh->nlmsg_len;
if(data && *found >= maxroutes)
return 0;
if(nh->nlmsg_type != RTM_NEWADDR &&
(data || nh->nlmsg_type != RTM_DELADDR))
nh->nlmsg_type != RTM_DELADDR)
return 0;
ifa = (struct ifaddrmsg *)NLMSG_DATA(nh);
len -= NLMSG_LENGTH(0);
rc = parse_addr_rta(ifa, len, &addr);
rc = parse_addr_rta(ifa, len, &addr->addr);
if(rc < 0)
return 0;
if(data && ll == !IN6_IS_ADDR_LINKLOCAL(&addr))
return 0;
if(ifindex && ifa->ifa_index != ifindex)
return 0;
addr->ifindex = ifa->ifa_index;
kdebugf("found address on interface %s(%d): %s\n",
if_indextoname(ifa->ifa_index, ifname), ifa->ifa_index,
format_address(addr.s6_addr));
if(data) {
struct kernel_route *route = &routes[*found];
memcpy(route->prefix, addr.s6_addr, 16);
route->plen = 128;
route->metric = 0;
route->ifindex = ifa->ifa_index;
route->proto = RTPROT_BABEL_LOCAL;
memset(route->gw, 0, 16);
*found = (*found)+1;
}
format_address(addr->addr.s6_addr));
return 1;
}
......@@ -1427,6 +1407,7 @@ filter_netlink(struct nlmsghdr *nh, struct kernel_filter *filter)
int *changed = data;
union {
struct kernel_route route;
struct kernel_addr addr;
} u;
switch(nh->nlmsg_type) {
......@@ -1444,10 +1425,10 @@ filter_netlink(struct nlmsghdr *nh, struct kernel_filter *filter)
return rc;
case RTM_NEWADDR:
case RTM_DELADDR:
rc = filter_addresses(nh, &kernel_addr);
if(changed && rc > 0)
*changed |= CHANGE_ADDR;
return rc;
if(!filter->addr) break;
rc = filter_addresses(nh, &u.addr);
if(rc <= 0) break;
return filter->addr(&u.addr, filter->addr_closure);
case RTM_NEWRULE:
case RTM_DELRULE:
rc = filter_kernel_rules(nh, NULL);
......@@ -1462,46 +1443,6 @@ filter_netlink(struct nlmsghdr *nh, struct kernel_filter *filter)
return 0;
}
int
kernel_addresses(char *ifname, int ifindex, int ll,
struct kernel_route *routes, int maxroutes)
{
int maxr = maxroutes;
int found = 0;
void *data[] = { &maxr, routes, &found, &ifindex, &ll, NULL };
struct rtgenmsg g;
int rc;
if(!nl_setup) {
fprintf(stderr, "kernel_addresses: netlink not initialized.\n");
errno = ENOSYS;
return -1;
}
if(nl_command.sock < 0) {
rc = netlink_socket(&nl_command, 0);
if(rc < 0) {
int save = errno;
perror("kernel_addresses: netlink_socket()");
errno = save;
return -1;
}
}
memset(&g, 0, sizeof(g));
g.rtgen_family = AF_UNSPEC;
rc = netlink_send_dump(RTM_GETADDR, &g, sizeof(g));
if(rc < 0)
return -1;
rc = netlink_read(&nl_command, NULL, 1, filter_addresses, (void*)data);
if(rc < 0)
return -1;
return found;
}
int
kernel_callback(struct kernel_filter *filter)
{
......
......@@ -687,9 +687,8 @@ parse_kernel_route(const struct rt_msghdr *rtm, struct kernel_route *route)
return 0;
}
int
kernel_dump(int operation, struct kernel_filter *filter)
{
static int
kernel_routes(struct kernel_filter *filter) {
int mib[6];
char *buf, *p;
size_t len;
......@@ -787,62 +786,57 @@ socket_read(int sock, struct kernel_filter *filter)
}
int
kernel_addresses(char *ifname, int ifindex, int ll,
struct kernel_route *routes, int maxroutes)
static int
kernel_addresses(struct kernel_filter *filter)
{
struct ifaddrs *ifa, *ifap;
int rc, i;
int rc;
rc = getifaddrs(&ifa);
if(rc < 0)
return -1;
ifap = ifa;
i = 0;
for(ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
struct kernel_addr addr;
addr.ifindex = if_nametoindex(ifap->ifa_name);
if(!addr.ifindex)
continue;
while(ifap && i < maxroutes) {
if((ifname != NULL && strcmp(ifap->ifa_name, ifname) != 0))
goto next;
if(ifap->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)ifap->ifa_addr;
if(!!ll != !!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
goto next;
memcpy(routes[i].prefix, &sin6->sin6_addr, 16);
if(ll)
memcpy(&addr.addr, &sin6->sin6_addr, 16);
if(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
/* This a perfect example of counter-productive optimisation :
KAME encodes interface index onto bytes 2 and 3, so we have
to reset those bytes to 0 before passing them to babeld. */
memset(routes[i].prefix + 2, 0, 2);
routes[i].plen = 128;
routes[i].metric = 0;
routes[i].ifindex = ifindex;
routes[i].proto = RTPROT_BABEL_LOCAL;
memset(routes[i].gw, 0, 16);
i++;
memset(((char*)&addr.addr) + 2, 0, 2);
} else if(ifap->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in*)ifap->ifa_addr;
if(ll)
goto next;
#if defined(IN_LINKLOCAL)
if(IN_LINKLOCAL(htonl(sin->sin_addr.s_addr)))
goto next;
continue;
#endif
memcpy(routes[i].prefix, v4prefix, 12);
memcpy(routes[i].prefix + 12, &sin->sin_addr, 4);
routes[i].plen = 128;
routes[i].metric = 0;
routes[i].ifindex = ifindex;
routes[i].proto = RTPROT_BABEL_LOCAL;
memset(routes[i].gw, 0, 16);
i++;
v4tov6((void*)&addr.addr, (void*) &sin->sin_addr);
} else {
continue;
}
next:
ifap = ifap->ifa_next;
filter->addr(&addr, filter->addr_closure);
}
freeifaddrs(ifa);
return i;
return 0;
}
int
kernel_dump(int operation, struct kernel_filter *filter)
{
switch(operation) {
case CHANGE_ROUTE: return kernel_routes(filter);
case CHANGE_ADDR: return kernel_addresses(filter);
default: break;
}
return -1;
}
int
......
......@@ -31,6 +31,7 @@ THE SOFTWARE.
#include "interface.h"
#include "source.h"
#include "neighbour.h"
#include "kernel.h"
#include "xroute.h"
#include "route.h"
#include "util.h"
......
......@@ -35,11 +35,11 @@ THE SOFTWARE.
#include "source.h"
#include "neighbour.h"
#include "route.h"
#include "kernel.h"
#include "xroute.h"
#include "resend.h"
#include "message.h"
#include "configuration.h"
#include "kernel.h"
unsigned char packet_header[4] = {42, 2};
......
......@@ -198,6 +198,52 @@ kernel_routes(struct kernel_route *routes, int maxroutes)
return found;
}
static int
filter_address(struct kernel_addr *addr, 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];
int ifindex = args[3] ? *(int*)args[3] : 0;
int ll = args[4] ? !!*(int*)args[4] : 0;
struct kernel_route *route = NULL;
if(*found >= maxroutes)
return 0;
if(ll == !IN6_IS_ADDR_LINKLOCAL(&addr->addr))
return 0;
if(addr->ifindex != ifindex)
return 0;
route = &routes[*found];
memcpy(route->prefix, addr->addr.s6_addr, 16);
route->plen = 128;
route->metric = 0;
route->ifindex = ifindex;
route->proto = RTPROT_BABEL_LOCAL;
memset(route->gw, 0, 16);
++ *found;
return 1;
}
int
kernel_addresses(int ifindex, int ll, struct kernel_route *routes,
int maxroutes)
{
int found = 0;
void *data[5] = { &maxroutes, routes, &found, &ifindex, &ll };
struct kernel_filter filter = {0};
filter.addr = filter_address;
filter.addr_closure = data;
kernel_dump(CHANGE_ADDR, &filter);
return found;
}
int
check_xroutes(int send_updates)
{
......@@ -215,7 +261,7 @@ check_xroutes(int send_updates)
if(routes == NULL)
return -1;
rc = kernel_addresses(NULL, 0, 0, routes, maxroutes);
rc = kernel_addresses(0, 0, routes, maxroutes);
if(rc < 0) {
perror("kernel_addresses");
numroutes = 0;
......
......@@ -42,4 +42,6 @@ int xroutes_estimate(void);
struct xroute_stream *xroute_stream();
struct xroute *xroute_stream_next(struct xroute_stream *stream);
void xroute_stream_done(struct xroute_stream *stream);
int kernel_addresses(int ifindex, int ll,
struct kernel_route *routes, int maxroutes);
int 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