git: f6d7a063ae11 - stable/15 - hn: Invoke the owned VF's transmit queue flush callback

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Thu, 29 Oct 2026 05:02:06 UTC
The branch stable/15 has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=f6d7a063ae11bce38a142965a94bb149381d503f

commit f6d7a063ae11bce38a142965a94bb149381d503f
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-09-15 00:26:14 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-10-29 05:01:55 +0000

    hn: Invoke the owned VF's transmit queue flush callback
    
    The generic if_qflush() only clears if_snd.  Calling it directly for a
    transparent VF bypasses the driver's callback and its private software
    transmit queues.  Add if_getqflushfn(), matching the existing callback
    accessors, and invoke the registered callback while hn_vf_lock protects
    the VF pointer.
    
    Flush an attached VF whenever transparent mode owns it, not only while
    the VF datapath is enabled.  Disabling transmit during handoff does not
    discard packets already queued to the VF.  This also covers the inactive
    interval after fallback.  Non-transparent VFs remain independently owned
    and are not flushed by hn.  Synthetic queue flushing is unchanged.
    
    Sponsored by:   BBOX.io
    
    (cherry picked from commit 8e816fc2e98c8c0bf0b6fef3bd5f52bc03c843ce)
---
 sys/dev/hyperv/netvsc/if_hn.c | 5 +++--
 sys/net/if.c                  | 6 ++++++
 sys/net/if_var.h              | 1 +
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/sys/dev/hyperv/netvsc/if_hn.c b/sys/dev/hyperv/netvsc/if_hn.c
index fd49a8cb100d..e86df282fd56 100644
--- a/sys/dev/hyperv/netvsc/if_hn.c
+++ b/sys/dev/hyperv/netvsc/if_hn.c
@@ -6253,8 +6253,9 @@ hn_xmit_qflush(if_t ifp)
 	if_qflush(ifp);
 
 	rm_rlock(&sc->hn_vf_lock, &pt);
-	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
-		if_qflush(sc->hn_vf_ifp);
+	/* Transparent mode owns the VF's queues even while switching paths. */
+	if (hn_xpnt_vf && sc->hn_vf_ifp != NULL)
+		if_getqflushfn(sc->hn_vf_ifp)(sc->hn_vf_ifp);
 	rm_runlock(&sc->hn_vf_lock, &pt);
 }
 
diff --git a/sys/net/if.c b/sys/net/if.c
index 6267afafe361..ec8385bb93a5 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -5064,6 +5064,12 @@ if_setqflushfn(if_t ifp, if_qflush_fn_t flush_fn)
 	ifp->if_qflush = flush_fn;
 }
 
+if_qflush_fn_t
+if_getqflushfn(if_t ifp)
+{
+	return (ifp->if_qflush);
+}
+
 void
 if_setsndtagallocfn(if_t ifp, if_snd_tag_alloc_t alloc_fn)
 {
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 3d0f0624aed2..60d9378dbb76 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -717,6 +717,7 @@ if_start_fn_t if_getstartfn(if_t ifp);
 void if_settransmitfn(if_t ifp, if_transmit_fn_t);
 if_transmit_fn_t if_gettransmitfn(if_t ifp);
 void if_setqflushfn(if_t ifp, if_qflush_fn_t);
+if_qflush_fn_t if_getqflushfn(if_t ifp);
 void if_setgetcounterfn(if_t ifp, if_get_counter_t);
 void if_setsndtagallocfn(if_t ifp, if_snd_tag_alloc_t);
 void if_setdebugnet_methods(if_t, struct debugnet_methods *);