From 3d8904c66b65caa9f301227ca4d736582ab364d8 Mon Sep 17 00:00:00 2001 From: Alexey Marchuk Date: Thu, 12 Aug 2021 19:01:39 +0300 Subject: [PATCH] nvmf: Add discovery filtering rules SPDK nvmf target reports all listeners on all subsystems in discovery pages, kernel target reports only subsystems listening on a port where discovery command is received. NVMEoF specification allows to specify any addresses/ transport types. Ch 5: The set of Discovery Log entries should include all applicable addresses on the same fabric as the Discovery Service and may include addresses on other fabrics. To align SPDK and kernel targets behaviour, add filtering rules to allow flexible configuration of what should be listed in discovery log page entries. Fixes #2082 Signed-off-by: Alexey Marchuk Change-Id: Ie981edebb29206793d3310940034dcbb22c52441 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/9185 Reviewed-by: Jim Harris Reviewed-by: Ben Walker Tested-by: SPDK CI Jenkins Community-CI: Broadcom CI Community-CI: Mellanox Build Bot --- CHANGELOG.md | 3 + doc/jsonrpc.md | 1 + include/spdk/nvmf.h | 15 + lib/nvmf/ctrlr.c | 11 +- lib/nvmf/ctrlr_discovery.c | 58 ++- lib/nvmf/nvmf.c | 6 + lib/nvmf/nvmf_internal.h | 8 +- lib/nvmf/nvmf_rpc.c | 63 +++- module/event/subsystems/nvmf/event_nvmf.h | 2 + module/event/subsystems/nvmf/nvmf_rpc.c | 54 ++- module/event/subsystems/nvmf/nvmf_tgt.c | 27 ++ scripts/rpc.py | 5 +- scripts/rpc/nvmf.py | 13 +- test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c | 2 +- .../ctrlr_discovery.c/ctrlr_discovery_ut.c | 347 ++++++++++++++++-- test/unit/lib/nvmf/tcp.c/tcp_ut.c | 3 +- 16 files changed, 576 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0bcf65e7a..8f26be6550 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ## v21.10 +Structure `spdk_nvmf_target_opts` has been extended with new member `discovery_filter` which allows to specify +filtering rules applied during discovery log generation. Refer to `enum spdk_nvmf_tgt_discovery_filter` for more info. + ### bdev New API `spdk_bdev_get_memory_domains` has been added, it allows to get SPDK memory domains used by bdev. diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index a3525251ef..59d61788ff 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -6736,6 +6736,7 @@ Name | Optional | Type | Description acceptor_poll_rate | Optional | number | Polling interval of the acceptor for incoming connections (microseconds) admin_cmd_passthru | Optional | object | Admin command passthru configuration poll_groups_mask | Optional | string | Set cpumask for NVMf poll groups +discovery_filter | Optional | string | Set discovery filter, possible values are: `match_any` (default) or comma separated values: `transport`, `address`, `svcid` #### admin_cmd_passthru {#spdk_nvmf_admin_passthru_conf} diff --git a/include/spdk/nvmf.h b/include/spdk/nvmf.h index 6f7987cc39..3bf44c47f6 100644 --- a/include/spdk/nvmf.h +++ b/include/spdk/nvmf.h @@ -67,11 +67,26 @@ struct spdk_json_write_ctx; struct spdk_json_val; struct spdk_nvmf_transport; +/** + * Specify filter rules which are applied during discovery log generation. + */ +enum spdk_nvmf_tgt_discovery_filter { + /** Log all listeners in discovery log page */ + SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY = 0, + /** Only log listeners with the same transport type on which the DISCOVERY command was received */ + SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE = 1u << 0u, + /** Only log listeners with the same transport address on which the DISCOVERY command was received */ + SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS = 1u << 1u, + /** Only log listeners with the same transport svcid on which the DISCOVERY command was received */ + SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID = 1u << 2u +}; + struct spdk_nvmf_target_opts { char name[NVMF_TGT_NAME_MAX_LENGTH]; uint32_t max_subsystems; uint32_t acceptor_poll_rate; uint16_t crdt[3]; + enum spdk_nvmf_tgt_discovery_filter discovery_filter; }; struct spdk_nvmf_transport_opts { diff --git a/lib/nvmf/ctrlr.c b/lib/nvmf/ctrlr.c index e40db404b7..154a1b2e3a 100644 --- a/lib/nvmf/ctrlr.c +++ b/lib/nvmf/ctrlr.c @@ -2271,6 +2271,7 @@ nvmf_ctrlr_get_log_page(struct spdk_nvmf_request *req) struct spdk_nvmf_subsystem *subsystem = ctrlr->subsys; struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl; + struct spdk_nvme_transport_id cmd_source_trid; uint64_t offset, len; uint32_t rae, numdl, numdu; uint8_t lid; @@ -2309,8 +2310,14 @@ nvmf_ctrlr_get_log_page(struct spdk_nvmf_request *req) if (subsystem->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY) { switch (lid) { case SPDK_NVME_LOG_DISCOVERY: - nvmf_get_discovery_log_page(subsystem->tgt, ctrlr->hostnqn, req->iov, req->iovcnt, offset, - len); + if (spdk_nvmf_qpair_get_listen_trid(req->qpair, &cmd_source_trid)) { + SPDK_ERRLOG("Failed to get LOG_DISCOVERY source trid\n"); + response->status.sct = SPDK_NVME_SCT_GENERIC; + response->status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } + nvmf_get_discovery_log_page(subsystem->tgt, ctrlr->hostnqn, req->iov, req->iovcnt, + offset, len, &cmd_source_trid); if (!rae) { nvmf_ctrlr_unmask_aen(ctrlr, SPDK_NVME_ASYNC_EVENT_DISCOVERY_LOG_CHANGE_MASK_BIT); } diff --git a/lib/nvmf/ctrlr_discovery.c b/lib/nvmf/ctrlr_discovery.c index a245381655..331d4ab0c9 100644 --- a/lib/nvmf/ctrlr_discovery.c +++ b/lib/nvmf/ctrlr_discovery.c @@ -3,6 +3,7 @@ * * Copyright (c) Intel Corporation. * All rights reserved. + * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -43,6 +44,7 @@ #include "spdk/string.h" #include "spdk/trace.h" #include "spdk/nvmf_spec.h" +#include "spdk_internal/assert.h" #include "spdk/log.h" @@ -65,8 +67,34 @@ nvmf_update_discovery_log(struct spdk_nvmf_tgt *tgt, const char *hostnqn) } } +static bool +nvmf_discovery_compare_trtype(const struct spdk_nvme_transport_id *trid1, + const struct spdk_nvme_transport_id *trid2) +{ + if (trid1->trtype == SPDK_NVME_TRANSPORT_CUSTOM) { + return strcasecmp(trid1->trstring, trid2->trstring) == 0; + } else { + return trid1->trtype == trid2->trtype; + } +} + +static bool +nvmf_discovery_compare_tr_addr(const struct spdk_nvme_transport_id *trid1, + const struct spdk_nvme_transport_id *trid2) +{ + return trid1->adrfam == trid2->adrfam && strcasecmp(trid1->traddr, trid2->traddr) == 0; +} + +static bool +nvmf_discovery_compare_tr_svcid(const struct spdk_nvme_transport_id *trid1, + const struct spdk_nvme_transport_id *trid2) +{ + return strcasecmp(trid1->trsvcid, trid2->trsvcid) == 0; +} + static struct spdk_nvmf_discovery_log_page * -nvmf_generate_discovery_log(struct spdk_nvmf_tgt *tgt, const char *hostnqn, size_t *log_page_size) +nvmf_generate_discovery_log(struct spdk_nvmf_tgt *tgt, const char *hostnqn, size_t *log_page_size, + struct spdk_nvme_transport_id *cmd_source_trid) { uint64_t numrec = 0; struct spdk_nvmf_subsystem *subsystem; @@ -104,6 +132,29 @@ nvmf_generate_discovery_log(struct spdk_nvmf_tgt *tgt, const char *hostnqn, size for (listener = spdk_nvmf_subsystem_get_first_listener(subsystem); listener != NULL; listener = spdk_nvmf_subsystem_get_next_listener(subsystem, listener)) { + + if ((tgt->discovery_filter & SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE) != 0 && + !nvmf_discovery_compare_trtype(listener->trid, cmd_source_trid)) { + SPDK_DEBUGLOG(nvmf, "ignore listener type %d (%s) due to type mismatch\n", + listener->trid->trtype, listener->trid->trstring); + continue; + } + if ((tgt->discovery_filter & SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS) != 0 && + !nvmf_discovery_compare_tr_addr(listener->trid, cmd_source_trid)) { + SPDK_DEBUGLOG(nvmf, "ignore listener addr %s due to addr mismatch\n", + listener->trid->traddr); + continue; + } + if ((tgt->discovery_filter & SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID) != 0 && + !nvmf_discovery_compare_tr_svcid(listener->trid, cmd_source_trid)) { + SPDK_DEBUGLOG(nvmf, "ignore listener svcid %s due to svcid mismatch\n", + listener->trid->trsvcid); + continue; + } + + SPDK_DEBUGLOG(nvmf, "listener %s:%s trtype %s\n", listener->trid->traddr, listener->trid->trsvcid, + listener->trid->trstring); + size_t new_size = cur_size + sizeof(*entry); void *new_log_page = realloc(disc_log, new_size); @@ -138,7 +189,8 @@ nvmf_generate_discovery_log(struct spdk_nvmf_tgt *tgt, const char *hostnqn, size void nvmf_get_discovery_log_page(struct spdk_nvmf_tgt *tgt, const char *hostnqn, struct iovec *iov, - uint32_t iovcnt, uint64_t offset, uint32_t length) + uint32_t iovcnt, uint64_t offset, uint32_t length, + struct spdk_nvme_transport_id *cmd_source_trid) { size_t copy_len = 0; size_t zero_len = 0; @@ -146,7 +198,7 @@ nvmf_get_discovery_log_page(struct spdk_nvmf_tgt *tgt, const char *hostnqn, stru size_t log_page_size = 0; struct spdk_nvmf_discovery_log_page *discovery_log_page; - discovery_log_page = nvmf_generate_discovery_log(tgt, hostnqn, &log_page_size); + discovery_log_page = nvmf_generate_discovery_log(tgt, hostnqn, &log_page_size, cmd_source_trid); /* Copy the valid part of the discovery log page, if any */ if (discovery_log_page) { diff --git a/lib/nvmf/nvmf.c b/lib/nvmf/nvmf.c index 7af3a9da18..337803a7d3 100644 --- a/lib/nvmf/nvmf.c +++ b/lib/nvmf/nvmf.c @@ -303,6 +303,12 @@ spdk_nvmf_tgt_create(struct spdk_nvmf_target_opts *opts) tgt->crdt[2] = opts->crdt[2]; } + if (!opts) { + tgt->discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY; + } else { + tgt->discovery_filter = opts->discovery_filter; + } + tgt->discovery_genctr = 0; TAILQ_INIT(&tgt->transports); TAILQ_INIT(&tgt->poll_groups); diff --git a/lib/nvmf/nvmf_internal.h b/lib/nvmf/nvmf_internal.h index 22b679f59b..37dd389d19 100644 --- a/lib/nvmf/nvmf_internal.h +++ b/lib/nvmf/nvmf_internal.h @@ -76,6 +76,8 @@ struct spdk_nvmf_tgt { uint32_t max_subsystems; + enum spdk_nvmf_tgt_discovery_filter discovery_filter; + /* Array of subsystem pointers of size max_subsystems indexed by sid */ struct spdk_nvmf_subsystem **subsystems; @@ -350,9 +352,9 @@ void nvmf_poll_group_resume_subsystem(struct spdk_nvmf_poll_group *group, struct spdk_nvmf_subsystem *subsystem, spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg); void nvmf_update_discovery_log(struct spdk_nvmf_tgt *tgt, const char *hostnqn); -void nvmf_get_discovery_log_page(struct spdk_nvmf_tgt *tgt, const char *hostnqn, - struct iovec *iov, - uint32_t iovcnt, uint64_t offset, uint32_t length); +void nvmf_get_discovery_log_page(struct spdk_nvmf_tgt *tgt, const char *hostnqn, struct iovec *iov, + uint32_t iovcnt, uint64_t offset, uint32_t length, + struct spdk_nvme_transport_id *cmd_source_trid); void nvmf_ctrlr_destruct(struct spdk_nvmf_ctrlr *ctrlr); int nvmf_ctrlr_process_admin_cmd(struct spdk_nvmf_request *req); diff --git a/lib/nvmf/nvmf_rpc.c b/lib/nvmf/nvmf_rpc.c index 532521fa83..7ab557df32 100644 --- a/lib/nvmf/nvmf_rpc.c +++ b/lib/nvmf/nvmf_rpc.c @@ -1657,11 +1657,63 @@ SPDK_RPC_REGISTER("nvmf_subsystem_allow_any_host", rpc_nvmf_subsystem_allow_any_ struct nvmf_rpc_target_ctx { char *name; uint32_t max_subsystems; + char *discovery_filter; }; +static int +decode_discovery_filter(const struct spdk_json_val *val, void *out) +{ + enum spdk_nvmf_tgt_discovery_filter *_filter = (enum spdk_nvmf_tgt_discovery_filter *)out; + enum spdk_nvmf_tgt_discovery_filter filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY; + char *tokens = spdk_json_strdup(val); + char *tok; + int rc = -EINVAL; + bool all_specified = false; + + if (!tokens) { + return -ENOMEM; + } + + tok = strtok(tokens, ","); + while (tok) { + if (strncmp(tok, "match_any", 9) == 0) { + if (filter != SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY) { + goto out; + } + filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY; + all_specified = true; + } else { + if (all_specified) { + goto out; + } + if (strncmp(tok, "transport", 9) == 0) { + filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE; + } else if (strncmp(tok, "address", 7) == 0) { + filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS; + } else if (strncmp(tok, "svcid", 5) == 0) { + filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID; + } else { + SPDK_ERRLOG("Invalid value %s\n", tok); + goto out; + } + } + + tok = strtok(NULL, ","); + } + + rc = 0; + *_filter = filter; + +out: + free(tokens); + + return rc; +} + static const struct spdk_json_object_decoder nvmf_rpc_create_target_decoder[] = { {"name", offsetof(struct nvmf_rpc_target_ctx, name), spdk_json_decode_string}, {"max_subsystems", offsetof(struct nvmf_rpc_target_ctx, max_subsystems), spdk_json_decode_uint32, true}, + {"discovery_filter", offsetof(struct nvmf_rpc_target_ctx, discovery_filter), decode_discovery_filter, true} }; static void @@ -1679,8 +1731,7 @@ rpc_nvmf_create_target(struct spdk_jsonrpc_request *request, &ctx)) { SPDK_ERRLOG("spdk_json_decode_object failed\n"); spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); - free(ctx.name); - return; + goto out; } snprintf(opts.name, NVMF_TGT_NAME_MAX_LENGTH, "%s", ctx.name); @@ -1689,8 +1740,7 @@ rpc_nvmf_create_target(struct spdk_jsonrpc_request *request, if (spdk_nvmf_get_tgt(opts.name) != NULL) { spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Target already exists."); - free(ctx.name); - return; + goto out; } tgt = spdk_nvmf_tgt_create(&opts); @@ -1698,14 +1748,15 @@ rpc_nvmf_create_target(struct spdk_jsonrpc_request *request, if (tgt == NULL) { spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Unable to create the requested target."); - free(ctx.name); - return; + goto out; } w = spdk_jsonrpc_begin_result(request); spdk_json_write_string(w, spdk_nvmf_tgt_get_name(tgt)); spdk_jsonrpc_end_result(request, w); +out: free(ctx.name); + free(ctx.discovery_filter); } /* private */ SPDK_RPC_REGISTER("nvmf_create_target", rpc_nvmf_create_target, SPDK_RPC_RUNTIME); diff --git a/module/event/subsystems/nvmf/event_nvmf.h b/module/event/subsystems/nvmf/event_nvmf.h index 9c796f9bbd..82b81627e6 100644 --- a/module/event/subsystems/nvmf/event_nvmf.h +++ b/module/event/subsystems/nvmf/event_nvmf.h @@ -3,6 +3,7 @@ * * Copyright (c) Intel Corporation. * All rights reserved. + * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -52,6 +53,7 @@ struct spdk_nvmf_tgt_conf { uint32_t acceptor_poll_rate; uint32_t conn_sched; /* Deprecated. */ struct spdk_nvmf_admin_passthru_conf admin_passthru; + enum spdk_nvmf_tgt_discovery_filter discovery_filter; }; extern struct spdk_nvmf_tgt_conf g_spdk_nvmf_tgt_conf; diff --git a/module/event/subsystems/nvmf/nvmf_rpc.c b/module/event/subsystems/nvmf/nvmf_rpc.c index c18efeb0f4..f138dc689e 100644 --- a/module/event/subsystems/nvmf/nvmf_rpc.c +++ b/module/event/subsystems/nvmf/nvmf_rpc.c @@ -3,6 +3,7 @@ * * Copyright (c) Intel Corporation. All rights reserved. * Copyright (c) 2018-2019 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -99,6 +100,56 @@ static int decode_admin_passthru(const struct spdk_json_val *val, void *out) return 0; } +static int +decode_discovery_filter(const struct spdk_json_val *val, void *out) +{ + enum spdk_nvmf_tgt_discovery_filter *_filter = (enum spdk_nvmf_tgt_discovery_filter *)out; + enum spdk_nvmf_tgt_discovery_filter filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY; + char *tokens = spdk_json_strdup(val); + char *tok; + int rc = -EINVAL; + bool all_specified = false; + + if (!tokens) { + return -ENOMEM; + } + + tok = strtok(tokens, ","); + while (tok) { + if (strncmp(tok, "match_any", 9) == 0) { + if (filter != SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY) { + goto out; + } + filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY; + all_specified = true; + } else { + if (all_specified) { + goto out; + } + if (strncmp(tok, "transport", 9) == 0) { + filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE; + } else if (strncmp(tok, "address", 7) == 0) { + filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS; + } else if (strncmp(tok, "svcid", 5) == 0) { + filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID; + } else { + SPDK_ERRLOG("Invalid value %s\n", tok); + goto out; + } + } + + tok = strtok(NULL, ","); + } + + rc = 0; + *_filter = filter; + +out: + free(tokens); + + return rc; +} + static int nvmf_is_subset_of_env_core_mask(const struct spdk_cpuset *set) { @@ -149,7 +200,8 @@ static const struct spdk_json_object_decoder nvmf_rpc_subsystem_tgt_conf_decoder {"acceptor_poll_rate", offsetof(struct spdk_nvmf_tgt_conf, acceptor_poll_rate), spdk_json_decode_uint32, true}, {"conn_sched", offsetof(struct spdk_nvmf_tgt_conf, conn_sched), decode_conn_sched, true}, {"admin_cmd_passthru", offsetof(struct spdk_nvmf_tgt_conf, admin_passthru), decode_admin_passthru, true}, - {"poll_groups_mask", 0, nvmf_decode_poll_groups_mask, true} + {"poll_groups_mask", 0, nvmf_decode_poll_groups_mask, true}, + {"discovery_filter", offsetof(struct spdk_nvmf_tgt_conf, discovery_filter), decode_discovery_filter, true} }; static void diff --git a/module/event/subsystems/nvmf/nvmf_tgt.c b/module/event/subsystems/nvmf/nvmf_tgt.c index 321ab765be..29c1a92ce0 100644 --- a/module/event/subsystems/nvmf/nvmf_tgt.c +++ b/module/event/subsystems/nvmf/nvmf_tgt.c @@ -307,6 +307,7 @@ nvmf_tgt_create_target(void) opts.crdt[0] = g_spdk_nvmf_tgt_crdt[0]; opts.crdt[1] = g_spdk_nvmf_tgt_crdt[1]; opts.crdt[2] = g_spdk_nvmf_tgt_crdt[2]; + opts.discovery_filter = g_spdk_nvmf_tgt_conf.discovery_filter; g_spdk_nvmf_tgt = spdk_nvmf_tgt_create(&opts); if (!g_spdk_nvmf_tgt) { SPDK_ERRLOG("spdk_nvmf_tgt_create() failed\n"); @@ -485,6 +486,31 @@ nvmf_subsystem_init(void) nvmf_tgt_advance_state(); } +static void +nvmf_subsystem_dump_discover_filter(struct spdk_json_write_ctx *w) +{ + static char const *const answers[] = { + "match_any", + "transport", + "address", + "transport,address", + "svcid", + "transport,svcid", + "address,svcid", + "transport,address,svcid" + }; + + if ((g_spdk_nvmf_tgt_conf.discovery_filter & ~(SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE | + SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS | + SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID)) != 0) { + SPDK_ERRLOG("Incorrect discovery filter %d\n", g_spdk_nvmf_tgt_conf.discovery_filter); + assert(0); + return; + } + + spdk_json_write_named_string(w, "discovery_filter", answers[g_spdk_nvmf_tgt_conf.discovery_filter]); +} + static void nvmf_subsystem_write_config_json(struct spdk_json_write_ctx *w) { @@ -495,6 +521,7 @@ nvmf_subsystem_write_config_json(struct spdk_json_write_ctx *w) spdk_json_write_named_object_begin(w, "params"); spdk_json_write_named_uint32(w, "acceptor_poll_rate", g_spdk_nvmf_tgt_conf.acceptor_poll_rate); + nvmf_subsystem_dump_discover_filter(w); spdk_json_write_named_object_begin(w, "admin_cmd_passthru"); spdk_json_write_named_bool(w, "identify_ctrlr", g_spdk_nvmf_tgt_conf.admin_passthru.identify_ctrlr); diff --git a/scripts/rpc.py b/scripts/rpc.py index e456c026c7..bc394cf13f 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -1908,7 +1908,8 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse acceptor_poll_rate=args.acceptor_poll_rate, conn_sched=args.conn_sched, passthru_identify_ctrlr=args.passthru_identify_ctrlr, - poll_groups_mask=args.poll_groups_mask) + poll_groups_mask=args.poll_groups_mask, + discovery_filter=args.discovery_filter) p = subparsers.add_parser('nvmf_set_config', aliases=['set_nvmf_target_config'], help='Set NVMf target config') @@ -1917,6 +1918,8 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p.add_argument('-i', '--passthru-identify-ctrlr', help="""Passthrough fields like serial number and model number when the controller has a single namespace that is an NVMe bdev""", action='store_true') p.add_argument('-m', '--poll-groups-mask', help='Set cpumask for NVMf poll groups (optional)', type=str) + p.add_argument('-d', '--discovery-filter', help="""Set discovery filter (optional), possible values are: `match_any` (default) or + comma separated values: `transport`, `address`, `svcid`""", type=str) p.set_defaults(func=nvmf_set_config) def nvmf_create_transport(args): diff --git a/scripts/rpc/nvmf.py b/scripts/rpc/nvmf.py index 4f1dd73587..915c04b4b6 100644 --- a/scripts/rpc/nvmf.py +++ b/scripts/rpc/nvmf.py @@ -24,12 +24,15 @@ def nvmf_set_config(client, acceptor_poll_rate=None, conn_sched=None, passthru_identify_ctrlr=None, - poll_groups_mask=None): + poll_groups_mask=None, + discovery_filter=None): """Set NVMe-oF target subsystem configuration. Args: acceptor_poll_rate: Acceptor poll period in microseconds (optional) conn_sched: (Deprecated) Ignored + discovery_filter: Set discovery filter (optional), possible values are: `match_any` (default) or + comma separated values: `transport`, `address`, `svcid` Returns: True or False @@ -46,18 +49,23 @@ def nvmf_set_config(client, params['admin_cmd_passthru'] = admin_cmd_passthru if poll_groups_mask: params['poll_groups_mask'] = poll_groups_mask + if discovery_filter: + params['discovery_filter'] = discovery_filter return client.call('nvmf_set_config', params) def nvmf_create_target(client, name, - max_subsystems=0): + max_subsystems=0, + discovery_filter="match_any"): """Create a new NVMe-oF Target. Args: name: Must be unique within the application max_subsystems: Maximum number of NVMe-oF subsystems (e.g. 1024). default: 0 (Uses SPDK_NVMF_DEFAULT_MAX_SUBSYSTEMS). + discovery_filter: Set discovery filter (optional), possible values are: `match_any` (default) or + comma separated values: `transport`, `address`, `svcid` Returns: The name of the new target. @@ -66,6 +74,7 @@ def nvmf_create_target(client, params['name'] = name params['max_subsystems'] = max_subsystems + params['discovery_filter'] = discovery_filter return client.call("nvmf_create_target", params) diff --git a/test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c b/test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c index d942ace9e6..16a15b14b0 100644 --- a/test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c +++ b/test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c @@ -104,7 +104,7 @@ DEFINE_STUB(nvmf_ctrlr_write_zeroes_supported, DEFINE_STUB_V(nvmf_get_discovery_log_page, (struct spdk_nvmf_tgt *tgt, const char *hostnqn, struct iovec *iov, - uint32_t iovcnt, uint64_t offset, uint32_t length)); + uint32_t iovcnt, uint64_t offset, uint32_t length, struct spdk_nvme_transport_id *cmd_src_trid)); DEFINE_STUB(spdk_nvmf_qpair_get_listen_trid, int, diff --git a/test/unit/lib/nvmf/ctrlr_discovery.c/ctrlr_discovery_ut.c b/test/unit/lib/nvmf/ctrlr_discovery.c/ctrlr_discovery_ut.c index 9ca17aee16..095bc09438 100644 --- a/test/unit/lib/nvmf/ctrlr_discovery.c/ctrlr_discovery_ut.c +++ b/test/unit/lib/nvmf/ctrlr_discovery.c/ctrlr_discovery_ut.c @@ -118,6 +118,14 @@ spdk_bdev_get_uuid(const struct spdk_bdev *bdev) return &bdev->uuid; } +int +spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1, + const struct spdk_nvme_transport_id *trid2) +{ + return !(trid1->trtype == trid2->trtype && strcasecmp(trid1->traddr, trid2->traddr) == 0 && + strcasecmp(trid1->trsvcid, trid2->trsvcid) == 0); +} + int spdk_nvmf_transport_listen(struct spdk_nvmf_transport *transport, const struct spdk_nvme_transport_id *trid, struct spdk_nvmf_listen_opts *opts) @@ -131,18 +139,37 @@ struct spdk_nvmf_listener * nvmf_transport_find_listener(struct spdk_nvmf_transport *transport, const struct spdk_nvme_transport_id *trid) { - return &g_listener; + struct spdk_nvmf_listener *listener; + + if (TAILQ_EMPTY(&transport->listeners)) { + return &g_listener; + } + + TAILQ_FOREACH(listener, &transport->listeners, link) { + if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) { + return listener; + } + } + + return NULL; } void nvmf_transport_listener_discover(struct spdk_nvmf_transport *transport, struct spdk_nvme_transport_id *trid, struct spdk_nvmf_discovery_log_page_entry *entry) +{ + transport->ops->listener_discover(transport, trid, entry); +} + +static void +test_dummy_listener_discover(struct spdk_nvmf_transport *transport, + struct spdk_nvme_transport_id *trid, struct spdk_nvmf_discovery_log_page_entry *entry) { entry->trtype = 42; } -struct spdk_nvmf_transport_ops g_transport_ops = {}; +struct spdk_nvmf_transport_ops g_transport_ops = { .listener_discover = test_dummy_listener_discover }; static struct spdk_nvmf_transport g_transport = { .ops = &g_transport_ops @@ -165,9 +192,11 @@ spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt *tgt, const char *subnqn) return NULL; } +DEFINE_RETURN_MOCK(spdk_nvmf_tgt_get_transport, struct spdk_nvmf_transport *); struct spdk_nvmf_transport * spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt, const char *transport_name) { + HANDLE_RETURN_MOCK(spdk_nvmf_tgt_get_transport); return &g_transport; } @@ -188,13 +217,6 @@ spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const return 0; } -int -spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1, - const struct spdk_nvme_transport_id *trid2) -{ - return 0; -} - void nvmf_ctrlr_ns_changed(struct spdk_nvmf_ctrlr *ctrlr, uint32_t nsid) { @@ -248,6 +270,26 @@ _subsystem_add_listen_done(void *cb_arg, int status) SPDK_CU_ASSERT_FATAL(status == 0); } +static void +test_gen_trid(struct spdk_nvme_transport_id *trid, enum spdk_nvme_transport_type trtype, + enum spdk_nvmf_adrfam adrfam, const char *tradd, const char *trsvcid) +{ + snprintf(trid->traddr, sizeof(trid->traddr), "%s", tradd); + snprintf(trid->trsvcid, sizeof(trid->trsvcid), "%s", trsvcid); + trid->adrfam = adrfam; + trid->trtype = trtype; + switch (trtype) { + case SPDK_NVME_TRANSPORT_RDMA: + snprintf(trid->trstring, SPDK_NVMF_TRSTRING_MAX_LEN, "%s", SPDK_NVME_TRANSPORT_NAME_RDMA); + break; + case SPDK_NVME_TRANSPORT_TCP: + snprintf(trid->trstring, SPDK_NVMF_TRSTRING_MAX_LEN, "%s", SPDK_NVME_TRANSPORT_NAME_TCP); + break; + default: + SPDK_CU_ASSERT_FATAL(0 && "not supported by test"); + } +} + static void test_discovery_log(void) { @@ -273,24 +315,22 @@ test_discovery_log(void) subsystem->flags.allow_any_host = true; SPDK_CU_ASSERT_FATAL(subsystem != NULL); - trid.trtype = SPDK_NVME_TRANSPORT_RDMA; - trid.adrfam = SPDK_NVMF_ADRFAM_IPV4; - snprintf(trid.traddr, sizeof(trid.traddr), "1234"); - snprintf(trid.trsvcid, sizeof(trid.trsvcid), "5678"); + test_gen_trid(&trid, SPDK_NVME_TRANSPORT_RDMA, SPDK_NVMF_ADRFAM_IPV4, "1234", "5678"); spdk_nvmf_subsystem_add_listener(subsystem, &trid, _subsystem_add_listen_done, NULL); subsystem->state = SPDK_NVMF_SUBSYSTEM_ACTIVE; /* Get only genctr (first field in the header) */ memset(buffer, 0xCC, sizeof(buffer)); disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; - nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, - sizeof(disc_log->genctr)); + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, sizeof(disc_log->genctr), + &trid); CU_ASSERT(disc_log->genctr == 2); /* one added subsystem and listener */ /* Get only the header, no entries */ memset(buffer, 0xCC, sizeof(buffer)); disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; - nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, sizeof(*disc_log)); + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, sizeof(*disc_log), + &trid); CU_ASSERT(disc_log->genctr == 2); CU_ASSERT(disc_log->numrec == 1); @@ -298,7 +338,7 @@ test_discovery_log(void) memset(buffer, 0xCC, sizeof(buffer)); disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, - sizeof(*disc_log) + sizeof(disc_log->entries[0])); + sizeof(*disc_log) + sizeof(disc_log->entries[0]), &trid); CU_ASSERT(disc_log->genctr != 0); CU_ASSERT(disc_log->numrec == 1); CU_ASSERT(disc_log->entries[0].trtype == 42); @@ -306,7 +346,7 @@ test_discovery_log(void) /* Offset 0, oversize buffer */ memset(buffer, 0xCC, sizeof(buffer)); disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; - nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, sizeof(buffer)); + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, sizeof(buffer), &trid); CU_ASSERT(disc_log->genctr != 0); CU_ASSERT(disc_log->numrec == 1); CU_ASSERT(disc_log->entries[0].trtype == 42); @@ -316,10 +356,8 @@ test_discovery_log(void) /* Get just the first entry, no header */ memset(buffer, 0xCC, sizeof(buffer)); entry = (struct spdk_nvmf_discovery_log_page_entry *)buffer; - nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, - 1, - offsetof(struct spdk_nvmf_discovery_log_page, entries[0]), - sizeof(*entry)); + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, + offsetof(struct spdk_nvmf_discovery_log_page, entries[0]), sizeof(*entry), &trid); CU_ASSERT(entry->trtype == 42); subsystem->state = SPDK_NVMF_SUBSYSTEM_INACTIVE; rc = spdk_nvmf_subsystem_destroy(subsystem, NULL, NULL); @@ -327,6 +365,270 @@ test_discovery_log(void) free(tgt.subsystems); } +static void +test_rdma_discover(struct spdk_nvmf_transport *transport, struct spdk_nvme_transport_id *trid, + struct spdk_nvmf_discovery_log_page_entry *entry) +{ + entry->trtype = SPDK_NVMF_TRTYPE_RDMA; + entry->adrfam = trid->adrfam; + memcpy(entry->traddr, trid->traddr, sizeof(entry->traddr)); + memcpy(entry->trsvcid, trid->trsvcid, sizeof(entry->trsvcid)); +} + +static void +test_tcp_discover(struct spdk_nvmf_transport *transport, struct spdk_nvme_transport_id *trid, + struct spdk_nvmf_discovery_log_page_entry *entry) +{ + entry->trtype = SPDK_NVMF_TRTYPE_TCP; + entry->adrfam = trid->adrfam; + memcpy(entry->traddr, trid->traddr, sizeof(entry->traddr)); + memcpy(entry->trsvcid, trid->trsvcid, sizeof(entry->trsvcid)); +} + +static void +test_discovery_log_with_filters(void) +{ + struct spdk_nvmf_tgt tgt = {}; + struct spdk_nvmf_transport_ops rdma_tr_ops = { .listener_discover = test_rdma_discover }, tcp_tr_ops + = { .listener_discover = test_tcp_discover }; + struct spdk_nvmf_transport rdma_tr = {.ops = &rdma_tr_ops }, tcp_tr = { .ops = &tcp_tr_ops }; + struct spdk_nvmf_subsystem *subsystem; + uint8_t buffer[8192]; + struct iovec iov; + struct spdk_nvmf_discovery_log_page *disc_log; + struct spdk_nvmf_listener rdma_listener_1 = {}, rdma_listener_2 = {}, rdma_listener_3 = {}, + tcp_listener_1 = {}, tcp_listener_2 = {}, tcp_listener_3 = {}; + struct spdk_nvme_transport_id rdma_trid_1 = {}, rdma_trid_2 = {}, rdma_trid_3 = {}, tcp_trid_1 = {}, + tcp_trid_2 = {}, tcp_trid_3 = {}; + + iov.iov_base = buffer; + iov.iov_len = 8192; + + tgt.max_subsystems = 4; + tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *)); + SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL); + + subsystem = spdk_nvmf_subsystem_create(&tgt, "nqn.2016-06.io.spdk:subsystem1", + SPDK_NVMF_SUBTYPE_NVME, 0); + subsystem->flags.allow_any_host = true; + SPDK_CU_ASSERT_FATAL(subsystem != NULL); + + test_gen_trid(&rdma_trid_1, SPDK_NVME_TRANSPORT_RDMA, SPDK_NVMF_ADRFAM_IPV4, "10.10.10.10", "4420"); + test_gen_trid(&rdma_trid_2, SPDK_NVME_TRANSPORT_RDMA, SPDK_NVMF_ADRFAM_IPV4, "11.11.11.11", "4420"); + test_gen_trid(&rdma_trid_3, SPDK_NVME_TRANSPORT_RDMA, SPDK_NVMF_ADRFAM_IPV4, "10.10.10.10", "4421"); + test_gen_trid(&tcp_trid_1, SPDK_NVME_TRANSPORT_TCP, SPDK_NVMF_ADRFAM_IPV4, "11.11.11.11", "4421"); + test_gen_trid(&tcp_trid_2, SPDK_NVME_TRANSPORT_TCP, SPDK_NVMF_ADRFAM_IPV4, "10.10.10.10", "4422"); + test_gen_trid(&tcp_trid_3, SPDK_NVME_TRANSPORT_TCP, SPDK_NVMF_ADRFAM_IPV4, "11.11.11.11", "4422"); + + rdma_listener_1.trid = rdma_trid_1; + rdma_listener_2.trid = rdma_trid_2; + rdma_listener_3.trid = rdma_trid_3; + TAILQ_INIT(&rdma_tr.listeners); + TAILQ_INSERT_TAIL(&rdma_tr.listeners, &rdma_listener_1, link); + TAILQ_INSERT_TAIL(&rdma_tr.listeners, &rdma_listener_2, link); + TAILQ_INSERT_TAIL(&rdma_tr.listeners, &rdma_listener_3, link); + + tcp_listener_1.trid = tcp_trid_1; + tcp_listener_2.trid = tcp_trid_2; + tcp_listener_3.trid = tcp_trid_3; + TAILQ_INIT(&tcp_tr.listeners); + TAILQ_INSERT_TAIL(&tcp_tr.listeners, &tcp_listener_1, link); + TAILQ_INSERT_TAIL(&tcp_tr.listeners, &tcp_listener_2, link); + TAILQ_INSERT_TAIL(&tcp_tr.listeners, &tcp_listener_3, link); + + MOCK_SET(spdk_nvmf_tgt_get_transport, &rdma_tr); + spdk_nvmf_subsystem_add_listener(subsystem, &rdma_trid_1, _subsystem_add_listen_done, NULL); + spdk_nvmf_subsystem_add_listener(subsystem, &rdma_trid_2, _subsystem_add_listen_done, NULL); + spdk_nvmf_subsystem_add_listener(subsystem, &rdma_trid_3, _subsystem_add_listen_done, NULL); + MOCK_SET(spdk_nvmf_tgt_get_transport, &tcp_tr); + spdk_nvmf_subsystem_add_listener(subsystem, &tcp_trid_1, _subsystem_add_listen_done, NULL); + spdk_nvmf_subsystem_add_listener(subsystem, &tcp_trid_2, _subsystem_add_listen_done, NULL); + spdk_nvmf_subsystem_add_listener(subsystem, &tcp_trid_3, _subsystem_add_listen_done, NULL); + MOCK_CLEAR(spdk_nvmf_tgt_get_transport); + + subsystem->state = SPDK_NVMF_SUBSYSTEM_ACTIVE; + + disc_log = (struct spdk_nvmf_discovery_log_page *)buffer; + memset(buffer, 0, sizeof(buffer)); + + /* Test case 1 - check that all trids are reported */ + tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY; + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_1); + CU_ASSERT(disc_log->numrec == 6); + + /* Test case 2 - check that only entries of the same transport type are returned */ + tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE; + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_1); + CU_ASSERT(disc_log->numrec == 3); + CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_1.trtype); + CU_ASSERT(disc_log->entries[1].trtype == rdma_trid_1.trtype); + CU_ASSERT(disc_log->entries[2].trtype == rdma_trid_1.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &tcp_trid_1); + CU_ASSERT(disc_log->numrec == 3); + CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_1.trtype); + CU_ASSERT(disc_log->entries[1].trtype == tcp_trid_1.trtype); + CU_ASSERT(disc_log->entries[2].trtype == tcp_trid_1.trtype); + + /* Test case 3 - check that only entries of the same transport address are returned */ + tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS; + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_1); + CU_ASSERT(disc_log->numrec == 3); + /* one tcp and 2 rdma */ + CU_ASSERT((disc_log->entries[0].trtype ^ disc_log->entries[1].trtype ^ disc_log->entries[2].trtype) + != 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_1.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[1].traddr, rdma_trid_1.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[2].traddr, rdma_trid_1.traddr) == 0); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &tcp_trid_1); + CU_ASSERT(disc_log->numrec == 3); + /* one rdma and two tcp */ + CU_ASSERT((disc_log->entries[0].trtype ^ disc_log->entries[1].trtype ^ disc_log->entries[2].trtype) + != 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_1.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[1].traddr, tcp_trid_1.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[2].traddr, tcp_trid_1.traddr) == 0); + + /* Test case 4 - check that only entries of the same transport address and type returned */ + tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE | + SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS; + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_1); + CU_ASSERT(disc_log->numrec == 2); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_1.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[1].traddr, rdma_trid_1.traddr) == 0); + CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_1.trtype); + CU_ASSERT(disc_log->entries[1].trtype == rdma_trid_1.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_2); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_2.traddr) == 0); + CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_2.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &tcp_trid_1); + CU_ASSERT(disc_log->numrec == 2); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_1.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[1].traddr, tcp_trid_1.traddr) == 0); + CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_1.trtype); + CU_ASSERT(disc_log->entries[1].trtype == tcp_trid_1.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_2); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_2.traddr) == 0); + CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_2.trtype); + + /* Test case 5 - check that only entries of the same transport address and type returned */ + tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE | + SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID; + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_1); + CU_ASSERT(disc_log->numrec == 2); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_1.trsvcid) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[1].trsvcid, rdma_trid_2.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_1.trtype); + CU_ASSERT(disc_log->entries[1].trtype == rdma_trid_2.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_3); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_3.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_3.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &tcp_trid_1); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_1.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_1.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &tcp_trid_2); + CU_ASSERT(disc_log->numrec == 2); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_2.trsvcid) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[1].trsvcid, tcp_trid_2.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_2.trtype); + CU_ASSERT(disc_log->entries[1].trtype == tcp_trid_2.trtype); + + /* Test case 6 - check that only entries of the same transport address and type returned. + * That also implies trtype since RDMA and TCP listeners can't occupy the same socket */ + tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS | + SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID; + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_1); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_1.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_1.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_1.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_2); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_2.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_2.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_2.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_3); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_3.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_3.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_3.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &tcp_trid_1); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_1.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_1.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_1.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &tcp_trid_2); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_2.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_2.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_2.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &tcp_trid_3); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_3.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_3.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_3.trtype); + + /* Test case 7 - check that only entries of the same transport address, svcid and type returned */ + tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE | + SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS | + SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID; + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_1); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_1.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_1.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_1.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_2); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_2.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_2.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_2.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &rdma_trid_3); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_3.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_3.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_3.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &tcp_trid_1); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_1.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_1.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_1.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &tcp_trid_2); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_2.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_2.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_2.trtype); + + nvmf_get_discovery_log_page(&tgt, "nqn.2016-06.io.spdk:host1", &iov, 1, 0, 8192, &tcp_trid_3); + CU_ASSERT(disc_log->numrec == 1); + CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_3.traddr) == 0); + CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_3.trsvcid) == 0); + CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_3.trtype); + + subsystem->state = SPDK_NVMF_SUBSYSTEM_INACTIVE; + spdk_nvmf_subsystem_destroy(subsystem, NULL, NULL); + free(tgt.subsystems); +} + int main(int argc, char **argv) { CU_pSuite suite = NULL; @@ -338,6 +640,7 @@ int main(int argc, char **argv) suite = CU_add_suite("nvmf", NULL, NULL); CU_ADD_TEST(suite, test_discovery_log); + CU_ADD_TEST(suite, test_discovery_log_with_filters); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests(); diff --git a/test/unit/lib/nvmf/tcp.c/tcp_ut.c b/test/unit/lib/nvmf/tcp.c/tcp_ut.c index 93d5d65467..d609fbb4e6 100644 --- a/test/unit/lib/nvmf/tcp.c/tcp_ut.c +++ b/test/unit/lib/nvmf/tcp.c/tcp_ut.c @@ -3,6 +3,7 @@ * * Copyright (c) Intel Corporation. * All rights reserved. + * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -92,7 +93,7 @@ DEFINE_STUB(nvmf_subsystem_find_listener, DEFINE_STUB_V(nvmf_get_discovery_log_page, (struct spdk_nvmf_tgt *tgt, const char *hostnqn, struct iovec *iov, - uint32_t iovcnt, uint64_t offset, uint32_t length)); + uint32_t iovcnt, uint64_t offset, uint32_t length, struct spdk_nvme_transport_id *cmd_src_trid)); DEFINE_STUB_V(nvmf_subsystem_remove_ctrlr, (struct spdk_nvmf_subsystem *subsystem, struct spdk_nvmf_ctrlr *ctrlr));