iscsi: Add set_iscsi_target_node_auth RPC to configure CHAP dynamically

An new RPC set_iscsi_target_node_auth enables users to configure CHAP
authentication for the target node dynamically.

New setting is used for new iSCSI sessions. For existing iSCSI sessions,
new setting is not used until user logout and login again.

Try to use descriptive message in the RPC when error occurs.

Change-Id: I0bd40d92262d708c1f7de0effb208078bdf8cc41
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/420974
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Shuhei Matsumoto 2018-08-20 09:12:59 +09:00 committed by Jim Harris
parent 6cd1714a99
commit 844735c928
7 changed files with 197 additions and 2 deletions

View File

@ -29,8 +29,9 @@ method for CHAP authentication in discovery sessions have been changed to
align with `construct_target_node` RPC method. Old names are still usable
but will be removed in future release.
`set_iscsi_discovery_auth` RPC method has been added to set CHAP authentication
for discovery sessions dynamically.
`set_iscsi_discovery_auth` and `set_iscsi_target_node_auth` RPC methods have
been added to set CHAP authentication for discovery sessions and existing
target nodes, respectively.
## v18.07:

View File

@ -2184,6 +2184,8 @@ chap_group | Optional | number | Authentication group ID for t
header_digest | Optional | boolean | Header Digest should be required for this target node
data_digest | Optional | boolean | Data Digest should be required for this target node
Parameters `disable_chap` and `require_chap` are mutually exclusive.
### Example
Example request:
@ -2231,6 +2233,50 @@ Example response:
}
~~~
## set_iscsi_target_node_auth method {#rpc_set_iscsi_target_node_auth}
Set CHAP authentication to an existing iSCSI target node.
### Parameters
Name | Optional | Type | Description
--------------------------- | -------- | --------| -----------
name | Required | string | Target node name (ASCII)
disable_chap | Optional | boolean | CHAP authentication should be disabled for this target
require_chap | Optional | boolean | CHAP authentication should be required for this target
mutual_chap | Optional | boolean | CHAP authentication should be bidirectional (`true`) or unidirectional (`false`)
chap_group | Optional | number | Authentication group ID for this target node
Parameters `disable_chap` and `require_chap` are mutually exclusive.
### Example
Example request:
~~~
{
"params": {
"chap_group": 1,
"require_chap": true,
"name": "iqn.2016-06.io.spdk:target1",
"mutual_chap": true
},
"jsonrpc": "2.0",
"method": "set_iscsi_target_node_auth",
"id": 1
}
~~~
Example response:
~~~
{
"jsonrpc": "2.0",
"id": 1,
"result": true
}
~~~
## add_pg_ig_maps method {#rpc_add_pg_ig_maps}
Add initiator group to portal group mappings to an existing iSCSI target node.

View File

@ -1035,6 +1035,75 @@ invalid:
}
SPDK_RPC_REGISTER("target_node_add_lun", spdk_rpc_target_node_add_lun, SPDK_RPC_RUNTIME)
struct rpc_target_auth {
char *name;
bool disable_chap;
bool require_chap;
bool mutual_chap;
int32_t chap_group;
};
static void
free_rpc_target_auth(struct rpc_target_auth *req)
{
free(req->name);
}
static const struct spdk_json_object_decoder rpc_target_auth_decoders[] = {
{"name", offsetof(struct rpc_target_auth, name), spdk_json_decode_string},
{"disable_chap", offsetof(struct rpc_target_auth, disable_chap), spdk_json_decode_bool, true},
{"require_chap", offsetof(struct rpc_target_auth, require_chap), spdk_json_decode_bool, true},
{"mutual_chap", offsetof(struct rpc_target_auth, mutual_chap), spdk_json_decode_bool, true},
{"chap_group", offsetof(struct rpc_target_auth, chap_group), spdk_json_decode_int32, true},
};
static void
spdk_rpc_set_iscsi_target_node_auth(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_target_auth req = {};
struct spdk_json_write_ctx *w;
struct spdk_iscsi_tgt_node *target;
int rc;
if (spdk_json_decode_object(params, rpc_target_auth_decoders,
SPDK_COUNTOF(rpc_target_auth_decoders), &req)) {
SPDK_ERRLOG("spdk_json_decode_object failed\n");
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
"Invalid parameters");
return;
}
target = spdk_iscsi_find_tgt_node(req.name);
if (target == NULL) {
spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
"Could not find target %s", req.name);
free_rpc_target_auth(&req);
return;
}
rc = spdk_iscsi_tgt_node_set_chap_params(target, req.disable_chap, req.require_chap,
req.mutual_chap, req.chap_group);
if (rc < 0) {
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
"Invalid combination of CHAP params");
free_rpc_target_auth(&req);
return;
}
free_rpc_target_auth(&req);
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_target_node_auth", spdk_rpc_set_iscsi_target_node_auth,
SPDK_RPC_RUNTIME)
static void
spdk_rpc_get_iscsi_global_params(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)

