1. 程式人生 > >Linux 上的基礎網路裝置詳解

Linux 上的基礎網路裝置詳解

Linux 抽象網路裝置簡介

和磁碟裝置類似,Linux 使用者想要使用網路功能,不能通過直接操作硬體完成,而需要直接或間接的操作一個 Linux 為我們抽象出來的裝置,既通用的 Linux 網路裝置來完成。一個常見的情況是,系統裡裝有一個硬體網絡卡,Linux 會在系統裡為其生成一個網路裝置例項,如 eth0,使用者需要對 eth0 發出命令以配置或使用它了。更多的硬體會帶來更多的裝置例項,虛擬的硬體也會帶來更多的裝置例項。隨著網路技術,虛擬化技術的發展,更多的高階網路裝置被加入了到了 Linux 中,使得情況變得更加複雜。在以下章節中,將一一分析在虛擬化技術中經常使用的幾種 Linux 網路裝置抽象型別:Bridge、802.1.q VLAN device、VETH、TAP,詳細解釋如何用它們配合 Linux 中的 Route table、IP table 簡單的創建出本地虛擬網路。

回頁首

相關網路裝置工作原理

Bridge

Bridge(橋)是 Linux 上用來做 TCP/IP 二層協議交換的裝置,與現實世界中的交換機功能相似。Bridge 裝置例項可以和 Linux 上其他網路裝置例項連線,既 attach 一個從裝置,類似於在現實世界中的交換機和一個使用者終端之間連線一根網線。當有資料到達時,Bridge 會根據報文中的 MAC 資訊進行廣播、轉發、丟棄處理。

圖 1.Bridge 裝置工作過程

如圖所示,Bridge 的功能主要在核心裡實現。當一個從裝置被 attach 到 Bridge 上時,相當於現實世界裡交換機的埠被插入了一根連有終端的網線。這時在核心程式裡,netdev_rx_handler_register()被呼叫,一個用於接受資料的回撥函式被註冊。以後每當這個從裝置收到資料時都會呼叫這個函式可以把資料轉發到 Bridge 上。當 Bridge 接收到此資料時,br_handle_frame()被呼叫,進行一個和現實世界中的交換機類似的處理過程:判斷包的類別(廣播/單點),查詢內部 MAC 埠對映表,定位目標埠號,將資料轉發到目標埠或丟棄,自動更新內部 MAC 埠對映表以自我學習。

Bridge 和現實世界中的二層交換機有一個區別,圖中左側畫出了這種情況:資料被直接發到 Bridge 上,而不是從一個埠接受。這種情況可以看做 Bridge 自己有一個 MAC 可以主動傳送報文,或者說 Bridge 自帶了一個隱藏埠和寄主 Linux 系統自動連線,Linux 上的程式可以直接從這個埠向 Bridge 上的其他埠發資料。所以當一個 Bridge 擁有一個網路裝置時,如 bridge0 加入了 eth0 時,實際上 bridge0 擁有兩個有效 MAC 地址,一個是 bridge0 的,一個是 eth0 的,他們之間可以通訊。由此帶來一個有意思的事情是,Bridge 可以設定 IP 地址。通常來說 IP 地址是三層協議的內容,不應該出現在二層裝置 Bridge 上。但是 Linux 裡 Bridge 是通用網路裝置抽象的一種,只要是網路裝置就能夠設定 IP 地址。當一個 bridge0 擁有 IP 後,Linux 便可以通過路由表或者 IP 表規則在三層定位 bridge0,此時相當於 Linux 擁有了另外一個隱藏的虛擬網絡卡和 Bridge 的隱藏埠相連,這個網絡卡就是名為 bridge0 的通用網路裝置,IP 可以看成是這個網絡卡的。當有符合此 IP 的資料到達 bridge0 時,核心協議棧認為收到了一包目標為本機的資料,此時應用程式可以通過 Socket 接收到它。一個更好的對比例子是現實世界中的帶路由的交換機裝置,它也擁有一個隱藏的 MAC 地址,供裝置中的三層協議處理程式和管理程式使用。裝置裡的三層協議處理程式,對應名為 bridge0 的通用網路裝置的三層協議處理程式,即寄主 Linux 系統核心協議棧程式。裝置裡的管理程式,對應 bridge0 寄主 Linux 系統裡的應用程式。

