[v2,06/13] net/txgbe: check length of Tx packets

Message ID 20241028023147.60157-7-jiawenwu@trustnetic.com (mailing list archive)
State Changes Requested, archived
Delegated to: Ferruh Yigit
Headers
Series Wangxun fixes |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Jiawen Wu Oct. 28, 2024, 2:31 a.m. UTC
Add checking of the Tx packet length to avoid TDM fatal error as far as
possible. Set the pkt_len=1518 for invalid packet in simple Tx code path,
and drop it directly in featured Tx code path.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
 drivers/net/txgbe/txgbe_rxtx.c          | 33 +++++++++++++++++++++++++
 drivers/net/txgbe/txgbe_rxtx_vec_neon.c | 10 +++++---
 drivers/net/txgbe/txgbe_rxtx_vec_sse.c  | 11 ++++++---
 3 files changed, 48 insertions(+), 6 deletions(-)
  

Comments

Ferruh Yigit Nov. 1, 2024, 1:22 a.m. UTC | #1
On 10/28/2024 2:31 AM, Jiawen Wu wrote:
> Add checking of the Tx packet length to avoid TDM fatal error as far as
> possible. Set the pkt_len=1518 for invalid packet in simple Tx code path,
> and drop it directly in featured Tx code path.
> 
> Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
> ---
>  drivers/net/txgbe/txgbe_rxtx.c          | 33 +++++++++++++++++++++++++
>  drivers/net/txgbe/txgbe_rxtx_vec_neon.c | 10 +++++---
>  drivers/net/txgbe/txgbe_rxtx_vec_sse.c  | 11 ++++++---
>  3 files changed, 48 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
> index 2d2b437643..06acbd0881 100644
> --- a/drivers/net/txgbe/txgbe_rxtx.c
> +++ b/drivers/net/txgbe/txgbe_rxtx.c
> @@ -160,6 +160,8 @@ tx4(volatile struct txgbe_tx_desc *txdp, struct rte_mbuf **pkts)
>  	for (i = 0; i < 4; ++i, ++txdp, ++pkts) {
>  		buf_dma_addr = rte_mbuf_data_iova(*pkts);
>  		pkt_len = (*pkts)->data_len;
> +		if (pkt_len < RTE_ETHER_HDR_LEN)
> +			pkt_len = TXGBE_FRAME_SIZE_DFT;
>  
>  		/* write data to descriptor */
>  		txdp->qw0 = rte_cpu_to_le_64(buf_dma_addr);
> @@ -180,6 +182,8 @@ tx1(volatile struct txgbe_tx_desc *txdp, struct rte_mbuf **pkts)
>  
>  	buf_dma_addr = rte_mbuf_data_iova(*pkts);
>  	pkt_len = (*pkts)->data_len;
> +	if (pkt_len < RTE_ETHER_HDR_LEN)
> +		pkt_len = TXGBE_FRAME_SIZE_DFT;
>  
>  	/* write data to descriptor */
>  	txdp->qw0 = cpu_to_le64(buf_dma_addr);
> @@ -813,6 +817,30 @@ txgbe_parse_tun_ptid(struct rte_mbuf *tx_pkt, uint8_t tun_len)
>  	return ptid;
>  }
>  
> +static inline bool
> +txgbe_check_pkt_err(struct rte_mbuf *tx_pkt)
> +{
> +	uint32_t total_len = 0, nb_seg = 0;
> +	struct rte_mbuf *mseg;
> +
> +	mseg = tx_pkt;
> +	do {
> +		if (mseg->data_len == 0)
> +			return true;
> +		total_len += mseg->data_len;
> +		nb_seg++;
> +		mseg = mseg->next;
> +	} while (mseg != NULL);
> +
> +	if (tx_pkt->pkt_len != total_len || tx_pkt->pkt_len == 0)
> +		return true;
> +
> +	if (tx_pkt->nb_segs != nb_seg || tx_pkt->nb_segs > 64)
> +		return true;
> +
> +	return false;
> +}
> +
>

Hi Jiawen,

Above are generic checks, we may add this function to ethdev driver
header (ethdev_driver.h) so that any PMD can use it, what do you think?
  
