[RFCv2] dpdk: enable hardware checksum support

Message ID 1494830549-32730-2-git-send-email-bogdan.pricope@linaro.org
State New
Headers show

Commit Message

Bogdan Pricope May 15, 2017, 6:42 a.m.
Signed-off-by: Bogdan Pricope <bogdan.pricope@linaro.org>

---
 example/generator/odp_generator.c      | 102 ++++++++++++++++++++++++----
 platform/linux-generic/odp_packet_io.c |   2 +
 platform/linux-generic/pktio/dpdk.c    | 117 +++++++++++++++++++++++++++++++--
 3 files changed, 202 insertions(+), 19 deletions(-)

-- 
1.9.1

Comments

Elo, Matias (Nokia - FI/Espoo) May 15, 2017, 12:56 p.m. | #1
> On 15 May 2017, at 9:42, Bogdan Pricope <bogdan.pricope@linaro.org> wrote:

> 

> Signed-off-by: Bogdan Pricope <bogdan.pricope@linaro.org>

> ---

> example/generator/odp_generator.c      | 102 ++++++++++++++++++++++++----

> platform/linux-generic/odp_packet_io.c |   2 +

> platform/linux-generic/pktio/dpdk.c    | 117 +++++++++++++++++++++++++++++++--

> 3 files changed, 202 insertions(+), 19 deletions(-)

> 

> 

> diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c

> index 6ac89bd..8296908 100644

> --- a/platform/linux-generic/pktio/dpdk.c

> +++ b/platform/linux-generic/pktio/dpdk.c

> @@ -27,6 +27,9 @@

> #include <rte_config.h>

> #include <rte_mbuf.h>

> #include <rte_ethdev.h>

> +#include <rte_ip.h>

> +#include <rte_udp.h>

> +#include <rte_tcp.h>

> #include <rte_string_fns.h>

> 

> static int disable_pktio; /** !0 this pktio disabled, 0 enabled */

> @@ -189,6 +192,7 @@ static int dpdk_setup_port(pktio_entry_t *pktio_entry)

> 	int ret;

> 	pkt_dpdk_t *pkt_dpdk = &pktio_entry->s.pkt_dpdk;

> 	struct rte_eth_rss_conf rss_conf;

> +	uint16_t hw_ip_checksum = 0;

> 

> 	/* Always set some hash functions to enable DPDK RSS hash calculation */

> 	if (pkt_dpdk->hash.all_bits == 0) {

> @@ -198,13 +202,18 @@ static int dpdk_setup_port(pktio_entry_t *pktio_entry)

> 		rss_conf_to_hash_proto(&rss_conf, &pkt_dpdk->hash);

> 	}

> 

> +	if (pktio_entry->s.config.pktin.bit.ipv4_chksum ||

> +		pktio_entry->s.config.pktin.bit.udp_chksum ||

> +		pktio_entry->s.config.pktin.bit.tcp_chksum)

> +		hw_ip_checksum = 1;

> +

