モードブリッジの2つのmacvlanインターフェイスが同じIPサブネット内の同じ物理インターフェイスに追加されるLinuxセットアップがあります。
ip link add link eth2 dev mvl0 type macvlan mode bridge
ip link add link eth2 dev mvl1 type macvlan mode bridge
ip addr add 192.168.42.16/24 dev mvl0
ip addr add 192.168.42.17/24 dev mvl1
ip link set dev mvl0 up
ip link set dev mvl1 up
インターフェイスにバインドされたソケットを使用してmvl0
とmvl1
の間で通信したいのですが、これは機能しません。例えば、
# ping -I mvl0 192.168.42.17
返信はありません。カーネルがlo
でARPを実行しようとしていることがわかりますが、応答がないため、機能しません。
たとえば、ルーティングテーブルまたはネイバーテーブルを操作することによって、これを機能させる方法はありますか?
これはLinuxカーネルのバグと見なす必要がありますか?結局のところ、モードmacvlan
のbridge
インターフェースはお互いを見ることができるはずです。
(背景:これは、同じプロセスコンテキストで実行されている2つの組み込みデバイスのシミュレーションです。フレームワークは常にソケットをインターフェイスにバインドして、通信が実際に目的のインターフェイスを経由するようにします。通信は通常、UDPを介して行われます。 )
(編集:以前のバージョンは発信パケット(UDP)に対してのみ機能しましたが、このバージョンは双方向(TCPとping)で機能します。)
あなたのようなセットアップにはさまざまな落とし穴があります。Linuxは、ネットワークインターフェイスアドレスと一致する送信元アドレスを持つ着信パケットをルーティングエラーと見なします(通常の状況ではルーティングループを示しているため)。また、デフォルトでは、カーネルが維持するlocal
ルーティングテーブルの優先度が最も高く、これにより、パケットがバインドされているインターフェイスから送信されなくなります。
ポリシールーティングに関する2番目の問題を解決できます。まず、重複するルートを削除します(これは問題を引き起こすだけです)。
ip route list
# overlapping routes should look like:
ip route del 192.168.42.0/24 dev mvl0 proto kernel scope link src 192.168.42.16
ip route del 192.168.42.0/24 dev mvl1 proto kernel scope link src 192.168.42.17
次に、local
テーブルの優先度を低くします(数値を高くします)。
ip rule add pref 1000 lookup local
ip rule del pref 0
着信パケットをlocal
テーブルに送信して受け入れる必要があります。
ip rule add pref 100 to 192.168.42.16 iif mvl0 lookup local
ip rule add pref 100 to 192.168.42.17 iif mvl1 lookup local
他のすべての(送信)パケットはそれぞれに送信されます。宛先は、他のインターフェースでそれらを強制的に排除する特別なテーブルを使用します。
ip rule add pref 200 to 192.168.42.17 lookup 100
ip rule add pref 200 to 192.168.42.16 lookup 101
ip route add default dev mvl0 table 100
ip route add default dev mvl1 table 101
さらに、リバースパスフィルタリングを無効にし(まだ無効になっていない場合)、ローカルソースを持つパケットを受け入れられるようにすることで、最初の問題に対処する必要があります。
echo "0" | tee /proc/sys/net/ipv4/conf/mvl{0,1}/rp_filter
echo "1" | tee /proc/sys/net/ipv4/conf/mvl{0,1}/accept_local
ping
インターフェースのいずれかにバインドされていなくても、mvl
が機能するようになりました。 TCPおよびUDPも機能し、socat
でテストします:
socat TCP4-LISTEN:9998,so-bindtodevice=mvl0 -
echo foo | socat - TCP4:192.168.42.16:9998,so-bindtodevice=mvl1
socat UDP4-RECV:9900,so-bindtodevice=mvl0 -
echo foo | socat - UDP4-SENDTO:192.168.42.16:9900,so-bindtodevice=mvl1