Skip to content

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

|

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

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 가속: 네트워크 드라이버 수준에서 초고속 패킷 처리

Cilium eBPF Datapath Deep Dive: Packet Processing Pipeline

Cilium eBPF Datapath Deep Dive: Packet Processing Pipeline

Overview

The Cilium eBPF datapath is a high-performance network pipeline that processes packets within the Linux kernel. This post provides a detailed analysis of the entire journey a packet takes when being sent or received by a Pod.

1. Packet Flow Overview

1.1 Ingress Packet Flow (External -> Pod)

External Network
    |
    v
[Physical NIC] eth0
    |
    v
[XDP Program] (optional)
  - NodePort acceleration
  - DDoS mitigation
  - Pre-filtering
    |
    v
[tc ingress: from-netdev]
  - Source Identity lookup (ipcache)
  - Tunnel decapsulation (VXLAN/Geneve)
  - NodePort DNAT
    |
    v
[Routing Decision]
  - Local Pod? -> cilium_host
  - Remote node? -> Tunnel or direct routing
    |
    v
[cilium_host: to-host]
  - Host firewall policy check
    |
    v
[tc egress: to-container] (lxc*)
  - Destination Identity check
  - Ingress policy check
  - L3/L4 filtering
  - Conntrack entry create/update
  - L7 redirect (to Envoy if needed)
    |
    v
[Pod Network Namespace]

1.2 Egress Packet Flow (Pod -> External)

[Pod Network Namespace]
    |
    v
[tc ingress: from-container] (lxc*)
  - Source endpoint identification
  - Egress policy check
  - Service DNAT (kube-proxy replacement)
  - Conntrack lookup/create
  - L7 redirect (if needed)
    |
    v
[Routing Decision]
  - Same-node Pod? -> Direct delivery
  - Remote Pod? -> Tunnel or direct routing
  - External? -> SNAT (masquerade)
    |
    v
[tc egress: to-netdev] (eth0)
  - Apply SNAT
  - Tunnel encapsulation (VXLAN/Geneve)
    |
    v
[Physical NIC] eth0
    |
    v
External Network

2. BPF Program Details

2.1 from-container (Pod Egress)

The first BPF program that processes packets leaving a Pod:

// Conceptual from-container processing flow (simplified)
// Actual code: bpf/bpf_lxc.c - handle_xgress()

int from_container(struct __sk_buff *skb) {
    // 1. Parse packet (L2/L3/L4 headers)
    // 2. Identify source endpoint
    // 3. Check egress policy
    //    - Identity-based L3/L4 policy
    //    - CIDR policy
    //    - L7 policy -> Envoy redirect
    // 4. Service load balancing
    //    - ClusterIP DNAT
    //    - NodePort DNAT
    // 5. Conntrack processing
    // 6. Routing decision
    //    - Same node: tail call to-container
    //    - Remote node: tunnel encap or direct routing
    //    - External: SNAT
    return TC_ACT_OK; // or TC_ACT_SHOT (drop)
}

Key processing stages:

StageDescriptionBPF Map Used
Packet parsingExtract L2/L3/L4 headers-
Endpoint identificationIdentify source Podcilium_lxc
Policy checkEgress policy matchingcilium_policy
Service LBClusterIP/NodePort DNATcilium_lb4_services
ConntrackConnection state trackingcilium_ct4_global
RoutingDetermine destination nodecilium_ipcache, cilium_tunnel_map

2.2 to-container (Pod Ingress)

The BPF program that processes packets arriving at a Pod:

// Conceptual to-container processing flow
// Actual code: bpf/bpf_lxc.c - handle_ingress()

int to_container(struct __sk_buff *skb) {
    // 1. Parse packet
    // 2. Source Identity lookup
    //    - Source IP -> Identity mapping from ipcache
    // 3. Ingress policy check
    //    - Identity-based L3/L4 policy
    //    - L7 policy -> Envoy redirect
    // 4. Conntrack update
    // 5. Reverse NAT (for response packets)
    // 6. Deliver to Pod
    return TC_ACT_OK;
}

