Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 19 Jul 2026 16:49:11 +0000
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Cc:        Nick Price <nick@spun.io>
Subject:   git: 73cd4048807d - main - aq(4): drop errored RX frames instead of resetting the interface
Message-ID:  <6a5d0007.31895.7826cc7b@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by adrian:

URL: https://cgit.FreeBSD.org/src/commit/?id=73cd4048807dc0b3a5329bfc9a80ea4bf2d975fd

commit 73cd4048807dc0b3a5329bfc9a80ea4bf2d975fd
Author:     Nick Price <nick@spun.io>
AuthorDate: 2026-07-19 16:40:46 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2026-07-19 16:40:46 +0000

    aq(4): drop errored RX frames instead of resetting the interface
    
    aq_isc_rxd_pkt_get() returned EBADMSG when a receive descriptor's
    MAC/receive-error bit (rx_stat bit 0) was set.  iflib treats any error
    from isc_rxd_pkt_get() as a fatal ring fault and answers with
    IFC_DO_RESET -- a full interface reinitialization.  A per-frame receive
    error is not a ring fault: on a marginal link or cable the Atlantic
    delivers errored frames continuously, so each one triggered another
    reset and the interface reset-stormed itself into carrying no traffic
    instead of merely dropping the bad frames.
    
    The Atlantic delivers errored frames to the host by design (Linux drops
    them in software via buff->is_error), and iflib offers no per-frame
    error return that isn't a reset.  Follow the vmxnet3 model: on a receive
    error zero the fragment lengths and return success.  iflib then discards
    the packet (assemble_segments() excludes zero-length fragments) while
    still recycling the descriptors through the refill path -- no reset.
    Also drop frames flagged with an RX-DMA fault (rdm_err), not just the
    MAC-error bit; and keep iri_len non-zero on that drop path, since iflib
    asserts iri_len != 0.
    
    The genuinely structural errors -- more segments than isc_rx_nsegments,
    or a pkt_len inconsistent with the descriptor count -- still return
    EBADMSG, since those indicate a confused ring where a reset is the right
    recovery.
    
    Reviewed by:    adrian
    Differential Revision:  https://reviews.freebsd.org/D58136
---
 sys/dev/aq/aq_ring.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/sys/dev/aq/aq_ring.c b/sys/dev/aq/aq_ring.c
index 8307fb0b3474..6afec86c63bc 100644
--- a/sys/dev/aq/aq_ring.c
+++ b/sys/dev/aq/aq_ring.c
@@ -333,11 +333,13 @@ aq_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
 	if_t ifp;
 	int cidx, rc = 0, i;
 	size_t len, total_len;
+	bool is_error = false;
 
 	AQ_DBG_ENTERA("[%d] start=%d", ring->index, ri->iri_cidx);
 	cidx = ri->iri_cidx;
 	ifp = iflib_get_ifp(aq_dev->ctx);
 	i = 0;
+	total_len = 0;
 
 	do {
 		if (i >= aq_dev->sctx->isc_rx_nsegments)
@@ -348,11 +350,15 @@ aq_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
 		trace_aq_rx_descr(ring->index, cidx,
 		    (volatile uint64_t *)rx_desc);
 
-		if ((rx_desc->wb.rx_stat & BIT(0)) != 0)
-			goto rx_err;
+		/* MAC error (rx_stat) or RX-DMA fault (rdm_err) -> drop. */
+		if ((rx_desc->wb.rx_stat & BIT(0)) != 0 || rx_desc->wb.rdm_err)
+			is_error = true;
 
 		if (!rx_desc->wb.eop) {
 			len = ring->rx_buf_size;
+		} else if (is_error) {
+			total_len = le32toh(rx_desc->wb.pkt_len);
+			len = 0;
 		} else {
 			total_len = le32toh(rx_desc->wb.pkt_len);
 			if (total_len < (size_t)i * ring->rx_buf_size)
@@ -375,6 +381,19 @@ aq_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
 		cidx = aq_next(cidx, ring->rx_size - 1);
 	} while (!rx_desc->wb.eop);
 
+	ri->iri_nfrags = i;
+	ri->iri_len = total_len;
+
+	/* Per-frame RX error: drop (zero-length frags), don't reset. */
+	if (is_error) {
+		counter_u64_add(ring->stats.rx_err, 1);
+		for (i = 0; i < ri->iri_nfrags; i++)
+			ri->iri_frags[i].irf_len = 0;
+		if (ri->iri_len == 0)
+			ri->iri_len = 1;	/* iflib asserts iri_len != 0 */
+		goto exit;
+	}
+
 	if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) {
 		aq_rx_set_cso_flags(rx_desc, ri);
 	}
@@ -383,9 +402,6 @@ aq_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
 		ri->iri_flowid = le32toh(rx_desc->wb.rss_hash);
 	}
 
-	ri->iri_len = total_len;
-	ri->iri_nfrags = i;
-
 	counter_u64_add(ring->stats.rx_bytes, total_len);
 	counter_u64_add(ring->stats.rx_pkts, 1);
 	goto exit;


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a5d0007.31895.7826cc7b>