[PATCH 00/11 net-next v4] Convert CONFIG_IPV6 to built-in and remove stubs

Fernando Fernandez Mancera posted 11 patches 2 weeks ago
There is a newer version of this series
arch/arm64/configs/defconfig                  |   2 +-
arch/m68k/configs/amiga_defconfig             |  44 +-------
arch/m68k/configs/apollo_defconfig            |  44 +-------
arch/m68k/configs/atari_defconfig             |  44 +-------
arch/m68k/configs/bvme6000_defconfig          |  44 +-------
arch/m68k/configs/hp300_defconfig             |  44 +-------
arch/m68k/configs/mac_defconfig               |  44 +-------
arch/m68k/configs/multi_defconfig             |  44 +-------
arch/m68k/configs/mvme147_defconfig           |  44 +-------
arch/m68k/configs/mvme16x_defconfig           |  44 +-------
arch/m68k/configs/q40_defconfig               |  44 +-------
arch/m68k/configs/sun3_defconfig              |  44 +-------
arch/m68k/configs/sun3x_defconfig             |  44 +-------
drivers/infiniband/Kconfig                    |   1 -
drivers/infiniband/core/addr.c                |   3 +-
drivers/infiniband/hw/ocrdma/Kconfig          |   2 +-
drivers/infiniband/sw/rxe/rxe_net.c           |   6 +-
drivers/infiniband/ulp/ipoib/Kconfig          |   2 +-
drivers/net/Kconfig                           |   9 --
drivers/net/ethernet/broadcom/Kconfig         |   2 +-
drivers/net/ethernet/chelsio/Kconfig          |   2 +-
.../mellanox/mlx5/core/en/rep/neigh.c         |   9 +-
.../ethernet/mellanox/mlx5/core/en/tc_tun.c   |   3 +-
.../mellanox/mlx5/core/en/tc_tun_encap.c      |   2 +-
.../mellanox/mlx5/core/en_accel/ipsec.c       |   1 -
.../net/ethernet/mellanox/mlx5/core/en_rep.c  |   1 -
.../net/ethernet/mellanox/mlx5/core/en_tc.c   |   1 -
drivers/net/ethernet/mellanox/mlxsw/Kconfig   |   1 -
drivers/net/ethernet/netronome/Kconfig        |   1 -
.../ethernet/netronome/nfp/flower/action.c    |   2 +-
.../netronome/nfp/flower/tunnel_conf.c        |   7 +-
drivers/net/ethernet/sfc/tc_counters.c        |   2 +-
drivers/net/ethernet/sfc/tc_encap_actions.c   |   5 +-
drivers/net/geneve.c                          |   1 -
drivers/net/gtp.c                             |   2 +-
drivers/net/ovpn/peer.c                       |   3 +-
drivers/net/ovpn/udp.c                        |   3 +-
drivers/net/usb/cdc_mbim.c                    |  17 +--
drivers/net/vxlan/vxlan_core.c                |  11 +-
drivers/net/vxlan/vxlan_multicast.c           |   6 +-
drivers/net/wireguard/socket.c                |   3 +-
drivers/net/wireless/intel/ipw2x00/ipw2100.c  |   2 +-
drivers/scsi/bnx2fc/Kconfig                   |   1 -
drivers/scsi/bnx2i/Kconfig                    |   1 -
drivers/scsi/cxgbi/cxgb3i/Kconfig             |   2 +-
drivers/scsi/cxgbi/cxgb4i/Kconfig             |   2 +-
fs/dlm/Kconfig                                |   2 +-
fs/gfs2/Kconfig                               |   2 +-
include/linux/icmpv6.h                        |  29 +----
include/linux/indirect_call_wrapper.h         |   2 +-
include/linux/netfilter_ipv6.h                | 102 ++----------------
include/net/ip.h                              |   8 --
include/net/ip6_fib.h                         |  35 +++++-
include/net/ip6_route.h                       |  26 +++++
include/net/ipv6.h                            |  12 +++
include/net/ipv6_stubs.h                      | 101 -----------------
include/net/ndisc.h                           |  38 +++----
include/net/udp_tunnel.h                      |   3 +-
net/bridge/Kconfig                            |   1 -
net/bridge/br_arp_nd_proxy.c                  |   3 +-
net/bridge/br_netfilter_hooks.c               |  12 +--
net/bridge/br_netfilter_ipv6.c                |   7 +-
net/core/dev.c                                |   3 -
net/core/filter.c                             |  68 +++++-------
net/core/hotdata.c                            |   1 -
net/core/lwt_bpf.c                            |  10 +-
net/core/neighbour.c                          |   1 -
net/ipv4/Kconfig                              |   9 +-
net/ipv4/fib_semantics.c                      |  11 +-
net/ipv4/icmp.c                               |   2 +-
net/ipv4/inet_connection_sock.c               |   2 -
net/ipv4/inet_hashtables.c                    |   5 -
net/ipv4/inetpeer.c                           |   4 -
net/ipv4/metrics.c                            |   1 -
net/ipv4/nexthop.c                            |  26 ++---
net/ipv4/ping.c                               |  16 ---
net/ipv4/route.c                              |   2 +-
net/ipv4/syncookies.c                         |   4 -
net/ipv4/tcp.c                                |  23 ----
net/ipv4/tcp_fastopen.c                       |   1 -
net/ipv4/tcp_input.c                          |   7 --
net/ipv4/tcp_ipv4.c                           |  21 ----
net/ipv4/tcp_minisocks.c                      |   4 -
net/ipv4/tcp_output.c                         |   6 --
net/ipv4/tcp_timer.c                          |   1 -
net/ipv4/udp.c                                |  36 +------
net/ipv6/Kconfig                              |   6 +-
net/ipv6/addrconf.c                           |  10 +-
net/ipv6/addrconf_core.c                      |  91 ----------------
net/ipv6/af_inet6.c                           |  67 +-----------
net/ipv6/icmp.c                               |   6 --
net/ipv6/ip6_fib.c                            |  10 +-
net/ipv6/ip6_icmp.c                           |  46 +-------
net/ipv6/ip6_offload.c                        |   4 +-
net/ipv6/ip6_output.c                         |   9 +-
net/ipv6/ip6_udp_tunnel.c                     |   3 +-
net/ipv6/ndisc.c                              |  35 +++---
net/ipv6/netfilter.c                          |  48 ---------
net/ipv6/route.c                              |  18 ++--
net/l2tp/Kconfig                              |   1 -
net/mpls/af_mpls.c                            |   3 +-
net/netfilter/Kconfig                         |   8 --
net/netfilter/core.c                          |   3 -
net/netfilter/nf_nat_masquerade.c             |  21 +---
net/netfilter/nfnetlink_queue.c               |  22 +++-
net/netfilter/utils.c                         |   1 -
net/openvswitch/actions.c                     |   3 +-
net/psp/psp_sock.c                            |   1 -
net/rxrpc/Kconfig                             |   2 +-
net/sched/sch_frag.c                          |   4 +-
net/sctp/Kconfig                              |   1 -
net/tipc/Kconfig                              |   1 -
net/tipc/udp_media.c                          |   9 +-
net/xfrm/espintcp.c                           |   5 +-
net/xfrm/xfrm_nat_keepalive.c                 |   4 +-
net/xfrm/xfrm_output.c                        |   3 +-
116 files changed, 322 insertions(+), 1416 deletions(-)
delete mode 100644 include/net/ipv6_stubs.h
[PATCH 00/11 net-next v4] Convert CONFIG_IPV6 to built-in and remove stubs
Posted by Fernando Fernandez Mancera 2 weeks ago
Historically, the Linux kernel has supported compiling the IPv6 stack as
a loadable module. While this made sense in the early days of IPv6
adoption, modern deployments and distributions overwhelmingly either
build IPv6 directly into the kernel (CONFIG_IPV6=y) or disable it
entirely (CONFIG_IPV6=n). The modular IPv6 use-case offers image size
and memory savings for specific setups, this benefit is outweighed by
the architectural burden it imposes on the subsystems on implementation
and maintenance.

