Commit 183d81d0 authored by John Barnard's avatar John Barnard Committed by Jim Harris
Browse files

nvmf: Move target opts to transport opts (part 2)



- Add independent functions to create transport with specific opts
  and add to target while maintaining backward compatibility with
  current apps and rpc configuration that still use the add listener
  method to create a transport.
- Add new rpc function to create transport and add to target.
  + Update json reporting to include new rpc function.
  + Update python scripts to support new rpc function.
  + New nvmf test script (cr_trprt.sh) to test new rpc function.

Change-Id: I12d0a42e34c9edff757755f18a78b722d5e1523e
Signed-off-by: default avatarJohn Barnard <john.barnard@broadcom.com>
Reviewed-on: https://review.gerrithub.io/423590


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent f8d0f6d6
Loading
Loading
Loading
Loading
+89 −0
Original line number Diff line number Diff line
@@ -703,6 +703,95 @@ const char *spdk_nvmf_subsystem_get_nqn(struct spdk_nvmf_subsystem *subsystem);
 */
enum spdk_nvmf_subtype spdk_nvmf_subsystem_get_type(struct spdk_nvmf_subsystem *subsystem);

/**
 * Initialize transport options
 *
 * \param type The transport type to create
 * \param opts The transport options (e.g. max_io_size)
 *
 * \return bool. true if successful, false if transport type
 *	   not found.
 */
bool
spdk_nvmf_transport_opts_init(enum spdk_nvme_transport_type type,
			      struct spdk_nvmf_transport_opts *opts);

/**
 * Create a protocol transport
 *
 * \param type The transport type to create
 * \param opts The transport options (e.g. max_io_size)
 *
 * \return new transport or NULL if create fails
 */
struct spdk_nvmf_transport *spdk_nvmf_transport_create(enum spdk_nvme_transport_type type,
		struct spdk_nvmf_transport_opts *opts);

/**
 * Destroy a protocol transport
 *
 * \param transport The transport to destory
 *
 * \return 0 on success, -1 on failure.
 */
int spdk_nvmf_transport_destroy(struct spdk_nvmf_transport *transport);

/**
 * Get an existing transport from the target
 *
 * \param tgt The NVMe-oF target
 * \param type The transport type to get
 *
 * \return the transport or NULL if not found
 */
struct spdk_nvmf_transport *spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt,
		enum spdk_nvme_transport_type type);

/**
 * Function to be called once transport add is complete
 *
 * \param cb_arg Callback argument passed to this function.
 * \param status 0 if it completed successfully, or negative errno if it failed.
 */
typedef void (*spdk_nvmf_tgt_add_transport_done_fn)(void *cb_arg, int status);

/**
 * Add a transport to a target
 *
 * \param tgt The NVMe-oF target
 * \param transport The transport to add
 * \param cb_fn A callback that will be called once the transport is created
 * \param cb_arg A context argument passed to cb_fn.
 *
 * \return void. The callback status argument will be 0 on success
 *	   or a negated errno on failure.
 */
void spdk_nvmf_tgt_add_transport(struct spdk_nvmf_tgt *tgt,
				 struct spdk_nvmf_transport *transport,
				 spdk_nvmf_tgt_add_transport_done_fn cb_fn,
				 void *cb_arg);

/**
 *
 * Add listener to transport and begin accepting new connections.
 *
 * \param transport The transport to add listener to
 * \param trid Address to listen at
 *
 * \return int. 0 if it completed successfully, or negative errno if it failed.
 */

int spdk_nvmf_transport_listen(struct spdk_nvmf_transport *transport,
			       const struct spdk_nvme_transport_id *trid);

/**
 * Write NVMe-oF target's transport configurations into provided JSON context.
 * \param w JSON write context
 * \param tgt The NVMe-oF target
 */
void
spdk_nvmf_tgt_transport_write_config_json(struct spdk_json_write_ctx *w, struct spdk_nvmf_tgt *tgt);

#ifdef __cplusplus
}
#endif
+145 −3
Original line number Diff line number Diff line
@@ -424,19 +424,161 @@ spdk_nvmf_parse_subsystems(void)
	return 0;
}

