4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 #include "spdk/stdinc.h"
37 #include "spdk/sock.h"
39 #include "spdk/string.h"
40 #include "spdk_internal/sock.h"
41 #include <vcl/vppcom.h>
43 #define MAX_TMPBUF 1024
46 static bool g_vpp_initialized
= false;
48 struct spdk_vpp_sock
{
49 struct spdk_sock base
;
53 struct spdk_vpp_sock_group_impl
{
54 struct spdk_sock_group_impl base
;
59 get_addr_str(struct sockaddr
*sa
, char *host
, size_t hlen
)
61 const char *result
= NULL
;
63 if (sa
== NULL
|| host
== NULL
) {
67 if (sa
->sa_family
== AF_INET
) {
68 result
= inet_ntop(AF_INET
, &(((struct sockaddr_in
*)sa
)->sin_addr
),
71 result
= inet_ntop(AF_INET6
, &(((struct sockaddr_in6
*)sa
)->sin6_addr
),
82 #define __vpp_sock(sock) (struct spdk_vpp_sock *)sock
83 #define __vpp_group_impl(group) (struct spdk_vpp_sock_group_impl *)group
86 vcom_socket_copy_ep_to_sockaddr(struct sockaddr
*addr
, socklen_t
*len
, vppcom_endpt_t
*ep
)
90 assert(ep
->vrf
== VPPCOM_VRF_DEFAULT
);
92 if (ep
->is_ip4
== VPPCOM_IS_IP4
) {
93 addr
->sa_family
= AF_INET
;
94 ((struct sockaddr_in
*) addr
)->sin_port
= ep
->port
;
95 if (*len
> sizeof(struct sockaddr_in
)) {
96 *len
= sizeof(struct sockaddr_in
);
98 sa_len
= sizeof(struct sockaddr_in
) - sizeof(struct in_addr
);
99 copy_len
= *len
- sa_len
;
101 memcpy(&((struct sockaddr_in
*) addr
)->sin_addr
, ep
->ip
, copy_len
);
104 addr
->sa_family
= AF_INET6
;
105 ((struct sockaddr_in6
*) addr
)->sin6_port
= ep
->port
;
106 if (*len
> sizeof(struct sockaddr_in6
)) {
107 *len
= sizeof(struct sockaddr_in6
);
109 sa_len
= sizeof(struct sockaddr_in6
) - sizeof(struct in6_addr
);
110 copy_len
= *len
- sa_len
;
112 memcpy(&((struct sockaddr_in6
*) addr
)->sin6_addr
, ep
->ip
, copy_len
);
118 getsockname_vpp(int fd
, struct sockaddr
*addr
, socklen_t
*len
)
121 uint32_t size
= sizeof(ep
);
122 uint8_t addr_buf
[sizeof(struct in6_addr
)];
131 rc
= vppcom_session_attr(fd
, VPPCOM_ATTR_GET_LCL_ADDR
, &ep
, &size
);
132 if (rc
== VPPCOM_OK
) {
133 vcom_socket_copy_ep_to_sockaddr(addr
, len
, &ep
);
141 getpeername_vpp(int sock
, struct sockaddr
*addr
, socklen_t
*len
)
144 uint32_t size
= sizeof(ep
);
145 uint8_t addr_buf
[sizeof(struct in6_addr
)];
154 rc
= vppcom_session_attr(sock
, VPPCOM_ATTR_GET_PEER_ADDR
, &ep
, &size
);
155 if (rc
== VPPCOM_OK
) {
156 vcom_socket_copy_ep_to_sockaddr(addr
, len
, &ep
);
163 spdk_vpp_sock_getaddr(struct spdk_sock
*_sock
, char *saddr
, int slen
, uint16_t *sport
,
164 char *caddr
, int clen
, uint16_t *cport
)
166 struct spdk_vpp_sock
*sock
= __vpp_sock(_sock
);
171 assert(sock
!= NULL
);
172 assert(g_vpp_initialized
);
174 memset(&sa
, 0, sizeof(sa
));
176 rc
= getsockname_vpp(sock
->fd
, &sa
, &salen
);
179 SPDK_ERRLOG("getsockname_vpp() failed (errno=%d)\n", errno
);
183 rc
= get_addr_str(&sa
, saddr
, slen
);
185 /* Errno already set by get_addr_str() */
186 SPDK_ERRLOG("get_addr_str() failed (errno=%d)\n", errno
);
191 if (sa
.ss_family
== AF_INET
) {
192 *sport
= ntohs(((struct sockaddr_in
*) &sa
)->sin_port
);
193 } else if (sa
.ss_family
== AF_INET6
) {
194 *sport
= ntohs(((struct sockaddr_in6
*) &sa
)->sin6_port
);
198 memset(&sa
, 0, sizeof(sa
));
200 rc
= getpeername_vpp(sock
->fd
, &sa
, &salen
);
203 SPDK_ERRLOG("getpeername_vpp() failed (errno=%d)\n", errno
);
207 rc
= get_addr_str(&sa
, caddr
, clen
);
209 /* Errno already set by get_addr_str() */
210 SPDK_ERRLOG("get_addr_str() failed (errno=%d)\n", errno
);
215 if (sa
.ss_family
== AF_INET
) {
216 *cport
= ntohs(((struct sockaddr_in
*) &sa
)->sin_port
);
217 } else if (sa
.ss_family
== AF_INET6
) {
218 *cport
= ntohs(((struct sockaddr_in6
*) &sa
)->sin6_port
);
225 enum spdk_vpp_create_type
{
226 SPDK_SOCK_CREATE_LISTEN
,
227 SPDK_SOCK_CREATE_CONNECT
,
230 static struct spdk_sock
*
231 spdk_vpp_sock_create(const char *ip
, int port
, enum spdk_vpp_create_type type
)
233 struct spdk_vpp_sock
*sock
;
235 vppcom_endpt_t endpt
;
236 uint8_t addr_buf
[sizeof(struct in6_addr
)];
242 /* Check address family */
243 if (inet_pton(AF_INET
, ip
, &addr_buf
)) {
244 endpt
.is_ip4
= VPPCOM_IS_IP4
;
245 } else if (inet_pton(AF_INET6
, ip
, &addr_buf
)) {
246 endpt
.is_ip4
= VPPCOM_IS_IP6
;
248 SPDK_ERRLOG("IP address with invalid format\n");
251 endpt
.vrf
= VPPCOM_VRF_DEFAULT
;
252 endpt
.ip
= (uint8_t *)&addr_buf
;
253 endpt
.port
= htons(port
);
255 fd
= vppcom_session_create(VPPCOM_VRF_DEFAULT
, VPPCOM_PROTO_TCP
, 1 /* is_nonblocking */);
258 SPDK_ERRLOG("vppcom_session_create() failed, errno = %d\n", errno
);
262 if (type
== SPDK_SOCK_CREATE_LISTEN
) {
263 rc
= vppcom_session_bind(fd
, &endpt
);
264 if (rc
!= VPPCOM_OK
) {
266 SPDK_ERRLOG("vppcom_session_bind() failed, errno = %d\n", errno
);
267 vppcom_session_close(fd
);
271 rc
= vppcom_session_listen(fd
, 512);
272 if (rc
!= VPPCOM_OK
) {
274 SPDK_ERRLOG("vppcom_session_listen() failed, errno = %d\n", errno
);
275 vppcom_session_close(fd
);
278 } else if (type
== SPDK_SOCK_CREATE_CONNECT
) {
279 rc
= vppcom_session_connect(fd
, &endpt
);
280 if (rc
!= VPPCOM_OK
) {
282 SPDK_ERRLOG("vppcom_session_connect() failed, errno = %d\n", errno
);
283 vppcom_session_close(fd
);
288 sock
= calloc(1, sizeof(*sock
));
291 SPDK_ERRLOG("sock allocation failed\n");
292 vppcom_session_close(fd
);
300 static struct spdk_sock
*
301 spdk_vpp_sock_listen(const char *ip
, int port
)
303 if (!g_vpp_initialized
) {
307 return spdk_vpp_sock_create(ip
, port
, SPDK_SOCK_CREATE_LISTEN
);
310 static struct spdk_sock
*
311 spdk_vpp_sock_connect(const char *ip
, int port
)
313 if (!g_vpp_initialized
) {
317 return spdk_vpp_sock_create(ip
, port
, SPDK_SOCK_CREATE_CONNECT
);
320 static struct spdk_sock
*
321 spdk_vpp_sock_accept(struct spdk_sock
*_sock
)
323 struct spdk_vpp_sock
*sock
= __vpp_sock(_sock
);
324 vppcom_endpt_t endpt
;
327 struct spdk_vpp_sock
*new_sock
;
328 double wait_time
= -1.0;
332 assert(sock
!= NULL
);
333 assert(g_vpp_initialized
);
335 rc
= vppcom_session_accept(sock
->fd
, &endpt
, O_NONBLOCK
, wait_time
);
341 new_sock
= calloc(1, sizeof(*sock
));
342 if (new_sock
== NULL
) {
343 SPDK_ERRLOG("sock allocation failed\n");
344 vppcom_session_close(rc
);
349 return &new_sock
->base
;
353 spdk_vpp_sock_close(struct spdk_sock
*_sock
)
355 struct spdk_vpp_sock
*sock
= __vpp_sock(_sock
);
358 assert(sock
!= NULL
);
359 assert(g_vpp_initialized
);
361 rc
= vppcom_session_close(sock
->fd
);
362 if (rc
!= VPPCOM_OK
) {
372 spdk_vpp_sock_recv(struct spdk_sock
*_sock
, void *buf
, size_t len
)
374 struct spdk_vpp_sock
*sock
= __vpp_sock(_sock
);
377 assert(sock
!= NULL
);
378 assert(g_vpp_initialized
);
380 rc
= vppcom_session_read(sock
->fd
, buf
, len
);
389 spdk_vpp_sock_writev(struct spdk_sock
*_sock
, struct iovec
*iov
, int iovcnt
)
391 struct spdk_vpp_sock
*sock
= __vpp_sock(_sock
);
395 assert(sock
!= NULL
);
396 assert(g_vpp_initialized
);
398 for (i
= 0; i
< iovcnt
; ++i
) {
399 rc
= vppcom_session_write(sock
->fd
, iov
[i
].iov_base
, iov
[i
].iov_len
);
416 * TODO: Check if there are similar parameters to configure in VPP
420 spdk_vpp_sock_set_recvlowat(struct spdk_sock
*_sock
, int nbytes
)
422 assert(g_vpp_initialized
);
428 spdk_vpp_sock_set_recvbuf(struct spdk_sock
*_sock
, int sz
)
430 assert(g_vpp_initialized
);
436 spdk_vpp_sock_set_sendbuf(struct spdk_sock
*_sock
, int sz
)
438 assert(g_vpp_initialized
);
444 spdk_vpp_sock_is_ipv6(struct spdk_sock
*_sock
)
446 struct spdk_vpp_sock
*sock
= __vpp_sock(_sock
);
448 uint32_t size
= sizeof(ep
);
449 uint8_t addr_buf
[sizeof(struct in6_addr
)];
452 assert(sock
!= NULL
);
453 assert(g_vpp_initialized
);
457 rc
= vppcom_session_attr(sock
->fd
, VPPCOM_ATTR_GET_LCL_ADDR
, &ep
, &size
);
458 if (rc
!= VPPCOM_OK
) {
463 return (ep
.is_ip4
== VPPCOM_IS_IP6
);
467 spdk_vpp_sock_is_ipv4(struct spdk_sock
*_sock
)
469 struct spdk_vpp_sock
*sock
= __vpp_sock(_sock
);
471 uint32_t size
= sizeof(ep
);
472 uint8_t addr_buf
[sizeof(struct in6_addr
)];
475 assert(sock
!= NULL
);
476 assert(g_vpp_initialized
);
480 rc
= vppcom_session_attr(sock
->fd
, VPPCOM_ATTR_GET_LCL_ADDR
, &ep
, &size
);
481 if (rc
!= VPPCOM_OK
) {
486 return (ep
.is_ip4
== VPPCOM_IS_IP4
);
489 static struct spdk_sock_group_impl
*
490 spdk_vpp_sock_group_impl_create(void)
492 struct spdk_vpp_sock_group_impl
*group_impl
;
495 if (!g_vpp_initialized
) {
499 group_impl
= calloc(1, sizeof(*group_impl
));
500 if (group_impl
== NULL
) {
501 SPDK_ERRLOG("sock_group allocation failed\n");
505 fd
= vppcom_epoll_create();
513 return &group_impl
->base
;
517 spdk_vpp_sock_group_impl_add_sock(struct spdk_sock_group_impl
*_group
, struct spdk_sock
*_sock
)
519 struct spdk_vpp_sock_group_impl
*group
= __vpp_group_impl(_group
);
520 struct spdk_vpp_sock
*sock
= __vpp_sock(_sock
);
522 struct epoll_event event
;
524 assert(sock
!= NULL
);
525 assert(group
!= NULL
);
526 assert(g_vpp_initialized
);
528 event
.events
= EPOLLIN
;
529 event
.data
.ptr
= sock
;
531 rc
= vppcom_epoll_ctl(group
->fd
, EPOLL_CTL_ADD
, sock
->fd
, &event
);
532 if (rc
!= VPPCOM_OK
) {
541 spdk_vpp_sock_group_impl_remove_sock(struct spdk_sock_group_impl
*_group
, struct spdk_sock
*_sock
)
543 struct spdk_vpp_sock_group_impl
*group
= __vpp_group_impl(_group
);
544 struct spdk_vpp_sock
*sock
= __vpp_sock(_sock
);
546 struct epoll_event event
;
548 assert(sock
!= NULL
);
549 assert(group
!= NULL
);
550 assert(g_vpp_initialized
);
552 rc
= vppcom_epoll_ctl(group
->fd
, EPOLL_CTL_DEL
, sock
->fd
, &event
);
553 if (rc
!= VPPCOM_OK
) {
562 spdk_vpp_sock_group_impl_poll(struct spdk_sock_group_impl
*_group
, int max_events
,
563 struct spdk_sock
**socks
)
565 struct spdk_vpp_sock_group_impl
*group
= __vpp_group_impl(_group
);
567 struct epoll_event events
[MAX_EVENTS_PER_POLL
];
569 assert(group
!= NULL
);
570 assert(socks
!= NULL
);
571 assert(g_vpp_initialized
);
573 num_events
= vppcom_epoll_wait(group
->fd
, events
, max_events
, 0);
574 if (num_events
< 0) {
579 for (i
= 0; i
< num_events
; i
++) {
580 socks
[i
] = events
[i
].data
.ptr
;
587 spdk_vpp_sock_group_impl_close(struct spdk_sock_group_impl
*_group
)
589 struct spdk_vpp_sock_group_impl
*group
= __vpp_group_impl(_group
);
592 assert(group
!= NULL
);
593 assert(g_vpp_initialized
);
595 rc
= vppcom_session_close(group
->fd
);
596 if (rc
!= VPPCOM_OK
) {
604 static struct spdk_net_impl g_vpp_net_impl
= {
606 .getaddr
= spdk_vpp_sock_getaddr
,
607 .connect
= spdk_vpp_sock_connect
,
608 .listen
= spdk_vpp_sock_listen
,
609 .accept
= spdk_vpp_sock_accept
,
610 .close
= spdk_vpp_sock_close
,
611 .recv
= spdk_vpp_sock_recv
,
612 .writev
= spdk_vpp_sock_writev
,
613 .set_recvlowat
= spdk_vpp_sock_set_recvlowat
,
614 .set_recvbuf
= spdk_vpp_sock_set_recvbuf
,
615 .set_sendbuf
= spdk_vpp_sock_set_sendbuf
,
616 .is_ipv6
= spdk_vpp_sock_is_ipv6
,
617 .is_ipv4
= spdk_vpp_sock_is_ipv4
,
618 .group_impl_create
= spdk_vpp_sock_group_impl_create
,
619 .group_impl_add_sock
= spdk_vpp_sock_group_impl_add_sock
,
620 .group_impl_remove_sock
= spdk_vpp_sock_group_impl_remove_sock
,
621 .group_impl_poll
= spdk_vpp_sock_group_impl_poll
,
622 .group_impl_close
= spdk_vpp_sock_group_impl_close
,
625 SPDK_NET_IMPL_REGISTER(vpp
, &g_vpp_net_impl
);
628 spdk_vpp_net_framework_init(void)
633 app_name
= spdk_sprintf_alloc("SPDK_%d", getpid());
634 if (app_name
== NULL
) {
635 SPDK_ERRLOG("Cannot alloc memory for SPDK app name\n");
639 rc
= vppcom_app_create(app_name
);
641 g_vpp_initialized
= true;
650 spdk_vpp_net_framework_fini(void)
652 if (g_vpp_initialized
) {
653 vppcom_app_destroy();
657 static struct spdk_net_framework g_vpp_net_framework
= {
659 .init
= spdk_vpp_net_framework_init
,
660 .fini
= spdk_vpp_net_framework_fini
,
663 SPDK_NET_FRAMEWORK_REGISTER(vpp
, &g_vpp_net_framework
);