51学通信论坛2017新版

标题: Neutron的软件实现 [打印本页]

作者: admin    时间: 2017-9-17 14:22
标题: Neutron的软件实现
上一节交代了Neutron基本的组网原理,本节我们来看一看Neutron在软件层面的实现。
在架构设计上, Neutron沿用了OpenStack完全分布式的思想,各组件之间通过消息机制进行通信,使得Neutron中各个组件甚至各个进程都可以运行在任意的节点上,如下图所示。这种微内核的架构使得开发者可以集中精力在网络业务的实现上。目前Neutron提供了众多的插件与驱动,基本上可以满足各种部署的需要,如果这些还难以支撑实际所需的环境,则可以方便地在Neutron的框架下扩展插件或驱动。

[attach]1245[/attach]

上图中,除了消息机制以外还涉及5类Neutron组件,neutron-server,neutron agent,neutron plugin,neutron database,neutron provider,下面先对这几个组件是什么进行简单的介绍,再按照根据这几个组件间的交互来介绍Neutron主体代码的实现。

在开始分析代码之前,还需要先对neutron-plugin进行一点更为详细的介绍,neutron-plugin分为core-plugin和service-plugin两类。
Network代表一个隔离的二层网段,是为创建它的租户而保留的一个广播域。subnet和port始终被分配给某个特定的network。Network的类型包括Flat,VLAN,VxLAN,GRE等等。
Subnet代表一个IPv4/v6的CIDR地址池,以及与其相关的配置,如网关、DNS等等,该subnet中的 VM 实例随后会自动继承该配置。Sunbet必须关联一个network。
Port代表虚拟交换机上的一个虚机交换端口。VM的网卡VIF连接 port 后,就会拥有 MAC 地址和 IP 地址。Port 的 IP 地址是从 subnet 地址池中分配的。


上一节曾经提到,“Neutron对Quantum的插件机制进行了优化,将各个厂商L2插件中独立的数据库实现提取出来,作为公共的ML2插件存储租户的业务需求,使得厂商可以专注于L2设备驱动的实现,而ML2作为总控可以协调多厂商L2设备共同运行”。在Quantum中,厂家都是开发各自的Service-plugin,不能兼容而且开发重复度很高,于是在Neutron中就为设计了ML2机制,使得各厂家的L2插件完全变成了可插拔的,方便了L2中network资源扩展与使用。
(注意,以前厂商开发的L2 plugin跟ML2都存在于neutron/plugins目录下,而可插拔的ML2设备驱动则存在于neutron/plugins/ml2/drivers目录下)
ML2作为L2的总控,其实现包括Type和Mechanism两部分,每部分又分为Manager和Driver。Type指的是L2网络的类型(如Flat、VLAN、VxLAN等),与厂家实现无关。Mechanism则是各个厂家自己设备机制的实现,如下图所示。当然有ML2,对应的就可以有ML3,不过在Neutron中L3的实现只负责路由的功能,传统路由器中的其他功能(如Firewalls、LB、VPN)都被独立出来实现了,因此暂时还没有看到对ML3的实际需求。

[attach]1246[/attach]

=============================== Codes Start ==================================
一般而言,neutron-server和各neutron-plugin部署在控制节点或者网络节点上,而neutron agent则部署在网络节点上和计算节点上。我们先来分析控制端neutron-server和neutron-plugin的工作,然后再分析设备端neutron-agent的工作。
=============================== 控制端的实现 ==================================
从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可能有其它的南向通信机制)。

[attach]1247[/attach]

(一)WSGI
从48行代码回溯WSGI的机理。向前追踪到neutron.service中的_run_wsgi方法,该方法中加载了各类Neutron资源(l 173),实例化wsgi server(l 177),然后启动wsgi socket(l 178),这样neutron-sever就开始监听Neutron REST API了。177和178行没什么好说的,173行后面的学问比较多,下面来具体分析一下。

[attach]1248[/attach]

Load_paste_app这个方法属于wsgi的paste deployment,用于发现、配置、连接WSGI Application和Server。对于Neutron来说就是在neutron –server和各类Neutron资源建立关系,使得neutron-server能够将对A plugin中资源进行操作的REST API分发给A plugin,将对B plugin中资源进行操作的REST API分发给B plugin。Neutron的paste deployment配置文件目录路径为/etc/neutron/api-paste.ini,该文件中设计Neutron REST API的主要涉及这么几行,如下图所示。
Sevice-plugins的处理发生在neutron.api.extensions文件的plugin_aware_extension_middleware_factory方法中。Filter_factory返回neutron.api.extensions中的ExtensionMiddleware(l 388),在该过程中实例化了/etc/neutron/neutron.conf中配置的core-plugin和service-plugin(l 387),ExtensionMiddleware则负责了扩展资源URL的生成和资源的Application化。这部分的代码是在太过于底层,比较让人头疼,就没有细致的捉摸,不过其大致的处理思路和下面要说的core_plugin是类似的。
Core-plugin的处理发生在neutron.api.v2.router.APIRouter。APIRouter类在实例化的过程中,首先获得core_plugin(l 76)然后生成core_plugin资源的URL(l 103),最后将资源Application化为Controller的实例(l 104,l 109),Controller实例即支持大家喜闻乐见的“REST资源的增删改查”。这样当wsgi server收到REST API请求后,就能够根据请求中的URL找到资源的Controller,然后Controller会自动拼接字符串,得到并调用相应的core_plugin方法,比如所请求操作的资源是network,Action是“Create”,则应该调用的core_plugin方法就是“create_network”。
默认配置中Neutron的core_plugin为ML2,ML2在执行create_network方法时(neutron.plugins.ml2.plugin,l 365),首先通过Type Manager分配可用的network id(l 384),并向neutron database进行注册(l 385),然后通过Mechanism Manager将该network的参数传给底层各个Mechanism Driver(neutron.plugins.ml2.managers,l 193),Mechanism Driver再具体进行执行(l 168)。
讲到这里Neutron北向接口wsgi的部分就分析完了,而REST API中业务请求在网络设备中的落实则主要通过rpc机制来完成。
(二)RPC
控制端neutron-plugin与设备端相应neutron-agent间的通信一般由rpc机制实现。在开始进入Neutron rpc服务的代码分析前,我们需要先简单地了解一下rpc。
Openstack 组件内部rpc机制的实现基于 AMQP作为通讯模型。AMQP 是用于异步消息通讯的消息中间件协议,有四个重要的概念:

