diff --git a/include/spdk/rpc.h b/include/spdk/rpc.h index 1dce7febb..7a02abcdc 100644 --- a/include/spdk/rpc.h +++ b/include/spdk/rpc.h @@ -38,9 +38,9 @@ #include "spdk/jsonrpc.h" -int spdk_rpc_initialize(void); -int spdk_rpc_finish(void); -void spdk_rpc_config_text(FILE *fp); +int spdk_rpc_listen(const char *listen_addr); +void spdk_rpc_accept(void); +void spdk_rpc_close(void); typedef void (*spdk_rpc_method_handler)(struct spdk_jsonrpc_server_conn *conn, const struct spdk_json_val *params, diff --git a/lib/event/subsystems/rpc/rpc.c b/lib/event/subsystems/rpc/rpc.c index b6ab4ea6e..a3a3fc3ae 100644 --- a/lib/event/subsystems/rpc/rpc.c +++ b/lib/event/subsystems/rpc/rpc.c @@ -33,25 +33,125 @@ #include "spdk/stdinc.h" +#include "spdk/conf.h" +#include "spdk/env.h" +#include "spdk/log.h" #include "spdk/rpc.h" #include "spdk_internal/event.h" +#define RPC_SELECT_INTERVAL 4000 /* 4ms */ +#define RPC_DEFAULT_LISTEN_ADDR "127.0.0.1:5260" + +static struct spdk_poller *g_rpc_poller = NULL; + +static int +enable_rpc(void) +{ + struct spdk_conf_section *sp; + + sp = spdk_conf_find_section(NULL, "Rpc"); + if (sp == NULL) { + return 0; + } + + return spdk_conf_section_get_boolval(sp, "Enable", false); +} + +static const char * +rpc_get_listen_addr(void) +{ + struct spdk_conf_section *sp; + const char *val; + + sp = spdk_conf_find_section(NULL, "Rpc"); + if (sp == NULL) { + return RPC_DEFAULT_LISTEN_ADDR; + } + + val = spdk_conf_section_get_val(sp, "Listen"); + if (val == NULL) { + val = RPC_DEFAULT_LISTEN_ADDR; + } + + return val; +} + +static void +spdk_rpc_subsystem_poll(void *arg) +{ + spdk_rpc_accept(); +} + +static void +spdk_rpc_subsystem_setup(void *arg) +{ + const char *listen_addr; + int rc; + + /* Unregister the poller */ + spdk_poller_unregister(&g_rpc_poller, NULL); + + if (!enable_rpc()) { + return; + } + + listen_addr = rpc_get_listen_addr(); + if (listen_addr == NULL) { + listen_addr = RPC_DEFAULT_LISTEN_ADDR; + } + + /* Listen on the requested address */ + rc = spdk_rpc_listen(listen_addr); + if (rc != 0) { + SPDK_ERRLOG("Unable to start RPC service at %s\n", listen_addr); + return; + } + + /* Register a poller to periodically check for RPCs */ + spdk_poller_register(&g_rpc_poller, spdk_rpc_subsystem_poll, NULL, spdk_env_get_current_core(), + RPC_SELECT_INTERVAL); +} + static void spdk_rpc_subsystem_initialize(void) { - int rc; + /* + * Defer setup of the RPC service until the reactor has started. This + * allows us to detect the RPC listen socket as a suitable proxy for determining + * when the SPDK application has finished initialization and ready for logins + * or RPC commands. + */ + spdk_poller_register(&g_rpc_poller, spdk_rpc_subsystem_setup, NULL, spdk_env_get_current_core(), 0); - rc = spdk_rpc_initialize(); - - spdk_subsystem_init_next(rc); + spdk_subsystem_init_next(0); } static int spdk_rpc_subsystem_finish(void) { - return spdk_rpc_finish(); + spdk_rpc_close(); + + return 0; +} + +static void +spdk_rpc_subsystem_config_text(FILE *fp) +{ + fprintf(fp, + "\n" + "[Rpc]\n" + " # Defines whether to enable configuration via RPC.\n" + " # Default is disabled. Note that the RPC interface is not\n" + " # authenticated, so users should be careful about enabling\n" + " # RPC in non-trusted environments.\n" + " Enable %s\n" + " # Listen address for the RPC service.\n" + " # May be an IP address or an absolute path to a Unix socket.\n" + " Listen %s\n", + enable_rpc() ? "Yes" : "No", rpc_get_listen_addr()); } SPDK_SUBSYSTEM_REGISTER(spdk_rpc, spdk_rpc_subsystem_initialize, - spdk_rpc_subsystem_finish, spdk_rpc_config_text) + spdk_rpc_subsystem_finish, + spdk_rpc_subsystem_config_text) diff --git a/lib/rpc/rpc.c b/lib/rpc/rpc.c index 22a862ca6..1801d82b0 100644 --- a/lib/rpc/rpc.c +++ b/lib/rpc/rpc.c @@ -36,20 +36,13 @@ #include "spdk/queue.h" #include "spdk/rpc.h" #include "spdk/env.h" -#include "spdk/conf.h" #include "spdk/log.h" #include "spdk/string.h" -#include "spdk_internal/event.h" - -#define RPC_SELECT_INTERVAL 4000 /* 4ms */ -#define RPC_DEFAULT_LISTEN_ADDR "127.0.0.1:5260" #define RPC_DEFAULT_PORT "5260" static struct sockaddr_un g_rpc_listen_addr_unix = {}; -static struct spdk_poller *g_rpc_poller = NULL; - static struct spdk_jsonrpc_server *g_jsonrpc_server = NULL; struct spdk_rpc_method { @@ -60,61 +53,6 @@ struct spdk_rpc_method { static SLIST_HEAD(, spdk_rpc_method) g_rpc_methods = SLIST_HEAD_INITIALIZER(g_rpc_methods); -static void -spdk_rpc_server_do_work(void *arg) -{ - spdk_jsonrpc_server_poll(g_jsonrpc_server); -} - -static int -enable_rpc(void) -{ - struct spdk_conf_section *sp; - - sp = spdk_conf_find_section(NULL, "Rpc"); - if (sp == NULL) { - return 0; - } - - return spdk_conf_section_get_boolval(sp, "Enable", false); -} - -static const char * -rpc_get_listen_addr(void) -{ - struct spdk_conf_section *sp; - const char *val; - - sp = spdk_conf_find_section(NULL, "Rpc"); - if (sp == NULL) { - return 0; - } - - val = spdk_conf_section_get_val(sp, "Listen"); - if (val == NULL) { - val = RPC_DEFAULT_LISTEN_ADDR; - } - - return val; -} - -void -spdk_rpc_register_method(const char *method, spdk_rpc_method_handler func) -{ - struct spdk_rpc_method *m; - - m = calloc(1, sizeof(struct spdk_rpc_method)); - assert(m != NULL); - - m->name = strdup(method); - assert(m->name != NULL); - - m->func = func; - - /* TODO: use a hash table or sorted list */ - SLIST_INSERT_HEAD(&g_rpc_methods, m, slist); -} - static void spdk_jsonrpc_handler( struct spdk_jsonrpc_server_conn *conn, @@ -136,27 +74,14 @@ spdk_jsonrpc_handler( spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_METHOD_NOT_FOUND, "Method not found"); } -static void -spdk_rpc_setup(void *arg) +int +spdk_rpc_listen(const char *listen_addr) { struct addrinfo hints; struct addrinfo *res; - const char *listen_addr; memset(&g_rpc_listen_addr_unix, 0, sizeof(g_rpc_listen_addr_unix)); - /* Unregister the one-shot setup poller */ - spdk_poller_unregister(&g_rpc_poller, NULL); - - if (!enable_rpc()) { - return; - } - - listen_addr = rpc_get_listen_addr(); - if (!listen_addr) { - return; - } - if (listen_addr[0] == '/') { int rc; @@ -167,7 +92,7 @@ spdk_rpc_setup(void *arg) if (rc < 0 || (size_t)rc >= sizeof(g_rpc_listen_addr_unix.sun_path)) { SPDK_ERRLOG("RPC Listen address Unix socket path too long\n"); g_rpc_listen_addr_unix.sun_path[0] = '\0'; - return; + return -1; } unlink(g_rpc_listen_addr_unix.sun_path); @@ -183,13 +108,13 @@ spdk_rpc_setup(void *arg) tmp = strdup(listen_addr); if (!tmp) { SPDK_ERRLOG("Out of memory\n"); - return; + return -1; } if (spdk_parse_ip_addr(tmp, &host, &port) < 0) { free(tmp); SPDK_ERRLOG("Invalid listen address '%s'\n", listen_addr); - return; + return -1; } if (port == NULL) { @@ -204,7 +129,7 @@ spdk_rpc_setup(void *arg) if (getaddrinfo(host, port, &hints, &res) != 0) { free(tmp); SPDK_ERRLOG("Unable to look up RPC listen address '%s'\n", listen_addr); - return; + return -1; } g_jsonrpc_server = spdk_jsonrpc_server_listen(res->ai_family, res->ai_protocol, @@ -217,58 +142,44 @@ spdk_rpc_setup(void *arg) if (g_jsonrpc_server == NULL) { SPDK_ERRLOG("spdk_jsonrpc_server_listen() failed\n"); - return; - } - - /* Register the periodic rpc_server_do_work */ - spdk_poller_register(&g_rpc_poller, spdk_rpc_server_do_work, NULL, spdk_env_get_current_core(), - RPC_SELECT_INTERVAL); -} - -int -spdk_rpc_initialize(void) -{ - /* - * Defer setup of the RPC service until the reactor has started. This - * allows us to detect the RPC listen socket as a suitable proxy for determining - * when the SPDK application has finished initialization and ready for logins - * or RPC commands. - */ - spdk_poller_register(&g_rpc_poller, spdk_rpc_setup, NULL, spdk_env_get_current_core(), 0); - - return 0; -} - -int -spdk_rpc_finish(void) -{ - if (g_rpc_listen_addr_unix.sun_path[0]) { - /* Delete the Unix socket file */ - unlink(g_rpc_listen_addr_unix.sun_path); - } - - spdk_poller_unregister(&g_rpc_poller, NULL); - - if (g_jsonrpc_server) { - spdk_jsonrpc_server_shutdown(g_jsonrpc_server); + return -1; } return 0; } void -spdk_rpc_config_text(FILE *fp) +spdk_rpc_accept(void) { - fprintf(fp, - "\n" - "[Rpc]\n" - " # Defines whether to enable configuration via RPC.\n" - " # Default is disabled. Note that the RPC interface is not\n" - " # authenticated, so users should be careful about enabling\n" - " # RPC in non-trusted environments.\n" - " Enable %s\n" - " # Listen address for the RPC service.\n" - " # May be an IP address or an absolute path to a Unix socket.\n" - " Listen %s\n", - enable_rpc() ? "Yes" : "No", rpc_get_listen_addr()); + spdk_jsonrpc_server_poll(g_jsonrpc_server); +} + +void +spdk_rpc_register_method(const char *method, spdk_rpc_method_handler func) +{ + struct spdk_rpc_method *m; + + m = calloc(1, sizeof(struct spdk_rpc_method)); + assert(m != NULL); + + m->name = strdup(method); + assert(m->name != NULL); + + m->func = func; + + /* TODO: use a hash table or sorted list */ + SLIST_INSERT_HEAD(&g_rpc_methods, m, slist); +} + +void +spdk_rpc_close(void) +{ + if (g_rpc_listen_addr_unix.sun_path[0]) { + /* Delete the Unix socket file */ + unlink(g_rpc_listen_addr_unix.sun_path); + } + + if (g_jsonrpc_server) { + spdk_jsonrpc_server_shutdown(g_jsonrpc_server); + } }