View File

@ -1332,6 +1332,26 @@ spdk_iscsi_tgt_node_add_lun(struct spdk_iscsi_tgt_node *target,
return 0;
}
int
spdk_iscsi_tgt_node_set_chap_params(struct spdk_iscsi_tgt_node *target,
bool disable_chap, bool require_chap,
bool mutual_chap, int32_t chap_group)
{
if (!spdk_iscsi_check_chap_params(disable_chap, require_chap,
mutual_chap, chap_group)) {
return -EINVAL;
}
pthread_mutex_lock(&target->mutex);
target->disable_chap = disable_chap;
target->require_chap = require_chap;
target->mutual_chap = mutual_chap;
target->chap_group = chap_group;
pthread_mutex_unlock(&target->mutex);
return 0;
}
static const char *target_nodes_section = \
"\n"
"# Users should change the TargetNode section(s) below to match the\n"

View File

@ -137,6 +137,9 @@ void spdk_iscsi_tgt_node_delete_map(struct spdk_iscsi_portal_grp *portal_group,
struct spdk_iscsi_init_grp *initiator_group);
int spdk_iscsi_tgt_node_add_lun(struct spdk_iscsi_tgt_node *target,
const char *bdev_name, int lun_id);
int spdk_iscsi_tgt_node_set_chap_params(struct spdk_iscsi_tgt_node *target,
bool disable_chap, bool require_chap,
bool mutual_chap, int32_t chap_group);
void spdk_iscsi_tgt_nodes_config_text(FILE *fp);
void spdk_iscsi_tgt_nodes_info_json(struct spdk_json_write_ctx *w);
void spdk_iscsi_tgt_nodes_config_json(struct spdk_json_write_ctx *w);

View File

@ -644,6 +644,28 @@ if __name__ == "__main__":
*** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
p.set_defaults(func=target_node_add_lun)
@call_cmd
def set_iscsi_target_node_auth(args):
rpc.iscsi.set_iscsi_target_node_auth(
args.client,
name=args.name,
chap_group=args.chap_group,
disable_chap=args.disable_chap,
require_chap=args.require_chap,
mutual_chap=args.mutual_chap)
p = subparsers.add_parser('set_iscsi_target_node_auth', help='Set CHAP authentication for the target node')
p.add_argument('name', help='Target node name (ASCII)')
p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
*** Authentication group must be precreated ***""", type=int, default=0)
p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
*** Mutually exclusive with --require-chap ***""", action='store_true')
p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
*** Mutually exclusive with --disable-chap ***""", action='store_true')
p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
action='store_true')
p.set_defaults(func=set_iscsi_target_node_auth)
@call_cmd
def add_pg_ig_maps(args):
pg_ig_maps = []

View File

@ -215,6 +215,40 @@ def target_node_add_lun(client, name, bdev_name, lun_id=None):
return client.call('target_node_add_lun', params)
def set_iscsi_target_node_auth(
client,
name,
chap_group=None,
disable_chap=None,
require_chap=None,
mutual_chap=None):
"""Set CHAP authentication for the target node.
Args:
name: Target node name (ASCII)
chap_group: Authentication group ID for this target node
disable_chap: CHAP authentication should be disabled for this target node
require_chap: CHAP authentication should be required for this target node
mutual_chap: CHAP authentication should be mutual/bidirectional
Returns:
True or False
"""
params = {
'name': name,
}
if chap_group:
params['chap_group'] = chap_group
if disable_chap:
params['disable_chap'] = disable_chap
if require_chap:
params['require_chap'] = require_chap
if mutual_chap:
params['mutual_chap'] = mutual_chap
return client.call('set_iscsi_target_node_auth', params)
def delete_pg_ig_maps(client, pg_ig_maps, name):
"""Delete PG-IG maps from the target node.