tap: refactor packets handling functions

Consolidate pool_tap4() and pool_tap6() into tap_flush_pools(),
and tap4_handler() and tap6_handler() into tap_handler().
Create a generic tap_add_packet() to consolidate packet
addition logic and reduce code duplication.

The purpose is to ease the export of these functions to use
them with the vhost-user backend.

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
Laurent Vivier 2024-06-13 14:36:50 +02:00 committed by Stefano Brivio
parent fba2b544b6
commit 9ecf7fedc5
2 changed files with 64 additions and 49 deletions

110
tap.c
View file

@ -921,6 +921,58 @@ append:
return in->count; return in->count;
} }
/**
* tap_flush_pools() - Flush both IPv4 and IPv6 packet pools
*/
void tap_flush_pools(void)
{
pool_flush(pool_tap4);
pool_flush(pool_tap6);
}
/**
* tap_handler() - IPv4/IPv6 and ARP packet handler for tap file descriptor
* @c: Execution context
* @now: Current timestamp
*/
void tap_handler(struct ctx *c, const struct timespec *now)
{
tap4_handler(c, pool_tap4, now);
tap6_handler(c, pool_tap6, now);
}
/**
* tap_add_packet() - Queue/capture packet, update notion of guest MAC address
* @c: Execution context
* @l2len: Total L2 packet length
* @p: Packet buffer
*/
void tap_add_packet(struct ctx *c, ssize_t l2len, char *p)
{
const struct ethhdr *eh;
pcap(p, l2len);
eh = (struct ethhdr *)p;
if (memcmp(c->mac_guest, eh->h_source, ETH_ALEN)) {
memcpy(c->mac_guest, eh->h_source, ETH_ALEN);
proto_update_l2_buf(c->mac_guest, NULL);
}
switch (ntohs(eh->h_proto)) {
case ETH_P_ARP:
case ETH_P_IP:
packet_add(pool_tap4, l2len, p);
break;
case ETH_P_IPV6:
packet_add(pool_tap6, l2len, p);
break;
default:
break;
}
}
/** /**
* tap_sock_reset() - Handle closing or failure of connect AF_UNIX socket * tap_sock_reset() - Handle closing or failure of connect AF_UNIX socket
* @c: Execution context * @c: Execution context
@ -947,7 +999,6 @@ static void tap_sock_reset(struct ctx *c)
void tap_handler_passt(struct ctx *c, uint32_t events, void tap_handler_passt(struct ctx *c, uint32_t events,
const struct timespec *now) const struct timespec *now)
{ {
const struct ethhdr *eh;
ssize_t n, rem; ssize_t n, rem;
char *p; char *p;
@ -960,8 +1011,7 @@ redo:
p = pkt_buf; p = pkt_buf;
rem = 0; rem = 0;
pool_flush(pool_tap4); tap_flush_pools();
pool_flush(pool_tap6);
n = recv(c->fd_tap, p, TAP_BUF_FILL, MSG_DONTWAIT); n = recv(c->fd_tap, p, TAP_BUF_FILL, MSG_DONTWAIT);
if (n < 0) { if (n < 0) {
@ -988,38 +1038,18 @@ redo:
/* Complete the partial read above before discarding a malformed /* Complete the partial read above before discarding a malformed
* frame, otherwise the stream will be inconsistent. * frame, otherwise the stream will be inconsistent.
*/ */
if (l2len < (ssize_t)sizeof(*eh) || if (l2len < (ssize_t)sizeof(struct ethhdr) ||
l2len > (ssize_t)ETH_MAX_MTU) l2len > (ssize_t)ETH_MAX_MTU)
goto next; goto next;
pcap(p, l2len); tap_add_packet(c, l2len, p);
eh = (struct ethhdr *)p;
if (memcmp(c->mac_guest, eh->h_source, ETH_ALEN)) {
memcpy(c->mac_guest, eh->h_source, ETH_ALEN);
proto_update_l2_buf(c->mac_guest, NULL);
}
switch (ntohs(eh->h_proto)) {
case ETH_P_ARP:
case ETH_P_IP:
packet_add(pool_tap4, l2len, p);
break;
case ETH_P_IPV6:
packet_add(pool_tap6, l2len, p);
break;
default:
break;
}
next: next:
p += l2len; p += l2len;
n -= l2len; n -= l2len;
} }
tap4_handler(c, pool_tap4, now); tap_handler(c, now);
tap6_handler(c, pool_tap6, now);
/* We can't use EPOLLET otherwise. */ /* We can't use EPOLLET otherwise. */
if (rem) if (rem)
@ -1044,35 +1074,18 @@ void tap_handler_pasta(struct ctx *c, uint32_t events,
redo: redo:
n = 0; n = 0;
pool_flush(pool_tap4); tap_flush_pools();
pool_flush(pool_tap6);
restart: restart:
while ((len = read(c->fd_tap, pkt_buf + n, TAP_BUF_BYTES - n)) > 0) { while ((len = read(c->fd_tap, pkt_buf + n, TAP_BUF_BYTES - n)) > 0) {
const struct ethhdr *eh = (struct ethhdr *)(pkt_buf + n);
if (len < (ssize_t)sizeof(*eh) || len > (ssize_t)ETH_MAX_MTU) { if (len < (ssize_t)sizeof(struct ethhdr) ||
len > (ssize_t)ETH_MAX_MTU) {
n += len; n += len;
continue; continue;
} }
pcap(pkt_buf + n, len);
if (memcmp(c->mac_guest, eh->h_source, ETH_ALEN)) { tap_add_packet(c, len, pkt_buf + n);
memcpy(c->mac_guest, eh->h_source, ETH_ALEN);
proto_update_l2_buf(c->mac_guest, NULL);
}
switch (ntohs(eh->h_proto)) {
case ETH_P_ARP:
case ETH_P_IP:
packet_add(pool_tap4, len, pkt_buf + n);
break;
case ETH_P_IPV6:
packet_add(pool_tap6, len, pkt_buf + n);
break;
default:
break;
}
if ((n += len) == TAP_BUF_BYTES) if ((n += len) == TAP_BUF_BYTES)
break; break;
@ -1083,8 +1096,7 @@ restart:
ret = errno; ret = errno;
tap4_handler(c, pool_tap4, now); tap_handler(c, now);
tap6_handler(c, pool_tap6, now);
if (len > 0 || ret == EAGAIN) if (len > 0 || ret == EAGAIN)
return; return;

3
tap.h
View file

@ -70,5 +70,8 @@ void tap_handler_passt(struct ctx *c, uint32_t events,
const struct timespec *now); const struct timespec *now);
int tap_sock_unix_open(char *sock_path); int tap_sock_unix_open(char *sock_path);
void tap_sock_init(struct ctx *c); void tap_sock_init(struct ctx *c);
void tap_flush_pools(void);
void tap_handler(struct ctx *c, const struct timespec *now);
void tap_add_packet(struct ctx *c, ssize_t l2len, char *p);
#endif /* TAP_H */ #endif /* TAP_H */