Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[IPV6] FIB6RULE: Find source address during looking up route.

When looking up route for destination with rules with
source address restrictions, we may need to find a source
address for the traffic if not given.

Based on patch from Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

YOSHIFUJI Hideaki and committed by
David S. Miller
29f6af77 ea2f10a3

+38 -7
+7 -4
include/linux/fib_rules.h
··· 5 5 #include <linux/rtnetlink.h> 6 6 7 7 /* rule is permanent, and cannot be deleted */ 8 - #define FIB_RULE_PERMANENT 1 9 - #define FIB_RULE_INVERT 2 10 - #define FIB_RULE_UNRESOLVED 4 11 - #define FIB_RULE_DEV_DETACHED 8 8 + #define FIB_RULE_PERMANENT 0x00000001 9 + #define FIB_RULE_INVERT 0x00000002 10 + #define FIB_RULE_UNRESOLVED 0x00000004 11 + #define FIB_RULE_DEV_DETACHED 0x00000008 12 + 13 + /* try to find source address in routing lookups */ 14 + #define FIB_RULE_FIND_SADDR 0x00010000 12 15 13 16 struct fib_rule_hdr 14 17 {
+31 -3
net/ipv6/fib6_rules.c
··· 17 17 18 18 #include <net/fib_rules.h> 19 19 #include <net/ipv6.h> 20 + #include <net/addrconf.h> 20 21 #include <net/ip6_route.h> 21 22 #include <net/netlink.h> 22 23 ··· 96 95 if (table) 97 96 rt = lookup(table, flp, flags); 98 97 99 - if (rt != &ip6_null_entry) 98 + if (rt != &ip6_null_entry) { 99 + struct fib6_rule *r = (struct fib6_rule *)rule; 100 + 101 + /* 102 + * If we need to find a source address for this traffic, 103 + * we check the result if it meets requirement of the rule. 104 + */ 105 + if ((rule->flags & FIB_RULE_FIND_SADDR) && 106 + r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) { 107 + struct in6_addr saddr; 108 + if (ipv6_get_saddr(&rt->u.dst, &flp->fl6_dst, 109 + &saddr)) 110 + goto again; 111 + if (!ipv6_prefix_equal(&saddr, &r->src.addr, 112 + r->src.plen)) 113 + goto again; 114 + ipv6_addr_copy(&flp->fl6_src, &saddr); 115 + } 100 116 goto out; 117 + } 118 + again: 101 119 dst_release(&rt->u.dst); 102 120 rt = NULL; 103 121 goto out; ··· 137 117 !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen)) 138 118 return 0; 139 119 120 + /* 121 + * If FIB_RULE_FIND_SADDR is set and we do not have a 122 + * source address for the traffic, we defer check for 123 + * source address. 124 + */ 140 125 if (r->src.plen) { 141 - if (!(flags & RT6_LOOKUP_F_HAS_SADDR) || 142 - !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen)) 126 + if (flags & RT6_LOOKUP_F_HAS_SADDR) { 127 + if (!ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, 128 + r->src.plen)) 129 + return 0; 130 + } else if (!(r->common.flags & FIB_RULE_FIND_SADDR)) 143 131 return 0; 144 132 } 145 133