[dpdk-dev,4/4] net/virtio: improve offload check performance

Message ID 20180601124758.22652-5-maxime.coquelin@redhat.com (mailing list archive)
State Superseded, archived
Delegated to: Maxime Coquelin
Headers

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK

Commit Message

Maxime Coquelin June 1, 2018, 12:47 p.m. UTC
  Instead of checking the multiple Virtio features bits for
every packet, let's do the check once at configure time and
store it in virtio_hw struct.

Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
---
 drivers/net/virtio/virtio_ethdev.c | 19 +++++++++++++++++++
 drivers/net/virtio/virtio_pci.h    |  2 ++
 drivers/net/virtio/virtio_rxtx.c   | 29 ++++++-----------------------
 3 files changed, 27 insertions(+), 23 deletions(-)
  

Comments

Tiwei Bie June 4, 2018, 11:55 a.m. UTC | #1
On Fri, Jun 01, 2018 at 02:47:58PM +0200, Maxime Coquelin wrote:
> Instead of checking the multiple Virtio features bits for
> every packet, let's do the check once at configure time and
> store it in virtio_hw struct.
> 
> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
> ---
>  drivers/net/virtio/virtio_ethdev.c | 19 +++++++++++++++++++
>  drivers/net/virtio/virtio_pci.h    |  2 ++
>  drivers/net/virtio/virtio_rxtx.c   | 29 ++++++-----------------------
>  3 files changed, 27 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
> index d481b282e..981e0994a 100644
> --- a/drivers/net/virtio/virtio_ethdev.c
> +++ b/drivers/net/virtio/virtio_ethdev.c
> @@ -1790,6 +1790,22 @@ rte_virtio_pmd_init(void)
>  	rte_pci_register(&rte_virtio_pmd);
>  }
>  
> +static inline int

Maybe it's better to return bool.

> +rx_offload_enabled(struct virtio_hw *hw)
> +{
> +	return vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_CSUM) ||
> +		vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO4) ||
> +		vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO6);
> +}
> +
> +static inline int

Ditto.

> +tx_offload_enabled(struct virtio_hw *hw)
> +{
> +	return vtpci_with_feature(hw, VIRTIO_NET_F_CSUM) ||
> +		vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO4) ||
> +		vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO6);
> +}
> +
>  /*
>   * Configure virtio device
>   * It returns 0 on success.
> @@ -1869,6 +1885,9 @@ virtio_dev_configure(struct rte_eth_dev *dev)
>  		return -ENOTSUP;
>  	}
>  
> +	hw->has_tx_offload = !!tx_offload_enabled(hw);
> +	hw->has_rx_offload = !!rx_offload_enabled(hw);
> +
>  	if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
>  		/* Enable vector (0) for Link State Intrerrupt */
>  		if (VTPCI_OPS(hw)->set_config_irq(hw, 0) ==
> diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
> index a28ba8339..e0bb871f2 100644
> --- a/drivers/net/virtio/virtio_pci.h
> +++ b/drivers/net/virtio/virtio_pci.h
> @@ -233,6 +233,8 @@ struct virtio_hw {
>  	uint8_t     modern;
>  	uint8_t     use_simple_rx;
>  	uint8_t     use_simple_tx;
> +	uint8_t		has_tx_offload;
> +	uint8_t		has_rx_offload;

I think it's better to use spaces, instead of
4 spaces width tabs after uint8_t.

>  	uint16_t    port_id;
>  	uint8_t     mac_addr[ETHER_ADDR_LEN];
>  	uint32_t    notify_off_multiplier;
> diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
> index 92fab2174..3f113a118 100644
> --- a/drivers/net/virtio/virtio_rxtx.c
> +++ b/drivers/net/virtio/virtio_rxtx.c
> @@ -225,13 +225,6 @@ virtio_tso_fix_cksum(struct rte_mbuf *m)
>  	}
>  }
>  
> -static inline int
> -tx_offload_enabled(struct virtio_hw *hw)
> -{
> -	return vtpci_with_feature(hw, VIRTIO_NET_F_CSUM) ||
> -		vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO4) ||
> -		vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO6);
> -}
>  
>  /* avoid write operation when necessary, to lessen cache issues */
>  #define ASSIGN_UNLESS_EQUAL(var, val) do {	\
> @@ -253,13 +246,15 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
>  	struct virtio_net_hdr *hdr;
>  	int offload;
>  
> -	offload = tx_offload_enabled(vq->hw);
>  	head_idx = vq->vq_desc_head_idx;
>  	idx = head_idx;
>  	dxp = &vq->vq_descx[idx];
>  	dxp->cookie = (void *)cookie;
>  	dxp->ndescs = needed;
>  
> +	offload = vq->hw->has_tx_offload &&
> +		(cookie->ol_flags & PKT_TX_OFFLOAD_MASK);

