과거에는 eBPF 프로그램을 작성한 후 커널에 로드하기 위해 수백 줄 이상의 C 코드를 직접 작성해야 했습니다. ELF 파일을 열고, Map을 생성하고, 프로그램을 로드한 뒤 Hook에 연결하는 작업을 모두 개발자가 구현해야 했기 때문입니다.
이러한 복잡함을 해결하기 위해 libbpf Skeleton이 등장했습니다.
Skeleton은 bpftool이 자동으로 생성하는 C 헤더 파일로, eBPF 프로그램을 매우 간단하게 로드하고 관리할 수 있도록 만들어 줍니다.
현재 대부분의 최신 eBPF 프로젝트(Cilium, Katran, Falco 일부 구성, libbpf-bootstrap 예제)는 Skeleton 방식을 사용합니다.
이번 글에서는 eBPF Skeleton의 개념과 동작 원리, 생성 방법, 주요 함수, 실무 활용 방법을 자세히 알아보겠습니다.
Linux eBPF Skeleton이란?
Skeleton은 eBPF Object 파일(.o)을 기반으로 bpftool이 자동 생성하는 C Header 파일입니다.
기본 구조는 다음과 같습니다.
program.bpf.c
↓
clang
↓
program.bpf.o
↓
bpftool
↓
program.skel.h
↓
Application
개발자는 Skeleton을 포함(Include)하기만 하면 복잡한 Loader 코드를 직접 작성할 필요가 없습니다.
Skeleton이 필요한 이유
기존 방식에서는 다음과 같은 작업을 직접 구현해야 했습니다.
- ELF Object 열기
- Map 생성
- Program Load
- CO-RE Relocation
- Verifier 실행
- Hook 연결
- 종료 처리
Skeleton은 이러한 과정을 자동으로 처리합니다.
Skeleton 생성 과정
전체 과정은 다음과 같습니다.
eBPF Source
↓
clang
↓
Object File
↓
bpftool gen skeleton
↓
Skeleton Header
↓
Application
자동 생성된 Header에는 프로그램을 제어하는 다양한 함수가 포함됩니다.
Skeleton 생성 방법
먼저 eBPF 프로그램을 컴파일합니다.
clang \
-target bpf \
-g \
-O2 \
-c program.bpf.c \
-o program.bpf.o
그다음 Skeleton을 생성합니다.
bpftool gen skeleton program.bpf.o > program.skel.h
이제 program.skel.h 파일을 프로젝트에서 사용할 수 있습니다.
Skeleton 내부 구조
Skeleton에는 다양한 정보가 포함됩니다.
Program
Map
BSS
RODATA
DATA
Link
Object
개발자는 이 구조체를 통해 모든 eBPF 리소스를 쉽게 제어할 수 있습니다.
Skeleton 사용 방법
헤더를 포함합니다.
#include "program.skel.h"
그다음 Object를 생성합니다.
struct program_bpf *skel;
이 구조체가 전체 eBPF 프로그램을 관리합니다.
Object 열기
Skeleton은 Object를 자동으로 엽니다.
skel = program_bpf__open();
내부적으로
- ELF 분석
- Map 확인
- Object 초기화
등을 수행합니다.
Program Load
Kernel에 프로그램을 로드합니다.
program_bpf__load(skel);
내부적으로
- CO-RE
- Verifier
- Map 생성
등이 자동으로 수행됩니다.
Hook 연결
Program을 Hook에 연결합니다.
program_bpf__attach(skel);
예를 들어
- Tracepoint
- XDP
- Kprobe
등에 자동으로 연결됩니다.
Program 종료
프로그램 종료 시
program_bpf__destroy(skel);
Map과 Link를 정리하고 메모리를 해제합니다.
Skeleton의 주요 함수
| 함수 | 설명 |
|---|---|
__open() | Object 열기 |
__load() | Kernel 로드 |
__attach() | Hook 연결 |
__detach() | Hook 해제 |
__destroy() | 메모리 해제 |
이 함수들만으로 대부분의 작업을 처리할 수 있습니다.
Skeleton의 장점
Skeleton을 사용하면 다음과 같은 장점이 있습니다.
- 코드 양 감소
- Loader 자동화
- CO-RE 자동 지원
- BTF 자동 처리
- Map 접근 단순화
- 유지보수 용이
- 최신 libbpf와 높은 호환성
복잡한 초기화 코드를 크게 줄일 수 있습니다.
Skeleton과 기존 방식 비교
| 항목 | 기존 방식 | Skeleton |
|---|---|---|
| 코드 길이 | 길다 | 짧다 |
| Loader 구현 | 직접 작성 | 자동 |
| CO-RE 지원 | 직접 구현 | 자동 |
| 유지보수 | 어려움 | 쉬움 |
| 권장 여부 | 기존 방식 | 최신 표준 |
현재는 Skeleton 사용이 일반적인 개발 방식입니다.
Skeleton과 bpftool의 관계
bpftool은 Skeleton 생성 도구입니다.
예를 들어
bpftool gen skeleton program.bpf.o
명령을 실행하면
program.skel.h
파일이 생성됩니다.
이 파일을 애플리케이션에서 사용하면 됩니다.
실무에서 자주 사용하는 명령어
eBPF 프로그램 컴파일
clang -target bpf \
-c program.bpf.c \
-o program.bpf.o
Skeleton 생성
bpftool gen skeleton program.bpf.o > program.skel.h
Program 확인
sudo bpftool prog show
Map 확인
sudo bpftool map show
Kernel 기능 확인
sudo bpftool feature
libbpf 버전 확인
pkg-config --modversion libbpf
실무 사례
예를 들어 Tracepoint 기반 프로세스 모니터링 프로그램을 개발한다고 가정해 보겠습니다.
예전에는 다음 작업을 모두 직접 구현해야 했습니다.
- ELF 파일 열기
- Map 생성
- Program Load
- CO-RE 적용
- Verifier 처리
- Tracepoint Attach
- 종료 시 Link 해제
하지만 Skeleton을 사용하면 다음과 같이 단순화됩니다.
program_bpf__open()program_bpf__load()program_bpf__attach()- 이벤트 수집
program_bpf__destroy()
코드가 훨씬 간결해지고 유지보수도 쉬워집니다.
자주 묻는 질문
Skeleton은 반드시 사용해야 하나요?
필수는 아닙니다. 직접 libbpf API를 호출하여 Loader를 구현할 수도 있습니다. 하지만 최신 eBPF 프로젝트에서는 Skeleton 사용이 일반적으로 권장됩니다.
Skeleton은 어떤 도구가 생성하나요?
bpftool gen skeleton 명령으로 자동 생성합니다. 생성된 헤더 파일에는 프로그램 로드와 관리에 필요한 함수와 구조체가 포함됩니다.
Skeleton은 CO-RE와 함께 사용되나요?
네. Skeleton은 libbpf와 함께 CO-RE를 자연스럽게 지원합니다. 실행 시 현재 커널의 BTF 정보를 이용해 필요한 Relocation을 자동으로 수행합니다.
마무리
Linux eBPF Skeleton은 libbpf 기반 개발을 크게 단순화한 자동 생성 코드입니다. bpftool이 생성한 Skeleton Header를 사용하면 프로그램 로드, Hook 연결, Map 관리, CO-RE 처리 등을 간단한 함수 호출만으로 수행할 수 있습니다. 현재 eBPF 개발에서는 Skeleton이 사실상의 표준으로 자리 잡았으며, 생산성과 유지보수성을 크게 향상시키는 핵심 기술입니다.