diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h
index 43c8da5cb..86f0d80a5 100644
--- a/platform/linux-generic/include/odp_packet_internal.h
+++ b/platform/linux-generic/include/odp_packet_internal.h
@@ -296,7 +296,8 @@ int packet_alloc_multi(odp_pool_t pool_hdl, uint32_t len,
 
 /* Perform packet parse up to a given protocol layer */
 int packet_parse_layer(odp_packet_hdr_t *pkt_hdr,
-		       odp_proto_layer_t layer);
+		       odp_proto_layer_t layer,
+		       odp_proto_chksums_t chksums);
 
 /* Reset parser metadata for a new parse */
 void packet_parse_reset(odp_packet_hdr_t *pkt_hdr);
@@ -333,7 +334,8 @@ static inline void packet_set_ts(odp_packet_hdr_t *pkt_hdr, odp_time_t *ts)
 }
 
 int packet_parse_common(packet_parser_t *pkt_hdr, const uint8_t *ptr,
-			uint32_t pkt_len, uint32_t seg_len, int layer);
+			uint32_t pkt_len, uint32_t seg_len, int layer,
+			odp_proto_chksums_t chksums);
 
 int _odp_cls_parse(odp_packet_hdr_t *pkt_hdr, const uint8_t *parseptr);
 
diff --git a/platform/linux-generic/odp_classification.c b/platform/linux-generic/odp_classification.c
index 276430923..4d3df49e2 100644
--- a/platform/linux-generic/odp_classification.c
+++ b/platform/linux-generic/odp_classification.c
@@ -973,7 +973,8 @@ int cls_classify_packet(pktio_entry_t *entry, const uint8_t *base,
 	packet_set_len(pkt_hdr, pkt_len);
 
 	packet_parse_common(&pkt_hdr->p, base, pkt_len, seg_len,
-			    ODP_PROTO_LAYER_ALL);
+			    ODP_PROTO_LAYER_ALL,
+			    entry->s.in_chksums);
 	cos = cls_select_cos(entry, base, pkt_hdr);
 
 	if (cos == NULL)
diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c
index a0bc8911a..d3c608ab0 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -2024,7 +2024,8 @@ static inline uint16_t parse_eth(packet_parser_t *prs, const uint8_t **parseptr,
  * Parser helper function for IPv4
  */
 static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr,
-				 uint32_t *offset, uint32_t frame_len)
+				 uint32_t *offset, uint32_t frame_len,
+				 odp_proto_chksums_t chksums)
 {
 	const _odp_ipv4hdr_t *ipv4 = (const _odp_ipv4hdr_t *)*parseptr;
 	uint8_t ver = _ODP_IPV4HDR_VER(ipv4->ver_ihl);
@@ -2040,6 +2041,14 @@ static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr,
 		return 0;
 	}
 
+	if (chksums.chksum.ipv4) {
+		prs->input_flags.l3_chksum_done = 1;
+		if (odp_chksum_ones_comp16(ipv4, ihl * 4) != 0xffff) {
+			prs->error_flags.l3_chksum = 1;
+			return 0;
+		}
+	}
+
 	*offset   += ihl * 4;
 	*parseptr += ihl * 4;
 
