Skip to content

✍️ 필사 모드: eBPF Deep Dive — Linuxカーネルをプログラマブルにした VM、Verifier、XDP、CO-RE 徹底解説 (2025)

日本語
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

TL;DR

  • eBPF は Linux カーネル内でサンドボックス化されたバイトコードを実行する VM である。カーネルモジュールをビルドせずにカーネル動作を観測・変更できる。
  • 11 レジスタ、64-bit RISC-like ISA。clang -target bpf で C をバイトコードに、ロード時に JIT でネイティブ化。
  • Verifier が安全性を保証する。ロード前に symbolic execution で全経路を検証: 無限ループ禁止、ポインタ境界チェック、未初期化レジスタ読み取り禁止。
  • Maps はカーネル・ユーザ空間の双方で読み書きできる共有データ構造。Hash、Array、LRU、LPM Trie、Ring Buffer、Per-CPU 変種など数十種。
  • プログラムタイプがフックポイントを決める。kprobetracepointXDPTCLSMcgroup_skb 等。
  • CO-RE + BTF がカーネル構造体のバージョン差問題を解決する。一度コンパイルすればどのカーネルでも動く。
  • XDP は NIC ドライバ直後でパケットを処理し、1 コアで毎秒数千万パケットを捌ける。DPDK 級の性能 + カーネル統合。
  • 実プロダクト: Cilium (K8s ネットワーキング/セキュリティ)、Pixie (可観測性)、Falco (ランタイムセキュリティ)、bpftrace (アドホックトレース)、Katran (L4 LB)。

1. なぜ eBPF か

1.1 カーネル拡張の古いジレンマ

カーネルに機能追加する手段は 3 つだった:

  1. カーネルパッチ: メインライン取り込みに数年。小さな機能は却下。
  2. カーネルモジュール (LKM): insmod でロード。クラッシュでカーネル panic。バージョンごとに再ビルド。
  3. ユーザ空間実装: syscall/ioctl でカーネルに問い合わせ。遅く、コンテキストスイッチがボトルネック。

L4 ロードバランサ例: HAProxy は毎パケット往復、IPVS は速いがカーネル panic 懸念、DPDK は数千万 pps だが CPU 1 コア丸ごと消費 + カーネルスタックと共存不可。eBPF は第 4 の道を開いた: 「カーネル内でサンドボックス実行」、安全性は verifier が保証。

1.2 BPF の起源 — 1992

Van Jacobson と Steven McCanne が Berkeley Packet Filter を作成。tcpdump のカーネル内フィルタリング用。32-bit ISA、2 レジスタ。これが cBPF。

1.3 Alexei Starovoitov の 2014 年再設計

eBPF (extended BPF) 誕生:

  • 11 レジスタ、64-bit 化。
  • Maps 追加: カーネル・ユーザ間の状態共有。
  • Helper 関数: 安全なカーネル API。
  • JIT: ネイティブ機械語化。
  • Verifier 強化: 複雑なプログラムも検証可能。
  • ネットワーク以外のフック: kprobe、tracepoint、cgroup など。

「カーネルモジュールの力 + ユーザ空間コードの安全性」が本質。

1.4 2025 年の生態系

Meta Katran、Netflix FlowLogs、GKE、Cloudflare DDoS mitigation、Cilium (K8s CNI の事実上の標準)、RHEL 9 で bpftrace/bcc/libbpf 公式サポート。eBPF Foundation が Linux Foundation 配下に発足。


2. eBPF 仮想マシン

2.1 命令フォーマット

固定 64-bit (8 バイト):

struct bpf_insn {
    __u8    code;       // 8 bits: opcode
    __u8    dst_reg:4;  // 4 bits: destination register
    __u8    src_reg:4;  // 4 bits: source register
    __s16   off;        // 16 bits: signed offset
    __s32   imm;        // 32 bits: signed immediate
};

2.2 レジスタ

R0  : 戻り値
R1-R5: 引数 (C 呼び出し規約)
R6-R9: callee-saved
R10 : フレームポインタ (read-only、スタックアクセス用)

R10 はスタックアクセス専用の読み取り専用レジスタ。

2.3 例

int add(int a, int b) { return a + b; }

clang -target bpf -O2 で:

; 0000000000000000 <add>:
;    0:  bf 10 00 00 00 00 00 00   r0 = r1       ; R0 = a
;    1:  0f 20 00 00 00 00 00 00   r0 += r2      ; R0 += b
;    2:  95 00 00 00 00 00 00 00   exit