2.3 from-overlay / to-overlay

Packet processing through the overlay network (VXLAN/Geneve):

VXLAN receive flow:
[Physical NIC] -> [VXLAN decapsulation] -> [from-overlay BPF]
  - Extract inner Identity (Geneve TLV or source IP based)
  - Destination endpoint lookup
  - Policy check
  - Deliver to target Pod

VXLAN send flow:
[from-container BPF] -> [Routing: remote node] -> [to-overlay BPF]
  - Include Identity info in tunnel header
  - VXLAN/Geneve encapsulation
  - Forward to physical NIC

3. Connection Tracking Implementation

3.1 Conntrack Structure

Cilium implements its own eBPF-based connection tracking:

// Conntrack key structure (conceptual)
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 value structure
struct ct_entry {
    __u64 rx_packets;
    __u64 rx_bytes;
    __u64 tx_packets;
    __u64 tx_bytes;
    __u32 lifetime;
    __u16 rev_nat_index;  // reverse NAT index
    __u16 src_sec_id;     // source Identity
    __u32 flags;
};

3.2 Conntrack State Machine

TCP connection state tracking:

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

Timeouts per state:
- NEW: 60 seconds
- ESTABLISHED: 6 hours (TCP), 60 seconds (UDP)
- CLOSING: 10 seconds

3.3 Conntrack Usage

# Query conntrack table
cilium bpf ct list global

# Example TCP connection output:
# 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

# Count conntrack entries
cilium bpf ct list global | wc -l

# Filter conntrack for specific IP
cilium bpf ct list global | grep "10.244.1.5"

3.4 Conntrack GC (Garbage Collection)

Expired conntrack entries are periodically cleaned up:

Agent internal GC loop:
1. Iterate all entries in the BPF map
2. Identify entries with expired timeouts
3. Delete expired entries
4. Also delete associated NAT entries
5. Update metrics

GC interval: Configurable (default ~12 seconds)

4. NAT Engine

4.1 SNAT (Source NAT / Masquerade)

Translates source IP to node IP for traffic from Pods to outside the cluster:

SNAT processing flow:

Pod (10.244.1.5:34567) -> External (8.8.8.8:443)
    |
    v
[from-container BPF]
  - Check if destination is outside cluster
  - Determine if SNAT is needed
    |
    v
[SNAT Engine]
  - Translate source IP to node IP (10.244.1.5 -> 192.168.1.100)
  - Translate source port to ephemeral port
  - Store NAT mapping in BPF map
    |
    v
Node IP (192.168.1.100:50123) -> External (8.8.8.8:443)

Response packet (Reverse SNAT):
External (8.8.8.8:443) -> Node IP (192.168.1.100:50123)
    |
    v
[to-netdev BPF]
  - Look up original source in NAT mapping
  - Restore destination to original Pod IP/port
    |
    v
External (8.8.8.8:443) -> Pod (10.244.1.5:34567)

4.2 DNAT (Service Load Balancing)

Translates Kubernetes service IPs to actual backend Pod IPs:

Service DNAT flow:

Client (10.244.1.5) -> Service (10.96.0.10:80)
    |
    v
[from-container BPF: Service LB]
  - Look up service in cilium_lb4_services
  - Select backend (round-robin, Maglev, etc.)
  - Translate destination IP/port to backend
    |
    v
Client (10.244.1.5) -> Backend Pod (10.244.2.10:8080)

4.3 Maglev Consistent Hashing

Maglev is a consistent hashing algorithm developed by Google, used in Cilium for service load balancing:

Maglev hashing process:

1. Build lookup table (65537 entries)
   - Each backend maps to multiple positions in the table
   - Uniform distribution regardless of backend count

2. Compute packet hash
   - 5-tuple hash: src_ip + dst_ip + src_port + dst_port + protocol
   - Hash value determines table index

3. Select backend
   - table[hash % table_size] = backend

