SR-IOV (Single Root I/O Virtualization)

SR-IOV 하드웨어 가상화 기술: PF/VF 개념, VF 리소스 할당, 커널 API, PF/VF 드라이버 구현, IOMMU+VFIO VM 패스스루, sysfs 관리, 성능 최적화

전제 조건: PCI / PCIe 서브시스템디바이스 드라이버 문서를 먼저 읽으세요. SR-IOV는 PCIe Extended Capability 위에 구축되므로, PCI 아키텍처와 드라이버 프레임워크의 기본 개념이 필요합니다.
일상 비유: SR-IOV는 하나의 고속도로 톨게이트를 여러 전용 차로로 나누는 것과 비슷합니다. 각 차로(VF)는 독립적으로 운영되어 서로 간섭 없이 동시에 통행할 수 있습니다.

SR-IOV(Single Root I/O Virtualization)는 PCI-SIG 표준(ECN SR-IOV 1.1)에 정의된 하드웨어 가상화 기술입니다. 하나의 물리 PCIe 디바이스(PF, Physical Function)를 여러 경량 가상 디바이스(VF, Virtual Function)로 분할하고, 각 VF에 독립적인 Config Space·BAR·MSI-X·TX/RX 큐를 부여하여 VM에 직접 패스스루(passthrough)합니다. IOMMU가 VF별 DMA 격리를 보장하므로, 에뮬레이션 오버헤드 없이 네이티브 대비 5% 이내 성능 손실로 I/O 가속이 가능합니다. 고성능 NIC(Intel X710/E810, Mellanox ConnectX), NVMe SSD, HBA, RDMA 가속기 등에 널리 적용됩니다.

SR-IOV 아키텍처 — PF/VF 분할과 VM 직접 할당 Host CPU & PCIe Root Complex IOMMU (Intel VT-d / AMD-Vi) — VF별 독립 DMA Domain 생성 Physical NIC (예: Intel X710 / Mellanox ConnectX-6) PF (Physical Function) BDF: 0000:03:00.0 Full Config Space (256B/4KB) 전체 BAR·큐·펌웨어 제어 호스트 드라이버 (i40e) SR-IOV Capability 보유 VF 0 03:00.2 경량 Config Space VF BAR0 (MMIO) MSI-X 2 벡터 TX/RX 큐 2쌍 VF 1 03:00.3 경량 Config Space VF BAR0 (MMIO) MSI-X 2 벡터 TX/RX 큐 2쌍 VF 2 03:00.4 경량 Config Space VF BAR0 (MMIO) MSI-X 2 벡터 TX/RX 큐 2쌍 VF N-1 최대 63 VF IOMMU — VF별 독립 Domain (DMA 격리) Group 15 (PF) Group 16 (VF 0) Group 17 (VF 1) Group 18 (VF 2) Host (PF 관리) i40e / ixgbe 드라이버 MAC/VLAN/QoS 정책 제어 VM 1 VF 0 직접 접근 vfio-pci 드라이버 VM 2 VF 1 직접 접근 vfio-pci 드라이버 VM 3 VF 2 직접 접근 vfio-pci 드라이버 각 VF는 별도 IOMMU 그룹 → DMA 격리 보장. VFIO를 통해 VM에 안전하게 패스스루 PF 드라이버(호스트)가 mailbox API로 VF MAC 주소·VLAN·대역폭 정책 통제 VM은 VF를 마치 전용 NIC처럼 사용 → 에뮬레이션 없이 거의 네이티브 성능

PF / VF 핵심 개념

개념설명특이사항
PF (Physical Function) 전체 디바이스 기능을 가진 물리 함수. SR-IOV Capability 보유. 호스트 드라이버가 직접 관리 VF 생성·삭제·MAC·VLAN·QoS 정책을 PF 드라이버가 제어 (mailbox)
VF (Virtual Function) 경량화된 가상 함수. 독립적 PCIe Config Space(일부)·BAR·MSI-X·TX/RX 큐 보유 Config Space 일부(전원 관리 등)는 PF가 가상화. VF 자체는 리셋·전원 제어 불가
VF BAR PF의 SR-IOV Capability에 정의된 VF 전용 MMIO BAR 영역. NumVFs × VF_BAR_size로 연속 매핑 VF[n] BAR 기준주소 = VF BAR 기준 + n × VF_BAR_size
First VF Offset / VF Stride VF의 Routing ID(BDF) 간격과 첫 VF BDF 오프셋. SR-IOV Capability 레지스터에 하드코딩 VF[n] BDF = PF BDF + FirstVFOffset + n × VFStride
ARI (Alt. Routing-ID) Function 번호를 8비트로 확장 — 한 디바이스에 최대 256개 Function 허용 PCIe 2.1 이상, ARI 지원 루트 포트 필요. 대규모 VF(예: 64개+)에 필수
IOMMU 그룹 격리 각 VF는 별도 IOMMU 그룹에 배치 → DMA 격리 보장. 단독 VFIO 패스스루 가능 ACS 미지원 스위치 아래에서는 PF와 VF가 동일 그룹이 될 수 있음 — lspci로 확인
Mailbox PF ↔ VF 간 메시지 채널. VF가 MAC/VLAN 변경·링크 상태 등을 PF에 요청 보안 경계: VM이 임의 MAC 스푸핑·VLAN 침입 불가 (PF가 화이트리스트 관리)

SR-IOV PCIe Extended Capability 구조

SR-IOV Extended Capability(Cap ID 0x0010)는 PCIe Extended Configuration Space(오프셋 0x100 이상)에 위치하며 PF에서만 노출됩니다. VF 수·BAR 크기·Stride 등을 하드웨어 레지스터로 기술합니다.