2.4 JIT

カーネルは x86_64、ARM64、RISC-V、MIPS、PowerPC、s390x、SPARC すべてで JIT 対応。5.x 以降はデフォルト有効:

sysctl net.core.bpf_jit_enable  # 1 = enabled

ネイティブ C とほぼ同等の性能。

2.5 命令数制限と Bounded Loop

  • 5.2 未満: 関数 4,096 命令。
  • 5.2+: 関数 1M 命令、verifier の複雑度予算あり。
  • 5.3+: verifier が上限証明可能なら bounded loop 許可。
for (int i = 0; i < 64; i++) { /* OK */ }

#pragma unroll
for (int i = 0; i < 4; i++) { /* 常に OK */ }

for (int i = 0; i < x; i++) { /* NG: x unknown */ }

3. Verifier — eBPF の心臓

3.1 検証目的

  1. 終了性: 無限ループなし、全経路が exit に到達。
  2. メモリ安全性: ポインタアクセスが確保領域内。
  3. 初期化保証: 読み取り前に書き込み。
  4. 型安全性: スカラーをポインタとして逆参照禁止。
  5. 複雑度制限: 検証自体が妥当な時間で終わる。

失敗時は bpf() syscall が -EINVAL を返し、詳細なログを出力。

3.2 Symbolic Execution

各レジスタ・スタックスロットの「取り得る値の範囲」を追跡し、分岐ごとに経路を fork:

int x = get_pid();   // x: [0, 4194304]
if (x > 100) {
    // この分岐では x: [101, 4194304]
    use(x);
}

s32_min/maxu32_min/maxs64_min/max およびポインタ種別・オフセットを追跡。

3.3 ポインタ型システム

PTR_TO_CTX        : プログラムコンテキスト
PTR_TO_PACKET     : ネットワークパケット
PTR_TO_PACKET_END : パケット終端
PTR_TO_MAP_KEY    : マップキー
PTR_TO_MAP_VALUE  : マップ値
PTR_TO_STACK      : スタックメモリ
PTR_TO_SOCKET     : ソケット
SCALAR_VALUE      : 非ポインタスカラー

PTR_TO_MAP_VALUE は NULL チェック後にのみ逆参照可:

void *val = bpf_map_lookup_elem(&my_map, &key);
if (!val) return 0;
*(int *)val = 42;

3.4 パケット境界チェック

SEC("xdp")
int drop_port_80(struct xdp_md *ctx) {
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    struct ethhdr *eth = data;

    if (data + sizeof(*eth) > data_end)  // 必須
        return XDP_PASS;
    if (eth->h_proto == bpf_htons(ETH_P_IP)) { /* ... */ }
    return XDP_PASS;
}

3.5 Verifier エラーの読み方

17: invalid access to packet, off=14 size=2, R1(id=0,off=14,r=0)
R1 offset is outside of the packet

対処: アクセス前に data + N > data_end チェックを追加。

3.6 複雑度予算

経路が多過ぎると "BPF program is too complex"。上限は 5.2+ で 1,000,000 状態。対策: bounded loop 優先、__always_inline で helper インライン化、state pruning (4.19+) 活用。


4. Maps

4.1 必要性

  • スタック 512 バイト制限。
  • プログラム間の直接共有不可。
  • ユーザ空間通信が必要。

→ Maps が解決する型付き KV ストア。

4.2 主要タイプ

タイプ用途
BPF_MAP_TYPE_HASHPID 別統計
BPF_MAP_TYPE_ARRAYカウンタ、設定
BPF_MAP_TYPE_PERCPU_HASHロックフリーカウンタ
BPF_MAP_TYPE_LRU_HASHコネクション追跡
BPF_MAP_TYPE_LPM_TRIEルーティングテーブル
BPF_MAP_TYPE_STACK_TRACEプロファイリング
BPF_MAP_TYPE_RINGBUFユーザへのイベント (5.8+)
BPF_MAP_TYPE_PROG_ARRAYtail call
BPF_MAP_TYPE_DEVMAPXDP redirect
BPF_MAP_TYPE_SK_STORAGEソケット別状態
BPF_MAP_TYPE_TASK_STORAGEタスク別状態

4.3 宣言 (libbpf スタイル)

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __type(key, u32);
    __type(value, u64);
    __uint(max_entries, 10240);
} pid_counts SEC(".maps");

