net/gve: fix DQO Tx queue stalls
Re: [PATCH v4 07/10] net/gve: export Tx drop counters in xstats
In reply to Tathagat PriyadarshiQuoted 8 lines · Tathagat Priyadarshi
too_many_descsis counted but missing from the Tx xstats table, so it cannot be read. Export it together withinvalid_mbufs.Fixes f4a70b449bfa ("net/gve: add DQO Tx descriptor limit")Signed-off-by Tathagat Priyadarshi <[email protected]>
Quoted 18 lines
--- drivers/net/gve/gve_ethdev.c | 2 ++ 1 file changed, 2 insertions(+)drivers/net/gve/gve_ethdev.c +2
-1@@ -1042,6 +1042,8 @@ static const struct gve_xstats_name_offset tx_xstats_name_offset[] = { { "packets", TX_QUEUE_STATS_OFFSET(packets) }, { "bytes", TX_QUEUE_STATS_OFFSET(bytes) }, { "errors", TX_QUEUE_STATS_OFFSET(errors) }, + { "too_many_descs", TX_QUEUE_STATS_OFFSET(too_many_descs) }, + { "invalid_mbufs", TX_QUEUE_STATS_OFFSET(invalid_mbufs) }, }; static const struct gve_xstats_name_offset rx_xstats_name_offset[] = { --
Quoted 2 lines
2.43.0
Thanks!
Re: [PATCH v4 08/10] net/gve: reject Tx packets that cannot fit in the ring
In reply to Tathagat PriyadarshiQuoted 7 lines · Tathagat Priyadarshi
A TSO packet needing more descriptors than the ring can ever have free fails the ring space check on every burst and blocks the queue. One slot is always reserved, the cacheline overlap margin must stay free, and up to
GVE_TX_MIN_RE_INTERVAL- 1 posted descriptors are not reclaimed until more are posted.
Quoted 6 lines
Drop such packets and count them as
too_many_descs.Fixes 403c671a46b6 ("net/gve: support TSO in DQO RDA")Signed-off-by Tathagat Priyadarshi <[email protected]>
Quoted 52 lines
--- drivers/net/gve/gve_tx_dqo.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)drivers/net/gve/gve_tx_dqo.c +18
-3@@ -123,14 +123,30 @@ gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) {gve_tx_clean_dqo (txq); } +/* Max descriptors a single packet may use. A larger packet can never pass +* gve_can_tx(): one slot is always reserved, the cacheline overlap margin +* must stay free, and up to GVE_TX_MIN_RE_INTERVAL - 1 descriptors posted +* after the last report_event are not reclaimed until more are posted. +*/ +static inline int +gve_tx_max_pkt_descs (const struct gve_tx_queue *txq) +{ +return (int )txq->nb_tx_desc -1 -GVE_TX_MIN_DESC_PREVENT_CACHE_OVERLAP - + (GVE_TX_MIN_RE_INTERVAL -1 ); +} +/* GVE expects at most 10 data descriptors per mtu-sized segment. Beyond this, * the hardware will assume the driver is malicious and stop transmitting * packets altogether. Validate that a packet can be sent to avoid sending * posting descriptors for an invalid packet. */ static inline bool -gve_tx_validate_descs (struct rte_mbuf *tx_pkt,uint16_t nb_descs,bool is_tso) +gve_tx_validate_descs (const struct gve_tx_queue *txq,struct rte_mbuf *tx_pkt, +uint16_t nb_descs,bool is_tso) { +if (nb_descs >gve_tx_max_pkt_descs (txq)) +return false; +if (!is_tso)return nb_descs <=GVE_TX_MAX_DATA_DESCS ;@@ -294,7 +310,7 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) nb_descs += tso;/* Drop packet if it doesn't adhere to hardware limits. */ -if (!gve_tx_validate_descs (tx_pkt, nb_descs, tso)) { +if (!gve_tx_validate_descs (txq, tx_pkt, nb_descs, tso)) { txq->stats.too_many_descs++;rte_pktmbuf_free (tx_pkt);continue ; --2.43.0
Re: [PATCH v4 09/10] net/gve: enforce DQO Tx packet length limits
In reply to Tathagat PriyadarshiQuoted 7 lines · Tathagat Priyadarshi
The device requires non-TSO packets to be 17 to 9728 bytes long, as noted in the Linux driver, but packets of any length are posted. The device treats an out-of-range packet as coming from a malicious
driver: it drops the packet and disables the datapath, stalling all queues.
Quoted 7 lines
Drop such packets in the driver and count them in a new
invalid_pktscounter.Fixes 4022f9999f56 ("net/gve: support basic Tx data path for DQO")Signed-off-by Tathagat Priyadarshi <[email protected]>
Quoted 49 lines
--- drivers/net/gve/base/gve_desc_dqo.h | 2 ++ drivers/net/gve/gve_ethdev.c | 1 + drivers/net/gve/gve_ethdev.h | 1 + drivers/net/gve/gve_tx_dqo.c | 17 +++++++++++++++++ 4 files changed, 21 insertions(+)drivers/net/gve/base/gve_desc_dqo.h +2
-0@@ -12,6 +12,8 @@#define GVE_TX_MAX_HDR_SIZE_DQO 255#define GVE_TX_MIN_TSO_MSS_DQO 88 +#define GVE_TX_MIN_PKT_SIZE_DQO 17 +#define GVE_TX_MAX_PKT_SIZE_DQO 9728/* Basic TX descriptor (DTYPE 0x0C) */ struct gve_tx_pkt_desc_dqo {drivers/net/gve/gve_ethdev.c +1
-0@@ -1044,6 +1044,7 @@ static const struct gve_xstats_name_offset tx_xstats_name_offset[] = { { "errors", TX_QUEUE_STATS_OFFSET(errors) }, { "too_many_descs", TX_QUEUE_STATS_OFFSET(too_many_descs) }, { "invalid_mbufs", TX_QUEUE_STATS_OFFSET(invalid_mbufs) }, + { "invalid_pkts", TX_QUEUE_STATS_OFFSET(invalid_pkts) }, }; static const struct gve_xstats_name_offset rx_xstats_name_offset[] = {drivers/net/gve/gve_ethdev.h +1
-0@@ -115,6 +115,7 @@ struct gve_tx_stats {uint64_t errors;uint64_t too_many_descs;uint64_t invalid_mbufs; +uint64_t invalid_pkts; };struct gve_rx_stats {drivers/net/gve/gve_tx_dqo.c +0
-0
drivers/net/gve/gve_tx_dqo.c gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) { · line 128
Quoted 6 lines
drivers/net/gve/gve_tx_dqo.c +3
-0@@ -123,6 +123,17 @@ gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) {gve_tx_clean_dqo (txq); } +/* Validate packet lengths against the device limits. */ +static inline bool +gve_tx_validate_pkt (const struct rte_mbuf *tx_pkt,bool is_tso)
Minor nit (not worth blocking over, but maybe can be done as the patches are being merged): can this be renamed to gve_tx_validate_pkt_len? This is one step of many in the packet validation pipeline.
Quoted 27 lines
drivers/net/gve/gve_tx_dqo.c +14
-1+{ +if (!is_tso) +return tx_pkt->pkt_len >=GVE_TX_MIN_PKT_SIZE_DQO && + tx_pkt->pkt_len <=GVE_TX_MAX_PKT_SIZE_DQO ; + +return true; +} +/* Max descriptors a single packet may use. A larger packet can never pass * gve_can_tx(): one slot is always reserved, the cacheline overlap margin * must stay free, and up to GVE_TX_MIN_RE_INTERVAL - 1 descriptors posted @@ -306,6 +317,12 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) tso = !!(ol_flags &RTE_MBUF_F_TX_TCP_SEG ); csum = !!(ol_flags &GVE_TX_CKSUM_OFFLOAD_MASK_DQO ); +if (!gve_tx_validate_pkt (tx_pkt, tso)) { + txq->stats.invalid_pkts++; +rte_pktmbuf_free (tx_pkt); +continue ; + } + nb_descs =gve_tx_pkt_nb_data_descs (tx_pkt); nb_descs += tso; --2.43.0
Re: [PATCH v4 10/10] net/gve: enforce DQO TSO header and length limits
In reply to Tathagat PriyadarshiQuoted 13 lines · Tathagat Priyadarshi
TSO packets are not checked against the device limits before use. The device requires an MSS of 88 to 9728 bytes and a payload of at most 262143 bytes, as noted in the Linux driver. A packet outside these limits triggers malicious driver detection, which drops it and disables the datapath, stalling all queues.
The missing checks also break the driver itself: a
tso_segszof 0 divides by zero ingve_tx_validate_descs(), headers longer than 255 bytes are truncated by the 8-bitheader_lenfield, and headers not contained in the first segment givegve_tx_validate_descs()a negative first segment length.
Quoted 8 lines
Drop TSO packets that violate these limits and count them as
invalid_pkts.Fixes 403c671a46b6 ("net/gve: support TSO in DQO RDA")Fixes be8f0eb81f98 ("net/gve: fix DQO TSO descriptor limit")Signed-off-by Tathagat Priyadarshi <[email protected]>
Quoted 49 lines
--- drivers/net/gve/base/gve_desc_dqo.h | 1 + drivers/net/gve/gve_tx_dqo.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-)drivers/net/gve/base/gve_desc_dqo.h +1
-0@@ -14,6 +14,7 @@#define GVE_TX_MIN_TSO_MSS_DQO 88#define GVE_TX_MIN_PKT_SIZE_DQO 17#define GVE_TX_MAX_PKT_SIZE_DQO 9728 +#define GVE_TX_MAX_TSO_LEN_DQO ((256 * 1024) - 1)/* Basic TX descriptor (DTYPE 0x0C) */ struct gve_tx_pkt_desc_dqo {drivers/net/gve/gve_tx_dqo.c +13
-2@@ -127,11 +127,23 @@ gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) {static inline bool gve_tx_validate_pkt (const struct rte_mbuf *tx_pkt,bool is_tso) { +uint32_t headlen; +if (!is_tso)return tx_pkt->pkt_len >=GVE_TX_MIN_PKT_SIZE_DQO && tx_pkt->pkt_len <=GVE_TX_MAX_PKT_SIZE_DQO ; -return true; +/* Headers must be present, fit the context descriptor, and be +* contained in the first segment; the payload must not be empty. +*/ + headlen = tx_pkt->l2_len + tx_pkt->l3_len + tx_pkt->l4_len; +if (tx_pkt->l4_len ==0 || headlen >GVE_TX_MAX_HDR_SIZE_DQO || + tx_pkt->data_len < headlen || tx_pkt->pkt_len <= headlen) +return false; + +return tx_pkt->pkt_len - headlen <=GVE_TX_MAX_TSO_LEN_DQO && + tx_pkt->tso_segsz >=GVE_TX_MIN_TSO_MSS_DQO && + tx_pkt->tso_segsz <=GVE_TX_MAX_PKT_SIZE_DQO ; }/* Max descriptors a single packet may use. A larger packet can never pass -- 2.43.0
v4 cover net/gve: fix DQO Tx queue stalls
This series fixes several ways the gve DQO RDA Tx path can stall or post invalid descriptors: completion handling bugs (1-2), a report event interval that can starve the ring (3), a stray TSO context descriptor when completion tags run out (4), a missing cacheline margin (5), invalid packets blocking the burst (6-8), and missing device length checks (9-10).
v4:
- Rebased on main; v3 no longer applied after 4a543ae8c8 ("net/gve: clean Tx queue directly in DQO") removed txqs next to the field changed in 3/10. No functional changes.
v3:
- Split the series into one fix per patch, per review feedback. The code is the same as v2 except where noted below.
- 1/10, 2/10: v2 1/4, split in two. Kept Joshua's Ack.
- 3/10: v2 2/4 without the declaration reordering
(per Joshua Washington) and without ringing the doorbell on each report event, which is a performance change to be sent separately with numbers (per Stephen Hemminger).
- 4/10: the completion tag reorder from v2 2/4, as its own patch. Fixes tag now points at the commit that made the tag pop fallible.
- 5/10: v2 3/4, unchanged. Kept Joshua's Ack.
- 6/10-10/10: v2 4/4, split:
* Keep too_many_descs and add per-reason invalid_mbufs and invalid_pkts counters instead of a generic dropped_pkts (per Joshua Washington), and export them as xstats (per Stephen Hemminger).
* Count sent packets after writing descriptors instead of subtracting drops (per Joshua Washington).
* Move the length and TSO header checks into gve_tx_validate_pkt(), leaving gve_tx_validate_descs() to descriptor counts, without the declaration moves.
* Reword the TSO length limit (per Stephen Hemminger) and shorten the commit messages.
- Stephen's Reviewed-by on v2 is not carried over because of the rework.
Tathagat Priyadarshi (10):
net/gve: fix DQO descriptor cleaning loop bound net/gve: fix DQO completion queue stall on unknown type net/gve: fix DQO Tx report event interval net/gve: fix stray TSO context descriptor on tag exhaustion net/gve: add cacheline overlap margin to DQO Tx ring net/gve: fix Tx stall on invalid packets
net/gve: export Tx drop counters in xstats net/gve: reject Tx packets that cannot fit in the ring net/gve: enforce DQO Tx packet length limits net/gve: enforce DQO TSO header and length limits
drivers/net/gve/base/gve_desc_dqo.h | 3 + drivers/net/gve/gve_ethdev.c | 3 + drivers/net/gve/gve_ethdev.h | 4 +- drivers/net/gve/gve_tx_dqo.c | 113 +++++++++++++++++++++------- 4 files changed, 96 insertions(+), 27 deletions(-)
Signature · 1 line
2.43.0
PATCH v4 1/10 net/gve: fix DQO descriptor cleaning loop bound
gve_tx_clean_descs_dqo() loops on "while (--nb_descs)", which processes one completion fewer than requested, and none when asked for one.
Use a post-decrement so exactly nb_descs completions are processed.
--- drivers/net/gve/gve_tx_dqo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/gve/gve_tx_dqo.c +1 -1
@@ -119,7 +119,7 @@ gve_tx_clean_dqo(struct gve_tx_queue *txq)static inline void gve_tx_clean_descs_dqo (struct gve_tx_queue *txq,uint16_t nb_descs) { -while (--nb_descs) +while (nb_descs--)gve_tx_clean_dqo (txq); }
Signature · 1 line
2.43.0
PATCH v4 2/10 net/gve: fix DQO completion queue stall on unknown type
In reply to Tathagat PriyadarshiWhen gve_tx_clean_dqo() sees an unknown completion type, it returns without advancing complq_tail. Every later call stops at the same entry, so Tx completions are never processed again.
Log the type and skip the entry.
--- drivers/net/gve/gve_tx_dqo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/gve/gve_tx_dqo.c +2 -2
@@ -105,8 +105,8 @@ gve_tx_clean_dqo(struct gve_tx_queue *txq)PMD_DRV_DP_LOG (DEBUG ,"GVE_COMPL_TYPE_DQO_MISS ignored !!!" );break ;default : -PMD_DRV_DP_LOG (ERR ,"unknown completion type." ); -return ; +PMD_DRV_DP_LOG (ERR ,"unknown completion type %u" , compl_desc->type); +break ; } next++;
Signature · 1 line
2.43.0
PATCH v4 3/10 net/gve: fix DQO Tx report event interval
In reply to Tathagat PriyadarshiA descriptor completion is requested once every 32 packets, and Tx descriptors are only reclaimed on these completions. With multi-segment or TSO packets the ring can fill before 32 packets are posted, so no completion is ever requested and the Tx queue stalls for good.
Request a completion once GVE_TX_MIN_RE_INTERVAL descriptors have been posted since the last one, as the Linux driver does.
--- drivers/net/gve/gve_ethdev.h | 2 +- drivers/net/gve/gve_tx_dqo.c | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-)
drivers/net/gve/gve_ethdev.h +1 -1
@@ -193,7 +193,7 @@ struct gve_tx_queue {uint16_t sw_size;uint8_t cur_gen_bit;uint32_t last_desc_cleaned; -uint16_t re_cnt; +uint16_t last_re_idx;/* Only valid for DQO_RDA queue format */ struct gve_tx_queue *complq;
drivers/net/gve/gve_tx_dqo.c +14 -8
@@ -251,6 +251,8 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)volatile union gve_tx_desc_dqo *txr;volatile union gve_tx_desc_dqo *txd;uint16_t mask = txq->nb_tx_desc -1 ; +uint16_t last_re_interval; +uint16_t last_desc_idx;struct gve_tx_pkt *pkts;struct rte_mbuf *tx_pkt;uint16_t compl_tag;
@@ -328,20 +330,23 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) txd = &txr[(tx_id -1 ) & mask]; txd->pkt.end_of_packet =1 ; +/* Request a descriptor completion once at least +* GVE_TX_MIN_RE_INTERVAL descriptors have been posted +* since the last request. +*/ + last_desc_idx = (tx_id -1 ) & mask; + last_re_interval = (last_desc_idx - txq->last_re_idx) & mask; +if (unlikely (last_re_interval >=GVE_TX_MIN_RE_INTERVAL )) { + txd->pkt.report_event = true; + txq->last_re_idx = last_desc_idx; + } + txq->nb_free -= nb_descs; txq->nb_used += nb_descs; }/* update the tail pointer if any packets were processed */ if (nb_tx >0 ) { -/* Request a descriptor completion on the last descriptor */ - txq->re_cnt += nb_tx; -if (txq->re_cnt >=GVE_TX_MIN_RE_INTERVAL ) { - txd = &txr[(tx_id -1 ) & mask]; - txd->pkt.report_event = true; - txq->re_cnt =0 ; - } -rte_write32 (tx_id, txq->qtx_tail); txq->tx_tail = tx_id;
@@ -442,6 +447,7 @@ gve_reset_tx_ring_state_dqo(struct gve_tx_queue *txq) txq->nb_used =0 ; txq->last_desc_cleaned =0 ; + txq->last_re_idx =0 ; txq->nb_free = txq->nb_tx_desc -1 ; txq->complq_tail =0 ;
Signature · 1 line
2.43.0
PATCH v4 4/10 net/gve: fix stray TSO context descriptor on tag exhaustion
In reply to Tathagat PriyadarshiFor TSO packets, the context descriptor is written and tx_id advanced before a completion tag is allocated. If no tag is available, the burst stops, but when earlier packets in the burst were sent, the tail written at the end of the burst still covers the context descriptor. The device then receives it with no data descriptors behind it, and the slot is never deducted from nb_free.
Allocate the completion tag before writing any descriptor.
--- drivers/net/gve/gve_tx_dqo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/gve/gve_tx_dqo.c +3 -3
@@ -305,15 +305,15 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)break ; } +if (!gve_free_compl_tags_pop (txq, &compl_tag)) +break ; +if (tso) { txd = &txr[tx_id];gve_tx_fill_seg_desc_dqo (txd, tx_pkt); tx_id = (tx_id +1 ) & mask; } -if (!gve_free_compl_tags_pop (txq, &compl_tag)) -break ; - pkts[compl_tag].mbuf = tx_pkt;while (tx_pkt) {/* Skip writing descriptors if mbuf has no data. */
Signature · 1 line
2.43.0
PATCH v4 5/10 net/gve: add cacheline overlap margin to DQO Tx ring
In reply to Tathagat PriyadarshiThe GVNIC DQO hardware DMA engine prefetches descriptors in cacheline units (64 bytes = 4 descriptors of 16 bytes each). When producer tail and consumer head indices share a cacheline, CPU and device DMA memory collisions can occur.
Align with the Linux driver (gve_has_tx_slots_available()) by requiring GVE_TX_MIN_DESC_PREVENT_CACHE_OVERLAP (4 descriptors) headroom when checking descriptor availability before enqueueing packets.
--- drivers/net/gve/gve_tx_dqo.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/net/gve/gve_tx_dqo.c +8 -4
@@ -256,6 +256,7 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)struct gve_tx_pkt *pkts;struct rte_mbuf *tx_pkt;uint16_t compl_tag; +uint16_t req_descs;const char *reason;uint16_t nb_tx =0 ;uint64_t bytes =0 ;
@@ -288,14 +289,17 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) nb_descs =gve_tx_pkt_nb_data_descs (tx_pkt); nb_descs += tso; + req_descs = nb_descs +GVE_TX_MIN_DESC_PREVENT_CACHE_OVERLAP ; -/* Clean if there aren't enough descriptors to send the packet. */ -if (unlikely (!gve_can_tx (txq, nb_descs,1 ))) { +/* Clean if there aren't enough descriptors to send the packet +* while maintaining the cacheline overlap margin. +*/ +if (unlikely (!gve_can_tx (txq, req_descs,1 ))) {int nb_to_clean =RTE_MAX (DQO_TX_MULTIPLIER * txq->rs_thresh, - nb_descs); + (int )req_descs);gve_tx_clean_descs_dqo (txq, nb_to_clean); -if (!gve_can_tx (txq, nb_descs,1 )) +if (!gve_can_tx (txq, req_descs,1 ))break ; }
Signature · 1 line
2.43.0
PATCH v4 6/10 net/gve: fix Tx stall on invalid packets
In reply to Tathagat PriyadarshiWhen a packet fails rte_mbuf_check() or exceeds the descriptor limit, the Tx burst stops at that packet without consuming it. The application retries the same packet, it fails again, and the queue never moves.
Free such packets and continue with the burst. Validate before the ring space check, so that an oversized packet is dropped instead of stopping the burst there. Count rte_mbuf_check() failures in a new invalid_mbufs counter.
--- drivers/net/gve/gve_ethdev.h | 1 + drivers/net/gve/gve_tx_dqo.c | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-)
drivers/net/gve/gve_ethdev.h +1 -0
@@ -114,6 +114,7 @@ struct gve_tx_stats {uint64_t bytes;uint64_t errors;uint64_t too_many_descs; +uint64_t invalid_mbufs; };struct gve_rx_stats {
drivers/net/gve/gve_tx_dqo.c +15 -9
@@ -258,6 +258,7 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)uint16_t compl_tag;uint16_t req_descs;const char *reason; +uint16_t nb_sent =0 ;uint16_t nb_tx =0 ;uint64_t bytes =0 ;uint64_t ol_flags;
@@ -280,7 +281,9 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)if (rte_mbuf_check (tx_pkt, true, &reason)) {PMD_DRV_DP_LOG (DEBUG ,"Invalid mbuf: %s" , reason); -break ; + txq->stats.invalid_mbufs++; +rte_pktmbuf_free (tx_pkt); +continue ; } ol_flags = tx_pkt->ol_flags;
@@ -289,6 +292,14 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) nb_descs =gve_tx_pkt_nb_data_descs (tx_pkt); nb_descs += tso; + +/* Drop packet if it doesn't adhere to hardware limits. */ +if (!gve_tx_validate_descs (tx_pkt, nb_descs, tso)) { + txq->stats.too_many_descs++; +rte_pktmbuf_free (tx_pkt); +continue ; + } + req_descs = nb_descs +GVE_TX_MIN_DESC_PREVENT_CACHE_OVERLAP ;/* Clean if there aren't enough descriptors to send the packet
@@ -303,12 +314,6 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)break ; } -/* Drop packet if it doesn't adhere to hardware limits. */ -if (!gve_tx_validate_descs (tx_pkt, nb_descs, tso)) { - txq->stats.too_many_descs++; -break ; - } -if (!gve_free_compl_tags_pop (txq, &compl_tag))break ;
@@ -347,6 +352,7 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) txq->nb_free -= nb_descs; txq->nb_used += nb_descs; + nb_sent++; }/* update the tail pointer if any packets were processed */
@@ -354,9 +360,9 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)rte_write32 (tx_id, txq->qtx_tail); txq->tx_tail = tx_id; - txq->stats.packets += nb_tx; + txq->stats.packets += nb_sent; txq->stats.bytes += bytes; - txq->stats.errors += nb_pkts - nb_tx; + txq->stats.errors += nb_pkts - nb_sent; }return nb_tx;
Signature · 1 line
2.43.0
PATCH v4 7/10 net/gve: export Tx drop counters in xstats
In reply to Tathagat Priyadarshitoo_many_descs is counted but missing from the Tx xstats table, so it cannot be read. Export it together with invalid_mbufs.
--- drivers/net/gve/gve_ethdev.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/gve/gve_ethdev.c +2 -0
@@ -1042,6 +1042,8 @@ static const struct gve_xstats_name_offset tx_xstats_name_offset[] = { { "packets", TX_QUEUE_STATS_OFFSET(packets) }, { "bytes", TX_QUEUE_STATS_OFFSET(bytes) }, { "errors", TX_QUEUE_STATS_OFFSET(errors) }, + { "too_many_descs", TX_QUEUE_STATS_OFFSET(too_many_descs) }, + { "invalid_mbufs", TX_QUEUE_STATS_OFFSET(invalid_mbufs) }, }; static const struct gve_xstats_name_offset rx_xstats_name_offset[] = {
Signature · 1 line
2.43.0
PATCH v4 8/10 net/gve: reject Tx packets that cannot fit in the ring
In reply to Tathagat PriyadarshiA TSO packet needing more descriptors than the ring can ever have free fails the ring space check on every burst and blocks the queue. One slot is always reserved, the cacheline overlap margin must stay free, and up to GVE_TX_MIN_RE_INTERVAL - 1 posted descriptors are not reclaimed until more are posted.
Drop such packets and count them as too_many_descs.
--- drivers/net/gve/gve_tx_dqo.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
drivers/net/gve/gve_tx_dqo.c +18 -2
@@ -123,14 +123,30 @@ gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) {gve_tx_clean_dqo (txq); } +/* Max descriptors a single packet may use. A larger packet can never pass +* gve_can_tx(): one slot is always reserved, the cacheline overlap margin +* must stay free, and up to GVE_TX_MIN_RE_INTERVAL - 1 descriptors posted +* after the last report_event are not reclaimed until more are posted. +*/ +static inline int +gve_tx_max_pkt_descs (const struct gve_tx_queue *txq) +{ +return (int )txq->nb_tx_desc -1 -GVE_TX_MIN_DESC_PREVENT_CACHE_OVERLAP - + (GVE_TX_MIN_RE_INTERVAL -1 ); +} +/* GVE expects at most 10 data descriptors per mtu-sized segment. Beyond this, * the hardware will assume the driver is malicious and stop transmitting * packets altogether. Validate that a packet can be sent to avoid sending * posting descriptors for an invalid packet. */ static inline bool -gve_tx_validate_descs (struct rte_mbuf *tx_pkt,uint16_t nb_descs,bool is_tso) +gve_tx_validate_descs (const struct gve_tx_queue *txq,struct rte_mbuf *tx_pkt, +uint16_t nb_descs,bool is_tso) { +if (nb_descs >gve_tx_max_pkt_descs (txq)) +return false; +if (!is_tso)return nb_descs <=GVE_TX_MAX_DATA_DESCS ;
@@ -294,7 +310,7 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) nb_descs += tso;/* Drop packet if it doesn't adhere to hardware limits. */ -if (!gve_tx_validate_descs (tx_pkt, nb_descs, tso)) { +if (!gve_tx_validate_descs (txq, tx_pkt, nb_descs, tso)) { txq->stats.too_many_descs++;rte_pktmbuf_free (tx_pkt);continue ;
Signature · 1 line
2.43.0
PATCH v4 9/10 net/gve: enforce DQO Tx packet length limits
In reply to Tathagat PriyadarshiThe device requires non-TSO packets to be 17 to 9728 bytes long, as noted in the Linux driver, but packets of any length are posted. The device treats an out-of-range packet as coming from a malicious
driver: it drops the packet and disables the datapath, stalling all queues.
Drop such packets in the driver and count them in a new invalid_pkts counter.
--- drivers/net/gve/base/gve_desc_dqo.h | 2 ++ drivers/net/gve/gve_ethdev.c | 1 + drivers/net/gve/gve_ethdev.h | 1 + drivers/net/gve/gve_tx_dqo.c | 17 +++++++++++++++++ 4 files changed, 21 insertions(+)
drivers/net/gve/base/gve_desc_dqo.h +2 -0
@@ -12,6 +12,8 @@#define GVE_TX_MAX_HDR_SIZE_DQO 255#define GVE_TX_MIN_TSO_MSS_DQO 88 +#define GVE_TX_MIN_PKT_SIZE_DQO 17 +#define GVE_TX_MAX_PKT_SIZE_DQO 9728/* Basic TX descriptor (DTYPE 0x0C) */ struct gve_tx_pkt_desc_dqo {
drivers/net/gve/gve_ethdev.c +1 -0
@@ -1044,6 +1044,7 @@ static const struct gve_xstats_name_offset tx_xstats_name_offset[] = { { "errors", TX_QUEUE_STATS_OFFSET(errors) }, { "too_many_descs", TX_QUEUE_STATS_OFFSET(too_many_descs) }, { "invalid_mbufs", TX_QUEUE_STATS_OFFSET(invalid_mbufs) }, + { "invalid_pkts", TX_QUEUE_STATS_OFFSET(invalid_pkts) }, }; static const struct gve_xstats_name_offset rx_xstats_name_offset[] = {
drivers/net/gve/gve_ethdev.h +1 -0
@@ -115,6 +115,7 @@ struct gve_tx_stats {uint64_t errors;uint64_t too_many_descs;uint64_t invalid_mbufs; +uint64_t invalid_pkts; };struct gve_rx_stats {
drivers/net/gve/gve_tx_dqo.c +17 -0
@@ -123,6 +123,17 @@ gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) {gve_tx_clean_dqo (txq); } +/* Validate packet lengths against the device limits. */ +static inline bool +gve_tx_validate_pkt (const struct rte_mbuf *tx_pkt,bool is_tso) +{ +if (!is_tso) +return tx_pkt->pkt_len >=GVE_TX_MIN_PKT_SIZE_DQO && + tx_pkt->pkt_len <=GVE_TX_MAX_PKT_SIZE_DQO ; + +return true; +} +/* Max descriptors a single packet may use. A larger packet can never pass * gve_can_tx(): one slot is always reserved, the cacheline overlap margin * must stay free, and up to GVE_TX_MIN_RE_INTERVAL - 1 descriptors posted
@@ -306,6 +317,12 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) tso = !!(ol_flags &RTE_MBUF_F_TX_TCP_SEG ); csum = !!(ol_flags &GVE_TX_CKSUM_OFFLOAD_MASK_DQO ); +if (!gve_tx_validate_pkt (tx_pkt, tso)) { + txq->stats.invalid_pkts++; +rte_pktmbuf_free (tx_pkt); +continue ; + } + nb_descs =gve_tx_pkt_nb_data_descs (tx_pkt); nb_descs += tso;
Signature · 1 line
2.43.0
PATCH v4 10/10 net/gve: enforce DQO TSO header and length limits
In reply to Tathagat PriyadarshiTSO packets are not checked against the device limits before use. The device requires an MSS of 88 to 9728 bytes and a payload of at most 262143 bytes, as noted in the Linux driver. A packet outside these limits triggers malicious driver detection, which drops it and disables the datapath, stalling all queues.
The missing checks also break the driver itself: a tso_segsz of 0 divides by zero in gve_tx_validate_descs(), headers longer than 255 bytes are truncated by the 8-bit header_len field, and headers not contained in the first segment give gve_tx_validate_descs() a negative first segment length.
Drop TSO packets that violate these limits and count them as invalid_pkts.
--- drivers/net/gve/base/gve_desc_dqo.h | 1 + drivers/net/gve/gve_tx_dqo.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-)
drivers/net/gve/base/gve_desc_dqo.h +1 -0
@@ -14,6 +14,7 @@#define GVE_TX_MIN_TSO_MSS_DQO 88#define GVE_TX_MIN_PKT_SIZE_DQO 17#define GVE_TX_MAX_PKT_SIZE_DQO 9728 +#define GVE_TX_MAX_TSO_LEN_DQO ((256 * 1024) - 1)/* Basic TX descriptor (DTYPE 0x0C) */ struct gve_tx_pkt_desc_dqo {
drivers/net/gve/gve_tx_dqo.c +13 -1
@@ -127,11 +127,23 @@ gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) {static inline bool gve_tx_validate_pkt (const struct rte_mbuf *tx_pkt,bool is_tso) { +uint32_t headlen; +if (!is_tso)return tx_pkt->pkt_len >=GVE_TX_MIN_PKT_SIZE_DQO && tx_pkt->pkt_len <=GVE_TX_MAX_PKT_SIZE_DQO ; -return true; +/* Headers must be present, fit the context descriptor, and be +* contained in the first segment; the payload must not be empty. +*/ + headlen = tx_pkt->l2_len + tx_pkt->l3_len + tx_pkt->l4_len; +if (tx_pkt->l4_len ==0 || headlen >GVE_TX_MAX_HDR_SIZE_DQO || + tx_pkt->data_len < headlen || tx_pkt->pkt_len <= headlen) +return false; + +return tx_pkt->pkt_len - headlen <=GVE_TX_MAX_TSO_LEN_DQO && + tx_pkt->tso_segsz >=GVE_TX_MIN_TSO_MSS_DQO && + tx_pkt->tso_segsz <=GVE_TX_MAX_PKT_SIZE_DQO ; }/* Max descriptors a single packet may use. A larger packet can never pass
Signature · 1 line
2.43.0
Re: [PATCH v4 09/10] net/gve: enforce DQO Tx packet length limits
In reply to Joshua WashingtonQuoted 70 lines · Joshua Washington
Quoted 7 lines · Tathagat Priyadarshi
The device requires non-TSO packets to be 17 to 9728 bytes long, as noted in the Linux driver, but packets of any length are posted. The device treats an out-of-range packet as coming from a malicious
driver: it drops the packet and disables the datapath, stalling all queues.Quoted 7 lines
Drop such packets in the driver and count them in a new
invalid_pktscounter.Fixes 4022f9999f56 ("net/gve: support basic Tx data path for DQO")Signed-off-by Tathagat Priyadarshi <[email protected]>Quoted 52 lines
--- drivers/net/gve/base/gve_desc_dqo.h | 2 ++ drivers/net/gve/gve_ethdev.c | 1 + drivers/net/gve/gve_ethdev.h | 1 + drivers/net/gve/gve_tx_dqo.c | 17 +++++++++++++++++ 4 files changed, 21 insertions(+)drivers/net/gve/base/gve_desc_dqo.h +2
-0@@ -12,6 +12,8 @@#define GVE_TX_MAX_HDR_SIZE_DQO 255#define GVE_TX_MIN_TSO_MSS_DQO 88 +#define GVE_TX_MIN_PKT_SIZE_DQO 17 +#define GVE_TX_MAX_PKT_SIZE_DQO 9728/* Basic TX descriptor (DTYPE 0x0C) */ struct gve_tx_pkt_desc_dqo {drivers/net/gve/gve_ethdev.c +1
-0@@ -1044,6 +1044,7 @@ static const struct gve_xstats_name_offset tx_xstats_name_offset[] = { { "errors", TX_QUEUE_STATS_OFFSET(errors) }, { "too_many_descs", TX_QUEUE_STATS_OFFSET(too_many_descs) }, { "invalid_mbufs", TX_QUEUE_STATS_OFFSET(invalid_mbufs) }, + { "invalid_pkts", TX_QUEUE_STATS_OFFSET(invalid_pkts) }, }; static const struct gve_xstats_name_offset rx_xstats_name_offset[] = {drivers/net/gve/gve_ethdev.h +1
-0@@ -115,6 +115,7 @@ struct gve_tx_stats {uint64_t errors;uint64_t too_many_descs;uint64_t invalid_mbufs; +uint64_t invalid_pkts; };struct gve_rx_stats {drivers/net/gve/gve_tx_dqo.c +0
-0@@ -123,6 +123,17 @@ gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) {gve_tx_clean_dqo (txq); }
Quoted 8 lines
drivers/net/gve/gve_tx_dqo.c gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) { · line 128
Quoted 3 lines
drivers/net/gve/gve_tx_dqo.c +3
-0+/* Validate packet lengths against the device limits. */ +static inline bool +gve_tx_validate_pkt (const struct rte_mbuf *tx_pkt,bool is_tso)Minor nit (not worth blocking over, but maybe can be done as the patches are being merged): can this be renamed to
gve_tx_validate_pkt_len? This is one step of many in the packet validation pipeline.
Thanks for the review, Joshua. Agreed on renaming to gve_tx_validate_pkt_len. This change impacts patches 9/10 and 10/10. I am happy to submit a v5 series if preferred,
or the maintainer can rename it upon applying.
Quoted 28 lines
Quoted 28 lines
drivers/net/gve/gve_tx_dqo.c +14
-1+{ +if (!is_tso) +return tx_pkt->pkt_len >=GVE_TX_MIN_PKT_SIZE_DQO && + tx_pkt->pkt_len <=GVE_TX_MAX_PKT_SIZE_DQO ; + +return true; +} +/* Max descriptors a single packet may use. A larger packet can never pass * gve_can_tx(): one slot is always reserved, the cacheline overlap margin * must stay free, and up to GVE_TX_MIN_RE_INTERVAL - 1 descriptors posted @@ -306,6 +317,12 @@ gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) tso = !!(ol_flags &RTE_MBUF_F_TX_TCP_SEG ); csum = !!(ol_flags &GVE_TX_CKSUM_OFFLOAD_MASK_DQO ); +if (!gve_tx_validate_pkt (tx_pkt, tso)) { + txq->stats.invalid_pkts++; +rte_pktmbuf_free (tx_pkt); +continue ; + } + nb_descs =gve_tx_pkt_nb_data_descs (tx_pkt); nb_descs += tso; --2.43.0
Re: [PATCH v4 09/10] net/gve: enforce DQO Tx packet length limits
Quoted 8 lines · On Sun, 18 Oct 2026 13:24:03 +0530 Tathagat Priyadarshi…
Quoted 7 lines
drivers/net/gve/gve_tx_dqo.c gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) { · line 128
Quoted 2 lines
drivers/net/gve/gve_tx_dqo.c +2
-0+static inline bool +gve_tx_validate_pkt (const struct rte_mbuf *tx_pkt,bool is_tso)Minor nit (not worth blocking over, but maybe can be done as the patches are being merged): can this be renamed to
gve_tx_validate_pkt_len? This is one step of many in the packet validation pipeline.
Quoted 4 lines
Thanks for the review, Joshua. Agreed on renaming to
gve_tx_validate_pkt_len. This change impacts patches 9/10 and 10/10. I am happy to submit a v5 series if preferred,
or the maintainer can rename it upon applying.
Renames should go through patchwork. I can cleanup commit messages and release notes, that is where I stop.
Re: [PATCH v4 09/10] net/gve: enforce DQO Tx packet length limits
Quoted 12 lines · Stephen Hemminger
Quoted 8 lines · On Sun, 18 Oct 2026 13:24:03 +0530 Tathagat Priyadarshi…
Quoted 7 lines
drivers/net/gve/gve_tx_dqo.c gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) { · line 128
Quoted 2 lines
drivers/net/gve/gve_tx_dqo.c +2
-0+static inline bool +gve_tx_validate_pkt (const struct rte_mbuf *tx_pkt,bool is_tso)Minor nit (not worth blocking over, but maybe can be done as the patches are being merged): can this be renamed to
gve_tx_validate_pkt_len? This is one step of many in the packet validation pipeline.
Quoted 7 lines
Quoted 4 lines
Thanks for the review, Joshua. Agreed on renaming to
gve_tx_validate_pkt_len. This change impacts patches 9/10 and 10/10. I am happy to submit a v5 series if preferred,
or the maintainer can rename it upon applying.Renames should go through patchwork. I can cleanup commit messages and release notes, that is where I stop.
In that case, would it be okay to merge as-is? I will be following up this series directly with some TX datapath fixes of my own which are kind of related to Tathagat's fixes, so I can probably update the function name in my patch series, rather than going to v5.
Re: [PATCH v4 09/10] net/gve: enforce DQO Tx packet length limits
Thanks, Joshua.
Stephen, could you please merge these, or let me know if we still need a v5?
Quoted 27 lines · Joshua Washington
Quoted 12 lines · Stephen Hemminger
Quoted 8 lines · On Sun, 18 Oct 2026 13:24:03 +0530 Tathagat Priyadarshi…
Quoted 7 lines
drivers/net/gve/gve_tx_dqo.c gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) { · line 128
Quoted 2 lines
drivers/net/gve/gve_tx_dqo.c +2
-0+static inline bool +gve_tx_validate_pkt (const struct rte_mbuf *tx_pkt,bool is_tso)Minor nit (not worth blocking over, but maybe can be done as the patches are being merged): can this be renamed to
gve_tx_validate_pkt_len? This is one step of many in the packet validation pipeline.Quoted 7 lines
Quoted 4 lines
Thanks for the review, Joshua. Agreed on renaming to
gve_tx_validate_pkt_len. This change impacts patches 9/10 and 10/10. I am happy to submit a v5 series if preferred,
or the maintainer can rename it upon applying.Renames should go through patchwork. I can cleanup commit messages and release notes, that is where I stop.
In that case, would it be okay to merge as-is? I will be following up this series directly with some TX datapath fixes of my own which are kind of related to Tathagat's fixes, so I can probably update the function name in my patch series, rather than going to v5.