P4开源Tutorials教程样例实战及对P4v1.1规范的初分析
Github链接:Github-P4Lang-Tutorials-p4v1.1
前言
本文主要对Barefoot开源教程中的p4v1.1实例simple_router的实战步骤进行记录与阐述,希望能帮助大家进一步对P4v1.1有所认识与了解。
实验环境
1.OS:Ubuntu 14.04,64bit。
2.bmv2,即behavioral-model
3.p4c-bm
4.tutorials
Hint:bmv2、p4c-bm、tutorials均在Github中开源,可以从P4Lang中git clone下来。
实验准备
1.首先修改env.sh中的脚本信息,env.sh脚本路径:tutorials/p4v1_1。
我的env.sh脚本如下:
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
# ---------------- EDIT THIS ------------------
BMV2_PATH=/home/wasdns/bmv2
# e.g. BMV2_PATH=$THIS_DIR/../bmv2
P4C_BM_PATH=/home/wasdns/p4c-bm
# e.g P4C_BM_PATH=$THIS_DIR/../p4c-bm
# ---------------- END ------------------
请根据实际情况修改bmv2和p4c-bm的路径。
2.修改脚本中的env.sh路径信息。
修改脚本中的env.sh路径信息:
source $THIS_DIR/../env.sh
我为了方便起见,将env.sh脚本拷贝至simple_router目录下,因此我的路径信息为:
source $THIS_DIR/env.sh
所有在simple_router目录下的脚本都需要修改。
实验原理
在执行目录simple_router下有如下文件:
add_entries.sh* README.md register_on_off.sh*
commands.txt p4src/ read_register.sh* run_demo.sh*
运行run_demo.sh脚本,先将p4src中的P4程序通过前端编译器p4c-bm转换为.json文件,启动behavioral-model中mininet目录下的1sw_demo.py脚本,建立由一个P4交换机和两个host组成的虚拟网络拓扑,并将上述生成的.json文件作为输入“配置”到P4交换机中。
此时,可以借助bmv2/tools目录下的runtime_CLI.py脚本来控制数据平面,启动该脚本时需要指定thrift服务端口(默认为9090)来对P4交换机进行配置,具体命令如下:
./runtime_CLI.py --thrift-port [thrift服务端口]
本实验中用于控制的脚本,如register_on_off.sh,均是借助CLI来对交换机进行实时控制的,读者可以直接执行可执行脚本文件来对运行中的P4交换机进行控制。
commands.txt内容如下:
table_set_default drop_expired do_drop_expired
table_set_default send_frame _drop
table_set_default forward _drop
table_set_default ipv4_lpm _drop
table_add send_frame rewrite_mac 1 => 00:aa:bb:00:00:00
table_add send_frame rewrite_mac 2 => 00:aa:bb:00:00:01
table_add forward set_dmac 10.0.0.10 => 00:04:00:00:00:00
table_add forward set_dmac 10.0.1.10 => 00:04:00:00:00:01
table_add ipv4_lpm set_nhop 10.0.0.10/32 => 10.0.0.10 1
table_add ipv4_lpm set_nhop 10.0.1.10/32 => 10.0.1.10 2
这里读者需要了解CLI的两种命令格式:
table_set_default <table name> <action name> <action parameters>
table_add <table name> <action name> <match fields> => <action parameters> [priority]
table_set_default
命令用于设置流表的默认动作,需要指定流表名称、默认动作名称以及需要给默认动作传递的执行参数。
table_add
命令用于为流表添加一条表项,需要指定流表名称、表项执行动作的名称、匹配的字段以及需要给动作传递的执行参数,可以指定该表项的优先级。
在没有给交换机添加表项之前,两个主机h1和h2之间是不能正常通信的;运行add_entries.py
脚本,将上文中command.txt
文件中的命令通过CLI配置到运行时的交换机中,使h1和h2能够互相ping通。
在使用mininet启动虚拟拓扑并借助CLI下发命令使拓扑中的两台主机能够正常通信之后,我们能够发送TTL字段值为1的包,这些包在经过P4交换机的时候会被交换机丢弃,可以借助提供的脚本查看丢弃数据报的总量。
提供的脚本有两个:1.register_on_off.sh 2.read_register.sh
其中 register_on_off.sh 脚本用来启动和停止对丢弃数据报数量的计数,而 read_register.sh 脚本用于查看丢弃的数据报总数。
P4语言的C-like化
p4src目录下的P4程序:
simple_router.p4
/* Copyright 2013-present Barefoot Networks, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
header_type ethernet_t {
fields {
bit<48> dstAddr;
bit<48> srcAddr;
bit<16> etherType;
}
}
header_type ipv4_t {
fields {
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;
bit<32> srcAddr;
bit<32> dstAddr;
}
}
parser start {
return parse_ethernet;
}
#define ETHERTYPE_IPV4 0x0800
header ethernet_t ethernet;
parser parse_ethernet {
extract(ethernet);
return select(latest.etherType) {
ETHERTYPE_IPV4 : parse_ipv4;
default: ingress;
}
}
header ipv4_t ipv4;
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;
}
parser parse_ipv4 {
extract(ipv4);
return ingress;
}
action _drop() {
drop();
}
header_type routing_metadata_t {
fields {
bit<32> nhop_ipv4;
}
}
metadata routing_metadata_t routing_metadata;
register drops_register {
width: 32;
static: drop_expired;
instance_count: 16;
}
register drops_register_enabled {
width: 1;
static: drop_expired;
instance_count: 16;
}
action do_drop_expired() {
drops_register[0] = drops_register[0] + ((drops_register_enabled[0] == 1) ? (bit<32>)1 : 0);
drop();
}
table drop_expired {
actions { do_drop_expired; }
size: 0;
}
action set_nhop(in bit<32> nhop_ipv4, in bit<9> port) {
routing_metadata.nhop_ipv4 = nhop_ipv4;
standard_metadata.egress_spec = port;
ipv4.ttl = ipv4.ttl - 1;
}
table ipv4_lpm {
reads {
ipv4.dstAddr : lpm;
}
actions {
set_nhop;
_drop;
}
size: 1024;
}
action set_dmac(in bit<48> dmac) {
ethernet.dstAddr = dmac;
// modify_field still valid
// modify_field(ethernet.dstAddr, dmac);
}
table forward {
reads {
routing_metadata.nhop_ipv4 : exact;
}
actions {
set_dmac;
_drop;
}
size: 512;
}
action rewrite_mac(in bit<48> smac) {
ethernet.srcAddr = smac;
}
table send_frame {
reads {
standard_metadata.egress_port: exact;
}
actions {
rewrite_mac;
_drop;
}
size: 256;
}
control ingress {
if(valid(ipv4)) {
if(ipv4.ttl > 1) {
apply(ipv4_lpm);
apply(forward);
} else {
apply(drop_expired);
}
}
}
control egress {
apply(send_frame);
}
可以看到该程序中与P4v1.0不一样的地方:
一、header_type中的字段长度。
p4v1.1:
header_type ipv4_t {
fields {
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;
bit<32> srcAddr;
bit<32> dstAddr;
}
}
p4v1.0:
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;
}
}
可以看到,p4v1.1规范中对字段长度的定义更接近C语言中的抽象数据类型。
二、更贴近C语言的语法。
我们可以在动作do_drop_expired中
action do_drop_expired() {
drops_register[0] = drops_register[0] + ((drops_register_enabled[0] == 1) ? (bit<32>)1 : 0);
drop();
}
看见如下表达式:
(drops_register_enabled[0] == 1) ? (bit<32>)1 : 0
该表达式采用了C语言中的条件运算符:?
,在C语言中,由条件运算符组成的条件语句一般形式如下:
表达式1 ? 表达式 2 : 表达式 3。
这条P4语句首先对寄存器实例drops_register_enabled[0]
进行判断,如果该寄存器值为1,则这个表达式的值为1;否则为0。
三、使用=
取代原有元动作modify_field
simple_router.p4程序中的动作rewrite_mac是用于修改数据报中的源mac地址的。其在P4v1.0的表现形式如下:
action set_dmac(dmac) {
modify_field(ethernet.dstAddr, dmac);
}
使用元动作modify_field
,将首部实例ethernet中的字段dstAddr值修改为传入的dmac参数。
而在p4v1.1中则可以直接使用=
符号进行赋值运算:
action rewrite_mac(in bit<48> smac) {
ethernet.srcAddr = smac;
}
P4v1.1语言规范中还有其他的细节差别,感兴趣的读者可以访问P4的官方网站P4.org下载P4v1.1的语言规范。
实验步骤
1.启动mininet虚拟网络拓扑:
./run_demo.sh
启动效果如下:
root@ubuntu:/home/wasdns/tutorials/p4v1_1/simple_router# ./run_demo.sh
WARNING: Token 'PPHASH' defined, but not used
WARNING: There is 1 unused token
Generating LALR tables
WARNING: 2 shift/reduce conflicts
parsing successful
semantic checking successful
Header type standard_metadata_t not byte-aligned, adding padding
WARNING:gen_json:The P4 program defines a checksum verification on field 'ipv4.hdrChecksum'; as of now bmv2 ignores all checksum verifications; checksum updates are processed correctly.
Generating json output to /home/wasdns/tutorials/p4v1_1/simple_router/simple_router.json
*** Creating network
*** Adding hosts:
h1 h2
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1)
*** Configuring hosts
h1 h2
*** Starting controller
*** Starting 1 switches
s1 Starting P4 switch s1
/home/wasdns/bmv2/targets/simple_switch/simple_switch -i 1@s1-eth1 -i 2@s1-eth2 --thrift-port 9090 --nanolog ipc:///tmp/bm-0-log.ipc --device-id 0 simple_router.json
switch has been started
**********
h1
default interface: eth0 10.0.0.10 00:04:00:00:00:00
**********
**********
h2
default interface: eth0 10.0.1.10 00:04:00:00:00:01
**********
Ready !
*** Starting CLI:
mininet>
此时交换机中没有任何表项,执行pingall显示主机h1和h2无法正常通信:
mininet> pingall
*** Ping: testing ping reachability
h1 -> X
h2 -> X
*** Results: 100% dropped (0/2 received)
2.添加表项,使主机h1和h2能够正常通信。
打开一个新的终端,运行脚本为交换机添加表项:
./add_entries.sh
添加表项效果如下:
root@ubuntu:/home/wasdns/tutorials/p4v1_1/simple_router# ./add_entries.sh
Using JSON input simple_router.json
No Thrift port specified, using CLI default
Control utility for runtime P4 table manipulation
RuntimeCmd: Setting default action of drop_expired
action: do_drop_expired
runtime data:
RuntimeCmd: Setting default action of send_frame
action: _drop
runtime data:
RuntimeCmd: Setting default action of forward
action: _drop
runtime data:
RuntimeCmd: Setting default action of ipv4_lpm
action: _drop
runtime data:
RuntimeCmd: Adding entry to exact match table send_frame
match key: EXACT-00:01
action: rewrite_mac
runtime data: 00:aa:bb:00:00:00
Entry has been added with handle 0
RuntimeCmd: Adding entry to exact match table send_frame
match key: EXACT-00:02
action: rewrite_mac
runtime data: 00:aa:bb:00:00:01
Entry has been added with handle 1
RuntimeCmd: Adding entry to exact match table forward
match key: EXACT-0a:00:00:0a
action: set_dmac
runtime data: 00:04:00:00:00:00
Entry has been added with handle 0
RuntimeCmd: Adding entry to exact match table forward
match key: EXACT-0a:00:01:0a
action: set_dmac
runtime data: 00:04:00:00:00:01
Entry has been added with handle 1
RuntimeCmd: Adding entry to lpm match table ipv4_lpm
match key: LPM-0a:00:00:0a/32
action: set_nhop
runtime data: 0a:00:00:0a 00:01
Entry has been added with handle 0
RuntimeCmd: Adding entry to lpm match table ipv4_lpm
match key: LPM-0a:00:01:0a/32
action: set_nhop
runtime data: 0a:00:01:0a 00:02
Entry has been added with handle 1
RuntimeCmd:
在mininet中验证h1和h2是否能够正常通信:
mininet> pingall
*** Ping: testing ping reachability
h1 -> h2
h2 -> h1
*** Results: 0% dropped (2/2 received)
3.通过脚本启动计数,开始记录交换机丢弃的数据报数量。
./register_on_off.sh on
root@ubuntu:/home/wasdns/tutorials/p4v1_1/simple_router# ./register_on_off.sh onEnabling packet drop count
Using JSON input simple_router.json
No Thrift port specified, using CLI default
Control utility for runtime P4 table manipulation
RuntimeCmd: RuntimeCmd:
Checking value...
Using JSON input simple_router.json
No Thrift port specified, using CLI default
Control utility for runtime P4 table manipulation
RuntimeCmd: drops_register_enabled[0]= 1
RuntimeCmd:
4.在mininet中,让h1向h2发送TTL字段值为1的数据报。
mininet> h1 ping h2 -t 1
数据报在通过交换机时被丢弃,我们不会观察到ping的回复。
5.在另一个终端中运行脚本 read_register.sh 查看交换机丢弃的数据报信息。
./read_register.sh
参考
1.P4.org
2.Github/P4Lang/Tutorials https://github.com/p4lang/tutorials/tree/master/p4v1_1/simple_router
2017/1/20
P4开源Tutorials教程样例实战及对P4v1.1规范的初分析的更多相关文章
- webgl opengl教程样例
webgl2样例: http://webglsamples.org opengl教程: https://learnopengl.com/ http://www.opengl-tutorial.org/ ...
- 最全SpringMVC具体演示样例实战教程
一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先.导入SpringMVC须要的jar包. 2.加入Web.xml配置文件里关于SpringMVC的配置 <!--conf ...
- Jackson 教程演示样例
查看原文教程:http://www.ibloger.net/article/275.html Json经常使用的类库例如以下 Jackson:http://jackson.codehaus.org/ ...
- zookeeper实战:SingleWorker代码样例
我们需要一个“单点worker”系统,此系统来确保系统中定时任务在分布式环境中,任意时刻只有一个实例处于活跃:比如,生产环境中,有6台机器支撑一个应用,但是一个应用中有30个定时任务,这些任务有些必须 ...
- C#开发Unity游戏教程循环遍历做出推断及Unity游戏演示样例
C#开发Unity游戏教程循环遍历做出推断及Unity游戏演示样例 Unity中循环遍历每一个数据,并做出推断 非常多时候.游戏在玩家做出推断以后.游戏程序会遍历玩家身上大量的所需数据,然后做出推断. ...
- 2单表CRUD综合样例开发教程
东软集团股份有限公司 基础软件事业部 单表CRUD综合样例开发教程 东软机密 tui 更改履历 版本号 更改时间 更改的 图表和章节号 状态 更改简要描述 更改申 请编号 更改人 批准人 V1.0 2 ...
- WebGL自学教程——WebGL演示样例:開始
最终開始WebGL的演示样例了,...... 開始 使用WebGL的步骤,非常easy: 1. 获得WebGL的渲染环境(也叫渲染上下文). 2. 发挥你的想象力,利用<WebGL參考手冊> ...
- 【spring教程之中的一个】创建一个最简单的spring样例
1.首先spring的主要思想,就是依赖注入.简单来说.就是不须要手动new对象,而这些对象由spring容器统一进行管理. 2.样例结构 如上图所看到的,採用的是mavenproject. 2.po ...
- 3 TFRecord样例程序实战
将图片数据写入Record文件 # 定义函数转化变量类型. def _int64_feature(value): return tf.train.Feature(int64_list=tf.train ...
随机推荐
- 20.Bulk Write Operations-官方文档摘录
1.有序操作列表将会串行执行,但如果在一个写操作过程出现异常错误,则不会处理剩余的任何写操作 2.无序操作列表将会并发执行,如果在一个写操作过程出现异常错误,则不影响,继续执行(并发无序) 3.对比无 ...
- KVm中EPT逆向映射机制分析
2017-05-30 前几天简要分析了linux remap机制,虽然还有些许瑕疵,但总算大致分析的比较清楚.今天分析下EPT下的逆向映射机制.EPT具体的工作流程可参考前面博文,本文对于EPT以及其 ...
- DRF频率、分页、解析器、渲染器
DRF的频率 频率限制是做什么的 开放平台的API接口调用需要限制其频率,以节约服务器资源和避免恶意的频繁调用. 频率组件原理 DRF中的频率控制基本原理是基于访问次数和时间的,当然我们可以通过自己定 ...
- Linux Anaconda安装步骤
首选下载wget https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.sh 可以去官网查看适合自己的文件https://www ...
- Linux more命令
more命令类似与cat命令,却比cat命令强大,它以全屏幕的方式按页显示文本文件的内容,支持vi中的关键字定位操作. 1.快捷键 space, z 向下翻页b,ctrl+b 向上翻页 E ...
- lock,Monitor,Mutex的区别
lock和Monitor的区别 一.lock的底层本身是Monitor来实现的,所以Monitor可以实现lock的所有功能. 二.Monitor有TryEnter的功能,可以防止出现死锁的问题,lo ...
- DIV+CSS如何让文字垂直居中?
在说到这个问题的时候,也许有人会问CSS中不是有vertical-align属性来设置垂直居中的吗?即使是某些浏览器不支持我只需做少许的CSS Hack技术就可以啊!所以在这里我还要啰嗦两句,CSS中 ...
- ambari关于ranger的一个大坑----端口永远是3306,需要手动修改
ambari关于ranger的一个大坑----端口永远是3306 这个坑是我在搭建ambari环境的时候发现的,我并没有找到原因,求助同事,然后一步步循着蛛丝马迹和试探,终于解决了,然而也揭露了amb ...
- keeplived + mysql双主复制部署 --原创
环境: master 1: 192.168.100.10 oracle linux 7.4 mysql 5.7.1 master 2: 192.168.100.11 oracle linux ...
- python爬虫中文乱码解决方法
python爬虫中文乱码 前几天用python来爬取全国行政区划编码的时候,遇到了中文乱码的问题,折腾了一会儿,才解决.现特记录一下,方便以后查看. 我是用python的requests和bs4库来实 ...