Jiawen Wu Nov. 1, 2024, 1:52 a.m. UTC | #2
On Fri, Nov 1, 2024 9:23 AM, Ferruh Yigit wrote:
> On 10/28/2024 2:31 AM, Jiawen Wu wrote:
> > Add checking of the Tx packet length to avoid TDM fatal error as far as
> > possible. Set the pkt_len=1518 for invalid packet in simple Tx code path,
> > and drop it directly in featured Tx code path.
> >
> > Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
> > ---
> >  drivers/net/txgbe/txgbe_rxtx.c          | 33 +++++++++++++++++++++++++
> >  drivers/net/txgbe/txgbe_rxtx_vec_neon.c | 10 +++++---
> >  drivers/net/txgbe/txgbe_rxtx_vec_sse.c  | 11 ++++++---
> >  3 files changed, 48 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
> > index 2d2b437643..06acbd0881 100644
> > --- a/drivers/net/txgbe/txgbe_rxtx.c
> > +++ b/drivers/net/txgbe/txgbe_rxtx.c
> > @@ -160,6 +160,8 @@ tx4(volatile struct txgbe_tx_desc *txdp, struct rte_mbuf **pkts)
> >  	for (i = 0; i < 4; ++i, ++txdp, ++pkts) {
> >  		buf_dma_addr = rte_mbuf_data_iova(*pkts);
> >  		pkt_len = (*pkts)->data_len;
> > +		if (pkt_len < RTE_ETHER_HDR_LEN)
> > +			pkt_len = TXGBE_FRAME_SIZE_DFT;
> >
> >  		/* write data to descriptor */
> >  		txdp->qw0 = rte_cpu_to_le_64(buf_dma_addr);
> > @@ -180,6 +182,8 @@ tx1(volatile struct txgbe_tx_desc *txdp, struct rte_mbuf **pkts)
> >
> >  	buf_dma_addr = rte_mbuf_data_iova(*pkts);
> >  	pkt_len = (*pkts)->data_len;
> > +	if (pkt_len < RTE_ETHER_HDR_LEN)
> > +		pkt_len = TXGBE_FRAME_SIZE_DFT;
> >
> >  	/* write data to descriptor */
> >  	txdp->qw0 = cpu_to_le64(buf_dma_addr);
> > @@ -813,6 +817,30 @@ txgbe_parse_tun_ptid(struct rte_mbuf *tx_pkt, uint8_t tun_len)
> >  	return ptid;
> >  }
> >
> > +static inline bool
> > +txgbe_check_pkt_err(struct rte_mbuf *tx_pkt)
> > +{
> > +	uint32_t total_len = 0, nb_seg = 0;
> > +	struct rte_mbuf *mseg;
> > +
> > +	mseg = tx_pkt;
> > +	do {
> > +		if (mseg->data_len == 0)
> > +			return true;
> > +		total_len += mseg->data_len;
> > +		nb_seg++;
> > +		mseg = mseg->next;
> > +	} while (mseg != NULL);
> > +
> > +	if (tx_pkt->pkt_len != total_len || tx_pkt->pkt_len == 0)
> > +		return true;
> > +
> > +	if (tx_pkt->nb_segs != nb_seg || tx_pkt->nb_segs > 64)
> > +		return true;
> > +
> > +	return false;
> > +}
> > +
> >
> 
> Hi Jiawen,
> 
> Above are generic checks, we may add this function to ethdev driver
> header (ethdev_driver.h) so that any PMD can use it, what do you think?

In fact, the limitation of tx_pkt->nb_segs is already implemented in
.tx_pkt_prepare. But users developing their own apps don't necessarily call
this function. So I'd like to add these in txgbe_xmit_pkts(). What are you
going to do about it?
  
