]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf: remove ipv6_bpf_stub completely and use direct function calls
authorFernando Fernandez Mancera <fmancera@suse.de>
Wed, 25 Mar 2026 12:08:50 +0000 (13:08 +0100)
committerJakub Kicinski <kuba@kernel.org>
Sun, 29 Mar 2026 18:21:24 +0000 (11:21 -0700)
As IPv6 is built-in only, the ipv6_bpf_stub can be removed completely.

Convert all ipv6_bpf_stub usage to direct function calls instead. The
fallback functions introduced previously will prevent linkage errors
when CONFIG_IPV6 is disabled.

Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Tested-by: Ricardo B. Marlière <rbm@suse.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://patch.msgid.link/20260325120928.15848-10-fmancera@suse.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/ipv6.h
include/net/ipv6_stubs.h
net/core/filter.c
net/core/lwt_bpf.c
net/ipv6/af_inet6.c

index f99f273341f0a512813585da79971dc8d78f4a13..d042afe7a24564a5a27ed16515500f17f0e39977 100644 (file)
@@ -1149,6 +1149,8 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu);
 void inet6_cleanup_sock(struct sock *sk);
 void inet6_sock_destruct(struct sock *sk);
 int inet6_release(struct socket *sock);
+int __inet6_bind(struct sock *sk, struct sockaddr_unsized *uaddr, int addr_len,
+                u32 flags);
 int inet6_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len);
 int inet6_bind_sk(struct sock *sk, struct sockaddr_unsized *uaddr, int addr_len);
 int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
index 907681cecde8eb69506cb1c0a8259a7b7dab1e3a..dc708d9eca7aebe6748e3b67a3c64dc7b3d1ae39 100644 (file)
@@ -77,25 +77,4 @@ struct ipv6_stub {
                        __u32 mark, struct ipv6_txoptions *opt, int tclass, u32 priority);
 };
 extern const struct ipv6_stub *ipv6_stub __read_mostly;
-
-/* A stub used by bpf helpers. Similarly ugly as ipv6_stub */
-struct ipv6_bpf_stub {
-       int (*inet6_bind)(struct sock *sk, struct sockaddr_unsized *uaddr, int addr_len,
-                         u32 flags);
-       struct sock *(*udp6_lib_lookup)(const struct net *net,
-                                       const struct in6_addr *saddr, __be16 sport,
-                                       const struct in6_addr *daddr, __be16 dport,
-                                       int dif, int sdif, struct sk_buff *skb);
-       int (*ipv6_setsockopt)(struct sock *sk, int level, int optname,
-                              sockptr_t optval, unsigned int optlen);
-       int (*ipv6_getsockopt)(struct sock *sk, int level, int optname,
-                              sockptr_t optval, sockptr_t optlen);
-       int (*ipv6_dev_get_saddr)(struct net *net,
-                                 const struct net_device *dst_dev,
-                                 const struct in6_addr *daddr,
-                                 unsigned int prefs,
-                                 struct in6_addr *saddr);
-};
-extern const struct ipv6_bpf_stub *ipv6_bpf_stub __read_mostly;
-
 #endif
index c56821afaa0f34307c0ced357c2a869894920b6f..d55525cc5540817a46bccb1e6883c55d81194742 100644 (file)
@@ -73,7 +73,6 @@
 #include <net/seg6.h>
 #include <net/seg6_local.h>
 #include <net/lwtunnel.h>
-#include <net/ipv6_stubs.h>
 #include <net/bpf_sk_storage.h>
 #include <net/transp_v6.h>
 #include <linux/btf_ids.h>
@@ -2279,7 +2278,7 @@ static int __bpf_redirect_neigh_v6(struct sk_buff *skb, struct net_device *dev,
                        .saddr        = ip6h->saddr,
                };
 
-               dst = ipv6_stub->ipv6_dst_lookup_flow(net, NULL, &fl6, NULL);
+               dst = ip6_dst_lookup_flow(net, NULL, &fl6, NULL);
                if (IS_ERR(dst))
                        goto out_drop;
 
@@ -5577,12 +5576,12 @@ static int sol_ipv6_sockopt(struct sock *sk, int optname,
        }
 
        if (getopt)
-               return ipv6_bpf_stub->ipv6_getsockopt(sk, SOL_IPV6, optname,
-                                                     KERNEL_SOCKPTR(optval),
-                                                     KERNEL_SOCKPTR(optlen));
+               return do_ipv6_getsockopt(sk, SOL_IPV6, optname,
+                                         KERNEL_SOCKPTR(optval),
+                                         KERNEL_SOCKPTR(optlen));
 
