[dpdk-dev,RFC,4/8] driver/virtio:enqueue TSO offload

Message ID 1441014108-3125-5-git-send-email-jijiang.liu@intel.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

Jijiang Liu Aug. 31, 2015, 9:41 a.m. UTC
  Enqueue TSO4/6 offload.

Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
---
 drivers/net/virtio/virtio_rxtx.c |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)
  

Comments

Ouyang Changchun Sept. 1, 2015, 3:28 a.m. UTC | #1
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jijiang Liu
> Sent: Monday, August 31, 2015 5:42 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO offload
> 
> Enqueue TSO4/6 offload.
> 
> Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
> ---
>  drivers/net/virtio/virtio_rxtx.c |   23 +++++++++++++++++++++++
>  1 files changed, 23 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
> index c5b53bb..4c2d838 100644
> --- a/drivers/net/virtio/virtio_rxtx.c
> +++ b/drivers/net/virtio/virtio_rxtx.c
> @@ -198,6 +198,28 @@ virtqueue_enqueue_recv_refill(struct virtqueue *vq,
> struct rte_mbuf *cookie)
>  	return 0;
>  }
> 
> +static void
> +virtqueue_enqueue_offload(struct virtqueue *txvq, struct rte_mbuf *m,
> +			uint16_t idx, uint16_t hdr_sz)
> +{
> +	struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)(uintptr_t)
> +				(txvq->virtio_net_hdr_addr + idx * hdr_sz);
> +
> +	if (m->tso_segsz != 0 && m->ol_flags & PKT_TX_TCP_SEG) {
> +		if (m->ol_flags & PKT_TX_IPV4) {
> +			if (!vtpci_with_feature(txvq->hw,
> VIRTIO_NET_F_HOST_TSO4))
> +				return;

Do we need return error if host can't handle tso for the packet?

> +			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
> +		} else if (m->ol_flags & PKT_TX_IPV6) {
> +			if (!vtpci_with_feature(txvq->hw,
> VIRTIO_NET_F_HOST_TSO6))
> +				return;

Same as above

> +			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
> +		}

Do we need else branch for the case of neither tcpv4 nor tcpv6?

> +		hdr->gso_size = m->tso_segsz;
> +		hdr->hdr_len = m->l2_len + m->l3_len + m->l4_len;
> +	}
> +}
> +
>  static int
>  virtqueue_enqueue_xmit(struct virtqueue *txvq, struct rte_mbuf *cookie)
> { @@ -221,6 +243,7 @@ virtqueue_enqueue_xmit(struct virtqueue *txvq,
> struct rte_mbuf *cookie)
>  	dxp->cookie = (void *)cookie;
>  	dxp->ndescs = needed;
> 
> +	virtqueue_enqueue_offload(txvq, cookie, idx, head_size);

If TSO is not enabled in the feature bit, how to resolve here?

>  	start_dp = txvq->vq_ring.desc;
>  	start_dp[idx].addr =
>  		txvq->virtio_net_hdr_mem + idx * head_size;
> --
> 1.7.7.6
  
Jijiang Liu Sept. 7, 2015, 6:11 a.m. UTC | #2
> -----Original Message-----
> From: Ouyang, Changchun
> Sent: Monday, August 31, 2015 8:29 PM
> To: Liu, Jijiang; dev@dpdk.org
> Cc: Ouyang, Changchun
> Subject: RE: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO offload
> 
> 
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jijiang Liu
> > Sent: Monday, August 31, 2015 5:42 PM
> > To: dev@dpdk.org
> > Subject: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO offload
> >
> > Enqueue TSO4/6 offload.
> >
> > Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
> > ---
> >  drivers/net/virtio/virtio_rxtx.c |   23 +++++++++++++++++++++++
> >  1 files changed, 23 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/net/virtio/virtio_rxtx.c
> > b/drivers/net/virtio/virtio_rxtx.c
> > index c5b53bb..4c2d838 100644
> > --- a/drivers/net/virtio/virtio_rxtx.c
> > +++ b/drivers/net/virtio/virtio_rxtx.c
> > @@ -198,6 +198,28 @@ virtqueue_enqueue_recv_refill(struct virtqueue
> > *vq, struct rte_mbuf *cookie)
> >  	return 0;
> >  }
> >
> > +static void
> > +virtqueue_enqueue_offload(struct virtqueue *txvq, struct rte_mbuf *m,
> > +			uint16_t idx, uint16_t hdr_sz)
> > +{
> > +	struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)(uintptr_t)
> > +				(txvq->virtio_net_hdr_addr + idx * hdr_sz);
> > +
> > +	if (m->tso_segsz != 0 && m->ol_flags & PKT_TX_TCP_SEG) {
> > +		if (m->ol_flags & PKT_TX_IPV4) {
> > +			if (!vtpci_with_feature(txvq->hw,
> > VIRTIO_NET_F_HOST_TSO4))
> > +				return;
> 
> Do we need return error if host can't handle tso for the packet?
> 
> > +			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
> > +		} else if (m->ol_flags & PKT_TX_IPV6) {
> > +			if (!vtpci_with_feature(txvq->hw,
> > VIRTIO_NET_F_HOST_TSO6))
> > +				return;
> 
> Same as above
> 
> > +			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
> > +		}
> 
> Do we need else branch for the case of neither tcpv4 nor tcpv6?
> 
> > +		hdr->gso_size = m->tso_segsz;
> > +		hdr->hdr_len = m->l2_len + m->l3_len + m->l4_len;
> > +	}
> > +}
> > +
> >  static int
> >  virtqueue_enqueue_xmit(struct virtqueue *txvq, struct rte_mbuf
> > *cookie) { @@ -221,6 +243,7 @@ virtqueue_enqueue_xmit(struct virtqueue
> > *txvq, struct rte_mbuf *cookie)
> >  	dxp->cookie = (void *)cookie;
> >  	dxp->ndescs = needed;
> >
> > +	virtqueue_enqueue_offload(txvq, cookie, idx, head_size);
> 
> If TSO is not enabled in the feature bit, how to resolve here?

The TSO enablement  check is in the function.

If TSO is not enabled, and don't need to fill virtio_net_hdr now.

> >  	start_dp = txvq->vq_ring.desc;
> >  	start_dp[idx].addr =
> >  		txvq->virtio_net_hdr_mem + idx * head_size;
> > --
> > 1.7.7.6
  
Ouyang Changchun Sept. 9, 2015, 1:17 a.m. UTC | #3
> -----Original Message-----
> From: Liu, Jijiang
> Sent: Monday, September 7, 2015 2:11 PM
> To: Ouyang, Changchun; dev@dpdk.org
> Subject: RE: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO offload
> 
> 
> 
> > -----Original Message-----
> > From: Ouyang, Changchun
> > Sent: Monday, August 31, 2015 8:29 PM
> > To: Liu, Jijiang; dev@dpdk.org
> > Cc: Ouyang, Changchun
> > Subject: RE: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO
> > offload
> >
> >
> >
> > > -----Original Message-----
> > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jijiang Liu
> > > Sent: Monday, August 31, 2015 5:42 PM
> > > To: dev@dpdk.org
> > > Subject: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO
> > > offload
> > >
> > > Enqueue TSO4/6 offload.
> > >
> > > Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
> > > ---
> > >  drivers/net/virtio/virtio_rxtx.c |   23 +++++++++++++++++++++++
> > >  1 files changed, 23 insertions(+), 0 deletions(-)
> > >
> > > diff --git a/drivers/net/virtio/virtio_rxtx.c
> > > b/drivers/net/virtio/virtio_rxtx.c
> > > index c5b53bb..4c2d838 100644
> > > --- a/drivers/net/virtio/virtio_rxtx.c
> > > +++ b/drivers/net/virtio/virtio_rxtx.c
> > > @@ -198,6 +198,28 @@ virtqueue_enqueue_recv_refill(struct virtqueue
> > > *vq, struct rte_mbuf *cookie)
> > >  	return 0;
> > >  }
> > >
> > > +static void
> > > +virtqueue_enqueue_offload(struct virtqueue *txvq, struct rte_mbuf
> *m,
> > > +			uint16_t idx, uint16_t hdr_sz)
> > > +{
> > > +	struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)(uintptr_t)
> > > +				(txvq->virtio_net_hdr_addr + idx * hdr_sz);
> > > +
> > > +	if (m->tso_segsz != 0 && m->ol_flags & PKT_TX_TCP_SEG) {
> > > +		if (m->ol_flags & PKT_TX_IPV4) {
> > > +			if (!vtpci_with_feature(txvq->hw,
> > > VIRTIO_NET_F_HOST_TSO4))
> > > +				return;
> >
> > Do we need return error if host can't handle tso for the packet?
> >
> > > +			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
> > > +		} else if (m->ol_flags & PKT_TX_IPV6) {
> > > +			if (!vtpci_with_feature(txvq->hw,
> > > VIRTIO_NET_F_HOST_TSO6))
> > > +				return;
> >
> > Same as above
> >
> > > +			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
> > > +		}
> >
> > Do we need else branch for the case of neither tcpv4 nor tcpv6?
> >
> > > +		hdr->gso_size = m->tso_segsz;
> > > +		hdr->hdr_len = m->l2_len + m->l3_len + m->l4_len;
> > > +	}
> > > +}
> > > +
> > >  static int
> > >  virtqueue_enqueue_xmit(struct virtqueue *txvq, struct rte_mbuf
> > > *cookie) { @@ -221,6 +243,7 @@ virtqueue_enqueue_xmit(struct
> > > virtqueue *txvq, struct rte_mbuf *cookie)
> > >  	dxp->cookie = (void *)cookie;
> > >  	dxp->ndescs = needed;
> > >
> > > +	virtqueue_enqueue_offload(txvq, cookie, idx, head_size);
> >
> > If TSO is not enabled in the feature bit, how to resolve here?
> 
> The TSO enablement  check is in the function.
> 
> If TSO is not enabled, and don't need to fill virtio_net_hdr now.

Here I mean if (m->ol_flags & PKT_TX_TCP_SEG) is true, that is to say, the virtio-pmd user expect do tso in vhost or virtio,
but the host feature bit doesn't support it, then it should handle this case,
either handle it in virtio pmd, or return error to caller. 
Otherwise the packet with flag tso maybe can't be send out normally.  
Am I right?

> 
> > >  	start_dp = txvq->vq_ring.desc;
> > >  	start_dp[idx].addr =
> > >  		txvq->virtio_net_hdr_mem + idx * head_size;
> > > --
> > > 1.7.7.6
  
Jijiang Liu Sept. 9, 2015, 5:21 p.m. UTC | #4
> -----Original Message-----
> From: Ouyang, Changchun
> Sent: Tuesday, September 8, 2015 6:18 PM
> To: Liu, Jijiang; dev@dpdk.org
> Cc: Ouyang, Changchun
> Subject: RE: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO offload
> 
> 
> 
> > -----Original Message-----
> > From: Liu, Jijiang
> > Sent: Monday, September 7, 2015 2:11 PM
> > To: Ouyang, Changchun; dev@dpdk.org
> > Subject: RE: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO
> > offload
> >
> >
> >
> > > -----Original Message-----
> > > From: Ouyang, Changchun
> > > Sent: Monday, August 31, 2015 8:29 PM
> > > To: Liu, Jijiang; dev@dpdk.org
> > > Cc: Ouyang, Changchun
> > > Subject: RE: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO
> > > offload
> > >
> > >
> > >
> > > > -----Original Message-----
> > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jijiang Liu
> > > > Sent: Monday, August 31, 2015 5:42 PM
> > > > To: dev@dpdk.org
> > > > Subject: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO
> > > > offload
> > > >
> > > > Enqueue TSO4/6 offload.
> > > >
> > > > Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
> > > > ---
> > > >  drivers/net/virtio/virtio_rxtx.c |   23 +++++++++++++++++++++++
> > > >  1 files changed, 23 insertions(+), 0 deletions(-)
> > > >
> > > > diff --git a/drivers/net/virtio/virtio_rxtx.c
> > > > b/drivers/net/virtio/virtio_rxtx.c
> > > > index c5b53bb..4c2d838 100644
> > > > --- a/drivers/net/virtio/virtio_rxtx.c
> > > > +++ b/drivers/net/virtio/virtio_rxtx.c
> > > > @@ -198,6 +198,28 @@ virtqueue_enqueue_recv_refill(struct
> > > > virtqueue *vq, struct rte_mbuf *cookie)
> > > >  	return 0;
> > > >  }
> > > >
> > > > +static void
> > > > +virtqueue_enqueue_offload(struct virtqueue *txvq, struct rte_mbuf
> > *m,
> > > > +			uint16_t idx, uint16_t hdr_sz) {
> > > > +	struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)(uintptr_t)
> > > > +				(txvq->virtio_net_hdr_addr + idx * hdr_sz);
> > > > +
> > > > +	if (m->tso_segsz != 0 && m->ol_flags & PKT_TX_TCP_SEG) {
> > > > +		if (m->ol_flags & PKT_TX_IPV4) {
> > > > +			if (!vtpci_with_feature(txvq->hw,
> > > > VIRTIO_NET_F_HOST_TSO4))
> > > > +				return;
> > >
> > > Do we need return error if host can't handle tso for the packet?
> > >
> > > > +			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
> > > > +		} else if (m->ol_flags & PKT_TX_IPV6) {
> > > > +			if (!vtpci_with_feature(txvq->hw,
> > > > VIRTIO_NET_F_HOST_TSO6))
> > > > +				return;
> > >
> > > Same as above
> > >
> > > > +			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
> > > > +		}
> > >
> > > Do we need else branch for the case of neither tcpv4 nor tcpv6?
> > >
> > > > +		hdr->gso_size = m->tso_segsz;
> > > > +		hdr->hdr_len = m->l2_len + m->l3_len + m->l4_len;
> > > > +	}
> > > > +}
> > > > +
> > > >  static int
> > > >  virtqueue_enqueue_xmit(struct virtqueue *txvq, struct rte_mbuf
> > > > *cookie) { @@ -221,6 +243,7 @@ virtqueue_enqueue_xmit(struct
> > > > virtqueue *txvq, struct rte_mbuf *cookie)
> > > >  	dxp->cookie = (void *)cookie;
> > > >  	dxp->ndescs = needed;
> > > >
> > > > +	virtqueue_enqueue_offload(txvq, cookie, idx, head_size);
> > >
> > > If TSO is not enabled in the feature bit, how to resolve here?
> >
> > The TSO enablement  check is in the function.
> >
> > If TSO is not enabled, and don't need to fill virtio_net_hdr now.
> 
> Here I mean if (m->ol_flags & PKT_TX_TCP_SEG) is true, that is to say, the virtio-
> pmd user expect do tso in vhost or virtio, but the host feature bit doesn't
> support it, then it should handle this case, either handle it in virtio pmd, or return
> error to caller.
> Otherwise the packet with flag tso maybe can't be send out normally.
> Am I right?
Not exactly, if host feature bit doesn't support TSO, and the TSO flag cannot been set in this function,
and then continue processing the packet in host. 
Now I think it had better return an error, and don't continue processing this packet.

> >
> > > >  	start_dp = txvq->vq_ring.desc;
> > > >  	start_dp[idx].addr =
> > > >  		txvq->virtio_net_hdr_mem + idx * head_size;
> > > > --
> > > > 1.7.7.6
  
Ouyang Changchun Sept. 9, 2015, 11:03 p.m. UTC | #5
> -----Original Message-----
> From: Liu, Jijiang
> Sent: Thursday, September 10, 2015 1:21 AM
> To: Ouyang, Changchun; dev@dpdk.org
> Subject: RE: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO offload
> 
> 
> 
> > -----Original Message-----
> > From: Ouyang, Changchun
> > Sent: Tuesday, September 8, 2015 6:18 PM
> > To: Liu, Jijiang; dev@dpdk.org
> > Cc: Ouyang, Changchun
> > Subject: RE: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO
> > offload
> >
> >
> >
> > > -----Original Message-----
> > > From: Liu, Jijiang
> > > Sent: Monday, September 7, 2015 2:11 PM
> > > To: Ouyang, Changchun; dev@dpdk.org
> > > Subject: RE: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO
> > > offload
> > >
> > >
> > >
> > > > -----Original Message-----
> > > > From: Ouyang, Changchun
> > > > Sent: Monday, August 31, 2015 8:29 PM
> > > > To: Liu, Jijiang; dev@dpdk.org
> > > > Cc: Ouyang, Changchun
> > > > Subject: RE: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO
> > > > offload
> > > >
> > > >
> > > >
> > > > > -----Original Message-----
> > > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jijiang Liu
> > > > > Sent: Monday, August 31, 2015 5:42 PM
> > > > > To: dev@dpdk.org
> > > > > Subject: [dpdk-dev] [RFC PATCH 4/8] driver/virtio:enqueue TSO
> > > > > offload
> > > > >
> > > > > Enqueue TSO4/6 offload.
> > > > >
> > > > > Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
> > > > > ---
> > > > >  drivers/net/virtio/virtio_rxtx.c |   23 +++++++++++++++++++++++
> > > > >  1 files changed, 23 insertions(+), 0 deletions(-)
> > > > >
> > > > > diff --git a/drivers/net/virtio/virtio_rxtx.c
> > > > > b/drivers/net/virtio/virtio_rxtx.c
> > > > > index c5b53bb..4c2d838 100644
> > > > > --- a/drivers/net/virtio/virtio_rxtx.c
> > > > > +++ b/drivers/net/virtio/virtio_rxtx.c
> > > > > @@ -198,6 +198,28 @@ virtqueue_enqueue_recv_refill(struct
> > > > > virtqueue *vq, struct rte_mbuf *cookie)
> > > > >  	return 0;
> > > > >  }
> > > > >
> > > > > +static void
> > > > > +virtqueue_enqueue_offload(struct virtqueue *txvq, struct
> > > > > +rte_mbuf
> > > *m,
> > > > > +			uint16_t idx, uint16_t hdr_sz) {
> > > > > +	struct virtio_net_hdr *hdr = (struct virtio_net_hdr
> *)(uintptr_t)
> > > > > +				(txvq->virtio_net_hdr_addr + idx *
> hdr_sz);
> > > > > +
> > > > > +	if (m->tso_segsz != 0 && m->ol_flags & PKT_TX_TCP_SEG) {
> > > > > +		if (m->ol_flags & PKT_TX_IPV4) {
> > > > > +			if (!vtpci_with_feature(txvq->hw,
> > > > > VIRTIO_NET_F_HOST_TSO4))
> > > > > +				return;
> > > >
> > > > Do we need return error if host can't handle tso for the packet?
> > > >
> > > > > +			hdr->gso_type =
> VIRTIO_NET_HDR_GSO_TCPV4;
> > > > > +		} else if (m->ol_flags & PKT_TX_IPV6) {
> > > > > +			if (!vtpci_with_feature(txvq->hw,
> > > > > VIRTIO_NET_F_HOST_TSO6))
> > > > > +				return;
> > > >
> > > > Same as above
> > > >
> > > > > +			hdr->gso_type =
> VIRTIO_NET_HDR_GSO_TCPV6;
> > > > > +		}
> > > >
> > > > Do we need else branch for the case of neither tcpv4 nor tcpv6?
> > > >
> > > > > +		hdr->gso_size = m->tso_segsz;
> > > > > +		hdr->hdr_len = m->l2_len + m->l3_len + m->l4_len;
> > > > > +	}
> > > > > +}
> > > > > +
> > > > >  static int
> > > > >  virtqueue_enqueue_xmit(struct virtqueue *txvq, struct rte_mbuf
> > > > > *cookie) { @@ -221,6 +243,7 @@ virtqueue_enqueue_xmit(struct
> > > > > virtqueue *txvq, struct rte_mbuf *cookie)
> > > > >  	dxp->cookie = (void *)cookie;
> > > > >  	dxp->ndescs = needed;
> > > > >
> > > > > +	virtqueue_enqueue_offload(txvq, cookie, idx, head_size);
> > > >
> > > > If TSO is not enabled in the feature bit, how to resolve here?
> > >
> > > The TSO enablement  check is in the function.
> > >
> > > If TSO is not enabled, and don't need to fill virtio_net_hdr now.
> >
> > Here I mean if (m->ol_flags & PKT_TX_TCP_SEG) is true, that is to say,
> > the virtio- pmd user expect do tso in vhost or virtio, but the host
> > feature bit doesn't support it, then it should handle this case,
> > either handle it in virtio pmd, or return error to caller.
> > Otherwise the packet with flag tso maybe can't be send out normally.
> > Am I right?
> Not exactly, if host feature bit doesn't support TSO, and the TSO flag cannot
> been set in this function, and then continue processing the packet in host.

TSO flag is set by upper level, so it could be set even if host feature bit doesn't support TSO,
You know the other path is also supporting TSO in guest feature bit.
Currently the virtio driver can't support TSO, at least we should return error for this possible case.

> Now I think it had better return an error, and don't continue processing this
> packet.
> 
> > >
> > > > >  	start_dp = txvq->vq_ring.desc;
> > > > >  	start_dp[idx].addr =
> > > > >  		txvq->virtio_net_hdr_mem + idx * head_size;
> > > > > --
> > > > > 1.7.7.6
  

Patch

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index c5b53bb..4c2d838 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -198,6 +198,28 @@  virtqueue_enqueue_recv_refill(struct virtqueue *vq, struct rte_mbuf *cookie)
 	return 0;
 }
 
