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

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

ipv4: Add fib_nh_common to fib_result



Most of the ipv4 code only needs data from fib_nh_common. Add
fib_nh_common selection to fib_result and update users to use it.

Right now, fib_nh_common in fib_result will point to a fib_nh struct
that is embedded within a fib_info:

        fib_info  --> fib_nh
                      fib_nh
                      ...
                      fib_nh
                        ^
    fib_result->nhc ----+

Later, nhc can point to a fib_nh within a nexthop struct:

        fib_info --> nexthop --> fib_nh
                                   ^
    fib_result->nhc ---------------+

or for a nexthop group:

        fib_info --> nexthop --> nexthop --> fib_nh
                                 nexthop --> fib_nh
                                 ...
                                 nexthop --> fib_nh
                                               ^
    fib_result->nhc ---------------------------+

In all cases nhsel within fib_result will point to which leg in the
multipath route is used.

Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0af7e7c1
Loading
Loading
Loading
Loading
+21 −26
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ struct fib_result {
	unsigned char		type;
	unsigned char		scope;
	u32			tclassid;
	struct fib_nh_common	*nhc;
	struct fib_info		*fi;
	struct fib_table	*table;
	struct hlist_head	*fa_head;
@@ -182,11 +183,10 @@ struct fib_result_nl {
	int             err;
};

#ifdef CONFIG_IP_ROUTE_MULTIPATH
#define FIB_RES_NH(res)		((res).fi->fib_nh[(res).nh_sel])
#else /* CONFIG_IP_ROUTE_MULTIPATH */
#define FIB_RES_NH(res)		((res).fi->fib_nh[0])
#endif /* CONFIG_IP_ROUTE_MULTIPATH */
static inline struct fib_nh_common *fib_info_nhc(struct fib_info *fi, int nhsel)
{
	return &fi->fib_nh[nhsel].nh_common;
}

#ifdef CONFIG_IP_MULTIPLE_TABLES
#define FIB_TABLE_HASHSZ 256
@@ -195,18 +195,11 @@ struct fib_result_nl {
#endif

__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh);
__be32 fib_result_prefsrc(struct net *net, struct fib_result *res);

#define FIB_RES_SADDR(net, res)				\
	((FIB_RES_NH(res).nh_saddr_genid ==		\
	  atomic_read(&(net)->ipv4.dev_addr_genid)) ?	\
	 FIB_RES_NH(res).nh_saddr :			\
	 fib_info_update_nh_saddr((net), &FIB_RES_NH(res)))
#define FIB_RES_GW(res)			(FIB_RES_NH(res).fib_nh_gw4)
#define FIB_RES_DEV(res)		(FIB_RES_NH(res).fib_nh_dev)
#define FIB_RES_OIF(res)		(FIB_RES_NH(res).fib_nh_oif)

#define FIB_RES_PREFSRC(net, res)	((res).fi->fib_prefsrc ? : \
					 FIB_RES_SADDR(net, res))
#define FIB_RES_NHC(res)		((res).nhc)
#define FIB_RES_DEV(res)	(FIB_RES_NHC(res)->nhc_dev)
#define FIB_RES_OIF(res)	(FIB_RES_NHC(res)->nhc_oif)

