两个问题
这一段时间研究Neutron DVR,即分布式路由 (Distributed Virtual Router)。当把南北向和东西向流程打通后,突然产生了两个问题,让我思索了很久,终于得到了比较令自己信服的答案,特此记录,分享给一同搞OpenStack的朋友们。如果有朋友觉得有错误,欢迎指出,一起探讨!
- 为什么要引入与计算节点绑定的MAC
- 为什么跨网段的东西向流量必须使用静态arp
1. 为什么要引入与计算节点绑定的MAC
1.1 什么是与计算节点绑定的MAC
首先说一下这个与计算节点绑定的MAC。我们知道,DVR的主要思想是将路由功能下发给所有的计算节点。从Linux实现的角度,就是每个计算节点都有一个namespace
用来实现路由功能,而所有的计算节点的namespace
中的虚拟网口都是一模一样的。DVR认为,这些namespace
中的虚拟网口qr
对其他计算节点应该是不可见的,因此,从Overlay发到其他计算节点的数据包中,如果源MAC是qr
的,都会被替换成该计算节点的唯一MAC;如果目的MAC是qr
的,都会被DROP。
注 与计算节点绑定的MAC在启用DVR之后会自动创建,并写入Neutron DB。通过neutron的配置文件可以指定这个唯一MAC的前缀。
1.2 Traffic Flow
L2 agent选择neutron-openvswitch-agent
时,主要是由br-tun
和br-int
来确保该功能正常运作的。以跨网段的东西向流量为例,拓扑图如下:
从Instance 1发往Instance2的traffic flow:
- Instance 1发往Instance 2的流量通过
br-int
的规则仍以NORMAL模式发送,在本地的namespace
做路由,从br-tun
准备发往Instance 2所在的计算节点。因为此时数据包的源MAC是Instance 2的默认网关qr-2
的MAC,所以br-tun
在数据包发出之前将源MAC修改为计算节点1的唯一MAC,即图中“1”的位置。 - 穿过了Overlay Network,数据包到达计算节点2,此时不需要再经过该节点的
namespace
,从patch口由br-tun
到达br-int
。br-int
流表中有规则被匹配:源MAC是计算节点1的唯一MAC且发往Instance 2。按常理讲,数据包应该是从Instance 2的网关发过来的,因此该规则的动作是:将计算节点唯一MAC改为Instance 2的网关qr-2
的MAC,即图中“2”的位置。
1.3 是否有必要修改qr的MAC
为什么计算节点的namespace
中的网口qr
不能让别的计算节点看到?这里假设图中“1”位置处并没有修改源MAC,我们再走一遍traffic flow:
- Instance 1发往Instance 2的流量通过
br-int
的流表规则仍以NORMAL模式发送,从br-tun
准备发往Instance 2所在的计算节点。 - 穿过的Overlay Network,数据包到达计算节点2,此时不需要再经过该节点的
namespace
,从patch口由br-tun
到达br-int
。br-int
的规则不会被匹配,因为此时源MAC是qr-2
的,因此会按照NORMAL模式发送,即按照MAC和端口转发,并且在MAC表中记下qr-2
的数据是从patch口进来的。
也就是说,此时图中1、2两个位置都没有进行数据包源MAC的修改,此时数据包还是可以到达Instance 2的。但,Instance 2再往Instance 1发的报文就会出问题,此时的traffic flow会是这样的:
假设Instance 2的arp表记住了
qr-2
的MAC,不需要再发送arp请求
- Instance 2发往Instance 1的流量通过
br-int
的流表规则仍以NORMAL模式发送,br-int
查看MAC表发现,qr-2
的数据包应该从patch口发出,因此数据包不会在计算节点2的namespace
做路由,而是进入br-tun
问题由此诞生。先不说br-tun
的流表规则会把目的MAC是qr
的流DROP,假设数据包可以到达计算节点1做路由,但这样的traffic flow显然已经丧失了DVR设计的初衷。
因此,与计算节点绑定的MAC是必须的。
2. 为什么跨网段的东西向流量必须使用静态arp
2.1 Traffic Flow
L2 agent选择neutron-openvswitch-agent
时,主要是由namespace
内部配置静态arp表来响应Instance 1的arp请求报文。以跨网段的东西向流量为例,拓扑图如下:
从Instance 1发往Instance 2的traffic flow:
- Instance 1与Instance 2不在同一网段,因此数据包通过
br-int
的流表规则最终仍是以NORMAL模式发送,到达namespace
中的qr-1
。 - L3 agent通过从Neutron DB获取其他实例port对应的IP/MAC关系,写入
namespace
的静态arp表中。Instance 1的默认网关qr-1
经过路由,由qr-2
根据arp表将数据包发送到Instance 2,即图中“+”位置。其余的部分与前面是一样的,省略。
2.2 为什么一定要使用静态arp
为什么不能向legacy_router模式或者同网段一样发送arp请求?通过手动将namespace
中的静态arp删掉发现无法获取到Instance 2的MAC,原因是在图中2的位置,arp请求报文会命中br-int
规则:源MAC是计算节点1的唯一MAC但并不是发往Instance 2,该规则的动作是:DROP,即图中“2”的位置是不会有arp请求报文发到Instance 2的。
静态arp和所有计算节点br-int
的流表规则都说明一件事:跨网段东西向流量必须使用静态arp。对比之下,同网段东西向流量可以使用arp请求来获取对端的MAC,总觉得匪夷所思。
假设放开静态arp和br-int
流表的限制,让arp请求报文到达Instance 2,看看会有什么问题:
- Instance 1与Instance 2不在同一网段,因此数据包通过
br-int
的流表规则最终仍是以NORMAL模式发送,到达namespace
中的qr-1
,qr-2
发送arp请求报文,询问Instance 2的MAC。arp请求从br-tun
准备发往所有的计算节点。因为此时数据包的源MAC是Instance 2的默认网关qr-2
的MAC,所以br-tun
在数据包发出之前将源MAC修改为计算节点1的唯一MAC,即图中“1”的位置。 - 穿过了Overlay Network,数据包到达计算节点2,从patch口由
br-tun
到达br-int
。在图中“2”位置发出,源MAC修改为Instance 2的网关qr-2
的MAC。 - Instance 2回复arp请求,将发往默认网关
qr-2
。数据包通过br-int
流表规则最终仍是以NORMAL模式发送,从MAC表查询得知,目的MAC为qr-2
的应发往namespace
。
问题由此诞生。目的MAC为qr
的数据包只能在计算节点内部,不能发送到其他计算节点,否则还是会引起br-int
的混乱。所以,就算跨网段的东西向流量允许发送arp请求,发送arp请求的namespace
也永远收不到arp回复报文。
因此,跨网段的东西向流量必须使用静态arp。
后面有时间会补充ovs流表作为证据