Featured image of post Proxmox Intel iGPU passthrough

Proxmox Intel iGPU passthrough

Tuto afin d’utiliser un GPU intégré au CPU dans une machine virtuelle Linux d’une machine Proxmox

Contexte

Mon MSI GS30-2M-Shadow que j’avais démonté afin de m’en servir comme serveur maison à rendu l’âme récemment (la batterie a gonflé et a dû endommager la carte mère…).

J’ai alors acheté un NAB6 sur lequel j’ai installé Proxmox au lieu d’un Ubuntu en baremetal.
Du coup, je n’ai plus accès au décodage matériel du CPU sur mon hôte (machine virtuelle Ubuntu) me servant pour mon serveur Jellyfin.

J’ai alors entrepris de transmettre le iGPU “UHD Graphics” à ma VM pour pouvoir effectuer les tâches de traitement vidéos.

Proxmox

Configuration du Serveur

Sur la machine physique, il faut faire en sorte que cette dernière ne prend plus en charge notre iGPU.
Pour cela, on va modifier les données du noyau de démarrage afin d’exclure notre matériel.

Afin de s’assurer de la faisabilité de la chose, on vérifie qu’on a bien un contrôleur graphique détecté :

lspci -nnv | grep VGA

00:02.0 VGA compatible controller [0300]: Intel Corporation Alder Lake-P GT1 [UHD Graphics] [8086:46a3] (rev 0c) (prog-if 00 [VGA controller])

Remarque

Méthodes

Il existe différentes méthodes pour arriver au même résultat.
J’utilise ici la méthode qui effectue le moins de modification sur le système.

On peut alors modifier le fichier /etc/default/grub en remplaçant la ligne GRUB_CMDLINE_LINUX_DEFAULT="quiet" par :

GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt pcie_acs_override=downstream,multifunction initcall_blacklist=sysfb_init video=simplefb:off video=vesafb:off video=efifb:off video=vesa:off disable_vga=1 vfio_iommu_type1.allow_unsafe_interrupts=1 kvm.ignore_msrs=1 modprobe.blacklist=radeon,nouveau,nvidia,nvidiafb,nvidia-gpu,snd_hda_intel,snd_hda_codec_hdmi,i915"

On met à jour le noyau de démarrage afin que cette modification soit prise en compte :

update-grub

Ensuite, on va activer des modules nécessaires au PCI Passthrough en ajoutant les modules suivants au fichier /etc/modules :

vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd

Et on fait en sorte que cela soit pris en compte :

update-initramfs -u -k all

Astuce

Version Ansible

Au sein d’un rôle passthrough qui s’applique sur mon serveur Proxmox :

tasks/main.yml :

- name:  Allow passthrough and Blacklists known graphics drivers
       # to prevent proxmox from utilizing the iGPU
  ansible.builtin.lineinfile:
    path: /etc/default/grub
    regexp: '^GRUB_CMDLINE_LINUX_DEFAULT='
    # Use C1 instead of C1E c-state, turn off hyperthreading, disable all optional CPU mitigations, turn on intel IOMMU, pass thru gpu
    line: 'GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt pcie_acs_override=downstream,multifunction initcall_blacklist=sysfb_init video=simplefb:off video=vesafb:off video=efifb:off video=vesa:off disable_vga=1 vfio_iommu_type1.allow_unsafe_interrupts=1 kvm.ignore_msrs=1 modprobe.blacklist=radeon,nouveau,nvidia,nvidiafb,nvidia-gpu,snd_hda_intel,snd_hda_codec_hdmi,i915"'
    mode: '644'
    state: present
    create: false
  notify:
    - Update grub

- name: Add vfio modules to allow PCI passthrough
  ansible.builtin.blockinfile:
    path: /etc/modules
    block: |
      vfio
      vfio_pci
      vfio_virqfd
      vfio_iommu_type1      
  notify:
    - Update initramfs

handlers/main.yml :

- name: Update grub
  ansible.builtin.command: update-grub

