NNetpath
原理入门预计 30 分钟

二层与三层:ARP、VLAN、子网与转发

交换机怎么决定往哪个口发,路由器怎么决定下一跳,以及同网段与跨网段的区别。

学完这节你能做到

  • 解释 ARP 的作用,并说出 ARP 表异常会造成什么现象
  • 看懂 CIDR 前缀,快速算出可用地址数与广播域大小
  • 读懂一台 Linux 主机的路由表并预测某个目的地址走哪条路

建议先学跳过这几节会看不懂本节的部分推导

只有两种情况

上一节说了 MAC 管同网段、IP 管跨网段。这一节把它落到具体动作上。

一台机器要发包,只需要判断一件事:目标在不在我这个网段?

目标在同一网段  →  直接发给它(二层转发,需要知道它的 MAC)
目标不在同一网段 →  发给网关,让网关去操心(三层转发)

就这两种情况。所有的路由表、ARP、VLAN 都是围绕这个判断展开的。

怎么判断"同不同网段"

靠子网掩码。看一个真实的地址配置:

ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
    inet 10.0.12.34/24 brd 10.0.12.255 scope global eth0

/24 是掩码长度,含义是:IP 的前 24 位是「网段」,剩下 8 位是「这个网段里的第几台」

10.0.12.34/24
└─────┬──┘└┬┘
   网段    主机号
10.0.12.0  ~ 10.0.12.255 都属于同一网段

判断过程就是把双方的 IP 都按掩码"切一刀",比较网段部分:

目标地址网段(按 /24 切)同网段?怎么发
10.0.12.9910.0.12直接发
10.0.13.510.0.13交给网关
8.8.8.88.8.8交给网关

常见掩码要有数量感

掩码可用主机数常见用途
/302两台设备互联的点对点链路
/24254最常见,一个机架或一个 VLAN
/221022一组机架
/1665534整个机房,或 K8s 的 Pod CIDR
/8一千六百多万10.0.0.0/8 整个私有网段
一个够用的心算法

/24 是 256 个地址。掩码每减 1,地址数翻倍

/24 = 256      /23 = 512     /22 = 1024
/25 = 128      /26 = 64      /27 = 32

实际可用要减 2(一个网络号、一个广播地址)。所以 /24 是 254 台,不是 256 台。

这个数量感在 L3 规划那节要反复用:给 K8s 划 Pod CIDR、给机房划 VLAN, 算错一位就是十几倍的差距。

三个私有网段

这三段不会出现在公网上,机房和家里用的都是它们:

10.0.0.0/8          最大,云上和机房最常用
172.16.0.0/12       Docker 默认用 172.17.0.0/16 就在这一段里
192.168.0.0/16      家用路由器最常见

看到这三类地址,就知道它是内网地址,公网访问不到

ARP:同网段还差一步

判断出"同网段、直接发"之后,还有个问题:网卡发包需要目标的 MAC 地址,而你只知道 IP。

ARP 就是干这个的——在网段里吼一声:

主机 A 广播: 谁是 10.0.12.99?请告诉我你的 MAC
主机 B 回答: 10.0.12.99 是我,我的 MAC 是 b8:ce:f6:2a:1c:41

结果会缓存起来,不用每次都问:

# 看 ARP 缓存(邻居表)
ip neigh
10.0.12.1 dev eth0 lladdr 0c:42:a1:5b:2e:80 REACHABLE     ← 网关
10.0.12.99 dev eth0 lladdr b8:ce:f6:2a:1c:41 REACHABLE
10.0.12.77 dev eth0  FAILED                               ← 问了没人应

三个状态值得认识:

状态含义
REACHABLE正常,最近确认过
STALE缓存还在但有点旧了,下次用会重新确认
FAILED问了没有回应 —— 这个 IP 在本网段里不存在,或者它挂了
×ARP 表异常的两个典型故障

1. FAILED 但对方确实活着

说明你们其实不在同一个网段(掩码配错了),或者中间的交换机端口/VLAN 配置有问题。 ARP 是广播,广播到不了对方就永远拿不到 MAC。

2. 同一个 IP 对应的 MAC 变来变去

大概率是IP 冲突——两台机器配了同一个地址,谁最后应答就用谁的。 症状是"时好时坏",非常难查。验证方法:

# 看这个 IP 到底有几个 MAC 在应答
arping -c 5 10.0.12.99

顺便记一个词:gARP(无请求 ARP)——不等别人问,主动广播"这个 IP 现在归我了"。 K8s 里 MetalLB 的 L2 模式就靠它宣告 VIP,主备切换时也靠它让全网更新缓存。 L4 有一节专门讲它。

交换机:按 MAC 转发

交换机的工作简单到有点朴素,就三步:

1. 收到一个包,记下「源 MAC 来自哪个口」        ← 这叫 MAC 学习
2. 查目标 MAC 在自己的表里对应哪个口
3. 查到了 → 只往那个口发;查不到 → 往所有口发(洪泛)

所以交换机的表是自己学出来的,不用配置。这也是它和路由器最大的区别: 交换机只看 MAC、只管同网段;路由器看 IP、负责跨网段。

交换机路由器
看什么MAC 地址IP 地址
管什么同网段内转发网段之间转发
表怎么来自动学习配置或路由协议
广播会转发(同一广播域)不转发

VLAN:把一台交换机切成几台

一台 48 口交换机,如果所有口都在同一个网段,那就是一个大广播域—— 任何一台机器的 ARP 广播全部 48 个口都收得到。机器多了,广播就成了负担; 而且任何两台机器天然互通,没有隔离。