Ferruh Yigit Nov. 1, 2024, 2:49 a.m. UTC | #3
On 11/1/2024 1:52 AM, Jiawen Wu wrote:
> On Fri, Nov 1, 2024 9:23 AM, Ferruh Yigit wrote:
>> On 10/28/2024 2:31 AM, Jiawen Wu wrote:
>>> Add checking of the Tx packet length to avoid TDM fatal error as far as
>>> possible. Set the pkt_len=1518 for invalid packet in simple Tx code path,
>>> and drop it directly in featured Tx code path.
>>>
>>> Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
>>> ---
>>>  drivers/net/txgbe/txgbe_rxtx.c          | 33 +++++++++++++++++++++++++
>>>  drivers/net/txgbe/txgbe_rxtx_vec_neon.c | 10 +++++---
>>>  drivers/net/txgbe/txgbe_rxtx_vec_sse.c  | 11 ++++++---
>>>  3 files changed, 48 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
>>> index 2d2b437643..06acbd0881 100644
>>> --- a/drivers/net/txgbe/txgbe_rxtx.c
>>> +++ b/drivers/net/txgbe/txgbe_rxtx.c
>>> @@ -160,6 +160,8 @@ tx4(volatile struct txgbe_tx_desc *txdp, struct rte_mbuf **pkts)
>>>  	for (i = 0; i < 4; ++i, ++txdp, ++pkts) {
>>>  		buf_dma_addr = rte_mbuf_data_iova(*pkts);
>>>  		pkt_len = (*pkts)->data_len;
>>> +		if (pkt_len < RTE_ETHER_HDR_LEN)
>>> +			pkt_len = TXGBE_FRAME_SIZE_DFT;
>>>
>>>  		/* write data to descriptor */
>>>  		txdp->qw0 = rte_cpu_to_le_64(buf_dma_addr);
>>> @@ -180,6 +182,8 @@ tx1(volatile struct txgbe_tx_desc *txdp, struct rte_mbuf **pkts)
>>>
>>>  	buf_dma_addr = rte_mbuf_data_iova(*pkts);
>>>  	pkt_len = (*pkts)->data_len;
>>> +	if (pkt_len < RTE_ETHER_HDR_LEN)
>>> +		pkt_len = TXGBE_FRAME_SIZE_DFT;
>>>
>>>  	/* write data to descriptor */
>>>  	txdp->qw0 = cpu_to_le64(buf_dma_addr);
>>> @@ -813,6 +817,30 @@ txgbe_parse_tun_ptid(struct rte_mbuf *tx_pkt, uint8_t tun_len)
>>>  	return ptid;
>>>  }
>>>
>>> +static inline bool
>>> +txgbe_check_pkt_err(struct rte_mbuf *tx_pkt)
>>> +{
>>> +	uint32_t total_len = 0, nb_seg = 0;
>>> +	struct rte_mbuf *mseg;
>>> +
>>> +	mseg = tx_pkt;
>>> +	do {
>>> +		if (mseg->data_len == 0)
>>> +			return true;
>>> +		total_len += mseg->data_len;
>>> +		nb_seg++;
>>> +		mseg = mseg->next;
>>> +	} while (mseg != NULL);
>>> +
>>> +	if (tx_pkt->pkt_len != total_len || tx_pkt->pkt_len == 0)
>>> +		return true;
>>> +
>>> +	if (tx_pkt->nb_segs != nb_seg || tx_pkt->nb_segs > 64)
>>> +		return true;
>>> +
>>> +	return false;
>>> +}
>>> +
>>>
>>
>> Hi Jiawen,
>>
>> Above are generic checks, we may add this function to ethdev driver
>> header (ethdev_driver.h) so that any PMD can use it, what do you think?
> 
> In fact, the limitation of tx_pkt->nb_segs is already implemented in
> .tx_pkt_prepare. But users developing their own apps don't necessarily call
> this function. So I'd like to add these in txgbe_xmit_pkts(). What are you
> going to do about it?
> 
> 

I had the same thought, that is why I am not suggesting to add these
checks to .tx_pkt_prepare() function.

But still these generic checks can go into a new static inline function
for drivers to use, not for end users, and any other driver can call
this function. Your two drivers already using the same function.

This is not hard requirement, but if there is a common code for multiple
drivers, that can go into a helper function in ethdev_driver.h
  
Stephen Hemminger Nov. 1, 2024, 2:56 a.m. UTC | #4
On Fri, 1 Nov 2024 01:22:47 +0000
Ferruh Yigit <ferruh.yigit@amd.com> wrote:

> Hi Jiawen,
> 
> Above are generic checks, we may add this function to ethdev driver
> header (ethdev_driver.h) so that any PMD can use it, what do you think?

This is in the fastpath, and additional checks should not be added there.
Or at least put them under RTE_ETHDEV_DEBUG.
  
Ferruh Yigit Nov. 1, 2024, 9:55 p.m. UTC | #5
On 11/1/2024 2:56 AM, Stephen Hemminger wrote:
> On Fri, 1 Nov 2024 01:22:47 +0000
> Ferruh Yigit <ferruh.yigit@amd.com> wrote:
> 
>> Hi Jiawen,
>>
>> Above are generic checks, we may add this function to ethdev driver
>> header (ethdev_driver.h) so that any PMD can use it, what do you think?
> 
> This is in the fastpath, and additional checks should not be added there.
> Or at least put them under RTE_ETHDEV_DEBUG.
>

It is in the datapath, and ideally there shouldn't be error checks in
datapath.
But if HW does not check for errors and doesn't recover from error
conditions, driver may prefer to get the hit and do the checks.

Not for all drivers, but for the drivers that intentionally wants do the
check, I thought having a common helper function helps but I can see it
can create confusion.

@Jiawen, please continue as it is in next version, I mean have the
checks function in the driver itself.
  

Patch

diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index 2d2b437643..06acbd0881 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -160,6 +160,8 @@  tx4(volatile struct txgbe_tx_desc *txdp, struct rte_mbuf **pkts)
 	for (i = 0; i < 4; ++i, ++txdp, ++pkts) {
 		buf_dma_addr = rte_mbuf_data_iova(*pkts);
 		pkt_len = (*pkts)->data_len;
+		if (pkt_len < RTE_ETHER_HDR_LEN)
+			pkt_len = TXGBE_FRAME_SIZE_DFT;
 
 		/* write data to descriptor */
 		txdp->qw0 = rte_cpu_to_le_64(buf_dma_addr);
@@ -180,6 +182,8 @@  tx1(volatile struct txgbe_tx_desc *txdp, struct rte_mbuf **pkts)
 
 	buf_dma_addr = rte_mbuf_data_iova(*pkts);
 	pkt_len = (*pkts)->data_len;
+	if (pkt_len < RTE_ETHER_HDR_LEN)
+		pkt_len = TXGBE_FRAME_SIZE_DFT;
 
 	/* write data to descriptor */
 	txdp->qw0 = cpu_to_le64(buf_dma_addr);
@@ -813,6 +817,30 @@  txgbe_parse_tun_ptid(struct rte_mbuf *tx_pkt, uint8_t tun_len)
 	return ptid;
 }
 
+static inline bool
+txgbe_check_pkt_err(struct rte_mbuf *tx_pkt)
+{
+	uint32_t total_len = 0, nb_seg = 0;
+	struct rte_mbuf *mseg;
+
+	mseg = tx_pkt;
+	do {
+		if (mseg->data_len == 0)
+			return true;
+		total_len += mseg->data_len;
+		nb_seg++;
+		mseg = mseg->next;
+	} while (mseg != NULL);
+
+	if (tx_pkt->pkt_len != total_len || tx_pkt->pkt_len == 0)
+		return true;
+
+	if (tx_pkt->nb_segs != nb_seg || tx_pkt->nb_segs > 64)
+		return true;
+
+	return false;
+}
+
 uint16_t
 txgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 		uint16_t nb_pkts)
@@ -864,6 +892,11 @@  txgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 	for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
 		new_ctx = 0;
 		tx_pkt = *tx_pkts++;
+		if (txgbe_check_pkt_err(tx_pkt)) {
+			rte_pktmbuf_free(tx_pkt);
+			continue;
+		}
+
 		pkt_len = tx_pkt->pkt_len;
 
 		/*
diff --git a/drivers/net/txgbe/txgbe_rxtx_vec_neon.c b/drivers/net/txgbe/txgbe_rxtx_vec_neon.c
index a96baf9b1d..d4d647fab5 100644
--- a/drivers/net/txgbe/txgbe_rxtx_vec_neon.c
+++ b/drivers/net/txgbe/txgbe_rxtx_vec_neon.c
@@ -476,9 +476,13 @@  static inline void
 vtx1(volatile struct txgbe_tx_desc *txdp,
 		struct rte_mbuf *pkt, uint64_t flags)
 {
-	uint64x2_t descriptor = {
-			pkt->buf_iova + pkt->data_off,
-			(uint64_t)pkt->pkt_len << 45 | flags | pkt->data_len};
+	uint16_t pkt_len = pkt->data_len;
+
+	if (pkt_len < RTE_ETHER_HDR_LEN)
+		pkt_len = TXGBE_FRAME_SIZE_DFT;
+
+	uint64x2_t descriptor = {pkt->buf_iova + pkt->data_off,
+				(uint64_t)pkt_len << 45 | flags | pkt_len};
 
 	vst1q_u64((uint64_t *)(uintptr_t)txdp, descriptor);
 }
diff --git a/drivers/net/txgbe/txgbe_rxtx_vec_sse.c b/drivers/net/txgbe/txgbe_rxtx_vec_sse.c
index 1a3f2ce3cd..8ecce33471 100644
--- a/drivers/net/txgbe/txgbe_rxtx_vec_sse.c
+++ b/drivers/net/txgbe/txgbe_rxtx_vec_sse.c
@@ -607,9 +607,14 @@  static inline void
 vtx1(volatile struct txgbe_tx_desc *txdp,
 		struct rte_mbuf *pkt, uint64_t flags)
 {
-	__m128i descriptor = _mm_set_epi64x((uint64_t)pkt->pkt_len << 45 |
-			flags | pkt->data_len,
-			pkt->buf_iova + pkt->data_off);
+	uint16_t pkt_len = pkt->data_len;
+	__m128i descriptor;
+
+	if (pkt_len < RTE_ETHER_HDR_LEN)
+		pkt_len = TXGBE_FRAME_SIZE_DFT;
+
+	descriptor = _mm_set_epi64x((uint64_t)pkt_len << 45 | flags | pkt_len,
+				pkt->buf_iova + pkt->data_off);
 	_mm_store_si128((__m128i *)(uintptr_t)txdp, descriptor);
 }