If features aren't negotiated, I think there is no need to
check ol_flags and update the net header.

> +
>  	start_dp = vq->vq_ring.desc;
>  
>  	if (can_push) {
> @@ -270,7 +265,6 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
>  		 * which is wrong. Below subtract restores correct pkt size.
>  		 */
>  		cookie->pkt_len -= head_size;
> -		/* if offload disabled, it is not zeroed below, do it now */
>  		if (offload == 0) {
>  			ASSIGN_UNLESS_EQUAL(hdr->csum_start, 0);
>  			ASSIGN_UNLESS_EQUAL(hdr->csum_offset, 0);
> @@ -686,14 +680,6 @@ virtio_rx_offload(struct rte_mbuf *m, struct virtio_net_hdr *hdr)
>  	return 0;
>  }
[...]

Best regards,
Tiwei Bie
  
Maxime Coquelin June 4, 2018, 2:29 p.m. UTC | #2
On 06/04/2018 01:55 PM, Tiwei Bie wrote:
> On Fri, Jun 01, 2018 at 02:47:58PM +0200, Maxime Coquelin wrote:
>> Instead of checking the multiple Virtio features bits for
>> every packet, let's do the check once at configure time and
>> store it in virtio_hw struct.
>>
>> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
>> ---
>>   drivers/net/virtio/virtio_ethdev.c | 19 +++++++++++++++++++
>>   drivers/net/virtio/virtio_pci.h    |  2 ++
>>   drivers/net/virtio/virtio_rxtx.c   | 29 ++++++-----------------------
>>   3 files changed, 27 insertions(+), 23 deletions(-)
>>
>> diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
>> index d481b282e..981e0994a 100644
>> --- a/drivers/net/virtio/virtio_ethdev.c
>> +++ b/drivers/net/virtio/virtio_ethdev.c
>> @@ -1790,6 +1790,22 @@ rte_virtio_pmd_init(void)
>>   	rte_pci_register(&rte_virtio_pmd);
>>   }
>>   
>> +static inline int
> 
> Maybe it's better to return bool.

Agree, I'll do that.
I just moved code from virtio_rxtx.c without change, but it is indeed
better to return bool.

