ipv6: cleanup after rt6_genid removal
Subsystems (3)
v2 cover ipv6: cleanup after rt6_genid removal
Leftover patches after rt6_genid removal after 705f1c869d577c ("ipv6:
remove rt6i_genid").
Major two changes are:
* keep fib6_sernum per namespace to reduce number of flushes in case system has high number of namespaces
* make fn_sernum updates cheaper
v2: Incorporated feedback from Cong Wang, thanks a lot!
Hannes Frederic Sowa (5):
ipv6: minor fib6 cleanups like type safety, bool conversion, inline
removal
ipv6: make rt_sernum atomic and serial number fields ordinary ints
ipv6: only generate one new serial number per fib mutation
ipv6: make fib6 serial number per namespace
ipv6: don't walk node's leaf during serial number update
include/net/ip6_fib.h | 20 +++++-- include/net/netns/ipv6.h | 2 +- net/ipv6/af_inet6.c | 2 +- net/ipv6/ip6_fib.c | 142 ++++++++++++++++++++++++----------------------- 4 files changed, 91 insertions(+), 75 deletions(-)
Signature · 1 line
1.9.3
PATCH v2 1/5 ipv6: minor fib6 cleanups like type safety, bool conversion, inline removal
Also renamed struct fib6_walker_t to fib6_walker and enum fib_walk_state_t to fib6_walk_state as recommended by Cong Wang.
--- include/net/ip6_fib.h | 18 ++++++++++--- net/ipv6/ip6_fib.c | 71 ++++++++++++++++++++++----------------------------- 2 files changed, 45 insertions(+), 44 deletions(-)
include/net/ip6_fib.h +14 -4
@@ -202,15 +202,25 @@ static inline void ip6_rt_put(struct rt6_info *rt)dst_release (&rt->dst); } -struct fib6_walker_t { +enum fib6_walk_state { +#ifdef CONFIG_IPV6_SUBTREES +FWS_S , +#endif +FWS_L , +FWS_R , +FWS_C , +FWS_U +}; + +struct fib6_walker {struct list_head lh;struct fib6_node *root, *node;struct rt6_info *leaf; -unsigned char state; -unsigned char prune; +enum fib6_walk_state state; +bool prune;unsigned int skip;unsigned int count; -int (*func)(struct fib6_walker_t *); +int (*func)(struct fib6_walker *);void *args; };
net/ipv6/ip6_fib.c +31 -40
228 lines not on this page · raw message
Signature · 1 line
1.9.3
PATCH v2 2/5 ipv6: make rt_sernum atomic and serial number fields ordinary ints
In reply to Hannes Frederic Sowa--- include/net/ip6_fib.h | 2 +- net/ipv6/ip6_fib.c | 23 +++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-)
include/net/ip6_fib.h +1 -1
@@ -64,7 +64,7 @@ struct fib6_node {__u16 fn_bit;/* bit key */ __u16 fn_flags; -__u32 fn_sernum; +int fn_sernum;struct rt6_info *rr_ptr; };
net/ipv6/ip6_fib.c +13 -10
@@ -74,7 +74,7 @@ static int fib6_walk_continue(struct fib6_walker *w);* result of redirects, path MTU changes, etc. */ -static __u32 rt_sernum; +static atomic_t rt_sernum =ATOMIC_INIT (1 );static void fib6_gc_timer_cb (unsigned long arg);
@@ -95,12 +95,15 @@ static void fib6_walker_unlink(struct fib6_walker *w)write_unlock_bh (&fib6_walker_lock); } -static u32 fib6_new_sernum (void ) +static int fib6_new_sernum (void ) { -u32 n = ++rt_sernum; -if ((__s32 )n <=0 ) - rt_sernum = n =1 ; -return n; +int new, old; + +do { + old =atomic_read (&rt_sernum); + new = old <INT_MAX ? old +1 :1 ; + }while (atomic_cmpxchg (&rt_sernum, old, new) != old); +return new; }/*
@@ -421,7 +424,7 @@ static struct fib6_node *fib6_add_1(struct fib6_node *root,struct rt6key *key;int bit;__be32 dir =0 ; -__u32 sernum =fib6_new_sernum (); +int sernum =fib6_new_sernum ();RT6_TRACE ("fib6_add_1\n" );
@@ -1598,7 +1601,7 @@ static void fib6_prune_clones(struct net *net, struct fib6_node *fn)static int fib6_update_sernum (struct rt6_info *rt,void *arg) { -__u32 sernum = *(__u32 *)arg; +int sernum = *(int *)arg;if (rt->rt6i_node && rt->rt6i_node->fn_sernum != sernum)
@@ -1609,7 +1612,7 @@ static int fib6_update_sernum(struct rt6_info *rt, void *arg)static void fib6_flush_trees (struct net *net) { -__u32 new_sernum =fib6_new_sernum (); +int new_sernum =fib6_new_sernum ();fib6_clean_all (net, fib6_update_sernum, &new_sernum); }
@@ -1822,7 +1825,7 @@ struct ipv6_route_iter {struct fib6_walker w;loff_t skip;struct fib6_table *tbl; -__u32 sernum; +int sernum; };static int ipv6_route_seq_show (struct seq_file *seq,void *v)
Signature · 1 line
1.9.3
PATCH v2 3/5 ipv6: only generate one new serial number per fib mutation
In reply to Hannes Frederic Sowa--- net/ipv6/ip6_fib.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
net/ipv6/ip6_fib.c +6 -6
@@ -417,14 +417,13 @@ out:static struct fib6_node *fib6_add_1 (struct fib6_node *root,struct in6_addr *addr,int plen,int offset,int allow_create, -int replace_required) +int replace_required,int sernum) {struct fib6_node *fn, *in, *ln;struct fib6_node *pn =NULL ;struct rt6key *key;int bit;__be32 dir =0 ; -int sernum =fib6_new_sernum ();RT6_TRACE ("fib6_add_1\n" );
@@ -842,6 +841,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info,int err = -ENOMEM ;int allow_create =1 ;int replace_required =0 ; +int sernum =fib6_new_sernum ();if (info->nlh) {if (!(info->nlh->nlmsg_flags &NLM_F_CREATE ))
@@ -854,7 +854,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info, fn =fib6_add_1 (root, &rt->rt6i_dst.addr, rt->rt6i_dst.plen, offsetof(struct rt6_info , rt6i_dst), allow_create, - replace_required); + replace_required, sernum);if (IS_ERR (fn)) { err =PTR_ERR (fn); fn =NULL ;
@@ -888,14 +888,14 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info, sfn->leaf = info->nl_net->ipv6.ip6_null_entry;atomic_inc (&info->nl_net->ipv6.ip6_null_entry->rt6i_ref); sfn->fn_flags =RTN_ROOT ; - sfn->fn_sernum =fib6_new_sernum (); + sfn->fn_sernum = sernum;/* Now add the first leaf node to new subtree */ sn =fib6_add_1 (sfn, &rt->rt6i_src.addr, rt->rt6i_src.plen, offsetof(struct rt6_info , rt6i_src), - allow_create, replace_required); + allow_create, replace_required, sernum);if (IS_ERR (sn)) {/* If it is failed, discard just allocated
@@ -914,7 +914,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info, sn =fib6_add_1 (fn->subtree, &rt->rt6i_src.addr, rt->rt6i_src.plen, offsetof(struct rt6_info , rt6i_src), - allow_create, replace_required); + allow_create, replace_required, sernum);if (IS_ERR (sn)) { err =PTR_ERR (sn);
Signature · 1 line
1.9.3
PATCH v2 4/5 ipv6: make fib6 serial number per namespace
In reply to Hannes Frederic SowaTry to reduce number of possible fn_sernum mutation by constraining them to their namespace.
Also remove rt_genid which I forgot to remove in 705f1c869d577c ("ipv6:
remove rt6i_genid").
--- include/net/netns/ipv6.h | 2 +- net/ipv6/af_inet6.c | 2 +- net/ipv6/ip6_fib.c | 13 ++++++------- 3 files changed, 8 insertions(+), 9 deletions(-)
include/net/netns/ipv6.h +1 -1
@@ -76,7 +76,7 @@ struct netns_ipv6 {#endif #endif atomic_t dev_addr_genid; -atomic_t rt_genid; +atomic_t fib6_sernum; };#if IS_ENABLED (CONFIG_NF_DEFRAG_IPV6 )
net/ipv6/af_inet6.c +1 -1
@@ -766,7 +766,7 @@ static int __net_init inet6_net_init(struct net *net) net->ipv6.sysctl.icmpv6_time =1 *HZ ; net->ipv6.sysctl.flowlabel_consistency =1 ; net->ipv6.sysctl.auto_flowlabels =0 ; -atomic_set (&net->ipv6.rt_genid,0 ); +atomic_set (&net->ipv6.fib6_sernum,1 ); err =ipv6_init_mibs (net);if (err)
net/ipv6/ip6_fib.c +6 -7
@@ -74,8 +74,6 @@ static int fib6_walk_continue(struct fib6_walker *w);* result of redirects, path MTU changes, etc. */ -static atomic_t rt_sernum =ATOMIC_INIT (1 ); -static void fib6_gc_timer_cb (unsigned long arg);static LIST_HEAD (fib6_walkers);
@@ -95,14 +93,15 @@ static void fib6_walker_unlink(struct fib6_walker *w)write_unlock_bh (&fib6_walker_lock); } -static int fib6_new_sernum (void ) +static int fib6_new_sernum (struct net *net) {int new, old;do { - old =atomic_read (&rt_sernum); + old =atomic_read (&net->ipv6.fib6_sernum); new = old <INT_MAX ? old +1 :1 ; - }while (atomic_cmpxchg (&rt_sernum, old, new) != old); + }while (atomic_cmpxchg (&net->ipv6.fib6_sernum, + old, new) != old);return new; }
@@ -841,7 +840,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info,int err = -ENOMEM ;int allow_create =1 ;int replace_required =0 ; -int sernum =fib6_new_sernum (); +int sernum =fib6_new_sernum (info->nl_net);if (info->nlh) {if (!(info->nlh->nlmsg_flags &NLM_F_CREATE ))
@@ -1612,7 +1611,7 @@ static int fib6_update_sernum(struct rt6_info *rt, void *arg)static void fib6_flush_trees (struct net *net) { -int new_sernum =fib6_new_sernum (); +int new_sernum =fib6_new_sernum (net);fib6_clean_all (net, fib6_update_sernum, &new_sernum); }
Signature · 1 line
1.9.3
PATCH v2 5/5 ipv6: don't walk node's leaf during serial number update
In reply to Hannes Frederic Sowa--- net/ipv6/ip6_fib.c | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-)
net/ipv6/ip6_fib.c +30 -17
@@ -50,6 +50,7 @@ struct fib6_cleaner {struct fib6_walker w;struct net *net;int (*func)(struct rt6_info *,void *arg); +int sernum;void *arg; };
@@ -105,6 +106,10 @@ static int fib6_new_sernum(struct net *net)return new; } +enum { +FIB6_NO_SERNUM_CHANGE =0 , +}; +/* * Auxiliary address test functions for the radix tree. *
@@ -1514,6 +1519,16 @@ static int fib6_clean_node(struct fib6_walker *w) .nl_net = c->net, }; +if (c->sernum !=FIB6_NO_SERNUM_CHANGE && + w->node->fn_sernum != c->sernum) + w->node->fn_sernum = c->sernum; + +if (!c->func) { +WARN_ON_ONCE (c->sernum ==FIB6_NO_SERNUM_CHANGE ); + w->leaf =NULL ; +return 0 ; + } +for (rt = w->leaf; rt; rt = rt->dst.rt6_next) { res = c->func (rt, c->arg);if (res <0 ) {
@@ -1547,7 +1562,7 @@ static int fib6_clean_node(struct fib6_walker *w)static void fib6_clean_tree (struct net *net,struct fib6_node *root,int (*func)(struct rt6_info *,void *arg), -bool prune,void *arg) +bool prune,int sernum,void *arg) {struct fib6_cleaner c;
@@ -1557,14 +1572,16 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root, c.w.count =0 ; c.w.skip =0 ; c.func = func; + c.sernum = sernum; c.arg = arg; c.net = net;fib6_walk (&c.w); } -void fib6_clean_all (struct net *net,int (*func)(struct rt6_info *,void *arg), -void *arg) +static void __fib6_clean_all (struct net *net, +int (*func)(struct rt6_info *,void *), +int sernum,void *arg) {struct fib6_table *table;struct hlist_head *head;
@@ -1576,13 +1593,19 @@ void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg),hlist_for_each_entry_rcu (table, head, tb6_hlist) {write_lock_bh (&table->tb6_lock);fib6_clean_tree (net, &table->tb6_root, - func, false, arg); + func, false, sernum, arg);write_unlock_bh (&table->tb6_lock); } }rcu_read_unlock (); } +void fib6_clean_all (struct net *net,int (*func)(struct rt6_info *,void *), +void *arg) +{ +__fib6_clean_all (net, func,FIB6_NO_SERNUM_CHANGE , arg); +} +static int fib6_prune_clone (struct rt6_info *rt,void *arg) {if (rt->rt6i_flags &RTF_CACHE ) {
@@ -1595,25 +1618,15 @@ static int fib6_prune_clone(struct rt6_info *rt, void *arg)static void fib6_prune_clones (struct net *net,struct fib6_node *fn) { -fib6_clean_tree (net, fn, fib6_prune_clone, true,NULL ); -} - -static int fib6_update_sernum (struct rt6_info *rt,void *arg) -{ -int sernum = *(int *)arg; - -if (rt->rt6i_node && - rt->rt6i_node->fn_sernum != sernum) - rt->rt6i_node->fn_sernum = sernum; - -return 0 ; +fib6_clean_tree (net, fn, fib6_prune_clone, true, +FIB6_NO_SERNUM_CHANGE ,NULL ); }static void fib6_flush_trees (struct net *net) {int new_sernum =fib6_new_sernum (net); -fib6_clean_all (net, fib6_update_sernum, &new_sernum); +__fib6_clean_all (net,NULL , new_sernum,NULL ); }/*
Signature · 1 line
1.9.3
David Miller
maintainerFrom: Hannes Frederic Sowa <[email protected]>
Date: Mon, 6 Oct 2014 19:58:33 +0200
Quoted 9 lines
Leftover patches after
rt6_genidremoval after705f1c869d577c("ipv6:
removert6i_genid").Major two changes are:
* keepfib6_sernumper namespace to reduce number of flushes in case system has high number of namespaces
* makefn_sernumupdates cheaperv2: Incorporated feedback from Cong Wang, thanks a lot!
Series applied, thanks.