Commit 9fac978e authored by Leonardo Lai's avatar Leonardo Lai

bugfix: failed to receive packets on INADDR_ANY

parent d61b436e
......@@ -7,10 +7,13 @@
// the IPs bound to that port (typically one, but can be many)
//
#include <arpa/inet.h> // inet_ntop
#include <netinet/in.h> // INADDR_ANY
#include "udpdk_bind_table.h"
#include "udpdk_shmalloc.h"
#define RTE_LOGTYPE_BTABLE RTE_LOGTYPE_USER1
const void *bind_info_alloc = NULL;
list_t **sock_bind_table;
......@@ -34,13 +37,14 @@ int btable_get_free_port(void)
return i;
}
}
RTE_LOG(WARNING, BTABLE, "Failed to find a free port\n");
return -1;
}
/* Verify if binding the pair (ip, port) is possible, provided the
* options and the previous bindings.
*/
static inline int btable_can_bind(struct in_addr ip, int port, int opts)
static inline bool btable_can_bind(struct in_addr ip, int port, int opts)
{
bool reuse_addr = opts & SO_REUSEADDR;
bool reuse_port = opts & SO_REUSEPORT;
......@@ -52,7 +56,7 @@ static inline int btable_can_bind(struct in_addr ip, int port, int opts)
bool oth_reuseport;
if (sock_bind_table[port] == NULL) {
return 0;
return true;
}
ip_new = ip.s_addr;
......@@ -81,11 +85,7 @@ static inline int btable_can_bind(struct in_addr ip, int port, int opts)
}
list_iterator_destroy(it);
if (can_bind) {
return 0;
} else {
return -1;
}
return can_bind;
}
int btable_add_binding(int s, struct in_addr ip, int port, int opts)
......@@ -95,6 +95,9 @@ int btable_add_binding(int s, struct in_addr ip, int port, int opts)
// Check if binding this pair is allowed
if (!btable_can_bind(ip, port, opts)) {
char buf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &ip, buf, sizeof(buf));
RTE_LOG(WARNING, BTABLE, "Cannot bind socket %d to %s:%d\n", s, buf, ntohs(port));
return -1;
}
......
......@@ -312,6 +312,8 @@ static inline void reassemble(struct rte_mbuf *m, uint16_t portid, uint32_t queu
uint16_t udp_dst_port;
unsigned long ip_dst_addr;
int sock_id;
bool delivered_once = false;
bool delivered_last = false;
rxq = &qconf->rx_queue;
......@@ -360,26 +362,39 @@ static inline void reassemble(struct rte_mbuf *m, uint16_t portid, uint32_t queu
// Find the sock_ids corresponding to the UDP dst port (L4 switching) and enqueue the packet to its queue
list_t *binds = btable_get_bindings(udp_dst_port);
if (binds == NULL) {
RTE_LOG(WARNING, POLLBODY, "Dropping packet for port %d: no socket bound\n", udp_dst_port);
RTE_LOG(WARNING, POLLBODY, "Dropping packet for port %d: no socket bound\n", ntohs(udp_dst_port));
return;
}
list_iterator_t *it = list_iterator_new(binds, LIST_HEAD);
list_node_t *node;
while ((node = list_iterator_next(it))) {
// TODO hand non trivial cases (see below)
/*
if dest unicast and not REUSEPORT (LIKELY), enqueue and break
if dest unicast and SO_REUSEPORT, should load balance
if dest broadcast and SO_REUSEADDR o SO_REUSEPORT, enqueue and continue
*/
if (ip_dst_addr == ((struct bind_info *)(node->val))->ip_addr.s_addr) {
break;
unsigned long ip_oth = ((struct bind_info *)(node->val))->ip_addr.s_addr;
bool oth_reuseaddr = ((struct bind_info *)(node->val))->reuse_addr;
bool oth_reuseport = ((struct bind_info *)(node->val))->reuse_port;
// TODO the semantic should be more complex actually:
// if dest unicast and SO_REUSEPORT, should load balance
// if dest broadcast and SO_REUSEADDR or SO_REUSEPORT, should deliver to all
// If matching
if (likely((ip_dst_addr == ip_oth) || (ip_oth == INADDR_ANY))) {
// Deliver to this socket
enqueue_rx_packet(((struct bind_info *)(node->val))->sockfd, m);
delivered_once = true;
// If other socket may exist on the same port, keep scanning
if (oth_reuseaddr || oth_reuseport) {
m = rte_pktmbuf_clone(m, rxq->pool);
delivered_last = false;
continue;
} else {
delivered_last = true;
break;
}
}
}
if (node != NULL) {
enqueue_rx_packet(((struct bind_info *)(node->val))->sockfd, m);
} else {
RTE_LOG(WARNING, POLLBODY, "Dropping packet for port %d: no socket matching\n", udp_dst_port);
if (!delivered_last) {
rte_pktmbuf_free(m);
}
if (!delivered_once) {
RTE_LOG(WARNING, POLLBODY, "Dropped packet to port %d: no socket matching\n", ntohs(udp_dst_port));
}
list_iterator_destroy(it);
}
......
......@@ -218,7 +218,6 @@ static int bind_validate_args(int sockfd, const struct sockaddr *addr, socklen_t
int udpdk_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
int ret;
unsigned short port;
const struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
......@@ -229,8 +228,7 @@ int udpdk_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
// Try to bind the socket
port = addr_in->sin_port;
ret = btable_add_binding(sockfd, addr_in->sin_addr, port, exch_zone_desc->slots[sockfd].so_options);
if (ret != -1) {
if (btable_add_binding(sockfd, addr_in->sin_addr, port, exch_zone_desc->slots[sockfd].so_options) < 0) {
errno = EADDRINUSE;
RTE_LOG(ERR, SYSCALL, "Failed to bind because port %d is already in use\n", ntohs(port));
return -1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment