Skip to content

Commit af7888a

Browse files
dsaherndavem330
authored andcommitted
ipv4: Refactor nhc evaluation in fib_table_lookup
FIB lookups can return an entry that references an external nexthop. While walking the nexthop struct we do not want to make multiple calls into the nexthop code which can result in 2 different structs getting accessed - one returning the number of paths the rest of the loop seeing a different nh_grp struct. If the nexthop group shrunk, the result is an attempt to access a fib_nh_common that does not exist for the new nh_grp struct but did for the old one. To fix that move the device evaluation code to a helper that can be used for inline fib_nh path as well as external nexthops. Update the existing check for fi->nh in fib_table_lookup to call a new helper, nexthop_get_nhc_lookup, which walks the external nexthop with a single rcu dereference. Fixes: 430a049 ("nexthop: Add support for nexthop groups") Signed-off-by: David Ahern <[email protected]> Acked-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0b5e2e3 commit af7888a

File tree

3 files changed

+71
-15
lines changed

3 files changed

+71
-15
lines changed

include/net/ip_fib.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,8 @@ void fib_nh_common_release(struct fib_nh_common *nhc);
479479
void fib_alias_hw_flags_set(struct net *net, const struct fib_rt_info *fri);
480480
void fib_trie_init(void);
481481
struct fib_table *fib_trie_table(u32 id, struct fib_table *alias);
482+
bool fib_lookup_good_nhc(const struct fib_nh_common *nhc, int fib_flags,
483+
const struct flowi4 *flp);
482484

483485
static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
484486
{

include/net/nexthop.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,39 @@ struct fib_nh_common *nexthop_fib_nhc(struct nexthop *nh, int nhsel)
233233
return &nhi->fib_nhc;
234234
}
235235

236+
/* called from fib_table_lookup with rcu_lock */
237+
static inline
238+
struct fib_nh_common *nexthop_get_nhc_lookup(const struct nexthop *nh,
239+
int fib_flags,
240+
const struct flowi4 *flp,
241+
int *nhsel)
242+
{
243+
struct nh_info *nhi;
244+
245+
if (nh->is_group) {
246+
struct nh_group *nhg = rcu_dereference(nh->nh_grp);
247+
int i;
248+
249+
for (i = 0; i < nhg->num_nh; i++) {
250+
struct nexthop *nhe = nhg->nh_entries[i].nh;
251+
252+
nhi = rcu_dereference(nhe->nh_info);
253+
if (fib_lookup_good_nhc(&nhi->fib_nhc, fib_flags, flp)) {
254+
*nhsel = i;
255+
return &nhi->fib_nhc;
256+
}
257+
}
258+
} else {
259+
nhi = rcu_dereference(nh->nh_info);
260+
if (fib_lookup_good_nhc(&nhi->fib_nhc, fib_flags, flp)) {
261+
*nhsel = 0;
262+
return &nhi->fib_nhc;
263+
}
264+
}
265+
266+
return NULL;
267+
}
268+
236269
static inline unsigned int fib_info_num_path(const struct fib_info *fi)
237270
{
238271
if (unlikely(fi->nh))

net/ipv4/fib_trie.c

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,26 @@ static inline t_key prefix_mismatch(t_key key, struct key_vector *n)
13711371
return (key ^ prefix) & (prefix | -prefix);
13721372
}
13731373

1374+
bool fib_lookup_good_nhc(const struct fib_nh_common *nhc, int fib_flags,
1375+
const struct flowi4 *flp)
1376+
{
1377+
if (nhc->nhc_flags & RTNH_F_DEAD)
1378+
return false;
1379+
1380+
if (ip_ignore_linkdown(nhc->nhc_dev) &&
1381+
nhc->nhc_flags & RTNH_F_LINKDOWN &&
1382+
!(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE))
1383+
return false;
1384+
1385+
if (!(flp->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF)) {
1386+
if (flp->flowi4_oif &&
1387+
flp->flowi4_oif != nhc->nhc_oif)
1388+
return false;
1389+
}
1390+
1391+
return true;
1392+
}
1393+
13741394
/* should be called with rcu_read_lock */
13751395
int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
13761396
struct fib_result *res, int fib_flags)
@@ -1503,6 +1523,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
15031523
/* Step 3: Process the leaf, if that fails fall back to backtracing */
15041524
hlist_for_each_entry_rcu(fa, &n->leaf, fa_list) {
15051525
struct fib_info *fi = fa->fa_info;
1526+
struct fib_nh_common *nhc;
15061527
int nhsel, err;
15071528

15081529
if ((BITS_PER_LONG > KEYLENGTH) || (fa->fa_slen < KEYLENGTH)) {
@@ -1528,26 +1549,25 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
15281549
if (fi->fib_flags & RTNH_F_DEAD)
15291550
continue;
15301551

1531-
if (unlikely(fi->nh && nexthop_is_blackhole(fi->nh))) {
1532-
err = fib_props[RTN_BLACKHOLE].error;
1533-
goto out_reject;
1552+
if (unlikely(fi->nh)) {
1553+
if (nexthop_is_blackhole(fi->nh)) {
1554+
err = fib_props[RTN_BLACKHOLE].error;
1555+
goto out_reject;
1556+
}
1557+
1558+
nhc = nexthop_get_nhc_lookup(fi->nh, fib_flags, flp,
1559+
&nhsel);
1560+
if (nhc)
1561+
goto set_result;
1562+
goto miss;
15341563
}
15351564

15361565
for (nhsel = 0; nhsel < fib_info_num_path(fi); nhsel++) {
1537-
struct fib_nh_common *nhc = fib_info_nhc(fi, nhsel);
1566+
nhc = fib_info_nhc(fi, nhsel);
15381567

1539-
if (nhc->nhc_flags & RTNH_F_DEAD)
1568+
if (!fib_lookup_good_nhc(nhc, fib_flags, flp))
15401569
continue;
1541-
if (ip_ignore_linkdown(nhc->nhc_dev) &&
1542-
nhc->nhc_flags & RTNH_F_LINKDOWN &&
1543-
!(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE))
1544-
continue;
1545-
if (!(flp->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF)) {
1546-
if (flp->flowi4_oif &&
1547-
flp->flowi4_oif != nhc->nhc_oif)
1548-
continue;
1549-
}
1550-
1570+
set_result:
15511571
if (!(fib_flags & FIB_LOOKUP_NOREF))
15521572
refcount_inc(&fi->fib_clntref);
15531573

@@ -1568,6 +1588,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
15681588
return err;
15691589
}
15701590
}
1591+
miss:
15711592
#ifdef CONFIG_IP_FIB_TRIE_STATS
15721593
this_cpu_inc(stats->semantic_match_miss);
15731594
#endif

0 commit comments

Comments
 (0)