diff mbox series

[ovs-dev,4/5] lib/dp-packet: Fold the 'packets' module into dp-packets.

Message ID 20260309161852.748047-5-aconole@redhat.com
State Changes Requested
Headers show
Series libopenvswitch: Restructure the massive OVS library into two parts. | expand

Checks

Context Check Description
ovsrobot/apply-robot warning apply and check: warning
ovsrobot/github-robot-_Build_and_Test success github build: passed

Commit Message

Aaron Conole March 9, 2026, 4:18 p.m. UTC
The leftover packets module was almost completely dealing with
dp-packet work anyway, so fold it into the dp-packets translation
unit to keep things consistent.  During this process, also move
some of the packet metadata stuff out and remove the packets
translation unit.

There were some additional cleanups here where packets.h was
pulling in all sorts of other dependencies into translation units
that didn't actually need them.  So the .c files are widely
updated to include just those headers they need (based on compiler
warnings).

Finally, there's a weird quirk in eth_push_vlan where a memmove
optimization bug seems to pop up, so add a comment on why there
are two warnings disabled.  The dp_packet_resize_l2 calling order
seems to matter, and an alternative is to force it to never
inline that function, but it seems worse to just disabling the
warnings.

Signed-off-by: Aaron Conole <aconole@redhat.com>
---
 lib/automake.mk                    |    2 -
 lib/bfd.c                          |    1 -
 lib/bfd.h                          |    2 +-
 lib/cfm.c                          |    1 -
 lib/cfm.h                          |    1 -
 lib/classifier.c                   |    1 -
 lib/conntrack-private.h            |    1 -
 lib/conntrack.h                    |    2 +-
 lib/ct-dpif.c                      |    1 +
 lib/ct-dpif.h                      |    3 +-
 lib/dhcp.h                         |    1 -
 lib/dp-packet.c                    | 1408 +++++++++++++++++++++++++++
 lib/dp-packet.h                    |  106 ++-
 lib/dpctl.c                        |    1 -
 lib/dpif-netdev-extract-avx512.c   |    1 -
 lib/dpif-netdev-lookup.c           |    1 +
 lib/dpif-netdev-private-extract.c  |    1 +
 lib/dpif-netdev-private-flow.h     |    1 +
 lib/dpif-netdev.c                  |    1 -
 lib/dpif-netdev.h                  |    1 -
 lib/dpif-netlink-rtnl.c            |    1 +
 lib/dpif-netlink.c                 |    1 -
 lib/dpif-offload-dpdk-netdev.c     |    3 +-
 lib/dpif-offload-dpdk.c            |    3 +
 lib/dpif.c                         |    1 -
 lib/dpif.h                         |    1 -
 lib/flow.c                         |    2 +-
 lib/flow.h                         |  157 ++-
 lib/ipf.c                          |    2 +-
 lib/lacp.c                         |    1 -
 lib/lacp.h                         |    6 +-
 lib/lldp/lldp.c                    |    1 -
 lib/lldp/lldpd-structs.h           |    1 -
 lib/lldp/lldpd.c                   |    1 -
 lib/lldp/lldpd.h                   |    1 -
 lib/mac-learning.c                 |    2 +
 lib/mac-learning.h                 |    1 -
 lib/match.c                        |    1 -
 lib/mcast-snooping.h               |    1 -
 lib/meta-flow.c                    |    1 -
 lib/multipath.c                    |    1 -
 lib/netdev-afxdp.c                 |    1 -
 lib/netdev-bsd.c                   |    1 -
 lib/netdev-dpdk.c                  |    1 -
 lib/netdev-dummy.c                 |    1 -
 lib/netdev-linux.c                 |    1 -
 lib/netdev-native-tnl.c            |    4 +-
 lib/netdev-native-tnl.h            |    1 -
 lib/netdev-provider.h              |    1 -
 lib/netdev-vport.c                 |    1 -
 lib/netdev-windows.c               |    1 -
 lib/netdev.c                       |    1 -
 lib/netdev.h                       |    1 -
 lib/nx-match.c                     |    2 +-
 lib/odp-execute-avx512.c           |    2 +-
 lib/odp-execute-private.c          |    1 +
 lib/odp-execute.c                  |    1 -
 lib/odp-util.c                     |    2 +-
 lib/odp-util.h                     |    1 +
 lib/ofp-ct.c                       |    2 +
 lib/ofp-ed-props.c                 |    2 -
 lib/ofp-match.c                    |    2 +
 lib/ofp-parse.c                    |    2 +-
 lib/ofp-print.c                    |    1 -
 lib/ofp-util.c                     |    1 -
 lib/ovs-lldp.c                     |    1 -
 lib/ovs-lldp.h                     |    1 -
 lib/ovs-router.c                   |    1 -
 lib/packets.c                      | 1420 ----------------------------
 lib/packets.h                      |  282 ------
 lib/pcap-file.c                    |    1 -
 lib/route-table-bsd.c              |    2 +-
 lib/route-table.c                  |    1 -
 lib/rstp-common.h                  |    1 -
 lib/rstp-state-machines.c          |    1 -
 lib/rstp.c                         |    1 -
 lib/rtnetlink.c                    |    2 +-
 lib/smap.c                         |    2 +-
 lib/socket-util.c                  |    2 +-
 lib/stp.c                          |    1 -
 lib/stream-ssl.c                   |    2 +-
 lib/stream-tcp.c                   |    1 -
 lib/stream-unix.c                  |    1 -
 lib/stream.c                       |    1 -
 lib/tc.c                           |    1 -
 lib/tnl-neigh-cache.c              |    1 -
 lib/tnl-neigh-cache.h              |    1 -
 lib/tnl-ports.h                    |    1 -
 lib/tun-metadata.c                 |    1 -
 lib/vconn.c                        |    1 -
 ofproto/bond.c                     |    1 -
 ofproto/bond.h                     |    1 -
 ofproto/in-band.c                  |    1 -
 ofproto/netflow.c                  |    1 -
 ofproto/ofproto-dpif-ipfix.c       |    1 -
 ofproto/ofproto-dpif-monitor.h     |    1 -
 ofproto/ofproto-dpif-sflow.c       |    1 -
 ofproto/ofproto-dpif-upcall.c      |    1 -
 ofproto/ofproto-dpif-xlate-cache.c |    1 -
 ofproto/ofproto-dpif-xlate.c       |    1 -
 ofproto/ofproto.c                  |    1 -
 ofproto/tunnel.c                   |    1 -
 tests/test-classifier.c            |    2 +-
 tests/test-conntrack.c             |    1 +
 tests/test-csum.c                  |    2 +-
 tests/test-lib-route-table.c       |    3 +-
 tests/test-netflow.c               |    2 +-
 tests/test-netlink-conntrack.c     |    2 +
 tests/test-packets.c               |    2 +-
 tests/test-rstp.c                  |    1 -
 tests/test-sflow.c                 |    2 +-
 tests/test-stp.c                   |    1 -
 utilities/ovs-ofctl.c              |    2 +-
 vswitchd/bridge.c                  |    1 -
 114 files changed, 1719 insertions(+), 1804 deletions(-)
 delete mode 100644 lib/packets.c
 delete mode 100644 lib/packets.h
diff mbox series

Patch

diff --git a/lib/automake.mk b/lib/automake.mk
index 879300b4a2..dd38762ad2 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -307,8 +307,6 @@  lib_libopenvswitch_la_SOURCES = \
 	lib/ovsdb-types.h \
 	lib/ox-stat.c \
 	lib/ox-stat.h \
-	lib/packets.c \
-	lib/packets.h \
 	lib/pcap-file.c \
 	lib/pcap-file.h \
 	lib/perf-counter.h \
diff --git a/lib/bfd.c b/lib/bfd.c
index b2d32b8aba..97aa753661 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -38,7 +38,6 @@ 
 #include "openvswitch/ofpbuf.h"
 #include "ovs-thread.h"
 #include "openvswitch/types.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "random.h"
 #include "seq.h"
diff --git a/lib/bfd.h b/lib/bfd.h
index 9d32327fb0..fe626c7cd6 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -21,7 +21,7 @@ 
 #include <stdbool.h>
 #include <inttypes.h>
 
-#include "packets.h"
+#include "net-proto.h"
 
 struct bfd;
 struct dpif_flow_stats;
diff --git a/lib/cfm.c b/lib/cfm.c
index 5a24a6a7d9..328f84bc6c 100644
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -31,7 +31,6 @@ 
 #include "openvswitch/hmap.h"
 #include "netdev.h"
 #include "ovs-atomic.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "random.h"
 #include "seq.h"
diff --git a/lib/cfm.h b/lib/cfm.h
index 5710c99522..8b7bdf0471 100644
--- a/lib/cfm.h
+++ b/lib/cfm.h
@@ -20,7 +20,6 @@ 
 
 #include "openvswitch/hmap.h"
 #include "openvswitch/types.h"
-#include "packets.h"
 
 struct flow;
 struct dp_packet;
diff --git a/lib/classifier.c b/lib/classifier.c
index 7db731beff..436bea6224 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -24,7 +24,6 @@ 
 #include "openvswitch/dynamic-string.h"
 #include "net-proto.h"
 #include "odp-util.h"
-#include "packets.h"
 #include "util.h"
 
 struct trie_ctx;
diff --git a/lib/conntrack-private.h b/lib/conntrack-private.h
index f1132e8aa8..576b26df2f 100644
--- a/lib/conntrack-private.h
+++ b/lib/conntrack-private.h
@@ -28,7 +28,6 @@ 
 #include "openvswitch/hmap.h"
 #include "openvswitch/list.h"
 #include "openvswitch/types.h"
-#include "packets.h"
 #include "rculist.h"
 #include "unaligned.h"
 #include "dp-packet.h"
diff --git a/lib/conntrack.h b/lib/conntrack.h
index c3136e9554..da5c024c6e 100644
--- a/lib/conntrack.h
+++ b/lib/conntrack.h
@@ -29,7 +29,6 @@ 
 #include "openvswitch/types.h"
 #include "ovs-atomic.h"
 #include "ovs-thread.h"
-#include "packets.h"
 #include "hindex.h"
 
 /* Userspace connection tracker
@@ -62,6 +61,7 @@ 
  */
 
 struct dp_packet_batch;
+struct dp_packet;
 
 struct conntrack;
 
diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c
index 5a836b6683..75d2a1c7fe 100644
--- a/lib/ct-dpif.c
+++ b/lib/ct-dpif.c
@@ -20,6 +20,7 @@ 
 #include <errno.h>
 
 #include "ct-dpif.h"
+#include "openvswitch/dynamic-string.h"
 #include "openvswitch/ofp-ct.h"
 #include "openvswitch/ofp-parse.h"
 #include "openvswitch/vlog.h"
diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h
index c3786d5ae5..f3e74ed76b 100644
--- a/lib/ct-dpif.h
+++ b/lib/ct-dpif.h
@@ -17,8 +17,8 @@ 
 #ifndef CT_DPIF_H
 #define CT_DPIF_H
 
+#include "openvswitch/list.h"
 #include "openvswitch/types.h"
-#include "packets.h"
 
 struct ofp_ct_match;
 
@@ -228,6 +228,7 @@  enum {
     CT_STATS_MAX,
 };
 
+struct ds;
 struct dpif;
 struct dpif_ipf_status;
 struct ipf_dump_ctx;
diff --git a/lib/dhcp.h b/lib/dhcp.h
index c904af6c46..b7ab2fa6df 100644
--- a/lib/dhcp.h
+++ b/lib/dhcp.h
@@ -18,7 +18,6 @@ 
 #define DHCP_H 1
 
 #include <stdint.h>
-#include "packets.h"
 #include "util.h"
 
 /* Ports used by DHCP. */
diff --git a/lib/dp-packet.c b/lib/dp-packet.c
index c04d608be6..b9b630076c 100644
--- a/lib/dp-packet.c
+++ b/lib/dp-packet.c
@@ -15,13 +15,20 @@ 
  */
 
 #include <config.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include "crc32c.h"
 #include "dp-packet.h"
+#include "dp-packet-gso.h"
 #include "netdev-afxdp.h"
 #include "netdev-dpdk.h"
 #include "netdev-provider.h"
+#include "net-proto.h"
 #include "openvswitch/dynamic-string.h"
 #include "util.h"
 
@@ -646,3 +653,1404 @@  dp_packet_ol_send_prepare(struct dp_packet *p, uint64_t flags)
         }
     }
 }