4.4 プログラムからのアクセス

u32 pid = bpf_get_current_pid_tgid() >> 32;
u64 *count = bpf_map_lookup_elem(&pid_counts, &pid);
if (!count) {
    u64 one = 1;
    bpf_map_update_elem(&pid_counts, &pid, &one, BPF_ANY);
} else {
    __sync_fetch_and_add(count, 1);
}

4.5 Per-CPU マップ

キャッシュライン競合を回避し、CPU ごとに自スロットを持つ:

int ncpus = libbpf_num_possible_cpus();
u64 vals[ncpus];
bpf_map_lookup_elem(fd, &key, vals);
u64 total = 0;
for (int i = 0; i < ncpus; i++) total += vals[i];

4.6 Ring Buffer

Linux 5.8+、MPSC、back-pressure 検知、event loss カウンタ:

struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 256 * 1024);
} events SEC(".maps");

SEC("tp/sched/sched_process_exec")
int handle_exec(void *ctx) {
    struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
    if (!e) return 0;
    e->pid = bpf_get_current_pid_tgid() >> 32;
    bpf_get_current_comm(&e->comm, sizeof(e->comm));
    bpf_ringbuf_submit(e, 0);
    return 0;
}

5. プログラムタイプとフックポイント

5.1 Kprobe / Kretprobe

カーネル関数のエントリ・終了にフック。ほぼ全てのカーネル関数に付けられるが、関数名・シグネチャがバージョン依存。

SEC("kprobe/do_sys_openat2")
int kprobe_openat(struct pt_regs *ctx) {
    const char *filename = (const char *)PT_REGS_PARM2(ctx);
    char buf[256];
    bpf_probe_read_user_str(buf, sizeof(buf), filename);
    return 0;
}

5.2 Tracepoint

カーネル開発者が明示的に定義した安定 ABI イベント。/sys/kernel/debug/tracing/events で一覧確認。

5.3 Fentry / Fexit (BPF Trampoline, 5.5+)

kprobe より高速。関数先頭の 5-byte NOP を call で上書き。オーバーヘッドほぼ 0。

SEC("fentry/tcp_v4_connect")
int BPF_PROG(connect_entry, struct sock *sk) { return 0; }

SEC("fexit/tcp_v4_connect")
int BPF_PROG(connect_exit, struct sock *sk, int ret) { return 0; }

5.4 XDP

NIC ドライバ直後、sk_buff 割当前に実行:

SEC("xdp")
int xdp_drop_tcp_80(struct xdp_md *ctx) {
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    struct ethhdr *eth = data;
    if (data + sizeof(*eth) > data_end) return XDP_PASS;
    if (eth->h_proto != bpf_htons(ETH_P_IP)) return XDP_PASS;

    struct iphdr *ip = data + sizeof(*eth);
    if ((void *)(ip + 1) > data_end) return XDP_PASS;
    if (ip->protocol != IPPROTO_TCP) return XDP_PASS;

    struct tcphdr *tcp = (void *)ip + ip->ihl * 4;
    if ((void *)(tcp + 1) > data_end) return XDP_PASS;

    if (tcp->dest == bpf_htons(80)) return XDP_DROP;
    return XDP_PASS;
}

戻り値: XDP_PASSXDP_DROPXDP_TXXDP_REDIRECTXDP_ABORTED

5.5 TC BPF

qdisc レベルで実行。egress 制御や Cilium の identity ベースフィルタに利用。

5.6 cgroup_skb / cgroup_sock

cgroup 単位のネットワーク制御。K8s ネームスペース隔離に使用。

5.7 LSM BPF (5.7+)

セキュリティ方針を eBPF で動的に実装。再コンパイルなしでデプロイ可能。

SEC("lsm/file_open")
int BPF_PROG(block_secret_file, struct file *file) {
    char name[256];
    bpf_probe_read_kernel_str(name, sizeof(name),
        file->f_path.dentry->d_iname);
    if (strcmp(name, "secret") == 0) return -EACCES;
    return 0;
}

5.8 Sockops

ソケットライフサイクルにフック。Cilium は connect(svc_ip) 時点で DNAT して iptables を完全にスキップ。


6. CO-RE — Compile Once, Run Everywhere

6.1 問題

構造体フィールドオフセットがバージョンでずれ、ビルド済み .o が別カーネルで誤ったメモリを読む。BCC はランタイム LLVM コンパイルで対処したが、イメージが数百 MB。

