Monitorowanie ruchu eBPF

Narzędzie do monitorowania ruchu w sieci eBPF wykorzystuje połączenie implementacji w jądrze systemu i przestrzeni użytkownika do monitorowania wykorzystania sieci na urządzeniu od ostatniego uruchomienia urządzenia. Zapewnia dodatkowe funkcje, takie jak tagowanie gniazd, rozdzielanie ruchu na pierwszym planie i w tle oraz zapora sieciowa dla każdego identyfikatora UID, która blokuje aplikacjom dostęp do sieci w zależności od stanu telefonu. Statystyki zbierane przez to narzędzie są przechowywane w strukturze danych jądra o nazwie eBPF maps, a wynik jest używany przez usługi takie jak NetworkStatsService do dostarczania trwałych statystyk ruchu od ostatniego uruchomienia.

Przykłady i źródło

Zmiany w przestrzeni użytkownika dotyczą głównie projektów system/netd i framework/base. Prace rozwojowe są prowadzone w ramach AOSP, więc kod AOSP będzie zawsze aktualny. Źródło znajduje się głównie w system/netd/server/TrafficController*, system/netd/bpfloader i system/netd/libbpf/. Niektóre niezbędne zmiany w platformie są też w framework/base/ i system/core.

Implementacja

Począwszy od Androida 9, urządzenia z Androidem działające na jądrze 4.9 lub nowszym i dostarczane pierwotnie z Androidem P MUSZĄ używać rozliczania opartego na eBPF do monitorowania ruchu w sieci zamiast xt_qtaguid. Nowa infrastruktura jest bardziej elastyczna i łatwiejsza w utrzymaniu oraz nie wymaga żadnego kodu jądra poza drzewem.

Główne różnice w konstrukcji między starszym a eBPF monitorowaniem ruchu przedstawiono na rysunku 1.

Różnice w projektowaniu starszego i eBPF-owego monitorowania ruchu

Rysunek 1. Różnice w projektach monitorowania ruchu w przypadku starszej wersji (po lewej) i eBPF (po prawej)

Nowa trafficController architektura opiera się na filtrze cgroup eBPF, a także na module xt_bpf netfilter w jądrze. Te filtry eBPF są stosowane do pakietów wysyłanych i odbieranych, gdy przechodzą przez filtr. cgroupFiltr eBPF znajduje się w warstwie transportowej i odpowiada za zliczanie ruchu w odniesieniu do odpowiedniego identyfikatora UID w zależności od identyfikatora UID gniazda oraz ustawień przestrzeni użytkownika. Filtr sieciowy xt_bpf jest podłączony do łańcuchów bw_raw_PREROUTING i bw_mangle_POSTROUTING i odpowiada za zliczanie ruchu na odpowiednim interfejsie.

Podczas uruchamiania procesu przestrzeni użytkownika trafficController tworzy mapy eBPF używane do zbierania danych i przypina wszystkie mapy jako plik wirtualny w lokalizacji sys/fs/bpf. Następnie uprzywilejowany proces bpfloader wczytuje wstępnie skompilowany program eBPF do jądra i dołącza go do odpowiedniego cgroup. Wszystkie dane o ruchu mają jeden węzeł główny cgroup, więc domyślnie wszystkie procesy powinny być w nim uwzględnione.cgroup

Podczas działania trafficController może oznaczać gniazdo tagiem lub usuwać tag, zapisując dane w polach traffic_cookie_tag_map i traffic_uid_counterSet_map. Usługa NetworkStatsService może odczytywać dane statystyczne o ruchu z usług traffic_tag_stats_map, traffic_uid_stats_map i traffic_iface_stats_map. Oprócz funkcji zbierania statystyk ruchu filtr trafficController i cgroup eBPF odpowiada też za blokowanie ruchu z określonych identyfikatorów UID w zależności od ustawień telefonu. Funkcja blokowania ruchu sieciowego na podstawie identyfikatora UID zastępuje moduł xt_owner w jądrze, a tryb szczegółowy można skonfigurować, zapisując dane w plikach traffic_powersave_uid_map, traffic_standby_uid_map i traffic_dozable_uid_map.

Nowa implementacja jest zgodna ze starszą implementacją modułu xt_qtaguid, więc funkcje TrafficController i NetworkStatsService będą działać zarówno w przypadku starszej, jak i nowej implementacji. Jeśli aplikacja korzysta z publicznych interfejsów API, nie powinna odczuwać żadnej różnicy, niezależnie od tego, czy w tle są używane narzędzia xt_qtaguid czy eBPF.

Jeśli jądro urządzenia jest oparte na wspólnym jądrze Androida 4.9 (SHA 39c856663dcc81739e52b02b77d6af259eb838f6 lub nowszym), do wdrożenia nowego narzędzia eBPF nie są wymagane żadne modyfikacje HAL-i, sterowników ani kodu jądra.