+
+
+
+struct in6_addr
+flow_tnl_dst(const struct flow_tnl *tnl)
+{
+    return tnl->ip_dst ? in6_addr_mapped_ipv4(tnl->ip_dst) : tnl->ipv6_dst;
+}
+
+struct in6_addr
+flow_tnl_src(const struct flow_tnl *tnl)
+{
+    return tnl->ip_src ? in6_addr_mapped_ipv4(tnl->ip_src) : tnl->ipv6_src;
+}
+
+/* Fills 'b' with a Reverse ARP packet with Ethernet source address 'eth_src'.
+ * This function is used by Open vSwitch to compose packets in cases where
+ * context is important but content doesn't (or shouldn't) matter.
+ *
+ * The returned packet has enough headroom to insert an 802.1Q VLAN header if
+ * desired. */
+void
+compose_rarp(struct dp_packet *b, const struct eth_addr eth_src)
+{
+    struct eth_header *eth;
+    struct arp_eth_header *arp;
+
+    dp_packet_clear(b);
+    dp_packet_prealloc_tailroom(b, 2 + ETH_HEADER_LEN + VLAN_HEADER_LEN
+                             + ARP_ETH_HEADER_LEN);
+    dp_packet_reserve(b, 2 + VLAN_HEADER_LEN);
+    eth = dp_packet_put_uninit(b, sizeof *eth);
+    eth->eth_dst = eth_addr_broadcast;
+    eth->eth_src = eth_src;
+    eth->eth_type = htons(ETH_TYPE_RARP);
+
+    arp = dp_packet_put_uninit(b, sizeof *arp);
+    arp->ar_hrd = htons(ARP_HRD_ETHERNET);
+    arp->ar_pro = htons(ARP_PRO_IP);
+    arp->ar_hln = sizeof arp->ar_sha;
+    arp->ar_pln = sizeof arp->ar_spa;
+    arp->ar_op = htons(ARP_OP_RARP);
+    arp->ar_sha = eth_src;
+    put_16aligned_be32(&arp->ar_spa, htonl(0));
+    arp->ar_tha = eth_src;
+    put_16aligned_be32(&arp->ar_tpa, htonl(0));
+
+    dp_packet_set_l3(b, arp);
+    b->packet_type = htonl(PT_ETH);
+}
+
+/* Insert VLAN header according to given TCI. Packet passed must be Ethernet
+ * packet.  Ignores the CFI bit of 'tci' using 0 instead.
+ *
+ * Also adjusts the layer offsets accordingly. */
+void
+eth_push_vlan(struct dp_packet *packet, ovs_be16 tpid, ovs_be16 tci)
+{
+    struct vlan_eth_header *veh;
+
+    /* Insert new 802.1Q header. */
+    veh = dp_packet_resize_l2(packet, VLAN_HEADER_LEN);
+    /* GCC cannot determine the buffer size through dp_packet_resize_l2 when
+     * both functions are in the same translation unit, causing a false
+     * positive around memmove.  An alternative to this would be to disable
+     * inlining the dp_packet_resize_l2, but that seems excessive in this
+     * case. */
+#if __GNUC__ && !__clang__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+    /* Also, newer versions of GCC include a stringop overread check */
+#if __GNUC__ > 11
+#pragma GCC diagnostic ignored "-Wstringop-overread"
+#endif
+#endif
+    memmove(veh, (char *)veh + VLAN_HEADER_LEN, 2 * ETH_ADDR_LEN);
+#if __GNUC__ && !__clang__
+#pragma GCC diagnostic pop
+#endif
+    veh->veth_type = tpid;
+    veh->veth_tci = tci & htons(~VLAN_CFI);
+}
+
+/* Removes outermost VLAN header (if any is present) from 'packet'.
+ *
+ * 'packet->l2_5' should initially point to 'packet''s outer-most VLAN header
+ * or may be NULL if there are no VLAN headers. */
+void
+eth_pop_vlan(struct dp_packet *packet)
+{
+    struct vlan_eth_header *veh = dp_packet_eth(packet);
+
+    if (veh && dp_packet_size(packet) >= sizeof *veh
+        && eth_type_vlan(veh->veth_type)) {
+
+        memmove((char *)veh + VLAN_HEADER_LEN, veh, 2 * ETH_ADDR_LEN);
+        dp_packet_resize_l2(packet, -VLAN_HEADER_LEN);
+    }
+}
+
+/* Push Ethernet header onto 'packet' assuming it is layer 3 */
+void
+push_eth(struct dp_packet *packet, const struct eth_addr *dst,
+         const struct eth_addr *src)
+{
+    struct eth_header *eh;
+
+    ovs_assert(!dp_packet_is_eth(packet));
+    eh = dp_packet_resize_l2(packet, ETH_HEADER_LEN);
+    eh->eth_dst = *dst;
+    eh->eth_src = *src;
+    eh->eth_type = pt_ns_type_be(packet->packet_type);
+    packet->packet_type = htonl(PT_ETH);
+}
+
+/* Removes Ethernet header, including VLAN header, from 'packet'.
+ *
+ * Previous to calling this function, 'ofpbuf_l3(packet)' must not be NULL */
+void
+pop_eth(struct dp_packet *packet)
+{
+    char *l2_5 = dp_packet_l2_5(packet);
+    char *l3 = dp_packet_l3(packet);
+    ovs_be16 ethertype;
+    int increment;
+
+    ovs_assert(dp_packet_is_eth(packet));
+    ovs_assert(l3 != NULL);
+
+    if (l2_5) {
+        increment = packet->l2_5_ofs;
+        ethertype = *(ALIGNED_CAST(ovs_be16 *, (l2_5 - 2)));
+    } else {
+        increment = packet->l3_ofs;
+        ethertype = *(ALIGNED_CAST(ovs_be16 *, (l3 - 2)));
+    }
+
+    dp_packet_resize_l2(packet, -increment);
+    packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE, ntohs(ethertype));
+}
+
+/* Set ethertype of the packet. */
+static void
+set_ethertype(struct dp_packet *packet, ovs_be16 eth_type)
+{
+    struct eth_header *eh = dp_packet_eth(packet);
+
+    if (!eh) {
+        return;
+    }
+
+    if (eth_type_vlan(eh->eth_type)) {
+        ovs_be16 *p;
+        char *l2_5 = dp_packet_l2_5(packet);
+
+        p = ALIGNED_CAST(ovs_be16 *,
+                         (l2_5 ? l2_5 : (char *)dp_packet_l3(packet)) - 2);
+        *p = eth_type;
+    } else {
+        eh->eth_type = eth_type;
+    }
+}
+
+static bool is_mpls(struct dp_packet *packet)
+{
+    return packet->l2_5_ofs != UINT16_MAX;
+}
+
+/* Set MPLS label stack entry to outermost MPLS header.*/
+void
+set_mpls_lse(struct dp_packet *packet, ovs_be32 mpls_lse)
+{
+    /* Packet type should be MPLS to set label stack entry. */
+    if (is_mpls(packet)) {
+        struct mpls_hdr *mh = dp_packet_l2_5(packet);
+
+        /* Update mpls label stack entry. */
+        put_16aligned_be32(&mh->mpls_lse, mpls_lse);
+    }
+}
+
+/* Push MPLS label stack entry 'lse' onto 'packet' as the outermost MPLS
+ * header.  If 'packet' does not already have any MPLS labels, then its
+ * Ethertype is changed to 'ethtype' (which must be an MPLS Ethertype). */
+void
+push_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse)
+{
+    char * header;
+    size_t len;
+
+    if (!eth_type_mpls(ethtype)) {
+        return;
+    }
+
+    if (!is_mpls(packet)) {
+        /* Set MPLS label stack offset. */
+        packet->l2_5_ofs = packet->l3_ofs;
+    }
+
+    set_ethertype(packet, ethtype);
+
+    /* Push new MPLS shim header onto packet. */
+    len = packet->l2_5_ofs;
+    header = dp_packet_resize_l2_5(packet, MPLS_HLEN);
+    memmove(header, header + MPLS_HLEN, len);
+    memcpy(header + len, &lse, sizeof lse);
+
+    pkt_metadata_init_conn(&packet->md);
+}
+
+void
+add_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse,
+         bool l3_encap)
+{
+    if (!eth_type_mpls(ethtype)) {
+        return;
+    }
+
+    if (!l3_encap) {
+        struct mpls_hdr *header = dp_packet_resize_l2(packet, MPLS_HLEN);
+
+        put_16aligned_be32(&header->mpls_lse, lse);
+        packet->l2_5_ofs = 0;
+        packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE,
+                                             ntohs(ethtype));
+    } else {
+        size_t len;
+        char *header;
+
+        if (!is_mpls(packet)) {
+            /* Set MPLS label stack offset. */
+            packet->l2_5_ofs = packet->l3_ofs;
+        }
+        set_ethertype(packet, ethtype);
+
+        /* Push new MPLS shim header onto packet. */
+        len = packet->l2_5_ofs;
+        header = dp_packet_resize_l2_5(packet, MPLS_HLEN);
+        memmove(header, header + MPLS_HLEN, len);
+        memcpy(header + len, &lse, sizeof lse);
+    }
+    pkt_metadata_init_conn(&packet->md);
+}
+
+/* If 'packet' is an MPLS packet, removes its outermost MPLS label stack entry.
+ * If the label that was removed was the only MPLS label, changes 'packet''s
+ * Ethertype to 'ethtype' (which ordinarily should not be an MPLS
+ * Ethertype). */
+void
+pop_mpls(struct dp_packet *packet, ovs_be16 ethtype)
+{
+    if (is_mpls(packet)) {
+        struct mpls_hdr *mh = dp_packet_l2_5(packet);
+        size_t len = packet->l2_5_ofs;
+
+        set_ethertype(packet, ethtype);
+        if (get_16aligned_be32(&mh->mpls_lse) & htonl(MPLS_BOS_MASK)) {
+            dp_packet_set_l2_5(packet, NULL);
+        }
+        /* Shift the l2 header forward. */
+        memmove((char*)dp_packet_data(packet) + MPLS_HLEN, dp_packet_data(packet), len);
+        dp_packet_resize_l2_5(packet, -MPLS_HLEN);
+
+        /* Invalidate offload flags as they are not valid after
+         * decapsulation of MPLS header. */
+        dp_packet_reset_offload(packet);
+
+        /* packet_type must be reset for the MPLS packets with no l2 header */
+        if (!len) {
+            if (ethtype == htons(ETH_TYPE_TEB)) {
+                /* The inner packet must be classified as ethernet if the
+                 * ethtype is ETH_TYPE_TEB. */
+                packet->packet_type = htonl(PT_ETH);
+            } else {
+                packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE,
+                                                     ntohs(ethtype));
+            }
+        }
+    }
+}
+
+void
+push_nsh(struct dp_packet *packet, const struct nsh_hdr *nsh_hdr_src)
+{
+    struct nsh_hdr *nsh;
+    size_t length = nsh_hdr_len(nsh_hdr_src);
+    uint8_t next_proto;
+
+    switch (ntohl(packet->packet_type)) {
+        case PT_ETH:
+            next_proto = NSH_P_ETHERNET;
+            break;
+        case PT_IPV4:
+            next_proto = NSH_P_IPV4;
+            break;
+        case PT_IPV6:
+            next_proto = NSH_P_IPV6;
+            break;
+        case PT_NSH:
+            next_proto = NSH_P_NSH;
+            break;
+        default:
+            OVS_NOT_REACHED();
+    }
+
+    nsh = (struct nsh_hdr *) dp_packet_resize_l2(packet, length);
+    memcpy(nsh, nsh_hdr_src, length);
+    nsh->next_proto = next_proto;
+    packet->packet_type = htonl(PT_NSH);
+    dp_packet_reset_offsets(packet);
+    packet->l3_ofs = 0;
+}
+
+bool
+pop_nsh(struct dp_packet *packet)
+{
+    struct nsh_hdr *nsh = (struct nsh_hdr *) dp_packet_l3(packet);
+    size_t length;
+    uint32_t next_pt;
+
+    if (packet->packet_type == htonl(PT_NSH) && nsh) {
+        switch (nsh->next_proto) {
+            case NSH_P_ETHERNET:
+                next_pt = PT_ETH;
+                break;
+            case NSH_P_IPV4:
+                next_pt = PT_IPV4;
+                break;
+            case NSH_P_IPV6:
+                next_pt = PT_IPV6;
+                break;
+            case NSH_P_NSH:
+                next_pt = PT_NSH;
+                break;
+            default:
+                /* Unknown inner packet type. Drop packet. */
+                return false;
+        }
+
+        length = nsh_hdr_len(nsh);
+        dp_packet_reset_packet(packet, length);
+        packet->packet_type = htonl(next_pt);
+        /* Packet must be recirculated for further processing. */
+    }
+    return true;
+}
+
+/* Converts hex digits in 'hex' to an Ethernet packet in '*packetp'.  The
+ * caller must free '*packetp'.  On success, returns NULL.  On failure, returns
+ * an error message and stores NULL in '*packetp'.
+ *
+ * Aligns the L3 header of '*packetp' on a 32-bit boundary. */
+const char *
+eth_from_hex(const char *hex, struct dp_packet **packetp)
+{
+    struct dp_packet *packet;
+
+    /* Use 2 bytes of headroom to 32-bit align the L3 header. */
+    packet = *packetp = dp_packet_new_with_headroom(strlen(hex) / 2, 2);
+
+    if (dp_packet_put_hex(packet, hex, NULL)[0] != '\0') {
+        dp_packet_delete(packet);
+        *packetp = NULL;
+        return "Trailing garbage in packet data";
+    }
+
+    if (dp_packet_size(packet) < ETH_HEADER_LEN) {
+        dp_packet_delete(packet);
+        *packetp = NULL;
+        return "Packet data too short for Ethernet";
+    }
+
+    return NULL;
+}
+
+/* Populates 'b' with an Ethernet II packet headed with the given 'eth_dst',
+ * 'eth_src' and 'eth_type' parameters.  A payload of 'size' bytes is allocated
+ * in 'b' and returned.  This payload may be populated with appropriate
+ * information by the caller.  Sets 'b''s 'frame' pointer and 'l3' offset to
+ * the Ethernet header and payload respectively.  Aligns b->l3 on a 32-bit
+ * boundary.
+ *
+ * The returned packet has enough headroom to insert an 802.1Q VLAN header if
+ * desired. */
+void *
+eth_compose(struct dp_packet *b, const struct eth_addr eth_dst,
+            const struct eth_addr eth_src, uint16_t eth_type,
+            size_t size)
+{
+    void *data;
+    struct eth_header *eth;
+
+
+    dp_packet_clear(b);
+
+    /* The magic 2 here ensures that the L3 header (when it is added later)
+     * will be 32-bit aligned. */
+    dp_packet_prealloc_tailroom(b, 2 + ETH_HEADER_LEN + VLAN_HEADER_LEN + size);
+    dp_packet_reserve(b, 2 + VLAN_HEADER_LEN);
+    eth = dp_packet_put_uninit(b, ETH_HEADER_LEN);
+    data = dp_packet_put_zeros(b, size);
+
+    eth->eth_dst = eth_dst;
+    eth->eth_src = eth_src;
+    eth->eth_type = htons(eth_type);
+
+    b->packet_type = htonl(PT_ETH);
+    dp_packet_set_l3(b, data);
+
+    return data;
+}
+
+void
+packet_set_ipv4_addr(struct dp_packet *packet,
+                     ovs_16aligned_be32 *addr, ovs_be32 new_addr)
+{
+    struct ip_header *nh = dp_packet_l3(packet);
+    ovs_be32 old_addr = get_16aligned_be32(addr);
+    size_t l4_size = dp_packet_l4_size(packet);
+
+    pkt_metadata_init_conn(&packet->md);
+
+    if (nh->ip_proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) {
+        if (dp_packet_l4_checksum_valid(packet)) {
+            dp_packet_l4_checksum_set_partial(packet);
+        } else {
+            struct tcp_header *th = dp_packet_l4(packet);
+            th->tcp_csum = recalc_csum32(th->tcp_csum, old_addr, new_addr);
+        }
+    } else if (nh->ip_proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN ) {
+        if (dp_packet_l4_checksum_valid(packet)) {
+            dp_packet_l4_checksum_set_partial(packet);
+        } else {
+            struct udp_header *uh = dp_packet_l4(packet);
+            if (uh->udp_csum) {
+                uh->udp_csum = recalc_csum32(uh->udp_csum, old_addr, new_addr);
+                if (!uh->udp_csum) {
+                    uh->udp_csum = htons(0xffff);
+                }
+            }
+        }
+    }
+
+    if (dp_packet_ip_checksum_valid(packet)) {
+        dp_packet_ip_checksum_set_partial(packet);
+    } else {
+        nh->ip_csum = recalc_csum32(nh->ip_csum, old_addr, new_addr);
+    }
+    put_16aligned_be32(addr, new_addr);
+}
+
+/* Returns true, if packet contains at least one routing header where
+ * segements_left > 0.
+ *
+ * This function assumes that L3 and L4 offsets are set in the packet. */
+bool
+packet_rh_present(struct dp_packet *packet, uint8_t *nexthdr, bool *first_frag)
+{
+    const struct ovs_16aligned_ip6_hdr *nh;
+    size_t len;
+    size_t remaining;
+    uint8_t *data = dp_packet_l3(packet);
+
+    remaining = packet->l4_ofs - packet->l3_ofs;
+    if (remaining < sizeof *nh) {
+        return false;
+    }
+    nh = ALIGNED_CAST(struct ovs_16aligned_ip6_hdr *, data);
+    data += sizeof *nh;
+    remaining -= sizeof *nh;
+    *nexthdr = nh->ip6_nxt;
+
+    while (1) {
+        if ((*nexthdr != IPPROTO_HOPOPTS)
+                && (*nexthdr != IPPROTO_ROUTING)
+                && (*nexthdr != IPPROTO_DSTOPTS)
+                && (*nexthdr != IPPROTO_AH)
+                && (*nexthdr != IPPROTO_FRAGMENT)) {
+            /* It's either a terminal header (e.g., TCP, UDP) or one we
+             * don't understand.  In either case, we're done with the
+             * packet, so use it to fill in 'nw_proto'. */
+            break;
+        }
+
+        /* We only verify that at least 8 bytes of the next header are
+         * available, but many of these headers are longer.  Ensure that
+         * accesses within the extension header are within those first 8
+         * bytes. All extension headers are required to be at least 8
+         * bytes. */
+        if (remaining < 8) {
+            return false;
+        }
+
+        if (*nexthdr == IPPROTO_AH) {
+            /* A standard AH definition isn't available, but the fields
+             * we care about are in the same location as the generic
+             * option header--only the header length is calculated
+             * differently. */
+            const struct ip6_ext *ext_hdr = (struct ip6_ext *)data;
+
+            *nexthdr = ext_hdr->ip6e_nxt;
+            len = (ext_hdr->ip6e_len + 2) * 4;
+        } else if (*nexthdr == IPPROTO_FRAGMENT) {
+            const struct ovs_16aligned_ip6_frag *frag_hdr
+                = ALIGNED_CAST(struct ovs_16aligned_ip6_frag *, data);
+
+            *first_frag = !(frag_hdr->ip6f_offlg & IP6F_OFF_MASK) &&
+                           (frag_hdr->ip6f_offlg & IP6F_MORE_FRAG);
+            *nexthdr = frag_hdr->ip6f_nxt;
+            len = sizeof *frag_hdr;
+        } else if (*nexthdr == IPPROTO_ROUTING) {
+            const struct ip6_rthdr *rh = (struct ip6_rthdr *)data;
+
+            if (rh->ip6r_segleft > 0) {
+                return true;
+            }
+
+            *nexthdr = rh->ip6r_nxt;
+            len = (rh->ip6r_len + 1) * 8;
+        } else {
+            const struct ip6_ext *ext_hdr = (struct ip6_ext *)data;
+
+            *nexthdr = ext_hdr->ip6e_nxt;
+            len = (ext_hdr->ip6e_len + 1) * 8;
+        }
+
+        if (remaining < len) {
+            return false;
+        }
+        remaining -= len;
+        data += len;
+    }
+
+    return false;
+}
+
+static void
+packet_update_csum128(struct dp_packet *packet, uint8_t proto,
+                      ovs_16aligned_be32 addr[4],
+                      const struct in6_addr *new_addr)
+{
+    size_t l4_size = dp_packet_l4_size(packet);
+
+    if (proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) {
+        if (dp_packet_l4_checksum_valid(packet)) {
+            dp_packet_l4_checksum_set_partial(packet);
+        } else {
+            struct tcp_header *th = dp_packet_l4(packet);
+
+            th->tcp_csum = recalc_csum128(th->tcp_csum, addr, new_addr);
+        }
+    } else if (proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN) {
+        if (dp_packet_l4_checksum_valid(packet)) {
+            dp_packet_l4_checksum_set_partial(packet);
+        } else {
+            struct udp_header *uh = dp_packet_l4(packet);
+
+            if (uh->udp_csum) {
+                uh->udp_csum = recalc_csum128(uh->udp_csum, addr, new_addr);
+                if (!uh->udp_csum) {
+                    uh->udp_csum = htons(0xffff);
+                }
+            }
+        }
+    } else if (proto == IPPROTO_ICMPV6 &&
+               l4_size >= sizeof(struct icmp6_header)) {
+        struct icmp6_header *icmp = dp_packet_l4(packet);
+
+        icmp->icmp6_cksum = recalc_csum128(icmp->icmp6_cksum, addr, new_addr);
+    }
+}
+
+void
+packet_set_ipv6_addr(struct dp_packet *packet, uint8_t proto,
+                     ovs_16aligned_be32 addr[4],
+                     const struct in6_addr *new_addr,
+                     bool recalculate_csum)
+{
+    if (recalculate_csum) {
+        packet_update_csum128(packet, proto, addr, new_addr);
+    }
+    memcpy(addr, new_addr, sizeof(ovs_be32[4]));
+    pkt_metadata_init_conn(&packet->md);
+}
+
+/* Modifies the IPv4 header fields of 'packet' to be consistent with 'src',
+ * 'dst', 'tos', and 'ttl'.  Updates 'packet''s L4 checksums as appropriate.
+ * 'packet' must contain a valid IPv4 packet with correctly populated l[347]
+ * markers. */
+void
+packet_set_ipv4(struct dp_packet *packet, ovs_be32 src, ovs_be32 dst,
+                uint8_t tos, uint8_t ttl)
+{
+    struct ip_header *nh = dp_packet_l3(packet);
+
+    if (get_16aligned_be32(&nh->ip_src) != src) {
+        packet_set_ipv4_addr(packet, &nh->ip_src, src);
+    }
+
+    if (get_16aligned_be32(&nh->ip_dst) != dst) {
+        packet_set_ipv4_addr(packet, &nh->ip_dst, dst);
+    }
+
+    if (nh->ip_tos != tos) {
+        uint8_t *field = &nh->ip_tos;
+
+        if (dp_packet_ip_checksum_valid(packet)) {
+            dp_packet_ip_checksum_set_partial(packet);
+        } else {
+            nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t) *field),
+                                        htons((uint16_t) tos));
+        }
+
+        *field = tos;
+    }
+
+    if (nh->ip_ttl != ttl) {
+        uint8_t *field = &nh->ip_ttl;
+
+        if (dp_packet_ip_checksum_valid(packet)) {
+            dp_packet_ip_checksum_set_partial(packet);
+        } else {
+            nh->ip_csum = recalc_csum16(nh->ip_csum, htons(*field << 8),
+                                        htons(ttl << 8));
+        }
+
+        *field = ttl;
+    }
+}
+
+/* Modifies the IPv6 header fields of 'packet' to be consistent with 'src',
+ * 'dst', 'traffic class', and 'next hop'.  Updates 'packet''s L4 checksums as
+ * appropriate. 'packet' must contain a valid IPv6 packet with correctly
+ * populated l[34] offsets. */
+void
+packet_set_ipv6(struct dp_packet *packet, const struct in6_addr *src,
+                const struct in6_addr *dst, uint8_t key_tc, ovs_be32 key_fl,
+                uint8_t key_hl)
+{
+    struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(packet);
+    bool recalc_csum = true;
+    uint8_t proto = 0;
+    bool rh_present;
+
+    rh_present = packet_rh_present(packet, &proto, &recalc_csum);
+
+    if (memcmp(&nh->ip6_src, src, sizeof(ovs_be32[4]))) {
+        packet_set_ipv6_addr(packet, proto, nh->ip6_src.be32,
+                             src, recalc_csum);
+    }
+
+    if (memcmp(&nh->ip6_dst, dst, sizeof(ovs_be32[4]))) {
+        packet_set_ipv6_addr(packet, proto, nh->ip6_dst.be32, dst,
+                             !rh_present && recalc_csum);
+    }
+
+    ip_set_ipv6_tc(&nh->ip6_flow, key_tc);
+    ip_set_ipv6_flow_label(&nh->ip6_flow, key_fl);
+    nh->ip6_hlim = key_hl;
+}
+
+static void
+packet_set_port(ovs_be16 *port, ovs_be16 new_port, ovs_be16 *csum)
+{
+    if (*port != new_port) {
+        if (csum) {
+            *csum = recalc_csum16(*csum, *port, new_port);
+        }
+        *port = new_port;
+    }
+}
+
+/* Sets the TCP source and destination port ('src' and 'dst' respectively) of
+ * the TCP header contained in 'packet'.  'packet' must be a valid TCP packet
+ * with its l4 offset properly populated. */
+void
+packet_set_tcp_port(struct dp_packet *packet, ovs_be16 src, ovs_be16 dst)
+{
+    struct tcp_header *th = dp_packet_l4(packet);
+    ovs_be16 *csum = NULL;
+
+    if (dp_packet_l4_checksum_valid(packet)) {
+        dp_packet_l4_checksum_set_partial(packet);
+    } else {
+        csum = &th->tcp_csum;
+    }
+
+    packet_set_port(&th->tcp_src, src, csum);
+    packet_set_port(&th->tcp_dst, dst, csum);
+    pkt_metadata_init_conn(&packet->md);
+}
+
+/* Sets the UDP source and destination port ('src' and 'dst' respectively) of
+ * the UDP header contained in 'packet'.  'packet' must be a valid UDP packet
+ * with its l4 offset properly populated. */
+void
+packet_set_udp_port(struct dp_packet *packet, ovs_be16 src, ovs_be16 dst)
+{
+    struct udp_header *uh = dp_packet_l4(packet);
+
+    if (dp_packet_l4_checksum_valid(packet)) {
+        dp_packet_l4_checksum_set_partial(packet);
+        packet_set_port(&uh->udp_src, src, NULL);
+        packet_set_port(&uh->udp_dst, dst, NULL);
+    } else {
+        ovs_be16 *csum = uh->udp_csum ? &uh->udp_csum : NULL;
+
+        packet_set_port(&uh->udp_src, src, csum);
+        packet_set_port(&uh->udp_dst, dst, csum);
+
+        if (csum && !uh->udp_csum) {
+            uh->udp_csum = htons(0xffff);
+        }
+    }
+
+    pkt_metadata_init_conn(&packet->md);
+}
+
+/* Sets the SCTP source and destination port ('src' and 'dst' respectively) of
+ * the SCTP header contained in 'packet'.  'packet' must be a valid SCTP packet
+ * with its l4 offset properly populated. */
+void
+packet_set_sctp_port(struct dp_packet *packet, ovs_be16 src, ovs_be16 dst)
+{
+    struct sctp_header *sh = dp_packet_l4(packet);
+
+    if (dp_packet_l4_checksum_valid(packet)) {
+        dp_packet_l4_checksum_set_partial(packet);
+        sh->sctp_src = src;
+        sh->sctp_dst = dst;
+    } else {
+        ovs_be32 old_csum, old_correct_csum, new_csum;
+        uint16_t tp_len = dp_packet_l4_size(packet);
+
+        old_csum = get_16aligned_be32(&sh->sctp_csum);
+        put_16aligned_be32(&sh->sctp_csum, 0);
+        old_correct_csum = crc32c((void *) sh, tp_len);
+
+        sh->sctp_src = src;
+        sh->sctp_dst = dst;
+
+        new_csum = crc32c((void *) sh, tp_len);
+        put_16aligned_be32(&sh->sctp_csum, old_csum ^ old_correct_csum
+                           ^ new_csum);
+    }
+
+    pkt_metadata_init_conn(&packet->md);
+}
+
+/* Sets the ICMP type and code of the ICMP header contained in 'packet'.
+ * 'packet' must be a valid ICMP packet with its l4 offset properly
+ * populated. */
+void
+packet_set_icmp(struct dp_packet *packet, uint8_t type, uint8_t code)
+{
+    struct icmp_header *ih = dp_packet_l4(packet);
+    ovs_be16 orig_tc = htons(ih->icmp_type << 8 | ih->icmp_code);
+    ovs_be16 new_tc = htons(type << 8 | code);
+
+    if (orig_tc != new_tc) {
+        ih->icmp_type = type;
+        ih->icmp_code = code;
+
+        ih->icmp_csum = recalc_csum16(ih->icmp_csum, orig_tc, new_tc);
+    }
+    pkt_metadata_init_conn(&packet->md);
+}
+
+/* Sets the IGMP type to IGMP_HOST_MEMBERSHIP_QUERY and populates the
+ * v3 query header fields in 'packet'. 'packet' must be a valid IGMPv3
+ * query packet with its l4 offset properly populated.
+ */
+void
+packet_set_igmp3_query(struct dp_packet *packet, uint8_t max_resp,
+                       ovs_be32 group, bool srs, uint8_t qrv, uint8_t qqic)
+{
+    struct igmpv3_query_header *igh = dp_packet_l4(packet);
+    ovs_be16 orig_type_max_resp =
+        htons(igh->type << 8 | igh->max_resp);
+    ovs_be16 new_type_max_resp =
+        htons(IGMP_HOST_MEMBERSHIP_QUERY << 8 | max_resp);
+
+    if (orig_type_max_resp != new_type_max_resp) {
+        igh->type = IGMP_HOST_MEMBERSHIP_QUERY;
+        igh->max_resp = max_resp;
+        igh->csum = recalc_csum16(igh->csum, orig_type_max_resp,
+                                  new_type_max_resp);
+    }
+
+    ovs_be32 old_group = get_16aligned_be32(&igh->group);
+
+    if (old_group != group) {
+        put_16aligned_be32(&igh->group, group);
+        igh->csum = recalc_csum32(igh->csum, old_group, group);
+    }
+
+    /* See RFC 3376 4.1.6. */
+    if (qrv > 7) {
+        qrv = 0;
+    }
+
+    ovs_be16 orig_srs_qrv_qqic = htons(igh->srs_qrv << 8 | igh->qqic);
+    ovs_be16 new_srs_qrv_qqic = htons(srs << 11 | qrv << 8 | qqic);
+
+    if (orig_srs_qrv_qqic != new_srs_qrv_qqic) {
+        igh->srs_qrv = (srs << 3 | qrv);
+        igh->qqic = qqic;
+        igh->csum = recalc_csum16(igh->csum, orig_srs_qrv_qqic,
+                                  new_srs_qrv_qqic);
+    }
+}
+
+void
+packet_set_nd_ext(struct dp_packet *packet, const ovs_16aligned_be32 rso_flags,
+                  const uint8_t opt_type)
+{
+    struct ovs_nd_msg *ns;
+    struct ovs_nd_lla_opt *opt;
+    int bytes_remain = dp_packet_l4_size(packet);
+    struct ovs_16aligned_ip6_hdr * nh = dp_packet_l3(packet);
+    uint32_t pseudo_hdr_csum = 0;
+
+    if (OVS_UNLIKELY(bytes_remain < sizeof(*ns))) {
+        return;
+    }
+
+    if (nh) {
+        pseudo_hdr_csum = ip_csum_pseudoheader6(nh);
+    }
+
+    ns = dp_packet_l4(packet);
+    opt = &ns->options[0];
+
+    /* set RSO flags and option type */
+    ns->rso_flags = rso_flags;
+    opt->type = opt_type;
+
+    /* recalculate checksum */
+    ovs_be16 *csum_value = &(ns->icmph.icmp6_cksum);
+    *csum_value = 0;
+    *csum_value = csum_finish(csum_continue(pseudo_hdr_csum,
+                              &(ns->icmph), bytes_remain));
+
+}
+
+void
+packet_set_nd(struct dp_packet *packet, const struct in6_addr *target,
+              const struct eth_addr sll, const struct eth_addr tll)
+{
+    struct ovs_nd_msg *ns;
+    struct ovs_nd_lla_opt *opt;
+    int bytes_remain = dp_packet_l4_size(packet);
+
+    if (OVS_UNLIKELY(bytes_remain < sizeof(*ns))) {
+        return;
+    }
+
+    ns = dp_packet_l4(packet);
+    opt = &ns->options[0];
+    bytes_remain -= sizeof(*ns);
+
+    if (memcmp(&ns->target, target, sizeof(ovs_be32[4]))) {
+        packet_set_ipv6_addr(packet, IPPROTO_ICMPV6, ns->target.be32, target,
+                             true);
+    }
+
+    while (bytes_remain >= ND_LLA_OPT_LEN && opt->len != 0
+           && bytes_remain >= (opt->len * ND_LLA_OPT_LEN)) {
+        if (opt->type == ND_OPT_SOURCE_LINKADDR && opt->len == 1) {
+            if (!eth_addr_equals(opt->mac, sll)) {
+                ovs_be16 *csum = &(ns->icmph.icmp6_cksum);
+
+                *csum = recalc_csum48(*csum, opt->mac, sll);
+                opt->mac = sll;
+            }
+
+            /* A packet can only contain one SLL or TLL option */
+            break;
+        } else if (opt->type == ND_OPT_TARGET_LINKADDR && opt->len == 1) {
+            if (!eth_addr_equals(opt->mac, tll)) {
+                ovs_be16 *csum = &(ns->icmph.icmp6_cksum);
+
+                *csum = recalc_csum48(*csum, opt->mac, tll);
+                opt->mac = tll;
+            }
+
+            /* A packet can only contain one SLL or TLL option */
+            break;
+        }
+
+        opt += opt->len;
+        bytes_remain -= opt->len * ND_LLA_OPT_LEN;
+    }
+}
+
+#define ARP_PACKET_SIZE  (2 + ETH_HEADER_LEN + VLAN_HEADER_LEN + \
+                          ARP_ETH_HEADER_LEN)
+
+/* Clears 'b' and replaces its contents by an ARP frame with the specified
+ * 'arp_op', 'arp_sha', 'arp_tha', 'arp_spa', and 'arp_tpa'.  The outer
+ * Ethernet frame is initialized with Ethernet source 'arp_sha' and destination
+ * 'arp_tha', except that destination ff:ff:ff:ff:ff:ff is used instead if
+ * 'broadcast' is true.  Points the L3 header to the ARP header. */
+void
+compose_arp(struct dp_packet *b, uint16_t arp_op,
+            const struct eth_addr arp_sha, const struct eth_addr arp_tha,
+            bool broadcast, ovs_be32 arp_spa, ovs_be32 arp_tpa)
+{
+    compose_arp__(b);
+
+    struct eth_header *eth = dp_packet_eth(b);
+    eth->eth_dst = broadcast ? eth_addr_broadcast : arp_tha;
+    eth->eth_src = arp_sha;
+
+    struct arp_eth_header *arp = dp_packet_l3(b);
+    arp->ar_op = htons(arp_op);
+    arp->ar_sha = arp_sha;
+    arp->ar_tha = arp_tha;
+    put_16aligned_be32(&arp->ar_spa, arp_spa);
+    put_16aligned_be32(&arp->ar_tpa, arp_tpa);
+}
+
+/* Clears 'b' and replaces its contents by an ARP frame.  Sets the fields in
+ * the Ethernet and ARP headers that are fixed for ARP frames to those fixed
+ * values, and zeroes the other fields.  Points the L3 header to the ARP
+ * header. */
+void
+compose_arp__(struct dp_packet *b)
+{
+    dp_packet_clear(b);
+    dp_packet_prealloc_tailroom(b, ARP_PACKET_SIZE);
+    dp_packet_reserve(b, 2 + VLAN_HEADER_LEN);
+
+    struct eth_header *eth = dp_packet_put_zeros(b, sizeof *eth);
+    eth->eth_type = htons(ETH_TYPE_ARP);
+
+    struct arp_eth_header *arp = dp_packet_put_zeros(b, sizeof *arp);
+    arp->ar_hrd = htons(ARP_HRD_ETHERNET);
+    arp->ar_pro = htons(ARP_PRO_IP);
+    arp->ar_hln = sizeof arp->ar_sha;
+    arp->ar_pln = sizeof arp->ar_spa;
+
+    dp_packet_set_l3(b, arp);
+
+    b->packet_type = htonl(PT_ETH);
+}
+
+/* This function expects packet with ethernet header with correct
+ * l3 pointer set. */
+void *
+compose_ipv6(struct dp_packet *packet, uint8_t proto,
+             const struct in6_addr *src, const struct in6_addr *dst,
+             uint8_t key_tc, ovs_be32 key_fl, uint8_t key_hl, int size)
+{
+    struct ovs_16aligned_ip6_hdr *nh;
+    void *data;
+
+    nh = dp_packet_l3(packet);
+    nh->ip6_vfc = 0x60;
+    nh->ip6_nxt = proto;
+    nh->ip6_plen = htons(size);
+    data = dp_packet_put_zeros(packet, size);
+    dp_packet_set_l4(packet, data);
+    packet_set_ipv6(packet, src, dst, key_tc, key_fl, key_hl);
+    return data;
+}
+
+/* Compose an IPv6 Neighbor Discovery Neighbor Solicitation message. */
+void
+compose_nd_ns(struct dp_packet *b, const struct eth_addr eth_src,
+              const struct in6_addr *ipv6_src, const struct in6_addr *ipv6_dst)
+{
+    struct in6_addr sn_addr;
+    struct eth_addr eth_dst;
+    struct ovs_nd_msg *ns;
+    struct ovs_nd_lla_opt *lla_opt;
+    uint32_t icmp_csum;
+
+    in6_addr_solicited_node(&sn_addr, ipv6_dst);
+    ipv6_multicast_to_ethernet(&eth_dst, &sn_addr);
+
+    eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
+    ns = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, &sn_addr,
+                      0, 0, 255, ND_MSG_LEN + ND_LLA_OPT_LEN);
+
+    ns->icmph.icmp6_type = ND_NEIGHBOR_SOLICIT;
+    ns->icmph.icmp6_code = 0;
+    put_16aligned_be32(&ns->rso_flags, htonl(0));
+
+    lla_opt = &ns->options[0];
+    lla_opt->type = ND_OPT_SOURCE_LINKADDR;
+    lla_opt->len = 1;
+
+    packet_set_nd(b, ipv6_dst, eth_src, eth_addr_zero);
+
+    ns->icmph.icmp6_cksum = 0;
+    icmp_csum = ip_csum_pseudoheader6(dp_packet_l3(b));
+    ns->icmph.icmp6_cksum = csum_finish(
+        csum_continue(icmp_csum, ns, ND_MSG_LEN + ND_LLA_OPT_LEN));
+}
+
+/* Compose an IPv6 Neighbor Discovery Neighbor Advertisement message. */
+void
+compose_nd_na(struct dp_packet *b,
+              const struct eth_addr eth_src, const struct eth_addr eth_dst,
+              const struct in6_addr *ipv6_src, const struct in6_addr *ipv6_dst,
+              ovs_be32 rso_flags)
+{
+    struct ovs_nd_msg *na;
+    struct ovs_nd_lla_opt *lla_opt;
+    uint32_t icmp_csum;
+
+    eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
+    na = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, ipv6_dst,
+                      0, 0, 255, ND_MSG_LEN + ND_LLA_OPT_LEN);
+
+    na->icmph.icmp6_type = ND_NEIGHBOR_ADVERT;
+    na->icmph.icmp6_code = 0;
+    put_16aligned_be32(&na->rso_flags, rso_flags);
+
+    lla_opt = &na->options[0];
+    lla_opt->type = ND_OPT_TARGET_LINKADDR;
+    lla_opt->len = 1;
+
+    packet_set_nd(b, ipv6_src, eth_addr_zero, eth_src);
+
+    na->icmph.icmp6_cksum = 0;
+    icmp_csum = ip_csum_pseudoheader6(dp_packet_l3(b));
+    na->icmph.icmp6_cksum = csum_finish(csum_continue(
+        icmp_csum, na, ND_MSG_LEN + ND_LLA_OPT_LEN));
+}
+
+/* Compose an IPv6 Neighbor Discovery Router Advertisement message with
+ * Source Link-layer Address Option and MTU Option.
+ * Caller can call packet_put_ra_prefix_opt to append Prefix Information
+ * Options to composed messags in 'b'. */
+void
+compose_nd_ra(struct dp_packet *b,
+              const struct eth_addr eth_src, const struct eth_addr eth_dst,
+              const struct in6_addr *ipv6_src, const struct in6_addr *ipv6_dst,
+              uint8_t cur_hop_limit, uint8_t mo_flags,
+              ovs_be16 router_lt, ovs_be32 reachable_time,
+              ovs_be32 retrans_timer, uint32_t mtu)
+{
+    /* Don't compose Router Advertisement packet with MTU Option if mtu
+     * value is 0. */
+    bool with_mtu = mtu != 0;
+    size_t mtu_opt_len = with_mtu ? ND_MTU_OPT_LEN : 0;
+
+    eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
+
+    struct ovs_ra_msg *ra = compose_ipv6(
+        b, IPPROTO_ICMPV6, ipv6_src, ipv6_dst, 0, 0, 255,
+        RA_MSG_LEN + ND_LLA_OPT_LEN + mtu_opt_len);
+    ra->icmph.icmp6_type = ND_ROUTER_ADVERT;
+    ra->icmph.icmp6_code = 0;
+    ra->cur_hop_limit = cur_hop_limit;
+    ra->mo_flags = mo_flags;
+    ra->router_lifetime = router_lt;
+    ra->reachable_time = reachable_time;
+    ra->retrans_timer = retrans_timer;
+
+    struct ovs_nd_lla_opt *lla_opt = ra->options;
+    lla_opt->type = ND_OPT_SOURCE_LINKADDR;
+    lla_opt->len = 1;
+    lla_opt->mac = eth_src;
+
+    if (with_mtu) {
+        /* ovs_nd_mtu_opt has the same size with ovs_nd_lla_opt. */
+        struct ovs_nd_mtu_opt *mtu_opt
+            = (struct ovs_nd_mtu_opt *)(lla_opt + 1);
+        mtu_opt->type = ND_OPT_MTU;
+        mtu_opt->len = 1;
+        mtu_opt->reserved = 0;
+        put_16aligned_be32(&mtu_opt->mtu, htonl(mtu));
+    }
+
+    ra->icmph.icmp6_cksum = 0;
+    uint32_t icmp_csum = ip_csum_pseudoheader6(dp_packet_l3(b));
+    ra->icmph.icmp6_cksum = csum_finish(csum_continue(
+        icmp_csum, ra, RA_MSG_LEN + ND_LLA_OPT_LEN + mtu_opt_len));
+}
+
+/* Append an IPv6 Neighbor Discovery Prefix Information option to a
+ * Router Advertisement message. */
+void
+packet_put_ra_prefix_opt(struct dp_packet *b,
+                         uint8_t plen, uint8_t la_flags,
+                         ovs_be32 valid_lifetime, ovs_be32 preferred_lifetime,
+                         const ovs_be128 prefix)
+{
+    size_t prev_l4_size = dp_packet_l4_size(b);
+    struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(b);
+    nh->ip6_plen = htons(prev_l4_size + ND_PREFIX_OPT_LEN);
+
+    struct ovs_nd_prefix_opt *prefix_opt =
+        dp_packet_put_uninit(b, sizeof *prefix_opt);
+    prefix_opt->type = ND_OPT_PREFIX_INFORMATION;
+    prefix_opt->len = 4;
+    prefix_opt->prefix_len = plen;
+    prefix_opt->la_flags = la_flags;
+    put_16aligned_be32(&prefix_opt->valid_lifetime, valid_lifetime);
+    put_16aligned_be32(&prefix_opt->preferred_lifetime, preferred_lifetime);
+    put_16aligned_be32(&prefix_opt->reserved, 0);
+    memcpy(prefix_opt->prefix.be32, prefix.be32, sizeof(ovs_be32[4]));
+
+    struct ovs_ra_msg *ra = dp_packet_l4(b);
+    ra->icmph.icmp6_cksum = 0;
+    uint32_t icmp_csum = ip_csum_pseudoheader6(dp_packet_l3(b));
+    ra->icmph.icmp6_cksum = csum_finish(csum_continue(
+        icmp_csum, ra, prev_l4_size + ND_PREFIX_OPT_LEN));
+}
+
+void
+IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6)
+{
+    if (is_ipv6) {
+        ovs_16aligned_be32 *ip6 = dp_packet_l3(pkt);
+
+        put_16aligned_be32(ip6, get_16aligned_be32(ip6) |
+                                htonl(IP_ECN_CE << 20));
+    } else {
+        struct ip_header *nh = dp_packet_l3(pkt);
+        uint8_t tos = nh->ip_tos;
+
+        tos |= IP_ECN_CE;
+        if (nh->ip_tos != tos) {
+            if (dp_packet_ip_checksum_valid(pkt)) {
+                dp_packet_ip_checksum_set_partial(pkt);
+            } else {
+                nh->ip_csum = recalc_csum16(nh->ip_csum, htons(nh->ip_tos),
+                                            htons((uint16_t) tos));
+            }
+
+            nh->ip_tos = tos;
+        }
+    }
+}
+
+/* Set TCP checksum field in packet 'p' with complete checksum.
+ * The packet must have the L3 and L4 offsets. */
+void
+packet_tcp_complete_csum(struct dp_packet *p, bool inner)
+{
+    struct tcp_header *tcp;
+    size_t tcp_sz;
+    void *ip_hdr;
+
+    if (inner) {
+        tcp = dp_packet_inner_l4(p);
+        ip_hdr = dp_packet_inner_l3(p);
+        tcp_sz = dp_packet_inner_l4_size(p);
+    } else {
+        tcp = dp_packet_l4(p);
+        ip_hdr = dp_packet_l3(p);
+        tcp_sz = dp_packet_l4_size(p);
+    }
+
+    ovs_assert(tcp);
+    ovs_assert(ip_hdr);
+
+    tcp->tcp_csum = 0;
+    if (IP_VER(((const struct ip_header *) ip_hdr)->ip_ihl_ver) == 4) {
+        struct ip_header *ip = ip_hdr;
+
+        tcp->tcp_csum = csum_finish(csum_continue(ip_csum_pseudoheader(ip),
+                                                  tcp, tcp_sz));
+    } else {
+        struct ovs_16aligned_ip6_hdr *ip6 = ip_hdr;
+
+        tcp->tcp_csum = ip_csum_upperlayer6(ip6, tcp, ip6->ip6_nxt,
+                                                tcp_sz);
+    }
+
+    if (inner) {
+        dp_packet_inner_l4_checksum_set_good(p);
+    } else {
+        dp_packet_l4_checksum_set_good(p);
+    }
+}
+
+/* Set UDP checksum field in packet 'p' with complete checksum.
+ * The packet must have the L3 and L4 offsets. */
+void
+packet_udp_complete_csum(struct dp_packet *p, bool inner)
+{
+    struct udp_header *udp;
+    size_t udp_sz;
+    void *ip_hdr;
+
+    if (inner) {
+        udp = dp_packet_inner_l4(p);
+        ip_hdr = dp_packet_inner_l3(p);
+        udp_sz = dp_packet_inner_l4_size(p);
+    } else {
+        udp = dp_packet_l4(p);
+        ip_hdr = dp_packet_l3(p);
+        udp_sz = dp_packet_l4_size(p);
+    }
+
+    ovs_assert(udp);
+    ovs_assert(ip_hdr);
+
+    /* Skip csum calculation if the udp_csum is zero. */
+    if (!udp->udp_csum) {
+        goto out;
+    }
+
+    udp->udp_csum = 0;
+    if (IP_VER(((const struct ip_header *) ip_hdr)->ip_ihl_ver) == 4) {
+        struct ip_header *ip = ip_hdr;
+
+        udp->udp_csum = csum_finish(csum_continue(ip_csum_pseudoheader(ip),
+                                                  udp, udp_sz));
+    } else {
+        struct ovs_16aligned_ip6_hdr *ip6 = ip_hdr;
+
+        udp->udp_csum = ip_csum_upperlayer6(ip6, udp, ip6->ip6_nxt,
+                                                udp_sz);
+    }
+
+    if (!udp->udp_csum) {
+        udp->udp_csum = htons(0xffff);
+    }
+
+out:
+    if (inner) {
+        dp_packet_inner_l4_checksum_set_good(p);
+    } else {
+        dp_packet_l4_checksum_set_good(p);
+    }
+}
+
+/* This helper computes a "constant" UDP checksum without looking at the
+ * L4 payload.
+ *
+ * This is possible when L4 is either TCP or UDP: the L4 payload checksum
+ * is either computed in SW or in HW later, but its contribution to the
+ * outer checksum is cancelled by the L4 payload being part of the global
+ * packet sum. */
+bool
+packet_udp_tunnel_csum(struct dp_packet *p)
+{
+    struct ip_header *inner_ip;
+    const void *inner_l4_data;
+    char *after_inner_l4_csum;
+    size_t inner_l4_csum_off;
+    struct udp_header *udp;
+    ovs_be16 inner_l4_csum;
+    uint32_t partial_csum;
+    struct ip_header *ip;
+    uint32_t inner_csum;
+    uint16_t tso_segsz;
+    bool inner_ipv4;
+    void *inner_l4;
+
+    inner_ip = dp_packet_inner_l3(p);
+    inner_l4 = dp_packet_inner_l4(p);
+    ip = dp_packet_l3(p);
+    udp = dp_packet_l4(p);
+
+    if (dp_packet_inner_l4_proto_tcp(p)) {
+        inner_l4_csum_off = offsetof(struct tcp_header, tcp_csum);
+        inner_l4_data = dp_packet_get_inner_tcp_payload(p);
+        if (!inner_l4_data) {
+            /* Malformed packet. */
+            return false;
+        }
+    } else if (dp_packet_inner_l4_proto_udp(p)) {
+        inner_l4_csum_off = offsetof(struct udp_header, udp_csum);
+        inner_l4_data = (char *) inner_l4 + sizeof (struct udp_header);
+        if (((struct udp_header *) inner_l4)->udp_csum == 0) {
+            /* There is no nested checksum.
+             * No choice but compute a full checksum. */
+            return false;
+        }
+    } else {
+        /* This optimisation applies only to inner TCP/UDP. */
+        return false;
+    }
+
+    if (!dp_packet_inner_l4_checksum_valid(p)) {
+        /* We have no idea about the contribution of the payload data
+         * and what the L4 checksum put in the packet data looks like.
+         * Simpler is to let a full checksum happen. */
+        return false;
+    }
+
+    inner_ipv4 = IP_VER(inner_ip->ip_ihl_ver) == 4;
+    if (inner_ipv4) {
+        inner_csum = ip_csum_pseudoheader(inner_ip);
+    } else {
+        struct ovs_16aligned_ip6_hdr *inner_ip6 = dp_packet_inner_l3(p);
+
+        inner_csum = ip_csum_pseudoheader6(inner_ip6);
+    }
+
+    inner_csum = csum_continue(inner_csum, inner_l4, inner_l4_csum_off);
+    after_inner_l4_csum = (char *) inner_l4 + inner_l4_csum_off + 2;
+    inner_l4_csum = csum_finish(csum_continue(inner_csum, after_inner_l4_csum,
+        (char *) inner_l4_data - after_inner_l4_csum));
+    /* Important: for inner UDP, a null inner_l4_csum here should in theory be
+     * replaced with 0xffff.  However, since the only use of inner_l4_csum is
+     * for the final outer checksum with a csum_add16() below, we can skip this
+     * entirely because adding 0xffff will have the same effect as adding 0x0
+     * after reducing in csum_finish. */
+
+    udp->udp_csum = 0;
+    if (IP_VER(ip->ip_ihl_ver) == 4) {
+        partial_csum = ip_csum_pseudoheader(ip);
+    } else {
+        struct ovs_16aligned_ip6_hdr *ip6 = dp_packet_l3(p);
+
+        partial_csum = ip_csum_pseudoheader6(ip6);
+    }
+
+    partial_csum = csum_continue(partial_csum, udp,
+        (char *) inner_ip - (char *) udp);
+    if (!inner_ipv4 || !dp_packet_inner_ip_checksum_valid(p)) {
+        /* IPv6 has no checksum, so for inner IPv6, we need to sum the header.
+         *
+         * In IPv4 case, if inner checksum is already good or HW offload
+         * has been requested, the (final) sum of the IPv4 header will be 0.
+         * Otherwise, we need to sum the header like for IPv6. */
+        partial_csum = csum_continue(partial_csum, inner_ip,
+            (char *) inner_l4 - (char *) inner_ip);
+    }
+    partial_csum = csum_continue(partial_csum, inner_l4, inner_l4_csum_off);
+    partial_csum = csum_add16(partial_csum, inner_l4_csum);
+    partial_csum = csum_continue(partial_csum, after_inner_l4_csum,
+        (char *) inner_l4_data - after_inner_l4_csum);
+    udp->udp_csum = csum_finish(partial_csum);
+    tso_segsz = dp_packet_get_tso_segsz(p);
+    if (tso_segsz) {
+        uint16_t payload_len = dp_packet_get_inner_tcp_payload_length(p);
+
+        ovs_assert(payload_len == tso_segsz * dp_packet_gso_nr_segs(p));
+
+        /* The pseudo header used in the outer UDP checksum is dependent on
+         * the ip_tot_len / ip6_plen which was a reflection of the TSO frame
+         * size. The segmented packet will be shorter. */
+        udp->udp_csum = recalc_csum16(udp->udp_csum, htons(payload_len),
+                                      htons(tso_segsz));
+
+        /* When segmenting the packet, various headers get updated:
+         * - inner L3
+         *   - for IPv4, ip_tot_len is updated, BUT it is not affecting the
+         *     outer UDP checksum because the IPv4 header itself contains
+         *     a checksum that compensates for this update,
+         *   - for IPv6, ip6_plen is updated, and this must be considered,
+         * - inner L4
+         *   - inner pseudo header used in the TCP checksum is dependent on
+         *     the inner ip_tot_len / ip6_plen,
+         *   - TCP seq number is updated,
+         *   - the HW may change some TCP flags (think PSH/FIN),
+         *   BUT the TCP checksum will compensate for those updates,
+         *
+         * Summary: we only care about the inner IPv6 header update.
+         */
+        if (IP_VER(inner_ip->ip_ihl_ver) != 4) {
+            udp->udp_csum = recalc_csum16(udp->udp_csum, htons(payload_len),
+                                          htons(tso_segsz));
+        }
+    }
+    if (!udp->udp_csum) {
+        udp->udp_csum = htons(0xffff);
+    }
+    dp_packet_l4_checksum_set_good(p);
+
+    return true;
+}
+
+/* Set SCTP checksum field in packet 'p' with complete checksum.
+ * The packet must have the L3 and L4 offsets. */
+void
+packet_sctp_complete_csum(struct dp_packet *p, bool inner)
+{
+    struct sctp_header *sh;
+    uint16_t tp_len;
+    ovs_be32 csum;
+
+    if (inner) {
+        sh = dp_packet_inner_l4(p);
+        tp_len = dp_packet_inner_l4_size(p);
+    } else {
+        sh = dp_packet_l4(p);
+        tp_len = dp_packet_l4_size(p);
+    }
+
+    ovs_assert(sh);
+
+    put_16aligned_be32(&sh->sctp_csum, 0);
+    csum = crc32c((void *) sh, tp_len);
+    put_16aligned_be32(&sh->sctp_csum, csum);
+
+    if (inner) {
+        dp_packet_inner_l4_checksum_set_good(p);
+    } else {
+        dp_packet_l4_checksum_set_good(p);
+    }
+}
diff --git a/lib/dp-packet.h b/lib/dp-packet.h
index 55114d0b39..845cdcee11 100644
--- a/lib/dp-packet.h
+++ b/lib/dp-packet.h
@@ -17,22 +17,34 @@ 
 #ifndef DPBUF_H
 #define DPBUF_H 1
 
