Skip to content
Published on

Cilium eBPF 데이터패스 심층 분석: 패킷 처리 파이프라인

Authors

Cilium eBPF 데이터패스 심층 분석: 패킷 처리 파이프라인

개요

Cilium의 eBPF 데이터패스는 리눅스 커널 내에서 패킷을 처리하는 고성능 네트워크 파이프라인입니다. 이 글에서는 패킷이 Pod에서 송수신될 때 거치는 전체 과정을 상세히 분석합니다.

1. 패킷 처리 흐름 개요

1.1 인그레스 패킷 흐름 (외부 -> Pod)

외부 네트워크
    |
    v
[물리 NIC] eth0
    |
    v
[XDP 프로그램] (선택적)
  - NodePort 가속
  - DDoS 방어
  - 사전 필터링
    |
    v
[tc ingress: from-netdev]
  - 소스 Identity 조회 (ipcache)
  - 터널 디캡슐화 (VXLAN/Geneve)
  - NodePort DNAT
    |
    v
[라우팅 결정]
  - 로컬 Pod? -> cilium_host
  - 원격 노드? -> 터널 또는 직접 라우팅
    |
    v
[cilium_host: to-host]
  - 호스트 방화벽 정책 확인
    |
    v
[tc egress: to-container] (lxc*)
  - 목적지 Identity 확인
  - 인그레스 정책 확인
  - L3/L4 필터링
  - conntrack 항목 생성/업데이트
  - L7 리디렉션 (필요시 Envoy로)
    |
    v
[Pod 네트워크 네임스페이스]

1.2 이그레스 패킷 흐름 (Pod -> 외부)

[Pod 네트워크 네임스페이스]
    |
    v
[tc ingress: from-container] (lxc*)
  - 소스 엔드포인트 식별
  - 이그레스 정책 확인
  - 서비스 DNAT (kube-proxy 대체)
  - conntrack 룩업/생성
  - L7 리디렉션 (필요시)
    |
    v
[라우팅 결정]
  - 같은 노드 Pod? -> 직접 전달
  - 원격 Pod? -> 터널 또는 직접 라우팅
  - 외부? -> SNAT (masquerade)
    |
    v
[tc egress: to-netdev] (eth0)
  - SNAT 적용
  - 터널 캡슐화 (VXLAN/Geneve)
    |
    v
[물리 NIC] eth0
    |
    v
외부 네트워크

2. BPF 프로그램 상세

2.1 from-container (Pod 이그레스)

Pod에서 나가는 패킷을 처리하는 첫 번째 BPF 프로그램입니다.

// 개념적 from-container 처리 흐름 (단순화)
// 실제 코드: bpf/bpf_lxc.c - handle_xgress()

int from_container(struct __sk_buff *skb) {
    // 1. 패킷 파싱 (L2/L3/L4 헤더)
    // 2. 소스 엔드포인트 식별
    // 3. 이그레스 정책 확인
    //    - Identity 기반 L3/L4 정책
    //    - CIDR 정책
    //    - L7 정책 -> Envoy 리디렉션
    // 4. 서비스 로드 밸런싱
    //    - ClusterIP DNAT
    //    - NodePort DNAT
    // 5. conntrack 처리
    // 6. 라우팅 결정
    //    - 같은 노드: tail call to-container
    //    - 원격 노드: 터널 캡슐화 또는 직접 라우팅
    //    - 외부: SNAT
    return TC_ACT_OK; // or TC_ACT_SHOT (drop)
}

주요 처리 단계:

단계설명BPF 맵 사용
패킷 파싱L2/L3/L4 헤더 추출-
엔드포인트 식별소스 Pod 확인cilium_lxc
정책 확인이그레스 정책 매칭cilium_policy
서비스 LBClusterIP/NodePort DNATcilium_lb4_services
conntrack연결 상태 추적cilium_ct4_global
라우팅목적지 노드 결정cilium_ipcache, cilium_tunnel_map

2.2 to-container (Pod 인그레스)

Pod으로 들어오는 패킷을 처리하는 BPF 프로그램입니다.

