BPF fun awọn ọmọ kekere, apakan akọkọ: BPF ti o gbooro

Ni ibẹrẹ imọ-ẹrọ kan wa ati pe a pe ni BPF. A wò ó ti tẹlẹ, Majẹmu Lailai article ti yi jara. Ni ọdun 2013, nipasẹ awọn igbiyanju Alexei Starovoitov ati Daniel Borkman, ẹya ti o ni ilọsiwaju, ti o dara julọ fun awọn ẹrọ 64-bit ode oni, ni idagbasoke ati pẹlu ekuro Linux. Imọ-ẹrọ tuntun yii ni ṣoki ti a pe ni BPF Inu, lẹhinna fun lorukọmii Extended BPF, ati ni bayi, lẹhin ọdun pupọ, gbogbo eniyan n pe ni BPF.

Ni aijọju, BPF ngbanilaaye lati ṣiṣẹ koodu ti olumulo ti a pese lainidii ni aaye ekuro Linux, ati pe faaji tuntun yipada lati ṣaṣeyọri tobẹẹ ti a yoo nilo awọn nkan mejila diẹ sii lati ṣapejuwe gbogbo awọn ohun elo rẹ. (Ohun kan ṣoṣo ti awọn olupilẹṣẹ ko ṣe daradara, bi o ti le rii ninu koodu iṣẹ ni isalẹ, ni ṣiṣẹda aami to bojumu.)

Nkan yii ṣapejuwe eto ti ẹrọ foju BPF, awọn atọkun kernel fun ṣiṣẹ pẹlu BPF, awọn irinṣẹ idagbasoke, bakanna bi kukuru kan, akopọ kukuru pupọ ti awọn agbara ti o wa tẹlẹ, ie. ohun gbogbo ti a yoo nilo ni ojo iwaju fun iwadi ti o jinlẹ ti awọn ohun elo ti o wulo ti BPF.
BPF fun awọn ọmọ kekere, apakan akọkọ: BPF ti o gbooro

Akopọ ti awọn article

Ifihan si BPF faaji. Ni akọkọ, a yoo ṣe iwo oju eye ti faaji BPF ati ṣe ilana awọn paati akọkọ.

Awọn iforukọsilẹ ati eto aṣẹ ti ẹrọ foju BPF. Tẹlẹ ti ni imọran ti faaji lapapọ, a yoo ṣe apejuwe eto ti ẹrọ foju BPF.

Aye igbesi aye ti awọn nkan BPF, eto faili bpffs. Ni apakan yii, a yoo ṣe akiyesi ni pẹkipẹki ni ọna igbesi aye ti awọn nkan BPF - awọn eto ati awọn maapu.

Ṣiṣakoso awọn nkan nipa lilo ipe eto bpf. Pẹlu oye diẹ ti eto ti wa tẹlẹ, a yoo nipari wo bii o ṣe le ṣẹda ati ṣe afọwọyi awọn nkan lati aaye olumulo nipa lilo ipe eto pataki kan - bpf(2).

Пишем программы BPF с помощью libbpf. Nitoribẹẹ, o le kọ awọn eto nipa lilo ipe eto kan. Sugbon o soro. Fun oju iṣẹlẹ ti o daju diẹ sii, awọn olupilẹṣẹ iparun ṣe agbekalẹ ile-ikawe kan libbpf. A yoo ṣẹda egungun ohun elo BPF ipilẹ ti a yoo lo ninu awọn apẹẹrẹ atẹle.

Awọn oluranlọwọ Ekuro. Nibi a yoo kọ ẹkọ bii awọn eto BPF ṣe le wọle si awọn iṣẹ oluranlọwọ kernel - irinṣẹ kan ti, papọ pẹlu awọn maapu, ni ipilẹṣẹ faagun awọn agbara ti BPF tuntun ni akawe si Ayebaye kan.

Wiwọle si awọn maapu lati awọn eto BPF. Nipa aaye yii, a yoo mọ to lati ni oye gangan bi a ṣe le ṣẹda awọn eto ti o lo awọn maapu. Ati pe jẹ ki a paapaa yoju ni iyara sinu oludaniloju nla ati alagbara.

Awọn irinṣẹ idagbasoke. Abala iranlọwọ lori bi o ṣe le ṣajọ awọn ohun elo ti o nilo ati ekuro fun awọn idanwo.

Ipari. Ní òpin àpilẹ̀kọ náà, àwọn tó bá ń ka èyí tó jìnnà réré yóò rí àwọn ọ̀rọ̀ tó wúni lórí àti àpèjúwe ṣókí nípa ohun tó máa ṣẹlẹ̀ nínú àwọn àpilẹ̀kọ tó kàn. A yoo tun ṣe atokọ nọmba awọn ọna asopọ fun ikẹkọ ti ara ẹni fun awọn ti ko ni ifẹ tabi agbara lati duro fun itesiwaju naa.

Ifihan si BPF Architecture

Ṣaaju ki a to bẹrẹ lati gbero faaji BPF, a yoo tọka si akoko ikẹhin kan (oh) si Ayebaye BPF, eyi ti o ti ni idagbasoke bi idahun si dide ti awọn ẹrọ RISC ati pe o yanju iṣoro ti sisẹ packet daradara. Awọn faaji wa ni jade lati wa ni ki aseyori ti, ti a bi ninu awọn dashing nineties ni Berkeley UNIX, ti o ti ported si julọ tẹlẹ awọn ọna šiše, ye sinu irikuri twenties ati ki o ti wa ni ṣi wiwa titun awọn ohun elo.

BPF tuntun ni idagbasoke bi idahun si ibigbogbo ti awọn ẹrọ 64-bit, awọn iṣẹ awọsanma ati iwulo alekun fun awọn irinṣẹ fun ṣiṣẹda SDN (Sohun elo-desan nsise). Ni idagbasoke nipasẹ awọn onimọ-ẹrọ nẹtiwọọki ekuro bi aropo ilọsiwaju fun BPF Ayebaye, BPF tuntun ni itumọ ọrọ gangan oṣu mẹfa lẹhinna rii awọn ohun elo ninu iṣẹ ṣiṣe ti o nira ti wiwa awọn eto Linux, ati ni bayi, ọdun mẹfa lẹhin irisi rẹ, a yoo nilo gbogbo nkan atẹle kan lati ṣe akojọ awọn oriṣiriṣi awọn eto.

Awọn aworan alarinrin

Ni ipilẹ rẹ, BPF jẹ ẹrọ foju apoti iyanrin ti o fun ọ laaye lati ṣiṣẹ koodu “lainidii” ni aaye ekuro laisi ibajẹ aabo. Awọn eto BPF ni a ṣẹda ni aaye olumulo, ti kojọpọ sinu ekuro, ati sopọ si orisun iṣẹlẹ kan. Iṣẹlẹ kan le jẹ, fun apẹẹrẹ, ifijiṣẹ ti apo kan si wiwo nẹtiwọọki kan, ifilọlẹ iṣẹ ekuro kan, ati bẹbẹ lọ. Ninu ọran ti package, eto BPF yoo ni iwọle si data ati metadata ti package (fun kika ati, o ṣee ṣe, kikọ, da lori iru eto); ninu ọran ti ṣiṣiṣẹ iṣẹ ekuro, awọn ariyanjiyan ti iṣẹ naa, pẹlu awọn itọka si iranti ekuro, ati bẹbẹ lọ.

Jẹ ki a ṣe akiyesi ilana yii ni pẹkipẹki. Lati bẹrẹ pẹlu, jẹ ki a sọrọ nipa iyatọ akọkọ lati BPF Ayebaye, awọn eto eyiti a kọ sinu apejọ. Ni titun ti ikede, awọn faaji ti a ti fẹ ki awọn eto le wa ni kikọ ni awọn ede giga, nipataki, dajudaju, ni C. Fun eyi, a backend fun llvm ti a ni idagbasoke, eyi ti o faye gba o lati se ina bytecode fun awọn BPF faaji.

BPF fun awọn ọmọ kekere, apakan akọkọ: BPF ti o gbooro

A ṣe apẹrẹ faaji BPF, ni apakan, lati ṣiṣẹ daradara lori awọn ẹrọ ode oni. Lati ṣe iṣẹ yii ni iṣe, BPF bytecode, ni kete ti kojọpọ sinu ekuro, ti tumọ si koodu abinibi nipa lilo paati kan ti a pe ni akopọ JIT (Just In Time). Nigbamii ti, ti o ba ranti, ni BPF Ayebaye eto naa ti kojọpọ sinu ekuro ati somọ orisun iṣẹlẹ atomically - ni aaye ti ipe eto ẹyọkan. Ninu faaji tuntun, eyi ṣẹlẹ ni awọn ipele meji - akọkọ, koodu ti kojọpọ sinu ekuro nipa lilo ipe eto kan. bpf(2)ati lẹhinna, nigbamii, nipasẹ awọn ilana miiran ti o yatọ da lori iru eto, eto naa somọ orisun iṣẹlẹ naa.

Nibi oluka le ni ibeere kan: ṣe o ṣee ṣe? Bawo ni aabo ipaniyan ti iru koodu ṣe jẹ iṣeduro? Aabo ipaniyan jẹ iṣeduro fun wa nipasẹ ipele ti ikojọpọ awọn eto BPF ti a pe ni verifier (ni ede Gẹẹsi ipele yii ni a pe ni oludaniloju ati pe Emi yoo tẹsiwaju lati lo ọrọ Gẹẹsi):

BPF fun awọn ọmọ kekere, apakan akọkọ: BPF ti o gbooro

Verifier jẹ olutupalẹ aimi ti o ni idaniloju pe eto kan ko ni idilọwọ iṣẹ deede ti ekuro. Eyi, nipasẹ ọna, ko tumọ si pe eto naa ko le dabaru pẹlu iṣẹ ṣiṣe ti eto - awọn eto BPF, da lori iru, le ka ati atunkọ awọn apakan ti iranti ekuro, awọn iye pada ti awọn iṣẹ, gige, append, atunkọ ati paapa siwaju nẹtiwọki awọn apo-iwe. Verifier ṣe iṣeduro pe ṣiṣe eto BPF kii yoo jamba ekuro ati pe eto kan ti, ni ibamu si awọn ofin, ni iraye si kikọ, fun apẹẹrẹ, data ti apo ti njade, kii yoo ni anfani lati kọ iranti ekuro ni ita apo-iwe naa. A yoo wo oludaniloju ni awọn alaye diẹ sii ni apakan ti o baamu, lẹhin ti a ba ni oye pẹlu gbogbo awọn paati miiran ti BPF.

Nitorina kini a ti kọ bẹ? Olumulo naa kọ eto kan ni C, gbe e sinu ekuro nipa lilo ipe eto kan bpf(2), nibiti o ti ṣayẹwo nipasẹ oludaniloju ati tumọ si bytecode abinibi. Lẹhinna olumulo kanna tabi olumulo miiran so eto naa pọ si orisun iṣẹlẹ ati pe o bẹrẹ lati ṣiṣẹ. Iyapa bata ati asopọ jẹ pataki fun awọn idi pupọ. Ni akọkọ, ṣiṣe ijẹrisi jẹ gbowolori diẹ ati nipa gbigba eto kanna ni ọpọlọpọ igba a padanu akoko kọnputa. Ni ẹẹkeji, ni deede bii eto ṣe sopọ da lori iru rẹ, ati ọkan “gbogbo” wiwo ti o dagbasoke ni ọdun kan sẹhin le ma dara fun awọn iru awọn eto tuntun. (Biotilẹjẹpe ni bayi pe faaji ti di ogbo diẹ sii, imọran wa lati ṣọkan wiwo yii ni ipele naa libbpf.)

Oluka akiyesi le ṣe akiyesi pe a ko ti pari pẹlu awọn aworan sibẹsibẹ. Lootọ, gbogbo awọn ti o wa loke ko ṣe alaye idi ti BPF ṣe yi aworan pada ni pataki ni akawe si BPF Ayebaye. Awọn imotuntun meji ti o gbooro ni pataki iwọn lilo ohun elo ni agbara lati lo iranti pinpin ati awọn iṣẹ oluranlọwọ ekuro. Ni BPF, iranti pinpin jẹ imuse nipa lilo awọn maapu ti a pe - awọn ẹya data pinpin pẹlu API kan pato. Boya wọn ni orukọ yii nitori pe iru maapu akọkọ ti o han ni tabili hash. Lẹhinna awọn akojọpọ han, awọn tabili hash agbegbe (fun-CPU) ati awọn akojọpọ agbegbe, awọn igi wiwa, awọn maapu ti o ni awọn itọka si awọn eto BPF ati pupọ diẹ sii. Ohun ti o nifẹ si wa ni bayi ni pe awọn eto BPF ni bayi ni agbara lati tẹsiwaju ipo laarin awọn ipe ati pin pẹlu awọn eto miiran ati pẹlu aaye olumulo.

Awọn maapu ti wọle lati awọn ilana olumulo nipa lilo ipe eto kan bpf(2), ati lati awọn eto BPF nṣiṣẹ ninu ekuro nipa lilo awọn iṣẹ oluranlọwọ. Pẹlupẹlu, awọn oluranlọwọ wa kii ṣe lati ṣiṣẹ pẹlu awọn maapu nikan, ṣugbọn tun lati wọle si awọn agbara ekuro miiran. Fun apẹẹrẹ, awọn eto BPF le lo awọn iṣẹ oluranlọwọ lati firanṣẹ awọn apo-iwe si awọn atọkun miiran, ṣe ipilẹṣẹ awọn iṣẹlẹ perf, awọn ẹya kernel wiwọle, ati bẹbẹ lọ.

BPF fun awọn ọmọ kekere, apakan akọkọ: BPF ti o gbooro

Ni akojọpọ, BPF n pese agbara lati fifuye lainidii, ie, idanwo-ijẹrisi, koodu olumulo sinu aaye ekuro. Koodu yii le ṣafipamọ ipo laarin awọn ipe ati data paṣipaarọ pẹlu aaye olumulo, ati tun ni iwọle si awọn eto inu ekuro ti o gba laaye nipasẹ iru eto.

Eyi jẹ iru awọn agbara ti a pese nipasẹ awọn modulu ekuro, ni akawe si eyiti BPF ni diẹ ninu awọn anfani (dajudaju, o le ṣe afiwe awọn ohun elo kanna, fun apẹẹrẹ, wiwa eto - iwọ ko le kọ awakọ lainidii pẹlu BPF). O le ṣe akiyesi ẹnu-ọna titẹsi kekere kan (diẹ ninu awọn ohun elo ti o lo BPF ko nilo olumulo lati ni awọn ọgbọn siseto ekuro, tabi awọn ọgbọn siseto ni gbogbogbo), ailewu asiko (gbe ọwọ rẹ soke ni awọn asọye fun awọn ti ko fọ eto nigba kikọ tabi awọn modulu idanwo), atomity - akoko isinmi wa nigbati awọn modulu tun gbejade, ati eto ipilẹ BPF ṣe idaniloju pe ko si awọn iṣẹlẹ ti o padanu (lati jẹ otitọ, eyi kii ṣe otitọ fun gbogbo awọn iru awọn eto BPF).

Iwaju iru awọn agbara bẹẹ jẹ ki BPF jẹ ohun elo gbogbo agbaye fun faagun ekuro, eyiti o jẹrisi ni iṣe: diẹ sii ati siwaju sii awọn iru eto tuntun ti a ṣafikun si BPF, awọn ile-iṣẹ nla ati siwaju sii lo BPF lori awọn olupin ija 24 × 7, siwaju ati siwaju sii. awọn ibẹrẹ kọ iṣowo wọn lori awọn solusan ti o da lori eyiti o da lori BPF. A lo BPF nibi gbogbo: ni aabo lodi si awọn ikọlu DDoS, ṣiṣẹda SDN (fun apẹẹrẹ, imuse awọn nẹtiwọọki fun kubernetes), bi ohun elo wiwa kakiri eto akọkọ ati olugba awọn iṣiro, ni awọn eto wiwa ifọle ati awọn ọna apoti iyanrin, ati bẹbẹ lọ.

Jẹ ki a pari apakan Akopọ ti nkan naa nibi ki o wo ẹrọ foju ati ilolupo BPF ni awọn alaye diẹ sii.

Digression: igbesi

Lati le ni anfani lati ṣiṣe awọn apẹẹrẹ ni awọn apakan atẹle, o le nilo nọmba awọn ohun elo, o kere ju. llvm/clang pẹlu bpf support ati bpftool... Ni ipin Awọn Irinṣẹ Idagbasoke O le ka awọn itọnisọna fun apejọ awọn ohun elo, bakanna bi ekuro rẹ. Abala yii wa ni isalẹ ki o má ba ṣe idamu ibaramu ti igbejade wa.

BPF foju Machine registers ati ilana System

Ilana faaji ati eto aṣẹ ti BPF ni idagbasoke ni akiyesi otitọ pe awọn eto yoo kọ ni ede C ati, lẹhin ikojọpọ sinu ekuro, tumọ si koodu abinibi. Nitorinaa, nọmba awọn iforukọsilẹ ati ṣeto awọn aṣẹ ni a yan pẹlu oju si ikorita, ni ori mathematiki, ti awọn agbara ti awọn ẹrọ ode oni. Ni afikun, orisirisi awọn ihamọ ti wa ni ti paṣẹ lori awọn eto, fun apẹẹrẹ, titi laipe o je ko ṣee ṣe lati kọ losiwajulosehin ati subroutines, ati awọn nọmba ti ilana ti wa ni opin si 4096 (bayi awọn eto anfani le fifuye soke to a million ilana).

BPF ni awọn iforukọsilẹ 64-bit ti olumulo mọkanla r0-r10 ati counter eto. Forukọsilẹ r10 ni a fireemu ijuboluwole ati ki o jẹ kika-nikan. Awọn eto ni iwọle si akopọ 512-baiti ni asiko asiko ati iye ailopin ti iranti pinpin ni irisi awọn maapu.

Awọn eto BPF ni a gba laaye lati ṣiṣe eto kan pato ti awọn oluranlọwọ ekuro iru eto ati, laipẹ diẹ, awọn iṣẹ ṣiṣe deede. Iṣẹ kọọkan ti a pe le gba to awọn ariyanjiyan marun, ti o kọja ni awọn iforukọsilẹ r1-r5, ati awọn pada iye ti wa ni koja si r0. O jẹ iṣeduro pe lẹhin ti o pada lati iṣẹ naa, awọn akoonu ti awọn iforukọsilẹ r6-r9 Yoo ko yipada.

Fun itumọ eto daradara, forukọsilẹ r0-r11 fun gbogbo awọn faaji ti o ni atilẹyin ni a ya sọtọ si awọn iforukọsilẹ gidi, ni akiyesi awọn ẹya ABI ti faaji lọwọlọwọ. Fun apẹẹrẹ, fun x86_64 awọn iforukọsilẹ r1-r5, ti a lo lati kọja awọn paramita iṣẹ, ti han lori rdi, rsi, rdx, rcx, r8, eyi ti o ti lo lati ṣe awọn paramita si awọn iṣẹ lori x86_64. Fun apẹẹrẹ, koodu ti o wa ni apa osi tumọ si koodu ni apa ọtun bi eleyi:

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

Forukọsilẹ r0 tun lo lati pada abajade ti ipaniyan eto, ati ninu iforukọsilẹ r1 eto naa ti kọja itọka si ọrọ-ọrọ - da lori iru eto, eyi le jẹ, fun apẹẹrẹ, eto kan struct xdp_md (fun XDP) tabi be struct __sk_buff (fun yatọ si awọn eto nẹtiwọki) tabi be struct pt_regs (fun awọn oriṣiriṣi awọn eto wiwa kakiri), ati bẹbẹ lọ.

Nitorinaa, a ni eto awọn iforukọsilẹ, awọn oluranlọwọ kernel, akopọ kan, itọka ọrọ-ọrọ ati iranti pinpin ni irisi awọn maapu. Kii ṣe pe gbogbo eyi jẹ pataki ni irin-ajo naa, ṣugbọn…

Jẹ ki a tẹsiwaju apejuwe naa ki o sọrọ nipa eto aṣẹ fun ṣiṣẹ pẹlu awọn nkan wọnyi. Gbogbo (Fere gbogbo) Awọn ilana BPF ni iwọn 64-bit ti o wa titi. Ti o ba wo itọnisọna kan lori ẹrọ Big Endian 64-bit iwọ yoo rii

BPF fun awọn ọmọ kekere, apakan akọkọ: BPF ti o gbooro

o ti wa ni Code - Eyi ni fifi koodu ti itọnisọna naa, Dst/Src jẹ awọn koodu ti olugba ati orisun, lẹsẹsẹ, Off - 16-bit wole indentation, ati Imm jẹ odidi 32-bit ti o fowo si ti a lo ni diẹ ninu awọn ilana (bii cBPF ibakan K). fifi koodu Code ni ọkan ninu awọn oriṣi meji:

BPF fun awọn ọmọ kekere, apakan akọkọ: BPF ti o gbooro

Awọn kilasi itọnisọna 0, 1, 2, 3 ṣalaye awọn aṣẹ fun ṣiṣẹ pẹlu iranti. Won ti wa ni a npe ni, BPF_LD, BPF_LDX, BPF_ST, BPF_STX, lẹsẹsẹ. Awọn kilasi 4, 7 (BPF_ALU, BPF_ALU64) je kan ti ṣeto ti ALU ilana. Awọn kilasi 5, 6 (BPF_JMP, BPF_JMP32) ni awọn ilana fo ninu.

Eto siwaju fun kikọ ẹkọ eto ẹkọ BPF jẹ atẹle yii: dipo kikojọ gbogbo awọn ilana ati awọn ayewọn wọn, a yoo wo awọn apẹẹrẹ meji ni apakan yii ati lati ọdọ wọn yoo han gbangba bi awọn ilana ṣe ṣiṣẹ gangan ati bii o ṣe le ṣe. pẹlu ọwọ tu eyikeyi faili alakomeji fun BPF. Lati ṣopọ ohun elo nigbamii ni nkan naa, a yoo tun pade pẹlu awọn itọnisọna kọọkan ni awọn apakan nipa Verifier, olupilẹṣẹ JIT, itumọ ti BPF Ayebaye, ati nigba ikẹkọ awọn maapu, awọn iṣẹ pipe, ati bẹbẹ lọ.

Nigba ti a ba sọrọ nipa awọn itọnisọna kọọkan, a yoo tọka si awọn faili mojuto bpf.h и bpf_common.h, eyiti o ṣalaye awọn koodu nọmba ti awọn ilana BPF. Nigbati o ba nkọ ẹkọ faaji lori tirẹ ati/tabi itupalẹ awọn alakomeji, o le wa awọn atunmọ ni awọn orisun atẹle, lẹsẹsẹ ni aṣẹ ti idiju: Laigba aṣẹ eBPF spec, BPF ati XDP Itọsọna Itọkasi, Eto Ilana, Documentation/nẹtiwọki/filter.txt ati, dajudaju, ni Linux orisun koodu - verifier, JIT, BPF onitumọ.

Apeere: pipọ BPF ni ori rẹ

Jẹ ki a wo apẹẹrẹ kan ninu eyiti a ṣe akopọ eto kan readelf-example.c ati ki o wo ni Abajade alakomeji. A yoo ṣafihan akoonu atilẹba readelf-example.c ni isalẹ, lẹhin ti a mu pada ọgbọn rẹ pada lati awọn koodu alakomeji:

$ 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 ................

Akọkọ ọwọn ni o wu readelf jẹ indentation ati eto wa nitorina ni awọn ofin mẹrin:

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

