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: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Ben Walker 2016-07-15 14:16:59 -07:00
parent d38d299576
commit 2b9d85c448
16 changed files with 156 additions and 1048 deletions

View File

@ -44,8 +44,6 @@
#include "spdk/event.h"
#include "nvmf/port.h"
#include "nvmf/host.h"
#include "nvmf/transport.h"
#include "spdk/log.h"

View File

@ -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

View File

@ -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

View File

@ -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;
}
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;
}
if (port_id < 1 || host_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;
}
ret = spdk_nvmf_subsystem_add_map(subsystem, port_id, host_id);
ret = spdk_nvmf_parse_addr(listen_addr, &traddr, &trsvc);
if (ret < 0) {
nvmf_delete_subsystem(subsystem);
return -1;
SPDK_ERRLOG("Unable to parse transport address '%s'\n", listen_addr);
continue;
}
spdk_nvmf_subsystem_add_listener(subsystem, transport, traddr, trsvc);
}
/* 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) {

View File

@ -1,301 +0,0 @@
/*-
* 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);
}

View File

@ -1,64 +0,0 @@
/*-
* 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.
*/
#ifndef NVMF_HOST_H
#define NVMF_HOST_H
#include "spdk/queue.h"
#include "port.h" // For enum group_state
struct spdk_nvmf_host {
int nnetmasks;
char **netmasks;
int ref;
int tag;
enum group_state state;
TAILQ_ENTRY(spdk_nvmf_host) tailq;
};
/* NVMf Initiator Group management API */
struct spdk_nvmf_host *
spdk_nvmf_host_create(int tag,
int num_netmasks,
char **netmasks);
struct spdk_nvmf_host *
spdk_nvmf_host_find_by_tag(int tag);
struct spdk_nvmf_host *
spdk_nvmf_host_find_by_addr(char *addr);
void
spdk_nvmf_host_destroy_all(void);
#endif

View File

