Il peut arriver dans certains cas que l'on ait besoin de donner a une machine virtuelle un périphérique physique. Par exemple dans le cas d'un serveur NAS virtualisé on peut lui passer directement la carte contrôleur SATA ou dans le cas d'un serveur multimédia on peut lui ajouter une carte graphique physique pour faciliter le transcoding d'un flux.

Dans notre cas on a pas de problèmes avec le réseau, les disques ou l'USB, Proxmox sait gérer ça, mais plutôt avec les ports PCI. C'est ça que recouvre le terme de PCI Passthrough: donner le contrôle exclusif à une machine virtuelle sur un périphérique PCI comme si on l'avait "branché" dessus.

Pour donner le contrôle d'un périphérique physique à une machine virtuelle il y'a une chose a comprendre: le IOMMU et ses groupes. Le IOMMU, pour faire simple, c'est ce qui gère a quel accès sont connectés les ressources matérielles. Il va faire correspondre à une addresse virtuelle en mémoire une adresse physique sur la carte mère. Selon la marque ou le modèle de carte mère le IOMMU n'est pas géré pareil. Dans l'idéal on pourrait faire correspondre une adresse mémoire a une adresse physique et on s'y retrouverait très bien. En pratique il n'y a pas vraiment de standard et certaines cartes deviennent un cauchemar à ce niveau (coucou ma chère Asus B550 Plus !)  C'est là qu'intervient la notion de groupes car PCI permettant aux périphériques qui l'utilisent de parler entre eux il arrive que des constructeurs en regroupent certains en groupes qui forment alors pour le système une seule adresse mémoire si l'on veut. Cela constitue une mesure de sécurité pour héviter que n'importe quoi puisse accèder à n'importe quel périphérique. Concrètement cela signifie que votre carte graphique peut se retrouver dans le même groupe matériel que votre carte réseau et lorsque que vous allez vouloir donner à une machine le contrôle sur la carte graphique elle ne sera plus accessible a l'hôte mais la carte réseau non plus. Cela peut s'avérer même catastrophique quand tous les périphériques PCI sont dans le même groupe. Heureusement comme beaucoup de choses ça se contourne.

Pour vérifier son grouping IOMMU on peut utiliser la commande ci dessous:

find /sys/kernel/iommu_groups/ -type l

Pour ma part pour simplifier l'affichage je préfère utiliser un petit script:

#!/bin/bash
shopt -s nullglob
for iommu_group in $(ls -v /sys/kernel/iommu_groups)
	do echo "IOMMU Group $iommu_group"
    for device in /sys/kernel/iommu_groups/$iommu_group/devices/*
    	do echo -n $'\t'
        lspci -s "${device##*/}" "$@"
    done
 done

Voilà un extrait ce que cela peut donner sur ma carte mère, une Asus Tuf Gaming B550 Plus:

IOMMU Group 0
    00:01.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge
IOMMU Group 1
    00:01.1 PCI bridge: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge
IOMMU Group 14
    01:00.0 Non-Volatile memory controller: Sandisk Corp Device 5006
IOMMU Group 15
    02:00.0 USB controller: Advanced Micro Devices, Inc. [AMD] Device 43ee
    02:00.1 SATA controller: Advanced Micro Devices, Inc. [AMD] Device 43eb
    02:00.2 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43e9
    03:00.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
    03:01.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
    03:02.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
    03:03.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
    03:04.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
    03:08.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
    03:09.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
    04:00.0 VGA compatible controller: NVIDIA Corporation GM206GL [Quadro M2000] (rev a1)
    04:00.1 Audio device: NVIDIA Corporation GM206 High Definition Audio Controller (rev a1)
    06:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 06)
    07:00.0 SATA controller: Marvell Technology Group Ltd. Device 9215 (rev 11)
    08:00.0 Non-Volatile memory controller: Sandisk Corp Device 5006
    0a:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. Device 8125 (rev 04)
IOMMU Group 16
    0b:00.0 Non-Volatile memory controller: Sandisk Corp Device 5006

Si on regarde bien le groupe 15 contient ma carte graphique, ma carte réseau supplémentaire et mon contrôleur SATA (Marvell). Ce qui veut dire que si je passe le contrôleur SATA à une machine je perd l'affichage et le réseau sur l'hôte.

Heureusement il y'a une méthode permettant de s'affranchir de ces groupes et dire que chaque périphérique a son propre groupe: l'ACS Override.

L'ACS c'est un peu le gestionnaire des groupes et des accès matériel au niveau de PCI donc le contourner signifie un problème de sécurité puisque il n'y aura plus d'isolation entre les différents groupes. Avant de se lancer dans la suite je préfère que vous connaissiez le risque.

Pour activer l'ACS Override on va tirer profit d'un patch déjà présent dans le kernel de Proxmox. Il suffit juste de l'activer au boot comme on a pu le faire pour l'IOMMU dans l'article précédent.

Sans EFI

Il faut modifier le fichier de configuration de Grub situé dans /etc/default/grub comme ceci

GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on pcie_acs_override=downstream,multifunction"

puis mettre à jour grub:

update-grub

Pour EFI:

vi /etc/kernel/cmdline

et ajouter à la ligne existante:

intel_iommu=on pcie_acs_override=downstream,multifunction

puis rafraîchir la config avec:

pve-efiboot-tool refresh

Dans tous les cas on rajoute juste pcie_acs_override=downstream,multifunction à la suite de nos paramètres existants et surtout sur la même ligne.

Un reboot suffit à appliquer le changement que l'on constate tout de suite:

IOMMU Group 14
	01:00.0 Non-Volatile memory controller: Sandisk Corp Device 5006
IOMMU Group 15
	02:00.0 USB controller: Advanced Micro Devices, Inc. [AMD] Device 43ee
IOMMU Group 16
	02:00.1 SATA controller: Advanced Micro Devices, Inc. [AMD] Device 43eb
IOMMU Group 17
	02:00.2 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43e9
IOMMU Group 18
	03:00.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
IOMMU Group 19
	03:01.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
IOMMU Group 20
	03:02.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
IOMMU Group 21
	03:03.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
IOMMU Group 22
	03:04.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
IOMMU Group 23
	03:08.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
IOMMU Group 24
	03:09.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43ea
IOMMU Group 25
	04:00.0 VGA compatible controller: NVIDIA Corporation GM206GL [Quadro M2000] (rev a1)
IOMMU Group 26
	04:00.1 Audio device: NVIDIA Corporation GM206 High Definition Audio Controller (rev a1)
IOMMU Group 27
	06:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 06)
IOMMU Group 28
	07:00.0 SATA controller: Marvell Technology Group Ltd. Device 9215 (rev 11)
IOMMU Group 29
	08:00.0 Non-Volatile memory controller: Sandisk Corp Device 5006
IOMMU Group 30
	0a:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. Device 8125 (rev 04)

Les groupes ne contiennent maintenant qu'un seul périphérique et l'on peut passer un périphérique à une machine sans crainte.

L'ACS Override est malgré tout déconseillé pour le risque de sécurité qu'il fait courir. La meilleure méthode reste encore de vérifier les groupes de sa carte mère avant l'achat par exemple.

Pour ajouter un périphérique PCI à une machine dans Proxmox:

et plus qu'à choisir:

N'hésitez pas à me faire signe si j'ai dit des bêtises bien sûr et si je peux répondre à vos questions je suis dispo ici !

Photo by Erik Gazi on Unsplash