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
