学习内容:
这次实验我们给switch添加支持隧道转发的功能。我们需要定义一个新的header type封装IP包头,修改交换机代码以支持识别这种新的封装从而指导转发。
虚机安装使参考:P4 Tutorial 安装
新的header type包括 protocol ID和destination ID,分别用于标识被封装包的类型和路由
开始的代码文件basic_tunnel.p4,这里面只是基于IP转发,就像之前的basic_forwarding实验。
关于控制平面
P4程序定义了一个包处理pipeline,控制平面给每一个table插出rules。当rule匹配数据包,就会调用action。
实验已经提前加上了必要的控制平面条目。我们只需要运行make run命令其它操作会自动完成。比如:启动mininet实例,为按照sX-runtime.json文件每个交换机table加载包处理rules。(这部分我在basic_forwarding实验里已经说明过了。)
重要提示:我们使用P4Runtime安装控制平面规则。 sX-runtime.json文件中有table、keys、actions的名称,如编译器生成的P4Info文件中定义的(执行make run后查找build/basic.P4Info文件)。P4程序中添加或重命名表、键或操作的任何更改都需要反映在这些sX-runtime.json文件中。
实验步骤:
步骤1:完善代码
basic_tunnel.p4文件中包含了一个基于IP转发的路由实现方式。同样TODO是需要我们自己修改的部分,这和之前的basic_forwarding实验是一样的。最终修改完basic_tunnel.p4后达到的效果:switch可以基于自定义的封装包头做转发,如果是普通的IP数据包也可以做正常IP转发。
解决方案的思路:
- 新的header tpye命名为myTunnel_t,包含里两个16bit字段:proto_id和dst_id。
- myTunnel_t添加到headers结构中。
- 更新解析器(parser),可以基于etherType提取myTunnel包头和ipv4 包头。etherType中myTunnel包头是0x1212。
myTunnel后如果proto_id==TYPE_IPv4(0x0800),解析器(parser)应该能够识别提取ipv4包头。 - 定义新的action命名为myTunnel_forward,这里只是简单设置控制平面提供的出接口编号(i.e. egress_spec field of the standard_metadata bus)
- 定义一个新的table命名为myTunnel_exact,匹配myTunnel包头的dst_id字段。如果有匹配的数据包,table应该调用myTunnel_forward action,否则调用drop action。
- 更新apply,如果myTunnel包头是可用的,在MyIngress控制模块应用新定义的myTunnel_exact table;如果ipv4包头是可用的,就调用ipv4_lpm table。
- 更新逆解析器(deparser),按顺序填充ethernet、myTunnel、ipv4包头。注意只有在包头可用时逆解析器(deparser)才会填充。如果解析器(parser)在提取时设置了隐含有效位,那么则不需要检查包头有效性。
- 为switch添加静态rule,以便switch能够依照dst_id转发。参照拓扑图,配置接口以及设置IDs。这一步需要添加转发规则到sX-runtime.json文件。(X代表switch编号)
完成以上工作就可以make run启动mininet 实例,进行测试了。
具体代码可以参照solution/basic_tunnel.p4 。
拓扑图
步骤2: 解决方案实施:
- 运行sudo make run ,编译basic_tunnel.p4,启动mininet,按拓扑图启动配置switch和host。
- 看到mininet提示符后,打开h1和h2终端
- h2模拟server端,如下命令:
- 在没有tunnel情况下,在h1发送消息给h2。
-
这时在h2应该能收到数据包,数据包是由ethernet header、ip header、tcp header和载荷message组成。但如果把目的IP换成h3的IP 10.0.3.3,h2是收不到消息的,因为此时是基于目的IP的转发。
-
现在测试tunnel情况,在h1发送消息给h2, 这时目的IP可以设成是h3 的10.0.3.3。
-
这时h2收到的数据包组成是:ethernet header、tunnel header、ip header、tcp header和载荷message。在tunnel情况下,把目的IP换成h3的IP 10.0.3.3,h2仍然能收到消息,因为这时switch的转发优先基于tunnel header不关注ip header了。
可以在logs目录下看一下switch的log
h1 到 h2 Tunnel转发,同时看下switch s1的log,tail -f s1.log。
首先port 1收包,开始parser处理,按照我们的预设把字段拆分解析,
然后进入pipeline管道,依次是ingress,然后是控制平面的table rule匹配,egress,
最后deparser,把差分解析的包再装回去。
一套过程可以对照basic_tunnel.p4。
深入思考:
在真实的网络环境中通常是:数据包进入网络时会打上tunnel封装,而离开网络时再剥离tunnel封装。那么如何修改P4代码使我们的实验更接近现网的情况?
- 在进入网络的第一台sw,我们应该为myTunnel包头做一个目的IP和dst_id的映射。同时设置一个有效位,以便在逆解析器(deparser)处理时可以填充数据包。
- 在离开网络的最后一台sw,根据dst_id字段找到了出接口之后,我们还需要移除myTunnel包头。
补充
sudo make stop 停止后台运行
sudo make clean 清理上次程序残留的build,log文件
每次开始运行sudo make run前,建议先执行以上两个命令把环境清理干净。