Skip to content

Commit 2b760fc

Browse files
tracywwnjdavem330
authored andcommitted
ipv6: hook up exception table to store dst cache
This commit makes use of the exception hash table implementation to store dst caches created by pmtu discovery and ip redirect into the hash table under the rt_info and no longer inserts these routes into fib6 tree. This makes the fib6 tree only contain static configured routes and could now be protected by rcu instead of a rw lock. With this change, in the route lookup related functions, after finding the rt6_info with the longest prefix, we also need to search for the exception table before doing backtracking. In the route delete function, if the route being deleted is not a dst cache, deletion of this route also need to flush the whole hash table under it. If it is a dst cache, then only delete the cached dst in the hash table. Note: for fib6_walk_continue() function, w->root now is always pointing to a root node considering that fib6_prune_clones() is removed from the code. So we add a WARN_ON() msg to make sure w->root always points to a root node and also removed the update of w->root in fib6_repair_tree(). This is a prerequisite for later patch because we don't need to make w->root as rcu protected when replacing rwlock with RCU. Also, we remove all prune related variables as it is no longer used. Signed-off-by: Wei Wang <[email protected]> Signed-off-by: Martin KaFai Lau <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 38fbeee commit 2b760fc

File tree

4 files changed

+72
-133
lines changed

4 files changed

+72
-133
lines changed

include/net/ip6_fib.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,6 @@ struct fib6_walker {
280280
struct fib6_node *root, *node;
281281
struct rt6_info *leaf;
282282
enum fib6_walk_state state;
283-
bool prune;
284283
unsigned int skip;
285284
unsigned int count;
286285
int (*func)(struct fib6_walker *);

net/ipv6/addrconf.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2326,7 +2326,6 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
23262326
if (!fn)
23272327
goto out;
23282328

2329-
noflags |= RTF_CACHE;
23302329
for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
23312330
if (rt->dst.dev->ifindex != dev->ifindex)
23322331
continue;

net/ipv6/ip6_fib.c

Lines changed: 17 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ struct fib6_cleaner {
5454
#define FWS_INIT FWS_L
5555
#endif
5656

57-
static void fib6_prune_clones(struct net *net, struct fib6_node *fn);
5857
static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn);
5958
static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn);
6059
static int fib6_walk(struct net *net, struct fib6_walker *w);
@@ -1101,6 +1100,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
11011100

11021101
if (WARN_ON_ONCE(!atomic_read(&rt->dst.__refcnt)))
11031102
return -EINVAL;
1103+
if (WARN_ON_ONCE(rt->rt6i_flags & RTF_CACHE))
1104+
return -EINVAL;
11041105