+#include <inttypes.h>
+#include <sys/types.h>
 #include <stddef.h>
 #include <stdint.h>
+#include <string.h>
 
 #ifdef DPDK_NETDEV
 #include <rte_config.h>
 #include <rte_mbuf.h>
 #endif
 
+#include "compiler.h"
 #include "csum.h"
+#include "flow.h"
+#include "openvswitch/geneve.h"
+#include "hash.h"
+#include "openvswitch/list.h"
 #include "netdev-afxdp.h"
 #include "netdev-dpdk.h"
 #include "net-proto.h"
-#include "openvswitch/list.h"
-#include "packets.h"
+#include "openvswitch/nsh.h"
+#include "odp-netlink.h"
+#include "openvswitch/packets.h"
+#include "random.h"
+#include "timeval.h"
+#include "openvswitch/types.h"
 #include "util.h"
-#include "flow.h"
+#include "unaligned.h"
 
 #ifdef  __cplusplus
 extern "C" {
@@ -1504,6 +1516,94 @@  dp_packet_update_rss_hash_ipv6_tcp_udp(struct dp_packet *packet)
     dp_packet_set_rss_hash(packet, hash);
 }
 
+
+void compose_rarp(struct dp_packet *, const struct eth_addr);
+
+void eth_push_vlan(struct dp_packet *, ovs_be16 tpid, ovs_be16 tci);
+void eth_pop_vlan(struct dp_packet *);
+
+const char *eth_from_hex(const char *hex, struct dp_packet **packetp);
+
+void set_mpls_lse(struct dp_packet *, ovs_be32 label);
+void push_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse);
+void pop_mpls(struct dp_packet *, ovs_be16 ethtype);
+void add_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse,
+              bool l3_encap);
+
+
+void push_eth(struct dp_packet *packet, const struct eth_addr *dst,
+              const struct eth_addr *src);
+void pop_eth(struct dp_packet *packet);
+
+void push_nsh(struct dp_packet *packet, const struct nsh_hdr *nsh_hdr_src);
+bool pop_nsh(struct dp_packet *packet);
+
+void *eth_compose(struct dp_packet *, const struct eth_addr eth_dst,
+                  const struct eth_addr eth_src, uint16_t eth_type,
+                  size_t size);
+void *snap_compose(struct dp_packet *, const struct eth_addr eth_dst,
+                   const struct eth_addr eth_src,
+                   unsigned int oui, uint16_t snap_type, size_t size);
+void packet_set_ipv4(struct dp_packet *, ovs_be32 src, ovs_be32 dst, uint8_t tos,
+                     uint8_t ttl);
+void packet_set_ipv4_addr(struct dp_packet *packet, ovs_16aligned_be32 *addr,
+                          ovs_be32 new_addr);
+void packet_set_ipv6(struct dp_packet *, const struct in6_addr *src,
+                     const struct in6_addr *dst, uint8_t tc,
+                     ovs_be32 fl, uint8_t hlmit);
+void packet_set_ipv6_addr(struct dp_packet *packet, uint8_t proto,
+                          ovs_16aligned_be32 addr[4],
+                          const struct in6_addr *new_addr,
+                          bool recalculate_csum);
+void packet_set_tcp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
+void packet_set_udp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
+void packet_set_sctp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
+void packet_set_icmp(struct dp_packet *, uint8_t type, uint8_t code);
+void packet_set_nd(struct dp_packet *, const struct in6_addr *target,
+                   const struct eth_addr sll, const struct eth_addr tll);
+void packet_set_nd_ext(struct dp_packet *packet,
+                       const ovs_16aligned_be32 rso_flags,
+                       const uint8_t opt_type);
+void packet_set_igmp3_query(struct dp_packet *, uint8_t max_resp,
+                            ovs_be32 group, bool srs, uint8_t qrv,
+                            uint8_t qqic);
+void *compose_ipv6(struct dp_packet *packet, uint8_t proto,
+                   const struct in6_addr *src, const struct in6_addr *dst,
+                   uint8_t key_tc, ovs_be32 key_fl, uint8_t key_hl, int size);
+void compose_arp__(struct dp_packet *);
+void compose_arp(struct dp_packet *, uint16_t arp_op,
+                 const struct eth_addr arp_sha,
+                 const struct eth_addr arp_tha, bool broadcast,
+                 ovs_be32 arp_spa, ovs_be32 arp_tpa);
+void compose_nd_ns(struct dp_packet *, const struct eth_addr eth_src,
+                   const struct in6_addr *ipv6_src,
+                   const struct in6_addr *ipv6_dst);
+void compose_nd_na(struct dp_packet *, const struct eth_addr eth_src,
+                   const struct eth_addr eth_dst,
+                   const struct in6_addr *ipv6_src,
+                   const struct in6_addr *ipv6_dst,
+                   ovs_be32 rso_flags);
+void compose_nd_ra(struct dp_packet *,
+                   const struct eth_addr eth_src,
+                   const struct eth_addr eth_dst,
+                   const struct in6_addr *ipv6_src,
+                   const struct in6_addr *ipv6_dst,
+                   uint8_t cur_hop_limit, uint8_t mo_flags,
+                   ovs_be16 router_lt, ovs_be32 reachable_time,
+                   ovs_be32 retrans_timer, uint32_t mtu);
+void packet_put_ra_prefix_opt(struct dp_packet *,
+                              uint8_t plen, uint8_t la_flags,
+                              ovs_be32 valid_lifetime,
+                              ovs_be32 preferred_lifetime,
+                              const ovs_be128 router_prefix);
+bool packet_rh_present(struct dp_packet *packet, uint8_t *nexthdr,
+                       bool *first_frag);
+void IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6);
+void packet_tcp_complete_csum(struct dp_packet *, bool is_inner);
+void packet_udp_complete_csum(struct dp_packet *, bool is_inner);
+bool packet_udp_tunnel_csum(struct dp_packet *);
+void packet_sctp_complete_csum(struct dp_packet *, bool is_inner);
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/lib/dpctl.c b/lib/dpctl.c
index 074e739222..904bf09b7e 100644
--- a/lib/dpctl.c
+++ b/lib/dpctl.c
@@ -43,7 +43,6 @@ 
 #include "odp-util.h"
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/ofp-ct.h"
-#include "packets.h"
 #include "openvswitch/shash.h"
 #include "simap.h"
 #include "smap.h"
