Hi Ben,

I have done some initial testing using the l2_switch.p4 program, and it
builds and works correctly. I can now match using the generated fields and
can route traffic based on these fields. Also, I think, we can now remove
the include/p4/src folder, as it's no longer needed.

At the moment, we are running both the legacy parser and the new parser,
generated using P4, in miniflow_extract. It seems like the next step is to
remove this legacy parser and fields from 'flow' struct and replace them
with the P4 generated fields. It requires replacing explicit references to
these legacy fields at different places in the code, i.e., in bfd.c, cfm.c,
and more, with the P4 fields. I'm working on a patch for this and will
share on the dev-list, soon.

Thanks,
Shahbaz

On Fri, Oct 14, 2016 at 8:56 PM Muhammad Shahbaz <mshah...@cs.princeton.edu>
wrote:

> Hi Ben,
>
> That's great! Thanks for the new set of changes to the new approach.
>
> I have looked at the changes and, I agree, it makes more sense to have
> template files inline with theOVS source code rather than having them
> under a separate folder. I like the new approach for P4, much cleaner.
>
> I will build and test it myself and let you know if I see any issues.
>
> Cheers,
> Shahbaz
>
>
> On Fri, Oct 14, 2016 at 8:00 PM Ben Pfaff <b...@ovn.org> wrote:
>
> I finished changing the build system to use the new approach.  It's on
> the same branch as before (force-pushed over the previous version).
>
> It builds, I haven't tried running it yet.
>
> On Thu, Oct 13, 2016 at 05:05:17PM -0700, Ben Pfaff wrote:
> > 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 <mshah...@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).
> > >
>
>
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to