11051106
if (info->nlh) {
11061107
if (!(info->nlh->nlmsg_flags & NLM_F_CREATE))
@@ -1192,11 +1193,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
11921193
#endif
11931194

11941195
err = fib6_add_rt2node(fn, rt, info, mxc);
1195-
if (!err) {
1196+
if (!err)
11961197
fib6_start_gc(info->nl_net, rt);
1197-
if (!(rt->rt6i_flags & RTF_CACHE))
1198-
fib6_prune_clones(info->nl_net, pn);
1199-
}
12001198

12011199
out:
12021200
if (err) {
@@ -1511,19 +1509,12 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
15111509
read_lock(&net->ipv6.fib6_walker_lock);
15121510
FOR_WALKERS(net, w) {
15131511
if (!child) {
1514-
if (w->root == fn) {
1515-
w->root = w->node = NULL;
1516-
RT6_TRACE("W %p adjusted by delroot 1\n", w);
1517-
} else if (w->node == fn) {
1512+
if (w->node == fn) {
15181513
RT6_TRACE("W %p adjusted by delnode 1, s=%d/%d\n", w, w->state, nstate);
15191514
w->node = pn;
15201515
w->state = nstate;
15211516
}
15221517
} else {
1523-
if (w->root == fn) {
1524-
w->root = child;
1525-
RT6_TRACE("W %p adjusted by delroot 2\n", w);
1526-
}
15271518
if (w->node == fn) {
15281519
w->node = child;
15291520
if (children&2) {
@@ -1557,12 +1548,17 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
15571548

15581549
RT6_TRACE("fib6_del_route\n");
15591550

1551+
WARN_ON_ONCE(rt->rt6i_flags & RTF_CACHE);
1552+
15601553
/* Unlink it */
15611554
*rtp = rt->dst.rt6_next;
15621555
rt->rt6i_node = NULL;
15631556
net->ipv6.rt6_stats->fib_rt_entries--;
15641557
net->ipv6.rt6_stats->fib_discarded_routes++;
15651558

1559+
/* Flush all cached dst in exception table */
1560+
rt6_flush_exceptions(rt);
1561+
15661562
/* Reset round-robin state, if necessary */
15671563
if (fn->rr_ptr == rt)
15681564
fn->rr_ptr = NULL;
@@ -1625,18 +1621,9 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
16251621

16261622
WARN_ON(!(fn->fn_flags & RTN_RTINFO));
16271623

1628-
if (!(rt->rt6i_flags & RTF_CACHE)) {
1629-
struct fib6_node *pn = fn;
1630-
#ifdef CONFIG_IPV6_SUBTREES
1631-
/* clones of this route might be in another subtree */
1632-
if (rt->rt6i_src.plen) {
1633-
while (!(pn->fn_flags & RTN_ROOT))
1634-
pn = pn->parent;
1635-
pn = pn->parent;
1636-
}
1637-
#endif
1638-
fib6_prune_clones(info->nl_net, pn);
1639-
}
1624+
/* remove cached dst from exception table */
1625+
if (rt->rt6i_flags & RTF_CACHE)
1626+
return rt6_remove_exception_rt(rt);
16401627

16411628
/*
16421629
* Walk the leaf entries looking for ourself
@@ -1679,16 +1666,14 @@ static int fib6_walk_continue(struct fib6_walker *w)
16791666
{
16801667
struct fib6_node *fn, *pn;
16811668

1669+
/* w->root should always be table->tb6_root */
1670+
WARN_ON_ONCE(!(w->root->fn_flags & RTN_TL_ROOT));
1671+
16821672
for (;;) {
16831673
fn = w->node;
16841674
if (!fn)
16851675
return 0;
16861676

1687-
if (w->prune && fn != w->root &&
1688-
fn->fn_flags & RTN_RTINFO && w->state < FWS_C) {
1689-
w->state = FWS_C;
1690-
w->leaf = fn->leaf;
1691-
}
16921677
switch (w->state) {
16931678
#ifdef CONFIG_IPV6_SUBTREES
16941679
case FWS_S:
@@ -1820,20 +1805,16 @@ static int fib6_clean_node(struct fib6_walker *w)
18201805
* func is called on each route.
18211806
* It may return -1 -> delete this route.
18221807
* 0 -> continue walking
1823-
*
1824-
* prune==1 -> only immediate children of node (certainly,
1825-
* ignoring pure split nodes) will be scanned.
18261808
*/
18271809

18281810
static void fib6_clean_tree(struct net *net, struct fib6_node *root,
18291811
int (*func)(struct rt6_info *, void *arg),
1830-
bool prune, int sernum, void *arg)
1812+
int sernum, void *arg)
18311813
{
18321814
struct fib6_cleaner c;
18331815

18341816
c.w.root = root;
18351817
c.w.func = fib6_clean_node;
1836-
c.w.prune = prune;
18371818
c.w.count = 0;
18381819
c.w.skip = 0;
18391820
c.func = func;
@@ -1858,7 +1839,7 @@ static void __fib6_clean_all(struct net *net,
18581839
hlist_for_each_entry_rcu(table, head, tb6_hlist) {
18591840
write_lock_bh(&table->tb6_lock);
18601841
fib6_clean_tree(net, &table->tb6_root,
1861-
func, false, sernum, arg);
1842+
func, sernum, arg);
18621843
write_unlock_bh(&table->tb6_lock);
18631844
}
18641845
}
@@ -1871,22 +1852,6 @@ void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *),
18711852
__fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg);
18721853
}
18731854

1874-
static int fib6_prune_clone(struct rt6_info *rt, void *arg)
1875-
{
1876-
if (rt->rt6i_flags & RTF_CACHE) {
1877-
RT6_TRACE("pruning clone %p\n", rt);
1878-
return -1;
1879-
}
1880-
1881-
return 0;
1882-
}
1883-
1884-
static void fib6_prune_clones(struct net *net, struct fib6_node *fn)
1885-
{
1886-
fib6_clean_tree(net, fn, fib6_prune_clone, true,
1887-
FIB6_NO_SERNUM_CHANGE, NULL);
1888-
}
1889-
18901855
static void fib6_flush_trees(struct net *net)
18911856
{
18921857
int new_sernum = fib6_new_sernum(net);
@@ -1914,32 +1879,6 @@ static int fib6_age(struct rt6_info *rt, void *arg)
19141879
return -1;
19151880
}
19161881
gc_args->more++;
1917-
/* The following part will soon be removed when the exception
1918-
* table is hooked up to store all cached routes.
1919-
*/
1920-
} else if (rt->rt6i_flags & RTF_CACHE) {
1921-
if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout))
1922-
rt->dst.obsolete = DST_OBSOLETE_KILL;
1923-
if (atomic_read(&rt->dst.__refcnt) == 1 &&
1924-
rt->dst.obsolete == DST_OBSOLETE_KILL) {
1925-
RT6_TRACE("aging clone %p\n", rt);
1926-
return -1;
1927-
} else if (rt->rt6i_flags & RTF_GATEWAY) {
1928-
struct neighbour *neigh;
1929-
__u8 neigh_flags = 0;
1930-
1931-
neigh = dst_neigh_lookup(&rt->dst, &rt->rt6i_gateway);
1932-
if (neigh) {
1933-
neigh_flags = neigh->flags;
1934-
neigh_release(neigh);
1935-
}
1936-
if (!(neigh_flags & NTF_ROUTER)) {
1937-
RT6_TRACE("purging route %p via non-router but gateway\n",
1938-
rt);
1939-
return -1;
1940-
}
1941-
}
1942-
gc_args->more++;
19431882
}
19441883

19451884
/* Also age clones in the exception table.

0 commit comments

Comments
 (0)