diff --git a/etc/spdk/nvmf.conf.in b/etc/spdk/nvmf.conf.in index 292ef0136..ae35f1b43 100644 --- a/etc/spdk/nvmf.conf.in +++ b/etc/spdk/nvmf.conf.in @@ -232,7 +232,7 @@ # - NQN is required and must be unique. # - Between 1 and 255 Listen directives are allowed. This defines # the addresses on which new connections may be accepted. The format -# is Listen
where type can be RDMA or TCP. +# is Listen
where type can be RDMA, TCP or FC. # - Between 0 and 255 Host directives are allowed. This defines the # NQNs of allowed hosts. If no Host directive is specified, all hosts # are allowed to connect. @@ -273,3 +273,16 @@ Namespace Malloc1 Namespace AIO0 Namespace AIO1 + +# Subsystem with FC listen address directive +# - Listen option allows subsystem access on specific FC ports identified +# by WWNN-WWPN. Each subsystem allows 0 - 255 listen directives. +# If no listen directive is provided, subsystem can be accessed on all +# avialable FC links permitted by FC zoning rules. +# +# [Subsystem3] + #NQN nqn.2016-06.io.spdk:cnode3 + #Listen FC "nn-0x20000090fac7ca5c:pn-0x10000090fac7ca5c" + #AllowAnyHost Yes + #SN SPDK00000000000003 + #Namespace Malloc4 diff --git a/include/spdk/nvmf.h b/include/spdk/nvmf.h index 3bdea4073..2de14c0c5 100644 --- a/include/spdk/nvmf.h +++ b/include/spdk/nvmf.h @@ -616,6 +616,29 @@ struct spdk_nvmf_listener *spdk_nvmf_subsystem_get_next_listener( const struct spdk_nvme_transport_id *spdk_nvmf_listener_get_trid( struct spdk_nvmf_listener *listener); +/** + * Set whether a subsystem should allow any listen address or only addresses in the allowed list. + * + * \param subsystem Subsystem to allow dynamic listener assignment. + * \param allow_any_listener true to allow dynamic listener assignment for + * this subsystem, or false to enforce the whitelist configured during + * subsystem setup. + */ +void spdk_nvmf_subsystem_allow_any_listener( + struct spdk_nvmf_subsystem *subsystem, + bool allow_any_listener); + +/** + * Check whether a subsystem allows any listen address or only addresses in the allowed list. + * + * \param subsystem Subsystem to query. + * + * \return true if this subsystem allows dynamic management of listen address list, + * or false if only allows addresses in the whitelist configured during subsystem setup. + */ +bool spdk_nvmf_subsytem_any_listener_allowed( + struct spdk_nvmf_subsystem *subsystem); + /** NVMe-oF target namespace creation options */ struct spdk_nvmf_ns_opts { /** diff --git a/lib/nvmf/fc.c b/lib/nvmf/fc.c index 8ce581754..77da54d0c 100644 --- a/lib/nvmf/fc.c +++ b/lib/nvmf/fc.c @@ -3003,16 +3003,23 @@ nvmf_fc_adm_add_rem_nport_listener(struct spdk_nvmf_fc_nport *nport, bool add) while (subsystem) { struct nvmf_fc_add_rem_listener_ctx *ctx; - ctx = calloc(1, sizeof(struct nvmf_fc_add_rem_listener_ctx)); - if (ctx) { - ctx->add_listener = add; - spdk_nvmf_fc_create_trid(&ctx->trid, nport->fc_nodename.u.wwn, - nport->fc_portname.u.wwn); - if (spdk_nvmf_subsystem_pause(subsystem, nvmf_fc_adm_subsystem_paused_cb, ctx)) { - SPDK_ERRLOG("Failed to pause subsystem: %s\n", subsystem->subnqn); - free(ctx); + if (spdk_nvmf_subsytem_any_listener_allowed(subsystem) == true) { + ctx = calloc(1, sizeof(struct nvmf_fc_add_rem_listener_ctx)); + if (ctx) { + ctx->add_listener = add; + spdk_nvmf_fc_create_trid(&ctx->trid, + nport->fc_nodename.u.wwn, + nport->fc_portname.u.wwn); + if (spdk_nvmf_subsystem_pause(subsystem, + nvmf_fc_adm_subsystem_paused_cb, + ctx)) { + SPDK_ERRLOG("Failed to pause subsystem: %s\n", + subsystem->subnqn); + free(ctx); + } } } + subsystem = spdk_nvmf_subsystem_get_next(subsystem); } diff --git a/lib/nvmf/nvmf_internal.h b/lib/nvmf/nvmf_internal.h index fa04275f6..fc6cca81d 100644 --- a/lib/nvmf/nvmf_internal.h +++ b/lib/nvmf/nvmf_internal.h @@ -350,6 +350,7 @@ struct spdk_nvmf_subsystem { enum spdk_nvmf_subtype subtype; uint16_t next_cntlid; bool allow_any_host; + bool allow_any_listener ; struct spdk_nvmf_tgt *tgt; diff --git a/lib/nvmf/subsystem.c b/lib/nvmf/subsystem.c index 122bd486e..dc34df3a3 100644 --- a/lib/nvmf/subsystem.c +++ b/lib/nvmf/subsystem.c @@ -842,6 +842,20 @@ spdk_nvmf_listener_get_trid(struct spdk_nvmf_listener *listener) return &listener->trid; } +void +spdk_nvmf_subsystem_allow_any_listener(struct spdk_nvmf_subsystem *subsystem, + bool allow_any_listener) +{ + subsystem->allow_any_listener = allow_any_listener; +} + +bool +spdk_nvmf_subsytem_any_listener_allowed(struct spdk_nvmf_subsystem *subsystem) +{ + return subsystem->allow_any_listener; +} + + struct subsystem_update_ns_ctx { struct spdk_nvmf_subsystem *subsystem; diff --git a/module/event/subsystems/nvmf/conf.c b/module/event/subsystems/nvmf/conf.c index c16d72d54..1b3b71978 100644 --- a/module/event/subsystems/nvmf/conf.c +++ b/module/event/subsystems/nvmf/conf.c @@ -266,6 +266,25 @@ spdk_nvmf_tgt_parse_listen_ip_addr(char *address, return 0; } +static int +spdk_nvmf_tgt_parse_listen_fc_addr(const char *address, + struct spdk_nvme_transport_id *trid) +{ + /* transport address format and requirements, + * "nn-0xWWNN:pn-0xWWPN" - size equals 43 bytes and is required to + * contain 'nn' and 'pn'. + */ + if (strlen(address) != 43 || strncmp(address, "nn-0x", 5) || + strncmp(&address[21], ":pn-0x", 6)) { + SPDK_ERRLOG("Unable to parse fc address '%s'\n", address); + return -1; + } + + snprintf(trid->traddr, sizeof(trid->traddr), "%s", address); + + return 0; +} + static int spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp) { @@ -273,6 +292,7 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp) size_t i; int lcore; bool allow_any_host; + bool allow_any_listener = true; const char *sn; const char *mn; struct spdk_nvmf_subsystem *subsystem; @@ -443,6 +463,11 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp) free(address_dup); continue; } + } else if (trid.trtype == SPDK_NVME_TRANSPORT_FC) { + if (spdk_nvmf_tgt_parse_listen_fc_addr(address_dup, &trid)) { + free(address_dup); + continue; + } } free(address_dup); @@ -450,8 +475,11 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp) spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt, &trid, spdk_nvmf_tgt_listen_done, NULL); spdk_nvmf_subsystem_add_listener(subsystem, &trid); + allow_any_listener = false; } + spdk_nvmf_subsystem_allow_any_listener(subsystem, allow_any_listener); + /* Parse Host sections */ for (i = 0; ; i++) { const char *host = spdk_conf_section_get_nval(sp, "Host", i);