Thread (20 messages) 20 messages, 3 authors, 19h ago
HOTtoday

[PATCH 09/13 RFC net-next] net: fib: split common nexthop logic to fib_core.c

From: Fernando Fernandez Mancera <hidden>
Date: 2026-07-12 01:41:30
Also in: bpf, lkml
Subsystem: networking [general], networking [ipv4/ipv6], the rest · Maintainers: "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Linus Torvalds

To enable compiling INET subsystem without IPv4, shared FIB and nexthop
logic must be accessible to IPv6 when IPv4 routing stack is omitted.

This patch creates fib_core.c and move all the functions for common
nexthop initialization and release from fib_semantics.c to fib_core.c.
Note that fib_core.c is under net/core.

Signed-off-by: Fernando Fernandez Mancera <redacted>
---
 include/net/ip_fib.h       |  43 +++++++++++
 include/net/route.h        |   6 ++
 net/core/Makefile          |   2 +-
 net/core/fib_core.c        | 146 +++++++++++++++++++++++++++++++++++++
 net/ipv4/Makefile          |   2 +
 net/ipv4/fib_semantics.c   | 142 ------------------------------------
 net/ipv4/netlink.c         |   2 +
 net/ipv4/nexthop.c         |   2 +-
 net/ipv4/sysctl_net_ipv4.c |   2 +
 net/ipv6/ip6_fib.c         |   2 +
 10 files changed, 205 insertions(+), 144 deletions(-)
 create mode 100644 net/core/fib_core.c
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 0a35355fb0f3..0c56d8690e00 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -250,7 +250,13 @@ int call_fib4_notifiers(struct net *net, enum fib_event_type event_type,
 int __net_init fib4_notifier_init(struct net *net);
 void __net_exit fib4_notifier_exit(struct net *net);
 
+#if IS_ENABLED(CONFIG_IPV4)
 void fib_info_notify_update(struct net *net, struct nl_info *info);
+#else
+static inline void fib_info_notify_update(struct net *net, struct nl_info *info)
+{
+}
+#endif
 int fib_notify(struct net *net, struct notifier_block *nb,
 	       struct netlink_ext_ack *extack);
 
@@ -578,10 +584,23 @@ void fib_select_multipath(struct fib_result *res, int hash,
 void fib_select_path(struct net *net, struct fib_result *res,
 		     struct flowi4 *fl4, const struct sk_buff *skb);
 
+#if IS_ENABLED(CONFIG_IPV4)
 int fib_nh_init(struct net *net, struct fib_nh *fib_nh,
 		struct fib_config *cfg, int nh_weight,
 		struct netlink_ext_ack *extack);
 void fib_nh_release(struct net *net, struct fib_nh *fib_nh);
+#else
+static inline int fib_nh_init(struct net *net, struct fib_nh *fib_nh,
+			      struct fib_config *cfg, int gfp,
+			      struct netlink_ext_ack *extack)
+{
+	return -EAFNOSUPPORT;
+}
+
+static inline void fib_nh_release(struct net *net, struct fib_nh *fib_nh)
+{
+}
+#endif
 int fib_nh_common_init(struct net *net, struct fib_nh_common *nhc,
 		       struct nlattr *fc_encap, u16 fc_encap_type,
 		       void *cfg, gfp_t gfp_flags,
@@ -620,7 +639,13 @@ static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
 #endif
 }
 
+#if IS_ENABLED(CONFIG_IPV4)
 void fib_flush(struct net *net);
+#else
+static inline void fib_flush(struct net *net)
+{
+}
+#endif
 void free_fib_info(struct fib_info *fi);
 
 static inline void fib_info_hold(struct fib_info *fi)
@@ -658,8 +683,26 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
 			  struct fib_dump_filter *filter,
 			  struct netlink_callback *cb);
 
+#if IS_ENABLED(CONFIG_IPV4)
 int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nh,
 		     u8 rt_family, unsigned char *flags, bool skip_oif);
 int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nh,
 		    int nh_weight, u8 rt_family, u32 nh_tclassid);
