diff mbox

[RFCv4] dpdk: enable hardware checksum support

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

Commit Message

Bogdan Pricope May 22, 2017, 9:13 a.m. UTC
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    | 161 ++++++++++++++++++++++++++++++++-
 3 files changed, 246 insertions(+), 19 deletions(-)

-- 
1.9.1

Comments

Elo, Matias (Nokia - FI/Espoo) May 24, 2017, 7:53 a.m. UTC | #1
Hi Bogdan,

I ran a quick test run with the patch and the overhead seems to be surprisingly small at least on a Xeon cpu (E5-2697v3). However, I would still suggest making some changes to the code. More below.

-Matias



>

> @@ -605,9 +663,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 +718,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_MASK) == 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_MASK) == 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_MASK) == 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;

> +             }

> +


Instead of doing packet parsing and checksum validation separately I would do both in one function. The api-next pktio code (should be merged to master) has a new configuration option 'odp_pktio_config_t.parser.layer', which selects the parsing level. packet_parse_layer() function is then used to parse the received packet up to the selected level.

So, instead of of calling packet_parse_layer() in dpdk pktio I would add a new dpdk specific implementation of this function. This way we can exploit all dpdk packet parsing features in addition to the checksum calculations. Also, by doing this you can remove most of the if() calls above. Enabling a higher protocol layer checksum calculation than the selected parsing level would be a user error (e.g. ODP_PKTIO_PARSER_LAYER_L2 and TCP checksum enabled).
Bogdan Pricope May 24, 2017, 8:32 a.m. UTC | #2
Hi Matias,

Using ptypes reported by dpdk in parser was intended for another patch
(next work after csum).

I guess your test is a degradation test (due to new ifs) and you did
not enabled csum offloads/ set flags on packets.

What will be interesting to see:
 - in a generation or termination test (UDP), what will be
degradation/gain with csum offload enabled
 - how degradation/gain is changing with bigger packets (256 bytes vs 64 bytes)

BR,
Bogdan


On 24 May 2017 at 10:53, Elo, Matias (Nokia - FI/Espoo)
<matias.elo@nokia.com> wrote:
> Hi Bogdan,

>

> I ran a quick test run with the patch and the overhead seems to be

> surprisingly small at least on a Xeon cpu (E5-2697v3). However, I would

> still suggest making some changes to the code. More below.

>

> -Matias

>

>

>

>>

>> @@ -605,9 +663,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 +718,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_MASK) ==

>> 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_MASK) ==

>> 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_MASK) ==

>> 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;

>> +             }

>> +

>

> Instead of doing packet parsing and checksum validation separately I would

> do both in one function. The api-next pktio code (should be merged to

> master) has a new configuration option 'odp_pktio_config_t.parser.layer',

> which selects the parsing level. packet_parse_layer() function is then used

> to parse the received packet up to the selected level.

>

> So, instead of of calling packet_parse_layer() in dpdk pktio I would add a

> new dpdk specific implementation of this function. This way we can exploit

> all dpdk packet parsing features in addition to the checksum calculations.

> Also, by doing this you can remove most of the if() calls above. Enabling a

> higher protocol layer checksum calculation than the selected parsing level

> would be a user error (e.g. ODP_PKTIO_PARSER_LAYER_L2 and TCP checksum

> enabled).

>

>
Elo, Matias (Nokia - FI/Espoo) May 24, 2017, 11:55 a.m. UTC | #3
> On 24 May 2017, at 11:32, Bogdan Pricope <bogdan.pricope@linaro.org> wrote:

> 

> Hi Matias,

> 

> Using ptypes reported by dpdk in parser was intended for another patch

> (next work after csum).

> 


Good, so we are on the same page. When implementing packet parsing you have to
move/reimplement this checksum code anyway, so it makes more sense to implement
both of them in the same patch / patch set.  

> I guess your test is a degradation test (due to new ifs) and you did

> not enabled csum offloads/ set flags on packets.


Yep, just standard l2fwd test without any offload flags.

> 

> What will be interesting to see:

> - in a generation or termination test (UDP), what will be

> degradation/gain with csum offload enabled