// 개념적 to-container 처리 흐름
// 실제 코드: bpf/bpf_lxc.c - handle_ingress()

int to_container(struct __sk_buff *skb) {
    // 1. 패킷 파싱
    // 2. 소스 Identity 조회
    //    - ipcache에서 소스 IP -> Identity 매핑
    // 3. 인그레스 정책 확인
    //    - Identity 기반 L3/L4 정책
    //    - L7 정책 -> Envoy 리디렉션
    // 4. conntrack 업데이트
    // 5. reverse NAT (응답 패킷의 경우)
    // 6. Pod으로 전달
    return TC_ACT_OK;
}

2.3 from-overlay / to-overlay

오버레이 네트워크(VXLAN/Geneve)를 통한 패킷 처리입니다.

VXLAN 수신 흐름:
[물리 NIC] -> [VXLAN 디캡슐화] -> [from-overlay BPF]
  - 내부 Identity 추출 (Geneve TLV 또는 소스 IP 기반)
  - 목적지 엔드포인트 조회
  - 정책 확인
  - 대상 Pod으로 전달

VXLAN 송신 흐름:
[from-container BPF] -> [라우팅: 원격 노드] -> [to-overlay BPF]
  - Identity 정보를 터널 헤더에 포함
  - VXLAN/Geneve 캡슐화
  - 물리 NIC으로 전달

3. 커넥션 트래킹 구현

3.1 conntrack 구조

Cilium은 자체 eBPF 기반 커넥션 트래킹을 구현합니다.

// conntrack 키 구조 (개념적)
struct ct_key {
    __u32 src_ip;
    __u32 dst_ip;
    __u16 src_port;
    __u16 dst_port;
    __u8  protocol;    // TCP, UDP, ICMP
    __u8  direction;   // ingress, egress
};

// conntrack 값 구조
struct ct_entry {
    __u64 rx_packets;
    __u64 rx_bytes;
    __u64 tx_packets;
    __u64 tx_bytes;
    __u32 lifetime;
    __u16 rev_nat_index;  // reverse NAT 인덱스
    __u16 src_sec_id;     // 소스 Identity
    __u32 flags;
};

3.2 conntrack 상태 머신

TCP 연결 상태 추적:

SYN -> [NEW] -> SYN-ACK -> [ESTABLISHED] -> FIN -> [CLOSING] -> [CLOSED]

상태별 타임아웃:
- NEW: 60- ESTABLISHED: 6시간 (TCP), 60 (UDP)
- CLOSING: 10

3.3 conntrack 활용

# conntrack 테이블 조회
cilium bpf ct list global

# TCP 연결 예시 출력:
# TCP IN  10.244.1.5:34567 -> 10.96.0.1:443
#   Expires: 21590s Identity: 48291
#   RxPackets: 142  RxBytes: 15234
#   TxPackets: 138  TxBytes: 12890
#   Flags: rx+tx established

# conntrack 항목 수 확인
cilium bpf ct list global | wc -l

# 특정 IP 관련 conntrack 필터링
cilium bpf ct list global | grep "10.244.1.5"

3.4 conntrack GC (가비지 컬렉션)

만료된 conntrack 항목은 주기적으로 정리됩니다.

Agent 내부 GC 루프:
1. BPF 맵의 모든 항목 순회
2. 타임아웃 만료 항목 식별
3. 만료 항목 삭제
4. 관련 NAT 항목도 함께 삭제
5. 메트릭 업데이트

GC 주기: 설정 가능 (기본 약 12)

4. NAT 엔진

4.1 SNAT (Source NAT / Masquerade)

Pod에서 클러스터 외부로 나가는 트래픽의 소스 IP를 노드 IP로 변환합니다.

SNAT 처리 흐름:

Pod (10.244.1.5:34567) -> 외부 (8.8.8.8:443)
    |
    v
[from-container BPF]
  - 목적지가 클러스터 외부인지 확인
  - SNAT 필요 여부 판단
    |
    v
[SNAT 엔진]
  - 소스 IP를 노드 IP변환 (10.244.1.5 -> 192.168.1.100)
  - 소스 포트를 에페메럴 포트로 변환
  - NAT 매핑을 BPF 맵에 저장
    |
    v
