Linux實現的IEEE 802.1Q VLAN

suzhouclark發表於2014-08-07

From:  http://blog.chinaunix.net/uid-26611973-id-3479560.html


第一部分:VLAN的核心概念

說起IEEE 802.1q,都知道是VLAN,說起VLAN,基本上也沒有盲區,網路基礎。然而說到配置,基本所有人都能順口溜一樣說出Cisco或者H3C裝置的配置命令,對於Linux的VLAN配置卻存在大量的疑問。這些疑問之所以存在我覺得有兩點原因: 
1.對VLAN的本質還是沒有理解。 
不管你的Cisco/H3C命令敲得再熟練,如果看不懂Linux的vconfig,那麼也將無法掩飾你對概念理解的淺顯; 
2.對Linux實現虛擬網路裝置風格不熟悉 

可能你已經十分理解802.1q了,也許還看過了IEEE的文件,然而卻對Linux的Bridge,tap,bond等虛擬裝置不是很理解,那麼也將無法順利配置VLAN。

對於VLAN概念的理解,有幾點要強調: 
1.VLAN分離了廣播域; 
2.單獨的一個VLAN模擬了一個常規的交換乙太網,因此VLAN將一個物理交換機分割成了一個或多個邏輯交換機; 
3.不同VLAN之間通訊需要三層參與; 
4.當多臺交換機級聯時,VLAN通過VID來識別,該ID插入到標準的以太幀中,被稱作tag; 
5.大多數的tag都不是端到端的,一般在上行路上第一個VLAN交換機打tag,下行鏈路的最後一個VLAN交換機去除tag; 
6.只有在一個資料幀不打tag就不能區分屬於哪個VLAN時才會打上tag,能去掉時儘早要去掉tag; 
7.最終,IEEE 802.1q解決了VLAN的tag問題。除了IEEE 802.1q,其餘的都是和實現相關的,雖然Cisco和H3C的實現很類似,Linux可以和它們有大不同。
 
關鍵看最後3點,也就是3,4,5。這是VLAN最難理解的部分,不過一旦理解了,VLAN也就不剩下什麼了。為了使得敘述上以及配置上更加的方便,Cisco以及其他的廠商定義了很多的細節,而這些細節在IEEE 802.1q標準中並沒有被定義,這些細節包括但不侷限於以下幾點: 

1.每一個VLAN交換機埠需要繫結一個VLAN id;

2.每一個VLAN交換機埠處於下面三類中的一類:access,trunk,hybrid。

2.1.access埠:從此類埠收到的資料幀是不打tag的,從此類埠發出的資料幀是不打tag的;

2.2.trunck埠:從此類埠收到的資料幀打著tag,從此類埠發出的資料幀需要打tag(不考慮預設VLAN的情況);

2.3.hybrid埠:略

我們實則沒有必要去深究Cisco/H3C的命令以及到底那三類埠型別有何區別,之所以有三類埠型別完全是為了將VLAN的概念(最終的IEEE 802.1q標準)很方便的用起來。說白了,trunk埠的存在是因為不得已,因為有屬於多個VLAN的資料幀要通過單一的物理鏈路,不打tag是無法區分各自屬於哪個VLAN的,於是就有了IEEE 802.1q這個標準,定義了一個tag插入到以太幀中,為了使這個理論性的東西被使用起來,廠商便定義了一系列的概念性的東西,比如和tag相關的鏈路就是trunk鏈路之類。 
        於是乎,我們可以完全拋開任何的配置命令,拋開任何廠商定義的東西,完全按照IEEE 802.1q標準以及我們的需求來理解VLAN,這樣下來之後,你絕對可以在Linux上完美實現任何VLAN配置了。首先我們定義一下我們的需求以及滿足該需求的網路拓撲,關鍵看如何接線。 

1.情況一.同一VLAN內部通訊

1.1.同一交換機同一VLAN的不同埠進行通訊

 

1.2.不同交換機的不同埠進行通訊

 

2.情況二.不同VLAN之間通訊

2.1.同一交換機不同VLAN之間進行通訊

 

2.2.不同交換機的不同VLAN進行通訊

