Zi 字媒體
2017-07-25T20:27:27+00:00
作者簡介:肖宏輝,畢業於中科院研究所院,8年的工作經驗,其中6年雲計算開發經驗,OpenStack社區積極活躍,有超過300個commit和超過30000行代碼的貢獻。目前關注SDN/NFV等虛擬網路技術。本文所有觀點僅代表作者個人觀點,與作者現在或者之前所在的公司無關。前言本文先介紹一下VLAN Trunk的基本概念,以及OpenStack Neutron和OpenFlow based SDN是如何為Trunk port提供網路支持。OpenStack對VLAN Trunk的支持具體是什麼?雖然OpenStack與容器,物理主機也做了集成,但是OpenStack最主要的應用還是虛機管理,而現代的操作系統,不論是Linux還是Windows,都支持將網卡配置成Trunk port。OpenStack對VLAN Trunk的支持就是指對OpenStack所管理的虛機的Trunk port,提供網路支持。主機的Trunk port是指在主機的一塊網卡上添加多個帶有不同VLAN ID的子網卡。通過子網卡發送的數據,打上VLAN Tag,被發送出去。由於帶了不同的VLAN Tag,子網卡可以認為連接在VLAN Tag標識的網路中。這樣,不用增減主機的網卡,就可以將主機添加到新的網路中。更主要的是,這種方式的網路添加是動態的。主機的Trunk port有什麼用?一個應用是在NFV場景下,一個VNF(Virtual Networking Function)可能需要同時連接多個網路。當然最簡單是一個網路對應一塊網卡,但如果網路數量巨大,網卡數量也巨大,一方面這不現實。另一方面,連接的多個網路也是動態增減的,如果每次增減都插拔VNF的網卡,明顯也是不能接受的。如果用Trunk port,當需要動態連接多個網路時,只需要動態的創建/刪除相應的子網卡即可。VLAN Trunk在NFV中的應用一、VLAN Trunk介紹1.1 VLAN簡介VLAN(Virtual LAN)由IEEE802.1Q定義。要講VLAN要先從廣播域(Broadcast Domain)開始說起。在下圖中,假設PC1-5在一個廣播域中,當PC1發出廣播幀,例如ARP,DHCP,由於目的MAC地址是廣播地址,同一個廣播域內的所有設備都將收到相應的廣播幀。如果PC1-5在一個子網中,那這本身也無可厚非,因為這正是ARP,DHCP的工作原理。如果PC1-5不在一個子網中呢?例如上圖中,PC1在橙色子網,PC2-3在綠色子網,PC4-5在紅色子網。理論上,PC1發出的廣播幀只應該在橙色子網內傳播。但實際上,是由於PC1-5在一個廣播域中,PC2-5還是會收到PC1的廣播幀。雖然PC2-5會直接丟棄這個廣播幀,但是這裡存在安全問題和性能問題。首先,PC2-5雖然不會處理PC1發來的廣播幀,但是數據還是發送過來了,通過偵聽和偽裝,可以達到劫持的目的,例如ARP spoof。其次,廣播幀本來不用在整個網路傳播,但現在就整個網路傳播,這樣佔用了交換機的帶寬,在大規模網路中,尤其會影響網路性能。解決這些問題的方法就是使用VLAN。VLAN是一組網路埠的集合。實現了VLAN的交換機,會將二層的單播、組播、廣播都局限在一個VLAN中,這樣不同的VLAN中的主機,交換機就不會有其他VLAN的數據。只有交換機能看到VLAN,連接交換機的其他設備,例如Server、Router都感覺不到VLAN的存在。將不同的子網規劃在不同的VLAN當中,可以實現子網的隔離。即使所有的設備都在一個交換機上,不同的VLAN之間通信也需要通過Router。1.2 VLAN Trunk簡介VLAN的劃分並非只能在一個交換機上,多個交換機可以共同組成VLAN。那多個交換機上的VLAN是怎麼連接到一起的?有兩種方法。第一種方法是把每個交換機上的每個VLAN都連在一起。如下圖所示:圖中有兩個交換機,各有兩個VLAN,為了讓VLAN能正常工作,將VLAN1和VLAN2分別連接起來。如果是兩個交換機,兩個VLAN還好,如果是100個VLAN,那麼這裡需要有100條線路,200個交換機埠。這麼連接可以嗎?可以,只要有錢,因為這裡的線路和交換機埠都是錢。這種方法,運維和成本支出比較大,不實用。第二種方法是通過VLAN Trunk連接交換機。VLAN Trunk是一種網路設備間的point-to-point的連接。一條VLAN Trunk線路可以同時傳輸多個甚至所有的VLAN數據。由於VLAN Trunk可以傳輸多個VLAN數據,Ethernet Frame在VLAN Trunk上傳輸時,需要帶上802.1Q定義的VLAN tag,這樣交換機才能區分Ethernet Frame到底屬於哪個VLAN。VLAN Trunk的具體使用過程如下:◆ 當最左側伺服器想要訪問最右側伺服器,最左側伺服器將Ethernet Frame發送到左側交換機◆ 左側交換機本地沒有目的MAC對應的轉發信息,因此Ethernet Frame發送到了左側交換機的VLAN Trunk port◆ 由於這是來自VLAN100的Ethernet Frame,交換機給Ethernet Frame打上VLAN 100的Tag,從自己的VLAN Trunk port發出,發送到右側交換機的VLAN Trunk port◆ 右側的VLAN Trunk port收到VLAN 100的Ethernet Frame,去除VLAN Tag,再在本地的VLAN 100埠中查找MAC轉發◆ 找到對應的MAC/埠記錄,最終Ethernet Frame發送到最右側的伺服器如果是VLAN200的數據,過程一樣,只是VLAN Tag從100變成了200。通過VLAN Trunk port,兩個交換機之間不論需要連接多少個VLAN,只需要一個VLAN Trunk連接(一對Trunk port)即可。如果有多個交換機需要連接,通常會用另外一個交換機連接它們,如下圖所示,交換機之間都通過Trunk port相連。紅色框內的交換機的4個port都是Trunk port,任意的VLAN 標籤的Ethernet Frame都可以在這個交換機內傳輸。可以把紅色框內看成是一個Trunk network,一個Trunk network可以傳輸帶VLAN標籤的Ethernet Frame。雖然圖中只有一個交換機,但是Trunk network可以更加複雜,由多個交換機組成。多個VLAN的網路數據共同在Trunk network上傳輸,通過VLAN Tag來識別VLAN。如果把上圖中下面四個交換機換成主機(虛機),那就是OpenStack VLAN Trunk希望支持的場景。為了支持這個場景,需要為虛機提供一個Trunk Network。1.3 Linux VLAN TrunkWindows也支持Trunk port,與Linux類似,這裡只說明Linux系統下的Trunk port。Linux系統可以通過內核模塊8021q支持VLAN Trunk。這裡有什麼不一樣?在一般情況下,主機是不感知VLAN Tag的,也就是說主機發送的網路數據都是不帶VLAN Tag,所有VLAN Tag操作都是由交換機完成。但是實際上交換機也不知道自己連接的是什麼,所以,如果在主機完成VLAN Tag的操作,再發送到交換機,交換機也能處理。基於這個前提,Linux能夠將一塊乙太網卡配置成一個支持802.1q的Trunk port,使得這塊網卡跟前面描述的交換機上的Trunk port一樣,能夠收發多個VLAN的網路數據包。並且通過配置Linux主機的子網卡,可以使得Linux主機內部完成VLAN Tag的操作(打上VLAN Tag,去除VLAN Tag)。有不止一種方法可以配置Linux VLAN Trunk,這裡以ip命令為例,為eth0添加名為eth0.102的子網卡,其VLAN ID為102。$ sudo ip link add link eth0 name eth0.102 type vlan id 102就這麼簡單,之後可以看到一個新的網卡在系統的網卡列表中。Linux VLAN Trunk工作過程如下:◆ 外界傳入的帶VLAN Tag 102的包,到達了eth0,VLAN Tag 102被去除,然後不帶VLAN Tag的Ethernet Frame被重新發往操作系統網路棧,再發送到eth0.102。◆ 從eth0.102發送出來的幀,被打上VLAN102的標籤,再從eth0傳出。應用層面,收發的還是不帶VLAN Tag的數據,只是經過Linux VLAN Trunk的處理,進出主機的的數據是帶VLAN Tag的數據。由於eth0配置成了VLAN Trunk port。為了讓帶有VLAN標籤的Ethernet Frame能夠在網路上傳輸。eth0所接入的網路必須是一個Trunk network。否則無法傳輸任意帶VLAN Tag的Ethernet Frame。也就是說,需要將主機的Trunk port連接到紅框內。接下來我們看看OpenStack是怎麼做的。二、OpenStack Neutron對VLAN Trunk的支持Neutron VLAN Transparency這是OpenStack Kilo版本的特性,由VLAN trunking networks for NFV定義。這個特性為Neutron network增加一個屬性「vlan-transparent」,當vlan-transparent為True時,表明在這個Neutron network是一個Trunk network。在這個Neutron network中的虛機可以使用Linux VLAN Trunk功能。接下來看看Neutron為了實現這個特性做了什麼?什麼也沒做!Neutron只是提供了這麼一個屬性,具體的實現交給底層的SDN。如果SDN不支持VLAN Transparency,可以在ML2中告知Neutron。那麼用戶在創建Neutron network時,如果指定了vlan-transparent=True,Neutron會返回「Backend does not support VLAN Transparency.」。例如OpenVSwitch,就不支持VLAN Transparency。所以,並非所有的SDN都支持這個功能,就算實現了,每種SDN的實現方式不一樣。不過本質上,都是將SDN控制的vSwitch配置成Trunk模式。需要注意的是,vSwitch最終還是要連接到Physical Switch,所以Physical Switch相應的埠也需要配置成Trunk port。先來看看VLAN Transparency的問題,◆ 不支持OpenVSwitch◆ 要求Physical Switch也配置相應的Trunk port◆ VLAN aware VMs在支持相同功能的前提下,解決了上面兩個問題。首先看看如何使用VLAN aware VMs這個功能。Neutron VLAN aware VMs是OpenStack Newton版本的特性,由VLAN aware VMs定義。VLAN aware VMs和VLAN Transparency說的其實是一件事情,就是如何傳遞VM發出來的帶VLAN Tag的幀。2.1 實驗步驟我用的是最新代碼(Pike 2017-08-08)配合OpenVSwitch完成下面的操作。要使能VLAN aware VMs,只需要在/etc/neutron/neutron.conf中,在service_plugins後面加上trunk。首先創建Trunk port所在的網路和VLAN子網卡所在的網路。注意這裡我並沒有指定網路的類型,網路可以不用是VLAN的,像在我的環境中,網路就是VXLAN類型。為什麼會這樣?在後面會說。接下來創建Trunk port和subport。這裡創建了兩組4個port,並用trunk模型將它們關聯起來了。除此之外,還為Trunk中的subport指定了segmentation-type和segmentation-id。VLAN是目前OpenVSwitch支持的唯一的segmentation type(也是大多數SDN唯一支持的類型),segmentation id就是在虛機中創建subport時指定的VLAN ID。接下來用parent port創建兩個虛機。因為Linux VLAN Trunk需要8021q內核模塊的支持,這裡用了一個Ubuntu16.04的image。到此為止,OpenStack的操作完成了。接下來,在兩個虛機內部,配置Linux VLAN Trunk。在vm1內部,做如下配置:這裡給虛機的subport配置的VLAN ID是102,這是之前通過OpenStack命令創建Trunk時指定的segmentation-id。這裡的ens3.102對應之前創建的sub-port1,為了讓ens3.102能使用Neutron DHCP服務,這裡將Neutron分配給sub-port1的MAC地址配置在ens3.102上。Linux子網卡默認會跟父網卡用同一個MAC地址,所以也可以在用OpenStack命令創建subport的時候,指定MAC地址。總之,這裡我們讓虛機內的子網卡的MAC地址與OpenStack Neutron中對應的subport的MAC地址一致。在vm2內部做同樣的操作,只是MAC地址換成成sub-port2的MAC地址。2.2 驗證連通性及DHCP服務DHCP服務 在兩個虛機內部,通過dhclient命令獲取子網卡IP地址。可以看到,子網卡也可以通過Neutron的DHCP服務獲取IP地址。VLAN互通 在vm1內部,ping vm2.在vm2內部,查看收到的包。前面講過Linux VLAN Trunk的工作過程,Ethernet Frame發送到ens3.102時,已經剝離了VLAN標籤。為了查看VLAN信息,所以我們這裡直接監聽ens3可以看到,vm2收到的原始Ethernet Frame是帶VLAN Tag的。2.3 原理註:這部分內容假設你對OpenStack Neutron已經有一定的了解了。雖然上面完成了VLAN aware VMs的配置和Linux VLAN Trunk的驗證,甚至虛機內的subport都可以使用Neutron的DHCP服務,但是這裡留下了兩個問題沒有解答。◆ 首先,不用在vSwitch和Physical switch上打開trunk模式,就能支持帶VLAN Tag的幀的傳遞,這中間發生了什麼?◆ 其次,一個傳輸VLAN數據的subport如何能使用定義在VXLAN網路中的DHCP服務?看完Neutron VLAN aware VMs的架構,這兩個問題自然就能解決。首先我們看看計算節點上的OpenVSwitch網橋。可以發現,對每個Trunk port,對應的新增了一個網橋。在這個網橋的埠中,qvo埠是用來連接虛機的,剩下的埠中,一個是bridge對應的埠,剩下兩個都是patch port。其中一個還帶了VLAN Tag 102,正是我們配置的segmentation-id。patch port都是成對出現,這裡的patch port peer都掛在br-int上。具體的網橋和埠的關係如下圖所示:左上角是正常的OpenVSwitch上連接的虛機,為什麼不是虛機直接到OpenVSwitch網橋?這是歷史遺留問題,這裡不做解釋,大家只需要知道qvo是br-int上用來連接虛機的埠。再看虛線框內,上半部分與原來虛機伸出的部分相同,下半部分就是之前展示的新增的網橋。網橋向上通過qvo連接虛機。向下通過patch port pair 連接parent port,從虛機出來的不帶VLAN Tag的幀,從這對patch port走到br-int。同時向下通過patch port pair 連接subport,一個subport對應一對spt-spi,注意的是每個spt都帶有相應的VLAN Tag,根據OVS的特性,所有從虛機出來的,帶上相應VLAN Tag的幀都會發送到相應的spt,再通過spi發送到br-int。所以,從虛機出來的Ethernet Frame,根據所攜帶的VLAN Tag(或者不帶VLAN Tag),在tbr網橋上,可以分配到不同的patch port,進而轉發到br-int上的不同埠。也就是說,在tbr上,從虛機里一塊網卡發出來的Ethernet Frame被分流了。在br-int上,其實不知道qvo、spi,tpi有什麼區別,這些埠對於br-int來說地位是一樣的。這些埠分別在不同的網路中(最開始為parent port和subport分別創建了網路),br-int根據埠所在的網路,將虛機發出來的Ethernet Frame打上Local network ID(又一個VLAN ID,類似於VTEP中VLAN ID與VXLAN ID對應中的VLAN),發往br-tun。在br-tun根據Local network ID轉換成VXLAN數據發送出去。在對端,經過br-tun發送到br-int,br-int根據不同的網路,將數據發送到相應的qvo,spi,tpi。這裡看spi這條線路,因為patch port的相連,數據發送到了tbr網橋,再經由qvo發向虛機。由於qvo沒有自己的VLAN Tag,所以它將保留入口埠的VLAN Tag,也就是VLAN 102,最後VLAN 102的幀發送給虛機。總結一下Ethernet Frame的處理流程。從虛機發出來的VLAN數據,在tbr網橋通過相應的patch port 對,發送到br-int。在patch port對的傳遞過程中,VLAN Tag由虛機內定義的VLAN ID變成了br-int內部的Local network ID。br-int將數據發送給br-tun。br-tun根據自身記錄的VLAN ID與VXLAN ID的對應,將VLAN數據中VLAN Tag去除,並將剩餘的Ethernet Frame封裝成VXLAN數據,在VXLAN tunnel上傳輸。對端收到VXLAN數據,在br-tun轉換成VLAN數據,VLAN Tag是Local network ID,再發送給br-int。br-int根據Local network ID和目的MAC地址,將VLAN數據從對應的埠(spi)發出。經過patch port 對的傳輸,VLAN Tag由Local network ID變成了spt上的VLAN Tag,最後通過qvo發送給虛機。虛機收到還是VLAN 102的數據,但是數據在中間是通過VXLAN網路傳輸。所以為什麼不需要vSwitch和Physical Switch對Trunk模式進行支持?因為VLAN數據換成了VXLAN數據,傳輸的都不是VLAN了,自然不需要交換機配置Trunk。為什麼子網卡能使用Neutron的DHCP服務,因為數據被換成了Neutron network網路數據(VXLAN),接入到Neutron network,自然就能使用Neutron network內的服務。三、SDN中VLAN的實現Neutron在OpenVSwitch上實現的VLAN aware VMs原理在上面介紹過,不得不說,這個方案比較複雜,希望我已經說清楚了。雖然這個方案不依賴物理網路配置Trunk,但是需要創建額外的網橋和埠,對應的轉換步驟也太多了。這麼實現有Neutron的歷史原因,也有Neutron輕度依賴OpenFlow的因素在裡面。我們接下來看看在OpenFlow中,如何實現VLAN aware VMs。VLAN aware VMs的核心思想是,用Neutron tenant network的overlay網路,來傳輸Linux VLAN Trunk發出來的各種VLAN數據。像上面的介紹,就是用VXLAN網路來傳輸虛機發出的VLAN數據,在進出虛機的時候再對VLAN Tag做相應的處理。相同的功能在OpenFlow中實現就簡單的多,我們以Dragonflow項目的實現為例,具體介紹在Spec for VLAN aware VMs。只需要在網橋上添加幾條OpenFlow流表,就能識別虛機發出的數據,並分發到不同的Neutron tenant network,進而通過Neutron tenant network傳輸。在虛機的出口,添加下列流表:這裡的REG6表明入口埠,METADATA用來識別網路,可見,在table0就已經完成了將虛機中一塊網卡發出的Ethernet Frame根據VLAN Tag分成不同的通道,並識別相應的網路。之後的傳輸不需要區分究竟是不是子網卡的數據,就是當成普通的overlay tenant network傳輸。在虛機的入口,添加下列流表:「mod_vlan_vid:vlan_vid:0x10066」就是打上VLAN Tag102,可以看出不同網路的數據,打上不同的VLAN Tag(對於parent port不打VLAN Tag)發向了同一個埠183(虛機網卡)。沒有多餘的網橋,沒有網橋上換來換去的VLAN ID,僅僅是在入口和出口處去除VLAN Tag和打上VLAN Tag,幾條流表就實現了所有的功能。簡單的實現一般意味著更高的效率和更少的錯誤,因此使用SDN方式實現VLAN aware VMs更具有優勢。四、VLAN Trunk在NFV中的應用最後我們再看看VLAN Trunk在NFV中的應用吧,這個在最開頭一些簡單的介紹,這裡來說個用例。一個多路復用設備,需要連接多個子設備,子設備的數目是不確定的,且有可能變化,並且要求子設備間網路是隔離的。當然,我也可以給多路復用設備配置多塊網卡,但是由於子設備數目不確定,網卡數目是不確定的。這個時候可以將多路復用設備的一塊Ethernet網卡配置成VLAN Trunk port,在之上創建相應的subport。子設備上的網卡也配置成VLAN Trunk port,並創建對應的subport。由於配置的VLAN不一樣,不同子設備之間的網路是隔離的。並且多路復用設備的subport是可以動態刪減的,這滿足了子設備數據是不確定的要求。具體如下圖所示:不論是VLAN Transparency還是VLAN aware VMs,都是為了使得OpenStack中的虛機能夠使用Linux VLAN Trunk功能。VLAN Transparency依賴vSwitch和物理交換機的配置,不說實際物理交換機的複雜性,單就是vSwitch也不一定支持Trunk模式。VLAN aware VMs通過一系列的轉換,擺脫了對vSwitch和物理交換機配置的依賴,走在網線上的數據甚至都可以不是VLAN數據,這比VLAN Transparency進了一步。而通過SDN實現VLAN aware VMs可以大大簡化實現過程,又更進了一步。微信ID:SDNLAB
寫了
5860316篇文章,獲得
23313次喜歡