1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "spdk/init.h" 37 #include "spdk/util.h" 38 #include "spdk/file.h" 39 #include "spdk/log.h" 40 #include "spdk/env.h" 41 #include "spdk/thread.h" 42 #include "spdk/jsonrpc.h" 43 #include "spdk/rpc.h" 44 45 #include "spdk_internal/event.h" 46 47 #define SPDK_DEBUG_APP_CFG(...) SPDK_DEBUGLOG(app_config, __VA_ARGS__) 48 49 /* JSON configuration format is as follows 50 * 51 * { 52 * "subsystems" : [ <<== *subsystems JSON array 53 * { <<== *subsystems_it array entry pointer (iterator) 54 * "subsystem": "<< SUBSYSTEM NAME >>", 55 * "config": [ <<== *config JSON array 56 * { <<== *config_it array entry pointer (iterator) 57 * "method": "<< METHOD NAME >>", <<== *method 58 * "params": { << PARAMS >> } <<== *params 59 * }, 60 * << MORE "config" ARRY ENTRIES >> 61 * ] 62 * }, 63 * << MORE "subsystems" ARRAY ENTRIES >> 64 * ] 65 * 66 * << ANYTHING ELSE IS IGNORRED IN ROOT OBJECT>> 67 * } 68 * 69 */ 70 71 struct load_json_config_ctx; 72 typedef void (*client_resp_handler)(struct load_json_config_ctx *, 73 struct spdk_jsonrpc_client_response *); 74 75 #define RPC_SOCKET_PATH_MAX SPDK_SIZEOF_MEMBER(struct sockaddr_un, sun_path) 76 77 /* 1s connections timeout */ 78 #define RPC_CLIENT_CONNECT_TIMEOUT_US (1U * 1000U * 1000U) 79 80 /* 81 * Currently there is no timeout in SPDK for any RPC command. This result that 82 * we can't put a hard limit during configuration load as it most likely randomly fail. 83 * So just print WARNLOG every 10s. */ 84 #define RPC_CLIENT_REQUEST_TIMEOUT_US (10U * 1000 * 1000) 85 86 struct load_json_config_ctx { 87 /* Thread used during configuration. */ 88 struct spdk_thread *thread; 89 spdk_subsystem_init_fn cb_fn; 90 void *cb_arg; 91 bool stop_on_error; 92 93 /* Current subsystem */ 94 struct spdk_json_val *subsystems; /* "subsystems" array */ 95 struct spdk_json_val *subsystems_it; /* current subsystem array position in "subsystems" array */ 96 97 struct spdk_json_val *subsystem_name; /* current subsystem name */ 98 99 /* Current "config" entry we are processing */ 100 struct spdk_json_val *config; /* "config" array */ 101 struct spdk_json_val *config_it; /* current config position in "config" array */ 102 103 /* Current request id we are sending. */ 104 uint32_t rpc_request_id; 105 106 /* Whole configuration file read and parsed. */ 107 size_t json_data_size; 108 char *json_data; 109 110 size_t values_cnt; 111 struct spdk_json_val *values; 112 113 char rpc_socket_path_temp[RPC_SOCKET_PATH_MAX + 1]; 114 115 struct spdk_jsonrpc_client *client_conn; 116 struct spdk_poller *client_conn_poller; 117 118 client_resp_handler client_resp_cb; 119 120 /* Timeout for current RPC client action. */ 121 uint64_t timeout; 122 }; 123 124 static void app_json_config_load_subsystem(void *_ctx); 125 126 static void 127 app_json_config_load_done(struct load_json_config_ctx *ctx, int rc) 128 { 129 spdk_poller_unregister(&ctx->client_conn_poller); 130 if (ctx->client_conn != NULL) { 131 spdk_jsonrpc_client_close(ctx->client_conn); 132 } 133 134 spdk_rpc_finish(); 135 136 SPDK_DEBUG_APP_CFG("Config load finished with rc %d\n", rc); 137 ctx->cb_fn(rc, ctx->cb_arg); 138 139 free(ctx->json_data); 140 free(ctx->values); 141 free(ctx); 142 } 143 144 static void 145 rpc_client_set_timeout(struct load_json_config_ctx *ctx, uint64_t timeout_us) 146 { 147 ctx->timeout = spdk_get_ticks() + timeout_us * spdk_get_ticks_hz() / (1000 * 1000); 148 } 149 150 static int 151 rpc_client_check_timeout(struct load_json_config_ctx *ctx) 152 { 153 if (ctx->timeout < spdk_get_ticks()) { 154 SPDK_WARNLOG("RPC client command timeout.\n"); 155 return -ETIMEDOUT; 156 } 157 158 return 0; 159 } 160 161 struct json_write_buf { 162 char data[1024]; 163 unsigned cur_off; 164 }; 165 166 static int 167 json_write_stdout(void *cb_ctx, const void *data, size_t size) 168 { 169 struct json_write_buf *buf = cb_ctx; 170 size_t rc; 171 172 rc = snprintf(buf->data + buf->cur_off, sizeof(buf->data) - buf->cur_off, 173 "%s", (const char *)data); 174 if (rc > 0) { 175 buf->cur_off += rc; 176 } 177 return rc == size ? 0 : -1; 178 } 179 180 static int 181 rpc_client_poller(void *arg) 182 { 183 struct load_json_config_ctx *ctx = arg; 184 struct spdk_jsonrpc_client_response *resp; 185 client_resp_handler cb; 186 int rc; 187 188 assert(spdk_get_thread() == ctx->thread); 189 190 rc = spdk_jsonrpc_client_poll(ctx->client_conn, 0); 191 if (rc == 0) { 192 rc = rpc_client_check_timeout(ctx); 193 if (rc == -ETIMEDOUT) { 194 rpc_client_set_timeout(ctx, RPC_CLIENT_REQUEST_TIMEOUT_US); 195 rc = 0; 196 } 197 } 198 199 if (rc == 0) { 200 /* No response yet */ 201 return SPDK_POLLER_BUSY; 202 } else if (rc < 0) { 203 app_json_config_load_done(ctx, rc); 204 return SPDK_POLLER_BUSY; 205 } 206 207 resp = spdk_jsonrpc_client_get_response(ctx->client_conn); 208 assert(resp); 209 210 if (resp->error) { 211 struct json_write_buf buf = {}; 212 struct spdk_json_write_ctx *w = spdk_json_write_begin(json_write_stdout, 213 &buf, SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE); 214 215 if (w == NULL) { 216 SPDK_ERRLOG("error response: (?)\n"); 217 } else { 218 spdk_json_write_val(w, resp->error); 219 spdk_json_write_end(w); 220 SPDK_ERRLOG("error response: \n%s\n", buf.data); 221 } 222 } 223 224 if (resp->error && ctx->stop_on_error) { 225 spdk_jsonrpc_client_free_response(resp); 226 app_json_config_load_done(ctx, -EINVAL); 227 } else { 228 /* We have response so we must have callback for it. */ 229 cb = ctx->client_resp_cb; 230 assert(cb != NULL); 231 232 /* Mark we are done with this handler. */ 233 ctx->client_resp_cb = NULL; 234 cb(ctx, resp); 235 } 236 237 238 return SPDK_POLLER_BUSY; 239 } 240 241 static int 242 rpc_client_connect_poller(void *_ctx) 243 { 244 struct load_json_config_ctx *ctx = _ctx; 245 int rc; 246 247 rc = spdk_jsonrpc_client_poll(ctx->client_conn, 0); 248 if (rc != -ENOTCONN) { 249 /* We are connected. Start regular poller and issue first request */ 250 spdk_poller_unregister(&ctx->client_conn_poller); 251 ctx->client_conn_poller = SPDK_POLLER_REGISTER(rpc_client_poller, ctx, 100); 252 app_json_config_load_subsystem(ctx); 253 } else { 254 rc = rpc_client_check_timeout(ctx); 255 if (rc) { 256 app_json_config_load_done(ctx, rc); 257 } 258 259 return SPDK_POLLER_IDLE; 260 } 261 262 return SPDK_POLLER_BUSY; 263 } 264 265 static int 266 client_send_request(struct load_json_config_ctx *ctx, struct spdk_jsonrpc_client_request *request, 267 client_resp_handler client_resp_cb) 268 { 269 int rc; 270 271 assert(spdk_get_thread() == ctx->thread); 272 273 ctx->client_resp_cb = client_resp_cb; 274 rpc_client_set_timeout(ctx, RPC_CLIENT_REQUEST_TIMEOUT_US); 275 rc = spdk_jsonrpc_client_send_request(ctx->client_conn, request); 276 277 if (rc) { 278 SPDK_DEBUG_APP_CFG("Sending request to client failed (%d)\n", rc); 279 } 280 281 return rc; 282 } 283 284 static int 285 cap_string(const struct spdk_json_val *val, void *out) 286 { 287 const struct spdk_json_val **vptr = out; 288 289 if (val->type != SPDK_JSON_VAL_STRING) { 290 return -EINVAL; 291 } 292 293 *vptr = val; 294 return 0; 295 } 296 297 static int 298 cap_object(const struct spdk_json_val *val, void *out) 299 { 300 const struct spdk_json_val **vptr = out; 301 302 if (val->type != SPDK_JSON_VAL_OBJECT_BEGIN) { 303 return -EINVAL; 304 } 305 306 *vptr = val; 307 return 0; 308 } 309 310 311 static int 312 cap_array_or_null(const struct spdk_json_val *val, void *out) 313 { 314 const struct spdk_json_val **vptr = out; 315 316 if (val->type != SPDK_JSON_VAL_ARRAY_BEGIN && val->type != SPDK_JSON_VAL_NULL) { 317 return -EINVAL; 318 } 319 320 *vptr = val; 321 return 0; 322 } 323 324 struct config_entry { 325 char *method; 326 struct spdk_json_val *params; 327 }; 328 329 static struct spdk_json_object_decoder jsonrpc_cmd_decoders[] = { 330 {"method", offsetof(struct config_entry, method), spdk_json_decode_string}, 331 {"params", offsetof(struct config_entry, params), cap_object, true} 332 }; 333 334 static void app_json_config_load_subsystem_config_entry(void *_ctx); 335 336 static void 337 app_json_config_load_subsystem_config_entry_next(struct load_json_config_ctx *ctx, 338 struct spdk_jsonrpc_client_response *resp) 339 { 340 /* Don't care about the response */ 341 spdk_jsonrpc_client_free_response(resp); 342 343 ctx->config_it = spdk_json_next(ctx->config_it); 344 app_json_config_load_subsystem_config_entry(ctx); 345 } 346 347 /* Load "config" entry */ 348 static void 349 app_json_config_load_subsystem_config_entry(void *_ctx) 350 { 351 struct load_json_config_ctx *ctx = _ctx; 352 struct spdk_jsonrpc_client_request *rpc_request; 353 struct spdk_json_write_ctx *w; 354 struct config_entry cfg = {}; 355 struct spdk_json_val *params_end; 356 size_t params_len = 0; 357 int rc; 358 359 if (ctx->config_it == NULL) { 360 SPDK_DEBUG_APP_CFG("Subsystem '%.*s': configuration done.\n", ctx->subsystem_name->len, 361 (char *)ctx->subsystem_name->start); 362 ctx->subsystems_it = spdk_json_next(ctx->subsystems_it); 363 /* Invoke later to avoid recurrency */ 364 spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem, ctx); 365 return; 366 } 367 368 if (spdk_json_decode_object(ctx->config_it, jsonrpc_cmd_decoders, 369 SPDK_COUNTOF(jsonrpc_cmd_decoders), &cfg)) { 370 SPDK_ERRLOG("Failed to decode config entry\n"); 371 app_json_config_load_done(ctx, -EINVAL); 372 goto out; 373 } 374 375 rc = spdk_rpc_is_method_allowed(cfg.method, spdk_rpc_get_state()); 376 if (rc == -EPERM) { 377 SPDK_DEBUG_APP_CFG("Method '%s' not allowed -> skipping\n", cfg.method); 378 /* Invoke later to avoid recurrency */ 379 ctx->config_it = spdk_json_next(ctx->config_it); 380 spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem_config_entry, ctx); 381 goto out; 382 } 383 384 SPDK_DEBUG_APP_CFG("\tmethod: %s\n", cfg.method); 385 386 if (cfg.params) { 387 /* Get _END by skipping params and going back by one element. */ 388 params_end = cfg.params + spdk_json_val_len(cfg.params) - 1; 389 390 /* Need to add one character to include '}' */ 391 params_len = params_end->start - cfg.params->start + 1; 392 393 SPDK_DEBUG_APP_CFG("\tparams: %.*s\n", (int)params_len, (char *)cfg.params->start); 394 } 395 396 rpc_request = spdk_jsonrpc_client_create_request(); 397 if (!rpc_request) { 398 app_json_config_load_done(ctx, -errno); 399 goto out; 400 } 401 402 w = spdk_jsonrpc_begin_request(rpc_request, ctx->rpc_request_id, NULL); 403 if (!w) { 404 spdk_jsonrpc_client_free_request(rpc_request); 405 app_json_config_load_done(ctx, -ENOMEM); 406 goto out; 407 } 408 409 spdk_json_write_named_string(w, "method", cfg.method); 410 411 if (cfg.params) { 412 /* No need to parse "params". Just dump the whole content of "params" 413 * directly into the request and let the remote side verify it. */ 414 spdk_json_write_name(w, "params"); 415 spdk_json_write_val_raw(w, cfg.params->start, params_len); 416 } 417 418 spdk_jsonrpc_end_request(rpc_request, w); 419 420 rc = client_send_request(ctx, rpc_request, app_json_config_load_subsystem_config_entry_next); 421 if (rc != 0) { 422 app_json_config_load_done(ctx, -rc); 423 goto out; 424 } 425 out: 426 free(cfg.method); 427 } 428 429 static void 430 subsystem_init_done(int rc, void *arg1) 431 { 432 struct load_json_config_ctx *ctx = arg1; 433 434 if (rc) { 435 app_json_config_load_done(ctx, rc); 436 return; 437 } 438 439 spdk_rpc_set_state(SPDK_RPC_RUNTIME); 440 /* Another round. This time for RUNTIME methods */ 441 SPDK_DEBUG_APP_CFG("'framework_start_init' done - continuing configuration\n"); 442 443 assert(ctx != NULL); 444 if (ctx->subsystems) { 445 ctx->subsystems_it = spdk_json_array_first(ctx->subsystems); 446 } 447 448 app_json_config_load_subsystem(ctx); 449 } 450 451 static struct spdk_json_object_decoder subsystem_decoders[] = { 452 {"subsystem", offsetof(struct load_json_config_ctx, subsystem_name), cap_string}, 453 {"config", offsetof(struct load_json_config_ctx, config), cap_array_or_null} 454 }; 455 456 /* 457 * Start loading subsystem pointed by ctx->subsystems_it. This must point to the 458 * beginning of the "subsystem" object in "subsystems" array or be NULL. If it is 459 * NULL then no more subsystems to load. 460 * 461 * There are two iterations: 462 * 463 * In first iteration only STARTUP RPC methods are used, other methods are ignored. When 464 * allsubsystems are walked the ctx->subsystems_it became NULL and "framework_start_init" 465 * is called to let the SPDK move to RUNTIME state (initialize all subsystems) and 466 * second iteration begins. 467 * 468 * In second iteration "subsystems" array is walked through again, this time only 469 * RUNTIME RPC methods are used. When ctx->subsystems_it became NULL second time it 470 * indicate that there is no more subsystems to load. The cb_fn is called to finish 471 * configuration. 472 */ 473 static void 474 app_json_config_load_subsystem(void *_ctx) 475 { 476 struct load_json_config_ctx *ctx = _ctx; 477 478 if (ctx->subsystems_it == NULL) { 479 if (spdk_rpc_get_state() == SPDK_RPC_STARTUP) { 480 SPDK_DEBUG_APP_CFG("No more entries for current state, calling 'framework_start_init'\n"); 481 spdk_subsystem_init(subsystem_init_done, ctx); 482 } else { 483 app_json_config_load_done(ctx, 0); 484 } 485 486 return; 487 } 488 489 /* Capture subsystem name and config array */ 490 if (spdk_json_decode_object(ctx->subsystems_it, subsystem_decoders, 491 SPDK_COUNTOF(subsystem_decoders), ctx)) { 492 SPDK_ERRLOG("Failed to parse subsystem configuration\n"); 493 app_json_config_load_done(ctx, -EINVAL); 494 return; 495 } 496 497 SPDK_DEBUG_APP_CFG("Loading subsystem '%.*s' configuration\n", ctx->subsystem_name->len, 498 (char *)ctx->subsystem_name->start); 499 500 /* Get 'config' array first configuration entry */ 501 ctx->config_it = spdk_json_array_first(ctx->config); 502 app_json_config_load_subsystem_config_entry(ctx); 503 } 504 505 static void * 506 read_file(const char *filename, size_t *size) 507 { 508 FILE *file = fopen(filename, "r"); 509 void *data; 510 511 if (file == NULL) { 512 /* errno is set by fopen */ 513 return NULL; 514 } 515 516 data = spdk_posix_file_load(file, size); 517 fclose(file); 518 return data; 519 } 520 521 static int 522 app_json_config_read(const char *config_file, struct load_json_config_ctx *ctx) 523 { 524 struct spdk_json_val *values = NULL; 525 void *json = NULL, *end; 526 ssize_t values_cnt, rc; 527 size_t json_size; 528 529 json = read_file(config_file, &json_size); 530 if (!json) { 531 SPDK_ERRLOG("Read JSON configuration file %s failed\n", config_file); 532 return -errno; 533 } 534 535 rc = spdk_json_parse(json, json_size, NULL, 0, &end, 536 SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS); 537 if (rc < 0) { 538 SPDK_ERRLOG("Parsing JSON configuration failed (%zd)\n", rc); 539 goto err; 540 } 541 542 values_cnt = rc; 543 values = calloc(values_cnt, sizeof(struct spdk_json_val)); 544 if (values == NULL) { 545 SPDK_ERRLOG("Out of memory\n"); 546 goto err; 547 } 548 549 rc = spdk_json_parse(json, json_size, values, values_cnt, &end, 550 SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS); 551 if (rc != values_cnt) { 552 SPDK_ERRLOG("Parsing JSON configuration failed (%zd)\n", rc); 553 goto err; 554 } 555 556 ctx->json_data = json; 557 ctx->json_data_size = json_size; 558 559 ctx->values = values; 560 ctx->values_cnt = values_cnt; 561 562 return 0; 563 err: 564 free(json); 565 free(values); 566 return rc; 567 } 568 569 void 570 spdk_subsystem_init_from_json_config(const char *json_config_file, const char *rpc_addr, 571 spdk_subsystem_init_fn cb_fn, void *cb_arg, 572 bool stop_on_error) 573 { 574 struct load_json_config_ctx *ctx = calloc(1, sizeof(*ctx)); 575 int rc; 576 577 assert(cb_fn); 578 if (!ctx) { 579 cb_fn(-ENOMEM, cb_arg); 580 return; 581 } 582 583 ctx->cb_fn = cb_fn; 584 ctx->cb_arg = cb_arg; 585 ctx->stop_on_error = stop_on_error; 586 ctx->thread = spdk_get_thread(); 587 588 rc = app_json_config_read(json_config_file, ctx); 589 if (rc) { 590 goto fail; 591 } 592 593 /* Capture subsystems array */ 594 rc = spdk_json_find_array(ctx->values, "subsystems", NULL, &ctx->subsystems); 595 if (rc) { 596 SPDK_WARNLOG("No 'subsystems' key JSON configuration file.\n"); 597 } else { 598 /* Get first subsystem */ 599 ctx->subsystems_it = spdk_json_array_first(ctx->subsystems); 600 if (ctx->subsystems_it == NULL) { 601 SPDK_NOTICELOG("'subsystems' configuration is empty\n"); 602 } 603 } 604 605 /* If rpc_addr is not an Unix socket use default address as prefix. */ 606 if (rpc_addr == NULL || rpc_addr[0] != '/') { 607 rpc_addr = SPDK_DEFAULT_RPC_ADDR; 608 } 609 610 /* FIXME: rpc client should use socketpair() instead of this temporary socket nonsense */ 611 rc = snprintf(ctx->rpc_socket_path_temp, sizeof(ctx->rpc_socket_path_temp), "%s.%d_config", 612 rpc_addr, getpid()); 613 if (rc >= (int)sizeof(ctx->rpc_socket_path_temp)) { 614 SPDK_ERRLOG("Socket name create failed\n"); 615 goto fail; 616 } 617 618 rc = spdk_rpc_initialize(ctx->rpc_socket_path_temp); 619 if (rc) { 620 goto fail; 621 } 622 623 ctx->client_conn = spdk_jsonrpc_client_connect(ctx->rpc_socket_path_temp, AF_UNIX); 624 if (ctx->client_conn == NULL) { 625 SPDK_ERRLOG("Failed to connect to '%s'\n", ctx->rpc_socket_path_temp); 626 goto fail; 627 } 628 629 rpc_client_set_timeout(ctx, RPC_CLIENT_CONNECT_TIMEOUT_US); 630 ctx->client_conn_poller = SPDK_POLLER_REGISTER(rpc_client_connect_poller, ctx, 100); 631 return; 632 633 fail: 634 app_json_config_load_done(ctx, -EINVAL); 635 } 636 637 SPDK_LOG_REGISTER_COMPONENT(app_config) 638