nvme/tcp: Allow to choose SSL socket implementation

Adding `psk` field to `spdk_nvme_ctrlr_opts`

Adding `psk` parameter to `bdev_nvme_attach_controller` RPC

Change-Id: Ie6f0d8b04ce472e6153934e985c026acded6cdfc
Signed-off-by: Boris Glimcher <Boris.Glimcher@emc.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/14046
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Boris Glimcher 2022-08-16 00:07:29 +03:00 committed by Tomasz Zawadzki
parent ef65d8467c
commit 35f7f0ce1e
12 changed files with 76 additions and 4 deletions

View File

@ -43,6 +43,9 @@ Calculate num_md_pages from num_md_pages_per_cluster_ratio, and pass it to spdk_
### rpc ### rpc
Added `psk` parameter to `bdev_nvme_attach_controller` RPC in order to enable SSL socket implementation
of TCP connection and set the PSK. Applicable for TCP transport only.
New options `enable_ktls` and `tls_version` were added to the `sock_impl_set_options` structure. New options `enable_ktls` and `tls_version` were added to the `sock_impl_set_options` structure.
New options `psk_key` and `psk_identity` were added to the `sock_impl_set_options` structure. New options `psk_key` and `psk_identity` were added to the `sock_impl_set_options` structure.
@ -81,6 +84,9 @@ tell the driver to not read the CHANGED_NS_LIST log page in response to a NS_ATT
AEN. When called the application is required to read this log page instead to clear the AEN. When called the application is required to read this log page instead to clear the
AEN. AEN.
Added `psk` field to `spdk_nvme_ctrlr_opts` struct in order to enable SSL socket implementation
of TCP connection and set the PSK. Applicable for TCP transport only.
### util ### util
Added new functions: `spdk_hexlify` and `spdk_unhexlify`. Added new functions: `spdk_hexlify` and `spdk_unhexlify`.

View File

@ -3245,6 +3245,7 @@ num_io_queues | Optional | uint32_t | The number of IO queues to
ctrlr_loss_timeout_sec | Optional | number | Time to wait until ctrlr is reconnected before deleting ctrlr. -1 means infinite reconnects. 0 means no reconnect. ctrlr_loss_timeout_sec | Optional | number | Time to wait until ctrlr is reconnected before deleting ctrlr. -1 means infinite reconnects. 0 means no reconnect.
reconnect_delay_sec | Optional | number | Time to delay a reconnect trial. 0 means no reconnect. reconnect_delay_sec | Optional | number | Time to delay a reconnect trial. 0 means no reconnect.
fast_io_fail_timeout_sec | Optional | number | Time to wait until ctrlr is reconnected before failing I/O to ctrlr. 0 means no such timeout. fast_io_fail_timeout_sec | Optional | number | Time to wait until ctrlr is reconnected before failing I/O to ctrlr. 0 means no such timeout.
psk | Optional | string | PSK in hexadecimal digits, e.g. 1234567890ABCDEF (Enables SSL socket implementation for TCP)
#### Example #### Example

View File

