diff --git a/acinclude.m4 b/acinclude.m4
index bb0d90a..a599607 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -265,6 +265,20 @@ AC_DEFUN([OVS_CHECK_DPDK], [
   AM_CONDITIONAL([DPDK_NETDEV], test "$DPDKLIB_FOUND" = true)
 ])

+AC_DEFUN([OVS_CHECK_P4], [
+  AC_ARG_VAR([p4inputfile], [Specify the p4 input file])
+  AS_IF([test -z "$p4inputfile"],
+        [AC_MSG_ERROR([missing arguments for p4 input file])])
+  AS_IF([test ! -e "$p4inputfile"],
+        [AC_MSG_ERROR([p4 input file does not exist])])
+
+  export PYTHONPATH="${PYTHONPATH}:include/p4/plugin"
+  rm -rf include/p4/src/datapath include/p4/src/include include/p4/src/lib include/p4/src/ofproto
+  p4c-behavioral $p4inputfile --gen-dir include/p4/src/temp --plugin-path include/p4/plugin --plugin ovs
+  mv include/p4/src/temp/plugin/ovs/* include/p4/src/
+  rm -rf include/p4/src/temp
+])
+
 dnl OVS_GREP_IFELSE(FILE, REGEX, [IF-MATCH], [IF-NO-MATCH])
 dnl
 dnl Greps FILE for REGEX.  If it matches, runs IF-MATCH, otherwise IF-NO-MATCH.
diff --git a/build-aux/extract-ofp-actions b/build-aux/extract-ofp-actions
index 3a72349..10510c4 100755
--- a/build-aux/extract-ofp-actions
+++ b/build-aux/extract-ofp-actions
@@ -268,8 +268,8 @@ def extract_ofp_actions(fn, definitions):
             assert v["arg_len"] == versions[0]["arg_len"]
             assert v["base_argtype"] == versions[0]["base_argtype"]
             if (v["min_length"] != versions[0]["min_length"] or
-                v["arg_ofs"] != versions[0]["arg_ofs"] or
-                v["type"] != versions[0]["type"]):
+                        v["arg_ofs"] != versions[0]["arg_ofs"] or
+                        v["type"] != versions[0]["type"]):
                 need_ofp_version = True
         base_argtype = versions[0]["base_argtype"]

diff --git a/build-aux/extract-ofp-fields b/build-aux/extract-ofp-fields
index 8d43e4b..c904ec6 100755
--- a/build-aux/extract-ofp-fields
+++ b/build-aux/extract-ofp-fields
@@ -1,5 +1,6 @@
 #! /usr/bin/python

+import getopt
 import sys
 import os.path
 import re
@@ -22,6 +23,10 @@ TYPES = {"u8":       (1,   False),
          "be128":    (16,  False),
          "tunnelMD": (124, True)}

+# @P4:
+for i in xrange(128):
+    TYPES["be"+str(8*i)] = (i, False)
+
 FORMATTING = {"decimal":            ("MFS_DECIMAL",      1,   8),
               "hexadecimal":        ("MFS_HEXADECIMAL",  1, 127),
               "ct state":           ("MFS_CT_STATE",     4,   4),
@@ -118,8 +123,9 @@ def usage():
     argv0 = os.path.basename(sys.argv[0])
     print('''\
 %(argv0)s, for extracting OpenFlow field properties from meta-flow.h
-usage: %(argv0)s INPUT [--meta-flow | --nx-match]
-  where INPUT points to lib/meta-flow.h in the source directory.
+usage: %(argv0)s [--meta-flow | --nx-match] INPUT...
+  where the first INPUT points to lib/meta-flow.h in the source directory
+        and additional INPUTs may point elsewhere.
 Depending on the option given, the output written to stdout is intended to be
 saved either as lib/meta-flow.inc or lib/nx-match.inc for the respective C
 file to #include.\
@@ -389,29 +395,32 @@ def make_nx_match(fields):
     print("};")
     return output

-
-def extract_ofp_fields(mode):
+# @P4:
+def extract_ofp_fields(search_start_enum):
     global line

     fields = []

-    while True:
-        get_line()
-        if re.match('enum.*mf_field_id', line):
-            break
+    # @P4:
+    if search_start_enum:
+        while True:
+            get_line()
+            if re.match('enum.*mf_field_id', line):
+                break

     while True:
         get_line()
         first_line_number = line_number
         here = '%s:%d' % (file_name, line_number)
-        if (line.startswith('/*')
+        # @P4:
+        if re.match('}', line) or re.match('(\s+)(// )?MFF_N_IDS', line):
+            break
+        elif (line.startswith('/*')
             or line.startswith(' *')
             or line.startswith('#')
             or not line
             or line.isspace()):
             continue
-        elif re.match('}', line) or re.match('\s+MFF_N_IDS', line):
-            break

         # Parse the comment preceding an MFF_ constant into 'comment',
         # one line to an array element.
@@ -495,6 +504,49 @@ def extract_ofp_fields(mode):
     if n_errors:
         sys.exit(1)

+    # @P4:
+    return fields
+
+
+if __name__ == '__main__':
+    try:
+        options, args = getopt.gnu_getopt(sys.argv[1:], 'h',
+                                          ['help', 'meta-flow', 'nx-match'])
+    except getopt.GetoptError, geo:
+        sys.stderr.write("%s: %s\n" % (argv0, geo.msg))
+        sys.exit(1)
+
+    mode = None
+    for key, value in options:
+        if key in ['-h', '--help']:
+            usage()
+        elif key in ['--meta-flow', '--nx-match']:
+            mode = key
+        else:
+            sys.stderr.write('key="%s"\n' % key)
+    if mode is None:
+        sys.stderr.write("either --meta-flow or --nx-match is required; "
+                         "use --help for help\n")
+        sys.exit(1)
+
+    if not args:
+        sys.stderr.write("at least one nonoption argument is required; "
+                         "use --help for help\n")
+        sys.exit(1)
+
+    global file_name
+    global input_file
+    global line_number
+
+    fields = []
+
+    search_start_enum = True
+    for file_name in args:
+        input_file = open(file_name)
+        line_number = 0
+        fields += extract_ofp_fields(search_start_enum)
+        search_start_enum = False
+
     print("""\
 /* Generated automatically; do not modify!    "-*- buffer-read-only: t -*- */
 """)
@@ -506,26 +558,5 @@ def extract_ofp_fields(mode):
     else:
         assert False

-    return output
-
-
-if __name__ == '__main__':
-    if '--help' in sys.argv:
-        usage()
-    elif len(sys.argv) != 3:
-        sys.stderr.write("exactly two arguments required; "
-                         "use --help for help\n")
-        sys.exit(1)
-    elif sys.argv[2] in ('--meta-flow', '--nx-match'):
-        global file_name
-        global input_file
-        global line_number
-        file_name = sys.argv[1]
-        input_file = open(file_name)
-        line_number = 0
-
-        for oline in extract_ofp_fields(sys.argv[2]):
-            print(oline)
-    else:
-        sys.stderr.write("invalid arguments; use --help for help\n")
-        sys.exit(1)
+    for oline in output:
+        print(oline)
diff --git a/configure.ac b/configure.ac
index 05d80d5..e0babbd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -168,6 +168,7 @@ AC_ARG_VAR(KARCH, [Kernel Architecture String])
 AC_SUBST(KARCH)
 OVS_CHECK_LINUX
 OVS_CHECK_DPDK
+OVS_CHECK_P4
 OVS_CHECK_PRAGMA_MESSAGE
 AC_SUBST([OVS_CFLAGS])
 AC_SUBST([OVS_LDFLAGS])
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index f1e80db..8b0e15f 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -43,6 +43,9 @@
 #include <linux/types.h>
 #include <linux/if_ether.h>

+// @P4:
+#include "p4/src/datapath/linux/compat/include/linux/openvswitch.h.h"
+
 /**
  * struct ovs_header - header for OVS Generic Netlink messages.
  * @dp_ifindex: ifindex of local port for datapath (0 to make a request not
@@ -359,6 +362,10 @@ enum ovs_key_attr {
 	/* Only used within kernel data path. */
 	OVS_KEY_ATTR_TUNNEL_INFO,  /* struct ovs_tunnel_info */
 #endif
+
+	// @P4:
+	OVS_KEY_ATTRS
+
 	__OVS_KEY_ATTR_MAX
 };

diff --git a/include/automake.mk b/include/automake.mk
index 6a4cf86..9e6cfa5 100644
--- a/include/automake.mk
+++ b/include/automake.mk
@@ -10,3 +10,4 @@ include include/openflow/automake.mk
 include include/openvswitch/automake.mk
 include include/sparse/automake.mk
 include include/windows/automake.mk
+include include/p4/automake.mk
diff --git a/include/openvswitch/flow.h b/include/openvswitch/flow.h
index 03d406b..c0a768f 100644
--- a/include/openvswitch/flow.h
+++ b/include/openvswitch/flow.h
@@ -20,6 +20,9 @@
 #include "openvswitch/packets.h"
 #include "openvswitch/util.h"

+// @P4:
+#include "p4/src/include/openvswitch/flow.h.h"
+
 /* This sequence number should be incremented whenever anything involving flows
  * or the wildcarding of flows changes.  This will cause build assertion
  * failures in places which likely need to be updated. */
@@ -121,12 +124,17 @@ struct flow {
     ovs_be16 tp_dst;            /* TCP/UDP/SCTP destination port/ICMP code. */
     ovs_be32 igmp_group_ip4;    /* IGMP group IPv4 address.
                                  * Keep last for BUILD_ASSERT_DECL below. */
+
+    // @P4:
+    OVS_FIELDS
 };
 BUILD_ASSERT_DECL(sizeof(struct flow) % sizeof(uint64_t) == 0);
 BUILD_ASSERT_DECL(sizeof(struct flow_tnl) % sizeof(uint64_t) == 0);

 #define FLOW_U64S (sizeof(struct flow) / sizeof(uint64_t))

+// @P4:
+// TODO: update the assertion logic for FLOW_WC_SEQ.
 /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
 BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t)
                   == sizeof(struct flow_tnl) + 216
diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
index 84a0946..c2fedb5 100644
--- a/include/openvswitch/meta-flow.h
+++ b/include/openvswitch/meta-flow.h
@@ -1720,6 +1720,8 @@ enum OVS_PACKED_ENUM mf_field_id {
      */
     MFF_ND_TLL,

+#include "p4/src/include/openvswitch/meta-flow.h.h" // @P4:
+
     MFF_N_IDS
 };

@@ -1902,6 +1904,9 @@ union mf_value {
     ovs_be32 be32;
     ovs_be16 be16;
     uint8_t u8;
+
+    // @P4:
+    uint8_t data[128];
 };
 BUILD_ASSERT_DECL(sizeof(union mf_value) == 128);
 BUILD_ASSERT_DECL(sizeof(union mf_value) >= TLV_MAX_OPT_SIZE);
diff --git a/include/openvswitch/packets.h b/include/openvswitch/packets.h
index 5d97309..dba0dd3 100644
--- a/include/openvswitch/packets.h
+++ b/include/openvswitch/packets.h
@@ -20,6 +20,9 @@
 #include <netinet/in.h>
 #include "openvswitch/tun-metadata.h"

+// @P4:
+#include "p4/src/include/openvswitch/packets.h.h"
+
 /* Tunnel information used in flow key and metadata. */
 struct flow_tnl {
     ovs_be32 ip_dst;
diff --git a/include/openvswitch/types.h b/include/openvswitch/types.h
index bc94145..c661d5c 100644
--- a/include/openvswitch/types.h
+++ b/include/openvswitch/types.h
@@ -21,6 +21,9 @@
 #include <stdint.h>
 #include "openvswitch/compiler.h"

+// @P4:
+#include "p4/src/include/openvswitch/types.h.h"
+
 #ifdef __CHECKER__
 #define OVS_BITWISE __attribute__((bitwise))
 #define OVS_FORCE __attribute__((force))
diff --git a/include/p4/automake.mk b/include/p4/automake.mk
new file mode 100644
index 0000000..66b8a5e
--- /dev/null
+++ b/include/p4/automake.mk
@@ -0,0 +1,20 @@
+EXTRA_DIST += \
+	include/p4/examples/l2-switch.p4 \
+	include/p4/examples/simple-router.p4 \
+	include/p4/plugin/ovs/datapath/linux/compat/include/linux/openvswitch.h.h \
+	include/p4/plugin/ovs/include/openvswitch/flow.h.h \
+	include/p4/plugin/ovs/include/openvswitch/meta-flow.h.h \
+	include/p4/plugin/ovs/include/openvswitch/packets.h.h \
+	include/p4/plugin/ovs/include/openvswitch/types.h.h \
+	include/p4/plugin/ovs/lib/dp-packet.h.h \
+	include/p4/plugin/ovs/lib/flow.c.h \
+	include/p4/plugin/ovs/lib/match.c.h \
+	include/p4/plugin/ovs/lib/meta-flow.c.h \
+	include/p4/plugin/ovs/lib/nx-match.c.h \
+	include/p4/plugin/ovs/lib/odp-execute.c.h \
+	include/p4/plugin/ovs/lib/odp-util.c.h \
+	include/p4/plugin/ovs/lib/packets.c.h \
+	include/p4/plugin/ovs/lib/packets.h.h \
+	include/p4/plugin/ovs/ofproto/ofproto-dpif-sflow.c.h \
+	include/p4/plugin/helpers.py \
+	include/p4/src/README.md
diff --git a/include/p4/examples/l2-switch.p4 b/include/p4/examples/l2-switch.p4
new file mode 100644
index 0000000..43d61fb
--- /dev/null
+++ b/include/p4/examples/l2-switch.p4
@@ -0,0 +1,89 @@
+header_type ethernet_t {
+    fields {
+        dstAddr : 48;
+        srcAddr : 48;
+        etherType : 16;
+    }
+}
+
+header_type intrinsic_metadata_t {
+    fields {
+        mcast_grp : 4;
+        egress_rid : 4;
+        mcast_hash : 16;
+        lf_field_list: 32;
+    }
+}
+
+parser start {
+    return parse_ethernet;
+}
+
+header ethernet_t ethernet_;
+metadata intrinsic_metadata_t intrinsic_metadata;
+
+parser parse_ethernet {
+    extract(ethernet_);
+    return ingress;
+}
+
+action _drop() {
+    drop();
+}
+
+action _nop() {
+}
+
+#define MAC_LEARN_RECEIVER 1024
+
+field_list mac_learn_digest {
+    ethernet_.srcAddr;
+    standard_metadata.ingress_port;
+}
+
+action mac_learn() {
+    generate_digest(MAC_LEARN_RECEIVER, mac_learn_digest);
+}
+
+table smac {
+    reads {
+        ethernet_.srcAddr : exact;
+    }
+    actions {mac_learn; _nop;}
+    size : 512;
+}
+
+action forward(port) {
+    modify_field(standard_metadata.egress_spec, port);
+}
+
+action broadcast() {
+    modify_field(intrinsic_metadata.mcast_grp, 1);
+}
+
+table dmac {
+    reads {
+        ethernet_.dstAddr : exact;
+    }
+    actions {forward; broadcast;}
+    size : 512;
+}
+
+table mcast_src_pruning {
+    reads {
+        standard_metadata.instance_type : exact;
+    }
+    actions {_nop; _drop;}
+    size : 1;
+}
+
+control ingress {
+    apply(smac);
+    apply(dmac);
+}
+
+control egress {
+    if(standard_metadata.ingress_port == standard_metadata.egress_port) {
+        apply(mcast_src_pruning);
+    }
+}
diff --git a/include/p4/examples/simple-router.p4 b/include/p4/examples/simple-router.p4
new file mode 100644
index 0000000..2c62d8a
--- /dev/null
+++ b/include/p4/examples/simple-router.p4
@@ -0,0 +1,143 @@
+
+header_type ethernet_t {
+    fields {
+        dstAddr : 48;
+        srcAddr : 48;
+        etherType : 16;
+    }
+}
+
+header_type ipv4_t {
+    fields {
+        version : 4;
+        ihl : 4;
+        diffserv : 8;
+        totalLen : 16;
+        identification : 16;
+        flags : 3;
+        fragOffset : 13;
+        ttl : 8;
+        protocol : 8;
+        hdrChecksum : 16;
+        srcAddr : 32;
+        dstAddr: 32;
+    }
+}
+
+parser start {
+    return parse_ethernet;
+}
+
+#define ETHERTYPE_IPV4 0x0800
+
+header ethernet_t ethernet_;
+
+parser parse_ethernet {
+    extract(ethernet_);
+    return select(latest.etherType) {
+        ETHERTYPE_IPV4 : parse_ipv4;
+        default: ingress;
+    }
+}
+
+header ipv4_t ipv4_;
+
+field_list ipv4_checksum_list {
+        ipv4_.version;
+        ipv4_.ihl;
+        ipv4_.diffserv;
+        ipv4_.totalLen;
+        ipv4_.identification;
+        ipv4_.flags;
+        ipv4_.fragOffset;
+        ipv4_.ttl;
+        ipv4_.protocol;
+        ipv4_.srcAddr;
+        ipv4_.dstAddr;
+}
+
+field_list_calculation ipv4_checksum {
+    input {
+        ipv4_checksum_list;
+    }
+    algorithm : csum16;
+    output_width : 16;
+}
+
+calculated_field ipv4_.hdrChecksum  {
+    verify ipv4_checksum;
+    update ipv4_checksum;
+}
+
+parser parse_ipv4 {
+    extract(ipv4_);
+    return ingress;
+}
+
+action _drop() {
+    drop();
+}
+
+header_type routing_metadata_t {
+    fields {
+        nhop_ipv4 : 32;
+    }
+}
+
+metadata routing_metadata_t routing_metadata;
+
+action set_nhop(nhop_ipv4, port) {
+    modify_field(routing_metadata.nhop_ipv4, nhop_ipv4);
+    modify_field(standard_metadata.egress_spec, port);
+    add_to_field(ipv4_.ttl, -1);
+}
+
+table ipv4_lpm {
+    reads {
+        ipv4_.dstAddr : lpm;
+    }
+    actions {
+        set_nhop;
+        _drop;
+    }
+    size: 1024;
+}
+
+action set_dmac(dmac) {
+    modify_field(ethernet_.dstAddr, dmac);
+}
+
+table forward {
+    reads {
+        routing_metadata.nhop_ipv4 : exact;
+    }
+    actions {
+        set_dmac;
+        _drop;
+    }
+    size: 512;
+}
+
+action rewrite_mac(smac) {
+    modify_field(ethernet_.srcAddr, smac);
+}
+
+table send_frame {
+    reads {
+        standard_metadata.egress_port: exact;
+    }
+    actions {
+        rewrite_mac;
+        _drop;
+    }
+    size: 256;
+}
+
+control ingress {
+    apply(ipv4_lpm);
+    apply(forward);
+}
+
+control egress {
+    apply(send_frame);
+}
diff --git a/include/p4/plugin/helpers.py b/include/p4/plugin/helpers.py
new file mode 100644
index 0000000..8ad4bfd
--- /dev/null
+++ b/include/p4/plugin/helpers.py
@@ -0,0 +1,91 @@
+
+import math
+ceil = math.ceil
+
+
+def byte_array_to_int(byte_array):
+    result = 0
+    length = len(byte_array)
+    for i in xrange(length):
+        result += byte_array[length - 1 - i] << (8 * i)
+    return result
+
+
+hton_postfix = {8: "", 16: "htons", 32: "htonl", 64: "htonll"}
+key_id_ofs = {8: 4, 16: 4, 32: 4, 64: 8}
+std_type = {8: "uint8_t", 16: "ovs_be16", 32: "ovs_be32", 64: "ovs_be64"}
+std_type_prefix = {8: "u8", 16: "be16", 32: "be32", 64: "be64"}
+
+
+def get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual):
+    return [header_name for header_name in ordered_header_instances_non_virtual
+            if header_name != "standard_metadata" and header_name != "intrinsic_metadata"]
+
+
+def get_ordered_header_instances_metadata(ordered_header_instances_metadata):
+    return [header_name for header_name in ordered_header_instances_metadata
+            if header_name != "standard_metadata" and header_name != "intrinsic_metadata"]
+
+def get_align_field_info(field_info, header_info, ordered_header_instances_all):
+    aligned_field_info = {}
+    for header_name in ordered_header_instances_all:
+        header = header_info[header_name]
+        field_names = []
+        run_bit_width = 0
+        for field_name in header['fields']:
+            bit_width = field_info[field_name]['bit_width']
+            run_bit_width += bit_width
+            if run_bit_width % 8 == 0:
+                if field_names:
+                    # We are assuming that smaller fields (i.e., less than a byte)
+                    # combine together to align on a byte boundary.
+                    if run_bit_width <= 1024:
+                        field_names += [field_name]
+                        total_bit_width = sum([field_info[f]['bit_width'] for f in field_names])
+                        trunc_field_names = [f[len(header_name) + 1:] for f in field_names]
+                        aligned_field_name = header_name + '_' + reduce(lambda x, y: x + '_' + y, trunc_field_names)
+                        run_bit_width = 0
+                        field_names.reverse()
+                        for field_name in field_names:
+                            bit_width = field_info[field_name]['bit_width']
+                            # TODO: this may break for fields greater than 64 bits, look into this!
+                            mask = (2 ** bit_width - 1) << run_bit_width
+                            aligned_field_info[field_name] = {"name": aligned_field_name,
+                                                              "bit_width": total_bit_width,
+                                                              "mask": mask,
+                                                              "bit_offset_hdr": run_bit_width}
+                            run_bit_width += bit_width
+                    else:
+                        # The aligned field's size is larger than 1024 (something isn't right!)
+                        assert(False)
+                else:
+                    aligned_field_name = header_name + '_' + field_name[len(header_name) + 1:]
+                    aligned_field_info[field_name] = {"name": aligned_field_name,
+                                                      "bit_width": bit_width,
+                                                      "mask": 0,
+                                                      "bit_offset_hdr": 0}
+                run_bit_width = 0
+                field_names = []
+            else:
+                field_names += [field_name]
+    return aligned_field_info
+
+
+def get_ordered_header_and_aligned_field_instances_non_virtual__name_width(ordered_header_instances_non_virtual,
+                                                                           header_info, aligned_field_info):
+    ordered_aligned_field_instances_non_virtual__name_width = []
+    ordered_header_instances_non_virtual_aligned_field__name_width = {}
+    for header_name in ordered_header_instances_non_virtual:
+        ordered_header_instances_non_virtual_aligned_field__name_width[header_name] = []
+        processed_fields = []
+        for field_name in header_info[header_name]["fields"]:
+            bit_width = aligned_field_info[field_name]["bit_width"]
+            field_name = aligned_field_info[field_name]["name"]
+            if field_name in processed_fields:
+                continue
+            processed_fields += [field_name]
+            ordered_aligned_field_instances_non_virtual__name_width += [(field_name, bit_width)]
+            ordered_header_instances_non_virtual_aligned_field__name_width[header_name] += [(field_name,
+                                                                                             bit_width)]
+    return (ordered_aligned_field_instances_non_virtual__name_width,
+            ordered_header_instances_non_virtual_aligned_field__name_width)
diff --git a/include/p4/plugin/ovs/datapath/linux/compat/include/linux/openvswitch.h.h b/include/p4/plugin/ovs/datapath/linux/compat/include/linux/openvswitch.h.h
new file mode 100644
index 0000000..481cb26
--- /dev/null
+++ b/include/p4/plugin/ovs/datapath/linux/compat/include/linux/openvswitch.h.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+//:: aligned_field_info = helpers.get_align_field_info(field_info, header_info, ordered_header_instances_all)
+//:: ordered_header_instances_non_virtual = helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual)
+//:: (_, ordered_header_instances_non_virtual_aligned_field__name_width) = helpers.get_ordered_header_and_aligned_field_instances_non_virtual__name_width(
+//::                                                                            ordered_header_instances_non_virtual,
+//::                                                                            header_info, aligned_field_info)
+
+#ifndef OVS_DATAPATH_LINUX_COMPAT_INCLUDE_LINUX_OPENVSWITCH_H_H
+#define	OVS_DATAPATH_LINUX_COMPAT_INCLUDE_LINUX_OPENVSWITCH_H_H 1
+
+/* -- Used in datapath/linux/compat/include/linux/openvswitch.h -- */
+#define OVS_KEY_ATTRS \
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_non_virtual:
+    OVS_KEY_ATTR_${header_name.upper()}, \
+//::  #endfor
+    OVS_KEY_ATTR_VALID, \
+    \
+
+/* -- Used in datapath/linux/compat/include/linux/openvswitch.h -- */
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_non_virtual:
+struct ovs_key_${header_name} {
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+//::      if bit_width in [8, 16, 32, 64]:
+    uint${bit_width}_t ${field_name};
+//::      else:
+    struct ${field_name}_t ${field_name};
+//::      #endif
+//::    #endfor
+};
+
+//::  #endfor
+struct ovs_key_valid {
+//::  for header_name in ordered_header_instances_regular:
+    uint8_t ${header_name}_valid;
+//::  #endfor
+    };
+
+#endif	/* OVS_DATAPATH_LINUX_COMPAT_INCLUDE_LINUX_OPENVSWITCH_H_H */
diff --git a/include/p4/plugin/ovs/include/openvswitch/flow.h.h b/include/p4/plugin/ovs/include/openvswitch/flow.h.h
new file mode 100644
index 0000000..79945ae
--- /dev/null
+++ b/include/p4/plugin/ovs/include/openvswitch/flow.h.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+
+#ifndef OVS_INCLUDE_OPENVSWITCH_FLOW_H_H
+#define	OVS_INCLUDE_OPENVSWITCH_FLOW_H_H 1
+
+/* -- Used in include/openvswitch/flow.h -- */
+#define OVS_FIELDS \
+//::  for header_name in helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual):
+    struct ${header_name}_padded_header ${header_name}; \
+//::  #endfor
+    struct valid_padded_header valid; \
+    \
+
+#endif	/* OVS_INCLUDE_OPENVSWITCH_FLOW_H_H */
diff --git a/include/p4/plugin/ovs/include/openvswitch/meta-flow.h.h b/include/p4/plugin/ovs/include/openvswitch/meta-flow.h.h
new file mode 100644
index 0000000..da036b3
--- /dev/null
+++ b/include/p4/plugin/ovs/include/openvswitch/meta-flow.h.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+//:: aligned_field_info = helpers.get_align_field_info(field_info, header_info, ordered_header_instances_all)
+//:: ordered_header_instances_non_virtual = helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual)
+//:: (_, ordered_header_instances_non_virtual_aligned_field__name_width) = helpers.get_ordered_header_and_aligned_field_instances_non_virtual__name_width(
+//::                                                                            ordered_header_instances_non_virtual,
+//::                                                                            header_info, aligned_field_info)
+
+#ifndef OVS_INCLUDE_OPENVSWITCH_META_FLOW_H_H
+#define	OVS_INCLUDE_OPENVSWITCH_META_FLOW_H_H 1
+
+/* -- Included in include/openvswitch/meta-flow.h -- */
+
+/* NOTE:
+ * 1. Don't forget to add preceding tabs in the following fields, otherwise, will result in errors.
+ * 2. For now prerequisites are not handled and all fields are maskable.
+ */
+
+//::  base_oxm_offset = 1 # We use 1 as the base line offset. If new NXOXM_ET_* fixed fields are added in OVS
+//::                      # this number will have to be updated accordingly.
+//::  for header_name in ordered_header_instances_non_virtual:
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+    /* "${field_name}".
+     *
+     * ${field_name} field.
+     *
+     * Type: be${bit_width}.
+     * Formatting: hexadecimal.
+     * Maskable: bitwise.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: NXOXM_ET_${field_name.upper()}(${base_oxm_offset}) since OF1.5 and v2.5.
+     */
+    MFF_${field_name.upper()},
+//::      base_oxm_offset += 1
+
+//::    #endfor
+//::  #endfor
+//::
+//::  for header_name in ordered_header_instances_regular:
+    /* "${header_name}_valid".
+     *
+     * ${header_name}_valid field.
+     *
+     * Type: u${8}.
+     * Formatting: hexadecimal.
+     * Maskable: bitwise.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: NXOXM_ET_${header_name.upper()}_VALID(${base_oxm_offset}) since OF1.5 and v2.5.
+     */
+    MFF_${header_name.upper()}_VALID,
+//::      base_oxm_offset += 1
+
+//::  #endfor
+
+/* Do NOT REMOVE THIS. */
+    // MFF_N_IDS
+
+#endif	/* OVS_INCLUDE_OPENVSWITCH_META_FLOW_H_H */
diff --git a/include/p4/plugin/ovs/include/openvswitch/packets.h.h b/include/p4/plugin/ovs/include/openvswitch/packets.h.h
new file mode 100644
index 0000000..5465cd8
--- /dev/null
+++ b/include/p4/plugin/ovs/include/openvswitch/packets.h.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+//:: aligned_field_info = helpers.get_align_field_info(field_info, header_info, ordered_header_instances_all)
+//:: ordered_header_instances_non_virtual = helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual)
+//:: (_, ordered_header_instances_non_virtual_aligned_field__name_width) = helpers.get_ordered_header_and_aligned_field_instances_non_virtual__name_width(
+//::                                                                            ordered_header_instances_non_virtual,
+//::                                                                            header_info, aligned_field_info)
+
+#ifndef OVS_INCLUDE_OPENVSWITCH_PACKETS_H_H
+#define	OVS_INCLUDE_OPENVSWITCH_PACKETS_H_H 1
+
+//::  for header_name in ordered_header_instances_non_virtual:
+//::    header_len = sum([bit_width for _, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]])/8
+#define ${header_name.upper()}_HEADER_LEN ${header_len}
+//::  #endfor
+#define VALID_HEADER_LEN ${len(ordered_header_instances_regular)}
+
+/* -- Used in include/openvswitch/packets.h -- */
+//::  for header_name in ordered_header_instances_non_virtual:
+//::    run_bit_width = 0
+OVS_PACKED(
+struct ${header_name}_header {
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+//::      if bit_width in [8, 16, 32, 64]:
+    uint${bit_width}_t ${field_name};
+//::      else:
+//::        # We assume that all fields are, at least, byte aligned.
+    struct ${field_name}_t ${field_name};
+//::      #endif
+//::      run_bit_width += bit_width
+//::    #endfor
+});
+BUILD_ASSERT_DECL(${header_name.upper()}_HEADER_LEN == sizeof(struct ${header_name}_header));
+
+OVS_PACKED(
+struct ${header_name}_padded_header {
+    struct ${header_name}_header hdr;
+//::    pad_bits = 64 - (run_bit_width % 64)
+//::    pad_bytes = 0
+//::    if pad_bits < 64:
+//::      pad_bytes = pad_bits/8
+    uint8_t pad[${pad_bytes}];
+//::    #endif
+});
+BUILD_ASSERT_DECL(${header_name.upper()}_HEADER_LEN+${pad_bytes} == sizeof(struct ${header_name}_padded_header));
+
+//::  #endfor
+//::
+OVS_PACKED(
+struct valid_header {
+//::  for header_name in ordered_header_instances_regular:
+    uint8_t ${header_name}_valid;
+//::  #endfor
+});
+BUILD_ASSERT_DECL(VALID_HEADER_LEN == sizeof(struct valid_header));
+
+OVS_PACKED(
+struct valid_padded_header {
+    struct valid_header hdr;
+//::    pad_bits = 64 - ((len(ordered_header_instances_regular) * 8) % 64)
+//::    pad_bytes = 0
+//::    if pad_bits < 64:
+//::      pad_bytes = pad_bits/8
+    uint8_t pad[${pad_bytes}];
+//::    #endif
+    });
+BUILD_ASSERT_DECL(VALID_HEADER_LEN+${pad_bytes} == sizeof(struct valid_padded_header));
+
+#endif	/* OVS_INCLUDE_OPENVSWITCH_PACKETS_H_H */
diff --git a/include/p4/plugin/ovs/include/openvswitch/types.h.h b/include/p4/plugin/ovs/include/openvswitch/types.h.h
new file mode 100644
index 0000000..22b3023
--- /dev/null
+++ b/include/p4/plugin/ovs/include/openvswitch/types.h.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+//:: aligned_field_info = helpers.get_align_field_info(field_info, header_info, ordered_header_instances_all)
+//:: ordered_header_instances_non_virtual = helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual)
+//:: (ordered_aligned_field_instances_non_virtual__name_width, _) = helpers.get_ordered_header_and_aligned_field_instances_non_virtual__name_width(
+//::                                                                    ordered_header_instances_non_virtual,
+//::                                                                    header_info, aligned_field_info)
+
+#ifndef OVS_INCLUDE_OPENVSWITCH_TYPES_H_H
+#define	OVS_INCLUDE_OPENVSWITCH_TYPES_H_H 1
+
+/* -- Used in include/openvswitch/types.h -- */
+//::  for field_name, bit_width in ordered_aligned_field_instances_non_virtual__name_width:
+//::    if not (bit_width in [8, 16, 32, 64]):
+struct ${field_name}_t {
+    uint8_t data[${bit_width}/8];
+};
+//::    #endif
+//::  #endfor
+
+#endif	/* OVS_INCLUDE_OPENVSWITCH_TYPES_H_H */
diff --git a/include/p4/plugin/ovs/lib/dp-packet.h.h b/include/p4/plugin/ovs/lib/dp-packet.h.h
new file mode 100644
index 0000000..36b8b59
--- /dev/null
+++ b/include/p4/plugin/ovs/lib/dp-packet.h.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#ifndef OVS_LIB_DP_PACKET_H_H
+#define	OVS_LIB_DP_PACKET_H_H 1
+//::
+//:: # NOTE: we don't have to specify metadata in the packet struct in the datapath.
+//:: # The parser can set the value of the metadata but only the final results (after
+//:: # constant propagation) are written in the cache. The only thing different from
+//:: # how native OVS treat metadata is that, in P4/OVS case, parser can set metadata
+//:: # to some arbitrary value, whereas in native OVS, the value of the metadata before
+//:: # being processed by the cache and match-action tables is always 0.
+
+/* -- Used in lib/dp-packet.h -- */
+#define OVS_HDR_ATTRS \
+//::  for header_name in ordered_header_instances_regular:
+    uint16_t ${header_name}_ofs; \
+    uint8_t ${header_name}_valid; \
+//::  #endfor
+    \
+
+/* -- Used in lib/dp-packet.h -- */
+#define OVS_HDR_GET_DP_PACKET_OFS \
+//::  for header_name in ordered_header_instances_regular:
+static inline void * dp_packet_${header_name}(const struct dp_packet *b) { \
+    return b->${header_name}_ofs != UINT16_MAX \
+        ? (char *) dp_packet_data(b) + b->${header_name}_ofs \
+        : NULL; \
+} \
+//::  #endfor
+\
+
+#endif	/* OVS_LIB_DP_PACKET_H_H */
diff --git a/include/p4/plugin/ovs/lib/flow.c.h b/include/p4/plugin/ovs/lib/flow.c.h
new file mode 100644
index 0000000..784920c
--- /dev/null
+++ b/include/p4/plugin/ovs/lib/flow.c.h
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+//:: aligned_field_info = helpers.get_align_field_info(field_info, header_info, ordered_header_instances_all)
+//:: ordered_header_instances_non_virtual = helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual)
+//:: (_, ordered_header_instances_non_virtual_aligned_field__name_width) = helpers.get_ordered_header_and_aligned_field_instances_non_virtual__name_width(
+//::                                                                            ordered_header_instances_non_virtual,
+//::                                                                            header_info, aligned_field_info)
+//:: ordered_header_instances_metadata = helpers.get_ordered_header_instances_metadata(ordered_header_instances_metadata)
+
+#ifndef OVS_LIB_FLOW_C_H
+#define	OVS_LIB_FLOW_C_H 1
+
+/* -- Used in lib/flow.c -- */
+#define OVS_HDR_RESET_ATTRS \
+//::  for header_name in ordered_header_instances_regular:
+    packet->${header_name}_ofs = UINT16_MAX; \
+    packet->${header_name}_valid = 0; \
+//::  #endfor
+    \
+
+/* -- Used in lib/flow.c -- */
+#define OVS_MINIFLOW_EXTRACT_METADATA_DEFS \
+//::  for header_name in ordered_header_instances_metadata:
+    struct ${header_name}_padded_header ${header_name} = {{0},{0}}; \
+    bool is_${header_name}_header_touched = false; \
+    \
+//::  #endfor
+    struct valid_padded_header valid = {{0},{0}}; \
+    \
+
+/* -- Used in lib/flow.c -- */
+#define OVS_MINIFLOW_EXTRACT \
+    { \
+        OVS_MINIFLOW_START \
+    } \
+    \
+
+//::  for state, parse_info in parse_states.items():
+#define OVS_MINIFLOW_${state.upper()} \
+//::    # a. --- Handle call sequence -------------------------------
+//::    call_id = 0
+//::    for call in parse_info["call_sequence"]:
+//::      type = call[0]
+//::      if type == "extract":
+//::        header_name = call[1]
+    if (OVS_UNLIKELY(size < sizeof(struct ${header_name}_header))) \
+    { \
+        OVS_MINIFLOW_OUT \
+    } \
+    \
+    packet->${header_name}_ofs = ((char *) data) - l2; \
+    struct ${header_name}_padded_header *${header_name} = (struct ${header_name}_padded_header *) data_pull(&data, &size, \
+        sizeof(struct ${header_name}_header)); \
+//::        # TODO: offset increase should be based on header length expression. This needs to be implemented.
+    miniflow_push_bytes_word_aligned_64(mf, ${header_name}, ${header_name}, sizeof(struct ${header_name}_header), \
+        sizeof(struct ${header_name}_padded_header) / sizeof(uint64_t)); \
+	valid.hdr.${header_name}_valid = 1; \
+    \
+//::      elif type == "set":
+//::        destination = call[1]
+//::        metadata_name = field_info[destination]["parent_header"]
+//::        aligned_metadata = {"name": aligned_field_info[destination]["name"],
+//::                            "mask": aligned_field_info[destination]["mask"],
+//::                            "bit_offset_hdr": aligned_field_info[destination]["bit_offset_hdr"],
+//::                            "bit_width": aligned_field_info[destination]["bit_width"]}
+//::        source_type = call[2]
+//::        if source_type == "immediate":
+//::          source_value = hex(helpers.byte_array_to_int(call[3]))
+//::          if aligned_metadata["mask"]:
+//::            if aligned_metadata["bit_width"] in [8, 16, 32, 64]:
+    ${metadata_name}.hdr.${aligned_metadata["name"]} = ${helpers.hton_postfix[aligned_metadata["bit_width"]]}(((uint${aligned_metadata["bit_width"]}_t) ${source_value}) << ${aligned_metadata["bit_offset_hdr"]}) \
+        | (_${metadata_name}.hdr.${aligned_metadata["name"]} & ~${helpers.hton_postfix[aligned_metadata["bit_width"]]}(${hex(aligned_metadata["mask"])})); \
+//::            else:
+//::              # TODO: handle this case (for arbitrary byte combinations).
+//::              assert(False)
+//::            #endif
+//::          else:
+//::            if aligned_metadata["bit_width"] in [8, 16, 32, 64]:
+    ${metadata_name}.hdr.${aligned_metadata["name"]} = ${helpers.hton_postfix[aligned_metadata["bit_width"]]}((uint${aligned_metadata["bit_width"]}_t) ${source_value}); \
+//::            else:
+//::              # TODO: handle this case (for arbitrary byte combinations).
+//::              assert(False)
+//::            #endif
+//::          #endif
+//::        elif source_type == "latest":
+//::          source = call[3]
+//::          header_name = field_info[source]["parent_header"]
+//::          aligned_field = {"name": aligned_field_info[source]["name"],
+//::                           "mask": aligned_field_info[source]["mask"],
+//::                           "bit_offset_hdr": aligned_field_info[source]["bit_offset_hdr"],
+//::                           "bit_width": aligned_field_info[source]["bit_width"]}
+//::          # P4 2014 specification assumes that the referenced source header in set_metadata() is already extracted
+//::          # at this point.
+//::          if header_name in ordered_header_instances_regular:
+//::            if aligned_field["mask"]:
+//::              if aligned_field["bit_width"] in [8, 16, 32, 64]:
+    uint${aligned_field["bit_width"]}_t value_${call_id} = (${helpers.hton_postfix[aligned_field["bit_width"]]}(${header_name}->hdr.${aligned_field["name"]}) & ${hex(aligned_field["mask"])}) >> ${aligned_field["bit_offset_hdr"]}; \
+//::              else:
+//::                # TODO: handle this case (for arbitrary byte combinations).
+//::                assert(False)
+//::              #endif
+//::            else:
+//::              if aligned_field["bit_width"] in [8, 16, 32, 64]:
+    uint${aligned_field["bit_width"]}_t value_${call_id} = ${helpers.hton_postfix[aligned_field["bit_width"]]}(${header_name}->hdr.${aligned_field["name"]}); \
+//::              else:
+//::                # TODO: handle this case (for arbitrary byte combinations).
+//::                assert(False)
+//::              #endif
+//::            #endif
+//::          elif header_name in ordered_header_instances_metadata:
+//::            if aligned_field["mask"]:
+//::              if aligned_field["bit_width"] in [8, 16, 32, 64]:
+    uint${aligned_field["bit_width"]}_t value_${call_id} = (${helpers.hton_postfix[aligned_field["bit_width"]]}(${metadata_name}.hdr.${aligned_field["name"]}) & ${hex(aligned_field["mask"])}) >> ${aligned_field["bit_offset_hdr"]}; \
+//::              else:
+//::                # TODO: handle this case (for arbitrary byte combinations).
+//::                assert(False)
+//::              #endif
+//::            else:
+//::              if aligned_field["bit_width"] in [8, 16, 32, 64]:
+    uint${aligned_field["bit_width"]}_t value_${call_id} = ${helpers.hton_postfix[aligned_field["bit_width"]]}(${metadata_name}.hdr.${aligned_field["name"]}); \
+//::              else:
+//::                # TODO: handle this case (for arbitrary byte combinations).
+//::                assert(False)
+//::              #endif
+//::            #endif
+//::          else:
+//::            assert(False)
+//::          #endif
+//::          if aligned_metadata["mask"]:
+//::            if aligned_metadata["bit_width"] in [8, 16, 32, 64]:
+    ${metadata_name}.hdr.${aligned_metadata["name"]} = ${helpers.hton_postfix[aligned_field["bit_width"]]}(((uint${aligned_metadata["bit_width"]}_t) value_${call_id}) << ${aligned_metadata["bit_offset_hdr"]}) \
+        | (${metadata_name}.hdr.${aligned_metadata["name"]} & ~${helpers.hton_postfix[aligned_field["bit_width"]]}(${hex(aligned_metadata["mask"])})); \
+//::            else:
+//::              # TODO: handle this case (for arbitrary byte combinations).
+//::              assert(False)
+//::            #endif
+//::          else:
+//::            if aligned_metadata["bit_width"] in [8, 16, 32, 64]:
+    ${metadata_name}.hdr.${aligned_metadata["name"]} = ${helpers.hton_postfix[aligned_field["bit_width"]]}((uint${aligned_metadata["bit_width"]}_t) value_${call_id}); \
+//::            else:
+//::              # TODO: handle this case (for arbitrary byte combinations).
+//::              assert(False)
+//::            #endif
+//::          #endif
+//::        else:
+//::          assert(False)
+//::        #endif
+    is_${metadata_name}_header_touched = true; \
+    \
+//::      else:
+//::        assert(False)
+//::      #endif
+//::      call_id += 1
+//::    #endfor
+//::    # a. --- Handle state transitions -------------------------------
+//::    branch_on = parse_info['branch_on']
+//::    branch_to = parse_info['branch_to']
+//::    case_id = 0
+//::    for case in branch_to:
+//::      case_type, case_value, case_mask, case_next_state = case
+//::      if case_type == "value":
+//::        branch_id = 0
+//::        key_id = 0
+//::        for key_type, key_value in branch_on:
+//::          if key_type == "field_ref":
+//::            header_name = field_info[key_value]["parent_header"]
+//::            aligned_field = {"name": aligned_field_info[key_value]["name"],
+//::                             "mask": aligned_field_info[key_value]["mask"],
+//::                             "bit_offset_hdr": aligned_field_info[key_value]["bit_offset_hdr"],
+//::                             "bit_width": aligned_field_info[key_value]["bit_width"]}
+//::            if header_name in ordered_header_instances_regular:
+//::              if aligned_field["bit_width"] in [8, 16, 32, 64]:
+//::                if aligned_field["mask"]:
+    bool check_${case_id}_${branch_id} = (((${helpers.hton_postfix[aligned_field["bit_width"]]}(${header_name}->hdr.${aligned_field["name"]}) & ${hex(aligned_field["mask"])}) >> ${aligned_field["bit_offset_hdr"]}) == ${hex(helpers.byte_array_to_int(case_value[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))}); \
+//::                else:
+    bool check_${case_id}_${branch_id} = (${helpers.hton_postfix[aligned_field["bit_width"]]}(${header_name}->hdr.${aligned_field["name"]}) == ${hex(helpers.byte_array_to_int(case_value[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))}); \
+//::                #endif
+//::                key_id += helpers.key_id_ofs[aligned_field["bit_width"]]
+//::              elif aligned_field["bit_width"] <= 64:
+//::                if aligned_field["mask"]:
+    bool check_${case_id}_${branch_id} = false; \
+    { \
+        uint64_t temp = 0; \
+//::                  for i in range(aligned_field["bit_width"]/8):
+        temp |= ((const uint8_t *) &${header_name}->hdr.${aligned_field["name"]})[${i}]; temp <<= (${aligned_field["bit_width"]} - (8 * (${i} + 1))); \
+//::                  #endfor
+        check_${case_id}_${branch_id} = ((temp & ${hex(aligned_field["mask"])}) >> ${aligned_field["bit_offset_hdr"]} == ${hex(helpers.byte_array_to_int(case_value[key_id:key_id + (aligned_field["bit_width"]/8)]))}); \
+    } \
+//::                else:
+    bool check_${case_id}_${branch_id} = false; \
+    { \
+        uint64_t temp = 0; \
+//::                  for i in range(aligned_field["bit_width"]/8):
+        temp |= ((const uint8_t *) &${header_name}->hdr.${aligned_field["name"]})[${i}]; temp <<= (${aligned_field["bit_width"]} - (8 * (${i} + 1))); \
+//::                  #endfor
+        check_${case_id}_${branch_id} = (temp == ${hex(helpers.byte_array_to_int(case_value[key_id:key_id + (aligned_field["bit_width"]/8)]))}); \
+    } \
+//::                #endif
+//::                key_id += aligned_field["bit_width"]/8
+//::              else:
+//::                # TODO: right now only covers up to 64 bits, look into how to extend this range.
+//::                assert(False)
+//::              #endif
+//::            elif header_name in ordered_header_instances_metadata:
+//::              if aligned_field["bit_width"] in [8, 16, 32, 64]:
+//::                if aligned_field_mask:
+    bool check_${case_id}_${branch_id} = (((${helpers.hton_postfix[aligned_field["bit_width"]]}(${header_name}.hdr.${aligned_field["name"]}) & ${hex(aligned_field["mask"])}) >> ${aligned_field["bit_offset_hdr"]}) == ${hex(helpers.byte_array_to_int(case_value[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))}); \
+//::                else:
+    bool check_${case_id}_${branch_id} = (${helpers.hton_postfix[aligned_field["bit_width"]]}(${header_name}.hdr.${aligned_field["name"]}) == ${hex(helpers.byte_array_to_int(case_value[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))}); \
+//::                #endif
+//::                key_id += helpers.key_id_ofs[aligned_field["bit_width"]]
+//::              elif aligned_field["bit_width"] <= 64:
+//::                if aligned_field["mask"]:
+    bool check_${case_id}_${branch_id} = false; \
+    { \
+        uint64_t temp = 0; \
+//::                  for i in range(aligned_field["bit_width"]/8):
+        temp |= ((const uint8_t *) &${header_name}.hdr.${aligned_field["name"]})[${i}]; temp <<= (${aligned_field["bit_width"]} - (8 * (${i} + 1))); \
+//::                  #endfor
+        check_${case_id}_${branch_id} = ((temp & ${hex(aligned_field["mask"])}) >> ${aligned_field["bit_offset_hdr"]} == ${hex(helpers.byte_array_to_int(case_value[key_id:key_id + (aligned_field["bit_width"]/8)]))}); \
+    } \
+//::                else:
+    bool check_${case_id}_${branch_id} = false; \
+    { \
+        uint64_t temp = 0; \
+//::                  for i in range(aligned_field["bit_width"]/8):
+        temp |= ((const uint8_t *) &${header_name}.hdr.${aligned_field["name"]})[${i}]; temp <<= (${aligned_field["bit_width"]} - (8 * (${i} + 1))); \
+//::                  #endfor
+        check_${case_id}_${branch_id} = (temp == ${hex(helpers.byte_array_to_int(case_value[key_id:key_id + (aligned_field["bit_width"]/8)]))}); \
+    } \
+//::                #endif
+//::                key_id += aligned_field["bit_width"]/8
+//::              else:
+//::                # TODO: right now only covers up to 64 bits, look into how to extend this range.
+//::                assert(False)
+//::              #endif
+//::            #endif
+//::          elif key_type == "current":
+//::            key_bit_offset, key_bit_width = key_value
+//::            aligned_key = {}
+//::            aligned_key["bit_base_offset"] = int(key_bit_offset/8)*8
+//::            aligned_key["bit_offset"] = key_bit_offset - aligned_key["bit_base_offset"]
+//::            aligned_key["bit_width"] = int(helpers.ceil((aligned_key["bit_offset"]+key_bit_width)/8.0) * 8)
+//::            aligned_key["bit_offset_hdr"] = aligned_key["bit_width"] - ((aligned_key["bit_offset"] % aligned_key["bit_width"]) + key_bit_width)
+//::            aligned_key["mask"] = ((1 << key_bit_width) - 1) << aligned_key["bit_offset_hdr"]
+//::            aligned_key["mask"] = 0 if (((1 << aligned_key["bit_width"]) - 1) == aligned_key["mask"]) else aligned_key["mask"]
+    if (OVS_UNLIKELY(size < (${aligned_key["bit_base_offset"]/8} + ${aligned_key["bit_width"]/8}))) { OVS_MINIFLOW_OUT } \
+//::            if aligned_key["bit_width"] in [8, 16, 32, 64]:
+//::              if aligned_key["mask"]:
+    bool check_${case_id}_${branch_id} = (((${helpers.hton_postfix[aligned_field["bit_width"]]}((*(${helpers.std_type[aligned_field["bit_width"]]} *) (((char *) data) + ${aligned_key["bit_base_offset"]/8}))) & ${hex(aligned_key["mask"])}) >> ${aligned_key["bit_offset_hdr"]}) == ${hex(helpers.byte_array_to_int(case_value[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))}); \
+//::              else:
+    bool check_${case_id}_${branch_id} = (${helpers.hton_postfix[aligned_field["bit_width"]]}((*(${helpers.std_type[aligned_field["bit_width"]]} *) (((char *) data) + ${aligned_key["bit_base_offset"]/8}))) == ${hex(helpers.byte_array_to_int(case_value[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))}); \
+//::              #endif
+//::              key_id += helpers.key_id_ofs[aligned_field["bit_width"]]
+//::            else:
+//::              # TODO: right now only covers up to 64 bits, look into how to extend this range.
+//::              assert(False)
+//::            #endif
+//::          else:
+//::            assert(False)
+//::          #endif
+//::          branch_id += 1
+//::        #endfor
+    if ( \
+//::        branch_id = 0
+//::        for key_type, key_value in branch_on:
+        check_${case_id}_${branch_id} && \
+//::          branch_id += 1
+//::        #endfor
+        true) \
+//::      elif case_type == "value_masked":
+//::        branch_id = 0
+//::        key_id = 0
+//::        for key_type, key_value in branch_on:
+//::          if key_type == "field_ref":
+//::            header_name = field_info[key_value]["parent_header"]
+//::            aligned_field = {"name": aligned_field_info[key_value]["name"],
+//::                             "mask": aligned_field_info[key_value]["mask"],
+//::                             "bit_offset_hdr": aligned_field_info[key_value]["bit_offset_hdr"],
+//::                             "bit_width": aligned_field_info[key_value]["bit_width"]}
+//::            if header_name in ordered_header_instances_regular:
+//::              if aligned_field["bit_width"] in [8, 16, 32, 64]:
+//::                if aligned_field["mask"]:
+    bool check_${case_id}_${branch_id} = (((${helpers.hton_postfix[aligned_field["bit_width"]]}(${header_name}->hdr.${aligned_field["name"]}) & ${hex(aligned_field["mask"])}) >> ${aligned_field["bit_offset_hdr"]}) == (${hex(helpers.byte_array_to_int(case_value[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))} & ${hex(byte_array_to_int(case_mask[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))})); \
+//::                else:
+    bool check_${case_id}_${branch_id} = (${helpers.hton_postfix[aligned_field["bit_width"]]}(${header_name}->hdr.${aligned_field["name"]}) == (${hex(helpers.byte_array_to_int(case_value[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))} & ${hex(byte_array_to_int(case_mask[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))})); \
+//::                #endif
+//::                key_id += helpers.key_id_ofs[aligned_field["bit_width"]]
+//::              elif aligned_field["bit_width"] <= 64:
+//::                if aligned_field["mask"]:
+    bool check_${case_id}_${branch_id} = false; \
+    { \
+        uint64_t temp = 0; \
+//::                  for i in range(aligned_field["bit_width"]/8):
+        temp |= ((const uint8_t *) &${header_name}->hdr.${aligned_field["name"]})[${i}]; temp <<= (${aligned_field["bit_width"]} - (8 * (${i} + 1))); \
+//::                  #endfor
+        check_${case_id}_${branch_id} = ((temp & ${hex(aligned_field["mask"])}) >> ${aligned_field["bit_offset_hdr"]} == (${hex(helpers.byte_array_to_int(case_value[key_id:key_id + (aligned_field["bit_width"]/8)]))} & ${hex(helpers.byte_array_to_int(case_mask[key_id:key_id + (aligned_field["bit_width"]/8)]))})); \
+    } \
+//::                else:
+    bool check_${case_id}_${branch_id} = false; \
+    { \
+        uint64_t temp = 0; \
+//::                  for i in range(aligned_field["bit_width"]/8):
+        temp |= ((const uint8_t *) &${header_name}->hdr.${aligned_field["name"]})[${i}]; temp <<= (${aligned_field["bit_width"]} - (8 * (${i} + 1))); \
+//::                  #endfor
+        check_${case_id}_${branch_id} = (temp == (${hex(helpers.byte_array_to_int(case_value[key_id:key_id + (aligned_field["bit_width"]/8)]))} & ${hex(helpers.byte_array_to_int(case_mask[key_id:key_id + (aligned_field["bit_width"]/8)]))})); \
+    } \
+//::                #endif
+//::                key_id += aligned_field["bit_width"]/8
+//::              else:
+//::                # TODO: right now only covers up to 64 bits, look into how to extend this range.
+//::                assert(False)
+//::              #endif
+//::            elif header_name in ordered_header_instances_metadata:
+//::              if aligned_field["bit_width"] in [8, 16, 32, 64]:
+//::                if aligned_field["mask"]:
+    bool check_${case_id}_${branch_id} = (((${helpers.hton_postfix[aligned_field["bit_width"]]}(${header_name}.hdr.${aligned_field["name"]}) & ${hex(aligned_field["mask"])}) >> ${aligned_field["bit_offset_hdr"]}) == (${hex(helpers.byte_array_to_int(case_value[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))} & ${hex(helpers.byte_array_to_int(case_mask[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))})); \
+//::                else:
+    bool check_${case_id}_${branch_id} = (${helpers.hton_postfix[aligned_field["bit_width"]]}(${header_name}.hdr.${aligned_field["name"]}) == (${hex(helpers.byte_array_to_int(case_value[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))} & ${hex(helpers.byte_array_to_int(case_mask[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))})); \
+//::                #endif
+//::                key_id += helpers.key_id_ofs[aligned_field["bit_width"]]
+//::              elif aligned_field["bit_width"] <= 64:
+//::                if aligned_field["mask"]:
+    bool check_${case_id}_${branch_id} = false; \
+    { \
+        uint64_t temp = 0; \
+//::                  for i in range(aligned_field["bit_width"]/8):
+        temp |= ((const uint8_t *) &_${header_name}.hdr.${aligned_field["name"]})[${i}]; temp <<= (${aligned_field["bit_width"]} - (8 * (${i} + 1))); \
+//::                  #endfor
+        check_${case_id}_${branch_id} = ((temp & ${hex(aligned_field["mask"])}) >> ${aligned_field["bit_offset_hdr"]} == (${hex(helpers.byte_array_to_int(case_value[key_id:key_id + (aligned_field["bit_width"]/8)]))} & ${hex(helpers.byte_array_to_int(case_mask[key_id:key_id + (aligned_field["bit_width"]/8)]))})); \
+    } \
+//::                else:
+    bool check_${case_id}_${branch_id} = false; \
+    { \
+        uint64_t temp = 0; \
+//::                  for i in range(aligned_field["bit_width"]/8):
+        temp |= ((const uint8_t *) &_${header_name}.hdr.${aligned_field["name"]})[${i}]; temp <<= (${aligned_field["bit_width"]} - (8 * (${i} + 1))); \
+//::                  #endfor
+        check_${case_id}_${branch_id} = (temp == (${hex(helpers.byte_array_to_int(case_value[key_id:key_id + (aligned_field["bit_width"]/8)]))} & ${hex(helpers.byte_array_to_int(case_mask[key_id:key_id + (aligned_field["bit_width"]/8)]))})); \
+    } \
+//::                #endif
+//::                key_id += aligned_field["bit_width"]/8
+//::              else:
+//::                # TODO: right now only covers up to 64 bits, look into how to extend this range.
+//::                assert(False)
+//::              #endif
+//::            #endif
+//::          elif key_type == "current":
+//::            key_bit_offset, key_bit_width = key_value
+//::            aligned_key = {}
+//::            aligned_key["bit_base_offset"] = int(key_bit_offset/8)*8
+//::            aligned_key["bit_offset"] = key_bit_offset - aligned_key["bit_base_offset"]
+//::            aligned_key["bit_width"] = int(helpers.ceil((aligned_key["bit_offset"]+key_bit_width)/8.0) * 8)
+//::            aligned_key["bit_offset_hdr"] = aligned_key["bit_width"] - ((aligned_key["bit_offset"] % aligned_key["bit_width"]) + key_bit_width)
+//::            aligned_key["mask"] = ((1 << key_bit_width) - 1) << aligned_key["bit_offset_hdr"]
+//::            aligned_key["mask"] = 0 if (((1 << aligned_key["bit_width"]) - 1) == aligned_key["mask"]) else aligned_key["mask"]
+    if (OVS_UNLIKELY(size < (${aligned_key["bit_base_offset"]/8} + ${aligned_key["bit_width"]/8}))) { OVS_MINIFLOW_OUT } \
+//::            if aligned_key["bit_width"] in [8, 16, 32, 64]:
+//::              if aligned_key["mask"]:
+    bool check_${case_id}_${branch_id} = (((${helpers.hton_postfix[aligned_field["bit_width"]]}((*(${helpers.std_type[aligned_field["bit_width"]]} *) (((char *) data) + ${aligned_key["bit_base_offset"]/8}))) & ${hex(aligned_key["mask"])}) >> ${aligned_key["bit_offset_hdr"]}) == (${hex(helpers.byte_array_to_int(case_value[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))} & ${hex(helpers.byte_array_to_int(case_mask[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))})); \
+//::              else:
+    bool check_${case_id}_${branch_id} = (${helpers.hton_postfix[aligned_field["bit_width"]]}((*(${helpers.std_type[aligned_field["bit_width"]]} *) (((char *) data) + ${aligned_key["bit_base_offset"]/8}))) == (${hex(helpers.byte_array_to_int(case_value[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))} & ${hex(helpers.byte_array_to_int(case_mask[key_id:key_id + helpers.key_id_ofs[aligned_field["bit_width"]]]))})); \
+//::              #endif
+//::              key_id += helpers.key_id_ofs[aligned_field["bit_width"]]
+//::            else:
+//::              # TODO: right now only covers up to 64 bits, look into how to extend this range.
+//::              assert(False)
+//::            #endif
+//::          else:
+//::            assert(False)
+//::          #endif
+//::          branch_id += 1
+//::        #endfor
+    if ( \
+//::        branch_id = 0
+//::        for key_type, key_value in branch_on:
+        check_${case_id}_${branch_id} && \
+//::          branch_id += 1
+//::        #endfor
+        true) \
+//::      elif case_type == "default":
+//::        pass
+//::      else:
+//::        assert(False)
+//::      #endif
+    { \
+//::      if case_next_state[0] == "parse_state":
+        OVS_MINIFLOW_${case_next_state[1].upper()} \
+//::      elif case_next_state[0] == "table" or case_next_state[0] == "conditional_table":
+        OVS_MINIFLOW_OUT \
+//::      else:
+//::        assert(False)
+//::      #endif
+    } \
+    \
+//::      case_id += 1
+//::    #endfor
+
+//::  #endfor
+//::
+#define OVS_MINIFLOW_OUT \
+//::  for header_name in ordered_header_instances_metadata:
+    if (OVS_LIKELY(is_${header_name}_header_touched)) \
+    { \
+        miniflow_push_bytes_word_aligned_64(mf, ${header_name}, &${header_name}, sizeof(struct ${header_name}_header), \
+        sizeof(struct ${header_name}_padded_header) / sizeof(uint64_t)); \
+    } \
+//::  #endfor
+    \
+	miniflow_push_bytes_word_aligned_64(mf, valid, &valid, sizeof(struct valid_header), \
+            sizeof(struct valid_padded_header) / sizeof(uint64_t)); \
+    goto out_; \
+    \
+
+/* -- Used in lib/flow.c -- */
+#define OVS_FLOW_WC_MASK \
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_metadata:
+    WC_MASK_FIELD(wc, ${header_name}); \
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    if (flow->valid.hdr.${header_name}_valid == 1) { \
+        WC_MASK_FIELD(wc, ${header_name}); \
+    } \
+//::  #endfor
+	\
+
+/* -- Used in lib/flow.c -- */
+#define OVS_FLOW_WC_MAP \
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_metadata:
+    FLOWMAP_SET(map, ${header_name}); \
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    if (flow->valid.hdr.${header_name}_valid == 1) { \
+        FLOWMAP_SET(map, ${header_name}); \
+    } \
+//::  #endfor
+    FLOWMAP_SET(map, valid); \
+    \
+
+#endif	/* OVS_LIB_FLOW_C_H */
diff --git a/include/p4/plugin/ovs/lib/match.c.h b/include/p4/plugin/ovs/lib/match.c.h
new file mode 100644
index 0000000..bdc3d39
--- /dev/null
+++ b/include/p4/plugin/ovs/lib/match.c.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+//:: aligned_field_info = helpers.get_align_field_info(field_info, header_info, ordered_header_instances_all)
+//:: ordered_header_instances_non_virtual = helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual)
+//:: (_, ordered_header_instances_non_virtual_aligned_field__name_width) = helpers.get_ordered_header_and_aligned_field_instances_non_virtual__name_width(
+//::                                                                            ordered_header_instances_non_virtual,
+//::                                                                            header_info, aligned_field_info)
+
+#ifndef OVS_LIB_MATCH_C_H
+#define	OVS_LIB_MATCH_C_H 1
+
+/* -- Used in lib/match.c -- */
+#define OVS_MATCH_FORMAT \
+    \
+
+#define OVS_MATCH_FORMAT_DISABLED \
+//::  for header_name in ordered_header_instances_non_virtual:
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+//::      if bit_width in [8, 16, 32, 64]:
+    format_be${bit_width}_masked(s, "${field_name}", f->${header_name}.hdr.${field_name}, \
+             wc->masks.${header_name}.hdr.${field_name}); \
+//::      else:
+//::        # We assume that all fields are, at least, byte aligned.
+    format_bex_masked(s, "${field_name}", \
+                      (const uint8_t *) &f->${header_name}.hdr.${field_name}, \
+                      (const uint8_t *) &wc->masks.${header_name}.hdr.${field_name}, \
+                      sizeof f->${header_name}.hdr.${field_name}); \
+//::      #endif
+//::    #endfor
+    \
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    format_be8_masked(s, "${header_name}_valid", f->valid.hdr.${header_name}_valid, \
+                      wc->masks.valid.hdr.${header_name}_valid); \
+//::  #endfor
+    \
+
+#endif	/* OVS_LIB_MATCH_C_H */
diff --git a/include/p4/plugin/ovs/lib/meta-flow.c.h b/include/p4/plugin/ovs/lib/meta-flow.c.h
new file mode 100644
index 0000000..9280fed
--- /dev/null
+++ b/include/p4/plugin/ovs/lib/meta-flow.c.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+//:: aligned_field_info = helpers.get_align_field_info(field_info, header_info, ordered_header_instances_all)
+//:: ordered_header_instances_non_virtual = helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual)
+//:: (_, ordered_header_instances_non_virtual_aligned_field__name_width) = helpers.get_ordered_header_and_aligned_field_instances_non_virtual__name_width(
+//::                                                                            ordered_header_instances_non_virtual,
+//::                                                                            header_info, aligned_field_info)
+
+#ifndef OVS_LIB_META_FLOW_C_H
+#define	OVS_LIB_META_FLOW_C_H 1
+
+/* -- Used in lib/meta-flow.c -- */
+#define OVS_GET_VALUE_CASES \
+//::  for header_name in ordered_header_instances_non_virtual:
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+    case MFF_${field_name.upper()}: \
+//::      if bit_width in [8, 16, 32, 64]:
+        value->${helpers.std_type_prefix[bit_width]} = flow->${header_name}.hdr.${field_name}; \
+//::      else:
+//::        # We assume that all fields are, at least, byte aligned.
+        memcpy(value->data, &flow->${header_name}.hdr.${field_name}, \
+            sizeof flow->${header_name}.hdr.${field_name}); \
+//::      #endif
+        break; \
+//::    #endfor
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    case MFF_${header_name.upper()}_VALID: \
+        value->u8 = flow->valid.hdr.${header_name}_valid; \
+        break; \
+//::  #endfor
+\
+
+/* -- Used in lib/meta-flow.c -- */
+#define OVS_IS_VALUE_VALID_CASES \
+//::  for header_name in ordered_header_instances_non_virtual:
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+    case MFF_${field_name.upper()}: \
+        return true; \
+//::    #endfor
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    case MFF_${header_name.upper()}_VALID: \
+        return true; \
+//::  #endfor
+\
+
+/* -- Used in lib/meta-flow.c -- */
+#define OVS_IS_ALL_WILD_CASES \
+//::  for header_name in ordered_header_instances_non_virtual:
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+    case MFF_${field_name.upper()}: \
+//::      if bit_width in [8, 16, 32, 64]:
+        return !wc->masks.${header_name}.hdr.${field_name}; \
+//::      else:
+        return is_all_zeros(&wc->masks.${header_name}.hdr.${field_name}, \
+            sizeof wc->masks.${header_name}.hdr.${field_name}); \
+//::      #endif
+//::    #endfor
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    case MFF_${header_name.upper()}_VALID: \
+        return !wc->masks.valid.hdr.${header_name}_valid; \
+//::  #endfor
+\
+
+/* -- Used in lib/meta-flow.c -- */
+#define OVS_SET_FLOW_VALUE_CASES \
+//::  for header_name in ordered_header_instances_non_virtual:
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+    case MFF_${field_name.upper()}: \
+//::      if bit_width in [8, 16, 32, 64]:
+        flow->${header_name}.hdr.${field_name} = value->${helpers.std_type_prefix[bit_width]}; \
+//::      else:
+//::        # We assume that all fields are, at least, byte aligned.
+        memcpy(&flow->${header_name}.hdr.${field_name}, value->data, \
+            sizeof flow->${header_name}.hdr.${field_name}); \
+//::      #endif
+        break; \
+//::    #endfor
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    case MFF_${header_name.upper()}_VALID: \
+        flow->valid.hdr.${header_name}_valid = value->u8; \
+        break; \
+//::  #endfor
+\
+
+/* -- Used in lib/meta-flow.c -- */
+#define OVS_SET_VALUE_CASES \
+//::  for header_name in ordered_header_instances_non_virtual:
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+    case MFF_${field_name.upper()}: \
+//::      if bit_width == 8:
+        match->wc.masks.${header_name}.hdr.${field_name} = 0xff; \
+        match->flow.${header_name}.hdr.${field_name} = value->${helpers.std_type_prefix[bit_width]}; \
+//::      elif bit_width in [16, 32, 64]:
+        match->wc.masks.${header_name}.hdr.${field_name} = OVS_BE${bit_width}_MAX; \
+        match->flow.${header_name}.hdr.${field_name} = value->${helpers.std_type_prefix[bit_width]}; \
+//::      else:
+//::        # We assume that all fields are, at least, byte aligned.
+        memset(&match->wc.masks.${header_name}.hdr.${field_name}, 0xff, \
+               sizeof match->wc.masks.${header_name}.hdr.${field_name}); \
+        memcpy(&match->flow.${header_name}.hdr.${field_name}, value->data, \
+               sizeof match->flow.${header_name}.hdr.${field_name}); \
+//::      #endif
+        break; \
+//::    #endfor
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    case MFF_${header_name.upper()}_VALID: \
+        match->wc.masks.valid.hdr.${header_name}_valid = 0xff; \
+        match->flow.valid.hdr.${header_name}_valid = value->u8; \
+        break; \
+//::  #endfor
+\
+
+/* -- Used in lib/meta-flow.c -- */
+#define OVS_SET_WILD_CASES \
+//::  for header_name in ordered_header_instances_non_virtual:
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+    case MFF_${field_name.upper()}: \
+//::      if bit_width in [8, 16, 32, 64]:
+        match->flow.${header_name}.hdr.${field_name} = 0; \
+        match->wc.masks.${header_name}.hdr.${field_name} = 0; \
+//::      else:
+//::        # We assume that all fields are, at least, byte aligned.
+        memset(&match->flow.${header_name}.hdr.${field_name}, 0, \
+               sizeof match->flow.${header_name}.hdr.${field_name}); \
+        memset(&match->wc.masks.${header_name}.hdr.${field_name}, 0, \
+               sizeof match->wc.masks.${header_name}.hdr.${field_name}); \
+//::      #endif
+        break; \
+//::    #endfor
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    case MFF_${header_name.upper()}_VALID: \
+        match->flow.valid.hdr.${header_name}_valid = 0; \
+        match->wc.masks.valid.hdr.${header_name}_valid = 0; \
+        break; \
+//::  #endfor
+\
+
+/* -- Used in lib/meta-flow.c -- */
+#define OVS_SET_CASES \
+//::  for header_name in ordered_header_instances_non_virtual:
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+    case MFF_${field_name.upper()}: \
+//::      if bit_width in [8, 16, 32, 64]:
+        match->flow.${header_name}.hdr.${field_name} = value->${helpers.std_type_prefix[bit_width]} & mask->${helpers.std_type_prefix[bit_width]}; \
+        match->wc.masks.${header_name}.hdr.${field_name} = mask->${helpers.std_type_prefix[bit_width]}; \
+//::      else:
+//::        # We assume that all fields are, at least, byte aligned.
+        for (size_t i = 0; i < sizeof match->flow.${header_name}.hdr.${field_name}; i++) { \
+            ((uint8_t *) &match->flow.${header_name}.hdr.${field_name})[i] = (value->data)[i] & (mask->data)[i]; \
+            ((uint8_t *) &match->wc.masks.${header_name}.hdr.${field_name})[i] = (mask->data)[i]; \
+        } \
+//::      #endif
+        break; \
+//::    #endfor
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    case MFF_${header_name.upper()}_VALID: \
+        match->flow.valid.hdr.${header_name}_valid = value->u8 & mask->u8; \
+        match->wc.masks.valid.hdr.${header_name}_valid = mask->u8; \
+        break; \
+//::  #endfor
+\
+
+#endif	/* OVS_LIB_META_FLOW_C_H */
diff --git a/include/p4/plugin/ovs/lib/nx-match.c.h b/include/p4/plugin/ovs/lib/nx-match.c.h
new file mode 100644
index 0000000..3278e00
--- /dev/null
+++ b/include/p4/plugin/ovs/lib/nx-match.c.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+//:: aligned_field_info = helpers.get_align_field_info(field_info, header_info, ordered_header_instances_all)
+//:: ordered_header_instances_non_virtual = helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual)
+//:: (_, ordered_header_instances_non_virtual_aligned_field__name_width) = helpers.get_ordered_header_and_aligned_field_instances_non_virtual__name_width(
+//::                                                                            ordered_header_instances_non_virtual,
+//::                                                                            header_info, aligned_field_info)
+
+#ifndef OVS_LIB_NX_MATCH_C_H
+#define	OVS_LIB_NX_MATCH_C_H 1
+
+/* -- Used in lib/nx-match.c -- */
+#define OVS_MATCH_PUT_RAW \
+//::  for header_name in ordered_header_instances_non_virtual:
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+//::      if bit_width in [8, 16, 32, 64]:
+    nxm_put_${bit_width}m(b, MFF_${field_name.upper()}, oxm, \
+               flow->${header_name}.hdr.${field_name}, \
+               match->wc.masks.${header_name}.hdr.${field_name}); \
+//::      else:
+//::        # We assume that all fields are, at least, byte aligned.
+    nxm_put(b, MFF_${field_name.upper()}, oxm, \
+            &flow->${header_name}.hdr.${field_name}, \
+            &match->wc.masks.${header_name}.hdr.${field_name}, \
+            sizeof flow->${header_name}.hdr.${field_name}); \
+//::      #endif
+//::    #endfor
+    \
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    nxm_put_8m(b, MFF_${header_name.upper()}_VALID, oxm, \
+               flow->valid.hdr.${header_name}_valid, \
+               match->wc.masks.valid.hdr.${header_name}_valid); \
+//::  #endfor
+    \
+
+#endif	/* OVS_LIB_NX_MATCH_C_H */
diff --git a/include/p4/plugin/ovs/lib/odp-execute.c.h b/include/p4/plugin/ovs/lib/odp-execute.c.h
new file mode 100644
index 0000000..78e7c93
--- /dev/null
+++ b/include/p4/plugin/ovs/lib/odp-execute.c.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+//:: aligned_field_info = helpers.get_align_field_info(field_info, header_info, ordered_header_instances_all)
+//:: ordered_header_instances_non_virtual = helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual)
+//:: (_, ordered_header_instances_non_virtual_aligned_field__name_width) = helpers.get_ordered_header_and_aligned_field_instances_non_virtual__name_width(
+//::                                                                            ordered_header_instances_non_virtual,
+//::                                                                            header_info, aligned_field_info)
+//:: ordered_header_instances_metadata = helpers.get_ordered_header_instances_metadata(ordered_header_instances_metadata)
+
+#ifndef OVS_LIB_ODP_EXECUTE_C_H
+#define	OVS_LIB_ODP_EXECUTE_C_H 1
+
+/* -- Used in lib/odp-execute.c -- */
+//::  for header_name in ordered_header_instances_regular:
+static void odp_set_${header_name}(struct dp_packet *packet, const struct ovs_key_${header_name} *key,
+            const struct ovs_key_${header_name} *mask)
+{
+    struct ${header_name}_header *${header_name} = dp_packet_${header_name}(packet);
+
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+//::      if bit_width in [8, 16, 32, 64]:
+    uint${bit_width}_t ${field_name} = key->${field_name} | (${header_name}->${field_name} & ~mask->${field_name});
+//::      else:
+    struct ${field_name}_t ${field_name};
+    for (size_t i = 0; i < sizeof(struct ${field_name}_t); i++) {
+        ((uint8_t *) &${field_name})[i] = ((const uint8_t *) &key->${field_name})[i] |
+            (((const uint8_t *) &${header_name}->${field_name})[i] &
+            ~((const uint8_t *) &mask->${field_name})[i]);
+    }
+//::      #endif
+//::    #endfor
+
+    packet_set_${header_name}(
+//::    for field_name, _ in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+        ${field_name},
+//::    #endfor
+        packet);
+}
+
+//::  #endfor
+//::
+static void odp_set_valid(struct dp_packet *packet, const struct ovs_key_valid *key,
+                          const struct ovs_key_valid *mask)
+{
+//::  for header_name in ordered_header_instances_regular:
+    uint8_t ${header_name}_valid = key->${header_name}_valid | (packet->${header_name}_valid & ~mask->${header_name}_valid);
+//::  #endfor
+
+    packet_set_valid(
+//::  for header_name in ordered_header_instances_regular:
+        ${header_name}_valid,
+//::  #endfor
+        packet);
+}
+
+/* -- Used in lib/odp-execute.c -- */
+#define OVS_ODP_EXECUTE_SET_ACTION_CASES \
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_metadata:
+    case OVS_KEY_ATTR_${header_name.upper()}: \
+        break; \
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    case OVS_KEY_ATTR_${header_name.upper()}: \
+    { \
+        const struct ovs_key_${header_name} *${header_name}_key = \
+            nl_attr_get_unspec(a, sizeof(struct ovs_key_${header_name})); \
+        packet_set_${header_name}( \
+//::    for field_name, _ in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+            ${header_name}_key->${field_name}, \
+//::    #endfor
+            packet); \
+        break; \
+    } \
+//::  #endfor
+    case OVS_KEY_ATTR_VALID: \
+    { \
+        const struct ovs_key_valid *valid_key = \
+            nl_attr_get_unspec(a, sizeof(struct ovs_key_valid)); \
+        packet_set_valid( \
+//::  for header_name in ordered_header_instances_regular:
+            valid_key->${header_name}_valid, \
+//::  #endfor
+            packet); \
+        break; \
+    } \
+    \
+
+/* -- Used in lib/odp-execute.c -- */
+#define OVS_ODP_EXECUTE_MASKED_SET_ACTION_CASES \
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_metadata:
+    case OVS_KEY_ATTR_${header_name.upper()}: \
+        break; \
+//::  #endfor
+//::  for header_name in ordered_header_instances_regular:
+    case OVS_KEY_ATTR_${header_name.upper()}: \
+        odp_set_${header_name}(packet, nl_attr_get(a), \
+                get_mask(a, struct ovs_key_${header_name})); \
+        break; \
+//::  #endfor
+    case OVS_KEY_ATTR_VALID: \
+        odp_set_valid(packet, nl_attr_get(a), \
+                      get_mask(a, struct ovs_key_valid)); \
+        break; \
+    \
+
+#endif	/* OVS_LIB_ODP_EXECUTE_C_H */
diff --git a/include/p4/plugin/ovs/lib/odp-util.c.h b/include/p4/plugin/ovs/lib/odp-util.c.h
new file mode 100644
index 0000000..11d2793
--- /dev/null
+++ b/include/p4/plugin/ovs/lib/odp-util.c.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+//:: aligned_field_info = helpers.get_align_field_info(field_info, header_info, ordered_header_instances_all)
+//:: ordered_header_instances_non_virtual = helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual)
+//:: (_, ordered_header_instances_non_virtual_aligned_field__name_width) = helpers.get_ordered_header_and_aligned_field_instances_non_virtual__name_width(
+//::                                                                            ordered_header_instances_non_virtual,
+//::                                                                            header_info, aligned_field_info)
+
+#ifndef OVS_LIB_ODP_UTIL_C_H
+#define	OVS_LIB_ODP_UTIL_C_H 1
+
+/* -- Used in lib/odp-util.c -- */
+#define OVS_KEY_ATTRS_TO_STRING_CASES \
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_non_virtual:
+    case OVS_KEY_ATTR_${header_name.upper()}: return "${header_name}"; \
+//::  #endfor
+    case OVS_KEY_ATTR_VALID: return "valid"; \
+    \
+
+/* -- Used in lib/odp-util.c -- */
+#define OVS_FORMAT_ODP_KEY_ATTR_CASES \
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_non_virtual:
+    case OVS_KEY_ATTR_${header_name.upper()}: { \
+        break; \
+    } \
+//::  #endfor
+    case OVS_KEY_ATTR_VALID: { \
+        break; \
+    } \
+    \
+
+/* These are disabled to avoid spurious test failures. */
+#define OVS_FORMAT_ODP_KEY_ATTR_CASES_DISABLED \
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_non_virtual:
+    case OVS_KEY_ATTR_${header_name.upper()}: { \
+        const struct ovs_key_${header_name} *key = nl_attr_get(a); \
+        const struct ovs_key_${header_name} *mask = ma ? nl_attr_get(ma) : NULL; \
+        \
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+//::      if bit_width in [8, 16, 32, 64]:
+        format_u${bit_width}x(ds, "${field_name}", key->${field_name}, MASK(mask, ${field_name}), verbose); \
+//::      else:
+        format_bex(ds, "${field_name}", (const uint8_t *) &key->${field_name}, \
+                   mask ? (const uint8_t (*)[]) &mask->${field_name} : NULL, \
+                   sizeof(struct ${field_name}_t), verbose); \
+//::      #endif
+//::    #endfor
+        ds_chomp(ds, ','); \
+        break; \
+    } \
+//::  #endfor
+    case OVS_KEY_ATTR_VALID: { \
+        const struct ovs_key_valid *key = nl_attr_get(a); \
+        const struct ovs_key_valid *mask = ma ? nl_attr_get(ma) : NULL; \
+        \
+//::  for header_name in ordered_header_instances_regular:
+        format_u8x(ds, "${header_name}_valid", key->${header_name}_valid, MASK(mask, ${header_name}_valid), verbose); \
+//::  #endfor
+        ds_chomp(ds, ','); \
+        break; \
+    } \
+    \
+
+/* -- Used in lib/odp-util.c -- */
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_non_virtual:
+static void get_${header_name}_key(const struct flow *flow, struct ovs_key_${header_name} *${header_name});
+static void put_${header_name}_key(const struct ovs_key_${header_name} *${header_name}, struct flow *flow);
+
+//::  #endfor
+//::
+static void get_valid_key(const struct flow *flow, struct ovs_key_valid *valid);
+static void put_valid_key(const struct ovs_key_valid *valid, struct flow *flow);
+
+/* -- Used in lib/odp-util.c -- */
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_non_virtual:
+static void get_${header_name}_key(const struct flow *flow, struct ovs_key_${header_name} *${header_name})
+{
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+    ${header_name}->${field_name} = flow->${header_name}.hdr.${field_name};
+//::    #endfor
+}
+static void put_${header_name}_key(const struct ovs_key_${header_name} *${header_name}, struct flow *flow)
+{
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+    flow->${header_name}.hdr.${field_name} = ${header_name}->${field_name};
+//::    #endfor
+}
+
+//::  #endfor
+//::
+static void get_valid_key(const struct flow *flow, struct ovs_key_valid *valid)
+{
+//::  for header_name in ordered_header_instances_regular:
+    valid->${header_name}_valid = flow->valid.hdr.${header_name}_valid;
+//::  #endfor
+}
+static void put_valid_key(const struct ovs_key_valid *valid, struct flow *flow)
+{
+//::  for header_name in ordered_header_instances_regular:
+    flow->valid.hdr.${header_name}_valid = valid->${header_name}_valid;
+//::  #endfor
+}
+
+/* -- Used in lib/odp-util.c -- */
+//::  for header_name in ordered_header_instances_regular:
+static void commit_set_${header_name}_action(const struct flow *flow, struct flow *base_flow,
+               struct ofpbuf *odp_actions,
+               struct flow_wildcards *wc,
+               bool use_masked)
+{
+    struct ovs_key_${header_name} key, base, mask;
+
+    get_${header_name}_key(flow, &key);
+    get_${header_name}_key(base_flow, &base);
+    get_${header_name}_key(&wc->masks, &mask);
+
+    if (commit(OVS_KEY_ATTR_${header_name.upper()}, use_masked,
+        &key, &base, &mask, sizeof key, odp_actions)) {
+        put_${header_name}_key(&base, base_flow);
+        put_${header_name}_key(&mask, &wc->masks);
+    }
+}
+
+//::  #endfor
+//::
+static void commit_set_valid_action(const struct flow *flow, struct flow *base_flow,
+               struct ofpbuf *odp_actions,
+               struct flow_wildcards *wc,
+               bool use_masked)
+{
+    struct ovs_key_valid key, base, mask;
+
+    get_valid_key(flow, &key);
+    get_valid_key(base_flow, &base);
+    get_valid_key(&wc->masks, &mask);
+
+    if (commit(OVS_KEY_ATTR_VALID, use_masked,
+        &key, &base, &mask, sizeof key, odp_actions)) {
+            put_valid_key(&base, base_flow);
+            put_valid_key(&mask, &wc->masks);
+    }
+}
+
+/* -- Used in lib/odp-util.c -- */
+#define OVS_COMMIT_ODP_ACTIONS_FUNCS \
+//::  for header_name in ordered_header_instances_regular:
+    commit_set_${header_name}_action(flow, base, odp_actions, wc, use_masked); \
+//::  #endfor
+    commit_set_valid_action(flow, base, odp_actions, wc, use_masked); \
+    \
+
+/* -- Used in lib/odp-util.c -- */
+#define OVS_FLOW_KEY_ATTR_LENS \
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_non_virtual:
+    [OVS_KEY_ATTR_${header_name.upper()}] = { .len = sizeof(struct ovs_key_${header_name}) }, \
+//::  #endfor
+    [OVS_KEY_ATTR_VALID] = { .len = sizeof(struct ovs_key_valid) }, \
+    \
+
+/* -- Used in lib/odp-util.c -- */
+#define OVS_FLOW_KEY_FROM_FLOW \
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_non_virtual:
+    struct ovs_key_${header_name} *${header_name}; \
+    ${header_name} = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_${header_name.upper()}, sizeof *${header_name}); \
+    get_${header_name}_key(data, ${header_name}); \
+    \
+//::  #endfor
+    struct ovs_key_valid *valid; \
+    valid = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_VALID, sizeof *valid); \
+    get_valid_key(data, valid); \
+    \
+
+/* -- Used in lib/odp-util.c -- */
+#define OVS_FLOW_KEY_TO_FLOW \
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in ordered_header_instances_non_virtual:
+    if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_${header_name.upper()})) { \
+        const struct ovs_key_${header_name} *${header_name}; \
+        \
+        ${header_name} = nl_attr_get(attrs[OVS_KEY_ATTR_${header_name.upper()}]); \
+        put_${header_name}_key(${header_name}, flow); \
+        if (is_mask) { \
+            expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_${header_name.upper()}; \
+        } \
+    } \
+    if (!is_mask) { \
+        expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_${header_name.upper()}; \
+    } \
+    \
+//::  #endfor
+    if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_VALID)) { \
+        const struct ovs_key_valid *valid; \
+        \
+        valid = nl_attr_get(attrs[OVS_KEY_ATTR_VALID]); \
+        put_valid_key(valid, flow); \
+        if (is_mask) { \
+            expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_VALID; \
+        } \
+    } \
+    if (!is_mask) { \
+        expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_VALID; \
+    } \
+    \
+
+#endif	/* OVS_LIB_ODP_UTIL_C_H */
diff --git a/include/p4/plugin/ovs/lib/packets.c.h b/include/p4/plugin/ovs/lib/packets.c.h
new file mode 100644
index 0000000..d6657f6
--- /dev/null
+++ b/include/p4/plugin/ovs/lib/packets.c.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+//:: aligned_field_info = helpers.get_align_field_info(field_info, header_info, ordered_header_instances_all)
+//:: ordered_header_instances_non_virtual = helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual)
+//:: (_, ordered_header_instances_non_virtual_aligned_field__name_width) = helpers.get_ordered_header_and_aligned_field_instances_non_virtual__name_width(
+//::                                                                            ordered_header_instances_non_virtual,
+//::                                                                            header_info, aligned_field_info)
+
+#ifndef OVS_LIB_PACKETS_C_H
+#define	OVS_LIB_PACKETS_C_H 1
+
+//:: # NOTE: here we can benefit from annotations. For example, we can provide
+//:: # annotations in P4 to specify which fields can be set in the datapath.
+//::
+/* -- Used in lib/packets.c -- */
+//::  for header_name in ordered_header_instances_regular:
+void packet_set_${header_name}(
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+//::      if bit_width in [8, 16, 32, 64]:
+    uint${bit_width}_t ${field_name},
+//::      else:
+    struct ${field_name}_t ${field_name},
+//::      #endif
+//::    #endfor
+    struct dp_packet *packet)
+{
+    struct ${header_name}_header *${header_name} = dp_packet_${header_name}(packet);
+
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+    ${header_name}->${field_name} = ${field_name};
+//::    #endfor
+}
+
+//:: #endfor
+//::
+void packet_set_valid(
+//::  for header_name in ordered_header_instances_regular:
+    uint8_t ${header_name}_valid,
+//::  #endfor
+    struct dp_packet *packet)
+{
+//::  for header_name in ordered_header_instances_regular:
+    packet->${header_name}_valid = ${header_name}_valid;
+//::  #endfor
+}
+
+#endif	/* OVS_LIB_PACKETS_C_H */
diff --git a/include/p4/plugin/ovs/lib/packets.h.h b/include/p4/plugin/ovs/lib/packets.h.h
new file mode 100644
index 0000000..7e26099
--- /dev/null
+++ b/include/p4/plugin/ovs/lib/packets.h.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+//:: aligned_field_info = helpers.get_align_field_info(field_info, header_info, ordered_header_instances_all)
+//:: ordered_header_instances_non_virtual = helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual)
+//:: (_, ordered_header_instances_non_virtual_aligned_field__name_width) = helpers.get_ordered_header_and_aligned_field_instances_non_virtual__name_width(
+//::                                                                            ordered_header_instances_non_virtual,
+//::                                                                            header_info, aligned_field_info)
+
+#ifndef OVS_LIB_PACKETS_H_H
+#define	OVS_LIB_PACKETS_H_H 1
+
+//:: # NOTE: here we can benefit from annotations. For example, we can provide
+//:: # annotations in P4 to specify which fields can be set in the datapath.
+//::
+/* -- Used in lib/packets.h -- */
+//::  for header_name in ordered_header_instances_regular:
+void packet_set_${header_name}(
+//::    for field_name, bit_width in ordered_header_instances_non_virtual_aligned_field__name_width[header_name]:
+//::      if bit_width in [8, 16, 32, 64]:
+    uint${bit_width}_t ${field_name},
+//::      else:
+//::        # We assume that all fields are, at least, byte aligned.
+    struct ${field_name}_t ${field_name},
+//::      #endif
+//::    #endfor
+    struct dp_packet *packet);
+
+//::  #endfor
+void packet_set_valid(
+//::  for header_name in ordered_header_instances_regular:
+    uint8_t ${header_name}_valid,
+//::  #endfor
+    struct dp_packet *packet);
+
+#endif	/* OVS_LIB_PACKETS_H_H */
diff --git a/include/p4/plugin/ovs/ofproto/ofproto-dpif-sflow.c.h b/include/p4/plugin/ovs/ofproto/ofproto-dpif-sflow.c.h
new file mode 100644
index 0000000..3bf22d8
--- /dev/null
+++ b/include/p4/plugin/ovs/ofproto/ofproto-dpif-sflow.c.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 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.
+ */
+//::
+//:: import helpers
+
+#ifndef OVS_OFPROTO_OFPROTO_DPIF_SFLOW_C_H
+#define	OVS_OFPROTO_OFPROTO_DPIF_SFLOW_C_H 1
+
+/* -- Called in ofproto/ofproto-dpif-sflow.h -- */
+#define OVS_SFLOW_READ_SET_ACTION_CASES \
+//::  # TODO: remove metadata that is not touched in the parser.
+//::  for header_name in helpers.get_ordered_header_instances_non_virtual(ordered_header_instances_non_virtual):
+    case OVS_KEY_ATTR_${header_name.upper()}: \
+        break; \
+//::  #endfor
+    case OVS_KEY_ATTR_VALID: \
+        break; \
+    \
+
+#endif	/* OVS_OFPROTO_OFPROTO_DPIF_SFLOW_C_H */
diff --git a/include/p4/src/README.md b/include/p4/src/README.md
new file mode 100644
index 0000000..6f42a20
--- /dev/null
+++ b/include/p4/src/README.md
@@ -0,0 +1 @@
+These files are auto-generated by p4c-behavioral at build time.
\ No newline at end of file
diff --git a/lib/automake.mk b/lib/automake.mk
index 4d4ee01..665aaf8 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -475,10 +475,10 @@ lib/dirs.c: lib/dirs.c.in Makefile
 	     > lib/dirs.c.tmp && \
 	mv lib/dirs.c.tmp lib/dirs.c

-lib/meta-flow.inc: $(srcdir)/build-aux/extract-ofp-fields include/openvswitch/meta-flow.h
+lib/meta-flow.inc: $(srcdir)/build-aux/extract-ofp-fields include/openvswitch/meta-flow.h include/p4/src/include/openvswitch/meta-flow.h.h
 	$(AM_V_GEN)$(run_python) $^ --meta-flow > $@.tmp && mv $@.tmp $@
 lib/meta-flow.lo: lib/meta-flow.inc
-lib/nx-match.inc: $(srcdir)/build-aux/extract-ofp-fields include/openvswitch/meta-flow.h
+lib/nx-match.inc: $(srcdir)/build-aux/extract-ofp-fields include/openvswitch/meta-flow.h include/p4/src/include/openvswitch/meta-flow.h.h
 	$(AM_V_GEN)$(run_python) $^ --nx-match > $@.tmp && mv $@.tmp $@
 lib/nx-match.lo: lib/nx-match.inc
 CLEANFILES += lib/meta-flow.inc lib/nx-match.inc
diff --git a/lib/dp-packet.h b/lib/dp-packet.h
index 7c1e637..bf25949 100644
--- a/lib/dp-packet.h
+++ b/lib/dp-packet.h
@@ -24,6 +24,9 @@
 #include "util.h"
 #include "netdev-dpdk.h"

+// @P4:
+#include "p4/src/lib/dp-packet.h.h"
+
 #ifdef  __cplusplus
 extern "C" {
 #endif
@@ -53,6 +56,7 @@ struct dp_packet {
     bool rss_hash_valid;        /* Is the 'rss_hash' valid? */
 #endif
     enum dp_packet_source source;  /* Source of memory allocated as 'base'. */
+
     uint8_t l2_pad_size;           /* Detected l2 padding size.
                                     * Padding is non-pullable. */
     uint16_t l2_5_ofs;             /* MPLS label stack offset, or UINT16_MAX */
@@ -65,6 +69,9 @@ struct dp_packet {
         struct pkt_metadata md;
         uint64_t data[DP_PACKET_CONTEXT_SIZE / 8];
     };
+
+    // @P4:
+    OVS_HDR_ATTRS
 };

 static inline void *dp_packet_data(const struct dp_packet *);
@@ -275,6 +282,9 @@ dp_packet_reset_offsets(struct dp_packet *b)
     b->l4_ofs = UINT16_MAX;
 }

+// @P4:
+OVS_HDR_GET_DP_PACKET_OFS
+
 static inline uint8_t
 dp_packet_l2_pad_size(const struct dp_packet *b)
 {
diff --git a/lib/flow.c b/lib/flow.c
index a4c1215..6cb38b2 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -40,6 +40,9 @@
 #include "random.h"
 #include "unaligned.h"

+// @P4:
+#include "p4/src/lib/flow.c.h"
+
 COVERAGE_DEFINE(flow_extract);
 COVERAGE_DEFINE(miniflow_malloc);

@@ -261,6 +264,15 @@ BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime "
     MF.data += (N_WORDS);                                       \
 }

+/* @P4: Data in 'valuep' may be unaligned. */
+#define miniflow_push_bytes_word_aligned_64_(MF, OFS, VALUEP, N_BYTES, N_WORDS) \
+{                                                                                \
+    MINIFLOW_ASSERT((OFS) % 8 == 0);                                             \
+    miniflow_set_maps(MF, (OFS) / 8, (N_WORDS));                                 \
+    memcpy(MF.data, (VALUEP), N_BYTES);                                          \
+    MF.data += (N_WORDS);                                                        \
+}
+
 /* Push 32-bit words padded to 64-bits. */
 #define miniflow_push_words_32_(MF, OFS, VALUEP, N_WORDS)               \
 {                                                                       \
@@ -305,6 +317,10 @@ BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime "
 #define miniflow_push_words(MF, FIELD, VALUEP, N_WORDS)                 \
     miniflow_push_words_(MF, offsetof(struct flow, FIELD), VALUEP, N_WORDS)

+// @P4:
+#define miniflow_push_bytes_word_aligned_64(MF, FIELD, VALUEP, N_BYTES, N_WORDS)              \
+    miniflow_push_bytes_word_aligned_64_(MF, offsetof(struct flow, FIELD), VALUEP, N_BYTES, N_WORDS)
+
 #define miniflow_push_words_32(MF, FIELD, VALUEP, N_WORDS)              \
     miniflow_push_words_32_(MF, offsetof(struct flow, FIELD), VALUEP, N_WORDS)

@@ -482,6 +498,7 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
     struct mf_ctx mf = { FLOWMAP_EMPTY_INITIALIZER, values,
                          values + FLOW_U64S };
     const char *l2;
+
     ovs_be16 dl_type;
     uint8_t nw_frag, nw_tos, nw_ttl, nw_proto;

@@ -806,7 +823,17 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
             }
         }
     }
- out:
+
+out:
+    // P4:
+    data = dp_packet_data(packet);
+    size = dp_packet_size(packet);
+    l2 = data;
+    OVS_HDR_RESET_ATTRS
+    OVS_MINIFLOW_EXTRACT_METADATA_DEFS /* TODO: see if these can be moved outside the extract function. */
+    OVS_MINIFLOW_EXTRACT
+
+out_:
     dst->map = mf.map;
 }

@@ -1293,6 +1320,9 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
     WC_MASK_FIELD(wc, dp_hash);
     WC_MASK_FIELD(wc, in_port);

+    // @P4:
+    OVS_FLOW_WC_MASK
+
     /* actset_output wildcarded. */

     WC_MASK_FIELD(wc, dl_dst);
@@ -1397,6 +1427,9 @@ flow_wc_map(const struct flow *flow, struct flowmap *map)
     FLOWMAP_SET(map, ct_mark);
     FLOWMAP_SET(map, ct_label);

+    // @P4:
+    OVS_FLOW_WC_MAP
+
     /* Ethertype-dependent fields. */
     if (OVS_LIKELY(flow->dl_type == htons(ETH_TYPE_IP))) {
         FLOWMAP_SET(map, nw_src);
diff --git a/lib/match.c b/lib/match.c
index db78831..bdc71a6 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -25,6 +25,9 @@
 #include "packets.h"
 #include "tun-metadata.h"

+// @P4:
+#include "p4/src/lib/match.c.h"
+
 /* Converts the flow in 'flow' into a match in 'match', with the given
  * 'wildcards'. */
 void
@@ -931,6 +934,46 @@ format_uint16_masked(struct ds *s, const char *name,
     }
 }

+// @P4:
+static void OVS_UNUSED
+format_bex_masked(struct ds *s, const char *name,
+                  const uint8_t *value, const uint8_t *mask, size_t n_bytes)
+{
+    if (!is_all_zeros(mask, n_bytes)) {
+        ds_put_format(s, "%s%s=%s", colors.param, name, colors.end);
+
+        int i;
+
+        ds_put_format(s, "0x""%02"PRIx8, value[0]);
+        for (i = 1; i < n_bytes; i++) {
+            ds_put_format(s, "%02"PRIx8, value[i]);
+        }
+        ds_put_format(s, "/0x""%02"PRIx8, mask[0]);
+        for (i = 1; i < n_bytes; i++) {
+            ds_put_format(s, "%02"PRIx8, mask[i]);
+        }
+
+        ds_put_char(s, ',');
+    }
+}
+
+// @P4:
+static void OVS_UNUSED
+format_be8_masked(struct ds *s, const char *name,
+                  uint8_t value, uint8_t mask)
+{
+    if (mask != 0) {
+        ds_put_format(s, "%s%s=%s", colors.param, name, colors.end);
+        if (mask == 0xff) {
+            ds_put_format(s, "%"PRIu8, value);
+        } else {
+            ds_put_format(s, "0x%"PRIx8"/0x%"PRIx8,
+                          value, mask);
+        }
+        ds_put_char(s, ',');
+    }
+}
+
 static void
 format_be16_masked(struct ds *s, const char *name,
                    ovs_be16 value, ovs_be16 mask)
@@ -1122,6 +1165,9 @@ match_format(const struct match *match, struct ds *s, int priority)
         format_ct_label_masked(s, &f->ct_label, &wc->masks.ct_label);
     }

+    // @P4:
+    OVS_MATCH_FORMAT
+
     if (wc->masks.dl_type) {
         skip_type = true;
         if (f->dl_type == htons(ETH_TYPE_IP)) {
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index e160de1..26ac50f 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -38,6 +38,9 @@
 #include "openvswitch/ofp-errors.h"
 #include "openvswitch/vlog.h"

+// @P4:
+#include "p4/src/lib/meta-flow.c.h"
+
 VLOG_DEFINE_THIS_MODULE(meta_flow);

 #define FLOW_U32OFS(FIELD)                                              \
@@ -325,6 +328,9 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
     case MFF_TCP_FLAGS:
         return !wc->masks.tcp_flags;

+    // @P4:
+    OVS_IS_ALL_WILD_CASES
+
     case MFF_N_IDS:
     default:
         OVS_NOT_REACHED();
@@ -556,6 +562,9 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
     case MFF_ND_TLL:
         return true;

+    // @P4:
+    OVS_IS_VALUE_VALID_CASES
+
     case MFF_IN_PORT_OXM:
     case MFF_ACTSET_OUTPUT: {
         ofp_port_t port;
@@ -845,6 +854,9 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
         value->ipv6 = flow->nd_target;
         break;

+    // @P4:
+    OVS_GET_VALUE_CASES
+
     case MFF_N_IDS:
     default:
         OVS_NOT_REACHED();
@@ -1103,6 +1115,9 @@ mf_set_value(const struct mf_field *mf,
         match_set_nd_target(match, &value->ipv6);
         break;

+    // @P4:
+    OVS_SET_VALUE_CASES
+
     case MFF_N_IDS:
     default:
         OVS_NOT_REACHED();
@@ -1416,6 +1431,9 @@ mf_set_flow_value(const struct mf_field *mf,
         flow->nd_target = value->ipv6;
         break;

+    // @P4:
+    OVS_SET_FLOW_VALUE_CASES
+
     case MFF_N_IDS:
     default:
         OVS_NOT_REACHED();
@@ -1740,6 +1758,9 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
         memset(&match->flow.nd_target, 0, sizeof match->flow.nd_target);
         break;

+    // @P4:
+    OVS_SET_WILD_CASES
+
     case MFF_N_IDS:
     default:
         OVS_NOT_REACHED();
@@ -1963,6 +1984,9 @@ mf_set(const struct mf_field *mf,
         match_set_tcp_flags_masked(match, value->be16, mask->be16);
         break;

+    // @P4:
+    OVS_SET_CASES
+
     case MFF_N_IDS:
     default:
         OVS_NOT_REACHED();
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 9a2ada9..088e882 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -37,6 +37,9 @@
 #include "unaligned.h"
 #include "util.h"

+// @P4:
+#include "p4/src/lib/nx-match.c.h"
+
 VLOG_DEFINE_THIS_MODULE(nx_match);

 /* OXM headers.
@@ -1070,6 +1073,9 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
     nxm_put_64m(b, MFF_METADATA, oxm,
                 flow->metadata, match->wc.masks.metadata);

+    // @P4:
+    OVS_MATCH_PUT_RAW
+
     /* Cookie. */
     if (cookie_mask) {
         bool masked = cookie_mask != OVS_BE64_MAX;
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 5a43904..e96242f 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -34,6 +34,9 @@
 #include "unaligned.h"
 #include "util.h"

+// @P4:
+#include "p4/src/lib/odp-execute.c.h"
+
 /* Masked copy of an ethernet address. 'src' is already properly masked. */
 static void
 ether_addr_copy_masked(struct eth_addr *dst, const struct eth_addr src,
@@ -326,6 +329,9 @@ odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a)
         md->recirc_id = nl_attr_get_u32(a);
         break;

+    // @P4:
+    OVS_ODP_EXECUTE_SET_ACTION_CASES
+
     case OVS_KEY_ATTR_UNSPEC:
     case OVS_KEY_ATTR_ENCAP:
     case OVS_KEY_ATTR_ETHERTYPE:
@@ -422,6 +428,9 @@ odp_execute_masked_set_action(struct dp_packet *packet,
             | (md->recirc_id & ~*get_mask(a, uint32_t));
         break;

+    // @P4:
+    OVS_ODP_EXECUTE_MASKED_SET_ACTION_CASES
+
     case OVS_KEY_ATTR_TUNNEL:    /* Masked data not supported for tunnel. */
     case OVS_KEY_ATTR_UNSPEC:
     case OVS_KEY_ATTR_CT_STATE:
diff --git a/lib/odp-util.c b/lib/odp-util.c
index fd1ca9b..4916cd7 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -44,6 +44,14 @@

 VLOG_DEFINE_THIS_MODULE(odp_util);

+static bool
+commit(enum ovs_key_attr attr, bool use_masked_set,
+       const void *key, void *base, void *mask, size_t size,
+       struct ofpbuf *odp_actions);
+
+// @P4:
+#include "p4/src/lib/odp-util.c.h"
+
 /* The interface between userspace and kernel uses an "OVS_*" prefix.
  * Since this is fairly non-specific for the OVS userspace components,
  * "ODP_*" (Open vSwitch Datapath) is used as the prefix for
@@ -165,6 +173,9 @@ ovs_key_attr_to_string(enum ovs_key_attr attr, char *namebuf, size_t bufsize)
     case OVS_KEY_ATTR_DP_HASH: return "dp_hash";
     case OVS_KEY_ATTR_RECIRC_ID: return "recirc_id";

+    // @P4:
+    OVS_KEY_ATTRS_TO_STRING_CASES
+
     case __OVS_KEY_ATTR_MAX:
     default:
         snprintf(namebuf, bufsize, "key%u", (unsigned int) attr);
@@ -1804,6 +1815,9 @@ static const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] =
     [OVS_KEY_ATTR_CT_ZONE]   = { .len = 2 },
     [OVS_KEY_ATTR_CT_MARK]   = { .len = 4 },
     [OVS_KEY_ATTR_CT_LABELS] = { .len = sizeof(struct ovs_key_ct_labels) },
+
+    // @P4:
+    OVS_FLOW_KEY_ATTR_LENS
 };

 /* Returns the correct length of the payload for a flow key attribute of the
@@ -2155,6 +2169,69 @@ format_be64(struct ds *ds, const char *name, ovs_be64 key,
     }
 }

+// @P4:
+static void OVS_UNUSED
+format_bex(struct ds *ds, const char *name, const uint8_t *key,
+           const uint8_t (*mask)[], size_t n_bytes, bool verbose)
+{
+    bool mask_empty = mask && is_all_zeros(*mask, n_bytes);
+
+    if (verbose || !mask_empty) {
+        int i;
+        bool mask_is_exact = mask && is_all_ones(*mask, n_bytes);
+        bool mask_full = !mask || mask_is_exact;
+
+        ds_put_format(ds, "%s=0x""%02"PRIx8, name, key[0]);
+        for (i = 1; i < n_bytes; i++) {
+            ds_put_format(ds, "%02"PRIx8, key[i]);
+        }
+
+        if (!mask_full) {
+            ds_put_format(ds, "/0x""%02"PRIx8, (*mask)[0]);
+            for (i = 1; i < n_bytes; i++) {
+                ds_put_format(ds, "%02"PRIx8, (*mask)[i]);
+            }
+        }
+        ds_put_char(ds, ',');
+    }
+}
+
+// @P4:
+static void OVS_UNUSED
+format_be32x(struct ds *ds, const char *name, ovs_be32 key,
+             const ovs_be32 *mask, bool verbose)
+{
+    bool mask_empty = mask && !*mask;
+
+    if (verbose || !mask_empty) {
+        bool mask_full = !mask || *mask == OVS_BE32_MAX;
+
+        ds_put_format(ds, "%s=%"PRIx32, name, ntohl(key));
+        if (!mask_full) { /* Partially masked. */
+            ds_put_format(ds, "/%#"PRIx32, ntohl(*mask));
+        }
+        ds_put_char(ds, ',');
+    }
+}
+
+// @P4:
+static void OVS_UNUSED
+format_be64x(struct ds *ds, const char *name, ovs_be64 key,
+             const ovs_be64 *mask, bool verbose)
+{
+    bool mask_empty = mask && !*mask;
+
+    if (verbose || !mask_empty) {
+        bool mask_full = !mask || *mask == OVS_BE64_MAX;
+
+        ds_put_format(ds, "%s=0x%"PRIx64, name, ntohll(key));
+        if (!mask_full) { /* Partially masked. */
+            ds_put_format(ds, "/%#"PRIx64, ntohll(*mask));
+        }
+        ds_put_char(ds, ',');
+    }
+}
+
 static void
 format_ipv4(struct ds *ds, const char *name, ovs_be32 key,
             const ovs_be32 *mask, bool verbose)
@@ -2932,6 +3009,10 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
         ds_chomp(ds, ',');
         break;
     }
+
+    // @P4:
+    OVS_FORMAT_ODP_KEY_ATTR_CASES
+
     case OVS_KEY_ATTR_UNSPEC:
     case __OVS_KEY_ATTR_MAX:
     default:
@@ -4065,6 +4146,9 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,

     SCAN_SINGLE_PORT("in_port(", uint32_t, OVS_KEY_ATTR_IN_PORT);

+    // @P4:
+    // TODO: add logic for scanning here. (Ask Ben)
+
     SCAN_BEGIN("eth(", struct ovs_key_ethernet) {
         SCAN_FIELD("src=", eth, eth_src);
         SCAN_FIELD("dst=", eth, eth_dst);
@@ -4308,6 +4392,9 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms,
         nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, data->in_port.odp_port);
     }

+    // @P4:
+    OVS_FLOW_KEY_FROM_FLOW
+
     eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ETHERNET,
                                        sizeof *eth_key);
     get_ethernet_key(data, eth_key);
@@ -5161,6 +5248,9 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len,
         flow->in_port.odp_port = ODPP_NONE;
     }

+    // @P4:
+    OVS_FLOW_KEY_TO_FLOW
+
     /* Ethernet header. */
     if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ETHERNET)) {
         const struct ovs_key_ethernet *eth_key;
@@ -5947,5 +6037,8 @@ commit_odp_actions(const struct flow *flow, struct flow *base,
     commit_set_priority_action(flow, base, odp_actions, wc, use_masked);
     commit_set_pkt_mark_action(flow, base, odp_actions, wc, use_masked);

+    // @P4:
+    OVS_COMMIT_ODP_ACTIONS_FUNCS
+
     return slow1 ? slow1 : slow2;
 }
diff --git a/lib/packets.c b/lib/packets.c
index a27264c..8c58282 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -33,6 +33,9 @@
 #include "dp-packet.h"
 #include "unaligned.h"

+// @P4:
+#include "p4/src/lib/packets.c.h"
+
 const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT;
 const struct in6_addr in6addr_all_hosts = IN6ADDR_ALL_HOSTS_INIT;

diff --git a/lib/packets.h b/lib/packets.h
index 077ccfa..012d529 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -35,6 +35,9 @@
 struct dp_packet;
 struct ds;

+// @P4:
+#include "p4/src/lib/packets.h.h"
+
 /* Purely internal to OVS userspace. These flags should never be exposed to
  * the outside world and so aren't included in the flags mask. */

diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index 7d0aa36..b256ebc 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -44,6 +44,9 @@
 #include "ofproto-provider.h"
 #include "lacp.h"

+// @P4:
+#include "p4/src/ofproto/ofproto-dpif-sflow.c.h"
+
 VLOG_DEFINE_THIS_MODULE(sflow);

 static struct ovs_mutex mutex;
@@ -1026,6 +1029,9 @@ sflow_read_set_action(const struct nlattr *attr,
         }
         break;

+    // @P4:
+	OVS_SFLOW_READ_SET_ACTION_CASES
+
     case OVS_KEY_ATTR_TCP_FLAGS:
     case OVS_KEY_ATTR_ICMP:
     case OVS_KEY_ATTR_ICMPV6:
