0

我正在尝试了解 linux 内核中的 vxlan 驱动程序代码。内核版本为:3.16.0-29-generic

看起来vxlan.c似乎每个 VNI 创建了一个 vxlan dev,它与 netdevice 所属的 netns 相关联,并且每个 dev 创建了一个 udp 套接字。

我对此有点困惑,因为除了全局 netns 之外,您不能真正将 vxlan 设备附加到物理设备 ( ethx),因为物理设备必须与 vxlan 设备属于相同的 netns。

例如:如果我在全局 netns 中创建一个 vxlan 链接,它会按预期工作:

ip link add vxlan0 type vxlan id 10 dev eth0
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
    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
    inet 10.10.100.51/24 scope global 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 pfifo_fast state UP group default qlen 1000
    link/ether 00:22:4d:99:32:6b brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.25/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::222:4dff:fe99:326b/64 scope link 
       valid_lft forever preferred_lft forever
15: vxlan0: <BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN group default 
    link/ether fe:9c:49:26:ba:63 brd ff:ff:ff:ff:ff:ff

如果我尝试在网络命名空间中做同样的事情,它将不起作用:

ip netns exec test0 ip link add vxlan1 type vxlan id 20 dev eth0
ip netns exec test0 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

这里的问题是它不喜欢“dev eth0”,因为代码会检查 eth0 是否与正在添加的链接在同一个 netns 中。

如果我在没有 eth0 的情况下创建相同的设备,它可以正常工作:

ip netns exec test0 ip link add vxlan1 type vxlan id 20 
ip netns exec test0 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: vxlan1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default 
    link/ether 46:7a:5b:87:7d:2f brd ff:ff:ff:ff:ff:ff

如果您无法将运营商连接到 vxlan 设备,您如何才能真正向/从主机外部发送/接收数据包?

这是否意味着实际上您只能将 vxlan 驱动程序与全局 netns 一起使用,或者您“必须”将其与网桥一起使用?

vxlan 数据包有一个与之关联的 VNI。您应该能够使用它直接将数据包发送到非全局 netns 中的开发人员,这与 macvlans 的实际情况类似。

我错过了什么吗?

4

3 回答 3

1

我想你可以看看Thomas Richter 的 Software Defined Networking using VXLAN(在 LinuxCon 2013 上介绍)

您可以打开l2miss和关闭不在全局 netnsl3miss中的设备,并手动设置 ARP 和 FDB 条目。vxlan

以下示例显示了如何实现此目的。

function setup_overlay() {
    docker run -d --net=none --name=test-overlay ubuntu sleep 321339
    sleep 3
    pid=`docker inspect -f '{{.State.Pid}}' test-overlay`
    ip netns add overlay
    ip netns exec overlay ip li ad dev br0 type bridge
    ip li add dev vxlan212 type vxlan id 42 l2miss l3miss proxy learning dstport 4789
    ip link set vxlan212 netns overlay
    ip netns exec overlay ip li set dev vxlan212 name vxlan1
    ip netns exec overlay brctl addif br0 vxlan1
    ip li add dev vetha1 mtu 1450 type veth peer name vetha2 mtu 1450
    ip li set dev vetha1 netns overlay
    ip netns exec overlay ip -d li set dev vetha1 name veth2
    ip netns exec overlay brctl addif br0 veth2
    ip netns exec overlay ip ad add dev br0 $bridge_gatway_cidr
    ip netns exec overlay ip li set vxlan1 up
    ip netns exec overlay ip li set veth2 up
    ip netns exec overlay ip li set br0 up
    ln -sfn /proc/$pid/ns/net /var/run/netns/$pid
    ip li set dev vetha2 netns $pid
    ip netns exec $pid ip li set dev vetha2 name eth1 address $container1_mac_addr
    ip netns exec $pid ip ad add dev eth1 $container1_ip_cidr
    ip netns exec $pid ip li set dev eth1 up

    ip netns exec overlay ip neighbor add $container2_ip lladdr $container2_mac_addr dev vxlan1 nud permanent
    ip netns exec overlay bridge fdb add $container2_mac_addr dev vxlan1 self dst $container2_host_ip vni 42 port 4789
}

# setup overlay on host1
bridge_gatway_cidr='10.0.0.1/24'
container1_ip_cidr='10.0.0.2/24'
container1_mac_addr='02:42:0a:00:00:02'
container2_ip='10.0.0.3'
container2_mac_addr='02:42:0a:00:00:03'
container2_host_ip='192.168.10.22'
setup_overlay

# setup overlay on host2
bridge_gatway_cidr='10.0.0.1/24'
container1_ip_cidr='10.0.0.3/24'
container1_mac_addr='02:42:0a:00:00:03'
container2_ip='10.0.0.2'
container2_mac_addr='02:42:0a:00:00:02'
container2_host_ip='192.168.10.21'
setup_overlay

上面的脚本在两个主机上的两个 docker 容器之间建立了一个覆盖网络。vxlan 设备连接到 netns 中的网桥br0overlaybr0通过一对 veth 设备连接到容器 netns。

现在检查您新设置的覆盖网络。

