KVM: fsck direkt auf dem KVM-Host zu Gast-Filesystemen in LUKS-verschlüsselten LVM-Volumes – Unterschiede zwischen Raw Devices und qcow2-Image-Files

Ich betreibe bestimmte Linux-Systeme als KVM-Gäste mit verschlüsseltem Plattenunterbau. Die Partitionen des KVM-Hosts selbst sind zwar auch verschlüsselt; in diesem Artikel betrachte ich aber verschlüsselte virtuelle Disks für KVM-Gastsysteme. Ich nutze hierfür auf dem KVM-Host definierte LVM-Volumes, die mit dm-crypt/LUKS verschlüsselt wurden.

Dabei setze ich regelmäßig zwei Varianten ein:

  • Variante 1: Ein oder mehrere verschlüsselte LVM-Volumes werden dem Gastsystem (in entschlüsseltem Zustand) als “Raw-Devices” zur Verfügung gestellt. Das Gastsystem erstellt dort seine Partitionen (oder im Einzelfall auch eigene LVM-Volumes) mit je einem Linux-Filesystem.
  • Variante 2: Verschlüsselte LVM-Volumes des Hosts enthalten qcow2-Container-Dateien, die vom KVM-Gast als virtuelle Disks genutzt werden. Im qcow2-Container legt der Gast dann eigene LVM-Volumes mit einem Linux-Filesystem an.

Für regelmäßige fsck-Checks der Filesysteme im KVM-Gast kann man einerseits dadurch sorgen, dass man entsprechende Einstellungen für das Gast-Filesystem selbst vornimmt. So kann man mit “tune2fs” den sog. “maximum mount count” auf eine hinreichend kleine Anzahl von Mounts stellen. Das empfiehlt sich vor allem beim root-Filesystem des Gastes: Das darf ja bei der Durchführung von fsck nicht gemountet sein – dies erfordert ansonsten Kunstgriffe, wenn man im bootenden KVM-Gast vor dem Mounten des root-Filesystems fsck erzwingen will.

Manchmal möchte man im Rahmen automatisierter Maintenance-Verfahren aber auch direkt vom KVM-Host aus Filesystem-Checks mit fsck für die Filesystem der KVM-Gäste durchführen. Natürlich ohne das Gastsystem hochzufahren. Wie macht man das im Fall der genannten zwei Varianten?

fsck in Variante 1 – LVM-Volume als verschlüsseltes Raw-Device des Gastes

Variante 1 weist folgende Schichtung bzgl. der physikalischen und virtuellen Disks auf:

  • Physikalische Plattenpartitionen für Raid   >>  
  • Raid 10   >>  
  • LVM   >>  
  • LVM-Groups und LVM-Volumes, die der Host nutzen kann   >>  
  • dm-crypt/LUKS-Verschlüsselung eines (oder mehrerer) von LVM-Volumes, die den Gästen as Raw-Devices bereitgestellt werden.   >>  
  • KVM/QEMU- und Gastsystem mit Zugriff auf das Raw-Volume als virtuelle Platte   >>  
  • Partitionen (oder LVM-Volumes) im Gastsystem   >>  
  • ext4-Filesysteme im Gastsystem

Hier führt der Weg über die Anwendung von “cryptsetup” und z.B. das Tool “kpartx” (das man natürlich installiert haben muss). Wir führen alle Operation natürlich nur dann durch, wenn das KVM-Gastsystem selbst nicht läuft. Wir müssen vermeiden, dass auf die Partitionen des Gastes von mehreren Betriebssystemen aus (Host und Gast) gleichzeitig schreibend zugegriffen wird.

Ich gehe in unserem Beispiel mal davon aus, dass die Entschlüsselung des betreffenden LVM-Volumes für den Gast auf dem KVM-Host noch nicht vorgenommen wurde. Dieses Volume liege in einer logischen Volume Group “lvg2” und habe die Bezeichnung “lvhd0”.

Das Kommando “la” ist in folgendem Beispiel ein Alias für ‘ls -la’; alle Kommandos werden direkt auf dem Host ausgeführt. Das jeweilige KVM-Gastsystem ist nicht hochgefahren. Unter dem Verzeichnis “/dev/mapper” finden wir dann bei aktivierten Volume-Groups auf dem KVM-Host etwa
folgenden Eintrag vor;

mytux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     340 Aug  4 09:46 .
drwxr-xr-x 22 root root    9720 Aug  4 09:50 ..
crw-------  1 root root 10, 236 Aug  4 09:41 control
... 
lrwxrwxrwx  1 root root       8 Aug  4 09:46 lvg2-lvhd0 -> ../dm-11
...                                                                    

Zunächst müssen wir dieses Volume entschlüsseln:

mytux:~ # cryptsetup open /dev/mapper/lvg2-lvhd0  cr_hd0
Enter passphrase for /dev/mapper/lvg2-lvhd0: 

mytux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     340 Aug  4 09:46 .
drwxr-xr-x 22 root root    9720 Aug  4 09:50 ..
crw-------  1 root root 10, 236 Aug  4 09:41 control
lrwxrwxrwx  1 root root       8 Aug  4 09:46 cr_hd0 -> ../dm-16
...
lrwxrwxrwx  1 root root       8 Aug  4 09:46 lvg2-lvhd0 -> ../dm-11
...                                                                    

Ok. Der Befehl “qemu-img” informiert uns darüber, dass wir es tatsächlich mit einem Raw-Device (von 100GB Größe) zu tun haben:

 
mytux:~ # qemu-img info /dev/mapper/cr_hd0
image: /dev/mapper/cr_hd0
file format: raw
virtual size: 100G (107372085248 bytes)
disk size: 0

Infos zur Partitionierung des “Raw Devices”
In unserem Beispiel befinden sich auf dem entschlüsselten LVM-Volume des Hosts zwei Partitionen des Gastes: eine swap-Partition und eine Partition mit einem ext4-Filesystem. Es gibt mehrere Tools, mit denen man die Partitionsstruktur unterhalb eines Raw-Devices für einen KVM-Gast auf dem Host selbst untersuchen kann:
“fdisk”, “parted”, “virt-filesystems” und eben auch “kpartx”:

 
mytux:~ # fdisk -l /dev/mapper/cr_hd0
Disk /dev/mapper/cr_imap: 100 GiB, 107372085248 bytes, 209711104 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00041fe1

Device                    Boot   Start       End   Sectors  Size Id Type
/dev/mapper/cr_hd0-part1         2048   3067903   3065856  1.5G 82 Linux swap / Solaris
/dev/mapper/cr_hd0-part2 *    3067904 167772159 164704256 78.6G 83 Linux

mytux:~ # parted /dev/mapper/cr_hd0 unit s print
Model: Linux device-mapper (crypt) (dm)
Disk /dev/mapper/cr_hd0: 209711104s
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start     End         Size        Type     File system     Flags
 1      2048s     3067903s    3065856s    primary  linux-swap(v1)  type=82
 2      3067904s  167772159s  164704256s  primary  ext4            boot, type=83
 
mytux:~ # virt-filesystems -a /dev/mapper/cr_hd0 --extra
/dev/sda1
/dev/sda2
mytux:~ # virt-filesystems -a /dev/mapper/cr_hd0 --extra -l
Name       Type        VFS   Label  Size         Parent
/dev/sda1  filesystem  swap  -      1569718272   -
/dev/sda2  filesystem  ext4  -      84328579072  -
 
mytux:~ # kpartx -l /dev/mapper/cr_hd0 
cr_hd01 : 0 3065856 /dev/mapper/cr_hd0 2048
cr_hd02 : 0 164704256 /dev/mapper/cr_hd0 3067904

Hinweis:

kpartx liefert Infos zur Partionierung (samt Offests) auch für Disk-Image-Files im “Raw”-Format. kpartx funktioniert jedoch nicht für Disk-Image-Files im qcow2-Format!

Mit Ausnahme von “virt-filesystems” stellen uns alle oben vorgestellten Tools auch Offset-Informationen zur Verfügung:
Die Angaben 2048(s) und 3067904(s) entsprechen Offset-Adressen der Partitionen; wir müssen die Zahl
der Sektoren allerdings noch mit der Anzahl der Bytes (512) multiplizieren: also z.B. 2048 * 512 ist der Offset für die erste (swap-) Partition.

Man könnte zur Partitionsbestimmmung auch “guestfish” und die zu guestfish gehörigen Sub-Kommandos run und list-filesystems oder aber auch das Tool “qemu-nbd” heranziehen. “qemu-nbd” diskutiere ich gleich im Detail anhand der Variante 2.

Partitionen des Raw-LVM-Volumes (= Raw-Device für das KVM-Gastsytem )ansprechen
“kpartx -a” liefert uns für Devices im Raw-Format eine einfache Möglichkeit, die darin liegenden Partitionen anzusprechen.

mytux:~ # kpartx -a /dev/mapper/cr_hd0
mytux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     420 Aug  6 14:36 .
drwxr-xr-x 22 root root    9740 Aug  6 14:36 ..
crw-------  1 root root 10, 236 Aug  6 08:26 control
lrwxrwxrwx  1 root root       8 Aug  6 14:32 cr_hd0 -> ../dm-16
lrwxrwxrwx  1 root root       8 Aug  6 14:36 cr_hd01 -> ../dm-17
lrwxrwxrwx  1 root root       8 Aug  6 14:36 cr_hd02 -> ../dm-18
lrwxrwxrwx  1 root root       8 Aug  6 14:36 cr_hd0_part1 -> ../dm-17
lrwxrwxrwx  1 root root       8 Aug  6 14:36 cr_hd0_part2 -> ../dm-18
....
lrwxrwxrwx  1 root root       7 Aug  6 08:55 lvg2-lvhd0 -> ../dm-11
...
mytux:~ # 

