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 mit QXL – hohe Auflösungen und virtuelle Monitore im Gastsystem definieren und nutzen – I

Wer KVM/QEMU ohne Spezialkenntnisse nutzen will, setzt hierfür z.B. “virt-manager” ein und vertraut darauf, dass das Gespann libvirt/qemu darunter schon sauber seine Arbeit verrichten wird. Die graphischen Tools von “virt-manager” unterstützen einen zumindest in Grenzen recht gut bei der Einrichtung und Überwachung der Gastsysteme. Das reicht für kleinere, lokale Virtualisierungsvorhaben in der Regel völlig aus; man muss nicht immer gleich zu Profi-Tools für die Verwaltung virtueller Systeme greifen. Für spezielle Gegebenheiten ist allerdings etwas Handarbeit erforderlich – das trifft u.U. auch auf den Einsatz eines oder mehrerer hochauflösender Monitore zu.

Diese Artikelserie geht auf die Frage ein, wie man mittels Tools von libvirt, QEMU, Spice und X-Windows hohe Monitor-Auflösungen auch beim Arbeiten mit virtualisierten Gastsystemen nutzen kann. Dies ist im besonderen dann von Interesse, wenn das Virtualisierungssystem bestimmte physikalische Möglichkeiten (z.B. externer Monitore) am Host oder in einem Remote-System nicht richtig erkennt und die gewünschte Auflösung deshalb über Standardtools der involvierten Desktop-Umgebungen des Gastes und u.U. auch des Hostes nicht angeboten wird.

Als ebenso spannend erweist sich in der Praxis die Frage, wie man denn für Linux-Gäste mehrere virtuelle Monitore auf hochauflösenden physikalischen Displays des Hostes oder eines Remote Systems nutzen kann. “virt-manager” allein bietet hierfür nämlich keine hinreichenden Konfigurationsoptionen an.

Ich setze nachfolgend voraus, dass der Leser sich schon mal mit “virt-manager” befasst hat und auch schon mal ein Linux-Gastsystem auf einem KVM-Host angelegt hat.

Voraussetzungen: Grafischer Zugriff auf das Gstsystem

Ist eine virtuelle Maschine mittels “virt-manager” unter KVM/QEMU erst einmal konfiguriert, so stellt sich die Frage nach dem Zugriff auf den Gast vom Host oder Remote-Systemen [RS] aus. Dabei sollen komplette grafische Oberflächen/Desktops des Gastes auf den physikalischen Monitoren des Hosts/RS dargestellt werden. Das ist natürlich u.a. mit VNC möglich. Speziell für Linux-Hosts und -Gäste wird ein performantes, verzögerungsfreies und auch bequemes Arbeiten vor allem aber durch die Kombination des Spice-Protokolls mit einer grafischen Spice-Konsole (Display Fenster) und mit einer virtuellen Grafikeinheit vom Typ “QXL” im Gastsystem gewährleistet.

Spice ist dabei für die Kommunikation der virtuellen Maschine mit dem Host/RS und darunter liegender HW verantwortlich. Spice ist als Client/Server-Protokoll konzipiert; auf dem Gastsystem verrichten Spice-Server-Komponenten, auf dem Host/RS dagegen Spice-Client-Komponenten ihre Arbeit. Der Grafik-Output des Gastes wird unter Einsatz von Kompressions- und Caching-Verfahren zum Host/RS transferiert und dort in ein Fenster (grafische Spice-Konsole) des Host/RS-Desktops eingeblendet (ähnlich wie bei VNC oder X2GO; allerdings ist Spice wohl nicht für mehrere parallele Verbindungen gedacht). Es gibt zwei Arten von grafischen Konsolen, die mit Spice kooperieren. “virt-manager” selbst bietet den sog. “virt-viewer” an.

“QXL” spielt dagegen den Part eines virtuellen Grafik-Devices im Gastsystem; ich nenne ein solches Device nachfolgend etwas vereinfacht auch eine “virtuelle Grafikkarte”. Für deren effiziente Nutzung benötigt das Gastsystem einen speziellen qxl-Treiber. Der wird meist über X-Server-Pakete der jeweiligen Linux-Distribution bereitgestellt. (Ich behandle in dieser Artikelserie nicht den virtio-Treiber für die Grafik-Einheiten der Gastsysteme.)

Hinsichtlich der Auflösung des Gast-Desktops unter einer Spice-Konsole auf dem Host/RS unterstützt QXL dann im Normalfall eine breite Palette an Werten. Eine entsprechende Liste, die sich weitgehend an den physikalischen Fähigkeiten des
Hosts/RS orientiert, bietet das Gast-System (!) unter Gnome bzw. KDE typischerweise über die jeweiligen Tools für die Screen/Display-Konfiguration an.

Der User kann dann im laufenden Betrieb die für ihn passende Auflösung wählen und umschalten. “virt-manager” erlaubt ergänzend eine Anpassung des “virt-viewer”-Fensters an die Größe des Gast-Desktops. Das hatte ich in dieser Form auch in einem früheren Artikel
KVM, video QXL und video virtio Treiber – Video-Auflösung des Gnome-Desktops eines Debian 8-Gastystems einstellen
erläutert.

Ist das schon die ganze Wahrheit? Leider nein. Es gibt nämlich eine Reihe von Problemen, die man als normaler User von “virt-manager” nicht oder nicht unmittelbar lösen kann:

  • Problem 1: Manchmal erweist sich das unter QXL angebotene Auflösungsspektrum nämlich als begrenzter als die physikalischen Möglichkeiten der Host-Monitore. Offenbar werden vermeintlich erkannte physikalische Einschränkungen des Hosts in einigen Fällen an das Gastsystem durchgereicht.
  • Problem 2: Copy/Paste zwischen Host und Gast funktionieren nicht!
  • Problem 3: Eine automatische Anpassung der Schirmauflösung des Gastsystems an die Größe des Spice-Viewers funktioniert nicht ohne weiteres!
  • Problem 4: Ein Multi-Monitor-Betrieb lässt sich für hohe Auflösungen auch für Linux-Gäste nicht ohne Kunstgriffe bewerkstelligen. Obwohl manche Artikel und Youtube Movies im Internet etwas anders versprechen!

