From nobody Thu Oct 29 06:10:02 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 4jFYjk3yHHz6xs1N for ; Thu, 29 Oct 2026 06:10:02 +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 4jFYjk2rc3z54lc for ; Thu, 29 Oct 2026 06:10:02 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1793254202; 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=8KQVyx+lnE4xmxWPiu6M3Ga9dFh00ZS5Q/RbsHHO/mo=; b=EwRrYEI649d7AGMiNNRGWQek/tHhl5+0SU1fKO5Kra4pTXdjkmiS2K6Ka8nRzyU4z/iKOp v3MZjcKYW6uybilPYAvcchMAFtMZ4608QFpxOWl1iyE22rF/NSbXqX+uOVDEYzPO8W5bUX LbR42R526Jlc++7yRrhBcTL97o3uEM8arNF2Nfj4P58zwHcc9zwzRPzPckb+ipIlEtKYYg wV4qzW4LBQDdStvlOhGTXghkG/cW0uPvXYuUs/E0g4/Vc4JQiQsk5HYRPtj02k5hOB5dYD iMjFh6oOw0lGyJvYYuaz784GbRW+iusM9c3/OA76w2ecFLG3ROC3Yr4U7vhfqg== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1793254202; b=v42TkFVspMoAlrtKubBpo7FS8eUV/lH6CcdjHS6VC39Lw7egWcslqVnM6V0knLJq8OMqEl QHHJXdZ6ihEQWsmATWUiF6RKc97RTyEacgyK/tc+aoct/x6l0zc+hNvZf9hg7v09QWyAtF C42Hfaiug82KSGj2oUDgjj/Y+v3NZz0woX2XluqYkw7oBIE2DORf3GA58auKQemOVxRZ9l pX2A44Vp1sp8htHsGi28aQ9q+Bum/FqlvDDnMlAPELei1EG5qtB+elSP1gQvObwG4ZlsPE KDetKleHENnwfB8TSFA8zLHVDDVBdQIufgv9oZ9rtZGoQK3RLdHtI97B6nnNEA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1793254202; 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=8KQVyx+lnE4xmxWPiu6M3Ga9dFh00ZS5Q/RbsHHO/mo=; b=GaRvclRM0kgq3PGhPH3RlTxKaE1BFpgQZdSw3oFaQPV6dsCb35x/QeO3kuUgmGR9vO979C 95iIkfSKyp7acdIoKPiEqCW63E2+XZ4eyOpFfc6w3guVkjs+zMFKldhn2sZ7vAbhLsBGEv UOGe2NEhYYr/JnOzt/xxyjPg6shb4yzhzO0EH+k+nU2mxqn72JyLcJiNPxcN4NknoyJdY+ kd77F++pqDO11NBsVGsK5GpVdX0JQ+oWMWA8hhEWKTYHQEUTZFChTEgLwe7LRBgZidwYdK 04mueixVkBjkLHcJHBrpQYAibMnkaSh8zarK+Y0Zn4F3Ul3d1a6kqfym4WjJIw== 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 4jFYjk2TNkzR8M for ; Thu, 29 Oct 2026 06:10:02 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3ae67 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 29 Oct 2026 06:10:02 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kevin Bowling Subject: git: 1f3df2e03875 - stable/15 - hn: Forward capability changes 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: 1f3df2e0387570f74dfec5bde1913721280d4181 Auto-Submitted: auto-generated Date: Thu, 29 Oct 2026 06:10:02 +0000 Message-Id: <6ae2e33a.3ae67.4a680aa2@gitrepo.freebsd.org> The branch stable/15 has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=1f3df2e0387570f74dfec5bde1913721280d4181 commit 1f3df2e0387570f74dfec5bde1913721280d4181 Author: Kevin Bowling AuthorDate: 2026-09-16 17:13:40 +0000 Commit: Kevin Bowling CommitDate: 2026-10-29 06:09:53 +0000 hn: Forward capability changes to transparent VFs The transparent VF capability handler ignored the requested change and only copied the VF's enabled capabilities. Forward SIOCSIFCAP to the VF and return its result. Preserve VF capabilities which hn does not expose. Limit advertised capabilities to those supported by the transparent packet path and VLAN relay. Do not inherit VF services such as send tags or the extended capability ioctl when hn has no corresponding methods. At handoff, adopt the VF's enabled offloads without reconfiguring it. Mark the datapath as switching while the VF applies a capability change, since its ioctl may reinitialize the device. If the association is still ready and unchanged afterwards, synchronize hn with the actual VF state even on error and restrict checksum assistance to the forwarded offloads. Republish link state suppressed during the transition when the VF is still ready. Refresh VLAN child capabilities after adoption and when restoring the synthetic path. Run the VF capability ioctl without hn_lock to avoid reversing the VLAN configuration lock order. Hold an ifnet reference, serialize capability changes and VF initialization, and make detach wait with hn_lock released. Revalidate the VF association before publishing the result. Defer VLAN-child capability notifications to the existing VF taskqueue so they also run without hn_lock, and drain that work before ifnet teardown. Sponsored by: BBOX.io (cherry picked from commit 31896115b5574944718cc4f5260efe47b622b55b) --- sys/dev/hyperv/netvsc/if_hn.c | 132 +++++++++++++++++++++++++++++++++------ sys/dev/hyperv/netvsc/if_hnvar.h | 2 + 2 files changed, 114 insertions(+), 20 deletions(-) diff --git a/sys/dev/hyperv/netvsc/if_hn.c b/sys/dev/hyperv/netvsc/if_hn.c index 93fd02b17f90..e4ea85b44bc9 100644 --- a/sys/dev/hyperv/netvsc/if_hn.c +++ b/sys/dev/hyperv/netvsc/if_hn.c @@ -186,6 +186,12 @@ do { \ #define HN_CSUM_IP6_HWASSIST(sc) \ ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK) +/* Packet offloads can follow the VF; services requiring hn methods cannot. */ +#define HN_XPNT_VF_CAPS (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 | \ + IFCAP_TSO | IFCAP_LRO | IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | \ + IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWFILTER | \ + IFCAP_JUMBO_MTU | IFCAP_LINKSTATE | IFCAP_HWSTATS | IFCAP_MEXTPG) + #define HN_PKTSIZE_MIN(align) \ roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \ HN_RNDIS_PKT_LEN, (align)) @@ -301,6 +307,8 @@ static void hn_xpnt_vf_input(if_t, struct mbuf *); static int hn_xpnt_vf_iocsetflags(struct hn_softc *); static int hn_xpnt_vf_iocsetcaps(struct hn_softc *, struct ifreq *); +static void hn_xpnt_vf_synccaps(struct hn_softc *); +static void hn_xpnt_vf_vlancap_taskfunc(void *, int); static void hn_xpnt_vf_saveifflags(struct hn_softc *); static bool hn_xpnt_vf_isready(struct hn_softc *); static bool hn_xpnt_vf_caninit(struct hn_softc *); @@ -1308,22 +1316,93 @@ hn_ifaddr_event(void *arg, if_t ifp) hn_rxvf_change(arg, ifp); } -static int -hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr __unused) +static void +hn_xpnt_vf_synccaps(struct hn_softc *sc) { if_t ifp, vf_ifp; + int caps; HN_LOCK_ASSERT(sc); ifp = sc->hn_ifp; vf_ifp = sc->hn_vf_ifp; + caps = if_getcapabilities(ifp); + + /* Reflect the actual VF state even if an ioctl failed partway through. */ + if_setcapenable(ifp, if_getcapenable(vf_ifp) & caps); + if_sethwassist(ifp, if_gethwassist(vf_ifp) & + (HN_CSUM_IP_MASK | HN_CSUM_IP6_MASK | CSUM_TSO)); + /* The worker refreshes VLAN children without holding hn_lock. */ + if (!sc->hn_detaching) + taskqueue_enqueue(sc->hn_vf_taskq, &sc->hn_vf_vlancap); +} + +static void +hn_xpnt_vf_vlancap_taskfunc(void *xsc, int pending __unused) +{ + struct hn_softc *sc = xsc; + + /* VLAN configuration takes vlan_sx before entering hn ioctls. */ + sx_assert(&sc->hn_lock, SA_UNLOCKED); + if_vlancap(sc->hn_ifp); +} + +static int +hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr) +{ + if_t vf_ifp; + u_int assoc; + int caps, error; + + HN_LOCK_ASSERT(sc); + if (sc->hn_vf_caps_busy) + return (EBUSY); + if (sc->hn_detaching || sc->hn_vf_detaching || + !hn_xpnt_vf_isready(sc)) + return (ENXIO); + + vf_ifp = sc->hn_vf_ifp; + if_ref(vf_ifp); + assoc = sc->hn_vf_active_assoc; + caps = if_getcapabilities(sc->hn_ifp); + /* Leave capabilities which hn does not expose unchanged on the VF. */ + ifr->ifr_reqcap = (ifr->ifr_reqcap & caps) | + (if_getcapenable(vf_ifp) & ~caps); + sc->hn_vf_caps_busy = true; + rm_wlock(&sc->hn_vf_lock); + sc->hn_xvf_flags |= HN_XVFFLAG_SWITCHING; + rm_wunlock(&sc->hn_vf_lock); /* - * Just sync up with VF's enabled capabilities. + * The VF ioctl may acquire vlan_sx, whose callers enter hn ioctls. + * Detach waits for hn_vf_caps_busy with hn_lock released; new VF + * initialization and capability changes cannot overlap this ioctl. */ - if_setcapenable(ifp, if_getcapenable(vf_ifp)); - if_sethwassist(ifp, if_gethwassist(vf_ifp)); + HN_UNLOCK(sc); + error = ifhwioctl(SIOCSIFCAP, vf_ifp, (caddr_t)ifr, curthread); + HN_LOCK(sc); - return (0); + if (!sc->hn_detaching && !sc->hn_vf_detaching && + sc->hn_vf_ifp == vf_ifp && hn_xpnt_vf_isready(sc) && + sc->hn_vf_active_assoc == assoc) { + hn_xpnt_vf_synccaps(sc); + rm_wlock(&sc->hn_vf_lock); + sc->hn_xvf_flags &= ~HN_XVFFLAG_SWITCHING; + /* A link event during the ioctl was suppressed by SWITCHING. */ + if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) && + hn_xpnt_vf_isready(sc)) + if_link_state_change(sc->hn_ifp, + if_getlinkstate(vf_ifp)); + rm_wunlock(&sc->hn_vf_lock); + } else if (error == 0) { + error = sc->hn_detaching || sc->hn_vf_detaching ? ENXIO : EAGAIN; + } + if_rele(vf_ifp); + sc->hn_vf_caps_busy = false; + wakeup(&sc->hn_vf_caps_busy); + /* Retry association work deferred while the ioctl was in flight. */ + if (!sc->hn_detaching && !sc->hn_vf_detaching) + taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init, 0); + return (error); } static int @@ -1711,13 +1790,11 @@ hn_xpnt_vf_setready(struct hn_softc *sc) sc->hn_saved_hwassist = if_gethwassist(ifp); /* - * Intersect supported/enabled capabilities. - * - * NOTE: - * if_hwassist is not changed here. + * Expose only capabilities supported by the transparent packet path. + * VF services such as send tags and the extended capability ioctl + * require methods which hn does not implement. */ - if_setcapabilitiesbit(ifp, 0, if_getcapabilities(vf_ifp)); - if_setcapenablebit(ifp, 0, if_getcapabilities(ifp)); + if_setcapabilities(ifp, if_getcapabilities(vf_ifp) & HN_XPNT_VF_CAPS); /* * Fix TSO settings. @@ -1730,12 +1807,9 @@ hn_xpnt_vf_setready(struct hn_softc *sc) if_sethwtsomaxsegsize(ifp, if_gethwtsomaxsegsize(vf_ifp)); /* - * Change VF's enabled capabilities. + * Adopt the VF's enabled capabilities without changing its settings. */ - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, if_name(vf_ifp), sizeof(ifr.ifr_name)); - ifr.ifr_reqcap = if_getcapenable(ifp); - hn_xpnt_vf_iocsetcaps(sc, &ifr); + hn_xpnt_vf_synccaps(sc); if (if_getmtu(ifp) != ETHERMTU) { int error; @@ -1786,6 +1860,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 && + !sc->hn_vf_caps_busy && (atomic_load_acq_int(&sc->hn_vf_assoc) & HN_VF_ASSOC_ALLOCATED) && (int)(ticks - sc->hn_vf_rdytick) >= 0); } @@ -1804,6 +1879,8 @@ hn_xpnt_vf_restore(struct hn_softc *sc) if_sethwtsomaxsegsize(ifp, sc->hn_saved_tsosegsz); if_setcapenable(ifp, sc->hn_saved_capenable); if_sethwassist(ifp, sc->hn_saved_hwassist); + if (!sc->hn_detaching) + taskqueue_enqueue(sc->hn_vf_taskq, &sc->hn_vf_vlancap); sc->hn_vf_ready = false; } @@ -1862,8 +1939,10 @@ hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf) /* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */ rm_wlock(&sc->hn_vf_lock); sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED; - if (clear_vf) + if (clear_vf) { + sc->hn_xvf_flags &= ~HN_XVFFLAG_SWITCHING; sc->hn_vf_ifp = NULL; + } rm_wunlock(&sc->hn_vf_lock); for (i = 0; i < sc->hn_rx_ring_cnt; ++i) @@ -1965,7 +2044,7 @@ hn_xpnt_vf_init(struct hn_softc *sc) * Some VF drivers initialize hwassist only when brought up. Refresh * the offload state before allowing transmit through the VF. */ - hn_xpnt_vf_iocsetcaps(sc, NULL); + hn_xpnt_vf_synccaps(sc); /* * NOTE: @@ -2009,7 +2088,8 @@ 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 || sc->hn_vf_detaching) + if (sc->hn_vf_ifp == NULL || sc->hn_vf_detaching || + sc->hn_vf_caps_busy) goto done; if (!hn_xpnt_vf) { if ((sc->hn_flags & HN_FLAG_RXVF) && sc->hn_vf_active_assoc != @@ -2146,6 +2226,9 @@ hn_ifnet_detevent(void *xsc, if_t ifp) if (hn_xpnt_vf) { sc->hn_vf_detaching = true; + while (sc->hn_vf_caps_busy) + sx_sleep(&sc->hn_vf_caps_busy, &sc->hn_lock, 0, + "hnvfcap", 0); /* * Make sure that the delayed initialization is not running. * @@ -2329,6 +2412,7 @@ hn_attach(device_t dev) device_get_nameunit(dev)); TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0, hn_xpnt_vf_init_taskfunc, sc); + TASK_INIT(&sc->hn_vf_vlancap, 0, hn_xpnt_vf_vlancap_taskfunc, sc); /* * Allocate ifnet and setup its name earlier, so that if_printf @@ -2687,12 +2771,15 @@ hn_detach(device_t dev) HN_LOCK(sc); sc->hn_detaching = true; + while (sc->hn_vf_caps_busy) + sx_sleep(&sc->hn_vf_caps_busy, &sc->hn_lock, 0, "hnvfcap", 0); 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); + taskqueue_drain(sc->hn_vf_taskq, &sc->hn_vf_vlancap); if (sc->hn_ifaddr_evthand != NULL) EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand); @@ -4089,6 +4176,11 @@ hn_ioctl(if_t ifp, u_long cmd, caddr_t data) case SIOCSIFCAP: HN_LOCK(sc); + if (sc->hn_detaching || sc->hn_vf_caps_busy) { + error = sc->hn_vf_caps_busy ? EBUSY : ENXIO; + HN_UNLOCK(sc); + break; + } if (hn_xpnt_vf_isready(sc)) { ifr_vf = *ifr; diff --git a/sys/dev/hyperv/netvsc/if_hnvar.h b/sys/dev/hyperv/netvsc/if_hnvar.h index 4be884d5522c..7fde5c8fe30e 100644 --- a/sys/dev/hyperv/netvsc/if_hnvar.h +++ b/sys/dev/hyperv/netvsc/if_hnvar.h @@ -268,6 +268,7 @@ struct hn_softc { /* Applied VLANs and VF lifetime use hn_lock. */ u_int hn_vf_vlans[HN_VLAN_WORDS]; bool hn_vf_detaching; + bool hn_vf_caps_busy; /* unlocked capability ioctl */ /* * Transparent VF delayed initialization. @@ -279,6 +280,7 @@ struct hn_softc { u_int hn_vf_active_assoc; /* confirmed VF generation */ struct taskqueue *hn_vf_taskq; struct timeout_task hn_vf_init; + struct task hn_vf_vlancap; /* * Saved information for VF under transparent mode.