web-dev-qa-db-ja.com

Linuxでの透過的なLANサービス

LinuxでVLANベースの透過LANサービスを実装する必要があります。つまり、構成済みのVLANを取得し、指定されたポートに直接転送する必要があります(すべてのブロードキャスト/マルチキャストおよびユニキャストパケット)。

簡単な解決策は、VLANインターフェイスと指定されたポートの間に1対1のブリッジを定義することです。この解決策の欠点は、このトンネル上のすべてのMACアドレスを認識できるようになることです。 Macテーブルが制限されている組み込みデバイスであり、接続しているネットワークからのデバイスでMacテーブルが汚染されないようにしたい。

私はこのタスクにebtablesを使用する方法を見つけようとしていましたが、ebtablesの-oオプションは、Macの学習後に発生するFORWARDチェーンでのみ役立つようです。 BROUTINGチェーンは私が必要としているものですが、この時点から特定のインターフェイスでパケットを強制的に出力することはできないようです。

したがって、ebtablesは行き止まりのようです。他のオプションはありますか?理想的な世界では、VLANだけでなく、任意のキーに基づいたTLSサービスを利用したいと思いますが、今のところVLANで十分です。

ありがとう、イリヤ。

3
Ilya

[〜#〜] update [〜#〜]:まだブリッジを使用しているソリューションを追加しました。とにかく、VLANケースの場合、そのVLANフィルタリング機能にLinuxブリッジを使用することは可能です、以下のtcは、セレクターを照合する一般的な方法としては依然として役立つ可能性があります(tcを適切に照合して使用する方がおそらく簡単です。 VLANは、コードのないブリッジを使用して処理する以外のセレクターとして)。


すべてのポートでMAC学習が無効になっているブリッジ

MACアドレスの学習を無効にすることが可能です。 bridge link コマンドで実行されます。次に、ブリッジを設定してVLANフィルタリング( bridge vlan も使用):MACアドレスを必要としない、すべての転送構成されたVLAN設定に基づいて実行されます。

学ぶことまたは学ぶこと

特定のポートが受信トラフィックからMACアドレスを学習するかどうかを制御します。オフかどうかを学習すると、ブリッジはFDBエントリのないトラフィックをフラッディングすることになります。デフォルトでは、このフラグはオンになっています。

learning_syncオンまたはLearning_syncオフ

特定のポートがデバイスポートで学習したMACアドレスをブリッジFDBに同期するかどうかを制御します。

たとえば、タグ付きフレームを持つトランクとしてインターフェイスeth0を使用し、eth1 eth2 eth3respを使用するシステムを見てみましょう。 VLAN ID 10、20、および30の場合、タグなし。これは次の方法で行われます。

ip link add name br0 type bridge vlan_filtering 1

#remove implicit bridge's self port br0 from any interaction.
# Might have to not be done if using an IP on the bridge
# but more configuration might then be needed anyway.
bridge vlan del vid 1 dev br0 self
bridge link set dev br0 learning off learning_sync off self

for $nic in eth0 eth1 eth2 eth3; do
    ip link set dev $nic master br0
    bridge link set dev $nic learning off learning_sync off
    bridge vlan del vid 1 dev $nic
done
ip link set br0 up

bridge vlan add 10 dev eth0
bridge vlan add 20 dev eth0
bridge vlan add 30 dev eth0

bridge vlan add vid 10 pvid 10 untagged dev eth1
bridge vlan add vid 20 pvid 20 untagged dev eth2
bridge vlan add vid 30 pvid 30 untagged dev eth3

この異なるセットアップがどのように動作するかをテストするには、最後にセットアップスクリプトの次の行を置き換えるだけです(回答の次の部分で説明するtcメソッドを使用しています)。

ip netns exec fakebridge tc qdisc add dev trunk0 ingress
for vlan in 10 20 30; do
    ip netns exec fakebridge tc qdisc add dev vlan$vlan ingress
    ip netns exec fakebridge tc filter add dev vlan$vlan parent ffff: matchall action vlan Push id $vlan action mirred egress redirect dev trunk0
    ip netns exec fakebridge tc filter add dev trunk0 parent ffff: basic match "meta(vlan mask 0xfff eq $vlan)" action vlan pop action mirred egress redirect dev vlan$vlan
done

代わりにこれらを使用します(これは偽のブリッジではありませんが、とにかく...):

ip -n fakebridge link add name br0 type bridge vlan_filtering 1
ip netns exec fakebridge bridge vlan del vid 1 dev br0 self #remove implicit bridge's self port br0 from any interaction
ip -n fakebridge link set dev trunk0 master br0
ip netns exec fakebridge bridge vlan del vid 1 dev trunk0
ip netns exec fakebridge bridge link set dev trunk0 learning off learning_sync off
for vlan in 10 20 30; do
    ip -n fakebridge link set dev vlan$vlan master br0
    ip netns exec fakebridge bridge link set dev vlan$vlan learning off learning_sync off
    ip netns exec fakebridge bridge vlan add vid $vlan dev trunk0
    ip netns exec fakebridge bridge vlan del vid 1 dev vlan$vlan
    ip netns exec fakebridge bridge vlan add vid $vlan pvid $vlan untagged dev vlan$vlan
done
ip -n fakebridge link set br0 up

ブリッジをまったく使用せず、操作にVLAN IDを使用して、...を使用することもできます。

tc (交通管制)

tcは、 tc vlan を使用してVLANを直接操作できます。

説明

Vlanアクションを使用すると、パケットに対して802.1Qカプセル化またはカプセル化解除を実行できます。これは、操作モードPOP、Push、およびMODIFYに反映されます。 POPモードは単純で、最も外側のVLANカプセル化を削除するために追加情報は必要ありません。プッシュモードとMODIFYモードには少なくともVLANIDが必要であり、オプションで使用するVLANPROTOを選択できます。 。

他のtc機能と一緒に:

そして通常の配管(haveqdisc、attachfilterwithaction)、 802.1Q VLAN IDをカプセル化またはカプセル化解除しながら、インターフェイスから別のインターフェイスにパケットを移動することができます。システムはこれらのパケットをブリッジまたはルーティングしません。システムはMACを記憶する必要はありません。 IPをアドレス指定または操作する場合、パケットとプロトコルの認識はtcで行われるものに制限されます。

これは概念実証であることに注意してください。もちろん、実際のシステムは、これらの設定に干渉しないように注意しながら、IPを使用して通信する必要があります。 tcが複雑なツールであることを考えると、これを本番環境に正しく実装するには、おそらく予期しない追加の問題が発生します。 tcを使用して、より一般的に処理する他のより良い方法もあります( tcフロー について考えてみてください。 = VLAN IDをクラスIDにマップするキーとして使用します。これは、より一般的に使用できます。または、カプセル化する方法がある限り、VLANの横にあるキーとして他の何かを使用できます。/decap。)。

たとえば、タグ付きフレームを持つトランクとしてインターフェイスeth0を使用し、eth1 eth2 eth3respを使用するシステムを見てみましょう。 VLAN ID 10、20、および30の場合、タグなし。タグ付き側が正しいタグなし側と通信できるようにし、その逆を行うには、次のようにします。

tc qdisc add dev eth0 handle ffff: ingress
tc qdisc add dev eth1 handle ffff: ingress
tc qdisc add dev eth2 handle ffff: ingress
tc qdisc add dev eth3 handle ffff: ingress

tc filter add dev eth0 parent ffff: basic match "meta(vlan mask 0xfff eq 10)" action vlan pop action mirred egress redirect dev eth1
tc filter add dev eth0 parent ffff: basic match "meta(vlan mask 0xfff eq 20)" action vlan pop action mirred egress redirect dev eth2
tc filter add dev eth0 parent ffff: basic match "meta(vlan mask 0xfff eq 30)" action vlan pop action mirred egress redirect dev eth3

tc filter add dev eth1 parent ffff: matchall action vlan Push id 10 action mirred egress redirect dev eth0
tc filter add dev eth2 parent ffff: matchall action vlan Push id 20 action mirred egress redirect dev eth0
tc filter add dev eth3 parent ffff: matchall action vlan Push id 30 action mirred egress redirect dev eth0

実際にトラフィックをリダイレクトするには、実際のインターフェイスをプロミスキャスモードにする必要があるのは理にかなっているように思われるかもしれませんが、カーネル5.0.xおよびvethインターフェイスでは、とにかくテスト中にこれは必要ありませんでした。 。


ネットワーク名前空間にip netnsを使用したモックアップ

ネットワーク名前空間を使用して、1つのタグ付きトランクインターフェイスといくつかのタグなしVLANインターフェイスを使用して偽のブリッジを実装するためにいくつかの実験を行いました。各「ホスト」には独自の名前空間があり、ネットワーク要素を使用して他のホストにリンクされ、ブリッジを含むotherネットワーク名前空間で実装されます。組み込みデバイスで何ができるかを模倣した実際のシステムは、VLAN認識ブリッジ)に似ている可能性があるため、fakebridgeと呼ばれます。