@ -266,8 +266,17 @@ struct spdk_nvme_ctrlr_opts {
* Default is `false` (CHANGED_NS_LIST log page is read). * Default is `false` (CHANGED_NS_LIST log page is read).
*/ */
uint8_t disable_read_changed_ns_list_log_page; uint8_t disable_read_changed_ns_list_log_page;
/**
* Set PSK and enable SSL socket implementation for NVMe/TCP only.
*
* If empty, a default socket implementation will be used.
* The TLS PSK interchange format is: NVMeTLSkey-1:xx:[Base64 encoded string]:
* 12B (header) + 2B (hash) + 176B (base64 for 1024b + crc32) + 3B (colons) + 1B (NULL) + 6B (extra space for future)
*/
char psk[200];
} __attribute__((packed)); } __attribute__((packed));
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_ctrlr_opts) == 617, "Incorrect size"); SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_ctrlr_opts) == 817, "Incorrect size");
/** /**
* NVMe acceleration operation callback. * NVMe acceleration operation callback.

View File

@ -962,6 +962,7 @@ nvme_ctrlr_opts_init(struct spdk_nvme_ctrlr_opts *opts,
SET_FIELD(fabrics_connect_timeout_us); SET_FIELD(fabrics_connect_timeout_us);
SET_FIELD(disable_read_ana_log_page); SET_FIELD(disable_read_ana_log_page);
SET_FIELD(disable_read_changed_ns_list_log_page); SET_FIELD(disable_read_changed_ns_list_log_page);
SET_FIELD_ARRAY(psk);
#undef FIELD_OK #undef FIELD_OK
#undef SET_FIELD #undef SET_FIELD

View File

@ -234,6 +234,10 @@ spdk_nvme_ctrlr_get_default_ctrlr_opts(struct spdk_nvme_ctrlr_opts *opts, size_t
SET_FIELD(disable_read_ana_log_page, false); SET_FIELD(disable_read_ana_log_page, false);
SET_FIELD(disable_read_changed_ns_list_log_page, false); SET_FIELD(disable_read_changed_ns_list_log_page, false);
if (FIELD_OK(psk)) {
memset(opts->psk, 0, sizeof(opts->psk));
}
#undef FIELD_OK #undef FIELD_OK
#undef SET_FIELD #undef SET_FIELD
} }

View File

@ -1882,6 +1882,9 @@ nvme_tcp_qpair_connect_sock(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpai
struct nvme_tcp_qpair *tqpair; struct nvme_tcp_qpair *tqpair;
int family; int family;
long int port; long int port;
char *sock_impl_name;
struct spdk_sock_impl_opts impl_opts;
size_t impl_opts_size = sizeof(impl_opts);
struct spdk_sock_opts opts; struct spdk_sock_opts opts;
tqpair = nvme_tcp_qpair(qpair); tqpair = nvme_tcp_qpair(qpair);
@ -1926,6 +1929,17 @@ nvme_tcp_qpair_connect_sock(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpai
return rc; return rc;
} }
sock_impl_name = ctrlr->opts.psk[0] ? "ssl" : NULL;
SPDK_DEBUGLOG(nvme, "sock_impl_name is %s\n", sock_impl_name);
spdk_sock_impl_get_opts(sock_impl_name, &impl_opts, &impl_opts_size);
impl_opts.enable_ktls = false;
impl_opts.tls_version = SPDK_TLS_VERSION_1_3;
/* TODO: Change current PSK HEX string format to TLS PSK Interchange Format */
impl_opts.psk_key = ctrlr->opts.psk;
/* TODO: generate identity from hostnqn instead */
impl_opts.psk_identity = "psk.spdk.io";
opts.opts_size = sizeof(opts); opts.opts_size = sizeof(opts);
spdk_sock_get_default_opts(&opts); spdk_sock_get_default_opts(&opts);
opts.priority = ctrlr->trid.priority; opts.priority = ctrlr->trid.priority;
@ -1933,7 +1947,11 @@ nvme_tcp_qpair_connect_sock(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpai
if (ctrlr->opts.transport_ack_timeout) { if (ctrlr->opts.transport_ack_timeout) {
opts.ack_timeout = 1ULL << ctrlr->opts.transport_ack_timeout; opts.ack_timeout = 1ULL << ctrlr->opts.transport_ack_timeout;
} }
tqpair->sock = spdk_sock_connect_ext(ctrlr->trid.traddr, port, NULL, &opts); if (sock_impl_name) {
opts.impl_opts = &impl_opts;
opts.impl_opts_size = sizeof(impl_opts);
}
tqpair->sock = spdk_sock_connect_ext(ctrlr->trid.traddr, port, sock_impl_name, &opts);
if (!tqpair->sock) { if (!tqpair->sock) {
SPDK_ERRLOG("sock connection error of tqpair=%p with addr=%s, port=%ld\n", SPDK_ERRLOG("sock connection error of tqpair=%p with addr=%s, port=%ld\n",
tqpair, ctrlr->trid.traddr, port); tqpair, ctrlr->trid.traddr, port);

View File

@ -777,6 +777,7 @@ nvmf_tcp_listen(struct spdk_nvmf_transport *transport, const struct spdk_nvme_tr
opts.opts_size = sizeof(opts); opts.opts_size = sizeof(opts);
spdk_sock_get_default_opts(&opts); spdk_sock_get_default_opts(&opts);
opts.priority = ttransport->tcp_opts.sock_priority; opts.priority = ttransport->tcp_opts.sock_priority;
/* TODO: also add impl_opts like on the initiator side */
port->listen_sock = spdk_sock_listen_ext(trid->traddr, trsvcid_int, port->listen_sock = spdk_sock_listen_ext(trid->traddr, trsvcid_int,
NULL, &opts); NULL, &opts);
if (port->listen_sock == NULL) { if (port->listen_sock == NULL) {

View File

@ -163,6 +163,7 @@ struct rpc_bdev_nvme_attach_controller {
char *hostnqn; char *hostnqn;
char *hostaddr; char *hostaddr;
char *hostsvcid; char *hostsvcid;
char *psk;
enum bdev_nvme_multipath_mode multipath; enum bdev_nvme_multipath_mode multipath;
struct nvme_ctrlr_opts bdev_opts; struct nvme_ctrlr_opts bdev_opts;
struct spdk_nvme_ctrlr_opts drv_opts; struct spdk_nvme_ctrlr_opts drv_opts;
@ -181,6 +182,7 @@ free_rpc_bdev_nvme_attach_controller(struct rpc_bdev_nvme_attach_controller *req
free(req->hostnqn); free(req->hostnqn);
free(req->hostaddr); free(req->hostaddr);
free(req->hostsvcid); free(req->hostsvcid);
free(req->psk);
} }
static int static int
@ -256,6 +258,7 @@ static const struct spdk_json_object_decoder rpc_bdev_nvme_attach_controller_dec
{"ctrlr_loss_timeout_sec", offsetof(struct rpc_bdev_nvme_attach_controller, bdev_opts.ctrlr_loss_timeout_sec), spdk_json_decode_int32, true}, {"ctrlr_loss_timeout_sec", offsetof(struct rpc_bdev_nvme_attach_controller, bdev_opts.ctrlr_loss_timeout_sec), spdk_json_decode_int32, true},
{"reconnect_delay_sec", offsetof(struct rpc_bdev_nvme_attach_controller, bdev_opts.reconnect_delay_sec), spdk_json_decode_uint32, true}, {"reconnect_delay_sec", offsetof(struct rpc_bdev_nvme_attach_controller, bdev_opts.reconnect_delay_sec), spdk_json_decode_uint32, true},
{"fast_io_fail_timeout_sec", offsetof(struct rpc_bdev_nvme_attach_controller, bdev_opts.fast_io_fail_timeout_sec), spdk_json_decode_uint32, true}, {"fast_io_fail_timeout_sec", offsetof(struct rpc_bdev_nvme_attach_controller, bdev_opts.fast_io_fail_timeout_sec), spdk_json_decode_uint32, true},
{"psk", offsetof(struct rpc_bdev_nvme_attach_controller, psk), spdk_json_decode_string, true},
}; };
#define NVME_MAX_BDEVS_PER_RPC 128 #define NVME_MAX_BDEVS_PER_RPC 128
@ -407,6 +410,11 @@ rpc_bdev_nvme_attach_controller(struct spdk_jsonrpc_request *request,
ctx->req.hostnqn); ctx->req.hostnqn);
} }
if (ctx->req.psk) {
snprintf(ctx->req.drv_opts.psk, sizeof(ctx->req.drv_opts.psk), "%s",
ctx->req.psk);
}
if (ctx->req.hostaddr) { if (ctx->req.hostaddr) {
maxlen = sizeof(ctx->req.drv_opts.src_addr); maxlen = sizeof(ctx->req.drv_opts.src_addr);
len = strnlen(ctx->req.hostaddr, maxlen); len = strnlen(ctx->req.hostaddr, maxlen);

View File

@ -600,7 +600,7 @@ def bdev_nvme_attach_controller(client, name, trtype, traddr, adrfam=None, trsvc
hostsvcid=None, prchk_reftag=None, prchk_guard=None, hostsvcid=None, prchk_reftag=None, prchk_guard=None,
hdgst=None, ddgst=None, fabrics_timeout=None, multipath=None, num_io_queues=None, hdgst=None, ddgst=None, fabrics_timeout=None, multipath=None, num_io_queues=None,
ctrlr_loss_timeout_sec=None, reconnect_delay_sec=None, ctrlr_loss_timeout_sec=None, reconnect_delay_sec=None,
fast_io_fail_timeout_sec=None): fast_io_fail_timeout_sec=None, psk=None):
"""Construct block device for each NVMe namespace in the attached controller. """Construct block device for each NVMe namespace in the attached controller.
Args: Args:
@ -635,6 +635,7 @@ def bdev_nvme_attach_controller(client, name, trtype, traddr, adrfam=None, trsvc
0 means no such timeout. 0 means no such timeout.
If fast_io_fail_timeout_sec is not zero, it has to be not less than reconnect_delay_sec and less than If fast_io_fail_timeout_sec is not zero, it has to be not less than reconnect_delay_sec and less than
ctrlr_loss_timeout_sec if ctrlr_loss_timeout_sec is not -1. (optional) ctrlr_loss_timeout_sec if ctrlr_loss_timeout_sec is not -1. (optional)
psk: Set PSK and enable TCP SSL socket implementation (optional)
Returns: Returns:
Names of created block devices. Names of created block devices.
@ -694,6 +695,9 @@ def bdev_nvme_attach_controller(client, name, trtype, traddr, adrfam=None, trsvc
if fast_io_fail_timeout_sec is not None: if fast_io_fail_timeout_sec is not None:
params['fast_io_fail_timeout_sec'] = fast_io_fail_timeout_sec params['fast_io_fail_timeout_sec'] = fast_io_fail_timeout_sec
if psk:
params['psk'] = psk
return client.call('bdev_nvme_attach_controller', params) return client.call('bdev_nvme_attach_controller', params)

View File

@ -608,7 +608,8 @@ if __name__ == "__main__":
num_io_queues=args.num_io_queues, num_io_queues=args.num_io_queues,
ctrlr_loss_timeout_sec=args.ctrlr_loss_timeout_sec, ctrlr_loss_timeout_sec=args.ctrlr_loss_timeout_sec,
reconnect_delay_sec=args.reconnect_delay_sec, reconnect_delay_sec=args.reconnect_delay_sec,
fast_io_fail_timeout_sec=args.fast_io_fail_timeout_sec)) fast_io_fail_timeout_sec=args.fast_io_fail_timeout_sec,
psk=args.psk))
p = subparsers.add_parser('bdev_nvme_attach_controller', help='Add bdevs with nvme backend') p = subparsers.add_parser('bdev_nvme_attach_controller', help='Add bdevs with nvme backend')
p.add_argument('-b', '--name', help="Name of the NVMe controller, prefix for each bdev name", required=True) p.add_argument('-b', '--name', help="Name of the NVMe controller, prefix for each bdev name", required=True)
@ -659,6 +660,8 @@ if __name__ == "__main__":
If fast_io_fail_timeout_sec is not zero, it has to be not less than reconnect_delay_sec and If fast_io_fail_timeout_sec is not zero, it has to be not less than reconnect_delay_sec and
less than ctrlr_loss_timeout_sec if ctrlr_loss_timeout_sec is not -1.""", less than ctrlr_loss_timeout_sec if ctrlr_loss_timeout_sec is not -1.""",
type=int) type=int)
p.add_argument('-k', '--psk',
help='Set PSK and enable TCP SSL socket implementation: e.g., 1234567890ABCDEF')
p.set_defaults(func=bdev_nvme_attach_controller) p.set_defaults(func=bdev_nvme_attach_controller)
def bdev_nvme_get_controllers(args): def bdev_nvme_get_controllers(args):