>> +rx_offload_enabled(struct virtio_hw *hw)
>> +{
>> +	return vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_CSUM) ||
>> +		vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO4) ||
>> +		vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO6);
>> +}
>> +
>> +static inline int
> 
> Ditto.
> 
>> +tx_offload_enabled(struct virtio_hw *hw)
>> +{
>> +	return vtpci_with_feature(hw, VIRTIO_NET_F_CSUM) ||
>> +		vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO4) ||
>> +		vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO6);
>> +}
>> +
>>   /*
>>    * Configure virtio device
>>    * It returns 0 on success.
>> @@ -1869,6 +1885,9 @@ virtio_dev_configure(struct rte_eth_dev *dev)
>>   		return -ENOTSUP;
>>   	}
>>   
>> +	hw->has_tx_offload = !!tx_offload_enabled(hw);
>> +	hw->has_rx_offload = !!rx_offload_enabled(hw);
>> +
>>   	if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
>>   		/* Enable vector (0) for Link State Intrerrupt */
>>   		if (VTPCI_OPS(hw)->set_config_irq(hw, 0) ==
>> diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
>> index a28ba8339..e0bb871f2 100644
>> --- a/drivers/net/virtio/virtio_pci.h
>> +++ b/drivers/net/virtio/virtio_pci.h
>> @@ -233,6 +233,8 @@ struct virtio_hw {
>>   	uint8_t     modern;
>>   	uint8_t     use_simple_rx;
>>   	uint8_t     use_simple_tx;
>> +	uint8_t		has_tx_offload;
>> +	uint8_t		has_rx_offload;

Acked.

> 
> I think it's better to use spaces, instead of
> 4 spaces width tabs after uint8_t.
> 
>>   	uint16_t    port_id;
>>   	uint8_t     mac_addr[ETHER_ADDR_LEN];
>>   	uint32_t    notify_off_multiplier;
>> diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
>> index 92fab2174..3f113a118 100644
>> --- a/drivers/net/virtio/virtio_rxtx.c
>> +++ b/drivers/net/virtio/virtio_rxtx.c
>> @@ -225,13 +225,6 @@ virtio_tso_fix_cksum(struct rte_mbuf *m)
>>   	}
>>   }
>>   
>> -static inline int
>> -tx_offload_enabled(struct virtio_hw *hw)
>> -{
>> -	return vtpci_with_feature(hw, VIRTIO_NET_F_CSUM) ||
>> -		vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO4) ||
>> -		vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO6);
>> -}
>>   
>>   /* avoid write operation when necessary, to lessen cache issues */
>>   #define ASSIGN_UNLESS_EQUAL(var, val) do {	\
>> @@ -253,13 +246,15 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
>>   	struct virtio_net_hdr *hdr;
>>   	int offload;
>>   
>> -	offload = tx_offload_enabled(vq->hw);
>>   	head_idx = vq->vq_desc_head_idx;
>>   	idx = head_idx;
>>   	dxp = &vq->vq_descx[idx];
>>   	dxp->cookie = (void *)cookie;
>>   	dxp->ndescs = needed;
>>   
>> +	offload = vq->hw->has_tx_offload &&
>> +		(cookie->ol_flags & PKT_TX_OFFLOAD_MASK);
> 
> If features aren't negotiated, I think there is no need to
> check ol_flags and update the net header.

Isn't what the code is doing?
has_tx_offload will be false if none of the Tx offload features have
been negotiated, so ol_flags won't be checked in that case.

