xref: /spdk/lib/init/rpc.c (revision 5846a39003ae731b706b40337d50f3faaa0c2c8b)
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 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
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
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
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
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 *
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
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 		/* Not treated as an error */
137 		return 0;
138 	}
139 
140 	rc = rpc_verify_opts_and_methods(opts);
141 	if (rc) {
142 		return rc;
143 	}
144 
145 	if (get_server_by_addr(listen_addr) != NULL) {
146 		SPDK_ERRLOG("Socket listen_addr already in use\n");
147 		return -EADDRINUSE;
148 	}
149 
150 	init_server = calloc(1, sizeof(struct init_rpc_server));
151 	if (init_server == NULL) {
152 		SPDK_ERRLOG("Unable to allocate init RPC server\n");
153 		return -ENOMEM;
154 	}
155 
156 	rc = snprintf(init_server->listen_addr, sizeof(init_server->listen_addr), "%s",
157 		      listen_addr);
158 	if (rc < 0) {
159 		SPDK_ERRLOG("Unable to copy listen address %s\n", listen_addr);
160 		free(init_server);
161 		return -EINVAL;
162 	}
163 
164 	/* Listen on the requested address */
165 	init_server->server = spdk_rpc_server_listen(listen_addr);
166 	if (init_server->server == NULL) {
167 		SPDK_ERRLOG("Unable to start RPC service at %s\n", listen_addr);
168 		free(init_server);
169 		/* TODO: Eventually, treat this as an error. But it historically has not
170 		 * been and many tests rely on this gracefully failing. */
171 		return 0;
172 	}
173 
174 	rpc_set_spdk_log_opts(opts);
175 	init_server->active = true;
176 
177 	STAILQ_INSERT_TAIL(&g_init_rpc_servers, init_server, link);
178 	if (g_rpc_poller == NULL) {
179 		/* Register a poller to periodically check for RPCs */
180 		g_rpc_poller = SPDK_POLLER_REGISTER(rpc_subsystem_poll_servers, NULL, RPC_SELECT_INTERVAL);
181 	}
182 
183 	return 0;
184 }
185 
186 void
187 spdk_rpc_server_finish(const char *listen_addr)
188 {
189 	struct init_rpc_server *init_server;
190 
191 	init_server = get_server_by_addr(listen_addr);
192 	if (!init_server) {
193 		SPDK_ERRLOG("No server listening on provided address: %s\n", listen_addr);
194 		return;
195 	}
196 
197 	spdk_rpc_server_close(init_server->server);
198 	STAILQ_REMOVE(&g_init_rpc_servers, init_server, init_rpc_server, link);
199 	free(init_server);
200 
201 	if (STAILQ_EMPTY(&g_init_rpc_servers)) {
202 		spdk_poller_unregister(&g_rpc_poller);
203 	}
204 }
205 
206 void
207 spdk_rpc_finish(void)
208 {
209 	struct init_rpc_server *init_server, *tmp;
210 
211 	STAILQ_FOREACH_SAFE(init_server, &g_init_rpc_servers, link, tmp) {
212 		spdk_rpc_server_finish(init_server->listen_addr);
213 	}
214 }
215 
216 static void
217 set_server_active_flag(const char *listen_addr, bool is_active)
218 {
219 	struct init_rpc_server *init_server;
220 
221 	init_server = get_server_by_addr(listen_addr);
222 	if (!init_server) {
223 		SPDK_ERRLOG("No server listening on provided address: %s\n", listen_addr);
224 		return;
225 	}
226 
227 	init_server->active = is_active;
228 }
229 
230 void
231 spdk_rpc_server_pause(const char *listen_addr)
232 {
233 	set_server_active_flag(listen_addr, false);
234 }
235 
236 void
237 spdk_rpc_server_resume(const char *listen_addr)
238 {
239 	set_server_active_flag(listen_addr, true);
240 }
241