subsystem/iscsi: Add set_iscsi_options RPC to set global params

An new RPC set_iscsi_options allocates and set options dynamically.
Initialization of iSCSI subsystem skips initialization of options
if it is already allocated.

To use and test this RPC easily, add python script too.

Change-Id: I71e252da6495a194ae9a1a9e3aaae4feb543487a
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/403624
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Shuhei Matsumoto 2018-05-15 08:24:19 +09:00 committed by Ben Walker
parent cfbae9c23b
commit 59b3479bfd
6 changed files with 289 additions and 14 deletions

View File

@ -35,7 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
CFLAGS += -I$(SPDK_ROOT_DIR)/lib
C_SRCS = iscsi.c
C_SRCS = iscsi.c iscsi_rpc.c
LIBNAME = event_iscsi
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk

View File

@ -0,0 +1,113 @@
/*-
* 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 "iscsi/iscsi.h"
#include "iscsi/conn.h"
#include "spdk/rpc.h"
#include "spdk/util.h"
#include "spdk/event.h"
#include "spdk_internal/log.h"
static const struct spdk_json_object_decoder rpc_set_iscsi_opts_decoders[] = {
{"auth_file", offsetof(struct spdk_iscsi_opts, authfile), spdk_json_decode_string, true},
{"node_base", offsetof(struct spdk_iscsi_opts, nodebase), spdk_json_decode_string, true},
{"timeout", offsetof(struct spdk_iscsi_opts, timeout), spdk_json_decode_int32, true},
{"nop_in_interval", offsetof(struct spdk_iscsi_opts, nopininterval), spdk_json_decode_int32, true},
{"no_discovery_auth", offsetof(struct spdk_iscsi_opts, no_discovery_auth), spdk_json_decode_bool, true},
{"req_discovery_auth", offsetof(struct spdk_iscsi_opts, req_discovery_auth), spdk_json_decode_bool, true},
{"req_discovery_auth_mutual", offsetof(struct spdk_iscsi_opts, req_discovery_auth_mutual), spdk_json_decode_bool, true},
{"discovery_auth_group", offsetof(struct spdk_iscsi_opts, discovery_auth_group), spdk_json_decode_int32, true},
{"max_sessions", offsetof(struct spdk_iscsi_opts, MaxSessions), spdk_json_decode_uint32, true},
{"max_queue_depth", offsetof(struct spdk_iscsi_opts, MaxQueueDepth), spdk_json_decode_uint32, true},
{"max_connections_per_session", offsetof(struct spdk_iscsi_opts, MaxConnectionsPerSession), spdk_json_decode_uint32, true},
{"default_time2wait", offsetof(struct spdk_iscsi_opts, DefaultTime2Wait), spdk_json_decode_uint32, true},
{"default_time2retain", offsetof(struct spdk_iscsi_opts, DefaultTime2Retain), spdk_json_decode_uint32, true},
{"immediate_data", offsetof(struct spdk_iscsi_opts, ImmediateData), spdk_json_decode_bool, true},
{"error_recovery_level", offsetof(struct spdk_iscsi_opts, ErrorRecoveryLevel), spdk_json_decode_uint32, true},
{"allow_duplicated_isid", offsetof(struct spdk_iscsi_opts, AllowDuplicateIsid), spdk_json_decode_bool, true},
{"min_connections_per_core", offsetof(struct spdk_iscsi_opts, min_connections_per_core), spdk_json_decode_uint32, true},
};
static void
spdk_rpc_iscsi_set_opts(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct spdk_iscsi_opts *opts;
struct spdk_json_write_ctx *w;
if (g_spdk_iscsi_opts != NULL) {
SPDK_ERRLOG("this RPC must not be called more than once.\n");
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"Must not call more than once");
return;
}
opts = spdk_iscsi_opts_alloc();
if (opts == NULL) {
SPDK_ERRLOG("spdk_iscsi_opts_alloc() failed.\n");
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"Out of memory");
return;
}
if (params != NULL) {
if (spdk_json_decode_object(params, rpc_set_iscsi_opts_decoders,
SPDK_COUNTOF(rpc_set_iscsi_opts_decoders), opts)) {
SPDK_ERRLOG("spdk_json_decode_object() failed\n");
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
"Invalid parameters");
return;
}
}
g_spdk_iscsi_opts = spdk_iscsi_opts_copy(opts);
spdk_iscsi_opts_free(opts);
if (g_spdk_iscsi_opts == NULL) {
SPDK_ERRLOG("spdk_iscsi_opts_copy() failed\n");
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"Out of memory");
return;
}
w = spdk_jsonrpc_begin_result(request);
if (w == NULL) {
return;
}
spdk_json_write_bool(w, true);
spdk_jsonrpc_end_result(request, w);
}
SPDK_RPC_REGISTER("set_iscsi_options", spdk_rpc_iscsi_set_opts, SPDK_RPC_STARTUP)

View File

@ -346,6 +346,7 @@ enum spdk_error_codes {
#define xstrdup(s) (s ? strdup(s) : (char *)NULL)
extern struct spdk_iscsi_globals g_spdk_iscsi;
extern struct spdk_iscsi_opts *g_spdk_iscsi_opts;
struct spdk_iscsi_task;
struct spdk_json_write_ctx;
@ -359,6 +360,10 @@ void spdk_shutdown_iscsi_conns_done(void);
void spdk_iscsi_config_text(FILE *fp);
void spdk_iscsi_config_json(struct spdk_json_write_ctx *w);
struct spdk_iscsi_opts *spdk_iscsi_opts_alloc(void);
void spdk_iscsi_opts_free(struct spdk_iscsi_opts *opts);
struct spdk_iscsi_opts *spdk_iscsi_opts_copy(struct spdk_iscsi_opts *src);
void spdk_iscsi_send_nopin(struct spdk_iscsi_conn *conn);
void spdk_iscsi_task_response(struct spdk_iscsi_conn *conn,
struct spdk_iscsi_task *task);

View File

@ -47,6 +47,8 @@
#include "spdk_internal/event.h"
#include "spdk_internal/log.h"
struct spdk_iscsi_opts *g_spdk_iscsi_opts = NULL;
static spdk_iscsi_init_cb g_init_cb_fn = NULL;
static void *g_init_cb_arg = NULL;
@ -397,11 +399,78 @@ spdk_iscsi_opts_init(struct spdk_iscsi_opts *opts)
opts->min_connections_per_core = DEFAULT_CONNECTIONS_PER_LCORE;
}
static void
struct spdk_iscsi_opts *
spdk_iscsi_opts_alloc(void)
{
struct spdk_iscsi_opts *opts;
opts = calloc(1, sizeof(*opts));
if (!opts) {
SPDK_ERRLOG("calloc() failed for iscsi options\n");
return NULL;
}
spdk_iscsi_opts_init(opts);
return opts;
}
void
spdk_iscsi_opts_free(struct spdk_iscsi_opts *opts)
{
free(opts->authfile);
free(opts->nodebase);
free(opts);
}
/* Deep copy of spdk_iscsi_opts */
struct spdk_iscsi_opts *
spdk_iscsi_opts_copy(struct spdk_iscsi_opts *src)
{
struct spdk_iscsi_opts *dst;
dst = calloc(1, sizeof(*dst));
if (!dst) {
SPDK_ERRLOG("calloc() failed for iscsi options\n");
return NULL;
}
if (src->authfile) {
dst->authfile = strdup(src->authfile);
if (!dst->authfile) {
free(dst);
SPDK_ERRLOG("failed to strdup for auth file %s\n", src->authfile);
return NULL;
}
}
if (src->nodebase) {
dst->nodebase = strdup(src->nodebase);
if (!dst->nodebase) {
free(dst->authfile);
free(dst);
SPDK_ERRLOG("failed to strdup for nodebase %s\n", src->nodebase);
return NULL;
}
}
dst->MaxSessions = src->MaxSessions;
dst->MaxConnectionsPerSession = src->MaxConnectionsPerSession;
dst->MaxQueueDepth = src->MaxQueueDepth;
dst->DefaultTime2Wait = src->DefaultTime2Wait;
dst->DefaultTime2Retain = src->DefaultTime2Retain;
dst->ImmediateData = src->ImmediateData;
dst->AllowDuplicateIsid = src->AllowDuplicateIsid;
dst->ErrorRecoveryLevel = src->ErrorRecoveryLevel;
dst->timeout = src->timeout;
dst->nopininterval = src->nopininterval;
dst->no_discovery_auth = src->no_discovery_auth;
dst->req_discovery_auth = src->req_discovery_auth;
dst->req_discovery_auth_mutual = src->req_discovery_auth;
dst->discovery_auth_group = src->discovery_auth_group;
dst->min_connections_per_core = src->min_connections_per_core;
return dst;
}
static int
@ -611,6 +680,36 @@ spdk_iscsi_opts_verify(struct spdk_iscsi_opts *opts)
return 0;
}
static int
spdk_iscsi_parse_options(struct spdk_iscsi_opts **popts)
{
struct spdk_iscsi_opts *opts;
struct spdk_conf_section *sp;
int rc;
opts = spdk_iscsi_opts_alloc();
if (!opts) {
SPDK_ERRLOG("spdk_iscsi_opts_alloc_failed() failed\n");
return -ENOMEM;
}
/* Process parameters */
SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "spdk_iscsi_read_config_file_parmas\n");
sp = spdk_conf_find_section(NULL, "iSCSI");
if (sp != NULL) {
rc = spdk_iscsi_read_config_file_params(sp, opts);
if (rc != 0) {
free(opts);
SPDK_ERRLOG("spdk_iscsi_read_config_file_params() failed\n");
return rc;
}
}
*popts = opts;
return 0;
}
static int
spdk_iscsi_set_global_params(struct spdk_iscsi_opts *opts)
{
@ -659,29 +758,24 @@ spdk_iscsi_set_global_params(struct spdk_iscsi_opts *opts)
static int
spdk_iscsi_initialize_global_params(void)
{
struct spdk_conf_section *sp;
struct spdk_iscsi_opts opts;
int rc;
spdk_iscsi_opts_init(&opts);
/* Process parameters */
SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "spdk_iscsi_read_config_file_parmas\n");
sp = spdk_conf_find_section(NULL, "iSCSI");
if (sp != NULL) {
rc = spdk_iscsi_read_config_file_params(sp, &opts);
if (!g_spdk_iscsi_opts) {
rc = spdk_iscsi_parse_options(&g_spdk_iscsi_opts);
if (rc != 0) {
SPDK_ERRLOG("spdk_iscsi_read_config_file_params() failed\n");
SPDK_ERRLOG("spdk_iscsi_parse_options() failed\n");
return rc;
}
}
rc = spdk_iscsi_set_global_params(&opts);
spdk_iscsi_opts_free(&opts);
rc = spdk_iscsi_set_global_params(g_spdk_iscsi_opts);
if (rc != 0) {
SPDK_ERRLOG("spdk_iscsi_set_global_params() failed\n");
}
spdk_iscsi_opts_free(g_spdk_iscsi_opts);
g_spdk_iscsi_opts = NULL;
return rc;
}

View File

@ -313,6 +313,31 @@ if __name__ == "__main__":
p.set_defaults(func=apply_firmware)
# iSCSI
def set_iscsi_options(args):
rpc.iscsi.set_iscsi_options(args.client, args)
p = subparsers.add_parser('set_iscsi_options', help="""Set options of iSCSI subsystem""")
p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file for discovery session')
p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node')
p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int)
p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int)
p.add_argument('-d', '--no-discovery-auth', help="""CHAP for discovery session should be disabled.
*** Mutually exclusive with --req-discovery-auth""", action='store_true')
p.add_argument('-r', '--req-discovery-auth', help="""CHAP for discovery session should be required.
*** Mutually exclusive with --no-discovery-auth""", action='store_true')
p.add_argument('-m', '--req-discovery-auth-mutual', help='CHAP for discovery session should be mutual', action='store_true')
p.add_argument('-g', '--discovery-auth-group', help="""Authentication group ID for discovery session.
*** Authentication group must be precreated ***""", type=int)
p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int)
p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int)
p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int)
p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int)
p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true')
p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int)
p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true')
p.add_argument('-u', '--min-connections-per-session', help='Allocation unit of connections per core', type=int)
p.set_defaults(func=set_iscsi_options)
@call_cmd
def get_portal_groups(args):
print_dict(rpc.iscsi.get_portal_groups(args.client, args))

