Commit 87a062e6 authored by Jacek Kalwas's avatar Jacek Kalwas Committed by Tomasz Zawadzki
Browse files

nvmf: introduce listener opts



With new spdk_nvmf_transport_listen function it should be possible to
add generic options without breaking API/ABI. For now it only delivers
json parameters which can be decoded on a transport specific layer.
This is similar to what was done for spdk_nvmf_transport_create and opts there.

Signed-off-by: default avatarJacek Kalwas <jacek.kalwas@intel.com>
Change-Id: Iaf576248a0b10b408c4a3182785270be3e32ebe4
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/5570


Reviewed-by: default avatarAleksey Marchuk <alexeymar@mellanox.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Community-CI: Broadcom CI
Community-CI: Mellanox Build Bot
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent de8ac98b
Loading
Loading
Loading
Loading
+33 −4
Original line number Diff line number Diff line
@@ -98,6 +98,18 @@ struct spdk_nvmf_transport_opts {
	size_t opts_size;
};

struct spdk_nvmf_listen_opts {
	/**
	 * The size of spdk_nvmf_listen_opts according to the caller of this library is used for ABI
	 * compatibility. The library uses this field to know how many fields in this
	 * structure are valid. And the library will populate any remaining fields with default values.
	 * New added fields should be put at the end of the struct.
	 */
	size_t opts_size;

	const struct spdk_json_val *transport_specific;
};

struct spdk_nvmf_poll_group_stat {
	uint32_t admin_qpairs;
	uint32_t io_qpairs;
@@ -209,7 +221,7 @@ struct spdk_nvmf_tgt *spdk_nvmf_get_next_tgt(struct spdk_nvmf_tgt *prev);
void spdk_nvmf_tgt_write_config_json(struct spdk_json_write_ctx *w, struct spdk_nvmf_tgt *tgt);

/**
 * Begin accepting new connections at the address provided.
 * Begin accepting new connections at the address provided (deprecated, please use spdk_nvmf_tgt_listen_ext).
 *
 * The connections will be matched with a subsystem, which may or may not allow
 * the connection based on a subsystem-specific list of allowed hosts. See
@@ -223,6 +235,22 @@ void spdk_nvmf_tgt_write_config_json(struct spdk_json_write_ctx *w, struct spdk_
int spdk_nvmf_tgt_listen(struct spdk_nvmf_tgt *tgt,
			 struct spdk_nvme_transport_id *trid);

/**
 * Begin accepting new connections at the address provided.
 *
 * The connections will be matched with a subsystem, which may or may not allow
 * the connection based on a subsystem-specific list of allowed hosts. See
 * spdk_nvmf_subsystem_add_host() and spdk_nvmf_subsystem_add_listener()
 *
 * \param tgt The target associated with this listen address.
 * \param trid The address to listen at.
 * \param opts Listener options.
 *
 * \return 0 on success or a negated errno on failure.
 */
int spdk_nvmf_tgt_listen_ext(struct spdk_nvmf_tgt *tgt, const struct spdk_nvme_transport_id *trid,
			     struct spdk_nvmf_listen_opts *opts);

/**
 * Stop accepting new connections at the provided address.
 *
@@ -1034,14 +1062,15 @@ void spdk_nvmf_tgt_add_transport(struct spdk_nvmf_tgt *tgt,
/**
 * Add listener to transport and begin accepting new connections.
 *
 * \param transport The transport to add listener to
 * \param trid Address to listen at
 * \param transport The transport to add listener to.
 * \param trid The address to listen at.
 * \param opts Listener options.
 *
 * \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);
			   const struct spdk_nvme_transport_id *trid, struct spdk_nvmf_listen_opts *opts);

/**
 * Remove listener from transport and stop accepting new connections.
+2 −2
Original line number Diff line number Diff line
@@ -241,8 +241,8 @@ struct spdk_nvmf_transport_ops {
	  * Instruct the transport to accept new connections at the address
	  * provided. This may be called multiple times.
	  */
	int (*listen)(struct spdk_nvmf_transport *transport,
		      const struct spdk_nvme_transport_id *trid);
	int (*listen)(struct spdk_nvmf_transport *transport, const struct spdk_nvme_transport_id *trid,
		      struct spdk_nvmf_listen_opts *opts);

