This adds necessary changes in the OVS codebase to consume the C (macro) code
generated by the OVS plugin in p4c-behavioral. It also updates the OVS build
system to take a P4 program as input at 'configure' time.

---
 acinclude.m4                                      |  17 +++
 build-aux/extract-ofp-actions                     |   4 +-
 build-aux/extract-ofp-fields                      |  99 ++++++++++-----
 configure.ac                                      |   1 +
 datapath/linux/compat/include/linux/openvswitch.h |  10 ++
 include/automake.mk                               |   1 +
 include/openvswitch/flow.h                        |   8 ++
 include/openvswitch/meta-flow.h                   |   5 +
 include/openvswitch/packets.h                     |   6 +
 include/openvswitch/types.h                       |   6 +
 include/p4/automake.mk                            |   3 +
 include/p4/examples/l2_switch.p4                  |  89 ++++++++++++++
 include/p4/examples/simple_router.p4              | 143 ++++++++++++++++++++++
 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                                 |  12 ++
 lib/odp-util.c                                    |  97 ++++++++++++++-
 lib/packets.c                                     |   6 +
 lib/packets.h                                     |   6 +
 ofproto/ofproto-dpif-sflow.c                      |   6 +
 24 files changed, 604 insertions(+), 40 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

diff --git a/acinclude.m4 b/acinclude.m4
index bb0d90a..d258c36 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -265,6 +265,23 @@ 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])
+  AC_ARG_VAR([p4outputdir], [Specify the p4 output directory])
+  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])])
+  AS_IF([test -z "$p4outputdir"],
+        [AC_MSG_ERROR([missing arguments for p4 output dir])])
+  AS_IF([test -d "$p4outputdir"], [rm -rf $p4outputdir], [])
+
+  mkdir -p $p4outputdir
+  p4c-behavioral $p4inputfile --gen-dir $p4outputdir/temp --plugin ovs
+  mv $p4outputdir/temp/plugin/ovs/inc/* $p4outputdir
+  rm -rf $p4outputdir/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..3f7a169 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
 };

@@ -489,6 +496,9 @@ struct ovs_key_ct_labels {

 #define OVS_CS_F_NAT_MASK (OVS_CS_F_SRC_NAT | OVS_CS_F_DST_NAT)

+// @P4:
+OVS_KEY_STRUCTS
+
 /**
  * enum ovs_flow_attr - attributes for %OVS_FLOW_* commands.
  * @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow
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..d6ccfcb 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;
@@ -61,4 +64,7 @@ union flow_in_port {
     ofp_port_t ofp_port;
 };

+// @P4:
+OVS_HDR_STRUCTS
+
 #endif /* packets.h */
diff --git a/include/openvswitch/types.h b/include/openvswitch/types.h
index bc94145..ee5e9d2 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))
@@ -147,4 +150,7 @@ struct eth_addr {
     };
 };

+// @P4:
+OVS_FIELD_STRUCTS
+
 #endif /* openvswitch/types.h */
diff --git a/include/p4/automake.mk b/include/p4/automake.mk
new file mode 100644
index 0000000..2918b58
--- /dev/null
+++ b/include/p4/automake.mk
@@ -0,0 +1,3 @@
+EXTRA_DIST += \
+       include/p4/examples/l2_switch.p4 \
+       include/p4/examples/simple_router.p4
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/lib/automake.mk b/lib/automake.mk
index 4d4ee01..665aaf8 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -475,10 +475,10 @@ lib/dirs.c: lib/dirs.c.in Makefile
             > lib/dirs.c.tmp && \
        mv lib/dirs.c.tmp lib/dirs.c

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+// @P4:
+#include "p4/src/lib/odp-execute.c.h"
+
 /* Masked copy of an ethernet address. 'src' is already properly masked. */
 static void
 ether_addr_copy_masked(struct eth_addr *dst, const struct eth_addr src,
@@ -222,6 +225,9 @@ odp_set_nd(struct dp_packet *packet, const struct 
ovs_key_nd *key,
     }
 }

