Я хотел бы иметь псевдопровод между двумя гостями в KVM. Я не могу использовать мост любого типа, так как гостевые виртуальные машины сами по себе являются виртуальными коммутаторами.
Концептуально кажется, что вет-пара - это лучший вариант, но после долгого чтения я не вижу способа сделать это. Я могу поместить каждого гостя в его собственное сетевое пространство имен, и я могу связать две сети net-n вместе с помощью veth, но я не могу заставить KVM распознавать интерфейсы в пространствах имен.
Любая помощь приветствуется.
Виртуальная машина обычно обрабатывается с помощью нажмите интерфейс, потому что его внутренняя сетевая карта эмулируется пользовательским пространством (обычно QEMU): на другой стороне этого интерфейса, представленного ядром, есть процесс пользовательского пространства обработки трафика, находясь на другой стороне veth интерфейс, снова ядро и его одноранговый veth-интерфейс.
Если QEMU не имеет функции для прямого подключения этих двух интерфейсов (возможно, эта функция действительно существует, но я ее не нашел), например, OpenVPN может подключать двух клиентов без участия сетевого стека ядра, то обычно предполагается использование моста. соединить их.
Если вы не можете использовать мост для перемещения данных из tap1 к tap2 и из tap2 к tap1 поскольку это может мешать протоколам моста, можно использовать интерфейс более низкого уровня, работающий на уровне сетевого интерфейса: 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 └────────────────┘
Если интерфейсы ответвлений названы tap1 и 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), но это связано с интерфейсами. Эти команды можно запускать только после того, как интерфейсы существуют, и их придется запускать снова, если они исчезнут и будут созданы заново (виртуальная машина остановлена и перезапущена).
Вы можете получить статистику активности с помощью:
tc -stats filter show dev tap1 ingress
tc -stats filter show dev tap2 ingress
Если у вас более двух виртуальных машин и вам необходимо перенаправить каждый поток на другой, это возможно, но фильтры и / или действия должны быть адаптированы так, чтобы они не завершались и позволяли сначала зеркалировать (а не перенаправлять) столько раз, сколько необходимо а затем выполните последнее действие перенаправления (или даже не перенаправляйте, если вы хотите, чтобы сетевой стек хоста видел трафик).