nvmf: allow configuration of ns NGUID and EUI64

Add optional parameters to namespace creation to let the user pick the
namespace globally unique identifier and EUI-64.

Change-Id: Ia3eebaf22f8a64733a00a83f90cafb4977c2d07a
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-on: https://review.gerrithub.io/399531
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
This commit is contained in:
Daniel Verkamp 2018-02-12 17:03:01 -07:00
parent 526cd58003
commit 1023ca7b46
11 changed files with 217 additions and 5 deletions

View File

@ -15,6 +15,11 @@ needed; previously, the response was limited to 32 kilobytes.
EXPERIMENTAL: Adds support for WDS and RDS capable CMBs in NVMe controllers. This support is
experimental pending a functional allocator to free and reallocate CMB buffers.
### NVMe-oF Target
Namespaces may now be assigned unique identifiers via new optional "eui64" and "nguid" parameters
to the `nvmf_subsystem_add_ns` RPC method.
## v18.01: Blobstore Thin Provisioning
### Build System

View File

@ -43,6 +43,143 @@
#include "nvmf_tgt.h"
static bool
all_zero(const void *data, size_t size)
{
const uint8_t *buf = data;
while (size--) {
if (*buf++ != 0) {
return false;
}
}
return true;
}
static int
json_write_hex_str(struct spdk_json_write_ctx *w, const void *data, size_t size)
{
static const char hex_char[16] = "0123456789ABCDEF";
const uint8_t *buf = data;
char *str, *out;
int rc;
str = malloc(size * 2 + 1);
if (str == NULL) {
return -1;
}
out = str;
while (size--) {
unsigned byte = *buf++;
out[0] = hex_char[(byte >> 4) & 0xF];
out[1] = hex_char[byte & 0xF];
out += 2;
}
*out = '\0';
rc = spdk_json_write_string(w, str);
free(str);
return rc;
}
static int
hex_nybble_to_num(char c)
{
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'a' && c <= 'f') {
return c - 'a' + 0xA;
}
if (c >= 'A' && c <= 'F') {
return c - 'A' + 0xA;
}
return -1;
}
static int
hex_byte_to_num(const char *str)
{
int hi, lo;
hi = hex_nybble_to_num(str[0]);
if (hi < 0) {
return hi;
}
lo = hex_nybble_to_num(str[1]);
if (lo < 0) {
return lo;
}
return hi * 16 + lo;
}
static int
decode_hex_string_be(const char *str, uint8_t *out, size_t size)
{
size_t i;
/* Decode a string in "ABCDEF012345" format to its binary representation */
for (i = 0; i < size; i++) {
int num = hex_byte_to_num(str);
if (num < 0) {
/* Invalid hex byte or end of string */
return -1;
}
out[i] = (uint8_t)num;
str += 2;
}
if (i != size || *str != '\0') {
/* Length mismatch */
return -1;
}
return 0;
}
static int
decode_ns_nguid(const struct spdk_json_val *val, void *out)
{
char *str = NULL;
int rc;
rc = spdk_json_decode_string(val, &str);
if (rc == 0) {
/* 16-byte NGUID */
rc = decode_hex_string_be(str, out, 16);
}
free(str);
return rc;
}
static int
decode_ns_eui64(const struct spdk_json_val *val, void *out)
{
char *str = NULL;
int rc;
rc = spdk_json_decode_string(val, &str);
if (rc == 0) {
/* 8-byte EUI-64 */
rc = decode_hex_string_be(str, out, 8);
}
free(str);
return rc;
}
static void
dump_nvmf_subsystem(struct spdk_json_write_ctx *w, struct spdk_nvmf_subsystem *subsystem)
{
@ -112,6 +249,7 @@ dump_nvmf_subsystem(struct spdk_json_write_ctx *w, struct spdk_nvmf_subsystem *s
if (spdk_nvmf_subsystem_get_type(subsystem) == SPDK_NVMF_SUBTYPE_NVME) {
struct spdk_nvmf_ns *ns;
struct spdk_nvmf_ns_opts ns_opts;
spdk_json_write_name(w, "serial_number");
spdk_json_write_string(w, spdk_nvmf_subsystem_get_sn(subsystem));
@ -119,6 +257,7 @@ dump_nvmf_subsystem(struct spdk_json_write_ctx *w, struct spdk_nvmf_subsystem *s
spdk_json_write_array_begin(w);
for (ns = spdk_nvmf_subsystem_get_first_ns(subsystem); ns != NULL;
ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns)) {
spdk_nvmf_ns_get_opts(ns, &ns_opts, sizeof(ns_opts));
spdk_json_write_object_begin(w);
spdk_json_write_name(w, "nsid");
spdk_json_write_int32(w, spdk_nvmf_ns_get_id(ns));
@ -127,6 +266,17 @@ dump_nvmf_subsystem(struct spdk_json_write_ctx *w, struct spdk_nvmf_subsystem *s
/* NOTE: "name" is kept for compatibility only - new code should use bdev_name. */
spdk_json_write_name(w, "name");
spdk_json_write_string(w, spdk_bdev_get_name(spdk_nvmf_ns_get_bdev(ns)));
if (!all_zero(ns_opts.nguid, sizeof(ns_opts.nguid))) {
spdk_json_write_name(w, "nguid");
json_write_hex_str(w, ns_opts.nguid, sizeof(ns_opts.nguid));
}
if (!all_zero(ns_opts.eui64, sizeof(ns_opts.eui64))) {
spdk_json_write_name(w, "eui64");
json_write_hex_str(w, ns_opts.eui64, sizeof(ns_opts.eui64));
}
spdk_json_write_object_end(w);
}
spdk_json_write_array_end(w);
@ -271,6 +421,8 @@ decode_rpc_hosts(const struct spdk_json_val *val, void *out)
struct spdk_nvmf_ns_params {
char *bdev_name;
uint32_t nsid;
char nguid[16];
char eui64[8];
};
struct rpc_namespaces {
@ -282,6 +434,8 @@ struct rpc_namespaces {
static const struct spdk_json_object_decoder rpc_ns_params_decoders[] = {
{"nsid", offsetof(struct spdk_nvmf_ns_params, nsid), spdk_json_decode_uint32, true},
{"bdev_name", offsetof(struct spdk_nvmf_ns_params, bdev_name), spdk_json_decode_string},
{"nguid", offsetof(struct spdk_nvmf_ns_params, nguid), decode_ns_nguid, true},
{"eui64", offsetof(struct spdk_nvmf_ns_params, eui64), decode_ns_eui64, true},
};
static void
@ -482,6 +636,12 @@ spdk_rpc_construct_nvmf_subsystem(struct spdk_jsonrpc_request *request,
spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
ns_opts.nsid = ns_params->nsid;
SPDK_STATIC_ASSERT(sizeof(ns_opts.nguid) == sizeof(ns_params->nguid), "size mismatch");
memcpy(ns_opts.nguid, ns_params->nguid, sizeof(ns_opts.nguid));
SPDK_STATIC_ASSERT(sizeof(ns_opts.eui64) == sizeof(ns_params->eui64), "size mismatch");
memcpy(ns_opts.eui64, ns_params->eui64, sizeof(ns_opts.eui64));
if (spdk_nvmf_subsystem_add_ns(subsystem, bdev, &ns_opts, sizeof(ns_opts)) == 0) {
SPDK_ERRLOG("Unable to add namespace\n");
spdk_nvmf_subsystem_destroy(subsystem);
@ -769,6 +929,12 @@ nvmf_rpc_ns_paused(struct spdk_nvmf_subsystem *subsystem,
spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
ns_opts.nsid = ctx->ns_params.nsid;
SPDK_STATIC_ASSERT(sizeof(ns_opts.nguid) == sizeof(ctx->ns_params.nguid), "size mismatch");
memcpy(ns_opts.nguid, ctx->ns_params.nguid, sizeof(ns_opts.nguid));
SPDK_STATIC_ASSERT(sizeof(ns_opts.eui64) == sizeof(ctx->ns_params.eui64), "size mismatch");
memcpy(ns_opts.eui64, ctx->ns_params.eui64, sizeof(ns_opts.eui64));
ctx->ns_params.nsid = spdk_nvmf_subsystem_add_ns(subsystem, bdev, &ns_opts, sizeof(ns_opts));
if (ctx->ns_params.nsid == 0) {
SPDK_ERRLOG("Unable to add namespace\n");

View File

@ -260,6 +260,8 @@ Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
nsid | Optional | number | Namespace ID between 1 and 4294967294, inclusive. Default: Automatically assign NSID.
bdev_name | Required | string | Name of bdev to expose as a namespace.
nguid | Optional | string | 16-byte namespace globally unique identifier in hexadecimal (e.g. "ABCDEF0123456789ABCDEF0123456789")
eui64 | Optional | string | 8-byte namespace EUI-64 in hexadecimal (e.g. "ABCDEF0123456789")
### Example

View File

@ -376,6 +376,20 @@ struct spdk_nvmf_ns_opts {
* Set to 0 to automatically assign a free NSID.
*/
uint32_t nsid;
/**
* Namespace Globally Unique Identifier
*
* Fill with 0s if not specified.
*/
uint8_t nguid[16];
/**
* IEEE Extended Unique Identifier
*
* Fill with 0s if not specified.
*/
uint8_t eui64[8];
};
/**

View File

@ -869,7 +869,7 @@ spdk_nvmf_ctrlr_identify_ns(struct spdk_nvmf_subsystem *subsystem,
return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
}
return spdk_nvmf_bdev_ctrlr_identify_ns(ns->bdev, nsdata);
return spdk_nvmf_bdev_ctrlr_identify_ns(ns, nsdata);
}
static int

View File

@ -103,8 +103,9 @@ nvmf_bdev_ctrlr_complete_cmd(struct spdk_bdev_io *bdev_io, bool success,
}
int
spdk_nvmf_bdev_ctrlr_identify_ns(struct spdk_bdev *bdev, struct spdk_nvme_ns_data *nsdata)
spdk_nvmf_bdev_ctrlr_identify_ns(struct spdk_nvmf_ns *ns, struct spdk_nvme_ns_data *nsdata)
{
struct spdk_bdev *bdev = ns->bdev;
uint64_t num_blocks;
num_blocks = spdk_bdev_get_num_blocks(bdev);
@ -117,6 +118,12 @@ spdk_nvmf_bdev_ctrlr_identify_ns(struct spdk_bdev *bdev, struct spdk_nvme_ns_dat
nsdata->lbaf[0].lbads = spdk_u32log2(spdk_bdev_get_block_size(bdev));
nsdata->noiob = spdk_bdev_get_optimal_io_boundary(bdev);
SPDK_STATIC_ASSERT(sizeof(nsdata->nguid) == sizeof(ns->opts.nguid), "size mismatch");
memcpy(nsdata->nguid, ns->opts.nguid, sizeof(nsdata->nguid));
SPDK_STATIC_ASSERT(sizeof(nsdata->eui64) == sizeof(ns->opts.eui64), "size mismatch");
memcpy(&nsdata->eui64, ns->opts.eui64, sizeof(nsdata->eui64));
return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
}

View File

@ -236,7 +236,7 @@ int spdk_nvmf_ctrlr_process_io_cmd(struct spdk_nvmf_request *req);
bool spdk_nvmf_ctrlr_dsm_supported(struct spdk_nvmf_ctrlr *ctrlr);
bool spdk_nvmf_ctrlr_write_zeroes_supported(struct spdk_nvmf_ctrlr *ctrlr);
int spdk_nvmf_bdev_ctrlr_identify_ns(struct spdk_bdev *bdev, struct spdk_nvme_ns_data *nsdata);
int spdk_nvmf_bdev_ctrlr_identify_ns(struct spdk_nvmf_ns *ns, struct spdk_nvme_ns_data *nsdata);
int spdk_nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem,
struct spdk_nvmf_ctrlr *ctrlr);

View File

@ -374,6 +374,8 @@ if __name__ == "__main__":
p.add_argument('nqn', help='NVMe-oF subsystem NQN')
p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
p.set_defaults(func=rpc.nvmf.nvmf_subsystem_add_ns)
# pmem

View File

@ -64,6 +64,12 @@ def nvmf_subsystem_add_ns(args):
if args.nsid:
ns['nsid'] = args.nsid
if args.nguid:
ns['nguid'] = args.nguid
if args.eui64:
ns['eui64'] = args.eui64
params = {'nqn': args.nqn,
'namespace': ns}

View File

@ -31,9 +31,19 @@ timing_exit start_nvmf_tgt
bdevs="$bdevs $($rpc_py construct_malloc_bdev $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE)"
$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 '' '' -a -s SPDK00000000000001 -n "$bdevs"
$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 '' '' -a -s SPDK00000000000001
$rpc_py nvmf_subsystem_add_listener nqn.2016-06.io.spdk:cnode1 -t RDMA -a $NVMF_FIRST_TARGET_IP -s 4420
for bdev in $bdevs; do
# NOTE: This will assign the same NGUID and EUI64 to all bdevs,
# but currently we only have one (see above), so this is OK.
$rpc_py nvmf_subsystem_add_ns nqn.2016-06.io.spdk:cnode1 "$bdev" \
--nguid "ABCDEF0123456789ABCDEF0123456789" \
--eui64 "ABCDEF0123456789"
done
$rpc_py get_nvmf_subsystems
$rootdir/examples/nvme/identify/identify -r "\
trtype:RDMA \
adrfam:IPv4 \

View File

@ -117,7 +117,7 @@ DEFINE_STUB(spdk_nvmf_ctrlr_write_zeroes_supported,
DEFINE_STUB(spdk_nvmf_bdev_ctrlr_identify_ns,
int,
(struct spdk_bdev *bdev, struct spdk_nvme_ns_data *nsdata),
(struct spdk_nvmf_ns *ns, struct spdk_nvme_ns_data *nsdata),
-1)
DEFINE_STUB_V(spdk_nvmf_get_discovery_log_page,