How to run p4 bmv2 docker in mininet ?

In this lab, I will show how to run p4 bmv2 in a docker host in mininet. Refer to https://github.com/cslev/p4-bmv2-docker and https://hub.docker.com/r/cslev/p4-bmv2-p4runtime, I put this docker in my “P4 Switch + Mininet + Docker Host” environment.

 

[Topology]

 

[basic.p4]

/* -*- P4_16 -*- */

#include <core.p4>

#include <v1model.p4>

 

const bit<16> TYPE_IPV4 = 0x800;

 

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

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

    /* empty */

}

 

struct headers {

    ethernet_t   ethernet;

    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_IPV4: parse_ipv4;

            default: accept;

        }

    }

 

    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 forward(egressSpec_t port) {

        standard_metadata.egress_spec = port;

    }

   

    table phy_forward {

        key = {

            standard_metadata.ingress_port: exact;

        }

        actions = {

            forward;

            drop;

        }

        size = 1024;

        default_action = drop();

    }

   

    apply {

        phy_forward.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) {

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

    }

}

 

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

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

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

 

V1Switch(

MyParser(),

MyVerifyChecksum(),

MyIngress(),

MyEgress(),

MyComputeChecksum(),

MyDeparser()

) main;

 

[cmd.txt]

table_add phy_forward forward 1 => 2

table_add phy_forward forward 2 => 1

 

[dockerhost2.py]

#!/usr/bin/python

 

from mininet.net import Containernet

from mininet.node import Controller, Docker, OVSSwitch

from mininet.cli import CLI

from mininet.log import setLogLevel, info

from mininet.link import TCLink, Link

 

 

def topology():

 

    "Create a network with some docker containers acting as hosts."

 

    net = Containernet(controller=Controller)

 

    info('*** Adding hosts\n')

    h1 = net.addHost('h1', ip="192.168.1.1/24")

    h2 = net.addHost('h2', ip="192.168.1.2/24")

 

    info('*** Adding docker containers\n')

    d1 = net.addDocker('d1', dimage="cslev/p4-bmv2-p4runtime:full")

 

    info('*** Creating links\n')

    net.addLink(h1, d1)

    net.addLink(h2, d1)

    info('*** Starting network\n')

    net.start()

 

    info('*** Running CLI\n')

    CLI(net)

 

    info('*** Stopping network')

    net.stop()

 

if __name__ == '__main__':

    setLogLevel('info')

    topology()

 

[execution]

1.      Download the p4 bmv4 docker image.

 

2.      Compile the basic.p4

 

3.      Run the mininet script

 

4.      Open another terminal and go into the d1 docker host (p4 bmv2).

 

5.      Install openssh-client and use scp to copy the basic.json into the docker.

 

 

 

6.      Run the simple_switch with basic.json

 

7.      Open another terminal and set the p4 switch rules through thrift protocol

 

8.      Test ping

 

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

Department of Computer Science and Information Engineering,

National Quemoy University, Kinmen, Taiwan.