neutron-plugin 分为 core-plugin 和 service-plugin 两类L2-L3称为core plugin,包含network、subnet、port
L4-L7称为service plugin,包含router、firewall、loadbalancer、VPN、metering等等
driver 是同一个 plugin 下替换不同网元实现的方式
ML2 type driver : vlan, vxlan, gre, etc.
ML2 mechanism driver : linux bridge, openvSwitch, etc
计算节点网络实现模型
下面我们直接介绍计算机节点上的虚拟机流量是如果被送出计算节点的,并在过程中插入介绍相关的虚拟网络设备于工作机理。
Step 1. 流量经由虚拟机内核 TCP/IP Stack 交给虚拟网卡 vNIC 处理,vNIC 是一个 Tap 设备,它允许用户态程序(这里指 GuestOS,一个 qemu 进程)向内核 TCP/IP 协议栈注入数据。Tap 设备可以运行在 GuestOS 上,提供与物理 NIC 完全相同的功能。
Step 2. 虚拟机的 vNIC(Tap 设备)没有直连到 OvS Bridge 上,而是通过 Linux Bridge 中继到 OvS br-int(Integrated bridge,综合网桥)。为什么 vNIC 不直连 br-int?这是因为 OvS 在 v2.5 以前只有静态防火墙规则,并不支持有状态的防火墙规则。这些规则是 Neutron Security Group 的底层支撑,为虚拟机提供针对端口(vNIC)级别的安全防护,所以引入了 Linux Bridge 作为安全层,应用 iptables 对有状态的数据包进行过滤。其中 Linux Bridge qbr 是 quantum bridge 的缩写。
Step 3. Linux Bridge 与 OvS Bridge 之间通过 veth pair (虚拟网线)设备连接,“网线” 的一端命名为 qvb(quantum veth bridge)另一端命名为 qvo(quantum veth ovs)。veth pair 设备总是成对存在的,用于连接两个虚拟网络设备,模拟虚拟设备间的数据收发。veth pair 设备的工作原理是反转通讯数据的方向,需要发送的数据会被转换成需要收到的数据重新送入内核 TCP/IP 协议栈进行处理,最终重定向到目标设备(“网线” 的另一端)。
Step 4. OvS br-int 是一个综合网桥,作为计算节点本地(Local)虚拟交换设备,完成虚拟机流量在本地的处理 ——Tenant flows are separated by internally assigned VLAN ID.(Tenant 网络的 Local VLAN ID 由内部分配)
Step 5. 从本地虚拟机传输到远端虚拟机(或网关)的流量由 OvS br-int 上的 int-br-eth1(ovs patch peer 设备)端口送到 OvS br-ethX 上。需要注意的是,br-ethX 并未是一成不变的:当网络类型为 Flat、VLAN 时,使用 br-ethX;当网络类型为 Tunnel(e.g. VxLAN、GRE)时,br-ethX 就会被 br-tun 替换。上图示例为 VLAN 网络。我们将 br-ethX、br-tun 统称为租户网络层网桥设备(TNB),以便于叙述。
NOTE:qbr-xxx 与 OvS br-int 之间使用 veth pair 设备相连,br-int 与 br-ethx/br-tun 之间使用 patch peer 设备相连。两种都是类似的虚拟 “网线”,区别在于前者是 Linux 虚拟网络设备,后者是 OvS 实现的虚拟网络设备。
NOTE:如果租户网桥是 br-tun 而不是 br-ethX,那么在 br-tun 上会有 port:patch-int,br-int 上会有 port:patch-tun,通过 patch-int 和 patch-tun 实现租户网桥 br-tun 和本地网桥 br-int 之间的通信。
Step 6. 当虚拟机流量流经 OvS br-int 与 OvS br-ethX 之间时,需要进行一个至关重要且非常复杂的动作 —— 内外 VID 转换。这是一种 “分层兼容” 的设计理念,让我想起了:所有计算机问题都可以通过引入一个中间层来解决。而 Neutron 面对的这个问题就是 —— 支持多种租户网络类型(Flat、VLAN、VxLAN、GRE)。
Step 7. 最后虚拟机流量通过挂载到 TNB(br-ethX/br-tun)上的物理网卡 ethX 发出到物理网络。OvS br-int 与 OvS br-ethX 之间也是通过 veth pair 设备实现。
Step 8. 虚拟机的流量进入到物理网络之后,剩下的就是传统网络的那一套了。网络包被交换机或其他桥接设备转发到其他计算、网络节点(PS:这取决于具体的部署网络拓扑,一般虚拟机流量只会被同处 Internal Network 的计算节点)接收到。
从网络层的角度看,计算节点的网络模型可分为:租户网络层、本地网络层

