Commit 8acc4ae5 authored by Daniel Verkamp's avatar Daniel Verkamp Committed by Jim Harris
Browse files

nvme: add controller option to specify host ID



A random host ID is generated per SPDK application startup if the user
doesn't specify a host ID during controller startup.

This also changes the default host NQN for NVMe-oF connections to a
random UUID NQN based on the host ID.

Change-Id: Ib0f70dd63e53087716842b412a1f134a9991d4da
Signed-off-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
Reviewed-on: https://review.gerrithub.io/380528


Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
parent 04124278
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -43,6 +43,12 @@ The HotplugEnable option in `[Nvme]` sections of the configuration file is now
The NVMe library now includes a function spdk_nvme_ns_get_ctrlr which returns the
NVMe Controller associated with a given namespace.

The NVMe library now allows the user to specify a host identifier when attaching
to a controller.  The host identifier is used as part of the Reservations feature,
as well as in the NVMe-oF Connect command.  The default host ID is also now a
randomly-generated UUID, and the default host NQN uses the host ID to generate
a UUID-based NQN.

### NVMe-oF Target (nvmf_tgt)

The NVMe-oF target no longer requires any in capsule data buffers to run, and
+36 −89
Original line number Diff line number Diff line
@@ -33,8 +33,10 @@

#include "spdk/stdinc.h"

#include "spdk/endian.h"
#include "spdk/nvme.h"
#include "spdk/env.h"
#include "spdk/log.h"

#define MAX_DEVS 64

@@ -52,44 +54,22 @@ static int num_devs = 0;

static int outstanding_commands;
static int reserve_command_result;
static int set_feature_result;

struct feature {
	uint32_t result;
	bool valid;
};

static struct feature features[256];
static bool get_host_id_successful;

#define HOST_ID		0xABABABABCDCDCDCD
#define EXT_HOST_ID	((uint8_t[]){0x0f, 0x97, 0xcd, 0x74, 0x8c, 0x80, 0x41, 0x42, \
				     0x99, 0x0f, 0x65, 0xc4, 0xf0, 0x39, 0x24, 0x20})

#define CR_KEY		0xDEADBEAF5A5A5A5B

static void
get_feature_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
{
	struct feature *feature = cb_arg;
	int fid = feature - features;

	if (spdk_nvme_cpl_is_error(cpl)) {
		fprintf(stdout, "get_feature(0x%02X) failed\n", fid);
		fprintf(stdout, "Get Features - Host Identifier failed\n");
		get_host_id_successful = false;
	} else {
		feature->result = cpl->cdw0;
		feature->valid = true;
	}
	outstanding_commands--;
}

static void
set_feature_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
{
	struct feature *feature = cb_arg;
	int fid = feature - features;

	if (spdk_nvme_cpl_is_error(cpl)) {
		fprintf(stdout, "set_feature(0x%02X) failed\n", fid);
		set_feature_result = -1;
	} else {
		set_feature_result = 0;
		get_host_id_successful = true;
	}
	outstanding_commands--;
}
@@ -98,81 +78,40 @@ static int
get_host_identifier(struct spdk_nvme_ctrlr *ctrlr)
{
	int ret;
	uint64_t *host_id;
	struct spdk_nvme_cmd cmd = {};

	cmd.opc = SPDK_NVME_OPC_GET_FEATURES;
	cmd.cdw10 = SPDK_NVME_FEAT_HOST_IDENTIFIER;

	host_id = spdk_dma_zmalloc(sizeof(*host_id), 0x1000, NULL);
	if (!host_id) {
		fprintf(stderr, "Host_ID DMA Buffer Allocation Failed\n");
		return -1;
	uint8_t host_id[16];
	uint32_t host_id_size;
	uint32_t cdw11;

	if (spdk_nvme_ctrlr_get_data(ctrlr)->ctratt.host_id_exhid_supported) {
		host_id_size = 16;
		cdw11 = 1;
		printf("Using 128-bit extended host identifier\n");
	} else {
		host_id_size = 8;
		cdw11 = 0;
		printf("Using 64-bit host identifier\n");
	}

	outstanding_commands = 0;
	ret = spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, &cmd, host_id, sizeof(*host_id),
					    get_feature_completion, &features[SPDK_NVME_FEAT_HOST_IDENTIFIER]);
	ret = spdk_nvme_ctrlr_cmd_get_feature(ctrlr, SPDK_NVME_FEAT_HOST_IDENTIFIER, cdw11, host_id,
					      host_id_size,
					      get_feature_completion, NULL);
	if (ret) {
		fprintf(stdout, "Get Feature: Failed\n");
		spdk_dma_free(host_id);
		return -1;
	}

	outstanding_commands++;
	get_host_id_successful = false;

	while (outstanding_commands) {
		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
	}

	if (features[SPDK_NVME_FEAT_HOST_IDENTIFIER].valid) {
		fprintf(stdout, "Get Feature: Host Identifier 0x%" PRIx64 "\n", *host_id);
	}

	spdk_dma_free(host_id);
	return 0;
}

