왜 eBPF인가

기존에 커널 내부 동작을 관측하거나 네트워크 패킷을 필터링하려면 커널 모듈을 작성하거나 iptables 규칙을 쌓아야 했다. 커널 모듈은 잘못 짜면 시스템 전체를 패닉시키고, iptables는 규칙이 수백 개로 늘어나면 선형 탐색 때문에 지연이 커진다. eBPF는 검증기(verifier)를 통과한 안전한 바이트코드를 커널 훅 지점에 JIT 컴파일해 붙인다. 즉 커널을 재부팅하거나 모듈을 올리지 않고도, 커널 공간에서 직접 이벤트를 잡거나 패킷을 처리할 수 있다.

동작 원리 한눈에

eBPF 프로그램은 특정 훅(hook)에 부착된다. 대표적으로 커널 함수 진입/반환을 잡는 kprobe/tracepoint, 네트워크 스택 진입 직후를 잡는 XDP, 소켓 계층의 tc가 있다. 프로그램은 맵(map)이라는 커널-유저 공유 자료구조로 상태를 저장하고, 유저 공간 프로그램이 이 맵을 읽어 지표를 수집한다. 검증기는 루프 무한 반복, 잘못된 메모리 접근, 스택 초과를 로드 시점에 차단하므로 런타임 크래시 위험이 낮다.

관측성: 실행되는 프로세스 추적

가장 쉬운 시작점은 bpftrace다. 별도 컴파일 없이 한 줄로 커널 이벤트를 관측할 수 있다. 아래는 시스템에서 새로 exec되는 모든 프로세스를 실시간으로 찍는 예시다.

#!/usr/bin/env bpftrace
# execve 진입 시점을 tracepoint로 후킹
tracepoint:syscalls:sys_enter_execve
{
    printf("%-8d %-16s %s\n", pid, comm, str(args->filename));
}
# 실행: sudo bpftrace exec-trace.bt

이 방식은 ps 폴링과 달리 이벤트 기반이라 짧게 살고 사라지는 프로세스도 놓치지 않는다. 컨테이너 환경에서 정체불명의 프로세스 실행을 잡을 때 특히 유용하다.

네트워크 필터링: XDP로 조기 드롭

DDoS 성 트래픽이나 특정 포트 스캔을 막을 때, 패킷이 커널 네트워크 스택 깊숙이 들어온 뒤 iptables에서 버리면 이미 자원을 소모한 상태다. XDP는 NIC 드라이버 수준, 즉 스택 진입 직전에 패킷을 처리해 훨씬 저비용으로 드롭한다. 아래는 특정 목적지 포트로 오는 UDP를 버리는 골격이다.

// drop_udp.bpf.c  (clang -O2 -target bpf 로 컴파일)
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <bpf/bpf_helpers.h>

SEC("xdp")
int drop_udp_9999(struct xdp_md *ctx) {
    void *data = (void *)(long)ctx->data;
    void *end  = (void *)(long)ctx->data_end;
    struct ethhdr *eth = data;
    if ((void*)(eth+1) > end) return XDP_PASS;
    if (eth->h_proto != __constant_htons(ETH_P_IP)) return XDP_PASS;

    struct iphdr *ip = (void*)(eth+1);
    if ((void*)(ip+1) > end) return XDP_PASS;
    if (ip->protocol != IPPROTO_UDP) return XDP_PASS;

    struct udphdr *udp = (void*)ip + ip->ihl*4;
    if ((void*)(udp+1) > end) return XDP_PASS;
    if (udp->dest == __constant_htons(9999)) return XDP_DROP;
    return XDP_PASS;
}
char _license[] SEC("license") = "GPL";

경계 검사(> end)가 반복되는 이유는 검증기가 모든 패킷 접근에 대해 범위 증명을 요구하기 때문이다. 이 검사를 빼면 로드 자체가 거부된다.

접근 방식 비교

방식처리 위치비용적합한 경우
iptablesnetfilter 훅규칙 수에 비례소규모 정적 규칙
tc(eBPF)큐잉 계층낮음egress 정형화, 트래픽 분류
XDP(eBPF)드라이버 직후가장 낮음고속 드롭, DDoS 완화

유저 공간에서 지표 수집

커널에서 채운 맵은 bpftool이나 라이브러리로 읽는다. 운영 중인 XDP 프로그램과 맵 상태를 확인하는 명령은 다음과 같다.

# 부착된 XDP 프로그램 목록
sudo bpftool prog show

# 특정 맵의 카운터 덤프 (id는 위 명령으로 확인)
sudo bpftool map dump id 42

# 인터페이스에서 XDP 프로그램 떼기
sudo ip link set dev eth0 xdp off

주의점

첫째, 커널 버전 의존성이 크다. 훅 종류와 헬퍼 함수 가용성이 버전마다 다르므로 CO-RE(Compile Once, Run Everywhere)와 BTF를 쓰지 않으면 배포 대상마다 재컴파일해야 한다. 둘째, XDP는 드라이버가 네이티브 모드를 지원하지 않으면 generic 모드로 떨어져 이점이 사라진다. 셋째, 검증기 제약 때문에 복잡한 로직은 여러 프로그램으로 쪼개고 tail call로 연결해야 한다. 넷째, 프로덕션 적용 전 반드시 XDP_PASS 기본값과 화이트리스트 검증을 거쳐야 정상 트래픽을 실수로 끊는 사고를 막을 수 있다.