Awọn koodu aṣẹ jẹ dogba b7, 15, b7 и 95. Ranti pe awọn die-die mẹta ti o kere ju ni pataki ni kilasi itọnisọna. Ninu ọran wa, ipin kẹrin ti gbogbo awọn ilana jẹ ofo, nitorinaa awọn kilasi itọnisọna jẹ 7, 5, 7, 5, lẹsẹsẹ. Kilasi 7 jẹ BPF_ALU64, ati 5 ni BPF_JMP. Fun awọn kilasi mejeeji, ọna kika itọnisọna jẹ kanna (wo loke) ati pe a le tun kọ eto wa bii eyi (ni akoko kanna a yoo tun kọ awọn ọwọn to ku ni fọọmu eniyan):

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

Isẹ b kilasi ALU64 Ṣe BPF_MOV. O ṣe ipinnu iye kan si iforukọsilẹ opin irin ajo. Ti o ba ti ṣeto bit s (orisun), lẹhinna iye naa ni a gba lati iforukọsilẹ orisun, ati pe, bi ninu ọran wa, ko ṣeto, lẹhinna iye naa ni a gba lati aaye naa. Imm. Nitorina ni awọn ilana akọkọ ati kẹta a ṣe iṣẹ naa r0 = Imm. Siwaju sii, iṣẹ JMP kilasi 1 jẹ BPF_JEQ (fo ti o ba ti dogba). Ninu ọran wa, niwon bit S jẹ odo, o ṣe afiwe iye ti iforukọsilẹ orisun pẹlu aaye Imm. Ti awọn iye ba ṣe deede, lẹhinna iyipada waye si PC + Offnibo PC, gẹgẹ bi igbagbogbo, ni adirẹsi ti itọnisọna atẹle ninu. Níkẹyìn, JMP Class 9 Isẹ jẹ BPF_EXIT. Ilana yii fopin si eto naa, pada si ekuro r0. Jẹ ki a ṣafikun iwe tuntun si tabili wa:

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

A le tun kọ eyi ni ọna irọrun diẹ sii:

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

Ti a ba ranti ohun ti o wa ninu awọn Forukọsilẹ r1 eto naa ti kọja itọka si ipo lati ekuro, ati ninu iforukọsilẹ r0 iye naa pada si ekuro, lẹhinna a le rii pe ti itọka si aaye naa jẹ odo, lẹhinna a pada 1, ati bibẹẹkọ - 2. Jẹ ki a ṣayẹwo pe a tọ nipa wiwo orisun naa:

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

Bẹẹni, o jẹ eto ti ko ni itumọ, ṣugbọn o tumọ si awọn itọnisọna rọrun mẹrin.

Iyatọ apẹẹrẹ: 16-baiti itọnisọna

A mẹnuba tẹlẹ pe diẹ ninu awọn ilana gba to ju 64 die-die. Eyi kan, fun apẹẹrẹ, si awọn itọnisọna lddw (koodu = 0x18 = BPF_LD | BPF_DW | BPF_IMM) - fifuye ọrọ meji lati awọn aaye sinu iforukọsilẹ Imm. Otitọ ni pe Imm ni iwọn 32, ati pe ọrọ ilọpo meji jẹ awọn iwọn 64, nitorinaa ikojọpọ iye 64-bit lẹsẹkẹsẹ sinu iforukọsilẹ ninu itọnisọna 64-bit kan kii yoo ṣiṣẹ. Lati ṣe eyi, awọn itọnisọna meji ti o wa nitosi ni a lo lati tọju apa keji ti iye 64-bit ni aaye naa Imm... Apẹẹrẹ:

$ 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                   ........

Awọn ilana meji nikan lo wa ninu eto alakomeji:

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

A yoo tun pade pẹlu awọn itọnisọna lddw, nigba ti a ba sọrọ nipa awọn iṣipopada ati ṣiṣẹ pẹlu awọn maapu.

Apeere: Pipapọ BPF ni lilo awọn irinṣẹ boṣewa

Nitorinaa, a ti kọ ẹkọ lati ka awọn koodu alakomeji BPF ati pe o ti ṣetan lati ṣe itupalẹ eyikeyi ilana ti o ba jẹ dandan. Sibẹsibẹ, o tọ lati sọ pe ni iṣe o rọrun diẹ sii ati yiyara lati ṣajọpọ awọn eto nipa lilo awọn irinṣẹ boṣewa, fun apẹẹrẹ:

$ 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

Igbesi aye ti awọn nkan BPF, eto faili bpffs

(Mo kọkọ kọ diẹ ninu awọn alaye ti a ṣalaye ninu apakan apakan yii lati ifiweranṣẹ Alexei Starovoitov ninu BPF Blog.)

Awọn nkan BPF - awọn eto ati awọn maapu - ni a ṣẹda lati aaye olumulo nipa lilo awọn aṣẹ BPF_PROG_LOAD и BPF_MAP_CREATE ipe eto bpf(2), a yoo sọrọ nipa gangan bi eyi ṣe ṣẹlẹ ni apakan atẹle. Eyi ṣẹda awọn ẹya data kernel ati fun ọkọọkan wọn refcount (Ika itọkasi) ti ṣeto si ọkan, ati pe oluṣapejuwe faili ti o tọka si nkan naa ni a da pada si olumulo. Lẹhin ti mimu ti wa ni pipade refcount Ohun naa yoo dinku nipasẹ ọkan, nigbati o ba de odo, ohun naa yoo run.

Ti eto naa ba nlo awọn maapu, lẹhinna refcount awọn maapu wọnyi pọ si nipasẹ ọkan lẹhin ikojọpọ eto naa, i.e. Awọn apejuwe faili wọn le wa ni pipade lati ilana olumulo ati ṣi refcount kii yoo di odo:

BPF fun awọn ọmọ kekere, apakan akọkọ: BPF ti o gbooro

Lẹhin ikojọpọ eto kan ni aṣeyọri, a maa n so pọ mọ iru olupilẹṣẹ iṣẹlẹ kan. Fun apẹẹrẹ, a le fi sii lori wiwo nẹtiwọọki lati ṣe ilana awọn apo-iwe ti nwọle tabi so pọ si diẹ ninu tracepoint ninu mojuto. Ni aaye yii, counter itọkasi yoo tun pọ si nipasẹ ọkan ati pe a yoo ni anfani lati pa apejuwe faili naa ni eto agberu.

Kini yoo ṣẹlẹ ti a ba tiipa bootloader bayi? O da lori iru olupilẹṣẹ iṣẹlẹ (kio). Gbogbo awọn ìkọ netiwọki yoo wa lẹhin ti agberu ba pari, iwọnyi ni ohun ti a pe ni kio agbaye. Ati, fun apẹẹrẹ, awọn eto itọpa yoo tu silẹ lẹhin ilana ti o ṣẹda wọn ti pari (ati nitori naa ni a pe ni agbegbe, lati “agbegbe si ilana”). Ni imọ-ẹrọ, awọn kio agbegbe nigbagbogbo ni oluṣapejuwe faili ti o baamu ni aaye olumulo ati nitorinaa sunmọ nigbati ilana naa ba wa ni pipade, ṣugbọn awọn kio agbaye ko ṣe. Ni nọmba ti o tẹle, ni lilo awọn agbelebu pupa, Mo gbiyanju lati fi han bi ifopinsi ti eto agberu yoo ni ipa lori igbesi aye awọn nkan ni ọran ti agbegbe ati awọn kio agbaye.

BPF fun awọn ọmọ kekere, apakan akọkọ: BPF ti o gbooro

Kini idi ti iyatọ laarin agbegbe ati awọn kio agbaye? Ṣiṣe diẹ ninu awọn iru awọn eto nẹtiwọọki jẹ oye laisi aaye olumulo kan, fun apẹẹrẹ, fojuinu aabo DDoS - bootloader kọ awọn ofin ati so eto BPF pọ si wiwo nẹtiwọọki, lẹhin eyi bootloader le lọ ki o pa ararẹ. Ni apa keji, fojuinu eto itọpa ti n ṣatunṣe aṣiṣe ti o kowe lori awọn ẽkun rẹ ni iṣẹju mẹwa - nigbati o ba ti pari, iwọ yoo fẹ pe ko si idoti ti o ku ninu eto naa, ati awọn kio agbegbe yoo rii daju pe.

Ni apa keji, fojuinu pe o fẹ sopọ si aaye itọpa ninu ekuro ati gba awọn iṣiro ni ọpọlọpọ ọdun. Ni idi eyi, iwọ yoo fẹ lati pari apakan olumulo ati pada si awọn iṣiro lati igba de igba. Eto faili bpf n pese anfani yii. O jẹ eto pseudo-faili inu-iranti nikan ti o fun laaye ẹda awọn faili ti o tọka si awọn nkan BPF ati nitorinaa pọ si refcount ohun elo. Lẹhin eyi, agberu le jade, ati awọn nkan ti o ṣẹda yoo wa laaye.

BPF fun awọn ọmọ kekere, apakan akọkọ: BPF ti o gbooro

Ṣiṣẹda awọn faili ni bpffs ti o tọka si awọn nkan BPF ni a pe ni "pinning" (gẹgẹbi ninu gbolohun ọrọ atẹle: "ilana le pin eto BPF tabi maapu kan"). Ṣiṣẹda awọn ohun elo faili fun awọn ohun BPF jẹ oye kii ṣe fun gigun igbesi aye awọn nkan agbegbe nikan, ṣugbọn fun lilo awọn ohun elo agbaye - pada si apẹẹrẹ pẹlu eto aabo DDoS agbaye, a fẹ lati ni anfani lati wa wo awọn iṣiro. lati akoko si akoko.

Eto faili BPF maa n gbe sinu /sys/fs/bpf, ṣugbọn o tun le gbe soke ni agbegbe, fun apẹẹrẹ, bii eyi:

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

Awọn orukọ eto faili ti ṣẹda nipa lilo aṣẹ BPF_OBJ_PIN BPF eto ipe. Lati ṣapejuwe, jẹ ki a mu eto kan, ṣajọ rẹ, gbee si, ki a pin si bpffs. Eto wa ko ṣe ohunkohun ti o wulo, a n ṣafihan koodu nikan ki o le tun apẹẹrẹ ṣe:

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

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

Jẹ ki a ṣajọ eto yii ki o ṣẹda ẹda agbegbe ti eto faili naa bpffs:

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

