Commit 2b9d85c4 authored by Ben Walker's avatar Ben Walker
Browse files

nvmf: Remove host.[ch] and port.[ch]



These can be simplified and merged into the subsystem.

Remove the concept of mappings from subsystems and replace
it with a list of hosts and ports. The host is optional -
not specifying a host means any host can connect.

Change-Id: Ib3786acb40a34b7e10935af55f4b6756d40cc906
Signed-off-by: default avatarBen Walker <benjamin.walker@intel.com>
parent d38d2995
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -44,8 +44,6 @@

#include "spdk/event.h"

#include "nvmf/port.h"
#include "nvmf/host.h"
#include "nvmf/transport.h"

#include "spdk/log.h"
+4 −42
Original line number Diff line number Diff line
@@ -43,30 +43,6 @@
  # initiator having the opportunity to specify a smaller value.
  #MaxQueueDepth 128

# Users must change the Port section(s) to match the IP addresses
#  for their environment.
# Port sections define which fabric network ports the NVMf server
#  will use to listen and accept incoming connections.  A Port is
#  also used to control which ports will be used for each individual
#  NVM subsystem controller session, providing a means to distribute NVMf
#  traffic across all network ports.
[Port1]
  Listen RDMA 15.15.15.2:4420

[Port2]
  Listen RDMA 192.168.2.21:4420

# Users must change the Host section(s) to match the IP
#  addresses of the clients that will connect to this target.
# Netmask can be used to specify a single IP address or a range of IP addresses
#  Netmask 192.168.1.20   <== single IP address
#  Netmask 192.168.1.0/24 <== IP range 192.168.1.*
[Host1]
  Netmask 15.15.15.0/24

[Host2]
  Netmask 192.168.2.0/24

# NVMe Device Whitelist
# Users may specify which NVMe devices to claim by their PCI
# domain, bus, device, and function. The format is dddd:bb:dd.f, which is
@@ -81,29 +57,15 @@
  BDF 0000:01:00.0 Nvme1
  # ClaimAllDevices Yes

# Users should change the Subsystem section(s) below to define the
#   set of local NVMe resources that will be accessible by specific groups
#   of hosts.  These mappings will be inspected to approve
#   remote fabric transport and NVMf protocol connection requests.
#
# Each approved NVMf connection represents a specific virtual controller
#   session within the NVMf subsystem.  Any such session is allowed access
#   to all NVMe namespaces within the subsystem.
#
# NQN, Mapping, Controller are minimum required.
# The Mapping defines the local fabric network port to be used by remote
#   connecting initiator.  Multiple mappings can be used to permit shared
#   access to the same subsystem.
# Each Controller identifies a specific HW device from the Nvme whitelist
#   section above.
[Subsystem1]
  NQN nqn.2016-06.io.spdk:cnode1
  Mapping Port1 Host1
  Listen RDMA 15.15.15.2:4420
  Host nqn.2016-06.io.spdk:init
  Controller Nvme0

[Subsystem2]
  NQN nqn.2016-06.io.spdk:cnode2
  Mapping Port2 Host2
  # Using NVME 1 namespace 1
  Listen RDMA 192.168.2.21:4420
  Host nqn.2016-06.io.spdk:init
  Controller Nvme1
+2 −2
Original line number Diff line number Diff line
@@ -35,8 +35,8 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)

CFLAGS += $(DPDK_INC)
LIBNAME = nvmf
C_SRCS = port.c conn.c controller.c \
	 host.c subsystem.c conf.c \
C_SRCS = conn.c controller.c \
	 subsystem.c conf.c \
	 nvmf.c request.c session.c transport.c

C_SRCS-$(CONFIG_RDMA) += rdma.c
+33 −193
Original line number Diff line number Diff line
@@ -41,14 +41,15 @@

#include "conf.h"
#include "controller.h"
#include "host.h"
#include "nvmf_internal.h"
#include "port.h"
#include "subsystem.h"
#include "transport.h"
#include "spdk/conf.h"
#include "spdk/log.h"

#define MAX_LISTEN_ADDRESSES 255
#define MAX_HOSTS 255

