[dpdk-dev] [PATCH 2/4] vhost: complete TSO settings

Yuanhan Liu yuanhan.liu at linux.intel.com
Fri Mar 25 07:01:32 CET 2016


Commit d0cf91303d73 ("vhost: add Tx offload capabilities") has only
done partial settings for enabling TSO, and left the following part
to the application, say vhost-switch example, by commit 9fd72e3cbd29
("examples/vhost: add virtio offload").

- Setting PKT_TX_IP_CKSUM and ipv4_hdr->hdr_checksum = 0 for IPv4.

- calculate the pseudo header checksum without taking ip_len in
  account, and set it in the TCP header

Here we complete the left part in vhost side, so that an user (such
as OVS) can do minimal (or even no) changes to get TSO enabled.

Signed-off-by: Yuanhan Liu <yuanhan.liu at linux.intel.com>
---
 lib/librte_vhost/vhost_rxtx.c | 47 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 35 insertions(+), 12 deletions(-)

diff --git a/lib/librte_vhost/vhost_rxtx.c b/lib/librte_vhost/vhost_rxtx.c
index 7d1224c..a204703 100644
--- a/lib/librte_vhost/vhost_rxtx.c
+++ b/lib/librte_vhost/vhost_rxtx.c
@@ -602,11 +602,11 @@ rte_vhost_enqueue_burst(struct virtio_net *dev, uint16_t queue_id,
 }
 
 static void
-parse_ethernet(struct rte_mbuf *m, uint16_t *l4_proto, void **l4_hdr)
+parse_ethernet(struct rte_mbuf *m, void **l3_hdr,
+	       void **l4_hdr, uint16_t *l4_proto)
 {
 	struct ipv4_hdr *ipv4_hdr;
 	struct ipv6_hdr *ipv6_hdr;
-	void *l3_hdr = NULL;
 	struct ether_hdr *eth_hdr;
 	uint16_t ethertype;
 
@@ -622,21 +622,19 @@ parse_ethernet(struct rte_mbuf *m, uint16_t *l4_proto, void **l4_hdr)
 		ethertype = rte_be_to_cpu_16(vlan_hdr->eth_proto);
 	}
 
-	l3_hdr = (char *)eth_hdr + m->l2_len;
+	*l3_hdr = (char *)eth_hdr + m->l2_len;
 
 	switch (ethertype) {
 	case ETHER_TYPE_IPv4:
-		ipv4_hdr = (struct ipv4_hdr *)l3_hdr;
+		ipv4_hdr  = *l3_hdr;
 		*l4_proto = ipv4_hdr->next_proto_id;
 		m->l3_len = (ipv4_hdr->version_ihl & 0x0f) * 4;
-		*l4_hdr = (char *)l3_hdr + m->l3_len;
 		m->ol_flags |= PKT_TX_IPV4;
 		break;
 	case ETHER_TYPE_IPv6:
-		ipv6_hdr = (struct ipv6_hdr *)l3_hdr;
+		ipv6_hdr = *l3_hdr;
 		*l4_proto = ipv6_hdr->proto;
 		m->l3_len = sizeof(struct ipv6_hdr);
-		*l4_hdr = (char *)l3_hdr + m->l3_len;
 		m->ol_flags |= PKT_TX_IPV6;
 		break;
 	default:
@@ -644,16 +642,28 @@ parse_ethernet(struct rte_mbuf *m, uint16_t *l4_proto, void **l4_hdr)
 		*l4_proto = 0;
 		break;
 	}
+
+	*l4_hdr = (char *)*l3_hdr + m->l3_len;
+}
+
+static uint16_t
+get_psd_sum(void *l3_hdr, uint64_t ol_flags)
+{
+	if (ol_flags & PKT_TX_IPV4)
+		return rte_ipv4_phdr_cksum(l3_hdr, ol_flags);
+	else
+		return rte_ipv6_phdr_cksum(l3_hdr, ol_flags);
 }
 
 static inline void __attribute__((always_inline))
 vhost_dequeue_offload(struct virtio_net_hdr *hdr, struct rte_mbuf *m)
 {
-	uint16_t l4_proto = 0;
-	void *l4_hdr = NULL;
-	struct tcp_hdr *tcp_hdr = NULL;
+	void *l3_hdr;
+	void *l4_hdr;
+	uint16_t l4_proto;
+
+	parse_ethernet(m, &l3_hdr, &l4_hdr, &l4_proto);
 
-	parse_ethernet(m, &l4_proto, &l4_hdr);
 	if (hdr->flags == VIRTIO_NET_HDR_F_NEEDS_CSUM) {
 		if (hdr->csum_start == (m->l2_len + m->l3_len)) {
 			switch (hdr->csum_offset) {
@@ -676,13 +686,26 @@ vhost_dequeue_offload(struct virtio_net_hdr *hdr, struct rte_mbuf *m)
 	}
 
 	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+		struct ipv4_hdr *ipv4_hdr = l3_hdr;
+		struct tcp_hdr *tcp_hdr   = l4_hdr;
+
 		switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
 		case VIRTIO_NET_HDR_GSO_TCPV4:
+			/*
+			 * According to comments for PKT_TX_TCP_SEG
+			 * at rte_mbuf.h, we need following settings
+			 * for IPv4.
+			 */
+			m->ol_flags |= PKT_TX_IP_CKSUM;
+			ipv4_hdr->hdr_checksum = 0;
+
+			/* Fall through */
 		case VIRTIO_NET_HDR_GSO_TCPV6:
-			tcp_hdr = (struct tcp_hdr *)l4_hdr;
 			m->ol_flags |= PKT_TX_TCP_SEG;
 			m->tso_segsz = hdr->gso_size;
 			m->l4_len = (tcp_hdr->data_off & 0xf0) >> 2;
+
+			tcp_hdr->cksum = get_psd_sum(l3_hdr, m->ol_flags);
 			break;
 		default:
 			RTE_LOG(WARNING, VHOST_DATA,
-- 
1.9.0



More information about the dev mailing list