On Mon, 26 Oct 2026 21:21:23 +0000
Tathagat Priyadarshi <[email protected]> wrote:
> This series fixes error handling in the MANA transmit burst and adds
> hardware TCP segmentation offload (TSO).
>
> Patch 1 drops a packet that cannot be sent, counting it in stats.errors,
> instead of skipping or stalling on it, so rte_eth_tx_burst() keeps
> returning a contiguous prefix and a short return means only a full ring.
> It also bounds the segment count by the size of the SGL array.
>
> Patch 2 adds hardware TSO for IPv4 and IPv6 TCP packets.
>
> Testing on Azure Standard_D8ds_v6 (kernel 6.8.0-1067-azure, MANA PCI
> 7870:00:00.0; the driver reports no firmware version), two VMs on one
> subnet:
> - VM A ran testpmd txonly, modified locally to emit TCP packets with
> RTE_MBUF_F_TX_TCP_SEG set (not part of this series), after
> "csum set ip hw 0", "csum set tcp hw 0" and "tso set 1460 0".
> - VM B captured the frames with tcpdump on its kernel interface, GRO off.
> - A 4000-byte IPv4 packet in a single mbuf, in mbufs with a header-only
> first segment, and in mbufs with payload in the first segment, each
> arrived as 1514, 1514 and 1080 byte frames with consecutive TCP
> sequence numbers, per-segment IP IDs and valid IP and TCP checksums.
> - Plain UDP with "tso set 0" was unaffected.
> IPv6 TSO was not tested.
>
> v2:
> - Patch 1:
> * Drop unsendable packets and return a separate consumed count instead
> of breaking out of the burst; break only when the ring is full.
> * Move the MAX_SGL_ENTRIES_FOR_TRANSMIT check here from patch 2, limit
> nb_seg_max and nb_mtu_seg_max to it, and add Fixes and Cc stable.
> - Patch 2:
> * Use the drop path for all per-packet TSO failures.
> * Honour the TCP checksum implied by RTE_MBUF_F_TX_TCP_SEG when the
> packet is sent unsegmented.
> * Bound the TSO segment walk and check the SGE count against the
> expected one, instead of the unreachable check in the loop.
> * Move GDMA_WR_OOB_IN_SGL and GDMA_WR_PAD_BY_SGE0 next to
> struct gdma_work_request.
> * Document the extra SGE in mana.rst, add a release note, and rewrite
> the commit message.
>
> With the drop-and-continue path, CQE suppression is back to the original
> behavior where only an uncompleted final packet of a burst may wait for a
> subsequent burst to generate a CQE.
>
> Tathagat Priyadarshi (2):
> net/mana: fix transmit burst error handling
> net/mana: add hardware TSO support
>
> doc/guides/nics/features/mana.ini | 1 +
> doc/guides/nics/mana.rst | 8 ++
> doc/guides/rel_notes/release_26_11.rst | 4 +
> drivers/net/mana/gdma.c | 5 +
> drivers/net/mana/mana.c | 4 +-
> drivers/net/mana/mana.h | 6 +-
> drivers/net/mana/tx.c | 191 +++++++++++++++++++++----
> 7 files changed, 186 insertions(+), 33 deletions(-)
>
AI review still turning up errors here.
Review: [PATCH v2 0/2] net/mana: tx error handling and TSO
Patch 1/2 is a good fix. Patch 2/2 has two hardware field width
truncations and a checksum bug in the new non-TSO fallback.
[PATCH v2 1/2] net/mana: fix transmit burst error handling
Info
Dropping a packet now happens mid-burst, after the previous WQE may
have been posted with suppress_tx_CQE_generation set (the decision
is made on pkt_idx + 1 < nb_pkts). If every remaining packet in the
burst is dropped, the last posted WQE has no CQE and its mbufs (and
any suppressed ones before it) are not reclaimed until a later burst
posts another WQE. Same for the post-failure break and the 32-bit
wqe_count break. Pre-existing, not a blocker here, but worth a
follow-up: decide suppression after validation of the next packet,
or never suppress the last WQE before ringing the doorbell.
[PATCH v2 2/2] net/mana: add hardware TSO support
Error
Non-TSO fallback computes the wrong pseudo-header checksum.
The fallback branch is entered for TCP_SEG packets with
tso_segsz == 0 or no payload, and passes m_pkt->ol_flags (with
RTE_MBUF_F_TX_TCP_SEG still set) to rte_ipv4_phdr_cksum() /
rte_ipv6_phdr_cksum(). Those helpers use length 0 when TCP_SEG is
set, so the seed is wrong for an unsegmented frame and the hardware
emits a bad TCP checksum. Mask the flag:
uint64_t ol = m_pkt->ol_flags & ~RTE_MBUF_F_TX_TCP_SEG;
...
tcp_hdr->cksum = rte_ipv4_phdr_cksum(ip_hdr, ol);
Also, TCP_SEG with tso_segsz == 0 or l4_len == 0 is invalid input
per the mbuf API. With gso_hs == 0 the fallback writes cksum at
l2_len + l3_len == 0, corrupting the Ethernet header. Drop these
instead of sending them:
if (m_pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
if (unlikely(m_pkt->tso_segsz == 0 ||
m_pkt->l4_len == 0 ||
m_pkt->data_len < gso_hs))
goto drop;
is_tso = m_pkt->pkt_len > gso_hs;
}
Error
client_data_unit is a 14-bit field in struct gdma_wqe_dma_oob, but
tso_segsz is uint16_t. Any tso_segsz >= 16384 is silently
truncated; 16384 becomes 0 == NOT_USING_CLIENT_DATA_UNIT and a
64KB frame is handed to the wire unsegmented. Reject it:
#define MANA_TSO_MAX_SEGSZ ((1u << 14) - 1)
if (unlikely(m_pkt->tso_segsz > MANA_TSO_MAX_SEGSZ))
goto drop;
Error
last_v_bytes is an 8-bit field, but gso_hs is
l2_len + l3_len + l4_len and can exceed 255 (IPv6 extension headers,
VLAN plus TCP options). gdma.c writes sgl[0].size into it and the
value wraps. Drop TSO packets with gso_hs > UINT8_MAX, or state the
real hardware header limit and check against that.
Warning
The extra SGE for a TSO header split is documented as a limitation
but not reflected in dev_info. tx_desc_lim.nb_seg_max is the TSO
limit (nb_mtu_seg_max is the non-TSO one), so applications and
rte_gso trusting it build packets that are then dropped. Advertise
the real limit and drop the mana.rst paragraph:
uint16_t max_sge = RTE_MIN(priv->max_send_sge,
MAX_SGL_ENTRIES_FOR_TRANSMIT);
dev_info->tx_desc_lim.nb_seg_max = max_sge - 1;
dev_info->tx_desc_lim.nb_mtu_seg_max = max_sge;
Warning
No bounds on the TSO request beyond the above. What is the maximum
payload (pkt_len - gso_hs) and the minimum MSS the adapter accepts?
Check both in the TSO validation and drop out-of-range packets,
rather than leaving it to the device.
Info
The TSO and non-TSO SGL loops duplicate the MR lookup and SGE fill.
One loop with a start offset on the first segment covers both:
uint32_t off = 0;
num_sge = 0;
if (is_tso) {
/* SGE0: headers only */
if (fill_sge(&sgl, num_sge++, m_pkt, 0, gso_hs, mr))
goto drop;
off = gso_hs;
}
for (m_seg = m_pkt; m_seg; m_seg = m_seg->next, off = 0) {
if (m_seg->data_len == off)
continue;
if (fill_sge(&sgl, num_sge++, m_seg, off,
m_seg->data_len - off, mr))
goto drop;
}
With expected_sge already checked against the array size, the
m_seg != NULL || num_sge != expected_sge re-check goes away.
Info
Header rewriting (total_length, hdr_checksum, cksum) in tx_burst
modifies data the application may share (refcnt > 1, external
buffers). The existing TCP_CKSUM path does the same, so not new,
but the conventional place is tx_pkt_prepare. A mana_tx_prepare()
using rte_validate_tx_offload() and rte_net_intel_cksum_prepare()
would also move the segment-count checks out of the fast path.
Info
Commit message: drop "allowing transmit bursts of up to 64KB TCP
packets at wire speed". The test log is useful, but belongs below
the "---" line, not in the permanent history.