Skip to content

WireGuard:一次完整的排查实录

先说结论

本环境里没能把 WireGuard 跑通。 配置全部被接受、握手报文在链路上流动, 但 peer 的邻接始终为空,数据面以 Peer error 丢包。

这一篇不假装它成功了。它记录的是一次完整的排查过程 —— 用前面章节教的工具(trace、错误计数、feature arc、逐层对照) 一步步缩小范围,最后确定问题边界。

对读者的价值有两层:一是如果你也要在类似环境试 WireGuard, 这里能省掉你重复走一遍;二是这套排查方法本身, 比任何一个"配置成功"的例子都更接近真实工作。

为什么想试 WireGuard

上一篇结尾说了 GRE 的硬伤:明文,无认证。 跑在互联网上必须叠加加密。

传统方案是 IPsec,但配置复杂(IKE 协商、SA、各种算法套件)。 WireGuard 用一套极简的设计做同样的事:

text
  · 只有一种加密套件,没得选,也就没法配错
  · 密钥就是一对公私钥,像 SSH 一样直观
  · "加密路由"(cryptokey routing)—— 每个 peer 声明自己负责哪些网段
  · 跑在 UDP 上,能穿 NAT
  · 代码量比 IPsec 小两个数量级

VPP 26.06 带 wireguard 插件,看起来是个理想的组合。

配置过程

命令族本身很干净:

bash
wireguard create listen-port <port> private-key <key> src <IP> [generate-key]
wireguard peer add <wg_int> public-key <对端公> endpoint <对端IP> \
    allowed-ip <> dst-port <> [persistent-keepalive <>]
show wireguard interface / peer / mode

一、建接口,让 VPP 自己生成密钥

bash
vppctl wireguard create listen-port 51820 src 198.51.100.1 generate-key   # nat1
vppctl wireguard create listen-port 51820 src 198.51.100.2 generate-key   # nat2
vppctl show wireguard interface
text
[0] wg0 src:198.51.100.1 port:51820
    private-key:AJDQGgL3mIU+qCneKWZRwMgRrz9utXQx2lSlm5P0sWM=
    public-key:0SWBMhZ7GcDdM5oZWDkZ9c9fq6MAGUi7DRthQ94i3wg=

公钥私钥都生成了,格式和标准 WireGuard 一致(base64 编码的 32 字节)。

二、互相添加 peer

bash
# nat1 上添加 nat2 作为 peer
vppctl wireguard peer add wg0 \
    public-key fW8DQqZP9KiLBXLVBJnDE/X+W9yNkx6PSfJ5hghLuVM= \
    endpoint 198.51.100.2 allowed-ip 10.2.0.0/24 \
    dst-port 51820 persistent-keepalive 10

allowed-ip 就是加密路由的核心:这个 peer 负责 10.2.0.0/24。 发往这个网段的包用它的公钥加密,从它那儿收到的包也只接受这个网段的源地址。

三、起接口、配地址、指路由

bash
vppctl set interface state wg0 up
vppctl set interface ip address wg0 10.99.2.1/30
vppctl ip route add 10.2.0.0/24 via 10.99.2.2

到这里所有命令都成功了,没有任何报错。

排查过程

但 hA 到 hB 不通,100% 丢包。下面是完整的诊断链条。

第 1 步:看错误计数

bash
vppctl show errors | grep -i wg
text
  4  wg4-output-tun  Peer error  error

Peer error —— 发包时 peer 处于不可用状态。这告诉我们问题在 发送侧的 peer 状态,不是在收包或加密上。

第 2 步:看包走到哪一步

bash
vppctl clear trace && vppctl trace add af-packet-input 6
# ...制造流量...
vppctl show trace
text
  → ip4-input
  → ip4-lookup
  → ip4-load-balance
  → ip4-midchain
    [@1]: dpo-drop ip4          ← 关键
  → wg4-output-tun
  → error-drop
  → drop

ip4-midchain 的转发链解析成了 dpo-drop

对比上一篇 GRE 正常工作时的 trace,那里是:

text
  → ip4-midchain
  → tunnel-output              ← 正常时走这里
  → ip4-rewrite

所以问题很明确:隧道的转发链没有建立起来

第 3 步:看 peer 的详细状态

bash
vppctl show wireguard peer
text
[0] endpoint:[198.51.100.1:51820->198.51.100.2:51820] wg0
    keep-alive:10 flags: 2, api-clients count: 0
  adj:                                    ← 空的
  public key:fW8DQqZP9KiLBXLVBJnDE/X+W9yNkx6PSfJ5hghLuVM=
  allowed-ips: 10.2.0.0/24

