我以前寫過一篇 介紹 tunnel 的文章 ,只是做了大體的介紹。裡面多數 tunnel 是很容易理解的,因為它們多是一對一的,換句話說,是直接從一端到另一端。比如 ipv6 over ipv4 的 tunnel,也就是 sit,它的原理如下圖所示:
顯然,除了端點的 host a 和 host b之外,中間經過的任何裝置都是看不到裡面的 ipv6 的頭,對於它們來說,經過 sit 發出的包和其它的 ipv4 的包沒有任何區別。
gre tunnel 卻不一樣了,它的原理從根本上和 sit,ipip 這樣的 tunnel 就不一樣。除了外層的 ip 頭和內層的 ip 頭之間多了乙個 gre 頭之外,它最大的不同是, tunnel 不是建立在最終的 host 上,而是在中間的 router 上 !換句話說,對於端點 host a 和 host b 來說,該 tunnel 是透明的(對比上面的 sit tunnel)。這是網上很多教程裡沒有直接告訴你的。理解這一點非常關鍵,正是因為它這麼設計的,所以它才能解決 ipip tunnel 解決不了的問題。
所以,經過 gre tunnel 傳送的包(從 host a 傳送到 host b)大體過程是這樣子的(仍然借用了 lartc 中的例子 ):
我們可以看出,從 host a 發出的包其實就是乙個很普通的 ip 包,除了目的位址不直接可達外。該 gre tunnel 的一端是建立在 router a上,另一段是建立在 router b上,所以新增外部的 ip 頭是在 router a 上完成的,而去掉外面的 ip 頭是在 router b上完成的,兩個端點的 host 上幾乎什麼都不用做(除了配置路由,把傳送到 10.0.2.0 的包路由到 router a)!
這麼設計的好處也就很容易看出來了,ipip tunnel 是端對端的,通訊也就只能是點對點的,而 gre tunnel 卻可以進行多播。
現在讓我們看看linux核心是怎麼實現的,我們必須假設 router a 和 b 上都是執行的 linux,而 host a 和 b上執行什麼是無所謂的。
傳送過程是很簡單的,因為 router a 上配置了一條路由規則,凡是發往 10.0.2.0 網路的包都要經過 netb 這個 tunnel 裝置,在核心中經過 forward 之後就最終到達這個 gre tunnel 裝置的 ndo_start_xmit(),也就是 ipgre_tunnel_xmit() 函式。這個函式所做的事情無非就是通過 tunnel 的 header_ops 構造乙個新的頭,並把對應的外部 ip 位址填進去,最後傳送出去。
稍微難理解的是接收過程,即 router b 上面進行的操作。這裡需要指出的一點是,gre tunnel 自己定義了乙個新的 ip proto,也就是 ipproto_gre。當 router b 收到從 router a 過來的這個包時,它暫時還不知道這個是 gre 的包,它首先會把它當作普通的 ip 包處理。因為外部的 ip 頭的目的位址是該路由器的位址,所以它自己會接收這個包,把它交給上層,到了 ip 層之後才發現這個包不是 tcp,udp,而是 gre,這時核心會轉交給 gre 模組處理。
gre 模組註冊了乙個 hook:
plain text
c: static
const
struct gre_protocol ipgre_protocol
=;
所以真正處理這個包的函式是 ipgre_rcv() 。ipgre_rcv() 所做的工作是:通過外層ip 頭找到對應的 tunnel,然後剝去外層 ip 頭,把這個「新的」包重新交給 ip 棧去處理,像接收到普通 ip 包一樣。到了這裡,「新的」包處理和其它普通的 ip 包已經沒有什麼兩樣了:根據 ip 頭中目的位址**給相應的 host。注意:這裡我所謂的「新的」包其實並不新,核心用的還是同乙個copy,只是skbuff 裡相應的指標變了。
以上就是linux 核心對 gre tunnel 的整個處理過程。另外,gre 的頭如下所示(來自 這裡 ):
深入理解C語言 深入理解指標
關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...
mysql 索引深入理解 深入理解MySql的索引
為什麼索引能提高查詢速度 先從 mysql的基本儲存結構說起 mysql的基本儲存結構是頁 記錄都存在頁裡邊 各個資料頁可以組成乙個雙向鍊錶每個資料頁中的記錄又可以組成乙個單向鍊錶 每個資料頁都會為儲存在它裡邊兒的記錄生成乙個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應...
深入理解C語言 深入理解指標
關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...