[5/6] dpdk: TX - set checksum calculation offload flags

Message ID 1496241660-27492-6-git-send-email-bogdan.pricope@linaro.org
State New
Headers show
Series
  • dpdk pktio: enable hardware checksum support
Related show

Commit Message

Bogdan Pricope May 31, 2017, 2:40 p.m.
Signed-off-by: Bogdan Pricope <bogdan.pricope@linaro.org>

---
 platform/linux-generic/pktio/dpdk.c | 105 ++++++++++++++++++++++++++++++++++--
 1 file changed, 102 insertions(+), 3 deletions(-)

-- 
1.9.1

Patch hide | download patch | download mbox

diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c
index 58e6db0..b721bf6 100644
--- a/platform/linux-generic/pktio/dpdk.c
+++ b/platform/linux-generic/pktio/dpdk.c
@@ -27,6 +27,10 @@ 
 #include <rte_config.h>
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
+#include <rte_ip.h>
+#include <rte_ip_frag.h>
+#include <rte_udp.h>
+#include <rte_tcp.h>
 #include <rte_string_fns.h>
 
 static int disable_pktio; /** !0 this pktio disabled, 0 enabled */
@@ -772,6 +776,41 @@  fail:
 	return (i > 0 ? i : -1);
 }
 
+static inline int packet_parse(void *l3_hdr, uint8_t *l3_proto_v4,
+			       uint8_t *l4_proto)
+{
+	uint8_t l3_proto_ver = _ODP_IPV4HDR_VER(*(uint8_t *)l3_hdr);
+
+	if (l3_proto_ver == _ODP_IPV4) {
+		struct ipv4_hdr *ip = (struct ipv4_hdr *)l3_hdr;
+
+		*l3_proto_v4 = 1;
+		if (!rte_ipv4_frag_pkt_is_fragmented(ip))
+			*l4_proto = ip->next_proto_id;
+		else
+			*l4_proto = 0;
+
+		return 0;
+	} else if (l3_proto_ver == _ODP_IPV6) {
+		struct ipv6_hdr *ipv6 = (struct ipv6_hdr *)l3_hdr;
+
+		*l3_proto_v4 = 0;
+		*l4_proto = ipv6->proto;
+		return 0;
+	}
+
+	return -1;
+}
+
+static inline uint16_t phdr_csum(int ipv4, void *l3_hdr,
+				 uint64_t ol_flags)
+{
+	if (ipv4)
+		return rte_ipv4_phdr_cksum(l3_hdr, ol_flags);
+	else /*ipv6*/
+		return rte_ipv6_phdr_cksum(l3_hdr, ol_flags);
+}
+
 static inline int pkt_to_mbuf(pktio_entry_t *pktio_entry,
 			      struct rte_mbuf *mbuf_table[],
 			      const odp_packet_t pkt_table[], uint16_t num)
@@ -779,15 +818,30 @@  static inline int pkt_to_mbuf(pktio_entry_t *pktio_entry,
 	pkt_dpdk_t *pkt_dpdk = &pktio_entry->s.pkt_dpdk;
 	int i, j;
 	char *data;
+	odp_packet_t pkt;
 	uint16_t pkt_len;
+	packet_parser_t *pkt_p;
+	struct rte_mbuf *mbuf;
+	void *l3_hdr, *l4_hdr;
+	odp_bool_t ipv4_chksum_cfg, udp_chksum_cfg, tcp_chksum_cfg;
+	odp_bool_t ipv4_chksum_pkt, udp_chksum_pkt, tcp_chksum_pkt;
+	uint8_t l3_proto_v4, l4_proto;
 
 	if (odp_unlikely((rte_pktmbuf_alloc_bulk(pkt_dpdk->pkt_pool,
 						 mbuf_table, num)))) {
 		ODP_ERR("Failed to alloc mbuf\n");
 		return 0;
 	}
+
+	ipv4_chksum_cfg = pktio_entry->s.config.pktout.bit.ipv4_chksum;
+	udp_chksum_cfg = pktio_entry->s.config.pktout.bit.udp_chksum;
+	tcp_chksum_cfg = pktio_entry->s.config.pktout.bit.tcp_chksum;
+
 	for (i = 0; i < num; i++) {
-		pkt_len = _odp_packet_len(pkt_table[i]);
+		mbuf = mbuf_table[i];
+		pkt = pkt_table[i];
+		pkt_len = _odp_packet_len(pkt);
+		pkt_p = &odp_packet_hdr(pkt)->p;
 
 		if (pkt_len > pkt_dpdk->mtu) {
 			if (i == 0)
@@ -796,9 +850,54 @@  static inline int pkt_to_mbuf(pktio_entry_t *pktio_entry,
 		}
 
 		/* Packet always fits in mbuf */
-		data = rte_pktmbuf_append(mbuf_table[i], pkt_len);
+		data = rte_pktmbuf_append(mbuf, pkt_len);
+
+		odp_packet_copy_to_mem(pkt, 0, pkt_len, data);
+
+		if (!pktio_entry->s.config.pktout.all_bits)
+			continue;
+
+		l3_hdr = (void *)(data + pkt_p->l3_offset);
+
+		if (packet_parse(l3_hdr, &l3_proto_v4, &l4_proto))
+			continue;
+
+		ipv4_chksum_pkt = ipv4_chksum_cfg && l3_proto_v4;
+		udp_chksum_pkt = udp_chksum_cfg &&
+			(l4_proto == _ODP_IPPROTO_UDP);
+		tcp_chksum_pkt = tcp_chksum_cfg &&
+			(l4_proto == _ODP_IPPROTO_TCP);
+
+		if (!ipv4_chksum_pkt && !udp_chksum_pkt && !tcp_chksum_pkt)
+			continue;
+
+		mbuf->l2_len = pkt_p->l3_offset - pkt_p->l2_offset;
+		mbuf->l3_len = pkt_p->l4_offset - pkt_p->l3_offset;
 
-		odp_packet_copy_to_mem(pkt_table[i], 0, pkt_len, data);
+		if (l3_proto_v4)
+			mbuf->ol_flags = PKT_TX_IPV4;
+		else
+			mbuf->ol_flags = PKT_TX_IPV6;
+
+		if (ipv4_chksum_pkt) {
+			mbuf->ol_flags |=  PKT_TX_IP_CKSUM;
+
+			((struct ipv4_hdr *)l3_hdr)->hdr_checksum = 0;
+		}
+
+		l4_hdr = (void *)(data + pkt_p->l4_offset);
+
+		if (udp_chksum_pkt) {
+			mbuf->ol_flags |= PKT_TX_UDP_CKSUM;
+
+			((struct udp_hdr *)l4_hdr)->dgram_cksum =
+				phdr_csum(l3_proto_v4, l3_hdr, mbuf->ol_flags);
+		} else if (tcp_chksum_pkt) {
+			mbuf->ol_flags |= PKT_TX_TCP_CKSUM;
+
+			((struct tcp_hdr *)l4_hdr)->cksum =
+				phdr_csum(l3_proto_v4, l3_hdr, mbuf->ol_flags);
+		}
 	}
 	return i;