Page MenuHomeFreeBSD

D59598.diff
No OneTemporary

D59598.diff

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

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)

Event Timeline