Bayi jẹ ki ká gba lati ayelujara wa eto nipa lilo awọn IwUlO bpftool ki o si wo awọn ipe eto ti o tẹle bpf(2) (diẹ ninu awọn laini ti ko ṣe pataki ti a yọkuro lati iṣelọpọ 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

Nibi ti a ti kojọpọ awọn eto nipa lilo BPF_PROG_LOAD, gba oluṣapejuwe faili kan lati ekuro 3 ati lilo aṣẹ BPF_OBJ_PIN ṣonṣo apejuwe faili yii bi faili kan "bpf-mountpoint/test". Lẹhin eyi eto bootloader bpftool pari iṣẹ, ṣugbọn eto wa wa ninu ekuro, botilẹjẹpe a ko so mọ ni wiwo nẹtiwọọki eyikeyi:

$ 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

A le pa ohun elo faili rẹ ni deede unlink(2) ati lẹhin naa eto ti o baamu yoo paarẹ:

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

Npa awọn nkan kuro

Nigbati o nsoro nipa piparẹ awọn nkan, o jẹ dandan lati ṣalaye pe lẹhin ti a ti ge asopọ eto naa kuro ninu kio (olupilẹṣẹ iṣẹlẹ), kii ṣe iṣẹlẹ tuntun kan ti yoo fa ifilọlẹ rẹ, sibẹsibẹ, gbogbo awọn iṣẹlẹ lọwọlọwọ ti eto naa yoo pari ni aṣẹ deede. .

Diẹ ninu awọn iru awọn eto BPF gba ọ laaye lati rọpo eto naa lori fo, i.e. pese atomity ọkọọkan replace = detach old program, attach new program. Ni ọran yii, gbogbo awọn iṣẹlẹ ti nṣiṣe lọwọ ti ẹya atijọ ti eto naa yoo pari iṣẹ wọn, ati pe awọn oluṣakoso iṣẹlẹ yoo ṣẹda lati inu eto tuntun, ati “atomicity” nibi tumọ si pe kii ṣe iṣẹlẹ kan yoo padanu.

So awọn eto si awọn orisun iṣẹlẹ

Ninu nkan yii, a kii yoo ṣe apejuwe awọn eto sisopọ lọtọ si awọn orisun iṣẹlẹ, nitori o jẹ oye lati kawe eyi ni aaye ti iru eto kan pato. Cm. apẹẹrẹ ni isalẹ, ninu eyiti a fihan bi awọn eto bii XDP ṣe sopọ.

Ifọwọyi Awọn nkan Lilo Ipe Eto bpf

Awọn eto BPF

Gbogbo awọn nkan BPF ni a ṣẹda ati iṣakoso lati aaye olumulo nipa lilo ipe eto kan bpf, nini awọn wọnyi Afọwọkọ:

#include <linux/bpf.h>

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

Eyi ni egbe naa cmd jẹ ọkan ninu awọn iye ti iru enum bpf_cmd, attr - ijuboluwole si awọn paramita fun eto kan pato ati size - iwọn ohun ni ibamu si itọka, i.e. nigbagbogbo eyi sizeof(*attr). Ni ekuro 5.8 ipe eto bpf atilẹyin 34 orisirisi awọn ofin, ati asọye union bpf_attr pa 200 ila. Ṣugbọn a ko yẹ ki o bẹru nipasẹ eyi, nitori a yoo faramọ ara wa pẹlu awọn aṣẹ ati awọn paramita lakoko awọn nkan pupọ.

Jẹ ká bẹrẹ pẹlu awọn egbe BPF_PROG_LOAD, eyiti o ṣẹda awọn eto BPF - gba eto awọn ilana BPF kan ati gbe e sinu ekuro. Ni akoko ikojọpọ, a ti ṣe ifilọlẹ oludaniloju, lẹhinna olupilẹṣẹ JIT ati, lẹhin ipaniyan aṣeyọri, oluṣapejuwe faili eto naa ti pada si olumulo naa. A ri ohun ti o ṣẹlẹ si i tókàn ninu awọn ti tẹlẹ apakan nipa awọn aye ọmọ ti BPF ohun.

A yoo kọ eto aṣa kan ti yoo gbe eto BPF kan ti o rọrun, ṣugbọn akọkọ a nilo lati pinnu iru eto ti a fẹ lati fifuye - a yoo ni lati yan iru kan ati laarin awọn ilana ti iru yi, kọ kan eto ti yoo ṣe awọn verifier igbeyewo. Sibẹsibẹ, ni ibere ki o má ba ṣe idiju ilana naa, eyi ni ojutu ti a ti ṣetan: a yoo mu eto kan bii BPF_PROG_TYPE_XDP, eyi ti yoo pada iye XDP_PASS (fo gbogbo awọn idii). Ninu apejọ BPF o rọrun pupọ:

r0 = 2
exit

Lẹhin ti a ti pinnu pe a yoo gbejade, a le sọ fun ọ bi a ṣe le ṣe:

#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();
}

Awọn iṣẹlẹ ti o nifẹ ninu eto bẹrẹ pẹlu itumọ ti orun insns - Eto BPF wa ni koodu ẹrọ. Ni ọran yii, itọnisọna kọọkan ti eto BPF ti wa ni akopọ sinu eto naa bpf_insn. Ohun akọkọ insns ni ibamu pẹlu awọn ilana r0 = 2, keji - exit.

Padasẹyin. Ekuro n ṣalaye awọn macros irọrun diẹ sii fun kikọ awọn koodu ẹrọ, ati lilo faili akọsori ekuro tools/include/linux/filter.h a le kọ

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

Ṣugbọn niwọn igba ti kikọ awọn eto BPF ni koodu abinibi jẹ pataki nikan fun awọn idanwo kikọ ninu ekuro ati awọn nkan nipa BPF, isansa ti awọn macros wọnyi ko ni idiju igbesi aye idagbasoke.

Lẹhin asọye eto BPF, a tẹsiwaju lati ṣajọpọ rẹ sinu ekuro. Wa minimalist ṣeto ti sile attr pẹlu iru eto, ṣeto ati nọmba awọn ilana, iwe-aṣẹ ti a beere, ati orukọ "woo", eyiti a lo lati wa eto wa lori eto lẹhin igbasilẹ. Eto naa, bi a ti ṣe ileri, ti kojọpọ sinu eto nipa lilo ipe eto kan bpf.

Ni ipari eto naa a pari ni lupu ailopin ti o ṣe afiwe isanwo isanwo naa. Laisi rẹ, eto naa yoo pa nipasẹ ekuro nigbati oluṣapejuwe faili ti ipe eto pada si wa ti wa ni pipade. bpf, ati awọn ti a yoo ko ri o ni awọn eto.

O dara, a ti ṣetan fun idanwo. Jẹ ki a pejọ ati ṣiṣe eto naa labẹ straceLati ṣayẹwo pe ohun gbogbo n ṣiṣẹ bi o ti yẹ:

$ 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(

Ohun gbogbo dara, bpf(2) pada mu 3 si wa ati awọn ti a lọ sinu ohun ailopin lupu pẹlu pause(). Jẹ ki a gbiyanju lati wa eto wa ninu eto naa. Lati ṣe eyi a yoo lọ si ebute miiran ki o lo ohun elo naa 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)

A rii pe eto ti kojọpọ wa lori eto naa woo ẹniti ID agbaye jẹ 390 ati pe o wa ni ilọsiwaju lọwọlọwọ simple-prog Apejuwe faili ṣiṣi wa ti n tọka si eto naa (ati ti simple-prog yoo pari iṣẹ naa, lẹhinna woo yoo farasin). Bi o ti ṣe yẹ, eto naa woo gba awọn baiti 16 - awọn ilana meji - ti awọn koodu alakomeji ni faaji BPF, ṣugbọn ni fọọmu abinibi rẹ (x86_64) o ti jẹ awọn baiti 40 tẹlẹ. Jẹ ki a wo eto wa ni fọọmu atilẹba rẹ:

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

ko si iyanilẹnu. Bayi jẹ ki a wo koodu ti ipilẹṣẹ nipasẹ olupilẹṣẹ 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

ko doko gidi fun exit(2), ṣugbọn ni otitọ, eto wa rọrun pupọ, ati fun awọn eto ti kii ṣe nkan ti o wa ni ibẹrẹ ati ọrọ-ọrọ ti a fi kun nipasẹ olupilẹṣẹ JIT jẹ, dajudaju, nilo.

Maps

Awọn eto BPF le lo awọn agbegbe iranti ti a ṣeto ti o wa si awọn eto BPF miiran ati si awọn eto ni aaye olumulo. Awọn nkan wọnyi ni a pe ni maapu ati ni apakan yii a yoo fihan bi a ṣe le ṣe afọwọyi wọn nipa lilo ipe eto kan bpf.

Jẹ ki a sọ lẹsẹkẹsẹ pe awọn agbara ti awọn maapu ko ni opin nikan si iraye si iranti pinpin. Awọn maapu idi pataki ti o ni ninu, fun apẹẹrẹ, awọn itọka si awọn eto BPF tabi awọn itọka si awọn atọkun nẹtiwọọki, awọn maapu fun ṣiṣẹ pẹlu awọn iṣẹlẹ perf, ati bẹbẹ lọ. A kii yoo sọrọ nipa wọn nibi, ki o má ba ṣe adaru oluka naa. Yato si eyi, a foju kọ awọn ọran imuṣiṣẹpọ, nitori eyi ko ṣe pataki fun awọn apẹẹrẹ wa. Atokọ pipe ti awọn oriṣi maapu ti o wa ni a le rii ninu <linux/bpf.h>, ati ni apakan yii a yoo gba gẹgẹbi apẹẹrẹ iru itan akọkọ, tabili hash BPF_MAP_TYPE_HASH.

Ti o ba ṣẹda tabili hash sinu, sọ, C ++, iwọ yoo sọ unordered_map<int,long> woo, eyiti o tumọ si ni Russian tumọ si “Mo nilo tabili kan woo iwọn ailopin, ti awọn bọtini jẹ iru int, ati awọn iye ni iru long" Lati ṣẹda tabili hash BPF, a nilo lati ṣe pupọ ohun kanna, ayafi pe a ni lati pato iwọn ti o pọju ti tabili, ati dipo sisọ iru awọn bọtini ati awọn iye, a nilo lati pato awọn iwọn wọn ni awọn baiti. . Lati ṣẹda awọn maapu lo pipaṣẹ BPF_MAP_CREATE ipe eto bpf. Jẹ ki a wo eto diẹ sii tabi kere si ti o ṣẹda maapu kan. Lẹhin eto iṣaaju ti o gbe awọn eto BPF, eyi yẹ ki o dabi ẹni pe o rọrun fun ọ:

$ 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();
}

Nibi ti a setumo kan ti ṣeto ti sile attr, ninu eyiti a sọ “Mo nilo tabili hash pẹlu awọn bọtini ati awọn iye iwọn sizeof(int), ninu eyiti Mo le fi awọn eroja mẹrin ti o pọju sii." Nigbati o ba ṣẹda awọn maapu BPF, o le pato awọn paramita miiran, fun apẹẹrẹ, ni ọna kanna bi ninu apẹẹrẹ pẹlu eto naa, a sọ orukọ nkan naa gẹgẹbi "woo".

Jẹ ki a ṣajọ ati ṣiṣẹ eto naa:

