问题概述

Linux 提供了 namespace 机制来实现系统资源的隔离,network namespace 提供了对网络资源的隔离。

如图所示:

截屏2023-12-09 上午2.33.24.png

我们希望把 netns1 和现有 VXLAN (10.0.1.0/24) 打通,一般情况下,netns1 的 veth 发出的 ARP 请求会到达位于 main netns 的另一端的 veth,然后如果 main netns 中有对应的 IP 就会回应 ARP 查询请求,否则就没有回应,例如 10.0.1.102 位于另一个 VTEP,如果 netns1 往外发出针对 10.0.1.102 的 ARP 查询请求 (who is 10.0.1.102, tell 10.0.1.103) 那么肯定收不到回复,这也就导致 netns1 ping 不通 10.0.1.102。而且,假如 10.0.1.102 发出一个 ARP 查询请求询问 10.0.1.103 的 MAC 地址,则这个 ARP 查询请求最多只会到达 server1 的 main netns, 到不了 10.0.1.103,因此 10.0.1.102 也无法主动向 10.0.1.103 发送数据。

要解决这个问题,我们学习 calico 的做法:

  1. 在 main netns 配置精确匹配的路由转发:Destination 10.0.1.103/32, NextHop netns1 在 main netns 的 veth;这样,server2 的 VTEP 就可以收到来自 netns1 的 ARP 查询请求;
  2. 启动 VTEP 的 ARP proxy 功能,假设是 “who is 10.0.1.102, tell 10.0.1.103”,netns1 发出的 ARP 查询请求会到达 server1 的 main netns,由于 ARP 查询请求是广播帧,所以 server1 的 main netns 的 VTEP 也会收到,默认情况下由于它不绑定 10.0.1.102,所以它简单地丢弃这个 ARP 查询请求广播帧,但是在开启了 ARP proxy 的情况下,它会把这个 ARP 查询请求转发给其它所有的 VTEP,假如说它的转发表里面没有对应的记录的话。

在 Linux,VXLAN 虚拟网卡的 ARP proxy 功能可以在它创建时设定,也可以在创建后设定,默认为关闭,需要我们显式地启用它。

试验过程

我们首先启动两个虚拟机,它们位于同一个网段:

$ multipass launch --name vm1
$ multipass launch --name vm2

创建 VXLAN 虚拟网卡:

# 在 vm1 执行
$ sudo ip link add vxlan1 type vxlan id 101 remote 192.168.64.36
$ sudo ip link set vxlan1 up
$ sudo ip link set lo up
$ sudo ip addr add 10.0.1.101/24 dev vxlan1
$ sudo sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=0

# 载 vm2 执行
$ sudo ip link add vxlan1 type vxlan id 101 remote 192.168.64.35
$ sudo ip link set vxlan1 up
$ sudo ip link set lo up
$ sudo ip addr add 10.0.1.102/24 dev vxlan1
$ sudo sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=0

具体 VM 的 IP 地址可以通过 multipass list 命令查看。

在任意一台 vm 执行:

$ ping -I vxlan1 224.0.0.1

PING 224.0.0.1 (224.0.0.1) from 10.0.1.102 vxlan1: 56(84) bytes of data.
64 bytes from 10.0.1.102: icmp_seq=1 ttl=64 time=0.090 ms
64 bytes from 10.0.1.101: icmp_seq=1 ttl=64 time=1.03 ms
64 bytes from 10.0.1.102: icmp_seq=2 ttl=64 time=0.090 ms
64 bytes from 10.0.1.101: icmp_seq=2 ttl=64 time=1.74 ms
^C
--- 224.0.0.1 ping statistics ---
2 packets transmitted, 2 received, +2 duplicates, 0% packet loss, time 1073ms
rtt min/avg/max/mdev = 0.090/0.736/1.740/0.694 ms

会看到 VXLAN 网络本身已经通了。

加下来我们在 vm1 上建立一个 netns,以复现文章开头提到的那种情况:

$ sudo ip netns add ns1
$ sudo ip -n ns1 link set lo up
$ sudo ip link add veth1 netns ns1 type veth peer ns1-veth1-peer
$ sudo ip -n ns1 link set veth1 up
$ sudo ip link set ns1-veth1-peer up
$ sudo ip -n ns1 addr add 10.0.1.103/24 dev veth1