Filtr pakietów BSD

BPF ( Berkeley Packet Filter ) lub filtr pakietów BSD , jest minimalistyczny kod wstrzykiwany do jądra , pozwala użytkownikowi na wykonywanie sieci filtrowania w jądrze. W różnych jego wersjach (przykład: eBPF (extend Berkeley Packet Filter)) wdrożono nowe narzędzia ułatwiające produkcję programów BPF. Ponadto można wykorzystać nowe obszary zastosowań, takie jak monitorowanie zdarzeń w jądrze i jego śledzenie. Do dziś istnieją różne problemy, głównie na poziomie audytora.

Definicja

BPF, pierwotnie zaprojektowany w 1992 roku, to minimalistyczny kod binarny wstrzykiwany do jądra z przestrzeni użytkownika . Pozwala użytkownikowi filtrować pakiety krążące w jądrze, unikając konieczności przesyłania ich do przestrzeni użytkownika. Jednak ze względu na swoją minimalistyczną stronę posiada niewiele instrukcji, ponadto jego trudność programistyczna powoduje, że jest używana przez niewielką liczbę aplikacji, takich jak tcpdump. W 2013 roku Aleksiej Starowojtow (inżynier oprogramowania specjalizujący się w jądrze na Facebooku) całkowicie przerobił BPF, dodając nowe funkcje i poprawiając jego wydajność. Ta nowa wersja nazywa się eBPF, w przeciwieństwie do cBPF (klasyczny BPF) oznaczający poprzednią wersję. Ten nowy język umożliwia projektowanie większej różnorodności przypadków użycia, które można podzielić na dwa obszary zastosowań. Pierwszym obszarem jest śledzenie i monitorowanie jądra, a drugim programowanie sieciowe.

Przypadek użycia

Istnieje wiele przypadków użycia, takich jak śledzenie, filtrowanie zapory kontenerowej lub tworzenie sieci, filtrowanie gniazd, filtrowanie pakietów i kontrola ruchu. Możliwe jest również wykonanie filtrowania na najniższym poziomie stosu sieciowego, to znaczy bezpośrednio przez sterownik karty sieciowej. Tak więc paczki można wyrzucić bardzo wcześnie; na przykład XDP (Express Data Path) to projekt wykorzystujący eBPF, który może być wykorzystany do zapobiegania atakom typu „odmowa usługi” . Ponadto BPF umożliwiają wydajne i elastyczne monitorowanie wydajności sieci dla aplikacji na maszynach wirtualnych , czego przykładem jest framework vNetTracer.

Oto niewyczerpująca lista projektów wykorzystujących GMP:

Śledzenie / monitorowanie:

Bpftrace jest językiem plotera wysokiego poziomu do ulepszania filtrów pakietów Linux Berkeley (eBPF), jest dostępny w najnowszych wersjach jądra linux (tj. od wersji 4.x). Dodatkowo bpftrace używa LLVM do kompilacji skryptów i używa BCC do interakcji z systemem linux BPF. Perf to narzędzie do analizy wydajności systemu opracowane przez społeczność programistów jądra systemu Linux. Zagięcie jest lekkim narzędziem do dynamicznego śledzenia bez zależności innych niż libc. Obsługuje architektury x86_64 arch64, arm i powerpc. Kompiluje skrypty warstwy do programu BPF i używa składni podobnej do C. Systemdotknij to narzędzie do śledzenia / sondowania na licencji GPL , które pozwala ominąć procedurę ponownej kompilacji, instalacji i ponownego uruchomienia w celu zebrania danych. Posiada interfejs wiersza poleceń oraz język skryptowy. PCP to skrót od „Performance Co-Pilot”. Jest to dojrzały, rozszerzalny, wieloplatformowy zestaw narzędzi, który umożliwia analizę systemu na żywo i retrospektywnie. Zakres splotu to narzędzie do monitorowania i kontrolowania kontenera Docker w czasie rzeczywistym. Oferuje widok na metryki, tagi i metadane kontenera; a także zarządzanie kontenerami.


Sieć:

