KVM/qemu mit QXL – hohe Auflösungen und virtuelle Monitore im Gastsystem definieren und nutzen – II

Diese Artikelserie befasst sich mit der Möglichkeit, hohe Monitor-Auflösungen auch beim Arbeiten mit Linux-Gastsystemen unter einem KVM/QEMU-Hypervisor zu nutzen. Dabei sollen das Spice-Protokoll und ein QXL-Device als virtuelle Grafikkarte des Gastsystems genutzt werden.

Wenn man mit einem virtualisierten System arbeitet, kann der Zugriff auf dessen Desktop entweder am KVM-Host selbst oder aber von einem Remote-System aus erfolgen. Bis auf weiteres konzentrieren wir uns auf das erstere Szenario, d.h. wir greifen unter einem Desktop des KVM-Hostes auf den Desktop des Gastes zu. Wir betrachten also den Fall mehrerer am Host selbst angeschlossener, hochauflösender Monitore, auf dem die Desktop-Umgebung des virtualisierten Gastsystems in einem oder mehreren Fenstern dargestellt werden soll. In einem solchen Szenario ist der durch Netzwerkprotokolle entstehende zusätzliche Komplexitätsgrad irrelevant.

Ausgangspunkt unserer Überlegungen des ersten Artikels war die Feststellung, dass nicht immer alle Möglichkeiten der physikalischen Monitore automatisch und richtig erkannt werden. Und selbst wenn das geschehen sollte, wird die Information nicht unbedingt korrekt an das Gastsystem weitergegeben. Dies gilt u.a. für externe Monitore. Dann ist Handarbeit angesagt. Besondere Vorkehrungen sind i.d.R. auch erforderlich, wenn man ggf. mehrere virtuelle Monitore eines Gastsystems nutzen und auf die physikalischen Schirme des Hosts verteilen will.

Im letzten Beitrag

KVM/qemu mit QXL – hohe Auflösungen und virtuelle Monitore im Gastsystem definieren und nutzen – I

hatte ich das Universaltool xrandr zur Konfiguration von Auflösung und Orientierung von Bildschirmen unter X-Window vorgestellt und bereits auf einem exemplarischen KVM-Host (Laptop mit Opensuse) eingesetzt. Danach hatten wir uns dem mittels “virt-manager” und QEMU virtualisierten Gastsystem zugewandt und uns ein wenig damit befasst, wie denn eine virtuelle Grafikkarte vom Typ QXL aussieht und wie man den dortigen Video RAM für hohe Auflösungen konfiguriert.

Wir gehen nun auf die Frage ein, welche Vorkehrungen im Gastsystems noch erforderlich sind, um einen oder mehrere hochauflösende virtuelle Monitore performant nutzen zu können. Abschließend wenden wir dann “xrandr” im Gastsystem an.

Zusammenspiel benötigter Komponenten

Wie greifen eigentlich die in unserem Szenario benötigten Komponenten Spice, virt-manager, libvirt, Qemu, QXL ineinander? Ich habe mal versucht, das in einer Skizze zu verdeutlichen:

Die Skizze stellt die Situation für einen Virtualisierungshost dar, an dem 3 physikalische Monitore angeschlossen sind. Ein auf diesem KVM-Host angemeldeter User greift mittels Spice-Clients auf das dort installierte Gastsystem zu. (Das ist ein typisches Szenario für Entwickler-Laptops oder Linux-Workstations, in dem man mittels Virtualisierung Eigenschaften eines Zielsystems darstellt.) Das Gast-OS läuft in einer virtualisierten Umgebung, die durch QEMU im Zusammenspiel mit KVM bereitgestellt wird; das virtualisierte System (also der “Gast”) wurde in der Skizze als QEMU VM (Virtual Machine) bezeichnet.

Die Spice-Komponenten sind gelblich dargestellt. “virt-viewer” und “remote-viewer” sind verschiedene Spice-Clients, die mit dem Spice-Server kommunizieren können. Diese Clients ermöglichen die Darstellung des grafischen Outputs des Gastsystems in einem Fenster. Ähnliches leistet auch die in “virt-
manager” integrierte “grafische Spice-Konsole“.