$ 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(

Eyi ni ipe eto bpf(2) pada wa nọmba map apejuwe 3 ati lẹhinna eto naa, bi o ti ṣe yẹ, duro fun awọn itọnisọna siwaju sii ninu ipe eto pause(2).

Bayi jẹ ki a firanṣẹ eto wa si abẹlẹ tabi ṣii ebute miiran ki o wo nkan wa nipa lilo ohun elo naa bpftool (a le ṣe iyatọ maapu wa lati awọn miiran nipasẹ orukọ rẹ):

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

Nọmba 114 jẹ ID agbaye ti nkan wa. Eyikeyi eto lori eto le lo ID yii lati ṣii maapu ti o wa tẹlẹ nipa lilo aṣẹ naa BPF_MAP_GET_FD_BY_ID ipe eto bpf.

Bayi a le ṣere pẹlu tabili hash wa. Jẹ ki a wo awọn akoonu inu rẹ:

$ sudo bpftool map dump id 114
Found 0 elements

Sofo. Jẹ ki a fi iye kan sinu rẹ hash[1] = 1:

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

Jẹ ki a wo tabili lẹẹkansi:

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

Hooray! A ṣakoso lati ṣafikun nkan kan. Ṣe akiyesi pe a ni lati ṣiṣẹ ni ipele baiti lati ṣe eyi, niwon bptftool ko mọ iru awọn iye ti o wa ninu tabili hash jẹ. (Imọ yii le ṣee gbe si ọdọ rẹ nipa lilo BTF, ṣugbọn diẹ sii lori iyẹn ni bayi.)

Bawo ni deede bpftool ṣe ka ati ṣafikun awọn eroja? Jẹ ki a wo labẹ hood:

$ 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

Ni akọkọ a ṣii maapu naa nipasẹ ID agbaye rẹ nipa lilo aṣẹ naa BPF_MAP_GET_FD_BY_ID и bpf(2) pada apejuwe 3 si wa. Siwaju sii nipa lilo pipaṣẹ BPF_MAP_GET_NEXT_KEY a ri bọtini akọkọ ninu tabili nipasẹ gbigbe NULL bi a ijuboluwole si awọn "tẹlẹ" bọtini. Ti a ba ni bọtini a le ṣe BPF_MAP_LOOKUP_ELEMeyi ti o pada a iye to a ijuboluwole value. Igbesẹ ti n tẹle ni a gbiyanju lati wa nkan atẹle nipa gbigbe itọka si bọtini lọwọlọwọ, ṣugbọn tabili wa ni ipin kan nikan ati aṣẹ naa. BPF_MAP_GET_NEXT_KEY pada ENOENT.

O dara, jẹ ki a yi iye pada nipasẹ bọtini 1, jẹ ki a sọ pe ọgbọn-ọrọ iṣowo wa nilo iforukọsilẹ 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

Bi o ti ṣe yẹ, o rọrun pupọ: aṣẹ naa BPF_MAP_GET_FD_BY_ID ṣi maapu wa nipasẹ ID, ati aṣẹ BPF_MAP_UPDATE_ELEM ìkọlélórí ano.

Nitorinaa, lẹhin ṣiṣẹda tabili hash lati eto kan, a le ka ati kọ awọn akoonu rẹ lati omiiran. Ṣe akiyesi pe ti a ba ni anfani lati ṣe eyi lati laini aṣẹ, lẹhinna eyikeyi eto miiran lori eto le ṣe. Ni afikun si awọn aṣẹ ti a ṣalaye loke, fun ṣiṣẹ pẹlu awọn maapu lati aaye olumulo, atẹle:

  • BPF_MAP_LOOKUP_ELEM: ri iye nipa bọtini
  • BPF_MAP_UPDATE_ELEM: imudojuiwọn / ṣẹda iye
  • BPF_MAP_DELETE_ELEM: yọ bọtini kuro
  • BPF_MAP_GET_NEXT_KEY: wa atẹle (tabi akọkọ) bọtini
  • BPF_MAP_GET_NEXT_ID: gba ọ laaye lati lọ nipasẹ gbogbo awọn maapu ti o wa tẹlẹ, iyẹn ni bi o ṣe n ṣiṣẹ bpftool map
  • BPF_MAP_GET_FD_BY_ID: ṣii maapu ti o wa tẹlẹ nipasẹ ID agbaye rẹ
  • BPF_MAP_LOOKUP_AND_DELETE_ELEM: atomically ṣe imudojuiwọn iye ohun kan ki o da ohun atijọ pada
  • BPF_MAP_FREEZE: jẹ ki maapu naa ko yipada lati aaye olumulo (iṣiṣẹ yii ko le ṣe atunṣe)
  • BPF_MAP_LOOKUP_BATCH, BPF_MAP_LOOKUP_AND_DELETE_BATCH, BPF_MAP_UPDATE_BATCH, BPF_MAP_DELETE_BATCH: ibi-mosi. Fun apere, BPF_MAP_LOOKUP_AND_DELETE_BATCH - Eyi ni ọna igbẹkẹle nikan lati ka ati tunto gbogbo awọn iye lati maapu naa

Kii ṣe gbogbo awọn aṣẹ wọnyi n ṣiṣẹ fun gbogbo awọn oriṣi maapu, ṣugbọn ni gbogbogbo ṣiṣẹ pẹlu awọn iru maapu miiran lati aaye olumulo dabi pe o ṣiṣẹ pẹlu awọn tabili hash.

Fun aṣẹ, jẹ ki a pari awọn adanwo tabili hash wa. Ranti pe a ṣẹda tabili ti o le ni awọn bọtini mẹrin bi? Jẹ ki a fi awọn eroja diẹ kun:

$ 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

Titi di bayi ti o dara:

$ 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

Jẹ ki a gbiyanju lati ṣafikun ọkan si:

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

Gẹgẹbi a ti ṣe yẹ, a ko ṣaṣeyọri. Jẹ ki a wo aṣiṣe ni alaye diẹ sii:

$ 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 +++

Ohun gbogbo dara: bi o ti ṣe yẹ, ẹgbẹ naa BPF_MAP_UPDATE_ELEM gbiyanju lati ṣẹda titun kan, karun, bọtini, ṣugbọn ipadanu E2BIG.

Nitorina, a le ṣẹda ati fifuye awọn eto BPF, bakannaa ṣẹda ati ṣakoso awọn maapu lati aaye olumulo. Bayi o jẹ ọgbọn lati wo bawo ni a ṣe le lo awọn maapu lati awọn eto BPF funrararẹ. A le sọrọ nipa eyi ni ede ti awọn eto lile-lati-ka ninu awọn koodu macro ẹrọ, ṣugbọn ni otitọ akoko ti de lati fihan bi awọn eto BPF ṣe kọ ati ṣetọju nitootọ - lilo libbpf.

(Fun awọn oluka ti ko ni itẹlọrun pẹlu aini apẹẹrẹ ipele kekere: a yoo ṣe itupalẹ awọn eto alaye ti o lo awọn maapu ati awọn iṣẹ oluranlọwọ ti a ṣẹda nipa lilo libbpf ati sọ fun ọ ohun ti o ṣẹlẹ ni ipele itọnisọna. Fun awọn onkawe ti ko ni itẹlọrun pupo pupo, a fi kun apẹẹrẹ ni aaye ti o yẹ ninu nkan naa.)

Kikọ awọn eto BPF nipa lilo libbpf

Kikọ awọn eto BPF nipa lilo awọn koodu ẹrọ le jẹ igbadun nikan ni igba akọkọ, ati lẹhinna satiety ṣeto sinu. Ni akoko yii o nilo lati yi ifojusi rẹ si llvm, eyi ti o ni a backend fun ti o npese koodu fun awọn BPF faaji, bi daradara bi a ìkàwé libbpf, eyiti o fun ọ laaye lati kọ ẹgbẹ olumulo ti awọn ohun elo BPF ati fifuye koodu ti awọn eto BPF ti ipilẹṣẹ nipa lilo llvm/clang.

Ni otitọ, bi a yoo rii ninu eyi ati awọn nkan atẹle, libbpf ṣe ọpọlọpọ iṣẹ laisi rẹ (tabi awọn irinṣẹ ti o jọra - iproute2, libbcc, libbpf-go, etc.) ko ṣee ṣe lati gbe. Ọkan ninu awọn ẹya apaniyan ti ise agbese na libbpf jẹ BPF CO-RE (Ṣakopọ lẹẹkan, Ṣiṣe Nibikibi) - iṣẹ akanṣe ti o fun ọ laaye lati kọ awọn eto BPF ti o ṣee gbe lati ekuro kan si ekeji, pẹlu agbara lati ṣiṣẹ lori awọn API oriṣiriṣi (fun apẹẹrẹ, nigbati eto kernel yipada lati ẹya. si ikede). Lati le ni anfani lati ṣiṣẹ pẹlu CO-RE, ekuro rẹ gbọdọ wa ni akojọpọ pẹlu atilẹyin BTF (a ṣe apejuwe bi o ṣe le ṣe eyi ni apakan Awọn Irinṣẹ Idagbasoke. O le ṣayẹwo boya ekuro rẹ jẹ itumọ pẹlu BTF tabi kii ṣe ni irọrun pupọ - nipasẹ wiwa faili atẹle:

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

Faili yii tọju alaye nipa gbogbo awọn oriṣi data ti a lo ninu ekuro ati pe a lo ninu gbogbo awọn apẹẹrẹ wa ni lilo libbpf. A yoo sọrọ ni awọn alaye nipa CO-RE ni nkan atẹle, ṣugbọn ninu ọkan yii - kan kọ ara rẹ ni ekuro pẹlu CONFIG_DEBUG_INFO_BTF.

ìkàwé libbpf ngbe ọtun ninu awọn liana tools/lib/bpf ekuro ati idagbasoke rẹ ni a ṣe nipasẹ atokọ ifiweranṣẹ [email protected]. Sibẹsibẹ, ibi ipamọ lọtọ ti wa ni itọju fun awọn iwulo awọn ohun elo ti ngbe ni ita ekuro https://github.com/libbpf/libbpf ninu eyiti ile-ikawe kernel ti ṣe afihan fun iwọle kika diẹ sii tabi kere si bi o ṣe jẹ.

Ni apakan yii a yoo wo bi o ṣe le ṣẹda iṣẹ akanṣe ti o nlo libbpf, jẹ ki a kọ ọpọlọpọ (diẹ sii tabi kere si asan) awọn eto idanwo ati ṣe itupalẹ ni apejuwe bi gbogbo rẹ ṣe n ṣiṣẹ. Eyi yoo gba wa laaye lati ṣe alaye ni irọrun diẹ sii ni awọn apakan atẹle ni pato bi awọn eto BPF ṣe nlo pẹlu awọn maapu, awọn oluranlọwọ kernel, BTF, ati bẹbẹ lọ.

Ojo melo ise agbese lilo libbpf ṣafikun ibi ipamọ GitHub kan bi git submodule, a yoo ṣe kanna:

$ 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.

Nlọ si libbpf rọrun pupọ:

$ 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

Eto wa ti o tẹle ni apakan yii jẹ bi atẹle: a yoo kọ eto BPF bii BPF_PROG_TYPE_XDP, kanna bi ninu apẹẹrẹ ti tẹlẹ, ṣugbọn ni C, a ṣe akopọ rẹ nipa lilo clang, ki o si kọ eto oluranlọwọ ti yoo gbe e sinu ekuro. Ni awọn apakan atẹle a yoo faagun awọn agbara ti eto BPF mejeeji ati eto oluranlọwọ.

Apeere: ṣiṣẹda ohun elo kikun nipa lilo libbpf

Lati bẹrẹ pẹlu, a lo faili naa /sys/kernel/btf/vmlinux, eyiti a mẹnuba loke, ati ṣẹda deede rẹ ni irisi faili akọsori kan:

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

Faili yii yoo tọju gbogbo awọn ẹya data ti o wa ninu ekuro wa, fun apẹẹrẹ, eyi ni bii akọle IPv4 ṣe tumọ si ninu ekuro:

$ 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;
};

Bayi a yoo kọ eto BPF wa ni 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";

Botilẹjẹpe eto wa yipada lati rọrun pupọ, a tun nilo lati fiyesi si awọn alaye pupọ. Ni akọkọ, faili akọsori akọkọ ti a pẹlu ni vmlinux.h, eyi ti a kan ti ipilẹṣẹ nipa lilo bpftool btf dump - ni bayi a ko nilo lati fi sori ẹrọ package awọn akọle kernel lati wa kini awọn ẹya ekuro dabi. Faili akọsori atẹle wa si wa lati ile-ikawe naa libbpf. Bayi a nilo nikan lati ṣalaye Makiro SEC, eyi ti o fi ohun kikọ ranṣẹ si apakan ti o yẹ ti faili ohun ELF. Eto wa wa ninu apakan xdp/simple, nibiti ṣaaju idinku ti a ṣalaye iru eto BPF - eyi ni apejọ ti a lo ninu libbpf, da lori orukọ apakan yoo rọpo iru ti o pe ni ibẹrẹ bpf(2). Eto BPF funrararẹ jẹ C - irorun ati ki o oriširiši ti ọkan ila return XDP_PASS. Níkẹyìn, a lọtọ apakan "license" ni awọn orukọ ti iwe-aṣẹ.

A le ṣe akopọ eto wa nipa lilo lvm/clang, ẹya>= 10.0.0, tabi dara julọ sibẹsibẹ, tobi julọ (wo apakan Awọn Irinṣẹ Idagbasoke):

$ 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

Lara awọn ẹya ti o nifẹ si: a tọkasi faaji ibi-afẹde -target bpf ati ọna si awọn akọle libbpf, eyi ti a laipe fi sori ẹrọ. Bakannaa, maṣe gbagbe nipa -O2, laisi aṣayan yii o le wa fun awọn iyanilẹnu ni ojo iwaju. Jẹ ki a wo koodu wa, ṣe a ṣakoso lati kọ eto ti a fẹ?

$ 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

Bẹẹni, o ṣiṣẹ! Bayi, a ni faili alakomeji pẹlu eto naa, ati pe a fẹ ṣẹda ohun elo kan ti yoo gbe e sinu ekuro. Fun idi eyi ile-ikawe libbpf nfun wa ni awọn aṣayan meji - lo API ipele-kekere tabi API ipele giga kan. A yoo lọ ni ọna keji, niwon a fẹ lati kọ bi a ṣe le kọ, fifuye ati so awọn eto BPF pọ pẹlu igbiyanju diẹ fun iwadi wọn ti o tẹle.

Ni akọkọ, a nilo lati ṣe ina “egungun” ti eto wa lati alakomeji rẹ nipa lilo ohun elo kanna bpftool - ọbẹ Swiss ti aye BPF (eyiti o le mu ni itumọ ọrọ gangan, niwon Daniel Borkman, ọkan ninu awọn ẹlẹda ati awọn olutọju ti BPF, jẹ Swiss):

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

Ninu faili xdp-simple.skel.h ni koodu alakomeji ti eto wa ati awọn iṣẹ fun iṣakoso - ikojọpọ, somọ, piparẹ nkan wa. Ninu ọran wa ti o rọrun eyi dabi apọju, ṣugbọn o tun ṣiṣẹ ninu ọran nibiti faili ohun naa ni ọpọlọpọ awọn eto BPF ati awọn maapu ati lati ṣaja ELF omiran yii a kan nilo lati ṣe ina egungun ati pe awọn iṣẹ kan tabi meji lati ohun elo aṣa a. ti wa ni kikọ Jẹ ki ká gbe lori bayi.

Ni pipe, eto agberu wa jẹ ohun kekere:

#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);
}

