1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2016 Intel Corporation. All rights reserved. 3 * Copyright (c) 2018-2019 Mellanox Technologies LTD. All rights reserved. 4 * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 5 */ 6 7 #include "event_nvmf.h" 8 9 #include "spdk/rpc.h" 10 #include "spdk/util.h" 11 #include "spdk/cpuset.h" 12 13 static const struct spdk_json_object_decoder nvmf_rpc_subsystem_tgt_opts_decoder[] = { 14 {"max_subsystems", 0, spdk_json_decode_uint32, true} 15 }; 16 17 static void 18 rpc_nvmf_set_max_subsystems(struct spdk_jsonrpc_request *request, 19 const struct spdk_json_val *params) 20 { 21 uint32_t max_subsystems = 0; 22 23 if (g_spdk_nvmf_tgt_conf.opts.max_subsystems != 0) { 24 SPDK_ERRLOG("this RPC must not be called more than once.\n"); 25 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 26 "Must not call more than once"); 27 return; 28 } 29 30 if (params != NULL) { 31 if (spdk_json_decode_object(params, nvmf_rpc_subsystem_tgt_opts_decoder, 32 SPDK_COUNTOF(nvmf_rpc_subsystem_tgt_opts_decoder), &max_subsystems)) { 33 SPDK_ERRLOG("spdk_json_decode_object() failed\n"); 34 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 35 "Invalid parameters"); 36 return; 37 } 38 } 39 40 g_spdk_nvmf_tgt_conf.opts.max_subsystems = max_subsystems; 41 42 spdk_jsonrpc_send_bool_response(request, true); 43 } 44 SPDK_RPC_REGISTER("nvmf_set_max_subsystems", rpc_nvmf_set_max_subsystems, 45 SPDK_RPC_STARTUP) 46 47 static const struct spdk_json_object_decoder admin_passthru_decoder[] = { 48 {"identify_ctrlr", offsetof(struct spdk_nvmf_admin_passthru_conf, identify_ctrlr), spdk_json_decode_bool} 49 }; 50 51 static int 52 decode_admin_passthru(const struct spdk_json_val *val, void *out) 53 { 54 struct spdk_nvmf_admin_passthru_conf *req = (struct spdk_nvmf_admin_passthru_conf *)out; 55 56 if (spdk_json_decode_object(val, admin_passthru_decoder, 57 SPDK_COUNTOF(admin_passthru_decoder), 58 req)) { 59 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 60 return -1; 61 } 62 63 return 0; 64 } 65 66 static int 67 decode_discovery_filter(const struct spdk_json_val *val, void *out) 68 { 69 uint32_t *_filter = out; 70 uint32_t filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY; 71 char *tokens = spdk_json_strdup(val); 72 char *tok; 73 char *sp = NULL; 74 int rc = -EINVAL; 75 bool all_specified = false; 76 77 if (!tokens) { 78 return -ENOMEM; 79 } 80 81 tok = strtok_r(tokens, ",", &sp); 82 while (tok) { 83 if (strncmp(tok, "match_any", 9) == 0) { 84 if (filter != SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY) { 85 goto out; 86 } 87 filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY; 88 all_specified = true; 89 } else { 90 if (all_specified) { 91 goto out; 92 } 93 if (strncmp(tok, "transport", 9) == 0) { 94 filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE; 95 } else if (strncmp(tok, "address", 7) == 0) { 96 filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS; 97 } else if (strncmp(tok, "svcid", 5) == 0) { 98 filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID; 99 } else { 100 SPDK_ERRLOG("Invalid value %s\n", tok); 101 goto out; 102 } 103 } 104 105 tok = strtok_r(NULL, ",", &sp); 106 } 107 108 rc = 0; 109 *_filter = filter; 110 111 out: 112 free(tokens); 113 114 return rc; 115 } 116 117 static int 118 nvmf_is_subset_of_env_core_mask(const struct spdk_cpuset *set) 119 { 120 uint32_t i, tmp_counter = 0; 121 122 SPDK_ENV_FOREACH_CORE(i) { 123 if (spdk_cpuset_get_cpu(set, i)) { 124 ++tmp_counter; 125 } 126 } 127 return spdk_cpuset_count(set) - tmp_counter; 128 } 129 130 static int 131 nvmf_decode_poll_groups_mask(const struct spdk_json_val *val, void *out) 132 { 133 char *mask = spdk_json_strdup(val); 134 int ret = -1; 135 136 if (mask == NULL) { 137 return -1; 138 } 139 140 if (!(g_poll_groups_mask = spdk_cpuset_alloc())) { 141 SPDK_ERRLOG("Unable to allocate a poll groups mask object in nvmf_decode_poll_groups_mask.\n"); 142 free(mask); 143 return -1; 144 } 145 146 ret = spdk_cpuset_parse(g_poll_groups_mask, mask); 147 free(mask); 148 if (ret == 0) { 149 if (nvmf_is_subset_of_env_core_mask(g_poll_groups_mask) == 0) { 150 return 0; 151 } else { 152 SPDK_ERRLOG("Poll groups cpumask 0x%s is out of range\n", spdk_cpuset_fmt(g_poll_groups_mask)); 153 } 154 } else { 155 SPDK_ERRLOG("Invalid cpumask\n"); 156 } 157 158 spdk_cpuset_free(g_poll_groups_mask); 159 g_poll_groups_mask = NULL; 160 return -1; 161 } 162 163 static int 164 decode_digest(const struct spdk_json_val *val, void *out) 165 { 166 uint32_t *flags = out; 167 char *digest = NULL; 168 int rc; 169 170 rc = spdk_json_decode_string(val, &digest); 171 if (rc != 0) { 172 return rc; 173 } 174 175 rc = spdk_nvme_dhchap_get_digest_id(digest); 176 if (rc >= 0) { 177 *flags |= SPDK_BIT(rc); 178 rc = 0; 179 } 180 free(digest); 181 182 return rc; 183 } 184 185 static int 186 decode_digest_array(const struct spdk_json_val *val, void *out) 187 { 188 uint32_t *flags = out; 189 size_t count; 190 191 *flags = 0; 192 193 return spdk_json_decode_array(val, decode_digest, out, 32, &count, 0); 194 } 195 196 static int 197 decode_dhgroup(const struct spdk_json_val *val, void *out) 198 { 199 uint32_t *flags = out; 200 char *dhgroup = NULL; 201 int rc; 202 203 rc = spdk_json_decode_string(val, &dhgroup); 204 if (rc != 0) { 205 return rc; 206 } 207 208 rc = spdk_nvme_dhchap_get_dhgroup_id(dhgroup); 209 if (rc >= 0) { 210 *flags |= SPDK_BIT(rc); 211 rc = 0; 212 } 213 free(dhgroup); 214 215 return rc; 216 } 217 218 static int 219 decode_dhgroup_array(const struct spdk_json_val *val, void *out) 220 { 221 uint32_t *flags = out; 222 size_t count; 223 224 *flags = 0; 225 226 return spdk_json_decode_array(val, decode_dhgroup, out, 32, &count, 0); 227 } 228 229 static const struct spdk_json_object_decoder nvmf_rpc_subsystem_tgt_conf_decoder[] = { 230 {"admin_cmd_passthru", offsetof(struct spdk_nvmf_tgt_conf, admin_passthru), decode_admin_passthru, true}, 231 {"poll_groups_mask", 0, nvmf_decode_poll_groups_mask, true}, 232 {"discovery_filter", offsetof(struct spdk_nvmf_tgt_conf, opts.discovery_filter), decode_discovery_filter, true}, 233 {"dhchap_digests", offsetof(struct spdk_nvmf_tgt_conf, opts.dhchap_digests), decode_digest_array, true}, 234 {"dhchap_dhgroups", offsetof(struct spdk_nvmf_tgt_conf, opts.dhchap_dhgroups), decode_dhgroup_array, true}, 235 }; 236 237 static void 238 rpc_nvmf_set_config(struct spdk_jsonrpc_request *request, 239 const struct spdk_json_val *params) 240 { 241 struct spdk_nvmf_tgt_conf conf; 242 243 memcpy(&conf, &g_spdk_nvmf_tgt_conf, sizeof(conf)); 244 245 if (params != NULL) { 246 if (spdk_json_decode_object(params, nvmf_rpc_subsystem_tgt_conf_decoder, 247 SPDK_COUNTOF(nvmf_rpc_subsystem_tgt_conf_decoder), &conf)) { 248 SPDK_ERRLOG("spdk_json_decode_object() failed\n"); 249 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 250 "Invalid parameters"); 251 return; 252 } 253 } 254 255 memcpy(&g_spdk_nvmf_tgt_conf, &conf, sizeof(conf)); 256 257 spdk_jsonrpc_send_bool_response(request, true); 258 } 259 SPDK_RPC_REGISTER("nvmf_set_config", rpc_nvmf_set_config, SPDK_RPC_STARTUP) 260 261 struct nvmf_rpc_set_crdt { 262 uint16_t crdt1; 263 uint16_t crdt2; 264 uint16_t crdt3; 265 }; 266 267 static const struct spdk_json_object_decoder rpc_set_crdt_opts_decoders[] = { 268 {"crdt1", offsetof(struct nvmf_rpc_set_crdt, crdt1), spdk_json_decode_uint16, true}, 269 {"crdt2", offsetof(struct nvmf_rpc_set_crdt, crdt2), spdk_json_decode_uint16, true}, 270 {"crdt3", offsetof(struct nvmf_rpc_set_crdt, crdt3), spdk_json_decode_uint16, true}, 271 }; 272 273 static void 274 rpc_nvmf_set_crdt(struct spdk_jsonrpc_request *request, 275 const struct spdk_json_val *params) 276 { 277 struct nvmf_rpc_set_crdt rpc_set_crdt; 278 279 rpc_set_crdt.crdt1 = 0; 280 rpc_set_crdt.crdt2 = 0; 281 rpc_set_crdt.crdt3 = 0; 282 283 if (params != NULL) { 284 if (spdk_json_decode_object(params, rpc_set_crdt_opts_decoders, 285 SPDK_COUNTOF(rpc_set_crdt_opts_decoders), &rpc_set_crdt)) { 286 SPDK_ERRLOG("spdk_json_decode_object() failed\n"); 287 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 288 "Invalid parameters"); 289 return; 290 } 291 } 292 293 g_spdk_nvmf_tgt_conf.opts.crdt[0] = rpc_set_crdt.crdt1; 294 g_spdk_nvmf_tgt_conf.opts.crdt[1] = rpc_set_crdt.crdt2; 295 g_spdk_nvmf_tgt_conf.opts.crdt[2] = rpc_set_crdt.crdt3; 296 297 spdk_jsonrpc_send_bool_response(request, true); 298 } 299 SPDK_RPC_REGISTER("nvmf_set_crdt", rpc_nvmf_set_crdt, SPDK_RPC_STARTUP) 300