实验8:数据平面可编程实践——P4

一、实验目的

  • 掌握V1Model框架下P4_16的程序结构和基本语法
  • 能够运用 P4 进行简单数据平面编程

二、实验环境

  • 下载虚拟机软件Oracle VisualBox或VMware;
  • 在虚拟机中安装Ubuntu 16.04 Desktop amd64,并安装完整Mininet和P4开发环境;
  • 提供P4镜像P4-Suite2018.ova,提取码:egwf

三、实验要求

学习P4官方示例教程,链接:https://github.com/p4lang/tutorials,了解P4-16版本的基本语法、基于V1Model的P4代码结构,完成如下练习:

(一)基本要求
熟悉使用P4实现交换机IPv4的基本转发原理,编写P4程序,在下面的拓扑中实现IPV4 隧道转发。

实验步骤:

  • 进入home/P4/tutorials/exercises/basic_tunnel,完善后basic_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();
   }
   
   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
  • pingall测试连通性

不使用隧道时:

  • 打开主机h1 h2,h3的模拟终端,并在h2,h3终端下输入./receive.py,开启服务器以便接收消息

  • 在h1输入./send.py 10.0.2.2 "hi h2,i am h1 send by 031902314hys"

  • 在h1输入./send.py 10.0.3.3 "hi h3,i am h1 send by 031902314hys"

使用隧道时

  • 在h1输入./send.py 10.0.2.2 "bye,h2 i am h1 send by 031902314hys" --dst_id 2

  • 在h1输入./send.py 10.0.3.3 "bye, i am h1 send by 031902314hys" --dst_id 2

对可知使用隧道转发时,改变IP交换机仍然将报文发送给h2主机.
个人总结

  • 实验难度:较难
  • 为了能够完成本次实验,需要学习P4语言的相关知识,花费的时间较长。还有就是百度网盘下载镜像耗费时间更长。此次实验倒是没有遇到很多问题。同学出现make run出错的现象也没有出现。
    -个人感想:通过本次实验,学习了基础的P4语言,在网络通信方面有了进一步的学习与理解。经过上学期的计网学习,加上此次课程的学习,理论与实践结合,让我也算有些许收获。
posted @ 2021-11-03 16:18  anamazingclown  阅读(29)  评论(0编辑  收藏  举报