我想在 KVM 中的两个客户机之间建立一条伪线路。我无法使用任何类型的桥接器,因为客户机虚拟机实际上本身就是虚拟交换机。
从概念上讲,veth-pair 似乎是可行的方法,但读了很多资料后,我还是没有找到这样做的方法。我可以将每个客户机放入其自己的网络命名空间中,并且可以使用 veth 将两个 net-ns 链接在一起,但我无法让 KVM 识别命名空间内的接口。
任何帮助都将受到赞赏。
答案1
VM 通常由轻敲接口,因为其内部 NIC 由用户空间(通常是 QEMU)模拟:在内核提供的这个接口的另一端,有一个用户空间进程处理交通,而在另一边韦特界面上,还有核心及其对等的 veth 接口。
除非 QEMU 具有直接连接这两个接口的功能(该功能可能存在,但我没有找到),就像 OpenVPN 可以在不涉及内核网络堆栈的情况下连接两个客户端一样,否则通常需要使用桥接器来连接它们。
如果你不能使用网桥将数据从点击1到tap2以及来自tap2到点击1因为它可能会干扰桥接协议,所以可以使用较低级别的接口,在网络接口级别工作:tc
和它的tc ... mirred
可以将数据包从一个接口移动到另一个接口的操作。目前tc ... mirred
只能有出口作为行动的方向,这很好,这就是这里需要的方向入口从一边到出口在另一侧,主机可以看到。因此,无论 VM1 输出什么(到主机的入口),它都会移动到 VM2(主机的出口)。无论 VM2 输出什么,它都会移动到 VM1。
VM1 HOST VM2
┌────────────────┐ ingress egress ┌────────────────┐
│ │ -----------redirect---------> │ │
│ CPU == NIC == QEMU == tap1 tap2 == QEMU == NIC == CPU │
│ or bridge │ <----------redirect---------- │ or bridge │
└────────────────┘ egress ingress └────────────────┘
如果 tap 接口被命名为点击1和tap2,然后你可以用这个来“连接”它们:
tc qdisc add dev tap1 ingress
tc filter add dev tap1 ingress matchall action mirred egress redirect dev tap2
tc qdisc add dev tap2 ingress
tc filter add dev tap2 ingress matchall action mirred egress redirect dev tap1
这些命令创建两个半双工数据传输,以获得全双工结果。在较旧的内核上matchall
可以替换为u32 match u32 0 0
对于真实接口,接口也应置于混杂模式以不按 MAC 进行过滤,但我不确定虚拟非硬件加速接口是否真的需要这样做。否则:
ip link set tap1 promisc on
ip link set tap2 promisc on
主机的网络堆栈将看不到重定向的数据包,如下图所示示意图:入口和出口之间的所有内容都是短路的。 类似 的工具tcpdump
仍将捕获这些数据包,因为 AF_PACKET 不在短路范围内。 但应注意不要让主机注入数据包:接口应禁用 IPv6(以避免 SLAAC、NDP、DAD 等)并且不分配 IPv4 地址:
sysctl -w net.ipv6.conf.tap1.disable_ipv6=1
sysctl -w net.ipv6.conf.tap2.disable_ipv6=1
这几乎不会干扰任何 KVM 使用(包括 libvirt),但它与接口有关。这些命令只能在接口存在时运行,如果接口消失并重新创建(VM 停止并重新启动),则必须再次运行。
您可以通过以下方式获取活动统计数据:
tc -stats filter show dev tap1 ingress
tc -stats filter show dev tap2 ingress
如果你有两个以上的虚拟机,并且必须将每个流量都泛洪到其他虚拟机,这是可能的,但必须调整过滤器和/或操作以避免终止,并允许首先根据需要多次镜像(而不是重定向)然后执行最后的重定向操作(如果您希望主机的网络堆栈看到流量,甚至不需要重定向)。
答案2
尽管这已经很老了,但我仍然可以提出解决方案。
您可以将物理网卡专用于客户机。例如,将其转发为 PCI 设备。
您可以使用 L2TPv3 或使用各种 TCP 和 UDP 原始隧道(“套接字”)模式连接虚拟机:
-netdev socket,id=id[,fd=h][,listen=[host]:port][,connect=host:port]
-netdev socket,id=id[,fd=h][,mcast=maddr:port[,localaddr=addr]]
-netdev l2tpv3,id=id,src=srcaddr,dst=dstaddr[,srcport=srcport][,dstport=dstport],txsession=txsession[,rxsession=rxsession][,ipv6=on|off][,udp=on|off][,cookie64][,counter][,pincounter][,txcookie=txcookie][,rxcookie=rxcookie][,offset=offset]
- 我在最近的手册中找不到任何信息,但我过去在以下配置中使用了套接字:
qemu-system-x86_64 -name net-client-1 \
...
-netdev socket,id=nioudp,udp=192.168.168.83:10004,localaddr=192.168.168.4:10083 \
-device virtio-net-pci,netdev=nioudp,mac=08:00:27:62:B1:C1 \
另一方面,您必须反转地址和端口。它仍然有效,但是似乎没有记录。
详情请阅读QEMU 手册中的网络部分。