216 条网络命令(一):地址、路由、连接、隧道
这是《216 条网络命令》系列第一篇,共四篇。清单来自一本 15 万字的网络排障书,去掉重复、按工具族分类,每条给一句「什么时候用它」和一个「最容易被误读的地方」。
这是《216 条网络命令》系列第一篇,共四篇。清单来自一本 15 万字的网络排障书,每条给一句「什么时候用它」和一个「最容易被误读的地方」。
先说三条纪律,否则清单会害了你
一、先写预期,再执行。 每条命令执行前,先在脑子里写一句「如果正常,我会看到什么」。看到的东西与预期不符,这一步就给出了方向;相符,才进下一步。没有预期就敲命令,等于在大海里舀水。
二、计数看增量,不看绝对值。 dropped 27 这六个字符本身没有意义——要看它 30 秒后还是不是 27。绝对值只会让你盯着一个历史遗留数字发呆。
三、带数字的判据必须带前提。 ping -M do -s 1392 只在 wg0 MTU = 1420 时成立;换一套 MTU 就得重算。任何不写前提的数字,等于什么都没说——这是这份清单里反复出现的规矩。
一、地址与邻居(8 条)
ip -4 addr show [dev eth0]
看内核实际生效的地址与掩码,不是配置文件里写了什么。
坑:出现 169.254.x.x 说明 DHCP 失败,很多人把它当成「网络通了」。
坑:只看有没有地址,不看前缀长度——/24 和 /32 决定它能不能直连网关。
ip -6 addr show scope global
scope global 过滤掉 fe80:: 链路本地,只看能路由的地址。
坑:有 global 地址 ≠ 有 v6 出口。必须再查 ip -6 route get。
坑:RA 可能在你没配过的情况下自动给地址,valid_lft 会随前缀变化。
ip neigh show [dev eth0]
ARP(v4)/ NDP(v6)邻居表。
关键:STALE 是正常老化态,不是故障;FAILED 才是解析失败。
判据:同网段不通,先看这里,不要先怀疑路由。
状态流转:INCOMPLETE → REACHABLE(约 30 秒不验证)→ STALE(过期但不查)→ 下次发包进 DELAY(5 秒窗口)→ 无人确认才 PROBE(真发 ARP)。FAILED 是解析失败。
为什么要有 DELAY 这 5 秒? 内核在说:「我先信你,但你得在 5 秒内证明一下。」TCP 用 ACK 完成了证明,UDP 没有这个能力,只能让内核亲自发 ARP 去问。
实测对照(veth 双 netns,强制置 STALE 后各发 8 秒流量):
| 协议 | 起始 | 过程中 | 抓到的 ARP 包 |
|---|---|---|---|
| TCP 长连接 | STALE | DELAY → REACHABLE | 0 个 |
| UDP 持续发送 | STALE | DELAY → PROBE | 2 个 |
所以看到一个 UDP 业务每隔几十秒发一次 ARP,这不是故障,是无连接语义在链路层的物理代价。
ip -s neigh
邻居解析的统计。配合容量参数看:
sysctl net.ipv4.neigh.default.gc_thresh3 # 硬上限,默认 1024
撞上限之后内核直接丢弃新的 ARP 学习请求,直到 GC 清到 gc_thresh2 之下。现场证据在 dmesg 里:
neighbour: arp_cache: neighbor table overflow!
看到这一行,「Pod 间偶发 No route to host、重试又好了」就有解释了:表没满时是 FAILED(问了没人应),表满了连问都问不出去。
arping -c 3 -A -I eth0 192.168.1.100
发免费 ARP,刷新上游交换机的 MAC 表。判据:VIP 切换成功但业务断五分钟,就是交换机 MAC 表 300 秒老化窗口。
ip -d link show type bridge / bridge link show
看 veth 拓扑与 bridge 端口状态。坑:veth 成对,netns 删了宿主侧会留孤儿。
二、路由与选路(14 条)
ip route get <目的IP> —— 整份清单里最重要的命令
直接打印内核的路由决策结论:为这个目的,选了哪个 dev、哪个 src。
ip route get 10.0.0.5
ip route get 10.0.0.5 from 10.0.0.1 # 测源地址路由
ip route get 10.0.0.5 mark 0x64 # 测策略路由
回归正题:这是「内核会怎么选」,不是「配置文件想让它怎么选」。
坑:用 ip route show 代替它。路由表里有十条,但内核只选一条,选哪条才是问题。
判据:流量不走隧道、metric 莫名其妙、被 /32 抢占——这些都先看这一条。
ip route show [table all]
列出路由条目,用来解释上一条为什么得出那个结论。
关键:只查 main 表会漏掉 ip rule 引到别的表的流量。
坑:metric 只在同前缀长度时比较。前缀比直连短,metric 根本没参与比较。
ip rule show
策略路由规则,按优先级数字从小到大匹配,先命中先走。
判据:「路由表里有却不走」——一半以上是包被 ip rule 引到另一张表了。
ip rule add from 203.0.113.9/32 lookup 100
ip route add default via 203.0.113.1 dev eth1 table 100
源地址匹配的流量进 100 号表。这是多出口选路的标准做法。
ip route add / replace / del
ip route add 10.0.0.0/24 dev wg0 metric 50
ip route replace default via 10.0.0.1 dev eth0 metric 100 # 原子替换
ip route del 10.0.0.0/24 dev wg0
坑:网关必须在直连网段内,否则内核直接拒绝(Network is unreachable)。
坑:排障时临时加的路由,改完必须清——忘了清就是下一个故障。
关键:replace 是原子的,但 ARP 不是。切换瞬间新网关 MAC 还没学到,会丢几个包。
缓解办法:切换前先 ping 一下新网关,把 ARP 提前建立。
ip -6 route get <v6 目的>
坑:ip -6 addr 有地址就以为 v6 可用。v4/v6 的路由是两个独立世界。
三、socket 与连接(13 条)
ss -tulnp
所有监听端口、绑定地址、归属进程。暴露面审计第一步。
坑:宿主看不到监听 ≠ 服务没起,可能在另一个 netns。用 nsenter 进去看。
坑:管理服务绑 0.0.0.0 被当成「方便」,实际是暴露面。
ss -tan state close-wait|time-wait|syn-recv
ss -tan state close-wait | wc -l # 应用没 close() 的连接数
ss -tan state syn-recv | wc -l # 半连接队列积压
ss -tan state time-wait | wc -l
这四行能分开「网络问题」和「程序问题」:
CLOSE-WAIT 堆积 → 应用代码没调 close(),调内核参数完全无效
SYN-RECV 堆积 → 半连接队列满了,或者 SYN 被丢在回程
TIME-WAIT 多 → 主动关闭方才有,正常;调 tcp_fin_timeout 没用
ss -lnt
LISTEN 状态下 Recv-Q / Send-Q 含义被改写,这是最常被误读的一条:
LISTEN 时:
Recv-Q = 已完成三次握手、但应用还没 accept() 的连接数
Send-Q = 队列上限(不是已发送字节)
判据:Recv-Q 接近 Send-Q → 服务进程活着但 accept 不过来,
表现为「服务活着但建连超时」。这类故障 ping 和 curl -I 都测不出来。
ss -ti [dport = :443]
单条连接的 rtt / retrans / cwnd / snd_wnd。
ss -ti 'dport = :443' | grep -o 'retrans:[0-9]*'
关键:cwnd 和 snd_wnd 取小才是实际窗口。
坑:只盯 cwnd 会漏掉「接收方读得慢」;只盯 retrans 会漏掉「窗口不足」。
ss -s
坑:输出里没有 "ports" 字样。ss -s | grep ports 永远是空的。
端口用量要看 ip_local_port_range + established 计数。
四、隧道(WireGuard)
wg show [wg0]
wg show wg0
wg show wg0 latest-handshakes
wg show wg0 transfer
wg show wg0 allowed-ips
关键:重握手约每 120 秒一次,30 秒内时间戳不变是正常的。阈值 < 180 秒(留 50% 余量)。
坑:有握手 ≠ 包进了隧道,要看 AllowedIPs。
坑:transfer 是累加值,判吞吐要用两次采样的增量。
wg set / wg syncconf
wg set wg0 peer <公钥> allowed-ips 10.0.0.0/24
wg set wg0 peer <公钥> persistent-keepalive 25
wg syncconf wg0 <(wg-quick strip wg0)
AllowedIPs 是覆盖语义不是追加,而且它同时管两件事:发送时选路、接收时准入。
坑:只改一侧 → 一半通(能发不能收)。
坑:syncconf 与 setconf 都会删掉文件里没有的 peer,但前者不重置未变 peer。
坑:少了 wg-quick strip,wg 会报不认识的键。
persistent-keepalive 25 对抗的是路径上 NAT 的 UDP 映射老化(常见 30–300 秒),不是本机 conntrack 的 30 秒。 因果一错,调优方向全错。
下一篇:(二)防火墙、conntrack、抓包、MTU