VLAN 解决这个:给每个端口打一个编号,只有同一个编号的端口之间能二层互通

交换机
├─ 端口 1-16   VLAN 10   →  生产网  10.0.10.0/24
├─ 端口 17-32  VLAN 20   →  测试网  10.0.20.0/24
└─ 端口 33-48  VLAN 30   →  管理网  10.0.30.0/24

VLAN 10 里的机器看不到 VLAN 20 的广播,要通只能走三层(经路由器)

两种端口类型:

类型说明用在哪
access只属于一个 VLAN,包里不带标签接服务器
trunk承载多个 VLAN,包里带 802.1Q 标签标明归属交换机之间、接虚拟化宿主机

服务器上要同时接多个 VLAN 时,可以在一张物理网卡上建子接口:

# 在 eth0 上建一个 VLAN 10 的子接口
ip link add link eth0 name eth0.10 type vlan id 10
ip addr add 10.0.10.34/24 dev eth0.10
ip link set eth0.10 up
iVLAN 标签会占 4 字节

802.1Q 标签插在以太网头里,占 4 字节。所以 trunk 链路上如果 MTU 还是 1500, 实际能承载的净荷会少 4 字节。

平时不影响,但在跑 overlay(L1 会讲,还要再减 50 字节)或者 RoCE 时, 这 4 字节要一起算进 MTU 账里。MTU 相关的故障几乎都来自"某处少算了几个字节"。

路由表:本机的决策依据

跨网段的包要交给网关,那"哪个是网关"写在哪?路由表。

ip route
default via 10.0.12.1 dev eth0                      ← 兜底:其它全交给网关
10.0.12.0/24 dev eth0 proto kernel scope link       ← 本网段:直连,不用网关
10.20.0.0/16 via 10.0.12.254 dev eth0               ← 特定网段走另一个下一跳
172.17.0.0/16 dev docker0 proto kernel scope link   ← Docker 建的

读法就三种:

形态含义
X.X.X.X/n dev eth0 scope link直连,同网段,直接发(ARP 拿 MAC)
X.X.X.X/n via A dev eth0去这个网段,交给下一跳 A
default via A兜底,前面都没匹配上就交给 A

匹配规则:前缀最长的优先。 不是从上往下,而是"哪条最具体用哪条":

目标 10.20.5.9
  10.20.0.0/16 via 10.0.12.254   ← 匹配 16 位,更具体,用这条
  default via 10.0.12.1          ← 只匹配 0 位,兜底

最有用的一条命令是让内核直接告诉你结果,不用自己推

ip route get 10.20.5.9
10.20.5.9 via 10.0.12.254 dev eth0 src 10.0.12.34
              ↑ 下一跳            ↑ 出口网卡  ↑ 源地址
ip route get 是排障第一梯队的命令

"这个包会从哪张网卡出去、交给谁"——这个问题不要靠看表推理,直接问内核。

多网卡机器(存储节点、GPU 节点、有 VPN 的机器)上路由表往往几十条, 外加策略路由(ip rule)参与决策,人工推理很容易错。ip route get 给的是内核真实的决策结果。

排查"为什么走错网卡了",第一条命令就是它。

把一次访问连起来

回到上一节那条 curl,现在能把二三层这部分补完整了:

curl https://example.com
   ↓
① DNS 拿到 IP:93.184.216.34
   ↓
② 本机判断:93.184.216.34 不在 10.0.12.0/24 里 → 跨网段
   ↓
③ 查路由表:没有更具体的匹配 → default via 10.0.12.1
   ↓
④ 网关 10.0.12.1 在同网段 → 查 ARP 拿它的 MAC
   ↓
⑤ 包发出去:目的 IP 是 93.184.216.34,目的 MAC 是网关的 MAC
   ↓
⑥ 网关继续往下一跳转发,每跳都换一次 MAC,IP 始终不变

注意第 ⑤ 和 ⑥ 步这个关键区别:

  • IP 地址全程不变(它标识最终目标)
  • MAC 地址每一跳都换(它只标识"这一段路的下一个设备")

这一条理解了,二三层的分工就真的通了。

检查点

检查点单选

本机地址是 10.0.12.34/24,要访问 10.0.13.5。会怎么发?

检查点单选

ip neigh 显示某个同网段 IP 是 FAILED,但你确认那台机器是开着的。最该怀疑什么?

检查点单选

路由表里同时有 10.20.0.0/16 via A 和 default via B。访问 10.20.5.9 走哪条?

这节课的落点

  • 发包只判断一件事:目标在不在本网段。在 → 直接发;不在 → 交给网关
  • 掩码决定网段边界;/24 = 254 台可用,掩码每减 1 地址数翻倍
  • 三个私有网段:10.0.0.0/8172.16.0.0/12192.168.0.0/16
  • ARP 用广播把 IP 换成 MAC;ip neigh 看缓存,FAILED 说明广播到不了对方
  • 同一 IP 的 MAC 变来变去 = IP 冲突,用 arping 验证
  • 交换机看 MAC、表自动学习、转发广播;路由器看 IP、不转发广播
  • VLAN 把一台交换机切成多个广播域;access 接服务器、trunk 带标签;标签占 4 字节
  • 路由表三种形态:直连 scope link、指定下一跳 via、兜底 default最长前缀优先
  • ip route get <目标> 是排"走错网卡"的第一条命令
  • 全程 IP 不变、MAC 每跳都换

延伸资料

  • ·Systems Performance, 2nd Edition — Brendan Gregg