下面对Openstack和Neutron的介绍,要从几个关键词入手。
1. 三代网络
在网络这一口,OpenStack经历了由nova-network到Quantum再到Neutron的演进过程。我们直观地来看看三代网络的对比分析:
1)Nova-network是隶属于nova项目的网络实现,它利用了linux-bridge(早期,目前也支持OVS)作为交换机,具备Flat、Flat DHCP、VLAN三种组网模式。优点是性能出色,工作稳定,支持multi-host部署以实现HA;缺点是网络模块不独立,功能不够灵活,组网模式也比较受限。
2)Quantum作为独立的网络管理项目出现在F版本,除了linux-bridge外还支持OVS,以及以及其他商业公司的插件,组网模式上增加了对GRE和VxLAN两个Overlay技术的支持。优点是功能灵活,支持大二层组网;缺点是集中式的网络节点缺乏HA,而且各厂商插件无法同时在底层网络中运行。
3)Neutron出现在H版本,由来是Quantum和一家公司的名称冲突而改名。Neutron对Quantum的插件机制进行了优化,将各个厂商L2插件中独立的数据库实现提取出来,作为公共的ML2插件存储租户的业务需求,使得厂商可以专注于L2设备驱动的实现,而ML2作为总控可以协调多厂商L2设备共同运行。Neutron继承了Quantum对大二层的支持,还支持L2 PoP,DVR,VRRP,HA等关键功能,集成了很多L4-L7的网络服务,一些blueprint也正在积极开发中,如SFC等。优点是开始引入SDN思想,功能上更为丰富,网络兼容性强;缺点是代码结构复杂,工作不够稳定,HA机制仍缺乏大规模商用的检验。
从应用场景来看,Nova-network组网模式过于简单,一些复杂的网络需求无法实现(比如两个公司合并,有大量IP重合的VM要迁移到一个平台,而且要求迁移后都要用原来的IP)。不过由于其简单稳定的特点,仍适合于中小型企业的生产环境;Quantum的实际部署目前基本都跟进到了Neutron;Neutron的大二层组网,适合于云计算规模的生产环境,但是由于分布式和HA机制仍不够成熟,因此目前多见于私有云和小规模共有云的部署,大规模的公有云仍然难以使用Neutron实现。
2. 四种组网模型
说完了基本特征与应用场景,下面开始对上述提到的一些网络问题进行详细的描述。我们抛开技术,结合图例来抽象地看看不同的组网模型。当然,以下模型的实现不仅仅局限于三张图中的方式。
1)Flat模型最为简单,所有的虚拟机共用一个私有IP网段,IP地址在虚拟机启动时完成注入,虚拟机间的通信直接通过HyperVisor中的网桥转发,公网流量在该网段的网关上进行NAT(Nova-network实现为开启nova-network主机内核的iptables,Neutron实现为网络节点上的l3-agent)。Flat DHCP模型与Flat区别在于网桥中开启了DHCP进程,虚拟机通过DHCP消息获得IP地址(Nova-network实现为nova-network主机中的dnsmaq,Neutron实现为网络节点上的dhcp-agent)。
2)VLAN模型引入了多租户机制,虚拟机可以使用不同的私有IP网段,一个租户可以拥有多个IP网段。虚拟机IP通过DHCP消息获取IP地址(Nova-network实现为nova-network主机中的dnsmaq,Neutron实现为网络节点上的dhcp-agent)。网段内部虚拟机间的通信直接通过HyperVisor中的网桥转发,同一租户跨网段通信通过网关路由,不同租户通过网关上的ACL进行隔离,公网流量在该网段的网关上进行NAT(Nova-network实现为开启nova-network主机内核的iptables,Neutron实现为网络节点上的l3-agent)。如果不同租户逻辑上共用一个网关,则无法实现租户间IP地址的复用。
3)Overlay模型(主要包括GRE和VxlAN隧道技术),相比于VLAN模型有以下改进。1)租户数量从4K增加到16million;2)租户内部通信可以跨越任意IP网络,支持虚拟机任意迁移;3)一般来说每个租户逻辑上都有一个网关实例,IP地址可以在租户间进行复用;4)能够结合SDN技术对流量进行优化。
3. 三类节点和三类网络
看过抽象的组网模型,下面我们来介绍组网具体的实现技术。下面的介绍都是针对Neutron的,对nova-network和Quantum将不做讨论。
1)3类节点——管理节点:实现镜像、块存储、身份认证、前端等服务,运行nova-compute的调度模块以及nova api-server;计算节点:实现nova-compute,以及neutron的各种agent(一般不包括l3-agent,DVR除外);网络节点,:实现neutron各种agent。注意,由于OpenStack为分布式架构实现,因此neutron-server既可以运行在控制节点,也可以运行在网络节点。
2)3种网络——OpenStack内部模块之间的交互发生在管理网络,虚拟机之间的通信发生在数据网络,而External Network/API Network网络是连接外网的,无论是用户调用Openstack API,还是虚拟机与外网间的互通都需要经过这个网络。
目前OpenStack通常采用out-of-bound方式进行部署,管理网络与另外两个网络是独立的,管理节点上一般也不会承载Openstack的业务流量,下面的分析中网络只涉及数据网络与External Network/API Network网络,节点只涉及计算节点和网络节点。
4. 两张图例
有了以上知识作为基础,就可以来分析Openstack中的网络通信了。由于OpenStack中容器的通信机制目前尚不成熟,并且有专门的项目Kuryr去实现容器相关网络技术,以下内容将不涉及OpenStack中的容器通信。
以下将通过两张图来分析Neutron中的VLAN组网模型,HyperVisor中的网络设备以OpenvSwitch为例。这三张图中每一个信息都是有用的,把这些信息完全弄懂了,Neutron的组网也就能基本掌握了,Overlay模型与VLAN模型的区别只在于将图中的br-eth1替换成br-tun即可,具体隧道如何进行封装,稍后我们再详细介绍。
第一张图是计算节点上的网络实现。以虚拟机发出流量方向为例,从虚拟机处开始分析:
1)流量经由虚拟机IP内核交给虚拟网卡处理,虚拟网卡由TAP软件实现,TAP允许用户态程序向内核协议栈注入数据,它可以运行于虚拟机操作系统之上,能够提供与硬件以太网卡完全相同的功能。
2)TAP设备并不是直接连接到OVS上的,而是通过linux bridge中继到ovs br-int上,其原因在于ovs无法实现linux bridge中一些带状态的iptables规则,而这些规则往往用于以虚拟机为单位的安全组(security group)功能的实现。qbr是quantum bridge的缩写,Neutron中沿用了Quantum的叫法。
3)linux bridge与ovs br int间的连接通过veth-pair技术实现,qvb代表quantum veth bridge,qvo代表quantum veth ovs。veth-pair用于连接两个虚拟网络设备,总是成对出现以模拟虚拟设备间的数据收发,其原理是反转通讯数据的方向,需要发送的数据会被转换成需要收到的数据重新送入内核网络层进行处理。veth-pair与tap的区别可以简单理解为veth-pair是软件模拟的网线,而tap是软件模拟的网卡。
4)ovs br-int是计算节点本地的虚拟交换设备,根据neutron-server中OVS Plugin的指导,完成流量在本地的处理:本地虚拟机送入的流量被标记本地VLAN tag,送到本地虚拟机的流量被去掉本地VLAN tag,本地虚拟机间的2层流量直接在本地转发,本地虚拟机到远端虚拟机、网关的流量由int-br-eth1送到ovs br-eth1上(在Overlay模型中送到ovs br-tun上)。注意,无论是VLAN模型还是Overlay模型,由于br-int上VLAN数量的限制,计算节点本地最多支持4K的租户。
5)ovs br-int与ovs br-eth1间的连接通过veth-pair技术实现。
6)ovs br-eth1将该计算节点与其他计算节点、网络节点连接起来,根据neutron-server中OVS Plugin的指导,完成流量送出、送入本地前的处理:根据底层物理网络租户VLAN与本地租户VLAN间的映射关系进行VLAN ID的转换(Overlay模型中此处进行隧道封装,并进行VNI与本地租户VLAN ID间的映射)。由于底层物理网络中VLAN数量的限制,VLAN模型最多支持4K的租户,而Overlay模型中,24位的VNI最多支持16million的租户。
7)ovs br-eth1直接关联物理宿主机的硬件网卡eth1,通过eth1将数据包送到物理网络中。Overlay模型中ovs br-tun通过TUN设备对数据包进行外层隧道封装并送到HyperVisor内核中,内核根据外层IP地址进行选路,从硬件网卡eth1将数据包送到物理网络中。TUN与TAP的实现机制类似,区别在于TAP工作在二层,而TUN工作在三层。
第二张图是网络节点上的网络实现,以流量流入网络节点方向为例,从底层物理网络流量通过eth1进入ovs br-eth1(Overlay模型中为ovs br-tun)开始分析:
1)ovs br-eth1将网络节点与计算节点连接起来,根据neutron-server中OVS Plugin的指导,完成流量送入网络节点前的处理:根据底层物理网络租户VLAN与本地租户VLAN间的映射关系进行VLAN ID的转换(Overlay模型中此处进行解封装,并进行VNI与本地租户VLAN ID间的映射)。注意,虽然同一租户在底层物理网络上的VLAN ID(Overlay模型中为VNI)唯一,但是在网络节点与计算节点,不同计算节点中同一租户对应的本地VLAN ID可能有所不同。另外由于网络节点也要在ovs br-int上使用本地VLAN,而租户跨网段流量与公网流量都要经过网络节点,因此使用单个网络节点时,Neutron最多能支持4K租户,可采用部署多个网络节点的方式来解决这一问题。
2)送入网络节点的流量,由ovs br-eth1(ovs br-tun)通过veth-pair送给ovs br-int,ovs br-int连接了本地不同的namespace,包括实现dhcp功能的dhcp-agent——dnsmasq,以及实现路由功能的l3-agent——router。Dnsmasq负责给对应租户的虚拟机分配IP地址,而router负责处理租户内跨网段流量以及公网流量。不同的租户有不同的dnsmasq和router实例,因此不同租户间可以实现IP地址的复用。
3)Router namesapce通过qr接口(Quantum Router)接收到租户内跨网段流量以及公网流量,在ns的IP内核中对跨网段流量进行路由,改写MAC地址并通过相应的qr接口向ovs br-int送出数据包。在ns的IP内核中对公网流量进行NAT,并通过qg接口(Quantum Gateway)发送给ovs br-ex。
4)Ovs br-ex通过关物理联宿主机的硬件网卡eth1将流量送至Internet路由器。
5)上述两幅图中,ovs br-int与ovs br-ex间有直连,据说主要是防止l3-agent出现问题时能够保证流量不中断,但实际上看来很少出现此问题。
**5. Neutron网络全家福
**
上图是在网上看过的更加细致,更为全面的一张图(http://blog.csdn.net/canxinghen/article/details/46761591#comments),图中清晰地展示了Neutron对多种L2技术(VLAN、VxLAN、GRE)共同运行的支持。图中的mellonax是intel等硬件厂商搞出的具备转发功能的网卡,能够避免虚拟交换机带来的资源消耗,并能够加快转发速率。一块这样的网卡能虚拟出63个VF,每个VF就好像一个独立的物理网卡一样,通过将VF直接挂到虚拟机上,能够实现转发性能的大幅度提高。
以上介绍了OpenStack中网络组件的演进,以及Neutron组网的基本原理。下面我们将对Neutron的软件实现进行简单的介绍。
二、Nova虚拟机启动时的网络处理
设备启动了,网络有了,可是现在还没有虚拟机。下面我们来看看nova虚拟机启动时的网络处理过程。
从头开始讲。虚拟机的启动通常来自于控制节点命令行的nova boot,该命令被组装成REST API送到nova-api。Nova-api与neutron-server干的是一样的活:接收REST请求,调nova-scheduler跑一些调度机制,计算出虚拟机部署的位置,然后通过rpc与相应计算节点上的agent——nova-compute进行通信,而启动虚拟机的实际工作由nova-compute完成。
当然,以上过程与网络并没有发生什么关系,这里不做深入分析,大家要是有兴趣可参考http://www.linuxqq.net/archives/1277.html。
假定nova-compute已经通过rpc收到了开始干活的命令,我们就从这里开始漫长的代码分析。在此之前,先来看一看OpenStack组件层面的调用流程。这里借用OpenStack大神SammyLiu的一张图吧,图中1-6步骤依次做了这么几件事:
1)Nova-compute向neutron-server请求虚拟机对应的Port资源。
2)Neutron-server根据neutron-database生成Port资源。
3)Neutron-server通知Dhcp agent虚拟机信息。
4)Dhcp agent将虚拟机信息通知给dhcp server。
5)虚拟机接入并启动。
6)虚拟机从dhcp server处获得IP地址。
最后一步就是传统的dhcp的交互过程,这里就不讲了,下面来看1-5的实现。时间有限,代码不再一步步回溯了,详见SDNLAB“网络虚拟化”专题的后续文章,这里给出代码的主体思路。
1)Nova-compute向neutron-server发送create_port的REST API请求,生成新的Port资源。
2)Neutron-server收到该REST请求,通过APIRouter路由到ML2的create_port方法。该方法中,获得了neutron-database新生成的Port,并通知ML2 Mechanism Driver该Port的生成。
3)Nova-compute向neutron发送update_port的REST API请求,
4)Neutron-server收到该REST请求,通过APIRouter路由到ML2的update_port方法。该方法中,在neutron-database更新该Port的状态,并根据ML2 Mechanism Driver的不同,决定后续的处理:若Mechanism Driver为hyperv/linuxbridge/ofagent/openvswitch,则需要通过ML2的update_port方法中执行rpc远程调用update_port;对于其余的Mechanism Driver,ML2的update_port方法调用其的update_port_postcommit方法进行处理,这些Mechanism Driver可能使用非rpc方式与自身的agent通信(如REST API、Netconf等)。
5)ML2执行完update_port方法后,Port资源在wsgi中对应的Controller实例通过DhcpAgentNotifyAPI实例rpc通知给网络节点上的dhcp agent(也可能通过一些调度机制通知给分布在计算节点上的dhcp agent)。
6)Dhcp agent收到该rpc通知,通过call_driver方法将虚拟机MAC与IP的绑定关系传递给本地的DHCP守护进程Dnsmaq。
7)Nova-compute通过libvirt driver的spawn方法将虚拟机接入网络,然后启动虚拟机。
到这里,虚拟机启动过程中的网络处理就都结束了,虚拟机间就可以开始通信了。下面开始介绍Neutron中OVS的流表逻辑,看看OVS是怎么支持虚拟机间的通信的。
三、Neutron的软件实现
5. 5类Neutron组件
在架构设计上, Neutron沿用了OpenStack完全分布式的思想,各组件之间通过消息机制进行通信,使得Neutron中各个组件甚至各个进程都可以运行在任意的节点上,如下图所示。这种微内核的架构使得开发者可以集中精力在网络业务的实现上。目前Neutron提供了众多的插件与驱动,基本上可以满足各种部署的需要,如果这些还难以支撑实际所需的环境,则可以方便地在Neutron的框架下扩展插件或驱动。
1)Neutron-server可以理解为一个专门用来接收Neutron REST API调用的服务器,然后负责将不同的rest api分发到不同的neutron-plugin上。
2)Neutron-plugin可以理解为不同网络功能实现的入口,各个厂商可以开发自己的plugin。Neutron-plugin接收neutron-server分发过来的REST API,向neutron database完成一些信息的注册,然后将具体要执行的业务操作和参数通知给自身对应的neutron agent。
3)Neutron-agent可以直观地理解为neutron-plugin在设备上的代理,接收相应的neutron-plugin通知的业务操作和参数,并转换为具体的设备级操作,以指导设备的动作。当设备本地发生问题时,neutron-agent会将情况通知给neutron-plugin。
4)Neutron database,顾名思义就是Neutron的数据库,一些业务相关的参数都存在这里。
5)Network provider,即为实际执行功能的网络设备,一般为虚拟交换机(OVS或者Linux Bridge)。
6 两类Plugin
1)Core-plugin,Neutron中即为ML2(Modular Layer 2),负责管理L2的网络连接。ML2中主要包括network、subnet、port三类核心资源,对三类资源进行操作的REST API被neutron-server看作Core API,由Neutron原生支持。其中:
2)Service-plugin,即为除core-plugin以外其它的plugin,包括l3 router、firewall、loadbalancer、VPN、metering等等,主要实现L3-L7的网络服务。这些plugin要操作的资源比较丰富,对这些资源进行操作的REST API被neutron-server看作Extension API,需要厂家自行进行扩展。
最开始曾经提到,“Neutron对Quantum的插件机制进行了优化,将各个厂商L2插件中独立的数据库实现提取出来,作为公共的ML2插件存储租户的业务需求,使得厂商可以专注于L2设备驱动的实现,而ML2作为总控可以协调多厂商L2设备共同运行”。在Quantum中,厂家都是开发各自的Service-plugin,不能兼容而且开发重复度很高,于是在Neutron中就为设计了ML2机制,使得各厂家的L2插件完全变成了可插拔的,方便了L2中network资源扩展与使用。
ML2作为L2的总控,其实现包括Type和Mechanism两部分,每部分又分为Manager和Driver。Type指的是L2网络的类型(如Flat、VLAN、VxLAN等),与厂家实现无关。Mechanism则是各个厂家自己设备机制的实现,如下图所示。当然有ML2,对应的就可以有ML3,不过在Neutron中L3的实现只负责路由的功能,传统路由器中的其他功能(如Firewalls、LB、VPN)都被独立出来实现了,因此暂时还没有看到对ML3的实际需求。
===================== 代码分析 =========================
一般而言,neutron-server和各neutron-plugin部署在控制节点或者网络节点上,而neutron agent则部署在网络节点上和计算节点上。我们先来简单地分析控制端neutron-server和neutron-plugin的工作,然后再分析设备端neutron-agent的工作。
具体的代码这次分享没有时间讲了,只能讲个大致的轮廓和思路。有兴趣深入研究的同志,可以关注SDNLAB上“网络虚拟化”专题的后续更新。
(注意,以前厂商开发的L2 plugin跟ML2都存在于neutron/plugins目录下,而可插拔的ML2设备驱动则存在于neutron/plugins/ml2/drivers目录下)
**1. 控制端的实现
**
从neutron-server的启动开始说起。neutron-server的启动入口在neutron.server.__init__中,主函数中主要就干了两件事,第一是下图l 48处启动wsgi服务器监听Neutron REST API,第二是在l 52启动rpc服务,用于core plugin与agent间的通信,两类服务作为绿色线程并发运行。从SDN的角度来看,wsgi负责Neutron的北向接口,而Neutron的南向通信机制主要依赖于rpc来实现(当然,不同厂家的plugin可能有其它的南向通信机制)。
1)北向方面,Neutron的wsgi通过Paste工具进行模板化部署,它接收Neutron REST API的业务请求,然后通过APIRouter将其分发给对应的plugin。
2)Neutron内部,plugin与数据库交互,获取业务的全局参数,然后通过rpc机制将操作与参数传给设备上的Agent(某些plugin和ML2 Mechanism Driver通过别的方式与Agent通信,比如REST API、NETCONF等)。
3)RPC机制就可以理解为Neutron的南向通信机制,Neutron的RPC实现基于AMPQ模型,plugins和agents之间通常采用“发布——订阅”模式传递消息,agents收到相应plugins的NotifyApi后,会回调设备本地的CallBack来操作设备,完成业务的底层部署。
2. 设备端的实现
控制端neutron-server通过wsgi接收北向REST API请求,neutron-plugin通过rpc与设备端进行南向通信。设备端agent则向上通过rpc与控制端进行通信,向下则直接在本地对网络设备进行配置。Neutron-agent的实现很多,彼此之间也没什么共性的地方,下面选取比较具有代表性的ovs-neutron-agent的实现进行简单的介绍。
Ovs-neutron-agent的启动入口为/neutron/plugins/openvswitch/agent/ovs-neutron-agent.py中的main方法,其中负责干活的两行代码在l 1471和l 1476。L 1471实例化了OVSNeutronAgent类,负责在本地配置OVS,而l 1476则启动了与控制端的rpc通信。
OVSNeutronAgent的实例化过程中依次干了6个工作:启动ovs br-int网桥;启动rpc;启动ovs br-eth1;启动ovs br-tun;实例化OVSSecurityGroupAgent;开始rpc轮询与监听。
rpc_loop做的工作主要就是轮询一些状态,根据这些状态,进行相应的操作。比如一旦探测到本地的OVS重启了(l 1295,l 1309),就重新创建本地的网桥(l 1294-1300),并重新添加port(l 1336);再比如一旦rpc监听到update_port事件(l 1309),则在本地使能相应的port(l 1336)。
ovs-neutron-agent的启动也就是这些工作了,启动完毕后,便开始了与相应plugin(OVS Plugin或者OVS Mechanism Driver)的rpc通信。
================= 代码分析 ====================
Neutron的软件实现就简单地介绍到这里了,下一节我们来具体看看Neutron中各个OVS上的流表逻辑是怎样的。
**四、Neutron OVS上的流表分析
**
在具体介绍OVS的工作机制之前,大家要先理解OVS并不是Neutron网络实现的唯一选择。
实际上,Neutron中底层网络的实现千差万别:有的agent本地是真正处理数据流的网络设备(OVS,Router,LoadBalancer等),而有的agent本地是SDN控制器(如ODL、ONOS、OpenContrail、NSX等)。上述Neutron底层网络的两种模型示意如下。
第一种模型中Neutron相当于SDN控制器,plugin与agent间的通信机制(如rpc)就相当于简单的南向协议。第二种模型中Neutron作为SDN应用,将业务需求告知SDN控制器,SDN控制器再通过五花八门的南向协议远程控制网络设备。当然,第二种模型中也可以把Neutron看做超级控制器或者网络编排器,去完成OpenStack中网络业务的集中分发。
以下我们讲的是第一种模型中OVS处理数据流的工作机制。后一种模型中,SDN控制器也可以通过OpenFlow或者OVSDB来控制OVS处理数据流,对此本节暂时不进行讨论,后续也会有文章会详细介绍ODL和ONOS等SDN控制器对Openstack的支持。
================== 分隔线 ======================
以Overlay组网模型对OVS的工作机制进行介绍,具体分为两个角度:OVS实现L2的基本连接,OVS对连接机制的优化。
**(一)L2基本连接的实现
**
复原一下通信场景,其中的网络基础请参考“OpenStack网络基础”一小节。图中某租户有两个网段,分别用橙红色和蓝色表示,网段间的互通要经过网络节点中的Router,网段内的通信不需要经过网络节点中的Router。网段间的互通可分为3步:橙红色网段通过网段内通信找到Router,Router进行路由,Router通过蓝色网段的网段内通信转发给目的地。Router上的路由是linux内核实现的,我们不去关心,因此可以说租户内部通信都是基于网段内通信实现的。
Overlay模型中,网段内通信涉及ovs br-int和ovs br-tun,计算节点和网络节点中两类网桥的实现没有什么区别。概括地说,br-int负责在节点本地的网段内通信,br-tun则负责节点间的网段内通信。
在本节的场景内br-int实现为普通的二层交换机,即完成VLAN标签的增删和正常的二层自学习与转发,没有必要进行过多的解释,其代码实现请参考“Neutron的软件实现”中agent部分。
Br-tun采用多级流表实现节点间的网段内通信,下面直接通过图示来看br-tun中多级流表的设计。图中流表的序号不是固定的,可在neutron.plugins.openvswitch.agent.common目录下的constants.py文件中修改。
所有流经br-tun的数据包首先进入Table 0进行处理。Table 0对数据包的来源进行判断,从与br-int相连的patch-int进入的数据包交给Table 1处理,从GRE或者VxLAN端口(不同节点间的隧道有不同的Port_ID)进入的分别交给Table 2、Table 3处理。Table 1根据数据包目的MAC地址判断是否为单播,是则送往Table 20,否则送往Table 21,Table 20根据(VLAN_ID,MAC)到(PORT_ID,TUNNEL_ID)的映射关系将单播包送到特定的隧道,Table 21将非单播包复制后送到所有隧道。进入Table 2或者Table 3的数据包,首先判断TUNNE_ID是否合法,是则添加本地VLAN_ID并送往Table 10,否则丢弃。Table 10记录数据包的VLAN_ID,MAC、入端口以及TUNNEL_ID,将(VLAN_ID,MAC)到(PORT_ID,TUNNEL_ID)的映射关系写入Table 20,然后将数据包从与br-int相连的patch-int送出。
可见,上述过程就是标准MAC自学习在隧道中的扩展,无非就是将(VLAN_ID,MAC)到PORT_ID的映射变为了(VLAN_ID,MAC)到(PORT_ID,TUNNEL_ID)的映射。这种自学习仍然要依赖于泛洪来完成,引入l2_population或者SDN控制器后可以避免掉泛洪。
(二)连接机制的优化
OVS上,连接机制的优化主要体现在l2_population机制,以及对DVR(Distributed Virtual Router,分布式L3-agent)的支持。
2.1 L2_population
虚拟机在通信前,会发送ARP请求去解析目的MAC与目的IP间的映射关系,这一过程需要发送二层的广播包。由(一)中的介绍可知,这会导致隧道上的泛洪,这显然是不能令人满意的。
传统网络中ARP依赖于广播泛洪的原因在于没有一个集中式的控制平面,而Neutron中的数据库存有所有虚拟机MAC地址与IP地址间的映射,可以说是一个天然原生的控制平面。因此有人提出了将该映射关系注入到OVS本地,在本地处理ARP广播,以避免隧道上的泛洪,这就是l2_population。
L2_population的实现并不复杂,就是在1介绍的流水线中增加一个ARP Table去处理ARP Request。ARP Table中会事先存好MAC与IP的映射关系,如果ARP Table中匹配ARP Request消息中的目的IP,则构造一个 ARP 响应包,从ARP Request的入端口返回给虚拟机。如果匹配失败,则跳转到 Table 21继续泛洪。上述过程如下图所示,之所以保留ARP Table到Table 21的跳转,主要是为了防止l2_population出现问题。
L2_population的工作就是这么简单,却可以大大减少不合意的隧道泛洪。其实dhcp也存在类似的问题,如果只在网络节点上放置dhcp-server,那么所有的DHCP DISCOVER消息都要靠隧道泛洪发送到网络节点上。当然,dhcp消息的数量和产生频率远远赶不上arp,问题也不会那么明显。
解决dhcp存在的上述问题,一种思路是在Table 21上专门写一条高优先级的dhcp流表项去匹配dhcp广播消息,并将所有的dhcp消息都封装送到网络节点的隧道。另外,也可以采用类似于l2_population的思路,从Table 1上专门写一条高优先级的dhcp流表项去匹配dhcp消息,这条流表项只需要将dhcp消息通过相应的端口转交给dhcp namespace即可。之所以用namespace实现,是因为Dhcp消息封装在应用层,OpenFlow流表无法直接支持dhcp消息的封装,因此这个活得由分布在计算节点上的dhcp namespace来完成。
第一种思路优点是实现简单,但是一旦网络节点发生单点故障,虚拟机便无法正常使用dhcp获取IP,不过kilo版本中已经有人在多个网络节点中实现了dhcp_loadbalance(https://blueprints.launchpad.net/neutron/+spec/dhcpservice-loadbalancing)。第二种思路实现复杂一些,但能够避免网络节点单点故障带来的问题,实现分布式dhcp。
2.2 DVR
上一小节简略地提到了分布式的dhcp,这个工作社区有人提过但是反响并不是很大,而分布式的路由(Distributed Virtual Routing)却很早就成为了社区的共识,并在Juno版本中给出了实现。
Neutron中Router用来实现同一租户不同网段的虚拟机间的通信,这属于东西向流量,具体可以分为两种:1. 同一个物理节点上不同网段内的虚机之间的通信;2. 不同物理节点上不同网段内的虚机之间的通信。Router还用来实现虚拟机与Internet间的流量,这属于南北向流量,具体也可分为两种:1. 虚拟机访问Internet的流量,通常需要经过SNAT处理;2. Internet访问虚拟机的流量,可能需要经过DNAT处理。
在Neutron较早的版本中,上述流量都需要通过经过网络节点上的Router来处理,一旦网络节点故障或者网络节点上的Router挂掉了,上述类型的流量也就都丢掉了。解决这一问题也有很多种思路:
1)一种是通过部署多个网络节点,在多个网络节点间做调度的,不过这种很难实现各个Router本身状态的一致性。
2)于是,就有了通过在Router间跑应用层面的VRRP来同步Router状态,这种方式是很不错的,VRRP协议也比较成熟。但是问题在于,大部分流量仍然需要“绕弯子”进行传输,如同一个物理节点上不同网段内的虚机之间的通信可能需要到另一个物理节点的Router上处理。
3)再于是,DVR就出现了,通过把Router分布在各个计算节点中,各类流量都可以得到最优的处理,也不会再有单点故障的问题了。
接下来对DVR的讲解发生在下图的场景中:某租户有红、绿两个网段,两台虚拟机vm1、vm2分属两个网段,分别位于计算节点CN1、CN2,租户拥有一个DVR路由器r1,分布在两个计算节点之上。假定vm1已经通过ARP获得了CN 1中r1在红色网段接口的MAC地址r1 red mac,现在vm1发起向vm2的ping request。
抛开流表的格式与下发的过程,先按照图中序号来看一看DVR流表下发后通信各个阶段的数据包特征。这里规定(源MAC,目的MAC,源IP,目的IP地址)为数据包的特征4元组。
1)vm1发出的ping包特征为(vm1 mac, r1 red mac, vm1 ip, vm2 ip),该数据包送至br-int-cn1。
2)br-int-cn1在之前ARP过程中学到了r1 red mac所在端口,将ping包直接转发给CN1中的r1。
3)r1进行路由,得知目的虚拟机连接在绿色网段上,而且r1中存有目的虚拟机的静态ARP表项,不需要进行ARP解析。于是CN1中的r1通过其绿色网段接口将ping包重新送回br-int-cn1。此时ping包特征为(r1 grn mac, vm2 mac, vm1 ip, vm2 ip),br-int-cn1还不知道vm2连在哪里,进行泛洪。
4)br-tun-cn1由br-int-cn1收到ping包,将源mac地址修改为全局唯一的dvr cn1 mac,并封装好隧道,标记绿色网段的TUNNEL_ID,直接送往CN2。此时ping包被封装在外层包头内,其特征为(dvr cn1 mac, vm2 mac, vm1 ip, vm2 ip)。
5)br-tun-cn2收到后去掉外层包头,打上绿色网段的本地VLAN标签,送给br-int-cn2,此时ping包特征仍为(dvr cn1 mac, vm2 mac, vm1 ip, vm2 ip)。
6)br-int-cn2识别出这是CN1经过绿色网段送过来的流量,于是将源mac地址改回r1 grn mac并剥掉VLAN标签。br-int-cn2还不知道vm2连在哪里,就将ping包泛洪。此时ping包特征为(r1 grn mac, vm2 mac, vm1 ip, vm2 ip)。
7)vm2收到ping request,回复ping echo,反向的通信过程和上述基本一致。
上述步骤给出了通信的外在特征,下面说明某些步骤内在的实现原理。
1)“r1中存有目的虚拟机的静态ARP表项”,是因为各个部署了DVR的计算节点中,l3-agent都事先从neutron数据库中获取了虚拟机的网络信息,直接注入到了r1中。这是为了防止r1跨隧道泛洪获取vm2的MAC地址(可以通过l2_population来实现)。
2)“将源mac地址修改为全局唯一的dvr cn1 mac”,是因为在所有计算节点上,r1位于相同网段的接口mac地址是一致的,即CN1上的r1 red/grn mac与CN2上的r1 red/grn mac一致。因此为了防止对端br-tun上的混乱, Neutron为每个部署了DVR的计算节点分配了全局唯一的dvr mac地址,br-tun在进行隧道传输前都需要进行源MAC地址的改写。
“并封装好隧道,标记绿色网段的TUNNEL_ID,直接送往CN2”,DVR要求开启l2_population事先学习(VLAN_ID,MAC)到(PORT_ID,TUNNEL_ID)的映射,以避免隧道上的泛洪。
3)br-tun-cn2解封装后,判断流量由dvr cn1送过来,不进行自学习,直接将流量送给br-int-cn2。
4)br-int-cn2中实现存有所有部署了DVR的计算节点的全局唯一的MAC地址,因而可以识别dvr cn1送过来的流量,完成源MAC地址的回写后进行转发。
流表的逻辑跳转图如下所示(注意,某些Table的ID发生了变化,且未表示l2_population)。
Table 0对数据包的来源进行判断,从与br-int相连的patch-int进入的数据包交给Table 1处理,从VxLAN端口(以VxLAN为例)进入的交给Table 4处理。Table 1判断数据包是否为发向r1的ARP,或者其他发给r1的二层帧,如果是则丢弃(为了保证虚拟机送到r1的数据包只在本地转发)。如果Table 1判断数据包是由r1发出来的,则将源mac地址改为CN1的dvr mac地址(为了避免对端br-tun上的混乱),然后送往Table 2。Table 2根据数据包目的MAC地址判断是否为单播,是则送往Table 20,否则送往Table 21。Table 20根据(VLAN_ID,MAC)到(PORT_ID,TUNNEL_ID)的映射关系将单播包送到特定的隧道,该映射关系可事先通过L2_populaiton学习到,也可以通过Table 10的触发学习到。Table 21将非单播包复制后送到所有隧道。进入Table4的数据包,首先判断TUNNE_ID是否合法,是则添加本地VLAN_ID并送往Table 9,否则丢弃。Table 9判断数据包源mac地址是否属于dvr mac地址(由于示例场景比较简单,图中示例流表只匹配了CN2的dvr-cn2-mac),如果是直接送给br-int-cn1处理,否则转给Table 10进行学习。Table 10记录数据包的VLAN_ID,MAC以及TUNNEL_ID,将(VLAN_ID,MAC)到(PORT_ID,TUNNEL_ID)的映射关系写入Table 20,然后从与br-int相连的patch-int送出。下面给出各个流表项的标注,其中红色的为新增的DVR表项。
DVR对于南北向流量的处理有两种模型,第一种是SNAT在节点本地完成,第二种是SNAT仍需要到网络节点进行,两种模型分别示意如下。在节点本地进行SNAT则需要在计算节点的qr上为虚拟机分配浮动IP地址,而在网络节点完成SNAT比较节省公网IP资源,具体选择哪种模型,要视用户实际的业务需求而定。
讲到这里,对Neutron OVS上的流表分析就结束了。
审核编辑:郭婷
评论
查看更多