From: Geliang Tang <tanggeliang@kylinos.cn>
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_sockops structure, which contains the
protocol of the socket and a set of function pointers for these socket
operations. A "sockops" field is also added to struct nvmet_tcp_port.
A TCP-specific version of struct nvmet_tcp_sockops is defined. In
nvmet_tcp_add_port(), port->sockops is set to nvmet_tcp_sockops 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_sockops structure.
Cc: Hannes Reinecke <hare@suse.de>
Co-developed-by: zhenwei pi <zhenwei.pi@linux.dev>
Signed-off-by: zhenwei pi <zhenwei.pi@linux.dev>
Co-developed-by: Hui Zhu <zhuhui@kylinos.cn>
Signed-off-by: Hui Zhu <zhuhui@kylinos.cn>
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
drivers/nvme/target/tcp.c | 43 ++++++++++++++++++++++++++++++++-------
1 file changed, 36 insertions(+), 7 deletions(-)
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index acc71a26733f..dc1207d96b30 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -198,12 +198,22 @@ struct nvmet_tcp_queue {
void (*write_space)(struct sock *);
};
+struct nvmet_tcp_sockops {
+ int proto;
+ 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);
+};
+
struct nvmet_tcp_port {
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_sockops *sockops;
};
static DEFINE_IDA(nvmet_tcp_queue_ida);
@@ -1698,19 +1708,22 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
if (ret < 0)
return ret;
+ if (!queue->port || !queue->port->sockops)
+ return -EINVAL;
+
/*
* 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);
+ queue->port->sockops->no_linger(sock->sk);
if (so_priority > 0)
- sock_set_priority(sock->sk, so_priority);
+ queue->port->sockops->set_priority(sock->sk, so_priority);
/* Set socket type of service */
if (inet->rcv_tos > 0)
- ip_sock_set_tos(sock->sk, inet->rcv_tos);
+ queue->port->sockops->set_tos(sock->sk, inet->rcv_tos);
ret = 0;
write_lock_bh(&sock->sk->sk_callback_lock);
@@ -2030,6 +2043,15 @@ static void nvmet_tcp_listen_data_ready(struct sock *sk)
read_unlock_bh(&sk->sk_callback_lock);
}
+static const struct nvmet_tcp_sockops nvmet_tcp_sockops = {
+ .proto = IPPROTO_TCP,
+ .set_reuseaddr = sock_set_reuseaddr,
+ .set_nodelay = tcp_sock_set_nodelay,
+ .set_priority = sock_set_priority,
+ .no_linger = sock_no_linger,
+ .set_tos = ip_sock_set_tos,
+};
+
static int nvmet_tcp_add_port(struct nvmet_port *nport)
{
struct nvmet_tcp_port *port;
@@ -2054,6 +2076,13 @@ static int nvmet_tcp_add_port(struct nvmet_port *nport)
goto err_port;
}
+ if (nport->disc_addr.trtype == NVMF_TRTYPE_TCP) {
+ port->sockops = &nvmet_tcp_sockops;
+ } else {
+ ret = -EINVAL;
+ goto err_port;
+ }
+
ret = inet_pton_with_scope(&init_net, af, nport->disc_addr.traddr,
nport->disc_addr.trsvcid, &port->addr);
if (ret) {
@@ -2068,7 +2097,7 @@ static int nvmet_tcp_add_port(struct nvmet_port *nport)
port->nport->inline_data_size = NVMET_TCP_DEF_INLINE_DATA_SIZE;
ret = sock_create(port->addr.ss_family, SOCK_STREAM,
- IPPROTO_TCP, &port->sock);
+ port->sockops->proto, &port->sock);
if (ret) {
pr_err("failed to create a socket\n");
goto err_port;
@@ -2077,10 +2106,10 @@ static int nvmet_tcp_add_port(struct nvmet_port *nport)
port->sock->sk->sk_user_data = port;
port->data_ready = port->sock->sk->sk_data_ready;
port->sock->sk->sk_data_ready = nvmet_tcp_listen_data_ready;
- sock_set_reuseaddr(port->sock->sk);
- tcp_sock_set_nodelay(port->sock->sk);
+ port->sockops->set_reuseaddr(port->sock->sk);
+ port->sockops->set_nodelay(port->sock->sk);
if (so_priority > 0)
- sock_set_priority(port->sock->sk, so_priority);
+ port->sockops->set_priority(port->sock->sk, so_priority);
ret = kernel_bind(port->sock, (struct sockaddr_unsized *)&port->addr,
sizeof(port->addr));
--
2.51.0