@@ -2175,7 +2184,8 @@ static inline
 int packet_parse_common_l3_l4(packet_parser_t *prs, const uint8_t *parseptr,
 			      uint32_t offset,
 			      uint32_t frame_len, uint32_t seg_len,
-			      int layer, uint16_t ethtype)
+			      int layer, uint16_t ethtype,
+			      odp_proto_chksums_t chksums)
 {
 	uint8_t  ip_proto;
 
@@ -2191,7 +2201,7 @@ int packet_parse_common_l3_l4(packet_parser_t *prs, const uint8_t *parseptr,
 	switch (ethtype) {
 	case _ODP_ETHTYPE_IPV4:
 		prs->input_flags.ipv4 = 1;
-		ip_proto = parse_ipv4(prs, &parseptr, &offset, frame_len);
+		ip_proto = parse_ipv4(prs, &parseptr, &offset, frame_len, chksums);
 		prs->l4_offset = offset;
 		break;
 
@@ -2275,7 +2285,7 @@ int packet_parse_common_l3_l4(packet_parser_t *prs, const uint8_t *parseptr,
  */
 int packet_parse_common(packet_parser_t *prs, const uint8_t *ptr,
 			uint32_t frame_len, uint32_t seg_len,
-			int layer)
+			int layer, odp_proto_chksums_t chksums)
 {
 	uint32_t offset;
 	uint16_t ethtype;
@@ -2296,20 +2306,21 @@ int packet_parse_common(packet_parser_t *prs, const uint8_t *ptr,
 	ethtype = parse_eth(prs, &parseptr, &offset, frame_len);
 
 	return packet_parse_common_l3_l4(prs, parseptr, offset, frame_len,
-					 seg_len, layer, ethtype);
+					 seg_len, layer, ethtype, chksums);
 }
 
 /**
  * Simple packet parser
  */
 int packet_parse_layer(odp_packet_hdr_t *pkt_hdr,
-		       odp_proto_layer_t layer)
+		       odp_proto_layer_t layer,
+		       odp_proto_chksums_t chksums)
 {
 	uint32_t seg_len = packet_first_seg_len(pkt_hdr);
 	void *base = packet_data(pkt_hdr);
 
 	return packet_parse_common(&pkt_hdr->p, base, pkt_hdr->frame_len,
-				   seg_len, layer);
+				   seg_len, layer, chksums);
 }
 
 int odp_packet_parse(odp_packet_t pkt, uint32_t offset,
@@ -2336,7 +2347,8 @@ int odp_packet_parse(odp_packet_t pkt, uint32_t offset,
 
 	if (proto == ODP_PROTO_ETH) {
 		ret = packet_parse_common(&pkt_hdr->p, data, packet_len,
-					  seg_len, layer);
+					  seg_len, layer,
+					  param->chksums);
 
 		if (ret)
 			return -1;
@@ -2348,7 +2360,9 @@ int odp_packet_parse(odp_packet_t pkt, uint32_t offset,
 
 		ret = packet_parse_common_l3_l4(&pkt_hdr->p, data, offset,
 						packet_len, seg_len,
-						layer, ethtype);
+						layer, ethtype,
+						param->chksums);
+
 
 		if (ret)
 			return -1;
diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c
index ad2cb39f8..bf6365e94 100644
--- a/platform/linux-generic/pktio/loop.c
+++ b/platform/linux-generic/pktio/loop.c
@@ -146,7 +146,8 @@ static int loopback_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
 			}
 		} else {
 			packet_parse_layer(pkt_hdr,
-					   pktio_entry->s.config.parser.layer);
+					   pktio_entry->s.config.parser.layer,
+					   pktio_entry->s.in_chksums);
 		}
 
 		packet_set_ts(pkt_hdr, ts);
diff --git a/platform/linux-generic/pktio/pcap.c b/platform/linux-generic/pktio/pcap.c
index 596bf6f28..573c31744 100644
--- a/platform/linux-generic/pktio/pcap.c
+++ b/platform/linux-generic/pktio/pcap.c
@@ -255,7 +255,8 @@ static int pcapif_recv_pkt(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
 		}
 
 		packet_parse_layer(pkt_hdr,
-				   pktio_entry->s.config.parser.layer);
+				   pktio_entry->s.config.parser.layer,
+				   pktio_entry->s.in_chksums);
 		pktio_entry->s.stats.in_octets += pkt_hdr->frame_len;
 
 		packet_set_ts(pkt_hdr, ts);
diff --git a/platform/linux-generic/pktio/socket.c b/platform/linux-generic/pktio/socket.c
index 0a80035f5..d0a55effe 100644
--- a/platform/linux-generic/pktio/socket.c
+++ b/platform/linux-generic/pktio/socket.c
@@ -676,7 +676,8 @@ static int sock_mmsg_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
 
 		if (!pktio_cls_enabled(pktio_entry))
 			packet_parse_layer(pkt_hdr,
-					   pktio_entry->s.config.parser.layer);
+					   pktio_entry->s.config.parser.layer,
+					   pktio_entry->s.in_chksums);
 
 		pkt_hdr->input = pktio_entry->s.handle;
 		packet_set_ts(pkt_hdr, ts);
diff --git a/platform/linux-generic/pktio/socket_mmap.c b/platform/linux-generic/pktio/socket_mmap.c
index c63a25398..f31d34dca 100644
--- a/platform/linux-generic/pktio/socket_mmap.c
+++ b/platform/linux-generic/pktio/socket_mmap.c
@@ -234,7 +234,8 @@ static inline unsigned pkt_mmap_v2_rx(pktio_entry_t *pktio_entry,
 			copy_packet_cls_metadata(&parsed_hdr, hdr);
 		else
 			packet_parse_layer(hdr,
-					   pktio_entry->s.config.parser.layer);
+					   pktio_entry->s.config.parser.layer,
+					   pktio_entry->s.in_chksums);
 
 		packet_set_ts(hdr, ts);
 
diff --git a/platform/linux-generic/pktio/tap.c b/platform/linux-generic/pktio/tap.c
index d8b78f3f8..da7a7b3a2 100644
--- a/platform/linux-generic/pktio/tap.c
+++ b/platform/linux-generic/pktio/tap.c
@@ -285,7 +285,8 @@ static odp_packet_t pack_odp_pkt(pktio_entry_t *pktio_entry, const void *data,
 		copy_packet_cls_metadata(&parsed_hdr, pkt_hdr);
 	else
 		packet_parse_layer(pkt_hdr,
-				   pktio_entry->s.config.parser.layer);
+				   pktio_entry->s.config.parser.layer,
+				   pktio_entry->s.in_chksums);
 
 	packet_set_ts(pkt_hdr, ts);
 	pkt_hdr->input = pktio_entry->s.handle;
