Commit d2838459 authored by Matthieu Boutier's avatar Matthieu Boutier Committed by Juliusz Chroboczek

Kernel-side implementation of source-sensitive routing.

parent b221c564
...@@ -28,6 +28,8 @@ THE SOFTWARE. ...@@ -28,6 +28,8 @@ THE SOFTWARE.
struct kernel_route { struct kernel_route {
unsigned char prefix[16]; unsigned char prefix[16];
int plen; int plen;
unsigned char src_prefix[16];
int src_plen; /* no source prefix <=> src_plen == 0 */
int metric; int metric;
unsigned int ifindex; unsigned int ifindex;
int proto; int proto;
...@@ -60,6 +62,7 @@ int kernel_interface_mtu(const char *ifname, int ifindex); ...@@ -60,6 +62,7 @@ int kernel_interface_mtu(const char *ifname, int ifindex);
int kernel_interface_wireless(const char *ifname, int ifindex); int kernel_interface_wireless(const char *ifname, int ifindex);
int kernel_interface_channel(const char *ifname, int ifindex); int kernel_interface_channel(const char *ifname, int ifindex);
int kernel_route(int operation, const unsigned char *dest, unsigned short plen, int kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *src, unsigned short src_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);
......
...@@ -554,6 +554,7 @@ kernel_setup(int setup) ...@@ -554,6 +554,7 @@ kernel_setup(int setup)
return 1; return 1;
} else { } else {
release_tables();
close(dgram_socket); close(dgram_socket);
dgram_socket = -1; dgram_socket = -1;
...@@ -912,16 +913,16 @@ kernel_interface_channel(const char *ifname, int ifindex) ...@@ -912,16 +913,16 @@ kernel_interface_channel(const char *ifname, int ifindex)
int int
kernel_route(int operation, const unsigned char *dest, unsigned short plen, kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *src, unsigned short src_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)
{ {
union { char raw[1024]; struct nlmsghdr nh; } buf; union { char raw[1024]; struct nlmsghdr nh; } buf;
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; int rc, ipv4, table;
if(!nl_setup) { if(!nl_setup) {
fprintf(stderr,"kernel_route: netlink not initialized.\n"); fprintf(stderr,"kernel_route: netlink not initialized.\n");
...@@ -941,14 +942,19 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -941,14 +942,19 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
} }
} }
table = find_table(src, src_plen);
if(table < 0)
return -1;
/* Check that the protocol family is consistent. */ /* Check that the protocol family is consistent. */
if(plen >= 96 && v4mapped(dest)) { if(plen >= 96 && v4mapped(dest)) {
if(!v4mapped(gate)) { if(!v4mapped(gate) ||
(src_plen > 0 && (!v4mapped(src) || src_plen < 96))) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
} else { } else {
if(v4mapped(gate)) { if(v4mapped(gate)|| (src_plen > 0 && v4mapped(src))) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
...@@ -967,9 +973,11 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -967,9 +973,11 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
stick with the naive approach, and hope that the window is stick with the naive approach, and hope that the window is
small enough to be negligible. */ small enough to be negligible. */
kernel_route(ROUTE_FLUSH, dest, plen, kernel_route(ROUTE_FLUSH, dest, plen,
src, src_plen,
gate, ifindex, metric, gate, ifindex, metric,
NULL, 0, 0); NULL, 0, 0);
rc = kernel_route(ROUTE_ADD, dest, plen, rc = kernel_route(ROUTE_ADD, dest, plen,
src, src_plen,
newgate, newifindex, newmetric, newgate, newifindex, newmetric,
NULL, 0, 0); NULL, 0, 0);
if(rc < 0) { if(rc < 0) {
...@@ -981,11 +989,12 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -981,11 +989,12 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
return rc; return rc;
} }
kdebugf("kernel_route: %s %s/%d metric %d dev %d nexthop %s\n", kdebugf("kernel_route: %s %s from %s "
operation == ROUTE_ADD ? "add" : "table %d metric %d dev %d nexthop %s\n",
operation == ROUTE_FLUSH ? "flush" : "???", operation == ROUTE_ADD ? "add" :
format_address(dest), plen, metric, ifindex, operation == ROUTE_FLUSH ? "flush" : "???",
format_address(gate)); format_prefix(dest, plen), format_prefix(src, src_plen),
table, metric, ifindex, format_address(gate));
/* Unreachable default routes cause all sort of weird interactions; /* Unreachable default routes cause all sort of weird interactions;
ignore them. */ ignore them. */
...@@ -1004,7 +1013,7 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -1004,7 +1013,7 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
rtm = NLMSG_DATA(&buf.nh); rtm = NLMSG_DATA(&buf.nh);
rtm->rtm_family = ipv4 ? AF_INET : AF_INET6; rtm->rtm_family = ipv4 ? AF_INET : AF_INET6;
rtm->rtm_dst_len = ipv4 ? plen - 96 : plen; rtm->rtm_dst_len = ipv4 ? plen - 96 : plen;
rtm->rtm_table = export_table; rtm->rtm_table = table;
rtm->rtm_scope = RT_SCOPE_UNIVERSE; rtm->rtm_scope = RT_SCOPE_UNIVERSE;
if(metric < KERNEL_INFINITY) if(metric < KERNEL_INFINITY)
rtm->rtm_type = RTN_UNICAST; rtm->rtm_type = RTN_UNICAST;
......
...@@ -29,8 +29,6 @@ THE SOFTWARE. ...@@ -29,8 +29,6 @@ THE SOFTWARE.
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <time.h> #include <time.h>
#include <strings.h> #include <strings.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/icmp6.h> #include <netinet/icmp6.h>
...@@ -53,7 +51,6 @@ THE SOFTWARE. ...@@ -53,7 +51,6 @@ THE SOFTWARE.
static int get_sdl(struct sockaddr_dl *sdl, char *ifname); static int get_sdl(struct sockaddr_dl *sdl, char *ifname);
static const unsigned char v4prefix[16] = static const unsigned char v4prefix[16] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
...@@ -387,6 +384,7 @@ kernel_interface_channel(const char *ifname, int ifindex) ...@@ -387,6 +384,7 @@ kernel_interface_channel(const char *ifname, int ifindex)
int int
kernel_route(int operation, const unsigned char *dest, unsigned short plen, kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *src, unsigned short src_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)
...@@ -427,9 +425,11 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -427,9 +425,11 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
/* Avoid atomic route changes that is buggy on OS X. */ /* Avoid atomic route changes that is buggy on OS X. */
kernel_route(ROUTE_FLUSH, dest, plen, kernel_route(ROUTE_FLUSH, dest, plen,
src, src_plen,
gate, ifindex, metric, gate, ifindex, metric,
NULL, 0, 0); NULL, 0, 0);
return kernel_route(ROUTE_ADD, dest, plen, return kernel_route(ROUTE_ADD, dest, plen,
src, src_plen,
newgate, newifindex, newmetric, newgate, newifindex, newmetric,
NULL, 0, 0); NULL, 0, 0);
...@@ -668,7 +668,7 @@ kernel_routes(struct kernel_route *routes, int maxroutes) ...@@ -668,7 +668,7 @@ kernel_routes(struct kernel_route *routes, int maxroutes)
size_t len; size_t len;
struct rt_msghdr *rtm; struct rt_msghdr *rtm;
int rc, i; int rc, i;
mib[0] = CTL_NET; mib[0] = CTL_NET;
mib[1] = PF_ROUTE; mib[1] = PF_ROUTE;
mib[2] = 0; mib[2] = 0;
......
...@@ -416,6 +416,7 @@ install_route(struct babel_route *route) ...@@ -416,6 +416,7 @@ install_route(struct babel_route *route)
} }
rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen, rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen,
zeroes, 0,
route->nexthop, route->nexthop,
route->neigh->ifp->ifindex, route->neigh->ifp->ifindex,
metric_to_kernel(route_metric(route)), NULL, 0, 0); metric_to_kernel(route_metric(route)), NULL, 0, 0);
...@@ -440,6 +441,7 @@ uninstall_route(struct babel_route *route) ...@@ -440,6 +441,7 @@ uninstall_route(struct babel_route *route)
return; return;
rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen, rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen,
zeroes, 0,
route->nexthop, route->nexthop,
route->neigh->ifp->ifindex, route->neigh->ifp->ifindex,
metric_to_kernel(route_metric(route)), NULL, 0, 0); metric_to_kernel(route_metric(route)), NULL, 0, 0);
...@@ -472,6 +474,7 @@ switch_routes(struct babel_route *old, struct babel_route *new) ...@@ -472,6 +474,7 @@ switch_routes(struct babel_route *old, struct babel_route *new)
"(this shouldn't happen)."); "(this shouldn't happen).");
rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen, rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen,
zeroes, 0,
old->nexthop, old->neigh->ifp->ifindex, old->nexthop, old->neigh->ifp->ifindex,
metric_to_kernel(route_metric(old)), metric_to_kernel(route_metric(old)),
new->nexthop, new->neigh->ifp->ifindex, new->nexthop, new->neigh->ifp->ifindex,
...@@ -502,6 +505,7 @@ change_route_metric(struct babel_route *route, ...@@ -502,6 +505,7 @@ change_route_metric(struct babel_route *route,
if(route->installed && old != new) { if(route->installed && old != new) {
int rc; int rc;
rc = kernel_route(ROUTE_MODIFY, route->src->prefix, route->src->plen, rc = kernel_route(ROUTE_MODIFY, route->src->prefix, route->src->plen,
zeroes, 0,
route->nexthop, route->neigh->ifp->ifindex, route->nexthop, route->neigh->ifp->ifindex,
old, old,
route->nexthop, route->neigh->ifp->ifindex, route->nexthop, route->neigh->ifp->ifindex,
......
...@@ -170,7 +170,7 @@ check_xroutes(int send_updates) ...@@ -170,7 +170,7 @@ check_xroutes(int send_updates)
debugf("\nChecking kernel routes.\n"); debugf("\nChecking kernel routes.\n");
again: again:
routes = malloc(maxroutes * sizeof(struct kernel_route)); routes = calloc(maxroutes, sizeof(struct kernel_route));
if(routes == NULL) if(routes == NULL)
return -1; return -1;
......
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