diff --git a/src/service/service/service_handlers/p4/p4_service_handler.py b/src/service/service/service_handlers/p4/p4_service_handler.py index 41cfcc5952601a16a13cd691f2e424017936aaa3..558f6a590620ec96e4dd3db88599acd037041268 100644 --- a/src/service/service/service_handlers/p4/p4_service_handler.py +++ b/src/service/service/service_handlers/p4/p4_service_handler.py @@ -71,6 +71,48 @@ def create_rule_del(endpoint_a, endpoint_b): ] } ) + +def create_int_set(endpoint_a, id): + return json_config_rule_set( + 'table', + { + 'table-name': 'EgressPipeImpl.int_table', + 'match-fields': [ + { + 'match-field': 'standard_metadata.ingress_port', + 'match-value': endpoint_a + } + ], + 'action-name': 'EgressPipeImpl.add_int_header', + 'action-params': [ + { + 'action-param': 'swid', + 'action-value': id + } + ] + } + ) + +def create_int_del(endpoint_a, id): + return json_config_rule_delete( + 'table', + { + 'table-name': 'EgressPipeImpl.int_table', + 'match-fields': [ + { + 'match-field': 'standard_metadata.ingress_port', + 'match-value': endpoint_a + } + ], + 'action-name': 'EgressPipeImpl.add_int_header', + 'action-params': [ + { + 'action-param': 'swid', + 'action-value': id + } + ] + } + ) def find_names(uuid_a, uuid_b, device_endpoints): endpoint_a, endpoint_b = None, None @@ -156,6 +198,9 @@ class P4ServiceHandler(_ServiceHandler): # The other way rule = create_rule_set(endpoint_b, endpoint_a) device.device_config.config_rules.append(ConfigRule(**rule)) + + rule = create_int_set(endpoint_a, device.name[-1]) + device.device_config.config_rules.append(ConfigRule(**rule)) self.__task_executor.configure_device(device) @@ -228,6 +273,9 @@ class P4ServiceHandler(_ServiceHandler): rule = create_rule_del(endpoint_b, endpoint_a) device.device_config.config_rules.append(ConfigRule(**rule)) + rule = create_int_del(endpoint_a, device.name[-1]) + device.device_config.config_rules.append(ConfigRule(**rule)) + self.__task_executor.configure_device(device) results.append(True) diff --git a/src/tests/hackfest3/new-probe/install-scapy.sh b/src/tests/hackfest3/new-probe/install-scapy.sh new file mode 100644 index 0000000000000000000000000000000000000000..59db5c7a92b6b1f104faf5b97a698b025db9d7b4 --- /dev/null +++ b/src/tests/hackfest3/new-probe/install-scapy.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +sed -i 's/deb.debian.org/archive.debian.org/g' /etc/apt/sources.list +sed -i 's|security.debian.org|archive.debian.org/debian-security/|g' /etc/apt/sources.list +sed -i '/stretch-updates/d' /etc/apt/sources.list +apt update +apt install -y python-scapy diff --git a/src/tests/hackfest3/new-probe/receive2.py b/src/tests/hackfest3/new-probe/receive2.py new file mode 100644 index 0000000000000000000000000000000000000000..9aea2c5a9636b6802475a7bf1f6685fc78db5665 --- /dev/null +++ b/src/tests/hackfest3/new-probe/receive2.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +import sys +import struct + +from scapy.all import sniff, sendp, hexdump, get_if_list, get_if_hwaddr +from scapy.all import Packet, IPOption +from scapy.all import PacketListField, ShortField, IntField, LongField, BitField, FieldListField, FieldLenField +from scapy.all import IP, UDP, Raw +from scapy.layers.inet import _IPOption_HDR + + +def get_if(): + ifs=get_if_list() + iface=None + for i in get_if_list(): + if "eth0" in i: + iface=i + break + if not iface: + print("Cannot find eth0 interface") + exit(1) + return iface + + +class SwitchTrace(Packet): + fields_desc = [ BitField("timestamp", 0, 32)] + def extract_padding(self, p): + return "", p + + +class IPOption_INT(IPOption): + name = "INT" + option = 31 + fields_desc = [ _IPOption_HDR, + FieldLenField("length", None, fmt="B", + length_of="int_headers", + adjust=lambda pkt,l:l*2+4), + ShortField("count", 0), + PacketListField("int_headers", + [], + SwitchTrace, + count_from=lambda pkt:(pkt.count*1)) ] + + +def handle_pkt(pkt): + print("got a packet") + pkt.show2() + sys.stdout.flush() + + +def main(): + iface = 'server-eth0' + print("sniffing on %s" % iface) + sys.stdout.flush() + sniff(filter="udp and port 4321", iface = iface, + prn = lambda x: handle_pkt(x)) + + +if __name__ == '__main__': + main() diff --git a/src/tests/hackfest3/p4/main.p4 b/src/tests/hackfest3/p4/main.p4 index 2594fab2c7c5e71982ba12d1f686161cc7076b33..68d93fe947f090bc4e0ae1d09b315337a2e9aa0e 100644 --- a/src/tests/hackfest3/p4/main.p4 +++ b/src/tests/hackfest3/p4/main.p4 @@ -35,8 +35,7 @@ typedef bit<48> macAddr_t; typedef bit<32> ip4Addr_t; typedef bit<13> switch_id_t; -typedef bit<13> queue_depth_t; -typedef bit<6> output_port_t; +typedef bit<32> queue_depth_t; header ethernet_t { macAddr_t dstAddr; @@ -72,9 +71,7 @@ header int_count_t { } header int_header_t { - switch_id_t switch_id; queue_depth_t queue_depth; - output_port_t output_port; } @@ -206,9 +203,7 @@ control EgressPipeImpl (inout parsed_headers_t hdr, // This was not needed in older specs. Now by default pushed // invalid elements are hdr.int_headers[0].setValid(); - hdr.int_headers[0].switch_id = (bit<13>)swid; - hdr.int_headers[0].queue_depth = (bit<13>)standard_metadata.deq_timedelta; - hdr.int_headers[0].output_port = (bit<6>)standard_metadata.egress_port; + hdr.int_headers[0].queue_depth = (bit<32>)standard_metadata.ingress_global_timestamp; //update ip header length hdr.ipv4.ihl = hdr.ipv4.ihl + 1; @@ -217,11 +212,14 @@ control EgressPipeImpl (inout parsed_headers_t hdr, } table int_table { + key = { + standard_metadata.ingress_port: exact; + } actions = { add_int_header; NoAction; } - default_action = NoAction(); + default_action = NoAction; } apply { diff --git a/src/tests/hackfest3/p4/qdepth.main.p4 b/src/tests/hackfest3/p4/qdepth.main.p4 new file mode 100644 index 0000000000000000000000000000000000000000..4a4f56c255c31d11c505afd3cf3bf72211ba0317 --- /dev/null +++ b/src/tests/hackfest3/p4/qdepth.main.p4 @@ -0,0 +1,281 @@ +/* + * Copyright 2019-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> + +typedef bit<9> port_num_t; +typedef bit<48> mac_addr_t; + +//------------------------------------------------------------------------------ +// HEADER DEFINITIONS +//------------------------------------------------------------------------------ + +#define MAX_INT_HEADERS 9 + +const bit<16> TYPE_IPV4 = 0x800; +const bit<5> IPV4_OPTION_INT = 31; + +typedef bit<9> egressSpec_t; +typedef bit<48> macAddr_t; +typedef bit<32> ip4Addr_t; + +typedef bit<13> switch_id_t; +typedef bit<13> queue_depth_t; +typedef bit<6> output_port_t; + +header ethernet_t { + macAddr_t dstAddr; + macAddr_t srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<6> dscp; + bit<2> ecn; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + ip4Addr_t srcAddr; + ip4Addr_t dstAddr; +} + +header ipv4_option_t { + bit<1> copyFlag; + bit<2> optClass; + bit<5> option; + bit<8> optionLength; +} + +header int_count_t { + bit<16> num_switches; +} + +header int_header_t { + switch_id_t switch_id; + queue_depth_t queue_depth; + output_port_t output_port; +} + + +struct parser_metadata_t { + bit<16> num_headers_remaining; +} + +struct local_metadata_t { + parser_metadata_t parser_metadata; +} + +struct parsed_headers_t { + ethernet_t ethernet; + ipv4_t ipv4; + ipv4_option_t ipv4_option; + int_count_t int_count; + int_header_t[MAX_INT_HEADERS] int_headers; +} + +error { IPHeaderWithoutOptions } + +//------------------------------------------------------------------------------ +// INGRESS PIPELINE +//------------------------------------------------------------------------------ + +parser ParserImpl(packet_in packet, + out parsed_headers_t hdr, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + + state start { + + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType){ + TYPE_IPV4: parse_ipv4; + default: accept; + } + } + + state parse_ipv4 { + packet.extract(hdr.ipv4); + //Check if ihl is bigger than 5. Packets without ip options set ihl to 5. + verify(hdr.ipv4.ihl >= 5, error.IPHeaderWithoutOptions); + transition select(hdr.ipv4.ihl) { + 5 : accept; + default : parse_ipv4_option; + } + } + + state parse_ipv4_option { + packet.extract(hdr.ipv4_option); + transition select(hdr.ipv4_option.option){ + + IPV4_OPTION_INT: parse_int; + default: accept; + + } + } + + state parse_int { + packet.extract(hdr.int_count); + local_metadata.parser_metadata.num_headers_remaining = hdr.int_count.num_switches; + transition select(local_metadata.parser_metadata.num_headers_remaining){ + 0: accept; + default: parse_int_headers; + } + } + + state parse_int_headers { + packet.extract(hdr.int_headers.next); + local_metadata.parser_metadata.num_headers_remaining = local_metadata.parser_metadata.num_headers_remaining -1 ; + transition select(local_metadata.parser_metadata.num_headers_remaining){ + 0: accept; + default: parse_int_headers; + } + } +} + +control VerifyChecksumImpl(inout parsed_headers_t hdr, + inout local_metadata_t meta) +{ + apply { /* EMPTY */ } +} + + +control IngressPipeImpl (inout parsed_headers_t hdr, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + + action drop() { + mark_to_drop(standard_metadata); + } + + action set_egress_port(port_num_t port) { + standard_metadata.egress_spec = port; + } + + // --- l2_exact_table ------------------ + + table l2_exact_table { + key = { + standard_metadata.ingress_port: exact; + } + actions = { + set_egress_port; + @defaultonly drop; + } + const default_action = drop; + } + + apply { + l2_exact_table.apply(); + } +} + +//------------------------------------------------------------------------------ +// EGRESS PIPELINE +//------------------------------------------------------------------------------ + +control EgressPipeImpl (inout parsed_headers_t hdr, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + + + action add_int_header(switch_id_t swid){ + //increase int stack counter by one + hdr.int_count.num_switches = hdr.int_count.num_switches + 1; + hdr.int_headers.push_front(1); + // This was not needed in older specs. Now by default pushed + // invalid elements are + hdr.int_headers[0].setValid(); + hdr.int_headers[0].switch_id = (bit<13>)swid; + hdr.int_headers[0].queue_depth = (bit<13>)standard_metadata.deq_qdepth; + hdr.int_headers[0].output_port = (bit<6>)standard_metadata.egress_port; + + //update ip header length + hdr.ipv4.ihl = hdr.ipv4.ihl + 1; + hdr.ipv4.totalLen = hdr.ipv4.totalLen + 4; + hdr.ipv4_option.optionLength = hdr.ipv4_option.optionLength + 4; + } + + table int_table { + key = { + standard_metadata.ingress_port: exact; + } + actions = { + add_int_header; + NoAction; + } + default_action = NoAction; + } + + apply { + if (hdr.int_count.isValid()){ + int_table.apply(); + } + } +} + + +control ComputeChecksumImpl(inout parsed_headers_t hdr, + inout local_metadata_t local_metadata) +{ + apply { + update_checksum( + hdr.ipv4.isValid(), + { hdr.ipv4.version, + hdr.ipv4.ihl, + hdr.ipv4.dscp, + hdr.ipv4.ecn, + hdr.ipv4.totalLen, + hdr.ipv4.identification, + hdr.ipv4.flags, + hdr.ipv4.fragOffset, + hdr.ipv4.ttl, + hdr.ipv4.protocol, + hdr.ipv4.srcAddr, + hdr.ipv4.dstAddr }, + hdr.ipv4.hdrChecksum, + HashAlgorithm.csum16); + } +} + +control DeparserImpl(packet_out packet, in parsed_headers_t hdr) { + apply { + + //parsed headers have to be added again into the packet. + packet.emit(hdr.ethernet); + packet.emit(hdr.ipv4); + packet.emit(hdr.ipv4_option); + packet.emit(hdr.int_count); + packet.emit(hdr.int_headers); + + } +} + +V1Switch( + ParserImpl(), + VerifyChecksumImpl(), + IngressPipeImpl(), + EgressPipeImpl(), + ComputeChecksumImpl(), + DeparserImpl() +) main;