git: 90e7dbe5e2ca - main - iflib: Add registration failure injection points
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 14 Aug 2026 21:55:41 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=90e7dbe5e2ca47baff4e4c6d9e892a0554eec4db
commit 90e7dbe5e2ca47baff4e4c6d9e892a0554eec4db
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-08 04:33:25 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-14 21:55:28 +0000
iflib: Add registration failure injection points
Add six device-scoped fail(9) points at the registration milestones
needed to exercise each unwind path. An exact, runtime-only device
selector prevents unrelated iflib devices from consuming an armed point.
Mark the points non-sleepable because registration holds the ifnet and
context locks. Document one-shot operation and bus-address reprobe so a
failed attach can be recovered without another kernel build.
Reviewed by: gallatin
MFC after: 2 weeks
Sponsored by: BBOX.io
Differential Revision: https://reviews.freebsd.org/D58722
---
share/man/man4/iflib.4 | 40 ++++++++++++++++++++++++++++++++++++++++
sys/net/iflib.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 86 insertions(+)
diff --git a/share/man/man4/iflib.4 b/share/man/man4/iflib.4
index 9ddba8933ed8..031e33a2409e 100644
--- a/share/man/man4/iflib.4
+++ b/share/man/man4/iflib.4
@@ -248,7 +248,47 @@ Current receive ring producer index.
.Pp
Additional OIDs useful for driver and iflib development are exposed when the
INVARIANTS and/or WITNESS options are enabled in the kernel.
+.Ss FAILURE INJECTION
+Registration failures can be injected for one selected device through the
+.Xr fail 9
+framework.
+Set
+.Va debug.fail_point.iflib.register_device
+to the exact device name and configure one of these fail points:
+.Bl -tag -width "register_before_attach_pre"
+.It Va register_before_attach_pre
+Before the driver's pre-attach method.
+.It Va register_after_attach_pre
+After the driver's pre-attach method succeeds.
+.It Va register_after_taskqueue
+After the private taskqueue is started.
+.It Va register_after_interrupts
+After interrupt resources are allocated.
+.It Va register_after_queues
+After queue setup and core-offset allocation.
+.It Va register_after_attach_post
+After the interface is attached and the driver's post-attach method succeeds.
+.El
+.Pp
+The fail points are under
+.Va debug.fail_point.iflib
+and accept the syntax described by
+.Xr fail 9 .
+A one-shot failure is safest because it permits the next probe to recover the
+device:
+.Bd -literal -offset indent
+sysctl debug.fail_point.iflib.register_device=igc1
+sysctl debug.fail_point.iflib.register_after_attach_pre='1*return(5)'
+devctl detach igc1
+devctl attach pci0:4:0:0 # returns EIO
+devctl attach pci0:4:0:0 # succeeds
+.Ed
+.Pp
+After detach, a device may no longer have its former name.
+Use a bus-specific address, as shown in the PCI example above, to reprobe it.
.Sh SEE ALSO
+.Xr devctl 8 ,
+.Xr fail 9 ,
.Xr iflib 9
.Sh HISTORY
This framework was introduced in
diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index 7b5de820fd71..461ff0ba273e 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -34,6 +34,7 @@
#include <sys/types.h>
#include <sys/bus.h>
#include <sys/eventhandler.h>
+#include <sys/fail.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -565,6 +566,15 @@ TASKQGROUP_DEFINE(if_config_tqg, 1, 1);
static SYSCTL_NODE(_net, OID_AUTO, iflib, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
"iflib driver parameters");
+static SYSCTL_NODE(_debug_fail_point, OID_AUTO, iflib,
+ CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "iflib fail points");
+
+static char iflib_register_fail_device[32];
+SYSCTL_STRING(_debug_fail_point_iflib, OID_AUTO, register_device,
+ CTLFLAG_RW | CTLFLAG_MPSAFE,
+ iflib_register_fail_device, sizeof(iflib_register_fail_device),
+ "device name eligible for registration fail points");
+
/*
* XXX need to ensure that this can't accidentally cause the head to be moved backwards
*/
@@ -5198,6 +5208,30 @@ unref_ctx_core_offset(if_ctx_t ctx)
MPASS(!ctx->ifc_core_offset_ref);
}
+static bool
+iflib_register_fail_device_matches(device_t dev)
+{
+ const char *nameunit;
+
+ nameunit = device_get_nameunit(dev);
+ return (iflib_register_fail_device[0] != '\0' && nameunit != NULL &&
+ strcmp(nameunit, iflib_register_fail_device) == 0);
+}
+
+#define IFLIB_REGISTER_FAIL_POINT(_dev, _name, _error, _label) do { \
+ KFAIL_POINT_CODE_COND(_debug_fail_point_iflib, _name, \
+ iflib_register_fail_device_matches((_dev)), \
+ FAIL_POINT_NONSLEEPABLE, { \
+ (_error) = RETURN_VALUE; \
+ if ((_error) <= 0) \
+ (_error) = EIO; \
+ device_printf((_dev), \
+ "injecting iflib registration failure at %s: %d\n", \
+ #_name, (_error)); \
+ goto _label; \
+ }); \
+} while (0)
+
int
iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ctxp)
{
@@ -5245,11 +5279,15 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
iflib_reset_qvalues(ctx);
IFNET_WLOCK();
CTX_LOCK(ctx);
+ IFLIB_REGISTER_FAIL_POINT(dev, register_before_attach_pre, err,
+ fail_cleanup);
if ((err = IFDI_ATTACH_PRE(ctx)) != 0) {
device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err);
goto fail_cleanup;
}
attach_pre_succeeded = true;
+ IFLIB_REGISTER_FAIL_POINT(dev, register_after_attach_pre, err,
+ fail_cleanup);
_iflib_pre_assert(scctx);
ctx->ifc_txrx = *scctx->isc_txrx;
@@ -5333,6 +5371,8 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
TASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx);
TASK_INIT(&ctx->ifc_led_task, 0, _task_fn_led, ctx);
+ IFLIB_REGISTER_FAIL_POINT(dev, register_after_taskqueue, err,
+ fail_cleanup);
/* Set up cpu set. If it fails, use the set of all CPUs. */
if (bus_get_cpus(dev, INTR_CPUS, sizeof(ctx->ifc_cpus), &ctx->ifc_cpus) != 0) {
@@ -5363,6 +5403,8 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
msix = 0;
}
intr_allocated = true;
+ IFLIB_REGISTER_FAIL_POINT(dev, register_after_interrupts, err,
+ fail_cleanup);
/* Get memory for the station queues */
if ((err = iflib_queues_alloc(ctx))) {
device_printf(dev, "Unable to allocate queue memory\n");
@@ -5377,6 +5419,8 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
* Now that we know how many queues there are, get the core offset.
*/
ctx->ifc_sysctl_core_offset = get_ctx_core_offset(ctx);
+ IFLIB_REGISTER_FAIL_POINT(dev, register_after_queues, err,
+ fail_cleanup);
if (msix > 1) {
/*
@@ -5442,6 +5486,8 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err);
goto fail_detach;
}
+ IFLIB_REGISTER_FAIL_POINT(dev, register_after_attach_post, err,
+ fail_detach);
/*
* Tell the upper layer(s) if IFCAP_VLAN_MTU is supported.