+// @P4:
+OVS_ODP_SET_ACTION_FUNCS
+
 static void
 odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a)
 {
@@ -326,6 +332,9 @@ odp_execute_set_action(struct dp_packet *packet, const 
struct nlattr *a)
         md->recirc_id = nl_attr_get_u32(a);
         break;

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

+    // @P4:
+    OVS_ODP_EXECUTE_MASKED_SET_ACTION_CASES
+
     case OVS_KEY_ATTR_TUNNEL:    /* Masked data not supported for tunnel. */
     case OVS_KEY_ATTR_UNSPEC:
     case OVS_KEY_ATTR_CT_STATE:
diff --git a/lib/odp-util.c b/lib/odp-util.c
index fd1ca9b..7127884 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -42,6 +42,9 @@
 #include "uuid.h"
 #include "openvswitch/vlog.h"

+// @P4:
+#include "p4/src/lib/odp-util.c.h"
+
 VLOG_DEFINE_THIS_MODULE(odp_util);

 /* The interface between userspace and kernel uses an "OVS_*" prefix.
@@ -165,6 +168,9 @@ ovs_key_attr_to_string(enum ovs_key_attr attr, char 
*namebuf, size_t bufsize)
     case OVS_KEY_ATTR_DP_HASH: return "dp_hash";
     case OVS_KEY_ATTR_RECIRC_ID: return "recirc_id";

+    // @P4:
+    OVS_KEY_ATTRS_TO_STRING_CASES
+
     case __OVS_KEY_ATTR_MAX:
     default:
         snprintf(namebuf, bufsize, "key%u", (unsigned int) attr);
@@ -1644,7 +1650,7 @@ parse_odp_action(const char *s, const struct simap 
*port_names,
         nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_VLAN);
         return 8;
     }
-
+
     {
         double percentage;
         int n = -1;
@@ -1804,6 +1810,9 @@ static const struct attr_len_tbl 
ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] =
     [OVS_KEY_ATTR_CT_ZONE]   = { .len = 2 },
     [OVS_KEY_ATTR_CT_MARK]   = { .len = 4 },
     [OVS_KEY_ATTR_CT_LABELS] = { .len = sizeof(struct ovs_key_ct_labels) },
+
+    // @P4:
+    OVS_FLOW_KEY_ATTR_LENS
 };

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

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

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

+    // @P4:
+    // TODO: add logic for scanning here. (Ask Ben)
+
     SCAN_BEGIN("eth(", struct ovs_key_ethernet) {
         SCAN_FIELD("src=", eth, eth_src);
         SCAN_FIELD("dst=", eth, eth_dst);
@@ -4255,6 +4334,9 @@ static void put_arp_key(const struct ovs_key_arp *, 
struct flow *);
 static void get_nd_key(const struct flow *, struct ovs_key_nd *);
 static void put_nd_key(const struct ovs_key_nd *, struct flow *);

+// @P4:
+OVS_SET_FUNC_DECLS
+
 /* These share the same layout. */
 union ovs_key_tp {
     struct ovs_key_tcp tcp;
@@ -4308,6 +4390,9 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms 
*parms,
         nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, data->in_port.odp_port);
     }

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

+    // @P4:
+    OVS_FLOW_KEY_TO_FLOW
+
     /* Ethernet header. */
     if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ETHERNET)) {
         const struct ovs_key_ethernet *eth_key;
@@ -5922,6 +6010,10 @@ commit_set_pkt_mark_action(const struct flow *flow, 
struct flow *base_flow,
     }
 }

+// @P4:
+OVS_SET_FUNC_DEFS
+OVS_COMMIT_ACTION_FUNCS
+
 /* If any of the flow key data that ODP actions can modify are different in
  * 'base' and 'flow', appends ODP actions to 'odp_actions' that change the flow
  * key from 'base' into 'flow', and then changes 'base' the same way.  Does not
@@ -5947,5 +6039,8 @@ commit_odp_actions(const struct flow *flow, struct flow 
*base,
     commit_set_priority_action(flow, base, odp_actions, wc, use_masked);
     commit_set_pkt_mark_action(flow, base, odp_actions, wc, use_masked);

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

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

@@ -1441,3 +1444,6 @@ IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6)
         }
     }
 }
+
+// @P4:
+OVS_HDR_DEFS
\ No newline at end of file
diff --git a/lib/packets.h b/lib/packets.h
index 077ccfa..082e90f 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -32,6 +32,9 @@
 #include "unaligned.h"
 #include "util.h"

+// @P4:
+#include "p4/src/lib/packets.h.h"
+
 struct dp_packet;
 struct ds;

@@ -1076,4 +1079,7 @@ void compose_na(struct dp_packet *,
 uint32_t packet_csum_pseudoheader(const struct ip_header *);
 void IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6);

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

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

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

+    // @P4:
+       OVS_SFLOW_READ_SET_ACTION_CASES
+
     case OVS_KEY_ATTR_TCP_FLAGS:
     case OVS_KEY_ATTR_ICMP:
     case OVS_KEY_ATTR_ICMPV6:
--
2.7.4 (Apple Git-66)
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to