git: 477e31110ab8 - main - ixl: Report SR-IOV VF status

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Sun, 06 Sep 2026 15:41:20 UTC
The branch main has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=477e31110ab84b941e95d95d62d8339e822719bc

commit 477e31110ab84b941e95d95d62d8339e822719bc
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-10 22:29:37 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-09-06 15:41:12 +0000

    ixl: Report SR-IOV VF status
    
    Expose cached per-VF configuration through the iflib VF status method.
    Report mailbox initialization and the negotiated virtual-channel API, MAC
    address, access or trunk VLAN mode, queue resources, administrator policy,
    PF traffic permission, and fault containment.
    
    Expose per-VF malicious-driver isolation and cumulative transmit and
    receive event counts through a versioned driver.ixl extension.
    
    Track successful PCI IOV attachment separately from hardware capability.
    This lets a successfully attached but unconfigured PF return an empty
    snapshot without claiming support when PCI IOV registration was
    unavailable.
    
    The query uses driver-cached state and does not issue AdminQ requests or
    read device registers.
    
    Sponsored by:   BBOX.io
---
 share/man/man4/ixl.4     |  32 ++++++++++++++-
 sys/dev/ixl/if_ixl.c     | 105 +++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/ixl/ixl_pf.h     |   1 +
 sys/dev/ixl/ixl_pf_iov.c |   4 +-
 4 files changed, 140 insertions(+), 2 deletions(-)

diff --git a/share/man/man4/ixl.4 b/share/man/man4/ixl.4
index b1a4a21c4592..af8327704842 100644
--- a/share/man/man4/ixl.4
+++ b/share/man/man4/ixl.4
@@ -29,7 +29,7 @@
 .\"
 .\" * Other names and brands may be claimed as the property of others.
 .\"
-.Dd August 12, 2026
+.Dd September 6, 2026
 .Dt IXL 4
 .Os
 .Sh NAME
@@ -293,6 +293,35 @@ minus one.
 An up to date list of parameters and their defaults can be found by using
 .Xr iovctl 8
 with the -S option.
+.Pp
+For each configured VF,
+.Xr ifconfig 8
+with the
+.Fl v
+option displays cached PF state, including the negotiated virtual-channel
+API after the VF completes its resource handshake following the last reset.
+The generic traffic and fault fields describe whether PF policy currently
+permits the VF to issue data traffic; they do not describe link or queue
+state.
+.Pp
+Structured status consumers also receive MDD diagnostics in the version 1
+.Cm driver.ixl
+namespace of the
+.Xr rtnetlink 4
+VF status response:
+.Bl -tag -width "mdd-tx-events"
+.It Cm version
+Namespace version number, currently 1.
+.It Cm mdd-blocked
+Boolean indicating that malicious-driver detection has isolated the VF.
+.It Cm mdd-tx-events
+Cumulative number of transmit malicious-driver latches attributed to the VF.
+.It Cm mdd-rx-events
+Cumulative number of receive malicious-driver latches attributed to the VF.
+.El
+.Pp
+The status query uses driver-cached state and does not issue AdminQ commands
+or read device registers.
 .Sh SUPPORT
 For general information and support,
 go to the Intel support website at:
@@ -307,6 +336,7 @@ email all the specific information related to the issue to
 .Xr iflib 4 ,
 .Xr led 4 ,
 .Xr netintro 4 ,
+.Xr rtnetlink 4 ,
 .Xr vlan 4 ,
 .Xr ifconfig 8 ,
 .Xr iovctl 8
diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c
index cfd673430e50..723126c0dfd9 100644
--- a/sys/dev/ixl/if_ixl.c
+++ b/sys/dev/ixl/if_ixl.c
@@ -34,6 +34,8 @@
 #include "ixl.h"
 #include "ixl_pf.h"
 
+#include <net/if_vf_status.h>
+
 #ifdef IXL_IW
 #include "ixl_iw.h"
 #include "ixl_iw_int.h"
@@ -55,6 +57,20 @@
     __XSTRING(IXL_DRIVER_VERSION_MINOR) "."		\
     __XSTRING(IXL_DRIVER_VERSION_BUILD) "-k"
 
+/* Version 1 driver.ixl extension schema; documented in ixl(4). */
+#define	IXL_VF_STATUS_NAMESPACE		"driver.ixl"
+#define	IXL_VF_STATUS_VERSION		1
+#define	IXL_VF_STATUS_MDD_BLOCKED	"mdd-blocked"
+#define	IXL_VF_STATUS_MDD_TX_EVENTS	"mdd-tx-events"
+#define	IXL_VF_STATUS_MDD_RX_EVENTS	"mdd-rx-events"
+
+enum ixl_vf_status_field {
+	IXL_VF_STATUS_FIELD_MDD_BLOCKED,
+	IXL_VF_STATUS_FIELD_MDD_TX_EVENTS,
+	IXL_VF_STATUS_FIELD_MDD_RX_EVENTS,
+	IXL_VF_STATUS_NUM_FIELDS
+};
+
 /*********************************************************************
  *  PCI Device ID Table
  *
@@ -123,6 +139,8 @@ static int	 ixl_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req);
 static int	 ixl_if_priv_ioctl(if_ctx_t ctx, u_long command, caddr_t data);
 static bool	 ixl_if_needs_restart(if_ctx_t ctx, enum iflib_restart_event event);
 static void	 ixl_if_led_func(if_ctx_t ctx, int onoff);
+static int	 ixl_if_vf_status(if_ctx_t ctx,
+		     struct if_vf_status **statusp);
 #ifdef PCI_IOV
 static void	 ixl_if_vflr_handle(if_ctx_t ctx);
 #endif
@@ -197,6 +215,7 @@ static device_method_t ixl_if_methods[] = {
 	DEVMETHOD(ifdi_priv_ioctl, ixl_if_priv_ioctl),
 	DEVMETHOD(ifdi_needs_restart, ixl_if_needs_restart),
 	DEVMETHOD(ifdi_led_func, ixl_if_led_func),
+	DEVMETHOD(ifdi_vf_status, ixl_if_vf_status),
 #ifdef PCI_IOV
 	DEVMETHOD(ifdi_iov_init, ixl_if_iov_init),
 	DEVMETHOD(ifdi_iov_uninit, ixl_if_iov_uninit),
@@ -1997,6 +2016,92 @@ ixl_if_needs_restart(if_ctx_t ctx __unused, enum iflib_restart_event event)
 	}
 }
 
+static int
+ixl_if_vf_status(if_ctx_t ctx, struct if_vf_status **statusp)
+{
+	struct ixl_pf *pf;
+	struct if_vf_extension *extension;
+	struct if_vf_info *info;
+	struct if_vf_status *status;
+	struct ixl_vf *vf;
+
+	pf = iflib_get_softc(ctx);
+	if (!pf->iov_attached)
+		return (EOPNOTSUPP);
+
+	status = if_vf_status_alloc(pf->num_vfs);
+	if (status == NULL)
+		return (ENOMEM);
+	for (int i = 0; i < pf->num_vfs; i++) {
+		vf = &pf->vfs[i];
+		info = &status->vfs[i];
+		info->fields = IFVF_F_CONFIGURED | IFVF_F_INITIALIZED |
+		    IFVF_F_VLAN_MODE | IFVF_F_VLAN_COUNT |
+		    IFVF_F_NUM_TX_QUEUES | IFVF_F_NUM_RX_QUEUES |
+		    IFVF_F_ALLOW_SET_MAC |
+		    IFVF_F_ALLOW_SET_VLAN | IFVF_F_MAC_ANTI_SPOOF |
+		    IFVF_F_ALLOW_PROMISC | IFVF_F_TRAFFIC_ALLOWED |
+		    IFVF_F_FAULT_BLOCKED;
+		info->index = i;
+		info->configured = (vf->vf_flags & VF_FLAG_ENABLED) != 0;
+		info->initialized = (vf->vf_flags & VF_FLAG_INITIALIZED) != 0;
+		if (info->initialized) {
+			snprintf(info->api_version, sizeof(info->api_version),
+			    "%u.%u", vf->version.major, vf->version.minor);
+			info->fields |= IFVF_F_API_VERSION;
+		}
+		if (!ETHER_IS_ZERO(vf->mac)) {
+			memcpy(info->mac, vf->mac, sizeof(info->mac));
+			info->fields |= IFVF_F_MAC;
+		}
+		if (vf->default_vlan == 0) {
+			info->vlan_mode = IFVF_VLAN_TRUNK;
+			info->vlan_count = vf->vsi.num_vlans;
+			info->vlan_limit = IXL_VF_MAX_VLAN_FILTERS;
+			info->fields |= IFVF_F_VLAN_LIMIT;
+		} else {
+			info->vlan_mode = IFVF_VLAN_ACCESS;
+			info->vlan = vf->default_vlan;
+			info->vlan_pcp = 0;
+			info->vlan_proto = ETHERTYPE_VLAN;
+			info->vlan_count = 1;
+			info->fields |= IFVF_F_VLAN | IFVF_F_VLAN_PCP |
+			    IFVF_F_VLAN_PROTO;
+		}
+		info->tx_queue_count = vf->qtag.num_active;
+		info->rx_queue_count = vf->qtag.num_active;
+		info->allow_set_mac =
+		    (vf->vf_flags & VF_FLAG_SET_MAC_CAP) != 0;
+		info->allow_set_vlan =
+		    (vf->vf_flags & VF_FLAG_VLAN_CAP) != 0;
+		info->mac_anti_spoof =
+		    (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF) != 0;
+		info->allow_promisc =
+		    (vf->vf_flags & VF_FLAG_PROMISC_CAP) != 0;
+		info->traffic_allowed = info->configured && !vf->mdd_blocked;
+		info->fault_blocked = vf->mdd_blocked;
+
+		extension = if_vf_status_add_extension(info,
+		    IXL_VF_STATUS_NAMESPACE, IXL_VF_STATUS_VERSION,
+		    IXL_VF_STATUS_NUM_FIELDS);
+		if (extension == NULL) {
+			if_vf_status_free(status);
+			return (ENOMEM);
+		}
+		if_vf_extension_set_bool(extension,
+		    IXL_VF_STATUS_FIELD_MDD_BLOCKED,
+		    IXL_VF_STATUS_MDD_BLOCKED, vf->mdd_blocked);
+		if_vf_extension_set_number(extension,
+		    IXL_VF_STATUS_FIELD_MDD_TX_EVENTS,
+		    IXL_VF_STATUS_MDD_TX_EVENTS, vf->mdd_tx_events);
+		if_vf_extension_set_number(extension,
+		    IXL_VF_STATUS_FIELD_MDD_RX_EVENTS,
+		    IXL_VF_STATUS_MDD_RX_EVENTS, vf->mdd_rx_events);
+	}
+	*statusp = status;
+	return (0);
+}
+
 /*
  * Sanity check and save off tunable values.
  */