其中本地网络层通过 VLAN ID 来划分 br-int 中处于不同网络的虚拟机(端口),本地网络仅支持 VLAN 类型;而租户网络层为了实现多类型混合平面的需求却要支持非隧道类型网络 Flat、VLAN(br-ethX)及隧道类型网络 VxLAN、GRE(br-tun)。显然,本地网络层和租户网络层之间必须存在一层转换。这就是所谓的 VID 转换。
VID 是一个逻辑概念,针对不同的租户网络类型也有不同类型的 “VID”。
| 本地网络层 | 租户网络层 |
|---|---|
| VLAN(ID) | VLAN(ID) |
| VLAN(ID) | VxLAN(VNI) |
| VLAN(ID) | GRE(key) |
需要注意的是 VID 的范围是由租户定义的 ——Tenant flows are separated by user defined VLAN ID.(租户网络的 VID 由User Defined,此时示例为 VLAN 类型网络)。所谓 “User Defined” 就是用户通过 Neutron 配置文件 ml2_conf.ini 为各种网络类型配置的 range。e.g.
# /etc/neutron/plugins/ml2/ml2_conf.ini
[ml2_type_vlan]
network_vlan_ranges = public:3001:4000
[ml2_type_vxlan]
vni_ranges = 1:1000
[ml2_type_gre]
tunnel_id_ranges = 1:1000
再次强调,本地网络的 VLAN ID 是由内部代码逻辑算法分配的,而租户网络的 VID 才是由用户自定义配置的。
VLAN 类型网络的内外 VID 转换:

VxLAN 类型的内外 VID 类型转换:

出报文:在 br-tun 的 G 口进行内外 VID 转换

入报文:在 br-tun 的 G 口进行内外 VID 转换
或许你会感到奇怪,为什么租户网络与本地网络同为 VLAN 类型的情况下还需要进行内外 VID 转换?解答这个问题只需要辩证思考一下:加入不进行内外 VID 转换会怎样?答案是会在混合 VLAN 和 VxLAN 类型租户网络的场景中出现内外 VID 冲突的情况。

假设网络1:租户网络 VLAN 的 VID 为 100,不做内外 VID 转换,那么本地网络 VLAN ID 也是 100。
网络2:租户网络 VxLAN 的 VID 为 1000,进行内外 VID 转换,本地网络 VLAN 100 也可能是 100。
这是因为 VxLAN 网络再进行内外 VID 转换的时候并不知道 VLAN 网络的 VID 是多少,只有当 VLAN 网络进行了内外 VID 转换之后才会知道,因为 VID 转换是有由 OvS Flow Table 记录并执行的 ——VLAN ID is converted with flow table。
所以 VLAN 类型网络也要进行内外 VID 转换是为了防止混合 VLAN 和 VxLAN 类型租户网络的场景中出现内外 VID 冲突的情况!
网络节点所承载的最核心的功能就是解决虚拟机与外部网络(e.g. Internet)通信的问题,围绕这个问题我们设想一下在传统网络中是怎么实现的?

所有计算节点内的虚拟机,要访问 Internet,必须先经过网络节点,网络节点作为第一层网关。
网络节点会通过连接 DC 物理网络中的一个设备(e.g. 交换机,或者是路由器)到达 DC 的网关 。 这个设备称为第二层网关。当然,网络节点也可以直接对接 DC 网关(如果 DC 网关可控的话),这时候,就不需要第二层网关了。
DC 网关再连接到 Internet上。
可见,网络节点要处理的事情就是第一层网关处理的事情,西接所有计算节点的流量,东接物理网络(第二层)网关设备。为此,网络节点所需要的元素就是一个 L3 Router。需要注意的是,这里所提到的 L3 Router 并不是一个 vRouter(SDN 中的虚拟路由器),而是网络节点本身(一个可作为路由器的 Linux 服务器)。借助于 Linux 服务器本身的路由转发功能,网络节点得以成为了上文提到的:访问外部网络所需要通过的第一层网关。

依旧从分层的角度来看,网络节点的网络实现模型可以分为 4 层:
网络节点出了提供 L3 Router 服务,同时也为每个有必要(用户手动开启)的租户网络提供 DHCP 服务。为了实现多租户网络资源隔离,应用了 Linux 提供的 Network Namesapce 技术。每创建一个 L3 Router 资源对象,就会添加一个与之对应的 qrouter-XXX namesapce;每为一个租户网络开启 DHCP 服务,就会添加一个与之对应的 qdhcp-XXX namesapce。