adj: 是空的。 邻接没有被填充,这正好解释了上一步的 dpo-drop

第 4 步:握手包到底有没有在走

怀疑是握手没完成。在对端抓包:

bash
# 在 nat2 上
vppctl clear trace && vppctl trace add af-packet-input 10
text
  收到 nat1 的 UDP 包数: 9
  UDP: 198.51.100.1 -> 198.51.100.2
00:05:59:937378: wg4-input          ← WireGuard 的输入节点确实处理了

握手报文在流动,而且被 wg4-input 节点正常接收了。 所以不是网络不通,也不是端口没监听。

第 5 步:排除周边因素

逐个排除:

text
  ARP 解析      show ip neighbors 里 198.51.100.2 已解析     ✓ 不是这个
  路由写法      改成 ip route add ... via wg0(接口路由)      ✗ 仍然 dpo-drop
  加密引擎      show crypto engines 有 4 个可用引擎           ✓ 不是这个
  异步模式      set wireguard async mode on                  ✗ 无变化
  allowed-ip    放宽到 0.0.0.0/0                             ✗ 无变化

五种尝试之后,adj: 依然是空的。

结论

问题定位在:peer 的邻接从未被填充。握手报文能收发, 但 peer 没有进入可用状态,导致隧道的转发链解析为丢弃。

这是环境问题还是版本问题?

我无法从这里判断。可能的因素包括:

  • VPP 26.06 的 wireguard 实现在这个配置下的问题
  • 容器 + AF_PACKET 环境下的某种交互
  • 某个我没找到的必需配置步骤

诚实的说法是:在本教程的实验环境里,用 CLI 配置的 WireGuard 没能建立数据面。 不能据此断言"VPP 的 WireGuard 不能用"。

这次排查用到的方法

回头看,整个过程就是第 7 章那套流程的应用:

text
  1. show errors           →  Peer error,锁定在发送侧的 peer 状态
  2. show trace            →  dpo-drop 出现在 ip4-midchain
  3. 和正常案例对照         →  GRE 的 trace 里是 tunnel-output,差异明确
  4. show wireguard peer   →  adj 为空,和第 2 步的现象对上了
  5. 对端抓包              →  握手包在走,排除网络层问题
  6. 逐个排除周边因素        →  ARP / 路由写法 / 加密引擎 / 异步模式 / allowed-ip

第 3 步"和正常案例对照"是效率最高的一步。 因为 GRE 已经跑通了, 两份 trace 一比,差异立刻收敛到 midchain 那一跳 —— 不然光看 dpo-drop 很难知道它本该是什么。

这也是为什么本教程坚持"每个特性都跑通一个可对照的正常案例"。

什么时候该停

排查到第 5 步时,已经能确定:不是网络问题、不是配置语法问题、 不是加密引擎问题。剩下的可能性需要读 VPP 源码或者查上游 issue, 超出了"配置和运维"的范畴。

在工程上,能把问题边界划清楚就已经完成了大部分价值 —— 知道"不是我的配置错了"和知道"具体是哪一行代码的 bug", 对决策的意义是一样的:换方案,或者去上游提 issue。

那加密隧道怎么办

如果需要在公网上跑加密隧道,VPP 26.06 里的现实选择:

text
  ✓ IPsec / IKEv2      插件齐全,是 VPP 上最成熟的加密隧道方案
                       代价是配置复杂度高得多

  ✓ GRE over IPsec     先 GRE 打通,再用 IPsec 保护外层
                       路由灵活性和加密兼得,是传统企业组网的常见做法

  ? WireGuard          本环境未能跑通(本篇)

本教程没有覆盖 IPsec —— 它值得单独一章,而且需要更细致的 算法套件、SA 生命周期、NAT 穿越等内容。

小结

想解决GRE 的明文问题,用比 IPsec 简单的方式做加密隧道
配置wireguard create + wireguard peer add + 路由,命令很干净
实测结果未能跑通:配置成功、握手包在流动,但 peer adj: 为空
故障签名wg4-output-tun: Peer error + trace 里 ip4-midchaindpo-drop
排除过的ARP、路由写法、加密引擎、异步模式、allowed-ip 范围
最有效的诊断手段和跑通的 GRE 做 trace 对照,差异立刻收敛到 midchain
替代方案IPsec / IKEv2,或 GRE over IPsec

第 10 章到此结束:

text
  GRE         打通两个私网,简单可靠,但明文
  MTU 与 MSS  隧道最高频的故障来源,clamping 是标准解法
  WireGuard   一次完整排查实录 —— 以及知道何时该停

实验环境基于 netlab + containerlab + VPP 26.06