Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9195bef7 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller
Browse files

[IPV4] fib_trie: avoid extra search on delete



Get rid of extra search that made route deletion O(n).

Signed-off-by: default avatarStephen Hemminger <shemminger@vyatta.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a88ee229
Loading
Loading
Loading
Loading
+12 −38
Original line number Diff line number Diff line
@@ -1545,49 +1545,23 @@ found:
	return ret;
}

/* only called from updater side */
static int trie_leaf_remove(struct trie *t, t_key key)
{
	t_key cindex;
	struct tnode *tp = NULL;
	struct node *n = t->trie;
	struct leaf *l;

	pr_debug("entering trie_leaf_remove(%p)\n", n);

	/* Note that in the case skipped bits, those bits are *not* checked!
	 * When we finish this, we will have NULL or a T_LEAF, and the
	 * T_LEAF may or may not match our key.
	 */

	while (n != NULL && IS_TNODE(n)) {
		struct tnode *tn = (struct tnode *) n;
		check_tnode(tn);
		n = tnode_get_child(tn, tkey_extract_bits(key,
							  tn->pos, tn->bits));

		BUG_ON(n && node_parent(n) != tn);
	}
	l = (struct leaf *) n;

	if (!n || !tkey_equals(l->key, key))
		return 0;

/*
	 * Key found.
	 * Remove the leaf and rebalance the tree
 * Remove the leaf and return parent.
 */
	tp = node_parent(n);
	tnode_free((struct tnode *) n);
static void trie_leaf_remove(struct trie *t, struct leaf *l)
{
	struct tnode *tp = node_parent((struct node *) l);

	pr_debug("entering trie_leaf_remove(%p)\n", l);

	if (tp) {
		cindex = tkey_extract_bits(key, tp->pos, tp->bits);
		t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits);
		put_child(t, (struct tnode *)tp, cindex, NULL);
		rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
	} else
		rcu_assign_pointer(t->trie, NULL);

	return 1;
	tnode_free((struct tnode *) l);
}

/*
@@ -1665,7 +1639,7 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
	}

	if (hlist_empty(&l->list))
		trie_leaf_remove(t, key);
		trie_leaf_remove(t, l);

	if (fa->fa_state & FA_S_ACCESSED)
		rt_cache_flush(-1);
@@ -1778,19 +1752,19 @@ static struct leaf *trie_nextleaf(struct leaf *l)
static int fn_trie_flush(struct fib_table *tb)
{
	struct trie *t = (struct trie *) tb->tb_data;
	struct leaf *ll = NULL, *l = NULL;
	struct leaf *l, *ll = NULL;
	int found = 0;

	for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
		found += trie_flush_leaf(t, l);

		if (ll && hlist_empty(&ll->list))
			trie_leaf_remove(t, ll->key);
			trie_leaf_remove(t, ll);
		ll = l;
	}

	if (ll && hlist_empty(&ll->list))
		trie_leaf_remove(t, ll->key);
		trie_leaf_remove(t, ll);

	pr_debug("trie_flush found=%d\n", found);
	return found;