Tüm eğitimler
TEKNİK REHBERGÖMÜLÜ LİNUXVİRTÜELLEŞTİRME2026

VFIO
Sanal Fonksiyon I/O Çerçevesi

VFIO ile donanım cihazlarını güvenli biçimde kullanıcı alanına veya sanal makinelere doğrudan geçirme, DMA güvenliği ve IOMMU entegrasyonu.

00 VFIO Neden Gerekli?

VFIO (Virtual Function I/O), donanım cihazlarını çekirdek sürücüleri olmaksızın — ve güvenli biçimde — kullanıcı alanı uygulamalarına ya da sanal makinelere doğrudan erişilebilir kılan bir Linux kernel alt sistemidir.

UIO'nun Sınırları

UIO (Userspace I/O), donanım kayıtlarını mmap() ile kullanıcı alanına açar; ancak ciddi güvenlik açıkları taşır. DMA işlemlerini denetleme mekanizması yoktur: kötü niyetli ya da hatalı bir UIO kullanıcısı, DMA motoruna çekirdek belleğine işaret eden adresler yazabilir ve tüm sistem belleğini okuyup değiştirebilir. Bu, özellikle sanallaştırma ortamlarında kabul edilemez bir tehdittir.

UIOMMIO mmap var, DMA koruması yok, kesme destekli; güvenlik açığı taşır
VFIOIOMMU tabanlı DMA koruması, güvenli cihaz geçişi, tam sürücü soyutlaması
vfio-pciPCIe cihazlar için özelleştirilmiş VFIO backend sürücüsü
vfio-platformMMIO tabanlı platform (DT) cihazlar için VFIO backend

DMA Güvenliği Sorunu

Kullanıcı alanındaki bir süreç, bir PCIe cihazına DMA adresi gönderebilir. IOMMU olmadan bu adres doğrudan fiziksel bellek adresidir ve cihaz herhangi bir bellek bölgesine erişebilir. IOMMU, cihazın gördüğü IOVA (I/O Virtual Address) ile fiziksel adres arasına bir çeviri tablosu koyar; böylece cihaz yalnızca kendisine ayrılan belleği görebilir.

  IOMMU Olmadan:
  Kullanıcı Alani -> DMA adres yaz -> PCIe Cihaz -> RAM fiziksel adres
                                                     (TUM BELLEGE ERISIM)

  IOMMU Ile (VFIO):
  Kullanıcı Alani -> IOVA yaz -> PCIe Cihaz -> IOMMU -> Izinli RAM bölgesi
                                                         (SINIRLI ERISIM)
  

SR-IOV ve Geçiş Motivasyonu

SR-IOV (Single Root I/O Virtualization) özellikli bir NIC veya FPGA, tek bir fiziksel fonksiyonu (PF) onlarca sanal fonksiyona (VF) bölebilir. VFIO, her VF'yi ayrı bir sanal makineye güvenle geçirir: VM, donanıma doğrudan erişir ve hipervisör kopyalama yüküne maruz kalmaz. Gömülü Linuxta ise VFIO kullanıcı alanı sürücüleri (DPDK, SPDK) için temel altyapıdır.

VFIO'nun Sunduğu Güvenceler

VFIO, aşağıdaki güvenlik özelliklerini bir arada sunar:

  • IOMMU korumalı DMA: Cihaz yalnızca haritalaması yapılmış belleğe erişebilir.
  • Cihaz izolasyonu: Bir gruptaki cihazlar diğer grupları göremez.
  • Kesme izolasyonu: Her kullanıcı alanı süreci yalnızca kendi cihazının kesmelerini alır.
  • Hata kapsama: Cihaz hatası yalnızca ilgili kullanıcı sürecini etkiler; sistemi çöküşe götürmez.

01 VFIO Mimarisi

VFIO üç hiyerarşik nesne modeli üzerine kuruludur: konteyner (container), grup (group) ve cihaz (device). Bu modelin anlaşılması, VFIO kullanımının temelidir.

  +--------------------------------------------------+
  |               VFIO Container                     |
  |  (tek IOMMU adresi uzayi -- /dev/vfio/vfio)      |
  |                                                  |
  |  +---------------+    +---------------+          |
  |  |  VFIO Group   |    |  VFIO Group   |          |
  |  |  /dev/vfio/0  |    |  /dev/vfio/1  |          |
  |  |               |    |               |          |
  |  |  +---------+  |    |  +---------+  |          |
  |  |  |  Cihaz  |  |    |  |  Cihaz  |  |          |
  |  |  |  (PCI)  |  |    |  |  (PCI)  |  |          |
  |  |  +---------+  |    |  +---------+  |          |
  |  +---------------+    +---------------+          |
  +--------------------------------------------------+
  