o ti wa ni struct xdp_simple_bpf asọye ninu faili naa xdp-simple.skel.h ati ṣe apejuwe faili nkan wa:

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;
};

A le rii awọn itọpa ti ipele kekere API nibi: eto naa struct bpf_program *simple и struct bpf_link *simple. Ilana akọkọ ṣe apejuwe eto wa ni pato, ti a kọ si apakan xdp/simple, ati keji ṣe apejuwe bi eto naa ṣe sopọ si orisun iṣẹlẹ.

Išẹ xdp_simple_bpf__open_and_load, ṣii ohun ELF kan, ṣe atunwo rẹ, ṣẹda gbogbo awọn ẹya ati awọn ipilẹ-ara (Yato si eto naa, ELF tun ni awọn apakan miiran - data, data kika nikan, alaye n ṣatunṣe aṣiṣe, iwe-aṣẹ, ati bẹbẹ lọ), ati lẹhinna gbe e sinu ekuro nipa lilo eto kan. ipe bpf, eyi ti a le ṣayẹwo nipa iṣakojọpọ ati ṣiṣe eto naa:

$ 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

Jẹ ká bayi wo ni wa eto nipa lilo bpftool. Jẹ ki a wa ID rẹ:

# 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)

ki o si da silẹ (a lo fọọmu kukuru ti aṣẹ naa bpftool prog dump xlated):

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

Nkankan titun! Eto naa ti tẹ awọn ṣoki ti faili orisun C wa. Eyi ni a ṣe nipasẹ ile-ikawe libbpf, eyiti o rii apakan yokokoro ni alakomeji, ṣajọ rẹ sinu nkan BTF kan, ti kojọpọ sinu ekuro nipa lilo BPF_BTF_LOAD, ati lẹhinna ṣalaye oluṣapejuwe faili ti o yọrisi nigbati o ba n gbe eto naa pẹlu aṣẹ naa BPG_PROG_LOAD.

Awọn oluranlọwọ Ekuro

Awọn eto BPF le ṣiṣe awọn iṣẹ “ita” - awọn oluranlọwọ kernel. Awọn iṣẹ oluranlọwọ wọnyi gba awọn eto BPF laaye lati wọle si awọn ẹya ekuro, ṣakoso awọn maapu, ati tun ṣe ibasọrọ pẹlu “aye gidi” - ṣẹda awọn iṣẹlẹ perf, ohun elo iṣakoso (fun apẹẹrẹ, awọn apo-itumọ), ati bẹbẹ lọ.

Apeere: bpf_get_smp_processor_id

Laarin ilana ti apẹrẹ “ẹkọ nipasẹ apẹẹrẹ”, jẹ ki a gbero ọkan ninu awọn iṣẹ oluranlọwọ, bpf_get_smp_processor_id(), pato ninu faili kernel/bpf/helpers.c. O da nọmba ero isise naa pada lori eyiti eto BPF ti o pe ni nṣiṣẹ. Ṣugbọn a ko nifẹ si awọn atunmọ rẹ bi ni otitọ pe imuse rẹ gba laini kan:

BPF_CALL_0(bpf_get_smp_processor_id)
{
    return smp_processor_id();
}

Awọn asọye iṣẹ oluranlọwọ BPF jẹ iru si awọn asọye ipe eto Linux. Nibi, fun apẹẹrẹ, iṣẹ kan ti wa ni asọye ti ko ni awọn ariyanjiyan. (Iṣẹ kan ti o gba, sọ, awọn ariyanjiyan mẹta jẹ asọye nipa lilo Makiro BPF_CALL_3. Nọmba ti o pọju awọn ariyanjiyan jẹ marun.) Sibẹsibẹ, eyi nikan jẹ apakan akọkọ ti itumọ. Apa keji ni lati ṣalaye iru eto naa struct bpf_func_proto, eyiti o ni apejuwe ti iṣẹ oluranlọwọ ti o ni oye:

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

Iforukọsilẹ Awọn iṣẹ Iranlọwọ

Ni ibere fun awọn eto BPF ti iru kan pato lati lo iṣẹ yii, wọn gbọdọ forukọsilẹ, fun apẹẹrẹ fun iru BPF_PROG_TYPE_XDP iṣẹ kan ti wa ni asọye ninu ekuro xdp_func_proto, eyi ti o pinnu lati ID iṣẹ oluranlọwọ boya XDP ṣe atilẹyin iṣẹ yii tabi rara. Iṣẹ wa ni awọn atilẹyin:

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;
    ...
    }
}

Awọn iru eto BPF tuntun jẹ “tumọ” ninu faili naa include/linux/bpf_types.h lilo Makiro BPF_PROG_TYPE. Ti ṣe asọye ni awọn agbasọ nitori pe o jẹ itumọ ọgbọn, ati ni awọn ofin ede C asọye ti gbogbo ṣeto ti awọn ẹya nja waye ni awọn aye miiran. Ni pato, ninu faili kernel/bpf/verifier.c gbogbo awọn asọye lati faili bpf_types.h ti wa ni lo lati ṣẹda ohun orun ti awọn ẹya 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
};

Iyẹn ni, fun iru eto BPF kọọkan, itọka si ọna data ti iru naa jẹ asọye struct bpf_verifier_ops, eyi ti o wa ni ibẹrẹ pẹlu iye _name ## _verifier_ops, i.e. xdp_verifier_ops fun xdp. Ilana xdp_verifier_ops pinnu ninu faili net/core/filter.c ni ọna atẹle:

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,
};

Nibi ti a ri wa faramọ iṣẹ xdp_func_proto, eyi ti yoo ṣiṣe awọn verifier ni gbogbo igba ti o ba pade a ipenija diẹ ninu awọn iṣẹ inu a BPF eto, wo verifier.c.

Jẹ ki a wo bawo ni eto BPF ti o ni idaniloju ṣe nlo iṣẹ naa bpf_get_smp_processor_id. Lati ṣe eyi, a tun kọ eto naa lati apakan ti tẹlẹ wa bi atẹle:

#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 pinnu в <bpf/bpf_helper_defs.h> .иблиотеки libbpf bi o

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

ti o jẹ, bpf_get_smp_processor_id jẹ itọkasi iṣẹ ti iye rẹ jẹ 8, nibiti 8 jẹ iye BPF_FUNC_get_smp_processor_id Iru enum bpf_fun_id, eyi ti o jẹ asọye fun wa ninu faili naa vmlinux.h (faili bpf_helper_defs.h ninu ekuro ti ipilẹṣẹ nipasẹ iwe afọwọkọ, nitorinaa awọn nọmba “idan” jẹ ok). Iṣẹ yii ko gba awọn ariyanjiyan ko si da iye iru pada __u32. Nigba ti a ba ṣiṣẹ ninu eto wa, clang ipilẹṣẹ itọnisọna BPF_CALL "Iru ti o tọ" Jẹ ki a ṣajọ eto naa ki a wo apakan naa 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

Ni ila akọkọ ti a ri awọn ilana call, paramita IMM eyi ti o jẹ dogba si 8, ati SRC_REG - odo. Gẹgẹbi adehun ABI ti a lo nipasẹ oludaniloju, eyi jẹ ipe si iṣẹ oluranlọwọ nọmba mẹjọ. Ni kete ti o ti ṣe ifilọlẹ, ọgbọn naa rọrun. Pada iye lati Forukọsilẹ r0 daakọ si r1 ati lori awọn ila 2,3 o ti wa ni iyipada si iru u32 - oke 32 die-die ti wa ni nso. Lori awọn ila 4,5,6,7 a pada 2 (XDP_PASS) tabi 1 (XDP_DROP) da lori boya iṣẹ oluranlọwọ lati laini 0 pada odo tabi iye ti kii ṣe odo.

Jẹ ki a ṣe idanwo fun ara wa: fifuye eto naa ki o wo abajade 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

O dara, oludaniloju ri oluranlọwọ kernel to pe.

Apeere: gbigbe awọn ariyanjiyan ati nikẹhin nṣiṣẹ eto naa!

Gbogbo awọn iṣẹ oluranlọwọ ipele-ṣiṣe ni apẹrẹ kan

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

Awọn paramita si awọn iṣẹ oluranlọwọ ti kọja ni awọn iforukọsilẹ r1-r5, ati awọn iye ti wa ni pada ninu awọn Forukọsilẹ r0. Ko si awọn iṣẹ ti o gba diẹ sii ju awọn ariyanjiyan marun, ati atilẹyin fun wọn ko nireti lati ṣafikun ni ọjọ iwaju.

Jẹ ki a wo oluranlọwọ ekuro tuntun ati bii BPF ṣe n kọja awọn ayeraye. Jẹ ki a tun kọ xdp-simple.bpf.c bi atẹle (awọn iyoku awọn ila ko ti yipada):

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

Eto wa tẹjade nọmba ti Sipiyu lori eyiti o nṣiṣẹ. Jẹ ki a ṣajọ rẹ ki o wo koodu naa:

$ 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

Ni awọn ila 0-7 a kọ okun naa running on CPU%un, ati ki o si lori ila 8 a ṣiṣe awọn faramọ ọkan bpf_get_smp_processor_id. Lori awọn ila 9-12 a mura awọn ariyanjiyan oluranlọwọ bpf_printk - awọn iforukọsilẹ r1, r2, r3. Kilode ti wọn jẹ mẹta ti kii ṣe meji? Nitori bpf_printkyi ni a Makiro wrapper ni ayika oluranlọwọ gidi bpf_trace_printk, eyi ti o nilo lati kọja iwọn ti okun kika.

Jẹ ki ká bayi fi kan tọkọtaya ti ila to xdp-simple.cki eto wa sopọ si wiwo lo ati ki o gan bere!

$ 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);
}

Nibi a lo iṣẹ naa bpf_set_link_xdp_fd, eyiti o so awọn eto BPF iru XDP pọ si awọn atọkun nẹtiwọki. A hardcoded ni wiwo nọmba lo, ti o jẹ nigbagbogbo 1. A ṣiṣe awọn iṣẹ lemeji lati akọkọ yọ atijọ eto ti o ba ti o ti so. Ṣe akiyesi pe ni bayi a ko nilo ipenija pause tabi lupu ailopin: eto agberu wa yoo jade, ṣugbọn eto BPF kii yoo pa nitori o ti sopọ si orisun iṣẹlẹ. Lẹhin igbasilẹ aṣeyọri ati asopọ, eto naa yoo ṣe ifilọlẹ fun soso nẹtiwọọki kọọkan ti o de lo.

Jẹ ki ká gba awọn eto ati ki o wo ni wiwo 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

Eto ti a ṣe igbasilẹ ni ID 669 ati pe a rii ID kanna lori wiwo lo. A yoo fi awọn akojọpọ meji ranṣẹ si 127.0.0.1 (ìbéèrè + èsì):