上图可见,DHCP 服务实际是由 dnsmasq 服务进程提供的,在 qdhcp-XXX namesapce 中会添加一个 DHCP 的端口(Tap 设备),这个 DHCP 端口连接到 br-int 上,具有与对应的租户网络相同的 Local VLAN tag(和租户网络 VID),以此实现为租户网络提供 DHCP 服务。
除此之外,还可以看见在 qrouter-XXX namesapce 中 br-int 和 br-ex 两个网桥设备通过 veth pair 设备 qr-XXX(quantum router) 和 qg-XXX(quantum gateway)连接到了一起。而且 qr-XXX 端口也具有租户网络对应的 Local VLAN tag。不同的租户网络通过不同的 Network Namesapce 实现了 Router 配置(路由表、iptables 规则)的隔离,启用 iptables 在 qrouter-XXX 中主要是提供 NAT 功能,支撑 Neutron 的 Floating IP 功能。
不同的租户具有不同的 qrouter-XXX 与 qdhcp-XXX 实例,所以不同租户间可以实现 IP 地址的复用。

在计算节点的网络模型章节中国我们介绍了虚拟机流量如何被送出计算节点,这里继续介绍虚拟机流量是如何被送出外部网络的:
Step 9. 物理网卡 ethX(OvS br-ethX/br-tun)从物理网络接收到从计算节点上虚拟机发出的外部网络访问流量,首先进行内外 VID 转换,然后通过 VETH Pair 设备传输到 OvS br-int。
NOTE:针对每一个租户网络在租户网络层上的 VID 肯定的一致的,而在不同(计算、网络)节点上的 Local VLAN ID 却未必一样,但这并不会导致不同租户网络间的数据包混乱,因为这一切都在 Open vSwitch 流表的掌握之中,我们暂且先对这个问题有个印象。
Step 10. 在网络节点上 OvS br-int 连接了不同的 Network namesapce,qrouter-XXX 通过 qr-XXX 端口接收到租户内跨网段访问流量以及公网访问流量。
Step 11. 最终由连接第二层网关并挂载到 br-ex 上的物理网卡 ethX 发出送至 Internet 路由器。
控制节点的网络实现模型就相对好理解很多了,因为控制节点不负责数据平面的问题,所以也没有实现具体的网络功能。我们需要关心的只是 neutron-server 这个服务进程。Neutron 没有显式(名为)的 neutron-api 服务进程,而是由 neutron-server 提供 Web Server 的服务。北向接收 REST API 请求,南向通过 RPC 协议转发各节点上的 Neutron Agent 服务进程,这就是 Neutron 在控制节点上的网络实现模型。
至此,我们介绍完了 Neutron 在分别计算、网络、控制节点上的网络实现模型,我们不妨回味一下这之间最重要的的设计思想 —— 分层。
让我们先抛开 OpenStack 和 Neutron,单纯的想象如何应用虚拟交换机实现跨主机间的虚拟机通信以及虚拟机访问外网的需求?答案其实很简单,如果应用 OvS,就会简单到只需要在每个节点上创建一个 Bridge(e.g. br-int)设备即可,无需 br-ex、br-ethX/br-tun、Linux Bridge 等等一大堆东西。e.g.
# Host1
ovs-vsctl add-br br-vxlan
# Host2
ovs-vsctl add-br br-vxlan
# Host1 上添加连接到 Host2 的 Tunnel Port
ovs-vsctl add-port br-vxlan tun0 -- set Interface tun0 type=vxlan options:remote_ip=<host2_ip>
# Host2 上添加连接到 Host1 的 Tunnel Port
ovs-vsctl add-port br-vxlan tun0 -- set Interface tun0 type=vxlan options:remote_ip=<host1_ip>
如果考虑到需要实现的是在「云平台上的多租户多平面网络」的话,那么事情就会变得相当复杂。一个有生命力的灵活的云平台,需要支持的网络类型实在是太多了,Neutron 至今仍在为之付出努力。在这样的条件下就急需设计出一个「上层抽象统一,下层异构兼容」的软件架构,而这种架构设计就是我们常说的 —— 分层架构设计。设计方案总是依赖于底层支撑选型,Neutron 网络实现模型的分层架构得益于 Open vSwitch(OpenFlow 交换机)的 Flow Table 定义功能。
OVN 提供的是一个轻量级控制器,提供了比 openvSwitch 更高层的抽象,与逻辑路由器和逻辑交换机而不是 flow 一起工作,实现了高层次的分布式交换机;这个轻量级不但体现在 OVN 本身的代码少(只有几个 C 语言文件,而且代码很少),模型简单(虽然简单但是很丰富,更懂得利用 OVS 本身的特性)而且它的流表设计(Pipeline)也容易理解。OVN 是一系列守护程序,它们将虚拟网络配置转换为 OpenFlow,并将其安装到 openvSwitch 中
。
对于Neutron来说,通过引入OVN,可以省去各种(L2, dhcp, l3, acl,qos)agent,简化系统复杂性,缩短网络路径,提高网络性能。
上图需要重新画一下