git: 1ccf543b21ef - main - ifconfig: Add SR-IOV VF status output
Date: Sun, 09 Aug 2026 06:47:43 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=1ccf543b21eff6e0828142e5c1d09519247143f4
commit 1ccf543b21eff6e0828142e5c1d09519247143f4
Author: Eric Joyner <erj@FreeBSD.org>
AuthorDate: 2019-03-18 18:30:00 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-09 06:46:29 +0000
ifconfig: Add SR-IOV VF status output
- Adds SR-IOV VF status to the existing ifconfig "-v" output
- Adds ioctl command for reporting VF status info from drivers
- Adds support to iflib for drivers to handle this new ioctl
- Add support for ioctl in ixl(4)
Signed-off-by: Eric Joyner <erj@freebsd.org>
Relnotes: yes
Differential Revision: https://reviews.freebsd.org/D19647
---
sbin/ifconfig/Makefile | 1 +
sbin/ifconfig/ifconfig.c | 2 ++
sbin/ifconfig/ifconfig.h | 1 +
sbin/ifconfig/ifconfig_netlink.c | 3 +-
sbin/ifconfig/ifvfstatus.c | 78 ++++++++++++++++++++++++++++++++++++++++
sys/dev/ixl/if_ixl.c | 35 +++++++++++++++++-
sys/net/if.h | 15 ++++++++
sys/net/ifdi_if.m | 12 +++++++
sys/net/iflib.c | 12 +++++++
sys/sys/sockio.h | 2 ++
10 files changed, 159 insertions(+), 2 deletions(-)
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile
index 26391023d54a..759b5d6f1438 100644
--- a/sbin/ifconfig/Makefile
+++ b/sbin/ifconfig/Makefile
@@ -35,6 +35,7 @@ SRCS+= ifgif.c # GIF reversed header workaround
SRCS+= ifipsec.c # IPsec VTI
SRCS+= sfp.c # SFP/SFP+ information
+SRCS+= ifvfstatus.c # VF status information
LIBADD+= ifconfig m util
CFLAGS+= -I${SRCTOP}/lib/libifconfig -I${OBJTOP}/lib/libifconfig
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 0e839eeafc5b..52aa5696804e 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -1891,6 +1891,8 @@ status(if_ctx *ctx, const struct sockaddr_dl *sdl __unused, struct ifaddrs *ifa)
args->afp->af_other_status(ctx);
print_ifstatus(ctx);
+ if (args->verbose > 0)
+ vf_status(ctx);
if (args->verbose > 0)
sfp_status(ctx);
diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h
index 672020443b8c..75778e27a340 100644
--- a/sbin/ifconfig/ifconfig.h
+++ b/sbin/ifconfig/ifconfig.h
@@ -281,6 +281,7 @@ void clone_setdefcallback_prefix(const char *, clone_callback_func *);
void clone_setdefcallback_filter(clone_match_func *, clone_callback_func *);
void sfp_status(if_ctx *ctx);
+void vf_status(if_ctx *ctx);
struct sockaddr_dl;
bool match_ether(const struct sockaddr_dl *sdl);
diff --git a/sbin/ifconfig/ifconfig_netlink.c b/sbin/ifconfig/ifconfig_netlink.c
index b1467fde4c93..565a1ac91e20 100644
--- a/sbin/ifconfig/ifconfig_netlink.c
+++ b/sbin/ifconfig/ifconfig_netlink.c
@@ -414,6 +414,8 @@ status_nl(if_ctx *ctx, struct iface *iface)
args->afp->af_other_status(ctx);
print_ifstatus(ctx);
+ if (args->verbose > 0)
+ vf_status(ctx);
if (args->drivername || args->verbose) {
if (ifconfig_get_orig_name(lifh, link->ifla_ifname,
&drivername) != 0) {
@@ -492,4 +494,3 @@ list_interfaces_nl(struct ifconfig_args *args)
close(ctx->io_s);
snl_free(&ss);
}
-
diff --git a/sbin/ifconfig/ifvfstatus.c b/sbin/ifconfig/ifvfstatus.c
new file mode 100644
index 000000000000..0c90d667855c
--- /dev/null
+++ b/sbin/ifconfig/ifvfstatus.c
@@ -0,0 +1,78 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ifconfig.h"
+
+void
+vf_status(if_ctx *ctx)
+{
+ struct ifvfstatus_entry *entries;
+ struct ifvfstatus ifvfs;
+
+ memset(&ifvfs, 0, sizeof(ifvfs));
+ strlcpy(ifvfs.ifvfs_name, ctx->ifname, sizeof(ifvfs.ifvfs_name));
+ if (ioctl_ctx(ctx, SIOCGIFVFSTATUS, &ifvfs) < 0)
+ return;
+ if (ifvfs.ifvfs_count == 0)
+ return;
+
+ entries = calloc(ifvfs.ifvfs_count, sizeof(*entries));
+ if (entries == NULL)
+ err(1, "calloc");
+ ifvfs.ifvfs_list = entries;
+ if (ioctl_ctx(ctx, SIOCGIFVFSTATUS, &ifvfs) < 0) {
+ free(entries);
+ warn("SIOCGIFVFSTATUS");
+ return;
+ }
+
+ printf("\tvirtual functions: %d\n", ifvfs.ifvfs_count);
+ for (int i = 0; i < ifvfs.ifvfs_count; i++) {
+ printf("\t\tvf %3d: mac %s", i,
+ ether_ntoa((const struct ether_addr *)entries[i].mac_addr));
+ if (entries[i].vlan > -1)
+ printf(" vlan %d", entries[i].vlan);
+ if (entries[i].active)
+ printf(" active");
+ putchar('\n');
+ }
+
+ free(entries);
+}
diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c
index bfaf6cd69e58..439b93f0b80a 100644
--- a/sys/dev/ixl/if_ixl.c
+++ b/sys/dev/ixl/if_ixl.c
@@ -122,6 +122,7 @@ static uint64_t ixl_if_get_counter(if_ctx_t ctx, ift_counter cnt);
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 int ixl_if_vfstat_ioctl(if_ctx_t ctx, struct ifvfstatus *ifvfs);
#ifdef PCI_IOV
static void ixl_if_vflr_handle(if_ctx_t ctx);
#endif
@@ -193,6 +194,7 @@ static device_method_t ixl_if_methods[] = {
DEVMETHOD(ifdi_i2c_req, ixl_if_i2c_req),
DEVMETHOD(ifdi_priv_ioctl, ixl_if_priv_ioctl),
DEVMETHOD(ifdi_needs_restart, ixl_if_needs_restart),
+ DEVMETHOD(ifdi_vfstat_ioctl, ixl_if_vfstat_ioctl),
#ifdef PCI_IOV
DEVMETHOD(ifdi_iov_init, ixl_if_iov_init),
DEVMETHOD(ifdi_iov_uninit, ixl_if_iov_uninit),
@@ -1908,6 +1910,38 @@ ixl_if_needs_restart(if_ctx_t ctx __unused, enum iflib_restart_event event)
}
}
+static int
+ixl_if_vfstat_ioctl(if_ctx_t ctx, struct ifvfstatus *ifvfs)
+{
+ struct ixl_pf *pf;
+ struct ifvfstatus_entry ent;
+ struct ixl_vf *vf;
+ int error;
+
+ pf = iflib_get_softc(ctx);
+ if (pf->num_vfs < 1)
+ return (ENXIO);
+ if (ifvfs->ifvfs_count == 0) {
+ ifvfs->ifvfs_count = pf->num_vfs;
+ return (0);
+ }
+ if (ifvfs->ifvfs_count != pf->num_vfs)
+ return (EINVAL);
+
+ for (int i = 0; i < pf->num_vfs; i++) {
+ vf = &pf->vfs[i];
+ memset(&ent, 0, sizeof(ent));
+ ent.active = !!(vf->vf_flags & VF_FLAG_ENABLED);
+ memcpy(ent.mac_addr, vf->mac, sizeof(ent.mac_addr));
+ /* No host VLAN support. */
+ ent.vlan = -1;
+ error = copyout(&ent, &ifvfs->ifvfs_list[i], sizeof(ent));
+ if (error != 0)
+ return (error);
+ }
+ return (0);
+}
+
/*
* Sanity check and save off tunable values.
*/
@@ -1976,4 +2010,3 @@ ixl_save_pf_tunables(struct ixl_pf *pf)
pf->fc = ixl_flow_control;
}
}
-
diff --git a/sys/net/if.h b/sys/net/if.h
index 4bb6a2659ce7..c5b7768f033d 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -662,6 +662,21 @@ struct ifdownreason {
char ifdr_msg[IFDR_MSG_SIZE];
};
+struct ifvfstatus_entry {
+ uint8_t mac_addr[6];
+ int16_t vlan;
+ uint8_t active;
+ uint8_t spare0;
+ uint16_t spare1;
+ uint32_t spare2;
+};
+
+struct ifvfstatus {
+ char ifvfs_name[IFNAMSIZ];
+ int ifvfs_count;
+ struct ifvfstatus_entry *ifvfs_list;
+};
+
#endif /* __BSD_VISIBLE */
/*
diff --git a/sys/net/ifdi_if.m b/sys/net/ifdi_if.m
index cb24ba36ee60..65a130d64ee4 100644
--- a/sys/net/ifdi_if.m
+++ b/sys/net/ifdi_if.m
@@ -112,6 +112,13 @@ CODE {
return (ENOTSUP);
}
+ static int
+ null_vfstat_ioctl(if_ctx_t _ctx __unused,
+ struct ifvfstatus *_ifvfs __unused)
+ {
+ return (ENOTSUP);
+ }
+
static bool
null_needs_restart(if_ctx_t _ctx __unused, enum iflib_restart_event _event __unused)
{
@@ -375,3 +382,8 @@ METHOD int get_downreason {
if_ctx_t _ctx;
struct ifdownreason *_ifdr;
} DEFAULT null_get_downreason;
+
+METHOD int vfstat_ioctl {
+ if_ctx_t _ctx;
+ struct ifvfstatus *_ifvfs;
+} DEFAULT null_vfstat_ioctl;
diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index c56f15cc00bc..314e8e527628 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -4657,6 +4657,18 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data)
err = IFDI_GET_DOWNREASON(ctx, (struct ifdownreason *)data);
CTX_UNLOCK(ctx);
break;
+ case SIOCGIFVFSTATUS:
+ {
+ struct ifvfstatus *ifvfs;
+
+ ifvfs = (struct ifvfstatus *)data;
+ if (ifvfs->ifvfs_count < 0)
+ return (EINVAL);
+ CTX_LOCK(ctx);
+ err = IFDI_VFSTAT_IOCTL(ctx, ifvfs);
+ CTX_UNLOCK(ctx);
+ break;
+ }
default:
err = ether_ioctl(ifp, command, data);
break;
diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h
index 121acd5ba287..a3ce196c7959 100644
--- a/sys/sys/sockio.h
+++ b/sys/sys/sockio.h
@@ -152,4 +152,6 @@
#define SIOCSUMBPARAM _IOW('i', 158, struct ifreq) /* set MBIM param */
#define SIOCGUMBPARAM _IOWR('i', 159, struct ifreq) /* get MBIM param */
+#define SIOCGIFVFSTATUS _IOWR('i', 163, struct ifvfstatus) /* get VF status */
+
#endif /* !_SYS_SOCKIO_H_ */