@ -41,8 +41,6 @@
#include "conf.h"
#include "conn.h"
#include "controller.h"
#include "port.h"
#include "host.h"
#include "subsystem.h"
#include "transport.h"
#include "spdk/trace.h"
@ -185,8 +183,6 @@ nvmf_tgt_subsystem_fini(void)
{
spdk_shutdown_nvmf_subsystems();
spdk_nvmf_shutdown_nvme();
spdk_nvmf_host_destroy_all();
spdk_nvmf_port_destroy_all();
spdk_nvmf_transport_fini();
pthread_mutex_destroy(&g_nvmf_tgt.mutex);

View File

@ -1,205 +0,0 @@
/*-
* 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 <rte_config.h>
#include <rte_debug.h>
#include "conn.h"
#include "port.h"
#include "transport.h"
#include "spdk/log.h"
#include "spdk/trace.h"
#include "spdk/nvmf_spec.h"
static TAILQ_HEAD(, spdk_nvmf_port) g_port_head = TAILQ_HEAD_INITIALIZER(g_port_head);
/* Assumes caller allocated host and port strings on the heap */
struct spdk_nvmf_fabric_intf *
spdk_nvmf_fabric_intf_create(const struct spdk_nvmf_transport *transport, char *host,
char *sin_port)
{
struct spdk_nvmf_fabric_intf *fabric_intf = NULL;
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Creating fabric intf: host address %s, port %s\n",
host, sin_port);
RTE_VERIFY(host != NULL);
RTE_VERIFY(sin_port != NULL);
fabric_intf = calloc(1, sizeof(*fabric_intf));
if (!fabric_intf) {
SPDK_ERRLOG("fabric_intf calloc error\n");
return NULL;
}
fabric_intf->host = host;
fabric_intf->sin_port = sin_port;
fabric_intf->transport = transport;
return fabric_intf;
}
void
spdk_nvmf_fabric_intf_destroy(struct spdk_nvmf_fabric_intf *fabric_intf)
{
RTE_VERIFY(fabric_intf != NULL);
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Enter\n");
free(fabric_intf);
}
struct spdk_nvmf_fabric_intf *
spdk_nvmf_port_find_fabric_intf_by_addr(char *addr)
{
struct spdk_nvmf_port *port;
struct spdk_nvmf_fabric_intf *fabric_intf;
if (addr == NULL)
goto find_error;
TAILQ_FOREACH(port, &g_port_head, tailq) {
TAILQ_FOREACH(fabric_intf, &port->head, tailq) {
if (!strncasecmp(fabric_intf->host, addr, strlen(fabric_intf->host))) {
return fabric_intf;
}
}
}
find_error:
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "No device addr match for %s\n", addr);
return NULL;
}
struct spdk_nvmf_port *
spdk_nvmf_port_create(int tag)
{
struct spdk_nvmf_port *port;
if (tag <= 0) {
SPDK_ERRLOG("invalid port tag (%d)\n", tag);
return NULL;
}
/* Make sure there are no duplicate port tags */
if (spdk_nvmf_port_find_by_tag(tag)) {
SPDK_ERRLOG("port creation failed. duplicate port tag (%d)\n", tag);
return NULL;
}
port = calloc(1, sizeof(*port));
if (!port) {
SPDK_ERRLOG("port calloc error (%d)\n", tag);
return NULL;
}
port->state = GROUP_INIT;
port->tag = tag;
TAILQ_INIT(&port->head);
pthread_mutex_lock(&g_nvmf_tgt.mutex);
port->state = GROUP_READY;
TAILQ_INSERT_TAIL(&g_port_head, port, tailq);
pthread_mutex_unlock(&g_nvmf_tgt.mutex);
return port;
}
void
spdk_nvmf_port_destroy(struct spdk_nvmf_port *port)
{
struct spdk_nvmf_fabric_intf *fabric_intf;
RTE_VERIFY(port != NULL);
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Enter\n");
while (!TAILQ_EMPTY(&port->head)) {
fabric_intf = TAILQ_FIRST(&port->head);
TAILQ_REMOVE(&port->head, fabric_intf, tailq);
#if 0 // TODO: fix bogus scan-build warning about use-after-free
spdk_nvmf_fabric_intf_destroy(fabric_intf);
#endif
}
TAILQ_REMOVE(&g_port_head, port, tailq);
#if 0 // TODO: fix bogus scan-build warning about use-after-free
free(port);
#endif
}
void
spdk_nvmf_port_add_fabric_intf(struct spdk_nvmf_port *port,
struct spdk_nvmf_fabric_intf *fabric_intf)
{
RTE_VERIFY(port != NULL);
RTE_VERIFY(fabric_intf != NULL);
fabric_intf->port = port;
TAILQ_INSERT_TAIL(&port->head, fabric_intf, tailq);
}
struct spdk_nvmf_port *
spdk_nvmf_port_find_by_tag(int tag)
{
struct spdk_nvmf_port *port;
if (tag <= 0) {
SPDK_ERRLOG("invalid port tag (%d)\n", tag);
return NULL;
}
TAILQ_FOREACH(port, &g_port_head, tailq) {
if (port->tag == tag) {
SPDK_TRACELOG(SPDK_TRACE_DEBUG, " found port with tag: port %p\n", port);
return port;
}
}
return NULL;
}
void
spdk_nvmf_port_destroy_all(void)
{
struct spdk_nvmf_port *port;
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Enter\n");
pthread_mutex_lock(&g_nvmf_tgt.mutex);
while (!TAILQ_EMPTY(&g_port_head)) {
port = TAILQ_FIRST(&g_port_head);
spdk_nvmf_port_destroy(port);
}
pthread_mutex_unlock(&g_nvmf_tgt.mutex);
}

View File

@ -1,103 +0,0 @@
/*-
* 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.
*/
#ifndef NVMF_PORT_H
#define NVMF_PORT_H
#include <stdint.h>
#include "spdk/conf.h"
#include "spdk/queue.h"
#include "spdk/nvmf_spec.h"
/** \file
* An NVMf subsystem port, referred to as simply "port" is defined by the
* specification as follows:
*
* An NVM subsystem port (port) is a collection of one or more physical fabric
* interfaces that together act as a single interface between the NVM subsystem
* and a fabric. When link aggregation (e.g., Ethernet) is used, the physical
* ports for the group of aggregated links constitute a single NVM subsystem port.
*/
struct spdk_nvmf_transport;
enum group_state {
GROUP_INIT = 0x0,
GROUP_READY = 0x1,
GROUP_DESTROY = 0x2,
};
struct spdk_nvmf_fabric_intf {
char *host;
char *sin_port;
struct spdk_nvmf_port *port;
const struct spdk_nvmf_transport *transport;
uint32_t num_sessions;
TAILQ_ENTRY(spdk_nvmf_fabric_intf) tailq;
};
struct spdk_nvmf_port {
int tag;
enum group_state state;
TAILQ_HEAD(, spdk_nvmf_fabric_intf) head;
TAILQ_ENTRY(spdk_nvmf_port) tailq;
};
struct spdk_nvmf_fabric_intf *
spdk_nvmf_fabric_intf_create(const struct spdk_nvmf_transport *transport, char *host,
char *sin_port);
void
spdk_nvmf_fabric_intf_destroy(struct spdk_nvmf_fabric_intf *fabric_intf);
struct spdk_nvmf_fabric_intf *
spdk_nvmf_port_find_fabric_intf_by_addr(char *addr);
struct spdk_nvmf_port *
spdk_nvmf_port_create(int tag);
void
spdk_nvmf_port_destroy(struct spdk_nvmf_port *port);
struct spdk_nvmf_port *
spdk_nvmf_port_find_by_tag(int tag);
void
spdk_nvmf_port_add_fabric_intf(struct spdk_nvmf_port *port,
struct spdk_nvmf_fabric_intf *fabric_intf);
void
spdk_nvmf_port_destroy_all(void);
#endif

