From: Geliang Tang <tanggeliang@kylinos.cn>
Add MPTCP support for BPF sockmap by implementing psock_update_sk_prot
callback. This allows MPTCP sockets to dynamically switch protocol
handlers when attached to or detached from sockmap programs. Separate
protocol structures are maintained for IPv4/IPv6 and TX/RX configurations.
tcp_bpf_update_proto() in net/ipv4/tcp_bpf.c is a frame of reference for
this patch.
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/521
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/mptcp/protocol.c | 96 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 900f26e21acd..d8fb71301bb4 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -11,6 +11,7 @@
#include <linux/netdevice.h>
#include <linux/sched/signal.h>
#include <linux/atomic.h>
+#include <linux/skmsg.h>
#include <net/aligned_data.h>
#include <net/rps.h>
#include <net/sock.h>
@@ -4017,6 +4018,91 @@ static int mptcp_connect(struct sock *sk, struct sockaddr_unsized *uaddr,
return 0;
}
+enum {
+ MPTCP_BPF_IPV4,
+ MPTCP_BPF_IPV6,
+ MPTCP_BPF_NUM_PROTS,
+};
+
+enum {
+ MPTCP_BPF_BASE,
+ MPTCP_BPF_TX,
+ MPTCP_BPF_RX,
+ MPTCP_BPF_TXRX,
+ MPTCP_BPF_NUM_CFGS,
+};
+
+static struct proto *mptcpv6_prot_saved __read_mostly;
+static DEFINE_SPINLOCK(mptcpv6_prot_lock);
+static struct proto mptcp_bpf_prots[MPTCP_BPF_NUM_PROTS][MPTCP_BPF_NUM_CFGS];
+
+static void mptcp_bpf_rebuild_protos(struct proto prot[MPTCP_BPF_NUM_CFGS],
+ struct proto *base)
+{
+ prot[MPTCP_BPF_BASE] = *base;
+ prot[MPTCP_BPF_BASE].destroy = sock_map_destroy;
+ prot[MPTCP_BPF_BASE].close = sock_map_close;
+ prot[MPTCP_BPF_BASE].sock_is_readable = sk_msg_is_readable;
+
+ prot[MPTCP_BPF_TX] = prot[MPTCP_BPF_BASE];
+ prot[MPTCP_BPF_RX] = prot[MPTCP_BPF_BASE];
+ prot[MPTCP_BPF_TXRX] = prot[MPTCP_BPF_TX];
+}
+
+static void mptcp_bpf_check_v6_needs_rebuild(struct proto *ops)
+{
+ /*
+ * Load with acquire semantics to ensure we see the latest protocol
+ * structure before checking for rebuild.
+ */
+ if (unlikely(ops != smp_load_acquire(&mptcpv6_prot_saved))) {
+ spin_lock_bh(&mptcpv6_prot_lock);
+ if (likely(ops != mptcpv6_prot_saved)) {
+ mptcp_bpf_rebuild_protos(mptcp_bpf_prots[MPTCP_BPF_IPV6], ops);
+ /* Ensure mptcpv6_prot_saved update is visible before releasing lock */
+ smp_store_release(&mptcpv6_prot_saved, ops);
+ }
+ spin_unlock_bh(&mptcpv6_prot_lock);
+ }
+}
+
+static int mptcp_bpf_assert_proto_ops(struct proto *ops)
+{
+ /* In order to avoid retpoline, we make assumptions when we call
+ * into ops if e.g. a psock is not present. Make sure they are
+ * indeed valid assumptions.
+ */
+ return ops->recvmsg == mptcp_recvmsg &&
+ ops->sendmsg == mptcp_sendmsg ? 0 : -EOPNOTSUPP;
+}
+
+static int mptcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
+{
+ int family = sk->sk_family == AF_INET6 ? MPTCP_BPF_IPV6 : MPTCP_BPF_IPV4;
+ int config = psock->progs.msg_parser ? MPTCP_BPF_TX : MPTCP_BPF_BASE;
+
+ if (psock->progs.stream_verdict || psock->progs.skb_verdict)
+ config = (config == MPTCP_BPF_TX) ? MPTCP_BPF_TXRX : MPTCP_BPF_RX;
+
+ if (restore) {
+ sk->sk_write_space = psock->saved_write_space;
+ /* Pairs with lockless read in sk_clone_lock() */
+ sock_replace_proto(sk, psock->sk_proto);
+ return 0;
+ }
+
+ if (sk->sk_family == AF_INET6) {
+ if (mptcp_bpf_assert_proto_ops(psock->sk_proto))
+ return -EINVAL;
+
+ mptcp_bpf_check_v6_needs_rebuild(psock->sk_proto);
+ }
+
+ /* Pairs with lockless read in sk_clone_lock() */
+ sock_replace_proto(sk, &mptcp_bpf_prots[family][config]);
+ return 0;
+}
+
static struct proto mptcp_prot = {
.name = "MPTCP",
.owner = THIS_MODULE,
@@ -4048,8 +4134,18 @@ static struct proto mptcp_prot = {
.obj_size = sizeof(struct mptcp_sock),
.slab_flags = SLAB_TYPESAFE_BY_RCU,
.no_autobind = true,
+#ifdef CONFIG_BPF_SYSCALL
+ .psock_update_sk_prot = mptcp_bpf_update_proto,
+#endif
};
+static int __init mptcp_bpf_v4_build_proto(void)
+{
+ mptcp_bpf_rebuild_protos(mptcp_bpf_prots[MPTCP_BPF_IPV4], &mptcp_prot);
+ return 0;
+}
+late_initcall(mptcp_bpf_v4_build_proto);
+
static int mptcp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len)
{
struct mptcp_sock *msk = mptcp_sk(sock->sk);
--
2.51.0
Hi Geliang,
kernel test robot noticed the following build errors:
[auto build test ERROR on mptcp/export]
[also build test ERROR on mptcp/export-net linus/master v6.19-rc2 next-20251219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Geliang-Tang/mptcp-implement-psock_update_sk_prot/20251225-170243
base: https://github.com/multipath-tcp/mptcp_net-next.git export
patch link: https://lore.kernel.org/r/f2508c5923c4ed365d6c12800e43a16761ed615a.1766653030.git.tanggeliang%40kylinos.cn
patch subject: [PATCH mptcp-next 1/3] mptcp: implement psock_update_sk_prot
config: arc-defconfig (https://download.01.org/0day-ci/archive/20251226/202512261326.9cQpYwdp-lkp@intel.com/config)
compiler: arc-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251226/202512261326.9cQpYwdp-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512261326.9cQpYwdp-lkp@intel.com/
All errors (new ones prefixed by >>):
net/mptcp/protocol.c: In function 'mptcp_bpf_rebuild_protos':
>> net/mptcp/protocol.c:4043:51: error: 'sock_map_destroy' undeclared (first use in this function); did you mean 'sock_diag_destroy'?
4043 | prot[MPTCP_BPF_BASE].destroy = sock_map_destroy;
| ^~~~~~~~~~~~~~~~
| sock_diag_destroy
net/mptcp/protocol.c:4043:51: note: each undeclared identifier is reported only once for each function it appears in
>> net/mptcp/protocol.c:4044:51: error: 'sock_map_close' undeclared (first use in this function); did you mean 'sk_msg_clone'?
4044 | prot[MPTCP_BPF_BASE].close = sock_map_close;
| ^~~~~~~~~~~~~~
| sk_msg_clone
net/mptcp/protocol.c: At top level:
net/mptcp/protocol.c:4079:12: warning: 'mptcp_bpf_update_proto' defined but not used [-Wunused-function]
4079 | static int mptcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
| ^~~~~~~~~~~~~~~~~~~~~~
vim +4043 net/mptcp/protocol.c
4038
4039 static void mptcp_bpf_rebuild_protos(struct proto prot[MPTCP_BPF_NUM_CFGS],
4040 struct proto *base)
4041 {
4042 prot[MPTCP_BPF_BASE] = *base;
> 4043 prot[MPTCP_BPF_BASE].destroy = sock_map_destroy;
> 4044 prot[MPTCP_BPF_BASE].close = sock_map_close;
4045 prot[MPTCP_BPF_BASE].sock_is_readable = sk_msg_is_readable;
4046
4047 prot[MPTCP_BPF_TX] = prot[MPTCP_BPF_BASE];
4048 prot[MPTCP_BPF_RX] = prot[MPTCP_BPF_BASE];
4049 prot[MPTCP_BPF_TXRX] = prot[MPTCP_BPF_TX];
4050 }
4051
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Geliang,
kernel test robot noticed the following build warnings:
[auto build test WARNING on mptcp/export]
[also build test WARNING on mptcp/export-net linus/master v6.19-rc2 next-20251219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Geliang-Tang/mptcp-implement-psock_update_sk_prot/20251225-170243
base: https://github.com/multipath-tcp/mptcp_net-next.git export
patch link: https://lore.kernel.org/r/f2508c5923c4ed365d6c12800e43a16761ed615a.1766653030.git.tanggeliang%40kylinos.cn
patch subject: [PATCH mptcp-next 1/3] mptcp: implement psock_update_sk_prot
config: arc-defconfig (https://download.01.org/0day-ci/archive/20251226/202512261144.DxrvwMS3-lkp@intel.com/config)
compiler: arc-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251226/202512261144.DxrvwMS3-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512261144.DxrvwMS3-lkp@intel.com/
All warnings (new ones prefixed by >>):
net/mptcp/protocol.c: In function 'mptcp_bpf_rebuild_protos':
net/mptcp/protocol.c:4043:51: error: 'sock_map_destroy' undeclared (first use in this function); did you mean 'sock_diag_destroy'?
4043 | prot[MPTCP_BPF_BASE].destroy = sock_map_destroy;
| ^~~~~~~~~~~~~~~~
| sock_diag_destroy
net/mptcp/protocol.c:4043:51: note: each undeclared identifier is reported only once for each function it appears in
net/mptcp/protocol.c:4044:51: error: 'sock_map_close' undeclared (first use in this function); did you mean 'sk_msg_clone'?
4044 | prot[MPTCP_BPF_BASE].close = sock_map_close;
| ^~~~~~~~~~~~~~
| sk_msg_clone
net/mptcp/protocol.c: At top level:
>> net/mptcp/protocol.c:4079:12: warning: 'mptcp_bpf_update_proto' defined but not used [-Wunused-function]
4079 | static int mptcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
| ^~~~~~~~~~~~~~~~~~~~~~
vim +/mptcp_bpf_update_proto +4079 net/mptcp/protocol.c
4078
> 4079 static int mptcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
4080 {
4081 int family = sk->sk_family == AF_INET6 ? MPTCP_BPF_IPV6 : MPTCP_BPF_IPV4;
4082 int config = psock->progs.msg_parser ? MPTCP_BPF_TX : MPTCP_BPF_BASE;
4083
4084 if (psock->progs.stream_verdict || psock->progs.skb_verdict)
4085 config = (config == MPTCP_BPF_TX) ? MPTCP_BPF_TXRX : MPTCP_BPF_RX;
4086
4087 if (restore) {
4088 sk->sk_write_space = psock->saved_write_space;
4089 /* Pairs with lockless read in sk_clone_lock() */
4090 sock_replace_proto(sk, psock->sk_proto);
4091 return 0;
4092 }
4093
4094 if (sk->sk_family == AF_INET6) {
4095 if (mptcp_bpf_assert_proto_ops(psock->sk_proto))
4096 return -EINVAL;
4097
4098 mptcp_bpf_check_v6_needs_rebuild(psock->sk_proto);
4099 }
4100
4101 /* Pairs with lockless read in sk_clone_lock() */
4102 sock_replace_proto(sk, &mptcp_bpf_prots[family][config]);
4103 return 0;
4104 }
4105
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.