1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2016 Intel Corporation. All rights reserved. 3 * Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved. 4 * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 5 */ 6 7 #include <sys/file.h> 8 9 #include "spdk/stdinc.h" 10 11 #include "spdk/queue.h" 12 #include "spdk/rpc.h" 13 #include "spdk/env.h" 14 #include "spdk/log.h" 15 #include "spdk/string.h" 16 #include "spdk/util.h" 17 #include "spdk/version.h" 18 19 static struct sockaddr_un g_rpc_listen_addr_unix = {}; 20 static char g_rpc_lock_path[sizeof(g_rpc_listen_addr_unix.sun_path) + sizeof(".lock")]; 21 static int g_rpc_lock_fd = -1; 22 23 static struct spdk_jsonrpc_server *g_jsonrpc_server = NULL; 24 static uint32_t g_rpc_state = SPDK_RPC_STARTUP; 25 static bool g_rpcs_correct = true; 26 static char **g_rpcs_allowlist = NULL; 27 28 struct spdk_rpc_method { 29 const char *name; 30 spdk_rpc_method_handler func; 31 SLIST_ENTRY(spdk_rpc_method) slist; 32 uint32_t state_mask; 33 bool is_deprecated; 34 struct spdk_rpc_method *is_alias_of; 35 bool deprecation_warning_printed; 36 }; 37 38 static SLIST_HEAD(, spdk_rpc_method) g_rpc_methods = SLIST_HEAD_INITIALIZER(g_rpc_methods); 39 40 void 41 spdk_rpc_set_state(uint32_t state) 42 { 43 g_rpc_state = state; 44 } 45 46 uint32_t 47 spdk_rpc_get_state(void) 48 { 49 return g_rpc_state; 50 } 51 52 static bool 53 rpc_is_allowed(const char *name) 54 { 55 size_t i; 56 57 if (g_rpcs_allowlist == NULL) { 58 return true; 59 } 60 61 for (i = 0; g_rpcs_allowlist[i] != NULL; i++) { 62 if (strcmp(name, g_rpcs_allowlist[i]) == 0) { 63 return true; 64 } 65 } 66 67 return false; 68 } 69 70 71 static struct spdk_rpc_method * 72 _get_rpc_method(const struct spdk_json_val *method) 73 { 74 struct spdk_rpc_method *m; 75 76 SLIST_FOREACH(m, &g_rpc_methods, slist) { 77 if (spdk_json_strequal(method, m->name)) { 78 if (!rpc_is_allowed(m->name)) { 79 return NULL; 80 } 81 return m; 82 } 83 } 84 85 return NULL; 86 } 87 88 static struct spdk_rpc_method * 89 _get_rpc_method_raw(const char *method) 90 { 91 struct spdk_json_val method_val; 92 93 method_val.type = SPDK_JSON_VAL_STRING; 94 method_val.len = strlen(method); 95 method_val.start = (char *)method; 96 97 return _get_rpc_method(&method_val); 98 } 99 100 static void 101 jsonrpc_handler(struct spdk_jsonrpc_request *request, 102 const struct spdk_json_val *method, 103 const struct spdk_json_val *params) 104 { 105 struct spdk_rpc_method *m; 106 107 assert(method != NULL); 108 109 m = _get_rpc_method(method); 110 if (m == NULL) { 111 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_METHOD_NOT_FOUND, "Method not found"); 112 return; 113 } 114 115 if (m->is_alias_of != NULL) { 116 if (m->is_deprecated && !m->deprecation_warning_printed) { 117 SPDK_WARNLOG("RPC method %s is deprecated. Use %s instead.\n", m->name, m->is_alias_of->name); 118 m->deprecation_warning_printed = true; 119 } 120 m = m->is_alias_of; 121 } 122 123 if ((m->state_mask & g_rpc_state) == g_rpc_state) { 124 m->func(request, params); 125 } else { 126 if (g_rpc_state == SPDK_RPC_STARTUP) { 127 spdk_jsonrpc_send_error_response_fmt(request, 128 SPDK_JSONRPC_ERROR_INVALID_STATE, 129 "Method may only be called after " 130 "framework is initialized " 131 "using framework_start_init RPC."); 132 } else { 133 spdk_jsonrpc_send_error_response_fmt(request, 134 SPDK_JSONRPC_ERROR_INVALID_STATE, 135 "Method may only be called before " 136 "framework is initialized. " 137 "Use --wait-for-rpc command line " 138 "parameter and then issue this RPC " 139 "before the framework_start_init RPC."); 140 } 141 } 142 } 143 144 int 145 spdk_rpc_listen(const char *listen_addr) 146 { 147 int rc; 148 149 memset(&g_rpc_listen_addr_unix, 0, sizeof(g_rpc_listen_addr_unix)); 150 151 g_rpc_listen_addr_unix.sun_family = AF_UNIX; 152 rc = snprintf(g_rpc_listen_addr_unix.sun_path, 153 sizeof(g_rpc_listen_addr_unix.sun_path), 154 "%s", listen_addr); 155 if (rc < 0 || (size_t)rc >= sizeof(g_rpc_listen_addr_unix.sun_path)) { 156 SPDK_ERRLOG("RPC Listen address Unix socket path too long\n"); 157 g_rpc_listen_addr_unix.sun_path[0] = '\0'; 158 return -1; 159 } 160 161 rc = snprintf(g_rpc_lock_path, sizeof(g_rpc_lock_path), "%s.lock", 162 g_rpc_listen_addr_unix.sun_path); 163 if (rc < 0 || (size_t)rc >= sizeof(g_rpc_lock_path)) { 164 SPDK_ERRLOG("RPC lock path too long\n"); 165 g_rpc_listen_addr_unix.sun_path[0] = '\0'; 166 g_rpc_lock_path[0] = '\0'; 167 return -1; 168 } 169 170 g_rpc_lock_fd = open(g_rpc_lock_path, O_RDWR | O_CREAT, 0600); 171 if (g_rpc_lock_fd == -1) { 172 SPDK_ERRLOG("Cannot open lock file %s: %s\n", 173 g_rpc_lock_path, spdk_strerror(errno)); 174 g_rpc_listen_addr_unix.sun_path[0] = '\0'; 175 g_rpc_lock_path[0] = '\0'; 176 return -1; 177 } 178 179 rc = flock(g_rpc_lock_fd, LOCK_EX | LOCK_NB); 180 if (rc != 0) { 181 SPDK_ERRLOG("RPC Unix domain socket path %s in use. Specify another.\n", 182 g_rpc_listen_addr_unix.sun_path); 183 g_rpc_listen_addr_unix.sun_path[0] = '\0'; 184 g_rpc_lock_path[0] = '\0'; 185 return -1; 186 } 187 188 /* 189 * Since we acquired the lock, it is safe to delete the Unix socket file 190 * if it still exists from a previous process. 191 */ 192 unlink(g_rpc_listen_addr_unix.sun_path); 193 194 g_jsonrpc_server = spdk_jsonrpc_server_listen(AF_UNIX, 0, 195 (struct sockaddr *)&g_rpc_listen_addr_unix, 196 sizeof(g_rpc_listen_addr_unix), 197 jsonrpc_handler); 198 if (g_jsonrpc_server == NULL) { 199 SPDK_ERRLOG("spdk_jsonrpc_server_listen() failed\n"); 200 close(g_rpc_lock_fd); 201 g_rpc_lock_fd = -1; 202 unlink(g_rpc_lock_path); 203 g_rpc_lock_path[0] = '\0'; 204 return -1; 205 } 206 207 return 0; 208 } 209 210 void 211 spdk_rpc_accept(void) 212 { 213 spdk_jsonrpc_server_poll(g_jsonrpc_server); 214 } 215 216 void 217 spdk_rpc_register_method(const char *method, spdk_rpc_method_handler func, uint32_t state_mask) 218 { 219 struct spdk_rpc_method *m; 220 221 m = _get_rpc_method_raw(method); 222 if (m != NULL) { 223 SPDK_ERRLOG("duplicate RPC %s registered...\n", method); 224 g_rpcs_correct = false; 225 return; 226 } 227 228 m = calloc(1, sizeof(struct spdk_rpc_method)); 229 assert(m != NULL); 230 231 m->name = strdup(method); 232 assert(m->name != NULL); 233 234 m->func = func; 235 m->state_mask = state_mask; 236 237 /* TODO: use a hash table or sorted list */ 238 SLIST_INSERT_HEAD(&g_rpc_methods, m, slist); 239 } 240 241 void 242 spdk_rpc_register_alias_deprecated(const char *method, const char *alias) 243 { 244 struct spdk_rpc_method *m, *base; 245 246 base = _get_rpc_method_raw(method); 247 if (base == NULL) { 248 SPDK_ERRLOG("cannot create alias %s - method %s does not exist\n", 249 alias, method); 250 g_rpcs_correct = false; 251 return; 252 } 253 254 if (base->is_alias_of != NULL) { 255 SPDK_ERRLOG("cannot create alias %s of alias %s\n", alias, method); 256 g_rpcs_correct = false; 257 return; 258 } 259 260 m = calloc(1, sizeof(struct spdk_rpc_method)); 261 assert(m != NULL); 262 263 m->name = strdup(alias); 264 assert(m->name != NULL); 265 266 m->is_alias_of = base; 267 m->is_deprecated = true; 268 m->state_mask = base->state_mask; 269 270 /* TODO: use a hash table or sorted list */ 271 SLIST_INSERT_HEAD(&g_rpc_methods, m, slist); 272 } 273 274 bool 275 spdk_rpc_verify_methods(void) 276 { 277 return g_rpcs_correct; 278 } 279 280 int 281 spdk_rpc_is_method_allowed(const char *method, uint32_t state_mask) 282 { 283 struct spdk_rpc_method *m; 284 285 if (!rpc_is_allowed(method)) { 286 return -ENOENT; 287 } 288 289 SLIST_FOREACH(m, &g_rpc_methods, slist) { 290 if (strcmp(m->name, method) != 0) { 291 continue; 292 } 293 294 if ((m->state_mask & state_mask) == state_mask) { 295 return 0; 296 } else { 297 return -EPERM; 298 } 299 } 300 301 return -ENOENT; 302 } 303 304 int 305 spdk_rpc_get_method_state_mask(const char *method, uint32_t *state_mask) 306 { 307 struct spdk_rpc_method *m; 308 309 SLIST_FOREACH(m, &g_rpc_methods, slist) { 310 if (strcmp(m->name, method) == 0) { 311 *state_mask = m->state_mask; 312 return 0; 313 } 314 } 315 316 return -ENOENT; 317 } 318 319 void 320 spdk_rpc_set_allowlist(const char **rpc_allowlist) 321 { 322 spdk_strarray_free(g_rpcs_allowlist); 323 324 if (rpc_allowlist == NULL) { 325 g_rpcs_allowlist = NULL; 326 return; 327 } 328 329 g_rpcs_allowlist = spdk_strarray_dup(rpc_allowlist); 330 assert(g_rpcs_allowlist != NULL); 331 } 332 333 void 334 spdk_rpc_close(void) 335 { 336 if (g_jsonrpc_server) { 337 if (g_rpc_listen_addr_unix.sun_path[0]) { 338 /* Delete the Unix socket file */ 339 unlink(g_rpc_listen_addr_unix.sun_path); 340 g_rpc_listen_addr_unix.sun_path[0] = '\0'; 341 } 342 343 spdk_jsonrpc_server_shutdown(g_jsonrpc_server); 344 g_jsonrpc_server = NULL; 345 346 if (g_rpc_lock_fd != -1) { 347 close(g_rpc_lock_fd); 348 g_rpc_lock_fd = -1; 349 } 350 351 if (g_rpc_lock_path[0]) { 352 unlink(g_rpc_lock_path); 353 g_rpc_lock_path[0] = '\0'; 354 } 355 } 356 } 357 358 struct rpc_get_methods { 359 bool current; 360 bool include_aliases; 361 }; 362 363 static const struct spdk_json_object_decoder rpc_get_methods_decoders[] = { 364 {"current", offsetof(struct rpc_get_methods, current), spdk_json_decode_bool, true}, 365 {"include_aliases", offsetof(struct rpc_get_methods, include_aliases), spdk_json_decode_bool, true}, 366 }; 367 368 static void 369 rpc_get_methods(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) 370 { 371 struct rpc_get_methods req = {}; 372 struct spdk_json_write_ctx *w; 373 struct spdk_rpc_method *m; 374 375 if (params != NULL) { 376 if (spdk_json_decode_object(params, rpc_get_methods_decoders, 377 SPDK_COUNTOF(rpc_get_methods_decoders), &req)) { 378 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 379 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 380 "Invalid parameters"); 381 return; 382 } 383 } 384 385 w = spdk_jsonrpc_begin_result(request); 386 spdk_json_write_array_begin(w); 387 SLIST_FOREACH(m, &g_rpc_methods, slist) { 388 if (!rpc_is_allowed(m->name)) { 389 continue; 390 } 391 if (m->is_alias_of != NULL && !req.include_aliases) { 392 continue; 393 } 394 if (req.current && ((m->state_mask & g_rpc_state) != g_rpc_state)) { 395 continue; 396 } 397 spdk_json_write_string(w, m->name); 398 } 399 spdk_json_write_array_end(w); 400 spdk_jsonrpc_end_result(request, w); 401 } 402 SPDK_RPC_REGISTER("rpc_get_methods", rpc_get_methods, SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME) 403 404 static void 405 rpc_spdk_get_version(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) 406 { 407 struct spdk_json_write_ctx *w; 408 409 if (params != NULL) { 410 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 411 "spdk_get_version method requires no parameters"); 412 return; 413 } 414 415 w = spdk_jsonrpc_begin_result(request); 416 spdk_json_write_object_begin(w); 417 418 spdk_json_write_named_string_fmt(w, "version", "%s", SPDK_VERSION_STRING); 419 spdk_json_write_named_object_begin(w, "fields"); 420 spdk_json_write_named_uint32(w, "major", SPDK_VERSION_MAJOR); 421 spdk_json_write_named_uint32(w, "minor", SPDK_VERSION_MINOR); 422 spdk_json_write_named_uint32(w, "patch", SPDK_VERSION_PATCH); 423 spdk_json_write_named_string_fmt(w, "suffix", "%s", SPDK_VERSION_SUFFIX); 424 #ifdef SPDK_GIT_COMMIT 425 spdk_json_write_named_string_fmt(w, "commit", "%s", SPDK_GIT_COMMIT_STRING); 426 #endif 427 spdk_json_write_object_end(w); 428 429 spdk_json_write_object_end(w); 430 spdk_jsonrpc_end_result(request, w); 431 } 432 SPDK_RPC_REGISTER("spdk_get_version", rpc_spdk_get_version, 433 SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME) 434