TT Lab
ブログ

한국어 English 日本語

はじめる
ブログ

ブログ

Ciliumを読む:エージェントがBPFマップを埋め、カーネルフックはそのマップだけを見て判断する構造

ステータス:ドラフト(2026-10-17)、一部実測。 基準バージョン cilium/cilium v1.20.1(コミット 7d68cfb394f2)。小規模なクラスタがまさにこのバージョン(エージェント・ operator-generic・hubble-relay v1.20.1、cilium-envoy 1.37系)を実行しているため、実測は2026-10-17にそのクラスタで 読み取りのみ で行いました(エージェントのポッド1つに対して cilium-dbg·bpftool·hubble observe 読み取りコマンド、ConfigMap・ポリシー数の読み取り、relayログの読み取り)。 DNSパターンのアクセスの結果は、コントリビューションの準備を進めながら2026-10-16〜17の間に測定した記録(PRドラフト)を引用します。 執筆のルール:実測データが基本であり、測定できなかったものは「未測定」、確認できなかったものは「未確認」と表示します。

目次

1. 一言まとめ

Ciliumを一言で要約すると、 「ノードごとの事務所(エージェント)がルール表(BPFマップ)を書き換え、カーネル各地の検問所(BPFプログラム)はそのルール表だけを見て通過・遮断・アドレス変換を決定する」 です。検問所は事務所に電話をかけません。パケットごとにユーザー空間に上がってくると遅いため、判断に必要なものはすべてあらかじめマップに書き込んでおきます。そのため、Ciliumのコードを読むときに真っ先に問うべき質問は常に 「この情報は誰がどのマップに書き, どのフックが読み取るのか」 です。

コンポーネント 役割 どこで動くか
cilium-agent Kubernetesの状態を受け取り、ポリシー・サービス・identityを計算してBPFマップに書き込む。BPFプログラムをコンパイル・ロードする。DNSプロキシとHubbleオブザーバーもこのプロセス内にある ノードごと(DaemonSet)
BPFプログラム(bpf/) ポッドのveth・ホストデバイス・トンネルデバイス・ソケットcgroupにアタッチされ、パケットと connect() を処理 カーネル内
cilium-operator CRDの登録、IPAM(モードによる)、残ったidentity・CiliumEndpointのクリーンアップ、LB-IPAM クラスターに1つ(リーダー選出)
cilium-envoy HTTPなどのL7ポリシーおよびIngress・Gatewayのためのプロキシ。xDSを使用してエージェントから設定を受け取る ノードごと(個別DaemonSet)
Hubble エージェント内のオブザーバーがBPFの発行するイベントをフローとして解釈してリングバファに格納し、relayが各ノードのフローを集約する オブザーバーはエージェント内、relayはクラスターに1つ

2. 構成図

Cilium 구성요소와 BPF 프로그램이 붙는 자리 kube-apiserver Service·CNP·CRD 를 감시 cilium-operator 클러스터에 1개 · IPAM·CRD·GC 노드마다 (DaemonSet 두 개) cilium-agent — hive 셀 묶음 infra · controlplane · datapath 정책·셀렉터 캐시 로드밸런서 표 DNS 프록시 loader (clang) Hubble 관찰기 IPAM·ipcache cilium-envoy L7 프록시 (HTTP·gRPC) 에이전트에게 xDS 로 설정 받음 BPF 맵 (/sys/fs/bpf 에 고정) 쓰기 events 서비스 정책 ipcache conntrack 훅 자리 → 붙는 프로그램 (bpf/ 의 파일) 읽기 cgroup 루트(소켓) bpf_sock.c → cil_sock4_connect 등 파드 veth (lxc*) bpf_lxc.c → cil_from_container cilium_host·net bpf_host.c → cil_from/to_host cilium_vxlan bpf_overlay.c → cil_from/to_overlay 물리 NIC (tc) bpf_host.c → cil_from/to_netdev 물리 NIC (XDP) bpf_xdp.c → cil_xdp_entry (꺼짐) hubble-relay · hubble-ui (클러스터에 1개) 에이전트마다 :4244(TLS)로 흐름을 모은다
図:Ciliumの構成要素とBPFプログラムがアタッチされる位置

