Subject: [PATCH RFC net-next 07/18] net: ipv4: Add fib_nh to fib_result

From: [email-masked]
Date: Fri, 31 Aug 2018 17:49:42 -0700

From: David Ahern <[email-masked]>

Add nexthop selection to fib_result and update FIB_RES macros to
use it. Right now, fib_nh in fib_result will point to a nexthop
within a fib_info. Later, fib_nh can point to data with a nexthop.

Signed-off-by: David Ahern <[email-masked]>
---
 include/net/ip_fib.h     | 21 +++++++++------------
 net/core/filter.c        |  2 +-
 net/ipv4/fib_frontend.c  |  4 ++--
 net/ipv4/fib_semantics.c |  4 ++--
 net/ipv4/fib_trie.c      |  4 ++--
 net/ipv4/route.c         | 18 +++++++++---------
 6 files changed, 25 insertions(+), 28 deletions(-)

diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index ce9b92485064..0b40c59b8a5f 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -141,6 +141,7 @@ struct fib_result {
 	unsigned char	type;
 	unsigned char	scope;
 	u32		tclassid;
+	struct fib_nh	*nh;
 	struct fib_info *fi;
 	struct fib_table *table;
 	struct hlist_head *fa_head;
@@ -161,11 +162,7 @@ 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 */
+#define FIB_RES_NH(res)		((res).nh)
 
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 #define FIB_TABLE_HASHSZ 256
@@ -177,13 +174,13 @@ __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh,
 				unsigned char scope);
 
 #define FIB_RES_SADDR(net, res)				\
-	((FIB_RES_NH(res).nh_saddr_genid ==		\
+	((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), (res).fi->fib_scope))
-#define FIB_RES_GW(res)			(FIB_RES_NH(res).nh_gw)
-#define FIB_RES_DEV(res)		(FIB_RES_NH(res).nh_dev)
-#define FIB_RES_OIF(res)		(FIB_RES_NH(res).nh_oif)
+	 FIB_RES_NH(res)->nh_saddr :			\
+	 fib_info_update_nh_saddr((net), FIB_RES_NH(res), (res).fi->fib_scope))
+#define FIB_RES_GW(res)			(FIB_RES_NH(res)->nh_gw)
+#define FIB_RES_DEV(res)		(FIB_RES_NH(res)->nh_dev)
+#define FIB_RES_OIF(res)		(FIB_RES_NH(res)->nh_oif)
 
 #define FIB_RES_PREFSRC(net, res)	((res).fi->fib_prefsrc ? : \
 					 FIB_RES_SADDR(net, res))
@@ -422,7 +419,7 @@ static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 	u32 rtag;
 #endif
-	*itag = FIB_RES_NH(*res).nh_tclassid<<16;
+	*itag = FIB_RES_NH(*res)->nh_tclassid << 16;
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 	rtag = res->tclassid;
 	if (*itag == 0)
diff --git a/net/core/filter.c b/net/core/filter.c
index c25eb36f1320..0ba4c477415d 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -4311,7 +4311,7 @@ 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];
+	nh = res.nh;
 
 	/* do not handle lwt encaps right now */
 	if (nh->nh_lwtstate)
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index b0910d8c8bd4..2f9bf1ec2678 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -380,7 +380,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
 		dev_match = true;
 #endif
 	if (dev_match) {
-		ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
+		ret = FIB_RES_NH(res)->nh_scope >= RT_SCOPE_HOST;
 		return ret;
 	}
 	if (no_addr)
@@ -392,7 +392,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).nh_scope >= RT_SCOPE_HOST;
+			ret = FIB_RES_NH(res)->nh_scope >= RT_SCOPE_HOST;
 	}
 	return ret;
 
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 0d792666821a..53e38ecfdd58 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -1728,7 +1728,7 @@ void fib_select_multipath(struct fib_result *res, int hash)
 			if (!fib_good_nh(nh))
 				continue;
 			if (!first) {
-				res->nh_sel = nhsel;
+				res->nh = &fi->fib_nh[nhsel];
 				first = true;
 			}
 		}
@@ -1736,7 +1736,7 @@ void fib_select_multipath(struct fib_result *res, int hash)
 		if (hash > atomic_read(&nh->nh_upper_bound))
 			continue;
 
