nvmf: Place deprecated RPCs in a separate file

This is code movement only. The deprecated RPCs are
actually quite complicated and are making the RPC
file much larger than it needed to be. Move the old
code to a separate file until it is eventually removed.

Change-Id: I7c9bcdb0faa8496ef611d787dcc9a35c82dcc61a
Signed-off-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-on: https://review.gerrithub.io/425178
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
This commit is contained in:
Ben Walker 2018-09-10 11:03:46 -07:00 committed by Jim Harris
parent aedac1a878
commit b67d175529
4 changed files with 771 additions and 542 deletions

View File

@ -2941,84 +2941,6 @@ Example response:
}
~~~
## construct_nvmf_subsystem method {#rpc_construct_nvmf_subsystem}
Construct an NVMe over Fabrics target subsystem.
### Parameters
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
nqn | Required | string | Subsystem NQN
listen_addresses | Optional | array | Array of @ref rpc_construct_nvmf_subsystem_listen_address objects
hosts | Optional | array | Array of strings containing allowed host NQNs. Default: No hosts allowed.
allow_any_host | Optional | boolean | Allow any host (`true`) or enforce allowed host whitelist (`false`). Default: `false`.
serial_number | Required | string | Serial number of virtual controller
namespaces | Optional | array | Array of @ref rpc_construct_nvmf_subsystem_namespace objects. Default: No namespaces.
max_namespaces | Optional | number | Maximum number of namespaces that can be attached to the subsystem. Default: 0 (Unlimited)
### listen_address {#rpc_construct_nvmf_subsystem_listen_address}
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
trtype | Required | string | Transport type ("RDMA")
adrfam | Required | string | Address family ("IPv4", "IPv6", "IB", or "FC")
traddr | Required | string | Transport address
trsvcid | Required | string | Transport service ID
### namespace {#rpc_construct_nvmf_subsystem_namespace}
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")
uuid | Optional | string | RFC 4122 UUID (e.g. "ceccf520-691e-4b46-9546-34af789907c5")
### Example
Example request:
~~~
{
"jsonrpc": "2.0",
"id": 1,
"method": "construct_nvmf_subsystem",
"params": {
"nqn": "nqn.2016-06.io.spdk:cnode1",
"listen_addresses": [
{
"trtype": "RDMA",
"adrfam": "IPv4",
"traddr": "192.168.0.123",
"trsvcid: "4420"
}
],
"hosts": [
"nqn.2016-06.io.spdk:host1",
"nqn.2016-06.io.spdk:host2"
],
"allow_any_host": false,
"serial_number": "abcdef",
"namespaces": [
{"nsid": 1, "bdev_name": "Malloc2"},
{"nsid": 2, "bdev_name": "Nvme0n1"}
]
}
}
~~~
Example response:
~~~
{
"jsonrpc": "2.0",
"id": 1,
"result": true
}
~~~
## nvmf_subsystem_create method {#rpc_nvmf_subsystem_create}
Construct an NVMe over Fabrics target subsystem.
@ -3103,7 +3025,16 @@ Add a new listen address to an NVMe-oF subsystem.
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
nqn | Required | string | Subsystem NQN
listen_address | Required | object | @ref rpc_construct_nvmf_subsystem_listen_address object
listen_address | Required | object | @ref rpc_nvmf_listen_address object
### listen_address {#rpc_nvmf_listen_address}
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
trtype | Required | string | Transport type ("RDMA")
adrfam | Required | string | Address family ("IPv4", "IPv6", "IB", or "FC")
traddr | Required | string | Transport address
trsvcid | Required | string | Transport service ID
### Example
@ -3145,7 +3076,17 @@ Add a namespace to a subsystem. The namespace ID is returned as the result.
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
nqn | Required | string | Subsystem NQN
namespace | Required | object | @ref rpc_construct_nvmf_subsystem_namespace object
namespace | Required | object | @ref rpc_nvmf_namespace object
### namespace {#rpc_nvmf_namespace}
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")
uuid | Optional | string | RFC 4122 UUID (e.g. "ceccf520-691e-4b46-9546-34af789907c5")
### Example

View File

@ -34,7 +34,7 @@
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
C_SRCS = conf.c nvmf_rpc.c nvmf_tgt.c
C_SRCS = conf.c nvmf_rpc.c nvmf_rpc_deprecated.c nvmf_tgt.c
LIBNAME = event_nvmf
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk

View File