In addition, most of the distributions are already using CONFIG_IPV6=y
by default [1], including openWRT [2] and Android gki_defconfig [3]. So
this won't have an impact on them. The most impacted architecture would
probably be arm64 as their default config is still using CONFIG_IPV6=m. 

To allow core networking, BPF, Netfilter, and various device drivers to
safely interact with a potentially unloaded IPv6 module, the kernel
relies on indirect call structures like ipv6_stub, ipv6_bpf_stub, and
nf_ipv6_ops, along with dynamic RCU registrations for things like ICMPv6
senders.

This patch series addresses this by changing CONFIG_IPV6 from a tristate
to a boolean, enforcing that IPv6 is either built-in or disabled. This
allows us to completely rip out the stub infrastructures and safely
replace them with direct function calls.

The bloat-o-meter report the following results for m68k, arm64, x86_64
defconfig.

m68k (keep on mind that CONFIG_IPV6 is disabled now):
add/remove: 65/938 grow/shrink: 36/254 up/down: 3022/-49692 (-46670)

arm64:
add/remove: 1251/265 grow/shrink: 81/46 up/down: 448740/-71519 (377221)

x86_64:
add/remove: 62/98 grow/shrink: 10/39 up/down: 2497/-4357 (-1860)

Considering that each new kernel release increases sizes by 30-40KiB on
average, this size increase isn't a huge jump for the distributions that
are still using CONFIG_IPV6=m. For the ones that are already using
CONFIG_IPV6=y, the size is reduced actually.

