Skip to content

Commit 138118e

Browse files
dsahernborkmann
authored andcommitted
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>
1 parent cc065a9 commit 138118e

File tree

3 files changed

+97
-2
lines changed

3 files changed

+97
-2
lines changed

include/net/ip6_fib.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,12 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
376376
const struct sk_buff *skb,
377377
int flags, pol_lookup_t lookup);
378378

379+
/* called with rcu lock held; can return error pointer
380+
* caller needs to select path
381+
*/
382+
struct fib6_info *fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
383+
int flags);
384+
379385
/* called with rcu lock held; caller needs to select path */
380386
struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table,
381387
int oif, struct flowi6 *fl6, int strict);

net/ipv6/fib6_rules.c

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,39 @@ unsigned int fib6_rules_seq_read(struct net *net)
6060
return fib_rules_seq_read(net, AF_INET6);
6161
}
6262

63+
/* called with rcu lock held; no reference taken on fib6_info */
64+
struct 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+
6396
struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
6497
const struct sk_buff *skb,
6598
int flags, pol_lookup_t lookup)
@@ -121,8 +154,48 @@ static int fib6_rule_saddr(struct net *net, struct fib_rule *rule, int flags,
121154
return 0;
122155
}
123156

124-
static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
125-
int flags, struct fib_lookup_arg *arg)
157+
static int fib6_rule_action_alt(struct fib_rule *rule, struct flowi *flp,
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+
197+
static int __fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
198+
int flags, struct fib_lookup_arg *arg)
126199
{
127200
struct flowi6 *flp6 = &flp->u.ip6;
128201
struct rt6_info *rt = NULL;
@@ -182,6 +255,15 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
182255
return err;
183256
}
184257

258+
static 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+
185267
static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
186268
{
187269
struct rt6_info *rt = (struct rt6_info *) arg->result;

net/ipv6/ip6_fib.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,13 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
354354
return &rt->dst;
355355
}
356356

357+
/* called with rcu lock held; no reference taken on fib6_info */
358+
struct fib6_info *fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
359+
int flags)
360+
{
361+
return fib6_table_lookup(net, net->ipv6.fib6_main_tbl, oif, fl6, flags);
362+
}
363+
357364
static void __net_init fib6_tables_init(struct net *net)
358365
{
359366
fib6_link_table(net, net->ipv6.fib6_main_tbl);

0 commit comments

Comments
 (0)