@ -329,249 +329,19 @@ spdk_rpc_get_nvmf_subsystems(struct spdk_jsonrpc_request *request,
}
SPDK_RPC_REGISTER("get_nvmf_subsystems", spdk_rpc_get_nvmf_subsystems, SPDK_RPC_RUNTIME)
struct rpc_listen_address {
char *transport;
char *adrfam;
char *traddr;
char *trsvcid;
};
#define RPC_MAX_LISTEN_ADDRESSES 255
#define RPC_MAX_HOSTS 255
#define RPC_MAX_NAMESPACES 255
struct rpc_listen_addresses {
size_t num_listen_address;
struct rpc_listen_address addresses[RPC_MAX_LISTEN_ADDRESSES];
};
static const struct spdk_json_object_decoder rpc_listen_address_decoders[] = {
/* NOTE: "transport" is kept for compatibility; new code should use "trtype" */
{"transport", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true},
{"trtype", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true},
{"adrfam", offsetof(struct rpc_listen_address, adrfam), spdk_json_decode_string, true},
{"traddr", offsetof(struct rpc_listen_address, traddr), spdk_json_decode_string},
{"trsvcid", offsetof(struct rpc_listen_address, trsvcid), spdk_json_decode_string},
};
static int
decode_rpc_listen_address(const struct spdk_json_val *val, void *out)
{
struct rpc_listen_address *req = (struct rpc_listen_address *)out;
if (spdk_json_decode_object(val, rpc_listen_address_decoders,
SPDK_COUNTOF(rpc_listen_address_decoders),
req)) {
SPDK_ERRLOG("spdk_json_decode_object failed\n");
return -1;
}
return 0;
}
static void
free_rpc_listen_address(struct rpc_listen_address *r)
{
free(r->transport);
free(r->adrfam);
free(r->traddr);
free(r->trsvcid);
}
static int
rpc_listen_address_to_trid(const struct rpc_listen_address *address,
struct spdk_nvme_transport_id *trid)
{
size_t len;
memset(trid, 0, sizeof(*trid));
if (spdk_nvme_transport_id_parse_trtype(&trid->trtype, address->transport)) {
SPDK_ERRLOG("Invalid transport type: %s\n", address->transport);
return -EINVAL;
}
if (address->adrfam) {
if (spdk_nvme_transport_id_parse_adrfam(&trid->adrfam, address->adrfam)) {
SPDK_ERRLOG("Invalid adrfam: %s\n", address->adrfam);
return -EINVAL;
}
} else {
trid->adrfam = SPDK_NVMF_ADRFAM_IPV4;
}
len = strlen(address->traddr);
if (len > sizeof(trid->traddr) - 1) {
SPDK_ERRLOG("Transport address longer than %zu characters: %s\n",
sizeof(trid->traddr) - 1, address->traddr);
return -EINVAL;
}
memcpy(trid->traddr, address->traddr, len + 1);
len = strlen(address->trsvcid);
if (len > sizeof(trid->trsvcid) - 1) {
SPDK_ERRLOG("Transport service id longer than %zu characters: %s\n",
sizeof(trid->trsvcid) - 1, address->trsvcid);
return -EINVAL;
}
memcpy(trid->trsvcid, address->trsvcid, len + 1);
return 0;
}
static int
decode_rpc_listen_addresses(const struct spdk_json_val *val, void *out)
{
struct rpc_listen_addresses *listen_addresses = out;
return spdk_json_decode_array(val, decode_rpc_listen_address, &listen_addresses->addresses,
RPC_MAX_LISTEN_ADDRESSES,
&listen_addresses->num_listen_address, sizeof(struct rpc_listen_address));
}
struct rpc_hosts {
size_t num_hosts;
char *hosts[RPC_MAX_HOSTS];
};
static int
decode_rpc_hosts(const struct spdk_json_val *val, void *out)
{
struct rpc_hosts *rpc_hosts = out;
return spdk_json_decode_array(val, spdk_json_decode_string, rpc_hosts->hosts, RPC_MAX_HOSTS,
&rpc_hosts->num_hosts, sizeof(char *));
}
struct spdk_nvmf_ns_params {
char *bdev_name;
uint32_t nsid;
char nguid[16];
char eui64[8];
struct spdk_uuid uuid;
};
struct rpc_namespaces {
size_t num_ns;
struct spdk_nvmf_ns_params ns_params[RPC_MAX_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},
{"uuid", offsetof(struct spdk_nvmf_ns_params, uuid), decode_ns_uuid, true},
};
static void
free_rpc_ns_params(struct spdk_nvmf_ns_params *ns_params)
{
free(ns_params->bdev_name);
}
static void
free_rpc_namespaces(struct rpc_namespaces *r)
{
size_t i;
for (i = 0; i < r->num_ns; i++) {
free_rpc_ns_params(&r->ns_params[i]);
}
}
static int
decode_rpc_ns_params(const struct spdk_json_val *val, void *out)
{
struct spdk_nvmf_ns_params *ns_params = out;
return spdk_json_decode_object(val, rpc_ns_params_decoders,
SPDK_COUNTOF(rpc_ns_params_decoders),
ns_params);
}
static int
decode_rpc_namespaces(const struct spdk_json_val *val, void *out)
{
struct rpc_namespaces *namespaces = out;
char *names[RPC_MAX_NAMESPACES] = {0}; /* old format - array of strings (bdev names) */
size_t i;
int rc;
/* First try to decode namespaces as an array of objects (new format) */
if (spdk_json_decode_array(val, decode_rpc_ns_params, namespaces->ns_params,
SPDK_COUNTOF(namespaces->ns_params),
&namespaces->num_ns, sizeof(*namespaces->ns_params)) == 0) {
return 0;
}
/* If that fails, try to decode namespaces as an array of strings (old format) */
free_rpc_namespaces(namespaces);
memset(namespaces, 0, sizeof(*namespaces));
rc = spdk_json_decode_array(val, spdk_json_decode_string, names,
SPDK_COUNTOF(names),
&namespaces->num_ns, sizeof(char *));
if (rc == 0) {
/* Decoded old format - copy to ns_params (new format) */
for (i = 0; i < namespaces->num_ns; i++) {
namespaces->ns_params[i].bdev_name = names[i];
}
return 0;
}
/* Failed to decode - don't leave dangling string pointers around */
for (i = 0; i < namespaces->num_ns; i++) {
free(names[i]);
}
return rc;
}
static void
free_rpc_listen_addresses(struct rpc_listen_addresses *r)
{
size_t i;
for (i = 0; i < r->num_listen_address; i++) {
free_rpc_listen_address(&r->addresses[i]);
}
}
static void
free_rpc_hosts(struct rpc_hosts *r)
{
size_t i;
for (i = 0; i < r->num_hosts; i++) {
free(r->hosts[i]);
}
}
struct rpc_subsystem {
int32_t core;
char *mode;
struct rpc_subsystem_create {
char *nqn;
struct rpc_listen_addresses listen_addresses;
struct rpc_hosts hosts;
bool allow_any_host;
char *pci_address;
char *serial_number;
struct rpc_namespaces namespaces;
uint32_t num_ns;
uint32_t max_namespaces;
bool allow_any_host;
};
static void
free_rpc_subsystem(struct rpc_subsystem *req)
{
if (req) {
free(req->mode);
free(req->nqn);
free(req->serial_number);
free_rpc_namespaces(&req->namespaces);
free_rpc_listen_addresses(&req->listen_addresses);
free_rpc_hosts(&req->hosts);
}
free(req);
}
static const struct spdk_json_object_decoder rpc_subsystem_create_decoders[] = {
{"nqn", offsetof(struct rpc_subsystem_create, nqn), spdk_json_decode_string},
{"serial_number", offsetof(struct rpc_subsystem_create, serial_number), spdk_json_decode_string, true},
{"max_namespaces", offsetof(struct rpc_subsystem_create, max_namespaces), spdk_json_decode_uint32, true},
{"allow_any_host", offsetof(struct rpc_subsystem_create, allow_any_host), spdk_json_decode_bool, true},
};
static void
spdk_rpc_nvmf_subsystem_started(struct spdk_nvmf_subsystem *subsystem,
@ -589,226 +359,6 @@ spdk_rpc_nvmf_subsystem_started(struct spdk_nvmf_subsystem *subsystem,
spdk_jsonrpc_end_result(request, w);
}
static const struct spdk_json_object_decoder rpc_subsystem_decoders[] = {
{"core", offsetof(struct rpc_subsystem, core), spdk_json_decode_int32, true},
{"mode", offsetof(struct rpc_subsystem, mode), spdk_json_decode_string, true},
{"nqn", offsetof(struct rpc_subsystem, nqn), spdk_json_decode_string},
{"listen_addresses", offsetof(struct rpc_subsystem, listen_addresses), decode_rpc_listen_addresses, true},
{"hosts", offsetof(struct rpc_subsystem, hosts), decode_rpc_hosts, true},
{"allow_any_host", offsetof(struct rpc_subsystem, allow_any_host), spdk_json_decode_bool, true},
{"serial_number", offsetof(struct rpc_subsystem, serial_number), spdk_json_decode_string, true},
{"namespaces", offsetof(struct rpc_subsystem, namespaces), decode_rpc_namespaces, true},
{"max_namespaces", offsetof(struct rpc_subsystem, num_ns), spdk_json_decode_uint32, true},
};
struct subsystem_listen_ctx {
struct rpc_subsystem *req;
struct spdk_nvmf_subsystem *subsystem;
struct spdk_jsonrpc_request *request;
uint32_t idx;
};
static void
spdk_rpc_construct_subsystem_listen_done(void *cb_arg, int status)
{
struct subsystem_listen_ctx *ctx = cb_arg;
struct rpc_listen_address *addr;
struct spdk_nvme_transport_id trid = {0};
if (status) {
goto invalid;
}
addr = &ctx->req->listen_addresses.addresses[ctx->idx];
if (rpc_listen_address_to_trid(addr, &trid)) {
goto invalid;
}
spdk_nvmf_subsystem_add_listener(ctx->subsystem, &trid);
ctx->idx++;
if (ctx->idx < ctx->req->listen_addresses.num_listen_address) {
addr = &ctx->req->listen_addresses.addresses[ctx->idx];
if (rpc_listen_address_to_trid(addr, &trid)) {
goto invalid;
}
spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt, &trid, spdk_rpc_construct_subsystem_listen_done, ctx);
return;
}
spdk_nvmf_subsystem_start(ctx->subsystem,
spdk_rpc_nvmf_subsystem_started,
ctx->request);
free_rpc_subsystem(ctx->req);
free(ctx);
return;
invalid:
spdk_nvmf_subsystem_destroy(ctx->subsystem);
spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
"Invalid parameters");
free_rpc_subsystem(ctx->req);
free(ctx);
}
static void
spdk_rpc_construct_nvmf_subsystem(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_subsystem *req;
struct spdk_nvmf_subsystem *subsystem;
size_t i;
req = calloc(1, sizeof(*req));
if (!req) {
goto invalid;
}
req->core = -1; /* Explicitly set the core as the uninitialized value */
if (spdk_json_decode_object(params, rpc_subsystem_decoders,
SPDK_COUNTOF(rpc_subsystem_decoders),
req)) {
SPDK_ERRLOG("spdk_json_decode_object failed\n");
goto invalid;
}
/* Mode is no longer a valid parameter, but print out a nice
* message if it exists to inform users.
*/
if (req->mode) {
SPDK_NOTICELOG("Mode present in the construct NVMe-oF subsystem RPC.\n"
"Mode was removed as a valid parameter.\n");
if (strcasecmp(req->mode, "Virtual") == 0) {
SPDK_NOTICELOG("Your mode value is 'Virtual' which is now the only possible mode.\n"
"Your RPC will work as expected.\n");
} else {
SPDK_NOTICELOG("Please remove 'mode' from the RPC.\n");
goto invalid;
}
}
/* Core is no longer a valid parameter, but print out a nice
* message if it exists to inform users.
*/
if (req->core != -1) {
SPDK_NOTICELOG("Core present in the construct NVMe-oF subsystem RPC.\n"
"Core was removed as an option. Subsystems can now run on all available cores.\n");
SPDK_NOTICELOG("Ignoring it and continuing.\n");
}
subsystem = spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt, req->nqn, SPDK_NVMF_SUBTYPE_NVME,
req->num_ns);
if (!subsystem) {
goto invalid;
}
if (spdk_nvmf_subsystem_set_sn(subsystem, req->serial_number)) {
SPDK_ERRLOG("Subsystem %s: invalid serial number '%s'\n", req->nqn, req->serial_number);
goto invalid;
}
for (i = 0; i < req->hosts.num_hosts; i++) {
spdk_nvmf_subsystem_add_host(subsystem, req->hosts.hosts[i]);
}
spdk_nvmf_subsystem_set_allow_any_host(subsystem, req->allow_any_host);
for (i = 0; i < req->namespaces.num_ns; i++) {
struct spdk_nvmf_ns_params *ns_params = &req->namespaces.ns_params[i];
struct spdk_bdev *bdev;
struct spdk_nvmf_ns_opts ns_opts;
bdev = spdk_bdev_get_by_name(ns_params->bdev_name);
if (bdev == NULL) {
SPDK_ERRLOG("Could not find namespace bdev '%s'\n", ns_params->bdev_name);
spdk_nvmf_subsystem_destroy(subsystem);
goto invalid;
}
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_mem_all_zero(&ns_params->uuid, sizeof(ns_params->uuid))) {
ns_opts.uuid = ns_params->uuid;
}
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);
goto invalid;
}
}
if (req->listen_addresses.num_listen_address > 0) {
struct rpc_listen_address *addr;
struct spdk_nvme_transport_id trid = {0};
struct subsystem_listen_ctx *ctx;
ctx = calloc(1, sizeof(*ctx));
if (!ctx) {
spdk_nvmf_subsystem_destroy(subsystem);
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "No Memory");
free_rpc_subsystem(req);
return;
}
ctx->req = req;
ctx->subsystem = subsystem;
ctx->request = request;
ctx->idx = 0;
addr = &req->listen_addresses.addresses[0];
if (rpc_listen_address_to_trid(addr, &trid)) {
free(ctx);
goto invalid;
}
spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt, &trid, spdk_rpc_construct_subsystem_listen_done, ctx);
return;
}
free_rpc_subsystem(req);
spdk_nvmf_subsystem_start(subsystem,
spdk_rpc_nvmf_subsystem_started,
request);
return;
invalid:
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
free_rpc_subsystem(req);
}
SPDK_RPC_REGISTER("construct_nvmf_subsystem", spdk_rpc_construct_nvmf_subsystem, SPDK_RPC_RUNTIME)
struct rpc_subsystem_create {
char *nqn;
char *serial_number;
uint32_t max_namespaces;
bool allow_any_host;
};
static const struct spdk_json_object_decoder rpc_subsystem_create_decoders[] = {
{"nqn", offsetof(struct rpc_subsystem_create, nqn), spdk_json_decode_string},
{"serial_number", offsetof(struct rpc_subsystem_create, serial_number), spdk_json_decode_string, true},
{"max_namespaces", offsetof(struct rpc_subsystem_create, max_namespaces), spdk_json_decode_uint32, true},
{"allow_any_host", offsetof(struct rpc_subsystem_create, allow_any_host), spdk_json_decode_bool, true},
};
static void
spdk_rpc_nvmf_subsystem_create(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
@ -933,6 +483,52 @@ invalid:
}
SPDK_RPC_REGISTER("delete_nvmf_subsystem", spdk_rpc_delete_nvmf_subsystem, SPDK_RPC_RUNTIME)
struct rpc_listen_address {
char *transport;
char *adrfam;
char *traddr;
char *trsvcid;
};
#define RPC_MAX_LISTEN_ADDRESSES 255
#define RPC_MAX_NAMESPACES 255
struct rpc_listen_addresses {
size_t num_listen_address;
struct rpc_listen_address addresses[RPC_MAX_LISTEN_ADDRESSES];
};
static const struct spdk_json_object_decoder rpc_listen_address_decoders[] = {
/* NOTE: "transport" is kept for compatibility; new code should use "trtype" */
{"transport", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true},
{"trtype", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true},
{"adrfam", offsetof(struct rpc_listen_address, adrfam), spdk_json_decode_string, true},
{"traddr", offsetof(struct rpc_listen_address, traddr), spdk_json_decode_string},
{"trsvcid", offsetof(struct rpc_listen_address, trsvcid), spdk_json_decode_string},
};
static int
decode_rpc_listen_address(const struct spdk_json_val *val, void *out)
{
struct rpc_listen_address *req = (struct rpc_listen_address *)out;
if (spdk_json_decode_object(val, rpc_listen_address_decoders,
SPDK_COUNTOF(rpc_listen_address_decoders),
req)) {
SPDK_ERRLOG("spdk_json_decode_object failed\n");
return -1;
}
return 0;
}
static void
free_rpc_listen_address(struct rpc_listen_address *r)
{
free(r->transport);
free(r->adrfam);
free(r->traddr);
free(r->trsvcid);
}
enum nvmf_rpc_listen_op {
NVMF_RPC_LISTEN_ADD,
NVMF_RPC_LISTEN_REMOVE,
@ -1045,6 +641,47 @@ nvmf_rpc_listen_paused(struct spdk_nvmf_subsystem *subsystem,
}
}
static int
rpc_listen_address_to_trid(const struct rpc_listen_address *address,
struct spdk_nvme_transport_id *trid)
{
size_t len;
memset(trid, 0, sizeof(*trid));
if (spdk_nvme_transport_id_parse_trtype(&trid->trtype, address->transport)) {
SPDK_ERRLOG("Invalid transport type: %s\n", address->transport);
return -EINVAL;
}
if (address->adrfam) {
if (spdk_nvme_transport_id_parse_adrfam(&trid->adrfam, address->adrfam)) {
SPDK_ERRLOG("Invalid adrfam: %s\n", address->adrfam);
return -EINVAL;
}
} else {
trid->adrfam = SPDK_NVMF_ADRFAM_IPV4;
}
len = strlen(address->traddr);
if (len > sizeof(trid->traddr) - 1) {
SPDK_ERRLOG("Transport address longer than %zu characters: %s\n",
sizeof(trid->traddr) - 1, address->traddr);
return -EINVAL;
}
memcpy(trid->traddr, address->traddr, len + 1);
len = strlen(address->trsvcid);
if (len > sizeof(trid->trsvcid) - 1) {
SPDK_ERRLOG("Transport service id longer than %zu characters: %s\n",
sizeof(trid->trsvcid) - 1, address->trsvcid);
return -EINVAL;
}
memcpy(trid->trsvcid, address->trsvcid, len + 1);
return 0;
}
static void
nvmf_rpc_subsystem_add_listener(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
@ -1149,6 +786,38 @@ nvmf_rpc_subsystem_remove_listener(struct spdk_jsonrpc_request *request,
SPDK_RPC_REGISTER("nvmf_subsystem_remove_listener", nvmf_rpc_subsystem_remove_listener,
SPDK_RPC_RUNTIME);
struct spdk_nvmf_ns_params {
char *bdev_name;
uint32_t nsid;
char nguid[16];
char eui64[8];
struct spdk_uuid uuid;
};
struct rpc_namespaces {
size_t num_ns;
struct spdk_nvmf_ns_params ns_params[RPC_MAX_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},
{"uuid", offsetof(struct spdk_nvmf_ns_params, uuid), decode_ns_uuid, true},
};
static int
decode_rpc_ns_params(const struct spdk_json_val *val, void *out)
{
struct spdk_nvmf_ns_params *ns_params = out;
return spdk_json_decode_object(val, rpc_ns_params_decoders,
SPDK_COUNTOF(rpc_ns_params_decoders),
ns_params);
}
struct nvmf_rpc_ns_ctx {
char *nqn;
struct spdk_nvmf_ns_params ns_params;
@ -1166,11 +835,10 @@ static void
nvmf_rpc_ns_ctx_free(struct nvmf_rpc_ns_ctx *ctx)
{
free(ctx->nqn);
free_rpc_ns_params(&ctx->ns_params);
free(ctx->ns_params.bdev_name);
free(ctx);
}
static void
nvmf_rpc_ns_resumed(struct spdk_nvmf_subsystem *subsystem,
void *cb_arg, int status)

View File

@ -0,0 +1,620 @@
/*-
* 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 "event_nvmf.h"
#include "spdk/bdev.h"
#include "spdk/log.h"
#include "spdk/rpc.h"
#include "spdk/env.h"
#include "spdk/nvme.h"
#include "spdk/nvmf.h"
#include "spdk/string.h"
#include "spdk/util.h"
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 int
decode_ns_uuid(const struct spdk_json_val *val, void *out)
{
char *str = NULL;
int rc;
rc = spdk_json_decode_string(val, &str);
if (rc == 0) {
rc = spdk_uuid_parse(out, str);
}
free(str);
return rc;
}
struct rpc_listen_address {
char *transport;
char *adrfam;
char *traddr;
char *trsvcid;
};
#define RPC_MAX_LISTEN_ADDRESSES 255
#define RPC_MAX_HOSTS 255
#define RPC_MAX_NAMESPACES 255
struct rpc_listen_addresses {
size_t num_listen_address;
struct rpc_listen_address addresses[RPC_MAX_LISTEN_ADDRESSES];
};
static const struct spdk_json_object_decoder rpc_listen_address_decoders[] = {
/* NOTE: "transport" is kept for compatibility; new code should use "trtype" */
{"transport", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true},
{"trtype", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true},
{"adrfam", offsetof(struct rpc_listen_address, adrfam), spdk_json_decode_string, true},
{"traddr", offsetof(struct rpc_listen_address, traddr), spdk_json_decode_string},
{"trsvcid", offsetof(struct rpc_listen_address, trsvcid), spdk_json_decode_string},
};
static int
decode_rpc_listen_address(const struct spdk_json_val *val, void *out)
{
struct rpc_listen_address *req = (struct rpc_listen_address *)out;
if (spdk_json_decode_object(val, rpc_listen_address_decoders,
SPDK_COUNTOF(rpc_listen_address_decoders),
req)) {
SPDK_ERRLOG("spdk_json_decode_object failed\n");
return -1;
}
return 0;
}
static void
free_rpc_listen_address(struct rpc_listen_address *r)
{
free(r->transport);
free(r->adrfam);
free(r->traddr);
free(r->trsvcid);
}
static int
rpc_listen_address_to_trid(const struct rpc_listen_address *address,
struct spdk_nvme_transport_id *trid)
{
size_t len;
memset(trid, 0, sizeof(*trid));
if (spdk_nvme_transport_id_parse_trtype(&trid->trtype, address->transport)) {
SPDK_ERRLOG("Invalid transport type: %s\n", address->transport);
return -EINVAL;
}
if (address->adrfam) {
if (spdk_nvme_transport_id_parse_adrfam(&trid->adrfam, address->adrfam)) {
SPDK_ERRLOG("Invalid adrfam: %s\n", address->adrfam);
return -EINVAL;
}
} else {
trid->adrfam = SPDK_NVMF_ADRFAM_IPV4;
}
len = strlen(address->traddr);
if (len > sizeof(trid->traddr) - 1) {
SPDK_ERRLOG("Transport address longer than %zu characters: %s\n",
sizeof(trid->traddr) - 1, address->traddr);
return -EINVAL;
}
memcpy(trid->traddr, address->traddr, len + 1);
len = strlen(address->trsvcid);
if (len > sizeof(trid->trsvcid) - 1) {
SPDK_ERRLOG("Transport service id longer than %zu characters: %s\n",
sizeof(trid->trsvcid) - 1, address->trsvcid);
return -EINVAL;
}
memcpy(trid->trsvcid, address->trsvcid, len + 1);
return 0;
}
static int
decode_rpc_listen_addresses(const struct spdk_json_val *val, void *out)
{
struct rpc_listen_addresses *listen_addresses = out;
return spdk_json_decode_array(val, decode_rpc_listen_address, &listen_addresses->addresses,
RPC_MAX_LISTEN_ADDRESSES,
&listen_addresses->num_listen_address, sizeof(struct rpc_listen_address));
}
struct rpc_hosts {
size_t num_hosts;
char *hosts[RPC_MAX_HOSTS];
};
static int
decode_rpc_hosts(const struct spdk_json_val *val, void *out)
{
struct rpc_hosts *rpc_hosts = out;
return spdk_json_decode_array(val, spdk_json_decode_string, rpc_hosts->hosts, RPC_MAX_HOSTS,
&rpc_hosts->num_hosts, sizeof(char *));
}
struct spdk_nvmf_ns_params {
char *bdev_name;
uint32_t nsid;
char nguid[16];
char eui64[8];
struct spdk_uuid uuid;
};
struct rpc_namespaces {
size_t num_ns;
struct spdk_nvmf_ns_params ns_params[RPC_MAX_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},
{"uuid", offsetof(struct spdk_nvmf_ns_params, uuid), decode_ns_uuid, true},
};
static void
free_rpc_ns_params(struct spdk_nvmf_ns_params *ns_params)
{
free(ns_params->bdev_name);
}
static void
free_rpc_namespaces(struct rpc_namespaces *r)
{
size_t i;
for (i = 0; i < r->num_ns; i++) {
free_rpc_ns_params(&r->ns_params[i]);
}
}
static int
decode_rpc_ns_params(const struct spdk_json_val *val, void *out)
{
struct spdk_nvmf_ns_params *ns_params = out;
return spdk_json_decode_object(val, rpc_ns_params_decoders,
SPDK_COUNTOF(rpc_ns_params_decoders),
ns_params);
}
static int
decode_rpc_namespaces(const struct spdk_json_val *val, void *out)
{
struct rpc_namespaces *namespaces = out;
char *names[RPC_MAX_NAMESPACES] = {0}; /* old format - array of strings (bdev names) */
size_t i;
int rc;
/* First try to decode namespaces as an array of objects (new format) */
if (spdk_json_decode_array(val, decode_rpc_ns_params, namespaces->ns_params,
SPDK_COUNTOF(namespaces->ns_params),
&namespaces->num_ns, sizeof(*namespaces->ns_params)) == 0) {
return 0;
}
/* If that fails, try to decode namespaces as an array of strings (old format) */
free_rpc_namespaces(namespaces);
memset(namespaces, 0, sizeof(*namespaces));
rc = spdk_json_decode_array(val, spdk_json_decode_string, names,
SPDK_COUNTOF(names),
&namespaces->num_ns, sizeof(char *));
if (rc == 0) {
/* Decoded old format - copy to ns_params (new format) */
for (i = 0; i < namespaces->num_ns; i++) {
namespaces->ns_params[i].bdev_name = names[i];
}
return 0;
}
/* Failed to decode - don't leave dangling string pointers around */
for (i = 0; i < namespaces->num_ns; i++) {
free(names[i]);
}
return rc;
}
static void
free_rpc_listen_addresses(struct rpc_listen_addresses *r)
{
size_t i;
for (i = 0; i < r->num_listen_address; i++) {
free_rpc_listen_address(&r->addresses[i]);
}
}
static void
free_rpc_hosts(struct rpc_hosts *r)
{
size_t i;
for (i = 0; i < r->num_hosts; i++) {
free(r->hosts[i]);
}
}
struct rpc_subsystem {
int32_t core;
char *mode;
char *nqn;
struct rpc_listen_addresses listen_addresses;
struct rpc_hosts hosts;
bool allow_any_host;
char *pci_address;
char *serial_number;
struct rpc_namespaces namespaces;
uint32_t num_ns;
};
static void
free_rpc_subsystem(struct rpc_subsystem *req)
{
if (req) {
free(req->mode);
free(req->nqn);
free(req->serial_number);
free_rpc_namespaces(&req->namespaces);
free_rpc_listen_addresses(&req->listen_addresses);
free_rpc_hosts(&req->hosts);
}
free(req);
}
static void
spdk_rpc_nvmf_subsystem_started(struct spdk_nvmf_subsystem *subsystem,
void *cb_arg, int status)
{
struct spdk_jsonrpc_request *request = cb_arg;
struct spdk_json_write_ctx *w;
w = spdk_jsonrpc_begin_result(request);
if (w == NULL) {
return;
}
spdk_json_write_bool(w, true);
spdk_jsonrpc_end_result(request, w);
}
static const struct spdk_json_object_decoder rpc_subsystem_decoders[] = {
{"core", offsetof(struct rpc_subsystem, core), spdk_json_decode_int32, true},
{"mode", offsetof(struct rpc_subsystem, mode), spdk_json_decode_string, true},
{"nqn", offsetof(struct rpc_subsystem, nqn), spdk_json_decode_string},
{"listen_addresses", offsetof(struct rpc_subsystem, listen_addresses), decode_rpc_listen_addresses, true},
{"hosts", offsetof(struct rpc_subsystem, hosts), decode_rpc_hosts, true},
{"allow_any_host", offsetof(struct rpc_subsystem, allow_any_host), spdk_json_decode_bool, true},
{"serial_number", offsetof(struct rpc_subsystem, serial_number), spdk_json_decode_string, true},
{"namespaces", offsetof(struct rpc_subsystem, namespaces), decode_rpc_namespaces, true},
{"max_namespaces", offsetof(struct rpc_subsystem, num_ns), spdk_json_decode_uint32, true},
};
struct subsystem_listen_ctx {
struct rpc_subsystem *req;
struct spdk_nvmf_subsystem *subsystem;
struct spdk_jsonrpc_request *request;
uint32_t idx;
};
static void
spdk_rpc_construct_subsystem_listen_done(void *cb_arg, int status)
{
struct subsystem_listen_ctx *ctx = cb_arg;
struct rpc_listen_address *addr;
struct spdk_nvme_transport_id trid = {0};
if (status) {
goto invalid;
}
addr = &ctx->req->listen_addresses.addresses[ctx->idx];
if (rpc_listen_address_to_trid(addr, &trid)) {
goto invalid;
}
spdk_nvmf_subsystem_add_listener(ctx->subsystem, &trid);
ctx->idx++;
if (ctx->idx < ctx->req->listen_addresses.num_listen_address) {
addr = &ctx->req->listen_addresses.addresses[ctx->idx];
if (rpc_listen_address_to_trid(addr, &trid)) {
goto invalid;
}
spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt, &trid, spdk_rpc_construct_subsystem_listen_done, ctx);
return;
}
spdk_nvmf_subsystem_start(ctx->subsystem,
spdk_rpc_nvmf_subsystem_started,
ctx->request);
free_rpc_subsystem(ctx->req);
free(ctx);
return;
invalid:
spdk_nvmf_subsystem_destroy(ctx->subsystem);
spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
"Invalid parameters");
free_rpc_subsystem(ctx->req);
free(ctx);
}
static void
spdk_rpc_construct_nvmf_subsystem(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_subsystem *req;
struct spdk_nvmf_subsystem *subsystem;
size_t i;
SPDK_WARNLOG("The construct_nvmf_subsystem RPC is deprecated. Use nvmf_subsystem_create instead.\n");
req = calloc(1, sizeof(*req));
if (!req) {
goto invalid;
}
req->core = -1; /* Explicitly set the core as the uninitialized value */
if (spdk_json_decode_object(params, rpc_subsystem_decoders,
SPDK_COUNTOF(rpc_subsystem_decoders),
req)) {
SPDK_ERRLOG("spdk_json_decode_object failed\n");
goto invalid;
}
/* Mode is no longer a valid parameter, but print out a nice
* message if it exists to inform users.
*/
if (req->mode) {
SPDK_NOTICELOG("Mode present in the construct NVMe-oF subsystem RPC.\n"
"Mode was removed as a valid parameter.\n");
if (strcasecmp(req->mode, "Virtual") == 0) {
SPDK_NOTICELOG("Your mode value is 'Virtual' which is now the only possible mode.\n"
"Your RPC will work as expected.\n");
} else {
SPDK_NOTICELOG("Please remove 'mode' from the RPC.\n");
goto invalid;
}
}
/* Core is no longer a valid parameter, but print out a nice
* message if it exists to inform users.
*/
if (req->core != -1) {
SPDK_NOTICELOG("Core present in the construct NVMe-oF subsystem RPC.\n"
"Core was removed as an option. Subsystems can now run on all available cores.\n");
SPDK_NOTICELOG("Ignoring it and continuing.\n");
}
subsystem = spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt, req->nqn, SPDK_NVMF_SUBTYPE_NVME,
req->num_ns);
if (!subsystem) {
goto invalid;
}
if (spdk_nvmf_subsystem_set_sn(subsystem, req->serial_number)) {
SPDK_ERRLOG("Subsystem %s: invalid serial number '%s'\n", req->nqn, req->serial_number);
goto invalid;
}
for (i = 0; i < req->hosts.num_hosts; i++) {
spdk_nvmf_subsystem_add_host(subsystem, req->hosts.hosts[i]);
}
spdk_nvmf_subsystem_set_allow_any_host(subsystem, req->allow_any_host);
for (i = 0; i < req->namespaces.num_ns; i++) {
struct spdk_nvmf_ns_params *ns_params = &req->namespaces.ns_params[i];
struct spdk_bdev *bdev;
struct spdk_nvmf_ns_opts ns_opts;
bdev = spdk_bdev_get_by_name(ns_params->bdev_name);
if (bdev == NULL) {
SPDK_ERRLOG("Could not find namespace bdev '%s'\n", ns_params->bdev_name);
spdk_nvmf_subsystem_destroy(subsystem);
goto invalid;
}
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_mem_all_zero(&ns_params->uuid, sizeof(ns_params->uuid))) {
ns_opts.uuid = ns_params->uuid;
}
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);
goto invalid;
}
}
if (req->listen_addresses.num_listen_address > 0) {
struct rpc_listen_address *addr;
struct spdk_nvme_transport_id trid = {0};
struct subsystem_listen_ctx *ctx;
ctx = calloc(1, sizeof(*ctx));
if (!ctx) {
spdk_nvmf_subsystem_destroy(subsystem);
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "No Memory");
free_rpc_subsystem(req);
return;
}
ctx->req = req;
ctx->subsystem = subsystem;
ctx->request = request;
ctx->idx = 0;
addr = &req->listen_addresses.addresses[0];
if (rpc_listen_address_to_trid(addr, &trid)) {
free(ctx);
goto invalid;
}
spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt, &trid, spdk_rpc_construct_subsystem_listen_done, ctx);
return;
}
free_rpc_subsystem(req);
spdk_nvmf_subsystem_start(subsystem,
spdk_rpc_nvmf_subsystem_started,
request);
return;
invalid:
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
free_rpc_subsystem(req);
}
SPDK_RPC_REGISTER("construct_nvmf_subsystem", spdk_rpc_construct_nvmf_subsystem, SPDK_RPC_RUNTIME)