BPF для самых ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ…, Ρ‡Π°ΡΡ‚ΡŒ пСрвая: extended BPF

Π’ Π½Π°Ρ‡Π°Π»Π΅ Π±Ρ‹Π»Π° тСхнология ΠΈ Π½Π°Π·Ρ‹Π²Π°Π»Π°ΡΡŒ ΠΎΠ½Π° BPF. ΠœΡ‹ посмотрСли Π½Π° Π½Π΅Π΅ Π² ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ, Π²Π΅Ρ‚Ρ…ΠΎΠ·Π°Π²Π΅Ρ‚Π½ΠΎΠΉ, ΡΡ‚Π°Ρ‚ΡŒΠ΅ этого Ρ†ΠΈΠΊΠ»Π°. Π’ 2013 Π³ΠΎΠ΄Ρƒ усилиями АлСксСя Π‘Ρ‚Π°Ρ€ΠΎΠ²ΠΎΠΉΡ‚ΠΎΠ²Π° (Alexei Starovoitov) ΠΈ Даниэля Π‘ΠΎΡ€ΠΊΠΌΠ°Π½Π° (Daniel Borkman) Π±Ρ‹Π»Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½Π° ΠΈ Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Π° Π² ядро Linux Π΅Π΅ ΡƒΡΠΎΠ²Π΅Ρ€ΡˆΠ΅Π½ΡΡ‚Π²ΠΎΠ²Π°Π½Π½Π°Ρ вСрсия, оптимизированная ΠΏΠΎΠ΄ соврСмСнныС 64-Π±ΠΈΡ‚Π½Ρ‹Π΅ ΠΌΠ°ΡˆΠΈΠ½Ρ‹. Π­Ρ‚Π° новая тСхнология Π½Π΅Π΄ΠΎΠ»Π³ΠΎΠ΅ врСмя носила Π½Π°Π·Π²Π°Π½ΠΈΠ΅ Internal BPF, Π·Π°Ρ‚Π΅ΠΌ Π±Ρ‹Π»Π° ΠΏΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½Π° Π² Extended BPF, Π° Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ, ΠΏΠΎ ΠΏΡ€ΠΎΡˆΠ΅ΡΡ‚Π²ΠΈΠΈ Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… Π»Π΅Ρ‚, всС Π΅Π΅ Π½Π°Π·Ρ‹Π²Π°ΡŽΡ‚ просто BPF.

Π“Ρ€ΡƒΠ±ΠΎ говоря, BPF позволяСт Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½Ρ‹ΠΉ ΠΊΠΎΠ΄, прСдоставляСмый ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΌ, Π² пространствС ядра Linux ΠΈ новая Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° оказалась Π½Π°ΡΡ‚ΠΎΠ»ΡŒΠΊΠΎ ΡƒΠ΄Π°Ρ‡Π½ΠΎΠΉ, Ρ‡Ρ‚ΠΎ Π½Π°ΠΌ потрСбуСтся Π΅Ρ‰Π΅ с дСсяток статСй, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ всС Π΅Π΅ примСнСния. (ЕдинствСнноС с Ρ‡Π΅ΠΌ Π½Π΅ ΡΠΏΡ€Π°Π²ΠΈΠ»ΠΈΡΡŒ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ, ΠΊΠ°ΠΊ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ Π½Π° ΠΊΠΏΠ΄Π² Π½ΠΈΠΆΠ΅, это с созданиСм ΠΏΡ€ΠΈΠ»ΠΈΡ‡Π½ΠΎΠ³ΠΎ Π»ΠΎΠ³ΠΎΡ‚ΠΈΠΏΠ°.)

Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ описываСтся строСниС Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠΉ ΠΌΠ°ΡˆΠΈΠ½Ρ‹ BPF, интСрфСйсы ядра для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с BPF, срСдства Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΊΡ€Π°Ρ‚ΠΊΠΈΠΉ, ΠΎΡ‡Π΅Π½ΡŒ ΠΊΡ€Π°Ρ‚ΠΊΠΈΠΉ, ΠΎΠ±Π·ΠΎΡ€ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΡ… возмоТностСй, Ρ‚.Π΅. всё Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ Π½Π°ΠΌ потрСбуСтся Π² дальнСйшСм для Π±ΠΎΠ»Π΅Π΅ Π³Π»ΡƒΠ±ΠΎΠΊΠΎΠ³ΠΎ изучСния практичСских ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠΉ BPF.
BPF для самых ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ…, Ρ‡Π°ΡΡ‚ΡŒ пСрвая: extended BPF

ΠšΡ€Π°Ρ‚ΠΊΠΎΠ΅ содСрТаниС ΡΡ‚Π°Ρ‚ΡŒΠΈ

Π’Π²Π΅Π΄Π΅Π½ΠΈΠ΅ Π² Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρƒ BPF. Π’Π½Π°Ρ‡Π°Π»Π΅ ΠΌΡ‹ посмотрим Π½Π° Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρƒ BPF с высоты ΠΏΡ‚ΠΈΡ‡ΡŒΠ΅Π³ΠΎ ΠΏΠΎΠ»Π΅Ρ‚Π° ΠΈ ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡ΠΈΠΌ основныС ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹.

РСгистры ΠΈ систСма ΠΊΠΎΠΌΠ°Π½Π΄ Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠΉ ΠΌΠ°ΡˆΠΈΠ½Ρ‹ BPF. Π£ΠΆΠ΅ имСя прСдставлСниС ΠΎΠ± Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅ Π² Ρ†Π΅Π»ΠΎΠΌ, ΠΌΡ‹ опишСм строСниС Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠΉ ΠΌΠ°ΡˆΠΈΠ½Ρ‹ BPF.

Π–ΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ» ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² BPF, файловая систСма bpffs. Π’ этом Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΌΡ‹ Π±ΠΎΠ»Π΅Π΅ ΠΏΡ€ΠΈΡΡ‚Π°Π»ΡŒΠ½ΠΎ посмотрим Π½Π° ΠΆΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ» ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² BPF β€” ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ ΠΈ ΠΌΠ°ΠΏΠΎΠ².

Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌΠΈ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf. ИмСя ΡƒΠΆΠ΅ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ прСдставлСниС ΠΎ систСмС ΠΌΡ‹, Π½Π°ΠΊΠΎΠ½Π΅Ρ†, посмотрим Π½Π° Ρ‚ΠΎ, ΠΊΠ°ΠΊ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΈ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌΠΈ ΠΈΠ· пространства ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ систСмного Π²Ρ‹Π·ΠΎΠ²Π° β€” bpf(2).

ПишСм ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ libbpf. ΠŸΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ систСмного Π²Ρ‹Π·ΠΎΠ²Π°, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, ΠΌΠΎΠΆΠ½ΠΎ. Но слоТно. Для Π±ΠΎΠ»Π΅Π΅ рСалистичного сцСнария ядСрными программистами Π±Ρ‹Π»Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½Π° Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° libbpf. ΠœΡ‹ создадим ΠΏΡ€ΠΎΡΡ‚Π΅ΠΉΡˆΠΈΠΉ скСлСт прилоТСния BPF, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π² ΠΏΠΎΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°Ρ….

Kernel Helpers. Π—Π΄Π΅ΡΡŒ ΠΌΡ‹ ΡƒΠ·Π½Π°Π΅ΠΌ ΠΊΠ°ΠΊ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΌΠΎΠ³ΡƒΡ‚ ΠΎΠ±Ρ€Π°Ρ‰Π°Ρ‚ΡŒΡΡ ΠΊ функциям-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ°ΠΌ ядра — инструмСнту, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ, наряду с ΠΌΠ°ΠΏΠ°ΠΌΠΈ, ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΈΠ°Π»ΡŒΠ½ΠΎ Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅Ρ‚ возмоТности Π½ΠΎΠ²ΠΎΠ³ΠΎ BPF ΠΏΠΎ ΡΡ€Π°Π²Π½Π΅Π½ΠΈΡŽ с классичСским.

Доступ ΠΊ maps ΠΈΠ· ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF. К этому ΠΌΠΎΠΌΠ΅Π½Ρ‚Ρƒ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π·Π½Π°Ρ‚ΡŒ достаточно, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ½ΡΡ‚ΡŒ ΠΊΠ°ΠΊ ΠΈΠΌΠ΅Π½Π½ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΠ΅ ΠΌΠ°ΠΏΡ‹. И Π΄Π°ΠΆΠ΅ ΠΎΠ΄Π½ΠΈΠΌ Π³Π»Π°Π·ΠΊΠΎΠΌ заглянСм Π² Π²Π΅Π»ΠΈΠΊΠΈΠΉ ΠΈ ΠΌΠΎΠ³ΡƒΡ‡ΠΈΠΉ verifier.

БрСдства Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ. Π‘ΠΏΡ€Π°Π²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ€Π°Π·Π΄Π΅Π» ΠΎ Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ Ρ‚Ρ€Π΅Π±ΡƒΠ΅ΠΌΡ‹Π΅ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ ΠΈ ядро для экспСримСнтов.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅. Π’ ΠΊΠΎΠ½Ρ†Π΅ ΡΡ‚Π°Ρ‚ΡŒΠΈ Ρ‚Π΅, ΠΊΡ‚ΠΎ Π΄ΠΎΡ‚ΡƒΠ΄Π° Π΄ΠΎΡ‡ΠΈΡ‚Π°Π΅Ρ‚, Π½Π°ΠΉΠ΄ΡƒΡ‚ ΠΌΠΎΡ‚ΠΈΠ²ΠΈΡ€ΡƒΡŽΡ‰ΠΈΠ΅ слова ΠΈ ΠΊΡ€Π°Ρ‚ΠΊΠΎΠ΅ описаниС Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… ΡΡ‚Π°Ρ‚ΡŒΡΡ…. ΠœΡ‹ Ρ‚Π°ΠΊΠΆΠ΅ пСрСчислим Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ количСство ссылок для ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ изучСния для Ρ‚Π΅Ρ…, Ρƒ ΠΊΠΎΠ³ΠΎ Π½Π΅Ρ‚ ТСлания ΠΈΠ»ΠΈ возмоТности ΠΆΠ΄Π°Ρ‚ΡŒ продолТСния.

Π’Π²Π΅Π΄Π΅Π½ΠΈΠ΅ Π² Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρƒ BPF

ΠŸΠ΅Ρ€Π΅Π΄ Ρ‚Π΅ΠΌ ΠΊΠ°ΠΊ Π½Π°Ρ‡Π°Ρ‚ΡŒ Ρ€Π°ΡΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρƒ BPF ΠΌΡ‹ Π² послСдний Ρ€Π°Π· (ΠΎΠΉ Π»ΠΈ) сошлСмся Π½Π° классичСский BPF, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±Ρ‹Π» Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½ ΠΊΠ°ΠΊ ΠΎΡ‚Π²Π΅Ρ‚ Π½Π° появлСниС RISC машин ΠΈ Ρ€Π΅ΡˆΠ°Π» ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ эффСктивной Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ². АрхитСктура ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»Π°ΡΡŒ Π½Π°ΡΡ‚ΠΎΠ»ΡŒΠΊΠΎ ΡƒΠ΄Π°Ρ‡Π½ΠΎΠΉ, Ρ‡Ρ‚ΠΎ, Ρ€ΠΎΠ΄ΠΈΠ²ΡˆΠΈΡΡŒ Π² Π»ΠΈΡ…ΠΈΠ΅ дСвяностыС Π² Berkeley UNIX, ΠΎΠ½Π° Π±Ρ‹Π»Π° ΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π° Π½Π° Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²ΠΎ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΡ… ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Ρ… систСм, Π΄ΠΎΠΆΠΈΠ»Π° Π΄ΠΎ Π±Π΅Π·ΡƒΠΌΠ½Ρ‹Ρ… Π΄Π²Π°Π΄Ρ†Π°Ρ‚Ρ‹Ρ… ΠΈ Π΄ΠΎ сих ΠΏΠΎΡ€ Π½Π°Ρ…ΠΎΠ΄ΠΈΡ‚ Π½ΠΎΠ²Ρ‹Π΅ примСнСния.

Новый BPF Π±Ρ‹Π» Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½ ΠΊΠ°ΠΊ ΠΎΡ‚Π²Π΅Ρ‚ Π½Π° повсСмСстноС распространСниС 64-Π±ΠΈΡ‚Π½Ρ‹Ρ… машин, ΠΎΠ±Π»Π°Ρ‡Π½Ρ‹Ρ… сСрвисов ΠΈ Π²ΠΎΠ·Ρ€ΠΎΡΡˆΠΈΡ… потрСбностСй Π² инструмСнтах для создания SDN (Software-defined networking). Π Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½Π½Ρ‹ΠΉ сСтСвыми ΠΈΠ½ΠΆΠ΅Π½Π΅Ρ€Π°ΠΌΠΈ ядра ΠΊΠ°ΠΊ ΡƒΡΠΎΠ²Π΅Ρ€ΡˆΠ΅Π½ΡΡ‚Π²ΠΎΠ²Π°Π½Π½Π°Ρ Π·Π°ΠΌΠ΅Π½Π° классичСского BPF, Π½ΠΎΠ²Ρ‹ΠΉ BPF Π±ΡƒΠΊΠ²Π°Π»ΡŒΠ½ΠΎ Ρ‡Π΅Ρ€Π΅Π· ΠΏΠΎΠ»Π³ΠΎΠ΄Π° нашСл примСнСния Π² Π½Π΅Π»Π΅Π³ΠΊΠΎΠΌ Π΄Π΅Π»Π΅ трассировки Linux систСм, Π° сСйчас, Ρ‡Π΅Ρ€Π΅Π· ΡˆΠ΅ΡΡ‚ΡŒ Π»Π΅Ρ‚ послС появлСния, Π½Π°ΠΌ потрСбуСтся цСлая, ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π°Ρ, ΡΡ‚Π°Ρ‚ΡŒΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠ΅Ρ€Π΅Ρ‡ΠΈΡΠ»ΠΈΡ‚ΡŒ Ρ€Π°Π·Π½Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ.

Π’Π΅Π‘Ρ‘Π›Ρ‹Π• ΠšΠ°Π Ρ‚Π˜Π½ΠšΠΈ

Π’ своСй основС BPF β€” это Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½Π°Ρ машина-пСсочница, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰Π°Ρ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Β«ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½Ρ‹ΠΉΒ» ΠΊΠΎΠ΄ Π² пространствС ядра Π±Π΅Π· ΡƒΡ‰Π΅Ρ€Π±Π° для бСзопасности. ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ Π² пространствС ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ, Π·Π°Π³Ρ€ΡƒΠΆΠ°ΡŽΡ‚ΡΡ Π² ядро ΠΈ ΠΏΠΎΠ΄ΡΠΎΠ΅Π΄ΠΈΠ½ΡΡŽΡ‚ΡΡ ΠΊ ΠΊΠ°ΠΊΠΎΠΌΡƒ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ источнику событий. Π‘ΠΎΠ±Ρ‹Ρ‚ΠΈΠ΅ΠΌ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, доставка ΠΏΠ°ΠΊΠ΅Ρ‚Π° Π½Π° сСтСвой интСрфСйс, запуск ΠΊΠ°ΠΊΠΎΠΉ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ядра, ΠΈ Ρ‚.ΠΏ. Π’ случаС ΠΏΠ°ΠΊΠ΅Ρ‚Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ BPF Π±ΡƒΠ΄ΡƒΡ‚ доступны Π΄Π°Π½Π½Ρ‹Π΅ ΠΈ ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΠ°ΠΊΠ΅Ρ‚Π° (Π½Π° Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ ΠΈ, ΠΌΠΎΠΆΠ΅Ρ‚, Π½Π° запись, Π² зависимости ΠΎΡ‚ Ρ‚ΠΈΠΏΠ° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹), Π² случаС запуска Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ядра β€” Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π²ΠΊΠ»ΡŽΡ‡Π°Ρ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π½Π° ΠΏΠ°ΠΌΡΡ‚ΡŒ ядра, ΠΈ Ρ‚.ΠΏ.

Π”Π°Π²Π°ΠΉΡ‚Π΅ посмотрим Π½Π° этот процСсс ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅. Для Π½Π°Ρ‡Π°Π»Π° расскаТСм ΠΏΡ€ΠΎ ΠΏΠ΅Ρ€Π²ΠΎΠ΅ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ классичСского BPF, ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ для ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ писались Π½Π° ассСмблСрС. Π’ Π½ΠΎΠ²ΠΎΠΉ вСрсии Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° Π±Ρ‹Π»Π° Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½Π° Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ стало ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π½Π° языках высокого уровня, Π² ΠΏΠ΅Ρ€Π²ΡƒΡŽ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, Π½Π° C. Для этого Π±Ρ‹Π» Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½ Π±Π°ΠΊΠ΅Π½Π΄ для llvm, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π±Π°ΠΉΡ‚-ΠΊΠΎΠ΄ для Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹ BPF.

BPF для самых ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ…, Ρ‡Π°ΡΡ‚ΡŒ пСрвая: extended BPF

АрхитСктура BPF Ρ€Π°Π·Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π»Π°ΡΡŒ, Π² частности, для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ эффСктивно Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ Π½Π° соврСмСнных ΠΌΠ°ΡˆΠΈΠ½Π°Ρ…. Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ это Ρ€Π°Π±ΠΎΡ‚Π°Π»ΠΎ Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅, Π±Π°ΠΉΡ‚-ΠΊΠΎΠ΄ BPF, послС Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Π² ядро транслируСтся Π² Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° ΠΏΠΎΠ΄ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ JIT compiler (Just In Time). Π”Π°Π»Π΅Π΅, Ссли Π²Ρ‹ ΠΏΠΎΠΌΠ½ΠΈΡ‚Π΅, Π² классичСском BPF ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Π·Π°Π³Ρ€ΡƒΠΆΠ°Π»Π°ΡΡŒ Π² ядро ΠΈ ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΡΠ»Π°ΡΡŒ ΠΊ источнику событий Π°Ρ‚ΠΎΠΌΠ°Ρ€Π½ΠΎ β€” Π² контСкстС ΠΎΠ΄Π½ΠΎΠ³ΠΎ систСмного Π²Ρ‹Π·ΠΎΠ²Π°. Π’ Π½ΠΎΠ²ΠΎΠΉ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅ это происходит Π² Π΄Π²Π° этапа β€” сначала ΠΊΠΎΠ΄ загруТаСтся Π² ядро ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf(2), Π° Π·Π°Ρ‚Π΅ΠΌ, ΠΏΠΎΠ·Π΄Π½Π΅Π΅, ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΠΎΠ², Ρ€Π°Π·Π½Ρ‹Ρ… Π² зависимости ΠΎΡ‚ Ρ‚ΠΈΠΏΠ° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° подсоСдиняСтся (attaches) ΠΊ источнику событий.

Π’ΡƒΡ‚ Ρƒ читатСля ΠΌΠΎΠΆΠ΅Ρ‚ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΡƒΡ‚ΡŒ вопрос: Π° Ρ‡Ρ‚ΠΎ, Ρ‚Π°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ? Каким ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ гарантируСтся Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ выполнСния Ρ‚Π°ΠΊΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°? Π‘Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ выполнСния гарантируСтся Π½Π°ΠΌ этапом Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF ΠΏΠΎΠ΄ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ Π²Π΅Ρ€ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ (ΠΏΠΎ-английски этот этап называСтся verifier ΠΈ я дальшС Π±ΡƒΠ΄Ρƒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ английскоС слово):

BPF для самых ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ…, Ρ‡Π°ΡΡ‚ΡŒ пСрвая: extended BPF

Verifier β€” это статичСский Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Π½Π΅ Π½Π°Ρ€ΡƒΡˆΠΈΡ‚ Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ…ΠΎΠ΄ Ρ€Π°Π±ΠΎΡ‚Ρ‹ ядра. Π­Ρ‚ΠΎ, кстати, Π½Π΅ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π²ΠΌΠ΅ΡˆΠ°Ρ‚ΡŒΡΡ Π² Ρ€Π°Π±ΠΎΡ‚Ρƒ систСмы β€” ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF, Π² зависимости ΠΎΡ‚ Ρ‚ΠΈΠΏΠ°, ΠΌΠΎΠ³ΡƒΡ‚ Ρ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΈ ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ участки памяти ядра, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Π΅ значСния Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, ΠΎΠ±Ρ€Π΅Π·Π°Ρ‚ΡŒ, Π΄ΠΎΠΏΠΎΠ»Π½ΡΡ‚ΡŒ, ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ ΠΈ Π΄Π°ΠΆΠ΅ ΠΏΠ΅Ρ€Π΅ΡΡ‹Π»Π°Ρ‚ΡŒ сСтСвыС ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹. Verifier Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΎΡ‚ запуска ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ядро Π½Π΅ свалится ΠΈ Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΏΠΎ ΠΏΡ€Π°Π²ΠΈΠ»Π°ΠΌ доступны Π½Π° запись, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π΄Π°Π½Π½Ρ‹Π΅ исходящСго ΠΏΠ°ΠΊΠ΅Ρ‚Π°, Π½Π΅ смоТСт ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΠ°ΠΌΡΡ‚ΡŒ ядра Π²Π½Π΅ ΠΏΠ°ΠΊΠ΅Ρ‚Π°. Π§ΡƒΡ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ ΠΌΡ‹ посмотрим Π½Π° verifier Π² ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΌ Ρ€Π°Π·Π΄Π΅Π»Π΅, послС Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ познакомимся со всСми ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹ΠΌΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ BPF.

Π˜Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΡƒΠ·Π½Π°Π»ΠΈ ΠΊ этому ΠΌΠΎΠΌΠ΅Π½Ρ‚Ρƒ? ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ ΠΏΠΈΡˆΠ΅Ρ‚ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ Π½Π° языкС C, Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ Π΅Π΅ Π² ядро ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf(2), Π³Π΄Π΅ ΠΎΠ½Π° ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΡƒ Π½Π° verifier ΠΈ транслируСтся Π² Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ Π±Π°ΠΉΡ‚ΠΊΠΎΠ΄. Π—Π°Ρ‚Π΅ΠΌ Ρ‚ΠΎΡ‚ ΠΆΠ΅ ΠΈΠ»ΠΈ Π΄Ρ€ΡƒΠ³ΠΎΠΉ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ подсоСдиняСт ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΊ источнику событий ΠΈ ΠΎΠ½Π° Π½Π°Ρ‡ΠΈΠ½Π°Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ. Π Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΈ подсоСдинСния Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎ нСскольким ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π°ΠΌ. Π’ΠΎ-ΠΏΠ΅Ρ€Π²Ρ‹Ρ…, запуск verifier β€” это ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π΄ΠΎΡ€ΠΎΠ³ΠΎ ΠΈ, загруТая ΠΎΠ΄Π½Ρƒ ΠΈ Ρ‚Ρƒ ΠΆΠ΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ нСсколько Ρ€Π°Π·, ΠΌΡ‹ Ρ‚Ρ€Π°Ρ‚ΠΈΠΌ ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π½ΠΎΠ΅ врСмя Π²ΠΏΡƒΡΡ‚ΡƒΡŽ. Π’ΠΎ-Π²Ρ‚ΠΎΡ€Ρ‹Ρ…, Ρ‚ΠΎ, ΠΊΠ°ΠΊ ΠΈΠΌΠ΅Π½Π½ΠΎ подсоСдиняСтся ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°, зависит ΠΎΡ‚ Π΅Π΅ Ρ‚ΠΈΠΏΠ° ΠΈ ΠΎΠ΄ΠΈΠ½ Β«ΡƒΠ½ΠΈΠ²Π΅Ρ€ΡΠ°Π»ΡŒΠ½Ρ‹ΠΉΒ» интСрфСйс, Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½Π½Ρ‹ΠΉ Π³ΠΎΠ΄ Π½Π°Π·Π°Π΄ ΠΌΠΎΠΆΠ΅Ρ‚ Π½Π΅ ΠΏΠΎΠ΄ΠΎΠΉΡ‚ΠΈ для Π½ΠΎΠ²Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ. (Π₯отя сСйчас, ΠΊΠΎΠ³Π΄Π° Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° становится Π±ΠΎΠ»Π΅Π΅ Π·Ρ€Π΅Π»ΠΎΠΉ, Π΅ΡΡ‚ΡŒ идСя ΡƒΠ½ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ этот интСрфСйс Π½Π° ΡƒΡ€ΠΎΠ²Π½Π΅ libbpf.)

Π’Π½ΠΈΠΌΠ°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ Ρ‡ΠΈΡ‚Π°Ρ‚Π΅Π»ΡŒ ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ Π΅Ρ‰Π΅ Π½Π΅ Π·Π°ΠΊΠΎΠ½Ρ‡ΠΈΠ»ΠΈ с ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ°ΠΌΠΈ. И ΠΏΡ€Π°Π²Π΄Π°, всС сказанноС Π²Ρ‹ΡˆΠ΅ Π½Π΅ ΠΎΠ±ΡŠΡΡΠ½ΡΠ΅Ρ‚, Ρ‡Π΅ΠΌ BPF ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΈΠ°Π»ΡŒΠ½ΠΎ мСняСт ΠΊΠ°Ρ€Ρ‚ΠΈΠ½Ρƒ ΠΏΠΎ ΡΡ€Π°Π²Π½Π΅Π½ΠΈΡŽ с классичСским BPF. Π”Π²Π° Π½ΠΎΠ²ΡˆΠ΅ΡΡ‚Π²Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ сущСствСнно Ρ€Π°ΡΡˆΠΈΡ€ΡΡŽΡ‚ Π³Ρ€Π°Π½ΠΈΡ†Ρ‹ примСнимости β€” это Π½Π°Π»ΠΈΡ‡ΠΈΠ΅ возмоТности ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π°Π·Π΄Π΅Π»ΡΠ΅ΠΌΡƒΡŽ ΠΏΠ°ΠΌΡΡ‚ΡŒ ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠΈ ядра (kernel helpers). Π’ BPF раздСляСмая ΠΏΠ°ΠΌΡΡ‚ΡŒ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π° ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ Ρ‚Π°ΠΊ Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΡ‹Ρ… maps β€” раздСляСмых структур Π΄Π°Π½Π½Ρ‹Ρ… с ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹ΠΌ API. Π’Π°ΠΊΠΎΠ΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΎΠ½ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ, Π½Π°Π²Π΅Ρ€Π½ΠΎΠ΅, ΠΏΠΎΡ‚ΠΎΠΌΡƒ, Ρ‡Ρ‚ΠΎ ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ появившимся Ρ‚ΠΈΠΏΠΎΠΌ map Π±Ρ‹Π»Π° Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Π°. Π”Π°Π»ΡŒΡˆΠ΅ появились массивы, Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Π΅ (per-CPU) Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΠΈ Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Π΅ массивы, Π΄Π΅Ρ€Π΅Π²ΡŒΡ поиска, ΠΌΠ°ΠΏΡ‹, содСрТащиС ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΈ ΠΌΠ½ΠΎΠ³ΠΎΠ΅ Π΄Ρ€ΡƒΠ³ΠΎΠ΅. Нам сСйчас интСрСсСн Ρ‚ΠΎΡ‚ Ρ„Π°ΠΊΡ‚, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΡΠΎΡ…Ρ€Π°Π½ΡΡ‚ΡŒ состояниС ΠΌΠ΅ΠΆΠ΄Ρƒ Π²Ρ‹Π·ΠΎΠ²Π°ΠΌΠΈ ΠΈ Ρ€Π°Π·Π΄Π΅Π»ΡΡ‚ΡŒ Π΅Π³ΠΎ с Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°ΠΌΠΈ ΠΈ с пространством ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ.

