Linux 网络协议栈开发—— 二层桥实现原理
網橋原理:
網橋工作在鏈路層,所以它是二層的東西,對于以太網來說網橋和二層網絡設備交換機的工作方式幾乎是一樣的,每個交換機包含一系列以太網接口,交換機通過其內部的硬件交換芯片實現對這些以太網接口出入報文的二層接收轉發及過濾等二層qos功能,網橋在功能上和交換機幾乎是一樣的,只不過它是由軟件實現這些功能。
下圖是交換機和網橋的內部實現原理簡圖:
二層交換機內部實現簡圖
網橋內部實現簡圖
如上圖,可以把網橋本身看做一個二層交換機,該交換機下面有eth0、usb1、vlan2、wlan3共4個接口,每個網橋下可以有很多個接口,不考慮STP生成樹協議的話,可以認為網橋下接口是由用戶配置的,普遍用brctl應用程序工具生成網橋,并在每個網橋下增加和刪除接口,brctl使用舉例如下:
初始情況下,沒有網橋,由命令“brctl addbr br0”創建一個網橋br0,然后可以觀察到創建了網橋br0,此時它底下還沒有接口,然后由命令“brctl addif br0 XXX”在網橋br0下加入接口eth1、eth2,然后可以觀察到網橋br0底下有這兩個接口;同時網橋br0的MAC地址表還加入了兩個靜態的MAC地址,分別是接口eth1和eth2的MAC地址,這時如果從eth1接口進入屬于網橋br0的報文,并且該報文的目的MAC地址與eth2接口的MAC地址相同,那么報文將被從eth2接口轉發出去,并且會記錄該報文的源MAC地址和進入接口eth1的對應關系作為網橋br0的一個動態MAC地址條目。
再如,我們的網關設備做測試時,如需測試二層業務流性能,經常把wan接口和vlan1接口做橋接,然后即可打雙向二層業務流,同樣是通過網橋學習兩個接口進入報文的源MAC地址和進入接口的對應關系,實現網橋的兩個接口對打二層業務流,由此可見,這和二層交換機的MAC地址學習和轉發的道理是一樣的。
【文章福利】小編推薦自己的Linux內核技術交流群:【977878001】整理一些個人覺得比較好得學習書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!!!前100進群領取,額外贈送一份價值699的內核資料包(含視頻教程、電子書、實戰項目及代碼)內核資料直通車:Linux內核源碼技術學習路線+視頻教程代碼資料
學習直通車:Linux內核源碼/內存調優/文件系統/進程管理/設備驅動/網絡協議棧
此外,linux的網橋同樣還實現了多種多樣的報文處理功能,同樣依托netfilter框架,通過不同的hook點掛載不同的包處理環節,其qos功能可以比二層交換機還要豐富。
1、linux的網橋實現:
1.1、涉及文件:
Linux網橋實現在代碼樹的net/bridge/目錄下,主要文件如下:
- l br.c:網橋模塊初始化;
- l br_device.c:網橋net_device的ops實現;
- l br_fdb.c:網橋的MAC地址表實現;
- l br_forward.c:網橋的報文轉發邏輯實現;
- l br_if.c:網橋及橋端口的創建增刪操作;
- l br_input.c:網橋的報文處理函數;
- l br_ioctl.c:網橋的用戶ioctl接口;
- l br_netfilter.c:網橋的netfilter框架及默認掛載的hook;
- l br_netlink.c:網橋的netlink接口;
- l br_notify.c:網橋的內核通知鏈;
- l 其余文件為網橋的STP協議相關和默認的netfilter處理函數實現;
1.2、重要數據結構:
1.2.1、網橋創建:
我們知道linux內核協議棧的鏈路層中,任何一個收發實體都是以結構體net_device描述的,這一個個的收發實體可以是有實際物理設備支持的,如常見的以太網卡設備ethX、usb網卡設備、無線網卡設備等等,也可以是沒有實際物理設備支持的虛擬網卡設備,如vlan接口、網橋接口,之所以這樣做是因為在內核中對收發實體的一切處理邏輯都是統一的接口,事實上這體現的就是linux內核面向對象的重要思想。
所以每一個網橋在linux內核中也都是以net_device結構體描述,不同的是網橋net_device的私貨部分是結構體net_bridge,它描述了網橋與其他類型net_device諸如以太網卡設備、vlan接口等的區別,事實上不同類型的net_device,其區別主要是通過私貨部分標識,對于網橋net_device它的私貨就是結構體net_bridge,如下圖:
如不考慮STP生成樹協議部分的內容,net_bridge結構最值得注意的字段如下:
1、dev:它標識該網橋自身的net_device,對于IP層及以上協議,鏈路層可見的是網橋,而不是網橋底下的接口,所以上層操作的net_device都是網橋的net_device;另外網橋自身的net_device也是區分不同網橋的依據,這些是該字段存在的重要意義;
2、ageing_time:動態MAC地址的老化時間;
3、stp_enabled:標識該網橋是否開啟STP功能,默認為關閉,本文不討論STP協議相關的內容
創建了一個網橋就如同創建了一個交換機,但此時這個“交換機”底下還沒有接口
用戶應用程序(典型如brctl)創建網橋的過程如下:
創建網橋的核心函數是br_add_bridge,它創建了網橋的net_device并將其注冊進內核,注意用戶創建網橋時只需傳入網橋名稱即可;
網橋net_device的私貨是結構體net_bridge,new_bridge_dev函數對它進行初始化,主要內容包括:
- 創建了網橋自身的net_device并由私貨回指(br->dev= dev);
- 設置默認關閉STP協議(br->stp_enabled= BR_NO_STP);
- 設置網橋的默認動態MAC地址老化時間為300秒(br->ageing_time= 300 * HZ);
- 開啟動態MAC地址老化定時器(br_stp_timer_init(br));
1.2.2、網橋接口添加:
創建網橋后,需要再加入接口,網橋的每一個接口在linux內核中以net_bridge_port結構體描述,在內核中稱為橋端口,如下:
同樣如果不考慮STP協議相關內容,只需關注如下字段:
- 1、br:標識該橋端口屬于哪個網橋;
- 2、dev:標識該橋端口實際對應哪個接口;
- 3、state:標識該橋端口的狀態,一般為BR_STATE_FORWARDING即轉發;
在創建好網橋后,應用程序通過網橋的ops在網橋中加入接口,過程如下:
有了網橋,并在網橋下加入了接口,那么該網橋就可以發揮二層交換機的作用了。需要注意的問題如下:
1、同一個接口不能作為不同網橋的橋端口;
2、網橋下的橋端口,都必須是混雜模式,但網橋自身不一定是混雜模式,往往在有特殊需求時如需要抓包時,會把網橋自身接口設置為混雜模式,即網橋下所有橋端口接收到的報文都要送給本機一份;
3、每創建一個橋端口,都會把該橋端口對應接口的MAC地址作為靜態MAC地址記錄在所屬網橋的MAC地址表中,靜態MAC地址不會被老化,因為目的地址是該接口MAC地址,說明是送給該接口所在主機的報文即送本地的報文,所以不能老化掉這樣的MAC地址;
4、網橋自身接口的mtu和MAC地址是其底下所有橋接口的mtu最小值和MAC地址最小值,都也可以由用戶配置修改;
5、不考慮STP協議情況下,橋端口的狀態是轉發(BR_STATE_FORWARDING),一般情況下不必考慮橋端口的其他狀態;
2、網橋報文接收處理:
前面已經提到,linux內核對于報文收發處理使用統一的接口,在報文接收處理中,都是由驅動層接收到報文后調用函數netif_receive_skb進入協議棧處理,網橋的處理入口函數為handle_bridge,實質處理函數是br_handle_frame,流程如下:
結合上圖,網橋處理的重點如下:
1、需要進行橋接處理的報文,其輸入接口必須屬于某網橋;
2、暫不考慮STP協議報文的處理,對于上圖重點關注“報文轉發流程”框之后的內容;
3、橋接處理前會檢查用戶是否通過ebtables工具在鏈路層對報文進行過濾或其他處理,ebtables工具類似iptables工具,可以加不同的規則,區別在于它工作在鏈路層,這實現了類似二層交換機的qos功能;
4、每次報文處理都首先進行動態MAC地址的學習或更新老化時間;
5、對于某些操作,如對網橋進行抓包,這會使網橋自身接口被設置為混雜模式,這時必須把報文復制一份送至本地;
6、 組播/廣播/未知單播報文會洪泛到每個橋端口,已知單播報文若目的端口為本機則送至本機,若非本機則從對應橋端口轉發出去;可見網橋與二層交換機在單播和廣播報文的轉發方面是一樣的,唯一區別在于組播報文的處理,在我們的網關設備上通過修改內核,是不允許組播報文在網橋上傳播的;
3、網橋報文發送處理:
前面一節中已經提到,網橋net_device的ops實現在內核的br_device.c文件中,如同網卡驅動一樣,網橋作為一種特殊的網絡設備,它也有它的ops方法集,linux已定義好它,如下圖:
其中指定了網橋這種網絡設備的發送方法為函數br_dev_xmit,即比如應用程序使用send函數族系統調用從網橋發送報文時,將最終調用br_dev_xmit函數,其處理邏輯依然遵循網橋原理或者說就是二層交換原理,已知單播報文即按MAC地址轉發,廣播/組播/未知單播報文洪泛到所有橋端口,處理流程如下:
4、網橋不同情況下的報文流向:
4.1、傳入本機:
切記這里的傳入本機,并不一定是要傳入本機傳輸層,而僅僅是意味著該報文的目的MAC地址是該網橋下某橋端口對應接口的MAC地址,即報文穿過網橋繼續走本機協議棧進行進一步處理,如下圖:
4.2、轉發出去:
轉發最終均調用dev_queue_xmit,這和所有的報文發送的道理是一樣的,需要注意的是轉發接口的更換和網橋轉發的兩次netfilter,如下圖:
4.3、傳入本機后再從網橋轉發:
這個情況實際是7.2.4.1中后續可能發生情況的一種,即在路由判決后,該報文應從一個網橋接口轉發,如下圖:
同理,該報文也可在傳入本機后再從某個其他接口轉發,如從某個以太網卡接口、usb接口、wlan接口等等。
總結
以上是生活随笔為你收集整理的Linux 网络协议栈开发—— 二层桥实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NEON----ARM通用 SIMD 引
- 下一篇: OrangePi3开发板使用指南