diff mbox

[RFCv5] dpdk: enable hardware checksum support

Message ID 1495802303-16766-2-git-send-email-bogdan.pricope@linaro.org
State Superseded
Headers show

Commit Message

Bogdan Pricope May 26, 2017, 12:38 p.m. UTC
Signed-off-by: Bogdan Pricope <bogdan.pricope@linaro.org>

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

-- 
1.9.1

Comments

Elo, Matias (Nokia - FI/Espoo) May 29, 2017, 12:08 p.m. UTC | #1
Hi Bogdan,

I still think rx checksum calculation should be combined with packet parsing but below are some comments regarding this rfc code.

-Matias

> 

> static int dpdk_open(odp_pktio_t id ODP_UNUSED,

> @@ -605,9 +666,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 +721,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) && /* covers IPv4, IPv4_EXT, IPv4_EXT_UKN */

> +			pktin_cfg->bit.ipv4_chksum &&

> +			mbuf->ol_flags & PKT_RX_IP_CKSUM_BAD) {


pktin_cfg->bit.ipv4_chksum should be checked first.

> +			if (pktin_cfg->bit.drop_ipv4_err) {

> +				odp_packet_free(pkt);

> +				continue;


The mbuf is never freed.

> +			} 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) {


pktin_cfg->bit.udp_chksum first.

> +			if (pktin_cfg->bit.drop_udp_err) {

> +				odp_packet_free(pkt);

> +				continue;


The mbuf is never freed.

> +			} 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) {


pktin_cfg->bit.tcp_chksum first.

> +			if (pktin_cfg->bit.drop_tcp_err) {

> +				odp_packet_free(pkt);

> +				continue;


The mbuf is never freed.

> 

> +#define IP_VERSION	0x40

> +#define IP6_VERSION	0x60

> +

> +static int packet_parse(void *l3_hdr, uint8_t *l3_proto_v4, uint8_t *l4_proto)

> +{

> +	uint8_t l3_proto = (*(uint8_t *)l3_hdr & 0xf0);

> +


You can use _ODP_IPV4HDR_VER(), _ODP_IPV4, _ODP_IPV6 here.

> @@ -700,9 +841,45 @@ 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);


You can check pktio_entry->s.config.pktout.all_bits here and do continue if no checksums
are enabled.

> +		ipv4_chksum_pkt = l3_proto_v4 && ipv4_chksum_cfg;

> +		udp_chksum_pkt = (l4_proto == IPPROTO_UDP) && udp_chksum_cfg;

> +		tcp_chksum_pkt = (l4_proto == IPPROTO_TCP) && tcp_chksum_cfg;


Config checks first.
Bogdan Pricope May 30, 2017, 6:13 a.m. UTC | #2
On 29 May 2017 at 15:08, Elo, Matias (Nokia - FI/Espoo)
<matias.elo@nokia.com> wrote:
> Hi Bogdan,

>

> I still think rx checksum calculation should be combined with packet parsing but below are some comments regarding this rfc code.


This RFC is for master branch: some of the APIs you need for optimized
parser or csum override are not there (yet) but in api-next. Also, I
am considering putting this in odp-dpdk instead of odp-linux since it
does not require API changes and odp-linux is not relevant for
performance runs.

It seams, with your changes you are favoring "non HW csum" case - this
should be the corner case. ODP is meant for performance and one would
select a board with HW capabilities and would expect maximum
performance for this case.
Anyway, I'll do this changes and send the (final) RFCv6. Speak now or
forever hold your peace.

/B

>

> -Matias

>

>>

>> static int dpdk_open(odp_pktio_t id ODP_UNUSED,

>> @@ -605,9 +666,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 +721,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) && /* covers IPv4, IPv4_EXT, IPv4_EXT_UKN */

>> +                     pktin_cfg->bit.ipv4_chksum &&

>> +                     mbuf->ol_flags & PKT_RX_IP_CKSUM_BAD) {

>

> pktin_cfg->bit.ipv4_chksum should be checked first.

>

>> +                     if (pktin_cfg->bit.drop_ipv4_err) {

>> +                             odp_packet_free(pkt);

>> +                             continue;

>

> The mbuf is never freed.

>

>> +                     } 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) {

>

> pktin_cfg->bit.udp_chksum first.

>

>> +                     if (pktin_cfg->bit.drop_udp_err) {

>> +                             odp_packet_free(pkt);

>> +                             continue;

>

> The mbuf is never freed.

>

>> +                     } 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) {

>

> pktin_cfg->bit.tcp_chksum first.

>

>> +                     if (pktin_cfg->bit.drop_tcp_err) {

>> +                             odp_packet_free(pkt);

>> +                             continue;

>

> The mbuf is never freed.

>

>>

>> +#define IP_VERSION   0x40

>> +#define IP6_VERSION  0x60

>> +

>> +static int packet_parse(void *l3_hdr, uint8_t *l3_proto_v4, uint8_t *l4_proto)

>> +{

>> +     uint8_t l3_proto = (*(uint8_t *)l3_hdr & 0xf0);

>> +

>

> You can use _ODP_IPV4HDR_VER(), _ODP_IPV4, _ODP_IPV6 here.

>

>> @@ -700,9 +841,45 @@ 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);

>

> You can check pktio_entry->s.config.pktout.all_bits here and do continue if no checksums

> are enabled.

>

>> +             ipv4_chksum_pkt = l3_proto_v4 && ipv4_chksum_cfg;

>> +             udp_chksum_pkt = (l4_proto == IPPROTO_UDP) && udp_chksum_cfg;

>> +             tcp_chksum_pkt = (l4_proto == IPPROTO_TCP) && tcp_chksum_cfg;

>

> Config checks first.

>
Elo, Matias (Nokia - FI/Espoo) May 30, 2017, 7:55 a.m. UTC | #3
> Also, I

> am considering putting this in odp-dpdk instead of odp-linux since it

> does not require API changes and odp-linux is not relevant for

> performance runs.

> 


This is a good idea. The changes can be ported to back linux-generic after the
necessary API changes are merged.

odp-dpdk probably requires couple patches before you start working on the parser
code. At least the API change 'api: pktio: add parser configuration' and the
implementation 'linux-gen: packet: remove lazy parsing' should to be ported.


> It seams, with your changes you are favoring "non HW csum" case - this

> should be the corner case. ODP is meant for performance and one would

> select a board with HW capabilities and would expect maximum

> performance for this case.


My objective is to minimise the overhead for the raw throughput case when
no checksumming etc. is enabled as this is almost always the baseline when
doing performance benchmarking.

-Matias
Savolainen, Petri (Nokia - FI/Espoo) May 30, 2017, 1:01 p.m. UTC | #4
> > It seams, with your changes you are favoring "non HW csum" case - this

> > should be the corner case. ODP is meant for performance and one would

> > select a board with HW capabilities and would expect maximum

> > performance for this case.

> 

> My objective is to minimise the overhead for the raw throughput case when

> no checksumming etc. is enabled as this is almost always the baseline when

> doing performance benchmarking.

> 

> -Matias


L4 checksum is end-to-end. It's not interesting when e.g. forwarding packets. ODP is used for both terminating and forwarding type applications / use cases. So, both yes/no checksum offload cases are equally important. Application which does not need checksum offload, should tell that to the implementation, so that performance / power consumption are optimized.

-Petri
diff mbox

Patch

diff --git a/example/generator/odp_generator.c b/example/generator/odp_generator.c
index 3ec7d8d..1cd3e29 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);
@@ -193,7 +198,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,8 +243,10 @@  static odp_packet_t setup_udp_pkt_ref(odp_pool_t pool)
 	udp->src_port = odp_cpu_to_be_16(args->appl.srcport);
 	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 = 0;
+		udp->chksum = odph_ipv4_udp_chksum(pkt);
+	}
 
 	return pkt;
 }