노드 IP (192.168.1.100:50123) -> 외부 (8.8.8.8:443)

응답 패킷 (Reverse SNAT):
외부 (8.8.8.8:443) -> 노드 IP (192.168.1.100:50123)
    |
    v
[to-netdev BPF]
  - NAT 매핑에서 원래 소스 조회
  - 목적지를 원래 Pod IP/포트로 복원
    |
    v
외부 (8.8.8.8:443) -> Pod (10.244.1.5:34567)

4.2 DNAT (서비스 로드 밸런싱)

쿠버네티스 서비스 IP를 실제 백엔드 Pod IP로 변환합니다.

서비스 DNAT 흐름:

클라이언트 (10.244.1.5) -> Service (10.96.0.10:80)
    |
    v
[from-container BPF: 서비스 LB]
  - cilium_lb4_services에서 서비스 조회
  - 백엔드 선택 (라운드로빈, Maglev)
  - 목적지 IP/포트를 백엔드로 변환
    |
    v
클라이언트 (10.244.1.5) -> Backend Pod (10.244.2.10:8080)

4.3 Maglev 일관된 해싱

Maglev는 Google이 개발한 일관된 해싱 알고리즘으로, Cilium에서 서비스 로드 밸런싱에 사용됩니다.

Maglev 해싱 과정:

1. 룩업 테이블 생성 (65537 엔트리)
   - 각 백엔드가 테이블의 여러 위치에 매핑
   - 백엔드 수에 관계없이 균일한 분포

2. 패킷 해시 계산
   - 5-tuple 해시: src_ip + dst_ip + src_port + dst_port + protocol
   - 해시 값으로 테이블 인덱스 결정

3. 백엔드 선택
   - table[hash % table_size] = backend

백엔드 변경 시 영향:
- 1개 백엔드 추가/제거 ->1/N 연결만 재매핑
- 기존 연결 대부분 유지
# Maglev 설정 확인
cilium config | grep maglev

# 서비스 백엔드 확인
cilium bpf lb list

# 서비스별 Maglev 룩업 테이블
cilium bpf lb maglev list

4.4 서비스 타입별 처리

ClusterIP:
  - from-container에서 DNAT
  - 소켓 수준 LB (bpf_sock) 또는 tc 수준

NodePort:
  - XDP 또는 tc ingress (from-netdev)에서 DNAT
  - DSR 모드: 응답 패킷 직접 전달
  - SNAT 모드: 원본 노드를 통해 응답

LoadBalancer:
  - NodePort와 동일한 처리 + ExternalIP 매핑
  - LB-IPAM에 의해 IP 할당

ExternalTrafficPolicy: Local
  - 로컬 백엔드가 있는 경우만 처리
  - 클라이언트 소스 IP 보존

5. DSR (Direct Server Return) 모드

5.1 DSR 동작 원리

DSR 모드에서는 응답 패킷이 원래 요청을 수신한 노드를 거치지 않고 직접 클라이언트에게 전달됩니다.

DSR 흐름:

1. 클라이언트 -> 노드A (NodePort)
   [노드A: DNAT + DSR 옵션 설정]
   - 목적지를 백엔드 Pod(노드B)로 변환
   - IP 옵션에 원래 서비스 IP/포트를 인코딩

2. 노드A -> 노드B (백엔드 Pod)
   [노드B: DSR 옵션 처리]
   - IP 옵션에서 원래 서비스 IP/포트 복원
   - conntrack에 reverse NAT 정보 저장

3. 노드B (백엔드 Pod) -> 클라이언트
   [노드B: reverse NAT]
   - 소스 IP를 서비스 IP로 변환
   - 노드A를 거치지 않고 직접 응답

일반 모드 (SNAT):
  클라이언트 -> 노드A -> 노드B -> 노드A -> 클라이언트
  (2홉 추가)

DSR 모드:
  클라이언트 -> 노드A -> 노드B -> 클라이언트
  (응답은 직접)

5.2 DSR 구현 방식

IPv4 DSR:
  - IP Options 또는 Geneve TLV를 통해 원래 주소 전달
  - 추가 패킷 오버헤드 최소화