SR-IOV Extended Capability 레지스터 레이아웃 (PF only) 오프셋 레지스터 설명 및 주요 필드 +0x00 32비트 SR-IOV Ext. Cap Header Cap ID = 0x0010 [15:0] Cap ID(0x10) [19:16] Cap Version [31:20] Next Cap Ptr lspci에서 "SR-IOV" 출력 근거 +0x04 SR-IOV Capabilities [0] VF Migration [21] ARI Capable VF Migration 지원 여부, ARI Capable Hierarchy pci_sriov_capable() 내부에서 참조 +0x08 16b + 16b SR-IOV Control / Status Control[0] VF Enable Control[2] VF MSE Control[4] ARI VF Enable=1 → VF Config Space 버스에 노출 VF MSE(Memory Space Enable) — VF BAR MMIO 활성화 커널이 pci_enable_sriov() 시 이 비트를 자동 셋 +0x0C InitialVFs / TotalVFs [15:0] InitialVFs [31:16] TotalVFs TotalVFs: 하드웨어 지원 최대 VF 수 (RO) sriov_totalvfs sysfs 노드 값의 근거 +0x10 NumVFs / FuncDepLink [15:0] NumVFs (RW) [31:16] FuncDepLink NumVFs: 실제 활성화할 VF 수 (0 ~ TotalVFs, RW) sriov_numvfs에 쓰면 커널이 이 레지스터를 설정 +0x14 First VF Offset / VF Stride [15:0] FirstVFOffset [31:16] VFStride VF[n] BDF = PF BDF + FirstVFOffset + n × VFStride PCIe 라우팅 ID(BDF) 계산에 사용 (RO) +0x18 VF Device ID [31:16] VF Device ID (RO) VF Config Space에 노출되는 Device ID (PF의 Vendor ID는 공유) VF 드라이버의 pci_device_id 테이블 매칭에 사용 +0x24 ~ +0x38 6×32비트 VF BAR 0 ~ 5 VF MMIO 주소 공간 크기 인코딩 (PF BAR과 별도, VF 전용) VF BAR 크기는 PCI-compatible alignment 인코딩 pci_enable_sriov() 시 커널이 VF BAR 전체 범위를 NumVFs × VF_BAR_size 크기로 연속 할당 VF BDF 계산 공식 VF[n] BDF = PF BDF + FirstVFOffset + n × VFStride (ARI 모드: 8비트 Function 번호 사용) lspci -vvv 출력 예시 (PF의 SR-IOV Capability) Capabilities: [180] Single Root I/O Virtualization (SR-IOV) IOVCap: Migration- Interrupt Message Number: 000 IOVCtl: Enable+ VF MSE+ ARI+ Initial VFs: 64, Total VFs: 64, Number of VFs: 4, Function Dependency Link: 00 First VF Offset: 128, VF Stride: 1, VF Device ID: 154c [VF BAR0-5 ...]

VF 리소스 할당 구조

SR-IOV 활성화 시 NIC의 물리 자원(TX/RX 큐, MSI-X 벡터, MMIO BAR 공간)이 VF 수에 맞게 분할됩니다. VF별로 독립적인 MMIO BAR 공간이 연속으로 매핑되어 게스트 드라이버가 직접 레지스터를 접근합니다.

SR-IOV VF 리소스 할당 (Intel X710 NIC 기준, NumVFs=4) PCIe MMIO 주소 공간 MSI-X 벡터 할당 TX/RX 큐 분할 PF BAR0 (128KB MMIO) 글로벌 제어·펌웨어·전체 큐 제어 VF BAR0 연속 영역 (128KB) = 4 VF × 32KB VF 0 MMIO +0x000000 (32KB) VF 1 MMIO +0x008000 (32KB) VF 2 MMIO +0x010000 (32KB) VF 3 MMIO +0x018000 (32KB) VF[n] 기준 = VF BAR 기준 + n×32KB PF MSI-X 128 벡터 관리·링크·에러 인터럽트 전용 VF 0 MSI-X 2 벡터 벡터 0: TX 완료 벡터 1: RX 수신 VF 1 MSI-X 2 벡터 벡터 0: TX 완료 벡터 1: RX 수신 VF 2 MSI-X 2 벡터 벡터 0: TX 완료 벡터 1: RX 수신 VF 3 MSI-X 2 벡터 벡터 0: TX 완료 벡터 1: RX 수신 PF 큐 32쌍 (TX+RX) 호스트 네이티브 I/O 전용 VF 0 큐 2쌍 (TX[0]+RX[0]) 큐 번호 = VF_idx × 큐수 VF 1 큐 2쌍 (TX[2]+RX[2]) VF 2 큐 2쌍 (TX[4]+RX[4]) VF 3 큐 2쌍 (TX[6]+RX[6]) VF Config Space = Vendor/Device ID + BAR 주소 + MSI-X Capability 만 노출 (전원 관리 등 제거) VF 드라이버: BAR0 ioremap → TX/RX 디스크립터 링 물리 주소 MMIO 레지스터에 직접 기록 → DMA 시작 자원 요약 (Intel X710 기준) • 총 TX/RX 큐: 512쌍 → PF 최대 256쌍 + VF당 최대 16쌍 • MSI-X: PF 128개 + VF당 1~4개 (디바이스별 상이) • 최대 VF 수: 64개 (ARI 활성화 시) VF 드라이버 동작 핵심 ① VF BAR0 ioremap → TX/RX 링 물리 주소 레지스터에 기록 ② MSI-X 벡터로 TX 완료 / RX 수신 인터럽트 처리 ③ mailbox로 PF에 MAC/VLAN 설정 요청

커널 API

#include <linux/pci.h>

/* ── VF 활성화 / 비활성화 ── */
/* PF 드라이버에서 num_vfs개 VF 활성화. 성공 시 num_vfs 반환 */
int  pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);

/* 모든 VF 비활성화. VM에 할당된 VF 있으면 호출 금지 */
void pci_disable_sriov(struct pci_dev *dev);

/* ── VF 수 조회 ── */
int  pci_num_vf(struct pci_dev *dev);           /* 현재 활성 VF 수 */
int  pci_vfs_assigned(struct pci_dev *dev);      /* VFIO에 할당된 VF 수 */
int  pci_sriov_get_totalvfs(struct pci_dev *dev);  /* 하드웨어 최대 VF 수 */

/* ── PF ↔ VF 관계 탐색 ── */
struct pci_dev *pci_physfn(struct pci_dev *dev);   /* VF → PF */
bool  pci_is_virtfn(struct pci_dev *dev);           /* VF 여부 확인 */

/* ── ARI 지원 확인 ── */
bool  pci_ari_enabled(struct pci_bus *bus);    /* 버스 ARI 활성 여부 */

/* ── VF 드라이버에서 PF 데이터 접근 패턴 ── */
struct pci_dev  *physfn = pci_physfn(vf_pdev);
struct my_pf_priv *pf  = pci_get_drvdata(physfn);
/* pf를 통해 mailbox, 전역 자원에 접근 */

PF 드라이버 구현

#include <linux/pci.h>
#include <linux/netdevice.h>

