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 : 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 : }
37 : }
38 :
39 0 : return SPDK_POLLER_BUSY;
40 : }
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 : }
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 : }
114 :
115 : static struct init_rpc_server *
116 0 : get_server_by_addr(const char *listen_addr)
117 : {
118 : 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 : }
125 :
126 0 : return NULL;
127 : }
128 :
129 : int
130 0 : spdk_rpc_initialize(const char *listen_addr, const struct spdk_rpc_opts *opts)
131 : {
132 : struct init_rpc_server *init_server;
133 : 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 : 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 : }
179 :
180 0 : return 0;
181 : }
182 :
183 : void
184 0 : spdk_rpc_server_finish(const char *listen_addr)
185 : {
186 : 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 : }
201 : }
202 :
203 : void
204 0 : spdk_rpc_finish(void)
205 : {
206 : 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 : }
211 0 : }
212 :
213 : static void
214 0 : set_server_active_flag(const char *listen_addr, bool is_active)
215 : {
216 : 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 : }
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 : }
|