diff --git a/lib/dpif-netdev-extract-avx512.c b/lib/dpif-netdev-extract-avx512.c
index 8741bbf296..18aa416e5f 100644
--- a/lib/dpif-netdev-extract-avx512.c
+++ b/lib/dpif-netdev-extract-avx512.c
@@ -48,7 +48,6 @@ 
 #include "dpif-netdev-private-extract.h"
 #include "dpif-netdev-private-flow.h"
 #include "dp-packet.h"
-#include "packets.h"
 
 /* AVX512-BW level permutex2var_epi8 emulation. */
 static inline __m512i
diff --git a/lib/dpif-netdev-lookup.c b/lib/dpif-netdev-lookup.c
index 4c1379aa54..eb73f3b571 100644
--- a/lib/dpif-netdev-lookup.c
+++ b/lib/dpif-netdev-lookup.c
@@ -19,6 +19,7 @@ 
 #include "dpif-netdev-lookup.h"
 
 #include "cpu.h"
+#include "openvswitch/dynamic-string.h"
 #include "openvswitch/vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(dpif_netdev_lookup);
diff --git a/lib/dpif-netdev-private-extract.c b/lib/dpif-netdev-private-extract.c
index ded08fd3ef..116db5cec0 100644
--- a/lib/dpif-netdev-private-extract.c
+++ b/lib/dpif-netdev-private-extract.c
@@ -24,6 +24,7 @@ 
 #include "dpif-netdev-private-dpcls.h"
 #include "dpif-netdev-private-extract.h"
 #include "dpif-netdev-private-thread.h"
+#include "openvswitch/dynamic-string.h"
 #include "flow.h"
 #include "openvswitch/vlog.h"
 #include "ovs-thread.h"
diff --git a/lib/dpif-netdev-private-flow.h b/lib/dpif-netdev-private-flow.h
index 308c5113f9..15c2d7d1cd 100644
--- a/lib/dpif-netdev-private-flow.h
+++ b/lib/dpif-netdev-private-flow.h
@@ -25,6 +25,7 @@ 
 #include <stdint.h>
 
 #include "cmap.h"
+#include "netlink-protocol.h"
 #include "openvswitch/thread.h"
 
 #ifdef  __cplusplus
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 9df05c4c28..03b158955e 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -74,7 +74,6 @@ 
 #include "openvswitch/vlog.h"
 #include "ovs-numa.h"
 #include "ovs-rcu.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "pvector.h"
 #include "random.h"
diff --git a/lib/dpif-netdev.h b/lib/dpif-netdev.h
index 6db6ed2e21..ecd450ccbf 100644
--- a/lib/dpif-netdev.h
+++ b/lib/dpif-netdev.h
@@ -23,7 +23,6 @@ 
 #include "dpif.h"
 #include "openvswitch/types.h"
 #include "dp-packet.h"