Bridge 的實現當前有一個限制:當一個裝置被 attach 到 Bridge 上時,那個裝置的 IP 會變的無效,Linux 不再使用那個 IP 在三層接受資料。舉例如下:如果 eth0 本來的 IP 是 192.168.1.2,此時如果收到一個目標地址是 192.168.1.2 的資料,Linux 的應用程式能通過 Socket 操作接受到它。而當 eth0 被 attach 到一個 bridge0 時,儘管 eth0 的 IP 還在,但應用程式是無法接受到上述資料的。此時應該把 IP 192.168.1.2 賦予 bridge0。

另外需要注意的是資料流的方向。對於一個被 attach 到 Bridge 上的裝置來說,只有它收到資料時,此包資料才會被轉發到 Bridge 上,進而完成查表廣播等後續操作。當請求是傳送型別時,資料是不會被轉發到 Bridge 上的,它會尋找下一個傳送出口。使用者在配置網路時經常忽略這一點從而造成網路故障。

VLAN device for 802.1.q

VLAN 又稱虛擬網路,是一個被廣泛使用的概念,有些應用程式把自己的內部網路也稱為 VLAN。此處主要說的是在物理世界中存在的,需要協議支援的 VLAN。它的種類很多,按照協議原理一般分為:MACVLAN、802.1.q VLAN、802.1.qbg VLAN、802.1.qbh VLAN。其中出現較早,應用廣泛並且比較成熟的是 802.1.q VLAN,其基本原理是在二層協議裡插入額外的 VLAN 協議資料(稱為 802.1.q VLAN Tag),同時保持和傳統二層裝置的相容性。Linux 裡的 VLAN 裝置是對 802.1.q 協議的一種內部軟體實現,模擬現實世界中的 802.1.q 交換機。

圖 2 .VLAN 裝置工作過程

如圖所示,Linux 裡 802.1.q VLAN 裝置是以母子關係成對出現的,母裝置相當於現實世界中的交換機 TRUNK 口,用於連線上級網路,子裝置相當於普通介面用於連線下級網路。當資料在母子裝置間傳遞時,核心將會根據 802.1.q VLAN Tag 進行對應操作。母子裝置之間是一對多的關係,一個母裝置可以有多個子裝置,一個子裝置只有一個母裝置。當一個子裝置有一包資料需要傳送時,資料將被加入 VLAN Tag 然後從母裝置傳送出去。當母裝置收到一包資料時,它將會分析其中的 VLAN Tag,如果有對應的子裝置存在,則把資料轉發到那個子裝置上並根據設定移除 VLAN Tag,否則丟棄該資料。在某些設定下,VLAN Tag 可以不被移除以滿足某些監聽程式的需要,如 DHCP 服務程式。舉例說明如下:eth0 作為母裝置建立一個 ID 為 100 的子裝置 eth0.100。此時如果有程式要求從 eth0.100 傳送一包資料,資料將被打上 VLAN 100 的 Tag 從 eth0 傳送出去。如果 eth0 收到一包資料,VLAN Tag 是 100,資料將被轉發到 eth0.100 上,並根據設定決定是否移除 VLAN Tag。如果 eth0 收到一包包含 VLAN Tag 101 的資料,其將被丟棄。上述過程隱含以下事實:對於寄主 Linux 系統來說,母裝置只能用來收資料,子裝置只能用來發送資料。和 Bridge 一樣,母子裝置的資料也是有方向的,子裝置收到的資料不會進入母裝置,同樣母裝置上請求傳送的資料不會被轉到子裝置上。可以把 VLAN 母子裝置作為一個整體想象為現實世界中的 802.1.q 交換機,下級介面通過子裝置連線到寄主 Linux 系統網路裡,上級介面同過主裝置連線到上級網路,當母裝置是物理網絡卡時上級網路是外界真實網路,當母裝置是另外一個 Linux 虛擬網路裝置時上級網路仍然是寄主 Linux 系統網路。

