练习3:IPv6路由
说明:本文翻译自onos-p4-tutorial的Exercise 3: IPv6 routing,用于理解纪录IPv6转发
在本练习中,您将修改P4程序和ONOS应用程序,以增加对连接到该结构的所有主机之间基于IPv6(L3)路由的支持,并支持ECMP以均衡多个spine之间的流量。
总览
要求
在这一阶段,我们希望我们的光纤网络表现得像标准IP光纤网络一样,交换机充当路由器。因此,应满足以下要求:
- Leaf接口应该被分配一个IPv6地址(网关地址)和一个我们将要调用的MAC地址
myStationMac
。 - Leaf交换机应该能够处理NDP邻居请求(NS)消息,即由主机发送的NDP邻居通告(NA)应答,以解析与交换机接口/网关IPv6地址关联的MAC
myStationMac
地址; - 以太网目标
myStationMac
接收到的数据包应通过路由pipeline进行处理(未丢失的流量随后可通过bridging pipeline进行处理); - 路由时,P4程序应查看IPv6目标地址。如果找到匹配的条目,则应将数据包转发到给定的下一跳,并相应地修改数据包的以太网地址(源设置为
myStationMac
,目标设置为下一跳); - 当将数据包经由各个spine路由到不同Leaf时,Leaf交换机应该能够使用ECMP来分配流量。
配置
该netcfg.json文件为每个名为srv6DeviceConfig
的设备打包了一个特殊配置,此部分定义了3个值:
-
myStationMac
:与每个设备关联的MAC地址,即路由器的MAC地址; -
mySid
:设备的SRv6 Segment ID,将在下一个练习中使用。 -
isSpine
:一个布尔型标志,表示是否应将设备视为spine交换机。
此外,netcfg.json文件还包括分配了IPv6前缀的接口列表(在文件的ports
部分下查找)。 Mininet拓扑脚本topo.py中使用了相同的IPv6地址。
尝试ping不同子网中的主机
与之前的练习类似,让我们开始使用Mininet来验证不同子网上的主机之间的ping操作不起作用。使它工作将是您的任务。
在Mininet CLI上:
mininet> h2 ping h3
PING 2001:2:3::1(2001:2:3::1) 56 data bytes
From 2001:1:2::1 icmp_seq=1 Destination unreachable: Address unreachable
From 2001:1:2::1 icmp_seq=2 Destination unreachable: Address unreachable
From 2001:1:2::1 icmp_seq=3 Destination unreachable: Address unreachable
...
如果检查ONOS日志,您会h2
发现已发现以下内容:
INFO [L2BridgingComponent] HOST_ADDED event! host=00:00:00:00:00:20/None, deviceId=device:leaf1, port=6
INFO [L2BridgingComponent] Adding L2 unicast rule on device:leaf1 for host 00:00:00:00:00:20/None (port 6)...
这是因为ONOS用h2
发送NDP NS消息来解析其网关的MAC地址(正如topo.py中所配置的2001:1:2::ff
)。
我们可以检查IPv6邻居表h2
以查看解析是否失败:
mininet> h2 ip -6 n
2001:1:2::ff dev h2-eth0 FAILED
基于P4的NDP消息生成
现在的P4代码已经提供了表ndp_reply_table
和操作ndp_ns_to_na(mac_addr_t target_mac)
来答复主机发送的NDP NS消息。
该表实质上提供了IPv6地址及其对应的MAC地址(定义为action参数)之间的映射。action实现将相同的NDP NS数据包转换为具有给定目标MAC地址的NA。
ONOS应用程序已经提供了一个组件NdpReplyComponent.java,,该组件负责使用netcfg.json中定义的ndp_reply_table
为所有接口的IPv6地址进行填充,并将其myStationMac
用作目标MAC地址。
该组件当前被禁用;您将需要在后续步骤中启用它。但是首先,让我们关注P4程序。
练习步骤
1.修改P4程序
第一步将是向中添加新表main.p4
。
IPv6的LPM路由表
此练习的主表将是一个与目的IPv6地址match的L3表。您应该创建一个在目的地址上执行最长前缀匹配(LPM)并执行所需的数据包转换的表。
在本练习中的action与练习2中那样定义的action不同。此action应:
- 用目的地址替换源以太网地址,目标地址应为
myStationMac
(请参阅下一节的"My Station"表); - 将目的以太网设置为下一跳的地址(作为action参数传递);
- 减少IPv6的
hop_limit
。
L3表和操作应提供给定的IPv6前缀和下一跳MAC地址之间的映射。在我们的解决方案中(因此在PTF入门代码和ONOS应用程序中),我们重复使用练习2中定义的L2表来提供下一跳MAC地址和输出端口之间的映射。如果要应用这样的解决方案,请确保在apply
块中的L2之前调用L3表。
此外,我们将希望在IPv6跳数限制达到0时丢弃数据包。这可以通过apply
在应用L3表之后在检查字段的块中插入逻辑来实现。
此时,您的管道应正确匹配,转换和转发IPv6数据包。
注意:为简单起见,我们使用全局路由表。如果您想将路由表划分为虚拟表(即使用VRF ID),则可以将其作为额外工作。
“My Station”表
您可能会发现 ,此时交换机将不加选择地执行IPv6路由,这在技术上是不正确的。交换机应仅路由发往路由器以太网地址(myStationMac
)的以太网帧。
注意区分路由和转发,这里用L3路由的当目的MAC地址是路由器MAC地址的情况下,主机MAC地址不在此列
要解决此问题,您将需要创建一个与目标以太网地址匹配的表,并在匹配时将数据包标记为要路由。我们称其为“My Station”表。
您可以自由使用特定的操作或元数据来携带此信息,或者为简单起见,可以使用NoAction
并在apply
块的此表中检查命中。创建该表后,请记住要更新您的apply
块。
使用action selectors添加对ECMP的支持
您将对pipeline进行的最后修改是添加一个action_selector
,该哈希将对不同可能的下一跳之间的流量进行哈希处理。在我们的叶-脊拓扑中,对于每个叶对,每个脊都有一条等价的路径,我们希望能够利用这一点。
您将对pipeline进行的最后修改是添加一个action_selector
,它将对可能存在的下一跳不同节点之间的流量进行哈希处理。在我们的Leaf-Spine拓扑中,对于每一对Leaf,每个Spine都有一条等价的路径,我们希望能够利用这一点。
我们已经在P4程序中为您定义了ecmp_selector
,但是您需要将selector添加到L3表中。您还需要将selector字段做为match的key进行添加。
对于IPv6流量,您需要将源IPv6地址和目标IPv6地址以及IPv6流标签作为ECMP哈希的一部分包括在内,但您可以自由地在包头中包含其他部分。例如,您可以包含其余的5元组(即L4原型和端口);如果要使用L4端口,则将其解析为local_metadata
。有关散列IPv6流量的必填字段的详细信息,请参阅RFC6438。
您可以在tutorial
目录使用make p4
编译程序。在继续操作之前,请确保解决所有编译器错误。
此时,我们的P4 pipeline应准备好进行测试。
2. 运行PTF测试
有关IPv6路由行为的测试位于ptf/tests/routing.py
中。打开该文件,然后在提示的地方进行修改(查找TODO EXERCISE 3
)。
要运行此练习的所有测试:
cd ptf
make routing
此命令将运行routing
组中的所有测试(即ptf/tests/routing.py
的内容)。要运行特定的测试用例,可以使用:
make <PYTHON MODULE>.<TEST CASE NAME>
例如:
make bridging.IPv6RoutingTest
回溯检查
为确保新更改不会破坏其他功能,请确保也对先前的练习进行测试。
make packetio
make bridging
make routing
如果所有测试成功,那么恭喜!您可以转到下一步。
3. 修改ONOS应用
练习的最后一部分是为ONOS应用程序的路由组件更新启动程序代码,该代码位于:app/src/main/java/org/p4/p4d2/tutorial/Ipv6RoutingComponent.java
与先前的练习类似,启动程序代码已经提供了事件侦听器和路由策略的实现,即,由于拓扑事件而触发的方法,例如,基于leaf和spine之间的可用链接来计算ECMP组。
要求您修改4种方法的实现。
-
setUpMyStationTable()
:为“My station”表插入流规则; -
createNextHopGroup()
:负责为路由表的ECMP selector创建等效于P4Runtime动作配置文件group的ONOS; -
createRoutingRule()
:为IPv6路由表创建流规则; -
createL2NextHopRule()
:创建将下一跳MAC地址(用于ECMP组)映射到输出端口的流规则。您应该已经在L2BridgingComponent
中实现了类似的方法(请参阅learnHost()
方法)。称此为在交换机之间创建L2规则,例如在leaf和spine之间转发数据包。由于主机相关转发规则是由L2BridgingComponent
插入的,因此这里无需处理主机的L2规则。
启用路由组件
一旦确定您对上一步的解决方案应该可以工作,在构建和重新加载应用程序之前,请记住通过将enabled
标志设置true
为类定义的顶部来启用与路由相关的组件。
为使IPv6路由正常工作,应启用以下组件:
Ipv6RoutingComponent.java
NdpReplyComponent.java
生成并重新加载应用
在ONOS运行时,使用以下命令来构建和重新加载您的应用程序:
$ make app-build app-reload
在构建应用程序时,修改后的P4编译器输出(bmv2.json
和 p4info.txt
)将与Java类一起打包在一起。重新加载应用程序后,您应该在ONOS日志中看到消息,表明已设置了新的管道配置,Ipv6RoutingComponent
并且 NdpReplyComponent
已激活和。
还要检查日志中是否存在潜在有害消息。请参阅 练习2以了解常见错误。
4. 在Mininet上测试IPv6路由
验证ping
在Mininet CLI中按顺序键入以下命令:
mininet> h2 ping h3
mininet> h3 ping h2
PING 2001:1:2::1(2001:1:2::1) 56 data bytes
64 bytes from 2001:1:2::1: icmp_seq=2 ttl=61 time=2.39 ms
64 bytes from 2001:1:2::1: icmp_seq=3 ttl=61 time=2.29 ms
64 bytes from 2001:1:2::1: icmp_seq=4 ttl=61 time=2.71 ms
...
现在h3
并h2
之间的ping应该工作。如果ping不起作用,请检查与练习2相同的故障排除步骤。
ONOS日志应显示以下消息:
INFO [Ipv6RoutingComponent] HOST_ADDED event! host=00:00:00:00:00:20/None, deviceId=device:leaf1, port=6
INFO [Ipv6RoutingComponent] Adding routes on device:leaf1 for host 00:00:00:00:00:20/None [[2001:1:2::1]]
...
INFO [Ipv6RoutingComponent] HOST_ADDED event! host=00:00:00:00:00:30/None, deviceId=device:leaf2, port=3
INFO [Ipv6RoutingComponent] Adding routes on device:leaf2 for host 00:00:00:00:00:30/None [[2001:2:3::1]]
...
如果您没有看到有关h2
(00:00:00:00:00:20
)发现的消息,那是因为在练习开始时尝试ping时,ONOS已经发现了该主机。
注意:我们需要先从h2
开始ping,然后再从h3
开始ping,以便ONOS在转发ping数据包之前发现两个主机的位置。这是因为当前的实现要求主机生成ONOS会发现的NDP NS数据包。为了避免必须手动生成NDP NS消息,可能的解决方案是:
-
在Mininet中配置IPv6主机,以定期自动生成另一种NDP消息,称为路由器请求(RS)。
-
在ACL表中插入流规则,以将NDP RS数据包克隆到CPU。这将需要匹配NDP NA和NS以外的ICMPv6代码的其他值。
-
修改
hostprovider
内置的应用程序实现,以从NDP RS消息中了解主机位置(当前仅使用NDP NA和NS)。
验证基于P4的NDP NA生成
要验证交换机基于P4的NDP NA生成是否正常工作,可以检查h2
或的邻居表h3
,它应该显示类似以下内容:
mininet> h3 ip -6 n
2001:2:3::ff dev h3-eth0 lladdr 00:aa:00:00:00:02 router REACHABLE
其中2001:2:3::ff
是在netcfg.json
和topo.py
中定义的IPv6网关地址,而00:aa:00:00:00:02
是在netcfg.json
中为leaf2
定义的myStationMac
。
使用ONOS Web UI可视化ECMP
为了验证ECMP是否正常工作,让我们开始从h2
到h3
使用iperf的多个并行流量。在Mininet命令提示符下,键入:
mininet> h2 iperf -c h3 -u -V -P5 -b1M -t600 -i1
此命令将在h2
上启动一个iperf客户端,通过IPv6(-V
)将UDP数据包(-u
)发送到h3
(-c
)。为此,我们生成5个不同的流(-P5
),每个流的上限为1Mbit/s(-b1M
),运行10分钟(-t600
),并每1秒报告一次统计信息(-i1
)。
由于我们正在生成UDP流量,因此无需在h3
上启动iperf服务器。
要可视化流量,请从教程VM中打开浏览器(例如Firefox)访问http://127.0.0.1:8181/onos/ui。询问时,请使用用户名onos
和密码rocks
。
在显示ONOS拓扑视图的页面上:
- 按
H
键盘上的显示主机; - 按下
L
以显示设备标签; - 多次按
A
,直到看到端口/链接统计信息,以包/秒(pps)或位/秒为单位。
如果您正确完成了P4和应用的实现,并且ECMP正常工作,则应该看到将流量转发到两个通道,如下面的屏幕截图所示:
routing-ecmp恭喜你!
您已完成练习3!现在,您的拓扑可以在任何主机之间转发IPv6流量。
网友评论