IPv6 DSR:
  - Segment Routing Header (SRH) 또는 Extension Header 사용
  - IPv6 네이티브 지원

6. eBPF 테일 콜: 프로그램 체이닝

6.1 테일 콜 메커니즘

eBPF 프로그램에는 명령어 수 제한이 있으므로, 복잡한 처리를 여러 프로그램으로 분리합니다.

테일 콜 체인 예시:

[from-container]
    |
    tail_call -> [IPv4 정책 확인]
                    |
                    tail_call -> [서비스 LB]
                                    |
                                    tail_call -> [NAT 처리]
                                                    |
                                                    tail_call -> [전달]

6.2 테일 콜 맵

// 테일 콜 맵 구조 (개념적)
// BPF_MAP_TYPE_PROG_ARRAY
struct bpf_map tail_call_map = {
    .type = BPF_MAP_TYPE_PROG_ARRAY,
    .max_entries = 64,
    // 인덱스 -> BPF 프로그램 FD 매핑
};

// 테일 콜 호출
// tail_call(skb, &tail_call_map, CILIUM_CALL_IPV4_FROM_LXC);

6.3 Cilium의 주요 테일 콜 포인트

CILIUM_CALL_IPV4_FROM_LXC      = 0   // IPv4 from-container 진입
CILIUM_CALL_IPV4_CT_INGRESS    = 4   // IPv4 conntrack 인그레스
CILIUM_CALL_IPV4_CT_EGRESS     = 5   // IPv4 conntrack 이그레스
CILIUM_CALL_IPV4_NODEPORT_NAT  = 13  // NodePort NAT
CILIUM_CALL_IPV4_NODEPORT_DSR  = 14  // NodePort DSR
CILIUM_CALL_IPV4_ENCAP         = 15  // 터널 캡슐화
CILIUM_CALL_SEND_ICMP_UNREACH  = 18  // ICMP Unreachable 전송
CILIUM_CALL_SRV6_ENCAP         = 23  // SRv6 캡슐화

7. 소켓 수준 로드 밸런싱

7.1 소켓 LB 개요

소켓 수준 로드 밸런싱은 iptables나 tc 수준의 NAT를 우회하여 connect() 시스템 콜 시점에 서비스 IP를 백엔드 IP로 직접 변환합니다.

전통적 방식 (iptables/tc):
connect(서비스IP) -> [커널 네트워크 스택] -> [NAT] -> [conntrack] -> 백엔드

소켓 LB 방식:
connect(서비스IP) -> [BPF sock_ops] -> connect(백엔드IP)
  - NAT 불필요
  - conntrack 항목 불필요
  - 네트워크 스택 오버헤드 제거

7.2 BPF 소켓 프로그램 타입

cgroup/connect4:     connect() 가로채기 (IPv4)
cgroup/connect6:     connect() 가로채기 (IPv6)
cgroup/sendmsg4:     UDP sendmsg() 가로채기 (IPv4)
cgroup/sendmsg6:     UDP sendmsg() 가로채기 (IPv6)
cgroup/recvmsg4:     UDP recvmsg() 가로채기 (IPv4)
cgroup/recvmsg6:     UDP recvmsg() 가로채기 (IPv6)
cgroup/getpeername4: getpeername() 가로채기 (IPv4)
cgroup/getpeername6: getpeername() 가로채기 (IPv6)

7.3 소켓 LB의 장점

성능 비교:

tc 수준 LB:
  - 패킷마다 NAT 수행
  - conntrack 항목 필요
  - 추가 CPU 사이클

소켓 수준 LB:
  - 연결당 한 번만 변환
  - conntrack 불필요
  - 최소 CPU 오버헤드
  - 원본 서비스 IP 보존 (getpeername)

7.4 소켓 LB 제한사항

소켓 LB가 적용되지 않는 경우:
  - 외부에서 NodePort로 들어오는 트래픽
  - hostNetwork Pod의 트래픽
  - 특정 kube-proxy 호환성 모드
  - L7 정책이 적용된 서비스 (Envoy 리디렉션 필요)

