Packets injected from the redirector chardev are raw Ethernet frames without a
vnet_hdr prefix. Mark them as RAW so downstream filters (e.g. dump) do not skip
vnet_hdr_len bytes, and strip the vnet_hdr prefix only when vnet_hdr_support is
enabled and a valid prefix is present.

Signed-off-by: Cindy Lu <[email protected]>
---
 net/filter-mirror.c | 30 +++++++++++++++++++++++++-----
 1 file changed, 25 insertions(+), 5 deletions(-)

diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index c1b9dabacd..de32028246 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -146,6 +146,7 @@ static int filter_send(MirrorState *s,
 }
 
 static void redirector_to_filter(NetFilterState *nf,
+                                 unsigned flags,
                                  const uint8_t *buf,
                                  int len)
 {
@@ -156,13 +157,13 @@ static void redirector_to_filter(NetFilterState *nf,
 
     if (nf->direction == NET_FILTER_DIRECTION_ALL ||
         nf->direction == NET_FILTER_DIRECTION_TX) {
-        qemu_netfilter_pass_to_next(nf->netdev, 0, &iov, 1, nf);
+        qemu_netfilter_pass_to_next(nf->netdev, flags, &iov, 1, nf);
     }
 
     if (nf->direction == NET_FILTER_DIRECTION_ALL ||
         nf->direction == NET_FILTER_DIRECTION_RX) {
-        qemu_netfilter_pass_to_next(nf->netdev->peer, 0, &iov, 1, nf);
-     }
+        qemu_netfilter_pass_to_next(nf->netdev->peer, flags, &iov, 1, nf);
+    }
 }
 
 static int redirector_chr_can_read(void *opaque)
@@ -294,12 +295,31 @@ static void redirector_rs_finalize(SocketReadState *rs)
 {
     MirrorState *s = container_of(rs, MirrorState, rs);
     NetFilterState *nf = NETFILTER(s);
+    const uint8_t *buf = rs->buf;
+    int len = rs->packet_len;
 
     /* Update indev statistics */
     s->indev_packets++;
-    s->indev_bytes += rs->packet_len;
+    s->indev_bytes += len;
+
+    /*
+     * If the sender enables vnet_hdr_support, received data includes a
+     * vnet_hdr prefix. Skip vnet_hdr_len bytes and pass the Ethernet frame.
+     */
+    if (s->vnet_hdr) {
+        if (rs->vnet_hdr_len <= 0 || rs->vnet_hdr_len >= len) {
+            return;
+        }
+        buf += rs->vnet_hdr_len;
+        len -= rs->vnet_hdr_len;
+    }
 
-    redirector_to_filter(nf, rs->buf, rs->packet_len);
+    /*
+     * Packets injected from the chardev are raw Ethernet frames without a
+     * vnet_hdr prefix. Mark them as RAW so downstream filters (e.g. dump)
+     * won't try to skip a vnet_hdr_len.
+     */
+    redirector_to_filter(nf, QEMU_NET_PACKET_FLAG_RAW, buf, len);
 }
 
 static void filter_redirector_vm_state_change(void *opaque, bool running,
-- 
2.52.0


Reply via email to