总体来说:消息发布者Publisher将Message发送给Exchange并且说明Routing Key。Exchange 负责根据Message的Routing Key进行路由,将Message正确地转发给相应的Message Queue。Consumer将会从Message Queue中读取消息。
Publisher可以分为4类:Direct Publisher发送点对点的消息;Topic Publisher采用“发布——订阅”模式发送消息;Fanout Publisher发送广播消息的发送;Notify Publisher同Topic Publisher,发送 Notification 相关的消息。类似地,Exchange可以分为3类:Direct Exchange根据Routing Key进行精确匹配,只有对应的 Message Queue 会接受到消息;
Topic Exchange根据Routing Key进行模式匹配,只要符合模式匹配的Message Queue都会收到消息;Fanout Exchange将消息转发给所有绑定的Message Queue。
了解了基础知识以后,我们接着从neutron_server启动文件主函数(neutron.server.__init__)中来分析各个neutron-plugin中rpc服务的启动。从L 52中调用的serve_rpc方法回溯,发现该方法(neutron.service l 141)只启动了core_plugin的rpc监听(l 142,l 157,l 160),而没有显示地启动service_plugins的rpc,实际上service_plugins的rpc在各个plugins实例化(在serve_wsgi方法中完成)的过程中已经启动了。

[attach]1249[/attach]

Neutron中控制端neutron-plugin和设备端相应的neutron-agent间rpc通信是单向异步的, plugin和agent上都要开启Publisher和Consumer。由于同一类的agent往往不止一个,因此Neutron rpc采用“发布——订阅”模式在plugin和agent间传递消息,在Publisher和Consumer实例化时需要指定全局唯一的Topic(规定在neutron.common.topics)。
Neutron中Publisher类的命名规范为**AgentNotifierApi,它们的实例可以向特定的Consumer发送消息,Consumer接收到消息后,通过dispatcher解封装,在调用**RpcCallBacks在本地执行消息体。Core_plugin在构造函数执行过程中实例化了AgentNotifierApi,其RpcCallBacks的实例化由neutron-server主函数中的l 52完成,如下第一张图所示;而service_plugins在构造函数执行过程中一起实例化了AgentNotifierApi和RpcCallBacks,如下第二张图所示。思路就是这个样子了,具体的代码就不再一行一行分析了。
[attach]1250[/attach]


[attach]1251[/attach]

===================== 设备端的实现 ========================
控制端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通信。

[attach]1252[/attach]

OVSNeutronAgent的实例化过程中主要干了如下6个工作,其中各个网桥的作用请参考上一小节的介绍,流表的具体逻辑这里也不细谈了,下一节内容会专门讲。
[attach]1253[/attach]

[attach]1254[/attach]

[attach]1255[/attach]

[attach]1256[/attach]

[attach]1257[/attach]

[attach]1258[/attach]

[attach]1259[/attach]


rpc_loop做的工作主要就是轮询一些状态,根据这些状态,进行相应的操作。比如一旦探测到本地的OVS重启了(l 1295,l 1309),就重新创建本地的网桥(l 1294-1300),并重新添加port(l 1336);再比如一旦rpc监听到update_port事件(l 1309),则在本地使能相应的port(l 1336)。
L 1336执行的process_network_ports方法(l 1129)有必要说一下,对port的增加和更新的处理调用treat_devices_added_or_updated方法(l 1152),对port的删除调用treat_devices_removed(l 1176)方法。Treat_devices_added_or_updated方法(l 1008)调用treat_vif_port方法(l 1038),treat_vif_port方法(l 936)中调用port_bound方法(l 948),port_bound方法(l 597)调用了provision_local_vlan方法(l 611)。Provision_local_vlan方法(l 436)向各个网桥下发相应的流表,完成port与本地vlan_id的绑定工作。
[attach]1260[/attach]

[attach]1261[/attach]

[attach]1262[/attach]


[attach]1263[/attach]

ovs-neutron-agent的启动也就是这些工作了,启动完毕后,便开始了与相应plugin(OVS Plugin或者OVS Mechanism Driver)的rpc通信。
=============================== Codes End ===================================
Neutron的软件实现就简单地介绍到这里了,下一节我们来具体看看Neutron中各个OVS上的流表逻辑是怎样的。
声明:本文转载自网络。版权归原作者所有,如有侵权请联系删除。




欢迎光临 51学通信论坛2017新版 (http://bbs.51xuetongxin.com/) Powered by Discuz! X3