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
