Ubuntu

兩個 NIC 上的相同 IP 一半的流量失去

  • February 15, 2020

我有一台連接到稍微損壞的科學儀器的機器,我正在嘗試解決這些問題。該連結是點對點的,2x25G 乙太網,不涉及其他設備。設備通過每個介面一個流傳輸 UDP 數據,我可以配置目標 IP 和 MAC 地址,但設備的源 IP 地址對於兩個介面是相同的。使用 tcpdump 我可以看到流量到達正確的介面,並且兩者都具有正確的目標 IP 和 MAC 地址。

但是我只能在其中一個 IP 上監聽並獲取數據,如果我在另一個 IP 上監聽,則沒有流量。核心顯然正在丟棄流量,我不知道為什麼,也不知道如何調試它。

機器執行的是 ubuntu 18.04,IP 為 10.50.5.1/16 和 10.50.5.129/16,設備的 IP 為 10.50.1.10。路線:

10.50.0.0/16 dev data0 proto kernel scope link src 10.50.5.1 
10.50.0.0/16 dev data1 proto kernel scope link src 10.50.5.129

有什麼建議麼?

我可以在 netstat 中看到數據包沒有被丟棄,那麼它們去哪裡了?

Kernel Interface table
Iface      MTU    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg
data0     9600   202320      0      0 0            29      0      0      0 BMRU
data1     9600   203600      0      0 0            31      0      0      0 BMRU

由於嘗試使用兩個不同的介面和路由到達同一目的地,您遇到了路由問題。預設情況下,路由是按目的地完成的,而不是按源完成的。預設情況下,使用弱主機模型(但 Ubuntu 也設置反向路徑過濾器,見下文)的 Linux 將選擇相同的介面:在其列表中首先出現的相同候選者中的一個。所以在這裡,源 IP 地址 10.50.5.1 和 10.50.5.129 都將使用data0到達 10.50.1.10,因為它目前是路由條目中兩個等號中的第一個。

否則需要在 Linux 上基於源的路由(又名策略路由):讓源也用於確定到目的地的路由。

同樣出於類似的原因,在您目前的配置中:在同一個 IP LAN (10.50.0.0/16) 中有兩個 IP 地址 Linux 將使用其任何 MAC 地址從其任何介面回答 LAN 中的 ARP 查詢。最後,除非您在設置中使用永久 ARP 條目而不是執行請求的設備,否則通常只有一個介面可以接收所有傳入流量(甚至可能是“錯誤”的)。

最後一根稻草是,即使儀器發送到具有正確 IP 地址目的地的正確介面,Ubuntu 的預設設置是啟用嚴格反向路徑,丟棄在“錯誤”介面上接收到的數據包。這就是您失去數據的原因:介面(嘗試使用現代ip -statistics link命令)接收到它們,但路由堆棧隨後立即丟棄了它們。要驗證這一點,只需詢問核心的路由堆棧它對發送和接收 IP 數據包的看法:

  • 發送
# ip route get from 10.50.5.1 10.50.1.10
10.50.1.10 from 10.50.5.1 dev data0 uid 0 
   cache 
# ip route get from 10.50.5.129 10.50.1.10
10.50.1.10 from 10.50.5.129 dev data0 uid 0 
   cache 

兩者都將使用data0發送,忽略data1

  • 接收
# ip route get from 10.50.1.10 iif data0 10.50.5.1
local 10.50.5.1 from 10.50.1.10 dev lo table local 
   cache <local> iif data0 
# ip route get from 10.50.1.10 iif data1 10.50.5.129
RTNETLINK answers: Invalid cross-device link

嚴格的反向路徑過濾器禁止在data1上接收。

您可以選擇禁用反向路徑,但如果您需要在特定介面上發送,無論如何也無濟於事。

我在下面提出了一種更清潔的方法。


首先,為了避免與 ARP 設置(和“ARP 通量”考慮因素)混在一起,請考慮這兩個介面的用途:點對點 IP 介面,即使在乙太網鏈路層上使用也是如此。因此無需使用整個 /16 LAN:只需點對點路由即可。

# ip address flush dev data0
# ip address flush dev data1

# ip address add 10.50.5.1 peer 10.50.1.10/32 dev data0
# ip address add 10.50.5.129 peer 10.50.1.10/32 dev data1

上面的兩個命令大多是ip address add 10.50.5.N/32 dev dataX; ip route add 10.50.1.10/32 dev dataX.

您可以選擇保留您的 /16 網路設置(例如:如果它們最終用於真正的 LAN 使用,後面有一堆設備),但這還需要切換arp_filter=1介面以保持安全。

要解決基於源的路由問題:使用指向附加路由表的規則,這些路由表將具有主路由表中某些路由的部分副本。我為這些路由表選擇任意值 1000 和 1001(即使不需要,也使用任意固定規則優先級 10000 10001)。表 1000 的所有內容都不是真正需要的(因為它是預設設置),但無論如何它更乾淨。

ip route add table 1000 10.50.1.10/32 dev data0 src 10.50.5.1
ip route add table 1001 10.50.1.10/32 dev data1 src 10.50.5.129

ip rule add pref 10000 from 10.50.5.1 lookup 1000
ip rule add pref 10001 from 10.50.5.129 lookup 1001

主表仍將確定預設使用的介面(可能是data0):任何未綁定到特定 IP 地址的工具將預設使用此介面(因此使用 10.50.5.1),如果綁定到 10.50.5.1 則相同。但是現在任何綁定到 10.50.5.129 的工具都將使用data1正確地進行雙向流量。

# ip route get 10.50.1.10
10.50.1.10 dev data0 src 10.50.5.1 uid 0 
   cache 
# ip route get from 10.50.5.1 10.50.1.10
10.50.1.10 from 10.50.5.1 dev data0 table 1000 uid 0 
   cache 
# ip route get from 10.50.5.129 10.50.1.10
10.50.1.10 from 10.50.5.129 dev data1 table 1001 uid 0 
   cache 

現在,反向路徑過濾器不會刪除data1上的傳入數據:

# ip route get from 10.50.1.10 iif data0 10.50.5.1
local 10.50.5.1 from 10.50.1.10 dev lo table local 
   cache <local> iif data0 
# ip route get from 10.50.1.10 iif data1 10.50.5.129
local 10.50.5.129 from 10.50.1.10 dev lo table local 
   cache <local> iif data1 

筆記:

額外的路由表是手動填充的,而不是由核心填充的。如果一個介面被關閉(或一個 IP 被刪除),然後恢復(或添加回來的 IP)相應的表 1000 或 1001 將被刷新並且不會被重新填充:它必須手動添加回來(或使用能夠執行此操作的網路配置工具)。

引用自:https://serverfault.com/questions/1003102