不同接口上的同一网络

不同接口上的同一网络

我们通过 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可能是创建这些东西的最简单方法。

创建 Tap 设备和桥接器,每个 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 服务器和映像...或省略只读并为每个 vm 创建一个映像文件(为此使用快照会更好,但这超出了该答案的范围)。

使用 tap 界面和图像文件运行 kvm 并测试 usb 网络连接。

比较

如果 connmark/policy 路由有效,则同步维护 tftp 存储库会容易得多。使用 KVM,您可能需要每个 VM 映像都有一个存储库(除非您将只读目录传递给每个 VM,这是可行的)。Connmark/policy 路由有点挑剔,但它也只需要一个 tftp 服务器,尽管如果您的端口不够随机,conntrack 可能会混淆并在端口重叠时覆盖(也可能不会)。另一方面,桥接到 kvms 需要更多内存;每个连接的 USB 设备都需要一个完整的 VM,但每次都更有可能工作,因为 VM 有一个完整的隔离网络堆栈可以使用,而主机内核只需通过桥接来回传递数据包,尤其是在桥接过滤关闭的情况下。

希望这两个中的一个对您有用。

相关内容