The GVNIC DQO hardware restricts each packet (or MTU segment in TSO)
to at most 10 data descriptors (GVE_TX_MAX_DATA_DESCS), beyond which
the hardware drops traffic. In addition to this 10-descriptor limit,
the hardware imposes strict packet sizing and header constraints.
Enforce these hardware packet and TSO validation constraints in DQO
RDA mode within gve_tx_validate_descs() matching the upstream Linux
kernel driver:
- Define GVE_TX_MAX_TSO_MSS_DQO (9728 bytes) to avoid 14-bit MSS
field overflow in struct gve_tx_tso_context_desc_dqo.
- Define GVE_TX_MIN_PKT_SIZE_DQO (17 bytes) and GVE_TX_MAX_PKT_SIZE_DQO
(9728 bytes) to reject runts (which cause hardware DMA parse errors)
and oversized non-TSO packets.
- In gve_tx_validate_descs():
* Reject zero-length mbufs (nb_descs == 0 or pkt_len == 0).
* Enforce packet size in [17, 9728] for non-TSO packets alongside
the 10-descriptor limit (nb_descs <= GVE_TX_MAX_DATA_DESCS).
* Reject split transport headers across mbuf segments
(data_len < headlen).
* Reject TSO packets missing an L4 header (l4_len == 0).
* Reject TSO packets without payload (pkt_len <= headlen).
* Enforce MSS limits [88, 9728] and header length limit <= 255.
Fixes: 403c671a46b6 ("net/gve: support TSO in DQO RDA")
Cc: [email protected]
Acked-by: Joshua Washington <[email protected]>
Signed-off-by: Tathagat Priyadarshi <[email protected]>
---
drivers/net/gve/base/gve_desc_dqo.h | 3 ++
drivers/net/gve/gve_tx_dqo.c | 44 ++++++++++++++++++++++++-----
2 files changed, 40 insertions(+), 7 deletions(-)
diff --git a/drivers/net/gve/base/gve_desc_dqo.h
b/drivers/net/gve/base/gve_desc_dqo.h
index c1534959c2..1740f69d73 100644
--- a/drivers/net/gve/base/gve_desc_dqo.h
+++ b/drivers/net/gve/base/gve_desc_dqo.h
@@ -12,6 +12,9 @@
#define GVE_TX_MAX_HDR_SIZE_DQO 255
#define GVE_TX_MIN_TSO_MSS_DQO 88
+#define GVE_TX_MAX_TSO_MSS_DQO 9728
+#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 {
diff --git a/drivers/net/gve/gve_tx_dqo.c b/drivers/net/gve/gve_tx_dqo.c
index 9210b02eb1..03ac3bd5dd 100644
--- a/drivers/net/gve/gve_tx_dqo.c
+++ b/drivers/net/gve/gve_tx_dqo.c
@@ -134,12 +134,43 @@ gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t
nb_descs) {
static inline bool
gve_tx_validate_descs(struct rte_mbuf *tx_pkt, uint16_t nb_descs, bool is_tso)
{
- if (!is_tso)
+ int tso_segsz, seg_remain, mbuf_remain;
+ int num_descs, seg_offset, mbuf_len;
+ int headlen;
+
+ /* Reject zero-length packet */
+ if (unlikely(nb_descs == 0 || tx_pkt->pkt_len == 0))
+ return false;
+
+ if (!is_tso) {
+ /* Reject packets that violate hardware length constraints */
+ if (unlikely(tx_pkt->pkt_len < GVE_TX_MIN_PKT_SIZE_DQO ||
+ tx_pkt->pkt_len > GVE_TX_MAX_PKT_SIZE_DQO))
+ return false;
return nb_descs <= GVE_TX_MAX_DATA_DESCS;
+ }
- int tso_segsz = tx_pkt->tso_segsz;
- int num_descs, seg_offset, mbuf_len;
- int headlen = tx_pkt->l2_len + tx_pkt->l3_len + tx_pkt->l4_len;
+ headlen = tx_pkt->l2_len + tx_pkt->l3_len + tx_pkt->l4_len;
+
+ /* Reject split transport header */
+ if (unlikely(tx_pkt->data_len < headlen))
+ return false;
+
+ /* Reject missing TCP header on TSO */
+ if (unlikely(tx_pkt->l4_len == 0))
+ return false;
+
+ /* Reject TSO packet without payload */
+ if (unlikely(tx_pkt->pkt_len <= (uint32_t)headlen))
+ return false;
+
+ /* Enforce GVE hardware MSS and header limits */
+ if (unlikely(tx_pkt->tso_segsz < GVE_TX_MIN_TSO_MSS_DQO ||
+ tx_pkt->tso_segsz > GVE_TX_MAX_TSO_MSS_DQO ||
+ headlen > GVE_TX_MAX_HDR_SIZE_DQO))
+ return false;
+
+ tso_segsz = tx_pkt->tso_segsz;
/* Headers will be split into their own buffer. */
num_descs = 1;
@@ -150,7 +181,7 @@ gve_tx_validate_descs(struct rte_mbuf *tx_pkt, uint16_t
nb_descs, bool is_tso)
if (!mbuf_len)
goto next_mbuf;
- int seg_remain = tso_segsz - seg_offset;
+ seg_remain = tso_segsz - seg_offset;
if (num_descs == GVE_TX_MAX_DATA_DESCS && seg_remain)
return false;
@@ -162,7 +193,7 @@ gve_tx_validate_descs(struct rte_mbuf *tx_pkt, uint16_t
nb_descs, bool is_tso)
* is not at risk of defying this limitation.
* Thus, such segments are ignored.
*/
- int mbuf_remain = tx_pkt->data_len %
GVE_TX_MAX_BUF_SIZE_DQO;
+ mbuf_remain = tx_pkt->data_len %
GVE_TX_MAX_BUF_SIZE_DQO;
/* For each TSO segment, HW will prepend
* headers. The remaining bytes of this mbuf
@@ -184,7 +215,6 @@ gve_tx_validate_descs(struct rte_mbuf *tx_pkt, uint16_t
nb_descs, bool is_tso)
mbuf_len = tx_pkt->data_len;
}
-
return true;
}
--
2.43.0