우당탕탕 개발일지
[DPDK] NIC의 개념과 역할 본문

네트워크 환경에서 높은 처리 성능을 얻기 위해 DPDK와 같은 고성능 패킷 처리 기술이 사용된다.
이러한 기술을 이해하려면, 먼저 네트워크 패킷이 서버 내부에서 어떤 구조로 처리되는지 이해해야 한다. 패킷은 단순히 NIC 포트를 통해 들어오고 나가는 것이 아니라, PCIe 장치로 인식된 NIC와 메모리 사이에서 Rx/Tx Descriptor Ring, DMA, 인터럽트 등의 구조를 통해 처리된다.
NIC (Network Interface Card, 이더넷 카드)

NIC는 서버와 외부 네트워크를 연결해 주는 하드웨어 장치로, 흔히 이더넷 카드라고 부른다. 메인보드에 내장되거나 PCIe 카드 형태로 추가 장착될 수 있으며, 서버가 네트워크와 통신할 수 있도록 패킷 송수신을 담당한다.
- MAC 주소 관리
- NIC는 고유한 MAC 주소를 가지며, 이 주소는 같은 네트워크 내에서 장치를 식별하는 데 사용된다.
- 프로토콜 처리
- NIC는 이더넷과 같은 네트워크 프로토콜을 지원하며, 주로 데이터 링크 계층과 물리 계층의 기능을 수행한다.
- 데이터 송수신
- NIC는 네트워크를 통해 데이터를 송수신하며, 컴퓨터 내부 데이터를 네트워크에서 전달 가능한 프레임 형태로 변환한다.
NIC의 MAC 주소는 DHCP 등을 통해 IP 주소가 할당되면, 운영체제는 이를 네트워크 인터페이스에 바인딩하여 통신에 사용한다.
Function 구조

NIC에는 실제 케이블이 연결되는 물리 포트가 있다. 운영체제에서는 이 포트가 eth0, ens1f0 같은 네트워크 인터페이스처럼 보이게 된다. 그래서 보통 "포트 = 인터페이스" 처럼 이해하게 된다. 하지만 그보다 더 아래인 서버 내부 관점에서 보면 NIC는 PCIe 버스에 연결된 하드웨어 장치로 인식된다.

PCI 장치는 보통 [도메인]:[버스]:[디바이스].[함수] 주소 형식으로 표현된다. 여기서 앞의 도메인, 버스, 디바이스는 PCIe 트리에서 장치가 연결된 위치를 나타내고, 맨 뒤의 .0, .1 같은 값이 Function 번호를 나타낸다. 즉, 마지막 함수(Function)가 하나의 PCI 장치 안에서 운영체제가 구분해서 보는 개별 논리 장치 이다.
이러한 PCI Function 구조를 기반으로 하나의 물리 장치를 여러 개의 가상 PCI 장치처럼 나누어 사용하는 기술이 SR-IOV이다.

SR-IOV (Single Root I/O Virtualization)
하나의 물리 PCI 장치를 여러 개의 가상 PCI 장치로 분할하여 각각을 독립적인 네트워크 인터페이스처럼 사용할 수 있도록 해주는 PCIe 확장 기술
PF (Physical Function)
- 실제 물리 디바이스
- NIC 전체를 대표하는 관리자 기능
- VF 세트를 생성하고 관리하는 담당
VF (Virtual Function)
- OS에서 독립된 PCI 장치처럼 보임
- PF로부터 생성된 경량 PCIe 기능
SR-IOV 환경에서는 이 Function이 다음과 같이 나뉜다. 이렇게 분리된 가상 PCI 장치는 각각을 독립적인 네트워크 인터페이스처럼 사용할 수 있다.
Driver
OS와 하드웨어 사이에서 제어 명령과 자원 관리를 담당하는 소프트웨어 계층

이러한 PF와 VF를 제어하는 것이 드라이버(Driver)이다.
SR-IOV 환경에서는 PF와 VF 역할이 다르기 때문에 각각에 맞는 드라이버가 존재한다.
Intel 800 Series (E810)
- PF Drvier : ice
- VF Driver : iavf
Intel 700 Series (X710, XL710)
- PF Driver : i40e
- VF Driver : 구 커널은 VF 드라이버가 i40evf로 불렸고, 이후 iavf로 통합됨
Intel 500 Series (X550)
- PF Driver : ixgbe
- VF Driver : ixgbevf
그렇기 때문에 SR-IOV 구성 시에는 NIC 모델에 맞는 드라이버인지 반드시 확인해야 한다. 다음 명령어로 네트워크 인터페이스에 어떤 드라이버가 사용되고 있는지 확인할 수 있다.
$ cd /sys/class/net | l
Rx / Tx Descriptor Ring

