Old-School Networking / 2026 ・ No.03
古法网络入门
第3讲 数据链路层 ── MAC 地址与交换机,“问所有人”的 ARP
发布
第 2 讲我们看到比特变成信号在网线上跑。
这一讲往上一层,是数据链路层。帧的收件人 MAC 地址,记住收件人并分别投递的交换机,从 IP 地址查 MAC 地址的 ARP。
第 1 讲里电脑为什么一开始就“问所有人”?我们用一台交换机和三台电脑的练习网络来确认。还会做一个实验:环路让一个帧每秒变成 55 万个。
收件人这一层
新井第 1 讲里,电脑一开始就对所有人问“10.0.1.1 的 MAC 是?”。这是不是有点失礼?一上来就问所有人。
古井不认识对方的脸,只能在教室里喊“古井在吗?”。只有被叫到的本人举手。
新井对没被叫到的人来说,是打扰吧。
古井所以有办法,只在第一次问所有人。今天就看这个。
全 12 讲路线图(当前位置:第 3 讲)
- MAC 地址 ── 6 字节的构成、厂商编号、本地与全球、发给所有人
- 交换机 ── 记住目的地,只发往需要的口。记住之前发往所有口
- ARP ── 从 IP 地址查 MAC 地址。答案记住 30 秒左右
- MTU、VLAN、STP ── 一次能运多大、把一台分开的技术、防止环路的技术
数据链路层的工作
数据链路层的工作,是在同一个网络里,送到相邻的设备。第 1 讲看到,MAC 地址每经过一台路由器就被换掉。数据链路层负责的只是“这条线上的下一台”。
为此,数据链路层把比特流切成叫帧的单位,写上收件人(目的和源 MAC 地址)和内容的种类,最后加上第 2 讲的 FCS,丢弃损坏的帧。代表是 Ethernet(有线)和 Wi-Fi(IEEE 802.11),两者都使用同样格式的 MAC 地址。
数据链路层=送到相邻设备的层。收件人是 MAC 地址,单位是帧。到远方对方的路径,是下一层第 3 层(IP)的工作。
MAC 地址
MAC 地址是 6 字节(48 位)的编号,通常用“:”连接十六进制来写。前 3 字节是 IEEE 分配给厂商的编号(OUI),后 3 字节是厂商给每台设备定的编号。
本系列电脑的 MAC 地址 02:00:00:00:01:10 的构成
第一个字节的最低两位有含义。最低位是 1 表示发给一组(组播)。全部为 1 的 ff:ff:ff:ff:ff:ff 是发给所有人(广播)。倒数第二位是 1,表示不是厂商给的编号,而是自己定的本地编号。本系列的 MAC 以 02 开头,是为了易读而手动设定的。
数一数 Wireshark 4.2.2 自带的厂商编号表,3 字节的 OUI 有 34,621 个。最多的是 Apple,1,193 个,其次是 Cisco 1,111 个、Huawei 1,097 个。一个 OUI 可以生成约 1,678 万台的编号,大公司都持有好几个。
不过,最近的手机和电脑在 Wi-Fi 上越来越多地不用真实 MAC 地址。iPhone 从 iOS 14 起有“私有 Wi-Fi 地址”,Android 从 10 起默认对每个网络使用随机的 MAC 地址。这是为了不让商店 Wi-Fi 等通过 MAC 地址追踪同一个人的行踪。请记住:MAC 地址不一定是“全球唯一的设备编号”。
帧的头部
Ethernet 帧的头部只有 14 字节。
Ethernet 头部(以及加入 VLAN 标签时)
目的地址在最前面,所以交换机只要读完前 6 个字节,就能开始查从哪个口送出去(也有在收完整帧之前就开始转发的交换机)。第三个“类型”(EtherType)是表示内容是什么的 2 字节。0800 是 IPv4 数据包,0806 是 ARP。接收方看这个编号,把内容交给下一个负责者(第 3 层)。
交换机会记住
第 2 讲说过,交换机只往目的口送。那么交换机怎么知道哪个口上是谁?答案是看收到的帧的源地址,记下来。
交换机的学习。记住发送方,不认识的目的地发往所有口
我重新搭了练习网络。用 Linux 网桥做交换机,接上新井(10.0.1.10)、古井(.11)、山田(.12)的电脑和路由器(.1)。在 4 台上同时记录,从新井向古井 ping 3 次。
# 交换机(网桥)记住的表。ping 之前是空的
$ bridge fdb show br br0
(什么都没有)
# 新井 ping 古井之后(MAC 以及对方所在的口)
$ bridge fdb show br br0
02:00:00:00:01:10 p1
02:00:00:00:01:11 p2
# 记住的内容 300 秒不用就会忘掉(ageing_time 的默认值)
| 收到的帧数 | 新井 | 古井 | 山田 | 路由器 |
|---|---|---|---|---|
| ① 普通 ping(从 ARP 开始) | 8 | 8 | 1 | 1 |
| ② 一开始就知道古井的 MAC 时 | 8 | 8 | 2 | 2 |
在①中,到达山田和路由器的只有 1 个发给所有人的 ARP。之后的 6 个 ping,交换机只发往记住的口。在②中,新井不做 ARP 就直接发给古井,交换机还不知道古井在哪个口,于是把第 1 个 ping 发往所有口(不认识的目的地就发给所有人)。有意思的是,之后古井的电脑不知道新井的 MAC,又反过来向所有人发了 ARP 询问。
新井在②里,山田收到了一个不认识的 ping。
古井不是发给自己的,山田的电脑只是丢掉。不过在同一个局域网里,像这样可能看到别人的帧。所以重要的内容要加密(第 8 讲)。
ARP:从 IP 查 MAC
应用知道的是对方的 IP 地址(第 1 讲中是 10.0.2.20)。但帧的收件人需要 MAC 地址。这时登场的是 ARP(Address Resolution Protocol)。封面照片就是新井电脑发出的 ARP 询问本身。
ARP 是“问所有人,只有本人回答”
询问是发给所有人的(目的 ff:ff:ff:ff:ff:ff),里面写着“我是 10.0.1.10、02:00:00:00:01:10,请告诉我 10.0.1.11 的 MAC”。对方的 MAC 还不知道,所以那里填 0。只有 10.0.1.11 的古井回答给新井。答案在 ARP 缓存里记一段时间,下次就不用再问了。
# ping 之后的 ARP 缓存(IP 与 MAC 的对应表)
$ ip neigh show
10.0.1.11 dev eth0 lladdr 02:00:00:00:01:11 REACHABLE
# 就这样等着……(每秒查看一次)
# 32 秒后变成 STALE(可能过期)
$ ip neigh show
10.0.1.11 dev eth0 lladdr 02:00:00:00:01:11 STALE
# 30 秒左右(15〜45 秒之间)就会变。并不会被删掉
对方在别的网络时,问对方的 MAC 也得不到回答。于是电脑去问出口路由器(默认网关)的 MAC。第 1 讲中新井的电脑问的不是 10.0.2.20 而是 10.0.1.1,就是这个原因。
ARP 没有确认“回答是否真实”的机制。同一局域网里的恶意机器如果谎称“10.0.1.1 是我”,就能截取通信(ARP 欺骗)。有些企业级交换机具备防范功能。
MTU:一次能运多大
Ethernet 帧能运的内容最多 1,500 字节。这个上限叫 MTU(Maximum Transmission Unit)。加上头部 14 和 FCS 4,帧最大 1,518 字节。再结合第 2 讲的“最少 64 字节”,帧的大小在 64〜1,518 字节之间。
我实际发了一个正好填满 MTU 的 ping,和一个只多 1 字节的 ping。
# 内容 1472 字节+ICMP 8+IP 20=1500。加上“不要分片(-M do)”发送
$ ping -c 1 -M do -s 1472 10.0.1.11
PING 10.0.1.11 (10.0.1.11) 1472(1500) bytes of data.
1480 bytes from 10.0.1.11: icmp_seq=1 ttl=64 time=0.053 ms
# 多 1 字节变成 1501……
$ ping -c 1 -M do -s 1473 10.0.1.11
PING 10.0.1.11 (10.0.1.11) 1473(1501) bytes of data.
ping: local error: message too long, mtu=1500
1,500 字节以内能通过,1,501 字节发不出去
大的数据由 TCP 切成 MTU 以内的块来发送(第 6 讲)。需要注意的是途中有 MTU 较小的区间时。家用光纤的 PPPoE(1,492)或 VPN 隧道,因为头部增加,MTU 会变小。如果只有大数据包过不去,就会出现“小页面能打开,只有大文件卡住”的怪故障(第 12 讲讨论)。
VLAN:把一台分开
办公室里“财务的电脑和访客 Wi-Fi 想接在同一台交换机上,但不想混在一起”时,不必买好几台交换机,而是用 VLAN。这是把一台交换机的口按编号当作不同局域网来处理的技术。
分成 VLAN 10 和 VLAN 20 后,“发给所有人”也分开了
在交换机之间或通往路由器的线上,为了一根线运送多个 VLAN(Trunk),会在帧里插入 4 字节的标签。81 00 是“有标签”的记号,接下来的 12 位是 VLAN 号。
本来也想在练习网络里搭 VLAN,但写这篇文章用的云端 Linux 没有 VLAN 功能,设置不了。所以照片里的帧,是把标签手工插进记录到的 ARP 里,再让 Wireshark 读取的。
环路与 STP
交换机会把“不认识的目的地和发给所有人的帧”发往所有口。那么,用两根线连接两台交换机,形成一个环(环路),会怎样?想当备用线接上去,就真的会发生。我测了一下。
实测:只发了一个“发给所有人”
从 hA 只发一个发给所有人的帧,两台交换机就互相转发,帧在环里不停地转。hB 1 秒内收到约 55 万个(测了 3 次,556,079〜582,306 个),不拔掉一根线就停不下来。帧没有像第 3 层 TTL 那样的“寿命”,所以不会自然消失。这叫广播风暴,在真实的办公室里,整个网络都会瘫痪。
防止它的是 STP(Spanning Tree Protocol,生成树协议)。交换机之间互相联络,为了不形成环,让一根线停用。
# 启用 STP 的两台交换机的端口状态(收敛用了 5.0 秒)
# SW1
pa forwarding
l1 forwarding
l2 forwarding
# SW2:第二根线(l2)是 blocking=被阻断
pb forwarding
l1 forwarding
l2 blocking
启用 STP 后,同样一个帧只到达 hB 一次。再切断正在使用的线,切换到被阻断的线花了 4.2 秒,期间 39 个 ping 没有回应。这是把老式 STP(802.1D)的等待时间设短后的值,默认设置要 30 秒左右。现在的企业交换机通常使用切换快得多的 RSTP(802.1w)。
新井只发一个就变成 55 万个……想当备用线加上去,就会这样啊。
古井古法的办公室里,有人在桌子底下把多余网线的两头插到同一个集线器上,整层楼就瘫了。家用交换机很多没有 STP。别接成环。
在自己的电脑上确认
| 想查什么 | Mac | Windows | Linux |
|---|---|---|---|
| 自己的 MAC 地址 | ifconfig en0 | ipconfig /all | ip link |
| ARP 缓存 | arp -a | arp -a | ip neigh |
| MTU | ifconfig en0 | netsh interface ipv4 show subinterfaces | ip link |
看 arp -a,一定能看到家里路由器(默认网关)的 IP 地址和 MAC 地址。因为所有发往互联网的通信,帧都是发给它的。
Wi-Fi 接入点也是数据链路层的设备。它作为连接无线一侧和有线一侧的“桥”(网桥),看 MAC 地址进行转发。电波上的帧(802.11)最多有 4 个地址,格式不同,但在电脑里会被转成和 Ethernet 一样的格式,所以在 Wireshark 里看起来几乎没区别。
结 — 一页总结与下一讲
- 数据链路层是送到相邻设备的层。收件人是 MAC 地址,单位是帧。
- MAC 是 6 字节。前半是厂商编号(OUI)。ff:ff:ff:ff:ff:ff 是发给所有人。手机的 Wi-Fi 多用随机 MAC。
- 头部 14 字节(目的、源、类型)。类型 0800 是 IPv4,0806 是 ARP。
- 交换机看源地址记下来,认识的目的地只发一个口,不认识的和发给所有人的发往所有口。
- ARP 问所有人,只有本人回答。答案进缓存。实测 32 秒变成 STALE。
- MTU 是 1,500。1,472+28 能通过,多 1 字节就发不出去。
- VLAN 把一台分开,用 4 字节标签区分。环路会让一个帧每秒变成 55 万个。用 STP 阻断一根。
新井MAC 只管到相邻设备。那像 10.0.2.20 这样远的对方,是谁来决定路线的?
古井那就是下一讲的第 3 层。先从 IP 地址本身开始。10.0.1.10 的“/24”是什么意思,你能说明吗?
参考
- Wikipedia — MAC address
- IEEE Registration Authority (OUI)
- Apple Support — Use private Wi-Fi addresses on Apple devices
- Android Open Source Project — MAC randomization behavior
- RFC 826 — An Ethernet Address Resolution Protocol
- Wikipedia — Maximum transmission unit
- Wikipedia — IEEE 802.1Q (VLAN)
- Wikipedia — Spanning Tree Protocol
- Wikipedia — Broadcast radiation (broadcast storm)
- bridge(8) — Linux manual page
- ip-neighbour(8) — Linux manual page
记录来自笔者在云端 Linux(Ubuntu 24.04)上用网络命名空间搭建的练习网络,于 2026 年 10 月 24 日抓取。交换机是 Linux 网桥(学习时间为默认的 300 秒,关闭了 IGMP 通知),环路实验也用两台 Linux 网桥(STP 为 802.1D,forward_delay 2 秒、hello_time 1 秒、max_age 6 秒)。数字都是从这些记录和当时命令的输出读出的实际数值。只有 VLAN 的帧,因为该环境无法使用 VLAN,是把标签插进记录到的 ARP 做出来的。厂商编号的数量,是数了 Wireshark 4.2.2 自带的列表(tshark -G manuf)。登场人物均为虚构。
古法网络入门 第3讲 — 数据链路层 / 2026.10