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).
> > > +//::              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.${
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to