6.2 BTF + CO-RE

BTF はカーネル型情報を /sys/kernel/btf/vmlinux に保存。CO-RE はフィールドアクセスを再配置可能に印付け、libbpf がロード時に現カーネルのオフセットにリライトする。

#include <vmlinux.h>
#include <bpf/bpf_core_read.h>

SEC("kprobe/tcp_sendmsg")
int trace_tcp_sendmsg(struct pt_regs *ctx) {
    struct sock *sk = (struct sock *)PT_REGS_PARM1(ctx);
    u16 sport;
    BPF_CORE_READ_INTO(&sport, sk, __sk_common.skc_num);
    return 0;
}

6.3 vmlinux.h の生成

bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

カーネルヘッダ不要。

6.4 Feature Detection

if (bpf_core_field_exists(task->comm_size)) {
    /* 新カーネル */
} else {
    /* 旧カーネル */
}

6.5 CO-RE が変えたこと

コンテナイメージは libbpf + CO-RE 可能な .bpf.o のみで数 MB。Cilium、Falco、Pixie、Inspektor Gadget 等が全て単一バイナリで配布。


7. XDP — 超高速パケット処理

7.1 配置

NIC -> XDP (ドライバ RX 直後) -> sk_buff 割当 -> TC ingress -> routing -> TC egress -> ドライバ TX -> NIC

XDP は sk_buff 割当前に実行され、数百 ns のオーバーヘッドを省く。

7.2 モード

  1. Native XDP: ドライバ統合、最速。
  2. Generic XDP: カーネルソフトウェアエミュレート、遅い。
  3. Offloaded XDP: SmartNIC でハードウェア実行。

7.3 性能数値

方式pps (1 コア)レイテンシ
カーネルスタック (iptables)約 1 Mpps約 10 us
XDP Native約 24 Mpps約 1 us
DPDK約 30 Mpps約 0.5 us

7.4 DDoS フィルタリング

LPM trie のブラックリスト、送信元別 SYN レートマップで XDP_DROP。Cloudflare は 5-10 Tbps の洪水を NIC 端で吸収。

7.5 Katran (Meta L4 LB)

  • DSR (Direct Server Return)。
  • Maglev ハッシュで均等分散 + 最小再割当。
  • ホスト 1 台で数百万 pps。

8. Cilium

8.1 K8s ネットワーキングの課題

iptables モードはサービス数に対し O(n) 増加。IPVS でも sk_buff と netfilter のオーバーヘッド残存。

8.2 Cilium の解決

veth ペアの TC フックに eBPF を付け、サービス解決・ポリシー・LB・暗号化を直接処理。iptables をバイパス。

8.3 Identity ベースポリシー

ラベル組み合わせに 16-bit identity ID を発行。ポリシー評価は (src_identity, dst_identity, port) の O(1) マップ参照。

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-frontend-to-backend
spec:
  endpointSelector:
    matchLabels:
      app: backend
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP

8.4 kube-proxy 代替

sockops が connect() をフック、BPF マップで O(1) に backend を解決、DNAT 済みで接続開始。同一ノードなら sockmap redirect でカーネルスタックも完全に迂回。


9. Observability: bpftrace、bcc、Pixie

9.1 bpftrace

DTrace 類似のワンライナー:

bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[probe] = count(); }'

bpftrace -e '
kprobe:tcp_v4_connect { @start[tid] = nsecs; }
kretprobe:tcp_v4_connect /@start[tid]/ {
    @latency = hist((nsecs - @start[tid]) / 1000);
    delete(@start[tid]);
}'

9.2 bcc

Python から BPF C を埋め込む。ランタイム LLVM 必要。CO-RE 登場後 libbpf へ移行中。

9.3 libbpf + skeleton — プロダクション標準

#include <vmlinux.h>
#include <bpf/bpf_helpers.h>

struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 256 * 1024);
} events SEC(".maps");

SEC("tp/syscalls/sys_enter_openat")
int handle_openat(void *ctx) {
    u32 *e = bpf_ringbuf_reserve(&events, sizeof(u32), 0);
    if (!e) return 0;
    *e = bpf_get_current_pid_tgid() >> 32;
    bpf_ringbuf_submit(e, 0);
    return 0;
}

char LICENSE[] SEC("license") = "GPL";

単一バイナリ、libbpf 依存のみ、CO-RE でカーネル非依存。