-#include "packets.h"
 
 #ifdef  __cplusplus
 extern "C" {
diff --git a/lib/dpif-netlink-rtnl.c b/lib/dpif-netlink-rtnl.c
index ca803d0af2..9755a9c9df 100644
--- a/lib/dpif-netlink-rtnl.c
+++ b/lib/dpif-netlink-rtnl.c
@@ -24,6 +24,7 @@ 
 
 #include "dpif-netlink.h"
 #include "netdev-vport.h"
+#include "netlink.h"
 #include "netlink-socket.h"
 #include "openvswitch/vlog.h"
 
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index f22a879340..7ddaad8dff 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -58,7 +58,6 @@ 
 #include "openvswitch/thread.h"
 #include "openvswitch/usdt-probes.h"
 #include "openvswitch/vlog.h"
-#include "packets.h"
 #include "random.h"
 #include "sset.h"
 #include "timeval.h"
diff --git a/lib/dpif-offload-dpdk-netdev.c b/lib/dpif-offload-dpdk-netdev.c
index efe99065e4..ed3977032a 100644
--- a/lib/dpif-offload-dpdk-netdev.c
+++ b/lib/dpif-offload-dpdk-netdev.c
@@ -27,13 +27,14 @@ 
 #include "dpif-netdev.h"
 #include "dpif-offload.h"
 #include "dpif-offload-dpdk-private.h"
+#include "openvswitch/dynamic-string.h"
 #include "netdev-provider.h"
 #include "netdev-vport.h"
+#include "netlink.h"
 #include "odp-util.h"
 #include "openvswitch/match.h"
 #include "openvswitch/vlog.h"
 #include "ovs-rcu.h"
-#include "packets.h"
 #include "uuid.h"
 
 VLOG_DEFINE_THIS_MODULE(dpif_offload_dpdk_netdev);
diff --git a/lib/dpif-offload-dpdk.c b/lib/dpif-offload-dpdk.c
index 2991c24bbd..fed8e48823 100644
--- a/lib/dpif-offload-dpdk.c
+++ b/lib/dpif-offload-dpdk.c
@@ -20,11 +20,14 @@ 
 #include "dpif-offload.h"
 #include "dpif-offload-provider.h"
 #include "dpif-offload-dpdk-private.h"
+#include "openvswitch/dynamic-string.h"
 #include "id-fpool.h"
 #include "mov-avg.h"
 #include "mpsc-queue.h"
 #include "netdev-provider.h"
 #include "netdev-vport.h"
+#include "net-proto.h"
+#include "openvswitch/ofpbuf.h"
 #include "util.h"
 #include "uuid.h"
 
diff --git a/lib/dpif.c b/lib/dpif.c
index 3178a24dd6..f7b39179a2 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -35,7 +35,6 @@ 
 #include "netlink.h"
 #include "odp-execute.h"
 #include "odp-util.h"
-#include "packets.h"
 #include "route-table.h"
 #include "seq.h"
 #include "sset.h"
diff --git a/lib/dpif.h b/lib/dpif.h
index 3e6a34a25c..c419bf775d 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -384,7 +384,6 @@ 
 #include "openflow/openflow.h"
 #include "openvswitch/ofp-meter.h"
 #include "ovs-numa.h"
-#include "packets.h"
 #include "util.h"
 
 #ifdef  __cplusplus
diff --git a/lib/flow.c b/lib/flow.c
index 20f7d6ea86..af2628f3ef 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -36,7 +36,6 @@ 
 #include "openvswitch/match.h"
 #include "dp-packet.h"
 #include "openflow/openflow.h"
-#include "packets.h"
 #include "odp-util.h"
 #include "random.h"
 #include "unaligned.h"
@@ -44,6 +43,7 @@ 
 #include "openvswitch/nsh.h"
 #include "ovs-router.h"
 #include "lib/netdev-provider.h"
+#include "tun-metadata.h"
 #include "openvswitch/vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(flow);
diff --git a/lib/flow.h b/lib/flow.h
index bf0656cacd..a9be873d7e 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -30,8 +30,8 @@ 
 #include "openflow/openflow.h"
 #include "openvswitch/flow.h"
 #include "net-proto.h"
-#include "packets.h"
 #include "hash.h"
+#include "odp-netlink.h"
 #include "util.h"
 
 struct dpif_flow_stats;
@@ -973,6 +973,161 @@  static inline bool is_ct_valid(const struct flow *flow,
     return flow->ct_state & CS_VALID_MASK;
 }
 
+/* Purely internal to OVS userspace. These flags should never be exposed to
+ * the outside world and so aren't included in the flags mask. */
+
+/* Tunnel information is in userspace datapath format. */
+#define FLOW_TNL_F_UDPIF (1 << 4)
+
+static inline bool
+flow_tnl_dst_is_set(const struct flow_tnl *tnl)
+{
+    return tnl->ip_dst || ipv6_addr_is_set(&tnl->ipv6_dst);
+}
+
+static inline bool
+flow_tnl_src_is_set(const struct flow_tnl *tnl)
+{
+    return tnl->ip_src || ipv6_addr_is_set(&tnl->ipv6_src);
+}
+
+struct in6_addr flow_tnl_dst(const struct flow_tnl *tnl);
+struct in6_addr flow_tnl_src(const struct flow_tnl *tnl);
+
+/* Returns an offset to 'src' covering all the meaningful fields in 'src'. */
+static inline size_t
+flow_tnl_size(const struct flow_tnl *src)
+{
+    if (!flow_tnl_dst_is_set(src)) {
+        /* Covers ip_dst and ipv6_dst only. */
+        return offsetof(struct flow_tnl, ip_src);
+    }
+    if (src->flags & FLOW_TNL_F_UDPIF) {
+        /* Datapath format, cover all options we have. */
+        return offsetof(struct flow_tnl, metadata.opts)
+            + src->metadata.present.len;
+    }
+    if (!src->metadata.present.map) {
+        /* No TLVs, opts is irrelevant. */
+        return offsetof(struct flow_tnl, metadata.opts);
+    }
+    /* Have decoded TLVs, opts is relevant. */
+    return sizeof *src;
+}
+
+/* Copy flow_tnl, but avoid copying unused portions of tun_metadata.  Unused
+ * data in 'dst' is NOT cleared, so this must not be used in cases where the
+ * uninitialized portion may be hashed over. */
+static inline void
+flow_tnl_copy__(struct flow_tnl *dst, const struct flow_tnl *src)
+{
+    memcpy(dst, src, flow_tnl_size(src));
+}
+
+/* Fwd declare conn here. */
+struct conn;
+
+/* Datapath packet metadata */
+struct pkt_metadata {
+PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline0,
+    uint32_t recirc_id;         /* Recirculation id carried with the
+                                   recirculating packets. 0 for packets
+                                   received from the wire. */
+    uint32_t dp_hash;           /* hash value computed by the recirculation
+                                   action. */
+    uint32_t skb_priority;      /* Packet priority for QoS. */
+    uint32_t pkt_mark;          /* Packet mark. */
+    uint8_t  ct_state;          /* Connection state. */
+    bool ct_orig_tuple_ipv6;
+    uint16_t ct_zone;           /* Connection zone. */
+    uint32_t ct_mark;           /* Connection mark. */
+    ovs_u128 ct_label;          /* Connection label. */
+    union flow_in_port in_port; /* Input port. */
+    odp_port_t orig_in_port;    /* Originating in_port for tunneled packets */
+    struct conn *conn;          /* Cached conntrack connection. */
+    bool reply;                 /* True if reply direction. */
+    bool icmp_related;          /* True if ICMP related. */
+);
+
+PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline1,
+    union {                     /* Populated only for non-zero 'ct_state'. */
+        struct ovs_key_ct_tuple_ipv4 ipv4;
+        struct ovs_key_ct_tuple_ipv6 ipv6;   /* Used only if                */
+    } ct_orig_tuple;                         /* 'ct_orig_tuple_ipv6' is set */
+);
+
+PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline2,
+    struct flow_tnl tunnel;     /* Encapsulating tunnel parameters. Note that
+                                 * if 'ip_dst' == 0, the rest of the fields may
+                                 * be uninitialized. */
+);
+};
+
+BUILD_ASSERT_DECL(offsetof(struct pkt_metadata, cacheline0) == 0);
+BUILD_ASSERT_DECL(offsetof(struct pkt_metadata, cacheline1) ==
+                  CACHE_LINE_SIZE);
+BUILD_ASSERT_DECL(offsetof(struct pkt_metadata, cacheline2) ==
+                  2 * CACHE_LINE_SIZE);
+
+static inline void
+pkt_metadata_init_tnl(struct pkt_metadata *md)
+{
+    odp_port_t orig_in_port;
+
+    /* Zero up through the tunnel metadata options. The length and table
+     * are before this and as long as they are empty, the options won't
+     * be looked at. Keep the orig_in_port field. */
+    orig_in_port = md->in_port.odp_port;
+    memset(md, 0, offsetof(struct pkt_metadata, tunnel.metadata.opts));
+    md->orig_in_port = orig_in_port;
+}
+
+static inline void
+pkt_metadata_init_conn(struct pkt_metadata *md)
+{
+    md->conn = NULL;
+}
+
+static inline void
+pkt_metadata_init(struct pkt_metadata *md, odp_port_t port)
+{
+    /* This is called for every packet in userspace datapath and affects
+     * performance if all the metadata is initialized. Hence, fields should
+     * only be zeroed out when necessary.
+     *
+     * Initialize only till ct_state. Once the ct_state is zeroed out rest
+     * of ct fields will not be looked at unless ct_state != 0.
+     */
+    memset(md, 0, offsetof(struct pkt_metadata, ct_orig_tuple_ipv6));
+
+    /* It can be expensive to zero out all of the tunnel metadata. However,
+     * we can just zero out ip_dst and the rest of the data will never be
+     * looked at. */
+    md->tunnel.ip_dst = 0;
+    md->tunnel.ipv6_dst = in6addr_any;
+    md->in_port.odp_port = port;
+    md->orig_in_port = port;
+    md->conn = NULL;
+}
+
+/* This function prefetches the cachelines touched by pkt_metadata_init()
+ * and pkt_metadata_init_tnl().  For performance reasons the two functions
+ * should be kept in sync. */
+static inline void
+pkt_metadata_prefetch_init(struct pkt_metadata *md)
+{
+    /* Prefetch cacheline0 as members till ct_state and odp_port will
+     * be initialized later in pkt_metadata_init(). */
+    OVS_PREFETCH(md->cacheline0);
+
+    /* Prefetch cacheline1 as members of this cacheline will be zeroed out
+     * in pkt_metadata_init_tnl(). */
+    OVS_PREFETCH(md->cacheline1);
+
+    /* Prefetch cachline2 as ip_dst & ipv6_dst fields will be initialized. */
+    OVS_PREFETCH(md->cacheline2);
+}
+
 static inline void
 pkt_metadata_from_flow(struct pkt_metadata *md, const struct flow *flow)
 {
diff --git a/lib/ipf.c b/lib/ipf.c
index 3f60ed81cc..d5caec5404 100644
--- a/lib/ipf.c
+++ b/lib/ipf.c
@@ -25,6 +25,7 @@ 
 
 #include "coverage.h"
 #include "csum.h"
+#include "openvswitch/dynamic-string.h"
 #include "ipf.h"
 #include "latch.h"
 #include "openvswitch/hmap.h"
@@ -32,7 +33,6 @@ 
 #include "openvswitch/types.h"
 #include "openvswitch/vlog.h"
 #include "ovs-atomic.h"
-#include "packets.h"
 #include "util.h"
 
 VLOG_DEFINE_THIS_MODULE(ipf);
diff --git a/lib/lacp.c b/lib/lacp.c
index 3252f17ebf..afc3bc0924 100644
--- a/lib/lacp.c
+++ b/lib/lacp.c
@@ -24,7 +24,6 @@ 
 #include "openvswitch/hmap.h"
 #include "dp-packet.h"
 #include "ovs-atomic.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "seq.h"
 #include "openvswitch/shash.h"
diff --git a/lib/lacp.h b/lib/lacp.h
index 5ba17c36a5..ff22b7fc57 100644
--- a/lib/lacp.h
+++ b/lib/lacp.h
@@ -18,8 +18,12 @@ 
 #define LACP_H 1
 
 #include <stdbool.h>
+#include <stddef.h>
 #include <stdint.h>
-#include "packets.h"
+
+#include "net-proto.h"
+
+struct dp_packet;
 
 /* LACP Protocol Implementation. */
 
diff --git a/lib/lldp/lldp.c b/lib/lldp/lldp.c
index 6fdcfef569..ad4f69c36f 100644
--- a/lib/lldp/lldp.c
+++ b/lib/lldp/lldp.c
@@ -27,7 +27,6 @@ 
 #include <sys/types.h>
 #include "compiler.h"
 #include "dp-packet.h"
-#include "packets.h"
 
 VLOG_DEFINE_THIS_MODULE(lldp);
 
diff --git a/lib/lldp/lldpd-structs.h b/lib/lldp/lldpd-structs.h
index fe5d5f9f86..500f21f900 100644
--- a/lib/lldp/lldpd-structs.h
+++ b/lib/lldp/lldpd-structs.h
@@ -25,7 +25,6 @@ 
 #include <sys/socket.h>
 #include "aa-structs.h"
 #include "lldp-const.h"
-#include "packets.h"
 
 enum {
     LLDPD_AF_UNSPEC = 0,
diff --git a/lib/lldp/lldpd.c b/lib/lldp/lldpd.c
index 4bff7b017f..e790c1a68c 100644
--- a/lib/lldp/lldpd.c
+++ b/lib/lldp/lldpd.c
@@ -42,7 +42,6 @@ 
 #include "compiler.h"
 #include "openvswitch/dynamic-string.h"
 #include "openvswitch/list.h"
-#include "packets.h"
 #include "timeval.h"
 
 VLOG_DEFINE_THIS_MODULE(lldpd);
diff --git a/lib/lldp/lldpd.h b/lib/lldp/lldpd.h
index 3f5be84a20..6d70c159a7 100644
--- a/lib/lldp/lldpd.h
+++ b/lib/lldp/lldpd.h
@@ -28,7 +28,6 @@ 
 #include "openvswitch/list.h"
 #include "lldpd-structs.h"
 #include "lldp-tlv.h"
-#include "packets.h"
 #include "openvswitch/vlog.h"
 
 #define ETHERTYPE_LLDP 0x88cc
diff --git a/lib/mac-learning.c b/lib/mac-learning.c
index affb2faf53..a82b79c2fc 100644
--- a/lib/mac-learning.c
+++ b/lib/mac-learning.c
@@ -23,8 +23,10 @@ 
 #include "bitmap.h"
 #include "coverage.h"
 #include "hash.h"
+#include "net-proto.h"
 #include "openvswitch/list.h"
 #include "openvswitch/poll-loop.h"
+#include "random.h"
 #include "timeval.h"
 #include "unaligned.h"
 #include "util.h"
diff --git a/lib/mac-learning.h b/lib/mac-learning.h
index 270fbd70d4..feee7107b1 100644
--- a/lib/mac-learning.h
+++ b/lib/mac-learning.h
@@ -23,7 +23,6 @@ 
 #include "openvswitch/list.h"
 #include "ovs-atomic.h"
 #include "ovs-thread.h"
-#include "packets.h"
 #include "timeval.h"
 
 /* MAC learning table
diff --git a/lib/match.c b/lib/match.c
index cb9f1740d1..4526205b36 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -23,7 +23,6 @@ 
 #include "openvswitch/dynamic-string.h"
 #include "openvswitch/meta-flow.h"
 #include "openvswitch/ofp-port.h"
-#include "packets.h"
 #include "tun-metadata.h"
 #include "openvswitch/nsh.h"
 
diff --git a/lib/mcast-snooping.h b/lib/mcast-snooping.h
index de42cf826b..f99f021939 100644
--- a/lib/mcast-snooping.h
+++ b/lib/mcast-snooping.h
@@ -25,7 +25,6 @@ 
 #include "openvswitch/list.h"
 #include "ovs-atomic.h"
 #include "ovs-thread.h"
-#include "packets.h"
 #include "timeval.h"
 
 struct mcast_snooping;
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 6f1458d789..545c4f4bc8 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -29,7 +29,6 @@ 
 #include "ovs-atomic.h"
 #include "ovs-rcu.h"
 #include "ovs-thread.h"
-#include "packets.h"
 #include "random.h"
 #include "openvswitch/shash.h"
 #include "socket-util.h"
diff --git a/lib/multipath.c b/lib/multipath.c
index 6896f94a1e..56aa259e58 100644
--- a/lib/multipath.c
+++ b/lib/multipath.c
@@ -27,7 +27,6 @@ 
 #include "openvswitch/dynamic-string.h"
 #include "openvswitch/ofp-actions.h"
 #include "openvswitch/ofp-errors.h"
-#include "packets.h"
 #include "util.h"
 
 /* Checks that 'mp' is valid on flow.  Returns 0 if it is valid, otherwise an
diff --git a/lib/netdev-afxdp.c b/lib/netdev-afxdp.c
index 8ef2ac192f..61a72af945 100644
--- a/lib/netdev-afxdp.c
+++ b/lib/netdev-afxdp.c
@@ -52,7 +52,6 @@ 
 #include "openvswitch/vlog.h"
 #include "ovs-atomic.h"
 #include "ovs-numa.h"
-#include "packets.h"
 #include "socket-util.h"
 #include "util.h"
 
diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
index d29589efde..25837b04de 100644
--- a/lib/netdev-bsd.c
+++ b/lib/netdev-bsd.c
@@ -55,7 +55,6 @@ 
 #include "fatal-signal.h"
 #include "openflow/openflow.h"
 #include "ovs-thread.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "openvswitch/shash.h"
 #include "socket-util.h"
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index b5d72283c9..c0a8e08dc1 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -66,7 +66,6 @@ 
 #include "ovs-numa.h"
 #include "ovs-rcu.h"
 #include "ovs-thread.h"
-#include "packets.h"
 #include "smap.h"
 #include "sset.h"
 #include "timeval.h"
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index 7d3a7b9682..1575afdad8 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -34,7 +34,6 @@ 
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
 #include "ovs-atomic.h"
-#include "packets.h"
 #include "pcap-file.h"
 #include "openvswitch/poll-loop.h"
 #include "openvswitch/shash.h"
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index c5ab11f5bb..2d480b4b09 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -68,7 +68,6 @@ 
 #include "openflow/openflow.h"
 #include "ovs-atomic.h"
 #include "ovs-numa.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "rtnetlink.h"
 #include "openvswitch/shash.h"
diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c
index 5e88f9f9a0..4e32784798 100644
--- a/lib/netdev-native-tnl.c
+++ b/lib/netdev-native-tnl.c
@@ -36,12 +36,14 @@ 
 #include "coverage.h"
 #include "csum.h"
 #include "dp-packet.h"
+#include "openvswitch/dynamic-string.h"
 #include "netdev.h"
+#include "net-proto.h"
 #include "netdev-vport.h"
 #include "netdev-vport-private.h"
 #include "odp-netlink.h"
-#include "packets.h"
 #include "seq.h"
+#include "tun-metadata.h"
 #include "unaligned.h"
 #include "unixctl.h"
 #include "util.h"
diff --git a/lib/netdev-native-tnl.h b/lib/netdev-native-tnl.h
index 47d6b6bbcf..0d38416285 100644
--- a/lib/netdev-native-tnl.h
+++ b/lib/netdev-native-tnl.h
@@ -21,7 +21,6 @@ 
 #include <stddef.h>
 #include "compiler.h"
 #include "dp-packet.h"
-#include "packets.h"
 #include "unixctl.h"
 
 struct netdev;
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 136d8188c2..fc249399f8 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -24,7 +24,6 @@ 
 #include "openvswitch/list.h"
 #include "ovs-numa.h"
 #include "ovs-rcu.h"
-#include "packets.h"
 #include "seq.h"
 #include "openvswitch/shash.h"
 #include "smap.h"
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index d11269d006..25b6fef2db 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -39,7 +39,6 @@ 
 #include "openvswitch/dynamic-string.h"
 #include "ovs-atomic.h"
 #include "ovs-router.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "route-table.h"
 #include "simap.h"
diff --git a/lib/netdev-windows.c b/lib/netdev-windows.c
index 3fad501e3e..89e6d9f14c 100644
--- a/lib/netdev-windows.c
+++ b/lib/netdev-windows.c
@@ -25,7 +25,6 @@ 
 #include "fatal-signal.h"
 #include "netdev-provider.h"
 #include "openvswitch/ofpbuf.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "openvswitch/shash.h"
 #include "svec.h"
diff --git a/lib/netdev.c b/lib/netdev.c
index daa4287362..6ce18cf14c 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -45,7 +45,6 @@ 
 #include "odp-netlink.h"
 #include "openvswitch/json.h"
 #include "openflow/openflow.h"
-#include "packets.h"
 #include "openvswitch/ofp-print.h"
 #include "openvswitch/poll-loop.h"
 #include "seq.h"
diff --git a/lib/netdev.h b/lib/netdev.h
index 40f1621eca..36beba603b 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -21,7 +21,6 @@ 
 #include "openvswitch/types.h"
 #include "ovs-atomic.h"
 #include "ovs-rcu.h"
-#include "packets.h"
 #include "flow.h"
 
 #ifdef  __cplusplus
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 225cd57204..12ef66916a 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -26,13 +26,13 @@ 
 #include "openflow/nicira-ext.h"
 #include "openvswitch/dynamic-string.h"
 #include "openvswitch/meta-flow.h"
+#include "openvswitch/nsh.h"
 #include "openvswitch/ofp-actions.h"
 #include "openvswitch/ofp-errors.h"
 #include "openvswitch/ofp-match.h"
 #include "openvswitch/ofp-port.h"
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
-#include "packets.h"
 #include "openvswitch/shash.h"
 #include "tun-metadata.h"
 #include "unaligned.h"
diff --git a/lib/odp-execute-avx512.c b/lib/odp-execute-avx512.c
index 510a215cda..cabe069b33 100644
--- a/lib/odp-execute-avx512.c
+++ b/lib/odp-execute-avx512.c
@@ -27,11 +27,11 @@ 
 #include "csum.h"
 #include "dp-packet.h"
 #include "immintrin.h"
+#include "netlink.h"
 #include "odp-execute.h"
 #include "odp-execute-private.h"
 #include "odp-netlink.h"
 #include "openvswitch/vlog.h"
-#include "packets.h"
 
 VLOG_DEFINE_THIS_MODULE(odp_execute_avx512);
 
diff --git a/lib/odp-execute-private.c b/lib/odp-execute-private.c
index 8b7a6b4ab0..bc10a0b8f4 100644
--- a/lib/odp-execute-private.c
+++ b/lib/odp-execute-private.c
@@ -22,6 +22,7 @@ 
 #include "cpu.h"
 #include "dpdk.h"
 #include "dp-packet.h"
+#include "netlink.h"
 #include "odp-execute.h"
 #include "odp-execute-private.h"
 #include "odp-netlink.h"
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index ecbda8c010..42bce32588 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -32,7 +32,6 @@ 
 #include "netlink.h"
 #include "odp-netlink.h"
 #include "odp-util.h"
-#include "packets.h"
 #include "flow.h"
 #include "unaligned.h"
 #include "util.h"
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 4924aff93a..42ebd6a2cd 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -33,8 +33,8 @@ 
 #include "openvswitch/dynamic-string.h"
 #include "flow.h"
 #include "netlink.h"
+#include "openvswitch/nsh.h"
 #include "openvswitch/ofpbuf.h"
-#include "packets.h"
 #include "simap.h"
 #include "timeval.h"
 #include "tun-metadata.h"
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 85386d5529..2f13afe1fe 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -32,6 +32,7 @@ 
 
 struct ds;
 struct nlattr;
+struct nsh_hdr;
 struct ofpbuf;
 struct simap;
 struct pkt_metadata;
diff --git a/lib/ofp-ct.c b/lib/ofp-ct.c
index 2e12790b43..da7dcb18cf 100644
--- a/lib/ofp-ct.c
+++ b/lib/ofp-ct.c
@@ -25,11 +25,13 @@ 
 #include "openvswitch/ofp-ct.h"
 #include "openflow/nicira-ext.h"
 #include "openvswitch/dynamic-string.h"
+#include "net-proto.h"
 #include "openvswitch/ofp-msgs.h"
 #include "openvswitch/ofp-parse.h"
 #include "openvswitch/ofp-errors.h"
 #include "openvswitch/ofp-prop.h"
 #include "openvswitch/ofp-util.h"
+#include "openvswitch/ofpbuf.h"
 #include "openvswitch/packets.h"
 #include "openvswitch/vlog.h"
 
diff --git a/lib/ofp-ed-props.c b/lib/ofp-ed-props.c
index d0649da028..58f3c93ee1 100644
--- a/lib/ofp-ed-props.c
+++ b/lib/ofp-ed-props.c
@@ -22,8 +22,6 @@ 
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/ofp-parse.h"
 #include "util.h"
-#include "lib/packets.h"
-
 
 enum ofperr
 decode_ed_prop(const struct ofp_ed_prop_header **ofp_prop,
diff --git a/lib/ofp-match.c b/lib/ofp-match.c
index 6525922ef8..efd11e9e3e 100644
--- a/lib/ofp-match.c
+++ b/lib/ofp-match.c
@@ -17,12 +17,14 @@ 
 #include <config.h>
 #include "openvswitch/ofp-match.h"
 #include "byte-order.h"
+#include "openvswitch/dynamic-string.h"
 #include "flow.h"
 #include "nx-match.h"
 #include "openvswitch/match.h"
 #include "openvswitch/ofp-errors.h"
 #include "openvswitch/ofp-msgs.h"
 #include "openvswitch/ofp-port.h"
+#include "openvswitch/ofpbuf.h"
 #include "openvswitch/packets.h"
 #include "openvswitch/vlog.h"
 
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 102b183a8f..77208e4861 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -20,11 +20,11 @@ 
 #include "byte-order.h"
 #include "openvswitch/match.h"
 #include "openvswitch/meta-flow.h"
+#include "net-proto.h"
 #include "openvswitch/ofp-actions.h"
 #include "openvswitch/ofp-flow.h"
 #include "openvswitch/ofp-match.h"
 #include "openvswitch/ofp-table.h"
-#include "packets.h"
 #include "socket-util.h"
 #include "util.h"
 
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 874079b84b..9297dfe887 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -60,7 +60,6 @@ 
 #include "openvswitch/ofp-util.h"
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/type-props.h"
-#include "packets.h"
 #include "unaligned.h"
 #include "util.h"
 #include "uuid.h"
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index a324ceeeab..4050d72d31 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -45,7 +45,6 @@ 
 #include "openvswitch/type-props.h"
 #include "openvswitch/vlog.h"
 #include "openflow/intel-ext.h"
-#include "packets.h"
 #include "random.h"
 #include "tun-metadata.h"
 #include "unaligned.h"
diff --git a/lib/ovs-lldp.c b/lib/ovs-lldp.c
index 152777248f..45a8e386be 100644
--- a/lib/ovs-lldp.c
+++ b/lib/ovs-lldp.c
@@ -41,7 +41,6 @@ 
 #include "lldp/lldpd-structs.h"
 #include "netdev.h"
 #include "openvswitch/types.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "smap.h"
 #include "unixctl.h"
diff --git a/lib/ovs-lldp.h b/lib/ovs-lldp.h
index 661ac4e18a..de2364fcd8 100644
--- a/lib/ovs-lldp.h
+++ b/lib/ovs-lldp.h
@@ -25,7 +25,6 @@ 
 #include "openvswitch/list.h"
 #include "lldp/lldpd.h"
 #include "ovs-atomic.h"
-#include "packets.h"
 #include "timer.h"
 
 /* Transmit every LLDPD_TX_INTERVAL seconds. */
diff --git a/lib/ovs-router.c b/lib/ovs-router.c
index 2566386ea2..2c436c83f1 100644
--- a/lib/ovs-router.c
+++ b/lib/ovs-router.c
@@ -39,7 +39,6 @@ 
 #include "openvswitch/dynamic-string.h"
 #include "openvswitch/json.h"
 #include "netdev.h"
-#include "packets.h"
 #include "seq.h"
 #include "ovs-thread.h"
 #include "route-table.h"
diff --git a/lib/packets.c b/lib/packets.c
deleted file mode 100644
index 6f58f80a34..0000000000
--- a/lib/packets.c
+++ /dev/null
@@ -1,1420 +0,0 @@ 
-/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <config.h>
-#include "packets.h"
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
-#include <stdlib.h>
-#include <netdb.h>
-#include "byte-order.h"
-#include "csum.h"
-#include "crc32c.h"
-#include "flow.h"
-#include "openvswitch/hmap.h"
-#include "openvswitch/dynamic-string.h"
-#include "ovs-thread.h"
-#include "odp-util.h"
-#include "dp-packet.h"
-#include "dp-packet-gso.h"
-#include "unaligned.h"
-
-struct in6_addr
-flow_tnl_dst(const struct flow_tnl *tnl)
-{
-    return tnl->ip_dst ? in6_addr_mapped_ipv4(tnl->ip_dst) : tnl->ipv6_dst;
-}
-
-struct in6_addr
-flow_tnl_src(const struct flow_tnl *tnl)
-{
-    return tnl->ip_src ? in6_addr_mapped_ipv4(tnl->ip_src) : tnl->ipv6_src;
-}
-
-/* Fills 'b' with a Reverse ARP packet with Ethernet source address 'eth_src'.
- * This function is used by Open vSwitch to compose packets in cases where
- * context is important but content doesn't (or shouldn't) matter.
- *
- * The returned packet has enough headroom to insert an 802.1Q VLAN header if
- * desired. */
-void
-compose_rarp(struct dp_packet *b, const struct eth_addr eth_src)
-{
-    struct eth_header *eth;
-    struct arp_eth_header *arp;
-
-    dp_packet_clear(b);
-    dp_packet_prealloc_tailroom(b, 2 + ETH_HEADER_LEN + VLAN_HEADER_LEN
-                             + ARP_ETH_HEADER_LEN);
-    dp_packet_reserve(b, 2 + VLAN_HEADER_LEN);
-    eth = dp_packet_put_uninit(b, sizeof *eth);
-    eth->eth_dst = eth_addr_broadcast;
-    eth->eth_src = eth_src;
-    eth->eth_type = htons(ETH_TYPE_RARP);
-
-    arp = dp_packet_put_uninit(b, sizeof *arp);
-    arp->ar_hrd = htons(ARP_HRD_ETHERNET);
-    arp->ar_pro = htons(ARP_PRO_IP);
-    arp->ar_hln = sizeof arp->ar_sha;
-    arp->ar_pln = sizeof arp->ar_spa;
-    arp->ar_op = htons(ARP_OP_RARP);
-    arp->ar_sha = eth_src;
-    put_16aligned_be32(&arp->ar_spa, htonl(0));
-    arp->ar_tha = eth_src;
-    put_16aligned_be32(&arp->ar_tpa, htonl(0));
-
-    dp_packet_set_l3(b, arp);
-    b->packet_type = htonl(PT_ETH);
-}
-
-/* Insert VLAN header according to given TCI. Packet passed must be Ethernet
- * packet.  Ignores the CFI bit of 'tci' using 0 instead.
- *
- * Also adjusts the layer offsets accordingly. */
-void
-eth_push_vlan(struct dp_packet *packet, ovs_be16 tpid, ovs_be16 tci)
-{
-    struct vlan_eth_header *veh;
-
-    /* Insert new 802.1Q header. */
-    veh = dp_packet_resize_l2(packet, VLAN_HEADER_LEN);
-    memmove(veh, (char *)veh + VLAN_HEADER_LEN, 2 * ETH_ADDR_LEN);
-    veh->veth_type = tpid;
-    veh->veth_tci = tci & htons(~VLAN_CFI);
-}
-
-/* Removes outermost VLAN header (if any is present) from 'packet'.
- *
- * 'packet->l2_5' should initially point to 'packet''s outer-most VLAN header
- * or may be NULL if there are no VLAN headers. */
-void
-eth_pop_vlan(struct dp_packet *packet)
-{
-    struct vlan_eth_header *veh = dp_packet_eth(packet);
-
-    if (veh && dp_packet_size(packet) >= sizeof *veh
-        && eth_type_vlan(veh->veth_type)) {
-
-        memmove((char *)veh + VLAN_HEADER_LEN, veh, 2 * ETH_ADDR_LEN);
-        dp_packet_resize_l2(packet, -VLAN_HEADER_LEN);
-    }
-}
-
-/* Push Ethernet header onto 'packet' assuming it is layer 3 */
-void
-push_eth(struct dp_packet *packet, const struct eth_addr *dst,
-         const struct eth_addr *src)
-{
-    struct eth_header *eh;
-
-    ovs_assert(!dp_packet_is_eth(packet));
-    eh = dp_packet_resize_l2(packet, ETH_HEADER_LEN);
-    eh->eth_dst = *dst;
-    eh->eth_src = *src;
-    eh->eth_type = pt_ns_type_be(packet->packet_type);
-    packet->packet_type = htonl(PT_ETH);
-}
-
-/* Removes Ethernet header, including VLAN header, from 'packet'.
- *
- * Previous to calling this function, 'ofpbuf_l3(packet)' must not be NULL */
-void
-pop_eth(struct dp_packet *packet)
-{
-    char *l2_5 = dp_packet_l2_5(packet);
-    char *l3 = dp_packet_l3(packet);
-    ovs_be16 ethertype;
-    int increment;
-
-    ovs_assert(dp_packet_is_eth(packet));
-    ovs_assert(l3 != NULL);
-
-    if (l2_5) {
-        increment = packet->l2_5_ofs;
-        ethertype = *(ALIGNED_CAST(ovs_be16 *, (l2_5 - 2)));
-    } else {
-        increment = packet->l3_ofs;
-        ethertype = *(ALIGNED_CAST(ovs_be16 *, (l3 - 2)));
-    }
-
-    dp_packet_resize_l2(packet, -increment);
-    packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE, ntohs(ethertype));
-}
-
-/* Set ethertype of the packet. */
-static void
-set_ethertype(struct dp_packet *packet, ovs_be16 eth_type)
-{
-    struct eth_header *eh = dp_packet_eth(packet);
-
-    if (!eh) {
-        return;
-    }
-
-    if (eth_type_vlan(eh->eth_type)) {
-        ovs_be16 *p;
-        char *l2_5 = dp_packet_l2_5(packet);
-
-        p = ALIGNED_CAST(ovs_be16 *,
-                         (l2_5 ? l2_5 : (char *)dp_packet_l3(packet)) - 2);
-        *p = eth_type;
-    } else {
-        eh->eth_type = eth_type;
-    }
-}
-
-static bool is_mpls(struct dp_packet *packet)
-{
-    return packet->l2_5_ofs != UINT16_MAX;
-}
-
-/* Set MPLS label stack entry to outermost MPLS header.*/
-void
-set_mpls_lse(struct dp_packet *packet, ovs_be32 mpls_lse)
-{
-    /* Packet type should be MPLS to set label stack entry. */
-    if (is_mpls(packet)) {
-        struct mpls_hdr *mh = dp_packet_l2_5(packet);
-
-        /* Update mpls label stack entry. */
-        put_16aligned_be32(&mh->mpls_lse, mpls_lse);
-    }
-}
-
-/* Push MPLS label stack entry 'lse' onto 'packet' as the outermost MPLS
- * header.  If 'packet' does not already have any MPLS labels, then its
- * Ethertype is changed to 'ethtype' (which must be an MPLS Ethertype). */
-void
-push_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse)
-{
-    char * header;
-    size_t len;
-
-    if (!eth_type_mpls(ethtype)) {
-        return;
-    }
-
-    if (!is_mpls(packet)) {
-        /* Set MPLS label stack offset. */
-        packet->l2_5_ofs = packet->l3_ofs;
-    }
-
-    set_ethertype(packet, ethtype);
-
-    /* Push new MPLS shim header onto packet. */
-    len = packet->l2_5_ofs;
-    header = dp_packet_resize_l2_5(packet, MPLS_HLEN);
-    memmove(header, header + MPLS_HLEN, len);
-    memcpy(header + len, &lse, sizeof lse);
-
-    pkt_metadata_init_conn(&packet->md);
-}
-
-void
-add_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse,
-         bool l3_encap)
-{
-    if (!eth_type_mpls(ethtype)) {
-        return;
-    }
-
-    if (!l3_encap) {
-        struct mpls_hdr *header = dp_packet_resize_l2(packet, MPLS_HLEN);
-
-        put_16aligned_be32(&header->mpls_lse, lse);
-        packet->l2_5_ofs = 0;
-        packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE,
-                                             ntohs(ethtype));
-    } else {
-        size_t len;
-        char *header;
-
-        if (!is_mpls(packet)) {
-            /* Set MPLS label stack offset. */
-            packet->l2_5_ofs = packet->l3_ofs;
-        }
-        set_ethertype(packet, ethtype);
-
-        /* Push new MPLS shim header onto packet. */
-        len = packet->l2_5_ofs;
-        header = dp_packet_resize_l2_5(packet, MPLS_HLEN);
-        memmove(header, header + MPLS_HLEN, len);
-        memcpy(header + len, &lse, sizeof lse);
-    }
-    pkt_metadata_init_conn(&packet->md);
-}
-
-/* If 'packet' is an MPLS packet, removes its outermost MPLS label stack entry.
- * If the label that was removed was the only MPLS label, changes 'packet''s
- * Ethertype to 'ethtype' (which ordinarily should not be an MPLS
- * Ethertype). */
-void
-pop_mpls(struct dp_packet *packet, ovs_be16 ethtype)
-{
-    if (is_mpls(packet)) {
-        struct mpls_hdr *mh = dp_packet_l2_5(packet);
-        size_t len = packet->l2_5_ofs;
-
-        set_ethertype(packet, ethtype);
-        if (get_16aligned_be32(&mh->mpls_lse) & htonl(MPLS_BOS_MASK)) {
-            dp_packet_set_l2_5(packet, NULL);
-        }
-        /* Shift the l2 header forward. */
-        memmove((char*)dp_packet_data(packet) + MPLS_HLEN, dp_packet_data(packet), len);
-        dp_packet_resize_l2_5(packet, -MPLS_HLEN);
-
-        /* Invalidate offload flags as they are not valid after
-         * decapsulation of MPLS header. */
-        dp_packet_reset_offload(packet);
-
-        /* packet_type must be reset for the MPLS packets with no l2 header */
-        if (!len) {
-            if (ethtype == htons(ETH_TYPE_TEB)) {
-                /* The inner packet must be classified as ethernet if the
-                 * ethtype is ETH_TYPE_TEB. */
-                packet->packet_type = htonl(PT_ETH);
-            } else {
-                packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE,
-                                                     ntohs(ethtype));
-            }
-        }
-    }
-}
-
-void
-push_nsh(struct dp_packet *packet, const struct nsh_hdr *nsh_hdr_src)
-{
-    struct nsh_hdr *nsh;
-    size_t length = nsh_hdr_len(nsh_hdr_src);
-    uint8_t next_proto;
-
-    switch (ntohl(packet->packet_type)) {
-        case PT_ETH:
-            next_proto = NSH_P_ETHERNET;
-            break;
-        case PT_IPV4:
-            next_proto = NSH_P_IPV4;
-            break;
-        case PT_IPV6:
-            next_proto = NSH_P_IPV6;
-            break;
-        case PT_NSH:
-            next_proto = NSH_P_NSH;
-            break;
-        default:
-            OVS_NOT_REACHED();
-    }
-
-    nsh = (struct nsh_hdr *) dp_packet_resize_l2(packet, length);
-    memcpy(nsh, nsh_hdr_src, length);
-    nsh->next_proto = next_proto;
-    packet->packet_type = htonl(PT_NSH);
-    dp_packet_reset_offsets(packet);
-    packet->l3_ofs = 0;
-}
-
-bool
-pop_nsh(struct dp_packet *packet)
-{
-    struct nsh_hdr *nsh = (struct nsh_hdr *) dp_packet_l3(packet);
-    size_t length;
-    uint32_t next_pt;
-
-    if (packet->packet_type == htonl(PT_NSH) && nsh) {
-        switch (nsh->next_proto) {
-            case NSH_P_ETHERNET:
-                next_pt = PT_ETH;
-                break;
-            case NSH_P_IPV4:
-                next_pt = PT_IPV4;
-                break;
-            case NSH_P_IPV6:
-                next_pt = PT_IPV6;
-                break;
-            case NSH_P_NSH:
-                next_pt = PT_NSH;
-                break;
-            default:
-                /* Unknown inner packet type. Drop packet. */
-                return false;
-        }
-
-        length = nsh_hdr_len(nsh);
-        dp_packet_reset_packet(packet, length);
-        packet->packet_type = htonl(next_pt);
-        /* Packet must be recirculated for further processing. */
-    }
-    return true;
-}
-
-/* Converts hex digits in 'hex' to an Ethernet packet in '*packetp'.  The
- * caller must free '*packetp'.  On success, returns NULL.  On failure, returns
- * an error message and stores NULL in '*packetp'.
- *
- * Aligns the L3 header of '*packetp' on a 32-bit boundary. */
-const char *
-eth_from_hex(const char *hex, struct dp_packet **packetp)
-{
-    struct dp_packet *packet;
-
-    /* Use 2 bytes of headroom to 32-bit align the L3 header. */
-    packet = *packetp = dp_packet_new_with_headroom(strlen(hex) / 2, 2);
-
-    if (dp_packet_put_hex(packet, hex, NULL)[0] != '\0') {
-        dp_packet_delete(packet);
-        *packetp = NULL;
-        return "Trailing garbage in packet data";
-    }
-
-    if (dp_packet_size(packet) < ETH_HEADER_LEN) {
-        dp_packet_delete(packet);
-        *packetp = NULL;
-        return "Packet data too short for Ethernet";
-    }
-
-    return NULL;
-}
-
-/* Populates 'b' with an Ethernet II packet headed with the given 'eth_dst',
- * 'eth_src' and 'eth_type' parameters.  A payload of 'size' bytes is allocated
- * in 'b' and returned.  This payload may be populated with appropriate
- * information by the caller.  Sets 'b''s 'frame' pointer and 'l3' offset to
- * the Ethernet header and payload respectively.  Aligns b->l3 on a 32-bit
- * boundary.
- *
- * The returned packet has enough headroom to insert an 802.1Q VLAN header if
- * desired. */
-void *
-eth_compose(struct dp_packet *b, const struct eth_addr eth_dst,
-            const struct eth_addr eth_src, uint16_t eth_type,
-            size_t size)
-{
-    void *data;
-    struct eth_header *eth;
-
-
-    dp_packet_clear(b);
-
-    /* The magic 2 here ensures that the L3 header (when it is added later)
-     * will be 32-bit aligned. */
-    dp_packet_prealloc_tailroom(b, 2 + ETH_HEADER_LEN + VLAN_HEADER_LEN + size);
-    dp_packet_reserve(b, 2 + VLAN_HEADER_LEN);
-    eth = dp_packet_put_uninit(b, ETH_HEADER_LEN);
-    data = dp_packet_put_zeros(b, size);
-
-    eth->eth_dst = eth_dst;
-    eth->eth_src = eth_src;
-    eth->eth_type = htons(eth_type);
-
-    b->packet_type = htonl(PT_ETH);
-    dp_packet_set_l3(b, data);
-
-    return data;
-}
-
-void
-packet_set_ipv4_addr(struct dp_packet *packet,
-                     ovs_16aligned_be32 *addr, ovs_be32 new_addr)
-{
-    struct ip_header *nh = dp_packet_l3(packet);
-    ovs_be32 old_addr = get_16aligned_be32(addr);
-    size_t l4_size = dp_packet_l4_size(packet);
-
-    pkt_metadata_init_conn(&packet->md);
-
-    if (nh->ip_proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) {
-        if (dp_packet_l4_checksum_valid(packet)) {
-            dp_packet_l4_checksum_set_partial(packet);
-        } else {
-            struct tcp_header *th = dp_packet_l4(packet);
-            th->tcp_csum = recalc_csum32(th->tcp_csum, old_addr, new_addr);
-        }
-    } else if (nh->ip_proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN ) {
-        if (dp_packet_l4_checksum_valid(packet)) {
-            dp_packet_l4_checksum_set_partial(packet);
-        } else {
-            struct udp_header *uh = dp_packet_l4(packet);
-            if (uh->udp_csum) {
-                uh->udp_csum = recalc_csum32(uh->udp_csum, old_addr, new_addr);
-                if (!uh->udp_csum) {
-                    uh->udp_csum = htons(0xffff);
-                }
-            }
-        }
-    }
-
-    if (dp_packet_ip_checksum_valid(packet)) {
-        dp_packet_ip_checksum_set_partial(packet);
-    } else {
-        nh->ip_csum = recalc_csum32(nh->ip_csum, old_addr, new_addr);
-    }
-    put_16aligned_be32(addr, new_addr);
-}
-
-/* Returns true, if packet contains at least one routing header where
- * segements_left > 0.
- *
- * This function assumes that L3 and L4 offsets are set in the packet. */
-bool
-packet_rh_present(struct dp_packet *packet, uint8_t *nexthdr, bool *first_frag)
-{
-    const struct ovs_16aligned_ip6_hdr *nh;
-    size_t len;
-    size_t remaining;
-    uint8_t *data = dp_packet_l3(packet);
-
-    remaining = packet->l4_ofs - packet->l3_ofs;
-    if (remaining < sizeof *nh) {
-        return false;
-    }
-    nh = ALIGNED_CAST(struct ovs_16aligned_ip6_hdr *, data);
-    data += sizeof *nh;
-    remaining -= sizeof *nh;
-    *nexthdr = nh->ip6_nxt;
-
-    while (1) {
-        if ((*nexthdr != IPPROTO_HOPOPTS)
-                && (*nexthdr != IPPROTO_ROUTING)
-                && (*nexthdr != IPPROTO_DSTOPTS)
-                && (*nexthdr != IPPROTO_AH)
-                && (*nexthdr != IPPROTO_FRAGMENT)) {
-            /* It's either a terminal header (e.g., TCP, UDP) or one we
-             * don't understand.  In either case, we're done with the
-             * packet, so use it to fill in 'nw_proto'. */
-            break;
-        }
-
-        /* We only verify that at least 8 bytes of the next header are
-         * available, but many of these headers are longer.  Ensure that
-         * accesses within the extension header are within those first 8
-         * bytes. All extension headers are required to be at least 8
-         * bytes. */
-        if (remaining < 8) {
-            return false;
-        }
-
-        if (*nexthdr == IPPROTO_AH) {
-            /* A standard AH definition isn't available, but the fields
-             * we care about are in the same location as the generic
-             * option header--only the header length is calculated
-             * differently. */
-            const struct ip6_ext *ext_hdr = (struct ip6_ext *)data;
-
-            *nexthdr = ext_hdr->ip6e_nxt;
-            len = (ext_hdr->ip6e_len + 2) * 4;
-        } else if (*nexthdr == IPPROTO_FRAGMENT) {
-            const struct ovs_16aligned_ip6_frag *frag_hdr
-                = ALIGNED_CAST(struct ovs_16aligned_ip6_frag *, data);
-
-            *first_frag = !(frag_hdr->ip6f_offlg & IP6F_OFF_MASK) &&
-                           (frag_hdr->ip6f_offlg & IP6F_MORE_FRAG);
-            *nexthdr = frag_hdr->ip6f_nxt;
-            len = sizeof *frag_hdr;
-        } else if (*nexthdr == IPPROTO_ROUTING) {
-            const struct ip6_rthdr *rh = (struct ip6_rthdr *)data;
-
-            if (rh->ip6r_segleft > 0) {
-                return true;
-            }
-
-            *nexthdr = rh->ip6r_nxt;
-            len = (rh->ip6r_len + 1) * 8;
-        } else {
-            const struct ip6_ext *ext_hdr = (struct ip6_ext *)data;
-
-            *nexthdr = ext_hdr->ip6e_nxt;
-            len = (ext_hdr->ip6e_len + 1) * 8;
-        }
-
-        if (remaining < len) {
-            return false;
-        }
-        remaining -= len;
-        data += len;
-    }
-
-    return false;
-}
-
-static void
-packet_update_csum128(struct dp_packet *packet, uint8_t proto,
-                      ovs_16aligned_be32 addr[4],
-                      const struct in6_addr *new_addr)
-{
-    size_t l4_size = dp_packet_l4_size(packet);
-
-    if (proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) {
-        if (dp_packet_l4_checksum_valid(packet)) {
-            dp_packet_l4_checksum_set_partial(packet);
-        } else {
-            struct tcp_header *th = dp_packet_l4(packet);
-
-            th->tcp_csum = recalc_csum128(th->tcp_csum, addr, new_addr);
-        }
-    } else if (proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN) {
-        if (dp_packet_l4_checksum_valid(packet)) {
-            dp_packet_l4_checksum_set_partial(packet);
-        } else {
-            struct udp_header *uh = dp_packet_l4(packet);
-
-            if (uh->udp_csum) {
-                uh->udp_csum = recalc_csum128(uh->udp_csum, addr, new_addr);
-                if (!uh->udp_csum) {
-                    uh->udp_csum = htons(0xffff);
-                }
-            }
-        }
-    } else if (proto == IPPROTO_ICMPV6 &&
-               l4_size >= sizeof(struct icmp6_header)) {
-        struct icmp6_header *icmp = dp_packet_l4(packet);
-
-        icmp->icmp6_cksum = recalc_csum128(icmp->icmp6_cksum, addr, new_addr);
-    }
-}
-
-void
-packet_set_ipv6_addr(struct dp_packet *packet, uint8_t proto,
-                     ovs_16aligned_be32 addr[4],
-                     const struct in6_addr *new_addr,
-                     bool recalculate_csum)
-{
-    if (recalculate_csum) {
-        packet_update_csum128(packet, proto, addr, new_addr);
-    }
-    memcpy(addr, new_addr, sizeof(ovs_be32[4]));
-    pkt_metadata_init_conn(&packet->md);
-}
-
-/* Modifies the IPv4 header fields of 'packet' to be consistent with 'src',
- * 'dst', 'tos', and 'ttl'.  Updates 'packet''s L4 checksums as appropriate.
- * 'packet' must contain a valid IPv4 packet with correctly populated l[347]
- * markers. */
-void
-packet_set_ipv4(struct dp_packet *packet, ovs_be32 src, ovs_be32 dst,
-                uint8_t tos, uint8_t ttl)
-{
-    struct ip_header *nh = dp_packet_l3(packet);
-
-    if (get_16aligned_be32(&nh->ip_src) != src) {
-        packet_set_ipv4_addr(packet, &nh->ip_src, src);
-    }
-
-    if (get_16aligned_be32(&nh->ip_dst) != dst) {
-        packet_set_ipv4_addr(packet, &nh->ip_dst, dst);
-    }
-
-    if (nh->ip_tos != tos) {
-        uint8_t *field = &nh->ip_tos;
-
-        if (dp_packet_ip_checksum_valid(packet)) {
-            dp_packet_ip_checksum_set_partial(packet);
-        } else {
-            nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t) *field),
-                                        htons((uint16_t) tos));
-        }
-
-        *field = tos;
-    }
-
-    if (nh->ip_ttl != ttl) {
-        uint8_t *field = &nh->ip_ttl;
-
-        if (dp_packet_ip_checksum_valid(packet)) {
-            dp_packet_ip_checksum_set_partial(packet);
-        } else {
-            nh->ip_csum = recalc_csum16(nh->ip_csum, htons(*field << 8),
-                                        htons(ttl << 8));
-        }
-
-        *field = ttl;
-    }
-}
-
-/* Modifies the IPv6 header fields of 'packet' to be consistent with 'src',
- * 'dst', 'traffic class', and 'next hop'.  Updates 'packet''s L4 checksums as
- * appropriate. 'packet' must contain a valid IPv6 packet with correctly
- * populated l[34] offsets. */
-void
-packet_set_ipv6(struct dp_packet *packet, const struct in6_addr *src,
-                const struct in6_addr *dst, uint8_t key_tc, ovs_be32 key_fl,
-                uint8_t key_hl)
-{
-    struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(packet);
-    bool recalc_csum = true;
-    uint8_t proto = 0;
-    bool rh_present;
-
-    rh_present = packet_rh_present(packet, &proto, &recalc_csum);
-
-    if (memcmp(&nh->ip6_src, src, sizeof(ovs_be32[4]))) {
-        packet_set_ipv6_addr(packet, proto, nh->ip6_src.be32,
-                             src, recalc_csum);
-    }
-
-    if (memcmp(&nh->ip6_dst, dst, sizeof(ovs_be32[4]))) {
-        packet_set_ipv6_addr(packet, proto, nh->ip6_dst.be32, dst,
-                             !rh_present && recalc_csum);
-    }
-
-    ip_set_ipv6_tc(&nh->ip6_flow, key_tc);
-    ip_set_ipv6_flow_label(&nh->ip6_flow, key_fl);
-    nh->ip6_hlim = key_hl;
-}
-
-static void
-packet_set_port(ovs_be16 *port, ovs_be16 new_port, ovs_be16 *csum)
-{
-    if (*port != new_port) {
-        if (csum) {
-            *csum = recalc_csum16(*csum, *port, new_port);
-        }
-        *port = new_port;
-    }
-}
-
-/* Sets the TCP source and destination port ('src' and 'dst' respectively) of
- * the TCP header contained in 'packet'.  'packet' must be a valid TCP packet
- * with its l4 offset properly populated. */
-void
-packet_set_tcp_port(struct dp_packet *packet, ovs_be16 src, ovs_be16 dst)
-{
-    struct tcp_header *th = dp_packet_l4(packet);
-    ovs_be16 *csum = NULL;
-
-    if (dp_packet_l4_checksum_valid(packet)) {
-        dp_packet_l4_checksum_set_partial(packet);
-    } else {
-        csum = &th->tcp_csum;
-    }
-
-    packet_set_port(&th->tcp_src, src, csum);
-    packet_set_port(&th->tcp_dst, dst, csum);
-    pkt_metadata_init_conn(&packet->md);
-}
-
-/* Sets the UDP source and destination port ('src' and 'dst' respectively) of
- * the UDP header contained in 'packet'.  'packet' must be a valid UDP packet
- * with its l4 offset properly populated. */
-void
-packet_set_udp_port(struct dp_packet *packet, ovs_be16 src, ovs_be16 dst)
-{
-    struct udp_header *uh = dp_packet_l4(packet);
-
-    if (dp_packet_l4_checksum_valid(packet)) {
-        dp_packet_l4_checksum_set_partial(packet);
-        packet_set_port(&uh->udp_src, src, NULL);
-        packet_set_port(&uh->udp_dst, dst, NULL);
-    } else {
-        ovs_be16 *csum = uh->udp_csum ? &uh->udp_csum : NULL;
-
-        packet_set_port(&uh->udp_src, src, csum);
-        packet_set_port(&uh->udp_dst, dst, csum);
-
-        if (csum && !uh->udp_csum) {
-            uh->udp_csum = htons(0xffff);
-        }
-    }
-
-    pkt_metadata_init_conn(&packet->md);
-}
-
-/* Sets the SCTP source and destination port ('src' and 'dst' respectively) of
- * the SCTP header contained in 'packet'.  'packet' must be a valid SCTP packet
- * with its l4 offset properly populated. */
-void
-packet_set_sctp_port(struct dp_packet *packet, ovs_be16 src, ovs_be16 dst)
-{
-    struct sctp_header *sh = dp_packet_l4(packet);
-
-    if (dp_packet_l4_checksum_valid(packet)) {
-        dp_packet_l4_checksum_set_partial(packet);
-        sh->sctp_src = src;
-        sh->sctp_dst = dst;
-    } else {
-        ovs_be32 old_csum, old_correct_csum, new_csum;
-        uint16_t tp_len = dp_packet_l4_size(packet);
-
-        old_csum = get_16aligned_be32(&sh->sctp_csum);
-        put_16aligned_be32(&sh->sctp_csum, 0);
-        old_correct_csum = crc32c((void *) sh, tp_len);
-
-        sh->sctp_src = src;
-        sh->sctp_dst = dst;
-
-        new_csum = crc32c((void *) sh, tp_len);
-        put_16aligned_be32(&sh->sctp_csum, old_csum ^ old_correct_csum
-                           ^ new_csum);
-    }
-
-    pkt_metadata_init_conn(&packet->md);
-}
-
-/* Sets the ICMP type and code of the ICMP header contained in 'packet'.
- * 'packet' must be a valid ICMP packet with its l4 offset properly
- * populated. */
-void
-packet_set_icmp(struct dp_packet *packet, uint8_t type, uint8_t code)
-{
-    struct icmp_header *ih = dp_packet_l4(packet);
-    ovs_be16 orig_tc = htons(ih->icmp_type << 8 | ih->icmp_code);
-    ovs_be16 new_tc = htons(type << 8 | code);
-
-    if (orig_tc != new_tc) {
-        ih->icmp_type = type;
-        ih->icmp_code = code;
-
-        ih->icmp_csum = recalc_csum16(ih->icmp_csum, orig_tc, new_tc);
-    }
-    pkt_metadata_init_conn(&packet->md);
-}
-
-/* Sets the IGMP type to IGMP_HOST_MEMBERSHIP_QUERY and populates the
- * v3 query header fields in 'packet'. 'packet' must be a valid IGMPv3
- * query packet with its l4 offset properly populated.
- */
-void
-packet_set_igmp3_query(struct dp_packet *packet, uint8_t max_resp,
-                       ovs_be32 group, bool srs, uint8_t qrv, uint8_t qqic)
-{
-    struct igmpv3_query_header *igh = dp_packet_l4(packet);
-    ovs_be16 orig_type_max_resp =
-        htons(igh->type << 8 | igh->max_resp);
-    ovs_be16 new_type_max_resp =
-        htons(IGMP_HOST_MEMBERSHIP_QUERY << 8 | max_resp);
-
-    if (orig_type_max_resp != new_type_max_resp) {
-        igh->type = IGMP_HOST_MEMBERSHIP_QUERY;
-        igh->max_resp = max_resp;
-        igh->csum = recalc_csum16(igh->csum, orig_type_max_resp,
-                                  new_type_max_resp);
-    }
-
-    ovs_be32 old_group = get_16aligned_be32(&igh->group);
-
-    if (old_group != group) {
-        put_16aligned_be32(&igh->group, group);
-        igh->csum = recalc_csum32(igh->csum, old_group, group);
-    }
-
-    /* See RFC 3376 4.1.6. */
-    if (qrv > 7) {
-        qrv = 0;
-    }
-
-    ovs_be16 orig_srs_qrv_qqic = htons(igh->srs_qrv << 8 | igh->qqic);
-    ovs_be16 new_srs_qrv_qqic = htons(srs << 11 | qrv << 8 | qqic);
-
-    if (orig_srs_qrv_qqic != new_srs_qrv_qqic) {
-        igh->srs_qrv = (srs << 3 | qrv);
-        igh->qqic = qqic;
-        igh->csum = recalc_csum16(igh->csum, orig_srs_qrv_qqic,
-                                  new_srs_qrv_qqic);
-    }
-}
-
-void
-packet_set_nd_ext(struct dp_packet *packet, const ovs_16aligned_be32 rso_flags,
-                  const uint8_t opt_type)
-{
-    struct ovs_nd_msg *ns;
-    struct ovs_nd_lla_opt *opt;
-    int bytes_remain = dp_packet_l4_size(packet);
-    struct ovs_16aligned_ip6_hdr * nh = dp_packet_l3(packet);
-    uint32_t pseudo_hdr_csum = 0;
-
-    if (OVS_UNLIKELY(bytes_remain < sizeof(*ns))) {
-        return;
-    }
-
-    if (nh) {
-        pseudo_hdr_csum = ip_csum_pseudoheader6(nh);
-    }
-
-    ns = dp_packet_l4(packet);
-    opt = &ns->options[0];
-
-    /* set RSO flags and option type */
-    ns->rso_flags = rso_flags;
-    opt->type = opt_type;
-
-    /* recalculate checksum */
-    ovs_be16 *csum_value = &(ns->icmph.icmp6_cksum);
-    *csum_value = 0;
-    *csum_value = csum_finish(csum_continue(pseudo_hdr_csum,
-                              &(ns->icmph), bytes_remain));
-
-}
-
-void
-packet_set_nd(struct dp_packet *packet, const struct in6_addr *target,
-              const struct eth_addr sll, const struct eth_addr tll)
-{
-    struct ovs_nd_msg *ns;
-    struct ovs_nd_lla_opt *opt;
-    int bytes_remain = dp_packet_l4_size(packet);
-
-    if (OVS_UNLIKELY(bytes_remain < sizeof(*ns))) {
-        return;
-    }
-
-    ns = dp_packet_l4(packet);
-    opt = &ns->options[0];
-    bytes_remain -= sizeof(*ns);
-
-    if (memcmp(&ns->target, target, sizeof(ovs_be32[4]))) {
-        packet_set_ipv6_addr(packet, IPPROTO_ICMPV6, ns->target.be32, target,
-                             true);
-    }
-
-    while (bytes_remain >= ND_LLA_OPT_LEN && opt->len != 0
-           && bytes_remain >= (opt->len * ND_LLA_OPT_LEN)) {
-        if (opt->type == ND_OPT_SOURCE_LINKADDR && opt->len == 1) {
-            if (!eth_addr_equals(opt->mac, sll)) {
-                ovs_be16 *csum = &(ns->icmph.icmp6_cksum);
-
-                *csum = recalc_csum48(*csum, opt->mac, sll);
-                opt->mac = sll;
-            }
-
-            /* A packet can only contain one SLL or TLL option */
-            break;
-        } else if (opt->type == ND_OPT_TARGET_LINKADDR && opt->len == 1) {
-            if (!eth_addr_equals(opt->mac, tll)) {
-                ovs_be16 *csum = &(ns->icmph.icmp6_cksum);
-
-                *csum = recalc_csum48(*csum, opt->mac, tll);
-                opt->mac = tll;
-            }
-
-            /* A packet can only contain one SLL or TLL option */
-            break;
-        }
-
-        opt += opt->len;
-        bytes_remain -= opt->len * ND_LLA_OPT_LEN;
-    }
-}
-
-#define ARP_PACKET_SIZE  (2 + ETH_HEADER_LEN + VLAN_HEADER_LEN + \
-                          ARP_ETH_HEADER_LEN)
-
-/* Clears 'b' and replaces its contents by an ARP frame with the specified
- * 'arp_op', 'arp_sha', 'arp_tha', 'arp_spa', and 'arp_tpa'.  The outer
- * Ethernet frame is initialized with Ethernet source 'arp_sha' and destination
- * 'arp_tha', except that destination ff:ff:ff:ff:ff:ff is used instead if
- * 'broadcast' is true.  Points the L3 header to the ARP header. */
-void
-compose_arp(struct dp_packet *b, uint16_t arp_op,
-            const struct eth_addr arp_sha, const struct eth_addr arp_tha,
-            bool broadcast, ovs_be32 arp_spa, ovs_be32 arp_tpa)
-{
-    compose_arp__(b);
-
-    struct eth_header *eth = dp_packet_eth(b);
-    eth->eth_dst = broadcast ? eth_addr_broadcast : arp_tha;
-    eth->eth_src = arp_sha;
-
-    struct arp_eth_header *arp = dp_packet_l3(b);
-    arp->ar_op = htons(arp_op);
-    arp->ar_sha = arp_sha;
-    arp->ar_tha = arp_tha;
-    put_16aligned_be32(&arp->ar_spa, arp_spa);
-    put_16aligned_be32(&arp->ar_tpa, arp_tpa);
-}
-
-/* Clears 'b' and replaces its contents by an ARP frame.  Sets the fields in
- * the Ethernet and ARP headers that are fixed for ARP frames to those fixed
- * values, and zeroes the other fields.  Points the L3 header to the ARP
- * header. */
-void
-compose_arp__(struct dp_packet *b)
-{
-    dp_packet_clear(b);
-    dp_packet_prealloc_tailroom(b, ARP_PACKET_SIZE);
-    dp_packet_reserve(b, 2 + VLAN_HEADER_LEN);
-
-    struct eth_header *eth = dp_packet_put_zeros(b, sizeof *eth);
-    eth->eth_type = htons(ETH_TYPE_ARP);
-
-    struct arp_eth_header *arp = dp_packet_put_zeros(b, sizeof *arp);
-    arp->ar_hrd = htons(ARP_HRD_ETHERNET);
-    arp->ar_pro = htons(ARP_PRO_IP);
-    arp->ar_hln = sizeof arp->ar_sha;
-    arp->ar_pln = sizeof arp->ar_spa;
-
-    dp_packet_set_l3(b, arp);
-
-    b->packet_type = htonl(PT_ETH);
-}
-
-/* This function expects packet with ethernet header with correct
- * l3 pointer set. */
-void *
-compose_ipv6(struct dp_packet *packet, uint8_t proto,
-             const struct in6_addr *src, const struct in6_addr *dst,
-             uint8_t key_tc, ovs_be32 key_fl, uint8_t key_hl, int size)
-{
-    struct ovs_16aligned_ip6_hdr *nh;
-    void *data;
-
-    nh = dp_packet_l3(packet);
-    nh->ip6_vfc = 0x60;
-    nh->ip6_nxt = proto;
-    nh->ip6_plen = htons(size);
-    data = dp_packet_put_zeros(packet, size);
-    dp_packet_set_l4(packet, data);
-    packet_set_ipv6(packet, src, dst, key_tc, key_fl, key_hl);
-    return data;
-}
-
-/* Compose an IPv6 Neighbor Discovery Neighbor Solicitation message. */
-void
-compose_nd_ns(struct dp_packet *b, const struct eth_addr eth_src,
-              const struct in6_addr *ipv6_src, const struct in6_addr *ipv6_dst)
-{
-    struct in6_addr sn_addr;
-    struct eth_addr eth_dst;
-    struct ovs_nd_msg *ns;
-    struct ovs_nd_lla_opt *lla_opt;
-    uint32_t icmp_csum;
-
-    in6_addr_solicited_node(&sn_addr, ipv6_dst);
-    ipv6_multicast_to_ethernet(&eth_dst, &sn_addr);
-
-    eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
-    ns = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, &sn_addr,
-                      0, 0, 255, ND_MSG_LEN + ND_LLA_OPT_LEN);
-
-    ns->icmph.icmp6_type = ND_NEIGHBOR_SOLICIT;
-    ns->icmph.icmp6_code = 0;
-    put_16aligned_be32(&ns->rso_flags, htonl(0));
-
-    lla_opt = &ns->options[0];
-    lla_opt->type = ND_OPT_SOURCE_LINKADDR;
-    lla_opt->len = 1;
-
-    packet_set_nd(b, ipv6_dst, eth_src, eth_addr_zero);
-
-    ns->icmph.icmp6_cksum = 0;
-    icmp_csum = ip_csum_pseudoheader6(dp_packet_l3(b));
-    ns->icmph.icmp6_cksum = csum_finish(
-        csum_continue(icmp_csum, ns, ND_MSG_LEN + ND_LLA_OPT_LEN));
-}
-
-/* Compose an IPv6 Neighbor Discovery Neighbor Advertisement message. */
-void
-compose_nd_na(struct dp_packet *b,
-              const struct eth_addr eth_src, const struct eth_addr eth_dst,
-              const struct in6_addr *ipv6_src, const struct in6_addr *ipv6_dst,
-              ovs_be32 rso_flags)
-{
-    struct ovs_nd_msg *na;
-    struct ovs_nd_lla_opt *lla_opt;
-    uint32_t icmp_csum;
-
-    eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
-    na = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, ipv6_dst,
-                      0, 0, 255, ND_MSG_LEN + ND_LLA_OPT_LEN);
-
-    na->icmph.icmp6_type = ND_NEIGHBOR_ADVERT;
-    na->icmph.icmp6_code = 0;
-    put_16aligned_be32(&na->rso_flags, rso_flags);
-
-    lla_opt = &na->options[0];
-    lla_opt->type = ND_OPT_TARGET_LINKADDR;
-    lla_opt->len = 1;
-
-    packet_set_nd(b, ipv6_src, eth_addr_zero, eth_src);
-
-    na->icmph.icmp6_cksum = 0;
-    icmp_csum = ip_csum_pseudoheader6(dp_packet_l3(b));
-    na->icmph.icmp6_cksum = csum_finish(csum_continue(
-        icmp_csum, na, ND_MSG_LEN + ND_LLA_OPT_LEN));
-}
-
-/* Compose an IPv6 Neighbor Discovery Router Advertisement message with
- * Source Link-layer Address Option and MTU Option.
- * Caller can call packet_put_ra_prefix_opt to append Prefix Information
- * Options to composed messags in 'b'. */
-void
-compose_nd_ra(struct dp_packet *b,
-              const struct eth_addr eth_src, const struct eth_addr eth_dst,
-              const struct in6_addr *ipv6_src, const struct in6_addr *ipv6_dst,
-              uint8_t cur_hop_limit, uint8_t mo_flags,
-              ovs_be16 router_lt, ovs_be32 reachable_time,
-              ovs_be32 retrans_timer, uint32_t mtu)
-{
-    /* Don't compose Router Advertisement packet with MTU Option if mtu
-     * value is 0. */
-    bool with_mtu = mtu != 0;
-    size_t mtu_opt_len = with_mtu ? ND_MTU_OPT_LEN : 0;
-
-    eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
-
-    struct ovs_ra_msg *ra = compose_ipv6(
-        b, IPPROTO_ICMPV6, ipv6_src, ipv6_dst, 0, 0, 255,
-        RA_MSG_LEN + ND_LLA_OPT_LEN + mtu_opt_len);
-    ra->icmph.icmp6_type = ND_ROUTER_ADVERT;
-    ra->icmph.icmp6_code = 0;
-    ra->cur_hop_limit = cur_hop_limit;
-    ra->mo_flags = mo_flags;
-    ra->router_lifetime = router_lt;
-    ra->reachable_time = reachable_time;
-    ra->retrans_timer = retrans_timer;
-
-    struct ovs_nd_lla_opt *lla_opt = ra->options;
-    lla_opt->type = ND_OPT_SOURCE_LINKADDR;
-    lla_opt->len = 1;
-    lla_opt->mac = eth_src;
-
-    if (with_mtu) {
-        /* ovs_nd_mtu_opt has the same size with ovs_nd_lla_opt. */
-        struct ovs_nd_mtu_opt *mtu_opt
-            = (struct ovs_nd_mtu_opt *)(lla_opt + 1);
-        mtu_opt->type = ND_OPT_MTU;
-        mtu_opt->len = 1;
-        mtu_opt->reserved = 0;
-        put_16aligned_be32(&mtu_opt->mtu, htonl(mtu));
-    }
-
-    ra->icmph.icmp6_cksum = 0;
-    uint32_t icmp_csum = ip_csum_pseudoheader6(dp_packet_l3(b));
-    ra->icmph.icmp6_cksum = csum_finish(csum_continue(
-        icmp_csum, ra, RA_MSG_LEN + ND_LLA_OPT_LEN + mtu_opt_len));
-}
-
-/* Append an IPv6 Neighbor Discovery Prefix Information option to a
- * Router Advertisement message. */
-void
-packet_put_ra_prefix_opt(struct dp_packet *b,
-                         uint8_t plen, uint8_t la_flags,
-                         ovs_be32 valid_lifetime, ovs_be32 preferred_lifetime,
-                         const ovs_be128 prefix)
-{
-    size_t prev_l4_size = dp_packet_l4_size(b);
-    struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(b);
-    nh->ip6_plen = htons(prev_l4_size + ND_PREFIX_OPT_LEN);
-
-    struct ovs_nd_prefix_opt *prefix_opt =
-        dp_packet_put_uninit(b, sizeof *prefix_opt);
-    prefix_opt->type = ND_OPT_PREFIX_INFORMATION;
-    prefix_opt->len = 4;
-    prefix_opt->prefix_len = plen;
-    prefix_opt->la_flags = la_flags;
-    put_16aligned_be32(&prefix_opt->valid_lifetime, valid_lifetime);
-    put_16aligned_be32(&prefix_opt->preferred_lifetime, preferred_lifetime);
-    put_16aligned_be32(&prefix_opt->reserved, 0);
-    memcpy(prefix_opt->prefix.be32, prefix.be32, sizeof(ovs_be32[4]));
-
-    struct ovs_ra_msg *ra = dp_packet_l4(b);
-    ra->icmph.icmp6_cksum = 0;
-    uint32_t icmp_csum = ip_csum_pseudoheader6(dp_packet_l3(b));
-    ra->icmph.icmp6_cksum = csum_finish(csum_continue(
-        icmp_csum, ra, prev_l4_size + ND_PREFIX_OPT_LEN));
-}
-
-void
-IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6)
-{
-    if (is_ipv6) {
-        ovs_16aligned_be32 *ip6 = dp_packet_l3(pkt);
-
-        put_16aligned_be32(ip6, get_16aligned_be32(ip6) |
-                                htonl(IP_ECN_CE << 20));
-    } else {
-        struct ip_header *nh = dp_packet_l3(pkt);
-        uint8_t tos = nh->ip_tos;
-
-        tos |= IP_ECN_CE;
-        if (nh->ip_tos != tos) {
-            if (dp_packet_ip_checksum_valid(pkt)) {
-                dp_packet_ip_checksum_set_partial(pkt);
-            } else {
-                nh->ip_csum = recalc_csum16(nh->ip_csum, htons(nh->ip_tos),
-                                            htons((uint16_t) tos));
-            }
-
-            nh->ip_tos = tos;
-        }
-    }
-}
-
-/* Set TCP checksum field in packet 'p' with complete checksum.
- * The packet must have the L3 and L4 offsets. */
-void
-packet_tcp_complete_csum(struct dp_packet *p, bool inner)
-{
-    struct tcp_header *tcp;
-    size_t tcp_sz;
-    void *ip_hdr;
-
-    if (inner) {
-        tcp = dp_packet_inner_l4(p);
-        ip_hdr = dp_packet_inner_l3(p);
-        tcp_sz = dp_packet_inner_l4_size(p);
-    } else {
-        tcp = dp_packet_l4(p);
-        ip_hdr = dp_packet_l3(p);
-        tcp_sz = dp_packet_l4_size(p);
-    }
-
-    ovs_assert(tcp);
-    ovs_assert(ip_hdr);
-
-    tcp->tcp_csum = 0;
-    if (IP_VER(((const struct ip_header *) ip_hdr)->ip_ihl_ver) == 4) {
-        struct ip_header *ip = ip_hdr;
-
-        tcp->tcp_csum = csum_finish(csum_continue(ip_csum_pseudoheader(ip),
-                                                  tcp, tcp_sz));
-    } else {
-        struct ovs_16aligned_ip6_hdr *ip6 = ip_hdr;
-
-        tcp->tcp_csum = ip_csum_upperlayer6(ip6, tcp, ip6->ip6_nxt,
-                                                tcp_sz);
-    }
-
-    if (inner) {
-        dp_packet_inner_l4_checksum_set_good(p);
-    } else {
-        dp_packet_l4_checksum_set_good(p);
-    }
-}
-
-/* Set UDP checksum field in packet 'p' with complete checksum.
- * The packet must have the L3 and L4 offsets. */
-void
-packet_udp_complete_csum(struct dp_packet *p, bool inner)
-{
-    struct udp_header *udp;
-    size_t udp_sz;
-    void *ip_hdr;
-
-    if (inner) {
-        udp = dp_packet_inner_l4(p);
-        ip_hdr = dp_packet_inner_l3(p);
-        udp_sz = dp_packet_inner_l4_size(p);
-    } else {
-        udp = dp_packet_l4(p);
-        ip_hdr = dp_packet_l3(p);
-        udp_sz = dp_packet_l4_size(p);
-    }
-
-    ovs_assert(udp);
-    ovs_assert(ip_hdr);
-
-    /* Skip csum calculation if the udp_csum is zero. */
-    if (!udp->udp_csum) {
-        goto out;
-    }
-
-    udp->udp_csum = 0;
-    if (IP_VER(((const struct ip_header *) ip_hdr)->ip_ihl_ver) == 4) {
-        struct ip_header *ip = ip_hdr;
-
-        udp->udp_csum = csum_finish(csum_continue(ip_csum_pseudoheader(ip),
-                                                  udp, udp_sz));
-    } else {
-        struct ovs_16aligned_ip6_hdr *ip6 = ip_hdr;
-
-        udp->udp_csum = ip_csum_upperlayer6(ip6, udp, ip6->ip6_nxt,
-                                                udp_sz);
-    }
-
-    if (!udp->udp_csum) {
-        udp->udp_csum = htons(0xffff);
-    }
-
-out:
-    if (inner) {
-        dp_packet_inner_l4_checksum_set_good(p);
-    } else {
-        dp_packet_l4_checksum_set_good(p);
-    }
-}
-
-/* This helper computes a "constant" UDP checksum without looking at the
- * L4 payload.
- *
- * This is possible when L4 is either TCP or UDP: the L4 payload checksum
- * is either computed in SW or in HW later, but its contribution to the
- * outer checksum is cancelled by the L4 payload being part of the global
- * packet sum. */
-bool
-packet_udp_tunnel_csum(struct dp_packet *p)
-{
-    struct ip_header *inner_ip;
-    const void *inner_l4_data;
-    char *after_inner_l4_csum;
-    size_t inner_l4_csum_off;
-    struct udp_header *udp;
-    ovs_be16 inner_l4_csum;
-    uint32_t partial_csum;
-    struct ip_header *ip;
-    uint32_t inner_csum;
-    uint16_t tso_segsz;
-    bool inner_ipv4;
-    void *inner_l4;
-
-    inner_ip = dp_packet_inner_l3(p);
-    inner_l4 = dp_packet_inner_l4(p);
-    ip = dp_packet_l3(p);
-    udp = dp_packet_l4(p);
-
-    if (dp_packet_inner_l4_proto_tcp(p)) {
-        inner_l4_csum_off = offsetof(struct tcp_header, tcp_csum);
-        inner_l4_data = dp_packet_get_inner_tcp_payload(p);
-        if (!inner_l4_data) {
-            /* Malformed packet. */
-            return false;
-        }
-    } else if (dp_packet_inner_l4_proto_udp(p)) {
-        inner_l4_csum_off = offsetof(struct udp_header, udp_csum);
-        inner_l4_data = (char *) inner_l4 + sizeof (struct udp_header);
-        if (((struct udp_header *) inner_l4)->udp_csum == 0) {
-            /* There is no nested checksum.
-             * No choice but compute a full checksum. */
-            return false;
-        }
-    } else {
-        /* This optimisation applies only to inner TCP/UDP. */
-        return false;
-    }
-
-    if (!dp_packet_inner_l4_checksum_valid(p)) {
-        /* We have no idea about the contribution of the payload data
-         * and what the L4 checksum put in the packet data looks like.
-         * Simpler is to let a full checksum happen. */
-        return false;
-    }
-
-    inner_ipv4 = IP_VER(inner_ip->ip_ihl_ver) == 4;
-    if (inner_ipv4) {
-        inner_csum = ip_csum_pseudoheader(inner_ip);
-    } else {
-        struct ovs_16aligned_ip6_hdr *inner_ip6 = dp_packet_inner_l3(p);
-
-        inner_csum = ip_csum_pseudoheader6(inner_ip6);
-    }
-
-    inner_csum = csum_continue(inner_csum, inner_l4, inner_l4_csum_off);
-    after_inner_l4_csum = (char *) inner_l4 + inner_l4_csum_off + 2;
-    inner_l4_csum = csum_finish(csum_continue(inner_csum, after_inner_l4_csum,
-        (char *) inner_l4_data - after_inner_l4_csum));
-    /* Important: for inner UDP, a null inner_l4_csum here should in theory be
-     * replaced with 0xffff.  However, since the only use of inner_l4_csum is
-     * for the final outer checksum with a csum_add16() below, we can skip this
-     * entirely because adding 0xffff will have the same effect as adding 0x0
-     * after reducing in csum_finish. */
-
-    udp->udp_csum = 0;
-    if (IP_VER(ip->ip_ihl_ver) == 4) {
-        partial_csum = ip_csum_pseudoheader(ip);
-    } else {
-        struct ovs_16aligned_ip6_hdr *ip6 = dp_packet_l3(p);
-
-        partial_csum = ip_csum_pseudoheader6(ip6);
-    }
-
-    partial_csum = csum_continue(partial_csum, udp,
-        (char *) inner_ip - (char *) udp);
-    if (!inner_ipv4 || !dp_packet_inner_ip_checksum_valid(p)) {
-        /* IPv6 has no checksum, so for inner IPv6, we need to sum the header.
-         *
-         * In IPv4 case, if inner checksum is already good or HW offload
-         * has been requested, the (final) sum of the IPv4 header will be 0.
-         * Otherwise, we need to sum the header like for IPv6. */
-        partial_csum = csum_continue(partial_csum, inner_ip,
-            (char *) inner_l4 - (char *) inner_ip);
-    }
-    partial_csum = csum_continue(partial_csum, inner_l4, inner_l4_csum_off);
-    partial_csum = csum_add16(partial_csum, inner_l4_csum);
-    partial_csum = csum_continue(partial_csum, after_inner_l4_csum,
-        (char *) inner_l4_data - after_inner_l4_csum);
-    udp->udp_csum = csum_finish(partial_csum);
-    tso_segsz = dp_packet_get_tso_segsz(p);
-    if (tso_segsz) {
-        uint16_t payload_len = dp_packet_get_inner_tcp_payload_length(p);
-
-        ovs_assert(payload_len == tso_segsz * dp_packet_gso_nr_segs(p));
-
-        /* The pseudo header used in the outer UDP checksum is dependent on
-         * the ip_tot_len / ip6_plen which was a reflection of the TSO frame
-         * size. The segmented packet will be shorter. */
-        udp->udp_csum = recalc_csum16(udp->udp_csum, htons(payload_len),
-                                      htons(tso_segsz));
-
-        /* When segmenting the packet, various headers get updated:
-         * - inner L3
-         *   - for IPv4, ip_tot_len is updated, BUT it is not affecting the
-         *     outer UDP checksum because the IPv4 header itself contains
-         *     a checksum that compensates for this update,
-         *   - for IPv6, ip6_plen is updated, and this must be considered,
-         * - inner L4
-         *   - inner pseudo header used in the TCP checksum is dependent on
-         *     the inner ip_tot_len / ip6_plen,
-         *   - TCP seq number is updated,
-         *   - the HW may change some TCP flags (think PSH/FIN),
-         *   BUT the TCP checksum will compensate for those updates,
-         *
-         * Summary: we only care about the inner IPv6 header update.
-         */
-        if (IP_VER(inner_ip->ip_ihl_ver) != 4) {
-            udp->udp_csum = recalc_csum16(udp->udp_csum, htons(payload_len),
-                                          htons(tso_segsz));
-        }
-    }
-    if (!udp->udp_csum) {
-        udp->udp_csum = htons(0xffff);
-    }
-    dp_packet_l4_checksum_set_good(p);
-
-    return true;
-}
-
-/* Set SCTP checksum field in packet 'p' with complete checksum.
- * The packet must have the L3 and L4 offsets. */
-void
-packet_sctp_complete_csum(struct dp_packet *p, bool inner)
-{
-    struct sctp_header *sh;
-    uint16_t tp_len;
-    ovs_be32 csum;
-
-    if (inner) {
-        sh = dp_packet_inner_l4(p);
-        tp_len = dp_packet_inner_l4_size(p);
-    } else {
-        sh = dp_packet_l4(p);
-        tp_len = dp_packet_l4_size(p);
-    }
-
-    ovs_assert(sh);
-
-    put_16aligned_be32(&sh->sctp_csum, 0);
-    csum = crc32c((void *) sh, tp_len);
-    put_16aligned_be32(&sh->sctp_csum, csum);
-
-    if (inner) {
-        dp_packet_inner_l4_checksum_set_good(p);
-    } else {
-        dp_packet_l4_checksum_set_good(p);
-    }
-}
diff --git a/lib/packets.h b/lib/packets.h
deleted file mode 100644
index fe23b2eff2..0000000000
--- a/lib/packets.h
+++ /dev/null
@@ -1,282 +0,0 @@ 
-/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef PACKETS_H
-#define PACKETS_H 1
-
-#include <inttypes.h>
-#include <sys/types.h>
-#include <stdint.h>
-#include <string.h>
-#include "compiler.h"
-#include "openvswitch/geneve.h"
-#include "openvswitch/packets.h"
-#include "openvswitch/types.h"
-#include "net-proto.h"
-#include "openvswitch/nsh.h"
-#include "odp-netlink.h"
-#include "random.h"
-#include "hash.h"
-#include "tun-metadata.h"
-#include "unaligned.h"
-#include "util.h"
-#include "timeval.h"
-
-struct dp_packet;
-struct conn;
-struct ds;
-
-/* Purely internal to OVS userspace. These flags should never be exposed to
- * the outside world and so aren't included in the flags mask. */
-
-/* Tunnel information is in userspace datapath format. */
-#define FLOW_TNL_F_UDPIF (1 << 4)
-
-static inline bool
-flow_tnl_dst_is_set(const struct flow_tnl *tnl)
-{
-    return tnl->ip_dst || ipv6_addr_is_set(&tnl->ipv6_dst);
-}
-
-static inline bool
-flow_tnl_src_is_set(const struct flow_tnl *tnl)
-{
-    return tnl->ip_src || ipv6_addr_is_set(&tnl->ipv6_src);
-}
-
-struct in6_addr flow_tnl_dst(const struct flow_tnl *tnl);
-struct in6_addr flow_tnl_src(const struct flow_tnl *tnl);
-
-/* Returns an offset to 'src' covering all the meaningful fields in 'src'. */
-static inline size_t
-flow_tnl_size(const struct flow_tnl *src)
-{
-    if (!flow_tnl_dst_is_set(src)) {
-        /* Covers ip_dst and ipv6_dst only. */
-        return offsetof(struct flow_tnl, ip_src);
-    }
-    if (src->flags & FLOW_TNL_F_UDPIF) {
-        /* Datapath format, cover all options we have. */
-        return offsetof(struct flow_tnl, metadata.opts)
-            + src->metadata.present.len;
-    }
-    if (!src->metadata.present.map) {
-        /* No TLVs, opts is irrelevant. */
-        return offsetof(struct flow_tnl, metadata.opts);
-    }
-    /* Have decoded TLVs, opts is relevant. */
-    return sizeof *src;
-}
-
-/* Copy flow_tnl, but avoid copying unused portions of tun_metadata.  Unused
- * data in 'dst' is NOT cleared, so this must not be used in cases where the
- * uninitialized portion may be hashed over. */
-static inline void
-flow_tnl_copy__(struct flow_tnl *dst, const struct flow_tnl *src)
-{
-    memcpy(dst, src, flow_tnl_size(src));
-}
-
-/* Datapath packet metadata */
-struct pkt_metadata {
-PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline0,
-    uint32_t recirc_id;         /* Recirculation id carried with the
-                                   recirculating packets. 0 for packets
-                                   received from the wire. */
-    uint32_t dp_hash;           /* hash value computed by the recirculation
-                                   action. */
-    uint32_t skb_priority;      /* Packet priority for QoS. */
-    uint32_t pkt_mark;          /* Packet mark. */
-    uint8_t  ct_state;          /* Connection state. */
-    bool ct_orig_tuple_ipv6;
-    uint16_t ct_zone;           /* Connection zone. */
-    uint32_t ct_mark;           /* Connection mark. */
-    ovs_u128 ct_label;          /* Connection label. */
-    union flow_in_port in_port; /* Input port. */
-    odp_port_t orig_in_port;    /* Originating in_port for tunneled packets */
-    struct conn *conn;          /* Cached conntrack connection. */
-    bool reply;                 /* True if reply direction. */
-    bool icmp_related;          /* True if ICMP related. */
-);
-
-PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline1,
-    union {                     /* Populated only for non-zero 'ct_state'. */
-        struct ovs_key_ct_tuple_ipv4 ipv4;
-        struct ovs_key_ct_tuple_ipv6 ipv6;   /* Used only if                */
-    } ct_orig_tuple;                         /* 'ct_orig_tuple_ipv6' is set */
-);
-
-PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline2,
-    struct flow_tnl tunnel;     /* Encapsulating tunnel parameters. Note that
-                                 * if 'ip_dst' == 0, the rest of the fields may
-                                 * be uninitialized. */
-);
-};
-
-BUILD_ASSERT_DECL(offsetof(struct pkt_metadata, cacheline0) == 0);
-BUILD_ASSERT_DECL(offsetof(struct pkt_metadata, cacheline1) ==
-                  CACHE_LINE_SIZE);
-BUILD_ASSERT_DECL(offsetof(struct pkt_metadata, cacheline2) ==
-                  2 * CACHE_LINE_SIZE);
-
-static inline void
-pkt_metadata_init_tnl(struct pkt_metadata *md)
-{
-    odp_port_t orig_in_port;
-
-    /* Zero up through the tunnel metadata options. The length and table
-     * are before this and as long as they are empty, the options won't
-     * be looked at. Keep the orig_in_port field. */
-    orig_in_port = md->in_port.odp_port;
-    memset(md, 0, offsetof(struct pkt_metadata, tunnel.metadata.opts));
-    md->orig_in_port = orig_in_port;
-}
-
-static inline void
-pkt_metadata_init_conn(struct pkt_metadata *md)
-{
-    md->conn = NULL;
-}
-
-static inline void
-pkt_metadata_init(struct pkt_metadata *md, odp_port_t port)
-{
-    /* This is called for every packet in userspace datapath and affects
-     * performance if all the metadata is initialized. Hence, fields should
-     * only be zeroed out when necessary.
-     *
-     * Initialize only till ct_state. Once the ct_state is zeroed out rest
-     * of ct fields will not be looked at unless ct_state != 0.
-     */
-    memset(md, 0, offsetof(struct pkt_metadata, ct_orig_tuple_ipv6));
-
-    /* It can be expensive to zero out all of the tunnel metadata. However,
-     * we can just zero out ip_dst and the rest of the data will never be
-     * looked at. */
-    md->tunnel.ip_dst = 0;
-    md->tunnel.ipv6_dst = in6addr_any;
-    md->in_port.odp_port = port;
-    md->orig_in_port = port;
-    md->conn = NULL;
-}
-
-/* This function prefetches the cachelines touched by pkt_metadata_init()
- * and pkt_metadata_init_tnl().  For performance reasons the two functions
- * should be kept in sync. */
-static inline void
-pkt_metadata_prefetch_init(struct pkt_metadata *md)
-{
-    /* Prefetch cacheline0 as members till ct_state and odp_port will
-     * be initialized later in pkt_metadata_init(). */
-    OVS_PREFETCH(md->cacheline0);
-
-    /* Prefetch cacheline1 as members of this cacheline will be zeroed out
-     * in pkt_metadata_init_tnl(). */
-    OVS_PREFETCH(md->cacheline1);
-
-    /* Prefetch cachline2 as ip_dst & ipv6_dst fields will be initialized. */
-    OVS_PREFETCH(md->cacheline2);
-}
-
-void compose_rarp(struct dp_packet *, const struct eth_addr);
-
-void eth_push_vlan(struct dp_packet *, ovs_be16 tpid, ovs_be16 tci);
-void eth_pop_vlan(struct dp_packet *);
-
-const char *eth_from_hex(const char *hex, struct dp_packet **packetp);
-
-void set_mpls_lse(struct dp_packet *, ovs_be32 label);
-void push_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse);
-void pop_mpls(struct dp_packet *, ovs_be16 ethtype);
-void add_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse,
-              bool l3_encap);
-
-
-void push_eth(struct dp_packet *packet, const struct eth_addr *dst,
-              const struct eth_addr *src);
-void pop_eth(struct dp_packet *packet);
-
-void push_nsh(struct dp_packet *packet, const struct nsh_hdr *nsh_hdr_src);
-bool pop_nsh(struct dp_packet *packet);
-
-void *eth_compose(struct dp_packet *, const struct eth_addr eth_dst,
-                  const struct eth_addr eth_src, uint16_t eth_type,
-                  size_t size);
-void *snap_compose(struct dp_packet *, const struct eth_addr eth_dst,
-                   const struct eth_addr eth_src,
-                   unsigned int oui, uint16_t snap_type, size_t size);
-void packet_set_ipv4(struct dp_packet *, ovs_be32 src, ovs_be32 dst, uint8_t tos,
-                     uint8_t ttl);
-void packet_set_ipv4_addr(struct dp_packet *packet, ovs_16aligned_be32 *addr,
-                          ovs_be32 new_addr);
-void packet_set_ipv6(struct dp_packet *, const struct in6_addr *src,
-                     const struct in6_addr *dst, uint8_t tc,
-                     ovs_be32 fl, uint8_t hlmit);
-void packet_set_ipv6_addr(struct dp_packet *packet, uint8_t proto,
-                          ovs_16aligned_be32 addr[4],
-                          const struct in6_addr *new_addr,
-                          bool recalculate_csum);
-void packet_set_tcp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
-void packet_set_udp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
-void packet_set_sctp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
-void packet_set_icmp(struct dp_packet *, uint8_t type, uint8_t code);
-void packet_set_nd(struct dp_packet *, const struct in6_addr *target,
-                   const struct eth_addr sll, const struct eth_addr tll);
-void packet_set_nd_ext(struct dp_packet *packet,
-                       const ovs_16aligned_be32 rso_flags,
-                       const uint8_t opt_type);
-void packet_set_igmp3_query(struct dp_packet *, uint8_t max_resp,
-                            ovs_be32 group, bool srs, uint8_t qrv,
-                            uint8_t qqic);
-void *compose_ipv6(struct dp_packet *packet, uint8_t proto,
-                   const struct in6_addr *src, const struct in6_addr *dst,
-                   uint8_t key_tc, ovs_be32 key_fl, uint8_t key_hl, int size);
-void compose_arp__(struct dp_packet *);
-void compose_arp(struct dp_packet *, uint16_t arp_op,
-                 const struct eth_addr arp_sha,
-                 const struct eth_addr arp_tha, bool broadcast,
-                 ovs_be32 arp_spa, ovs_be32 arp_tpa);
-void compose_nd_ns(struct dp_packet *, const struct eth_addr eth_src,
-                   const struct in6_addr *ipv6_src,
-                   const struct in6_addr *ipv6_dst);
-void compose_nd_na(struct dp_packet *, const struct eth_addr eth_src,
-                   const struct eth_addr eth_dst,
-                   const struct in6_addr *ipv6_src,
-                   const struct in6_addr *ipv6_dst,
-                   ovs_be32 rso_flags);
-void compose_nd_ra(struct dp_packet *,
-                   const struct eth_addr eth_src,
-                   const struct eth_addr eth_dst,
-                   const struct in6_addr *ipv6_src,
-                   const struct in6_addr *ipv6_dst,
-                   uint8_t cur_hop_limit, uint8_t mo_flags,
-                   ovs_be16 router_lt, ovs_be32 reachable_time,
-                   ovs_be32 retrans_timer, uint32_t mtu);
-void packet_put_ra_prefix_opt(struct dp_packet *,
-                              uint8_t plen, uint8_t la_flags,
-                              ovs_be32 valid_lifetime,
-                              ovs_be32 preferred_lifetime,
-                              const ovs_be128 router_prefix);
-bool packet_rh_present(struct dp_packet *packet, uint8_t *nexthdr,
-                       bool *first_frag);
-void IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6);
-void packet_tcp_complete_csum(struct dp_packet *, bool is_inner);
-void packet_udp_complete_csum(struct dp_packet *, bool is_inner);
-bool packet_udp_tunnel_csum(struct dp_packet *);
-void packet_sctp_complete_csum(struct dp_packet *, bool is_inner);
-
-
-#endif /* packets.h */
diff --git a/lib/pcap-file.c b/lib/pcap-file.c
index 8e4d6b3ddd..ed7bede414 100644
--- a/lib/pcap-file.c
+++ b/lib/pcap-file.c
@@ -26,7 +26,6 @@ 
 #include "dp-packet.h"
 #include "flow.h"
 #include "openvswitch/hmap.h"
