diff options
-rw-r--r-- | include/linux/fib_rules.h | 11 | ||||
-rw-r--r-- | net/ipv6/fib6_rules.c | 34 |
2 files changed, 38 insertions, 7 deletions
diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index f278ba781d09..87b606b63f1e 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h | |||
@@ -5,10 +5,13 @@ | |||
5 | #include <linux/rtnetlink.h> | 5 | #include <linux/rtnetlink.h> |
6 | 6 | ||
7 | /* rule is permanent, and cannot be deleted */ | 7 | /* rule is permanent, and cannot be deleted */ |
8 | #define FIB_RULE_PERMANENT 1 | 8 | #define FIB_RULE_PERMANENT 0x00000001 |
9 | #define FIB_RULE_INVERT 2 | 9 | #define FIB_RULE_INVERT 0x00000002 |
10 | #define FIB_RULE_UNRESOLVED 4 | 10 | #define FIB_RULE_UNRESOLVED 0x00000004 |
11 | #define FIB_RULE_DEV_DETACHED 8 | 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 | struct fib_rule_hdr | 16 | struct fib_rule_hdr |
14 | { | 17 | { |
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index dd9720e700ef..fc3882c90604 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #include <net/fib_rules.h> | 18 | #include <net/fib_rules.h> |
19 | #include <net/ipv6.h> | 19 | #include <net/ipv6.h> |
20 | #include <net/addrconf.h> | ||
20 | #include <net/ip6_route.h> | 21 | #include <net/ip6_route.h> |
21 | #include <net/netlink.h> | 22 | #include <net/netlink.h> |
22 | 23 | ||
@@ -95,8 +96,27 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | |||
95 | if (table) | 96 | if (table) |
96 | rt = lookup(table, flp, flags); | 97 | rt = lookup(table, flp, flags); |
97 | 98 | ||
98 | if (rt != &ip6_null_entry) | 99 | if (rt != &ip6_null_entry) { |
100 | struct fib6_rule *r = (struct fib6_rule *)rule; | ||
101 | |||
102 | /* | ||
103 | * If we need to find a source address for this traffic, | ||
104 | * we check the result if it meets requirement of the rule. | ||
105 | */ | ||
106 | if ((rule->flags & FIB_RULE_FIND_SADDR) && | ||
107 | r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) { | ||
108 | struct in6_addr saddr; | ||
109 | if (ipv6_get_saddr(&rt->u.dst, &flp->fl6_dst, | ||
110 | &saddr)) | ||
111 | goto again; | ||
112 | if (!ipv6_prefix_equal(&saddr, &r->src.addr, | ||
113 | r->src.plen)) | ||
114 | goto again; | ||
115 | ipv6_addr_copy(&flp->fl6_src, &saddr); | ||
116 | } | ||
99 | goto out; | 117 | goto out; |
118 | } | ||
119 | again: | ||
100 | dst_release(&rt->u.dst); | 120 | dst_release(&rt->u.dst); |
101 | rt = NULL; | 121 | rt = NULL; |
102 | goto out; | 122 | goto out; |
@@ -117,9 +137,17 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | |||
117 | !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen)) | 137 | !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen)) |
118 | return 0; | 138 | return 0; |
119 | 139 | ||
140 | /* | ||
141 | * If FIB_RULE_FIND_SADDR is set and we do not have a | ||
142 | * source address for the traffic, we defer check for | ||
143 | * source address. | ||
144 | */ | ||
120 | if (r->src.plen) { | 145 | if (r->src.plen) { |
121 | if (!(flags & RT6_LOOKUP_F_HAS_SADDR) || | 146 | if (flags & RT6_LOOKUP_F_HAS_SADDR) { |
122 | !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen)) | 147 | if (!ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, |
148 | r->src.plen)) | ||
149 | return 0; | ||
150 | } else if (!(r->common.flags & FIB_RULE_FIND_SADDR)) | ||
123 | return 0; | 151 | return 0; |
124 | } | 152 | } |
125 | 153 | ||