summaryrefslogtreecommitdiffstats
path: root/fabrics.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-01-31 04:13:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-01-31 04:13:03 +0000
commitd2082ee94267e4ca59b187c5e37dac03c1d65187 (patch)
treecd93a882e0726a7df500fedf2263263984406b36 /fabrics.c
parentReleasing debian version 2.2.1-4. (diff)
downloadnvme-cli-d2082ee94267e4ca59b187c5e37dac03c1d65187.tar.xz
nvme-cli-d2082ee94267e4ca59b187c5e37dac03c1d65187.zip
Merging upstream version 2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'fabrics.c')
-rw-r--r--fabrics.c294
1 files changed, 203 insertions, 91 deletions
diff --git a/fabrics.c b/fabrics.c
index 5560b72..b94097b 100644
--- a/fabrics.c
+++ b/fabrics.c
@@ -124,6 +124,94 @@ static void space_strip_len(int max, char *str)
}
}
+/*
+ * Compare two C strings and handle NULL pointers gracefully.
+ * If either of the two strings is NULL, return 0
+ * to let caller ignore the compare.
+ */
+static inline int strcmp0(const char *s1, const char *s2)
+{
+ if (!s1 || !s2)
+ return 0;
+ return strcmp(s1, s2);
+}
+
+/*
+ * Compare two C strings and handle NULL pointers gracefully.
+ * If either of the two strings is NULL, return 0
+ * to let caller ignore the compare.
+ */
+static inline int strcasecmp0(const char *s1, const char *s2)
+{
+ if (!s1 || !s2)
+ return 0;
+ return strcasecmp(s1, s2);
+}
+
+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 bool disc_ctrl_config_match(nvme_ctrl_t c, struct tr_config *trcfg)
+{
+ if (nvme_ctrl_is_discovery_ctrl(c) &&
+ !strcmp0(nvme_ctrl_get_transport(c), trcfg->transport) &&
+ !strcasecmp0(nvme_ctrl_get_traddr(c), trcfg->traddr) &&
+ !strcmp0(nvme_ctrl_get_trsvcid(c), trcfg->trsvcid) &&
+ !strcmp0(nvme_ctrl_get_host_traddr(c), trcfg->host_traddr) &&
+ !strcmp0(nvme_ctrl_get_host_iface(c), trcfg->host_iface))
+ return true;
+
+ return false;
+}
+
+static bool ctrl_config_match(nvme_ctrl_t c, struct tr_config *trcfg)
+{
+ if (!strcmp0(nvme_ctrl_get_subsysnqn(c), trcfg->subsysnqn) &&
+ !strcmp0(nvme_ctrl_get_transport(c), trcfg->transport) &&
+ !strcasecmp0(nvme_ctrl_get_traddr(c), trcfg->traddr) &&
+ !strcmp0(nvme_ctrl_get_trsvcid(c), trcfg->trsvcid) &&
+ !strcmp0(nvme_ctrl_get_host_traddr(c), trcfg->host_traddr) &&
+ !strcmp0(nvme_ctrl_get_host_iface(c), trcfg->host_iface))
+ return true;
+
+ return false;
+}
+
+static nvme_ctrl_t __lookup_ctrl(nvme_root_t r, struct tr_config *trcfg,
+ bool (*filter)(nvme_ctrl_t, struct tr_config *))
+{
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ nvme_subsystem_for_each_ctrl(s, c) {
+ if (!(filter(c, trcfg)))
+ continue;
+ return c;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static nvme_ctrl_t lookup_discovery_ctrl(nvme_root_t r, struct tr_config *trcfg)
+{
+ return __lookup_ctrl(r, trcfg, disc_ctrl_config_match);
+}
+
+static nvme_ctrl_t lookup_ctrl(nvme_root_t r, struct tr_config *trcfg)
+{
+ return __lookup_ctrl(r, trcfg, ctrl_config_match);
+}
+
static int set_discovery_kato(struct nvme_fabrics_config *cfg)
{
int tmo = cfg->keep_alive_tmo;
@@ -152,6 +240,8 @@ static nvme_ctrl_t __create_discover_ctrl(nvme_root_t r, nvme_host_t h,
return NULL;
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);
errno = 0;
@@ -159,7 +249,6 @@ static nvme_ctrl_t __create_discover_ctrl(nvme_root_t r, nvme_host_t h,
cfg->keep_alive_tmo = tmo;
if (ret) {
- errno = ret;
nvme_free_ctrl(c);
return NULL;
}
@@ -177,7 +266,7 @@ static nvme_ctrl_t create_discover_ctrl(nvme_root_t r, nvme_host_t h,
if (!c)
return NULL;
- if (!persistent)
+ if (nvme_ctrl_is_unique_discovery_ctrl(c))
return c;
/* Find out the name of discovery controller */
@@ -225,11 +314,12 @@ static void print_discovery_log(struct nvmf_discovery_log *log, int numrec)
nvmf_adrfam_str(e->adrfam): "");
printf("subtype: %s\n", nvmf_subtype_str(e->subtype));
printf("treq: %s\n", nvmf_treq_str(e->treq));
- printf("portid: %d\n", e->portid);
+ printf("portid: %d\n", le16_to_cpu(e->portid));
printf("trsvcid: %s\n", e->trsvcid);
printf("subnqn: %s\n", e->subnqn);
printf("traddr: %s\n", e->traddr);
- printf("eflags: %s\n", nvmf_eflags_str(e->eflags));
+ printf("eflags: %s\n",
+ nvmf_eflags_str(le16_to_cpu(e->eflags)));
switch (e->trtype) {
case NVMF_TRTYPE_RDMA:
@@ -265,9 +355,9 @@ static void json_discovery_log(struct nvmf_discovery_log *log, int numrec)
struct nvmf_disc_log_entry *e = &log->entries[i];
struct json_object *entry = json_create_object();
- nvme_strip_spaces(e->trsvcid, NVMF_TRSVCID_SIZE);
- nvme_strip_spaces(e->subnqn, NVMF_NQN_SIZE);
- nvme_strip_spaces(e->traddr, NVMF_TRADDR_SIZE);
+ space_strip_len(NVMF_TRSVCID_SIZE, e->trsvcid);
+ space_strip_len(NVMF_NQN_SIZE, e->subnqn);
+ space_strip_len(NVMF_TRADDR_SIZE, e->traddr);
json_object_add_value_string(entry, "trtype",
nvmf_trtype_str(e->trtype));
@@ -282,7 +372,8 @@ static void json_discovery_log(struct nvmf_discovery_log *log, int numrec)
json_object_add_value_string(entry, "trsvcid", e->trsvcid);
json_object_add_value_string(entry, "subnqn", e->subnqn);
json_object_add_value_string(entry, "traddr", e->traddr);
- json_object_add_value_uint(entry, "eflags", e->eflags);
+ json_object_add_value_string(entry, "eflags",
+ nvmf_eflags_str(le16_to_cpu(e->eflags)));
switch (e->trtype) {
case NVMF_TRTYPE_RDMA:
@@ -355,43 +446,104 @@ static int __discover(nvme_ctrl_t c, struct nvme_fabrics_config *defcfg,
struct nvmf_discovery_log *log = NULL;
nvme_subsystem_t s = nvme_ctrl_get_subsystem(c);
nvme_host_t h = nvme_subsystem_get_host(s);
+ nvme_root_t r = nvme_host_get_root(h);
uint64_t numrec;
- int err;
- err = nvmf_get_discovery_log(c, &log, MAX_DISC_RETRIES);
- if (err) {
- if (err > 0)
- nvme_show_status(err);
- else
- fprintf(stderr, "failed to get discovery log: %s\n",
- nvme_strerror(errno));
- return 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,
+ };
+ log = nvmf_get_discovery_wargs(&args);
+ if (!log) {
+ fprintf(stderr, "failed to get discovery log: %s\n",
+ nvme_strerror(errno));
+ return errno;
+ }
numrec = le64_to_cpu(log->numrec);
if (raw)
save_discovery_log(raw, log);
else if (!connect) {
- if (flags == JSON)
- json_discovery_log(log, numrec);
- else
+ switch (flags) {
+ case NORMAL:
print_discovery_log(log, numrec);
+ break;
+ case JSON:
+ json_discovery_log(log, numrec);
+ break;
+ case BINARY:
+ d_raw((unsigned char *)log,
+ sizeof(struct nvmf_discovery_log) +
+ numrec * sizeof(struct nvmf_disc_log_entry));
+ break;
+ default:
+ break;
+ }
} 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(r, &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)))
+ if (strcmp(nvme_ctrl_get_transport(c),
+ nvmf_trtype_str(e->trtype)))
continue;
- if (e->subtype == NVME_NQN_DISC)
+ 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;
+ }
errno = 0;
child = nvmf_connect_disc_entry(h, e, defcfg,
@@ -403,8 +555,8 @@ static int __discover(nvme_ctrl_t c, struct nvme_fabrics_config *defcfg,
if (discover)
__discover(child, defcfg, raw,
true, persistent, flags);
- if (e->subtype != NVME_NQN_NVME &&
- !persistent) {
+
+ if (disconnect) {
nvme_disconnect_ctrl(child);
nvme_free_ctrl(child);
}
@@ -423,62 +575,6 @@ static int __discover(nvme_ctrl_t c, struct nvme_fabrics_config *defcfg,
return 0;
}
-/*
- * Compare two C strings and handle NULL pointers gracefully.
- * If either of the two strings is NULL, return 0
- * to let caller ignore the compare.
- */
-static inline int strcmp0(const char *s1, const char *s2)
-{
- if (!s1 || !s2)
- return 0;
- return strcmp(s1, s2);
-}
-
-/*
- * Compare two C strings and handle NULL pointers gracefully.
- * If either of the two strings is NULL, return 0
- * to let caller ignore the compare.
- */
-static inline int strcasecmp0(const char *s1, const char *s2)
-{
- if (!s1 || !s2)
- return 0;
- return strcasecmp(s1, s2);
-}
-
-static bool ctrl_config_match(nvme_ctrl_t c, struct tr_config *trcfg)
-{
- if (!strcmp0(nvme_ctrl_get_transport(c), trcfg->transport) &&
- !strcasecmp0(nvme_ctrl_get_traddr(c), trcfg->traddr) &&
- !strcmp0(nvme_ctrl_get_trsvcid(c), trcfg->trsvcid) &&
- !strcmp0(nvme_ctrl_get_host_traddr(c), trcfg->host_traddr) &&
- !strcmp0(nvme_ctrl_get_host_iface(c), trcfg->host_iface))
- return true;
-
- return false;
-}
-
-static nvme_ctrl_t lookup_discover_ctrl(nvme_root_t r, struct tr_config *trcfg)
-{
- nvme_host_t h;
- nvme_subsystem_t s;
- nvme_ctrl_t c;
-
- nvme_for_each_host(r, h) {
- nvme_for_each_subsystem(h, s) {
- nvme_subsystem_for_each_ctrl(s, c) {
- if (!nvme_ctrl_is_discovery_ctrl(c))
- continue;
- if (ctrl_config_match(c, trcfg))
- return c;
- }
- }
- }
-
- return NULL;
-}
-
static char *get_default_trsvcid(const char *transport,
bool discovery_ctrl)
{
@@ -581,7 +677,7 @@ static int discover_from_conf_file(nvme_root_t r, nvme_host_t h,
};
if (!force) {
- c = lookup_discover_ctrl(r, &trcfg);
+ c = lookup_discovery_ctrl(r, &trcfg);
if (c) {
__discover(c, &cfg, raw, connect,
true, flags);
@@ -594,7 +690,7 @@ static int discover_from_conf_file(nvme_root_t r, nvme_host_t h,
goto next;
__discover(c, &cfg, raw, connect, persistent, flags);
- if (!persistent)
+ if (!(persistent || is_persistent_discovery_ctrl(h, c)))
ret = nvme_disconnect_ctrl(c);
nvme_free_ctrl(c);
@@ -657,9 +753,9 @@ static int discover_from_json_config_file(nvme_root_t r, nvme_host_t h,
};
if (!force) {
- cn = lookup_discover_ctrl(r, &trcfg);
+ cn = lookup_discovery_ctrl(r, &trcfg);
if (cn) {
- __discover(c, &cfg, raw, connect,
+ __discover(cn, &cfg, raw, connect,
true, flags);
continue;
}
@@ -670,7 +766,7 @@ static int discover_from_json_config_file(nvme_root_t r, nvme_host_t h,
continue;
__discover(cn, &cfg, raw, connect, persistent, flags);
- if (!persistent)
+ if (!(persistent || is_persistent_discovery_ctrl(h, cn)))
ret = nvme_disconnect_ctrl(cn);
nvme_free_ctrl(cn);
}
@@ -825,7 +921,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect)
}
}
if (!c && !force) {
- c = lookup_discover_ctrl(r, &trcfg);
+ c = lookup_discovery_ctrl(r, &trcfg);
if (c)
persistent = true;
}
@@ -841,9 +937,8 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect)
}
}
- ret = __discover(c, &cfg, raw, connect,
- persistent, flags);
- if (!persistent)
+ ret = __discover(c, &cfg, raw, connect, persistent, flags);
+ if (!(persistent || is_persistent_discovery_ctrl(h, c)))
nvme_disconnect_ctrl(c);
nvme_free_ctrl(c);
@@ -953,6 +1048,23 @@ int nvmf_connect(const char *desc, int argc, char **argv)
nvme_host_set_dhchap_key(h, hostkey);
if (!trsvcid)
trsvcid = get_default_trsvcid(transport, false);
+
+ struct tr_config trcfg = {
+ .subsysnqn = subsysnqn,
+ .transport = transport,
+ .traddr = traddr,
+ .host_traddr = cfg.host_traddr,
+ .host_iface = cfg.host_iface,
+ .trsvcid = trsvcid,
+ };
+
+ c = lookup_ctrl(r, &trcfg);
+ if (c && nvme_ctrl_get_name(c)) {
+ fprintf(stderr, "already connected\n");
+ errno = EALREADY;
+ goto out_free;
+ }
+
c = nvme_create_ctrl(r, subsysnqn, transport, traddr,
cfg.host_traddr, cfg.host_iface, trsvcid);
if (!c) {
@@ -965,7 +1077,7 @@ int nvmf_connect(const char *desc, int argc, char **argv)
errno = 0;
ret = nvmf_add_ctrl(h, c, &cfg);
if (ret)
- fprintf(stderr, "no controller found: %s\n",
+ fprintf(stderr, "could not add new controller: %s\n",
nvme_strerror(errno));
else {
errno = 0;