-#include "packets.h"
 #include "timeval.h"
 #include "unaligned.h"
 #include "util.h"
diff --git a/lib/route-table-bsd.c b/lib/route-table-bsd.c
index 34d42cfab7..c551d08726 100644
--- a/lib/route-table-bsd.c
+++ b/lib/route-table-bsd.c
@@ -31,8 +31,8 @@ 
 #include <string.h>
 #include <unistd.h>
 
+#include "net-proto.h"
 #include "ovs-router.h"
-#include "packets.h"
 #include "openvswitch/vlog.h"
 #include "util.h"
 
diff --git a/lib/route-table.c b/lib/route-table.c
index 2a13a5cc7d..62884b8430 100644
--- a/lib/route-table.c
+++ b/lib/route-table.c
@@ -36,7 +36,6 @@ 
 #include "openvswitch/list.h"
 #include "openvswitch/ofpbuf.h"
 #include "ovs-router.h"
-#include "packets.h"
 #include "rtnetlink.h"
 #include "tnl-ports.h"
 #include "openvswitch/vlog.h"
diff --git a/lib/rstp-common.h b/lib/rstp-common.h
index 7948842f4d..382147e425 100644
--- a/lib/rstp-common.h
+++ b/lib/rstp-common.h
@@ -36,7 +36,6 @@ 
 #include "openvswitch/hmap.h"
 #include "openvswitch/list.h"
 #include "ovs-atomic.h"
