xref: /spdk/lib/init/rpc.c (revision 95d6c9fac17572b107042103439aafd696d60b0e)
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 		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
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
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
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
228 spdk_rpc_server_pause(const char *listen_addr)
229 {
230 	set_server_active_flag(listen_addr, false);
231 }
232 
233 void
234 spdk_rpc_server_resume(const char *listen_addr)
235 {
236 	set_server_active_flag(listen_addr, true);
237 }
238