不同介面上的同一網絡

不同介面上的同一網絡

我們使用在 USB 網路連接上使用 TFTP 進行快閃記憶體(工廠)的裝置。

伺服器有固定的 192.168.2.100 位址,設備有固定的 192.168.2.101 位址。當它啟動時,它會連接以下載韌體。

在目前設定中,只有一台設備可以同時工作。但我希望能夠閃存盡可能多的設備(因為我們可能有一些大量的閃存要求)。

為了繞過路由問題,我製作了一個 xinetd 版本,將 setsockopt 設定為 SO_BIND_DEVICE。

但我沒有註意到 Linux 無法同時處理兩個介面上的 ARP 請求。

如果我同時執行“ping 192.168.2.101 -I usb0”和“ping 192.168.2.101 -I usb1”,它將在一個介面上工作:

ARP, Request who-has sk tell 192.168.2.100, length 28
ARP, Reply 192.168.2.101 is-at 7a:0f:66:7c:fc:2c (oui Unknown), length 28
IP 192.168.2.100 > 192.168.2.101: ICMP echo request, id 21807, seq 1, length 64
IP 192.168.2.101 > 192.168.2.100: ICMP echo reply, id 21807, seq 1, length 64

但另一方面它不會:

IP 192.168.2.100 > 192.168.2.101: ICMP echo request, id 31071, seq 1, length 64
ARP, Request who-has 192.168.2.100 tell 192.168.2.101, length 28
ARP, Request who-has 192.168.2.100 tell 192.168.2.101, length 28
IP 192.168.2.100 > 192.168.2.101: ICMP echo request, id 31071, seq 2, length 64
IP 192.168.2.100 > 192.168.2.101: ICMP echo request, id 31077, seq 1, length 64
ARP, Request who-has 192.168.2.100 tell 192.168.2.101, length 28

伺服器似乎沒有響應 ARP 請求。

這是使用 /etc/network/if-up.d/000-first 腳本在伺服器上處理來自裝置的連線的方式:

ifconfig $IFACE up
ifconfig $IFACE 192.168.2.100

PID=/var/run/xinetd-$IFACE.pid

# this is the modified xinetd version to bind on one address
kill -9 `cat $PID`
xinetd -pidfile $PID -interface $IFACE

# I tried this to force the handling of ARP table per interface, but it doesn't change anything:
# /usr/sbin/arpd -b /tmp/$IFACE.db -a 3 -k $IFACE 

這是修改後的 xinetd 版本: https://github.com/fclairamb/xinetd/commit/1f5c1e8f9944e372b137e6aa46247f8de807bece#L8R253

答案1

首先,如果您還沒有嘗試過代理 arp 本身,您應該嘗試代理 arp。

echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp

選項 1:一些 connmark/policy 路由修改

如果單獨的代理 arp 不起作用,我不能保證這會起作用,但我認為值得一試。我要描述的是如何使用 conntrack 設定策略路由以根據輸入介面綁定回應。我將描述如何為兩個介面設定它,並且它應該很容易擴展到任意數量。另一方面,它不但不能工作,反而可能會變得非常混亂,並且不會做任何該死的事情(可能是因為內核 arp 表不知道它應該緩存每個設備的 ip/mac 對)。如果發生這種情況,請嘗試第二種更醜陋的方法。

首先,設定一些 connmark mangle 規則:

iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j ACCEPT

在 /etc/iproute2/rt_tables 中新增兩個表 100 和 101,將它們標記為 usb0 和 usb1

100    usb0
101    usb1

對於每個表格添加以下內容(將 <N> 替換為適當的數字):

ip route add 192.168.2.0/24 dev usb<N> table usb<N>
ip rule add fw <N> table usb<N>
iptables -t mangle -A PREROUTING -i usb<N> -j MARK --set-mark <N>

我不確定,但您可能需要設定一個虛擬接口,如下所示,以便您的 tftp 守護程式監聽:

modprobe dummy
ifconfig dummy0 192.168.2.100/32 up
echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp
sysctl net.ipv4.ip_forward=1
iptables -I FORWARD -s 192.168.2.100 -j ACCEPT
iptables -I FORWARD -d 192.168.2.100 -j ACCEPT

現在用兩台設備進行測試。如果有效,那就太好了,否則請嘗試下一個方法:

選項 2:每個 USB 網路裝置的 kvm 容器

選項 2 比較醜陋,涉及一些橋接和 qemu/kvm。 virt-manager可能是創建這些東西的最簡單的方法。

建立分路設備和橋接器,每個 USB 介面一個。

tunctl -t tap<N>
brctl addbr usb<N>br
brctl addif usb<N>br tap<N>
brctl addif usb<N>br usb<N>  # this may need to be done each time the usb device is connected/disconnected.

建立kvm 映像檔或啟動CD,設計為唯讀並託管您的tftp 伺服器和映像...或忽略只讀並為每個虛擬機器建立映像檔(為此使用快照會更好,但更多的是範圍比這個答案得到的範圍更大)。

使用 Tap 介面和映像檔執行 kvm 並測試 USB 網路連線。

比較

如果 connmark/policy 路由有效,同步維護 tftp 儲存庫就會容易得多。使用 KVM,您可能需要為每個 VM 映像提供一個儲存庫(除非您將唯讀目錄傳遞給每個 VM,這是可行的)。 Connmark/policy 路由有點挑剔,但它也只需要一台 tftp 伺服器,但如果您的連接埠不夠隨機,如果存在連接埠重疊(也可能不重疊),conntrack 可能會感到困惑並被覆蓋。另一方面,橋接 kvm 需要更多記憶體;每個連接的USB 設備都有一個完整的虛擬機,但每次都更有可能工作,因為虛擬機有一個完整的隔離網路堆疊可以使用,而主機核心只需透過橋接來回傳遞資料包,尤其是在橋接過濾的情況下已關閉。

希望這兩者之一適合您。

相關內容