Virtualization 101- (5) SR-IOV Deep Dive (feat. vNIC SR-IOV)

송주환·2023년 10월 28일
0

Virtualization 101

목록 보기
6/6
post-thumbnail

들어가며

서버 가상화 환경에 SR-IOV (Single Root I/O Virtualization) 기술이 도입된 지 꽤 많은 시간이 흘렀다.
하지만 SR-IOV 기반 장치 가상화의 제약들 때문에 NIC 가상화와 vGPU 가상화 등의 일부 사용 사례에 국한되어 쓰이고 있으며, 때문에 가상화 엔지니어와 서버 엔지니어 중 SR-IOV를 제대로 다뤄본 사람이 거의 없고, SR-IOV에 대한 기술적인 이해도도 낮은 것이 현실이다.

이번 포스팅에서는 SR-IOV에 대한 기술적 설명과, SR-IOV vNIC을 예시로 하여 SR-IOV 사용 시에 주의해야 할 점을 알아볼 것이다.

SR-IOV의 기술적 설명

Single Root I/O Virtualization 이라는 이름에서 짐작할 수 있듯이, 하나의 PCI-E Root 장치를 여러개의 가상 PCI-E 장치로 '보이게' 만드는 기술을 SR-IOV라고 부른다.

이를 구현하기 위해서는 다음과 같은 전제 조건들이 필요하다.

  1. Virtual Function (이하, 가상 장치)은 서로 다른 PCI 주소 공간을 점유한다
  2. 가상 장치는 서로 다른 PCI Configuration Register 값을 가질 수 있어야 한다
  3. 가상 장치간의 트래픽은 서로 격리되어야 한다

1, 2번 조건을 만족하기 위해, SR-IOV에서는 기존 PCI-E 표준을 확장하여 가상 장치의 독립된 주소 공간을 할당해준다.

PCI-E Enumeration 과정을 떠올려보면, 전원이 켜진 뒤 BIOS/OS는 PCI-E 장치를 검색, Capability Pointer를 타고 PCI-E 확장 기능 레지스터들을 탐색하다 SR-IOV Capability가 정의된 주소 영역에 도달한다.

그리고 SR-IOV Capability 중, TotalVFs (=장치에서 지원 가능한 최대 VF 갯수)와 System Page Size 필드를 참고하여 VF들을 위한 Memory Map을 할당한다.
이 때, VF의 Base Address는 BAR0+BAR1 (64bit 시스템의 경우) 을 사용하고, VF의 갯수에 맞춰 Page Size 만큼의 Offset을 가지고 메모리 공간에 순차적으로 할당된다.

TotalVFs는 장치 제조사가 정의하는 Read Only 필드 이며, NumVFs (=실제로 OS에 노출되어야 하는 VF 갯수)는 Read/Write 필드이기 때문에, 시스템 초기화가 완료된 이후 NumVFs를 변경할 수 있으려면 사전에 (TotalVFs * System Page Size) 만큼의 연속된 메모리 공간을 할당해야 할 필요가 있다.

SR-IOV Spec에 따르면 NumVFs는 8비트 필드이며, 개별 VF는 RoutingID (기존의 Bus Number/Device Number/Function Number) 필드를 기준으로 식별될 수 있다.
이제 Hypervisor는 SR-IOV Capability의 BAR과 RoutingID를 이용하여 개별 VM에 할당된 VF Memory Map에 접근할 수 있으며, Guest OS는 독립된 PCI-E 장치를 사용하는 것과 같은 방식으로 VF를 제어할 수 있게 된다.

3번은 IOMMU 그룹과 ACS (Access Control Service)를 통해 구현되는데, 해당 기능에 대한 간단한 설명은 이전 포스팅에서 확인할 수 있다.

SR-IOV 구현에 있어 ACS가 필수는 아니지만, ACS를 사용하지 않을 경우 의도치 않은 PCI-E P2P 통신 기능이 노출될 수 있으며, 하이퍼바이저 관점에서 정의되지 않은 동작이 일어나 전체 시스템이 불안정해 질 수 있다.
때문에 ESXi는 기본적으로 ACS를 지원하지 않는 장치의 IOMMU 기능 사용을 차단한다.

SR-IOV를 이용한 vSphere에서의 NIC 가상화

vSphere 환경에서 SR-IOV NIC을 할당하기 위한 Best Practice는 공식 매뉴얼을 참고하면 된다.
해당 매뉴얼에서는 VM에 새 VM Network Adapter를 추가하고, 네트워크 속성(VLAN 태그 등)을 지정하기 위해 포트 그룹을 할당하며, 마지막으로 가상 시스템에 할당할 PF를 지정하게 되어 있다.

하지만, SR-IOV의 기술적인 구현을 생각해보면, 위와 같은 절차를 거치는 대신 VM에 NIC의 VF를 직접 할당해도 모든 기능이 정상적으로 동작해야 할 것이다. 왜냐하면 SR-IOV는 PCI-E 장치에 범용적으로 적용되는 기술이기 때문이다.

하지만, 정말 그럴까? 실제 Practice를 통해 알아보자.