	/**
	  * Stop accepting new connections at the given address.
+2 −2
Original line number Diff line number Diff line
@@ -1879,8 +1879,8 @@ nvmf_fc_destroy(struct spdk_nvmf_transport *transport,
}

static int
nvmf_fc_listen(struct spdk_nvmf_transport *transport,
	       const struct spdk_nvme_transport_id *trid)
nvmf_fc_listen(struct spdk_nvmf_transport *transport, const struct spdk_nvme_transport_id *trid,
	       struct spdk_nvmf_listen_opts *listen_opts)
{
	return 0;
}
+45 −3
Original line number Diff line number Diff line
@@ -598,12 +598,45 @@ spdk_nvmf_tgt_write_config_json(struct spdk_json_write_ctx *w, struct spdk_nvmf_
	}
}

static void
nvmf_listen_opts_copy(struct spdk_nvmf_listen_opts *opts,
		      const struct spdk_nvmf_listen_opts *opts_src, size_t opts_size)
{
	assert(opts);
	assert(opts_src);

	opts->opts_size = opts_size;

#define SET_FIELD(field) \
    if (offsetof(struct spdk_nvmf_listen_opts, field) + sizeof(opts->field) <= opts_size) { \
                 opts->field = opts_src->field; \
    } \

	SET_FIELD(transport_specific);
#undef SET_FIELD

	/* Do not remove this statement, you should always update this statement when you adding a new field,
	 * and do not forget to add the SET_FIELD statement for your added field. */
	SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_listen_opts) == 16, "Incorrect size");
}

int
spdk_nvmf_tgt_listen(struct spdk_nvmf_tgt *tgt,
		     struct spdk_nvme_transport_id *trid)
spdk_nvmf_tgt_listen_ext(struct spdk_nvmf_tgt *tgt, const struct spdk_nvme_transport_id *trid,
			 struct spdk_nvmf_listen_opts *opts)
{
	struct spdk_nvmf_transport *transport;
	int rc;
	struct spdk_nvmf_listen_opts opts_local = {};

	if (!opts) {
		SPDK_ERRLOG("opts should not be NULL\n");
		return -EINVAL;
	}

	if (!opts->opts_size) {
		SPDK_ERRLOG("The opts_size in opts structure should not be zero\n");
		return -EINVAL;
	}

	transport = spdk_nvmf_tgt_get_transport(tgt, trid->trstring);
	if (!transport) {
@@ -612,7 +645,8 @@ spdk_nvmf_tgt_listen(struct spdk_nvmf_tgt *tgt,
		return -EINVAL;
	}

	rc = spdk_nvmf_transport_listen(transport, trid);
	nvmf_listen_opts_copy(&opts_local, opts, opts->opts_size);
	rc = spdk_nvmf_transport_listen(transport, trid, &opts_local);
	if (rc < 0) {
		SPDK_ERRLOG("Unable to listen on address '%s'\n", trid->traddr);
	}
@@ -620,6 +654,14 @@ spdk_nvmf_tgt_listen(struct spdk_nvmf_tgt *tgt,
	return rc;
}

int
spdk_nvmf_tgt_listen(struct spdk_nvmf_tgt *tgt, struct spdk_nvme_transport_id *trid)
{
	struct spdk_nvmf_listen_opts opts = {.opts_size = sizeof(opts)};

	return spdk_nvmf_tgt_listen_ext(tgt, trid, &opts);
}

int
spdk_nvmf_tgt_stop_listen(struct spdk_nvmf_tgt *tgt,
			  struct spdk_nvme_transport_id *trid)
+8 −5
Original line number Diff line number Diff line
@@ -685,6 +685,7 @@ struct nvmf_rpc_listener_ctx {
	struct spdk_nvme_transport_id	trid;
	enum nvmf_rpc_listen_op		op;
	bool				response_sent;
	struct spdk_nvmf_listen_opts	opts;
};

static const struct spdk_json_object_decoder nvmf_rpc_listener_decoder[] = {
@@ -799,7 +800,7 @@ nvmf_rpc_listen_paused(struct spdk_nvmf_subsystem *subsystem,

	if (ctx->op == NVMF_RPC_LISTEN_ADD) {
		if (!nvmf_subsystem_find_listener(subsystem, &ctx->trid)) {
			rc = spdk_nvmf_tgt_listen(ctx->tgt, &ctx->trid);
			rc = spdk_nvmf_tgt_listen_ext(ctx->tgt, &ctx->trid, &ctx->opts);
			if (rc == 0) {
				spdk_nvmf_subsystem_add_listener(ctx->subsystem, &ctx->trid, nvmf_rpc_subsystem_listen, ctx);
				return;
@@ -900,10 +901,10 @@ rpc_nvmf_subsystem_add_listener(struct spdk_jsonrpc_request *request,

	ctx->request = request;

	if (spdk_json_decode_object(params, nvmf_rpc_listener_decoder,
	if (spdk_json_decode_object_relaxed(params, nvmf_rpc_listener_decoder,
					    SPDK_COUNTOF(nvmf_rpc_listener_decoder),
					    ctx)) {
		SPDK_ERRLOG("spdk_json_decode_object failed\n");
		SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n");
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
		nvmf_rpc_listener_ctx_free(ctx);
		return;
@@ -937,6 +938,8 @@ rpc_nvmf_subsystem_add_listener(struct spdk_jsonrpc_request *request,
	}

	ctx->op = NVMF_RPC_LISTEN_ADD;
	ctx->opts.transport_specific = params;
	ctx->opts.opts_size = sizeof(ctx->opts);

	rc = spdk_nvmf_subsystem_pause(subsystem, nvmf_rpc_listen_paused, ctx);
	if (rc != 0) {
Loading