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 > [email protected] && mv [email protected] $@
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 > [email protected] && mv [email protected] $@
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
[email protected]
http://openvswitch.org/mailman/listinfo/dev