Ich werde in den nachfolgenden Artikeln darstellen, dass und wie man dann u.U. “xrandr” nutzen kann, um die Grenzen des angebotenen Auflösungsspektrums im KVM-Gastsystem (genauer dessen graphischer Desktop) zu überschreiten und die Screen-Auflösung des Gastes an oder über die physikalischen Auflösungsmöglichkeiten der Host-Monitore zu treiben. Wobei ein “über” in der Praxis natürlich nur einen begrenzten Sinn hat.

Zudem werfen wir kurz einen Blick auf die Möglichkeit, den Speicher der virtuellen Video-Einheit zu erhöhen. Es liegt ja auf der Hand, dass hohe Auflösungen auch den Speicherbedarf von virtuellen Grafik-Devices erhöhen werden. Das gilt vor allem für einen Multi-Monitor-Betrieb; hierfür reichen die von virt-manger vergebenen Standardwerte nicht aus. Mittels “spice-vdagent” sorgen wir dann für etwas mehr Komfort. Wir beleuchten danach weitere Voraussetzungen zur Nutzung eines KVM-Gastes mit mehreren virtuellen Monitoren.

Problemmeldung eines Lesers

Wiso nehme ich mich hier überhaupt dieses Themas an? Kurz vor dem letzten Wochenende hat mich ein Leser angeschrieben, der an einem Laptop einen hochauflösenden externen Schirm mit einer Auflösung von 2560×1440 betreibt. Da über Display-Port sogar mit einer Vertikalfrequenz von 60Hz. Leider war es ihm nicht möglich, diese Auflösung auch in debian-basierten, virtualisierten Gastsystemen zu erreichen, die er unter KVM/qemu installiert hatte. Seine Frage war, was man da tun könne.

Ich konnte das Verhalten an einem eigenen Laptop weitgehend nachstellen. Es handelt sich bei meinem Laptop um einen älteren Worthmann Terra mit einer Optimus-Kombination aus Nvidia-Grafikkarte und einer CPU-gebundenen Intel HD4000, wobei letztere auch eine HDMI-Schnittstelle versorgt. Leider sind die Fähigkeiten der HD4000/HDMI-Kombination limitiert (auch durch den Hersteller). Das Board versorgt den HDMI-Bus nur mit einer Maximalfrequenz von 225 MHz. Das reicht leider nicht, um Auflösungen jenseits von 2048×1152 bei einer Vertikalfrequenz von 60Hz zu versorgen. Möglich sind aber 2048×1152 bei 60Hz und 2560×1440 bei einer Frequenz von 40 oder 44 Hz. Damit konnte ich das
Problem des Lesers auf meinem Laptop aber nachstellen. Der Laptop wurde dazu als KVM-Host unter Opensuse Leap 42.2 mit KDE-Desktop betrieben:

Die maximale Auflösung, die mir debian-basierte KVM-Gastsysteme (Kali2017 mit Kernel 4.9, Debian 8 mit Kernel 3.16) auf diesem KVM-Host anboten, betrug unter “spice” und “qxl” 1920×1080 Pixel. Das entsprach gerade der Auflösung des integrierten Laptop-Schirms!

Die physikalisch möglichen Auflösungen des externen Monitors von 2048x1152_60.00Hz bzw. 2560x1440_44.00Hz unter HDMI wurden dagegen völlig ignoriert! Warum auch immer … Tja, was kann man in einem solchen Fall tun?

Einsatz von xrandr und CVT auf dem Host als Ausgangspunkt …

Es ist instruktiv, sich zunächst anzusehen, wie ich den Laptop dazu brachte, 2560x1440__44.00Hz auf dem HDMI-Monitor zu unterstützen. KDE’s Tool “systemsettings5 > Anzeige und Monitor” bot mir diese Auflösung für den Desktop des Hosts nämlich keineswegs an; ich nehme an, dass die Ursache dafür auch im Intel i915-Treiber zu suchen ist:

Unter Linux steht (berechtigten Usern) das Werkzeug “xrandr” zur Verfügung, um Auflösungen für verschiedene Monitore zu konfigurieren. xrandr nutzt dazu die RandR-Erweiterung des X-Window-Systems. Siehe die unten angegebenen Links für weitere Infos. Verschiedene Desktops (Gnome, KDE, LXDE) nutzen “xrandr” über eigene integrierte grafische Tools. “xrandr” lässt sich als Kommando jedoch auch direkt an einem Shell-Prompt absetzen; ein Blick in die man-Seiten lohnt sich.

Gibt man etwa xrandr ohne Parameter am Prompt eines Terminalfensters ein, so erhält man Informationen zu den aktuell erkannten Monitoren und deren Auflösung. In meinem Fall etwa:

myself@mytux:~> xrandr
Screen 0: minimum 8 x 8, current 3968 x 1152, maximum 32767 x 32767
LVDS1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 382mm x 215mm
   1920x1080     60.02*+
   1400x1050     59.98  
   1600x900      60.00  
   1280x1024     60.02  
   1280x960      60.00  
   1368x768      60.00  
   1280x720      60.00  
   1024x768      60.00  
   1024x576      60.00  
   960x540       60.00  
   800x600       60.32    56.25  
   864x486       60.00  
   640x480       59.94  
   720x405       60.00  
   640x360       60.00  
DP1 disconnected (normal left inverted right x axis y axis)
HDMI1 connected 2048x1152+1920+0 (normal left inverted right x axis y axis) 553mm x 311mm
   2048x1152_60.00  59.90  
   2048x1152     60.00* 
   1920x1200     59.95  
   1920x1080     60.00    60.00    50.00    59.94    30.00    25.00    24.00    29.97    23.98  
   1920x1080i    60.00    50.00    59.94  
   1600x1200     60.00  
   1680x1050     59.88  
   1280x1024     75.02    60.02  
   1200x960      59.99  
   1152x864      75.00  
   1280x720      60.00    50.00    59.94  
   1024x768      75.03    60.00  
   800x600       75.00    60.32  
   720x576       50.00  
   720x576i      50.00  
   720x480       60.00    59.94  
   720x480i      60.00    59.94  
   640x480       75.00    60.00    59.94  
   720x400       70.08  
VGA1 disconnected (normal left inverted right x axis y axis)
VIRTUAL1 disconnected (normal left inverted right x axis y axis)

 
Man erkennt, dass für den HDMI1-Monitor als Maximal-Mode 2048×1440 bei 60Hz gelistet ist. Natürlich kann der tatsächlich angeschlossene Dell U2515H aber mehr.

