diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h
index d5ace12..ab54227 100644
--- a/platform/linux-generic/include/odp_packet_internal.h
+++ b/platform/linux-generic/include/odp_packet_internal.h
@@ -192,6 +192,9 @@ static inline void copy_packet_parser_metadata(odp_packet_hdr_t *src_hdr,
 	dst_hdr->l4_len         = src_hdr->l4_len;
 
 	dst_hdr->dst_queue      = src_hdr->dst_queue;
+	dst_hdr->flow_hash      = src_hdr->flow_hash;
+	dst_hdr->timestamp      = src_hdr->timestamp;
+	dst_hdr->op_result      = src_hdr->op_result;
 }
 
 static inline void *packet_map(odp_packet_hdr_t *pkt_hdr,
@@ -294,7 +297,7 @@ static inline int packet_parse_not_complete(odp_packet_hdr_t *pkt_hdr)
 }
 
 /* Forward declarations */
-void _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt);
+int _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt);
 
 odp_packet_t packet_alloc(odp_pool_t pool_hdl, uint32_t len, int parse);
 
diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c
index 2868736..40549a8 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -756,22 +756,11 @@ odp_packet_t odp_packet_copy(odp_packet_t pkt, odp_pool_t pool)
 {
 	odp_packet_hdr_t *srchdr = odp_packet_hdr(pkt);
 	uint32_t pktlen = srchdr->frame_len;
-	uint32_t meta_offset = ODP_FIELD_SIZEOF(odp_packet_hdr_t, buf_hdr);
 	odp_packet_t newpkt = odp_packet_alloc(pool, pktlen);
 
 	if (newpkt != ODP_PACKET_INVALID) {
-		odp_packet_hdr_t *newhdr = odp_packet_hdr(newpkt);
-		uint8_t *newstart, *srcstart;
-
-		/* Must copy metadata first, followed by packet data */
-		newstart = (uint8_t *)newhdr + meta_offset;
-		srcstart = (uint8_t *)srchdr + meta_offset;
-
-		memcpy(newstart, srcstart,
-		       sizeof(odp_packet_hdr_t) - meta_offset);
-
-		if (odp_packet_copy_from_pkt(newpkt, 0, pkt, 0,
-					     pktlen) != 0) {
+		if (_odp_packet_copy_md_to_packet(pkt, newpkt) ||
+		    odp_packet_copy_from_pkt(newpkt, 0, pkt, 0, pktlen)) {
 			odp_packet_free(newpkt);
 			newpkt = ODP_PACKET_INVALID;
 		}
@@ -966,7 +955,7 @@ int odp_packet_is_valid(odp_packet_t pkt)
  *
  */
 
-void _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt)
+int _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt)
 {
 	odp_packet_hdr_t *srchdr = odp_packet_hdr(srcpkt);
 	odp_packet_hdr_t *dsthdr = odp_packet_hdr(dstpkt);
@@ -986,6 +975,12 @@ void _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt)
 		odp_atomic_load_u32(
 			&srchdr->buf_hdr.ref_count));
 	copy_packet_parser_metadata(srchdr, dsthdr);
+
+	/* Metadata copied, but return indication of whether the packet
+	 * user area was truncated in the process. Note this can only
+	 * happen when copying between different pools.
+	 */
+	return dsthdr->buf_hdr.uarea_size < srchdr->buf_hdr.uarea_size;
 }
 
 /**
diff --git a/test/validation/packet/packet.c b/test/validation/packet/packet.c
index 6770339..f71b658 100644
--- a/test/validation/packet/packet.c
+++ b/test/validation/packet/packet.c
@@ -863,32 +863,41 @@ free_packet:
 	odp_packet_free(pkt);
 }
 
-#define COMPARE_INFLAG(p1, p2, flag) \
+#define COMPARE_HAS_INFLAG(p1, p2, flag) \
 	CU_ASSERT(odp_packet_has_##flag(p1) == odp_packet_has_##flag(p2))
 
+#define COMPARE_INFLAG(p1, p2, flag) \
+	CU_ASSERT(odp_packet_##flag(p1) == odp_packet_##flag(p2))
+
 static void _packet_compare_inflags(odp_packet_t pkt1, odp_packet_t pkt2)
 {
-	COMPARE_INFLAG(pkt1, pkt2, l2);
-	COMPARE_INFLAG(pkt1, pkt2, l3);
-	COMPARE_INFLAG(pkt1, pkt2, l4);
-	COMPARE_INFLAG(pkt1, pkt2, eth);
-	COMPARE_INFLAG(pkt1, pkt2, eth_bcast);
-	COMPARE_INFLAG(pkt1, pkt2, eth_mcast);
-	COMPARE_INFLAG(pkt1, pkt2, jumbo);
-	COMPARE_INFLAG(pkt1, pkt2, vlan);
-	COMPARE_INFLAG(pkt1, pkt2, vlan_qinq);
-	COMPARE_INFLAG(pkt1, pkt2, arp);
-	COMPARE_INFLAG(pkt1, pkt2, ipv4);
-	COMPARE_INFLAG(pkt1, pkt2, ipv6);
-	COMPARE_INFLAG(pkt1, pkt2, ip_bcast);
-	COMPARE_INFLAG(pkt1, pkt2, ip_mcast);
-	COMPARE_INFLAG(pkt1, pkt2, ipfrag);
-	COMPARE_INFLAG(pkt1, pkt2, ipopt);
-	COMPARE_INFLAG(pkt1, pkt2, ipsec);
-	COMPARE_INFLAG(pkt1, pkt2, udp);
-	COMPARE_INFLAG(pkt1, pkt2, tcp);
-	COMPARE_INFLAG(pkt1, pkt2, sctp);
-	COMPARE_INFLAG(pkt1, pkt2, icmp);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, l2);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, l3);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, l4);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, eth);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, eth_bcast);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, eth_mcast);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, jumbo);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, vlan);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, vlan_qinq);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, arp);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, ipv4);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, ipv6);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, ip_bcast);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, ip_mcast);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, ipfrag);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, ipopt);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, ipsec);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, udp);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, tcp);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, sctp);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, icmp);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, flow_hash);
+	COMPARE_HAS_INFLAG(pkt1, pkt2, ts);
+
+	COMPARE_INFLAG(pkt1, pkt2, color);
+	COMPARE_INFLAG(pkt1, pkt2, drop_eligible);
+	COMPARE_INFLAG(pkt1, pkt2, shaper_len_adjust);
 }
 
 static void _packet_compare_data(odp_packet_t pkt1, odp_packet_t pkt2)