需要注意的是母子 VLAN 裝置擁有相同的 MAC 地址,可以把它當成現實世界中 802.1.q 交換機的 MAC,因此多個 VLAN 裝置會共享一個 MAC。當一個母裝置擁有多個 VLAN 子裝置時,子裝置之間是隔離的,不存在 Bridge 那樣的交換轉發關係,原因如下:802.1.q VLAN 協議的主要目的是從邏輯上隔離子網。現實世界中的 802.1.q 交換機存在多個 VLAN,每個 VLAN 擁有多個埠,同一 VLAN 埠之間可以交換轉發,不同 VLAN 埠之間隔離,所以其包含兩層功能:交換與隔離。Linux VLAN device 實現的是隔離功能,沒有交換功能。一個 VLAN 母裝置不可能擁有兩個相同 ID 的 VLAN 子裝置,因此也就不可能出現數據交換情況。如果想讓一個 VLAN 裡接多個裝置,就需要交換功能。在 Linux 裡 Bridge 專門實現交換功能,因此將 VLAN 子裝置 attach 到一個 Bridge 上就能完成後續的交換功能。總結起來,Bridge 加 VLAN device 能在功能層面完整模擬現實世界裡的 802.1.q 交換機。

Linux 支援 VLAN 硬體加速,在安裝有特定硬體情況下,圖中所述核心處理過程可以被放到物理裝置上完成。

TAP 裝置與 VETH 裝置

TUN/TAP 裝置是一種讓使用者態程式向核心協議棧注入資料的裝置,一個工作在三層,一個工作在二層,使用較多的是 TAP 裝置。VETH 裝置出現較早,它的作用是反轉通訊資料的方向,需要傳送的資料會被轉換成需要收到的資料重新送入核心網路層進行處理,從而間接的完成資料的注入。

圖 3 .TAP 裝置和 VETH 裝置工作過程

如圖所示,當一個 TAP 裝置被建立時,在 Linux 裝置檔案目錄下將會生成一個對應 char 裝置,使用者程式可以像開啟普通檔案一樣開啟這個檔案進行讀寫。當執行 write()操作時,資料進入 TAP 裝置,此時對於 Linux 網路層來說,相當於 TAP 裝置收到了一包資料,請求核心接受它,如同普通的物理網絡卡從外界收到一包資料一樣,不同的是其實資料來自 Linux 上的一個使用者程式。Linux 收到此資料後將根據網路配置進行後續處理,從而完成了使用者程式向 Linux 核心網路層注入資料的功能。當用戶程式執行 read()請求時,相當於向核心查詢 TAP 裝置上是否有需要被髮送出去的資料,有的話取出到使用者程式裡,完成 TAP 裝置的傳送資料功能。針對 TAP 裝置的一個形象的比喻是:使用 TAP 裝置的應用程式相當於另外一臺計算機,TAP 裝置是本機的一個網絡卡,他們之間相互連線。應用程式通過 read()/write()操作,和本機網路核心進行通訊。

VETH 裝置總是成對出現,送到一端請求傳送的資料總是從另一端以請求接受的形式出現。該裝置不能被使用者程式直接操作,但使用起來比較簡單。建立並配置正確後,向其一端輸入資料,VETH 會改變資料的方向並將其送入核心網路核心,完成資料的注入。在另一端能讀到此資料。

回頁首

網路設定舉例說明