#define PORTNUMSTRLEN 32

static int
@@ -181,145 +182,6 @@ spdk_nvmf_parse_addr(char *listen_addr, char **host, char **port)
	return 0;
}

static int
spdk_nvmf_parse_port(struct spdk_conf_section *sp)
{
	struct spdk_nvmf_port		*port;
	struct spdk_nvmf_fabric_intf	*fabric_intf;
	char *transport_name, *listen_addr, *host, *listen_port;
	int i = 0, rc = 0;

	/* Create the Subsystem Port */
	port = spdk_nvmf_port_create(sp->num);
	if (!port) {
		SPDK_ERRLOG("Port create failed\n");
		return -1;
	}

	/* Loop over the listen addresses and add them to the port */
	for (i = 0; ; i++) {
		const struct spdk_nvmf_transport *transport;

		transport_name = spdk_conf_section_get_nmval(sp, "Listen", i, 0);
		if (transport_name == NULL) {
			break;
		}

		transport = spdk_nvmf_transport_get(transport_name);
		if (transport == NULL) {
			SPDK_ERRLOG("Unknown transport type '%s'\n", transport_name);
			return -1;
		}

		listen_addr = spdk_conf_section_get_nmval(sp, "Listen", i, 1);
		if (listen_addr == NULL) {
			SPDK_ERRLOG("Missing address for Listen in Port%d\n", sp->num);
			break;
		}
		rc = spdk_nvmf_parse_addr(listen_addr, &host, &listen_port);
		if (rc < 0) {
			continue;
		}
		fabric_intf = spdk_nvmf_fabric_intf_create(transport, host, listen_port);
		if (!fabric_intf) {
			continue;
		}

		spdk_nvmf_port_add_fabric_intf(port, fabric_intf);
	}

	if (TAILQ_EMPTY(&port->head)) {
		SPDK_ERRLOG("No fabric interface found\n");
		return -1;
	}

	return 0;
}

static int
spdk_nvmf_parse_ports(void)
{
	int rc = 0;
	struct spdk_conf_section *sp;

	sp = spdk_conf_first_section(NULL);
	while (sp != NULL) {
		if (spdk_conf_section_match_prefix(sp, "Port")) {
			rc = spdk_nvmf_parse_port(sp);
			if (rc < 0) {
				return -1;
			}
		}
		sp = spdk_conf_next_section(sp);
	}
	return 0;
}

static int
spdk_nvmf_parse_host(struct spdk_conf_section *sp)
{
	int i;
	const char *mask;
	char **netmasks;
	int num_netmasks;
	struct spdk_nvmf_host *host;


	for (num_netmasks = 0; ; num_netmasks++) {
		mask = spdk_conf_section_get_nval(sp, "Netmask", num_netmasks);
		if (mask == NULL) {
			break;
		}
	}

	if (num_netmasks == 0) {
		return -1;
	}


	netmasks = calloc(num_netmasks, sizeof(char *));
	if (!netmasks) {
		return -1;
	}

	for (i = 0; i < num_netmasks; i++) {
		mask = spdk_conf_section_get_nval(sp, "Netmask", i);
		netmasks[i] = strdup(mask);
		if (!netmasks[i]) {
			free(netmasks);
			return -1;
		}
	}

	host = spdk_nvmf_host_create(sp->num, num_netmasks, netmasks);

	if (!host) {
		free(netmasks);
		return -1;
	}

	return 0;
}

static int
spdk_nvmf_parse_hosts(void)
{
	int rc = 0;
	struct spdk_conf_section *sp;

	sp = spdk_conf_first_section(NULL);
	while (sp != NULL) {
		if (spdk_conf_section_match_prefix(sp, "Host")) {
			rc = spdk_nvmf_parse_host(sp);
			if (rc < 0) {
				return -1;
			}
		}
		sp = spdk_conf_next_section(sp);
	}
	return 0;
}