All the patches has been independently build tested. With allmodconfig
and allmodconfig + CONFIG_IPV6=n. In addition, net selftest has been run
against them on virtme-ng.

The series applied as a whole as been tested with allyesconfig and also
allyesconfig + CONFIG_IPV6=n but not all patches has been independently
tested this way.

[1] https://github.com/nyrahul/linux-kernel-configs

[2] https://github.com/openwrt/openwrt/commit/832e7b817221d288df76b763ca12c585365db5d8

[3] https://android.googlesource.com/kernel/common/+/refs/heads/android-mainline/arch/arm64/configs/gki_defconfig


Changes:
  v4:
    Patch 2: new patch introduced on this revision
    Patch 3: drop some IS_BUILTIN(IPV6) on files compiled only when IPV6=y
    Patch 5: introduce ipv6_mod_enabled() checks on fib6_nh_init(), ip6_dst_lookup_flow() and ip6_fragment() to avoid crash when ipv6.disable=1 during boot
    Patch 6: use &nd_tbl on code guarded by IS_ENABLED(CONFIG_IPV6)
    Patch 7: ipv6_stub->fib6_update_sernum() is replaced by fib6_update_sernum_upto_root() variant and guarded by spinlocks as it was on the ipv6_stub variant. This fixes the RCU warnings.

  v3: https://lore.kernel.org/netdev/20260317140141.5723-1-fmancera@suse.de/
    Patch 1: bring back CONFIG_NET_FOU_IP_TUNNELS on m68k defconfigs and drop unrelated changes.
    Patch 4: add missing netlink error message indicating IPv6 is disabled
    Patch 8: use __inet6_bind() instead the alias that was just created.

  v2: https://lore.kernel.org/netdev/20260310153506.5181-1-fmancera@suse.de/
    Patch 1: change fs_initcall() to device_initcall() to avoid race condition and disable CONFIG_IPV6 on m68k defconfigs.

  v1: https://lore.kernel.org/netdev/20260309022013.5199-1-fmancera@suse.de/

