Linux eBPF & XDP Networking Primer
// BPF map: src IP → drop flag (1 = drop)
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, __u32); // source IPv4 address
__type(value, __u32); // 1 = block
} blocklist SEC(".maps");
SEC("xdp")
int xdp_drop_udp(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
// Parse Ethernet header
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end) return XDP_PASS;
if (eth->h_proto != __constant_htons(ETH_P_IP)) return XDP_PASS;
// Parse IPv4 header
struct iphdr *ip = (void *)(eth + 1);
if ((void *)(ip + 1) > data_end) return XDP_PASS;
if (ip->protocol != IPPROTO_UDP) return XDP_PASS;
// Check blocklist map
__u32 src = ip->saddr;
__u32 *val = bpf_map_lookup_elem(&blocklist, &src);
if (val && *val == 1) return XDP_DROP;
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
경계 확인은 필수입니다.eBPF 검증자는 그 이상으로 메모리에 액세스하는 프로그램을 거부합니다.
data_end. 모든 포인터 산술 연산 뒤에는 경계 검사가 뒤따라야 합니다. 그렇지 않으면 프로그램이 로드되지 않습니다.다음을 사용하여 로드하고 연결하세요.ip:
# Compile
clang -O2 -target bpf -c xdp_drop_udp.c -o xdp_drop_udp.o
# Attach to interface (native XDP)
ip link set eth0 xdp obj xdp_drop_udp.o sec xdp
# Add an IP to the blocklist via bpftool
bpftool map update name blocklist key 0x01 0x02 0x03 0x04 value 0x01 0x00 0x00 0x00
# Remove XDP program
ip link set eth0 xdp off
4. AF_XDP: 커널 바이패스
AF_XDPXDP와 결합된 소켓 제품군입니다.XDP_REDIRECT평결은 패킷당 커널 개입 없이 패킷을 UMEM(사용자 공간 메모리 영역)에 직접 전달합니다. 이는 DPDK의 커널 우회 모델에 대한 eBPF 생태계의 답변입니다.
주요 구성 요소:
- UMEM: 사용자 공간에 등록된 메모리 영역을 프레임으로 구분합니다. 공유 메모리를 통해 커널과 사용자 공간 간에 공유됩니다.
- 반지: 소켓당 4개의 잠금 해제 링: 채우기(사용자 공간 → 여유 프레임이 있는 커널), 완료(커널 → TX 완료 프레임이 있는 사용자 공간), RX 링(커널 → 수신된 프레임이 있는 사용자 공간), TX 링(사용자 공간 → 보낼 프레임이 있는 커널).
- 제로 카피 모드: 드라이버가 지원하는 경우 프레임은 복사 없이 포인터 전달만으로 전송됩니다.
AF_XDP는 DPDK의 운영 복잡성 없이 회선 속도에서 사용자 정의 패킷 처리에 이상적입니다(거대한 페이지가 없고 기본 사용에 CPU 고정이 필요하지 않음).
5. tc BPF: 트래픽 형성 및 필터링
tc(트래픽 제어) BPF 프로그램은clsactqdisc이며 수신 또는 송신 시 실행될 수 있습니다. XDP와 달리 전체 내용을 볼 수 있습니다.sk_buff소켓 메타데이터, VLAN 및 터널 헤더에 액세스할 수 있습니다.
// tc_mark.c — Mark packets with DSCP EF (46) for VoIP traffic on port 5060
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <bpf/bpf_helpers.h>
SEC("classifier")
int tc_mark_voip(struct __sk_buff *skb) {
void *data = (void *)(long)skb->data;
void *data_end = (void *)(long)skb->data_end;
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end) return TC_ACT_OK;
if (eth->h_proto != __constant_htons(ETH_P_IP)) return TC_ACT_OK;
struct iphdr *ip = (void *)(eth + 1);
if ((void *)(ip + 1) > data_end) return TC_ACT_OK;
if (ip->protocol != IPPROTO_UDP) return TC_ACT_OK;
struct udphdr *udp = (void *)(ip + 1);
if ((void *)(udp + 1) > data_end) return TC_ACT_OK;
// Mark SIP traffic (port 5060) with DSCP EF (46 = 0xB8 in TOS byte)
if (udp->dest == __constant_htons(5060) || udp->source == __constant_htons(5060)) {
// DSCP EF = 46, shifted left 2 bits in TOS field = 184 (0xB8)
bpf_skb_store_bytes(skb, offsetof(struct iphdr, tos) + sizeof(struct ethhdr),
&((__u8){184}), 1, BPF_F_RECOMPUTE_CSUM);
}
return TC_ACT_OK;
}
char _license[] SEC("license") = "GPL";
# Attach tc BPF program
tc qdisc add dev eth0 clsact
tc filter add dev eth0 egress bpf da obj tc_mark.o sec classifier
6. eBPF 맵을 통한 속도 제한
eBPF 맵은 상태 저장 처리를 가능하게 합니다. 다음 패턴은 저장소에 저장된 토큰 버킷을 사용하여 소스 IP별 속도 제한을 구현합니다.BPF_MAP_TYPE_LRU_HASH:
// Conceptual token bucket per source IP — checks tokens, drops if exceeded
struct ratelimit_entry {
__u64 tokens; // current token count
__u64 last_update; // nanoseconds timestamp
};
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(max_entries, 65536);
__type(key, __u32); // source IP
__type(value, struct ratelimit_entry);
} rate_map SEC(".maps");
// In XDP program:
// 1. bpf_ktime_get_ns() — get current time
// 2. Lookup entry for src IP
// 3. Refill tokens: tokens += (elapsed_ns / 1e9) * rate_pps
// 4. If tokens >= 1: decrement and XDP_PASS
// 5. Else: XDP_DROP
7. bpftool 및 bpftrace 내부 검사
라이브 eBPF 프로그램 작업을 위한 두 가지 필수 도구:
# bpftool — inspect loaded programs and maps
bpftool prog list # list all loaded eBPF programs
bpftool prog show id 42 # details for program ID 42
bpftool prog dump xlated id 42 # disassemble to eBPF bytecode
bpftool prog dump jited id 42 # dump JIT-compiled native code
bpftool map list # list all BPF maps
bpftool map dump name blocklist # dump all entries in map "blocklist"
bpftool map update name blocklist \
key 192 168 1 100 value 1 0 0 0 # add entry (network byte order)
# bpftrace — DTrace-style one-liners for kernel tracing
# Count XDP drops per second
bpftrace -e 'tracepoint:xdp:xdp_exception { @drops[args->action] = count(); } interval:s:1 { print(@drops); clear(@drops); }'
# Trace tcp_retransmit_skb — show retransmit events with comm name
bpftrace -e 'kprobe:tcp_retransmit_skb { printf("%s retransmit\n", comm); }'
# Histogram of packet sizes on eth0
bpftrace -e 'tracepoint:net:netif_receive_skb /args->name == "eth0"/ { @size = hist(args->len); }'
8. 비교: eBPF/XDP vs DPDK vs RDMA
| 특징 | eBPF/XDP | DPDK | RDMA |
|---|---|---|---|
| 커널 참여 | 최소(드라이버의 XDP) | 없음(완전 우회) | 없음(RDMA NIC) |
| 메모리 모델 | 표준 + AF_XDP UMEM | 거대한 페이지가 필요합니다. | 등록된 메모리 영역 |
| 최대 처리량 | ~100Gbps 기본 XDP | >100Gbps | 200Gbps 이상(InfiniBand) |
| CPU 사용량 | 낮음(이벤트 중심) | 높음(사용 중 폴링 코어) | 거의 영점(오프로드됨) |
| 운영 복잡성 | 낮음 - 표준 도구 | 높음 - 전용 코어, 거대 페이지 | 높음 - 패브릭 관리 |
| 사용 사례 | DDoS 완화, LB, 관측 가능성 | 가상 라우터, NFV, 패킷 생성 | 스토리지(NVMe-oF), HPC MPI |
| 언어 | 제한된 C / Rust | C/러스트 | 동사 API(C) |
경험 법칙:eBPF/XDP로 시작하세요. 기존 커널 도구와 통합되고 특별한 하드웨어나 대용량 페이지가 필요하지 않으며 100Gbps 미만의 대부분의 고성능 네트워킹 사용 사례를 처리합니다. 전용 CPU 코어가 필요하고 커널 예약 오버헤드를 허용할 수 없는 경우에만 DPDK로 이동하세요.