Hi folks The attached patch implements source ip selection in routes for ipv6. There a some issues left, which I can't solve: - the route add code for ipv4 includes a check for loopback ips or so, I don't understand them and therefor can't convert it for ipv6. - there is no check if the ip is local. Bastian Please cc. -- Captain's Log, star date 21:34.5...
diff -ur linux-2.6.5.orig/include/linux/ipv6_route.h linux-2.6.5/include/linux/ipv6_route.h --- linux-2.6.5.orig/include/linux/ipv6_route.h 2004-03-11 03:55:23.000000000 +0100 +++ linux-2.6.5/include/linux/ipv6_route.h 2004-04-16 19:17:26.000000000 +0200 @@ -30,6 +30,7 @@ struct in6_rtmsg { struct in6_addr rtmsg_dst; struct in6_addr rtmsg_src; + struct in6_addr rtmsg_prefsrc; struct in6_addr rtmsg_gateway; __u32 rtmsg_type; __u16 rtmsg_dst_len; diff -ur linux-2.6.5.orig/include/net/ip6_fib.h linux-2.6.5/include/net/ip6_fib.h --- linux-2.6.5.orig/include/net/ip6_fib.h 2004-03-11 03:55:37.000000000 +0100 +++ linux-2.6.5/include/net/ip6_fib.h 2004-04-16 19:53:08.000000000 +0200 @@ -71,6 +71,7 @@ struct rt6key rt6i_dst; struct rt6key rt6i_src; + struct rt6key rt6i_prefsrc; u8 rt6i_protocol; }; diff -ur linux-2.6.5.orig/net/ipv6/ip6_output.c linux-2.6.5/net/ipv6/ip6_output.c --- linux-2.6.5.orig/net/ipv6/ip6_output.c 2004-04-16 22:25:17.000000000 +0200 +++ linux-2.6.5/net/ipv6/ip6_output.c 2004-04-16 21:04:04.000000000 +0200 @@ -768,8 +768,13 @@ if ((err = (*dst)->error)) goto out_err_release; if (ipv6_addr_any(&fl->fl6_src)) { - err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); + struct rt6_info *rt = (struct rt6_info*)*dst; + /* XXX needs to check */ + if (rt->rt6i_prefsrc.plen) + ipv6_addr_copy(&fl->fl6_src, &rt->rt6i_prefsrc.addr); + else + err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); if (err) { #if IP6_DEBUG >= 2 diff -ur linux-2.6.5.orig/net/ipv6/route.c linux-2.6.5/net/ipv6/route.c --- linux-2.6.5.orig/net/ipv6/route.c 2004-03-11 03:55:37.000000000 +0100 +++ linux-2.6.5/net/ipv6/route.c 2004-04-16 21:40:42.000000000 +0200 @@ -702,7 +708,7 @@ struct rtattr **rta; struct rt6_info *rt; struct net_device *dev = NULL; - int addr_type; + int addr_type, i, j; rta = (struct rtattr **) _rtattr; @@ -758,6 +764,17 @@ rt->rt6i_metric = rtmsg->rtmsg_metric; + /* XXX is there another way to compare ipv6 addresses? */ + for (i = 0, j = 0; i < 4; i++) + if (rtmsg->rtmsg_prefsrc.s6_addr32[i] != in6addr_any.s6_addr32[i]) + j = 1; + if (j) { + memcpy(&rt->rt6i_prefsrc.addr, &rtmsg->rtmsg_prefsrc, 16); + rt->rt6i_prefsrc.plen = 128; + } + else + rt->rt6i_prefsrc.plen = 0; + /* We cannot add true routes via loopback here, they would result in kernel looping; promote them to reject routes */ @@ -837,6 +854,16 @@ rt->rt6i_flags = rtmsg->rtmsg_flags; + /* XXX: I don't understand this check */ +#if 0 + if (rt->rt6i_prefsrc) { + if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || + memcmp(&fi->fib_prefsrc, rta->rta_dst, 4)) + if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) + goto err_inval; + } +#endif + install_route: if (rta && rta[RTA_METRICS-1]) { int attrlen = RTA_PAYLOAD(rta[RTA_METRICS-1]); @@ -1147,6 +1174,7 @@ #ifdef CONFIG_IPV6_SUBTREES memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); #endif + memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key)); } return rt; } @@ -1431,6 +1459,9 @@ return -EINVAL; memcpy(&rtmsg->rtmsg_metric, RTA_DATA(rta[RTA_PRIORITY-1]), 4); } + if (rta[RTA_PREFSRC-1]) { + memcpy(&rtmsg->rtmsg_prefsrc, RTA_DATA(rta[RTA_PREFSRC-1]), 16); + } return 0; } @@ -1523,11 +1554,9 @@ #endif if (iif) RTA_PUT(skb, RTA_IIF, 4, &iif); - else if (dst) { - struct in6_addr saddr_buf; - if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) - RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); - } + if (rt->rt6i_prefsrc.plen) + RTA_PUT(skb, RTA_PREFSRC, 16, &rt->rt6i_prefsrc); + if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) goto rtattr_failure; if (rt->u.dst.neighbour)
Attachment:
signature.asc
Description: Digital signature