p4runtime——experiment
experiment explanation
step1
本练习中,使用P4Runtime将流条目发送到交换机,而不是使用交换机的CLI
topology.json

将会使用mycontrller.py 已经一些在p4runtime_lib中的libraries来创建主机1和主机2的隧道所必要的表条目
该实验在basic_tunnel的基础上新增了两个计数器(ingressTunnelCounter,egressTunnelCounter)和两个新动作(myTunnel_ingress, myTunnel_egress)
(1)在终端执行make将

·编译advanced_tunnel.p4程序
·形成拓扑结构

·为主机1、主机2、主机3分配IP地址
因为我们还没有为交换机制定规则,所以不会受到任何的回复

打开另外一个终端运行controller.py文件

这将在交换机上安装程序,并推送隧道ingress的规则
这个程序每两秒打印隧道ingress和egress计数器的值
我们可以看到s1交换机的ingress tunnel计数器呈增长状态
s1 ingressTunnelCounter 100: 2 packets
but 为啥我为啥还是0packer?????damn!
每一个交换机都根据目标地址IP地址将流量映射到tunnel中,我们的任务是根据tunnel ID编写交换机之间的流量
潜在问题:
如果在运行时看到以下错误消息,则grpc服务器未在一个或多个交换机上运行controller.py
p4@p4:~/tutorials/exercises/p4runtime$ ./mycontroller.py
...
grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with (StatusCode.UNAVAILABLE, Connect Failed)>
可以通过运行以下命令来检查哪些gRPC端口证字啊侦听计算机上
sudo netstat -lpnt
something about the control plane
P4程序定义数据包处理管道,但每个表中的规则由控制平面插入,在本例中我们将配置control plane,而不是像之前的用静态表条目 (可以看看之前的mycontroller.py,做个comparation)
tips
P4程序还定义了交换机流水线和控制平面的接口,此接口在一个文件中定义。
我们根据表的keys、actions的名字使用P4Info helper将这些名字转移成P4rt所需要的IDs
add or rename tables,keys or actions need to be reflected in the table entries
advanced_tunnel.p4info mycontroller.py
step2
mycontroller相当于控制平面,对交换机进行配置,其主要功能为:
1.为P4Runtime服务建立到交换机的gRPC连接
2.将P4程序推到每个交换机
3.为h1和h2之间的两个隧道编写隧道入口和隧道出口规则
4.每两秒读取隧道入口和出口计数器
我们的任务是编写transit rule来匹配tunnel ID 并转发packets到下一跳
writeTunnelRules
p4runtime_lib
在这个实验过程中,可能用到一些dictionary中的类和方法
helper.py
包含了一些用来解析P4InfoHelperp4info文件的类
提供从实体名转换成IDnumber的方法
构建程序无关的一些P4Runtime 表条目
switch.py
包含一些获取gRPC客户端的存根,并建立一些和交换机的连接SwitchConnection
提供构造 P4Runtime protocol buffer messages并进行 P4Runtime gRPC 服务调用方法。
bmv2.py
包含扩展并提供特定于 BMv2 的设备有效负载以加载 P4 程序Bmv2SwitchConnection SwitchConnections
convret.py
为protocol buffer messages需要的strings和numbers
提供编码和解码方法
step3
编写完controller.py后
运行
./my_controller.py
应该开始在 Mininet 提示符中看到 ICMP 回复,并且应该开始看到所有计数器的值开始递增。
process
basic_tunnel的

首先看看拓扑结构:

在这个拓扑结构中
h1与s1交换机的1号端口相连,h1主机的dst_id=1
h2与s2交换机的1号端口相连,h2主机的dst_id=2
h3与s3交换机的1号端口相连,h3主机的dst_id=3
advance_tunnel.p4
主要是ingress部分的作用
1)引入了两个计数器,分别是入口隧道的计数器和出口隧道的计数器

2)一个drop action和正常的转发ipv4 action

3)接着是这次实验的重要部分
隧道入口action

注意:
ingressTunnelCounter.count((bit<32>) hdr.myTunnel.dst_id);
隧道转发action

隧道出口action

转发表

在myTunnel表中可以看到
我们对myTunnel.dst_id进行匹配
并执行my_tunnel_forward、my_tunnel_egress、drop操作
apply

接下来就是编写控制平面controller.py
逐步理解一下controller.py到底在干什么
引入一些必要的...