struct my_pf_priv {
    struct pci_dev     *pdev;
    int                 num_vfs;
    struct my_vf_info  *vf_info;   /* VF당 MAC·VLAN 설정 테이블 */
    void __iomem       *hw;        /* PF BAR0 */
};

static int my_sriov_configure(struct pci_dev *pdev, int num_vfs)
{
    struct my_pf_priv *pf = pci_get_drvdata(pdev);
    int ret;

    if (num_vfs == 0) {
        /* VFIO에 할당된 VF가 있으면 비활성화 거부 */
        if (pci_vfs_assigned(pdev))
            return -EPERM;

        my_hw_disable_vfs(pf);
        kfree(pf->vf_info);
        pf->vf_info = NULL;
        pci_disable_sriov(pdev);
        pf->num_vfs = 0;
        return 0;
    }

    if (num_vfs > pci_sriov_get_totalvfs(pdev))
        return -EINVAL;

    /* VF당 자원 구조체 할당 (MAC 주소, VLAN, 신뢰 모드 등) */
    pf->vf_info = kcalloc(num_vfs, sizeof(*pf->vf_info), GFP_KERNEL);
    if (!pf->vf_info)
        return -ENOMEM;

    /* 하드웨어 VF 큐·인터럽트 할당 */
    ret = my_hw_enable_vfs(pf, num_vfs);
    if (ret) {
        kfree(pf->vf_info);
        return ret;
    }

    /* PCIe SR-IOV Capability NumVFs 레지스터 설정 & VF Config Space 노출 */
    ret = pci_enable_sriov(pdev, num_vfs);
    if (ret) {
        my_hw_disable_vfs(pf);
        kfree(pf->vf_info);
        return ret;
    }

    pf->num_vfs = num_vfs;
    dev_info(&pdev->dev, "%d VFs 활성화
", num_vfs);
    return num_vfs;   /* 성공 시 활성화된 VF 수 반환 */
}

/* PF 드라이버의 NDO 콜백 — VF MAC/VLAN/QoS 정책 제어 */
static int my_ndo_set_vf_mac(struct net_device *dev, int vf_id,
                              u8 *mac)
{
    struct my_pf_priv *pf = netdev_priv(dev);
    if (vf_id >= pf->num_vfs)
        return -EINVAL;
    ether_addr_copy(pf->vf_info[vf_id].mac, mac);
    my_hw_set_vf_mac(pf, vf_id, mac);  /* MMIO 레지스터에 MAC 기록 */
    return 0;
}

static const struct net_device_ops my_netdev_ops = {
    .ndo_set_vf_mac        = my_ndo_set_vf_mac,
    .ndo_set_vf_vlan       = my_ndo_set_vf_vlan,
    .ndo_set_vf_rate       = my_ndo_set_vf_rate,       /* QoS 대역폭 */
    .ndo_get_vf_config     = my_ndo_get_vf_config,
    .ndo_set_vf_trust      = my_ndo_set_vf_trust,      /* 신뢰 모드 */
    .ndo_set_vf_link_state = my_ndo_set_vf_link_state,
};

static struct pci_driver my_pf_driver = {
    .name            = "my_nic_pf",
    .id_table        = my_pf_ids,
    .probe           = my_pf_probe,
    .remove          = my_pf_remove,
    .sriov_configure = my_sriov_configure,  /* sysfs sriov_numvfs 쓰기 시 호출 */
};
코드 설명
  • sriov_configure 콜백사용자가 echo N > /sys/bus/pci/devices/.../sriov_numvfs를 실행하면 커널이 이 콜백을 호출합니다. num_vfs == 0이면 VF 비활성화, 양수면 해당 수만큼 VF 생성을 요청합니다. drivers/pci/iov.csriov_numvfs_store()에서 호출됩니다.
  • pci_vfs_assigned()VFIO를 통해 VM에 할당(passthrough)된 VF가 있는지 확인합니다. 할당된 VF가 있는 상태에서 SR-IOV를 비활성화하면 VM이 크래시할 수 있으므로, 반드시 0인지 확인 후 비활성화해야 합니다.
  • pci_enable_sriov()SR-IOV Extended Capability의 NumVFs 레지스터를 설정하고 VF Enable 비트를 활성화합니다. 이후 커널이 각 VF의 Configuration Space를 탐색하여 pci_dev 구조체를 생성하고, 버스에 등록합니다. drivers/pci/iov.c에 구현되어 있습니다.
  • NDO 콜백 (ndo_set_vf_mac 등)PF 드라이버의 net_device_ops에 VF 관리 콜백을 등록하면, ip link set dev PF vf N mac XX:XX:XX:XX:XX:XX 같은 명령으로 VF의 MAC 주소, VLAN, QoS, 신뢰 모드를 PF를 통해 제어할 수 있습니다.
  • pci_sriov_get_totalvfs()SR-IOV Capability의 TotalVFs 레지스터를 읽어 하드웨어가 지원하는 최대 VF 수를 반환합니다. 요청된 num_vfs가 이 값을 초과하면 거부해야 합니다.

VF 드라이버 구현

/* VF 드라이버 — VM 내부 게스트 OS 또는 호스트에서 VF 직접 제어 */
struct my_vf_priv {
    struct pci_dev    *pdev;
    void __iomem      *hw;       /* VF BAR0 */
    struct my_tx_ring  tx_ring;
    struct my_rx_ring  rx_ring;
};

static int my_vf_probe(struct pci_dev *pdev,
                       const struct pci_device_id *id)
{
    struct my_vf_priv *vf;
    int ret;

    ret = pcim_enable_device(pdev);
    ret = pcim_iomap_regions(pdev, BIT(0), "my_nic_vf");

    vf = devm_kzalloc(&pdev->dev, sizeof(*vf), GFP_KERNEL);
    vf->pdev = pdev;
    vf->hw   = pcim_iomap_table(pdev)[0];  /* VF BAR0 ioremap */

    pci_set_master(pdev);   /* DMA Bus Master 활성화 */

    /* VF는 IOMMU가 격리 보장 — DMA 마스크 직접 설정 */
    ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));

    /* TX/RX 디스크립터 링 DMA 할당 후 하드웨어 레지스터에 물리 주소 기록 */
    my_vf_setup_rings(vf);

    /* MSI-X 벡터 할당 (VF Config Space에 명시된 최대 수 이내) */
    ret = pci_alloc_irq_vectors(pdev, 1, MY_VF_MSIX_MAX, PCI_IRQ_MSIX);

    request_irq(pci_irq_vector(pdev, 0), my_vf_tx_irq,
                0, "my_vf_tx", vf);
    request_irq(pci_irq_vector(pdev, 1), my_vf_rx_irq,
                0, "my_vf_rx", vf);

    /* PF mailbox로 MAC 주소 요청 (VF는 MAC 직접 변경 불가) */
    my_vf_mailbox_send(vf, MSG_REQUEST_MAC, NULL);

    pci_set_drvdata(pdev, vf);
    return 0;
}

