LCOV - code coverage report
Current view: top level - lib/init - rpc.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 115 0.0 %
Date: 2024-12-06 08:19:16 Functions: 0 12 0.0 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2017 Intel Corporation. All rights reserved.
       3             :  *   Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
       4             :  */
       5             : 
       6             : #include "spdk/stdinc.h"
       7             : 
       8             : #include "spdk/env.h"
       9             : #include "spdk/init.h"
      10             : #include "spdk/thread.h"
      11             : #include "spdk/log.h"
      12             : #include "spdk/rpc.h"
      13             : 
      14             : #define RPC_SELECT_INTERVAL     4000 /* 4ms */
      15             : 
      16             : static struct spdk_poller *g_rpc_poller = NULL;
      17             : 
      18             : struct init_rpc_server {
      19             :         struct spdk_rpc_server *server;
      20             :         char listen_addr[sizeof(((struct sockaddr_un *)0)->sun_path)];
      21             :         bool active;
      22             :         STAILQ_ENTRY(init_rpc_server) link;
      23             : };
      24             : 
      25             : static STAILQ_HEAD(, init_rpc_server) g_init_rpc_servers = STAILQ_HEAD_INITIALIZER(
      26             :                         g_init_rpc_servers);
      27             : 
      28             : static int
      29           0 : rpc_subsystem_poll_servers(void *arg)
      30             : {
      31           0 :         struct init_rpc_server *init_server;
      32             : 
      33           0 :         STAILQ_FOREACH(init_server, &g_init_rpc_servers, link) {
      34           0 :                 if (init_server->active) {
      35           0 :                         spdk_rpc_server_accept(init_server->server);
      36           0 :                 }
      37           0 :         }
      38             : 
      39           0 :         return SPDK_POLLER_BUSY;
      40           0 : }
      41             : 
      42             : static void
      43           0 : rpc_opts_copy(struct spdk_rpc_opts *opts, const struct spdk_rpc_opts *opts_src,
      44             :               size_t size)
      45             : {
      46           0 :         assert(opts);
      47           0 :         assert(opts_src);
      48             : 
      49           0 :         opts->size = size;
      50             : 
      51             : #define SET_FIELD(field) \
      52             :         if (offsetof(struct spdk_rpc_opts, field) + sizeof(opts->field) <= size) { \
      53             :                 opts->field = opts_src->field; \
      54             :         } \
      55             : 
      56           0 :         SET_FIELD(log_file);
      57           0 :         SET_FIELD(log_level);
      58             : 
      59             :         /* Do not remove this statement, you should always update this statement when you adding a new field,
      60             :          * and do not forget to add the SET_FIELD statement for your added field. */
      61             :         SPDK_STATIC_ASSERT(sizeof(struct spdk_rpc_opts) == 24, "Incorrect size");
      62             : 
      63             : #undef SET_FIELD
      64           0 : }
      65             : 
      66             : static void
      67           0 : rpc_opts_get_default(struct spdk_rpc_opts *opts, size_t size)
      68             : {
      69           0 :         assert(opts);
      70             : 
      71           0 :         opts->size = size;
      72             : 
      73             : #define SET_FIELD(field, value) \
      74             :         if (offsetof(struct spdk_rpc_opts, field) + sizeof(opts->field) <= size) { \
      75             :                 opts->field = value; \
      76             :         } \
      77             : 
      78           0 :         SET_FIELD(log_file, NULL);
      79           0 :         SET_FIELD(log_level, SPDK_LOG_DISABLED);
      80             : 
      81             : #undef SET_FIELD
      82           0 : }
      83             : 
      84             : static int
      85           0 : rpc_verify_opts_and_methods(const struct spdk_rpc_opts *opts)
      86             : {
      87           0 :         if (!spdk_rpc_verify_methods()) {
      88           0 :                 return -EINVAL;
      89             :         }
      90             : 
      91           0 :         if (opts != NULL && opts->size == 0) {
      92           0 :                 SPDK_ERRLOG("size in the options structure should not be zero\n");
      93           0 :                 return -EINVAL;
      94             :         }
      95             : 
      96           0 :         return 0;
      97           0 : }
      98             : 
      99             : static void
     100           0 : rpc_set_spdk_log_opts(const struct spdk_rpc_opts *_opts)
     101             : {
     102           0 :         struct spdk_rpc_opts opts;
     103             : 
     104           0 :         rpc_opts_get_default(&opts, sizeof(opts));
     105           0 :         if (_opts != NULL) {
     106           0 :                 rpc_opts_copy(&opts, _opts, _opts->size);
     107           0 :         } else if (!STAILQ_EMPTY(&g_init_rpc_servers)) {
     108           0 :                 return;
     109             :         }
     110             : 
     111           0 :         spdk_jsonrpc_set_log_file(opts.log_file);
     112           0 :         spdk_jsonrpc_set_log_level(opts.log_level);
     113           0 : }
     114             : 
     115             : static struct init_rpc_server *
     116           0 : get_server_by_addr(const char *listen_addr)
     117             : {
     118           0 :         struct init_rpc_server *init_server;
     119             : 
     120           0 :         STAILQ_FOREACH(init_server, &g_init_rpc_servers, link) {
     121           0 :                 if (strcmp(listen_addr, init_server->listen_addr) == 0) {
     122           0 :                         return init_server;
     123             :                 }
     124           0 :         }
     125             : 
     126           0 :         return NULL;
     127           0 : }
     128             : 
     129             : int
     130           0 : spdk_rpc_initialize(const char *listen_addr, const struct spdk_rpc_opts *opts)
     131             : {
     132           0 :         struct init_rpc_server *init_server;
     133           0 :         int rc;
     134             : 
     135           0 :         if (listen_addr == NULL) {
     136           0 :                 return -EINVAL;
     137             :         }
     138             : 
     139           0 :         rc = rpc_verify_opts_and_methods(opts);
     140           0 :         if (rc) {
     141           0 :                 return rc;
     142             :         }
     143             : 
     144           0 :         if (get_server_by_addr(listen_addr) != NULL) {
     145           0 :                 SPDK_ERRLOG("Socket listen_addr already in use\n");
     146           0 :                 return -EADDRINUSE;
     147             :         }
     148             : 
     149           0 :         init_server = calloc(1, sizeof(struct init_rpc_server));
     150           0 :         if (init_server == NULL) {
     151           0 :                 SPDK_ERRLOG("Unable to allocate init RPC server\n");
     152           0 :                 return -ENOMEM;
     153             :         }
     154             : 
     155           0 :         rc = snprintf(init_server->listen_addr, sizeof(init_server->listen_addr), "%s",
     156           0 :                       listen_addr);
     157           0 :         if (rc < 0) {
     158           0 :                 SPDK_ERRLOG("Unable to copy listen address %s\n", listen_addr);
     159           0 :                 free(init_server);
     160           0 :                 return -EINVAL;
     161             :         }
     162             : 
     163             :         /* Listen on the requested address */
     164           0 :         init_server->server = spdk_rpc_server_listen(listen_addr);
     165           0 :         if (init_server->server == NULL) {
     166           0 :                 SPDK_ERRLOG("Unable to start RPC service at %s\n", listen_addr);
     167           0 :                 free(init_server);
     168           0 :                 return -EINVAL;
     169             :         }
     170             : 
     171           0 :         rpc_set_spdk_log_opts(opts);
     172           0 :         init_server->active = true;
     173             : 
     174           0 :         STAILQ_INSERT_TAIL(&g_init_rpc_servers, init_server, link);
     175           0 :         if (g_rpc_poller == NULL) {
     176             :                 /* Register a poller to periodically check for RPCs */
     177           0 :                 g_rpc_poller = SPDK_POLLER_REGISTER(rpc_subsystem_poll_servers, NULL, RPC_SELECT_INTERVAL);
     178           0 :         }
     179             : 
     180           0 :         return 0;
     181           0 : }
     182             : 
     183             : void
     184           0 : spdk_rpc_server_finish(const char *listen_addr)
     185             : {
     186           0 :         struct init_rpc_server *init_server;
     187             : 
     188           0 :         init_server = get_server_by_addr(listen_addr);
     189           0 :         if (!init_server) {
     190           0 :                 SPDK_ERRLOG("No server listening on provided address: %s\n", listen_addr);
     191           0 :                 return;
     192             :         }
     193             : 
     194           0 :         spdk_rpc_server_close(init_server->server);
     195           0 :         STAILQ_REMOVE(&g_init_rpc_servers, init_server, init_rpc_server, link);
     196           0 :         free(init_server);
     197             : 
     198           0 :         if (STAILQ_EMPTY(&g_init_rpc_servers)) {
     199           0 :                 spdk_poller_unregister(&g_rpc_poller);
     200           0 :         }
     201           0 : }
     202             : 
     203             : void
     204           0 : spdk_rpc_finish(void)
     205             : {
     206           0 :         struct init_rpc_server *init_server, *tmp;
     207             : 
     208           0 :         STAILQ_FOREACH_SAFE(init_server, &g_init_rpc_servers, link, tmp) {
     209           0 :                 spdk_rpc_server_finish(init_server->listen_addr);
     210           0 :         }
     211           0 : }
     212             : 
     213             : static void
     214           0 : set_server_active_flag(const char *listen_addr, bool is_active)
     215             : {
     216           0 :         struct init_rpc_server *init_server;
     217             : 
     218           0 :         init_server = get_server_by_addr(listen_addr);
     219           0 :         if (!init_server) {
     220           0 :                 SPDK_ERRLOG("No server listening on provided address: %s\n", listen_addr);
     221           0 :                 return;
     222             :         }
     223             : 
     224           0 :         init_server->active = is_active;
     225           0 : }
     226             : 
     227             : void
     228           0 : spdk_rpc_server_pause(const char *listen_addr)
     229             : {
     230           0 :         set_server_active_flag(listen_addr, false);
     231           0 : }
     232             : 
     233             : void
     234           0 : spdk_rpc_server_resume(const char *listen_addr)
     235             : {
     236           0 :         set_server_active_flag(listen_addr, true);
     237           0 : }

Generated by: LCOV version 1.15