為了更好的說明 Linux 網路裝置的用法,下面將用一系列的例子,說明在一個複雜的 Linux 網路元素組合出的虛擬網路裡,資料的流向。網路設定簡介如下:一箇中心 Bridge:bridge0 下 attach 了 4 個網路裝置,包括 2 個 VETH 裝置,1 個 TAP 裝置 tap0,1 個物理網絡卡 eth0。在 VETH 的另外一端又建立了 VLAN 子裝置。Linux 上共存在 2 個 VLAN 網路,既 vlan100 與 vlan200。物理網絡卡和外部網路相連,並且在它之下建立了一個 VLAN ID 為 200 的 VLAN 子裝置。

從 vlan100 子裝置傳送 ARP 報文

圖 4 .ARP from vlan100 child device

如圖所示,當用戶嘗試 ping 192.168.100.3 時,Linux 將會根據路由表,從 vlan100 子裝置發出 ARP 報文,具體過程如下:

1) 使用者 ping 192.168.100.3

2) Linux 向 vlan100 子裝置傳送 ARP 資訊。

3) ARP 報文被打上 VLAN ID 100 的 Tag 成為 [email protected],轉發到母裝置上。

4) VETH 裝置將這一發送請求轉變方向,成為一個需要接受處理的報文送入核心網路模組。

5) 由於對端的 VETH 裝置被加入到了 bridge0 上,並且核心發現它收到一個報文,於是報文被轉發到 bridge0 上。

6) bridge0 處理此 [email protected] 資訊,根據 TCP/IP 二層協議發現是一個廣播請求,於是向它所知道的所有埠廣播此報文,其中一路進入另一對 VETH 裝置的一端,一路進入 TAP 裝置 tap0,一路進入物理網絡卡裝置 eth0。此時在 tap0 上,使用者程式可以通過 read()操作讀到 [email protected],eth0 將會向外界傳送 [email protected],但 eth0 的 VLAN 子裝置不會收到它,因為此資料方向為請求傳送而不是請求接收。

7) VETH 將請求方向轉換,此時在另一端得到請求接受的 [email protected] 報文。

8) 對端 VETH 裝置發現有資料需要接受,並且自己有兩個 VLAN 子裝置,於是執行 VLAN 處理邏輯。其中一個子裝置是 vlan100,與 [email protected] 吻合,於是去除 VLAN ID 100 的 Tag 轉發到這個子裝置上,重新成為標準的乙太網 ARP 報文。另一個子裝置由於 ID 不吻合,不會得到此報文。

9) 此 VLAN 子裝置又被 attach 到另一個橋 bridge1 上,於是轉發自己收到的 ARP 報文。

10) bridge1 廣播 ARP 報文。

11) 最終另外一個 TAP 裝置 tap1 收到此請求傳送報文,使用者程式通過 read()可以得到它。

從 vlan200 子裝置傳送 ARP 報文

圖 5 .ARP from vlan200 child device

和前面情況類似,區別是 VLAN ID 是 200,對端的 vlan200 子裝置設定為 reorder_hdr = 0,表示此裝置被要求保留收到的報文中的 VLAN Tag。此時子裝置會收到 ARP 報文,但是帶了 VLAN ID 200 的 Tag,既 [email protected]

從中心 bridge 傳送 ARP 報文

圖 5 .ARP from central bridge

當 bridge0 擁有 IP 時,通過 Linux 路由表使用者程式可以直接將 ARP 報文發向 bridge0。這時 tap0 和外部網路都能收到 ARP,但 VLAN 子裝置由於 VLAN ID 過濾的原因,將收不到 ARP 資訊。

從外部網路向物理網絡卡傳送 [email protected] 報文

圖 6 .ARP from external network

當外部網路連線在一個支援 VLAN 並且對應埠為 vlan200 時,此情況會發生。此時所有的 VLAN ID 為 200 的 VLAN 子裝置都將接受到報文,如果設定 reorder_hdr=0 則會收到帶 Tag 的 [email protected]

從 TAP 裝置以 ping 方式傳送 ARP

圖 7 .ping from TAP device