테스트를 위해 두 대의 호스트에 위치한 VM에 PCI-E Passthrough를 이용해 각각 하나씩의 VF를 할당하고, 패킷 전송을 시도한다.
이 때, 상단 스위치의 MTU는 9100이고, VM의 NIC MTU는 9000, 그리고 ESXi Host vmnic의 MTU는 1500이다.

실제로 테스트를 해 보면, 스위치와 VM의 MTU가 정상적으로 점보 프레임으로 구성되어 있음에도 불구하고, 패킷이 정상적으로 전송되지 않는다.

이것은 VF의 MTU 값이 실제로는 PF에 종속적이기 때문이며, PF의 MTU 값은 기본적으로 VMNIC의 MTU 값을 따라가기 때문에 생기는 문제이다.

ESXi에서 VMNIC의 MTU 값을 변경하는 방법은 두 가지가 있다.
첫번째는, vSphere 매뉴얼에서 시키는 대로 가상 스위치와 포트그룹을 생성하고, VMNIC을 업링크로 지정한 다음 MTU 값을 변경하는 것이다.
두번째는, vsish를 사용하여 VMNIC의 MTU를 변경하는 것이다.

위와 같이 vsish -e set /net/pNics/vmnic<X>/mtu <MTU> 명령어를 이용해 간단하게 MTU 값을 변경할 수 있다.
단, 이렇게 설정한 값은 ESXi를 재부팅할 경우 유지되지 않으며, vCenter의 MTU 구성과 충돌할 수 있다는 점을 명심해야 한다.

VMNIC의 MTU 값을 변경한 뒤, 정상적으로 SR-IOV 인터페이스를 통해 점보 프레임 패킷이 전송되는 것을 확인할 수 있었다.
실제로 VF의 MTU 최대값이 PF에 종속적이라는 것은 잘 알려진 사실인 것으로 보인다.

위와 같은 일련의 테스트를 통해, 왜 VMware가 VF를 직접 패스스루해서 붙이는 대신 SR-IOV용 포트 그룹과 가상 스위치를 별도로 생성하도록 권고하는지, SR-IOV 인터페이스 구성 항목에서 Allow Guest MTU Change 옵션을 제공하는지 알 수 있었다.
또한 MTU 구성 문제 외에도 SR-IOV 기반의 vMotion 지원 등의 다른 이유들이 있을 것으로 예상된다.

그런데, VF MTU는 PF에 종속적이어야만 할까? 아쉽게도 Mellanox NIC의 레지스터 구성은 문서화되어 있지 않아, 드라이버 코드만을 가지고 추적할 수는 없었지만, Linux inbox mlx5_en 드라이버의 MTU 설정 함수를 통해 그 이유를 짐작해 볼 수 있었다.

위 코드를 통해 PF의 MTU를 업데이트 한 뒤, VPORT(=VF)의 MTU도 함께 업데이트 하는 것을 확인할 수 있었다. 전체 드라이버 소스코드 중 mlx5_modify_nic_vport_mtu()를 호출하는 컨텍스트는 해당 코드 패스가 유일했으므로, 적어도 Mellanox NIC의 리눅스 드라이버는 PF MTU == VF MTU를 상정하고 있다는 것을 알 수 있다.

정리

결과적으로, SR-IOV Capability 표준이 PF와 VF를 완전히 분리하여 구성할 수 있는 토대를 제공함에도 불구하고, 실제 칩셋, 펌웨어 그리고 드라이버의 구현에 따라서 VF의 구성이 PF에 종속적일 수 있음을 보였다.

MTU의 경우, 제조사와 칩셋의 종류에 따라서도 서로 다른 양상을 보였는데, 예를 들어 인텔의 일부 칩셋은 점보 프레임과 일반 프레임을 혼용하는 구성을 지원하지 않았고, 일부 칩셋의 경우 PF MTU >= VF MTU의 조건을 만족하는 구성을 지원하였다.

'올바른' MTU 구성을 사용자에게 알리기 위한 문서화와 구현에 대한 요구사항이 여러 차례 있었으나, 이러한 비일관성과 복잡성으로 인해 네트워크 관리 도구에서 이것을 바르게 처리하는 일은 거의 불가능하다고 여겨지는 것으로 보인다.

결국, 사용자가 하드웨어와 드라이버의 제약사항을 이해하고, 전체 시스템에 표준화된 구성 (예를 들어, MTU 9000으로 VF/PF MTU를 통일하는 등)을 적용하는 것이 바람직하다.

그리고 프로덕션 환경에서 기본 구성 값을 변경하기 전에 드라이버 의존적인 다른 설정들 (RSS, RX/TX Queue, VLAN 등)이 VF/PF에 대해 어떻게 동작하는지 추가로 테스트 해 볼 필요가 있을 것이다.

레퍼런스

PCI Express I/O Virtualization Explained (SDC 2010, SNIA)
Assign a Virtual Function as SR-IOV Passthrough Adapter to a Virtual Machine (VMware)

profile
Virtualization / Network / Storage / Server Hardware and.. Linux

0개의 댓글