Experiment 8: data plane programming practice - P4

1, Experimental purpose

Master P4 under V1Model framework_ 16 program structure and basic syntax
Be able to use P4 for simple data plane programming

2, Experimental environment

Download the virtual machine software Oracle VisualBox or VMware;
Install Ubuntu 16.04 Desktop amd64 in the virtual machine, and install the complete Mininet and P4 development environment;
Provide P4 image P4-Suite2018.ova, extraction code: egwf

3, Experimental requirements

Learn the P4 official sample tutorial, link: https://github.com/p4lang/tutorials, Understand the basic syntax of P4-16 version and the P4 code structure based on V1Model, and complete the following exercises:

(1) Basic requirements

Be familiar with the basic forwarding principle of switch IPv4 using P4, write P4 program, and realize IPv4 tunnel forwarding in the following topology

  • Supplement basic in P4 tutorial_ tunnel.p4
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>
const bit<16> TYPE_MYTUNNEL = 0x1212;
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 myTunnel_t {
    bit<16> proto_id;
    bit<16> dst_id;
}
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;
    myTunnel_t   myTunnel;
    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_MYTUNNEL: parse_myTunnel;
            TYPE_IPV4: parse_ipv4;
            default: accept;
        }
    } 
    state parse_myTunnel {
        packet.extract(hdr.myTunnel);
        transition select(hdr.myTunnel.proto_id) {
            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(standard_metadata);
    } 
    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 = drop()
    }
    action myTunnel_forward(egressSpec_t port) {
        standard_metadata.egress_spec = port;
    }
    table myTunnel_exact {
        key = {
            hdr.myTunnel.dst_id: exact;
        }
        actions = {
            myTunnel_forward;
            drop;
        }
        size = 1024;
        default_action = drop();
    }
    apply {
        if (hdr.ipv4.isValid() && !hdr.myTunnel.isValid()) {
            // Process only non-tunneled IPv4 packets
            ipv4_lpm.apply();
        }
        if (hdr.myTunnel.isValid()) {
           // process tunneled packets
            myTunnel_exact.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.myTunnel);
        packet.emit(hdr.ipv4);
    }
} 
/*************************************************************************
***********************  S W I T C H  *******************************
*************************************************************************/
V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main;

make run

Compile and run the above program

xterm h1 h2 h3

Open the terminal and run it in h2 and h3

./receive.py

Start listening

Start sending packets to h2 and h3 when running on the h1 command line
1. Tunnel not used:

  • Using the command in h1
./send.py 10.0.2.2 "102192121"

  • Using the command in h1
./send.py 10.0.3.3 "102192121"


As shown in the figure, without tunnel forwarding, when h1 sends a message to h2, h3 cannot receive it, and when h1 sends a message to h3, h2 cannot receive it.
2. Use tunnel:

  • Using the command in h1
./send.py 10.0.2.2 "102192121 tunnel" --dst_id 3


When using tunnel forwarding, packets in h1 ignore the destination ip address of 10.0.2.2, and according to dst_id service h3.

4, Personal summary:

The experimental design is still difficult. There is a problem in installing the software, which is easy to solve. It is difficult to learn P4 later. Finally, I asked the students how to do it. There were errors due to code problems.

After modifying the program code, the problem was solved. The later packet transmission is relatively simple, and the main problem is the programming.
In general, this experiment has learned a lot of new knowledge and understood P4 under the V1Model framework_ 16 program structure and basic syntax, as well as being able to use P4 for simple data plane programming, which has benefited me a lot.

Posted by DimeDropper on Thu, 04 Nov 2021 13:51:16 -0700