[PATCH 16/16] nvmet-tcp: control messages for recvmsg()

Hannes Reinecke hare at suse.de
Wed Aug 9 04:35:29 PDT 2023


On 8/9/23 13:30, Sagi Grimberg wrote:
> 
> 
> On 8/8/23 19:53, Hannes Reinecke wrote:
>> kTLS requires control messages for recvmsg() to relay any out-of-band
>> TLS messages (eg TLS alerts) to the caller.
>>
>> Signed-off-by: Hannes Reinecke <hare at suse.de>
>> ---
>>   drivers/nvme/target/tcp.c | 83 +++++++++++++++++++++++++++++++++------
>>   1 file changed, 72 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
>> index 75e4cb4c2f29..e1aea52e58da 100644
>> --- a/drivers/nvme/target/tcp.c
>> +++ b/drivers/nvme/target/tcp.c
>> @@ -14,6 +14,7 @@
>>   #include <net/sock.h>
>>   #include <net/tcp.h>
>>   #include <net/tls.h>
>> +#include <net/tls_prot.h>
>>   #include <net/handshake.h>
>>   #include <linux/inet.h>
>>   #include <linux/llist.h>
>> @@ -70,6 +71,9 @@ device_param_cb(idle_poll_period_usecs, &set_param_ops,
>>   MODULE_PARM_DESC(idle_poll_period_usecs,
>>           "nvmet tcp io_work poll till idle time period in usecs: 
>> Default 0");
>> +#define nvmet_queue_is_tls(queue) \
>> +    ((queue)->port->nport->disc_addr.tsas.tcp.sectype == 
>> NVMF_TCP_SECTYPE_TLS13)
> 
> That is some steep dereferencing... I'd say just cache a flag
> in the queue itself, or in the port.
> 
Yeah, not happy with that one, either.
Will be adding a queue flag.

>> +
>>   #ifdef CONFIG_NVME_TARGET_TCP_TLS
>>   /*
>>    * TLS handshake timeout
>> @@ -118,6 +122,7 @@ struct nvmet_tcp_cmd {
>>       u32                pdu_len;
>>       u32                pdu_recv;
>>       int                sg_idx;
>> +    char                recv_cbuf[CMSG_LEN(sizeof(char))];
>>       struct msghdr            recv_msg;
>>       struct bio_vec            *iov;
>>       u32                flags;
>> @@ -1116,20 +1121,59 @@ static inline bool nvmet_tcp_pdu_valid(u8 type)
>>       return false;
>>   }
>> +static int nvmet_tcp_tls_record_ok(struct nvmet_tcp_queue *queue,
>> +        struct msghdr *msg, char *cbuf)
>> +{
>> +    struct cmsghdr *cmsg = (struct cmsghdr *)cbuf;
>> +    u8 ctype, level, description;
>> +    int ret = 0;
>> +
>> +    if (!nvmet_queue_is_tls(queue))
>> +        return 0;
>> +
>> +    ctype = tls_get_record_type(queue->sock->sk, cmsg);
>> +    switch (ctype) {
>> +    case 0:
>> +        break;
>> +    case TLS_RECORD_TYPE_DATA:
>> +        break;
>> +    case TLS_RECORD_TYPE_ALERT:
>> +        tls_alert_recv(queue->sock->sk, msg, &level, &description);
>> +        pr_err("TLS Alert level %u desc %u\n", level, description);
>> +        ret = (level == TLS_ALERT_LEVEL_FATAL) ?
>> +            -ENOTCONN : -EAGAIN;
>> +        break;
>> +    default:
>> +        /* discard this record type */
>> +        pr_err("TLS record %d unhandled\n", ctype);
>> +        ret = -EAGAIN;
>> +        break;
>> +    }
>> +    return ret;
>> +}
>> +
>>   static int nvmet_tcp_try_recv_pdu(struct nvmet_tcp_queue *queue)
>>   {
>>       struct nvme_tcp_hdr *hdr = &queue->pdu.cmd.hdr;
>> -    int len;
>> +    int len, ret;
>>       struct kvec iov;
>> +    char cbuf[CMSG_LEN(sizeof(char))] = {};
>>       struct msghdr msg = { .msg_flags = MSG_DONTWAIT };
>>   recv:
>>       iov.iov_base = (void *)&queue->pdu + queue->offset;
>>       iov.iov_len = queue->left;
>> +    if (nvmet_queue_is_tls(queue)) {
>> +        msg.msg_control = cbuf;
>> +        msg.msg_controllen = sizeof(cbuf);
>> +    }
>>       len = kernel_recvmsg(queue->sock, &msg, &iov, 1,
>>               iov.iov_len, msg.msg_flags);
>>       if (unlikely(len < 0))
>>           return len;
>> +    ret = nvmet_tcp_tls_record_ok(queue, &msg, cbuf);
>> +    if (ret < 0)
>> +        return ret;
>>       queue->offset += len;
>>       queue->left -= len;
>> @@ -1182,16 +1226,21 @@ static void nvmet_tcp_prep_recv_ddgst(struct 
>> nvmet_tcp_cmd *cmd)
>>   static int nvmet_tcp_try_recv_data(struct nvmet_tcp_queue *queue)
>>   {
>>       struct nvmet_tcp_cmd  *cmd = queue->cmd;
>> -    int ret;
>> +    int len, ret;
>>       while (msg_data_left(&cmd->recv_msg)) {
>> -        ret = sock_recvmsg(cmd->queue->sock, &cmd->recv_msg,
>> +        len = sock_recvmsg(cmd->queue->sock, &cmd->recv_msg,
>>               cmd->recv_msg.msg_flags);
>> -        if (ret <= 0)
>> +        if (len <= 0)
>> +            return len;
>> +        ret = nvmet_tcp_tls_record_ok(cmd->queue,
>> +                          &cmd->recv_msg,
>> +                          cmd->recv_cbuf);
> 
> I think it will be better to condition on tls on the
> call sites, so it will be clearer that we are checking
> the tls record only for tls queues.

Ok, will be doing that.

Cheers,

Hannes




More information about the Linux-nvme mailing list