|
@@ -1760,6 +1760,71 @@ out:
|
|
|
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)
|
|
|
{
|