From nobody Thu Sep 17 00:09:10 2026 X-Original-To: dev-commits-src-all@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 4hlbhq3Q3wz6sXCM for ; Thu, 17 Sep 2026 00:09:15 +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 4hlbhq2mgVz4LwP for ; Thu, 17 Sep 2026 00:09:15 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1789603755; 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=IBDbantddbM7ts64Ls2djefebC1ScloXB/v5kVuoWNJjpIMbPL7BelEXq4fQ5Chr2H42Xv qMCBFLtj3e6UweTeuFiyS4/jPG/cmYy+SnroPWbmt0v8fj/bw6f7FrEL+G4NYzzfvwvkim sLXWeGbn1FQ7tZ3Vy9sS62E06nXBHSlADqF5FWzObEqX+I1H7Uvfd4lbCn2DqjCbtpduYD R9EL2d9qtoypdE3/0IiRdrEPpgOcqzZe+Kkvo8epkWwcsQv3vXcu/FCsXyQAsYN34oMk6E pzIRMcqTFA3/yQzQVYRLB/6nX/9bVklMXU6r7cur5JIf/QN76UqS3qyo3AI6dQ== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1789603755; b=q5Dg0XhX+APwSVt2YyqYtajZhrhUHXxKoef+Wl6qJ7uSfYGvhAC4d1xnoeX5c/F5fG3FjS BHf25WiAt2lLN8niH1LU64n53ZQFgES37eDWBUL32yyz6Ch4CIMcYXo1xr3w0z1nrG+Bs8 StK51O2SH/5AJsMHQFz2FNeHN998Eo+bJitc3uYwpv1YXBaDO892nGJzZRqJDY6MPh5eMd XLrvp516AqGhFz8ta9lqxd353enRymZqcn4Pw81e6wFxqJPSYzxzapAZNbFKZ03kidrhGH mSvA4ZS0KIlVlyG/Om3EBr9IUOMJUg6/HdZpaya2Md6ZR8ccneC5X6/TK8m8oQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1789603755; 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=lgdPS1SlfZ1Bf9U7+DVxYoINqIpn1NoJwr6whT3+RsAeUlRcKS3GfWITOkZ66ciqwBt5Dc bt4WP4wJu3hHjLtIu0cEzfOOHBrdJB+BFs7xRTU7LZ6MH+33FvnV0xTbw8pKNQwokdd5ua CBwcWauz/dOQ8cYEp5xVEoZYo/cgtvB8jJtR5nD78ms9XtT4Q11qP8r3JvlLpjdKtypBI+ kYW2oD5cs8/HDv7F7qxcxaHwEiHR3S6Hkw/USf1Fm9gXTUpl+sbSURmCQfSUGgwd0SNdHQ v9AfXKjdF2GRlS1i8Qw+RtOdZHT6ij2tEJ0WIiO//1/RP91EqOzvIw9BZnkwVA== 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 4hlbhq1qQVz17tX for ; Thu, 17 Sep 2026 00:09:15 +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 all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@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.