From nobody Thu Oct 29 06:09:47 2026 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4jFYjS0kFGz6xrsY for ; Thu, 29 Oct 2026 06:09:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 4jFYjR6t8rz54hC for ; Thu, 29 Oct 2026 06:09:47 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1793254188; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=hhcGmEIqfxDD0aAafcQiy3OLHlT00eB61Z9DhF/L/NY=; b=A4VBlmAGX5AGOt/JuBXYZJ/m53ibmI2mbwL2Y/GD+keX2FOiqeT+aKF6JtLkihwD82lDoF erTWL7FTwf4pvY/4qFq1g1VEqDMgQdqBXdL8FHScTTfcTFCW9WHeyOf7MDSf3Bc6gWmU4A b/rxjv5n2xUc1O7hV9RhJteEsg0r15CfdEYUjb8y/D2BNAfVmeHiXWO2XaTQqgrgFt3pqZ lyTDJSapP3mI2z+KS5NDeu4c9RTGE5BUXLxyOx4LfYDYKEJtjsqoiQFOT0KKql5dSPhgBF tbMSSevJWKEdf45Y0nwrR09YLzM9xkMD5ZZxAMqGVi0wd+iTcI0M9A9qfT3JuA== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1793254188; b=aeHBC8QX26itFCCDkUxAxAYfe//TRsITTo+dwsHtrBjtNEkC42DvJqjM6fbeztW/VKgAVA lz53/U5oItI627gic3ZIhBCufFMMA4HuvMRhwKaRfiES37SCas1lBARUk5C8w+ct/u1XaB 2RA0B6oFtCS59XRU5QLnnIdrk0X16aGYfya4gGX8VlG/5ADEqtl8KWyfVmtUyWBRZuLreG FhezNk35OuJdKBBOkbO1WvTZTJtAqPBv3CTFOsMrP4IJhijdp3FyQy0sNoidYg4NkJhCSa d+AoctLmcmHTOcQw5zexlD/s6dmcdwEdSapn8B9QeBXVopn7PdzFpVq+ldVBpQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1793254188; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=hhcGmEIqfxDD0aAafcQiy3OLHlT00eB61Z9DhF/L/NY=; b=oUgmjqFUdwpsuSjcG3p72dLuH5hMZtM13S/qjDUlDGx3CflUUySQqktYN9e25btt7cmriO VTEK4d6M1BjVhMBXri9pXhiaS88Yc0o8EjhTrhnPuU+GAZaeMEGbDeMr5egUXfyDleikuV piYdR8WqExFaAcM2KsDz9EXm8pc3nFzLCobTJJ2RfMoImsVcV2nQgnQEyytswXnO9fzRF8 UUisMfV7IA6m2IH1pMiWFORXSEJgMvjOcJ5ml25HewuEVOdY2Uq/8bJexBNZ1C6cihvTVM BRxdQVnqYjDAjOvd27vbgXT/Hbt2Wcxt5eSzqfcL1wuhzjPq5AFWQCtOA2k+lQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4jFYjR6WZNzR9m for ; Thu, 29 Oct 2026 06:09:47 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3a599 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 29 Oct 2026 06:09:47 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kevin Bowling Subject: git: 46cec8479c2f - stable/15 - hn: Relay VLAN membership to transparent VFs List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org List-Id: Commits to the stable branches of the FreeBSD src repository List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kbowling X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: 46cec8479c2f21e374233225c6b845ccf42c68a9 Auto-Submitted: auto-generated Date: Thu, 29 Oct 2026 06:09:47 +0000 Message-Id: <6ae2e32b.3a599.540a27a5@gitrepo.freebsd.org> The branch stable/15 has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=46cec8479c2f21e374233225c6b845ccf42c68a9 commit 46cec8479c2f21e374233225c6b845ccf42c68a9 Author: Kevin Bowling AuthorDate: 2026-09-16 17:13:40 +0000 Commit: Kevin Bowling CommitDate: 2026-10-29 06:09:38 +0000 hn: Relay VLAN membership to transparent VFs VLANs configured on the synthetic interface do not otherwise reach the accelerating VF's VLAN callbacks. Those callbacks can be needed for hardware filter membership or for interpreting stripped VLAN tags, even though no vlan interface is attached directly to the VF. Subscribe to VLAN events only in transparent mode and schedule the existing VF task. Snapshot the synthetic interface's VLAN topology under network epoch, then leave epoch before invoking the VF callbacks, which may sleep. Do not acquire hn_lock or configure the VF from a VLAN event handler; the worker applies membership outside the VLAN configuration lock. Keep an applied-VID bitmap under hn_lock and relay only changes. Replay VLANs configured before VF arrival, reconcile changes while acceleration is active, and preserve membership across temporary datapath switches. This relays guest intent; it does not configure host access VLAN policy or overcome PF restrictions on tagged traffic. Block initialization while either interface is detaching. Deregister VLAN handlers before draining work, remove registrations when hn leaves a live VF, and discard the applied bitmap when the VF itself departs. Sponsored by: BBOX.io (cherry picked from commit 83b308875d254a894e04dbe91d5fbdb637eafdf2) --- sys/dev/hyperv/netvsc/if_hn.c | 85 ++++++++++++++++++++++++++++++++++++++-- sys/dev/hyperv/netvsc/if_hnvar.h | 8 ++++ 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/sys/dev/hyperv/netvsc/if_hn.c b/sys/dev/hyperv/netvsc/if_hn.c index e86df282fd56..93fd02b17f90 100644 --- a/sys/dev/hyperv/netvsc/if_hn.c +++ b/sys/dev/hyperv/netvsc/if_hn.c @@ -97,6 +97,7 @@ #include #include #include +#include #include #ifdef RSS #include @@ -1784,6 +1785,7 @@ hn_xpnt_vf_caninit(struct hn_softc *sc) HN_LOCK_ASSERT(sc); return (hn_xpnt_vf && sc->hn_vf_ifp != NULL && + !sc->hn_detaching && !sc->hn_vf_detaching && (atomic_load_acq_int(&sc->hn_vf_assoc) & HN_VF_ASSOC_ALLOCATED) && (int)(ticks - sc->hn_vf_rdytick) >= 0); } @@ -1868,6 +1870,60 @@ hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf) sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF; } +/* + * Do not configure the VF from the VLAN event callback. The worker reads + * and applies the current VLAN topology outside the VLAN configuration + * lock, including VLANs configured before the VF arrives. Only + * transparent mode subscribes. + */ +static void +hn_vlan_event(void *xsc, if_t ifp, uint16_t vid __unused) +{ + struct hn_softc *sc = xsc; + + if (ifp != sc->hn_ifp) + return; + taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init, 0); +} + +/* Apply guest VLAN intent, not the host's administrative access VLAN. */ +static void +hn_xpnt_vf_sync_vlans(struct hn_softc *sc, bool remove) +{ + struct epoch_tracker et; + u_int desired[HN_VLAN_WORDS] = { 0 }, changed, mask; + unsigned int i, bit; + uint16_t vid; + + HN_LOCK_ASSERT(sc); + KASSERT(sc->hn_vf_ifp != NULL, ("VLAN sync without a VF")); + if (!remove) { + NET_EPOCH_ENTER(et); + for (vid = 1; vid < EVL_VLID_MASK; vid++) { + if (VLAN_DEVAT(sc->hn_ifp, vid) != NULL) + desired[vid / 32] |= 1U << (vid % 32); + } + NET_EPOCH_EXIT(et); + } + /* VF callbacks may sleep; never invoke them inside network epoch. */ + for (i = 0; i < HN_VLAN_WORDS; i++) { + changed = desired[i] ^ sc->hn_vf_vlans[i]; + while (changed != 0) { + bit = ffs(changed) - 1; + mask = 1U << bit; + vid = i * 32 + bit; + if ((desired[i] & mask) != 0) + EVENTHANDLER_INVOKE(vlan_config, sc->hn_vf_ifp, + vid); + else + EVENTHANDLER_INVOKE(vlan_unconfig, sc->hn_vf_ifp, + vid); + changed &= ~mask; + } + sc->hn_vf_vlans[i] = desired[i]; + } +} + static void hn_xpnt_vf_init(struct hn_softc *sc) { @@ -1880,6 +1936,7 @@ hn_xpnt_vf_init(struct hn_softc *sc) ("%s: transparent VF was enabled", if_name(sc->hn_ifp))); if (!hn_xpnt_vf_caninit(sc)) return; + hn_xpnt_vf_sync_vlans(sc, false); assoc = atomic_load_acq_int(&sc->hn_vf_assoc); rm_wlock(&sc->hn_vf_lock); sc->hn_xvf_flags |= HN_XVFFLAG_SWITCHING; @@ -1952,7 +2009,7 @@ hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused) if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) goto done; - if (sc->hn_vf_ifp == NULL) + if (sc->hn_vf_ifp == NULL || sc->hn_vf_detaching) goto done; if (!hn_xpnt_vf) { if ((sc->hn_flags & HN_FLAG_RXVF) && sc->hn_vf_active_assoc != @@ -1965,13 +2022,14 @@ hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused) if (sc->hn_vf_active_assoc != 0 && sc->hn_vf_active_assoc != atomic_load_acq_int(&sc->hn_vf_assoc)) hn_xpnt_vf_deactivate(sc); - if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) - goto done; if ((int)(ticks - sc->hn_vf_rdytick) < 0) { taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init, sc->hn_vf_rdytick - ticks); goto done; } + hn_xpnt_vf_sync_vlans(sc, false); + if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) + goto done; if (if_getdrvflags(sc->hn_ifp) & IFF_DRV_RUNNING) { /* @@ -2046,6 +2104,7 @@ hn_ifnet_attevent(void *xsc, if_t ifp) ("%s: transparent VF was enabled", if_name(sc->hn_ifp))); sc->hn_vf_ifp = ifp; rm_wunlock(&sc->hn_vf_lock); + sc->hn_vf_detaching = false; if (hn_xpnt_vf) { int wait_ticks; @@ -2086,6 +2145,7 @@ hn_ifnet_detevent(void *xsc, if_t ifp) goto done; if (hn_xpnt_vf) { + sc->hn_vf_detaching = true; /* * Make sure that the delayed initialization is not running. * @@ -2107,6 +2167,8 @@ hn_ifnet_detevent(void *xsc, if_t ifp) hn_xpnt_vf_deactivate(sc); else hn_xpnt_vf_restore(sc); + /* A departing VF discards its registration state itself. */ + bzero(sc->hn_vf_vlans, sizeof(sc->hn_vf_vlans)); if_setinputfn(ifp, sc->hn_vf_input); sc->hn_vf_input = NULL; } else if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { @@ -2553,6 +2615,13 @@ hn_attach(device_t dev) if_sethwtsomaxsegsize(ifp, PAGE_SIZE); } + /* Schedule reconciliation when the synthetic interface's VLANs change. */ + if (hn_xpnt_vf) { + sc->hn_vlan_atthand = EVENTHANDLER_REGISTER(vlan_config, + hn_vlan_event, sc, EVENTHANDLER_PRI_ANY); + sc->hn_vlan_dethand = EVENTHANDLER_REGISTER(vlan_unconfig, + hn_vlan_event, sc, EVENTHANDLER_PRI_ANY); + } ether_ifattach(ifp, eaddr); if ((if_getcapabilities(ifp) & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) { @@ -2619,6 +2688,10 @@ hn_detach(device_t dev) HN_LOCK(sc); sc->hn_detaching = true; HN_UNLOCK(sc); + if (sc->hn_vlan_atthand != NULL) + EVENTHANDLER_DEREGISTER(vlan_config, sc->hn_vlan_atthand); + if (sc->hn_vlan_dethand != NULL) + EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->hn_vlan_dethand); taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init); if (sc->hn_ifaddr_evthand != NULL) @@ -2636,8 +2709,12 @@ hn_detach(device_t dev) if (sc->hn_ifnet_lnkhand != NULL) EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand); + HN_LOCK(sc); vf_ifp = sc->hn_vf_ifp; - __compiler_membar(); + /* hn is leaving; remove its registrations from the live VF. */ + if (vf_ifp != NULL && hn_xpnt_vf) + hn_xpnt_vf_sync_vlans(sc, true); + HN_UNLOCK(sc); if (vf_ifp != NULL) hn_ifnet_detevent(sc, vf_ifp); diff --git a/sys/dev/hyperv/netvsc/if_hnvar.h b/sys/dev/hyperv/netvsc/if_hnvar.h index fb545b8b2bc8..4be884d5522c 100644 --- a/sys/dev/hyperv/netvsc/if_hnvar.h +++ b/sys/dev/hyperv/netvsc/if_hnvar.h @@ -46,6 +46,8 @@ #define HN_GPACNT_MAX 32 +#define HN_VLAN_WORDS 128 + struct hn_txdesc; #ifndef HN_USE_TXDESC_BUFRING SLIST_HEAD(hn_txdesc_list, hn_txdesc); @@ -260,6 +262,12 @@ struct hn_softc { eventhandler_tag hn_ifnet_atthand; eventhandler_tag hn_ifnet_dethand; eventhandler_tag hn_ifnet_lnkhand; + eventhandler_tag hn_vlan_atthand; + eventhandler_tag hn_vlan_dethand; + + /* Applied VLANs and VF lifetime use hn_lock. */ + u_int hn_vf_vlans[HN_VLAN_WORDS]; + bool hn_vf_detaching; /* * Transparent VF delayed initialization.