# ping container2 on host1
ip netns exec $pid ping -c 10 10.0.0.3
## successful output
root@docker-1:/home/vagrant# ip netns exec $pid ping -c 10 10.0.0.3
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
64 bytes from 10.0.0.3: icmp_seq=1 ttl=64 time=0.879 ms
64 bytes from 10.0.0.3: icmp_seq=2 ttl=64 time=0.558 ms
64 bytes from 10.0.0.3: icmp_seq=3 ttl=64 time=0.576 ms
64 bytes from 10.0.0.3: icmp_seq=4 ttl=64 time=0.614 ms
64 bytes from 10.0.0.3: icmp_seq=5 ttl=64 time=0.521 ms
64 bytes from 10.0.0.3: icmp_seq=6 ttl=64 time=0.389 ms
64 bytes from 10.0.0.3: icmp_seq=7 ttl=64 time=0.551 ms
64 bytes from 10.0.0.3: icmp_seq=8 ttl=64 time=0.565 ms
64 bytes from 10.0.0.3: icmp_seq=9 ttl=64 time=0.488 ms
64 bytes from 10.0.0.3: icmp_seq=10 ttl=64 time=0.531 ms

--- 10.0.0.3 ping statistics ---
10 packets transmitted, 10 received, 0% packet loss, time 9008ms
rtt min/avg/max/mdev = 0.389/0.567/0.879/0.119 ms

## tcpdump sample on host1
root@docker-1:/home/vagrant# tcpdump -vv -n -s 0 -e -i eth1
tcpdump: listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
12:09:35.589244 08:00:27:00:4a:3a > 08:00:27:82:e5:ca, ethertype IPv4 (0x0800), length 148: (tos 0x0, ttl 64, id 59751, offset 0, flags [none], proto UDP (17), length 134)
    192.168.0.11.42791 > 192.168.0.12.4789: [no cksum] VXLAN, flags [I] (0x08), vni 42
02:42:0a:00:00:02 > 02:42:0a:00:00:03, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 49924, offset 0, flags [DF], proto ICMP (1), length 84)
    10.0.0.2 > 10.0.0.3: ICMP echo request, id 1908, seq 129, length 64
12:09:35.589559 08:00:27:82:e5:ca > 08:00:27:00:4a:3a, ethertype IPv4 (0x0800), length 148: (tos 0x0, ttl 64, id 38389, offset 0, flags [none], proto UDP (17), length 134)
    192.168.0.12.56727 > 192.168.0.11.4789: [no cksum] VXLAN, flags [I] (0x08), vni 42
02:42:0a:00:00:03 > 02:42:0a:00:00:02, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 19444, offset 0, flags [none], proto ICMP (1), length 84)
    10.0.0.3 > 10.0.0.2: ICMP echo reply, id 1908, seq 129, length 64
12:09:36.590840 08:00:27:00:4a:3a > 08:00:27:82:e5:ca, ethertype IPv4 (0x0800), length 148: (tos 0x0, ttl 64, id 59879, offset 0, flags [none], proto UDP (17), length 134)
    192.168.0.11.42791 > 192.168.0.12.4789: [no cksum] VXLAN, flags [I] (0x08), vni 42
02:42:0a:00:00:02 > 02:42:0a:00:00:03, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 49951, offset 0, flags [DF], proto ICMP (1), length 84)
    10.0.0.2 > 10.0.0.3: ICMP echo request, id 1908, seq 130, length 64
12:09:36.591328 08:00:27:82:e5:ca > 08:00:27:00:4a:3a, ethertype IPv4 (0x0800), length 148: (tos 0x0, ttl 64, id 38437, offset 0, flags [none], proto UDP (17), length 134)
    192.168.0.12.56727 > 192.168.0.11.4789: [no cksum] VXLAN, flags [I] (0x08), vni 42
02:42:0a:00:00:03 > 02:42:0a:00:00:02, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 19687, offset 0, flags [none], proto ICMP (1), length 84)
    10.0.0.3 > 10.0.0.2: ICMP echo reply, id 1908, seq 130, length 64

清理每台主机

ip netns del overlay
ip netns del $pid
docker rm -v -f test-overlay

解释为什么 vxlan 设备在非全局 netns 中没有接收器的情况下工作:

请注意,我们首先在全局 netns 中创建 vxlan 设备并将其移动到overlaynetns 中。这确实是需要的,因为内核中的 vxlan 驱动程序将在创建 vxlan 设备时保留对 src netns 的引用。请参阅以下代码drivers/net/vxlan.c

static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
     
        struct vxlan_config *conf)
     {
    //...
    vxlan->net = src_net;
    
    //...
}

并且 vxlan 驱动程序在 src netns 中创建 udp 套接字

vxlan_sock_add(vxlan->net, vxlan->cfg.dst_port, vxlan->cfg.no_share, vxlan->flags);

于 2015-11-06T06:55:48.487 回答
0

事实证明,您可以将物理设备添加到非全局 netns。因此,这个问题没有实际意义。我宁愿看到全局 netns 中的一个 vxlan 设备基于 VNI 将数据包发送到适当的 netns,类似于在 macvlans 的情况下如何实现这一点。

于 2015-02-05T09:16:05.700 回答
0

在内核 4.3 中,有一些补丁添加了一种使用 VXLAN 的新方法,使用单个 VXLAN netdev 并使用路由规则来添加隧道信息。

根据补丁,您将能够创建查看隧道信息的路由规则,例如:

ip rule add from all tunnel-id 100 lookup 100
ip rule add from all tunnel-id 200 lookup 200

并添加具有以下规则的封装标头:

ip route add 40.1.1.1/32 encap vxlan id 10 dst 50.1.1.2 dev vxlan0
于 2015-10-21T12:12:14.183 回答