从在上级工具目录中引入一些P4Runtime所需要的工具类如bmv2、helper....

SWITCH_TO_HOST_PORT = 1
SWITCH_TO_SWITCH_PORT = 2
writeTunnelRules
def writeTunnelRules(p4info_helper, ingress_sw, egress_sw, tunnel_id,
dst_eth_addr, dst_ip_addr):
一些参数

dst_ip_addr:目的地的以太网地址,用于egress rule
dst_eth_addr:目的IP地址用于在ingress rule中进行匹配
我们加入三条规则
1.在ingress switch 上的 tunnel ingress rule 用于
ipv4_lpm table,将流量封装到指定 ID 的隧道中

table_name="MyIngress.ipv4_lpm"
根据hdr.ipv4.dstAddr进行匹配
ingress_sw.WriteTableEntry(table_entry) 在ingress交换机中写入条目
2.在ingress switch的传输规则,用来根据特定的ID进行转发
Tunnel transition Rule

这个规则将被添加到myTunnel_exact 表中,并和tunnel ID(hdr.myTunnel.dst_id)进行匹配,流量需要使用端口连接的下一个交换机的myTunnel_forward action转发
对于我们这个简单的拓扑结构,交换机1和交换机2使用port2进行连接,我们在前面定义了 SWITCH_TO_SWITCH_PORT,可以在这个action中使用这个输出端口
我们在入口交换机中只需要一个转发规则因为我们用的是一个简单的拓扑结构,但对于大多数情况,我们需要对每个交换机(除了最后一个交换机(有着自己的egress rule))指定转发规则,且我么需要根据我们指定的拓扑结构动态的对每个交换机选择端口
TODO:指定交换规则
TODO: 在ingress 交换机中安装这个交换规则

match_fields={
"hdr.myTunnel.dst_id": tunnel_id
}
hdr.myTunnel.dst_id这个在p4程序中出现
tunnel_id在控制平面出现
这一part感觉还要理解下.....
SWITCH_TO_SWITCH_PORT=2
3.在egress switch上的tunnel egress rule 用于根据特定的ID对流量进行解封装,同时发送至主机
对于我们这个简易的拓扑结构,主机总是被连载在交换机的一号端口上
但是,在平常情况,我们需要跟踪主机连接的端口

SWITCH_TO_HOST_PORT=1
readTableRules

这一块用来读取交换机上的所有表条目
sw为交换机的connection

for循环第一层:对于每个交换机的表条目集合
for循环第二层:对于每个表条目集合中的实体
TODO:用p4info_helper来将entry中的id转化成name
ps:name ? entry?二者什么差别...remain to be solved
table_name = p4info_helper.get_tables_name(entry.table_id)
根据table_id获得table_name
for循环第三层:对于每个条目中的每个match项
print(p4info_helper.get_match_field_name(table_name, m.field_id), end=' ')
我们根据上一步获得的表的name,在p4info_helper中获取对应表中,某个field_id 对应的field_name
再看看图吧...

print('%r' % (p4info_helper.get_match_field_value(m),), end=' ')
输出所匹配的field对于的value
ps:为什么是acton.action?
答:我自己觉得是rt helper把action的参数、action集合成了一大个action,action.action是取其中的action
然后我们通过action的id获得action的name
然后输出action所提供的参数...
printCounter
def printCounter(p4info_helper, sw, counter_name, index):
"""
我们通过交换机的specific index(在我们程序中是tunnel ID)来读取特定的counter值,如果index是0,将会return计数器的所有values


index就是tunnelID(在这个实验中)
对于每一个实体
我们输出交换机的名字,计数器的名字,tunnelID,计数器记录的packet数,以及数据量(以字节为单位)
printGrpcError
def printGrpcError(e):

main
实例化helper


为交换机s1和s2创建一个连接,这由P4RT gRPC链接支持
并转储所有P4Runtime messages以特定的的 txt 文件给交换机
发送主仲裁更新消息以将此控制器建立为主控制器(P4Runtime 要求这个步骤要在执行任何其他写入操作之前)

将P4程序安装在交换机上

输出h1到h2的隧道流量

读取s1和s2交换机的条目


if shutdown or error


解析器...
增加P4info的描述
增加BMv2 json的描述(p4c)
if....缺失文件...
step4
运行编写后的controller.py
我们就ping通了!!!!!!!


终于搞完了....^ ^
over over over

浙公网安备 33010602011771号