P4 hello world学习曲线确实有点陡。。

 因为要想办法看懂一篇SIGCOMM的文章。试水一下P4 hello world,找一下感觉。

摸索了一段时间。。。记录一下。P4作为一个交换机编程语言,主要是为了写交换机的特性而生的(也就是说告诉交换机怎么处理包),理想如上图。 BTW,Nick等人做出了openflow还不过瘾,一定要做到极致。。。做出了barefoot,还把Cisco带上了Cisco S1的路。。。

P4的文章拿了2024 SIGCOMM时间考验奖。

先大概看一下这文章怎么介绍P4的。。。

它说P4可以用来指定包头,包解析器,多个匹配动作表,以及通过这些表的控制流,并且这篇文章引入了编译器来隔离不同的交换机实现,只保留了图2的交换机抽象。

P4相对Click来说,更加针对硬件优化,要使得硬件能够更好的加速,必须告诉硬件控制流中的依赖关系(TDGs, table dependency graphs)。所以P4编译器首先实现将P4程序转换成TDG,然后再转换TDG到相应的交换机实现上。

文章通过mTag的例子介绍了P4的基本组件。但是这个例子对我来说还是略微复杂了。。。语言现在已经进化到P4/16。

所以找感觉的话还是直接选择github的tutorial了,基本上就是follow这个https://github.com/p4lang/tutorials,里面有一站式打包的virtualbox虚拟机,可以在Apple芯片的笔记本上跑。

这个hello world是实现一个p4程序使得上图中各个主机能相互ping通,只设计一个table,对于我这种不熟悉各种协议的小白来说比较友好。

先总结用到的实验环境(代码质量很高,赏心悦目,不像看有些代码,常常想骂人):

Network: Mininet Mininet: An Instant Virtual Network on Your Laptop (or Other PC) - Mininet

http://conferences.sigcomm.org/hotnets/2010/papers/a19-lantz.pdf

P4 Program: basic.py

P4 Architecture model: V1Model

P4 Compiler: P4C is modular; it provides a standard frontend and midend which can be combined with a target-specific backend to create a complete P4 compiler. The goal is to make adding new backends easy. 我们这里用的后端是

Target: P4 simple_switch

几个概念之间的关系可以参考P4 architecture - #2 by ederollora - P4 Programming Language

然后我们看一下我们的hello world程序。这个程序实现IPv4转发,对于每个包,交换机要完成以下步骤1. 更新源和目的MAC地址。2. TTL减1。3. 把包转发到合适的端口。

交换机只有一个表,这个表通过控制平面写好静态的规则。每条规则会把一个IP地址映射到MAC地址,以及下一跳的端口。

整个代码是209行,感觉不是很多。首先是main函数,在整个文件的最底端,大概是总结了pipeline上的各个模块。

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

V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main;

然后看一下MyParser(),这个parser的功能就是从包当中提取ethernet和ipv4头,看上去还是比较直观的。

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;
    }

}

MyIngress():

/*************************************************************************
**************  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();
    }

    apply {
        if (hdr.ipv4.isValid()) {
            ipv4_lpm.apply();
        }
    }
}

Ingress,先定义两个2 actions,一个是drop一个是ipv4 forward。这个ipv4_forward的参数是dstAddr和port,这两个参数是通过结合控制平面设置的表项确定的。这个Ingress就定义了一个ipv4_lpm的表,这个表当包的ipv4头是有效的时候就应用match&action,根据lpm如果ipv4的目的地址匹配,就执行ipv4_forward,如果不匹配就drop。ipv4_forward就完成之前要求的3个步骤1.更新源和目的MAC地址。2. TTL减1。3. 把包转发到合适的端口。

控制平面设置的表项的一个例子如下:

  "table_entries": [
    {
      "table": "MyIngress.ipv4_lpm",
      "default_action": true,
      "action_name": "MyIngress.drop",
      "action_params": { }
    },
    {
      "table": "MyIngress.ipv4_lpm",
      "match": {
        "hdr.ipv4.dstAddr": ["10.0.1.1", 32]
      },
      "action_name": "MyIngress.ipv4_forward",
      "action_params": {
        "dstAddr": "08:00:00:00:01:11",
        "port": 1
      }
    },
    {
      "table": "MyIngress.ipv4_lpm",
      "match": {
        "hdr.ipv4.dstAddr": ["10.0.2.2", 32]
      },
      "action_name": "MyIngress.ipv4_forward",
      "action_params": {
        "dstAddr": "08:00:00:00:02:22",
        "port": 2
      }

MyEgress(),egress比较简单,这个都不需要处理,因为该处理的逻辑已经处理完了。

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

MyComputeChecksum()主要是计算ipv4校验和。


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);
    }
}

MyDeparser()主要把我们经过pipeline的包头重新放到最后的包当中:

control MyDeparser(packet_out packet, in headers hdr) {
    apply {
        packet.emit(hdr.ethernet);
        packet.emit(hdr.ipv4);
    }
}

在修改完这个程序之后,在虚拟机的~/tutorials/exercises/basic目录下执行make run之后,代码就会生成编译生成P4程序。

p4c-bm2-ss --p4v 16 --p4runtime-files build/basic.p4.p4info.txtpb -o build/basic.json basic.p4

然后由mininet根据拓扑信息(pod-topo/topology.json)建立网络拓扑。simple_switch_grpc把P4程序basic.json加载到4个交换机里面。

最后通过P4runtime接口把交换机的表项(pod-topo/sX-runtime.json)加载到各个交换机。

然后实际的效果就是各个主机可以相互ping通。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值