交换机与路由器:两种转发机制
网络设备按工作在哪一层分工。交换机看 MAC 地址,在一个广播域内搬帧;路由器看 IP 地址,在广播域之间搬包。
两者的差别落在动不动包上——交换机原样搬,路由器拆了重装。
1. 交换机与 MAC 表
1.1 三个动作
收帧
├─ ① 学习:把「源 MAC + 入端口」写进 MAC 表
├─ ② 查表:看目的 MAC,命中 → 只从对应端口发(单播转发)
└─ ③ 泛洪:未命中 → 从除入端口外的所有端口发学习靠源 MAC,转发靠目的 MAC——这个不对称是理解交换机的关键。一台交换机不需要任何配置,接上网线就能工作,靠的就是这个自学习机制。
MAC 表项有老化时间(通常 300 秒),老条目会被删除,所以设备换端口后网络能自己收敛。
1.2 三种转发模式
| 模式 | 读多少就开始转发 | 延迟 | 代价 |
|---|---|---|---|
| 存储转发(store-and-forward) | 收完整帧、校验 FCS | 大 | 能丢弃坏帧 |
| 直通(cut-through) | 只读前 6 字节(目的 MAC) | 小 | 会转发坏帧 |
| 无碎片(fragment-free) | 读满 64 字节(最小帧长) | 折中 | 能过滤残帧 |
直通模式的适用边界:链路质量好、对延迟敏感的场景(如高性能计算集群)。链路上误码多时,坏帧被转发出去反而浪费下游带宽。
1.3 三条性质
| 性质 | 说明 |
|---|---|
| 不隔离广播域 | 广播帧(FF:FF:FF:FF:FF:FF)泛洪到所有端口 |
| 隔离冲突域 | 每个端口一个冲突域;全双工下冲突已消失 |
| 完全不改帧 | 源/目的 MAC、TTL、校验和一个都不动 |
第三条的成因很直接——交换机不看 IP 首部,所以没有任何理由去改它。
1.4 环路要靠 STP
二层没有 TTL 这样的兜底机制。一条二层环路会让广播帧无限循环,几秒钟打满整个网络。这一个数字值得推一遍——
三台交换机两两相连(三角形),一台机器发出一个广播帧:
T=0 SW1 收到 → 从另外两个口各发一份 → SW2、SW3 各收到一份
T=1 SW2 收到 → 除入端口外泛洪 → 发回 SW1,同时发给 SW3
SW3 收到 → 除入端口外泛洪 → 发回 SW1,同时发给 SW2
T=2 SW2 又收到一份(来自 SW3)→ 再泛洪
SW3 又收到一份(来自 SW2)→ 再泛洪T=1 那一行是关键:两台交换机各自收到的那份又被互相转发了一遍,于是每绕一圈帧数翻倍。二层帧里没有任何字段会随转发递减,所以它不会自己停:
| 绕圈数 | 环上的帧数 |
|---|---|
| 1 | 2 |
| 2 | 4 |
| 10 | 1024 |
| 20 | 一百多万 |
以交换机微秒级的转发速度,几秒内就能打满链路带宽与 CPU。这就是广播风暴。
同时还有两个连带后果:
| 后果 | 机制 |
|---|---|
| MAC 表震荡(MAC flapping) | 同一个源 MAC 从两个不同端口轮流进来,表项被反复改写,CPU 全花在写表上 |
| 重复帧 | 同一个广播帧在环里绕,接收方收到多份 |
1.5 STP 怎么断环
三代防环协议的完整细节(选举与定时器、RSTP 的提议-同意握手、MSTP 的多实例与 Region)在 13-STP、RSTP 与 MSTP,这一节只讲基础机制。
解法是 STP(Spanning Tree Protocol,IEEE 802.1D):所有交换机协商出一个共识——哪些端口可以转发,哪些必须闲着。
「闲着」不等于「断开」:
| 阻塞端口仍然做 | 阻塞端口不做 |
|---|---|
收发 BPDU(协议报文) | 不转发用户数据帧 |
| 听拓扑变化 | 不学习源 MAC 到 MAC 表 |
所以那条链路平时闲着,但心跳还在。活跃链路一断,它立刻接手——这就是冗余的意义。
四步选举
| 步骤 | 选什么 | 判据 |
|---|---|---|
| 1 | 根桥(全网一台) | BID 最小 |
| 2 | 根端口(每台非根交换机一个) | 到根桥的路径开销最小 |
| 3 | 指定端口(每条链路一个) | 该链路上到根桥开销最小的一端 |
| 4 | 落选的 | 阻塞 |
BID(Bridge ID,8 字节) = 桥优先级(2 字节)+ 交换机 MAC(6 字节)。先比优先级,小的赢;相同再比 MAC。 优先级默认 32768,只能取 4096 的倍数(0、4096、8192…)。
路径开销按带宽折算并沿途累加:
| 链路带宽 | 经典 STP | RSTP |
|---|---|---|
| 10 Mbps | 100 | 2000000 |
| 100 Mbps | 19 | 200000 |
| 1 Gbps | 4 | 20000 |
| 10 Gbps | 2 | 2000 |
所以「到根桥的开销」= 沿途各出端口开销之和。环里开销大的那条链路,会有一端被判为阻塞——这就是图里 SW3 ↔ SW2 那条的由来。
BPDU
上述信息靠 BPDU 传递,默认每 2 秒一次,发往链路协议专用组播地址 01:80:C2:00:00:00(交换机不会转发这类帧,只在本机处理)。
| 字段 | 作用 |
|---|---|
| 根桥 ID | 发送方认为的根桥是谁 |
| 到根桥的路径开销 | 从这里到根桥要花多少 |
| 发送方桥 ID / 端口 ID | 我是谁、从哪个口发的 |
| 消息寿命 / 最大寿命 | 防止 BPDU 无限转发的计时字段 |
「发送方认为的根桥」是协议的精髓:每台交换机启动时都以为自己是根桥(BPDU 里填自己),收到别人的 BPDU 一比较——发现对方报的根桥更优就改认对方,并把更新后的信息往下游传。这个过程就是收敛。
根桥持续每 2 秒发一次;非根交换机收到后把自己的开销加上再往下传,所以从根桥往外,BPDU 里的开销递增。
端口状态与收敛时间
经典 STP 的五个状态:
| 状态 | 持续 | 收 BPDU | 学 MAC | 转发数据 |
|---|---|---|---|---|
Disabled | —— | 否 | 否 | 否 |
Blocking | —— | 是 | 否 | 否 |
Listening | 15 秒 | 是 | 否 | 否 |
Learning | 15 秒 | 是 | 是 | 否 |
Forwarding | —— | 是 | 是 | 是 |
从阻塞到转发最少等 30 秒(15 + 15),全程通常 30~50 秒。
为什么要等:拓扑变化时新 BPDU 要一层层传到全网,传播本身需要时间。端口若立刻转发,在「有人还以为旧拓扑有效」的窗口里会形成临时环路。这 30 秒是用一个保守的等待窗口覆盖信息传播的最坏延迟。
这个数字在今天很难接受——插上网线等半分钟才通。这是 RSTP 出现的主要动机。
拓扑变化的通知
链路断了,下游怎么告诉根桥?靠 TCN BPDU:
1. 发现变化的交换机 → 从根端口向上游发 TCN
2. 上游继续向上转发 → 一直到根桥
3. 根桥 → 回带 TCA 标志的 BPDU 确认
4. 根桥 → 向下游广播「拓扑变了」
5. 所有交换机把 MAC 表老化时间从 300 秒缩短到 15 秒第 5 步是关键:拓扑变了,原有的「MAC → 端口」映射可能已失效,不清理就会继续往旧端口发。缩短老化时间让收敛更快。
三代协议
| 协议 | 标准 | 状态数 | 收敛 | 关键改进 |
|---|---|---|---|---|
| STP | 802.1D | 5 | 30~50 秒 | 基础版本 |
| RSTP | 802.1w | 3 | 亚秒级 | 提议 / 同意握手,断开即可切换 |
| MSTP | 802.1s | 3 | 亚秒级 | 多实例,可做负载分担 |
RSTP 快在哪:把 Listening / Learning 合并成 Discarding,引入提议-同意(Proposal-Agreement)握手——上游发提议、下游同意,端口立刻转发,不等定时器。只有对端不回话时才退回老的等待模式。
MSTP 解决的是闲置问题:经典 STP 全网只有一棵树,所有 VLAN 共用同一条活跃路径,其余冗余链路全部闲置。MSTP 把多个 VLAN 映射到不同实例,每实例一棵独立的树:
实例 1(VLAN 1-10) → 活跃路径走链路 A
实例 2(VLAN 11-20) → 活跃路径走链路 B两条链路都在用,冗余链路从「闲置」变成「负载分担」。
代价与替代
核心代价是「用闲置换无环」——为断环必须阻塞链路,而阻塞的就是白白闲置的带宽。
| 方案 | 思路 |
|---|---|
| MLAG / vPC | 把两台物理交换机当成一台逻辑设备,从根上不产生环,链路全部可用 |
| TRILL / SPB | 用类似三层路由的方式做二层转发,支持多路径 |
| VXLAN + EVPN | 数据中心主流:用 overlay 封装绕过二层,底层走三层等价多路径 |
数据中心现在基本不以 STP 为主力——要么 MLAG 消环,要么 VXLAN 绕开二层。STP 主要留在办公网与接入层这类对收敛不苛刻的场景。
三个最常见的坑
| 现象 | 成因 | 处置 |
|---|---|---|
| 根桥不是核心交换机 | 默认优先级全为 32768,于是比 MAC——MAC 小的当选,等于随机。一台接入层设备可能成为全网中心 | 核心交换机显式配 priority 4096 |
| 插了台家用路由器全网卡顿 | 它发 BPDU 参与选举,或不参与导致临时环路 | 接入端口配 BPDU Guard(收到 BPDU 就关端口) |
| 收敛慢、业务中断 30 秒以上 | 还在跑经典 STP | 换 RSTP,终端口配 edge port 不参与选举 |
# Linux bridge
cat /sys/class/net/br0/bridge/root_id # 根桥 ID
bridge link show # 各端口状态2. 路由器与路由表
2.1 完整转发路径
收到帧
├─ 目的 MAC 不是本机,也不是组播/广播 → 丢弃
└─ 剥掉帧头,把 IP 包交给 IP 层
├─ 目的地址是本机 → 按 Protocol 字段交给上层协议
└─ 需要转发
├─ TTL 减 1;减到 0 → 丢弃 + 回 ICMP Time Exceeded
├─ 查路由表(最长前缀匹配)
│ ├─ 无命中 → 丢弃 + 回 ICMP Destination Unreachable
│ └─ 命中 → 得到下一跳与出接口
├─ 包长 > 出接口 MTU?
│ ├─ DF=0 → 分片
│ └─ DF=1 → 丢弃 + 回 ICMP Fragmentation Needed
├─ 重算 IP 首部校验和(TTL 变了)
├─ 查 ARP 缓存拿下一跳的 MAC → 重新封装成帧
└─ 从出接口发出第 7、8 步是路由器的核心特征:
TTL变了,首部校验和必须重算(TCP 的校验和不用改,因为它不覆盖TTL);- 下一跳变了,帧头的目的 MAC 必须换。
所以同一个包穿过多个路由器时,MAC 地址逐跳改写,IP 地址端到端不变。
2.2 路由表的四个来源
$ ip route show
default via 10.0.0.1 dev eth0 proto dhcp metric 100 # 租约下发
10.1.0.0/16 via 10.0.0.2 dev eth0 proto static # 手工配置
10.0.0.0/24 dev eth0 proto kernel scope link # 内核按掩码自动算
172.16.0.0/16 via 10.0.0.3 dev eth0 proto ospf # 动态路由协议proto 字段是排查的钥匙——看到一条不符合预期的路由,先看这一列就知道该去哪改:
proto | 来源 | 该去哪改 |
|---|---|---|
kernel | 配地址时按掩码自动生成 | 改地址配置 |
static | 手工 ip route add | 改配置或脚本 |
dhcp | 租约下发(见 11-主机接入网络:DHCP 与地址配置) | 改 DHCP 服务器 |
ospf / bgp / isis | 动态协议学到的 | 查协议邻居 |
2.3 三条性质
| 性质 | 说明 |
|---|---|
| 隔离广播域 | 不转发广播帧,一个接口一个广播域 |
| 每跳改包 | TTL 减一、校验和重算、帧头 MAC 重写 |
| 查不到就丢 | 回 ICMP Destination Unreachable,没有泛洪兜底 |
3. 逐项对比
| 维度 | 交换机 | 路由器 |
|---|---|---|
| 工作层 | 二层(链路层) | 三层(网络层) |
| 转发表 | MAC 表 | 路由表 / FIB |
| 表的来源 | 自学习(看源 MAC) | 直连 + 静态 + 动态协议 + DHCP |
| 匹配方式 | 精确匹配(48 位全等) | 最长前缀匹配 |
| 是否改包 | 完全不动 | TTL、校验和、帧头 MAC 全改 |
| 隔离广播域 | 不能 | 能 |
| 查不到时 | 泛洪 | 丢包 + ICMP |
| 环路防护 | STP(协议主动断环) | TTL(自然兜底) |
| 延迟量级 | 微秒 | 几十微秒到毫秒 |
| 端口成本 | 低(芯片简单) | 高(要跑协议、存路由) |
一句话分工:
交换机在一个广播域内用 MAC 地址搬帧,路由器在广播域之间用 IP 地址搬包。MAC 逐跳改写,IP 端到端不变。
广播域与冲突域
两个概念的区分值得单独记:
| 设备 | 隔离冲突域 | 隔离广播域 |
|---|---|---|
| 集线器(Hub) | 否 | 否 |
| 交换机 | 是(每端口一个) | 否 |
| 路由器 | 是 | 是(每接口一个) |
| VLAN | —— | 是(一个 VLAN 一个广播域) |
VLAN 的价值就在这张表里:它让一台交换机上划分出多个广播域,等价于「在一台设备里装了多台逻辑交换机」。跨 VLAN 通信必须经过三层——这是 VLAN 安全隔离的基础。
4. 为什么需要两种设备
| 只用交换机 | 只用路由器 |
|---|---|
| 广播域无限大,一台主机的广播打到全网 | 每个网段都要一个接口,成本爆炸 |
| 无法跨越网段 | 慢:每个包都要拆装 |
三层交换机
折中产物:把路由功能做进交换芯片。
- 第一个包走慢路径:CPU 查路由表、把结果装进硬件转发表;
- 后续同一条流的包直接查硬件表,不再经过 CPU。
这叫「一次路由、多次交换」。数据中心里跨 VLAN 的流量基本都靠它——层二的速度、层三的功能。
代价是它通常不具备广域网接口,也跑不了完整的 BGP 表(FIB 表项受芯片容量限制)。
5. 现实中的设备是组合体
「交换机」和「路由器」是逻辑角色,实际设备经常一身兼多职:
| 场景 | 实际构成 |
|---|---|
| 家用路由器 | 交换机 + 路由器 + NAT + DHCP 服务器,一个盒子 |
| 数据中心接入交换机 | 三层交换机,兼做 VLAN 间路由 |
| K8s 节点 | Linux bridge 当交换机、IP 转发当路由器,都在内核里 |
| 容器 | 每个 netns 一套独立路由表,靠 veth 对接到 bridge |
容器网络是这套模型的直接翻版:
容器 netns 宿主机
eth0 ←── veth 对 ──→ veth0 ┐
├─ bridge(当交换机用,也有 MAC 表与自学习)
容器 B 的 veth ───────────────┘
└─ ip_forward=1(当路由器用)Linux bridge 的行为与物理交换机几乎一致:MAC 表、自学习、泛洪、老化都有。net.ipv4.ip_forward=1 打开的就是「路由转发」这个角色。
云厂商的 VPC 也是同一套抽象:子网 = 广播域,路由表 = 三层路由,安全组作用在两边。
6. 排查时按哪张表找
三个层次的「转发失败」对应三种完全不同的现象,按这个顺序查:
| 顺序 | 查什么 | 命令 | 失败现象 |
|---|---|---|---|
| 1 | 路由表 | ip route get <目标> | Network is unreachable / No route to host |
| 2 | 邻居表 | ip neigh show | 路由有但下一跳解析不出来 |
| 3 | 交换机 MAC 表 | 交换机管理界面 | 链路层泛洪、丢包 |
三类典型症状
| 症状 | 指向 | 依据 |
|---|---|---|
| 同网段通、跨网段不通 | 路由问题 | 默认路由缺失或网关配错 |
| 路由有、网关 ping 不通 | ARP 问题 | ip neigh 里网关是 FAILED |
| 时通时不通、广播量大 | 交换机问题 | MAC 表被打满,或者存在二层环路 |
| 跨 VLAN 不通 | 三层问题 | 没配 VLAN 间路由(SVI 或单臂路由) |
一个直接的判据:ping 不通时先看它是「立刻报错」还是「卡住超时」。
- 立刻报错(
Network is unreachable)→ 本机路由表就没有可用条目,问题在自己; - 卡住超时 → 包发出去了但没回来,问题在中间或对端。
这个区分能把排查范围立刻砍掉一半。
相关
- 10-以太网与 ARP —— 链路层细节:以太网帧格式、MAC 地址、交换机的 MAC 表与泛洪
- 08-IP 协议与路由 —— 网络层细节:IP 首部字段、路由表的最长前缀匹配、转发与分片
- 11-主机接入网络:DHCP 与地址配置 —— 一台主机接入时,路由表与邻居表是怎么建起来的
- 01-容器的本质 ——
netns与veth:容器里这套模型的软件实现
参考
- IEEE 802.1D — MAC Bridges (Spanning Tree Protocol). IEEE. https://standards.ieee.org/ieee/802.1D/998/
- IEEE 802.1Q — Bridges and Bridged Networks. IEEE. https://standards.ieee.org/ieee/802.1Q/6844/
- F. Baker, ed. Requirements for IP Version 4 Routers. RFC 1812, June 1995. https://www.rfc-editor.org/rfc/rfc1812
- Linux Bridge. Linux kernel documentation,
Documentation/networking/bridge.rst. https://www.kernel.org/doc/Documentation/networking/bridge.rst
IEEE 802.1D 与 802.1Q 是付费标准,本篇的 STP 与 VLAN 描述对照公开资料;Linux bridge 与 ip_forward 的行为来自内核文档,未逐条对应到单一规范。
YJ