P4,走进网络数据平面可编程

本文介绍了P4编程语言及其在网络设备中的应用,通过一个实例展示了如何使用P4编译器创建P4程序,并在BMV2软件交换机上部署。详细步骤包括P4程序编写、编译、网络拓扑构建以及使用P4Runtime进行路由配置。最终通过Scapy工具测试了三层转发功能,验证了P4程序的正确性。
摘要由CSDN通过智能技术生成

P4 概述

Programming Protocol-independent Packet Processors (P4) 是网络设备的特定领域语言,指定数据平面设备(交换机、网卡、路由器、过滤器等)如何处理数据包。

P4 工作流程

  1. P4程序(prog.p4)根据报文头和对传入报文采取的动作(例如,转发、丢弃)对报文进行分类。
  2. P4编译器生成运行时映射元数据,以允许控制平面和数据平面使用P4Runtime (prog.p4info)进行通信。
  3. P4编译器还为目标数据平面生成一个可执行文件(target_prog.bin),指定目标设备的头文件格式和相应的操作。
    在这里插入图片描述

P4 项目组件

BMV2

bmv2(Behavior Model Version 2)是 P4 项目实现的一个 P4 可编程软件交换机。bmv2 并不是一个产品质量级交换机,它只是用于开发人员开发、测试、调试 P4 程序。

P4Runtime

P4 是用于对数据平面进行编程的语言,它定义了数据平面所支持的功能。但是数据平面仍然需要在运行时接收控制平面下发的控制信息,以指导数据平面对现网实现正确的转发行为。而 P4Runtime 就是一套控制平面规范,用于控制网络设备的转发平面。

P4C

p4c 是 P4 编程语言的参考编译器。支持 P4-14 和 P4-16。

P4 实践

开发环境搭建

参考: https://blog.csdn.net/father_is_/article/details/108225712

编写 P4 程序
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>

const bit<16> TYPE_IPV4 = 0x800;

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

parser ParserImpl(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;
    }

}

control VerifyChecksumImpl(inout headers hdr, inout metadata meta) {   
    apply {  }
}

control IngressImpl(inout headers hdr,
                  inout metadata meta,
                  inout standard_metadata_t standard_metadata) {
    action drop() {
        mark_to_drop(standard_metadata);
    }
    
    action ipv4_forward(egressSpec_t port) {
        standard_metadata.egress_spec = port;
        hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
    }
    
    table ipv4_lpm {
        key = {
            hdr.ipv4.dstAddr: lpm;
        }
        actions = {
            ipv4_forward;
            drop;
            NoAction;
        }
        size = 512;
        default_action = NoAction();
    }
    
    apply {
        if (hdr.ipv4.isValid()) {
            ipv4_lpm.apply();
        }
    }
}

control EgressImpl(inout headers hdr,
                 inout metadata meta,
                 inout standard_metadata_t standard_metadata) {
    apply {  }
}

control ComputeChecksumImpl(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);
    }
}

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

V1Switch(
ParserImpl(),
VerifyChecksumImpl(),
IngressImpl(),
EgressImpl(),
ComputeChecksumImpl(),
DeparserImpl()
) main;

将文件命名为 demo.p4

执行编译
p4c -b bmv2 -o build demo.p4

-b:指定 target
-o:指定输出路径
编译成功后会在 build 文件夹下看到 demo.json 和 demo.p4i 这两个文件
在这里插入图片描述

构建网络拓扑

在这里插入图片描述

  1. 创建虚拟 veth pair 接口,同时禁用该接口上的 IPv6,防止对后面测试产生干扰

    sudo ip link add name veth0 type veth peer name veth1
    sudo ip link set dev veth0 up
    sudo ip link set dev veth1 up
    sudo sysctl net.ipv6.conf.veth0.disable_ipv6=1
    sudo sysctl net.ipv6.conf.veth1.disable_ipv6=1
    
    sudo ip link add name veth2 type veth peer name veth3
    sudo ip link set dev veth2 up
    sudo ip link set dev veth3 up
    sudo sysctl net.ipv6.conf.veth2.disable_ipv6=1
    sudo sysctl net.ipv6.conf.veth3.disable_ipv6=1
    
    sudo ip link add name veth4 type veth peer name veth5
    sudo ip link set dev veth4 up
    sudo ip link set dev veth5 up
    sudo sysctl net.ipv6.conf.veth4.disable_ipv6=1
    sudo sysctl net.ipv6.conf.veth5.disable_ipv6=1
    
  2. 启动 simple_switch 交换机

    cyquen@cyquen-virtual-machine:~/P4/demo$ sudo simple_switch --interface 0@veth0 --interface 1@veth2 --interface 2@veth4 build/demo.json &
    [1] 2089
    cyquen@cyquen-virtual-machine:~/P4/demo$ Calling target program-options parser
    Adding interface veth0 as port 0
    Adding interface veth2 as port 1
    Adding interface veth4 as port 2
    