Fernando Fernandez Mancera (11):
  ipv6: convert CONFIG_IPV6 to built-in only and clean up Kconfigs
  net: EXPORT_IPV6_MOD() and EXPORT_IPV6_MOD_GPL() macros
  ipv6: replace IS_BUILTIN(CONFIG_IPV6) with IS_ENABLED(CONFIG_IPV6)
  ipv6: remove dynamic ICMPv6 sender registration infrastructure
  ipv6: prepare headers for ipv6_stub removal
  drivers: net: drop ipv6_stub usage and use direct function calls
  ipv4: drop ipv6_stub usage and use direct function calls
  net: convert remaining ipv6_stub users to direct function calls
  bpf: remove ipv6_bpf_stub completely and use direct function calls
  ipv6: remove ipv6_stub infrastructure completely
  netfilter: remove nf_ipv6_ops and use direct function calls

 arch/arm64/configs/defconfig                  |   2 +-
 arch/m68k/configs/amiga_defconfig             |  44 +-------
 arch/m68k/configs/apollo_defconfig            |  44 +-------
 arch/m68k/configs/atari_defconfig             |  44 +-------
 arch/m68k/configs/bvme6000_defconfig          |  44 +-------
 arch/m68k/configs/hp300_defconfig             |  44 +-------
 arch/m68k/configs/mac_defconfig               |  44 +-------
 arch/m68k/configs/multi_defconfig             |  44 +-------
 arch/m68k/configs/mvme147_defconfig           |  44 +-------
 arch/m68k/configs/mvme16x_defconfig           |  44 +-------
 arch/m68k/configs/q40_defconfig               |  44 +-------
 arch/m68k/configs/sun3_defconfig              |  44 +-------
 arch/m68k/configs/sun3x_defconfig             |  44 +-------
 drivers/infiniband/Kconfig                    |   1 -
 drivers/infiniband/core/addr.c                |   3 +-
 drivers/infiniband/hw/ocrdma/Kconfig          |   2 +-
 drivers/infiniband/sw/rxe/rxe_net.c           |   6 +-
 drivers/infiniband/ulp/ipoib/Kconfig          |   2 +-
 drivers/net/Kconfig                           |   9 --
 drivers/net/ethernet/broadcom/Kconfig         |   2 +-
 drivers/net/ethernet/chelsio/Kconfig          |   2 +-
 .../mellanox/mlx5/core/en/rep/neigh.c         |   9 +-
 .../ethernet/mellanox/mlx5/core/en/tc_tun.c   |   3 +-
 .../mellanox/mlx5/core/en/tc_tun_encap.c      |   2 +-
 .../mellanox/mlx5/core/en_accel/ipsec.c       |   1 -
 .../net/ethernet/mellanox/mlx5/core/en_rep.c  |   1 -
 .../net/ethernet/mellanox/mlx5/core/en_tc.c   |   1 -
 drivers/net/ethernet/mellanox/mlxsw/Kconfig   |   1 -
 drivers/net/ethernet/netronome/Kconfig        |   1 -
 .../ethernet/netronome/nfp/flower/action.c    |   2 +-
 .../netronome/nfp/flower/tunnel_conf.c        |   7 +-
 drivers/net/ethernet/sfc/tc_counters.c        |   2 +-
 drivers/net/ethernet/sfc/tc_encap_actions.c   |   5 +-
 drivers/net/geneve.c                          |   1 -
 drivers/net/gtp.c                             |   2 +-
 drivers/net/ovpn/peer.c                       |   3 +-
 drivers/net/ovpn/udp.c                        |   3 +-
 drivers/net/usb/cdc_mbim.c                    |  17 +--
 drivers/net/vxlan/vxlan_core.c                |  11 +-
 drivers/net/vxlan/vxlan_multicast.c           |   6 +-
 drivers/net/wireguard/socket.c                |   3 +-
 drivers/net/wireless/intel/ipw2x00/ipw2100.c  |   2 +-
 drivers/scsi/bnx2fc/Kconfig                   |   1 -
 drivers/scsi/bnx2i/Kconfig                    |   1 -
 drivers/scsi/cxgbi/cxgb3i/Kconfig             |   2 +-
 drivers/scsi/cxgbi/cxgb4i/Kconfig             |   2 +-
 fs/dlm/Kconfig                                |   2 +-
 fs/gfs2/Kconfig                               |   2 +-
 include/linux/icmpv6.h                        |  29 +----
 include/linux/indirect_call_wrapper.h         |   2 +-
 include/linux/netfilter_ipv6.h                | 102 ++----------------
 include/net/ip.h                              |   8 --
 include/net/ip6_fib.h                         |  35 +++++-
 include/net/ip6_route.h                       |  26 +++++
 include/net/ipv6.h                            |  12 +++
 include/net/ipv6_stubs.h                      | 101 -----------------
 include/net/ndisc.h                           |  38 +++----
 include/net/udp_tunnel.h                      |   3 +-
 net/bridge/Kconfig                            |   1 -
 net/bridge/br_arp_nd_proxy.c                  |   3 +-
 net/bridge/br_netfilter_hooks.c               |  12 +--
 net/bridge/br_netfilter_ipv6.c                |   7 +-
 net/core/dev.c                                |   3 -
 net/core/filter.c                             |  68 +++++-------
 net/core/hotdata.c                            |   1 -
 net/core/lwt_bpf.c                            |  10 +-
 net/core/neighbour.c                          |   1 -
 net/ipv4/Kconfig                              |   9 +-
 net/ipv4/fib_semantics.c                      |  11 +-
 net/ipv4/icmp.c                               |   2 +-
 net/ipv4/inet_connection_sock.c               |   2 -
 net/ipv4/inet_hashtables.c                    |   5 -
 net/ipv4/inetpeer.c                           |   4 -
 net/ipv4/metrics.c                            |   1 -
 net/ipv4/nexthop.c                            |  26 ++---
 net/ipv4/ping.c                               |  16 ---
 net/ipv4/route.c                              |   2 +-
 net/ipv4/syncookies.c                         |   4 -
 net/ipv4/tcp.c                                |  23 ----
 net/ipv4/tcp_fastopen.c                       |   1 -
 net/ipv4/tcp_input.c                          |   7 --
 net/ipv4/tcp_ipv4.c                           |  21 ----
 net/ipv4/tcp_minisocks.c                      |   4 -
 net/ipv4/tcp_output.c                         |   6 --
 net/ipv4/tcp_timer.c                          |   1 -
 net/ipv4/udp.c                                |  36 +------
 net/ipv6/Kconfig                              |   6 +-
 net/ipv6/addrconf.c                           |  10 +-
 net/ipv6/addrconf_core.c                      |  91 ----------------
 net/ipv6/af_inet6.c                           |  67 +-----------
 net/ipv6/icmp.c                               |   6 --
 net/ipv6/ip6_fib.c                            |  10 +-
 net/ipv6/ip6_icmp.c                           |  46 +-------
 net/ipv6/ip6_offload.c                        |   4 +-
 net/ipv6/ip6_output.c                         |   9 +-
 net/ipv6/ip6_udp_tunnel.c                     |   3 +-
 net/ipv6/ndisc.c                              |  35 +++---
 net/ipv6/netfilter.c                          |  48 ---------
 net/ipv6/route.c                              |  18 ++--
 net/l2tp/Kconfig                              |   1 -
 net/mpls/af_mpls.c                            |   3 +-
 net/netfilter/Kconfig                         |   8 --
 net/netfilter/core.c                          |   3 -
 net/netfilter/nf_nat_masquerade.c             |  21 +---
 net/netfilter/nfnetlink_queue.c               |  22 +++-
 net/netfilter/utils.c                         |   1 -
 net/openvswitch/actions.c                     |   3 +-
 net/psp/psp_sock.c                            |   1 -
 net/rxrpc/Kconfig                             |   2 +-
 net/sched/sch_frag.c                          |   4 +-
 net/sctp/Kconfig                              |   1 -
 net/tipc/Kconfig                              |   1 -
 net/tipc/udp_media.c                          |   9 +-
 net/xfrm/espintcp.c                           |   5 +-
 net/xfrm/xfrm_nat_keepalive.c                 |   4 +-
 net/xfrm/xfrm_output.c                        |   3 +-
 116 files changed, 322 insertions(+), 1416 deletions(-)
 delete mode 100644 include/net/ipv6_stubs.h