Container (Konteyner)

Konteyner, /dev/vfio/vfio aygıt dosyasıyla temsil edilir. Bir IOMMU adresi uzayını kapsar. Kullanıcı alanı uygulaması bu dosyayı açarak IOMMU türünü sorgular ve DMA haritalamaları oluşturur. Birden fazla grup aynı konteynere bağlanabilir; bu durumda hepsi aynı IOMMU adresi uzayını paylaşır.

Group (Grup)

Grup, IOMMU'nun izolasyon birimini temsil eder. Aynı IOMMU grubundaki tüm cihazlar birbirini görür (ACS — Access Control Services yoksa). Güvenli geçiş için bir gruptaki tüm cihazların VFIO'ya bağlanmış olması gerekir. Gruplar /dev/vfio/N dosyaları olarak görünür.

Device (Cihaz)

Cihaz nesnesi, PCI konfigürasyon alanı okuma/yazma, MMIO bölgelerinin mmap'i ve kesme yapılandırması işlemlerini ioctl arayüzü ile sunar. Bir kullanıcı alanı sürücüsü, cihaz nesnesi aracılığıyla donanıma sanki çekirdek sürücüsüymüş gibi erişir.

IOMMU Domain Bağlaması

Bir grup konteynere bağlandığında, VFIO o gruba ait cihazları kernel'in IOMMU sürücüsü aracılığıyla konteyner IOMMU domain'ine atar. Artık DMA haritalamaları (VFIO_IOMMU_MAP_DMA ioctl) fiziksel bellekle IOVA arasında birebir eşlemeler oluşturur.

/* VFIO acilis sirasi */
int container = open("/dev/vfio/vfio", O_RDWR);
int group     = open("/dev/vfio/42",   O_RDWR);

/* Grubu konteynere bagla */
ioctl(group, VFIO_GROUP_SET_CONTAINER, &container);

/* IOMMU turunu etkinlestir */
ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU);

/* Cihaz taniticisi al */
int device = ioctl(group, VFIO_GROUP_GET_DEVICE_FD, "0000:03:00.0");

IOMMU Türleri

IOMMU TürüAçıklamaPlatform
VFIO_TYPE1_IOMMUTemel IOVA çeviri, pinned pagesx86 Intel VT-d / AMD-Vi
VFIO_TYPE1v2_IOMMUMAP sırasında sayfa pinleme + dirty trackingx86 gelişmiş
VFIO_ARM_SMMU_V3_IOMMUARM SMMUv3 doğrudan destekARM64 SoC
VFIO_NOIOMMU_IOMMUIOMMU koruması YOK; yalnızca test içinTüm platformlar

02 Cihaz Bağlama

Bir PCIe cihazını VFIO'ya bağlamak için önce mevcut çekirdek sürücüsünü ayırmak (unbind), ardından cihazı vfio-pci sürücüsüne bağlamak (bind) gerekir.

Gerekli Çekirdek Modülleri

# IOMMU desteğini kernel komut satırında etkinlestir
# GRUB: intel_iommu=on veya amd_iommu=on
# /etc/default/grub dosyasinda:
# GRUB_CMDLINE_LINUX="intel_iommu=on iommu=pt"

# VFIO modullerini yukle
modprobe vfio
modprobe vfio_pci
modprobe vfio_iommu_type1

# Modullerın yuklendigini dogrula
lsmod | grep vfio
# vfio_pci              65536  0
# vfio_iommu_type1      36864  0
# vfio                  36864  2 vfio_pci,vfio_iommu_type1

Cihazı Belirleme

# Hedef PCI cihazini bul (ornek: Ethernet kontroloru)
lspci -nn | grep -i ethernet
# 03:00.0 Ethernet controller [0200]: Intel XL710 [8086:1572]

# Cihazin IOMMU grubunu bul
readlink /sys/bus/pci/devices/0000:03:00.0/iommu_group
# ../../../kernel/iommu_groups/42