Migawka to oprogramowanie typu open source, które zapewnia i zabezpiecza połączenia sieciowe i równoważące obciążenie między kontenerami aplikacji lub procesami. Jest zintegrowany ze strukturami orkiestracji Kubernetes i Mesos . Suricata to system wykrywania włamań do sieci, system zapobiegania włamaniom i urządzenie do kontroli bezpieczeństwa sieci. Systemd to zestaw programów do zarządzania systemem w jądrze linux. Iproute2 to oprogramowanie typu open source dostarczające narzędzia do kontrolowania i monitorowania sieci w jądrze linux. P4c-xdp to kompilator zaplecza kodu P4 dla XDP.


Inne:

LLVM to kompilator kodu C w programie eBPF. UDW skrót od BPF Compiler Collection, to zestaw narzędzi do pisania wydajnych programów do śledzenia i manipulowania jądrem. Dodatkowo BCC ułatwia pisanie programów BPF, z instrumentacją jądra w C i jego nakładkami w Pythonie i lua . Libbpf to biblioteka BPF pozwalająca na ładowanie programów BPF, w formacie ELF produkowanym przez LLVM, w jądrze. Bpftool to narzędzie do kontroli i manipulacji programami eBPF. Gobpf to biblioteka GO umożliwiająca zestawowi narzędzi BCC tworzenie programów eBPF z kodu GO. Ebpf_asm to asembler dla programów eBPF napisany w składni podobnej do składni Intela.

Operacja techniczna

BPF wykorzystuje wykresy przepływu sterowania CFG do reprezentowania kryteriów używanych w analizie pakietów, a także do jego wydajności w wyrażeniach modelu drzewa . Ponadto wykresy te są wykorzystywane przez BPF do konfigurowania reguł filtrowania, dzięki czemu można skutecznie zredukować ścieżki CFG niepotrzebne do analizy pakietu, a także nadmiarowe porównania. Transfer danych wykonywany przez wywołania systemowe odbywa się dwukierunkowo między jądrem a przestrzenią użytkownika. Pozwalają one na prawidłowy postęp wstrzykiwania kodu binarnego eBPF do jądra, a także komunikację danych z jądra docelowego do procesu w przestrzeni użytkownika. Pakiety skojarzone z programem BPF są częściowo kopiowane do bufora przed przeniesieniem do przestrzeni użytkownika. BPF umożliwia programowi zdefiniowanie liczby bajtów pakietu do skopiowania do bufora. Oszczędza to czas, unikając kopiowania niepotrzebnych danych. Na przykład dla pakietów TCP/IP/Ethernet wystarczy 134 bajty. Program chcący wykonać statystyki ramek TCP będzie mógł skopiować tylko część ramek, oszczędzając w ten sposób czas wykonania.

eBPF jest rozszerzeniem BPF, które różni się od niego na kilka sposobów: ładowanie programów jest wykonywane przez użytkownika, a po zakończeniu programu sprawdzane jest, czy można go bezpiecznie uruchomić. Najnowszym rozszerzeniem wprowadzonym przez eBPF jest możliwość dostępu do współdzielonych struktur danych. W rzeczywistości, aby udostępnić te dane, eBPF wykorzystuje trzy różne mechanizmy:

Od wersji 3.15 jądra Linux funkcje maszyny wirtualnej eBPF zapewniają dostęp do warstwy łącza poprzez podstawowe instrukcje i wprowadzenie nowej funkcjonalności eBPF, co tworzy sposób filtrowania i filtrowania, analizy pakietów sieciowych. Jednak programy eBPF mogą być wywoływane w różnych warstwach stosu sieciowego, co pozwala na przetwarzanie przechwyconych pakietów przed przejściem do następnej warstwy. EBPF opiera się na kodzie binarnym skompilowanym do natywnych instrukcji procesora, gdy rozszerzenie jest ładowane do jądra. W przeciwieństwie do klasycznego kodu bajtowego, na przykład Javy, kompilator i czas wykonania eBPF nie narzucają żadnego zabezpieczenia typu ani pamięci. Zamiast tego bezpieczeństwo jest zwiększane przez statyczny weryfikator, który sprawdza, czy program nie może uzyskać dostępu do struktur danych jądra lub spowodować błędy stron.