+#else
+static inline int fib_nexthop_info(struct sk_buff *skb,
+				   const struct fib_nh_common *nh,
+				   u8 rt_family, unsigned char *flags,
+				   bool skip_oif)
+{
+	return 0;
+}
+
+static inline int fib_add_nexthop(struct sk_buff *skb,
+				  const struct fib_nh_common *nh,
+				  int nh_weight, u8 rt_family,
+				  u32 nh_tclassid)
+{
+	return 0;
+}
+#endif
 #endif  /* _NET_FIB_H */
diff --git a/include/net/route.h b/include/net/route.h
index 08adb14224a9..29944be291f8 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -128,7 +128,13 @@ extern struct ip_rt_acct __percpu *ip_rt_acct;
 struct in_device;
 
 int ip_rt_init(void);
+#if IS_ENABLED(CONFIG_IPV4)
 void rt_cache_flush(struct net *net);
+#else
+static inline void rt_cache_flush(struct net *net)
+{
+}
+#endif
 void rt_flush_dev(struct net_device *dev);
 
 static inline void inet_sk_init_flowi4(const struct inet_sock *inet,
diff --git a/net/core/Makefile b/net/core/Makefile
index b3fdcb4e355f..63ebcdc6b9f1 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -12,7 +12,7 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
 obj-y		     += dev.o dev_api.o dev_addr_lists.o dst.o netevent.o \
 			neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
 			sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
-			fib_notifier.o xdp.o flow_offload.o gro.o \
+			fib_notifier.o fib_core.o xdp.o flow_offload.o gro.o \
 			netdev-genl.o netdev-genl-gen.o netdev_work.o gso.o
 
 obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o
diff --git a/net/core/fib_core.c b/net/core/fib_core.c
new file mode 100644
index 000000000000..93894b5847e9
--- /dev/null
+++ b/net/core/fib_core.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/types.h>
+#include <net/lwtunnel.h>
+#include <net/route.h>
+
+static void rt_fibinfo_free(struct rtable __rcu **rtp)
+{
+	struct rtable *rt = rcu_dereference_protected(*rtp, 1);
+
+	if (!rt)
+		return;
+
+	/* Not even needed : RCU_INIT_POINTER(*rtp, NULL);
+	 * because we waited an RCU grace period before calling
+	 * free_fib_info_rcu()
+	 */
+
+	dst_dev_put(&rt->dst);
+	dst_release_immediate(&rt->dst);
+}
+
+static void free_nh_exceptions(struct fib_nh_common *nhc)
+{
+	struct fnhe_hash_bucket *hash;
+	int i;
+
+	hash = rcu_dereference_protected(nhc->nhc_exceptions, 1);
+	if (!hash)
+		return;
+	for (i = 0; i < FNHE_HASH_SIZE; i++) {
+		struct fib_nh_exception *fnhe;
+
+		fnhe = rcu_dereference_protected(hash[i].chain, 1);
+		while (fnhe) {
+			struct fib_nh_exception *next;
+
+			next = rcu_dereference_protected(fnhe->fnhe_next, 1);
+
+			rt_fibinfo_free(&fnhe->fnhe_rth_input);
+			rt_fibinfo_free(&fnhe->fnhe_rth_output);
+
+			kfree(fnhe);
+
+			fnhe = next;
+		}
+	}
+	kfree(hash);
+}
+
+static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp)
+{
+	int cpu;
+
+	if (!rtp)
+		return;
+
+	for_each_possible_cpu(cpu) {
+		struct rtable *rt;
+
+		rt = rcu_dereference_protected(*per_cpu_ptr(rtp, cpu), 1);
+		if (rt) {
+			dst_dev_put(&rt->dst);
+			dst_release_immediate(&rt->dst);
+		}
+	}
+	free_percpu(rtp);
+}
+
+void fib_nh_common_release(struct fib_nh_common *nhc)
+{
+	netdev_put(nhc->nhc_dev, &nhc->nhc_dev_tracker);
+	lwtstate_put(nhc->nhc_lwtstate);
+	rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output);
+	rt_fibinfo_free(&nhc->nhc_rth_input);
+	free_nh_exceptions(nhc);
+}
+
+int fib_nh_common_init(struct net *net, struct fib_nh_common *nhc,
+		       struct nlattr *encap, u16 encap_type,
+		       void *cfg, gfp_t gfp_flags,
+		       struct netlink_ext_ack *extack)
+{
+	int err;
+
+	nhc->nhc_pcpu_rth_output = alloc_percpu_gfp(struct rtable __rcu *,
+						    gfp_flags);
+	if (!nhc->nhc_pcpu_rth_output)
+		return -ENOMEM;
+
+	if (encap) {
+		struct lwtunnel_state *lwtstate;
+
+		err = lwtunnel_build_state(net, encap_type, encap,
+					   nhc->nhc_family, cfg, &lwtstate,
+					   extack);
+		if (err)
+			goto lwt_failure;
+
+		nhc->nhc_lwtstate = lwtstate_get(lwtstate);
+	}
+
+	return 0;
+
+lwt_failure:
+	rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output);
+	nhc->nhc_pcpu_rth_output = NULL;
+	return err;
+}
+
+/* Update the PMTU of exceptions when:
+ * - the new MTU of the first hop becomes smaller than the PMTU
+ * - the old MTU was the same as the PMTU, and it limited discovery of
+ *   larger MTUs on the path. With that limit raised, we can now
+ *   discover larger MTUs
+ * A special case is locked exceptions, for which the PMTU is smaller
+ * than the minimal accepted PMTU:
+ * - if the new MTU is greater than the PMTU, don't make any change
+ * - otherwise, unlock and set PMTU
+ */
+void fib_nhc_update_mtu(struct fib_nh_common *nhc, u32 new, u32 orig)
+{
+	struct fnhe_hash_bucket *bucket;
+	int i;
+
+	bucket = rcu_dereference_protected(nhc->nhc_exceptions, 1);
+	if (!bucket)
+		return;
+
+	for (i = 0; i < FNHE_HASH_SIZE; i++) {
+		struct fib_nh_exception *fnhe;
+
+		for (fnhe = rcu_dereference_protected(bucket[i].chain, 1);
+		     fnhe;
+		     fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) {
+			if (fnhe->fnhe_mtu_locked) {
+				if (new <= fnhe->fnhe_pmtu) {
+					fnhe->fnhe_pmtu = new;
+					fnhe->fnhe_mtu_locked = false;
+				}
+			} else if (new < fnhe->fnhe_pmtu ||
+				   orig == fnhe->fnhe_pmtu) {
+				fnhe->fnhe_pmtu = new;
+			}
+		}
+	}
+}
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 83c25f52eb58..b540d549f25a 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -19,7 +19,9 @@ obj-$(CONFIG_IPV4) += route.o ip_input.o ip_fragment.o ip_forward.o ip_options.o
 obj-$(CONFIG_NET_IP_TUNNEL) += ip_tunnel.o
 obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
 obj-$(CONFIG_PROC_FS) += proc.o