-- 
2.53.0
Re: [PATCH 00/11 net-next v4] Convert CONFIG_IPV6 to built-in and remove stubs
Posted by Jakub Kicinski 1 week, 6 days ago
On Fri, 20 Mar 2026 19:55:52 +0100 Fernando Fernandez Mancera wrote:
> Historically, the Linux kernel has supported compiling the IPv6 stack as
> a loadable module. While this made sense in the early days of IPv6
> adoption, modern deployments and distributions overwhelmingly either
> build IPv6 directly into the kernel (CONFIG_IPV6=y) or disable it
> entirely (CONFIG_IPV6=n). The modular IPv6 use-case offers image size
> and memory savings for specific setups, this benefit is outweighed by
> the architectural burden it imposes on the subsystems on implementation
> and maintenance.

I think it breaks BPF LWT tests?

FWIW you can open a pull request against this repo, and it will run all
the BPF tests for you: https://github.com/kernel-patches/bpf
Just delete the code that makes it not build because of the conflict.
Re: [PATCH 00/11 net-next v4] Convert CONFIG_IPV6 to built-in and remove stubs
Posted by Fernando Fernandez Mancera 1 week, 4 days ago
On 3/22/26 1:03 AM, Jakub Kicinski wrote:
> On Fri, 20 Mar 2026 19:55:52 +0100 Fernando Fernandez Mancera wrote:
>> Historically, the Linux kernel has supported compiling the IPv6 stack as
>> a loadable module. While this made sense in the early days of IPv6
>> adoption, modern deployments and distributions overwhelmingly either
>> build IPv6 directly into the kernel (CONFIG_IPV6=y) or disable it
>> entirely (CONFIG_IPV6=n). The modular IPv6 use-case offers image size
>> and memory savings for specific setups, this benefit is outweighed by
>> the architectural burden it imposes on the subsystems on implementation
>> and maintenance.
> 
> I think it breaks BPF LWT tests?
> 
> FWIW you can open a pull request against this repo, and it will run all
> the BPF tests for you: https://github.com/kernel-patches/bpf
> Just delete the code that makes it not build because of the conflict.
> 

All seems to be fine, am I missing something here?

https://github.com/kernel-patches/bpf/pull/11507
Re: [PATCH 00/11 net-next v4] Convert CONFIG_IPV6 to built-in and remove stubs
Posted by Jakub Kicinski 1 week, 4 days ago
On Mon, 23 Mar 2026 13:32:51 +0100 Fernando Fernandez Mancera wrote:
> > I think it breaks BPF LWT tests?
> > 
> > FWIW you can open a pull request against this repo, and it will run all
> > the BPF tests for you: https://github.com/kernel-patches/bpf
> > Just delete the code that makes it not build because of the conflict.
> >   
> 
> All seems to be fine, am I missing something here?

