Added tor.p4 to p4src
Change-Id: I8c3a02dee76cbe45e0f9a4f7ca1f93a6f1d8a016
diff --git a/tools/test/p4src/tor/class_id.p4 b/tools/test/p4src/tor/class_id.p4
new file mode 100644
index 0000000..326dce7
--- /dev/null
+++ b/tools/test/p4src/tor/class_id.p4
@@ -0,0 +1,54 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for a Class ID assignment table.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#ifndef P4_SPEC_CLASS_ID_P4_
+#define P4_SPEC_CLASS_ID_P4_
+
+#include "headers.p4"
+#include "parser.p4"
+
+//------------------------------------------------------------------------------
+// Packet Classification
+//------------------------------------------------------------------------------
+
+control class_id(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+
+ @proto_package("class_id")
+ action set_class_id(@proto_tag(1) bit<8> class_id_value) {
+ local_metadata.class_id = class_id_value;
+ }
+
+ @proto_package("class_id")
+ table class_id_assignment_table {
+ key = {
+ hdr.ethernet.ether_type: exact @proto_tag(1);
+
+ hdr.ipv4_base.ttl: ternary @proto_tag(2);
+ hdr.ipv6_base.hop_limit: ternary @proto_tag(3);
+ hdr.ipv4_base.dst_addr: ternary @proto_tag(4);
+ hdr.ipv6_base.dst_addr: ternary @proto_tag(5);
+ hdr.ipv4_base.protocol: ternary @proto_tag(6);
+ hdr.ipv6_base.next_header: ternary @proto_tag(7);
+
+ local_metadata.l4_src_port: ternary @proto_tag(8);
+ local_metadata.l4_dst_port: ternary @proto_tag(9);
+
+ hdr.vlan_tag[0].vid: ternary @proto_tag(10);
+ hdr.vlan_tag[0].pcp: ternary @proto_tag(11);
+ }
+ actions = {
+ @proto_tag(1) set_class_id;
+ }
+ const default_action = set_class_id(0);
+ }
+ apply {
+ class_id_assignment_table.apply();
+ }
+
+} // end class_id
+
+#endif // P4_SPEC_CLASS_ID_P4_
diff --git a/tools/test/p4src/tor/class_id_main.p4 b/tools/test/p4src/tor/class_id_main.p4
new file mode 100644
index 0000000..ce80ba8
--- /dev/null
+++ b/tools/test/p4src/tor/class_id_main.p4
@@ -0,0 +1,33 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for class_id instance.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#include "class_id.p4"
+
+control ingress(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ class_id.apply(hdr, local_metadata, standard_metadata);
+ }
+} // end ingress
+
+control egress(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply { }
+}
+
+control verify_checksum(in parsed_packet_t hdr,
+ inout local_metadata_t local_metadata) {
+ apply { }
+}
+
+control compute_checksum(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata) {
+ apply { }
+}
+
+V1Switch(pkt_parser(), verify_checksum(), ingress(), egress(),
+ compute_checksum(), pkt_deparser()) main;
diff --git a/tools/test/p4src/tor/headers.p4 b/tools/test/p4src/tor/headers.p4
new file mode 100644
index 0000000..7284a3f
--- /dev/null
+++ b/tools/test/p4src/tor/headers.p4
@@ -0,0 +1,145 @@
+// Copyright (c) 2017, Google Inc.
+//
+// Common header definitions.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#ifndef P4_SPEC_HEADERS_P4_
+#define P4_SPEC_HEADERS_P4_
+
+//------------------------------------------------------------------------------
+// Field type definitions
+//------------------------------------------------------------------------------
+
+typedef bit<48> EthernetAddress;
+typedef bit<32> IPv4Address;
+typedef bit<128> IPv6Address;
+typedef bit<9> PortNum;
+
+//------------------------------------------------------------------------------
+// Protocol header definitions
+//------------------------------------------------------------------------------
+
+header ethernet_t {
+ EthernetAddress dst_addr;
+ EthernetAddress src_addr;
+ bit<16> ether_type;
+}
+
+header ipv4_base_t {
+ bit<4> version;
+ bit<4> ihl;
+ bit<8> diffserv;
+ bit<16> total_len;
+ bit<16> identification;
+ bit<3> flags;
+ bit<13> frag_offset;
+ bit<8> ttl;
+ bit<8> protocol;
+ bit<16> hdr_checksum;
+ IPv4Address src_addr;
+ IPv4Address dst_addr;
+}
+
+// Fixed ipv6 header
+header ipv6_base_t {
+ bit<4> version;
+ bit<8> traffic_class;
+ bit<20> flow_label;
+ bit<16> payload_length;
+ bit<8> next_header;
+ bit<8> hop_limit;
+ IPv6Address src_addr;
+ IPv6Address dst_addr;
+}
+
+header udp_t {
+ bit<16> src_port;
+ bit<16> dst_port;
+ bit<16> hdr_length;
+ bit<16> checksum;
+}
+
+header tcp_t {
+ bit<16> src_port;
+ bit<16> dst_port;
+ bit<32> seq_no;
+ bit<32> ack_no;
+ bit<4> data_offset;
+ bit<4> res;
+ bit<8> flags;
+ bit<16> window;
+ bit<16> checksum;
+ bit<16> urgent_ptr;
+}
+
+// Same for both ip v4 and v6
+header icmp_header_t {
+ bit<8> icmp_type;
+ bit<8> code;
+ bit<16> checksum;
+}
+
+header vlan_tag_t {
+ bit<3> pcp;
+ bit cfi;
+ bit<12> vid;
+ bit<16> ether_type;
+}
+
+header arp_t {
+ bit<16> hw_type;
+ bit<16> proto_type;
+ bit<8> hw_addr_len;
+ bit<8> proto_addr_len;
+ bit<16> opcode;
+ bit<48> sender_hw_addr;
+ bit<32> sender_proto_addr;
+ bit<48> target_hw_addr;
+ bit<32> target_proto_addr;
+}
+
+//------------------------------------------------------------------------------
+// Controller header definitions
+//------------------------------------------------------------------------------
+
+@controller_header("packet_in")
+header packet_in_header_t {
+ // TODO(samarabdi) Change once we move from 9 to 32 bits
+ @proto_tag(1) bit<9> ingress_physical_port;
+ @proto_tag(4) bit<7> padding1;
+ @proto_tag(2) bit<32> ingress_logical_port;
+ // The initial intended egress port decided for the packet by the pipeline.
+ // This is standard metadata.egress_spec at the time the punt-rule was hit.
+ // TODO(samarabdi) Change once we move from 9 to 32 bits
+ @proto_tag(3) bit<9> target_egress_port;
+ @proto_tag(5) bit<7> padding2;
+}
+
+@not_extracted_in_egress
+@controller_header("packet_out")
+header packet_out_header_t {
+ // TODO(samarabdi) Change once we move from 9 to 32 bits
+ @proto_tag(1) bit<9> egress_physical_port;
+ @proto_tag(2) bit<1> submit_to_ingress;
+ @proto_tag(3) bit<6> padding;
+}
+
+//------------------------------------------------------------------------------
+// Metadata definition
+//------------------------------------------------------------------------------
+
+// Local meta-data for each packet being processed.
+// TODO(samarabdi): Evaluate if this should be role-based.
+struct local_metadata_t {
+ bit<32> vrf_id;
+ bit<8> class_id; // Dst traffic class ID (IPSP)
+ bit<5> cpu_cos_queue_id;
+ bit<1> skip_egress;
+ // TODO(samarabdi) Change once we move from 9 to 32 bits
+ bit<9> egress_spec_at_punt_match;
+ bit<2> color;
+ bit<16> l4_src_port;
+ bit<16> l4_dst_port;
+ bit<8> icmp_code;
+}
+#endif // P4_SPEC_HEADERS_P4_
diff --git a/tools/test/p4src/tor/ipv4_checksum.p4 b/tools/test/p4src/tor/ipv4_checksum.p4
new file mode 100644
index 0000000..e76a984
--- /dev/null
+++ b/tools/test/p4src/tor/ipv4_checksum.p4
@@ -0,0 +1,48 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for IPv4 checksum verify and update.
+// Status: WORK IN PROGRESS
+// Note: This code has not been tested and is expected to contain bugs.
+
+#include "headers.p4"
+
+
+control verify_checksum(in parsed_packet_t hdr,
+ inout local_metadata_t local_metadata) {
+ Checksum16() ipv4_checksum;
+ bit<16> ck;
+ apply {
+ if (hdr.ipv4_base.isValid()) {
+ ck = ipv4_checksum.get(
+ {
+ hdr.ipv4_base.version, hdr.ipv4_base.ihl,
+ hdr.ipv4_base.diffserv, hdr.ipv4_base.total_len,
+ hdr.ipv4_base.identification, hdr.ipv4_base.flags,
+ hdr.ipv4_base.frag_offset, hdr.ipv4_base.ttl,
+ hdr.ipv4_base.protocol, hdr.ipv4_base.src_addr,
+ hdr.ipv4_base.dst_addr
+ });
+ if (hdr.ipv4_base.hdr_checksum != ck) {
+ mark_to_drop();
+ }
+ }
+ }
+}
+
+control compute_checksum(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata) {
+ Checksum16() ipv4_checksum;
+ apply {
+ if (hdr.ipv4_base.isValid()) {
+ hdr.ipv4_base.hdr_checksum = ipv4_checksum.get(
+ {
+ hdr.ipv4_base.version, hdr.ipv4_base.ihl,
+ hdr.ipv4_base.diffserv, hdr.ipv4_base.total_len,
+ hdr.ipv4_base.identification, hdr.ipv4_base.flags,
+ hdr.ipv4_base.frag_offset, hdr.ipv4_base.ttl,
+ hdr.ipv4_base.protocol, hdr.ipv4_base.src_addr,
+ hdr.ipv4_base.dst_addr
+ });
+ }
+ }
+}
diff --git a/tools/test/p4src/tor/l3_fwd.p4 b/tools/test/p4src/tor/l3_fwd.p4
new file mode 100644
index 0000000..b5b8aa6
--- /dev/null
+++ b/tools/test/p4src/tor/l3_fwd.p4
@@ -0,0 +1,194 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for a L3 forwarding app.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#ifndef P4_SPEC_L3_FWD_P4_
+#define P4_SPEC_L3_FWD_P4_
+
+#include "headers.p4"
+#include "parser.p4"
+
+#ifdef P4_EXPLICIT_LAG
+#include "lag.p4"
+#endif
+
+//------------------------------------------------------------------------------
+// IPv4/v6 L3 Forwarding
+//------------------------------------------------------------------------------
+
+control l3_fwd(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+
+
+ @proto_package("l3_fwd")
+ action set_nexthop(@proto_tag(1) PortNum port,
+ @proto_tag(2) EthernetAddress smac,
+ @proto_tag(3) EthernetAddress dmac) {
+ standard_metadata.egress_spec = port;
+ hdr.ethernet.src_addr = smac;
+ hdr.ethernet.dst_addr = dmac;
+ // if (hdr.ipv4_base.isValid()) {
+ hdr.ipv4_base.ttl = hdr.ipv4_base.ttl - 1;
+ // } else if (hdr.ipv6_base.isValid()) {
+ // hdr.ipv6_base.hop_limit = hdr.ipv6_base.hop_limit - 1;
+ // }
+ }
+
+ // Hit implies that the packet needs to be L3 forwarded.
+ // Equivalent of BCM MY_STATION table
+ @proto_package("l3_fwd")
+ table l3_routing_classifier_table {
+ key = {
+ hdr.ethernet.dst_addr : exact @proto_tag(1);
+ }
+ actions = {
+ @proto_tag(1) NoAction;
+ }
+ const default_action = NoAction();
+ }
+
+ action_selector(HashAlgorithm.crc16, 32w1024, 32w14) wcmp_action_profile;
+
+ // LPM forwarding tables for IPV4 packets.
+ @proto_package("l3_fwd")
+ table l3_ipv4_override_table {
+ key = {
+ hdr.ipv4_base.dst_addr : lpm @proto_tag(1);
+
+ hdr.ipv4_base.dst_addr : selector @proto_tag(2);
+ hdr.ipv4_base.src_addr : selector @proto_tag(3);
+ hdr.ipv4_base.protocol : selector @proto_tag(4);
+ local_metadata.l4_src_port : selector @proto_tag(5);
+ local_metadata.l4_dst_port : selector @proto_tag(6);
+ }
+ actions = {
+ @proto_tag(1) set_nexthop;
+ @proto_tag(2) NoAction;
+ }
+ const default_action = NoAction();
+ // TODO(samarabdi): do we need to specify selector size?
+ implementation = wcmp_action_profile;
+ }
+
+ @proto_package("l3_fwd")
+ table l3_ipv4_vrf_table {
+ key = {
+ local_metadata.vrf_id: exact @proto_tag(1);
+ hdr.ipv4_base.dst_addr : lpm @proto_tag(2);
+ hdr.ipv4_base.dst_addr : selector @proto_tag(3);
+ hdr.ipv4_base.src_addr : selector @proto_tag(4);
+ hdr.ipv4_base.protocol : selector @proto_tag(5);
+ local_metadata.l4_src_port : selector @proto_tag(6);
+ local_metadata.l4_dst_port : selector @proto_tag(7);
+ }
+ actions = {
+ @proto_tag(1) set_nexthop;
+ @proto_tag(2) NoAction;
+ }
+ const default_action = NoAction();
+ implementation = wcmp_action_profile;
+ }
+
+ @proto_package("l3_fwd")
+ table l3_ipv4_fallback_table {
+ key = {
+ hdr.ipv4_base.dst_addr : lpm @proto_tag(1);
+ hdr.ipv4_base.dst_addr : selector @proto_tag(2);
+ hdr.ipv4_base.src_addr : selector @proto_tag(3);
+ hdr.ipv4_base.protocol : selector @proto_tag(4);
+ local_metadata.l4_src_port : selector @proto_tag(5);
+ local_metadata.l4_dst_port : selector @proto_tag(6);
+ }
+ actions = {
+ @proto_tag(1) set_nexthop;
+ @proto_tag(2) NoAction;
+ }
+ const default_action = NoAction();
+ implementation = wcmp_action_profile;
+ }
+
+ // LPM forwarding tables for IPV6 packets.
+
+ // @proto_package("l3_fwd")
+ // table l3_ipv6_override_table {
+ // key = {
+ // hdr.ipv6_base.dst_addr : lpm @proto_tag(1);
+ // hdr.ipv6_base.dst_addr : selector @proto_tag(2);
+ // hdr.ipv6_base.src_addr : selector @proto_tag(3);
+ // hdr.ipv6_base.flow_label : selector @proto_tag(4);
+ // local_metadata.l4_src_port : selector @proto_tag(5);
+ // local_metadata.l4_dst_port : selector @proto_tag(6);
+ // }
+ // actions = {
+ // @proto_tag(1) set_nexthop;
+ // }
+ // implementation = wcmp_action_profile;
+ // }
+
+ // @proto_package("l3_fwd")
+ // table l3_ipv6_vrf_table {
+ // key = {
+ // local_metadata.vrf_id: exact @proto_tag(1);
+ // hdr.ipv6_base.dst_addr : lpm @proto_tag(2);
+ // hdr.ipv6_base.dst_addr : selector @proto_tag(3);
+ // hdr.ipv6_base.src_addr : selector @proto_tag(4);
+ // hdr.ipv6_base.flow_label : selector @proto_tag(5);
+ // local_metadata.l4_src_port : selector @proto_tag(6);
+ // local_metadata.l4_dst_port : selector @proto_tag(7);
+ // }
+ // actions = {
+ // @proto_tag(1) set_nexthop;
+ // }
+ // implementation = wcmp_action_profile;
+ // }
+
+ // @proto_package("l3_fwd")
+ // table l3_ipv6_fallback_table {
+ // key = {
+ // hdr.ipv6_base.dst_addr : lpm @proto_tag(1);
+ // hdr.ipv6_base.dst_addr : selector @proto_tag(2);
+ // hdr.ipv6_base.src_addr : selector @proto_tag(3);
+ // hdr.ipv6_base.flow_label : selector @proto_tag(4);
+ // local_metadata.l4_src_port : selector @proto_tag(5);
+ // local_metadata.l4_dst_port : selector @proto_tag(6);
+ // }
+ // actions = {
+ // @proto_tag(1) set_nexthop;
+ // }
+ // implementation = wcmp_action_profile;
+ // }
+
+ apply {
+ if(l3_routing_classifier_table.apply().hit) {
+ if (hdr.ipv4_base.isValid()) {
+ if(!l3_ipv4_override_table.apply().hit) {
+ if(!l3_ipv4_vrf_table.apply().hit) {
+ l3_ipv4_fallback_table.apply();
+ }
+ }
+ if(hdr.ipv4_base.ttl == 0) {
+ mark_to_drop();
+ return;
+ }
+ }// else if (hdr.ipv6_base.isValid()) {
+ // if(!l3_ipv6_override_table.apply().hit) {
+ // if(!l3_ipv6_vrf_table.apply().hit) {
+ // l3_ipv6_fallback_table.apply();
+ // }
+ // }
+ // if(hdr.ipv6_base.hop_limit == 0) {
+ // mark_to_drop();
+ // return;
+ // }
+ // }
+ }
+ }
+#ifdef P4_EXPLICIT_LAG
+ lag_handling() lag;
+ lag(hdr, local_metadata, standard_metadata);
+#endif
+} // end l3_fwd
+
+#endif // P4_SPEC_L3_FWD_P4_
diff --git a/tools/test/p4src/tor/l3_fwd_main.p4 b/tools/test/p4src/tor/l3_fwd_main.p4
new file mode 100644
index 0000000..9162bce
--- /dev/null
+++ b/tools/test/p4src/tor/l3_fwd_main.p4
@@ -0,0 +1,24 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for l3_fwd instance.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#include "l3_fwd.p4"
+#include "ipv4_checksum.p4"
+
+control ingress(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ l3_fwd.apply(hdr, local_metadata, standard_metadata);
+ }
+} // end ingress
+
+control egress(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply { }
+}
+
+V1Switch(pkt_parser(), verify_checksum(), ingress(), egress(),
+ compute_checksum(), pkt_deparser()) main;
diff --git a/tools/test/p4src/tor/middleblock.p4 b/tools/test/p4src/tor/middleblock.p4
new file mode 100644
index 0000000..93ab2a5
--- /dev/null
+++ b/tools/test/p4src/tor/middleblock.p4
@@ -0,0 +1,39 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for a middleblock switch in a Jupiter superblock.
+// Status: WORK IN PROGRESS
+// Note: This code has not been tested and is expected to contain bugs.
+
+#include "parser.p4"
+#include "class_id.p4"
+#include "l3_fwd.p4"
+#include "packetio.p4"
+#include "punt.p4"
+#include "vrf.p4"
+#include "ipv4_checksum.p4"
+
+
+control ingress_middleblock(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ if (hdr.packet_out.isValid()) {
+ packetio_ingress.apply(hdr, local_metadata, standard_metadata);
+ }
+ vrf.apply(hdr, local_metadata, standard_metadata);
+ class_id.apply(hdr, local_metadata, standard_metadata);
+ l3_fwd.apply(hdr, local_metadata, standard_metadata);
+ punt.apply(hdr, local_metadata, standard_metadata);
+ }
+} // end ingress_middleblock
+
+control egress_middleblock(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ packetio_egress.apply(hdr, local_metadata, standard_metadata);
+ }
+} // end egress_middleblock
+
+V1Switch(pkt_parser(), verify_checksum(), ingress_middleblock(),
+ egress_middleblock(), compute_checksum(), pkt_deparser()) main;
diff --git a/tools/test/p4src/tor/packetio.p4 b/tools/test/p4src/tor/packetio.p4
new file mode 100644
index 0000000..75b84d8
--- /dev/null
+++ b/tools/test/p4src/tor/packetio.p4
@@ -0,0 +1,55 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4 Modeling of controller Packet-IO behavior.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#ifndef P4_SPEC_PACKETIO_P4_
+#define P4_SPEC_PACKETIO_P4_
+
+#include "headers.p4"
+#include "parser.p4"
+
+//------------------------------------------------------------------------------
+// Packet IO
+//------------------------------------------------------------------------------
+
+control packetio_ingress(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ if (hdr.packet_out.submit_to_ingress == 0) {
+ local_metadata.skip_egress = 1;
+ standard_metadata.egress_spec = hdr.packet_out.egress_physical_port;
+ hdr.packet_out.setInvalid();
+ exit;
+ }
+ hdr.packet_out.setInvalid();
+ }
+} // end packetio_ingress
+
+
+control packetio_egress(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ action encap_packet_in_header() {
+ hdr.packet_in.setValid();
+ hdr.packet_in.ingress_physical_port = standard_metadata.ingress_port;
+ hdr.packet_in.target_egress_port = local_metadata.egress_spec_at_punt_match;
+
+ // At this time, ingress_logical_port cannot be set directly from within
+ // a P4-defined pipeline. It's existance currently serves to define
+ // this metadata field (as part of packet_in header). The target
+ // software will figure out the logical-port separately, and populate
+ // it into the P4Runtime stream message using the field-ID generated
+ // from the P4 packet_in header.
+ }
+
+ apply {
+ if (standard_metadata.egress_port == CPU_PORT) {
+ encap_packet_in_header();
+ }
+ if (local_metadata.skip_egress == 1) exit;
+ }
+} // end packetio_egress
+
+#endif // P4_SPEC_PACKETIO_P4_
diff --git a/tools/test/p4src/tor/parser.p4 b/tools/test/p4src/tor/parser.p4
new file mode 100644
index 0000000..e9b0c77
--- /dev/null
+++ b/tools/test/p4src/tor/parser.p4
@@ -0,0 +1,165 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for a packet parser.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#ifndef P4_SPEC_PARSER_P4_
+#define P4_SPEC_PARSER_P4_
+
+#include <v1model.p4>
+#include "headers.p4"
+
+//------------------------------------------------------------------------------
+// Global defines
+//------------------------------------------------------------------------------
+
+#define ETHERTYPE_VLAN1 0x8100
+#define ETHERTYPE_VLAN2 0x9100
+#define ETHERTYPE_VLAN3 0x9200
+#define ETHERTYPE_VLAN4 0x9300
+
+#define ETHERTYPE_IPV4 0x0800
+#define ETHERTYPE_IPV6 0x86dd
+#define ETHERTYPE_ARP 0x0806
+#define ETHERTYPE_ND 0x6007
+#define ETHERTYPE_LLDP 0x88CC
+
+#define IP_PROTOCOLS_TCP 6
+#define IP_PROTOCOLS_UDP 17
+#define IP_PROTOCOLS_ICMP 1
+#define IP_PROTOCOLS_ICMPv6 58
+
+#ifndef CPU_PORT
+// TODO(samarabdi) Change once we move from 9 to 32 bits
+#define CPU_PORT 0xFD // 0xFFFFFFFD
+#endif
+#define VLAN_DEPTH 2
+
+//------------------------------------------------------------------------------
+// List of all recognized headers
+//------------------------------------------------------------------------------
+
+struct parsed_packet_t {
+ ethernet_t ethernet;
+ ipv4_base_t ipv4_base;
+ ipv6_base_t ipv6_base;
+ icmp_header_t icmp_header;
+ tcp_t tcp;
+ udp_t udp;
+ vlan_tag_t[VLAN_DEPTH] vlan_tag; // header stack
+ arp_t arp;
+ packet_in_header_t packet_in;
+ packet_out_header_t packet_out;
+}
+
+//------------------------------------------------------------------------------
+// Parser
+//------------------------------------------------------------------------------
+
+parser pkt_parser(packet_in pk, out parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ state start {
+ transition select(standard_metadata.ingress_port) {
+ CPU_PORT : parse_cpu_header;
+ _ : parse_ethernet;
+ }
+ }
+
+ state parse_ethernet {
+ pk.extract(hdr.ethernet);
+ transition select(hdr.ethernet.ether_type) {
+ ETHERTYPE_VLAN1: parse_vlan;
+ ETHERTYPE_VLAN2: parse_vlan;
+ ETHERTYPE_VLAN3: parse_vlan;
+ ETHERTYPE_VLAN4: parse_vlan;
+ ETHERTYPE_IPV4: parse_ipv4;
+ ETHERTYPE_IPV6: parse_ipv6;
+ ETHERTYPE_ARP: parse_arp;
+ _ : accept;
+ }
+ }
+
+ state parse_vlan {
+ // reference the next element in header stack
+ pk.extract(hdr.vlan_tag.next);
+ transition select(hdr.vlan_tag.last.ether_type) {
+ ETHERTYPE_VLAN1: parse_vlan;
+ ETHERTYPE_VLAN2: parse_vlan;
+ ETHERTYPE_VLAN3: parse_vlan;
+ ETHERTYPE_VLAN4: parse_vlan;
+ ETHERTYPE_IPV4 : parse_ipv4;
+ ETHERTYPE_IPV6 : parse_ipv6;
+ _ : accept;
+ }
+ }
+
+ state parse_ipv4 {
+ pk.extract(hdr.ipv4_base);
+ // TODO(samarabdi): confirm if below concats the two fields
+ transition select(hdr.ipv4_base.frag_offset ++ hdr.ipv4_base.protocol) {
+ IP_PROTOCOLS_ICMP : parse_icmp;
+ IP_PROTOCOLS_TCP : parse_tcp;
+ IP_PROTOCOLS_UDP : parse_udp;
+ _ : accept;
+ }
+ }
+
+ state parse_ipv6 {
+ pk.extract(hdr.ipv6_base);
+ transition select(hdr.ipv6_base.next_header) {
+ IP_PROTOCOLS_ICMPv6: parse_icmp;
+ IP_PROTOCOLS_TCP : parse_tcp;
+ IP_PROTOCOLS_UDP : parse_udp;
+ _ : accept;
+ }
+ }
+
+ state parse_tcp {
+ pk.extract(hdr.tcp);
+ // Normalize TCP port metadata to common port metadata
+ local_metadata.l4_src_port = hdr.tcp.src_port;
+ local_metadata.l4_dst_port = hdr.tcp.dst_port;
+ transition accept;
+ }
+
+ state parse_udp {
+ pk.extract(hdr.udp);
+ // Normalize UDP port metadata to common port metadata
+ local_metadata.l4_src_port = hdr.udp.src_port;
+ local_metadata.l4_dst_port = hdr.udp.dst_port;
+ transition accept;
+ }
+
+ state parse_icmp {
+ pk.extract(hdr.icmp_header);
+ transition accept;
+ }
+
+ state parse_arp {
+ pk.extract(hdr.arp);
+ transition accept;
+ }
+
+ state parse_cpu_header {
+ pk.extract(hdr.packet_out);
+ transition parse_ethernet;
+ }
+} // end pkt_parser
+
+control pkt_deparser(packet_out b, in parsed_packet_t hdr) {
+ apply {
+ // packet_out is not a valid header in a packet destined to CPU_PORT
+ b.emit(hdr.packet_in);
+ b.emit(hdr.ethernet);
+ b.emit(hdr.vlan_tag);
+ b.emit(hdr.ipv4_base);
+ b.emit(hdr.ipv6_base);
+ b.emit(hdr.arp);
+ b.emit(hdr.icmp_header);
+ b.emit(hdr.tcp);
+ b.emit(hdr.udp);
+ }
+}
+
+#endif // P4_SPEC_PARSER_P4_
diff --git a/tools/test/p4src/tor/punt.p4 b/tools/test/p4src/tor/punt.p4
new file mode 100644
index 0000000..2bdd45a
--- /dev/null
+++ b/tools/test/p4src/tor/punt.p4
@@ -0,0 +1,98 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for packet punting behavior.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#ifndef P4_SPEC_PUNT_P4_
+#define P4_SPEC_PUNT_P4_
+
+#include "headers.p4"
+#include "parser.p4"
+
+//------------------------------------------------------------------------------
+// Global defines
+//------------------------------------------------------------------------------
+
+#define CPU_MIRROR_SESSION_ID 1023
+// TODO(samarabdi): Make sure this is also the behavior of the v1model extern
+#define METER_GREEN 0
+
+//------------------------------------------------------------------------------
+// Control Pipelines
+//------------------------------------------------------------------------------
+
+control punt(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+
+ @proto_package("punt")
+ direct_meter<bit<2>>(MeterType.bytes) ingress_port_meter;
+
+ @proto_package("punt")
+ direct_counter(CounterType.packets) punt_packet_counter;
+
+ @proto_package("punt")
+ action set_queue_and_clone_to_cpu(@proto_tag(1) bit<5> queue_id) {
+ local_metadata.cpu_cos_queue_id = queue_id;
+ local_metadata.egress_spec_at_punt_match = standard_metadata.egress_spec;
+ clone3<tuple<bit<9>>>(CloneType.I2E, CPU_MIRROR_SESSION_ID,
+ {standard_metadata.ingress_port});
+ ingress_port_meter.read(local_metadata.color);
+ punt_packet_counter.count();
+ }
+
+ @proto_package("punt")
+ action set_queue_and_send_to_cpu(@proto_tag(1) bit<5> queue_id) {
+ local_metadata.cpu_cos_queue_id = queue_id;
+ local_metadata.egress_spec_at_punt_match = standard_metadata.egress_spec;
+ standard_metadata.egress_spec = CPU_PORT;
+ ingress_port_meter.read(local_metadata.color);
+ punt_packet_counter.count();
+ }
+
+ // Combined punt table.
+ @proto_package("punt")
+ table punt_table {
+ key = {
+ standard_metadata.ingress_port: ternary @proto_tag(1);
+ standard_metadata.egress_spec: ternary @proto_tag(2);
+
+ hdr.ethernet.ether_type: ternary @proto_tag(3);
+
+ hdr.ipv4_base.diffserv: ternary @proto_tag(4);
+ hdr.ipv6_base.traffic_class: ternary @proto_tag(5);
+ hdr.ipv4_base.ttl: ternary @proto_tag(6);
+ hdr.ipv6_base.hop_limit: ternary @proto_tag(7);
+ hdr.ipv4_base.src_addr: ternary @proto_tag(8);
+ hdr.ipv4_base.dst_addr: ternary @proto_tag(9);
+ hdr.ipv6_base.src_addr: ternary @proto_tag(10);
+ hdr.ipv6_base.dst_addr: ternary @proto_tag(11);
+ hdr.ipv4_base.protocol: ternary @proto_tag(12);
+ hdr.ipv6_base.next_header: ternary @proto_tag(13);
+
+ hdr.arp.target_proto_addr: ternary @proto_tag(14);
+ local_metadata.icmp_code: ternary @proto_tag(15);
+
+ hdr.vlan_tag[0].vid: ternary @proto_tag(16);
+ hdr.vlan_tag[0].pcp: ternary @proto_tag(17);
+
+ local_metadata.class_id: ternary @proto_tag(18);
+ local_metadata.vrf_id: ternary @proto_tag(19);
+ }
+ actions = {
+ @proto_tag(1) set_queue_and_clone_to_cpu;
+ @proto_tag(2) set_queue_and_send_to_cpu;
+ }
+ meters = ingress_port_meter;
+ counters = punt_packet_counter;
+ }
+
+ apply {
+ punt_table.apply();
+ if(local_metadata.color != METER_GREEN) {
+ mark_to_drop();
+ }
+ }
+} // end punt
+
+#endif // P4_SPEC_PUNT_P4_
diff --git a/tools/test/p4src/tor/punt_main.p4 b/tools/test/p4src/tor/punt_main.p4
new file mode 100644
index 0000000..dec8ba4
--- /dev/null
+++ b/tools/test/p4src/tor/punt_main.p4
@@ -0,0 +1,33 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for punt instance.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#include "punt.p4"
+
+control ingress(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ punt.apply(hdr, local_metadata, standard_metadata);
+ }
+} // end ingress
+
+control egress(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply { }
+}
+
+control verify_checksum(in parsed_packet_t hdr,
+ inout local_metadata_t local_metadata) {
+ apply { }
+}
+
+control compute_checksum(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata) {
+ apply { }
+}
+
+V1Switch(pkt_parser(), verify_checksum(), ingress(), egress(),
+ compute_checksum(), pkt_deparser()) main;
diff --git a/tools/test/p4src/tor/spine.p4 b/tools/test/p4src/tor/spine.p4
new file mode 100644
index 0000000..b466518
--- /dev/null
+++ b/tools/test/p4src/tor/spine.p4
@@ -0,0 +1,39 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for a Spine switch.
+// Status: WORK IN PROGRESS
+// Note: This code has not been tested and is expected to contain bugs.
+
+#include "parser.p4"
+#include "class_id.p4"
+#include "l3_fwd.p4"
+#include "packetio.p4"
+#include "punt.p4"
+#include "vrf.p4"
+#include "ipv4_checksum.p4"
+
+
+control ingress_spine(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ if (hdr.packet_out.isValid()) {
+ packetio_ingress.apply(hdr, local_metadata, standard_metadata);
+ }
+ vrf.apply(hdr, local_metadata, standard_metadata);
+ class_id.apply(hdr, local_metadata, standard_metadata);
+ l3_fwd.apply(hdr, local_metadata, standard_metadata);
+ punt.apply(hdr, local_metadata, standard_metadata);
+ }
+} // end ingress_spine
+
+control egress_spine(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ packetio_egress.apply(hdr, local_metadata, standard_metadata);
+ }
+} // end egress_spine
+
+V1Switch(pkt_parser(), verify_checksum(), ingress_spine(), egress_spine(),
+ compute_checksum(), pkt_deparser()) main;
diff --git a/tools/test/p4src/tor/spoof_protection.p4 b/tools/test/p4src/tor/spoof_protection.p4
new file mode 100644
index 0000000..2c14f67
--- /dev/null
+++ b/tools/test/p4src/tor/spoof_protection.p4
@@ -0,0 +1,47 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification dhcp spoof table.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#ifndef P4_SPEC_SPOOF_PROTECTION_P4_
+#define P4_SPEC_SPOOF_PROTECTION_P4_
+
+#include "headers.p4"
+#include "parser.p4"
+
+//------------------------------------------------------------------------------
+// Spoof protection
+//------------------------------------------------------------------------------
+
+control spoof_protection(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+
+ @proto_package("spoof_protection")
+ action drop_packet() {
+ mark_to_drop();
+ }
+
+ // Drop all DHCP response packets to all host-facing ports.
+ // This protects against a host sending a DHCP response to another host
+ // directly and hijacking the DHCP session
+ // (i.e. spoof the installer/DHCP-Relay app).
+ @proto_package("spoof_protection")
+ table dhcp_spoof_protection_table {
+ key = {
+ local_metadata.l4_dst_port: exact @proto_tag(1);
+ standard_metadata.egress_spec: exact @proto_tag(2);
+ }
+ actions = {
+ @proto_tag(1) drop_packet;
+ }
+ }
+
+ apply {
+ if(hdr.udp.isValid()) {
+ dhcp_spoof_protection_table.apply();
+ }
+ }
+} // end spoof_protection
+
+#endif // P4_SPEC_SPOOF_PROTECTION_P4_
diff --git a/tools/test/p4src/tor/spoof_protection_main.p4 b/tools/test/p4src/tor/spoof_protection_main.p4
new file mode 100644
index 0000000..27b678e
--- /dev/null
+++ b/tools/test/p4src/tor/spoof_protection_main.p4
@@ -0,0 +1,35 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for dhcp spoof instance.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#include "spoof_protection.p4"
+
+control ingress(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+
+ apply { }
+
+} // end ingress
+
+control egress(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ spoof_protection.apply(hdr, local_metadata, standard_metadata);
+ }
+}
+
+control verify_checksum(in parsed_packet_t hdr,
+ inout local_metadata_t local_metadata) {
+ apply { }
+}
+
+control compute_checksum(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata) {
+ apply { }
+}
+
+V1Switch(pkt_parser(), verify_checksum(), ingress(), egress(),
+ compute_checksum(), pkt_deparser()) main;
diff --git a/tools/test/p4src/tor/tor.p4 b/tools/test/p4src/tor/tor.p4
new file mode 100644
index 0000000..33ebfcd
--- /dev/null
+++ b/tools/test/p4src/tor/tor.p4
@@ -0,0 +1,41 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for a ToR (top-of-rack) switch.
+// Status: WORK IN PROGRESS
+// Note: This code has not been tested and is expected to contain bugs.
+
+#include "parser.p4"
+#include "class_id.p4"
+#include "spoof_protection.p4"
+#include "l3_fwd.p4"
+#include "packetio.p4"
+#include "punt.p4"
+#include "vrf.p4"
+#include "ipv4_checksum.p4"
+
+
+control ingress_tor(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ if (hdr.packet_out.isValid()) {
+ packetio_ingress.apply(hdr, local_metadata, standard_metadata);
+ }
+ vrf.apply(hdr, local_metadata, standard_metadata);
+ class_id.apply(hdr, local_metadata, standard_metadata);
+ l3_fwd.apply(hdr, local_metadata, standard_metadata);
+ punt.apply(hdr, local_metadata, standard_metadata);
+ }
+} // end ingress_tor
+
+control egress_tor(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ packetio_egress.apply(hdr, local_metadata, standard_metadata);
+ spoof_protection.apply(hdr, local_metadata, standard_metadata);
+ }
+}
+
+V1Switch(pkt_parser(), verify_checksum(), ingress_tor(), egress_tor(),
+ compute_checksum(), pkt_deparser()) main;
diff --git a/tools/test/p4src/tor/vrf.p4 b/tools/test/p4src/tor/vrf.p4
new file mode 100644
index 0000000..0441f1c
--- /dev/null
+++ b/tools/test/p4src/tor/vrf.p4
@@ -0,0 +1,52 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for a VRF classifier.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#ifndef P4_SPEC_VRF_P4_
+#define P4_SPEC_VRF_P4_
+
+#include "headers.p4"
+#include "parser.p4"
+
+//------------------------------------------------------------------------------
+// Global defines
+//------------------------------------------------------------------------------
+
+#define DEFAULT_VRF0 0
+
+//------------------------------------------------------------------------------
+// Map traffic to a particular VRF
+//------------------------------------------------------------------------------
+
+control vrf(inout parsed_packet_t hdr, inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+
+ @proto_package("vrf")
+ action set_vrf(@proto_tag(1) bit<32> vrf_id) {
+ local_metadata.vrf_id = vrf_id;
+ }
+
+ @proto_package("vrf")
+ table vrf_classifier_table {
+ key = {
+ hdr.ethernet.ether_type : exact @proto_tag(1);
+ hdr.ethernet.src_addr : ternary @proto_tag(2);
+ hdr.ipv4_base.diffserv : ternary @proto_tag(3);
+ hdr.ipv4_base.dst_addr : ternary @proto_tag(4);
+ standard_metadata.ingress_port: exact @proto_tag(5);
+ hdr.ipv6_base.traffic_class : ternary @proto_tag(6);
+ hdr.ipv6_base.dst_addr : ternary @proto_tag(7);
+ }
+ actions = {
+ @proto_tag(1) set_vrf;
+ }
+ const default_action = set_vrf(DEFAULT_VRF0);
+ }
+
+ apply {
+ vrf_classifier_table.apply();
+ }
+} // end vrf
+
+#endif // P4_SPEC_VRF_P4_
diff --git a/tools/test/p4src/tor/vrf_main.p4 b/tools/test/p4src/tor/vrf_main.p4
new file mode 100644
index 0000000..da4d2e6
--- /dev/null
+++ b/tools/test/p4src/tor/vrf_main.p4
@@ -0,0 +1,33 @@
+// Copyright (c) 2017, Google Inc.
+//
+// P4_16 specification for vrf instance.
+// Note: This code has not been tested and is expected to contain bugs.
+
+#include "vrf.p4"
+
+control ingress(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ vrf.apply(hdr, local_metadata, standard_metadata);
+ }
+} // end ingress
+
+control egress(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata,
+ inout standard_metadata_t standard_metadata) {
+ apply { }
+}
+
+control verify_checksum(in parsed_packet_t hdr,
+ inout local_metadata_t local_metadata) {
+ apply { }
+}
+
+control compute_checksum(inout parsed_packet_t hdr,
+ inout local_metadata_t local_metadata) {
+ apply { }
+}
+
+V1Switch(pkt_parser(), verify_checksum(), ingress(), egress(),
+ compute_checksum(), pkt_deparser()) main;