>> +
>>   	start_dp = vq->vq_ring.desc;
>>   
>>   	if (can_push) {
>> @@ -270,7 +265,6 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
>>   		 * which is wrong. Below subtract restores correct pkt size.
>>   		 */
>>   		cookie->pkt_len -= head_size;
>> -		/* if offload disabled, it is not zeroed below, do it now */
>>   		if (offload == 0) {
>>   			ASSIGN_UNLESS_EQUAL(hdr->csum_start, 0);
>>   			ASSIGN_UNLESS_EQUAL(hdr->csum_offset, 0);
>> @@ -686,14 +680,6 @@ virtio_rx_offload(struct rte_mbuf *m, struct virtio_net_hdr *hdr)
>>   	return 0;
>>   }
> [...]
> 
> Best regards,
> Tiwei Bie
>
  
Tiwei Bie June 5, 2018, 3:10 a.m. UTC | #3
On Mon, Jun 04, 2018 at 04:29:56PM +0200, Maxime Coquelin wrote:
> On 06/04/2018 01:55 PM, Tiwei Bie wrote:
> > On Fri, Jun 01, 2018 at 02:47:58PM +0200, Maxime Coquelin wrote:
[...]
> > > @@ -253,13 +246,15 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
> > >   	struct virtio_net_hdr *hdr;
> > >   	int offload;
> > > -	offload = tx_offload_enabled(vq->hw);
> > >   	head_idx = vq->vq_desc_head_idx;
> > >   	idx = head_idx;
> > >   	dxp = &vq->vq_descx[idx];
> > >   	dxp->cookie = (void *)cookie;
> > >   	dxp->ndescs = needed;
> > > +	offload = vq->hw->has_tx_offload &&
> > > +		(cookie->ol_flags & PKT_TX_OFFLOAD_MASK);
> > 
> > If features aren't negotiated, I think there is no need to
> > check ol_flags and update the net header.
> 
> Isn't what the code is doing?
> has_tx_offload will be false if none of the Tx offload features have
> been negotiated, so ol_flags won't be checked in that case.

Hmm.. Somehow I treated 'and' as 'or'..

I have another question. When 'can_push' is false
and 'vq->hw->has_tx_offload' is true, there will
be a chance that virtio net hdr won't be zeroed
when ol_flags doesn't specify any Tx offloads.

Best regards,
Tiwei Bie
  
Maxime Coquelin June 5, 2018, 9:43 a.m. UTC | #4
On 06/05/2018 05:10 AM, Tiwei Bie wrote:
> On Mon, Jun 04, 2018 at 04:29:56PM +0200, Maxime Coquelin wrote:
>> On 06/04/2018 01:55 PM, Tiwei Bie wrote:
>>> On Fri, Jun 01, 2018 at 02:47:58PM +0200, Maxime Coquelin wrote:
> [...]
>>>> @@ -253,13 +246,15 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
>>>>    	struct virtio_net_hdr *hdr;
>>>>    	int offload;
>>>> -	offload = tx_offload_enabled(vq->hw);
>>>>    	head_idx = vq->vq_desc_head_idx;
>>>>    	idx = head_idx;
>>>>    	dxp = &vq->vq_descx[idx];
>>>>    	dxp->cookie = (void *)cookie;
>>>>    	dxp->ndescs = needed;
>>>> +	offload = vq->hw->has_tx_offload &&
>>>> +		(cookie->ol_flags & PKT_TX_OFFLOAD_MASK);
>>>
>>> If features aren't negotiated, I think there is no need to
>>> check ol_flags and update the net header.
>>
>> Isn't what the code is doing?
>> has_tx_offload will be false if none of the Tx offload features have
>> been negotiated, so ol_flags won't be checked in that case.
> 
> Hmm.. Somehow I treated 'and' as 'or'..
> 
> I have another question. When 'can_push' is false
> and 'vq->hw->has_tx_offload' is true, there will
> be a chance that virtio net hdr won't be zeroed
> when ol_flags doesn't specify any Tx offloads.

Right, good catch.
It may be better to remove this small optimization.
Indeed, with the series, if the application does not enable offloads,
then the Virtio features are re-negotiated with the offload features.

Thanks,
Maxime

> Best regards,
> Tiwei Bie
>
  
Tiwei Bie June 5, 2018, 11:20 a.m. UTC | #5
On Tue, Jun 05, 2018 at 11:43:11AM +0200, Maxime Coquelin wrote:
> On 06/05/2018 05:10 AM, Tiwei Bie wrote:
> > On Mon, Jun 04, 2018 at 04:29:56PM +0200, Maxime Coquelin wrote:
> > > On 06/04/2018 01:55 PM, Tiwei Bie wrote:
> > > > On Fri, Jun 01, 2018 at 02:47:58PM +0200, Maxime Coquelin wrote:
> > [...]
> > > > > @@ -253,13 +246,15 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
> > > > >    	struct virtio_net_hdr *hdr;
> > > > >    	int offload;
> > > > > -	offload = tx_offload_enabled(vq->hw);
> > > > >    	head_idx = vq->vq_desc_head_idx;
> > > > >    	idx = head_idx;
> > > > >    	dxp = &vq->vq_descx[idx];
> > > > >    	dxp->cookie = (void *)cookie;
> > > > >    	dxp->ndescs = needed;
> > > > > +	offload = vq->hw->has_tx_offload &&
> > > > > +		(cookie->ol_flags & PKT_TX_OFFLOAD_MASK);
> > > > 
> > > > If features aren't negotiated, I think there is no need to
> > > > check ol_flags and update the net header.
> > > 
> > > Isn't what the code is doing?
> > > has_tx_offload will be false if none of the Tx offload features have
> > > been negotiated, so ol_flags won't be checked in that case.
> > 
> > Hmm.. Somehow I treated 'and' as 'or'..
> > 
> > I have another question. When 'can_push' is false
> > and 'vq->hw->has_tx_offload' is true, there will
> > be a chance that virtio net hdr won't be zeroed
> > when ol_flags doesn't specify any Tx offloads.
> 
> Right, good catch.
> It may be better to remove this small optimization.
> Indeed, with the series, if the application does not enable offloads,
> then the Virtio features are re-negotiated with the offload features.

Yeah. It's a good idea to disable the features when
the corresponding Tx offloads aren't requested by
the applications! I like it!

This issue happens for the mbufs whose ol_flags
doesn't specify Tx offloads when applications
enable Tx offloads and can_push is false. I think
when applications enable Tx offloads, although
most packets to be sent will have Tx offloads
specified in their ol_flags, it's still possible
that some packets don't have Tx offloads specified
in their ol_flags.

Best regards,
Tiwei Bie

> 
> Thanks,
> Maxime
> 
> > Best regards,
> > Tiwei Bie
> >
  
Maxime Coquelin June 5, 2018, 11:58 a.m. UTC | #6
On 06/05/2018 01:20 PM, Tiwei Bie wrote:
> On Tue, Jun 05, 2018 at 11:43:11AM +0200, Maxime Coquelin wrote:
>> On 06/05/2018 05:10 AM, Tiwei Bie wrote:
>>> On Mon, Jun 04, 2018 at 04:29:56PM +0200, Maxime Coquelin wrote:
>>>> On 06/04/2018 01:55 PM, Tiwei Bie wrote:
>>>>> On Fri, Jun 01, 2018 at 02:47:58PM +0200, Maxime Coquelin wrote:
>>> [...]
>>>>>> @@ -253,13 +246,15 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
>>>>>>     	struct virtio_net_hdr *hdr;
>>>>>>     	int offload;
>>>>>> -	offload = tx_offload_enabled(vq->hw);
>>>>>>     	head_idx = vq->vq_desc_head_idx;
>>>>>>     	idx = head_idx;
>>>>>>     	dxp = &vq->vq_descx[idx];
>>>>>>     	dxp->cookie = (void *)cookie;
>>>>>>     	dxp->ndescs = needed;
>>>>>> +	offload = vq->hw->has_tx_offload &&
>>>>>> +		(cookie->ol_flags & PKT_TX_OFFLOAD_MASK);
>>>>>
>>>>> If features aren't negotiated, I think there is no need to
>>>>> check ol_flags and update the net header.
>>>>
>>>> Isn't what the code is doing?
>>>> has_tx_offload will be false if none of the Tx offload features have
>>>> been negotiated, so ol_flags won't be checked in that case.
>>>
>>> Hmm.. Somehow I treated 'and' as 'or'..
>>>
>>> I have another question. When 'can_push' is false
>>> and 'vq->hw->has_tx_offload' is true, there will
>>> be a chance that virtio net hdr won't be zeroed
>>> when ol_flags doesn't specify any Tx offloads.
>>
>> Right, good catch.
>> It may be better to remove this small optimization.
>> Indeed, with the series, if the application does not enable offloads,
>> then the Virtio features are re-negotiated with the offload features.
> 
> Yeah. It's a good idea to disable the features when
> the corresponding Tx offloads aren't requested by
> the applications! I like it!
> 
> This issue happens for the mbufs whose ol_flags
> doesn't specify Tx offloads when applications
> enable Tx offloads and can_push is false. I think
> when applications enable Tx offloads, although
> most packets to be sent will have Tx offloads
> specified in their ol_flags, it's still possible
> that some packets don't have Tx offloads specified
> in their ol_flags.

Reading again my reply, I think it wasn't clear enough,
let me rephrase it.

My proposal is to keep disabling the features if the corresponding
Tx offloads aren't negotiated by the application, but just to remove the
check on mbuf's ol_flags, so:
offload = vq->hw->has_tx_offload;

Doing that, we retrieve the old behaviour, i.e. if Virtio features are
negotiated but no ol_flags set, virtio-net header will be cleared.

Maxime
> Best regards,
> Tiwei Bie
> 
>>
>> Thanks,
>> Maxime
>>
>>> Best regards,
>>> Tiwei Bie
>>>
  
Tiwei Bie June 5, 2018, 12:21 p.m. UTC | #7
On Tue, Jun 05, 2018 at 01:58:00PM +0200, Maxime Coquelin wrote:
> On 06/05/2018 01:20 PM, Tiwei Bie wrote:
> > On Tue, Jun 05, 2018 at 11:43:11AM +0200, Maxime Coquelin wrote:
> > > On 06/05/2018 05:10 AM, Tiwei Bie wrote:
> > > > On Mon, Jun 04, 2018 at 04:29:56PM +0200, Maxime Coquelin wrote:
> > > > > On 06/04/2018 01:55 PM, Tiwei Bie wrote:
> > > > > > On Fri, Jun 01, 2018 at 02:47:58PM +0200, Maxime Coquelin wrote:
> > > > [...]
> > > > > > > @@ -253,13 +246,15 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
> > > > > > >     	struct virtio_net_hdr *hdr;
> > > > > > >     	int offload;
> > > > > > > -	offload = tx_offload_enabled(vq->hw);
> > > > > > >     	head_idx = vq->vq_desc_head_idx;
> > > > > > >     	idx = head_idx;
> > > > > > >     	dxp = &vq->vq_descx[idx];
> > > > > > >     	dxp->cookie = (void *)cookie;
> > > > > > >     	dxp->ndescs = needed;
> > > > > > > +	offload = vq->hw->has_tx_offload &&
> > > > > > > +		(cookie->ol_flags & PKT_TX_OFFLOAD_MASK);
> > > > > > 
> > > > > > If features aren't negotiated, I think there is no need to
> > > > > > check ol_flags and update the net header.
> > > > > 
> > > > > Isn't what the code is doing?
> > > > > has_tx_offload will be false if none of the Tx offload features have
> > > > > been negotiated, so ol_flags won't be checked in that case.
> > > > 
> > > > Hmm.. Somehow I treated 'and' as 'or'..
> > > > 
> > > > I have another question. When 'can_push' is false
> > > > and 'vq->hw->has_tx_offload' is true, there will
> > > > be a chance that virtio net hdr won't be zeroed
> > > > when ol_flags doesn't specify any Tx offloads.
> > > 
> > > Right, good catch.
> > > It may be better to remove this small optimization.
> > > Indeed, with the series, if the application does not enable offloads,
> > > then the Virtio features are re-negotiated with the offload features.
> > 
> > Yeah. It's a good idea to disable the features when
> > the corresponding Tx offloads aren't requested by
> > the applications! I like it!
> > 
> > This issue happens for the mbufs whose ol_flags
> > doesn't specify Tx offloads when applications
> > enable Tx offloads and can_push is false. I think
> > when applications enable Tx offloads, although
> > most packets to be sent will have Tx offloads
> > specified in their ol_flags, it's still possible
> > that some packets don't have Tx offloads specified
> > in their ol_flags.
> 
> Reading again my reply, I think it wasn't clear enough,
> let me rephrase it.
> 
> My proposal is to keep disabling the features if the corresponding
> Tx offloads aren't negotiated by the application, but just to remove the
> check on mbuf's ol_flags, so:
> offload = vq->hw->has_tx_offload;
> 
> Doing that, we retrieve the old behaviour, i.e. if Virtio features are
> negotiated but no ol_flags set, virtio-net header will be cleared.

It sounds good! Thanks!

Best regards,
Tiwei Bie
  

Patch

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index d481b282e..981e0994a 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -1790,6 +1790,22 @@  rte_virtio_pmd_init(void)
 	rte_pci_register(&rte_virtio_pmd);
 }
 
