Packets captured from AF_PACKET now either go to the chardev outdev or
into the filter chain, and both paths update the new netdev statistics.
Use the same routing from redirector_rs_finalize() so replay traffic and
normal receive handling share one dispatch policy.

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

diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index e57fbc94b8..1ff58e1d27 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -305,6 +305,81 @@ static void redirector_chr_event(void *opaque, 
QEMUChrEvent event)
     }
 }
 
+static void filter_redirector_recv_from_chardev(NetFilterState *nf,
+                                                        const uint8_t *buf,
+                                                        int len)
+{
+    MirrorState *s = FILTER_REDIRECTOR(nf);
+    bool inject_netdev = filter_redirector_use_inject_netdev(nf);
+    ssize_t ret;
+    struct iovec iov = {
+        .iov_base = (void *)buf,
+        .iov_len = len,
+    };
+
+    if (len <= 0) {
+        return;
+    }
+
+    /* chardev indev */
+    s->indev_packets++;
+    s->indev_bytes += len;
+
+    if (inject_netdev) {
+        ret = filter_redirector_send_netdev_iov(s, &iov, 1);
+        if (ret < 0) {
+            error_report("filter redirector send failed(%s)", strerror(-ret));
+        }
+        return;
+    }
+
+    if (s->outdev) {
+        ret = filter_redirector_send_chardev_iov(s, &iov, 1);
+        if (ret < 0) {
+            error_report("filter redirector send failed(%s)", strerror(-ret));
+        } else if (ret > 0) {
+            s->outdev_packets++;
+            s->outdev_bytes += ret;
+        }
+        return;
+    }
+
+    redirector_to_filter(nf, buf, len);
+}
+
+static bool filter_redirector_recv_from_netdev(NetFilterState *nf,
+                                                          const uint8_t *buf,
+                                                          int len)
+{
+    MirrorState *s = FILTER_REDIRECTOR(nf);
+    ssize_t ret;
+    struct iovec iov = {
+        .iov_base = (void *)buf,
+        .iov_len = len,
+    };
+
+    if (len <= 0) {
+        return false;
+    }
+
+    if (s->outdev) {
+        ret = filter_redirector_send_chardev_iov(s, &iov, 1);
+        if (ret > 0) {
+            s->outdev_packets++;
+            s->outdev_bytes += ret;
+        }
+    } else {
+        redirector_to_filter(nf, buf, len);
+        return true;
+    }
+
+    if (ret < 0) {
+        error_report("filter redirector send failed(%s)", strerror(-ret));
+        return false;
+    }
+    return true;
+}
+
 static void filter_redirector_netdev_read(void *opaque)
 {
     NetFilterState *nf = opaque;
@@ -329,7 +404,9 @@ static void filter_redirector_netdev_read(void *opaque)
             continue;
         }
 
-        redirector_to_filter(nf, s->in_netbuf, len);
+        s->netdev_rx_packets++;
+        s->netdev_rx_bytes += len;
+        filter_redirector_recv_from_netdev(nf, s->in_netbuf, len);
     }
 
     if (len < 0 && errno != EAGAIN && errno != EWOULDBLOCK &&
@@ -369,21 +446,34 @@ static ssize_t 
filter_redirector_receive_iov(NetFilterState *nf,
                                              NetPacketSent *sent_cb)
 {
     MirrorState *s = FILTER_REDIRECTOR(nf);
+    bool capture_netdev = filter_redirector_use_capture_netdev(nf);
+    bool inject_netdev = filter_redirector_use_inject_netdev(nf);
     int ret;
 
-    if (qemu_chr_fe_backend_connected(&s->chr_out)) {
-        ret = filter_send(s, iov, iovcnt);
+    if (s->indev || inject_netdev) {
+        return 0;
+    }
+
+    if (capture_netdev || s->outdev) {
+        if (capture_netdev) {
+            return 0;
+        }
+
+        ret = filter_redirector_send_chardev_iov(s, iov, iovcnt);
         if (ret < 0) {
             error_report("filter redirector send failed(%s)", strerror(-ret));
         } else if (ret > 0) {
-            /* Update outdev statistics on successful send */
             s->outdev_packets++;
             s->outdev_bytes += ret;
         }
-        return iov_size(iov, iovcnt);
-    } else {
+        /*
+         * Without an active AF_PACKET capture socket, outdev mirroring is a
+         * sideband copy only and must not consume the guest-bound packet.
+         */
         return 0;
     }
+
+    return 0;
 }
 
 static void filter_mirror_cleanup(NetFilterState *nf)
@@ -444,6 +534,11 @@ static void redirector_rs_finalize(SocketReadState *rs)
     MirrorState *s = container_of(rs, MirrorState, rs);
     NetFilterState *nf = NETFILTER(s);
 
+    if (s->outdev || filter_redirector_use_inject_netdev(nf)) {
+        filter_redirector_recv_from_chardev(nf, rs->buf, rs->packet_len);
+        return;
+    }
+
     /* Update indev statistics */
     s->indev_packets++;
     s->indev_bytes += rs->packet_len;
-- 
2.52.0


Reply via email to