struct spdk_nvmf_parse_transport_ctx {
	struct spdk_conf_section *sp;
	spdk_nvmf_parse_conf_done_fn cb_fn;
};

static void spdk_nvmf_parse_transport(struct spdk_nvmf_parse_transport_ctx *ctx);

static void
spdk_nvmf_tgt_add_transport_done(void *cb_arg, int status)
{
	struct spdk_nvmf_parse_transport_ctx *ctx = cb_arg;
	int rc;

	if (status < 0) {
		SPDK_ERRLOG("Add transport to target failed (%d).\n", status);
		ctx->cb_fn(status);
		free(ctx);
		return;
	}

	/* find next transport */
	ctx->sp = spdk_conf_next_section(ctx->sp);
	while (ctx->sp) {
		if (spdk_conf_section_match_prefix(ctx->sp, "Transport")) {
			spdk_nvmf_parse_transport(ctx);
			return;
		}
		ctx->sp = spdk_conf_next_section(ctx->sp);
	}

	/* done with transports, parse Subsystem sections */
	rc = spdk_nvmf_parse_subsystems();

	ctx->cb_fn(rc);
	free(ctx);
}

static void
spdk_nvmf_parse_transport(struct spdk_nvmf_parse_transport_ctx *ctx)
{
	const char *type;
	struct spdk_nvmf_transport_opts opts = { 0 };
	enum spdk_nvme_transport_type trtype;
	struct spdk_nvmf_transport *transport;
	int val;

	type = spdk_conf_section_get_val(ctx->sp, "Type");
	if (type == NULL) {
		SPDK_ERRLOG("Transport missing Type\n");
		ctx->cb_fn(-1);
		free(ctx);
		return;
	}

	if (spdk_nvme_transport_id_parse_trtype(&trtype, type)) {
		SPDK_ERRLOG("Invalid transport type '%s'\n", type);
		ctx->cb_fn(-1);
		free(ctx);
		return;
	}

	if (spdk_nvmf_tgt_get_transport(g_spdk_nvmf_tgt, trtype)) {
		SPDK_ERRLOG("Duplicate transport type '%s'\n", type);
		ctx->cb_fn(-1);
		free(ctx);
		return;
	}

	if (!spdk_nvmf_transport_opts_init(trtype, &opts)) {
		ctx->cb_fn(-1);
		free(ctx);
		return;
	}

	val = spdk_conf_section_get_intval(ctx->sp, "MaxQueueDepth");
	if (val >= 0) {
		opts.max_queue_depth = val;
	}
	val = spdk_conf_section_get_intval(ctx->sp, "MaxQueuesPerSession");
	if (val >= 0) {
		opts.max_qpairs_per_ctrlr = val;
	}
	val = spdk_conf_section_get_intval(ctx->sp, "InCapsuleDataSize");
	if (val >= 0) {
		opts.in_capsule_data_size = val;
	}
	val = spdk_conf_section_get_intval(ctx->sp, "MaxIOSize");
	if (val >= 0) {
		opts.max_io_size = val;
	}
	val = spdk_conf_section_get_intval(ctx->sp, "IOUnitSize");
	if (val >= 0) {
		opts.io_unit_size = val;
	}
	val = spdk_conf_section_get_intval(ctx->sp, "MaxAQDepth");
	if (val >= 0) {
		opts.max_aq_depth = val;
	}

	transport = spdk_nvmf_transport_create(trtype, &opts);
	if (transport) {
		spdk_nvmf_tgt_add_transport(g_spdk_nvmf_tgt, transport, spdk_nvmf_tgt_add_transport_done, ctx);
	} else {
		ctx->cb_fn(-1);
		free(ctx);
		return;
	}
}

static int
spdk_nvmf_parse_transports(spdk_nvmf_parse_conf_done_fn cb_fn)
{
	struct spdk_nvmf_parse_transport_ctx *ctx;

	ctx = calloc(1, sizeof(struct spdk_nvmf_parse_transport_ctx));
	if (!ctx) {
		SPDK_ERRLOG("Failed alloc of context memory for parse transports\n");
		return -ENOMEM;
	}

	ctx->cb_fn = cb_fn;
	ctx->sp = spdk_conf_first_section(NULL);
	while (ctx->sp != NULL) {
		if (spdk_conf_section_match_prefix(ctx->sp, "Transport")) {
			spdk_nvmf_parse_transport(ctx);
			return 0;
		}
		ctx->sp = spdk_conf_next_section(ctx->sp);
	}

	/* if we get here, there are no transports defined in conf file */
	free(ctx);
	cb_fn(spdk_nvmf_parse_subsystems());

	return 0;
}

