分布式路由

目录

  1. 典型场景
    1. 东西向
      1. 同一机器
      2. 不同机器
    2. 南北向
      1. 无floating IP
      2. 有floating IP
  2. 网络节点
  3. 计算节点
    1. 东西流量
    2. 南北流量
      1. 流表规则
        1. 所有对网关的arp request不能出到外部网络
        2. 所有发往网关的包也不能出到外部网络
        3. 所有从路由器接口路由出去的包,需要修改源mac为特殊mac
        4. 收到外部特殊源mac的包要修改为正确的路由器接口mac
        5. 其他
    3. 注意事项
  4. 配置
    1. Neutron Server
    2. L3 Agent
    3. L2 Agent
    4. 实现细节
      1. 添加路由器接口

OpenStack用户会发现,按照Neutron原先的设计,所有网络服务都在网络节点上进行,这意味着大量的流量和处理,给网络节点带来了很大的压力。这些处理的核心是路由器服务。任何需要跨子网的访问都需要路由器进行路由。

为了降低网络节点的负载,同时提高可扩展性,OpenStack自Juno版本开始正式引入了分布式路由(Distributed Virtual Router,DVR)特性(用户可以选择使用与否),来让计算节点自己来处理原先的大量的东西流量和非SNAT南北流量(有floating IP的vm和外面的通信)。

这样网络节点只需要处理一部分的SNAT(无floating IP的vm和外面的通信)流量,大大降低了负载和整个系统对网络节点的依赖。很自然的,FWaaS也可以放在计算节点上。

DHCP服务、VPN服务目前仍然需要集中在网络节点上进行。

典型场景

从网络的访问看,涉及到路由服务的至少是需要跨子网的访问,又包括是否是同一机器、是否是涉及到外网(东西向vs南北向)。

方向 同一机器 不同机器
东西 本地网桥处理 本地东西路由器
南北 本地南北路由器floating转发 网络节点SNAT转发

东西向

东西向意味着租户同一个数据中心内不同子网之间的相互访问。

同一机器

对于同一主机的不同子网之间访问,路由器直接在br-int上转发即可,不需要经过外部网桥。

不同机器

DVR

如图所示,租户T1的两台虚机VM1(计算节点1)和VM4(计算节点2)分别属于不同的子网,位于不同的计算节点。

VM1要访问VM4,由计算节点1上的IR1起到路由器功能。返程的网包,则由计算节点2上的路由器IR2起作用。两个路由器的ID、内部接口、功能等其实都是一样的。即同一个路由器,但是实际上在多个计算节点上同时存在。

VM1 -> BR-INT -> IR1 -> BR-INT -> BR-TUN(Node 1) -> BR-TUN(Node 2)-> VM4

这里可能有人会想到,多台同样的路由器,如果都暴露在外部网络上,会出现冲突。例如当VM1的请求包离开计算节点1时,带的源mac是路由器目标接口的mac,而这个mac在计算节点2上的路由器上同样存在。

因此,需要拦截路由器对外的暴露信息。一个是让每个路由器只应答本机的mac请求;另一个是绝对不让带着路由器mac地址的包直接扔出去。实现在br-int上进行拦截,修改其源mac为tunnel端口的mac。同样的,计算节点2在br-int上拦截源mac为这个tunnel端口的mac,替换为正常的子网网关的mac,直接扔给目标虚拟机所在的主机。

南北向

无floating IP

这种情况(即SNAT)下,跟传统模式很类似。外部访问内部子网。

DVR

租户T2在外部,通过默认的SNAT网关访问内部子网的VM1。此时,网络节点上的T2-SNAT起到路由器的作用。

外网 -> BR-EX(Network Node)-> T2-SNAT -> BR-INT -> BR-TUN -> BR-TUN(Node 1) -> BR-INT -> T2-VM1

DVR

反过来,租户T2内部子网的VM1试图访问外部网络,则仍然经过网络节点上的T2-SNAT路由器。

T2-VM1 -> BR-INT(Node1) -> IR2 -> BR-INT -> BR-TUN -> BR-TUN(Network Node) -> BR-INT -> T2-SNAT -> BR-EX -> 外网

为何这种情况下必须从网络节点走?

这是因为,对于外部网络来说,看到的都是外部接口的地址,这个地址只有一个。

当然,如果以后每个计算节点上都可以带有这样一个SNAT默认外部地址的话,这种情况下的流量也是可以直接从计算节点出去的。

有floating IP

DVR

这种情况下,计算节点上的专门负责的外部路由器将负责进行转发,即计算节点1上的IR2和计算节点2上的IR1。

T1-VM2 -> BR-INT -> IR2 -> Floating IP -> BR-EX -> 外网

T1-VM4 -> BR-INT -> IR2 -> Floating IP -> BR-EX -> 外网

网络节点

服务基本没变,除了L3服务需要配置为dvr_snat模式。

命名空间上会多一个专门的snat-xxx命名空间,处理来自计算节点的无floating IP的南北向流量。

计算节点

需要额外启用l3_agent(dvr模式),以及metadata agent。

其实,跟传统情况下的网络节点十分类似。每一个东西向路由器有自己的命名空间,负责跨子网的转发。另外,多一个floating路由器,专门负责经由floating地址的南北向转发。