# Gruptaki tum cihazlari listele (hepsini VFIO'ya baglamak gerekebilir)
ls /sys/kernel/iommu_groups/42/devices/
# 0000:03:00.0
# 0000:03:00.1

Mevcut Sürücüyü Ayır (Unbind)

# Mevcut surucuyu bul
cat /sys/bus/pci/devices/0000:03:00.0/driver/module/drivers

# Suruculen ayir
echo "0000:03:00.0" > /sys/bus/pci/devices/0000:03:00.0/driver/unbind

# Cihazin surucusuz kaldığını dogrula
ls -l /sys/bus/pci/devices/0000:03:00.0/driver
# (baglantin yok)

vfio-pci'ye Bağla (Bind)

# Vendor/Device ID ogren
cat /sys/bus/pci/devices/0000:03:00.0/vendor  # 0x8086
cat /sys/bus/pci/devices/0000:03:00.0/device  # 0x1572

# Cihazi vfio-pci'ye yonlendir
echo "8086 1572" > /sys/bus/pci/drivers/vfio-pci/new_id

# Alternatif: dogrudan bind
echo "0000:03:00.0" > /sys/bus/pci/drivers/vfio-pci/bind

# Basariyi dogrula
ls /dev/vfio/
# vfio  42

Otomatik Bağlama: vfio-pci Modül Parametresi

# Sistem baslangicindan itibaren otomatik baglama icin
# /etc/modprobe.d/vfio.conf dosyasina ekle:
options vfio-pci ids=8086:1572,8086:1573

# GRUB'da da belirtilabilir:
# vfio-pci.ids=8086:1572,8086:1573

IOMMU Grup Durumunu Kontrol Et

# Tum cihazlarin gruba baglandigini dogrula
for dev in /sys/kernel/iommu_groups/42/devices/*; do
    bdf=$(basename $dev)
    driver=$(readlink $dev/driver | awk -F/ '{print $NF}')
    echo "$bdf: $driver"
done
# 0000:03:00.0: vfio-pci  -- dogru
# 0000:03:00.1: vfio-pci  -- dogru (her ikisi de bağlı olmali)
iommu=ptPass-through modu: IOMMU yalnızca cihaz geçişinde devreye girer, sistem genelinde ek yük azalır
iommu=onTüm cihazlar için IOMMU çevirisi; en güvenli ama en yüksek yük
intel_iommu=onIntel VT-d etkinleştirme parametresi
amd_iommu=onAMD-Vi etkinleştirme parametresi

03 Kullanıcı Alanından DMA

VFIO'nun en güçlü özelliği, kullanıcı alanından DMA haritalamaları oluşturabilmektir. IOMMU koruması altında, kullanıcı alanı belleği cihaza güvenle gösterilebilir.

DMA Belleği Tahsis Etme

DMA tamponu için kullanılacak bellek, sayfaların fiziksel olarak sabitlenmiş (pinned) ve ardışık (contiguous) veya IOMMU ile eşlenmiş olması gerekir. Tipik yaklaşım huge pages kullanmaktır; VFIO, sayfaları otomatik olarak pinler.

#include <linux/vfio.h>
#include <sys/mman.h>

/* 2 MB huge page tahsis et */
void *dma_buf = mmap(NULL, 2 * 1024 * 1024,
                     PROT_READ | PROT_WRITE,
                     MAP_PRIVATE | MAP_ANONYMOUS |
                     MAP_HUGETLB | MAP_HUGE_2MB,
                     -1, 0);

if (dma_buf == MAP_FAILED) {
    perror("mmap huge page");
    exit(1);
}

VFIO_IOMMU_MAP_DMA ile IOVA Eşleme

Bellek tahsis edildikten sonra VFIO_IOMMU_MAP_DMA ioctl ile IOMMU'ya kaydettirilir. Cihaza verilecek adres IOVA'dır (fiziksel adres değil).

struct vfio_iommu_type1_dma_map dma_map = {
    .argsz = sizeof(dma_map),
    .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE,
    .vaddr = (uint64_t)(uintptr_t)dma_buf,  /* Sanal adres */
    .iova  = 0x10000000,                    /* Cihazin gorecegi IOVA */
    .size  = 2 * 1024 * 1024,
};

if (ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map)) {
    perror("VFIO_IOMMU_MAP_DMA");
    exit(1);
}

/* Artik cihaza 0x10000000 adresi verilebilir */
printf("DMA haritasi kuruldu: IOVA=0x%lx\n", dma_map.iova);