Einsatz von xrandr

Wirft man einen Blick in die man-Seiten zu xrandr, entdeckt man, dass xrandr einem Monitor Video-“Modes” zuordnen kann. Dazu benötigt man aber bestimmte Daten einer sog. “Modline”. Wie erhält man nun eine gültige Modline für neue, vom System nicht erkannte Auflösungen? Unter Linux hilft hier das Tool “CVT”. Es berechnet für gewünschte Auflösungen/Frequenzen die notwendigen Daten. Damit kann man ein wenig rumspielen – Bsp.:

myself@mytux:~> cvt 2560 1440 40
# 2560x1440 39.96 Hz (CVT) hsync: 58.98 kHz; pclk: 201.00 MHz                                                          
Modeline "2560x1440_40.00"  201.00  2560 2720 2984 3408  1440 1443 1448 1476 -hsync +vsync                             

myself@mytux:~> 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      

myself@mytux:~> cvt 2560 1440 50
# 2560x1440 49.96 Hz (CVT 3.69M9) hsync: 74.15 kHz; pclk: 256.25 MHz                                                   
Modeline "2560x1440_50.00"  256.25  2560 2736 3008 3456  1440 1443 1448 1484 -hsync +vsync                             

 
Die erste Zahl nach dem Auflösungsstring gibt jeweils die Taktrate/Frequenz an, mit der die Pixel angesteuert werden (PixelClock). Die nimmt mit Auflösung und Vertikal-Frequenz natürlich zu. In meinem Fall muss sie – wie gesagt – unter 225MHz liegen.

Folgende Sequenz an Befehlen erfasst nun eine neue Mode und ordnet diese dem HDMI1-Monitor zu (ggf. als User root absetzen).

mytux:~ # xrandr --newmode 2560x1440_44 222.75  2560 2720 2992 3424  1440 1443 1448 1479 -hsync +vsync
mytux:~ # xrandr --addmode HDMI1 2560x1440_44
mytux:~ # xrandr --output HDMI1 --mode "2560x1440_44"

Danach bietet mir KDE’s “systemsettings5” diese Auflösung bereits an:

Dort kann man die Auflösung auch aktivieren. Wer für die Aktivierung jedoch die Kommandozeile vorzieht, kann auch den Befehl

mytux:~ # xrandr --output HDMI1 --mode "2560x1440_44"

absetzen. Und schon läuft der externe Schirm mit höherer Auflösung :

myself@mytux:~> xrandr --current
Screen 0: minimum 8 x 8, current 4480 x 1440, maximum 32767 x 32767
LVDS1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 382mm x 215mm
   1920x1080     60.02*+
   ....
   .... 
DP1 disconnected (normal left inverted right x axis y axis)
HDMI1 connected 2560x1440+1920+0 (normal left inverted right x axis y axis) 553mm x 311mm
   2560x1440     43.99 +
   2048x1152_60.00  59.90  
   2048x1152     60.00  
   1920x1200     59.95  
   1920x1080     60.00    60.00    50.00    59.94    30.00    25.00    24.00    29.97    23.98  
   1920x1080i    60.00    50.00    59.94  
   1600x1200     60.00  
   1680x1050     59.88  
   1280x1024     75.02    60.02  
   1200x960      59.99  
   1152x864      75.00  
   1280x720      60.00    50.00    59.94  
   1024x768      75.03    60.00  
   800x600       75.00    60.32  
   720x576       50.00  
   720x576i      50.00  
   720x480       60.00    59.94  
   720x480i      60.00    59.94  
   640x480       75.00    60.00    59.94  
   720x400       70.08  
   2560x1440_44  43.99* 
VGA1 disconnected (normal left inverted right x axis y axis)
VIRTUAL1 disconnected (normal left inverted right x axis y axis)

 

Um eine Persistenz dieser Auflösungsvorgaben über einen Shutdown und Reboot hinaus zu erreichen, trägt man die gefundene Modline dann in eine Datei “/etc/X11/xorg.conf.d/10-monitor.conf” ein. Dies ist u.a. unter https://wiki.archlinux.org/ index.php/ xrandr beschrieben. Alternativ kann man eine Batchdatei anlegen und diese beim Start des Desktops automatisch ausführen lassen. Eine weitere Möglichkeit ist unter https://wiki.ubuntuusers.de/RandR/ beschrieben. Ich komme darauf in einem Folgeartikel detaillierter zurück; dort aber bei der Anwendung von “xrandr” im KVM-Gastsystem.

Funktioniert xrandr auch innerhalb von KVM/QEMU-Gastsystemen?

Für Neugierige, die schon mal experimentieren wollen: Ja, das geht! Zumindest mit QXL! Ist dabei die Vertikalfrequenz relevant? So, wie ich das verstehe, nicht. Die Video-Information wird ja per Spice in den Speicher der physikalischen Grafikkarte eingeblendet. Dafür sollte nur die Fenster- und Pixel-Info relevant sein. Aber es schadet nicht, sich an vernünftige Limits (60Hz) zu halten.

Es gibt allerdings andere Beschränkungen für ein performantes Verhalten hochauflösender Videomodes. Genauso wie physikalische Karten muss auch die virtuelle Video-Einheit mit hinreichendem Speicher für hohe Auflösungen versorgt werden!

Und Leute, die sich mit VMware auskennen, wissen auch, dass im Gastsystem Zusatzprogramme aktiviert werden müssen – u.a. um Copy/Paste zwischen Host und Gast zu ermöglichen oder eine dynamische Anpassung der Gast-Auflösung an die Fenstergröße zu ereichen. Man vermutet nicht ganz zu Unrecht, das es etwas Korrespondierendes wohl auch unter KVM/qemu geben sollte.

Bevor wir auf dem Client xrandr testen, kümmern wir uns deshalb zunächst um drei wichtige Aspekte der Gast-Ausstattung für Spice/QXL – Vorgaben für den Video-Speicher des QXL-Devices, die Bereitstellung eines Treibers und des sog. “spice-vdagent”. Als erstes müssen wir Spice und QXL überhaupt erstmal für unsere Virtuelle Maschine unter QEMU bereitstellen und aktivieren.

Spice und QXL aktivieren