Доступ ΠΊ maps осущСствляСтся ΠΈΠ· ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΡ… процСссов ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf(2), Π° ΠΈΠ· ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF, Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‰ΠΈΡ… Π² ядрС β€” ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠΎΠ². Π‘ΠΎΠ»Π΅Π΅ Ρ‚ΠΎΠ³ΠΎ, helpers ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‚ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΌΠ°ΠΏΠ°ΠΌΠΈ, Π½ΠΎ ΠΈ для доступа ΠΊ Π΄Ρ€ΡƒΠ³ΠΈΠΌ возмоТностям ядра. НапримСр, ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΌΠΎΠ³ΡƒΡ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠΈ для пСрСнаправлСния ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ² Π½Π° Π΄Ρ€ΡƒΠ³ΠΈΠ΅ интСрфСйсы, для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ событий подсистСмы perf, доступа ΠΊ структурам ядра ΠΈ Ρ‚.ΠΏ.

BPF для самых ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ…, Ρ‡Π°ΡΡ‚ΡŒ пСрвая: extended BPF

Π˜Ρ‚ΠΎΠ³ΠΎ, BPF прСдоставляСт Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½Ρ‹ΠΉ, Ρ‚.Π΅., ΠΏΡ€ΠΎΡˆΠ΅Π΄ΡˆΠΈΠΉ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΡƒ Π½Π° verifier, ΠΊΠΎΠ΄ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π² пространство ядра. Π­Ρ‚ΠΎΡ‚ ΠΊΠΎΠ΄ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠΎΡ…Ρ€Π°Π½ΡΡ‚ΡŒ состояниС ΠΌΠ΅ΠΆΠ΄Ρƒ Π²Ρ‹Π·ΠΎΠ²Π°ΠΌΠΈ ΠΈ ΠΎΠ±ΠΌΠ΅Π½ΠΈΠ²Π°Ρ‚ΡŒΡΡ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ с пространством ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΈΠΌΠ΅Π΅Ρ‚ доступ ΠΊ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½Π½Ρ‹ΠΌ Π΄Π°Π½Π½ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ подсистСмам ядра.

Π­Ρ‚ΠΎ ΡƒΠΆΠ΅ ΠΏΠΎΡ…ΠΎΠΆΠ΅ Π½Π° возмоТности, прСдоставляСмыС модулями ядра, ΠΏΠΎ ΡΡ€Π°Π²Π½Π΅Π½ΠΈΡŽ с ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ Ρƒ BPF Π΅ΡΡ‚ΡŒ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ прСимущСства (ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, ΡΡ€Π°Π²Π½ΠΈΠ²Π°Ρ‚ΡŒ ΠΌΠΎΠΆΠ½ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎΡ…ΠΎΠΆΠΈΠ΅ прилоТСния, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, трассировку систСмы β€” Π½Π° BPF нСльзя Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½Ρ‹ΠΉ Π΄Ρ€Π°ΠΉΠ²Π΅Ρ€). МоТно ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ Π½ΠΈΠ·ΠΊΠΈΠΉ ΠΏΠΎΡ€ΠΎΠ³ Π²Ρ…ΠΎΠ΄Π° (Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΠ΅ BPF Π½Π΅ ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»Π°Π³Π°ΡŽΡ‚ Ρƒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π½Π°Π»ΠΈΡ‡ΠΈΠ΅ Π½Π°Π²Ρ‹ΠΊΠΎΠ² программирования ядра, Π΄Π° ΠΈ Π²ΠΎΠΎΠ±Ρ‰Π΅ Π½Π°Π²Ρ‹ΠΊΠΎΠ² программирования), Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ выполнСния (ΠΏΠΎΠ΄Π½ΠΈΠΌΠΈΡ‚Π΅ Ρ€ΡƒΠΊΡƒ Π² коммСнтариях Ρ‚Π΅, ΠΊΡ‚ΠΎ Π½Π΅ Π»ΠΎΠΌΠ°Π» систСму ΠΏΡ€ΠΈ написании ΠΈΠ»ΠΈ тСстировании ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ), Π°Ρ‚ΠΎΠΌΠ°Ρ€Π½ΠΎΡΡ‚ΡŒ β€” ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ΅ ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ Π΅ΡΡ‚ΡŒ врСмя простоя, Π° подсистСма BPF Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ Π½ΠΈ ΠΎΠ΄Π½ΠΎ событиС Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠΏΡƒΡ‰Π΅Π½ΠΎ (справСдливости Ρ€Π°Π΄ΠΈ, это Π²Π΅Ρ€Π½ΠΎ Π½Π΅ для всСх Ρ‚ΠΈΠΏΠΎΠ² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF).

НаличиС Ρ‚Π°ΠΊΠΈΡ… возмоТностСй ΠΈ Π΄Π΅Π»Π°Π΅Ρ‚ BPF ΡƒΠ½ΠΈΠ²Π΅Ρ€ΡΠ°Π»ΡŒΠ½Ρ‹ΠΌ инструмСнтом для Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ ядра, Ρ‡Ρ‚ΠΎ подтвСрТдаСтся Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅: всС Π½ΠΎΠ²Ρ‹Π΅ ΠΈ Π½ΠΎΠ²Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ΡΡ Π² BPF, всС большС ΠΊΡ€ΡƒΠΏΠ½Ρ‹Ρ… ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ BPF Π½Π° Π±ΠΎΠ΅Π²Ρ‹Ρ… сСрвСрах 24×7, всС большС стартапов строят свой бизнСс Π½Π° Ρ€Π΅ΡˆΠ΅Π½ΠΈΡΡ…, Π² основС ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π»Π΅ΠΆΠΈΡ‚ BPF. BPF ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π²Π΅Π·Π΄Π΅: Π² Π·Π°Ρ‰ΠΈΡ‚Π΅ ΠΎΡ‚ DDoS Π°Ρ‚Π°ΠΊ, создании SDN (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ сСтСй для kubernetes), Π² качСствС основного инструмСнта трассировки систСм ΠΈ сборщика статистики, Π² систСмах обнаруТСния вторТСния ΠΈ Π² систСмах-пСсочницах ΠΈ Ρ‚.ΠΏ.

Π”Π°Π²Π°ΠΉΡ‚Π΅ Π½Π° этом Π·Π°ΠΊΠΎΠ½Ρ‡ΠΈΠΌ ΠΎΠ±Π·ΠΎΡ€Π½ΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ ΡΡ‚Π°Ρ‚ΡŒΠΈ ΠΈ посмотрим Π½Π° Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΡƒΡŽ ΠΌΠ°ΡˆΠΈΠ½Ρƒ ΠΈ Π½Π° экосистСму BPF Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ.

ΠžΡ‚ΡΡ‚ΡƒΠΏΠ»Π΅Π½ΠΈΠ΅: ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹

Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠΌΠ΅Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΈΠ· ΠΏΠΎΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… Ρ€Π°Π·Π΄Π΅Π»ΠΎΠ², Π²Π°ΠΌ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΎΠ²Π°Ρ‚ΡŒΡΡ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ количСство ΡƒΡ‚ΠΈΠ»ΠΈΡ‚, ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌ llvm/clang с ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ bpf ΠΈ bpftool. Π’ Ρ€Π°Π·Π΄Π΅Π»Π΅ БрСдства Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ инструкции ΠΏΠΎ сборкС ΡƒΡ‚ΠΈΠ»ΠΈΡ‚, Π° Ρ‚Π°ΠΊΠΆΠ΅ своСго ядра. Π­Ρ‚ΠΎΡ‚ Ρ€Π°Π·Π΄Π΅Π» ΠΏΠΎΠΌΠ΅Ρ‰Π΅Π½ Π½ΠΈΠΆΠ΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ Π½Π°Ρ€ΡƒΡˆΠ°Ρ‚ΡŒ ΡΡ‚Ρ€ΠΎΠΉΠ½ΠΎΡΡ‚ΡŒ нашСго излоТСния.

РСгистры ΠΈ систСма ΠΊΠΎΠΌΠ°Π½Π΄ Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠΉ ΠΌΠ°ΡˆΠΈΠ½Ρ‹ BPF

АрхитСктура ΠΈ систСма ΠΊΠΎΠΌΠ°Π½Π΄ BPF Ρ€Π°Π·Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π»Π°ΡΡŒ с ΡƒΡ‡Π΅Ρ‚ΠΎΠΌ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΠΈΡΠ°Ρ‚ΡŒΡΡ Π½Π° языкС C ΠΈ послС Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Π² ядро Ρ‚Ρ€Π°Π½ΡΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ Π² Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ ΠΊΠΎΠ΄. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ количСство рСгистров ΠΈ мноТСство ΠΊΠΎΠΌΠ°Π½Π΄ Π²Ρ‹Π±ΠΈΡ€Π°Π»ΠΎΡΡŒ с оглядкой Π½Π° пСрСсСчСниС, Π² матСматичСском смыслС, возмоТностСй соврСмСнных машин. ΠšΡ€ΠΎΠΌΠ΅ этого, Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ налагались Ρ€Π°Π·Π½ΠΎΠ³ΠΎ Ρ€ΠΎΠ΄Π° ограничСния, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π΄ΠΎ Π½Π΅Π΄Π°Π²Π½Π΅Π³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ Π½Π΅ Π±Ρ‹Π»ΠΎ возмоТности ΠΏΠΈΡΠ°Ρ‚ΡŒ Ρ†ΠΈΠΊΠ»Ρ‹ ΠΈ ΠΏΠΎΠ΄ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, Π° количСство инструкций Π±Ρ‹Π»ΠΎ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΎ 4096 (сСйчас ΠΏΡ€ΠΈΠ²ΠΈΠ»Π΅Π³ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°ΠΌ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ Π΄ΠΎ ΠΌΠΈΠ»Π»ΠΈΠΎΠ½Π° инструкций).

Π’ BPF имССтся ΠΎΠ΄ΠΈΠ½Π½Π°Π΄Ρ†Π°Ρ‚ΡŒ доступных ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ 64-Π±ΠΈΡ‚Π½Ρ‹Ρ… рСгистров r0β€”r10 ΠΈ счётчик ΠΊΠΎΠΌΠ°Π½Π΄ (program counter). РСгистр r10 содСрТит ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° стСк (frame pointer) ΠΈ доступСн Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для чтСния. ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°ΠΌ Π²ΠΎ врСмя выполнСния доступСн стСк Π² 512 Π±Π°ΠΉΡ‚ ΠΈ Π½Π΅ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½Π½ΠΎΠ΅ количСство раздСляСмой памяти Π² Π²ΠΈΠ΄Π΅ maps.

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°ΠΌ BPF Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ΡΡ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹ΠΉ Π² зависимости ΠΎΡ‚ Ρ‚ΠΈΠΏΠ° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π½Π°Π±ΠΎΡ€ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠΎΠ² (kernel helpers) ΠΈ, с Π½Π΅Π΄Π°Π²Π½ΠΈΡ… ΠΏΠΎΡ€, ΠΈ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ. КаТдая вызываСмая функция ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ Π΄ΠΎ пяти Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ², ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Π΅ΠΌΡ‹Ρ… Π² рСгистрах r1β€”r5, Π° Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ пСрСдаСтся Π² r0. ГарантируСтся, Ρ‡Ρ‚ΠΎ послС Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π° ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ содСрТаниС рСгистров r6β€”r9 Π½Π΅ измСнится.

Для эффСктивной трансляции ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ рСгистры r0β€”r11 для всСх ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅ΠΌΡ‹Ρ… Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€ ΠΎΠ΄Π½ΠΎΠ·Π½Π°Ρ‡Π½ΠΎ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°ΡŽΡ‚ΡΡ Π½Π° настоящиС рСгистры с ΡƒΡ‡Π΅Ρ‚ΠΎΠΌ особСнностСй ABI Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹. НапримСр, для x86_64 рСгистры r1β€”r5, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΠ΅ΡΡ для ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°ΡŽΡ‚ΡΡ Π½Π° rdi, rsi, rdx, rcx, r8, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ для ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π½Π° x86_64. НапримСр, ΠΊΠΎΠ΄ слСва транслируСтся Π² ΠΊΠΎΠ΄ справа Π²ΠΎΡ‚ Ρ‚Π°ΠΊ:

1:  (b7) r1 = 1                    mov    $0x1,%rdi
2:  (b7) r2 = 2                    mov    $0x2,%rsi
3:  (b7) r3 = 3                    mov    $0x3,%rdx
4:  (b7) r4 = 4                    mov    $0x4,%rcx
5:  (b7) r5 = 5                    mov    $0x5,%r8
6:  (85) call pc+1                 callq  0x0000000000001ee8

РСгистр r0 Ρ‚Π°ΠΊΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° выполнСния ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, Π° Π² рСгистрС r1 ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ пСрСдаСтся ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° контСкст β€” Π² зависимости ΠΎΡ‚ Ρ‚ΠΈΠΏΠ° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ это ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, структура struct xdp_md (для XDP) ΠΈΠ»ΠΈ структура struct __sk_buff (для Ρ€Π°Π·Π½Ρ‹Ρ… сСтСвых ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ) ΠΈΠ»ΠΈ структура struct pt_regs (для Ρ€Π°Π·Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ² tracing ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ) ΠΈ Ρ‚.ΠΏ.

Π˜Ρ‚Π°ΠΊ, Ρƒ нас Π±Ρ‹Π» Π½Π°Π±ΠΎΡ€ рСгистров, kernel helpers, стСк, ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° контСкст ΠΈ раздСляСмая ΠΏΠ°ΠΌΡΡ‚ΡŒ Π² Π²ΠΈΠ΄Π΅ maps. НС Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ всё это Π±Ρ‹Π»ΠΎ катСгоричСски Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π² ΠΏΠΎΠ΅Π·Π΄ΠΊΠ΅, Π½ΠΎ…

Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΠΌ описаниС ΠΈ расскаТСм ΠΏΡ€ΠΎ систСму ΠΊΠΎΠΌΠ°Π½Π΄ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с этими ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌΠΈ. ВсС (ΠΏΠΎΡ‡Ρ‚ΠΈ всС) инструкции BPF ΠΈΠΌΠ΅ΡŽΡ‚ фиксированный 64-Π±ΠΈΡ‚Π½Ρ‹ΠΉ Ρ€Π°Π·ΠΌΠ΅Ρ€. Если Π²Ρ‹ посмотритС Π½Π° ΠΎΠ΄Π½Ρƒ ΠΈΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ Π½Π° 64-Π±ΠΈΡ‚Π½ΠΎΠΉ Big Endian машинС, Ρ‚ΠΎ Π²Ρ‹ ΡƒΠ²ΠΈΠ΄ΠΈΡ‚Π΅

BPF для самых ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ…, Ρ‡Π°ΡΡ‚ΡŒ пСрвая: extended BPF

Π—Π΄Π΅ΡΡŒ Code β€” это ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΊΠ° инструкции, Dst/Src — это ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΊΠΈ ΠΏΡ€ΠΈΠ΅ΠΌΠ½ΠΈΠΊΠ° ΠΈ источника, соотвСтствСнно, Off β€” 16-Π±ΠΈΡ‚Π½Ρ‹ΠΉ Π·Π½Π°ΠΊΠΎΠ²Ρ‹ΠΉ отступ, Π° Imm β€” это 32-Π±ΠΈΡ‚Π½ΠΎΠ΅ Π·Π½Π°ΠΊΠΎΠ²ΠΎΠ΅ Ρ†Π΅Π»ΠΎΠ΅ число, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠ΅ Π² Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΊΠΎΠΌΠ°Π½Π΄Π°Ρ… (Π°Π½Π°Π»ΠΎΠ³ константы K ΠΈΠ· cBPF). ΠšΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΊΠ° Code ΠΈΠΌΠ΅Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ ΠΈΠ· Π΄Π²ΡƒΡ… Π²ΠΈΠ΄ΠΎΠ²:

BPF для самых ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ…, Ρ‡Π°ΡΡ‚ΡŒ пСрвая: extended BPF

ΠšΠ»Π°ΡΡΡ‹ инструкций 0, 1, 2, 3 ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΏΠ°ΠΌΡΡ‚ΡŒΡŽ. Они Π½Π°Π·Ρ‹Π²Π°ΡŽΡ‚ΡΡ, BPF_LD, BPF_LDX, BPF_ST, BPF_STX, соотвСтствСнно. ΠšΠ»Π°ΡΡΡ‹ 4, 7 (BPF_ALU, BPF_ALU64) ΡΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‚ Π½Π°Π±ΠΎΡ€ ALU инструкций. ΠšΠ»Π°ΡΡΡ‹ 5, 6 (BPF_JMP, BPF_JMP32) Π·Π°ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‚ Π² сСбС инструкции ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Π°.

Π”Π°Π»ΡŒΠ½Π΅ΠΉΡˆΠΈΠΉ ΠΏΠ»Π°Π½ изучСния систСмы ΠΊΠΎΠΌΠ°Π½Π΄ BPF Ρ‚Π°ΠΊΠΎΠΉ: вмСсто Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π΄ΠΎΡ‚ΠΎΡˆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Ρ‡ΠΈΡΠ»ΡΡ‚ΡŒ всС инструкции ΠΈ ΠΈΡ… ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹, ΠΌΡ‹ Ρ€Π°Π·Π±Π΅Ρ€Π΅ΠΌ ΠΏΠ°Ρ€Ρƒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ² Π² этом Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΈ ΠΈΠ· Π½ΠΈΡ… станСт ясно, ΠΊΠ°ΠΊ устроСны инструкции Π½Π° самом Π΄Π΅Π»Π΅ ΠΈ ΠΊΠ°ΠΊ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ Π΄ΠΈΠ·Π°ΡΡΠ΅ΠΌΠ±Π»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ любой Π±ΠΈΠ½Π°Ρ€Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» для BPF. Для закрСплСния ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Π° дальшС Π² ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ Π΅Ρ‰Π΅ встрСтимся с ΠΈΠ½Π΄ΠΈΠ²ΠΈΠ΄ΡƒΠ°Π»ΡŒΠ½Ρ‹ΠΌΠΈ инструкциями Π² Ρ€Π°Π·Π΄Π΅Π»Π°Ρ… ΠΏΡ€ΠΎ Verifier, JIT компилятор, Ρ‚Ρ€Π°Π½ΡΠ»ΡΡ†ΠΈΡŽ классичСского BPF, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΡ€ΠΈ ΠΈΠ·ΡƒΡ‡Π΅Π½ΠΈΠΈ maps, Π²Ρ‹Π·ΠΎΠ²Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ ΠΈ Ρ‚.ΠΏ.

Когда ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ΡŒ ΠΎΠ± ΠΈΠ½Π΄ΠΈΠ²ΠΈΠ΄ΡƒΠ°Π»ΡŒΠ½Ρ‹Ρ… инструкциях, ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΡΡΡ‹Π»Π°Ρ‚ΡŒΡΡ Π½Π° Ρ„Π°ΠΉΠ»Ρ‹ ядра bpf.h ΠΈ bpf_common.h, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡ числСнныС ΠΊΠΎΠ΄Ρ‹ инструкций BPF. ΠŸΡ€ΠΈ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎΠΌ ΠΈΠ·ΡƒΡ‡Π΅Π½ΠΈΠΈ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹ ΠΈ/ΠΈΠ»ΠΈ Ρ€Π°Π·Π±ΠΎΡ€Π΅ Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊΠΎΠ², сСмантику Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π½Π°ΠΉΡ‚ΠΈ Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ…, отсортированных Π² порядкС слоТности, источниках: Unofficial eBPF spec, BPF and XDP Reference Guide, Instruction Set, Documentation/networking/filter.txt ΠΈ, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, Π² исходных ΠΊΠΎΠ΄Π°Ρ… Linux β€” verifier, JIT, ΠΈΠ½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚Π°Ρ‚ΠΎΡ€ BPF.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€: дизассСмблируСм BPF Π² ΡƒΠΌΠ΅

Π”Π°Π²Π°ΠΉΡ‚Π΅ Ρ€Π°Π·Π±Π΅Ρ€Π΅ΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΌΡ‹ скомпилируСм ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ readelf-example.c ΠΈ посмотрим Π½Π° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ²ΡˆΠΈΠΉΡΡ Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊ. ΠœΡ‹ раскроСм ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ содСрТимоС readelf-example.c Π½ΠΈΠΆΠ΅, послС Ρ‚ΠΎΠ³ΠΎ ΠΊΠ°ΠΊ восстановим Π΅Π³ΠΎ Π»ΠΎΠ³ΠΈΠΊΡƒ ΠΈΠ· Π±ΠΈΠ½Π°Ρ€Π½Ρ‹Ρ… ΠΊΠΎΠ΄ΠΎΠ²:

$ clang -target bpf -c readelf-example.c -o readelf-example.o -O2
$ llvm-readelf -x .text readelf-example.o
Hex dump of section '.text':
0x00000000 b7000000 01000000 15010100 00000000 ................
0x00000010 b7000000 02000000 95000000 00000000 ................

ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ столбСц Π² Π²Ρ‹Π²ΠΎΠ΄Π΅ readelf β€” это отступ ΠΈ наша ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°, Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, состоит ΠΈΠ· Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅Ρ… ΠΊΠΎΠΌΠ°Π½Π΄:

Code Dst Src Off  Imm
b7   0   0   0000 01000000
15   0   1   0100 00000000
b7   0   0   0000 02000000
95   0   0   0000 00000000

ΠšΠΎΠ΄Ρ‹ ΠΊΠΎΠΌΠ°Π½Π΄ Ρ€Π°Π²Π½Ρ‹ b7, 15, b7 ΠΈ 95. Вспомним, Ρ‡Ρ‚ΠΎ Ρ‚Ρ€ΠΈ младшиС Π±ΠΈΡ‚Π° β€” это класс инструкции. Π’ нашСм случаС Ρ‡Π΅Ρ‚Π²Π΅Ρ€Ρ‚Ρ‹ΠΉ Π±ΠΈΡ‚ Ρƒ всСх инструкций пустой, поэтому классы инструкций Ρ€Π°Π²Π½Ρ‹, соотвСтствСнно, 7, 5, 7, 5. Класс 7 β€” это BPF_ALU64, Π° 5 β€” это BPF_JMP. Для ΠΎΠ±ΠΎΠΈΡ… классов Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ инструкции ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹ΠΉ (см. Π²Ρ‹ΡˆΠ΅) ΠΈ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡΠ°Ρ‚ΡŒ Π½Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ Ρ‚Π°ΠΊ (Π·Π°ΠΎΠ΄Π½ΠΎ ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡˆΠ΅ΠΌ ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ столбцы Π² чСловСчСском Π²ΠΈΠ΄Π΅):

Op S  Class   Dst Src Off  Imm
b  0  ALU64   0   0   0    1
1  0  JMP     0   1   1    0
b  0  ALU64   0   0   0    2
9  0  JMP     0   0   0    0

ΠžΠΏΠ΅Ρ€Π°Ρ†ΠΈΡ b класса ALU64 β€” это BPF_MOV. Она присваиваСт Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ рСгистру-ΠΏΡ€ΠΈΠ΅ΠΌΠ½ΠΈΠΊΡƒ. Если установлСн Π±ΠΈΡ‚ s (source), Ρ‚ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ бСрСтся ΠΈΠ· рСгистра-источника, Π° Ссли, ΠΊΠ°ΠΊ Π² нашСм случаС, ΠΎΠ½ Π½Π΅ установлСн, Ρ‚ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ бСрСтся ΠΈΠ· поля Imm. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Π² ΠΏΠ΅Ρ€Π²ΠΎΠΉ ΠΈ Ρ‚Ρ€Π΅Ρ‚ΡŒΠ΅ΠΉ инструкциях ΠΌΡ‹ выполняСм ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ r0 = Imm. Π”Π°Π»Π΅Π΅, опСрация 1 класса JMP β€” это BPF_JEQ (jump if equal). Π’ нашСм случаС, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ Π±ΠΈΡ‚ S Ρ€Π°Π²Π΅Π½ Π½ΡƒΠ»ΡŽ, ΠΎΠ½Π° сравниваСт Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ рСгистра-источника с ΠΏΠΎΠ»Π΅ΠΌ Imm. Если значСния ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‚, Ρ‚ΠΎ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ происходит Π½Π° PC + Off, Π³Π΄Π΅ PC, ΠΊΠ°ΠΊ водится, содСрТит адрСс ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ инструкции. НаконСц, опСрация 9 класса JMP β€” это BPF_EXIT. Π­Ρ‚Π° инструкция Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, возвращая ядру r0. Π”ΠΎΠ±Π°Π²ΠΈΠΌ Π½ΠΎΠ²Ρ‹ΠΉ столбСц ΠΊ нашСй Ρ‚Π°Π±Π»ΠΈΡ†Π΅:

Op    S  Class   Dst Src Off  Imm    Disassm
MOV   0  ALU64   0   0   0    1      r0 = 1
JEQ   0  JMP     0   1   1    0      if (r1 == 0) goto pc+1
MOV   0  ALU64   0   0   0    2      r0 = 2
EXIT  0  JMP     0   0   0    0      exit

ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡΠ°Ρ‚ΡŒ это Π² Π±ΠΎΠ»Π΅Π΅ ΡƒΠ΄ΠΎΠ±Π½ΠΎΠΌ Π²ΠΈΠ΄Π΅:

     r0 = 1
     if (r1 == 0) goto END
     r0 = 2
END:
     exit