MMIO Bölgelerini mmap ile Açma

Cihazın BAR (Base Address Register) bölgeleri VFIO_DEVICE_GET_REGION_INFO ile sorgulanır, ardından mmap ile kullanıcı alanına açılır.

struct vfio_region_info reg = {
    .argsz = sizeof(reg),
    .index = VFIO_PCI_BAR0_REGION_INDEX,
};

ioctl(device, VFIO_DEVICE_GET_REGION_INFO, ®);

/* BAR0'i mmap et */
void *bar0 = mmap(NULL, reg.size,
                  PROT_READ | PROT_WRITE,
                  MAP_SHARED,
                  device,
                  reg.offset);

if (bar0 == MAP_FAILED) {
    perror("BAR0 mmap");
    exit(1);
}

/* Dogrudan kayit erisimi */
volatile uint32_t *ctrl_reg = (uint32_t *)bar0;
*ctrl_reg = 0x1;  /* DMA baslat */

/* Tamamlanma bitini bekle */
while (!(*ctrl_reg & 0x2))
    ;

DMA Eşlemesini Kaldırma

struct vfio_iommu_type1_dma_unmap dma_unmap = {
    .argsz = sizeof(dma_unmap),
    .flags = 0,
    .iova  = 0x10000000,
    .size  = 2 * 1024 * 1024,
};

ioctl(container, VFIO_IOMMU_UNMAP_DMA, &dma_unmap);
munmap(dma_buf, 2 * 1024 * 1024);

Çoklu DMA Bölgesi Yönetimi

Gerçek uygulamalarda birden fazla DMA bölgesi (RX halkası, TX halkası, kontrol yapıları) gerekir. Her biri için ayrı VFIO_IOMMU_MAP_DMA çağrısı yapılır ve IOVA uzayı çakışmayacak biçimde planlanır.

#define IOVA_RX_BASE   0x10000000
#define IOVA_TX_BASE   0x20000000
#define IOVA_CTRL_BASE 0x30000000
#define DMA_BUF_SIZE   (2 * 1024 * 1024)

/* RX tamponu */
void *rx_buf = mmap_hugepage(DMA_BUF_SIZE);
vfio_map_dma(container, rx_buf, IOVA_RX_BASE, DMA_BUF_SIZE);

/* TX tamponu */
void *tx_buf = mmap_hugepage(DMA_BUF_SIZE);
vfio_map_dma(container, tx_buf, IOVA_TX_BASE, DMA_BUF_SIZE);

04 Kesme Yönetimi

VFIO, cihaz kesmelerini kullanıcı alanına eventfd mekanizması aracılığıyla iletir. Bu yaklaşım, kullanıcı alanı sürücüsünün busy-poll yapmak zorunda kalmadan kesmeleri verimli biçimde almasını sağlar.

Kesme Bilgisi Sorgulama

#include <linux/vfio.h>

struct vfio_irq_info irq_info = {
    .argsz = sizeof(irq_info),
    .index = VFIO_PCI_MSI_IRQ_INDEX,
};

if (ioctl(device, VFIO_DEVICE_GET_IRQ_INFO, &irq_info)) {
    perror("VFIO_DEVICE_GET_IRQ_INFO");
    exit(1);
}

printf("MSI kesmesi sayisi: %u\n", irq_info.count);
printf("Flags: 0x%x\n", irq_info.flags);
/* VFIO_IRQ_INFO_EVENTFD: eventfd destekli */
/* VFIO_IRQ_INFO_MASKABLE: maskelenebilir  */
/* VFIO_IRQ_INFO_AUTOMASKED: otomatik maskeleme */

eventfd ile Kesme Yapılandırma

Her MSI/MSI-X vektörü için bir eventfd oluşturulur. VFIO_DEVICE_SET_IRQS ioctl bu eventfd'leri cihaz kesmelerine bağlar.

#include <sys/eventfd.h>

/* Kesme basina eventfd olustur */
int irq_fd = eventfd(0, 0);
if (irq_fd < 0) {
    perror("eventfd");
    exit(1);
}

/* VFIO_DEVICE_SET_IRQS yapisi dinamik boyutludur */
struct vfio_irq_set *irq_set;
int irq_set_size = sizeof(*irq_set) + sizeof(int);
irq_set = calloc(1, irq_set_size);