static const struct pci_device_id my_vf_ids[] = {
    { PCI_VDEVICE(INTEL, 0x154c), 0 },   /* Intel X710 VF */
    { PCI_VDEVICE(INTEL, 0x1571), 0 },   /* Intel XL710 VF */
    {}
};
MODULE_DEVICE_TABLE(pci, my_vf_ids);

static struct pci_driver my_vf_driver = {
    .name     = "my_nic_vf",
    .id_table = my_vf_ids,
    .probe    = my_vf_probe,
    .remove   = my_vf_remove,
    /* VF 드라이버는 sriov_configure 없음 */
};

SR-IOV + IOMMU + VFIO → VM 패스스루 전체 스택

SR-IOV + IOMMU + VFIO → VM 패스스루 전체 스택 VM 1 (게스트) Guest NIC 드라이버 (iavf.ko) Guest 물리 주소(GPA)로 TX/RX 링 디스크립터 업데이트 VM 2 (게스트) Guest NIC 드라이버 (iavf.ko) Guest 물리 주소(GPA)로 TX/RX 링 디스크립터 업데이트 QEMU / KVM 하이퍼바이저 + VFIO VFIO VF 0 (/dev/vfio/16) VFIO_IOMMU_MAP_DMA: GPA → HPA 매핑 등록 VFIO VF 1 (/dev/vfio/17) VFIO_IOMMU_MAP_DMA: GPA → HPA 매핑 등록 IOMMU (Intel VT-d / AMD-Vi) Domain 16 (VF 0 전용): GPA → HPA 변환 Domain 17 (VF 1 전용): GPA → HPA 변환 Interrupt Remapping: VF MSI-X → irqfd → KVM → 게스트 인터럽트 물리 NIC (PCIe 디바이스) PF (03:00.0) i40e.ko (호스트) MAC/VLAN 정책 제어 VF 0 (03:00.2) iavf.ko (게스트) IOMMU Group 16 VF 1 (03:00.3) iavf.ko (게스트) IOMMU Group 17 VF 2 (미할당) 03:00.4 호스트 직접 사용 mailbox 데이터 흐름 핵심 포인트 ① TX: VM 드라이버가 GPA 기반 TX 디스크립터 링 직접 업데이트 — VM-exit 발생 없음 (zero-copy) ② DMA: NIC VF가 GPA로 DMA 시 IOMMU가 GPA→HPA 변환 — VF는 VM 전용 메모리 외 접근 불가 ③ RX 인터럽트: VF MSI-X → IOMMU Interrupt Remapping → QEMU irqfd → KVM → 게스트 vCPU 인터럽트 ④ 정책: PF 드라이버가 mailbox로 VF MAC/VLAN/대역폭 제어 — VM이 임의 MAC 스푸핑·VLAN 침입 불가 ⑤ 한계: VF는 하드웨어 상태 보유 → 라이브 마이그레이션 불가 (vDPA/virtio 사용 시 마이그레이션 가능)

sysfs 인터페이스 상세

# PF 기준 경로: /sys/bus/pci/devices/0000:03:00.0/

## VF 수 조회 및 제어
cat /sys/bus/pci/devices/0000:03:00.0/sriov_totalvfs    # 최대 VF 수 (RO)
cat /sys/bus/pci/devices/0000:03:00.0/sriov_numvfs      # 현재 활성 VF 수
echo 4 > /sys/bus/pci/devices/0000:03:00.0/sriov_numvfs # VF 4개 활성화
echo 0 > /sys/bus/pci/devices/0000:03:00.0/sriov_numvfs # VF 전부 비활성화

## VF 활성화 후 생성된 VF 디바이스 목록
ls -l /sys/bus/pci/devices/0000:03:00.0/virtfn*
# virtfn0 → ../0000:03:00.2
# virtfn1 → ../0000:03:00.3

## VF → PF 역방향 참조
readlink /sys/bus/pci/devices/0000:03:00.2/physfn
# ../0000:03:00.0  (PF BDF)

## VF를 vfio-pci에 바인딩 (VM 패스스루 준비)
VFBDF="0000:03:00.2"
echo $VFBDF > /sys/bus/pci/devices/$VFBDF/driver/unbind 2>/dev/null || true
echo "vfio-pci" > /sys/bus/pci/devices/$VFBDF/driver_override
echo $VFBDF > /sys/bus/pci/drivers/vfio-pci/bind

## IOMMU 그룹 번호 확인
readlink /sys/bus/pci/devices/$VFBDF/iommu_group | grep -o '[0-9]*$'

## ip link로 PF에서 VF 설정 (네트워크 드라이버)
ip link set enp3s0f0 vf 0 mac 52:54:00:aa:bb:cc  # VF 0 MAC 설정
ip link set enp3s0f0 vf 0 vlan 100               # VF 0 VLAN 태그
ip link set enp3s0f0 vf 0 rate 1000              # 최대 1Gbps 대역폭
ip link set enp3s0f0 vf 0 trust on               # 신뢰 모드 (MAC 스푸핑 허용)
ip link set enp3s0f0 vf 0 spoofchk off           # 스푸핑 검사 비활성
ip link show enp3s0f0                             # VF 설정 전체 확인

SR-IOV + DPDK 고성능 패킷 처리

SR-IOV VF를 DPDK의 PMD(Poll Mode Driver)와 결합하면 커널 네트워크 스택(Network Stack)을 완전히 우회하여 라인 레이트(100Gbps+) 패킷 처리가 가능합니다. DPDK iavf PMD는 VF BAR에 직접 접근하여 TX/RX 디스크립터 링을 폴링(Polling) 방식으로 처리합니다.

# DPDK에서 SR-IOV VF 사용 예시

# 1. 대용량 페이지 설정
echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
mount -t hugetlbfs nodev /mnt/huge

# 2. VF를 vfio-pci에 바인딩 (위 절차와 동일)

# 3. DPDK testpmd로 VF 성능 테스트
dpdk-testpmd -l 0-3 -n 4 \
  -- --forward-mode=io --nb-cores=2 \
  --rxq=2 --txq=2 --stats-period=1

