1. 程式人生 > >Linux鄰居子系統的細節之confirm-OpenVPN server模式的MAC地址學習

Linux鄰居子系統的細節之confirm-OpenVPN server模式的MAC地址學習

虛擬 關於 剖析 定時 sdn -m mac ets ntop

在《Linux實現的ARP緩存老化時間原理解析》一文中。我剖析了Linux協議棧IPv4的鄰居子系統的轉化,再次貼出那個狀態機轉化圖,可是這個圖更具體了些,因為它有一個外部輸入,那就是confirm:


技術分享


請註意。假設socket或者路由子系統在上層confirm了一個neighbour,那麽該arp將持續留在reachable狀態而能夠不用轉換到stale狀態。

這個特性是有意義的。請觀察一個現象:
1.本機IP地址為192.168.1.10/24,直連的機器IP地址為192.168.1.20/24,從本機ping對端。
2.將本機的/proc/sys/net/ipv4/neigh/eth0/base_reachable_time設置為4秒,對端的相應值設置為8秒;
3.抓包發現每隔8秒左右會有一個一個arp request從對端發來。符合上述的圖示;
4.抓包始終未見有本端到對端的arp request。按說應該每隔4秒左右發出一個的啊。
5.改動對端設備的IP地址為192.168.1.30/24,本端在間隔4秒左右後。立即發出了arp request。


以上現象有2個疑點:為何本端在reachable狀態到期了仍然不切換狀態,不又一次解析對端IP地址?為何對端的IP地址改動掉或者刪除掉之後,本端立即發現了這一事實。間隔reachable到期時間後發出了arp request?
要澄清上述兩個疑點,就要從下向上來逐步定位。當我設置了iptables規則在INPUT上禁止ping reply接收時,和改動刪除對端IP的效果一樣,ping立即發現了這一點,間隔4秒左右發出了arp request。因此問題就在ping本身,對ping進行strace。發現其sendmsg的最後一個參數為MSG_CONFIRM。查閱man手冊。發現:
MSG_CONFIRM (Since Linux 2.3.15)
Tell the link layer that forward progress happened: you got a successful reply from the other side. If the link
layer doesn‘t get this it will regularly reprobe the neighbor (e.g., via a unicast ARP). Only valid on SOCK_DGRAM
and SOCK_RAW sockets and currently only implemented for IPv4 and IPv6. See arp(7) for details.

因為對端僅僅是接收ping request。進而直接在協議棧中回應ping reply。因此不會涉及socket,並且也沒有涉及路由子系統中關於redirect等關聯的confirm。因此對端嚴格依照IPv4鄰居子系統的狀態圖轉換,而本端則每每收到ping reply,就會confirm。進而使arp表項維持在reachable狀態,一旦收不到ping reply,便不會再confirm。等到reachable狀態到期,便進入短暫的stale。delay狀態了,進而進入probe發出arp request。
說了這麽多關於arp的一個細節,旨在解釋一個tap模式的OpenVPN執行在multi模式,即server模式時的MAC地址學習的問題。


我們知道。OpenVPN在tap模式下能夠看作一個虛擬的交換機,並且是學習型的。它學習的內容為:為每個multi_instance關聯一個MAC地址鏈表。凡是來自該multi_instance的以太幀的源MAC地址都會進入這個鏈表。這個鏈表的作用在於為從OpenVPN服務端返回到client的數據包關聯一個multi_instance。對於一個從OpenVPN服務端發往client方向的數據包,其目的MAC地址肯定在某一個OpenVPNclient後面或者是OpenVPNclient的tap網卡本身。OpenVPN服務端用這個MAC地址作為鍵值檢查MAC/instance表。終於找出一個multi_instance發送出去。
如今考慮一個主動從OpenVPN服務端發送的數據包,當它到OpenVPN進程的時候,因為事先沒有從OpenVPNclient過來的不論什麽數據包供OpenVPN服務端學習,因此數據包必須丟棄。因為它無法相應到不論什麽一個multi_instance。

是這樣嗎?NO!

因為你沒有考慮到arp。在以太網發送不論什麽數據包之前,都要經過arp解析對端的IP地址,而arp請求是廣播,將發送到全部的multi_instance,僅僅有有來自某個OpenVPNclient方向的arp回應,OpenVPN服務端將會學習到一條MAC/instance表項。因此不存在數據包被drop的可能。
可是,假設OpenVPN服務端後面的機器發送數據包的時候,IP/MAC地址映射已經存在了,那麽就不會發送arp請求了,也就沒有機會讓OpenVPN服務端從arp回應中學習了,此時數據包將會被丟棄。

是這樣嗎?是的,可是假設你看懂了IPv4鄰居子系統的狀態轉換圖,就會等待reachable到期時間後再次重試。

因為根本不可能有數據從OpenVPNclient發來。因此就沒有機會被confirm。全部最久的等待時間就是reachable+stale+delay的定時器時間和。然而有一種情況,假設服務端這邊設置了一條永久的arp表項,那就完蛋了。
OpenVPN執行在tap模式時,能夠通過arp來自己主動學習MAC/instance映射。那麽執行在tun模式下呢?因為IPv4除了DHCP等不具備不論什麽自己主動配置機制,且DHCP又不是必須使用的。因此僅僅能手工配置,這個在OpenVPN中就是iroute選項,即Internal route。
自己主動學習比較不易,那麽假設你僅僅僅僅是為了使用OpenVPN連接兩個遠程網絡。那麽就別用server模式了。使用p2p。即pointopoint模式比較好,它僅僅是進行簡單的tun-link-link-tun的轉發而已。

Linux鄰居子系統的細節之confirm-OpenVPN server模式的MAC地址學習