+static void
+virtqueue_enqueue_offload(struct virtqueue *txvq, struct rte_mbuf *m,
+			uint16_t idx, uint16_t hdr_sz)
+{
+	struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)(uintptr_t)
+				(txvq->virtio_net_hdr_addr + idx * hdr_sz);
+
+	if (m->tso_segsz != 0 && m->ol_flags & PKT_TX_TCP_SEG) {
+		if (m->ol_flags & PKT_TX_IPV4) {
+			if (!vtpci_with_feature(txvq->hw, VIRTIO_NET_F_HOST_TSO4))
+				return;
+			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+		} else if (m->ol_flags & PKT_TX_IPV6) {
+			if (!vtpci_with_feature(txvq->hw, VIRTIO_NET_F_HOST_TSO6))
+				return;
+			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+		}
+		hdr->gso_size = m->tso_segsz;
+		hdr->hdr_len = m->l2_len + m->l3_len + m->l4_len;
+	}
+}
+
 static int
 virtqueue_enqueue_xmit(struct virtqueue *txvq, struct rte_mbuf *cookie)
 {
@@ -221,6 +243,7 @@  virtqueue_enqueue_xmit(struct virtqueue *txvq, struct rte_mbuf *cookie)
 	dxp->cookie = (void *)cookie;
 	dxp->ndescs = needed;
 
+	virtqueue_enqueue_offload(txvq, cookie, idx, head_size);
 	start_dp = txvq->vq_ring.desc;
 	start_dp[idx].addr =
 		txvq->virtio_net_hdr_mem + idx * head_size;