Title: The eXpress Data Path: Fast Programmable Packet Processing in the Operating System Kernel
Author: Toke Høiland-Jørgensen, Jesper Dangaard Brouer, Daniel Borkmann, John Fastabend, Tom Herbert, David Ahern, David Miller
Published: CoNEXT '18
ABSTRACT
Programmable packet 처리를 할 때 context switch가 발생하는 것을 피하기 위해 userspace에서 networking hardware를 control하는 kernerl을 우회하는 기술이 나날이 구현되고 있다. 하지만 os를 우회하기 때문에 기존에 os에서 제공한 application isolation(application access 권한 O)이나 보안적인 측면 또한 같이 우회가 된다.
이러한 문제를 해결하기 위해서 XDP(eXpress Data Path)를 제안한다. XDP는 packet을 custom하기 위해 Device deriver에서 실행되어 OS kernel이 안전한 실행 환경을 제공한다. XDP는 mainline linux kernel과 통합되어 있으며 linux network stack과 함께 동작한다. 고급언어로 쓰여진 application은 kernel에서 안전을 위해 정적으로 custom byte-code로 컴파일되며 자연어로 번역된다.
*mainline linux kernel = Linus Torvalds에 의해 직접 관리되는 공식 리눅스 커널로 안정적이다.
XDP는 single-core에서 초당 2,400만개 패킷을 처리할 수 있으며, 본 논문에서 3가지 use case를 보여주어 flexibility하다는 걸 보여준다. (L3 routing, inline DDoS protection, L4 load balancing)
1. Introduction
SW에서 고성능 패킷 처리를 위해서는 각 패킷을 처리하기 위한 시간이 촉박하다. 그렇기 때문에 각 패킷 당 많은 명령어를 처리하도록 범용 OS는 flexibility에 최적화되어 있다. 그래서 OS를 우회하며 flexibility를 위해 전용 toolkit이 제안되었으며 OS를 우회하는 대신에 하나 이상의 코어가 패킷 전용이 되어 패킷을 처리한다. 예시로는, DPDK(Data Plane Development Kit)가 있다.
* DPDK = kernel bypass framework. 커널 밖에서 networking hardware를 제어함으로써 kernel과 userspace에서 발생하는 overhead를 완전히 제거한다. (존재하는 프레임워크 중에서 가장 높은 성능을 제공한다. But, 관리, 유지보수, 보안 측면에서 단점이 존재)
하지만 전용 toolkit 같은 경우는 커널을 우회하기 때문에 성능 측면에서는 상당히 향상되지만, 기존 OS와 통합이 완전히 되지 않는다는 단점이 있고 OS가 제공하는 기능성에 대해서 다시 구현해야 된다는 단점이 있다. (routing tables, higher level protocols) 또한, 패킷 처리 application은 완전히 분리된 환경에서 직접 하드웨어에 접근해야 하기 때문에 os가 기존에 제공하던 tool과 deployment 메커니즘을 사용하지 못한다. 결과적으로 시스템 복잡성이 증가하고 os 커널에 의해 시행되던 보안 바운더리가 모호해진다. 특히 후자는, 커널에 의해 자원 isolation과 추상화가 시행되던 오케스트레이션 시스템(도커/쿠버네티스)과 컨테이너 기반 워크로드가 문제가 된다. (인프라 자원 isolation 문제)
이 논문에서는 기존 kernel bypass tech.의 한계를 극복하기 위해 새로운 시스템 디자인을 제안한다. 이 디자인은 기존 os에 programmability를 직접적으로 추가하는 시스템으로 이때 사용되는 프레임워크가 XDP(eXpress Data Path)이다. XDP는 기존 os와 통합이 가능하며 선택적으로 os의 기능성을 활용할 수 있다. (기존 한계 극복) XDP는 eBPF를 실행하는 VM 형태로 제한된 실행 환경을 제공한다. 간단한 원리는 패킷이 하드웨어로 들어오고 난 후에 가장 빠르게 접근할 수 있는 지점에서 kernel이 packet의 data에 접근하기 전에, custom program을 실행시키는 것이다. kernel은 load time에 정적으로 패킷을 검증함으로써 안전한 실행 환경을 제공하고 program은 기계어로 컴파일되어 고성능을 보장한다.
* load time = 컴파일 시간에 물리적 주소를 결정하고 로드 시간에 논리 주소를 물리적 주소로 바인딩한다.
XDP는 리눅스 커널에 계속해서 통합되고 있다. 하지만 DPDK만큼의 고성능을 제공하지 못한다. 그래서 본 논문에서는 이 점을 감안할 수 있을 만큼의 설득력 있는 제안을 한다.
- 기존 networking stack과 통합함으로써 커널에서 하드웨어에 대한 통제권을 유지한다. 보안적인 경계를 유지하며 네트워크 구성과 관리 툴을 변경하지 않아도 된다. 기존 존재하는 driver는 XDP hook만 추가되면 된다.
- 커널 네트워크 스택을 선택적으로 사용할 수 있다. 즉, routing table, TCP stack 등,,
- eBPF 명령어 set과 API의 안전성 보장
- userspace에서 kernel로 패킷 재주입할 필요가 없음
- 새로운 deployment 시나리오 가능
- 서비스 중단없이 동적으로 재프로그래밍이 가능
- 패킷 처리에 전체 CPU core를 할당할 필요가 없음
2. Related Work
XDP는 최초의 programmable packet processing 기술은 아니며 최근에도 점점 기술이 발전하고 있고 지금까지 여러 많은 프레임워크들이 제안되어 왔다. (여러 프레임워크들 덕분에 많은 application이 가능해졌는데, 그 예시로는 라우팅, 스위칭, name-based 포워딩, 분류, 캐싱, 트래픽 생성과 같은 단일 가능 수행하는 application) COTS 하드웨어에서 패킷 처리 기술을 사용하기 위해서는 NIC과 패킷 처리를 수행하는 프로그램 간 bottleneck을 해결해야하는데, 그 중 주요 원인은 os kernel과 user-level applicatone 사이의 인터페이스에서 발생한다. (system call의 높은 오버헤드와 기본 기능이 많은 stack의 복잡성) 이를 해결하기 위해 많은 프레임워크들이 나왔으며 XDP는 많은 프레임워크들 중 몇 개를 빌드업한 기술이다.
DPDK는 기존 가장 널리 사용되는 high-speed packet processing 프레임워크로 Intel-specific 하드웨어 지원 패키지로 시작되었지만 이후 Linux Foundation의 관리 하에 폭넓게 사용되었다. DPDK는 kernel의 역할인 하드웨어 제어를 networkig appliction이 하도록 하여 context switch로 인해 발생하는 오버헤드를 완전히 제거한 kernel bypass framework이다. (비슷하게 PF_RING_ZC, Solarflare사의 OpenOnload가 있다) 하지만 DPDK는 관리, 유지, 보안에 단점이 있다. (기존 os와 완전히 통합되지 않거나, os의 functionality를 재구현해야한다던가, hypervisor isolation와 같은 보안 문제)
기존에 널리 사용되던 프레임워크인 DPDK와 다르게, XDP는 networking 하드웨어 제어권을 바꾸는 것이 아니라 패킷 처리 작업을 os networking stack이 시작하기 전에 먼저 끝내버리는 것이다. 그러면 커널이 하드웨어 컨트롤을 계속 유지하면서 context switch 오버헤드를 제거할 수 있다. 커널이 하드웨어 컨트롤까지 하니까 보안 또한 문제가 되지 않는다. 이를 가능하게 하는 핵심 기술은 로드된 프로그램에 대해서 검증하는 가상 실행 환경을 사용하는 것이다.
XDP를 도입하기 전에는 packet processing 기능을 커널 모듈로 구현하였는데, 이 방식은 커널과 충돌할 수도 있고 Linux kernel community의 지원을 받지 않아 내부 커널 API가 자주 변경되면 이에 맞게 커널 모듈 개발자가 수정해야 하므로 비용이 많이 든다. 그래서 시스템에서 잘 사용하지 않았다. (XDP 이전에 사용되었던 프레임워크 : Open vSwitch, Click, Contrail) XDP를 도입한다면, linux kernel 커뮤니티의 지원을 받기 때문에 application API에 있어서 비용이 들지 않으며, 안전한 실행 환경을 제공하여 kernel과 실수로 충돌할 염려를 하지 않아도 된다. 또한 기존의 networking stack에 완전한 통합이 가능하기 때문에 커널 모듈 구현보다 높은 성능을 제공한다.
High-performance packet processing 기술로 DPDK와 같은 소프트웨어 NetFPGA와 같은 programmable hardware도 있다. 어떤 의미에서 XDP는 "software offload"와 같다. 왜냐하면 networking stack과 application이 상호작용하면서 고성능을 위해 패킷 처리를 offload하기 때문이다. 또한, kernel helper function에 access할 필요가 없어서 XDP프로그램이 지원이 가능한 Networking hardware로 완전히 오프될 수도 있다. (kernel helper function은 우리가 프로그래밍을 할 때 printk(), strncpy(), strlen(), kmalloc()과 같은 커널 내부 코드에서 자주 사용되는 기능의 함수를 의미한다.)
즉, XDP는 이전 접근 방식을 기반으로 성능, 시스템 통합, flexibility 간의 새로운 균형을 제공하는 high-performance packet processing에 대한 approach를 제공한다.
3. The design of XDP
XDP 설계의 기본 원리는 os kernel과 통합하면서 나머지 시스템에서 안전성과 무결성을 제공하고 high-performance packet processing을 할 수 있도록 하는 것이다. 설계에서는 XDP의 구성요소들이 어떻게 작동하는지와 XDP가 full system을 만들기 위해 어떻게 결합되는지를 설명한다.
XDP의 주요 구성 요소 4가지
- (3.1) The XDP driver hook : XDP 프로그램을 위한 주요 진입점으로 packet이 hardware에 들어왔을 때 실행이 된다.
- (3.2) The eBPF virtual machine : XDP 프로그램의 바이트코드를 실행하고, JIT 컴파일을 수행한다.
- (3.3) BPF maps : 시스템의 나머지 부분에서 communication channel 역할을 하는 KVS
- (3.4) The eBPF verifier : XDP 프로그램이 로드되기 전에 정적으로 프로그램을 검증한다. (동작중인 kernel과 충돌이 나지 않음을 보장하기 위함)
3.1 The XDP Driver Hook
XDP driver hook은 packet이 들어올 때마다 실행이 되는데, 이는 kernel에 library function으로서 포함되어 있다. 즉, context switch없이 직접 Device driver에서 실행한다. XDP driver hook은 하드웨어로부터 패킷이 들어오고 sk_buff 데이터 구조를 할당하거나 parse packet을 하기 전 가능한 가장 빠른 순간에 실행이 된다.
Figure 2를 보면, 프로그램은 context object에 access하여 시작한다. packet이 들어오면 우선 parsing을 한다. context object는 쉽게 생각하면 packet의 정보를 알고 있는 포인터라고 생각하면 되는데, interface와 receive queue를 묘사하는 메타데이터와 raw packet data에 대한 포인터이다. 즉, packet의 정보를 받고 xdp 프로그램은 시작한다. 또한 tail call을 통해 다른 xdp 프로그램에 제어권을 전달할 수 있는데, 이것의 의미는 처리를 논리적 하위 단위로 쪼갤 수 있다는 의미이다.
context object는 메모리 내 packet의 data와 인접한 special memory area에 access가 가능해서 XDP program이 자제 메타데이터를 packet의 첨부할 수 있고 이는 시스템을 통과할 때 같이 전달된다. 패킷별 메타데이터 외에도 BPF map을 통해서 자체 영구적인 데이터 구조를 정의하고 접근할 수 있으며 다양한 helper function을 사용하여 kernel 기능에도 접근이 가능하다. (XDP는 linux kernel community 하에서 관리 되기 때문에 새로운 helper function은 적극적으로 추가되고 계속 확장되고 있다.) 프로그램은 헤더를 추가하거나 삭제하기 위해 packet buffer를 확장하거나 축소할 수도 있고 패킷 데이터의 모든 부분을 사용할 수 있다. (encapsulation/decapsulation, rewrite) Figure 2의 왼쪽 세 박스는 번갈아 가면서 실행이 가능하며 임의의 명령어를 추가할 수도 있지만, 고성능을 위해서는 위 flow대로 하는 것이 제일 좋다.
처리가 끝나면, XDP 프로그램은 packet에 대해 최종 판정을 내린다. parameter가 없는 3개의 return code와 parameter가 있는 1개의 return code 중 하나를 선택하여 수행을 한다. parameter가 없는 3개의 return code는 packet drop, re-transmit out the same network interface(Xmit out), or allow to be processed by the networking stack(parse to stack).
나머지 한 개의 returen code는 program이 나가기 전에 helper function을 통해 설정되는 redirection target을 지정하는 매개 변수를 요청하는 redirect return code이다. redirect functionalirt는 (1) 다른 interface로 전송 (2) 추가 처리를 위해 다른 CPU로 전송 (3) 다음 작업을 수행하는데 특수 userspace socket address family(AF_XDP)에 직접 전달. Redirect 매개변수는 map lookup(XDP 프로그램이 조회 key를 제공)으로 구현되어서 프로그램 수정없이 동적으로 변경 가능.
3.2 The eBPF Virtual Machine
XDP 프로그램은 eBPF VM을 사용하여 실행이 된다. eBPF는 BPF의 확장 버전으로 64bit, 11개의 레지스터를 지원하여 레지스터 기반 VM을 사용한다. 64bit 레지스터는 커널이 지원하는 64bit 아키텍처의 하드웨어 레지스터에 1:1로 매핑이 가능하여 기계어로 효율적인 JIT 컴파일이 가능하다. (1:1 매핑이 가능하다는 건, 메모리 복사를 통한 오버헤드가 없으며 데이터 변환, context switch를 통한 오버헤드가 없다는 의미이다. 즉, 함수 호출에 있어서 zero additional overhead) 이러한 매핑은 eBPF 프로그램이 커널과 상호작용이 가능하며 eBPF 프로그램 간 함수 호출을 지원할 수 있다.
eBPF는 커널에서 지원하는 아키텍처에서 사용하는 C언어 규칙과 동일한 호출 규칙을 채택하며 kernel address space 내에서 로드된 프로그램을 실행하기 때문에 안전하며 eBPF는 XDP 뿐만 아니라 linux 커널의 다양한 작업을 유용하게 실행한다. 또한 모든 eBPF 프로그램은 동일한 set of maps를 공유하므로 만약 CPU 로드를 모니터링하다가 로드가 임계값을 넘어가면 드롭하도록 지시를 할 수 있다.
즉, eBPF VM은 동적으로 프로그램을 로드하고 reload 또한 지원하며 모든 프로그램의 수명 주기를 관리한다.이를 통해 처리량을 확장하거나 제한하여 필요하지 않은 프로그램 부분은 제거도 가능하다. 또한 프로그램의 동적 로딩은 직접 processing rule을 program code에서 표현이 가능하며 범용 데이터 구조로 대체함으로써 성능을 향상시킬 수 있다.
3.3 BPF Maps
BPF Maps는 eBPF 프로그램이 로드될 때 커널의 event에 대한 답으로 실행되어 실행될 때마다 initial state로 실행된다. 영구적인 메모리에 접근을 할 수 없어서 kernel은 helper function을 제공하여 BPF Maps에 접근할 수 있도록 한다.
BPF Maps는 영구적인 KVS로, eBPF 프로그램이 로드 시 정의되며 eBPF 코드 내에서 참조가 가능하다. BPF Maps의 타입은 hash map, array, radix trees, specialised types(tail call을 부를 때 pointer), redirect target pointer가 있다.
eBPF 프로그램 호출 간 KVS로 사용되며, eBPF 프로그램이 다른 부분의 동작을 변경하면 이에 대해 업데이트를 하는 역할(전역 조정 도구)도 한다. 또한 같은 eBPF 프로그램 간 또는 eBPF 프로그램과 userspace 간의 communication 담당도 한다.
3.4 The eBPF Verifier
eBPF verifier의 역할은 eBPF code가 실행되면 virtual memory address에 직접적인 접근이나 잠재적인 충돌이 발생할 수 있기 때문에 직접적인 접근을 막기 위해서 in-kernel single entry point에서 먼저 실행이 되어 정적으로 모든 eBPF program의 바이트 코드를 검증한다. (eBPF code가 virtual memory address에 접근하는 이유는 유연한 커널 추적이나 모니터링을 위해서이다. 구조체에 접근해서 메모리에 읽기/쓰기를 함으로써 매핑정보를 확인할 수 있다.)
The verifier는 DAG(싸이클이 없는 비순환 그래프)에서 프로그램의 control flow를 building 한다. 우선 깊이 우선 탐색으로 제한된 루프나 최대 크기 메모리 사이즈가 있는지 확인하고 그 다음에 모든 가능한 path를 확인해서 안전한 메모리 접근을 하는지 확인하고 helper function에 올바른 인자를 사용하였는지 확인한다. 인자의 유효성 확인은 모든 레지스터와 스택 변수의 상태를 정적으로 추적해서 확인한다. 각 path에서 가능한 state 범위를 추적하는 레지스터 상태 추적 메커니즘은 다양한 크기의 packet으로 인해 미리 메모리 boundary를 알 수 없기 때문에 verifier는 프로그램이 로드되면 역참조를 방지하기 위해 자신의 bounds checking하고 map lookup이 NULL인지 확인한다.
Data access를 추적할 때, state variables에 range information을 저장하는데, range information은 프로그램이 실행될 때 register state가 명령어에 기반하여 업데이트 되고 레지스터에서 새로운 값을 저장하면 레지스터는 state variables에 상속을 한다. state variables에 range 정보가 있기 때문에 verifier는 이를 기반으로 메모리 범위를예측하여 안전한 메모리 접근만 수행한다는 걸 보장할 수 있다.
The verifier는 안전하지 않은 action이 있는 program은 수행하지 않고 load time에 종료시킬 것임을 보장하기 때문에 kernel 내부가 안전하게 동작하는 걸 보장한다. 즉, eBPF verifier의 목적은 악의가 있거나 버그가 있는 eBPF 프로그램으로부터 커널 내부를 안전하게 보호하는 것이다.
3.5 Example XDP program
eBFP 프로그램이 실행되면 첫 번째로 eBPF byte code로 컴파일되고 그 다음으로 eBPF verifier에 의해 검사를 한다.
(1) loop의 부재 & 프로그램의 전체 사이즈 → verifier에서 깊이 우선 탐색으로 탐색한다. 그리고 제한된 크기 이상으로 넘어갔는지 확인한다.
(2) 모든 direct packet data가 적절한 bound에 접근했는지 확인 → 모든 패킷 사이즈가 다양하기 때문에 verifier나 map이 미리 메모리 boundary를 알 수 없어서 자신의 bounds checking을 하고, 다른 메모리에 접근하지 않았는지 체크한다. (레지스터와 스택 변수의 state를 사용해서)
(3) map lookup function에 전달된 parameter의 size가 map definition와 일치하는지
(4) return value가 access되기 전에 NULL인지 확인
3.6 Summary
XDP driver hook은 XDP program의 entry point로 packet이 하드웨어로부터 들어왔을 때, sk_buff를 실행하거나 networking stack으로 data가 넘어가지 전에 실행이 된다.
The eBPF virtual machine은 RISC 계열의 eBPF를 사용하여 효율적인 JIT 컴파일과 동적 로드를 통해 성능을 향상시킨다. (eBPF VM을 사용하여야 하는 이유는 커널 내에서 실행을 하기 때문에 추가적인 context switch가 발생하지 않기 때문이다. 기존의 high-performance packet processing 기술은 커널을 우회하는데 이는 커널 내에서 JIT 컴파일을 통해 overhead가 발생하지 않으며 커널 내에서 기존의 os와 os의 functionality를 사용할 수 있기 때문이다.)
BPF maps는 communication channel 역할을 하고 기존에는 메모리에 접근이 되지 않았는데 maps의 영구적인 KVS를 사용할 수 있다.
The eBPF verifier는 커널 내부에서 메모리 접근이나 충돌을 방지하고 안전한 커널 내부를 보장하기 위해서 eBPF 코드를 검증하는 역할을 한다.
위 네 가지 component는 writing custom packet processing을 강력하고 안전한 환경을 만들어준다.
4. Performance Evaluation - raw packet processing performance
XDP 성능을 평가하기 위해서 DPDK와 비교하였다. (모든 packet processing 기술을 다루기에는 논문 범위에 한계가 있으며 현재 최신 기술에서 high-performance이기 때문에 선정) DPDK의 testpmd를 사용하였으며 세부사항은 밑에 깃헙 레포지토리를 참고하면 된다.
Benchmark에서 사용한 CPU는 Intel DDIO를 지원하는 hexa-core Intel® Xeon E5-16450 v4를 사용하였다. Intel DDIO 기술은 하드웨어 DMA가 패킷 데이터를 CPU cache에 직접 배치할 수 있기 때문에 성능이 향상된다. 네트워크 어댑터는 2개의 Mellanox ConnectX-5 Ex VPI dual ports 100Gbps를 사용하였으며 TRex packet generator를 사용하여 일정한 테스트 트래픽을 생성하였다. OS는 Linux kernel pre-release of version 4.18을 사용하였다.
Intel DDIO 기술: networking processing을 할 때 메인 메모리가 아니라 CPU cache를 사용하도록 하는 기술이다.
https://github.com/tohojo/xdp-paper → (source code와 raw test data) Repository
Evaluaion을 위해 3가지 지표를 사용하였다.
- (4.1) Packet drop performance : 최대 패킷 처리 성능을 보여주기 위해서 가장 간단하게 측정할 수 있는 건, 들어오는 패킷을 drop하는 것이다. 이는 효과적으로 오버헤드를 측정하며 실제 애플리케이션의 상한성을 알 수 있다.
- (4.2) CPU usage : XDP의 이점은 패킷을 처리하는 전용 CPU를 두는 것 대신에 CPU 사용량을 패킷 로드에 따라 확장시키는 것이다. 어떻게 확장시키는지 보여준다.
- (4.3) Packet forwarding performance : forwarding을 할 수 없는 시스템은 유용성 측면에서 제한되고 forwarding을 하는 것은 복잡하기 때문에, forwarding을 평가하면서 latency와 throughput을 보여준다.
초당 최대 패킷 수를 처리하는 것이 중요하기 때문에 최소 크기(64 bytes)로 측정한다. (물론 single core의 half-idle 상태에서 또한 최대 크기(1500 bytes)로 100Gbps에서도 측정을 하였다.) CPU usage에서는 CPU core 수에 따라 성능 확장이 어떻게 되는지 보여주기 위해 패킷을 처리하는 전용 코어 수를 늘려가면서 측정한다. 또한 XDP와 Linux network stack은 하드웨어 RSS 기술을 사용하여 각 테스트에서 원하는 코어 수로 트래픽을 조정하였다.
hardware Receive Side Scaling (RSS) : Receive packet에 중점을 두어, 여러 CPU에서 네트워크 수신 처리를 효율적으로 분산할 수 있는 network driver 기술이다. (network packet 처리를 여러 CPU core에 분산시켜 네트워크 성능 향상)
4.1 Packet Drop Performance
아래 Figure 3은 packet drop performance를 보여주며 하드웨어의 한계까지 측정하였다. DPDK와 XDP는 PCI bus의 전역 성능 한계에 도달할 때까지 측정한 결과, DPDK는 43.5Mpps, XDP는 24Mpps가 single core에서 측정되었다. 두 모델 다 선형적으로 증가함을 볼 수 있다. (DPDK가 더 높은 이유는 DPDK는 완전하게 커널 밖에서 실행이 되기 때문에 context switch를 완전히 제거한다. 또한 DPDK는 패킷 처리를 하는 전용 CPU core가 따로 있고 최대 5개까지 사용이 가능하기 때문에 5개까지 성능측정을 하였다.)
또한, 2가지 구성의 Linux networking stack 성능을 보여준다. Linux(raw)는 iptables를 사용하여 가장 빠른 drop을 보장하는 것을 보여주고 Linux(conntrack)은 높은 오버헤드가 있지만 Linux distribution에서 기본적으로 활성화되는 모듈이다. conntrack은 1.8Mpps, raw는 4.8Mpps의 성능 범위를 보여주었다.
결론적으로, XDP는 Linux networking stack의 최대 성능인 Linux(raw)의 4.8Mpps에 비해 5배 향상된 성능을 제공한다.
4.2 CPU Usage
single core에서 mpstat system utility를 사용하여 packet drop을 실행하였다. 처리할 수 있는 최대값까지 각 제공된 패킷 로드를 측정한 것이다. (예를 들어, 1초동안 500만개 주었을 때, 1000만개 주었을 때,,,이렇게 측정하였다.) 근데 Figure 3에서, single core를 측정할 때 DPDK는 이미 43.5Mpps를 드랍하였으므로 전부 100%이다. XDP는 24Mpps였으므로 선형적으로 CPU 사용량이 증가하다가 24Mpps가 제공되었을 때 100%가 되었다.
DPDK는 설계상 전체 코어를 패킷 처리 전용으로 사용하고 Busy polling을 사용하기 때문에 CPU 사용량은 항상 100%로 나왔다. XDP와 Linux는 제공된 load에 따라 선형적으로 확장하였으며 적게 제공되었을 때는 CPU 사용량이 상대적으로 약간 더 증가하였다. (적은 쪽이 그래프가 더 가파름)
왼쪽 하단의 비선형은 인터럽트 처리의 고정 오버헤드로인해 발생하여 패킷 속도가 낮을수록 인터럽트 동안 처리하는 패킷 수가 적고 패킷당 CPU 사용량이 높아진다.
4.3 Packet Forwarding Performance
The forwarding application은 들어오는 패킷의 source, destination address가 교환되는 간단한 이더넷 address rewrite를 수행한다.이는 packet forwarding을 하는데 필요한 최소한의 작업이므로 결과적으로 성능의 상한선이다.
XDP는 같은 NIC, 다른 NIC 둘 다 가능하고 DPDK는 다른 NIC만 가능하기 때문에 Figure 5와 같은 실험이 진행되었다.
(Linux networking stack의 경우는 forwarding을 지원하지 않으며 이를 위해서는 full bridging이나 routing loopup이 필요하다. loopup은 비용이 많이 들고 다른 application은 이를 수행하지 않으므로 직접적인 비교가 불가능하다.)
절대적으로는 성능이 packet drop case보다 forwarding의 overhead가 더 낮게 측정이 되었다. 또한 2개 코어 이상에서 XDP는 DPDK보다 더 높은 packet forwarding을 보여주었다. 성능 차이는 주로 메모리에서의 처리 차이로 발생하는데 packet buffer는 device driver에 의해 할당되고 receive interface와 연결된다. 그렇기 때문에 different NIC에서 packet buffer는 연결된 인터페이스로 반환이 되어야 한다.
아래 Table 1에서 볼 수 있듯이, packet forwarding latency를 보면 서로 다른 NIC forwarding에 대해 둘 다 상대적으로 높은 성능이 반영되었다. 하지만, XDP의 대기시간은 인터럽트 처리 시간에 의해 좌우되며, DPDK는 폴링 기반이기 때문에 end-ti-end latency는 DPDK보다 XDP가 더 길다.
4.4 Discussion
XDP보다 DPDK가 더 성능이 좋은 이유는 DPDK가 low-level code에서 더 성능 최적화를 통합했기 때문이다. 둘의 성능 차이는 18.7ns 차이가 나는데, 어느 정도의 큰 차이냐면 single function call을 했을 때 발생하는 오버헤드가 1.3ns이다. 하지만 저자는 linux에서의 오버헤드는 피할 수 없으며, XDP의 function call을 일부 제거하고 다른 성능 최적화와 결합을 하면 DPDK와의 성능 차이가 좁혀질 것이라고 주장한다. 또한 유연성과 시스템 통합 측면에서는 XDP가 더 매력적이라고 한다.
5. Real-world Use cases
XDP의 다양한 측면을 사용하여 유용한 real-world application을 구현하는 것을 보여준다. 코드를 사용 가능하게 할려고 간단한 버전을 사용하였으며 최신 구현에 대해서 철저한 성능 평가를 하지는 않았다. baseline은 Linux networking stack을 사용하였고 이에 대해 XDP application을 벤치마킹한다.
5.1 Sofrware Routing
Linux에는 모든 기능을 갖춘 라우팅 테이블이 있으며 이는 control plane에서 routing networking stack을 재구현하는 것은 비용이 많이 드니까 XDP가 적합하며 data plane에서는 라우팅 테이블이 성능을 향상시킨다. 그렇기 때문에 XDP는 직접 full 라우팅 테이블을 조회하는 작업에 적합하다. XDP는 packet에 대해서 테이블 조회를 통해 egress interface와 다음 hop의 MAC 주소를 알 수 있는데 만약 다음 hop의 MAC 주소를 알지 못하면 networking stack으로 보내서 packet을 XDP가 포워딩 할 수 있도록 한다.
아래 Figure 6에서 Linux networking stack과 두 가지 테스트를 수행한 결과이다. 테스트 중 하나는 라우팅 테이블에 설치된 single route이고 다른 하나는 전역 BGP 라우팅 테이블의 전체 dump를 사용하는 것이다. (전체 테이블에는 752,138개의 개별 경로가 있으며 4,000개의 랜덤 destination IP 주소를 생성한다) 결과적으로 full table을 사용하면 XDP는 2.5배, single route의 경우 3배로 성능이 향상되었다. 즉, 단일 코어에서 전체 BFP 테이블이 있는 소프트웨어 라우터를 사용할 수 있다.
5.2 Inline Dos Mitigation
DoS 공격을 완화하기 위해, XDP로 패킷 필터링을 배포하여 완화할 수 있다. 가상 머신의 경우에도 hypervisor에서 필터 설치가 가능하므로 가상 머신의 보호가 가능하다.
XDP를 필터링 매커니즘으로 사용하는 Cloudflare의 DDoS 완화 아키텍처 모델로 테스트를 한다. 해당 모델(=Gatebot)은 분산된 PoP(지역 데이터센터)에 위치한 서버에서 트래픽을 중앙에서 수집하고 분석을 기반으로 완화 rule을 공식화하는 방식이다. 이는 eBPF 프로그램이 XDP 모드에서 실행되어 공격 패킷을 차단한다. 성능을 실험하기 위해 패킷 헤더 파싱, 공격 트래픽 식별 및 삭제하는 XDP 프로그램을 사용하고 CPU 리디렉션 기능으로 다른 CPU 코어에게 분산적으로 전달하여 처리한다. 정상 트래픽 부하는 Netperf 벤치마킹 도구로 TCP-based round-trip benchmark이다.
single core에서 초당 35,000 TCP 트랜잭션의 baseline load를 적용하고 패킷 필터와 일치하는 UDP 공격 트래픽 로드 증가를 제공하여 DoS 공격을 시뮬레이션한다. 데이터 포인트 당 평균 4번의 테스트를 반복하였다. Figure 7에서 볼 수 있다시피, XDP를 적용하면 19.5 Mpps가 될 때까지 트랜잭션이 안정적이었다가 그 이후 급격하게 떨어진다. 이는 single core에서 10Gbps에서 XDP 기반 DDoS 필터링이 효과적으로 대응할 수 있음을 보여준다.
5.3 Load Balancing
XDP는 로드 밸런서를 Facebook에서 오픈소스로 release한 Katran load balancer를 XDP 구성요소로 사용하였다. 로드밸런서는 src.IP를 해시하여 des.서버를 선택한다. 그리고 캡슐화되어서 캡슐화 해제, 요청 처리, 보낸 사람에게 직접적으로 응답하는 서버로 전송된다. 이때 XDP는 해싱 및 캡슐화를 하고 수신했던 인터페이스로 패킷을 return 한다. (BPF map에서 구성 data를 유지하고 eBPF 프로그램에서 완전한 캡슐화를 구현함.)
아래 Table 2는 XDP와 Linux 커널의 일부인 IPVS 로드 밸런서를 비교한다. CPU 수에 따른 선형적 증가를 보여주며 XDP는 IPVS에 비해 4.3배의 성능 향상을 보여준다.
7. Conclusion
XDP는 안전하게 os kernel에 통합이 가능한 fast programmable packet 처리 기술로 single CPU core에서 24Mpps의 raw pakcet 처리 성능을 보여주었다. 비록 DPDK보다 낮은 성능이지만 XDP는 그만큼의 성능 차이를 감안할 수 있는 장점이 있다. (커널 안전 유지, 관리 호환성, 선택적으로 kernel stack 기술 사용, 안전한 프로그래밍 인터페이스, 완전한 투명성) 또한 XDP는 서비스 중단 없이 동적으로 재프로그래밍이 가능하며 DPDK와 같이 전용 CPU가 따로 없고 특별한 하드웨어를 요구하지도 않는다.
본 논문에서 real-world application의 다양한 XDP의 적용을 보여주었으며, XDP는 여전히 발전하고 있고 계속해서 향상이 될 것임을 주장한다.
Reference
Linux mainline kernel
load time
https://gamedevlog.tistory.com/83
PF_RING_ZA (multi 10Gbit Ethernet, RX/TX packet processing framework)
https://www.ntop.org/products/packet-capture/pf_ring/pf_ring-zc-zero-copy/
Solarflare OpenOnload (using BSD socket, high performance user-level network stack)
https://github.com/Xilinx-CNS/onload
Gigabit Ethernet
https://designusefulthings.tistory.com/38
Intel DDIO technolohy
https://www.intel.com/content/www/us/en/io/data-direct-i-o-technology.html
RSS
BGP
'연구 > Paper' 카테고리의 다른 글
[Eurosys '24] SmartNIC Security Isolation in the Cloud with S-NIC (2) | 2024.03.18 |
---|---|
[SOSP '23] Achieving Microsecond-Scale Tail Latency Efficiently with Approximate Optimal Scheduling (2) | 2023.11.18 |