From nobody Wed Apr 1 20:45:07 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3B2373C457D for ; Wed, 1 Apr 2026 12:54:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048055; cv=none; b=UYvpsQq4M+cJGXr5+nXgqAy3JTGwSBSIBpGdXg7+nfHfPMfOAIljE9iKONH1Xq67Pn5sHFgY6rpy68LAnZDmoMzJKZO7MbCSTL3kYaJgcZYUYCuVzd7/nqqo8cb1tthI4yuqO7hM7jhdVGrAtynQKpirRfqoDroJJV8B76PlSSY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048055; c=relaxed/simple; bh=lPqEDVAibGOo8RUs2/Z21JT7XruoP5DXlmqZpTgU6U8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JT8Q7/OxxEkGOb3eLEXheaNntXXZ0IboLOr6/gnU5Q0EeLTSwtjz3G5maqWrwGXeiqCEhjC5BcKlxkHf6DQAbiG47XAjmgNhPKLKED9GdjtLXyvhzDXKz0eAI3uOkHKeF4sPrd10epeoIUvyWPildsNvp1fOAJnElPk0iW2WrSg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NYmtDebO; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NYmtDebO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D4657C4CEF7; Wed, 1 Apr 2026 12:54:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1775048054; bh=lPqEDVAibGOo8RUs2/Z21JT7XruoP5DXlmqZpTgU6U8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NYmtDebOcL8hEvcldFyLBmoHnM4zT7bXxrZpZFvbxtTf1w0PfmU6u7+/B0u3ZtjV8 JxqNfDHlQmc9Hr9SOcvuYd7TZWPOW62Ve1v2dxmFRr5yea6+s+VW4MbO9e+/jzvcan 1N4u3uq8aMtCftCF5XwE07Guds11krW01H2fL1VmE9tMWRQ0GjqYVCvH+085mcgP3W yKGlq6c9uU6mK+h8xP7xCkjPSox8naY4gHAuP77/wLIdFnq/Xg7MY05j+kcUE11dU3 z2icB/TRgNCKy8MY83jwqpCnB3Ymprfk2ZMFR81IF+vBg05dvFa9OjmNUVqKSpp8oG 0k3GZq2YdiNLg== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang , Hannes Reinecke , zhenwei pi , Hui Zhu , Gang Yan Subject: [RFC mptcp-next v8 1/7] nvmet-tcp: define target tcp_proto struct Date: Wed, 1 Apr 2026 20:53:39 +0800 Message-ID: <519fa1af4856352621362298296af7b0ed6765aa.1775047736.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.51.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang To add MPTCP support in "NVMe over TCP", the target side needs to pass IPPROTO_MPTCP to sock_create() instead of IPPROTO_TCP to create an MPTCP socket. Additionally, the setsockopt operations for this socket need to be switched to a set of MPTCP-specific functions. This patch defines the nvmet_tcp_proto structure, which contains the protocol of the socket and a set of function pointers for these socket operations. A "proto" field is also added to struct nvmet_tcp_port. A TCP-specific version of struct nvmet_tcp_proto is defined. In nvmet_tcp_add_port(), port->proto is set to nvmet_tcp_proto based on whether trtype is TCP. All locations that previously called TCP setsockopt functions are updated to call the corresponding function pointers in the nvmet_tcp_proto structure. This new nvmet_fabrics_ops is selected in nvmet_tcp_done_recv_pdu() based on the protocol type. RCU protection is added when accessing queue->port in the I/O path (nvmet_tcp_alloc_cmd, nvmet_tcp_done_recv_pdu, nvmet_tcp_set_queue_sock) to prevent use-after-free when a port is removed while asynchronous operations (e.g., TLS handshake) are pending. The port structure is released using kfree_rcu() in nvmet_tcp_remove_port(), and queue->port is assigned using rcu_assign_pointer() in nvmet_tcp_alloc_queue(). Cc: Hannes Reinecke Co-developed-by: zhenwei pi Signed-off-by: zhenwei pi Co-developed-by: Hui Zhu Signed-off-by: Hui Zhu Co-developed-by: Gang Yan Signed-off-by: Gang Yan Signed-off-by: Geliang Tang --- drivers/nvme/target/tcp.c | 66 ++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index acc71a26733f..d8d3d97de8ed 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include =20 #include "nvmet.h" @@ -198,12 +199,24 @@ struct nvmet_tcp_queue { void (*write_space)(struct sock *); }; =20 +struct nvmet_tcp_proto { + int protocol; + void (*set_reuseaddr)(struct sock *sk); + void (*set_nodelay)(struct sock *sk); + void (*set_priority)(struct sock *sk, u32 priority); + void (*no_linger)(struct sock *sk); + void (*set_tos)(struct sock *sk, int val); + const struct nvmet_fabrics_ops *ops; +}; + struct nvmet_tcp_port { + struct rcu_head rcu; struct socket *sock; struct work_struct accept_work; struct nvmet_port *nport; struct sockaddr_storage addr; void (*data_ready)(struct sock *); + const struct nvmet_tcp_proto *proto; }; =20 static DEFINE_IDA(nvmet_tcp_queue_ida); @@ -1027,6 +1040,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_q= ueue *queue) { struct nvme_tcp_hdr *hdr =3D &queue->pdu.cmd.hdr; struct nvme_command *nvme_cmd =3D &queue->pdu.cmd.cmd; + const struct nvmet_fabrics_ops *ops; struct nvmet_req *req; int ret; =20 @@ -1067,7 +1081,10 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_= queue *queue) req =3D &queue->cmd->req; memcpy(req->cmd, nvme_cmd, sizeof(*nvme_cmd)); =20 - if (unlikely(!nvmet_req_init(req, &queue->nvme_sq, &nvmet_tcp_ops))) { + rcu_read_lock(); + ops =3D rcu_dereference(queue->port)->proto->ops; + rcu_read_unlock(); + if (unlikely(!nvmet_req_init(req, &queue->nvme_sq, ops))) { pr_err("failed cmd %p id %d opcode %d, data_len: %d, status: %04x\n", req->cmd, req->cmd->common.command_id, req->cmd->common.opcode, @@ -1686,6 +1703,7 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_= queue *queue) { struct socket *sock =3D queue->sock; struct inet_sock *inet =3D inet_sk(sock->sk); + const struct nvmet_tcp_proto *proto; int ret; =20 ret =3D kernel_getsockname(sock, @@ -1698,19 +1716,23 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tc= p_queue *queue) if (ret < 0) return ret; =20 + rcu_read_lock(); + proto =3D rcu_dereference(queue->port)->proto; + rcu_read_unlock(); + /* * Cleanup whatever is sitting in the TCP transmit queue on socket * close. This is done to prevent stale data from being sent should * the network connection be restored before TCP times out. */ - sock_no_linger(sock->sk); + proto->no_linger(sock->sk); =20 if (so_priority > 0) - sock_set_priority(sock->sk, so_priority); + proto->set_priority(sock->sk, so_priority); =20 /* Set socket type of service */ if (inet->rcv_tos > 0) - ip_sock_set_tos(sock->sk, inet->rcv_tos); + proto->set_tos(sock->sk, inet->rcv_tos); =20 ret =3D 0; write_lock_bh(&sock->sk->sk_callback_lock); @@ -2030,6 +2052,16 @@ static void nvmet_tcp_listen_data_ready(struct sock = *sk) read_unlock_bh(&sk->sk_callback_lock); } =20 +static const struct nvmet_tcp_proto nvmet_tcp_proto =3D { + .protocol =3D IPPROTO_TCP, + .set_reuseaddr =3D sock_set_reuseaddr, + .set_nodelay =3D tcp_sock_set_nodelay, + .set_priority =3D sock_set_priority, + .no_linger =3D sock_no_linger, + .set_tos =3D ip_sock_set_tos, + .ops =3D &nvmet_tcp_ops, +}; + static int nvmet_tcp_add_port(struct nvmet_port *nport) { struct nvmet_tcp_port *port; @@ -2054,6 +2086,13 @@ static int nvmet_tcp_add_port(struct nvmet_port *npo= rt) goto err_port; } =20 + if (nport->disc_addr.trtype =3D=3D NVMF_TRTYPE_TCP) { + port->proto =3D &nvmet_tcp_proto; + } else { + ret =3D -EINVAL; + goto err_port; + } + ret =3D inet_pton_with_scope(&init_net, af, nport->disc_addr.traddr, nport->disc_addr.trsvcid, &port->addr); if (ret) { @@ -2068,7 +2107,7 @@ static int nvmet_tcp_add_port(struct nvmet_port *npor= t) port->nport->inline_data_size =3D NVMET_TCP_DEF_INLINE_DATA_SIZE; =20 ret =3D sock_create(port->addr.ss_family, SOCK_STREAM, - IPPROTO_TCP, &port->sock); + port->proto->protocol, &port->sock); if (ret) { pr_err("failed to create a socket\n"); goto err_port; @@ -2077,10 +2116,10 @@ static int nvmet_tcp_add_port(struct nvmet_port *np= ort) port->sock->sk->sk_user_data =3D port; port->data_ready =3D port->sock->sk->sk_data_ready; port->sock->sk->sk_data_ready =3D nvmet_tcp_listen_data_ready; - sock_set_reuseaddr(port->sock->sk); - tcp_sock_set_nodelay(port->sock->sk); + port->proto->set_reuseaddr(port->sock->sk); + port->proto->set_nodelay(port->sock->sk); if (so_priority > 0) - sock_set_priority(port->sock->sk, so_priority); + port->proto->set_priority(port->sock->sk, so_priority); =20 ret =3D kernel_bind(port->sock, (struct sockaddr_unsized *)&port->addr, sizeof(port->addr)); @@ -2111,11 +2150,16 @@ static int nvmet_tcp_add_port(struct nvmet_port *np= ort) static void nvmet_tcp_destroy_port_queues(struct nvmet_tcp_port *port) { struct nvmet_tcp_queue *queue; + struct nvmet_tcp_port *qport; =20 mutex_lock(&nvmet_tcp_queue_mutex); - list_for_each_entry(queue, &nvmet_tcp_queue_list, queue_list) - if (queue->port =3D=3D port) + list_for_each_entry(queue, &nvmet_tcp_queue_list, queue_list) { + rcu_read_lock(); + qport =3D rcu_dereference(queue->port); + rcu_read_unlock(); + if (qport =3D=3D port) kernel_sock_shutdown(queue->sock, SHUT_RDWR); + } mutex_unlock(&nvmet_tcp_queue_mutex); } =20 @@ -2135,7 +2179,7 @@ static void nvmet_tcp_remove_port(struct nvmet_port *= nport) nvmet_tcp_destroy_port_queues(port); =20 sock_release(port->sock); - kfree(port); + kfree_rcu(port, rcu); } =20 static void nvmet_tcp_delete_ctrl(struct nvmet_ctrl *ctrl) --=20 2.51.0 From nobody Wed Apr 1 20:45:07 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D6F0339BFF4 for ; Wed, 1 Apr 2026 12:54:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048057; cv=none; b=qOOkuuVYAKnQKBLUFgtaXx423owUhVuCPPvHIO6sQyk/ScvKNuezR5QOpLrEdra4d2M+hKikqHaqWy50pw61J9xWQIu+1gcAKmFEpoqz1OMG6JGsywIHEHBT0V7N8XwLO2ypbfGUMSxQiKQasrQRAEz2hDKRW+cgEjgx/Nw2zyM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048057; c=relaxed/simple; bh=GjBdqHu3TDh4vJikVg8CChp0XJ2Yqqvj8KbktsUL7X8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DhwGhsdTOsO9Z4urE44txYy9M2XqaznL10R5ZpLP/Oo4OJgW6e/E+dk+CjXymTj9aF+NUyfQO3rS+dD78wyd5Pag8IKS8Cd2T3Fjae4m50cWF4m8J3+ippzpIf/0fxdIbead/VT1lhwHwECyGIud7l1AyYHVprdPRaYmA0ikBI0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=IJljZ5Dk; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="IJljZ5Dk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5EE72C4CEF7; Wed, 1 Apr 2026 12:54:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1775048057; bh=GjBdqHu3TDh4vJikVg8CChp0XJ2Yqqvj8KbktsUL7X8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IJljZ5DkbdJxP8BQAK8prKYoCPqqrO5DfvPbjRS+8Gy5J90AnO2SgvoF9Ld4iaM3Z ekRBKNmXSJQij1xD24Y/mRuZfLTZIqtQYLxkH034Baq211os5mYZLAFpr8TqWFZ06X MWj7wvpi9pyV8Qm+WPWmSPstYMtjKvZ19NcSTi2eEyCvbcbo4MywnHO/bCgL1lGKa8 SBWqpw+nRh9DY02o/P2ZMoUqxWme2+63fgsBO9uIc6h6u70S2eLdMU3R7llDpIvhiu 4pdNLXaQ4VOsT3gMZU8VAgV6Jxh5j3EitY7hQrcr5cReoNlRLNsc5c+yEy/ndlfun/ 168H521MAvOGw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang , Hannes Reinecke , zhenwei pi , Hui Zhu , Gang Yan Subject: [RFC mptcp-next v8 2/7] nvmet-tcp: register target mptcp transport Date: Wed, 1 Apr 2026 20:53:40 +0800 Message-ID: <502c21c5ebb8554710aa606327fec3334e3a58d5.1775047736.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.51.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang This patch adds a new nvme target transport type NVMF_TRTYPE_MPTCP for MPTCP. And defines a new nvmet_fabrics_ops named nvmet_mptcp_ops, which is almost the same as nvmet_tcp_ops except .type. It is registered in nvmet_tcp_init() and unregistered in nvmet_tcp_exit(). A MODULE_ALIAS for "nvmet-transport-4" is also added. v2: - use trtype instead of tsas (Hannes). v3: - check mptcp protocol from disc_addr.trtype instead of passing a parameter (Hannes). v4: - check CONFIG_MPTCP. Cc: Hannes Reinecke Co-developed-by: zhenwei pi Signed-off-by: zhenwei pi Co-developed-by: Hui Zhu Signed-off-by: Hui Zhu Co-developed-by: Gang Yan Signed-off-by: Gang Yan Signed-off-by: Geliang Tang --- drivers/nvme/target/configfs.c | 1 + drivers/nvme/target/tcp.c | 27 +++++++++++++++++++++++++++ include/linux/nvme.h | 1 + 3 files changed, 29 insertions(+) diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index 3088e044dbcb..4b7498ffb102 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -38,6 +38,7 @@ static struct nvmet_type_name_map nvmet_transport[] =3D { { NVMF_TRTYPE_RDMA, "rdma" }, { NVMF_TRTYPE_FC, "fc" }, { NVMF_TRTYPE_TCP, "tcp" }, + { NVMF_TRTYPE_MPTCP, "mptcp" }, { NVMF_TRTYPE_PCI, "pci" }, { NVMF_TRTYPE_LOOP, "loop" }, }; diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index d8d3d97de8ed..0c1ce80a5179 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -2264,6 +2264,21 @@ static const struct nvmet_fabrics_ops nvmet_tcp_ops = =3D { .host_traddr =3D nvmet_tcp_host_port_addr, }; =20 +#ifdef CONFIG_MPTCP +static const struct nvmet_fabrics_ops nvmet_mptcp_ops =3D { + .owner =3D THIS_MODULE, + .type =3D NVMF_TRTYPE_MPTCP, + .msdbd =3D 1, + .add_port =3D nvmet_tcp_add_port, + .remove_port =3D nvmet_tcp_remove_port, + .queue_response =3D nvmet_tcp_queue_response, + .delete_ctrl =3D nvmet_tcp_delete_ctrl, + .install_queue =3D nvmet_tcp_install_queue, + .disc_traddr =3D nvmet_tcp_disc_port_addr, + .host_traddr =3D nvmet_tcp_host_port_addr, +}; +#endif + static int __init nvmet_tcp_init(void) { int ret; @@ -2277,6 +2292,14 @@ static int __init nvmet_tcp_init(void) if (ret) goto err; =20 +#ifdef CONFIG_MPTCP + ret =3D nvmet_register_transport(&nvmet_mptcp_ops); + if (ret) { + nvmet_unregister_transport(&nvmet_tcp_ops); + goto err; + } +#endif + return 0; err: destroy_workqueue(nvmet_tcp_wq); @@ -2287,6 +2310,9 @@ static void __exit nvmet_tcp_exit(void) { struct nvmet_tcp_queue *queue; =20 +#ifdef CONFIG_MPTCP + nvmet_unregister_transport(&nvmet_mptcp_ops); +#endif nvmet_unregister_transport(&nvmet_tcp_ops); =20 flush_workqueue(nvmet_wq); @@ -2306,3 +2332,4 @@ module_exit(nvmet_tcp_exit); MODULE_DESCRIPTION("NVMe target TCP transport driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("nvmet-transport-3"); /* 3 =3D=3D NVMF_TRTYPE_TCP */ +MODULE_ALIAS("nvmet-transport-4"); /* 4 =3D=3D NVMF_TRTYPE_MPTCP */ diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 655d194f8e72..8069667ad47e 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -68,6 +68,7 @@ enum { NVMF_TRTYPE_RDMA =3D 1, /* RDMA */ NVMF_TRTYPE_FC =3D 2, /* Fibre Channel */ NVMF_TRTYPE_TCP =3D 3, /* TCP/IP */ + NVMF_TRTYPE_MPTCP =3D 4, /* Multipath TCP */ NVMF_TRTYPE_LOOP =3D 254, /* Reserved for host usage */ NVMF_TRTYPE_MAX, }; --=20 2.51.0 From nobody Wed Apr 1 20:45:07 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4A1EC39BFF4 for ; Wed, 1 Apr 2026 12:54:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048060; cv=none; b=sJZ03VWf+AC4meZ/YkqedweJHbl4mNC8UCGfS9J+it4r9SBKyRkQNKH542z6S45id5DI06O5HUbxKEt3QR/CUyzpjiVrpEZmnKtNN+ahvdKVcnnTKzPEAfZr79/TKfUiUwtGKi9t/Ypb7GFgGTT7bzCD4++2d8Lt3Bl94Usd/nk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048060; c=relaxed/simple; bh=+CxdxZziYNSoIsrcEmX64CewimIRaPLP6EG5xX7+pOI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DtsvRYRH/0Ibbn/E82I1vXR1M8RQu0ybe5J1J5Z8IqByfPSLl58t86m6n/Z5pRYL5nPYZ3HndrKc3sn4oZeMW+FTwrpfUZFyCaPFL9amUc6MY5k9Wm2HnuRlMF9OeZafAWze+hbWAvwxfv46CbtwzwCIsm6A4al90HM7eJ5/oLY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=efISHa/p; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="efISHa/p" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 41780C116C6; Wed, 1 Apr 2026 12:54:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1775048060; bh=+CxdxZziYNSoIsrcEmX64CewimIRaPLP6EG5xX7+pOI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=efISHa/p7TFq5nkIYdEqmhphaacOshhnuhy8mWVK4UoZeB+241UGAHK0vzqGAW8vA GuRQKhBSuKCuZUZky6uG1KDd8MeRxs1DZVBaxYTyPgYuPvAs5UZmrnqPowrSIAKAZP op5SGA9bP3wXXWy0yYraqT/TIQ9TJ0Vfw9LwB2czUaRp6ZMeMpZYV7o1LiH2li8f0A eBBG7Ac760VPn2FzLTGoRsQPQgMqEP5v+f8Oja6TUexgZnd1fj5m4juKEmYP1NM+aj oluQH58Ao3VleQ1Qr7Fi7M5y1Z9vkKtDn29I567LG68eRt3K8xD+aRuwXC7x+BTFxv IbXH/YbPW/m9A== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang , Hannes Reinecke , zhenwei pi , Hui Zhu , Gang Yan Subject: [RFC mptcp-next v8 3/7] nvmet-tcp: implement target mptcp proto Date: Wed, 1 Apr 2026 20:53:41 +0800 Message-ID: X-Mailer: git-send-email 2.51.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang This patch introduces a new NVMe target transport type NVMF_TRTYPE_MPTCP to support MPTCP. An MPTCP-specific version of struct nvmet_tcp_proto is implemented, and it is assigned to port->proto when the transport type is MPTCP. Dedicated MPTCP helpers are introduced for setting socket options. These helpers set the values on the first subflow socket of an MPTCP connection. The values are then synchronized to other newly created subflows in sync_socket_options(). Cc: Hannes Reinecke Co-developed-by: zhenwei pi Signed-off-by: zhenwei pi Co-developed-by: Hui Zhu Signed-off-by: Hui Zhu Co-developed-by: Gang Yan Signed-off-by: Gang Yan Signed-off-by: Geliang Tang --- drivers/nvme/target/tcp.c | 19 ++++++++ include/net/mptcp.h | 20 +++++++++ net/mptcp/sockopt.c | 91 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 0c1ce80a5179..afded6a84da6 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -225,6 +225,9 @@ static DEFINE_MUTEX(nvmet_tcp_queue_mutex); =20 static struct workqueue_struct *nvmet_tcp_wq; static const struct nvmet_fabrics_ops nvmet_tcp_ops; +#ifdef CONFIG_MPTCP +static const struct nvmet_fabrics_ops nvmet_mptcp_ops; +#endif static void nvmet_tcp_free_cmd(struct nvmet_tcp_cmd *c); static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd); =20 @@ -2062,6 +2065,18 @@ static const struct nvmet_tcp_proto nvmet_tcp_proto = =3D { .ops =3D &nvmet_tcp_ops, }; =20 +#ifdef CONFIG_MPTCP +static const struct nvmet_tcp_proto nvmet_mptcp_proto =3D { + .protocol =3D IPPROTO_MPTCP, + .set_reuseaddr =3D mptcp_sock_set_reuseaddr, + .set_nodelay =3D mptcp_sock_set_nodelay, + .set_priority =3D mptcp_sock_set_priority, + .no_linger =3D mptcp_sock_no_linger, + .set_tos =3D mptcp_sock_set_tos, + .ops =3D &nvmet_mptcp_ops, +}; +#endif + static int nvmet_tcp_add_port(struct nvmet_port *nport) { struct nvmet_tcp_port *port; @@ -2088,6 +2103,10 @@ static int nvmet_tcp_add_port(struct nvmet_port *npo= rt) =20 if (nport->disc_addr.trtype =3D=3D NVMF_TRTYPE_TCP) { port->proto =3D &nvmet_tcp_proto; +#ifdef CONFIG_MPTCP + } else if (nport->disc_addr.trtype =3D=3D NVMF_TRTYPE_MPTCP) { + port->proto =3D &nvmet_mptcp_proto; +#endif } else { ret =3D -EINVAL; goto err_port; diff --git a/include/net/mptcp.h b/include/net/mptcp.h index 4cf59e83c1c5..91ce7b9b639d 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -237,6 +237,16 @@ static inline __be32 mptcp_reset_option(const struct s= k_buff *skb) } =20 void mptcp_active_detect_blackhole(struct sock *sk, bool expired); + +void mptcp_sock_set_reuseaddr(struct sock *sk); + +void mptcp_sock_set_nodelay(struct sock *sk); + +void mptcp_sock_set_priority(struct sock *sk, u32 priority); + +void mptcp_sock_no_linger(struct sock *sk); + +void mptcp_sock_set_tos(struct sock *sk, int val); #else =20 static inline void mptcp_init(void) @@ -323,6 +333,16 @@ static inline struct request_sock *mptcp_subflow_reqsk= _alloc(const struct reques static inline __be32 mptcp_reset_option(const struct sk_buff *skb) { retu= rn htonl(0u); } =20 static inline void mptcp_active_detect_blackhole(struct sock *sk, bool exp= ired) { } + +static inline void mptcp_sock_set_reuseaddr(struct sock *sk) { } + +static inline void mptcp_sock_set_nodelay(struct sock *sk) { } + +static inline void mptcp_sock_set_priority(struct sock *sk, u32 priority) = { } + +static inline void mptcp_sock_no_linger(struct sock *sk) { } + +static inline void mptcp_sock_set_tos(struct sock *sk, int val) { } #endif /* CONFIG_MPTCP */ =20 #if IS_ENABLED(CONFIG_MPTCP_IPV6) diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index de90a2897d2d..0f18398932a0 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -1537,6 +1537,7 @@ static void sync_socket_options(struct mptcp_sock *ms= k, struct sock *ssk) static const unsigned int tx_rx_locks =3D SOCK_RCVBUF_LOCK | SOCK_SNDBUF_= LOCK; struct sock *sk =3D (struct sock *)msk; bool keep_open; + u32 priority; =20 keep_open =3D sock_flag(sk, SOCK_KEEPOPEN); if (ssk->sk_prot->keepalive) @@ -1586,6 +1587,11 @@ static void sync_socket_options(struct mptcp_sock *m= sk, struct sock *ssk) inet_assign_bit(FREEBIND, ssk, inet_test_bit(FREEBIND, sk)); inet_assign_bit(BIND_ADDRESS_NO_PORT, ssk, inet_test_bit(BIND_ADDRESS_NO_= PORT, sk)); WRITE_ONCE(inet_sk(ssk)->local_port_range, READ_ONCE(inet_sk(sk)->local_p= ort_range)); + + ssk->sk_reuse =3D sk->sk_reuse; + priority =3D READ_ONCE(sk->sk_priority); + if (priority > 0) + sock_set_priority(ssk, priority); } =20 void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk) @@ -1652,3 +1658,88 @@ int mptcp_set_rcvlowat(struct sock *sk, int val) } return 0; } + +void mptcp_sock_set_reuseaddr(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct sock *ssk; + + lock_sock(sk); + sockopt_seq_inc(msk); + sk->sk_reuse =3D SK_CAN_REUSE; + ssk =3D __mptcp_nmpc_sk(msk); + if (IS_ERR(ssk)) + goto unlock; + sock_set_reuseaddr(ssk); +unlock: + release_sock(sk); +} +EXPORT_SYMBOL(mptcp_sock_set_reuseaddr); + +void mptcp_sock_set_nodelay(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct sock *ssk; + + lock_sock(sk); + sockopt_seq_inc(msk); + msk->nodelay =3D true; + ssk =3D __mptcp_nmpc_sk(msk); + if (IS_ERR(ssk)) + goto unlock; + lock_sock(ssk); + __tcp_sock_set_nodelay(ssk, true); + release_sock(ssk); +unlock: + release_sock(sk); +} +EXPORT_SYMBOL(mptcp_sock_set_nodelay); + +void mptcp_sock_set_priority(struct sock *sk, u32 priority) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct sock *ssk =3D msk->first; + + if (!ssk) + return; + + lock_sock(sk); + sockopt_seq_inc(msk); + sock_set_priority(sk, priority); + lock_sock(ssk); + sock_set_priority(ssk, priority); + release_sock(ssk); + release_sock(sk); +} +EXPORT_SYMBOL(mptcp_sock_set_priority); + +void mptcp_sock_no_linger(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + + if (!msk->first) + return; + + lock_sock(sk); + sockopt_seq_inc(msk); + WRITE_ONCE(sk->sk_lingertime, 0); + sock_set_flag(sk, SOCK_LINGER); + sock_no_linger(msk->first); + release_sock(sk); +} +EXPORT_SYMBOL(mptcp_sock_no_linger); + +void mptcp_sock_set_tos(struct sock *sk, int val) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + + if (!msk->first) + return; + + lock_sock(sk); + sockopt_seq_inc(msk); + __ip_sock_set_tos(sk, val); + ip_sock_set_tos(msk->first, val); + release_sock(sk); +} +EXPORT_SYMBOL(mptcp_sock_set_tos); --=20 2.51.0 From nobody Wed Apr 1 20:45:07 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8DE7540823D for ; Wed, 1 Apr 2026 12:54:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048062; cv=none; b=q4mmilQKZyKLK/EvkatBGijeaZpOUFLlyDYd0gIGCjqR1OPFLFj/c3hKYb/iSbCWpgCzZsx91T/AivFQwCSXvGkK4/g2MBMqWqrW/dx55iW+vL/RwCk22RbcoXetojcL7r4saxozSjVu9yzM//4puNO05ZjCsoFQDTYSc6zfTHo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048062; c=relaxed/simple; bh=k4kz0JiqAuLT1IazLigfeNqVPkREnEsIkrzlroD0eAw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=F0E58aNJvuGhkGMGr04O6tjNOMVbVALvw762cPXy8MoOXEAXUbj23Yn1U4FR3TjuLPZW3VrftAjADGbhOqsGioiEMaUqAdnjvxEbqrg6fEwwfPAphPWZa+iEFX9spDnqRzxbbfxH6aGQD8YtfewWZNlp+pM+Z96+Q2NIvhv6kGU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uwVHJ+f7; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uwVHJ+f7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A8234C2BCB0; Wed, 1 Apr 2026 12:54:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1775048062; bh=k4kz0JiqAuLT1IazLigfeNqVPkREnEsIkrzlroD0eAw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uwVHJ+f7zlOcOxxfulYg/WWZM8rJ3r0G+MsYHCH3QUn0cLpBeEUBxYPS6wbIFnhPM I1TX7KdIk/lpWS1wdtJuaEC2eJbwQVlcuXjeOY2qc1zQPd9a4kxOEzAEvCjOjxiqil 0pFhntM92/lpj1P5wkZIO7xMcJTdDj5etstiWhtn4ddUfpnP2P466st6xJVP4VNjG1 Z/TRM+uQ7RcquJNyvYqp5t5VJmX/vhWn0qzgDWKekfAOzVlyzDg7zxwx3ovol4Gnqf vxHYTm//DA0k5n71H0QWCoV1PiTpJudUf/b/x2p186T3Y1jaK7HYp+5xocYa3XvSmV yLEUlP+ukpTcQ== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang , Hannes Reinecke , zhenwei pi , Hui Zhu , Gang Yan Subject: [RFC mptcp-next v8 4/7] nvme-tcp: define host tcp_proto struct Date: Wed, 1 Apr 2026 20:53:42 +0800 Message-ID: <643f4040bb6cd03ff408b90ba7c160eed5c3895d.1775047736.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.51.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang To add MPTCP support in "NVMe over TCP", the host side needs to pass IPPROTO_MPTCP to sock_create_kern() instead of IPPROTO_TCP to create an MPTCP socket. Similar to the target-side nvmet_tcp_proto, this patch defines the host-side nvme_tcp_proto structure, which contains the protocol of the socket and a set of function pointers for socket operations. The only difference is that it defines .set_syncnt instead of .set_reuseaddr. A TCP-specific version of this structure is defined, and a proto field is added to nvme_tcp_ctrl. When the transport string is "tcp", it is assigned to ctrl->proto using RCU assignment. All locations that previously called TCP setsockopt functions are updated to call the corresponding function pointers in the nvme_tcp_proto structure. RCU protection is added when accessing ctrl->proto in the I/O path (nvme_tcp_alloc_queue()) to prevent use-after-free when the controller is being removed concurrently. The proto field is released using kfree_rcu() in nvme_tcp_free_ctrl(). Cc: Hannes Reinecke Co-developed-by: zhenwei pi Signed-off-by: zhenwei pi Co-developed-by: Hui Zhu Signed-off-by: Hui Zhu Co-developed-by: Gang Yan Signed-off-by: Gang Yan Signed-off-by: Geliang Tang --- drivers/nvme/host/tcp.c | 53 ++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 243dab830dc8..30e4d915011e 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -182,7 +183,19 @@ struct nvme_tcp_queue { void (*write_space)(struct sock *); }; =20 +struct nvme_tcp_proto { + int protocol; + int (*set_syncnt)(struct sock *sk, int val); + void (*set_nodelay)(struct sock *sk); + void (*no_linger)(struct sock *sk); + void (*set_priority)(struct sock *sk, u32 priority); + void (*set_tos)(struct sock *sk, int val); + const struct nvme_ctrl_ops *ops; +}; + struct nvme_tcp_ctrl { + struct rcu_head rcu; + /* read only in the hot path */ struct nvme_tcp_queue *queues; struct blk_mq_tag_set tag_set; @@ -198,6 +211,8 @@ struct nvme_tcp_ctrl { struct delayed_work connect_work; struct nvme_tcp_request async_req; u32 io_queues[HCTX_MAX_TYPES]; + + const struct nvme_tcp_proto *proto; }; =20 static LIST_HEAD(nvme_tcp_ctrl_list); @@ -1767,6 +1782,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nct= rl, int qid, { struct nvme_tcp_ctrl *ctrl =3D to_tcp_ctrl(nctrl); struct nvme_tcp_queue *queue =3D &ctrl->queues[qid]; + const struct nvme_tcp_proto *proto; int ret, rcv_pdu_size; struct file *sock_file; =20 @@ -1783,9 +1799,13 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nc= trl, int qid, queue->cmnd_capsule_len =3D sizeof(struct nvme_command) + NVME_TCP_ADMIN_CCSZ; =20 + rcu_read_lock(); + proto =3D rcu_dereference(ctrl->proto); + rcu_read_unlock(); + ret =3D sock_create_kern(current->nsproxy->net_ns, ctrl->addr.ss_family, SOCK_STREAM, - IPPROTO_TCP, &queue->sock); + proto->protocol, &queue->sock); if (ret) { dev_err(nctrl->device, "failed to create socket: %d\n", ret); @@ -1802,24 +1822,24 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *n= ctrl, int qid, nvme_tcp_reclassify_socket(queue->sock); =20 /* Single syn retry */ - tcp_sock_set_syncnt(queue->sock->sk, 1); + proto->set_syncnt(queue->sock->sk, 1); =20 /* Set TCP no delay */ - tcp_sock_set_nodelay(queue->sock->sk); + proto->set_nodelay(queue->sock->sk); =20 /* * Cleanup whatever is sitting in the TCP transmit queue on socket * close. This is done to prevent stale data from being sent should * the network connection be restored before TCP times out. */ - sock_no_linger(queue->sock->sk); + proto->no_linger(queue->sock->sk); =20 if (so_priority > 0) - sock_set_priority(queue->sock->sk, so_priority); + proto->set_priority(queue->sock->sk, so_priority); =20 /* Set socket type of service */ if (nctrl->opts->tos >=3D 0) - ip_sock_set_tos(queue->sock->sk, nctrl->opts->tos); + proto->set_tos(queue->sock->sk, nctrl->opts->tos); =20 /* Set 10 seconds timeout for icresp recvmsg */ queue->sock->sk->sk_rcvtimeo =3D 10 * HZ; @@ -2564,7 +2584,7 @@ static void nvme_tcp_free_ctrl(struct nvme_ctrl *nctr= l) nvmf_free_options(nctrl->opts); free_ctrl: kfree(ctrl->queues); - kfree(ctrl); + kfree_rcu(ctrl, rcu); } =20 static void nvme_tcp_set_sg_null(struct nvme_command *c) @@ -2886,6 +2906,16 @@ nvme_tcp_existing_controller(struct nvmf_ctrl_option= s *opts) return found; } =20 +static const struct nvme_tcp_proto nvme_tcp_proto =3D { + .protocol =3D IPPROTO_TCP, + .set_syncnt =3D tcp_sock_set_syncnt, + .set_nodelay =3D tcp_sock_set_nodelay, + .no_linger =3D sock_no_linger, + .set_priority =3D sock_set_priority, + .set_tos =3D ip_sock_set_tos, + .ops =3D &nvme_tcp_ctrl_ops, +}; + static struct nvme_tcp_ctrl *nvme_tcp_alloc_ctrl(struct device *dev, struct nvmf_ctrl_options *opts) { @@ -2950,13 +2980,20 @@ static struct nvme_tcp_ctrl *nvme_tcp_alloc_ctrl(st= ruct device *dev, goto out_free_ctrl; } =20 + if (!strcmp(ctrl->ctrl.opts->transport, "tcp")) { + rcu_assign_pointer(ctrl->proto, &nvme_tcp_proto); + } else { + ret =3D -EINVAL; + goto out_free_ctrl; + } + ctrl->queues =3D kzalloc_objs(*ctrl->queues, ctrl->ctrl.queue_count); if (!ctrl->queues) { ret =3D -ENOMEM; goto out_free_ctrl; } =20 - ret =3D nvme_init_ctrl(&ctrl->ctrl, dev, &nvme_tcp_ctrl_ops, 0); + ret =3D nvme_init_ctrl(&ctrl->ctrl, dev, ctrl->proto->ops, 0); if (ret) goto out_kfree_queues; =20 --=20 2.51.0 From nobody Wed Apr 1 20:45:07 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DA699408249 for ; Wed, 1 Apr 2026 12:54:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048065; cv=none; b=TTnJja6OhgvQFwQYXFoRsN8fF96kRrIR1adZ2HgeDlFM9msnTBQbDJJeny2QW/WL/gjlUiEf6vpokvPVcCos+KZFQTp+5CtJ5EU5cZ46lBnId4M3+Cl0AhR3oj+bZtDOfZ0Nm813q6vQMRMEdwhkC0+eDeWtDZ9DvuL728spZX0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048065; c=relaxed/simple; bh=AJWqOxlxo2+o2DiQiENh5RMMJiYZ6jjhJX0rPI7pr+4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OHhyaTOQlI+kDD8mjDgNIxwaUeZUQOzqSWmimtO+1lCTFq2Zng0Lq3fCcndOCNtCgOXguL3GWyPjRcFkvxYfmIods1VpgPdEAEhVvyQi3tRDJkgm7evNMD3y6IVLGSsGnAj8k13f7qamht6gyzlhwRPJH+K/OcL1ePZr16di6KA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZLJfgx94; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZLJfgx94" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2D484C116C6; Wed, 1 Apr 2026 12:54:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1775048065; bh=AJWqOxlxo2+o2DiQiENh5RMMJiYZ6jjhJX0rPI7pr+4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZLJfgx94JEfYJuuJDdPHyMeJHMbxtM9tAvyf6f4HC36ZVJmLfSQXuqUPCGRP4/1xW GkkFa+TuvYiu3Il8Nizfyw6BHxab4v+OPUoykcL/WsI9jEYhspkmY40lZkApjQAGiv mtsq1+SpDwNwp7BdrmAIOZTpTGRUB5xlJBqoNLptTS1Zewa4/gbYRwVydL/aemrOO/ GiLNJ7g6VG5XpUgGMKrG9V9pfrWVhMihJyWpRjbmio0y+8LKBR88VStdh43UPZlOWv uAbvndWPVAeqwOu8HqJrT20iXeXYk54o4lp69CpQWe95IFBLGT/lkIM0+5uddl3u4L 5fEtOihpjFSug== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang , Hannes Reinecke , zhenwei pi , Hui Zhu , Gang Yan Subject: [RFC mptcp-next v8 5/7] nvme-tcp: register host mptcp transport Date: Wed, 1 Apr 2026 20:53:43 +0800 Message-ID: <0784d6f12b6f3e056c526a841fe8ad0e4ebb7cfe.1775047736.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.51.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang This patch defines a new nvmf_transport_ops named nvme_mptcp_transport, which is almost the same as nvme_tcp_transport except .type and .allowed_opts. MPTCP currently does not support TLS. The four TLS-related options (NVMF_OPT_TLS, NVMF_OPT_KEYRING, NVMF_OPT_TLS_KEY, and NVMF_OPT_CONCAT) have been removed from allowed_opts. They will be added back once MPTCP TLS is supported. It is registered in nvme_tcp_init_module() and unregistered in nvme_tcp_cleanup_module(). A separate nvme_mptcp_ctrl_ops structure with .name =3D "mptcp" is defined and used for MPTCP controllers. A MODULE_ALIAS("nvme-mptcp") declaration alongside the other module metadata is added at the end of the file. v2: - use 'trtype' instead of '--mptcp' (Hannes) v3: - check mptcp protocol from opts->transport instead of passing a parameter (Hannes). v4: - check CONFIG_MPTCP. Cc: Hannes Reinecke Co-developed-by: zhenwei pi Signed-off-by: zhenwei pi Co-developed-by: Hui Zhu Signed-off-by: Hui Zhu Co-developed-by: Gang Yan Signed-off-by: Gang Yan Signed-off-by: Geliang Tang --- drivers/nvme/host/tcp.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 30e4d915011e..30ff6e03b32f 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -3060,6 +3060,20 @@ static struct nvmf_transport_ops nvme_tcp_transport = =3D { .create_ctrl =3D nvme_tcp_create_ctrl, }; =20 +#ifdef CONFIG_MPTCP +static struct nvmf_transport_ops nvme_mptcp_transport =3D { + .name =3D "mptcp", + .module =3D THIS_MODULE, + .required_opts =3D NVMF_OPT_TRADDR, + .allowed_opts =3D NVMF_OPT_TRSVCID | NVMF_OPT_RECONNECT_DELAY | + NVMF_OPT_HOST_TRADDR | NVMF_OPT_CTRL_LOSS_TMO | + NVMF_OPT_HDR_DIGEST | NVMF_OPT_DATA_DIGEST | + NVMF_OPT_NR_WRITE_QUEUES | NVMF_OPT_NR_POLL_QUEUES | + NVMF_OPT_TOS | NVMF_OPT_HOST_IFACE, + .create_ctrl =3D nvme_tcp_create_ctrl, +}; +#endif + static int __init nvme_tcp_init_module(void) { unsigned int wq_flags =3D WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_SYSFS; @@ -3085,6 +3099,9 @@ static int __init nvme_tcp_init_module(void) atomic_set(&nvme_tcp_cpu_queues[cpu], 0); =20 nvmf_register_transport(&nvme_tcp_transport); +#ifdef CONFIG_MPTCP + nvmf_register_transport(&nvme_mptcp_transport); +#endif return 0; } =20 @@ -3092,6 +3109,9 @@ static void __exit nvme_tcp_cleanup_module(void) { struct nvme_tcp_ctrl *ctrl; =20 +#ifdef CONFIG_MPTCP + nvmf_unregister_transport(&nvme_mptcp_transport); +#endif nvmf_unregister_transport(&nvme_tcp_transport); =20 mutex_lock(&nvme_tcp_ctrl_mutex); @@ -3108,3 +3128,4 @@ module_exit(nvme_tcp_cleanup_module); =20 MODULE_DESCRIPTION("NVMe host TCP transport driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("nvme-mptcp"); --=20 2.51.0 From nobody Wed Apr 1 20:45:07 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 33CE6406297 for ; Wed, 1 Apr 2026 12:54:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048068; cv=none; b=Na2wlIv2LT3CI9pMycAWz20m06P4T68HcimPTfwc76f5Ek9I7t/Jydv20A9cxH9jslD75AxkMemrxJf/PQKWOCKbWsA4X9vgrRySUZkaU00JkWTSmqsjPsPcgh4yPWZP96mWU+pBKZet87a51ReEtvTR3bYJuXH/80UKcvnO0jg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048068; c=relaxed/simple; bh=CvrKBWIacTzuM4sVKLfPAXsBK2tmuH3oC6bzXlhtyHI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=T4P7JpELFEfjAmz/0soghYWXP3ZKZmglqVnBsaT9QXh/OPELhMreEqcN+X+CKPL0k5vIqm9k873GOFX8lQ6cRLIsi9dDwh6Jf9fW3ndjUWql7zk10BkZ1ujWCmH2agxlZnETbkEN0VPLBNJ1Jj7499fBPvnSlQSW5IRVXUm2Kvs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kyM1zUgO; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kyM1zUgO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0E7E5C116C6; Wed, 1 Apr 2026 12:54:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1775048067; bh=CvrKBWIacTzuM4sVKLfPAXsBK2tmuH3oC6bzXlhtyHI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kyM1zUgOhumAZOIT29qb28NNocbWe+6LG7lp9P/GGHadu83zsa/6epOTGaGnJY+Y6 unST+yiyKTN6RHW/UxgdK/IeXCWMw2zvbvyG3gHXIYBMMvlC0mr6Yc3jEAmI72S2ak /dug78ruq5ZHFs1QdvDtk4OYiJvmHLi5trm9JMf2rlQwRSsSBGGo7Gggocoigi6APB leUJpkgsWpwQstcc81XRsu5j8nBgtxGPFGW6IZCRBfAH4X+2bMRRHB0/+N3HScbdcu LzamKTouFq+1C401eLTaliBwU7QFbpIuj7nc1epJwpV9XU3UoxRWqADUoXt5z2TpkM rBKIbBF4Wh+Vw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang , Hannes Reinecke , zhenwei pi , Hui Zhu , Gang Yan Subject: [RFC mptcp-next v8 6/7] nvme-tcp: implement host mptcp proto Date: Wed, 1 Apr 2026 20:53:44 +0800 Message-ID: <809b0993a41df56f3d6627e6ebddd8b158551faa.1775047736.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.51.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang An MPTCP-specific version of struct nvme_tcp_proto is implemented, and it is assigned to ctrl->proto when the transport string is "mptcp". The socket option setting logic is similar to the target side, except that mptcp_sock_set_syncnt is newly defined for the host side. It sets the value on the first subflow socket of an MPTCP connection. The value is then synchronized to other newly created subflows in sync_socket_options(). A separate nvme_mptcp_ctrl_ops structure with .name =3D "mptcp" is defined and used for MPTCP controllers. Cc: Hannes Reinecke Co-developed-by: zhenwei pi Signed-off-by: zhenwei pi Co-developed-by: Hui Zhu Signed-off-by: Hui Zhu Co-developed-by: Gang Yan Signed-off-by: Gang Yan Signed-off-by: Geliang Tang --- drivers/nvme/host/tcp.c | 34 ++++++++++++++++++++++++++++++++++ include/net/mptcp.h | 7 +++++++ net/mptcp/protocol.h | 1 + net/mptcp/sockopt.c | 25 +++++++++++++++++++++++++ 4 files changed, 67 insertions(+) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 30ff6e03b32f..54d27acdd4b5 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -2889,6 +2889,24 @@ static const struct nvme_ctrl_ops nvme_tcp_ctrl_ops = =3D { .get_virt_boundary =3D nvmf_get_virt_boundary, }; =20 +#ifdef CONFIG_MPTCP +static const struct nvme_ctrl_ops nvme_mptcp_ctrl_ops =3D { + .name =3D "mptcp", + .module =3D THIS_MODULE, + .flags =3D NVME_F_FABRICS | NVME_F_BLOCKING, + .reg_read32 =3D nvmf_reg_read32, + .reg_read64 =3D nvmf_reg_read64, + .reg_write32 =3D nvmf_reg_write32, + .subsystem_reset =3D nvmf_subsystem_reset, + .free_ctrl =3D nvme_tcp_free_ctrl, + .submit_async_event =3D nvme_tcp_submit_async_event, + .delete_ctrl =3D nvme_tcp_delete_ctrl, + .get_address =3D nvme_tcp_get_address, + .stop_ctrl =3D nvme_tcp_stop_ctrl, + .get_virt_boundary =3D nvmf_get_virt_boundary, +}; +#endif + static bool nvme_tcp_existing_controller(struct nvmf_ctrl_options *opts) { @@ -2916,6 +2934,18 @@ static const struct nvme_tcp_proto nvme_tcp_proto = =3D { .ops =3D &nvme_tcp_ctrl_ops, }; =20 +#ifdef CONFIG_MPTCP +static const struct nvme_tcp_proto nvme_mptcp_proto =3D { + .protocol =3D IPPROTO_MPTCP, + .set_syncnt =3D mptcp_sock_set_syncnt, + .set_nodelay =3D mptcp_sock_set_nodelay, + .no_linger =3D mptcp_sock_no_linger, + .set_priority =3D mptcp_sock_set_priority, + .set_tos =3D mptcp_sock_set_tos, + .ops =3D &nvme_mptcp_ctrl_ops, +}; +#endif + static struct nvme_tcp_ctrl *nvme_tcp_alloc_ctrl(struct device *dev, struct nvmf_ctrl_options *opts) { @@ -2982,6 +3012,10 @@ static struct nvme_tcp_ctrl *nvme_tcp_alloc_ctrl(str= uct device *dev, =20 if (!strcmp(ctrl->ctrl.opts->transport, "tcp")) { rcu_assign_pointer(ctrl->proto, &nvme_tcp_proto); +#ifdef CONFIG_MPTCP + } else if (!strcmp(ctrl->ctrl.opts->transport, "mptcp")) { + rcu_assign_pointer(ctrl->proto, &nvme_mptcp_proto); +#endif } else { ret =3D -EINVAL; goto out_free_ctrl; diff --git a/include/net/mptcp.h b/include/net/mptcp.h index 91ce7b9b639d..49031a111e69 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -247,6 +247,8 @@ void mptcp_sock_set_priority(struct sock *sk, u32 prior= ity); void mptcp_sock_no_linger(struct sock *sk); =20 void mptcp_sock_set_tos(struct sock *sk, int val); + +int mptcp_sock_set_syncnt(struct sock *sk, int val); #else =20 static inline void mptcp_init(void) @@ -343,6 +345,11 @@ static inline void mptcp_sock_set_priority(struct sock= *sk, u32 priority) { } static inline void mptcp_sock_no_linger(struct sock *sk) { } =20 static inline void mptcp_sock_set_tos(struct sock *sk, int val) { } + +static inline int mptcp_sock_set_syncnt(struct sock *sk, int val) +{ + return 0; +} #endif /* CONFIG_MPTCP */ =20 #if IS_ENABLED(CONFIG_MPTCP_IPV6) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index f5d4d7d030f2..84e80816b2a4 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -335,6 +335,7 @@ struct mptcp_sock { int keepalive_idle; int keepalive_intvl; int maxseg; + int icsk_syn_retries; struct work_struct work; struct sk_buff *ooo_last_skb; struct rb_root out_of_order_queue; diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index 0f18398932a0..814cebc9125f 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -1592,6 +1592,7 @@ static void sync_socket_options(struct mptcp_sock *ms= k, struct sock *ssk) priority =3D READ_ONCE(sk->sk_priority); if (priority > 0) sock_set_priority(ssk, priority); + tcp_sock_set_syncnt(ssk, msk->icsk_syn_retries); } =20 void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk) @@ -1743,3 +1744,27 @@ void mptcp_sock_set_tos(struct sock *sk, int val) release_sock(sk); } EXPORT_SYMBOL(mptcp_sock_set_tos); + +int mptcp_sock_set_syncnt(struct sock *sk, int val) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct sock *ssk; + int ret =3D 0; + + if (val < 1 || val > MAX_TCP_SYNCNT) + return -EINVAL; + + lock_sock(sk); + sockopt_seq_inc(msk); + msk->icsk_syn_retries =3D val; + ssk =3D __mptcp_nmpc_sk(msk); + if (IS_ERR(ssk)) { + ret =3D PTR_ERR(ssk); + goto unlock; + } + tcp_sock_set_syncnt(ssk, val); +unlock: + release_sock(sk); + return ret; +} +EXPORT_SYMBOL(mptcp_sock_set_syncnt); --=20 2.51.0 From nobody Wed Apr 1 20:45:07 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 90E083C457D for ; Wed, 1 Apr 2026 12:54:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048071; cv=none; b=lD/RJ5HC4NS23x16hDSIXCbQYFVkTcOzpz09xPjgXrKR0iqCDGONrNGCV2AhBbECcRvwl5vVUmbHbIkk/ZWzQ4JllPKyDuWhuk0REORxoUBNMiOxqOeK7JhvdmERJ33AQjqtkX4mrnqGDWt9vDiBl8GXAo6kVfUBWsLrApHtlHU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775048071; c=relaxed/simple; bh=SSwrmnxlgId8ZBAiDfe9i9qiHSefb/jOBMjHtpkcMQA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qwFBuGm6SBUDd3C7EP20HHNF3ufywD87cQ/iAZAXsv96gyt5DscUgd7+yIeyKnq5B/ZIVrFdgNm7OQ2GvUzjM071f2yuYE3/SoMRxR1lit4q6E9Rx3iK2vJHf06V1pOOnxhlxwiPbFdwxshtb9TQe59vEPZdqsNv9Y8+Qp74wCI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JIAdI73w; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JIAdI73w" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7C1A3C116C6; Wed, 1 Apr 2026 12:54:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1775048071; bh=SSwrmnxlgId8ZBAiDfe9i9qiHSefb/jOBMjHtpkcMQA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JIAdI73w9vBkmQpOVBp7sF5jwqKphTJ1FKEgBmXktURxbmKqabfEoYLLoi3W6idpB lCna7cy/TKMZ7erYblm4AV0JIz2cBu/BDd2ZRc7j9YxifDaaXkHImSA/PadW9FKYTV h0/ewS3wahBZUUpLP2qllDfriLIKm4FMKkrLPPqIWOsf2MuHorCRFmq9+/qxxIqlEI 0gK80qphc7jK6faE/AByQpEi7xN8kktXCHg/y1FDWT2ERgic1HC7vq6/b08rvo8d4p AyLRu3qigLBDTNEAQpJyQzItRUdtpziW03zD84uCzNu8LW0Hbg12pCTAG9/uBOTaTs JXT0fMgTPcd3Q== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang , Hannes Reinecke , Nilay Shroff , Ming Lei , zhenwei pi , Hui Zhu , Gang Yan Subject: [RFC mptcp-next v8 7/7] selftests: mptcp: add NVMe over MPTCP test Date: Wed, 1 Apr 2026 20:53:45 +0800 Message-ID: X-Mailer: git-send-email 2.51.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang A test case for NVMe over MPTCP has been implemented. It verifies the proper functionality of nvme list, discover, connect, and disconnect commands. Additionally, read/write performance has been evaluated using fio. This test simulates four NICs on both target and host sides, each limited to 100MB/s. It shows that 'NVMe over MPTCP' delivered bandwidth up to four times that of standard TCP: # ./mptcp_nvme.sh tcp READ: bw=3D112MiB/s (118MB/s), 112MiB/s-112MiB/s (118MB/s-118MB/s), io=3D1123MiB (1177MB), run=3D10018-10018msec WRITE: bw=3D112MiB/s (117MB/s), 112MiB/s-112MiB/s (117MB/s-117MB/s), io=3D1118MiB (1173MB), run=3D10018-10018msec # ./mptcp_nvme.sh mptcp READ: bw=3D427MiB/s (448MB/s), 427MiB/s-427MiB/s (448MB/s-448MB/s), io=3D4286MiB (4494MB), run=3D10039-10039msec WRITE: bw=3D387MiB/s (406MB/s), 387MiB/s-387MiB/s (406MB/s-406MB/s), io=3D3885MiB (4073MB), run=3D10043-10043msec Also add NVMe iopolicy testing to mptcp_nvme.sh, with the default set to "numa". It can be set to "round-robin" or "queue-depth". # ./mptcp_nvme.sh mptcp round-robin Cc: Hannes Reinecke Cc: Nilay Shroff Cc: Ming Lei Co-developed-by: zhenwei pi Signed-off-by: zhenwei pi Co-developed-by: Hui Zhu Signed-off-by: Hui Zhu Co-developed-by: Gang Yan Signed-off-by: Gang Yan Signed-off-by: Geliang Tang --- tools/testing/selftests/net/mptcp/Makefile | 1 + tools/testing/selftests/net/mptcp/config | 7 + .../testing/selftests/net/mptcp/mptcp_lib.sh | 12 + .../testing/selftests/net/mptcp/mptcp_nvme.sh | 240 ++++++++++++++++++ 4 files changed, 260 insertions(+) create mode 100755 tools/testing/selftests/net/mptcp/mptcp_nvme.sh diff --git a/tools/testing/selftests/net/mptcp/Makefile b/tools/testing/sel= ftests/net/mptcp/Makefile index 22ba0da2adb8..7b308447a58b 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_nvme.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 59051ee2a986..0eee348eff8b 100644 --- a/tools/testing/selftests/net/mptcp/config +++ b/tools/testing/selftests/net/mptcp/config @@ -34,3 +34,10 @@ CONFIG_NFT_SOCKET=3Dm CONFIG_NFT_TPROXY=3Dm CONFIG_SYN_COOKIES=3Dy CONFIG_VETH=3Dy +CONFIG_CONFIGFS_FS=3Dy +CONFIG_NVME_CORE=3Dy +CONFIG_NVME_FABRICS=3Dy +CONFIG_NVME_TCP=3Dy +CONFIG_NVME_TARGET=3Dy +CONFIG_NVME_TARGET_TCP=3Dy +CONFIG_NVME_MULTIPATH=3Dy diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing= /selftests/net/mptcp/mptcp_lib.sh index 5fea7e7df628..62e01afc50ed 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh @@ -526,6 +526,18 @@ mptcp_lib_check_tools() { exit ${KSFT_SKIP} fi ;; + "nvme") + if ! nvme --version &> /dev/null; then + mptcp_lib_pr_skip "Could not run test without nvme tool" + exit ${KSFT_SKIP} + fi + ;; + "fio") + if ! fio -h &> /dev/null; then + mptcp_lib_pr_skip "Could not run test without fio tool" + 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_nvme.sh b/tools/testin= g/selftests/net/mptcp/mptcp_nvme.sh new file mode 100755 index 000000000000..101536b66b9d --- /dev/null +++ b/tools/testing/selftests/net/mptcp/mptcp_nvme.sh @@ -0,0 +1,240 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(dirname "$0")/mptcp_lib.sh" + +ret=3D0 +trtype=3D"${1:-mptcp}" +iopolicy=3D${2:-"numa"} # round-robin, queue-depth +nqn=3D"nqn.2014-08.org.nvmexpress.${trtype}dev.$$.${RANDOM}" +ns=3D1 +port=3D$((RANDOM % 10000 + 20000)) +trsvcid=3D$((RANDOM % 64512 + 1024)) +ns1=3D"" +ns2=3D"" +temp_file=3D$(mktemp /tmp/test.XXXXXX.raw) +loop_dev=3D"" + +ns1_cleanup() +{ + mount -t configfs none /sys/kernel/config + + pushd /sys/kernel/config/nvmet || exit 1 + rm -rf ports/"${port}"/subsystems/"${trtype}"subsys + rmdir ports/"${port}" + echo 0 > subsystems/"${nqn}"/namespaces/"${ns}"/enable + echo -n 0 > subsystems/"${nqn}"/namespaces/"${ns}"/device_path + rmdir subsystems/"${nqn}"/namespaces/"${ns}" + rmdir subsystems/"${nqn}" + popd || exit 1 +} + +ns2_cleanup() +{ + nvme disconnect -n "${nqn}" || true +} + +cleanup() +{ + ip netns exec "$ns2" bash <<- EOF + $(declare -f ns2_cleanup) + ns2_cleanup + EOF + + sleep 1 + + ip netns exec "$ns1" bash <<- EOF + $(declare -f ns1_cleanup) + ns1_cleanup + EOF + + if [ -n "${loop_dev}" ] && [ -b "${loop_dev}" ]; then + losetup -d "${loop_dev}" 2>/dev/null || true + fi + rm -rf "${temp_file}" + + mptcp_lib_ns_exit "$ns1" "$ns2" + + kill "$monitor_pid_ns1" 2>/dev/null + wait "$monitor_pid_ns1" 2>/dev/null + + kill "$monitor_pid_ns2" 2>/dev/null + wait "$monitor_pid_ns2" 2>/dev/null + + unset -v trtype nqn ns port trsvcid +} + +init() +{ + mptcp_lib_ns_init ns1 ns2 + + # 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" addr add dead:beef:"$i"::1/64 \ + dev ns1eth"$i" nodad + ip -net "$ns1" link set ns1eth"$i" up + ip -net "$ns2" addr add 10.1."$i".2/24 dev ns2eth"$i" + ip -net "$ns2" addr add dead:beef:"$i"::2/64 \ + dev ns2eth"$i" nodad + 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" + ip -net "$ns2" route add default via dead:beef:"$i"::1 \ + dev ns2eth"$i" metric 10"$i" + + # Add tc qdisc to both namespaces for bandwidth limiting + 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.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.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 + + ip -n "${ns1}" mptcp monitor & + monitor_pid_ns1=3D$! + ip -n "${ns2}" mptcp monitor & + monitor_pid_ns2=3D$! +} + +run_target() +{ + mount -t configfs none /sys/kernel/config + + cd /sys/kernel/config/nvmet/subsystems || exit + mkdir -p "${nqn}" + cd "${nqn}" || exit + echo 1 > attr_allow_any_host + mkdir -p namespaces/"${ns}" + echo "${loop_dev}" > namespaces/"${ns}"/device_path + echo 1 > namespaces/"${ns}"/enable + + cd /sys/kernel/config/nvmet/ports || exit + mkdir -p "${port}" + cd "${port}" || exit + echo "${trtype}" > addr_trtype + echo ipv4 > addr_adrfam + echo 0.0.0.0 > addr_traddr + echo "${trsvcid}" > addr_trsvcid + + cd subsystems || exit + ln -sf ../../../subsystems/"${nqn}" "${trtype}"subsys +} + +run_host() +{ + local traddr=3D10.1.1.1 + local output + local devname + local subname + + echo "nvme discover -a ${traddr}" + nvme discover -t "${trtype}" -a "${traddr}" -s "${trsvcid}" + if [ $? -ne 0 ]; then + return 1 + fi + + echo "nvme connect" + output=3D$(nvme connect -t "${trtype}" -a "${traddr}" \ + -s "${trsvcid}" -n "${nqn}" 2>&1) + if [ $? -ne 0 ]; then + echo "nvme connect failed: $output" >&2 + return 1 + fi + + devname=3D$(echo "$output" | awk '{print $NF}') + if [ -z "$devname" ]; then + echo "Failed to parse device name from output: $output" >&2 + return 1 + fi + + sleep 1 + + echo "nvme list" + nvme list + + subname=3D$(nvme list-subsys /dev/"${devname}"n1 | + grep -o 'nvme-subsys[0-9]*' | head -1) + + echo "${iopolicy}" > /sys/class/nvme-subsystem/"${subname}"/iopolicy + cat /sys/class/nvme-subsystem/"${subname}"/iopolicy + + echo "fio randread /dev/${devname}n1" + fio --name=3Dglobal --direct=3D1 --norandommap --randrepeat=3D0 \ + --ioengine=3Dlibaio --thread=3D1 --blocksize=3D4k --runtime=3D10 \ + --time_based --rw=3Drandread --numjobs=3D4 --iodepth=3D256 \ + --group_reporting --size=3D100% --name=3Dlibaio_4_256_4k_randread \ + --filename=3D/dev/"${devname}"n1 + if [ $? -ne 0 ]; then + return 1 + fi + + sleep 1 + + echo "fio randwrite /dev/${devname}n1" + fio --name=3Dglobal --direct=3D1 --norandommap --randrepeat=3D0 \ + --ioengine=3Dlibaio --thread=3D1 --blocksize=3D4k --runtime=3D10 \ + --time_based --rw=3Drandwrite --numjobs=3D4 --iodepth=3D256 \ + --group_reporting --size=3D100% --name=3Dlibaio_4_256_4k_randwrite \ + --filename=3D/dev/"${devname}"n1 + if [ $? -ne 0 ]; then + return 1 + fi + + nvme flush /dev/"${devname}"n1 +} + +mptcp_lib_check_tools nvme fio + +init +trap cleanup EXIT + +dd if=3D/dev/zero of=3D"${temp_file}" bs=3D1M count=3D0 seek=3D512 +loop_dev=3D$(losetup -f --show "${temp_file}") + +run_test() +{ + export trtype nqn ns port trsvcid + export loop_dev temp_file + export iopolicy + + if ! ip netns exec "$ns1" bash <<- EOF + $(declare -f run_target) + run_target + exit \$? + EOF + then + ret=3D"${KSFT_FAIL}" + fi + + if ! ip netns exec "$ns2" bash <<- EOF + $(declare -f run_host) + run_host + exit \$? + EOF + then + ret=3D"${KSFT_FAIL}" + fi + + sleep 1 +} + +run_test "$@" + +mptcp_lib_result_print_all_tap +exit "$ret" --=20 2.51.0