View File

@ -17,6 +17,8 @@ DEFINE_STUB(spdk_sock_listen, struct spdk_sock *, (const char *ip, int port, con
DEFINE_STUB(spdk_sock_listen_ext, struct spdk_sock *, (const char *ip, int port, DEFINE_STUB(spdk_sock_listen_ext, struct spdk_sock *, (const char *ip, int port,
const char *impl_name, struct spdk_sock_opts *opts), NULL); const char *impl_name, struct spdk_sock_opts *opts), NULL);
DEFINE_STUB_V(spdk_sock_get_default_opts, (struct spdk_sock_opts *opts)); DEFINE_STUB_V(spdk_sock_get_default_opts, (struct spdk_sock_opts *opts));
DEFINE_STUB(spdk_sock_impl_get_opts, int, (const char *impl_name, struct spdk_sock_impl_opts *opts,
size_t *len), 0);
DEFINE_STUB(spdk_sock_accept, struct spdk_sock *, (struct spdk_sock *sock), NULL); DEFINE_STUB(spdk_sock_accept, struct spdk_sock *, (struct spdk_sock *sock), NULL);
DEFINE_STUB(spdk_sock_close, int, (struct spdk_sock **sock), 0); DEFINE_STUB(spdk_sock_close, int, (struct spdk_sock **sock), 0);
DEFINE_STUB(spdk_sock_recv, ssize_t, (struct spdk_sock *sock, void *buf, size_t len), 1); DEFINE_STUB(spdk_sock_recv, ssize_t, (struct spdk_sock *sock, void *buf, size_t len), 1);

View File

@ -116,5 +116,20 @@ $rpc_py nvmf_subsystem_add_ns nqn.2016-06.io.spdk:cnode1 malloc0 -n 1
-r "trtype:${TEST_TRANSPORT} adrfam:IPv4 traddr:${NVMF_FIRST_TARGET_IP} trsvcid:${NVMF_PORT} \ -r "trtype:${TEST_TRANSPORT} adrfam:IPv4 traddr:${NVMF_FIRST_TARGET_IP} trsvcid:${NVMF_PORT} \
subnqn:nqn.2016-06.io.spdk:cnode1" --psk-key 1234567890ABCDEF --psk-identity psk.spdk.io subnqn:nqn.2016-06.io.spdk:cnode1" --psk-key 1234567890ABCDEF --psk-identity psk.spdk.io
# use bdevperf to test "bdev_nvme_attach_controller"
bdevperf_rpc_sock=/var/tmp/bdevperf.sock
$rootdir/test/bdev/bdevperf/bdevperf -m 0x4 -z -r $bdevperf_rpc_sock -q 128 -o 4096 -w verify -t 10 &
bdevperf_pid=$!
trap 'process_shm --id $NVMF_APP_SHM_ID; killprocess $bdevperf_pid; nvmftestfini; exit 1' SIGINT SIGTERM EXIT
waitforlisten $bdevperf_pid $bdevperf_rpc_sock
# send RPC
$rpc_py -s $bdevperf_rpc_sock bdev_nvme_attach_controller -b TLSTEST -t $TEST_TRANSPORT -a $NVMF_FIRST_TARGET_IP \
-s $NVMF_PORT -f ipv4 -n nqn.2016-06.io.spdk:cnode1 --psk 1234567890ABCDEF
# run I/O and wait
$rootdir/test/bdev/bdevperf/bdevperf.py -t 20 -s $bdevperf_rpc_sock perform_tests
# finish
killprocess $bdevperf_pid
trap - SIGINT SIGTERM EXIT trap - SIGINT SIGTERM EXIT
nvmftestfini nvmftestfini