【博客608】源ip是本地网卡ip的流量都发往lo网卡的原因剖析

148 篇文章 16 订阅
130 篇文章 10 订阅

源ip是本地网卡ip的流量都发往lo网卡的原因剖析

场景:本地ip之间通信,流量都会发现lo,不会发往本地ip所在device

example:

ubuntu@10.200.60.4:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 52:54:0a:ea:44:04 brd ff:ff:ff:ff:ff:ff
    inet 10.200.60.4/26 brd 10.234.68.63 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:aff:feea:4404/64 scope link
       valid_lft forever preferred_lft forever
       
ubuntu@10.200.60.4:~$ ping 10.200.60.4
PING 10.200.60.4 (10.200.60.4) 56(84) bytes of data.
64 bytes from 10.200.60.4: icmp_seq=1 ttl=64 time=0.022 ms
64 bytes from 10.200.60.4: icmp_seq=2 ttl=64 time=0.035 ms
64 bytes from 10.200.60.4: icmp_seq=3 ttl=64 time=0.032 ms
^C
--- 10.200.60.4 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2039ms
rtt min/avg/max/mdev = 0.022/0.029/0.035/0.005 ms

ubuntu@10.200.60.4:~$ sudo tcpdump -i lo src host 10.200.60.4 and dst host 10.200.60.4
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
17:31:16.545502 IP 10.200.60.4 > 10.200.60.4: ICMP echo request, id 15, seq 1, length 64
17:31:16.545510 IP 10.200.60.4 > 10.200.60.4: ICMP echo reply, id 15, seq 1, length 64
17:31:17.560711 IP 10.200.60.4 > 10.200.60.4: ICMP echo request, id 15, seq 2, length 64
17:31:17.560720 IP 10.200.60.4 > 10.200.60.4: ICMP echo reply, id 15, seq 2, length 64

前置知识:虚拟网络接口与lo设备

  • 1、linux虚拟网络接口

在linux的网络设备驱动框架里面, 使用一个net_device来代表一个网络设备接口, 因此, 一个物理网卡对应着一个net_device结构。虚拟网络接口是指一个网络接口的net_device没有直接对应的物理设备

  • 2、环回接口lo

环回地址lo是主机用于向自身发送通信的一个特殊地址(也就是一个特殊的目的地址)。
本机和本机Socket通信不走网卡,不走物理设备,但是走虚拟设备,loopback device环回. 本机发给本机的数据,在网络层就可以判别是本机,不需要往外转发。
在Linux服务器抓包的时候,本机间程序的通信监听lo网卡的数据包即可获取相应的数据。
linux上的回环网络接口也是一个虚拟网络接口, 所有通过该设备发送的数据都会被该接口接收返回

  • 3、环回接口的实现

通过注册了一个名为“lo”的net_device,通过lo发送的目的端地址是环回地址,可以省略部分传输层和所有网络层的逻辑操作,但是linux中还是照样完成传输层和网络层的所有过程

在linux的网络协议栈的L2中, 会处理网桥和VLAN, 但是对于127.x.x.x的地址则不会进行这些处理, 因此, 在设置桥接的时候,不要将地址设置为 127.xxx.xxx.xxx网段

在不同的net namespace中, 都有一个独立的“lo”接口

  • 4、localhost/127.0.0.1/本机ip 的差别

根据惯例,大多数系统把IP地址127.0.0.1分配给环回接口, 并且将其命名为locahhost,在访问本机时, 可以使用localhost, 127.0.0.1, 以及本机网卡的ip, 那么, 这3者有何差别呢?

localhost:

一个保留的DNS域名, 会被转换为127.0.0.1, 例如, 在linux上“/etc/hosts”中会定义

127.0.0.1 localhost

127.0.0.1:

事实上 127.0.0.1 ~ 127.255.255.254 都是 loopback 地址

linux上会由系统维护一张 名为“local”的路由表, 并且优先级最高, 其中有

local 127.0.0.0/8 dev lo  proto kernel  scope host  src 127.0.0.1
local 127.0.0.1 dev lo  proto kernel  scope host  src 127.0.0.1

所有目的地址在 127.0.0.0/8 网段的数据包都通过“lo”网络接口收发

本机某一网卡的ip:

kernel的__ip_route_output_key()中, 若认为目标ip是本机ip后, 无论在路由过程中, 选定哪一个网络接口作为出口网络设备, 会强制将出口网络设备设置为 loopback_dev (即“lo”)

目的地址为本机ip的数据包, 都是通过lo口来收发(即使eth0没有接网线)

  • 5、考虑多net namespace情况下lo的差异