+ifeq ($(CONFIG_IPV4),y)
 obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
+endif
 obj-$(CONFIG_IP_MROUTE) += ipmr.o
 obj-$(CONFIG_IP_MROUTE_COMMON) += ipmr_base.o
 obj-$(CONFIG_NET_IPIP) += ipip.o
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 4f3c0740dde9..6ed252e9559e 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -136,78 +136,6 @@ const struct fib_prop fib_props[RTN_MAX + 1] = {
 	},
 };
 
-static void rt_fibinfo_free(struct rtable __rcu **rtp)
-{
-	struct rtable *rt = rcu_dereference_protected(*rtp, 1);
-
-	if (!rt)
-		return;
-
-	/* Not even needed : RCU_INIT_POINTER(*rtp, NULL);
-	 * because we waited an RCU grace period before calling
-	 * free_fib_info_rcu()
-	 */
-
-	dst_dev_put(&rt->dst);
-	dst_release_immediate(&rt->dst);
-}
-
-static void free_nh_exceptions(struct fib_nh_common *nhc)
-{
-	struct fnhe_hash_bucket *hash;
-	int i;
-
-	hash = rcu_dereference_protected(nhc->nhc_exceptions, 1);
-	if (!hash)
-		return;
-	for (i = 0; i < FNHE_HASH_SIZE; i++) {
-		struct fib_nh_exception *fnhe;
-
-		fnhe = rcu_dereference_protected(hash[i].chain, 1);
-		while (fnhe) {
-			struct fib_nh_exception *next;
-
-			next = rcu_dereference_protected(fnhe->fnhe_next, 1);
-
-			rt_fibinfo_free(&fnhe->fnhe_rth_input);
-			rt_fibinfo_free(&fnhe->fnhe_rth_output);
-
-			kfree(fnhe);
-
-			fnhe = next;
-		}
-	}
-	kfree(hash);
-}
-
-static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp)
-{
-	int cpu;
-
-	if (!rtp)
-		return;
-
-	for_each_possible_cpu(cpu) {
-		struct rtable *rt;
-
-		rt = rcu_dereference_protected(*per_cpu_ptr(rtp, cpu), 1);
-		if (rt) {
-			dst_dev_put(&rt->dst);
-			dst_release_immediate(&rt->dst);
-		}
-	}
-	free_percpu(rtp);
-}
-
-void fib_nh_common_release(struct fib_nh_common *nhc)
-{
-	netdev_put(nhc->nhc_dev, &nhc->nhc_dev_tracker);
-	lwtstate_put(nhc->nhc_lwtstate);
-	rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output);
-	rt_fibinfo_free(&nhc->nhc_rth_input);
-	free_nh_exceptions(nhc);
-}
-
 void fib_nh_release(struct net *net, struct fib_nh *fib_nh)
 {
 #ifdef CONFIG_IP_ROUTE_CLASSID
@@ -607,38 +535,6 @@ static int fib_detect_death(struct fib_info *fi, int order,
 	return 1;
 }
 
-int fib_nh_common_init(struct net *net, struct fib_nh_common *nhc,
-		       struct nlattr *encap, u16 encap_type,
-		       void *cfg, gfp_t gfp_flags,
-		       struct netlink_ext_ack *extack)
-{
-	int err;
-
-	nhc->nhc_pcpu_rth_output = alloc_percpu_gfp(struct rtable __rcu *,
-						    gfp_flags);
-	if (!nhc->nhc_pcpu_rth_output)
-		return -ENOMEM;
-
-	if (encap) {
-		struct lwtunnel_state *lwtstate;
-
-		err = lwtunnel_build_state(net, encap_type, encap,
-					   nhc->nhc_family, cfg, &lwtstate,
-					   extack);
-		if (err)
-			goto lwt_failure;
-
-		nhc->nhc_lwtstate = lwtstate_get(lwtstate);
-	}
-
-	return 0;
-
-lwt_failure:
-	rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output);
-	nhc->nhc_pcpu_rth_output = NULL;
-	return err;
-}
-
 int fib_nh_init(struct net *net, struct fib_nh *nh,
 		struct fib_config *cfg, int nh_weight,
 		struct netlink_ext_ack *extack)