-#include "packets.h"
 
 enum admin_port_state {
     RSTP_ADMIN_BRIDGE_PORT_STATE_DISABLED = 0,
diff --git a/lib/rstp-state-machines.c b/lib/rstp-state-machines.c
index 7bd1f80c41..ce97de008d 100644
--- a/lib/rstp-state-machines.c
+++ b/lib/rstp-state-machines.c
@@ -40,7 +40,6 @@ 
 #include "connectivity.h"
 #include "openvswitch/ofpbuf.h"
 #include "dp-packet.h"
-#include "packets.h"
 #include "seq.h"
 #include "unixctl.h"
 #include "util.h"
diff --git a/lib/rstp.c b/lib/rstp.c
index 90e8094599..4dfeb54990 100644
--- a/lib/rstp.c
+++ b/lib/rstp.c
@@ -42,7 +42,6 @@ 
 #include "openvswitch/ofpbuf.h"
 #include "ofproto/ofproto.h"
 #include "dp-packet.h"
-#include "packets.h"
 #include "seq.h"
 #include "unixctl.h"
 #include "util.h"
diff --git a/lib/rtnetlink.c b/lib/rtnetlink.c
index 37078d00e1..942aada804 100644
--- a/lib/rtnetlink.c
+++ b/lib/rtnetlink.c
@@ -24,8 +24,8 @@ 
 
 #include "netlink.h"
 #include "netlink-notifier.h"
+#include "net-proto.h"
 #include "openvswitch/ofpbuf.h"
-#include "packets.h"
 
 #if IFLA_INFO_MAX < 5
 #define IFLA_INFO_SLAVE_KIND 4
diff --git a/lib/smap.c b/lib/smap.c
index 122adca271..5071625cd8 100644
--- a/lib/smap.c
+++ b/lib/smap.c
@@ -19,7 +19,7 @@ 
 
 #include "hash.h"
 #include "openvswitch/json.h"
-#include "packets.h"
+#include "net-proto.h"
 #include "util.h"
 #include "uuid.h"
 
diff --git a/lib/socket-util.c b/lib/socket-util.c
index c569b7d166..4fb1615119 100644
--- a/lib/socket-util.c
+++ b/lib/socket-util.c
@@ -36,8 +36,8 @@ 
 #include <sys/un.h>
 #include <unistd.h>
 #include "openvswitch/dynamic-string.h"
+#include "net-proto.h"
 #include "ovs-thread.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "util.h"
 #include "openvswitch/vlog.h"
diff --git a/lib/stp.c b/lib/stp.c
index f37337992a..034004b438 100644
--- a/lib/stp.c
+++ b/lib/stp.c
@@ -30,7 +30,6 @@ 
 #include "openvswitch/ofpbuf.h"
 #include "ovs-atomic.h"
 #include "dp-packet.h"
-#include "packets.h"
 #include "seq.h"
 #include "unixctl.h"
 #include "util.h"
diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c
index c8eb26b2a9..e01ccacd6f 100644
--- a/lib/stream-ssl.c
+++ b/lib/stream-ssl.c
@@ -36,9 +36,9 @@ 
 #include "coverage.h"
 #include "openvswitch/dynamic-string.h"
 #include "entropy.h"
+#include "net-proto.h"
 #include "openvswitch/ofpbuf.h"
 #include "openflow/openflow.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "openvswitch/shash.h"
 #include "socket-util.h"
diff --git a/lib/stream-tcp.c b/lib/stream-tcp.c
index e8dc2bfaa2..aa2096cb36 100644
--- a/lib/stream-tcp.c
+++ b/lib/stream-tcp.c
@@ -26,7 +26,6 @@ 
 #include <sys/socket.h>
 #include <unistd.h>
 #include "openvswitch/dynamic-string.h"
-#include "packets.h"
 #include "socket-util.h"
 #include "util.h"
 #include "stream-provider.h"
diff --git a/lib/stream-unix.c b/lib/stream-unix.c
index d265efb83a..007a2821f2 100644
--- a/lib/stream-unix.c
+++ b/lib/stream-unix.c
@@ -27,7 +27,6 @@ 
 #include <string.h>
 #include <unistd.h>
 #include "ovs-atomic.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "socket-util.h"
 #include "dirs.h"
diff --git a/lib/stream.c b/lib/stream.c
index feaa1cb2d1..62d245f65b 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -35,7 +35,6 @@ 
 #include "openvswitch/vlog.h"
 #include "ovs-replay.h"
 #include "ovs-thread.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "random.h"
 #include "socket-util.h"
diff --git a/lib/tc.c b/lib/tc.c
index 4a9c6c2676..16a982dc56 100644
--- a/lib/tc.c
+++ b/lib/tc.c
@@ -43,7 +43,6 @@ 
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/util.h"
 #include "openvswitch/vlog.h"
-#include "packets.h"
 #include "timeval.h"
 #include "unaligned.h"
 
diff --git a/lib/tnl-neigh-cache.c b/lib/tnl-neigh-cache.c
index bdff1debc8..1cd79bdc9f 100644
--- a/lib/tnl-neigh-cache.c
+++ b/lib/tnl-neigh-cache.c
@@ -34,7 +34,6 @@ 
 #include "netdev.h"
 #include "ovs-atomic.h"
 #include "ovs-thread.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "seq.h"
 #include "socket-util.h"
diff --git a/lib/tnl-neigh-cache.h b/lib/tnl-neigh-cache.h
index 877bca3127..6a55caeba4 100644
--- a/lib/tnl-neigh-cache.h
+++ b/lib/tnl-neigh-cache.h
@@ -28,7 +28,6 @@ 
 
 #include "flow.h"
 #include "netdev.h"
-#include "packets.h"
 #include "util.h"
 
 int tnl_neigh_snoop(const struct flow *flow, struct flow_wildcards *wc,
diff --git a/lib/tnl-ports.h b/lib/tnl-ports.h
index 61ca0f8e26..f5da4c266a 100644
--- a/lib/tnl-ports.h
+++ b/lib/tnl-ports.h
@@ -21,7 +21,6 @@ 
 #include <sys/socket.h>
 
 #include "flow.h"
-#include "packets.h"
 #include "util.h"
 
 odp_port_t tnl_port_map_lookup(struct flow *flow, struct flow_wildcards *wc);
diff --git a/lib/tun-metadata.c b/lib/tun-metadata.c
index af0bcbde8d..a98bed5c5d 100644
--- a/lib/tun-metadata.c
+++ b/lib/tun-metadata.c
@@ -26,7 +26,6 @@ 
 #include "odp-netlink.h"
 #include "openvswitch/ofp-match.h"
 #include "ovs-rcu.h"
-#include "packets.h"
 #include "tun-metadata.h"
 #include "util.h"
 
diff --git a/lib/vconn.c b/lib/vconn.c
index 040955d675..8051598fe1 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -36,7 +36,6 @@ 
 #include "openvswitch/ofp-util.h"
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "random.h"
 #include "util.h"
diff --git a/ofproto/bond.c b/ofproto/bond.c
index ef481a3604..a0130d7a41 100644
--- a/ofproto/bond.c
+++ b/ofproto/bond.c
@@ -40,7 +40,6 @@ 
 #include "openvswitch/ofp-actions.h"
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "seq.h"
 #include "openvswitch/shash.h"
diff --git a/ofproto/bond.h b/ofproto/bond.h
index 3aa5c640de..8c9623d4c6 100644
--- a/ofproto/bond.h
+++ b/ofproto/bond.h
@@ -20,7 +20,6 @@ 
 #include <stdbool.h>
 #include <stdint.h>
 #include "ofproto-provider.h"
-#include "packets.h"
 
 struct flow;
 struct netdev;
diff --git a/ofproto/in-band.c b/ofproto/in-band.c
index 3992251f5f..03e6c2e079 100644
--- a/ofproto/in-band.c
+++ b/ofproto/in-band.c
@@ -37,7 +37,6 @@ 
 #include "openvswitch/ofp-actions.h"
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "timeval.h"
 
diff --git a/ofproto/netflow.c b/ofproto/netflow.c
index aad9f9c77a..17c9514c33 100644
--- a/ofproto/netflow.c
+++ b/ofproto/netflow.c
@@ -30,7 +30,6 @@ 
 #include "openvswitch/ofpbuf.h"
 #include "ofproto.h"
 #include "ofproto/netflow.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "socket-util.h"
 #include "timeval.h"
diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
index 1f561b3bc7..7da6646888 100644
--- a/ofproto/ofproto-dpif-ipfix.c
+++ b/ofproto/ofproto-dpif-ipfix.c
@@ -29,7 +29,6 @@ 
 #include "ofproto.h"
 #include "ofproto-dpif.h"
 #include "dp-packet.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "sset.h"
 #include "util.h"
diff --git a/ofproto/ofproto-dpif-monitor.h b/ofproto/ofproto-dpif-monitor.h
index 7d6d0da876..8763810dba 100644
--- a/ofproto/ofproto-dpif-monitor.h
+++ b/ofproto/ofproto-dpif-monitor.h
@@ -18,7 +18,6 @@ 
 #include <stdint.h>
 
 #include "openflow/openflow.h"
-#include "packets.h"
 
 struct bfd;
 struct cfm;
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index e043d7cbc8..7beee20c25 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -31,7 +31,6 @@ 
 #include "netlink.h"
 #include "openvswitch/ofpbuf.h"
 #include "ofproto.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "ovs-router.h"
 #include "route-table.h"
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 8e4897202b..6c00e41290 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -38,7 +38,6 @@ 
 #include "ofproto-dpif-xlate-cache.h"
 #include "ofproto-dpif-trace.h"
 #include "ovs-rcu.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "seq.h"
 #include "tunnel.h"
diff --git a/ofproto/ofproto-dpif-xlate-cache.c b/ofproto/ofproto-dpif-xlate-cache.c
index c6d935cf0a..cf76279a6d 100644
--- a/ofproto/ofproto-dpif-xlate-cache.c
+++ b/ofproto/ofproto-dpif-xlate-cache.c
@@ -42,7 +42,6 @@ 
 #include "openvswitch/dynamic-string.h"
 #include "openvswitch/vlog.h"
 #include "ovs-router.h"
-#include "packets.h"
 #include "tnl-neigh-cache.h"
 #include "util.h"
 
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 7a29b9bd86..2ebee82dd2 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -61,7 +61,6 @@ 
 #include "openvswitch/vlog.h"
 #include "ovs-lldp.h"
 #include "ovs-router.h"
-#include "packets.h"
 #include "tnl-neigh-cache.h"
 #include "tnl-ports.h"
 #include "tunnel.h"
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index ec6d60a44f..1c335808c5 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -53,7 +53,6 @@ 
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
 #include "ovs-rcu.h"
-#include "packets.h"
 #include "pinsched.h"
 #include "openvswitch/poll-loop.h"
 #include "random.h"
diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
index d8a289548a..0e78a57fcc 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -26,7 +26,6 @@ 
 #include "netdev.h"
 #include "odp-util.h"
 #include "openvswitch/ofpbuf.h"
-#include "packets.h"
 #include "route-table.h"
 #include "seq.h"
 #include "smap.h"
diff --git a/tests/test-classifier.c b/tests/test-classifier.c
index 6ac276d2e0..7f66a6d9ad 100644
--- a/tests/test-classifier.c
+++ b/tests/test-classifier.c
@@ -35,13 +35,13 @@ 
 #include "byte-order.h"
 #include "classifier-private.h"
 #include "command-line.h"
+#include "openvswitch/dynamic-string.h"
 #include "fatal-signal.h"
 #include "flow.h"
 #include "openvswitch/vlog.h"
 #include "ovstest.h"
 #include "ovs-atomic.h"
 #include "ovs-thread.h"
-#include "packets.h"
 #include "random.h"
 #include "timeval.h"
 #include "unaligned.h"
diff --git a/tests/test-conntrack.c b/tests/test-conntrack.c
index dc8d6cff94..eebef0279d 100644
--- a/tests/test-conntrack.c
+++ b/tests/test-conntrack.c
@@ -18,6 +18,7 @@ 
 #include "conntrack.h"
 
 #include "dp-packet.h"
+#include "openvswitch/dynamic-string.h"
 #include "fatal-signal.h"
 #include "flow.h"
 #include "netdev.h"
diff --git a/tests/test-csum.c b/tests/test-csum.c
index 9f8511d810..974c0b33ee 100644
--- a/tests/test-csum.c
+++ b/tests/test-csum.c
@@ -26,8 +26,8 @@ 
 #include <stdlib.h>
 #include <string.h>
 #include "crc32c.h"
+#include "net-proto.h"
 #include "ovstest.h"
-#include "packets.h"
 #include "random.h"
 #include "unaligned.h"
 #include "util.h"
diff --git a/tests/test-lib-route-table.c b/tests/test-lib-route-table.c
index f99f056c8d..df79c9df03 100644
--- a/tests/test-lib-route-table.c
+++ b/tests/test-lib-route-table.c
@@ -18,13 +18,14 @@ 
 
 #undef NDEBUG
 
+#include <inttypes.h>
 #include <linux/rtnetlink.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 #include "netlink-notifier.h"
+#include "net-proto.h"
 #include "ovstest.h"
-#include "packets.h"
 #include "route-table.h"
 
 /* The following definition should be available in Linux 6.15 and might be
diff --git a/tests/test-netflow.c b/tests/test-netflow.c
index 7c23cff147..c03f3d06b2 100644
--- a/tests/test-netflow.c
+++ b/tests/test-netflow.c
@@ -25,9 +25,9 @@ 
 #include "command-line.h"
 #include "daemon.h"
 #include "openvswitch/dynamic-string.h"
+#include "net-proto.h"
 #include "openvswitch/ofpbuf.h"
 #include "ovstest.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "socket-util.h"
 #include "unixctl.h"
diff --git a/tests/test-netlink-conntrack.c b/tests/test-netlink-conntrack.c
index 2a62615b25..95bacf4a88 100644
--- a/tests/test-netlink-conntrack.c
+++ b/tests/test-netlink-conntrack.c
@@ -19,7 +19,9 @@ 
 #include <stdlib.h>
 #include <linux/netfilter/nfnetlink.h>
 
+#include "net-proto.h"
 #include "ct-dpif.h"
+#include "netlink.h"
 #include "netlink-conntrack.h"
 #include "netlink-notifier.h"
 #include "ovstest.h"
diff --git a/tests/test-packets.c b/tests/test-packets.c
index 6151c633c3..8b9f9f4325 100644
--- a/tests/test-packets.c
+++ b/tests/test-packets.c
@@ -16,11 +16,11 @@ 
 
 #include <config.h>
 #undef NDEBUG
-#include "packets.h"
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "net-proto.h"
 #include "ovstest.h"
 
 static void
diff --git a/tests/test-rstp.c b/tests/test-rstp.c
index 707ee3a6c8..4a9f567fb6 100644
--- a/tests/test-rstp.c
+++ b/tests/test-rstp.c
@@ -10,7 +10,6 @@ 
 #include "openvswitch/ofpbuf.h"
 #include "ovstest.h"
 #include "dp-packet.h"
-#include "packets.h"
 #include "openvswitch/vlog.h"
 
 #define MAX_PORTS 10
diff --git a/tests/test-sflow.c b/tests/test-sflow.c
index 3c617bdd16..03fac29f62 100644
--- a/tests/test-sflow.c
+++ b/tests/test-sflow.c
@@ -30,9 +30,9 @@ 
 #include "command-line.h"
 #include "daemon.h"
 #include "openvswitch/dynamic-string.h"
+#include "net-proto.h"
 #include "openvswitch/ofpbuf.h"
 #include "ovstest.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "socket-util.h"
 #include "unixctl.h"
diff --git a/tests/test-stp.c b/tests/test-stp.c
index c85c99d673..7c2f03a46c 100644
--- a/tests/test-stp.c
+++ b/tests/test-stp.c
@@ -26,7 +26,6 @@ 
 #include "dp-packet.h"
 #include "openvswitch/ofpbuf.h"
 #include "ovstest.h"
-#include "packets.h"
 #include "openvswitch/vlog.h"
 
 struct bpdu {
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index ba3458e55a..8aa5f7141b 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -66,7 +66,6 @@ 
 #include "openvswitch/shash.h"
 #include "openvswitch/vconn.h"
 #include "openvswitch/vlog.h"
-#include "packets.h"
 #include "pcap-file.h"
 #include "openvswitch/poll-loop.h"
 #include "random.h"
@@ -74,6 +73,7 @@ 
 #include "stream-ssl.h"
 #include "socket-util.h"
 #include "timeval.h"
+#include "tun-metadata.h"
 #include "unixctl.h"
 #include "util.h"
 
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 7a68e19ac3..d3c4bee245 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -52,7 +52,6 @@ 
 #include "openvswitch/vlog.h"
 #include "ovs-lldp.h"
 #include "ovs-numa.h"
-#include "packets.h"
 #include "openvswitch/poll-loop.h"
 #include "seq.h"
 #include "sflow_api.h"