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