-       return ipv6_bpf_stub->ipv6_setsockopt(sk, SOL_IPV6, optname,
-                                             KERNEL_SOCKPTR(optval), *optlen);
+       return do_ipv6_setsockopt(sk, SOL_IPV6, optname,
+                                 KERNEL_SOCKPTR(optval), *optlen);
 }
 
 static int __bpf_setsockopt(struct sock *sk, int level, int optname,
@@ -5981,9 +5980,6 @@ static const struct bpf_func_proto bpf_sock_ops_cb_flags_set_proto = {
        .arg2_type      = ARG_ANYTHING,
 };
 
-const struct ipv6_bpf_stub *ipv6_bpf_stub __read_mostly;
-EXPORT_SYMBOL_GPL(ipv6_bpf_stub);
-
 BPF_CALL_3(bpf_bind, struct bpf_sock_addr_kern *, ctx, struct sockaddr *, addr,
           int, addr_len)
 {
@@ -6007,11 +6003,9 @@ BPF_CALL_3(bpf_bind, struct bpf_sock_addr_kern *, ctx, struct sockaddr *, addr,
                        return err;
                if (((struct sockaddr_in6 *)addr)->sin6_port == htons(0))
                        flags |= BIND_FORCE_ADDRESS_NO_PORT;
-               /* ipv6_bpf_stub cannot be NULL, since it's called from
-                * bpf_cgroup_inet6_connect hook and ipv6 is already loaded
-                */
-               return ipv6_bpf_stub->inet6_bind(sk, (struct sockaddr_unsized *)addr,
-                                                addr_len, flags);
+
+               return __inet6_bind(sk, (struct sockaddr_unsized *)addr,
+                                   addr_len, flags);
 #endif /* CONFIG_IPV6 */
        }
 #endif /* CONFIG_INET */
@@ -6099,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;
@@ -6221,8 +6215,8 @@ 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
-               neigh = __ipv6_neigh_lookup_noref_stub(dev, params->ipv6_dst);
+       else if (IS_ENABLED(CONFIG_IPV6))
+               neigh = __ipv6_neigh_lookup_noref(dev, params->ipv6_dst);
 
        if (!neigh || !(READ_ONCE(neigh->nud_state) & NUD_VALID))
                return BPF_FIB_LKUP_RET_NO_NEIGH;
@@ -6290,12 +6284,11 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
                        params->tbid = 0;
                }
 
-               tb = ipv6_stub->fib6_get_table(net, tbid);
+               tb = fib6_get_table(net, tbid);
                if (unlikely(!tb))
                        return BPF_FIB_LKUP_RET_NOT_FWDED;
 
-               err = ipv6_stub->fib6_table_lookup(net, tb, oif, &fl6, &res,
-                                                  strict);
+               err = fib6_table_lookup(net, tb, oif, &fl6, &res, strict);
        } else {
                if (flags & BPF_FIB_LOOKUP_MARK)
                        fl6.flowi6_mark = params->mark;
@@ -6305,7 +6298,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
                fl6.flowi6_tun_key.tun_id = 0;
                fl6.flowi6_uid = sock_net_uid(net, NULL);
 
-               err = ipv6_stub->fib6_lookup(net, oif, &fl6, &res, strict);
+               err = fib6_lookup(net, oif, &fl6, &res, strict);
        }
 
        if (unlikely(err || IS_ERR_OR_NULL(res.f6i) ||
@@ -6326,11 +6319,11 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
                return BPF_FIB_LKUP_RET_NOT_FWDED;
        }
 
-       ipv6_stub->fib6_select_path(net, &res, &fl6, fl6.flowi6_oif,
-                                   fl6.flowi6_oif != 0, NULL, strict);
+       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(&res, dst, src);
+               mtu = ip6_mtu_from_fib6(&res, dst, src);
                if (params->tot_len > mtu) {
                        params->mtu_result = mtu; /* union with tot_len */
                        return BPF_FIB_LKUP_RET_FRAG_NEEDED;
@@ -6351,9 +6344,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
                if (res.f6i->fib6_prefsrc.plen) {
                        *src = res.f6i->fib6_prefsrc.addr;
                } else {
-                       err = ipv6_bpf_stub->ipv6_dev_get_saddr(net, dev,
-                                                               &fl6.daddr, 0,
-                                                               src);
+                       err = ipv6_dev_get_saddr(net, dev, &fl6.daddr, 0, src);
                        if (err)
                                return BPF_FIB_LKUP_RET_NO_SRC_ADDR;
                }
@@ -6365,7 +6356,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
        /* xdp and cls_bpf programs are run in RCU-bh so rcu_read_lock_bh is
         * not needed here.
         */
-       neigh = __ipv6_neigh_lookup_noref_stub(dev, dst);
+       neigh = __ipv6_neigh_lookup_noref(dev, dst);
        if (!neigh || !(READ_ONCE(neigh->nud_state) & NUD_VALID))
                return BPF_FIB_LKUP_RET_NO_NEIGH;
        memcpy(params->dmac, neigh->ha, ETH_ALEN);
@@ -6900,11 +6891,10 @@ static struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple,
                                            src6, tuple->ipv6.sport,
                                            dst6, ntohs(tuple->ipv6.dport),
                                            dif, sdif, &refcounted);
-               else if (likely(ipv6_bpf_stub))
-                       sk = ipv6_bpf_stub->udp6_lib_lookup(net,
-                                                           src6, tuple->ipv6.sport,
-                                                           dst6, tuple->ipv6.dport,
-                                                           dif, sdif, NULL);
+               else if (likely(ipv6_mod_enabled()))
+                       sk = __udp6_lib_lookup(net, src6, tuple->ipv6.sport,
+                                              dst6, tuple->ipv6.dport,
+                                              dif, sdif, NULL);
 #endif
        }
 