向交换机的路由表中下发路由

接下来将通过 simple_switch_CLI命令来控制该 P4 软件交换机

cyquen@cyquen-virtual-machine:~/P4/demo$ simple_switch_CLI 
Obtaining JSON from switch...
Done
Control utility for runtime P4 table manipulation
RuntimeCmd: 

使用 show tables命令查看当前所有表,使用 table_info命令查看指定表的具体信息:

RuntimeCmd: show_tables
IngressImpl.ipv4_lpm           [implementation=None, mk=ipv4.dstAddr(lpm, 32)]
RuntimeCmd: table_info ipv4_lpm
IngressImpl.ipv4_lpm           [implementation=None, mk=ipv4.dstAddr(lpm, 32)]
********************************************************************************
IngressImpl.drop               []
IngressImpl.ipv4_forward       [port(9)]
NoAction                       []
RuntimeCmd: 

使用 table_add命令向交换机添加路由,这里假设:

  • port 0(veth 0)连接 10.0.0.0/8 网段
  • port 1(veth 2)连接 20.0.0.0/8 网段
  • port 2(veth 4)连接 30.0.0.0/8 网段
RuntimeCmd: table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 0
Adding entry to lpm match table ipv4_lpm
match key:           LPM-0a:00:00:00/8
action:              ipv4_forward
runtime data:        00:00
Entry has been added with handle 0
RuntimeCmd: table_add ipv4_lpm ipv4_forward 20.0.0.0/8 => 1
Adding entry to lpm match table ipv4_lpm
match key:           LPM-14:00:00:00/8
action:              ipv4_forward
runtime data:        00:01
Entry has been added with handle 1
RuntimeCmd: table_add ipv4_lpm ipv4_forward 30.0.0.0/8 => 2
Adding entry to lpm match table ipv4_lpm
match key:           LPM-1e:00:00:00/8
action:              ipv4_forward
runtime data:        00:02
Entry has been added with handle 2

使用 table_dump查看添加的表项:

RuntimeCmd: table_dump ipv4_lpm
==========
TABLE ENTRIES
**********
Dumping entry 0x0
Match key:
* ipv4.dstAddr        : LPM       0a000000/8
Action entry: IngressImpl.ipv4_forward - 00
**********
Dumping entry 0x1
Match key:
* ipv4.dstAddr        : LPM       14000000/8
Action entry: IngressImpl.ipv4_forward - 01
**********
Dumping entry 0x2
Match key:
* ipv4.dstAddr        : LPM       1e000000/8
Action entry: IngressImpl.ipv4_forward - 02
==========
Dumping default entry
Action entry: NoAction - 
==========
测试交换机的三层转发

使用 scapy 工具从 veth1 注入报文,然后分别在 veth3 和 veth 5 上使用 tcpdump 抓包:

cyquen@cyquen-virtual-machine:~$ sudo scapy
[sudo] password for cyquen: 
INFO: Can't import matplotlib. Won't be able to plot.
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
WARNING: No route found for IPv6 destination :: (no default route?)
                                      
                     aSPY//YASa       
             apyyyyCY//YCa       |
            sY//YSpcs  scpCY//Pp     | Welcome to Scapy
 ayp ayyyyyyySCP//Pp           syY//C    | Version 2.4.3
 AYAsAYYYYYYYY///Ps              cY//S   |
         pCCCCY//p          cSSps y//Y   | https://github.com/secdev/scapy
         SPPPP///a          pP///AC//Y   |
              A//A            cyPC   | Have fun!
              p///Ac            sC///a   |
              PYCpc           A//A   | Wanna support scapy? Rate it on
       scccccp///pSP///p          p//Y   | sectools!
      sY/y  caa           S//P   | http://sectools.org/tool/scapy/
       cayCyayP//Ya              pY/Ya   |             -- Satoshi Nakamoto
        sY/PsYYCc          aC//Yp    |
         sc  sccaCY//PCypaapyCP//YSs  
                  spCPY//YPSps    
                       ccaacs         
                                       using IPython 7.13.0