Spice und QXL lassen sich bereits bei der Konfiguration eines Gastsystems über die entsprechende Oberfläche von “virt-manager” einstellen. Die Video-Konfiguration lässt sich dort aber auch im Nachhinein beeinflussen. Man entfernt dazu die alten Video-HW-Komponenten und ersetzt sie durch folgende:

Man sieht am letzten Fenster bereits, dass die Parameter für die QXL-Karte unter “virt-manager” leider nicht beeinflussbar sind!

Parameter für das Video Memory des QXL-Devices

Hohe 2D-Auflösungen bis 4K (4096 × 2160) erfordern als Minimum 32MiB Speicherkapazität für einen Schirm. Für flüssiges Arbeiten und die dafür notwendige Pufferung von Bildschirminhalten etc. aber deutlich mehr (64MB). Ich rede hier lediglich über 2D-Operationen. Die Standardeinstellung der qxl-Karte ist (zumindest unter Opensuse) für Framebuffer-Memory lediglich 16MB. Das reicht für 2560x1440x32 gerade so. Es schadet aber nichts, für noch höhere Auflösungen, mit denen man ggf. arbeiten will, mehr Video-RAM zu Verfügung zu stellen. Wie macht man das?

Leider gibt es keine Möglichkeit, das direkt mit “virt-manager” (Vers. 1.4) zu erledigen. Man ist vielmehr gezwungen, die unter libvirt erzeugten XML-
Dateien, die die Konfiguration virtueller Maschinen beschreiben, zu editieren. Unter “libvirt” spricht man auch von der Konfigurationsdatei einer virtuellen “Domäne”.

Das Editieren der XML-Domän-Dateien kann man entweder mit “virsh edit” oder aber durch direkten Zugriff mit seinem Lieblingseditor auf die Konfigurationsdateien durchführen. In letzterem Fall muss man selbst dafür sorgen, dass die XML-Struktur in Takt bleibt und alle Tags sauber abgeschlossen werden.