View File

@ -48,8 +48,6 @@
#include "conn.h"
#include "request.h"
#include "port.h"
#include "host.h"
#include "session.h"
#include "subsystem.h"
#include "transport.h"
@ -575,19 +573,15 @@ fail:
static int
nvmf_rdma_connect(struct rdma_cm_event *event)
{
struct spdk_nvmf_host *host;
struct spdk_nvmf_fabric_intf *fabric_intf;
struct rdma_cm_id *conn_id;
struct spdk_nvmf_rdma_conn *rdma_conn = NULL;
struct spdk_nvmf_conn *conn;
struct spdk_nvmf_rdma_request *rdma_req;
struct ibv_device_attr ibdev_attr;
struct sockaddr_in *addr;
struct rdma_conn_param *host_event_data = NULL;
struct rdma_conn_param ctrlr_event_data;
struct spdk_nvmf_rdma_accept_private_data accept_data;
uint16_t sts = 0;
char addr_str[INET_ADDRSTRLEN];
int rc, qp_depth, rw_depth;
@ -604,30 +598,6 @@ nvmf_rdma_connect(struct rdma_cm_event *event)
}
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Connect Recv on fabric intf name %s, dev_name %s\n",
conn_id->verbs->device->name, conn_id->verbs->device->dev_name);
addr = (struct sockaddr_in *)rdma_get_local_addr(conn_id);
inet_ntop(AF_INET, &(addr->sin_addr), addr_str, INET_ADDRSTRLEN);
SPDK_TRACELOG(SPDK_TRACE_RDMA, "Connect Route: local addr %s\n",
addr_str);
fabric_intf = spdk_nvmf_port_find_fabric_intf_by_addr(addr_str);
if (fabric_intf == NULL) {
SPDK_ERRLOG("connect request: rdma device does not exist!\n");
goto err1;
}
SPDK_TRACELOG(SPDK_TRACE_RDMA, "Found existing RDMA Device %p\n", fabric_intf);
/* validate remote address is within a provisioned initiator group */
addr = (struct sockaddr_in *)rdma_get_peer_addr(conn_id);
inet_ntop(AF_INET, &(addr->sin_addr), addr_str, INET_ADDRSTRLEN);
SPDK_TRACELOG(SPDK_TRACE_RDMA, "Connect Route: peer addr %s\n",
addr_str);
host = spdk_nvmf_host_find_by_addr(addr_str);
if (host == NULL) {
SPDK_ERRLOG("connect request: remote host addr not provisioned!\n");
goto err1;
}
SPDK_TRACELOG(SPDK_TRACE_RDMA, "Found approved remote host %p\n", host);
/* Init the NVMf rdma transport connection */
rdma_conn = allocate_rdma_conn();
@ -1178,15 +1148,15 @@ nvmf_check_rdma_completions(struct spdk_nvmf_conn *conn)
}
static void
nvmf_rdma_discover(struct spdk_nvmf_fabric_intf *fabric_intf,
nvmf_rdma_discover(struct spdk_nvmf_listen_addr *listen_addr,
struct spdk_nvmf_discovery_log_page_entry *entry)
{
entry->trtype = SPDK_NVMF_TRANS_RDMA;
entry->adrfam = SPDK_NVMF_ADDR_FAMILY_IPV4;
entry->treq = SPDK_NVMF_TREQ_NOT_SPECIFIED;
snprintf(entry->trsvcid, sizeof(entry->trsvcid), "%s", fabric_intf->sin_port);
snprintf(entry->traddr, sizeof(entry->traddr), "%s", fabric_intf->host);
snprintf(entry->trsvcid, sizeof(entry->trsvcid), "%s", listen_addr->trsvc);
snprintf(entry->traddr, sizeof(entry->traddr), "%s", listen_addr->traddr);
entry->tsas.rdma.rdma_qptype = SPDK_NVMF_QP_TYPE_RELIABLE_CONNECTED;
entry->tsas.rdma.rdma_prtype = SPDK_NVMF_RDMA_NO_PROVIDER;
@ -1206,7 +1176,7 @@ const struct spdk_nvmf_transport spdk_nvmf_transport_rdma = {
.conn_fini = nvmf_rdma_conn_cleanup,
.conn_poll = nvmf_check_rdma_completions,
.fabric_intf_discover = nvmf_rdma_discover,
.listen_addr_discover = nvmf_rdma_discover,
};
SPDK_LOG_REGISTER_TRACE_FLAG("rdma", SPDK_TRACE_RDMA)

View File

@ -443,7 +443,7 @@ nvmf_process_connect(struct spdk_nvmf_request *req)
}
/* Look up the requested subsystem */
subsystem = nvmf_find_subsystem(data->subnqn);
subsystem = nvmf_find_subsystem(data->subnqn, data->hostnqn);
if (subsystem == NULL) {
SPDK_ERRLOG("Could not find subsystem '%s'\n", data->subnqn);
INVALID_CONNECT_DATA(subnqn);

View File

@ -208,7 +208,7 @@ spdk_nvmf_session_connect(struct spdk_nvmf_conn *conn,
SPDK_TRACELOG(SPDK_TRACE_NVMF, " subnqn: \"%s\"\n", data->subnqn);
SPDK_TRACELOG(SPDK_TRACE_NVMF, " hostnqn: \"%s\"\n", data->hostnqn);
subsystem = nvmf_find_subsystem(data->subnqn);
subsystem = nvmf_find_subsystem(data->subnqn, data->hostnqn);
if (subsystem == NULL) {
SPDK_ERRLOG("Could not find subsystem '%s'\n", data->subnqn);
INVALID_CONNECT_DATA(subnqn);

View File

@ -34,8 +34,6 @@
#include <ctype.h>
#include "controller.h"
#include "port.h"
#include "host.h"
#include "nvmf_internal.h"
#include "session.h"
#include "subsystem.h"
@ -48,22 +46,30 @@
static TAILQ_HEAD(, spdk_nvmf_subsystem) g_subsystems = TAILQ_HEAD_INITIALIZER(g_subsystems);
struct spdk_nvmf_subsystem *
nvmf_find_subsystem(const char *subnqn)
nvmf_find_subsystem(const char *subnqn, const char *hostnqn)
{
struct spdk_nvmf_subsystem *subs;
struct spdk_nvmf_subsystem *subsystem;
struct spdk_nvmf_host *host;
if (subnqn == NULL)
if (!subnqn || !hostnqn) {
return NULL;
}
TAILQ_FOREACH(subs, &g_subsystems, entries) {
if (strcasecmp(subnqn, subs->subnqn) == 0) {
SPDK_TRACELOG(SPDK_TRACE_NVMF, "found subsystem group with name: %s\n",
subnqn);
return subs;
TAILQ_FOREACH(subsystem, &g_subsystems, entries) {
if (strcasecmp(subnqn, subsystem->subnqn) == 0) {
if (subsystem->num_hosts == 0) {
/* No hosts means any host can connect */
return subsystem;
}
TAILQ_FOREACH(host, &subsystem->hosts, link) {
if (strcasecmp(hostnqn, host->nqn) == 0) {
return subsystem;
}
}
}
}
fprintf(stderr, "can't find subsystem %s\n", subnqn);
return NULL;
}
@ -105,6 +111,8 @@ nvmf_create_subsystem(int num, const char *name,
subsystem->num = num;
subsystem->subtype = sub_type;
snprintf(subsystem->subnqn, sizeof(subsystem->subnqn), "%s", name);
TAILQ_INIT(&subsystem->listen_addrs);
TAILQ_INIT(&subsystem->hosts);
subsystem->poller.fn = spdk_nvmf_subsystem_poller;
subsystem->poller.arg = subsystem;
@ -118,7 +126,8 @@ nvmf_create_subsystem(int num, const char *name,
int
nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem)
{
int i;
struct spdk_nvmf_listen_addr *listen_addr, *listen_addr_tmp;
struct spdk_nvmf_host *host, *host_tmp;
if (subsystem == NULL) {
SPDK_TRACELOG(SPDK_TRACE_NVMF,
@ -126,8 +135,19 @@ nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem)
return 0;
}
for (i = 0; i < subsystem->map_count; i++) {
subsystem->map[i].host->ref--;
TAILQ_FOREACH_SAFE(listen_addr, &subsystem->listen_addrs, link, listen_addr_tmp) {
TAILQ_REMOVE(&subsystem->listen_addrs, listen_addr, link);
free(listen_addr->traddr);
free(listen_addr->trsvc);
free(listen_addr);
subsystem->num_listen_addrs--;
}
TAILQ_FOREACH_SAFE(host, &subsystem->hosts, link, host_tmp) {
TAILQ_REMOVE(&subsystem->hosts, host, link);
free(host->nqn);
free(host);
subsystem->num_hosts--;
}
if (subsystem->session) {
@ -140,6 +160,38 @@ nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem)
return 0;
}
int
spdk_nvmf_subsystem_add_listener(struct spdk_nvmf_subsystem *subsystem,
const struct spdk_nvmf_transport *transport,
char *traddr, char *trsvc)
{
struct spdk_nvmf_listen_addr *listen_addr;
listen_addr = calloc(1, sizeof(*listen_addr));
listen_addr->traddr = strdup(traddr);
listen_addr->trsvc = strdup(trsvc);
listen_addr->transport = transport;
TAILQ_INSERT_HEAD(&subsystem->listen_addrs, listen_addr, link);
subsystem->num_listen_addrs++;
return 0;
}
int
spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, char *host_nqn)
{
struct spdk_nvmf_host *host;
host = calloc(1, sizeof(*host));
host->nqn = strdup(host_nqn);
TAILQ_INSERT_HEAD(&subsystem->hosts, host, link);
subsystem->num_hosts++;
return 0;
}
int
nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem,
struct spdk_nvme_ctrlr *ctrlr)
@ -156,41 +208,6 @@ nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem,
return 0;
}
int
spdk_nvmf_subsystem_add_map(struct spdk_nvmf_subsystem *subsystem,
int port_tag, int host_tag)
{
struct spdk_nvmf_access_map *map;
struct spdk_nvmf_port *port;
struct spdk_nvmf_host *host;
port = spdk_nvmf_port_find_by_tag(port_tag);
if (port == NULL) {
SPDK_ERRLOG("%s: Port%d not found\n", subsystem->subnqn, port_tag);
return -1;
}
if (port->state != GROUP_READY) {
SPDK_ERRLOG("%s: Port%d not active\n", subsystem->subnqn, port_tag);
return -1;
}
host = spdk_nvmf_host_find_by_tag(host_tag);
if (host == NULL) {
SPDK_ERRLOG("%s: Host%d not found\n", subsystem->subnqn, host_tag);
return -1;
}
if (host->state != GROUP_READY) {
SPDK_ERRLOG("%s: Host%d not active\n", subsystem->subnqn, host_tag);
return -1;
}
host->ref++;
map = &subsystem->map[subsystem->map_count];
map->port = port;
map->host = host;
subsystem->map_count++;
return 0;
}
int
spdk_add_nvmf_discovery_subsystem(void)
{
@ -218,11 +235,9 @@ spdk_add_nvmf_discovery_subsystem(void)
void
spdk_format_discovery_log(struct spdk_nvmf_discovery_log_page *disc_log, uint32_t length)
{
int i, numrec = 0;
int numrec = 0;
struct spdk_nvmf_subsystem *subsystem;
struct spdk_nvmf_access_map *map;
struct spdk_nvmf_port *port;
struct spdk_nvmf_fabric_intf *fabric_intf;
struct spdk_nvmf_listen_addr *listen_addr;
struct spdk_nvmf_discovery_log_page_entry *entry;
TAILQ_FOREACH(subsystem, &g_subsystems, entries) {
@ -230,29 +245,22 @@ spdk_format_discovery_log(struct spdk_nvmf_discovery_log_page *disc_log, uint32_
continue;
}
for (i = 0; i < subsystem->map_count; i++) {
map = &subsystem->map[i];
port = map->port;
if (port != NULL) {
TAILQ_FOREACH(fabric_intf, &port->head, tailq) {
/* include the discovery log entry */
if (length > sizeof(struct spdk_nvmf_discovery_log_page)) {
if (sizeof(struct spdk_nvmf_discovery_log_page) + (numrec + 1) * sizeof(
struct spdk_nvmf_discovery_log_page_entry) > length) {
break;
}
entry = &disc_log->entries[numrec];
entry->portid = port->tag;
/* Dynamic controllers */
entry->cntlid = 0xffff;
entry->subtype = subsystem->subtype;
snprintf(entry->subnqn, 256, "%s", subsystem->subnqn);
fabric_intf->transport->fabric_intf_discover(fabric_intf, entry);
}
numrec++;
TAILQ_FOREACH(listen_addr, &subsystem->listen_addrs, link) {
/* include the discovery log entry */
if (length > sizeof(struct spdk_nvmf_discovery_log_page)) {
if (sizeof(struct spdk_nvmf_discovery_log_page) + (numrec + 1) * sizeof(
struct spdk_nvmf_discovery_log_page_entry) > length) {
break;
}
entry = &disc_log->entries[numrec];
entry->portid = subsystem->num;
entry->cntlid = 0xffff;
entry->subtype = subsystem->subtype;
snprintf(entry->subnqn, sizeof(entry->subnqn), "%s", subsystem->subnqn);
listen_addr->transport->listen_addr_discover(listen_addr, entry);
}
numrec++;
}
}

View File

@ -40,12 +40,18 @@
struct spdk_nvmf_conn;
#define MAX_PER_SUBSYSTEM_ACCESS_MAP 2
#define MAX_NQN_SIZE 255
struct spdk_nvmf_access_map {
struct spdk_nvmf_port *port;
struct spdk_nvmf_host *host;
struct spdk_nvmf_listen_addr {
char *traddr;
char *trsvc; /* TODO: Change to trsvcid */
const struct spdk_nvmf_transport *transport;
TAILQ_ENTRY(spdk_nvmf_listen_addr) link;
};
struct spdk_nvmf_host {
char *nqn;
TAILQ_ENTRY(spdk_nvmf_host) link;
};
/*
@ -63,8 +69,11 @@ struct spdk_nvmf_subsystem {
struct spdk_poller poller;
int map_count;
struct spdk_nvmf_access_map map[MAX_PER_SUBSYSTEM_ACCESS_MAP];
TAILQ_HEAD(, spdk_nvmf_listen_addr) listen_addrs;
uint32_t num_listen_addrs;
TAILQ_HEAD(, spdk_nvmf_host) hosts;
uint32_t num_hosts;
TAILQ_ENTRY(spdk_nvmf_subsystem) entries;
};
@ -78,16 +87,21 @@ int
nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem);
struct spdk_nvmf_subsystem *
nvmf_find_subsystem(const char *subnqn);
nvmf_find_subsystem(const char *subnqn, const char *hostnqn);
int
spdk_nvmf_subsystem_add_listener(struct spdk_nvmf_subsystem *subsystem,
const struct spdk_nvmf_transport *transport,
char *traddr, char *trsvc);
int
spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem,
char *host_nqn);
int
nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem,
struct spdk_nvme_ctrlr *ctrlr);
int
spdk_nvmf_subsystem_add_map(struct spdk_nvmf_subsystem *subsystem,
int port_tag, int host_tag);
int
spdk_shutdown_nvmf_subsystems(void);

View File

@ -36,7 +36,7 @@
struct spdk_nvmf_conn;
struct spdk_nvmf_discovery_log_page_entry;
struct spdk_nvmf_fabric_intf;
struct spdk_nvmf_listen_addr;
struct spdk_nvmf_request;
struct spdk_nvmf_transport {
@ -86,9 +86,9 @@ struct spdk_nvmf_transport {
int (*conn_poll)(struct spdk_nvmf_conn *conn);
/**
* Fill out a discovery log entry for a specific fabric interface.
* Fill out a discovery log entry for a specific listen address.
*/
void (*fabric_intf_discover)(struct spdk_nvmf_fabric_intf *fabric_intf,
void (*listen_addr_discover)(struct spdk_nvmf_listen_addr *listen_addr,
struct spdk_nvmf_discovery_log_page_entry *entry);
};

View File

@ -5,19 +5,12 @@
[Nvmf]
MaxConnectionsPerSession 4
[Port1]
Comment "Test1"
Listen RDMA 192.168.100.8:4420
[Host1]
Netmask 192.168.100.0/24
[Nvme]
ClaimAllDevices Yes
UnbindFromKernel Yes
[Subsystem1]
NQN "nqn.2016-06.io.spdk:cnode1"
Mapping Port1 Host1
Listen RDMA 192.168.100.8:4420
QueueDepth 128
Controller Nvme0