diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h
index 90dfe80..9890dc8 100644
--- a/platform/linux-generic/include/odp_packet_internal.h
+++ b/platform/linux-generic/include/odp_packet_internal.h
@@ -34,7 +34,8 @@ typedef union {
 	uint32_t all;
 
 	struct {
-		/* Bitfield flags for each protocol */
+		uint32_t unparsed:1;  /**< Set to inticate parse needed */
+
 		uint32_t l2:1;        /**< known L2 protocol present */
 		uint32_t l3:1;        /**< known L3 protocol present */
 		uint32_t l4:1;        /**< known L4 protocol present */
@@ -245,6 +246,14 @@ static inline void packet_set_len(odp_packet_t pkt, uint32_t len)
 	odp_packet_hdr(pkt)->frame_len = len;
 }
 
+#define ODP_PACKET_UNPARSED ~0
+
+static inline void _odp_packet_reset_parse(odp_packet_t pkt)
+{
+	odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
+	pkt_hdr->input_flags.all = ODP_PACKET_UNPARSED;
+}
+
 /* Forward declarations */
 int _odp_packet_copy_to_packet(odp_packet_t srcpkt, uint32_t srcoffset,
 			       odp_packet_t dstpkt, uint32_t dstoffset,
@@ -254,7 +263,7 @@ void _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt);
 
 odp_packet_t _odp_packet_alloc(odp_pool_t pool_hdl);
 
-int _odp_packet_parse(odp_packet_t pkt);
+int _odp_packet_parse(odp_packet_hdr_t *pkt_hdr);
 
 /* Convert a packet handle to a buffer handle */
 odp_buffer_t _odp_packet_to_buffer(odp_packet_t pkt);
diff --git a/platform/linux-generic/odp_classification.c b/platform/linux-generic/odp_classification.c
index 0e46b1b..fdb544d 100644
--- a/platform/linux-generic/odp_classification.c
+++ b/platform/linux-generic/odp_classification.c
@@ -823,6 +823,10 @@ cos_t *pktio_select_cos(pktio_entry_t *entry, uint8_t *pkt_addr,
 
 	cls = &entry->s.cls;
 
+	/* Check for lazy parse needed */
+	if (pkt_hdr->input_flags.unparsed)
+		_odp_packet_parse(pkt_hdr);
+
 	/* Return error cos for error packet */
 	if (pkt_hdr->error_flags.all)
 		return cls->error_cos;
diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c
index 3ef0267..668ddda 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -242,12 +242,17 @@ uint32_t odp_packet_user_area_size(odp_packet_t pkt)
 void *odp_packet_l2_ptr(odp_packet_t pkt, uint32_t *len)
 {
 	odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
+	if (pkt_hdr->input_flags.unparsed)
+		_odp_packet_parse(pkt_hdr);
 	return packet_map(pkt_hdr, pkt_hdr->l2_offset, len);
 }
 
 uint32_t odp_packet_l2_offset(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->l2_offset;
+	odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
+	if (pkt_hdr->input_flags.unparsed)
+		_odp_packet_parse(pkt_hdr);
+	return pkt_hdr->l2_offset;
 }
 
 int odp_packet_l2_offset_set(odp_packet_t pkt, uint32_t offset)
@@ -257,6 +262,8 @@ int odp_packet_l2_offset_set(odp_packet_t pkt, uint32_t offset)
 	if (offset >= pkt_hdr->frame_len)
 		return -1;
 
+	if (pkt_hdr->input_flags.unparsed)
+		_odp_packet_parse(pkt_hdr);
 	pkt_hdr->l2_offset = offset;
 	return 0;
 }
@@ -264,12 +271,17 @@ int odp_packet_l2_offset_set(odp_packet_t pkt, uint32_t offset)
 void *odp_packet_l3_ptr(odp_packet_t pkt, uint32_t *len)
 {
 	odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
+	if (pkt_hdr->input_flags.unparsed)
+		_odp_packet_parse(pkt_hdr);
 	return packet_map(pkt_hdr, pkt_hdr->l3_offset, len);
 }
 
 uint32_t odp_packet_l3_offset(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->l3_offset;
+	odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
+	if (pkt_hdr->input_flags.unparsed)
+		_odp_packet_parse(pkt_hdr);
+	return pkt_hdr->l3_offset;
 }
 
 int odp_packet_l3_offset_set(odp_packet_t pkt, uint32_t offset)
@@ -279,6 +291,8 @@ int odp_packet_l3_offset_set(odp_packet_t pkt, uint32_t offset)
 	if (offset >= pkt_hdr->frame_len)
 		return -1;
 
+	if (pkt_hdr->input_flags.unparsed)
+		_odp_packet_parse(pkt_hdr);
 	pkt_hdr->l3_offset = offset;
 	return 0;
 }
