xref: /spdk/lib/sock/sock.c (revision 7392cdeff7d8d8d30ec1d8f24a3eebe6f762cde4)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "spdk/log.h"
37 #include "spdk/sock.h"
38 #include "spdk_internal/sock.h"
39 #include "spdk/queue.h"
40 
41 static STAILQ_HEAD(, spdk_net_impl) g_net_impls = STAILQ_HEAD_INITIALIZER(g_net_impls);
42 
43 struct spdk_sock_placement_id_entry {
44 	int placement_id;
45 	uint32_t ref;
46 	struct spdk_sock_group *group;
47 	STAILQ_ENTRY(spdk_sock_placement_id_entry) link;
48 };
49 
50 static STAILQ_HEAD(, spdk_sock_placement_id_entry) g_placement_id_map = STAILQ_HEAD_INITIALIZER(
51 			g_placement_id_map);
52 static pthread_mutex_t g_map_table_mutex = PTHREAD_MUTEX_INITIALIZER;
53 
54 /* Insert a group into the placement map.
55  * If the group is already in the map, take a reference.
56  */
57 static int
58 spdk_sock_map_insert(int placement_id, struct spdk_sock_group *group)
59 {
60 	struct spdk_sock_placement_id_entry *entry;
61 
62 	pthread_mutex_lock(&g_map_table_mutex);
63 	STAILQ_FOREACH(entry, &g_placement_id_map, link) {
64 		if (placement_id == entry->placement_id) {
65 			/* The mapping already exists, it means that different sockets have
66 			 * the same placement_ids.
67 			 */
68 			entry->ref++;
69 			pthread_mutex_unlock(&g_map_table_mutex);
70 			return 0;
71 		}
72 	}
73 
74 	entry = calloc(1, sizeof(*entry));
75 	if (!entry) {
76 		SPDK_ERRLOG("Cannot allocate an entry for placement_id=%u\n", placement_id);
77 		pthread_mutex_unlock(&g_map_table_mutex);
78 		return -ENOMEM;
79 	}
80 
81 	entry->placement_id = placement_id;
82 	entry->group = group;
83 	entry->ref++;
84 
85 	STAILQ_INSERT_TAIL(&g_placement_id_map, entry, link);
86 	pthread_mutex_unlock(&g_map_table_mutex);
87 
88 	return 0;
89 }
90 
91 /* Release a reference to the group for a given placement_id.
92  * If the reference count is 0, remove the group.
93  */
94 static void
95 spdk_sock_map_release(int placement_id)
96 {
97 	struct spdk_sock_placement_id_entry *entry;
98 
99 	pthread_mutex_lock(&g_map_table_mutex);
100 	STAILQ_FOREACH(entry, &g_placement_id_map, link) {
101 		if (placement_id == entry->placement_id) {
102 			assert(entry->ref > 0);
103 			entry->ref--;
104 			if (!entry->ref) {
105 				STAILQ_REMOVE(&g_placement_id_map, entry, spdk_sock_placement_id_entry, link);
106 				free(entry);
107 			}
108 			break;
109 		}
110 	}
111 
112 	pthread_mutex_unlock(&g_map_table_mutex);
113 }
114 
115 /* Look up the group for a placement_id. */
116 static void
117 spdk_sock_map_lookup(int placement_id, struct spdk_sock_group **group)
118 {
119 	struct spdk_sock_placement_id_entry *entry;
120 
121 	*group = NULL;
122 	pthread_mutex_lock(&g_map_table_mutex);
123 	STAILQ_FOREACH(entry, &g_placement_id_map, link) {
124 		if (placement_id == entry->placement_id) {
125 			assert(entry->group != NULL);
126 			*group = entry->group;
127 			break;
128 		}
129 	}
130 	pthread_mutex_unlock(&g_map_table_mutex);
131 }
132 
133 /* Remove the socket group from the map table */
134 static void
135 spdk_sock_remove_sock_group_from_map_table(struct spdk_sock_group *group)
136 {
137 	struct spdk_sock_placement_id_entry *entry, *tmp;
138 
139 	pthread_mutex_lock(&g_map_table_mutex);
140 	STAILQ_FOREACH_SAFE(entry, &g_placement_id_map, link, tmp) {
141 		if (entry->group == group) {
142 			STAILQ_REMOVE(&g_placement_id_map, entry, spdk_sock_placement_id_entry, link);
143 			free(entry);
144 		}
145 	}
146 	pthread_mutex_unlock(&g_map_table_mutex);
147 
148 }
149 
150 int
151 spdk_sock_get_optimal_sock_group(struct spdk_sock *sock, struct spdk_sock_group **group)
152 {
153 	int placement_id = 0, rc;
154 
155 	rc = sock->net_impl->get_placement_id(sock, &placement_id);
156 	if (!rc && (placement_id != 0)) {
157 		spdk_sock_map_lookup(placement_id, group);
158 		return 0;
159 	} else {
160 		return -1;
161 	}
162 }
163 
164 int
165 spdk_sock_getaddr(struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport,
166 		  char *caddr, int clen, uint16_t *cport)
167 {
168 	return sock->net_impl->getaddr(sock, saddr, slen, sport, caddr, clen, cport);
169 }
170 
171 struct spdk_sock *
172 spdk_sock_connect(const char *ip, int port)
173 {
174 	struct spdk_net_impl *impl = NULL;
175 	struct spdk_sock *sock;
176 
177 	STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
178 		sock = impl->connect(ip, port);
179 		if (sock != NULL) {
180 			sock->net_impl = impl;
181 			return sock;
182 		}
183 	}
184 
185 	return NULL;
186 }
187 
188 struct spdk_sock *
189 spdk_sock_listen(const char *ip, int port)
190 {
191 	struct spdk_net_impl *impl = NULL;
192 	struct spdk_sock *sock;
193 
194 	STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
195 		sock = impl->listen(ip, port);
196 		if (sock != NULL) {
197 			sock->net_impl = impl;
198 			return sock;
199 		}
200 	}
201 
202 	return NULL;
203 }
204 
205 struct spdk_sock *
206 spdk_sock_accept(struct spdk_sock *sock)
207 {
208 	struct spdk_sock *new_sock;
209 
210 	new_sock = sock->net_impl->accept(sock);
211 	if (new_sock != NULL) {
212 		new_sock->net_impl = sock->net_impl;
213 	}
214 
215 	return new_sock;
216 }
217 
218 int
219 spdk_sock_close(struct spdk_sock **sock)
220 {
221 	int rc;
222 
223 	if (*sock == NULL) {
224 		errno = EBADF;
225 		return -1;
226 	}
227 
228 	if ((*sock)->cb_fn != NULL) {
229 		/* This sock is still part of a sock_group. */
230 		errno = EBUSY;
231 		return -1;
232 	}
233 
234 	rc = (*sock)->net_impl->close(*sock);
235 	if (rc == 0) {
236 		*sock = NULL;
237 	}
238 
239 	return rc;
240 }
241 
242 ssize_t
243 spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len)
244 {
245 	if (sock == NULL) {
246 		errno = EBADF;
247 		return -1;
248 	}
249 
250 	return sock->net_impl->recv(sock, buf, len);
251 }
252 
253 ssize_t
254 spdk_sock_readv(struct spdk_sock *sock, struct iovec *iov, int iovcnt)
255 {
256 	if (sock == NULL) {
257 		errno = EBADF;
258 		return -1;
259 	}
260 
261 	return sock->net_impl->readv(sock, iov, iovcnt);
262 }
263 
264 ssize_t
265 spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt)
266 {
267 	if (sock == NULL) {
268 		errno = EBADF;
269 		return -1;
270 	}
271 
272 	return sock->net_impl->writev(sock, iov, iovcnt);
273 }
274 
275 int
276 spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes)
277 {
278 	return sock->net_impl->set_recvlowat(sock, nbytes);
279 }
280 
281 int
282 spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz)
283 {
284 	return sock->net_impl->set_recvbuf(sock, sz);
285 }
286 
287 int
288 spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz)
289 {
290 	return sock->net_impl->set_sendbuf(sock, sz);
291 }
292 
293 int
294 spdk_sock_set_priority(struct spdk_sock *sock, int priority)
295 {
296 	return sock->net_impl->set_priority(sock, priority);
297 }
298 
299 bool
300 spdk_sock_is_ipv6(struct spdk_sock *sock)
301 {
302 	return sock->net_impl->is_ipv6(sock);
303 }
304 
305 bool
306 spdk_sock_is_ipv4(struct spdk_sock *sock)
307 {
308 	return sock->net_impl->is_ipv4(sock);
309 }
310 
311 struct spdk_sock_group *
312 spdk_sock_group_create(void *ctx)
313 {
314 	struct spdk_net_impl *impl = NULL;
315 	struct spdk_sock_group *group;
316 	struct spdk_sock_group_impl *group_impl;
317 
318 	group = calloc(1, sizeof(*group));
319 	if (group == NULL) {
320 		return NULL;
321 	}
322 
323 	STAILQ_INIT(&group->group_impls);
324 
325 	STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
326 		group_impl = impl->group_impl_create();
327 		if (group_impl != NULL) {
328 			STAILQ_INSERT_TAIL(&group->group_impls, group_impl, link);
329 			TAILQ_INIT(&group_impl->socks);
330 			group_impl->net_impl = impl;
331 		}
332 	}
333 
334 	group->ctx = ctx;
335 	return group;
336 }
337 
338 void *
339 spdk_sock_group_get_ctx(struct spdk_sock_group *group)
340 {
341 	if (group == NULL) {
342 		return NULL;
343 	}
344 
345 	return group->ctx;
346 }
347 
348 int
349 spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock,
350 			 spdk_sock_cb cb_fn, void *cb_arg)
351 {
352 	struct spdk_sock_group_impl *group_impl = NULL;
353 	int rc, placement_id = 0;
354 
355 	if (cb_fn == NULL) {
356 		errno = EINVAL;
357 		return -1;
358 	}
359 
360 	if (sock->cb_fn != NULL) {
361 		/*
362 		 * This sock is already part of a sock_group.  Currently we don't
363 		 *  support this.
364 		 */
365 		errno = EBUSY;
366 		return -1;
367 	}
368 
369 	rc = sock->net_impl->get_placement_id(sock, &placement_id);
370 	if (!rc && (placement_id != 0)) {
371 		rc = spdk_sock_map_insert(placement_id, group);
372 		if (rc < 0) {
373 			return -1;
374 		}
375 	}
376 
377 	STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
378 		if (sock->net_impl == group_impl->net_impl) {
379 			break;
380 		}
381 	}
382 
383 	if (group_impl == NULL) {
384 		errno = EINVAL;
385 		return -1;
386 	}
387 
388 	rc = group_impl->net_impl->group_impl_add_sock(group_impl, sock);
389 	if (rc == 0) {
390 		TAILQ_INSERT_TAIL(&group_impl->socks, sock, link);
391 		sock->cb_fn = cb_fn;
392 		sock->cb_arg = cb_arg;
393 	}
394 
395 	return rc;
396 }
397 
398 int
399 spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock)
400 {
401 	struct spdk_sock_group_impl *group_impl = NULL;
402 	int rc, placement_id = 0;
403 
404 	STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
405 		if (sock->net_impl == group_impl->net_impl) {
406 			break;
407 		}
408 	}
409 
410 	if (group_impl == NULL) {
411 		errno = EINVAL;
412 		return -1;
413 	}
414 
415 	rc = sock->net_impl->get_placement_id(sock, &placement_id);
416 	if (!rc && (placement_id != 0)) {
417 		spdk_sock_map_release(placement_id);
418 	}
419 
420 	rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock);
421 	if (rc == 0) {
422 		TAILQ_REMOVE(&group_impl->socks, sock, link);
423 		sock->cb_fn = NULL;
424 		sock->cb_arg = NULL;
425 	}
426 
427 	return rc;
428 }
429 
430 int
431 spdk_sock_group_poll(struct spdk_sock_group *group)
432 {
433 	return spdk_sock_group_poll_count(group, MAX_EVENTS_PER_POLL);
434 }
435 
436 static int
437 spdk_sock_group_impl_poll_count(struct spdk_sock_group_impl *group_impl,
438 				struct spdk_sock_group *group,
439 				int max_events)
440 {
441 	struct spdk_sock *socks[MAX_EVENTS_PER_POLL];
442 	int num_events, i;
443 
444 	if (TAILQ_EMPTY(&group_impl->socks)) {
445 		return 0;
446 	}
447 
448 	num_events = group_impl->net_impl->group_impl_poll(group_impl, max_events, socks);
449 	if (num_events == -1) {
450 		return -1;
451 	}
452 
453 	for (i = 0; i < num_events; i++) {
454 		struct spdk_sock *sock = socks[i];
455 
456 		assert(sock->cb_fn != NULL);
457 		sock->cb_fn(sock->cb_arg, group, sock);
458 	}
459 	return num_events;
460 }
461 
462 int
463 spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events)
464 {
465 	struct spdk_sock_group_impl *group_impl = NULL;
466 	int rc, num_events = 0;
467 
468 	if (max_events < 1) {
469 		errno = -EINVAL;
470 		return -1;
471 	}
472 
473 	/*
474 	 * Only poll for up to 32 events at a time - if more events are pending,
475 	 *  the next call to this function will reap them.
476 	 */
477 	if (max_events > MAX_EVENTS_PER_POLL) {
478 		max_events = MAX_EVENTS_PER_POLL;
479 	}
480 
481 	STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
482 		rc = spdk_sock_group_impl_poll_count(group_impl, group, max_events);
483 		if (rc < 0) {
484 			num_events = -1;
485 			SPDK_ERRLOG("group_impl_poll_count for net(%s) failed\n",
486 				    group_impl->net_impl->name);
487 		} else if (num_events >= 0) {
488 			num_events += rc;
489 		}
490 	}
491 
492 	return num_events;
493 }
494 
495 int
496 spdk_sock_group_close(struct spdk_sock_group **group)
497 {
498 	struct spdk_sock_group_impl *group_impl = NULL, *tmp;
499 	int rc;
500 
501 	if (*group == NULL) {
502 		errno = EBADF;
503 		return -1;
504 	}
505 
506 	STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
507 		if (!TAILQ_EMPTY(&group_impl->socks)) {
508 			errno = EBUSY;
509 			return -1;
510 		}
511 	}
512 
513 	STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
514 		rc = group_impl->net_impl->group_impl_close(group_impl);
515 		if (rc != 0) {
516 			SPDK_ERRLOG("group_impl_close for net(%s) failed\n",
517 				    group_impl->net_impl->name);
518 		}
519 		free(group_impl);
520 	}
521 
522 	spdk_sock_remove_sock_group_from_map_table(*group);
523 	free(*group);
524 	*group = NULL;
525 
526 	return 0;
527 }
528 
529 void
530 spdk_net_impl_register(struct spdk_net_impl *impl)
531 {
532 	if (!strcmp("posix", impl->name)) {
533 		STAILQ_INSERT_TAIL(&g_net_impls, impl, link);
534 	} else {
535 		STAILQ_INSERT_HEAD(&g_net_impls, impl, link);
536 	}
537 }
538