- name: Update initramfs
  ansible.builtin.command: update-initramfs -u -k all

Ainsi, on redémarre la machine (que j’ai fait via la WebUI de Proxmox).

On vérifie que le passthrough est bien actif :

dmesg | grep -e DMAR -e IOMMU

Dans les résultats de la commande, vous devriez avoir la ligne suivante :

[ 0.060254] DMAR: IOMMU enabled

Configuration de l’hôte

Votre VM doit être de type q35. Si ce n’est pas le cas, effectué le changement et vérifier que votre VM démarre bien de cette manière.

Type de VM

Information

Changement du type de machine

J’étais aussi dans le cas ou ma VM était de type Default (i440fx).

En modifiant son type, j’ai perdu le réseau dessus.
Pour une raison que j’ignore, le nom de mon interface réseau a été modifié par ce changement. J’ai donc édité ma configuration Netplan via le VNC de Proxmox.

On ajoute donc un périphérique PCI (dans le menu “Hardware”, “Add”, “PCI Device”) en sélectionnant notre périphérique graphique :

Ajout périphérique PCI : Sélection

Et on lui attribue les paramètres suivants :

Ajout périphérique PCI : Configuration

Ce blog impliquant souvent des drames, cet article n’en fait pas exeption.

En démarrant ma VM avec ces paramètres, la VM ne voulait plus démarrer… J’ai trouvé la solution en mettant le paramètre Display à none (none).
Cela implique que le VNC de Proxmox n’est plus utilisable mais cela ne me pose pas de problème car j’utilise ma VM via SSH.

Configuration matériel finale

Hôte Proxmox (VM)

Vérification

Sur ma VM (Ubuntu 24.04), je vois bien mon périphérique :

lspci -nnv | grep VGA

01:00.0 VGA compatible controller [0300]: Intel Corporation Alder Lake-P GT1 [UHD Graphics] [8086:46a3] (rev 0c) (prog-if 00 [VGA controller])

Pour vérifier que le décodage hardware est possible, on vérifie la présence du driver renderD128 :

cd /dev/dri
ls -la

Driver renderD128

Utilisation sur Jellyfin (Docker)

Mon service Jellyfin étant sur Docker, je dois effectuer des modifications afin que le conteneur ait accès au matériel.

Sur mon hôte Docker (donc ma VM Proxmox Ubuntu), j’ai besoin de connaitre l’ID du groupe render.

getent group render | cut -d ':' -f3

Dans mon cas, render est dans le groupe d’ID 993.

Cela va me permettre de faire en sorte que l’utilisateur du conteneur puisse utiliser le périphérique.

J’édite alors mon Docker Compose pour Jellyfin :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
services:
  jellyfin:
    image: jellyfin/jellyfin
    container_name: jellyfin
    restart: unless-stopped
    user: 0:0
    group_add:
      - "993"
    devices:
      - /dev/dri/renderD128:/dev/dri/renderD128
    network_mode: "host"
    volumes:
      - /var/lib/jellyfin/config:/config
      - /var/lib/jellyfin/cache:/cache
      - /mnt/nas/commun/Videos/Films:/media:ro
      - /mnt/nas/commun/Videos/Series:/media2:ro

Une fois le conteneur recréé, je vais sur le tableau de bord de Jellyfin et active le transcodage selon les paramètres suivants :

Transcodage sur Jellyfin

Pour le choix des cases à cocher, j’ai trouvé des recommandations sur Internet mais je ne suis pas sûr que cela soit les bons réglages.
Ne prenez donc pas cela comme étant la seule et bonne méthode.

Pour tester cela, j’ai alors lancé un film qui faisait que mon CPU était très sollicité. Et ce n’est plus le cas ! Donc ma configuration a bien fonctionné.

Mot de la fin

On a donc vu ici comment j’ai fait pour “envoyé un périphérique PCI” sur une VM.
Bien qu’ici, on le fait pour un iGPU, le principe peut-être repris pour autre chose.

Généré avec Hugo
Thème Stack conçu par Jimmy