aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/fib_rules.h11
-rw-r--r--net/ipv6/fib6_rules.c34
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
13struct fib_rule_hdr 16struct 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 }
119again:
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