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 <[email protected]>

Relnotes:	yes
Differential Revision:	https://reviews.freebsd.org/D19647
This commit is contained in:
Eric Joyner authored and Kevin Bowling committed 2026-08-08 23:46:29 -07:00
1 parent 75538a0f32
commit 1ccf543b21
10 files changed
+159 -2

No files matched your search

+1
View File
@@ -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
+2
View File
@@ -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);
+1
View File
@@ -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);
+2 -1
View File
@@ -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);
}
+78
View File
@@ -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);
}
+34 -1
View File
@@ -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;
}
}
+15
View File
@@ -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 */
/*
+12
View File
@@ -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;
+12
View File
@@ -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;
+2
View File
@@ -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_ */