MACアドレスの学習とフレーム転送
同じスイッチへフレームを順に入れ、転送表と出力ポートの変化を確認します。
説明
Ethernetスイッチは受信したフレームの送信元MACから、その端末がいる方向を学習します。宛先が未学習なら同じVLAN内へ広く送り、学習済みなら対応するポートを選びます。
4ポートのスイッチを使い、最初の送信、返信、繰返し通信、端末移動、一定時間後の送信を順に計算します。転送表を毎回残し、どの受信が表を更新したのかを確認します。
1同じVLANの4ポート
AとBはMACの短縮ラベルです。4ポートともVLAN10に所属し、最初の転送表は空とします。
ports = {1: 10, 2: 10, 3: 10, 4: 10}VLAN所属; fdb = {}; age = 30空の転送表と保持秒数; print(ports, fdb)初期状態FDBはMACとポートの対応を保持する表です。このモデルではVLANもキーに含め、最後に送信元として観測してから30秒で期限切れとします。実機の保持時間は設定によって異なります。
2受信時の学習と出力ポート
関数は期限切れを除去し、送信元を受信ポートへ記録してから宛先を調べます。通常のユニキャストのみを扱います。
def receive(now, ingress, source, destination):時刻と受信フレーム
vlan = ports[ingress]受信VLAN
expired = [key for key, (_, seen) in fdb.items() if now - seen >= age]期限切れを抽出
for key in expired:
del fdb[key]期限切れを削除
fdb[vlan, source] = (ingress, now)送信元を学習
target = fdb.get((vlan, destination))宛先を検索
outputs = [target[0]] if target else [p for p,v in ports.items() if v == vlan]既知の宛先または同じVLAN
outputs = [p for p in outputs if p != ingress]受信ポートを除外
print("out=", outputs, "FDB=", sorted(fdb.items()))転送先と表を表示学習に使うのは送信元で、転送先の検索に使うのは宛先です。通常の動作では入ってきたポートへ同じフレームを送り返しません。この関数はhairpin転送やポート制限等を含まない基本モデルです。
3最初のAからBへの送信
時刻0でAからBへのフレームをポート1に入れます。
receive(0, 1, "A", "B")ポート1でAからBを受信Aはポート1と学習され、未学習のB宛ては2・3・4へ出ます。フラッディングしても宛先MACをブロードキャストへ書き換えるわけではなく、B宛ての同じフレームを複数方向へ送ります。
4Bからの返信
1秒後、ポート2からBがAへ返信します。
receive(1, 2, "B", "A")ポート2から返信Bがポート2と学習され、A宛ては既知のポート1だけへ出ます。最初のAの送信が、返信の転送先を決める情報になっています。
5同じAからBでも出力先が変わる
2秒後に最初と同じA→Bを送ります。
receive(2, 1, "A", "B")学習後の同じ通信今度はポート2だけです。Aの最終観測時刻は2に更新されますが、Bは送信元として観測されていないので時刻1のままです。宛先へ転送しただけで、このモデルのBの保持期限は延長しません。
6端末を別のポートへ移動
Bをポート4へ移し、そこからAへ送信します。その後Aから返信します。
receive(3, 4, "B", "A")Bの新しい受信方向を学習; receive(4, 1, "A", "B")更新後の転送先Bの対応が2から4へ更新され、Aの返信も4へ出ます。同じMACが短時間に複数ポートを行き来する場合は、端末移動だけでなくループ等も調べます。
7保持時間を過ぎた後の通信
次の送信は36秒時点です。最後の観測から30秒以上たった項目を除去してから転送します。
receive(36, 1, "A", "B")無通信時間の後に再送Bの対応が期限切れとなり、再び2・3・4へ出ます。Aはこのフレームで新しく学習されています。期限切れは端末の故障を意味せず、最近どの方向にいるかという学習情報が失われた状態です。
8宛先が受信ポート側にある場合
ポート1の先に別のブリッジがあり、AとBがどちらもその先にいる状態を考えます。BからAをポート1で受けます。
receive(37, 1, "B", "A")同じ方向の端末間通信出力は空です。Aも同じポート1の先と分かっているため、他ポートへ送る必要がありません。スイッチは送信元の学習と宛先の転送判定を分けて行います。
まとめ
FDBは受信した送信元MACから更新し、宛先MACで転送先を調べます。
未知宛先のフラッディングと、宛先MACがブロードキャストであることは別です。
端末移動や保持期限により、同じ宛先でも出力ポートが変わります。
操作履歴と解説を振り返れます。
Python 3
ports = {1: 10, 2: 10, 3: 10, 4: 10}; fdb = {}; age = 30; print(ports, fdb){1: 10, 2: 10, 3: 10, 4: 10} {}def receive(now, ingress, source, destination):
vlan = ports[ingress]
expired = [key for key, (_, seen) in fdb.items() if now - seen >= age]
for key in expired:
del fdb[key]
fdb[vlan, source] = (ingress, now)
target = fdb.get((vlan, destination))
outputs = [target[0]] if target else [p for p,v in ports.items() if v == vlan]
outputs = [p for p in outputs if p != ingress]
print("out=", outputs, "FDB=", sorted(fdb.items()))receive(0, 1, "A", "B")out= [2, 3, 4] FDB= [((10, 'A'), (1, 0))]
receive(1, 2, "B", "A")out= [1] FDB= [((10, 'A'), (1, 0)), ((10, 'B'), (2, 1))]
receive(2, 1, "A", "B")out= [2] FDB= [((10, 'A'), (1, 2)), ((10, 'B'), (2, 1))]
receive(3, 4, "B", "A"); receive(4, 1, "A", "B")out= [1] FDB= [((10, 'A'), (1, 2)), ((10, 'B'), (4, 3))] out= [4] FDB= [((10, 'A'), (1, 4)), ((10, 'B'), (4, 3))]
receive(36, 1, "A", "B")out= [2, 3, 4] FDB= [((10, 'A'), (1, 36))]
receive(37, 1, "B", "A")out= [] FDB= [((10, 'A'), (1, 36)), ((10, 'B'), (1, 37))]
演習完了