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