OpenStack Neutron Dynamic Routing
如果你还不了解BGP,建议先看这篇BGP漫谈。
作为航空母舰的OpenStack怎么能没有BGP这个功能呢?这次来看看OpenStack里的BGP项目:neutron-dynamic-routing。
Neutron dynamic routing是由HPE工程师发起的项目,其实代码开始在neutron里面,后来才独立出去的。Neutron号称只处理2-3层的业务,BGP作为7层的协议,独立出去也符合Neutron的发展方向。
以上一篇BGP漫谈里面讲的小明的云4.0版本为案例来说明,小明有了自己的公网IP池,但这个也不是无限的,不可能给每个虚机都分配一个公网IP,这样太了。现实的数据中心中,通常只能有部分虚机有公网IP,大部分虚机都还是私网IP。例如在一个3层应用架构里面,之需要给web server分配公网IP,application server和DB server用私网IP就可以了,也更安全。
那问题又来了:
1. 小明的云中路由器如何区分公网IP和私网IP。具体来说,公网IP需要直接路由出去,而私网IP需要走NAT访问外网。
2. 小明的BGP服务怎么知道哪些IP可以广播出去,而哪些就算广播出去也没用(私网IP地址)。
为了解决这个问题,我们需要看一下Neutron的address scope。Neutron address scope是我在Neutron Mitaka版本参与完成的功能,我之前和HPE的工程师Carl Baldwin在Austin峰会讲过address scope。
因为Neutron address scope是基于Neutron subnetpool,所以先看看subnetpool。
Subnetpool
Subnetpool是一个逻辑的概念,在Subnetpool之前,Neutron中的subnet是由用户自己申请CIDR,对于CIDR没有一个统一的管理。这就导致,不同的租户申请的CIDR可能是重叠的,一旦重叠,那么租户的网络就不可能通过L3连接在一起。另外在其他的应用场合里面,也要求私网地址不能重叠,例如kuryr。所以kuryr也是基于Neutron subnetpool,这我在之前的文章里面也提过。
Subnetpool就是为了解决这个问题而诞生的,subnetpool预先分配好CIDR池,用户在创建subnet的时候,可以不用自己指定CIDR,而是指定subnetpool,然后subnetpool会给subnet 分配CIDR。通过subnetpool的统一分配,可以保证,一个subnetpool下的所有subnet,CIDR是且不重叠的。对应的也就有,一个subnetpool下面的所有网络端口,IP也是的。
相应的,在Neutron subnet中也新增了一个属性,subnetpool_id,用来表示当前subnet属于哪个subnetpool。Subnetpool与subnet是一对多的关系,并且一个Neutron network下的所有同一类subnet只可能属于一个subnetpool。这里说的同一类是指IPv4或者IPv6。
Address Scope
先看address scope跟subnetpool的关系。
Address scope与subnetpool的对应关系也是一对多。这说明subnetpool只能属于一个address scope,对应的在subnetpool中也新增了一个属性:address_scope_id。相应的Neutron network也新增了两个属性,ipv4_address_scope和ipv6_address_scope。与subnetpool相似,一个address scope内的subnetpool不允许CIDR地址重叠。也就是说,如果两个IP地址都来自一个address scope,那么它们肯定不相同。
不同于subnetpool的是,address scope不仅是一个逻辑功能,还是一个附加在L3上的实际的网络功能。具体的功能有:
这是一个隔离的功能,也就说如果两个网络不在一个address scope中,那么就算用router将它们连接在一起,它们之间还是不能互通。为什么要这么做?当你的address scope1里面的IP地址是公网IP,而address scope2的地址是私网IP,你肯定不想让私网IP通过路由器就能转发到公网IP。另一方面,你也不想让你的私网地址能都直接被公网地址访问。私网和公网之间应该是隔离的。
如果与router gateway在一个address scope内,那么租户网络地址在经过Neutron router时,不会做NAT,而是直接路由出去。相反,如果不在同一个address scope,那么租户网络还是通过NAT访问外网。这是不是就解决了前面提出的个问题,在路由器上区分公网IP和私网IP。只需要给公网IP和私网IP指定相应的address scope,那么Neutron router就能区分它们,并且分别执行相应的动作。
为了不影响使用和向前兼容,我们在实现的时候,对于所有未指定address scope的network和subnetpool,都认为属于no scope。在no scope下,CIDR是可以重叠的,且在L3也没有特殊功能(东西向都互通,南北向都走NAT)。也就是说不使用address scope,是感觉不到它的存在的。
Neutron dynamic routing
前面解决了一个问题,那再来看第二个问题,Neutron的BGP服务怎么知道哪些地址是可以通过BGP广播出去的?其实也很明显了。只有跟外网在一个address scope的地址,且这些网络连接到了路由器,才会被广播出去。
为什么需要跟外网在一个address scope,因为address scope确保了IP地址不重叠,这些CIDR是可以安全的广播出来,另一个方面不同的address scope之间做了隔离,这些CIDR广播出来也不会造成安全问题。
为什么需要连接到路由器的网络地址才会被广播?因为只有连接到路由器的地址才有可能被访问到啊。否则就是在一个二层网络里面了。
上图中,也就是与provider network在同一个address scope内的三个浅蓝色的self-service network会被Neutron BGP广播出去。而浅绿色的那个网络还是通过NAT,借助router gateway访问外网。
具体使用
有了前面的介绍,再来介绍Neutron dynamic routing的使用,就简单多了。接下来都是基于neutron的官方文档来描述。
先是创建address scope和subnetpool,把self-service network 和provider network都创建在address scope下。这里不再说私网,公网了,而是说self-service network 和provider network。self-service network就是给云上的虚拟机使用的网络,可以是私网地址,也可以是外网地址,provider network映射物理网络,在BGP的环境下,必须是外网地址。当self-service network创建在与provider network在同一个address scope下时,可以认为self-service里的也是外网地址。
然后将self-service network 和provider network都加到Neutron router上。self-service network作为router interface接入,provider network作为router gateway接入。
之后创建BGP speaker,这里的BGP
speaker可以看成是前一篇BGP漫谈里面的BGP router。
$ neutron bgp-speaker-create --ip-version 4 --local-as LOCAL_AS bgpspeaker
这里指定的local-as就是BGP router所在的AS分配到的编号。
BGP router该广播哪些本地路由,这个是需要指定的。Quagga可以通过静态配置文件来指定需要广播的路由,而对于OpenStack来说,是通过将BGP speaker与provider network关联来指定需要广播的路由。这之间是什么关系?
一旦BGP speaker与provider
network关联了,Neutron会查找所有连接到provider
network的router,进而查找连接到这些router上的,且与provider network在同一个address scope下的self-service network,这些self-service network就是需要被广播的对象。这比静态指定方便多了。可以通过以下命令查看当前BGP speaker具体会广播哪些路由。
$ neutron bgp-speaker-advertiseroute-list bgpspeaker
再之后,创建一个BGP peer。这里的BGP peer是对端BGP router的信息。指定peer-ip,以供BGP连接使用,而remote-as是对端的AS编号。创建完之后,将BGP peer与BGP speaker关联。注意,一个BGP speaker可以关联多个BGP peer。
$ neutron bgp-peer-create --peer-ip 192.0.2.1 --remote-as REMOTE_AS bgppeer
到此为止,BGP还只是Neutron的一个逻辑概念,不能工作。需要将BGP speaker指定到BGP agent。制定完成之后,由BGP agent管理实际的BGP进程。而此时,BGP speaker已经可以向对端发送路由信息了。具体的过程在上一篇也简单说过。
总的来看,一个OpenStack网络的路由信息是以这样的结构广播出去的。
实际中,对DVR在广播floatingip时会有些不同。不过整体思路没有变。
Neutron dynamic routing目前只支持向外广播路由信息,不支持接收外部路由信息并应用到本地或者再转发出去。也就是说BGP功能支持的不是很完善。底层BGP协议的实现,目前也只有基于RYU一种实现。不过因为是个开源项目,任何人都可以去完善这些功能。
相关文章