>>>  
cyquen@cyquen-virtual-machine:~$ sudo tcpdump -n -i veth3
[sudo] password for cyquen: 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth3, link-type EN10MB (Ethernet), capture size 262144 bytes
cyquen@cyquen-virtual-machine:~$ sudo tcpdump -n -i veth5
[sudo] password for cyquen: 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth5, link-type EN10MB (Ethernet), capture size 262144 bytes
  • 从 veth1 注入目的地为 20.0.0.1 的报文,veth 3 收到报文,而 veth 5 没有收到任何报文

    >>> p = Ether()/IP(dst="20.0.0.1")/UDP()
    >>> sendp(p, iface="veth1")
    .
    Sent 1 packets.
    
    cyquen@cyquen-virtual-machine:~$ sudo tcpdump -n -i veth3
    [sudo] password for cyquen: 
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on veth3, link-type EN10MB (Ethernet), capture size 262144 bytes
    16:38:40.238448 IP 192.168.99.132.53 > 20.0.0.1.53: domain [length 0 < 12] (invalid)
    
  • 从 veth1 注入目的地为 30.0.0.1 的报文,veth 5 收到报文,而 veth 3 没有收到任何报文

    >>> p = Ether()/IP(dst="30.0.0.1")/UDP()
    >>> sendp(p, iface="veth1")
    .
    Sent 1 packets.
    
    cyquen@cyquen-virtual-machine:~$ sudo tcpdump -n -i veth5
    [sudo] password for cyquen: 
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on veth5, link-type EN10MB (Ethernet), capture size 262144 bytes
    16:42:11.133833 IP 192.168.99.132.53 > 30.0.0.1.53: domain [length 0 < 12] (invalid)
    

可以看到,自己编写的 P4 程序的 simple_switch 按照预期执行了 LPM 转发。
结束!

参考

[1] https://p4.org/
[2] https://www.sdnlab.com/24136.html

  • 4
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
1. 简介 随着AI技术的不断发展,越来越多的计算任务需要在数据中心中完成。然而,传统的数据中心网络架构很难满足AI计算任务的需求,因为这些任务通常需要大量的计算资源和高带宽的网络连接。为了解决这个问题,我们提出了一种基于可编程交换机P4数据面编程的AI计算卸载架构设计。该架构可以将AI计算任务从服务器卸载到网络中,在网络中完成计算任务,从而降低服务器负载,提高网络带宽利用率。 2. 架构设计 该架构由三个主要组件组成:可编程交换机P4数据面编程实现、AI计算卸载模块和AI计算任务调度器。其中,可编程交换机P4数据面编程实现负责在网络中实现AI计算任务的计算,AI计算卸载模块负责将计算任务卸载到网络中,并将计算结果返回给服务器,AI计算任务调度器负责管理计算任务的调度和分配。 2.1 可编程交换机P4数据面编程实现 可编程交换机P4数据面编程实现是实现AI计算任务的关键组件。它可以根据AI计算任务的需求,动态地调整网络中的数据流,以实现计算任务。具体来说,它可以对网络中的数据包进行分类、过滤、分组和聚合等操作,以实现AI计算任务。为了实现这些操作,我们使用了P4语言进行编程,通过P4程序来控制数据面的行为。 2.2 AI计算卸载模块 AI计算卸载模块负责将计算任务从服务器卸载到网络中。它可以将计算任务分成多个子任务,并将这些子任务分配到不同的可编程交换机中进行计算。为了实现这个功能,我们需要在数据包中加入一些特殊的标识,以便于可编程交换机进行计算。同时,我们还需要设计一些算法来决定如何将计算任务分配到不同的可编程交换机中,以达到最优的性能和负载平衡。 2.3 AI计算任务调度器 AI计算任务调度器负责管理计算任务的调度和分配。它可以根据不同的任务需求,将计算任务分配到不同的可编程交换机中进行计算。同时,它还可以监控计算任务的状态,并在需要时进行重新分配或重新调度,以确保任务的顺利完成。 3. 总结 本文提出了一种基于可编程交换机P4数据面编程的AI计算卸载架构设计,可以将AI计算任务从服务器卸载到网络中,在网络中完成计算任务,从而降低服务器负载,提高网络带宽利用率。该架构可以为数据中心中的AI计算任务提供高效、可靠的计算环境,为AI技术的发展提供支持。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值