diff options
author | Laurent Vivier <lvivier@redhat.com> | 2025-09-02 09:52:27 +0200 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2025-09-03 20:42:20 +0200 |
commit | 720d8fc06946bef73ddb042c431a0c71bd6cf409 (patch) | |
tree | 7f27521b91baf6f298e60a49f10e3813b50be86b | |
parent | 70b9c0c0a2281fe332692283e4b4edd1f6db092c (diff) | |
download | passt-720d8fc06946bef73ddb042c431a0c71bd6cf409.tar passt-720d8fc06946bef73ddb042c431a0c71bd6cf409.tar.gz passt-720d8fc06946bef73ddb042c431a0c71bd6cf409.tar.bz2 passt-720d8fc06946bef73ddb042c431a0c71bd6cf409.tar.lz passt-720d8fc06946bef73ddb042c431a0c71bd6cf409.tar.xz passt-720d8fc06946bef73ddb042c431a0c71bd6cf409.tar.zst passt-720d8fc06946bef73ddb042c431a0c71bd6cf409.zip |
tap: Use iov_tail with tap_add_packet()
Use IOV_PEEK_HEADER() to get the ethernet header from the iovec.
Move the workaround about multiple iovec array from vu_handle_tx() to
tap_add_packet(). Removing the offset out of the iovec array should
reduce the iovec count to 1.
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r-- | iov.c | 1 | ||||
-rw-r--r-- | iov.h | 20 | ||||
-rw-r--r-- | pcap.c | 1 | ||||
-rw-r--r-- | tap.c | 30 | ||||
-rw-r--r-- | tap.h | 3 | ||||
-rw-r--r-- | vu_common.c | 26 |
6 files changed, 48 insertions, 33 deletions
@@ -200,7 +200,6 @@ size_t iov_tail_size(struct iov_tail *tail) * * Return: true if the item still contains any bytes, otherwise false */ -/* cppcheck-suppress unusedFunction */ bool iov_drop_header(struct iov_tail *tail, size_t len) { tail->off = tail->off + len; @@ -70,6 +70,18 @@ struct iov_tail { #define IOV_TAIL(iov_, cnt_, off_) \ (struct iov_tail){ .iov = (iov_), .cnt = (cnt_), .off = (off_) } +/** + * IOV_TAIL_FROM_BUF() - Create a new IOV tail from a buffer + * @buf_: Buffer address to use in the iovec + * @len_: Buffer size + * @off_: Byte offset in the buffer where the tail begins + */ +#define IOV_TAIL_FROM_BUF(buf_, len_, off_) \ + IOV_TAIL((&(const struct iovec){ .iov_base = (buf_), \ + .iov_len = (len_) }), \ + 1, \ + (off_)) + bool iov_tail_prune(struct iov_tail *tail); size_t iov_tail_size(struct iov_tail *tail); bool iov_drop_header(struct iov_tail *tail, size_t len); @@ -114,4 +126,12 @@ ssize_t iov_tail_clone(struct iovec *dst_iov, size_t dst_iov_cnt, ((__typeof__(var_) *)(iov_remove_header_((tail_), &(var_), \ sizeof(var_), __alignof__(var_)))) +/** IOV_DROP_HEADER() - Remove a typed header from an IOV tail + * @tail_: IOV tail to remove header from (modified) + * @type_: Data type of the header to remove + * + * Return: true if the tail still contains any bytes, otherwise false + */ +#define IOV_DROP_HEADER(tail_, type_) iov_drop_header((tail_), sizeof(type_)) + #endif /* IOVEC_H */ @@ -74,6 +74,7 @@ static void pcap_frame(const struct iovec *iov, size_t iovcnt, * @pkt: Pointer to data buffer, including L2 headers * @l2len: L2 frame length */ +/* cppcheck-suppress unusedFunction */ void pcap(const char *pkt, size_t l2len) { struct iovec iov = { (char *)pkt, l2len }; @@ -1070,24 +1070,29 @@ void tap_handler(struct ctx *c, const struct timespec *now) /** * tap_add_packet() - Queue/capture packet, update notion of guest MAC address * @c: Execution context - * @l2len: Total L2 packet length - * @p: Packet buffer + * @data: Packet to add to the pool * @now: Current timestamp */ -void tap_add_packet(struct ctx *c, ssize_t l2len, char *p, +void tap_add_packet(struct ctx *c, struct iov_tail *data, const struct timespec *now) { + struct ethhdr eh_storage; const struct ethhdr *eh; - pcap(p, l2len); + pcap_iov(data->iov, data->cnt, data->off); - eh = (struct ethhdr *)p; + eh = IOV_PEEK_HEADER(data, eh_storage); + if (!eh) + return; if (memcmp(c->guest_mac, eh->h_source, ETH_ALEN)) { memcpy(c->guest_mac, eh->h_source, ETH_ALEN); proto_update_l2_buf(c->guest_mac, NULL); } + iov_tail_prune(data); + ASSERT(data->cnt == 1); /* packet_add() doesn't support iovec */ + switch (ntohs(eh->h_proto)) { case ETH_P_ARP: case ETH_P_IP: @@ -1095,14 +1100,16 @@ void tap_add_packet(struct ctx *c, ssize_t l2len, char *p, tap4_handler(c, pool_tap4, now); pool_flush(pool_tap4); } - packet_add(pool_tap4, l2len, p); + packet_add(pool_tap4, data->iov[0].iov_len - data->off, + (char *)data->iov[0].iov_base + data->off); break; case ETH_P_IPV6: if (pool_full(pool_tap6)) { tap6_handler(c, pool_tap6, now); pool_flush(pool_tap6); } - packet_add(pool_tap6, l2len, p); + packet_add(pool_tap6, data->iov[0].iov_len - data->off, + (char *)data->iov[0].iov_base + data->off); break; default: break; @@ -1170,6 +1177,7 @@ static void tap_passt_input(struct ctx *c, const struct timespec *now) while (n >= (ssize_t)sizeof(uint32_t)) { uint32_t l2len = ntohl_unaligned(p); + struct iov_tail data; if (l2len < sizeof(struct ethhdr) || l2len > L2_MAX_LEN_PASST) { err("Bad frame size from guest, resetting connection"); @@ -1184,7 +1192,8 @@ static void tap_passt_input(struct ctx *c, const struct timespec *now) p += sizeof(uint32_t); n -= sizeof(uint32_t); - tap_add_packet(c, l2len, p, now); + data = IOV_TAIL_FROM_BUF(p, l2len, 0); + tap_add_packet(c, &data, now); p += l2len; n -= l2len; @@ -1228,6 +1237,8 @@ static void tap_pasta_input(struct ctx *c, const struct timespec *now) for (n = 0; n <= (ssize_t)(sizeof(pkt_buf) - L2_MAX_LEN_PASTA); n += len) { + struct iov_tail data; + len = read(c->fd_tap, pkt_buf + n, L2_MAX_LEN_PASTA); if (len == 0) { @@ -1249,7 +1260,8 @@ static void tap_pasta_input(struct ctx *c, const struct timespec *now) len > (ssize_t)L2_MAX_LEN_PASTA) continue; - tap_add_packet(c, len, pkt_buf + n, now); + data = IOV_TAIL_FROM_BUF(pkt_buf + n, len, 0); + tap_add_packet(c, &data, now); } tap_handler(c, now); @@ -119,7 +119,6 @@ void tap_sock_update_pool(void *base, size_t size); void tap_backend_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, +void tap_add_packet(struct ctx *c, struct iov_tail *data, const struct timespec *now); - #endif /* TAP_H */ diff --git a/vu_common.c b/vu_common.c index 5e6fd4a..b77b214 100644 --- a/vu_common.c +++ b/vu_common.c @@ -163,7 +163,6 @@ static void vu_handle_tx(struct vu_dev *vdev, int index, struct vu_virtq_element elem[VIRTQUEUE_MAX_SIZE]; struct iovec out_sg[VIRTQUEUE_MAX_SIZE]; struct vu_virtq *vq = &vdev->vq[index]; - int hdrlen = sizeof(struct virtio_net_hdr_mrg_rxbuf); int out_sg_count; int count; @@ -176,6 +175,7 @@ static void vu_handle_tx(struct vu_dev *vdev, int index, while (count < VIRTQUEUE_MAX_SIZE && out_sg_count + VU_MAX_TX_BUFFER_NB <= VIRTQUEUE_MAX_SIZE) { int ret; + struct iov_tail data; elem[count].out_num = VU_MAX_TX_BUFFER_NB; elem[count].out_sg = &out_sg[out_sg_count]; @@ -191,26 +191,10 @@ static void vu_handle_tx(struct vu_dev *vdev, int index, warn("virtio-net transmit queue contains no out buffers"); break; } - if (elem[count].out_num == 1) { - tap_add_packet(vdev->context, - elem[count].out_sg[0].iov_len - hdrlen, - (char *)elem[count].out_sg[0].iov_base + - hdrlen, now); - } else { - /* vnet header can be in a separate iovec */ - if (elem[count].out_num != 2) { - debug("virtio-net transmit queue contains more than one buffer ([%d]: %u)", - count, elem[count].out_num); - } else if (elem[count].out_sg[0].iov_len != (size_t)hdrlen) { - debug("virtio-net transmit queue entry not aligned on hdrlen ([%d]: %d != %zu)", - count, hdrlen, elem[count].out_sg[0].iov_len); - } else { - tap_add_packet(vdev->context, - elem[count].out_sg[1].iov_len, - (char *)elem[count].out_sg[1].iov_base, - now); - } - } + + data = IOV_TAIL(elem[count].out_sg, elem[count].out_num, 0); + if (IOV_DROP_HEADER(&data, struct virtio_net_hdr_mrg_rxbuf)) + tap_add_packet(vdev->context, &data, now); count++; } |