From nobody Thu Nov 5 07:28:11 2026 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793010939; b=C36NCpZGExCqRbwcYjrB1DHeAnaSJU6iFyoNeGQZuV83/pRr3bPEnbyzrVBEIetbm5V0 nBnn/o//r88RTpN2tfI3S0jwhN0iQisUXiwOCuOAwjhVoyMkRVPZKkaNlnzTCAPtKzAI2 snQHquPJYwbm1f3jQ9nOZLGq92zKn0iGzy5WU6EAFjCDx5AZwzeHmEbJ3iDJqr+XKXcbC J6m7p41FVu2+XVto0tbVxocik6uzacsGlsLRKGtKnKZ6iFOaFXB6knyuDfURuv/OwrD+x V8D8NFKNXlkr/XGPD/xtoTy2qav+gtBiooaKMXzkZStQ+CyYOKiFs4ev9Hu02O1aRLA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793010939; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=SlHOVdo0RAFE/BGGtaqw1/9lKWq/HiFDQA47IkzI+s0=; b=cRw02G2NtgWXA+Zn0mgtxegyYjvXpRX+oWPFQg9/dsp+0kYpUPnZVqQEQWJOYsq1lPxv 0wT7+luz90gR8z9jwpEN0gczSKT2cYCvJaJTLFCLJPp1AE8UE4DRkKtUU3GBBV0i1RkCZ 83LFPVYEkzMx+LDSG3DNpDproReZYXEyaOFC+jUL3GAiz7kgb44Z51JOxjjHGd6r5f8O1 KRm5uFH4xCPqF/STpbZGsz2fPLmQAAkRrKNaVcCd6kwKrAH/wzzU2oEqFdcfEqX95zXY0 etiTlHZS5kQR6+jrO9T2Lgn8Czl6o2EhpPbECltVEB5InXiI7jhQ+I/JZOuAY99Pwsg== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=OpxPPpS3; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0EADA606A31A for ; Mon, 26 Oct 2026 10:35:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=OpxPPpS3 Received: by smtp.kernel.org (Postfix) with ESMTPSA id B415E1F01828; Mon, 26 Oct 2026 10:35:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793010938; bh=SlHOVdo0RAFE/BGGtaqw1/9lKWq/HiFDQA47IkzI+s0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=OpxPPpS3AMoayDoyh934yY44sUTYtx0ERBNdnF4ceKys2mnNNEMiBgU3jzlH4gl2U PAA1I/g5NGuWenvhd4VcYZaBI62tlb+y7L02j6kFu0Cf1FN9DHJV8lVPaiEdXW3uPq Y5q9gq60B6sA3Y9IAmEd4MR++rzQFpCLqUgPIzPWaJtK4TgMzL/NmDmD8gYeVu40Bv QxBpzlIkJ08tlGLNERel3tkuBaTNEGQIgZuPtghhqvEzfcxbvwDVRXr58PiT8QlAly NX+UZXrIzjFOYwbOrcA56ID8Nl5mg2Z95YtX3D400qoo/rJpGzVj/7FwFgMdIi0NMg PA5Mll6I9ajkQ== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v2 1/4] mptcp: give MPTCP sockets a distinct lockdep class Date: Mon, 26 Oct 2026 18:35:25 +0800 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang MPTCP sockets and their subflows share the same k-sk_lock-AF_INET lockdep class. When both are kernel sockets, lockdep flags every path that holds the MPTCP socket lock and then locks a subflow (setsockopt, connect, bind, worker send-ack) as "possible recursive locking". Extract the lock reclassification logic from PM listener socket creation into mptcp_reclassify_socket() helper. Assign distinct lock classes based on both socket type (kernel or user) and address family (IPv4 or IPv6) to prevent lockdep from conflating kernel MPTCP socket usage (which may nest with fs/storage locks) with user-space socket API usage (which records mmap_lock dependencies through page faults). Call mptcp_reclassify_socket() from mptcp_init_sock() for actively created sockets, and from mptcp_sk_clone_init() before bh_lock_sock() for passively cloned sockets. The reclassification must happen before the lock is held to avoid lockdep warnings. PM listener sockets are automatically reclassified through the mptcp_init_sock() path when created via sock_create_kern(). Signed-off-by: Geliang Tang --- net/mptcp/pm_kernel.c | 16 ---------------- net/mptcp/protocol.c | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/net/mptcp/pm_kernel.c b/net/mptcp/pm_kernel.c index d3014bf57bf3..03603defdf6c 100644 --- a/net/mptcp/pm_kernel.c +++ b/net/mptcp/pm_kernel.c @@ -846,13 +846,9 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm= _nl_pernet *pernet, return ret; } =20 -static struct lock_class_key mptcp_slock_keys[2]; -static struct lock_class_key mptcp_keys[2]; - static int mptcp_pm_nl_create_listen_socket(struct sock *sk, struct mptcp_pm_addr_entry *entry) { - bool is_ipv6 =3D entry->addr.family =3D=3D AF_INET6; int addrlen =3D sizeof(struct sockaddr_in); struct sockaddr_storage addr; struct sock *newsk, *ssk; @@ -868,18 +864,6 @@ static int mptcp_pm_nl_create_listen_socket(struct soc= k *sk, if (!newsk) return -EINVAL; =20 - /* The subflow socket lock is acquired in a nested to the msk one - * in several places, even by the TCP stack, and this msk is a kernel - * socket: lockdep complains. Instead of propagating the _nested - * modifiers in several places, re-init the lock class for the msk - * socket to an mptcp specific one. - */ - sock_lock_init_class_and_name(newsk, - is_ipv6 ? "mlock-AF_INET6" : "mlock-AF_INET", - &mptcp_slock_keys[is_ipv6], - is_ipv6 ? "msk_lock-AF_INET6" : "msk_lock-AF_INET", - &mptcp_keys[is_ipv6]); - lock_sock(newsk); ssk =3D __mptcp_nmpc_sk(mptcp_sk(newsk)); release_sock(newsk); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 02a4f479d9d8..d4f42dfc227e 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3267,11 +3267,43 @@ static void mptcp_ca_reset(struct sock *sk) icsk->icsk_ca_ops =3D NULL; } =20 +/* The subflow socket lock is acquired in a nested to the msk one + * in several places, even by the TCP stack: lockdep complains when + * both are kernel sockets. Instead of propagating the _nested modifiers + * in several places, re-init the lock class for the msk socket to an + * mptcp specific one. Separate lock classes are used for kernel and + * user sockets to prevent lockdep from conflating their usage patterns. + */ +static struct lock_class_key mptcp_slock_keys[2][2]; +static struct lock_class_key mptcp_keys[2][2]; + +static void mptcp_reclassify_socket(struct sock *sk) +{ + bool is_ipv6 =3D sk->sk_family =3D=3D AF_INET6; + const char *slock_name, *lock_name; + bool is_kern =3D !!sk->sk_kern_sock; + + if (is_kern) { + slock_name =3D is_ipv6 ? "kmlock-AF_INET6" : "kmlock-AF_INET"; + lock_name =3D is_ipv6 ? "kmsk_lock-AF_INET6" : + "kmsk_lock-AF_INET"; + } else { + slock_name =3D is_ipv6 ? "mlock-AF_INET6" : "mlock-AF_INET"; + lock_name =3D is_ipv6 ? "msk_lock-AF_INET6" : "msk_lock-AF_INET"; + } + + sock_lock_init_class_and_name(sk, slock_name, + &mptcp_slock_keys[is_kern][is_ipv6], + lock_name, &mptcp_keys[is_kern][is_ipv6]); +} + static int mptcp_init_sock(struct sock *sk) { struct net *net =3D sock_net(sk); int ret; =20 + mptcp_reclassify_socket(sk); + __mptcp_init_sock(sk); =20 if (!mptcp_is_enabled(net)) @@ -3772,13 +3804,16 @@ struct sock *mptcp_sk_clone_init(const struct sock = *sk, struct request_sock *req) { struct mptcp_subflow_request_sock *subflow_req =3D mptcp_subflow_rsk(req); - struct sock *nsk =3D sk_clone_lock(sk, GFP_ATOMIC); + struct sock *nsk =3D sk_clone(sk, GFP_ATOMIC, false); struct mptcp_subflow_context *subflow; struct mptcp_sock *msk; =20 if (!nsk) return NULL; =20 + mptcp_reclassify_socket(nsk); + + bh_lock_sock(nsk); #if IS_ENABLED(CONFIG_MPTCP_IPV6) if (nsk->sk_family =3D=3D AF_INET6) inet_sk(nsk)->pinet6 =3D mptcp_inet6_sk(nsk); --=20 2.55.0 From nobody Thu Nov 5 07:28:11 2026 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793010941; b=shJoi0HzhUqDZ3B4ITkr5MQO0HDL1neUaWHfebNSYj7eU9kHUpe4B+rAApIYBV/TOZoC C5q1gjiI9bVwVWhhFgIkVdHU3Pyb+Tj90cv9R79rcIMk+Sj9osQdwZJhUhQkJRmHsJ94O yTdbyS2+xZBUK8a/kFe9x23w87b4vtdcOtjdDLqB1lscA3hyKeGtpjDuyAka6BC4+7L2R ybXhIjEIGxuVjPM0zfoHMdjADI3eDyP4mToXPXXPat1E9uv9fB1yGdOH+kHHPwvipw0m8 TczohiuXugcC3DPAfNX3+JLTXmqPb2j6xHFbCpN9+CITsIlMeMbZfGQLe1eDRoemz5w== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793010941; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=EBNwE8s1NAm8Boo+DDfLG6fiMsfMkcA91M8T6BswFtA=; b=e5xFItFlAchH71PJJN46KzQ3pU9T40kmBFzQX33331Az1qQuK6oECpz48G9m4x5kB4xH W+o5WQNzVH/ey22nYWOhbeyWv8JowytOS9q4TLY6cxpdHW0X1oN4IlKBvatze2TJXIdUI BrmTgWGZXcW2lraHl54ypa+Wz71iOZnBLun/kgIHkvr5C6TuentF1UCghzwrK/vEqVCd7 daJ0vpdRZ74zNJjadYl7A9HFpxmQgUwUUArQf+oeXDhLlpjnYZ5exAgzreuI2gNDG1d9f TSAFigCH2yyZHgi9QdwCHhc2mvTV36g3OSHcDXigce6GWKinBcM5f8cGEOLKCt3pkqQ== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=lq2YqidU; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 08D29606A31A for ; Mon, 26 Oct 2026 10:35:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=lq2YqidU Received: by smtp.kernel.org (Postfix) with ESMTPSA id 498E51F031E1; Mon, 26 Oct 2026 10:35:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793010940; bh=EBNwE8s1NAm8Boo+DDfLG6fiMsfMkcA91M8T6BswFtA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=lq2YqidUcFRApX+qXnBpE5Mh2DBgpEGhmDSCY40Wa9T8HGbtSZAhXYGBrcD8Zk5qn GyDUsmeaofbS8hGYIXGGKTQa60Vd5irgsnRxGpyKWgUyKqlNbjEYEJ9EteOPoItAXO pkh+iAcU7BVjlUQ0b1H9IYA/9f3jaTuGspg3KQE/ALd1m72aJioF5mUmeOh6B2GRqS 42mmvjI1amwcVRRYxUpcWF34vCmjnTwP8THN49KQqxf2g8RGOQQrM9ySSygmZjCDyz P/iuPfMs1WGljEbyhcGbzm7AkcpElPtJzEu/llFIEkqF3qzKvn3eMYDb/gJdZebmil 1n92rTOok2bTA== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v2 2/4] sock: add set_memalloc protocol callback Date: Mon, 26 Oct 2026 18:35:26 +0800 Message-ID: <2394cada9a75d45edb8773c3d24e699e9211e98c.1793010744.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang Add a protocol-specific callback set_memalloc() to struct proto that gets invoked when SOCK_MEMALLOC flag or allocation settings change on a socket. This allows protocols like MPTCP to propagate these settings to their sub-sockets automatically. For MPTCP, when the master socket's memalloc settings change (via sk_set_memalloc/sk_clear_memalloc), the callback synchronizes SOCK_MEMALLOC flag, sk_allocation, and sk_use_task_frag to all subflow sockets immediately. This ensures subflows can use emergency memory reserves when needed, preventing deadlocks in memory pressure scenarios. NBD (Network Block Device) benefits from this when used over MPTCP for swap devices. Previously, NBD would set sk_allocation directly in __sock_xmit() but this wouldn't propagate to MPTCP subflows. Now it calls sk_set_memalloc() which triggers the MPTCP callback to sync all subflows. The callback mechanism maintains clean layering: core socket code doesn't need MPTCP-specific knowledge, and MPTCP handles its own subflow synchronization transparently. Signed-off-by: Geliang Tang --- drivers/block/nbd.c | 1 + include/net/sock.h | 1 + net/core/sock.c | 8 ++++++++ net/mptcp/protocol.c | 21 +++++++++++++++++++++ 4 files changed, 31 insertions(+) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index ffce519bf008..c5e26fc98d1a 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -579,6 +579,7 @@ static int __sock_xmit(struct nbd_device *nbd, struct s= ocket *sock, int send, do { sock->sk->sk_allocation =3D GFP_NOIO | __GFP_MEMALLOC; sock->sk->sk_use_task_frag =3D false; + sk_set_memalloc(sock->sk); msg.msg_flags =3D msg_flags | MSG_NOSIGNAL; =20 if (send) diff --git a/include/net/sock.h b/include/net/sock.h index 173b37b2b8bb..aaf50293ea37 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1361,6 +1361,7 @@ struct proto { /* Memory pressure */ void (*enter_memory_pressure)(struct sock *sk); void (*leave_memory_pressure)(struct sock *sk); + void (*set_memalloc)(struct sock *sk); atomic_long_t *memory_allocated; /* Current allocated memory. */ int __percpu *per_cpu_fw_alloc; struct percpu_counter *sockets_allocated; /* Current number of sockets. */ diff --git a/net/core/sock.c b/net/core/sock.c index e7405be8941f..dc5fbe2f63fc 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -306,6 +306,10 @@ void sk_set_memalloc(struct sock *sk) sock_set_flag(sk, SOCK_MEMALLOC); sk->sk_allocation |=3D __GFP_MEMALLOC; static_branch_inc(&memalloc_socks_key); + + /* Call protocol-specific callback if available */ + if (sk->sk_prot->set_memalloc) + sk->sk_prot->set_memalloc(sk); } EXPORT_SYMBOL_GPL(sk_set_memalloc); =20 @@ -315,6 +319,10 @@ void sk_clear_memalloc(struct sock *sk) sk->sk_allocation &=3D ~__GFP_MEMALLOC; static_branch_dec(&memalloc_socks_key); =20 + /* Call protocol-specific callback if available */ + if (sk->sk_prot->set_memalloc) + sk->sk_prot->set_memalloc(sk); + /* * SOCK_MEMALLOC is allowed to ignore rmem limits to ensure forward * progress of swapping. SOCK_MEMALLOC may be cleared while diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index d4f42dfc227e..5eccff04151d 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -4327,6 +4327,26 @@ static int mptcp_connect(struct sock *sk, struct soc= kaddr_unsized *uaddr, return 0; } =20 +static void mptcp_set_memalloc(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct mptcp_subflow_context *subflow; + bool memalloc; + + lock_sock(sk); + memalloc =3D sock_flag(sk, SOCK_MEMALLOC); + mptcp_for_each_subflow(msk, subflow) { + struct sock *ssk =3D mptcp_subflow_tcp_sock(subflow); + + lock_sock_nested(ssk, SINGLE_DEPTH_NESTING); + sock_valbool_flag(ssk, SOCK_MEMALLOC, memalloc); + ssk->sk_allocation =3D sk->sk_allocation; + ssk->sk_use_task_frag =3D sk->sk_use_task_frag; + release_sock(ssk); + } + release_sock(sk); +} + static struct proto mptcp_prot =3D { .name =3D "MPTCP", .owner =3D THIS_MODULE, @@ -4358,6 +4378,7 @@ static struct proto mptcp_prot =3D { .obj_size =3D sizeof(struct mptcp_sock), .slab_flags =3D SLAB_TYPESAFE_BY_RCU, .no_autobind =3D true, + .set_memalloc =3D mptcp_set_memalloc, }; =20 static int mptcp_bind(struct socket *sock, struct sockaddr_unsized *uaddr,= int addr_len) --=20 2.55.0 From nobody Thu Nov 5 07:28:11 2026 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793010943; b=yKUptoDmyIH59IUGMhK/lsjfn+OsBsBbCbgrYWdPvuBA7PU38UJhmowQdrMXZhKUZ7hN PPJgzFQ7fcvBHtifYoRWmRm6vY1P0vrWkfRRL8ePMjtkno9AE0oFG8fW/x89ORgHcQpIt hcJ9DNbWjTbd6Pc1AzslKYssKm/38EJgOJAoDH0r2OROO5PcjVtPaDDeMwtFEN9tNltLP yF2WqBuXo9vBCjQrVN48ZRcX69PQ7ALU0nsUVfKy5vHBf7Fn5dDPwD0obpWapBAdZG0PU ZHzRHPaUqKT9JUG2DIwb/xwTU57MPB1nMozf1ArH+C8poDgMRjNT+OLGTAwf7wuycIw== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793010943; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=t04EphSPfNStBcFThpXgmL04PnNNqPMwD29cgZSCzqI=; b=qOx9gqjVaaJDm+sGTuhXs5I5PcA39KR3W/nTlwO+XuQnBOEkR/v4Ym8x/b1aQ9zuvCgW 3xWckxeQFvSSITv33nDM5zDvCjsLhfiSpFYnjtNNTmCwXK1wRTQllWsLsHYSPDh2p35Qe bkbJ39jfefXThgtaQc0MVZz2Vy5p5VzCi8NeuA5dNvEGTDqUM3+a0VGlfWNzN3cdGJWw3 gvKD1xRdxoICbtqh2Nt4OgxW9y2E+nQyCe8JgtbQhCYAiCU9rKaXGKor0edpNVkXHG0mB WGxfR3umacwGFCXos8yrwteattuT6r0qkQw30dByz6wFDkVzuOF6txWgyUKVKZNpt/A== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=fjgw3Hsc; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A808C606A31A for ; Mon, 26 Oct 2026 10:35:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=fjgw3Hsc Received: by smtp.kernel.org (Postfix) with ESMTPSA id 355C71F031E2; Mon, 26 Oct 2026 10:35:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793010942; bh=t04EphSPfNStBcFThpXgmL04PnNNqPMwD29cgZSCzqI=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=fjgw3HscjN7xxDD4LtQP9+tFWOiMgQ82U+cPgrnj5s5cHDwAEWPFZMCChKiAfQhm6 ki+5WAOtool6ytgB1U+TlvbwASGYy72EsHjaE4jaTjbWrMx85M4N2ciddztvz1yRUp ziQbCX5Mn/jRbm/08PYP6O6ujbtgcHzUSYSoWmnrt7i+NIsRE7NgDCw259sI1pE0GZ /6Jv5j4dk3R2U/pszv4QIwvCfCo2r6+o53GB5678nb2XzOqbkEJHz9ZAdaNCxuRuHR 8PBANuvN0tNR0YKgKtbe5Ab9MZ6M4FlNhhYqKqnfhS+nitA9ib6HCA58HCD/tLSVLc yPsm4GRccknYA== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v2 3/4] nbd: allow MPTCP sockets Date: Mon, 26 Oct 2026 18:35:27 +0800 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang MPTCP (Multipath TCP, RFC 8684) is an extension to TCP introduced in Linux 5.6 that can combine bandwidth from multiple network interfaces. For NBD (Network Block Device), MPTCP provides significant bandwidth aggregation in multi-NIC scenarios. Our tests with 4 virtual NICs (each limited to 1000 Mbit/s / 125 MB/s) show ~4x improvement, TCP achieves ~110 MiB/s while MPTCP achieves ~400 MiB/s for both read and write: # ./mptcp_nbd.sh mptcp INFO: nbd-server lacks native MPTCP, using mptcpize INFO: nbd-client lacks native MPTCP, using mptcpize Negotiation: ..size =3D 256MB Connected /dev/nbd0 connected fio-3.41 ... ... Run status group 0 (all jobs): READ: bw=3D406MiB/s (426MB/s), 406MiB/s-406MiB/s (426MB/s-426MB/s), \ io=3D4063MiB (4261MB), run=3D10001-10001msec ... ... Run status group 0 (all jobs): WRITE: bw=3D376MiB/s (394MB/s), 376MiB/s-376MiB/s (394MB/s-394MB/s), \ io=3D3758MiB (3940MB), run=3D10001-10001msec MPTCP sockets can be created with: fd =3D socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP); Or enabled transparently using the mptcpize tool without modifying applications (mptcpize run nbd-server, mptcpize run nbd-client). Future patches will add -M (--mptcp) options to nbd-server and nbd-client for native MPTCP support. Currently, the kernel NBD driver only accepts TCP and UNIX sockets. This patch adds MPTCP socket support by adding msk_is_mptcp() check in nbd_get_socket(). Signed-off-by: Geliang Tang --- drivers/block/nbd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index c5e26fc98d1a..9cf89d53839a 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1222,8 +1223,9 @@ static struct socket *nbd_get_socket(struct nbd_devic= e *nbd, unsigned long fd, return NULL; =20 if (!sk_is_tcp(sock->sk) && + !msk_is_mptcp(sock->sk) && !sk_is_stream_unix(sock->sk)) { - dev_err(disk_to_dev(nbd->disk), "Unsupported socket: should be TCP or UN= IX.\n"); + dev_err(disk_to_dev(nbd->disk), "Unsupported socket: should be TCP, MPTC= P or UNIX.\n"); *err =3D -EINVAL; sockfd_put(sock); return NULL; --=20 2.55.0 From nobody Thu Nov 5 07:28:11 2026 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793010944; b=AUNUFoiVoZje9HVwzbE/wbxJdfUTEHfha/SShnGzoKC5emy9yPmxCge6mAX0co5b+bi3 VgljC+81CPgFOtADvcnqQSkokNs73yedNBmHnjfiFtVV2VwaYykrn/DAYwg4o2abGPQMx nmMCFHzMMxdwars4JtV8HeZHErtjBSjPGehoCHINxnuzwsPQnmn3R76Og9TGAQnlMiWeK NYcdhRgIsMSSiJWbsuhsUmGkjg15KwowYzLFLy76V5ZJdn6BIfWMhHayqhjP6Tu8KEN7Y m+SnR0moaEof+L8Qkp/nqylt2YbBb94UEKr9SciS5hMj0IyM67EEbAczLu0eZj/Lzgw== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793010944; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=AwedCw9HauZAg9E7H5gCp0Hty7nvYJAYUbyT0DPW7q8=; b=Dw8RuMUk3IEuJaPhyEaaga/5HP5KMAEit2Lxxp6rpNXKL2JdvEjakpOeQdMr+hxjpw9n gxOBx4cFvAoGQpFPdSdr69gJKq+JUK77hZePj/igA7+aUfnZNy1mC9u+S4dzTEqdf1ccD ts3BGNnmGBTb6YExMf90NO6wWRWtDOYOkjpZZ9D5UjOh9ESetE3RUixaIUQcDShtWcl5R oJBmle6P05ikqt2sGb1XUtLeP+WJD6ALVh/5Z5iOP10w/w7cA9EvntLv73TEZdrbN0qB6 GdAsYLdLHdIR7P0CHfawQYVYryZNPxEM7x2fCof9gILRI31mf/ZESM9zn28mZKFNrRQ== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=Ctrl5r55; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 426F5606A31A for ; Mon, 26 Oct 2026 10:35:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=Ctrl5r55 Received: by smtp.kernel.org (Postfix) with ESMTPSA id EAED01F031E1; Mon, 26 Oct 2026 10:35:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793010944; bh=AwedCw9HauZAg9E7H5gCp0Hty7nvYJAYUbyT0DPW7q8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Ctrl5r55k2uvteKAfaMAltjlLJjj/pqwXGCCu7LIc/DVScUhM7cZBPK8IJOIJtM5b llry93iuuSjB4VLOFGMkaQtYkay5IR+lumf4bQYYVUN3mwU67Dl4WbJMHO1znra+Et qPaZDivW8POjmIsH7Ug6bRGJL2PhTiIxmAWzcRK7EQLrkD0V0FuQA0csrrncFRz/K4 NtDTRDS7nGrqPdCpIq7V7uSPdau+R6xZbID/a0epDZSXYqfT87kxzAyk7tG4dpQrzI TBhp2uf52W5e7HRSqq9ygSA8W31NxgdpeYNUi5alvP93g0ISETLx6K3hIieBQj/1Lg lt0p9vstPFRrw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v2 4/4] selftests: mptcp: add mptcp nbd tests Date: Mon, 26 Oct 2026 18:35:28 +0800 Message-ID: <14de6d44e34c880f684ce171784dc04407e8958c.1793010744.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang Add mptcp_nbd.sh to verify NBD (Network Block Device) works correctly over both TCP and MPTCP. Both ns1 and ns2 have 4 virtual network interfaces, each limited to 1000 Mbit/s (125 MB/s). When running NBD over TCP, fio tests show read/write bandwidth of about 110 MiB/s: # ./mptcp_nbd.sh tcp Negotiation: ..size =3D 256MB Connected /dev/nbd0 connected fio-3.41 ... ... Run status group 0 (all jobs): READ: bw=3D112MiB/s (117MB/s), 112MiB/s-112MiB/s (117MB/s-117MB/s), \ io=3D1119MiB (1173MB), run=3D10002-10002msec ... ... Run status group 0 (all jobs): WRITE: bw=3D113MiB/s (118MB/s), 113MiB/s-113MiB/s (118MB/s-118MB/s), \ io=3D1129MiB (1184MB), run=3D10002-10002msec With simple MPTCP configuration and running MPTCP NBD, we can achieve about 400 MiB/s read/write bandwidth: # ./mptcp_nbd.sh mptcp INFO: nbd-server lacks native MPTCP, using mptcpize INFO: nbd-client lacks native MPTCP, using mptcpize Negotiation: ..size =3D 256MB Connected /dev/nbd0 connected fio-3.41 ... ... Run status group 0 (all jobs): READ: bw=3D406MiB/s (426MB/s), 406MiB/s-406MiB/s (426MB/s-426MB/s), \ io=3D4063MiB (4261MB), run=3D10001-10001msec ... ... Run status group 0 (all jobs): WRITE: bw=3D376MiB/s (394MB/s), 376MiB/s-376MiB/s (394MB/s-394MB/s), \ io=3D3758MiB (3940MB), run=3D10001-10001msec Signed-off-by: Geliang Tang --- tools/testing/selftests/net/mptcp/Makefile | 1 + tools/testing/selftests/net/mptcp/config | 1 + .../testing/selftests/net/mptcp/mptcp_lib.sh | 13 + .../testing/selftests/net/mptcp/mptcp_nbd.sh | 373 ++++++++++++++++++ 4 files changed, 388 insertions(+) create mode 100755 tools/testing/selftests/net/mptcp/mptcp_nbd.sh diff --git a/tools/testing/selftests/net/mptcp/Makefile b/tools/testing/sel= ftests/net/mptcp/Makefile index 22ba0da2adb8..2c8b12866f81 100644 --- a/tools/testing/selftests/net/mptcp/Makefile +++ b/tools/testing/selftests/net/mptcp/Makefile @@ -13,6 +13,7 @@ TEST_PROGS :=3D \ mptcp_connect_sendfile.sh \ mptcp_connect_splice.sh \ mptcp_join.sh \ + mptcp_nbd.sh \ mptcp_sockopt.sh \ pm_netlink.sh \ simult_flows.sh \ diff --git a/tools/testing/selftests/net/mptcp/config b/tools/testing/selft= ests/net/mptcp/config index 6a96cfbbc461..f6f266211bee 100644 --- a/tools/testing/selftests/net/mptcp/config +++ b/tools/testing/selftests/net/mptcp/config @@ -1,3 +1,4 @@ +CONFIG_BLK_DEV_NBD=3Dy CONFIG_INET_DIAG=3Dm CONFIG_INET_MPTCP_DIAG=3Dm CONFIG_IP_ADVANCED_ROUTER=3Dy diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing= /selftests/net/mptcp/mptcp_lib.sh index e1c8c6fd8820..aee7a73d9772 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh @@ -541,6 +541,19 @@ mptcp_lib_check_tools() { exit ${KSFT_SKIP} fi ;; + "nbd") + if ! command -v nbd-client &> /dev/null || \ + ! command -v nbd-server &> /dev/null; then + mptcp_lib_pr_skip "nbd tools not found" + exit ${KSFT_SKIP} + fi + ;; + "fio") + if ! fio -h &> /dev/null; then + mptcp_lib_pr_skip "fio tool not found" + exit ${KSFT_SKIP} + fi + ;; *) mptcp_lib_pr_fail "Internal error: unsupported tool: ${tool}" exit ${KSFT_FAIL} diff --git a/tools/testing/selftests/net/mptcp/mptcp_nbd.sh b/tools/testing= /selftests/net/mptcp/mptcp_nbd.sh new file mode 100755 index 000000000000..29998be71a98 --- /dev/null +++ b/tools/testing/selftests/net/mptcp/mptcp_nbd.sh @@ -0,0 +1,373 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(dirname "$0")/mptcp_lib.sh" + +ret=3D0 +trtype=3D"${1:-mptcp}" +ns1=3D"" +ns2=3D"" +port=3D$((RANDOM % 10000 + 20000)) +temp_file=3D"" +conf_file=3D"" +pid_file=3D"" +server_pid=3D"" + +export trtype port +export temp_file conf_file pid_file server_pid + +usage() +{ + cat << EOF + +Usage: + + $(basename "$0") [trtype] + + trtype Transport type (tcp|mptcp) - default: mptcp + +EOF +exit ${KSFT_FAIL} +} + +validate_params() +{ + if [[ ! "${trtype}" =3D~ ^(tcp|mptcp)$ ]]; then + echo "Invalid trtype ${trtype}. Must be tcp or mptcp" + usage + fi +} + +# This function is used in the cleanup trap +#shellcheck disable=3DSC2317,SC2329 +cleanup() +{ + # Disconnect nbd device in ns2 + ip netns exec "$ns2" nbd-client -d /dev/nbd0 2>/dev/null || true + + sleep 1 + + # Kill nbd-server in ns1 + if [ -n "${server_pid}" ]; then + ip netns exec "$ns1" kill "${server_pid}" 2>/dev/null || true + ip netns exec "$ns1" kill -9 "${server_pid}" 2>/dev/null || true + fi + + # Clean up temp files + if [ -n "${temp_file}" ]; then + ip netns exec "$ns1" rm -f "${temp_file}" 2>/dev/null || true + fi + if [ -n "${conf_file}" ]; then + ip netns exec "$ns1" rm -f "${conf_file}" 2>/dev/null || true + fi + if [ -n "${pid_file}" ]; then + ip netns exec "$ns1" rm -f "${pid_file}" 2>/dev/null || true + fi + + mptcp_lib_ns_exit "$ns1" "$ns2" + + unset -v trtype port + unset -v temp_file server_pid +} + +init() +{ + mptcp_lib_ns_init ns1 ns2 + + ip netns exec "$ns1" sysctl -qw net.ipv4.tcp_reflect_tos=3D1 + + # ns1 ns2 + # 10.1.1.1 10.1.1.2 + # 10.1.2.1 10.1.2.2 + # 10.1.3.1 10.1.3.2 + # 10.1.4.1 10.1.4.2 + for i in {1..4}; do + ip link add ns1eth"$i" netns "$ns1" type veth peer \ + name ns2eth"$i" netns "$ns2" + ip -net "$ns1" addr add 10.1."$i".1/24 dev ns1eth"$i" + ip -net "$ns1" link set ns1eth"$i" up + ip -net "$ns2" addr add 10.1."$i".2/24 dev ns2eth"$i" + ip -net "$ns2" link set ns2eth"$i" up + ip -net "$ns2" route add default via 10.1."$i".1 \ + dev ns2eth"$i" metric 10"$i" + + # Rate limit to 1000mbit + tc -n "$ns1" qdisc add dev ns1eth"$i" root netem rate 1000mbit + tc -n "$ns2" qdisc add dev ns2eth"$i" root netem rate 1000mbit + done + + mptcp_lib_pm_nl_set_limits "${ns1}" 8 8 + mptcp_lib_pm_nl_add_endpoint "$ns1" 10.1.1.1 flags signal + mptcp_lib_pm_nl_add_endpoint "$ns1" 10.1.2.1 flags signal + mptcp_lib_pm_nl_add_endpoint "$ns1" 10.1.3.1 flags signal + mptcp_lib_pm_nl_add_endpoint "$ns1" 10.1.4.1 flags signal + + mptcp_lib_pm_nl_set_limits "${ns2}" 8 8 + mptcp_lib_pm_nl_add_endpoint "$ns2" 10.1.1.2 flags subflow + mptcp_lib_pm_nl_add_endpoint "$ns2" 10.1.2.2 flags subflow + mptcp_lib_pm_nl_add_endpoint "$ns2" 10.1.3.2 flags subflow + mptcp_lib_pm_nl_add_endpoint "$ns2" 10.1.4.2 flags subflow + + # Create temp files using mktemp for security + temp_file=3D$(mktemp /tmp/nbd_backing_XXXXXX.raw) + conf_file=3D$(mktemp /tmp/nbd_server_XXXXXX.conf) + pid_file=3D$(mktemp /tmp/nbd_server_XXXXXX.pid) +} + +# This function is invoked indirectly +#shellcheck disable=3DSC2317,SC2329 +run_server() +{ + # Create backing file + dd if=3D/dev/zero of=3D"${temp_file}" bs=3D1M count=3D0 seek=3D256 2>/dev= /null + + # Detect MPTCP support: native config or mptcpize fallback + local use_mptcpize=3D"" + local mptcp_opt=3D"" + if [ "${trtype}" =3D "mptcp" ]; then + if ! grep -q '"mptcp"' /usr/bin/nbd-server 2>/dev/null && \ + ! nbd-server --help 2>&1 | grep -qi mptcp; then + if command -v mptcpize &> /dev/null; then + use_mptcpize=3D"mptcpize run -d" + echo "INFO: nbd-server lacks native MPTCP," \ + "using mptcpize" + else + echo "ERROR: no MPTCP support in nbd-server" + return 1 + fi + else + mptcp_opt=3D"mptcp =3D true" + echo "INFO: nbd-server has native MPTCP support" + fi + fi + + cat > "${conf_file}" << CONF +[generic] + port =3D ${port} + listenaddr =3D 0.0.0.0 + ${mptcp_opt} + +[test] + exportname =3D ${temp_file} +CONF + + # Use -n (nodaemon) and background manually for better control + ${use_mptcpize} nbd-server -C "${conf_file}" -n > /dev/null 2>&1 & + server_pid=3D$! + + # Write PID to file for parent process to read + echo "${server_pid}" > "${pid_file}" + + # Verify server is running + if ! kill -0 "${server_pid}" 2>/dev/null; then + echo "nbd-server failed to start" + return 1 + fi +} + +# This function is invoked indirectly +#shellcheck disable=3DSC2317,SC2329 +run_client() +{ + local extra_args=3D() + local nbd_dev=3D"/dev/nbd0" + local server_addr=3D"10.1.1.1" + + local use_mptcpize=3D"" + if [ "${trtype}" =3D "mptcp" ]; then + if nbd-client 2>&1 | grep -qE "\-M|\-\-mptcp"; then + extra_args+=3D("-M") + echo "INFO: nbd-client has native MPTCP support (-M)" + elif command -v mptcpize &> /dev/null; then + use_mptcpize=3D"mptcpize run -d" + echo "INFO: nbd-client lacks native MPTCP," \ + "using mptcpize" + else + echo "ERROR: no MPTCP support in nbd-client" + return 1 + fi + fi + + # Options before positional args: -N name host port device + if ! ${use_mptcpize} nbd-client -N test "${extra_args[@]}" \ + "${server_addr}" "${port}" "${nbd_dev}"; then + echo "Failed to connect ${nbd_dev} to ${server_addr}" + return 1 + fi + + sleep 1 + + # Verify connection + if ! nbd-client -c /dev/nbd0; then + echo "nbd-client check failed" + return 1 + fi + + return 0 +} + +# This function is invoked indirectly +#shellcheck disable=3DSC2317,SC2329 +run_io_test() +{ + local nbd_dev=3D"/dev/nbd0" + local test_data + local read_data + + # Create temp files for data integrity test + test_data=3D$(mktemp /tmp/nbd_test_XXXXXX.bin) + read_data=3D$(mktemp /tmp/nbd_read_XXXXXX.bin) + + # Data integrity test: write and verify + dd if=3D/dev/urandom of=3D"${test_data}" bs=3D1M count=3D10 2>/dev/null + if ! dd if=3D"${test_data}" of=3D"${nbd_dev}" bs=3D1M \ + conv=3Dfdatasync 2>/dev/null; then + echo "dd write failed" + rm -f "${test_data}" "${read_data}" + return 1 + fi + + if ! dd if=3D"${nbd_dev}" of=3D"${read_data}" bs=3D1M count=3D10 \ + 2>/dev/null; then + echo "dd read failed" + rm -f "${test_data}" "${read_data}" + return 1 + fi + + if ! cmp -s "${test_data}" "${read_data}"; then + echo "FAIL: Data integrity check failed" + rm -f "${test_data}" "${read_data}" + return 1 + fi + echo "PASS: Data integrity verified" + rm -f "${test_data}" "${read_data}" + + # dd write test (larger, for performance measurement) + if ! dd if=3D/dev/urandom of=3D"${nbd_dev}" bs=3D4k count=3D1000 \ + conv=3Dfdatasync 2>/dev/null; then + echo "dd write failed" + return 1 + fi + + # dd read test + if ! dd if=3D"${nbd_dev}" of=3D/dev/null bs=3D4k count=3D1000 2>/dev/null= ; then + echo "dd read failed" + return 1 + fi + + # fio random read test + if ! fio --name=3Drandread --direct=3D1 --ioengine=3Dlibaio \ + --blocksize=3D4k --runtime=3D10 --time_based \ + --rw=3Drandread --numjobs=3D1 --iodepth=3D32 \ + --group_reporting --size=3D128M \ + --filename=3D"${nbd_dev}"; then + echo "fio randread failed" + return 1 + fi + + # fio random write test + if ! fio --name=3Drandwrite --direct=3D1 --ioengine=3Dlibaio \ + --blocksize=3D4k --runtime=3D10 --time_based \ + --rw=3Drandwrite --numjobs=3D1 --iodepth=3D32 \ + --group_reporting --size=3D128M \ + --filename=3D"${nbd_dev}"; then + echo "fio randwrite failed" + return 1 + fi + + # Verify MPTCP subflows if trtype is mptcp + if [ "${trtype}" =3D "mptcp" ]; then + local sf_total sf_max tcp_conns is_fallback + sf_total=3D$(ss -Mia | grep -oP "subflows_total:\K[0-9]+" | \ + head -1) + sf_max=3D$(ss -Mia | grep -oP "subflows_max:\K[0-9]+" | head -1) + tcp_conns=3D$(ss -tia | grep -c "tcp-ulp-mptcp" || true) + is_fallback=3D$(ss -Mia | grep -c "fallback" || true) + if [ "${is_fallback}" -gt 0 ]; then + echo "FAIL: MPTCP fell back to TCP!" \ + "subflows_total:${sf_total}" \ + "tcp_subflows:${tcp_conns}" + return 1 + elif [ -n "${sf_total}" ]; then + echo "PASS: MPTCP subflows_total:${sf_total}" \ + "subflows_max:${sf_max}" \ + "tcp_subflows:${tcp_conns}" + else + echo "FAIL: No MPTCP subflows info found" + return 1 + fi + fi + + return 0 +} + +# Check MPTCP support in kernel +mptcp_lib_check_mptcp + +# Check for required tools +mptcp_lib_check_tools ip tc ss nbd fio + +# Check for /dev/nbd0 +if [ ! -b /dev/nbd0 ]; then + mptcp_lib_pr_skip "/dev/nbd0 not found" + exit ${KSFT_SKIP} +fi + +validate_params + +# Check for mptcpize if using MPTCP transport +if [ "${trtype}" =3D "mptcp" ]; then + if ! command -v mptcpize &> /dev/null; then + mptcp_lib_pr_skip "mptcpize tool not found" + exit ${KSFT_SKIP} + fi +fi + +trap cleanup EXIT + +init + +run_test() +{ + if ! ip netns exec "$ns1" bash <<- EOF + $(declare -f run_server) + export trtype port + run_server + exit \$? + EOF + then + ret=3D"${KSFT_FAIL}" + return + fi + + # Get server pid for cleanup from file + server_pid=3D$(ip netns exec "$ns1" cat "${pid_file}" 2>/dev/null) + server_pid=3D"${server_pid:-}" + + # Wait for server to be ready instead of fixed sleep + mptcp_lib_wait_local_port_listen "$ns1" "$port" + + if ! ip netns exec "$ns2" bash <<- EOF + $(declare -f run_client run_io_test) + export trtype port + run_client || exit 1 + run_io_test || exit 1 + exit \$? + EOF + then + ret=3D"${KSFT_FAIL}" + fi + + sleep 1 +} + +run_test "$@" + +if [ "${ret}" -eq 0 ]; then + mptcp_lib_result_pass "nbd over ${trtype} test" +else + mptcp_lib_result_fail "nbd over ${trtype} test" +fi + +mptcp_lib_result_print_all_tap +exit "$ret" --=20 2.55.0