9.4 Pixie

DaemonSet が uprobe で libssl/libc/libgrpc にフックし、HTTP/gRPC/SQL をコード改修なしでデコード。


10. Falco — ランタイムセキュリティ

Falco は eBPF で syscall を全監視し、ルールマッチで通知:

- rule: Read sensitive file untrusted
  desc: Detect reading sensitive files
  condition: >
    sensitive_files and open_read
    and proc_name_exists
    and not proc.name in (trusted_procs)
  output: >
    Sensitive file opened (user=%user.name
    command=%proc.cmdline file=%fd.name)
  priority: WARNING

カーネルモジュールから eBPF 移行後: K8s ノードに即デプロイ可、カーネル版差なし (CO-RE)、オーバーヘッド 1% 未満。


11. 限界と注意点

11.1 Verifier の壁

複雑なロジックは tail call や bpf_loop (5.17+) で分割する必要がある。

11.2 GPL 制約

bpf_printkbpf_probe_read_kernel 等の有用な helper の多くは GPL:

char LICENSE[] SEC("license") = "GPL";

指定がないと verifier が拒否。

11.3 性能オーバーヘッド

XDP ベンチマーク:

  • 空プログラム: 約 24 Mpps
  • map lookup 1 回: 約 18 Mpps
  • map lookup 3 回 + 簡単ロジック: 約 10 Mpps

11.4 デバッグの困難

  • bpf_printktrace_pipe へ (遅くグローバル)。
  • スタックトレースなし、GDB 不可。

代替: bpftool prog dump jited、verifier ログ精読、BPF_PROG_TEST_RUN によるテスト。

11.5 Observer Effect

uprobe/kprobe は呼出し毎に 5-30 ns 追加。高頻度関数では顕著。軽量フィルタを前置し、ring buffer へ転送する設計を推奨。


12. セキュリティ

12.1 eBPF は安全か

Verifier はメモリ安全性を証明するが意図的安全性は別。Spectre 系サイドチャネル、verifier DoS、特権ユーザによるカーネルメモリ読み取りが懸念。kernel lockdown と CAP_BPF で緩和。

12.2 権限体系

  • CAP_SYS_ADMIN: 従来の広範な権限。
  • CAP_BPF (5.8+): BPF 専用に細分化。
  • CAP_PERFMON: トレース用。
  • CAP_NET_ADMIN: ネットワーク BPF 用。

12.3 非特権 BPF の衰退

Spectre 以降デフォルト無効 (kernel.unprivileged_bpf_disabled=1)。2025 年時点で事実上禁止状態。


13. ベンチマークとチューニング

13.1 XDP

ip link set dev eth0 xdp obj drop.o sec xdp
ip -s link show eth0

bpftool prog show + bpftool prog profileperf stat -e cycles,instructions

13.2 Verifier プロファイル

bpftool prog load prog.o /sys/fs/bpf/prog \
    log_level 2 log_size 4194304 2>&1 | tee verifier.log

13.3 XDP 最適化

  1. 連続フィールドの境界チェックをまとめる。
  2. bpf_xdp_adjust_head 回避。
  3. PCIe NIC の RX ring を拡大。
  4. RPS/RFS で IRQ を特定 CPU に固定。
  5. Huge page で TLB ミス削減。

14. Tail Call と BPF-to-BPF Call

14.1 Tail Call

BPF_MAP_TYPE_PROG_ARRAY 経由でプログラム間を飛ぶ:

struct {
    __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    __uint(max_entries, 4);
    __type(key, u32);
    __type(value, u32);
} prog_array SEC(".maps");

SEC("xdp")
int entry(struct xdp_md *ctx) {
    bpf_tail_call(ctx, &prog_array, NEXT_PROG);
    return XDP_PASS;
}

スタック喪失、最大連鎖 33 段。

14.2 BPF-to-BPF Call (4.16+)

通常の関数呼び出し。スタック保持・戻り値あり。再帰不可 (verifier が終了証明不可)。


15. 未来とトレンド

15.1 eBPF for Windows

Microsoft が開発中。同一 ELF を Linux/Windows 両方で実行するのが目標。2025 年時点でベータ。

15.2 sched_ext (Linux 6.12)

プロセススケジューラ自体を eBPF で書ける。Meta 主導:

SEC("struct_ops/scx_example_enqueue")
void BPF_STRUCT_OPS(enqueue, struct task_struct *p, u64 enq_flags) {
    scx_bpf_dispatch(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags);
}