# DPDK 지원 VF PMD 드라이버
# Intel iavf PMD:    drivers/net/iavf/  (X710/E810 VF)
# Mellanox mlx5 PMD: drivers/net/mlx5/  (ConnectX VF)
# Virtio-user PMD:   DPDK vhost 통합 시 SR-IOV 대안

디버깅

# SR-IOV Capability 및 VF 상태 확인
lspci -vvv -s 0000:03:00.0 | grep -A 12 "SR-IOV"
# IOVCtl: Enable+ → VF 활성화됨
# Number of VFs: 4, Total VFs: 64

# 생성된 VF 디바이스 목록
lspci | grep "Virtual Function"
# 03:00.2 Ethernet [0200]: Intel [Virtual Function]

# IOMMU 그룹 격리 확인 (VF별 별도 그룹이어야 안전)
for vf in /sys/bus/pci/devices/0000:03:00.*/iommu_group; do
    echo "$(basename $(dirname $vf)): group $(readlink $vf | grep -o '[0-9]*$')"
done

# dmesg: SR-IOV 활성화 로그
dmesg | grep -i "sriov\|virtfn\|VF enable"
# pci 0000:03:00.0: 4 VFs enabled
# pci 0000:03:00.2: [8086:154c] type 00 class 0x020000

# VF 드라이버 바인딩 상태 확인
lspci -nnk -s 0000:03:00.2
# Kernel driver in use: vfio-pci  ← VM 패스스루 준비 완료
# Kernel driver in use: iavf      ← 호스트에서 직접 사용 중

# VF가 대규모일 때: ARI 활성화 여부 확인
lspci -vvv -s 0000:03:00.0 | grep "ARI Forwarding"
# ARI Forwarding: +  ← 256개 Function 지원 (64+ VF 가능)

# VF 통계 (PF 드라이버에서 조회)
ethtool -S enp3s0f0 | grep -i "vf"
SR-IOV 주요 제약사항:
  • 라이브 마이그레이션 불가 — VF는 하드웨어 상태를 가져 VFIO passthrough VM의 라이브 마이그레이션이 불가능합니다. vDPA(virtio Data Path Acceleration) 또는 virtio를 사용하면 마이그레이션 가능합니다.
  • VF 비활성화 전 VM 종료 필요pci_vfs_assigned()가 0이 아닐 때 pci_disable_sriov()는 -EPERM을 반환합니다.
  • ACS 미지원 스위치 경고 — ACS 없는 PCIe 스위치 아래 VF는 P2P DMA로 인해 IOMMU 격리가 불완전할 수 있습니다.
  • VF Config Space 제한 — VF는 FLR(Function Level Reset) 이외의 전원 관리·ASPM 기능이 없으며, Config Space의 일부 필드만 접근 가능합니다.
  • SR-IOV vs mdev 선택 — 하드웨어가 SR-IOV를 지원하면 성능이 뛰어나지만, 라이브 마이그레이션이 필요하거나 VF 수보다 더 많은 VM을 서비스할 때는 mdev 또는 virtio가 적합합니다.

pci_enable_msix_range() 소스 분석

pci_enable_msix_range()는 드라이버가 원하는 MSI-X 벡터 수의 범위(minvec~maxvec)를 지정하면, 하드웨어가 지원하는 최대값으로 협상하여 할당합니다. 내부적으로 pci_msix_vec_count()로 하드웨어 상한을 확인한 뒤 __pci_enable_msix_range()를 호출합니다.

/* drivers/pci/msi/api.c */
int pci_enable_msix_range(struct pci_dev *dev,
                          struct msix_entry *entries,
                          int minvec, int maxvec)
{
    int rc;

    if (maxvec < minvec)
        return -ERANGE;

    if (WARN_ON_ONCE(dev->msix_enabled)) {
        int nvec = pci_msix_vec_count(dev);
        if (nvec < 0)
            return nvec;
        if (nvec < minvec)
            return -ENOSPC;
    }

    rc = __pci_enable_msix_range(dev, entries, minvec, maxvec, NULL, 0);
    if (rc < 0)
        return rc;

    if (rc < minvec) {
        pci_free_irq_vectors(dev);
        return -ENOSPC;
    }
    return rc;   /* 실제 할당된 벡터 수 반환 */
}
EXPORT_SYMBOL(pci_enable_msix_range);
코드 설명
  • maxvec < minvec범위가 역전된 경우 즉시 -ERANGE로 거부합니다. 드라이버가 잘못된 인수를 넘기는 것을 조기 차단합니다.
  • WARN_ON_ONCE(dev->msix_enabled)이미 MSI-X가 활성화된 상태에서 재진입 시 경고를 출력합니다. 이 경우 pci_msix_vec_count()로 하드웨어 상한을 다시 읽어 minvec과 비교합니다.
  • __pci_enable_msix_range()실제 MSI-X 테이블·PBA를 MMIO에 매핑하고, irq_domain을 통해 각 벡터에 Linux IRQ 번호를 할당하며, Config Space의 MSI-X Enable 비트를 설정합니다.
  • rc < minvec하드웨어가 minvec보다 적은 벡터만 제공할 수 있으면 이미 부분 할당된 벡터를 pci_free_irq_vectors()로 해제하고 -ENOSPC를 반환합니다.
  • return rc성공 시 실제 할당된 벡터 수(minvec~maxvec 사이)를 반환합니다. 드라이버는 이 값으로 큐 수를 결정합니다.

pci_enable_sriov() 소스 분석

pci_enable_sriov()는 PF의 SR-IOV Capability를 프로그래밍하여 지정한 수의 VF를 생성합니다. VF용 PCIe Config Space 주소를 계산하고, 각 VF를 pci_dev로 등록하여 드라이버 바인딩이 가능하도록 합니다.

/* drivers/pci/iov.c */
int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
{
    might_sleep();

    if (!dev->is_physfn)
        return -ENOSYS;           /* VF에서는 호출 불가 */

    return sriov_enable(dev, nr_virtfn);
}
EXPORT_SYMBOL_GPL(pci_enable_sriov);