+static inline int
+rx_offload_enabled(struct virtio_hw *hw)
+{
+	return vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_CSUM) ||
+		vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO4) ||
+		vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO6);
+}
+
+static inline int
+tx_offload_enabled(struct virtio_hw *hw)
+{
+	return vtpci_with_feature(hw, VIRTIO_NET_F_CSUM) ||
+		vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO4) ||
+		vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO6);
+}
+
 /*
  * Configure virtio device
  * It returns 0 on success.
@@ -1869,6 +1885,9 @@  virtio_dev_configure(struct rte_eth_dev *dev)
 		return -ENOTSUP;
 	}
 
+	hw->has_tx_offload = !!tx_offload_enabled(hw);
+	hw->has_rx_offload = !!rx_offload_enabled(hw);
+
 	if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
 		/* Enable vector (0) for Link State Intrerrupt */
 		if (VTPCI_OPS(hw)->set_config_irq(hw, 0) ==
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index a28ba8339..e0bb871f2 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -233,6 +233,8 @@  struct virtio_hw {
 	uint8_t     modern;
 	uint8_t     use_simple_rx;
 	uint8_t     use_simple_tx;
+	uint8_t		has_tx_offload;
+	uint8_t		has_rx_offload;
 	uint16_t    port_id;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
 	uint32_t    notify_off_multiplier;
diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index 92fab2174..3f113a118 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -225,13 +225,6 @@  virtio_tso_fix_cksum(struct rte_mbuf *m)
 	}
 }
 