@@ -252,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;
@@ -274,7 +283,14 @@  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);
+	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_l4_offset_set(pkt, ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN);
+	}
 
 	return pkt;
 }
@@ -343,7 +359,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;
@@ -368,7 +385,8 @@  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);
+	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);
@@ -382,6 +400,12 @@  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_l4_offset_set(pkt, ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN);
+	}
+
 	return pkt;
 }
 
@@ -422,6 +446,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;
 
@@ -482,6 +522,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;
@@ -491,9 +532,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);
@@ -522,7 +564,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;
 			}
@@ -533,7 +575,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);
@@ -684,6 +726,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;
@@ -705,6 +748,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))) {
@@ -714,9 +778,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;
@@ -810,7 +876,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;
 
@@ -972,6 +1037,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;
@@ -1001,6 +1067,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;
@@ -1032,15 +1099,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 50a000e..dc24ee9 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..1a4d97d 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 */
@@ -189,6 +193,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 +203,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 +430,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 +446,55 @@  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:
+			case RTE_PTYPE_L3_IPV4_EXT_UNKNOWN:
+			case RTE_PTYPE_L3_IPV4_EXT:
+				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 +666,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 +721,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) && /* covers IPv4, IPv4_EXT, IPv4_EXT_UKN */
+			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,6 +766,42 @@  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);
+}
+#define IP_VERSION	0x40
+#define IP6_VERSION	0x60
+
+static int packet_parse(void *l3_hdr, uint8_t *l3_proto_v4, uint8_t *l4_proto)
+{
+	uint8_t l3_proto = (*(uint8_t *)l3_hdr & 0xf0);
+
+	if (l3_proto == IP_VERSION) {
+		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 == IP6_VERSION) {
+		struct ipv6_hdr *ipv6 = (struct ipv6_hdr *)l3_hdr;
+
+		*l3_proto_v4 = 0;
+		*l4_proto = ipv6->proto;
+		return 0;
+	}
+
+	return -1;
+}
 
 static inline int pkt_to_mbuf(pktio_entry_t *pktio_entry,
 			      struct rte_mbuf *mbuf_table[],
@@ -683,15 +810,29 @@  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_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;
+	odp_packet_t pkt;
 	uint16_t pkt_len;
+	packet_parser_t *pkt_p;
+	struct rte_mbuf *mbuf;
+	void *l3_hdr;
 
 	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_p = &odp_packet_hdr(pkt)->p;
 
 		if (pkt_len > pkt_dpdk->mtu) {
 			if (i == 0)
@@ -700,9 +841,45 @@  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);
+
+		l3_hdr = (void *)(data + pkt_p->l3_offset);
+		if (packet_parse(l3_hdr, &l3_proto_v4, &l4_proto))
+			continue;
 
-		odp_packet_copy_to_mem(pkt_table[i], 0, pkt_len, data);
+		ipv4_chksum_pkt = l3_proto_v4 && ipv4_chksum_cfg;
+		udp_chksum_pkt = (l4_proto == IPPROTO_UDP) && udp_chksum_cfg;
+		tcp_chksum_pkt = (l4_proto == IPPROTO_TCP) && tcp_chksum_cfg;
+
+		if (ipv4_chksum_pkt || udp_chksum_pkt || tcp_chksum_pkt) {
+			mbuf->l2_len = pkt_p->l3_offset - pkt_p->l2_offset;
+			mbuf->l3_len = pkt_p->l4_offset - pkt_p->l3_offset;
+
+			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;
+			}
+
+			if (udp_chksum_pkt) {
+				mbuf->ol_flags |= PKT_TX_UDP_CKSUM;
+
+				((struct udp_hdr *)(data + pkt_p->l4_offset))->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 *)(data + pkt_p->l4_offset))->cksum =
+					phdr_csum(l3_proto_v4, l3_hdr, mbuf->ol_flags);
+			}
+		}
 	}
 	return i;