Neutron的軟件實現(xiàn)

責任編輯:editor005

作者:張晨

2016-04-07 15:22:26

摘自:SDNLAB

Neutron中控制端neutron-plugin和設備端相應的neutron-agent間rpc通信是單向異步的, plugin和agent上都要開啟Publisher和Consumer

上一節(jié)交代了Neutron基本的組網(wǎng)原理,本節(jié)我們來看一看Neutron在軟件層面的實現(xiàn)。

在架構設計上, Neutron沿用了OpenStack完全分布式的思想,各組件之間通過消息機制進行通信,使得Neutron中各個組件甚至各個進程都可以運行在任意的節(jié)點上,如下圖所示。這種微內核的架構使得開發(fā)者可以集中精力在網(wǎng)絡業(yè)務的實現(xiàn)上。目前Neutron提供了眾多的插件與驅動,基本上可以滿足各種部署的需要,如果這些還難以支撐實際所需的環(huán)境,則可以方便地在Neutron的框架下擴展插件或驅動。

上圖中,除了消息機制以外還涉及5類Neutron組件,neutron-server,neutron agent,neutron plugin,neutron database,neutron provider,下面先對這幾個組件是什么進行簡單的介紹,再按照根據(jù)這幾個組件間的交互來介紹Neutron主體代碼的實現(xiàn)。

Neutron-server可以理解為一個專門用來接收Neutron REST API調用的服務器,然后負責將不同的rest api分發(fā)到不同的neutron-plugin上。Neutron-plugin可以理解為不同網(wǎng)絡功能實現(xiàn)的入口,各個廠商可以開發(fā)自己的plugin。Neutron-plugin接收neutron-server分發(fā)過來的REST API,向neutron database完成一些信息的注冊,然后將具體要執(zhí)行的業(yè)務操作和參數(shù)通知給自身對應的neutron agent。Neutron-agent可以直觀地理解為neutron-plugin在設備上的代理,接收相應的neutron-plugin通知的業(yè)務操作和參數(shù),并轉換為具體的設備級操作,以指導設備的動作。當設備本地發(fā)生問題時,neutron-agent會將情況通知給neutron-plugin。Neutron database,顧名思義就是Neutron的數(shù)據(jù)庫,一些業(yè)務相關的參數(shù)都存在這里。Network provider,即為實際執(zhí)行功能的網(wǎng)絡設備,一般為虛擬交換機(OVS或者Linux Bridge)。

在開始分析代碼之前,還需要先對neutron-plugin進行一點更為詳細的介紹,neutron-plugin分為core-plugin和service-plugin兩類。

Core-plugin,Neutron中即為ML2(Modular Layer 2),負責管理L2的網(wǎng)絡連接。ML2中主要包括network、subnet、port三類核心資源,對三類資源進行操作的REST API被neutron-server看作Core API,由Neutron原生支持。其中:
Network 代表一個隔離的二層網(wǎng)段,是為創(chuàng)建它的租戶而保留的一個廣播域。subnet和port始終被分配給某個特定的network。Network的類型包括Flat,VLAN,VxLAN,GRE等等。
Subnet 代表一個IPv4/v6的CIDR地址池,以及與其相關的配置,如網(wǎng)關、DNS等等,該subnet中的 VM 實例隨后會自動繼承該配置。Sunbet必須關聯(lián)一個network。
Port 代表虛擬交換機上的一個虛機交換端口。VM的網(wǎng)卡VIF連接 port 后,就會擁有 MAC 地址和 IP 地址。Port 的 IP 地址是從 subnet 地址池中分配的。
Service-plugin,即為除core-plugin以外其它的plugin,包括l3 router、firewall、loadbalancer、VPN、metering等等,主要實現(xiàn)L3-L7的網(wǎng)絡服務。這些plugin要操作的資源比較豐富,對這些資源進行操作的REST API被neutron-server看作Extension API,需要廠家自行進行擴展。

