无法通过虚拟 Tap 接口将 vm 连接到 IPv6 互联网

uMd*_*ert 5 kvm ipv6 tap virtual-interface amazon-linux

我无法通过主机上的虚拟 Tap 设备虚拟机连接到 IPv6 互联网。即,我无法 ping ipv6.google.com 或公共 IPv6 主机全局主接口地址。前任:

-bash-4.2$ ping6 ipv6.google.com
    PING ipv6.google.com(sea15s11-in-x0e.1e100.net) 56 data bytes
    From 2600:1f14:680:xxxx:66a3:79d5:6c1d:14c icmp_seq=1 Destination unreachable: Address unreachable
    From 2600:1f14:680:xxxx:66a3:79d5:6c1d:14c icmp_seq=2 Destination unreachable: Address unreachable
    From 2600:1f14:680:xxxx:66a3:79d5:6c1d:14c icmp_seq=3 Destination unreachable: Address unreachable
    ^C
    --- ipv6.google.com ping statistics ---
    4 packets transmitted, 0

 received, +3 errors, 100% packet loss, time 3082ms
Run Code Online (Sandbox Code Playgroud)

或者到主机的全局 ipv6 地址,我得到同样的错误。

简单拓扑:

   router -----(eth0)----- host ----(tap device)---- vm
Run Code Online (Sandbox Code Playgroud)

主机上的邻居发现似乎存在一些问题,当我从主机的 tap 端点对 tap 接口进行 tcpdump 时,我收到了请求消息,但没有返回任何内容:

[user ~]$ sudo tcpdump ip6 -vv -i tp-0gn-0000go-0    
tcpdump: listening on tp-0gn-0000go-0, link-type EN10MB (Ethernet), capture size 262144 bytes
    01:45:16.596378 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) 2600:1f14:680:xxxx:66a3:79d5:6c1d:14c > ff02::1:ff00:200e: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has sea15s11-in-x0e.1e100.net
          source link-address option (1), length 8 (1): 02:fc:80:d4:52:b6
            0x0000:  02fc 80d4 52b6
    01:45:17.610410 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) 2600:1f14:680:xxxx:66a3:79d5:6c1d:14c > ff02::1:ff00:200e: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has sea15s11-in-x0e.1e100.net
          source link-address option (1), length 8 (1): 02:fc:80:d4:52:b6
            0x0000:  02fc 80d4 52b6
    01:45:18.634402 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) 2600:1f14:680:xxxx:66a3:79d5:6c1d:14c > ff02::1:ff00:200e: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has sea15s11-in-x0e.1e100.net
          source link-address option (1), length 8 (1): 02:fc:80:d4:52:b6
            0x0000:  02fc 80d4 52b6
Run Code Online (Sandbox Code Playgroud)

注意:我可以从主机 ping ipv6.google.com:

[user ~]$ ping6 ipv6.google.com
PING ipv6.google.com(sea15s11-in-x0e.1e100.net (2607:f8b0:400a:808::200e)) 56 data bytes
64 bytes from sea15s11-in-x0e.1e100.net (2607:f8b0:400a:808::200e): icmp_seq=1 ttl=39 time=9.93 ms
64 bytes from sea15s11-in-x0e.1e100.net (2607:f8b0:400a:808::200e): icmp_seq=2 ttl=39 time=10.1 ms
64 bytes from sea15s11-in-x0e.1e100.net (2607:f8b0:400a:808::200e): icmp_seq=3 ttl=39 time=10.1 ms
Run Code Online (Sandbox Code Playgroud)

邻居发现似乎存在问题。我不确定我是否面临 DAD、NUD 或其他方面的问题,或者根本不是邻居发现问题?

我目前只有路由器ip -6 neigh show,但我对邻居发现缓存的印象只是一个缓存,并且路由应该仍然完整并且可以被发现(尽管这是我非常有限的理解)。也许我错过了一些邻居发现/广告内核参数?

[user ~]$ ip -6 neigh show
fe80::460:a1ff:fec3:9cb6 dev eth0 lladdr 06:60:a1:c3:9c:b6 router STALE 
Run Code Online (Sandbox Code Playgroud)

我有一种预感,我在net.ipv6这里缺少一些内核参数,但我不确定从哪里开始修改它们。任何建议都非常感谢。可以在下面找到完整的网络设置信息。注意我手动配置了vm全局地址,所以和host很像,一个是:XXXb/128,一个是:XXXc/128。

VM 端点 - 接口:

-bash-4.2$ ip a s eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 02:fc:80:d4:52:b6 brd ff:ff:ff:ff:ff:ff
    inet 169.254.18.177/30 brd 169.254.18.179 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2600:1f14:680:xxxx:66a3:79d5:6c1d:14c/128 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::fc:80ff:fed4:52b6/64 scope link 
       valid_lft forever preferred_lft forever
Run Code Online (Sandbox Code Playgroud)

和相关的虚拟机路由:

-bash-4.2$ ip -6 r s
2600:1f14:680:6f00:66a3:79d5:6c1d:14c dev eth0  proto kernel  metric 256  pref medium
fe80::/64 dev eth1  proto kernel  metric 256  pref medium
fe80::/64 dev eth0  proto kernel  metric 256  pref medium
default dev eth0  metric 1024  pref medium
Run Code Online (Sandbox Code Playgroud)

主机 - Tap 和主界面如下所示:

[user ~]$ ip a s tp-0gn-0000go-0
2393: tp-0gn-0000go-0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether d2:d5:4e:f3:de:ab brd ff:ff:ff:ff:ff:ff
    inet 169.254.18.178/30 scope global tp-0gn-0000go-0
       valid_lft forever preferred_lft forever
    inet6 fe80::d0d5:4eff:fef3:deab/64 scope link 
       valid_lft forever preferred_lft forever
[user ~]$ ip a s eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 06:b6:f7:16:ac:04 brd ff:ff:ff:ff:ff:ff
    inet 172.30.255.4/28 brd 172.30.255.15 scope global dynamic eth0
       valid_lft 2994sec preferred_lft 2994sec
    inet6 2600:1f14:680:6f00:66a3:79d5:6c1d:14b/128 scope global dynamic 
       valid_lft 405sec preferred_lft 105sec
    inet6 fe80::4b6:f7ff:fe16:ac04/64 scope link 
       valid_lft forever preferred_lft forever
Run Code Online (Sandbox Code Playgroud)

以及相关路线:

[user ~]$ ip -6 r s
2600:1f14:680:6f00:66a3:79d5:6c1d:14b dev eth0 proto kernel metric 256 expires 389sec pref medium
2600:1f14:680:6f00:66a3:79d5:6c1d:14c dev tp-0gn-0000go-0 metric 1024 pref medium
2600:1f14:680:6f00::/64 dev eth0 proto kernel metric 256 pref medium
unreachable 3ffe:ffff::/32 dev lo metric 1024 error 4294967183 pref medium
fe80::/64 dev eth0 proto kernel metric 256 pref medium
default via fe80::460:a1ff:fec3:9cb6 dev eth0 proto ra metric 1024 expires 1798sec hoplimit 64 pref medium
Run Code Online (Sandbox Code Playgroud)

ip6tables 过滤器允许一切

[user ~]$ sudo ip6tables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination 
Run Code Online (Sandbox Code Playgroud)

主机是amazon-linux,类似于centos/rhel/fedora,cat /etc/os-release

NAME ="Amazon Linux"
VERSION="2"
ID_LIKE="centos rhel fedora"
Run Code Online (Sandbox Code Playgroud)

任何建议都非常感谢。如果我遗漏了任何必要的信息或概念上的任何内容,请告诉我。提前致谢。


更新:我还应该注意,在侦听主机的 eth0 并尝试从虚拟机 ping ipv6.google.com 时,我没有收到任何 tcpdump 数据包。从第一个 tcpdump 中可以看出,数据包首先被发送到所有节点请求多播地址,该地址应该通过 eth0(基于本地路由表)路由,但我从未看到数据包通过 tcpdump 通过 eth0。我现在有net.ipv6.conf.all.forwarding=1net.ipv6.conf.all.accept_ra=2net.ipv6.conf.all.accept_ra_from_local=1


更新 #2:我看到了这篇文章。我添加net.ipv6.conf.all.proxy_ndp=1并添加了一个代理邻居,ip -6 neigh add proxy <host eth0 global ip6 addr> dev <tap device>它允许我从 vm ping 主机的 eth0 全局地址。仍然没有运气从虚拟机连接到 ipv6.google.com 虽然我觉得我越来越近了。


更新 #2.5:我认为之前的更新无关紧要。我认为问题的核心是 vm 不知道任何路由器,因此它正在发送全局 ipv6 地址的邻居请求。我认为不应该是这样,但这只是我的预感。我还没有遇到一个很好的资源,它明确说明应该何时发送邻居请求、路由器请求和回声请求。