從上述1.2可以看出,為了節省線纜和避免環路,兩個VLAN交換機的兩個埠之間的同一條鏈路需要承載不同的VLAN資料幀,為了使彼此能夠識別每個資料幀到底屬於哪個VLAN,十分顯然的辦法就是為資料幀打上tag,因此上述1.2中的埠J和埠K之間的鏈路上的資料幀需要打tag,埠J和埠K都同屬於兩個VLAN,分別為VLAN m和VLAN n。換句話說,只要一個埠需要傳輸和接收屬於多個VLAN的資料幀,那麼從該埠發出的資料幀就要打上tag,從該埠接收的資料幀可以通過tag來識別它屬於哪個VLAN,用Cisco/H3C等廠商的術語來講,它就是trunk埠,兩個trunck埠之間的鏈路屬於trunk鏈路。 
        我們知道,一般而言,我們的PC機直接連線在常規二層交換機或者支援VLAN的交換機埠上,而我們的PC機發出的一般都是常規的乙太網資料幀,這些資料幀是沒有tag的,它們可能根本不知道802.1q為何物,然而VLAN存在的目的就是把一些PC機劃在一個VLAN中,而把另一些PC機劃在另一個VLAN中從而實現隔離,那麼很顯然的一種辦法就是將支援VLAN的交換機的某些埠劃在一個VLAN,而另一些埠劃在另一個VLAN中,一個VLAN的所有埠其實就形成了一個邏輯上的二層常規交換機,同屬於一個VLAN的PC機連線在劃在同一個VLAN的埠上,為了擴充套件VLAN,鑑於單臺交換機埠數量的限制,需要級聯交換機,那麼級聯鏈路上則同時承載著不同VLAN流量,因此級聯鏈路則成為trunk鏈路,所有不是級聯鏈路的鏈路都是直接鏈路,用廠商術語來講就是access鏈路(注意,這裡暫且不談hybrid),自然而然的,access鏈路兩端的埠都是和tag無關的,只需要做到“沒有tag直通,有tag去掉即可”,因此它可以連線PC機或者常規交換機以及VLAN交換機的非trunk埠。 
        VLAN的內容基本也就是以上那些了,分為三部分: 

1.設計目的

隔離廣播域,節省物理裝置,隔離安全策略域 

2.IEEE 802.1q

為擴充套件VLAN的級聯方案提供了一個標準的協議 

3.如何使用VLAN

將某些埠劃為一個VLAN,基於MAC地址什麼的... 
其實,至於怎麼劃分VLAN,標準中並沒有給出什麼硬性的規定,只要能夠保證屬於同一VLAN的埠完全否則IEEE 802系列的標準即可,換句話說就是屬於同一VLAN的所有交換機的所有同一VLAN的埠完全就是一個乙太網即可,透傳以太幀。 
        到此為止,我們基本上已經忘了配置trunk,access,基於埠劃VLAN的命令了,腦子裡面留下的只是VLAN的核心概念,使用這些核心的概念,我們就可以在Linux上配置完整的VLAN方案了,如果你去硬套Cisco的配置,那麼結果只是悲哀。比如如果你問:如何在Linux上配置埠為access,如何在Linux上將某些網路卡劃到一個VLAN... 
        理解Linux Bridge的都知道,Linux本身就可以實現多個Bridge裝置,因為Linux的Bridge是軟的,所以一個Linux Box可以配置多個邏輯意義的Bridge,而多個Bridge裝置之間必須通過第三層進行通訊,加之第三層正是乙太網的邊界,因此一個Linux Box也就可以模擬多個乙太網了,不同的Bridge裝置就可以代表不同的VLAN。 

第二部分:Linux上的VLAN

Linux上的VLAN和Cisco/H3C上的VLAN不同,後者的VLAN是現有了LAN,再有V,也就是說是先有一個大的LAN,再劃分為不同的VLAN,而Linux則正好相反,由於Linux的Bridge裝置是被建立出來的邏輯裝置,因此Linux需要先建立VLAN,再建立一個Bridge關聯到該VLAN,建立VLAN很簡單: 
ifconfig eth0 0.0.0.0 up 
vconfig eth0 10 
ifconfig eth0.10 up
 
