diff options
Diffstat (limited to 'fabrics.c')
-rw-r--r-- | fabrics.c | 294 |
1 files changed, 203 insertions, 91 deletions
@@ -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; |