3. コードマップ

リポジトリは大きいですが、最初に見るべき場所は決まっています。

パス 内容 最初に読むファイル
daemon/ エージェントのエントリポイントとセルのまとめ daemon/cmd/cells.go
bpf/ カーネル上で実行されるCプログラム。エントリファイル bpf_*.c と共通ヘッダー bpf/lib/ bpf/bpf_lxc.c
pkg/datapath/ BPFのコンパイル・ロード(loader)、デバイス・ルート・sysctlの調整、マップの定義 pkg/datapath/loader/endpoint.go
pkg/loadbalancer/ v1.18以降で再設計されたサービスロードバランシング制御部(StateDBテーブル + reconciler) pkg/loadbalancer/README.md
pkg/policy/ ポリシーリポジトリ、selector cache、エンドポイントごとのポリシー計算 pkg/policy/selectorcache.go
pkg/fqdn/ DNSプロキシ、名前→IPキャッシュ、 matchPattern 正規表現変換 pkg/fqdn/matchpattern/matchpattern.go
pkg/hubble/, hubble-relay/ フローの解釈・リングバファ・gRPCサーバー、およびrelay pkg/hubble/observer/local_observer.go
operator/ operatorのエントリポイントとセル operator/cmd/root.go

エージェントとoperatorはどちらも hive という依存性注入フレームワークで組み立てられます。1つの機能が1つの「セル(cell)」であり、セルは何を提供し何を必要とするかだけを宣言します。エージェント main は daemon/main.go:11 での hive.New(cmd.Agent) 1行であり、その Agent が daemon/cmd/cells.go:103 で Infrastructure·ControlPlane·datapath.Cell の3つに分かれています。 ControlPlane(cells.go:194) コメントに分かれている理由が直接書かれています。制御部は「純粋なビジネスロジック」であるため、カーネル権限なしで統合テストを実行できるようにするためです。BPFを実際に触る処理は pkg/datapath/cells.go:52 の datapath モジュールに集約しました。実測した cilium-dbg status --verbose のモジュールツリーも controlplane / datapath / infra の3つに分かれていました(セクション6)。

4. コアパスを辿る

4.1 エージェントがBPFをコンパイル・ロードする道

