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 |
| 서비스 LB | ClusterIP/NodePort DNAT | cilium_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 failed | conntrack 맵 삽입 실패 |
| No mapping for NAT | NAT 매핑 없음 |
| Unknown L3 target | L3 대상을 알 수 없음 |
| Stale or unroutable IP | 오래되거나 라우팅 불가능한 IP |
| Authentication required | mTLS 인증 필요 |
| 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:
| Stage | Description | BPF Map Used |
|---|---|---|
| Packet parsing | Extract L2/L3/L4 headers | - |
| Endpoint identification | Identify source Pod | cilium_lxc |
| Policy check | Egress policy matching | cilium_policy |
| Service LB | ClusterIP/NodePort DNAT | cilium_lb4_services |
| Conntrack | Connection state tracking | cilium_ct4_global |
| Routing | Determine destination node | cilium_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:
| Code | Description |
|---|---|
| Policy denied | Denied by policy |
| Invalid source ip | Source IP is invalid |
| CT: Map insertion failed | Conntrack map insertion failed |
| No mapping for NAT | No NAT mapping found |
| Unknown L3 target | Unknown L3 destination |
| Stale or unroutable IP | Stale or unroutable IP |
| Authentication required | mTLS authentication required |
| Service backend not found | No 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