View File

@ -1,3 +1,41 @@
def set_iscsi_options(client, args):
params = {}
if args.auth_file:
params['auth_file'] = args.auth_file
if args.node_base:
params['node_base'] = args.node_base
if args.nop_timeout:
params['nop_timeout'] = args.nop_timeout
if args.nop_in_interval:
params['nop_in_interval'] = args.nop_in_interval
if args.no_discovery_auth:
params['no_discovery_auth'] = args.no_discovery_auth
if args.req_discovery_auth:
params['req_discovery_auth'] = args.req_discovery_auth
if args.req_discovery_auth_mutual:
params['req_discovery_auth_mutual'] = args.req_discovery_auth_mutual
if args.discovery_auth_group:
params['discovery_auth_group'] = args.discovery_auth_group
if args.max_sessions:
params['max_sessions'] = args.max_sessions
if args.max_connections_per_session:
params['max_connections_per_session'] = args.max_connections_per_session
if args.default_time2wait:
params['default_time2wait'] = args.default_time2wait
if args.default_time2retain:
params['default_time2retain'] = args.default_time2retain
if args.immediate_data:
params['immediate_data'] = args.immediate_data
if args.error_recovery_level:
params['error_recovery_level'] = args.error_recovery_level
if args.allow_duplicated_isid:
params['allow_duplicated_isid'] = args.allow_duplicated_isid
if args.min_connections_per_session:
params['min_connections_per_session'] = args.min_connections_per_session
return client.call('set_iscsi_options', params)
def get_portal_groups(client, args):
return client.call('get_portal_groups')