int
spdk_nvmf_parse_conf(void)
spdk_nvmf_parse_conf(spdk_nvmf_parse_conf_done_fn cb_fn)
{
	int rc;

	if (cb_fn == NULL) {
		SPDK_ERRLOG("Callback function is NULL\n");
		return -1;
	}

	/* NVMf section */
	rc = spdk_nvmf_parse_nvmf_tgt();
	if (rc < 0) {
		return rc;
	}

	/* Subsystem sections */
	rc = spdk_nvmf_parse_subsystems();
	/* Transport sections */
	rc = spdk_nvmf_parse_transports(cb_fn);
	if (rc < 0) {
		return rc;
	}
+3 −1
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ extern struct spdk_nvmf_tgt_conf *g_spdk_nvmf_tgt_conf;

extern struct spdk_nvmf_tgt *g_spdk_nvmf_tgt;

int spdk_nvmf_parse_conf(void);
typedef void (*spdk_nvmf_parse_conf_done_fn)(int status);

int spdk_nvmf_parse_conf(spdk_nvmf_parse_conf_done_fn cb_fn);

#endif
+138 −0
Original line number Diff line number Diff line
@@ -1422,3 +1422,141 @@ nvmf_rpc_subsystem_set_tgt_conf(struct spdk_jsonrpc_request *request,
	spdk_jsonrpc_end_result(request, w);
}
SPDK_RPC_REGISTER("set_nvmf_target_config", nvmf_rpc_subsystem_set_tgt_conf, SPDK_RPC_STARTUP)

struct nvmf_rpc_create_transport_ctx {
	char				*trtype;
	struct spdk_nvmf_transport_opts opts;
	struct spdk_jsonrpc_request	*request;
};

static const struct spdk_json_object_decoder nvmf_rpc_create_transport_decoder[] = {
	{	"trtype", offsetof(struct nvmf_rpc_create_transport_ctx, trtype), spdk_json_decode_string},
	{
		"max_queue_depth", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_queue_depth),
		spdk_json_decode_uint16, true
	},
	{
		"max_qpairs_per_ctrlr", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_qpairs_per_ctrlr),
		spdk_json_decode_uint16, true
	},
	{
		"in_capsule_data_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.in_capsule_data_size),
		spdk_json_decode_uint32, true
	},
	{
		"max_io_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_io_size),
		spdk_json_decode_uint32, true
	},
	{
		"io_unit_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.io_unit_size),
		spdk_json_decode_uint32, true
	},
	{
		"max_aq_depth", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_aq_depth),
		spdk_json_decode_uint32, true
	},
};

static void
nvmf_rpc_create_transport_ctx_free(struct nvmf_rpc_create_transport_ctx *ctx)
{
	free(ctx->trtype);
	free(ctx);
}

static void
nvmf_rpc_tgt_add_transport_done(void *cb_arg, int status)
{
	struct nvmf_rpc_create_transport_ctx *ctx = cb_arg;
	struct spdk_jsonrpc_request *request;
	struct spdk_json_write_ctx *w;

	request = ctx->request;
	nvmf_rpc_create_transport_ctx_free(ctx);

	if (status) {
		SPDK_ERRLOG("Failed to add transport to tgt.(%d)\n", status);
		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
						     "Failed to add transport to tgt.(%d)\n",
						     status);
		return;
	}

	w = spdk_jsonrpc_begin_result(request);
	if (w == NULL) {
		return;
	}

	spdk_json_write_bool(w, true);
	spdk_jsonrpc_end_result(request, w);
}