Zagrożenia bezpieczeństwa i stabilności występują, gdy kod jest wykonywany w jądrze. Aby złagodzić te zagrożenia, BPF polega na interpreterze, który bezpiecznie wykonuje program. Aby zmniejszyć to ryzyko, eBPF wprowadza weryfikator Linuksa, który zapewnia, że ​​każdy program spełnia określone warunki przed załadowaniem do jądra, unikając w ten sposób wysokich kosztów czasu weryfikacji. Zapewnia, że ​​program jest w stanie zakończyć działanie, że nie zawiera pętli, która mogłaby spowodować awarię jądra lub że niektóre instrukcje są niedostępne. A innym razem sprawdza każdą instrukcję i symuluje ją, aby mieć pewność, że stan rejestrów i baterii jest prawidłowy, uniemożliwiając w ten sposób dostęp do pamięci lub stanu jądra poza jej przydzielonym obszarem. Implementacja eBPF zapewnia bezpieczeństwo jądra, ale także oferuje możliwość wykonania różnych prac w jądrze, takich jak śledzenie jądra i tworzenie sieci.

Wywołania systemowe umożliwiają ładowanie kodu binarnego. Aby wgranie się powiodło, program musi zostać zweryfikowany przez weryfikatora eBPF. Programy EBPF mogą być tworzone w tym samym czasie, nawet na różnych hakach. Dzięki temu mogą działać pojedynczo lub być połączone łańcuchami.

Sieci

Program BPF może nasłuchiwać na interfejsie, gdy tak się dzieje, sterownik interfejsu wywołuje ten program jako pierwszy. BPF następnie dystrybuuje pakiety do każdego filtra uczestniczącego w przetwarzaniu. Zdefiniowane przez użytkownika filtry są następnie stosowane do pakietów i decydują, czy pakiet jest akceptowany, czy nie oraz ile bajtów każdego pakietu należy zapisać. Dla każdego filtra, który akceptuje pakiet, BPF kopiuje żądaną ilość danych jako bufor do skojarzenia z ten filtr. Gdy nastąpią modyfikacje topologii lub zmiany w aplikacjach, konieczne staje się zmodyfikowanie reguł służących jako firewall, aby móc dodawać, usuwać lub modyfikować porty i adresy, na które wpływają filtry. Aby to zrobić, dzięki strategii bitmapowej, która sprawia, że ​​program w C jest prosty, wystarczy utworzyć nowy program z nowymi mapami i załadować mapę z nowymi parami klucz-wartość i zamienić ją na stary program, naśladując w ten sposób zachowanie iptables-restore.

Przybory

Kompilacja jita

Filtry są interpretowane jako kod bajtowy w jądrze z interpreterem. W przypadku braku tego, eBPF może użyć kompilatora on-the-fly jądra (kompilatora JIT) do tłumaczenia kodów bajtowych produkowanych przez eBPF na kod natywny i do przeprowadzania opcjonalnych optymalizacji zależnych od maszyny.

LLVM

Clang (natywny LLVM) pozwala użytkownikowi skompilować swój kod C do instrukcji eBPF w pliku ELF.

UDW

Programowanie w instrukcji eBPF może być skomplikowane. Dlatego istnieje zestaw narzędzi o nazwie BPF Compiler Collection (BCC), który pozwala użytkownikowi na łatwe tworzenie programów eBPF. BCC obejmuje i ulepsza LLVM, aby zapewnić użytkownikowi możliwość definiowania map eBPF w kodzie C i kompilowania tego kodu C w program eBPF.

Instrukcje

Maszyna wirtualna BPF+ posiada 5 klas działania:

Ulepszenia i ograniczenia

W 2019 roku deweloperowi wciąż pojawiają się różne problemy, takie jak:

Istnieją ograniczenia w korzystaniu z usług jądra, niewiele funkcji pomocniczych, aw programach eBPF nie można używać przestrzeni użytkownika ani usług stron trzecich. Pewne ograniczenia sprawiają, że kontrole programu są elastyczne i umożliwiają integralność systemu, takie jak niemożność dokonywania alokacji dynamicznych, dostępu do struktur danych jądra, wywoływania API jądra lub instrukcji skoku. Jak również fakt, że jest wykonywany w jednym wątku, a zatem ma czas wykonania powiązany z liczbą instrukcji.