$ ping -c1 localhost

ati ni bayi jẹ ki a wo awọn akoonu ti faili foju yokokoro /sys/kernel/debug/tracing/trace_pipe, ninu eyiti bpf_printk kọ awọn ifiranṣẹ rẹ:

# 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

Meji jo won gbo lori lo ati ni ilọsiwaju lori CPU0 - eto BPF ti ko ni itumọ akọkọ wa ṣiṣẹ!

O tọ lati ṣe akiyesi pe bpf_printk Kii ṣe fun ohunkohun ti o kọwe si faili yokokoro: eyi kii ṣe oluranlọwọ aṣeyọri julọ fun lilo ninu iṣelọpọ, ṣugbọn ibi-afẹde wa ni lati ṣafihan nkan ti o rọrun.

Wiwọle awọn maapu lati awọn eto BPF

Apeere: lilo maapu lati inu eto BPF

Ni awọn apakan ti tẹlẹ a kọ bii o ṣe le ṣẹda ati lo awọn maapu lati aaye olumulo, ati ni bayi jẹ ki a wo apakan kernel. Jẹ ki a bẹrẹ, bi igbagbogbo, pẹlu apẹẹrẹ. Jẹ ki a tun eto wa kọ xdp-simple.bpf.c ni ọna atẹle:

#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";

Ni ibere ti awọn eto ti a fi kun a map definition woo: Eyi jẹ apẹrẹ 8-eroja ti o tọju awọn iye bii u64 (ni C a yoo setumo iru ohun orun bi u64 woo[8]). Ninu eto kan "xdp/simple" a gba nọmba ero isise lọwọlọwọ sinu oniyipada kan key ati lẹhinna lilo iṣẹ oluranlọwọ bpf_map_lookup_element a gba itọka si titẹ sii ti o baamu ni titobi, eyiti a pọ si nipasẹ ọkan. Itumọ si ede Rọsia: a ṣe iṣiro awọn iṣiro lori eyiti Sipiyu ṣe ilana awọn apo-iwe ti nwọle. Jẹ ki a gbiyanju lati mu eto naa ṣiṣẹ:

$ 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

Jẹ ki a ṣayẹwo pe o ti sopọ mọ lo ki o si fi awọn apo-iwe diẹ ranṣẹ:

$ 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

Bayi jẹ ki a wo awọn akoonu ti orun:

$ 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 }
]

Fere gbogbo awọn ilana ni a ṣe ilana lori CPU7. Eyi kii ṣe pataki fun wa, ohun akọkọ ni pe eto naa ṣiṣẹ ati pe a loye bi a ṣe le wọle si awọn maapu lati awọn eto BPF - lilo хелперов bpf_mp_*.

Atọka aramada

Nitorinaa, a le wọle si maapu lati eto BPF nipa lilo awọn ipe bii

val = bpf_map_lookup_elem(&woo, &key);

ibi ti iṣẹ oluranlọwọ dabi

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

sugbon a ti wa ni ran a ijuboluwole &woo si eto ti a ko darukọ struct { ... }...

Ti a ba wo olupilẹṣẹ eto, a rii pe iye naa &woo ko ṣe alaye gangan (ila 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
...

ati pe o wa ninu awọn iṣipopada:

$ 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

Ṣugbọn ti a ba wo eto ti kojọpọ tẹlẹ, a rii itọka si maapu to pe (ila 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]
...

Nitorinaa, a le pinnu pe ni akoko ifilọlẹ eto agberu wa, ọna asopọ si &woo ti a rọpo nipa nkankan pẹlu kan ìkàwé libbpf. Ni akọkọ a yoo wo abajade 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

A ri iyẹn libbpf ṣẹda maapu woo ati lẹhinna ṣe igbasilẹ eto wa simple. Jẹ ki a ṣe akiyesi diẹ sii bi a ṣe n ṣajọpọ eto naa:

  • ipe xdp_simple_bpf__open_and_load lati faili xdp-simple.skel.h
  • eyiti o fa xdp_simple_bpf__load lati faili xdp-simple.skel.h
  • eyiti o fa bpf_object__load_skeleton lati faili libbpf/src/libbpf.c
  • eyiti o fa bpf_object__load_xattr ati bẹbẹ lọ libbpf/src/libbpf.c

Awọn ti o kẹhin iṣẹ, ninu ohun miiran, yoo pe bpf_object__create_maps, eyi ti o ṣẹda tabi ṣi awọn maapu ti o wa tẹlẹ, titan wọn si awọn apejuwe faili. (Eyi ni ibiti a ti rii BPF_MAP_CREATE ninu o wu strace.) Nigbamii ti iṣẹ naa ni a npe ni bpf_object__relocate òun sì ni ó fẹ́ràn wa, níwọ̀n bí a ti rántí ohun tí a rí woo ninu tabili iṣipopada. Ṣiṣayẹwo rẹ, a bajẹ ri ara wa ni iṣẹ naa bpf_program__relocate, eyiti dunadura pẹlu map sibugbeegbe:

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

Nitorina a gba awọn itọnisọna wa

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

ati ki o rọpo iforukọsilẹ orisun ninu rẹ pẹlu BPF_PSEUDO_MAP_FD, ati IMM akọkọ si oluṣapejuwe faili ti maapu wa ati, ti o ba dọgba si, fun apẹẹrẹ, 0xdeadbeef, lẹhinna bi abajade a yoo gba itọnisọna naa

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

Eyi ni bii alaye maapu ṣe gbe lọ si eto BPF kan ti o kojọpọ. Ni idi eyi, maapu naa le ṣẹda ni lilo BPF_MAP_CREATE, ati ṣiṣi nipasẹ ID lilo BPF_MAP_GET_FD_BY_ID.

Lapapọ, nigba lilo libbpf algorithm jẹ bi atẹle: +

  • nigba akopo, igbasilẹ ti wa ni da ni awọn sibugbe tabili fun awọn ọna asopọ si awọn maapu
  • libbpf ṣii iwe ohun ELF, wa gbogbo awọn maapu ti a lo ati ṣẹda awọn apejuwe faili fun wọn
  • Awọn apejuwe faili ti kojọpọ sinu ekuro gẹgẹbi apakan ti itọnisọna naa LD64

Bi o ṣe le fojuinu, diẹ sii wa lati wa ati pe a yoo ni lati wo inu mojuto. Da, a ni a olobo - a ti kọ si isalẹ awọn itumo BPF_PSEUDO_MAP_FD sinu iforukọsilẹ orisun ati pe a le sin, ti yoo mu wa lọ si mimọ ti gbogbo awọn eniyan mimọ - kernel/bpf/verifier.c, nibiti iṣẹ kan ti o ni orukọ iyasọtọ rọpo oluṣapejuwe faili kan pẹlu adirẹsi ti eto iru 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;

(kikun koodu le ṣee ri asopọ). Nitorinaa a le faagun algorithm wa:

  • lakoko ikojọpọ eto naa, oludaniloju ṣayẹwo lilo maapu deede ati kọ adirẹsi ti eto ti o baamu struct bpf_map

Nigbati o ba ṣe igbasilẹ alakomeji ELF nipa lilo libbpf Ọ̀pọ̀ nǹkan ló ń lọ, àmọ́ a máa jíròrò rẹ̀ nínú àwọn àpilẹ̀kọ míì.

Awọn eto ikojọpọ ati awọn maapu laisi libbpf

Gẹgẹbi a ti ṣe ileri, eyi jẹ apẹẹrẹ fun awọn oluka ti o fẹ lati mọ bi o ṣe le ṣẹda ati fifuye eto ti o nlo awọn maapu, laisi iranlọwọ libbpf. Eyi le wulo nigbati o ba n ṣiṣẹ ni agbegbe fun eyiti o ko le kọ awọn igbẹkẹle, tabi fifipamọ gbogbo nkan, tabi kikọ eto bii ply, eyi ti o ṣe agbejade koodu alakomeji BPF lori fo.

Lati jẹ ki o rọrun lati tẹle imọran, a yoo tun ṣe apẹẹrẹ wa fun awọn idi wọnyi xdp-simple. Awọn pipe ati die-die ti fẹ koodu ti awọn eto sísọ ni yi apẹẹrẹ le ti wa ni ri ni yi ikun.

Imọye ti ohun elo wa jẹ bi atẹle:

  • ṣẹda maapu iru BPF_MAP_TYPE_ARRAY lilo pipaṣẹ BPF_MAP_CREATE,
  • ṣẹda eto ti o nlo maapu yii,
  • so awọn eto si awọn wiwo lo,

eyi ti o tumo sinu eda eniyan bi

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);
}

o ti wa ni map_create ṣẹda maapu ni ọna kanna bi a ti ṣe ni apẹẹrẹ akọkọ nipa ipe eto bpf - “Ekuro, jọwọ ṣe mi ni maapu tuntun ni irisi titobi ti awọn eroja 8 bii __u64 ki o si fun mi ni apejuwe faili naa pada":

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));
}

Eto naa tun rọrun lati fifuye:

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));
}

Awọn ti ẹtan apakan prog_load jẹ itumọ ti eto BPF wa bi ọpọlọpọ awọn ẹya struct bpf_insn insns[]. Ṣugbọn niwon a nlo eto ti a ni ni C, a le ṣe iyanjẹ diẹ:

$ 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

Ni apapọ, a nilo lati kọ awọn ilana 14 ni irisi awọn ẹya bii struct bpf_insn (imọran: Mu idalẹnu lati oke, tun-ka apakan ilana, ṣii linux/bpf.h и linux/bpf_common.h ki o si gbiyanju lati pinnu struct bpf_insn insns[] ti ara ẹni):

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
    },
};

Idaraya fun awọn ti ko kọ eyi funrararẹ - wa map_fd.

Apa kan ti a ko sọ di mimọ wa ninu eto wa - xdp_attach. Laanu, awọn eto bii XDP ko le sopọ pẹlu ipe eto kan bpf. Awọn eniyan ti o ṣẹda BPF ati XDP wa lati agbegbe Linux lori ayelujara, eyiti o tumọ si pe wọn lo ọkan ti o mọ julọ fun wọn (ṣugbọn kii ṣe lati deede eniyan) ni wiwo fun ibaraenisepo pẹlu ekuro: netlink iho, wo eleyi na RFC3549. Ọna to rọọrun lati lo xdp_attach ti wa ni didakọ koodu lati libbpf, eyun, lati faili naa netlink.c, eyiti a ṣe ni kukuru diẹ:

Kaabo si aye ti netlink sockets

Ṣii iru iho netlink kan 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;
}

A ka lati inu iho yii:

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;
}

Nikẹhin, eyi ni iṣẹ wa ti o ṣii iho kan ti o fi ifiranṣẹ pataki ranṣẹ si rẹ ti o ni apejuwe faili kan ninu:

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;
}

Nitorinaa, ohun gbogbo ti ṣetan fun idanwo:

$ 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 +++

Jẹ ki a wo boya eto wa ti sopọ si 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

Jẹ ki a firanṣẹ awọn pings ki a wo maapu naa:

$ 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

Hurray, ohun gbogbo ṣiṣẹ. Ṣe akiyesi, nipasẹ ọna, pe maapu wa tun han ni irisi awọn baiti. Eyi jẹ nitori otitọ pe, ko dabi libbpf a ko fifuye iru alaye (BTF). Ṣugbọn a yoo sọrọ diẹ sii nipa eyi nigba miiran.

Awọn Irinṣẹ Idagbasoke

Ni apakan yii, a yoo wo ohun elo irinṣẹ idagbasoke BPF ti o kere julọ.

Ni gbogbogbo, iwọ ko nilo ohunkohun pataki lati ṣe agbekalẹ awọn eto BPF - BPF nṣiṣẹ lori eyikeyi ekuro pinpin didara, ati pe awọn eto ti kọ nipa lilo clang, eyi ti o le wa ni ipese lati awọn package. Sibẹsibẹ, nitori otitọ pe BPF wa labẹ idagbasoke, ekuro ati awọn irinṣẹ n yipada nigbagbogbo, ti o ko ba fẹ kọ awọn eto BPF nipa lilo awọn ọna ti atijọ lati ọdun 2019, lẹhinna o yoo ni lati ṣajọ.

  • llvm/clang
  • pahole
  • awọn oniwe-mojuto
  • bpftool

