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