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

ipv6: Rename fib6_multipath_select and pass fib6_result



Add 'struct fib6_result' to hold the fib entry and fib6_nh from a fib
lookup as separate entries, similar to what IPv4 now has with fib_result.

Rename fib6_multipath_select to fib6_select_path, pass fib6_result to
it, and set f6i and nh in the result once a path selection is done.
Call fib6_select_path unconditionally for path selection which means
moving the sibling and oif check to fib6_select_path. To handle the two
different call paths (2 only call multipath_select if flowi6_oif == 0 and
the other always calls it), add a new have_oif_match that controls the
sibling walk if relevant.

Update callers of fib6_multipath_select accordingly and have them use the
fib6_info and fib6_nh from the result.

This is needed for multipath nexthop objects where a single f6i can
point to multiple fib6_nh (similar to IPv4).

Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6b0a7f84
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -190,6 +190,11 @@ struct rt6_info {
	unsigned short			rt6i_nfheader_len;
};

struct fib6_result {
	struct fib6_nh		*nh;
	struct fib6_info	*f6i;
};

#define for_each_fib6_node_rt_rcu(fn)					\
	for (rt = rcu_dereference((fn)->leaf); rt;			\
	     rt = rcu_dereference(rt->fib6_next))
@@ -391,11 +396,9 @@ struct fib6_info *fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table,
				    int oif, struct flowi6 *fl6, int strict);