Impact on backend changes:
- Adding/removing 1 backend -> Only ~1/N connections remapped
- Most existing connections maintained
# Check Maglev configuration
cilium config | grep maglev

# Check service backends
cilium bpf lb list

# Service Maglev lookup table
cilium bpf lb maglev list

4.4 Processing by Service Type

ClusterIP:
  - DNAT in from-container
  - Socket-level LB (bpf_sock) or tc level

NodePort:
  - DNAT at XDP or tc ingress (from-netdev)
  - DSR mode: Direct response packet delivery
  - SNAT mode: Response through original node

LoadBalancer:
  - Same as NodePort + ExternalIP mapping
  - IP allocated by LB-IPAM

ExternalTrafficPolicy: Local
  - Only process if local backends exist
  - Preserve client source IP

5. DSR (Direct Server Return) Mode

5.1 DSR Operation

In DSR mode, response packets are delivered directly to the client without passing through the original node that received the request:

DSR flow:

1. Client -> Node A (NodePort)
   [Node A: DNAT + set DSR option]
   - Translate destination to backend Pod (Node B)
   - Encode original service IP/port in IP options

2. Node A -> Node B (backend Pod)
   [Node B: Process DSR option]
   - Restore original service IP/port from IP options
   - Store reverse NAT info in conntrack

3. Node B (backend Pod) -> Client
   [Node B: Reverse NAT]
   - Translate source IP to service IP
   - Respond directly without going through Node A

Normal mode (SNAT):
  Client -> Node A -> Node B -> Node A -> Client
  (2 extra hops)

DSR mode:
  Client -> Node A -> Node B -> Client
  (response is direct)

5.2 DSR Implementation Methods

IPv4 DSR:
  - Pass original address via IP Options or Geneve TLV
  - Minimize additional packet overhead

IPv6 DSR:
  - Use Segment Routing Header (SRH) or Extension Header
  - Native IPv6 support

6. eBPF Tail Calls: Program Chaining

6.1 Tail Call Mechanism

eBPF programs have instruction count limits, so complex processing is split across multiple programs:

Tail call chain example:

[from-container]
    |
    tail_call -> [IPv4 policy check]
                    |
                    tail_call -> [Service LB]
                                    |
                                    tail_call -> [NAT processing]
                                                    |
                                                    tail_call -> [Forward]

6.2 Tail Call Map

// Tail call map structure (conceptual)
// BPF_MAP_TYPE_PROG_ARRAY
struct bpf_map tail_call_map = {
    .type = BPF_MAP_TYPE_PROG_ARRAY,
    .max_entries = 64,
    // index -> BPF program FD mapping
};

// Tail call invocation
// tail_call(skb, &tail_call_map, CILIUM_CALL_IPV4_FROM_LXC);

6.3 Key Tail Call Points in Cilium

CILIUM_CALL_IPV4_FROM_LXC      = 0   // IPv4 from-container entry
CILIUM_CALL_IPV4_CT_INGRESS    = 4   // IPv4 conntrack ingress
CILIUM_CALL_IPV4_CT_EGRESS     = 5   // IPv4 conntrack egress
CILIUM_CALL_IPV4_NODEPORT_NAT  = 13  // NodePort NAT
CILIUM_CALL_IPV4_NODEPORT_DSR  = 14  // NodePort DSR
CILIUM_CALL_IPV4_ENCAP         = 15  // Tunnel encapsulation
CILIUM_CALL_SEND_ICMP_UNREACH  = 18  // Send ICMP Unreachable
CILIUM_CALL_SRV6_ENCAP         = 23  // SRv6 encapsulation

7. Socket-Level Load Balancing

7.1 Socket LB Overview

Socket-level load balancing bypasses iptables and tc-level NAT by translating service IPs to backend IPs directly at the connect() system call:

Traditional approach (iptables/tc):
connect(serviceIP) -> [kernel network stack] -> [NAT] -> [conntrack] -> backend

Socket LB approach:
connect(serviceIP) -> [BPF sock_ops] -> connect(backendIP)
  - No NAT needed
  - No conntrack entries needed
  - Network stack overhead eliminated