更新 #3:我取消了地址的手动分配,并试图让 vm 与 DHCP 服务器(这是在 EC2 vpc btw 中)通信以获取它的地址。我在主机中添加了一个 DHCPv6 中继,但是似乎中继消息正在发送到 DHCPv6 服务器并且永远不会回来。如果其他人感兴趣,我很乐意发布有关此的更多信息/tcpdump。

A.B*_*A.B 5

以下是我认为错误的地方以及解决方法。

虚拟机端

第一个问题是虚拟机上的这个问题:

default dev eth0  metric 1024  pref medium
Run Code Online (Sandbox Code Playgroud)

这使得整个互联网的虚拟机路由堆栈可以直接在eth0的链接上使用。因此,对于任何IPv6 目的地,它将发送 NDP 请求,但没有任何东西(包括主机)会回答它。

要解决此问题,虚拟机只需使用主机作为路由器及其本地链路地址。它可以简单地在虚拟机上手动配置:

ip -6 route delete default dev eth0
ip -6 route add default via fe80::d0d5:4eff:fef3:deab dev eth0
Run Code Online (Sandbox Code Playgroud)

对于VM 端来说就是这样。

VM(和主机的tp-0gn-0000go-0)上的备用设置

如果您不想使用链接本地地址(例如:如果由于主机的tp-0gn-0000go-0上的随机 MAC 地址而导致重新启动时可能会发生变化),您可以使用主机的全局 IP 地址将其复制到tp-0gn-0000go-0上。

在主机上,还将tp-0gn-0000go-0上的 IP 地址添加为 /128(或者noprefixroute如果已经不仅仅是一个 /128,则添加):

ip -6 address add 2600:1f14:680:6f00:66a3:79d5:6c1d:14b/128 dev tp-0gn-0000go-0
Run Code Online (Sandbox Code Playgroud)

在虚拟机上,而不是上面:

ip -6 route delete default dev eth0
ip -6 route add 2600:1f14:680:6f00:66a3:79d5:6c1d:14b/128 dev eth0
ip -6 route add default via 2600:1f14:680:6f00:66a3:79d5:6c1d:14b dev eth0
Run Code Online (Sandbox Code Playgroud)

主机端(在eth0上)

主机自己的路由器不知道虚拟机,因为虚拟机在主机的eth0端不存在。当来自互联网的数据包到达主机的路由器时,它将执行邻居请求,但没有任何东西会回答它,包括主机(当然,除非可以以其他方式配置该路由器,这会简化一切)。主机必须配置ND 代理才能实际响应此请求,以便最终将数据包发送到主机。

为此,请在主机上启用proxy_ndpeth0 添加proxy_ndp特定的 NDP 代理条目(仅当在接口上启用时才有效):

sysctl -w net.ipv6.conf.eth0.proxy_ndp=1
ip -6 neighbour add proxy 2600:1f14:680:6f00:66a3:79d5:6c1d:14c dev eth0
Run Code Online (Sandbox Code Playgroud)

(邻居代理条目可以通过ip neighbour show proxy来显示和删除ip neighbour flush proxy。默认情况下不通过 来显示ip neighbour或删除ip neighbour flush all

主机现在将接收数据包2600:1f14:680:6f00:66a3:79d5:6c1d:14c并将其路由到虚拟机(如其路由表中所定义)。


现在两个方向都已正确转发:它应该可以工作。

我没有尝试使用路由器广告守护进程 ( radvd) 来自动配置虚拟机的路由,因为它与 SLAAC 相关,而SLAAC应该用于不小于 /64 的内容,我不确定它是否会起作用。


更新:正如 @uMdRupert 所提到的,只要激活转发(net.ipv6.conf.all.forwarding=1),如果由路由器通告配置,主机上也需要此设置:

sysctl -w net.ipv6.conf.eth0.accept_ra=2
Run Code Online (Sandbox Code Playgroud)

原因是默认情况下 Linux IPv6 路由器会忽略路由通告(我猜原因是:因为它已经配置为路由器,所以无需更改此配置)。因此,只需在通过路由器通告接收其默认路由的主机上激活 IPv6转发(如此类路由中所示proto ra [...] expires 1798sec),可能会在一段时间后(或配置更改后重新启动时)丢失该路由并变得无法访问。必须通过设置为 2 来否决这一点,以便仍然允许在eth0上接受此类 RA 。accept_ra