diff --git a/sys/dev/ixl/ixl_pf.h b/sys/dev/ixl/ixl_pf.h
index 7d751d3bd1dc..d244a2e36a38 100644
--- a/sys/dev/ixl/ixl_pf.h
+++ b/sys/dev/ixl/ixl_pf.h
@@ -187,6 +187,7 @@ struct ixl_pf {
 	/* SR-IOV */
 	struct ixl_vf		*vfs;
 	int			num_vfs;
+	bool			iov_attached;
 	uint16_t		veb_seid;
 	int			vc_debug_lvl;
 
diff --git a/sys/dev/ixl/ixl_pf_iov.c b/sys/dev/ixl/ixl_pf_iov.c
index 64e7a5e36bcc..29f0f1fd839e 100644
--- a/sys/dev/ixl/ixl_pf_iov.c
+++ b/sys/dev/ixl/ixl_pf_iov.c
@@ -123,8 +123,10 @@ ixl_initialize_sriov(struct ixl_pf *pf)
 		device_printf(dev,
 		    "Failed to initialize SR-IOV (error=%d)\n",
 		    iov_error);
-	} else
+	} else {
+		pf->iov_attached = true;
 		device_printf(dev, "SR-IOV ready\n");
+	}
 
 	pf->vc_debug_lvl = 1;
 }