#include <libgen.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
#include <ccan/list/list.h>
#include "ioctl.h"
#include "filters.h"
free(c);
}
+#define ____stringify(x...) #x
+#define __stringify(x...) ____stringify(x)
+
+static void discovery_trsvcid(nvme_ctrl_t c)
+{
+ if (!strcmp(c->transport, "tcp")) {
+ /* Default port for NVMe/TCP discovery controllers */
+ c->trsvcid = strdup(__stringify(NVME_DISC_IP_PORT));
+ } else if (!strcmp(c->transport, "rdma")) {
+ /* Default port for NVMe/RDMA controllers */
+ c->trsvcid = strdup(__stringify(NVME_RDMA_IP_PORT));
+ }
+}
+
+static bool traddr_is_hostname(const char *transport, const char *traddr)
+{
+ char addrstr[NVMF_TRADDR_SIZE];
+
+ if (!traddr || !transport)
+ return false;
+ if (strcmp(transport, "tcp") &&
+ strcmp(transport, "rdma"))
+ return false;
+ if (inet_pton(AF_INET, traddr, addrstr) > 0 ||
+ inet_pton(AF_INET6, traddr, addrstr) > 0)
+ return false;
+ return true;
+}
+
+void hostname2traddr(nvme_ctrl_t c, const char *host_traddr)
+{
+ struct addrinfo *host_info, hints = {.ai_family = AF_UNSPEC};
+ char addrstr[NVMF_TRADDR_SIZE];
+ const char *p;
+ int ret;
+
+ ret = getaddrinfo(host_traddr, NULL, &hints, &host_info);
+ if (ret) {
+ nvme_msg(LOG_DEBUG, "failed to resolve host %s info\n",
+ host_traddr);
+ c->host_traddr = strdup(host_traddr);
+ return;
+ }
+
+ switch (host_info->ai_family) {
+ case AF_INET:
+ p = inet_ntop(host_info->ai_family,
+ &(((struct sockaddr_in *)host_info->ai_addr)->sin_addr),
+ addrstr, NVMF_TRADDR_SIZE);
+ break;
+ case AF_INET6:
+ p = inet_ntop(host_info->ai_family,
+ &(((struct sockaddr_in6 *)host_info->ai_addr)->sin6_addr),
+ addrstr, NVMF_TRADDR_SIZE);
+ break;
+ default:
+ nvme_msg(LOG_DEBUG, "unrecognized address family (%d) %s\n",
+ host_info->ai_family, c->traddr);
+ c->host_traddr = strdup(host_traddr);
+ goto free_addrinfo;
+ }
+ if (!p) {
+ nvme_msg(LOG_DEBUG, "failed to get traddr for %s\n",
+ c->traddr);
+ c->host_traddr = strdup(host_traddr);
+ } else
+ c->host_traddr = strdup(addrstr);
+
+free_addrinfo:
+ freeaddrinfo(host_info);
+}
+
struct nvme_ctrl *nvme_create_ctrl(const char *subsysnqn,
const char *transport, const char *traddr,
const char *host_traddr, const char *trsvcid)
{
struct nvme_ctrl *c;
+ bool discovery = false;
- if (!transport)
+ if (!transport) {
+ nvme_msg(LOG_ERR, "No transport specified\n");
+ return NULL;
+ }
+ if (strncmp(transport, "loop", 4) && !traddr) {
+ nvme_msg(LOG_ERR, "No transport address for '%s'\n", transport);
+ return NULL;
+ }
+ if (!subsysnqn) {
+ nvme_msg(LOG_ERR, "No subsystem NQN specified\n");
return NULL;
+ } else if (!strcmp(subsysnqn, NVME_DISC_SUBSYS_NAME))
+ discovery = true;
c = calloc(1, sizeof(*c));
c->fd = -1;
c->cfg.tos = -1;
list_head_init(&c->paths);
list_node_init(&c->entry);
c->transport = strdup(transport);
- if (subsysnqn)
- c->subsysnqn = strdup(subsysnqn);
+ c->subsysnqn = strdup(subsysnqn);
if (traddr)
c->traddr = strdup(traddr);
- else
- c->traddr = strdup("none");
- if (host_traddr)
- c->host_traddr = strdup(host_traddr);
- else
- c->host_traddr = strdup("none");
+ if (host_traddr) {
+ if (traddr_is_hostname(transport, host_traddr))
+ hostname2traddr(c, host_traddr);
+ else
+ c->host_traddr = strdup(host_traddr);
+ }
if (trsvcid)
c->trsvcid = strdup(trsvcid);
- else
- c->trsvcid = strdup("none");
+ else if (discovery)
+ discovery_trsvcid(c);
+ else if (!strncmp(transport, "rdma", 4) ||
+ !strncmp(transport, "tcp", 3)) {
+ nvme_msg(LOG_ERR, "No trsvcid specified for '%s'\n",
+ transport);
+ nvme_free_ctrl(c);
+ c = NULL;
+ }
return c;
}
nvme_subsystem_for_each_ctrl(s, c) {
if (strcmp(c->transport, transport))
continue;
- if (traddr &&
+ if (traddr && c->traddr &&
strcmp(c->traddr, traddr))
continue;
- if (host_traddr &&
+ if (host_traddr && c->host_traddr &&
strcmp(c->host_traddr, host_traddr))
continue;
- if (trsvcid &&
+ if (trsvcid && c->trsvcid &&
strcmp(c->trsvcid, trsvcid))
continue;
return c;