上一節(jié)曾經(jīng)提到,“Neutron對Quantum的插件機制進行了優(yōu)化,將各個廠商L2插件中獨立的數(shù)據(jù)庫實現(xiàn)提取出來,作為公共的ML2插件存儲租戶的業(yè)務需求,使得廠商可以專注于L2設備驅動的實現(xiàn),而ML2作為總控可以協(xié)調多廠商L2設備共同運行”。在Quantum中,廠家都是開發(fā)各自的Service-plugin,不能兼容而且開發(fā)重復度很高,于是在Neutron中就為設計了ML2機制,使得各廠家的L2插件完全變成了可插拔的,方便了L2中network資源擴展與使用。

(注意,以前廠商開發(fā)的L2 plugin跟ML2都存在于neutron/plugins目錄下,而可插拔的ML2設備驅動則存在于neutron/plugins/ml2/drivers目錄下)

ML2作為L2的總控,其實現(xiàn)包括Type和Mechanism兩部分,每部分又分為Manager和Driver。Type指的是L2網(wǎng)絡的類型(如Flat、VLAN、VxLAN等),與廠家實現(xiàn)無關。Mechanism則是各個廠家自己設備機制的實現(xiàn),如下圖所示。當然有ML2,對應的就可以有ML3,不過在Neutron中L3的實現(xiàn)只負責路由的功能,傳統(tǒng)路由器中的其他功能(如Firewalls、LB、VPN)都被獨立出來實現(xiàn)了,因此暫時還沒有看到對ML3的實際需求。

=============================== Codes Start ==================================

一般而言,neutron-server和各neutron-plugin部署在控制節(jié)點或者網(wǎng)絡節(jié)點上,而neutron agent則部署在網(wǎng)絡節(jié)點上和計算節(jié)點上。我們先來分析控制端neutron-server和neutron-plugin的工作,然后再分析設備端neutron-agent的工作。

=============================== 控制端的實現(xiàn) ==================================

從neutron-server的啟動開始說起。neutron-server的啟動入口在neutron.server.__init__中,主函數(shù)中主要就干了兩件事,第一是下圖l 48處啟動wsgi服務器監(jiān)聽Neutron REST API,第二是在l 52啟動rpc服務,用于core plugin與agent間的通信,兩類服務作為綠色線程并發(fā)運行。從SDN的角度來看,wsgi負責Neutron的北向接口,而Neutron的南向通信機制主要依賴于rpc來實現(xiàn)(當然,不同廠家的plugin可能有其它的南向通信機制)。

(一)WSGI

從48行代碼回溯WSGI的機理。向前追蹤到neutron.service中的_run_wsgi方法,該方法中加載了各類Neutron資源(l 173),實例化wsgi server(l 177),然后啟動wsgi socket(l 178),這樣neutron-sever就開始監(jiān)聽Neutron REST API了。177和178行沒什么好說的,173行后面的學問比較多,下面來具體分析一下。

Load_paste_app這個方法屬于wsgi的paste deployment,用于發(fā)現(xiàn)、配置、連接WSGI Application和Server。對于Neutron來說就是在neutron –server和各類Neutron資源建立關系,使得neutron-server能夠將對A plugin中資源進行操作的REST API分發(fā)給A plugin,將對B plugin中資源進行操作的REST API分發(fā)給B plugin。Neutron的paste deployment配置文件目錄路徑為/etc/neutron/api-paste.ini,該文件中設計Neutron REST API的主要涉及這么幾行,如下圖所示。


Sevice-plugins的處理發(fā)生在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的處理發(fā)生在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請求后,就能夠根據(jù)請求中的URL找到資源的Controller,然后Controller會自動拼接字符串,得到并調用相應的core_plugin方法,比如所請求操作的資源是network,Action是“Create”,則應該調用的core_plugin方法就是“create_network”。