static int
set_host_identifier(struct spdk_nvme_ctrlr *ctrlr)
{
	int ret;
	uint64_t *host_id;
	struct spdk_nvme_cmd cmd = {};

	cmd.opc = SPDK_NVME_OPC_SET_FEATURES;
	cmd.cdw10 = SPDK_NVME_FEAT_HOST_IDENTIFIER;

	host_id = spdk_dma_zmalloc(sizeof(*host_id), 0x1000, NULL);
	if (!host_id) {
		fprintf(stderr, "Host_ID DMA Buffer Allocation Failed\n");
		return -1;
	if (get_host_id_successful) {
		spdk_trace_dump(stdout, "Get Feature: Host Identifier:", host_id, host_id_size);
	}

	*host_id = HOST_ID;

	outstanding_commands = 0;
	set_feature_result = -1;

	fprintf(stdout, "Set Feature: Host Identifier 0x%" PRIx64 "\n", *host_id);
	ret = spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, &cmd, host_id, sizeof(*host_id),
					    set_feature_completion, &features[SPDK_NVME_FEAT_HOST_IDENTIFIER]);
	if (ret) {
		fprintf(stdout, "Set Feature: Failed\n");
		spdk_dma_free(host_id);
		return -1;
	}

	outstanding_commands++;

	while (outstanding_commands) {
		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
	}

	if (set_feature_result)
		fprintf(stdout, "Set Feature: Host Identifier Failed\n");

	spdk_dma_free(host_id);
	return 0;
}

@@ -369,7 +308,6 @@ reserve_controller(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair,
	if (!cdata->oncs.reservations)
		return;

	set_host_identifier(ctrlr);
	get_host_identifier(ctrlr);

	/* tested 1 namespace */
@@ -383,6 +321,15 @@ static bool
probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
	 struct spdk_nvme_ctrlr_opts *opts)
{
	/*
	 * Provide both 64-bit and 128-bit host identifiers.
	 *
	 * The NVMe library will choose which one to use based on whether the controller
	 * supports extended host identifiers.
	 */
	to_le64(opts->host_id, HOST_ID);
	memcpy(opts->extended_host_id, EXT_HOST_ID, sizeof(opts->extended_host_id));

	return true;
}

+14 −0
Original line number Diff line number Diff line
@@ -130,6 +130,20 @@ struct spdk_nvme_ctrlr_opts {
	 * specified.
	 */
	char src_svcid[SPDK_NVMF_TRSVCID_MAX_LEN + 1];

	/**
	 * The host identifier to use when connecting to controllers with 64-bit host ID support.
	 *
	 * Set to all zeroes to specify that no host ID should be provided to the controller.
	 */
	uint8_t host_id[8];

	/**
	 * The host identifier to use when connecting to controllers with extended (128-bit) host ID support.
	 *
	 * Set to all zeroes to specify that no host ID should be provided to the controller.
	 */
	uint8_t extended_host_id[16];
};

/**
+8 −0
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@
#include "spdk/nvmf_spec.h"
#include "nvme_internal.h"

#include <uuid/uuid.h>

#define SPDK_NVME_DRIVER_NAME "spdk_nvme_driver"

struct nvme_driver	*g_spdk_nvme_driver;
@@ -227,6 +229,7 @@ nvme_robust_mutex_init_shared(pthread_mutex_t *mtx)
static int
nvme_driver_init(void)
{
	uuid_t host_id;
	int ret = 0;
	/* Any socket ID */
	int socket_id = -1;
@@ -300,6 +303,11 @@ nvme_driver_init(void)
	TAILQ_INIT(&g_spdk_nvme_driver->init_ctrlrs);
	TAILQ_INIT(&g_spdk_nvme_driver->attached_ctrlrs);

	SPDK_STATIC_ASSERT(sizeof(host_id) == sizeof(g_spdk_nvme_driver->default_extended_host_id),
			   "host ID size mismatch");
	uuid_generate(host_id);
	memcpy(g_spdk_nvme_driver->default_extended_host_id, host_id, sizeof(host_id));

	nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);

	return ret;
+83 −1
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@

#include "spdk/env.h"

#include <uuid/uuid.h>

static int nvme_ctrlr_construct_and_submit_aer(struct spdk_nvme_ctrlr *ctrlr,
		struct nvme_async_event_request *aer);