이런 경우 tc 수준에서 fallback 처리됨

8. 패킷 드롭과 모니터링

8.1 드롭 이유 코드

Cilium은 패킷 드롭 시 상세한 이유 코드를 제공합니다.

# 드롭된 패킷 모니터링
cilium monitor --type drop

# 출력 예시:
# xx drop (Policy denied) flow ...
# xx drop (Invalid source ip) flow ...
# xx drop (CT: Map insertion failed) flow ...

주요 드롭 이유:

코드설명
Policy denied정책에 의해 거부됨
Invalid source ip소스 IP가 유효하지 않음
CT: Map insertion failedconntrack 맵 삽입 실패
No mapping for NATNAT 매핑 없음
Unknown L3 targetL3 대상을 알 수 없음
Stale or unroutable IP오래되거나 라우팅 불가능한 IP
Authentication requiredmTLS 인증 필요
Service backend not found서비스 백엔드 없음

8.2 패킷 트레이싱

# 실시간 패킷 트레이스
cilium monitor --type trace

# 특정 엔드포인트의 트래픽만 모니터링
cilium monitor --type trace --from-endpoint 1234

# 정책 verdict 모니터링
cilium monitor --type policy-verdict

# 디버그 수준 모니터링
cilium monitor --type debug

9. 성능 최적화 기법

9.1 XDP 가속

XDP 모드별 성능:
  - XDP native (드라이버 내장): 최고 성능
  - XDP generic (소프트웨어): 호환성 우선
  - XDP offload (NIC 하드웨어): 특정 NIC만 지원

XDP 활용 사례:
  - NodePort 가속
  - LoadBalancer 가속
  - DDoS 방어 (패킷 드롭)
  - 프리필터링

9.2 BIG TCP

BIG TCP 동작:
  - GRO(Generic Receive Offload)로 수신 패킷을 64KB+ 크기로 병합
  - 내부적으로 대용량 패킷으로 처리하여 패킷당 오버헤드 감소
  - GSO(Generic Segmentation Offload)로 송신 시 분할
  - MTU 제약 없이 내부 처리 최적화

9.3 eBPF 프로그램 최적화

컴파일 시간 최적화:
  - 사용하지 않는 기능은 컴파일에서 제외
  - 정책이 없는 엔드포인트: 최소한의 BPF 코드
  - IPv4 전용 환경: IPv6 코드 제거

런타임 최적화:
  - BPF 맵 프리페칭
  - 인라인 함수 활용
  - 불필요한 조건 분기 제거
  - JIT 컴파일로 네이티브 코드 실행

10. 데이터패스 디버깅

10.1 BPF 프로그램 상태 확인

# 모든 BPF 프로그램 목록
bpftool prog list

# 특정 인터페이스의 BPF 프로그램
tc filter show dev lxc1234 ingress
tc filter show dev lxc1234 egress

# BPF 프로그램 통계
bpftool prog show id 42 --json

# BPF 맵 통계
bpftool map show id 10 --json

10.2 성능 메트릭

# 데이터패스 관련 메트릭
cilium metrics list | grep datapath

# 주요 메트릭:
# cilium_datapath_conntrack_gc_runs_total
# cilium_datapath_conntrack_gc_entries
# cilium_bpf_map_ops_total
# cilium_drop_count_total
# cilium_forward_count_total

정리

Cilium의 eBPF 데이터패스는 다음과 같은 핵심 설계로 고성능을 달성합니다.

  • 커널 내 처리: 모든 패킷 처리가 커널 공간에서 이루어져 사용자 공간 전환 오버헤드 제거
  • 테일 콜 체이닝: 복잡한 로직을 여러 BPF 프로그램으로 분리하여 모듈성 확보
  • 자체 conntrack: 리눅스 netfilter conntrack 대신 BPF 맵 기반 고성능 커넥션 트래킹
  • 소켓 수준 LB: NAT 없이 서비스 로드 밸런싱으로 최소 오버헤드
  • DSR 모드: 불필요한 네트워크 홉 제거로 응답 지연 시간 감소
  • XDP 가속: 네트워크 드라이버 수준에서 초고속 패킷 처리