@@ -286,12 +300,17 @@ int odp_packet_l3_offset_set(odp_packet_t pkt, uint32_t offset)
 void *odp_packet_l4_ptr(odp_packet_t pkt, uint32_t *len)
 {
 	odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
+	if (pkt_hdr->input_flags.unparsed)
+		_odp_packet_parse(pkt_hdr);
 	return packet_map(pkt_hdr, pkt_hdr->l4_offset, len);
 }
 
 uint32_t odp_packet_l4_offset(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->l4_offset;
+	odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
+	if (pkt_hdr->input_flags.unparsed)
+		_odp_packet_parse(pkt_hdr);
+	return pkt_hdr->l4_offset;
 }
 
 int odp_packet_l4_offset_set(odp_packet_t pkt, uint32_t offset)
@@ -301,6 +320,8 @@ int odp_packet_l4_offset_set(odp_packet_t pkt, uint32_t offset)
 	if (offset >= pkt_hdr->frame_len)
 		return -1;
 
+	if (pkt_hdr->input_flags.unparsed)
+		_odp_packet_parse(pkt_hdr);
 	pkt_hdr->l4_offset = offset;
 	return 0;
 }
@@ -814,9 +835,8 @@ static inline void parse_udp(odp_packet_hdr_t *pkt_hdr,
  * Simple packet parser
  */
 
-int _odp_packet_parse(odp_packet_t pkt)
+int _odp_packet_parse(odp_packet_hdr_t *pkt_hdr)
 {
-	odp_packet_hdr_t *const pkt_hdr = odp_packet_hdr(pkt);
 	odph_ethhdr_t *eth;
 	odph_vlanhdr_t *vlan;
 	uint16_t ethtype;
diff --git a/platform/linux-generic/odp_packet_flags.c b/platform/linux-generic/odp_packet_flags.c
index ab3d12f..4f680a1 100644
--- a/platform/linux-generic/odp_packet_flags.c
+++ b/platform/linux-generic/odp_packet_flags.c
@@ -7,182 +7,198 @@
 #include <odp/packet_flags.h>
 #include <odp_packet_internal.h>
 
+#define retflag(p, x) do {			       \
+	odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(p); \
+	if (pkt_hdr->input_flags.unparsed)	       \
+		_odp_packet_parse(pkt_hdr);	       \
+	return pkt_hdr->x;			       \
+	} while (0)
+
+#define setflag(p, x, v) do {			       \
+	odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(p); \
+	if (pkt_hdr->input_flags.unparsed)	       \
+		_odp_packet_parse(pkt_hdr);	       \
+	pkt_hdr->x = v & 1;			       \
+	} while (0)
 
 int odp_packet_has_error(odp_packet_t pkt)
 {
-	return (odp_packet_hdr(pkt)->error_flags.all != 0);
+	odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
+	if (pkt_hdr->input_flags.unparsed)
+		_odp_packet_parse(pkt_hdr);
+	return odp_packet_hdr(pkt)->error_flags.all != 0;
 }
 
 /* Get Input Flags */
 
 int odp_packet_has_l2(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.l2;
+	retflag(pkt, input_flags.l2);
 }
 
 int odp_packet_has_l3(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.l3;
+	retflag(pkt, input_flags.l3);
 }
 
 int odp_packet_has_l4(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.l4;
+	retflag(pkt, input_flags.l4);
 }
 
 int odp_packet_has_eth(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.eth;
+	retflag(pkt, input_flags.eth);
 }
 
 int odp_packet_has_jumbo(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.jumbo;
+	retflag(pkt, input_flags.jumbo);
 }
 
 int odp_packet_has_vlan(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.vlan;
+	retflag(pkt, input_flags.vlan);
 }
 
 int odp_packet_has_vlan_qinq(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.vlan_qinq;
+	retflag(pkt, input_flags.vlan_qinq);
 }
 
 int odp_packet_has_arp(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.arp;
+	retflag(pkt, input_flags.arp);
 }
 
 int odp_packet_has_ipv4(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.ipv4;
+	retflag(pkt, input_flags.ipv4);
 }
 
 int odp_packet_has_ipv6(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.ipv6;
+	retflag(pkt, input_flags.ipv6);
 }
 
 int odp_packet_has_ipfrag(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.ipfrag;
+	retflag(pkt, input_flags.ipfrag);
 }
 
 int odp_packet_has_ipopt(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.ipopt;
+	retflag(pkt, input_flags.ipopt);
 }
 
 int odp_packet_has_ipsec(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.ipsec;
+	retflag(pkt, input_flags.ipsec);
 }
 
 int odp_packet_has_udp(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.udp;
+	retflag(pkt, input_flags.udp);
 }
 
 int odp_packet_has_tcp(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.tcp;
+	retflag(pkt, input_flags.tcp);
 }
 
 int odp_packet_has_sctp(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.sctp;
+	retflag(pkt, input_flags.sctp);
 }
 
 int odp_packet_has_icmp(odp_packet_t pkt)
 {
-	return odp_packet_hdr(pkt)->input_flags.icmp;
+	retflag(pkt, input_flags.icmp);
 }
 
 /* Set Input Flags */
 
 void odp_packet_has_l2_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.l2 = val;
