aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2014-10-06 13:58:38 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-07 00:02:30 -0400
commit327571cb100cad587c9eda351e7a2d182466873b (patch)
tree586acd1e34fa9855cbe336ea70f987bc62e08dc8 /net
parent812918c464eca0e8c145f975932ca5020e9c05cb (diff)
ipv6: don't walk node's leaf during serial number update
Cc: YOSHIFUJI Hideaki <hideaki@yoshifuji.org> Cc: Martin Lau <kafai@fb.com> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/ip6_fib.c47
1 files changed, 30 insertions, 17 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 6f9beb1f2861..b2d1838897c9 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -50,6 +50,7 @@ struct fib6_cleaner {
50 struct fib6_walker w; 50 struct fib6_walker w;
51 struct net *net; 51 struct net *net;
52 int (*func)(struct rt6_info *, void *arg); 52 int (*func)(struct rt6_info *, void *arg);
53 int sernum;
53 void *arg; 54 void *arg;
54}; 55};
55 56
@@ -105,6 +106,10 @@ static int fib6_new_sernum(struct net *net)
105 return new; 106 return new;
106} 107}
107 108
109enum {
110 FIB6_NO_SERNUM_CHANGE = 0,
111};
112
108/* 113/*
109 * Auxiliary address test functions for the radix tree. 114 * Auxiliary address test functions for the radix tree.
110 * 115 *
@@ -1514,6 +1519,16 @@ static int fib6_clean_node(struct fib6_walker *w)
1514 .nl_net = c->net, 1519 .nl_net = c->net,
1515 }; 1520 };
1516 1521
1522 if (c->sernum != FIB6_NO_SERNUM_CHANGE &&
1523 w->node->fn_sernum != c->sernum)
1524 w->node->fn_sernum = c->sernum;
1525
1526 if (!c->func) {
1527 WARN_ON_ONCE(c->sernum == FIB6_NO_SERNUM_CHANGE);
1528 w->leaf = NULL;
1529 return 0;
1530 }
1531
1517 for (rt = w->leaf; rt; rt = rt->dst.rt6_next) { 1532 for (rt = w->leaf; rt; rt = rt->dst.rt6_next) {
1518 res = c->func(rt, c->arg); 1533 res = c->func(rt, c->arg);
1519 if (res < 0) { 1534 if (res < 0) {
@@ -1547,7 +1562,7 @@ static int fib6_clean_node(struct fib6_walker *w)
1547 1562
1548static void fib6_clean_tree(struct net *net, struct fib6_node *root, 1563static void fib6_clean_tree(struct net *net, struct fib6_node *root,
1549 int (*func)(struct rt6_info *, void *arg), 1564 int (*func)(struct rt6_info *, void *arg),
1550 bool prune, void *arg) 1565 bool prune, int sernum, void *arg)
1551{ 1566{
1552 struct fib6_cleaner c; 1567 struct fib6_cleaner c;
1553 1568
@@ -1557,14 +1572,16 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root,
1557 c.w.count = 0; 1572 c.w.count = 0;
1558 c.w.skip = 0; 1573 c.w.skip = 0;
1559 c.func = func; 1574 c.func = func;
1575 c.sernum = sernum;
1560 c.arg = arg; 1576 c.arg = arg;
1561 c.net = net; 1577 c.net = net;
1562 1578
1563 fib6_walk(&c.w); 1579 fib6_walk(&c.w);
1564} 1580}
1565 1581
1566void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), 1582static void __fib6_clean_all(struct net *net,
1567 void *arg) 1583 int (*func)(struct rt6_info *, void *),
1584 int sernum, void *arg)
1568{ 1585{
1569 struct fib6_table *table; 1586 struct fib6_table *table;
1570 struct hlist_head *head; 1587 struct hlist_head *head;
@@ -1576,13 +1593,19 @@ void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg),
1576 hlist_for_each_entry_rcu(table, head, tb6_hlist) { 1593 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
1577 write_lock_bh(&table->tb6_lock); 1594 write_lock_bh(&table->tb6_lock);
1578 fib6_clean_tree(net, &table->tb6_root, 1595 fib6_clean_tree(net, &table->tb6_root,
1579 func, false, arg); 1596 func, false, sernum, arg);
1580 write_unlock_bh(&table->tb6_lock); 1597 write_unlock_bh(&table->tb6_lock);
1581 } 1598 }
1582 } 1599 }
1583 rcu_read_unlock(); 1600 rcu_read_unlock();
1584} 1601}
1585 1602
1603void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *),
1604 void *arg)
1605{
1606 __fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg);
1607}
1608
1586static int fib6_prune_clone(struct rt6_info *rt, void *arg) 1609static int fib6_prune_clone(struct rt6_info *rt, void *arg)
1587{ 1610{
1588 if (rt->rt6i_flags & RTF_CACHE) { 1611 if (rt->rt6i_flags & RTF_CACHE) {
@@ -1595,25 +1618,15 @@ static int fib6_prune_clone(struct rt6_info *rt, void *arg)
1595 1618
1596static void fib6_prune_clones(struct net *net, struct fib6_node *fn) 1619static void fib6_prune_clones(struct net *net, struct fib6_node *fn)
1597{ 1620{
1598 fib6_clean_tree(net, fn, fib6_prune_clone, true, NULL); 1621 fib6_clean_tree(net, fn, fib6_prune_clone, true,
1599} 1622 FIB6_NO_SERNUM_CHANGE, NULL);
1600
1601static int fib6_update_sernum(struct rt6_info *rt, void *arg)
1602{
1603 int sernum = *(int *)arg;
1604
1605 if (rt->rt6i_node &&
1606 rt->rt6i_node->fn_sernum != sernum)
1607 rt->rt6i_node->fn_sernum = sernum;
1608
1609 return 0;
1610} 1623}
1611 1624
1612static void fib6_flush_trees(struct net *net) 1625static void fib6_flush_trees(struct net *net)
1613{ 1626{
1614 int new_sernum = fib6_new_sernum(net); 1627 int new_sernum = fib6_new_sernum(net);
1615 1628
1616 fib6_clean_all(net, fib6_update_sernum, &new_sernum); 1629 __fib6_clean_all(net, NULL, new_sernum, NULL);
1617} 1630}
1618 1631
1619/* 1632/*