ONOS-7000 P4 tutorial application and P4 program
Change-Id: Ia0a6befa6374a1950485c1fba0cfacb5ff4ce52c
diff --git a/apps/p4-tutorial/pipeconf/src/main/resources/main.p4 b/apps/p4-tutorial/pipeconf/src/main/resources/main.p4
new file mode 100644
index 0000000..9f0b809
--- /dev/null
+++ b/apps/p4-tutorial/pipeconf/src/main/resources/main.p4
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <core.p4>
+#include <v1model.p4>
+
+#define ETH_TYPE_IPV4 0x0800
+#define MAX_PORTS 511
+
+typedef bit<9> port_t;
+const port_t CPU_PORT = 255;
+const port_t DROP_PORT = 511;
+
+//------------------------------------------------------------------------------
+// HEADERS
+//------------------------------------------------------------------------------
+
+header ethernet_t {
+ bit<48> dst_addr;
+ bit<48> src_addr;
+ bit<16> ether_type;
+}
+
+header ipv4_t {
+ bit<4> version;
+ bit<4> ihl;
+ bit<8> diffserv;
+ bit<16> len;
+ bit<16> identification;
+ bit<3> flags;
+ bit<13> frag_offset;
+ bit<8> ttl;
+ bit<8> protocol;
+ bit<16> hdr_checksum;
+ bit<32> src_addr;
+ bit<32> dst_addr;
+}
+
+/*
+Packet-in header. Prepended to packets sent to the controller and used to carry
+the original ingress port where the packet was received.
+ */
+@controller_header("packet_in")
+header packet_in_header_t {
+ bit<9> ingress_port;
+}
+
+/*
+Packet-out header. Prepended to packets received by the controller and used to
+tell the switch on which physical port this packet should be forwarded.
+ */
+@controller_header("packet_out")
+header packet_out_header_t {
+ bit<9> egress_port;
+}
+
+/*
+For convenience we collect all headers under the same struct.
+ */
+struct headers_t {
+ ethernet_t ethernet;
+ ipv4_t ipv4;
+ packet_out_header_t packet_out;
+ packet_in_header_t packet_in;
+}
+
+/*
+Metadata can be used to carry information from one table to another.
+ */
+struct metadata_t {
+ /* Empty. We don't use it in this program. */
+}
+
+//------------------------------------------------------------------------------
+// PARSER
+//------------------------------------------------------------------------------
+
+parser ParserImpl(packet_in packet,
+ out headers_t hdr,
+ inout metadata_t meta,
+ inout standard_metadata_t standard_metadata) {
+
+ state start {
+ transition select(standard_metadata.ingress_port) {
+ CPU_PORT: parse_packet_out;
+ default: parse_ethernet;
+ }
+ }
+
+ state parse_packet_out {
+ packet.extract(hdr.packet_out);
+ transition parse_ethernet;
+ }
+
+ state parse_ethernet {
+ packet.extract(hdr.ethernet);
+ transition select(hdr.ethernet.ether_type) {
+ ETH_TYPE_IPV4: parse_ipv4;
+ default: accept;
+ }
+ }
+
+ state parse_ipv4 {
+ packet.extract(hdr.ipv4);
+ transition accept;
+ }
+}
+
+//------------------------------------------------------------------------------
+// INGRESS PIPELINE
+//------------------------------------------------------------------------------
+
+control IngressImpl(inout headers_t hdr,
+ inout metadata_t meta,
+ inout standard_metadata_t standard_metadata) {
+
+ action send_to_cpu() {
+ standard_metadata.egress_spec = CPU_PORT;
+ /*
+ Packets sent to the controller needs to be prepended with the packet-in
+ header. By setting it valid we make sure it will be deparsed before the
+ ethernet header (see DeparserImpl).
+ */
+ hdr.packet_in.setValid();
+ hdr.packet_in.ingress_port = standard_metadata.ingress_port;
+ }
+
+ action set_egress_port(port_t port) {
+ standard_metadata.egress_spec = port;
+ }
+
+ action _drop() {
+ standard_metadata.egress_spec = DROP_PORT;
+ }
+
+ table table0 {
+ key = {
+ standard_metadata.ingress_port : ternary;
+ hdr.ethernet.dst_addr : ternary;
+ hdr.ethernet.src_addr : ternary;
+ hdr.ethernet.ether_type : ternary;
+ }
+ actions = {
+ set_egress_port();
+ send_to_cpu();
+ _drop();
+ }
+ default_action = _drop();
+ }
+
+ table ip_proto_filter_table {
+ key = {
+ hdr.ipv4.src_addr : ternary;
+ hdr.ipv4.protocol : exact;
+ }
+ actions = {
+ _drop();
+ }
+ }
+
+ /*
+ Port counters.
+ We use these counter instances to count packets/bytes received/sent on each
+ port. BMv2 always counts both packets and bytes, even if the counter is
+ instantiated as "packets". For each counter we instantiate a number of cells
+ equal to MAX_PORTS.
+ */
+ counter(MAX_PORTS, CounterType.packets) egr_port_counter;
+ counter(MAX_PORTS, CounterType.packets) igr_port_counter;
+
+ /*
+ We define here the processing to be executed by this ingress pipeline.
+ */
+ apply {
+ if (standard_metadata.ingress_port == CPU_PORT) {
+ /*
+ Packet received from CPU_PORT, this is a packet-out sent by the
+ controller. Skip pipeline processing, set the egress port as
+ requested by the controller (packet_out header) and remove the
+ packet_out header.
+ */
+ standard_metadata.egress_spec = hdr.packet_out.egress_port;
+ hdr.packet_out.setInvalid();
+ } else {
+ /*
+ Packet received from switch port. Apply table0, if action is
+ set_egress_port and packet is IPv4, then apply
+ ip_proto_filter_table.
+ */
+ switch(table0.apply().action_run) {
+ set_egress_port: {
+ if (hdr.ipv4.isValid()) {
+ ip_proto_filter_table.apply();
+ }
+ }
+ }
+ }
+
+ /*
+ For each port counter, we update the cell at index = ingress/egress
+ port. We avoid counting packets sent/received on CPU_PORT or dropped
+ (DROP_PORT).
+ */
+ if (standard_metadata.egress_spec < MAX_PORTS) {
+ egr_port_counter.count((bit<32>) standard_metadata.egress_spec);
+ }
+ if (standard_metadata.ingress_port < MAX_PORTS) {
+ igr_port_counter.count((bit<32>) standard_metadata.ingress_port);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// EGRESS PIPELINE
+//------------------------------------------------------------------------------
+
+control EgressImpl(inout headers_t hdr,
+ inout metadata_t meta,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ /*
+ Nothing to do on the egress pipeline.
+ */
+ }
+}
+
+//------------------------------------------------------------------------------
+// CHECKSUM HANDLING
+//------------------------------------------------------------------------------
+
+control VerifyChecksumImpl(in headers_t hdr, inout metadata_t meta) {
+ apply {
+ /*
+ Nothing to do here, we assume checksum is always correct.
+ */
+ }
+}
+
+control ComputeChecksumImpl(inout headers_t hdr, inout metadata_t meta) {
+ apply {
+ /*
+ Nothing to do here, as we do not modify packet headers.
+ */
+ }
+}
+
+//------------------------------------------------------------------------------
+// DEPARSER
+//------------------------------------------------------------------------------
+
+control DeparserImpl(packet_out packet, in headers_t hdr) {
+ apply {
+ /*
+ Deparse headers in order. Only valid headers are emitted.
+ */
+ packet.emit(hdr.packet_in);
+ packet.emit(hdr.ethernet);
+ packet.emit(hdr.ipv4);
+ }
+}
+
+//------------------------------------------------------------------------------
+// SWITCH INSTANTIATION
+//------------------------------------------------------------------------------
+
+V1Switch(ParserImpl(),
+ VerifyChecksumImpl(),
+ IngressImpl(),
+ EgressImpl(),
+ ComputeChecksumImpl(),
+ DeparserImpl()) main;