Source Routing for p4_16 (Add the routing information at the ingress switch of network)

 

Based on https://github.com/p4lang/tutorials/tree/master/exercises/source_routing, I re-write the code. The difference is that the routing information is added when the packet enters the network, rather than at source node. Then each switch along the transmission path will pop out a record from the routing headers and forward the packet to the corresponding output port.

 

h1 ----- (port 1) s1 (port 2)----- (port 2) s2 (port 1) ------h2

 

the packet format between h1 and s1:  Ethernet header --- IP header ---Data

 

when the packet enters s1, the routing information will be added. So that the packet will look like:  Ethernet header --- 2, 1 --- IP header ---Data (2 means the output port for the first switch along the transmission path. 1 means the second output port) When s1 sends out the packet, it will pop the first record, i.e. 2. And s1 will know that the packet should be sent out throughput output port 2.

 

the packet between s1 and s2: Ethernet header --- 1 --- IP header---Data

 

when s2 pops out the source routing information, i.e. 1, it will send the packet out through output port 1.

 

the packet between s2 and h2: Ethernet header --- IP header ---Data

 

The advantage of this method: we don’t need to change anything at the hosts. We only need to added the routing information at the ingress switch. The core switches only need to pop one routing record and forward the packets according to the information indicated by the popped routing record.

 

[topology.json]

{

    "hosts": [

        "h1",

        "h2"

    ],

    "switches": {

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

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

    },

    "links": [

        ["h1", "s1", "0.1ms", 10 ], ["s1", "s2", "5ms", 0.5 ], ["s2", "h2", "0.1ms", 10]

    ]

}

 

Makefile

include ../../utils/Makefile

 

s1-command.txt  (when we set the output ports information, we need the set them in a reversed way. In this example, the routing information will be 2, 1. So we need to set the routing information as 1,2. So 10.0.2.2/32 => 1 1 means when the destination is 10.0.2.2/32, we set the first output port to 1. The second 1 means that we have more routing information. So the second 10.0.2.2/32 => 2 0 means when the destination is 10.0.2.2/32, we set the second output port to 2. The 0 after 2 means that we don’t have any more routing information.)

table_add ipv4_lpm AddHeader  10.0.2.2/32 => 1 1

table_add ipv4_lpm2 AddHeader2  10.0.2.2/32 => 2 0

table_add ipv4_final dmac 10.0.1.1/32 => 00:00:00:00:01:01

 

s2-command.txt

table_add ipv4_lpm AddHeader  10.0.1.1/32 => 1 1

table_add ipv4_lpm2 AddHeader2  10.0.1.1/32 => 2 0

table_add ipv4_final dmac 10.0.2.2/32 => 00:00:00:00:02:02

 

source_routing.p4

/* -*- P4_16 -*- */

#include <core.p4>

#include <v1model.p4>

 

const bit<16> TYPE_IPV4 = 0x800;

const bit<16> TYPE_SRCROUTING = 0x1234;

 

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

 

header ethernet_t {

    macAddr_t dstAddr;

    macAddr_t srcAddr;

    bit<16>   etherType;

}

 

header srcRoute_t {

    bit<1>    bos;

    bit<15>   port;

}

 

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;

}

 

struct metadata {

}

 

struct headers {

    ethernet_t              ethernet;

    srcRoute_t[MAX_HOPS]    srcRoutes;

    ipv4_t                  ipv4;

}

 

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

*********************** 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_SRCROUTING: parse_srcRouting;

            TYPE_IPV4: parse_ipv4;

            default: accept;

        }

    }

 

    state parse_srcRouting {

        packet.extract(hdr.srcRoutes.next);

        transition select(hdr.srcRoutes.last.bos) {

            1: parse_ipv4;

            default: parse_srcRouting;

        }

    }

 

    state parse_ipv4 {

        packet.extract(hdr.ipv4);

        transition accept;

    }

 

}

 

 

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