Если ΠΌΡ‹ вспомним, Ρ‡Ρ‚ΠΎ Π² рСгистрС r1 ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ пСрСдаСтся ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° контСкст ΠΎΡ‚ ядра, Π° Π² рСгистрС r0 Π² ядро возвращаСтся Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, Ρ‚ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ссли ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° контСкст Ρ€Π°Π²Π΅Π½ Π½ΡƒΠ»ΡŽ, Ρ‚ΠΎ ΠΌΡ‹ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ 1, Π° Π² ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π½ΠΎΠΌ случаС β€” 2. ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΠΏΡ€Π°Π²Ρ‹, посмотрСв Π½Π° исходник:

$ cat readelf-example.c
int foo(void *ctx)
{
        return ctx ? 2 : 1;
}

Π”Π°, это бСссмыслСнная ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°, Π½ΠΎ Π·Π°Ρ‚ΠΎ ΠΎΠ½Π° транслируСтся всСго Π² Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅ простых инструкции.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€-ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅: 16-байтная инструкция

Π Π°Π½Π΅Π΅ ΠΌΡ‹ упомянули, Ρ‡Ρ‚ΠΎ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ инструкции Π·Π°Π½ΠΈΠΌΠ°ΡŽΡ‚ большС, Ρ‡Π΅ΠΌ 64 Π±ΠΈΡ‚Π°. Π­Ρ‚ΠΎ относится, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΊ инструкции lddw (Code = 0x18 = BPF_LD | BPF_DW | BPF_IMM) β€” Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ Π² рСгистр Π΄Π²ΠΎΠΉΠ½ΠΎΠ΅ слово ΠΈΠ· ΠΏΠΎΠ»Π΅ΠΉ Imm. Π”Π΅Π»ΠΎ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Imm ΠΈΠΌΠ΅Π΅Ρ‚ Ρ€Π°Π·ΠΌΠ΅Ρ€ 32, Π° Π΄Π²ΠΎΠΉΠ½ΠΎΠ΅ слово β€” 64 Π±ΠΈΡ‚Π°, поэтому Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ Π² рСгистр 64-Π±ΠΈΡ‚Π½ΠΎΠ΅ нСпосрСдствСнноС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π² ΠΎΠ΄Π½ΠΎΠΉ 64-Π±ΠΈΡ‚Π½ΠΎΠΉ инструкции Π½Π΅ получится. Для этого Π΄Π²Π΅ сосСдниС инструкции ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ для хранСния Π²Ρ‚ΠΎΡ€ΠΎΠΉ части 64-Π±ΠΈΡ‚Π½ΠΎΠ³ΠΎ значСния Π² ΠΏΠΎΠ»Π΅ Imm. ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

$ cat x64.c
long foo(void *ctx)
{
        return 0x11223344aabbccdd;
}
$ clang -target bpf -c x64.c -o x64.o -O2
$ llvm-readelf -x .text x64.o
Hex dump of section '.text':
0x00000000 18000000 ddccbbaa 00000000 44332211 ............D3".
0x00000010 95000000 00000000                   ........

Π’ Π±ΠΈΠ½Π°Ρ€Π½ΠΎΠΉ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ всСго Π΄Π²Π΅ инструкции:

Binary                                 Disassm
18000000 ddccbbaa 00000000 44332211    r0 = Imm[0]|Imm[1]
95000000 00000000                      exit

ΠœΡ‹ Π΅Ρ‰Π΅ встрСтимся с инструкциСй lddw, ΠΊΠΎΠ³Π΄Π° ΠΏΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΎ рСлокациях ΠΈ Ρ€Π°Π±ΠΎΡ‚Π΅ с maps.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€: дизассСмблируСм BPF стандартными срСдствами

Π˜Ρ‚Π°ΠΊ, ΠΌΡ‹ Π½Π°ΡƒΡ‡ΠΈΠ»ΠΈΡΡŒ Ρ‡ΠΈΡ‚Π°Ρ‚ΡŒ Π±ΠΈΠ½Π°Ρ€Π½Ρ‹Π΅ ΠΊΠΎΠ΄Ρ‹ BPF ΠΈ Π³ΠΎΡ‚ΠΎΠ²Ρ‹ Ρ€Π°Π·ΠΎΠ±Ρ€Π°Ρ‚ΡŒ Π»ΡŽΠ±ΡƒΡŽ ΠΈΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ, Ссли потрСбуСтся. Однако, стоит ΡΠΊΠ°Π·Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅ ΡƒΠ΄ΠΎΠ±Π½Π΅Π΅ ΠΈ быстрСС Π΄ΠΈΠ·Π°ΡΡΠ΅ΠΌΠ±Π»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ стандартных срСдств, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€:

$ llvm-objdump -d x64.o

Disassembly of section .text:

0000000000000000 <foo>:
 0: 18 00 00 00 dd cc bb aa 00 00 00 00 44 33 22 11 r0 = 1234605617868164317 ll
 2: 95 00 00 00 00 00 00 00 exit

Π–ΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ» ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² BPF, файловая систСма bpffs

(НСкоторыС подробности, описываСмыС Π² этом ΠΏΠΎΠ΄Ρ€Π°Π·Π΄Π΅Π»Π΅, я Π²ΠΏΠ΅Ρ€Π²Ρ‹Π΅ ΡƒΠ·Π½Π°Π» ΠΈΠ· поста Alexei Starovoitov Π² BPF Blog.)

ΠžΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ BPF β€” ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΈ ΠΌΠ°ΠΏΡ‹ β€” ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ ΠΈΠ· пространства ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄ BPF_PROG_LOAD ΠΈ BPF_MAP_CREATE систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf(2), ΠΌΡ‹ ΠΏΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΏΡ€ΠΎ Ρ‚ΠΎ ΠΊΠ°ΠΊ ΠΈΠΌΠ΅Π½Π½ΠΎ это происходит Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌ Ρ€Π°Π·Π΄Π΅Π»Π΅. ΠŸΡ€ΠΈ этом ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ структуры Π΄Π°Π½Π½Ρ‹Ρ… ядра ΠΈ для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΈΠ· Π½ΠΈΡ… refcount (счСтчик ссылок) устанавливаСтся Ρ€Π°Π²Π½Ρ‹ΠΌ Π΅Π΄ΠΈΠ½ΠΈΡ†Π΅, Π° ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ возвращаСтся Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор, ΡƒΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉ Π½Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚. ПослС закрытия дСскриптора refcount ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° ΡƒΠΌΠ΅Π½ΡŒΡˆΠ°Π΅Ρ‚ΡΡ Π½Π° Π΅Π΄ΠΈΠ½ΠΈΡ†Ρƒ, ΠΈ ΠΏΡ€ΠΈ достиТСнии ΠΈΠΌ нуля ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ уничтоТаСтся.

Если ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΌΠ°ΠΏΡ‹, Ρ‚ΠΎ refcount этих ΠΌΠ°ΠΏΠΎΠ² увСличиваСтся Π½Π° Π΅Π΄ΠΈΠ½ΠΈΡ†Ρƒ послС Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, Ρ‚.Π΅. ΠΈΡ… Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹Π΅ дСскрипторы ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΡŒ ΠΈΠ· ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ процСсса ΠΈ ΠΏΡ€ΠΈ этом refcount Π½Π΅ станСт Π½ΡƒΠ»Π΅ΠΌ:

BPF для самых ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ…, Ρ‡Π°ΡΡ‚ΡŒ пСрвая: extended BPF

ПослС ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΉ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΌΡ‹ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ присоСдиняСм Π΅Π΅ ΠΊ ΠΊΠ°ΠΊΠΎΠΌΡƒ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Ρƒ событий. НапримСр, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΡΠ°Π΄ΠΈΡ‚ΡŒ Π΅Π΅ Π½Π° сСтСвой интСрфСйс для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ входящих ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ² ΠΈΠ»ΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Π΅Π΅ ΠΊ ΠΊΠ°ΠΊΠΎΠΉ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ tracepoint Π² ядрС. Π’ этот ΠΌΠΎΠΌΠ΅Π½Ρ‚ счСтчик ссылок Ρ‚ΠΎΠΆΠ΅ увСличится Π½Π° Π΅Π΄ΠΈΠ½ΠΈΡ†Ρƒ ΠΈ ΠΌΡ‹ смоТСм Π·Π°ΠΊΡ€Ρ‹Ρ‚ΡŒ Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅-Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊΠ΅.

Π§Ρ‚ΠΎ случится Ссли ΠΌΡ‹ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Π·Π°Π²Π΅Ρ€ΡˆΠΈΠΌ Ρ€Π°Π±ΠΎΡ‚Ρƒ Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊΠ°? Π­Ρ‚ΠΎ зависит ΠΎΡ‚ Ρ‚ΠΈΠΏΠ° Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Π° событий (hook). ВсС сСтСвыС Ρ…ΡƒΠΊΠΈ Π±ΡƒΠ΄ΡƒΡ‚ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ послС Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊΠ°, это, Ρ‚Π°ΠΊ Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΡ‹Π΅, Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹Π΅ Ρ…ΡƒΠΊΠΈ. А, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ трассировки Π±ΡƒΠ΄ΡƒΡ‚ освобоТдСны послС Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ процСсса, создавшСго ΠΈΡ… (ΠΈ поэтому Π½Π°Π·Ρ‹Π²Π°ΡŽΡ‚ΡΡ Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΌΠΈ, ΠΎΡ‚ Β«local to the processΒ»). ВСхничСски, Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Π΅ Ρ…ΡƒΠΊΠΈ всСгда ΠΈΠΌΠ΅ΡŽΡ‚ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор Π² пространствС ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΈ поэтому Π·Π°ΠΊΡ€Ρ‹Π²Π°ΡŽΡ‚ΡΡ с Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ΠΌ процСсса, Π° Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹Π΅ β€”Β Π½Π΅Ρ‚. На ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌ рисункС я ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ красных крСстиков ΡΡ‚Π°Ρ€Π°ΡŽΡΡŒ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΊΠ°ΠΊ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹-Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊΠ° влияСт Π½Π° врСмя ΠΆΠΈΠ·Π½ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π² случаС Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Ρ… ΠΈ Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹Ρ… Ρ…ΡƒΠΊΠΎΠ².

BPF для самых ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ…, Ρ‡Π°ΡΡ‚ΡŒ пСрвая: extended BPF

Π—Π°Ρ‡Π΅ΠΌ сущСствуСт Ρ€Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Π½Π° Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Π΅ ΠΈ Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹Π΅ Ρ…ΡƒΠΊΠΈ? Запуск Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ² сСтСвых ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ ΠΈΠΌΠ΅Π΅Ρ‚ смысл ΠΈ Π±Π΅Π· userspace, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²ΡŒΡ‚Π΅ Π·Π°Ρ‰ΠΈΡ‚Ρƒ ΠΎΡ‚ DDoS β€” Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊ прописываСт ΠΏΡ€Π°Π²ΠΈΠ»Π° ΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ BPF ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΊ сСтСвому интСрфСйсу, послС Ρ‡Π΅Π³ΠΎ Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠΉΡ‚ΠΈ ΠΈ ΡƒΠ±ΠΈΡ‚ΡŒΡΡ. Π‘ Π΄Ρ€ΡƒΠ³ΠΎΠΉ стороны, ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²ΡŒΡ‚Π΅ сСбС ΠΎΡ‚Π»Π°Π΄ΠΎΡ‡Π½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ трассировки, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ Π²Ρ‹ написали Π½Π° ΠΊΠΎΠ»Π΅Π½ΠΊΠ΅ Π·Π° Π΄Π΅ΡΡΡ‚ΡŒ ΠΌΠΈΠ½ΡƒΡ‚ — послС Π΅Π΅ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ Π²Π°ΠΌ Π±Ρ‹ Ρ…ΠΎΡ‚Π΅Π»ΠΎΡΡŒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π² систСмС Π½Π΅ ΠΎΡΡ‚Π°Π²Π°Π»ΠΎΡΡŒ мусора, ΠΈ Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Π΅ Ρ…ΡƒΠΊΠΈ это Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΡŽΡ‚.

Π‘ Π΄Ρ€ΡƒΠ³ΠΎΠΉ стороны, ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²ΡŒΡ‚Π΅, Ρ‡Ρ‚ΠΎ Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΠΎΠ΄ΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ tracepoint Π² ядрС ΠΈ ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ статистику Π² Ρ‚Π΅Ρ‡Π΅Π½ΠΈΠ΅ ΠΌΠ½ΠΎΠ³ΠΈΡ… Π»Π΅Ρ‚. Π’ этом случаС Π²Π°ΠΌ Π±Ρ‹ Ρ…ΠΎΡ‚Π΅Π»ΠΎΡΡŒ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒΡΡ ΠΊ статистикС врСмя ΠΎΡ‚ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ. Π’Π°ΠΊΡƒΡŽ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ прСдоставляСт файловая систСма bpf. Π­Ρ‚ΠΎ псСвдо-файловая систСма, ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰Π°Ρ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² памяти, которая позволяСт ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ»Ρ‹, ΡΡΡ‹Π»Π°ΡŽΡ‰ΠΈΠ΅ΡΡ Π½Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ BPF ΠΈ, Ρ‚Π΅ΠΌ самым, ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΠ²Π°ΡŽΡ‰ΠΈΠ΅ refcount ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ². ПослС этого Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊ ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ, Π° созданныС ΠΈΠΌ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ останутся ΠΆΠΈΠ²Ρ‹.

BPF для самых ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ…, Ρ‡Π°ΡΡ‚ΡŒ пСрвая: extended BPF

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»ΠΎΠ² Π² bpffs, ΡΡΡ‹Π»Π°ΡŽΡ‰ΠΈΡ…ΡΡ Π½Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ BPF называСтся Β«Π·Π°ΠΊΡ€Π΅ΠΏΠ»Π΅Π½ΠΈΠ΅Β» (Β«pinΒ», ΠΊΠ°ΠΊ Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ Ρ„Ρ€Π°Π·Π΅: Β«process can pin a BPF program or mapΒ»). Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² для ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² BPF ΠΈΠΌΠ΅Π΅Ρ‚ смысл Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для продлСния ΠΆΠΈΠ·Π½ΠΈ Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ², Π½ΠΎ ΠΈ для удобства использования Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² β€” Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡΡΡŒ ΠΊ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ с глобальной ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΎΠΉ для Π·Π°Ρ‰ΠΈΡ‚Ρ‹ ΠΎΡ‚ DDoS, ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ ΠΈΠΌΠ΅Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ врСмя ΠΎΡ‚ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ΡŒ ΠΈ ΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° статистику.

Ѐайловая систСма BPF ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ монтируСтся Π² /sys/fs/bpf, Π½ΠΎ Π΅Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΡΠΌΠΎΠ½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ локально, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Ρ‚Π°ΠΊ:

$ mkdir bpf-mountpoint
$ sudo mount -t bpf none bpf-mountpoint

ИмСна Π² Ρ„Π°ΠΉΠ»ΠΎΠ²ΠΎΠΉ систСмС ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ BPF_OBJ_PIN систСмного Π²Ρ‹Π·ΠΎΠ²Π° BPF. Π’ качСствС ΠΈΠ»Π»ΡŽΡΡ‚Ρ€Π°Ρ†ΠΈΠΈ Π΄Π°Π²Π°ΠΉΡ‚Π΅ возьмСм ΠΊΠ°ΠΊΡƒΡŽ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ, скомпилируСм, Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΈ Π·Π°ΠΊΡ€Π΅ΠΏΠΈΠΌ Π΅Π΅ Π² bpffs. Наша ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Π½Π΅ Π΄Π΅Π»Π°Π΅Ρ‚ Π½ΠΈΡ‡Π΅Π³ΠΎ ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠ³ΠΎ, ΠΌΡ‹ ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΠΌ Π΅Π΅ ΠΊΠΎΠ΄ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹ ΠΌΠΎΠ³Π»ΠΈ воспроизвСсти ΠΏΡ€ΠΈΠΌΠ΅Ρ€:

$ cat test.c
__attribute__((section("xdp"), used))
int test(void *ctx)
{
        return 0;
}

char _license[] __attribute__((section("license"), used)) = "GPL";

Π‘ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΡƒΠ΅ΠΌ эту ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΈ создадим Π»ΠΎΠΊΠ°Π»ΡŒΠ½ΡƒΡŽ копию Ρ„Π°ΠΉΠ»ΠΎΠ²ΠΎΠΉ систСмы bpffs:

$ clang -target bpf -c test.c -o test.o
$ mkdir bpf-mountpoint
$ sudo mount -t bpf none bpf-mountpoint

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ Π½Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ bpftool ΠΈ посмотрим Π½Π° ΡΠΎΠΏΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ систСмныС Π²Ρ‹Π·ΠΎΠ²Ρ‹ bpf(2) (ΠΈΠ· Π²Ρ‹Π²ΠΎΠ΄Π° strace ΡƒΠ΄Π°Π»Π΅Π½Ρ‹ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½Π΅ относящиСся ΠΊ Π΄Π΅Π»Ρƒ строки):

$ sudo strace -e bpf bpftool prog load ./test.o bpf-mountpoint/test
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_XDP, prog_name="test", ...}, 120) = 3
bpf(BPF_OBJ_PIN, {pathname="bpf-mountpoint/test", bpf_fd=3}, 120) = 0

Π—Π΄Π΅ΡΡŒ ΠΌΡ‹ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠ»ΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ BPF_PROG_LOAD, ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ ΠΎΡ‚ ядра Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор 3 ΠΈ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ BPF_OBJ_PIN Π·Π°ΠΊΡ€Π΅ΠΏΠΈΠ»ΠΈ этот Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор Π² Π²ΠΈΠ΄Π΅ Ρ„Π°ΠΉΠ»Π° "bpf-mountpoint/test". ПослС этого ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°-Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊ bpftool Π·Π°ΠΊΠΎΠ½Ρ‡ΠΈΠ»Π° Ρ€Π°Π±ΠΎΡ‚Ρƒ, Π½ΠΎ наша ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° ΠΎΡΡ‚Π°Π»Π°ΡΡŒ Π² ядрС, хотя ΠΌΡ‹ ΠΈ Π½Π΅ прикрСпляли Π΅Π΅ Π½ΠΈ ΠΊ ΠΊΠ°ΠΊΠΎΠΌΡƒ сСтСвому интСрфСйсу:

$ sudo bpftool prog | tail -3
783: xdp  name test  tag 5c8ba0cf164cb46c  gpl
        loaded_at 2020-05-05T13:27:08+0000  uid 0
        xlated 24B  jited 41B  memlock 4096B

ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΌ unlink(2) ΠΈ послС этого ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π°Ρ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΠ΄Π°Π»Π΅Π½Π°:

$ sudo rm ./bpf-mountpoint/test
$ sudo bpftool prog show id 783
Error: get by id (783): No such file or directory

Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ²

Говоря ΠΎΠ± ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ², Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡƒΡ‚ΠΎΡ‡Π½ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ послС Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΌΡ‹ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΎΡ‚ Ρ…ΡƒΠΊΠ° (Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Π° событий), Π½ΠΈ ΠΎΠ΄Π½ΠΎ Π½ΠΎΠ²ΠΎΠ΅ событиС Π½Π΅ ΠΏΠΎΠ²Π»Π΅Ρ‡Π΅Ρ‚ Π΅Π΅ запуск, ΠΎΠ΄Π½Π°ΠΊΠΎ, всС Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠ΅ экзСмпляры ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π±ΡƒΠ΄ΡƒΡ‚ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½Ρ‹ Π² Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½ΠΎΠΌ порядкС.

НСкоторыС Π²ΠΈΠ΄Ρ‹ BPF ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ ΠΏΠΎΠ΄ΠΌΠ΅Π½ΡΡ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ Π½Π° Π»Π΅Ρ‚Ρƒ, Ρ‚.Π΅. ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‚ Π°Ρ‚ΠΎΠΌΠ°Ρ€Π½ΠΎΡΡ‚ΡŒ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ replace = detach old program, attach new program. ΠŸΡ€ΠΈ этом всС Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ экзСмпляры старой вСрсии ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π·Π°ΠΊΠΎΠ½Ρ‡Π°Ρ‚ свою Ρ€Π°Π±ΠΎΡ‚Ρƒ, Π° Π½ΠΎΠ²Ρ‹Π΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ событий Π±ΡƒΠ΄ΡƒΡ‚ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒΡΡ ΡƒΠΆΠ΅ ΠΈΠ· Π½ΠΎΠ²ΠΎΠΉ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, ΠΈ Β«Π°Ρ‚ΠΎΠΌΠ°Ρ€Π½ΠΎΡΡ‚ΡŒΒ» ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ здСсь, Ρ‡Ρ‚ΠΎ Π½ΠΈ ΠΎΠ΄Π½ΠΎ событиС Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠΏΡƒΡ‰Π΅Π½ΠΎ.

ΠŸΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ ΠΊ источникам событий

Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ ΠΎΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ подсоСдинСниС ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ ΠΊ источникам событий, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ это ΠΈΠΌΠ΅Π΅Ρ‚ смысл ΠΈΠ·ΡƒΡ‡Π°Ρ‚ΡŒ Π² контСкстС ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹. Π‘ΠΌ. ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π½ΠΈΠΆΠ΅, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΌΡ‹ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ ΠΊΠ°ΠΊ ΠΏΠΎΠ΄ΡΠΎΠ΅Π΄ΠΈΠ½ΡΡŽΡ‚ΡΡ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Ρ‚ΠΈΠΏΠ° XDP.

Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌΠΈ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF

ВсС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ BPF ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ ΠΈ ΡƒΠΏΡ€Π°Π²Π»ΡΡŽΡ‚ΡΡ ΠΈΠ· пространства ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf, ΠΈΠΌΠ΅ΡŽΡ‰Π΅Π³ΠΎ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΏΡ€ΠΎΡ‚ΠΎΡ‚ΠΈΠΏ:

#include <linux/bpf.h>

int bpf(int cmd, union bpf_attr *attr, unsigned int size);

Π—Π΄Π΅ΡΡŒ ΠΊΠΎΠΌΠ°Π½Π΄Π° cmd β€” это ΠΎΠ΄Π½ΠΎ ΠΈΠ· Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Ρ‚ΠΈΠΏΠ° enum bpf_cmd, attr β€”Β ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ для ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΉ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΈ size β€” Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° ΠΏΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŽ, Ρ‚.Π΅. ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ это sizeof(*attr). Π’ ядрС 5.8 систСмный Π²Ρ‹Π·ΠΎΠ² bpf ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ 34 Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹, Π° ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ union bpf_attr Π·Π°Π½ΠΈΠΌΠ°Π΅Ρ‚ 200 строчСк. Но нас Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ это ΠΏΡƒΠ³Π°Ρ‚ΡŒ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π·Π½Π°ΠΊΠΎΠΌΠΈΡ‚ΡŒΡΡ с ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌΠΈ ΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ Π½Π° протяТСнии Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… статСй.

НачнСм ΠΌΡ‹ с ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ BPF_PROG_LOAD, которая создаСт ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF β€” Π±Π΅Ρ€Π΅Ρ‚ Π½Π°Π±ΠΎΡ€ инструкций BPF ΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ Π΅Π³ΠΎ Π² ядро. Π’ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ запускаСтся verifier, Π° ΠΏΠΎΡ‚ΠΎΠΌ JIT compiler ΠΈ, послС ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠ³ΠΎ выполнСния, ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ возвращаСтся Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹. ΠœΡ‹ Π²ΠΈΠ΄Π΅Π»ΠΈ Ρ‡Ρ‚ΠΎ с Π½ΠΈΠΌ происходит дальшС Π² ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΌ Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΏΡ€ΠΎ ΠΆΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ» ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² BPF.

БСйчас ΠΌΡ‹ напишСм ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ, которая Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΡΡ‚ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ BPF, Π½ΠΎ сначала Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Ρ€Π΅ΡˆΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΈΠΌΠ΅Π½Π½ΠΎ Π·Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ β€”Β Π½Π°ΠΌ придСтся Π²Ρ‹Π±Ρ€Π°Ρ‚ΡŒ Ρ‚ΠΈΠΏ ΠΈ Π² Ρ€Π°ΠΌΠΊΠ°Ρ… этого Ρ‚ΠΈΠΏΠ° Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ, которая ΠΏΡ€ΠΎΠΉΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΡƒ Π½Π° verifier. Однако, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΡƒΡΠ»ΠΎΠΆΠ½ΡΡ‚ΡŒ процСсс, Π²ΠΎΡ‚ Π³ΠΎΡ‚ΠΎΠ²ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅: ΠΌΡ‹ возьмСм ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ Ρ‚ΠΈΠΏΠ° BPF_PROG_TYPE_XDP, которая Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ XDP_PASS (ΠΏΡ€ΠΎΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ всС ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹). На ассСмблСрС BPF это выглядит ΠΎΡ‡Π΅Π½ΡŒ просто:

r0 = 2
exit

ПослС Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΌΡ‹ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈΡΡŒ с Ρ‚Π΅ΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Ρ€Π°ΡΡΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΊΠ°ΠΊ ΠΌΡ‹ это сдСлаСм:

#define _GNU_SOURCE
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/bpf.h>

static inline __u64 ptr_to_u64(const void *ptr)
{
        return (__u64) (unsigned long) ptr;
}

int main(void)
{
    struct bpf_insn insns[] = {
        {
            .code = BPF_ALU64 | BPF_MOV | BPF_K,
            .dst_reg = BPF_REG_0,
            .imm = XDP_PASS
        },
        {
            .code = BPF_JMP | BPF_EXIT
        },
    };

    union bpf_attr attr = {
        .prog_type = BPF_PROG_TYPE_XDP,
        .insns     = ptr_to_u64(insns),
        .insn_cnt  = sizeof(insns)/sizeof(insns[0]),
        .license   = ptr_to_u64("GPL"),
    };

    strncpy(attr.prog_name, "woo", sizeof(attr.prog_name));
    syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));

    for ( ;; )
        pause();
}

Π˜Π½Ρ‚Π΅Ρ€Π΅ΡΠ½Ρ‹Π΅ события Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‚ΡΡ с опрСдСлСния массива insns β€” нашСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF Π² ΠΌΠ°ΡˆΠΈΠ½Π½Ρ‹Ρ… ΠΊΠΎΠ΄Π°Ρ…. ΠŸΡ€ΠΈ этом каТдая инструкция ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF упаковываСтся Π² структуру bpf_insn. ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт insns соотвСтствуСт инструкции r0 = 2, Π²Ρ‚ΠΎΡ€ΠΎΠΉ β€”Β exit.

ΠžΡ‚ΡΡ‚ΡƒΠΏΠ»Π΅Π½ΠΈΠ΅. Π’ ядрС ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Ρ‹ Π±ΠΎΠ»Π΅Π΅ ΡƒΠ΄ΠΎΠ±Π½Ρ‹Π΅ макросы для написания ΠΌΠ°ΡˆΠΈΠ½Π½Ρ‹Ρ… ΠΊΠΎΠ΄ΠΎΠ², ΠΈ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ядСрный Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» tools/include/linux/filter.h ΠΌΡ‹ ΠΌΠΎΠ³Π»ΠΈ Π±Ρ‹ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ

struct bpf_insn insns[] = {
    BPF_MOV64_IMM(BPF_REG_0, XDP_PASS),
    BPF_EXIT_INSN()
};

Но Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ написаниС ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF Π² ΠΌΠ°ΡˆΠΈΠ½Π½Ρ‹Ρ… ΠΊΠΎΠ΄Π°Ρ… Π½ΡƒΠΆΠ½ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для написания тСстов Π² ядрС ΠΈ статСй ΠΏΡ€ΠΎ BPF, отсутствиС этих макросов Π½Π° самом Π΄Π΅Π»Π΅ Π½Π΅ услоТняСт Тизнь Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°.

ПослС опрСдСлСния ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ ΠΊ Π΅Π΅ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ΅ Π² ядро. Наш минималистский Π½Π°Π±ΠΎΡ€ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² attr Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Π² сСбя Ρ‚ΠΈΠΏ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, Π½Π°Π±ΠΎΡ€ ΠΈ количСство инструкций, ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΡƒΡŽ Π»ΠΈΡ†Π΅Π½Π·ΠΈΡŽ, Π° Ρ‚Π°ΠΊΠΆΠ΅ имя "woo", ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π°ΠΉΡ‚ΠΈ Π½Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ Π² систСмС послС Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ. ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°, ΠΊΠ°ΠΊ ΠΈ Π±Ρ‹Π»ΠΎ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΎ, загруТаСтся Π² систСму ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf.

Π’ ΠΊΠΎΠ½Ρ†Π΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΌΡ‹ ΠΏΠΎΠΏΠ°Π΄Π°Π΅ΠΌ Π² бСсконСчный Ρ†ΠΈΠΊΠ», ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΠΌΠΈΡ‚ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΏΠΎΠ»Π΅Π·Π½ΡƒΡŽ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ. Π‘Π΅Π· Π½Π΅Π³ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΠ½ΠΈΡ‡Ρ‚ΠΎΠΆΠ΅Π½Π° ядром ΠΏΡ€ΠΈ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΈΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ²ΠΎΠ³ΠΎ дСскриптора, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ΠΈΠ» Π½Π°ΠΌ систСмный Π²Ρ‹Π·ΠΎΠ² bpf, ΠΈ ΠΌΡ‹ Π½Π΅ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ Π΅Π΅ Π² систСмС.

Ну Ρ‡Ρ‚ΠΎ ΠΆΠ΅, ΠΌΡ‹ Π³ΠΎΡ‚ΠΎΠ²Ρ‹ ΠΊ Ρ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡŽ. Π‘ΠΎΠ±Π΅Ρ€Π΅ΠΌ ΠΈ запустим ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΏΠΎΠ΄ strace, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ всС Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΊΠ°ΠΊ Π½Π°Π΄ΠΎ:

$ clang -g -O2 simple-prog.c -o simple-prog

$ sudo strace ./simple-prog
execve("./simple-prog", ["./simple-prog"], 0x7ffc7b553480 /* 13 vars */) = 0
...
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_XDP, insn_cnt=2, insns=0x7ffe03c4ed50, license="GPL", log_level=0, log_size=0, log_buf=NULL, kern_version=KERNEL_V
ERSION(0, 0, 0), prog_flags=0, prog_name="woo", prog_ifindex=0, expected_attach_type=BPF_CGROUP_INET_INGRESS}, 72) = 3
pause(

ВсС Π² порядкС, bpf(2) Π²Π΅Ρ€Π½ΡƒΠ» Π½Π°ΠΌ дСскриптор 3 ΠΈ ΠΌΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈΡΡŒ Π² бСсконСчный Ρ†ΠΈΠΊΠ» с pause(). Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π½Π°ΠΉΡ‚ΠΈ Π½Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ Π² систСмС. Для этого ΠΌΡ‹ ΠΏΠΎΠΉΠ΄Π΅ΠΌ Π² Π΄Ρ€ΡƒΠ³ΠΎΠΉ Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π» ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρƒ bpftool:

# bpftool prog | grep -A3 woo
390: xdp  name woo  tag 3b185187f1855c4c  gpl
        loaded_at 2020-08-31T24:66:44+0000  uid 0
        xlated 16B  jited 40B  memlock 4096B
        pids simple-prog(10381)

ΠœΡ‹ Π²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π² систСмС имССтся загруТСнная ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° woo Ρ‡Π΅ΠΉ Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹ΠΉ ID Ρ€Π°Π²Π΅Π½ 390, ΠΈ Ρ‡Ρ‚ΠΎ Π² Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π² процСссС simple-prog имССтся ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΉ Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор, ΡƒΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉ Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ (ΠΈ Ссли simple-prog Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ, Ρ‚ΠΎ woo исчСзнСт). Как ΠΈ оТидалось, ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° woo Π·Π°Π½ΠΈΠΌΠ°Π΅Ρ‚ 16 Π±Π°ΠΉΡ‚ β€”Β Π΄Π²Π΅ инструкции β€” Π±ΠΈΠ½Π°Ρ€Π½Ρ‹Ρ… ΠΊΠΎΠ΄ΠΎΠ² Π² Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅ BPF, Π½ΠΎ Π² Π½Π°Ρ‚ΠΈΠ²Π½ΠΎΠΌ Π²ΠΈΠ΄Π΅ (x86_64) — это ΡƒΠΆΠ΅ 40 Π±Π°ΠΉΡ‚. Π”Π°Π²Π°ΠΉΡ‚Π΅ посмотрим Π½Π° Π½Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ Π² ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΌ Π²ΠΈΠ΄Π΅:

# bpftool prog dump xlated id 390
   0: (b7) r0 = 2
   1: (95) exit

Π±Π΅Π· ΡΡŽΡ€ΠΏΡ€ΠΈΠ·ΠΎΠ². Π’Π΅ΠΏΠ΅Ρ€ΡŒ посмотрим Π½Π° ΠΊΠΎΠ΄, созданный JIT компилятором:

# bpftool prog dump jited id 390
bpf_prog_3b185187f1855c4c_woo:
   0:   nopl   0x0(%rax,%rax,1)
   5:   push   %rbp
   6:   mov    %rsp,%rbp
   9:   sub    $0x0,%rsp
  10:   push   %rbx
  11:   push   %r13
  13:   push   %r14
  15:   push   %r15
  17:   pushq  $0x0
  19:   mov    $0x2,%eax
  1e:   pop    %rbx
  1f:   pop    %r15
  21:   pop    %r14
  23:   pop    %r13
  25:   pop    %rbx
  26:   leaveq
  27:   retq

Π½Π΅ ΠΎΡ‡Π΅Π½ΡŒ-Ρ‚ΠΎ эффСктивно для exit(2), Π½ΠΎ справСдливости Ρ€Π°Π΄ΠΈ, наша ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° слишком ΡƒΠΆ проста, Π° для Π½Π΅Ρ‚Ρ€ΠΈΠ²ΠΈΠ°Π»ΡŒΠ½Ρ‹Ρ… ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ ΠΏΡ€ΠΎΠ»ΠΎΠ³ ΠΈ эпилог, Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Π½Ρ‹Π΅ JIT компилятором, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, Π½ΡƒΠΆΠ½Ρ‹.

Maps

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΌΠΎΠ³ΡƒΡ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ структурированныС области памяти, доступныС ΠΊΠ°ΠΊ Π΄Ρ€ΡƒΠ³ΠΈΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°ΠΌ BPF, Ρ‚Π°ΠΊ ΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°ΠΌ ΠΈΠ· пространства ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ. Π­Ρ‚ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ Π½Π°Π·Ρ‹Π²Π°ΡŽΡ‚ΡΡ maps ΠΈ Π² этом Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΌΡ‹ ΠΏΠΎΠΊΠ°ΠΆΠ΅ΠΌ ΠΊΠ°ΠΊ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΈΠΌΠΈ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf.

Π‘Ρ€Π°Π·Ρƒ скаТСм, Ρ‡Ρ‚ΠΎ возмоТности maps Π½Π΅ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°ΡŽΡ‚ΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ доступом ΠΊ ΠΎΠ±Ρ‰Π΅ΠΉ памяти. Π‘ΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‚ ΠΌΠ°ΠΏΡ‹ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ назначСния, содСрТащиС, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΈΠ»ΠΈ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π½Π° сСтСвыС интСрфСйсы, ΠΌΠ°ΠΏΡ‹ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с perf events ΠΈ Ρ‚.ΠΏ. Π—Π΄Π΅ΡΡŒ ΠΌΡ‹ ΠΎ Π½ΠΈΡ… Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ΡŒ Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΏΡƒΡ‚Π°Ρ‚ΡŒ читатСля. ΠšΡ€ΠΎΠΌΠ΅ этого, ΠΌΡ‹ ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ синхронизации, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ это Π½Π΅ Π²Π°ΠΆΠ½ΠΎ для Π½Π°ΡˆΠΈΡ… ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ². ΠŸΠΎΠ»Π½Ρ‹ΠΉ список доступных Ρ‚ΠΈΠΏΠΎΠ² ΠΌΠ°ΠΏΠΎΠ² ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ Π² <linux/bpf.h>, Π° Π² этом Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΌΡ‹ Π² качСствС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° возьмСм историчСски ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ Ρ‚ΠΈΠΏ, Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ BPF_MAP_TYPE_HASH.

Если Π²Ρ‹ создаСтС Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ, скаТСм, Π² C++, Π²Ρ‹ скаТСтС unordered_map<int,long> woo, Ρ‡Ρ‚ΠΎ ΠΏΠΎ-русски ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ Β«ΠΌΠ½Π΅ Π½ΡƒΠΆΠ½Π° Ρ‚Π°Π±Π»ΠΈΡ†Π° woo Π½Π΅ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½Π½ΠΎΠ³ΠΎ Ρ€Π°Π·ΠΌΠ΅Ρ€Π°, Ρƒ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΊΠ»ΡŽΡ‡ΠΈ ΠΈΠΌΠ΅ΡŽΡ‚ Ρ‚ΠΈΠΏ int, Π° значСния β€” Ρ‚ΠΈΠΏ longΒ». Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ BPF ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Ρ‚ΠΎ ΠΆΠ΅ самоС, с ΠΏΠΎΠΏΡ€Π°Π²ΠΊΠΎΠΉ Π½Π° Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ Π½Π°ΠΌ придСтся ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, Π° вмСсто Ρ‚ΠΈΠΏΠΎΠ² ΠΊΠ»ΡŽΡ‡Π΅ΠΉ ΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΈΡ… Ρ€Π°Π·ΠΌΠ΅Ρ€Ρ‹ Π² Π±Π°ΠΉΡ‚Π°Ρ…. Для создания ΠΌΠ°ΠΏΠΎΠ² ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΊΠΎΠΌΠ°Π½Π΄Π° BPF_MAP_CREATE систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf. Π”Π°Π²Π°ΠΉΡ‚Π΅ посмотрим Π½Π° Π±ΠΎΠ»Π΅Π΅-ΠΌΠ΅Π½Π΅Π΅ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ, которая создаСт map. ПослС ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, Π·Π°Π³Ρ€ΡƒΠΆΠ°ΡŽΡ‰Π΅ΠΉ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF, эта Π΄ΠΎΠ»ΠΆΠ½Π° Π²Π°ΠΌ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒΡΡ простой:

$ cat simple-map.c
#define _GNU_SOURCE
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/bpf.h>

int main(void)
{
    union bpf_attr attr = {
        .map_type = BPF_MAP_TYPE_HASH,
        .key_size = sizeof(int),
        .value_size = sizeof(int),
        .max_entries = 4,
    };
    strncpy(attr.map_name, "woo", sizeof(attr.map_name));
    syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));

    for ( ;; )
        pause();
}

Π—Π΄Π΅ΡΡŒ ΠΌΡ‹ опрСдСляСм Π½Π°Π±ΠΎΡ€ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² attr, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π³ΠΎΠ²ΠΎΡ€ΠΈΠΌ Β«ΠΌΠ½Π΅ Π½ΡƒΠΆΠ½Π° Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Π° с ΠΊΠ»ΡŽΡ‡Π°ΠΌΠΈ ΠΈ значСниями Ρ€Π°Π·ΠΌΠ΅Ρ€Π° sizeof(int), Π² ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ я ΠΌΠΎΠ³Ρƒ ΠΏΠΎΠ»ΠΎΠΆΠΈΡ‚ΡŒ максимум Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅ элСмСнта». ΠŸΡ€ΠΈ создании BPF ΠΌΠ°ΠΏΠΎΠ² ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Ρ‚Π°ΠΊ ΠΆΠ΅, ΠΊΠ°ΠΊ ΠΈ Π² ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ с ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΎΠΉ, ΠΌΡ‹ ΡƒΠΊΠ°Π·Π°Π»ΠΈ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° ΠΊΠ°ΠΊ "woo".

Π‘ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΡƒΠ΅ΠΌ ΠΈ запустим ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ:

$ clang -g -O2 simple-map.c -o simple-map
$ sudo strace ./simple-map
execve("./simple-map", ["./simple-map"], 0x7ffd40a27070 /* 14 vars */) = 0
...
bpf(BPF_MAP_CREATE, {map_type=BPF_MAP_TYPE_HASH, key_size=4, value_size=4, max_entries=4, map_name="woo", ...}, 72) = 3
pause(

Π—Π΄Π΅ΡΡŒ систСмный Π²Ρ‹Π·ΠΎΠ² bpf(2) Π²Π΅Ρ€Π½ΡƒΠ» Π½Π°ΠΌ дСскриптор ΠΌΠ°ΠΏΠ° Π½ΠΎΠΌΠ΅Ρ€ 3 ΠΈ дальшС ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°, ΠΊΠ°ΠΊ ΠΈ оТидалось, ΠΆΠ΄Π΅Ρ‚ Π΄Π°Π»ΡŒΠ½Π΅ΠΉΡˆΠΈΡ… ΡƒΠΊΠ°Π·Π°Π½ΠΈΠΉ Π² систСмном Π²Ρ‹Π·ΠΎΠ²Π΅ pause(2).

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠΌ Π½Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ Π² background ΠΈΠ»ΠΈ ΠΎΡ‚ΠΊΡ€ΠΎΠ΅ΠΌ Π΄Ρ€ΡƒΠ³ΠΎΠΉ Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π» ΠΈ посмотрим Π½Π° наш ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ bpftool (ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΡ‚ΡŒ наш map ΠΎΡ‚ Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΏΠΎ Π΅Π³ΠΎ ΠΈΠΌΠ΅Π½ΠΈ):

$ sudo bpftool map
...
114: hash  name woo  flags 0x0
        key 4B  value 4B  max_entries 4  memlock 4096B
...

Число 114 β€” это Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹ΠΉ ID нашСго ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°. Π›ΡŽΠ±Π°Ρ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Π² систСмС ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ этот ID, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ ΡƒΠΆΠ΅ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ map ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ BPF_MAP_GET_FD_BY_ID систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠΈΠ³Ρ€Π°Ρ‚ΡŒΡΡ с нашСй Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Π΅ΠΉ. Π”Π°Π²Π°ΠΉΡ‚Π΅ посмотрим Π½Π° Π΅Π΅ содСрТимоС:

$ sudo bpftool map dump id 114
Found 0 elements

ΠŸΡƒΡΡ‚ΠΎ. Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ Π² Π½Π΅Π΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ hash[1] = 1:

$ sudo bpftool map update id 114 key 1 0 0 0 value 1 0 0 0

ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π½Π° Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ Π΅Ρ‰Π΅ Ρ€Π°Π·:

$ sudo bpftool map dump id 114
key: 01 00 00 00  value: 01 00 00 00
Found 1 element

Π£Ρ€Π°! Π£ нас ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΎΠ΄ΠΈΠ½ элСмСнт. Π—Π°ΠΌΠ΅Ρ‚ΡŒΡ‚Π΅, Ρ‡Ρ‚ΠΎ для этого Π½Π°ΠΌ приходится Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π½Π° ΡƒΡ€ΠΎΠ²Π½Π΅ Π±Π°ΠΉΡ‚ΠΎΠ², Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ bptftool Π½Π΅ Π·Π½Π°Π΅Ρ‚ ΠΊΠ°ΠΊΠΎΠΉ Ρ‚ΠΈΠΏ ΠΈΠΌΠ΅ΡŽΡ‚ значСния Π² Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Π΅. (Π•ΠΉ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ это Π·Π½Π°Π½ΠΈΠ΅, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ BTF, Π½ΠΎ ΠΎΠ± этом Π½Π΅ сСйчас.)

Как ΠΈΠΌΠ΅Π½Π½ΠΎ bpftool Ρ‡ΠΈΡ‚Π°Π΅Ρ‚ ΠΈ добавляСт элСмСнты? Π”Π°Π²Π°ΠΉΡ‚Π΅ заглянСм ΠΏΠΎΠ΄ ΠΊΠ°ΠΏΠΎΡ‚:

$ sudo strace -e bpf bpftool map dump id 114
bpf(BPF_MAP_GET_FD_BY_ID, {map_id=114, next_id=0, open_flags=0}, 120) = 3
bpf(BPF_MAP_GET_NEXT_KEY, {map_fd=3, key=NULL, next_key=0x55856ab65280}, 120) = 0
bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3, key=0x55856ab65280, value=0x55856ab652a0}, 120) = 0
key: 01 00 00 00  value: 01 00 00 00
bpf(BPF_MAP_GET_NEXT_KEY, {map_fd=3, key=0x55856ab65280, next_key=0x55856ab65280}, 120) = -1 ENOENT

Π‘Π½Π°Ρ‡Π°Π»Π° ΠΌΡ‹ ΠΎΡ‚ΠΊΡ€Ρ‹Π»ΠΈ ΠΌΠ°ΠΏ ΠΏΠΎ Π΅Π³ΠΎ Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½ΠΎΠΌΡƒ ID ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ BPF_MAP_GET_FD_BY_ID ΠΈ bpf(2) Π²Π΅Ρ€Π½ΡƒΠ» Π½Π°ΠΌ дСскриптор 3. Π”Π°Π»ΡŒΡˆΠ΅ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ BPF_MAP_GET_NEXT_KEY ΠΌΡ‹ нашли ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ ΠΊΠ»ΡŽΡ‡ Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅, ΠΏΠ΅Ρ€Π΅Π΄Π°Π² NULL Π² качСствС указатСля Π½Π° Β«ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΉΒ» ΠΊΠ»ΡŽΡ‡. ΠŸΡ€ΠΈ Π½Π°Π»ΠΈΡ‡ΠΈΠΈ ΠΊΠ»ΡŽΡ‡Π° ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ BPF_MAP_LOOKUP_ELEM, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π² ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ value. Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ шаг β€” ΠΌΡ‹ пытаСмся Π½Π°ΠΉΡ‚ΠΈ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ элСмСнт, пСрСдавая ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΊΠ»ΡŽΡ‡, Π½ΠΎ наша Ρ‚Π°Π±Π»ΠΈΡ†Π° содСрТит Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄ΠΈΠ½ элСмСнт ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Π° BPF_MAP_GET_NEXT_KEY Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ENOENT.

Π₯ΠΎΡ€ΠΎΡˆΠΎ, Π΄Π°Π²Π°ΠΉΡ‚Π΅ помСняСм Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ ΠΊΠ»ΡŽΡ‡Ρƒ 1, скаТСм, наша бизнСс-Π»ΠΎΠ³ΠΈΠΊΠ° Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ ΠΏΡ€ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ hash[1] = 2:

$ sudo strace -e bpf bpftool map update id 114 key 1 0 0 0 value 2 0 0 0
bpf(BPF_MAP_GET_FD_BY_ID, {map_id=114, next_id=0, open_flags=0}, 120) = 3
bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3, key=0x55dcd72be260, value=0x55dcd72be280, flags=BPF_ANY}, 120) = 0

Как ΠΈ оТидалось, это ΠΎΡ‡Π΅Π½ΡŒ просто: ΠΊΠΎΠΌΠ°Π½Π΄Π° BPF_MAP_GET_FD_BY_ID ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ наш ΠΌΠ°ΠΏ ΠΏΠΎ ID, Π° ΠΊΠΎΠΌΠ°Π½Π΄Π° BPF_MAP_UPDATE_ELEM пСрСзаписываСт элСмСнт.

Π˜Ρ‚ΠΎΠ³ΠΎ, послС создания Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΠΈΠ· ΠΎΠ΄Π½ΠΎΠΉ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Ρ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΈ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π΅Π΅ содСрТимоС ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΎΠΉ. Π—Π°ΠΌΠ΅Ρ‚ΡŒΡ‚Π΅, Ρ‡Ρ‚ΠΎ Ссли ΠΌΡ‹ смогли это ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΈΠ· ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки, Ρ‚ΠΎ это ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈ любая другая ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Π² систСмС. ΠšΡ€ΠΎΠΌΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄, описанных Π²Ρ‹ΡˆΠ΅, для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΌΠ°ΠΏΠ°ΠΌΠΈ ΠΈΠ· пространства ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ доступны ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅:

  • BPF_MAP_LOOKUP_ELEM: Π½Π°ΠΉΡ‚ΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ ΠΊΠ»ΡŽΡ‡Ρƒ
  • BPF_MAP_UPDATE_ELEM: ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ/ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅
  • BPF_MAP_DELETE_ELEM: ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ ΠΊΠ»ΡŽΡ‡
  • BPF_MAP_GET_NEXT_KEY: Π½Π°ΠΉΡ‚ΠΈ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ (ΠΈΠ»ΠΈ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ) ΠΊΠ»ΡŽΡ‡
  • BPF_MAP_GET_NEXT_ID: позволяСт ΠΏΡ€ΠΎΠΉΡ‚ΠΈΡΡŒ ΠΏΠΎ всСм ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΌ ΠΌΠ°ΠΏΠ°ΠΌ, Ρ‚Π°ΠΊ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ bpftool map
  • BPF_MAP_GET_FD_BY_ID: ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ ΠΌΠ°ΠΏ ΠΏΠΎ Π΅Π³ΠΎ Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½ΠΎΠΌΡƒ ID
  • BPF_MAP_LOOKUP_AND_DELETE_ELEM: Π°Ρ‚ΠΎΠΌΠ°Ρ€Π½ΠΎ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° ΠΈ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ староС
  • BPF_MAP_FREEZE: ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΌΠ°ΠΏ нСизмСняСмым ΠΈΠ· userspace (эту ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ нСльзя ΠΎΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ)
  • BPF_MAP_LOOKUP_BATCH, BPF_MAP_LOOKUP_AND_DELETE_BATCH, BPF_MAP_UPDATE_BATCH, BPF_MAP_DELETE_BATCH: массовыС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ. НапримСр, BPF_MAP_LOOKUP_AND_DELETE_BATCH — это СдинствСнный Π½Π°Π΄Π΅ΠΆΠ½Ρ‹ΠΉ способ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΈ ΠΎΠ±Π½ΡƒΠ»ΠΈΡ‚ΡŒ всС значСния ΠΈΠ· ΠΌΠ°ΠΏΠ°

НС всС ΠΈΠ· этих ΠΊΠΎΠΌΠ°Π½Π΄ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ для всСх Ρ‚ΠΈΠΏΠΎΠ² ΠΌΠ°ΠΏΠΎΠ², Π½ΠΎ Π²ΠΎΠΎΠ±Ρ‰Π΅ Ρ€Π°Π±ΠΎΡ‚Π° с Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ Ρ‚ΠΈΠΏΠ°ΠΌΠΈ maps ΠΈΠ· пространства ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ выглядит Ρ‚ΠΎΡ‡Π½ΠΎ Ρ‚Π°ΠΊ ΠΆΠ΅, ΠΊΠ°ΠΊ ΠΈ Ρ€Π°Π±ΠΎΡ‚Π° с Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Π°ΠΌΠΈ.

Для порядка, Π΄Π°Π²Π°ΠΉΡ‚Π΅ Π·Π°Π²Π΅Ρ€ΡˆΠΈΠΌ наши экспСримСнты с Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Π΅ΠΉ. ΠŸΠΎΠΌΠ½ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ создали Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒΡΡ Π΄ΠΎ Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅Ρ… ΠΊΠ»ΡŽΡ‡Π΅ΠΉ? Π”ΠΎΠ±Π°Π²ΠΈΠΌ Π΅Ρ‰Π΅ нСсколько элСмСнтов:

$ sudo bpftool map update id 114 key 2 0 0 0 value 1 0 0 0
$ sudo bpftool map update id 114 key 3 0 0 0 value 1 0 0 0
$ sudo bpftool map update id 114 key 4 0 0 0 value 1 0 0 0

Пока всС Ρ…ΠΎΡ€ΠΎΡˆΠΎ:

$ sudo bpftool map dump id 114
key: 01 00 00 00  value: 01 00 00 00
key: 02 00 00 00  value: 01 00 00 00
key: 04 00 00 00  value: 01 00 00 00
key: 03 00 00 00  value: 01 00 00 00
Found 4 elements

ΠŸΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π΅Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½:

$ sudo bpftool map update id 114 key 5 0 0 0 value 1 0 0 0
Error: update failed: Argument list too long

Как ΠΈ оТидалось, Ρƒ нас Π½Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ. ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π½Π° ΠΎΡˆΠΈΠ±ΠΊΡƒ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅:

$ sudo strace -e bpf bpftool map update id 114 key 5 0 0 0 value 1 0 0 0
bpf(BPF_MAP_GET_FD_BY_ID, {map_id=114, next_id=0, open_flags=0}, 120) = 3
bpf(BPF_OBJ_GET_INFO_BY_FD, {info={bpf_fd=3, info_len=80, info=0x7ffe6c626da0}}, 120) = 0
bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3, key=0x56049ded5260, value=0x56049ded5280, flags=BPF_ANY}, 120) = -1 E2BIG (Argument list too long)
Error: update failed: Argument list too long
+++ exited with 255 +++

ВсС Π² порядкС: ΠΊΠ°ΠΊ ΠΈ оТидалось, ΠΊΠΎΠΌΠ°Π½Π΄Π° BPF_MAP_UPDATE_ELEM пытаСтся ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ, пятый, ΠΊΠ»ΡŽΡ‡, Π½ΠΎ ΠΏΠ°Π΄Π°Π΅Ρ‚ с E2BIG.

