From 6e93142e31222d1c1a9245dc9af61faa22ff6d90 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 9 Dec 2025 14:54:29 +0100 Subject: [PATCH 01/13] util: move nvme_strerror to libraray This is a useful helper which can be reused inside the library as well. Signed-off-by: Daniel Wagner --- libnvme/src/libnvme.map | 1 + libnvme/src/nvme/util.c | 7 +++++++ libnvme/src/nvme/util.h | 9 +++++++++ nvme.c | 7 ------- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/libnvme/src/libnvme.map b/libnvme/src/libnvme.map index e0e81af3c4..c1541c0b98 100644 --- a/libnvme/src/libnvme.map +++ b/libnvme/src/libnvme.map @@ -247,6 +247,7 @@ LIBNVME_2_0 { nvme_skip_namespaces; nvme_status_to_errno; nvme_status_to_string; + nvme_strerror; nvme_submit_admin_passthru; nvme_submit_io_passthru; nvme_subsys_filter; diff --git a/libnvme/src/nvme/util.c b/libnvme/src/nvme/util.c index 18222c4729..3e67020431 100644 --- a/libnvme/src/nvme/util.c +++ b/libnvme/src/nvme/util.c @@ -641,6 +641,13 @@ const char *nvme_errno_to_string(int status) return s; } +const char *nvme_strerror(int errnum) +{ + if (errnum >= ENVME_CONNECT_RESOLVE) + return nvme_errno_to_string(errnum); + return strerror(errnum); +} + #ifdef HAVE_NETDB int hostname2traddr(struct nvme_global_ctx *ctx, const char *traddr, char **hostname) diff --git a/libnvme/src/nvme/util.h b/libnvme/src/nvme/util.h index 0bb7fe0a4d..539d6caabf 100644 --- a/libnvme/src/nvme/util.h +++ b/libnvme/src/nvme/util.h @@ -95,6 +95,15 @@ const char *nvme_status_to_string(int status, bool fabrics); */ const char *nvme_errno_to_string(int err); +/** + * nvme_strerror() - Returns string describing nvme errors and errno + * @err: Returned error codes from all libnvme functions + * + * Return: String representation of either the nvme connect error codes + * (positive values) or errno string (negative values) + */ +const char *nvme_strerror(int errnum); + /** * nvme_init_ctrl_list() - Initialize an nvme_ctrl_list structure from an array. * @cntlist: The controller list structure to initialize diff --git a/nvme.c b/nvme.c index b453fdf646..5aeabae3ab 100644 --- a/nvme.c +++ b/nvme.c @@ -314,13 +314,6 @@ static OPT_VALS(feature_name) = { VAL_END() }; -const char *nvme_strerror(int errnum) -{ - if (errnum >= ENVME_CONNECT_RESOLVE) - return nvme_errno_to_string(errnum); - return strerror(errnum); -} - static ssize_t getrandom_bytes(void *buf, size_t buflen) { ssize_t result; From cead161967c826fefb297f792f0669a9505cd5c1 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 9 Dec 2025 16:11:54 +0100 Subject: [PATCH 02/13] fabrics: move __discover to the library This is generic code for discovery, thus move it the library. Signed-off-by: Daniel Wagner --- fabrics.c | 228 +++++++++++++++++-------------------- libnvme/src/libnvme.map | 8 ++ libnvme/src/nvme/fabrics.c | 215 ++++++++++++++++++++++++++++++++++ libnvme/src/nvme/fabrics.h | 25 ++++ libnvme/src/nvme/private.h | 29 +++++ libnvme/src/nvme/util.h | 2 +- 6 files changed, 380 insertions(+), 127 deletions(-) diff --git a/fabrics.c b/fabrics.c index 6537610937..006c0db137 100644 --- a/fabrics.c +++ b/fabrics.c @@ -301,127 +301,21 @@ static void save_discovery_log(char *raw, struct nvmf_discovery_log *log) close(fd); } -static int __discover(nvme_ctrl_t c, struct nvme_fabrics_config *defcfg, - char *raw, bool connect, bool persistent, - nvme_print_flags_t flags) -{ - struct nvmf_discovery_log *log = NULL; - nvme_subsystem_t s = nvme_ctrl_get_subsystem(c); - nvme_host_t h = nvme_subsystem_get_host(s); - uint64_t numrec; - int err; - - struct nvme_get_discovery_args args = { - .c = c, - .args_size = sizeof(args), - .max_retries = MAX_DISC_RETRIES, - .result = 0, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lsp = 0, - }; - - err = nvmf_get_discovery_wargs(&args, &log); - if (err) { - fprintf(stderr, "failed to get discovery log: %s\n", - nvme_strerror(err)); - return err; - } - - numrec = le64_to_cpu(log->numrec); - if (raw) - save_discovery_log(raw, log); - else if (!connect) { - nvme_show_discovery_log(log, numrec, flags); - } else if (connect) { - int i; - - for (i = 0; i < numrec; i++) { - struct nvmf_disc_log_entry *e = &log->entries[i]; - nvme_ctrl_t cl; - bool discover = false; - bool disconnect; - nvme_ctrl_t child; - int tmo = defcfg->keep_alive_tmo; - - struct tr_config trcfg = { - .subsysnqn = e->subnqn, - .transport = nvmf_trtype_str(e->trtype), - .traddr = e->traddr, - .host_traddr = defcfg->host_traddr, - .host_iface = defcfg->host_iface, - .trsvcid = e->trsvcid, - }; - - /* Already connected ? */ - cl = lookup_ctrl(h, &trcfg); - if (cl && nvme_ctrl_get_name(cl)) - continue; - - /* Skip connect if the transport types don't match */ - if (strcmp(nvme_ctrl_get_transport(c), - nvmf_trtype_str(e->trtype))) - continue; - - if (e->subtype == NVME_NQN_DISC || - e->subtype == NVME_NQN_CURR) { - __u16 eflags = le16_to_cpu(e->eflags); - /* - * Does this discovery controller return the - * same information? - */ - if (eflags & NVMF_DISC_EFLAGS_DUPRETINFO) - continue; - - /* Are we supposed to keep the discovery controller around? */ - disconnect = !persistent; - - if (strcmp(e->subnqn, NVME_DISC_SUBSYS_NAME)) { - /* - * Does this discovery controller doesn't - * support explicit persistent connection? - */ - if (!(eflags & NVMF_DISC_EFLAGS_EPCSD)) - disconnect = true; - else - disconnect = false; - } - - set_discovery_kato(defcfg); - } else { - /* NVME_NQN_NVME */ - disconnect = false; - } - - err = nvmf_connect_disc_entry(h, e, defcfg, - &discover, &child); - - defcfg->keep_alive_tmo = tmo; - - if (!child) { - if (discover) - __discover(child, defcfg, raw, - true, persistent, flags); - - if (disconnect) { - nvme_disconnect_ctrl(child); - nvme_free_ctrl(child); - } - } else if (err == -ENVME_CONNECT_ALREADY && !quiet) { - const char *subnqn = log->entries[i].subnqn; - const char *trtype = nvmf_trtype_str(log->entries[i].trtype); - const char *traddr = log->entries[i].traddr; - const char *trsvcid = log->entries[i].trsvcid; +struct cb_discovery_log_data { + nvme_print_flags_t flags; + char *raw; +}; - fprintf(stderr, - "already connected to hostnqn=%s,nqn=%s,transport=%s,traddr=%s,trsvcid=%s\n", - nvme_host_get_hostnqn(h), subnqn, - trtype, traddr, trsvcid); - } - } - } +static void cb_discovery_log(struct nvmf_discovery_ctx *dctx, + bool connect, struct nvmf_discovery_log *log, + uint64_t numrec, void *user_data) +{ + struct cb_discovery_log_data *dld = user_data; - free(log); - return 0; + if (dld->raw) + save_discovery_log(dld->raw, log); + else if (!connect) + nvme_show_discovery_log(log, numrec, dld->flags); } char * nvmf_get_default_trsvcid(const char *transport, bool discovery_ctrl) @@ -442,6 +336,63 @@ char * nvmf_get_default_trsvcid(const char *transport, bool discovery_ctrl) return NULL; } +static void already_connected(struct nvme_host *host, + struct nvmf_disc_log_entry *entry, + void *user_data) +{ + if (quiet) + return; + + fprintf(stderr, + "already connected to hostnqn=%s,nqn=%s,transport=%s,traddr=%s,trsvcid=%s\n", + nvme_host_get_hostnqn(host), entry->subnqn, + nvmf_trtype_str(entry->trtype), entry->traddr, entry->trsvcid); +} + +static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, + bool persistent, + struct nvme_fabrics_config *defcfg, + void *user_data, struct nvmf_discovery_ctx **dctxp) +{ + struct nvmf_discovery_ctx *dctx; + int err; + + err = nvmf_discovery_ctx_create(ctx, user_data, &dctx); + if (err) + return err; + + err = nvmf_discovery_ctx_max_retries(dctx, MAX_DISC_RETRIES); + if (err) + goto err; + + err = nvmf_discovery_ctx_keep_alive_timeout(dctx, NVMF_DEF_DISC_TMO); + if (err) + goto err; + + err = nvmf_discovery_ctx_discovery_log_set(dctx, cb_discovery_log); + if (err) + goto err; + + err = nvmf_discovery_ctx_already_connected_set(dctx, already_connected); + if (err) + goto err; + + err = nvmf_discovery_ctx_persistent_set(dctx, persistent); + if (err) + goto err; + + err = nvmf_discovery_ctx_default_fabrics_config_set(dctx, defcfg); + if (err) + goto err; + + *dctxp = dctx; + return 0; + +err: + free(dctx); + return err; +} + static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, const char *desc, bool connect, const struct nvme_fabrics_config *defcfg) @@ -449,6 +400,7 @@ static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, char *transport = NULL, *traddr = NULL, *trsvcid = NULL; char *hostnqn = NULL, *hostid = NULL, *hostkey = NULL; char *subsysnqn = NULL, *keyring = NULL, *tls_key = NULL; + _cleanup_free_ struct nvmf_discovery_ctx *dctx = NULL; char *tls_key_identity = NULL; char *ptr, **argv, *p, line[4096]; int argc, ret = 0; @@ -458,7 +410,6 @@ static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, char *format = "normal"; struct nvme_fabrics_config cfg; bool force = false; - NVMF_ARGS(opts, cfg, OPT_FMT("output-format", 'o', &format, output_format), OPT_FILE("raw", 'r', &raw, "save raw output to file"), @@ -519,11 +470,18 @@ static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, .trsvcid = trsvcid, }; + struct cb_discovery_log_data dld = { + .flags = flags, + .raw = raw, + }; + ret = create_discovery_log_ctx(ctx, true, &cfg, &dld, &dctx); + if (ret) + return ret; + if (!force) { c = lookup_ctrl(h, &trcfg); if (c) { - __discover(c, &cfg, raw, connect, - true, flags); + nvmf_discovery(ctx, dctx, connect, c); goto next; } } @@ -532,7 +490,8 @@ static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, if (ret) goto next; - __discover(c, &cfg, raw, connect, persistent, flags); + nvmf_discovery_ctx_persistent_set(dctx, persistent); + nvmf_discovery(ctx, dctx, connect, c); if (!(persistent || is_persistent_discovery_ctrl(h, c))) ret = nvme_disconnect_ctrl(c); nvme_free_ctrl(c); @@ -551,6 +510,7 @@ static int _discover_from_json_config_file(struct nvme_global_ctx *ctx, const struct nvme_fabrics_config *defcfg, nvme_print_flags_t flags, bool force) { + _cleanup_free_ struct nvmf_discovery_ctx *dctx = NULL; const char *transport, *traddr, *host_traddr; const char *host_iface, *trsvcid, *subsysnqn; struct nvme_fabrics_config cfg; @@ -611,10 +571,16 @@ static int _discover_from_json_config_file(struct nvme_global_ctx *ctx, .trsvcid = trsvcid, }; + struct cb_discovery_log_data dld = { + .flags = flags, + .raw = raw, + }; + ret = create_discovery_log_ctx(ctx, true, &cfg, &dld, &dctx); + if (!force) { cn = lookup_ctrl(h, &trcfg); if (cn) { - __discover(cn, &cfg, raw, connect, true, flags); + nvmf_discovery(ctx, dctx, connect, cn); return 0; } } @@ -623,7 +589,8 @@ static int _discover_from_json_config_file(struct nvme_global_ctx *ctx, if (ret) return 0; - __discover(cn, &cfg, raw, connect, persistent, flags); + nvmf_discovery_ctx_persistent_set(dctx, persistent); + nvmf_discovery(ctx, dctx, connect, cn); if (!(persistent || is_persistent_discovery_ctrl(h, cn))) ret = nvme_disconnect_ctrl(cn); nvme_free_ctrl(cn); @@ -732,6 +699,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) char *context = NULL; nvme_print_flags_t flags; _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; + _cleanup_free_ struct nvmf_discovery_ctx *dctx = NULL; nvme_host_t h; nvme_ctrl_t c = NULL; unsigned int verbose = 0; @@ -917,7 +885,15 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) } } - ret = __discover(c, &cfg, raw, connect, persistent, flags); + struct cb_discovery_log_data dld = { + .flags = flags, + .raw = raw, + }; + ret = create_discovery_log_ctx(ctx, persistent, &cfg, &dld, &dctx); + if (ret) + return ret; + + ret = nvmf_discovery(ctx, dctx, connect, c); if (!(persistent || is_persistent_discovery_ctrl(h, c))) nvme_disconnect_ctrl(c); nvme_free_ctrl(c); diff --git a/libnvme/src/libnvme.map b/libnvme/src/libnvme.map index c1541c0b98..ef9b6a68c0 100644 --- a/libnvme/src/libnvme.map +++ b/libnvme/src/libnvme.map @@ -291,6 +291,14 @@ LIBNVME_2_0 { nvmf_connect_ctrl; nvmf_connect_disc_entry; nvmf_default_config; + nvmf_discovery; + nvmf_discovery_ctx_already_connected_set; + nvmf_discovery_ctx_create; + nvmf_discovery_ctx_default_fabrics_config_set; + nvmf_discovery_ctx_discovery_log_set; + nvmf_discovery_ctx_keep_alive_timeout; + nvmf_discovery_ctx_max_retries; + nvmf_discovery_ctx_persistent_set; nvmf_eflags_str; nvmf_exat_ptr_next; nvmf_get_discovery_log; diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index 7a9c8e4d30..24e227de8c 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -195,6 +195,72 @@ const char *nvmf_cms_str(__u8 cm) return arg_str(cms, ARRAY_SIZE(cms), cm); } +int nvmf_discovery_ctx_create(struct nvme_global_ctx *ctx, + void *user_data, struct nvmf_discovery_ctx **dctxp) +{ + struct nvmf_discovery_ctx *dctx; + + dctx = calloc(1, sizeof(*dctx)); + if (!dctx) + return -ENOMEM; + + dctx->user_data = user_data; + + *dctxp = dctx; + return 0; +} + +int nvmf_discovery_ctx_max_retries(struct nvmf_discovery_ctx *dctx, + int max_retries) +{ + dctx->default_max_discovery_retries = max_retries; + + return 0; +} +int nvmf_discovery_ctx_keep_alive_timeout(struct nvmf_discovery_ctx *dctx, + int keep_alive_timeout) +{ + dctx->default_keep_alive_timeout = keep_alive_timeout; + + return 0; +} + +int nvmf_discovery_ctx_discovery_log_set(struct nvmf_discovery_ctx *dctx, + void (*discover_log)(struct nvmf_discovery_ctx *dctx, + bool connect, struct nvmf_discovery_log *log, + uint64_t numrec, void *user_data)) +{ + dctx->discovery_log = discover_log; + + return 0; +} + +int nvmf_discovery_ctx_already_connected_set(struct nvmf_discovery_ctx *dctx, + void (*already_connected)(struct nvme_host *host, + struct nvmf_disc_log_entry *entry, void *user_data)) +{ + dctx->already_connected = already_connected; + + return 0; +} + +int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, + bool persistent) +{ + dctx->persistent = persistent; + + return 0; +} + +int nvmf_discovery_ctx_default_fabrics_config_set( + struct nvmf_discovery_ctx *dctx, + struct nvme_fabrics_config *defcfg) +{ + dctx->defcfg = defcfg; + + return 0; +} + /* * Derived from Linux's supported options (the opt_tokens table) * when the mechanism to report supported options was added (f18ee3d988157). @@ -1913,3 +1979,152 @@ void nvme_free_uri(struct nvme_fabrics_uri *uri) free(uri->fragment); free(uri); } + +static nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct tr_config *trcfg) +{ + nvme_subsystem_t s; + nvme_ctrl_t c; + + nvme_for_each_subsystem(h, s) { + c = nvme_ctrl_find(s, + trcfg->transport, + trcfg->traddr, + trcfg->trsvcid, + trcfg->subsysnqn, + trcfg->host_traddr, + trcfg->host_iface); + if (c) + return c; + } + + return NULL; +} + +static int set_discovery_kato(struct nvmf_discovery_ctx *dctx, + struct nvme_fabrics_config *cfg) +{ + int tmo = cfg->keep_alive_tmo; + + /* Set kato to NVMF_DEF_DISC_TMO for persistent controllers */ + if (dctx->persistent && !cfg->keep_alive_tmo) + cfg->keep_alive_tmo = dctx->default_keep_alive_timeout; + /* Set kato to zero for non-persistent controllers */ + else if (!dctx->persistent && (cfg->keep_alive_tmo > 0)) + cfg->keep_alive_tmo = 0; + + return tmo; +} + +int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, + bool connect, struct nvme_ctrl *c) +{ + _cleanup_free_ struct nvmf_discovery_log *log = NULL; + nvme_subsystem_t s = nvme_ctrl_get_subsystem(c); + nvme_host_t h = nvme_subsystem_get_host(s); + uint64_t numrec; + int err; + + struct nvme_get_discovery_args args = { + .c = c, + .args_size = sizeof(args), + .max_retries = dctx->default_max_discovery_retries, + .result = 0, + .lsp = 0, + }; + + err = nvmf_get_discovery_wargs(&args, &log); + if (err) { + nvme_msg(ctx, LOG_ERR, "failed to get discovery log: %s\n", + nvme_strerror(err)); + return err; + } + + numrec = le64_to_cpu(log->numrec); + if (dctx->discovery_log) + dctx->discovery_log(dctx, connect, log, numrec, + dctx->user_data); + + if (!connect) + return 0; + + for (int i = 0; i < numrec; i++) { + struct nvmf_disc_log_entry *e = &log->entries[i]; + nvme_ctrl_t cl; + bool discover = false; + bool disconnect; + nvme_ctrl_t child; + int tmo = dctx->defcfg->keep_alive_tmo; + + struct tr_config trcfg = { + .subsysnqn = e->subnqn, + .transport = nvmf_trtype_str(e->trtype), + .traddr = e->traddr, + .host_traddr = dctx->defcfg->host_traddr, + .host_iface = dctx->defcfg->host_iface, + .trsvcid = e->trsvcid, + }; + + /* Already connected ? */ + cl = lookup_ctrl(h, &trcfg); + if (cl && nvme_ctrl_get_name(cl)) + continue; + + /* Skip connect if the transport types don't match */ + if (strcmp(nvme_ctrl_get_transport(c), + nvmf_trtype_str(e->trtype))) + continue; + + if (e->subtype == NVME_NQN_DISC || + e->subtype == NVME_NQN_CURR) { + __u16 eflags = le16_to_cpu(e->eflags); + /* + * Does this discovery controller return the + * same information? + */ + if (eflags & NVMF_DISC_EFLAGS_DUPRETINFO) + continue; + + /* + * Are we supposed to keep the discovery + * controller around? + */ + disconnect = !dctx->persistent; + + if (strcmp(e->subnqn, NVME_DISC_SUBSYS_NAME)) { + /* + * Does this discovery controller doesn't + * support explicit persistent connection? + */ + if (!(eflags & NVMF_DISC_EFLAGS_EPCSD)) + disconnect = true; + else + disconnect = false; + } + + set_discovery_kato(dctx, dctx->defcfg); + } else { + /* NVME_NQN_NVME */ + disconnect = false; + } + + err = nvmf_connect_disc_entry(h, e, dctx->defcfg, + &discover, &child); + + dctx->defcfg->keep_alive_tmo = tmo; + + if (!child) { + if (discover) + nvmf_discovery(ctx, dctx, true, child); + + if (disconnect) { + nvme_disconnect_ctrl(child); + nvme_free_ctrl(child); + } + } else if (err == -ENVME_CONNECT_ALREADY) { + dctx->already_connected(h, &log->entries[i], + dctx->user_data); + } + } + + return 0; +} diff --git a/libnvme/src/nvme/fabrics.h b/libnvme/src/nvme/fabrics.h index 01d3db6bda..27c0a2e213 100644 --- a/libnvme/src/nvme/fabrics.h +++ b/libnvme/src/nvme/fabrics.h @@ -23,6 +23,29 @@ /* default to 600 seconds of reconnect attempts before giving up */ #define NVMF_DEF_CTRL_LOSS_TMO 600 +struct nvmf_discovery_ctx; + +int nvmf_discovery_ctx_create(struct nvme_global_ctx *ctx, + void *user_data, struct nvmf_discovery_ctx **dctx); + +int nvmf_discovery_ctx_max_retries(struct nvmf_discovery_ctx *dctx, + int max_retries); +int nvmf_discovery_ctx_keep_alive_timeout(struct nvmf_discovery_ctx *dctx, + int keep_alive_timeout); +int nvmf_discovery_ctx_discovery_log_set(struct nvmf_discovery_ctx *dctx, + void (*discover_log)(struct nvmf_discovery_ctx *dctx, + bool connect, struct nvmf_discovery_log *log, + uint64_t numrec, void *user_data)); +int nvmf_discovery_ctx_already_connected_set(struct nvmf_discovery_ctx *dctx, + void (*already_connected)(struct nvme_host *host, + struct nvmf_disc_log_entry *entry, + void *user_data)); +int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, + bool persistent); +int nvmf_discovery_ctx_default_fabrics_config_set( + struct nvmf_discovery_ctx *dctx, + struct nvme_fabrics_config *defcfg); + /** * struct nvme_fabrics_config - Defines all linux nvme fabrics initiator options * @host_traddr: Host transport address @@ -407,4 +430,6 @@ int nvme_parse_uri(const char *str, struct nvme_fabrics_uri **uri); */ void nvme_free_uri(struct nvme_fabrics_uri *uri); +int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, + bool connect, struct nvme_ctrl *c); #endif /* _LIBNVME_FABRICS_H */ diff --git a/libnvme/src/nvme/private.h b/libnvme/src/nvme/private.h index e7825376b4..781ed8de69 100644 --- a/libnvme/src/nvme/private.h +++ b/libnvme/src/nvme/private.h @@ -272,6 +272,35 @@ struct nvme_global_ctx { struct nvme_fabric_options *options; }; +struct nvmf_discovery_ctx { + /* defaults */ + int default_max_discovery_retries; + int default_keep_alive_timeout; + + void (*discovery_log)(struct nvmf_discovery_ctx *dctx, + bool connect, + struct nvmf_discovery_log *log, + uint64_t numrec, void *user_data); + void (*already_connected)(struct nvme_host *host, + struct nvmf_disc_log_entry *entry, + void *user_data); + + /* connfiguration */ + bool persistent; + struct nvme_fabrics_config *defcfg; + + void *user_data; +}; + +struct tr_config { + const char *subsysnqn; + const char *transport; + const char *traddr; + const char *host_traddr; + const char *host_iface; + const char *trsvcid; +}; + int nvme_set_attr(const char *dir, const char *attr, const char *value); int json_read_config(struct nvme_global_ctx *ctx, const char *config_file); diff --git a/libnvme/src/nvme/util.h b/libnvme/src/nvme/util.h index 539d6caabf..a32bfc1790 100644 --- a/libnvme/src/nvme/util.h +++ b/libnvme/src/nvme/util.h @@ -102,7 +102,7 @@ const char *nvme_errno_to_string(int err); * Return: String representation of either the nvme connect error codes * (positive values) or errno string (negative values) */ -const char *nvme_strerror(int errnum); +const char *nvme_strerror(int err); /** * nvme_init_ctrl_list() - Initialize an nvme_ctrl_list structure from an array. From fe5813e24a29467d541a8aca4b0723cb1d36e3c6 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Wed, 10 Dec 2025 16:17:33 +0100 Subject: [PATCH 03/13] fabrics: move json config based discovery to library Move more of the discovery code from nvme-cli to the library. Signed-off-by: Daniel Wagner --- fabrics.c | 195 ++++----------------------- libnvme/src/libnvme.map | 3 + libnvme/src/nvme/fabrics.c | 261 +++++++++++++++++++++++++++++++++++++ libnvme/src/nvme/fabrics.h | 8 ++ libnvme/src/nvme/private.h | 2 + 5 files changed, 302 insertions(+), 167 deletions(-) diff --git a/fabrics.c b/fabrics.c index 006c0db137..62ebe68023 100644 --- a/fabrics.c +++ b/fabrics.c @@ -318,24 +318,6 @@ static void cb_discovery_log(struct nvmf_discovery_ctx *dctx, nvme_show_discovery_log(log, numrec, dld->flags); } -char * nvmf_get_default_trsvcid(const char *transport, bool discovery_ctrl) -{ - if (!transport) - return NULL; - if (!strcmp(transport, "tcp")) { - if (discovery_ctrl) - /* Default port for NVMe/TCP discovery controllers */ - return stringify(NVME_DISC_IP_PORT); - /* Default port for NVMe/TCP io controllers */ - return stringify(NVME_RDMA_IP_PORT); - } else if (!strcmp(transport, "rdma")) { - /* Default port for NVMe/RDMA controllers */ - return stringify(NVME_RDMA_IP_PORT); - } - - return NULL; -} - static void already_connected(struct nvme_host *host, struct nvmf_disc_log_entry *entry, void *user_data) @@ -349,6 +331,17 @@ static void already_connected(struct nvme_host *host, nvmf_trtype_str(entry->trtype), entry->traddr, entry->trsvcid); } +static bool nvmf_decide_retry(struct nvmf_discovery_ctx *dctx, int err, + void *user_data) +{ + if (err == -EAGAIN || (err == -EINTR && !nvme_sigint_received)) { + print_debug("nvmf_add_ctrl returned '%s'\n", strerror(-err)); + return true; + } + + return false; +} + static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, bool persistent, struct nvme_fabrics_config *defcfg, @@ -377,6 +370,10 @@ static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, if (err) goto err; + err = nvmf_discovery_ctx_decide_retry_set(dctx, nvmf_decide_retry); + if (err) + goto err; + err = nvmf_discovery_ctx_persistent_set(dctx, persistent); if (err) goto err; @@ -504,144 +501,6 @@ static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, return ret; } -static int _discover_from_json_config_file(struct nvme_global_ctx *ctx, - nvme_host_t h, nvme_ctrl_t c, - const char *desc, bool connect, - const struct nvme_fabrics_config *defcfg, - nvme_print_flags_t flags, bool force) -{ - _cleanup_free_ struct nvmf_discovery_ctx *dctx = NULL; - const char *transport, *traddr, *host_traddr; - const char *host_iface, *trsvcid, *subsysnqn; - struct nvme_fabrics_config cfg; - nvme_ctrl_t cn; - int ret = 0; - - transport = nvme_ctrl_get_transport(c); - traddr = nvme_ctrl_get_traddr(c); - host_traddr = nvme_ctrl_get_host_traddr(c); - host_iface = nvme_ctrl_get_host_iface(c); - - if (!transport && !traddr) - return 0; - - /* ignore none fabric transports */ - if (strcmp(transport, "tcp") && - strcmp(transport, "rdma") && - strcmp(transport, "fc")) - return 0; - - /* ignore if no host_traddr for fc */ - if (!strcmp(transport, "fc")) { - if (!host_traddr) { - fprintf(stderr, "host_traddr required for fc\n"); - return 0; - } - } - - /* ignore if host_iface set for any transport other than tcp */ - if (!strcmp(transport, "rdma") || !strcmp(transport, "fc")) { - if (host_iface) { - fprintf(stderr, - "host_iface not permitted for rdma or fc\n"); - return 0; - } - } - - trsvcid = nvme_ctrl_get_trsvcid(c); - if (!trsvcid || !strcmp(trsvcid, "")) - trsvcid = nvmf_get_default_trsvcid(transport, true); - - if (force) - subsysnqn = nvme_ctrl_get_subsysnqn(c); - else - subsysnqn = NVME_DISC_SUBSYS_NAME; - - if (nvme_ctrl_is_persistent(c)) - persistent = true; - - memcpy(&cfg, defcfg, sizeof(cfg)); - - struct tr_config trcfg = { - .subsysnqn = subsysnqn, - .transport = transport, - .traddr = traddr, - .host_traddr = host_traddr, - .host_iface = host_iface, - .trsvcid = trsvcid, - }; - - struct cb_discovery_log_data dld = { - .flags = flags, - .raw = raw, - }; - ret = create_discovery_log_ctx(ctx, true, &cfg, &dld, &dctx); - - if (!force) { - cn = lookup_ctrl(h, &trcfg); - if (cn) { - nvmf_discovery(ctx, dctx, connect, cn); - return 0; - } - } - - ret = nvmf_create_discover_ctrl(ctx, h, &cfg, &trcfg, &cn); - if (ret) - return 0; - - nvmf_discovery_ctx_persistent_set(dctx, persistent); - nvmf_discovery(ctx, dctx, connect, cn); - if (!(persistent || is_persistent_discovery_ctrl(h, cn))) - ret = nvme_disconnect_ctrl(cn); - nvme_free_ctrl(cn); - - return ret; -} - -static int discover_from_json_config_file(struct nvme_global_ctx *ctx, - const char *hostnqn, - const char *hostid, const char *desc, - bool connect, - const struct nvme_fabrics_config *defcfg, - nvme_print_flags_t flags, bool force) -{ - const char *hnqn, *hid; - nvme_host_t h; - nvme_subsystem_t s; - nvme_ctrl_t c; - int ret = 0, err; - - nvme_for_each_host(ctx, h) { - nvme_for_each_subsystem(h, s) { - hnqn = nvme_host_get_hostnqn(h); - if (hostnqn && hnqn && strcmp(hostnqn, hnqn)) - continue; - hid = nvme_host_get_hostid(h); - if (hostid && hid && strcmp(hostid, hid)) - continue; - - nvme_subsystem_for_each_ctrl(s, c) { - err = _discover_from_json_config_file( - ctx, h, c, desc, connect, defcfg, - flags, force); - - if (err) { - fprintf(stderr, - "failed to connect to hostnqn=%s,nqn=%s,%s\n", - nvme_host_get_hostnqn(h), - nvme_subsystem_get_name(s), - nvme_ctrl_get_address(c)); - - if (!ret) - ret = err; - } - } - } - } - - return ret; -} - static int nvme_read_volatile_config(struct nvme_global_ctx *ctx) { char *filename, *ext; @@ -785,7 +644,18 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) if (hostkey) nvme_host_set_dhchap_key(h, hostkey); + struct cb_discovery_log_data dld = { + .flags = flags, + .raw = raw, + }; + + ret = create_discovery_log_ctx(ctx, persistent, &cfg, &dld, &dctx); + if (ret) + return ret; + if (!device && !transport && !traddr) { + nvmf_discovery_ctx_persistent_set(dctx, true); + if (!nonbft) ret = discover_from_nbft(ctx, hostnqn, hostid, hnqn, hid, desc, connect, @@ -794,9 +664,8 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) goto out_free; if (json_config) - ret = discover_from_json_config_file(ctx, hostnqn, hostid, - desc, connect, &cfg, - flags, force); + ret = nvmf_discovery_config_json(ctx, dctx, + hostnqn, hostid, connect, force); if (ret || access(PATH_NVMF_DISC, F_OK)) goto out_free; @@ -885,14 +754,6 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) } } - struct cb_discovery_log_data dld = { - .flags = flags, - .raw = raw, - }; - ret = create_discovery_log_ctx(ctx, persistent, &cfg, &dld, &dctx); - if (ret) - return ret; - ret = nvmf_discovery(ctx, dctx, connect, c); if (!(persistent || is_persistent_discovery_ctrl(h, c))) nvme_disconnect_ctrl(c); diff --git a/libnvme/src/libnvme.map b/libnvme/src/libnvme.map index ef9b6a68c0..67f5d93fc3 100644 --- a/libnvme/src/libnvme.map +++ b/libnvme/src/libnvme.map @@ -292,8 +292,10 @@ LIBNVME_2_0 { nvmf_connect_disc_entry; nvmf_default_config; nvmf_discovery; + nvmf_discovery_config_json; nvmf_discovery_ctx_already_connected_set; nvmf_discovery_ctx_create; + nvmf_discovery_ctx_decide_retry_set; nvmf_discovery_ctx_default_fabrics_config_set; nvmf_discovery_ctx_discovery_log_set; nvmf_discovery_ctx_keep_alive_timeout; @@ -301,6 +303,7 @@ LIBNVME_2_0 { nvmf_discovery_ctx_persistent_set; nvmf_eflags_str; nvmf_exat_ptr_next; + nvmf_get_default_trsvcid; nvmf_get_discovery_log; nvmf_get_discovery_wargs; nvmf_hostid_from_file; diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index 24e227de8c..0ae7fc01f1 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -244,6 +244,15 @@ int nvmf_discovery_ctx_already_connected_set(struct nvmf_discovery_ctx *dctx, return 0; } +int nvmf_discovery_ctx_decide_retry_set(struct nvmf_discovery_ctx *dctx, + bool (*decide_retry)(struct nvmf_discovery_ctx *dctx, int err, + void *user_data)) +{ + dctx->decide_retry = decide_retry; + + return 0; +} + int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, bool persistent) { @@ -2128,3 +2137,255 @@ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, return 0; } + +char *nvmf_get_default_trsvcid(const char *transport, bool discovery_ctrl) +{ + if (!transport) + return NULL; + if (!strcmp(transport, "tcp")) { + if (discovery_ctrl) + /* Default port for NVMe/TCP discovery controllers */ + return stringify(NVME_DISC_IP_PORT); + /* Default port for NVMe/TCP io controllers */ + return stringify(NVME_RDMA_IP_PORT); + } else if (!strcmp(transport, "rdma")) { + /* Default port for NVMe/RDMA controllers */ + return stringify(NVME_RDMA_IP_PORT); + } + + return NULL; +} + +static bool is_persistent_discovery_ctrl(nvme_host_t h, nvme_ctrl_t c) +{ + if (nvme_host_is_pdc_enabled(h, DEFAULT_PDC_ENABLED)) + return nvme_ctrl_is_unique_discovery_ctrl(c); + + return false; +} + +static int nvme_add_ctrl(struct nvmf_discovery_ctx *dctx, + struct nvme_host *h, struct nvme_ctrl *c, + struct nvme_fabrics_config *cfg) +{ + int err; + +retry: + err = nvmf_add_ctrl(h, c, cfg); + if (!err) + return 0; + if (dctx->decide_retry(dctx, err, dctx->user_data)) + goto retry; + + return err; +} + +static int __create_discovery_ctrl(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, nvme_host_t h, + struct nvme_fabrics_config *cfg, struct tr_config *trcfg, + struct nvme_ctrl **ctrl) +{ + nvme_ctrl_t c; + int tmo, ret; + + ret = nvme_create_ctrl(ctx, trcfg->subsysnqn, trcfg->transport, + trcfg->traddr, trcfg->host_traddr, + trcfg->host_iface, trcfg->trsvcid, &c); + if (ret) + return ret; + + nvme_ctrl_set_discovery_ctrl(c, true); + nvme_ctrl_set_unique_discovery_ctrl(c, + strcmp(trcfg->subsysnqn, NVME_DISC_SUBSYS_NAME)); + tmo = set_discovery_kato(dctx, cfg); + + ret = nvme_add_ctrl(dctx, h, c, cfg); + cfg->keep_alive_tmo = tmo; + if (ret) { + nvme_free_ctrl(c); + return ret; + } + + *ctrl = c; + return 0; +} + +int nvmf_create_discovery_ctrl(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, nvme_host_t h, + struct nvme_fabrics_config *cfg, + struct tr_config *trcfg, + struct nvme_ctrl **ctrl) +{ + _cleanup_free_ struct nvme_id_ctrl *id = NULL; + struct nvme_ctrl *c; + int ret; + + ret = __create_discovery_ctrl(ctx, dctx, h, cfg, trcfg, &c); + if (ret) + return ret; + + if (nvme_ctrl_is_unique_discovery_ctrl(c)) { + *ctrl = c; + return 0; + } + + id = __nvme_alloc(sizeof(*id)); + if (!id) { + nvme_free_ctrl(c); + return -ENOMEM; + } + + /* Find out the name of discovery controller */ + ret = nvme_ctrl_identify(c, id); + if (ret) { + fprintf(stderr, "failed to identify controller, error %s\n", + nvme_strerror(-ret)); + nvme_disconnect_ctrl(c); + nvme_free_ctrl(c); + return ret; + } + + if (!strcmp(id->subnqn, NVME_DISC_SUBSYS_NAME)) { + *ctrl = c; + return 0; + } + + /* + * The subsysnqn is not the well-known name. Prefer the unique + * subsysnqn over the well-known one. + */ + nvme_disconnect_ctrl(c); + nvme_free_ctrl(c); + + trcfg->subsysnqn = id->subnqn; + ret = __create_discovery_ctrl(ctx, dctx, h, cfg, trcfg, &c); + if (ret) + return ret; + + *ctrl = c; + return 0; +} + +int _discovery_config_json(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, nvme_host_t h, nvme_ctrl_t c, + bool connect, bool force) +{ + const char *transport, *traddr, *host_traddr; + const char *host_iface, *trsvcid, *subsysnqn; + struct nvme_fabrics_config cfg; + nvme_ctrl_t cn; + int ret = 0; + + transport = nvme_ctrl_get_transport(c); + traddr = nvme_ctrl_get_traddr(c); + host_traddr = nvme_ctrl_get_host_traddr(c); + host_iface = nvme_ctrl_get_host_iface(c); + + if (!transport && !traddr) + return 0; + + /* ignore none fabric transports */ + if (strcmp(transport, "tcp") && + strcmp(transport, "rdma") && + strcmp(transport, "fc")) + return 0; + + /* ignore if no host_traddr for fc */ + if (!strcmp(transport, "fc")) { + if (!host_traddr) { + fprintf(stderr, "host_traddr required for fc\n"); + return 0; + } + } + + /* ignore if host_iface set for any transport other than tcp */ + if (!strcmp(transport, "rdma") || !strcmp(transport, "fc")) { + if (host_iface) { + fprintf(stderr, + "host_iface not permitted for rdma or fc\n"); + return 0; + } + } + + trsvcid = nvme_ctrl_get_trsvcid(c); + if (!trsvcid || !strcmp(trsvcid, "")) + trsvcid = nvmf_get_default_trsvcid(transport, true); + + if (force) + subsysnqn = nvme_ctrl_get_subsysnqn(c); + else + subsysnqn = NVME_DISC_SUBSYS_NAME; + + if (nvme_ctrl_is_persistent(c)) + dctx->persistent = true; + + memcpy(&cfg, dctx->defcfg, sizeof(cfg)); + + struct tr_config trcfg = { + .subsysnqn = subsysnqn, + .transport = transport, + .traddr = traddr, + .host_traddr = host_traddr, + .host_iface = host_iface, + .trsvcid = trsvcid, + }; + + if (!force) { + cn = lookup_ctrl(h, &trcfg); + if (cn) { + dctx->persistent = true; + nvmf_discovery(ctx, dctx, connect, cn); + return 0; + } + } + + ret = nvmf_create_discovery_ctrl(ctx, dctx, h, &cfg, &trcfg, &cn); + if (ret) + return 0; + + nvmf_discovery(ctx, dctx, connect, cn); + if (!(dctx->persistent || is_persistent_discovery_ctrl(h, cn))) + ret = nvme_disconnect_ctrl(cn); + nvme_free_ctrl(cn); + + return ret; +} + +int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, const char *hostnqn, + const char *hostid, bool connect, bool force) +{ + const char *hnqn, *hid; + nvme_host_t h; + nvme_subsystem_t s; + nvme_ctrl_t c; + int ret = 0, err; + + nvme_for_each_host(ctx, h) { + nvme_for_each_subsystem(h, s) { + hnqn = nvme_host_get_hostnqn(h); + if (hostnqn && hnqn && strcmp(hostnqn, hnqn)) + continue; + hid = nvme_host_get_hostid(h); + if (hostid && hid && strcmp(hostid, hid)) + continue; + + nvme_subsystem_for_each_ctrl(s, c) { + err = _discovery_config_json(ctx, dctx, h, c, + connect, force); + if (err) { + nvme_msg(ctx, LOG_ERR, + "failed to connect to hostnqn=%s,nqn=%s,%s\n", + nvme_host_get_hostnqn(h), + nvme_subsystem_get_name(s), + nvme_ctrl_get_address(c)); + + if (!ret) + ret = err; + } + } + } + } + + return ret; +} diff --git a/libnvme/src/nvme/fabrics.h b/libnvme/src/nvme/fabrics.h index 27c0a2e213..a7555d808d 100644 --- a/libnvme/src/nvme/fabrics.h +++ b/libnvme/src/nvme/fabrics.h @@ -40,6 +40,9 @@ int nvmf_discovery_ctx_already_connected_set(struct nvmf_discovery_ctx *dctx, void (*already_connected)(struct nvme_host *host, struct nvmf_disc_log_entry *entry, void *user_data)); +int nvmf_discovery_ctx_decide_retry_set(struct nvmf_discovery_ctx *dctx, + bool (*decide_retry)(struct nvmf_discovery_ctx *dctx, int err, + void *user_data)); int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, bool persistent); int nvmf_discovery_ctx_default_fabrics_config_set( @@ -430,6 +433,11 @@ int nvme_parse_uri(const char *str, struct nvme_fabrics_uri **uri); */ void nvme_free_uri(struct nvme_fabrics_uri *uri); +char *nvmf_get_default_trsvcid(const char *transport, bool discovery_ctrl); + int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, bool connect, struct nvme_ctrl *c); +int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, const char *hostnqn, + const char *hostid, bool connect, bool force); #endif /* _LIBNVME_FABRICS_H */ diff --git a/libnvme/src/nvme/private.h b/libnvme/src/nvme/private.h index 781ed8de69..222b9e8b47 100644 --- a/libnvme/src/nvme/private.h +++ b/libnvme/src/nvme/private.h @@ -284,6 +284,8 @@ struct nvmf_discovery_ctx { void (*already_connected)(struct nvme_host *host, struct nvmf_disc_log_entry *entry, void *user_data); + bool (*decide_retry)(struct nvmf_discovery_ctx *dctx, int err, + void *user_data); /* connfiguration */ bool persistent; From eb72bba88ee17d8b7268e272763f6241cb075259 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Thu, 11 Dec 2025 10:08:02 +0100 Subject: [PATCH 04/13] fabrics: move connect config json code to the library Move the connect config json code to the library. Signed-off-by: Daniel Wagner --- fabrics.c | 52 +------------------------------------- libnvme/src/libnvme.map | 1 + libnvme/src/nvme/fabrics.c | 49 +++++++++++++++++++++++++++++++++++ libnvme/src/nvme/fabrics.h | 3 +++ 4 files changed, 54 insertions(+), 51 deletions(-) diff --git a/fabrics.c b/fabrics.c index 62ebe68023..10734c5de8 100644 --- a/fabrics.c +++ b/fabrics.c @@ -766,56 +766,6 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) return ret; } -static int nvme_connect_config(struct nvme_global_ctx *ctx, const char *hostnqn, - const char *hostid, - const struct nvme_fabrics_config *cfg) -{ - const char *hnqn, *hid; - const char *transport; - nvme_host_t h; - nvme_subsystem_t s; - nvme_ctrl_t c, _c; - int ret = 0, err; - - nvme_for_each_host(ctx, h) { - nvme_for_each_subsystem(h, s) { - hnqn = nvme_host_get_hostnqn(h); - if (hostnqn && hnqn && strcmp(hostnqn, hnqn)) - continue; - hid = nvme_host_get_hostid(h); - if (hostid && hid && strcmp(hostid, hid)) - continue; - - nvme_subsystem_for_each_ctrl_safe(s, c, _c) { - transport = nvme_ctrl_get_transport(c); - - /* ignore none fabric transports */ - if (strcmp(transport, "tcp") && - strcmp(transport, "rdma") && - strcmp(transport, "fc")) - continue; - - err = nvmf_connect_ctrl(c); - if (err) { - if (err == -ENVME_CONNECT_ALREADY) - continue; - - fprintf(stderr, - "failed to connect to hostnqn=%s,nqn=%s,%s\n", - nvme_host_get_hostnqn(h), - nvme_subsystem_get_name(s), - nvme_ctrl_get_address(c)); - - if (!ret) - ret = err; - } - } - } - } - - return ret; -} - static void nvme_parse_tls_args(const char *keyring, const char *tls_key, const char *tls_key_identity, struct nvme_fabrics_config *cfg, nvme_ctrl_t c) @@ -944,7 +894,7 @@ int nvmf_connect(const char *desc, int argc, char **argv) trsvcid = nvmf_get_default_trsvcid(transport, false); if (config_file) - return nvme_connect_config(ctx, hostnqn, hostid, &cfg); + return nvmf_connect_config_json(ctx, hostnqn, hostid, &cfg); struct tr_config trcfg = { .subsysnqn = subsysnqn, diff --git a/libnvme/src/libnvme.map b/libnvme/src/libnvme.map index 67f5d93fc3..462d0c7e32 100644 --- a/libnvme/src/libnvme.map +++ b/libnvme/src/libnvme.map @@ -288,6 +288,7 @@ LIBNVME_2_0 { nvmf_add_ctrl; nvmf_adrfam_str; nvmf_cms_str; + nvmf_connect_config_json; nvmf_connect_ctrl; nvmf_connect_disc_entry; nvmf_default_config; diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index 0ae7fc01f1..4f4bdef929 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -2389,3 +2389,52 @@ int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, return ret; } + +int nvmf_connect_config_json(struct nvme_global_ctx *ctx, const char *hostnqn, + const char *hostid, const struct nvme_fabrics_config *cfg) +{ + const char *hnqn, *hid; + const char *transport; + nvme_host_t h; + nvme_subsystem_t s; + nvme_ctrl_t c, _c; + int ret = 0, err; + + nvme_for_each_host(ctx, h) { + nvme_for_each_subsystem(h, s) { + hnqn = nvme_host_get_hostnqn(h); + if (hostnqn && hnqn && strcmp(hostnqn, hnqn)) + continue; + hid = nvme_host_get_hostid(h); + if (hostid && hid && strcmp(hostid, hid)) + continue; + + nvme_subsystem_for_each_ctrl_safe(s, c, _c) { + transport = nvme_ctrl_get_transport(c); + + /* ignore none fabric transports */ + if (strcmp(transport, "tcp") && + strcmp(transport, "rdma") && + strcmp(transport, "fc")) + continue; + + err = nvmf_connect_ctrl(c); + if (err) { + if (err == -ENVME_CONNECT_ALREADY) + continue; + + fprintf(stderr, + "failed to connect to hostnqn=%s,nqn=%s,%s\n", + nvme_host_get_hostnqn(h), + nvme_subsystem_get_name(s), + nvme_ctrl_get_address(c)); + + if (!ret) + ret = err; + } + } + } + } + + return ret; +} diff --git a/libnvme/src/nvme/fabrics.h b/libnvme/src/nvme/fabrics.h index a7555d808d..3e9f45bf9c 100644 --- a/libnvme/src/nvme/fabrics.h +++ b/libnvme/src/nvme/fabrics.h @@ -440,4 +440,7 @@ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, const char *hostnqn, const char *hostid, bool connect, bool force); + +int nvmf_connect_config_json(struct nvme_global_ctx *ctx, const char *hostnqn, + const char *hostid, const struct nvme_fabrics_config *cfg); #endif /* _LIBNVME_FABRICS_H */ From bf36b5d5c9cdcc9244e772ea0b8f36e905dc0157 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Thu, 11 Dec 2025 16:05:12 +0100 Subject: [PATCH 05/13] fabrics: move nbft code to the library Move more discovery code to the library. Signed-off-by: Daniel Wagner --- fabrics.c | 41 +++- libnvme/src/libnvme.map | 4 + libnvme/src/nvme/cleanup.h | 9 + libnvme/src/nvme/fabrics.c | 473 +++++++++++++++++++++++++++++++++++ libnvme/src/nvme/fabrics.h | 16 ++ libnvme/src/nvme/private.h | 2 + meson.build | 1 - nbft.c | 487 ------------------------------------- nbft.h | 19 -- plugins/nbft/nbft-plugin.c | 33 +-- 10 files changed, 558 insertions(+), 527 deletions(-) delete mode 100644 nbft.c delete mode 100644 nbft.h diff --git a/fabrics.c b/fabrics.c index 10734c5de8..c0c1f993d0 100644 --- a/fabrics.c +++ b/fabrics.c @@ -42,7 +42,6 @@ #include "common.h" #include "nvme.h" -#include "nbft.h" #include "nvme-print.h" #include "fabrics.h" #include "util/cleanup.h" @@ -342,6 +341,32 @@ static bool nvmf_decide_retry(struct nvmf_discovery_ctx *dctx, int err, return false; } +static void nvmf_connected(struct nvmf_discovery_ctx *dctx, + struct nvme_ctrl *c, void *user_data) +{ + struct cb_discovery_log_data *dld = user_data; + + if (dld->flags == NORMAL) { + printf("device: %s\n", nvme_ctrl_get_name(c)); + return; + } + +#ifdef CONFIG_JSONC + if (dld->flags == JSON) { + struct json_object *root; + + root = json_create_object(); + + json_object_add_value_string(root, "device", + nvme_ctrl_get_name(c)); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } +#endif +} + static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, bool persistent, struct nvme_fabrics_config *defcfg, @@ -374,6 +399,10 @@ static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, if (err) goto err; + err = nvmf_discovery_ctx_connected_set(dctx, nvmf_connected); + if (err) + goto err; + err = nvmf_discovery_ctx_persistent_set(dctx, persistent); if (err) goto err; @@ -544,6 +573,8 @@ static int nvme_read_config_checked(struct nvme_global_ctx *ctx, return nvme_read_config(ctx, filename); } +#define NBFT_SYSFS_PATH "/sys/firmware/acpi/tables" + /* returns negative errno values */ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) { @@ -654,12 +685,10 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) return ret; if (!device && !transport && !traddr) { - nvmf_discovery_ctx_persistent_set(dctx, true); - if (!nonbft) - ret = discover_from_nbft(ctx, hostnqn, hostid, - hnqn, hid, desc, connect, - &cfg, nbft_path, flags, verbose); + ret = nvmf_discovery_nbft(ctx, dctx, hostnqn, hostid, + hnqn, hid, connect, + &cfg, nbft_path); if (nbft) goto out_free; diff --git a/libnvme/src/libnvme.map b/libnvme/src/libnvme.map index 462d0c7e32..d12bc9b84b 100644 --- a/libnvme/src/libnvme.map +++ b/libnvme/src/libnvme.map @@ -295,6 +295,7 @@ LIBNVME_2_0 { nvmf_discovery; nvmf_discovery_config_json; nvmf_discovery_ctx_already_connected_set; + nvmf_discovery_ctx_connected_set; nvmf_discovery_ctx_create; nvmf_discovery_ctx_decide_retry_set; nvmf_discovery_ctx_default_fabrics_config_set; @@ -302,6 +303,7 @@ LIBNVME_2_0 { nvmf_discovery_ctx_keep_alive_timeout; nvmf_discovery_ctx_max_retries; nvmf_discovery_ctx_persistent_set; + nvmf_discovery_nbft; nvmf_eflags_str; nvmf_exat_ptr_next; nvmf_get_default_trsvcid; @@ -313,6 +315,8 @@ LIBNVME_2_0 { nvmf_hostnqn_generate; nvmf_hostnqn_generate_from_hostid; nvmf_is_registration_supported; + nvmf_nbft_free; + nvmf_nbft_read_files; nvmf_prtype_str; nvmf_qptype_str; nvmf_register_ctrl; diff --git a/libnvme/src/nvme/cleanup.h b/libnvme/src/nvme/cleanup.h index 4c275398d9..2a1e3db00e 100644 --- a/libnvme/src/nvme/cleanup.h +++ b/libnvme/src/nvme/cleanup.h @@ -10,6 +10,8 @@ #include #include +#include "fabrics.h" + #define __cleanup__(fn) __attribute__((cleanup(fn))) #define DECLARE_CLEANUP_FUNC(name, type) \ @@ -44,4 +46,11 @@ static inline void cleanup_fd(int *fd) static inline DEFINE_CLEANUP_FUNC(cleanup_addrinfo, struct addrinfo *, freeaddrinfo) #define _cleanup_addrinfo_ __cleanup__(cleanup_addrinfo) +static inline void free_uri(struct nvme_fabrics_uri **uri) +{ + if (*uri) + nvme_free_uri(*uri); +} +#define _cleanup_uri_ __cleanup__(free_uri) + #endif diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index 4f4bdef929..cb61a86257 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,7 @@ #include "fabrics.h" #include "linux.h" #include "ioctl.h" +#include "nbft.h" #include "nvme/tree.h" #include "util.h" #include "log.h" @@ -253,6 +255,15 @@ int nvmf_discovery_ctx_decide_retry_set(struct nvmf_discovery_ctx *dctx, return 0; } +int nvmf_discovery_ctx_connected_set(struct nvmf_discovery_ctx *dctx, + void (*connected)(struct nvmf_discovery_ctx *dctx, + struct nvme_ctrl *c, void *user_data)) +{ + dctx->connected = connected; + + return 0; +} + int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, bool persistent) { @@ -2438,3 +2449,465 @@ int nvmf_connect_config_json(struct nvme_global_ctx *ctx, const char *hostnqn, return ret; } + +#define NBFT_SYSFS_FILENAME "NBFT*" + +static int nbft_filter(const struct dirent *dent) +{ + return !fnmatch(NBFT_SYSFS_FILENAME, dent->d_name, FNM_PATHNAME); +} + +int nvmf_nbft_read_files(char *path, struct nbft_file_entry **head) +{ + struct nbft_file_entry *entry = NULL; + struct nbft_info *nbft; + struct dirent **dent; + char filename[PATH_MAX]; + int i, count, ret; + + count = scandir(path, &dent, nbft_filter, NULL); + if (count < 0) + return -errno; + + for (i = 0; i < count; i++) { + snprintf(filename, sizeof(filename), "%s/%s", path, + dent[i]->d_name); + + ret = nvme_nbft_read(&nbft, filename); + if (!ret) { + struct nbft_file_entry *new; + + new = calloc(1, sizeof(*new)); + if (!new) + return -ENOMEM; + new->nbft = nbft; + if (entry) { + entry->next = new; + entry = entry->next; + } else { + entry = new; + *head = entry; + } + } + free(dent[i]); + } + free(dent); + return 0; +} + +void nvmf_nbft_free(struct nbft_file_entry *head) +{ + while (head) { + struct nbft_file_entry *next = head->next; + + nvme_nbft_free(head->nbft); + free(head); + + head = next; + } +} + +static bool validate_uri(struct nbft_info_discovery *dd, + struct nvme_fabrics_uri *uri) +{ + if (!uri) { + fprintf(stderr, + "Discovery Descriptor %d: failed to parse URI %s\n", + dd->index, dd->uri); + return false; + } + if (strcmp(uri->scheme, "nvme") != 0) { + fprintf(stderr, + "Discovery Descriptor %d: unsupported scheme '%s'\n", + dd->index, uri->scheme); + return false; + } + if (!uri->protocol || strcmp(uri->protocol, "tcp") != 0) { + fprintf(stderr, + "Discovery Descriptor %d: unsupported transport '%s'\n", + dd->index, uri->protocol); + return false; + } + + return true; +} + +static int nbft_connect(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, struct nvme_host *h, + struct nvmf_disc_log_entry *e, + struct nbft_info_subsystem_ns *ss, struct tr_config *trcfg, + struct nvme_fabrics_config *cfg) +{ + nvme_ctrl_t c; + int saved_log_level; + bool saved_log_tstamp; + bool saved_log_pid; + int ret; + + saved_log_level = nvme_get_logging_level(ctx, &saved_log_tstamp, + &saved_log_pid); + + /* Already connected ? */ + c = lookup_ctrl(h, trcfg); + if (c && nvme_ctrl_get_name(c)) + return 0; + + ret = nvme_create_ctrl(ctx, trcfg->subsysnqn, trcfg->transport, + trcfg->traddr, trcfg->host_traddr, + trcfg->host_iface, trcfg->trsvcid, &c); + if (ret) + return ret; + + /* Pause logging for unavailable SSNSs */ + if (ss && ss->unavailable && saved_log_level < 1) + nvme_init_logging(ctx, -1, false, false); + + if (e) { + if (e->trtype == NVMF_TRTYPE_TCP && + e->tsas.tcp.sectype != NVMF_TCP_SECTYPE_NONE) + cfg->tls = true; + } + + ret = nvmf_add_ctrl(h, c, cfg); + + /* Resume logging */ + if (ss && ss->unavailable && saved_log_level < 1) + nvme_init_logging(ctx, + saved_log_level, + saved_log_pid, + saved_log_tstamp); + + if (ret) { + nvme_free_ctrl(c); + /* + * In case this SSNS was marked as 'unavailable' and + * our connection attempt has failed, ignore it. + */ + if (ss && ss->unavailable) { + nvme_msg(ctx, LOG_INFO, + "SSNS %d reported as unavailable, skipping\n", + ss->index); + return 0; + } + return ret; + } + + if (dctx->connected) + dctx->connected(dctx, c, dctx->user_data); + + return 0; +} + +static int nbft_discovery(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, struct nbft_info_discovery *dd, + struct nvme_host *h, struct nvme_ctrl *c, + struct nvme_fabrics_config *defcfg, struct tr_config *deftrcfg) +{ + struct nvmf_discovery_log *log = NULL; + int ret; + int i; + + struct nvme_get_discovery_args args = { + .c = c, + .args_size = sizeof(args), + .max_retries = 10 /* MAX_DISC_RETRIES */, + .result = 0, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lsp = 0, + }; + + ret = nvmf_get_discovery_wargs(&args, &log); + if (ret) { + nvme_msg(ctx, LOG_ERR, + "Discovery Descriptor %d: failed to get discovery log: %s\n", + dd->index, nvme_strerror(ret)); + return ret; + } + + for (i = 0; i < le64_to_cpu(log->numrec); i++) { + struct nvmf_disc_log_entry *e = &log->entries[i]; + nvme_ctrl_t cl; + int tmo = defcfg->keep_alive_tmo; + + struct tr_config trcfg = { + .subsysnqn = e->subnqn, + .transport = nvmf_trtype_str(e->trtype), + .traddr = e->traddr, + .host_traddr = deftrcfg->host_traddr, + .host_iface = deftrcfg->host_iface, + .trsvcid = e->trsvcid, + }; + + if (e->subtype == NVME_NQN_CURR) + continue; + + /* Already connected ? */ + cl = lookup_ctrl(h, &trcfg); + if (cl && nvme_ctrl_get_name(cl)) + continue; + + /* Skip connect if the transport types don't match */ + if (strcmp(nvme_ctrl_get_transport(c), + nvmf_trtype_str(e->trtype))) + continue; + + if (e->subtype == NVME_NQN_DISC) { + nvme_ctrl_t child; + + ret = nvmf_connect_disc_entry(h, e, defcfg, + NULL, &child); + if (ret) + continue; + nbft_discovery(ctx, dctx, dd, h, child, defcfg, &trcfg); + nvme_disconnect_ctrl(child); + nvme_free_ctrl(child); + } else { + ret = nbft_connect(ctx, dctx, h, e, NULL, + &trcfg, defcfg); + + /* + * With TCP/DHCP, it can happen that the OS + * obtains a different local IP address than the + * firmware had. Retry without host_traddr. + */ + if (ret == -ENVME_CONNECT_ADDRNOTAVAIL && + !strcmp(trcfg.transport, "tcp") && + strlen(dd->hfi->tcp_info.dhcp_server_ipaddr) > 0) { + const char *htradr = trcfg.host_traddr; + + trcfg.host_traddr = NULL; + ret = nbft_connect(ctx, dctx, h, e, NULL, + &trcfg, defcfg); + + if (ret == 0) + nvme_msg(ctx, LOG_INFO, + "Discovery Descriptor %d: connect with host_traddr=\"%s\" failed, success after omitting host_traddr\n", + dd->index, + htradr); + } + + if (ret) + nvme_msg(ctx, LOG_ERR, + "Discovery Descriptor %d: no controller found\n", + dd->index); + if (ret == -ENOMEM) + break; + } + + defcfg->keep_alive_tmo = tmo; + } + + free(log); + return 0; +} + +int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, char *hostnqn_arg, + char *hostid_arg, char *hostnqn_sys, char *hostid_sys, + bool connect, struct nvme_fabrics_config *cfg, char *nbft_path) +{ + char *hostnqn = NULL, *hostid = NULL, *host_traddr = NULL; + nvme_host_t h; + int ret, rr, i; + char uuid[NVME_UUID_LEN_STRING]; + struct nbft_file_entry *entry = NULL; + struct nbft_info_subsystem_ns **ss; + struct nbft_info_hfi *hfi; + struct nbft_info_discovery **dd; + + if (!connect) + /* TODO: print discovery-type info from NBFT tables */ + return 0; + + ret = nvmf_nbft_read_files(nbft_path, &entry); + if (ret) { + if (ret != -ENOENT) + nvme_msg(ctx, LOG_ERR, + "Failed to access ACPI tables directory\n"); + else + ret = 0; /* nothing to connect */ + goto out_free; + } + + for (; entry; entry = entry->next) { + if (hostnqn_arg) + hostnqn = hostnqn_arg; + else { + hostnqn = entry->nbft->host.nqn; + if (!hostnqn) + hostnqn = hostnqn_sys; + } + + if (hostid_arg) + hostid = hostid_arg; + else if (*entry->nbft->host.id) { + ret = nvme_uuid_to_string(entry->nbft->host.id, uuid); + if (!ret) + hostid = uuid; + else + hostid = hostid_sys; + } + + h = nvme_lookup_host(ctx, hostnqn, hostid); + if (!h) { + ret = -ENOENT; + goto out_free; + } + + /* Subsystem Namespace Descriptor List */ + for (ss = entry->nbft->subsystem_ns_list; ss && *ss; ss++) + for (i = 0; i < (*ss)->num_hfis; i++) { + hfi = (*ss)->hfis[i]; + + /* Skip discovery NQN records */ + if (strcmp((*ss)->subsys_nqn, + NVME_DISC_SUBSYS_NAME) == 0) { + nvme_msg(ctx, LOG_INFO, + "SSNS %d points to well-known discovery NQN, skipping\n", + (*ss)->index); + continue; + } + + host_traddr = NULL; + if (!cfg->host_traddr && + !strncmp((*ss)->transport, "tcp", 3)) + host_traddr = hfi->tcp_info.ipaddr; + + struct tr_config trcfg = { + .subsysnqn = (*ss)->subsys_nqn, + .transport = (*ss)->transport, + .traddr = (*ss)->traddr, + .host_traddr = host_traddr, + .host_iface = NULL, + .trsvcid = (*ss)->trsvcid, + }; + + rr = nbft_connect(ctx, dctx, h, NULL, + *ss, &trcfg, cfg); + + /* + * With TCP/DHCP, it can happen that the OS + * obtains a different local IP address than the + * firmware had. Retry without host_traddr. + */ + if (rr == -ENVME_CONNECT_ADDRNOTAVAIL && + !strcmp(trcfg.transport, "tcp") && + strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { + trcfg.host_traddr = NULL; + + rr = nbft_connect(ctx, dctx, h, NULL, + *ss, &trcfg, cfg); + + if (rr == 0) + nvme_msg(ctx, LOG_INFO, + "SSNS %d: connect with host_traddr=\"%s\" failed, success after omitting host_traddr\n", + (*ss)->index, + host_traddr); + } + + if (rr) { + nvme_msg(ctx, LOG_ERR, + "SSNS %d: no controller found\n", + (*ss)->index); + /* report an error */ + ret = rr; + } + + if (rr == -ENOMEM) + goto out_free; + } + + /* Discovery Descriptor List */ + for (dd = entry->nbft->discovery_list; dd && *dd; dd++) { + _cleanup_uri_ struct nvme_fabrics_uri *uri = NULL; + _cleanup_free_ char *trsvcid = NULL; + bool persistent = false; + bool linked = false; + nvme_ctrl_t c; + + /* only perform discovery when no SSNS record references it */ + for (ss = entry->nbft->subsystem_ns_list; + ss && *ss; ss++) + if ((*ss)->discovery && + (*ss)->discovery->index == (*dd)->index && + /* unavailable boot attempts are not discovered + * and may get transferred along with a well-known + * discovery NQN into an SSNS record. + */ + strcmp((*ss)->subsys_nqn, + NVME_DISC_SUBSYS_NAME) != 0) { + linked = true; + break; + } + if (linked) + continue; + + hfi = (*dd)->hfi; + ret = nvme_parse_uri((*dd)->uri, &uri); + if (ret) + continue; + if (!validate_uri(*dd, uri)) + continue; + + host_traddr = NULL; + if (!cfg->host_traddr && + !strncmp(uri->protocol, "tcp", 3)) + host_traddr = hfi->tcp_info.ipaddr; + if (uri->port > 0) { + if (asprintf(&trsvcid, "%d", uri->port) < 0) { + ret = -ENOMEM; + goto out_free; + } + } else + trsvcid = + strdup(nvmf_get_default_trsvcid( + uri->protocol, true)); + + struct tr_config trcfg = { + .subsysnqn = NVME_DISC_SUBSYS_NAME, + .transport = uri->protocol, + .traddr = uri->host, + .host_traddr = host_traddr, + .host_iface = NULL, + .trsvcid = trsvcid, + }; + + /* Lookup existing discovery controller */ + c = lookup_ctrl(h, &trcfg); + if (c && nvme_ctrl_get_name(c)) + persistent = true; + + if (!c) { + ret = nvmf_create_discovery_ctrl(ctx, dctx, h, + cfg, &trcfg, &c); + if (ret == -ENVME_CONNECT_ADDRNOTAVAIL && + !strcmp(trcfg.transport, "tcp") && + strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { + trcfg.host_traddr = NULL; + ret = nvmf_create_discovery_ctrl(ctx, + dctx, h, cfg, &trcfg, &c); + } + } else + ret = 0; + + if (ret) { + nvme_msg(ctx, LOG_ERR, + "Discovery Descriptor %d: failed to add discovery controller: %s\n", + (*dd)->index, nvme_strerror(-ret)); + goto out_free; + } + + rr = nbft_discovery(ctx, dctx, *dd, h, c, cfg, &trcfg); + if (!persistent) + nvme_disconnect_ctrl(c); + nvme_free_ctrl(c); + if (rr == -ENOMEM) { + ret = rr; + goto out_free; + } + } + } +out_free: + nvmf_nbft_free(entry); + return ret; +} diff --git a/libnvme/src/nvme/fabrics.h b/libnvme/src/nvme/fabrics.h index 3e9f45bf9c..16b0e9fafb 100644 --- a/libnvme/src/nvme/fabrics.h +++ b/libnvme/src/nvme/fabrics.h @@ -43,6 +43,9 @@ int nvmf_discovery_ctx_already_connected_set(struct nvmf_discovery_ctx *dctx, int nvmf_discovery_ctx_decide_retry_set(struct nvmf_discovery_ctx *dctx, bool (*decide_retry)(struct nvmf_discovery_ctx *dctx, int err, void *user_data)); +int nvmf_discovery_ctx_connected_set(struct nvmf_discovery_ctx *dctx, + void (*connected)(struct nvmf_discovery_ctx *dctx, + struct nvme_ctrl *c, void *user_data)); int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, bool persistent); int nvmf_discovery_ctx_default_fabrics_config_set( @@ -440,7 +443,20 @@ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, const char *hostnqn, const char *hostid, bool connect, bool force); +int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, char *hostnqn_arg, + char *hostid_arg, char *hostnqn_sys, char *hostid_sys, + bool connect, struct nvme_fabrics_config *cfg, char *nbft_path); int nvmf_connect_config_json(struct nvme_global_ctx *ctx, const char *hostnqn, const char *hostid, const struct nvme_fabrics_config *cfg); + +struct nbft_file_entry { + struct nbft_file_entry *next; + struct nbft_info *nbft; +}; + +int nvmf_nbft_read_files(char *path, struct nbft_file_entry **head); +void nvmf_nbft_free(struct nbft_file_entry *head); + #endif /* _LIBNVME_FABRICS_H */ diff --git a/libnvme/src/nvme/private.h b/libnvme/src/nvme/private.h index 222b9e8b47..83ab63b97e 100644 --- a/libnvme/src/nvme/private.h +++ b/libnvme/src/nvme/private.h @@ -286,6 +286,8 @@ struct nvmf_discovery_ctx { void *user_data); bool (*decide_retry)(struct nvmf_discovery_ctx *dctx, int err, void *user_data); + void (*connected)(struct nvmf_discovery_ctx *dctx, struct nvme_ctrl *c, + void *user_data); /* connfiguration */ bool persistent; diff --git a/meson.build b/meson.build index cc8ee695f0..c0c0ca0703 100644 --- a/meson.build +++ b/meson.build @@ -502,7 +502,6 @@ if want_nvme subdir('util') # declares: util_sources sources = [ - 'nbft.c', 'fabrics.c', 'nvme.c', 'nvme-models.c', diff --git a/nbft.c b/nbft.c deleted file mode 100644 index f683f2dfa4..0000000000 --- a/nbft.c +++ /dev/null @@ -1,487 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include -#include -#include - -#include - -#include "common.h" -#include "nvme.h" -#include "nbft.h" -#include "fabrics.h" -#include "nvme-print.h" - -#include "util/types.h" -#include "logging.h" - -#define NBFT_SYSFS_FILENAME "NBFT*" - -static void print_connect_msg(nvme_ctrl_t c) -{ - printf("device: %s\n", nvme_ctrl_get_name(c)); -} - -static void json_connect_msg(nvme_ctrl_t c) -{ -#ifdef CONFIG_JSONC - struct json_object *root; - - root = json_create_object(); - json_object_add_value_string(root, "device", nvme_ctrl_get_name(c)); - - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -#endif -} - -int nbft_filter(const struct dirent *dent) -{ - return !fnmatch(NBFT_SYSFS_FILENAME, dent->d_name, FNM_PATHNAME); -} - -int read_nbft_files(struct list_head *nbft_list, char *path) -{ - struct dirent **dent; - char filename[PATH_MAX]; - int i, count, ret; - struct nbft_file_entry *entry; - struct nbft_info *nbft; - - count = scandir(path, &dent, nbft_filter, NULL); - if (count < 0) - return -errno; - - for (i = 0; i < count; i++) { - snprintf(filename, sizeof(filename), "%s/%s", path, dent[i]->d_name); - ret = nvme_nbft_read(&nbft, filename); - if (!ret) { - entry = calloc(1, sizeof(*entry)); - entry->nbft = nbft; - list_add_tail(nbft_list, &entry->node); - } - free(dent[i]); - } - free(dent); - return 0; -} - -void free_nbfts(struct list_head *nbft_list) -{ - struct nbft_file_entry *entry; - - while ((entry = list_pop(nbft_list, struct nbft_file_entry, node))) { - nvme_nbft_free(entry->nbft); - free(entry); - } -} - -static bool validate_uri(struct nbft_info_discovery *dd, - struct nvme_fabrics_uri *uri) -{ - if (!uri) { - fprintf(stderr, - "Discovery Descriptor %d: failed to parse URI %s\n", - dd->index, dd->uri); - return false; - } - if (strcmp(uri->scheme, "nvme") != 0) { - fprintf(stderr, - "Discovery Descriptor %d: unsupported scheme '%s'\n", - dd->index, uri->scheme); - return false; - } - if (!uri->protocol || strcmp(uri->protocol, "tcp") != 0) { - fprintf(stderr, - "Discovery Descriptor %d: unsupported transport '%s'\n", - dd->index, uri->protocol); - return false; - } - - return true; -} - -static int do_connect(struct nvme_global_ctx *ctx, - nvme_host_t h, - struct nvmf_disc_log_entry *e, - struct nbft_info_subsystem_ns *ss, - struct tr_config *trcfg, - struct nvme_fabrics_config *cfg, - nvme_print_flags_t flags, - unsigned int verbose) -{ - nvme_ctrl_t c; - int saved_log_level = log_level; - bool saved_log_pid = false; - bool saved_log_tstamp = false; - int ret; - - /* Already connected ? */ - c = lookup_ctrl(h, trcfg); - if (c && nvme_ctrl_get_name(c)) - return 0; - - ret = nvme_create_ctrl(ctx, trcfg->subsysnqn, trcfg->transport, - trcfg->traddr, trcfg->host_traddr, - trcfg->host_iface, trcfg->trsvcid, &c); - if (ret) - return ret; - - /* Pause logging for unavailable SSNSs */ - if (ss && ss->unavailable && verbose < 1) { - saved_log_level = nvme_get_logging_level(ctx, - &saved_log_pid, - &saved_log_tstamp); - nvme_init_logging(ctx, -1, false, false); - } - - if (e) { - if (e->trtype == NVMF_TRTYPE_TCP && - e->tsas.tcp.sectype != NVMF_TCP_SECTYPE_NONE) - cfg->tls = true; - } - - ret = nvmf_add_ctrl(h, c, cfg); - - /* Resume logging */ - if (ss && ss->unavailable && verbose < 1) - nvme_init_logging(ctx, - saved_log_level, - saved_log_pid, - saved_log_tstamp); - - if (ret) { - nvme_free_ctrl(c); - /* - * In case this SSNS was marked as 'unavailable' and - * our connection attempt has failed, ignore it. - */ - if (ss && ss->unavailable) { - if (verbose >= 1) - fprintf(stderr, - "SSNS %d reported as unavailable, skipping\n", - ss->index); - return 0; - } - return ret; - } - - if (flags == NORMAL) - print_connect_msg(c); - else if (flags == JSON) - json_connect_msg(c); - - return 0; -} - -static int do_discover(struct nbft_info_discovery *dd, - struct nvme_global_ctx *ctx, - nvme_host_t h, - nvme_ctrl_t c, - struct nvme_fabrics_config *defcfg, - struct tr_config *deftrcfg, - nvme_print_flags_t flags, - unsigned int verbose) -{ - struct nvmf_discovery_log *log = NULL; - int ret; - int i; - - struct nvme_get_discovery_args args = { - .c = c, - .args_size = sizeof(args), - .max_retries = 10 /* MAX_DISC_RETRIES */, - .result = 0, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lsp = 0, - }; - - ret = nvmf_get_discovery_wargs(&args, &log); - if (ret) { - fprintf(stderr, - "Discovery Descriptor %d: failed to get discovery log: %s\n", - dd->index, nvme_strerror(ret)); - return ret; - } - - for (i = 0; i < le64_to_cpu(log->numrec); i++) { - struct nvmf_disc_log_entry *e = &log->entries[i]; - nvme_ctrl_t cl; - int tmo = defcfg->keep_alive_tmo; - - struct tr_config trcfg = { - .subsysnqn = e->subnqn, - .transport = nvmf_trtype_str(e->trtype), - .traddr = e->traddr, - .host_traddr = deftrcfg->host_traddr, - .host_iface = deftrcfg->host_iface, - .trsvcid = e->trsvcid, - }; - - if (e->subtype == NVME_NQN_CURR) - continue; - - /* Already connected ? */ - cl = lookup_ctrl(h, &trcfg); - if (cl && nvme_ctrl_get_name(cl)) - continue; - - /* Skip connect if the transport types don't match */ - if (strcmp(nvme_ctrl_get_transport(c), - nvmf_trtype_str(e->trtype))) - continue; - - if (e->subtype == NVME_NQN_DISC) { - nvme_ctrl_t child; - - ret = nvmf_connect_disc_entry(h, e, defcfg, NULL, &child); - if (ret) - continue; - do_discover(dd, ctx, h, child, defcfg, &trcfg, - flags, verbose); - nvme_disconnect_ctrl(child); - nvme_free_ctrl(child); - } else { - ret = do_connect(ctx, h, e, NULL, &trcfg, - defcfg, flags, verbose); - - /* - * With TCP/DHCP, it can happen that the OS - * obtains a different local IP address than the - * firmware had. Retry without host_traddr. - */ - if (ret == -ENVME_CONNECT_ADDRNOTAVAIL && - !strcmp(trcfg.transport, "tcp") && - strlen(dd->hfi->tcp_info.dhcp_server_ipaddr) > 0) { - const char *htradr = trcfg.host_traddr; - - trcfg.host_traddr = NULL; - ret = do_connect(ctx, h, e, NULL, &trcfg, - defcfg, flags, verbose); - - if (ret == 0 && verbose >= 1) - fprintf(stderr, - "Discovery Descriptor %d: connect with host_traddr=\"%s\" failed, success after omitting host_traddr\n", - dd->index, - htradr); - } - - if (ret) - fprintf(stderr, "Discovery Descriptor %d: no controller found\n", - dd->index); - if (ret == -ENOMEM) - break; - } - - defcfg->keep_alive_tmo = tmo; - } - - free(log); - return 0; -} - -int discover_from_nbft(struct nvme_global_ctx *ctx, char *hostnqn_arg, - char *hostid_arg, char *hostnqn_sys, char *hostid_sys, - const char *desc, bool connect, - struct nvme_fabrics_config *cfg, char *nbft_path, - nvme_print_flags_t flags, unsigned int verbose) -{ - char *hostnqn = NULL, *hostid = NULL, *host_traddr = NULL; - nvme_host_t h; - int ret, rr, i; - struct list_head nbft_list; - struct nbft_file_entry *entry = NULL; - struct nbft_info_subsystem_ns **ss; - struct nbft_info_hfi *hfi; - struct nbft_info_discovery **dd; - - if (!connect) - /* TODO: print discovery-type info from NBFT tables */ - return 0; - - list_head_init(&nbft_list); - ret = read_nbft_files(&nbft_list, nbft_path); - if (ret) { - if (ret != -ENOENT) - nvme_show_perror("Failed to access ACPI tables directory"); - else - ret = 0; /* nothing to connect */ - goto out_free; - } - - list_for_each(&nbft_list, entry, node) { - if (hostnqn_arg) - hostnqn = hostnqn_arg; - else { - hostnqn = entry->nbft->host.nqn; - if (!hostnqn) - hostnqn = hostnqn_sys; - } - - if (hostid_arg) - hostid = hostid_arg; - else if (*entry->nbft->host.id) { - hostid = (char *)util_uuid_to_string(entry->nbft->host.id); - if (!hostid) - hostid = hostid_sys; - } - - h = nvme_lookup_host(ctx, hostnqn, hostid); - if (!h) { - ret = -ENOENT; - goto out_free; - } - - /* Subsystem Namespace Descriptor List */ - for (ss = entry->nbft->subsystem_ns_list; ss && *ss; ss++) - for (i = 0; i < (*ss)->num_hfis; i++) { - hfi = (*ss)->hfis[i]; - - /* Skip discovery NQN records */ - if (strcmp((*ss)->subsys_nqn, NVME_DISC_SUBSYS_NAME) == 0) { - if (verbose >= 1) - fprintf(stderr, - "SSNS %d points to well-known discovery NQN, skipping\n", - (*ss)->index); - continue; - } - - host_traddr = NULL; - if (!cfg->host_traddr && - !strncmp((*ss)->transport, "tcp", 3)) - host_traddr = hfi->tcp_info.ipaddr; - - struct tr_config trcfg = { - .subsysnqn = (*ss)->subsys_nqn, - .transport = (*ss)->transport, - .traddr = (*ss)->traddr, - .host_traddr = host_traddr, - .host_iface = NULL, - .trsvcid = (*ss)->trsvcid, - }; - - rr = do_connect(ctx, h, NULL, *ss, &trcfg, - cfg, flags, verbose); - - /* - * With TCP/DHCP, it can happen that the OS - * obtains a different local IP address than the - * firmware had. Retry without host_traddr. - */ - if (rr == -ENVME_CONNECT_ADDRNOTAVAIL && - !strcmp(trcfg.transport, "tcp") && - strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { - trcfg.host_traddr = NULL; - - rr = do_connect(ctx, h, NULL, *ss, &trcfg, - cfg, flags, verbose); - - if (rr == 0 && verbose >= 1) - fprintf(stderr, - "SSNS %d: connect with host_traddr=\"%s\" failed, success after omitting host_traddr\n", - (*ss)->index, - host_traddr); - } - - if (rr) { - fprintf(stderr, "SSNS %d: no controller found\n", - (*ss)->index); - /* report an error */ - ret = rr; - } - - if (rr == -ENOMEM) - goto out_free; - } - - /* Discovery Descriptor List */ - for (dd = entry->nbft->discovery_list; dd && *dd; dd++) { - nvme_ctrl_t c; - bool linked = false; - bool persistent = false; - _cleanup_uri_ struct nvme_fabrics_uri *uri = NULL; - _cleanup_free_ char *trsvcid = NULL; - - /* only perform discovery when no SSNS record references it */ - for (ss = entry->nbft->subsystem_ns_list; ss && *ss; ss++) - if ((*ss)->discovery && - (*ss)->discovery->index == (*dd)->index && - /* unavailable boot attempts are not discovered - * and may get transferred along with a well-known - * discovery NQN into an SSNS record. - */ - strcmp((*ss)->subsys_nqn, NVME_DISC_SUBSYS_NAME) != 0) { - linked = true; - break; - } - if (linked) - continue; - - hfi = (*dd)->hfi; - ret = nvme_parse_uri((*dd)->uri, &uri); - if (ret) - continue; - if (!validate_uri(*dd, uri)) - continue; - - host_traddr = NULL; - if (!cfg->host_traddr && - !strncmp(uri->protocol, "tcp", 3)) - host_traddr = hfi->tcp_info.ipaddr; - if (uri->port > 0) { - if (asprintf(&trsvcid, "%d", uri->port) < 0) { - ret = -ENOMEM; - goto out_free; - } - } else - trsvcid = strdup(nvmf_get_default_trsvcid(uri->protocol, true)); - - struct tr_config trcfg = { - .subsysnqn = NVME_DISC_SUBSYS_NAME, - .transport = uri->protocol, - .traddr = uri->host, - .host_traddr = host_traddr, - .host_iface = NULL, - .trsvcid = trsvcid, - }; - - /* Lookup existing discovery controller */ - c = lookup_ctrl(h, &trcfg); - if (c && nvme_ctrl_get_name(c)) - persistent = true; - - if (!c) { - ret = nvmf_create_discover_ctrl(ctx, h, cfg, &trcfg, &c); - if (ret == -ENVME_CONNECT_ADDRNOTAVAIL && - !strcmp(trcfg.transport, "tcp") && - strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { - trcfg.host_traddr = NULL; - ret = nvmf_create_discover_ctrl(ctx, h, cfg, &trcfg, &c); - } - } else - ret = 0; - - if (ret) { - fprintf(stderr, - "Discovery Descriptor %d: failed to add discovery controller: %s\n", - (*dd)->index, nvme_strerror(-ret)); - goto out_free; - } - - rr = do_discover(*dd, ctx, h, c, cfg, &trcfg, - flags, verbose); - if (!persistent) - nvme_disconnect_ctrl(c); - nvme_free_ctrl(c); - if (rr == -ENOMEM) { - ret = rr; - goto out_free; - } - } - } -out_free: - free_nbfts(&nbft_list); - return ret; -} diff --git a/nbft.h b/nbft.h deleted file mode 100644 index 412ce67f6e..0000000000 --- a/nbft.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#include - -#define NBFT_SYSFS_PATH "/sys/firmware/acpi/tables" - -struct nbft_file_entry { - struct list_node node; - struct nbft_info *nbft; -}; - -int read_nbft_files(struct list_head *nbft_list, char *path); -void free_nbfts(struct list_head *nbft_list); - -extern int discover_from_nbft(struct nvme_global_ctx *ctx, char *hostnqn_arg, - char *hostid_arg, char *hostnqn_sys, - char *hostid_sys, const char *desc, bool connect, - struct nvme_fabrics_config *cfg, char *nbft_path, - nvme_print_flags_t flags, unsigned int verbose); diff --git a/plugins/nbft/nbft-plugin.c b/plugins/nbft/nbft-plugin.c index f6952348a5..1770bd7607 100644 --- a/plugins/nbft/nbft-plugin.c +++ b/plugins/nbft/nbft-plugin.c @@ -7,7 +7,6 @@ #include #include "nvme-print.h" #include "nvme.h" -#include "nbft.h" #include "fabrics.h" #include "logging.h" @@ -321,24 +320,25 @@ static struct json_object *nbft_to_json(struct nbft_info *nbft, bool show_subsys return NULL; } -static int json_show_nbfts(struct list_head *nbft_list, bool show_subsys, +static int json_show_nbfts(struct nbft_file_entry *head, bool show_subsys, bool show_hfi, bool show_discovery) { struct json_object *nbft_json_array, *nbft_json; - struct nbft_file_entry *entry = NULL; nbft_json_array = json_create_array(); if (!nbft_json_array) return -ENOMEM; - list_for_each(nbft_list, entry, node) { - nbft_json = nbft_to_json(entry->nbft, show_subsys, show_hfi, show_discovery); + while (head) { + nbft_json = nbft_to_json(head->nbft, show_subsys, + show_hfi, show_discovery); if (!nbft_json) goto fail; if (json_object_array_add(nbft_json_array, nbft_json)) { json_free_object(nbft_json); goto fail; } + head = head->next; } json_print_object(nbft_json_array, NULL); @@ -515,23 +515,26 @@ static void normal_show_nbft(struct nbft_info *nbft, bool show_subsys, } } -static void normal_show_nbfts(struct list_head *nbft_list, bool show_subsys, +static void normal_show_nbfts(struct nbft_file_entry *head, bool show_subsys, bool show_hfi, bool show_discovery) { bool not_first = false; - struct nbft_file_entry *entry = NULL; - list_for_each(nbft_list, entry, node) { + while (head) { if (not_first) printf("\n"); - normal_show_nbft(entry->nbft, show_subsys, show_hfi, show_discovery); + normal_show_nbft(head->nbft, show_subsys, show_hfi, show_discovery); + head = head->next; not_first = true; } } +#define NBFT_SYSFS_PATH "/sys/firmware/acpi/tables" + int show_nbft(int argc, char **argv, struct command *acmd, struct plugin *plugin) { const char *desc = "Display contents of the ACPI NBFT files."; + struct nbft_file_entry *head = NULL; struct list_head nbft_list; char *format = "normal"; char *nbft_path = NBFT_SYSFS_PATH; @@ -565,13 +568,15 @@ int show_nbft(int argc, char **argv, struct command *acmd, struct plugin *plugin show_subsys = show_hfi = show_discovery = true; list_head_init(&nbft_list); - ret = read_nbft_files(&nbft_list, nbft_path); - if (!ret) { + ret = nvmf_nbft_read_files(nbft_path, &head); + if (!ret && head) { if (flags == NORMAL) - normal_show_nbfts(&nbft_list, show_subsys, show_hfi, show_discovery); + normal_show_nbfts(head, show_subsys, + show_hfi, show_discovery); else if (flags == JSON) - ret = json_show_nbfts(&nbft_list, show_subsys, show_hfi, show_discovery); - free_nbfts(&nbft_list); + ret = json_show_nbfts(head, show_subsys, + show_hfi, show_discovery); + nvmf_nbft_free(head); } return ret; } From 22fe1522cec54e643eb4ebffffe1df308e873f42 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Fri, 12 Dec 2025 13:47:01 +0100 Subject: [PATCH 06/13] fabrics: move host_traddr and host_iface to ctrl The host_traddr and host_iface are property of the controller not of the fabric configuration. Because the discovery API was stable, it ended up in the fabric configuration. The discovery API is reworked thus we can move it to where it actually belongs. See also 9a4dd3828091 ("Move 'host_traddr' and 'host_iface' into fabrics configuration"). Signed-off-by: Daniel Wagner --- fabrics.c | 49 +++++++++++++++++++----------- libnvme/libnvme/nvme.i | 8 ----- libnvme/src/libnvme.map | 3 +- libnvme/src/nvme/fabrics.c | 61 ++++++++++++++++++++++---------------- libnvme/src/nvme/fabrics.h | 24 +++------------ libnvme/src/nvme/private.h | 4 +++ libnvme/src/nvme/tree.c | 40 ++++++++++++------------- 7 files changed, 98 insertions(+), 91 deletions(-) diff --git a/fabrics.c b/fabrics.c index c0c1f993d0..463febc5e5 100644 --- a/fabrics.c +++ b/fabrics.c @@ -100,8 +100,8 @@ static const char *nvmf_context = "execution context identification string"; OPT_STRING("nqn", 'n', "STR", &subsysnqn, nvmf_nqn), \ OPT_STRING("traddr", 'a', "STR", &traddr, nvmf_traddr), \ OPT_STRING("trsvcid", 's', "STR", &trsvcid, nvmf_trsvcid), \ - OPT_STRING("host-traddr", 'w', "STR", &c.host_traddr, nvmf_htraddr), \ - OPT_STRING("host-iface", 'f', "STR", &c.host_iface, nvmf_hiface), \ + OPT_STRING("host-traddr", 'w', "STR", &host_traddr, nvmf_htraddr), \ + OPT_STRING("host-iface", 'f', "STR", &host_iface, nvmf_hiface), \ OPT_STRING("hostnqn", 'q', "STR", &hostnqn, nvmf_hostnqn), \ OPT_STRING("hostid", 'I', "STR", &hostid, nvmf_hostid), \ OPT_STRING("dhchap-secret", 'S', "STR", &hostkey, nvmf_hostkey), \ @@ -369,6 +369,7 @@ static void nvmf_connected(struct nvmf_discovery_ctx *dctx, static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, bool persistent, + const char *host_traddr, const char *host_iface, struct nvme_fabrics_config *defcfg, void *user_data, struct nvmf_discovery_ctx **dctxp) { @@ -407,6 +408,14 @@ static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, if (err) goto err; + err = nvmf_discovery_ctx_host_traddr_set(dctx, host_traddr); + if (err) + goto err; + + err = nvmf_discovery_ctx_host_iface_set(dctx, host_iface); + if (err) + goto err; + err = nvmf_discovery_ctx_default_fabrics_config_set(dctx, defcfg); if (err) goto err; @@ -427,6 +436,7 @@ static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, char *hostnqn = NULL, *hostid = NULL, *hostkey = NULL; char *subsysnqn = NULL, *keyring = NULL, *tls_key = NULL; _cleanup_free_ struct nvmf_discovery_ctx *dctx = NULL; + char *host_iface = NULL, *host_traddr = NULL; char *tls_key_identity = NULL; char *ptr, **argv, *p, line[4096]; int argc, ret = 0; @@ -491,8 +501,8 @@ static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, .subsysnqn = subsysnqn, .transport = transport, .traddr = traddr, - .host_traddr = cfg.host_traddr, - .host_iface = cfg.host_iface, + .host_traddr = host_traddr, + .host_iface = host_iface, .trsvcid = trsvcid, }; @@ -500,7 +510,8 @@ static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, .flags = flags, .raw = raw, }; - ret = create_discovery_log_ctx(ctx, true, &cfg, &dld, &dctx); + ret = create_discovery_log_ctx(ctx, true, host_traddr, + host_iface, &cfg, &dld, &dctx); if (ret) return ret; @@ -581,6 +592,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) char *subsysnqn = NVME_DISC_SUBSYS_NAME; char *hostnqn = NULL, *hostid = NULL, *hostkey = NULL; char *transport = NULL, *traddr = NULL, *trsvcid = NULL; + char *host_iface = NULL, *host_traddr = NULL; char *keyring = NULL, *tls_key = NULL; char *tls_key_identity = NULL; char *config_file = PATH_NVMF_CONFIG; @@ -680,7 +692,8 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) .raw = raw, }; - ret = create_discovery_log_ctx(ctx, persistent, &cfg, &dld, &dctx); + ret = create_discovery_log_ctx(ctx, persistent, host_traddr, + host_iface, &cfg, &dld, &dctx); if (ret) return ret; @@ -709,8 +722,8 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) .subsysnqn = subsysnqn, .transport = transport, .traddr = traddr, - .host_traddr = cfg.host_traddr, - .host_iface = cfg.host_iface, + .host_traddr = host_traddr, + .host_iface = host_iface, .trsvcid = trsvcid, }; @@ -719,7 +732,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) if (!ret) { /* Check if device matches command-line options */ if (!nvme_ctrl_config_match(c, transport, traddr, trsvcid, subsysnqn, - cfg.host_traddr, cfg.host_iface)) { + host_traddr, host_iface)) { fprintf(stderr, "ctrl device %s found, ignoring non matching command-line options\n", device); @@ -750,10 +763,10 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) * for the udev rules). This ensures that host-traddr/ * host-iface are consistent with the discovery controller (c). */ - if (!cfg.host_traddr) - cfg.host_traddr = (char *)nvme_ctrl_get_host_traddr(c); - if (!cfg.host_iface) - cfg.host_iface = (char *)nvme_ctrl_get_host_iface(c); + if (!host_traddr) + host_traddr = (char *)nvme_ctrl_get_host_traddr(c); + if (!host_iface) + host_iface = (char *)nvme_ctrl_get_host_iface(c); } } else { /* @@ -830,6 +843,7 @@ int nvmf_connect(const char *desc, int argc, char **argv) char *trsvcid = NULL, *hostnqn = NULL, *hostid = NULL; char *hostkey = NULL, *ctrlkey = NULL, *keyring = NULL; char *tls_key = NULL, *tls_key_identity = NULL; + char *host_iface = NULL, *host_traddr = NULL; _cleanup_free_ char *hnqn = NULL; _cleanup_free_ char *hid = NULL; char *config_file = NULL; @@ -929,8 +943,8 @@ int nvmf_connect(const char *desc, int argc, char **argv) .subsysnqn = subsysnqn, .transport = transport, .traddr = traddr, - .host_traddr = cfg.host_traddr, - .host_iface = cfg.host_iface, + .host_traddr = host_traddr, + .host_iface = host_iface, .trsvcid = trsvcid, }; @@ -941,7 +955,7 @@ int nvmf_connect(const char *desc, int argc, char **argv) } ret = nvme_create_ctrl(ctx, subsysnqn, transport, traddr, - cfg.host_traddr, cfg.host_iface, trsvcid, &c); + host_traddr, host_iface, trsvcid, &c); if (ret) return ret; @@ -1184,6 +1198,7 @@ int nvmf_config(const char *desc, int argc, char **argv) char *subsysnqn = NULL; char *transport = NULL, *traddr = NULL; char *trsvcid = NULL, *hostnqn = NULL, *hostid = NULL; + char *host_traddr = NULL, *host_iface = NULL; _cleanup_free_ char *hnqn = NULL; _cleanup_free_ char *hid = NULL; char *hostkey = NULL, *ctrlkey = NULL; @@ -1270,7 +1285,7 @@ int nvmf_config(const char *desc, int argc, char **argv) return -ENODEV; } c = nvme_lookup_ctrl(s, transport, traddr, - cfg.host_traddr, cfg.host_iface, + host_traddr, host_iface, trsvcid, NULL); if (!c) { fprintf(stderr, "Failed to lookup controller\n"); diff --git a/libnvme/libnvme/nvme.i b/libnvme/libnvme/nvme.i index 43312f40cb..2cca7d6565 100644 --- a/libnvme/libnvme/nvme.i +++ b/libnvme/libnvme/nvme.i @@ -110,14 +110,6 @@ PyObject *hostid_from_file(); temp.tos = -1; temp.ctrl_loss_tmo = NVMF_DEF_CTRL_LOSS_TMO; while (PyDict_Next($input, &pos, &key, &value)) { - if (!PyUnicode_CompareWithASCIIString(key, "host_traddr")) { - temp.host_traddr = PyBytes_AsString(value); - continue; - } - if (!PyUnicode_CompareWithASCIIString(key, "host_iface")) { - temp.host_iface = PyBytes_AsString(value); - continue; - } if (!PyUnicode_CompareWithASCIIString(key, "nr_io_queues")) { temp.nr_io_queues = PyLong_AsLong(value); continue; diff --git a/libnvme/src/libnvme.map b/libnvme/src/libnvme.map index d12bc9b84b..061593c588 100644 --- a/libnvme/src/libnvme.map +++ b/libnvme/src/libnvme.map @@ -290,7 +290,6 @@ LIBNVME_2_0 { nvmf_cms_str; nvmf_connect_config_json; nvmf_connect_ctrl; - nvmf_connect_disc_entry; nvmf_default_config; nvmf_discovery; nvmf_discovery_config_json; @@ -300,6 +299,8 @@ LIBNVME_2_0 { nvmf_discovery_ctx_decide_retry_set; nvmf_discovery_ctx_default_fabrics_config_set; nvmf_discovery_ctx_discovery_log_set; + nvmf_discovery_ctx_host_iface_set; + nvmf_discovery_ctx_host_traddr_set; nvmf_discovery_ctx_keep_alive_timeout; nvmf_discovery_ctx_max_retries; nvmf_discovery_ctx_persistent_set; diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index cb61a86257..342fd2c7e6 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -272,6 +272,22 @@ int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, return 0; } +int nvmf_discovery_ctx_host_traddr_set(struct nvmf_discovery_ctx *dctx, + const char *host_traddr) +{ + dctx->host_traddr = host_traddr; + + return 0; +} + +int nvmf_discovery_ctx_host_iface_set(struct nvmf_discovery_ctx *dctx, + const char *host_iface) +{ + dctx->host_iface = host_iface; + + return 0; +} + int nvmf_discovery_ctx_default_fabrics_config_set( struct nvmf_discovery_ctx *dctx, struct nvme_fabrics_config *defcfg) @@ -321,15 +337,11 @@ void nvmf_default_config(struct nvme_fabrics_config *cfg) #define MERGE_CFG_OPTION(c, n, o, d) \ if ((c)->o == d) (c)->o = (n)->o -#define MERGE_CFG_OPTION_STR(c, n, o, d) \ - if ((c)->o == d && (n)->o) (c)->o = strdup((n)->o) static struct nvme_fabrics_config *merge_config(nvme_ctrl_t c, const struct nvme_fabrics_config *cfg) { struct nvme_fabrics_config *ctrl_cfg = nvme_ctrl_get_config(c); - MERGE_CFG_OPTION_STR(ctrl_cfg, cfg, host_traddr, NULL); - MERGE_CFG_OPTION_STR(ctrl_cfg, cfg, host_iface, NULL); MERGE_CFG_OPTION(ctrl_cfg, cfg, nr_io_queues, 0); MERGE_CFG_OPTION(ctrl_cfg, cfg, nr_write_queues, 0); MERGE_CFG_OPTION(ctrl_cfg, cfg, nr_poll_queues, 0); @@ -358,8 +370,6 @@ void nvmf_update_config(nvme_ctrl_t c, const struct nvme_fabrics_config *cfg) { struct nvme_fabrics_config *ctrl_cfg = nvme_ctrl_get_config(c); - UPDATE_CFG_OPTION(ctrl_cfg, cfg, host_traddr, NULL); - UPDATE_CFG_OPTION(ctrl_cfg, cfg, host_iface, NULL); UPDATE_CFG_OPTION(ctrl_cfg, cfg, nr_io_queues, 0); UPDATE_CFG_OPTION(ctrl_cfg, cfg, nr_write_queues, 0); UPDATE_CFG_OPTION(ctrl_cfg, cfg, nr_poll_queues, 0); @@ -723,9 +733,9 @@ static int build_options(nvme_host_t h, nvme_ctrl_t c, char **argstr) add_argument(ctx, argstr, traddr, nvme_ctrl_get_traddr(c)) || add_argument(ctx, argstr, host_traddr, - cfg->host_traddr) || + nvme_ctrl_get_host_traddr(c)) || add_argument(ctx, argstr, host_iface, - cfg->host_iface) || + nvme_ctrl_get_host_iface(c)) || add_argument(ctx, argstr, trsvcid, nvme_ctrl_get_trsvcid(c)) || (hostnqn && add_argument(ctx, argstr, hostnqn, hostnqn)) || @@ -1071,14 +1081,14 @@ int nvmf_connect_ctrl(nvme_ctrl_t c) return 0; } -int nvmf_connect_disc_entry(nvme_host_t h, - struct nvmf_disc_log_entry *e, - const struct nvme_fabrics_config *cfg, - bool *discover, - nvme_ctrl_t *cp) +static int nvmf_connect_disc_entry(nvme_host_t h, + struct nvmf_disc_log_entry *e, + const char *host_traddr, const char *host_iface, + const struct nvme_fabrics_config *cfg, + bool *discover, nvme_ctrl_t *cp) { - const char *transport; char *traddr = NULL, *trsvcid = NULL; + const char *transport; nvme_ctrl_t c; int ret; @@ -1126,7 +1136,7 @@ int nvmf_connect_disc_entry(nvme_host_t h, transport, traddr, trsvcid); ret = nvme_create_ctrl(h->ctx, e->subnqn, transport, traddr, - cfg->host_traddr, cfg->host_iface, trsvcid, &c); + host_traddr, host_iface, trsvcid, &c); if (ret) { nvme_msg(h->ctx, LOG_DEBUG, "skipping discovery entry, " "failed to allocate %s controller with traddr %s\n", @@ -2079,8 +2089,8 @@ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, .subsysnqn = e->subnqn, .transport = nvmf_trtype_str(e->trtype), .traddr = e->traddr, - .host_traddr = dctx->defcfg->host_traddr, - .host_iface = dctx->defcfg->host_iface, + .host_traddr = dctx->host_traddr, + .host_iface = dctx->host_iface, .trsvcid = e->trsvcid, }; @@ -2127,8 +2137,9 @@ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, disconnect = false; } - err = nvmf_connect_disc_entry(h, e, dctx->defcfg, - &discover, &child); + err = nvmf_connect_disc_entry(h, e, dctx->host_traddr, + dctx->host_iface, dctx->defcfg, + &discover, &child); dctx->defcfg->keep_alive_tmo = tmo; @@ -2633,8 +2644,8 @@ static int nbft_discovery(struct nvme_global_ctx *ctx, .subsysnqn = e->subnqn, .transport = nvmf_trtype_str(e->trtype), .traddr = e->traddr, - .host_traddr = deftrcfg->host_traddr, - .host_iface = deftrcfg->host_iface, + .host_traddr = dctx->host_traddr, + .host_iface = dctx->host_iface, .trsvcid = e->trsvcid, }; @@ -2654,8 +2665,8 @@ static int nbft_discovery(struct nvme_global_ctx *ctx, if (e->subtype == NVME_NQN_DISC) { nvme_ctrl_t child; - ret = nvmf_connect_disc_entry(h, e, defcfg, - NULL, &child); + ret = nvmf_connect_disc_entry(h, e, dctx->host_traddr, + dctx->host_iface, defcfg, NULL, &child); if (ret) continue; nbft_discovery(ctx, dctx, dd, h, child, defcfg, &trcfg); @@ -2769,7 +2780,7 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, } host_traddr = NULL; - if (!cfg->host_traddr && + if (!dctx->host_traddr && !strncmp((*ss)->transport, "tcp", 3)) host_traddr = hfi->tcp_info.ipaddr; @@ -2850,7 +2861,7 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, continue; host_traddr = NULL; - if (!cfg->host_traddr && + if (!dctx->host_traddr && !strncmp(uri->protocol, "tcp", 3)) host_traddr = hfi->tcp_info.ipaddr; if (uri->port > 0) { diff --git a/libnvme/src/nvme/fabrics.h b/libnvme/src/nvme/fabrics.h index 16b0e9fafb..0a566230f9 100644 --- a/libnvme/src/nvme/fabrics.h +++ b/libnvme/src/nvme/fabrics.h @@ -48,14 +48,16 @@ int nvmf_discovery_ctx_connected_set(struct nvmf_discovery_ctx *dctx, struct nvme_ctrl *c, void *user_data)); int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, bool persistent); +int nvmf_discovery_ctx_host_traddr_set(struct nvmf_discovery_ctx *dctx, + const char *host_traddr); +int nvmf_discovery_ctx_host_iface_set(struct nvmf_discovery_ctx *dctx, + const char *host_iface); int nvmf_discovery_ctx_default_fabrics_config_set( struct nvmf_discovery_ctx *dctx, struct nvme_fabrics_config *defcfg); /** * struct nvme_fabrics_config - Defines all linux nvme fabrics initiator options - * @host_traddr: Host transport address - * @host_iface: Host interface name * @queue_size: Number of IO queue entries * @nr_io_queues: Number of controller IO queues to establish * @reconnect_delay: Time between two consecutive reconnect attempts. @@ -76,8 +78,6 @@ int nvmf_discovery_ctx_default_fabrics_config_set( * @concat: Enable secure concatenation (TCP) */ struct nvme_fabrics_config { - char *host_traddr; - char *host_iface; int queue_size; int nr_io_queues; int reconnect_delay; @@ -367,22 +367,6 @@ char *nvmf_hostnqn_from_file(); */ char *nvmf_hostid_from_file(); -/** - * nvmf_connect_disc_entry() - Connect controller based on the discovery log page entry - * @h: Host to which the controller should be connected - * @e: Discovery log page entry - * @defcfg: Default configuration to be used for the new controller - * @discover: Set to 'true' if the new controller is a discovery controller - * @c: crtl object to return - * - * Return: 0 on success, or an error code on failure. - */ -int nvmf_connect_disc_entry(nvme_host_t h, - struct nvmf_disc_log_entry *e, - const struct nvme_fabrics_config *defcfg, - bool *discover, - nvme_ctrl_t *c); - /** * nvmf_is_registration_supported - check whether registration can be performed. * @c: Controller instance diff --git a/libnvme/src/nvme/private.h b/libnvme/src/nvme/private.h index 83ab63b97e..278cf7fab0 100644 --- a/libnvme/src/nvme/private.h +++ b/libnvme/src/nvme/private.h @@ -188,6 +188,8 @@ struct nvme_ctrl { char *cntlid; char *dctype; char *phy_slot; + char *host_traddr; + char *host_iface; bool discovery_ctrl; bool unique_discovery_ctrl; bool discovered; @@ -291,6 +293,8 @@ struct nvmf_discovery_ctx { /* connfiguration */ bool persistent; + const char *host_traddr; + const char *host_iface; struct nvme_fabrics_config *defcfg; void *user_data; diff --git a/libnvme/src/nvme/tree.c b/libnvme/src/nvme/tree.c index c4d5a94b89..bd45da864c 100644 --- a/libnvme/src/nvme/tree.c +++ b/libnvme/src/nvme/tree.c @@ -1155,12 +1155,12 @@ const char *nvme_ctrl_get_trsvcid(nvme_ctrl_t c) const char *nvme_ctrl_get_host_traddr(nvme_ctrl_t c) { - return c->cfg.host_traddr; + return c->host_traddr; } const char *nvme_ctrl_get_host_iface(nvme_ctrl_t c) { - return c->cfg.host_iface; + return c->host_iface; } struct nvme_fabrics_config *nvme_ctrl_get_config(nvme_ctrl_t c) @@ -1379,8 +1379,8 @@ static void __nvme_free_ctrl(nvme_ctrl_t c) FREE_CTRL_ATTR(c->transport); FREE_CTRL_ATTR(c->subsysnqn); FREE_CTRL_ATTR(c->traddr); - FREE_CTRL_ATTR(c->cfg.host_traddr); - FREE_CTRL_ATTR(c->cfg.host_iface); + FREE_CTRL_ATTR(c->host_traddr); + FREE_CTRL_ATTR(c->host_iface); FREE_CTRL_ATTR(c->trsvcid); free(c); } @@ -1445,12 +1445,12 @@ int nvme_create_ctrl(struct nvme_global_ctx *ctx, c->traddr = strdup(traddr); if (host_traddr) { if (traddr_is_hostname(transport, host_traddr)) - hostname2traddr(ctx, host_traddr, &c->cfg.host_traddr); - if (!c->cfg.host_traddr) - c->cfg.host_traddr = strdup(host_traddr); + hostname2traddr(ctx, host_traddr, &c->host_traddr); + if (!c->host_traddr) + c->host_traddr = strdup(host_traddr); } if (host_iface) - c->cfg.host_iface = strdup(host_iface); + c->host_iface = strdup(host_iface); if (trsvcid) c->trsvcid = strdup(trsvcid); @@ -1473,8 +1473,8 @@ int nvme_create_ctrl(struct nvme_global_ctx *ctx, */ static bool _tcp_ctrl_match_host_traddr_no_src_addr(struct nvme_ctrl *c, struct candidate_args *candidate) { - if (c->cfg.host_traddr) - return candidate->addreq(candidate->host_traddr, c->cfg.host_traddr); + if (c->host_traddr) + return candidate->addreq(candidate->host_traddr, c->host_traddr); /* If c->cfg.host_traddr is NULL, then the controller (c) * uses the interface's primary address as the source @@ -1482,9 +1482,9 @@ static bool _tcp_ctrl_match_host_traddr_no_src_addr(struct nvme_ctrl *c, struct * determine the primary address associated with that * interface and compare that to the candidate->host_traddr. */ - if (c->cfg.host_iface) + if (c->host_iface) return nvme_iface_primary_addr_matches(candidate->iface_list, - c->cfg.host_iface, + c->host_iface, candidate->host_traddr); /* If both c->cfg.host_traddr and c->cfg.host_iface are @@ -1514,16 +1514,16 @@ static bool _tcp_ctrl_match_host_traddr_no_src_addr(struct nvme_ctrl *c, struct */ static bool _tcp_ctrl_match_host_iface_no_src_addr(struct nvme_ctrl *c, struct candidate_args *candidate) { - if (c->cfg.host_iface) - return streq0(candidate->host_iface, c->cfg.host_iface); + if (c->host_iface) + return streq0(candidate->host_iface, c->host_iface); /* If c->cfg.host_traddr is not NULL we can infer the controller's (c) * interface from it and compare it to the candidate->host_iface. */ - if (c->cfg.host_traddr) { + if (c->host_traddr) { const char *c_host_iface; - c_host_iface = nvme_iface_matching_addr(candidate->iface_list, c->cfg.host_traddr); + c_host_iface = nvme_iface_matching_addr(candidate->iface_list, c->host_traddr); return streq0(candidate->host_iface, c_host_iface); } @@ -1697,12 +1697,12 @@ static bool _match_ctrl(struct nvme_ctrl *c, struct candidate_args *candidate) !candidate->addreq(c->traddr, candidate->traddr)) return false; - if (candidate->host_traddr && c->cfg.host_traddr && - !candidate->addreq(c->cfg.host_traddr, candidate->host_traddr)) + if (candidate->host_traddr && c->host_traddr && + !candidate->addreq(c->host_traddr, candidate->host_traddr)) return false; - if (candidate->host_iface && c->cfg.host_iface && - !streq0(c->cfg.host_iface, candidate->host_iface)) + if (candidate->host_iface && c->host_iface && + !streq0(c->host_iface, candidate->host_iface)) return false; if (candidate->trsvcid && c->trsvcid && From 03fe0bd938cc548043f1f14fc6c473819b53217a Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Fri, 12 Dec 2025 13:57:07 +0100 Subject: [PATCH 07/13] fabrics: add context to common fabrics arg parser The NVMF_ARGS macro parses the common arguments for the transport configuration. Move all those open coded variables into a context, so it's simpler to pass a complete configuration around. Signed-off-by: Daniel Wagner --- fabrics.c | 180 +++++++++++++++---------------------- fabrics.h | 8 ++ libnvme/src/nvme/fabrics.c | 9 +- libnvme/src/nvme/fabrics.h | 7 +- libnvme/src/nvme/tree.c | 2 +- libnvme/src/nvme/tree.h | 2 +- 6 files changed, 91 insertions(+), 117 deletions(-) diff --git a/fabrics.c b/fabrics.c index 463febc5e5..ff24da56bc 100644 --- a/fabrics.c +++ b/fabrics.c @@ -94,20 +94,21 @@ static const char *nvmf_concat = "enable secure concatenation"; static const char *nvmf_config_file = "Use specified JSON configuration file or 'none' to disable"; static const char *nvmf_context = "execution context identification string"; -#define NVMF_ARGS(n, c, ...) \ +#define NVMF_ARGS(n, t, c, ...) \ struct argconfig_commandline_options n[] = { \ - OPT_STRING("transport", 't', "STR", &transport, nvmf_tport), \ - OPT_STRING("nqn", 'n', "STR", &subsysnqn, nvmf_nqn), \ - OPT_STRING("traddr", 'a', "STR", &traddr, nvmf_traddr), \ - OPT_STRING("trsvcid", 's', "STR", &trsvcid, nvmf_trsvcid), \ - OPT_STRING("host-traddr", 'w', "STR", &host_traddr, nvmf_htraddr), \ - OPT_STRING("host-iface", 'f', "STR", &host_iface, nvmf_hiface), \ - OPT_STRING("hostnqn", 'q', "STR", &hostnqn, nvmf_hostnqn), \ - OPT_STRING("hostid", 'I', "STR", &hostid, nvmf_hostid), \ - OPT_STRING("dhchap-secret", 'S', "STR", &hostkey, nvmf_hostkey), \ - OPT_STRING("keyring", 0, "STR", &keyring, nvmf_keyring), \ - OPT_STRING("tls-key", 0, "STR", &tls_key, nvmf_tls_key), \ - OPT_STRING("tls-key-identity", 0, "STR", &tls_key_identity, nvmf_tls_key_identity), \ + OPT_STRING("transport", 't', "STR", &t.transport, nvmf_tport), \ + OPT_STRING("nqn", 'n', "STR", &t.subsysnqn, nvmf_nqn), \ + OPT_STRING("traddr", 'a', "STR", &t.traddr, nvmf_traddr), \ + OPT_STRING("trsvcid", 's', "STR", &t.trsvcid, nvmf_trsvcid), \ + OPT_STRING("host-traddr", 'w', "STR", &t.host_traddr, nvmf_htraddr), \ + OPT_STRING("host-iface", 'f', "STR", &t.host_iface, nvmf_hiface), \ + OPT_STRING("hostnqn", 'q', "STR", &t.hostnqn, nvmf_hostnqn), \ + OPT_STRING("hostid", 'I', "STR", &t.hostid, nvmf_hostid), \ + OPT_STRING("dhchap-secret", 'S', "STR", &t.hostkey, nvmf_hostkey), \ + OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &t.ctrlkey, nvmf_ctrlkey), \ + OPT_STRING("keyring", 0, "STR", &t.keyring, nvmf_keyring), \ + OPT_STRING("tls-key", 0, "STR", &t.tls_key, nvmf_tls_key), \ + OPT_STRING("tls-key-identity", 0, "STR", &t.tls_key_identity, nvmf_tls_key_identity), \ OPT_INT("nr-io-queues", 'i', &c.nr_io_queues, nvmf_nr_io_queues), \ OPT_INT("nr-write-queues", 'W', &c.nr_write_queues, nvmf_nr_write_queues), \ OPT_INT("nr-poll-queues", 'P', &c.nr_poll_queues, nvmf_nr_poll_queues), \ @@ -368,8 +369,7 @@ static void nvmf_connected(struct nvmf_discovery_ctx *dctx, } static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, - bool persistent, - const char *host_traddr, const char *host_iface, + bool persistent, struct tr_config *trcfg, struct nvme_fabrics_config *defcfg, void *user_data, struct nvmf_discovery_ctx **dctxp) { @@ -408,11 +408,11 @@ static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, if (err) goto err; - err = nvmf_discovery_ctx_host_traddr_set(dctx, host_traddr); + err = nvmf_discovery_ctx_host_traddr_set(dctx, trcfg->host_traddr); if (err) goto err; - err = nvmf_discovery_ctx_host_iface_set(dctx, host_iface); + err = nvmf_discovery_ctx_host_iface_set(dctx, trcfg->host_iface); if (err) goto err; @@ -432,12 +432,7 @@ static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, const char *desc, bool connect, const struct nvme_fabrics_config *defcfg) { - char *transport = NULL, *traddr = NULL, *trsvcid = NULL; - char *hostnqn = NULL, *hostid = NULL, *hostkey = NULL; - char *subsysnqn = NULL, *keyring = NULL, *tls_key = NULL; _cleanup_free_ struct nvmf_discovery_ctx *dctx = NULL; - char *host_iface = NULL, *host_traddr = NULL; - char *tls_key_identity = NULL; char *ptr, **argv, *p, line[4096]; int argc, ret = 0; unsigned int verbose = 0; @@ -445,8 +440,9 @@ static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, nvme_print_flags_t flags; char *format = "normal"; struct nvme_fabrics_config cfg; + struct tr_config trcfg; bool force = false; - NVMF_ARGS(opts, cfg, + NVMF_ARGS(opts, trcfg, cfg, OPT_FMT("output-format", 'o', &format, output_format), OPT_FILE("raw", 'r', &raw, "save raw output to file"), OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"), @@ -487,31 +483,23 @@ static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, argv[argc] = NULL; memcpy(&cfg, defcfg, sizeof(cfg)); - subsysnqn = NVME_DISC_SUBSYS_NAME; + trcfg.subsysnqn = NVME_DISC_SUBSYS_NAME; ret = argconfig_parse(argc, argv, desc, opts); if (ret) goto next; - if (!transport && !traddr) + if (!trcfg.transport && !trcfg.traddr) goto next; - if (!trsvcid) - trsvcid = nvmf_get_default_trsvcid(transport, true); - - struct tr_config trcfg = { - .subsysnqn = subsysnqn, - .transport = transport, - .traddr = traddr, - .host_traddr = host_traddr, - .host_iface = host_iface, - .trsvcid = trsvcid, - }; + if (!trcfg.trsvcid) + trcfg.trsvcid = + nvmf_get_default_trsvcid(trcfg.transport, true); struct cb_discovery_log_data dld = { .flags = flags, .raw = raw, }; - ret = create_discovery_log_ctx(ctx, true, host_traddr, - host_iface, &cfg, &dld, &dctx); + ret = create_discovery_log_ctx(ctx, true, &trcfg, &cfg, + &dld, &dctx); if (ret) return ret; @@ -589,12 +577,6 @@ static int nvme_read_config_checked(struct nvme_global_ctx *ctx, /* returns negative errno values */ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) { - char *subsysnqn = NVME_DISC_SUBSYS_NAME; - char *hostnqn = NULL, *hostid = NULL, *hostkey = NULL; - char *transport = NULL, *traddr = NULL, *trsvcid = NULL; - char *host_iface = NULL, *host_traddr = NULL; - char *keyring = NULL, *tls_key = NULL; - char *tls_key_identity = NULL; char *config_file = PATH_NVMF_CONFIG; _cleanup_free_ char *hnqn = NULL; _cleanup_free_ char *hid = NULL; @@ -608,13 +590,14 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) int ret; char *format = "normal"; struct nvme_fabrics_config cfg; + struct tr_config trcfg = { .subsysnqn = NVME_DISC_SUBSYS_NAME }; char *device = NULL; bool force = false; bool json_config = false; bool nbft = false, nonbft = false; char *nbft_path = NBFT_SYSFS_PATH; - NVMF_ARGS(opts, cfg, + NVMF_ARGS(opts, trcfg, cfg, OPT_STRING("device", 'd', "DEV", &device, "use existing discovery controller device"), OPT_FMT("output-format", 'o', &format, output_format), OPT_FILE("raw", 'r', &raw, "save raw output to file"), @@ -668,7 +651,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) return ret; } - ret = nvme_host_get_ids(ctx, hostnqn, hostid, &hnqn, &hid); + ret = nvme_host_get_ids(ctx, trcfg.hostnqn, trcfg.hostid, &hnqn, &hid); if (ret < 0) return ret; @@ -684,30 +667,29 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) else if (!strncmp(device, "/dev/", 5)) device += 5; } - if (hostkey) - nvme_host_set_dhchap_key(h, hostkey); + if (trcfg.hostkey) + nvme_host_set_dhchap_key(h, trcfg.hostkey); struct cb_discovery_log_data dld = { .flags = flags, .raw = raw, }; - - ret = create_discovery_log_ctx(ctx, persistent, host_traddr, - host_iface, &cfg, &dld, &dctx); + ret = create_discovery_log_ctx(ctx, persistent, &trcfg, + &cfg, &dld, &dctx); if (ret) return ret; - if (!device && !transport && !traddr) { + if (!device && !trcfg.transport && !trcfg.traddr) { if (!nonbft) - ret = nvmf_discovery_nbft(ctx, dctx, hostnqn, hostid, - hnqn, hid, connect, - &cfg, nbft_path); + ret = nvmf_discovery_nbft(ctx, dctx, + trcfg.hostnqn, trcfg.hostid, hnqn, hid, connect, + &cfg, nbft_path); if (nbft) goto out_free; if (json_config) ret = nvmf_discovery_config_json(ctx, dctx, - hostnqn, hostid, connect, force); + trcfg.hostnqn, trcfg.hostid, connect, force); if (ret || access(PATH_NVMF_DISC, F_OK)) goto out_free; @@ -715,24 +697,17 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) goto out_free; } - if (!trsvcid) - trsvcid = nvmf_get_default_trsvcid(transport, true); - - struct tr_config trcfg = { - .subsysnqn = subsysnqn, - .transport = transport, - .traddr = traddr, - .host_traddr = host_traddr, - .host_iface = host_iface, - .trsvcid = trsvcid, - }; + if (!trcfg.trsvcid) + trcfg.trsvcid = nvmf_get_default_trsvcid(trcfg.transport, true); if (device && !force) { ret = nvme_scan_ctrl(ctx, device, &c); if (!ret) { /* Check if device matches command-line options */ - if (!nvme_ctrl_config_match(c, transport, traddr, trsvcid, subsysnqn, - host_traddr, host_iface)) { + if (!nvme_ctrl_config_match(c, trcfg.transport, + trcfg.traddr, trcfg.trsvcid, + trcfg.subsysnqn, trcfg.host_traddr, + trcfg.host_iface)) { fprintf(stderr, "ctrl device %s found, ignoring non matching command-line options\n", device); @@ -763,10 +738,10 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) * for the udev rules). This ensures that host-traddr/ * host-iface are consistent with the discovery controller (c). */ - if (!host_traddr) - host_traddr = (char *)nvme_ctrl_get_host_traddr(c); - if (!host_iface) - host_iface = (char *)nvme_ctrl_get_host_iface(c); + if (!trcfg.host_traddr) + trcfg.host_traddr = (char *)nvme_ctrl_get_host_traddr(c); + if (!trcfg.host_iface) + trcfg.host_iface = (char *)nvme_ctrl_get_host_iface(c); } } else { /* @@ -838,12 +813,6 @@ static void nvme_parse_tls_args(const char *keyring, const char *tls_key, int nvmf_connect(const char *desc, int argc, char **argv) { - char *subsysnqn = NULL; - char *transport = NULL, *traddr = NULL; - char *trsvcid = NULL, *hostnqn = NULL, *hostid = NULL; - char *hostkey = NULL, *ctrlkey = NULL, *keyring = NULL; - char *tls_key = NULL, *tls_key_identity = NULL; - char *host_iface = NULL, *host_traddr = NULL; _cleanup_free_ char *hnqn = NULL; _cleanup_free_ char *hid = NULL; char *config_file = NULL; @@ -855,10 +824,10 @@ int nvmf_connect(const char *desc, int argc, char **argv) int ret; nvme_print_flags_t flags; struct nvme_fabrics_config cfg = { 0 }; + struct tr_config trcfg = { 0 }; char *format = "normal"; - NVMF_ARGS(opts, cfg, - OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &ctrlkey, nvmf_ctrlkey), + NVMF_ARGS(opts, trcfg, cfg, OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file), OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), OPT_FLAG("dump-config", 'O', &dump_config, "Dump JSON configuration to stdout"), @@ -880,23 +849,23 @@ int nvmf_connect(const char *desc, int argc, char **argv) if (config_file && strcmp(config_file, "none")) goto do_connect; - if (!subsysnqn) { + if (!trcfg.subsysnqn) { fprintf(stderr, "required argument [--nqn | -n] not specified\n"); return -EINVAL; } - if (!transport) { + if (!trcfg.transport) { fprintf(stderr, "required argument [--transport | -t] not specified\n"); return -EINVAL; } - if (strcmp(transport, "loop")) { - if (!traddr) { + if (strcmp(trcfg.transport, "loop")) { + if (!trcfg.traddr) { fprintf(stderr, "required argument [--traddr | -a] not specified for transport %s\n", - transport); + trcfg.transport); return -EINVAL; } } @@ -924,29 +893,21 @@ int nvmf_connect(const char *desc, int argc, char **argv) return ret; } - ret = nvme_host_get_ids(ctx, hostnqn, hostid, &hnqn, &hid); + ret = nvme_host_get_ids(ctx, trcfg.hostnqn, trcfg.hostid, &hnqn, &hid); if (ret < 0) return ret; h = nvme_lookup_host(ctx, hnqn, hid); if (!h) return -ENOMEM; - if (hostkey) - nvme_host_set_dhchap_key(h, hostkey); - if (!trsvcid) - trsvcid = nvmf_get_default_trsvcid(transport, false); + if (trcfg.hostkey) + nvme_host_set_dhchap_key(h, trcfg.hostkey); + if (!trcfg.trsvcid) + trcfg.trsvcid = nvmf_get_default_trsvcid(trcfg.transport, false); if (config_file) - return nvmf_connect_config_json(ctx, hostnqn, hostid, &cfg); - - struct tr_config trcfg = { - .subsysnqn = subsysnqn, - .transport = transport, - .traddr = traddr, - .host_traddr = host_traddr, - .host_iface = host_iface, - .trsvcid = trsvcid, - }; + return nvmf_connect_config_json(ctx, trcfg.hostnqn, + trcfg.hostid, &cfg); c = lookup_ctrl(h, &trcfg); if (c && nvme_ctrl_get_name(c) && !cfg.duplicate_connect) { @@ -954,21 +915,23 @@ int nvmf_connect(const char *desc, int argc, char **argv) return -EALREADY; } - ret = nvme_create_ctrl(ctx, subsysnqn, transport, traddr, - host_traddr, host_iface, trsvcid, &c); + ret = nvme_create_ctrl(ctx, trcfg.subsysnqn, trcfg.transport, + trcfg.traddr, trcfg.host_traddr, trcfg.host_iface, + trcfg.trsvcid, &c); if (ret) return ret; - if (ctrlkey) - nvme_ctrl_set_dhchap_key(c, ctrlkey); + if (trcfg.ctrlkey) + nvme_ctrl_set_dhchap_key(c, trcfg.ctrlkey); - nvme_parse_tls_args(keyring, tls_key, tls_key_identity, &cfg, c); + nvme_parse_tls_args(trcfg.keyring, trcfg.tls_key, + trcfg.tls_key_identity, &cfg, c); /* * We are connecting to a discovery controller, so let's treat * this as a persistent connection and specify a KATO. */ - if (!strcmp(subsysnqn, NVME_DISC_SUBSYS_NAME)) { + if (!strcmp(trcfg.subsysnqn, NVME_DISC_SUBSYS_NAME)) { persistent = true; set_discovery_kato(&cfg); @@ -1208,9 +1171,10 @@ int nvmf_config(const char *desc, int argc, char **argv) _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; int ret; struct nvme_fabrics_config cfg; + struct tr_config trcfg = { }; bool scan_tree = false, modify_config = false, update_config = false; - NVMF_ARGS(opts, cfg, + NVMF_ARGS(opts, trcfg, cfg, OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &ctrlkey, nvmf_ctrlkey), OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file), OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), diff --git a/fabrics.h b/fabrics.h index 50ff00dee4..2c5ea12bc2 100644 --- a/fabrics.h +++ b/fabrics.h @@ -9,6 +9,14 @@ struct tr_config { const char *host_traddr; const char *host_iface; const char *trsvcid; + + const char *hostnqn; + const char *hostid; + const char *hostkey; + const char *ctrlkey; + const char *keyring; + const char *tls_key; + const char *tls_key_identity; }; extern nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct tr_config *trcfg); diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index 342fd2c7e6..6728e0392a 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -2713,11 +2713,12 @@ static int nbft_discovery(struct nvme_global_ctx *ctx, } int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, char *hostnqn_arg, - char *hostid_arg, char *hostnqn_sys, char *hostid_sys, - bool connect, struct nvme_fabrics_config *cfg, char *nbft_path) + struct nvmf_discovery_ctx *dctx, const char *hostnqn_arg, + const char *hostid_arg, const char *hostnqn_sys, + const char *hostid_sys, bool connect, + struct nvme_fabrics_config *cfg, char *nbft_path) { - char *hostnqn = NULL, *hostid = NULL, *host_traddr = NULL; + const char *hostnqn = NULL, *hostid = NULL, *host_traddr = NULL; nvme_host_t h; int ret, rr, i; char uuid[NVME_UUID_LEN_STRING]; diff --git a/libnvme/src/nvme/fabrics.h b/libnvme/src/nvme/fabrics.h index 0a566230f9..17b3e78c32 100644 --- a/libnvme/src/nvme/fabrics.h +++ b/libnvme/src/nvme/fabrics.h @@ -428,9 +428,10 @@ int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, const char *hostnqn, const char *hostid, bool connect, bool force); int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, char *hostnqn_arg, - char *hostid_arg, char *hostnqn_sys, char *hostid_sys, - bool connect, struct nvme_fabrics_config *cfg, char *nbft_path); + struct nvmf_discovery_ctx *dctx, const char *hostnqn_arg, + const char *hostid_arg, const char *hostnqn_sys, + const char *hostid_sys, bool connect, + struct nvme_fabrics_config *cfg, char *nbft_path); int nvmf_connect_config_json(struct nvme_global_ctx *ctx, const char *hostnqn, const char *hostid, const struct nvme_fabrics_config *cfg); diff --git a/libnvme/src/nvme/tree.c b/libnvme/src/nvme/tree.c index bd45da864c..2fdde49ee2 100644 --- a/libnvme/src/nvme/tree.c +++ b/libnvme/src/nvme/tree.c @@ -127,7 +127,7 @@ static char *nvme_hostid_from_hostnqn(const char *hostnqn) } int nvme_host_get_ids(struct nvme_global_ctx *ctx, - char *hostnqn_arg, char *hostid_arg, + const char *hostnqn_arg, const char *hostid_arg, char **hostnqn, char **hostid) { _cleanup_free_ char *nqn = NULL; diff --git a/libnvme/src/nvme/tree.h b/libnvme/src/nvme/tree.h index c1622d3454..541f1c5601 100644 --- a/libnvme/src/nvme/tree.h +++ b/libnvme/src/nvme/tree.h @@ -191,7 +191,7 @@ int nvme_default_host(struct nvme_global_ctx *ctx, nvme_host_t *h); * which the caller needs to free), or negative error code otherwise. */ int nvme_host_get_ids(struct nvme_global_ctx *ctx, - char *hostnqn_arg, char *hostid_arg, + const char *hostnqn_arg, const char *hostid_arg, char **hostnqn, char **hostid); /** From 73efbe76c9e7e0a0476ea0b53373ec812cb9982b Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Fri, 12 Dec 2025 14:32:36 +0100 Subject: [PATCH 08/13] fabrics: move discovery config file code to library Move the discovery config file to the library. Add a callback interface to retrieve the next line to execute. Signed-off-by: Daniel Wagner --- fabrics.c | 261 +++++++++++++++++++++---------------- libnvme/src/libnvme.map | 15 +++ libnvme/src/nvme/fabrics.c | 164 +++++++++++++++++++++++ libnvme/src/nvme/fabrics.h | 34 +++++ libnvme/src/nvme/private.h | 18 +++ 5 files changed, 381 insertions(+), 111 deletions(-) diff --git a/fabrics.c b/fabrics.c index ff24da56bc..b568516510 100644 --- a/fabrics.c +++ b/fabrics.c @@ -301,21 +301,24 @@ static void save_discovery_log(char *raw, struct nvmf_discovery_log *log) close(fd); } -struct cb_discovery_log_data { +struct cb_discovery_data { + struct nvme_fabrics_config *defcfg; nvme_print_flags_t flags; char *raw; + char **argv; + FILE *f; }; static void cb_discovery_log(struct nvmf_discovery_ctx *dctx, bool connect, struct nvmf_discovery_log *log, uint64_t numrec, void *user_data) { - struct cb_discovery_log_data *dld = user_data; + struct cb_discovery_data *cdd = user_data; - if (dld->raw) - save_discovery_log(dld->raw, log); + if (cdd->raw) + save_discovery_log(cdd->raw, log); else if (!connect) - nvme_show_discovery_log(log, numrec, dld->flags); + nvme_show_discovery_log(log, numrec, cdd->flags); } static void already_connected(struct nvme_host *host, @@ -345,15 +348,15 @@ static bool nvmf_decide_retry(struct nvmf_discovery_ctx *dctx, int err, static void nvmf_connected(struct nvmf_discovery_ctx *dctx, struct nvme_ctrl *c, void *user_data) { - struct cb_discovery_log_data *dld = user_data; + struct cb_discovery_data *cdd = user_data; - if (dld->flags == NORMAL) { + if (cdd->flags == NORMAL) { printf("device: %s\n", nvme_ctrl_get_name(c)); return; } #ifdef CONFIG_JSONC - if (dld->flags == JSON) { + if (cdd->flags == JSON) { struct json_object *root; root = json_create_object(); @@ -368,6 +371,131 @@ static void nvmf_connected(struct nvmf_discovery_ctx *dctx, #endif } +static int parser_init(struct nvmf_discovery_ctx *dctx, void *user_data) +{ + struct cb_discovery_data *cdd = user_data; + + cdd->f = fopen(PATH_NVMF_DISC, "r"); + if (cdd->f == NULL) { + fprintf(stderr, "No params given and no %s\n", PATH_NVMF_DISC); + return -ENOENT; + } + + cdd->argv = calloc(MAX_DISC_ARGS, sizeof(char *)); + if (!cdd->argv) + return -1; + + cdd->argv[0] = "discover"; + + return 0; +} + +static void parser_cleanup(struct nvmf_discovery_ctx *dctx, void *user_data) +{ + struct cb_discovery_data *cdd = user_data; + + free(cdd->argv); + fclose(cdd->f); +} + +static int parser_next_line(struct nvmf_discovery_ctx *dctx, void *user_data) +{ + struct cb_discovery_data *cdd = user_data; + struct nvme_fabrics_config cfg; + struct tr_config trcfg = {}; + char *ptr, *p, line[4096]; + int argc, ret = 0; + bool force = false; + + NVMF_ARGS(opts, trcfg, cfg, + OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"), + OPT_FLAG("force", 0, &force, "Force persistent discovery controller creation")); + + memcpy(&cfg, cdd->defcfg, sizeof(cfg)); +next: + if (fgets(line, sizeof(line), cdd->f) == NULL) + return -EOF; + + if (line[0] == '#' || line[0] == '\n') + goto next; + + argc = 1; + p = line; + while ((ptr = strsep(&p, " =\n")) != NULL) + cdd->argv[argc++] = ptr; + cdd->argv[argc] = NULL; + + trcfg.subsysnqn = NVME_DISC_SUBSYS_NAME; + ret = argconfig_parse(argc, cdd->argv, "config", opts); + if (ret) + goto next; + if (!trcfg.transport && !trcfg.traddr) + goto next; + + if (!trcfg.trsvcid) + trcfg.trsvcid = nvmf_get_default_trsvcid(trcfg.transport, true); + + ret = nvmf_discovery_ctx_subsysnqn_set(dctx, trcfg.subsysnqn); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_transport_set(dctx, trcfg.transport); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_traddr_set(dctx, trcfg.traddr); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_host_traddr_set(dctx, trcfg.host_traddr); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_host_iface_set(dctx, trcfg.host_iface); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_trsvcid_set(dctx, trcfg.trsvcid); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_hostnqn_set(dctx, trcfg.hostnqn); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_hostid_set(dctx, trcfg.hostid); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_hostkey_set(dctx, trcfg.hostkey); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_ctrlkey_set(dctx, trcfg.ctrlkey); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_keyring_set(dctx, trcfg.keyring); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_tls_key_set(dctx, trcfg.tls_key); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_tls_key_identity_set(dctx, + trcfg.tls_key_identity); + if (ret) + return ret; + + ret = nvmf_discovery_ctx_default_fabrics_config_set(dctx, &cfg); + if (ret) + return ret; + + return 0; +} + + static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, bool persistent, struct tr_config *trcfg, struct nvme_fabrics_config *defcfg, @@ -404,6 +532,18 @@ static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, if (err) goto err; + err = nvmf_discovery_ctx_parser_init_set(dctx, parser_init); + if (err) + goto err; + + err = nvmf_discovery_ctx_parser_cleanup_set(dctx, parser_cleanup); + if (err) + goto err; + + err = nvmf_discovery_ctx_parser_next_line_set(dctx, parser_next_line); + if (err) + goto err; + err = nvmf_discovery_ctx_persistent_set(dctx, persistent); if (err) goto err; @@ -428,107 +568,6 @@ static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, return err; } -static int discover_from_conf_file(struct nvme_global_ctx *ctx, nvme_host_t h, - const char *desc, bool connect, - const struct nvme_fabrics_config *defcfg) -{ - _cleanup_free_ struct nvmf_discovery_ctx *dctx = NULL; - char *ptr, **argv, *p, line[4096]; - int argc, ret = 0; - unsigned int verbose = 0; - _cleanup_file_ FILE *f = NULL; - nvme_print_flags_t flags; - char *format = "normal"; - struct nvme_fabrics_config cfg; - struct tr_config trcfg; - bool force = false; - NVMF_ARGS(opts, trcfg, cfg, - OPT_FMT("output-format", 'o', &format, output_format), - OPT_FILE("raw", 'r', &raw, "save raw output to file"), - OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"), - OPT_FLAG("quiet", 0, &quiet, "suppress already connected errors"), - OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), - OPT_FLAG("force", 0, &force, "Force persistent discovery controller creation")); - - nvmf_default_config(&cfg); - - ret = validate_output_format(format, &flags); - if (ret < 0) { - nvme_show_error("Invalid output format"); - return ret; - } - - f = fopen(PATH_NVMF_DISC, "r"); - if (f == NULL) { - fprintf(stderr, "No params given and no %s\n", PATH_NVMF_DISC); - return -ENOENT; - } - - argv = calloc(MAX_DISC_ARGS, sizeof(char *)); - if (!argv) - return -1; - - argv[0] = "discover"; - memset(line, 0, sizeof(line)); - while (fgets(line, sizeof(line), f) != NULL) { - nvme_ctrl_t c; - - if (line[0] == '#' || line[0] == '\n') - continue; - - argc = 1; - p = line; - while ((ptr = strsep(&p, " =\n")) != NULL) - argv[argc++] = ptr; - argv[argc] = NULL; - - memcpy(&cfg, defcfg, sizeof(cfg)); - trcfg.subsysnqn = NVME_DISC_SUBSYS_NAME; - ret = argconfig_parse(argc, argv, desc, opts); - if (ret) - goto next; - if (!trcfg.transport && !trcfg.traddr) - goto next; - - if (!trcfg.trsvcid) - trcfg.trsvcid = - nvmf_get_default_trsvcid(trcfg.transport, true); - - struct cb_discovery_log_data dld = { - .flags = flags, - .raw = raw, - }; - ret = create_discovery_log_ctx(ctx, true, &trcfg, &cfg, - &dld, &dctx); - if (ret) - return ret; - - if (!force) { - c = lookup_ctrl(h, &trcfg); - if (c) { - nvmf_discovery(ctx, dctx, connect, c); - goto next; - } - } - - ret = nvmf_create_discover_ctrl(ctx, h, &cfg, &trcfg, &c); - if (ret) - goto next; - - nvmf_discovery_ctx_persistent_set(dctx, persistent); - nvmf_discovery(ctx, dctx, connect, c); - if (!(persistent || is_persistent_discovery_ctrl(h, c))) - ret = nvme_disconnect_ctrl(c); - nvme_free_ctrl(c); - -next: - memset(&cfg, 0, sizeof(cfg)); - } - free(argv); - - return ret; -} - static int nvme_read_volatile_config(struct nvme_global_ctx *ctx) { char *filename, *ext; @@ -670,7 +709,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) if (trcfg.hostkey) nvme_host_set_dhchap_key(h, trcfg.hostkey); - struct cb_discovery_log_data dld = { + struct cb_discovery_data dld = { .flags = flags, .raw = raw, }; @@ -693,7 +732,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) if (ret || access(PATH_NVMF_DISC, F_OK)) goto out_free; - ret = discover_from_conf_file(ctx, h, desc, connect, &cfg); + ret = nvmf_discovery_config_file(ctx, dctx, h, connect, force); goto out_free; } diff --git a/libnvme/src/libnvme.map b/libnvme/src/libnvme.map index 061593c588..ba6dfcab65 100644 --- a/libnvme/src/libnvme.map +++ b/libnvme/src/libnvme.map @@ -292,18 +292,33 @@ LIBNVME_2_0 { nvmf_connect_ctrl; nvmf_default_config; nvmf_discovery; + nvmf_discovery_config_file; nvmf_discovery_config_json; nvmf_discovery_ctx_already_connected_set; nvmf_discovery_ctx_connected_set; nvmf_discovery_ctx_create; + nvmf_discovery_ctx_ctrlkey_set; nvmf_discovery_ctx_decide_retry_set; nvmf_discovery_ctx_default_fabrics_config_set; nvmf_discovery_ctx_discovery_log_set; nvmf_discovery_ctx_host_iface_set; nvmf_discovery_ctx_host_traddr_set; + nvmf_discovery_ctx_hostid_set; + nvmf_discovery_ctx_hostkey_set; + nvmf_discovery_ctx_hostnqn_set; nvmf_discovery_ctx_keep_alive_timeout; + nvmf_discovery_ctx_keyring_set; nvmf_discovery_ctx_max_retries; + nvmf_discovery_ctx_parser_cleanup_set; + nvmf_discovery_ctx_parser_init_set; + nvmf_discovery_ctx_parser_next_line_set; nvmf_discovery_ctx_persistent_set; + nvmf_discovery_ctx_subsysnqn_set; + nvmf_discovery_ctx_tls_key_identity_set; + nvmf_discovery_ctx_tls_key_set; + nvmf_discovery_ctx_traddr_set; + nvmf_discovery_ctx_transport_set; + nvmf_discovery_ctx_trsvcid_set; nvmf_discovery_nbft; nvmf_eflags_str; nvmf_exat_ptr_next; diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index 6728e0392a..53fa752e0b 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -264,6 +264,33 @@ int nvmf_discovery_ctx_connected_set(struct nvmf_discovery_ctx *dctx, return 0; } +int nvmf_discovery_ctx_parser_init_set(struct nvmf_discovery_ctx *dctx, + int (*parser_init)(struct nvmf_discovery_ctx *dctx, + void *user_data)) +{ + dctx->parser_init = parser_init; + + return 0; +} + +int nvmf_discovery_ctx_parser_cleanup_set(struct nvmf_discovery_ctx *dctx, + void (*parser_cleanup)(struct nvmf_discovery_ctx *dctx, + void *user_data)) +{ + dctx->parser_cleanup = parser_cleanup; + + return 0; +} + +int nvmf_discovery_ctx_parser_next_line_set(struct nvmf_discovery_ctx *dctx, + int (*parser_next)(struct nvmf_discovery_ctx *dctx, + void *user_data)) +{ + dctx->parser_next_line = parser_next; + + return 0; +} + int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, bool persistent) { @@ -272,6 +299,30 @@ int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, return 0; } +int nvmf_discovery_ctx_subsysnqn_set(struct nvmf_discovery_ctx *dctx, + const char *subsysnqn) +{ + dctx->subsysnqn = subsysnqn; + + return 0; +} + +int nvmf_discovery_ctx_transport_set(struct nvmf_discovery_ctx *dctx, + const char *transport) +{ + dctx->transport = transport; + + return 0; +} + +int nvmf_discovery_ctx_traddr_set(struct nvmf_discovery_ctx *dctx, + const char *traddr) +{ + dctx->traddr = traddr; + + return 0; +} + int nvmf_discovery_ctx_host_traddr_set(struct nvmf_discovery_ctx *dctx, const char *host_traddr) { @@ -287,6 +338,69 @@ int nvmf_discovery_ctx_host_iface_set(struct nvmf_discovery_ctx *dctx, return 0; } +int nvmf_discovery_ctx_trsvcid_set(struct nvmf_discovery_ctx *dctx, + const char *trsvcid) +{ + dctx->trsvcid = trsvcid; + + return 0; +} + +int nvmf_discovery_ctx_hostnqn_set(struct nvmf_discovery_ctx *dctx, + const char *hostnqn) +{ + dctx->hostnqn = hostnqn; + + return 0; +} + +int nvmf_discovery_ctx_hostid_set(struct nvmf_discovery_ctx *dctx, + const char *hostid) +{ + dctx->hostid = hostid; + + return 0; +} + +int nvmf_discovery_ctx_hostkey_set(struct nvmf_discovery_ctx *dctx, + const char *hostkey) +{ + dctx->hostkey = hostkey; + + return 0; +} + +int nvmf_discovery_ctx_ctrlkey_set(struct nvmf_discovery_ctx *dctx, + const char *ctrlkey) +{ + dctx->ctrlkey = ctrlkey; + + return 0; +} + +int nvmf_discovery_ctx_keyring_set(struct nvmf_discovery_ctx *dctx, + const char *keyring) +{ + dctx->keyring = keyring; + + return 0; +} + +int nvmf_discovery_ctx_tls_key_set(struct nvmf_discovery_ctx *dctx, + const char *tls_key) +{ + dctx->tls_key = tls_key; + + return 0; +} + +int nvmf_discovery_ctx_tls_key_identity_set(struct nvmf_discovery_ctx *dctx, + const char *tls_key_identity) +{ + dctx->tls_key_identity = tls_key_identity; + + return 0; +} int nvmf_discovery_ctx_default_fabrics_config_set( struct nvmf_discovery_ctx *dctx, @@ -2461,6 +2575,56 @@ int nvmf_connect_config_json(struct nvme_global_ctx *ctx, const char *hostnqn, return ret; } +int nvmf_discovery_config_file(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, struct nvme_host *h, + bool connect, bool force) +{ + nvme_ctrl_t c; + int err; + + err = dctx->parser_init(dctx, dctx->user_data); + if (err) + return err; + + do { + err = dctx->parser_next_line(dctx, dctx->user_data); + if (err) + break; + + struct tr_config trcfg = { + .transport = dctx->transport, + .traddr = dctx->traddr, + .trsvcid = dctx->trsvcid, + .subsysnqn = dctx->subsysnqn, + .host_traddr = dctx->host_traddr, + .host_iface = dctx->host_iface, + }; + + if (!force) { + c = lookup_ctrl(h, &trcfg); + if (c) { + nvmf_discovery(ctx, dctx, connect, c); + continue; + } + } + + err = nvmf_create_discovery_ctrl(ctx, dctx, h, dctx->defcfg, + &trcfg, &c); + if (err) + continue; + + nvmf_discovery(ctx, dctx, connect, c); + if (!(dctx->persistent || is_persistent_discovery_ctrl(h, c))) + err = nvme_disconnect_ctrl(c); + nvme_free_ctrl(c); + } while (!err); + + if (err != -EOF) + return err; + + return 0; +} + #define NBFT_SYSFS_FILENAME "NBFT*" static int nbft_filter(const struct dirent *dent) diff --git a/libnvme/src/nvme/fabrics.h b/libnvme/src/nvme/fabrics.h index 17b3e78c32..fc1869e787 100644 --- a/libnvme/src/nvme/fabrics.h +++ b/libnvme/src/nvme/fabrics.h @@ -46,8 +46,23 @@ int nvmf_discovery_ctx_decide_retry_set(struct nvmf_discovery_ctx *dctx, int nvmf_discovery_ctx_connected_set(struct nvmf_discovery_ctx *dctx, void (*connected)(struct nvmf_discovery_ctx *dctx, struct nvme_ctrl *c, void *user_data)); +int nvmf_discovery_ctx_parser_init_set(struct nvmf_discovery_ctx *dctx, + int (*parser_init)(struct nvmf_discovery_ctx *dctx, + void *user_data)); +int nvmf_discovery_ctx_parser_cleanup_set(struct nvmf_discovery_ctx *dctx, + void (*parser_cleanup)(struct nvmf_discovery_ctx *dctx, + void *user_data)); +int nvmf_discovery_ctx_parser_next_line_set(struct nvmf_discovery_ctx *dctx, + int (*parser_next)(struct nvmf_discovery_ctx *dctx, + void *user_data)); int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, bool persistent); +int nvmf_discovery_ctx_subsysnqn_set(struct nvmf_discovery_ctx *dctx, + const char *subsysnqn); +int nvmf_discovery_ctx_transport_set(struct nvmf_discovery_ctx *dctx, + const char *transport); +int nvmf_discovery_ctx_traddr_set(struct nvmf_discovery_ctx *dctx, + const char *traddr); int nvmf_discovery_ctx_host_traddr_set(struct nvmf_discovery_ctx *dctx, const char *host_traddr); int nvmf_discovery_ctx_host_iface_set(struct nvmf_discovery_ctx *dctx, @@ -55,6 +70,22 @@ int nvmf_discovery_ctx_host_iface_set(struct nvmf_discovery_ctx *dctx, int nvmf_discovery_ctx_default_fabrics_config_set( struct nvmf_discovery_ctx *dctx, struct nvme_fabrics_config *defcfg); +int nvmf_discovery_ctx_trsvcid_set(struct nvmf_discovery_ctx *dctx, + const char *trsvcid); +int nvmf_discovery_ctx_hostnqn_set(struct nvmf_discovery_ctx *dctx, + const char *hostnqn); +int nvmf_discovery_ctx_hostid_set(struct nvmf_discovery_ctx *dctx, + const char *hostid); +int nvmf_discovery_ctx_hostkey_set(struct nvmf_discovery_ctx *dctx, + const char *hostkey); +int nvmf_discovery_ctx_ctrlkey_set(struct nvmf_discovery_ctx *dctx, + const char *ctrlkey); +int nvmf_discovery_ctx_keyring_set(struct nvmf_discovery_ctx *dctx, + const char *keyring); +int nvmf_discovery_ctx_tls_key_set(struct nvmf_discovery_ctx *dctx, + const char *tls_key); +int nvmf_discovery_ctx_tls_key_identity_set(struct nvmf_discovery_ctx *dctx, + const char *tls_key_identity); /** * struct nvme_fabrics_config - Defines all linux nvme fabrics initiator options @@ -427,6 +458,9 @@ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, const char *hostnqn, const char *hostid, bool connect, bool force); +int nvmf_discovery_config_file(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, struct nvme_host *h, + bool connect, bool force); int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, const char *hostnqn_arg, const char *hostid_arg, const char *hostnqn_sys, diff --git a/libnvme/src/nvme/private.h b/libnvme/src/nvme/private.h index 278cf7fab0..59a25d7fd3 100644 --- a/libnvme/src/nvme/private.h +++ b/libnvme/src/nvme/private.h @@ -290,11 +290,29 @@ struct nvmf_discovery_ctx { void *user_data); void (*connected)(struct nvmf_discovery_ctx *dctx, struct nvme_ctrl *c, void *user_data); + int (*parser_init)(struct nvmf_discovery_ctx *dctx, + void *user_data); + void (*parser_cleanup)(struct nvmf_discovery_ctx *dctx, + void *user_data); + int (*parser_next_line)(struct nvmf_discovery_ctx *dctx, + void *user_data); /* connfiguration */ bool persistent; + const char *subsysnqn; + const char *transport; + const char *traddr; const char *host_traddr; const char *host_iface; + const char *trsvcid; + const char *hostnqn; + const char *hostid; + const char *hostkey; + const char *ctrlkey; + const char *keyring; + const char *tls_key; + const char *tls_key_identity; + struct nvme_fabrics_config *cfg; struct nvme_fabrics_config *defcfg; void *user_data; From 945f722d47a24a234e0236545f6413c4995701c9 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 16 Dec 2025 10:47:19 +0100 Subject: [PATCH 09/13] fabrics: move final discovery code to library The final discovery logic can be moved to the library now. This leaves the nvme-cli with just the parsing operations and setting up the discovery context and then the whole logic happens in the library. The APIs are not final there are very rough and these need more cleanups. But the important tasks was to move the logic code into the library. Signed-off-by: Daniel Wagner --- fabrics.c | 294 +++++++++---------------------------- fabrics.h | 6 - libnvme/src/libnvme.map | 1 + libnvme/src/nvme/fabrics.c | 213 ++++++++++++++++++++++++++- libnvme/src/nvme/fabrics.h | 4 +- libnvme/src/nvme/private.h | 1 + 6 files changed, 280 insertions(+), 239 deletions(-) diff --git a/fabrics.c b/fabrics.c index b568516510..067f36b30d 100644 --- a/fabrics.c +++ b/fabrics.c @@ -129,14 +129,6 @@ static const char *nvmf_context = "execution context identification string"; OPT_END() \ } -static bool is_persistent_discovery_ctrl(nvme_host_t h, nvme_ctrl_t c) -{ - if (nvme_host_is_pdc_enabled(h, DEFAULT_PDC_ENABLED)) - return nvme_ctrl_is_unique_discovery_ctrl(c); - - return false; -} - nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct tr_config *trcfg) { nvme_subsystem_t s; @@ -192,92 +184,6 @@ static int nvme_add_ctrl(nvme_host_t h, nvme_ctrl_t c, return ret; } - -static int __create_discover_ctrl(struct nvme_global_ctx *ctx, nvme_host_t h, - struct nvme_fabrics_config *cfg, - struct tr_config *trcfg, - nvme_ctrl_t *ctrl) -{ - nvme_ctrl_t c; - int tmo, ret; - - ret = nvme_create_ctrl(ctx, trcfg->subsysnqn, trcfg->transport, - trcfg->traddr, trcfg->host_traddr, - trcfg->host_iface, trcfg->trsvcid, &c); - if (ret) - return ret; - - nvme_ctrl_set_discovery_ctrl(c, true); - nvme_ctrl_set_unique_discovery_ctrl(c, - strcmp(trcfg->subsysnqn, NVME_DISC_SUBSYS_NAME)); - tmo = set_discovery_kato(cfg); - - ret = nvme_add_ctrl(h, c, cfg); - cfg->keep_alive_tmo = tmo; - if (ret) { - nvme_free_ctrl(c); - return ret; - } - - *ctrl = c; - return 0; -} - -int nvmf_create_discover_ctrl(struct nvme_global_ctx *ctx, nvme_host_t h, - struct nvme_fabrics_config *cfg, - struct tr_config *trcfg, - nvme_ctrl_t *ctrl) -{ - _cleanup_free_ struct nvme_id_ctrl *id = NULL; - nvme_ctrl_t c; - int ret; - - ret = __create_discover_ctrl(ctx, h, cfg, trcfg, &c); - if (ret) - return ret; - - if (nvme_ctrl_is_unique_discovery_ctrl(c)) { - *ctrl = c; - return 0; - } - - id = nvme_alloc(sizeof(*id)); - if (!id) { - nvme_free_ctrl(c); - return -ENOMEM; - } - - /* Find out the name of discovery controller */ - ret = nvme_ctrl_identify(c, id); - if (ret) { - fprintf(stderr, "failed to identify controller, error %s\n", - nvme_strerror(-ret)); - nvme_disconnect_ctrl(c); - nvme_free_ctrl(c); - return ret; - } - - if (!strcmp(id->subnqn, NVME_DISC_SUBSYS_NAME)) { - *ctrl = c; - return 0; - } - - /* - * The subsysnqn is not the well-known name. Prefer the unique - * subsysnqn over the well-known one. - */ - nvme_disconnect_ctrl(c); - nvme_free_ctrl(c); - - trcfg->subsysnqn = id->subnqn; - ret = __create_discover_ctrl(ctx, h, cfg, trcfg, &c); - if (ret) - return ret; - - *ctrl = c; - return 0; -} - static void save_discovery_log(char *raw, struct nvmf_discovery_log *log) { uint64_t numrec = le64_to_cpu(log->numrec); @@ -398,6 +304,67 @@ static void parser_cleanup(struct nvmf_discovery_ctx *dctx, void *user_data) fclose(cdd->f); } +static int discovery_ctx_set_trcfg(struct nvmf_discovery_ctx *dctx, + struct tr_config *trcfg) +{ + int err; + + err = nvmf_discovery_ctx_subsysnqn_set(dctx, trcfg->subsysnqn); + if (err) + return err; + + err = nvmf_discovery_ctx_transport_set(dctx, trcfg->transport); + if (err) + return err; + + err = nvmf_discovery_ctx_traddr_set(dctx, trcfg->traddr); + if (err) + return err; + + err = nvmf_discovery_ctx_host_traddr_set(dctx, trcfg->host_traddr); + if (err) + return err; + + err = nvmf_discovery_ctx_host_iface_set(dctx, trcfg->host_iface); + if (err) + return err; + + err = nvmf_discovery_ctx_trsvcid_set(dctx, trcfg->trsvcid); + if (err) + return err; + + err = nvmf_discovery_ctx_hostnqn_set(dctx, trcfg->hostnqn); + if (err) + return err; + + err = nvmf_discovery_ctx_hostid_set(dctx, trcfg->hostid); + if (err) + return err; + + err = nvmf_discovery_ctx_hostkey_set(dctx, trcfg->hostkey); + if (err) + return err; + + err = nvmf_discovery_ctx_ctrlkey_set(dctx, trcfg->ctrlkey); + if (err) + return err; + + err = nvmf_discovery_ctx_keyring_set(dctx, trcfg->keyring); + if (err) + return err; + + err = nvmf_discovery_ctx_tls_key_set(dctx, trcfg->tls_key); + if (err) + return err; + + err = nvmf_discovery_ctx_tls_key_identity_set(dctx, + trcfg->tls_key_identity); + if (err) + return err; + + return 0; +} + static int parser_next_line(struct nvmf_discovery_ctx *dctx, void *user_data) { struct cb_discovery_data *cdd = user_data; @@ -435,56 +402,7 @@ static int parser_next_line(struct nvmf_discovery_ctx *dctx, void *user_data) if (!trcfg.trsvcid) trcfg.trsvcid = nvmf_get_default_trsvcid(trcfg.transport, true); - ret = nvmf_discovery_ctx_subsysnqn_set(dctx, trcfg.subsysnqn); - if (ret) - return ret; - - ret = nvmf_discovery_ctx_transport_set(dctx, trcfg.transport); - if (ret) - return ret; - - ret = nvmf_discovery_ctx_traddr_set(dctx, trcfg.traddr); - if (ret) - return ret; - - ret = nvmf_discovery_ctx_host_traddr_set(dctx, trcfg.host_traddr); - if (ret) - return ret; - - ret = nvmf_discovery_ctx_host_iface_set(dctx, trcfg.host_iface); - if (ret) - return ret; - - ret = nvmf_discovery_ctx_trsvcid_set(dctx, trcfg.trsvcid); - if (ret) - return ret; - - ret = nvmf_discovery_ctx_hostnqn_set(dctx, trcfg.hostnqn); - if (ret) - return ret; - - ret = nvmf_discovery_ctx_hostid_set(dctx, trcfg.hostid); - if (ret) - return ret; - - ret = nvmf_discovery_ctx_hostkey_set(dctx, trcfg.hostkey); - if (ret) - return ret; - - ret = nvmf_discovery_ctx_ctrlkey_set(dctx, trcfg.ctrlkey); - if (ret) - return ret; - - ret = nvmf_discovery_ctx_keyring_set(dctx, trcfg.keyring); - if (ret) - return ret; - - ret = nvmf_discovery_ctx_tls_key_set(dctx, trcfg.tls_key); - if (ret) - return ret; - - ret = nvmf_discovery_ctx_tls_key_identity_set(dctx, - trcfg.tls_key_identity); + ret = discovery_ctx_set_trcfg(dctx, &trcfg); if (ret) return ret; @@ -497,7 +415,8 @@ static int parser_next_line(struct nvmf_discovery_ctx *dctx, void *user_data) static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, - bool persistent, struct tr_config *trcfg, + bool persistent, const char *device, + struct tr_config *trcfg, struct nvme_fabrics_config *defcfg, void *user_data, struct nvmf_discovery_ctx **dctxp) { @@ -544,15 +463,15 @@ static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, if (err) goto err; - err = nvmf_discovery_ctx_persistent_set(dctx, persistent); + err = nvmf_discovery_ctx_device_set(dctx, device); if (err) goto err; - err = nvmf_discovery_ctx_host_traddr_set(dctx, trcfg->host_traddr); + err = nvmf_discovery_ctx_persistent_set(dctx, persistent); if (err) goto err; - err = nvmf_discovery_ctx_host_iface_set(dctx, trcfg->host_iface); + err = discovery_ctx_set_trcfg(dctx, trcfg); if (err) goto err; @@ -624,7 +543,6 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; _cleanup_free_ struct nvmf_discovery_ctx *dctx = NULL; nvme_host_t h; - nvme_ctrl_t c = NULL; unsigned int verbose = 0; int ret; char *format = "normal"; @@ -713,7 +631,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) .flags = flags, .raw = raw, }; - ret = create_discovery_log_ctx(ctx, persistent, &trcfg, + ret = create_discovery_log_ctx(ctx, persistent, device, &trcfg, &cfg, &dld, &dctx); if (ret) return ret; @@ -739,81 +657,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) if (!trcfg.trsvcid) trcfg.trsvcid = nvmf_get_default_trsvcid(trcfg.transport, true); - if (device && !force) { - ret = nvme_scan_ctrl(ctx, device, &c); - if (!ret) { - /* Check if device matches command-line options */ - if (!nvme_ctrl_config_match(c, trcfg.transport, - trcfg.traddr, trcfg.trsvcid, - trcfg.subsysnqn, trcfg.host_traddr, - trcfg.host_iface)) { - fprintf(stderr, - "ctrl device %s found, ignoring non matching command-line options\n", - device); - } - - if (!nvme_ctrl_is_discovery_ctrl(c)) { - fprintf(stderr, - "ctrl device %s found, ignoring non discovery controller\n", - device); - - nvme_free_ctrl(c); - c = NULL; - persistent = false; - } else { - /* - * If the controller device is found it must - * be persistent, and shouldn't be disconnected - * on exit. - */ - persistent = true; - /* - * When --host-traddr/--host-iface are not specified on the - * command line, use the discovery controller's (c) host- - * traddr/host-iface for the connections to controllers - * returned in the Discovery Log Pages. This is essential - * when invoking "connect-all" with --device to reuse an - * existing persistent discovery controller (as is done - * for the udev rules). This ensures that host-traddr/ - * host-iface are consistent with the discovery controller (c). - */ - if (!trcfg.host_traddr) - trcfg.host_traddr = (char *)nvme_ctrl_get_host_traddr(c); - if (!trcfg.host_iface) - trcfg.host_iface = (char *)nvme_ctrl_get_host_iface(c); - } - } else { - /* - * No controller found, fall back to create one. - * But that controller cannot be persistent. - */ - fprintf(stderr, - "ctrl device %s not found%s\n", device, - persistent ? ", ignoring --persistent" : ""); - persistent = false; - } - } - if (!c && !force) { - c = lookup_ctrl(h, &trcfg); - if (c) - persistent = true; - } - if (!c) { - /* No device or non-matching device, create a new controller */ - ret = nvmf_create_discover_ctrl(ctx, h, &cfg, &trcfg, &c); - if (ret) { - if (ret != -ENVME_CONNECT_IGNORED) - fprintf(stderr, - "failed to add controller, error %s\n", - nvme_strerror(-ret)); - goto out_free; - } - } - - ret = nvmf_discovery(ctx, dctx, connect, c); - if (!(persistent || is_persistent_discovery_ctrl(h, c))) - nvme_disconnect_ctrl(c); - nvme_free_ctrl(c); + ret = nvmf_discovery(ctx, dctx, h, connect, force); out_free: if (dump_config) diff --git a/fabrics.h b/fabrics.h index 2c5ea12bc2..e95fa3e3c0 100644 --- a/fabrics.h +++ b/fabrics.h @@ -26,12 +26,6 @@ extern int nvmf_disconnect(const char *desc, int argc, char **argv); extern int nvmf_disconnect_all(const char *desc, int argc, char **argv); extern int nvmf_config(const char *desc, int argc, char **argv); extern int nvmf_dim(const char *desc, int argc, char **argv); -extern int nvmf_create_discover_ctrl(struct nvme_global_ctx *ctx, nvme_host_t h, - struct nvme_fabrics_config *cfg, - struct tr_config *trcfg, - nvme_ctrl_t *ctrl); -extern char *nvmf_get_default_trsvcid(const char *transport, - bool discovery_ctrl); #endif diff --git a/libnvme/src/libnvme.map b/libnvme/src/libnvme.map index ba6dfcab65..a5bed4b589 100644 --- a/libnvme/src/libnvme.map +++ b/libnvme/src/libnvme.map @@ -300,6 +300,7 @@ LIBNVME_2_0 { nvmf_discovery_ctx_ctrlkey_set; nvmf_discovery_ctx_decide_retry_set; nvmf_discovery_ctx_default_fabrics_config_set; + nvmf_discovery_ctx_device_set; nvmf_discovery_ctx_discovery_log_set; nvmf_discovery_ctx_host_iface_set; nvmf_discovery_ctx_host_traddr_set; diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index 53fa752e0b..415f6fb0eb 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -299,6 +299,14 @@ int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, return 0; } +int nvmf_discovery_ctx_device_set(struct nvmf_discovery_ctx *dctx, + const char *device) +{ + dctx->device = device; + + return 0; +} + int nvmf_discovery_ctx_subsysnqn_set(struct nvmf_discovery_ctx *dctx, const char *subsysnqn) { @@ -2159,8 +2167,9 @@ static int set_discovery_kato(struct nvmf_discovery_ctx *dctx, return tmo; } -int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, - bool connect, struct nvme_ctrl *c) +static int _nvmf_discovery(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, bool connect, + struct nvme_ctrl *c) { _cleanup_free_ struct nvmf_discovery_log *log = NULL; nvme_subsystem_t s = nvme_ctrl_get_subsystem(c); @@ -2259,7 +2268,7 @@ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, if (!child) { if (discover) - nvmf_discovery(ctx, dctx, true, child); + _nvmf_discovery(ctx, dctx, true, child); if (disconnect) { nvme_disconnect_ctrl(child); @@ -2470,7 +2479,7 @@ int _discovery_config_json(struct nvme_global_ctx *ctx, cn = lookup_ctrl(h, &trcfg); if (cn) { dctx->persistent = true; - nvmf_discovery(ctx, dctx, connect, cn); + _nvmf_discovery(ctx, dctx, connect, cn); return 0; } } @@ -2479,7 +2488,7 @@ int _discovery_config_json(struct nvme_global_ctx *ctx, if (ret) return 0; - nvmf_discovery(ctx, dctx, connect, cn); + _nvmf_discovery(ctx, dctx, connect, cn); if (!(dctx->persistent || is_persistent_discovery_ctrl(h, cn))) ret = nvme_disconnect_ctrl(cn); nvme_free_ctrl(cn); @@ -2603,7 +2612,7 @@ int nvmf_discovery_config_file(struct nvme_global_ctx *ctx, if (!force) { c = lookup_ctrl(h, &trcfg); if (c) { - nvmf_discovery(ctx, dctx, connect, c); + _nvmf_discovery(ctx, dctx, connect, c); continue; } } @@ -2613,7 +2622,7 @@ int nvmf_discovery_config_file(struct nvme_global_ctx *ctx, if (err) continue; - nvmf_discovery(ctx, dctx, connect, c); + _nvmf_discovery(ctx, dctx, connect, c); if (!(dctx->persistent || is_persistent_discovery_ctrl(h, c))) err = nvme_disconnect_ctrl(c); nvme_free_ctrl(c); @@ -3087,3 +3096,193 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, nvmf_nbft_free(entry); return ret; } + +static int __create_discover_ctrl(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, + nvme_host_t h, + struct nvme_fabrics_config *cfg, + struct tr_config *trcfg, + struct nvme_ctrl **ctrl) +{ + struct nvme_ctrl *c; + int tmo, ret; + + ret = nvme_create_ctrl(ctx, trcfg->subsysnqn, trcfg->transport, + trcfg->traddr, trcfg->host_traddr, + trcfg->host_iface, trcfg->trsvcid, &c); + if (ret) + return ret; + + nvme_ctrl_set_discovery_ctrl(c, true); + nvme_ctrl_set_unique_discovery_ctrl(c, strcmp(trcfg->subsysnqn, + NVME_DISC_SUBSYS_NAME)); + tmo = set_discovery_kato(dctx, cfg); + + ret = nvme_add_ctrl(dctx, h, c, cfg); + cfg->keep_alive_tmo = tmo; + if (ret) { + nvme_free_ctrl(c); + return ret; + } + + *ctrl = c; + return 0; +} + +static int nvmf_create_discover_ctrl(struct nvme_global_ctx *ctx, + struct nvmf_discovery_ctx *dctx, + struct nvme_host *h, + struct nvme_fabrics_config *cfg, + struct tr_config *trcfg, + struct nvme_ctrl **ctrl) +{ + _cleanup_free_ struct nvme_id_ctrl *id = NULL; + struct nvme_ctrl *c; + int ret; + + ret = __create_discover_ctrl(ctx, dctx, h, cfg, trcfg, &c); + if (ret) + return ret; + + if (nvme_ctrl_is_unique_discovery_ctrl(c)) { + *ctrl = c; + return 0; + } + + id = __nvme_alloc(sizeof(*id)); + if (!id) { + nvme_free_ctrl(c); + return -ENOMEM; + } + + /* Find out the name of discovery controller */ + ret = nvme_ctrl_identify(c, id); + if (ret) { + fprintf(stderr, "failed to identify controller, error %s\n", + nvme_strerror(-ret)); + nvme_disconnect_ctrl(c); + nvme_free_ctrl(c); + return ret; + } + + if (!strcmp(id->subnqn, NVME_DISC_SUBSYS_NAME)) { + *ctrl = c; + return 0; + } + + /* + * The subsysnqn is not the well-known name. Prefer the unique + * subsysnqn over the well-known one. + */ + nvme_disconnect_ctrl(c); + nvme_free_ctrl(c); + + trcfg->subsysnqn = id->subnqn; + ret = __create_discover_ctrl(ctx, dctx, h, cfg, trcfg, &c); + if (ret) + return ret; + + *ctrl = c; + return 0; +} + +int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, + struct nvme_host *h, bool connect, bool force) +{ + struct nvme_ctrl *c = NULL; + int ret; + + if (dctx->device && !force) { + ret = nvme_scan_ctrl(ctx, dctx->device, &c); + if (!ret) { + /* Check if device matches command-line options */ + if (!nvme_ctrl_config_match( + c, dctx->transport, dctx->traddr, + dctx->trsvcid, dctx->subsysnqn, + dctx->host_traddr, dctx->host_iface)) { + nvme_msg( + ctx, LOG_ERR, + "ctrl device %s found, ignoring non matching command-line options\n", + dctx->device); + } + + if (!nvme_ctrl_is_discovery_ctrl(c)) { + nvme_msg( + ctx, LOG_ERR, + "ctrl device %s found, ignoring non discovery controller\n", + dctx->device); + + nvme_free_ctrl(c); + c = NULL; + dctx->persistent = false; + } else { + /* + * If the controller device is found it must + * be persistent, and shouldn't be disconnected + * on exit. + */ + dctx->persistent = true; + /* + * When --host-traddr/--host-iface are not specified on the + * command line, use the discovery controller's (c) host- + * traddr/host-iface for the connections to controllers + * returned in the Discovery Log Pages. This is essential + * when invoking "connect-all" with --device to reuse an + * existing persistent discovery controller (as is done + * for the udev rules). This ensures that host-traddr/ + * host-iface are consistent with the discovery controller (c). + */ + if (!dctx->host_traddr) + dctx->host_traddr = (char *) + nvme_ctrl_get_host_traddr(c); + if (!dctx->host_iface) + dctx->host_iface = (char *) + nvme_ctrl_get_host_iface(c); + } + } else { + /* + * No controller found, fall back to create one. + * But that controller cannot be persistent. + */ + nvme_msg(ctx, LOG_ERR, "ctrl device %s not found%s\n", + dctx->device, + dctx->persistent ? ", ignoring --persistent" : + ""); + dctx->persistent = false; + } + } + + struct tr_config trcfg = { + .subsysnqn = dctx->subsysnqn, + .transport = dctx->transport, + .traddr = dctx->traddr, + .host_traddr = dctx->host_traddr, + .host_iface = dctx->host_iface, + .trsvcid = dctx->trsvcid, + }; + + if (!c && !force) { + c = lookup_ctrl(h, &trcfg); + if (c) + dctx->persistent = true; + } + if (!c) { + /* No device or non-matching device, create a new controller */ + ret = nvmf_create_discover_ctrl(ctx, dctx, h, dctx->defcfg, + &trcfg, &c); + if (ret) { + if (ret != -ENVME_CONNECT_IGNORED) + nvme_msg(ctx, LOG_ERR, + "failed to add controller, error %s\n", + nvme_strerror(-ret)); + return ret; + } + } + + ret = _nvmf_discovery(ctx, dctx, connect, c); + if (!(dctx->persistent || is_persistent_discovery_ctrl(h, c))) + nvme_disconnect_ctrl(c); + nvme_free_ctrl(c); + + return ret; +} diff --git a/libnvme/src/nvme/fabrics.h b/libnvme/src/nvme/fabrics.h index fc1869e787..021faa9806 100644 --- a/libnvme/src/nvme/fabrics.h +++ b/libnvme/src/nvme/fabrics.h @@ -57,6 +57,8 @@ int nvmf_discovery_ctx_parser_next_line_set(struct nvmf_discovery_ctx *dctx, void *user_data)); int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, bool persistent); +int nvmf_discovery_ctx_device_set(struct nvmf_discovery_ctx *dctx, + const char *device); int nvmf_discovery_ctx_subsysnqn_set(struct nvmf_discovery_ctx *dctx, const char *subsysnqn); int nvmf_discovery_ctx_transport_set(struct nvmf_discovery_ctx *dctx, @@ -454,7 +456,7 @@ void nvme_free_uri(struct nvme_fabrics_uri *uri); char *nvmf_get_default_trsvcid(const char *transport, bool discovery_ctrl); int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, - bool connect, struct nvme_ctrl *c); + struct nvme_host *h, bool connect, bool force); int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, const char *hostnqn, const char *hostid, bool connect, bool force); diff --git a/libnvme/src/nvme/private.h b/libnvme/src/nvme/private.h index 59a25d7fd3..4e1e1d3f0a 100644 --- a/libnvme/src/nvme/private.h +++ b/libnvme/src/nvme/private.h @@ -299,6 +299,7 @@ struct nvmf_discovery_ctx { /* connfiguration */ bool persistent; + const char *device; const char *subsysnqn; const char *transport; const char *traddr; From 97b41ba7b768adc0730d607c5e8610e90eb96ec5 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 16 Dec 2025 13:28:45 +0100 Subject: [PATCH 10/13] fabrics: generalize nvmf_discovery_ctx to nvmf_context The connect and discovery APIs use a lot of common context information. Thus generalize the discovery context into nvmf_context which then can be used by either APIs types. Signed-off-by: Daniel Wagner --- fabrics.c | 261 ++++++++------------ libnvme/src/libnvme.map | 9 + libnvme/src/nvme/fabrics.c | 482 ++++++++++++++----------------------- libnvme/src/nvme/fabrics.h | 108 ++++----- libnvme/src/nvme/private.h | 54 +++++ 5 files changed, 393 insertions(+), 521 deletions(-) diff --git a/fabrics.c b/fabrics.c index 067f36b30d..12a206fc35 100644 --- a/fabrics.c +++ b/fabrics.c @@ -207,7 +207,10 @@ static void save_discovery_log(char *raw, struct nvmf_discovery_log *log) close(fd); } -struct cb_discovery_data { +static int setup_common_context(struct nvmf_context *fctx, + struct tr_config *trcfg); + +struct cb_fabrics_data { struct nvme_fabrics_config *defcfg; nvme_print_flags_t flags; char *raw; @@ -215,32 +218,7 @@ struct cb_discovery_data { FILE *f; }; -static void cb_discovery_log(struct nvmf_discovery_ctx *dctx, - bool connect, struct nvmf_discovery_log *log, - uint64_t numrec, void *user_data) -{ - struct cb_discovery_data *cdd = user_data; - - if (cdd->raw) - save_discovery_log(cdd->raw, log); - else if (!connect) - nvme_show_discovery_log(log, numrec, cdd->flags); -} - -static void already_connected(struct nvme_host *host, - struct nvmf_disc_log_entry *entry, - void *user_data) -{ - if (quiet) - return; - - fprintf(stderr, - "already connected to hostnqn=%s,nqn=%s,transport=%s,traddr=%s,trsvcid=%s\n", - nvme_host_get_hostnqn(host), entry->subnqn, - nvmf_trtype_str(entry->trtype), entry->traddr, entry->trsvcid); -} - -static bool nvmf_decide_retry(struct nvmf_discovery_ctx *dctx, int err, +static bool cb_decide_retry(struct nvmf_context *fctx, int err, void *user_data) { if (err == -EAGAIN || (err == -EINTR && !nvme_sigint_received)) { @@ -251,18 +229,18 @@ static bool nvmf_decide_retry(struct nvmf_discovery_ctx *dctx, int err, return false; } -static void nvmf_connected(struct nvmf_discovery_ctx *dctx, +static void cb_connected(struct nvmf_context *fctx, struct nvme_ctrl *c, void *user_data) { - struct cb_discovery_data *cdd = user_data; + struct cb_fabrics_data *cfd = user_data; - if (cdd->flags == NORMAL) { + if (cfd->flags == NORMAL) { printf("device: %s\n", nvme_ctrl_get_name(c)); return; } #ifdef CONFIG_JSONC - if (cdd->flags == JSON) { + if (cfd->flags == JSON) { struct json_object *root; root = json_create_object(); @@ -277,97 +255,61 @@ static void nvmf_connected(struct nvmf_discovery_ctx *dctx, #endif } -static int parser_init(struct nvmf_discovery_ctx *dctx, void *user_data) +static void cb_already_connected(struct nvmf_context *fctx, + struct nvme_host *host, const char *subsysnqn, + const char *transport, const char *traddr, + const char *trsvcid, void *user_data) { - struct cb_discovery_data *cdd = user_data; - - cdd->f = fopen(PATH_NVMF_DISC, "r"); - if (cdd->f == NULL) { - fprintf(stderr, "No params given and no %s\n", PATH_NVMF_DISC); - return -ENOENT; - } - - cdd->argv = calloc(MAX_DISC_ARGS, sizeof(char *)); - if (!cdd->argv) - return -1; - - cdd->argv[0] = "discover"; + if (quiet) + return; - return 0; + fprintf(stderr, "already connected to hostnqn=%s,nqn=%s,transport=%s,traddr=%s,trsvcid=%s\n", + nvme_host_get_hostnqn(host), subsysnqn, + transport, traddr, trsvcid); } -static void parser_cleanup(struct nvmf_discovery_ctx *dctx, void *user_data) +static void cb_discovery_log(struct nvmf_context *fctx, + bool connect, struct nvmf_discovery_log *log, + uint64_t numrec, void *user_data) { - struct cb_discovery_data *cdd = user_data; + struct cb_fabrics_data *cfd = user_data; - free(cdd->argv); - fclose(cdd->f); + if (cfd->raw) + save_discovery_log(cfd->raw, log); + else if (!connect) + nvme_show_discovery_log(log, numrec, cfd->flags); } -static int discovery_ctx_set_trcfg(struct nvmf_discovery_ctx *dctx, - struct tr_config *trcfg) +static int cb_parser_init(struct nvmf_context *dctx, void *user_data) { - int err; - - err = nvmf_discovery_ctx_subsysnqn_set(dctx, trcfg->subsysnqn); - if (err) - return err; - - err = nvmf_discovery_ctx_transport_set(dctx, trcfg->transport); - if (err) - return err; - - err = nvmf_discovery_ctx_traddr_set(dctx, trcfg->traddr); - if (err) - return err; - - err = nvmf_discovery_ctx_host_traddr_set(dctx, trcfg->host_traddr); - if (err) - return err; - - err = nvmf_discovery_ctx_host_iface_set(dctx, trcfg->host_iface); - if (err) - return err; - - err = nvmf_discovery_ctx_trsvcid_set(dctx, trcfg->trsvcid); - if (err) - return err; - - err = nvmf_discovery_ctx_hostnqn_set(dctx, trcfg->hostnqn); - if (err) - return err; - - err = nvmf_discovery_ctx_hostid_set(dctx, trcfg->hostid); - if (err) - return err; + struct cb_fabrics_data *cfd = user_data; - err = nvmf_discovery_ctx_hostkey_set(dctx, trcfg->hostkey); - if (err) - return err; + cfd->f = fopen(PATH_NVMF_DISC, "r"); + if (cfd->f == NULL) { + fprintf(stderr, "No params given and no %s\n", PATH_NVMF_DISC); + return -ENOENT; + } - err = nvmf_discovery_ctx_ctrlkey_set(dctx, trcfg->ctrlkey); - if (err) - return err; + cfd->argv = calloc(MAX_DISC_ARGS, sizeof(char *)); + if (!cfd->argv) + return -1; - err = nvmf_discovery_ctx_keyring_set(dctx, trcfg->keyring); - if (err) - return err; + cfd->argv[0] = "discover"; - err = nvmf_discovery_ctx_tls_key_set(dctx, trcfg->tls_key); - if (err) - return err; + return 0; +} - err = nvmf_discovery_ctx_tls_key_identity_set(dctx, - trcfg->tls_key_identity); - if (err) - return err; +static void cb_parser_cleanup(struct nvmf_context *fctx, void *user_data) +{ + struct cb_fabrics_data *cfd = user_data; - return 0; + free(cfd->argv); + fclose(cfd->f); } -static int parser_next_line(struct nvmf_discovery_ctx *dctx, void *user_data) +static int cb_parser_next_line(struct nvmf_context *fctx, void *user_data) { - struct cb_discovery_data *cdd = user_data; + struct cb_fabrics_data *cfd = user_data; struct nvme_fabrics_config cfg; struct tr_config trcfg = {}; char *ptr, *p, line[4096]; @@ -378,9 +320,9 @@ static int parser_next_line(struct nvmf_discovery_ctx *dctx, void *user_data) OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"), OPT_FLAG("force", 0, &force, "Force persistent discovery controller creation")); - memcpy(&cfg, cdd->defcfg, sizeof(cfg)); + memcpy(&cfg, cfd->defcfg, sizeof(cfg)); next: - if (fgets(line, sizeof(line), cdd->f) == NULL) + if (fgets(line, sizeof(line), cfd->f) == NULL) return -EOF; if (line[0] == '#' || line[0] == '\n') @@ -389,11 +331,11 @@ static int parser_next_line(struct nvmf_discovery_ctx *dctx, void *user_data) argc = 1; p = line; while ((ptr = strsep(&p, " =\n")) != NULL) - cdd->argv[argc++] = ptr; - cdd->argv[argc] = NULL; + cfd->argv[argc++] = ptr; + cfd->argv[argc] = NULL; trcfg.subsysnqn = NVME_DISC_SUBSYS_NAME; - ret = argconfig_parse(argc, cdd->argv, "config", opts); + ret = argconfig_parse(argc, cfd->argv, "config", opts); if (ret) goto next; if (!trcfg.transport && !trcfg.traddr) @@ -402,88 +344,91 @@ static int parser_next_line(struct nvmf_discovery_ctx *dctx, void *user_data) if (!trcfg.trsvcid) trcfg.trsvcid = nvmf_get_default_trsvcid(trcfg.transport, true); - ret = discovery_ctx_set_trcfg(dctx, &trcfg); + ret = setup_common_context(fctx, &trcfg); if (ret) return ret; - ret = nvmf_discovery_ctx_default_fabrics_config_set(dctx, &cfg); + ret = nvmf_context_set_fabrics_config(fctx, &cfg); if (ret) return ret; return 0; } - -static int create_discovery_log_ctx(struct nvme_global_ctx *ctx, - bool persistent, const char *device, - struct tr_config *trcfg, - struct nvme_fabrics_config *defcfg, - void *user_data, struct nvmf_discovery_ctx **dctxp) +static int setup_common_context(struct nvmf_context *fctx, + struct tr_config *trcfg) { - struct nvmf_discovery_ctx *dctx; int err; - err = nvmf_discovery_ctx_create(ctx, user_data, &dctx); + err = nvmf_context_set_connection(fctx, + trcfg->subsysnqn, trcfg->transport, + trcfg->traddr, trcfg->trsvcid, + trcfg->host_traddr, trcfg->host_iface); if (err) return err; - err = nvmf_discovery_ctx_max_retries(dctx, MAX_DISC_RETRIES); - if (err) - goto err; - - err = nvmf_discovery_ctx_keep_alive_timeout(dctx, NVMF_DEF_DISC_TMO); + err = nvmf_context_set_hostnqn(fctx, + trcfg->hostnqn, trcfg->hostid); if (err) - goto err; - - err = nvmf_discovery_ctx_discovery_log_set(dctx, cb_discovery_log); - if (err) - goto err; + return err; - err = nvmf_discovery_ctx_already_connected_set(dctx, already_connected); + err = nvmf_context_set_crypto(fctx, + trcfg->hostkey, trcfg->ctrlkey, + trcfg->keyring, trcfg->tls_key, + trcfg->tls_key_identity); if (err) - goto err; + return err; - err = nvmf_discovery_ctx_decide_retry_set(dctx, nvmf_decide_retry); - if (err) - goto err; + return 0; +} - err = nvmf_discovery_ctx_connected_set(dctx, nvmf_connected); - if (err) - goto err; +static int create_discovery_context(struct nvme_global_ctx *ctx, + bool persistent, const char *device, + struct tr_config *trcfg, + struct nvme_fabrics_config *cfg, + void *user_data, struct nvmf_context **fctxp) +{ + struct nvmf_context *fctx; + int err; - err = nvmf_discovery_ctx_parser_init_set(dctx, parser_init); + err = nvmf_context_create(ctx, cb_decide_retry, cb_connected, + cb_already_connected, user_data, &fctx); if (err) - goto err; + return err; - err = nvmf_discovery_ctx_parser_cleanup_set(dctx, parser_cleanup); + err = nvmf_context_set_connection(fctx, trcfg->subsysnqn, + trcfg->transport, trcfg->traddr, trcfg->trsvcid, + trcfg->host_traddr, trcfg->host_iface); if (err) - goto err; + return err; - err = nvmf_discovery_ctx_parser_next_line_set(dctx, parser_next_line); + err = nvmf_context_set_discovery_cbs(fctx, cb_discovery_log, + cb_parser_init, cb_parser_cleanup, cb_parser_next_line); if (err) - goto err; + return err; - err = nvmf_discovery_ctx_device_set(dctx, device); + err = nvmf_context_set_discovery_defaults(fctx, MAX_DISC_RETRIES, + NVMF_DEF_DISC_TMO); if (err) - goto err; + return err; - err = nvmf_discovery_ctx_persistent_set(dctx, persistent); + err = nvmf_context_set_fabrics_config(fctx, cfg); if (err) goto err; - err = discovery_ctx_set_trcfg(dctx, trcfg); + err = nvmf_context_set_device(fctx, device); if (err) goto err; - err = nvmf_discovery_ctx_default_fabrics_config_set(dctx, defcfg); + err = nvmf_context_set_persistent(fctx, persistent); if (err) goto err; - *dctxp = dctx; + *fctxp = fctx; return 0; err: - free(dctx); + free(fctx); return err; } @@ -541,7 +486,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) char *context = NULL; nvme_print_flags_t flags; _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; - _cleanup_free_ struct nvmf_discovery_ctx *dctx = NULL; + _cleanup_free_ struct nvmf_context *fctx = NULL; nvme_host_t h; unsigned int verbose = 0; int ret; @@ -627,37 +572,37 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) if (trcfg.hostkey) nvme_host_set_dhchap_key(h, trcfg.hostkey); - struct cb_discovery_data dld = { + struct cb_fabrics_data dld = { .flags = flags, .raw = raw, }; - ret = create_discovery_log_ctx(ctx, persistent, device, &trcfg, - &cfg, &dld, &dctx); + ret = create_discovery_context(ctx, persistent, device, &trcfg, + &cfg, &dld, &fctx); if (ret) return ret; if (!device && !trcfg.transport && !trcfg.traddr) { if (!nonbft) - ret = nvmf_discovery_nbft(ctx, dctx, + ret = nvmf_discovery_nbft(ctx, fctx, trcfg.hostnqn, trcfg.hostid, hnqn, hid, connect, &cfg, nbft_path); if (nbft) goto out_free; if (json_config) - ret = nvmf_discovery_config_json(ctx, dctx, + ret = nvmf_discovery_config_json(ctx, fctx, trcfg.hostnqn, trcfg.hostid, connect, force); if (ret || access(PATH_NVMF_DISC, F_OK)) goto out_free; - ret = nvmf_discovery_config_file(ctx, dctx, h, connect, force); + ret = nvmf_discovery_config_file(ctx, fctx, h, connect, force); goto out_free; } if (!trcfg.trsvcid) trcfg.trsvcid = nvmf_get_default_trsvcid(trcfg.transport, true); - ret = nvmf_discovery(ctx, dctx, h, connect, force); + ret = nvmf_discovery(ctx, fctx, h, connect, force); out_free: if (dump_config) diff --git a/libnvme/src/libnvme.map b/libnvme/src/libnvme.map index a5bed4b589..acd67180cc 100644 --- a/libnvme/src/libnvme.map +++ b/libnvme/src/libnvme.map @@ -290,6 +290,15 @@ LIBNVME_2_0 { nvmf_cms_str; nvmf_connect_config_json; nvmf_connect_ctrl; + nvmf_context_create; + nvmf_context_set_connection; + nvmf_context_set_crypto; + nvmf_context_set_device; + nvmf_context_set_discovery_cbs; + nvmf_context_set_discovery_defaults; + nvmf_context_set_fabrics_config; + nvmf_context_set_hostnqn; + nvmf_context_set_persistent; nvmf_default_config; nvmf_discovery; nvmf_discovery_config_file; diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index 415f6fb0eb..9812f6a343 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -197,224 +197,117 @@ const char *nvmf_cms_str(__u8 cm) return arg_str(cms, ARRAY_SIZE(cms), cm); } -int nvmf_discovery_ctx_create(struct nvme_global_ctx *ctx, - void *user_data, struct nvmf_discovery_ctx **dctxp) -{ - struct nvmf_discovery_ctx *dctx; - - dctx = calloc(1, sizeof(*dctx)); - if (!dctx) +int nvmf_context_create(struct nvme_global_ctx *ctx, + bool (*decide_retry)(struct nvmf_context *fctx, int err, + void *user_data), + void (*connected)(struct nvmf_context *fctx, + struct nvme_ctrl *c, void *user_data), + void (*already_connected)(struct nvmf_context *fctx, + struct nvme_host *host, const char *subsysnqn, + const char *transport, const char *traddr, + const char *trsvcid, void *user_data), + void *user_data, struct nvmf_context **fctxp) +{ + struct nvmf_context *fctx; + + fctx = calloc(1, sizeof(*fctx)); + if (!fctx) return -ENOMEM; - dctx->user_data = user_data; - - *dctxp = dctx; - return 0; -} - -int nvmf_discovery_ctx_max_retries(struct nvmf_discovery_ctx *dctx, - int max_retries) -{ - dctx->default_max_discovery_retries = max_retries; - - return 0; -} -int nvmf_discovery_ctx_keep_alive_timeout(struct nvmf_discovery_ctx *dctx, - int keep_alive_timeout) -{ - dctx->default_keep_alive_timeout = keep_alive_timeout; - - return 0; -} - -int nvmf_discovery_ctx_discovery_log_set(struct nvmf_discovery_ctx *dctx, - void (*discover_log)(struct nvmf_discovery_ctx *dctx, - bool connect, struct nvmf_discovery_log *log, - uint64_t numrec, void *user_data)) -{ - dctx->discovery_log = discover_log; - - return 0; -} - -int nvmf_discovery_ctx_already_connected_set(struct nvmf_discovery_ctx *dctx, - void (*already_connected)(struct nvme_host *host, - struct nvmf_disc_log_entry *entry, void *user_data)) -{ - dctx->already_connected = already_connected; - - return 0; -} - -int nvmf_discovery_ctx_decide_retry_set(struct nvmf_discovery_ctx *dctx, - bool (*decide_retry)(struct nvmf_discovery_ctx *dctx, int err, - void *user_data)) -{ - dctx->decide_retry = decide_retry; + fctx->decide_retry = decide_retry; + fctx->connected = connected; + fctx->already_connected = already_connected; - return 0; -} - -int nvmf_discovery_ctx_connected_set(struct nvmf_discovery_ctx *dctx, - void (*connected)(struct nvmf_discovery_ctx *dctx, - struct nvme_ctrl *c, void *user_data)) -{ - dctx->connected = connected; + fctx->user_data = user_data; + *fctxp = fctx; return 0; } -int nvmf_discovery_ctx_parser_init_set(struct nvmf_discovery_ctx *dctx, - int (*parser_init)(struct nvmf_discovery_ctx *dctx, +int nvmf_context_set_discovery_cbs(struct nvmf_context *fctx, + void (*discovery_log)(struct nvmf_context *fctx, + bool connect, + struct nvmf_discovery_log *log, + uint64_t numrec, void *user_data), + int (*parser_init)(struct nvmf_context *fctx, + void *user_data), + void (*parser_cleanup)(struct nvmf_context *fctx, + void *user_data), + int (*parser_next_line)(struct nvmf_context *fctx, void *user_data)) { - dctx->parser_init = parser_init; - - return 0; -} - -int nvmf_discovery_ctx_parser_cleanup_set(struct nvmf_discovery_ctx *dctx, - void (*parser_cleanup)(struct nvmf_discovery_ctx *dctx, - void *user_data)) -{ - dctx->parser_cleanup = parser_cleanup; - - return 0; -} - -int nvmf_discovery_ctx_parser_next_line_set(struct nvmf_discovery_ctx *dctx, - int (*parser_next)(struct nvmf_discovery_ctx *dctx, - void *user_data)) -{ - dctx->parser_next_line = parser_next; - - return 0; -} - -int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, - bool persistent) -{ - dctx->persistent = persistent; - - return 0; -} - -int nvmf_discovery_ctx_device_set(struct nvmf_discovery_ctx *dctx, - const char *device) -{ - dctx->device = device; - - return 0; -} - -int nvmf_discovery_ctx_subsysnqn_set(struct nvmf_discovery_ctx *dctx, - const char *subsysnqn) -{ - dctx->subsysnqn = subsysnqn; - - return 0; -} - -int nvmf_discovery_ctx_transport_set(struct nvmf_discovery_ctx *dctx, - const char *transport) -{ - dctx->transport = transport; - - return 0; -} - -int nvmf_discovery_ctx_traddr_set(struct nvmf_discovery_ctx *dctx, - const char *traddr) -{ - dctx->traddr = traddr; - - return 0; -} - -int nvmf_discovery_ctx_host_traddr_set(struct nvmf_discovery_ctx *dctx, - const char *host_traddr) -{ - dctx->host_traddr = host_traddr; - - return 0; -} - -int nvmf_discovery_ctx_host_iface_set(struct nvmf_discovery_ctx *dctx, - const char *host_iface) -{ - dctx->host_iface = host_iface; - - return 0; -} -int nvmf_discovery_ctx_trsvcid_set(struct nvmf_discovery_ctx *dctx, - const char *trsvcid) -{ - dctx->trsvcid = trsvcid; + fctx->discovery_log = discovery_log; + fctx->parser_init = parser_init; + fctx->parser_cleanup = parser_cleanup; + fctx->parser_next_line = parser_next_line; return 0; } -int nvmf_discovery_ctx_hostnqn_set(struct nvmf_discovery_ctx *dctx, - const char *hostnqn) +int nvmf_context_set_discovery_defaults(struct nvmf_context *fctx, + int max_discovery_retries, int keep_alive_timeout) { - dctx->hostnqn = hostnqn; + fctx->default_max_discovery_retries = max_discovery_retries; + fctx->default_keep_alive_timeout = keep_alive_timeout; return 0; } -int nvmf_discovery_ctx_hostid_set(struct nvmf_discovery_ctx *dctx, - const char *hostid) -{ - dctx->hostid = hostid; - - return 0; -} - -int nvmf_discovery_ctx_hostkey_set(struct nvmf_discovery_ctx *dctx, - const char *hostkey) +int nvmf_context_set_fabrics_config(struct nvmf_context *fctx, + struct nvme_fabrics_config *cfg) { - dctx->hostkey = hostkey; + fctx->cfg = cfg; return 0; } -int nvmf_discovery_ctx_ctrlkey_set(struct nvmf_discovery_ctx *dctx, - const char *ctrlkey) +int nvmf_context_set_connection(struct nvmf_context *fctx, + const char *subsysnqn, const char *transport, + const char *traddr, const char *trsvcid, + const char *host_traddr, const char *host_iface) { - dctx->ctrlkey = ctrlkey; + fctx->subsysnqn = subsysnqn; + fctx->transport = transport; + fctx->traddr = traddr; + fctx->trsvcid = trsvcid; + fctx->host_traddr = host_iface; return 0; } -int nvmf_discovery_ctx_keyring_set(struct nvmf_discovery_ctx *dctx, - const char *keyring) +int nvmf_context_set_hostnqn(struct nvmf_context *fctx, + const char *hostnqn, const char *hostid) { - dctx->keyring = keyring; + fctx->hostnqn = hostnqn; + fctx->hostid = hostid; return 0; } -int nvmf_discovery_ctx_tls_key_set(struct nvmf_discovery_ctx *dctx, - const char *tls_key) +int nvmf_context_set_crypto(struct nvmf_context *fctx, + const char *hostkey, const char *ctrlkey, + const char *keyring, const char *tls_key, + const char *tls_key_identity) { - dctx->tls_key = tls_key; + fctx->hostkey = hostkey; + fctx->ctrlkey = ctrlkey; + fctx->keyring = keyring; + fctx->tls_key = tls_key; + fctx->tls_key_identity = tls_key_identity; return 0; } -int nvmf_discovery_ctx_tls_key_identity_set(struct nvmf_discovery_ctx *dctx, - const char *tls_key_identity) +int nvmf_context_set_persistent(struct nvmf_context *fctx, bool persistent) { - dctx->tls_key_identity = tls_key_identity; + fctx->persistent = persistent; return 0; } -int nvmf_discovery_ctx_default_fabrics_config_set( - struct nvmf_discovery_ctx *dctx, - struct nvme_fabrics_config *defcfg) +int nvmf_context_set_device(struct nvmf_context *fctx, const char *device) { - dctx->defcfg = defcfg; + fctx->device = device; return 0; } @@ -2152,23 +2045,23 @@ static nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct tr_config *trcfg) return NULL; } -static int set_discovery_kato(struct nvmf_discovery_ctx *dctx, +static int set_discovery_kato(struct nvmf_context *fctx, struct nvme_fabrics_config *cfg) { int tmo = cfg->keep_alive_tmo; /* Set kato to NVMF_DEF_DISC_TMO for persistent controllers */ - if (dctx->persistent && !cfg->keep_alive_tmo) - cfg->keep_alive_tmo = dctx->default_keep_alive_timeout; + if (fctx->persistent && !cfg->keep_alive_tmo) + cfg->keep_alive_tmo = fctx->default_keep_alive_timeout; /* Set kato to zero for non-persistent controllers */ - else if (!dctx->persistent && (cfg->keep_alive_tmo > 0)) + else if (!fctx->persistent && (cfg->keep_alive_tmo > 0)) cfg->keep_alive_tmo = 0; return tmo; } static int _nvmf_discovery(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, bool connect, + struct nvmf_context *fctx, bool connect, struct nvme_ctrl *c) { _cleanup_free_ struct nvmf_discovery_log *log = NULL; @@ -2180,7 +2073,7 @@ static int _nvmf_discovery(struct nvme_global_ctx *ctx, struct nvme_get_discovery_args args = { .c = c, .args_size = sizeof(args), - .max_retries = dctx->default_max_discovery_retries, + .max_retries = fctx->default_max_discovery_retries, .result = 0, .lsp = 0, }; @@ -2193,9 +2086,9 @@ static int _nvmf_discovery(struct nvme_global_ctx *ctx, } numrec = le64_to_cpu(log->numrec); - if (dctx->discovery_log) - dctx->discovery_log(dctx, connect, log, numrec, - dctx->user_data); + if (fctx->discovery_log) + fctx->discovery_log(fctx, connect, log, numrec, + fctx->user_data); if (!connect) return 0; @@ -2206,14 +2099,14 @@ static int _nvmf_discovery(struct nvme_global_ctx *ctx, bool discover = false; bool disconnect; nvme_ctrl_t child; - int tmo = dctx->defcfg->keep_alive_tmo; + int tmo = fctx->cfg->keep_alive_tmo; struct tr_config trcfg = { .subsysnqn = e->subnqn, .transport = nvmf_trtype_str(e->trtype), .traddr = e->traddr, - .host_traddr = dctx->host_traddr, - .host_iface = dctx->host_iface, + .host_traddr = fctx->host_traddr, + .host_iface = fctx->host_iface, .trsvcid = e->trsvcid, }; @@ -2241,7 +2134,7 @@ static int _nvmf_discovery(struct nvme_global_ctx *ctx, * Are we supposed to keep the discovery * controller around? */ - disconnect = !dctx->persistent; + disconnect = !fctx->persistent; if (strcmp(e->subnqn, NVME_DISC_SUBSYS_NAME)) { /* @@ -2254,29 +2147,32 @@ static int _nvmf_discovery(struct nvme_global_ctx *ctx, disconnect = false; } - set_discovery_kato(dctx, dctx->defcfg); + set_discovery_kato(fctx, fctx->cfg); } else { /* NVME_NQN_NVME */ disconnect = false; } - err = nvmf_connect_disc_entry(h, e, dctx->host_traddr, - dctx->host_iface, dctx->defcfg, + err = nvmf_connect_disc_entry(h, e, fctx->host_traddr, + fctx->host_iface, fctx->cfg, &discover, &child); - dctx->defcfg->keep_alive_tmo = tmo; + fctx->cfg->keep_alive_tmo = tmo; if (!child) { if (discover) - _nvmf_discovery(ctx, dctx, true, child); + _nvmf_discovery(ctx, fctx, true, child); if (disconnect) { nvme_disconnect_ctrl(child); nvme_free_ctrl(child); } } else if (err == -ENVME_CONNECT_ALREADY) { - dctx->already_connected(h, &log->entries[i], - dctx->user_data); + struct nvmf_disc_log_entry *e = &log->entries[i]; + + fctx->already_connected(fctx, h, e->subnqn, + nvmf_trtype_str(e->trtype), e->traddr, + e->trsvcid, fctx->user_data); } } @@ -2309,7 +2205,7 @@ static bool is_persistent_discovery_ctrl(nvme_host_t h, nvme_ctrl_t c) return false; } -static int nvme_add_ctrl(struct nvmf_discovery_ctx *dctx, +static int nvme_add_ctrl(struct nvmf_context *fctx, struct nvme_host *h, struct nvme_ctrl *c, struct nvme_fabrics_config *cfg) { @@ -2319,14 +2215,14 @@ static int nvme_add_ctrl(struct nvmf_discovery_ctx *dctx, err = nvmf_add_ctrl(h, c, cfg); if (!err) return 0; - if (dctx->decide_retry(dctx, err, dctx->user_data)) + if (fctx->decide_retry(fctx, err, fctx->user_data)) goto retry; return err; } static int __create_discovery_ctrl(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, nvme_host_t h, + struct nvmf_context *fctx, nvme_host_t h, struct nvme_fabrics_config *cfg, struct tr_config *trcfg, struct nvme_ctrl **ctrl) { @@ -2342,9 +2238,9 @@ static int __create_discovery_ctrl(struct nvme_global_ctx *ctx, nvme_ctrl_set_discovery_ctrl(c, true); nvme_ctrl_set_unique_discovery_ctrl(c, strcmp(trcfg->subsysnqn, NVME_DISC_SUBSYS_NAME)); - tmo = set_discovery_kato(dctx, cfg); + tmo = set_discovery_kato(fctx, cfg); - ret = nvme_add_ctrl(dctx, h, c, cfg); + ret = nvme_add_ctrl(fctx, h, c, cfg); cfg->keep_alive_tmo = tmo; if (ret) { nvme_free_ctrl(c); @@ -2355,8 +2251,8 @@ static int __create_discovery_ctrl(struct nvme_global_ctx *ctx, return 0; } -int nvmf_create_discovery_ctrl(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, nvme_host_t h, +static int nvmf_create_discovery_ctrl(struct nvme_global_ctx *ctx, + struct nvmf_context *fctx, nvme_host_t h, struct nvme_fabrics_config *cfg, struct tr_config *trcfg, struct nvme_ctrl **ctrl) @@ -2365,7 +2261,7 @@ int nvmf_create_discovery_ctrl(struct nvme_global_ctx *ctx, struct nvme_ctrl *c; int ret; - ret = __create_discovery_ctrl(ctx, dctx, h, cfg, trcfg, &c); + ret = __create_discovery_ctrl(ctx, fctx, h, cfg, trcfg, &c); if (ret) return ret; @@ -2403,7 +2299,7 @@ int nvmf_create_discovery_ctrl(struct nvme_global_ctx *ctx, nvme_free_ctrl(c); trcfg->subsysnqn = id->subnqn; - ret = __create_discovery_ctrl(ctx, dctx, h, cfg, trcfg, &c); + ret = __create_discovery_ctrl(ctx, fctx, h, cfg, trcfg, &c); if (ret) return ret; @@ -2412,7 +2308,7 @@ int nvmf_create_discovery_ctrl(struct nvme_global_ctx *ctx, } int _discovery_config_json(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, nvme_host_t h, nvme_ctrl_t c, + struct nvmf_context *fctx, nvme_host_t h, nvme_ctrl_t c, bool connect, bool force) { const char *transport, *traddr, *host_traddr; @@ -2462,9 +2358,9 @@ int _discovery_config_json(struct nvme_global_ctx *ctx, subsysnqn = NVME_DISC_SUBSYS_NAME; if (nvme_ctrl_is_persistent(c)) - dctx->persistent = true; + fctx->persistent = true; - memcpy(&cfg, dctx->defcfg, sizeof(cfg)); + memcpy(&cfg, fctx->cfg, sizeof(cfg)); struct tr_config trcfg = { .subsysnqn = subsysnqn, @@ -2478,18 +2374,18 @@ int _discovery_config_json(struct nvme_global_ctx *ctx, if (!force) { cn = lookup_ctrl(h, &trcfg); if (cn) { - dctx->persistent = true; - _nvmf_discovery(ctx, dctx, connect, cn); + fctx->persistent = true; + _nvmf_discovery(ctx, fctx, connect, cn); return 0; } } - ret = nvmf_create_discovery_ctrl(ctx, dctx, h, &cfg, &trcfg, &cn); + ret = nvmf_create_discovery_ctrl(ctx, fctx, h, &cfg, &trcfg, &cn); if (ret) return 0; - _nvmf_discovery(ctx, dctx, connect, cn); - if (!(dctx->persistent || is_persistent_discovery_ctrl(h, cn))) + _nvmf_discovery(ctx, fctx, connect, cn); + if (!(fctx->persistent || is_persistent_discovery_ctrl(h, cn))) ret = nvme_disconnect_ctrl(cn); nvme_free_ctrl(cn); @@ -2497,7 +2393,7 @@ int _discovery_config_json(struct nvme_global_ctx *ctx, } int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, const char *hostnqn, + struct nvmf_context *fctx, const char *hostnqn, const char *hostid, bool connect, bool force) { const char *hnqn, *hid; @@ -2516,7 +2412,7 @@ int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, continue; nvme_subsystem_for_each_ctrl(s, c) { - err = _discovery_config_json(ctx, dctx, h, c, + err = _discovery_config_json(ctx, fctx, h, c, connect, force); if (err) { nvme_msg(ctx, LOG_ERR, @@ -2585,45 +2481,45 @@ int nvmf_connect_config_json(struct nvme_global_ctx *ctx, const char *hostnqn, } int nvmf_discovery_config_file(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, struct nvme_host *h, + struct nvmf_context *fctx, struct nvme_host *h, bool connect, bool force) { nvme_ctrl_t c; int err; - err = dctx->parser_init(dctx, dctx->user_data); + err = fctx->parser_init(fctx, fctx->user_data); if (err) return err; do { - err = dctx->parser_next_line(dctx, dctx->user_data); + err = fctx->parser_next_line(fctx, fctx->user_data); if (err) break; struct tr_config trcfg = { - .transport = dctx->transport, - .traddr = dctx->traddr, - .trsvcid = dctx->trsvcid, - .subsysnqn = dctx->subsysnqn, - .host_traddr = dctx->host_traddr, - .host_iface = dctx->host_iface, + .transport = fctx->transport, + .traddr = fctx->traddr, + .trsvcid = fctx->trsvcid, + .subsysnqn = fctx->subsysnqn, + .host_traddr = fctx->host_traddr, + .host_iface = fctx->host_iface, }; if (!force) { c = lookup_ctrl(h, &trcfg); if (c) { - _nvmf_discovery(ctx, dctx, connect, c); + _nvmf_discovery(ctx, fctx, connect, c); continue; } } - err = nvmf_create_discovery_ctrl(ctx, dctx, h, dctx->defcfg, + err = nvmf_create_discovery_ctrl(ctx, fctx, h, fctx->cfg, &trcfg, &c); if (err) continue; - _nvmf_discovery(ctx, dctx, connect, c); - if (!(dctx->persistent || is_persistent_discovery_ctrl(h, c))) + _nvmf_discovery(ctx, fctx, connect, c); + if (!(fctx->persistent || is_persistent_discovery_ctrl(h, c))) err = nvme_disconnect_ctrl(c); nvme_free_ctrl(c); } while (!err); @@ -2717,7 +2613,7 @@ static bool validate_uri(struct nbft_info_discovery *dd, } static int nbft_connect(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, struct nvme_host *h, + struct nvmf_context *fctx, struct nvme_host *h, struct nvmf_disc_log_entry *e, struct nbft_info_subsystem_ns *ss, struct tr_config *trcfg, struct nvme_fabrics_config *cfg) @@ -2776,14 +2672,14 @@ static int nbft_connect(struct nvme_global_ctx *ctx, return ret; } - if (dctx->connected) - dctx->connected(dctx, c, dctx->user_data); + if (fctx->connected) + fctx->connected(fctx, c, fctx->user_data); return 0; } static int nbft_discovery(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, struct nbft_info_discovery *dd, + struct nvmf_context *fctx, struct nbft_info_discovery *dd, struct nvme_host *h, struct nvme_ctrl *c, struct nvme_fabrics_config *defcfg, struct tr_config *deftrcfg) { @@ -2817,8 +2713,8 @@ static int nbft_discovery(struct nvme_global_ctx *ctx, .subsysnqn = e->subnqn, .transport = nvmf_trtype_str(e->trtype), .traddr = e->traddr, - .host_traddr = dctx->host_traddr, - .host_iface = dctx->host_iface, + .host_traddr = fctx->host_traddr, + .host_iface = fctx->host_iface, .trsvcid = e->trsvcid, }; @@ -2838,15 +2734,15 @@ static int nbft_discovery(struct nvme_global_ctx *ctx, if (e->subtype == NVME_NQN_DISC) { nvme_ctrl_t child; - ret = nvmf_connect_disc_entry(h, e, dctx->host_traddr, - dctx->host_iface, defcfg, NULL, &child); + ret = nvmf_connect_disc_entry(h, e, fctx->host_traddr, + fctx->host_iface, defcfg, NULL, &child); if (ret) continue; - nbft_discovery(ctx, dctx, dd, h, child, defcfg, &trcfg); + nbft_discovery(ctx, fctx, dd, h, child, defcfg, &trcfg); nvme_disconnect_ctrl(child); nvme_free_ctrl(child); } else { - ret = nbft_connect(ctx, dctx, h, e, NULL, + ret = nbft_connect(ctx, fctx, h, e, NULL, &trcfg, defcfg); /* @@ -2860,7 +2756,7 @@ static int nbft_discovery(struct nvme_global_ctx *ctx, const char *htradr = trcfg.host_traddr; trcfg.host_traddr = NULL; - ret = nbft_connect(ctx, dctx, h, e, NULL, + ret = nbft_connect(ctx, fctx, h, e, NULL, &trcfg, defcfg); if (ret == 0) @@ -2886,7 +2782,7 @@ static int nbft_discovery(struct nvme_global_ctx *ctx, } int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, const char *hostnqn_arg, + struct nvmf_context *fctx, const char *hostnqn_arg, const char *hostid_arg, const char *hostnqn_sys, const char *hostid_sys, bool connect, struct nvme_fabrics_config *cfg, char *nbft_path) @@ -2954,7 +2850,7 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, } host_traddr = NULL; - if (!dctx->host_traddr && + if (!fctx->host_traddr && !strncmp((*ss)->transport, "tcp", 3)) host_traddr = hfi->tcp_info.ipaddr; @@ -2967,7 +2863,7 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, .trsvcid = (*ss)->trsvcid, }; - rr = nbft_connect(ctx, dctx, h, NULL, + rr = nbft_connect(ctx, fctx, h, NULL, *ss, &trcfg, cfg); /* @@ -2980,7 +2876,7 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { trcfg.host_traddr = NULL; - rr = nbft_connect(ctx, dctx, h, NULL, + rr = nbft_connect(ctx, fctx, h, NULL, *ss, &trcfg, cfg); if (rr == 0) @@ -3035,7 +2931,7 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, continue; host_traddr = NULL; - if (!dctx->host_traddr && + if (!fctx->host_traddr && !strncmp(uri->protocol, "tcp", 3)) host_traddr = hfi->tcp_info.ipaddr; if (uri->port > 0) { @@ -3063,14 +2959,14 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, persistent = true; if (!c) { - ret = nvmf_create_discovery_ctrl(ctx, dctx, h, + ret = nvmf_create_discovery_ctrl(ctx, fctx, h, cfg, &trcfg, &c); if (ret == -ENVME_CONNECT_ADDRNOTAVAIL && !strcmp(trcfg.transport, "tcp") && strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { trcfg.host_traddr = NULL; ret = nvmf_create_discovery_ctrl(ctx, - dctx, h, cfg, &trcfg, &c); + fctx, h, cfg, &trcfg, &c); } } else ret = 0; @@ -3082,7 +2978,7 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, goto out_free; } - rr = nbft_discovery(ctx, dctx, *dd, h, c, cfg, &trcfg); + rr = nbft_discovery(ctx, fctx, *dd, h, c, cfg, &trcfg); if (!persistent) nvme_disconnect_ctrl(c); nvme_free_ctrl(c); @@ -3098,11 +2994,9 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, } static int __create_discover_ctrl(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, - nvme_host_t h, - struct nvme_fabrics_config *cfg, - struct tr_config *trcfg, - struct nvme_ctrl **ctrl) + struct nvmf_context *fctx, nvme_host_t h, + struct nvme_fabrics_config *cfg, struct tr_config *trcfg, + struct nvme_ctrl **ctrl) { struct nvme_ctrl *c; int tmo, ret; @@ -3114,11 +3008,11 @@ static int __create_discover_ctrl(struct nvme_global_ctx *ctx, return ret; nvme_ctrl_set_discovery_ctrl(c, true); - nvme_ctrl_set_unique_discovery_ctrl(c, strcmp(trcfg->subsysnqn, - NVME_DISC_SUBSYS_NAME)); - tmo = set_discovery_kato(dctx, cfg); + nvme_ctrl_set_unique_discovery_ctrl(c, + strcmp(trcfg->subsysnqn, NVME_DISC_SUBSYS_NAME)); + tmo = set_discovery_kato(fctx, cfg); - ret = nvme_add_ctrl(dctx, h, c, cfg); + ret = nvme_add_ctrl(fctx, h, c, cfg); cfg->keep_alive_tmo = tmo; if (ret) { nvme_free_ctrl(c); @@ -3130,17 +3024,15 @@ static int __create_discover_ctrl(struct nvme_global_ctx *ctx, } static int nvmf_create_discover_ctrl(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, - struct nvme_host *h, - struct nvme_fabrics_config *cfg, - struct tr_config *trcfg, - struct nvme_ctrl **ctrl) + struct nvmf_context *fctx, + struct nvme_host *h, struct nvme_fabrics_config *cfg, + struct tr_config *trcfg, struct nvme_ctrl **ctrl) { _cleanup_free_ struct nvme_id_ctrl *id = NULL; struct nvme_ctrl *c; int ret; - ret = __create_discover_ctrl(ctx, dctx, h, cfg, trcfg, &c); + ret = __create_discover_ctrl(ctx, fctx, h, cfg, trcfg, &c); if (ret) return ret; @@ -3178,7 +3070,7 @@ static int nvmf_create_discover_ctrl(struct nvme_global_ctx *ctx, nvme_free_ctrl(c); trcfg->subsysnqn = id->subnqn; - ret = __create_discover_ctrl(ctx, dctx, h, cfg, trcfg, &c); + ret = __create_discover_ctrl(ctx, fctx, h, cfg, trcfg, &c); if (ret) return ret; @@ -3186,42 +3078,41 @@ static int nvmf_create_discover_ctrl(struct nvme_global_ctx *ctx, return 0; } -int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, - struct nvme_host *h, bool connect, bool force) +int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, + struct nvme_host *h, bool connect, bool force) { struct nvme_ctrl *c = NULL; int ret; - if (dctx->device && !force) { - ret = nvme_scan_ctrl(ctx, dctx->device, &c); + if (fctx->device && !force) { + ret = nvme_scan_ctrl(ctx, fctx->device, &c); if (!ret) { /* Check if device matches command-line options */ - if (!nvme_ctrl_config_match( - c, dctx->transport, dctx->traddr, - dctx->trsvcid, dctx->subsysnqn, - dctx->host_traddr, dctx->host_iface)) { - nvme_msg( - ctx, LOG_ERR, - "ctrl device %s found, ignoring non matching command-line options\n", - dctx->device); + if (!nvme_ctrl_config_match(c, fctx->transport, + fctx->traddr, fctx->trsvcid, + fctx->subsysnqn, fctx->host_traddr, + fctx->host_iface)) { + nvme_msg(ctx, LOG_ERR, + "ctrl device %s found, ignoring non matching command-line options\n", + fctx->device); } if (!nvme_ctrl_is_discovery_ctrl(c)) { nvme_msg( ctx, LOG_ERR, "ctrl device %s found, ignoring non discovery controller\n", - dctx->device); + fctx->device); nvme_free_ctrl(c); c = NULL; - dctx->persistent = false; + fctx->persistent = false; } else { /* * If the controller device is found it must * be persistent, and shouldn't be disconnected * on exit. */ - dctx->persistent = true; + fctx->persistent = true; /* * When --host-traddr/--host-iface are not specified on the * command line, use the discovery controller's (c) host- @@ -3232,11 +3123,11 @@ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, * for the udev rules). This ensures that host-traddr/ * host-iface are consistent with the discovery controller (c). */ - if (!dctx->host_traddr) - dctx->host_traddr = (char *) + if (!fctx->host_traddr) + fctx->host_traddr = (char *) nvme_ctrl_get_host_traddr(c); - if (!dctx->host_iface) - dctx->host_iface = (char *) + if (!fctx->host_iface) + fctx->host_iface = (char *) nvme_ctrl_get_host_iface(c); } } else { @@ -3244,32 +3135,31 @@ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, * No controller found, fall back to create one. * But that controller cannot be persistent. */ - nvme_msg(ctx, LOG_ERR, "ctrl device %s not found%s\n", - dctx->device, - dctx->persistent ? ", ignoring --persistent" : - ""); - dctx->persistent = false; + nvme_msg(ctx, LOG_ERR, + "ctrl device %s not found%s\n", fctx->device, + fctx->persistent ? ", ignoring --persistent" : ""); + fctx->persistent = false; } } struct tr_config trcfg = { - .subsysnqn = dctx->subsysnqn, - .transport = dctx->transport, - .traddr = dctx->traddr, - .host_traddr = dctx->host_traddr, - .host_iface = dctx->host_iface, - .trsvcid = dctx->trsvcid, + .subsysnqn = fctx->subsysnqn, + .transport = fctx->transport, + .traddr = fctx->traddr, + .host_traddr = fctx->host_traddr, + .host_iface = fctx->host_iface, + .trsvcid = fctx->trsvcid, }; if (!c && !force) { c = lookup_ctrl(h, &trcfg); if (c) - dctx->persistent = true; + fctx->persistent = true; } if (!c) { /* No device or non-matching device, create a new controller */ - ret = nvmf_create_discover_ctrl(ctx, dctx, h, dctx->defcfg, - &trcfg, &c); + ret = nvmf_create_discover_ctrl(ctx, fctx, h, fctx->cfg, + &trcfg, &c); if (ret) { if (ret != -ENVME_CONNECT_IGNORED) nvme_msg(ctx, LOG_ERR, @@ -3279,8 +3169,8 @@ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, } } - ret = _nvmf_discovery(ctx, dctx, connect, c); - if (!(dctx->persistent || is_persistent_discovery_ctrl(h, c))) + ret = _nvmf_discovery(ctx, fctx, connect, c); + if (!(fctx->persistent || is_persistent_discovery_ctrl(h, c))) nvme_disconnect_ctrl(c); nvme_free_ctrl(c); diff --git a/libnvme/src/nvme/fabrics.h b/libnvme/src/nvme/fabrics.h index 021faa9806..8d3e384568 100644 --- a/libnvme/src/nvme/fabrics.h +++ b/libnvme/src/nvme/fabrics.h @@ -23,71 +23,45 @@ /* default to 600 seconds of reconnect attempts before giving up */ #define NVMF_DEF_CTRL_LOSS_TMO 600 -struct nvmf_discovery_ctx; - -int nvmf_discovery_ctx_create(struct nvme_global_ctx *ctx, - void *user_data, struct nvmf_discovery_ctx **dctx); - -int nvmf_discovery_ctx_max_retries(struct nvmf_discovery_ctx *dctx, - int max_retries); -int nvmf_discovery_ctx_keep_alive_timeout(struct nvmf_discovery_ctx *dctx, - int keep_alive_timeout); -int nvmf_discovery_ctx_discovery_log_set(struct nvmf_discovery_ctx *dctx, - void (*discover_log)(struct nvmf_discovery_ctx *dctx, - bool connect, struct nvmf_discovery_log *log, - uint64_t numrec, void *user_data)); -int nvmf_discovery_ctx_already_connected_set(struct nvmf_discovery_ctx *dctx, - void (*already_connected)(struct nvme_host *host, - struct nvmf_disc_log_entry *entry, +struct nvmf_context; + +int nvmf_context_create(struct nvme_global_ctx *ctx, + bool (*decide_retry)(struct nvmf_context *fctx, int err, + void *user_data), + void (*connected)(struct nvmf_context *fctx, + struct nvme_ctrl *c, void *user_data), + void (*already_connected)(struct nvmf_context *fctx, + struct nvme_host *host, const char *subsysnqn, + const char *transport, const char *traddr, + const char *trsvcid, void *user_data), + void *user_data, struct nvmf_context **fctxp); +int nvmf_context_set_discovery_cbs(struct nvmf_context *fctx, + void (*discovery_log)(struct nvmf_context *fctx, + bool connect, + struct nvmf_discovery_log *log, + uint64_t numrec, void *user_data), + int (*parser_init)(struct nvmf_context *fctx, + void *user_data), + void (*parser_cleanup)(struct nvmf_context *fctx, + void *user_data), + int (*parser_next_line)(struct nvmf_context *fctx, void *user_data)); -int nvmf_discovery_ctx_decide_retry_set(struct nvmf_discovery_ctx *dctx, - bool (*decide_retry)(struct nvmf_discovery_ctx *dctx, int err, - void *user_data)); -int nvmf_discovery_ctx_connected_set(struct nvmf_discovery_ctx *dctx, - void (*connected)(struct nvmf_discovery_ctx *dctx, - struct nvme_ctrl *c, void *user_data)); -int nvmf_discovery_ctx_parser_init_set(struct nvmf_discovery_ctx *dctx, - int (*parser_init)(struct nvmf_discovery_ctx *dctx, - void *user_data)); -int nvmf_discovery_ctx_parser_cleanup_set(struct nvmf_discovery_ctx *dctx, - void (*parser_cleanup)(struct nvmf_discovery_ctx *dctx, - void *user_data)); -int nvmf_discovery_ctx_parser_next_line_set(struct nvmf_discovery_ctx *dctx, - int (*parser_next)(struct nvmf_discovery_ctx *dctx, - void *user_data)); -int nvmf_discovery_ctx_persistent_set(struct nvmf_discovery_ctx *dctx, - bool persistent); -int nvmf_discovery_ctx_device_set(struct nvmf_discovery_ctx *dctx, - const char *device); -int nvmf_discovery_ctx_subsysnqn_set(struct nvmf_discovery_ctx *dctx, - const char *subsysnqn); -int nvmf_discovery_ctx_transport_set(struct nvmf_discovery_ctx *dctx, - const char *transport); -int nvmf_discovery_ctx_traddr_set(struct nvmf_discovery_ctx *dctx, - const char *traddr); -int nvmf_discovery_ctx_host_traddr_set(struct nvmf_discovery_ctx *dctx, - const char *host_traddr); -int nvmf_discovery_ctx_host_iface_set(struct nvmf_discovery_ctx *dctx, - const char *host_iface); -int nvmf_discovery_ctx_default_fabrics_config_set( - struct nvmf_discovery_ctx *dctx, - struct nvme_fabrics_config *defcfg); -int nvmf_discovery_ctx_trsvcid_set(struct nvmf_discovery_ctx *dctx, - const char *trsvcid); -int nvmf_discovery_ctx_hostnqn_set(struct nvmf_discovery_ctx *dctx, - const char *hostnqn); -int nvmf_discovery_ctx_hostid_set(struct nvmf_discovery_ctx *dctx, - const char *hostid); -int nvmf_discovery_ctx_hostkey_set(struct nvmf_discovery_ctx *dctx, - const char *hostkey); -int nvmf_discovery_ctx_ctrlkey_set(struct nvmf_discovery_ctx *dctx, - const char *ctrlkey); -int nvmf_discovery_ctx_keyring_set(struct nvmf_discovery_ctx *dctx, - const char *keyring); -int nvmf_discovery_ctx_tls_key_set(struct nvmf_discovery_ctx *dctx, - const char *tls_key); -int nvmf_discovery_ctx_tls_key_identity_set(struct nvmf_discovery_ctx *dctx, +int nvmf_context_set_discovery_defaults(struct nvmf_context *fctx, + int max_discovery_retries, int keep_alive_timeout); +int nvmf_context_set_fabrics_config(struct nvmf_context *fctx, + struct nvme_fabrics_config *cfg); +int nvmf_context_set_connection(struct nvmf_context *fctx, + const char *subsysnqn, const char *transport, + const char *traddr, const char *trsvcid, + const char *host_traddr, const char *host_iface); +int nvmf_context_set_hostnqn(struct nvmf_context *fctx, + const char *hostnqn, const char *hostid); +int nvmf_context_set_crypto(struct nvmf_context *fctx, + const char *hostkey, const char *ctrlkey, + const char *keyring, const char *tls_key, const char *tls_key_identity); +int nvmf_context_set_persistent(struct nvmf_context *fctx, bool persistent); +int nvmf_context_set_device(struct nvmf_context *fctx, const char *device); /** * struct nvme_fabrics_config - Defines all linux nvme fabrics initiator options @@ -455,16 +429,16 @@ void nvme_free_uri(struct nvme_fabrics_uri *uri); char *nvmf_get_default_trsvcid(const char *transport, bool discovery_ctrl); -int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_discovery_ctx *dctx, +int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, struct nvme_host *h, bool connect, bool force); int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, const char *hostnqn, + struct nvmf_context *fctx, const char *hostnqn, const char *hostid, bool connect, bool force); int nvmf_discovery_config_file(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, struct nvme_host *h, + struct nvmf_context *fctx, struct nvme_host *h, bool connect, bool force); int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, - struct nvmf_discovery_ctx *dctx, const char *hostnqn_arg, + struct nvmf_context *fctx, const char *hostnqn_arg, const char *hostid_arg, const char *hostnqn_sys, const char *hostid_sys, bool connect, struct nvme_fabrics_config *cfg, char *nbft_path); diff --git a/libnvme/src/nvme/private.h b/libnvme/src/nvme/private.h index 4e1e1d3f0a..637088caef 100644 --- a/libnvme/src/nvme/private.h +++ b/libnvme/src/nvme/private.h @@ -319,6 +319,60 @@ struct nvmf_discovery_ctx { void *user_data; }; +struct nvmf_context { + /* common callbacks */ + bool (*decide_retry)(struct nvmf_context *fctx, int err, + void *user_data); + void (*connected)(struct nvmf_context *fctx, struct nvme_ctrl *c, + void *user_data); + void (*already_connected)(struct nvmf_context *fctx, + struct nvme_host *host, const char *subsysnqn, + const char *transport, const char *traddr, + const char *trsvcid, void *user_data); + + /* discovery callbacks */ + void (*discovery_log)(struct nvmf_context *fctx, + bool connect, + struct nvmf_discovery_log *log, + uint64_t numrec, void *user_data); + int (*parser_init)(struct nvmf_context *fctx, + void *user_data); + void (*parser_cleanup)(struct nvmf_context *fctx, + void *user_data); + int (*parser_next_line)(struct nvmf_context *fctx, + void *user_data); + + /* discovery defaults */ + int default_max_discovery_retries; + int default_keep_alive_timeout; + + /* common fabrics configuraiton */ + const char *device; + bool persistent; + struct nvme_fabrics_config *cfg; + + /* connection configuration */ + const char *subsysnqn; + const char *transport; + const char *traddr; + const char *trsvcid; + const char *host_traddr; + const char *host_iface; + + /* host configuration */ + const char *hostnqn; + const char *hostid; + + /* authentication and transport encryption configuration */ + const char *hostkey; + const char *ctrlkey; + const char *keyring; + const char *tls_key; + const char *tls_key_identity; + + void *user_data; +}; + struct tr_config { const char *subsysnqn; const char *transport; From 0c978aa4a4210cbbcab662b28904f4d78d9e0dbe Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 16 Dec 2025 15:23:26 +0100 Subject: [PATCH 11/13] fabrics: move connect logic to library Move more of the logic code into the library. Drop the nvmf_ prefix for the commands in nvme-cli so we can use it for the library. Signed-off-by: Daniel Wagner --- fabrics.c | 291 ++++++++++++++++--------------------- fabrics.h | 30 +--- libnvme/src/libnvme.map | 1 + libnvme/src/nvme/fabrics.c | 113 ++++++++++++-- libnvme/src/nvme/fabrics.h | 2 + libnvme/src/nvme/private.h | 2 +- nvme.c | 14 +- 7 files changed, 242 insertions(+), 211 deletions(-) diff --git a/fabrics.c b/fabrics.c index 12a206fc35..af9fdcbded 100644 --- a/fabrics.c +++ b/fabrics.c @@ -94,21 +94,37 @@ static const char *nvmf_concat = "enable secure concatenation"; static const char *nvmf_config_file = "Use specified JSON configuration file or 'none' to disable"; static const char *nvmf_context = "execution context identification string"; -#define NVMF_ARGS(n, t, c, ...) \ +struct fabric_args { + const char *subsysnqn; + const char *transport; + const char *traddr; + const char *host_traddr; + const char *host_iface; + const char *trsvcid; + const char *hostnqn; + const char *hostid; + const char *hostkey; + const char *ctrlkey; + const char *keyring; + const char *tls_key; + const char *tls_key_identity; +}; + +#define NVMF_ARGS(n, f, c, ...) \ struct argconfig_commandline_options n[] = { \ - OPT_STRING("transport", 't', "STR", &t.transport, nvmf_tport), \ - OPT_STRING("nqn", 'n', "STR", &t.subsysnqn, nvmf_nqn), \ - OPT_STRING("traddr", 'a', "STR", &t.traddr, nvmf_traddr), \ - OPT_STRING("trsvcid", 's', "STR", &t.trsvcid, nvmf_trsvcid), \ - OPT_STRING("host-traddr", 'w', "STR", &t.host_traddr, nvmf_htraddr), \ - OPT_STRING("host-iface", 'f', "STR", &t.host_iface, nvmf_hiface), \ - OPT_STRING("hostnqn", 'q', "STR", &t.hostnqn, nvmf_hostnqn), \ - OPT_STRING("hostid", 'I', "STR", &t.hostid, nvmf_hostid), \ - OPT_STRING("dhchap-secret", 'S', "STR", &t.hostkey, nvmf_hostkey), \ - OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &t.ctrlkey, nvmf_ctrlkey), \ - OPT_STRING("keyring", 0, "STR", &t.keyring, nvmf_keyring), \ - OPT_STRING("tls-key", 0, "STR", &t.tls_key, nvmf_tls_key), \ - OPT_STRING("tls-key-identity", 0, "STR", &t.tls_key_identity, nvmf_tls_key_identity), \ + OPT_STRING("transport", 't', "STR", &f.transport, nvmf_tport), \ + OPT_STRING("nqn", 'n', "STR", &f.subsysnqn, nvmf_nqn), \ + OPT_STRING("traddr", 'a', "STR", &f.traddr, nvmf_traddr), \ + OPT_STRING("trsvcid", 's', "STR", &f.trsvcid, nvmf_trsvcid), \ + OPT_STRING("host-traddr", 'w', "STR", &f.host_traddr, nvmf_htraddr), \ + OPT_STRING("host-iface", 'f', "STR", &f.host_iface, nvmf_hiface), \ + OPT_STRING("hostnqn", 'q', "STR", &f.hostnqn, nvmf_hostnqn), \ + OPT_STRING("hostid", 'I', "STR", &f.hostid, nvmf_hostid), \ + OPT_STRING("dhchap-secret", 'S', "STR", &f.hostkey, nvmf_hostkey), \ + OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &f.ctrlkey, nvmf_ctrlkey), \ + OPT_STRING("keyring", 0, "STR", &f.keyring, nvmf_keyring), \ + OPT_STRING("tls-key", 0, "STR", &f.tls_key, nvmf_tls_key), \ + OPT_STRING("tls-key-identity", 0, "STR", &f.tls_key_identity, nvmf_tls_key_identity), \ OPT_INT("nr-io-queues", 'i', &c.nr_io_queues, nvmf_nr_io_queues), \ OPT_INT("nr-write-queues", 'W', &c.nr_write_queues, nvmf_nr_write_queues), \ OPT_INT("nr-poll-queues", 'P', &c.nr_poll_queues, nvmf_nr_poll_queues), \ @@ -129,61 +145,6 @@ static const char *nvmf_context = "execution context identification string"; OPT_END() \ } -nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct tr_config *trcfg) -{ - nvme_subsystem_t s; - nvme_ctrl_t c; - - nvme_for_each_subsystem(h, s) { - c = nvme_ctrl_find(s, - trcfg->transport, - trcfg->traddr, - trcfg->trsvcid, - trcfg->subsysnqn, - trcfg->host_traddr, - trcfg->host_iface); - if (c) - return c; - } - - return NULL; -} - -static int set_discovery_kato(struct nvme_fabrics_config *cfg) -{ - int tmo = cfg->keep_alive_tmo; - - /* Set kato to NVMF_DEF_DISC_TMO for persistent controllers */ - if (persistent && !cfg->keep_alive_tmo) - cfg->keep_alive_tmo = NVMF_DEF_DISC_TMO; - /* Set kato to zero for non-persistent controllers */ - else if (!persistent && (cfg->keep_alive_tmo > 0)) - cfg->keep_alive_tmo = 0; - - return tmo; -} - -static int nvme_add_ctrl(nvme_host_t h, nvme_ctrl_t c, - struct nvme_fabrics_config *cfg) -{ - int ret; - -retry: - /* - * __create_discover_ctrl and callers depend on errno being set - * in the error case. - */ - ret = nvmf_add_ctrl(h, c, cfg); - if (!ret) - return 0; - - if (ret == -EAGAIN || (ret == -EINTR && !nvme_sigint_received)) { - print_debug("nvmf_add_ctrl returned '%s'\n", strerror(-ret)); - goto retry; - } - - return ret; -} static void save_discovery_log(char *raw, struct nvmf_discovery_log *log) { uint64_t numrec = le64_to_cpu(log->numrec); @@ -208,7 +169,7 @@ static void save_discovery_log(char *raw, struct nvmf_discovery_log *log) } static int setup_common_context(struct nvmf_context *fctx, - struct tr_config *trcfg); + struct fabric_args *fa); struct cb_fabrics_data { struct nvme_fabrics_config *defcfg; @@ -311,12 +272,12 @@ static int cb_parser_next_line(struct nvmf_context *fctx, void *user_data) { struct cb_fabrics_data *cfd = user_data; struct nvme_fabrics_config cfg; - struct tr_config trcfg = {}; + struct fabric_args fa = {}; char *ptr, *p, line[4096]; int argc, ret = 0; bool force = false; - NVMF_ARGS(opts, trcfg, cfg, + NVMF_ARGS(opts, fa, cfg, OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"), OPT_FLAG("force", 0, &force, "Force persistent discovery controller creation")); @@ -334,17 +295,17 @@ static int cb_parser_next_line(struct nvmf_context *fctx, void *user_data) cfd->argv[argc++] = ptr; cfd->argv[argc] = NULL; - trcfg.subsysnqn = NVME_DISC_SUBSYS_NAME; + fa.subsysnqn = NVME_DISC_SUBSYS_NAME; ret = argconfig_parse(argc, cfd->argv, "config", opts); if (ret) goto next; - if (!trcfg.transport && !trcfg.traddr) + if (!fa.transport && !fa.traddr) goto next; - if (!trcfg.trsvcid) - trcfg.trsvcid = nvmf_get_default_trsvcid(trcfg.transport, true); + if (!fa.trsvcid) + fa.trsvcid = nvmf_get_default_trsvcid(fa.transport, true); - ret = setup_common_context(fctx, &trcfg); + ret = setup_common_context(fctx, &fa); if (ret) return ret; @@ -356,35 +317,34 @@ static int cb_parser_next_line(struct nvmf_context *fctx, void *user_data) } static int setup_common_context(struct nvmf_context *fctx, - struct tr_config *trcfg) + struct fabric_args *fa) { int err; err = nvmf_context_set_connection(fctx, - trcfg->subsysnqn, trcfg->transport, - trcfg->traddr, trcfg->trsvcid, - trcfg->host_traddr, trcfg->host_iface); + fa->subsysnqn, fa->transport, + fa->traddr, fa->trsvcid, + fa->host_traddr, fa->host_iface); if (err) return err; err = nvmf_context_set_hostnqn(fctx, - trcfg->hostnqn, trcfg->hostid); + fa->hostnqn, fa->hostid); if (err) return err; err = nvmf_context_set_crypto(fctx, - trcfg->hostkey, trcfg->ctrlkey, - trcfg->keyring, trcfg->tls_key, - trcfg->tls_key_identity); + fa->hostkey, fa->ctrlkey, + fa->keyring, fa->tls_key, + fa->tls_key_identity); if (err) return err; return 0; } -static int create_discovery_context(struct nvme_global_ctx *ctx, - bool persistent, const char *device, - struct tr_config *trcfg, +static int create_common_context(struct nvme_global_ctx *ctx, + bool persistent, struct fabric_args *fa, struct nvme_fabrics_config *cfg, void *user_data, struct nvmf_context **fctxp) { @@ -396,31 +356,54 @@ static int create_discovery_context(struct nvme_global_ctx *ctx, if (err) return err; - err = nvmf_context_set_connection(fctx, trcfg->subsysnqn, - trcfg->transport, trcfg->traddr, trcfg->trsvcid, - trcfg->host_traddr, trcfg->host_iface); + err = nvmf_context_set_connection(fctx, fa->subsysnqn, + fa->transport, fa->traddr, fa->trsvcid, + fa->host_traddr, fa->host_iface); if (err) - return err; + goto err; - err = nvmf_context_set_discovery_cbs(fctx, cb_discovery_log, - cb_parser_init, cb_parser_cleanup, cb_parser_next_line); + err = nvmf_context_set_fabrics_config(fctx, cfg); if (err) - return err; + goto err; - err = nvmf_context_set_discovery_defaults(fctx, MAX_DISC_RETRIES, - NVMF_DEF_DISC_TMO); + err = nvmf_context_set_persistent(fctx, persistent); + if (err) + goto err; + + *fctxp = fctx; + + return 0; + +err: + free(fctx); + return err; +} + +static int create_discovery_context(struct nvme_global_ctx *ctx, + bool persistent, const char *device, + struct fabric_args *fa, + struct nvme_fabrics_config *cfg, + void *user_data, struct nvmf_context **fctxp) +{ + struct nvmf_context *fctx; + int err; + + err = create_common_context(ctx, persistent, fa, cfg, user_data, + &fctx); if (err) return err; - err = nvmf_context_set_fabrics_config(fctx, cfg); + err = nvmf_context_set_discovery_cbs(fctx, cb_discovery_log, + cb_parser_init, cb_parser_cleanup, cb_parser_next_line); if (err) goto err; - err = nvmf_context_set_device(fctx, device); + err = nvmf_context_set_discovery_defaults(fctx, MAX_DISC_RETRIES, + NVMF_DEF_DISC_TMO); if (err) goto err; - err = nvmf_context_set_persistent(fctx, persistent); + err = nvmf_context_set_device(fctx, device); if (err) goto err; @@ -477,8 +460,7 @@ static int nvme_read_config_checked(struct nvme_global_ctx *ctx, #define NBFT_SYSFS_PATH "/sys/firmware/acpi/tables" -/* returns negative errno values */ -int nvmf_discover(const char *desc, int argc, char **argv, bool connect) +int fabrics_discovery(const char *desc, int argc, char **argv, bool connect) { char *config_file = PATH_NVMF_CONFIG; _cleanup_free_ char *hnqn = NULL; @@ -492,14 +474,14 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) int ret; char *format = "normal"; struct nvme_fabrics_config cfg; - struct tr_config trcfg = { .subsysnqn = NVME_DISC_SUBSYS_NAME }; + struct fabric_args fa = { .subsysnqn = NVME_DISC_SUBSYS_NAME }; char *device = NULL; bool force = false; bool json_config = false; bool nbft = false, nonbft = false; char *nbft_path = NBFT_SYSFS_PATH; - NVMF_ARGS(opts, trcfg, cfg, + NVMF_ARGS(opts, fa, cfg, OPT_STRING("device", 'd', "DEV", &device, "use existing discovery controller device"), OPT_FMT("output-format", 'o', &format, output_format), OPT_FILE("raw", 'r', &raw, "save raw output to file"), @@ -553,7 +535,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) return ret; } - ret = nvme_host_get_ids(ctx, trcfg.hostnqn, trcfg.hostid, &hnqn, &hid); + ret = nvme_host_get_ids(ctx, fa.hostnqn, fa.hostid, &hnqn, &hid); if (ret < 0) return ret; @@ -569,29 +551,29 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) else if (!strncmp(device, "/dev/", 5)) device += 5; } - if (trcfg.hostkey) - nvme_host_set_dhchap_key(h, trcfg.hostkey); + if (fa.hostkey) + nvme_host_set_dhchap_key(h, fa.hostkey); struct cb_fabrics_data dld = { .flags = flags, .raw = raw, }; - ret = create_discovery_context(ctx, persistent, device, &trcfg, + ret = create_discovery_context(ctx, persistent, device, &fa, &cfg, &dld, &fctx); if (ret) return ret; - if (!device && !trcfg.transport && !trcfg.traddr) { + if (!device && !fa.transport && !fa.traddr) { if (!nonbft) ret = nvmf_discovery_nbft(ctx, fctx, - trcfg.hostnqn, trcfg.hostid, hnqn, hid, connect, + fa.hostnqn, fa.hostid, hnqn, hid, connect, &cfg, nbft_path); if (nbft) goto out_free; if (json_config) ret = nvmf_discovery_config_json(ctx, fctx, - trcfg.hostnqn, trcfg.hostid, connect, force); + fa.hostnqn, fa.hostid, connect, force); if (ret || access(PATH_NVMF_DISC, F_OK)) goto out_free; @@ -599,8 +581,8 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) goto out_free; } - if (!trcfg.trsvcid) - trcfg.trsvcid = nvmf_get_default_trsvcid(trcfg.transport, true); + if (!fa.trsvcid) + fa.trsvcid = nvmf_get_default_trsvcid(fa.transport, true); ret = nvmf_discovery(ctx, fctx, h, connect, force); @@ -639,7 +621,7 @@ static void nvme_parse_tls_args(const char *keyring, const char *tls_key, } } -int nvmf_connect(const char *desc, int argc, char **argv) +int fabrics_connect(const char *desc, int argc, char **argv) { _cleanup_free_ char *hnqn = NULL; _cleanup_free_ char *hid = NULL; @@ -647,15 +629,16 @@ int nvmf_connect(const char *desc, int argc, char **argv) char *context = NULL; unsigned int verbose = 0; _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; + _cleanup_free_ struct nvmf_context *fctx = NULL; nvme_host_t h; _cleanup_nvme_ctrl_ nvme_ctrl_t c = NULL; int ret; nvme_print_flags_t flags; struct nvme_fabrics_config cfg = { 0 }; - struct tr_config trcfg = { 0 }; + struct fabric_args fa = { 0 }; char *format = "normal"; - NVMF_ARGS(opts, trcfg, cfg, + NVMF_ARGS(opts, fa, cfg, OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file), OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), OPT_FLAG("dump-config", 'O', &dump_config, "Dump JSON configuration to stdout"), @@ -677,23 +660,23 @@ int nvmf_connect(const char *desc, int argc, char **argv) if (config_file && strcmp(config_file, "none")) goto do_connect; - if (!trcfg.subsysnqn) { + if (!fa.subsysnqn) { fprintf(stderr, "required argument [--nqn | -n] not specified\n"); return -EINVAL; } - if (!trcfg.transport) { + if (!fa.transport) { fprintf(stderr, "required argument [--transport | -t] not specified\n"); return -EINVAL; } - if (strcmp(trcfg.transport, "loop")) { - if (!trcfg.traddr) { + if (strcmp(fa.transport, "loop")) { + if (!fa.traddr) { fprintf(stderr, "required argument [--traddr | -a] not specified for transport %s\n", - trcfg.transport); + fa.transport); return -EINVAL; } } @@ -721,60 +704,38 @@ int nvmf_connect(const char *desc, int argc, char **argv) return ret; } - ret = nvme_host_get_ids(ctx, trcfg.hostnqn, trcfg.hostid, &hnqn, &hid); + ret = nvme_host_get_ids(ctx, fa.hostnqn, fa.hostid, &hnqn, &hid); if (ret < 0) return ret; h = nvme_lookup_host(ctx, hnqn, hid); if (!h) return -ENOMEM; - if (trcfg.hostkey) - nvme_host_set_dhchap_key(h, trcfg.hostkey); - if (!trcfg.trsvcid) - trcfg.trsvcid = nvmf_get_default_trsvcid(trcfg.transport, false); + if (fa.hostkey) + nvme_host_set_dhchap_key(h, fa.hostkey); + if (!fa.trsvcid) + fa.trsvcid = nvmf_get_default_trsvcid(fa.transport, false); if (config_file) - return nvmf_connect_config_json(ctx, trcfg.hostnqn, - trcfg.hostid, &cfg); + return nvmf_connect_config_json(ctx, fa.hostnqn, + fa.hostid, &cfg); - c = lookup_ctrl(h, &trcfg); - if (c && nvme_ctrl_get_name(c) && !cfg.duplicate_connect) { - fprintf(stderr, "already connected\n"); - return -EALREADY; - } - - ret = nvme_create_ctrl(ctx, trcfg.subsysnqn, trcfg.transport, - trcfg.traddr, trcfg.host_traddr, trcfg.host_iface, - trcfg.trsvcid, &c); + struct cb_fabrics_data dld = { + .flags = flags, + .raw = raw, + }; + ret = create_common_context(ctx, persistent, &fa, + &cfg, &dld, &fctx); if (ret) return ret; - if (trcfg.ctrlkey) - nvme_ctrl_set_dhchap_key(c, trcfg.ctrlkey); - - nvme_parse_tls_args(trcfg.keyring, trcfg.tls_key, - trcfg.tls_key_identity, &cfg, c); - - /* - * We are connecting to a discovery controller, so let's treat - * this as a persistent connection and specify a KATO. - */ - if (!strcmp(trcfg.subsysnqn, NVME_DISC_SUBSYS_NAME)) { - persistent = true; - - set_discovery_kato(&cfg); - } - - ret = nvme_add_ctrl(h, c, &cfg); + ret = nvmf_connect(ctx, fctx, h); if (ret) { - fprintf(stderr, "could not add new controller: %s\n", - nvme_strerror(-ret)); + fprintf(stderr, "failed to connected: %s\n", + nvme_strerror(ret)); return ret; } - /* always print connected device */ - nvme_show_connect_msg(c, flags); - if (dump_config) nvme_dump_config(ctx); @@ -825,7 +786,7 @@ static void nvmf_disconnect_nqn(struct nvme_global_ctx *ctx, char *nqn) printf("NQN:%s disconnected %d controller(s)\n", nqn, i); } -int nvmf_disconnect(const char *desc, int argc, char **argv) +int fabrics_disconnect(const char *desc, int argc, char **argv) { const char *device = "nvme device handle"; _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; @@ -914,7 +875,7 @@ int nvmf_disconnect(const char *desc, int argc, char **argv) return 0; } -int nvmf_disconnect_all(const char *desc, int argc, char **argv) +int fabrics_disconnect_all(const char *desc, int argc, char **argv) { _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; nvme_host_t h; @@ -984,7 +945,7 @@ int nvmf_disconnect_all(const char *desc, int argc, char **argv) return 0; } -int nvmf_config(const char *desc, int argc, char **argv) +int fabrics_config(const char *desc, int argc, char **argv) { char *subsysnqn = NULL; char *transport = NULL, *traddr = NULL; @@ -999,10 +960,10 @@ int nvmf_config(const char *desc, int argc, char **argv) _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; int ret; struct nvme_fabrics_config cfg; - struct tr_config trcfg = { }; + struct fabric_args fa = { }; bool scan_tree = false, modify_config = false, update_config = false; - NVMF_ARGS(opts, trcfg, cfg, + NVMF_ARGS(opts, fa, cfg, OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &ctrlkey, nvmf_ctrlkey), OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file), OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), @@ -1124,7 +1085,7 @@ static int dim_operation(nvme_ctrl_t c, enum nvmf_dim_tas tas, const char *name) return nvme_status_to_errno(status, true); } -int nvmf_dim(const char *desc, int argc, char **argv) +int fabrics_dim(const char *desc, int argc, char **argv) { _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; enum nvmf_dim_tas tas; diff --git a/fabrics.h b/fabrics.h index e95fa3e3c0..e66fc4f991 100644 --- a/fabrics.h +++ b/fabrics.h @@ -2,30 +2,12 @@ #ifndef _FABRICS_H #define _FABRICS_H -struct tr_config { - const char *subsysnqn; - const char *transport; - const char *traddr; - const char *host_traddr; - const char *host_iface; - const char *trsvcid; - - const char *hostnqn; - const char *hostid; - const char *hostkey; - const char *ctrlkey; - const char *keyring; - const char *tls_key; - const char *tls_key_identity; -}; - -extern nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct tr_config *trcfg); -extern int nvmf_discover(const char *desc, int argc, char **argv, bool connect); -extern int nvmf_connect(const char *desc, int argc, char **argv); -extern int nvmf_disconnect(const char *desc, int argc, char **argv); -extern int nvmf_disconnect_all(const char *desc, int argc, char **argv); -extern int nvmf_config(const char *desc, int argc, char **argv); -extern int nvmf_dim(const char *desc, int argc, char **argv); +int fabrics_discovery(const char *desc, int argc, char **argv, bool connect); +int fabrics_connect(const char *desc, int argc, char **argv); +int fabrics_disconnect(const char *desc, int argc, char **argv); +int fabrics_disconnect_all(const char *desc, int argc, char **argv); +int fabrics_config(const char *desc, int argc, char **argv); +int fabrics_dim(const char *desc, int argc, char **argv); #endif diff --git a/libnvme/src/libnvme.map b/libnvme/src/libnvme.map index acd67180cc..4054de184f 100644 --- a/libnvme/src/libnvme.map +++ b/libnvme/src/libnvme.map @@ -288,6 +288,7 @@ LIBNVME_2_0 { nvmf_add_ctrl; nvmf_adrfam_str; nvmf_cms_str; + nvmf_connect; nvmf_connect_config_json; nvmf_connect_ctrl; nvmf_context_create; diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index 9812f6a343..653cbe3536 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -2025,7 +2025,7 @@ void nvme_free_uri(struct nvme_fabrics_uri *uri) free(uri); } -static nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct tr_config *trcfg) +static nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct fabric_args *trcfg) { nvme_subsystem_t s; nvme_ctrl_t c; @@ -2101,7 +2101,7 @@ static int _nvmf_discovery(struct nvme_global_ctx *ctx, nvme_ctrl_t child; int tmo = fctx->cfg->keep_alive_tmo; - struct tr_config trcfg = { + struct fabric_args trcfg = { .subsysnqn = e->subnqn, .transport = nvmf_trtype_str(e->trtype), .traddr = e->traddr, @@ -2223,7 +2223,7 @@ static int nvme_add_ctrl(struct nvmf_context *fctx, static int __create_discovery_ctrl(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, nvme_host_t h, - struct nvme_fabrics_config *cfg, struct tr_config *trcfg, + struct nvme_fabrics_config *cfg, struct fabric_args *trcfg, struct nvme_ctrl **ctrl) { nvme_ctrl_t c; @@ -2254,7 +2254,7 @@ static int __create_discovery_ctrl(struct nvme_global_ctx *ctx, static int nvmf_create_discovery_ctrl(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, nvme_host_t h, struct nvme_fabrics_config *cfg, - struct tr_config *trcfg, + struct fabric_args *trcfg, struct nvme_ctrl **ctrl) { _cleanup_free_ struct nvme_id_ctrl *id = NULL; @@ -2362,7 +2362,7 @@ int _discovery_config_json(struct nvme_global_ctx *ctx, memcpy(&cfg, fctx->cfg, sizeof(cfg)); - struct tr_config trcfg = { + struct fabric_args trcfg = { .subsysnqn = subsysnqn, .transport = transport, .traddr = traddr, @@ -2496,7 +2496,7 @@ int nvmf_discovery_config_file(struct nvme_global_ctx *ctx, if (err) break; - struct tr_config trcfg = { + struct fabric_args trcfg = { .transport = fctx->transport, .traddr = fctx->traddr, .trsvcid = fctx->trsvcid, @@ -2615,7 +2615,7 @@ static bool validate_uri(struct nbft_info_discovery *dd, static int nbft_connect(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, struct nvme_host *h, struct nvmf_disc_log_entry *e, - struct nbft_info_subsystem_ns *ss, struct tr_config *trcfg, + struct nbft_info_subsystem_ns *ss, struct fabric_args *trcfg, struct nvme_fabrics_config *cfg) { nvme_ctrl_t c; @@ -2681,7 +2681,7 @@ static int nbft_connect(struct nvme_global_ctx *ctx, static int nbft_discovery(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, struct nbft_info_discovery *dd, struct nvme_host *h, struct nvme_ctrl *c, - struct nvme_fabrics_config *defcfg, struct tr_config *deftrcfg) + struct nvme_fabrics_config *defcfg, struct fabric_args *deftrcfg) { struct nvmf_discovery_log *log = NULL; int ret; @@ -2709,7 +2709,7 @@ static int nbft_discovery(struct nvme_global_ctx *ctx, nvme_ctrl_t cl; int tmo = defcfg->keep_alive_tmo; - struct tr_config trcfg = { + struct fabric_args trcfg = { .subsysnqn = e->subnqn, .transport = nvmf_trtype_str(e->trtype), .traddr = e->traddr, @@ -2854,7 +2854,7 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, !strncmp((*ss)->transport, "tcp", 3)) host_traddr = hfi->tcp_info.ipaddr; - struct tr_config trcfg = { + struct fabric_args trcfg = { .subsysnqn = (*ss)->subsys_nqn, .transport = (*ss)->transport, .traddr = (*ss)->traddr, @@ -2944,7 +2944,7 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, strdup(nvmf_get_default_trsvcid( uri->protocol, true)); - struct tr_config trcfg = { + struct fabric_args trcfg = { .subsysnqn = NVME_DISC_SUBSYS_NAME, .transport = uri->protocol, .traddr = uri->host, @@ -2995,7 +2995,7 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, static int __create_discover_ctrl(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, nvme_host_t h, - struct nvme_fabrics_config *cfg, struct tr_config *trcfg, + struct nvme_fabrics_config *cfg, struct fabric_args *trcfg, struct nvme_ctrl **ctrl) { struct nvme_ctrl *c; @@ -3026,7 +3026,7 @@ static int __create_discover_ctrl(struct nvme_global_ctx *ctx, static int nvmf_create_discover_ctrl(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, struct nvme_host *h, struct nvme_fabrics_config *cfg, - struct tr_config *trcfg, struct nvme_ctrl **ctrl) + struct fabric_args *trcfg, struct nvme_ctrl **ctrl) { _cleanup_free_ struct nvme_id_ctrl *id = NULL; struct nvme_ctrl *c; @@ -3142,7 +3142,7 @@ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, } } - struct tr_config trcfg = { + struct fabric_args trcfg = { .subsysnqn = fctx->subsysnqn, .transport = fctx->transport, .traddr = fctx->traddr, @@ -3176,3 +3176,88 @@ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, return ret; } + +static void nvme_parse_tls_args(const char *keyring, const char *tls_key, + const char *tls_key_identity, + struct nvme_fabrics_config *cfg, nvme_ctrl_t c) +{ + if (keyring) { + char *endptr; + long id = strtol(keyring, &endptr, 0); + + if (endptr != keyring) + cfg->keyring = id; + else + nvme_ctrl_set_keyring(c, keyring); + } + + if (tls_key_identity) + nvme_ctrl_set_tls_key_identity(c, tls_key_identity); + + if (tls_key) { + char *endptr; + long id = strtol(tls_key, &endptr, 0); + + if (endptr != tls_key) + cfg->tls_key = id; + else + nvme_ctrl_set_tls_key(c, tls_key); + } +} + +int nvmf_connect(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, + struct nvme_host *h) +{ + struct nvme_ctrl *c; + int err; + + struct fabric_args trcfg = { + .subsysnqn = fctx->subsysnqn, + .transport = fctx->transport, + .traddr = fctx->traddr, + .host_traddr = fctx->host_traddr, + .host_iface = fctx->host_iface, + .trsvcid = fctx->trsvcid, + }; + + c = lookup_ctrl(h, &trcfg); + if (c && nvme_ctrl_get_name(c) && !fctx->cfg->duplicate_connect) { + fctx->already_connected(fctx, h, nvme_ctrl_get_subsysnqn(c), + nvme_ctrl_get_transport(c), nvme_ctrl_get_traddr(c), + nvme_ctrl_get_trsvcid(c), fctx->user_data); + return -EALREADY; + } + + err = nvme_create_ctrl(ctx, trcfg.subsysnqn, trcfg.transport, + trcfg.traddr, trcfg.host_traddr, trcfg.host_iface, + trcfg.trsvcid, &c); + if (err) + return err; + + if (fctx->ctrlkey) + nvme_ctrl_set_dhchap_key(c, fctx->ctrlkey); + + nvme_parse_tls_args(fctx->keyring, fctx->tls_key, + fctx->tls_key_identity, fctx->cfg, c); + + /* + * We are connecting to a discovery controller, so let's treat + * this as a persistent connection and specify a KATO. + */ + if (!strcmp(trcfg.subsysnqn, NVME_DISC_SUBSYS_NAME)) { + fctx->persistent = true; + + set_discovery_kato(fctx, fctx->cfg); + } + + err = nvme_add_ctrl(fctx, h, c, fctx->cfg); + if (err) { + nvme_msg(ctx, LOG_ERR, "could not add new controller: %s\n", + nvme_strerror(-err)); + return err; + } + + fctx->connected(fctx, c, fctx->user_data); + + return 0; +} diff --git a/libnvme/src/nvme/fabrics.h b/libnvme/src/nvme/fabrics.h index 8d3e384568..1d63366363 100644 --- a/libnvme/src/nvme/fabrics.h +++ b/libnvme/src/nvme/fabrics.h @@ -443,6 +443,8 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, const char *hostid_sys, bool connect, struct nvme_fabrics_config *cfg, char *nbft_path); +int nvmf_connect(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, + struct nvme_host *h); int nvmf_connect_config_json(struct nvme_global_ctx *ctx, const char *hostnqn, const char *hostid, const struct nvme_fabrics_config *cfg); diff --git a/libnvme/src/nvme/private.h b/libnvme/src/nvme/private.h index 637088caef..6b2a864805 100644 --- a/libnvme/src/nvme/private.h +++ b/libnvme/src/nvme/private.h @@ -373,7 +373,7 @@ struct nvmf_context { void *user_data; }; -struct tr_config { +struct fabric_args { const char *subsysnqn; const char *transport; const char *traddr; diff --git a/nvme.c b/nvme.c index 5aeabae3ab..58849c5cb8 100644 --- a/nvme.c +++ b/nvme.c @@ -10159,28 +10159,28 @@ static int discover_cmd(int argc, char **argv, struct command *acmd, struct plug { const char *desc = "Send Get Log Page request to Discovery Controller."; - return nvmf_discover(desc, argc, argv, false); + return fabrics_discovery(desc, argc, argv, false); } static int connect_all_cmd(int argc, char **argv, struct command *acmd, struct plugin *plugin) { const char *desc = "Discover NVMeoF subsystems and connect to them"; - return nvmf_discover(desc, argc, argv, true); + return fabrics_discovery(desc, argc, argv, true); } static int connect_cmd(int argc, char **argv, struct command *acmd, struct plugin *plugin) { const char *desc = "Connect to NVMeoF subsystem"; - return nvmf_connect(desc, argc, argv); + return fabrics_connect(desc, argc, argv); } static int disconnect_cmd(int argc, char **argv, struct command *acmd, struct plugin *plugin) { const char *desc = "Disconnect from NVMeoF subsystem"; - return nvmf_disconnect(desc, argc, argv); + return fabrics_disconnect(desc, argc, argv); } int disconnect_all_cmd(int argc, char **argv, struct command *acmd, @@ -10188,14 +10188,14 @@ int disconnect_all_cmd(int argc, char **argv, struct command *acmd, { const char *desc = "Disconnect from all connected NVMeoF subsystems"; - return nvmf_disconnect_all(desc, argc, argv); + return fabrics_disconnect_all(desc, argc, argv); } static int config_cmd(int argc, char **argv, struct command *acmd, struct plugin *plugin) { const char *desc = "Configuration of NVMeoF subsystems"; - return nvmf_config(desc, argc, argv); + return fabrics_config(desc, argc, argv); } static int dim_cmd(int argc, char **argv, struct command *acmd, struct plugin *plugin) @@ -10203,7 +10203,7 @@ static int dim_cmd(int argc, char **argv, struct command *acmd, struct plugin *p const char *desc = "Send Discovery Information Management command to a Discovery Controller (DC)"; - return nvmf_dim(desc, argc, argv); + return fabrics_dim(desc, argc, argv); } static int nvme_mi(int argc, char **argv, __u8 admin_opcode, const char *desc) From b020730e79d84a9bd8b00984e967166e237d6e81 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Wed, 17 Dec 2025 11:42:32 +0100 Subject: [PATCH 12/13] fabrics: remove duplicate arguments from discover/connect There a arguments which are already stored in the nvmf_context object, thus we can remove those. While at it, also remove the host lookup and configuring code to the library. Besides making the API more consistent it also more generic code to the library. Signed-off-by: Daniel Wagner --- fabrics.c | 49 ++---------- libnvme/src/nvme/fabrics.c | 153 ++++++++++++++++++++++++++++--------- libnvme/src/nvme/fabrics.h | 24 +++--- 3 files changed, 136 insertions(+), 90 deletions(-) diff --git a/fabrics.c b/fabrics.c index af9fdcbded..d22213bd27 100644 --- a/fabrics.c +++ b/fabrics.c @@ -463,13 +463,10 @@ static int nvme_read_config_checked(struct nvme_global_ctx *ctx, int fabrics_discovery(const char *desc, int argc, char **argv, bool connect) { char *config_file = PATH_NVMF_CONFIG; - _cleanup_free_ char *hnqn = NULL; - _cleanup_free_ char *hid = NULL; char *context = NULL; nvme_print_flags_t flags; _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; _cleanup_free_ struct nvmf_context *fctx = NULL; - nvme_host_t h; unsigned int verbose = 0; int ret; char *format = "normal"; @@ -535,24 +532,12 @@ int fabrics_discovery(const char *desc, int argc, char **argv, bool connect) return ret; } - ret = nvme_host_get_ids(ctx, fa.hostnqn, fa.hostid, &hnqn, &hid); - if (ret < 0) - return ret; - - h = nvme_lookup_host(ctx, hnqn, hid); - if (!h) { - ret = -ENOMEM; - goto out_free; - } - if (device) { if (!strcmp(device, "none")) device = NULL; else if (!strncmp(device, "/dev/", 5)) device += 5; } - if (fa.hostkey) - nvme_host_set_dhchap_key(h, fa.hostkey); struct cb_fabrics_data dld = { .flags = flags, @@ -566,25 +551,21 @@ int fabrics_discovery(const char *desc, int argc, char **argv, bool connect) if (!device && !fa.transport && !fa.traddr) { if (!nonbft) ret = nvmf_discovery_nbft(ctx, fctx, - fa.hostnqn, fa.hostid, hnqn, hid, connect, - &cfg, nbft_path); + connect, nbft_path); if (nbft) goto out_free; if (json_config) ret = nvmf_discovery_config_json(ctx, fctx, - fa.hostnqn, fa.hostid, connect, force); + connect, force); if (ret || access(PATH_NVMF_DISC, F_OK)) goto out_free; - ret = nvmf_discovery_config_file(ctx, fctx, h, connect, force); + ret = nvmf_discovery_config_file(ctx, fctx, connect, force); goto out_free; } - if (!fa.trsvcid) - fa.trsvcid = nvmf_get_default_trsvcid(fa.transport, true); - - ret = nvmf_discovery(ctx, fctx, h, connect, force); + ret = nvmf_discovery(ctx, fctx, connect, force); out_free: if (dump_config) @@ -630,7 +611,6 @@ int fabrics_connect(const char *desc, int argc, char **argv) unsigned int verbose = 0; _cleanup_nvme_global_ctx_ struct nvme_global_ctx *ctx = NULL; _cleanup_free_ struct nvmf_context *fctx = NULL; - nvme_host_t h; _cleanup_nvme_ctrl_ nvme_ctrl_t c = NULL; int ret; nvme_print_flags_t flags; @@ -704,22 +684,6 @@ int fabrics_connect(const char *desc, int argc, char **argv) return ret; } - ret = nvme_host_get_ids(ctx, fa.hostnqn, fa.hostid, &hnqn, &hid); - if (ret < 0) - return ret; - - h = nvme_lookup_host(ctx, hnqn, hid); - if (!h) - return -ENOMEM; - if (fa.hostkey) - nvme_host_set_dhchap_key(h, fa.hostkey); - if (!fa.trsvcid) - fa.trsvcid = nvmf_get_default_trsvcid(fa.transport, false); - - if (config_file) - return nvmf_connect_config_json(ctx, fa.hostnqn, - fa.hostid, &cfg); - struct cb_fabrics_data dld = { .flags = flags, .raw = raw, @@ -729,7 +693,10 @@ int fabrics_connect(const char *desc, int argc, char **argv) if (ret) return ret; - ret = nvmf_connect(ctx, fctx, h); + if (config_file) + return nvmf_connect_config_json(ctx, fctx); + + ret = nvmf_connect(ctx, fctx); if (ret) { fprintf(stderr, "failed to connected: %s\n", nvme_strerror(ret)); diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index 653cbe3536..7d8ebe383c 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -2045,6 +2045,41 @@ static nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct fabric_args *trcfg) return NULL; } +static int lookup_host(struct nvme_global_ctx *ctx, + struct nvmf_context *fctx, struct nvme_host **host) +{ + _cleanup_free_ char *hnqn = NULL; + _cleanup_free_ char *hid = NULL; + struct nvme_host *h; + int err; + + err = nvme_host_get_ids(ctx, fctx->hostnqn, fctx->hostid, &hnqn, &hid); + if (err < 0) + return err; + + h = nvme_lookup_host(ctx, hnqn, hid); + if (!h) + return -ENOMEM; + + *host = h; + + return 0; +} + +static int setup_connection(struct nvmf_context *fctx, struct nvme_host *h, + bool discovery) +{ + if (fctx->hostkey) + nvme_host_set_dhchap_key(h, fctx->hostkey); + + if (!fctx->trsvcid) + fctx->trsvcid = nvmf_get_default_trsvcid(fctx->transport, + discovery); + + return 0; +} + + static int set_discovery_kato(struct nvmf_context *fctx, struct nvme_fabrics_config *cfg) { @@ -2393,22 +2428,31 @@ int _discovery_config_json(struct nvme_global_ctx *ctx, } int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, - struct nvmf_context *fctx, const char *hostnqn, - const char *hostid, bool connect, bool force) + struct nvmf_context *fctx, bool connect, bool force) { const char *hnqn, *hid; - nvme_host_t h; - nvme_subsystem_t s; - nvme_ctrl_t c; + struct nvme_subsystem *s; + struct nvme_host *h; + struct nvme_ctrl *c; int ret = 0, err; + err = lookup_host(ctx, fctx, &h); + if (err) + return err; + + err = setup_connection(fctx, h, false); + if (err) + return err; + nvme_for_each_host(ctx, h) { nvme_for_each_subsystem(h, s) { hnqn = nvme_host_get_hostnqn(h); - if (hostnqn && hnqn && strcmp(hostnqn, hnqn)) + if (fctx->hostnqn && hnqn && + strcmp(fctx->hostnqn, hnqn)) continue; hid = nvme_host_get_hostid(h); - if (hostid && hid && strcmp(hostid, hid)) + if (fctx->hostid && hid && + strcmp(fctx->hostid, hid)) continue; nvme_subsystem_for_each_ctrl(s, c) { @@ -2431,8 +2475,8 @@ int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, return ret; } -int nvmf_connect_config_json(struct nvme_global_ctx *ctx, const char *hostnqn, - const char *hostid, const struct nvme_fabrics_config *cfg) +int nvmf_connect_config_json(struct nvme_global_ctx *ctx, + struct nvmf_context *fctx) { const char *hnqn, *hid; const char *transport; @@ -2441,13 +2485,23 @@ int nvmf_connect_config_json(struct nvme_global_ctx *ctx, const char *hostnqn, nvme_ctrl_t c, _c; int ret = 0, err; + err = lookup_host(ctx, fctx, &h); + if (err) + return err; + + err = setup_connection(fctx, h, false); + if (err) + return err; + nvme_for_each_host(ctx, h) { nvme_for_each_subsystem(h, s) { hnqn = nvme_host_get_hostnqn(h); - if (hostnqn && hnqn && strcmp(hostnqn, hnqn)) + if (fctx->hostnqn && hnqn && + strcmp(fctx->hostnqn, hnqn)) continue; hid = nvme_host_get_hostid(h); - if (hostid && hid && strcmp(hostid, hid)) + if (fctx->hostid && hid && + strcmp(fctx->hostid, hid)) continue; nvme_subsystem_for_each_ctrl_safe(s, c, _c) { @@ -2481,12 +2535,20 @@ int nvmf_connect_config_json(struct nvme_global_ctx *ctx, const char *hostnqn, } int nvmf_discovery_config_file(struct nvme_global_ctx *ctx, - struct nvmf_context *fctx, struct nvme_host *h, - bool connect, bool force) + struct nvmf_context *fctx, bool connect, bool force) { - nvme_ctrl_t c; + struct nvme_host *h; + struct nvme_ctrl *c; int err; + err = lookup_host(ctx, fctx, &h); + if (err) + return err; + + err = setup_connection(fctx, h, false); + if (err) + return err; + err = fctx->parser_init(fctx, fctx->user_data); if (err) return err; @@ -2782,19 +2844,24 @@ static int nbft_discovery(struct nvme_global_ctx *ctx, } int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, - struct nvmf_context *fctx, const char *hostnqn_arg, - const char *hostid_arg, const char *hostnqn_sys, - const char *hostid_sys, bool connect, - struct nvme_fabrics_config *cfg, char *nbft_path) + struct nvmf_context *fctx, bool connect, char *nbft_path) { const char *hostnqn = NULL, *hostid = NULL, *host_traddr = NULL; - nvme_host_t h; - int ret, rr, i; char uuid[NVME_UUID_LEN_STRING]; struct nbft_file_entry *entry = NULL; struct nbft_info_subsystem_ns **ss; struct nbft_info_hfi *hfi; struct nbft_info_discovery **dd; + struct nvme_host *h; + int ret, rr, i; + + ret = lookup_host(ctx, fctx, &h); + if (ret) + return ret; + + ret = setup_connection(fctx, h, false); + if (ret) + return ret; if (!connect) /* TODO: print discovery-type info from NBFT tables */ @@ -2811,22 +2878,22 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, } for (; entry; entry = entry->next) { - if (hostnqn_arg) - hostnqn = hostnqn_arg; + if (fctx->hostnqn) + hostnqn = fctx->hostnqn; else { hostnqn = entry->nbft->host.nqn; if (!hostnqn) - hostnqn = hostnqn_sys; + hostnqn = fctx->hostnqn; } - if (hostid_arg) - hostid = hostid_arg; + if (fctx->hostid) + hostid = fctx->hostid; else if (*entry->nbft->host.id) { ret = nvme_uuid_to_string(entry->nbft->host.id, uuid); if (!ret) hostid = uuid; else - hostid = hostid_sys; + hostid = fctx->hostid; } h = nvme_lookup_host(ctx, hostnqn, hostid); @@ -2864,7 +2931,7 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, }; rr = nbft_connect(ctx, fctx, h, NULL, - *ss, &trcfg, cfg); + *ss, &trcfg, fctx->cfg); /* * With TCP/DHCP, it can happen that the OS @@ -2877,7 +2944,7 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, trcfg.host_traddr = NULL; rr = nbft_connect(ctx, fctx, h, NULL, - *ss, &trcfg, cfg); + *ss, &trcfg, fctx->cfg); if (rr == 0) nvme_msg(ctx, LOG_INFO, @@ -2960,13 +3027,13 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, if (!c) { ret = nvmf_create_discovery_ctrl(ctx, fctx, h, - cfg, &trcfg, &c); + fctx->cfg, &trcfg, &c); if (ret == -ENVME_CONNECT_ADDRNOTAVAIL && !strcmp(trcfg.transport, "tcp") && strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { trcfg.host_traddr = NULL; ret = nvmf_create_discovery_ctrl(ctx, - fctx, h, cfg, &trcfg, &c); + fctx, h, fctx->cfg, &trcfg, &c); } } else ret = 0; @@ -2978,7 +3045,8 @@ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, goto out_free; } - rr = nbft_discovery(ctx, fctx, *dd, h, c, cfg, &trcfg); + rr = nbft_discovery(ctx, fctx, *dd, h, c, fctx->cfg, + &trcfg); if (!persistent) nvme_disconnect_ctrl(c); nvme_free_ctrl(c); @@ -3079,11 +3147,20 @@ static int nvmf_create_discover_ctrl(struct nvme_global_ctx *ctx, } int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, - struct nvme_host *h, bool connect, bool force) + bool connect, bool force) { struct nvme_ctrl *c = NULL; + struct nvme_host *h; int ret; + ret = lookup_host(ctx, fctx, &h); + if (ret) + return ret; + + ret = setup_connection(fctx, h, true); + if (ret) + return ret; + if (fctx->device && !force) { ret = nvme_scan_ctrl(ctx, fctx->device, &c); if (!ret) { @@ -3205,12 +3282,20 @@ static void nvme_parse_tls_args(const char *keyring, const char *tls_key, } } -int nvmf_connect(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, - struct nvme_host *h) +int nvmf_connect(struct nvme_global_ctx *ctx, struct nvmf_context *fctx) { + struct nvme_host *h; struct nvme_ctrl *c; int err; + err = lookup_host(ctx, fctx, &h); + if (err) + return err; + + err = setup_connection(fctx, h, false); + if (err) + return err; + struct fabric_args trcfg = { .subsysnqn = fctx->subsysnqn, .transport = fctx->transport, diff --git a/libnvme/src/nvme/fabrics.h b/libnvme/src/nvme/fabrics.h index 1d63366363..3f31b4f09a 100644 --- a/libnvme/src/nvme/fabrics.h +++ b/libnvme/src/nvme/fabrics.h @@ -429,24 +429,18 @@ void nvme_free_uri(struct nvme_fabrics_uri *uri); char *nvmf_get_default_trsvcid(const char *transport, bool discovery_ctrl); -int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, - struct nvme_host *h, bool connect, bool force); +int nvmf_discovery(struct nvme_global_ctx *ctx, + struct nvmf_context *fctx, bool connect, bool force); int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, - struct nvmf_context *fctx, const char *hostnqn, - const char *hostid, bool connect, bool force); + struct nvmf_context *fctx, bool connect, bool force); int nvmf_discovery_config_file(struct nvme_global_ctx *ctx, - struct nvmf_context *fctx, struct nvme_host *h, - bool connect, bool force); + struct nvmf_context *fctx, bool connect, bool force); int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, - struct nvmf_context *fctx, const char *hostnqn_arg, - const char *hostid_arg, const char *hostnqn_sys, - const char *hostid_sys, bool connect, - struct nvme_fabrics_config *cfg, char *nbft_path); - -int nvmf_connect(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, - struct nvme_host *h); -int nvmf_connect_config_json(struct nvme_global_ctx *ctx, const char *hostnqn, - const char *hostid, const struct nvme_fabrics_config *cfg); + struct nvmf_context *fctx, bool connect, char *nbft_path); + +int nvmf_connect(struct nvme_global_ctx *ctx, struct nvmf_context *fctx); +int nvmf_connect_config_json(struct nvme_global_ctx *ctx, + struct nvmf_context *fctx); struct nbft_file_entry { struct nbft_file_entry *next; From aadec981e382756f4a016d494d5832936daffd75 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Wed, 17 Dec 2025 12:52:22 +0100 Subject: [PATCH 13/13] fabrics: add documentation to the new discovery/connnect API Document the new APIs. Signed-off-by: Daniel Wagner --- libnvme/src/nvme/fabrics.c | 3 +- libnvme/src/nvme/fabrics.h | 293 +++++++++++++++++++++++++++++++------ 2 files changed, 254 insertions(+), 42 deletions(-) diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index 7d8ebe383c..6e8393a529 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -2214,7 +2214,8 @@ static int _nvmf_discovery(struct nvme_global_ctx *ctx, return 0; } -char *nvmf_get_default_trsvcid(const char *transport, bool discovery_ctrl) +const char *nvmf_get_default_trsvcid(const char *transport, + bool discovery_ctrl) { if (!transport) return NULL; diff --git a/libnvme/src/nvme/fabrics.h b/libnvme/src/nvme/fabrics.h index 3f31b4f09a..c4d0ba7fba 100644 --- a/libnvme/src/nvme/fabrics.h +++ b/libnvme/src/nvme/fabrics.h @@ -23,46 +23,6 @@ /* default to 600 seconds of reconnect attempts before giving up */ #define NVMF_DEF_CTRL_LOSS_TMO 600 -struct nvmf_context; - -int nvmf_context_create(struct nvme_global_ctx *ctx, - bool (*decide_retry)(struct nvmf_context *fctx, int err, - void *user_data), - void (*connected)(struct nvmf_context *fctx, - struct nvme_ctrl *c, void *user_data), - void (*already_connected)(struct nvmf_context *fctx, - struct nvme_host *host, const char *subsysnqn, - const char *transport, const char *traddr, - const char *trsvcid, void *user_data), - void *user_data, struct nvmf_context **fctxp); -int nvmf_context_set_discovery_cbs(struct nvmf_context *fctx, - void (*discovery_log)(struct nvmf_context *fctx, - bool connect, - struct nvmf_discovery_log *log, - uint64_t numrec, void *user_data), - int (*parser_init)(struct nvmf_context *fctx, - void *user_data), - void (*parser_cleanup)(struct nvmf_context *fctx, - void *user_data), - int (*parser_next_line)(struct nvmf_context *fctx, - void *user_data)); -int nvmf_context_set_discovery_defaults(struct nvmf_context *fctx, - int max_discovery_retries, int keep_alive_timeout); -int nvmf_context_set_fabrics_config(struct nvmf_context *fctx, - struct nvme_fabrics_config *cfg); -int nvmf_context_set_connection(struct nvmf_context *fctx, - const char *subsysnqn, const char *transport, - const char *traddr, const char *trsvcid, - const char *host_traddr, const char *host_iface); -int nvmf_context_set_hostnqn(struct nvmf_context *fctx, - const char *hostnqn, const char *hostid); -int nvmf_context_set_crypto(struct nvmf_context *fctx, - const char *hostkey, const char *ctrlkey, - const char *keyring, const char *tls_key, - const char *tls_key_identity); -int nvmf_context_set_persistent(struct nvmf_context *fctx, bool persistent); -int nvmf_context_set_device(struct nvmf_context *fctx, const char *device); - /** * struct nvme_fabrics_config - Defines all linux nvme fabrics initiator options * @queue_size: Number of IO queue entries @@ -427,27 +387,278 @@ int nvme_parse_uri(const char *str, struct nvme_fabrics_uri **uri); */ void nvme_free_uri(struct nvme_fabrics_uri *uri); -char *nvmf_get_default_trsvcid(const char *transport, bool discovery_ctrl); +/** + * nvmf_get_default_trsvcid() - Get default transport service ID + * @transport: Transport type string (e.g., "tcp", "rdma") + * @discovery_ctrl: True if for discovery controller, false otherwise + * + * Returns the default trsvcid (port) for the given transport and controller + * type. + * + * Return: Allocated string with default trsvcid, or NULL on failure. + */ +const char *nvmf_get_default_trsvcid(const char *transport, + bool discovery_ctrl); +/* + * struct nvmf_context - Opaque context for fabrics operations + * + * Used to manage state and configuration for fabrics discovery and connect + * operations. + */ +struct nvmf_context; + +/** + * nvmf_context_create() - Create a new fabrics context for discovery/connect + * @ctx: Global context + * @decide_retry: Callback to decide if a retry should be attempted + * @connected: Callback invoked when a connection is established + * @already_connected: Callback invoked if already connected + * @user_data: User data passed to callbacks + * @fctxp: Pointer to store the created context + * + * Allocates and initializes a new fabrics context for discovery/connect + * operations. + * + * Return: 0 on success, or a negative error code on failure. + */ +int nvmf_context_create(struct nvme_global_ctx *ctx, + bool (*decide_retry)(struct nvmf_context *fctx, int err, + void *user_data), + void (*connected)(struct nvmf_context *fctx, + struct nvme_ctrl *c, void *user_data), + void (*already_connected)(struct nvmf_context *fctx, + struct nvme_host *host, const char *subsysnqn, + const char *transport, const char *traddr, + const char *trsvcid, void *user_data), + void *user_data, struct nvmf_context **fctxp); + +/** + * nvmf_context_set_discovery_cbs() - Set discovery callbacks for context + * @fctx: Fabrics context + * @discovery_log: Callback for discovery log events + * @parser_init: Callback to initialize parser + * @parser_cleanup: Callback to cleanup parser + * @parser_next_line: Callback to parse next line + * + * Sets the callbacks used during discovery operations for the given context. + * + * Return: 0 on success, or a negative error code on failure. + */ +int nvmf_context_set_discovery_cbs(struct nvmf_context *fctx, + void (*discovery_log)(struct nvmf_context *fctx, + bool connect, struct nvmf_discovery_log *log, + uint64_t numrec, void *user_data), + int (*parser_init)(struct nvmf_context *fctx, + void *user_data), + void (*parser_cleanup)(struct nvmf_context *fctx, + void *user_data), + int (*parser_next_line)(struct nvmf_context *fctx, + void *user_data)); + +/** + * nvmf_context_set_discovery_defaults() - Set default discovery parameters + * @fctx: Fabrics context + * @max_discovery_retries: Maximum number of discovery retries + * @keep_alive_timeout: Keep-alive timeout in seconds + * + * Sets default values for discovery retries and keep-alive timeout. + * + * Return: 0 on success, or a negative error code on failure. + */ +int nvmf_context_set_discovery_defaults(struct nvmf_context *fctx, + int max_discovery_retries, int keep_alive_timeout); +/** + * nvmf_context_set_fabrics_config() - Set fabrics configuration for context + * @fctx: Fabrics context + * @cfg: Fabrics configuration to apply + * + * Applies the given fabrics configuration to the context. + * + * Return: 0 on success, or a negative error code on failure. + */ +int nvmf_context_set_fabrics_config(struct nvmf_context *fctx, + struct nvme_fabrics_config *cfg); + +/** + * nvmf_context_set_connection() - Set connection parameters for context + * @fctx: Fabrics context + * @subsysnqn: Subsystem NQN + * @transport: Transport type + * @traddr: Transport address + * @trsvcid: Transport service ID + * @host_traddr: Host transport address + * @host_iface: Host interface + * + * Sets the connection parameters for the context. + * + * Return: 0 on success, or a negative error code on failure. + */ +int nvmf_context_set_connection(struct nvmf_context *fctx, + const char *subsysnqn, const char *transport, + const char *traddr, const char *trsvcid, + const char *host_traddr, const char *host_iface); + +/** + * nvmf_context_set_hostnqn() - Set host NQN and host ID for context + * @fctx: Fabrics context + * @hostnqn: Host NQN + * @hostid: Host identifier + * + * Sets the host NQN and host ID for the context. + * + * Return: 0 on success, or a negative error code on failure. + */ +int nvmf_context_set_hostnqn(struct nvmf_context *fctx, + const char *hostnqn, const char *hostid); + +/** + * nvmf_context_set_crypto() - Set cryptographic parameters for context + * @fctx: Fabrics context + * @hostkey: Host key + * @ctrlkey: Controller key + * @keyring: Keyring identifier + * @tls_key: TLS key + * @tls_key_identity: TLS key identity + * + * Sets cryptographic and TLS parameters for the context. + * + * Return: 0 on success, or a negative error code on failure. + */ +int nvmf_context_set_crypto(struct nvmf_context *fctx, + const char *hostkey, const char *ctrlkey, + const char *keyring, const char *tls_key, + const char *tls_key_identity); + +/** + * nvmf_context_set_persistent() - Set persistence for context + * @fctx: Fabrics context + * @persistent: Whether to enable persistent connections + * + * Sets whether the context should use persistent connections. + * + * Return: 0 on success, or a negative error code on failure. + */ + +int nvmf_context_set_persistent(struct nvmf_context *fctx, bool persistent); + +/** + * nvmf_context_set_device() - Set device for context + * @fctx: Fabrics context + * @device: Device path or identifier + * + * Sets the device to be used by the context. + * + * Return: 0 on success, or a negative error code on failure. + */ +int nvmf_context_set_device(struct nvmf_context *fctx, const char *device); + +/** + * nvmf_discovery() - Perform fabrics discovery + * @ctx: Global context + * @fctx: Fabrics context + * @connect: Whether to connect discovered subsystems + * @force: Force discovery even if already connected + * + * Performs discovery for fabrics subsystems and optionally connects. + * + * Return: 0 on success, or a negative error code on failure. + */ int nvmf_discovery(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, bool connect, bool force); + +/** + * nvmf_discovery_config_json() - Perform discovery using JSON config + * @ctx: Global context + * @fctx: Fabrics context + * @connect: Whether to connect discovered subsystems + * @force: Force discovery even if already connected + * + * Performs discovery using a JSON configuration. + * + * Return: 0 on success, or a negative error code on failure. + */ int nvmf_discovery_config_json(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, bool connect, bool force); + +/** + * nvmf_discovery_config_file() - Perform discovery using config file + * @ctx: Global context + * @fctx: Fabrics context + * @connect: Whether to connect discovered subsystems + * @force: Force discovery even if already connected + * + * Performs discovery using a configuration file. + * + * Return: 0 on success, or a negative error code on failure. + */ int nvmf_discovery_config_file(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, bool connect, bool force); + +/** + * nvmf_discovery_nbft() - Perform discovery using NBFT + * @ctx: Global context + * @fctx: Fabrics context + * @connect: Whether to connect discovered subsystems + * @nbft_path: Path to NBFT file + * + * Performs discovery using the specified NBFT file. + * + * Return: 0 on success, or a negative error code on failure. + */ int nvmf_discovery_nbft(struct nvme_global_ctx *ctx, struct nvmf_context *fctx, bool connect, char *nbft_path); +/** + * nvmf_connect() - Connect to fabrics subsystem + * @ctx: Global context + * @fctx: Fabrics context + * + * Connects to the fabrics subsystem using the provided context. + * + * Return: 0 on success, or a negative error code on failure. + */ int nvmf_connect(struct nvme_global_ctx *ctx, struct nvmf_context *fctx); + +/** + * nvmf_connect_config_json() - Connect using JSON config + * @ctx: Global context + * @fctx: Fabrics context + * + * Connects to the fabrics subsystem using a JSON configuration. + * + * Return: 0 on success, or a negative error code on failure. + */ int nvmf_connect_config_json(struct nvme_global_ctx *ctx, struct nvmf_context *fctx); +/** + * struct nbft_file_entry - Linked list entry for NBFT files + * @next: Pointer to next entry + * @nbft: Pointer to NBFT info structure + */ struct nbft_file_entry { struct nbft_file_entry *next; struct nbft_info *nbft; }; +/** + * nvmf_nbft_read_files() - Read NBFT files from path + * @path: Path to NBFT files + * @head: Pointer to store linked list of NBFT file entries + * + * Reads NBFT files from the specified path and populates a linked list. + * + * Return: 0 on success, or a negative error code on failure. + */ int nvmf_nbft_read_files(char *path, struct nbft_file_entry **head); + +/** + * nvmf_nbft_free() - Free NBFT file entry list + * @head: Head of the NBFT file entry list + * + * Frees all memory associated with the NBFT file entry list. + */ void nvmf_nbft_free(struct nbft_file_entry *head); #endif /* _LIBNVME_FABRICS_H */