1. eBPF란 무엇입니까?

eBPF(확장 버클리 패킷 필터)는 커널 소스 코드를 수정하거나 커널 모듈을 로드하지 않고도 커널 내에서 샌드박스 프로그램을 실행할 수 있게 해주는 Linux 커널 하위 시스템입니다. 프로그램은 실행 전에 커널 바이트코드 검증기에 의해 검증되어 안전성을 보장합니다.

네트워킹을 위해 eBPF 프로그램은 다음에 연결됩니다.훅 포인트커널의 네트워크 스택에 있으며 패킷을 검사, 수정, 리디렉션 또는 삭제할 수 있습니다. 무엇보다 중요한 장점iptables또는 커널 모듈은 성능과 프로그래밍 가능성입니다. eBPF 프로그램은 기본 코드로 JIT 컴파일되며 다음을 통해 상태를 공유할 수 있습니다.지도(커널과 사용자 공간 간에 공유되는 키-값 저장소)

위치숨어 있음사용 사례
XDPsk_buff 할당 전 NIC 드라이버최저DDoS 드롭, 로드 밸런싱
TC 수신/송신sk_buff 할당 후낮은트래픽 형성, 표시, 리디렉션
소켓 필터소켓 수신 경로중간tcpdump 스타일 필터링
kprobe/추적점커널 함수 시작/종료다양함관찰 가능성, 추적

2. XDP 후크 포인트

XDP(eXpress Data Path) 프로그램은 커널이 할당하기 전에 네트워크 스택의 가능한 가장 빠른 지점, 즉 NIC 드라이버 내부에서 실행됩니다.sk_buff. 이는 다음을 의미합니다.

  • 기본 XDP: 드라이버는 기본적으로 XDP를 지원합니다(Intel i40e, Mellanox mlx5 등). 가장 빠름 — 드라이버 컨텍스트에서 실행됩니다.
  • 일반 XDP: 기본 지원이 없는 드라이버에 대한 대체입니다. 다음 이후에 실행sk_buff할당 — 여전히 iptables보다 빠르지만 기본만큼 빠르지는 않습니다.
  • 오프로드된 XDP: 프로그램은 NIC ASIC 자체에서 실행됩니다. SmartNIC 하드웨어(예: Netronome)가 필요합니다. CPU 비용이 없습니다.

XDP 프로그램은 다음 5가지 판정 중 하나를 반환합니다.

반환 코드행동
XDP_DROP즉시 패킷 삭제 - 대기 시간이 가장 짧은 폐기
XDP_PASS일반 네트워크 스택까지 전달
XDP_TX동일한 인터페이스를 다시 전송(바운스)
XDP_REDIRECT다른 인터페이스 또는 AF_XDP 소켓으로 리디렉션
XDP_ABORTED오류 경로 - 추적 이벤트와 함께 삭제

3. XDP 패킷 삭제 예시

다음 프로그램은 eBPF 맵에 저장된 소스 IP에서 모든 UDP 패킷을 삭제하여 사용자 공간 제어 플레인이 런타임에 차단 목록을 업데이트할 수 있도록 합니다.

// xdp_drop_udp.c — Drop UDP from IPs in a BPF map
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <bpf/bpf_helpers.h>

// 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/XDPDPDKRDMA
커널 참여최소(드라이버의 XDP)없음(완전 우회)없음(RDMA NIC)
메모리 모델표준 + AF_XDP UMEM거대한 페이지가 필요합니다.등록된 메모리 영역
최대 처리량~100Gbps 기본 XDP>100Gbps200Gbps 이상(InfiniBand)
CPU 사용량낮음(이벤트 중심)높음(사용 중 폴링 코어)거의 영점(오프로드됨)
운영 복잡성낮음 - 표준 도구높음 - 전용 코어, 거대 페이지높음 - 패브릭 관리
사용 사례DDoS 완화, LB, 관측 가능성가상 라우터, NFV, 패킷 생성스토리지(NVMe-oF), HPC MPI
언어제한된 C / RustC/러스트동사 API(C)
경험 법칙:eBPF/XDP로 시작하세요. 기존 커널 도구와 통합되고 특별한 하드웨어나 대용량 페이지가 필요하지 않으며 100Gbps 미만의 대부분의 고성능 네트워킹 사용 사례를 처리합니다. 전용 CPU 코어가 필요하고 커널 예약 오버헤드를 허용할 수 없는 경우에만 DPDK로 이동하세요.