CiliumはBPFオブジェクトをイメージにあらかじめ焼き込まず、 ノード上でclangによりコンパイルします(エージェントイメージにclang 19.1.7が含まれていることを実測)。ノードごとにカーネル機能や設定(トンネルの有無、マスカレード、IPv6など)が異なるため、使用しない機能を #ifdef で完全に削ることで、検証器(Verifier)を通過させ、命令数の上限にも引っかからないようにするためです。

  1. ベースのデータパス。 pkg/datapath/orchestrator/orchestrator.go:167 reconciler がノードの設定が変更されるたびに Reinitialize を呼び出し、 pkg/datapath/loader/base.go:298 Reinitialize がトンネルデバイス用の bpf_overlay.c、XDP、およびソケットLBが有効な場合は bpf_sock.c をコンパイルしてbase.go:406) cgroupにアタッチします (pkg/socketlb/socketlb.go:83 Enable).
  2. エンドポイント(ポッド)ごと。 pkg/datapath/loader/endpoint.go:83 ReloadDatapath はまず cache.go:176 fetchOrCompile を呼び出します。ここが設計のポイントです。エンドポイントの設定から ポッドごとに異なる値(エンドポイントID、IP、ifindexなど)を除外した残りの部分でハッシュを作成し、同じハッシュのオブジェクトがすでに存在する場合はコンパイルを行わずにコピーして使用します。実際のコンパイルは compile.go:160 compile がclangを実行します。
  3. 値の埋め込みとアタッチ。 endpoint.go:195 reloadEndpoint がテンプレートにポッドごとの値を 定数として上書きしながら(Constants: endpointConfiguration(...)ロードし、ポリシープログラムをtail callマップにあらかじめ挿入した上で、 cil_from_container をvethのingressにアタッチします。順序についてのコメントが記載されています。入口を先に開くと半分だけ準備できたプログラムにパケットが入ってしまうためです。ポッド側のegressプログラム(cil_to_container)は RequireEgressProg() が真のときのみアタッチされます。

実測がその理由を示しています。1つのノードの13個のエンドポイントが 1つのテンプレートハッシュを共有しており、テンプレートは bpf_lxc.o(約1.0MB)と bpf_host.o(約1.4MB)の2つのみでした。コンパイルは1回だけで、残りは定数を書き換えてロードするため、ポッド作成の遅延からclangの処理が排除されます。

4.2 kube-proxyの代替:Serviceが connect() からバックエンドに切り替わるまで

kube-proxyはServiceをiptables(またはIPVS)ルールに変換します。Ciliumは同じ情報をBPFハッシュマップに格納し、 可能であればパケットが生成されるよりも前に ソケットの宛先アドレスを書き換えます。v1.18ではこの制御部がStateDBベースで再設計されており、その構造は pkg/loadbalancer/README.md の図の通りです。

  1. 反映(reflect)。 pkg/loadbalancer/reflectors/k8s.go:208 runServiceEndpointsReflector がServiceとEndpointSliceの変更を一時的に集約して1つのトランザクションとして書き込みます(大量のロールアウト時にマップを何千回も個別に修正することを避けるため)。
  2. テーブルへの書き込み。 pkg/loadbalancer/writer/writer.go:326 UpsertServiceAndFrontends などがサービス・フロントエンド・バックエンドの3つのテーブルの参照を同期させます。データソースが複数あっても、このWriter経由でのみ書き込まれます。
  3. マップへの適合。 pkg/loadbalancer/reconciler/bpf_reconciler.go:725 Update がフロントエンドテーブルを監視し、 updateFrontend(842行目) でマップに書き込みます。マップ cilium_lb4_services_v2(bpf/lib/lb.h:284はキーが (주소, 포트, 프로토콜, 슬롯) であり、スロット0が「ヘッダー部分」(バックエンド数・フラグ)、スロット1..nがバックエンドIDです。リトライはreconcilerが担当するため、データの送信元はマップのエラーを意識する必要がありません。
  4. ソケットでの解決。 bpf/bpf_sock.c:467 cil_sock4_connect がcgroup connect4 フックで __sock4_xlate_fwd(298行目) を呼び出し、そこで lb4_lookup_service を用いてヘッダー部分を検索した後、 sock_select_slot() % count + 1 を使ってスロットを選択し、ソケットアドレスをバックエンドに書き換えます。アプリケーションはClusterIPに接続したと認識しますが、カーネルソケットは最初からバックエンドに接続されているため、パケットごとにNAT処理を行う必要がありません。

しかし、ステップ4には1つ例外の扉があります。

	if (is_defined(ENABLE_SOCKET_LB_HOST_ONLY) && !in_hostns)
		return -ENXIO;

	if (!udp_only && !sock_proto_enabled(protocol))
		return -ENOTSUP;

	/* In case a direct match fails, we try to look-up surrogate
	 * service entries via wildcarded lookup for NodePort and
	 * HostPort services.
	 */
	svc = lb4_lookup_service(&key, true);
	if (!svc)
		svc = sock4_wildcard_lookup_full(&key, in_hostns);
	if (!svc)
		return -ENXIO;

出所:cilium v1.20.1 bpf/bpf_sock.c 322–335行目、GPL-2.0-only OR BSD-2-Clause

socketLB.hostNamespaceOnly を有効にすると、ポッドネームスペースのソケットはここでそのまま処理されます。では、サービスアドレスの変換は誰が行うのでしょうか? bpf_lxc.c がコンパイル時に自ら判断します。

#if !defined(ENABLE_SOCKET_LB_FULL) || \
    defined(ENABLE_SOCKET_LB_HOST_ONLY) || \
    defined(ENABLE_L7_LB)               || \
    defined(ENABLE_SCTP)                || \
    defined(ENABLE_CLUSTER_AWARE_ADDRESSING)
# define ENABLE_PER_PACKET_LB 1
#endif

出所:cilium v1.20.1 bpf/bpf_lxc.c 90–96行目、GPL-2.0-only OR BSD-2-Clause

ソケットで完全に解決できないケースが1つでもある場合、ポッドのvethのtcプログラムにパケット単位のLB__per_packet_lb_svc_xlate_4(152行目)が挿入されます。公式ドキュメントでは、このバイパスはIstioサイドカのように本来ClusterIPが必要な場合や、KubeVirt・Kata・gVisorのようにソケットLBが効果を発揮しないポッドを対象としたものであると説明されています(kubeproxy-freeドキュメントの「Socket LoadBalancer Bypass in Pod Namespace」)。実測した小規模なクラスタはまさにこのモードでしたSocket LB Coverage: Hostns-only。TT LabクラスタはKubeVirt VMを実行しているため、この選択には理由がありますKubeVirt実習VMシリーズ)。結果として、ポッドからサービスに向かう接続は cil_from_container の内部で解決され、ソケット逆変換マップ(cilium_lb4_reverse_sk)にはホストネームスペースのソケット13個のみが存在していました。「kube-proxyの代替 = ソケットLB」と暗記していると誤解してしまうポイントです。

4.3 toFQDNsポリシーがDNSプロキシを経由して「このIPを許可」するようになる道

BPFはIPとポートしか見ません。しかし人間は *.docker.com のように名前でポリシーを記述したいと考えます。Ciliumの答えは DNS応答を傍受して名前からIPを学習し、学習したIPに名前から導出されたidentityを付与することです。名前はBPFまで降りず、BPFはこれまで通り「このidentityを許可するか?」のみを問い合せます。

toFQDNs 가 「이 IP 허용」 이 되기까지 강조한 두 칸(③·⑤)이 matchpattern 정규식을 쓰는 곳 ① 정책이 FQDN 셀렉터를 등록 toFQDNs → NameManager.RegisterFQDNSelector ② 파드의 DNS 질의를 프록시로 돌린다 bpf_lxc 가 53번을 노드의 DNS 프록시로(투명 프록시) ③ 질의 이름 검사 — rules.dns ServeDNS → CheckAllowed, 안 맞으면 REFUSED ④ 위로 보내고 응답을 받는다 DNSClients.Exchange → 응답의 이름·IP·TTL ⑤ 이름이 어느 toFQDNs 셀렉터에 맞나 UpdateGenerateDNS → deriveLabelsForName ⑥ IP 에 fqdn: 라벨 → identity → 정책 맵 ipcache 갱신 → SelectorCache.UpdateIdentities ⑦ 반영을 기다린 뒤 응답을 돌려준다 WaitForRevision(최대 100ms) → WriteMsg ⑧ 파드가 그 IP 로 연결 → bpf_lxc 가 정책 맵에서 허용을 찾는다 matchpattern 변환 (escapeRegexpCharacters) *.docker.com — * 는 점을 넘지 않는다 ^[-a-zA-Z0-9_]*[.]docker[.]com[.]$ **.docker.com — 앞머리 **. 만 여러 칸 ^(라벨([.]라벨)*)[.]docker[.]com[.]$ 질의 이름 * 패턴 **. 패턴 hub.docker.com 맞음 맞음 production.cloudflare.docker.com 아님 맞음 docker.com 아님 아님
図: toFQDNsがIP許可に至るまで
  1. セレクターの登録。 ポリシーに toFQDNs がある場合、 pkg/fqdn/namemanager/manager.go:140 RegisterFQDNSelector がセレクターを受け取り、すでにキャッシュ内にある名前で一致するものがあれば即座にIPを表示します。セレクターの正規表現は、 pkg/policy/api/fqdn.go:115 ToRegex がmatchpatternで作成します。
  2. クエリの傍受。 同様のポリシーの rules.dns(ポート53)により、 bpf_lxc がそのポッドのDNSパケットをノードのDNSプロキシに転送します。 pkg/fqdn/dnsproxy/proxy.go:895 ServeDNS が CheckAllowed(763行目) でクエリ名を検証します。 その正規表現は、 GeneratePattern(1439行目) が rules.dns のパターンを | で結合して作成したものです。一致しない場合は拒否応答を返します(小さなクラスターの設定は refused).
  3. 応答から名前キャッシュへ。 許可されれば上流へ送り、応答を受け取ったらクライアントに返す 前に NotifyOnDNSMsg を呼び出します。これが pkg/fqdn/messagehandler/message_handler.go:277 UpdateOnDNSMsg を経由して namemanager/manager.go:214 UpdateGenerateDNS に向かいます。
  4. 名前のマッチング。 manager.go:422 deriveLabelsForName が応答名をすべてのFQDNセレクターの正規表現と照合し、一致するセレクターごとに fqdn:<패턴> ラベルを集めます。
  5. IPへのidentity付与。 manager.go:315 updateMetadata が応答のIPごとにそのラベルをipcacheに登録し、ipcacheがラベルのセットに一致するidentityを割り当てます。新しいidentityは pkg/policy/selectorcache.go:768 UpdateIdentities を通じてセレクターキャッシュに入り、そのセレクターを使用するエンドポイントのポリシーマップに許可エントリが生成されます。
  6. 待機してから応答を返す。 UpdateGenerateDNS は、ipcacheがその変更をマップに反映するまで(WaitForRevision)待機するチャネルを返します。ハンドラーは tofqdns-proxy-response-max-delay(小さなクラスターでは100ms)の間だけ待機し、応答をポッドに書き込みます。ポッドが応答を受け取ってすぐに接続しても、ポリシーマップがすでに開いている状態にするための順序です。

ここでmatchpatternが2回使用される点が重要です(図の③・⑤)。変換ルールは簡潔です。

func escapeRegexpCharacters(pattern string) string {
	// Convert '.' in the match pattern as literal '.' for regex pattern.
	pattern = strings.ReplaceAll(pattern, ".", "[.]")

	// '**.' in match pattern prefix is a subdomain wildcard specifier which matches one ore more
	// entire labels.
	pattern = subdomainWildcardSpecifierPrefix.ReplaceAllString(pattern, dnsWildcardREGroup)

	// Base case: * becomes .*, but only for DNS valid characters
	// `*` wildcard matches all DNS characters within the subdomain boundary(doesn't include '.' literal)
	pattern = wildcardSpecifier.ReplaceAllString(pattern, allowedDNSCharsREGroup+"*")

	return pattern
}

出典: cilium v1.20.1 pkg/fqdn/matchpattern/matchpattern.go 131–144行目、Apache-2.0

* は [-a-zA-Z0-9_]*(17行目)に変換され、 ドットを越えることができません。 複数受け入れるのは先頭の **. ひとつだけであり(37行目の ^[*]{2,}\[\.\]、23行目の dnsWildcardREGroup)、中間にある ** は最後の行で単に * のように変換されます。末尾にドットを付与する正規化は Sanitize(87行目) が実行します。

実測事例。 コントリビューションの準備中に小さなクラスターで測定した記録(2026-10-16〜17、PRドラフト)です。イメージレジストリ用のポリシーが toFQDNs: matchPattern: "*.docker.com" で、DNSが * として開いているポッドから3つの名前にそれぞれ2回ずつ接続しました。

名前 DNS解決 接続 理由
hub.docker.com 成功 接続成功 (HTTP 200) 1つ分 → *.docker.com に一致
production.cloudflare.docker.com 成功 タイムアウト (curl 28) 2つ分 → * がドットを越えられない
docker.com 成功 タイムアウト *. 先頭に1つ分が必要

2行目はDocker Hubのイメージレイヤーを配信するCDN名であるため、ポリシーは一致しているように見えるにもかかわらずイメージの取得のみが失敗する現象になります。同じ記録においてmainのmatchpatternをGoで直接実行した(Validate(Sanitize(p)))結果も表と同様であり(**.docker.com は2行目に一致)、記事の執筆中に変換ルールをPythonに移植して再実行した結果も同様でした(図の下の表)。DNSはいずれも解決されていたため、ブロックされている箇所は③ではなく⑤です。同様の性質が実習用ポッドのDNS egressポリシーでどのような問題を引き起こしたかについては、「DNSへの漏洩経路の遮断」に別途記載しています。この記事では、その性質がコードのどの行に起因しているかまでを取り上げます。 DNSへの漏洩経路の遮断 この記事では、その性質がコードのどの行に起因しているかまでを取り上げます。

4.4 Hubble: perfリングバッファからrelayまで

  1. BPFがイベントを出力する。 パケットが転送・破棄・ポリシー判定される際、 bpf/lib/trace.h:210 _send_trace_notify などが cilium_events(bpf/lib/events.h:13, PERF_EVENT_ARRAY)に短い記録を書き込みます。すべてのパケットを書き込むと負荷が高いため、 MONITOR_AGGREGATION で削減します。実測したエンドポイントの ep_config.h は MONITOR_AGGREGATION 3(アクティブな接続の追跡を簡略化、ConfigMapの monitor-aggregation: medium)でした。
  2. エージェントが読み取る。 pkg/monitor/agent/agent.go:324 handleEvents がperfリーダーを開き、レコードごとに notifyPerfEventLocked(428行目) でコンシューマーに分配します。Hubbleはそのコンシューマーの1つです(pkg/hubble/monitor/consumer.go:73).
  3. 解釈してリングバッファへ。 pkg/hubble/observer/local_observer.go:116 Start のループがイベントを Decode してフロー(Flow)を生成し、メトリクスフックを経由して container/ring.go:168 Ring.Write で固定サイズのリングに格納します。サイズは2のべき乗マイナス1(デフォルト4095)であるため、インデックスは除算ではなくマスクによって求められます。 GetFlows(260行目)はこのリングを読み取るだけです。
  4. relayによる集約。 relayは各エージェントのHubbleサーバー(:4244、TLS)に接続されます(pkg/hubble/relay/pool/manager.go:51)。 リクエストが来ると、 pkg/hubble/relay/observer/server.go:62 GetFlows がすべてのピアに同じリクエストを送信し(observer.go:37)、 返ってきたフローを時系列順に再ソートして(sortFlows、67行目)出力します。

この設計の意図は「保存しない」という点にあります。フローはノードのメモリ上のリングにのみ存在し、relayも保持しません。実測したノードではリングが4095/4095で埋まった状態で毎秒58.5個のフローが流入していたため、1つのノードが記憶している過去の履歴は 約70秒です。長期間保持したい場合は、メトリクスやエクスポーターを別途使用します。

5. ユーザーコントリビューションとの関連

筆者は4.3の性質に関するドキュメントを修正する変更を準備していました(原典第5節「準備のみ完了した項目」)。まだ 公開していません。 CiliumはAIが大部分を作成したコミュニケーション(PR本文など)を受け付けない方針であるため、本文は筆者が自ら記述する必要があります。そのため、ここでも「準備のみ完了した」という段階までを記載しています。

ドキュメント上の位置(v1.20.1) 現在の内容 コードの根拠
Documentation/security/policy/layer7.rst:159 L7 DNSの matchPattern の説明に **. がない GeneratePattern も ToUnAnchoredRegexp →同じ escapeRegexpCharacters
layer7.rst:166, :227 1つ分のみ一致する例を「any subdomains」と呼称 * → [-a-zA-Z0-9_]*(141行目)
layer3.rst:548 **. の説明はあるが「先頭のみ」という記載がない 37行目の正規表現が ^ に固定、テストの test.**.cilium.io. 事例

根拠は4.3の実測表およびGoによる再現結果です。ドキュメントの3つのファイルと matchpattern.go は、v1.20.1とmainが同一であることを準備の段階で確認したとドラフトに記載されています。

6. 実測

2026-10-17、小さなクラスター(ノード8台、kube-proxy DaemonSetなし)のコントロールプレーンノードの1つのエージェントポッドに対してのみ読み取りコマンドを実行しました。生データは別途保管し、以下は名前とアドレスを除外した値です。

コマンド 確認結果
cilium-dbg status KubeProxyReplacement: True, Routing: Network: Tunnel [vxlan] Host: BPF, Attach Mode: TCX, Device Mode: veth, Masquerading: BPF, Host firewall: Enabled、コントローラー 90/90、モジュール 125 OK、クラスターの健全性 8/8
cilium-dbg status --verbose Socket LB: Enabled, Socket LB Coverage: Hostns-only, Backend Selection: Random, XDP Acceleration: Disabled、IPAMはノードあたり/24から15個を割り当て
cilium-dbg service list フロントエンド 211個 (ClusterIP 171、NodePort 20、LoadBalancer 20)
cilium-dbg bpf lb list, map list cilium_lb4_services_v2 573エントリ = ヘッドエントリ 358 + バックエンドスロット 215。ヘッドエントリのうち127個はポート0/ANYのワイルドカードエントリ(用途の詳細は未確認)。バックエンドマップ 163、逆変換マップ 231、ソケット逆変換 13
bpftool net show lxcデバイス13個すべて tcx/ingress cil_from_container のみ、egressなし。物理NIC cil_from/to_netdev, cilium_host·cilium_net cil_to_host·cil_from_host, cilium_vxlan cil_from/to_overlay、XDPは空
bpftool prog show Ciliumプログラム 231個 (tc 218、cgroup sock_addr 8、cgroup sock 3、ソケット終了用tracing 2)。tc側はエンドポイントごとに概ね ingress 3個 + tail call 10個
bpftool cgroup tree cgroupのルートに cil_sock4_connect·sendmsg4·recvmsg4·getpeername4·post_bind4·sock_release など11個
ステータスディレクトリ ls テンプレート2個(bpf_lxc.o 1,086,040バイト、 bpf_host.o 1,452,768バイト)。エンドポイント13個の template.txt のハッシュがすべて一致
hubble observe --last 500 500個が10.5秒分、FORWARDED 489、DROPPED 11(すべて UNSUPPORTED_L3_PROTOCOL)。リング 4095/4095、58.5フロー/秒
cilium-dbg fqdn cache list, fqdn names このノードは空(FQDNセレクター 0) — このノードにはDNSルールが適用されたポッドが存在しなかった
ポリシー数(クラスター全体) CNP 22個のうち rules.dns が存在するもの 5、 toFQDNs が存在するもの 2
relayのログ 8個のピアに :4244、TLSで接続

読むべき対象は3つあります。

7. どこから読むべきか

  1. daemon/cmd/cells.go:103 — セルのリストを走査し、エージェントに何が含まれているかのマップを作成します。コメントが親切です。
  2. pkg/loadbalancer/README.md と bpf_reconciler.go:842 — 「テーブル → reconciler → マップ」というCiliumの新しい制御プレーンの作法を最も短時間で学べる箇所です。
  3. bpf/bpf_sock.c:298 — マップを読み取る側。2番で使用したエントリがどのように読み取られるかを確認します。
  4. pkg/datapath/loader/endpoint.go:195 — テンプレート、定数、tcxアタッチの順序。
  5. pkg/fqdn/dnsproxy/proxy.go:895 から namemanager/manager.go:214 まで — ユーザー空間プロキシとBPFポリシーが交差する場所。
  6. bpf/bpf_lxc.c:1780 cil_from_container — 最後に読みます。tail callと #ifdef が多く含まれているため、前半の5つを理解した上で読まないと道に迷ってしまいます。

8. 最初の一歩としてコントリビューションしやすい場所

ソースコードを読みながら実際に気付いた点です(未公開であり、mainでそのまま維持されているかは未確認)。

9. 制限事項

著者の一言。 Ciliumの検問所は電話に出ません。事前に受け取ったルール表を見るだけです。だから変だと思ったら検問所ではなく 誰がその表を書いたのかを探しに行ってみてください。そして * はドット一つも超えられない臆病者だということを、忘れないでください。

参考

すべての資料は2026-10-17に閲覧しました。ソースはcilium/cilium v1.20.1タグ(コミット7d68cfb394f2)です。

引用したコード: bpf/bpf_sock.c·bpf/bpf_lxc.c は GPL-2.0-only OR BSD-2-Clause、 pkg/fqdn/matchpattern/matchpattern.go は Apache-2.0 (Copyright Authors of Cilium)。

ログインするといいねできます

コメント

まだコメントはありません。

ログインするとコメントできます