Wydajność BPF

cGMP wykorzystuje bufor strategii implementacji, który sprawia, że ​​jego całkowita wydajność jest do 100 razy szybsza niż SUN NIT (Network Interface Tap ) działający na tym samym sprzęcie. Czas wykonania wywołania BPF wynosi około 6 mikrosekund na pakiet dla filtru, który odrzuca wszystkie pakiety. EBPF są do 4 razy szybsze na architekturach x86_64 niż implementacja cBPF dla niektórych mikrobenchmarków filtrowania sieci, a większość jest 1,5 raza szybsza. Istnieje współczynnik poprawy wydajności eBPF o 10 w porównaniu z IPTABLES i NFTABLES.

Pre-jądro (XDP)

XDP, dołączony do najniższego poziomu stosu sieciowego, jest odpowiedni do zgrubnego filtrowania pakietów, takiego jak zapobieganie atakom typu „odmowa usługi” . Może generować czterokrotnie większą wydajność w porównaniu z podobnym zadaniem w jądrze. Ponadto XDP oferuje również poprawę mediany opóźnień przy użyciu kompilacji kodu w JIT (Just In Time), do 45% poprawy wydajności kosztem wyższych wartości opóźnień odstających. XDP oferuje kompromis, nie oferuje tak dobrej wydajności, jak wysokowydajne dedykowane frameworki, które zastępują jądro. Oferuje jednak integrację jądra, co oznacza, że ​​pakiety mogą przechodzić przez stos sieciowy ze wszystkimi jego zaletami. Chociaż obsługuje tylko 50% przepustowości linii 10 GbE, reprezentuje to wydajność pojedynczego rdzenia, czyli skaluje się wraz z liczbą rdzeni procesora.

Historia BPF

BPF pierwotnie oznacza „filtr pakietów Berkeley”, opracowany dla systemu UNIX w 1992 roku w celu filtrowania pakietów sieciowych, a następnie umożliwia poprawę wydajności w aplikacjach monitorujących sieć, takich jak „tcpdump”. BPF nie ma funkcji odrzucania odebranych pakietów, ale opisane jako filtr mogą kojarzyć pakiety, kopiować pakiety i wysyłać pakiety Początkowo BPF są zaimplementowane w jądrze linux 2.x, mającym 2 rejestry 32 Następnie w 2013 roku Aleksiej Starowojtow zaproponował ulepszenie BPF, które teraz różnicuje cBPF (klasyczny BPF) i eBPF (rozszerzony BPF), jedną z najbardziej zauważalnych zmian jest przejście do 10 rejestrów 64 bitowych, a także wywołanie funkcji w jądrze dzięki nowej instrukcji Kolejna różnica to brak trwałości stanu w cBPF natomiast w eBPF stany mogą być utrzymywane dzięki mapom eBPF pojawiają się w wersji 3 .x z jądra Linuksa, z ciągłymi ulepszeniami, takimi jak kompilator JIT (Just In Time), nowe funkcje, takie jak „mapy” i „wywołania ogonowe”.

Odniesienie

  1. Monnet 2016
  2. Chaignon 2018
  3. Suo 2018
  4. Scholz 2018
  5. Cilium Autorzy 2019
  6. bpftrace
  7. perf
  8. warstwowa
  9. systemdotknij
  10. PCP
  11. Zakres splotu
  12. rzęska
  13. Suricata
  14. Systemd
  15. iproute2
  16. p4c-XDP
  17. LLVM
  18. BCC
  19. libbpf
  20. bpftool
  21. gobpf
  22. ebpf_asm
  23. McCanne 1993
  24. Lidl 2002
  25. Baidya 2018
  26. Saif 2018
  27. Ellis 2017
  28. Belkalem 2018
  29. 2017
  30. Gershuni 2019
  31. Fleming 2017
  32. Miano 2018
  33. Deepak 2018
  34. Begel 1999
  35. Wt 2018
  36. Van Tu 2017
  37. Zabawka 2015
  38. Corbet 2014
  39. Zabawka 2017
  40. Bos 2004

Bibliografia

Stronie internetowej

Zobacz również