From nobody Fri Aug 7 01:47:47 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 4hGRqR4y0wz6ndl3 for ; Fri, 07 Aug 2026 01:47:47 +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 "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hGRqR1gn7z3njV for ; Fri, 07 Aug 2026 01:47:47 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786067267; 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=R4vexhQdUDKjl1f4dOTFMbv5mCo6YCT2XXB8J1mB6JQ=; b=o4V6ZIPsEv9o2/PnomPO3LICptW1vB8qttlVrizeCjHE3kpkISRL9nyEg1d4O+3/qqP5F7 0aPGgx7O4BqOxV8it73uk4dpaKuf2NMvZUNprbHkzPFVap69D/jcB6pkeWBxYmdKt9AzJu x+CoYeO4EAeTFurtvPUdpEBDxlLbfJO0fK3HcZZn2fhu7BdZHvF6tLz3fOlma6BhgnhmhS r/vG/mgHHUjBcXx2xjD1JAbv4VAXyKcFtDmCimjh23X+onSjHXWImVg2CvB40Y01tKvdIl kQU/nOBoTN4XTtNA/UstdDVRw7DAGqqCCPpRCk7GPlJ+p16kTuqT5RsVt1rIKA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1786067267; a=rsa-sha256; cv=none; b=hkokpj9wYIbFxFGxPxO/fU9NW2+GHn88HpVh5CM1Q/O2Y2YxvqRQtOW8sYIryHo/NKfY2H ZW6hnawzHOfTRqk31yvkeJiO44ILTeQM9upPd1Y0SlQfUUU1uKhqxaVD3yrgYIk+QpewWS x/xPPyxvqUnoU9Pt9nimRxc7wq32YzTMekSxk+N1Jl5AKbzQSHuNPYGl1ECdT/QQIKHhfW K37kYkGMnyEmSFSmidofe2Zx2duHboyIJ+PthldnBV1yfDttTXoF0D2GYsYAeGKRwQFhzt VXuhVD3MtXaf24mpBofnExsMXWXcFPTkqvV486pBIHNVlvI0HpbUulUoekxsvg== 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=1786067267; 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=R4vexhQdUDKjl1f4dOTFMbv5mCo6YCT2XXB8J1mB6JQ=; b=WP6mMbgTAEjAeJ3v1pOBK+zulw2tj/GV97fb3+yJYBojLiKQHsYzWHGegBS9ZUKXwQUPc/ v+VdABiJYk64gYrQTm0vPa+NpTgwepbkYe4Y/+1S+anu4gpi9X8GVq3q+K8cctbnMWDaV2 0O0sNnC6FgtJJHlkRMihb4Yz8t29njVrpt0aoObjwr3ZRR0XQtARkcjsh27Ok1437T2Mr5 00HTA2UA3TnhQHSCB0ovrwbycCO72vjqSq8UhLXmaAl2Ghlk9qYvj8wT7LW3YURRPDwELi DTqJLUZdBvwwYOVXpS6uDKSpj2FWNKshNDpKAuAF2C+F1eYn4R/wrt4q+f5Gag== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hGRqR0l03zmqq for ; Fri, 07 Aug 2026 01:47:47 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3c60b by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Fri, 07 Aug 2026 01:47:47 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kevin Bowling Subject: git: 6404ef10d629 - main - ixgbe: implement VF secondary MAC filters 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: 6404ef10d62999d6ac16b0fb25bbdcb463b866a2 Auto-Submitted: auto-generated Date: Fri, 07 Aug 2026 01:47:47 +0000 Message-Id: <6a753943.3c60b.174df26@gitrepo.freebsd.org> The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=6404ef10d62999d6ac16b0fb25bbdcb463b866a2 commit 6404ef10d62999d6ac16b0fb25bbdcb463b866a2 Author: Kevin Bowling AuthorDate: 2026-07-31 12:58:01 +0000 Commit: Kevin Bowling CommitDate: 2026-08-07 01:42:14 +0000 ixgbe: implement VF secondary MAC filters The PF advertises the legacy SET_MACVLAN mailbox request but always rejects it. The request installs secondary unicast addresses. Allocate an owned RAR pool for VF secondary addresses, reserve low entries for PF filters, and place VF-primary addresses at the top of the usable RAR range. Reject address collisions and cap each VF at three secondary filters so one guest cannot exhaust the shared table. Clear secondary filters on VF or PF reset and on SR-IOV teardown. This hardware can anti-spoof only the VF primary source address. Reject secondary filters while MAC anti-spoofing is configured, so installing them requires an explicit administrative policy choice. Report optional filter-table allocation failure without disabling SR-IOV. Adapt the owned-RAR allocation and reset-cleanup model from igb(4) in a2ed165f0049 to DPDK's ixgbe SET_MACVLAN mailbox semantics. MFC after: 1 week Relnotes: yes --- share/man/man4/ix.4 | 10 +++ sys/dev/ixgbe/if_sriov.c | 154 ++++++++++++++++++++++++++++++++++++++++++-- sys/dev/ixgbe/ixgbe.h | 10 +++ sys/dev/ixgbe/ixgbe_sriov.h | 2 + 4 files changed, 171 insertions(+), 5 deletions(-) diff --git a/share/man/man4/ix.4 b/share/man/man4/ix.4 index fb1d1032c0f1..62fe4e1f9287 100644 --- a/share/man/man4/ix.4 +++ b/share/man/man4/ix.4 @@ -91,6 +91,16 @@ registered by the VF are presented normally to its network stack. VLAN filtering remains enabled in the hardware while SR-IOV is active so that the PF can enforce VLAN ownership for each VF pool, including when hardware VLAN filtering has been disabled on the PF interface. +.Pp +Secondary unicast addresses requested by a VF are accepted only when the VF +is permitted to change its MAC address and +.Va mac-anti-spoof +is disabled in its +.Xr iovctl.conf 5 +configuration. +The hardware MAC anti-spoofing control can validate only the VF's primary +source address, so the driver does not silently weaken an enabled policy to +install secondary addresses. .Sh HARDWARE The .Nm diff --git a/sys/dev/ixgbe/if_sriov.c b/sys/dev/ixgbe/if_sriov.c index 903ed72d6e2f..31db2cbb0407 100644 --- a/sys/dev/ixgbe/if_sriov.c +++ b/sys/dev/ixgbe/if_sriov.c @@ -167,6 +167,31 @@ ixgbe_vf_mac_changed(struct ixgbe_vf *vf, const uint8_t *mac) return (bcmp(mac, vf->ether_addr, ETHER_ADDR_LEN) != 0); } +static bool +ixgbe_rar_mac_in_use(struct ixgbe_softc *sc, const uint8_t *mac, + int excluded_rar) +{ + struct ixgbe_hw *hw; + uint32_t addr_high, addr_low, rah; + int i; + + hw = &sc->hw; + addr_low = (uint32_t)mac[0] | ((uint32_t)mac[1] << 8) | + ((uint32_t)mac[2] << 16) | ((uint32_t)mac[3] << 24); + addr_high = (uint32_t)mac[4] | ((uint32_t)mac[5] << 8); + for (i = 0; i < hw->mac.num_rar_entries; i++) { + if (i == excluded_rar) + continue; + rah = IXGBE_READ_REG(hw, IXGBE_RAH(i)); + if ((rah & IXGBE_RAH_AV) != 0 && + (rah & 0xffff) == addr_high && + IXGBE_READ_REG(hw, IXGBE_RAL(i)) == addr_low) + return (true); + } + return (ixgbe_validate_mac_addr(hw->mac.san_addr) == IXGBE_SUCCESS && + bcmp(hw->mac.san_addr, mac, ETHER_ADDR_LEN) == 0); +} + static inline int ixgbe_vf_queues(int mode) { @@ -437,6 +462,25 @@ ixgbe_vf_reset_vlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf, return (error); } +static void +ixgbe_vf_clear_mac_filters(struct ixgbe_softc *sc, struct ixgbe_vf *vf, + bool clear_hw) +{ + struct ixgbe_vf_mac_filter *filter; + int i; + + for (i = 0; i < sc->num_vf_mac_filters; i++) { + filter = &sc->vf_mac_filters[i]; + if (!filter->active || filter->pool != vf->pool) + continue; + if (clear_hw) + (void)ixgbe_clear_rar(&sc->hw, filter->rar_index); + filter->active = false; + bzero(filter->mac, sizeof(filter->mac)); + } + vf->num_mac_filters = 0; +} + static boolean_t ixgbe_vf_frame_size_compatible(struct ixgbe_softc *sc, struct ixgbe_vf *vf) { @@ -501,6 +545,7 @@ ixgbe_process_vf_reset(struct ixgbe_softc *sc, struct ixgbe_vf *vf) if (rebuild_mta) ixgbe_iov_rebuild_mta(sc); + ixgbe_vf_clear_mac_filters(sc, vf, true); ixgbe_clear_rar(&sc->hw, vf->rar_index); ixgbe_vf_set_anti_spoof(sc, vf); ixgbe_toggle_txdctl(&sc->hw, vf->pool); @@ -607,6 +652,11 @@ ixgbe_vf_set_mac(struct ixgbe_softc *sc, struct ixgbe_vf *vf, uint32_t *msg) ixgbe_send_vf_failure(sc, vf, msg[0]); return; } + if (ixgbe_vf_mac_changed(vf, mac) && + ixgbe_rar_mac_in_use(sc, mac, vf->rar_index)) { + ixgbe_send_vf_failure(sc, vf, msg[0]); + return; + } bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); @@ -732,7 +782,73 @@ static void ixgbe_vf_set_macvlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf, uint32_t *msg) { - //XXX implement this + struct ixgbe_vf_mac_filter *filter, *free_filter; + struct ixgbe_hw *hw; + uint8_t *mac; + int i, index; + + hw = &sc->hw; + index = IXGBE_VT_MSGINFO(msg[0]); + if (index == 0) { + ixgbe_vf_clear_mac_filters(sc, vf, true); + ixgbe_vf_set_anti_spoof(sc, vf); + ixgbe_send_vf_success(sc, vf, msg[0]); + return; + } + if (!(vf->flags & IXGBE_VF_CAP_MAC)) + goto failure; + /* This hardware can anti-spoof only the VF's primary source MAC. */ + if ((vf->flags & IXGBE_VF_ANTI_SPOOF) != 0) + goto failure; + + mac = (uint8_t *)&msg[1]; + if (ixgbe_validate_mac_addr(mac) != IXGBE_SUCCESS) + goto failure; + if (index == 1) + ixgbe_vf_clear_mac_filters(sc, vf, true); + if (bcmp(mac, vf->ether_addr, ETHER_ADDR_LEN) == 0) { + ixgbe_vf_set_anti_spoof(sc, vf); + ixgbe_send_vf_success(sc, vf, msg[0]); + return; + } + + free_filter = NULL; + for (i = 0; i < sc->num_vf_mac_filters; i++) { + filter = &sc->vf_mac_filters[i]; + if (!filter->active) { + if (free_filter == NULL) + free_filter = filter; + continue; + } + if (bcmp(filter->mac, mac, ETHER_ADDR_LEN) != 0) + continue; + if (filter->pool != vf->pool) + goto failure; + ixgbe_send_vf_success(sc, vf, msg[0]); + return; + } + if (vf->num_mac_filters >= IXGBE_MAX_VF_MAC_FILTERS || + free_filter == NULL) + goto failure; + + /* Reject collisions with PF, VF-primary, or other reserved RARs. */ + if (ixgbe_rar_mac_in_use(sc, mac, -1)) + goto failure; + + if (ixgbe_set_rar(hw, free_filter->rar_index, mac, vf->pool, + true) != IXGBE_SUCCESS) + goto failure; + free_filter->active = true; + free_filter->pool = vf->pool; + bcopy(mac, free_filter->mac, ETHER_ADDR_LEN); + vf->num_mac_filters++; + /* MAC anti-spoofing accepts only the primary address on this family. */ + ixgbe_vf_set_anti_spoof(sc, vf); + ixgbe_send_vf_success(sc, vf, msg[0]); + return; + +failure: + ixgbe_vf_set_anti_spoof(sc, vf); ixgbe_send_vf_failure(sc, vf, msg[0]); } /* ixgbe_vf_set_macvlan */ @@ -924,7 +1040,7 @@ int ixgbe_if_iov_init(if_ctx_t ctx, u16 num_vfs, const nvlist_t *config) { struct ixgbe_softc *sc; - int retval = 0; + int i, num_filters, retval = 0; sc = iflib_get_softc(ctx); sc->iov_mode = IXGBE_NO_VM; @@ -961,6 +1077,22 @@ ixgbe_if_iov_init(if_ctx_t ctx, u16 num_vfs, const nvlist_t *config) retval = ENOMEM; goto err_init_iov; } + num_filters = sc->hw.mac.num_rar_entries - num_vfs - 1 - + IXGBE_MAX_PF_MAC_FILTERS; + if (num_filters > 0) { + sc->vf_mac_filters = mallocarray(num_filters, + sizeof(*sc->vf_mac_filters), M_IXGBE_SRIOV, + M_NOWAIT | M_ZERO); + if (sc->vf_mac_filters != NULL) { + sc->num_vf_mac_filters = num_filters; + for (i = 0; i < num_filters; i++) + sc->vf_mac_filters[i].rar_index = + IXGBE_MAX_PF_MAC_FILTERS + 1 + i; + } else + device_printf(sc->dev, + "could not allocate VF secondary MAC filters; " + "SET_MACVLAN will be unavailable\n"); + } sc->num_vfs = num_vfs; ixgbe_init_mbx_params_pf(&sc->hw); @@ -1004,6 +1136,7 @@ ixgbe_if_iov_uninit(if_ctx_t ctx) for (i = 0; i < sc->num_vfs; i++) { if (!(sc->vfs[i].flags & IXGBE_VF_ACTIVE)) continue; + ixgbe_vf_clear_mac_filters(sc, &sc->vfs[i], true); sc->vfs[i].flags &= ~IXGBE_VF_ANTI_SPOOF; ixgbe_vf_set_anti_spoof(sc, &sc->vfs[i]); } @@ -1016,6 +1149,9 @@ ixgbe_if_iov_uninit(if_ctx_t ctx) sc->num_vfs = 0; ixgbe_iov_rebuild_mta(sc); + free(sc->vf_mac_filters, M_IXGBE_SRIOV); + sc->vf_mac_filters = NULL; + sc->num_vf_mac_filters = 0; free(sc->vfs, M_IXGBE_SRIOV); sc->vfs = NULL; sc->feat_en &= ~IXGBE_FEATURE_SRIOV; @@ -1046,6 +1182,7 @@ ixgbe_init_vf(struct ixgbe_softc *sc, struct ixgbe_vf *vf) vf->api_ver = IXGBE_API_VER_UNKNOWN; vf->num_mc_hashes = 0; bzero(vf->mc_hash, sizeof(vf->mc_hash)); + ixgbe_vf_clear_mac_filters(sc, vf, false); error = ixgbe_vf_reset_vlan(sc, vf, false); if (error != IXGBE_SUCCESS) return (error); @@ -1145,6 +1282,7 @@ ixgbe_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config) struct ixgbe_softc *sc; struct ixgbe_vf *vf; const void *mac; + uint8_t mac_addr[ETHER_ADDR_LEN]; uint64_t configured_vlan; uint16_t vlan; s32 error; @@ -1157,6 +1295,7 @@ ixgbe_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config) vf = &sc->vfs[vfnum]; if (vf->flags & IXGBE_VF_ACTIVE) return (EBUSY); + bzero(vf, sizeof(*vf)); configured_vlan = nvlist_get_number(config, "vlan"); if (configured_vlan > VF_VLAN_TRUNK) @@ -1169,8 +1308,8 @@ ixgbe_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config) vf->pool = vfnum; - /* RAR[0] is used by the PF so use vfnum + 1 for VF RAR. */ - vf->rar_index = vfnum + 1; + /* Allocate VF-primary RARs from the top, away from PF filters. */ + vf->rar_index = sc->hw.mac.num_rar_entries - (vfnum + 1); vf->default_vlan = vlan; vf->maximum_frame_size = ETHER_MAX_LEN; ixgbe_update_max_frame(sc, vf->maximum_frame_size); @@ -1181,7 +1320,12 @@ ixgbe_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config) if (nvlist_exists_binary(config, "mac-addr")) { mac = nvlist_get_binary(config, "mac-addr", NULL); - bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); + bcopy(mac, mac_addr, sizeof(mac_addr)); + if (ixgbe_validate_mac_addr(mac_addr) != IXGBE_SUCCESS) + return (EINVAL); + if (ixgbe_rar_mac_in_use(sc, mac_addr, vf->rar_index)) + return (EADDRINUSE); + bcopy(mac_addr, vf->ether_addr, ETHER_ADDR_LEN); if (nvlist_get_bool(config, "allow-set-mac")) vf->flags |= IXGBE_VF_CAP_MAC; } else diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h index 330d1a8a2cb3..4db140249006 100644 --- a/sys/dev/ixgbe/ixgbe.h +++ b/sys/dev/ixgbe/ixgbe.h @@ -345,6 +345,13 @@ struct ix_tx_queue { #define IXGBE_MAX_VF_MC 30 /* Max number of multicast entries */ +struct ixgbe_vf_mac_filter { + uint16_t rar_index; + uint16_t pool; + bool active; + uint8_t mac[ETHER_ADDR_LEN]; +}; + struct ixgbe_vf { u_int pool; u_int rar_index; @@ -354,6 +361,7 @@ struct ixgbe_vf { uint16_t mc_hash[IXGBE_MAX_VF_MC]; uint32_t vlans[IXGBE_VFTA_SIZE]; uint16_t num_mc_hashes; + uint16_t num_mac_filters; uint16_t num_vlans; uint16_t default_vlan; uint16_t api_ver; @@ -444,6 +452,8 @@ struct ixgbe_softc { int num_vfs; int pool; struct ixgbe_vf *vfs; + struct ixgbe_vf_mac_filter *vf_mac_filters; + int num_vf_mac_filters; bool iov_mta_valid; bool iov_vfta_valid; bool iov_vlan_promisc; diff --git a/sys/dev/ixgbe/ixgbe_sriov.h b/sys/dev/ixgbe/ixgbe_sriov.h index 491a708b6f41..84b5e25a8c3c 100644 --- a/sys/dev/ixgbe/ixgbe_sriov.h +++ b/sys/dev/ixgbe/ixgbe_sriov.h @@ -69,6 +69,8 @@ #define IXGBE_NO_VM 0 #define IXGBE_32_VM 32 #define IXGBE_64_VM 64 +#define IXGBE_MAX_PF_MAC_FILTERS 15 +#define IXGBE_MAX_VF_MAC_FILTERS 3 int ixgbe_if_iov_vf_add(if_ctx_t, u16, const nvlist_t *); int ixgbe_if_iov_init(if_ctx_t, u16, const nvlist_t *);