-		res->nh_sel = nhsel;
+		res->nh = &fi->fib_nh[nhsel];
 		return;
 	} endfor_nexthops(fi);
 }
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 5bc0c89e81e4..51e7b38f3a7b 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1468,7 +1468,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
 		if (fi->fib_flags & RTNH_F_DEAD)
 			continue;
 		for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
-			const struct fib_nh *nh = &fi->fib_nh[nhsel];
+			struct fib_nh *nh = &fi->fib_nh[nhsel];
 			struct in_device *in_dev = __in_dev_get_rcu(nh->nh_dev);
 
 			if (nh->nh_flags & RTNH_F_DEAD)
@@ -1489,7 +1489,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
 
 			res->prefix = htonl(n->key);
 			res->prefixlen = KEYLENGTH - fa->fa_slen;
-			res->nh_sel = nhsel;
+			res->nh = nh;
 			res->type = fa->fa_type;
 			res->scope = fi->fib_scope;
 			res->fi = fi;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index b678466da451..1297c7c934a8 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -776,7 +776,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow
 			neigh_event_send(n, NULL);
 		} else {
 			if (fib_lookup(net, fl4, &res, 0) == 0) {
-				struct fib_nh *nh = &FIB_RES_NH(res);
+				struct fib_nh *nh = FIB_RES_NH(res);
 
 				update_or_create_fnhe(nh, fl4->daddr, new_gw,
 						0, false,
@@ -1021,7 +1021,7 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
 
 	rcu_read_lock();
 	if (fib_lookup(dev_net(dst->dev), fl4, &res, 0) == 0) {
-		struct fib_nh *nh = &FIB_RES_NH(res);
+		struct fib_nh *nh = FIB_RES_NH(res);
 
 		update_or_create_fnhe(nh, fl4->daddr, 0, mtu, lock,
 				      jiffies + ip_rt_mtu_expires);
@@ -1350,7 +1350,7 @@ static struct fib_nh_exception *find_exception(struct fib_nh *nh, __be32 daddr)
 u32 ip_mtu_from_fib_result(struct fib_result *res, __be32 daddr)
 {
 	struct fib_info *fi = res->fi;
-	struct fib_nh *nh = &fi->fib_nh[res->nh_sel];
+	struct fib_nh *nh = res->nh;
 	struct net_device *dev = nh->nh_dev;
 	u32 mtu = 0;
 
@@ -1527,7 +1527,7 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
 	bool cached = false;
 
 	if (fi) {
-		struct fib_nh *nh = &FIB_RES_NH(*res);
+		struct fib_nh *nh = FIB_RES_NH(*res);
 
 		if (nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK) {
 			rt->rt_gateway = nh->nh_gw;
@@ -1744,12 +1744,12 @@ static int __mkroute_input(struct sk_buff *skb,
 		}
 	}
 
-	fnhe = find_exception(&FIB_RES_NH(*res), daddr);
+	fnhe = find_exception(FIB_RES_NH(*res), daddr);
 	if (do_cache) {
 		if (fnhe)
 			rth = rcu_dereference(fnhe->fnhe_rth_input);
 		else
-			rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);
+			rth = rcu_dereference(FIB_RES_NH(*res)->nh_rth_input);
 		if (rt_cache_valid(rth)) {
 			skb_dst_set_noref(skb, &rth->dst);
 			goto out;
@@ -2039,7 +2039,7 @@ out:	return err;
 	do_cache = false;
 	if (res->fi) {
 		if (!itag) {
-			rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);
+			rth = rcu_dereference(FIB_RES_NH(*res)->nh_rth_input);
 			if (rt_cache_valid(rth)) {
 				skb_dst_set_noref(skb, &rth->dst);
 				err = 0;
@@ -2069,7 +2069,7 @@ out:	return err;
 	}
 
 	if (do_cache) {
-		struct fib_nh *nh = &FIB_RES_NH(*res);
+		struct fib_nh *nh = FIB_RES_NH(*res);
 
 		rth->dst.lwtstate = lwtstate_get(nh->nh_lwtstate);
 		if (lwtunnel_input_redirect(rth->dst.lwtstate)) {
@@ -2249,7 +2249,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
 	do_cache &= fi != NULL;
 	if (fi) {
 		struct rtable __rcu **prth;
-		struct fib_nh *nh = &FIB_RES_NH(*res);
+		struct fib_nh *nh = FIB_RES_NH(*res);
 
 		fnhe = find_exception(nh, fl4->daddr);
 		if (!do_cache)
-- 
2.11.0