Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F171587134
D59598.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D59598.diff
View Options
Index: share/man/man9/iflibdi.9
===================================================================
--- share/man/man9/iflibdi.9
+++ share/man/man9/iflibdi.9
@@ -1,4 +1,4 @@
-.Dd August 8, 2026
+.Dd September 11, 2026
.Dt IFLIBDI 9
.Os
.Sh NAME
@@ -92,6 +92,10 @@
.Fo iflib_init_failed
.Fa "if_ctx_t ctx"
.Fc
+.Ft bool
+.Fo iflib_is_running
+.Fa "if_ctx_t ctx"
+.Fc
.Ft void
.Fo iflib_add_int_delay_sysctl
.Fa "if_ctx_t ctx"
@@ -260,6 +264,29 @@
.Dv IFF_DRV_RUNNING
clear and does not enable interrupts or periodic timers.
Output remains blocked so explicitly scheduled admin recovery work can run.
+.It Fn iflib_is_running
+Return an atomic snapshot of whether iflib admits software traffic to its
+queues.
+This function may be called from an interrupt filter without acquiring an
+iflib lock.
+Admission opens after successful driver initialization and receive-buffer
+setup, before enabling interrupts, and closes before stop or when the watchdog
+requests recovery.
+It remains closed after failed initialization.
+.Pp
+This is neither the physical link state nor proof that queue DMA has stopped.
+In particular, admission closes before deferred watchdog recovery stops the
+device.
+The snapshot does not hold a reference to the context or wait for existing
+queue users; callers must retain their normal lifetime and queue
+synchronization.
+Administrative and firmware recovery work may still be needed while admission
+is closed.
+.Pp
+Drivers should use this accessor instead of reading
+.Dv IFF_DRV_RUNNING
+for software run-state checks, and must not modify the driver flags.
+Iflib continues to publish the legacy driver flags for network-stack consumers.
.It Fn iflib_add_int_delay_sysctl
Modifies settings to user defined values for a given set of variables.
.El
Index: sys/net/iflib.h
===================================================================
--- sys/net/iflib.h
+++ sys/net/iflib.h
@@ -436,6 +436,13 @@
if_t iflib_get_ifp(if_ctx_t ctx);
+/*
+ * Lockless software admission snapshot. This neither pins the context nor
+ * establishes that queue DMA has stopped; callers retain their usual lifetime
+ * and queue synchronization requirements.
+ */
+bool iflib_is_running(if_ctx_t ctx);
+
struct ifmedia *iflib_get_media(if_ctx_t ctx);
if_softc_ctx_t iflib_get_softc_ctx(if_ctx_t ctx);
Index: sys/net/iflib.c
===================================================================
--- sys/net/iflib.c
+++ sys/net/iflib.c
@@ -149,9 +149,9 @@
*
* Only STOPPED establishes that the device can no longer access the mappings;
* a failed initialization can leave queues active. IFF_UP separately records
- * administrative intent. Existing datapath users still use IFF_DRV_RUNNING,
- * but clearing that flag does not establish quiescence: the watchdog clears
- * it before the admin task stops the hardware. Use this state for lifecycle
+ * administrative intent. ifc_running separately gates software traffic,
+ * but clearing it does not establish quiescence: the watchdog closes that
+ * gate before the admin task stops the hardware. Use this state for lifecycle
* decisions under ifc_ctx_sx, not as an unlocked datapath admission check.
*/
enum iflib_datapath_state {
@@ -210,6 +210,8 @@
uint32_t ifc_flags;
enum iflib_datapath_state ifc_datapath_state;
enum iflib_pm_state ifc_pm_state;
+ /* Atomic software admission snapshot, not proof of DMA quiescence. */
+ u_int ifc_running;
uint32_t ifc_max_fl_buf_size;
uint32_t ifc_rx_mbuf_sz;
@@ -287,6 +289,13 @@
return (ctx->ifc_ifp);
}
+bool
+iflib_is_running(if_ctx_t ctx)
+{
+
+ return (atomic_load_acq_int(&ctx->ifc_running) != 0);
+}
+
struct ifmedia *
iflib_get_media(if_ctx_t ctx)
{
@@ -560,7 +569,7 @@
#define MAX_SINGLE_PACKET_FRACTION 12
#define IF_BAD_DMA ((bus_addr_t)-1)
-#define CTX_ACTIVE(ctx) ((if_getdrvflags((ctx)->ifc_ifp) & IFF_DRV_RUNNING))
+#define CTX_ACTIVE(ctx) iflib_is_running(ctx)
#define CTX_LOCK_INIT(_sc) sx_init(&(_sc)->ifc_ctx_sx, "iflib ctx lock")
#define CTX_LOCK(ctx) sx_xlock(&(ctx)->ifc_ctx_sx)
@@ -689,13 +698,13 @@
&iflib_fl_refills_large, 0, "# large refills");
static int iflib_txq_drain_flushing;
-static int iflib_txq_drain_oactive;
+static int iflib_txq_drain_stopped;
static int iflib_txq_drain_notready;
SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_flushing, CTLFLAG_RD,
&iflib_txq_drain_flushing, 0, "# drain flushes");
-SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_oactive, CTLFLAG_RD,
- &iflib_txq_drain_oactive, 0, "# drain oactives");
+SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_stopped, CTLFLAG_RD,
+ &iflib_txq_drain_stopped, 0, "# drains interrupted by stop");
SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_notready, CTLFLAG_RD,
&iflib_txq_drain_notready, 0, "# drain notready");
@@ -746,7 +755,7 @@
{
iflib_tx_seen = iflib_tx_sent = iflib_tx_encap = iflib_rx_allocs =
iflib_fl_refills = iflib_fl_refills_large = iflib_tx_frees =
- iflib_txq_drain_flushing = iflib_txq_drain_oactive =
+ iflib_txq_drain_flushing = iflib_txq_drain_stopped =
iflib_txq_drain_notready =
iflib_encap_load_mbuf_fail = iflib_encap_pad_mbuf_fail =
iflib_encap_txq_avail_fail = iflib_encap_txd_encap_fail =
@@ -2478,6 +2487,28 @@
}
}
+/*
+ * Serialize admission changes and publication of the legacy driver flags.
+ * Opening admission publishes queue setup to lockless readers before device
+ * interrupts are enabled. Closing it does not wait for existing users:
+ * queue locks, task drains and the driver stop contract still apply.
+ */
+static void
+iflib_set_running(if_ctx_t ctx, bool running)
+{
+
+ mtx_assert(&ctx->ifc_state_mtx, MA_OWNED);
+ if (running) {
+ if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_RUNNING,
+ IFF_DRV_OACTIVE);
+ atomic_store_rel_int(&ctx->ifc_running, 1);
+ } else {
+ atomic_store_rel_int(&ctx->ifc_running, 0);
+ if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE,
+ IFF_DRV_RUNNING);
+ }
+}
+
/*
* Timer routine
*/
@@ -2489,7 +2520,7 @@
if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
uint64_t this_tick = ticks;
- if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING))
+ if (!iflib_is_running(ctx))
return;
/*
@@ -2571,8 +2602,7 @@
txq->ift_id, TXQ_AVAIL(txq),
txq->ift_pidx);
STATE_LOCK(ctx);
- if_setdrvflagbits(ctx->ifc_ifp,
- IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
+ iflib_set_running(ctx, false);
ctx->ifc_flags |=
(IFC_DO_WATCHDOG | IFC_DO_RESET);
iflib_admin_intr_deferred(ctx);
@@ -2589,7 +2619,7 @@
GROUPTASK_ENQUEUE(&txq->ift_task);
sctx->isc_pause_frames = 0;
- if (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)
+ if (iflib_is_running(ctx))
callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer,
txq, txq->ift_timer.c_cpu);
}
@@ -2643,7 +2673,9 @@
("iflib init from datapath state %d", ctx->ifc_datapath_state));
ctx->ifc_datapath_state = IFLIB_DP_STARTING;
- if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
+ STATE_LOCK(ctx);
+ iflib_set_running(ctx, false);
+ STATE_UNLOCK(ctx);
IFDI_INTR_DISABLE(ctx);
/*
@@ -2722,7 +2754,9 @@
}
}
}
- if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
+ STATE_LOCK(ctx);
+ iflib_set_running(ctx, true);
+ STATE_UNLOCK(ctx);
IFDI_INTR_ENABLE(ctx);
txq = ctx->ifc_txqs;
for (i = 0; i < scctx->isc_ntxqsets; i++, txq++)
@@ -2796,7 +2830,9 @@
stop_hardware = ctx->ifc_datapath_state != IFLIB_DP_STOPPED;
/* Tell the stack that the interface is no longer active */
- if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
+ STATE_LOCK(ctx);
+ iflib_set_running(ctx, false);
+ STATE_UNLOCK(ctx);
if (stop_hardware) {
ctx->ifc_datapath_state = IFLIB_DP_STOPPING;
@@ -4096,8 +4132,7 @@
int mcast_sent, pkt_sent, reclaimed;
bool do_prefetch, rang, ring;
- if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING) ||
- !LINK_ACTIVE(ctx))) {
+ if (__predict_false(!iflib_is_running(ctx) || !LINK_ACTIVE(ctx))) {
DBG_COUNTER_INC(txq_drain_notready);
return (0);
}
@@ -4118,11 +4153,11 @@
return (avail);
}
- if (__predict_false(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE)) {
+ if (__predict_false(!iflib_is_running(ctx))) {
CALLOUT_LOCK(txq);
callout_stop(&txq->ift_timer);
CALLOUT_UNLOCK(txq);
- DBG_COUNTER_INC(txq_drain_oactive);
+ DBG_COUNTER_INC(txq_drain_stopped);
return (0);
}
@@ -4166,7 +4201,7 @@
DBG_COUNTER_INC(tx_sent);
mcast_sent += !!(m->m_flags & M_MCAST);
- if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)))
+ if (__predict_false(!iflib_is_running(ctx)))
break;
ETHER_BPF_MTAP(ifp, m);
rang = iflib_txd_db_check(txq, false);
@@ -4237,13 +4272,15 @@
{
iflib_txq_t txq = context;
if_ctx_t ctx = txq->ift_ctx;
+#if defined(DEV_NETMAP) || defined(ALTQ)
if_t ifp = ctx->ifc_ifp;
+#endif
int abdicate = ctx->ifc_sysctl_tx_abdicate;
#ifdef IFLIB_DIAGNOSTICS
txq->ift_cpu_exec_count[curcpu]++;
#endif
- if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
+ if (!iflib_is_running(ctx))
return;
#ifdef DEV_NETMAP
if ((if_getcapenable(ifp) & IFCAP_NETMAP) &&
@@ -4293,7 +4330,7 @@
rxq->ifr_cpu_exec_count[curcpu]++;
#endif
DBG_COUNTER_INC(task_fn_rxs);
- if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)))
+ if (__predict_false(!iflib_is_running(ctx)))
return;
#ifdef DEV_NETMAP
nmirq = netmap_rx_irq(ctx->ifc_ifp, rxq->ifr_id, &work);
@@ -4316,7 +4353,7 @@
IFDI_RX_QUEUE_INTR_ENABLE(ctx, rxq->ifr_id);
DBG_COUNTER_INC(rx_intr_enables);
}
- if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)))
+ if (__predict_false(!iflib_is_running(ctx)))
return;
if (more & IFLIB_RXEOF_MORE)
@@ -4395,12 +4432,10 @@
if (iflib_in_detach(ctx))
return;
- if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) &&
- !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
- return;
-
CTX_LOCK(ctx);
- if (ctx->ifc_pm_state != IFLIB_PM_ACTIVE) {
+ if (ctx->ifc_pm_state != IFLIB_PM_ACTIVE ||
+ (!iflib_is_running(ctx) &&
+ !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))) {
CTX_UNLOCK(ctx);
return;
}
@@ -4459,7 +4494,7 @@
int err, qidx;
int abdicate;
- if (__predict_false((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0 || !LINK_ACTIVE(ctx))) {
+ if (__predict_false(!iflib_is_running(ctx) || !LINK_ACTIVE(ctx))) {
DBG_COUNTER_INC(tx_frees);
m_freem(m);
return (ENETDOWN);
@@ -4665,7 +4700,7 @@
*/
if (avoid_reset) {
if_setflagbits(ifp, IFF_UP, 0);
- if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
+ if (!iflib_is_running(ctx))
reinit = 1;
#ifdef INET
if (!(if_getflags(ifp) & IFF_NOARP))
@@ -4702,7 +4737,7 @@
case SIOCSIFFLAGS:
CTX_LOCK(ctx);
if (if_getflags(ifp) & IFF_UP) {
- if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
+ if (iflib_is_running(ctx)) {
if ((if_getflags(ifp) ^ ctx->ifc_if_flags) &
(IFF_PROMISC | IFF_ALLMULTI)) {
CTX_UNLOCK(ctx);
@@ -4720,13 +4755,13 @@
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
- if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
- CTX_LOCK(ctx);
+ CTX_LOCK(ctx);
+ if (iflib_is_running(ctx)) {
IFDI_INTR_DISABLE(ctx);
IFDI_MULTI_SET(ctx);
IFDI_INTR_ENABLE(ctx);
- CTX_UNLOCK(ctx);
}
+ CTX_UNLOCK(ctx);
break;
case SIOCSIFMEDIA:
CTX_LOCK(ctx);
@@ -5929,7 +5964,9 @@
ctx->ifc_pm_state = IFLIB_PM_ACTIVE;
if ((if_getflags(ifp) & IFF_UP) == 0) {
- if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
+ STATE_LOCK(ctx);
+ iflib_set_running(ctx, false);
+ STATE_UNLOCK(ctx);
return (0);
}
@@ -6064,10 +6101,10 @@
/*
* Drivers which change the PF queue layout need the complete iflib
* stop/init sequence around their IOV callback. Administrative state
- * and IFF_DRV_RUNNING do not establish that the queues are stopped:
+ * and software admission do not establish DMA quiescence:
* failed initialization or a pending watchdog reset can leave DMA
* active. Let iflib_stop() decide whether hardware needs quiescing,
- * and preserve administrative state across the layout change.
+ * and preserve administrative intent across the layout change.
*/
restart = (if_getflags(ifp) & IFF_UP) != 0;
iflib_stop(ctx);
@@ -6098,9 +6135,9 @@
CTX_LOCK(ctx);
/*
- * RUNNING can be clear while a watchdog reset is pending but the
- * hardware is still live. Always stop before the driver changes its
- * queue layout, and use IFF_UP only to preserve administrative state.
+ * Software admission can be closed while a watchdog reset is pending
+ * but the hardware is still live. Always stop before the driver changes
+ * its queue layout, and use IFF_UP only to preserve administrative intent.
*/
restart = (if_getflags(ctx->ifc_ifp) & IFF_UP) != 0;
iflib_stop(ctx);
@@ -7733,8 +7770,7 @@
int pkt_sent = 0;
ctx = if_getsoftc(ifp);
- if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
- IFF_DRV_RUNNING)
+ if (!iflib_is_running(ctx))
return (EBUSY);
txq = &ctx->ifc_txqs[0];
@@ -7756,8 +7792,7 @@
ctx = if_getsoftc(ifp);
scctx = &ctx->ifc_softc_ctx;
- if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
- IFF_DRV_RUNNING)
+ if (!iflib_is_running(ctx))
return (EBUSY);
txq = &ctx->ifc_txqs[0];
@@ -7795,8 +7830,7 @@
ctx = if_getsoftc(ifp);
- if (__predict_false((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0
- || !LINK_ACTIVE(ctx))) {
+ if (__predict_false(!iflib_is_running(ctx) || !LINK_ACTIVE(ctx))) {
DBG_COUNTER_INC(tx_frees);
m_freem(m);
return (ENETDOWN);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Sep 12, 10:42 PM (9 m, 54 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38823100
Default Alt Text
D59598.diff (13 KB)
Attached To
Mode
D59598: iflib: Separate software admission from legacy driver flags
Attached
Detach File
Event Timeline
Log In to Comment