index 9f40be0c3e71dd893b9eb86daa039aa42d81fffe..f71ef82a5f3d366757fb52c71dccf54a2e490fbf 100644 (file)
@@ -13,7 +13,6 @@
 #include <net/gre.h>
 #include <net/ip.h>
 #include <net/ip6_route.h>
-#include <net/ipv6_stubs.h>
 
 struct bpf_lwt_prog {
        struct bpf_prog *prog;
@@ -103,7 +102,12 @@ static int bpf_lwt_input_reroute(struct sk_buff *skb)
                dev_put(dev);
        } else if (skb->protocol == htons(ETH_P_IPV6)) {
                skb_dst_drop(skb);
-               err = ipv6_stub->ipv6_route_input(skb);
+               if (IS_ENABLED(CONFIG_IPV6)) {
+                       ip6_route_input(skb);
+                       err = skb_dst(skb)->error;
+               } else {
+                       err = -EAFNOSUPPORT;
+               }
        } else {
                err = -EAFNOSUPPORT;
        }
@@ -233,7 +237,7 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb)
                fl6.daddr = iph6->daddr;
                fl6.saddr = iph6->saddr;
 
-               dst = ipv6_stub->ipv6_dst_lookup_flow(net, skb->sk, &fl6, NULL);
+               dst = ip6_dst_lookup_flow(net, skb->sk, &fl6, NULL);
                if (IS_ERR(dst)) {
                        err = PTR_ERR(dst);
                        goto err;
index bb29b29fdcfbb4b249264fc51d1954dd3e29c60b..07ae6ea7743a4d75df3c0af33b18fbf8ac2efad7 100644 (file)
@@ -264,8 +264,8 @@ out_sk_release:
        goto out;
 }
 
-static int __inet6_bind(struct sock *sk, struct sockaddr_unsized *uaddr, int addr_len,
-                       u32 flags)
+int __inet6_bind(struct sock *sk, struct sockaddr_unsized *uaddr, int addr_len,
+                u32 flags)
 {
        struct sockaddr_in6 *addr = (struct sockaddr_in6 *)uaddr;
        struct inet_sock *inet = inet_sk(sk);
@@ -1032,14 +1032,6 @@ static const struct ipv6_stub ipv6_stub_impl = {
        .ip6_xmit = ip6_xmit,
 };
 
-static const struct ipv6_bpf_stub ipv6_bpf_stub_impl = {
-       .inet6_bind = __inet6_bind,
-       .udp6_lib_lookup = __udp6_lib_lookup,
-       .ipv6_setsockopt = do_ipv6_setsockopt,
-       .ipv6_getsockopt = do_ipv6_getsockopt,
-       .ipv6_dev_get_saddr = ipv6_dev_get_saddr,
-};
-
 static int __init inet6_init(void)
 {
        struct list_head *r;
@@ -1199,7 +1191,6 @@ static int __init inet6_init(void)
        /* ensure that ipv6 stubs are visible only after ipv6 is ready */
        wmb();
        ipv6_stub = &ipv6_stub_impl;
-       ipv6_bpf_stub = &ipv6_bpf_stub_impl;
 out:
        return err;