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;