bigywater.tech
网络协议 · 5

VLAN 与 802.1Q:帧里多出来的 4 字节

VLAN 的标签只有 4 个字节,却让一张物理网络变成很多个逻辑网络。这篇把 802.1Q 标签按位拆开,拼一个真正的带标签帧让 tcpdump 解析,并说清楚它对帧长、MTU 的影响,以及这台机器上为什么看不到真实的标签。

+4 字节
一层 802.1Q 标签让帧长增加的字节数(Q-in-Q 两层 +8)
4094
12 位 VLAN 号里实际可用的数量(0 和 4095 保留)
0 个
真实网口 en0 上 20 秒内抓到的带标签帧——接入口上标签已被剥掉

标签的位置和格式

实测 · 本机执行输出
  ifconfig 里含 vlan 的接口: 没有
  networksetup -listVLANs: There are no VLANs currently configured on this system.
  en0 上 `vlan` 过滤器 20 秒内抓到 0 个帧——接入口(access port)上交换机已经把标签剥掉了,主机看到的是普通帧;标签只在交换机之间的干道(trunk)上出现

在源 MAC 之后、EtherType 之前插入 4 字节:TPID=0x8100(表示这是 802.1Q 标签),接着 16 位的 TCI,拆成 PCP(3 位优先级)、DEI(1 位)和 VID(12 位)。

主机看不到标签

实测 · 本机执行输出
  没标签的帧(前 18 字节): 02 11 22 33 44 55 02 aa bb cc dd ee 08 00 45 00 00 26
    目的 MAC 02 11 22 33 44 55  源 MAC 02 aa bb cc dd ee  EtherType 08 00(0800=IPv4)
  带标签的帧(前 22 字节): 02 11 22 33 44 55 02 aa bb cc dd ee 81 00 a0 64 08 00 45 00 00 26
    目的 MAC、源 MAC 之后多出 4 字节: 81 00 a0 64  → TPID=81 00(8100 = 802.1Q) TCI=a0 64(0xa064);原来的 EtherType 08 00 被挤到标签后面
    TCI 拆开:PCP = 5(3 位优先级) DEI = 0(1 位丢弃标志) VID = 100(12 位 VLAN 号)
  tcpdump 解析: 06:13:20.000000 02:aa:bb:cc:dd:ee > 02:11:22:33:44:55, ethertype IPv4 (0x0800), length 52: 10.0.0.1.1234 > 10.0.0.2.5678: UDP, length 10
  tcpdump 解析: 06:13:21.000000 02:aa:bb:cc:dd:ee > 02:11:22:33:44:55, ethertype 802.1Q (0x8100), length 56: vlan 100, p 5, ethertype IPv4 (0x0800), 10.0.0.1.1234 > 10.0.0.2.5678: UDP, l
  dpkt 解析: vlan_tags = [(pri, cfi, vid)] = [(5, 0, 100)],去掉标签后载荷是 IP

接入口上交换机已经把标签剥掉,只有交换机之间的 trunk 才带标签,所以在普通主机上抓包看不到(实测 20 秒 0 个)。

对帧长的影响

实测 · 本机执行输出
  载荷 1500:没标签 1514 字节,带标签 1518 字节(+4);加上 4 字节 FCS:1518 → 1522
  最小帧(按 802.3 / 802.1Q 规范,不是实测):整个帧含 FCS 至少 64 字节,所以没标签时载荷至少 46 字节,带标签时载荷至少 42 字节,更短的由网卡补零

带标签的帧最大 1518(不含 FCS),不带的是 1514;VLAN 接口的 MTU 仍是 1500。

Q-in-Q

实测 · 本机执行输出
  双层标签的帧(前 26 字节): 02 11 22 33 44 55 02 aa bb cc dd ee 88 a8 00 c8 81 00 a0 64 08 00 45 00 00 26
  tcpdump 解析: 06:13:20.000000 02:aa:bb:cc:dd:ee > 02:11:22:33:44:55, ethertype 802.1Q-QinQ (0x88a8), length 60: vlan 200, p 0, ethertype 802.1Q (0x8100), vlan 100, p 5, ethertype IPv4 (0x0800), 10.0.0.1.1234 > 10.0
  帧长 60 字节,比没标签的多 8 字节(2 个标签 × 4)

运营商在客户标签外再加一层 0x88a8 的 S-TAG,帧长再 +4。

取值范围

实测 · 本机执行输出
  8 × 4096 = 32768 种 (PCP, VID) 组合打包后再解出来全部一致: True
  可用 VLAN 号 1~4094 = 4094 个;PCP 0~7 = 8 级优先级(7 最高,不同厂商对应的队列策略不同)
  VLAN 1 通常是默认 VLAN;很多交换机的 trunk 上默认 VLAN 的帧不带标签(native VLAN)——这是配置错误的常见来源,本机无法实验

VID 12 位,可用 1~4094;PCP 3 位 8 级。native VLAN(trunk 上不带标签的那个)是常见的配置陷阱。

分步演示

VLAN 与 802.1Q
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64(Apple 芯片)/ Python 3.14.8 / tcpdump(libpcap)/ scapy 2.8 / dpkt / dnspython / h2 / aioquic / OpenSSL / curl 8.7.1;抓包在 lo0(环回)上做,少数实验用真实网卡 en0(这台机器上 en0 是 Wi-Fi,tcpdump 看到的是系统转成以太网格式的帧,所以文中的“以太网头”都指这个 14 字节的头)或访问公网(会在文章里注明);需要丢包 / 延迟 / 限速时,用一个只作用于 lo0 端口 9400-9499 的 dummynet 辅助脚本(netlab);所有服务端都是本机自己起的进程;时间戳取自 tcpdump 的 -tt,数字每次运行会有小幅抖动。第一节是真实环境的观察;第二到五节用 struct 自己拼帧、写成 pcap 再用 tcpdump -r 与 dpkt 解析——验证的是 802.1Q 的帧格式,而不是真实 VLAN 流量(这台机器无法创建 VLAN 接口、也不能注入原始帧)
    • 没有验证:真实交换机的 trunk / access 行为;native VLAN 错配;VLAN 间路由;STP / 多实例生成树;QoS 对 PCP 的映射;VXLAN 等覆盖网络(见“VPN 隧道封装”一篇);802.1ad 的 DEI/DE 位在运营商网络里的用法
    京ICP备2026067502号-1京公网安备11010502063487号