Man beachte die unterschiedliche Bezeichnung, die auf das gleiche Device verlinken. Wir wissen bereits, dass die zweite Partition ein ext4-Filesystem des KVM-Gastes enthält. Also

mytux:~ # fsck -f /dev/mapper/cr_hd02
fsck from util-linux 2.29.2
e2fsck 1.42.11 (09-Jul-2014)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/cr_hd02: 1016912/5152768 files (0.1% non-contiguous), 6724050/20588032 blocks
mytux:~ # 

Anschließend können wir das Mapping durch “kpartx -d” wieder rückgängig machen:

mytux:~ # kpartx -d /dev/mapper/cr_hd0
mytux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     340 Aug  6 14:45 .
drwxr-xr-x 22 root root    9700 Aug  6 14:45 ..
crw-------  1 root root 10, 236 Aug  6 08:26 control
lrwxrwxrwx  1 root root       8 Aug  6 14:32 cr_hd0 -> ../dm-16
...
lrwxrwxrwx  1 root root       7 Aug  6 08:55 lvg2-lvhd0 -> ../dm-11 
mytux:~ # 

Was tun, wenn das Gastsystem auch selbst LVM nutzt?
In unserem Fall lag im Gastsystem selbst keine LVM-Struktur vor. Hätten wir das gehabt, hätten wir noch zwei weitere Schritte vornehmen müssen – nämlich “vgscan”, “vgchange -ay”. Erst danach hätten wir “fsck” ausführen können. Wir werden dies weiter unten bei der Diskussion der Variante 2 sehen.

Arbeit über Loop-Devices
Der Vollständigkeit halber zeige ich kurz noch, wie man Partitionen von KVM-RAW-Devices über ihre Offsets auch als Loop-Devices ansprechen kann. Die zweite Partition hat in unserem Beispiel einen Offset von 3067904 * 512 = 1570766848 Bytes.

Also:

mytux:~ # losetup -r -o 1570766848  /dev/loop3 /dev/mapper/cr_hd0
mytux:~ # fsck -f /dev/loop3
fsck from util-linux 2.29.2
e2fsck 1.42.11 (09-Jul-2014)
fsck.ext4: Operation not permitted while trying to open /dev/loop3
You must have r/w access to the filesystem or be root
mytux:~ # losetup -d  /dev/loop3 
mytux:~ # losetup  -o 1570766848  /dev/loop3 /dev/mapper/cr_hd0  
mytux:~ # fsck -f /dev/loop3     
fsck from util-linux 2.29.2
e2fsck 1.42.11 (09-Jul-2014)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking 
reference counts
Pass 5: Checking group summary information
/dev/loop3: 1016912/5152768 files (0.1% non-contiguous), 6724050/20588032 blocks
mytux:~ # 
mytux:~ # tune2fs -l /dev/loop3
tune2fs 1.42.11 (09-Jul-2014)
Filesystem volume name:   <none>
Last mounted on:          /
Filesystem UUID:          4388dd4b-ac1a-5c9c-b8d6-88e53b12bd2d
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash 
Default mount options:    user_xattr acl
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              5152768
Block count:              20588032
Reserved block count:     267644
Free blocks:              13863982
Free inodes:              4135856
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      1019
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         8192
Inode blocks per group:   512
Flex block group size:    16
Filesystem created:       Mon Jan  6 15:44:37 2014
Last mount time:          Mon Aug  6 08:56:27 2018
Last write time:          Mon Aug  6 15:01:58 2018
Mount count:              0
Maximum mount count:      2
Last checked:             Mon Aug  6 15:01:58 2018
Check interval:           172800 (2 days)
Next check after:         Wed Aug  8 15:01:58 2018
Lifetime writes:          2270 GB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      ce2daf83-bc25-44d5-fcdf-b35afd5c8f2b
Journal backup:           inode blocks
mytux:~ # 
mytux:~ # losetup -d  /dev/loop3

Der Leser sieht, dass ich in der letzten Befehlssequenz anfänglich aus lauter guter Gewohnheit das Device nur im read-only modus als Loop-Device angelegt hatte. Erst nach einer Korrektur läuft dann fsck. Natürlich kann man dann z.B. auch tune2fs auf das Loop-Device anwenden. Über Loop-Devices geht es also auch. Man muss dann halt nur die Offsets wissen!

fsck in Variante 2 – verschlüsseltes LVM-Volume mit Disk-Image-File im “qcow2”-Format

In diesem Szenario liegt eine wirklich komplexe Schichtung vor:

KVM-Host -> LVM-Volume-Group -> Luks-verschlüsseltes LVM-Volume -> qcow2-Image-File -> Partitions- und LVM-Struktur des KVM-Gastsystems -> Volumegroup mit LVM-Volume des Gastes -> ext4-Filesystem

In diesem Szenario wirken sich vor allem zwei bedeutsame Unterschiede zur Variante 1 aus:

  • Unser Disk-Image-File (eine Art Container-File; “os43.qcow2”) hat kein Raw-Format – daran scheitert u.a. “kpartx -a”.
  • In dem Container-File befindet sich eine Partition, mittels derer das Gastsystem eine LVM-Logical-Volume-Group “lvg1” samt einem Logical Volume “lvroot” angelegt hat.

Zum ersten Problem:
Es ist hier zu bedenken, dass wir das zu prüfende Filesystem ja nicht auf dem Host mounten wollen. Das einzige mir bekannte Programm, das uns den Inhalt (also die Partitionen) des qcow2-Files samt Offsets bedarfsgerecht zur Verfügung stellt, ist <strong>qemu-nbd</strong>. Bedarfsgerecht heißt hier, dass Physical Volumes (Partitione) des Gastes anschließend auf dem KVM-Host in Form von Loop-Devices weiter genutzt werden können. Das ermöglicht es uns dann, die LVM Volume-Group und die LVM-Volumes innerhalb des qcow2-Files anzusprechen und “fsck -f” auszuführen.

Hinweis:

Es gibt zwar eine Möglichkeit eine Standardvariante von fsck innerhalb des Kommandos “guestfish” aus der libguestfs-Suite anzuwenden (s.u.); “fsck -f” geht damit aber nicht.

Zum zweiten Problem:
Neben der Aufdröselung der Partitionsstruktur (samt Offsets) im qcow2-File mit seinem komplexen Format, müssen geeignete Tools auf dem Host auch noch die interne LVM-Struktur erkennen und zu aktivieren. Wir werden hierfür das Gespann “vgscan und “vgchange” einsetzen.

Entschlüsselung und Mounten des LVM-Volumes des Hosts
Alle nachfolgenden Kommandos werden wieder direkt auf dem KVM-Host ausgeführt. Zunächst müssen wir wie in Variante 1 das passende LVM-Volume des KVM-Hosts entschlüsseln. Wir müssen das dekryptierte Device anschließend aber auch noch an geeigneter Stelle des Hosts mounten, um das dort enthaltene Disk-Image-File ansprechen zu können:

mxtux:~ # cryptsetup open /dev/mapper/volssd10-kvmos  cr_kvmos
Enter passphrase for /dev/mapper/volssd10-kvmos:
mxtux:~ # 
mxtux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     420 Aug  6 11:52 .
drwxr-xr-x 27 root root   12300 Aug  6 11:52 ..
crw-------  1 root root 10, 236 Aug  6 08:49 control
lrwxrwxrwx  1 root root       8 Aug  6 11:48 cr_kvmos -> ../dm-16
...
lrwxrwxrwx  1 root root       7 Aug  6 11:48 volssd10-kvmos -> ../dm-6
...  
mxtux:~ # 
mount /dev/mapper/cr_kvmos /kvm/os                                                                  
mxtux:~ # 

Informationen zum Partitionsaufbau innerhalb des qcow2-Image-Files:
Während kpartx keine ausreichenden Informationen liefert, ermöglicht uns das Kommando “virt-filesystems” aus der libguestfs-Suite (bei Bedarf installieren!) einen Einblick in die Unterteilung des qcow2-Image-Files “os43.qcow2”:

mytux:~ # virt-filesystems  -a  /kvm/os/os43.qcow2 --extra -l 
Name              Type        VFS   Label  Size        Parent
/dev/sda1         filesystem  swap  -      2153775104  -
/dev/lvg1/lvroot  filesystem  ext4  -      8589934592  -

Netterweise erkennt “virt-filesystems” sogar die LVM-Volume-Group “lvg1” und das Volume “lvroot” ! Wir könnten dieses logische Volume des Gastes nun sogar mittels des Kommandos “guestmount” (ebenfalls Teil der libguestfs) auf dem Host mounten und mit den Inhalten arbeiten:

mytux:~ # guestmount -a /kvm/os/os43.qcow2 -m /dev/lvg1/lvroot --ro /mnt2
mytux:~ # la /mnt2
total 136
drwxr-xr-x  23 root root   4096 Jun  7 18:27 .
drwxr-xr-x  40 root root   4096 Jul 25 18:55 ..
drwxr-xr-x   2 root root   4096 May 14 19:20 bin
drwxr-xr-x   3 root root   4096 May 14 19:22 boot
drwxr-xr-x   2 root root   4096 May 14 17:09 dev
drwxr-xr-x 128 root root  12288 Aug  4 11:41 etc
drwxr-xr-x   3 rmu  users  4096 May 28 17:43 extras
drwxr-xr-x   4 root root   4096 May 15 20:29 home
drwxr-xr-x  12 root root   4096 May 14 19:20 lib
drwxr-xr-x   7 root root  12288 May 14 19:21 lib64
drwx------   2 root root  16384 May 14 17:09 lost+found
drwxr-xr-x   2 root root   4096 May 10  2017 mnt
drwxr-xr-x   2 root root   4096 May 10  2017 opt
drwxr-xr-x   2 root root   4096 May 14 17:09 proc
drwx------   9 root root   4096 Jun 12 21:52 root
drwxr-xr-x   2 root root   4096 May 14 17:09 run
drwxr-xr-x   2 root root  12288 May 14 21:12 sbin
drwxr-xr-x   2 root root   4096 May 10  2017 selinux
drwxr-xr-x   5 root root   4096 May 14 17:12 srv
drwxr-xr-x   2 root root   4096 May 14 17:09 sys
drwxrwxrwt  26 root root  12288 Aug  4 11:41 tmp
drwxr-xr-x  13 root root   4096 May 14 17:10 usr
drwxr-xr-x  12 root root   4096 May 14 17:24 var
mytux:~ # umount /mnt2