Ich habe versucht, in der Skizze anzudeuten, dass der Spice-Client “remote-viewer” ganz unabhängig von libvirt-Komponenten funktioniert (s. hierzu etwa Red Hat Virtualization Guide für RHEL 6, Kap. 17.2 .

Eine Skizze zur genaueren Struktur des QXL-Devices der QEMU VM mit bis zu vier “heads” für vier virtuelle Monitore von Linux-Gastsystemen hatte ich bereits im vorhergehenden Artikel geliefert. In der hiesigen Skizze habe ich die Situation für 2 “heads” angedeutet; 2 virtuelle Monitore des Gastes werden auf zwei physikalischen Monitoren in Spice-Client-Fenstern angezeigt.

Anmerkungen zur Client-Server-Struktur

Aus der Skizze geht die Client/Server-Struktur der Komponenten nicht so recht hervor, da im dargestellten Fall ja alles auf dem Virtualisierungshost abläuft. Aber sowohl Spice als auch libvirt/qemu sind netzwerkfähig und somit als Client/Server-Systeme ausgelegt. Der “Spice-Server” wie auch der Dämon “libvirtd” sind dabei immer auf dem Virtualisierungs-Server (also dem KVM-Host) zu installieren. Zur Konfiguration der Protokoll-Einstellungen auf einem Linux-Remote-System, von dem aus die Spice-Clients “Spice Console des virt-managers” bzw. der stand-alone Spice-Client “remote-viewer” über ein Netz mit ihren Gegenparts auf dem Virtualisierungshost kommunizieren sollen, siehe
https://www.spice-space.org/spice-user-manual.html
bzw.
https://libvirt.org/docs.html
https://wiki.ubuntuusers.de/virt-manager/.
Virtualization-Administration-Guide von Red Hat für RHEL 6

Im virt-manager bietet der Punkt “File” > Add new connection” Felder zur Konfiguration einer Verbindung an. Spice kann über SSH getunnelt werden; für virt-manager wird eh’ qemu+ssh angeboten.

Wie einleitend festgestellt, werden uns in dieser Artikelserie zunächst mit einer Konfiguration, wie sie auf der Skizze dargestellt ist, begnügen. Spezielle Netzwerk-Einstellungen entfallen dann.

QXL-Treiber und spice-vdagent

Auf der rechten Seite der obigen Skizze erkennt man das virtuelle QXL-Device. Die Skizze deutet hier an, dass im Betriebssystem [OS] des Gastes zwei Komponenten erforderlich sind, um die notwendige Unterstützung zu liefern – ein Treiber und ein sogenannter “spice-vdagent”. Wir müssen uns nun mit deren Bereitstellung im Gastsystem befassen. Es gilt:

  • Der qxl-Treiber ist, wie Video-Treiber für reale Karten auch, ein drm-fähiges Kernelmodul. “drm” steht dabei für “direct rendering manager”; https://de.wikipedia.org/ wiki/ Direct_Rendering_Manager).
  • Der spice-vdagent wird dagegen als Dämon bereitgestellt und ist als Service zu aktivieren.

Versionsabhängigkeiten und Test-Setup

Leider muss ich vor weiteren Details vorausschicken, dass sowohl das Laden des qxl-Kernel-Moduls als auch die faktische Wirkungsweise von qxl-Treiber und spice-vdagent stark von der Art/Version des Linux-Gastsystems, dessen Kernel und zu allem Überfluss auch noch von der dortigen Desktop-Version abhängen. Ich nehme als Beispiel mal Debian 8 “Jessie”:

Unter dem ursprünglichen Kernel 3.16 von Jessie lässt sich das qxl-Modul nicht ohne weiteres laden. Es verlangt einen mir
unbekannten Parameter. In Installationen, die Debian-Backport-Pakete nutzen, wird ab Kernelversion 4.2 das qxl-Modul dagegen automatisch geladen. Ferner hat das Laden des qxl-Moduls – je nach Kernelversion und Desktop-Version unterschiedliche Auswirkungen auf automatische Auflösungsanpassungen. Ich komme darauf in einem weiteren Artikel zurück.

Wer die nachfolgend beschriebenen Punkte in einer konsistenten Weise nachvollziehen will, sollte bzgl. der Gastsysteme deshalb auf ein aktuelles Debian 9 (“Stretch”) (mit Gnome, KDE 5) oder aber ein Kali 2017 (mit Gnome) zurückgreifen. Diese Systeme bilden im Moment aus meiner Sicht den Sollzustand am besten ab.

Wählt man dagegen Opensuse Leap 42.2, so bitte mit Gnome. Mit debian-8-basierten Systemen, neueren Kernel-Versionen, unterschiedlichen libvirt/spice-Versionen aus Backport Repositories sowie mit dem offiziellen Plasma5-KDE5/KDE4-Mix unter Opensuse 42.1/42.2 kann es dagegen abweichende Resultate geben. “Red Hat”-Gastsysteme habe ich bislang nicht getestet.

Test-Setup

  • KVM-Gast: Debian 9 “Stretch” (mit Gnome und KDE5) / Kali2017 (Gnome). Virtuelles Grafik-Device: QXL mit maximaler ram/vram-Bestückung.
  • KVM-Host: Linux-Systeme mit Opensuse Leap 42.2 und dem dortigen KDE5/Plasma5/KDE4-Mix; darunter auch der im letzten Artikel angesprochene Laptop mit einem externen HDMI-Schirm.
  • Grafischer Spice-Client für einen virtuellen Monitor: die “grafische Spice Konsole”, die in virt-manager integriert ist.
  • Grafischer Spice-Client für mehrere virtuelle Monitore: “remote-viewer” (muss ggf. über das Paket “virt-viewer” nachinstalliert werden).

Bereitstellung QXL-Treiber im Gastsystem

Die Kapazitäten und die Performance einer Grafikkarte können nur mit einem geeigneten Treiber vollständig genutzt werden. Das ist für virtuelle Grafik-Devices wie das QXL-Device nicht anders.

Für einen KVM-Gast kann man in einem Spice-Client in jedem Fall Auflösungen bis zu 1024×768 erreichbar – auch wenn der device-spezifische QXL-Treiber im Gastystem gar nicht installiert ist. (Dies wird durch einen Fallback auf einen “standard vga”-Treiber bzw. ein VESA Framebuffer-Device ermöglicht.) Will man dagegen mit höheren Auflösungen arbeiten, so kann dies ggf. auch ohne QXL-Treiber funktonieren; allein aus Performancegründen lohnt es sich aber zu überprüfen, ob der QXL-Treiber im Gastsystem geladen ist:

root@deb11:~# lsmod | grep -iE "(video|qxl|drm)"
qxl                    69632  3
ttm                    98304  1 qxl
drm_kms_helper        155648  1 qxl
drm                   360448  6 qxl,ttm,drm_kms_helper

 
Falls das nicht der Fall sein sollte, muss man ggf. SW-Pakete nachinstallieren. Das Kernelmodul wird unter Debian über das Paket “xserver-xorg-video-qxl” bereitgestellt; unter Opensuse ist dagegen das Paket “xf86-video-qxl” erforderlich. (Zudem sollte “qemu-vgabios” installiert sein).

U.a. unter Opensuse Leap 42.2 lädt das Gastsystem den QXL-Treiber dann aber immer noch nicht zwingend automatisch. Das Modul ist in solchen Fällen also von Hand über “modprobe qxl” zu laden; den X-Server muss man dann neu starten. Ferner muss man sich darum kümmern, in welcher Weise man in seinem (Gast-) Betriebssystem dafür sorgen kann, dass Kernelmodule bereits beim Booten geladen werden:

Automatisches Laden des qxl-Kernelmoduls unter Opensuse Leap
Unter Opensuse kann man etwa “dracut -f” oder “mkinit” bemühen, nachdem man einer Datei “/etc/dracut.conf.d/01-dist.conf” einen Eintrag
force_drivers+=”qxl”
hinterlassen hat. Dabei wird das initramfs bemüht.
 
Alternativ und soweit systemd aktiv ist:
Im Verzeichnis “/etc/modules-load.d/” eine Datei “qxl.conf” anlegen und dort einfach “qxl” eintragen.
 
Als weitere Möglichkeit, die ich aber nicht getestet habe, legt man unter “/etc/X11/xorg.conf.d/50-device.conf” einen Eintrag der Form

Section "Device"
 Identifier "device0"
 Driver "qxl"
EndSection

an.

Automatisches Laden des qxl-Kernelmoduls unter Debian
Unter Debian-Systemen nimmt man dagegen einfach einen Eintrag in der Datei “etc/modules” vor. Debian 9 lädt das qxl-Modul aber eh’ schon automatisch, wenn es erkennt, dass es unter KVM/QEMU virtualisiert läuft und ein QXL-Device vorhanden ist .

OS-unabhängig über einen systemd-Service
Persönlich finde ich eigentlich ein kleines eigenes Skript, das man mit einer Service-Datei (qxl.service) versieht, am besten. Dort kann man nämlich z.B. über “lspci” vorab analysieren, ob überhaupt ein QXL Device zur Verfügung steht. Ich gehe auf diese Lösung aus Platzgründen aber nicht weiter ein.

Für alle Varianten gilt: Der Treiber sollte jedenfalls geladen sein, bevor der X- oder Wayland-Server gestartet wurde.

Bedeutung und Aktivierung des spice-vdagent

Der sog. “spice-vdagent” hat/hatte mehrere wichtige Aufgaben; ich stelle sie mal nach meinem Verständnis dar:

  • Kommunikations- und Event-Support: Der vdagent triggert und optimiert die Kommunikation zwischen dem Gast OS über den Spice-Server mit dem (remote) Spice-Client auf dem KVM-Host oder auf einem Remote-Host. U.a. werden Mouse-Positionen zwischen KVM-Gastsystem und Host abgeglichen und interpretiert – das ermöglicht u.a. ein nahtloses Verlassen von Spice-Fenstern auf dem Host.
  • Copy/Paste: Der vdagent ermöglicht beidseitiges Copy/Paste zwischen Applikationen des (Remote-) Host-Systems, auf dem das Spice-Fenster zur Ansicht des Gast-Desktops läuft, und Applikationen des KVM-Gast-Systems.
  • Multi-Monitor-Support: Er unterstützt im Zusammenspiel mit dem qxl-Treiber Gast-Systeme mit mehreren virtuellen Monitoren, deren Output in mehreren Spice-Remote-Viewer-Fenstern dargestellt werden kann. U.a. übernimmt er dabei das korrekte Mouse-Handling auf der Gast- wie der (Remote-) Host-Seite.
  • Auflösungsanpassung: Er ermöglichte eine automatische Anpassung der Auflösung des Gast-Desktops an die gewählte Größe des Spice-Client-Fensters auf dem (Remote-) Host.
    Hinweis: Das wird in aktuelleren Linux-Systemen aber wohl anders gemacht; s. hierzu den nächsten Artikel.
  • File-Transfer: Freigabe eines Zugriff des Gastsystems auf bestimmte Verzeichnisse des (Remote-) Hostes; File-Transfer mittels Drag & Drop

Man sieht: Der spice-vdagent hat etwa solche Aufgaben wie die “VMmware-Tools”, die in einem VMware-Gastsystem zu installieren sind.

Einen detaillierteren Überblick verschaffen die Web-Seiten https://www.spice-space.org/spice-user-manual.html#agent und https://www.spice-space.org/features.html
Die Platzierung des Agents im KVM-Gast und in der Kommunikationsstruktur entnimmt man der Skizze auf der Seite https://www.spice-space.org/index.html.

Die Nutzung des spice-vdagent erfordert bestimmte Voraussetzungen:

Vorbereitung der QEMU VM auf dem KVM-Host
Der Einsatz des spice-vdagents erfordert bestimmte Features der virtuellen Maschine und zugehörige Startoptionen für die QEMU VM. So muss ein bestimmtes Serial-Device vorhanden sein (s. die Skizze oben) und ein Kommunikationskanal für den Spice-Agent reserviert werden (https://wiki.archlinux.org/ index.php/ QEMU#SPICE). Man kann sich einige händische Arbeit durch das Anlegen der virtuellen Maschinen (“Domänen” im QEMU-Slang) mittels “virt-manager” ersparen:
“virt-manager” gibt die notwendigen Features automatisch vor und konfiguriert die zugehörigen QEMU-Optionen für den Start der virtuellen Maschine.

Maßnahmen im Gast-OS
Der spice-vdagent ist als systemd-Service ausgelegt und kann als solcher im KVM-Gastsystem enabled (über den nächsten Reboot hinaus) und gestartet werden.

root@guest:~#  systemctl enable spice-vdagentd.service
root@guest:~#  systemctl start spice-vdagentd.service

 
(Nachtrag 22.02.2018: Natürlich muss man den Agent erstmal installieren; hierzu nutzt man das Paket-Management des Gastsystems; unter Debian mittels “apt-get install spice-vdagent”. Um nach dem “Enablen” des zugehörigen Service z.B. Copy/Paste in beide (!) Richtungen zwischen Spiece-Konsole und der Umgebung ausführen zu können, muss man zudem die virtuelle Maschine und deren Konsole neu starten.)

Damit haben wir alles erledigt, was zur Performance-Optimierung, einer vernünftigen Mouse-Steuerung etc. notwendig war.

Einsatz von xrandr für unerkannte Auflösungsmodes im Gastsystem

Wir kommen nun wieder auf unser Laptop-Problem mit einer unerkannten Auflösung von 2560x1440_44Hz aus dem letzten Artikel zurück. Dort hatten wir bereits beschrieben, wie man den KVM-Host vorbereitet und die dort bislang unerkannte Auflösung auf einem externen HDMI1-Monitor mittels xrandr aktiviert. Wird dann die für den Host-Desktop bereitgestellte Auflösung auch auf dem Gastsystem automatisch erkannt?

Wir starten über “virt-manager” z.B. einen “Kali2017”-Gast und betrachten ihn über die grafische Spice-Konsole des virt-managers auf dem HDMI-Monitor; dabei unterbinden wir zunächst eine automatische Skalierung der Gastauflösung (darauf kommen wir später zurück):

Leider bieten dann weder ein Kali2017- noch ein Debian-Stretch-Gast die maximal mögliche Auflösung an:

Der Einsatz des QXL-Treibers und des vdagents hat in dieser Hinsicht also nichts verbessert. Dass beide SW-Komponenten samt QXL-Device im Gastsystem vorhanden sind, belegt folgender Output:

root@kali2017-1:~# lsmod | grep qxl
qxl                    69632  3
ttm                    98304  1 qxl
drm_kms_helper        155648  1 qxl
drm                   360448  6 qxl,ttm,drm_kms_helper
root@kali2017-1:~# 

root@kali2017-1:~# systemctl status spice-vdagentd.service
● spice-vdagentd.service - Agent daemon for Spice guests
   Loaded: loaded (/lib/systemd/system/spice-vdagentd.service; enabled; vendor p
   
Active: active (running) since Thu 2017-07-13 09:49:54 CEST; 5min ago
  Process: 397 ExecStart=/usr/sbin/spice-vdagentd $SPICE_VDAGENTD_EXTRA_ARGS (co
  Process: 390 ExecStartPre=/bin/rm -f /var/run/spice-vdagentd/spice-vdagent-soc
 Main PID: 427 (spice-vdagentd)
    Tasks: 1 (limit: 4915)
   CGroup: /system.slice/spice-vdagentd.service
           └─427 /usr/sbin/spice-vdagentd

root@kali2017-1:~# dmesg | grep drm
[    2.272876] [drm] Initialized
[    2.391864] [drm] Device Version 0.0
[    2.391865] [drm] Compression level 0 log level 0
[    2.391866] [drm] Currently using mode #0, list at 0x488
[    2.391866] [drm] 114686 io pages at offset 0x4000000
[    2.391867] [drm] 67108864 byte draw area at offset 0x0
[    2.391867] [drm] RAM header offset: 0x1fffe000
[    2.391868] [drm] rom modes offset 0x488 for 142 modes
[    2.391916] [drm] qxl: 64M of VRAM memory size
[    2.391917] [drm] qxl: 511M of IO pages memory ready (VRAM domain)
[    2.391917] [drm] qxl: 512M of Surface memory size
[    2.392479] [drm] main mem slot 1 [a0000000,1fffe000]
[    2.392479] [drm] surface mem slot 2 [c0000000,20000000]
[    2.392481] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
[    2.392482] [drm] No driver support for vblank timestamp query.
[    2.392739] [drm] fb mappable at 0xA0000000, size 3145728
[    2.392740] [drm] fb: depth 24, pitch 4096, width 1024, height 768
[    2.392772] fbcon: qxldrmfb (fb0) is primary device
[    2.405136] qxl 0000:00:02.0: fb0: qxldrmfb frame buffer device
[    2.418839] [drm] Initialized qxl 0.1.0 20120117 for 0000:00:02.0 on minor 0

 
Hinweis:

Ob der spice-vdagent tatsächlich seinen Job tut, verifiziert man am einfachsten dadurch, indem man Copy/Paste-Übertragungen von Text zwischen Host- und Gast-System ausprobiert.

Einsatz von xrandr

Wir greifen im Gast nun zum gleichen Trick wie auf dem Host. Ein Absetzen des Befehls xrandr zeigt, dass der relevante (virtuelle) Monitor des Gastsystems “Virtual_0” heißt:

root@kali2017-1:~# xrandr
Screen 0: minimum 320 x 200, current 1024 x 768, maximum 8192 x 8192
Virtual-0 connected primary 1024x768+0+0 0mm x 0mm
   1024x768      59.92*+
   1920x1200     59.88  
   1920x1080     59.96  
   1600x1200     59.87  
   1680x1050     59.95  
   1400x1050     59.98  
   1280x1024     59.89  
   1440x900      59.89  
   1280x960      59.94  
   1280x854      59.89  
   1280x800      59.81  
   1280x720      59.86  
   1152x768      59.78  
   800x600       59.86  
   848x480       59.66  
   720x480       59.71  
   640x480       59.38  
Virtual-1 disconnected
Virtual-2 disconnected
Virtual-3 disconnected

 
Also:

root@kali2017-1:~# cvt 2560 1440 44
# 2560x1440 43.99 Hz (CVT) hsync: 65.06 kHz; pclk: 222.75 MHz
Modeline "2560x1440_44.00"  222.75  2560 2720 2992 3424  1440 1443 1448 1479 -hsync +vsync

root@kali2017-1:~# xrandr --newmode 2560x1440_44  222.75  2560 2720 2992 3424  1440 1443 1448 1479 -hsync +vsync
root@kali2017-1:~# xrandr --addmode Virtual-0 2560x1440_44
root@kali2017-1:~# xrandr --output Virtual-0 --mode 2560x1440_44

 

Und schon ist unsere gewünschte hohe Auflösung nach ein wenig Flackern im Spice-Fenster aktiv :

root@kali2017-1:~# xrandr --current
Screen 0: minimum 320 x 200, current 2560 x 1440, maximum 8192 x 8192
Virtual-0 connected primary 2560x1440+0+0 0mm x 0mm
   1024x768      59.92 +
   1920x1200  
   59.88  
   1920x1080     59.96  
   1600x1200     59.87  
   1680x1050     59.95  
   1400x1050     59.98  
   1280x1024     59.89  
   1440x900      59.89  
   1280x960      59.94  
   1280x854      59.89  
   1280x800      59.81  
   1280x720      59.86  
   1152x768      59.78  
   800x600       59.86  
   848x480       59.66  
   720x480       59.71  
   640x480       59.38  
   2560x1440_44  43.99* 
Virtual-1 disconnected
Virtual-2 disconnected
Virtual-3 disconnected

 

Das im Bildausschnitt erkennbare farbige Hintergrundsbild außerhalb der Spice-Konsole stammt vom KDE-Desktop des Opensuse-Hosts; es wurde für den HDMI-Schirm festgelegt. Man erkennt, dass das Fenster der grafischen Spice-Konsole Scrollbalken anbietet, wenn der aktuelle Fensterrahmen zu klein für die Auflösung des Gast-Desktops ist. Wegen meines GTK-Themes werden die Scrollbalken nur angezeigt, wenn die Maus dem jeweiligen Fensterrand nahe kommt. Deshalb ist im Bild nur der vertikale Balken sichtbar.

Natürlich kann man das Spice-Fenster auf dem externen HDMI-Monitor auch im Vollbild-Modus betreiben. Am einfachsten geht das, indem man die Fenstergröße an die Gastauflösung anpassen lässt; die Spice-Konsole bietet aber unter “View” zudem einen eigenen Menüpunkt zum Wechsel in den Vollbild-Modus an:

Mein HDMI-Schirm mit 2560×1440 zeigt dann folgendes Bild:

Genau das war aber unser erstes Ziel:

Wir können die hohe Auflösung eines physikalischen Host-Monitors, auf dem ein Spice-Client-Fenster im Vollbild-Modus läuft, nun für die Darstellung des Desktops eines unter KVM/QEMU virtualisierten Gastsystems nutzen.

Anzumerken bleibt auch, dass die Spice/QXL-Performance selbst mit der relativ schwachbrüstigen Intel HD4000, die in der Laptop-CPU integriert ist, völlig annehmbar ist. Zu verdanken ist das vor allem dem Einsatz des QXL-Treibers.

Ausblick

Im nächsten Artikel

KVM/qemu mit QXL – hohe Auflösungen und virtuelle Monitore im Gastsystem definieren und nutzen – III

befassen wir uns damit, wie man die mit CVT und xrandr gefundenen bzw. definierten Modes persistent im Gast-System hinterlegt, so dass sie auch einen Boot-Vorgang überstehen. Zudem wollen wir die Auflösung auch für den Display-Manager (etwa gdm3) hinterlegen. Danach wenden wir uns der Frage zu, ob und wie eine automatische Auflösungsanpassung an den Fensterrahmen der Spice-Clients möglich ist.

KVM/qemu, libvirt, virt-manager – persistent names for virtual network interfaces of guest systems

Whilst experimenting with KVM guests and netfilter iptables, I cloned some guest systems. The virtual network interfaces of the different guests (old ones and cloned ones) were created with reference to a “virtual network” – a “host only network” in my case. The corresponding bridge was defined via virt-manager.

I found that one cannot always rely on a persistent “N“-number in the name “vnetN” of the interface devices of my virtual guests throughout cloning, further system changes and a reboot. I am not quite sure whether there is also an impact of systemd/udev – as I installed a new version of systemd during my experiments, too. Whatever exact reason: There are obviously conditions under which the name of a previously defined virtual NIC device of a specific guest may change due to a vnet-renumbering.

In my case one of the guests originally had gotten a virtual NIC (tun device) with a defined MAC and a name of “vnet3”. Later on (after cloning and other system changes) the guest’s virtual NIC with the same MAC got a device name “vnet6” – although I had not touched its configuration. That the MAC was kept up is not surprising as it resides in the XML-definition file created for the guest when I configured it with the help of virt-manager.

Such a change of the name of an Ethernet interface may of course become a disaster for the application of NETFILTER rules – especially for IPTABLES rules which directly refer to device names via the “–physdev” option. Your precious firewall rules may become worthless after a renaming of your virtual NIC.

I had to search a while to find an information on how to make the names created by libvirt for tun interfaces of KVM/qemu guests persistent. Stupid me! I should have looked into the libvirt Wiki in the first place:
http://libvirt.org/formatdomain.html#elementsNICSVirtual
http://libvirt.org/formatdomain.html#elementsNICSTargetOverride

The trick is to place an additional tag inside the tag for the interface definition in the guest’s XML file. And to follow a naming rule …

In my case I used virsh (virsh edit kali3) to edit the configuration file “kali3.xml” og a guest named “kali3”. You find the guest configuration files in the directory “/etc/libvirt/qemu/” of your Linux host. In the editor I navigated to the relevant interface definition – see the last one in the list below – which I changed :

 
    <interface type='bridge'>
      <mac address='52:54:00:22:cf:63'/>
      <source bridge='virbr_vmw'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <interface type='network'>
      <mac address='52:54:00:96:db:01'/>
      <source network='kali2'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/>
    </interface>
    <interface type='network'>
      <mac address='52:54:00:b2:7c:1f'/>
      <source network='virbr6'/>
      <target dev='vk61'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/>
    </interface>

 
You see some interface definitions there. All interface definitions include a MAC definition. The MACs were statistically created and assigned when I added the virtual NICs to the guests’ configuration via virt-manager. None of the first definitions contains anything that resembles a device name
definition. However, the interesting supplement can be found in the last interface definition:

<target dev='vk61'/>

The “target” tag allows for the definition of a persistent device name (here: vk61). Note that the documentation says that the name chosen must NOT start with “vnet”.

To apply the changes save the modified configuration files for your guests and restart the libvirtd service :

systemctl restart libvirtd.service

I hope this helps other people who need persistent names of the device interfaces of their KVM guests!

Opensuse/Linux – KVM, VMware WS – virtuelle Brücken zwischen den Welten

Bei der Wahl einer Virtualisierungsumgebung auf einem Linux-Host spielen viele Faktoren eine Rolle. Kosten, Anzahl der Gäste, Ressourcenbelastung des Hosts, Verfügbarkeit von Monitoring- und Admin-Umgebungen – aber auch die Kompatibilität mit den zu implementierenden Gastsystemen. Ich betrachte in diesem Artikel ausschließlich Linux-Arbeitsplatzsysteme als Virtualisierungshosts – also Desktops oder Laptops. Auf solchen Systemen verfolge ich dabei andere Interessen als auf Hosts für Server-Gast-Systeme:

In meinem Desktop-Umfeld spielen Windows-Gastsysteme für Entwicklungs- und für Penetrationstetsts neben Mehrzweck-Linux-Systemen wie Debian oder Kali2 eine Rolle. Ich benötige nur wenige und rudimentär ausgestattete Gäste. Die durchschnittliche Belastung des Virtualisierungs-Hosts ist somit relativ gering. Die Kosten sollen möglichst klein sein, die administrativen Möglichkeiten ausreichend, d.h. ohne Luxus. Für alle Gastsysteme gilt aber, dass die emulierte grafische Oberfläche hinreichend flüssig bedienbar sein muss.

Für die Windows-Desktops verwende ich deshalb eine VMware-Workstation-Umgebung, da mir diese Virtualisierungs-Plattform erfahrungsgemäß gut handhabbare Windows-Gastsysteme inkl. einer schnellen grafischen Oberfläche liefert. Zur Not auch mit 3D-Grafik-Unterstützung. Linux-Gäste fahre ich dagegen unter der KVM/Qemu-Virtualisierungsinfrastruktur – durch virtio-Treiber, Spice und Video XQL ist dort die grafische Nutzeroberfläche (inzwischen) hinreichend schnell (wenn z.Z. auch noch ohne 3D-Support). Libvirt/virt-manager liefern für KVM ausreichende und bequeme Möglichkeiten der Administration.

Mixt man – wie ich – zwei unterschiedliche Virtualisierungsumgebungen auf ein und demselben Host, so entstehen neue Begehrlichkeiten. Das gilt im Besonderen für die Konfiguration eines Pentest-Labors und die schnelle Abänderung der Netzwerk-Konfiguration. Für Penetrationstests isoliert man die Gäste i.d.R. in privaten Netzwerken. Diese werden jeweils durch eine virtuelle Bridge repräsentiert – mit oder ggf. auch mal ohne Host-NIC, um auch den Host an das jeweilige Netzwerk anbinden zu können. Ein direktes Bridging zu physikalischen Devices des Hosts bringt dagegen je nach Testsituation zu viele Gefahren für den Hosts selbst und dessen LAN-Umgebung mit sich.

“Host-Only-Netzwerke” [HON] kann man sowohl unter VMware WS als auch unter KVM realisieren. Jedes Host-Only-Netzwerk definiert ein bestimmtes Netzwerksegment, dem die jeweiligen Gastsysteme und ggf. der Host über spezielle virtuelle NICs zugeordnet werden.

In vorliegenden Artikel will ich auf die Frage eingehen, ob und wie man

  • Gäste einer “KVM”-Umgebung an eine Host-Only-Bridge Bridge einer VMware WS-Umgebung
  • und/oder umgekehrt Gäste einer “VMware WS”-Umgebung an eine Host-Only-Bridge Bridge einer KVM-Umgebung

anbinden kann. Natürlich könnte man immer über den Host zwischen den Netzwerksegmenten der Virtualisierungsumgebungen routen. Das ist sicher die schnellste Art der Kopplung. Mich interessieren in diesem Artikel aber Möglichkeiten, die ohne Routing auskommen. Ich meine also Szenarien, in denen die Gastsysteme der beiden Virtualisierungsumgebungen Teil eines logischen Netzwerk-Segmentes (auf Layer 3) werden.

Es geht also um eine Art “Cross”-Bridging” für bestimmte Gäste der unterschiedlichen Virtualisierungsumgebungen. Ich stelle hierfür nachfolgend drei verschiedene Lösungen vor. Eine vierte Lösung – eine elegante Spielart der dritten Lösung – wird im kommenden Artikel Fun with veth devices, Linux virtual bridges, KVM, VMware – attach the host and connect bridges via veth
vorgestellt.

Wozu braucht man die Möglichkeit einer gegenseitigen direkten Anbindung von Gästen einer “KVM”- oder “VMware WS”-Umgebung an ein Host-Only-Netzwerk der jeweils anderen Virtualisierungs-Infrastruktur?

Stattet man die Gastsysteme mit nur einer NIC aus, welche über die Verwaltungstools der jeweiligen Virtualisierungsinfrastruktur an die dort beheimatete virtuelle Bridge angebunden wird, so können die Gastsysteme des Segments der einen Virtualisierungsumgebung mit den Gastsystemen des Segments der jeweils anderen Virtualisierungsumgebung nur dann kommunizieren, wenn Routing über den Host und dessen Paketfilter zugelassen wird. Damit sind unter Penetrationstest-Bedingungen aber erneut Sicherheitsrisiken (“packet leackage” ins physikalische Netz) verbunden.

Umgekehrt gilt: Auch ohne Paketfilter erzwingen die Standardeinstellungen der Router/Forwarding-Funktionalität eines Linux-Systems Einschränkungen – u.a. werden IP-gespoofte Pakete, mit Ursprungsadressen im jeweils anderen Segment, nicht vom Linux-Kernel des Hosts weitergeleitet. Unter diesen Bedingungen kann im Rahmen von Penetrationstests dann z.B. ein NMAP Idle-Scan von einem Linux-System im KVM-Segment über ein “idle” Windows-System zu einem Windows-Target im VMware-Segment nicht durchgespielt werden.

Grundsätzlich ist meine Anforderung die, dass man auf die Vorteile der jeweiligen Virtualisierungsumgebung für die Gast-Einrichtung nicht verzichten will, unter bestimmten Bedingungen aber eine direkte – d.h. routing-freie – Anbindung eines Gastsystems an das Host-Only-Netzwerksegment der jeweils anderen Virtualisierungsumgebung nutzen möchte – über eine entsprechende konfigurierte (ggf. zusätzliche) virtuelle NIC.

Ich wollte das schon länger mal aus Prinzip ausprobieren – einfach um zu sehen, ob und wie das ggf. geht. Durch Aktivierung/Deaktivierung von NICs und zugehörigen Profilen will ich für ein Gastsystem schnell zwischen Szenarien mit Routing und ggf. zwischengeschalteten Paketfiltern einerseits und direkter Segment-Anbindung andererseits umschalten können.

Das Ganze ist aber auch unter dem Aspekt interessant, dass ein direktes “cascaded” oder “nested” Bridging von Linux-Bridges nicht möglich ist. So stellt sich u.a. die Frage: Wie bekommt man eine VMware Bridge an eine Linux-Bridge angeschlossen?

Netzwerk-Editoren

In der “VMware WS”-Umgebung nutzt man zur Konfiguration virtueller Netzwerke/virtueller Bridges als User root den “Virtual Network Editor” (s. Abbdg.), unter KVM den “Virtual Machine Manager” (virt-manager > “Edit” >> “Connection Details” >> “Virtual Networks”) und/oder eine Kombination aus “brctl”- und “ip” bzw. “tunctl”-Kommandos.

VMware Virtual Network Editor [VNE]
vmware_vne_1

KVM Virtual Machine Manager => Virtual Networks
kvm_ne_1

CLI-Kommandos: brctl/tunctl/ip
Wir kommen auf die praktische Anwendung dieser Kommandos weiter unten zurück. (Siehe aber auch: Opensuse – manuelles Anlegen von Bridge to LAN Devices (br0, br1, …) für KVM Hosts.) Festzuhalten bleibt zunächst, dass ein mittels “tunctl” erzeugtes virtuelles “tap”-Device (Layer 2 Ethernet Device) nur genau einer Linux-Bridge zugeordnet werden kann. Ein Kaskadieren von Bridges (= direktes Einhängen einer Linux-Bridge in eine andere) ist wie gesagt auch nicht möglich.

Ein paar Anmerkungen zum VMware VNE:
nVermutlich reichen die Konfigurationsmöglichkeiten der VMware WS nicht an die der großen VMware Vitualisierungsumgebungen heran – hinreichend sind sie aber. So kann man u.a. Host-Only-Netzwerke (Bridges) mit oder ohne NAT erzeugen. Bei der Erzeugung eines VMware Host-Only-Segments wird automatisch eine Host-NIC für die erzeugte Bridge mit erzeugt. Diese Host-NIC für das VMware Host-Only-Netz erscheint dann – obwohl virtuell – als Ethernet-Device des Hostes.

vmnet1          device-unconfigured
      link:     #11, state up, mtu 1500
      type:     ethernet, hwaddr 00:50:56:c0:00:01
      addr:     ipv4 192.168.48.1/24

vmnet2          device-unconfigured
      link:     #12, state up, mtu 1500
      type:     ethernet, hwaddr 00:50:56:c0:00:02
      addr:     ipv4 192.168.3.1/24

 
Das ist insofern bemerkenswert, als es in einem entscheidenden Punkt anders aussieht als bei den “tap”- und Bridge-Devices, die man (z.B. mit virt-manager) zu virtuellen “vibr”-Bridges in der KVM-Welt erzeugt:

Der Typ des virtuellen VMware Devices ist “ethernet”! Nicht “bridge” oder “tap”.

Die VMware-Umgebung bietet auch ein direktes Bridging zu physikalischen Host-NICs an. Erzeugt man virtuelle Devices unter Linux und verfolgt, was sich dann auf der VMware-Seite tut, so sieht man: Die VMware Umgebung erkennt neue Netzwerk-Devices (wie erzeugte virtuelle Linux-Bridges und Linux Tap-Devices) und bietet (zumindest theoretisch) ein direktes Bridging auch zu diesen virtuellen Devices an.

Wie bringt man nun mit diesem Rüstzeug die unterschiedlichen Virtualisierungs-Welten bzw. ihre Gastsysteme auf einem Linux-Desktop-System zusammen? Welche Möglichkeiten gibt es?

Lösungsansatz 1: Anbindung von KVM-Gästen an das virtuelle VMware-Netz mittels “macvtap”-Devices

Im ersten Lösungsansatz möchte ich versuchen, ausgewählte KVM-Gäste der Linux-Bridge direkt an das virtuelle VMware-Netz anzubinden. Das soll vom Effekt her ungefähr so aussehen:

kvm_to_vmware

Im Zentrum des Interesses steht “Guest0” im KVM-Bereich. Das eine Interface (vnet1) dieses Gastes ist regulär an die Linux-Bridge “virbr0” angebunden. Von dort könnte über den Host ins VMware-Netz geroutet werden. Das wollen wir aber vermeiden und statt dessen über ein weiteres Interface die nahtlose Anbindung von Guest0 an das virtuelle Netz “vmnet1” auf der VMware-Seite erreichen – unter Umgehung irgendwelcher Paketfilter des Hostes. Siehe die gestrichelte Linie. Auch wenn wir das nicht direkt in der dargestellten Form verwirklichen können, so soll doch zumindest der effektive Datentransport der Logik dieses Bildes entsprechen.

Der VMware WS VNE bietet eine direkte Anbindung virtueller “tap”-Devices von VMware Gästen an die vmnet1-Bridge leider nicht an. Das einzige Element von “vmnet1”, das auf der Linux-Seite für evtl. Manipulationen zur Verfügung steht, ist die zugehörige virtuelle Host-NIC gleichen Namens. Was können wir damit aus Sicht eines KVM-Gastes tun?

macvtap-Devices?

KVM unterstützt seit einigen Jahren die Nutzung physikalischer Ethernet Devices durch Gastsysteme in Form sog. virtueller “macvtap”-Bridge-Devices. Zur Einführung siehe
http://virt.kernelnewbies.org/MacVTap

Ein weiterer sehr lesenswerter Artikel hat mein Verständnis beträchtlich erhöht:
https://seravo.fi/2012/virtualized-bridged-networking-with-macvtap

Der folgende
Artikel zeigt, wie man macvtap Devices in einer mit “libvirt” verwalteten Umgebung manuell über entsprechende Einträge in XML-Konfigurationsdateien einbindet.

 
Weitere interessante Artikel zu macvtap-Devices sind:
https://wiki.math.cmu.edu/iki/wiki/tips/20140303-kvm-macvtap.html
http://www.furorteutonicus.eu/2013/08/04/enabling-host-guest-networking-with-kvm-macvlan-and-macvtap/

Man beachte, dass alle genannten Artikel auf physikalische Devices als sog. “lower devices” einer “macvtap”-Bridge Bezug nehmen. Kann man evtl. auch virtuelle VMware-Devices in einer macvtap-Bridge nutzen?

Nutzung von VMware Host-NICs in einer MacVtap-Bridge?

Die Vermutung liegt nahe, dass aus Sicht des Linux-Kernels lediglich relevant ist, dass ein entsprechender “device node” mit zugeordneten Treibern und einem unterstützten Ethernet Stack vorhanden ist. VMware hat hier ganze Arbeit geleistet:

Die virtuellen Host-NICs für die virtuellen VMware Host-Only-Netze erscheinen unter “ifconfig” als vollwertige Ethernet Devices (s.o.). Unter dem Verzeichnis “/dev/” findet man zudem zugehörige Dateien für zeichenorientierte Geräte.

Also: Warum nicht mal ein virtuelles VMware “Ethernet”-Devices in KVM über MacVtap bridgen? Man könnte dann einem KVM-(Linux)-Gast-System eine virtuelle NIC zuordnen, die das Ethernet-Device “vmnet1” über den “macvtap”-Mechanismus nutzt. Wird das virtuelle Device im KVM-Gastsystem danach mit einer IP-Adresse versehen, die zum VMware-Netzwerk-Segment “vmnet1” passt, sollte der KVM-Gast direkt im VMware-Netz erreichbar sein bzw. direkt mit Gästen des VMware-Netzes kommunizieren können.

Konfiguration eines MacVtap-Devices auf einem KVM-Gast mit virt-manager

Um meinem Kali2-Gastsystem in der KVM-Umgebung testweise ein macvtap-Device zuzuordnen benutze ich “virt-manager”. (Ich gehe dabei davon aus, dass der libvirtd-Dämon gestartet wurde, nachdem das virtuelle VMware-Netz angelegt wurde, so dass die “vmnet”-Netzwerk-Devices der KVM-Umgebung mit Sicherheit bekannt sind.)

kvm_ne_3

Mit dem Ergebnis:

kvm_ne_2_800

Nun ggf. das Gastsystem nochmal rebooten. Dann die neue virtuelle NIC im Gastsystem konfigurieren – hier in einem Kali2-System:

kvm_ne_4_800

Danach unter VMware WS ein Gastsystem starten. Hier z.B. ein altes XP-System mit einer IP 192.168.48.3. Dann auf beiden Seiten pingen:

kvm_ne_5

vmware_vne_2

Sieht doch gut aus! Nun auch noch testweise einen nmap-Scan durchführen:

kvm_ne_6

Bestens – Lösungsansatz 1 funktioniert offenbar! Wenn intern auch nicht exakt so, wie im einleitenden Bild dargestellt.

Lösungansatz 2: Der umgekehrte Weg über eine virtuelle Linux-Bridge

Nun wollen wir uns um den umgekehrten Ansatz kümmern. Ein ausgewählter VMware WS-Gast soll irgendwie an eine Linux-Bridge, die von KVM-Gästen bereits über tap-Devices genutzt wird, angebunden werden. Die nachfolgende Abbildung zeigt, wie man sich das in etwa vorstellen kann.

vmware_to_kvm

Im Gegensatz zum entsprechenden Bild für den Lösungsansatz 1 haben wir jetzt die Möglichkeit des Routings über den Host ganz ausgeblendet. Zu beachten ist auch, dass das 192.168.48.0/24-Netz sich jetzt auf der rechten Seite befindet. Der Host selbst erhält in unserem Szenario nicht mal eine eigene, and die Bridge angeschlossene virtuelle NIC.

Die entscheidende Frage ist, ob und wie VMware WS dazu zu bekommen ist, eine Linux-Bridge zu nutzen, die mit “brctl addbr” erzeugt wird. Wer einen genauen Blick auf die ursprüngliche VMware-Netz-Konfiguration meines Testsystems weiter oben wirft, stellt fest, dass VMware offenbar virtuelle Netzwerke mit Zugriff auf eine Linux-Bridge (im Beispiel br0) einrichten kann. Das “br0”-Device ist auf meinem Testsystem eine direkte Linux-Bridge zu einem physikalischen Device. Was aber nichts daran ändert, dass es sich dabei um eine kernel-unterstützte Bridge handelt. Deshalb liegt es nahe, das ganze Spiel mal mit einer Linux-Bridge für ein rein virtuelles Host-Only-Netzwerk zu probieren.

Um Verwerfungen zu vermeiden, fahren wir dazu unseren KVM-Gast runter, entfernen dann das oben eingerichtete MacVtap-Device aus diesem Gast mittels “virt-manager”. Dann wechseln wir als root in den VMware Network Editor und löschen das Netzwerk “vmnet1”. Die entsprechende Host-NIC ist ist danach auch nicht mehr als Character-Device unter Linux vorhanden. In der Konfiguration der VMware-Gäste entfernen wir zur Sicherheit entsprechende Netzwerk-Karten vollständig.

Nun richten wir manuell eine Linux-Bridge namens “virbr_vmw” auf unserem Linux-Host ein:

mytux:/etc/init.d # brctl addbr virbr_vmw
mytux:/etc/init.d # ifconfig virbr_vmw 192.168.48.1 netmask 255.255.255.0 broadcast 192.168.48.255 
maytux:/etc/init.d # wicked show all
...
...
virbr_vmw       device-unconfigured
      link:     #47, state up, mtu 1500
      type:     bridge
      addr:     ipv4 192.168.48.1/24
...

 
Wir wechseln dann erneut zu VMwares “Virtual Network Editor”. Hier fügen wir ein neues Netzwerk hinzu. Und zwar im Modus “Bridged” – hierdurch wird für die VMware-Gäste eine Bridge zum Sharen eines Linux-Devices erzeugt. Wir verwenden für das neue virtuelle Netzwerk den inzwischen wieder freigewordenen Namen “vmnet1”:

vmware_vne_3

Durch eine VMware-Automatik wird das Netzwerk “vmnet1” dabei vorerst der nächsten freien physikalischen Netzwerkschnittstelle – soweit vorhanden – zugeordnet. In meinem Fall ist das das Device “enp9s0”:

vmware_vne_4

Wir können das aber ändern und wählen über die Combobox vielmehr die neu angelegte Linux-Bridge “virbr_vmw” aus :

vmware_vne_5

[Sollte die Linux-Bridge noch nicht in der Auswahl angezeigt werden, müssen die VMware-Dienste ggf. runter gefahren und dann über die entsprechen Skripte (/etc/init.d/vmware restart) neu gestartet werden.]

In den Konfigurationseinstellungen eines geeigneten VMware-Gastes legen wir nun ein Netzwerk-Interface zum virtuellen Netz “vmnet1” an. Wir fahren den Gast (in unserem Testfall ein XP-System) anschließend hoch und konfigurieren dort das neue Device mittels der Konfigurationswerkzeuge des VMware-Gastes (hier eines Windows-Systems). Soweit, so gut. Unsere Bridge kann natürlich von unserem Linux-Host aus angepingt werden. Ist unser VMware-Gast aber auch vom Host aus erreichbar?

kvm_ne_7

Offenbar ja! Aber wir haben insgesamt noch keine permanente, statische Konfiguration sondern nur eine temporäre erzeugt, die beim nächsten Systemboot verloren gehen würde.

Nun machen wir die ganze Sache auf unserem Opensuse-System permanent. Dazu legen als root unter dem Verzeichnis “/etc/sysconfig/network” eine Datei “ifcfg-virbr_vmw” an – mit folgendem Inhalt:

BOOTPROTO='static'
BRIDGE='yes'
BRIDGE_FORWARDDELAY='0'
BRIDGE_PORTS=''
BRIDGE_STP='off'
BROADCAST=''
DHCLIENT_SET_DEFAULT_ROUTE='yes'
ETHTOOL_OPTIONS=''
IPADDR='192.168.48.1/24'
MTU=''
NETWORK=''
PREFIXLEN='24'
REMOTE_IPADDR=''
STARTMODE='auto'
NAME=''

 
Im Gegensatz zu einer evtl. schon vorhandenen Bridge “br0” ordnen wir dem Bridge-Device aber keine physikalische NIC des Hostes (wie etwa “enp9s0”) zu!

Hinweis: Debian- oder Red Hat-Anhänger nutzen entsprechende Konfigurationsdateien ihres Systems, die sich teils in anderen Verzeichnissen befinden, einen anderen Namen haben und eine im Detail abweichende Syntax erfordern.

Nun fahren wir alle evtl. noch laufenden virtuellen Maschinen runter und re-booten danach unseren Host. Nach dem Booten sollte man nach Eingabe des Kommandos “ifconfig” in ein Host-Terminal u.a. Folgendes sehen:

virbr_vmw Link encap:Ethernet  HWaddr EA:93:44:6E:45:55  
          inet addr:192.168.48.1  Bcast:192.168.48.255  Mask:255.255.255.0
          inet6 addr: fe80::e893:44ff:fe6e:4555/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:132 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 b)  TX bytes:21008 (20.5 Kb)

 
Wir fahren unseren VMware-Gast wieder hoch und prüfen, ob ein An-Pingen des Hostes möglich ist.

vmware_vne_6

Wenn nicht, so ist noch etwas an der Konfigurationsdatei falsch. Ggf. mit YaST über die dortigen Module zur Netzwerk-Konfiguration prüfen. Zur Sicherheit auch nochmal die Routen auf dem Host und im VMware-Gast kontrollieren.

Nun wenden wir uns unserem KVM-Gast-System zu. Über die Verwaltungsoberfläche von virt-manager fügen wir der Hardware des Gastes ein neues Device hinzu:

kvm_ne_8

Wir starten danach den KVM-Gast und konfigurieren dort das neue Ethernet-Device mit den Mitteln des Gastsystems (hier mit Kali2/Debian-Einstellungswerkzeugen):

kvm_ne_9

Abschließend testen wir wieder Pings in Richtung Host, VMware-Gast und zurück:

kvm_ne_11

vmware_vne_7

So liebe ich Virtualisierung! Weitere KVM-Gäste benötigen lediglich ein Netzwerk-Interface zur Bridge “virbr_vmw” – und dann stehen auch sie schon in Verbindung zu entsprechend konfigurierten Gästen des VMware-Systems.

Lösungsansatz 3: Einbinden des VMware-Ethernet-Devices in die Linux-Bridge

Lösungsansatz 1 bot eine Möglichkeit zur direkten Anbindung einzelner KVM-Gäste an das VMware Host-Only-Netzwerk. Es stellt sich die Frage: Geht das nicht auch kollektiv?

Dazu müsste man das von VMware bereitgestellte Ethernet-Device in die Linux-Bridge einbinden. Sprich das Host-Interface des VMware-Switches muss Teil der Linux-Bridge werden. Das entspräche einem Kaskadieren von Bridges. Funktioniert das? Bildlich sähe das dann etwa wie folgt aus:

vmw-to_kvm_1

Die erste Frage, die sich einem beim Betrachten stellt, ist: Wie vermeidet man Kollisionen in der Addresszuweisung? DHCP-seitig sollte nach dem Einhängen der des VMware-Devices nur noch genau ein DHCP-Dienst laufen – z.B. der auf der Linux-Seite. Dazu muss beim Einrichten des VMware-Netzwerkes die angebotene DHCP-Funktionalität abgewählt werden.

Der andere Punkt ist der, dass man zumindest mit dem “Virtual Machine Manager” ein Problem bekommt, wenn man ein virtuelles Host-Only-Netzwerk anlegen will, dass das gleiche Segment betrifft, aus dessen Adressbereich anderen virtuellen oder physikalischen Devices bereits IP-Adressen zugewiesen wurden. Also legt man als Erstes am besten die Bridge auf der rechten Seite der obigen Abbildung an. Wir benutzen dazu KVM’s virt-manager:

vmw-to_kvm_2

Das Netzwerk taucht in meinem Fall in Form der virtuellen Bridge “virbr2” auf dem Host auf (mit “brtcl show” prüfbar). Nun ordnen wir einem KVM-Gast noch ein entsprechendes virtuelles Device zu:

vmw-to_kvm_3

Wir können diesen Gast schon mal starten und die Zuordnung zur Bridge prüfen:

mytux:~ # brctl show virbr2
bridge name     bridge id               STP enabled     interfaces
virbr2          8000.005056c00008       yes             virbr2-nic
                                                        vnet4
mytux:~ # 

 
OK, jetzt aber zur VMware-Seite. Ein neues virtuelles Netzwerk ist auch im VNE schnell angelegt:

vmw-to_kvm_4

r
(Hinweis: Das ist nicht mehr das standardmäßige vmnet8 Host-Only-Network, das VMware nach einer anfänglichen Installation automatisch konfiguriert, sondern mein eigenes. Ihr könnt zum Testen natürlich auch das vorkonfigurierte verwenden – oder statt der “8” eine andere Nummer wählen).

Leider ist VMware beim Generieren des gleichnamigen Host-Interfaces gnadenlos und überprüft im Gegensatz zu KVM nicht, ob der Adressraum Überschneidungen aufweist:

mytux:~ # ip address show       
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
...
18: virbr2: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 52:54:00:6b:ab:44 brd ff:ff:ff:ff:ff:ff
    inet 192.168.6.1/24 brd 192.168.6.255 scope global virbr2
       valid_lft forever preferred_lft forever
19: virbr2-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr2 state DOWN group default qlen 500
    link/ether 52:54:00:6b:ab:44 brd ff:ff:ff:ff:ff:ff
20: vmnet8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:50:56:c0:00:08 brd ff:ff:ff:ff:ff:ff
    inet 192.168.6.1/24 brd 192.168.6.255 scope global vmnet8
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:fec0:8/64 scope link 
       valid_lft forever preferred_lft forever
mytux:~ # 

 
So gehts natürlich nicht – wir entfernen die IP-Adresse manuell vom VMware-Interface:

mytux:~ # ip addr del 192.168.6.1/24 broadcast 192.168.6.255 dev vmnet8

 

Nachtrag, 30.01.2016:
Interessanterweise wurde nach einem heutigen Kernelupdate und einer Neukompilation der VMware-Programme der VMware-Dienst “Virtual Ethernet” zur Aktivierung der virtuellen VMware-Netze nicht mehr erfolgreich gestartet, wenn dadurch Überlapps in der IP-Adresse mit irgendeiner gestarteten KVM-Bridge produziert wurden. In einem solchen Fall muss man die VMware Standard-DHCP-Einstellungen für das betroffene virtuelle Netzwerk in der Datei “/etc/vmware/netzwerkname/dhcpd/dhcpd.conf” für das erzeugte Ethernet-Device der Bridge manuell abändern.

Nun kommt ein wichtiger Punkt:

Welche IP ordnen wir dem Interface “vmnet8” statt dessen zu? Erinnern wir uns an Linux-Bridges zu physikalischen Ethernet-Devices (s. etwa: Opensuse – manuelles Anlegen von Bridge to LAN Devices (br0, br1, …) für KVM Hosts):
Dem Ethernet Device (in seiner Funktion als Uplink-Device) darf dort keine IP-Adresse zugeordnet sein! Die richtige Antwort ist auch in diesem Fall: Keine IP-Adresse für das vmnet-Device!

Da wir schon schon auf der Kommandozeile sind, ordnen wir jetzt unserer Bridge “virbr2” das Device “vmnet8” manuell zu:

mytux:~ # brctl addif virbr2 vmnet8
mytux:~ # brctl show virbr2
bridge name     bridge id               STP enabled     interfaces
virbr2          8000.005056c00008       yes             virbr2-nic
                                                        vmnet8
                                                        vnet4
mytux:~ # 

 
Nun statten wir unseren exemplarischen VMware-Gast noch mit einem passenden Interface aus:

vmw-to_kvm_5

Dann fahren wir den VMware-Gast hoch, konfigurieren unsere neue
Netzwerkschnittstelle dort mit den vorhandenen Tools des Gast-Betriebssystems (hier Windows) manuell und probieren, ob wir den Host erreichen können:

vmw-to_kvm_6

Bestens! Nun zu unserem Linux-KVM-Gast:

vmw-to_kvm_7

Alles klar! Lösung 3 funktioniert. Der Leser, der das nachbaut, kann ja selbst weitere Tests durchführen.

Lösung 3 erscheint mir persönlich unter den drei hier besprochenen Ansätzen die strukturell klarste zu sein. Sie hat allerdings den Nachteil, dass man sich selbst darum kümmern muss, dass dem VMware Interface (hier “vmnet8”) auch beim nächsten Systemstart die IP-Adresse entzogen wird. Sobald der VMware-Dienst startet, konfiguriert er “vmnet8” ansonsten nämlich wieder mit einer Adresse. Ich habe bislang keine Möglichkeit gefunden, das über die VMware-Netzwerk-Konfigurations-Tools und zugehörige Konfigurationsdateien unter “/etc/vmware” abzustellen.

Auch die Zuordnung des VMware Devices zur Linux-Bridge sollte man am besten selbst vornehmen, um von der Reihenfolge des Starts der diversen Virtualisierungsdienste etwas unabhängiger zu werden. Für die Abarbeitung entsprechender Kommandos erstellt man sich ein kleines Script, dass man mit ein bisschen Geschick auch als eigenen systemd-Service in den systemd-Startup-Vorgang einbinden kann.

Alternativer Lösungsansatz 4: Nutzung von veth-Device-Paaren für die Bridge-Kopplung

Ein anderer Weg zur Realisierung einer Bridge-Kopplung im Geiste von Lösung 3 besteht darin, die VMware Bridge von vornherein als Bridge zu einem im Linux-System angelegten “veth”-Device zu kreieren. Das zweite Interface des veth-Paars wird dann zur Anbindung an die Linux-Bridge eingesetzt. Ehrlich gesagt, ist das dann die Lösung, die ich für die wirklich beste halte. Ich gehe auf den Einsatz von veth-device-Paaren für ein strukturiertes Bridge-Linking ausführlich in einem kommenden Artikel ein (Fun with veth devices, Linux virtual bridges, KVM, VMware – attach the host and connect bridges via veth).

Performance der vorgestellten Lösungen?

Ein gute Frage! Ohne gezielte Messungen traue ich mich nicht, hierzu Aussagen zu machen. MacVtap bietet z.B. eine leichtgewichtige und auch performante Methode, ein Ethernet-Interface zu nutzen. Die Frage ist allerdings, wie gut das Character-Device, das VMware auf dem Host für ein virtuelles Netz bereitstellt, mit mehreren Kommunikationsströmen zwischen KVM-Gästen und VMware-Gästen, die in Lösung 1 und Lösung 3 gleichzeitig über dieses eine (!) Interface transferiert werden müssen, klarkommt. In Lösung 2 hängt dagegen alles an der unter Linux definierten (und vom Kernel unterstützten) virtuellen Bridge, die gleichzeitig von Gästen aus beiden Virtualisierungs-Umgebungen geteilt wird.

Schwer einzuschätzen …… Bin für Hinweise dankbar. In meinem Mini-Labor für Penetrationstests konnte ich bislang keine signifikanten Unterschiede ausmachen. Werde die Sache aber im Auge behalten …

Security

Standard-Bridges haben aus Security-Sicht einen grundlegenden Nachteil: Sie müssen mindestens über ein angeschlossenes Netzwerk-Interface Pakete für verschiedene IP-Adressen entgegennehmen können. Was bedeutet das eigentlich im Fall unserer zweiten und dritten Lösung für die Sicherheit? Eine sehr gute Frage, die man dann aber auch gleich für die Standardbridge “br0” stellen muss. Hier muss ich den Leser vertrösten. Ich werde mich in kommenden Artikeln mit diesem
Thema etwas intensiver auseinandersetzen. Siehe u.a.:
VMware WS – bridging of Linux bridges and security implications

Für den Augenblick möchte ich allerdings folgende explizite Warnung aussprechen:

Warnung : Das Bridgen einer Bridge – wie in Lösung 2 – ist aus Security-Gesichtspunkten ein gefährliches Spiel. In Pentest-Labors mag so etwas nützlich sein – in Produktivumgebungen sollten beim Admin alle roten Warnleuchten angehen, da die Bridge dann selbst – und nicht nur ein spezielles Uplink-Interface – in den “promiscuous mode” versetzt wird.
 
Eine Abschottung des Datenverkehrs bestimmter Gastsysteme von und mit externen Systemen gegen ein Mithören durch andere Gäste ist dann nicht mehr garantiert – selbst wenn die Linux-Bridge das im Normalfall leisten würde.  
 
Man muss dann sehr genau wissen, was man tut, und ggf. explizit untersuchen, wie die Linux-Bridge auf die Modifikationen durch erneutes Bridging reagiert.

Fazit

Was haben wir erreicht? Die von einer “VMware WS” bereitgestellten virtuellen Devices des Hosts erscheinen unter Linux als vollwertige (zeichen-orientierte) Ethernet-Devices. Sie können von einem KVM-Gast z.B. über die Einrichtung eines individuellen MacVtap-Devices genutzt werden. Nach Konfiguration mit IP-Adressen und passenden Routen wird der KVM-Gast dann für alle praktischen Anwendungen Mitglied des VMware-Netzes.

Umgekehrt und alternativ lässt sich eine virtuelle Linux-Bridge, die mit einer IP-Adresse ausgestattet wurde, unter VMware als direkt gebridgtes Ethernet-Device von mehreren VMware-Gästen nutzen. KVM-Gäste werden an die Linux-Bridge mit Standard-Verfahren angebunden. VMware-Gäste, die über das Bridging der Linux-Bridge an selbige Linux-Bridge angeschlossen wurden, kommunizieren direkt mit allen KVM-Gastsystemen.

Beiden Lösungen 1 und 2 ist gemeinsam, dass sie ein bereits virtualisiertes Devices auf einer Metaebene nochmals in virtualisierter Form nutzen. Das allein macht diese Lösungen – wie ich finde – spannend.

Am elegantesten erscheint im Rückblick jedoch Lösung 3 (bzw. Lösung 4) zu sein. Der VMware-Switch wird dabei einfach und ohne IP-Adresse in die Linux-Bridge integriert. Das Vmware-Hostinterface funktioniert dann wie ein Uplink-Device zum VMware-Switch.

Alle beschriebenen Methoden können im Einzelfall jedoch erhebliche Sicherheitsimplikationen nach sich ziehen. Damit werde ich mich in kommenden Artikeln befassen.

Immerhin:
Durch Aktivierung oder Deaktivierung von entsprechend konfigurierten Ethernet-Devices auf KVM- und VMware-Gästen kann man in allen drei dargestellten Fällen schnell zwischen

  • einer Konfiguration mit einer über den Host gerouteten Verbindung zum VMware-Netz
  • oder einer Konfiguration mit einer direkten Ein-/An-Bindung der Gastsysteme in das jeweils andere Netz ohne Routing

hin- und herschalten.

Das erhöht u.a. die Flexibilität für das Durchspielen verschiedener Penetrationstest-Szenarien in einem virtuellen Test-Labor eines Linux-Hostes beträchtlich. Man kann sich natürlich aber auch etliche Alltags-Szenarien vorstellen, in denen diese Art des Brückenschlags zwischen den Welten nützlich ist. Solange es keine speziellen Sicherheitsanforderungen gibt ….

Viel Spaß nun mit dem Einsatz von Brücken zwischen den Virtualisierungswelten von VMware WS und KVM unter Linux!