Skip to content
Published on

Cilium eBPFデータパス深層分析:パケット処理パイプライン

Authors

Cilium eBPFデータパス深層分析:パケット処理パイプライン

概要

CiliumのeBPFデータパスはLinuxカーネル内でパケットを処理する高性能ネットワークパイプラインです。この記事ではパケットが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(マスカレード)
    |
    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]

状態別タイムアウト:
- NEW60- ESTABLISHED6時間(TCP)、60秒(UDP- CLOSING10

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 / マスカレード)

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
ノードIP192.168.1.100:50123-> 外部(8.8.8.8:443
応答パケット(Reverse SNAT):
外部(8.8.8.8:443-> ノードIP192.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(サービスロードバランシング)

Kubernetesサービス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の接続のみ再マッピング
- 既存接続の大部分を維持

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)
   [ノードADNAT + DSRオプション設定]
   - 宛先をバックエンドPod(ノードB)に変換
   - IPオプションに元のサービスIP/ポートをエンコード

2. ノードA -> ノードB(バックエンドPod)
   [ノードBDSRオプション処理]
   - IPオプションから元のサービスIP/ポートを復元
   - conntrackにreverse NAT情報を保存

3. ノードB(バックエンドPod)-> クライアント
   [ノードB:reverse NAT]
   - ソースIPをサービスIPに変換
   - ノードAを経由せず直接応答

通常モード(SNAT):
  クライアント -> ノードA -> ノードB -> ノードA -> クライアント
2ホップ追加)

DSRモード:
  クライアント -> ノードA -> ノードB -> クライアント
  (応答は直接)

6. eBPFテールコール:プログラムチェイニング

6.1 テールコールメカニズム

eBPFプログラムには命令数制限があるため、複雑な処理を複数のプログラムに分離します。

テールコールチェーン例:

[from-container]
    |
    tail_call -> [IPv4ポリシー確認]
                    |
                    tail_call -> [サービスLB]
                                    |
                                    tail_call -> [NAT処理]
                                                    |
                                                    tail_call -> [転送]

6.2 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 ソケットLBの利点

パフォーマンス比較:

tcレベルLB  - パケットごとにNAT実行
  - conntrackエントリが必要
  - 追加CPUサイクル

ソケットレベルLB  - 接続ごとに1回のみ変換
  - conntrack不要
  - 最小CPUオーバーヘッド
  - 元のサービスIPを保持(getpeername)

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宛先が不明
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のみサポート

9.2 BIG TCP

BIG TCPの動作:
  - GRO(Generic Receive Offload)で受信パケットを64KB+サイズに統合
  - 内部的に大容量パケットとして処理しパケットあたりのオーバーヘッドを削減
  - GSO(Generic Segmentation Offload)で送信時に分割

9.3 eBPFプログラム最適化

コンパイル時最適化:
  - 未使用機能をコンパイルから除外
  - ポリシーのないエンドポイント:最小限のBPFコード
  - IPv4専用環境:IPv6コードを除去

ランタイム最適化:
  - BPFマッププリフェッチ
  - インライン関数の活用
  - 不要な条件分岐の除去
  - JITコンパイルによるネイティブコード実行

まとめ

CiliumのeBPFデータパスは以下の核心設計で高性能を達成しています。

  • カーネル内処理:すべてのパケット処理がカーネル空間で行われユーザー空間遷移オーバーヘッドを除去
  • テールコールチェイニング:複雑なロジックを複数のBPFプログラムに分離しモジュール性を確保
  • 独自conntrack:Linux netfilter conntrackの代わりにBPFマップベースの高性能コネクショントラッキング
  • ソケットレベルLB:NATなしでサービスロードバランシングし最小オーバーヘッド
  • DSRモード:不要なネットワークホップを除去し応答レイテンシーを削減
  • XDPアクセラレーション:ネットワークドライバレベルで超高速パケット処理