P4 switch (thrift controller): change path

[Topology]

http://csie.nqu.edu.tw/smallko/sdn/mointorqlenp4.files/image003.png

Normally, h11 will send the traffic to h22 via s1 (ouput port 4) and s2. I will use bash to write a simple thrift controller to make s1 to change the rule so that the traffic will be directed to outport 5. Then the traffic sent from h11 h22 will go through s1 (ouput port 5), s3 and s2.

 

[qdepth.sh: thrift controller]

#!/bin/bash

 

CLI_PATH=/home/vagrant/behavioral-model/targets/simple_switch/simple_switch_CLI

 

i=0

while true; do

  #echo "get qdepth 4"

  echo -n "s1(--s2,port4): "

  echo "register_read qdepth 4" | $CLI_PATH --thrift-port 9090 | grep qdepth | awk '{print $3}'

  echo -n "s1(--s3,port5): "

  echo "register_read qdepth 5" | $CLI_PATH --thrift-port 9090 | grep qdepth | awk '{print $3}'

      

  i=$((i+1))

  if [ $i -eq 5 ]; then

        echo "change the path to 10.0.2.0/24 from port 4 ==> port 5"

       echo "table_delete ipv4_lpm 4" | $CLI_PATH --thrift-port 9090   

        echo "table_add ipv4_lpm ipv4_forward 10.0.2.0/24 => 00:00:00:02:03:00 5" | $CLI_PATH --thrift-port 9090

  fi

  sleep 1

done

 

 

[topology.py]

{

    "hosts": [

        "h1",

        "h2",

        "h3",

        "h11",

        "h22",

        "h33",

        "h44"

    ],

    "switches": {

        "s1": { "cli_input" : "s1-commands.txt" },

        "s2": { "cli_input" : "s2-commands.txt" },

        "s3": { "cli_input" : "s3-commands.txt" }

    },

    "links": [

              ["h1", "s1"], ["h11", "s1"], ["s1", "s2", "0", 0.5], ["s1", "s3", "0", 0.8],

              ["s3", "s2"], ["s2", "h2"], ["s2", "h22"], ["s3", "h3"],

              ["h33", "s1"], ["s2", "h44"]

    ]

}

 

[s1-commands.txt]

table_set_default ipv4_lpm drop

table_set_default swtrace add_swtrace 1

table_add ipv4_lpm ipv4_forward 10.0.1.1/32  => 00:00:00:00:01:01 2

table_add ipv4_lpm ipv4_forward 10.0.1.11/32 => 00:00:00:00:01:0b 1

table_add ipv4_lpm ipv4_forward 10.0.1.33/32 => 00:00:00:00:01:0b 3

table_add ipv4_lpm ipv4_forward 10.0.2.44/32 => 00:00:00:03:02:00 5

table_add ipv4_lpm ipv4_forward 10.0.2.0/24 => 00:00:00:02:03:00 4

table_add ipv4_lpm ipv4_forward 10.0.3.0/24 => 00:00:00:03:02:00 5

 

[s2-commands.txt]

table_set_default ipv4_lpm drop

table_set_default swtrace add_swtrace 2

table_add ipv4_lpm ipv4_forward 10.0.2.2/32  => 00:00:00:00:02:02 2

table_add ipv4_lpm ipv4_forward 10.0.2.22/32 => 00:00:00:00:02:16 1

table_add ipv4_lpm ipv4_forward 10.0.2.44/32 => 00:00:00:00:02:2c 3

table_add ipv4_lpm ipv4_forward 10.0.1.0/24 => 00:00:00:01:03:00 4

table_add ipv4_lpm ipv4_forward 10.0.3.0/24 => 00:00:00:03:03:00 5

 

[s3-commands.txt]

table_set_default ipv4_lpm drop

table_set_default swtrace add_swtrace 3

table_add ipv4_lpm ipv4_forward 10.0.3.3/32  => 00:00:00:00:03:01 1

table_add ipv4_lpm ipv4_forward 10.0.1.0/24 => 00:00:00:01:04:00 2

table_add ipv4_lpm ipv4_forward 10.0.2.0/24 => 00:00:00:02:04:00 3

 

[mri.p4]

/* -*- P4_16 -*- */

#include <core.p4>

#include <v1model.p4>

 

const bit<8>  UDP_PROTOCOL = 0x11;

const bit<16> TYPE_IPV4 = 0x800;

const bit<5>  IPV4_OPTION_MRI = 31;

 

#define MAX_HOPS 9

 

/*************************************************************************

*********************** H E A D E R S  ***********************************

*************************************************************************/

 

typedef bit<9>  egressSpec_t;

typedef bit<48> macAddr_t;

typedef bit<32> ip4Addr_t;

typedef bit<32> switchID_t;

typedef bit<32> qdepth_t;

 

header ethernet_t {

    macAddr_t dstAddr;

    macAddr_t srcAddr;

    bit<16>   etherType;

}

 