Leider bringt uns das hinsichtlich des angestrebten “fsck” aber gar nichts.

nEinsatz von “qemu-nbd”
Im Gegensatz zu RAW-Devices oder Raw-Image-Files kommen wir an dieser Stelle nicht um den Einsatz von des qemu-eigenen Kommandos “qemu-nbd” herum. Also:

mxtux:~ # modprobe nbd max_part=8
mxtux:~ # qemu-nbd --connect=/dev/nbd0 /kvm/os/os43.qcow2 
mxtux:~ # la /dev/ | grep nbd0
brw-rw----   1 root disk       43,   0 Aug  6 16:22 nbd0
brw-rw----   1 root disk       43,   1 Aug  6 16:22 nbd0p1
brw-rw----   1 root disk       43,   2 Aug  6 16:22 nbd0p2

Was verbirgt sich hinter diesen neuen Devices dahinter?

mxtux:~ # fdisk -l /dev/nbd0
Disk /dev/nbd0: 15 GiB, 16106127360 bytes, 31457280 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x000392a8

Device      Boot   Start      End  Sectors Size Id Type
/dev/nbd0p1         2048  4208639  4206592   2G 82 Linux swap / Solaris
/dev/nbd0p2 *    4208640 31457279 27248640  13G 8e Linux LVM

Aha, fdisk erkennt, dass die zweite Partition LVM nutzt. Wie kommen wir nun weiter? “kpartx” führt uns nicht zum Ziel, da LVM Volume Groups erst aktiviert werden müssen. Hierzu sind zwei Schritte nötig

  • Schritt 1: Wir müssen uns das LVM-Device des qcow2-Files auf dem Host zugänglich machen – als Loop-Device. Dazu berechnen wir dessen Offset ( = 4208640 * 512 = 2154823680)
  • Schritt 2: Wir müssen wir auf dem KVM-Host das Kommando “vgscan” ausführen und danach die gewünschten Volume Group mit “vgchange” aktivieren

Also:

mxtux:~ # vgscan
  Reading all physical volumes.  This may take a while...
  Found volume group "volssd10" using metadata type lvm2
  Found volume group "lvgssd5" using metadata type lvm2
  Found volume group "lvg2" using metadata type lvm2
  Found volume group "lvg10f2" using metadata type lvm2
  Found volume group "volgrp1" using metadata type lvm2

mxtux:~ # losetup -o 2154823680 /dev/loop5 /dev/nbd0

mxtux:~ # vgscan
  Reading all physical volumes.  This may take a while...
  Found volume group "lvg1" using metadata type lvm2
  Found volume group "volssd10" using metadata type lvm2
  Found volume group "lvgssd5" using metadata type lvm2
  Found volume group "lvg2" using metadata type lvm2
  Found volume group "lvg10f2" using metadata type lvm2
  Found volume group "volgrp1" using metadata type lvm2
mxtux:~ # 

Aha, vgscan erkennt eine neue Volume-Group “lvg1”. Wir sehen hier übrigens, dass es sich lohnt, die Bezeichnungen von Groups auf dem Host und den Gastsystemen unterschiedlich und global eindeutig zu wählen – etwas, das ich hier zu meiner Schande versäumt habe. Nun müssen wir die Volume Group noch aktivieren:

mxtux:~ # vgchange -ay lvg1
  1 logical volume(s) in volume group "lvg1" now active
mxtux:~ #
mxtux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     460 Aug  6 16:44 .
drwxr-xr-x 28 root root   12880 Aug  6 16:44 ..
crw-------  1 root root 10, 236 Aug  6 08:49 control
lrwxrwxrwx  1 root root       8 Aug  6 11:48 cr_kvmos -> ../dm-16
...
lrwxrwxrwx  1 root root       8 Aug  6 16:44 lvg1-lvroot -> ../dm-19
...
lrwxrwxrwx  1 root root       8 Aug  6 16:33 nbd0p2p1 -> ../dm-18
...

mxtux:~ # fdisk -l /dev/mapper/lvg1-lvroot
Disk /dev/mapper/lvg1-lvroot: 8 GiB, 8589934592 bytes, 16777216 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

mxtux:~ # 
virt-filesystems -a /dev/nbd0 --extra --parts --blkdevs --filesystems -l --lvs
Name             Type       VFS  Label MBR Size        Parent
/dev/sda1        filesystem swap -     -   2153775104  -
/dev/lvg1/lvroot filesystem ext4 -     -   8589934592  -
/dev/lvg1/lvroot lv         -    -     -   8589934592  /dev/lvg1
/dev/sda1        partition  -    -     82  2153775104  /dev/sda
/dev/sda2        partition  -    -     8e  13951303680 /dev/sda
/dev/sda         device     -    -     -   16106127360 -

Nun können wir den Filesystem-Check des LVM-Volume des KVM-Gasts, das sich m qcow2-File befindet, auf dem KVM-Host ausführen. Und danach alle Kommandos wieder rückgängig machen:

mxtux:~ # fsck -f /dev/mapper/lvg1-lvroot
fsck from util-linux 2.29.2
e2fsck 1.42.11 (09-Jul-2014)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/lvg1-lvroot: 245825/524288 files (0.1% non-contiguous), 1707336/2097152 blocks
mxtux:~ # 
mxtux:~ #  vgchange -an lvg1
  0 logical volume(s) in volume group "lvg1" now active
rux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     440 Aug  6 17:09 .
drwxr-xr-x 27 root root   12840 Aug  6 17:09 ..
crw-------  1 root root 10, 236 Aug  6 08:49 control
lrwxrwxrwx  1 root root       8 Aug  6 11:48 cr_kvmos -> ../dm-16
...
lrwxrwxrwx  1 root root       8 Aug  6 16:33 nbd0p2p1 -> ../dm-18
..
mxtux:~ # losetup -d /dev/loop5 
mxtux:~ # qemu-nbd -d /dev/nbd0 
/dev/nbd0 disconnected
mxtux:~ # rmmod nbd
mxtux:~ # 

Ich bitte zu beachten, dass wir in diesem Fall trotz der bereits sehr komplexen Schichtung immer noch einen Vorteil hatten: Es gab nur genau ein virtuelles LVM-Physical-Volume des Gast-Systems, nämlich die zweite Partition innerhalb des qcow2-Files. Ferner gabe es nur eine Volume-Group. Bei mehreren “Volume Groups”, die sich über unetrschiedliche “Physical Volumes” aus verschiedenen virtuellen Partitionen des Gastes erstreckten, hätten wir alle zugehörigen virtuellen Partitionen auf dem Host als Loop-Devices bereitstellen müssen. Das ist uns im Beipiel erspart geblieben.

fsck in einer dritten Variante – verschlüsseltes LVM-Volume mit einem RAW Image File

Nach all dem Zirkus mit qcow2 stellt sich die Frage: Warum verwendet man nicht gleich Image-Files im Raw-Format? Das ist ein gute Frage; ich werde die Antwort aber auf einen anderen Artikel verschieben. Genannt sei nur der Vorteil des langsam auf die Maximalgröße wachsenden Platzbedarfs im Falle qcow2. Für Disk-Image-Files im Raw-Format spricht aber die Performance. Dennoch ein lapidarer Hinweise zum Einsatz von “fsck” für Partitionen in Raw-Container-Files:

Dieser Fall kann im Kern fast genauso behandelt werden kann, wie oben unter Variante 1 beschrieben. Wer so etwas testen will, kann ja mal ein qcow2-File in ein Raw-Format-File mittels des Kommandos “qemu-img convert” umwandeln (s. die entsprechende man -Seite).

Fazit und eine Alternative

“fsck” mit zugehörigen Optionen für Filesysteme anzuwenden, die sich in verschlüsselten LVM-Volumes eines KVM-Hosts befinden, ist relativ einfach, wenn das LVM-Volume dem KVM-Gast entweder direkt als Raw-Device zur Verfügung gestellt wird oder aber über ein Disk-Image-File im RAW-Format, das sich auf dem Volume befindet. Befinden sich dann unter dem Raw-Device nur gewöhnliche Partitionen kann man sich das Leben mit “kpartx” bequem machen.

Deutlich schwieriger wird die Sache aber mit qcow2-Imag-Files und/oder virtuellen Partitionen von Image-Files, die auf dem Gastsystem in dortigen LVM-Volume-Groups eingesetzt werden. Im Falle von qcow2-Files muss man zunächst zwingend das Kernel-Modul “nbd” und den “qemu-nbd”-Befehl einsetzen.
LVM-Groups innerhalb vom Image-Disk-Files verlangen ferner die Bereitstellung aller entsprechenden zugehörigen virtuellen “Physical Volumes” (virtuelle Partitionen) als Loop-Devices auf dem KVM-Host. Danach sind die Befehle “vgscan” und “vgchange” anzuwenden, um schließlich unter “/dev/mapper” das logische Volume des Gastes mit seinem Filesystem zu erhalten. Erst dann kann man hierauf “fsck” anwenden. Das ist schon komplex, aber man hat am Ende die volle Kontrolle über fsck.

