aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/fib6_rules.c
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2018-05-09 23:34:23 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-05-10 18:10:56 -0400
commit138118ec96cbfc303c1d7cc05fbb2caf8382c95b (patch)
treef047e24bb0444ca0f79fdbc802317f34e13533b6 /net/ipv6/fib6_rules.c
parentcc065a9eb96f7f2a29a04ca49331a9ccb1cfcfa2 (diff)
net/ipv6: Add fib6_lookup
Add IPv6 equivalent to fib_lookup. Does a fib lookup, including rules, but returns a FIB entry, fib6_info, rather than a dst based rt6_info. fib6_lookup is any where from 140% (MULTIPLE_TABLES config disabled) to 60% faster than any of the dst based lookup methods (without custom rules) and 25% faster with custom rules (e.g., l3mdev rule). Since the lookup function has a completely different signature, fib6_rule_action is split into 2 paths: the existing one is renamed __fib6_rule_action and a new one for the fib6_info path is added. fib6_rule_action decides which to call based on the lookup_ptr. If it is fib6_table_lookup then the new path is taken. Caller must hold rcu lock as no reference is taken on the returned fib entry. Signed-off-by: David Ahern <dsahern@gmail.com> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'net/ipv6/fib6_rules.c')
-rw-r--r--net/ipv6/fib6_rules.c86
1 files changed, 84 insertions, 2 deletions
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index d040c4bff3a0..f590446595d8 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -60,6 +60,39 @@ unsigned int fib6_rules_seq_read(struct net *net)
60 return fib_rules_seq_read(net, AF_INET6); 60 return fib_rules_seq_read(net, AF_INET6);
61} 61}
62 62
63/* called with rcu lock held; no reference taken on fib6_info */
64struct fib6_info *fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
65 int flags)
66{
67 struct fib6_info *f6i;
68 int err;
69
70 if (net->ipv6.fib6_has_custom_rules) {
71 struct fib_lookup_arg arg = {
72 .lookup_ptr = fib6_table_lookup,
73 .lookup_data = &oif,
74 .flags = FIB_LOOKUP_NOREF,
75 };
76
77 l3mdev_update_flow(net, flowi6_to_flowi(fl6));
78
79 err = fib_rules_lookup(net->ipv6.fib6_rules_ops,
80 flowi6_to_flowi(fl6), flags, &arg);
81 if (err)
82 return ERR_PTR(err);
83
84 f6i = arg.result ? : net->ipv6.fib6_null_entry;
85 } else {
86 f6i = fib6_table_lookup(net, net->ipv6.fib6_local_tbl,
87 oif, fl6, flags);
88 if (!f6i || f6i == net->ipv6.fib6_null_entry)
89 f6i = fib6_table_lookup(net, net->ipv6.fib6_main_tbl,
90 oif, fl6, flags);
91 }
92
93 return f6i;
94}
95
63struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, 96struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
64 const struct sk_buff *skb, 97 const struct sk_buff *skb,
65 int flags, pol_lookup_t lookup) 98 int flags, pol_lookup_t lookup)
@@ -121,8 +154,48 @@ static int fib6_rule_saddr(struct net *net, struct fib_rule *rule, int flags,
121 return 0; 154 return 0;
122} 155}
123 156
124static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, 157static int fib6_rule_action_alt(struct fib_rule *rule, struct flowi *flp,
125 int flags, struct fib_lookup_arg *arg) 158 int flags, struct fib_lookup_arg *arg)
159{
160 struct flowi6 *flp6 = &flp->u.ip6;
161 struct net *net = rule->fr_net;
162 struct fib6_table *table;
163 struct fib6_info *f6i;
164 int err = -EAGAIN, *oif;
165 u32 tb_id;
166
167 switch (rule->action) {
168 case FR_ACT_TO_TBL:
169 break;
170 case FR_ACT_UNREACHABLE:
171 return -ENETUNREACH;
172 case FR_ACT_PROHIBIT:
173 return -EACCES;
174 case FR_ACT_BLACKHOLE:
175 default:
176 return -EINVAL;
177 }
178
179 tb_id = fib_rule_get_table(rule, arg);
180 table = fib6_get_table(net, tb_id);
181 if (!table)
182 return -EAGAIN;
183
184 oif = (int *)arg->lookup_data;
185 f6i = fib6_table_lookup(net, table, *oif, flp6, flags);
186 if (f6i != net->ipv6.fib6_null_entry) {
187 err = fib6_rule_saddr(net, rule, flags, flp6,
188 fib6_info_nh_dev(f6i));
189
190 if (likely(!err))
191 arg->result = f6i;
192 }
193
194 return err;
195}
196
197static int __fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
198 int flags, struct fib_lookup_arg *arg)
126{ 199{
127 struct flowi6 *flp6 = &flp->u.ip6; 200 struct flowi6 *flp6 = &flp->u.ip6;
128 struct rt6_info *rt = NULL; 201 struct rt6_info *rt = NULL;
@@ -182,6 +255,15 @@ out:
182 return err; 255 return err;
183} 256}
184 257
258static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
259 int flags, struct fib_lookup_arg *arg)
260{
261 if (arg->lookup_ptr == fib6_table_lookup)
262 return fib6_rule_action_alt(rule, flp, flags, arg);
263
264 return __fib6_rule_action(rule, flp, flags, arg);
265}
266
185static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg) 267static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
186{ 268{
187 struct rt6_info *rt = (struct rt6_info *) arg->result; 269 struct rt6_info *rt = (struct rt6_info *) arg->result;