[ovs-dev] [PATCH v2] Introducing support for P4 in OVS

Ben Pfaff blp at ovn.org
Fri Oct 14 00:05:17 UTC 2016


Thanks for sending v2.

I think that the changes to extract-ofp-actions are white-space only and
can be dropped.

I spent a lot of time this afternoon playing with the build system.
Running p4c-behavioral once at configure time is not a great way to
go.  Furthermore, it's a pain to have all these files in a separate
directory that's walled off from the main code.  I think that we can do
better.  So I pushed this branch:
        https://github.com/blp/ovs-reviews/tree/p4-2
which adds a commit to demonstrate a different approach.  The basic idea
is to teach the build system to run any file whose name ends in .p4c
through p4c-behavioral regardless of where it occurs in the tree.
p4c-behavioral isn't well suited for this so I had to write a script
(preprocess-p4) to make it possible.  I included a demo use of the idea
for just include/openvswitch/flow.h.  You can probably see how this is
easier to follow than the indirection through a separate directory plus
an extra nested #include.

I'll certainly have other comments, but I spent all afternoon on this
and I'm out of time for the day.

What do you think of this approach?  It's an incomplete conversion for
now, of course, so the tree doesn't build.

On Sat, Oct 08, 2016 at 02:12:11AM -0500, Muhammad Shahbaz wrote:
> This is a follow-up patch with changes proposed by Ben Pfaff in an earlier thread,
> "[PATCH 1/2] adding P4 support." This patch doesn't contain changes for the
> microflow cache; those will be posted later.
> 
> Following changes have been addressed:
> 
> 1. All ovs-related code is now in under the include/p4/plugin directory.
> p4c-behavioral reads this code using the --plugin-path flag. Also, no changes
> are needed in the p4c-behvaioral repository now.
> 2. Identifier names no longer begin with a leading "_."
> 3. Dropping macro definitions for headers for better readability.
> 4. Unified code for repetitive 8/16/32/64 bit cases.
> 5. Replaced OXM_OF_* with NXOXM_ET_*.
> 6. Only fields with valid headers are now masked.
> 7. Code refactoring to remove repetition and to improve readability.
> 
> Remaining changes, from the earlier thread, that still need to be addressed are:
> 
> 1. Removing duplicate parsing and integrating resets into dp_packet_reset_offsets().
> 2. Inlining packet_set__*() functions.
> 3. Come up with a compact representation of valid bits for the headers.
> 
> Signed-off-by: Muhammad Shahbaz <mshahbaz at cs.princeton.edu>
> ---
>  acinclude.m4                                       |  14 +
>  build-aux/extract-ofp-actions                      |   4 +-
>  build-aux/extract-ofp-fields                       |  99 +++--
>  configure.ac                                       |   1 +
>  datapath/linux/compat/include/linux/openvswitch.h  |   7 +
>  include/automake.mk                                |   1 +
>  include/openvswitch/flow.h                         |   8 +
>  include/openvswitch/meta-flow.h                    |   5 +
>  include/openvswitch/packets.h                      |   3 +
>  include/openvswitch/types.h                        |   3 +
>  include/p4/automake.mk                             |  20 +
>  include/p4/examples/l2-switch.p4                   |  89 ++++
>  include/p4/examples/simple-router.p4               | 143 +++++++
>  include/p4/plugin/helpers.py                       |  91 ++++
>  .../linux/compat/include/linux/openvswitch.h.h     |  56 +++
>  include/p4/plugin/ovs/include/openvswitch/flow.h.h |  30 ++
>  .../plugin/ovs/include/openvswitch/meta-flow.h.h   |  77 ++++
>  .../p4/plugin/ovs/include/openvswitch/packets.h.h  |  84 ++++
>  .../p4/plugin/ovs/include/openvswitch/types.h.h    |  36 ++
>  include/p4/plugin/ovs/lib/dp-packet.h.h            |  46 +++
>  include/p4/plugin/ovs/lib/flow.c.h                 | 457 +++++++++++++++++++++
>  include/p4/plugin/ovs/lib/match.c.h                |  53 +++
>  include/p4/plugin/ovs/lib/meta-flow.c.h            | 185 +++++++++
>  include/p4/plugin/ovs/lib/nx-match.c.h             |  52 +++
>  include/p4/plugin/ovs/lib/odp-execute.c.h          | 123 ++++++
>  include/p4/plugin/ovs/lib/odp-util.c.h             | 227 ++++++++++
>  include/p4/plugin/ovs/lib/packets.c.h              |  62 +++
>  include/p4/plugin/ovs/lib/packets.h.h              |  50 +++
>  .../p4/plugin/ovs/ofproto/ofproto-dpif-sflow.c.h   |  33 ++
>  include/p4/src/README.md                           |   1 +
>  lib/automake.mk                                    |   4 +-
>  lib/dp-packet.h                                    |  10 +
>  lib/flow.c                                         |  35 +-
>  lib/match.c                                        |  46 +++
>  lib/meta-flow.c                                    |  24 ++
>  lib/nx-match.c                                     |   6 +
>  lib/odp-execute.c                                  |   9 +
>  lib/odp-util.c                                     |  93 +++++
>  lib/packets.c                                      |   3 +
>  lib/packets.h                                      |   3 +
>  ofproto/ofproto-dpif-sflow.c                       |   6 +
>  41 files changed, 2260 insertions(+), 39 deletions(-)
>  create mode 100644 include/p4/automake.mk
>  create mode 100644 include/p4/examples/l2-switch.p4
>  create mode 100644 include/p4/examples/simple-router.p4
>  create mode 100644 include/p4/plugin/helpers.py
>  create mode 100644 include/p4/plugin/ovs/datapath/linux/compat/include/linux/openvswitch.h.h
>  create mode 100644 include/p4/plugin/ovs/include/openvswitch/flow.h.h
>  create mode 100644 include/p4/plugin/ovs/include/openvswitch/meta-flow.h.h
>  create mode 100644 include/p4/plugin/ovs/include/openvswitch/packets.h.h
>  create mode 100644 include/p4/plugin/ovs/include/openvswitch/types.h.h
>  create mode 100644 include/p4/plugin/ovs/lib/dp-packet.h.h
>  create mode 100644 include/p4/plugin/ovs/lib/flow.c.h
>  create mode 100644 include/p4/plugin/ovs/lib/match.c.h
>  create mode 100644 include/p4/plugin/ovs/lib/meta-flow.c.h
>  create mode 100644 include/p4/plugin/ovs/lib/nx-match.c.h
>  create mode 100644 include/p4/plugin/ovs/lib/odp-execute.c.h
>  create mode 100644 include/p4/plugin/ovs/lib/odp-util.c.h
>  create mode 100644 include/p4/plugin/ovs/lib/packets.c.h
>  create mode 100644 include/p4/plugin/ovs/lib/packets.h.h
>  create mode 100644 include/p4/plugin/ovs/ofproto/ofproto-dpif-sflow.c.h
>  create mode 100644 include/p4/src/README.md
> 
> 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:
> --
> 2.8.4 (Apple Git-73)
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev



More information about the dev mailing list