From nobody Thu Sep 17 00:09:10 2026 X-Original-To: dev-commits-src-main@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 4hlbhk31Pnz6sXR3 for ; Thu, 17 Sep 2026 00:09:10 +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 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hlbhk2JdRz4Lhv for ; Thu, 17 Sep 2026 00:09:10 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1789603750; 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=M1qZbq1CWqxEC2vqPVrnQ0GQ1jmxxqGT1F/zRLX4c88=; b=hLyYbl9NpGLEBuedgksqt5UntxT8+RKrp1u3YsvsKglOyLriFKELP7x8uFgP14apyoYcrV lZ4ckQMjjWKbTZLWYA/0dlhpUHYemjA2tjnodS8Tndn3fHuTge0s6xIXBU1XNQaKteNoza zFvCWwewaAl7FMah1JHv0zUtWOX9+nxS2gL2rRtdhYNBeU4PA07BlpCk7xW+6g2nyy34rE ekNa7PSM2t+yhgtDB5fhPz9T/VBuFnelBwam+bTj7NT4kw1GLloFIEQrTRNv8LK8zdKk42 j1gs/aQPoRpl6EviSKSC2ZFZSdzQy/ushSlKrRdoz35Zdc3lDGq/+5mrcBplbw== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1789603750; b=KHrrlHmU38lorfhXFHVNhO4fnQLuODpgA7MekGU81YmpKRLpjJPGkcyomRt0eMRYJhx2pA /tfZZujtuDNl7jlAJuwwJ1yA/X8Ny+B4/GMXGUCnIIPyH2K1uq5kfXxXnXkY5MgRgTicMN F4f5wxHOwz43T0ERzqWo3VROwWzt22w1ZD031pVoEDuZqV31HByMZ8VyToPnYOYBdCSkhF JBAnnic/YB3sGGgzhG8yh4fD6J4TIdI2TVn+QLT1Em3dECqHEaGoKqWl71t1tpIo99CNgX 2OBqXEL38rEvL18VuIytySiSi79wkYaNhSJZQ2uhJeY9UExrUMI3ZcK9EXm7Ww== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1789603750; 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=M1qZbq1CWqxEC2vqPVrnQ0GQ1jmxxqGT1F/zRLX4c88=; b=mJ1Gq4FIs30eK6XokjTf0lbAY6fQaU1DaBpOTOqmPV/DyThqiiQGsQX5a067T5/noOPFmP BT8Jil0NUvYLW42FzIVjDxJTk7P88etH53H22ZNvh2O14GCkv7Bj1Ny7BwWzr2m9a/ZDm3 cgZ8HznilOa4RAi9h5o7iq8d+lI4z9cqnr/ZnsvKqxAEE2aOo0q4DR/orhVhX8o61ztwtM vaJE1x0+QfJZ3pmgWn+qKxVJ3ETv/+f58srUtGS00WhZBEfUtVmiLkl9N5yhybSTVPV6Yh B7rJdwjBCyJWYpqa6tDuylKZloPqNjOY9rAUg7hyD6GPQ2e3OrxtmKZskaPfPA== 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 4hlbhk17cnz17wk for ; Thu, 17 Sep 2026 00:09:10 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 25877 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 17 Sep 2026 00:09:10 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kevin Bowling Subject: git: 83b308875d25 - main - hn: Relay VLAN membership to transparent VFs List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: 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/main X-Git-Reftype: branch X-Git-Commit: 83b308875d254a894e04dbe91d5fbdb637eafdf2 Auto-Submitted: auto-generated Date: Thu, 17 Sep 2026 00:09:10 +0000 Message-Id: <6aab2fa6.25877.721ad2aa@gitrepo.freebsd.org> The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=83b308875d254a894e04dbe91d5fbdb637eafdf2 commit 83b308875d254a894e04dbe91d5fbdb637eafdf2 Author: Kevin Bowling AuthorDate: 2026-09-16 17:13:40 +0000 Commit: Kevin Bowling CommitDate: 2026-09-17 00:07:32 +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. MFC after: 2 weeks Sponsored by: BBOX.io --- 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 72bef946b0d5..73ad8b978c7e 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 #include @@ -1771,6 +1772,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); } @@ -1855,6 +1857,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) { @@ -1867,6 +1923,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; @@ -1939,7 +1996,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 != @@ -1952,13 +2009,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) { /* @@ -2033,6 +2091,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; @@ -2073,6 +2132,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. * @@ -2094,6 +2154,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) { @@ -2540,6 +2602,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) { @@ -2606,6 +2675,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) @@ -2623,8 +2696,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.