Commit 55c894f7 authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller
Browse files

net: fib_notifier: propagate possible error during fib notifier registration



Unlike events for registered notifier, during the registration, the
errors that happened for the block being registered are not propagated
up to the caller. Make sure the error is propagated for FIB rules and
entries.

Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7c550daf
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -229,7 +229,7 @@ int __net_init fib4_notifier_init(struct net *net);
void __net_exit fib4_notifier_exit(struct net *net);

void fib_info_notify_update(struct net *net, struct nl_info *info);
void fib_notify(struct net *net, struct notifier_block *nb);
int fib_notify(struct net *net, struct notifier_block *nb);

struct fib_table {
	struct hlist_node	tb_hlist;
+8 −3
Original line number Diff line number Diff line
@@ -354,15 +354,20 @@ int fib_rules_dump(struct net *net, struct notifier_block *nb, int family)
{
	struct fib_rules_ops *ops;
	struct fib_rule *rule;
	int err = 0;

	ops = lookup_rules_ops(net, family);
	if (!ops)
		return -EAFNOSUPPORT;
	list_for_each_entry_rcu(rule, &ops->rules_list, list)
		call_fib_rule_notifier(nb, FIB_EVENT_RULE_ADD, rule, family);
	list_for_each_entry_rcu(rule, &ops->rules_list, list) {
		err = call_fib_rule_notifier(nb, FIB_EVENT_RULE_ADD,
					     rule, family);
		if (err)
			break;
	}
	rules_ops_put(ops);

	return 0;
	return err;
}
EXPORT_SYMBOL_GPL(fib_rules_dump);

+1 −3
Original line number Diff line number Diff line
@@ -42,9 +42,7 @@ static int fib4_dump(struct net *net, struct notifier_block *nb)
	if (err)
		return err;

	fib_notify(net, nb);

	return 0;
	return fib_notify(net, nb);
}

static const struct fib_notifier_ops fib4_notifier_ops_template = {
+22 −9
Original line number Diff line number Diff line
@@ -2015,10 +2015,11 @@ void fib_info_notify_update(struct net *net, struct nl_info *info)
	}
}

static void fib_leaf_notify(struct key_vector *l, struct fib_table *tb,
static int fib_leaf_notify(struct key_vector *l, struct fib_table *tb,
			   struct notifier_block *nb)
{
	struct fib_alias *fa;
	int err;

	hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) {
		struct fib_info *fi = fa->fa_info;
@@ -2032,38 +2033,50 @@ static void fib_leaf_notify(struct key_vector *l, struct fib_table *tb,
		if (tb->tb_id != fa->tb_id)
			continue;

		call_fib_entry_notifier(nb, FIB_EVENT_ENTRY_ADD, l->key,
		err = call_fib_entry_notifier(nb, FIB_EVENT_ENTRY_ADD, l->key,
					      KEYLENGTH - fa->fa_slen, fa);
		if (err)
			return err;
	}
	return 0;
}

static void fib_table_notify(struct fib_table *tb, struct notifier_block *nb)
static int fib_table_notify(struct fib_table *tb, struct notifier_block *nb)
{
	struct trie *t = (struct trie *)tb->tb_data;
	struct key_vector *l, *tp = t->kv;
	t_key key = 0;
	int err;

	while ((l = leaf_walk_rcu(&tp, key)) != NULL) {
		fib_leaf_notify(l, tb, nb);
		err = fib_leaf_notify(l, tb, nb);
		if (err)
			return err;

		key = l->key + 1;
		/* stop in case of wrap around */
		if (key < l->key)
			break;
	}
	return 0;
}

void fib_notify(struct net *net, struct notifier_block *nb)
int fib_notify(struct net *net, struct notifier_block *nb)
{
	unsigned int h;
	int err;

	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
		struct hlist_head *head = &net->ipv4.fib_table_hash[h];
		struct fib_table *tb;

		hlist_for_each_entry_rcu(tb, head, tb_hlist)
			fib_table_notify(tb, nb);
		hlist_for_each_entry_rcu(tb, head, tb_hlist) {
			err = fib_table_notify(tb, nb);
			if (err)
				return err;
		}
	}
	return 0;
}

static void __trie_free_rcu(struct rcu_head *head)
+15 −7
Original line number Diff line number Diff line
@@ -409,17 +409,25 @@ int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family,
			if (!v->dev)
				continue;

			mr_call_vif_notifier(nb, family,
			err = mr_call_vif_notifier(nb, family,
						   FIB_EVENT_VIF_ADD,
						   v, vifi, mrt->id);
			if (err)
				break;
		}
		read_unlock(mrt_lock);

		if (err)
			return err;

		/* Notify on table MFC entries */
		list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list)
			mr_call_mfc_notifier(nb, family,
		list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
			err = mr_call_mfc_notifier(nb, family,
						   FIB_EVENT_ENTRY_ADD,
						   mfc, mrt->id);
			if (err)
				return err;
		}
	}

	return 0;
Loading