> - how degradation/gain is changing with bigger packets (256 bytes vs 64 bytes)


That would definitely be more interesting. I tried quickly enabling 'ipv4_chksum'
and 'udp_chksum' flags on odp_l2fwd and the performance degradation was minimal
(~0.2%).

While testing this I noticed a small problem in the code:

> +		ptype_cnt = rte_eth_dev_get_supported_ptypes(pkt_dpdk->port_id,

> +											   ptype_mask, ptypes, ptype_cnt);

> +		for (i = 0; i < ptype_cnt; i++)

> +			switch (ptypes[i]) {

> +			case RTE_PTYPE_L3_IPV4:

> +				ptype_l3_ipv4 = 1;

> +				break;

> +			case RTE_PTYPE_L4_TCP:

> +				ptype_l4_tcp = 1;

> +				break;

> +			case RTE_PTYPE_L4_UDP:

> +				ptype_l4_udp = 1;

> +				break;

> +			}

> +	}


This doesn't work alone in all cases. For example Fortville NIC uses
RTE_PTYPE_L3_IPV4_EXT_UNKNOWN but not RTE_PTYPE_L3_IPV4.


-Matias
diff mbox

Patch

diff --git a/example/generator/odp_generator.c b/example/generator/odp_generator.c
index 79efe5b..d68a31f 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;
@@ -92,6 +93,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 */
@@ -116,6 +118,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);
@@ -194,7 +199,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;
@@ -239,7 +245,8 @@  static odp_packet_t setup_udp_pkt_ref(odp_pool_t pool)
 	udp->dst_port = odp_cpu_to_be_16(args->appl.dstport);
 	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;
 }
@@ -253,7 +260,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;
@@ -275,7 +283,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;
 }
@@ -344,7 +362,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;
@@ -369,7 +388,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);
@@ -383,6 +404,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;
 }
 
@@ -423,6 +451,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;
 
@@ -483,6 +527,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;
@@ -492,9 +537,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);
@@ -523,7 +569,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;
 			}
