练习2:桥接
说明:本文翻译自onos-p4-tutorial的Exercise 2: Bridging,用于理解纪录L2转发逻辑
在本练习中,您将修改P4程序和ONOS应用程序,以增加对以太网(L2)桥接的支持,以支持连接到同一leaf交换机且属于同一子网的主机。
总览
ONOS应用程序假定给定子网的主机都连接到相同的leaf,并且两个不同leaf的两个接口无法配置相同的IPv6子网。换句话说,仅对连接到同一leaf的主机允许L2桥接。
本教程中使用的Mininet脚本topo.py定义了4个子网:
-
2001:1:1::/64
有3台主机(h1a
,h1b
,和h1c
)连接到leaf1
-
2001:1:2::/64
有1台主机(h2
)连接到leaf1
-
2001:2:3::/64
有1台主机(h3
)连接到leaf2
-
2001:2:4::/64
有1台主机(h4
)连接到leaf2
相同的IPv6前缀在netcfg.json文件中定义,用于为ONOS提供接口配置。
尝试ping主机
首先,尝试使用Mininet对第一个子网的任意两个主机执行ping操作。它应该不起作用,因为您尚未在P4中实现任何桥接逻辑,也没有为其安装表条目。
在Mininet CLI上:
mininet> h1a ping h1b
PING 2001:1:1::b(2001:1:1::b) 56 data bytes
From 2001:1:1::a icmp_seq=1 Destination unreachable: Address unreachable
From 2001:1:1::a icmp_seq=2 Destination unreachable: Address unreachable
From 2001:1:1::a icmp_seq=3 Destination unreachable: Address unreachable
...
但是,由于h1a
预期会生成NDP邻居请求(NS)消息以发现h1b
的以太网地址,并且由于我们hostprovider
在上一个练习中已经激活了该应用程序(请记住将NDP数据包克隆到CPU的ACL流规则),因此我们希望ONOS能够发现主机h1a
。要进行检查,请使用ONOS CLI:
onos> hosts -s
id=00:00:00:00:00:1A/None, mac=00:00:00:00:00:1A, locations=[device:leaf1/3], vlan=None, ip(s)=[2001:1:1::a]
该hostprovider
应用已通过嗅探NDP NS数据包获悉了主机MAC地址,位置和IPv6地址。
练习步骤
1. 修改P4程序
在main.p4
的入口pipeline中,我们已经定义了完成练习所需的一些操作-即set_output_port
单播数据包以及set_multicast_group
从多个端口发送数据包,例如NDP NS消息。稍后将由ONOS应用创建多播组。缺少的是使用这些操作的表。
第一步将是创建一个L2表,其中要match目的以太网地址和上述actions。您需要支持两种类型的目标地址:
-
Broadcast/multicast条目:将复制的NDP邻居请求(NS)消息复制到所有面向主机的端口;
-
Unicast条目:发现主机后,将由控制平面(即ONOS应用)填充。
与广播到以太网目标地址FF:FF:FF:FF:FF:FF的ARP消息不同,NDP消息使用IPv6广播/组播数据包,该数据包发送到RFC2464指定的特殊以太网地址。这些目标地址以33:33
为前缀,后四个八位位组是IPv6目标多播地址的后四个八位位组。在不深入研究RFC2464细节的情况下,对此类IPv6广播/多播数据包进行匹配的最直接方法是在33:33:**:**:**:**
上使用三元匹配,其中*
表示“不在乎”。
头脑风暴:您将为此表使用哪种类型的匹配键(例如exact,LPM和ternary)?exact对多播条目有效吗?使用非精确单播条目是否有弊端?我们的解决方案对每种类型的条目使用两个L2表(对于单播来说是精确的,对于多播来说是ternary),但是您可以选择不同的方法。
注意:为简单起见,我们不会使用VLAN来划分L2域,但是您可以添加对VLAN的支持,作为额外的功劳练习。
创建L2表后,您需要在入口pipeline(IngressPipeImpl
)的apply
块区域中应用这些表。
完成后,您可以在tutorial
目录使用make p4
编译程序。在继续操作之前,请确保解决所有编译器错误。
此时,您的P4管道应已准备好进行测试。
2. 运行PTF测试
L2桥接行为的测试位于中ptf/tests/bridging.py
。打开该文件,然后在提示的地方进行修改(查找TODO EXERCISE 2
)。
要运行此练习的所有测试:
cd ptf
make bridging
此命令将运行bridging
组中的所有测试(即的内容 ptf/tests/bridging.py
)。要运行特定的测试用例,可以使用:
make <PYTHON MODULE>.<TEST CASE NAME>
例如:
make bridging.ArpNdpRequestWithCloneTest
回溯检查
为确保新更改不会破坏其他功能,请确保也对先前的练习进行测试。
make packetio
make bridging
如果所有测试成功,那么恭喜!您可以转到下一步。
3. 修改ONOS应用
下一步将是修改ONOS应用程序,以控制之前修改的P4程序的L2桥接部分。
您将需要修改的源代码位于:app/src/main/java/org/p4/p4d2/tutorial/L2BridgingComponent.java
根据提示修改代码(查找TODO EXERCISE 2
)。
完整的方法实现以插入L2流规则
这个应用程序组件定义了两个事件侦听器,它们位于L2BridgingComponent
类的底部,InternalDeviceListener
用于设备事件(例如,连接新交换机)和InternalHostListener
主机事件(例如,发现新主机)。这些监听器依次调用以下方法:
-
setUpDevice()
:负责为所有面向主机的端口创建一个多播组,并为广播/多播数据包(例如ARP和NDP消息)插入流规则; -
learnHost()
:负责根据发现的主机位置为交换机插入单播L2条目。
为了支持重新加载应用程序实现,在激活时,ONOS已知的所有设备和主机在组件激活时也会调用这些方法(查找方法activate()
和setUpAllDevices()
)。
为简单起见,我们的广播域将被限制在单个设备上,即,我们仅允许对同一leaf交换机的端口进行数据包复制的广播。因此,我们可以将去往多播组中spine的端口排除在外。为了确定端口是否应该面向主机,我们查看netcfg.json文件中的接口配置(查找JSON文件的ports
部分)。
入门代码已经提供了insertMulticastGroup()
方法的实现;您需要完成其他两种方法的实现:insertMulticastFlowRules()
和learnHost()
。
启用桥接组件
一旦确定您上一步的解决方案可以工作,那么在构建和重新加载应用程序之前,请记得通过在类定义顶部将enabled
标志设置为true
来启用组件:
/**
* App component that configures devices to provide L2 bridging capabilities.
*/
@Component(
immediate = true,
enabled = true
)
public class L2BridgingComponent {
...
生成并重新加载应用
在ONOS运行时,使用以下命令来构建和重新加载您的应用程序:
$ make app-build app-reload
在构建应用程序时,修改后的P4编译器的输出(bmv2.json
和p4info.txt
)将与Java类一起打包在一起。重新加载应用程序后,您应该看到如下消息,表明已设置了新的pipeline配置并已将L2BridgingComponent
激活:
INFO [PiPipeconfManager] Unregistered pipeconf: org.p4.srv6-tutorial (fingerprint=2e:39:f0:81:cd:a3:76:20)
INFO [PipeconfLoader] Found 1 outdated drivers for pipeconf 'org.p4.srv6-tutorial', removing...
INFO [PiPipeconfManager] New pipeconf registered: org.p4.srv6-tutorial (fingerprint=2e:39:f0:81:1f:37:e6:82)
INFO [PipelineConfigClientImpl] Setting pipeline config for device:leaf1 to org.p4.srv6-tutorial...
...
INFO [MainComponent] Waiting to remove flows and groups from previous execution of org.p4.srv6-tutorial..
...
INFO [MainComponent] Started
INFO [L2BridgingComponent] Started
...
INFO [L2BridgingComponent] *** L2 BRIDGING - Starting initial set up for device:leaf1...
INFO [L2BridgingComponent] Adding L2 multicast group with 4 ports on device:leaf1...
INFO [L2BridgingComponent] Adding L2 multicast rules on device:leaf1...
INFO [L2BridgingComponent] Adding L2 unicast rule on device:leaf1 for host 00:00:00:00:00:1A/None (port 3)...
...
了解ONOS错误日志
在Mininet中尝试解决方案之前,值得查看一下ONOS日志中可能的错误。重新加载应用程序时可能会看到两种主要类型的错误:
-
写入错误,例如删除不存在的实体或插入已经存在的实体:
WARN [WriteResponseImpl] Unable to DELETE PRE entry on device...: NOT_FOUND Multicast group does not exist ... WARN [WriteResponseImpl] Unable to INSERT table entry on device...: ALREADY_EXIST Match entry exists, use MODIFY if you wish to change action ...
这些通常是暂时性错误,您不必担心它们。它们描述了ONOS内部设备状态的暂时不一致,应通过定期对帐(reconciliation)机制尽快恢复这种状态。 ONOS核心会定期轮询设备状态,以确保其内部表示准确无误,同时将任何pending的修改写入设备,以解决这些错误。
否则,如果您看到它们定期出现(每3-4秒一次),则表示对帐过程不起作用,并且其他地方出了问题。尝试重新加载应用(
make app-reload
);如果仍不能解决警告,请与教员联系。 -
Translation错误,表示ONOS无法将应用程序生成的流规则(或组)转换为与P4Info兼容的表示形式。例如:
WARN [P4RuntimeFlowRuleProgrammable] Unable to translate flow rule for pipeconf 'org.p4.srv6-tutorial':...
仔细阅读错误消息,并根据需要对应用程序进行更改。可能您使用的表、匹配字段或操作名称在P4Info中不存在。检查您的P4Info文件,修改并重新加载应用程序(
make app-build app-reload
)。
4. 在Mininet上测试L2桥接
现在,该应用程序已被修改并重新加载,并且ONOS日志中没有潜在的有害错误,您应该能够重复在练习开始时执行的相同ping测试。这一次它应该有效:
mininet> h1a ping h1b
PING 2001:1:1::b(2001:1:1::b) 56 data bytes
64 bytes from 2001:1:1::b: icmp_seq=2 ttl=64 time=0.580 ms
64 bytes from 2001:1:1::b: icmp_seq=3 ttl=64 time=0.483 ms
64 bytes from 2001:1:1::b: icmp_seq=4 ttl=64 time=0.484 ms
...
检查ONOS日志,您应该看到与发现主机有关的消息,该主机h1b
现在正在从中接收NDP NS消息h1a
并以NDP NA消息进行回复(请记住h1a
在练习开始时已经发现):
INFO [L2BridgingComponent] HOST_ADDED event! host=00:00:00:00:00:1B/None, deviceId=device:leaf1, port=4
INFO [L2BridgingComponent] Adding L2 unicast rule on device:leaf1 for host 00:00:00:00:00:1B/None (port 4)...
故障排除
如果ping不起作用,您可以采取以下步骤来排除网络故障:
-
检查所有流规则和组是否已成功写入设备。使用ONOS CLI命令(例如
flows -s any device:leaf1
和)groups any device:leaf1
,验证所有流和组都处于状态ADDED
。如果您看到其他状态,例如PENDING_ADD
,则将这些条目写入设备,请检查ONOS日志中是否存在错误。您还可以使用ONOS网络用户界面检查流程和群组状态。 -
使用表计数器来验证是否按预期命中了表。如果您尚未为L2表定义直接计数器,请修改P4程序以添加一些计数器,然后构建并重新加载应用程序(
make app-build app-reload
)。ONOS应该每3-4秒(对帐过程的同一时间段)自动检测一次并轮询计数器。要检查其值,可以使用ONOS CLI(flows -s any device:leaf1
)或Web UI。 -
仔细检查PTF测试,并确保您在中创建了类似的流规则
L2BridgingComponent.java
。你注意到有什么区别吗? -
查看BMv2日志中可能的错误。检查文件
/tmp/bmv2-<SW-NAME>-log
或使用bm-log <SW-NAME>
bash命令。 -
如果在这里仍然无法正常工作,请与一位教员联系以寻求帮助。
5. 可视化ONOS Web UI上的主机
从教程VM(例如Firefox)中打开浏览器,前往http://127.0.0.1:8181/onos/ui。访问时,请使用用户名onos
和密码rocks
。
要在拓扑视图上切换显示/不显示主机,请按H
键。
恭喜啦
您已经完成练习2!现在,您的交换矩阵能够在同一子网中的主机之间转发数据包,并连接到同一leaf交换机。
网友评论