Commit 613f727c authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'ipv6-multipath-routing-fixes'

Ido Schimmel says:

====================
ipv6: Multipath routing fixes

This patchset contains two fixes for IPv6 multipath routing. See the
commit messages for more details.
====================

Link: https://patch.msgid.link/20250402114224.293392-1-idosch@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 51de3600 8b8e0dd3
Loading
Loading
Loading
Loading
+38 −4
Original line number Diff line number Diff line
@@ -412,12 +412,37 @@ static bool rt6_check_expired(const struct rt6_info *rt)
	return false;
}

static struct fib6_info *
rt6_multipath_first_sibling_rcu(const struct fib6_info *rt)
{
	struct fib6_info *iter;
	struct fib6_node *fn;

	fn = rcu_dereference(rt->fib6_node);
	if (!fn)
		goto out;
	iter = rcu_dereference(fn->leaf);
	if (!iter)
		goto out;

	while (iter) {
		if (iter->fib6_metric == rt->fib6_metric &&
		    rt6_qualify_for_ecmp(iter))
			return iter;
		iter = rcu_dereference(iter->fib6_next);
	}

out:
	return NULL;
}

void fib6_select_path(const struct net *net, struct fib6_result *res,
		      struct flowi6 *fl6, int oif, bool have_oif_match,
		      const struct sk_buff *skb, int strict)
{
	struct fib6_info *match = res->f6i;
	struct fib6_info *first, *match = res->f6i;
	struct fib6_info *sibling;
	int hash;

	if (!match->nh && (!match->fib6_nsiblings || have_oif_match))
		goto out;
@@ -440,16 +465,25 @@ void fib6_select_path(const struct net *net, struct fib6_result *res,
		return;
	}

	if (fl6->mp_hash <= atomic_read(&match->fib6_nh->fib_nh_upper_bound))
	first = rt6_multipath_first_sibling_rcu(match);
	if (!first)
		goto out;

	list_for_each_entry_rcu(sibling, &match->fib6_siblings,
	hash = fl6->mp_hash;
	if (hash <= atomic_read(&first->fib6_nh->fib_nh_upper_bound) &&
	    rt6_score_route(first->fib6_nh, first->fib6_flags, oif,
			    strict) >= 0) {
		match = first;
		goto out;
	}

	list_for_each_entry_rcu(sibling, &first->fib6_siblings,
				fib6_siblings) {
		const struct fib6_nh *nh = sibling->fib6_nh;
		int nh_upper_bound;

		nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound);
		if (fl6->mp_hash > nh_upper_bound)
		if (hash > nh_upper_bound)
			continue;
		if (rt6_score_route(nh, sibling->fib6_flags, oif, strict) < 0)
			break;