默認配置中Neutron的core_plugin為ML2,ML2在執(zhí)行create_network方法時(neutron.plugins.ml2.plugin,l 365),首先通過Type Manager分配可用的network id(l 384),并向neutron database進行注冊(l 385),然后通過Mechanism Manager將該network的參數(shù)傳給底層各個Mechanism Driver(neutron.plugins.ml2.managers,l 193),Mechanism Driver再具體進行執(zhí)行(l 168)。

講到這里Neutron北向接口wsgi的部分就分析完了,而REST API中業(yè)務請求在網(wǎng)絡設備中的落實則主要通過rpc機制來完成。

(二)RPC

控制端neutron-plugin與設備端相應neutron-agent間的通信一般由rpc機制實現(xiàn)。在開始進入Neutron rpc服務的代碼分析前,我們需要先簡單地了解一下rpc。

Openstack 組件內部rpc機制的實現(xiàn)基于 AMQP作為通訊模型。AMQP 是用于異步消息通訊的消息中間件協(xié)議,有四個重要的概念:

Exchange:根據(jù)Routing key轉發(fā)消息到不同的Message Queue中。Routing key:用于Exchange判斷哪些消息需要發(fā)送對應的Message Queue。Publisher:消息發(fā)送者,將消息發(fā)送給Exchange并指明Routing Key。Consumer:消息接受者,從Message Queue獲取消息,并在本地進行執(zhí)行。

總體來說:消息發(fā)布者Publisher將Message發(fā)送給Exchange并且說明Routing Key。Exchange 負責根據(jù)Message的Routing Key進行路由,將Message正確地轉發(fā)給相應的Message Queue。Consumer將會從Message Queue中讀取消息。

Publisher可以分為4類:Direct Publisher發(fā)送點對點的消息;Topic Publisher采用“發(fā)布——訂閱”模式發(fā)送消息;Fanout Publisher發(fā)送廣播消息的發(fā)送;Notify Publisher同Topic Publisher,發(fā)送 Notification 相關的消息。類似地,Exchange可以分為3類:Direct Exchange根據(jù)Routing Key進行精確匹配,只有對應的 Message Queue 會接受到消息;

Topic Exchange根據(jù)Routing Key進行模式匹配,只要符合模式匹配的Message Queue都會收到消息;Fanout Exchange將消息轉發(fā)給所有綁定的Message Queue。

了解了基礎知識以后,我們接著從neutron_server啟動文件主函數(shù)(neutron.server.__init__)中來分析各個neutron-plugin中rpc服務的啟動。從L 52中調用的serve_rpc方法回溯,發(fā)現(xiàn)該方法(neutron.service l 141)只啟動了core_plugin的rpc監(jiān)聽(l 142,l 157,l 160),而沒有顯示地啟動service_plugins的rpc,實際上service_plugins的rpc在各個plugins實例化(在serve_wsgi方法中完成)的過程中已經(jīng)啟動了。

Neutron中控制端neutron-plugin和設備端相應的neutron-agent間rpc通信是單向異步的, plugin和agent上都要開啟Publisher和Consumer。由于同一類的agent往往不止一個,因此Neutron rpc采用“發(fā)布——訂閱”模式在plugin和agent間傳遞消息,在Publisher和Consumer實例化時需要指定全局唯一的Topic(規(guī)定在neutron.common.topics)。

Neutron中Publisher類的命名規(guī)范為**AgentNotifierApi,它們的實例可以向特定的Consumer發(fā)送消息,Consumer接收到消息后,通過dispatcher解封裝,在調用**RpcCallBacks在本地執(zhí)行消息體。Core_plugin在構造函數(shù)執(zhí)行過程中實例化了AgentNotifierApi,其RpcCallBacks的實例化由neutron-server主函數(shù)中的l 52完成,如下第一張圖所示;而service_plugins在構造函數(shù)執(zhí)行過程中一起實例化了AgentNotifierApi和RpcCallBacks,如下第二張圖所示。思路就是這個樣子了,具體的代碼就不再一行一行分析了。