Π˜Ρ‚Π°ΠΊ, ΠΌΡ‹ ΡƒΠΌΠ΅Π΅ΠΌ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΈ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΌΠ°ΠΏΠ°ΠΌΠΈ ΠΈΠ· пространства ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ. Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π»ΠΎΠ³ΠΈΡ‡Π½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° Ρ‚ΠΎ, ΠΊΠ°ΠΊ ΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ°ΠΏΡ‹ ΠΈΠ· самих ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF. ΠœΡ‹ ΠΌΠΎΠ³Π»ΠΈ Π±Ρ‹ Ρ€Π°ΡΡΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΎΠ± этом, Π½Π° языкС Ρ‚Ρ€ΡƒΠ΄Π½ΠΎ-Ρ‡ΠΈΡ‚Π°Π΅ΠΌΡ‹Ρ… ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ Π² ΠΌΠ°ΡˆΠΈΠ½Π½Ρ‹Ρ… ΠΊΠΎΠ΄Π°Ρ…-макросах, Π½ΠΎ Π½Π° самом Π΄Π΅Π»Π΅ ΠΏΡ€ΠΈΡˆΠ»Π° ΠΏΠΎΡ€Π° ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ ΠΏΠΈΡˆΡƒΡ‚ΡΡ ΠΈ ΠΎΠ±ΡΠ»ΡƒΠΆΠΈΠ²Π°ΡŽΡ‚ΡΡ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF Π½Π° самом Π΄Π΅Π»Π΅ β€”Β ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ libbpf.

(Для Ρ‡ΠΈΡ‚Π°Ρ‚Π΅Π»Π΅ΠΉ, Π½Π΅Π΄ΠΎΠ²ΠΎΠ»ΡŒΠ½Ρ‹Ρ… отсутствиСм Π½ΠΈΠ·ΠΊΠΎΡƒΡ€ΠΎΠ²Π½Π΅Π³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°: ΠΌΡ‹ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ Ρ€Π°Π·Π±Π΅Ρ€Π΅ΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΠ΅ ΠΌΠ°ΠΏΡ‹ ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠΈ, созданныС ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ libbpf ΠΈ расскаТСм, Ρ‡Ρ‚ΠΎ происходит Π½Π° ΡƒΡ€ΠΎΠ²Π½Π΅ инструкций. Для Ρ‡ΠΈΡ‚Π°Ρ‚Π΅Π»Π΅ΠΉ, Π½Π΅Π΄ΠΎΠ²ΠΎΠ»ΡŒΠ½Ρ‹Ρ… ΠΎΡ‡Π΅Π½ΡŒ сильно, ΠΌΡ‹ Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π² ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΌ мСстС ΡΡ‚Π°Ρ‚ΡŒΠΈ.)

ПишСм ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ libbpf

ΠŸΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΠΌΠ°ΡˆΠΈΠ½Π½Ρ‹Ρ… ΠΊΠΎΠ΄ΠΎΠ² ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ интСрСсно Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠ΅Ρ€Π²ΠΎΠ΅ врСмя, Π° ΠΏΠΎΡ‚ΠΎΠΌ наступаСт прСсыщСниС. Π’ этот ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒ свой Π²Π·ΠΎΡ€ Π½Π° llvm, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π΅ΡΡ‚ΡŒ Π±Π°ΠΊΠ΅Π½Π΄ для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ ΠΊΠΎΠ΄Π° для Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹ BPF, Π° Ρ‚Π°ΠΊΠΆΠ΅ Π½Π° Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ libbpf, которая позволяСт ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ BPF ΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ ΠΊΠΎΠ΄ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF, сгСнСрированных ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ llvm/clang.

На самом Π΄Π΅Π»Π΅, ΠΊΠ°ΠΊ ΠΌΡ‹ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ Π² этой ΠΈ ΠΏΠΎΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… ΡΡ‚Π°Ρ‚ΡŒΡΡ…, libbpf Π΄Π΅Π»Π°Π΅Ρ‚ довольно ΠΌΠ½ΠΎΠ³ΠΎ Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΈ Π±Π΅Π· Π½Π΅Π΅ (ΠΈΠ»ΠΈ Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½Ρ‹Ρ… инструмСнтов β€” iproute2, libbcc, libbpf-go, ΠΈ Ρ‚.ΠΏ.) ΠΆΠΈΡ‚ΡŒ Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ. Одной ΠΈΠ· killer-Ρ„ΠΈΡ‡ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° libbpf являСтся BPF CO-RE (Compile Once, Run Everywhere) β€”Β ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ позволяСт ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF, пСрСносимыС с ΠΎΠ΄Π½ΠΎΠ³ΠΎ ядра Π½Π° Π΄Ρ€ΡƒΠ³ΠΎΠ΅, с Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒΡŽ запуска Π½Π° Ρ€Π°Π·Π½Ρ‹Ρ… API (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΊΠΎΠ³Π΄Π° структура ядра мСняСтся ΠΎΡ‚ вСрсии ΠΊ вСрсии). Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠΌΠ΅Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с CO-RE, вашС ядро Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ скомпилировано с ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ BTF (ΠΊΠ°ΠΊ это ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΌΡ‹ рассказываСм Π² Ρ€Π°Π·Π΄Π΅Π»Π΅ БрСдства Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ. ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ, собрано Π»ΠΈ вашС ядро с BTF ΠΈΠ»ΠΈ Π½Π΅Ρ‚, ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‡Π΅Π½ΡŒ просто β€” ΠΏΠΎ Π½Π°Π»ΠΈΡ‡ΠΈΡŽ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ Ρ„Π°ΠΉΠ»Π°:

$ ls -lh /sys/kernel/btf/vmlinux
-r--r--r-- 1 root root 2.6M Jul 29 15:30 /sys/kernel/btf/vmlinux

Π­Ρ‚ΠΎΡ‚ Ρ„Π°ΠΉΠ» Ρ…Ρ€Π°Π½ΠΈΡ‚ Π² сСбС ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΎΠ±ΠΎ всСх Ρ‚ΠΈΠΏΠ°Ρ… Π΄Π°Π½Π½Ρ‹Ρ…, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Ρ… Π² ядрС ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π²ΠΎ всСх Π½Π°ΡˆΠΈΡ… ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°Ρ…, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΡ… libbpf. ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎ CO-RE Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΡΡ‚Π°Ρ‚ΡŒΠ΅, Π° Π² этой — просто постройтС сСбС ядро с CONFIG_DEBUG_INFO_BTF.

Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° libbpf ΠΆΠΈΠ²Π΅Ρ‚ прямо Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ tools/lib/bpf ядра ΠΈ Π΅Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° вСдСтся Ρ‡Π΅Ρ€Π΅Π· список рассылки [email protected]. Однако для Π½ΡƒΠΆΠ΄ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ, ΠΆΠΈΠ²ΡƒΡ‰ΠΈΡ… Π·Π° ΠΏΡ€Π΅Π΄Π΅Π»Π°ΠΌΠΈ ядра, поддСрТиваСтся ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ https://github.com/libbpf/libbpf Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ядСрная Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° зСркалируСтся для доступа Π½Π° Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ Π±ΠΎΠ»Π΅Π΅-ΠΌΠ΅Π½Π΅Π΅ ΠΊΠ°ΠΊ Π΅ΡΡ‚ΡŒ.

Π’ Π΄Π°Π½Π½ΠΎΠΌ Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΌΡ‹ посмотрим Π½Π° Ρ‚ΠΎ, ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΠΉ libbpf, напишСм нСсколько (Π±ΠΎΠ»Π΅Π΅-ΠΌΠ΅Π½Π΅Π΅ бСссмыслСнных) тСстовых ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ ΠΈ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ Ρ€Π°Π·Π±Π΅Ρ€Π΅ΠΌ ΠΊΠ°ΠΊ всС это Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚. Π­Ρ‚ΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ‚ Π½Π°ΠΌ Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… Ρ€Π°Π·Π΄Π΅Π»Π°Ρ… ΠΏΡ€ΠΎΡ‰Π΅ ΠΎΠ±ΡŠΡΡΠ½ΠΈΡ‚ΡŒ, ΠΊΠ°ΠΊ ΠΈΠΌΠ΅Π½Π½ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡ‚Π²ΡƒΡŽΡ‚ с maps, kernel helpers, BTF, ΠΈ Ρ‚.ΠΏ.

ΠžΠ±Ρ‹Ρ‡Π½ΠΎ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρ‹, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΠ΅ libbpf Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ гитхабовский Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ Π² качСствС git submodule, сдСлаСм это ΠΈ ΠΌΡ‹:

$ mkdir /tmp/libbpf-example
$ cd /tmp/libbpf-example/
$ git init-db
Initialized empty Git repository in /tmp/libbpf-example/.git/
$ git submodule add https://github.com/libbpf/libbpf.git
Cloning into '/tmp/libbpf-example/libbpf'...
remote: Enumerating objects: 200, done.
remote: Counting objects: 100% (200/200), done.
remote: Compressing objects: 100% (103/103), done.
remote: Total 3354 (delta 101), reused 118 (delta 79), pack-reused 3154
Receiving objects: 100% (3354/3354), 2.05 MiB | 10.22 MiB/s, done.
Resolving deltas: 100% (2176/2176), done.

БобираСтся libbpf ΠΎΡ‡Π΅Π½ΡŒ просто:

$ cd libbpf/src
$ mkdir build
$ OBJDIR=build DESTDIR=root make -s install
$ find root
root
root/usr
root/usr/include
root/usr/include/bpf
root/usr/include/bpf/bpf_tracing.h
root/usr/include/bpf/xsk.h
root/usr/include/bpf/libbpf_common.h
root/usr/include/bpf/bpf_endian.h
root/usr/include/bpf/bpf_helpers.h
root/usr/include/bpf/btf.h
root/usr/include/bpf/bpf_helper_defs.h
root/usr/include/bpf/bpf.h
root/usr/include/bpf/libbpf_util.h
root/usr/include/bpf/libbpf.h
root/usr/include/bpf/bpf_core_read.h
root/usr/lib64
root/usr/lib64/libbpf.so.0.1.0
root/usr/lib64/libbpf.so.0
root/usr/lib64/libbpf.a
root/usr/lib64/libbpf.so
root/usr/lib64/pkgconfig
root/usr/lib64/pkgconfig/libbpf.pc

Наш дальнСйший ΠΏΠ»Π°Π½ Π² этом Ρ€Π°Π·Π΄Π΅Π»Π΅ Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌ: ΠΌΡ‹ напишСм ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ BPF Ρ‚ΠΈΠΏΠ° BPF_PROG_TYPE_XDP, Ρ‚Ρƒ ΠΆΠ΅ ΡΠ°ΠΌΡƒΡŽ, Ρ‡Ρ‚ΠΎ ΠΈ Π² ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅, Π½ΠΎ Π½Π° C, скомпилируСм Π΅Π΅ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ clang, ΠΈ напишСм ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊ, которая Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ Π΅Π΅ Π² ядро. Π’ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… Ρ€Π°Π·Π΄Π΅Π»Π°Ρ… ΠΌΡ‹ Ρ€Π°ΡΡˆΠΈΡ€ΠΈΠΌ возмоТности ΠΊΠ°ΠΊ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF, Ρ‚Π°ΠΊ ΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ°.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€: создаСм ΠΏΠΎΠ»Π½ΠΎΡ†Π΅Π½Π½ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ libbpf

Для Π½Π°Ρ‡Π°Π»Π° ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ„Π°ΠΉΠ» /sys/kernel/btf/vmlinux, ΠΎ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π³ΠΎΠ²ΠΎΡ€ΠΈΠ»ΠΎΡΡŒ Π²Ρ‹ΡˆΠ΅, ΠΈ создадим Π΅Π³ΠΎ эквивалСнт Π² Π²ΠΈΠ΄Π΅ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π°:

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

Π’ этом Ρ„Π°ΠΉΠ»Π΅ Π±ΡƒΠ΄ΡƒΡ‚ хранится всС структуры Π΄Π°Π½Π½Ρ‹Ρ…, ΠΈΠΌΠ΅ΡŽΡ‰ΠΈΠ΅ΡΡ Π² нашСм ядрС, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π²ΠΎΡ‚ Ρ‚Π°ΠΊ Π² ядрС опрСдСляСтся Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ IPv4:

$ grep -A 12 'struct iphdr {' vmlinux.h
struct iphdr {
    __u8 ihl: 4;
    __u8 version: 4;
    __u8 tos;
    __be16 tot_len;
    __be16 id;
    __be16 frag_off;
    __u8 ttl;
    __u8 protocol;
    __sum16 check;
    __be32 saddr;
    __be32 daddr;
};

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ напишСм Π½Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ BPF Π½Π° языкС C:

$ cat xdp-simple.bpf.c
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>

SEC("xdp/simple")
int simple(void *ctx)
{
        return XDP_PASS;
}

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

Π₯ΠΎΡ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Ρƒ нас ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»Π°ΡΡŒ ΠΎΡ‡Π΅Π½ΡŒ простая, Π½ΠΎ всС ΠΆΠ΅ ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° мноТСство Π΄Π΅Ρ‚Π°Π»Π΅ΠΉ. Π’ΠΎ-ΠΏΠ΅Ρ€Π²Ρ‹Ρ…, ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΌ Ρ„Π°ΠΉΠ»ΠΎΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ являСтся vmlinux.h, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‡Ρ‚ΠΎ сгСнСрировали ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ bpftool btf dump β€”Β Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Π½Π°ΠΌ Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ ΡƒΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒ ΠΏΠ°ΠΊΠ΅Ρ‚ kernel-headers, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ·Π½Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ выглядят структуры ядра. Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ ΠΊ Π½Π°ΠΌ ΠΈΠ· Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ libbpf. БСйчас ΠΎΠ½ Π½Π°ΠΌ Π½ΡƒΠΆΠ΅Π½ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ опрСдСлился макрос SEC, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ отправляСт символ Π² ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΡƒΡŽ ΡΠ΅ΠΊΡ†ΠΈΡŽ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° ELF. Наша ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° содСрТится Π² сСкции xdp/simple, Π³Π΄Π΅ ΠΏΠ΅Ρ€Π΅Π΄ слэшСм ΠΌΡ‹ опрСдСляСм Ρ‚ΠΈΠΏ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF — это соглашСниС, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠ΅ Π² libbpf, Π½Π° основС названия сСкции ΠΎΠ½Π° подставит ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ Ρ‚ΠΈΠΏ ΠΏΡ€ΠΈ запускС bpf(2). Π‘Π°ΠΌΠ° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° BPF Π½Π° C β€”Β ΠΎΡ‡Π΅Π½ΡŒ простая ΠΈ состоит ΠΈΠ· ΠΎΠ΄Π½ΠΎΠΉ строчки return XDP_PASS. НаконСц, ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Π°Ρ сСкция "license" содСрТит Π½Π°Π·Π²Π°Π½ΠΈΠ΅ Π»ΠΈΡ†Π΅Π½Π·ΠΈΠΈ.

ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π½Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ llvm/clang, вСрсии >= 10.0.0, Π° Π»ΡƒΡ‡ΡˆΠ΅ β€”Β Π±ΠΎΠ»ΡŒΡˆΠ΅ (см. Ρ€Π°Π·Π΄Π΅Π» БрСдства Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ):

$ clang --version
clang version 11.0.0 (https://github.com/llvm/llvm-project.git afc287e0abec710398465ee1f86237513f2b5091)
...

$ clang -O2 -g -c -target bpf -I libbpf/src/root/usr/include xdp-simple.bpf.c -o xdp-simple.bpf.o

Из интСрСсных особСнностСй: ΠΌΡ‹ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ Ρ†Π΅Π»Π΅Π²ΡƒΡŽ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρƒ -target bpf ΠΈ ΠΏΡƒΡ‚ΡŒ ΠΊ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ°ΠΌ libbpf, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ Π½Π΅Π΄Π°Π²Π½ΠΎ установили. Π’Π°ΠΊΠΆΠ΅, Π½Π΅ Π·Π°Π±Ρ‹Π²Π°ΠΉΡ‚Π΅ ΠΏΡ€ΠΎ -O2, Π±Π΅Π· этой ΠΎΠΏΡ†ΠΈΠΈ вас ΠΌΠΎΠ³ΡƒΡ‚ ΠΎΠΆΠΈΠ΄Π°Ρ‚ΡŒ ΡΡŽΡ€ΠΏΡ€ΠΈΠ·Ρ‹ Π² дальнСйшСм. ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π½Π° наш ΠΊΠΎΠ΄, ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ Π»ΠΈ Ρƒ нас Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΌΡ‹ Ρ…ΠΎΡ‚Π΅Π»ΠΈ?

$ llvm-objdump --section=xdp/simple --no-show-raw-insn -D xdp-simple.bpf.o

xdp-simple.bpf.o:       file format elf64-bpf

Disassembly of section xdp/simple:

0000000000000000 <simple>:
       0:       r0 = 2
       1:       exit

Π”Π°, ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ! Π’Π΅ΠΏΠ΅Ρ€ΡŒ, Ρƒ нас Π΅ΡΡ‚ΡŒ Π±ΠΈΠ½Π°Ρ€Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» с ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΎΠΉ, ΠΈ ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π΅Π³ΠΎ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ Π² ядро. Для этого Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° libbpf ΠΏΡ€Π΅Π΄Π»Π°Π³Π°Π΅Ρ‚ Π½Π°ΠΌ Π΄Π²Π° Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π° β€”Β ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ Π½ΠΈΠ·ΠΊΠΎΡƒΡ€ΠΎΠ²Π½Π΅Π²ΠΎΠ΅ API ΠΈΠ»ΠΈ Π±ΠΎΠ»Π΅Π΅ высокоуровнСвоС API. ΠœΡ‹ ΠΏΠΎΠΉΠ΄Π΅ΠΌ Π²Ρ‚ΠΎΡ€Ρ‹ΠΌ ΠΏΡƒΡ‚Π΅ΠΌ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ Π½Π°ΠΌ хочСтся Π½Π°ΡƒΡ‡ΠΈΡ‚ΡŒΡΡ ΠΏΠΈΡΠ°Ρ‚ΡŒ, Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ ΠΈ ΠΏΠΎΠ΄ΡΠΎΠ΅Π΄ΠΈΠ½ΡΡ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΌΠΈ усилиями для ΠΈΡ… ΠΏΠΎΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ изучСния.

Для Π½Π°Ρ‡Π°Π»Π°, Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΡΠ³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ «скСлСт» нашСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΈΠ· Π΅Π΅ Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊΠ° ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ всС Ρ‚ΠΎΠΉ ΠΆΠ΅ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ bpftool β€”Β ΡˆΠ²Π΅ΠΉΡ†Π°Ρ€ΡΠΊΠΎΠ³ΠΎ Π½ΠΎΠΆΠ° ΠΌΠΈΡ€Π° BPF (Ρ‡Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ½ΠΈΠΌΠ°Ρ‚ΡŒ ΠΈ Π±ΡƒΠΊΠ²Π°Π»ΡŒΠ½ΠΎ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ Daniel Borkman β€” ΠΎΠ΄ΠΈΠ½ ΠΈΠ· создатСлСй ΠΈ ΠΌΠ°Π½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠ² BPF β€”Β ΡˆΠ²Π΅ΠΉΡ†Π°Ρ€Π΅Ρ†):

$ bpftool gen skeleton xdp-simple.bpf.o > xdp-simple.skel.h

Π’ Ρ„Π°ΠΉΠ»Π΅ xdp-simple.skel.h содСрТится Π±ΠΈΠ½Π°Ρ€Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ нашСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ для управлСния β€”Β Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ, присоСдинСния, удалСния нашСго ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°. Π’ нашСм простом случаС это выглядит ΠΊΠ°ΠΊ overkill, Π½ΠΎ это Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΈ Π² случаС, ΠΊΠΎΠ³Π΄Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» содСрТит мноТСство ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF ΠΈ ΠΌΠ°ΠΏΠΎΠ² ΠΈ для Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ этого гигантского ELF Π½Π°ΠΌ достаточно лишь ΡΠ³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ скСлСт ΠΈ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ ΠΎΠ΄Π½Ρƒ-Π΄Π²Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ· ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ прилоТСния, ΠΊ написанию ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΌΡ‹ сСйчас ΠΈ ΠΏΠ΅Ρ€Π΅ΠΉΠ΄Π΅ΠΌ.

БобствСнно говоря, наша ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°-Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊ β€”Β Ρ‚Ρ€ΠΈΠ²ΠΈΠ°Π»ΡŒΠ½Π°Ρ:

#include <err.h>
#include <unistd.h>
#include "xdp-simple.skel.h"

int main(int argc, char **argv)
{
    struct xdp_simple_bpf *obj;

    obj = xdp_simple_bpf__open_and_load();
    if (!obj)
        err(1, "failed to open and/or load BPF objectn");

    pause();

    xdp_simple_bpf__destroy(obj);
}

Π—Π΄Π΅ΡΡŒ struct xdp_simple_bpf опрСдСляСтся Π² Ρ„Π°ΠΉΠ»Π΅ xdp-simple.skel.h ΠΈ описываСт наш ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ»:

struct xdp_simple_bpf {
    struct bpf_object_skeleton *skeleton;
    struct bpf_object *obj;
    struct {
        struct bpf_program *simple;
    } progs;
    struct {
        struct bpf_link *simple;
    } links;
};

ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π·Π°ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ Ρ‚ΡƒΡ‚ слСды Π½ΠΈΠ·ΠΊΠΎΡƒΡ€ΠΎΠ²Π½Π΅Π³ΠΎ API: структуру struct bpf_program *simple ΠΈ struct bpf_link *simple. ΠŸΠ΅Ρ€Π²Π°Ρ структура описываСт ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎ Π½Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ, Π·Π°ΠΏΠΈΡΠ°Π½Π½ΡƒΡŽ Π² сСкции xdp/simple, Π° вторая — описываСт Ρ‚ΠΎ, ΠΊΠ°ΠΊ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° подсоСдиняСтся ΠΊ источнику событий.

Ѐункция xdp_simple_bpf__open_and_load, ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ELF, парсит Π΅Π³ΠΎ, создаСт всС структуры ΠΈ подструктуры (ΠΊΡ€ΠΎΠΌΠ΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π² ELF находятся ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ сСкции β€”Β data, readonly data, отладочная информация, лицСнзия ΠΈ Ρ‚.ΠΏ.), Π° ΠΏΠΎΡ‚ΠΎΠΌ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ Π² ядро посрСдством систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ, скомпилировав ΠΈ запустив ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ:

$ clang -O2 -I ./libbpf/src/root/usr/include/ xdp-simple.c -o xdp-simple ./libbpf/src/root/usr/lib64/libbpf.a -lelf -lz

$ sudo strace -e bpf ./xdp-simple
...
bpf(BPF_BTF_LOAD, 0x7ffdb8fd9670, 120)  = 3
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_XDP, insn_cnt=2, insns=0xdfd580, license="GPL", log_level=0, log_size=0, log_buf=NULL, kern_version=KERNEL_VERSION(5, 8, 0), prog_flags=0, prog_name="simple", prog_ifindex=0, expected_attach_type=0x25 /* BPF_??? */, ...}, 120) = 4

Π”Π°Π²Π°ΠΉΡ‚Π΅ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ посмотрим Π½Π° Π½Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ bpftool. НайдСм Π΅Π΅ ID:

# bpftool p | grep -A4 simple
463: xdp  name simple  tag 3b185187f1855c4c  gpl
        loaded_at 2020-08-01T01:59:49+0000  uid 0
        xlated 16B  jited 40B  memlock 4096B
        btf_id 185
        pids xdp-simple(16498)

ΠΈ сдампим (ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ сокращСнный Π²ΠΈΠ΄ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ bpftool prog dump xlated):

# bpftool p d x id 463
int simple(void *ctx):
; return XDP_PASS;
   0: (b7) r0 = 2
   1: (95) exit

Π§Ρ‚ΠΎ-Ρ‚ΠΎ Π½ΠΎΠ²ΠΎΠ΅! ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Π½Π°ΠΏΠ΅Ρ‡Π°Ρ‚Π°Π»Π° куски нашСго исходного Ρ„Π°ΠΉΠ»Π° Π½Π° языкС C. Π­Ρ‚ΠΎ Π±Ρ‹Π»ΠΎ ΠΏΡ€ΠΎΠ΄Π΅Π»Π°Π½ΠΎ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΎΠΉ libbpf, которая нашла ΠΎΡ‚Π»Π°Π΄ΠΎΡ‡Π½ΡƒΡŽ ΡΠ΅ΠΊΡ†ΠΈΡŽ Π² Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊΠ΅, скомпилировала Π΅Π΅ Π² ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ BTF, Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠ»Π° Π΅Π³ΠΎ Π² ядро ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ BPF_BTF_LOAD, Π° ΠΏΠΎΡ‚ΠΎΠΌ ΡƒΠΊΠ°Π·Π°Π»Π° ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор ΠΏΡ€ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ BPG_PROG_LOAD.

Kernel Helpers

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΌΠΎΠ³ΡƒΡ‚ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ «внСшниС» Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ β€”Β kernel helpers. Π­Ρ‚ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°ΠΌ BPF ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ доступ ΠΊ структурам ядра, ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ maps, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΎΠ±Ρ‰Π°Ρ‚ΡŒΡΡ с Β«Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹ΠΌ ΠΌΠΈΡ€ΠΎΠΌΒ» β€”Β ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ perf events, ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΎΠ±ΠΎΡ€ΡƒΠ΄ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΏΠ΅Ρ€Π΅Π½Π°ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹) ΠΈ Ρ‚.ΠΏ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€: bpf_get_smp_processor_id

Π’ Ρ€Π°ΠΌΠΊΠ°Ρ… ΠΏΠ°Ρ€Π°Π΄ΠΈΠ³ΠΌΡ‹ «учимся Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°Ρ…Β», рассмотрим ΠΎΠ΄Π½Ρƒ ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠΎΠ², bpf_get_smp_processor_id(), ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΡƒΡŽ Π² Ρ„Π°ΠΉΠ»Π΅ kernel/bpf/helpers.c. Она Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π½ΠΎΠΌΠ΅Ρ€ процСссора, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ запускаСтся Π²Ρ‹Π·Π²Π°Π²ΡˆΠ°Ρ Π΅Π΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° BPF. Но нас Π½Π΅ Ρ‚Π°ΠΊ интСрСсуСт Π΅Π΅ сСмантика, ΠΊΠ°ΠΊ Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ Π΅Π΅ рСализация Π·Π°Π½ΠΈΠΌΠ°Π΅Ρ‚ ΠΎΠ΄Π½Ρƒ строчку:

BPF_CALL_0(bpf_get_smp_processor_id)
{
    return smp_processor_id();
}

ΠžΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΡ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠΎΠ² BPF ΠΏΠΎΡ…ΠΎΠΆΠΈ Π½Π° опрСдСлСния систСмных Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² Linux. Π—Π΄Π΅ΡΡŒ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, опрСдСляСтся функция, Π½Π΅ ΠΈΠΌΠ΅ΡŽΡ‰Π°Ρ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ². (Ѐункция, ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‰Π°Ρ, скаТСм, Ρ‚Ρ€ΠΈ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°, опрСдСляСтся ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ макроса BPF_CALL_3. МаксимальноС количСство Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² Ρ€Π°Π²Π½ΠΎ пяти.) Однако, это Ρ‚ΠΎΠ»ΡŒΠΊΠΎ пСрвая Ρ‡Π°ΡΡ‚ΡŒ опрСдСлСния. Вторая Ρ‡Π°ΡΡ‚ΡŒ Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠΈ структуры Ρ‚ΠΈΠΏΠ° struct bpf_func_proto, которая содСрТит описаниС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ°, понятноС verifier:

const struct bpf_func_proto bpf_get_smp_processor_id_proto = {
    .func     = bpf_get_smp_processor_id,
    .gpl_only = false,
    .ret_type = RET_INTEGER,
};

РСгистрация Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠΎΠ²

Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° ΠΌΠΎΠ³Π»ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ эту Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, ΠΎΠ½ΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π·Π°Ρ€Π΅Π³ΠΈΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π΅, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, для Ρ‚ΠΈΠΏΠ° BPF_PROG_TYPE_XDP Π² ядрС опрСдСляСтся функция xdp_func_proto, которая ΠΏΠΎ ID Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ° опрСдСляСт, ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Π»ΠΈ XDP эту Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΈΠ»ΠΈ Π½Π΅Ρ‚. ΠΠ°ΡˆΡƒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΎΠ½Π° ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚:

static const struct bpf_func_proto *
xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
{
    switch (func_id) {
    ...
    case BPF_FUNC_get_smp_processor_id:
        return &bpf_get_smp_processor_id_proto;
    ...
    }
}

НовыС Ρ‚ΠΈΠΏΡ‹ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF Β«ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡΒ» Π² Ρ„Π°ΠΉΠ»Π΅ include/linux/bpf_types.h ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ макроса BPF_PROG_TYPE. ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡ взято Π² ΠΊΠ°Π²Ρ‹Ρ‡ΠΊΠΈ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ это логичСскоС ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅, Π° Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Ρ… языка C ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Ρ†Π΅Π»ΠΎΠ³ΠΎ Π½Π°Π±ΠΎΡ€Π° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Ρ… структур происходит Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… мСстах. Π’ частности, Π² Ρ„Π°ΠΉΠ»Π΅ kernel/bpf/verifier.c всС опрСдСлСния ΠΈΠ· Ρ„Π°ΠΉΠ»Π° bpf_types.h ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ массив структур bpf_verifier_ops[]:

static const struct bpf_verifier_ops *const bpf_verifier_ops[] = {
#define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) 
    [_id] = & _name ## _verifier_ops,
#include <linux/bpf_types.h>
#undef BPF_PROG_TYPE
};

Π’ΠΎ Π΅ΡΡ‚ΡŒ, для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF опрСдСляСтся ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° структуру Π΄Π°Π½Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠ° struct bpf_verifier_ops, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ инициализируСтся Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ _name ## _verifier_ops, Ρ‚.Π΅., xdp_verifier_ops для xdp. Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° xdp_verifier_ops опрСдСляСтся Π² Ρ„Π°ΠΉΠ»Π΅ net/core/filter.c ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

const struct bpf_verifier_ops xdp_verifier_ops = {
    .get_func_proto     = xdp_func_proto,
    .is_valid_access    = xdp_is_valid_access,
    .convert_ctx_access = xdp_convert_ctx_access,
    .gen_prologue       = bpf_noop_prologue,
};

Π—Π΄Π΅ΡΡŒ ΠΌΡ‹ ΠΈ Π²ΠΈΠ΄ΠΈΠΌ Π½Π°ΡˆΡƒ Π·Π½Π°ΠΊΠΎΠΌΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ xdp_func_proto, которая Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒΡΡ verifier ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π·, ΠΊΠ°ΠΊ ΠΎΠ½ встрСтит Π²Ρ‹Π·ΠΎΠ² ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF, см. verifier.c.

ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π½Π° Ρ‚ΠΎ, ΠΊΠ°ΠΊ гипотСтичСская ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° BPF ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ bpf_get_smp_processor_id. Для этого ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡˆΠ΅ΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΈΠ· нашСго ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π³ΠΎ Ρ€Π°Π·Π΄Π΅Π»Π° ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

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

SEC("xdp/simple")
int simple(void *ctx)
{
    if (bpf_get_smp_processor_id() != 0)
        return XDP_DROP;
    return XDP_PASS;
}

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

Π‘ΠΈΠΌΠ²ΠΎΠ» bpf_get_smp_processor_id опрСдСляСтся Π² <bpf/bpf_helper_defs.h> Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ libbpf ΠΊΠ°ΠΊ

static u32 (*bpf_get_smp_processor_id)(void) = (void *) 8;

Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ, bpf_get_smp_processor_id β€” это ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Ρ€Π°Π²Π½ΠΎ 8, Π³Π΄Π΅ 8 — это Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ BPF_FUNC_get_smp_processor_id Ρ‚ΠΈΠΏΠ° enum bpf_fun_id, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ опрСдСляСтся для нас Π² Ρ„Π°ΠΉΠ»Π΅ vmlinux.h (Ρ„Π°ΠΉΠ» bpf_helper_defs.h Π² ядрС гСнСрируСтся скриптом, поэтому «магичСскиС» числа — это ok). Π­Ρ‚Π° функция Π½Π΅ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Ρ‚ΠΈΠΏΠ° __u32. Когда ΠΌΡ‹ запускаСм Π΅Π΅ Π² нашСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅, clang Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΈΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ BPF_CALL Β«ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠ³ΠΎ Π²ΠΈΠ΄Π°Β». Π”Π°Π²Π°ΠΉΡ‚Π΅ скомпилируСм ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΈ посмотрим Π½Π° ΡΠ΅ΠΊΡ†ΠΈΡŽ xdp/simple:

$ clang -O2 -g -c -target bpf -I libbpf/src/root/usr/include xdp-simple.bpf.c -o xdp-simple.bpf.o
$ llvm-objdump -D --section=xdp/simple xdp-simple.bpf.o

xdp-simple.bpf.o:       file format elf64-bpf

Disassembly of section xdp/simple:

0000000000000000 <simple>:
       0:       85 00 00 00 08 00 00 00 call 8
       1:       bf 01 00 00 00 00 00 00 r1 = r0
       2:       67 01 00 00 20 00 00 00 r1 <<= 32
       3:       77 01 00 00 20 00 00 00 r1 >>= 32
       4:       b7 00 00 00 02 00 00 00 r0 = 2
       5:       15 01 01 00 00 00 00 00 if r1 == 0 goto +1 <LBB0_2>
       6:       b7 00 00 00 01 00 00 00 r0 = 1

0000000000000038 <LBB0_2>:
       7:       95 00 00 00 00 00 00 00 exit

Π’ ΠΏΠ΅Ρ€Π²ΠΎΠΉ ΠΆΠ΅ строчкС ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ ΠΈΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ call, ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ IMM ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Ρ€Π°Π²Π΅Π½ 8, Π° SRC_REG β€” Π½ΡƒΠ»ΡŽ. По ABI-соглашСнию, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠΌΡƒ verifier, это ΠΈ Π΅ΡΡ‚ΡŒ Π²Ρ‹Π·ΠΎΠ² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ° ΠΏΠΎΠ΄ Π½ΠΎΠΌΠ΅Ρ€ΠΎΠΌ восСмь. ПослС Π΅Π΅ запуска Π»ΠΎΠ³ΠΈΠΊΠ° простая. Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈΠ· рСгистра r0 копируСтся Π² r1 ΠΈ Π½Π° строчках 2,3 приводится ΠΊ Ρ‚ΠΈΠΏΡƒ u32 β€” Π²Π΅Ρ€Ρ…Π½ΠΈΠ΅ 32 Π±ΠΈΡ‚Π° ΠΎΠ±Π½ΡƒΠ»ΡΡŽΡ‚ΡΡ. На строчках 4,5,6,7 ΠΌΡ‹ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ 2 (XDP_PASS) ΠΈΠ»ΠΈ 1 (XDP_DROP) Π² зависимости ΠΎΡ‚ Ρ‚ΠΎΠ³ΠΎ, Π²Π΅Ρ€Π½ΡƒΠ»Π° Π»ΠΈ функция-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊ со строчки 0 Π½ΡƒΠ»Π΅Π²ΠΎΠ΅ ΠΈΠ»ΠΈ Π½Π΅Π½ΡƒΠ»Π΅Π²ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ сСбя: Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΈ посмотрим Π½Π° Π²Ρ‹Π²ΠΎΠ΄ bpftool prog dump xlated:

$ bpftool gen skeleton xdp-simple.bpf.o > xdp-simple.skel.h
$ clang -O2 -g -I ./libbpf/src/root/usr/include/ -o xdp-simple xdp-simple.c ./libbpf/src/root/usr/lib64/libbpf.a -lelf -lz
$ sudo ./xdp-simple &
[2] 10914

$ sudo bpftool p | grep simple
523: xdp  name simple  tag 44c38a10c657e1b0  gpl
        pids xdp-simple(10915)

$ sudo bpftool p d x id 523
int simple(void *ctx):
; if (bpf_get_smp_processor_id() != 0)
   0: (85) call bpf_get_smp_processor_id#114128
   1: (bf) r1 = r0
   2: (67) r1 <<= 32
   3: (77) r1 >>= 32
   4: (b7) r0 = 2
; }
   5: (15) if r1 == 0x0 goto pc+1
   6: (b7) r0 = 1
   7: (95) exit

Π₯ΠΎΡ€ΠΎΡˆΠΎ, verifier нашСл ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ kernel-helper.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€: ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅ΠΌ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ ΠΈ, Π½Π°ΠΊΠΎΠ½Π΅Ρ†, запускаСм ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ!

ВсС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠΈ Π½Π° ΡƒΡ€ΠΎΠ²Π½Π΅ выполнСния ΠΈΠΌΠ΅ΡŽΡ‚ ΠΏΡ€ΠΎΡ‚ΠΎΡ‚ΠΈΠΏ

u64 fn(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)

ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ функциям-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ°ΠΌ ΠΏΠ΅Ρ€Π΅Π΄Π°ΡŽΡ‚ΡΡ Π² рСгистрах r1β€”r5, Π° Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ возвращаСтся Π² рСгистрС r0. Π€ΡƒΠ½ΠΊΡ†ΠΈΠΉ, ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‰ΠΈΡ… большС пяти Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² β€”Β Π½Π΅Ρ‚ ΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ ΠΈΡ… ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΡƒ Π² Π±ΡƒΠ΄ΡƒΡ‰Π΅ΠΌ Π½Π΅ прСдполагаСтся.

Π”Π°Π²Π°ΠΉΡ‚Π΅ посмотрим Π½Π° Π½ΠΎΠ²Ρ‹ΠΉ kernel helper ΠΈ Ρ‚ΠΎ ΠΊΠ°ΠΊ BPF ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅Ρ‚ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹. ΠŸΠ΅Ρ€Π΅ΠΏΠΈΡˆΠ΅ΠΌ xdp-simple.bpf.c ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ (ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ строки Π½Π΅ измСнились):

SEC("xdp/simple")
int simple(void *ctx)
{
    bpf_printk("running on CPU%un", bpf_get_smp_processor_id());
    return XDP_PASS;
}

Наша ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° ΠΏΠ΅Ρ‡Π°Ρ‚Π°Π΅Ρ‚ Π½ΠΎΠΌΠ΅Ρ€ CPU, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΎΠ½Π° Π·Π°ΠΏΡƒΡ‰Π΅Π½Π°. Π‘ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΡƒΠ΅ΠΌ Π΅Π΅ ΠΈ посмотрим Π½Π° ΠΊΠΎΠ΄:

$ llvm-objdump -D --section=xdp/simple --no-show-raw-insn xdp-simple.bpf.o

0000000000000000 <simple>:
       0:       r1 = 10
       1:       *(u16 *)(r10 - 8) = r1
       2:       r1 = 8441246879787806319 ll
       4:       *(u64 *)(r10 - 16) = r1
       5:       r1 = 2334956330918245746 ll
       7:       *(u64 *)(r10 - 24) = r1
       8:       call 8
       9:       r1 = r10
      10:       r1 += -24
      11:       r2 = 18
      12:       r3 = r0
      13:       call 6
      14:       r0 = 2
      15:       exit

Π’ строках 0-7 ΠΌΡ‹ записываСм Π½Π° стСк строку running on CPU%un, Π° Π·Π°Ρ‚Π΅ΠΌ Π½Π° строкС 8 запускаСм Π·Π½Π°ΠΊΠΎΠΌΡ‹ΠΉ Π½Π°ΠΌ bpf_get_smp_processor_id. Π’ строках 9-12 ΠΌΡ‹ ΠΏΠΎΠ΄Π³ΠΎΡ‚Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ Ρ…Π΅Π»ΠΏΠ΅Ρ€Π° bpf_printk β€” рСгистры r1, r2, r3. ΠŸΠΎΡ‡Π΅ΠΌΡƒ ΠΈΡ… Ρ‚Ρ€ΠΈ, Π° Π½Π΅ Π΄Π²Π°? ΠŸΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ bpf_printk — это макрос-ΠΎΠ±Π΅Ρ€Ρ‚ΠΊΠ° Π²ΠΎΠΊΡ€ΡƒΠ³ настоящСго Ρ…Π΅Π»ΠΏΠ΅Ρ€Π° bpf_trace_printk, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌΡƒ трСбуСтся ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π½ΠΎΠΉ строки.

Π”Π°Π²Π°ΠΉΡ‚Π΅ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ ΠΏΠ°Ρ€Ρƒ строчСк ΠΊ xdp-simple.c, Ρ‡Ρ‚ΠΎΠ±Ρ‹ наша ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° подсоСдинялась ΠΊ интСрфСйсу lo ΠΈ ΠΏΠΎ-настоящСму Π·Π°ΠΏΡƒΡΠΊΠ°Π»Π°ΡΡŒ!

$ cat xdp-simple.c
#include <linux/if_link.h>
#include <err.h>
#include <unistd.h>
#include "xdp-simple.skel.h"

int main(int argc, char **argv)
{
    __u32 flags = XDP_FLAGS_SKB_MODE;
    struct xdp_simple_bpf *obj;

    obj = xdp_simple_bpf__open_and_load();
    if (!obj)
        err(1, "failed to open and/or load BPF objectn");

    bpf_set_link_xdp_fd(1, -1, flags);
    bpf_set_link_xdp_fd(1, bpf_program__fd(obj->progs.simple), flags);

cleanup:
    xdp_simple_bpf__destroy(obj);
}

Π—Π΄Π΅ΡΡŒ ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ bpf_set_link_xdp_fd, которая подсоСдиняСт ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF Ρ‚ΠΈΠΏΠ° XDP ΠΊ сСтСвым интСрфСйсам. ΠœΡ‹ Π·Π°Ρ…Π°Ρ€Π΄ΠΊΠΎΠ΄ΠΈΠ»ΠΈ Π½ΠΎΠΌΠ΅Ρ€ интСрфСйса lo, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ всСгда Ρ€Π°Π²Π΅Π½ 1. ΠœΡ‹ запускаСм Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ Π΄Π²Π° Ρ€Π°Π·Π°, Ρ‡Ρ‚ΠΎΠ±Ρ‹ сначала ΠΎΡ‚ΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ ΡΡ‚Π°Ρ€ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ, Ссли ΠΎΠ½Π° Π±Ρ‹Π»Π° присоСдинСна. Π—Π°ΠΌΠ΅Ρ‚ΡŒΡ‚Π΅, Ρ‡Ρ‚ΠΎ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Π½Π°ΠΌ Π½Π΅ Π½ΡƒΠΆΠ΅Π½ Π²Ρ‹Π·ΠΎΠ² pause ΠΈΠ»ΠΈ бСсконСчный Ρ†ΠΈΠΊΠ»: наша ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°-Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ, Π½ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° BPF Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΠ½ΠΈΡ‡Ρ‚ΠΎΠΆΠ΅Π½Π°, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΎΠ½Π° подсоСдинСна ΠΊ источнику событий. ПослС ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΉ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΈ подсоСдинСния, ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒΡΡ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ сСтСвого ΠΏΠ°ΠΊΠ΅Ρ‚Π°, приходящСго Π½Π° lo.

Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΈ посмотрим Π½Π° интСрфСйс lo:

$ sudo ./xdp-simple
$ sudo bpftool p | grep simple
669: xdp  name simple  tag 4fca62e77ccb43d6  gpl
$ ip l show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 xdpgeneric qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    prog/xdp id 669

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΌΡ‹ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠ»ΠΈ ΠΈΠΌΠ΅Π΅Ρ‚ ID 669 ΠΈ Ρ‚ΠΎΡ‚ ΠΆΠ΅ ID ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ Π½Π° интСрфСйсС lo. ПошлСм ΠΏΠ°Ρ€Ρƒ ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ² Π½Π° 127.0.0.1 (request + reply):

$ ping -c1 localhost

ΠΈ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ посмотрим Π½Π° содСрТимоС ΠΎΡ‚Π»Π°Π΄ΠΎΡ‡Π½ΠΎΠ³ΠΎ Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° /sys/kernel/debug/tracing/trace_pipe, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ bpf_printk ΠΏΠΈΡˆΠ΅Ρ‚ свои сообщСния:

# cat /sys/kernel/debug/tracing/trace_pipe
ping-13937 [000] d.s1 442015.377014: bpf_trace_printk: running on CPU0
ping-13937 [000] d.s1 442015.377027: bpf_trace_printk: running on CPU0

Π”Π²Π° ΠΏΠ°ΠΊΠ΅Ρ‚Π° Π±Ρ‹Π»ΠΈ Π·Π°ΠΌΠ΅Ρ‡Π΅Π½Ρ‹ Π½Π° lo ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π½Ρ‹ Π½Π° CPU0 β€”Β Π½Π°ΡˆΠ° пСрвая полноцСнная бСссмыслСнная ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° BPF ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Π»Π°!

Π‘Ρ‚ΠΎΠΈΡ‚ Π·Π°ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ bpf_printk Π½Π΅ Π΄Π°Ρ€ΠΎΠΌ ΠΏΠΈΡˆΠ΅Ρ‚ Π² ΠΎΡ‚Π»Π°Π΄ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ»: это Π½Π΅ самый ΡƒΠ΄Π°Ρ‡Π½Ρ‹ΠΉ Ρ…Π΅Π»ΠΏΠ΅Ρ€ для использования Π² production, Π½ΠΎ наша Ρ†Π΅Π»ΡŒ Π±Ρ‹Π»Π° ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ простоС.

Доступ ΠΊ maps ΠΈΠ· ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF

ΠŸΡ€ΠΈΠΌΠ΅Ρ€: ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΠΌΠ°ΠΏ ΠΈΠ· ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF

Π’ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΡ… Ρ€Π°Π·Π΄Π΅Π»Π°Ρ… ΠΌΡ‹ Π½Π°ΡƒΡ‡ΠΈΠ»ΠΈΡΡŒ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ°ΠΏΡ‹ ΠΈΠ· пространства ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ, Π° Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ посмотрим Π½Π° ΡΠ΄Π΅Ρ€Π½ΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ. НачнСм, ΠΊΠ°ΠΊ водится, с ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°. ΠŸΠ΅Ρ€Π΅ΠΏΠΈΡˆΠ΅ΠΌ Π½Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ xdp-simple.bpf.c ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

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

struct {
    __uint(type, BPF_MAP_TYPE_ARRAY);
    __uint(max_entries, 8);
    __type(key, u32);
    __type(value, u64);
} woo SEC(".maps");

SEC("xdp/simple")
int simple(void *ctx)
{
    u32 key = bpf_get_smp_processor_id();
    u32 *val;

    val = bpf_map_lookup_elem(&woo, &key);
    if (!val)
        return XDP_ABORTED;

    *val += 1;

    return XDP_PASS;
}

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

Π’ Π½Π°Ρ‡Π°Π»ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΌΡ‹ Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΌΠ°ΠΏΠ° woo: это массив ΠΈΠ· 8 элСмСнтов, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ хранятся значСния Ρ‚ΠΈΠΏΠ° u64 (Π½Π° C ΠΌΡ‹ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈ Π±Ρ‹ Ρ‚Π°ΠΊΠΎΠΉ массив ΠΊΠ°ΠΊ u64 woo[8]). Π’ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ "xdp/simple" ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ Π½ΠΎΠΌΠ΅Ρ€ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ процСссора Π² ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ key ΠΈ Π·Π°Ρ‚Π΅ΠΌ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ° bpf_map_lookup_element ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΡƒΡŽ запись Π² массивС, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΠ²Π°Π΅ΠΌ Π½Π° Π΅Π΄ΠΈΠ½ΠΈΡ†Ρƒ. Π’ ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π΅ Π½Π° русский: ΠΌΡ‹ подсчитываСм статистику Ρ‚ΠΎΠ³ΠΎ, Π½Π° ΠΊΠ°ΠΊΠΎΠΌ CPU Π±Ρ‹Π»ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π½Ρ‹ входящиС ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹. ΠŸΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ:

$ clang -O2 -g -c -target bpf -I libbpf/src/root/usr/include xdp-simple.bpf.c -o xdp-simple.bpf.o
$ bpftool gen skeleton xdp-simple.bpf.o > xdp-simple.skel.h
$ clang -O2 -g -I ./libbpf/src/root/usr/include/ -o xdp-simple xdp-simple.c ./libbpf/src/root/usr/lib64/libbpf.a -lelf -lz
$ sudo ./xdp-simple

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΎΠ½Π° ΠΏΠΎΠ΄Ρ†Π΅ΠΏΠΈΠ»Π°ΡΡŒ ΠΊ lo ΠΈ пошлСм Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ²:

$ ip l show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 xdpgeneric qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    prog/xdp id 108

$ for s in `seq 234`; do sudo ping -f -c 100 127.0.0.1 >/dev/null 2>&1; done

Π’Π΅ΠΏΠ΅Ρ€ΡŒ посмотрим Π½Π° содСрТимоС массива:

$ sudo bpftool map dump name woo
[
    { "key": 0, "value": 0 },
    { "key": 1, "value": 400 },
    { "key": 2, "value": 0 },
    { "key": 3, "value": 0 },
    { "key": 4, "value": 0 },
    { "key": 5, "value": 0 },
    { "key": 6, "value": 0 },
    { "key": 7, "value": 46400 }
]

ΠŸΠΎΡ‡Ρ‚ΠΈ всС процСссы Π±Ρ‹Π»ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π½Ρ‹ Π½Π° CPU7. Нам это Π½Π΅ Π²Π°ΠΆΠ½ΠΎ, Π³Π»Π°Π²Π½ΠΎΠ΅, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΈ ΠΌΡ‹ поняли ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ ΠΌΠ°ΠΏΠ°ΠΌ ΠΈΠ· ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF β€” ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ Ρ…Π΅Π»ΠΏΠ΅Ρ€ΠΎΠ² bpf_mp_*.

ΠœΠΈΡΡ‚ΠΈΡ‡Π΅ΡΠΊΠΈΠΉ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ

Π˜Ρ‚Π°ΠΊ, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ доступ ΠΈΠ· ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΊ ΠΌΠ°ΠΏΡƒ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² Π²ΠΈΠ΄Π°

val = bpf_map_lookup_elem(&woo, &key);

Π³Π΄Π΅ функция-ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊ выглядит ΠΊΠ°ΠΊ

void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)

Π½ΠΎ ΠΌΡ‹ ΠΆΠ΅ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ &woo Π½Π° Π±Π΅Π·Ρ‹ΠΌΡΠ½Π½ΡƒΡŽ структуру struct { ... }

Если ΠΌΡ‹ посмотрим Π½Π° ассСмблСр ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, Ρ‚ΠΎ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ &woo Π½Π° самом Π΄Π΅Π»Π΅ Π½Π΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΎ (строчка 4):

llvm-objdump -D --section xdp/simple xdp-simple.bpf.o

xdp-simple.bpf.o:       file format elf64-bpf

Disassembly of section xdp/simple:

0000000000000000 <simple>:
       0:       85 00 00 00 08 00 00 00 call 8
       1:       63 0a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r0
       2:       bf a2 00 00 00 00 00 00 r2 = r10
       3:       07 02 00 00 fc ff ff ff r2 += -4
       4:       18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
       6:       85 00 00 00 01 00 00 00 call 1
...

ΠΈ содСрТится Π² рСлокациях:

$ llvm-readelf -r xdp-simple.bpf.o | head -4

Relocation section '.relxdp/simple' at offset 0xe18 contains 1 entries:
    Offset             Info             Type               Symbol's Value  Symbol's Name
0000000000000020  0000002700000001 R_BPF_64_64            0000000000000000 woo

Но Ссли ΠΌΡ‹ посмотрим Π½Π° ΡƒΠΆΠ΅ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Π½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ, Ρ‚ΠΎ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ map (строка 4):

$ sudo bpftool prog dump x name simple
int simple(void *ctx):
   0: (85) call bpf_get_smp_processor_id#114128
   1: (63) *(u32 *)(r10 -4) = r0
   2: (bf) r2 = r10
   3: (07) r2 += -4
   4: (18) r1 = map[id:64]
...

Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π²Ρ‹Π²ΠΎΠ΄, Ρ‡Ρ‚ΠΎ Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚ запуска нашСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹-Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊΠ° ссылка Π½Π° &woo Π±Ρ‹Π»Π° Π½Π° Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π·Π°ΠΌΠ΅Π½Π΅Π½Π° Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΎΠΉ libbpf. Для Π½Π°Ρ‡Π°Π»Π° ΠΌΡ‹ посмотрим Π½Π° Π²Ρ‹Π²ΠΎΠ΄ strace:

$ sudo strace -e bpf ./xdp-simple
...
bpf(BPF_MAP_CREATE, {map_type=BPF_MAP_TYPE_ARRAY, key_size=4, value_size=8, max_entries=8, map_name="woo", ...}, 120) = 4
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_XDP, prog_name="simple", ...}, 120) = 5

