diff --git a/include/odp_packet.h b/include/odp_packet.h
index 3c7c9d0..4a16e11 100644
--- a/include/odp_packet.h
+++ b/include/odp_packet.h
@@ -209,6 +209,17 @@ void odp_packet_set_l4_offset(odp_packet_t pkt, size_t offset);
  */
 void odp_packet_print(odp_packet_t pkt);
 
+/**
+ * Copy contents and metadata from pkt_src to pkt_dst
+ * Useful when creating copies of packets
+ *
+ * @param pkt_dst Destination packet
+ * @param pkt_src Source packet
+ *
+ * @return 0 if successful
+ */
+int odp_packet_copy(odp_packet_t pkt_dst, odp_packet_t pkt_src);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/platform/linux-generic/include/odp_buffer_internal.h b/platform/linux-generic/include/odp_buffer_internal.h
index c4e5b33..f8ebc7c 100644
--- a/platform/linux-generic/include/odp_buffer_internal.h
+++ b/platform/linux-generic/include/odp_buffer_internal.h
@@ -107,6 +107,8 @@ typedef struct odp_buffer_chunk_hdr_t {
 
 int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf);
 
+void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t buf_src);
+
 
 #ifdef __cplusplus
 }
diff --git a/platform/linux-generic/source/odp_buffer.c b/platform/linux-generic/source/odp_buffer.c
index f506d35..afbe96a 100644
--- a/platform/linux-generic/source/odp_buffer.c
+++ b/platform/linux-generic/source/odp_buffer.c
@@ -111,3 +111,9 @@ void odp_buffer_print(odp_buffer_t buf)
 
 	printf("\n%s\n", str);
 }
+
+void odp_buffer_copy_scatter(odp_buffer_t buf_dst, odp_buffer_t buf_src)
+{
+	(void)buf_dst;
+	(void)buf_src;
+}
diff --git a/platform/linux-generic/source/odp_packet.c b/platform/linux-generic/source/odp_packet.c
index 8af5169..eb7c227 100644
--- a/platform/linux-generic/source/odp_packet.c
+++ b/platform/linux-generic/source/odp_packet.c
@@ -328,3 +328,41 @@ void odp_packet_print(odp_packet_t pkt)
 
 	printf("\n%s\n", str);
 }
+
+int odp_packet_copy(odp_packet_t pkt_dst, odp_packet_t pkt_src)
+{
+	odp_packet_hdr_t *const pkt_hdr_dst = odp_packet_hdr(pkt_dst);
+	odp_packet_hdr_t *const pkt_hdr_src = odp_packet_hdr(pkt_src);
+	const size_t start_offset = ODP_FIELD_SIZEOF(odp_packet_hdr_t, buf_hdr);
+	uint8_t *start_src;
+	uint8_t *start_dst;
+	size_t len;
+
+	if (pkt_dst == ODP_PACKET_INVALID || pkt_src == ODP_PACKET_INVALID)
+		return -1;
+
+	if (pkt_hdr_dst->buf_hdr.size <
+		pkt_hdr_src->frame_len + pkt_hdr_src->frame_offset)
+		return -1;
+
+	/* Copy packet header */
+	start_dst = (uint8_t *)pkt_hdr_dst + start_offset;
+	start_src = (uint8_t *)pkt_hdr_src + start_offset;
+	len = ODP_OFFSETOF(odp_packet_hdr_t, payload) - start_offset;
+	memcpy(start_dst, start_src, len);
+
+	/* Copy frame payload */
+	start_dst = (uint8_t *)odp_packet_start(pkt_dst);
+	start_src = (uint8_t *)odp_packet_start(pkt_src);
+	len = pkt_hdr_src->frame_len;
+	memcpy(start_dst, start_src, len);
+
+	/* Copy useful things from the buffer header */
+	pkt_hdr_dst->buf_hdr.cur_offset = pkt_hdr_src->buf_hdr.cur_offset;
+
+	/* Create a copy of the scatter list */
+	odp_buffer_copy_scatter(odp_buffer_from_packet(pkt_dst),
+				odp_buffer_from_packet(pkt_src));
+
+	return 0;
+}
diff --git a/test/packet_netmap/odp_example_pktio_netmap.c b/test/packet_netmap/odp_example_pktio_netmap.c
index 2d74f8a..7c60467 100644
--- a/test/packet_netmap/odp_example_pktio_netmap.c
+++ b/test/packet_netmap/odp_example_pktio_netmap.c
@@ -25,6 +25,7 @@
 #include <helper/odp_linux.h>
 #include <helper/odp_eth.h>
 #include <helper/odp_ip.h>
+#include <helper/odp_packet_helper.h>
 
 #include <odp_pktio_netmap.h>
 
@@ -149,33 +150,25 @@ static void *pktio_queue_thread(void *arg)
 
 		/* Lookup the thread associated with the entry */
 		pktio_nr = args->pktio_tbl[pktio_tmp];
-		odp_queue_enq(args->thread[pktio_nr].bridge_q, buf);
 
 		/* Send back packets arrived on physical interface */
 		if (args->thread[pktio_nr].netmap_mode == ODP_NETMAP_MODE_HW) {
 			odp_packet_t pkt_copy;
-			odp_buffer_t buf_copy;
-			size_t frame_len = odp_packet_get_len(pkt);
-			size_t l2_offset = odp_packet_l2_offset(pkt);
-			size_t l3_offset = odp_packet_l3_offset(pkt);
-
-			buf_copy = odp_buffer_alloc(pkt_pool);
-			pkt_copy = odp_packet_from_buffer(buf_copy);
-
-			odp_packet_init(pkt_copy);
-			odp_packet_set_len(pkt_copy, frame_len);
-			odp_packet_set_l2_offset(pkt_copy, l2_offset);
-			odp_packet_set_l3_offset(pkt_copy, l3_offset);
-
-			memcpy(odp_buffer_addr(pkt_copy),
-			       odp_buffer_addr(pkt), frame_len);
 
-			swap_pkt_addrs(&pkt_copy, 1);
+			pkt_copy = odp_packet_alloc(pkt_pool);
 
-			buf_copy = odp_buffer_from_packet(pkt_copy);
-			odp_queue_enq(outq_def, buf_copy);
+			if (odp_packet_copy(pkt_copy, pkt) != 0) {
+				ODP_ERR("Packet copy failed!\n");
+				odp_packet_free(pkt_copy);
+			} else {
+				swap_pkt_addrs(&pkt_copy, 1);
+				odp_queue_enq(outq_def,
+					      odp_buffer_from_packet(pkt_copy));
+			}
 		}
 
+		odp_queue_enq(args->thread[pktio_nr].bridge_q, buf);
+
 		/* Print packet counts every once in a while */
 		if (odp_unlikely(pkt_cnt++ % 100000 == 0)) {
 			printf("  [%02i] pkt_cnt:%lu\n", thr, pkt_cnt);