namespace是linux上轻量级的虚拟化的容器技术, 用于提供独立的用户空间以及系统资源, 而其中的net name space则用于分离网络资源,一个net namespace有自己独立的路由表,iptables策略, 网络协议栈以及网络接口, 和其它的net namespace完全独立

因此, 若两个网络接口分配不同的ip, 并且加入不同的net namespace, 若从本机中的另一个net namespace中ping另外一个net namespace中的ip, 则数据包不会通过“lo”接口来loopback, 需要使用线缆来连接两个网卡, 因此, 若需要在一台机器上测试网卡的性能, 需要将其加入不同的net namespace

正题:源ip是本地网卡ip的流量都发往lo网卡的原因剖析

lo接口处理流量的性质:

  • Linu支持环回接口( Loopback Interface),以允许运行在同一台主机上的客户程序和服务器程序通TCP/IP进行通信。

  • A 类网络127就是为环回接口预留的 。根据惯例,大多数系统把IP地址127.0.0.1分配给这个接口,并命名为localhost。一个传给环回接口的IP数据报不能在任何网络上出现。
    实际上,访问127.x.x.x的所有IP都是访问环回接口(lo)。

  • 按理来说,一旦传输层检测到目的端地址是环回地址时,应该可以省略部分传输层和所有网络层的逻辑操作。但是大多数的产品还是照样完成传输层和网络层的所有过程,只是当
    IP数据报离开网络层时把它返回给自己。Linux的内核实现就是这样。

核心点:任何传访问127.0.0.1和本机IP(比如192.168.1.10)的数据均送到环回接口lo,由lo设备来完成处理

linux默认路由表:local,main,default

ubuntu@10.200.60.4:~$ ip rule  list
0:        from all lookup local
32766:    from all lookup main
32767:    from all lookup default

linux在进行路由查找时,先查找local,再查找main:

static inline int fib_lookup(const struct flowi *flp, struct fib_result *res)

{

       if (ip_fib_local_table->tb_lookup(ip_fib_local_table, flp, res) &&

           ip_fib_main_table->tb_lookup(ip_fib_main_table, flp, res))

              return -ENETUNREACH;

       return 0;

}

如果内核认为目标地址是本机IP,就会将包的出口设备设置为loopback_dev(不管路由表将出口设备设置成什么)

linux里local路由表里的路由类型为RTN_LOCAL

static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)

{
...
       if (res.type == RTN_LOCAL) {

              if (!fl.fl4_src)

                     fl.fl4_src = fl.fl4_dst;

              if (dev_out)

                     dev_put(dev_out);

              dev_out = &loopback_dev;

              dev_hold(dev_out);

              fl.oif = dev_out->ifindex;

              if (res.fi)

                     fib_info_put(res.fi);

              res.fi = NULL;

              flags |= RTCF_LOCAL;

              goto make_route;
       }

原因总结:

1、linux优先匹配local路由表

2、linux为local路由表里的路由设置的类型为RTN_LOCAL

3、linux在进行路由匹配时,优先使用local表,如果匹配到了为本机流量,
   也就是匹配到了路由类型为RTN_LOCAL,也就是匹配到了local路由表的规则,
   那么就会将包的出口设备设置为loopback_dev(不管路由表将出口设备设置成什么)

查看linux路由表信息

ip route show本质就是ip route show table main,也是ip route,也是route -n

ubuntu@10.200.60.4:~$ ip rule  list
0:        from all lookup local
32766:    from all lookup main
32767:    from all lookup default

ubuntu@10.200.60.4:~$ ip route show table local
broadcast 10.200.60.0 dev eth0 proto kernel scope link src 10.200.60.4
local 10.200.60.4 dev eth0 proto kernel scope host src 10.200.60.4
broadcast 10.234.68.63 dev eth0 proto kernel scope link src 10.200.60.4
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1


ubuntu@10.200.60.4:~$ ip route show
default via 10.200.60.1 dev eth0 proto static
10.200.60.0/26 dev eth0 proto kernel scope link src 10.200.60.4

ubuntu@10.200.60.4:~$ ip route show table main
default via 10.200.60.1 dev eth0 proto static
10.200.60.0/26 dev eth0 proto kernel scope link src 10.200.60.4

ubuntu@10.200.60.4:~$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.200.60.1     0.0.0.0         UG    0      0        0 eth0
10.200.60.0     0.0.0.0         255.255.255.192 U     0      0        0 eth0

ubuntu@10.200.60.4:~$ ip route
default via 10.200.60.1 dev eth0 proto static
10.200.60.0/26 dev eth0 proto kernel scope link src 10.200.60.4
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值