ΠœΡ‹ Π²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ libbpf создала ΠΌΠ°ΠΏ woo ΠΈ ΠΏΠΎΡ‚ΠΎΠΌ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠ»Π° Π½Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ simple. ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π±ΠΎΠ»Π΅Π΅ ΠΏΡ€ΠΈΡΡ‚Π°Π»ΡŒΠ½ΠΎ Π½Π° Ρ‚ΠΎ, ΠΊΠ°ΠΊ ΠΌΡ‹ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ:

  • Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌ xdp_simple_bpf__open_and_load ΠΈΠ· Ρ„Π°ΠΉΠ»Π° xdp-simple.skel.h
  • которая Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ xdp_simple_bpf__load ΠΈΠ· Ρ„Π°ΠΉΠ»Π° xdp-simple.skel.h
  • которая Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ bpf_object__load_skeleton ΠΈΠ· Ρ„Π°ΠΉΠ»Π° libbpf/src/libbpf.c
  • которая Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ bpf_object__load_xattr ΠΈΠ· libbpf/src/libbpf.c

ПослСдняя функция, ΠΊΡ€ΠΎΠΌΠ΅ всСго ΠΏΡ€ΠΎΡ‡Π΅Π³ΠΎ, Π²Ρ‹Π·ΠΎΠ²Π΅Ρ‚ bpf_object__create_maps, которая создаСт ΠΈΠ»ΠΈ ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ maps, прСвращая ΠΈΡ… Π² Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹Π΅ дСскрипторы. (Π­Ρ‚ΠΎ Ρ‚ΠΎ мСсто, Π³Π΄Π΅ ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ BPF_MAP_CREATE Π² Π²Ρ‹Π²ΠΎΠ΄Π΅ strace.) Π”Π°Π»ΡŒΡˆΠ΅ вызываСтся функция bpf_object__relocate ΠΈ ΠΈΠΌΠ΅Π½Π½ΠΎ ΠΎΠ½Π° нас ΠΈ интСрСсуСт, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΌΡ‹ ΠΏΠΎΠΌΠ½ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ Π²ΠΈΠ΄Π΅Π»ΠΈ woo Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ Ρ€Π΅Π»ΠΎΠΊΠ°Ρ†ΠΈΠΉ. Π˜ΡΡΠ»Π΅Π΄ΡƒΡ Π΅Π΅, ΠΌΡ‹, Π² ΠΊΠΎΠ½Ρ†Π΅-ΠΊΠΎΠ½Ρ†ΠΎΠ² ΠΏΠΎΠΏΠ°Π΄Π°Π΅ΠΌ Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ bpf_program__relocate, которая ΠΈ занимаСтся рСлокациями ΠΌΠ°ΠΏΠΎΠ²:

case RELO_LD64:
    insn[0].src_reg = BPF_PSEUDO_MAP_FD;
    insn[0].imm = obj->maps[relo->map_idx].fd;
    break;

Π˜Ρ‚Π°ΠΊ, ΠΌΡ‹ Π±Π΅Ρ€Π΅ΠΌ Π½Π°ΡˆΡƒ ΠΈΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ

18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll

ΠΈ замСняСм Π² Π½Π΅ΠΉ рСгистр-источник Π½Π° BPF_PSEUDO_MAP_FD, Π° ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ IMM Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор нашСго ΠΌΠ°ΠΏΠ° ΠΈ, Ссли ΠΎΠ½ Ρ€Π°Π²Π΅Π½, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, 0xdeadbeef, Ρ‚ΠΎ Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ ΠΈΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ

18 11 00 00 ef eb ad de 00 00 00 00 00 00 00 00 r1 = 0 ll

ИмСнно Ρ‚Π°ΠΊ информация ΠΎ ΠΌΠ°ΠΏΠ°Ρ… пСрСдаСтся Π² ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΡƒΡŽ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Π½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ BPF. ΠŸΡ€ΠΈ этом ΠΌΠ°ΠΏ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΊΠ°ΠΊ создан ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ BPF_MAP_CREATE, Ρ‚Π°ΠΊ ΠΈ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ ΠΏΠΎ ID ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ BPF_MAP_GET_FD_BY_ID.

Π˜Ρ‚ΠΎΠ³ΠΎ, ΠΏΡ€ΠΈ использовании libbpf Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ:

  • Π²ΠΎ врСмя компиляции для ссылок Π½Π° ΠΌΠ°ΠΏΡ‹ ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ записи Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ Ρ€Π΅Π»ΠΎΠΊΠ°Ρ†ΠΈΠΈ
  • libbpf ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΈΠΊ ELF, Π½Π°Ρ…ΠΎΠ΄ΠΈΡ‚ всС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Π΅ ΠΌΠ°ΠΏΡ‹ ΠΈ создаСт для Π½ΠΈΡ… Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹Π΅ дСскрипторы
  • Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹Π΅ дСскрипторы Π·Π°Π³Ρ€ΡƒΠΆΠ°ΡŽΡ‚ΡΡ Π² ядро ΠΊΠ°ΠΊ Ρ‡Π°ΡΡ‚ΡŒ инструкции LD64

Как Π²Ρ‹ ΠΏΠΎΠ½ΠΈΠΌΠ°Π΅Ρ‚Π΅, это Π΅Ρ‰Π΅ Π½Π΅ всС, ΠΈ Π½Π°ΠΌ придСтся Π·Π°Π³Π»ΡΠ½ΡƒΡ‚ΡŒ Π² ядро. К ΡΡ‡Π°ΡΡ‚ΡŒΡŽ, Ρƒ нас Π΅ΡΡ‚ΡŒ Π·Π°Ρ†Π΅ΠΏΠΊΠ° β€”Β ΠΌΡ‹ прописали Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ BPF_PSEUDO_MAP_FD Π² рСгистр-источник ΠΈ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ³Ρ€Π΅ΠΏΠ°Ρ‚ΡŒ Π΅Π³ΠΎ, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Ρ‚ нас Π² святая всСх святых β€” kernel/bpf/verifier.c, Π³Π΄Π΅ функция с Ρ…Π°Ρ€Π°ΠΊΡ‚Π΅Ρ€Π½Ρ‹ΠΌ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ замСняСт Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор Π½Π° адрСс структуры Ρ‚ΠΈΠΏΠ° struct bpf_map:

static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env) {
    ...

    f = fdget(insn[0].imm);
    map = __bpf_map_get(f);
    if (insn->src_reg == BPF_PSEUDO_MAP_FD) {
        addr = (unsigned long)map;
    }
    insn[0].imm = (u32)addr;
    insn[1].imm = addr >> 32;

(ΠΏΠΎΠ»Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ ΠΏΠΎ ссылкС). Π’Π°ΠΊ Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ наш Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ:

  • Π²ΠΎ врСмя Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ verifier провСряСт ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎΡΡ‚ΡŒ использования ΠΌΠ°ΠΏΠ° ΠΈ прописываСт адрСс ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΉ структуры struct bpf_map

ΠŸΡ€ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ΅ Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊΠ° ELF ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ libbpf происходит Π΅Ρ‰Π΅ ΠΌΠ½ΠΎΠ³ΠΎ событий, Π½ΠΎ ΠΌΡ‹ обсудим это Π² Ρ€Π°ΠΌΠΊΠ°Ρ… Π΄Ρ€ΡƒΠ³ΠΈΡ… статСй.

Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΈ ΠΌΠ°ΠΏΡ‹ Π±Π΅Π· libbpf

Как ΠΈ ΠΎΠ±Π΅Ρ‰Π°Π»ΠΎΡΡŒ, Π²ΠΎΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ для Ρ‡ΠΈΡ‚Π°Ρ‚Π΅Π»Π΅ΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ хотят Π·Π½Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΡƒΡŽ ΠΌΠ°ΠΏΡ‹, Π±Π΅Π· ΠΏΠΎΠΌΠΎΡ‰ΠΈ libbpf. Π­Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΏΠΎΠ»Π΅Π·Π½ΠΎ, ΠΊΠΎΠ³Π΄Π° Π²Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚Π΅ Π² ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠΈ, для ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ зависимости, ΠΈΠ»ΠΈ экономитС ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Π±ΠΈΡ‚, ΠΈΠ»ΠΈ ΠΏΠΈΡˆΠ΅Ρ‚Π΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ Ρ‚ΠΈΠΏΠ° ply, которая Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ Π±ΠΈΠ½Π°Ρ€Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ BPF Π½Π°Π»Π΅Ρ‚Ρƒ.

Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π±Ρ‹Π»ΠΎ ΠΏΡ€ΠΎΡ‰Π΅ ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚ΡŒ Π·Π° Π»ΠΎΠ³ΠΈΠΊΠΎΠΉ, ΠΌΡ‹ для этих Ρ†Π΅Π»Π΅ΠΉ ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡˆΠ΅ΠΌ наш ΠΏΡ€ΠΈΠΌΠ΅Ρ€ xdp-simple. ΠŸΠΎΠ»Π½Ρ‹ΠΉ ΠΈ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, рассматриваСмой Π² этом ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π½Π°ΠΉΡ‚ΠΈ Π² этом gist.

Π›ΠΎΠ³ΠΈΠΊΠ° нашСго прилоТСния ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π°Ρ:

  • ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΌΠ°ΠΏ Ρ‚ΠΈΠΏΠ° BPF_MAP_TYPE_ARRAY ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ BPF_MAP_CREATE,
  • ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΡƒΡŽ этот ΠΌΠ°ΠΏ,
  • ΠΏΠΎΠ΄ΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΊ интСрфСйсу lo,

Ρ‡Ρ‚ΠΎ пСрСводится Π½Π° чСловСчСский ΠΊΠ°ΠΊ

int main(void)
{
    int map_fd, prog_fd;

    map_fd = map_create();
    if (map_fd < 0)
        err(1, "bpf: BPF_MAP_CREATE");

    prog_fd = prog_load(map_fd);
    if (prog_fd < 0)
        err(1, "bpf: BPF_PROG_LOAD");

    xdp_attach(1, prog_fd);
}

Π—Π΄Π΅ΡΡŒ map_create создаСт ΠΌΠ°ΠΏ Ρ‚ΠΎΡ‡Π½ΠΎ Ρ‚Π°ΠΊ ΠΆΠ΅, ΠΊΠ°ΠΊ ΠΌΡ‹ Π΄Π΅Π»Π°Π»ΠΈ это Π² ΠΏΠ΅Ρ€Π²ΠΎΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΏΡ€ΠΎ систСмный Π²Ρ‹Π·ΠΎΠ² bpf β€” «ядро, поТалуйста, сдСлай ΠΌΠ½Π΅ Π½ΠΎΠ²Ρ‹ΠΉ ΠΌΠ°ΠΏ Π² видС массива ΠΈΠ· 8 элСмСнтов Ρ‚ΠΈΠΏΠ° __u64 ΠΈ Π²Π΅Ρ€Π½ΠΈ ΠΌΠ½Π΅ Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор»:

static int map_create()
{
    union bpf_attr attr;

    memset(&attr, 0, sizeof(attr));
    attr.map_type = BPF_MAP_TYPE_ARRAY,
    attr.key_size = sizeof(__u32),
    attr.value_size = sizeof(__u64),
    attr.max_entries = 8,
    strncpy(attr.map_name, "woo", sizeof(attr.map_name));
    return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
}

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Ρ‚ΠΎΠΆΠ΅ загруТаСтся просто:

static int prog_load(int map_fd)
{
    union bpf_attr attr;
    struct bpf_insn insns[] = {
        ...
    };

    memset(&attr, 0, sizeof(attr));
    attr.prog_type = BPF_PROG_TYPE_XDP;
    attr.insns     = ptr_to_u64(insns);
    attr.insn_cnt  = sizeof(insns)/sizeof(insns[0]);
    attr.license   = ptr_to_u64("GPL");
    strncpy(attr.prog_name, "woo", sizeof(attr.prog_name));
    return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
}

БлоТная Ρ‡Π°ΡΡ‚ΡŒ prog_load β€” это ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ нашСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF Π² Π²ΠΈΠ΄Π΅ массива структур struct bpf_insn insns[]. Но Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ, которая Ρƒ нас Π΅ΡΡ‚ΡŒ Π½Π° C, Ρ‚ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΡΡ…ΠΈΡ‚Ρ€ΠΈΡ‚ΡŒ:

$ llvm-objdump -D --section xdp/simple xdp-simple.bpf.o

0000000000000000 <simple>:
       0:       85 00 00 00 08 00 00 00 call 8
       1:       63 0a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r0
       2:       bf a2 00 00 00 00 00 00 r2 = r10
       3:       07 02 00 00 fc ff ff ff r2 += -4
       4:       18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
       6:       85 00 00 00 01 00 00 00 call 1
       7:       b7 01 00 00 00 00 00 00 r1 = 0
       8:       15 00 04 00 00 00 00 00 if r0 == 0 goto +4 <LBB0_2>
       9:       61 01 00 00 00 00 00 00 r1 = *(u32 *)(r0 + 0)
      10:       07 01 00 00 01 00 00 00 r1 += 1
      11:       63 10 00 00 00 00 00 00 *(u32 *)(r0 + 0) = r1
      12:       b7 01 00 00 02 00 00 00 r1 = 2

0000000000000068 <LBB0_2>:
      13:       bf 10 00 00 00 00 00 00 r0 = r1
      14:       95 00 00 00 00 00 00 00 exit

Π˜Ρ‚ΠΎΠ³ΠΎ, Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ 14 инструкций Π² Π²ΠΈΠ΄Π΅ структур Ρ‚ΠΈΠΏΠ° struct bpf_insn (совСт: Π²ΠΎΠ·ΡŒΠΌΠΈΡ‚Π΅ Π΄Π°ΠΌΠΏ свСрху, ΠΏΠ΅Ρ€Π΅Ρ‡ΠΈΡ‚Π°ΠΉΡ‚Π΅ Ρ€Π°Π·Π΄Π΅Π» ΠΏΡ€ΠΎ инструкции, ΠΎΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ linux/bpf.h ΠΈ linux/bpf_common.h ΠΈ ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ struct bpf_insn insns[] ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ):

struct bpf_insn insns[] = {
    /* 85 00 00 00 08 00 00 00 call 8 */
    {
        .code = BPF_JMP | BPF_CALL,
        .imm = 8,
    },

    /* 63 0a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r0 */
    {
        .code = BPF_MEM | BPF_STX,
        .off = -4,
        .src_reg = BPF_REG_0,
        .dst_reg = BPF_REG_10,
    },

    /* bf a2 00 00 00 00 00 00 r2 = r10 */
    {
        .code = BPF_ALU64 | BPF_MOV | BPF_X,
        .src_reg = BPF_REG_10,
        .dst_reg = BPF_REG_2,
    },

    /* 07 02 00 00 fc ff ff ff r2 += -4 */
    {
        .code = BPF_ALU64 | BPF_ADD | BPF_K,
        .dst_reg = BPF_REG_2,
        .imm = -4,
    },

    /* 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll */
    {
        .code = BPF_LD | BPF_DW | BPF_IMM,
        .src_reg = BPF_PSEUDO_MAP_FD,
        .dst_reg = BPF_REG_1,
        .imm = map_fd,
    },
    { }, /* placeholder */

    /* 85 00 00 00 01 00 00 00 call 1 */
    {
        .code = BPF_JMP | BPF_CALL,
        .imm = 1,
    },

    /* b7 01 00 00 00 00 00 00 r1 = 0 */
    {
        .code = BPF_ALU64 | BPF_MOV | BPF_K,
        .dst_reg = BPF_REG_1,
        .imm = 0,
    },

    /* 15 00 04 00 00 00 00 00 if r0 == 0 goto +4 <LBB0_2> */
    {
        .code = BPF_JMP | BPF_JEQ | BPF_K,
        .off = 4,
        .src_reg = BPF_REG_0,
        .imm = 0,
    },

    /* 61 01 00 00 00 00 00 00 r1 = *(u32 *)(r0 + 0) */
    {
        .code = BPF_MEM | BPF_LDX,
        .off = 0,
        .src_reg = BPF_REG_0,
        .dst_reg = BPF_REG_1,
    },

    /* 07 01 00 00 01 00 00 00 r1 += 1 */
    {
        .code = BPF_ALU64 | BPF_ADD | BPF_K,
        .dst_reg = BPF_REG_1,
        .imm = 1,
    },

    /* 63 10 00 00 00 00 00 00 *(u32 *)(r0 + 0) = r1 */
    {
        .code = BPF_MEM | BPF_STX,
        .src_reg = BPF_REG_1,
        .dst_reg = BPF_REG_0,
    },

    /* b7 01 00 00 02 00 00 00 r1 = 2 */
    {
        .code = BPF_ALU64 | BPF_MOV | BPF_K,
        .dst_reg = BPF_REG_1,
        .imm = 2,
    },

    /* <LBB0_2>: bf 10 00 00 00 00 00 00 r0 = r1 */
    {
        .code = BPF_ALU64 | BPF_MOV | BPF_X,
        .src_reg = BPF_REG_1,
        .dst_reg = BPF_REG_0,
    },

    /* 95 00 00 00 00 00 00 00 exit */
    {
        .code = BPF_JMP | BPF_EXIT
    },
};

Π£ΠΏΡ€Π°ΠΆΠ½Π΅Π½ΠΈΠ΅ для Ρ‚Π΅Ρ…, ΠΊΡ‚ΠΎ Π½Π΅ стал ΠΏΠΈΡΠ°Ρ‚ΡŒ это сам β€”Β Π½Π°ΠΉΠ΄ΠΈΡ‚Π΅ map_fd.

Π’ нашСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ ΠΎΡΡ‚Π°Π»Π°ΡΡŒ Π΅Ρ‰Π΅ ΠΎΠ΄Π½Π° нСраскрытая Ρ‡Π°ΡΡ‚ΡŒ β€” xdp_attach. К соТалСнию, ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Ρ‚ΠΈΠΏΠ° XDP нСльзя ΠΏΠΎΠ΄ΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ систСмного Π²Ρ‹Π·ΠΎΠ²Π° bpf. Π›ΡŽΠ΄ΠΈ, создававшиС BPF ΠΈ XDP Π±Ρ‹Π»ΠΈ ΠΈΠ· сСтСвого сообщСства Linux, Π° Π·Π½Π°Ρ‡ΠΈΡ‚, ΠΎΠ½ΠΈ использовали самый ΠΏΡ€ΠΈΠ²Ρ‹Ρ‡Π½Ρ‹ΠΉ для Π½ΠΈΡ… (Π½ΠΎ Π½Π΅ для Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½Ρ‹Ρ… людСй) интСрфСйс взаимодСйствия с ядром: netlink sockets, см. Ρ‚Π°ΠΊΠΆΠ΅ RFC3549. Π‘Π°ΠΌΡ‹ΠΉ простой способ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ xdp_attach β€” это ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΊΠΎΠ΄Π° ΠΈΠ· libbpf, Π° ΠΈΠΌΠ΅Π½Π½ΠΎ, ΠΈΠ· Ρ„Π°ΠΉΠ»Π° netlink.c, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΠΈ ΠΏΡ€ΠΎΠ΄Π΅Π»Π°Π»ΠΈ, Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΡƒΠΊΠΎΡ€ΠΎΡ‚ΠΈΠ² Π΅Π³ΠΎ:

Π”ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒ Π² ΠΌΠΈΡ€ netlink сокСтов

ΠžΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅ΠΌ netlink сокСт Ρ‚ΠΈΠΏΠ° NETLINK_ROUTE:

int netlink_open(__u32 *nl_pid)
{
    struct sockaddr_nl sa;
    socklen_t addrlen;
    int one = 1, ret;
    int sock;

    memset(&sa, 0, sizeof(sa));
    sa.nl_family = AF_NETLINK;

    sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (sock < 0)
        err(1, "socket");

    if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK, &one, sizeof(one)) < 0)
        warnx("netlink error reporting not supported");

    if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0)
        err(1, "bind");

    addrlen = sizeof(sa);
    if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0)
        err(1, "getsockname");

    *nl_pid = sa.nl_pid;
    return sock;
}

Π§ΠΈΡ‚Π°Π΅ΠΌ ΠΈΠ· Ρ‚Π°ΠΊΠΎΠ³ΠΎ сокСта:

static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq)
{
    bool multipart = true;
    struct nlmsgerr *errm;
    struct nlmsghdr *nh;
    char buf[4096];
    int len, ret;

    while (multipart) {
        multipart = false;
        len = recv(sock, buf, sizeof(buf), 0);
        if (len < 0)
            err(1, "recv");

        if (len == 0)
            break;

        for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
                nh = NLMSG_NEXT(nh, len)) {
            if (nh->nlmsg_pid != nl_pid)
                errx(1, "wrong pid");
            if (nh->nlmsg_seq != seq)
                errx(1, "INVSEQ");
            if (nh->nlmsg_flags & NLM_F_MULTI)
                multipart = true;
            switch (nh->nlmsg_type) {
                case NLMSG_ERROR:
                    errm = (struct nlmsgerr *)NLMSG_DATA(nh);
                    if (!errm->error)
                        continue;
                    ret = errm->error;
                    // libbpf_nla_dump_errormsg(nh); too many code to copy...
                    goto done;
                case NLMSG_DONE:
                    return 0;
                default:
                    break;
            }
        }
    }
    ret = 0;
done:
    return ret;
}

НаконСц, Π²ΠΎΡ‚ наша функция, которая ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ сокСт ΠΈ посылаСт Π² Π½Π΅Π³ΠΎ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ΅ сообщСниС, содСрТащСС Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор:

static int xdp_attach(int ifindex, int prog_fd)
{
    int sock, seq = 0, ret;
    struct nlattr *nla, *nla_xdp;
    struct {
        struct nlmsghdr  nh;
        struct ifinfomsg ifinfo;
        char             attrbuf[64];
    } req;
    __u32 nl_pid = 0;

    sock = netlink_open(&nl_pid);
    if (sock < 0)
        return sock;

    memset(&req, 0, sizeof(req));
    req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
    req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
    req.nh.nlmsg_type = RTM_SETLINK;
    req.nh.nlmsg_pid = 0;
    req.nh.nlmsg_seq = ++seq;
    req.ifinfo.ifi_family = AF_UNSPEC;
    req.ifinfo.ifi_index = ifindex;

    /* started nested attribute for XDP */
    nla = (struct nlattr *)(((char *)&req)
            + NLMSG_ALIGN(req.nh.nlmsg_len));
    nla->nla_type = NLA_F_NESTED | IFLA_XDP;
    nla->nla_len = NLA_HDRLEN;

    /* add XDP fd */
    nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
    nla_xdp->nla_type = IFLA_XDP_FD;
    nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
    memcpy((char *)nla_xdp + NLA_HDRLEN, &prog_fd, sizeof(prog_fd));
    nla->nla_len += nla_xdp->nla_len;

    /* if user passed in any flags, add those too */
    __u32 flags = XDP_FLAGS_SKB_MODE;
    nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
    nla_xdp->nla_type = IFLA_XDP_FLAGS;
    nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
    memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
    nla->nla_len += nla_xdp->nla_len;

    req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);

    if (send(sock, &req, req.nh.nlmsg_len, 0) < 0)
        err(1, "send");
    ret = bpf_netlink_recv(sock, nl_pid, seq);

cleanup:
    close(sock);
    return ret;
}

Π˜Ρ‚Π°ΠΊ, всС Π³ΠΎΡ‚ΠΎΠ²ΠΎ ΠΊ Ρ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡŽ:

$ cc nolibbpf.c -o nolibbpf
$ sudo strace -e bpf ./nolibbpf
bpf(BPF_MAP_CREATE, {map_type=BPF_MAP_TYPE_ARRAY, map_name="woo", ...}, 72) = 3
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_XDP, insn_cnt=15, prog_name="woo", ...}, 72) = 4
+++ exited with 0 +++

ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ, подсоСдинилась Π»ΠΈ наша ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° ΠΊ lo:

$ ip l show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 xdpgeneric qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    prog/xdp id 160

ПошлСм ΠΏΠΈΠ½Π³ΠΈ ΠΈ ΠΏΠΎΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π½Π° map:

$ for s in `seq 234`; do sudo ping -f -c 100 127.0.0.1 >/dev/null 2>&1; done
$ sudo bpftool m dump name woo
key: 00 00 00 00  value: 90 01 00 00 00 00 00 00
key: 01 00 00 00  value: 00 00 00 00 00 00 00 00
key: 02 00 00 00  value: 00 00 00 00 00 00 00 00
key: 03 00 00 00  value: 00 00 00 00 00 00 00 00
key: 04 00 00 00  value: 00 00 00 00 00 00 00 00
key: 05 00 00 00  value: 00 00 00 00 00 00 00 00
key: 06 00 00 00  value: 40 b5 00 00 00 00 00 00
key: 07 00 00 00  value: 00 00 00 00 00 00 00 00
Found 8 elements

Π£Ρ€Π°, всС Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚. Π—Π°ΠΌΠ΅Ρ‚ΡŒΡ‚Π΅, кстати, Ρ‡Ρ‚ΠΎ наш map ΠΎΠΏΡΡ‚ΡŒ отобраТаСтся Π² Π²ΠΈΠ΄Π΅ Π±Π°ΠΉΡ‚ΠΈΠΊΠΎΠ². Π­Ρ‚ΠΎ ΠΏΡ€ΠΎΠΈΡ…ΠΎΠ΄ΠΈΡ‚ ΠΈΠ·-Π·Π° Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ, Π² ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ libbpf ΠΌΡ‹ Π½Π΅ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π»ΠΈ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΎ Ρ‚ΠΈΠΏΠ°Ρ… (BTF). Но ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅ ΠΎΠ± этом ΠΌΡ‹ ΠΏΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΠΌ Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Ρ€Π°Π·.

БрСдства Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ

Π’ этом Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΌΡ‹ посмотрим Π½Π° ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΈΠ½ΡΡ‚Ρ€ΡƒΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½Ρ‹ΠΉ Π½Π°Π±ΠΎΡ€ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° BPF.

Π’ΠΎΠΎΠ±Ρ‰Π΅ говоря, для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ Π½ΠΈΡ‡Π΅Π³ΠΎ особСнного β€”Β BPF Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π½Π° любом ΠΏΡ€ΠΈΠ»ΠΈΡ‡Π½ΠΎΠΌ дистрибутивном ядрС, Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΡΠΎΠ±ΠΈΡ€Π°ΡŽΡ‚ΡΡ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ clang, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π°. Однако, ΠΈΠ·-Π·Π° Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ BPF находится Π² процСссС Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ, ядро ΠΈ инструмСнты постоянно ΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ, Ссли Π²Ρ‹ Π½Π΅ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF дСдовскими ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌΠΈ ΠΈΠ· 2019-Ρ…, Ρ‚ΠΎ Π²Π°ΠΌ придСтся ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ

  • llvm/clang
  • pahole
  • своС ядро
  • bpftool

