Commit 17a5984e authored by David Ahern's avatar David Ahern Committed by David S. Miller
Browse files

ipv6: Handle all fib6_nh in a nexthop in __find_rr_leaf



Add a hook in __find_rr_leaf to handle nexthop struct in a fib6_info.
nexthop_for_each_fib6_nh is used to walk each fib6_nh in a nexthop and
call find_match. On a match, use the fib6_nh saved in the callback arg
to setup fib6_result.

Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 962b6803
Loading
Loading
Loading
Loading
+47 −2
Original line number Diff line number Diff line
@@ -765,6 +765,24 @@ out:
	return rc;
}

struct fib6_nh_frl_arg {
	u32		flags;
	int		oif;
	int		strict;
	int		*mpri;
	bool		*do_rr;
	struct fib6_nh	*nh;
};

static int rt6_nh_find_match(struct fib6_nh *nh, void *_arg)
{
	struct fib6_nh_frl_arg *arg = _arg;

	arg->nh = nh;
	return find_match(nh, arg->flags, arg->oif, arg->strict,
			  arg->mpri, arg->do_rr);
}

static void __find_rr_leaf(struct fib6_info *f6i_start,
			   struct fib6_info *nomatch, u32 metric,
			   struct fib6_result *res, struct fib6_info **cont,
@@ -775,6 +793,7 @@ static void __find_rr_leaf(struct fib6_info *f6i_start,
	for (f6i = f6i_start;
	     f6i && f6i != nomatch;
	     f6i = rcu_dereference(f6i->fib6_next)) {
		bool matched = false;
		struct fib6_nh *nh;

		if (cont && f6i->fib6_metric != metric) {
@@ -785,8 +804,34 @@ static void __find_rr_leaf(struct fib6_info *f6i_start,
		if (fib6_check_expired(f6i))
			continue;

		if (unlikely(f6i->nh)) {
			struct fib6_nh_frl_arg arg = {
				.flags  = f6i->fib6_flags,
				.oif    = oif,
				.strict = strict,
				.mpri   = mpri,
				.do_rr  = do_rr
			};

			if (nexthop_is_blackhole(f6i->nh)) {
				res->fib6_flags = RTF_REJECT;
				res->fib6_type = RTN_BLACKHOLE;
				res->f6i = f6i;
				res->nh = nexthop_fib6_nh(f6i->nh);
				return;
			}
			if (nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_find_match,
						     &arg)) {
				matched = true;
				nh = arg.nh;
			}
		} else {
			nh = f6i->fib6_nh;
		if (find_match(nh, f6i->fib6_flags, oif, strict, mpri, do_rr)) {
			if (find_match(nh, f6i->fib6_flags, oif, strict,
				       mpri, do_rr))
				matched = true;
		}
		if (matched) {
			res->f6i = f6i;
			res->nh = nh;
			res->fib6_flags = f6i->fib6_flags;