8.1 Ethernet frame、MAC address 与邻居解析
数据链路层负责当前链路上的帧封装、MAC 寻址和交换。在常见的 IPv4 局域网中,ARP 将下一跳 IP 地址解析为 MAC 地址。路由器把数据包转发到下一条链路时,会重新封装链路层首部。
网络层的数据包(packet)会被封装成当前链路使用的帧(frame)。铜缆信号、光调制、无线信道和位同步属于物理层;帧边界、链路内寻址与差错检测属于链路层。排障时先分清这两层,换网线和查 MAC 表解决的是不同问题。
1. Ethernet II frame 的计数边界
| Destination | Source | Type | Payload + padding | FCS |
| 6 B | 6 B | 2 B | 46–1500 B | 4 B |对普通 untagged Ethernet frame,从 Destination address 到 FCS 通常为 64–1518 bytes。Preamble(7 bytes)和 Start Frame Delimiter(1 byte)用于 physical/MAC synchronization,不计入这个 64–1518-byte frame size。Interpacket gap 也不是 frame field。
| Field | 作用 |
|---|---|
| Destination | unicast、multicast 或 broadcast destination MAC address |
| Source | sender MAC address,不应是 multicast address |
| EtherType | 标识 payload protocol,如 IPv4 0x0800、ARP 0x0806、IPv6 0x86DD |
| Payload/pad | network-layer packet;太短时 padding 使 frame 达到 minimum size |
| FCS | 接收方通过 CRC 校验检测损坏,通常丢弃校验失败的帧;不负责重传 |
这个 2-byte 字段在值不大于 1500 时表示长度,不小于 1536(0x0600)时按 EtherType 解释;中间的 1501–1535 不属于这两种有效范围。抓包通常没有 preamble/SFD,网卡或驱动也常剥离 FCS。例如 60 bytes 的捕获数据加上线上 4-byte FCS,正好是 64-byte 最小帧;不能再把本来就不计入帧长的 preamble/SFD 混进来。还要检查抓包链路类型与截断长度。
64-byte minimum 源于 classic shared-medium half-duplex Ethernet 的 collision detection constraint。现代 switched full-duplex Ethernet 不使用 CSMA/CD 解决 collision,但 frame format compatibility 保留了 minimum size。
2. MAC address 不是 physical location
常见 Ethernet MAC address 为 48 bits,例如 02:00:5e:10:00:01。按常用十六进制写法,第一个字节有两个重要标志:
- I/G bit 是最低位(掩码
0x01):0 为单播,1 为组播; - U/L bit 是次低位(掩码
0x02):0 表示全局管理,1 表示本地管理。
因此例子中的 02 表示本地管理的单播地址;仅看字符串开头并不能确认是哪台设备。
ff:ff:ff:ff:ff:ff 是 broadcast address。Universally administered address 的 prefix 可由 IEEE registration authority 分配,但这不意味每个 MAC address 都是厂商烧录、全球唯一或永久不变。OS 可配置 locally administered address,Wi-Fi client 也常做 address randomization:virtual interface、container 和 VM 同样可生成 MAC address。
MAC address 用于链路层转发,不能证明身份、地理位置或 Internet 路由位置。它可被伪造,也可在不同广播域重复。路由器转发到下一条 Ethernet 链路时会重建源/目的 MAC 首部;普通二层交换转发通常保留这两个地址。
3. 发给谁:先 route lookup,再 neighbor lookup
Host 要向 destination IP 发 packet 时,不是立即 ARP destination IP。先用 route table 决定:
- outgoing interface;
- next-hop IP;
- source address 和其他 route attributes。
如果 destination 在 directly connected prefix,next hop 通常就是 destination。如果 destination 在 remote network,next hop 是 gateway/router。Neighbor resolution 解析的是 next-hop link-layer address,所以 host 访问 Internet server 时,在 local Ethernet 上通常查 gateway MAC,不是 remote server MAC。
# Linux:看 kernel 对某 destination 的 route decision
ip route get 203.0.113.10
# 查 neighbor table
ip neigh show4. IPv4 ARP
ARP 在同一 link/broadcast domain 上将 IPv4 protocol address 映射到 link-layer address。Typical exchange:
Host A broadcasts:
Who has 192.0.2.1? Tell 192.0.2.10
Owner of 192.0.2.1 usually unicasts:
192.0.2.1 is at 02:00:5e:00:53:01初次解析未知 MAC 时,ARP request 通常使用 Ethernet broadcast,ARP 内部的 target hardware address 未知,常填零;它与外层广播目的 MAC 是两个字段。Reply 通常单播给请求者。已有映射的缓存验证也可能使用单播 ARP request。Host 会将 mapping 放入 neighbor table,但 cache lifetime/state machine 是 OS-specific,不要硬编码“都是 120 秒”。Linux 会显示 INCOMPLETE、REACHABLE、STALE、DELAY、PROBE、FAILED 等 neighbor state。
RFC 5227 区分地址探测与公告:ARP Probe 的 sender IP 为 0.0.0.0,target IP 是准备使用的地址;ARP Announcement 则把已采用的地址同时填入 sender IP 与 target IP,用于公告并辅助冲突处理。故障切换常用 gratuitous ARP 更新映射,但接收方是否接受取决于系统与安全配置。ARP 没有密码学认证,报文里自报家门不等于核验身份。
5. IPv6 不使用 ARP
IPv6 使用 ICMPv6 Neighbor Discovery(NDP)完成 address resolution、router discovery、prefix discovery、neighbor reachability detection 等任务。用于地址解析的 Neighbor Solicitation 发往 solicited-node multicast;对已知邻居做可达性探测时,也可发送单播 NS。IPv6 没有照搬 Ethernet broadcast ARP。
NDP 依赖 ICMPv6。粗暴阻断所有 ICMPv6 会破坏 IPv6 neighbor discovery、Path MTU Discovery 和其他基本功能。Security design 要按 ICMPv6 type/code 与 rate policy 过滤,不是“禁止 ICMP 更安全”。
6. 一个不伪造 FCS 的 Ethernet II parser
Packet capture 常只提供 Destination 开始、FCS 已被 strip 的 bytes。下面的 parser 只接收无 VLAN tag、FCS 已剥离的 Ethernet II 数据,不自动猜测抓包格式,也不从末尾零字节推断 padding:
from dataclasses import dataclass
import struct
@dataclass(frozen=True)
class EthernetII:
destination: str
source: str
ethertype: int
payload_and_padding: bytes
def format_mac(raw: bytes) -> str:
return ":".join(f"{octet:02x}" for octet in raw)
def parse_ethernet_ii(raw: bytes) -> EthernetII:
if len(raw) < 14:
raise ValueError("capture is shorter than an Ethernet II header")
destination = format_mac(raw[0:6])
source = format_mac(raw[6:12])
ethertype = struct.unpack("!H", raw[12:14])[0]
if ethertype < 0x0600:
raise ValueError("not a valid EtherType for this parser")
if ethertype in (0x8100, 0x88A8):
raise ValueError("VLAN-tagged frames need a tag-aware parser")
return EthernetII(destination, source, ethertype, raw[14:])
sample = bytes.fromhex(
"ffffffffffff" # Ethernet destination
"02005e100001" # Ethernet source
"0806" # ARP EtherType
"0001080006040001" # Ethernet/IPv4, address lengths, ARP request
"02005e100001c000020a" # sender MAC, 192.0.2.10
"000000000000c0000201" # unknown target MAC, 192.0.2.1
) + bytes(18) # pad 28-byte ARP payload to 46 bytes
assert len(sample) == 60 # 64 bytes on wire once the FCS is included
frame = parse_ethernet_ii(sample)
assert frame.destination == "ff:ff:ff:ff:ff:ff"
assert frame.ethertype == 0x0806
print(frame)示例包含完整 ARP request 与 padding,但不含 FCS。Parser 只拆首部,并未验证每种 EtherType 的载荷结构、帧长上限或地址合法性;解析成功不等于通过线上验收。它保留末尾的 padding,因为零字节也可能是有效载荷,不能看见零就删。已识别的 VLAN tag 被明确拒绝,下一课再解释其布局。
7. 验收问题
- 为什么 packet capture 显示 60 bytes 不等于 wire 上的 frame 违反 64-byte minimum?
- 区分 MAC address 的 I/G 与 U/L bit。
- Host
192.0.2.10/24访问198.51.100.8,default gateway 是192.0.2.1:ARP target 应是谁? - 为什么 MAC address 不能作为 authentication identity?
- 列出 IPv6 NDP 比 IPv4 ARP 多承担的两项任务。
下一课进入8.2 Ethernet switching、VLAN 与环路防护。