From: Jason Wang <[email protected]>

filter-redirector uses a vm change state handler to enable netdev read_poll()
when enable_when_stopped=true and the VM stops, so that host traffic can be
still drained into the netfilter chain while vCPUs are not running.

However, qemu_add_vm_change_state_handler() does not invoke the callback for
the current VM state at registration time. If a redirector is created after
the VM is already stopped (or if enable_when_stopped is toggled on while
stopped), read_poll() may remain disabled and packets will not be drained.

Add a helper that checks the current runstate and proactively enables
read_poll() when enable_when_stopped is set and the VM is already stopped.
Call it from redirector setup and from the enable_when_stopped property setter.

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

diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index eb703b7dee..c1b9dabacd 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -314,6 +314,27 @@ static void filter_redirector_vm_state_change(void 
*opaque, bool running,
     }
 }
 
+static void filter_redirector_maybe_enable_read_poll(NetFilterState *nf)
+{
+    MirrorState *s = FILTER_REDIRECTOR(nf);
+    NetClientState *nc = nf->netdev;
+
+    if (!nc || !nc->info || !nc->info->read_poll) {
+        return;
+    }
+
+    /*
+     * When a redirector is created while the VM is already stopped,
+     * qemu_add_vm_change_state_handler() will not immediately invoke the
+     * callback for the current state. If enable_when_stopped is set, we
+     * must proactively enable read_poll so that tap packets can be drained
+     * into the netfilter chain (e.g. redirector+buffer) during stop.
+     */
+    if (!runstate_is_running() && s->enable_when_stopped) {
+        nc->info->read_poll(nc, true);
+    }
+}
+
 static void filter_redirector_setup(NetFilterState *nf, Error **errp)
 {
     MirrorState *s = FILTER_REDIRECTOR(nf);
@@ -366,6 +387,8 @@ static void filter_redirector_setup(NetFilterState *nf, 
Error **errp)
 
     s->vmsentry = qemu_add_vm_change_state_handler(
         filter_redirector_vm_state_change, nf);
+
+    filter_redirector_maybe_enable_read_poll(nf);
 }
 
 static void filter_redirector_status_changed(NetFilterState *nf, Error **errp)
@@ -484,8 +507,17 @@ static void 
filter_redirector_set_enable_when_stopped(Object *obj,
                                                       Error **errp)
 {
     MirrorState *s = FILTER_REDIRECTOR(obj);
+    NetFilterState *nf = NETFILTER(obj);
 
     s->enable_when_stopped = value;
+
+    /*
+     * If toggled on while the VM is already stopped, ensure we enable 
read_poll
+     * immediately (vm_state_change callback only runs on transitions).
+     */
+    if (value) {
+        filter_redirector_maybe_enable_read_poll(nf);
+    }
 }
 
 static void filter_mirror_class_init(ObjectClass *oc, const void *data)
-- 
2.52.0


Reply via email to