@@ -534,7 +580,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);
@@ -673,6 +719,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;
@@ -694,6 +741,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))) {
@@ -703,9 +771,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;
@@ -799,7 +869,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;
 
@@ -961,6 +1030,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;
@@ -990,6 +1060,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;
@@ -1021,15 +1092,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..1c5ffa4 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,
@@ -420,6 +429,11 @@  static void dpdk_init_capability(pktio_entry_t *pktio_entry,
 {
 	pkt_dpdk_t *pkt_dpdk = &pktio_entry->s.pkt_dpdk;
 	odp_pktio_capability_t *capa = &pkt_dpdk->capa;
+	int ptype_cnt;
+	int ptype_l3_ipv4 = 0;
+	int ptype_l4_tcp = 0;
+	int ptype_l4_udp = 0;
+	uint32_t ptype_mask = RTE_PTYPE_L3_MASK | RTE_PTYPE_L4_MASK;
 
 	memset(dev_info, 0, sizeof(struct rte_eth_dev_info));
 	memset(capa, 0, sizeof(odp_pktio_capability_t));
@@ -431,9 +445,53 @@  static void dpdk_init_capability(pktio_entry_t *pktio_entry,
 					  PKTIO_MAX_QUEUES);
 	capa->set_op.op.promisc_mode = 1;
 
+	ptype_cnt = rte_eth_dev_get_supported_ptypes(pkt_dpdk->port_id,
+										   ptype_mask, NULL, 0);
+	if (ptype_cnt > 0) {
+		uint32_t ptypes[ptype_cnt];
+		int i;
+
+		ptype_cnt = rte_eth_dev_get_supported_ptypes(pkt_dpdk->port_id,
+											   ptype_mask, ptypes, ptype_cnt);
+		for (i = 0; i < ptype_cnt; i++)
+			switch (ptypes[i]) {
+			case RTE_PTYPE_L3_IPV4:
+				ptype_l3_ipv4 = 1;
+				break;
+			case RTE_PTYPE_L4_TCP:
+				ptype_l4_tcp = 1;
+				break;
+			case RTE_PTYPE_L4_UDP:
+				ptype_l4_udp = 1;
+				break;
+			}
+	}
+
 	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 = ptype_l3_ipv4 &&
+		(dev_info->rx_offload_capa & DEV_RX_OFFLOAD_IPV4_CKSUM)? 1:0;
+	if (capa->config.pktin.bit.ipv4_chksum)
+		capa->config.pktin.bit.drop_ipv4_err = 1;
+
+	capa->config.pktin.bit.udp_chksum = ptype_l4_udp &&
+		(dev_info->rx_offload_capa & DEV_RX_OFFLOAD_UDP_CKSUM)? 1:0;
+	if (capa->config.pktin.bit.udp_chksum)
+		capa->config.pktin.bit.drop_udp_err = 1;
+
+	capa->config.pktin.bit.tcp_chksum = ptype_l4_tcp &&
+		(dev_info->rx_offload_capa & DEV_RX_OFFLOAD_TCP_CKSUM)? 1:0;
+	if (capa->config.pktin.bit.tcp_chksum)
+		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 +663,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 +718,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_MASK) == 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_MASK) == 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_MASK) == 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 +763,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 +780,26 @@  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_cfg, udp_chksum_cfg, tcp_chksum_cfg;
+	odp_bool_t ipv4_chksum_pkt, udp_chksum_pkt, tcp_chksum_pkt;
+	odp_packet_t pkt;
+	odp_packet_hdr_t *pkt_hdr;
+	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_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]);
+		pkt = pkt_table[i];
+		mbuf = mbuf_table[i];
+		pkt_len = _odp_packet_len(pkt);
+		pkt_hdr = odp_packet_hdr(pkt);
 
 		if (pkt_len > pkt_dpdk->mtu) {
 			if (i == 0)
@@ -700,9 +808,52 @@  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);
+
+		ipv4_chksum_pkt = pkt_hdr->p.input_flags.ipv4 && ipv4_chksum_cfg;
+		if (pkt_hdr->p.input_flags.ipfrag) {
+			udp_chksum_pkt = 0;
+			tcp_chksum_pkt = 0;
+		} else {
+			udp_chksum_pkt = pkt_hdr->p.input_flags.udp &&
+				udp_chksum_cfg;
+			tcp_chksum_pkt = pkt_hdr->p.input_flags.tcp &&
+				tcp_chksum_cfg;
+		}
+
+		if (ipv4_chksum_pkt || udp_chksum_pkt || tcp_chksum_pkt) {
+			mbuf->l2_len = pkt_hdr->p.l3_offset - pkt_hdr->p.l2_offset;
+			mbuf->l3_len = pkt_hdr->p.l4_offset - pkt_hdr->p.l3_offset;
+
+			if (pkt_hdr->p.input_flags.ipv4)
+				mbuf->ol_flags = PKT_TX_IPV4;
+			else
+				mbuf->ol_flags = PKT_TX_IPV6;
 
-		odp_packet_copy_to_mem(pkt_table[i], 0, pkt_len, data);
+			if (ipv4_chksum_pkt) /* ip->hdr_checksum = zero, l2_len and l3_len set */
+				mbuf->ol_flags |=  PKT_TX_IP_CKSUM;
+
+			if (udp_chksum_pkt) { /* l2_len and l3_len set */
+				struct udp_hdr *udp = (struct udp_hdr *)(data + mbuf->l2_len +
+														 mbuf->l3_len);
+
+				udp->dgram_cksum = phdr_csum(pkt_hdr->p.input_flags.ipv4,
+											 (void *)(data + mbuf->l2_len),
+											 mbuf->ol_flags);
+
+				mbuf->ol_flags |= PKT_TX_UDP_CKSUM;
+			} else if (tcp_chksum_pkt) { /* l2_len and l3_len set */
+				struct tcp_hdr *tcp = (struct tcp_hdr *)(data + mbuf->l2_len +
+														 mbuf->l3_len);
+
+				tcp->cksum = phdr_csum(pkt_hdr->p.input_flags.ipv4,
+									   (void *)(data + mbuf->l2_len),
+									   mbuf->ol_flags);
+				mbuf->ol_flags |= PKT_TX_TCP_CKSUM;
+			}
+		}
 	}
 	return i;