> 	struct rte_eth_conf port_conf = {

> 		.rxmode = {

> 			.mq_mode = ETH_MQ_RX_RSS,

> 			.max_rx_pkt_len = pkt_dpdk->data_room,

> 			.split_hdr_size = 0,

> 			.header_split   = 0,

> -			.hw_ip_checksum = 0,

> +			.hw_ip_checksum = hw_ip_checksum,

> 			.hw_vlan_filter = 0,

> 			.jumbo_frame    = 1,

> 			.hw_strip_crc   = 0,

> @@ -434,6 +443,22 @@ static void dpdk_init_capability(pktio_entry_t *pktio_entry,

> 	odp_pktio_config_init(&capa->config);

> 	capa->config.pktin.bit.ts_all = 1;

> 	capa->config.pktin.bit.ts_ptp = 1;

> +	capa->config.pktin.bit.ipv4_chksum =

> +		(dev_info->rx_offload_capa & DEV_RX_OFFLOAD_IPV4_CKSUM)? 1:0;

> +	capa->config.pktin.bit.udp_chksum =

> +		(dev_info->rx_offload_capa & DEV_RX_OFFLOAD_UDP_CKSUM)? 1:0;

> +	capa->config.pktin.bit.tcp_chksum =

> +		(dev_info->rx_offload_capa & DEV_RX_OFFLOAD_TCP_CKSUM)? 1:0;

> +	capa->config.pktin.bit.drop_ipv4_err = 1;

> +	capa->config.pktin.bit.drop_udp_err = 1;

> +	capa->config.pktin.bit.drop_tcp_err = 1;

> +

> +	capa->config.pktout.bit.ipv4_chksum =

> +		(dev_info->tx_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM)? 1:0;

> +	capa->config.pktout.bit.udp_chksum =

> +		(dev_info->tx_offload_capa & DEV_TX_OFFLOAD_UDP_CKSUM)? 1:0;

> +	capa->config.pktout.bit.tcp_chksum=

> +		(dev_info->tx_offload_capa & DEV_TX_OFFLOAD_TCP_CKSUM)? 1:0;

> }

> 

> static int dpdk_open(odp_pktio_t id ODP_UNUSED,

> @@ -605,9 +630,11 @@ static inline int mbuf_to_pkt(pktio_entry_t *pktio_entry,

> 	int nb_pkts = 0;

> 	int alloc_len, num;

> 	odp_pool_t pool = pktio_entry->s.pkt_dpdk.pool;

> +	odp_pktin_config_opt_t *pktin_cfg;

> 

> 	/* Allocate maximum sized packets */

> 	alloc_len = pktio_entry->s.pkt_dpdk.data_room;

> +	pktin_cfg = &pktio_entry->s.config.pktin;

> 

> 	num = packet_alloc_multi(pool, alloc_len, pkt_table, mbuf_num);

> 	if (num != mbuf_num) {

> @@ -658,6 +685,34 @@ static inline int mbuf_to_pkt(pktio_entry_t *pktio_entry,

> 		if (mbuf->ol_flags & PKT_RX_RSS_HASH)

> 			odp_packet_flow_hash_set(pkt, mbuf->hash.rss);

> 

> +		if (mbuf->packet_type & RTE_PTYPE_L3_IPV4 &&


Supported packet types vary amongst dpdk ethernet devices, so one may not assume that the mbuf->packet_type is always set correctly. rte_eth_dev_get_supported_ptypes() can be used to query supported types. In this case the comparison is probably fine if the particular rx checksum offload is supported.

As a whole this patch adds quite many if statements to the rx fast path (even when checksum calculation is not enabled) and I'm a bit worried about the performance penalty. Would it make sense to add a dpdk pktio specific packet parsing function? Checksum validations would be done in this function at the matching layer. This would also enable us to use all available dpdk packet parsing features (mainly the packet types).

-Matias

Patch hide | download patch | download mbox

diff --git a/example/generator/odp_generator.c b/example/generator/odp_generator.c
index ede1cdf..59f7f02 100644
--- a/example/generator/odp_generator.c
+++ b/example/generator/odp_generator.c
@@ -46,6 +46,7 @@ 
 
 typedef struct {
 	odp_pktio_t pktio;
+	odp_pktio_config_t config;
 	odp_pktout_queue_t pktout[MAX_WORKERS];
 	unsigned pktout_count;
 } interface_t;
@@ -90,6 +91,7 @@  static struct {
  */
 typedef struct {
 	odp_pktout_queue_t pktout; /**< Packet output queue to use*/
+	odp_pktout_config_opt_t *pktout_cfg; /**< Packet output offload config*/
 	odp_pool_t pool;	/**< Pool for packet IO */
 	odp_timer_pool_t tp;	/**< Timer pool handle */
 	odp_queue_t tq;		/**< Queue for timeouts */
@@ -114,6 +116,9 @@  static args_t *args;
 /** Barrier to sync threads execution */
 static odp_barrier_t barrier;
 
+/** List of interfaces */
+static interface_t *ifs;
+
 /* helper funcs */
 static void parse_args(int argc, char *argv[], appl_args_t *appl_args);
 static void print_info(char *progname, appl_args_t *appl_args);
@@ -192,7 +197,8 @@  static int scan_ip(char *buf, unsigned int *paddr)
  * @return Handle of created packet
  * @retval ODP_PACKET_INVALID  Packet could not be created
  */
-static odp_packet_t setup_udp_pkt_ref(odp_pool_t pool)
+static odp_packet_t setup_udp_pkt_ref(odp_pool_t pool,
+									  odp_pktout_config_opt_t *pktout_cfg)
 {
 	odp_packet_t pkt;
 	char *buf;
@@ -237,7 +243,8 @@  static odp_packet_t setup_udp_pkt_ref(odp_pool_t pool)
 	udp->dst_port = 0;
 	udp->length = odp_cpu_to_be_16(args->appl.payload + ODPH_UDPHDR_LEN);
 	udp->chksum = 0;
-	udp->chksum = odph_ipv4_udp_chksum(pkt);
+	if (!pktout_cfg->bit.udp_chksum)
+		udp->chksum = odph_ipv4_udp_chksum(pkt);
 
 	return pkt;
 }
@@ -251,7 +258,8 @@  static odp_packet_t setup_udp_pkt_ref(odp_pool_t pool)
  * @return Handle of created packet
  * @retval ODP_PACKET_INVALID  Packet could not be created
  */
-static odp_packet_t pack_udp_pkt(odp_pool_t pool, odp_packet_t pkt_ref)
+static odp_packet_t pack_udp_pkt(odp_pool_t pool, odp_packet_t pkt_ref,
+								 odp_pktout_config_opt_t *pktout_cfg)
 {
 	odp_packet_t pkt;
 	char *buf;
@@ -273,7 +281,17 @@  static odp_packet_t pack_udp_pkt(odp_pool_t pool, odp_packet_t pkt_ref)
 	ip = (odph_ipv4hdr_t *)(buf + ODPH_ETHHDR_LEN);
 	seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xFFFF;
 	ip->id = odp_cpu_to_be_16(seq);
-	ip->chksum = odph_chksum(ip, ODPH_IPV4HDR_LEN);
+	ip->chksum = 0;
+	if (!pktout_cfg->bit.ipv4_chksum)
+		ip->chksum = odph_chksum(ip, ODPH_IPV4HDR_LEN);
+
+	if (pktout_cfg->bit.ipv4_chksum || pktout_cfg->bit.udp_chksum) {
+		odp_packet_l2_offset_set(pkt, 0);
+		odp_packet_l3_offset_set(pkt, ODPH_ETHHDR_LEN);
+		odp_packet_has_ipv4_set(pkt, 1);
+		odp_packet_l4_offset_set(pkt, ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN);
+		odp_packet_has_udp_set(pkt, 1);
+	}
 
 	return pkt;
 }
@@ -342,7 +360,8 @@  static odp_packet_t setup_icmp_pkt_ref(odp_pool_t pool)
  * @return Handle of created packet
  * @retval ODP_PACKET_INVALID  Packet could not be created
  */
-static odp_packet_t pack_icmp_pkt(odp_pool_t pool, odp_packet_t pkt_ref)
+static odp_packet_t pack_icmp_pkt(odp_pool_t pool, odp_packet_t pkt_ref,
+								  odp_pktout_config_opt_t *pktout_cfg)
 {
 	odp_packet_t pkt;
 	char *buf;
@@ -367,7 +386,9 @@  static odp_packet_t pack_icmp_pkt(odp_pool_t pool, odp_packet_t pkt_ref)
 	ip = (odph_ipv4hdr_t *)(buf + ODPH_ETHHDR_LEN);
 	seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xffff;
 	ip->id = odp_cpu_to_be_16(seq);
-	ip->chksum = odph_chksum(ip, ODPH_IPV4HDR_LEN);
+	ip->chksum = 0;
+	if (!pktout_cfg->bit.ipv4_chksum)
+		ip->chksum = odph_chksum(ip, ODPH_IPV4HDR_LEN);
 
 	/* icmp */
 	icmp = (odph_icmphdr_t *)(buf + ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN);
@@ -381,6 +402,13 @@  static odp_packet_t pack_icmp_pkt(odp_pool_t pool, odp_packet_t pkt_ref)
 	icmp->chksum = 0;
 	icmp->chksum = odph_chksum(icmp, args->appl.payload + ODPH_ICMPHDR_LEN);
 
+	if (pktout_cfg->bit.ipv4_chksum) {
+		odp_packet_l2_offset_set(pkt, 0);
+		odp_packet_l3_offset_set(pkt, ODPH_ETHHDR_LEN);
+		odp_packet_has_ipv4_set(pkt, 1);
+		odp_packet_l4_offset_set(pkt, ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN);
+	}
+
 	return pkt;
 }
 
@@ -421,6 +449,22 @@  static int create_pktio(const char *dev, odp_pool_t pool,
 			    dev);
 		return -1;
 	}
+
+	odp_pktio_config_init(&itf->config);
+	itf->config.pktin.bit.ipv4_chksum = capa.config.pktin.bit.ipv4_chksum;
+	itf->config.pktin.bit.udp_chksum = capa.config.pktin.bit.udp_chksum;
+	itf->config.pktin.bit.drop_ipv4_err = capa.config.pktin.bit.drop_ipv4_err;
+	itf->config.pktin.bit.drop_udp_err = capa.config.pktin.bit.drop_udp_err;
+
+	itf->config.pktout.bit.ipv4_chksum = capa.config.pktout.bit.ipv4_chksum;
+	itf->config.pktout.bit.udp_chksum = capa.config.pktout.bit.udp_chksum;
+
+	if (odp_pktio_config(itf->pktio, &itf->config)) {
+		EXAMPLE_ERR("Error: Failed to set interface configuration %s\n",
+			    dev);
+		return -1;
+	}
+
 	if (num_rx_queues > capa.max_input_queues)
 		num_rx_queues = capa.max_input_queues;
 
@@ -481,6 +525,7 @@  static int gen_send_thread(void *arg)
 	int ret, i;
 	thread_args_t *thr_args;
 	odp_pktout_queue_t pktout;
+	odp_pktout_config_opt_t *pktout_cfg;
 	odp_packet_t pkt_array[MAX_UDP_TX_BURST];
 	int pkt_array_size;
 	int burst_start, burst_size;
@@ -490,9 +535,10 @@  static int gen_send_thread(void *arg)
 	thr_args = arg;
 
 	pktout = thr_args->pktout;
+	pktout_cfg = thr_args->pktout_cfg;
 
 	if (args->appl.mode == APPL_MODE_UDP) {
-		pkt_ref = setup_udp_pkt_ref(thr_args->pool);
+		pkt_ref = setup_udp_pkt_ref(thr_args->pool, pktout_cfg);
 		pkt_array_size = args->appl.udp_tx_burst;
 	} else if (args->appl.mode == APPL_MODE_PING) {
 		pkt_ref = setup_icmp_pkt_ref(thr_args->pool);
@@ -521,7 +567,7 @@  static int gen_send_thread(void *arg)
 		if (args->appl.mode == APPL_MODE_UDP) {
 			for (i = 0; i < pkt_array_size; i++) {
 				pkt_array[i] = pack_udp_pkt(thr_args->pool,
-						pkt_ref);
+						pkt_ref, pktout_cfg);
 				if (!odp_packet_is_valid(pkt_array[i]))
 					break;
 			}
@@ -532,7 +578,7 @@  static int gen_send_thread(void *arg)
 				break;
 			}
 		} else if (args->appl.mode == APPL_MODE_PING) {
-			pkt_array[0] = pack_icmp_pkt(thr_args->pool, pkt_ref);
+			pkt_array[0] = pack_icmp_pkt(thr_args->pool, pkt_ref, pktout_cfg);
 			if (!odp_packet_is_valid(pkt_array[0])) {
 				EXAMPLE_ERR("  [%2i] alloc_single failed\n",
 					    thr);
@@ -671,6 +717,7 @@  static int gen_recv_thread(void *arg)
 	odp_packet_t pkts[MAX_RX_BURST], pkt;
 	odp_event_t events[MAX_RX_BURST];
 	int pkt_cnt, ev_cnt, i;
+	interface_t *itf;
 
 	thr = odp_thread_id();
 	(void)arg;
@@ -692,6 +739,27 @@  static int gen_recv_thread(void *arg)
 			continue;
 		for (i = 0, pkt_cnt = 0; i < ev_cnt; i++) {
 			pkt = odp_packet_from_event(events[i]);
+			itf = &ifs[odp_pktio_index(odp_packet_input(pkt))];
+
+			if (odp_packet_has_ipv4(pkt)) {
+				if (itf->config.pktin.bit.ipv4_chksum) { /* HW validation */
+					if (odp_packet_has_l3_error(pkt))
+						printf("HW detected L3 error\n");
+				} /* else SW validation */
+			}
+
+			if (odp_packet_has_udp(pkt)) {
+				if (itf->config.pktin.bit.udp_chksum) { /* HW validation*/
+					if (odp_packet_has_l4_error(pkt))
+						printf("HW detected L4 error\n");
+				} /* else SW validation */
+			}
+			if (odp_packet_has_tcp(pkt)) {
+				if (itf->config.pktin.bit.tcp_chksum) { /* HW validation */
+					if (odp_packet_has_l4_error(pkt))
+						printf("HW detected L4 error\n");
+				} /*else SW validation */
+			}
 
 			/* Drop packets with errors */
 			if (odp_unlikely(odp_packet_has_error(pkt))) {
@@ -701,9 +769,11 @@  static int gen_recv_thread(void *arg)
 			pkts[pkt_cnt++] = pkt;
 		}
 
-		print_pkts(thr, pkts, pkt_cnt);
+		if (pkt_cnt) {
+			print_pkts(thr, pkts, pkt_cnt);
 
-		odp_packet_free_multi(pkts, pkt_cnt);
+			odp_packet_free_multi(pkts, pkt_cnt);
+		}
 	}
 
 	return 0;
@@ -797,7 +867,6 @@  int main(int argc, char *argv[])
 	odp_pool_t tmop;
 	odp_queue_t tq;
 	odp_event_t ev;
-	interface_t *ifs;
 	odp_instance_t instance;
 	odph_odpthread_params_t thr_params;
 
@@ -959,6 +1028,7 @@  int main(int argc, char *argv[])
 			abort();
 		}
 		(void)args->thread[1].pktout; /* Not used*/
+		(void)args->thread[1].pktout_cfg; /* Not used*/
 		args->thread[1].pool = pool;
 		args->thread[1].tp = tp;
 		args->thread[1].tq = tq;
@@ -988,6 +1058,7 @@  int main(int argc, char *argv[])
 			abort();
 		}
 		args->thread[0].pktout = ifs[0].pktout[0];
+		args->thread[0].pktout_cfg = &ifs[0].config.pktout;
 		args->thread[0].pool = pool;
 		args->thread[0].tp = tp;
 		args->thread[0].tq = tq;
@@ -1019,15 +1090,18 @@  int main(int argc, char *argv[])
 			int (*thr_run_func)(void *);
 			int if_idx, pktout_idx;
 
-			if (args->appl.mode == APPL_MODE_RCV)
+			if (args->appl.mode == APPL_MODE_RCV) {
 				(void)args->thread[i].pktout; /*not used*/
-			else {
+				(void)args->thread[i].pktout_cfg; /*not used*/
+			} else {
 				if_idx = i % args->appl.if_count;
 				pktout_idx = (i / args->appl.if_count) %
 					ifs[if_idx].pktout_count;
 
 				args->thread[i].pktout =
 					ifs[if_idx].pktout[pktout_idx];
+				args->thread[i].pktout_cfg =
+					&ifs[if_idx].config.pktout;
 			}
 			tq = odp_queue_create("", NULL);
 			if (tq == ODP_QUEUE_INVALID) {
diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c
index 98460a5..6c00b10 100644
--- a/platform/linux-generic/odp_packet_io.c
+++ b/platform/linux-generic/odp_packet_io.c
@@ -150,6 +150,8 @@  static void init_pktio_entry(pktio_entry_t *entry)
 	init_out_queues(entry);
 
 	pktio_classifier_init(entry);
+
+	odp_pktio_config_init(&entry->s.config);
 }
 
 static odp_pktio_t alloc_lock_pktio_entry(void)
diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c
index 6ac89bd..8296908 100644
--- a/platform/linux-generic/pktio/dpdk.c
+++ b/platform/linux-generic/pktio/dpdk.c
@@ -27,6 +27,9 @@ 
 #include <rte_config.h>
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+#include <rte_tcp.h>
 #include <rte_string_fns.h>
 
 static int disable_pktio; /** !0 this pktio disabled, 0 enabled */
@@ -189,6 +192,7 @@  static int dpdk_setup_port(pktio_entry_t *pktio_entry)
 	int ret;
 	pkt_dpdk_t *pkt_dpdk = &pktio_entry->s.pkt_dpdk;
 	struct rte_eth_rss_conf rss_conf;
+	uint16_t hw_ip_checksum = 0;
 
 	/* Always set some hash functions to enable DPDK RSS hash calculation */
 	if (pkt_dpdk->hash.all_bits == 0) {
@@ -198,13 +202,18 @@  static int dpdk_setup_port(pktio_entry_t *pktio_entry)
 		rss_conf_to_hash_proto(&rss_conf, &pkt_dpdk->hash);
 	}
 
+	if (pktio_entry->s.config.pktin.bit.ipv4_chksum ||
+		pktio_entry->s.config.pktin.bit.udp_chksum ||
+		pktio_entry->s.config.pktin.bit.tcp_chksum)
+		hw_ip_checksum = 1;
+
 	struct rte_eth_conf port_conf = {
 		.rxmode = {
 			.mq_mode = ETH_MQ_RX_RSS,
 			.max_rx_pkt_len = pkt_dpdk->data_room,
 			.split_hdr_size = 0,
 			.header_split   = 0,
-			.hw_ip_checksum = 0,
+			.hw_ip_checksum = hw_ip_checksum,
 			.hw_vlan_filter = 0,
 			.jumbo_frame    = 1,
 			.hw_strip_crc   = 0,
@@ -434,6 +443,22 @@  static void dpdk_init_capability(pktio_entry_t *pktio_entry,
 	odp_pktio_config_init(&capa->config);
 	capa->config.pktin.bit.ts_all = 1;
 	capa->config.pktin.bit.ts_ptp = 1;
+	capa->config.pktin.bit.ipv4_chksum =
+		(dev_info->rx_offload_capa & DEV_RX_OFFLOAD_IPV4_CKSUM)? 1:0;
+	capa->config.pktin.bit.udp_chksum =
+		(dev_info->rx_offload_capa & DEV_RX_OFFLOAD_UDP_CKSUM)? 1:0;
+	capa->config.pktin.bit.tcp_chksum =
+		(dev_info->rx_offload_capa & DEV_RX_OFFLOAD_TCP_CKSUM)? 1:0;
+	capa->config.pktin.bit.drop_ipv4_err = 1;
+	capa->config.pktin.bit.drop_udp_err = 1;
+	capa->config.pktin.bit.drop_tcp_err = 1;
+
+	capa->config.pktout.bit.ipv4_chksum =
+		(dev_info->tx_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM)? 1:0;
+	capa->config.pktout.bit.udp_chksum =
+		(dev_info->tx_offload_capa & DEV_TX_OFFLOAD_UDP_CKSUM)? 1:0;
+	capa->config.pktout.bit.tcp_chksum=
+		(dev_info->tx_offload_capa & DEV_TX_OFFLOAD_TCP_CKSUM)? 1:0;
 }
 
 static int dpdk_open(odp_pktio_t id ODP_UNUSED,
@@ -605,9 +630,11 @@  static inline int mbuf_to_pkt(pktio_entry_t *pktio_entry,
 	int nb_pkts = 0;
 	int alloc_len, num;
 	odp_pool_t pool = pktio_entry->s.pkt_dpdk.pool;
+	odp_pktin_config_opt_t *pktin_cfg;
 
 	/* Allocate maximum sized packets */
 	alloc_len = pktio_entry->s.pkt_dpdk.data_room;
+	pktin_cfg = &pktio_entry->s.config.pktin;
 
 	num = packet_alloc_multi(pool, alloc_len, pkt_table, mbuf_num);
 	if (num != mbuf_num) {
@@ -658,6 +685,34 @@  static inline int mbuf_to_pkt(pktio_entry_t *pktio_entry,
 		if (mbuf->ol_flags & PKT_RX_RSS_HASH)
 			odp_packet_flow_hash_set(pkt, mbuf->hash.rss);
 
+		if (mbuf->packet_type & RTE_PTYPE_L3_IPV4 &&
+			pktin_cfg->bit.ipv4_chksum &&
+			mbuf->ol_flags & PKT_RX_IP_CKSUM_BAD) {
+			if (pktin_cfg->bit.drop_ipv4_err) {
+				odp_packet_free(pkt);
+				continue;
+			} else
+				pkt_hdr->p.error_flags.ip_err = 1;
+		}
+
+		if (mbuf->packet_type & RTE_PTYPE_L4_UDP &&
+			pktin_cfg->bit.udp_chksum &&
+			mbuf->ol_flags & PKT_RX_L4_CKSUM_BAD) {
+			if (pktin_cfg->bit.drop_udp_err) {
+				odp_packet_free(pkt);
+				continue;
+			} else
+				pkt_hdr->p.error_flags.udp_err = 1;
+		} else if (mbuf->packet_type & RTE_PTYPE_L4_TCP &&
+			pktin_cfg->bit.tcp_chksum &&
+			mbuf->ol_flags & PKT_RX_L4_CKSUM_BAD) {
+			if (pktin_cfg->bit.drop_tcp_err) {
+				odp_packet_free(pkt);
+				continue;
+			} else
+				pkt_hdr->p.error_flags.tcp_err = 1;
+		}
+
 		packet_set_ts(pkt_hdr, ts);
 
 		pkt_table[nb_pkts++] = pkt;
@@ -675,7 +730,15 @@  fail:
 
 	return (i > 0 ? i : -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)
@@ -684,14 +747,23 @@  static inline int pkt_to_mbuf(pktio_entry_t *pktio_entry,
 	int i, j;
 	char *data;
 	uint16_t pkt_len;
+	odp_bool_t ipv4_chksum, udp_chksum, tcp_chksum;
+	odp_packet_t pkt;
+	struct rte_mbuf *mbuf;
 
 	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 = pktio_entry->s.config.pktout.bit.ipv4_chksum ? 1 : 0;
+	udp_chksum = pktio_entry->s.config.pktout.bit.udp_chksum ? 1 : 0;
+	tcp_chksum = pktio_entry->s.config.pktout.bit.tcp_chksum ? 1 : 0;
+
 	for (i = 0; i < num; i++) {
-		pkt_len = _odp_packet_len(pkt_table[i]);
+		pkt = pkt_table[i];
+		mbuf = mbuf_table[i];
+		pkt_len = _odp_packet_len(pkt);
 
 		if (pkt_len > pkt_dpdk->mtu) {
 			if (i == 0)
@@ -700,9 +772,44 @@  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_table[i], 0, pkt_len, data);
+		odp_packet_copy_to_mem(pkt, 0, pkt_len, data);
+
+		if (ipv4_chksum || udp_chksum || tcp_chksum) {
+			void *l3_hdr;
+
+			mbuf->l2_len = odp_packet_l3_offset(pkt) -
+				odp_packet_l2_offset(pkt);
+			mbuf->l3_len = odp_packet_l4_offset(pkt) -
+				odp_packet_l3_offset(pkt);
+			mbuf->ol_flags = 0;
+
+			l3_hdr = (void *)(data + mbuf->l2_len);
+
+			if (ipv4_chksum && odp_packet_has_ipv4(pkt)) {
+				struct ipv4_hdr *ip = (struct ipv4_hdr *)l3_hdr;
+
+				mbuf->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM;
+				ip->hdr_checksum = 0;
+			}
+
+			if (udp_chksum && odp_packet_has_udp(pkt)) {
+				struct udp_hdr *udp = (struct udp_hdr *)(data + mbuf->l2_len +
+														 mbuf->l3_len);
+
+				mbuf->ol_flags |= PKT_TX_UDP_CKSUM;
+				udp->dgram_cksum = phdr_csum(odp_packet_has_ipv4(pkt),
+											 l3_hdr, mbuf->ol_flags);
+			} else if (tcp_chksum && odp_packet_has_tcp(pkt)) {
+				struct tcp_hdr *tcp = (struct tcp_hdr *)(data + mbuf->l2_len +
+														 mbuf->l3_len);
+
+				mbuf->ol_flags |= PKT_TX_TCP_CKSUM;
+				tcp->cksum = phdr_csum(odp_packet_has_ipv4(pkt),
+											 l3_hdr, mbuf->ol_flags);
+			}
+		}
 	}
 	return i;