P4 Switch: MAC Layer and IP Layer Forwarding

 

[Brief Description]

        The work is based on minip4 project. The P4 Switch follows the P4-14 standard. I have prepare a VM that I have installed almost everything for simulation.

 

[Topology]

h101 --------- s1 ---------- h102

 

One P4 switch (s1) and two hosts, i.e. h101 and h102.

 

[mac layer forwarding]

P4-topo.yml

defaults:

  switch:

    bmv2: ../../bmv2

    p4c: ../../p4c-bmv2

    p4src : test.p4

    dump: true

    port: 22222

    commands: commands-s101.txt

    verbose: 'debug'

 

host:

- ip: 10.0.1.1/16

  mac: 00:00:00:00:00:01

  name: h101

  command:

    - arp -s 10.0.1.2 00:00:00:00:00:02

- ip: 10.0.1.2/16

  mac: 00:00:00:00:00:02

  name: h102

  command:

    - arp -s 10.0.1.1 00:00:00:00:00:01

 

switch:

- name: s101

 

link:

- source: h101

  destination: s101

- source: h102

  destination: s101

 

commands-s101.txt

table_set_default dmac _drop

table_add dmac forward 00:00:00:00:00:01 => 1

table_add dmac forward 00:00:00:00:00:02 => 2

 

test.p4

header_type ethernet_t {

    fields {

        dstAddr : 48;

        srcAddr : 48;

        etherType : 16;

    }

}

 

header ethernet_t ethernet;

 

parser start {

    return parse_ethernet;

}

 

parser parse_ethernet {

    extract(ethernet);

    return ingress;

}

 

action _drop() {

    drop();

}

 

action forward(port) {

    modify_field(standard_metadata.egress_spec, port);

}

 

table dmac {

    reads {

        ethernet.dstAddr : exact;

    }

    actions {

        forward;

        _drop;

    }

    size : 512;

}

 

control ingress {

    apply(dmac);

}

 

control egress {

}

 

[execution]

Ping Test.

 

[IP layer forwarding]

P4-topo.yml

defaults:

  switch:

    bmv2: ../../bmv2

    p4c: ../../p4c-bmv2

    p4src : test.p4

    dump: true

    port: 22222

    commands: commands-s101.txt

    verbose: 'debug'

 

host:

- ip: 10.0.1.1/16

  mac: 00:00:00:00:00:01

  name: h101

  command:

    - arp -s 10.0.1.2 00:00:00:00:00:02

- ip: 10.0.1.2/16

  mac: 00:00:00:00:00:02

  name: h102

  command:

    - arp -s 10.0.1.1 00:00:00:00:00:01

 

 

switch:

- name: s101

 

link:

- source: h101

  destination: s101

- source: h102

  destination: s101

 

commands-s101.txt

table_set_default dmac _drop

table_add ipv4_lpm set_nhop 10.0.1.1/32 => 1

table_add ipv4_lpm set_nhop 10.0.1.2/32 => 2

 

test.p4

#define ETHERTYPE_IPV4 0x0800

#define ETHERTYPE_ARP  0x0806

#define IPPROTO_ICMP   0x01

#define ARP_HTYPE_ETHERNET  0x0001

#define ARP_PTYPE_IPV4      0x0800

#define ARP_HLEN_ETHERNET   6

#define ARP_PLEN_IPV4     4

#define ARP_OPER_REQUEST    1

#define ARP_OPER_REPLY      2

#define ICMP_ECHO_REQUEST   8

#define ICMP_ECHO_REPLY     0

 

header_type ethernet_t {

    fields {

        dstAddr : 48;

        srcAddr : 48;

        etherType : 16;

    }

}

 

header_type ipv4_t {

    fields {

        version : 4;

        ihl : 4;

        diffserv : 8;

        totalLen : 16;

        identification : 16;

        flags : 3;

        fragOffset : 13;

        ttl : 8;

        protocol : 8;

        hdrChecksum : 16;

        srcAddr : 32;

        dstAddr: 32;

    }

}

 

header_type arp_t {

    fields {

        htype : 16;

        ptype : 16;

        hlen : 8;

        plen : 8;

        opcode : 16;

        hwSrcAddr : 48;

        protoSrcAddr : 32;

        hwDstAddr : 48;

        protoDstAddr : 32;

    }

}

 

header ethernet_t ethernet;

 

parser start {

    return parse_ethernet;

}

 

parser parse_ethernet {

    extract(ethernet);

    return select(latest.etherType){

      ETHERTYPE_IPV4 : parse_ipv4;

      ETHERTYPE_ARP  : parse_arp;

      default : ingress;

    }

}

 

header ipv4_t ipv4;

 

parser parse_ipv4 {

    extract(ipv4);

    return ingress;

}

 

header arp_t arp;

 

parser parse_arp{

    extract(arp);

    return ingress;

}

 

field_list ipv4_checksum_list{

    ipv4.version;

    ipv4.ihl;

    ipv4.diffserv;

    ipv4.totalLen;

    ipv4.identification;

    ipv4.flags;

    ipv4.fragOffset;

    ipv4.ttl;

    ipv4.protocol;

    ipv4.srcAddr;

    ipv4.dstAddr;  

}

 

field_list_calculation ipv4_checksum{

    input {

      ipv4_checksum_list;

    }

    algorithm : csum16;

    output_width : 16;

}

 

calculated_field ipv4.hdrChecksum {

    verify ipv4_checksum;

    update ipv4_checksum;

}

 

action _drop() {

    drop();

}

 

action set_nhop(port) {

    modify_field(standard_metadata.egress_spec, port);

    add_to_field(ipv4.ttl, -1);

}

 

table ipv4_lpm {

    reads {

        ipv4.dstAddr : lpm;

    }

    actions {

        set_nhop;

        _drop;

    }

    default_action: _drop();

    size : 512;

}

 

control ingress {

    apply(ipv4_lpm);

}

 

control egress {

}

 

[execution]

 

Ping test.


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

Department of Computer Science and Information Engineering,

National Quemoy University, Kinmen, Taiwan.