git: 01409400eb11 - stable/12 - vmxnet3: skip zero-length descriptor in the middle of a packet

From: Andriy Gapon <avg_at_FreeBSD.org>
Date: Mon, 27 Dec 2021 12:01:45 UTC
The branch stable/12 has been updated by avg:

URL: https://cgit.FreeBSD.org/src/commit/?id=01409400eb118d1275861c9072b7a25770d82d90

commit 01409400eb118d1275861c9072b7a25770d82d90
Author:     Andriy Gapon <avg@FreeBSD.org>
AuthorDate: 2021-12-06 07:59:28 +0000
Commit:     Andriy Gapon <avg@FreeBSD.org>
CommitDate: 2021-12-27 12:01:26 +0000

    vmxnet3: skip zero-length descriptor in the middle of a packet
    
    Passing up such descriptors to iflib is obviously wasteful.
    But the main conern is that we may overrun iri_frags array because of
    them.  That's been observed in practice.
    
    Also, assert that the number of fragments / descriptors / segments is
    less than IFLIB_MAX_RX_SEGS.
    
    Sponsored by:   Panzura LLC
    
    (cherry picked from commit 9c612a5d0af17021abc6e1bb2a8baa5a4c97d05f)
---
 sys/dev/vmware/vmxnet3/if_vmx.c    | 29 +++++++++++++++++------------
 sys/dev/vmware/vmxnet3/if_vmxvar.h |  1 +
 2 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/sys/dev/vmware/vmxnet3/if_vmx.c b/sys/dev/vmware/vmxnet3/if_vmx.c
index b3cddcbc879f..cf2a4d8bf086 100644
--- a/sys/dev/vmware/vmxnet3/if_vmx.c
+++ b/sys/dev/vmware/vmxnet3/if_vmx.c
@@ -1505,8 +1505,6 @@ vmxnet3_isc_rxd_pkt_get(void *vsc, if_rxd_info_t ri)
 	struct vmxnet3_rxqueue *rxq;
 	struct vmxnet3_comp_ring *rxc;
 	struct vmxnet3_rxcompdesc *rxcd;
-	struct vmxnet3_rxring *rxr;
-	struct vmxnet3_rxdesc *rxd;
 	if_rxd_frag_t frag;
 	int cqidx;
 	uint16_t total_len;
@@ -1606,16 +1604,19 @@ vmxnet3_isc_rxd_pkt_get(void *vsc, if_rxd_info_t ri)
 		rxcd = &rxc->vxcr_u.rxcd[cqidx];
 		KASSERT(rxcd->gen == rxc->vxcr_gen,
 		    ("%s: generation mismatch", __func__));
-		flid = (rxcd->qid >= scctx->isc_nrxqsets) ? 1 : 0;
-		rxr = &rxq->vxrxq_cmd_ring[flid];
-		rxd = &rxr->vxrxr_rxd[rxcd->rxd_idx];
-
-		frag = &ri->iri_frags[nfrags];
-		frag->irf_flid = flid;
-		frag->irf_idx = rxcd->rxd_idx;
-		frag->irf_len = rxcd->len;
-		total_len += rxcd->len;
-		nfrags++;
+		KASSERT(nfrags < IFLIB_MAX_RX_SEGS,
+		    ("%s: too many fragments", __func__));
+		if (__predict_true(rxcd->len != 0)) {
+			frag = &ri->iri_frags[nfrags];
+			flid = (rxcd->qid >= scctx->isc_nrxqsets) ? 1 : 0;
+			frag->irf_flid = flid;
+			frag->irf_idx = rxcd->rxd_idx;
+			frag->irf_len = rxcd->len;
+			total_len += rxcd->len;
+			nfrags++;
+		} else {
+			rxc->vcxr_zero_length_frag++;
+		}
 		if (++cqidx == rxc->vxcr_ndesc) {
 			cqidx = 0;
 			rxc->vxcr_gen ^= 1;
@@ -1887,6 +1888,7 @@ vmxnet3_rxinit(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rxq)
 	rxc->vxcr_next = 0;
 	rxc->vxcr_gen = VMXNET3_INIT_GEN;
 	rxc->vxcr_zero_length = 0;
+	rxc->vcxr_zero_length_frag = 0;
 	rxc->vxcr_pkt_errors = 0;
 	/*
 	 * iflib has zeroed out the descriptor array during the prior attach
@@ -2370,6 +2372,9 @@ vmxnet3_setup_debug_sysctl(struct vmxnet3_softc *sc,
 		    &rxq->vxrxq_comp_ring.vxcr_gen, 0, "");
 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_zero_length", CTLFLAG_RD,
 		    &rxq->vxrxq_comp_ring.vxcr_zero_length, 0, "");
+		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_zero_length_frag",
+		    CTLFLAG_RD, &rxq->vxrxq_comp_ring.vcxr_zero_length_frag,
+		    0, "");
 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_pkt_errors", CTLFLAG_RD,
 		    &rxq->vxrxq_comp_ring.vxcr_pkt_errors, 0, "");
 	}
diff --git a/sys/dev/vmware/vmxnet3/if_vmxvar.h b/sys/dev/vmware/vmxnet3/if_vmxvar.h
index e39b552ab8cf..9811ae42534d 100644
--- a/sys/dev/vmware/vmxnet3/if_vmxvar.h
+++ b/sys/dev/vmware/vmxnet3/if_vmxvar.h
@@ -81,6 +81,7 @@ struct vmxnet3_comp_ring {
 	int			 vxcr_gen;
 	bus_addr_t		 vxcr_paddr;
 	uint64_t		 vxcr_zero_length;
+	uint64_t		 vcxr_zero_length_frag;
 	uint64_t		 vxcr_pkt_errors;
 };