筆者在利用gns3模擬器搭建網絡實驗時,發現交換機設備和服務器之間無法成功協商LACP協議,CISCO NEXUS 9K互相之間卻可以成功協商LACP, 在交換機和服務器上抓包發現,Nexus 9K發出的LACP報文中的目的MAC地址爲00:01:02:03:04:05(而標準LACP協議中規定的是01:80:c2:00:00:02),服務器發出的LACP報文的目的MAC是01:80:c2:00:00:02。然而,進一步思考,爲什麼在gns3模擬器中, Nexus 9K的LACP的目標MAC跟標準協議不同呢?經過查閱,這是因爲在gns3上的所有虛擬設備都是運行在同一個物理服務器上,互相之間通過網橋相連,默認情況下,linux的網橋會將01:80:c2:00:00:0x的目標MAC地址全部過濾,Nexus 9K爲了避免該問題調整了LACP的目標MAC, 而服務器卻沒有調整。調整group_fwd_mask這個內核參數,可以控制linux網橋對MAC地址的過濾範圍,這也是本文想要探討的問題。
IEEE 802.1D協議中規定的網橋過濾MAC地址
下面一段話引用自IEEE Standard Group MAC Addresses tutorial,IEEE 802.1D協議規定,01-80-C2-00-00-00 -- 01-80-C2-00-00-0F是IEEE爲標準協議留出的範圍,使用這些地址的包將被網橋過濾,而不會被轉發。
IEEE 802.1D MAC Bridge Filtered MAC Group Addresses: 01-80-C2-00-00-00 to 01-80-C2-00-00-0F; MAC frames that have a destination MAC address within this range are not relayed by MAC bridges conforming to IEEE 802.1D.
IEEE協議中規定的預留的MAC地址表如下:
MAC address | Protocol |
01-80-C2-00-00-00 | Spanning Tree (STP/RSPT/MSTP) |
01-80-C2-00-00-01 | Ethernet Flow Control (pause frames) |
01-80-C2-00-00-02 | Link Aggregation Control Protocol (LACP) |
01-80-C2-00-00-03 | 802.1X Port-Based Network Access Control |
01-80-C2-00-00-08 | Provider Bridge protocols (STP) |
01-80-C2-00-00-0D | Provider Bridge protocols (MVRP) |
01-80-C2-00-00-0E | 802.1AB Link Layer Discovery Protocol (LLDP) |
出現的問題
所有使用上述MAC地址的協議,都會被網橋過濾掉(因爲網橋符合IEEE 802.1D協議的規定),如果使用的是物理網橋,這樣的情況將無法改變,但是對於linux中的虛擬網橋呢,是不是也是一樣呢?默認情況下,linux的虛擬網橋完全符合IEEE 802.1D的規定,跟物理網橋一樣,完全過濾了目的MAC地址爲01-80-C2-00-00-0x的協議,因此造成了本文開頭所述的情況。
解決方法
那怎樣才能在gns3上模擬這麼多被過濾的協議呢?顯然一定還有其他人遇到過相同的問題,只要google一下便不難找到解決方法了。從Linux Kernel 2.6開始,就可以通過調整內核參數/sys/class/net/bridge-iface/bridge/group_fwd_mask來控制虛擬網橋對802.1D中規定的地址範圍中,哪些MAC地址不再過濾。/sys/class/net/bridge-iface/bridge/group_fwd_mask的默認值爲0,意味着將對01-80-C2-00-00-0x的所有地址進行過濾。將/sys/class/net/bridge-iface/bridge/group_fwd_mask的值設爲16384, 則可以讓虛擬網橋轉發LLDP報文(目的MAC: 01-80-C2-00-00-0E)
echo 16384 > /sys/class/net/br0/bridge/group_fwd_mask
需要注意的是,在默認的發行版本中,對於該MAC地址範圍中的前三個(-00,-01,-02)是不能通過以上方式控制的, 意味着在gns3的模擬環境中,我們仍然不能成功的測試STP,流控和LACP。要克服這個限制,必須要自己編譯linux kernel纔行,點擊查看方法,也可以下載EVE編譯好的版本,點擊進入鏈接。這樣就可以隨意調整group_fwd_mask的值,支持不過濾01-80-C2-00-00-0x的所有地址了。
bitmasks和group_fwd_mask
前文中把group_fwd_mask設爲16384,對應的MAC是01-80-C2-00-00-0E,對應的協議是LLDP, 那麼group_fwd_mask是如何計算的呢?
例1: 如果要允許01-80-C2-00-00-0E,對應的表格如下,MAC地址的最後兩位是0E, 則將下表中的0E的bit置爲1。
MAC | 0F | 0E | 0D | 0C | 0B | 0A | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
BIT | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
bitmasks是二進制數0100 0000 0000 0000, 轉換成10進制則爲16384。
例2: 如果要允許01-80-C2-00-00-0E,01-80-C2-00-00-03,01-80-C2-00-00-02, 則對應的表如下, 將表中的0E,03,02的bit置爲1。
MAC | 0F | 0E | 0D | 0C | 0B | 0A | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
BIT | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
bitmasks是二進制數0100 0000 0000 1100, 轉換成10進制則爲16396。這樣就可以允許LLDP,LACP,802.1x協議了。
按照這樣的方法,要解除linux網橋對規定地址範圍內所有地址的過濾,就把所有的bit都置爲1 即可:
- 打過patch的kernel:
echo 65535 > /sys/class/net/br0/bridge/group_fwd_mask
- 官方kernel(最後3位不能爲1):
echo 65528 > /sys/class/net/br0/bridge/group_fwd_mask
注意
在生產環境中要慎用這個參數,否則可能造成bridge轉發很多不必要的包造成網絡風暴引起故障或性能下降。但在使用linux搭建虛擬網絡實驗環境時還是非常有用的,可以實現各種協議的模擬。