irq_set->argsz = irq_set_size;
irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
                 VFIO_IRQ_SET_ACTION_TRIGGER;
irq_set->index = VFIO_PCI_MSI_IRQ_INDEX;
irq_set->start = 0;
irq_set->count = 1;

/* eventfd dosya taniticisini yerlestiр */
memcpy(irq_set->data, &irq_fd, sizeof(irq_fd));

if (ioctl(device, VFIO_DEVICE_SET_IRQS, irq_set)) {
    perror("VFIO_DEVICE_SET_IRQS");
    exit(1);
}
free(irq_set);

Kesme Bekleme ve İşleme

#include <poll.h>

struct pollfd pfd = {
    .fd     = irq_fd,
    .events = POLLIN,
};

while (1) {
    int ret = poll(&pfd, 1, -1);  /* Sonsuz bekleme */
    if (ret < 0) {
        perror("poll");
        break;
    }

    if (pfd.revents & POLLIN) {
        uint64_t count;
        read(irq_fd, &count, sizeof(count));
        printf("Kesme alindi! Sayac: %lu\n", count);
        /* Donanim kesme isleyicisi... */
        handle_interrupt();
    }
}

IRQ Maskeleme ve Aç

İşlem süresince kesmeler maskelenebilir; bu, boyutlu işleme (batched processing) için gereklidir.

/* Maskeleme icin eventfd olustur */
int mask_fd = eventfd(0, 0);

irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
                 VFIO_IRQ_SET_ACTION_MASK;
memcpy(irq_set->data, &mask_fd, sizeof(mask_fd));
ioctl(device, VFIO_DEVICE_SET_IRQS, irq_set);

/* Kesmeyi maskele */
uint64_t val = 1;
write(mask_fd, &val, sizeof(val));

/* ... toplu isleme ... */

/* Kesmeyi ac (unmask) */
irq_set->flags = VFIO_IRQ_SET_DATA_NONE |
                 VFIO_IRQ_SET_ACTION_UNMASK;
ioctl(device, VFIO_DEVICE_SET_IRQS, irq_set);
Kesme TürüVFIO İndeksiAçıklama
INTx (legacy)VFIO_PCI_INTX_IRQ_INDEXEski PCIe kesmesi; paylaşımlı, yavaş
MSIVFIO_PCI_MSI_IRQ_INDEXMesaj tabanlı kesme; genellikle 1 vektör
MSI-XVFIO_PCI_MSIX_IRQ_INDEXÇok vektörlü MSI; NIC queue başına kesme
HataVFIO_PCI_ERR_IRQ_INDEXPCIe hata bildirimleri

05 VFIO-platform

vfio-pci PCIe cihazlar içindir; gömülü sistemlerdeki platform cihazları (MMIO tabanlı, DT ile tanımlı IP blokları) için vfio-platform kullanılır. Bu, ARM SoC'larında FPGA blokları veya doğrudan adreslenebilir donanım hızlandırıcıları için kritik öneme sahiptir.

vfio-platform Mimarisi

vfio-platform, vfio_platform_device yapısı aracılığıyla platform cihazının MMIO bölgelerini ve kesmelerini, PCI'ya özgü olmayan bir arayüzle kullanıcı alanına sunar. SMMU (ARM'ın IOMMU'su) ile birlikte DMA koruması da sağlanır.

# Gerekli moduller
modprobe vfio
modprobe vfio_platform
modprobe vfio_iommu_type1

Platform Cihazını VFIO'ya Bağlama

# Platform cihazini bul
ls /sys/bus/platform/devices/ | grep fpga
# fpga@40000000

# Mevcut suruculen ayir
echo "fpga@40000000" > \
  /sys/bus/platform/devices/fpga@40000000/driver/unbind

# vfio-platform'a bagla
echo "fpga@40000000" > \
  /sys/bus/platform/drivers/vfio-platform/bind

# VFIO grubu olustu mu?
ls /dev/vfio/

Device Tree'de Reset Sağlayıcısı

Platform cihazları için VFIO, cihazın kullanıcı alanına geçmeden önce sıfırlanıp sıfırlanamayacağını kontrol eder. Cihazın bir reset mekanizması yoksa DT'ye özellik eklenmesi gerekebilir:

/* DT'de vfio-platform icin reset saglayicisi */
fpga: fpga@40000000 {
    compatible = "vendor,my-fpga";
    reg = <0x40000000 0x10000>;
    interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
    resets = <&reset_controller 5>;
    reset-names = "fpga-reset";
    iommus = <&smmu 0x100>; /* SMMU stream ID */
};

Gömülü Kullanım Senaryosu

Gerçek zamanlı bir sinyal işleme uygulamasında FPGA hızlandırıcısının vfio-platform ile kullanıcı alanına geçirilmesi şu avantajları sağlar: çekirdek modülü yazma gerekmez, güncelleme için yeniden başlatma gerekmez ve süreç izolasyonu garanti edilir.

/* vfio-platform kullanici alani erisimi -- platform'a ozgu bolgeler */
struct vfio_region_info reg = {
    .argsz = sizeof(reg),
    .index = 0,  /* Ilk MMIO bolgesi */
};
ioctl(device_fd, VFIO_DEVICE_GET_REGION_INFO, ®);

void *mmio = mmap(NULL, reg.size,
                  PROT_READ | PROT_WRITE,
                  MAP_SHARED, device_fd, reg.offset);

/* FPGA registerlerina dogrudan eris */
volatile uint32_t *fpga_ctrl = (uint32_t *)mmio;
fpga_ctrl[0] = 0x1;  /* Islemi baslat */

/* Islem tamamlandi mi? */
while (!(fpga_ctrl[1] & 0x1))
    ;  /* Durum bitini bekle */

vfio-platform ve vfio-pci Karşılaştırması

vfio-pciPCIe veri yolu; BAR bölgeleri, PCIe config space, MSI/MSI-X; x86 ve ARM
vfio-platformPlatform veri yolu (DT); MMIO bölgeleri, GIC kesmesi; gömülü ARM SoC
SMMUARM SystemMMU; vfio-platform için IOMMU sağlayıcısı
reset zorunluluğuvfio-platform, cihaz reset mekanizması olmadan çalışmayı reddedebilir

06 DPDK ve VFIO

DPDK (Data Plane Development Kit), yüksek hızlı ağ paketi işlemesi için kullanıcı alanı PMD (Poll Mode Driver) sürücüleri sunar. VFIO, DPDK'nın IOMMU korumalı DMA ortamında çalışması için tercih edilen altyapıdır.

DPDK VFIO Mimarisi

  Kullanici Alani:
  +------------------------------------------+
  |           DPDK Uygulamasi                |
  |  +---------------+  +----------------+  |
  |  | rte_eal_init  |  |  PMD Surucusu  |  |
  |  | (VFIO init)   |->| (i40e, ixgbe)  |  |
  |  +---------------+  +----------------+  |
  +---------------------+--------------------+
                        | VFIO ioctl
  +---------------------v--------------------+
  |      Linux Kernel (VFIO + IOMMU)         |
  +------------------------------------------+
  

Huge Pages Yapılandırması

DPDK, DMA tamponları için büyük sayfa (huge page) kullanır. Bu sayfalar VFIO_IOMMU_MAP_DMA ile IOMMU'ya kaydettirilir.

# 1 GB huge page rezervasyonu (kernel komut satirinda)
# hugepagesz=1G hugepages=4 default_hugepagesz=1G

# Calisma aninda 2 MB huge page
echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

# Huge page mount noktasi
mkdir -p /dev/hugepages
mount -t hugetlbfs nodev /dev/hugepages

# Hugepage durumu kontrol et
cat /proc/meminfo | grep Huge
# HugePages_Total: 1024
# HugePages_Free:  1024
# Hugepagesize:    2048 kB

DPDK ile NIC Bağlama

# dpdk-devbind.py ile cihazi VFIO'ya bagla
dpdk-devbind.py --bind=vfio-pci 03:00.0

# Baglama durumunu kontrol et
dpdk-devbind.py --status-dev net

# DPDK uygulamasini VFIO ile baslat
./dpdk-testpmd \
    -l 0-3 \
    -n 4 \
    --vfio-intr=msi \
    -- \
    --portmask=0x1 \
    --nb-cores=2 \
    --rxq=2 \
    --txq=2 \
    -i

Zero-Copy Paket İşleme

DPDK + VFIO kombinasyonu sayesinde ağ paketi NIC DMA tamponundan doğrudan uygulama belleğine kopyalanır; çekirdek arabelleği devreye girmez. Bu, 10 Gbps üzerindeki hızlarda bile düşük gecikme garantisi sağlar.

