1#define _POSIX_C_SOURCE 200809L
65#include <netinet/in.h>
70#include "rte/oal/memory/rte_mem_util.h"
71#include "rte/oal/log/rte_log.h"
72#include <sys/socket.h>
78#define POSIX_NETLINK_UDP_HELLO ((uint8_t)0xA5U)
79#define POSIX_NETLINK_UDP_HELLO_ACK ((uint8_t)0x5AU)
88#define POSIX_NETLINK_UDP_HELLO_PERIOD_MS (20U)
101typedef char posix_netlink_storage_fits_[(
sizeof(
posix_netlink_state_t) <=
sizeof(rte_netlink_storage_t)) ? 1
104static rte_status_t set_nonblocking(
int fd)
106 int flags = fcntl(fd, F_GETFL, 0);
110 return RTE_STATUS_INTERNAL_ERROR;
112 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0)
114 return RTE_STATUS_INTERNAL_ERROR;
116 return RTE_STATUS_OK;
119static void compute_deadline(rte_duration_ms_t timeout_ms,
struct timespec *out_deadline)
121 (void)clock_gettime(CLOCK_MONOTONIC, out_deadline);
122 out_deadline->tv_sec += (time_t)(timeout_ms / 1000U);
123 out_deadline->tv_nsec += (long)((timeout_ms % 1000U) * 1000000L);
124 if (out_deadline->tv_nsec >= 1000000000L)
126 out_deadline->tv_sec += 1;
127 out_deadline->tv_nsec -= 1000000000L;
132static bool same_peer(
const struct sockaddr_in *a,
const struct sockaddr_in *b)
134 return (a->sin_addr.s_addr == b->sin_addr.s_addr) && (a->sin_port == b->sin_port);
137static rte_status_t open_listen_udp(
const rte_netlink_config_t *config,
int *out_fd,
struct sockaddr_in *out_peer,
138 socklen_t *out_peer_len)
142 struct sockaddr_in bind_addr;
143 struct sockaddr_in peer_addr;
144 struct timespec deadline;
145 uint8_t ack_byte = POSIX_NETLINK_UDP_HELLO_ACK;
146 socklen_t peer_addr_len =
sizeof(peer_addr);
148 fd = socket(AF_INET, SOCK_DGRAM, 0);
153 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
157 return RTE_STATUS_INTERNAL_ERROR;
159 (void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
161 rte_mem_set(&bind_addr, 0,
sizeof(bind_addr));
162 bind_addr.sin_family = AF_INET;
163 bind_addr.sin_port = htons(config->port);
164 if (config->host == NULL)
166 bind_addr.sin_addr.s_addr = INADDR_ANY;
168 else if (inet_pton(AF_INET, config->host, &bind_addr.sin_addr) != 1)
171 return RTE_STATUS_INVALID_PARAM;
174 if (bind(fd, (
struct sockaddr *)&bind_addr,
sizeof(bind_addr)) != 0)
178 (void)snprintf(msg,
sizeof(msg),
"RTE: open_listen_udp: bind port %u failed errno=%d", config->port, errno);
179 rte_log_write(RTE_LOG_LEVEL_ERROR,
"RTE", msg);
181 return RTE_STATUS_INTERNAL_ERROR;
186 (void)snprintf(msg,
sizeof(msg),
"RTE: open UDP listen bound port %u successfully (fd=%d)", config->port, fd);
187 rte_log_write(RTE_LOG_LEVEL_INFO,
"RTE", msg);
193 if (buf_status != RTE_STATUS_OK)
199 if (set_nonblocking(fd) != RTE_STATUS_OK)
202 return RTE_STATUS_INTERNAL_ERROR;
209 int wait_ms = posix_remaining_ms(&deadline);
217 rc = poll(&pfd, 1, (wait_ms > 0) ? wait_ms : 0);
221 return RTE_STATUS_TIMEOUT;
230 return RTE_STATUS_TIMEOUT;
235 return RTE_STATUS_INTERNAL_ERROR;
238 rte_mem_set(&peer_addr, 0,
sizeof(peer_addr));
239 peer_addr_len =
sizeof(peer_addr);
240 n = recvfrom(fd, &hello_byte,
sizeof(hello_byte), 0, (
struct sockaddr *)&peer_addr, &peer_addr_len);
243 if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR))
250 (void)snprintf(msg,
sizeof(msg),
"RTE: open_listen_udp: recvfrom failed errno=%d", errno);
251 rte_log_write(RTE_LOG_LEVEL_ERROR,
"RTE", msg);
254 return RTE_STATUS_INTERNAL_ERROR;
260 rte_log_write(RTE_LOG_LEVEL_INFO,
"RTE",
"RTE: open UDP listen learned its peer, sending ACK");
264 if (sendto(fd, &ack_byte,
sizeof(ack_byte), 0, (
struct sockaddr *)&peer_addr, peer_addr_len)
265 != (ssize_t)
sizeof(ack_byte))
269 (void)snprintf(msg,
sizeof(msg),
"RTE: open_listen_udp: send ACK failed errno=%d", errno);
270 rte_log_write(RTE_LOG_LEVEL_ERROR,
"RTE", msg);
272 return RTE_STATUS_INTERNAL_ERROR;
274 rte_log_write(RTE_LOG_LEVEL_INFO,
"RTE",
"RTE: open UDP listen ACK sent OK");
287 *out_peer = peer_addr;
288 *out_peer_len = peer_addr_len;
289 return RTE_STATUS_OK;
292static rte_status_t open_connect_udp(
const rte_netlink_config_t *config,
int *out_fd)
294 struct addrinfo hints;
295 struct addrinfo *resolved = NULL;
298 struct timespec deadline;
299 struct timespec next_hello_deadline;
302 (void)snprintf(port_str,
sizeof(port_str),
"%u", (
unsigned int)config->port);
306 (void)snprintf(msg,
sizeof(msg),
"RTE: opening UDP connection to host=%s port=%s", config->host, port_str);
307 rte_log_write(RTE_LOG_LEVEL_DEBUG,
"RTE", msg);
310 rte_mem_set(&hints, 0,
sizeof(hints));
311 hints.ai_family = AF_INET;
312 hints.ai_socktype = SOCK_DGRAM;
313 if (getaddrinfo(config->host, port_str, &hints, &resolved) != 0)
315 return RTE_STATUS_INVALID_PARAM;
318 fd = socket(resolved->ai_family, resolved->ai_socktype, resolved->ai_protocol);
323 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
327 freeaddrinfo(resolved);
328 return RTE_STATUS_INTERNAL_ERROR;
334 if (buf_status != RTE_STATUS_OK)
337 freeaddrinfo(resolved);
341 if (set_nonblocking(fd) != RTE_STATUS_OK)
344 freeaddrinfo(resolved);
345 return RTE_STATUS_INTERNAL_ERROR;
352 if (connect(fd, resolved->ai_addr, resolved->ai_addrlen) != 0)
356 (void)snprintf(msg,
sizeof(msg),
"RTE: open UDP connect failed errno=%d", errno);
357 rte_log_write(RTE_LOG_LEVEL_ERROR,
"RTE", msg);
359 freeaddrinfo(resolved);
360 return RTE_STATUS_INTERNAL_ERROR;
365 (void)snprintf(msg,
sizeof(msg),
"RTE: open UDP connect succeeded (fd=%d)", fd);
366 rte_log_write(RTE_LOG_LEVEL_INFO,
"RTE", msg);
368 freeaddrinfo(resolved);
372 rte_log_write(RTE_LOG_LEVEL_DEBUG,
"RTE",
"RTE: open UDP handshake entering loop");
376 int wait_ms = posix_remaining_ms(&deadline);
396 return RTE_STATUS_TIMEOUT;
399 hello_wait_ms = posix_remaining_ms(&next_hello_deadline);
400 if (hello_wait_ms <= 0)
402 ssize_t sres = send(fd, &hello_byte,
sizeof(hello_byte), 0);
404 if ((sres < 0) && (errno != ECONNREFUSED) &&
405 (errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != ENOTCONN) &&
406 (errno != EHOSTUNREACH) && (errno != EADDRNOTAVAIL) && (errno != EPIPE) &&
407 (errno != ECONNRESET) && (errno != ENETUNREACH))
411 (void)snprintf(msg,
sizeof(msg),
"RTE: open_connect_udp: unhandled send error errno=%d", errno);
412 rte_log_write(RTE_LOG_LEVEL_ERROR,
"RTE", msg);
414 return RTE_STATUS_INTERNAL_ERROR;
417 hello_wait_ms = posix_remaining_ms(&next_hello_deadline);
420 poll_wait_ms = (hello_wait_ms < wait_ms) ? hello_wait_ms : wait_ms;
424 rc = poll(&pfd, 1, poll_wait_ms);
432 return RTE_STATUS_INTERNAL_ERROR;
439 n = recv(fd, &ack_byte,
sizeof(ack_byte), MSG_PEEK);
442 if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR) || (errno == ECONNREFUSED) ||
443 (errno == ENOTCONN) || (errno == EHOSTUNREACH) || (errno == EPIPE) || (errno == ECONNRESET) ||
444 (errno == ENETUNREACH))
451 (void)snprintf(msg,
sizeof(msg),
"RTE: open_connect_udp: recv failed errno=%d", errno);
452 rte_log_write(RTE_LOG_LEVEL_ERROR,
"RTE", msg);
455 return RTE_STATUS_INTERNAL_ERROR;
460 (void)snprintf(msg,
sizeof(msg),
"RTE: open_connect_udp: peeked n=%ld byte=%02x", (
long)n, ack_byte);
461 rte_log_write(RTE_LOG_LEVEL_DEBUG,
"RTE", msg);
463 if ((n == (ssize_t)
sizeof(ack_byte)) && (ack_byte == POSIX_NETLINK_UDP_HELLO_ACK))
465 uint8_t consumed_byte;
467 (void)recv(fd, &consumed_byte,
sizeof(consumed_byte), 0);
468 rte_log_write(RTE_LOG_LEVEL_INFO,
"RTE",
"RTE: open UDP connect consumed ACK successfully");
478 return RTE_STATUS_OK;
481static rte_status_t osadapter_open(rte_netlink_storage_t *storage,
const rte_netlink_config_t *config,
482 rte_netlink_handle_t *out_handle)
487 struct sockaddr_in peer;
488 socklen_t peer_len = 0;
490 if ((storage == NULL) || (config == NULL) || (out_handle == NULL))
492 return RTE_STATUS_INVALID_PARAM;
498 (void)snprintf(msg,
sizeof(msg),
"RTE: osadapter_open role=%d host=%s port=%u", config->role,
499 config->host ? config->host :
"NULL", config->port);
500 rte_log_write(RTE_LOG_LEVEL_DEBUG,
"RTE", msg);
502 rte_mem_set(&peer, 0,
sizeof(peer));
503 if (config->role == RTE_NETLINK_ROLE_LISTEN)
505 status = open_listen_udp(config, &fd, &peer, &peer_len);
509 status = open_connect_udp(config, &fd);
514 (void)snprintf(msg,
sizeof(msg),
"RTE: osadapter_open (role=%d) returned status=%d", config->role, (
int)status);
515 rte_log_write(RTE_LOG_LEVEL_DEBUG,
"RTE", msg);
517 if (status != RTE_STATUS_OK)
524 state->message_size = config->message_size;
525 state->
listen = (config->role == RTE_NETLINK_ROLE_LISTEN);
527 state->peer_len = peer_len;
528 *out_handle = (rte_netlink_handle_t)(
void *)storage;
529 return RTE_STATUS_OK;
532static rte_status_t backend_send(rte_netlink_handle_t handle,
const void *message,
size_t message_size,
533 rte_duration_ms_t timeout_ms)
536 struct timespec deadline;
537 bool first_iteration =
true;
539 if ((state == NULL) || (message == NULL) || (message_size == 0U))
541 return RTE_STATUS_INVALID_PARAM;
548 int wait_ms = posix_remaining_ms(&deadline);
552 if (!first_iteration && (wait_ms <= 0))
554 return RTE_STATUS_TIMEOUT;
556 first_iteration =
false;
562 pfd.events = POLLOUT;
564 rc = poll(&pfd, 1, wait_ms);
567 return RTE_STATUS_TIMEOUT;
575 return RTE_STATUS_INTERNAL_ERROR;
579 ? sendto(state->fd, message, message_size, 0, (
const struct sockaddr *)&state->
peer, state->peer_len)
580 : send(state->fd, message, message_size, 0);
583 if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR))
587 if (errno == ECONNREFUSED)
589 return RTE_STATUS_HARDWARE_FAULT;
591 return RTE_STATUS_INTERNAL_ERROR;
593 if ((
size_t)n != message_size)
599 return RTE_STATUS_INTERNAL_ERROR;
601 return RTE_STATUS_OK;
605static rte_status_t
backend_receive(rte_netlink_handle_t handle,
void *out_message,
size_t buffer_size,
606 rte_duration_ms_t timeout_ms)
609 struct timespec deadline;
610 bool first_iteration =
true;
612 if ((state == NULL) || (out_message == NULL) || (buffer_size == 0U))
614 return RTE_STATUS_INVALID_PARAM;
621 int wait_ms = posix_remaining_ms(&deadline);
625 if (!first_iteration && (wait_ms <= 0))
627 return RTE_STATUS_TIMEOUT;
629 first_iteration =
false;
637 rc = poll(&pfd, 1, wait_ms);
640 return RTE_STATUS_TIMEOUT;
648 return RTE_STATUS_INTERNAL_ERROR;
659 struct sockaddr_in src;
660 socklen_t src_len =
sizeof(src);
662 n = recvfrom(state->fd, out_message, buffer_size, 0, (
struct sockaddr *)&src, &src_len);
664 n = recvfrom(state->fd, out_message, buffer_size, MSG_TRUNC, (
struct sockaddr *)&src, &src_len);
672 const uint8_t ack = POSIX_NETLINK_UDP_HELLO_ACK;
675 state->peer_len = src_len;
676 (void)sendto(state->fd, &ack,
sizeof(ack), 0, (
const struct sockaddr *)&src, src_len);
677 rte_log_write(RTE_LOG_LEVEL_INFO,
"RTE",
"RTE: UDP listen re-learned a restarted peer");
684 const uint8_t ack = POSIX_NETLINK_UDP_HELLO_ACK;
686 (void)sendto(state->fd, &ack,
sizeof(ack), 0, (
const struct sockaddr *)&src, src_len);
692 if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR))
696 if (errno == ECONNREFUSED)
698 return RTE_STATUS_HARDWARE_FAULT;
700 return RTE_STATUS_INTERNAL_ERROR;
702 if ((
size_t)n != buffer_size)
712 if ((n == (ssize_t)
sizeof(uint8_t)) &&
714 (((
const uint8_t *)out_message)[0] == POSIX_NETLINK_UDP_HELLO_ACK)))
723 return RTE_STATUS_DATA_CORRUPTION;
725 return RTE_STATUS_OK;
729static rte_status_t osadapter_close(rte_netlink_handle_t handle)
735 return RTE_STATUS_INVALID_PARAM;
737 (void)close(state->fd);
738 return RTE_STATUS_OK;
741static const rte_osadapter_netlink_t s_posix_netlink_osadapter = { osadapter_open, backend_send,
backend_receive,
746 return &s_posix_netlink_osadapter;
Real POSIX/Linux OSAdapter for every OAL service (ADR-018).
const rte_osadapter_netlink_t * rte_posix_osadapter_netlink(void)
The POSIX rte_netlink OSAdapter (TCP sockets, LISTEN/CONNECT).
static bool compute_deadline(rte_duration_ms_t timeout_ms, struct timespec *out_deadline)
static rte_status_t backend_receive(rte_ipc_handle_t handle, void *out_message, size_t buffer_size, rte_duration_ms_t timeout_ms)
static bool same_peer(const struct sockaddr_in *a, const struct sockaddr_in *b)
#define POSIX_NETLINK_UDP_HELLO
#define POSIX_NETLINK_UDP_HELLO_PERIOD_MS
Private helpers: millisecond waits for poll()'s int timeout argument.
rte_status_t posix_socket_apply_buffers(int fd, const rte_netlink_config_t *config)
Sets and confirms config->rcvbuf_bytes (SO_RCVBUF) and config->sndbuf_bytes (SO_SNDBUF) on a socket.
Private helper: applies the socket buffer sizes of a link config (OSA rules R5, R6).