static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
{
    int rc, i;
    int nres;
    u16 initial;
    struct pci_dev *pdev;
    struct pci_sriov *iov = dev->sriov;
    u16 offset, stride, tmp;

    if (!nr_virtfn)
        return 0;

    if (iov->num_VFs)
        return -EINVAL;           /* 이미 VF가 활성화 중 */

    pci_read_config_word(dev, iov->pos + PCI_SRIOV_INITIAL_VF, &initial);
    if (nr_virtfn > iov->total_VFs ||
        (!(iov->cap & PCI_SRIOV_CAP_VFM) && nr_virtfn > initial)) {
        pci_err(dev, "can't enable %d VFs (max %d)\n",
                nr_virtfn, iov->total_VFs);
        return -EINVAL;
    }

    /* VF BAR 리소스 계산 및 할당 */
    rc = sriov_enable_vf_resources(dev, nr_virtfn);
    if (rc)
        return rc;

    /* SR-IOV Control: VF Enable + VF MSE 비트 설정 */
    pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn);
    pci_iov_set_numvfs(dev, nr_virtfn);   /* SRIOV Control 레지스터 */

    iov->num_VFs = nr_virtfn;

    /* 각 VF에 대해 pci_dev 생성 및 등록 */
    for (i = 0; i < nr_virtfn; i++) {
        rc = pci_iov_add_virtfn(dev, i);
        if (rc)
            goto failed;
    }
    return 0;

failed:
    sriov_disable(dev);
    return rc;
}
코드 설명
  • might_sleep()VF 생성 과정에서 슬리프가 발생할 수 있음을 명시합니다. pci_enable_sriov()는 인터럽트 컨텍스트에서 호출할 수 없습니다.
  • !dev->is_physfnVF(is_virtfn == 1)에서 SR-IOV를 활성화하려는 시도를 차단합니다. SR-IOV 활성화는 PF에서만 가능합니다.
  • iov->num_VFs이미 VF가 활성화된 상태에서 재활성화를 시도하면 -EINVAL을 반환합니다. 먼저 pci_disable_sriov()를 호출해야 합니다.
  • PCI_SRIOV_INITIAL_VFSR-IOV Capability에서 초기 VF 수를 읽습니다. VF Migration 기능이 없는 경우 nr_virtfn이 이 값을 초과할 수 없습니다.
  • sriov_enable_vf_resources()VF BAR 크기를 읽고(PCI_SRIOV_BAR 레지스터), VF 수만큼 곱한 크기의 주소 공간을 부모 버스 윈도우에서 할당합니다.
  • pci_iov_set_numvfs()SR-IOV Control 레지스터의 VF Enable 비트와 VF MSE(Memory Space Enable) 비트를 설정하여 하드웨어가 VF를 PCIe 토폴로지에 노출하도록 지시합니다.
  • pci_iov_add_virtfn()각 VF에 대해 BDF(Bus/Device/Function)를 계산하고, pci_dev를 할당하여 is_virtfn = 1로 설정합니다. 이후 pci_device_add()device_add()로 sysfs 공개 및 드라이버 매칭을 수행합니다.
  • goto failed / sriov_disable()VF 등록 도중 실패 시 이미 등록된 VF를 모두 제거하고 Config Space를 원래 상태로 복원합니다. 원자적 트랜잭션처럼 동작합니다.
pci_enable_sriov() 내부 VF 생성 흐름 유효성 검사 is_physfn 확인 · total_VFs 한계 확인 sriov_enable_vf_resources() VF BAR 크기 계산 · 주소 공간 할당 pci_iov_set_numvfs() SR-IOV Control: VF Enable + VF MSE 설정 for i in 0..nr_virtfn pci_iov_add_virtfn(dev, i) pci_dev 할당 (is_virtfn=1) device_add() → sysfs 공개 → 드라이버 매칭 실패 시 sriov_disable() — 등록된 VF 제거 + Config Space 복원
pci_enable_sriov() 내부 VF 생성 흐름 — 유효성 검사부터 pci_dev 등록까지

SR-IOV + Kubernetes 통합

클라우드 네이티브 환경에서 SR-IOV VF를 컨테이너(Pod)에 직접 할당하면, 커널 네트워크 스택 오버헤드 없이 네이티브에 가까운 네트워크 성능을 달성할 수 있습니다. Kubernetes에서는 SR-IOV Device PluginSR-IOV CNI Plugin이 VF 자원 관리와 네트워크 인터페이스 연결을 담당합니다. Multus CNI를 통해 Pod에 여러 네트워크 인터페이스를 부착할 수 있습니다.

SR-IOV Kubernetes 통합 아키텍처 Kubernetes Node kubelet SR-IOV Device Plugin Multus CNI VF 자원 풀 intel.com/sriov_netdevice: 8 SR-IOV CNI Plugin VF → Pod netns 이동 Pod A eth0: 기본 CNI (flannel) net1: SR-IOV VF0 10Gbps 직접 접근 Pod B eth0: 기본 CNI (flannel) net1: SR-IOV VF1 10Gbps 직접 접근 Pod C (DPDK) eth0: 기본 CNI (flannel) net1: SR-IOV VF2 (vfio) userspace DPDK PMD 물리 NIC (PF: enp3s0f0) VF0 (netdev) | VF1 (netdev) | VF2 (vfio-pci) | VF3~7 (미할당)
SR-IOV Device Plugin이 VF 자원을 관리하고, Multus + SR-IOV CNI가 Pod에 VF를 네트워크 인터페이스로 연결합니다

NetworkAttachmentDefinition은 Multus가 참조하는 추가 네트워크 정의입니다. SR-IOV CNI Plugin이 VF를 Pod의 네트워크 네임스페이스로 이동시킵니다.

# SR-IOV Network Attachment Definition (Multus)
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
  name: sriov-net-a
  annotations:
    k8s.v1.cni.cncf.io/resourceName: intel.com/sriov_netdevice
spec:
  config: '{
    "type": "sriov",
    "cniVersion": "0.3.1",
    "vlan": 100,
    "spoofchk": "on",
    "trust": "off",
    "ipam": {
      "type": "host-local",
      "subnet": "10.56.0.0/16",
      "rangeStart": "10.56.1.10",
      "rangeEnd": "10.56.1.250"
    }
  }'
# Pod에서 SR-IOV VF 자원 요청
apiVersion: v1
kind: Pod
metadata:
  name: sriov-pod
  annotations:
    k8s.v1.cni.cncf.io/networks: sriov-net-a
spec:
  containers:
  - name: app
    image: my-app:latest
    resources:
      requests:
        intel.com/sriov_netdevice: "1"
      limits:
        intel.com/sriov_netdevice: "1"
