lo口与local路由表

小实验

接上篇文章 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口上,会有什么不同呢?

实验题目

  1. ping 本机 lo 口的IP地址 127.0.0.1 能ping通吗?
  2. ping 127.0.0.0/8 网段下的其他地址能ping通吗?
  3. 把一个任意IP地址配置到 lo 口上,又会有什么实验结果呢?

实验结果

case1:ping 127.0.0.1 OK

这个很自然,lo口默认有127.0.0.1地址,ping自己当然能通。

ping lo口IP地址

case2: ping 127.x.x.x 网段其他地址 OK

这个就有趣了。127.0.0.2、127.1.2.3 等 127.0.0.0/8 网段下的任意地址都能 ping 通!

ping 127网段其他地址

case3: lo 口上配置任意IP地址

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

lo口配置IP后整个网段都通

实验结论: lo口点石成金

通过上面的实验,我们发现只要是一个 IP 地址被配置到 lo 口上,
不仅原来的 ip 地址本身能 ping 通,这个IP地址整个网段都是可以ping通的
原因在哪里?

原理分析

回顾上篇文章中 fib_add_ifaddr 函数里添加网段路由的代码:

1
2
3
4
5
6
7
1167         if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) &&
1168 (prefix != addr || ifa->ifa_prefixlen < 32)) {
1169 if (!(ifa->ifa_flags & IFA_F_NOPREFIXROUTE))
1170 fib_magic(RTM_NEWROUTE,
1171 dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
1172 prefix, ifa->ifa_prefixlen, prim,
1173 ifa->ifa_rt_priority);

关键就在第 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口的这个特性,就能理解它在实际中的几个典型应用:

  1. VIP(虚拟IP)地址:LVS/keepalived等负载均衡场景中,Real Server把VIP配置在lo口上,就是利用了lo口会把VIP的网段路由设为RTN_LOCAL,使得目的地为VIP的报文能被本机协议栈接收处理。

  2. 容器网络:在某些容器网络方案中,把Service IP或Cluster IP配在lo口上,使得Pod能够直接处理目标为这些IP的流量。

  3. 路由黑洞/汇总:把一个大网段配在lo口上,可以实现类似路由黑洞的效果,阻止该网段的流量发往外部网络。

小结

lo口的”点石成金”能力,本质上是内核在 fib_add_ifaddr 函数中对 loopback 设备做了特殊处理:

  • 普通网口的网段路由类型为 RTN_UNICAST,存放在 main 表
  • lo 口的网段路由类型为 RTN_LOCAL,存放在 local 表
  • local 表优先级高于 main 表,因此整个网段的流量都被路由到本机

一行代码之差 dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,造就了lo口独特的网络行为。