Wem das alles zu schwierig ist, der kann alternativ mal eine einfache Standardvariante des fsck-Befehls unter “guestfish” für Filesysteme von KVM-Gästen ausprobieren. Funktioniert für Raw-Devices und qcow2-Files!

KVM – virtuelles Netzwerk, libvirt, IP-Forwarding auf dem Host und die Susefirewall2

Hinweis:
Der nachfolgende Artikel wurde am 21.02.2017 vollständig überarbeitet – ein von mir am 20.02.2017 als Problem dargestelltes Verhalten der “Susefirewall2” im Zusammenspiel mit “libvirtd” halte ich nun für korrekt und angemessen. Ich konnte das am gestrigen Abend in einem Anfall von geistiger Umnachtung nur nicht sofort richtig einordnen. Aber auch aus der eigenen Vergesslichkeit kann man ja was lernen ….

Virtuelles Netzwerk mit “virt-manager”

Ich habe gestern probeweise einen KVM-Gast (Kali) unter Opensuse Leap 42.3 installiert. Das von der KVM-Instanz zu nutzende virtuelle Netzwerk namens “deb” hatte ich mit Hilfe von “virt-manager” als “Isolated network, internal and host routing only” aufgesetzt. In diesem Fall für ein C-Netz 192.168.10.0/24.

Die korrespondierende Definitionsdatei “/etc/libvirt/networks/deb.xml” sieht dann wie folgt aus

mytux:/etc/libvirt/qemu/networks # cat deb.xml 
<!--
WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:
  virsh net-edit kali
or other application using the libvirt API.
-->

<network>
  <name>deb</name>
  <uuid>8a344aae-20c0-436b-b2a6-daf4d1d10e90</uuid>
  <bridge name='virbr3' stp='on' delay='0'/>
  <mac address='52:54:00:bf:4f:73'/>
  <domain name='kali'/>
  <ip address='192.168.10.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.10.10' end='192.168.50.254'/>
    </dhcp>
  </ip>
</network>

Für jemanden, der sich mit virtuellen Netzwerken auskennt, erscheint an dieser Stelle klar, dass auf dem Host eine virtuelle Bridge (in meinem Fall “virbr3”) implementiert wird, die eine IP-Adresse auf dem Host erhält (192.168.10.1; Device virbr3-nic). Virtuelle KVM Gast-Maschinen, die das eben definierte virtuelle Netz nutzen, erhalten dann je ein virtuelles Netzwerk-Device (vnetx, x=0,1,2 …), welches an die Bridge angebunden wird. Ebenso klar ist, dass das neue Netzwerk ohne IP-Forwarding auf dem Host nur den Host selbst erreichen wird.

Im laufenden Betrieb meines KVM-Gastes sieht das dann auf dem Host so aus:

mytux:/etc/sysconfig # brctl show virbr3
bridge name     bridge id               STP enabled     interfaces
virbr3          8000.525400026902       yes             virbr3-nic
                                                        vnet0

In meinem Fall sollte die virtuelle Maschine über einen Gateway-Rechner des realen Netzwerks (z.B. 192.168.90.0/24) ins Internet dürfen. Auf dem KVM-Host selbst hatte ich entsprechende Routes angelegt und das IP-Forwarding aktiviert. In Firewall-Regeln auf dem KVM-Host wie dem Gateway wurde der Paket-Transport zwischen den Netzwerken zunächst vollständig zugelassen.

Eine interessante Frage ist nun: Reicht das erstmal? Oder aber: Ist das virtuelle Netzwerk wirklich “isoliert”?

Meine Erwartung aus früheren Installationen war: Nein – sobald das Forwarding auf dem KVM-Host aktiviert ist, erreicht das Gastsystem den Gateway und auch das Internet.

Isoliert oder nicht isoliert – das war dann die Frage …

Auf einem KVM-Host nutze ich normalerweise ein IPtables-Paketfilter-Setup (Skript) mit selbst definierten Regeln. Diese Regeln werden über eine systemd-Unit nach dem Starten von libvirtd über ein Skript geladen. Dabei werden alle evtl. bereits existierenden Regeln verworfen und ersetzt.

Ein Test ergab: Mit meinen eigenen selektiven “Iptables”-Regeln funktionierte das Forwarding auf dem KVM-Host anstandslos. Erlaubte Web-Server im Internet konnten vom KVM-Gast problemfrei angesprochen
werden.

Meine KVM-Maschine soll später allerdings auf einem Host zum Einsatz kommen, auf dem eine Susefirewall2 läuft. Deswegen deaktivierte ich in einem weiteren Test mal mein eigenes Firewall-Skript und griff auf die “Susefirewall2” zurück. Die hatte ich über Einträge in der Datei “/etc/sysconfig/SuSEfirewall2” so konfiguriert, dass ein Fowarding/Routing zwischen den betroffenen Netzen erlaubt wurde; relevant hierfür ist die Zeile:

FW_FORWARD="192.168.90.0/24,192.168.10.0/24 192.168.10.0/24,192.168.90.0/24"

Nach einem Neustart des Hosts rieb ich mir dann aber zunächst die Augen:

Pings der virtuellen Maschine in Richtung Gateway und umgekehrt erreichten nicht ihr Ziel.

Das trieb mich gestern zunächst in die Verzweiflung. Nach einem Abschalten von IPtables und nach einem testweisen Laden eigener Regeln lief nämlich alles wieder wie erwartet. Ein nachfolgender Start der Susefirewall2 blockierte dagegen erneut die Verbindung des KVM-Gastes zum Gateway. Das virtuelle Netzwerk wurde durch die Susefirewall2 faktisch isoliert.

Ein detailiertes Verfolgen der Pakete mit Wireshark zeigte dann, dass das Forwarding auf dem Host nicht funktionierte, sondern zu Reject-Meldungen der Art “icmp-port-unreachable” führte. Ein erster Blick in die generierten Firewall-Regeln brachte gestern Abend zunächst keine sinnvollen Erkenntnisse, da zu komplex.

Neudefinition des virtuellen Netzwerks mit virt-manager

In meiner Not versuchte ich das virtuelle Netzwerk mit “virt-manager” neu anzulegen. Dabei erreicht man zwischenzeitlich die Seite 4 des Setup-Dialogs:

Wegen meines Problems entschied ich mich diesmal testweise für ein nicht-isoliertes Netzwerk – sondern für ein “Routed network”:

Danach: Neustart von libvirtd mittels “systemctl restart libvirtd” und Neustarten der Susefirewall2 über YaST:

Und, oh Wunder: Danach lief die Verbindung meines KVM-Hostes ins Internet!

Die Botschaft dieses Experiments war also, dass die Susefirewall2 Einstellungen des Isolationslevels für virtuelle Netzes, die mit virt-manager/libvirt definiert wurden, aufgreift!

libvirt generiert IPtables-Regeln

Heute früh wurde mir beim Aufwachen dann klar, was ich gestern beim Testen übersehen (besser:vergessen) hatte: Das Gespann “virt-manager/libvirt” generiert im Zuge der Generierung virtueller Netzwerke selbst IPtables-Regeln zur Umsetzung der verschiedenen Isolationsniveaus:

Legt man ein (virtuelles) “Isolated network” an, stoppt man danach die Susefirewall und startet man anschließend “libvirtd” neu, so zeigt das Kommando “iptables -S” folgenden Output:

mytux:/etc/sysconfig # iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
.....
-A INPUT -i virbr3 -p udp 
-m udp --dport 53 -j ACCEPT
-A INPUT -i virbr3 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -i virbr3 -p udp -m udp --dport 67 -j ACCEPT
-A INPUT -i virbr3 -p tcp -m tcp --dport 67 -j ACCEPT
...
-A FORWARD -i virbr3 -o virbr3 -j ACCEPT
-A FORWARD -o virbr3 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i virbr3 -j REJECT --reject-with icmp-port-unreachable
..
-A OUTPUT -o virbr3 -p udp -m udp --dport 68 -j ACCEPT

Hier geht also nichts – außer innerhalb des virtuellen Netzwerks, das über die Bridge “virbr3” verköpert wird.

Definiert man dagegen ein “Routed network”, so ergibt sich ein anderer, freundlicherer Regelsatz:

mytux:/etc/sysconfig # iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i virbr3 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -i virbr3 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -i virbr3 -p udp -m udp --dport 67 -j ACCEPT
-A INPUT -i virbr3 -p tcp -m tcp --dport 67 -j ACCEPT
...
-A FORWARD -d 192.168.10.0/24 -o virbr3 -j ACCEPT
-A FORWARD -s 192.168.10.0/24 -i virbr3 -j ACCEPT
-A FORWARD -i virbr3 -o virbr3 -j ACCEPT
-A FORWARD -o virbr3 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i virbr3 -j REJECT --reject-with icmp-port-unreachable
...
-A OUTPUT -o virbr3 -p udp -m udp --dport 68 -j ACCEPT

Ein nachfolgender Start der Susefirewall2 respektiert nun diese Regeln (trotz Änderung der Default-Policy). Ich zeige nachfolgend nur einige relevante Zeilen für den Fall des “Routed network”, in dem die Kommunikation erlaubt wird:

rux:/etc/sysconfig # iptables -S
-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT
-N forward_ext
-N forward_int
-N input_ext
-N input_int
-N reject_func
-A INPUT -i virbr3 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -i virbr3 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -i virbr3 -p udp -m udp --dport 67 -j ACCEPT
-A INPUT -i virbr3 -p tcp -m tcp --dport 67 -j ACCEPT
...
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
-A INPUT -p icmp -m conntrack --ctstate RELATED -j ACCEPT
...
-A INPUT -j input_ext
-A INPUT -m limit --limit 3/min -j LOG --log-prefix "SFW2-IN-ILL-TARGET " --log-tcp-options --log-ip-options
-A INPUT -j DROP
-A FORWARD -d 192.168.10.0/24 -o virbr3 -j ACCEPT
-A FORWARD -s 192.168.10.0/24 -i virbr3 -j ACCEPT
-A FORWARD -i virbr3 -o virbr3 -j ACCEPT
-A FORWARD -o virbr3 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i virbr3 -j REJECT --reject-with icmp-port-unreachable
...
-A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
-A FORWARD -m physdev --physdev-is-bridged -j ACCEPT
...
-A FORWARD -i virbr3 -j forward_ext
-A FORWARD -i virbr3_nic -j forward_ext
...
-A FORWARD -m limit --limit 3/min -j LOG --log-prefix "SFW2-FWD-ILL-ROUTING " --log-tcp-options --log-ip-options
-A FORWARD -j DROP
-A OUTPUT -o virbr3 -p udp -m udp --dport 68 -j ACCEPT
...
-A OUTPUT -o lo -j ACCEPT
-A forward_ext -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 0 -j ACCEPT
-A forward_ext -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 3 -j ACCEPT
-A forward_ext -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 11 -j ACCEPT
-A forward_ext -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 12 -j ACCEPT
-A forward_ext -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 14 -j ACCEPT
-A forward_ext -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 18 -j ACCEPT
-A forward_ext -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 3/2 -j ACCEPT
-A forward_ext -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 5 -j ACCEPT
-A forward_
ext -s 192.168.90.0/24 -d 192.168.10.0/24 -m limit --limit 3/min -m conntrack --ctstate NEW -j LOG --log-prefix "SFW2-FWDext-ACC-FORW " --log-tcp-options --log-ip-options
-A forward_ext -s 192.168.90.0/24 -d 192.168.10.0/24 -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT
-A forward_ext -s 192.168.10.0/24 -d 192.168.90.0/24 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A forward_ext -s 192.168.10.0/24 -d 192.168.90.0/24 -m limit --limit 3/min -m conntrack --ctstate NEW -j LOG --log-prefix "SFW2-FWDext-ACC-FORW " --log-tcp-options --log-ip-options
-A forward_ext -s 192.168.10.0/24 -d 192.168.90.0/24 -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT
-A forward_ext -s 192.168.90.0/24 -d 192.168.10.0/24 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A forward_ext -m comment --comment "sfw2.insert.pos" -m pkttype ! --pkt-type unicast -j DROP
-A forward_ext -p tcp -m limit --limit 3/min -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j LOG --log-prefix "SFW2-FWDext-DROP-DEFLT " --log-tcp-options --log-ip-options
-A forward_ext -p icmp -m limit --limit 3/min -j LOG --log-prefix "SFW2-FWDext-DROP-DEFLT " --log-tcp-options --log-ip-options
-A forward_ext -p udp -m limit --limit 3/min -m conntrack --ctstate NEW -j LOG --log-prefix "SFW2-FWDext-DROP-DEFLT " --log-tcp-options --log-ip-options
-A forward_ext -j DROP
-A forward_int -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 0 -j ACCEPT
-A forward_int -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 3 -j ACCEPT
-A forward_int -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 11 -j ACCEPT
-A forward_int -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 12 -j ACCEPT
-A forward_int -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 14 -j ACCEPT
-A forward_int -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 18 -j ACCEPT
-A forward_int -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 3/2 -j ACCEPT
-A forward_int -p icmp -m conntrack --ctstate RELATED,ESTABLISHED -m icmp --icmp-type 5 -j ACCEPT
-A forward_int -s 192.168.0.0/24 -d 192.168.10.0/24 -m limit --limit 3/min -m conntrack --ctstate NEW -j LOG --log-prefix "SFW2-FWDint-ACC-FORW " --log-tcp-options --log-ip-options
-A forward_int -s 192.168.90.0/24 -d 192.168.10.0/24 -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT
-A forward_int -s 192.168.10.0/24 -d 192.168.90.0/24 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A forward_int -s 192.168.10.0/24 -d 192.168.90.0/24 -m limit --limit 3/min -m conntrack --ctstate NEW -j LOG --log-prefix "SFW2-FWDint-ACC-FORW " --log-tcp-options --log-ip-options
-A forward_int -s 192.168.10.0/24 -d 192.168.90.0/24 -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT
-A forward_int -s 192.168.90.0/24 -d 192.168.10.0/24 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A forward_int -m comment --comment "sfw2.insert.pos" -m pkttype ! --pkt-type unicast -j DROP
-A forward_int -p tcp -m limit --limit 3/min -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j LOG --log-prefix "SFW2-FWDint-DROP-DEFLT " --log-tcp-options --log-ip-options
-A forward_int -p icmp -m limit --limit 3/min -j LOG --log-prefix "SFW2-FWDint-DROP-DEFLT " --log-tcp-options --log-ip-options
-A forward_int -p udp -m limit --limit 3/min -m conntrack --ctstate NEW -j LOG --log-prefix "SFW2-FWDint-DROP-DEFLT " --log-tcp-options --log-ip-options
-A forward_int -j reject_func
-A input_ext -p udp -m pkttype --pkt-type broadcast -m udp --dport 5353 -j ACCEPT
..
-A input_ext -m pkttype --pkt-type broadcast -j DROP
...
-A input_ext -s 192.168.10.0/24 -m limit --limit 3/min -m conntrack --ctstate NEW -j LOG --log-prefix "SFW2-INext-ACC-TRUST " --log-tcp-options --log-ip-options
-A input_ext -s 192.168.10.0/24 -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT
...
-A input_ext -j DROP
-A input_int -j ACCEPT
-A reject_
func -p tcp -j REJECT --reject-with tcp-reset
-A reject_func -p udp -j REJECT --reject-with icmp-port-unreachable
-A reject_func -j REJECT --reject-with icmp-proto-unreachable

 
Damit lässt sich mein Befund von gestern Abend ganz einfach erklären:

Mein eigener Regelsatz löschte zunächst alle vordefinierten Regeln von “libvirt” und erlaubte das Forwarding über den Gateway in jedem Fall. Im Falle eines Starts der Susefirewall2 und eines “Isolated network” respektiert die Susefirewall2 die blockierenden Regeln, die über “virt-manager/libvirt” für das virtuelle Netzwerk vorgegeben wurden. Dito im positiven Fall des “Routed network”.

Merke:

Die “Susefirewall2” setzt die IPtables-Regeln von “virt-manager/libvirtd” für virtuelle Netzwerke nicht außer Kraft!

So simpel; man muss sich halt nur daran erinnern. Nachdem nun das Grundsätzliche geklärt ist, kann ich endlich spezifischere, engmaschigere IPtables-Regeln mit der Susefirewall2 für den eigentlichen Zielhost meiner virtuellen Maschine festlegen. In meinem eigenen Netz nutze ich dagegen lieber weiterhin meine eigenen Firewall-Skripte … und vergesse hoffentlich nicht mehr, welche grundsätzlichen Unterschiede das im Vergleich zur Susefirewall2 nach sich zieht und warum.

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

In den ersten beiden Artikeln dieser Serie

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

hatte ich diskutiert, wie man das QXL-Device von Linux-Gastsystemen eines KVM/QEMU-Hypervisors für den performanten Umgang mit hohen Auflösungen vorbereitet.

Ich hatte zudem gezeigt, wie man mit Hilfe der Tools “xrandr” und “cvt” Auflösungen für Monitore unter einem X-Server einstellt.

Das funktioniert ganz unabhängig von Virtualisierungsaufgaben. So lassen sich u.U. auf Laptops und Workstations Auflösungen “erzwingen”, die trotz gegebener physikalischer Möglichkeiten der Grafikkarte und der angeschlossenen Monitoren nicht automatisch erkannt wurden. “cvt” nutzt man dabei zur Bestimmung der erforderlichen “modelines”.

“xrandr” funktioniert aber auch für X-Server virtualisierter Systeme – u.a. für Linux-Gastsysteme unter KVM/QEMU. Im Verlauf der letzten beiden Artikel hatten wir xrandr dann sowohl auf einem Linux-Virtualisierungs-Host wie auch in einem unter KVM/QEMU virtualisierten Linux-Gastsystem angewendet, um die jeweiligen KDE/Gnome-Desktops in angemessener Auflösung darzustellen.

Als praxisnahes Testobjekt musste dabei ein Laptop unter Opensuse Leap 42.2 herhalten, der mit KVM/QEMU ausgestattet war. Er beherbergte virtualisierte Gastsysteme unter “Debian 9 (Stretch)” und Kali2017. Ein relativ hochauflösender Monitor am HDMI-Ausgang (2560×1440) des Laptops konnte mit Hilfe von xrandr vollständig zur Darstellung der Gastsysteme genutzt werden, obwohl diese Auflösung vom Host nicht erkannt und nicht automatisch unterstützt wurde. Die grafische Darstellung des Gast-Desktops (Gnome/KDE) wurde dabei durch Spice-Clients auf dem Host und QXL-Devices in den virtuellen Maschinen ermöglicht.

Offene Fragen => Themen dieses Artikels