===================== 設備端的實現(xiàn) ========================

控制端neutron-server通過wsgi接收北向REST API請求,neutron-plugin通過rpc與設備端進行南向通信。設備端agent則向上通過rpc與控制端進行通信,向下則直接在本地對網(wǎng)絡設備進行配置。Neutron-agent的實現(xiàn)很多,彼此之間也沒什么共性的地方,下面選取比較具有代表性的ovs-neutron-agent的實現(xiàn)進行簡單的介紹。

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個工作,其中各個網(wǎng)橋的作用請參考上一小節(jié)的介紹,流表的具體邏輯這里也不細談了,下一節(jié)內容會專門講。

L 203,通過setup_intergration_br方法啟動ovs br-int網(wǎng)橋。該方法中通過ovs-vsctl在本地創(chuàng)建網(wǎng)橋(l 671),配置安全模式(l 672),刪除patch端口(l 674),并對網(wǎng)橋中的流表進行初始化(l 675-679)。L 206,通過setup_rpc方法啟動rpc。該方法中實例化了rpc Publisher(l 262,l 263),實例化了rpc Consumer(l 268-277),啟動了rpc心跳機制(l 284)。注意,Ovs-neutron-agent的rpc Consumer只監(jiān)聽4類topic:update_port,delete_network,tunnel_update,sg_update。L 208,通過setup_physical_bridge方法啟動ovs br-eth1。該方法中通過ovs-vsctl在本地創(chuàng)建網(wǎng)橋并對其進行初始化(l 832,l 833),建立與ovs br-int間的veth-pair(l 838,l 854),并封鎖兩個網(wǎng)橋間不經(jīng)過veth-pair的通信(l 856,l 859),然后開啟veth-pair(l 864,l 865)。L227,通過setup_tunnel_br方法啟動ovs br-tun。該方法中通過ovs-vsctl在本地創(chuàng)建網(wǎng)橋并對其進行初始化(l 717,l 719),建立與ovs br-int間的patch連接(l 720- 722),然后生成流表邏輯(l 730-767)。L232,實例化OVSSecurityGroupAgent,開啟rpc(l 119),并初始化防火墻(l 121)。L237,把run_daemon_loop變量置為True(l 237),開始循環(huán)查詢的工作。當run_daemon_loop變量置為True,main方法調用daemon_loop方法,之后調用rpc_loop。

rpc_loop做的工作主要就是輪詢一些狀態(tài),根據(jù)這些狀態(tài),進行相應的操作。比如一旦探測到本地的OVS重啟了(l 1295,l 1309),就重新創(chuàng)建本地的網(wǎng)橋(l 1294-1300),并重新添加port(l 1336);再比如一旦rpc監(jiān)聽到update_port事件(l 1309),則在本地使能相應的port(l 1336)。

L 1336執(zhí)行的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)向各個網(wǎng)橋下發(fā)相應的流表,完成port與本地vlan_id的綁定工作。




ovs-neutron-agent的啟動也就是這些工作了,啟動完畢后,便開始了與相應plugin(OVS Plugin或者OVS Mechanism Driver)的rpc通信。

=============================== Codes End ===================================

Neutron的軟件實現(xiàn)就簡單地介紹到這里了,下一節(jié)我們來具體看看Neutron中各個OVS上的流表邏輯是怎樣的。

作者簡介:
張晨,2014/09-至今,北京郵電大學信息與通信工程學院未來網(wǎng)絡理論與應用實驗室(FNL實驗室)攻讀碩士研究生。
主要研究方向:SDN、虛擬化、數(shù)據(jù)中心
個人博客:sdnv.xyz
個人郵箱:zhangchen9211@126.com

鏈接已復制,快去分享吧

企業(yè)網(wǎng)版權所有?2010-2024 京ICP備09108050號-6京公網(wǎng)安備 11010502049343號