static void
nvmf_rpc_create_transport(struct spdk_jsonrpc_request *request,
			  const struct spdk_json_val *params)
{
	struct nvmf_rpc_create_transport_ctx *ctx;
	enum spdk_nvme_transport_type trtype;
	struct spdk_nvmf_transport *transport;

	ctx = calloc(1, sizeof(*ctx));
	if (!ctx) {
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
		return;
	}

	/* Decode parameters the first time to get the transport type */
	if (spdk_json_decode_object(params, nvmf_rpc_create_transport_decoder,
				    SPDK_COUNTOF(nvmf_rpc_create_transport_decoder),
				    ctx)) {
		SPDK_ERRLOG("spdk_json_decode_object failed\n");
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
		nvmf_rpc_create_transport_ctx_free(ctx);
		return;
	}

	if (spdk_nvme_transport_id_parse_trtype(&trtype, ctx->trtype)) {
		SPDK_ERRLOG("Invalid transport type '%s'\n", ctx->trtype);
		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
						     "Invalid transport type '%s'\n", ctx->trtype);
		nvmf_rpc_create_transport_ctx_free(ctx);
		return;
	}

	/* Initialize all the transport options (based on transport type) and decode the
	 * parameters again to update any options passed in rpc create transport call.
	 */
	spdk_nvmf_transport_opts_init(trtype, &ctx->opts);
	if (spdk_json_decode_object(params, nvmf_rpc_create_transport_decoder,
				    SPDK_COUNTOF(nvmf_rpc_create_transport_decoder),
				    ctx)) {
		SPDK_ERRLOG("spdk_json_decode_object failed\n");
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
		nvmf_rpc_create_transport_ctx_free(ctx);
		return;
	}

	if (spdk_nvmf_tgt_get_transport(g_spdk_nvmf_tgt, trtype)) {
		SPDK_ERRLOG("Transport type '%s' already exists\n", ctx->trtype);
		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
						     "Transport type '%s' already exists\n", ctx->trtype);
		nvmf_rpc_create_transport_ctx_free(ctx);
		return;
	}

	transport = spdk_nvmf_transport_create(trtype, &ctx->opts);

	if (!transport) {
		SPDK_ERRLOG("Transport type '%s' create failed\n", ctx->trtype);
		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
						     "Transport type '%s' create failed\n", ctx->trtype);
		nvmf_rpc_create_transport_ctx_free(ctx);
		return;
	}

	/* add transport to target */
	ctx->request = request;
	spdk_nvmf_tgt_add_transport(g_spdk_nvmf_tgt, transport, nvmf_rpc_tgt_add_transport_done, ctx);
}

SPDK_RPC_REGISTER("nvmf_create_transport", nvmf_rpc_create_transport, SPDK_RPC_RUNTIME)
+21 −8
Original line number Diff line number Diff line
@@ -305,6 +305,23 @@ nvmf_tgt_destroy_done(void *ctx, int status)
	nvmf_tgt_advance_state();
}

static void
nvmf_tgt_parse_conf_done(int status)
{
	g_tgt_state = (status == 0) ? NVMF_TGT_INIT_CREATE_POLL_GROUPS : NVMF_TGT_ERROR;
	nvmf_tgt_advance_state();
}

static void
nvmf_tgt_parse_conf_start(void *ctx)
{
	if (spdk_nvmf_parse_conf(nvmf_tgt_parse_conf_done)) {
		SPDK_ERRLOG("spdk_nvmf_parse_conf() failed\n");
		g_tgt_state = NVMF_TGT_ERROR;
		nvmf_tgt_advance_state();
	}
}

static void
nvmf_tgt_advance_state(void)
{
@@ -333,14 +350,10 @@ nvmf_tgt_advance_state(void)
			break;
		}
		case NVMF_TGT_INIT_PARSE_CONFIG:
			rc = spdk_nvmf_parse_conf();
			if (rc < 0) {
				SPDK_ERRLOG("spdk_nvmf_parse_conf() failed\n");
				g_tgt_state = NVMF_TGT_ERROR;
				rc = -EINVAL;
				break;
			}
			g_tgt_state = NVMF_TGT_INIT_CREATE_POLL_GROUPS;
			/* Send message to self to call parse conf func.
			 * Prevents it from possibly performing cb before getting
			 * out of this function, which causes problems. */
			spdk_thread_send_msg(spdk_get_thread(), nvmf_tgt_parse_conf_start, NULL);
			break;
		case NVMF_TGT_INIT_CREATE_POLL_GROUPS:
			/* Send a message to each thread and create a poll group */
Loading