CFS/EEVDF の代替として独自ポリシーを投入可能。

15.3 eBPF + Rust

aya フレームワークが成熟:

use aya_bpf::{macros::xdp, programs::XdpContext};

#[xdp]
pub fn my_xdp(ctx: XdpContext) -> u32 {
    match unsafe { try_my_xdp(ctx) } {
        Ok(ret) => ret,
        Err(_) => xdp_action::XDP_PASS,
    }
}

15.4 Service Mesh

Cilium Service Mesh は eBPF + per-node envoy モデルで Istio のサイドカーを置換。L4・identity・mTLS は eBPF、L7 パースのみ envoy。オーバーヘッド約 70% 削減。


16. 学習ロードマップ

  1. ebpf.io と公式 "What is eBPF" を読む。
  2. bpftrace のワンライナーを試す。
  3. BCC の tools/ を読む (tcp_latency、biosnoop、execsnoop 等 100 以上)。
  4. libbpf-bootstrap の例題、vmlinux.h 生成、skeleton パターンを学ぶ。
  5. Cilium bpf/、Katran、Tetragon を読む。

書籍: "Learning eBPF" (Liz Rice)、"Linux Observability with BPF" (Calavera & Fontana)。カンファレンス: eBPF Summit、LPC BPF トラック、KubeCon。


17. 要約チートシート

eBPF Cheat Sheet
- VM: 11 regs、64-bit RISC-like、JIT、1M insn 制限
- Verifier: symbolic execution、メモリ安全性、ポインタ型付け
- Maps: Hash、ArrayLRULPM trie、Ring buffer、Per-CPU
- Program types: kprobe、tracepoint、fentry/fexit、XDPTC、cgroup_skb、LSM、sockops
- CO-RE: BTF リロケーション、単一バイナリ、全カーネル対応
- Production: Cilium、Katran、Pixie、Falco、bpftrace
- Tools: bpftool、libbpf、bcc、aya (Rust)

18. クイズ

Q1. Verifier がプログラムを拒否する最も多い理由は?

A. ポインタアクセス前の境界チェック欠如、または map lookup 結果を NULL チェックなしで逆参照。XDP では invalid access to packet, off=N size=MR1 pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL が典型。

Q2. CO-RE が解決する問題は?

A. カーネル構造体のレイアウトがバージョンで変わり、ビルド済み eBPF プログラムが別カーネルで誤ったメモリを読む問題。BTF がカーネル型情報を持ち、libbpf がロード時にフィールドオフセットをリライトして単一バイナリで複数カーネルに対応。

Q3. XDP が iptables より速い理由は?

A. iptables は sk_buff 割当後に netfilter チェーンを走査する。XDP は NIC ドライバ直後、sk_buff 割当前に実行され、JIT ネイティブコードでルール解釈もない。結果として 1 コアで数千万 pps を実現。

Q4. Per-CPU マップが通常ハッシュより速い理由は?

A. キャッシュライン競合がない。複数 CPU が同一カウンタを更新すると MESI で行がコア間を往復し性能崩壊。Per-CPU は各 CPU が自スロットのみ書く。ユーザ空間読み取り時に合計。

Q5. Cilium はどのように iptables を迂回して kube-proxy を置き換えるか?

A. sockops が connect() をフックし、BPF マップを O(1) で参照して実 backend へ DNAT。カーネルスタックは最初から backend IP で接続。同一ノード Pod は sockmap redirect で localhost 通信化しスタックも迂回。

Q6. Tail Call の欠点は?

A. スタック喪失。呼出元のローカル変数が消える。状態共有は map 経由。最大連鎖 33 段。

Q7. ユーザ空間関数にフックするには?

A. uprobe / uretprobe。Pixie は libsslSSL_read/write にフックし TLS 終端後の HTTPS 平文を観測。


本稿が役立ったら次もどうぞ:

  • 「Linux ネットワークスタック Deep Dive」
  • 「Cilium Architecture 徹底解説」
  • 「io_uring Deep Dive」
  • 「DPDK vs XDP 比較」

현재 단락 (1/376)

- **eBPF** は Linux カーネル内でサンドボックス化されたバイトコードを実行する VM である。カーネルモジュールをビルドせずにカーネル動作を観測・変更できる。

작성 글자: 0원문 글자: 14,259작성 단락: 0/376