當使用vconfig建立了eth0.10之後,它就是一個“真實意義”的虛擬網路卡裝置了,類似br0,tap0,bond0之類的,在這個虛擬網路卡之下繫結的是一個真實網路卡eth0,也就是資料從eth0這塊真實網路卡發出,eth0.10中的“.10”表示它可以承載VLAN 10的資料幀,並且在通過eth0發出之前要打上tag。那麼打tag這件事自然而然就是通過eth0.10這個虛擬裝置的hard_xmit來完成的,在這個hard_xmit中,打上相應的tag後,再呼叫eth0的hard_xmit將資料真正發出,如下圖所示: 
 
因此一個真實的物理網路卡比如ethx,它可以承載多個VLAN的資料幀,因此它就是trunk埠了,如下所示: 
 
Linux的VLAN工具vconfig採用ethx.y的方式以ethx為trunk埠加入VLAN id為y的VLAN中。類比Cisco/H3C,我們已經建立了trunk,總結一下:使用vconfig建立一個ethx.y的虛擬裝置,就建立了一個trunk,其中ethx就是trunk口,而y代表該trunk口連線的trunk鏈路可以承載的VLAN資料幀的id,我們建立ethx.a,ethx.b,ethx.c,ethx.d,就說明ethx可以承載VLAN a,VLAN b,VLAN c,VLAN d的資料幀。 
        接下來,我們看一下如何建立access埠。首先注意,由於Linux的Bridge是虛擬的,邏輯意義的,因此可以先建立了VLAN之後,再根據這個VLAN動態的建立Bridge,而不是“為每一個埠配置VLAN id”,我們需要做的很簡單: 
建立VLAN: 
ifconfig eth0 0.0.0.0 up 
vconfig eth0 10 
ifconfig eth0.10 up 
為該VLAN建立Bridge: 
brctl addbr brvlan10 
brctl addif brvlan10 eth0.10 
為該VLAN新增網路卡: 
ifconfig eth1 0.0.0.0 up 
brctl addif brvlan10 eth1 
ifconfig eth2 0.0.0.0 up 
brctl addif brvlan10 eth2
 
... 
這就完了。從此,eth1和eth2就是VLAN 10的access埠了,而eth0則是一個trunk埠,級聯VLAN的時候要用到,如果不需要級聯VLAN,而僅僅需要擴充套件VLAN 10,那麼你大可將eth1連線在一個二層常規交換機或者hub上...同樣的,你可以再建立一個VLAN,同樣通過eth0來級聯上游VLAN交換機: 
ifconfig eth0 0.0.0.0 up 
vconfig eth0 20 
ifconfig eth0.20 up 
brctl addbr brvlan20 
brctl addif brvlan20 eth0.20 
ifconfig eth5 0.0.0.0 up 
brctl addif brvlan20 eth5
 
如下圖所示: 
 
這下基本就搞定了Linux上VLAN的配置,接下來還有一個內容,那就是VLAN之間的通訊。這個知識點最簡單了,那就是使用路由,為此很多人把支援VLAN的三層交換機和路由器等同起來。既然使用路由就需要一個IP地址作為閘道器,那麼如何能定址到這個IP地址自然就是一個不可迴避的問題,我們要把這個IP配置在哪裡呢?可以肯定的是,必須配置在當前VLAN的某處,於是我們有多個地方可以配置這個IP: 

1.同屬於一個VLAN的路由器介面上,且該路由器有到達目的VLAN的路由(該路由器介面為trunk口)。