給 tap0 賦予 IP 並加入路由,此時再 Ping 其對應網段的未知 IP 會產生 ARP 傳送請求。需要注意的是此時由於 tap0 上存在的是傳送而不是接收請求,因此 ARP 報文不會被轉發到橋上,從而什麼也不會發生。圖中右邊畫了一個類似情況:從 vlan200 子裝置傳送 ARP 請求。由於缺少 VETH 裝置反轉請求方向,因此報文也不會被轉發到橋上,而是直接通過物理網絡卡發往外部網路。

以檔案操作方式從 TAP 裝置傳送報文

圖 8 .file operation on TAP device

使用者程式指定 tap0 裝置傳送報文有兩種方式:socket 和 file operation。當用 socket_raw 標誌新建 socket 並指定裝置編號時,可以要求核心將報文從 tap0 傳送。但和前面的 ping from tap0 情況類似,由於報文方向問題,訊息並不會被轉發到 bridge0 上。當用 open()方式開啟 tap 裝置檔案時,情況有所不同。當執行 write()操作時,核心認為 tap0 收到了報文,從而會觸發轉發動作,bridge0 將收到它。如果傳送的報文如圖所示,是一個以 A 為目的地的攜帶 VLAN ID 100 Tag 的單點報文,bridge0 將會找到對應的裝置進行轉發,對應的 VLAN 子裝置將收到沒有 VLAN ID 100 Tag 的報文。

回頁首

Linux 上配置網路裝置命令舉例

以 Redhat6.2 紅帽 Linux 發行版為例,如果已安裝 VLAN 核心模組和管理工具 vconfig,TAP/TUN 裝置管理工具 tunctl,那麼可以用以下命令設定前述網路裝置:

  • 建立 Bridge:brctl addbr [BRIDGE NAME]
  • 刪除 Bridge:brctl delbr [BRIDGE NAME]
  • attach 裝置到 Bridge:brctl addif [BRIDGE NAME] [DEVICE NAME]
  • 從 Bridge detach 裝置:brctl delif [BRIDGE NAME] [DEVICE NAME]
  • 查詢 Bridge 情況:brctl show
  • 建立 VLAN 裝置:vconfig add [PARENT DEVICE NAME] [VLAN ID]
  • 刪除 VLAN 裝置:vconfig rem [VLAN DEVICE NAME]
  • 設定 VLAN 裝置 flag:vconfig set_flag [VLAN DEVICE NAME] [FLAG] [VALUE]
  • 設定 VLAN 裝置 qos:

vconfig set_egress_map [VLAN DEVICE NAME] [SKB_PRIORITY] [VLAN_QOS]

vconfig set_ingress_map [VLAN DEVICE NAME] [SKB_PRIORITY] [VLAN_QOS]

  • 查詢 VLAN 裝置情況:cat /proc/net/vlan/[VLAN DEVICE NAME]
  • 建立 VETH 裝置:ip link add link [DEVICE NAME] type veth
  • 建立 TAP 裝置:tunctl -p [TAP DEVICE NAME]
  • 刪除 TAP 裝置:tunctl -d [TAP DEVICE NAME]
  • 查詢系統裡所有二層裝置,包括 VETH/TAP 裝置:ip link show
  • 刪除普通二層裝置:ip link delete [DEVICE NAME] type [TYPE]

回頁首

小結

綜上所述,Linux 已經提供一套基本工具供使用者創建出各種內部網路,利用這些工具可以方便的創建出特定網路給應用程式使用,包括雲端計算中的初級內部虛擬網路。

原文連結:https://www.ibm.com/developerworks/community/blogs/5144904d-5d75-45ed-9d2b-cf1754ee936a/entry/linux_%25e4%25b8%258a%25e7%259a%2584%25e5%259f%25ba%25e7%25a1%2580%25e7%25bd%2591%25e7%25bb%259c%25e8%25ae%25be%25e5%25a4%2587%25e8%25af%25a6%25e8%25a7%25a3?lang=es