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
rpc_subsystem_poll_servers(void * arg)29 rpc_subsystem_poll_servers(void *arg)
30 {
31 struct init_rpc_server *init_server;
32
33 STAILQ_FOREACH(init_server, &g_init_rpc_servers, link) {
34 if (init_server->active) {
35 spdk_rpc_server_accept(init_server->server);
36 }
37 }
38
39 return SPDK_POLLER_BUSY;
40 }
41
42 static void
rpc_opts_copy(struct spdk_rpc_opts * opts,const struct spdk_rpc_opts * opts_src,size_t size)43 rpc_opts_copy(struct spdk_rpc_opts *opts, const struct spdk_rpc_opts *opts_src,
44 size_t size)
45 {
46 assert(opts);
47 assert(opts_src);
48
49 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 SET_FIELD(log_file);
57 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 }
65
66 static void
rpc_opts_get_default(struct spdk_rpc_opts * opts,size_t size)67 rpc_opts_get_default(struct spdk_rpc_opts *opts, size_t size)
68 {
69 assert(opts);
70
71 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 SET_FIELD(log_file, NULL);
79 SET_FIELD(log_level, SPDK_LOG_DISABLED);
80
81 #undef SET_FIELD
82 }
83
84 static int
rpc_verify_opts_and_methods(const struct spdk_rpc_opts * opts)85 rpc_verify_opts_and_methods(const struct spdk_rpc_opts *opts)
86 {
87 if (!spdk_rpc_verify_methods()) {
88 return -EINVAL;
89 }
90
91 if (opts != NULL && opts->size == 0) {
92 SPDK_ERRLOG("size in the options structure should not be zero\n");
93 return -EINVAL;
94 }
95
96 return 0;
97 }
98
99 static void
rpc_set_spdk_log_opts(const struct spdk_rpc_opts * _opts)100 rpc_set_spdk_log_opts(const struct spdk_rpc_opts *_opts)
101 {
102 struct spdk_rpc_opts opts;
103
104 rpc_opts_get_default(&opts, sizeof(opts));
105 if (_opts != NULL) {
106 rpc_opts_copy(&opts, _opts, _opts->size);
107 } else if (!STAILQ_EMPTY(&g_init_rpc_servers)) {
108 return;
109 }
110
111 spdk_jsonrpc_set_log_file(opts.log_file);
112 spdk_jsonrpc_set_log_level(opts.log_level);
113 }
114
115 static struct init_rpc_server *
get_server_by_addr(const char * listen_addr)116 get_server_by_addr(const char *listen_addr)
117 {
118 struct init_rpc_server *init_server;
119
120 STAILQ_FOREACH(init_server, &g_init_rpc_servers, link) {
121 if (strcmp(listen_addr, init_server->listen_addr) == 0) {
122 return init_server;
123 }
124 }
125
126 return NULL;
127 }
128
129 int
spdk_rpc_initialize(const char * listen_addr,const struct spdk_rpc_opts * opts)130 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 if (listen_addr == NULL) {
136 return -EINVAL;
137 }
138
139 rc = rpc_verify_opts_and_methods(opts);
140 if (rc) {
141 return rc;
142 }
143
144 if (get_server_by_addr(listen_addr) != NULL) {
145 SPDK_ERRLOG("Socket listen_addr already in use\n");
146 return -EADDRINUSE;
147 }
148
149 init_server = calloc(1, sizeof(struct init_rpc_server));
150 if (init_server == NULL) {
151 SPDK_ERRLOG("Unable to allocate init RPC server\n");
152 return -ENOMEM;
153 }
154
155 rc = snprintf(init_server->listen_addr, sizeof(init_server->listen_addr), "%s",
156 listen_addr);
157 if (rc < 0) {
158 SPDK_ERRLOG("Unable to copy listen address %s\n", listen_addr);
159 free(init_server);
160 return -EINVAL;
161 }
162
163 /* Listen on the requested address */
164 init_server->server = spdk_rpc_server_listen(listen_addr);
165 if (init_server->server == NULL) {
166 SPDK_ERRLOG("Unable to start RPC service at %s\n", listen_addr);
167 free(init_server);
168 return -EINVAL;
169 }
170
171 rpc_set_spdk_log_opts(opts);
172 init_server->active = true;
173
174 STAILQ_INSERT_TAIL(&g_init_rpc_servers, init_server, link);
175 if (g_rpc_poller == NULL) {
176 /* Register a poller to periodically check for RPCs */
177 g_rpc_poller = SPDK_POLLER_REGISTER(rpc_subsystem_poll_servers, NULL, RPC_SELECT_INTERVAL);
178 }
179
180 return 0;
181 }
182
183 void
spdk_rpc_server_finish(const char * listen_addr)184 spdk_rpc_server_finish(const char *listen_addr)
185 {
186 struct init_rpc_server *init_server;
187
188 init_server = get_server_by_addr(listen_addr);
189 if (!init_server) {
190 SPDK_ERRLOG("No server listening on provided address: %s\n", listen_addr);
191 return;
192 }
193
194 spdk_rpc_server_close(init_server->server);
195 STAILQ_REMOVE(&g_init_rpc_servers, init_server, init_rpc_server, link);
196 free(init_server);
197
198 if (STAILQ_EMPTY(&g_init_rpc_servers)) {
199 spdk_poller_unregister(&g_rpc_poller);
200 }
201 }
202
203 void
spdk_rpc_finish(void)204 spdk_rpc_finish(void)
205 {
206 struct init_rpc_server *init_server, *tmp;
207
208 STAILQ_FOREACH_SAFE(init_server, &g_init_rpc_servers, link, tmp) {
209 spdk_rpc_server_finish(init_server->listen_addr);
210 }
211 }
212
213 static void
set_server_active_flag(const char * listen_addr,bool is_active)214 set_server_active_flag(const char *listen_addr, bool is_active)
215 {
216 struct init_rpc_server *init_server;
217
218 init_server = get_server_by_addr(listen_addr);
219 if (!init_server) {
220 SPDK_ERRLOG("No server listening on provided address: %s\n", listen_addr);
221 return;
222 }
223
224 init_server->active = is_active;
225 }
226
227 void
spdk_rpc_server_pause(const char * listen_addr)228 spdk_rpc_server_pause(const char *listen_addr)
229 {
230 set_server_active_flag(listen_addr, false);
231 }
232
233 void
spdk_rpc_server_resume(const char * listen_addr)234 spdk_rpc_server_resume(const char *listen_addr)
235 {
236 set_server_active_flag(listen_addr, true);
237 }
238