$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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 3: eth0@if771: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1440 qdisc noqueue state UP link/ether 66:fb:34:db:c9:b4 brd ff:ff:ff:ff:ff:ff inet 172.17.8.2/32 scope global eth0 valid_lft forever preferred_lft forever
容器 A 的默认路由
1 2 3
$ ip route default via 169.254.1.1 dev eth0 169.254.1.1 dev eth0 scope link
从路由表可以知道 169.254.1.1 是容器的默认网关,但却找不到任何一张网卡对应这个 IP 地址
当一个数据包的目的地址不是本机时,就会查询路由表,从路由表中查到网关后,它首先会通过 ARP 获得网关的 MAC 地址,然后在发出的网络数据包中将目标 MAC 改为网关的 MAC,而网关的 IP 地址不会出现在任何网络包头中。也就是说,没有人在乎这个 IP 地址究竟是什么,只要能找到对应的 MAC 地址,能响应 ARP 就行了。
可以通过 ip neigh 命令查看一下本地的 ARP 缓存:
1 2
$ ip neigh 169.254.1.1 dev eth0 lladdr ee:ee:ee:ee:ee:ee REACHABLE
上面这张图中,电脑发送 ARP 请求服务器 8.8.8.8 的 MAC 地址,路由器(网关)收到这个请求时会进行判断,由于目标 8.8.8.8 不属于本网段(即跨网段),此时便返回自己的接口 MAC 地址给 PC,后续电脑访问服务器时,目标 MAC 直接封装为 MAC254。
查看宿主机的网卡信息和路由信息:
1 2 3 4 5 6 7 8 9 10 11 12
$ ip addr ... 771: calicba2f87f6bb@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1440 qdisc noqueue state UP group default link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 14 inet6 fe80::ecee:eeff:feee:eeee/64 scope link valid_lft forever preferred_lft forever ...
$ ip route ... 172.17.8.2 dev calicba2f87f6bb scope link ...
$ ip link add veth0 type veth peer name eth0 $ ip netns add ns0 $ ip link set eth0 netns ns0 $ ip netns exec ns0 ip a add 10.20.1.2/24 dev eth0 $ ip netns exec ns0 ip link set eth0 up $ ip netns exec ns0 ip route add 169.254.1.1 dev eth0 scope link $ ip netns exec ns0 ip route add default via 169.254.1.1 dev eth0 $ ip link set veth0 up $ ip route add 10.20.1.2 dev veth0 scope link $ ip route add 10.20.1.3 via 192.168.1.16 dev ens192 $ echo 1 > /proc/sys/net/ipv4/conf/veth0/proxy_arp
在 Host1 上执行以下命令:
1 2 3 4 5 6 7 8 9 10 11
$ ip link add veth0 type veth peer name eth0 $ ip netns add ns1 $ ip link set eth0 netns ns1 $ ip netns exec ns1 ip a add 10.20.1.3/24 dev eth0 $ ip netns exec ns1 ip link set eth0 up $ ip netns exec ns1 ip route add 169.254.1.1 dev eth0 scope link $ ip netns exec ns1 ip route add default via 169.254.1.1 dev eth0 $ ip link set veth0 up $ ip route add 10.20.1.3 dev veth0 scope link $ ip route add 10.20.1.2 via 192.168.1.32 dev ens192 $ echo 1 > /proc/sys/net/ipv4/conf/veth0/proxy_arp
网络连通性测试:
1 2 3 4 5
# Host0 $ ip netns exec ns1 ping 10.20.1.3 PING 10.20.1.3 (10.20.1.3) 56(84) bytes of data. 64 bytes from 10.20.1.3: icmp_seq=1 ttl=62 time=0.303 ms 64 bytes from 10.20.1.3: icmp_seq=2 ttl=62 time=0.334 ms
具体的转发过程如下:
ns0 网络空间的所有数据包都转发到一个虚拟的 IP 地址 169.254.1.1,发送 ARP 请求。