2.同屬於一個VLAN的ethx.y似的虛擬介面上,且該Linux Box擁有到指定VLAN a的路由(最顯然的,擁有ethx'.a虛擬介面)。

3.同屬於一個VLAN的Bridge裝置上(Linux的Bridge預設帶有一個本地介面,可以配置IP地址),且該Linux Box擁有到指定VLAN a的路由(最顯然的,擁有ethx'.a虛擬介面或者目標VLAN的Bridge裝置)。

其中的1和2實際上沒有什麼差別,本質上就是找一個能配置IP地址的地方,大多數情況下使用2,但是如果出現同一個VLAN在同一個Linux Box配置了兩個trunk埠,那麼就要使用Bridge的地址了,比如下面的配置: 
brctl addbr brvlan10 
brctl addif brvlan10 eth0.10 
brctl addif brvlan10 eth1.10 
ifconfig brvlan10 up
 
此時有兩個ethx.y型的虛擬介面,為了不使路由衝突,只能配置一個IP,那麼此IP地址就只能配置在brvlan10上了。不管配置在Bridge上還是配置在ethx.y上,都是要走IP路由的,只要MAC地址指向了本地的任意的一個介面,在netif_receive_skb呼叫handle_bridge的時候都會將資料幀導向本地的IP路由來處理。Linux作為一個軟體,其並沒有原生實現硬體cache轉發,因此對於Linux而言,所謂的三層交換其實就是路由。 
        我們看一下一個被打上tag的資料幀什麼時候脫去這個tag,在定義上,它是從access埠發出時脫去的,然而在語義上,只要能保證access埠發出的資料幀不帶有tag即可,因此對於何時脫去tag並沒有什麼嚴格的要求。在Linux的VLAN實現上,packet_type的func作為一個第三層的處理函式來單獨處理802.1q資料幀,802.1q此時和IP協議處於一個同等的位置,VLAN的func函式vlan_skb_recv正如IP的處理函式ip_rcv一樣。在Linux實現的VLAN中,只有當一個埠收到了一個資料幀,並且該資料幀是發往本地的時候,才會到達第三層的packet_type的func處理,否則只會被第二層處理,也就是Bridge邏輯處理,Linux的原生Bridge實現並不能處理802.1q資料幀,甚至都不能識別它。整個trunk口收發資料幀,IEEE 802.1q幀處理,以及VLAN間通訊的示意圖如下: 

 

到此為止,Linux的VLAN要點基本已經說完了,有了這些理解,我想設計一個單臂Linux Box就不是什麼難事了,單臂裝置最大的優勢就是節省物理裝置,同時還能實現隔離。這個配置不復雜,如果不想用VLAN實現的話也可以用ip addr add dev ...增加虛擬IP的方式來實現,然而用VLAN實現的好處在於可以和既有的三層交換機進行聯動,也可以直接插在支援標準的IEEE 802.1q的裝置的trunk口上。 
         機制搭臺,策略唱戲。既然VLAN的實現機制已經瞭然於胸了,那麼它的缺點估計你也看到了,如何去克服呢?PVLAN說實在的是一個VLAN的替代方案。解決了VLAN間的IP網段隔離問題,我們在Linux上如何實現它呢?這倒也不難,無非就是在LAN上新增一些訪問控制策略罷了,完全可以用純軟體的方式來實現,甚至都可以用ebtables/arptables/iptables來實現一個PVLAN。如果說VLAN是一個硬實現的VLAN的話,那麼PVLAN純粹是一個軟實現的VLAN,甚至都不需要劃分什麼VLAN,大家都處於一個IP網段,只需要配置好訪問控制策略即可,使得同一IP子網的Host只能和預設閘道器通訊,而之間不能通訊,所以說,即使你不知道“隔離VLAN”,“團體VLAN”之類的術語,實際上你已經實現了一個PVLAN了。 

第三部分:幾點總結

1.你需要首先規劃出你的網路拓撲而不是先去研究VLAN在Linux上如何配置以及如何實現; 
2.你需要深入理解VLAN設計的初衷,該配置哪些東西; 
3.你需要知道對於VLAN哪些概念是核心,哪些概念並不是必須的。 
4.不管基於什麼平臺配置VLAN,只有兩點是必須的:a.哪些埠屬於哪個VLAN;b.哪個埠是級聯埠,屬於多個VLAN。 

5.其它的都不用去死記硬背,都是浮雲...


附:

http://wenku.baidu.com/link?url=JQpTuK37_A5rT_hR0gj8x7oIbB7RyayCRGKKX4MlixW3_z9ROdzbY8ISDb8zdL6rpN6NG9gl-Hs1rGxB6wsvit9gxdBgw_GaowxRM6V-Jly   802.1Q_VLAN簡介

相關文章