/* DPDK mbuf dogrudan NIC DMA bolgesinden geliyor */
struct rte_mbuf *pkt;
while (rte_eth_rx_burst(port_id, queue_id, &pkt, 1) == 1) {
    /* Sifir kopya: veri NIC DMA tamponunda, mbuf pointer tutuyor */
    uint8_t  *data = rte_pktmbuf_mtod(pkt, uint8_t *);
    uint16_t  len  = rte_pktmbuf_data_len(pkt);

    /* Basit islem: UDP payload'i al */
    process_packet(data, len);

    rte_pktmbuf_free(pkt);
}
Avantaj: GecikmeÇekirdek kopyalaması yok; tek DMA transferi yeterli
Avantaj: GüvenlikIOMMU DMA koruma, NIC yalnızca ayrılmış belleğe erişebilir
Gereksinim: IOMMUintel_iommu=on veya amd_iommu=on kernel parametresi şart
Gereksinim: Huge PagesDMA tamponları için büyük sayfa şart; küçük sayfa DMA eşlemesi pahalıdır

07 QEMU/KVM ile Cihaz Geçişi

VFIO'nun en yaygın kullanım senaryolarından biri, bir PCIe cihazı (GPU, NIC, FPGA) doğrudan bir KVM sanal makinesine geçirmektir. Sanal makine cihaza doğrudan erişir; hipervisör öykünme yükü sıfıra yaklaşır.

QEMU ile PCIe Geçişi

qemu-system-x86_64 \
  -enable-kvm \
  -m 8192 \
  -cpu host \
  -smp 4 \
  \
  -device vfio-pci,host=03:00.0,id=passthrough_nic \
  \
  -drive file=vm.qcow2,format=qcow2 \
  \
  -netdev user,id=mgmt \
  -device virtio-net,netdev=mgmt \
  \
  -nographic

Çoklu Cihaz Geçişi (SR-IOV VF)

SR-IOV destekli bir NIC'ten sanal fonksiyonlar (VF) oluşturarak her VM'e ayrı VF geçirilebilir. Bu, ağ yoğun iş yüklerinde fiziksel NIC'i birden fazla VM arasında doğrudan paylaştırır.

# PF uzerinde VF olustur (i40e surucusu)
echo 4 > /sys/bus/pci/devices/0000:03:00.0/sriov_numvfs

# Olusturulan VF'leri listele
lspci | grep "Virtual Function"
# 03:02.0 Ethernet controller: Intel XL710 VF
# 03:02.1 Ethernet controller: Intel XL710 VF

# Her VF'yi ayri VFIO grubuna bagla
dpdk-devbind.py --bind=vfio-pci 03:02.0
dpdk-devbind.py --bind=vfio-pci 03:02.1

# VM1'e VF gecir
qemu-system-x86_64 -enable-kvm \
    -device vfio-pci,host=03:02.0 \
    -m 4096 vm1.qcow2 &

# VM2'ye VF gecir
qemu-system-x86_64 -enable-kvm \
    -device vfio-pci,host=03:02.1 \
    -m 4096 vm2.qcow2 &

Huge Page ve IOMMU Zorunlulukları

# KVM + VFIO icin GRUB parametreleri (/etc/default/grub)
# GRUB_CMDLINE_LINUX="intel_iommu=on iommu=pt
#   hugepagesz=1G hugepages=16
#   default_hugepagesz=1G"

# QEMU'ya huge page bellek tahsisi
qemu-system-x86_64 \
  -m 8G \
  -mem-path /dev/hugepages \
  -mem-prealloc \
  -enable-kvm \
  -cpu host \
  -device vfio-pci,host=03:00.0

PCIe ACS (Access Control Services)

IOMMU izolasyonu için PCIe cihazlar arası ACS etkinleştirilmelidir. Aksi takdirde aynı PCIe köprüsü altındaki cihazlar birbirinin DMA trafiğini görebilir ve aynı IOMMU grubuna düşer.

# ACS durumunu kontrol et
lspci -vvv | grep -A2 "Access Control"

# ACS override (test ortami -- uretimde dikkatli kullan)
# Kernel parametresi: pcie_acs_override=downstream,multifunction

GPU Geçişi Örneği

# Nvidia GPU'yu VFIO'ya bagla
echo "10de:2204" > /sys/bus/pci/drivers/vfio-pci/new_id