@@ -1864,44 +1760,6 @@ static int call_fib_nh_notifiers(struct fib_nh *nh,
 	return NOTIFY_DONE;
 }
 
-/* Update the PMTU of exceptions when:
- * - the new MTU of the first hop becomes smaller than the PMTU
- * - the old MTU was the same as the PMTU, and it limited discovery of
- *   larger MTUs on the path. With that limit raised, we can now
- *   discover larger MTUs
- * A special case is locked exceptions, for which the PMTU is smaller
- * than the minimal accepted PMTU:
- * - if the new MTU is greater than the PMTU, don't make any change
- * - otherwise, unlock and set PMTU
- */
-void fib_nhc_update_mtu(struct fib_nh_common *nhc, u32 new, u32 orig)
-{
-	struct fnhe_hash_bucket *bucket;
-	int i;
-
-	bucket = rcu_dereference_protected(nhc->nhc_exceptions, 1);
-	if (!bucket)
-		return;
-
-	for (i = 0; i < FNHE_HASH_SIZE; i++) {
-		struct fib_nh_exception *fnhe;
-
-		for (fnhe = rcu_dereference_protected(bucket[i].chain, 1);
-		     fnhe;
-		     fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) {
-			if (fnhe->fnhe_mtu_locked) {
-				if (new <= fnhe->fnhe_pmtu) {
-					fnhe->fnhe_pmtu = new;
-					fnhe->fnhe_mtu_locked = false;
-				}
-			} else if (new < fnhe->fnhe_pmtu ||
-				   orig == fnhe->fnhe_pmtu) {
-				fnhe->fnhe_pmtu = new;
-			}
-		}
-	}
-}
-
 void fib_sync_mtu(struct net_device *dev, u32 orig_mtu)
 {
 	struct hlist_head *head = fib_nh_head(dev);
diff --git a/net/ipv4/netlink.c b/net/ipv4/netlink.c
index b920e1bdcf58..57d4dca16d3e 100644
--- a/net/ipv4/netlink.c
+++ b/net/ipv4/netlink.c
@@ -16,10 +16,12 @@ int rtm_getroute_parse_ip_proto(struct nlattr *attr, u8 *ip_proto, u8 family,
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
 		return 0;
+#if IS_ENABLED(CONFIG_IPV4)
 	case IPPROTO_ICMP:
 		if (family != AF_INET)
 			break;
 		return 0;
+#endif
 #if IS_ENABLED(CONFIG_IPV6)
 	case IPPROTO_ICMPV6:
 		if (family != AF_INET6)
diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index 6205bd57aa85..b113a31f6150 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -1414,7 +1414,7 @@ static bool nexthop_is_good_nh(const struct nexthop *nh)
 
 	switch (nhi->family) {
 	case AF_INET:
-		return ipv4_good_nh(&nhi->fib_nh);
+		return IS_ENABLED(CONFIG_IPV4) && ipv4_good_nh(&nhi->fib_nh);
 	case AF_INET6:
 		return IS_ENABLED(CONFIG_IPV6) && ipv6_good_nh(&nhi->fib6_nh);
 	}
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index ca1180dba1de..9c343c9566b7 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -613,6 +613,7 @@ static struct ctl_table ipv4_table[] = {
 		.mode		= 0644,
 		.proc_handler	= proc_doulongvec_minmax,
 	},
+#if IS_ENABLED(CONFIG_IPV4)
 	{
 		.procname	= "fib_sync_mem",
 		.data		= &sysctl_fib_sync_mem,
@@ -622,6 +623,7 @@ static struct ctl_table ipv4_table[] = {
 		.extra1		= &sysctl_fib_sync_mem_min,
 		.extra2		= &sysctl_fib_sync_mem_max,
 	},
+#endif
 };
 
 static struct ctl_table ipv4_net_table[] = {
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index a130cdfaebfb..8b5f855c8dcb 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -645,9 +645,11 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
 
 	rcu_read_lock();
 	if (cb->strict_check) {
+#if IS_ENABLED(CONFIG_IPV4)
 		err = ip_valid_fib_dump_req(net, nlh, &arg.filter, cb);
 		if (err < 0)
 			goto unlock;
+#endif
 	} else if (nlmsg_len(nlh) >= sizeof(struct rtmsg)) {
 		struct rtmsg *rtm = nlmsg_data(nlh);
 
-- 
2.54.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help