코드 설명
  • NetworkAttachmentDefinitionMultus CNI가 인식하는 커스텀 리소스입니다. resourceName 어노테이션이 SR-IOV Device Plugin이 등록한 자원 이름(intel.com/sriov_netdevice)과 매칭되어야 합니다.
  • sriov CNI typeSR-IOV CNI Plugin이 할당된 VF를 Pod의 네트워크 네임스페이스로 이동시킵니다. VLAN, spoofchk, trust 등의 VF 정책도 여기서 설정합니다.
  • intel.com/sriov_netdeviceSR-IOV Device Plugin이 kubelet에 등록하는 Extended Resource 이름입니다. Pod이 이 자원을 requests/limits에 선언하면 kubelet이 Device Plugin을 통해 VF를 할당합니다.
  • k8s.v1.cni.cncf.io/networksPod 어노테이션에 추가 네트워크를 지정합니다. Multus가 이 값을 읽어 기본 CNI(eth0) 외에 SR-IOV 네트워크(net1)를 추가로 연결합니다.
DPDK Pod의 경우: VF를 vfio-pci로 바인딩한 상태에서 할당하려면 intel.com/sriov_vfio 자원 유형을 별도로 구성해야 합니다. SR-IOV Device Plugin의 configMap에서 "drivers": ["vfio-pci"]로 설정하면 DPDK 전용 VF 풀을 분리할 수 있습니다.

Scalable IOV (SIOV)

Intel Scalable IOV(SIOV)는 SR-IOV의 한계를 극복하기 위해 설계된 차세대 I/O 가상화 기술입니다. SR-IOV가 하드웨어에 고정된 수의 VF를 생성하는 반면, SIOV는 ADI(Assignable Device Interface)라는 소프트웨어 정의 가상 디바이스를 PASID(Process Address Space ID) 기반으로 동적 생성합니다. ADI는 BAR 공간을 소비하지 않으므로 수천 개의 가상 디바이스를 유연하게 생성할 수 있습니다.

ADI와 PASID 기반 격리

SIOV에서 각 ADI는 고유한 PASID 값을 가지며, IOMMU가 PASID별 페이지 테이블(Page Table)을 관리하여 DMA 격리를 보장합니다. 디바이스가 TLP(Transaction Layer Packet)에 PASID를 포함하여 전송하면, IOMMU는 해당 PASID의 주소 공간으로 DMA를 제한합니다.

SR-IOV vs Scalable IOV vs vDPA vs mdev 비교

항목 SR-IOV Scalable IOV vDPA mdev
가상 디바이스 단위 VF (PCIe Function) ADI (PASID 기반) virtio datapath Mediated Device
최대 인스턴스 ~256 (하드웨어 고정) 수천 (소프트웨어 정의) 드라이버 의존 드라이버 의존
BAR 공간 소비 VF당 별도 BAR 필요 공유 BAR (PASID 구분) 없음 없음 (에뮬레이션)
생성 방식 PCIe 재열거 필요 런타임 동적 생성 런타임 동적 생성 런타임 동적 생성
DMA 격리 IOMMU (BDF 기반) IOMMU (PASID 기반) 소프트웨어 (vhost) 소프트웨어 (mdev)
라이브 마이그레이션 불가 (하드웨어 상태) 제한적 (PASID 전환) 가능 (virtio 표준) 벤더 의존
성능 (지연시간) 네이티브급 네이티브급 SR-IOV에 근접 에뮬레이션 오버헤드
커널 지원 상태 완전 지원 (v2.6.30+) 초기 단계 (IDXD 등) v5.7+ (vDPA 프레임워크) v4.10+ (mdev 프레임워크)
대표 디바이스 NIC, NVMe, GPU Intel IDXD, DSA NIC (virtio-net) GPU (NVIDIA vGPU, Intel GVT)
SIOV 커널 지원 현황: Intel Data Streaming Accelerator(DSA/IDXD)가 SIOV 방식을 최초로 구현한 디바이스입니다. 커널의 drivers/dma/idxd/에서 PASID 기반의 Work Queue(WQ)를 mdev 인터페이스를 통해 VM에 할당합니다. 범용 SIOV 프레임워크는 아직 커널에 통합되지 않았으며, 디바이스별로 개별 구현되고 있습니다.

VF Configuration Space 구조

VF의 Configuration Space는 PCIe Type 0(Endpoint) 헤더 형식이지만, 대부분의 필드가 읽기 전용(RO)이거나 하드와이어(HwInit)되어 있습니다. VF의 리소스(BAR, Interrupt)는 PF의 SR-IOV Capability를 통해 간접적으로 결정되므로, VF Config Space의 직접 설정 범위가 제한됩니다.

VF Configuration Space 레이아웃 (Type 0 Header) 오프셋 필드 속성 VF에서의 동작 0x00 Vendor ID / Device ID RO Vendor=PF와 동일, Device=PF SR-IOV Cap의 VF Device ID 0x04 Command / Status RW* Bus Master, Memory Space는 PF의 VF MSE로 제어 0x08 Revision / Class Code RO PF와 동일한 Class Code (예: 0x020000 = Ethernet) 0x10 ~ 0x24 BAR 0 ~ 5 (MMIO 주소) RO (HwInit) PF SR-IOV Cap의 VF BAR로부터 계산됨 VF BAR[n] = PF_VF_BAR[n] + VF_index × VF_BAR_size 0x2C Subsystem Vendor / ID RO PF의 Subsystem ID와 다를 수 있음 0x34 Capabilities Pointer RO MSI-X, PCIe Capability 등만 포함 (SR-IOV Cap 없음) 0x100+ Extended Capabilities MSI-X, AER, ACS 등 RO FLR(Function Level Reset)만 VF에서 실행 가능 PM, ASPM 등 전원 관리는 미지원 PF SR-IOV Capability → VF BAR 주소 계산 PF SR-IOV Capability VF BAR0 base = 0xFB00_0000 VF BAR0 size = 64KB per VF FirstVFOffset=128, VFStride=1 VF BAR 주소 매핑 VF0 BAR0: 0xFB00_0000 (64KB) VF1 BAR0: 0xFB01_0000 (64KB) VF2 BAR0: 0xFB02_0000 (64KB) VF BDF 및 BAR 주소 계산 공식 VF[n] BDF = PF_BDF + FirstVFOffset + n × VFStride VF[n] BAR[m] = PF_SR-IOV_VF_BAR[m]_base + n × VF_BAR[m]_size 예: PF=03:00.0, Offset=128 → VF0=03:02.0, VF1=03:02.1 (ARI 모드: 03:00.128, 03:00.129)
VF Config Space는 Type 0 헤더 형식이지만, BAR과 대부분의 필드가 PF SR-IOV Capability를 통해 간접 결정됩니다
VF Config Space 제약사항:
  • BAR 직접 쓰기 불가 — VF BAR 값은 PF의 VF BAR 레지스터로부터 계산되며, VF Config Space의 BAR 필드에 직접 쓸 수 없습니다
  • SR-IOV Capability 없음 — VF는 SR-IOV Extended Capability를 가지지 않습니다 (중첩 가상화 불가)
  • 전원 관리 제한 — VF는 D0/D3hot 상태 전환만 지원하며, ASPM과 같은 링크 전원 관리는 PF가 제어합니다
  • FLR만 지원 — VF의 유일한 리셋 방식은 Function Level Reset입니다. VF FLR은 해당 VF만 리셋하고 다른 VF에 영향을 주지 않습니다