Eine Fragestellung an das bislang besprochene Szenario ist etwa, ob man mit hohen Auflösungen auch dann arbeiten kann, wenn die Spice-Clients auf einem anderen Linux-Host laufen als dem KVM-Virtualisierungshost selbst. Ich werde auf dieses Thema nur kurz und pauschal eingehen. Die Netzwerkkonfiguration von Spice und Libvirt werde ich bei Gelegenheit an anderer Stelle vertiefen.

Ergänzend stellte ein Leser zwischenzeitlich die Frage, ob man im Bedarfsfall eigentlich auch noch höhere Auflösungen für das Gastsystem vorgeben kann als die, die in einem physikalischen Monitor des Betrachter-Hosts unterstützt werden.

Für die Praxis ist zudem folgender Punkt wichtig:
Die bislang beschriebene manuelle Handhabung von QVT und xrandr zur Einstellung von Desktop-Auflösungen ist ziemlich unbequem. Das gilt im Besonderen für den Desktop des Gastsystems im Spice-Fenster. Wer hat schon Lust, jedesmal nach dem Starten eines Gastes “xrandr”-Befehle in ein Terminal-Fenster einzutippen? Das muss doch bequemer gehen! Wie also kann man die gewünschte Auflösung auf dem Betrachter-Host oder im virtualisierten Linux-Gastsystem persistent hinterlegen?

Noch idealer wäre freilich eine Skalierung der Auflösung des Gast-Desktops mit der Größe des Spice-Fensters auf dem Desktop des Anwenders. Lässt sich eine solche automatische Auflösungsanpassung unter Spice bewerkstelligen?

Der nachfolgende Artikel geht deshalb auf folgende Themen ein:

  • Auflösungen und Vertikalfrequenzen für den Desktop des KVM-Gast, die physikalisch am Host des Betrachters nicht unterstützt
    werden.
  • Persistenz der xrandr-Einstellungen für den Gast-Desktop und den dortigen Display-Manager (bzw. dessen Login-Fenster).
  • Automatische (!) Auflösungsanpassung des Gast-Desktops an die Rahmengröße des Spice-Client-Fensters.

Zugriff auf virtualisierte Hosts über Netzwerke

Spice und libvirt sind netzwerkfähig! Siehe hierzu etwa http://www.linux-magazin.de/Ausgaben/2012/10/Spice. Das, was wir in den letzten beiden Artikeln bewerkstelligt haben, hätten wir demnach auch erreichen können, wenn wir xrandr nicht auf dem Virtualisierungshost selbst, sondern auf einem beliebigen Remote-Host zur Darstellung des Gast-Desktops in Spice-Fenstern eingesetzt hätten.

In den nachfolgenden Artikeln unterscheiden wir daher etwas genauer als bisher den “Linux-KVM-Host” vom “Host des Betrachters“. Letzteres liefert dem Anwender den “Desktop des Betrachters“, den wir vom “Desktop des virtualisierten Gastsystems” abgrenzen:

Auf dem “Desktop des Betrachters” werden Spice-Client-Fenster aufgerufen, über die der Anwender den Desktop des KVM-Gast-Systems betrachtet. Der “Linux-Host des Betrachters” kann also der KVM-Virtualisierungshost sein, muss es aber nicht. Die physikalisch mögliche Trennung zwischen dem Host, der den “Desktop des Betrachters” anzeigt, vom Linux-Host, auf dem ein Hypervisor das virtualisierte Gastsystem unterstützt, kommt in folgender Skizze zum Ausdruck:

Der Einsatz von Libvirt und Spice über ein Netzwerk erfordert allerdings besondere System-Einstellungen. Ich werde erst in einem späteren Artikel zurückkommen. Die weiteren Ausführungen in diesem Artikel sind im Moment daher vor allem für Anwender interessant, die virtualisierte Systeme unter KVM auf ihrer lokalen Linux-Workstation betreiben. Leser, die unbedingt jetzt schon remote arbeiten wollen oder müssen, seien darauf hingewiesen, dass X2GO nach wie vor eine sehr performante Alternative zu Spice darstellt, die SSH nutzt, einfach zu installieren ist und headless, d.h. ganz ohne QXL, funktioniert.

Auflösungen und Vertikalfrequenzen des Gastdesktops jenseits der Möglichkeiten eines (einzelnen) physikalischen Monitors

Aufmerksame Leser haben am Ende des letzten Artikels sicherlich festgestellt, dass die in den virt-manager integrierte grafische Spice-Konsole Scrollbalken anbietet, wenn die Auflösung des darzustellenden Gast-Desktops die Rahmengröße des Spice-Fensters übersteigt. Das führt zu folgenden Fragen:

Kann man für den Desktop des Gastsystems auch Auflösungen vorgeben, die die physikalischen Grenzen eines am Betrachter-Host angeschlossenen Monitors übersteigen?

Antwort: Ja, man kann für den Gast durchaus höhere Auflösungen vorgeben als die, die ein physikalischer Monitor unterstützt. Das führt logischerweise zu einer pixelmäßig nicht schärfer werdenden Vergrößerung der Desktop-Fläche des Gastes. Man muss dann eben im Spice-Fenster scrollen, wenn man das Spice-Fenster nicht über die Größe des fraglichen physikalischen Monitors ausdehnen kann.

Haben höhere Gast-Auflösungen als die eines physikalischen Monitors überhaupt einen Sinn?

Antwort: Ja – nämlich dann, wenn man am Linux-Host, von dem aus man den Gast-Desktop betrachtet, mehrere Monitore per “xinerama” zu einem von der Pixelfläche her zusammenhängenden Monitor gekoppelt hat!

An einem von mir betreuten System hängen etwa drei Monitore mit je max. 2560×1440 px Auflösung. Nachfolgend seht ihr ein Bild von einem testweise installierten Debian-Gast, für den mittels CVT und xrandr eine Auflösung von 5120×1080 Pixel eingestellt wurde. Das Spice-Fenster auf dieser Linux-Workstation erstreckt sich dann über 2 von 3 physikalischen Monitoren. Siehe die linke Seite der nachfolgenden Abbildung:

Von der grafischen Performance her ist das auf diesem System (Nvidia 960GTX) überhaupt kein Problem; der Gewinn für den Anwender besteht in komfortablem Platz zum Arbeiten auf dem Desktop des Gastsystems! In der Regel bedeutet das nicht mal eine Einschränkung für das Arbeiten mit dem Desktop des Betrachter-Hosts: Man kann unter KDE oder Gnome ja beispielsweise einfach auf eine weitere, alle drei Monitore überstreckende “Arbeitsfläche” des Betrachter-Desktops ausweichen.

U.a. ist es auch möglich, 4K-Auflösungen, also 4096 × 2160 Pixel, für den Desktop des virtualisierten Systems einzustellen. Man hat dann entweder physikalische Monitore am Betrachter-Host verfügbar, die 4K unterstützen, oder genügend Monitore mit geringerer Auflösung zusammengeschlossen – oder man muss, wie gesagt, eben scrollen. Für manche Grafik-Tests mag selbst Letzteres eine interessante Option sein.

Gibt es Grenzen für die einstellbare QXL-Auflösung des virtualisierten Gast-Systems?

Antwort: Ja; momentan unterstützt das QXL-Device maximal 8192×8192 Pixel.

Geht man so hoch, muss man, wie bereits im ersten Artikel beschrieben, aber auch den Video-RAM des QXL-Devices anpassen und ggf. auf den Parameter “vram64” zurückgreifen!

Nachtrag 15.08.2017:

Nutzt man ein Memory/RAM der VM > 2048 MiB, so gibt es zusätzliche Einschränkungen für den maximalen ram-Wert des QXL-Devices. S. hierzu die inzwischen eingefügten Hinweise im ersten Artikel.

Funktionieren bei den Gastsystem-Einstellungen auch andere Vertikalfrequenzen als solche, die vom physikalischen Monitor unterstützt werden?

Antwort: Ja, auch das funktioniert!

Z.B. unterstützt der in den vorhergehenden Artikeln angesprochene Laptop die Auflösung 2560×1440 physikalisch nur mit 44Hz. Dennoch kann ich für den virtualisierten Gast-Desktop auch Modelines für eine Vertikalfrequenz von 60Hz oder 20Hz anfordern. Das macht in der finalen Darstellung auf dem Host des Betrachters nichts aus – die Grafik-Information wird ja lediglich in das dortige Spice-Fenster eingeblendet; die Abfrage von Änderungen am virtuellen Desktop erfolgt von Spice und QEMU (vermutlich) mit eigenen, intern definierten Frequenzen und wird entsprechend zwischen Spice-Server und -Client übertragen. Aber es schadet nicht, bei der Wahl der Vertikalfrequenz für die Video-Modes des Gastsystems einen vernünftigen Wert wie 60Hz oder 50HZ zu wählen.

Persistenz der Auflösungseinstellungen

Es gibt verschiedene Wege, per CVT gefundene Auflösungen und deren Modelines permanent in einem Linux-System zu hinterlegen und diese Modes beim Start einer graphischen Desktop-Sitzung direkt zu aktivieren. Der Erfolg des einen oder anderen Weges ist aber immer auch ein wenig distributions- und desktop-abhängig.

Ich konzentriere mich nachfolgend nur auf ein Debian-Gast-System mit Gnome 3 und gdm3 als Display Manager. Ich diskutiere dafür auch nur 2 mögliche Ansätze. Für KDE5 und SDDM gibt es allerdings ähnliche Lösungen ….

Warnhinweis:

Am Beispiel des bereits diskutierten Laptops sollte klargeworden sein, dass solche
Einstellungen ggf. sowohl im virtualisierten Gastsystem als auch auf dem Linux-Host, an dem die physikalischen Monitore hängen, dauerhaft hinterlegt werden müssen. Bzgl. der physikalisch wirksamen Einstellungen auf dem eBtrachter-Host ist allerdings Vorsicht geboten; man sollte seine Video-Modes und Frequenzen dort unbedingt im Rahmen der unterstützten Monitor- und Grafikartengrenzen wählen.