Wymagania

  1. W konfiguracji jądra MUSZĄ być włączone te ustawienia:

    1. CONFIG_CGROUP_BPF=y
    2. CONFIG_BPF=y
    3. CONFIG_BPF_SYSCALL=y
    4. CONFIG_NETFILTER_XT_MATCH_BPF=y
    5. CONFIG_INET_UDP_DIAG=y

    Test konfiguracji jądra VTS pomaga sprawdzić, czy włączona jest prawidłowa konfiguracja.

Proces wycofywania starszego parametru xt_qtaguid

Nowe narzędzie eBPF zastępuje modułxt_qtaguid i modułxt_owner, na którym jest oparte. Zaczniemy usuwać moduł xt_qtaguid z jądra Androida i wyłączać jego niepotrzebne konfiguracje.

W Androidzie 9 moduł xt_qtaguid jest włączony na wszystkich urządzeniach, ale wszystkie publiczne interfejsy API, które bezpośrednio odczytują plik proc modułu xt_qtaguid, są przenoszone do usługi NetworkManagement. W zależności od wersji jądra urządzenia i pierwszego poziomu interfejsu API usługa NetworkManagement wie, czy narzędzia eBPF są włączone, i wybiera odpowiedni moduł, aby uzyskać statystyki wykorzystania sieci przez każdą aplikację. Aplikacje z pakietem SDK na poziomie 28 lub wyższym nie mają dostępu do plików xt_qtaguid proc ze względu na zasady sepolicy.

W kolejnej wersji Androida po wersji 9 dostęp aplikacji do tych plików xt_qtaguid proc zostanie całkowicie zablokowany, a my zaczniemy usuwać moduł xt_qtaguid z nowych wspólnych jąder Androida. Po usunięciu modułu zaktualizujemy podstawową konfigurację Androida dla tej wersji jądra, aby wyraźnie wyłączyć moduł xt_qtaguid. Moduł xt_qtaguid zostanie całkowicie wycofany, gdy minimalna wersja jądra wymagana w przypadku wersji Androida będzie wynosić 4.9 lub więcej.

W Androidzie 9 tylko urządzenia, które są wprowadzane na rynek z Androidem 9, muszą mieć nową funkcję eBPF. W przypadku urządzeń, które zostały dostarczone z jądrem obsługującym narzędzia eBPF, zalecamy zaktualizowanie go do nowej funkcji eBPF podczas uaktualniania do Androida 9. Nie ma testu CTS, który wymusza tę aktualizację.

Weryfikacja

Regularnie pobieraj poprawki z wspólnych jąder Androida i głównej gałęzi AOSP Androida. Upewnij się, że Twoja implementacja przechodzi odpowiednie testy VTS i CTS, netd_unit_test i libbpf_test.

Testowanie

Istnieją testy jądra net_tests, które sprawdzają, czy masz włączone wymagane funkcje i czy wymagane poprawki jądra zostały przeniesione do starszej wersji. Testy są zintegrowane z testami VTS w wersji Androida 9. W folderach system/netd/(netd_unit_test i libbpf_test) znajdują się testy jednostkowe. W folderze netd_integration_test znajdują się testy, które sprawdzają ogólne działanie nowego narzędzia.

CTS i weryfikator CTS

Oba moduły monitorowania ruchu są obsługiwane w Androidzie 9, więc nie ma testu CTS, który wymuszałby wdrożenie nowego modułu na wszystkich urządzeniach. W przypadku urządzeń z wersją jądra w wersji nowszej niż 4.9, które zostały pierwotnie wprowadzone na rynek z Androidem 9 (czyli pierwszy poziom interfejsu API >= 28), istnieją testy CTS na GSI, które sprawdzają, czy nowy moduł jest prawidłowo skonfigurowany. Stare testy CTS, takie jak TrafficStatsTest, NetworkUsageStatsTest i CtsNativeNetTestCases, mogą służyć do weryfikacji zachowania pod kątem zgodności ze starym modułem UID.

Testy ręczne

W system/netd/ znajdują się testy jednostkowe (netd_unit_test, netd_integration_test i libbpf_test). Dostępna jest funkcja dumpsys, która umożliwia ręczne sprawdzanie stanu. Polecenie dumpsys netd wyświetla podstawowy stan modułu trafficController i informację, czy eBPF jest prawidłowo włączony. Jeśli eBPF jest włączony, polecenie dumpsys netd trafficcontroller wyświetla szczegółową zawartość każdej mapy eBPF, w tym informacje o oznaczonych gniazdach, statystyki według tagu, identyfikator UID i interfejs oraz dopasowanie identyfikatora UID właściciela.

Lokalizacje testów

Testy CTS znajdują się w tym katalogu:

Testy VTS znajdują się na stronie https://android.googlesource.com/kernel/tests/+/android17-release/net/test/bpf_test.py.

Testy jednostkowe znajdują się w: