一覧NW-02-2 · Ethernetとリンク

MACアドレスとフレームの受信

ユニキャスト・ブロードキャスト・マルチキャストの宛先を調べます。

説明

MACアドレスには一台を示す個別アドレスと、複数の受信先を示すグループアドレスがあります。同じフレームがリンク上を流れても、すべての端末が上位処理へ渡すとは限りません。

三種類の宛先を持つPCAPを読み、受信条件のモデルでBとCの扱いを確認します。I/GとU/Lビットを調べ、最後に異なるIPマルチキャストが同じMACへ対応する例を計算します。

1同じLANの三つの端末

Aが送信し、BとCが受信する例です。Bだけが01:00:5e:01:02:03のマルチキャストを受け付ける設定とします。

cat nodes.csvMACと受信グループ

三台は同じVLAN内です。以後は送信元Aを除き、BとCの通常のMAC受信フィルターを比較します。プロミスキャスや全マルチキャスト受信は無効とした条件です。

2三種類の宛先を含む記録

同じDATAをユニキャスト、ブロードキャスト、マルチキャストへ送ったPCAPを読みます。

tcpdump -n -tt -e宛先MACを表示 -r destinations.pcap三種類のフレーム

宛先は順にBのMAC、ff:ff:ff:ff:ff:ff、01:00:5e:01:02:03です。EtherTypeは実験用0x88b5で、IPパケットではありません。配送先のMACだけを比較できるよう、内容は同じにしています。

3受信条件をソースで確認

delivery.pyは端末の受信条件を表す短いモデルです。全員宛て、自分宛て、加入グループ宛てを確認します。

cat delivery.py受信判定の条件

スイッチの出力ポート選択と、端末がフレームを受け付けるかは別です。このプログラムは、フレームがその端末へ届いたときの受信条件だけを判定します。実際のスイッチでどのポートへ転送するかは、学習状態やマルチキャスト制御等でも変わります。

4一台のMACへ送る

BのMACを宛先にします。

python3 delivery.py端末の受信条件を評価 02:00:00:00:00:0bBへの個別宛先

Bだけacceptです。先頭バイト02の最下位ビットI/Gが0なので個別アドレスです。次のU/Lビットが1なのでローカル管理アドレスであり、メーカーのOUIとして先頭3バイトを解釈しません。

5同じLANの全端末へ送る

全ビット1の宛先を指定します。

python3 delivery.py受信範囲を評価 ff:ff:ff:ff:ff:ffブロードキャスト宛先

BとCがacceptです。ブロードキャストは同じブロードキャスト領域へ向けた配送で、インターネットの全端末へ配る意味ではありません。ルーターは通常、このEthernetフレームをそのまま別LANへ中継しません。

6指定グループへ送る

Bだけが受け付けるグループMACを指定します。

python3 delivery.py加入グループを照合 01:00:5e:01:02:03マルチキャスト宛先

Bがaccept、Cがdiscardです。先頭バイト01のI/Gビットが1でグループアドレスを表します。スイッチ側で複数ポートへ転送されても、通常の端末フィルターで受け付ける範囲は加入設定によります。

7異なるIPグループが同じMACになる場合

IPv4マルチキャストの下位23ビットをMACへ対応させる規則で、239.1.2.3と225.1.2.3を変換します。

python3 -cIPv4グループをMACへ変換 'import ipaddress; groups=["239.1.2.3","225.1.2.3"]; print([(ip,(bytes.fromhex("01005e")+(int(ipaddress.IPv4Address(ip))&0x7fffff).to_bytes(3,"big")).hex(":")) for ip in groups])'下位23ビットの対応

両方01:00:5e:01:02:03になります。IPグループの情報すべてをMACへ写しているわけではないため、MACだけではIPグループを一意に決められません。受信側ではIP層の宛先も確認します。

まとめ

I/Gは個別・グループ、U/Lはグローバル・ローカル管理の区別に使います。

スイッチの転送範囲と端末の通常の受信フィルターは別の判定です。

IPグループとMACグループは一対一ではないため、上位の宛先も確認します。

操作履歴と解説を振り返れます。

シェル / PCAPと通信の記録

1
cat nodes.csv
NODE,MAC,MULTICAST
A,02:00:00:00:00:0a,no
B,02:00:00:00:00:0b,01:00:5e:01:02:03
C,02:00:00:00:00:0c,no
2
tcpdump -n -tt -e -r destinations.pcap
reading from file destinations.pcap, link-type EN10MB (Ethernet)
0.000000 02:00:00:00:00:0a > 02:00:00:00:00:0b, ethertype Unknown (0x88b5), length 60: 
	0x0000:  4441 5441 0000 0000 0000 0000 0000 0000  DATA............
	0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................
	0x0020:  0000 0000 0000 0000 0000 0000 0000       ..............
0.000100 02:00:00:00:00:0a > ff:ff:ff:ff:ff:ff, ethertype Unknown (0x88b5), length 60: 
	0x0000:  4441 5441 0000 0000 0000 0000 0000 0000  DATA............
	0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................
	0x0020:  0000 0000 0000 0000 0000 0000 0000       ..............
0.000200 02:00:00:00:00:0a > 01:00:5e:01:02:03, ethertype Unknown (0x88b5), length 60: 
	0x0000:  4441 5441 0000 0000 0000 0000 0000 0000  DATA............
	0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................
	0x0020:  0000 0000 0000 0000 0000 0000 0000       ..............
3
cat delivery.py
"""Destination filtering model for nodes B/C; all are on the same VLAN."""
import csv, sys
from pathlib import Path
nodes=list(csv.DictReader(Path('nodes.csv').open()))
dest=sys.argv[1].lower()
first=int(dest[:2],16)
print('destination:',dest,'I/G:',first&1,'U/L:',(first>>1)&1)
for node in nodes:
    if node['NODE']=='A':
        continue
    accepted=dest=='ff:ff:ff:ff:ff:ff' or dest==node['MAC'] or dest==node['MULTICAST']
    print(node['NODE'], 'accept' if accepted else 'discard')
4
python3 delivery.py 02:00:00:00:00:0b
destination: 02:00:00:00:00:0b I/G: 0 U/L: 1
B accept
C discard
5
python3 delivery.py ff:ff:ff:ff:ff:ff
destination: ff:ff:ff:ff:ff:ff I/G: 1 U/L: 1
B accept
C accept
6
python3 delivery.py 01:00:5e:01:02:03
destination: 01:00:5e:01:02:03 I/G: 1 U/L: 0
B accept
C discard
7
python3 -c 'import ipaddress; groups=["239.1.2.3","225.1.2.3"]; print([(ip,(bytes.fromhex("01005e")+(int(ipaddress.IPv4Address(ip))&0x7fffff).to_bytes(3,"big")).hex(":")) for ip in groups])'
[('239.1.2.3', '01:00:5e:01:02:03'), ('225.1.2.3', '01:00:5e:01:02:03')]

演習完了