(Для справки: этот Ρ€Π°Π·Π΄Π΅Π» ΠΈ всС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Π² ΡΡ‚Π°Ρ‚ΡŒΠ΅ Π·Π°ΠΏΡƒΡΠΊΠ°Π»ΠΈΡΡŒ Π½Π° Debian 10.)

llvm/clang

BPF Π΄Ρ€ΡƒΠΆΠΈΡ‚ с LLVM ΠΈ, хотя с Π½Π΅Π΄Π°Π²Π½ΠΈΡ… ΠΏΠΎΡ€ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ для BPF ΠΌΠΎΠΆΠ½ΠΎ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ gcc, вся тСкущая Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° вСдСтся для LLVM. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ Π΄Π΅Π»ΠΎΠΌ ΠΌΡ‹ собСрСм Ρ‚Π΅ΠΊΡƒΡ‰ΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ clang ΠΈΠ· git:

$ sudo apt install ninja-build
$ git clone --depth 1 https://github.com/llvm/llvm-project.git
$ mkdir -p llvm-project/llvm/build/install
$ cd llvm-project/llvm/build
$ cmake .. -G "Ninja" -DLLVM_TARGETS_TO_BUILD="BPF;X86" 
                      -DLLVM_ENABLE_PROJECTS="clang" 
                      -DBUILD_SHARED_LIBS=OFF 
                      -DCMAKE_BUILD_TYPE=Release 
                      -DLLVM_BUILD_RUNTIME=OFF
$ time ninja
... ΠΌΠ½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ спустя
$

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ, ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ Π»ΠΈ всС ΡΠΎΠ±Ρ€Π°Π»ΠΎΡΡŒ:

$ ./bin/llc --version
LLVM (http://llvm.org/):
  LLVM version 11.0.0git
  Optimized build.
  Default target: x86_64-unknown-linux-gnu
  Host CPU: znver1

  Registered Targets:
    bpf    - BPF (host endian)
    bpfeb  - BPF (big endian)
    bpfel  - BPF (little endian)
    x86    - 32-bit X86: Pentium-Pro and above
    x86-64 - 64-bit X86: EM64T and AMD64

(Π˜Π½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡ ΠΏΠΎ сборкС clang взята ΠΌΠ½ΠΎΠΉ ΠΈΠ· bpf_devel_QA.)

ΠœΡ‹ Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ ΡƒΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‡Ρ‚ΠΎ собранныС ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, Π° вмСсто этого просто Π΄ΠΎΠ±Π°Π²ΠΈΠΌ ΠΈΡ… Π² PATH, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€:

export PATH="`pwd`/bin:$PATH"

(Π­Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² .bashrc ΠΈΠ»ΠΈ Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ Ρ„Π°ΠΉΠ». Π›ΠΈΡ‡Π½ΠΎ я добавляю Ρ‚Π°ΠΊΠΈΠ΅ Π²Π΅Ρ‰ΠΈ Π² ~/bin/activate-llvm.sh ΠΈ ΠΊΠΎΠ³Π΄Π° Π½ΡƒΠΆΠ½ΠΎ дСлаю . activate-llvm.sh.)

Pahole ΠΈ BTF

Π£Ρ‚ΠΈΠ»ΠΈΡ‚Π° pahole ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΏΡ€ΠΈ сборкС ядра для создания ΠΎΡ‚Π»Π°Π΄ΠΎΡ‡Π½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ BTF. ΠœΡ‹ Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ Π² этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ ΠΎΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒΡΡ Π½Π° дСталях Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ BTF, ΠΊΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ Ρ„Π°ΠΊΡ‚Π°, Ρ‡Ρ‚ΠΎ это ΡƒΠ΄ΠΎΠ±Π½ΠΎ ΠΈ ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Π΅Π³ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ, Ссли Π²Ρ‹ ΡΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚Π΅ΡΡŒ ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ своС ядро, собСритС сначала pahole (Π±Π΅Π· pahole Π²Ρ‹ Π½Π΅ смоТСтС ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ ядро с ΠΎΠΏΡ†ΠΈΠ΅ΠΉ CONFIG_DEBUG_INFO_BTF:

$ git clone https://git.kernel.org/pub/scm/devel/pahole/pahole.git
$ cd pahole/
$ sudo apt install cmake
$ mkdir build
$ cd build/
$ cmake -D__LIB=lib ..
$ make
$ sudo make install
$ which pahole
/usr/local/bin/pahole

Π―Π΄Ρ€Π° для экспСримСнтов с BPF

ΠŸΡ€ΠΈ исслСдовании возмоТностСй BPF хочСтся ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ своС ядро. Π­Ρ‚ΠΎ, Π²ΠΎΠΎΠ±Ρ‰Π΅ говоря, Π½Π΅ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ Π²Ρ‹ смоТСтС ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ ΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ BPF ΠΈ Π½Π° дистрибутивном ядрС, ΠΎΠ΄Π½Π°ΠΊΠΎ, Π½Π°Π»ΠΈΡ‡ΠΈΠ΅ своСго ядра позволяСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ самыС Π½ΠΎΠ²Ρ‹Π΅ возмоТности BPF, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ окаТутся Π² вашСм дистрибутивС Π² Π»ΡƒΡ‡ΡˆΠ΅ΠΌ случаС Ρ‡Π΅Ρ€Π΅Π· мСсяцы ΠΈΠ»ΠΈ, ΠΊΠ°ΠΊ Π² случаС с Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ ΠΎΡ‚Π»Π°Π΄ΠΎΡ‡Π½Ρ‹ΠΌΠΈ инструмСнтами, Π²ΠΎΠΎΠ±Ρ‰Π΅ Π½Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΠΏΠ°ΠΊΠ΅Ρ‡Π΅Π½Ρ‹ Π² ΠΎΠ±ΠΎΠ·Ρ€ΠΈΠΌΠΎΠΌ Π±ΡƒΠ΄ΡƒΡ‰Π΅ΠΌ. Π’Π°ΠΊΠΆΠ΅ своС ядро позволяСт ΠΏΠΎΡ‡ΡƒΠ²ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ сСбя Π²Π°ΠΆΠ½Ρ‹ΠΌ ΡΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ с ΠΊΠΎΠ΄ΠΎΠΌ.

Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ядро Π²Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ, Π²ΠΎ-ΠΏΠ΅Ρ€Π²Ρ‹Ρ…, само ядро, Π° Π²ΠΎ-Π²Ρ‚ΠΎΡ€Ρ‹Ρ…, Ρ„Π°ΠΉΠ» ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ ядра. Для экспСримСнтов с BPF ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠ΅ ванильноС ядро ΠΈΠ»ΠΈ ΠΎΠ΄Π½ΠΎ ΠΈΠ· дСвСлопСрских ядСр. Π˜ΡΡ‚ΠΎΡ€ΠΈΡ‡Π΅ΡΠΊΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° BPF происходит Π² Ρ€Π°ΠΌΠΊΠ°Ρ… сСтСвого сообщСства Linux ΠΈ поэтому всС измСнСния Ρ€Π°Π½ΠΎ ΠΈΠ»ΠΈ ΠΏΠΎΠ·Π΄Π½ΠΎ проходят Ρ‡Π΅Ρ€Π΅Π· Дэвида ΠœΠΈΠ»Π»Π΅Ρ€Π° (David Miller) β€” ΠΌΠ°Π½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° сСтСвой части Linux. Π’ зависимости ΠΎΡ‚ своСй ΠΏΡ€ΠΈΡ€ΠΎΠ΄Ρ‹ β€” ΠΏΡ€Π°Π²ΠΊΠ° ΠΈΠ»ΠΈ Π½ΠΎΠ²Ρ‹Π΅ Ρ„ΠΈΡ‡ΠΈ β€” сСтСвыС измСнСния ΠΏΠΎΠΏΠ°Π΄Π°ΡŽΡ‚ Π² ΠΎΠ΄Π½ΠΎ ΠΈΠ· Π΄Π²ΡƒΡ… ядСр β€” net ΠΈΠ»ΠΈ net-next. ИзмСнСния для BPF Ρ‚Π°ΠΊΠΈΠΌ ΠΆΠ΅ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ Ρ€Π°ΡΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡ ΠΌΠ΅ΠΆΠ΄Ρƒ bpf ΠΈ bpf-next, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΡ‚ΠΎΠΌ пулятся Π² net ΠΈ net-next, соотвСтствСнно. ΠŸΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅ см. Π² bpf_devel_QA ΠΈ netdev-FAQ. Π’Π°ΠΊ Ρ‡Ρ‚ΠΎ Π²Ρ‹Π±ΠΈΡ€Π°ΠΉΡ‚Π΅ ядро исходя ΠΈΠ· вашСго вкуса ΠΈ потрСбностСй Π² ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½ΠΎΡΡ‚ΠΈ систСмы, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π²Ρ‹ тСстируСтС (*-next ядра самыС Π½Π΅ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½Ρ‹Π΅ ΠΈΠ· пСрСчислСнных).

Π’ Ρ€Π°ΠΌΠΊΠΈ Π΄Π°Π½Π½ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠΈ Π½Π΅ Π²Ρ…ΠΎΠ΄ΠΈΡ‚ рассказ ΠΎ Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒΡΡ с Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ ядра β€” прСдполагаСтся, Ρ‡Ρ‚ΠΎ Π²Ρ‹ Π»ΠΈΠ±ΠΎ ΡƒΠΆΠ΅ ΡƒΠΌΠ΅Π΅Ρ‚Π΅ это Π΄Π΅Π»Π°Ρ‚ΡŒ, Π»ΠΈΠ±ΠΎ Π³ΠΎΡ‚ΠΎΠ²Ρ‹ Π½Π°ΡƒΡ‡ΠΈΡ‚ΡŒΡΡ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ. Однако, ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… инструкций Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ, Π±ΠΎΠ»Π΅Π΅-ΠΌΠ΅Π½Π΅Π΅, достаточно, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρƒ вас ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»Π°ΡΡŒ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‰Π°Ρ систСма с ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ BPF.

Π‘ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ ΠΎΠ΄Π½ΠΎ ΠΈΠ· Π²Ρ‹ΡˆΠ΅ΡƒΠΏΠΎΠΌΡΠ½ΡƒΡ‚Ρ‹Ρ… ядСр:

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git
$ cd bpf-next

Π‘ΠΎΠ±Ρ€Π°Ρ‚ΡŒ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‰ΠΈΠΉ ΠΊΠΎΠ½Ρ„ΠΈΠ³ ядра:

$ cp /boot/config-`uname -r` .config
$ make localmodconfig

Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ ΠΎΠΏΡ†ΠΈΠΈ BPF Π² Ρ„Π°ΠΉΠ»Π΅ .config ΠΏΠΎ своСму Π²Ρ‹Π±ΠΎΡ€Ρƒ (скорСС всСго, сам CONFIG_BPF ΡƒΠΆΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΊΠ»ΡŽΡ‡Π΅Π½, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ Π΅Π³ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ systemd). Π’ΠΎΡ‚ список ΠΎΠΏΡ†ΠΈΠΉ ΠΈΠ· ядра, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ использовалось для этой ΡΡ‚Π°Ρ‚ΡŒΠΈ:

CONFIG_CGROUP_BPF=y
CONFIG_BPF=y
CONFIG_BPF_LSM=y
CONFIG_BPF_SYSCALL=y
CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_JIT_DEFAULT_ON=y
CONFIG_IPV6_SEG6_BPF=y
# CONFIG_NETFILTER_XT_MATCH_BPF is not set
# CONFIG_BPFILTER is not set
CONFIG_NET_CLS_BPF=y
CONFIG_NET_ACT_BPF=y
CONFIG_BPF_JIT=y
CONFIG_BPF_STREAM_PARSER=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_BPF_EVENTS=y
CONFIG_BPF_KPROBE_OVERRIDE=y
CONFIG_DEBUG_INFO_BTF=y

Π”Π°Π»ΡŒΡˆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π»Π΅Π³ΠΊΠΎ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ ΠΈ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΌΠΎΠ΄ΡƒΠ»ΠΈ ΠΈ ядро (кстати, ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ ядро ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‡Ρ‚ΠΎ собранного clang, Π΄ΠΎΠ±Π°Π²ΠΈΠ² CC=clang):

$ make -s -j $(getconf _NPROCESSORS_ONLN)
$ sudo make modules_install
$ sudo make install

ΠΈ ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒΡΡ с Π½ΠΎΠ²Ρ‹ΠΌ ядром (я ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽ для этого kexec ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° kexec-tools):

v=5.8.0-rc6+ # Ссли Π²Ρ‹ пСрСсобираСтС Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ ядро, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ v=`uname -r`
sudo kexec -l -t bzImage /boot/vmlinuz-$v --initrd=/boot/initrd.img-$v --reuse-cmdline &&
sudo kexec -e

bpftool

НаиболСС часто ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠΉ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚ΠΎΠΉ Π² ΡΡ‚Π°Ρ‚ΡŒΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π° bpftool, поставляСмая Π² составС ядра Linux. Она написана ΠΈ поддСрТиваСтся Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°ΠΌΠΈ BPF для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ² BPF ΠΈ с Π΅Π΅ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒΡΡ со всСми Ρ‚ΠΈΠΏΠ°ΠΌΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² BPF β€” Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΈ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ maps, ΠΈΡΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚ΡŒ ΠΆΠΈΠ·Π½Π΅Π΄Π΅ΡΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ экосистСмы BPF, ΠΈ Ρ‚.ΠΏ. Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡŽ Π² Π²ΠΈΠ΄Π΅ исходников ΠΊ man pages ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ Π² ядрС ΠΈΠ»ΠΈ, ΡƒΠΆΠ΅ ΡΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Π½Π½ΡƒΡŽ, Π² сСти.

На ΠΌΠΎΠΌΠ΅Π½Ρ‚ написания ΡΡ‚Π°Ρ‚ΡŒΠΈ bpftool поставляСтся Π² Π³ΠΎΡ‚ΠΎΠ²ΠΎΠΌ Π²ΠΈΠ΄Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для RHEL, Fedora ΠΈ Ubuntu (см., Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, этот Ρ‚Ρ€Π΅Π΄, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ рассказываСтся нСокончСнная история опакСчивания bpftool Π² Debian). Но Ссли Π²Ρ‹ ΡƒΠΆΠ΅ собрали своС ядро, Ρ‚ΠΎ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ bpftool ΠΏΡ€ΠΎΡ‰Π΅ простого:

$ cd ${linux}/tools/bpf/bpftool
# ... ΠΏΡ€ΠΎΠΏΠΈΡˆΠΈΡ‚Π΅ ΠΏΡƒΡ‚ΠΈ ΠΊ послСднСму clang, ΠΊΠ°ΠΊ рассказано Π²Ρ‹ΡˆΠ΅
$ make -s

Auto-detecting system features:
...                        libbfd: [ on  ]
...        disassembler-four-args: [ on  ]
...                          zlib: [ on  ]
...                        libcap: [ on  ]
...               clang-bpf-co-re: [ on  ]

Auto-detecting system features:
...                        libelf: [ on  ]
...                          zlib: [ on  ]
...                           bpf: [ on  ]

$

(здСсь ${linux} β€” это ваша дирСктория с ядром.) ПослС выполнСния этих ΠΊΠΎΠΌΠ°Π½Π΄ bpftool Π±ΡƒΠ΄Π΅Ρ‚ собрана Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ ${linux}/tools/bpf/bpftool ΠΈ Π΅Π΅ ΠΌΠΎΠΆΠ½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ Π² ΠΏΡƒΡ‚ΡŒ (ΠΏΡ€Π΅ΠΆΠ΄Π΅ всСго ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ root) ΠΈΠ»ΠΈ просто ΡΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π² /usr/local/sbin.

Π‘ΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ bpftool Π»ΡƒΡ‡ΡˆΠ΅ всСго ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ послСднСго clang, собранного, ΠΊΠ°ΠΊ рассказано Π²Ρ‹ΡˆΠ΅, Π° ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ, ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ Π»ΠΈ ΠΎΠ½Π° ΡΠΎΠ±Ρ€Π°Π»Π°ΡΡŒ β€” ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹

$ sudo bpftool feature probe kernel
Scanning system configuration...
bpf() syscall for unprivileged users is enabled
JIT compiler is enabled
JIT compiler hardening is disabled
JIT compiler kallsyms exports are enabled for root
...

которая ΠΏΠΎΠΊΠ°ΠΆΠ΅Ρ‚, ΠΊΠ°ΠΊΠΈΠ΅ Ρ„ΠΈΡ‡ΠΈ BPF Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹ Ρƒ вас Π² ядрС.

ΠšΡΡ‚Π°Ρ‚ΠΈ, ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΡƒΡŽ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΊΠ°ΠΊ

# bpftool f p k

Π­Ρ‚ΠΎ сдСлано ΠΏΠΎ Π°Π½Π°Π»ΠΎΠ³ΠΈΠΈ с ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π°ΠΌΠΈ ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° iproute2, Π³Π΄Π΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΡΠΊΠ°Π·Π°Ρ‚ΡŒ ip a s eth0 вмСсто ip addr show dev eth0.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

BPF позволяСт ΠΏΠΎΠ΄ΠΊΠΎΠ²Π°Ρ‚ΡŒ Π±Π»ΠΎΡ…Ρƒ эффСктивно ΠΈΠ·ΠΌΠ΅Ρ€ΡΡ‚ΡŒ ΠΈ Π½Π°Π»Π΅Ρ‚Ρƒ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ ядра. БистСма ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»Π°ΡΡŒ ΠΎΡ‡Π΅Π½ΡŒ ΡƒΠ΄Π°Ρ‡Π½ΠΎΠΉ, Π² Π»ΡƒΡ‡ΡˆΠΈΡ… традициях UNIX: простой ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ (ΠΏΠ΅Ρ€Π΅)ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ядро, ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΠ» ΠΎΠ³Ρ€ΠΎΠΌΠ½ΠΎΠΌΡƒ количСству людСй ΠΈ ΠΎΡ€Π³Π°Π½ΠΈΠ·Π°Ρ†ΠΈΠΉ ΡΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ. И, хотя экспСримСнты, Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΊΠ°ΠΊ ΠΈ Ρ€Π°Π·Π²ΠΈΡ‚ΠΈΠ΅ самой инфраструктуры BPF, Π΅Ρ‰Π΅ Π΄Π°Π»Π΅ΠΊΠΎ Π½Π΅ Π·Π°ΠΊΠΎΠ½Ρ‡Π΅Π½Ρ‹, систСма ΡƒΠΆΠ΅ ΠΈΠΌΠ΅Π΅Ρ‚ ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½ΠΎΠ΅ ABI, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰Π΅Π΅ Π²Ρ‹ΡΡ‚Ρ€Π°ΠΈΠ²Π°Ρ‚ΡŒ Π½Π°Π΄Π΅ΠΆΠ½ΡƒΡŽ, Π° Π³Π»Π°Π²Π½ΠΎΠ΅, ΡΡ„Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΡƒΡŽ бизнСс-Π»ΠΎΠ³ΠΈΠΊΡƒ.

Π₯очСтся ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΏΠΎ ΠΌΠΎΠ΅ΠΌΡƒ мнСнию тСхнология ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»Π°ΡΡŒ Π½Π°ΡΡ‚ΠΎΠ»ΡŒΠΊΠΎ популярной ΠΎΡ‚Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ с ΠΎΠ΄Π½ΠΎΠΉ стороны, Π² Π½Π΅Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΠ³Ρ€Π°Ρ‚ΡŒ (Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρƒ ΠΌΠ°ΡˆΠΈΠ½Ρ‹ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ½ΡΡ‚ΡŒ Π±ΠΎΠ»Π΅Π΅-ΠΌΠ΅Π½Π΅Π΅ Π·Π° ΠΎΠ΄ΠΈΠ½ Π²Π΅Ρ‡Π΅Ρ€), Π° с Π΄Ρ€ΡƒΠ³ΠΎΠΉ β€”Β Ρ€Π΅ΡˆΠ°Ρ‚ΡŒ Π·Π°Π΄Π°Ρ‡ΠΈ, Π½Π΅ Ρ€Π΅ΡˆΠ°Π΅ΠΌΡ‹Π΅ (красиво) Π΄ΠΎ Π΅Π΅ появлСния. Π”Π²Π΅ эти ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ вмСстС Π·Π°ΡΡ‚Π°Π²Π»ΡΡŽΡ‚ людСй ΡΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ ΠΌΠ΅Ρ‡Ρ‚Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΈ ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ ΠΊ появлСнию всС Π½ΠΎΠ²Ρ‹Ρ… ΠΈ Π½ΠΎΠ²Ρ‹Ρ… ΠΈΠ½Π½ΠΎΠ²Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Ρ… Ρ€Π΅ΡˆΠ΅Π½ΠΈΠΉ.

Данная ΡΡ‚Π°Ρ‚ΡŒΡ, Ρ…ΠΎΡ‚ΡŒ ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»Π°ΡΡŒ Π½Π΅ особо ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΎΠΉ, являСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π²Π²Π΅Π΄Π΅Π½ΠΈΠ΅ΠΌ Π² ΠΌΠΈΡ€ BPF ΠΈ Π½Π΅ описываСт Β«ΠΏΡ€ΠΎΠ΄Π²ΠΈΠ½ΡƒΡ‚Ρ‹Π΅Β» возмоТности ΠΈ Π²Π°ΠΆΠ½Ρ‹Π΅ части Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹. Π”Π°Π»ΡŒΠ½Π΅ΠΉΡˆΠΈΠΉ ΠΏΠ»Π°Π½, ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ, Ρ‚Π°ΠΊΠΎΠΉ: ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π°Ρ ΡΡ‚Π°Ρ‚ΡŒΡ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠ±Π·ΠΎΡ€ΠΎΠΌ Ρ‚ΠΈΠΏΠΎΠ² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ BPF (Π² ядрС 5.8 поддСрТиваСтся 30 Ρ‚ΠΈΠΏΠΎΠ² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ), Π·Π°Ρ‚Π΅ΠΌ ΠΌΡ‹, Π½Π°ΠΊΠΎΠ½Π΅Ρ†, посмотрим Π½Π° Ρ‚ΠΎ, ΠΊΠ°ΠΊ ΠΏΠΈΡΠ°Ρ‚ΡŒ настоящиС прилоТСния Π½Π° BPF Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ для трассировки ядра, Π·Π°Ρ‚Π΅ΠΌ ΠΏΡ€ΠΈΠ΄Π΅Ρ‚ врСмя для Π±ΠΎΠ»Π΅Π΅ ΡƒΠ³Π»ΡƒΠ±Π»Π΅Π½Π½ΠΎΠ³ΠΎ курса ΠΏΠΎ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅ BPF, Π° Π·Π°Ρ‚Π΅ΠΌ β€” для ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ² сСтСвых ΠΈ security ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ BPF.

ΠŸΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠ΅ ΡΡ‚Π°Ρ‚ΡŒΠΈ этого Ρ†ΠΈΠΊΠ»Π°

  1. BPF для самых ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ…, Ρ‡Π°ΡΡ‚ΡŒ нулСвая: classic BPF

Π‘Ρ‹Π»ΠΊΠΈ

  1. BPF and XDP Reference Guide β€” докумСнтация ΠΏΠΎ BPF ΠΎΡ‚ cilium, Π° Ρ‚ΠΎΡ‡Π½Π΅Π΅ ΠΎΡ‚ Daniel Borkman, ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΈΠ· создатСлСй ΠΈ ΠΌΠ°Π½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠ² BPF. Π­Ρ‚ΠΎ ΠΎΠ΄Π½ΠΎ ΠΈΠ· ΠΏΠ΅Ρ€Π²Ρ‹Ρ… ΡΠ΅Ρ€ΡŒΠ΅Π·Π½Ρ‹Ρ… описаний, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΎΡ‚Π»ΠΈΡ‡Π½ΠΎ ΠΎΡ‚ ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Ρ… Ρ‚Π΅ΠΌ, Ρ‡Ρ‚ΠΎ Daniel Ρ‚ΠΎΡ‡Π½ΠΎ Π·Π½Π°Π΅Ρ‚ ΠΎ Ρ‡Π΅ΠΌ ΠΏΠΈΡˆΠ΅Ρ‚ ΠΈ ляпов Ρ‚Π°ΠΌ Π½Π΅ Π½Π°Π±Π»ΡŽΠ΄Π°Π΅Ρ‚ΡΡ. Π’ частности, Π² этом Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π΅ рассказываСтся ΠΊΠ°ΠΊ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°ΠΌΠΈ BPF Ρ‚ΠΈΠΏΠΎΠ² XDP ΠΈ TC ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ извСстной ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ ip ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° iproute2.

  2. Documentation/networking/filter.txt β€” ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» с Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠ΅ΠΉ ΠΏΠΎ классичСскому, Π° Π·Π°Ρ‚Π΅ΠΌ ΠΈ ΠΏΠΎ extended BPF. ПолСзно Ρ‡ΠΈΡ‚Π°Ρ‚ΡŒ, Ссли Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΠΎΠΊΠΎΠΏΠ°Ρ‚ΡŒΡΡ Π² ассСмблСрС ΠΈ тСхничСских дСталях Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹.

  3. Π‘Π»ΠΎΠ³ ΠΏΡ€ΠΎ BPF ΠΎΡ‚ facebook. ΠžΠ±Π½ΠΎΠ²Π»ΡΠ΅Ρ‚ΡΡ Ρ€Π΅Π΄ΠΊΠΎ, Π½ΠΎ ΠΌΠ΅Ρ‚ΠΊΠΎ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΏΠΈΡˆΡƒΡ‚ Ρ‚ΡƒΠ΄Π° Alexei Starovoitov (Π°Π²Ρ‚ΠΎΡ€ eBPF) ΠΈ Andrii Nakryiko β€” (ΠΌΠ°Π½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ libbpf).

  4. Π‘Π΅ΠΊΡ€Π΅Ρ‚Ρ‹ bpftool. Π—Π°Π½ΠΈΠΌΠ°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ twitter-Ρ‚Ρ€Π΅Π΄ ΠΎΡ‚ Quentin Monnet с ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°ΠΌΠΈ ΠΈ сСкрСтами использования bpftool.

  5. Dive into BPF: a list of reading material. Гигантский (ΠΈ Π΄ΠΎ сих ΠΏΠΎΡ€ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅ΠΌΡ‹ΠΉ) список ссылок Π½Π° Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡŽ ΠΏΠΎ BPF ΠΎΡ‚ Quentin Monnet.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