当社では、USB ネットワーク接続で TFTP を使用してフラッシュされた (工場出荷時の) デバイスを操作します。
サーバーのアドレスは固定の 192.168.2.100 で、デバイスのアドレスは固定の 192.168.2.101 です。起動すると、ファームウェアをダウンロードするために接続します。
現在の設定では、同時に動作できるのは 1 つのデバイスだけです。ただし、接続できるデバイスをできるだけ多くフラッシュできるようにしたいと考えています (フラッシュ要件が膨大になる可能性があるため)。
ルーティングの問題を回避するために、setsockopt を SO_BIND_DEVICE に設定する xinetd バージョンを作成しました。
しかし、私が予想していなかったのは、Linux が両方のインターフェースで同時に ARP 要求を処理できないことです。
「ping 192.168.2.101 -I usb0」と「ping 192.168.2.101 -I usb1」を同時に実行すると、1 つのインターフェースで動作します。
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/ポリシールートのマングリング
プロキシ ARP だけでは機能しなかった場合は、これが機能するかどうかは保証できませんが、試してみる価値はあると思います。これから説明するのは、conntrack を使用して入力インターフェイスに基づいて応答をバインドするポリシー ルーティングを設定する方法です。2 つのインターフェイスに設定する方法について説明しますが、任意の数に拡張するのは簡単です。一方、機能する代わりに、非常に混乱して何も実行されない可能性があります (おそらく、カーネル ARP テーブルがデバイスごとに IP/MAC ペアをキャッシュする必要があることを認識していないためです)。その場合は、2 番目の、より見苦しい方法を試してください。
まず、いくつかの connmark マングル ルールを設定します。
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に2つのテーブル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 つのデバイスでテストします。動作する場合は問題ありませんが、動作しない場合は次の方法を試してください。
オプション 2: USB ネット デバイスごとの KVM コンテナー
オプション 2 は、ブリッジと qemu/kvm を必要とするため、見た目は劣りますが、 virt-manager
おそらくこれらを作成する最も簡単な方法です。
USB インターフェイスごとに 1 つの TAP デバイスとブリッジを作成します。
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.
読み取り専用として設計され、TFTP サーバーとイメージをホストする kvm イメージ ファイルまたはブート CD を作成します... または、読み取り専用を省略して、VM ごとに 1 つのイメージ ファイルを作成します (この場合はスナップショットを使用する方が適切ですが、この回答の範囲を超えています)。
TAP インターフェイスとイメージ ファイルを使用して KVM を実行し、USB ネットワーク接続をテストします。
比較
connmark/policy ルートが機能すれば、tftp リポジトリを同期的に維持するのがずっと簡単になります。KVM では、VM イメージごとにリポジトリが必要になる場合があります (読み取り専用ディレクトリを各 VM に渡す場合を除きます。これは可能です)。connmark/policy ルートはやや扱いにくいですが、必要な tftp サーバーも 1 つだけです。ただし、ポートが十分にランダムでない場合、ポートが重複すると conntrack が混乱して上書きする可能性があります (重複しない場合もあります)。一方、kvms へのブリッジには、接続された USB デバイスごとに VM 全体が必要になるため、はるかに多くのメモリが必要ですが、VM には動作する分離されたネットワーク スタック全体があり、ホスト カーネルはブリッジを介してパケットをやり取りするだけでよいため、毎回機能する可能性がずっと高くなります。これは、ブリッジ フィルタリングがオフの場合に特に当てはまります。
これら 2 つのうちの 1 つが役に立つことを願っています。