Variante 1 – rein lokale, userspezifische Lösung: Eine distributions- und desktop-neutrale Variante wäre etwa, die xrandr-Kommandos in einer Datei “~/.profile” für den Login-Vorgang oder (besser!) in einer Autostart-Datei für das Eröffnen der graphischen Desktop-Sitzung zu hinterlegen. Siehe hierzu etwa:
https://askubuntu.com/ questions/ 754231/ how-do-i-save-my-new-resolution-setting-with-xrandr

Der Nachteil dieses Ansatzes ist, dass der User bereits wissen muss, welche Auflösungen man für seinen Monitor per “xrandr” sinnvollerweise einstellen kann und sollte. Beim “.profile”-Ansatz kommt hinzu, dass sich das bei jedem Login auswirkt. Falsche Modes sind auf der physikalischen Host-Seite aber, wie gesagt, problematisch. Es wäre besser, die User nutzten nur vom Admin vordefinierte Auflösungen und dies mit den üblichen Desktop-Tools. Einen entsprechenden Ausweg bietet die nachfolgende Methode.

Variante 2 – zentrale und lokale Festlegungen:
Dieser Weg führt über 2 Schritte; er ist ebenfalls neutral gegenüber diversen Linux-Varianten. Bei diesem Weg wird globale Information mit user-spezifischen Setzungen kombiniert:

Unter Opensuse Leap ist ein zentrales Konfigurationsverzeichnis “/etc/X11/xorg.conf.d/” für X-Sitzungen bereits vorhanden. Man kann dieses Verzeichnis aber auch unter Debian-Systemen manuell anlegen. Dort hinterlegt man dann in einer Datei “10-monitor.conf” Folgendes:

Section "Monitor"
	Identifier "Virtual-0"
	Modeline "2560x1440_44.00"  222.75  2560 2720 2992 3424  1440 1443 1448 1479 -hsync +vsync
	Option "PreferredMode" "2560x1440_44.00"
EndSection

Section "Screen"
	Identifier "Screen0"
	Monitor "Virtual-0"
	DefaultDepth 24
	SubSection "Display"
		Modes "2560x1440_44.00"
	EndSubsection
EndSection

 
Diese Statements hinterlegen eine definierte Auflösung – hier 2560×1440 bei 44Hz – für unseren virtuellen Schirm “Virtual-0” permanent. Die Modline haben wir, wie in den letzten Artikeln beschrieben, mittels CVT gewonnen. (Die angegebene Werte für die Modline und die Auflösung sind vom Leser natürlich dem eigenen System und den eigenen Wünschen anzupassen.)

Die obigen Festlegungen bedeuten nun aber noch nicht, dass nach einem weiteren Login eine neue Gnome- oder KDE-Sitzung unter Debian bereits die hohe Auflösung produzieren würde. Die “PreferredMode” wird vielmehr ignoriert. Warum ist mir, ehrlich gesagt, nicht klar. Egal: Die Auflösung steht immerhin in den lokalen Konfigurationstools des jeweiligen Desktops zur Auswahl zur Verfügung. Damit kann der Anwender dann die lokalen Auflösungswerte in persistenter Weise festlegen:

Unter “Gnome 3” rufen wir dazu im KVM-Gastsystem etwa das “gnome-control-center” auf:

myself@debian8:~$ gnome-control-center &

Dort wählen wir unter der Rubrik “Hardware” den Punkt “Bildschirme” und stellen die gewünschte Auflösung ein. Die Einstellung landet dann in einer Datei “~/.config/monitors.xml” – und ist X-Session-übergreifend verankert.

Im Falle von “KDE 5” wählen wir dagegen

myself@debian8:~$ systemsettings5 &

und dort dann den Punkt “Hardware >&
gt; Anzeige und Monitor”. Die dort getroffenen Einstellungen werden in einer Datei “~/.local/kscreen/” in einem JSON-ähnlichen Format gespeichert.

Diese 2-te Lösung hat den Vorteil, dass die maximale Auflösung systemweit vorgegeben wird. Der jeweilige User kann jedoch die von ihm gewünschte Einstellung wie gewohnt lokal hinterlegen und dafür die gewohnten Desktop-Tools einsetzen.

Persistenz der Auflösungseinstellungen für den “Display Manager” bzw. den Login-Schirm

Nachdem wir nun die Desktop-Sitzung unter Kontrolle haben, wäre es doch schön, auch das Login-Fenster des Display-Managers dauerhaft auf eine hohe Auflösung setzen zu können. Das geht am einfachsten für “gdm3”. 2 Varianten sind möglich:

Variante 1 – Globale Nutzung der Datei “monitors.xml”:
Die Festlegungen für den Gnome-Desktop wurden in einer Datei “~/.config/monitors.xml” festgehalten. Wir kopieren die “monitors.xml”-Datei nun als User “root” in das Verzeichnis “/var/lib/gdm3/.config/”:

root@debian8:~# cp /home/myself/.config/monitors.xml /var/lib/gdm3/.config/

Dort wird eine Konfigurationsdatei im XML-Format für den gdm3-Schirm ausgewertet. Unter Debian 8/9 hat sich hier allerdings ein Problem eingeschlichen:
gdm3 läuft dort bereits unter Wayland – und dieser X-Server ignoriert leider die getroffenen Einstellungen. Das lässt sich aber leicht beheben, indem man für gdm3 die Nutzung des klassischen X11-Servers erzwingt! In der Datei “/etc/gdm3/daemon.conf” muss dazu folgender Eintrag auskommentiert werden:

[daemon]
WaylandEnable=false

Danach wird dann beim nächsten gdm3-Start auch die “monitors.xml” akzeptiert – und die vorgeschlagene Auflösung übernommen. Leider ist es hier Benutzern ohne Root-Rechte nicht möglich, eigene Einstellungen zu treffen. Als Administrator sollte man hier natürlich zur HW passende Einstellungen wählen.

Links zum Thema “Ignoring monitors.xml in /var/lib/gdm3/.config/”
https://bugzilla.redhat.com/ show_bug.cgi? id=1184617
https://bugzilla.gnome.org/ show_bug.cgi? id=748098
In letzterem ist für Wayland auch ein Workaround beschrieben; ich habe das vorgeschlagene Vorgehen aber nicht getestet.

Variante 2: Nutzung von xrandr-Befehlen in Startup-Scripts des Display Managers
Man kann die “xrandr”-Befehle auch in den Startup-Scripts des jeweiligen Display Managers hinterlegen (xorg-Einstellungen werden leider grundsätzlich ignoriert). Für gdm3 also in der Datei “/etc/gdm3/Init/Default”. Dort kann man die xrandr-Anweisungen etwa am Dateiende anbringe. Siehe hierzu: https://wiki.ubuntu.com/X/ Config/ Resolution#Setting-xrandr-commands-in-kdm.2Fgdm_startup_scripts

Für mich ist das die präferierte Art, fixe Einstellungen für den Desktop-Display/Login-Manager vorzunehmen. Man muss sich allerdings für jeden der populären Manager (gdm3, ssdm, lightdm) kundig machen, in welcher Form Startup-Skripts eingebunden werden können. Leider gibt es dafür keinen Standard.

Nachtrag vom 02.03.2018:
Da “gdm3” im Moment unter aktuellen Debian- wie Kali-Installationen Probleme beim Shutdown macht (hängender Prozess, der von systemd nicht gestoppt werden kann), habe ich auch mal den simplen Login-Manager “lightdm” ausprobiert. Dort findet man Möglichkeiten zum Starten von Skripten in der Datei /etc/lightdm/lightdm.conf”. Siehe dort etwa die Option “display-setup-script”. Dort kann man auf bereits definierte Modes unter “/etc/X11/xorg.conf.d/10-monitor.conf” zurückgreifen – z.B. per “xrandr –output
Virtual-0 –mode 2560x1440_44.00”.

Automatische (!) Auflösungsanpassung des Gast-Desktops an die Größe des Spice-Client-Fensters

Die oben vorgeschlagenen Lösungen funktionieren zwar und mögen für den einen oder anderen Leser durchaus einen gangbaren Weg zur dauerhaften Nutzung hoher Auflösungen (genauer: großer Spice-Fenster-Abmessungen) von KVM/QEMU-Gastsystemen darstellen. Aber das ganze Procedere ist halt immer noch relativ arbeitsintensiv. Leute, die VMware nutzen, kennen dagegen die Möglichkeit, die Auflösung des Gastsystems direkt an die VMware-Fenstergröße anpassen zu lassen. Voraussetzung ist dort die Installation der sog. “VMware Tools” im Gastsystem. Gibt es etwas Korrespondierendes auch unter KVM/QXL/Spice ?

Antwort: Ja, aber …

Eine Voraussetzung ist, dass der QXL-Treiber und der spice-vdagent im Gastsystem installiert und aktiv sind. Eine andere ist aktuell aber auch, dass der jeweilige grafische Desktop des KVM-Gastes (Gnome, KDE, …) mit diesem Duo und den von ihm bereitgestellten Informationen in sinnvoller Weise umgehen kann (s.u.).

Die dynamische Desktop-Anpassung an die Spice-Fenstergröße kann durch KVM-Anwender über die Option

View >> Scale Display >> Auto resize VM with window

aktiviert werden. Die grafische Spice-Konsole (von virt-manager) bietet den entsprechenden Haupt-Menüpunkt in ihrer Menüleiste an.

Nachtrag 02.03.2018:

Es gibt übrigens noch einen zweiten Spice-Client, den man über ein Terminal-Fenster starten kann – nämlich den sog. “Remote-Viewer” (siehe hierzu auch den nächsten Artikel dieser Serie). Je nach Versionsstand bietet der “Remote Viewer” entweder einen ähnlichen Menüpunkt an – oder aber der dargestellte Desktop des KVM-Gastes reagiert bei laufendem vdagent automatisch richtig, wenn im “Remote-Viewer” die Option “Ansicht (View) => Zoom => Normal Size” gewählt wird.

Nun verhält es sich leider so, dass sich das gewünschte Verhalten beim Aktivieren des Menüpunktes in einigen Fällen nicht unmittelbar einstellen mag.

Diesbzgl. sind als erstes 2 wichtige Punkte festzuhalten:

Hinweis 1: Die Funktionalität zur automatischen Auflösungsanpassung ist nicht völlig kompatibel mit den obigen Ansätzen zur Hinterlegung persistenter Auflösungseinstellungen! Im Besonderen muss man die Datei “/etc/X11/xorg.conf.d/10-monitor.conf” zunächst auf ein absolutes Minimum beschränken:

Section "Monitor"
	Identifier "Virtual-0"
	Modeline "2560x1440_44.00"  222.75  2560 2720 2992 3424  1440 1443 1448 1479 -hsync +vsync
EndSection

 
Oder man muss diese Datei gleich ganz entfernen.

Hinweis 2:
Manchmal passiert nichts, wenn man seine Spice-Screen-Größe schon verändert hat und erst dann die Option zur automatischen Anpassung an die Fenstergröße anklickt. Das irritiert den Anwender womöglich, der eine unmittelbare Reaktion erwartet. Die Informationen des Duos “vdagent/QXL-Treiber” zur Änderung der Größe des Spice-Client-Fensters werden offenbar aber erst dann erstmalig verarbeitet, wenn die Ausdehnung des Spice-Fensters tatsächlich durch den Nutzer geändert wird! Das Anklicken der Option im Menü allein ist also für eine erste Anpassung noch nicht ausreichend. Daher der Rat: Bitte testweise mit der Maus eine erste Größenänderung des Spice-Fensters vornehmen. Danach sollte der Desktop reagieren.

Ich zeige den Effekt in den nachfolgenden Bildern mal für ein “Debian 9”-Gast-System. Ich habe zwischen den Bildern dabei mit der Maus die Breite die Breite des Spice-Fensters auf dem KVM-Host von 1700px auf 1200px reduziert.

Aber auch das Beachten der oben genannten zwei Punkte ist im Moment in vielen Fällen nicht hinreichend. Zur Erläuterung muss man leider ein wenig ausholen. Früher war eine automatische Auflösungsanpassung u.a. Aufgabe des spice-vdagent. Im Moment gelten jedoch folgende Feststellungen:

  • Politikwechsel: Red Hat hat aus (hoffentlich guten) Gründen die Politik bzgl. der Auflösungsanpassung geändert. Inzwischen nimmt nicht mehr der spice-vdagent die Auflösungsänderung vor, sondern überlässt dies dem aktuell laufenden Desktop (bzw. bzgl. des Login-Screens dem Desktop-Manager). Das Duo aus vdagent und QXL-Treiber übermittelt hierzu nur noch ein Signal samt der notwendigen Auflösungsinformationen an den aktuell laufenden Desktop (genauer an dessen kontrollierendes Programm) und überlässt ihm weitere Maßnahmen. Wobei die zugehörigen Programme vermutlich wiederum xrandr einsetzen. Für diesen Vorgang muss der QXL-Treiber (Kernelmodul!) aber auch geladen sein.
  • Versionsabhängigkeiten: Eine automatische Auflösungsanpassung funktioniert aufgrund des Umbruchs bzgl. der Verantwortlichkeiten nicht mit allen Host- und Gast-Dristibutionen bzw. Programmständen von libvirt/spice bzw. QXL so wie erwartet.

Unter https://bugzilla.redhat.com/ show_bug.cgi? id=1290586 lesen wir entsprechend:

spice-vdagent used to be doing something like this, but this was racing with desktop environments keeping track of the current resolution/monitors/.., so we are now informing the desktop environment that a resolution change would be desirable, and let it handle it.
… It’s no longer going through spice-vdagent if you use the QXL KMS driver (although it needs spice-vdagent to be started iirc).

Dadurch ergeben sich aber neue Abhängigkeiten – denn wenn der QXL-Treiber und vdagent in einer aktuellen Version geladen sind, aber die jeweilige Desktop-Umgebung das Anliegen von QXL nicht unterstützt, geht halt nix. Mit den QXL-Anforderungen zur Auflösungsskalierung können nur neuere Versionen von Gnome und KDE vernünftig umgehen. Unter LXDE funktioniert im Moment leider überhaupt keine automatische Auflösungsanpassung mehr. Ein Beispiel für die etwas vertrackte Übergangssituation liefert etwa Debian 8:

Unter Debian Jessie mit Kernel 3.16 etwa funktionierte eine automatische Auflösungsanpassung noch – das lag aber damals daran, dass der QXL-Treiber gar nicht geladen werden konnte. Installiert man dagegen Kernel 4.9 unter Debian 9 “Jessie”, dann lässt sich das QXL-Modul laden – aber weder der Gnome-, noch der KDE-, noch ein LXDE-Desktop ziehen dann bzgl. der Auflösungsanpassung mit. Entlädt man das QXL-Treibermodul (mit Performance-Nachteilen) funktioniert die automatische Auflösungsanpassung dagegen wieder (nämlich über die alte Funktionalität des spice-vdagent.

Es ist leider ein wenig chaotisch. Erst unter Debian 9 passt alles wieder zusammen – zumindest unter den dort aktualisierten Gnome3- und KDE5-Versionen.

Die neue Politik abseits des vdagents wird primär durch aktuelle Versionen des QXL-Treiber umgesetzt. Teilweise kann man Probleme mit einer automatischen Auflösungsanpassung deshalb umgehen, indem man das qxl-drm-Kernel-Modul “blacklisten” ließ/lässt. Siehe hierzu:
https://bugs.debian.org/ cgi-bin/ bugreport.cgi? bug=824364
Ein Nichtverwenden des QXL-Treibers hat aber leider auch Performance-Nachteile.

Mit welchen Gastsystemen funktioniert die automatische Auflösungsanpassung?

  • Unter Debian 8 Jessie mit Kernel 3.16, aber ohne geladenen QXL-Treiber (nicht jedoch mit Kernel 4.9, libvirt und qxl aus den Backports)
  • Unter Kali2017 mit Gnome 3.
  • Unter Debian 9 “Stretch” mit Gnome3 und KDE5 – aber nicht mit Mate, nicht mit LXDE.
  • Unter Opensuse Leap 42.2 mit upgedatetem Gnome3 (nicht aber mit KDE5).

Wenn Sie also mit einer automatischen Auflösungsanpassung an die Spice-Fenstergröße experimentieren wollen, dann sollten Sie am besten mit Debian 9 (Stretch) basierten Gast-Systemen arbeiten oder entsprechend upgraden.

Nachtrag 1 vom 02.03.2018:
Die automatische Auflösungsanpassung funktioniert auch mit Kali 2018.1, aktuellem 4.14-Kernel und Gnome3 in der Version 3.26.

Nachtrag 2 vom 02.03.2018:
Ein leidiger Punkt ist die Frage einer automatischen Auflösungsanpassung der Desktop-Display/Login-Manager an das Fenster der grafischen Spice-Konsole. Hierzu habe ich sehr gemischte Erfahrungen:

Während “gdm3” sich als fähig erweist, mit dem “spice-vdagent” zu kooperieren, gilt dies etwa für “lightdm” nicht. Hinweise aus früheren Zeiten zum vorherigen Start von “spice-vdagent” über ein “Wrapper-Skript” (s. etwa: https://www.spinics.net/lists/spice-devel/msg24986.html) funktionieren dabei wegen der oben beschriebenen Politik-Änderung nicht:
Der Display-Manager muss so programmiert sein, dass er die Dienste des vdagent auch nutzt und Screen-Änderungen kontinuierlich abfragt. So wird die aktuelle Screen-Größe i.d.R. nur genau einmal – nämlich beim Starten des Desktop-Managers übernommen. Danach bleibt die Größe des Greeter-Fensters konstant, egal ob man den Spice-Fenster-Rahmen ändert oder nicht.

Fazit

Wir haben gesehen, dass man Auflösungseinstellungen für die Desktops, die man sich über xrandr auf dem Betrachter-Host bzw. im Gastsystem mühsam zurechtgebastelt hat, auch persistent in den betroffenen Systemen hinterlegen kann. Ein u.U. sehr viel einfachere Methode zur Nutzung hoher Auflösungen – nämlich eine automatische Anpassung der Auflösung des Gast-Desktops an die Fenstergröße des Spice-Fensters funktioniert optimal im Moment nur mit Gastsystemen, die aktuelle Versionen des KDE5- oder des Gnome3-Desktops integriert haben. Dort macht diese Option aber ein mühsames Handtieren mit xrandr-befehlen im Gastsystem weitgehend überflüssig.

Ausblick

Im nächsten Artikel dieser Serie

https://linux-blog.anracom.com/ 2017/08/15/ kvmqemu-mit-qxl-hohe-aufloesungen-und-virtuelle-monitore-im-gastsystem-definieren-und-nutzen-iv/

befasse ich mich mit der Möglichkeit, mehrere virtuelle Desktop-Schirme für die Gastsysteme auf (mehreren) realen Monitoren des Betrachter-Hosts zu nutzen.