diff --git a/include/odp.h b/include/odp.h
index 08c7c31..6a52346 100644
--- a/include/odp.h
+++ b/include/odp.h
@@ -295,6 +295,7 @@ extern "C" {
 #include <odp_schedule.h>
 #include <odp_sync.h>
 #include <odp_packet.h>
+#include <odp_packet_flags.h>
 #include <odp_packet_io.h>
 
 #ifdef __cplusplus
diff --git a/include/odp_packet_flags.h b/include/odp_packet_flags.h
new file mode 100644
index 0000000..eb9315b
--- /dev/null
+++ b/include/odp_packet_flags.h
@@ -0,0 +1,189 @@
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+
+/**
+ * @file
+ *
+ * ODP packet flags
+ */
+
+#ifndef ODP_PACKET_FLAGS_H_
+#define ODP_PACKET_FLAGS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp_std_types.h>
+#include <odp_packet.h>
+
+/**
+ * Check for packet errors
+ *
+ * Checks all error flags at once.
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet has errors, 0 otherwise
+ */
+int odp_packet_error(odp_packet_t pkt);
+
+/**
+ * Check if error was 'frame length' error
+ *
+ * @param pkt Packet handle
+ * @return 1 if frame length error detected, 0 otherwise
+ */
+int odp_packet_errflag_frame_len(odp_packet_t pkt);
+
+/**
+ * Check for L2 header, e.g. ethernet
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains a valid & known L2 header, 0 otherwise
+ */
+int odp_packet_inflag_l2(odp_packet_t pkt);
+
+/**
+ * Check for L3 header, e.g. IPv4, IPv6
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains a valid & known L3 header, 0 otherwise
+ */
+int odp_packet_inflag_l3(odp_packet_t pkt);
+
+/**
+ * Check for L4 header, e.g. UDP, TCP, SCTP (also ICMP)
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains a valid & known L4 header, 0 otherwise
+ */
+int odp_packet_inflag_l4(odp_packet_t pkt);
+
+/**
+ * Check for Ethernet header
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains a valid eth header, 0 otherwise
+ */
+int odp_packet_inflag_eth(odp_packet_t pkt);
+
+/**
+ * Check for jumbo frame
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains jumbo frame, 0 otherwise
+ */
+int odp_packet_inflag_jumbo(odp_packet_t pkt);
+
+/**
+ * Check for VLAN
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains a VLAN header, 0 otherwise
+ */
+int odp_packet_inflag_vlan(odp_packet_t pkt);
+
+/**
+ * Check for VLAN QinQ (stacked VLAN)
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains a VLAN QinQ header, 0 otherwise
+ */
+int odp_packet_inflag_vlan_qinq(odp_packet_t pkt);
+
+/**
+ * Check for ARP
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains an ARP header, 0 otherwise
+ */
+int odp_packet_inflag_arp(odp_packet_t pkt);
+
+/**
+ * Check for IPv4
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains an IPv4 header, 0 otherwise
+ */
+int odp_packet_inflag_ipv4(odp_packet_t pkt);
+
+/**
+ * Check for IPv6
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains an IPv6 header, 0 otherwise
+ */
+int odp_packet_inflag_ipv6(odp_packet_t pkt);
+
+/**
+ * Check for IP fragment
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet is an IP fragment, 0 otherwise
+ */
+int odp_packet_inflag_ipfrag(odp_packet_t pkt);
+
+/**
+ * Check for IP options
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains IP options, 0 otherwise
+ */
+int odp_packet_inflag_ipopt(odp_packet_t pkt);
+
+/**
+ * Check for IPSec
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet requires IPSec processing, 0 otherwise
+ */
+int odp_packet_inflag_ipsec(odp_packet_t pkt);
+
+/**
+ * Check for UDP
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains a UDP header, 0 otherwise
+ */
+int odp_packet_inflag_udp(odp_packet_t pkt);
+
+/**
+ * Check for TCP
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains a TCP header, 0 otherwise
+ */
+int odp_packet_inflag_tcp(odp_packet_t pkt);
+
+/**
+ * Check for SCTP
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains an SCTP header, 0 otherwise
+ */
+int odp_packet_inflag_sctp(odp_packet_t pkt);
+
+/**
+ * Check for ICMP
+ *
+ * @param pkt Packet handle
+ * @return 1 if packet contains an ICMP header, 0 otherwise
+ */
+int odp_packet_inflag_icmp(odp_packet_t pkt);
+
+/**
+ * Request L4 checksum calculation
+ *
+ * @param pkt Packet handle
+ */
+void odp_packet_outflag_l4_chksum(odp_packet_t pkt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/linux-generic/Makefile b/platform/linux-generic/Makefile
index f665683..b640928 100644
--- a/platform/linux-generic/Makefile
+++ b/platform/linux-generic/Makefile
@@ -54,6 +54,7 @@ OBJS    += $(OBJ_DIR)/odp_coremask.o
 OBJS    += $(OBJ_DIR)/odp_init.o
 OBJS    += $(OBJ_DIR)/odp_linux.o
 OBJS    += $(OBJ_DIR)/odp_packet.o
+OBJS    += $(OBJ_DIR)/odp_packet_flags.o
 OBJS    += $(OBJ_DIR)/odp_packet_io.o
 OBJS    += $(OBJ_DIR)/odp_packet_socket.o
 OBJS    += $(OBJ_DIR)/odp_queue.o
diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h
index afef976..f0dda95 100644
--- a/platform/linux-generic/include/odp_packet_internal.h
+++ b/platform/linux-generic/include/odp_packet_internal.h
@@ -25,59 +25,98 @@ extern "C" {
 #include <odp_packet.h>
 #include <odp_packet_io.h>
 
-typedef struct {
-	uint32_t l2:1;
-	uint32_t l3:1;
-	uint32_t l4:1;
-
-	uint32_t macsec:1;
-	uint32_t vlan:1;
-	uint32_t vlan_double:1;
-	uint32_t ipv4:1;
-	uint32_t ipv6:1;
-	uint32_t ip_frag:1;
-	uint32_t udp:1;
-	uint32_t tcp:1;
-	uint32_t icmp:1;
-} proto_flags_t;
+/**
+ * Packet input & protocol flags
+ */
+typedef union {
+	/* All input flags */
+	uint32_t all;
 
-typedef struct {
-	uint32_t frame_len:1;
-	uint32_t l2_chksum:1;
-	uint32_t ip_err:1;
-	uint32_t tcp_err:1;
-	uint32_t udp_err:1;
+	/* Bitfield flags for each protocol */
+	uint32_t l2:1;        /**< known L2 protocol present */
+	uint32_t l3:1;        /**< known L3 protocol present */
+	uint32_t l4:1;        /**< known L4 protocol present */
+
+	uint32_t eth:1;       /**< Ethernet */
+	uint32_t jumbo:1;     /**< Jumbo frame */
+	uint32_t vlan:1;      /**< VLAN hdr found */
+	uint32_t vlan_qinq:1; /**< Stacked VLAN found, QinQ */
+
+	uint32_t arp:1;       /**< ARP */
+
+	uint32_t ipv4:1;      /**< IPv4 */
+	uint32_t ipv6:1;      /**< IPv6 */
+	uint32_t ipfrag:1;    /**< IP fragment */
+	uint32_t ipopt:1;     /**< IP optional headers */
+	uint32_t ipsec;       /**< IPSec decryption may be needed */
+
+	uint32_t udp:1;       /**< UDP */
+	uint32_t tcp:1;       /**< TCP */
+	uint32_t sctp:1;      /**< SCTP */
+	uint32_t icmp:1;      /**< ICMP */
+} input_flags_t;
+
+ODP_ASSERT(sizeof(input_flags_t) == sizeof(uint32_t), INPUT_FLAGS_SIZE_ERROR);
+
+/**
+ * Packet error flags
+ */
+typedef union {
+	/* All error flags */
+	uint32_t all;
+
+	/* Bitfield flags for each detected error */
+	uint32_t frame_len:1; /**< Frame length error */
+	uint32_t l2_chksum:1; /**< L2 checksum error, checks TBD */
+	uint32_t ip_err:1;    /**< IP error,  checks TBD */
+	uint32_t tcp_err:1;   /**< TCP error, checks TBD */
+	uint32_t udp_err:1;   /**< UDP error, checks TBD */
 } error_flags_t;
 
-typedef struct {
-	uint32_t calc_l4_chksum:1;
+ODP_ASSERT(sizeof(error_flags_t) == sizeof(uint32_t), ERROR_FLAGS_SIZE_ERROR);
+
+/**
+ * Packet output flags
+ */
+typedef union {
+	/* All output flags */
+	uint32_t all;
+
+	/* Bitfield flags for each output option */
+	uint32_t l4_chksum:1; /**< Request L4 checksum calculation */
 } output_flags_t;
 
+ODP_ASSERT(sizeof(output_flags_t) == sizeof(uint32_t), OUTPUT_FLAGS_SIZE_ERROR);
+
 /**
  * Internal Packet header
  */
-typedef struct odp_packet_hdr_t {
+typedef struct {
 	/* common buffer header */
 	odp_buffer_hdr_t buf_hdr;
 
-	proto_flags_t  proto_flags;
+	input_flags_t  input_flags;
 	error_flags_t  error_flags;
 	output_flags_t output_flags;
 
-	uint32_t l2_offset;
-	uint32_t l3_offset;
-	uint32_t l4_offset;
+	uint32_t frame_offset; /**< offset to start of frame, even on error */
+	uint32_t l2_offset; /**< offset to L2 hdr, e.g. Eth */
+	uint32_t l3_offset; /**< offset to L3 hdr, e.g. IPv4, IPv6 */
+	uint32_t l4_offset; /**< offset to L4 hdr (TCP, UDP, SCTP, also ICMP) */
 
 	uint32_t frame_len;
 
 	odp_pktio_t input;
 
+	uint32_t pad;
 	uint8_t payload[];
 
 } odp_packet_hdr_t;
 
 ODP_ASSERT(sizeof(odp_packet_hdr_t) == ODP_OFFSETOF(odp_packet_hdr_t, payload),
 	   ODP_PACKET_HDR_T__SIZE_ERR);
+ODP_ASSERT(sizeof(odp_packet_hdr_t) % sizeof(uint64_t) == 0,
+	   ODP_PACKET_HDR_T__SIZE_ERR2);
 
 /**
  * Return the packet header
diff --git a/platform/linux-generic/source/odp_packet.c b/platform/linux-generic/source/odp_packet.c
index 6b06f76..6ee2c5b 100644
--- a/platform/linux-generic/source/odp_packet.c
+++ b/platform/linux-generic/source/odp_packet.c
@@ -124,7 +124,7 @@ void odp_packet_parse(odp_packet_t pkt, size_t len, size_t l2_offset)
 	if (odp_unlikely(len < ODP_ETH_LEN_MIN))
 		pkt_hdr->error_flags.frame_len = 1;
 
-	pkt_hdr->proto_flags.l2 = 1;
+	pkt_hdr->input_flags.l2 = 1;
 	pkt_hdr->l2_offset = l2_offset;
 	eth = (odp_ethhdr_t *)odp_packet_l2(pkt);
 
@@ -132,25 +132,25 @@ void odp_packet_parse(odp_packet_t pkt, size_t len, size_t l2_offset)
 	vlan = (odp_vlanhdr_t *)&eth->type;
 
 	if (ethtype == ODP_ETHTYPE_VLAN_OUTER) {
-		pkt_hdr->proto_flags.vlan_double = 1;
+		pkt_hdr->input_flags.vlan_qinq = 1;
 		ethtype = odp_be_to_cpu_16(vlan->tpid);
 		offset += sizeof(odp_vlanhdr_t);
 		vlan = &vlan[1];
 	}
 
 	if (ethtype == ODP_ETHTYPE_VLAN) {
-		pkt_hdr->proto_flags.vlan = 1;
+		pkt_hdr->input_flags.vlan = 1;
 		ethtype = odp_be_to_cpu_16(vlan->tpid);
 		offset += sizeof(odp_vlanhdr_t);
 	}
 
-	pkt_hdr->proto_flags.l3 = 1;
+	pkt_hdr->input_flags.l3 = 1;
 	pkt_hdr->l3_offset = l2_offset + ODP_ETHHDR_LEN + offset;
 
 	if (ethtype == ODP_ETHTYPE_IPV4) {
 		uint8_t ihl;
 
-		pkt_hdr->proto_flags.ipv4 = 1;
+		pkt_hdr->input_flags.ipv4 = 1;
 		ip = (odp_ipv4hdr_t *)odp_packet_l3(pkt);
 
 		ihl = ODP_IPV4HDR_IHL(ip->ver_ihl);
@@ -159,19 +159,19 @@ void odp_packet_parse(odp_packet_t pkt, size_t len, size_t l2_offset)
 			return;
 		}
 
-		pkt_hdr->proto_flags.l4 = 1;
+		pkt_hdr->input_flags.l4 = 1;
 		pkt_hdr->l4_offset = pkt_hdr->l3_offset +
 				     sizeof(uint32_t) * ihl;
 
 		switch (ip->proto) {
 		case ODP_IPPROTO_UDP:
-			pkt_hdr->proto_flags.udp = 1;
+			pkt_hdr->input_flags.udp = 1;
 			break;
 		case ODP_IPPROTO_TCP:
-			pkt_hdr->proto_flags.tcp = 1;
+			pkt_hdr->input_flags.tcp = 1;
 			break;
 		case ODP_IPPROTO_ICMP:
-			pkt_hdr->proto_flags.icmp = 1;
+			pkt_hdr->input_flags.icmp = 1;
 			break;
 		}
 	}
diff --git a/platform/linux-generic/source/odp_packet_flags.c b/platform/linux-generic/source/odp_packet_flags.c
new file mode 100644
index 0000000..0fd0aa9
--- /dev/null
+++ b/platform/linux-generic/source/odp_packet_flags.c
@@ -0,0 +1,116 @@
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+ #include <odp_packet_flags.h>
+ #include <odp_packet_internal.h>
+
+
+int odp_packet_error(odp_packet_t pkt)
+{
+	return (odp_packet_hdr(pkt)->error_flags.all != 0);
+}
+
+/* Get Error Flags */
+
+int odp_packet_errflag_frame_len(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->error_flags.frame_len;
+}
+
+/* Get Input Flags */
+
+int odp_packet_inflag_l2(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.l2;
+}
+
+int odp_packet_inflag_l3(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.l3;
+}
+
+int odp_packet_inflag_l4(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.l4;
+}
+
+int odp_packet_inflag_eth(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.eth;
+}
+
+int odp_packet_inflag_jumbo(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.jumbo;
+}
+
+int odp_packet_inflag_vlan(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.vlan;
+}
+
+int odp_packet_inflag_vlan_qinq(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.vlan_qinq;
+}
+
+int odp_packet_inflag_arp(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.arp;
+}
+
+int odp_packet_inflag_ipv4(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.ipv4;
+}
+
+int odp_packet_inflag_ipv6(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.ipv6;
+}
+
+int odp_packet_inflag_ipfrag(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.ipfrag;
+}
+
+int odp_packet_inflag_ipopt(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.ipopt;
+}
+
+int odp_packet_inflag_ipsec(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.ipsec;
+}
+
+int odp_packet_inflag_udp(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.udp;
+}
+
+int odp_packet_inflag_tcp(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.tcp;
+}
+
+int odp_packet_inflag_sctp(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.sctp;
+}
+
+int odp_packet_inflag_icmp(odp_packet_t pkt)
+{
+	return odp_packet_hdr(pkt)->input_flags.icmp;
+}
+
+/* Set Output Flags */
+
+void odp_packet_outflag_l4_chksum(odp_packet_t pkt)
+{
+	odp_packet_hdr(pkt)->output_flags.l4_chksum = 1;
+}
+
