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

Commit cea29a70 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ipv6-Use-fib6_result-for-fib_lookups'



David Ahern says:

====================
ipv6: Use fib6_result for fib_lookups

Add fib6_result as a single data structure to hold results from a fib
lookup. IPv6 currently has everything in 1 data structure - a fib6_info,
but with nexthop objects the fib6_nh can be in a nexthop or a nexthop
can be a blackhole which affects the fib6_type and flags (REJECT).

v2
- fixed 2 bugs in patch12:
  i. checking return from fib6_table_lookup in fib6_lookup
  ii. call to fib6_rule_saddr in fib6_rule_action_alt should use res->nh
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6b0a7f84 7d21fec9
Loading
Loading
Loading
Loading
+15 −9
Original line number Diff line number Diff line
@@ -190,6 +190,13 @@ struct rt6_info {
	unsigned short			rt6i_nfheader_len;
};

struct fib6_result {
	struct fib6_nh		*nh;
	struct fib6_info	*f6i;
	u32			fib6_flags;
	u8			fib6_type;
};

#define for_each_fib6_node_rt_rcu(fn)					\
	for (rt = rcu_dereference((fn)->leaf); rt;			\
	     rt = rcu_dereference(rt->fib6_next))
@@ -384,18 +391,17 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
/* called with rcu lock held; can return error pointer
 * caller needs to select path
 */
struct fib6_info *fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
			      int flags);
int fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
		struct fib6_result *res, int flags);

/* called with rcu lock held; caller needs to select path */
struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table,
				    int oif, struct flowi6 *fl6, int strict);
int fib6_table_lookup(struct net *net, struct fib6_table *table,
		      int oif, struct flowi6 *fl6, struct fib6_result *res,
		      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);
+3 −2
Original line number Diff line number Diff line
@@ -302,8 +302,9 @@ static inline unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
	return mtu;
}

u32 ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr,
		      struct in6_addr *saddr);
u32 ip6_mtu_from_fib6(const struct fib6_result *res,
		      const struct in6_addr *daddr,
		      const struct in6_addr *saddr);

struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,
				   struct net_device *dev, struct sk_buff *skb,
+12 −13
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.
@@ -28,19 +29,17 @@ struct ipv6_stub {
	int (*ipv6_route_input)(struct sk_buff *skb);

	struct fib6_table *(*fib6_get_table)(struct net *net, u32 id);
	struct fib6_info *(*fib6_lookup)(struct net *net, int oif,
					 struct flowi6 *fl6, int flags);
	struct fib6_info *(*fib6_table_lookup)(struct net *net,
					      struct fib6_table *table,
	int (*fib6_lookup)(struct net *net, int oif, struct flowi6 *fl6,
			   struct fib6_result *res, int flags);
	int (*fib6_table_lookup)(struct net *net, 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);
	u32 (*ip6_mtu_from_fib6)(struct fib6_info *f6i, struct in6_addr *daddr,
				 struct in6_addr *saddr);
				 struct fib6_result *res, int flags);
	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)(const struct fib6_result *res,
				 const struct in6_addr *daddr,
				 const struct in6_addr *saddr);

	int (*fib6_nh_init)(struct net *net, struct fib6_nh *fib6_nh,
			    struct fib6_config *cfg, gfp_t gfp_flags,
+8 −8
Original line number Diff line number Diff line
@@ -12,10 +12,10 @@

TRACE_EVENT(fib6_table_lookup,

	TP_PROTO(const struct net *net, const struct fib6_info *f6i,
	TP_PROTO(const struct net *net, const struct fib6_result *res,
		 struct fib6_table *table, const struct flowi6 *flp),

	TP_ARGS(net, f6i, table, flp),
	TP_ARGS(net, res, table, flp),

	TP_STRUCT__entry(
		__field(	u32,	tb_id		)
@@ -39,7 +39,7 @@ TRACE_EVENT(fib6_table_lookup,
		struct in6_addr *in6;

		__entry->tb_id = table->tb6_id;
		__entry->err = ip6_rt_type_to_error(f6i->fib6_type);
		__entry->err = ip6_rt_type_to_error(res->fib6_type);
		__entry->oif = flp->flowi6_oif;
		__entry->iif = flp->flowi6_iif;
		__entry->tos = ip6_tclass(flp->flowlabel);
@@ -62,20 +62,20 @@ TRACE_EVENT(fib6_table_lookup,
			__entry->dport = 0;
		}

		if (f6i->fib6_nh.fib_nh_dev) {
			__assign_str(name, f6i->fib6_nh.fib_nh_dev);
		if (res->nh && res->nh->fib_nh_dev) {
			__assign_str(name, res->nh->fib_nh_dev);
		} else {
			__assign_str(name, "-");
		}
		if (f6i == net->ipv6.fib6_null_entry) {
		if (res->f6i == net->ipv6.fib6_null_entry) {
			struct in6_addr in6_zero = {};

			in6 = (struct in6_addr *)__entry->gw;
			*in6 = in6_zero;

		} else if (f6i) {
		} else if (res->nh) {
			in6 = (struct in6_addr *)__entry->gw;
			*in6 = f6i->fib6_nh.fib_nh_gw6;
			*in6 = res->nh->fib_nh_gw6;
		}
	),

+27 −29
Original line number Diff line number Diff line
@@ -4679,12 +4679,12 @@ 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;
	int oif, err;
	u32 mtu;

	/* link local addresses are never forwarded */
@@ -4726,21 +4726,25 @@ 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);
		err = ipv6_stub->fib6_table_lookup(net, tb, oif, &fl6, &res,
						   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);
		err = ipv6_stub->fib6_lookup(net, oif, &fl6, &res, strict);
	}

	if (unlikely(IS_ERR_OR_NULL(f6i) || f6i == net->ipv6.fib6_null_entry))
	if (unlikely(err || 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) {
	switch (res.fib6_type) {
	/* only unicast is forwarded */
	case RTN_UNICAST:
		break;
	case RTN_BLACKHOLE:
		return BPF_FIB_LKUP_RET_BLACKHOLE;
	case RTN_UNREACHABLE:
@@ -4750,30 +4754,24 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
	default:
		return BPF_FIB_LKUP_RET_NOT_FWDED;
	}
	}

	if (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, 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.
Loading