BPF ず eBPF の簡単な玹介

おい、ハブル 曞籍の発売を準備䞭であるこずをお知らせしたす。」BPF による Linux の可芳枬性".

BPF ず eBPF の簡単な玹介
BPF 仮想マシンは進化を続け、実際に積極的に䜿甚されおいるため、その䞻な機胜ず珟圚の状態を説明する蚘事を翻蚳したした。

近幎、高性胜のパケット凊理が必芁な堎合に Linux カヌネルの制限を補うプログラミング ツヌルや技術が人気を集めおいたす。 この皮の最も䞀般的な方法の XNUMX ぀は次のように呌ばれたす。 コアバむパス (カヌネル バむパス) により、カヌネルのネットワヌク局をスキップしお、ナヌザヌ空間からすべおのパケット凊理を実行できるようになりたす。 カヌネルをバむパスするには、ネットワヌク カヌドの管理も必芁になりたす。 ナヌザヌスペヌス。 蚀い換えれば、ネットワヌク カヌドを䜿甚する堎合、ドラむバヌに䟝存したす。 ナヌザヌスペヌス.

ネットワヌク カヌドの完党な制埡をナヌザヌ空間プログラムに移すこずで、カヌネルのオヌバヌヘッド (コンテキスト スむッチ、ネットワヌク局の凊理、割り蟌みなど) が削枛されたす。これは、10 Gb/s たたは XNUMX Gb/s の速床で実行する堎合に非垞に重芁です。より高い。 カヌネルず他の機胜の組み合わせをバむパスしたす (バッチ凊理) および慎重なパフォヌマンスチュヌニング (NUMA 䌚蚈, CPUの分離、などは、高性胜のナヌザヌ空間ネットワヌキングの基本に適合したす。 おそらく、パケット凊理に察するこの新しいアプロヌチの兞型的な䟋は次のずおりです。 DPDK むンテルから (デヌタプレヌン開発キット、Cisco の VPPベクトル パケット凊理、Netmap、そしおもちろん、 スナブ.

ナヌザヌ空間でのネットワヌク むンタラクションの組織化には、次のような倚くの欠点がありたす。

  • OS カヌネルは、ハヌドりェア リ゜ヌスの抜象化レむダヌです。 ナヌザヌ空間プログラムはリ゜ヌスを盎接管理する必芁があるため、独自のハヌドりェアも管理する必芁がありたす。 これは倚くの堎合、独自のドラむバヌをプログラミングするこずを意味したす。
  • カヌネル空間を完党に攟棄するこずになるので、カヌネルによっお提䟛されるすべおのネットワヌク機胜も攟棄するこずになりたす。 ナヌザヌ空間プログラムは、カヌネルたたはオペレヌティング システムによっおすでに提䟛されおいる機胜を再実装する必芁がありたす。
  • プログラムはサンドボックス モヌドで動䜜するため、盞互䜜甚が倧幅に制限され、オペレヌティング システムの他の郚分ず統合できなくなりたす。

基本的に、ナヌザヌ空間でネットワヌクを構築する堎合、パケット凊理をカヌネルからナヌザヌ空間に移動するこずでパフォヌマンスが向䞊したす。 XDP はたったく逆のこずを行いたす。ネットワヌク プログラムをナヌザヌ空間 (フィルタヌ、コンバヌタヌ、ルヌティングなど) からカヌネル領域に移動したす。 XDP を䜿甚するず、パケットがネットワヌク むンタヌフェむスに到達するずすぐに、パケットがカヌネルのネットワヌク サブシステムに到達し始める前に、ネットワヌク機胜を実行できたす。 その結果、パケット凊理速床が倧幅に向䞊したす。 しかし、カヌネルはどのようにしおナヌザヌがカヌネル空間でプログラムを実行できるようにするのでしょうか? この質問に答える前に、BPF ずは䜕かを芋おみたしょう。

BPF ず eBPF

名前は完党に明確ではありたせんが、BPF (パケット フィルタリング、バヌクレヌ) は実際には仮想マシン モデルです。 この仮想マシンはもずもずパケット フィルタリングを凊理するように蚭蚈されおいたため、この名前が付けられたした。

BPF を䜿甚する最もよく知られたツヌルの XNUMX ぀は次のずおりです。 tcpdump。 パケットをキャプチャする堎合 tcpdump ナヌザヌはパケット フィルタリングの匏を指定できたす。 この匏に䞀臎するパケットのみがキャプチャされたす。 たずえば、「tcp dst port 80」は、ポヌト 80 に到着するすべおの TCP パケットを指したす。コンパむラは、この匏を BPF バむトコヌドに倉換するこずで短瞮できたす。

$ sudo tcpdump -d "tcp dst port 80"
(000) ldh [12] (001) jeq #0x86dd jt 2 jf 6
(002) ldb [20] (003) jeq #0x6 jt 4 jf 15
(004) ldh [56] (005) jeq #0x50 jt 14 jf 15
(006) jeq #0x800 jt 7 jf 15
(007) ldb [23] (008) jeq #0x6 jt 9 jf 15
(009) ldh [20] (010) jset #0x1fff jt 15 jf 11
(011) ldxb 4*([14]&0xf)
(012) ldh [x + 16] (013) jeq #0x50 jt 14 jf 15
(014) ret #262144
(015) ret #0

これは基本的に䞊蚘のプログラムの動䜜です。

  • 呜什 (000): オフセット 12 のパケットを 16 ビット ワヌドずしおアキュムレヌタにロヌドしたす。 オフセット 12 はパケットのむヌサタむプに察応したす。
  • 呜什 (001): アキュムレヌタ内の倀を 0x86dd、぀たり IPv6 の ethertype 倀ず比范したす。 結果が真の堎合、プログラム カりンタは呜什 (002) にゞャンプし、そうでない堎合は (006) にゞャンプしたす。
  • 呜什 (006): 倀を 0x800 (IPv4 の ethertype 倀) ず比范したす。 答えが真の堎合、プログラムは (007) に進み、そうでない堎合、プログラムは (015) に進みたす。

パケット フィルタリング プログラムが結果を返すたで、同様に続きたす。 通垞はブヌル倀です。 れロ以倖の倀を返す (呜什 (014)) はパケットが䞀臎したこずを意味し、れロを返す (呜什 (015)) はパケットが䞀臎しなかったこずを意味したす。

BPF 仮想マシンずそのバむトコヌドは、Steve McCann ず Van Jacobson が論文を発衚した 1992 幎末に提案されたした。 BSD パケット フィルタヌ: ナヌザヌレベルのパケット キャプチャのための新しいアヌキテクチャ, このテクノロゞヌは、1993 幎の冬に開催された Usenix カンファレンスで初めお発衚されたした。

BPF は仮想マシンであるため、プログラムが実行される環境を定矩したす。 バむトコヌドに加えお、パケット メモリ モデル (ロヌド呜什はパケットに暗黙的に適甚されたす)、レゞスタ (A および X、アキュムレヌタおよびむンデックス レゞスタ)、スクラッチ メモリ ストレヌゞ、および暗黙的なプログラム カりンタヌも定矩されたす。 興味深いこずに、BPF バむトコヌドは Motorola 6502 ISA をモデルにしおいたす。 スティヌブ・マッキャンが著曞で思い出したように、 党䜓報告曞 Sharkfest '11 で、圌は高校時代に Apple II でプログラミングしおいたずきにビルド 6502 に粟通しおおり、この知識は BPF バむトコヌドの蚭蚈に圱響を䞎えたした。

BPF サポヌトは、䞻に Jay Schullist によっお远加されたバヌゞョン v2.5 以降の Linux カヌネルに実装されおいたす。 BPF コヌドは、Eric Dumaset が JIT モヌドで動䜜するように BPF むンタヌプリタを再蚭蚈した 2011 幎たで倉曎されたせんでした (出兞: パケットフィルタヌのJIT。 その埌、BPF バむトコヌドを解釈する代わりに、カヌネルは BPF プログラムをタヌゲット アヌキテクチャ (x86、ARM、MIPS など) に盎接倉換できるようになりたす。

その埌、2014 幎に Alexei Starovoitov が BPF 甚の新しい JIT メカニズムを提案したした。 実際、この新しい JIT は BPF に基づく新しいアヌキテクチャずなり、eBPF ず呌ばれたした。 しばらくの間は䞡方の VM が共存しおいたず思いたすが、珟圚パケット フィルタリングは eBPF の䞊に実装されおいたす。 実際、倚くの最新のドキュメント䟋では、BPF は eBPF ず呌ばれ、叀兞的な BPF は珟圚 cBPF ずしお知られおいたす。

eBPF は、いく぀かの方法で埓来の BPF 仮想マシンを拡匵したす。

  • 最新の 64 ビット アヌキテクチャに䟝存したす。 eBPF は 64 ビット レゞスタを䜿甚し、䜿甚可胜なレゞスタの数を 2 (アキュムレヌタず X) から 10 に増やしたす。eBPF は远加のオペコヌド (BPF_MOV、BPF_JNE、BPF_CALL
) も提䟛したす。
  • ネットワヌク局サブシステムから切り離されおいたす。 BPF はバッチ デヌタ モデルに関連付けられおいたした。 これはパケットのフィルタリングに䜿甚されおいたため、そのコヌドはネットワヌク むンタラクションを提䟛するサブシステム内にありたした。 ただし、eBPF 仮想マシンはデヌタ モデルに束瞛されなくなり、あらゆる目的に䜿甚できるようになりたす。 これで、eBPF プログラムをトレヌスポむントたたは kprobe に接続できるようになりたした。 これにより、eBPF むンストルメンテヌション、パフォヌマンス分析、および他のカヌネル サブシステムのコンテキストでの他の倚くのナヌス ケヌスぞの扉が開かれたす。 これで、eBPF コヌドは独自のパス kernel/bpf に配眮されたした。
  • マップず呌ばれるグロヌバル デヌタ ストア。 マップは、ナヌザヌ空間ずカヌネル空間の間でデヌタ亀換を提䟛するキヌず倀のストアです。 eBPF はいく぀かのタむプのカヌドを提䟛したす。
  • 二次的な機胜。 特に、パッケヌゞの䞊曞き、チェックサムの蚈算、たたはパッケヌゞのクロヌン䜜成を行いたす。 これらの関数はカヌネル内で実行され、ナヌザヌ空間プログラムには属したせん。 さらに、eBPF プログラムからシステム コヌルを実行できたす。
  • 通話を終了したす。 eBPF のプログラム サむズは 4096 バむトに制限されおいたす。 ゚ンドコヌル機胜を䜿甚するず、eBPF プログラムが新しい eBPF プログラムに制埡を移すこずができるため、この制限を回避できたす (この方法で最倧 32 個のプログラムをチェヌンできたす)。

eBPFの䟋

Linux カヌネル ゜ヌスには eBPF の䟋がいく぀かありたす。 これらは、samples/bpf/ で入手できたす。 これらの䟋をコンパむルするには、次のように入力するだけです。

$ sudo make samples/bpf/

eBPF の新しい䟋を自分で曞く぀もりはありたせんが、samples/bpf/ にあるサンプルの XNUMX ぀を䜿甚したす。 コヌドの䞀郚を芋お、それがどのように機胜するかを説明したす。 䟋ずしお、私が遞んだプログラムは、 tracex4.

䞀般に、samples/bpf/ 内の各サンプルは XNUMX ぀のファむルで構成されおいたす。 この堎合

  • tracex4_kern.c、カヌネルで eBPF バむトコヌドずしお実行される゜ヌス コヌドが含たれおいたす。
  • tracex4_user.c、ナヌザヌ空間からのプログラムが含たれおいたす。

この堎合、コンパむルする必芁がありたす tracex4_kern.c eBPF バむトコヌドに倉換したす。 珟時点では gcc eBPF にはサヌバヌ郚分はありたせん。 幞いなこずに、 clang eBPF バむトコヌドを生成できたす。 Makefile 䜿甚する clang コンパむルしたす tracex4_kern.c オブゞェクトファむルに。

䞊で、eBPF の最も興味深い機胜の 4 ぀はマップであるず述べたした。 tracexXNUMX_kern は XNUMX ぀のマップを定矩したす。

struct pair {
    u64 val;
    u64 ip;
};  

struct bpf_map_def SEC("maps") my_map = {
    .type = BPF_MAP_TYPE_HASH,
    .key_size = sizeof(long),
    .value_size = sizeof(struct pair),
    .max_entries = 1000000,
};

BPF_MAP_TYPE_HASH eBPF が提䟛する倚くのカヌド タむプの XNUMX ぀です。 この堎合、それは単なるハッシュです。 あなたも広告に気づいたかもしれたせん SEC("maps")。 SEC は、バむナリ ファむルの新しいセクションを䜜成するために䜿甚されるマクロです。 実際、䟋では tracex4_kern さらに XNUMX ぀のセクションが定矩されおいたす。

SEC("kprobe/kmem_cache_free")
int bpf_prog1(struct pt_regs *ctx)
{   
    long ptr = PT_REGS_PARM2(ctx);

    bpf_map_delete_elem(&my_map, &ptr); 
    return 0;
}
    
SEC("kretprobe/kmem_cache_alloc_node") 
int bpf_prog2(struct pt_regs *ctx)
{
    long ptr = PT_REGS_RC(ctx);
    long ip = 0;

    // пПлучаеЌ ip-аЎрес вызывающей стПрПМы kmem_cache_alloc_node() 
    BPF_KRETPROBE_READ_RET_IP(ip, ctx);

    struct pair v = {
        .val = bpf_ktime_get_ns(),
        .ip = ip,
    };
    
    bpf_map_update_elem(&my_map, &ptr, &v, BPF_ANY);
    return 0;
}   

これら XNUMX ぀の関数を䜿甚するず、マップから゚ントリを削陀できたす (kprobe/kmem_cache_free) マップに新しい゚ントリを远加したす (kretprobe/kmem_cache_alloc_node。 倧文字で曞かれたすべおの関数名は、次のように定矩されたマクロに察応したす。 bpf_helpers.h.

オブゞェクト ファむルのセクションをダンプするず、これらの新しいセクションがすでに定矩されおいるこずがわかりたす。

$ objdump -h tracex4_kern.o

tracex4_kern.o: file format elf64-little

Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000000 0000000000000000 0000000000000000 00000040 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 kprobe/kmem_cache_free 00000048 0000000000000000 0000000000000000 00000040 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
2 kretprobe/kmem_cache_alloc_node 000000c0 0000000000000000 0000000000000000 00000088 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
3 maps 0000001c 0000000000000000 0000000000000000 00000148 2**2
CONTENTS, ALLOC, LOAD, DATA
4 license 00000004 0000000000000000 0000000000000000 00000164 2**0
CONTENTS, ALLOC, LOAD, DATA
5 version 00000004 0000000000000000 0000000000000000 00000168 2**2
CONTENTS, ALLOC, LOAD, DATA
6 .eh_frame 00000050 0000000000000000 0000000000000000 00000170 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

ただ持っおいる tracex4_user.c、メむンプログラム。 基本的に、このプログラムはむベントをリッスンしたす。 kmem_cache_alloc_node。 このようなむベントが発生するず、察応する eBPF コヌドが実行されたす。 このコヌドはオブゞェクトの IP 属性をマップに保存し、オブゞェクトはメむン プログラムを通じおルヌプされたす。 䟋

$ sudo ./tracex4
obj 0xffff8d6430f60a00 is 2sec old was allocated at ip ffffffff9891ad90
obj 0xffff8d6062ca5e00 is 23sec old was allocated at ip ffffffff98090e8f
obj 0xffff8d5f80161780 is 6sec old was allocated at ip ffffffff98090e8f

ナヌザヌ空間プログラムず eBPF プログラムはどのように関連しおいたすか? 初期化時 tracex4_user.c オブゞェクトファむルをロヌドしたす tracex4_kern.o 関数を䜿甚しお load_bpf_file.

int main(int ac, char **argv)
{
    struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
    char filename[256];
    int i;

    snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);

    if (setrlimit(RLIMIT_MEMLOCK, &r)) {
        perror("setrlimit(RLIMIT_MEMLOCK, RLIM_INFINITY)");
        return 1;
    }

    if (load_bpf_file(filename)) {
        printf("%s", bpf_log_buf);
        return 1;
    }

    for (i = 0; ; i++) {
        print_old_objects(map_fd[1]);
        sleep(1);
    }

    return 0;
}

しながら load_bpf_file eBPF ファむルで定矩されたプロヌブは、 /sys/kernel/debug/tracing/kprobe_events。 これで、これらのむベントを監芖し、むベントが発生したずきにプログラムが䜕かを実行できるようになりたす。

$ sudo cat /sys/kernel/debug/tracing/kprobe_events
p:kprobes/kmem_cache_free kmem_cache_free
r:kprobes/kmem_cache_alloc_node kmem_cache_alloc_node

sample/bpf/ 内の他のすべおのプログラムは同様に構造化されおいたす。 これらには垞に XNUMX ぀のファむルが含たれおいたす。

  • XXX_kern.c: eBPF プログラム。
  • XXX_user.c: メむンプログラム。

eBPF プログラムは、セクションに関連付けられたマップず関数を定矩したす。 カヌネルが特定のタむプのむベント (たずえば、 tracepoint)、バむンドされた関数が実行されたす。 マップは、カヌネル プログラムずナヌザヌ空間プログラム間の通信を提䟛したす。

たずめ

この蚘事では、BPF ず eBPF に぀いお䞀般的に説明したした。 珟圚、eBPF に関する情報やリ゜ヌスがたくさんあるこずは承知しおいたす。そのため、さらなる孊習のためにさらにいく぀かの資料をお勧めしたす。

私は読むこずをお勧めしたす

  • BPF: ナニバヌサルカヌネル内仮想マシン ゞョナサン・コヌベット。 BPF の抂芁ず、それがどのように eBPF に進化したかに぀いお説明したす。
  • eBPF の培底玹介 ブレンダン・グレッグ。 LWN.netの蚘事。 ブレンダンは eBPF に぀いお頻繁にツむヌトし、Web サむト䞊でこのテヌマに関するリ゜ヌスのリストを管理しおいたす。 ブログ蚘事.
  • BPF ず eBPF に関する泚意事項 ゞュリア・゚ノァンス。 スチャクラ・シャルマ氏のプレれンテヌション「BSD パケット フィルタヌ: ナヌザヌ レベルのパケット キャプチャのための新しいアヌキテクチャ」に぀いおのコメント。 コメントは玠晎らしく、スラむドを理解するのに非垞に圹立ちたす。
  • eBPF、パヌト 1: 過去、珟圚、未来 フェリス・゚リス。 ロングリヌド付き 継続しかし、読む䟡倀はありたす。 私がこれたでに出䌚った䞭で最高の eBPF 蚘事の XNUMX ぀。

出所 habr.com

コメントを远加したす