东西流量

EAST-WEST

如上图所示,租户两个子网,红色和绿色,分别有VM1和VM2,位于节点CN1和CN2上。

VM1访问VM2的网包步骤如下,整个过程IP保持不变。

  1. 原始包,VM1访问VM2,目的mac为本地(红色子网)的路由器网关接口R1 Red mac。
  2. 经过BR-INT-CN1转发,该网包通过本地(红色子网)网关接口扔给本地路由器R1。
  3. R1根据路由规则,经过到绿色子网的接口发出,此时网包的源mac地址改为绿色子网的网关接口R1 Green mac,目的mac改为VM2 mac,并带上绿色子网的本地vlan tag。
  4. 网包发给BR-TUN-CN1进行Tunnel,扔出去之前,将源mac替换为跟节点相关的特定mac DVR CN1 mac,之后带着目标子网(绿色子网)的外部Tunnel id扔出去(实现可以为vlan、vxlan、gre等,功能都是一样的)。
  5. 节点CN2的网桥BR-TUN-CN2会从Tunnel收到这个包,解封包,并带上本地vlan tag,最终抵达网桥BR-INT-CN2。
  6. BR-INT-CN2上替换网包的源mac(此时为DVR-CN1-mac)为本地路由器的绿色子网网关接口,然后发给VM2。

南北流量

South-North

所不同的是,单独有一个qfloat-XXX路由器(也在一个独立命名空间中)来负责处理带有floating IP的南北向流量。

Floating-IP

流表规则

为了实现上面描述的功能需要下面几种流表规则。

所有对网关的arp request不能出到外部网络

在tunnel网桥上看到的一律丢弃。

1
2
3
DVR PROCESS Table 1 (New table for dvr):
table=1, prioity=4, dl_vlan=red1-L-vlan, dl_type=arp, ar_tpa=r1-red-ip actions:drop
table=1, prioity=4, dl_vlan=grn1-L-vlan, dl_type=arp, ar_tpa=r1-grn-ip actions:drop
所有发往网关的包也不能出到外部网络

在tunnel网桥上看到的一律丢弃。

1
2
3
DVR PROCESS Table 1 (New table for dvr):
table=1, prioity=2, dl_vlan=red2-L-vlan, dl_dst=r1-red-mac actions:drop
table=1, prioity=2, dl_vlan=grn2-L-vlan, dl_dst=r1-grn-mac actions:drop
所有从路由器接口路由出去的包,需要修改源mac为特殊mac

在tunnel网桥上进行处理。

1
2
3
DVR PROCESS Table 1 (New table for dvr):
table=1, prioity=2, dl_vlan=red2-L-vlan, dl_src=r1-red-mac actions:mod_dl_src=dvr-cn1-mac, resubmit(,2)
table=1, prioity=2, dl_vlan=grn2-L-vlan, dl_src=r1-grn-mac actions:mod_dl_src=dvr-cn1-mac, resubmit(,2)
收到外部特殊源mac的包要修改为正确的路由器接口mac

在intergration网桥上进行处理。

1
2
3
4
5
6
7
Table 0:(Local switching table)
table=0, priority=2, in_port=patch-tun, dl_src=dvr-cn1-mac actions:goto table 1
table=0, priority=1, actions:output->NORMAL

Table 1:(DVR_TO_LOCALMAC table)
table=1, priority=2, dl_vlan=grn2-L-vlan, nw_dst=grn-subnet actions:strip_vlan, mod_dl_src=r1-grn-MAC, output->port-vm2
table=1, priority=1 actions:drop
其他

采用L2 pre-population技术,提前把相关计算节点的地址关系放到本地的FDB表中,减少外部广播。

在integration网桥上,采用组表来调整规则顺序等。

1
2
Table 1:(DVR_TO_LOCALMAC table)
table=1, priority=2, dl_vlan=grn2-L-vlan, nw_dst=grn-subnet actions:strip_vlan, mod_dl_src=r1-grn-mac, output->port-vm2

注意事项

允许有个多个同样的网关存在于多个计算节点(同一个子网跨多个物理节点导致)的情况,保证:

  • 要让本地的请求找到本地的路由器;
  • 要避免路由器的接口mac地址直接暴露到外部网络上。

要解决这两个问题,首先是合理处理好本地的ARP请求,让本地对网关的请求拦截发给本地的路由器。
同时,路由器路由后的网包,发到外部网络之前,先用一个跟节点绑定的特殊mac替换掉源mac。这个mac地址是控制器为每一个计算节点单独分配的唯一地址。

配置

要启动DVR,比较简单,分别在各个节点的网络配置文件上做如下修改或添加。

Neutron Server

/etc/neutron/neutron.conf

1
router_distributed = True

L3 Agent

/etc/neutron/l3_agent.ini

1
agent_mode = [dvr_snat | dvr | legacy ]

网络节点上配置为dvr_snat,计算节点上配置为dvr。

L2 Agent

/etc/neutron/plugins/ml2/ml2_conf.ini

1
2
3
4
5
6
mechanism_drivers = openvswitch, linuxbridge, l2population

[agent]
l2_population = True
tunnel_types = vxlan
enable_distributed_routing = True

实现细节

添加路由器接口