struct fib6_info *fib6_multipath_select(const struct net *net,
					struct fib6_info *match,
					struct flowi6 *fl6, int oif,
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_node *fib6_node_lookup(struct fib6_node *root,
				   const struct in6_addr *daddr,
				   const struct in6_addr *saddr);
+4 −5
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
struct fib6_info;
struct fib6_nh;
struct fib6_config;
struct fib6_result;

/* This is ugly, ideally these symbols should be built
 * into the core kernel.
@@ -34,11 +35,9 @@ struct ipv6_stub {
					      struct fib6_table *table,
					      int oif, struct flowi6 *fl6,
					      int flags);
	struct fib6_info *(*fib6_multipath_select)(const struct net *net,
						   struct fib6_info *f6i,
						   struct flowi6 *fl6, int oif,
						   const struct sk_buff *skb,
						   int strict);
	void (*fib6_select_path)(const struct net *net, struct fib6_result *res,
				 struct flowi6 *fl6, int oif, bool oif_match,
				 const struct sk_buff *skb, int strict);
	u32 (*ip6_mtu_from_fib6)(struct fib6_info *f6i, struct in6_addr *daddr,
				 struct in6_addr *saddr);

+17 −17
Original line number Diff line number Diff line
@@ -4679,9 +4679,9 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
	struct in6_addr *src = (struct in6_addr *) params->ipv6_src;
	struct in6_addr *dst = (struct in6_addr *) params->ipv6_dst;
	struct neighbour *neigh;
	struct fib6_result res;
	struct net_device *dev;
	struct inet6_dev *idev;
	struct fib6_info *f6i;
	struct flowi6 fl6;
	int strict = 0;
	int oif;
@@ -4726,21 +4726,23 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
		if (unlikely(!tb))
			return BPF_FIB_LKUP_RET_NOT_FWDED;

		f6i = ipv6_stub->fib6_table_lookup(net, tb, oif, &fl6, strict);
		res.f6i = ipv6_stub->fib6_table_lookup(net, tb, oif, &fl6,
						       strict);
	} else {
		fl6.flowi6_mark = 0;
		fl6.flowi6_secid = 0;
		fl6.flowi6_tun_key.tun_id = 0;
		fl6.flowi6_uid = sock_net_uid(net, NULL);

		f6i = ipv6_stub->fib6_lookup(net, oif, &fl6, strict);
		res.f6i = ipv6_stub->fib6_lookup(net, oif, &fl6, strict);
	}

	if (unlikely(IS_ERR_OR_NULL(f6i) || f6i == net->ipv6.fib6_null_entry))
	if (unlikely(IS_ERR_OR_NULL(res.f6i) ||
		     res.f6i == net->ipv6.fib6_null_entry))
		return BPF_FIB_LKUP_RET_NOT_FWDED;

	if (unlikely(f6i->fib6_flags & RTF_REJECT)) {
		switch (f6i->fib6_type) {
	if (unlikely(res.f6i->fib6_flags & RTF_REJECT)) {
		switch (res.f6i->fib6_type) {
		case RTN_BLACKHOLE:
			return BPF_FIB_LKUP_RET_BLACKHOLE;
		case RTN_UNREACHABLE:
@@ -4752,28 +4754,26 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
		}
	}

	if (f6i->fib6_type != RTN_UNICAST)
	if (res.f6i->fib6_type != RTN_UNICAST)
		return BPF_FIB_LKUP_RET_NOT_FWDED;

	if (f6i->fib6_nsiblings && fl6.flowi6_oif == 0)
		f6i = ipv6_stub->fib6_multipath_select(net, f6i, &fl6,
						       fl6.flowi6_oif, NULL,
						       strict);
	ipv6_stub->fib6_select_path(net, &res, &fl6, fl6.flowi6_oif,
				    fl6.flowi6_oif != 0, NULL, strict);

	if (check_mtu) {
		mtu = ipv6_stub->ip6_mtu_from_fib6(f6i, dst, src);
		mtu = ipv6_stub->ip6_mtu_from_fib6(res.f6i, dst, src);
		if (params->tot_len > mtu)
			return BPF_FIB_LKUP_RET_FRAG_NEEDED;
	}

	if (f6i->fib6_nh.fib_nh_lws)
	if (res.nh->fib_nh_lws)
		return BPF_FIB_LKUP_RET_UNSUPP_LWT;

	if (f6i->fib6_nh.fib_nh_gw_family)
		*dst = f6i->fib6_nh.fib_nh_gw6;
	if (res.nh->fib_nh_gw_family)
		*dst = res.nh->fib_nh_gw6;

	dev = f6i->fib6_nh.fib_nh_dev;
	params->rt_metric = f6i->fib6_metric;
	dev = res.nh->fib_nh_dev;
	params->rt_metric = res.f6i->fib6_metric;

	/* xdp and cls_bpf programs are run in RCU-bh so rcu_read_lock_bh is
	 * not needed here.
+5 −6
Original line number Diff line number Diff line
@@ -158,12 +158,11 @@ eafnosupport_fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
	return NULL;
}

static struct fib6_info *
eafnosupport_fib6_multipath_select(const struct net *net, struct fib6_info *f6i,
				   struct flowi6 *fl6, int oif,
static void
eafnosupport_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)
{
	return f6i;
}

static u32
@@ -187,7 +186,7 @@ const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) {
	.fib6_get_table    = eafnosupport_fib6_get_table,
	.fib6_table_lookup = eafnosupport_fib6_table_lookup,
	.fib6_lookup       = eafnosupport_fib6_lookup,
	.fib6_multipath_select = eafnosupport_fib6_multipath_select,
	.fib6_select_path  = eafnosupport_fib6_select_path,
	.ip6_mtu_from_fib6 = eafnosupport_ip6_mtu_from_fib6,
	.fib6_nh_init	   = eafnosupport_fib6_nh_init,
};
+1 −1
Original line number Diff line number Diff line
@@ -917,7 +917,7 @@ static const struct ipv6_stub ipv6_stub_impl = {
	.fib6_get_table	   = fib6_get_table,
	.fib6_table_lookup = fib6_table_lookup,
	.fib6_lookup       = fib6_lookup,
	.fib6_multipath_select = fib6_multipath_select,
	.fib6_select_path  = fib6_select_path,
	.ip6_mtu_from_fib6 = ip6_mtu_from_fib6,
	.fib6_nh_init	   = fib6_nh_init,
	.fib6_nh_release   = fib6_nh_release,
Loading