Tue, Nov 15, 2016 at 11:46:06AM CET, alexander.h.du...@intel.com wrote: >The patch that removed the FIB offload infrastructure was a bit too >aggressive and also removed code needed to clean up us splitting the table >if additional rules were added. Specifically the function >fib_trie_flush_external was called at the end of a new rule being added to >flush the foreign trie entries from the main trie. > >I updated the code so that we only call fib_trie_flush_external on the main >table so that we flush the entries for local from main. This way we don't >call it for every rule change which is what was happening previously.
Well, the function was introduced by: commit 104616e74e0b464d449fdd2ee2f547d2fad71610 Author: Scott Feldman <sfel...@gmail.com> Date: Thu Mar 5 21:21:16 2015 -0800 switchdev: don't support custom ip rules, for now Keep switchdev FIB offload model simple for now and don't allow custom ip rules. Why this was not needed before? What changed in between: 104616e74e0b464d449fdd2ee2f547d2fad71610 ("switchdev: don't support custom ip rules, for now") and 347e3b28c1ba2 ("switchdev: remove FIB offload infrastructure") ? > >Fixes: 347e3b28c1ba2 ("switchdev: remove FIB offload infrastructure") >Reported-by: Eric Dumazet <eduma...@google.com> >Cc: Jiri Pirko <j...@mellanox.com> >Signed-off-by: Alexander Duyck <alexander.h.du...@intel.com> >--- > include/net/ip_fib.h | 1 + > net/ipv4/fib_frontend.c | 20 +++++++++++--- > net/ipv4/fib_trie.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 81 insertions(+), 5 deletions(-) > >diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h >index b9314b4..f390c3b 100644 >--- a/include/net/ip_fib.h >+++ b/include/net/ip_fib.h >@@ -243,6 +243,7 @@ int fib_table_dump(struct fib_table *table, struct sk_buff >*skb, > struct netlink_callback *cb); > int fib_table_flush(struct net *net, struct fib_table *table); > struct fib_table *fib_trie_unmerge(struct fib_table *main_tb); >+void fib_table_flush_external(struct fib_table *table); > void fib_free_table(struct fib_table *tb); > > #ifndef CONFIG_IP_MULTIPLE_TABLES >diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c >index c3b8047..161fc0f 100644 >--- a/net/ipv4/fib_frontend.c >+++ b/net/ipv4/fib_frontend.c >@@ -151,7 +151,7 @@ static void fib_replace_table(struct net *net, struct >fib_table *old, > > int fib_unmerge(struct net *net) > { >- struct fib_table *old, *new; >+ struct fib_table *old, *new, *main_table; > > /* attempt to fetch local table if it has been allocated */ > old = fib_get_table(net, RT_TABLE_LOCAL); >@@ -162,11 +162,21 @@ int fib_unmerge(struct net *net) > if (!new) > return -ENOMEM; > >+ /* table is already unmerged */ >+ if (new == old) >+ return 0; >+ > /* replace merged table with clean table */ >- if (new != old) { >- fib_replace_table(net, old, new); >- fib_free_table(old); >- } >+ fib_replace_table(net, old, new); >+ fib_free_table(old); >+ >+ /* attempt to fetch main table if it has been allocated */ >+ main_table = fib_get_table(net, RT_TABLE_MAIN); >+ if (!main_table) >+ return 0; >+ >+ /* flush local entries from main table */ >+ fib_table_flush_external(main_table); > > return 0; > } >diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c >index 4cff74d..735edc9 100644 >--- a/net/ipv4/fib_trie.c >+++ b/net/ipv4/fib_trie.c >@@ -1760,6 +1760,71 @@ struct fib_table *fib_trie_unmerge(struct fib_table >*oldtb) > return NULL; > } > >+/* Caller must hold RTNL */ >+void fib_table_flush_external(struct fib_table *tb) >+{ >+ struct trie *t = (struct trie *)tb->tb_data; >+ struct key_vector *pn = t->kv; >+ unsigned long cindex = 1; >+ struct hlist_node *tmp; >+ struct fib_alias *fa; >+ >+ /* walk trie in reverse order */ >+ for (;;) { >+ unsigned char slen = 0; >+ struct key_vector *n; >+ >+ if (!(cindex--)) { >+ t_key pkey = pn->key; >+ >+ /* cannot resize the trie vector */ >+ if (IS_TRIE(pn)) >+ break; >+ >+ /* resize completed node */ >+ pn = resize(t, pn); >+ cindex = get_index(pkey, pn); >+ >+ continue; >+ } >+ >+ /* grab the next available node */ >+ n = get_child(pn, cindex); >+ if (!n) >+ continue; >+ >+ if (IS_TNODE(n)) { >+ /* record pn and cindex for leaf walking */ >+ pn = n; >+ cindex = 1ul << n->bits; >+ >+ continue; >+ } >+ >+ hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) { >+ /* if alias was cloned to local then we just >+ * need to remove the local copy from main >+ */ >+ if (tb->tb_id != fa->tb_id) { >+ hlist_del_rcu(&fa->fa_list); >+ alias_free_mem_rcu(fa); >+ continue; >+ } >+ >+ /* record local slen */ >+ slen = fa->fa_slen; >+ } >+ >+ /* update leaf slen */ >+ n->slen = slen; >+ >+ if (hlist_empty(&n->leaf)) { >+ put_child_root(pn, n->key, NULL); >+ node_free(n); >+ } >+ } >+} >+ > /* Caller must hold RTNL. */ > int fib_table_flush(struct net *net, struct fib_table *tb) > { >