[PATCH v2] nvme-tcp: Print actual source IP address in address attribute

Sagi Grimberg sagi at grimberg.me
Thu Sep 1 04:03:21 PDT 2022



On 8/31/22 22:38, Martin Belanger wrote:
> From: Martin Belanger <martin.belanger at dell.com>
> 
> TCP transport relies on the routing table to determine which
> source address and interface to use when making a connection.
> Currently, there is no way to tell from userspace where a
> connection was made. This patch allows exposing the actual source
> address using the host_traddr field of the address attribute.
> 
> This is needed to diagnose and identify connectivity issues since it will
> allow us to tell which interface and source address is associated with each
> connection.
> 
> Signed-off-by: Martin Belanger <martin.belanger at dell.com>
> ---
>   drivers/nvme/host/tcp.c | 34 +++++++++++++++++++++++++++++++++-
>   1 file changed, 33 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
> index 044da18c06f5..adbb76483a74 100644
> --- a/drivers/nvme/host/tcp.c
> +++ b/drivers/nvme/host/tcp.c
> @@ -165,6 +165,7 @@ struct nvme_tcp_ctrl {
>   	struct blk_mq_tag_set	admin_tag_set;
>   	struct sockaddr_storage addr;
>   	struct sockaddr_storage src_addr;
> +	struct sockaddr_storage sock_addr;
>   	struct nvme_ctrl	ctrl;
>   
>   	struct work_struct	err_work;
> @@ -1597,6 +1598,12 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
>   		goto err_rcv_pdu;
>   	}
>   
> +	/* Retrieve the actual source address from the socket */
> +	ret = kernel_getsockname(queue->sock,
> +		(struct sockaddr *)&ctrl->sock_addr);
> +	if (ret < 0)
> +		memset(&ctrl->sock_addr, 0, sizeof(ctrl->sock_addr));
> +

For every queue?

>   	ret = nvme_tcp_init_connection(queue);
>   	if (ret)
>   		goto err_init_connect;
> @@ -2532,6 +2539,31 @@ static int nvme_tcp_poll(struct blk_mq_hw_ctx *hctx, struct io_comp_batch *iob)
>   	return queue->nr_cqe;
>   }
>   
> +static int nvme_tcp_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
> +{
> +	int len = 0;
> +	struct sockaddr_storage *sa = &to_tcp_ctrl(ctrl)->sock_addr;

You can just retrieve the sock_addr from the admin queue here locally. I
don't think we need a struct member for it.

> +
> +	if (ctrl->opts->mask & NVMF_OPT_TRADDR)
> +		len += scnprintf(buf, size, "traddr=%s", ctrl->opts->traddr);
> +	if (ctrl->opts->mask & NVMF_OPT_TRSVCID)
> +		len += scnprintf(buf + len, size - len, "%strsvcid=%s",
> +				(len) ? "," : "", ctrl->opts->trsvcid);
> +	if ((sa->ss_family == AF_INET) || (sa->ss_family == AF_INET6)) {
> +		len += scnprintf(buf + len, size - len, "%shost_traddr=%pISc",
> +				(len) ? "," : "", sa);

It is confusing to expose that if it was not specified, that is creating
a different behavior from the existing behavior and from other
transports.

> +	} else if (ctrl->opts->mask & NVMF_OPT_HOST_TRADDR) {
> +		len += scnprintf(buf + len, size - len, "%shost_traddr=%s",
> +				(len) ? "," : "", ctrl->opts->host_traddr);
> +	}
> +	if (ctrl->opts->mask & NVMF_OPT_HOST_IFACE)
> +		len += scnprintf(buf + len, size - len, "%shost_iface=%s",
> +				(len) ? "," : "", ctrl->opts->host_iface);
> +	len += scnprintf(buf + len, size - len, "\n");
> +
> +	return len;
> +}
> +
>   static const struct blk_mq_ops nvme_tcp_mq_ops = {
>   	.queue_rq	= nvme_tcp_queue_rq,
>   	.commit_rqs	= nvme_tcp_commit_rqs,
> @@ -2563,7 +2595,7 @@ static const struct nvme_ctrl_ops nvme_tcp_ctrl_ops = {
>   	.free_ctrl		= nvme_tcp_free_ctrl,
>   	.submit_async_event	= nvme_tcp_submit_async_event,
>   	.delete_ctrl		= nvme_tcp_delete_ctrl,
> -	.get_address		= nvmf_get_address,
> +	.get_address		= nvme_tcp_get_address,
>   	.stop_ctrl		= nvme_tcp_stop_ctrl,
>   };
>   



More information about the Linux-nvme mailing list