タグなしタグなし_______ 
。| Host10b | 
 + ------- +。 ======= 
 + ------ + | | .... vlan10 .... | Host10 | 
 | | .......トランク...... |偽物| ====== 
 |ルーター| .................. | | .... vlan20 .... | Host20 | 
 | | (VLAN 10 + 20 + 30)|ブリッジ| ====== 
 + ------ + | | .... vlan30 .... | Host30 | 
 + ------- + ------ 

したがって、1 + 1 + 4 = 6ホスト、1 + 3 = 4ネットワーク、合計10の名前空間。

以下のスクリプトが(rootとして)実行されると、次のようなコマンドでテストおよび監視できます。

term1:

ip netns exec fakebridge tcpdump -l -n -s0 -e -p -i trunk0

term2:

ip netns exec Host10 ping -c1 198.51.100.20

例を挙げて:

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on trunk0, link-type EN10MB (Ethernet), capture size 262144 bytes
00:27:56.036743 c2:e8:f4:79:28:96 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 10, p 0, ethertype ARP, Request who-has 192.0.2.110 tell 192.0.2.10, length 28
00:27:56.036777 16:51:fa:18:21:b0 > c2:e8:f4:79:28:96, ethertype 802.1Q (0x8100), length 46: vlan 10, p 0, ethertype ARP, Reply 192.0.2.110 is-at 16:51:fa:18:21:b0, length 28
00:27:56.036794 c2:e8:f4:79:28:96 > 16:51:fa:18:21:b0, ethertype 802.1Q (0x8100), length 102: vlan 10, p 0, ethertype IPv4, 192.0.2.10 > 198.51.100.20: ICMP echo request, id 13483, seq 1, length 64
00:27:56.036807 16:51:fa:18:21:b0 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 198.51.100.20 tell 198.51.100.120, length 28
00:27:56.036832 b6:1d:bc:33:87:98 > 16:51:fa:18:21:b0, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Reply 198.51.100.20 is-at b6:1d:bc:33:87:98, length 28
00:27:56.036841 16:51:fa:18:21:b0 > b6:1d:bc:33:87:98, ethertype 802.1Q (0x8100), length 102: vlan 20, p 0, ethertype IPv4, 192.0.2.10 > 198.51.100.20: ICMP echo request, id 13483, seq 1, length 64
00:27:56.036860 b6:1d:bc:33:87:98 > 16:51:fa:18:21:b0, ethertype 802.1Q (0x8100), length 102: vlan 20, p 0, ethertype IPv4, 198.51.100.20 > 192.0.2.10: ICMP echo reply, id 13483, seq 1, length 64
00:27:56.036867 16:51:fa:18:21:b0 > c2:e8:f4:79:28:96, ethertype 802.1Q (0x8100), length 102: vlan 10, p 0, ethertype IPv4, 198.51.100.20 > 192.0.2.10: ICMP echo reply, id 13483, seq 1, length 64
00:28:01.043203 16:51:fa:18:21:b0 > c2:e8:f4:79:28:96, ethertype 802.1Q (0x8100), length 46: vlan 10, p 0, ethertype ARP, Request who-has 192.0.2.10 tell 192.0.2.110, length 28
00:28:01.043246 b6:1d:bc:33:87:98 > 16:51:fa:18:21:b0, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Request who-has 198.51.100.120 tell 198.51.100.20, length 28
00:28:01.043287 c2:e8:f4:79:28:96 > 16:51:fa:18:21:b0, ethertype 802.1Q (0x8100), length 46: vlan 10, p 0, ethertype ARP, Reply 192.0.2.10 is-at c2:e8:f4:79:28:96, length 28
00:28:01.043284 16:51:fa:18:21:b0 > b6:1d:bc:33:87:98, ethertype 802.1Q (0x8100), length 46: vlan 20, p 0, ethertype ARP, Reply 198.51.100.120 is-at 16:51:fa:18:21:b0, length 28

Rootとして実行するようにスクリプトを設定します。 ip netns を使用してさまざまなネットワーク名前空間を作成し、必要なネットワークリンク(ブリッジとveth)を設定し、tcfakebridgeをフィルタリングし、最後にさまざまなホストのIPを構成して実験できるようにします。 fakebridgeはIPもブリッジもありません。埋めることができるMACテーブルはありません。IPなしのARPもブリッジなしのMAC学習もないため、ip neighまたはbridge fdbはトラフィックに関連するものを何も表示しません。

#!/bin/sh

if ip netns id | grep -qv '^ *$' ; then
    printf 'ERROR: leave netns "%s" first\n' $(ip netns id) >&2
    exit 1
fi

hosts='router fakebridge Host10 Host10b Host20 Host30'
nets='trunk vlan10 vlan20 vlan30'

for ns in $hosts $nets; do
    ip netns del $ns 2>/dev/null || :
    ip netns add $ns
    ip netns exec $ns sysctl -q -w net.ipv6.conf.default.disable_ipv6=1
    ip netns exec $ns sysctl -q -w net.ipv4.icmp_echo_ignore_broadcasts=0
done

for ns in $hosts; do
    ip -n $ns link set lo up
done

bmac=1
for ns in $nets; do
    ip -n $ns link add bridge0 address 02:00:00:00:00:$(printf '%02d' $bmac) type bridge
    ip -n $ns link set bridge0 up
    bmac=$(($bmac+1))
done

link_ns () {
    ip -n $1 link add name "$3" type veth peer netns $2 name "$4"
    ip -n $1 link set dev "$3" up
    ip -n $2 link set dev "$4" up

    if printf '%s\n' "$nets" | grep -q -w "$1"; then
    ip -n "$1" link set dev "$3" master bridge0
    fi
    if printf '%s\n' "$nets" | grep -q -w "$2"; then
    ip -n "$2" link set dev "$4" master bridge0
    fi
}

link_ns trunk  fakebridge fakebridge trunk0
link_ns vlan10 fakebridge fakebridge vlan10
link_ns vlan20 fakebridge fakebridge vlan20
link_ns vlan30 fakebridge fakebridge vlan30

link_ns trunk  router  router  trunk0
link_ns vlan10 Host10  Host10  eth0
link_ns vlan10 Host10b Host10b eth0
link_ns vlan20 Host20  Host20  eth0
link_ns vlan30 Host30  Host30  eth0


ip netns exec fakebridge tc qdisc add dev trunk0 ingress
for vlan in 10 20 30; do
    ip netns exec fakebridge tc qdisc add dev vlan$vlan ingress
    ip netns exec fakebridge tc filter add dev vlan$vlan parent ffff: matchall action vlan Push id $vlan action mirred egress redirect dev trunk0
    ip netns exec fakebridge tc filter add dev trunk0 parent ffff: basic match "meta(vlan mask 0xfff eq $vlan)" action vlan pop action mirred egress redirect dev vlan$vlan
done

for vlan in 10 20 30; do
    ip -n router link add link trunk0 name trunk.$vlan type vlan id $vlan
    ip -n router link set dev trunk.$vlan up
    ip netns exec router sysctl -q -w net.ipv4.conf.trunk/$vlan.forwarding=1
done
ip -n router address add 192.0.2.110/24 dev trunk.10
ip -n router address add 198.51.100.120/24 dev trunk.20
ip -n router address add 203.0.113.130/24 dev trunk.30

ip -n Host10 address add 192.0.2.10/24 dev eth0
ip -n Host10b address add 192.0.2.11/24 dev eth0
ip -n Host20 address add 198.51.100.20/24 dev eth0
ip -n Host30 address add 203.0.113.30/24 dev eth0

ip -n Host10 route add default via 192.0.2.110
ip -n Host10b route add default via 192.0.2.110
ip -n Host20 route add default via 198.51.100.120
ip -n Host30 route add default via 203.0.113.130
1
A.B