P4 tutorials实验 - basic

P4 tutorials实验 - basic

基础知识

  • P4,是网络设备的域特定语言,用于指定数据平面设备(交换机、网卡、路由器等)如何处理数据包
  • Bmv2 simple_switch是一种软件交换机
  • V1Model架构,是在simple_switch上实现的,用于测试P4程序功能

其中,parser,deparser都是可编程的,parser可以用某种P4定义的方式提取数据包头,deparser用来按照P4程序的规定,重构数据包

  • bit< n >:无符号整数,可使用typedef增加别名,提高可读性

实验预览

实验链接:https://github.com/p4lang/tutorials/tree/master/exercises/basic

本实验的目标是写一个P4程序,实现基本的转发,为简单起见,只实现ipv4的转发

在basic目录下提供的基本的p4程序basic.p4会丢弃所有数据包,我们的工作是扩展这个程序(完成代码中的TODO部分),使其能够正确转发ipv4数据包

需要实现TODO的部分有:

parser部分

parser MyParser(packet_in packet,
                out headers hdr,
                inout metadata meta,
                inout standard_metadata_t standard_metadata) {
//inout: 同时作为输入和输出值,类似 c++ 里面的引用
    state start {
        /* TODO: add parser logic */
        //可以填充ethernet_t和ipv4_t字段
        transition accept;
    }
}//MyParser的作用是解析数据包,提取包头

ingress processing部分

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) {
        /* TODO: fill out code in action body */
    }
    //要实现一个ipv4_forward操作,可以设置下一跳的出端口、用交换机的MAC地址更新数据包的源MAC地址、用下一个跃点的地址更新数据包的目的MAC地址,并减少ttl字段
    
    table ipv4_lpm {
        key = {
            hdr.ipv4.dstAddr: lpm;
        }
        actions = {
            ipv4_forward;
            drop;
            NoAction;
        }
        size = 1024;
        default_action = NoAction();
    }
    apply {
        /* TODO: fix ingress control logic
         *  - ipv4_lpm should be applied only when IPv4 header is valid
         */
        ipv4_lpm.apply();
    }
}//MyIngress的作用是输入处理

deparser部分

control MyDeparser(packet_out packet, in headers hdr) {
    apply {
        /* TODO: add deparser logic */
    }
}//MyDeparser是逆解析器

具体实验

step 1:修改basic.p4之前

在basic目录下,用make run命令编译运行basic.p4实验,发现无法ping通

step 2:修改basic.p4

参考basic/solution目录下的basic.p4

  • parser部分
parser MyParser(packet_in packet,
                out headers hdr,
                inout metadata meta,
                inout standard_metadata_t standard_metadata) {

    state start {
        transition parse_ethernet;
        //单独的transition可以理解为跳转
    }

    state parse_ethernet {
        packet.extract(hdr.ethernet);
        //提取ethernet部分,也就是根据ethernet_t中定义的格式来提取报头内容
        transition select(hdr.ethernet.etherType) {
            TYPE_IPV4: parse_ipv4;
            	//如果etherType==Type_IPV4,则转到ipv4_parser状态
            default: accept;
            	//如果是其他值,默认接受
        }
    }

    state parse_ipv4 {//ipv4解析部分
        packet.extract(hdr.ipv4);//取出ipv4报头
        transition accept;
    }
}

Parser可以看作一个状态机,Parser始终以start状态开始,执行零或多个语句,转换到另一个状态,直到遇到accept或reject状态。所以代码从state start处开始执行。当解析器开始对首部实例进行提取操作时,它根据作为extract函数参数的首部实例的格式进行提取,将数据包的数据更新到该首部实例中,同时更新该数据包的解析表示。transition select可以理解为C语言中的switch-case语句,对参数进行值的匹配。

在此基础上,改写成:

state start{
	packet.extract(hdr.ethernet);
    transition select(hdr.ethernet.etherType){
    	TYPE_IPV4: ipv4_parser;
        default: accept;
    }
    state ipv4_parser{
        packet.extract(hdr.ipv4);
        transition accept;
    }
}

也可以实现相同的功能

  • ingress processing部分
//actions可以看成C语言的函数(但没有循环)
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
	standard_metadata.egress_spec = port;
	//设置下一跳的出端口
	hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
	//用交换机的MAC地址更新数据包的源MAC地址
	hdr.ethernet.dstAddr = dstAddr;
	//用下一个跃点的地址更新数据包的目的MAC地址
	//egress_spec是standard_metadata_t中的一个字段
	hdr.ipv4.ttl = hdr.ipv4.ttl - 1;//减少ttl字段
}
apply {
	//仅当ipv4报头是有效的,才应用ipv4_lpm
	if (hdr.ipv4.isValid()) {
		ipv4_lpm.apply();
	}
}
  • deparser部分
control MyDeparser(packet_out packet, in headers hdr) {
    apply {
    //使用emit函数重构数据包
        packet.emit(hdr.ethernet);
        packet.emit(hdr.ipv4);
        //顺序不能对调,对调之后无法ping通
        //因为要按照解析的顺序装回去,前面先拆的是ethernet,就先装ethernet
    }
}

step 3:修改basic.p4后
修改代码之后重新make run运行:

posted @ 2022-03-12 21:00  瑞图恩灵  阅读(1062)  评论(0编辑  收藏  举报