************   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 srcRoute_nhop() {

        standard_metadata.egress_spec = (bit<9>)hdr.srcRoutes[0].port;

        hdr.srcRoutes.pop_front(1);

    }

 

    action srcRoute_finish() {

        hdr.ethernet.etherType = TYPE_IPV4;

    }

 

    action update_ttl(){

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

    }

 

    action AddHeader(bit<15> port, bit<1> flag){

        hdr.ethernet.etherType = TYPE_SRCROUTING;

        hdr.ipv4.diffserv=(bit<8>)flag;

        hdr.srcRoutes.push_front(1); 

        hdr.srcRoutes[0].port=port;

        hdr.srcRoutes[0].bos=1;

        hdr.srcRoutes[0].setValid();

    }

 

    action AddHeader2(bit<15> port, bit<1> flag){

        hdr.srcRoutes.push_front(1);

        hdr.srcRoutes[0].port=port; 

        hdr.srcRoutes[0].bos=0;

        hdr.ipv4.diffserv=(bit<8>)flag;

    }

 

    action AddHeader3(bit<15> port, bit<1> flag){

        hdr.srcRoutes.push_front(1);

        hdr.srcRoutes[0].port=port; 

        hdr.srcRoutes[0].bos=0;       

        hdr.ipv4.diffserv=(bit<8>)flag;

    }

 

    action AddHeader4(bit<15> port, bit<1> flag){

        hdr.srcRoutes.push_front(1);

        hdr.srcRoutes[0].port=port; 

        hdr.srcRoutes[0].bos=0;       

        hdr.ipv4.diffserv=(bit<8>)flag;

    }

 

    action AddHeader5(bit<15> port, bit<1> flag){

        hdr.srcRoutes.push_front(1);

        hdr.srcRoutes[0].port=port; 

        hdr.srcRoutes[0].bos=0;       

        hdr.ipv4.diffserv=(bit<8>)flag;

    } 

  

    table ipv4_lpm {

        key = {

            hdr.ipv4.dstAddr: lpm;

        }

        actions = {

            AddHeader;

            drop;

        }

        size = 1024;

        default_action = drop();

    }

 

    table ipv4_lpm2 {

        key = {

            hdr.ipv4.dstAddr: lpm;

        }

        actions = {

            AddHeader2;

            drop;

        }

        size = 1024;

        default_action = drop();

    }

 

    table ipv4_lpm3 {

        key = {

            hdr.ipv4.dstAddr: lpm;

        }

        actions = {

            AddHeader3;

            drop;

        }

        size = 1024;

        default_action = drop();

    }

 

    table ipv4_lpm4 {

        key = {

            hdr.ipv4.dstAddr: lpm;

        }

        actions = {

            AddHeader4;

            drop;

        }

        size = 1024;

        default_action = drop();

    }

 

    table ipv4_lpm5 {

        key = {

            hdr.ipv4.dstAddr: lpm;

        }

        actions = {

            AddHeader5;

            drop;

        }

        size = 1024;

        default_action = drop();

    }

 

    apply {

 

        if (hdr.ethernet.etherType == TYPE_IPV4){

                   ipv4_lpm.apply();

        }

       

        if (hdr.ipv4.diffserv == 1) {

                ipv4_lpm2.apply();

        }

 

        if (hdr.ipv4.diffserv == 1) {

                ipv4_lpm3.apply();

        }

 

        if (hdr.ipv4.diffserv == 1) {

                ipv4_lpm4.apply();

        } 

 

        if (hdr.ipv4.diffserv == 1) {

                ipv4_lpm5.apply();

        }

 

        if (hdr.srcRoutes[0].isValid()){

            if (hdr.srcRoutes[0].bos == 1){

                srcRoute_finish();

            }

            srcRoute_nhop();

            if (hdr.ipv4.isValid()){

                update_ttl();

            }

        }else{

            drop();

        }

    }

}

 

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

****************  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) {

    

     action dmac(macAddr_t dstAddr) {

        hdr.ethernet.dstAddr = dstAddr;

     }   

 

     table ipv4_final {

        key = {

            hdr.ipv4.dstAddr: lpm;

        }

        actions = {

            dmac;

            NoAction;

        }

        size = 1024;

        default_action = NoAction();

    }

       

 

    apply {

       ipv4_final.apply();

    }

}

 

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

*************   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.srcRoutes);

        packet.emit(hdr.ipv4);

    }

}

 

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

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

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

 

V1Switch(

MyParser(),

MyVerifyChecksum(),

MyIngress(),

MyEgress(),

MyComputeChecksum(),

MyDeparser()

) main;

 

[Execution]

 

Ping test. (We monitor the packets at the s1-eth2. From the following figure that we can see that Ethernet type is 0x1234 (routing information header). Followed by 12 34, we can see 80 01.

(80 means the last record. If it is not the last record, we can see 00. 01 is the output port for the next switch)

 

Iperf test

 

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

Department of Computer Science and Information Engineering,

National Quemoy University, Kinmen, Taiwan.