+	setflag(pkt, input_flags.l2, val);
 }
 
 void odp_packet_has_l3_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.l3 = val;
+	setflag(pkt, input_flags.l3, val);
 }
 
 void odp_packet_has_l4_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.l4 = val;
+	setflag(pkt, input_flags.l4, val);
 }
 
 void odp_packet_has_eth_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.eth = val;
+	setflag(pkt, input_flags.eth, val);
 }
 
 void odp_packet_has_jumbo_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.jumbo = val;
+	setflag(pkt, input_flags.jumbo, val);
 }
 
 void odp_packet_has_vlan_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.vlan = val;
+	setflag(pkt, input_flags.vlan, val);
 }
 
 void odp_packet_has_vlan_qinq_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.vlan_qinq = val;
+	setflag(pkt, input_flags.vlan_qinq, val);
 }
 
 void odp_packet_has_arp_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.arp = val;
+	setflag(pkt, input_flags.arp, val);
 }
 
 void odp_packet_has_ipv4_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.ipv4 = val;
+	setflag(pkt, input_flags.ipv4, val);
 }
 
 void odp_packet_has_ipv6_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.ipv6 = val;
+	setflag(pkt, input_flags.ipv6, val);
 }
 
 void odp_packet_has_ipfrag_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.ipfrag = val;
+	setflag(pkt, input_flags.ipfrag, val);
 }
 
 void odp_packet_has_ipopt_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.ipopt = val;
+	setflag(pkt, input_flags.ipopt, val);
 }
 
 void odp_packet_has_ipsec_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.ipsec = val;
+	setflag(pkt, input_flags.ipsec, val);
 }
 
 void odp_packet_has_udp_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.udp = val;
+	setflag(pkt, input_flags.udp, val);
 }
 
 void odp_packet_has_tcp_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.tcp = val;
+	setflag(pkt, input_flags.tcp, val);
 }
 
 void odp_packet_has_sctp_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.sctp = val;
+	setflag(pkt, input_flags.sctp, val);
 }
 
 void odp_packet_has_icmp_set(odp_packet_t pkt, int val)
 {
-	odp_packet_hdr(pkt)->input_flags.icmp = val;
+	setflag(pkt, input_flags.icmp, val);
 }
diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c
index f16685d..5ae24b9 100644
--- a/platform/linux-generic/odp_packet_io.c
+++ b/platform/linux-generic/odp_packet_io.c
@@ -378,7 +378,7 @@ static int deq_loopback(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
 
 	for (i = 0; i < nbr; ++i) {
 		pkts[i] = _odp_packet_from_buffer(odp_hdr_to_buf(hdr_tbl[i]));
-		_odp_packet_parse(pkts[i]);
+		_odp_packet_reset_parse(pkts[i]);
 	}
 
 	return nbr;
diff --git a/platform/linux-generic/odp_packet_socket.c b/platform/linux-generic/odp_packet_socket.c
index 2802c43..9272146 100644
--- a/platform/linux-generic/odp_packet_socket.c
+++ b/platform/linux-generic/odp_packet_socket.c
@@ -251,7 +251,7 @@ int recv_pkt_sock_basic(pkt_sock_t *const pkt_sock,
 
 		/* Parse and set packet header data */
 		odp_packet_pull_tail(pkt, pkt_sock->max_frame_len - recv_bytes);
-		_odp_packet_parse(pkt);
+		_odp_packet_reset_parse(pkt);
 
 		pkt_table[nb_rx] = pkt;
 		pkt = ODP_PACKET_INVALID;
@@ -360,7 +360,7 @@ int recv_pkt_sock_mmsg(pkt_sock_t *const pkt_sock,
 		odp_packet_pull_tail(pkt_table[i],
 				     pkt_sock->max_frame_len -
 				     msgvec[i].msg_len);
-		_odp_packet_parse(pkt_table[i]);
+		_odp_packet_reset_parse(pkt_table[i]);
 
 		pkt_table[nb_rx] = pkt_table[i];
 		nb_rx++;
@@ -519,7 +519,7 @@ static inline unsigned pkt_mmap_v2_rx(int sock, struct ring *ring,
 			mmap_rx_user_ready(ppd.raw);
 
 			/* Parse and set packet header data */
-			_odp_packet_parse(pkt_table[i]);
+			_odp_packet_reset_parse(pkt_table[i]);
 
 			frame_num = next_frame_num;
 			i++;
