Linux核心協議棧的socket尋找緩衝路由機制,協議棧socket
是查路由錶快呢?還是查socket雜湊表快?這不是問題的根本。問題的根本是怎麼有效利用這兩者,讓兩者成為合作者而不是競爭者。這是怎麼回事?
我們知道,如果一個資料包要到達本地,那麼它要經過兩次尋找過程(暫時不考慮conntrack):IP層尋找路由和傳輸層尋找socket。怎麼合并這兩者。
Linux核心協議棧採用了一種辦法:在socket中增加一個dst欄位作為緩衝路由的手段,skb在尋找路由之前首先尋找socket,找到的話,就將緩衝的dst設定到skb,接下來在尋找路由的時候,發現已經有了dst,就省去了路由尋找的過程。
問題是,socket的dst欄位什麼時候設定的呢?當然是“和該socket相關的第一個skb”到來的時候設定上的,無疑即便這第一個skb找到了socket,此時的socket上的dst也是NULL,那麼它會去老老實實尋找路由表,如果找到,則將找到的路由項設定到socket的dst欄位。
這個特性在Linux的實現中叫做ip_early_demux,在核心文檔中,描述如下:
ip_early_demux - BOOLEAN Optimize input packet processing down to one demux for
certain kinds of local sockets. Currently we only do this
for established TCP sockets.
It may add an additional cost for pure routing workloads that
reduces overall throughput, in such case you should disable it.
Default: 1
對於forward轉寄,這個特性必然要降低效能,但是我並不是想說這個顯而易見的問題,我想說的有兩點:
1.層次cache邏輯
我們知道,路由尋找是一個“儘力而為”的多對一匹配過程,skb和路由entry並不是精確的一一對應關係,因此不能在路由entry中緩衝socket,但是卻可以在socket中緩衝路由entry,因為socket和skb是一個一一對應的關係(我說的不是TCP listen socket..),同樣,我也能在路由cache中緩衝socket,因為路由cache和skb也是一一對應的關係。
然而linux核心還是去掉了路由cache的支援,不過這沒關係,只要知道一點就夠了:一一對應的精確匹配項可以緩衝更加鬆散的非一一對應的匹配項。如果將目光移到conntrack,就知道該怎麼做了,我曾經將路由entry緩衝到了conntrack裡面,按照這個邏輯,是合理的,同樣的,socket也可以被緩衝到conntrack裡面,這一點已經有了iptables相關的match和target。
2.自動還是手動
既然Linux有了ip_early_demux配置參數,問題就是什麼時候開啟它而什麼時候關閉它。特別是,在你事先不知道有多少包是到達本地,有多少包是forward的情況下,這個問題顯得更加不易回答。此時,是相信管理員的非0即1的配置呢,還是讓系統去動態自適應?
如何統計包顯得尤為重要,典型情況下,如果有超過60%的包是到達本地的,那麼就開啟它,反之則關閉它。ip_early_demux配置參數作為一個全域的參數並沒有什麼不好,因為如果不是這樣,那麼就會出現另一個問題,即如何判斷一個包是否要進行early_demux...對於邊界非七層裝置,一般而言,流量是分類的,分為管理面流量和資料面流量,對於前者而言,流量的終點就是本地,而對於後者,本機僅僅做forward,如果能事先高效地將包進行平面分類,那麼兩個ip_early_demux配置會顯得更好,對於頻外管理而言,Linux的nsnamespace可以很好地完成這個任務。