xref: /spdk/module/sock/posix/posix.c (revision 6b6dfea6c704a049e553024aa7e44ae916948e20)
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 #if defined(__linux__)
37 #include <sys/epoll.h>
38 #elif defined(__FreeBSD__)
39 #include <sys/event.h>
40 #endif
41 
42 #include "spdk/log.h"
43 #include "spdk/sock.h"
44 #include "spdk/string.h"
45 #include "spdk_internal/sock.h"
46 
47 #define MAX_TMPBUF 1024
48 #define PORTNUMLEN 32
49 #define SO_RCVBUF_SIZE (2 * 1024 * 1024)
50 
51 struct spdk_posix_sock {
52 	struct spdk_sock	base;
53 	int			fd;
54 };
55 
56 struct spdk_posix_sock_group_impl {
57 	struct spdk_sock_group_impl	base;
58 	int				fd;
59 };
60 
61 static int
62 get_addr_str(struct sockaddr *sa, char *host, size_t hlen)
63 {
64 	const char *result = NULL;
65 
66 	if (sa == NULL || host == NULL) {
67 		return -1;
68 	}
69 
70 	switch (sa->sa_family) {
71 	case AF_INET:
72 		result = inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
73 				   host, hlen);
74 		break;
75 	case AF_INET6:
76 		result = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr),
77 				   host, hlen);
78 		break;
79 	default:
80 		break;
81 	}
82 
83 	if (result != NULL) {
84 		return 0;
85 	} else {
86 		return -1;
87 	}
88 }
89 
90 #define __posix_sock(sock) (struct spdk_posix_sock *)sock
91 #define __posix_group_impl(group) (struct spdk_posix_sock_group_impl *)group
92 
93 static int
94 spdk_posix_sock_getaddr(struct spdk_sock *_sock, char *saddr, int slen, uint16_t *sport,
95 			char *caddr, int clen, uint16_t *cport)
96 {
97 	struct spdk_posix_sock *sock = __posix_sock(_sock);
98 	struct sockaddr_storage sa;
99 	socklen_t salen;
100 	int rc;
101 
102 	assert(sock != NULL);
103 
104 	memset(&sa, 0, sizeof sa);
105 	salen = sizeof sa;
106 	rc = getsockname(sock->fd, (struct sockaddr *) &sa, &salen);
107 	if (rc != 0) {
108 		SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
109 		return -1;
110 	}
111 
112 	switch (sa.ss_family) {
113 	case AF_UNIX:
114 		/* Acceptable connection types that don't have IPs */
115 		return 0;
116 	case AF_INET:
117 	case AF_INET6:
118 		/* Code below will get IP addresses */
119 		break;
120 	default:
121 		/* Unsupported socket family */
122 		return -1;
123 	}
124 
125 	rc = get_addr_str((struct sockaddr *)&sa, saddr, slen);
126 	if (rc != 0) {
127 		SPDK_ERRLOG("getnameinfo() failed (errno=%d)\n", errno);
128 		return -1;
129 	}
130 
131 	if (sport) {
132 		if (sa.ss_family == AF_INET) {
133 			*sport = ntohs(((struct sockaddr_in *) &sa)->sin_port);
134 		} else if (sa.ss_family == AF_INET6) {
135 			*sport = ntohs(((struct sockaddr_in6 *) &sa)->sin6_port);
136 		}
137 	}
138 
139 	memset(&sa, 0, sizeof sa);
140 	salen = sizeof sa;
141 	rc = getpeername(sock->fd, (struct sockaddr *) &sa, &salen);
142 	if (rc != 0) {
143 		SPDK_ERRLOG("getpeername() failed (errno=%d)\n", errno);
144 		return -1;
145 	}
146 
147 	rc = get_addr_str((struct sockaddr *)&sa, caddr, clen);
148 	if (rc != 0) {
149 		SPDK_ERRLOG("getnameinfo() failed (errno=%d)\n", errno);
150 		return -1;
151 	}
152 
153 	if (cport) {
154 		if (sa.ss_family == AF_INET) {
155 			*cport = ntohs(((struct sockaddr_in *) &sa)->sin_port);
156 		} else if (sa.ss_family == AF_INET6) {
157 			*cport = ntohs(((struct sockaddr_in6 *) &sa)->sin6_port);
158 		}
159 	}
160 
161 	return 0;
162 }
163 
164 enum spdk_posix_sock_create_type {
165 	SPDK_SOCK_CREATE_LISTEN,
166 	SPDK_SOCK_CREATE_CONNECT,
167 };
168 
169 static struct spdk_sock *
170 spdk_posix_sock_create(const char *ip, int port, enum spdk_posix_sock_create_type type)
171 {
172 	struct spdk_posix_sock *sock;
173 	char buf[MAX_TMPBUF];
174 	char portnum[PORTNUMLEN];
175 	char *p;
176 	struct addrinfo hints, *res, *res0;
177 	int fd, flag;
178 	int val = 1;
179 	int rc;
180 
181 	if (ip == NULL) {
182 		return NULL;
183 	}
184 	if (ip[0] == '[') {
185 		snprintf(buf, sizeof(buf), "%s", ip + 1);
186 		p = strchr(buf, ']');
187 		if (p != NULL) {
188 			*p = '\0';
189 		}
190 		ip = (const char *) &buf[0];
191 	}
192 
193 	snprintf(portnum, sizeof portnum, "%d", port);
194 	memset(&hints, 0, sizeof hints);
195 	hints.ai_family = PF_UNSPEC;
196 	hints.ai_socktype = SOCK_STREAM;
197 	hints.ai_flags = AI_NUMERICSERV;
198 	hints.ai_flags |= AI_PASSIVE;
199 	hints.ai_flags |= AI_NUMERICHOST;
200 	rc = getaddrinfo(ip, portnum, &hints, &res0);
201 	if (rc != 0) {
202 		SPDK_ERRLOG("getaddrinfo() failed (errno=%d)\n", errno);
203 		return NULL;
204 	}
205 
206 	/* try listen */
207 	fd = -1;
208 	for (res = res0; res != NULL; res = res->ai_next) {
209 retry:
210 		fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
211 		if (fd < 0) {
212 			/* error */
213 			continue;
214 		}
215 		rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
216 		if (rc != 0) {
217 			close(fd);
218 			/* error */
219 			continue;
220 		}
221 		rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val);
222 		if (rc != 0) {
223 			close(fd);
224 			/* error */
225 			continue;
226 		}
227 
228 		if (res->ai_family == AF_INET6) {
229 			rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof val);
230 			if (rc != 0) {
231 				close(fd);
232 				/* error */
233 				continue;
234 			}
235 		}
236 
237 		if (type == SPDK_SOCK_CREATE_LISTEN) {
238 			rc = bind(fd, res->ai_addr, res->ai_addrlen);
239 			if (rc != 0) {
240 				SPDK_ERRLOG("bind() failed at port %d, errno = %d\n", port, errno);
241 				switch (errno) {
242 				case EINTR:
243 					/* interrupted? */
244 					close(fd);
245 					goto retry;
246 				case EADDRNOTAVAIL:
247 					SPDK_ERRLOG("IP address %s not available. "
248 						    "Verify IP address in config file "
249 						    "and make sure setup script is "
250 						    "run before starting spdk app.\n", ip);
251 				/* FALLTHROUGH */
252 				default:
253 					/* try next family */
254 					close(fd);
255 					fd = -1;
256 					continue;
257 				}
258 			}
259 			/* bind OK */
260 			rc = listen(fd, 512);
261 			if (rc != 0) {
262 				SPDK_ERRLOG("listen() failed, errno = %d\n", errno);
263 				close(fd);
264 				fd = -1;
265 				break;
266 			}
267 		} else if (type == SPDK_SOCK_CREATE_CONNECT) {
268 			rc = connect(fd, res->ai_addr, res->ai_addrlen);
269 			if (rc != 0) {
270 				SPDK_ERRLOG("connect() failed, errno = %d\n", errno);
271 				/* try next family */
272 				close(fd);
273 				fd = -1;
274 				continue;
275 			}
276 		}
277 
278 		flag = fcntl(fd, F_GETFL);
279 		if (fcntl(fd, F_SETFL, flag | O_NONBLOCK) < 0) {
280 			SPDK_ERRLOG("fcntl can't set nonblocking mode for socket, fd: %d (%d)\n", fd, errno);
281 			close(fd);
282 			fd = -1;
283 			break;
284 		}
285 		break;
286 	}
287 	freeaddrinfo(res0);
288 
289 	if (fd < 0) {
290 		return NULL;
291 	}
292 
293 	sock = calloc(1, sizeof(*sock));
294 	if (sock == NULL) {
295 		SPDK_ERRLOG("sock allocation failed\n");
296 		close(fd);
297 		return NULL;
298 	}
299 
300 	sock->fd = fd;
301 	return &sock->base;
302 }
303 
304 static struct spdk_sock *
305 spdk_posix_sock_listen(const char *ip, int port)
306 {
307 	return spdk_posix_sock_create(ip, port, SPDK_SOCK_CREATE_LISTEN);
308 }
309 
310 static struct spdk_sock *
311 spdk_posix_sock_connect(const char *ip, int port)
312 {
313 	return spdk_posix_sock_create(ip, port, SPDK_SOCK_CREATE_CONNECT);
314 }
315 
316 static struct spdk_sock *
317 spdk_posix_sock_accept(struct spdk_sock *_sock)
318 {
319 	struct spdk_posix_sock		*sock = __posix_sock(_sock);
320 	struct sockaddr_storage		sa;
321 	socklen_t			salen;
322 	int				rc, fd;
323 	struct spdk_posix_sock		*new_sock;
324 	int				flag;
325 	size_t				sz = 0;
326 
327 	memset(&sa, 0, sizeof(sa));
328 	salen = sizeof(sa);
329 
330 	assert(sock != NULL);
331 
332 	rc = accept(sock->fd, (struct sockaddr *)&sa, &salen);
333 
334 	if (rc == -1) {
335 		return NULL;
336 	}
337 
338 	fd = rc;
339 
340 	flag = fcntl(fd, F_GETFL);
341 	if ((!(flag & O_NONBLOCK)) && (fcntl(fd, F_SETFL, flag | O_NONBLOCK) < 0)) {
342 		SPDK_ERRLOG("fcntl can't set nonblocking mode for socket, fd: %d (%d)\n", fd, errno);
343 		close(fd);
344 		return NULL;
345 	}
346 
347 	rc = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sz, &salen);
348 	if (rc < 0) {
349 		SPDK_ERRLOG("Unable to get recvbuf size for socket fd %d (%s)\n", fd, spdk_strerror(errno));
350 		close(fd);
351 		return NULL;
352 	}
353 
354 	if (sz < SO_RCVBUF_SIZE) {
355 		sz = SO_RCVBUF_SIZE;
356 		rc = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz));
357 		if (rc < 0) {
358 			SPDK_WARNLOG("Unable to increase size of rcvbuf for socket fd %d (%s)", fd, spdk_strerror(errno));
359 		}
360 	}
361 
362 	new_sock = calloc(1, sizeof(*sock));
363 	if (new_sock == NULL) {
364 		SPDK_ERRLOG("sock allocation failed\n");
365 		close(fd);
366 		return NULL;
367 	}
368 
369 	new_sock->fd = fd;
370 	return &new_sock->base;
371 }
372 
373 static int
374 spdk_posix_sock_close(struct spdk_sock *_sock)
375 {
376 	struct spdk_posix_sock *sock = __posix_sock(_sock);
377 	int rc;
378 
379 	rc = close(sock->fd);
380 	if (rc == 0) {
381 		free(sock);
382 	}
383 
384 	return rc;
385 }
386 
387 static ssize_t
388 spdk_posix_sock_recv(struct spdk_sock *_sock, void *buf, size_t len)
389 {
390 	struct spdk_posix_sock *sock = __posix_sock(_sock);
391 
392 	return recv(sock->fd, buf, len, MSG_DONTWAIT);
393 }
394 
395 static ssize_t
396 spdk_posix_sock_readv(struct spdk_sock *_sock, struct iovec *iov, int iovcnt)
397 {
398 	struct spdk_posix_sock *sock = __posix_sock(_sock);
399 
400 	return readv(sock->fd, iov, iovcnt);
401 }
402 
403 static ssize_t
404 spdk_posix_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt)
405 {
406 	struct spdk_posix_sock *sock = __posix_sock(_sock);
407 
408 	return writev(sock->fd, iov, iovcnt);
409 }
410 
411 static int
412 spdk_posix_sock_set_recvlowat(struct spdk_sock *_sock, int nbytes)
413 {
414 	struct spdk_posix_sock *sock = __posix_sock(_sock);
415 	int val;
416 	int rc;
417 
418 	assert(sock != NULL);
419 
420 	val = nbytes;
421 	rc = setsockopt(sock->fd, SOL_SOCKET, SO_RCVLOWAT, &val, sizeof val);
422 	if (rc != 0) {
423 		return -1;
424 	}
425 	return 0;
426 }
427 
428 static int
429 spdk_posix_sock_set_recvbuf(struct spdk_sock *_sock, int sz)
430 {
431 	struct spdk_posix_sock *sock = __posix_sock(_sock);
432 
433 	assert(sock != NULL);
434 
435 	return setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
436 			  &sz, sizeof(sz));
437 }
438 
439 static int
440 spdk_posix_sock_set_sendbuf(struct spdk_sock *_sock, int sz)
441 {
442 	struct spdk_posix_sock *sock = __posix_sock(_sock);
443 
444 	assert(sock != NULL);
445 
446 	return setsockopt(sock->fd, SOL_SOCKET, SO_SNDBUF,
447 			  &sz, sizeof(sz));
448 }
449 
450 static int
451 spdk_posix_sock_set_priority(struct spdk_sock *_sock, int priority)
452 {
453 	int rc = 0;
454 
455 #if defined(SO_PRIORITY)
456 	struct spdk_posix_sock *sock = __posix_sock(_sock);
457 
458 	assert(sock != NULL);
459 
460 	rc = setsockopt(sock->fd, SOL_SOCKET, SO_PRIORITY,
461 			&priority, sizeof(priority));
462 #endif
463 	return rc;
464 }
465 
466 static bool
467 spdk_posix_sock_is_ipv6(struct spdk_sock *_sock)
468 {
469 	struct spdk_posix_sock *sock = __posix_sock(_sock);
470 	struct sockaddr_storage sa;
471 	socklen_t salen;
472 	int rc;
473 
474 	assert(sock != NULL);
475 
476 	memset(&sa, 0, sizeof sa);
477 	salen = sizeof sa;
478 	rc = getsockname(sock->fd, (struct sockaddr *) &sa, &salen);
479 	if (rc != 0) {
480 		SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
481 		return false;
482 	}
483 
484 	return (sa.ss_family == AF_INET6);
485 }
486 
487 static bool
488 spdk_posix_sock_is_ipv4(struct spdk_sock *_sock)
489 {
490 	struct spdk_posix_sock *sock = __posix_sock(_sock);
491 	struct sockaddr_storage sa;
492 	socklen_t salen;
493 	int rc;
494 
495 	assert(sock != NULL);
496 
497 	memset(&sa, 0, sizeof sa);
498 	salen = sizeof sa;
499 	rc = getsockname(sock->fd, (struct sockaddr *) &sa, &salen);
500 	if (rc != 0) {
501 		SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
502 		return false;
503 	}
504 
505 	return (sa.ss_family == AF_INET);
506 }
507 
508 static int
509 spdk_posix_sock_get_placement_id(struct spdk_sock *_sock, int *placement_id)
510 {
511 	int rc = -1;
512 
513 #if defined(SO_INCOMING_NAPI_ID)
514 	struct spdk_posix_sock *sock = __posix_sock(_sock);
515 	socklen_t salen = sizeof(int);
516 
517 	rc = getsockopt(sock->fd, SOL_SOCKET, SO_INCOMING_NAPI_ID, placement_id, &salen);
518 	if (rc != 0) {
519 		SPDK_ERRLOG("getsockopt() failed (errno=%d)\n", errno);
520 	}
521 
522 #endif
523 	return rc;
524 }
525 
526 static struct spdk_sock_group_impl *
527 spdk_posix_sock_group_impl_create(void)
528 {
529 	struct spdk_posix_sock_group_impl *group_impl;
530 	int fd;
531 
532 #if defined(__linux__)
533 	fd = epoll_create1(0);
534 #elif defined(__FreeBSD__)
535 	fd = kqueue();
536 #endif
537 	if (fd == -1) {
538 		return NULL;
539 	}
540 
541 	group_impl = calloc(1, sizeof(*group_impl));
542 	if (group_impl == NULL) {
543 		SPDK_ERRLOG("group_impl allocation failed\n");
544 		close(fd);
545 		return NULL;
546 	}
547 
548 	group_impl->fd = fd;
549 
550 	return &group_impl->base;
551 }
552 
553 static int
554 spdk_posix_sock_group_impl_add_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock)
555 {
556 	struct spdk_posix_sock_group_impl *group = __posix_group_impl(_group);
557 	struct spdk_posix_sock *sock = __posix_sock(_sock);
558 	int rc;
559 
560 #if defined(__linux__)
561 	struct epoll_event event;
562 
563 	memset(&event, 0, sizeof(event));
564 	event.events = EPOLLIN;
565 	event.data.ptr = sock;
566 
567 	rc = epoll_ctl(group->fd, EPOLL_CTL_ADD, sock->fd, &event);
568 #elif defined(__FreeBSD__)
569 	struct kevent event;
570 	struct timespec ts = {0};
571 
572 	EV_SET(&event, sock->fd, EVFILT_READ, EV_ADD, 0, 0, sock);
573 
574 	rc = kevent(group->fd, &event, 1, NULL, 0, &ts);
575 #endif
576 	return rc;
577 }
578 
579 static int
580 spdk_posix_sock_group_impl_remove_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock)
581 {
582 	struct spdk_posix_sock_group_impl *group = __posix_group_impl(_group);
583 	struct spdk_posix_sock *sock = __posix_sock(_sock);
584 	int rc;
585 #if defined(__linux__)
586 	struct epoll_event event;
587 
588 	/* Event parameter is ignored but some old kernel version still require it. */
589 	rc = epoll_ctl(group->fd, EPOLL_CTL_DEL, sock->fd, &event);
590 #elif defined(__FreeBSD__)
591 	struct kevent event;
592 	struct timespec ts = {0};
593 
594 	EV_SET(&event, sock->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
595 
596 	rc = kevent(group->fd, &event, 1, NULL, 0, &ts);
597 	if (rc == 0 && event.flags & EV_ERROR) {
598 		rc = -1;
599 		errno = event.data;
600 	}
601 #endif
602 	return rc;
603 }
604 
605 static int
606 spdk_posix_sock_group_impl_poll(struct spdk_sock_group_impl *_group, int max_events,
607 				struct spdk_sock **socks)
608 {
609 	struct spdk_posix_sock_group_impl *group = __posix_group_impl(_group);
610 	int num_events, i;
611 
612 #if defined(__linux__)
613 	struct epoll_event events[MAX_EVENTS_PER_POLL];
614 
615 	num_events = epoll_wait(group->fd, events, max_events, 0);
616 #elif defined(__FreeBSD__)
617 	struct kevent events[MAX_EVENTS_PER_POLL];
618 	struct timespec ts = {0};
619 
620 	num_events = kevent(group->fd, NULL, 0, events, max_events, &ts);
621 #endif
622 
623 	if (num_events == -1) {
624 		return -1;
625 	}
626 
627 	for (i = 0; i < num_events; i++) {
628 #if defined(__linux__)
629 		socks[i] = events[i].data.ptr;
630 #elif defined(__FreeBSD__)
631 		socks[i] = events[i].udata;
632 #endif
633 	}
634 
635 	return num_events;
636 }
637 
638 static int
639 spdk_posix_sock_group_impl_close(struct spdk_sock_group_impl *_group)
640 {
641 	struct spdk_posix_sock_group_impl *group = __posix_group_impl(_group);
642 
643 	return close(group->fd);
644 }
645 
646 static struct spdk_net_impl g_posix_net_impl = {
647 	.name		= "posix",
648 	.getaddr	= spdk_posix_sock_getaddr,
649 	.connect	= spdk_posix_sock_connect,
650 	.listen		= spdk_posix_sock_listen,
651 	.accept		= spdk_posix_sock_accept,
652 	.close		= spdk_posix_sock_close,
653 	.recv		= spdk_posix_sock_recv,
654 	.readv		= spdk_posix_sock_readv,
655 	.writev		= spdk_posix_sock_writev,
656 	.set_recvlowat	= spdk_posix_sock_set_recvlowat,
657 	.set_recvbuf	= spdk_posix_sock_set_recvbuf,
658 	.set_sendbuf	= spdk_posix_sock_set_sendbuf,
659 	.set_priority	= spdk_posix_sock_set_priority,
660 	.is_ipv6	= spdk_posix_sock_is_ipv6,
661 	.is_ipv4	= spdk_posix_sock_is_ipv4,
662 	.get_placement_id	= spdk_posix_sock_get_placement_id,
663 	.group_impl_create	= spdk_posix_sock_group_impl_create,
664 	.group_impl_add_sock	= spdk_posix_sock_group_impl_add_sock,
665 	.group_impl_remove_sock = spdk_posix_sock_group_impl_remove_sock,
666 	.group_impl_poll	= spdk_posix_sock_group_impl_poll,
667 	.group_impl_close	= spdk_posix_sock_group_impl_close,
668 };
669 
670 SPDK_NET_IMPL_REGISTER(posix, &g_posix_net_impl);
671