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:
parent
526cd58003
commit
1023ca7b46
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
||||
|
@ -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];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user