Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
3 : : * Copyright (C) 2016 Intel Corporation.
4 : : * All rights reserved.
5 : : */
6 : :
7 : : #include "spdk/stdinc.h"
8 : :
9 : : #include "spdk/sock.h"
10 : : #include "spdk/string.h"
11 : :
12 : : #include "spdk/log.h"
13 : :
14 : : #include "iscsi/iscsi.h"
15 : : #include "iscsi/conn.h"
16 : : #include "iscsi/portal_grp.h"
17 : : #include "iscsi/tgt_node.h"
18 : :
19 : : #define PORTNUMSTRLEN 32
20 : : #define ACCEPT_TIMEOUT_US 1000 /* 1ms */
21 : :
22 : : static int
23 : 2222740 : iscsi_portal_accept(void *arg)
24 : : {
25 : 2222740 : struct spdk_iscsi_portal *portal = arg;
26 : 0 : struct spdk_sock *sock;
27 : : int rc;
28 : 2222740 : int count = 0;
29 : :
30 [ - + ]: 2222740 : if (portal->sock == NULL) {
31 : 0 : return -1;
32 : : }
33 : :
34 : : while (1) {
35 : 2223315 : sock = spdk_sock_accept(portal->sock);
36 [ + + ]: 2223315 : if (sock != NULL) {
37 : 575 : rc = iscsi_conn_construct(portal, sock);
38 [ - + ]: 575 : if (rc < 0) {
39 : 0 : spdk_sock_close(&sock);
40 : 0 : SPDK_ERRLOG("spdk_iscsi_connection_construct() failed\n");
41 : 0 : break;
42 : : }
43 : 575 : count++;
44 : : } else {
45 [ - + - - ]: 2222740 : if (errno != EAGAIN && errno != EWOULDBLOCK) {
46 : 0 : SPDK_ERRLOG("accept error(%d): %s\n", errno, spdk_strerror(errno));
47 : : }
48 : 2222740 : break;
49 : : }
50 : : }
51 : :
52 : 2222740 : return count;
53 : : }
54 : :
55 : : static struct spdk_iscsi_portal *
56 : 113 : iscsi_portal_find_by_addr(const char *host, const char *port)
57 : : {
58 : : struct spdk_iscsi_portal *p;
59 : :
60 [ + + ]: 126 : TAILQ_FOREACH(p, &g_iscsi.portal_head, g_tailq) {
61 [ + + + + : 18 : if (!strcmp(p->host, host) && !strcmp(p->port, port)) {
+ + - + -
+ + + ]
62 : 5 : return p;
63 : : }
64 : : }
65 : :
66 : 108 : return NULL;
67 : : }
68 : :
69 : : /* Assumes caller allocated host and port strings on the heap */
70 : : struct spdk_iscsi_portal *
71 : 113 : iscsi_portal_create(const char *host, const char *port)
72 : : {
73 : 113 : struct spdk_iscsi_portal *p = NULL, *tmp;
74 : :
75 [ - + ]: 113 : assert(host != NULL);
76 [ - + ]: 113 : assert(port != NULL);
77 : :
78 [ + + + + : 113 : if (strlen(host) > MAX_PORTAL_ADDR || strlen(port) > MAX_PORTAL_PORT) {
- + - + ]
79 : 0 : return NULL;
80 : : }
81 : :
82 : 113 : p = calloc(1, sizeof(*p));
83 [ - + ]: 113 : if (!p) {
84 : 0 : SPDK_ERRLOG("calloc() failed for portal\n");
85 : 0 : return NULL;
86 : : }
87 : :
88 : : /* check and overwrite abbreviation of wildcard */
89 [ + + + + ]: 113 : if (strcasecmp(host, "[*]") == 0) {
90 : 5 : SPDK_WARNLOG("Please use \"[::]\" as IPv6 wildcard\n");
91 : 5 : SPDK_WARNLOG("Convert \"[*]\" to \"[::]\" automatically\n");
92 : 5 : SPDK_WARNLOG("(Use of \"[*]\" will be deprecated in a future release)");
93 : 5 : snprintf(p->host, sizeof(p->host), "[::]");
94 [ + + + + ]: 108 : } else if (strcasecmp(host, "*") == 0) {
95 : 5 : SPDK_WARNLOG("Please use \"0.0.0.0\" as IPv4 wildcard\n");
96 : 5 : SPDK_WARNLOG("Convert \"*\" to \"0.0.0.0\" automatically\n");
97 : 5 : SPDK_WARNLOG("(Use of \"[*]\" will be deprecated in a future release)");
98 : 5 : snprintf(p->host, sizeof(p->host), "0.0.0.0");
99 : : } else {
100 [ - + - + : 103 : memcpy(p->host, host, strlen(host));
- + ]
101 : : }
102 : :
103 [ - + - + : 113 : memcpy(p->port, port, strlen(port));
- + ]
104 : :
105 : 113 : p->sock = NULL;
106 : 113 : p->group = NULL; /* set at a later time by caller */
107 : 113 : p->acceptor_poller = NULL;
108 : :
109 [ - + ]: 113 : pthread_mutex_lock(&g_iscsi.mutex);
110 : 113 : tmp = iscsi_portal_find_by_addr(host, port);
111 [ + + ]: 113 : if (tmp != NULL) {
112 [ # # ]: 5 : pthread_mutex_unlock(&g_iscsi.mutex);
113 : 5 : SPDK_ERRLOG("portal (%s, %s) already exists\n", host, port);
114 : 5 : goto error_out;
115 : : }
116 : :
117 : 108 : TAILQ_INSERT_TAIL(&g_iscsi.portal_head, p, g_tailq);
118 [ - + ]: 108 : pthread_mutex_unlock(&g_iscsi.mutex);
119 : :
120 : 108 : return p;
121 : :
122 : 5 : error_out:
123 : 5 : free(p);
124 : :
125 : 5 : return NULL;
126 : : }
127 : :
128 : : void
129 : 108 : iscsi_portal_destroy(struct spdk_iscsi_portal *p)
130 : : {
131 [ - + ]: 108 : assert(p != NULL);
132 : :
133 [ - + - + ]: 108 : SPDK_DEBUGLOG(iscsi, "iscsi_portal_destroy\n");
134 : :
135 [ - + ]: 108 : pthread_mutex_lock(&g_iscsi.mutex);
136 [ + + ]: 108 : TAILQ_REMOVE(&g_iscsi.portal_head, p, g_tailq);
137 [ - + ]: 108 : pthread_mutex_unlock(&g_iscsi.mutex);
138 : :
139 : 108 : free(p);
140 : :
141 : 108 : }
142 : :
143 : : static int
144 : 73 : iscsi_portal_open(struct spdk_iscsi_portal *p)
145 : : {
146 : : struct spdk_sock *sock;
147 : : int port;
148 : :
149 [ - + ]: 73 : if (p->sock != NULL) {
150 : 0 : SPDK_ERRLOG("portal (%s, %s) is already opened\n",
151 : : p->host, p->port);
152 : 0 : return -1;
153 : : }
154 : :
155 [ - + ]: 73 : port = (int)strtol(p->port, NULL, 0);
156 [ + - - + ]: 73 : if (port <= 0 || port > 65535) {
157 : 0 : SPDK_ERRLOG("invalid port %s\n", p->port);
158 : 0 : return -1;
159 : : }
160 : :
161 : 73 : sock = spdk_sock_listen(p->host, port, NULL);
162 [ - + ]: 73 : if (sock == NULL) {
163 : 0 : SPDK_ERRLOG("listen error %.64s.%d\n", p->host, port);
164 : 0 : return -1;
165 : : }
166 : :
167 : 73 : p->sock = sock;
168 : :
169 : : /*
170 : : * When the portal is created by config file, incoming connection
171 : : * requests for the socket are pended to accept until reactors start.
172 : : * However the gap between listen() and accept() will be slight and
173 : : * the requests will be queued by the nonzero backlog of the socket
174 : : * or resend by TCP.
175 : : */
176 : 73 : p->acceptor_poller = SPDK_POLLER_REGISTER(iscsi_portal_accept, p, ACCEPT_TIMEOUT_US);
177 : :
178 : 73 : return 0;
179 : : }
180 : :
181 : : static void
182 : 73 : iscsi_portal_close(struct spdk_iscsi_portal *p)
183 : : {
184 [ + - ]: 73 : if (p->sock) {
185 [ - + - + ]: 73 : SPDK_DEBUGLOG(iscsi, "close portal (%s, %s)\n",
186 : : p->host, p->port);
187 : 73 : spdk_poller_unregister(&p->acceptor_poller);
188 : 73 : spdk_sock_close(&p->sock);
189 : : }
190 : 73 : }
191 : :
192 : : static void
193 : 0 : iscsi_portal_pause(struct spdk_iscsi_portal *p)
194 : : {
195 [ # # ]: 0 : assert(p->acceptor_poller != NULL);
196 : :
197 : 0 : spdk_poller_pause(p->acceptor_poller);
198 : 0 : }
199 : :
200 : : static void
201 : 0 : iscsi_portal_resume(struct spdk_iscsi_portal *p)
202 : : {
203 [ # # ]: 0 : assert(p->acceptor_poller != NULL);
204 : :
205 : 0 : spdk_poller_resume(p->acceptor_poller);
206 : 0 : }
207 : :
208 : : int
209 : 2 : iscsi_parse_redirect_addr(struct sockaddr_storage *sa,
210 : : const char *host, const char *port)
211 : : {
212 : 0 : struct addrinfo hints, *res;
213 : : int rc;
214 : :
215 [ + - - + ]: 2 : if (host == NULL || port == NULL) {
216 : 0 : return -EINVAL;
217 : : }
218 : :
219 [ - + ]: 2 : memset(&hints, 0, sizeof(hints));
220 : 2 : hints.ai_family = PF_UNSPEC;
221 : 2 : hints.ai_socktype = SOCK_STREAM;
222 : 2 : hints.ai_flags = AI_NUMERICSERV;
223 : 2 : hints.ai_flags |= AI_NUMERICHOST;
224 : 2 : rc = getaddrinfo(host, port, &hints, &res);
225 [ - + ]: 2 : if (rc != 0) {
226 : 0 : SPDK_ERRLOG("getaddinrfo failed: %s (%d)\n", gai_strerror(rc), rc);
227 : 0 : return -(abs(rc));
228 : : }
229 : :
230 [ - + ]: 2 : if (res->ai_addrlen > sizeof(*sa)) {
231 : 0 : SPDK_ERRLOG("getaddrinfo() ai_addrlen %zu too large\n",
232 : : (size_t)res->ai_addrlen);
233 : 0 : rc = -EINVAL;
234 : : } else {
235 [ - + - + ]: 2 : memcpy(sa, res->ai_addr, res->ai_addrlen);
236 : : }
237 : :
238 : 2 : freeaddrinfo(res);
239 : 2 : return rc;
240 : : }
241 : :
242 : : struct spdk_iscsi_portal_grp *
243 : 81 : iscsi_portal_grp_create(int tag, bool is_private)
244 : : {
245 : 81 : struct spdk_iscsi_portal_grp *pg = malloc(sizeof(*pg));
246 : :
247 [ - + ]: 81 : if (!pg) {
248 : 0 : SPDK_ERRLOG("malloc() failed for portal group\n");
249 : 0 : return NULL;
250 : : }
251 : :
252 : 81 : pg->ref = 0;
253 : 81 : pg->tag = tag;
254 : 81 : pg->is_private = is_private;
255 : :
256 [ - + ]: 81 : pthread_mutex_lock(&g_iscsi.mutex);
257 [ - + ]: 81 : pg->disable_chap = g_iscsi.disable_chap;
258 [ - + ]: 81 : pg->require_chap = g_iscsi.require_chap;
259 [ - + ]: 81 : pg->mutual_chap = g_iscsi.mutual_chap;
260 : 81 : pg->chap_group = g_iscsi.chap_group;
261 [ - + ]: 81 : pthread_mutex_unlock(&g_iscsi.mutex);
262 : :
263 : 81 : TAILQ_INIT(&pg->head);
264 : :
265 : 81 : return pg;
266 : : }
267 : :
268 : : void
269 : 81 : iscsi_portal_grp_destroy(struct spdk_iscsi_portal_grp *pg)
270 : : {
271 : : struct spdk_iscsi_portal *p;
272 : :
273 [ - + ]: 81 : assert(pg != NULL);
274 : :
275 [ - + - + ]: 81 : SPDK_DEBUGLOG(iscsi, "iscsi_portal_grp_destroy\n");
276 [ + + ]: 164 : while (!TAILQ_EMPTY(&pg->head)) {
277 : 83 : p = TAILQ_FIRST(&pg->head);
278 [ + + ]: 83 : TAILQ_REMOVE(&pg->head, p, per_pg_tailq);
279 : 83 : iscsi_portal_destroy(p);
280 : : }
281 : 81 : free(pg);
282 : 81 : }
283 : :
284 : : int
285 : 86 : iscsi_portal_grp_register(struct spdk_iscsi_portal_grp *pg)
286 : : {
287 : 86 : int rc = -1;
288 : : struct spdk_iscsi_portal_grp *tmp;
289 : :
290 [ - + ]: 86 : assert(pg != NULL);
291 : :
292 [ - + ]: 86 : pthread_mutex_lock(&g_iscsi.mutex);
293 : 86 : tmp = iscsi_portal_grp_find_by_tag(pg->tag);
294 [ + + ]: 86 : if (tmp == NULL) {
295 : 81 : TAILQ_INSERT_TAIL(&g_iscsi.pg_head, pg, tailq);
296 : 81 : rc = 0;
297 : : }
298 [ - + ]: 86 : pthread_mutex_unlock(&g_iscsi.mutex);
299 : 86 : return rc;
300 : : }
301 : :
302 : : void
303 : 83 : iscsi_portal_grp_add_portal(struct spdk_iscsi_portal_grp *pg,
304 : : struct spdk_iscsi_portal *p)
305 : : {
306 [ - + ]: 83 : assert(pg != NULL);
307 [ - + ]: 83 : assert(p != NULL);
308 : :
309 : 83 : p->group = pg;
310 : 83 : TAILQ_INSERT_TAIL(&pg->head, p, per_pg_tailq);
311 : 83 : }
312 : :
313 : : struct spdk_iscsi_portal *
314 : 2 : iscsi_portal_grp_find_portal_by_addr(struct spdk_iscsi_portal_grp *pg,
315 : : const char *host, const char *port)
316 : : {
317 : : struct spdk_iscsi_portal *p;
318 : :
319 [ + + ]: 4 : TAILQ_FOREACH(p, &pg->head, per_pg_tailq) {
320 [ - + - + : 2 : if (!strcmp(p->host, host) && !strcmp(p->port, port)) {
- + - - -
- - - ]
321 : 0 : return p;
322 : : }
323 : : }
324 : :
325 : 2 : return NULL;
326 : : }
327 : :
328 : : int
329 : 0 : iscsi_portal_grp_set_chap_params(struct spdk_iscsi_portal_grp *pg,
330 : : bool disable_chap, bool require_chap,
331 : : bool mutual_chap, int32_t chap_group)
332 : : {
333 [ # # ]: 0 : if (!iscsi_check_chap_params(disable_chap, require_chap,
334 : : mutual_chap, chap_group)) {
335 : 0 : return -EINVAL;
336 : : }
337 : :
338 : 0 : pg->disable_chap = disable_chap;
339 : 0 : pg->require_chap = require_chap;
340 : 0 : pg->mutual_chap = mutual_chap;
341 : 0 : pg->chap_group = chap_group;
342 : :
343 : 0 : return 0;
344 : : }
345 : :
346 : : struct spdk_iscsi_portal_grp *
347 : 260 : iscsi_portal_grp_find_by_tag(int tag)
348 : : {
349 : : struct spdk_iscsi_portal_grp *pg;
350 : :
351 [ + + ]: 273 : TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) {
352 [ + + ]: 192 : if (pg->tag == tag) {
353 : 179 : return pg;
354 : : }
355 : : }
356 : :
357 : 81 : return NULL;
358 : : }
359 : :
360 : : void
361 : 619 : iscsi_portal_grps_destroy(void)
362 : : {
363 : : struct spdk_iscsi_portal_grp *pg;
364 : :
365 [ - + - + ]: 619 : SPDK_DEBUGLOG(iscsi, "iscsi_portal_grps_destroy\n");
366 [ - + ]: 619 : pthread_mutex_lock(&g_iscsi.mutex);
367 [ + + ]: 669 : while (!TAILQ_EMPTY(&g_iscsi.pg_head)) {
368 : 50 : pg = TAILQ_FIRST(&g_iscsi.pg_head);
369 [ + + ]: 50 : TAILQ_REMOVE(&g_iscsi.pg_head, pg, tailq);
370 [ - + ]: 50 : pthread_mutex_unlock(&g_iscsi.mutex);
371 : 50 : iscsi_portal_grp_destroy(pg);
372 [ - + ]: 50 : pthread_mutex_lock(&g_iscsi.mutex);
373 : : }
374 [ - + ]: 619 : pthread_mutex_unlock(&g_iscsi.mutex);
375 : 619 : }
376 : :
377 : : int
378 : 71 : iscsi_portal_grp_open(struct spdk_iscsi_portal_grp *pg, bool pause)
379 : : {
380 : : struct spdk_iscsi_portal *p;
381 : : int rc;
382 : :
383 [ + + ]: 144 : TAILQ_FOREACH(p, &pg->head, per_pg_tailq) {
384 : 73 : rc = iscsi_portal_open(p);
385 [ - + ]: 73 : if (rc < 0) {
386 : 0 : return rc;
387 : : }
388 : :
389 [ - + ]: 73 : if (pause) {
390 : 0 : iscsi_portal_pause(p);
391 : : }
392 : : }
393 : 71 : return 0;
394 : : }
395 : :
396 : : static void
397 : 71 : iscsi_portal_grp_close(struct spdk_iscsi_portal_grp *pg)
398 : : {
399 : : struct spdk_iscsi_portal *p;
400 : :
401 [ + + ]: 144 : TAILQ_FOREACH(p, &pg->head, per_pg_tailq) {
402 : 73 : iscsi_portal_close(p);
403 : : }
404 : 71 : }
405 : :
406 : : void
407 : 0 : iscsi_portal_grp_resume(struct spdk_iscsi_portal_grp *pg)
408 : : {
409 : : struct spdk_iscsi_portal *p;
410 : :
411 [ # # ]: 0 : TAILQ_FOREACH(p, &pg->head, per_pg_tailq) {
412 : 0 : iscsi_portal_resume(p);
413 : : }
414 : 0 : }
415 : :
416 : : void
417 : 614 : iscsi_portal_grp_close_all(void)
418 : : {
419 : : struct spdk_iscsi_portal_grp *pg;
420 : :
421 [ - + - + ]: 614 : SPDK_DEBUGLOG(iscsi, "iscsi_portal_grp_close_all\n");
422 [ - + ]: 614 : pthread_mutex_lock(&g_iscsi.mutex);
423 [ + + ]: 654 : TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) {
424 : 40 : iscsi_portal_grp_close(pg);
425 : : }
426 [ - + ]: 614 : pthread_mutex_unlock(&g_iscsi.mutex);
427 : 614 : }
428 : :
429 : : struct spdk_iscsi_portal_grp *
430 : 31 : iscsi_portal_grp_unregister(int tag)
431 : : {
432 : : struct spdk_iscsi_portal_grp *pg;
433 : :
434 [ - + ]: 31 : pthread_mutex_lock(&g_iscsi.mutex);
435 [ + - ]: 31 : TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) {
436 [ + - ]: 31 : if (pg->tag == tag) {
437 [ + + ]: 31 : TAILQ_REMOVE(&g_iscsi.pg_head, pg, tailq);
438 [ - + ]: 31 : pthread_mutex_unlock(&g_iscsi.mutex);
439 : 31 : return pg;
440 : : }
441 : : }
442 [ # # ]: 0 : pthread_mutex_unlock(&g_iscsi.mutex);
443 : 0 : return NULL;
444 : : }
445 : :
446 : : void
447 : 21 : iscsi_portal_grp_release(struct spdk_iscsi_portal_grp *pg)
448 : : {
449 : 21 : iscsi_portal_grp_close(pg);
450 : 21 : iscsi_portal_grp_destroy(pg);
451 : 21 : }
452 : :
453 : : static void
454 : 128 : iscsi_portal_grp_info_json(struct spdk_iscsi_portal_grp *pg,
455 : : struct spdk_json_write_ctx *w)
456 : : {
457 : : struct spdk_iscsi_portal *portal;
458 : :
459 : 128 : spdk_json_write_object_begin(w);
460 : :
461 : 128 : spdk_json_write_named_int32(w, "tag", pg->tag);
462 : :
463 : 128 : spdk_json_write_named_array_begin(w, "portals");
464 [ + + ]: 312 : TAILQ_FOREACH(portal, &pg->head, per_pg_tailq) {
465 : 184 : spdk_json_write_object_begin(w);
466 : :
467 : 184 : spdk_json_write_named_string(w, "host", portal->host);
468 : 184 : spdk_json_write_named_string(w, "port", portal->port);
469 : :
470 : 184 : spdk_json_write_object_end(w);
471 : : }
472 : 128 : spdk_json_write_array_end(w);
473 : :
474 [ - + ]: 128 : spdk_json_write_named_bool(w, "private", pg->is_private);
475 : :
476 : 128 : spdk_json_write_object_end(w);
477 : 128 : }
478 : :
479 : : static void
480 : 8 : iscsi_portal_grp_config_json(struct spdk_iscsi_portal_grp *pg,
481 : : struct spdk_json_write_ctx *w)
482 : : {
483 : 8 : spdk_json_write_object_begin(w);
484 : :
485 : 8 : spdk_json_write_named_string(w, "method", "iscsi_create_portal_group");
486 : :
487 : 8 : spdk_json_write_name(w, "params");
488 : 8 : iscsi_portal_grp_info_json(pg, w);
489 : :
490 : 8 : spdk_json_write_object_end(w);
491 : 8 : }
492 : :
493 : : void
494 : 125 : iscsi_portal_grps_info_json(struct spdk_json_write_ctx *w)
495 : : {
496 : : struct spdk_iscsi_portal_grp *pg;
497 : :
498 [ + + ]: 245 : TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) {
499 : 120 : iscsi_portal_grp_info_json(pg, w);
500 : : }
501 : 125 : }
502 : :
503 : : void
504 : 101 : iscsi_portal_grps_config_json(struct spdk_json_write_ctx *w)
505 : : {
506 : : struct spdk_iscsi_portal_grp *pg;
507 : :
508 [ + + ]: 109 : TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) {
509 : 8 : iscsi_portal_grp_config_json(pg, w);
510 : : }
511 : 101 : }
|