ipv6: Pass fib6_result to rt6_select and find_rr_leaf

Pass fib6_result to rt6_select. Instead of returning the fib entry, it
will set f6i and nh based on the lookup.

find_rr_leaf is changed to remove the match option in favor of taking
fib6_result and having __find_rr_leaf set f6i in the result.

In the process, update fib6_info references in __find_rr_leaf to f6i names.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David Ahern 2019-04-16 14:36:08 -07:00 committed by David S. Miller
parent 75ef7389dd
commit b7bc4b6a62
1 changed files with 43 additions and 39 deletions

View File

@ -695,66 +695,68 @@ out:
return rc; return rc;
} }
static void __find_rr_leaf(struct fib6_info *rt_start, static void __find_rr_leaf(struct fib6_info *f6i_start,
struct fib6_info *nomatch, u32 metric, struct fib6_info *nomatch, u32 metric,
struct fib6_info **match, struct fib6_info **cont, struct fib6_result *res, struct fib6_info **cont,
int oif, int strict, bool *do_rr, int *mpri) int oif, int strict, bool *do_rr, int *mpri)
{ {
struct fib6_info *rt; struct fib6_info *f6i;
for (rt = rt_start; for (f6i = f6i_start;
rt && rt != nomatch; f6i && f6i != nomatch;
rt = rcu_dereference(rt->fib6_next)) { f6i = rcu_dereference(f6i->fib6_next)) {
struct fib6_nh *nh; struct fib6_nh *nh;
if (cont && rt->fib6_metric != metric) { if (cont && f6i->fib6_metric != metric) {
*cont = rt; *cont = f6i;
return; return;
} }
if (fib6_check_expired(rt)) if (fib6_check_expired(f6i))
continue; continue;
nh = &rt->fib6_nh; nh = &f6i->fib6_nh;
if (find_match(nh, rt->fib6_flags, oif, strict, mpri, do_rr)) if (find_match(nh, f6i->fib6_flags, oif, strict, mpri, do_rr)) {
*match = rt; res->f6i = f6i;
res->nh = nh;
}
} }
} }
static struct fib6_info *find_rr_leaf(struct fib6_node *fn, static void find_rr_leaf(struct fib6_node *fn, struct fib6_info *leaf,
struct fib6_info *leaf, struct fib6_info *rr_head, int oif, int strict,
struct fib6_info *rr_head, bool *do_rr, struct fib6_result *res)
u32 metric, int oif, int strict,
bool *do_rr)
{ {
struct fib6_info *match = NULL, *cont = NULL; u32 metric = rr_head->fib6_metric;
struct fib6_info *cont = NULL;
int mpri = -1; int mpri = -1;
__find_rr_leaf(rr_head, NULL, metric, &match, &cont, __find_rr_leaf(rr_head, NULL, metric, res, &cont,
oif, strict, do_rr, &mpri); oif, strict, do_rr, &mpri);
__find_rr_leaf(leaf, rr_head, metric, &match, &cont, __find_rr_leaf(leaf, rr_head, metric, res, &cont,
oif, strict, do_rr, &mpri); oif, strict, do_rr, &mpri);
if (match || !cont) if (res->f6i || !cont)
return match; return;
__find_rr_leaf(cont, NULL, metric, &match, NULL, __find_rr_leaf(cont, NULL, metric, res, NULL,
oif, strict, do_rr, &mpri); oif, strict, do_rr, &mpri);
return match;
} }
static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn, static void rt6_select(struct net *net, struct fib6_node *fn, int oif,
int oif, int strict) struct fib6_result *res, int strict)
{ {
struct fib6_info *leaf = rcu_dereference(fn->leaf); struct fib6_info *leaf = rcu_dereference(fn->leaf);
struct fib6_info *match, *rt0; struct fib6_info *rt0;
bool do_rr = false; bool do_rr = false;
int key_plen; int key_plen;
/* make sure this function or its helpers sets f6i */
res->f6i = NULL;
if (!leaf || leaf == net->ipv6.fib6_null_entry) if (!leaf || leaf == net->ipv6.fib6_null_entry)
return net->ipv6.fib6_null_entry; goto out;
rt0 = rcu_dereference(fn->rr_ptr); rt0 = rcu_dereference(fn->rr_ptr);
if (!rt0) if (!rt0)
@ -771,11 +773,9 @@ static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn,
key_plen = rt0->fib6_src.plen; key_plen = rt0->fib6_src.plen;
#endif #endif
if (fn->fn_bit != key_plen) if (fn->fn_bit != key_plen)
return net->ipv6.fib6_null_entry; goto out;
match = find_rr_leaf(fn, leaf, rt0, rt0->fib6_metric, oif, strict,
&do_rr);
find_rr_leaf(fn, leaf, rt0, oif, strict, &do_rr, res);
if (do_rr) { if (do_rr) {
struct fib6_info *next = rcu_dereference(rt0->fib6_next); struct fib6_info *next = rcu_dereference(rt0->fib6_next);
@ -792,7 +792,11 @@ static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn,
} }
} }
return match ? match : net->ipv6.fib6_null_entry; out:
if (!res->f6i) {
res->f6i = net->ipv6.fib6_null_entry;
res->nh = &res->f6i->fib6_nh;
}
} }
static bool rt6_is_gw_or_nonexthop(const struct fib6_result *res) static bool rt6_is_gw_or_nonexthop(const struct fib6_result *res)
@ -1839,7 +1843,7 @@ struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table,
int oif, struct flowi6 *fl6, int strict) int oif, struct flowi6 *fl6, int strict)
{ {
struct fib6_node *fn, *saved_fn; struct fib6_node *fn, *saved_fn;
struct fib6_info *f6i; struct fib6_result res;
fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
saved_fn = fn; saved_fn = fn;
@ -1848,8 +1852,8 @@ struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table,
oif = 0; oif = 0;
redo_rt6_select: redo_rt6_select:
f6i = rt6_select(net, fn, oif, strict); rt6_select(net, fn, oif, &res, strict);
if (f6i == net->ipv6.fib6_null_entry) { if (res.f6i == net->ipv6.fib6_null_entry) {
fn = fib6_backtrack(fn, &fl6->saddr); fn = fib6_backtrack(fn, &fl6->saddr);
if (fn) if (fn)
goto redo_rt6_select; goto redo_rt6_select;
@ -1861,9 +1865,9 @@ redo_rt6_select:
} }
} }
trace_fib6_table_lookup(net, f6i, table, fl6); trace_fib6_table_lookup(net, res.f6i, table, fl6);
return f6i; return res.f6i;
} }
struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,