@@ -78,15 +80,21 @@ nvme_ctrlr_set_cc(struct spdk_nvme_ctrlr *ctrlr, const union spdk_nvme_cc_regist
void
spdk_nvme_ctrlr_opts_set_defaults(struct spdk_nvme_ctrlr_opts *opts)
{
	char host_id_str[37];

	opts->num_io_queues = DEFAULT_MAX_IO_QUEUES;
	opts->use_cmb_sqs = true;
	opts->arb_mechanism = SPDK_NVME_CC_AMS_RR;
	opts->keep_alive_timeout_ms = 10 * 1000;
	opts->io_queue_size = DEFAULT_IO_QUEUE_SIZE;
	strncpy(opts->hostnqn, DEFAULT_HOSTNQN, sizeof(opts->hostnqn));
	opts->io_queue_requests = DEFAULT_IO_QUEUE_REQUESTS;
	memset(opts->src_addr, 0, sizeof(opts->src_addr));
	memset(opts->src_svcid, 0, sizeof(opts->src_svcid));
	memset(opts->host_id, 0, sizeof(opts->host_id));
	memcpy(opts->extended_host_id, g_spdk_nvme_driver->default_extended_host_id,
	       sizeof(opts->extended_host_id));
	uuid_unparse(opts->extended_host_id, host_id_str);
	snprintf(opts->hostnqn, sizeof(opts->hostnqn), "2014-08.org.nvmexpress:uuid:%s", host_id_str);
}

/**
@@ -808,6 +816,76 @@ nvme_ctrlr_set_keep_alive_timeout(struct spdk_nvme_ctrlr *ctrlr)
	return 0;
}

static int
nvme_ctrlr_set_host_id(struct spdk_nvme_ctrlr *ctrlr)
{
	struct nvme_completion_poll_status status;
	bool all_zeroes;
	uint8_t *host_id;
	uint32_t host_id_size;
	uint32_t i;
	int rc;

	if (ctrlr->trid.trtype != SPDK_NVME_TRANSPORT_PCIE) {
		/*
		 * NVMe-oF sends the host ID during Connect and doesn't allow
		 * Set Features - Host Identifier after Connect, so we don't need to do anything here.
		 */
		SPDK_DEBUGLOG(SPDK_TRACE_NVME, "NVMe-oF transport - not sending Set Features - Host ID\n");
		return 0;
	}

	if (ctrlr->cdata.ctratt.host_id_exhid_supported) {
		SPDK_DEBUGLOG(SPDK_TRACE_NVME, "Using 128-bit extended host identifier\n");
		host_id = ctrlr->opts.extended_host_id;
		host_id_size = sizeof(ctrlr->opts.extended_host_id);
	} else {
		SPDK_DEBUGLOG(SPDK_TRACE_NVME, "Using 64-bit host identifier\n");
		host_id = ctrlr->opts.host_id;
		host_id_size = sizeof(ctrlr->opts.host_id);
	}

	/* If the user specified an all-zeroes host identifier, don't send the command. */
	all_zeroes = true;
	for (i = 0; i < host_id_size; i++) {
		if (host_id[i] != 0) {
			all_zeroes = false;
			break;
		}
	}

	if (all_zeroes) {
		SPDK_DEBUGLOG(SPDK_TRACE_NVME,
			      "User did not specify host ID - not sending Set Features - Host ID\n");
		return 0;
	}

	SPDK_TRACEDUMP(SPDK_TRACE_NVME, "host_id", host_id, host_id_size);

	status.done = false;
	rc = nvme_ctrlr_cmd_set_host_id(ctrlr, host_id, host_id_size, nvme_completion_poll_cb, &status);
	if (rc != 0) {
		SPDK_ERRLOG("Set Features - Host ID failed: %d\n", rc);
		return rc;
	}

	while (status.done == false) {
		spdk_nvme_qpair_process_completions(ctrlr->adminq, 0);
	}
	if (spdk_nvme_cpl_is_error(&status.cpl)) {
		SPDK_WARNLOG("Set Features - Host ID failed: SC 0x%x SCT 0x%x\n",
			     status.cpl.status.sc, status.cpl.status.sct);
		/*
		 * Treat Set Features - Host ID failure as non-fatal, since the Host ID feature
		 * is optional.
		 */
		return 0;
	}

	SPDK_DEBUGLOG(SPDK_TRACE_NVME, "Set Features - Host ID was successful\n");
	return 0;
}

static void
nvme_ctrlr_destruct_namespaces(struct spdk_nvme_ctrlr *ctrlr)
{
@@ -1394,6 +1472,10 @@ nvme_ctrlr_start(struct spdk_nvme_ctrlr *ctrlr)
		return -1;
	}

	if (nvme_ctrlr_set_host_id(ctrlr) != 0) {
		return -1;
	}

	return 0;
}

Loading