(Fun itọkasi, apakan yii ati gbogbo awọn apẹẹrẹ ninu nkan naa ni a ṣiṣẹ lori Debian 10.)

llvm/clang

BPF jẹ ọrẹ pẹlu LLVM ati, botilẹjẹpe awọn eto aipẹ fun BPF le ṣe akopọ nipa lilo gcc, gbogbo idagbasoke lọwọlọwọ ni a ṣe fun LLVM. Nitorina, akọkọ ti gbogbo, a yoo kọ awọn ti isiyi ti ikede clang lati 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
... много времени спустя
$

Bayi a le ṣayẹwo ti ohun gbogbo ba papọ ni deede:

$ ./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

(Awọn itọnisọna apejọ clang gba nipasẹ mi lati bpf_devel_QA.)

A kii yoo fi sori ẹrọ awọn eto ti a kan kọ, ṣugbọn dipo kan ṣafikun wọn si PATHfun apẹẹrẹ:

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

(Eyi le ṣe afikun si .bashrc tabi si faili lọtọ. Tikalararẹ, Mo ṣafikun awọn nkan bii eyi si ~/bin/activate-llvm.sh ati nigbati pataki Mo ṣe o . activate-llvm.sh.)

Pahole ati BTF

IwUlO pahole ti a lo nigba kikọ ekuro lati ṣẹda alaye n ṣatunṣe aṣiṣe ni ọna kika BTF. A kii yoo lọ sinu alaye ni nkan yii nipa awọn alaye ti imọ-ẹrọ BTF, miiran ju otitọ pe o rọrun ati pe a fẹ lati lo. Nitorinaa ti o ba fẹ kọ ekuro rẹ, kọ akọkọ pahole (laisi pahole iwọ kii yoo ni anfani lati kọ ekuro pẹlu aṣayan 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

Awọn ekuro fun idanwo pẹlu BPF

Nigbati o ba n ṣawari awọn aye ti BPF, Mo fẹ lati pejọ mojuto ti ara mi. Eyi, ni gbogbogbo, ko ṣe pataki, nitori iwọ yoo ni anfani lati ṣajọ ati fifuye awọn eto BPF lori ekuro pinpin, sibẹsibẹ, nini ekuro tirẹ fun ọ laaye lati lo awọn ẹya BPF tuntun, eyiti yoo han ninu pinpin rẹ ni awọn oṣu ti o dara julọ. , tabi, bi ninu ọran diẹ ninu awọn irinṣẹ n ṣatunṣe aṣiṣe kii yoo ṣe akopọ rara ni ọjọ iwaju ti a rii tẹlẹ. Pẹlupẹlu, ipilẹ ti ara rẹ jẹ ki o lero pataki lati ṣe idanwo pẹlu koodu naa.

Lati le kọ ekuro kan o nilo, ni akọkọ, ekuro funrararẹ, ati keji, faili iṣeto ekuro kan. Lati ṣe idanwo pẹlu BPF a le lo deede fanila ekuro tabi ọkan ninu awọn ekuro idagbasoke. Itan-akọọlẹ, idagbasoke BPF waye laarin agbegbe Nẹtiwọọki Linux ati nitorinaa gbogbo awọn iyipada laipẹ tabi ya lọ nipasẹ David Miller, olutọju Nẹtiwọọki Linux. Da lori iseda wọn - awọn atunṣe tabi awọn ẹya tuntun - awọn iyipada nẹtiwọọki ṣubu sinu ọkan ninu awọn ohun kohun meji - net tabi net-next. Awọn iyipada fun BPF ti pin ni ọna kanna laarin bpf и bpf-next, eyi ti o wa ni idapo sinu net ati net-tókàn, lẹsẹsẹ. Fun alaye diẹ sii, wo bpf_devel_QA и netdev-FAQ. Nitorinaa yan ekuro kan ti o da lori itọwo rẹ ati awọn iwulo iduroṣinṣin ti eto ti o ṣe idanwo lori (*-next kernels jẹ riru julọ ti awọn ti a ṣe akojọ).

O kọja ipari ti nkan yii lati sọrọ nipa bii o ṣe le ṣakoso awọn faili iṣeto kernel - o ro pe o ti mọ tẹlẹ bi o ṣe le ṣe, tabi setan lati ko eko on tikararẹ. Sibẹsibẹ, awọn ilana atẹle yẹ ki o jẹ diẹ sii tabi kere si lati fun ọ ni eto ṣiṣe BPF ti n ṣiṣẹ.

Ṣe igbasilẹ ọkan ninu awọn kernel loke:

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

Kọ atunto ekuro iṣẹ ti o kere julọ:

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

Mu awọn aṣayan BPF ṣiṣẹ ninu faili .config ti yiyan tirẹ (o ṣeeṣe julọ CONFIG_BPF yoo ti ṣiṣẹ tẹlẹ niwon systemd ti lo). Eyi ni atokọ awọn aṣayan lati ekuro ti a lo fun nkan yii:

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

Lẹhinna a le ni irọrun ṣajọpọ ati fi sori ẹrọ awọn modulu ati ekuro (nipasẹ ọna, o le ṣajọ ekuro ni lilo apejọ tuntun. clangnipa fifi CC=clang):

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

ati atunbere pẹlu ekuro tuntun (Mo lo fun eyi kexec lati package 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

IwUlO ti o wọpọ julọ ninu nkan naa yoo jẹ ohun elo naa bpftool, ti a pese gẹgẹbi apakan ti ekuro Linux. O ti kọ ati ṣetọju nipasẹ awọn olupilẹṣẹ BPF fun awọn idagbasoke BPF ati pe o le ṣee lo lati ṣakoso gbogbo iru awọn nkan BPF - awọn eto fifuye, ṣẹda ati ṣatunkọ awọn maapu, ṣawari igbesi aye ilolupo BPF, ati bẹbẹ lọ. Awọn iwe aṣẹ ni irisi awọn koodu orisun fun awọn oju-iwe eniyan ni a le rii ninu mojuto tabi, ti ṣajọ tẹlẹ, lori àwọn.

Ni akoko kikọ yii bpftool wa ni ti ṣetan nikan fun RHEL, Fedora ati Ubuntu (wo, fun apẹẹrẹ, okun yii, eyi ti o sọ itan ti ko pari ti apoti bpftool ni Debian). Ṣugbọn ti o ba ti kọ ekuro rẹ tẹlẹ, lẹhinna kọ bpftool rọrun bi paii:

$ 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  ]

$

(Nibi ${linux} - Eyi ni itọsọna kernel rẹ.) Lẹhin ṣiṣe awọn aṣẹ wọnyi bpftool yoo wa ni gba ni a liana ${linux}/tools/bpf/bpftool ati pe o le ṣafikun si ọna (akọkọ gbogbo si olumulo root) tabi o kan daakọ si /usr/local/sbin.

Gba bpftool o dara julọ lati lo igbehin clang, ti a pejọ gẹgẹbi a ti salaye loke, ki o ṣayẹwo boya o ti ṣajọpọ daradara - lilo, fun apẹẹrẹ, aṣẹ naa

$ 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
...

eyi ti yoo fihan iru awọn ẹya BPF ti o ṣiṣẹ ninu ekuro rẹ.

Nipa ọna, aṣẹ iṣaaju le ṣee ṣiṣẹ bi

# bpftool f p k

Eyi ni a ṣe nipasẹ afiwe pẹlu awọn ohun elo lati package iproute2, nibiti a ti le, fun apẹẹrẹ, sọ ip a s eth0 dipo ip addr show dev eth0.

ipari

BPF ngbanilaaye lati bata eefa kan lati ṣe iwọn daradara ati lori-fly yi iṣẹ ṣiṣe ti mojuto pada. Eto naa wa ni aṣeyọri pupọ, ni awọn aṣa ti o dara julọ ti UNIX: ẹrọ ti o rọrun ti o fun ọ laaye lati (tun) eto ekuro gba nọmba nla ti eniyan ati awọn ajo laaye lati ṣe idanwo. Ati pe, botilẹjẹpe awọn adanwo, bakanna bi idagbasoke ti awọn amayederun BPF funrararẹ, ti jinna lati pari, eto naa ti ni iduroṣinṣin ABI ti o fun ọ laaye lati kọ igbẹkẹle, ati pataki julọ, ọgbọn iṣowo ti o munadoko.

Emi yoo fẹ lati ṣe akiyesi pe, ni ero mi, imọ-ẹrọ ti di olokiki nitori pe, ni apa kan, o le ṣeré (awọn faaji ti ẹrọ le ni oye diẹ sii tabi kere si ni irọlẹ kan), ati ni apa keji, lati yanju awọn iṣoro ti ko le yanju (lẹwa) ṣaaju irisi rẹ. Awọn paati meji wọnyi papọ fi agbara mu awọn eniyan lati ṣe idanwo ati ala, eyiti o yori si ifarahan ti awọn solusan tuntun ati siwaju sii.

Nkan yii, botilẹjẹpe kii ṣe kukuru paapaa, jẹ ifihan nikan si agbaye ti BPF ati pe ko ṣe apejuwe awọn ẹya “ilọsiwaju” ati awọn ẹya pataki ti faaji. Eto ti nlọ siwaju jẹ nkan bii eyi: nkan atẹle yoo jẹ awotẹlẹ ti awọn oriṣi eto BPF (awọn iru eto 5.8 wa ni atilẹyin ninu ekuro 30), lẹhinna a yoo nipari wo bii o ṣe le kọ awọn ohun elo BPF gidi nipa lilo awọn eto wiwa kakiri ekuro fun apẹẹrẹ, lẹhinna o to akoko fun ikẹkọ ijinle diẹ sii lori faaji BPF, atẹle nipasẹ awọn apẹẹrẹ ti Nẹtiwọki BPF ati awọn ohun elo aabo.

Awọn nkan iṣaaju ninu jara yii

  1. BPF fun awọn ọmọ kekere, apakan odo: BPF Ayebaye

Awọn ọna asopọ

  1. BPF ati XDP Itọsọna Itọkasi - iwe lori BPF lati cilium, tabi diẹ ẹ sii gbọgán lati Daniel Borkman, ọkan ninu awọn ẹlẹda ati olutọju ti BPF. Eyi jẹ ọkan ninu awọn apejuwe pataki akọkọ, eyiti o yatọ si awọn miiran ni pe Daniẹli mọ pato ohun ti o nkọ nipa rẹ ati pe ko si awọn aṣiṣe nibẹ. Ni pato, iwe-ipamọ yii ṣe apejuwe bi o ṣe le ṣiṣẹ pẹlu awọn eto BPF ti awọn XDP ati awọn iru TC nipa lilo ohun elo ti a mọ daradara. ip lati package iproute2.

  2. Documentation/nẹtiwọki/filter.txt - faili atilẹba pẹlu iwe fun Ayebaye ati lẹhinna BPF ti o gbooro sii. Kika ti o dara ti o ba fẹ lati ṣawari sinu ede apejọ ati awọn alaye ayaworan imọ-ẹrọ.

  3. Bulọọgi nipa BPF lati Facebook. O ti ni imudojuiwọn ṣọwọn, ṣugbọn ni deede, bi Alexei Starovoitov (onkọwe ti eBPF) ati Andrii Nakryiko - (olutọju) kọwe sibẹ libbpf).

  4. Asiri ti bpftool. Okun twitter igbadun lati Quentin Monnet pẹlu awọn apẹẹrẹ ati awọn aṣiri ti lilo bpftool.

  5. Diọ sinu BPF: atokọ ti ohun elo kika. Atokọ omiran (ti o tun ṣe itọju) awọn ọna asopọ si iwe BPF lati Quentin Monnet.

orisun: www.habr.com

Fi ọrọìwòye kun