Yeah, sorry I ef'ed up the merge. Returning the series to pw now.
Re: [PATCH 00/11 net-next v4] Convert CONFIG_IPV6 to built-in and remove stubs
Posted by Ido Schimmel 1 week, 5 days ago
On Fri, Mar 20, 2026 at 07:55:52PM +0100, Fernando Fernandez Mancera wrote:
> Changes:
>   v4:
>     Patch 2: new patch introduced on this revision
>     Patch 3: drop some IS_BUILTIN(IPV6) on files compiled only when IPV6=y
>     Patch 5: introduce ipv6_mod_enabled() checks on fib6_nh_init(), ip6_dst_lookup_flow() and ip6_fragment() to avoid crash when ipv6.disable=1 during boot
>     Patch 6: use &nd_tbl on code guarded by IS_ENABLED(CONFIG_IPV6)

The IPv6 code is still using ipv6_get_nd_tbl() for some reason. If you
remove it from there (it's not needed), then we are only left with
handful of users that can be converted to use '&nd_tbl' when IPv6 is
enabled. Something like the patch below.

diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 9043ec00c050..6794ce58acca 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -67,12 +67,6 @@ struct prefix_info;
 
 extern struct neigh_table nd_tbl;
 
-#if IS_ENABLED(CONFIG_IPV6)
-#define ipv6_get_nd_tbl() (&nd_tbl)
-#else
-#define ipv6_get_nd_tbl() NULL
-#endif
-
 struct nd_msg {
         struct icmp6hdr	icmph;
         struct in6_addr	target;
@@ -360,7 +354,7 @@ static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, _
 
 static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev, const void *pkey)
 {
-	return ___neigh_lookup_noref(ipv6_get_nd_tbl(), neigh_key_eq128,
+	return ___neigh_lookup_noref(&nd_tbl, neigh_key_eq128,
 				     ndisc_hashfn, pkey, dev);
 }
 
diff --git a/net/core/filter.c b/net/core/filter.c
index 4b0c98f0d994..d55525cc5540 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -6093,9 +6093,9 @@ static int bpf_fib_set_fwd_params(struct bpf_fib_lookup *params, u32 mtu)
 static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
 			       u32 flags, bool check_mtu)
 {
+	struct neighbour *neigh = NULL;
 	struct fib_nh_common *nhc;
 	struct in_device *in_dev;
-	struct neighbour *neigh;
 	struct net_device *dev;
 	struct fib_result res;
 	struct flowi4 fl4;
@@ -6215,7 +6215,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
 	if (likely(nhc->nhc_gw_family != AF_INET6))
 		neigh = __ipv4_neigh_lookup_noref(dev,
 						  (__force u32)params->ipv4_dst);
-	else
+	else if (IS_ENABLED(CONFIG_IPV6))
 		neigh = __ipv6_neigh_lookup_noref(dev, params->ipv6_dst);
 
 	if (!neigh || !(READ_ONCE(neigh->nud_state) & NUD_VALID))
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index b576dd74d678..3e8fadc28798 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -585,8 +585,8 @@ static int fib_detect_death(struct fib_info *fi, int order,
 
 	if (likely(nhc->nhc_gw_family == AF_INET))
 		n = neigh_lookup(&arp_tbl, &nhc->nhc_gw.ipv4, nhc->nhc_dev);
-	else if (nhc->nhc_gw_family == AF_INET6)
-		n = neigh_lookup(ipv6_get_nd_tbl(), &nhc->nhc_gw.ipv6, nhc->nhc_dev);
+	else if (IS_ENABLED(CONFIG_IPV6) && nhc->nhc_gw_family == AF_INET6)
+		n = neigh_lookup(&nd_tbl, &nhc->nhc_gw.ipv6, nhc->nhc_dev);
 	else
 		n = NULL;
 
@@ -2146,7 +2146,8 @@ static bool fib_good_nh(const struct fib_nh *nh)
 		if (likely(nh->fib_nh_gw_family == AF_INET))
 			n = __ipv4_neigh_lookup_noref(nh->fib_nh_dev,
 						   (__force u32)nh->fib_nh_gw4);
-		else if (nh->fib_nh_gw_family == AF_INET6)
+		else if (IS_ENABLED(CONFIG_IPV6) &&
+			 nh->fib_nh_gw_family == AF_INET6)
 			n = __ipv6_neigh_lookup_noref(nh->fib_nh_dev,
 						      &nh->fib_nh_gw6);
 		else
diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index c65f88b253b9..9703e67d552a 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -1401,7 +1401,7 @@ static bool nexthop_is_good_nh(const struct nexthop *nh)
 	case AF_INET:
 		return ipv4_good_nh(&nhi->fib_nh);
 	case AF_INET6:
-		return ipv6_good_nh(&nhi->fib6_nh);
+		return IS_ENABLED(CONFIG_IPV6) && ipv6_good_nh(&nhi->fib6_nh);
 	}
 
 	return false;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 802c68a1b446..bc1296f0ea69 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -446,7 +446,7 @@ static void ipv4_confirm_neigh(const struct dst_entry *dst, const void *daddr)
 
 	if (rt->rt_gw_family == AF_INET) {
 		pkey = (const __be32 *)&rt->rt_gw4;
-	} else if (rt->rt_gw_family == AF_INET6) {
+	} else if (IS_ENABLED(CONFIG_IPV6) && rt->rt_gw_family == AF_INET6) {
 		return __ipv6_confirm_neigh(dev, &rt->rt_gw6);
 	} else if (!daddr ||
 		 (rt->rt_flags &
Re: [PATCH 00/11 net-next v4] Convert CONFIG_IPV6 to built-in and remove stubs
Posted by Fernando Fernandez Mancera 1 week, 4 days ago
On 3/22/26 6:27 PM, Ido Schimmel wrote:
> On Fri, Mar 20, 2026 at 07:55:52PM +0100, Fernando Fernandez Mancera wrote:
>> Changes:
>>    v4:
>>      Patch 2: new patch introduced on this revision
>>      Patch 3: drop some IS_BUILTIN(IPV6) on files compiled only when IPV6=y
>>      Patch 5: introduce ipv6_mod_enabled() checks on fib6_nh_init(), ip6_dst_lookup_flow() and ip6_fragment() to avoid crash when ipv6.disable=1 during boot
>>      Patch 6: use &nd_tbl on code guarded by IS_ENABLED(CONFIG_IPV6)
> 
> The IPv6 code is still using ipv6_get_nd_tbl() for some reason. If you
> remove it from there (it's not needed), then we are only left with
> handful of users that can be converted to use '&nd_tbl' when IPv6 is
> enabled. Something like the patch below.
> 
Hi Ido, the main reason why ipv6_get_nd_tbl() is used on IPv6 code is 
due to inlined functions. __ipv6_neigh_lookup_noref() is used in several 
places not guarded by IS_ENABLED(CONFIG_IPV6) preprocessor directive. 
That leads to undefined references when compiling with CONFIG_IPV6=n.

ld: vmlinux.o: in function `bpf_ipv4_fib_lookup':
filter.c:(.text+0x322b9dc): undefined reference to `nd_tbl'
ld: filter.c:(.text+0x322b9fb): undefined reference to `nd_tbl'
ld: filter.c:(.text+0x322ce1a): undefined reference to `nd_tbl'
ld: vmlinux.o: in function `ipv4_confirm_neigh':
route.c:(.text+0x345ade7): undefined reference to `nd_tbl'
ld: route.c:(.text+0x345ae06): undefined reference to `nd_tbl'
ld: vmlinux.o:route.c:(.text+0x345b74f): more undefined references to 
`nd_tbl' follow

I think that using ipv6_get_nd_tbl() is cleaner than guarding the usage 
of nd_tbl inside the function itself. In addition, I do not think we 
need to guard every __ipv6_neigh_lookup_noref_stub() instance we are 
dropping/replacing because that code should never be reached with 
ipv6.disabled=1 or CONFIG_IPV6=n, otherwise it would crash. That means 
it should be safe to use ipv6_get_nd_tbl() there.

What do you think Ido? I can still drop ipv6_get_nd_tbl() but it will 
require some IS_ENABLED(IPV6) preprocessor checks.

Thanks,
Fernando
Re: [PATCH 00/11 net-next v4] Convert CONFIG_IPV6 to built-in and remove stubs
Posted by David Ahern 1 week, 4 days ago
On 3/23/26 6:19 AM, Fernando Fernandez Mancera wrote:
> On 3/22/26 6:27 PM, Ido Schimmel wrote:
>> On Fri, Mar 20, 2026 at 07:55:52PM +0100, Fernando Fernandez Mancera
>> wrote:
>>> Changes:
>>>    v4:
>>>      Patch 2: new patch introduced on this revision
>>>      Patch 3: drop some IS_BUILTIN(IPV6) on files compiled only when
>>> IPV6=y
>>>      Patch 5: introduce ipv6_mod_enabled() checks on fib6_nh_init(),
>>> ip6_dst_lookup_flow() and ip6_fragment() to avoid crash when
>>> ipv6.disable=1 during boot
>>>      Patch 6: use &nd_tbl on code guarded by IS_ENABLED(CONFIG_IPV6)
>>
>> The IPv6 code is still using ipv6_get_nd_tbl() for some reason. If you
>> remove it from there (it's not needed), then we are only left with
>> handful of users that can be converted to use '&nd_tbl' when IPv6 is
>> enabled. Something like the patch below.
>>
> Hi Ido, the main reason why ipv6_get_nd_tbl() is used on IPv6 code is
> due to inlined functions. __ipv6_neigh_lookup_noref() is used in several
> places not guarded by IS_ENABLED(CONFIG_IPV6) preprocessor directive.
> That leads to undefined references when compiling with CONFIG_IPV6=n.
> 
> ld: vmlinux.o: in function `bpf_ipv4_fib_lookup':
> filter.c:(.text+0x322b9dc): undefined reference to `nd_tbl'
> ld: filter.c:(.text+0x322b9fb): undefined reference to `nd_tbl'
> ld: filter.c:(.text+0x322ce1a): undefined reference to `nd_tbl'
> ld: vmlinux.o: in function `ipv4_confirm_neigh':
> route.c:(.text+0x345ade7): undefined reference to `nd_tbl'
> ld: route.c:(.text+0x345ae06): undefined reference to `nd_tbl'
> ld: vmlinux.o:route.c:(.text+0x345b74f): more undefined references to
> `nd_tbl' follow

are these errors with Ido's suggested additional change?
Re: [PATCH 00/11 net-next v4] Convert CONFIG_IPV6 to built-in and remove stubs
Posted by Fernando Fernandez Mancera 1 week, 4 days ago
On 3/23/26 3:38 PM, David Ahern wrote:
> On 3/23/26 6:19 AM, Fernando Fernandez Mancera wrote:
>> On 3/22/26 6:27 PM, Ido Schimmel wrote:
>>> On Fri, Mar 20, 2026 at 07:55:52PM +0100, Fernando Fernandez Mancera
>>> wrote:
>>>> Changes:
>>>>     v4:
>>>>       Patch 2: new patch introduced on this revision
>>>>       Patch 3: drop some IS_BUILTIN(IPV6) on files compiled only when
>>>> IPV6=y
>>>>       Patch 5: introduce ipv6_mod_enabled() checks on fib6_nh_init(),
>>>> ip6_dst_lookup_flow() and ip6_fragment() to avoid crash when
>>>> ipv6.disable=1 during boot
>>>>       Patch 6: use &nd_tbl on code guarded by IS_ENABLED(CONFIG_IPV6)
>>>
>>> The IPv6 code is still using ipv6_get_nd_tbl() for some reason. If you
>>> remove it from there (it's not needed), then we are only left with
>>> handful of users that can be converted to use '&nd_tbl' when IPv6 is
>>> enabled. Something like the patch below.
>>>
>> Hi Ido, the main reason why ipv6_get_nd_tbl() is used on IPv6 code is
>> due to inlined functions. __ipv6_neigh_lookup_noref() is used in several
>> places not guarded by IS_ENABLED(CONFIG_IPV6) preprocessor directive.
>> That leads to undefined references when compiling with CONFIG_IPV6=n.
>>
>> ld: vmlinux.o: in function `bpf_ipv4_fib_lookup':
>> filter.c:(.text+0x322b9dc): undefined reference to `nd_tbl'
>> ld: filter.c:(.text+0x322b9fb): undefined reference to `nd_tbl'
>> ld: filter.c:(.text+0x322ce1a): undefined reference to `nd_tbl'
>> ld: vmlinux.o: in function `ipv4_confirm_neigh':
>> route.c:(.text+0x345ade7): undefined reference to `nd_tbl'
>> ld: route.c:(.text+0x345ae06): undefined reference to `nd_tbl'
>> ld: vmlinux.o:route.c:(.text+0x345b74f): more undefined references to
>> `nd_tbl' follow
> 
> are these errors with Ido's suggested additional change?

Actually no. I missed the Dead-code elimination optimization. Never mind 
my reply, it makes sense to follow Ido's suggestion.

Thanks and sorry for the back-and-forth. *facepalm*
Fernando.