Man findet die Konfigurationsdateien unter “/etc/libvirt/qemu” in der Form NAME.xml”. NAME steht hier für eine – z.B. über virt-manager angelegte – Virtualisierungs-“Domäne” (s. hierzu die Einleitung in https://libvirt.org/ formatdomain.html# elements .

Für virtuelle qxl-basierte Video-Einheiten gibt es z.Z. mehrere Konfigurationsparameter: ram, vram, vram64, vgamem. Zusätzlich wichtig ist der Parameter “heads”. Der besagt, wieviele virtuelle Monitore angeschlossen werden sollen und kann max. den Wert “4” annehmen. Dieser Wert wird nur in Linux-Gast-Systeme berücksichtigt. (Virtueller Multi-Monitor-Betrieb von Windows-Gastsystemen erfordert mehrere QXL-Einheiten).

Ein typischer Standard-Eintrag für ein QXL-Device hat etwa folgende Form:

    <video>
      <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/>
    </video>

 
Bzgl. der Anzahl, der Bezeichnung und Bedeutung der QXL-Paramter hat sich in den letzten Jahren einiges in schnellem Rhythmus verändert. Ich kann daher nur versuchen, mein aktuelles Verständnis davon wiederzugeben; es beruht auf nachfolgend genannten Artikeln im Internet und eigenen Tests.
Siehe hierzu etwa https://libvirt.org/ formatdomain.html# elementsVideo, siehe aber auch http://www.ovirt.org/documentation/ draft/video-ram/.

Die Angaben unter den beiden Links sind – soweit ich das sehe – nicht ganz kompatibel. Was sagen eigene Tests?

  • KiB: Die Werte zu diesen Parametern werden in der Konfigurationsdatei in “KiB” angegeben. 512MiB entsprechen daher 524288 KiB und ‘536870912’ Byte, 64MiB = 67108864 Byte. Das ist deshalb interessant, weil diese Werte vom System in anderen Kontexten durchaus in unterschiedlichen Einheiten angegeben werden.
  • Standardwerte: ram=’65536′, vram=’65536′, vram64=’0′, vgamem=’16384′, ‘heads=1’.
  • heads:Steht für die Anzahl der Ausgänge der virtuellen qxl-Grafikkarte, d.h. für die Anzahl der virtuellen Monitore, die man in einem Linux-Gastsystem über dasselbe Video-Device bedienen will. Ja, es ist durchaus möglich, ein Gastsystem mit mehreren virtuellen Monitoren auszustatten; s. hierzu eine der kommenden Artikel dieser Serie. Der Maximalwert für “heads” ist z.Z. offenbar 4. [“heads” mit einem Wert > 1 zu versehen, ist übrigens nur für Linux-Gastsysteme sinnvoll. Für Windows-Gastsysteme müssen mehrere Grafik-Devices für virtuelle Multi-Monitor-Konfigurationen angelegt werden.]
  • vgamem:Minimalwert (entspricht gleichzeit der Framebuffergröße) – dieser Minimalwert muss den Wert der Auflösung x Farbtiefe abdecken. Der Framebuffer-Modus dient auch als Fallback-Modus – etwa, wenn der QXL-Treiber im Gastystem nicht installiert ist. Da 32Bit Farbtiefe 4 Bytes entsprechen, ist die Auflösung Höhe x Breite in Pixel mit einem Faktor 4 zu multiplizieren. Im Falle von Linux-Gastystemen ist als
    Faktor noch die Anzahl der Schirme (=Heads) zu berücksichtigen.
  • ram: Tests zeigen, dass der Parameter offenbar einen limitierten Memory-Bereich wiedergibt (für einen sog. virtuellen Memory-Bar 1; entspricht einem PCI Memory Bar-Bereich). Für diesen primären Memory-“Bar” erhält man nie effektiv wirksame Video-Ram-Werte > 512MiB – auch wenn man etwa ram=’1073741824′ festlegt. Das liegt offenbar an einer 32-Bit Adressierung. Dieser Speicher steht als sog. “IO Pages Memory” zur Verfügung. Er sollte (Pufferung!) mehr als das 4-fache des vgamem-Wertes betragen.
  • vram:Tests zeigen, dass dieser Parameter offenbar einen weiteren mit 32Bit addressierten Memory-Bereich wiedergibt (Adress-Bar 2; entspricht einem PCI Memory Bar-Bereich). Auch für diesen sekundären Memory-“Bar” erhält man daher nie effektiv wirksame Video-Ram-Werte > 512MiB. Der Speicherbereich steht als sog. Surface-Memory der virtuellen Graka zur Verfügung. Er sollte mindestens so groß sein, wie das Doppelte des vgamem-Wertes.
    Dieser Memory-bereich kann bei Bedarf neben Texturen wohl auch IO-Page-Daten aufnehmen.
  • vram64:Alternative zu vram! Tests zeigen, dass dieser Parameter offenbar einen mit 64Bit adressierten Memory-Bereich wiedergibt (Adress-Bar 2). Der Parameter überschreibt vram; d.h. wenn angegeben, gilt vram64 und vram wird ignoriert. Der zweite Memory-Bar kann unter vram64 somit sehr viele größere Speicherwerte adressieren als unter vram. vram64-Angaben sind daher vor allem interessant, wenn man mit wirklich großen Auflösungen (4K und größer) und mehreren virtuellen Schirmen arbeiten will.

Man kann sich das QXL-Device – also die virtuelle Grafikkarte – etwa wie folgt vorstellen:

Für Linux-Gastsysteme gelten dabei folgende Formeln :

Formeln zur Berechnung des QXL Video RAMs

vgamem >= Breite x Höhe x 4 x Anzahl Heads
ram >= 4 x vgamem (maximal 524288 KiB)
vram >= 2 x vgamem (maximal 524288 KiB)
Hohe Auflösungen : vram64 > 4 x vgamem (beliebig ≤ 2×10^12)

Was bedeutet das in unserem Fall für die Auflösung 2560 x 1440 ?

vgamem >= 2560 x 1440 x 4 x Anzahl Heads
Plant man also mit 4 virtuellen Monitoren zu arbeiten:
vgamem ≥ 14400 x 4; wir runden das auf: 16384 x 4 = 65536 (= 64 MiB)
ram ≥ 262144 (248 MiB)
vram ≥ 131072 (128 MiB)

Rücksichtnahme auf den verfügbaren RAM des Hosts!

Natürlich kann es für Experimente auch mit nur einem virtuellen Monitor sinnvoll sein, bei hohen Auflösungen bzgl. der Video-Speicher-Größe auf die sichere Seite zu gehen. Es gilt aber:

Der insgesamt bereitgestellte Video RAM addiert sich zum festgelegten RAM der virtuellen Maschine dazu; d.h. er wird zusätzlich vom verfügbaren RAM des Hosts für KVM-Gastsysteme abgezweigt.

Das ist dann wichtig, wenn der RAM des Hostes begrenzt ist. In meinem Fall (16G RAM auf dem Laptop, 64G auf Desktops) ist das bei einer oder zwei virtuellen Maschinen nicht so relevant. Aber wenn der Speicher begrenzter ist und/oder mehr virtuelle Maschinen laufen sollen, lohnt es sich schon, den Video RAM auf das Notwendige einzuschränken. Für die Gesamtperformance des Systems kann mehr RAM durchaus viel wichtiger sein als ein zu groß gewählter Video RAM !

Abändern der Parameter in den Domän-Dateien von libvirt

Man kann meines Wissens z.Z. noch keine Einstellungen von Parametern für virtuelle QXL-Devices mittels “virt-manager” vornehmen. Davon lassen wir uns aber nicht abschrecken. Was immer man beim Aufsetzen einer virtuellen Maschine unter KVM/qemu mittels des Tools “virt-manager” vornimmt, landet ja in einer entsprechenden XML-Konfigurationsdatei unter dem Verzeichnis “/etc/libvirt/qemu”. In der dortigen XML-Datei muss man die Zeilen mit <video> suchen und abändern. Valide Einträge, die man mit dem Lieblingseditor seiner Wahl vornimmt, sind in unserem Fall (heads=4) etwa :

    <video>
      <model type='qxl' ram='262144' vram='262144' vgamem='65536' heads='4' primary='yes'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>

Getestet habe ich in den nachfolgenden Artikeln mit den eben genannten Werten.

Mit Maximalwerten für ram, vram sähe das Ganze dagegen so aus:

    <video>
      <model type='qxl' ram='524288' vram='524288' vgamem='65536' heads='4' primary='yes'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>

Testweise kann man sich ja aber auch mal ansehen, was bei folgenden Einstellungen passiert:

    <video>
      <model type='qxl' ram='262144' vram64='2097152' vgamem='65536' heads='4' primary='yes'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    
    <video>
      <model type='qxl' ram='1048576' vram='1048576' vgamem='65536' heads='4' primary='yes'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>

 

Wichtiger Nachtrag 15.08.2017:

Ich musste gerade feststellen, dass es mit dem theoretischen Maximalwert für ram in Abhängigkeit vom RAM der virtuellen Maschine (“memory”) ein Problem gibt. In einer der Debian-Gastsysteme versuchte ich zwischenzeitlich, den normalen RAM von 2048 MB auf 4096 MB zu erhöhen. vram war auf “524288” gesetzt. Daraufhin blieb der Bildschirm des Gastes beim Starten leider schwarz.

Lösung:

Nach etwas Recherche habe ich dann eine Bugmeldung für Virtual-Box zu einem ähnlichen Fehler gefunden; dort half eine Reduktion des Video Rams. Also habe ich das mal unter QEMU ausprobiert und bin bzgl. QXL zurück auf ram=’262144′. Dann klappt alles auch mit einem Memory der VM ≥ 4096 MB.

Eine Wert vram=’524288′ oder vram64=’2097152′ bereitet dagegen keine Probleme. Dieser Wert ist auch groß genug für die meisten sinnvollen Anwendungen.

Mir ist im Moment nicht klar, warum dieses Problem auftritt. Der geneigte Leser sei hiermit aber vorgewarnt.

Wichtiger Hinweis: Restart des libvirtd.service vornehmen oder “virsh define” ausführen, um die Änderungen an den Domän-Dateien unter virt-manager bekannt zu machen.

Wenn ich solche Eingriffe in einer Domän-XML-Datei vornehme fahre ich die betroffene virtuelle Maschine vorher zur Sicherheit runter. (Den Zustand aller anderen laufenden Gastsysteme kann man zwischenzeitlich dagegen auf die Festplatte speichern und die zugehörigen virtuellen Maschinen selbst pausieren lassen. Siehe hierzu die entsprechende Option “Save” unter virt-manager”). Nach der Durchführung der
Änderungen an der XML-Definitionsdatei zu einer einzelnen virtuellen Maschine ( bzw. “Domäne”) müssen die neuen Einstellungen dem laufenden libvirtd-Dämon oder zugehörigen administrativen Programmen bekannt gemacht werden. Dafür gibt es zwei Möglichkeiten:/p>

Möglichkeit 1: Restart des libvirtd-Dämons und ein neues Connecten zum Dämon unter “virt-manager”. Vorab sollte der Zustand aller laufenden virtuellen Maschinen ge-“saved” werden. Danach als user “root” das Kommando
systemctl restart libvirtd.service
absetzen! Dann sich unter virt-manager wieder mit dem Dämon verbinden und die geänderte Maschine neu hochfahren sowie die suspendierten anderen Systeme erneut starten.

Möglichkeit 2: Nutzen von “virsh” für eine Re-Definition der geänderten libvirt-“Domäne”:

$ virsh --connect qemu:///system
Connecting to uri: qemu:///system
Welcome to virsh, the virtualization interactive terminal.

Type:  'help' for help with commands
       'quit' to quit

virsh # define /etc/libvirt/qemu/NAME_der_geanderten_VM.xml

Siehe zur 2-ten Möglichkeit auch: https://help.ubuntu.com/ community/KVM/ Managing.

Überprüfung des angeforderten und des tatsächlich bereitgestellten Video-Speichers

Wie prüfe ich, wie die Daten der XML-Datei beim erneuten Start des Gastsystems umgesetzt werden? Dazu kann man sich zunächst mal den Befehl ansehen, der zum Start der virtuellen Maschine faktisch abgesetzt wurde:

ps aux | grep qemu | grep mem

Im Output finden sich dann Abschnitte wie

    -chardev spicevmc,id=charchannel0,name=vdagent 
    -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=com.redhat.spice.0 
    -spice port=5900,addr=127.0.0.1,disable-ticketing,image-compression=off,seamless-migration=on 
    -device qxl-vga,id=video0,ram_size=268435456,vram_size=268435456,vram64_size_mb=0,vgamem_mb=64,max_outputs=4,bus=pci.0,addr=0x2

 

Man erkennt hier unschwer die Umsetzung der Speicheranforderungen. Komischerweise in unterschiedlichen Einheiten (ram_size und vram_size in Bytes und vgamem_mb bzw. vram64_size in MiB! Das soll uns aber nicht weiter stören ….

Im Gastsystem selbst hilft nach dem Start meist ein Absetzen des Kommandos “dmesg | grep drm”.

root@kali2017-1:~# dmesg | grep drm
[    1.668901] [drm] Initialized
[    1.828524] [drm] Device Version 0.0
[    1.828529] [drm] Compression level 0 log level 0
[    1.828530] [drm] Currently using mode #0, list at 0x488
[    1.828530] [drm] 114686 io pages at offset 0x4000000
[    1.828531] [drm] 67108864 byte draw area at offset 0x0
[    1.828531] [drm] RAM header offset: 0x1fffe000
[    1.828532] [drm] rom modes offset 0x488 for 142 modes
[    1.832481] [drm] qxl: 64M of VRAM memory size
[    1.832481] [drm] qxl: 511M of IO pages memory ready (VRAM domain)
[    1.832482] [drm] qxl: 2048M of Surface memory size
[    1.836647] [drm] main mem slot 1 [a0000000,1fffe000]
[    1.836648] [drm] surface mem slot 2 [100000000,80000000]
[    1.836649] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
[    1.836649] [drm] No driver support for vblank timestamp query.
[    1.837401] [drm] fb mappable at 0xA0000000, size 3145728
[    1.837402] [drm] fb: depth 24, pitch 4096, width 1024, height 768
[    1.838735] fbcon: qxldrmfb (fb0) is primary device
[    1.865428] qxl 0000:00:02.0: fb0: qxldrmfb frame buffer device
[    1.889589] [drm] Initialized 
qxl 0.1.0 20120117 for 0000:00:02.0 on minor 0
[    1.927986] [drm] Device Version 1.0
[    1.927987] [drm] Compression level 0 log level 0
[    1.927988] [drm] Currently using mode #0, list at 0x488
[    1.927989] [drm] 12286 io pages at offset 0x1000000
[    1.927989] [drm] 16777216 byte draw area at offset 0x0
[    1.927990] [drm] RAM header offset: 0x3ffe000
[    1.927990] [drm] rom modes offset 0x488 for 128 modes
[    1.927996] [drm] qxl: 16M of VRAM memory size
[    1.927997] [drm] qxl: 63M of IO pages memory ready (VRAM domain)
[    1.927997] [drm] qxl: 64M of Surface memory size
[    1.932065] [drm] main mem slot 1 [e0000000,3ffe000]
[    1.932067] [drm] surface mem slot 2 [e4000000,4000000]
[    1.932068] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
[    1.932068] [drm] No driver support for vblank timestamp query.
[    1.933351] [drm] fb mappable at 0xE0000000, size 3145728
[    1.933352] [drm] fb: depth 24, pitch 4096, width 1024, height 768
[    1.933890] qxl 0000:00:0a.0: fb1: qxldrmfb frame buffer device
[    1.933894] [drm] Initialized qxl 0.1.0 20120117 for 0000:00:0a.0 on minor 1
root@kali2017-1:~# 

 
Der aufmerksame Leser hat sicher mitbekommen, dass ich im letzten Beispiel eine virtuelle Maschine mit 2 QXL-Devices dargestellt habe. Das erste QXL-Device hat dabei Werte von ram=’524288′ vram64=’2097152′ vgamem=’65536′ zugeteilt bekommen.

Wenn der Ringpuffer des dmesg-Befehl das obige Ergebnis nicht liefert (kann nach einer Weile im laufenden Betrieb des Gastsystems passieren), der kann sich z.B. das Paket “hwinfo” installieren, damit alle HW-Einstellungen auslesen und dann im Output nach “graphics” suchen (oder die Ergebnisse von vornherein auf Zeilen mit “video” und “Graphic” einschränken.)

Genug für heute! Im Nachfolgeartikel

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

laden wir den qxl-Treiber im Gastsdystem nach, starten zudem auch den spice-vdagent und wenden schließlich “xrandr” im Gastsystem an.

Links

virt-manager
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Virtualization_Deployment_and_Administration_Guide/sect-Creating_guests_with_virt_manager.html
https://wiki.ubuntuusers.de/virt-manager
https://www.thomas-krenn.com/de/wiki/Virtual_Machine_Manager_-_GUI_zur_Verwaltung_virtueller_Maschinen
https://wiki.libvirt.org/page/CreatingNewVM_in_VirtualMachineManager

Video und Video-RAM
https://www.x.org/wiki/Development/Documentation/HowVideoCardsWork/
http://www.ovirt.org/documentation/draft/video-ram/
http://bart.vanhauwaert.org/hints/installing-win10-on-KVM.html
https://wiki.archlinux.org/index.php/QEMU#qxl
https://lists.freedesktop.org/archives/spice-devel/2015-June/020459.html
https://askubuntu.com/questions/46197/how-to-check-video-memory-size

xrandr
https://wiki.archlinux.org/index.php/xrandr
https://wiki.gentoo.org/wiki/Xrandr
https://pkg-xorg.alioth.debian.org/howto/use-xrandr.html
https://bbs.archlinux.org/viewtopic.php?id=199100
https://unix.stackexchange.com/questions/227876/how-to-set-custom-resolution-using-xrandr-when-the-resolution-is-not-available-i
https://wiki.ubuntuusers.de/RandR/
https://axebase.net/blog/2011/07/27/hinzufuegen-einer-aufloesung-ueber-cvt-und-xrandr/

CVT
http://www.uruk.org/projects/cvt/

PHP und Apache Rewrite von Web-Requests – Ausschluss von Dateien des Typs CSS, JPG, etc. ?

Gestern bin ich in eine klassische Falle im Zusammenhang mit Apache Rewrites gestolpert.

Für ein CMS-Projekt hatte ich in einer “.htacces”-Datei eines Apache-Servers Rewrite-Direktiven für externe HTTP-Requests nach HTML-Dateien hinterlegt. Das CMS arbeitet intern ausschließlich mit PHP-Dateien und Parametern zur Erzeugung von Webseiten. Nach außen hin werden aber reguläre Adressen von HTML-Dateien angeboten. Angeforderte HTML-Seiten müssen daher auf dem Server auf bestimmte Generatorprogramme und zugehörige GET/POST-Parameter abgebildet werden.

Rewriting ist für solche Anforderungen eine Standardlösung (siehe etwa auch das Vorgehen von WordPress):

Der Request wird an eine zentrale PHP-Datei weitergereicht. Diese zerlegt den URL-String der angeforderten HTML-Datei; über Datenbank-Informationen werden dann Parameter für Webseitengeneratoren (PHP-Programme) ermittelt. Die zentrale Datei gibt danach die Kontrolle an die Generatoren ab. Die notwendige Datenbankinformation wird vom CMS bereits während der Anlage und Konfiguration der Webseiten durch den User erzeugt.

Im meinem Fall war ich bzgl. der Rewrite-Anweisung allerdings ein wenig bequem:

Alle (!) Abfragen zu nicht existierenden Dateien wurden zur Behandlung an eine zentrale PHP-Datei “pager.php5” meines CMS verwiesen.

Das funktionierte auch wunderbar – solange nur HTML-Dateien abgefragt wurden, zu denen die Website Links anbot und die im CMS auch mal angelegt worden waren. Traten bzgl. solcher Anfragen Fehler auf oder lies sich aus der Datenbank keine adäquate Info zur angeforderten HTML-Seite ermitteln, wich das PHP-Programm “pager.php5” kontrolliert auf Fehlerroutinen aus.

Nun sah ich bei der Überprüfung des Netzwerkverkehrs bei bestimmten Seiten allerdings, dass es gleich zig-fach zu einem wiederholten Abrufversuch für eine Datei “err_page.php5” in einem bestimmten Bild-Verzeichnis kam; diese PHP-Fehler-Datei existierte dort jedoch gar nicht und war dort auch nie vorgesehen.

Ursachenanalyse

Tatsächlich rufe ich solche PHP-Files zur Behandlung bestimmter Fehler auf, die im CMS im Zuge der Seitengenerierung entstehen können. Allerdings nicht in einem Bildverzeichnis ….

Nach einer Weile fand ich heraus, dass das Problem dennoch durch eine angeforderte, aber auf dem Test-Server nicht vorhandene Bilddatei ausgelöst wurde.

Das war keineswegs so einfach zu erkennen, wie man vielleicht meinen möchte – bei nicht vorhandener Datei übernimmt ja ordnungsgemäß “pager.php5” die Kontrolle – und somit erscheint im Browser nicht zwingend eine Warnung. Eine Warnung auf HTTP-Ebene würde im Einzelfall ja das gezielte Absetzen einer HTTP-Protokoll-Meldung im Verlauf der Situationsbehandlung erfordern. So schlau war ich bei der Konzeption aber nicht gewesen.

Ich dachte deshalb zunächst an einen Fehler in einer PHP-Routine zur automatischen Bildskalierung auf vom CMS-User vorgegebene Größen. Ein Fehler bzw. eine Fehlerbehandlung für nicht existierende Bilddateien in der festgestellten Form lag dort aber nicht vor.

Weitere Tests und ein genauerer Blick in den HTTP-Verkehr zeigten schließlich, dass der “Referrer” der fehlerhaften Datei-Anforderung eine CSS-Datei war! Selbige CSS-Datei existierte und wurde auch ordnungsgemäß gefunden.

Was war das eigentliche Problem?

In der CSS-Datei gab es eine Anweisung der Art

background-image:url(Pfad-zum-(fehlenden)-Bild);

für ein Hintergrundsbild – leider für eines, das auf dem Server nicht existierte.

Der entsprechende Abruf führte dann in Kombination mit der Rewrite-Anweisung zu einer Reaktion nach dem Muster

  • Abruf nicht existierende Datei aus CSS-Anweisung
  • => pager.php5
  • => Auslösen
    einer “Fehlerbehandlung” durch eine err_page.php5, die aus Gründen mangelnder Voraussicht im Bildverzeichnis erwartet wurde, dort aber nicht existierte
  • => Abruf einer nicht existierenden PHP-Datei
  • => pager.php5 =&gt. Erneuter Verweis auf Fehlerbehandlung durch eine nicht existierende “err_page.php5”
  • => Abruf einer nicht existierenden PHP-Datei
  • etc., etc.

Apache versucht es dann mehrfach und bricht schließlich ab.

Lösungsansatz 1: Klammere Dateien bestimmter Typen aus der Rewrite-Anweisung aus

Das Erlebnis brachte mich dazu, genauer darüber nachzudenken, wie ich eigentlich mit Rewrites normaler Dateien der Typen “.jpg, .gif, .png, .swf, .css, .js” etc. umgehen sollte, für die eine Ersetzung durch PHP-Programme gar nicht vorgesehen ist.

Eine Lösungsvariante ist das Ausklammern dieser Dateitypen von der Rewrite-Anweisung in der “.htaccess”-Datei. Das sieht im einfachsten Fall etwa so aus:

Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteRule ^php/hmenu/pager.php5(.*)$ - [L] 

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule \.(js|css|ico|gif|jpg|png|swf|ttf|eot)$ - [NC,L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ my_Rw_Php_Path/pager.php5?adr=$1 [PT]   

 
Hier werden zwei “Condition/Rewrite”-Sequenzen eingesetzt, da ohne besondere Tricks (Skip-Direktiven) zu einem Block aus Condition-Anweisungen nur genau eine Rewrite-Anweisung gehören sollte. “NC” sorgt für eine Nichtbeachtung von Groß-/Klein-Schreibung. “L” beendet die Rewrite-Analyse. “my_Rw_Php_Path” steht für einen Pfad zu einem Serververzeichnis, das die zentralen Programme zur Rewrite-Behandlung beherbergt.

Wird nun eine nicht vorhandene Datei der genannten Typen von einem Web-Client angefordert, wird diese Anforderung durchgereicht und vom Apache-Server mit HTTP-Fehlern der Art “404 Not Found” quittiert. Das reicht in Testphasen zur Prüfung der Lauffähigkeit einer CMS-basierten Website normalerweise aus.

Lösung 2: Behandle fehlende Dateien bestimmter Typen als Sonderfälle in einer zentralen PHP-Datei

Eine kontrollierte Reaktion des Systems auf nicht vorhandene Dateien bestimmter Typen jenseits von HTML-Dateien lässt sich natürlich auch in einer weiteren zentralen PHP-Datei (etwa “missing.php5”) vorsehen, auf die eine gesonderte Rewrite-Anweisung verweist. Beispielsweise könnte man den mittleren Teil der obigen “.htaccess” in diesem Sinne ersetzen durch:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)\.(js|css|ico|gif|jpg|png|swf|ttf|eot)$ my_Rw_Php_Path/missing.php5?missadr=$1\.$2 [NC,L]

Bzgl. der Problembehandlung in der “missing.php5” muss man sich aber genau überlegen, für welche Dateien man tatsächlich eine offene und für den User auch erkennbare Fehlermeldung vorsehen will. Ein fehlendes Bild z.B. ist meist nicht überlebenskritisch.

Ich tendiere im Moment dazu, gezielt Meldungen in eine eigene Log-Datei auf dem Server zu schreiben, die man sowohl im Test- als auch Produktivbetrieb regelmäßig auswertet. Ein Minimal-PHP-Skript “missing.php5” könnte für diesen Zweck dann in etwa so aussehen:

<?php
$missadr = 'unknown'; 
if (isset($_GET['missadr']) ) {
	$missadr = $_GET['missadr']; 
}

$fh = fopen("missing.log", 'a+'); 
$out_str = "\r\n" . date('d.m.Y :: H.I.s') . " :: A requested file (" .$missadr . ") is missing"; 
fputs($fh, $out_str)
; 
fclose($fh); 

header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
exit;
?> 

 
Natürlich wäre das in dieser Einfachheit fahrlässig; der Inhalt von $_GET[‘missadr’] ist im produktiven Einsatz zu prüfen und ggf. zu bereinigen, um den Inhalt als Teil eines Angriffsvektors auszuschalten. In diesem Artikel geht es aber nur um einen ersten Ansatz.

Der Header-Output ist wichtig; durch ihn kann man z.B. auch in Browser-Tools (bei FF etwa in der Web-Konsole) erkennen, dass ein Fehler vorliegt und eine Datei tatsächlich nicht vorhanden ist.

Ein typischer Output in der Datei “missing.log” hat nach zwei Aufrufen bestimmter Webseite, für die indirekt eine Bilddatei “hg_dxm_7.jpg” angefordert wird, dann ggf. folgenden Inhalt:

27.06.2017 :: 12:0:38 :: A requested file (image/hg_dxm_7.jpg) is missing
27.06.2017 :: 12:0:39 :: A requested file (image/hg_dxm_7.jpg) is missing
27.06.2017 :: 12:0:02 :: A requested file (image/hg_dxm_7.jpg) is missing
27.06.2017 :: 12:0:02 :: A requested file (image/hg_dxm_7.jpg) is missing

Man erkennt hier an der Zeitangabe, dass die fehlende Datei pro Seitenaufruf gleich zweimal angefordert wird; in meinem Fall aus einer CSS-Datei heraus, aber auch direkt über ein HTML-Tag.

Fazit

Nicht nur in einem CMS will man ggf. Requests nach HTML-Dateien durch den gezielten Einsatz von PHP-Webgeneratoren beantworten. Die Nutzer (und auch Suchmaschinen) glauben, reguläre HTML-Dateien abzurufen. In Wirklichkeit sind die Dateien nicht vorhanden; Apache Rewrites sorgen vielmehr für die Erzeugung von HTML-Seiten durch PHP-Programme.

Zu einfach gehaltene Rewrite-Anweisungen für nicht vorhandene Dateien können dabei allerdings schnell zu schwer zu durchschauenden bis rekursiven Fehlern führen. Fordern HTTP-Requests evtl. nicht vorhandene Dateien eines bestimmten Typs an, für die eine gezielte Ersetzung gar nicht vorgesehen ist, so hängt es allein von der Voraussicht der Entwickler ab, was im Detail über Ersetzungen passiert. Es empfiehlt sich deshalb, solche Datei-Anforderungen

  • entweder von vornherein aus der Rewrite-Behandlung auszuschließen
  • oder sie aber einer gezielten Sonderbehandlung durch eine eigene PHP-Datei zuzuführen. Dabei sollten angemessene HTTP-Antwortcodes erzeugt werden.