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