Commit 8245e259 authored by kesnar's avatar kesnar
Browse files

wip: timestamp p4 program

parent 3ecbf159
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -72,6 +72,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
    for endpoint in device_endpoints:
@@ -157,6 +199,9 @@ class P4ServiceHandler(_ServiceHandler):
                    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)
            
                    results.append(True)
@@ -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)
+7 −0
Original line number Diff line number Diff line
#!/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
+60 −0
Original line number Diff line number Diff line
#!/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()
+6 −8
Original line number Diff line number Diff line
@@ -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 {
+281 −0
Original line number Diff line number Diff line
/*
 * 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;