Commit 7fa1be74 authored by Matthieu Boutier's avatar Matthieu Boutier

kernel_netlink: take IPV6_SUBTREES into account.

The linux kernel should be able to deal correctly with source-sensitive ipv6
route entries since 3.11 (when it is configured with IPV6_SUBTREES).  This patch
modify the kernel so that ipv6 route entries sent into the kernel are not pushed
in a different routing table.

The behavior for v4 doesn't change.
parent 7b413d28
......@@ -80,6 +80,12 @@ THE SOFTWARE.
#endif
#endif
#ifdef IPV6_SUBTREES
#define has_ipv6_subtrees 1
#else
#define has_ipv6_subtrees 0
#endif
extern struct timeval now;
extern int debug;
extern time_t reboot_time;
......
......@@ -1013,6 +1013,8 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
rtm = NLMSG_DATA(&buf.nh);
rtm->rtm_family = ipv4 ? AF_INET : AF_INET6;
rtm->rtm_dst_len = ipv4 ? plen - 96 : plen;
if(has_ipv6_subtrees && src && !ipv4)
rtm->rtm_src_len = src_plen;
rtm->rtm_table = table;
rtm->rtm_scope = RT_SCOPE_UNIVERSE;
if(metric < KERNEL_INFINITY)
......@@ -1034,6 +1036,12 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
rta->rta_len = RTA_LENGTH(sizeof(struct in6_addr));
rta->rta_type = RTA_DST;
memcpy(RTA_DATA(rta), dest, sizeof(struct in6_addr));
if(has_ipv6_subtrees && src) {
rta = RTA_NEXT(rta, len);
rta->rta_len = RTA_LENGTH(sizeof(struct in6_addr));
rta->rta_type = RTA_SRC;
memcpy(RTA_DATA(rta), src, sizeof(struct in6_addr));
}
}
rta = RTA_NEXT(rta, len);
......@@ -1073,19 +1081,16 @@ parse_kernel_route_rta(struct rtmsg *rtm, int len, struct kernel_route *route)
struct rtattr *rta= RTM_RTA(rtm);;
len -= NLMSG_ALIGN(sizeof(*rtm));
memset(&route->prefix, 0, sizeof(struct in6_addr));
memset(&route->gw, 0, sizeof(struct in6_addr));
route->plen = rtm->rtm_dst_len;
memset(route, 0, sizeof(struct kernel_route));
if(rtm->rtm_family == AF_INET) {
/* if RTA_DST is not a TLV, that's a default destination */
const unsigned char zeroes[4] = {0, 0, 0, 0};
v4tov6(route->prefix, zeroes);
route->plen += 96;
route->plen = 96;
}
route->metric = 0;
route->ifindex = 0;
route->proto = rtm->rtm_protocol;
#define GET_PLEN(p) (rtm->rtm_family == AF_INET) ? p + 96 : p
#define COPY_ADDR(d, s) \
do { \
if(rtm->rtm_family == AF_INET6) \
......@@ -1099,8 +1104,13 @@ parse_kernel_route_rta(struct rtmsg *rtm, int len, struct kernel_route *route)
while(RTA_OK(rta, len)) {
switch(rta->rta_type) {
case RTA_DST:
route->plen = GET_PLEN(rtm->rtm_dst_len);
COPY_ADDR(route->prefix, RTA_DATA(rta));
break;
case RTA_SRC:
route->src_plen = GET_PLEN(rtm->rtm_src_len);
COPY_ADDR(route->src_prefix, RTA_DATA(rta));
break;
case RTA_GATEWAY:
COPY_ADDR(route->gw, RTA_DATA(rta));
break;
......@@ -1121,6 +1131,7 @@ parse_kernel_route_rta(struct rtmsg *rtm, int len, struct kernel_route *route)
rta = RTA_NEXT(rta, len);
}
#undef COPY_ADDR
#undef GET_PLEN
int i;
for(i = 0; i < import_table_count; i++)
......@@ -1135,6 +1146,7 @@ print_kernel_route(int add, int protocol, int type,
{
char ifname[IFNAMSIZ];
char addr_prefix[INET6_ADDRSTRLEN];
char src_addr_prefix[INET6_ADDRSTRLEN];
char addr_gw[INET6_ADDRSTRLEN];
if(!inet_ntop(AF_INET6, route->prefix,
......@@ -1145,6 +1157,21 @@ print_kernel_route(int add, int protocol, int type,
return;
}
if(route->src_plen >= 0) {
if(!inet_ntop(AF_INET6, route->src_prefix,
src_addr_prefix, sizeof(src_addr_prefix))) {
kdebugf("Couldn't format kernel route for printing.");
return;
}
kdebugf("%s kernel route: dest: %s/%d gw: %s metric: %d if: %s "
"(proto: %d, type: %d, from: %s/%d)",
add == RTM_NEWROUTE ? "Add" : "Delete",
addr_prefix, route->plen, addr_gw, route->metric, ifname,
protocol, type, src_addr_prefix, route->src_plen);
return;
}
kdebugf("%s kernel route: dest: %s/%d gw: %s metric: %d if: %s "
"(proto: %d, type: %d)",
add == RTM_NEWROUTE ? "Add" : "Delete",
......@@ -1189,9 +1216,6 @@ filter_kernel_routes(struct nlmsghdr *nh, void *data)
if(rtm->rtm_protocol == RTPROT_BABEL)
return 0;
if(rtm->rtm_src_len != 0)
return 0;
/* Ignore cached routes, advertised by some kernels (linux 3.x). */
if(rtm->rtm_flags & RTM_F_CLONED)
return 0;
......@@ -1205,7 +1229,8 @@ filter_kernel_routes(struct nlmsghdr *nh, void *data)
if(rc < 0)
return 0;
if(martian_prefix(current_route->prefix, current_route->plen))
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. */
......@@ -1778,6 +1803,9 @@ find_table(const unsigned char *src, unsigned short src_plen)
struct kernel_table *kt = NULL;
int i, new_i;
if(has_ipv6_subtrees && (src_plen < 96 || !v4mapped(src)))
return export_table;
if(src_plen == 0)
return export_table;
......
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