header ipv4_t {

    bit<4>    version;

    bit<4>    ihl;

    bit<8>    diffserv;

    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 mri_t {

    bit<16>  count;

}

 

header switch_t {

    switchID_t  swid;

    qdepth_t    qdepth;

}

 

struct ingress_metadata_t {

    bit<16>  count;

}

 

struct parser_metadata_t {

    bit<16>  remaining;

}

 

struct metadata {

    ingress_metadata_t   ingress_metadata;

    parser_metadata_t   parser_metadata;

}

 

struct headers {

    ethernet_t         ethernet;

    ipv4_t             ipv4;

    ipv4_option_t      ipv4_option;

    mri_t              mri;

    switch_t[MAX_HOPS] swtraces;

}

 

error { IPHeaderTooShort }

 

/*************************************************************************

*********************** P A R S E R  ***********************************

*************************************************************************/

 

parser MyParser(packet_in packet,

                out headers hdr,

                inout metadata meta,

                inout standard_metadata_t standard_metadata) {

 

    state start {

        transition parse_ethernet;

    }

 

    state parse_ethernet {

        packet.extract(hdr.ethernet);

        transition select(hdr.ethernet.etherType) {

            TYPE_IPV4: parse_ipv4;

            default: accept;

        }

    }

 

    state parse_ipv4 {

        packet.extract(hdr.ipv4);

        verify(hdr.ipv4.ihl >= 5, error.IPHeaderTooShort);

        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_MRI: parse_mri;

            default: accept;

        }

    }

 

    state parse_mri {

        packet.extract(hdr.mri);

        meta.parser_metadata.remaining = hdr.mri.count;

        transition select(meta.parser_metadata.remaining) {

            0 : accept;

            default: parse_swtrace;

        }

    }

 

    state parse_swtrace {

        packet.extract(hdr.swtraces.next);

        meta.parser_metadata.remaining = meta.parser_metadata.remaining  - 1;

        transition select(meta.parser_metadata.remaining) {

            0 : accept;

            default: parse_swtrace;

        }

    }   

}

 

 

/*************************************************************************

************   C H E C K S U M    V E R I F I C A T I O N   *************

*************************************************************************/

 

control MyVerifyChecksum(inout headers hdr, inout metadata meta) {  

    apply {  }

}

 

 

/*************************************************************************

**************  I N G R E S S   P R O C E S S I N G   *******************

*************************************************************************/

 

control MyIngress(inout headers hdr,

                  inout metadata meta,

                  inout standard_metadata_t standard_metadata) {

 

    action drop() {

        mark_to_drop();

    }

   

    action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {

        standard_metadata.egress_spec = port;

        hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;

        hdr.ethernet.dstAddr = dstAddr;

        hdr.ipv4.ttl = hdr.ipv4.ttl - 1;

    }

 

    table ipv4_lpm {

        key = {

            hdr.ipv4.dstAddr: lpm;

        }

        actions = {

            ipv4_forward;

            drop;

            NoAction;

        }

        size = 1024;

        default_action = NoAction();

    }

   

    apply {

        if (hdr.ipv4.isValid()) {

            ipv4_lpm.apply();

        }

    }

}

 

/*************************************************************************

****************  E G R E S S   P R O C E S S I N G   *******************

*************************************************************************/

 

control MyEgress(inout headers hdr,

                 inout metadata meta,

                 inout standard_metadata_t standard_metadata) {

 

    register<bit<32>>(256) qdepth;

    action do_add_qdepth() {

        qdepth.write((bit<32>)standard_metadata.egress_port, (qdepth_t)standard_metadata.deq_qdepth);

    }

       

    action add_swtrace(switchID_t swid) {

        hdr.mri.count = hdr.mri.count + 1;

        hdr.swtraces.push_front(1);

        hdr.swtraces[0].swid = swid;

        hdr.swtraces[0].qdepth = (qdepth_t)standard_metadata.deq_qdepth;

 

        hdr.ipv4.ihl = hdr.ipv4.ihl + 2;

        hdr.ipv4_option.optionLength = hdr.ipv4_option.optionLength + 8;

            hdr.ipv4.totalLen = hdr.ipv4.totalLen + 8;

    }

 

    table swtrace {

        actions = {

            add_swtrace;

            NoAction;

        }

        default_action = NoAction();     

    }

   

    apply {

        if (hdr.mri.isValid()) {

            swtrace.apply();

        }

        do_add_qdepth();

    }

}

 

/*************************************************************************

*************   C H E C K S U M    C O M P U T A T I O N   **************

*************************************************************************/

 

control MyComputeChecksum(inout headers hdr, inout metadata meta) {

     apply {

        update_checksum(

            hdr.ipv4.isValid(),

            { hdr.ipv4.version,

              hdr.ipv4.ihl,

              hdr.ipv4.diffserv,

              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);

    }

}

 

/*************************************************************************

***********************  D E P A R S E R  *******************************

*************************************************************************/

 

control MyDeparser(packet_out packet, in headers hdr) {

    apply {

        packet.emit(hdr.ethernet);

        packet.emit(hdr.ipv4);

        packet.emit(hdr.ipv4_option);

        packet.emit(hdr.mri);

        packet.emit(hdr.swtraces);                 

    }

}

 

/*************************************************************************

***********************  S W I T C H  *******************************

*************************************************************************/

 

V1Switch(

MyParser(),

MyVerifyChecksum(),

MyIngress(),

MyEgress(),

MyComputeChecksum(),

MyDeparser()

) main;

 

[Execution]

 

Open another terminal to start thrift controller.

 

We can see that the queue length of s1-s3 is 0 in the beginning. Then rule changes. We can see the queue length of s1-s3 is not equal to 0. So the path for the traffic sent from h11 to h12 changes.

 

Dr. Chih-Heng Ke (smallko@gmail.com)

Department of Computer Science and Information Engineering,

National Quemoy University, Kinmen, Taiwan.