7.2 BPF Socket Program Types

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

7.3 Socket LB Advantages

Performance comparison:

tc-level LB:
  - NAT performed per packet
  - Conntrack entries required
  - Additional CPU cycles

Socket-level LB:
  - Translation only once per connection
  - No conntrack needed
  - Minimal CPU overhead
  - Original service IP preserved (getpeername)

7.4 Socket LB Limitations

Socket LB is not applied for:
  - Traffic entering from external via NodePort
  - hostNetwork Pod traffic
  - Certain kube-proxy compatibility modes
  - Services with L7 policies (Envoy redirect needed)

In these cases, tc-level fallback processing is used

8. Packet Drops and Monitoring

8.1 Drop Reason Codes

Cilium provides detailed reason codes when packets are dropped:

# Monitor dropped packets
cilium monitor --type drop

# Example output:
# xx drop (Policy denied) flow ...
# xx drop (Invalid source ip) flow ...
# xx drop (CT: Map insertion failed) flow ...

Key drop reasons:

CodeDescription
Policy deniedDenied by policy
Invalid source ipSource IP is invalid
CT: Map insertion failedConntrack map insertion failed
No mapping for NATNo NAT mapping found
Unknown L3 targetUnknown L3 destination
Stale or unroutable IPStale or unroutable IP
Authentication requiredmTLS authentication required
Service backend not foundNo service backend available

8.2 Packet Tracing

# Real-time packet trace
cilium monitor --type trace

# Monitor traffic for a specific endpoint only
cilium monitor --type trace --from-endpoint 1234

# Policy verdict monitoring
cilium monitor --type policy-verdict

# Debug-level monitoring
cilium monitor --type debug

9. Performance Optimization Techniques

9.1 XDP Acceleration

Performance by XDP mode:
  - XDP native (driver-integrated): Best performance
  - XDP generic (software): Compatibility first
  - XDP offload (NIC hardware): Specific NICs only

XDP use cases:
  - NodePort acceleration
  - LoadBalancer acceleration
  - DDoS mitigation (packet drop)
  - Pre-filtering

9.2 BIG TCP

BIG TCP operation:
  - GRO (Generic Receive Offload) merges received packets into 64KB+ size
  - Process as large packets internally, reducing per-packet overhead
  - GSO (Generic Segmentation Offload) segments on transmit
  - Internal processing optimization without MTU constraints

9.3 eBPF Program Optimization

Compile-time optimization:
  - Exclude unused features from compilation
  - Endpoints without policies: minimal BPF code
  - IPv4-only environments: remove IPv6 code

Runtime optimization:
  - BPF map prefetching
  - Inline function usage
  - Eliminate unnecessary conditional branches
  - Native code execution via JIT compilation

10. Datapath Debugging

10.1 BPF Program Status Check

# List all BPF programs
bpftool prog list

# BPF programs for specific interface
tc filter show dev lxc1234 ingress
tc filter show dev lxc1234 egress

# BPF program statistics
bpftool prog show id 42 --json

# BPF map statistics
bpftool map show id 10 --json

10.2 Performance Metrics

# Datapath-related metrics
cilium metrics list | grep datapath

# Key metrics:
# cilium_datapath_conntrack_gc_runs_total
# cilium_datapath_conntrack_gc_entries
# cilium_bpf_map_ops_total
# cilium_drop_count_total
# cilium_forward_count_total

Summary

Cilium's eBPF datapath achieves high performance through these core design principles:

  • In-Kernel Processing: All packet processing in kernel space, eliminating user space transition overhead
  • Tail Call Chaining: Complex logic split across multiple BPF programs for modularity
  • Custom Conntrack: High-performance BPF map-based connection tracking instead of Linux netfilter conntrack
  • Socket-Level LB: Service load balancing without NAT for minimal overhead
  • DSR Mode: Eliminates unnecessary network hops, reducing response latency
  • XDP Acceleration: Ultra-fast packet processing at the network driver level