[PATCH mptcp-next 1/3] mptcp: implement psock_update_sk_prot

Geliang Tang posted 3 patches 2 weeks ago
There is a newer version of this series
[PATCH mptcp-next 1/3] mptcp: implement psock_update_sk_prot
Posted by Geliang Tang 2 weeks ago
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
Re: [PATCH mptcp-next 1/3] mptcp: implement psock_update_sk_prot
Posted by kernel test robot 1 week, 6 days ago
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
Re: [PATCH mptcp-next 1/3] mptcp: implement psock_update_sk_prot
Posted by kernel test robot 1 week, 6 days ago
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