개요

PCI Passthrough는 PCI Express장비를 호스트 커널을 거치지 않고, Guest OS에 직접 전달하는 가상화의 한 방식이다. PCI Passthrough를 사용하게 되면 Guest OS는 추가적인 Virtualization overhead없이 PCI장비에 직접 I/O request를 날릴 수 있게 되어 성능상의 이점을 가져올 수 있다. 보통 GPU, Network NIC, NVMe Storage처럼 퍼포먼스가 중요한 장비들을 오버헤드 없이 GuestOS가 사용할 수 있도록 하기 위해서 사용된다.

PCI Passthrough를 사용하기 위해서 리눅스 커널은 VFIO라는 API를 User-level에 제공한다. VFIO를 사용하면 user-level program은 PCI 장비에 직접 접근할 수 있는 권한을 얻을 수 있다. 이때 PCI는 Physical address가 필요함으로 User-level address를 안전하게 PCI의 address로 translation해주어야 한다. 이를 위해서 IOMMU를 통해서 자동으로 Guest PCI Address를 Host PCI Address로 변환해 준다.

리눅스

PCI Device configuration

grub configuration을 다음과 같이 수정한다.

sudo vi /etc/default/grub
GRUB_CMDLINE_LINUX="intel_iommu=on iommu=pt vfio_iommu_type1 allow_unsafe_interrupts=1 vfio-pci.ids=8086:2700"
  • intel_iommu=on: passthrough를 사용하게 하는 옵션으로 필수적으로 사용해야 한다.
  • iommu=pt: passthrough로 사용되는 장치만 IOMMU를 사용하게 하는 옵션이다.
  • vfio_iommu_type1 allow_unsafe_interrupts=1: 하드웨어가 인터럽트 리매핑을 허용하지 않는 경우 강제적으로 unsafe interrupts를 허용하게 한다. 이는 MSI보안 취약점이 있기에 기본적으로는 꺼져있다.
  • vfio-pci.ids=8086:2700: 부팅시에 Passthrough로 사용할 하드웨어 장비의 PCI번호를 적는다. 추후에 external tool로 추가할 수도 있으나, 특정 하드웨어를 지속적으로 passthrough로 사용할 경우, 부팅시에 바로 passthrough모드로 작동되도록 하는 옵션이다.

여기서 PCI 번호는

lspci -nn 으로 확인할 수 있다.

정상적으로 연결되면, dmesg가 다음과 같이 표기되며,

➜  ~ dmesg | grep -i vfio
[    0.000000] Command line: BOOT_IMAGE=/vmlinuz-6.4.0-rc5+ root=/dev/mapper/ubuntu--vg-ubuntu--lv ro pti=off intel_iommu=on iommu=pt vfio-pci.ids=8086:2700
[    0.188367] Kernel command line: BOOT_IMAGE=/vmlinuz-6.4.0-rc5+ root=/dev/mapper/ubuntu--vg-ubuntu--lv ro pti=off intel_iommu=on iommu=pt vfio-pci.ids=8086:2700
[   13.417405] VFIO - User Level meta-driver version: 0.3
[   13.417544] vfio_pci: add [8086:2700[ffffffff:ffffffff]] class 0x000000/00000000
lspci -k

라 하였을때, 정상적으로 Kernel driver in use: vfio-pci로 표기된다.

Virtual machine configuration

최종적으로 Virtual machine에서 사용하기 위해서는 qemu 아규먼트로 -device vfio-pci,host=65:00.0인자를 제공하면 된다. 여기서 65:00.0는 lspci -k로 확인하여 나오는 PCI index로 채워넣으면 된다.

QEMU_ARGS="-enable-kvm -s -cpu host -nographic -vnc localhost:2 -m 16G -smp 28 -drive format=raw,file=$INSTALL_PATH/disk.img,if=virtio,cache=none -net nic -net user,hostfwd=tcp::2223-:22 -device vfio-pci,host=65:00.0"