diff --git a/lib/nvmf/Makefile b/lib/nvmf/Makefile index 32082ac8b..e2f4f86cb 100644 --- a/lib/nvmf/Makefile +++ b/lib/nvmf/Makefile @@ -37,7 +37,7 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk CFLAGS += $(ENV_CFLAGS) LIBNAME = nvmf -C_SRCS = subsystem.c nvmf.c \ +C_SRCS = discovery.c subsystem.c nvmf.c \ request.c session.c transport.c \ direct.c virtual.c diff --git a/lib/nvmf/discovery.c b/lib/nvmf/discovery.c new file mode 100644 index 000000000..cbb3c0714 --- /dev/null +++ b/lib/nvmf/discovery.c @@ -0,0 +1,219 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * NVMe over Fabrics discovery service + */ + +#include +#include + +#include "nvmf_internal.h" +#include "session.h" +#include "subsystem.h" +#include "request.h" +#include "transport.h" + +#include "spdk/string.h" +#include "spdk/trace.h" +#include "spdk/nvmf_spec.h" + +#include "spdk_internal/bdev.h" +#include "spdk_internal/log.h" + +static void +nvmf_update_discovery_log(void) +{ + uint64_t numrec = 0; + struct spdk_nvmf_subsystem *subsystem; + struct spdk_nvmf_subsystem_allowed_listener *allowed_listener; + struct spdk_nvmf_listen_addr *listen_addr; + struct spdk_nvmf_discovery_log_page_entry *entry; + const struct spdk_nvmf_transport *transport; + struct spdk_nvmf_discovery_log_page *disc_log; + size_t cur_size; + + SPDK_TRACELOG(SPDK_TRACE_NVMF, "Generating log page for genctr %" PRIu64 "\n", + g_nvmf_tgt.discovery_genctr); + + cur_size = sizeof(struct spdk_nvmf_discovery_log_page); + disc_log = calloc(1, cur_size); + if (disc_log == NULL) { + SPDK_ERRLOG("Discovery log page memory allocation error\n"); + return; + } + + TAILQ_FOREACH(subsystem, &g_nvmf_tgt.subsystems, entries) { + if (subsystem->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY) { + continue; + } + + TAILQ_FOREACH(allowed_listener, &subsystem->allowed_listeners, link) { + size_t new_size = cur_size + sizeof(*entry); + void *new_log_page = realloc(disc_log, new_size); + + if (new_log_page == NULL) { + SPDK_ERRLOG("Discovery log page memory allocation error\n"); + break; + } + + listen_addr = allowed_listener->listen_addr; + + disc_log = new_log_page; + cur_size = new_size; + + entry = &disc_log->entries[numrec]; + memset(entry, 0, sizeof(*entry)); + entry->portid = numrec; + entry->cntlid = 0xffff; + entry->asqsz = g_nvmf_tgt.max_queue_depth; + entry->subtype = subsystem->subtype; + snprintf(entry->subnqn, sizeof(entry->subnqn), "%s", subsystem->subnqn); + + transport = spdk_nvmf_transport_get(listen_addr->trname); + assert(transport != NULL); + + transport->listen_addr_discover(listen_addr, entry); + + numrec++; + } + } + + disc_log->numrec = numrec; + disc_log->genctr = g_nvmf_tgt.discovery_genctr; + + free(g_nvmf_tgt.discovery_log_page); + + g_nvmf_tgt.discovery_log_page = disc_log; + g_nvmf_tgt.discovery_log_page_size = cur_size; +} + +void +spdk_nvmf_get_discovery_log_page(void *buffer, uint64_t offset, uint32_t length) +{ + size_t copy_len = 0; + size_t zero_len = length; + + if (g_nvmf_tgt.discovery_log_page == NULL || + g_nvmf_tgt.discovery_log_page->genctr != g_nvmf_tgt.discovery_genctr) { + nvmf_update_discovery_log(); + } + + /* Copy the valid part of the discovery log page, if any */ + if (g_nvmf_tgt.discovery_log_page && offset < g_nvmf_tgt.discovery_log_page_size) { + copy_len = spdk_min(g_nvmf_tgt.discovery_log_page_size - offset, length); + zero_len -= copy_len; + memcpy(buffer, (char *)g_nvmf_tgt.discovery_log_page + offset, copy_len); + } + + /* Zero out the rest of the buffer */ + if (zero_len) { + memset((char *)buffer + copy_len, 0, zero_len); + } + + /* We should have copied or zeroed every byte of the output buffer. */ + assert(copy_len + zero_len == length); +} + +static inline uint32_t +nvmf_get_log_page_len(struct spdk_nvme_cmd *cmd) +{ + uint32_t numdl = (cmd->cdw10 >> 16) & 0xFFFFu; + uint32_t numdu = (cmd->cdw11) & 0xFFFFu; + return ((numdu << 16) + numdl + 1) * sizeof(uint32_t); +} + +spdk_nvmf_request_exec_status +spdk_nvmf_process_discovery_cmd(struct spdk_nvmf_request *req) +{ + struct spdk_nvmf_session *session = req->conn->sess; + struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; + struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl; + uint64_t log_page_offset; + uint32_t len; + + /* pre-set response details for this command */ + response->status.sc = SPDK_NVME_SC_SUCCESS; + + if (req->data == NULL) { + SPDK_ERRLOG("discovery command with no buffer\n"); + response->status.sc = SPDK_NVME_SC_INVALID_FIELD; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } + + switch (cmd->opc) { + case SPDK_NVME_OPC_IDENTIFY: + /* Only identify controller can be supported */ + if ((cmd->cdw10 & 0xFF) == SPDK_NVME_IDENTIFY_CTRLR) { + SPDK_TRACELOG(SPDK_TRACE_NVMF, "Identify Controller\n"); + memcpy(req->data, (char *)&session->vcdata, sizeof(struct spdk_nvme_ctrlr_data)); + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } else { + SPDK_ERRLOG("Unsupported identify command\n"); + response->status.sc = SPDK_NVME_SC_INVALID_FIELD; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } + break; + case SPDK_NVME_OPC_GET_LOG_PAGE: + log_page_offset = (uint64_t)cmd->cdw12 | ((uint64_t)cmd->cdw13 << 32); + if (log_page_offset & 3) { + SPDK_ERRLOG("Invalid log page offset 0x%" PRIx64 "\n", log_page_offset); + response->status.sc = SPDK_NVME_SC_INVALID_FIELD; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } + + len = nvmf_get_log_page_len(cmd); + if (len > req->length) { + SPDK_ERRLOG("Get log page: len (%u) > buf size (%u)\n", + len, req->length); + response->status.sc = SPDK_NVME_SC_INVALID_FIELD; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } + + if ((cmd->cdw10 & 0xFF) == SPDK_NVME_LOG_DISCOVERY) { + spdk_nvmf_get_discovery_log_page(req->data, log_page_offset, len); + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } else { + SPDK_ERRLOG("Unsupported log page %u\n", cmd->cdw10 & 0xFF); + response->status.sc = SPDK_NVME_SC_INVALID_FIELD; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } + break; + default: + SPDK_ERRLOG("Unsupported Opcode 0x%x for Discovery service\n", cmd->opc); + response->status.sc = SPDK_NVME_SC_INVALID_OPCODE; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } + + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; +} diff --git a/lib/nvmf/request.c b/lib/nvmf/request.c index de642b5d6..7eae2ba77 100644 --- a/lib/nvmf/request.c +++ b/lib/nvmf/request.c @@ -67,79 +67,6 @@ spdk_nvmf_request_complete(struct spdk_nvmf_request *req) return 0; } -static inline uint32_t -nvmf_get_log_page_len(struct spdk_nvme_cmd *cmd) -{ - uint32_t numdl = (cmd->cdw10 >> 16) & 0xFFFFu; - uint32_t numdu = (cmd->cdw11) & 0xFFFFu; - return ((numdu << 16) + numdl + 1) * sizeof(uint32_t); -} - -static spdk_nvmf_request_exec_status -nvmf_process_discovery_cmd(struct spdk_nvmf_request *req) -{ - struct spdk_nvmf_session *session = req->conn->sess; - struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; - struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl; - uint64_t log_page_offset; - uint32_t len; - - /* pre-set response details for this command */ - response->status.sc = SPDK_NVME_SC_SUCCESS; - - if (req->data == NULL) { - SPDK_ERRLOG("discovery command with no buffer\n"); - response->status.sc = SPDK_NVME_SC_INVALID_FIELD; - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - } - - switch (cmd->opc) { - case SPDK_NVME_OPC_IDENTIFY: - /* Only identify controller can be supported */ - if ((cmd->cdw10 & 0xFF) == SPDK_NVME_IDENTIFY_CTRLR) { - SPDK_TRACELOG(SPDK_TRACE_NVMF, "Identify Controller\n"); - memcpy(req->data, (char *)&session->vcdata, sizeof(struct spdk_nvme_ctrlr_data)); - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - } else { - SPDK_ERRLOG("Unsupported identify command\n"); - response->status.sc = SPDK_NVME_SC_INVALID_FIELD; - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - } - break; - case SPDK_NVME_OPC_GET_LOG_PAGE: - log_page_offset = (uint64_t)cmd->cdw12 | ((uint64_t)cmd->cdw13 << 32); - if (log_page_offset & 3) { - SPDK_ERRLOG("Invalid log page offset 0x%" PRIx64 "\n", log_page_offset); - response->status.sc = SPDK_NVME_SC_INVALID_FIELD; - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - } - - len = nvmf_get_log_page_len(cmd); - if (len > req->length) { - SPDK_ERRLOG("Get log page: len (%u) > buf size (%u)\n", - len, req->length); - response->status.sc = SPDK_NVME_SC_INVALID_FIELD; - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - } - - if ((cmd->cdw10 & 0xFF) == SPDK_NVME_LOG_DISCOVERY) { - spdk_nvmf_get_discovery_log_page(req->data, log_page_offset, len); - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - } else { - SPDK_ERRLOG("Unsupported log page %u\n", cmd->cdw10 & 0xFF); - response->status.sc = SPDK_NVME_SC_INVALID_FIELD; - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - } - break; - default: - SPDK_ERRLOG("Unsupported Opcode 0x%x for Discovery service\n", cmd->opc); - response->status.sc = SPDK_NVME_SC_INVALID_OPCODE; - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - } - - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; -} - static spdk_nvmf_request_exec_status nvmf_process_property_get(struct spdk_nvmf_request *req) { @@ -362,7 +289,7 @@ spdk_nvmf_request_exec(struct spdk_nvmf_request *req) subsystem = session->subsys; assert(subsystem != NULL); if (subsystem->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY) { - status = nvmf_process_discovery_cmd(req); + status = spdk_nvmf_process_discovery_cmd(req); } else { if (subsystem->is_removed) { rsp->status.sc = SPDK_NVME_SC_ABORTED_BY_REQUEST; diff --git a/lib/nvmf/request.h b/lib/nvmf/request.h index 44fc00400..43cea88c2 100644 --- a/lib/nvmf/request.h +++ b/lib/nvmf/request.h @@ -73,4 +73,6 @@ spdk_nvmf_request_exec(struct spdk_nvmf_request *req); int spdk_nvmf_request_complete(struct spdk_nvmf_request *req); +spdk_nvmf_request_exec_status spdk_nvmf_process_discovery_cmd(struct spdk_nvmf_request *req); + #endif diff --git a/lib/nvmf/subsystem.c b/lib/nvmf/subsystem.c index 917a4e47a..52caa77a0 100644 --- a/lib/nvmf/subsystem.c +++ b/lib/nvmf/subsystem.c @@ -370,100 +370,6 @@ nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem, return 0; } -static void -nvmf_update_discovery_log(void) -{ - uint64_t numrec = 0; - struct spdk_nvmf_subsystem *subsystem; - struct spdk_nvmf_subsystem_allowed_listener *allowed_listener; - struct spdk_nvmf_listen_addr *listen_addr; - struct spdk_nvmf_discovery_log_page_entry *entry; - const struct spdk_nvmf_transport *transport; - struct spdk_nvmf_discovery_log_page *disc_log; - size_t cur_size; - - SPDK_TRACELOG(SPDK_TRACE_NVMF, "Generating log page for genctr %" PRIu64 "\n", - g_nvmf_tgt.discovery_genctr); - - cur_size = sizeof(struct spdk_nvmf_discovery_log_page); - disc_log = calloc(1, cur_size); - if (disc_log == NULL) { - SPDK_ERRLOG("Discovery log page memory allocation error\n"); - return; - } - - TAILQ_FOREACH(subsystem, &g_nvmf_tgt.subsystems, entries) { - if (subsystem->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY) { - continue; - } - - TAILQ_FOREACH(allowed_listener, &subsystem->allowed_listeners, link) { - size_t new_size = cur_size + sizeof(*entry); - void *new_log_page = realloc(disc_log, new_size); - - if (new_log_page == NULL) { - SPDK_ERRLOG("Discovery log page memory allocation error\n"); - break; - } - - listen_addr = allowed_listener->listen_addr; - - disc_log = new_log_page; - cur_size = new_size; - - entry = &disc_log->entries[numrec]; - memset(entry, 0, sizeof(*entry)); - entry->portid = numrec; - entry->cntlid = 0xffff; - entry->asqsz = g_nvmf_tgt.max_queue_depth; - entry->subtype = subsystem->subtype; - snprintf(entry->subnqn, sizeof(entry->subnqn), "%s", subsystem->subnqn); - - transport = spdk_nvmf_transport_get(listen_addr->trname); - assert(transport != NULL); - - transport->listen_addr_discover(listen_addr, entry); - - numrec++; - } - } - - disc_log->numrec = numrec; - disc_log->genctr = g_nvmf_tgt.discovery_genctr; - - free(g_nvmf_tgt.discovery_log_page); - - g_nvmf_tgt.discovery_log_page = disc_log; - g_nvmf_tgt.discovery_log_page_size = cur_size; -} - -void -spdk_nvmf_get_discovery_log_page(void *buffer, uint64_t offset, uint32_t length) -{ - size_t copy_len = 0; - size_t zero_len = length; - - if (g_nvmf_tgt.discovery_log_page == NULL || - g_nvmf_tgt.discovery_log_page->genctr != g_nvmf_tgt.discovery_genctr) { - nvmf_update_discovery_log(); - } - - /* Copy the valid part of the discovery log page, if any */ - if (g_nvmf_tgt.discovery_log_page && offset < g_nvmf_tgt.discovery_log_page_size) { - copy_len = spdk_min(g_nvmf_tgt.discovery_log_page_size - offset, length); - zero_len -= copy_len; - memcpy(buffer, (char *)g_nvmf_tgt.discovery_log_page + offset, copy_len); - } - - /* Zero out the rest of the buffer */ - if (zero_len) { - memset((char *)buffer + copy_len, 0, zero_len); - } - - /* We should have copied or zeroed every byte of the output buffer. */ - assert(copy_len + zero_len == length); -} - static void spdk_nvmf_ctrlr_hot_remove(void *remove_ctx) { struct spdk_nvmf_subsystem *subsystem = (struct spdk_nvmf_subsystem *)remove_ctx; diff --git a/mk/nvmf.unittest.mk b/mk/nvmf.unittest.mk index 235f71187..577b95aef 100644 --- a/mk/nvmf.unittest.mk +++ b/mk/nvmf.unittest.mk @@ -34,7 +34,7 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk include $(SPDK_ROOT_DIR)/mk/spdk.app.mk -C_SRCS = $(TEST_FILE) +C_SRCS = $(TEST_FILE) $(OTHER_FILES) CFLAGS += -I$(SPDK_ROOT_DIR)/lib/nvmf CFLAGS += -I$(SPDK_ROOT_DIR)/test @@ -53,4 +53,7 @@ $(APP) : $(OBJS) $(SPDK_LIB_FILES) clean: $(CLEAN_C) $(APP) +%.o: $(SPDK_ROOT_DIR)/lib/nvmf/%.c %.d $(MAKEFILE_LIST) + $(COMPILE_C) + include $(SPDK_ROOT_DIR)/mk/spdk.deps.mk diff --git a/test/lib/nvmf/Makefile b/test/lib/nvmf/Makefile index 072ba2da7..f568dddb0 100644 --- a/test/lib/nvmf/Makefile +++ b/test/lib/nvmf/Makefile @@ -34,7 +34,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk -DIRS-y = direct request session subsystem virtual +DIRS-y = direct discovery request session subsystem virtual .PHONY: all clean $(DIRS-y) diff --git a/test/lib/nvmf/discovery/.gitignore b/test/lib/nvmf/discovery/.gitignore new file mode 100644 index 000000000..8672f8a58 --- /dev/null +++ b/test/lib/nvmf/discovery/.gitignore @@ -0,0 +1 @@ +discovery_ut diff --git a/test/lib/nvmf/discovery/Makefile b/test/lib/nvmf/discovery/Makefile new file mode 100644 index 000000000..7f5ee3b80 --- /dev/null +++ b/test/lib/nvmf/discovery/Makefile @@ -0,0 +1,39 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) + +TEST_FILE = discovery_ut.c +OTHER_FILES = subsystem.c + +include $(SPDK_ROOT_DIR)/mk/nvmf.unittest.mk diff --git a/test/lib/nvmf/discovery/discovery_ut.c b/test/lib/nvmf/discovery/discovery_ut.c new file mode 100644 index 000000000..2df41f599 --- /dev/null +++ b/test/lib/nvmf/discovery/discovery_ut.c @@ -0,0 +1,297 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "spdk_cunit.h" + +#include "discovery.c" + +SPDK_LOG_REGISTER_TRACE_FLAG("nvmf", SPDK_TRACE_NVMF) + +const struct spdk_nvmf_ctrlr_ops spdk_nvmf_direct_ctrlr_ops; +const struct spdk_nvmf_ctrlr_ops spdk_nvmf_virtual_ctrlr_ops; + +struct spdk_nvmf_tgt g_nvmf_tgt = { + .subsystems = TAILQ_HEAD_INITIALIZER(g_nvmf_tgt.subsystems) +}; + +struct spdk_nvmf_listen_addr * +spdk_nvmf_listen_addr_create(const char *trname, const char *traddr, const char *trsvcid) +{ + struct spdk_nvmf_listen_addr *listen_addr; + + listen_addr = calloc(1, sizeof(*listen_addr)); + if (!listen_addr) { + return NULL; + } + + listen_addr->traddr = strdup(traddr); + if (!listen_addr->traddr) { + free(listen_addr); + return NULL; + } + + listen_addr->trsvcid = strdup(trsvcid); + if (!listen_addr->trsvcid) { + free(listen_addr->traddr); + free(listen_addr); + return NULL; + } + + listen_addr->trname = strdup(trname); + if (!listen_addr->trname) { + free(listen_addr->traddr); + free(listen_addr->trsvcid); + free(listen_addr); + return NULL; + } + + return listen_addr; +} + +void +spdk_nvmf_listen_addr_cleanup(struct spdk_nvmf_listen_addr *addr) +{ + return; +} + +bool +spdk_bdev_claim(struct spdk_bdev *bdev, spdk_bdev_remove_cb_t remove_cb, + void *remove_ctx) +{ + return true; +} + +static int +test_transport1_listen_addr_add(struct spdk_nvmf_listen_addr *listen_addr) +{ + return 0; +} + +static void +test_transport1_listen_addr_discover(struct spdk_nvmf_listen_addr *listen_addr, + struct spdk_nvmf_discovery_log_page_entry *entry) +{ + entry->trtype = 42; +} + +static const struct spdk_nvmf_transport test_transport1 = { + .listen_addr_add = test_transport1_listen_addr_add, + .listen_addr_discover = test_transport1_listen_addr_discover, +}; + +const struct spdk_nvmf_transport * +spdk_nvmf_transport_get(const char *trname) +{ + if (!strcasecmp(trname, "test_transport1")) { + return &test_transport1; + } + + return NULL; +} + +void +spdk_nvmf_session_destruct(struct spdk_nvmf_session *session) +{ +} + +int +spdk_nvmf_session_poll(struct spdk_nvmf_session *session) +{ + return -1; +} + +static void +test_process_discovery_cmd(void) +{ + struct spdk_nvmf_request req = {}; + int ret; + /* random request length value for testing */ + int req_length = 122; + struct spdk_nvmf_conn req_conn = {}; + struct spdk_nvmf_session req_sess = {}; + struct spdk_nvme_ctrlr_data req_data = {}; + struct spdk_nvmf_discovery_log_page req_page = {}; + union nvmf_h2c_msg req_cmd = {}; + union nvmf_c2h_msg req_rsp = {}; + + req.conn = &req_conn; + req.cmd = &req_cmd; + req.rsp = &req_rsp; + + /* no request data check */ + ret = spdk_nvmf_process_discovery_cmd(&req); + CU_ASSERT_EQUAL(ret, SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE); + CU_ASSERT_EQUAL(req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_INVALID_FIELD); + + /* IDENTIFY opcode return value check */ + req.cmd->nvme_cmd.opc = SPDK_NVME_OPC_IDENTIFY; + req.cmd->nvme_cmd.cdw10 = SPDK_NVME_IDENTIFY_CTRLR; + req.conn->sess = &req_sess; + req.data = &req_data; + ret = spdk_nvmf_process_discovery_cmd(&req); + CU_ASSERT_EQUAL(req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_SUCCESS); + CU_ASSERT_EQUAL(ret, SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE); + + /* GET_LOG_PAGE opcode return value check */ + req.cmd->nvme_cmd.opc = SPDK_NVME_OPC_GET_LOG_PAGE; + req.cmd->nvme_cmd.cdw10 = SPDK_NVME_LOG_DISCOVERY; + req.data = &req_page; + req.length = req_length; + ret = spdk_nvmf_process_discovery_cmd(&req); + CU_ASSERT_EQUAL(req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_SUCCESS); + CU_ASSERT_EQUAL(ret, SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE); + req.cmd->nvme_cmd.cdw10 = 15; + ret = spdk_nvmf_process_discovery_cmd(&req); + CU_ASSERT_EQUAL(req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_INVALID_FIELD); + CU_ASSERT_EQUAL(ret, SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE); + + /* Invalid opcode return value check */ + req.cmd->nvme_cmd.opc = 100; + ret = spdk_nvmf_process_discovery_cmd(&req); + CU_ASSERT_EQUAL(req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_INVALID_OPCODE); + CU_ASSERT_EQUAL(ret, SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE); +} + +static bool +all_zero(const void *buf, size_t size) +{ + const uint8_t *b = buf; + + while (size--) { + if (*b != 0) { + return false; + } + b++; + } + + return true; +} + +static void +test_discovery_log(void) +{ + struct spdk_nvmf_subsystem *subsystem; + uint8_t buffer[8192]; + struct spdk_nvmf_discovery_log_page *disc_log; + struct spdk_nvmf_discovery_log_page_entry *entry; + struct spdk_nvmf_listen_addr *listen_addr; + + /* Reset discovery-related globals */ + g_nvmf_tgt.discovery_genctr = 0; + free(g_nvmf_tgt.discovery_log_page); + g_nvmf_tgt.discovery_log_page = NULL; + g_nvmf_tgt.discovery_log_page_size = 0; + + /* Add one subsystem and verify that the discovery log contains it */ + subsystem = spdk_nvmf_create_subsystem("nqn.2016-06.io.spdk:subsystem1", SPDK_NVMF_SUBTYPE_NVME, + NVMF_SUBSYSTEM_MODE_DIRECT, NULL, NULL, NULL); + SPDK_CU_ASSERT_FATAL(subsystem != NULL); + + listen_addr = spdk_nvmf_tgt_listen("test_transport1", "1234", "5678"); + SPDK_CU_ASSERT_FATAL(listen_addr != NULL); + + SPDK_CU_ASSERT_FATAL(spdk_nvmf_subsystem_add_listener(subsystem, listen_addr) == 0); + + /* Get only genctr (first field in the header) */ + memset(buffer, 0xCC, sizeof(buffer)); + disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; + spdk_nvmf_get_discovery_log_page(buffer, 0, sizeof(disc_log->genctr)); + CU_ASSERT(disc_log->genctr == 2); /* one added subsystem + one added listen address */ + + /* Get only the header, no entries */ + memset(buffer, 0xCC, sizeof(buffer)); + disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; + spdk_nvmf_get_discovery_log_page(buffer, 0, sizeof(*disc_log)); + CU_ASSERT(disc_log->genctr == 2); + CU_ASSERT(disc_log->numrec == 1); + + /* Offset 0, exact size match */ + memset(buffer, 0xCC, sizeof(buffer)); + disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; + spdk_nvmf_get_discovery_log_page(buffer, 0, sizeof(*disc_log) + sizeof(disc_log->entries[0])); + CU_ASSERT(disc_log->genctr != 0); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(disc_log->entries[0].trtype == 42); + + /* Offset 0, oversize buffer */ + memset(buffer, 0xCC, sizeof(buffer)); + disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; + spdk_nvmf_get_discovery_log_page(buffer, 0, sizeof(buffer)); + CU_ASSERT(disc_log->genctr != 0); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(disc_log->entries[0].trtype == 42); + CU_ASSERT(all_zero(buffer + sizeof(*disc_log) + sizeof(disc_log->entries[0]), + sizeof(buffer) - (sizeof(*disc_log) + sizeof(disc_log->entries[0])))); + + /* Get just the first entry, no header */ + memset(buffer, 0xCC, sizeof(buffer)); + entry = (struct spdk_nvmf_discovery_log_page_entry *)buffer; + spdk_nvmf_get_discovery_log_page(buffer, + offsetof(struct spdk_nvmf_discovery_log_page, entries[0]), + sizeof(*entry)); + CU_ASSERT(entry->trtype == 42); +} + +int main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + if (CU_initialize_registry() != CUE_SUCCESS) { + return CU_get_error(); + } + + suite = CU_add_suite("nvmf", NULL, NULL); + if (suite == NULL) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if ( + CU_add_test(suite, "process_discovery_command", test_process_discovery_cmd) == NULL || + CU_add_test(suite, "discovery_log", test_discovery_log) == NULL) { + CU_cleanup_registry(); + return CU_get_error(); + } + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + return num_failures; +} diff --git a/test/lib/nvmf/request/request_ut.c b/test/lib/nvmf/request/request_ut.c index a17fcd4b3..54106b3ed 100644 --- a/test/lib/nvmf/request/request_ut.c +++ b/test/lib/nvmf/request/request_ut.c @@ -135,58 +135,13 @@ spdk_nvmf_subsystem_host_allowed(struct spdk_nvmf_subsystem *subsystem, const ch return false; } -static void -test_nvmf_process_discovery_cmd(void) +spdk_nvmf_request_exec_status +spdk_nvmf_process_discovery_cmd(struct spdk_nvmf_request *req) { - struct spdk_nvmf_request req = {}; - int ret; - /* random request length value for testing */ - int req_length = 122; - struct spdk_nvmf_conn req_conn = {}; - struct spdk_nvmf_session req_sess = {}; - struct spdk_nvme_ctrlr_data req_data = {}; - struct spdk_nvmf_discovery_log_page req_page = {}; - union nvmf_h2c_msg req_cmd = {}; - union nvmf_c2h_msg req_rsp = {}; - - req.conn = &req_conn; - req.cmd = &req_cmd; - req.rsp = &req_rsp; - - /* no request data check */ - ret = nvmf_process_discovery_cmd(&req); - CU_ASSERT_EQUAL(ret, SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE); - CU_ASSERT_EQUAL(req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_INVALID_FIELD); - - /* IDENTIFY opcode return value check */ - req.cmd->nvme_cmd.opc = SPDK_NVME_OPC_IDENTIFY; - req.cmd->nvme_cmd.cdw10 = SPDK_NVME_IDENTIFY_CTRLR; - req.conn->sess = &req_sess; - req.data = &req_data; - ret = nvmf_process_discovery_cmd(&req); - CU_ASSERT_EQUAL(req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_SUCCESS); - CU_ASSERT_EQUAL(ret, SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE); - - /* GET_LOG_PAGE opcode return value check */ - req.cmd->nvme_cmd.opc = SPDK_NVME_OPC_GET_LOG_PAGE; - req.cmd->nvme_cmd.cdw10 = SPDK_NVME_LOG_DISCOVERY; - req.data = &req_page; - req.length = req_length; - ret = nvmf_process_discovery_cmd(&req); - CU_ASSERT_EQUAL(req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_SUCCESS); - CU_ASSERT_EQUAL(ret, SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE); - req.cmd->nvme_cmd.cdw10 = 15; - ret = nvmf_process_discovery_cmd(&req); - CU_ASSERT_EQUAL(req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_INVALID_FIELD); - CU_ASSERT_EQUAL(ret, SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE); - - /* Invalid opcode return value check */ - req.cmd->nvme_cmd.opc = 100; - ret = nvmf_process_discovery_cmd(&req); - CU_ASSERT_EQUAL(req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_INVALID_OPCODE); - CU_ASSERT_EQUAL(ret, SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE); + abort(); } + static void test_nvmf_process_fabrics_cmd(void) { @@ -224,7 +179,6 @@ int main(int argc, char **argv) } if ( - CU_add_test(suite, "nvmf_process_discovery_command", test_nvmf_process_discovery_cmd) == NULL || CU_add_test(suite, "nvmf_process_fabrics_command", test_nvmf_process_fabrics_cmd) == NULL) { CU_cleanup_registry(); return CU_get_error(); diff --git a/test/lib/nvmf/subsystem/subsystem_ut.c b/test/lib/nvmf/subsystem/subsystem_ut.c index 45083deac..75c49a65c 100644 --- a/test/lib/nvmf/subsystem/subsystem_ut.c +++ b/test/lib/nvmf/subsystem/subsystem_ut.c @@ -203,86 +203,6 @@ nvmf_test_find_subsystem(void) CU_ASSERT_PTR_NULL(nvmf_find_subsystem("fake")); } -static bool -all_zero(const void *buf, size_t size) -{ - const uint8_t *b = buf; - - while (size--) { - if (*b != 0) { - return false; - } - b++; - } - - return true; -} - -static void -test_discovery_log(void) -{ - struct spdk_nvmf_subsystem *subsystem; - uint8_t buffer[8192]; - struct spdk_nvmf_discovery_log_page *disc_log; - struct spdk_nvmf_discovery_log_page_entry *entry; - struct spdk_nvmf_listen_addr *listen_addr; - - /* Reset discovery-related globals */ - g_nvmf_tgt.discovery_genctr = 0; - free(g_nvmf_tgt.discovery_log_page); - g_nvmf_tgt.discovery_log_page = NULL; - g_nvmf_tgt.discovery_log_page_size = 0; - - /* Add one subsystem and verify that the discovery log contains it */ - subsystem = spdk_nvmf_create_subsystem("nqn.2016-06.io.spdk:subsystem1", SPDK_NVMF_SUBTYPE_NVME, - NVMF_SUBSYSTEM_MODE_DIRECT, NULL, NULL, NULL); - SPDK_CU_ASSERT_FATAL(subsystem != NULL); - - listen_addr = spdk_nvmf_tgt_listen("test_transport1", "1234", "5678"); - SPDK_CU_ASSERT_FATAL(listen_addr != NULL); - - SPDK_CU_ASSERT_FATAL(spdk_nvmf_subsystem_add_listener(subsystem, listen_addr) == 0); - - /* Get only genctr (first field in the header) */ - memset(buffer, 0xCC, sizeof(buffer)); - disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; - spdk_nvmf_get_discovery_log_page(buffer, 0, sizeof(disc_log->genctr)); - CU_ASSERT(disc_log->genctr == 2); /* one added subsystem + one added listen address */ - - /* Get only the header, no entries */ - memset(buffer, 0xCC, sizeof(buffer)); - disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; - spdk_nvmf_get_discovery_log_page(buffer, 0, sizeof(*disc_log)); - CU_ASSERT(disc_log->genctr == 2); - CU_ASSERT(disc_log->numrec == 1); - - /* Offset 0, exact size match */ - memset(buffer, 0xCC, sizeof(buffer)); - disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; - spdk_nvmf_get_discovery_log_page(buffer, 0, sizeof(*disc_log) + sizeof(disc_log->entries[0])); - CU_ASSERT(disc_log->genctr != 0); - CU_ASSERT(disc_log->numrec == 1); - CU_ASSERT(disc_log->entries[0].trtype == 42); - - /* Offset 0, oversize buffer */ - memset(buffer, 0xCC, sizeof(buffer)); - disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; - spdk_nvmf_get_discovery_log_page(buffer, 0, sizeof(buffer)); - CU_ASSERT(disc_log->genctr != 0); - CU_ASSERT(disc_log->numrec == 1); - CU_ASSERT(disc_log->entries[0].trtype == 42); - CU_ASSERT(all_zero(buffer + sizeof(*disc_log) + sizeof(disc_log->entries[0]), - sizeof(buffer) - (sizeof(*disc_log) + sizeof(disc_log->entries[0])))); - - /* Get just the first entry, no header */ - memset(buffer, 0xCC, sizeof(buffer)); - entry = (struct spdk_nvmf_discovery_log_page_entry *)buffer; - spdk_nvmf_get_discovery_log_page(buffer, - offsetof(struct spdk_nvmf_discovery_log_page, entries[0]), - sizeof(*entry)); - CU_ASSERT(entry->trtype == 42); -} - int main(int argc, char **argv) { CU_pSuite suite = NULL; @@ -300,8 +220,7 @@ int main(int argc, char **argv) if ( CU_add_test(suite, "create_subsystem", nvmf_test_create_subsystem) == NULL || - CU_add_test(suite, "find_subsystem", nvmf_test_find_subsystem) == NULL || - CU_add_test(suite, "discovery_log", test_discovery_log) == NULL) { + CU_add_test(suite, "find_subsystem", nvmf_test_find_subsystem) == NULL) { CU_cleanup_registry(); return CU_get_error(); } diff --git a/unittest.sh b/unittest.sh index 936bfeec1..0fcd1683b 100755 --- a/unittest.sh +++ b/unittest.sh @@ -24,6 +24,7 @@ $valgrind test/lib/jsonrpc/server/jsonrpc_server_ut $valgrind test/lib/log/log_ut +$valgrind test/lib/nvmf/discovery/discovery_ut $valgrind test/lib/nvmf/request/request_ut $valgrind test/lib/nvmf/session/session_ut $valgrind test/lib/nvmf/subsystem/subsystem_ut