From nobody Fri Sep 18 00:33:16 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 4hmDB469m7z6sKvk for ; Fri, 18 Sep 2026 00:33:16 +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 4hmDB45JKqz4n84 for ; Fri, 18 Sep 2026 00:33:16 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1789691596; 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=Wuud9DpR8PSfimTttoDaYvMoTsB9NiIXBeF+dmrpyn8=; b=aclwRwV4gGvLRcqiTXlJZTKwZoMjKCmXx8DHkkSZkY4Olr7hvCWQ5ikUNjnH873aXxCecJ OLA+dqmmtV2yzVyip0NX8Dm/RIBsLh4oKWMfXtksC5hKf14WmuSf/EsfAMdOOanVnfKCND /PYlXlEzRJuJxkk/w336wYVtjusEkRwoZD0Nu6sxtffx9JPvWGUGnbHs6DO6MoQ1NaJ+eG RCH/IZmRyhbKPDFthw8CHVbDGkNwy6SEQalmiILdbz640/FTUM9SXMaNmXbxlRIYGZfH8c HuA2W6Yx2Q68nl3dRZOAcSSh8R1vJO8xWbs4nsLhk5paoNf2ZKrF7EyZsxMuQQ== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1789691596; b=xtrBZc+Pq0nrh5nXSrpWeVUcRbeVdf1cDxy/SoOqxlzKj8/xdkVUJ6mgsRxXxjOf5loXLh 1kEsunYggxFHyRqkx7VBiD/vapBnuk5ed5vFGIfrrexK+WiaIdERY5u/yq+bbVlZBZkuGN 9iAgcRfLEyuB3N4icWTguJ+VS+v0Y8EPQvTICG+eRu9+OGlGFRPvTWpgVfuZbBRF6TgDe5 MPNO89Vo3qgvKNaLplaHV4mM6dWFY28Ge5eZMNjfM+r+ZXNhHi/jy0d/GGn17PjpEOF/1q AovHy0zt7yPfFVLBFyu232EEjKo3R/oNrK79gyvMlXsCuMUupAyjyZJHU5WcVA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1789691596; 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=Wuud9DpR8PSfimTttoDaYvMoTsB9NiIXBeF+dmrpyn8=; b=njoP+3EKuc+LMLtRxsHw1tMwS8w9oBtP8Ct5pON0R9JEMFYkFUgDDSQJy7i2fiLsJItibO KQ28gf9Q9NzDXSfdjTx2hkrw83NnXzrSFYAgXVGmQ+/Sk6J6Na48Hvx/hO4zqAyURKuonm 32wYc7EwF+JxJ8fKacm/FSgrAej1g0lrWJgu2G9+pSmojNtNn+8h1xRF+YN8jJXcr6A6cw EQ3iX5qUM36cfYPtVjxFQ85CUbI/RsKIBj+2p0na0+FFna3vmJ6w5WZaYklLebz6SEe5NE IRPRlq7hkq+WyaIm+R1SL/MkJ0S+siXRzvEqBUC1Z3Jl0i+wkYOttPAwjxk3Aw== 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 4hmDB44LwjzwRC for ; Fri, 18 Sep 2026 00:33:16 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 31deb by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Fri, 18 Sep 2026 00:33:16 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kevin Bowling Subject: git: 3faea48e1179 - main - ice: Make VF MAC filter requests idempotent 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: 3faea48e117939ae41f92c8738784d8e38a78612 Auto-Submitted: auto-generated Date: Fri, 18 Sep 2026 00:33:16 +0000 Message-Id: <6aac86cc.31deb.9d0bfda@gitrepo.freebsd.org> The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=3faea48e117939ae41f92c8738784d8e38a78612 commit 3faea48e117939ae41f92c8738784d8e38a78612 Author: Kevin Bowling AuthorDate: 2026-08-19 05:52:43 +0000 Commit: Kevin Bowling CommitDate: 2026-09-18 00:32:52 +0000 ice: Make VF MAC filter requests idempotent VF drivers replay their address filters after reset and may retry a request whose reply was lost. The PF tracked only a count and incremented it after an idempotent hardware add, so duplicate replays eventually exhausted the quota. It then rejected an entire address batch, including the administrator-assigned address. Track exact non-primary MAC filter membership within each VF quota. Validate a complete batch before changing hardware, charge only unique absent addresses, and update ownership after each successful operation. Preserve an administrator-assigned address when the VF is not permitted to change it. Validated on an E810-XXV with a host-attached iavf VF. The configured filter quota was filled, then the complete set was replayed across VFR and PF reset without a duplicate warning or ADD_ETH_ADDR NACK. Deleting an absent address was a no-op. With allow-set-mac disabled, the guest could not remove its administrator-assigned filter, while multicast filter additions continued to succeed. MFC after: 2 weeks Sponsored by: BBOX.io Differential Revision: https://reviews.freebsd.org/D59026 --- share/man/man4/ice.4 | 19 +++++-- sys/dev/ice/ice_iov.c | 144 +++++++++++++++++++++++++++++++++++++------------- sys/dev/ice/ice_iov.h | 5 ++ 3 files changed, 126 insertions(+), 42 deletions(-) diff --git a/share/man/man4/ice.4 b/share/man/man4/ice.4 index a4bb498edf55..0174f09af4e9 100644 --- a/share/man/man4/ice.4 +++ b/share/man/man4/ice.4 @@ -1143,11 +1143,20 @@ resource; this is used to prevent a VF from starving other VFs or the PF of filter resources. By default, this is set to 16. .It max-mac-filters Pq uint16_t -Specify maximum number of MAC address filters that the VF can use. -Each allowed MAC address requires a hardware filter which are a finite -resource; this is used to prevent a VF from starving other VFs or the PF of -filter resources. -The VF's default mac address does not count towards this limit. +Specify the maximum number of unique MAC address filters that the VF can +request. +Repeated requests for the same address count once. +Each allowed MAC address requires a hardware filter, which is a finite +resource; this limit prevents a VF from starving other VFs or the PF of filter +resources. +A PF-assigned +.Dq mac-addr +does not count towards this limit. +When +.Dq mac-addr +is omitted, a VF-chosen address, including an address randomly generated by +.Xr iavf 4 , +counts as a unique filter. By default, this is set to 64. .El .Pp diff --git a/sys/dev/ice/ice_iov.c b/sys/dev/ice/ice_iov.c index 68cfae7197db..315950b6f8f8 100644 --- a/sys/dev/ice/ice_iov.c +++ b/sys/dev/ice/ice_iov.c @@ -103,6 +103,7 @@ static void ice_vc_del_vlan_msg(struct ice_softc *sc, struct ice_vf *vf, static int ice_vc_select_vlans(struct ice_vf *vf, u16 *vids, u16 count, bool add, u16 *selected_count); static enum virtchnl_status_code ice_iov_err_to_virt_err(int ice_err); +static int ice_vf_mac_filter_index(struct ice_vf *vf, const uint8_t *addr); static int ice_vf_validate_mac(struct ice_vf *vf, const uint8_t *addr); #ifdef DRIVER_FAILPOINTS @@ -520,6 +521,19 @@ ice_iov_add_vf(struct ice_softc *sc, uint16_t vfnum, const nvlist_t *params) vf->vlan_limit = nvlist_get_number(params, "max-vlan-allowed"); vf->mac_filter_limit = nvlist_get_number(params, "max-mac-filters"); + if (vf->mac_filter_limit != 0) { + vf->mac_filters = mallocarray(vf->mac_filter_limit, + sizeof(*vf->mac_filters), M_ICE, M_NOWAIT | M_ZERO); + if (vf->mac_filters == NULL) { + device_printf(sc->dev, + "Unable to allocate VF-%d MAC filter memory\n", + vfnum); + error = ENOMEM; + goto release_imap; + } + } + ICE_IOV_FAIL_POINT(sc, vfnum, add_after_mac_filter_memory, error, + free_mac_filters); vf->vf_flags |= VF_FLAG_VLAN_CAP; @@ -528,29 +542,33 @@ ice_iov_add_vf(struct ice_softc *sc, uint16_t vfnum, const nvlist_t *params) if (error) { device_printf(sc->dev, "Unable to initialize VF %d VSI: %s\n", vfnum, ice_err_str(error)); - goto release_imap; + goto free_mac_filters; } ICE_IOV_FAIL_POINT(sc, vfnum, add_after_vsi_init, error, - release_imap); + free_mac_filters); error = ice_iov_configure_mac_anti_spoof(sc, vf); if (error != 0) - goto release_imap; + goto free_mac_filters; /* Add the broadcast address */ error = ice_add_vsi_mac_filter(vsi, broadcastaddr); if (error) { device_printf(sc->dev, "Unable to add broadcast filter VF %d VSI: %s\n", vfnum, ice_err_str(error)); - goto release_imap; + goto free_mac_filters; } ICE_IOV_FAIL_POINT(sc, vfnum, add_after_broadcast_filter, error, - release_imap); + free_mac_filters); atomic_set_32(&vf->vf_flags, VF_FLAG_ENABLED); ice_iov_ready_vf(sc, vf); return (0); +free_mac_filters: + free(vf->mac_filters, M_ICE); + vf->mac_filters = NULL; + vf->mac_filter_cnt = 0; release_imap: ice_resmgr_release_map(&sc->dev_imgr, vf->vf_imap, vf->num_irq_vectors); @@ -594,6 +612,9 @@ ice_iov_uninit(struct ice_softc *sc) vf = &sc->vfs[i]; atomic_store_rel_32(&vf->vf_flags, 0); vsi = vf->vsi; + free(vf->mac_filters, M_ICE); + vf->mac_filters = NULL; + vf->mac_filter_cnt = 0; /* Free VF interrupt reservation */ if (vf->vf_imap) { @@ -1180,6 +1201,25 @@ ice_vf_validate_mac(struct ice_vf *vf, const uint8_t *addr) return (0); } +/** + * ice_vf_mac_filter_index - Find a VF-owned MAC filter + * @vf: VF tracking structure + * @addr: MAC address to find + * + * The administrator-assigned address does not consume the configurable VF + * filter quota and is therefore not stored in this array. + */ +static int +ice_vf_mac_filter_index(struct ice_vf *vf, const uint8_t *addr) +{ + + for (u16 i = 0; i < vf->mac_filter_cnt; i++) { + if (memcmp(vf->mac_filters[i].addr, addr, ETHER_ADDR_LEN) == 0) + return (i); + } + return (-1); +} + /** * ice_vc_add_eth_addr_msg - Handle VIRTCHNL_OP_ADD_ETH_ADDR msg from VF * @sc: device private structure @@ -1195,38 +1235,50 @@ ice_vc_add_eth_addr_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf) enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS; struct virtchnl_ether_addr_list *addr_list; struct ice_hw *hw = &sc->hw; - u16 added_addr_cnt = 0; + u16 new_filters; int error = 0; addr_list = (struct virtchnl_ether_addr_list *)msg_buf; - if (addr_list->num_elements > - (vf->mac_filter_limit - vf->mac_filter_cnt)) { + /* Validate the entire batch and charge only unique, absent filters. */ + new_filters = 0; + for (int i = 0; i < addr_list->num_elements; i++) { + u8 *addr = addr_list->list[i].addr; + int j; + + error = ice_vf_validate_mac(vf, addr); + if (error != 0) { + device_printf(sc->dev, + "%s: VF-%d: invalid or unauthorized MAC for VSI %d\n", + __func__, vf->vf_num, vf->vsi->idx); + v_status = VIRTCHNL_STATUS_ERR_PARAM; + goto done; + } + for (j = 0; j < i; j++) { + if (memcmp(addr_list->list[j].addr, addr, + ETHER_ADDR_LEN) == 0) + break; + } + if (j != i || memcmp(addr, vf->mac, ETHER_ADDR_LEN) == 0 || + ice_vf_mac_filter_index(vf, addr) >= 0) + continue; + new_filters++; + } + if ((u32)vf->mac_filter_cnt + new_filters > vf->mac_filter_limit) { v_status = VIRTCHNL_STATUS_ERR_NO_MEMORY; goto done; } for (int i = 0; i < addr_list->num_elements; i++) { u8 *addr = addr_list->list[i].addr; + bool assigned; /* The type flag is currently ignored; every MAC address is * treated as the LEGACY type */ - - error = ice_vf_validate_mac(vf, addr); - if (error == EPERM) { - device_printf(sc->dev, - "%s: VF-%d: Not permitted to add MAC addr for VSI %d\n", - __func__, vf->vf_num, vf->vsi->idx); - v_status = VIRTCHNL_STATUS_ERR_PARAM; - continue; - } else if (error) { - device_printf(sc->dev, - "%s: VF-%d: Did not add invalid MAC addr for VSI %d\n", - __func__, vf->vf_num, vf->vsi->idx); - v_status = VIRTCHNL_STATUS_ERR_PARAM; + assigned = memcmp(addr, vf->mac, ETHER_ADDR_LEN) == 0; + if (!assigned && ice_vf_mac_filter_index(vf, addr) >= 0) continue; - } error = ice_add_vsi_mac_filter(vf->vsi, addr); if (error) { @@ -1236,13 +1288,14 @@ ice_vc_add_eth_addr_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf) v_status = VIRTCHNL_STATUS_ERR_PARAM; continue; } - /* Don't count VF's MAC against its MAC filter limit */ - if (memcmp(addr, vf->mac, ETHER_ADDR_LEN)) - added_addr_cnt++; + if (!assigned) { + MPASS(vf->mac_filter_cnt < vf->mac_filter_limit); + memcpy(vf->mac_filters[vf->mac_filter_cnt].addr, addr, + ETHER_ADDR_LEN); + vf->mac_filter_cnt++; + } } - vf->mac_filter_cnt += added_addr_cnt; - done: ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_ADD_ETH_ADDR, v_status, NULL, 0, NULL); @@ -1263,13 +1316,29 @@ ice_vc_del_eth_addr_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf) enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS; struct virtchnl_ether_addr_list *addr_list; struct ice_hw *hw = &sc->hw; - u16 deleted_addr_cnt = 0; int error = 0; addr_list = (struct virtchnl_ether_addr_list *)msg_buf; for (int i = 0; i < addr_list->num_elements; i++) { - error = ice_remove_vsi_mac_filter(vf->vsi, addr_list->list[i].addr); + u8 *addr = addr_list->list[i].addr; + bool assigned; + int index; + + error = ice_vf_validate_mac(vf, addr); + if (error != 0) { + v_status = VIRTCHNL_STATUS_ERR_PARAM; + continue; + } + assigned = memcmp(addr, vf->mac, ETHER_ADDR_LEN) == 0; + if (assigned && + (vf->vf_flags & VF_FLAG_SET_MAC_CAP) == 0) + continue; + index = assigned ? -1 : ice_vf_mac_filter_index(vf, addr); + if (!assigned && index < 0) + continue; + + error = ice_remove_vsi_mac_filter(vf->vsi, addr); if (error) { device_printf(sc->dev, "%s: VF-%d: Error removing MAC addr for VSI %d\n", @@ -1277,16 +1346,17 @@ ice_vc_del_eth_addr_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf) v_status = VIRTCHNL_STATUS_ERR_PARAM; continue; } - /* Don't count VF's MAC against its MAC filter limit */ - if (memcmp(addr_list->list[i].addr, vf->mac, ETHER_ADDR_LEN)) - deleted_addr_cnt++; + if (!assigned) { + if (index + 1 < vf->mac_filter_cnt) { + memmove(&vf->mac_filters[index], + &vf->mac_filters[index + 1], + (vf->mac_filter_cnt - index - 1) * + sizeof(*vf->mac_filters)); + } + vf->mac_filter_cnt--; + } } - if (deleted_addr_cnt >= vf->mac_filter_cnt) - vf->mac_filter_cnt = 0; - else - vf->mac_filter_cnt -= deleted_addr_cnt; - ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_DEL_ETH_ADDR, v_status, NULL, 0, NULL); } diff --git a/sys/dev/ice/ice_iov.h b/sys/dev/ice/ice_iov.h index 9091bbd8fbf6..fc78169172d2 100644 --- a/sys/dev/ice/ice_iov.h +++ b/sys/dev/ice/ice_iov.h @@ -75,6 +75,10 @@ enum ice_vf_flags { VF_FLAG_RESET_FAILED = BIT(7), }; +struct ice_vf_mac_filter { + u8 addr[ETHER_ADDR_LEN]; +}; + /** * @struct ice_vf * @brief PF's VF software context @@ -91,6 +95,7 @@ struct ice_vf { u16 mac_filter_limit; u16 mac_filter_cnt; + struct ice_vf_mac_filter *mac_filters; u16 vlan_limit; u16 vlan_cnt; #define ICE_VF_VLAN_MAP_LEN (EVL_VLID_MASK + 1)