struct fib_entry_notifier_info {
	struct fib_notifier_info info; /* must be first */
@@ -453,10 +446,12 @@ struct fib_table *fib_trie_table(u32 id, struct fib_table *alias);
static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
{
#ifdef CONFIG_IP_ROUTE_CLASSID
	struct fib_nh_common *nhc = res->nhc;
	struct fib_nh *nh = container_of(nhc, struct fib_nh, nh_common);
#ifdef CONFIG_IP_MULTIPLE_TABLES
	u32 rtag;
#endif
	*itag = FIB_RES_NH(*res).nh_tclassid<<16;
	*itag = nh->nh_tclassid << 16;
#ifdef CONFIG_IP_MULTIPLE_TABLES
	rtag = res->tclassid;
	if (*itag == 0)
+6 −6
Original line number Diff line number Diff line
@@ -4555,11 +4555,11 @@ static int bpf_fib_set_fwd_params(struct bpf_fib_lookup *params,
static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
			       u32 flags, bool check_mtu)
{
	struct fib_nh_common *nhc;
	struct in_device *in_dev;
	struct neighbour *neigh;
	struct net_device *dev;
	struct fib_result res;
	struct fib_nh *nh;
	struct flowi4 fl4;
	int err;
	u32 mtu;
@@ -4632,15 +4632,15 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
			return BPF_FIB_LKUP_RET_FRAG_NEEDED;
	}

	nh = &res.fi->fib_nh[res.nh_sel];
	nhc = res.nhc;

	/* do not handle lwt encaps right now */
	if (nh->fib_nh_lws)
	if (nhc->nhc_lwtstate)
		return BPF_FIB_LKUP_RET_UNSUPP_LWT;

	dev = nh->fib_nh_dev;
	if (nh->fib_nh_gw4)
		params->ipv4_dst = nh->fib_nh_gw4;
	dev = nhc->nhc_dev;
	if (nhc->nhc_has_gw)
		params->ipv4_dst = nhc->nhc_gw.ipv4;

	params->rt_metric = res.fi->fib_priority;

+3 −3
Original line number Diff line number Diff line
@@ -307,7 +307,7 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb)
			.flowi4_mark = vmark ? skb->mark : 0,
		};
		if (!fib_lookup(net, &fl4, &res, 0))
			return FIB_RES_PREFSRC(net, res);
			return fib_result_prefsrc(net, &res);
	} else {
		scope = RT_SCOPE_LINK;
	}
@@ -390,7 +390,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,

	dev_match = fib_info_nh_uses_dev(res.fi, dev);
	if (dev_match) {
		ret = FIB_RES_NH(res).fib_nh_scope >= RT_SCOPE_HOST;
		ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_HOST;
		return ret;
	}
	if (no_addr)
@@ -402,7 +402,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
	ret = 0;
	if (fib_lookup(net, &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE) == 0) {
		if (res.type == RTN_UNICAST)
			ret = FIB_RES_NH(res).fib_nh_scope >= RT_SCOPE_HOST;
			ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_HOST;
	}
	return ret;

+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ static inline void fib_result_assign(struct fib_result *res,
{
	/* we used to play games with refcounts, but we now use RCU */
	res->fi = fi;
	res->nhc = fib_info_nhc(fi, 0);
}

struct fib_prop {
+21 −4
Original line number Diff line number Diff line
@@ -1075,6 +1075,21 @@ __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh)
	return nh->nh_saddr;
}

__be32 fib_result_prefsrc(struct net *net, struct fib_result *res)
{
	struct fib_nh_common *nhc = res->nhc;
	struct fib_nh *nh;

	if (res->fi->fib_prefsrc)
		return res->fi->fib_prefsrc;

	nh = container_of(nhc, struct fib_nh, nh_common);
	if (nh->nh_saddr_genid == atomic_read(&net->ipv4.dev_addr_genid))
		return nh->nh_saddr;

	return fib_info_update_nh_saddr(net, nh);
}

static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc)
{
	if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst ||
@@ -1762,20 +1777,22 @@ void fib_select_multipath(struct fib_result *res, int hash)
	struct net *net = fi->fib_net;
	bool first = false;

	for_nexthops(fi) {
	change_nexthops(fi) {
		if (net->ipv4.sysctl_fib_multipath_use_neigh) {
			if (!fib_good_nh(nh))
			if (!fib_good_nh(nexthop_nh))
				continue;
			if (!first) {
				res->nh_sel = nhsel;
				res->nhc = &nexthop_nh->nh_common;
				first = true;
			}
		}

		if (hash > atomic_read(&nh->fib_nh_upper_bound))
		if (hash > atomic_read(&nexthop_nh->fib_nh_upper_bound))
			continue;

		res->nh_sel = nhsel;
		res->nhc = &nexthop_nh->nh_common;
		return;
	} endfor_nexthops(fi);
}
@@ -1802,5 +1819,5 @@ void fib_select_path(struct net *net, struct fib_result *res,

check_saddr:
	if (!fl4->saddr)
		fl4->saddr = FIB_RES_PREFSRC(net, *res);
		fl4->saddr = fib_result_prefsrc(net, res);
}
Loading