static int
spdk_nvmf_parse_nvme(void)
{
@@ -450,8 +312,6 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp)
{
	const char *val, *nqn;
	struct spdk_nvmf_subsystem *subsystem;
	const char *port_name, *host_name;
	int port_id, host_id;
	struct spdk_nvmf_ctrlr *nvmf_ctrlr;
	int i, ret;
	uint64_t mask;
@@ -467,8 +327,6 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp)
		return -1;
	}



	/* Determine which core to assign to the subsystem using round robin */
	mask = spdk_app_get_core_mask();
	lcore = 0;
@@ -483,50 +341,44 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp)
		return -1;
	}

	val = spdk_conf_section_get_val(sp, "Mapping");
	if (val == NULL) {
		SPDK_ERRLOG("No Mapping entry in Subsystem %d\n", sp->num);
		nvmf_delete_subsystem(subsystem);
		return -1;
	}
	/* Parse Listen sections */
	for (i = 0; i < MAX_LISTEN_ADDRESSES; i++) {
		char *transport_name, *listen_addr;
		char *traddr, *trsvc;
		const struct spdk_nvmf_transport *transport;

	for (i = 0; i < MAX_PER_SUBSYSTEM_ACCESS_MAP; i++) {
		val = spdk_conf_section_get_nmval(sp, "Mapping", i, 0);
		if (val == NULL) {
		transport_name = spdk_conf_section_get_nmval(sp, "Listen", i, 0);
		listen_addr = spdk_conf_section_get_nmval(sp, "Listen", i, 1);

		if (!transport_name || !listen_addr) {
			break;
		}

		port_name = spdk_conf_section_get_nmval(sp, "Mapping", i, 0);
		host_name = spdk_conf_section_get_nmval(sp, "Mapping", i, 1);
		if (port_name == NULL || host_name == NULL) {
			nvmf_delete_subsystem(subsystem);
			return -1;
		}
		if (strncasecmp(port_name, "Port",
				strlen("Port")) != 0
		    || sscanf(port_name, "%*[^0-9]%d", &port_id) != 1) {
			SPDK_ERRLOG("Invalid mapping for Subsystem %d\n", sp->num);
			nvmf_delete_subsystem(subsystem);
			return -1;
		transport = spdk_nvmf_transport_get(transport_name);
		if (transport == NULL) {
			SPDK_ERRLOG("Unknown transport type '%s'\n", transport_name);
			continue;
		}
		if (strncasecmp(host_name, "Host",
				strlen("Host")) != 0
		    || sscanf(host_name, "%*[^0-9]%d", &host_id) != 1) {
			SPDK_ERRLOG("Invalid mapping for Subsystem %d\n", sp->num);
			nvmf_delete_subsystem(subsystem);
			return -1;

		ret = spdk_nvmf_parse_addr(listen_addr, &traddr, &trsvc);
		if (ret < 0) {
			SPDK_ERRLOG("Unable to parse transport address '%s'\n", listen_addr);
			continue;
		}
		if (port_id < 1 || host_id < 1) {
			SPDK_ERRLOG("Invalid mapping for Subsystem %d\n", sp->num);
			nvmf_delete_subsystem(subsystem);
			return -1;

		spdk_nvmf_subsystem_add_listener(subsystem, transport, traddr, trsvc);
	}

		ret = spdk_nvmf_subsystem_add_map(subsystem, port_id, host_id);
		if (ret < 0) {
			nvmf_delete_subsystem(subsystem);
			return -1;
	/* Parse Host sections */
	for (i = 0; i < MAX_HOSTS; i++) {
		char *host_nqn;

		host_nqn = spdk_conf_section_get_nval(sp, "Host", i);
		if (!host_nqn) {
			break;
		}

		spdk_nvmf_subsystem_add_host(subsystem, host_nqn);
	}

	val = spdk_conf_section_get_val(sp, "Controller");
@@ -587,18 +439,6 @@ spdk_nvmf_parse_conf(void)
		return rc;
	}

	/* Port sections */
	rc = spdk_nvmf_parse_ports();
	if (rc < 0) {
		return rc;
	}

	/* Host sections */
	rc = spdk_nvmf_parse_hosts();
	if (rc < 0) {
		return rc;
	}

	/* NVMe sections */
	rc = spdk_nvmf_parse_nvme();
	if (rc < 0) {

lib/nvmf/host.c

deleted100644 → 0
+0 −301
Original line number Diff line number Diff line
/*-
 *   BSD LICENSE
 *
 *   Copyright (c) Intel Corporation.
 *   All rights reserved.
 *
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *     * Neither the name of Intel Corporation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

#include "host.h"
#include "nvmf_internal.h"
#include "subsystem.h"
#include "spdk/log.h"
#include "spdk/trace.h"

#define MAX_MASKBUF 128
#define MAX_INITIATOR 8
#define MAX_INITIATOR_GROUP 32

#define MAX_ADDRBUF 64
#define MAX_INITIATOR_ADDR (MAX_ADDRBUF)
#define MAX_INITIATOR_NAME 256
#define MAX_NETMASK 256

static TAILQ_HEAD(, spdk_nvmf_host) g_host_head = TAILQ_HEAD_INITIALIZER(g_host_head);

struct spdk_nvmf_host *
spdk_nvmf_host_create(int tag,
		      int num_netmasks,
		      char **netmasks)
{
	int i;
	struct spdk_nvmf_host *host = NULL;

	/* Make sure there are no duplicate initiator group tags */
	if (spdk_nvmf_host_find_by_tag(tag)) {
		SPDK_ERRLOG("Initiator group creation failed due to duplicate initiator group tag (%d)\n",
			    tag);
		return NULL;
	}

	if (num_netmasks > MAX_NETMASK) {
		SPDK_ERRLOG("%d > MAX_NETMASK\n", num_netmasks);
		return NULL;
	}

	SPDK_TRACELOG(SPDK_TRACE_DEBUG,
		      "add initiator group (from initiator list) tag=%d, #masks=%d\n",
		      tag, num_netmasks);

	host = calloc(1, sizeof(*host));
	if (!host) {
		SPDK_ERRLOG("Unable to allocate host (%d)\n", tag);
		return NULL;
	}

	host->tag = tag;

	host->nnetmasks = num_netmasks;
	host->netmasks = netmasks;
	for (i = 0; i < num_netmasks; i++) {
		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Netmask %s\n", host->netmasks[i]);
	}

	host->state = GROUP_INIT;

	pthread_mutex_lock(&g_nvmf_tgt.mutex);
	host->state = GROUP_READY;
	TAILQ_INSERT_TAIL(&g_host_head, host, tailq);
	pthread_mutex_unlock(&g_nvmf_tgt.mutex);

	return host;
}

static void
nvmf_initiator_group_destroy(struct spdk_nvmf_host *host)
{
#if 0 // TODO: fix bogus scan-build warning about use-after-free
	int i;

	if (!host) {
		return;
	}

	for (i = 0; i < host->nnetmasks; i++) {
		free(host->netmasks[i]);
	}

	free(host->netmasks);
	free(host);
#endif
}


static int
spdk_nvmf_allow_ipv6(const char *netmask, const char *addr)
{
	struct in6_addr in6_mask;
	struct in6_addr in6_addr;
	char mask[MAX_MASKBUF];
	const char *p;
	size_t n;
	int bits, bmask;
	int i;

	if (netmask[0] != '[')
		return 0;
	p = strchr(netmask, ']');
	if (p == NULL)
		return 0;
	n = p - (netmask + 1);
	if (n + 1 > sizeof mask)
		return 0;

	memcpy(mask, netmask + 1, n);
	mask[n] = '\0';
	p++;

	if (p[0] == '/') {
		bits = (int) strtol(p + 1, NULL, 10);
		if (bits < 0 || bits > 128)
			return 0;
	} else {
		bits = 128;
	}

	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "input %s\n", addr);
	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "mask  %s / %d\n", mask, bits);

	/* presentation to network order binary */
	if (inet_pton(AF_INET6, mask, &in6_mask) <= 0
	    || inet_pton(AF_INET6, addr, &in6_addr) <= 0) {
		return 0;
	}

	/* check 128bits */
	for (i = 0; i < (bits / 8); i++) {
		if (in6_mask.s6_addr[i] != in6_addr.s6_addr[i])
			return 0;
	}
	if (bits % 8 && i < (MAX_MASKBUF / 8)) {
		bmask = (0xffU << (8 - (bits % 8))) & 0xffU;
		if ((in6_mask.s6_addr[i] & bmask) != (in6_addr.s6_addr[i] & bmask))
			return 0;
	}

	/* match */
	return 1;
}

static int
spdk_nvmf_allow_ipv4(const char *netmask, const char *addr)
{
	struct in_addr in4_mask;
	struct in_addr in4_addr;
	char mask[MAX_MASKBUF];
	const char *p;
	uint32_t bmask;
	size_t n;
	int bits;

	p = strchr(netmask, '/');
	if (p == NULL) {
		p = netmask + strlen(netmask);
	}
	n = p - netmask;
	if (n + 1 > sizeof mask)
		return 0;

	memcpy(mask, netmask, n);
	mask[n] = '\0';

	if (p[0] == '/') {
		bits = (int) strtol(p + 1, NULL, 10);
		if (bits < 0 || bits > 32)
			return 0;
	} else {
		bits = 32;
	}

	/* presentation to network order binary */
	if (inet_pton(AF_INET, mask, &in4_mask) <= 0
	    || inet_pton(AF_INET, addr, &in4_addr) <= 0) {
		return 0;
	}

	/* check 32bits */
	bmask = (0xffffffffULL << (32 - bits)) & 0xffffffffU;
	if ((ntohl(in4_mask.s_addr) & bmask) != (ntohl(in4_addr.s_addr) & bmask))
		return 0;

	/* match */
	return 1;
}

static int
spdk_nvmf_allow_netmask(const char *netmask, const char *addr)
{
	if (netmask == NULL || addr == NULL)
		return 0;
	if (strcasecmp(netmask, "ALL") == 0)
		return 1;
	if (netmask[0] == '[') {
		/* IPv6 */
		if (spdk_nvmf_allow_ipv6(netmask, addr))
			return 1;
	} else {
		/* IPv4 */
		if (spdk_nvmf_allow_ipv4(netmask, addr))
			return 1;
	}
	return 0;
}

struct spdk_nvmf_host *
spdk_nvmf_host_find_by_addr(char *addr)
{
	struct spdk_nvmf_host	*host;
	int i;
	int rc;

	if (addr == NULL)
		return NULL;

	TAILQ_FOREACH(host, &g_host_head, tailq) {
		/* check netmask of each group looking for permission */
		for (i = 0; i < host->nnetmasks; i++) {
			SPDK_TRACELOG(SPDK_TRACE_DEBUG, "netmask=%s, addr=%s\n",
				      host->netmasks[i], addr);
			rc = spdk_nvmf_allow_netmask(host->netmasks[i], addr);
			if (rc > 0) {
				/* OK netmask */
				return host;
			}
		}
	}

	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "No initiator group addr match for %s\n",
		      addr);
	return NULL;
}

struct spdk_nvmf_host *
spdk_nvmf_host_find_by_tag(int tag)
{
	struct spdk_nvmf_host *host;

	TAILQ_FOREACH(host, &g_host_head, tailq) {
		if (host->tag == tag) {
			SPDK_TRACELOG(SPDK_TRACE_DEBUG, " found initiator group with tag: host %p\n", host);
			return host;
		}
	}

	return NULL;
}

void
spdk_nvmf_host_destroy_all(void)
{
	struct spdk_nvmf_host *host;

	SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Enter\n");
	pthread_mutex_lock(&g_nvmf_tgt.mutex);
	while (!TAILQ_EMPTY(&g_host_head)) {
		host = TAILQ_FIRST(&g_host_head);
		host->state = GROUP_DESTROY;
		TAILQ_REMOVE(&g_host_head, host, tailq);
		nvmf_initiator_group_destroy(host);
	}
	pthread_mutex_unlock(&g_nvmf_tgt.mutex);
}
Loading