P4 source files for BMv2 demo

Change-Id: I3adc57eb346e3cb34f17d54b82505d2d9e89b4ad
diff --git a/tools/test/p4src/default.p4 b/tools/test/p4src/default.p4
new file mode 100644
index 0000000..3d5629e
--- /dev/null
+++ b/tools/test/p4src/default.p4
@@ -0,0 +1,31 @@
+#include "include/defines.p4"
+#include "include/headers.p4"
+#include "include/parser.p4"
+#include "include/actions.p4"
+#include "include/port_counters.p4"
+
+table table0 {
+    reads {
+        standard_metadata.ingress_port : ternary;
+        ethernet.dstAddr : ternary;
+        ethernet.srcAddr : ternary;
+        ethernet.etherType : ternary;
+    }
+    actions {
+        set_egress_port;
+        send_to_cpu;
+        _drop;
+    }
+    support_timeout: true;
+}
+
+counter table0_counter {
+    type: packets;
+    direct: table0;
+    min_width : 32;
+}
+
+control ingress {
+    apply(table0);
+    process_port_counters();
+}
\ No newline at end of file
diff --git a/tools/test/p4src/ecmp.p4 b/tools/test/p4src/ecmp.p4
new file mode 100644
index 0000000..95af85f
--- /dev/null
+++ b/tools/test/p4src/ecmp.p4
@@ -0,0 +1,84 @@
+#include "include/defines.p4"
+#include "include/headers.p4"
+#include "include/parser.p4"
+#include "include/actions.p4"
+#include "include/port_counters.p4"
+
+header_type ecmp_metadata_t {
+    fields {
+        groupId : 16;
+        selector : 16;
+    }
+}
+
+metadata ecmp_metadata_t ecmp_metadata;
+
+field_list ecmp_hash_fields {
+    ipv4.srcAddr;
+    ipv4.dstAddr;
+    ipv4.protocol;
+    tcp.srcPort;
+    tcp.dstPort;
+    udp.srcPort;
+    udp.dstPort;
+}
+
+field_list_calculation ecmp_hash {
+    input {
+        ecmp_hash_fields;
+    }
+    algorithm : bmv2_hash;
+    output_width : 64;
+}
+
+action ecmp_group(groupId, groupSize) {
+    modify_field(ecmp_metadata.groupId, groupId);
+    modify_field_with_hash_based_offset(ecmp_metadata.selector, 0, ecmp_hash, groupSize);
+}
+
+table table0 {
+    reads {
+        standard_metadata.ingress_port : ternary;
+        ethernet.dstAddr : ternary;
+        ethernet.srcAddr : ternary;
+        ethernet.etherType : ternary;
+    }
+    actions {
+        set_egress_port;
+        ecmp_group;
+        send_to_cpu;
+        _drop;
+    }
+    support_timeout: true;
+}
+
+table ecmp_group_table {
+    reads {
+        ecmp_metadata.groupId : exact;
+        ecmp_metadata.selector : exact;
+    }
+    actions {
+        set_egress_port;
+    }
+}
+
+counter table0_counter {
+    type: packets;
+    direct: table0;
+    min_width : 32;
+}
+
+counter ecmp_group_table_counter {
+    type: packets;
+    direct: ecmp_group_table;
+    min_width : 32;
+}
+
+control ingress {
+    apply(table0) {
+        ecmp_group {
+            apply(ecmp_group_table);
+        }
+    }
+    process_port_counters();
+}
\ No newline at end of file
diff --git a/tools/test/p4src/empty.p4 b/tools/test/p4src/empty.p4
new file mode 100644
index 0000000..91e6e67
--- /dev/null
+++ b/tools/test/p4src/empty.p4
@@ -0,0 +1,28 @@
+header_type dummy_t {
+    fields {
+        dummyField : 8;
+    }
+}
+
+metadata dummy_t dummy_metadata;
+
+parser start {
+    return ingress;
+}
+
+table table0 {
+    reads {
+        dummy_metadata.dummyField : exact;
+    }
+    actions {
+    	dummy_action;
+    }
+}
+
+action dummy_action() {
+    modify_field(dummy_metadata.dummyField, 1);
+}
+
+control ingress {
+	apply(table0);
+}
\ No newline at end of file
diff --git a/tools/test/p4src/include/actions.p4 b/tools/test/p4src/include/actions.p4
new file mode 100644
index 0000000..a8693e2
--- /dev/null
+++ b/tools/test/p4src/include/actions.p4
@@ -0,0 +1,11 @@
+action set_egress_port(port) {
+    modify_field(standard_metadata.egress_spec, port);
+}
+
+action _drop() {
+    modify_field(standard_metadata.egress_spec, DROP_PORT);
+}
+
+action send_to_cpu() {
+    modify_field(standard_metadata.egress_spec, CPU_PORT);
+}
\ No newline at end of file
diff --git a/tools/test/p4src/include/defines.p4 b/tools/test/p4src/include/defines.p4
new file mode 100644
index 0000000..c9229c9
--- /dev/null
+++ b/tools/test/p4src/include/defines.p4
@@ -0,0 +1,4 @@
+// Logic ports as defined in the simple_switch target
+#define MAX_PORTS 254
+#define CPU_PORT 255
+#define DROP_PORT 511
diff --git a/tools/test/p4src/include/headers.p4 b/tools/test/p4src/include/headers.p4
new file mode 100644
index 0000000..57bda87
--- /dev/null
+++ b/tools/test/p4src/include/headers.p4
@@ -0,0 +1,58 @@
+header_type intrinsic_metadata_t {
+    fields {
+        ingress_global_timestamp : 32;
+        lf_field_list : 32;
+        mcast_grp : 16;
+        egress_rid : 16;
+    }
+}
+
+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;
+    }
+}
+
+header_type tcp_t {
+    fields {
+        srcPort : 16;
+        dstPort : 16;
+        seqNo : 32;
+        ackNo : 32;
+        dataOffset : 4;
+        res : 3;
+        ecn : 3;
+        ctrl : 6;
+        window : 16;
+        checksum : 16;
+        urgentPtr : 16;
+    }
+}
+
+header_type udp_t {
+    fields {
+        srcPort : 16;
+        dstPort : 16;
+        length_ : 16;
+        checksum : 16;
+    }
+}
\ No newline at end of file
diff --git a/tools/test/p4src/include/parser.p4 b/tools/test/p4src/include/parser.p4
new file mode 100644
index 0000000..6a205ec
--- /dev/null
+++ b/tools/test/p4src/include/parser.p4
@@ -0,0 +1,45 @@
+metadata intrinsic_metadata_t intrinsic_metadata;
+
+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;
+
+#define IP_PROTOCOLS_TCP  6
+#define IP_PROTOCOLS_UDP  17
+
+parser parse_ipv4 {
+    extract(ipv4);
+    return select(latest.fragOffset, latest.protocol) {
+        IP_PROTOCOLS_TCP : parse_tcp;
+        IP_PROTOCOLS_UDP : parse_udp;
+        default: ingress;
+    }
+}
+
+header tcp_t tcp;
+
+parser parse_tcp {
+    extract(tcp);
+    return ingress;
+}
+
+header udp_t udp;
+
+parser parse_udp {
+    extract(udp);
+    return ingress;
+}
\ No newline at end of file
diff --git a/tools/test/p4src/include/port_counters.p4 b/tools/test/p4src/include/port_counters.p4
new file mode 100644
index 0000000..06cba4f
--- /dev/null
+++ b/tools/test/p4src/include/port_counters.p4
@@ -0,0 +1,29 @@
+counter ingress_port_counter {
+    type : packets; // bmv2 always counts both bytes and packets 
+    instance_count : MAX_PORTS;
+    min_width : 32;
+}
+
+counter egress_port_counter {
+    type: packets;
+    instance_count : MAX_PORTS;
+    min_width : 32;
+}
+
+table port_count_table {
+    actions {
+        count_packet;
+    }
+}
+
+action count_packet() {
+    count(ingress_port_counter, standard_metadata.ingress_port);
+    count(egress_port_counter, standard_metadata.egress_spec);
+}
+
+control process_port_counters {
+	// Avoid counting logical ports, such as drop and cpu
+	if (standard_metadata.egress_spec < MAX_PORTS) {
+		apply(port_count_table);
+	}
+}
\ No newline at end of file
diff --git a/tools/test/p4src/wcmp.p4 b/tools/test/p4src/wcmp.p4
new file mode 100644
index 0000000..1cb6a6c
--- /dev/null
+++ b/tools/test/p4src/wcmp.p4
@@ -0,0 +1,102 @@
+#include "include/defines.p4"
+#include "include/headers.p4"
+#include "include/parser.p4"
+#include "include/actions.p4"
+#include "include/port_counters.p4"
+
+#define SELECTOR_WIDTH 64
+
+header_type wcmp_meta_t {
+    fields {
+        groupId : 16;
+        numBits: 8;
+        selector : SELECTOR_WIDTH;
+    }
+}
+
+metadata wcmp_meta_t wcmp_meta;
+
+field_list wcmp_hash_fields {
+    ipv4.srcAddr;
+    ipv4.dstAddr;
+    ipv4.protocol;
+    tcp.srcPort;
+    tcp.dstPort;
+    udp.srcPort;
+    udp.dstPort;
+}
+
+field_list_calculation wcmp_hash {
+    input {
+        wcmp_hash_fields;
+    }
+    algorithm : bmv2_hash;
+    output_width : 64;
+}
+
+action wcmp_group(groupId) {
+    modify_field(wcmp_meta.groupId, groupId);
+    modify_field_with_hash_based_offset(wcmp_meta.numBits, 2, wcmp_hash, (SELECTOR_WIDTH - 2));
+}
+
+action wcmp_set_selector() {
+    modify_field(wcmp_meta.selector,
+                 (((1 << wcmp_meta.numBits) - 1) << (SELECTOR_WIDTH - wcmp_meta.numBits)));
+}
+
+table table0 {
+    reads {
+        standard_metadata.ingress_port : ternary;
+        ethernet.dstAddr : ternary;
+        ethernet.srcAddr : ternary;
+        ethernet.etherType : ternary;
+    }
+    actions {
+        set_egress_port;
+        wcmp_group;
+        send_to_cpu;
+        _drop;
+    }
+    support_timeout: true;
+}
+
+table wcmp_set_selector_table {
+    actions {
+        wcmp_set_selector;
+    }
+}
+
+table wcmp_group_table {
+    reads {
+        wcmp_meta.groupId : exact;
+        wcmp_meta.selector : lpm;
+    }
+    actions {
+        set_egress_port;
+    }
+}
+
+counter table0_counter {
+    type: packets;
+    direct: table0;
+    min_width : 32;
+}
+
+counter wcmp_group_table_counter {
+    type: packets;
+    direct: wcmp_group_table;
+    min_width : 32;
+}
+
+control ingress {
+    apply(table0) {
+        wcmp_group {
+            apply(wcmp_set_selector_table) {
+                wcmp_set_selector {
+                    apply(wcmp_group_table);
+                }
+            }
+        }
+    }
+    process_port_counters();
+}
\ No newline at end of file