From nobody Mon Aug 24 00:53:40 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 4hSsq85c3Mz6q2X5 for ; Mon, 24 Aug 2026 00:53:40 +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 4hSsq81whxz3vcF for ; Mon, 24 Aug 2026 00:53:40 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1787532820; 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=lCWmNiQXBMvTwJzw9K9Lt+IlB9EfAEUujmMvR95gLew=; b=jGkocRyAlr1NZQv5B8+bloNIRZ7Ymqu1VIVNg4Joq0kmMIE3oTkmG1sc25sDG+YFykryu0 N7epFEEjp8r8TDBtD/IuF5BUvPn/o1iEuP6ZFa/3FnBKqOTt34acLHlWVZ98L04rj/KIIy 078TogAcUrRMvFtZZAUycwzTKhmvvlaezQw701PLuavcarvp03BBXfb5D95hp/6yEiWrm9 X76x/qOjGC5SeyaUddo9bVE8qPPU8Q/czpLD7WCNGeX/T+hhbrFZHCGnaA9cfWEzCPbuBH n17bh2quR3w6MXQKcsgpmt2PSBCvbOXB2q5ojCApxUVev2ocdvpO2TRaIiaTsA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1787532820; a=rsa-sha256; cv=none; b=TMDgw3pCgeZt7C3JXAiWmlCUCSgh4z3ryvVb8os6/bJaifV0ul7YpWI6Pc61Zs6u3zhvV2 23+NirY/1O/9nYOXe5nxDZYPvQ8kEalFLwJES8qWTO6V5MmbxbCoNm0KEso8QmamvpQuLG T1xKGpbfxDncZaIwDvKAYc+3OOXv/WcbsFMsXtMxMa8IBuAqgEI5DGC7/estytMMrD/ElZ uNnCjRa5kIiOfUCNPU0UqdD6n48sn67etQCGzn/NuqObxSH4lf3OMPLA0aACk6mAUZV16L 3fNDwwAqKC3jftz3RIGv0E9yb4kU9aZDBQoKQ2CDAUSeX+lSKZVBLmygjWmTTg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1787532820; 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=lCWmNiQXBMvTwJzw9K9Lt+IlB9EfAEUujmMvR95gLew=; b=OC9G1Kd2cCkDyFX1JWk92IraOo7r8Dzxhv7hHgiOAizgrsCT4JUwy+nD3IFJQqjGLu1BX3 14e5lGJKBbryIeUdctnl96/Y3bcmsq3eucLtRBIJZQzG5WzdlFHTXlDoo85idX1WC2KMt4 iRzFrCcORFGJJz6Gn29G81iwZfWy/I2MWgGBO+b0KX53pzkOGpVK2FKoQ8JA+P3KYaQpJP 5aze13r1gLKeeoN6REim6cyWe4/IWKi7tA/McQBgYJWJmzkkQwvmf6YhC9H4K7n4+MaToI KieeGNvv2lCQalKAexOnBJvMp1Ps5kCvtphz3MBOR99iIoxsiLbHDOWcbhR/yQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hSsq80kyqzj8N for ; Mon, 24 Aug 2026 00:53:40 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 32a40 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 24 Aug 2026 00:53:40 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kevin Bowling Subject: git: 0f3586ea6dde - stable/15 - ixl: Track and recover MDD-blocked 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/stable/15 X-Git-Reftype: branch X-Git-Commit: 0f3586ea6ddedddccb699a8ed793764c1c71609e Auto-Submitted: auto-generated Date: Mon, 24 Aug 2026 00:53:40 +0000 Message-Id: <6a8b9614.32a40.65557713@gitrepo.freebsd.org> The branch stable/15 has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=0f3586ea6ddedddccb699a8ed793764c1c71609e commit 0f3586ea6ddedddccb699a8ed793764c1c71609e Author: Kevin Bowling AuthorDate: 2026-08-10 03:46:24 +0000 Commit: Kevin Bowling CommitDate: 2026-08-24 00:49:05 +0000 ixl: Track and recover MDD-blocked VFs The hardware identifies each VF with TX and RX malicious-driver status latches, but the driver combined all events into one counter and reported only the last VF found. It also did not record that hardware had blocked the VF, leaving the condition invisible to management tools. Consume every PF and VF latch, keep per-direction VF counters, rate-limit per-VF diagnostics, and report the blocked and traffic-enabled state via the VF status interface. Clear the software block only after a successful VF or PF reset reconstructs its resources. Match Linux i40e policy by leaving a detected VF blocked by default. Add an opt-in hw.ixl.mdd_auto_reset_vf tunable that notifies and resets the VF for installations that prefer availability. DPDK provides the register clear and per-VF attribution precedent; Linux provides the recovery policy. (cherry picked from commit 93f1065920d806400ace6b60b025faf91926bdaa) --- share/man/man4/ixl.4 | 6 +++ sys/dev/ixl/if_ixl.c | 7 +++ sys/dev/ixl/ixl_pf.h | 9 +++- sys/dev/ixl/ixl_pf_iov.c | 30 +++++++++++ sys/dev/ixl/ixl_pf_main.c | 132 ++++++++++++++++++++++------------------------ 5 files changed, 115 insertions(+), 69 deletions(-) diff --git a/share/man/man4/ixl.4 b/share/man/man4/ixl.4 index ef52b9f8b456..37d8c0cf5db8 100644 --- a/share/man/man4/ixl.4 +++ b/share/man/man4/ixl.4 @@ -213,6 +213,12 @@ use a value written to memory by the hardware instead of scanning the descriptor ring for completed descriptors. Enabled by default; disable to mimic the TX behavior found in .Xr ix 4 . +.It Va hw.ixl.mdd_auto_reset_vf +Automatically reset a VF after malicious-driver detection blocks it. +This is disabled by default so a non-cooperative VF remains unable to issue +traffic until it performs an FLR or the SR-IOV configuration is recreated. +Enabling this tunable favors availability but allows a persistently faulty or +hostile VF to resume after each reset. .El .Sh SYSCTL PROCEDURES .Bl -tag -width indent diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c index bc929753944b..9caba0d7c89b 100644 --- a/sys/dev/ixl/if_ixl.c +++ b/sys/dev/ixl/if_ixl.c @@ -251,6 +251,12 @@ SYSCTL_INT(_hw_ixl, OID_AUTO, enable_vf_loopback, CTLFLAG_RDTUN, &ixl_enable_vf_loopback, 0, IXL_SYSCTL_HELP_VF_LOOPBACK); +static int ixl_mdd_auto_reset_vf; +TUNABLE_INT("hw.ixl.mdd_auto_reset_vf", &ixl_mdd_auto_reset_vf); +SYSCTL_INT(_hw_ixl, OID_AUTO, mdd_auto_reset_vf, CTLFLAG_RDTUN, + &ixl_mdd_auto_reset_vf, 0, + "Automatically reset VFs blocked by malicious-driver detection"); + /* * Different method for processing TX descriptor * completion. @@ -1938,6 +1944,7 @@ ixl_save_pf_tunables(struct ixl_pf *pf) pf->hw.debug_mask = ixl_shared_debug_mask; pf->vsi.enable_head_writeback = !!(ixl_enable_head_writeback); pf->enable_vf_loopback = !!(ixl_enable_vf_loopback); + pf->mdd_auto_reset_vf = !!(ixl_mdd_auto_reset_vf); #if 0 pf->dynamic_rx_itr = ixl_dynamic_rx_itr; pf->dynamic_tx_itr = ixl_dynamic_tx_itr; diff --git a/sys/dev/ixl/ixl_pf.h b/sys/dev/ixl/ixl_pf.h index adf87bef48eb..e79fcac3c4c8 100644 --- a/sys/dev/ixl/ixl_pf.h +++ b/sys/dev/ixl/ixl_pf.h @@ -103,7 +103,12 @@ enum ixl_state { struct ixl_vf { struct ixl_vsi vsi; u32 vf_flags; - u32 num_mdd_events; + u64 mdd_tx_events; + u64 mdd_rx_events; + struct timeval last_mdd_log; + bool mdd_blocked; + bool mdd_event_pending; + bool mdd_reset_pending; u8 mac[ETHER_ADDR_LEN]; u8 mac_filters[IXL_VF_MAX_MAC_FILTERS][ETHER_ADDR_LEN]; @@ -151,6 +156,7 @@ struct ixl_pf { int tx_itr; int rx_itr; int enable_vf_loopback; + int mdd_auto_reset_vf; bool link_up; int advertised_speed; @@ -386,6 +392,7 @@ int ixl_pf_reset(struct ixl_pf *); #ifdef PCI_IOV void ixl_notify_vfs_reset(struct ixl_pf *); int ixl_rebuild_vfs_after_reset(struct ixl_pf *); +int ixl_reset_vf_on_mdd(struct ixl_pf *, uint16_t); #endif void ixl_set_queue_rx_itr(struct ixl_rx_queue *); diff --git a/sys/dev/ixl/ixl_pf_iov.c b/sys/dev/ixl/ixl_pf_iov.c index 67b43276e6b3..765f4d17682a 100644 --- a/sys/dev/ixl/ixl_pf_iov.c +++ b/sys/dev/ixl/ixl_pf_iov.c @@ -497,6 +497,9 @@ ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf) wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), VIRTCHNL_VFR_VFACTIVE); ixl_flush(hw); + vf->mdd_blocked = false; + vf->mdd_event_pending = false; + vf->mdd_reset_pending = false; return (0); } @@ -1766,6 +1769,10 @@ ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event) (vf->vf_flags & VF_FLAG_ENABLED) ? " " : " disabled ", vf_num, msg_size); + /* Only a reset outside the virtchnl dispatcher may unblock the VF. */ + if (vf->mdd_blocked) + return; + /* Perform basic checks on the msg */ err = virtchnl_vc_validate_vf_msg(&vf->version, opcode, msg, msg_size); if (err) { @@ -2036,6 +2043,26 @@ ixl_notify_vfs_reset(struct ixl_pf *pf) } } +int +ixl_reset_vf_on_mdd(struct ixl_pf *pf, uint16_t vfnum) +{ + struct virtchnl_pf_event event; + struct ixl_vf *vf; + + if (vfnum >= pf->num_vfs) + return (EINVAL); + vf = &pf->vfs[vfnum]; + if (!(vf->vf_flags & VF_FLAG_ENABLED)) + return (ENXIO); + + bzero(&event, sizeof(event)); + event.event = VIRTCHNL_EVENT_RESET_IMPENDING; + event.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM; + ixl_send_vf_msg(pf, vf, VIRTCHNL_OP_EVENT, I40E_SUCCESS, + &event, sizeof(event)); + return (ixl_reset_vf(pf, vf)); +} + int ixl_rebuild_vfs_after_reset(struct ixl_pf *pf) { @@ -2065,6 +2092,9 @@ ixl_rebuild_vfs_after_reset(struct ixl_pf *pf) bit_nclear(vf->vsi.vlans_map, 0, IXL_VLANS_MAP_LEN - 1); vf->num_mac_filters = 0; + vf->mdd_blocked = false; + vf->mdd_event_pending = false; + vf->mdd_reset_pending = false; } error = ixl_setup_iov_switch(pf); diff --git a/sys/dev/ixl/ixl_pf_main.c b/sys/dev/ixl/ixl_pf_main.c index b1bd1a3bc258..a09321850958 100644 --- a/sys/dev/ixl/ixl_pf_main.c +++ b/sys/dev/ixl/ixl_pf_main.c @@ -1854,12 +1854,8 @@ ixl_handle_tx_mdd_event(struct ixl_pf *pf) struct i40e_hw *hw = &pf->hw; device_t dev = pf->dev; struct ixl_vf *vf; - bool mdd_detected = false; - bool pf_mdd_detected = false; - bool vf_mdd_detected = false; u16 vf_num, queue; u8 pf_num, event; - u8 pf_mdet_num, vp_mdet_num; u32 reg; /* find what triggered the MDD event */ @@ -1873,18 +1869,20 @@ ixl_handle_tx_mdd_event(struct ixl_pf *pf) I40E_GL_MDET_TX_EVENT_SHIFT; queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >> I40E_GL_MDET_TX_QUEUE_SHIFT; + if (queue >= hw->func_caps.base_queue) + queue -= hw->func_caps.base_queue; + device_printf(dev, + "last TX malicious-driver cause %#x on queue %u, " + "PF %#x, VF %#x\n", event, queue, pf_num, vf_num); wr32(hw, I40E_GL_MDET_TX, 0xffffffff); - mdd_detected = true; } - if (!mdd_detected) - return; - reg = rd32(hw, I40E_PF_MDET_TX); if (reg & I40E_PF_MDET_TX_VALID_MASK) { wr32(hw, I40E_PF_MDET_TX, 0xFFFF); - pf_mdet_num = hw->pf_id; - pf_mdd_detected = true; + device_printf(dev, + "TX malicious-driver issue detected on PF-%u\n", + hw->pf_id); } /* Check if MDD was caused by a VF */ @@ -1893,32 +1891,16 @@ ixl_handle_tx_mdd_event(struct ixl_pf *pf) reg = rd32(hw, I40E_VP_MDET_TX(i)); if (reg & I40E_VP_MDET_TX_VALID_MASK) { wr32(hw, I40E_VP_MDET_TX(i), 0xFFFF); - vp_mdet_num = i; - vf->num_mdd_events++; - vf_mdd_detected = true; + if (!(vf->vf_flags & VF_FLAG_ENABLED)) + continue; + vf->mdd_tx_events++; + vf->mdd_event_pending = true; + if (!vf->mdd_blocked) { + vf->mdd_blocked = true; + vf->mdd_reset_pending = true; + } } } - - /* Print out an error message */ - if (vf_mdd_detected && pf_mdd_detected) - device_printf(dev, - "Malicious Driver Detection event %d" - " on TX queue %d, pf number %d (PF-%d), vf number %d (VF-%d)\n", - event, queue, pf_num, pf_mdet_num, vf_num, vp_mdet_num); - else if (vf_mdd_detected && !pf_mdd_detected) - device_printf(dev, - "Malicious Driver Detection event %d" - " on TX queue %d, pf number %d, vf number %d (VF-%d)\n", - event, queue, pf_num, vf_num, vp_mdet_num); - else if (!vf_mdd_detected && pf_mdd_detected) - device_printf(dev, - "Malicious Driver Detection event %d" - " on TX queue %d, pf number %d (PF-%d)\n", - event, queue, pf_num, pf_mdet_num); - /* Theoretically shouldn't happen */ - else - device_printf(dev, - "TX Malicious Driver Detection event (unknown)\n"); } static void @@ -1927,12 +1909,8 @@ ixl_handle_rx_mdd_event(struct ixl_pf *pf) struct i40e_hw *hw = &pf->hw; device_t dev = pf->dev; struct ixl_vf *vf; - bool mdd_detected = false; - bool pf_mdd_detected = false; - bool vf_mdd_detected = false; u16 queue; u8 pf_num, event; - u8 pf_mdet_num, vp_mdet_num; u32 reg; /* @@ -1947,18 +1925,20 @@ ixl_handle_rx_mdd_event(struct ixl_pf *pf) I40E_GL_MDET_RX_EVENT_SHIFT; queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >> I40E_GL_MDET_RX_QUEUE_SHIFT; + if (queue >= hw->func_caps.base_queue) + queue -= hw->func_caps.base_queue; + device_printf(dev, + "last RX malicious-driver cause %#x on queue %u, " + "function %#x\n", event, queue, pf_num); wr32(hw, I40E_GL_MDET_RX, 0xffffffff); - mdd_detected = true; } - if (!mdd_detected) - return; - reg = rd32(hw, I40E_PF_MDET_RX); if (reg & I40E_PF_MDET_RX_VALID_MASK) { wr32(hw, I40E_PF_MDET_RX, 0xFFFF); - pf_mdet_num = hw->pf_id; - pf_mdd_detected = true; + device_printf(dev, + "RX malicious-driver issue detected on PF-%u\n", + hw->pf_id); } /* Check if MDD was caused by a VF */ @@ -1967,32 +1947,16 @@ ixl_handle_rx_mdd_event(struct ixl_pf *pf) reg = rd32(hw, I40E_VP_MDET_RX(i)); if (reg & I40E_VP_MDET_RX_VALID_MASK) { wr32(hw, I40E_VP_MDET_RX(i), 0xFFFF); - vp_mdet_num = i; - vf->num_mdd_events++; - vf_mdd_detected = true; + if (!(vf->vf_flags & VF_FLAG_ENABLED)) + continue; + vf->mdd_rx_events++; + vf->mdd_event_pending = true; + if (!vf->mdd_blocked) { + vf->mdd_blocked = true; + vf->mdd_reset_pending = true; + } } } - - /* Print out an error message */ - if (vf_mdd_detected && pf_mdd_detected) - device_printf(dev, - "Malicious Driver Detection event %d" - " on RX queue %d, pf number %d (PF-%d), (VF-%d)\n", - event, queue, pf_num, pf_mdet_num, vp_mdet_num); - else if (vf_mdd_detected && !pf_mdd_detected) - device_printf(dev, - "Malicious Driver Detection event %d" - " on RX queue %d, pf number %d, (VF-%d)\n", - event, queue, pf_num, vp_mdet_num); - else if (!vf_mdd_detected && pf_mdd_detected) - device_printf(dev, - "Malicious Driver Detection event %d" - " on RX queue %d, pf number %d (PF-%d)\n", - event, queue, pf_num, pf_mdet_num); - /* Theoretically shouldn't happen */ - else - device_printf(dev, - "RX Malicious Driver Detection event (unknown)\n"); } /** @@ -2005,6 +1969,10 @@ void ixl_handle_mdd_event(struct ixl_pf *pf) { struct i40e_hw *hw = &pf->hw; + struct ixl_vf *vf; + static const struct timeval log_interval = { 2, 0 }; + bool reset; + int i; u32 reg; /* @@ -2013,6 +1981,34 @@ ixl_handle_mdd_event(struct ixl_pf *pf) */ ixl_handle_tx_mdd_event(pf); ixl_handle_rx_mdd_event(pf); + for (i = 0; i < pf->num_vfs; i++) { + vf = &pf->vfs[i]; + if (!vf->mdd_event_pending) + continue; + vf->mdd_event_pending = false; + reset = vf->mdd_reset_pending; + vf->mdd_reset_pending = false; + if (ratecheck(&vf->last_mdd_log, &log_interval)) { + device_printf(pf->dev, + "malicious-driver event from VF-%d " + "(tx %ju, rx %ju); %s\n", i, + (uintmax_t)vf->mdd_tx_events, + (uintmax_t)vf->mdd_rx_events, + pf->mdd_auto_reset_vf && reset ? + "resetting VF" : "VF remains blocked"); + } +#ifdef PCI_IOV + if (pf->mdd_auto_reset_vf && reset) { + int error; + + error = ixl_reset_vf_on_mdd(pf, i); + if (error != 0) + device_printf(pf->dev, + "failed to reset MDD-blocked VF-%d: %d\n", + i, error); + } +#endif + } ixl_clear_state(&pf->state, IXL_STATE_MDD_PENDING);