NIC는 CPU와 직접 패킷을 주고 받는 것이 아니라, 메모리를 통해 통신한다. 이때 NIC와 드라이버 사이에서 사용되는 구조가 Rx/Tx Descriptor Ring 이다. 실제로 NIC의 Ring 정보는 다음 명령어로 확인할 수 있다.
$ ethtool -g ens1f0
이 Ring은 원형 버퍼 구조로 되어 있으며, 여러 개의 Descriptor가 배열 형태로 들어가 있다. Descriptor에는 다음 정보가 저장된다.
- DMA buffer 물리 주소
- 패킷 데이터 길이 정보
- status bit
- flags / control field
여기서 RX Ring은 수신용 버퍼, TX Ring은 송신용 버퍼로 사용된다.
패킷 수신 흐름
- 드라이버가 미리 패킷 버퍼들을 할당하고, 그 버퍼 주소를 RX descriptor ring에 채워넣는다.
- NIC은 외부로부터 패킷이 들어오면, DMA 엔진을 이용해 Descriptor가 가리키는 메모리 주소로 패킷을 써 넣는다.
- 데이터 기록이 끝나면 NIC는 해당 Descriptor 상태 비트를 “완료”로 바꾼다.
- 이때 NIC는 수신 완료를 알리기 위해 CPU에게 인터럽트를 발생시킨다.
※ Descriptor Status Bit
| 비트명 | 의미 |
| DD (Descriptor Done) | 수신 완료 |
| EOP (End Of Packet) | 패킷 마지막 조각 |
패킷 송신 흐름
- CPU 또는 드라이버가 전송할 패킷 데이터를 메모리 버퍼에 담는다.
- 패킷을 담은 버퍼 주소를 TX Descriptor Ring 에 등록한다.
- NIC는 TX Ring을 확인한 뒤, DMA를 통해 해당 메모리 버퍼의 패킷 데이터를 읽어온다.
- 이후 NIC가 패킷을 실제 네트워크로 전송하고, CPU에게 인터럽트로 전송 완료됨을 알린다.
※ Descriptor Status Bit
| 비트명 | 의미 |
| DD (Descriptor Done) | 수신 완료 |
| RS (Report Status) | 상태 보고 요청 |
이러한 송수신 구조에서 공통적인 문제점은 패킷마다 CPU와 커널이 개입하면서, 대량의 패킷을 처리할수록 오버헤드가 급격히 커진다는 점이다.
Kernel Network Stack의 병목 구간



1. 시스템 콜과 컨텍스트 스위칭 오버헤드
패킷을 송수신할 때마다 send(), recv()와 같은 시스템 콜이 발생하고, 이 과정에서 유저 모드와 커널 모드 간 전환이 반복된다.
이러한 전환은 패킷 수가 많아질수록 CPU 부담을 크게 증가시킨다.
2. 커널 네트워크 스택에서 발생하는 CPU 연산 비용
커널은 패킷을 처리하는 과정에서 메모리 복사, 프로토콜 헤더 처리, 체크섬 계산, 버퍼 관리 등 다양한 작업을 수행한다.
이 역시 패킷 처리량이 증가할수록 성능 저하의 원인이 된다.
3. 인터럽트 오버헤드
패킷이 도착할 때마다 인터럽트가 발생하면, 대량 트래픽 환경에서는 초당 매우 많은 인터럽트를 처리해야 한다.
이로 인해 CPU는 패킷 자체를 처리하기보다 인터럽트 대응에 많은 시간을 쓰게 되고, 전체 성능 저하로 이어진다.
이러한 문제를 해결하기 위해 Polling 기반 처리 방식과 Kernel Bypass 구조가 등장하였고, 대표적인 구현이 DPDK이다.
Polling & Kernel Bypass

Polling은 패킷이 도착했는지를 인터럽트로 통지받는 것이 아니라, CPU가 패킷을 받았는지 NIC의 Rx / Tx Descriptor Ring을 계속 확인하는 방식이다. Kernel Bypass는 커널 네트워크 스택을 우회하여 User Space에서 NIC를 직접 제어하는 구조이다.
DPDK는 이 두가지를 결합하여 고성능 패킷 처리를 구현하였다.
'Network' 카테고리의 다른 글
| [DPDK] DPDK 아키텍처 (0) | 2026.03.22 |
|---|