-static inline int
-tx_offload_enabled(struct virtio_hw *hw)
-{
-	return vtpci_with_feature(hw, VIRTIO_NET_F_CSUM) ||
-		vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO4) ||
-		vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO6);
-}
 
 /* avoid write operation when necessary, to lessen cache issues */
 #define ASSIGN_UNLESS_EQUAL(var, val) do {	\
@@ -253,13 +246,15 @@  virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
 	struct virtio_net_hdr *hdr;
 	int offload;
 
-	offload = tx_offload_enabled(vq->hw);
 	head_idx = vq->vq_desc_head_idx;
 	idx = head_idx;
 	dxp = &vq->vq_descx[idx];
 	dxp->cookie = (void *)cookie;
 	dxp->ndescs = needed;
 
+	offload = vq->hw->has_tx_offload &&
+		(cookie->ol_flags & PKT_TX_OFFLOAD_MASK);
+
 	start_dp = vq->vq_ring.desc;
 
 	if (can_push) {
@@ -270,7 +265,6 @@  virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
 		 * which is wrong. Below subtract restores correct pkt size.
 		 */
 		cookie->pkt_len -= head_size;
-		/* if offload disabled, it is not zeroed below, do it now */
 		if (offload == 0) {
 			ASSIGN_UNLESS_EQUAL(hdr->csum_start, 0);
 			ASSIGN_UNLESS_EQUAL(hdr->csum_offset, 0);
@@ -686,14 +680,6 @@  virtio_rx_offload(struct rte_mbuf *m, struct virtio_net_hdr *hdr)
 	return 0;
 }
 
-static inline int
-rx_offload_enabled(struct virtio_hw *hw)
-{
-	return vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_CSUM) ||
-		vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO4) ||
-		vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO6);
-}
-
 #define VIRTIO_MBUF_BURST_SZ 64
 #define DESC_PER_CACHELINE (RTE_CACHE_LINE_SIZE / sizeof(struct vring_desc))
 uint16_t