# QEMU ile GPU passthrough
qemu-system-x86_64 \
  -enable-kvm \
  -m 16G \
  -cpu host,hv_relaxed,hv_spinlocks=0x1fff,hv_vapic,hv_time \
  -device vfio-pci,host=01:00.0,multifunction=on,x-vga=on \
  -device vfio-pci,host=01:00.1 \
  -vga none \
  -nographic \
  win11.qcow2

08 Hata Ayıklama

VFIO sorunlarının büyük çoğunluğu IOMMU yapılandırması, grup izolasyonu veya sürücü çakışmalarından kaynaklanır. Sistematik bir hata ayıklama süreci bu sorunları hızla tespit eder.

IOMMU ve VFIO Durumu Kontrolü

# IOMMU etkin mi?
dmesg | grep -i iommu | head -20
# [    0.123456] DMAR: IOMMU enabled
# [    0.234567] iommu: Default domain type: Translated

# VFIO grup durumu
ls -la /dev/vfio/
# crw------- 1 root root 246, 0 ... /dev/vfio/vfio
# crw------- 1 root root 246, 1 ... /dev/vfio/42

# Grup sahipligini kullaniciya ver
chown emirpehlevan /dev/vfio/42

dmesg IOMMU Hata Mesajları

# IOMMU fault loglarini izle
dmesg -w | grep -E "iommu|DMAR|vfio"

# Yaygin IOMMU hata mesajlari:
# DMAR: DRHD: handling fault status reg 3
# DMAR: [DMA Read] Request device [03:00.0] fault addr 0xdeadbeef
# Bunlar genellikle IOVA eslenenmis adrese DMA denemesini gosterir

# IOMMU domain bilgisi (debugfs)
cat /sys/kernel/debug/iommu/devices

VFIO Grup Durumu Sorgulama

#include <linux/vfio.h>

/* Grup durumunu sorgula */
struct vfio_group_status status = {
    .argsz = sizeof(status),
};

int group_fd = open("/dev/vfio/42", O_RDWR);
ioctl(group_fd, VFIO_GROUP_GET_STATUS, &status);

if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
    fprintf(stderr, "Grup uygun degil: "
            "grupdaki tum cihazlar vfio-pci'ye baglanmali\n");
}
if (!(status.flags & VFIO_GROUP_FLAGS_CONTAINER_SET)) {
    fprintf(stderr, "Grup henuz konteynere baglanmamis\n");
}

lspci ile Cihaz Sürücü Kontrolü

# Cihaz suruculunu dogrula
lspci -k -s 03:00.0
# 03:00.0 Ethernet controller: Intel XL710
#         Subsystem: Intel Ethernet CNA X710
#         Kernel driver in use: vfio-pci
#         Kernel modules: i40e

# Tum VFIO cihazlarini listele
for bdf in /sys/bus/pci/drivers/vfio-pci/*/; do
    echo $(basename $bdf)
done

IOMMU Bilgi Sorgulama

/* IOMMU bilgisini ioctl ile al */
struct vfio_iommu_type1_info iommu_info = {
    .argsz = sizeof(iommu_info),
};
ioctl(container, VFIO_IOMMU_GET_INFO, &iommu_info);

printf("IOMMU flags: 0x%x\n",  iommu_info.flags);
printf("IOMMU PGSIZE: 0x%lx\n", iommu_info.iova_pgsizes);
/* Desteklenen sayfa boyutlari: 0x1000 (4KB), 0x200000 (2MB) */
SorunOlası NedenÇözüm
VFIO_GROUP_FLAGS_VIABLE değilGruptaki bir cihaz hâlâ kernel sürücüsüne bağlıTüm grup cihazlarını unbind + vfio-pci bind
VFIO_IOMMU_MAP_DMA EINVALIOVA hizalaması veya aralık sorunuIOMMU sayfa boyutuna hizala (4KB/2MB/1GB)
IOMMU DMA faultEşlenmemiş IOVA'ya DMA denemesiDMA adres hesabını ve MAP_DMA çağrısını kontrol et
lspci sürücü "vfio-pci" değilbind komutu başarısızdmesg'de hata oku; cihaz ID doğrula
Kesme alınamıyorMSI desteklenmiyor ya da grup konteynere bağlanmamışVFIO_PCI_INTX_IRQ_INDEX ile başla; group container set kontrol et