SR-IOV 성능 최적화

SR-IOV는 하드웨어 패스스루 방식으로 에뮬레이션 오버헤드를 제거하여 네이티브에 가까운 성능을 제공합니다. 다음은 주요 가상화 NIC 방식별 성능 특성 비교입니다.

가상화 NIC 방식별 성능 비교

항목 SR-IOV VF vDPA (vhost) virtio-net (vhost-net) 에뮬레이션 (e1000)
지연시간 (RTT) ~15 μs ~20 μs ~50 μs ~200 μs
처리량 (64B 패킷) ~14.8 Mpps ~12 Mpps ~3 Mpps ~0.3 Mpps
CPU 사용률 (10Gbps) ~5% ~8% ~30% ~90%
데이터 경로 VF → PCIe → IOMMU → Memory VF → vDPA bus → vhost → Memory Guest → vhost-net → tap → Host Guest → QEMU → tap → Host
라이브 마이그레이션 불가 가능 가능 가능
VM Exit 빈도 최소 (MSI-X 직접 전달) 낮음 중간 (eventfd) 매우 높음

※ 위 수치는 10GbE NIC(Intel X710) 기준 대표값이며, 하드웨어·드라이버·설정에 따라 달라질 수 있습니다.

데이터 경로 비교: SR-IOV vs virtio-net SR-IOV 패스스루 경로 (최소 지연) Guest 드라이버 (iavf/mlx5) VF (PCIe) DMA 직접 접근 IOMMU VF별 DMA 격리 물리 메모리 Guest RAM ~15 μs RTT virtio-net (vhost-net) 경로 Guest virtio-net virtqueue shared memory vhost-net 커널 모듈 tap 디바이스 호스트 NIC 드라이버 ~50 μs RTT SR-IOV 주요 튜닝 포인트 VF 큐 수 조정 ethtool -L $VF combined N 인터럽트 코얼레싱 ethtool -C $VF rx-usecs 50 링 버퍼 크기 ethtool -G $VF rx 4096 tx 4096 CPU 친화성 IRQ affinity를 NUMA 노드에 고정 ACS (Access Control Services) 주의사항 ACS 미지원 PCIe 스위치 하위의 VF 간 P2P DMA가 IOMMU를 우회할 수 있음 → IOMMU 그룹이 분리되지 않아 격리 불완전
SR-IOV는 Guest 드라이버가 VF를 통해 직접 DMA 접근하므로 virtio-net 대비 3배 이상 낮은 지연시간을 달성합니다

성능 튜닝 가이드

# ── VF 큐 수 조정 (멀티코어 활용) ──
# PF 드라이버가 지원하는 경우 VF당 큐 수 변경
ethtool -L enp3s2 combined 4

# ── 인터럽트 코얼레싱 최적화 ──
# 지연시간 우선: rx-usecs 낮게
ethtool -C enp3s2 rx-usecs 10 tx-usecs 10

# 처리량 우선: rx-usecs 높게 (배치 처리)
ethtool -C enp3s2 rx-usecs 100 tx-usecs 100 rx-frames 64

# ── 링 버퍼 크기 증가 (패킷 드롭 방지) ──
ethtool -G enp3s2 rx 4096 tx 4096

# ── IRQ 친화성: VF 인터럽트를 같은 NUMA 노드 CPU에 고정 ──
# NIC NUMA 노드 확인
cat /sys/bus/pci/devices/0000:03:02.0/numa_node

# 해당 NUMA 노드의 CPU 확인
lscpu | grep "NUMA node0"

# IRQ 친화성 설정 (VF의 MSI-X 벡터별)
for irq in $(grep enp3s2 /proc/interrupts | awk '{print $1}' | tr -d :); do
    echo 0-3 > /proc/irq/$irq/smp_affinity_list
done

# ── ACS 확인 (VF 간 IOMMU 격리 검증) ──
lspci -vvv -s 0000:00:01.0 | grep "Access Control Services"
# ACSCtl: SrcValid+ TransBlk+ ReqRedir+ CmpltRedir+ UpstreamFwd+ EgrCtrl+ DirTrans+

# IOMMU 그룹 격리 상태 확인
for d in /sys/kernel/iommu_groups/*/devices/*; do
    g=$(echo $d | cut -d/ -f5)
    echo "Group $g: $(basename $d) $(lspci -nns $(basename $d) | cut -d' ' -f2-)"
done
코드 설명
  • ethtool -L combinedVF의 TX/RX 큐 수를 조정합니다. CPU 코어 수에 맞추면 RSS(Receive Side Scaling)가 여러 코어로 패킷을 분산 처리합니다. PF 드라이버에서 VF당 최대 큐 수를 제한할 수 있습니다.
  • ethtool -C rx-usecs인터럽트 코얼레싱(Coalescing)은 여러 패킷을 모아 하나의 인터럽트로 처리합니다. 값이 작으면 지연시간이 줄지만 인터럽트가 잦아지고, 값이 크면 처리량이 향상되지만 지연시간이 증가합니다.
  • NUMA 친화성NIC과 같은 NUMA 노드의 CPU에서 패킷을 처리하면 메모리 접근 지연시간이 줄어듭니다. 다른 NUMA 노드의 CPU에서 처리하면 QPI/UPI 인터커넥트 지연이 추가됩니다.
  • ACS 확인ACS(Access Control Services)는 PCIe 스위치에서 Function 간 P2P 트래픽을 제어합니다. ACS가 없으면 같은 스위치 하위의 VF 간 DMA가 IOMMU를 우회하여 격리가 깨질 수 있습니다.

참고자료