@@ -709,7 +695,6 @@  virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	int error;
 	uint32_t i, nb_enqueued;
 	uint32_t hdr_size;
-	int offload;
 	struct virtio_net_hdr *hdr;
 
 	nb_rx = 0;
@@ -731,7 +716,6 @@  virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 
 	nb_enqueued = 0;
 	hdr_size = hw->vtnet_hdr_size;
-	offload = rx_offload_enabled(hw);
 
 	for (i = 0; i < num ; i++) {
 		rxm = rcv_pkts[i];
@@ -760,7 +744,7 @@  virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 		if (hw->vlan_strip)
 			rte_vlan_strip(rxm);
 
-		if (offload && virtio_rx_offload(rxm, hdr) < 0) {
+		if (hw->has_rx_offload && virtio_rx_offload(rxm, hdr) < 0) {
 			virtio_discard_rxbuf(vq, rxm);
 			rxvq->stats.errors++;
 			continue;
@@ -825,7 +809,6 @@  virtio_recv_mergeable_pkts(void *rx_queue,
 	uint16_t extra_idx;
 	uint32_t seg_res;
 	uint32_t hdr_size;
-	int offload;
 
 	nb_rx = 0;
 	if (unlikely(hw->started == 0))
@@ -843,7 +826,6 @@  virtio_recv_mergeable_pkts(void *rx_queue,
 	extra_idx = 0;
 	seg_res = 0;
 	hdr_size = hw->vtnet_hdr_size;
-	offload = rx_offload_enabled(hw);
 
 	while (i < nb_used) {
 		struct virtio_net_hdr_mrg_rxbuf *header;
@@ -888,7 +870,8 @@  virtio_recv_mergeable_pkts(void *rx_queue,
 		rx_pkts[nb_rx] = rxm;
 		prev = rxm;
 
-		if (offload && virtio_rx_offload(rxm, &header->hdr) < 0) {
+		if (hw->has_rx_offload &&
+				virtio_rx_offload(rxm, &header->hdr) < 0) {
 			virtio_discard_rxbuf(vq, rxm);
 			rxvq->stats.errors++;
 			continue;