小实验
接上篇文章 ping本机网口的IP地址,tcpdump在lo口才能抓到对应报文,我们知道在网口eth1上增加一个IP地址192.168.8.8/24后,内核会生成3条路由:
- local表:增加192.168.8.8/32的主机路由(
RTN_LOCAL) - main表:增加192.168.8.8/24的网段路由(
RTN_UNICAST) - local表:增加广播路由
其中主机路由类型是RTN_LOCAL,网段路由类型是RTN_UNICAST。
那如果把IP地址配到lo口上,会有什么不同呢?
实验题目
- ping 本机 lo 口的IP地址 127.0.0.1 能ping通吗?
- ping 127.0.0.0/8 网段下的其他地址能ping通吗?
- 把一个任意IP地址配置到 lo 口上,又会有什么实验结果呢?
实验结果
case1:ping 127.0.0.1 OK
这个很自然,lo口默认有127.0.0.1地址,ping自己当然能通。

case2: ping 127.x.x.x 网段其他地址 OK
这个就有趣了。127.0.0.2、127.1.2.3 等 127.0.0.0/8 网段下的任意地址都能 ping 通!

case3: lo 口上配置任意IP地址
在lo口上配一个新的IP地址(比如192.168.8.0/24网段),结果发现不仅这个IP本身能ping通,整个网段的所有地址都能ping通!

实验结论: lo口点石成金
通过上面的实验,我们发现只要是一个 IP 地址被配置到 lo 口上,
不仅原来的 ip 地址本身能 ping 通,这个IP地址整个网段都是可以ping通的。
原因在哪里?
原理分析
回顾上篇文章中 fib_add_ifaddr 函数里添加网段路由的代码:
1 | 1167 if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) && |
关键就在第 1171 行:
1 | dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST |
对于普通网口(如eth1),网段路由的类型是 RTN_UNICAST,被添加到 main 路由表里。
查找到这类路由时,报文会从对应物理口发出去。
对于lo口,网段路由的类型变成了 RTN_LOCAL,被添加到 local 路由表里。
查找到这类路由时,报文走lo口重新回到本机协议栈。
这就是lo口”点石成金”的秘密:
| 网口 | 主机路由(/32) | 网段路由(/prefix) |
|---|---|---|
| eth1 | RTN_LOCAL → local表 |
RTN_UNICAST → main表 |
| lo | RTN_LOCAL → local表 |
RTN_LOCAL → local表 |
由于 local 路由表的查找优先级高于 main 表,所以配在 lo 口上的IP地址,其整个网段的流量都会被路由到本机,而不是发往网络。
典型应用场景
理解了lo口的这个特性,就能理解它在实际中的几个典型应用:
VIP(虚拟IP)地址:LVS/keepalived等负载均衡场景中,Real Server把VIP配置在lo口上,就是利用了lo口会把VIP的网段路由设为
RTN_LOCAL,使得目的地为VIP的报文能被本机协议栈接收处理。容器网络:在某些容器网络方案中,把Service IP或Cluster IP配在lo口上,使得Pod能够直接处理目标为这些IP的流量。
路由黑洞/汇总:把一个大网段配在lo口上,可以实现类似路由黑洞的效果,阻止该网段的流量发往外部网络。
小结
lo口的”点石成金”能力,本质上是内核在 fib_add_ifaddr 函数中对 loopback 设备做了特殊处理:
- 普通网口的网段路由类型为
RTN_UNICAST,存放在 main 表 - lo 口的网段路由类型为
RTN_LOCAL,存放在 local 表 - local 表优先级高于 main 表,因此整个网段的流量都被路由到本机
一行代码之差 dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,造就了lo口独特的网络行为。