Monitorowanie ruchu eBPF

Narzędzie do monitorowania ruchu sieciowego eBPF korzysta z kombinacji implementacji w przestrzeni jądra i użytkownika, aby monitorować wykorzystanie sieci na urządzeniu od ostatniego uruchomienia. Zapewnia ona dodatkowe funkcje, takie jak oznaczanie gniazd, oddzielanie ruchu w tle i firewall na podstawie UID, aby blokować dostęp aplikacji do sieci w zależności od stanu telefonu. Statystyki zebrane przez narzędzie są przechowywane w strukturze danych jądra o nazwie eBPF maps, a ich 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/netdframework/base. Programy są prowadzone w AOSP, więc kod AOSP będzie zawsze aktualny. Źródło znajduje się głównie w system/netd/server/TrafficController*, system/netd/bpfloadersystem/netd/libbpf/. Niektóre niezbędne zmiany w ramach znajdują się też w dokumentach framework/base/system/core.

Implementacja

Począwszy od Androida 9 urządzenia z Androidem z jądrem w wersji 4.9 lub nowszej, które zostały pierwotnie dostarczone z wersją P, MUSZĄ używać rejestrowania monitorowania ruchu sieciowego na podstawie eBPF zamiast xt_qtaguid. Nowa infrastruktura jest bardziej elastyczna i łatwiejsza w utrzymaniu, a dodatkowo nie wymaga kodu jądra poza drzewem.

Rysunek 1 przedstawia główne różnice w projektowaniu między starszym a eBPF monitorowaniem ruchu.

Różnice w projektowaniu starszych i eBPF dotyczących monitorowania ruchu

Rysunek 1. Różnice między starszym (po lewej) a nową (po prawej) wersją monitorowania ruchu

Nowa architektura trafficController opiera się na filtrach eBPF na poziomie cgroup oraz module netfilter xt_bpf w jądrze. Filtry eBPF są stosowane do pakietów tx/rx, gdy przechodzą przez filtr. Filtr eBPF cgroup znajduje się na warstwie transportowej i odpowiada za zliczanie ruchu w stosunku do właściwego identyfikatora UID w zależności od identyfikatora gniazda oraz ustawień przestrzeni użytkownika. Filtr sieci xt_bpf jest podłączony do łańcucha bw_raw_PREROUTING i bw_mangle_POSTROUTING i odpowiada za zliczanie ruchu w odniesieniu do właściwego interfejsu.

Podczas uruchamiania proces w przestrzeni użytkownika trafficController tworzy mapy eBPF służące do zbierania danych i przypina wszystkie mapy jako plik wirtualny w folderze sys/fs/bpf. Następnie proces uprzywilejowany bpfloader wczytuje skompilowany program eBPF do jądra i dołącza go do odpowiedniego cgroup. W przypadku całego ruchu istnieje jeden główny obiekt cgroup, więc domyślnie w tym cgroup powinien być uwzględniony cały proces.

W czasie wykonywania trafficController może dodawać i usuwać tagi z gniazda, zapisując w nim dane za pomocą funkcji traffic_cookie_tag_maptraffic_uid_counterSet_map. 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 eBPF trafficControllercgroup odpowiada też za blokowanie ruchu z określonych identyfikatorów użytkownika w zależności od ustawień telefonu. Funkcja blokowania ruchu sieciowego na podstawie 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_maptraffic_dozable_uid_map.

Nowa implementacja jest zgodna ze starszą implementacją modułu xt_qtaguid, więc moduły TrafficControllerNetworkStatsService będą działać z wersją starszą lub nowszą. Jeśli aplikacja korzysta z publicznych interfejsów API, nie powinno mieć znaczenia, 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 w wersji 4.9 (SHA2 39c856663dcc81739e52b02b77d6af259eb838f6 lub nowszej), nie trzeba modyfikować interfejsów HAL, sterowników ani kodu jądra, aby wdrożyć nowe narzędzie eBPF.

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 jest przydatny podczas sprawdzania, czy włączona jest prawidłowa konfiguracja.

Proces wycofywania starszej wersji atrybutu xt_qtaguid

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

W wersji Androida 9 moduł xt_qtaguid jest włączony na wszystkich urządzeniach, ale wszystkie publiczne interfejsy API, które bezpośrednio odczytują plik 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ł do uzyskania statystyk dotyczących wykorzystania sieci przez każdą aplikację. Aplikacje z poziomem pakietu SDK 28 lub wyższym nie mają dostępu do plików xt_qtaguid proc. z powodu ograniczeń w zasadach zabezpieczeń.

W następnej wersji Androida po 9 będzie całkowicie zablokowany dostęp aplikacji do tych plików xt_qtaguid proc. Zaczniemy usuwać moduł xt_qtaguid z nowych wspólnych jąder Androida. Po usunięciu tego 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 minimalne wymagania dotyczące wersji jądra dla wersji Androida będą wynosić 4.9 lub nowszą.

W wersji Androida 9 nowa funkcja eBPF jest wymagana tylko na urządzeniach, które są uruchamiane z Androidem 9. W przypadku urządzeń dostarczonych z jądrem, które może obsługiwać narzędzia eBPF, zalecamy zaktualizowanie go do nowej funkcji eBPF podczas przechodzenia na Androida 9. Nie ma testu CTS, który wymuszałby tę aktualizację.

Weryfikacja

Należy regularnie pobierać poprawki z powszechnie używanych jąder Androida i Androida AOSP. Upewnij się, że Twoja implementacja przeszła odpowiednie testy VTS i CTS, netd_unit_testoraz libbpf_test.

Testowanie

Dostępne są testy jądra systemu, które sprawdzają, czy wymagane funkcje są włączone, a wymagane poprawki jądra zostały przywrócone. Testy są zintegrowane w ramach testów VTS w ramach wersji Androida 9. W system/netd/ znajdują się testy jednostkowe (netd_unit_testlibbpf_test). W 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 wersji Androida 9, więc nie ma testu CTS, który wymusiłby implementację nowego modułu na wszystkich urządzeniach. Jednak w przypadku urządzeń z jądrem nowszym niż 4.9, które pierwotnie były dostarczane z wersją Androida 9 (czyli z poziomem interfejsu API ≥ 28), dostępne są testy CTS na GSI, które sprawdzają, czy nowy moduł jest prawidłowo skonfigurowany. Stare testy CTS, takie jak TrafficStatsTest, NetworkUsageStatsTest i CtsNativeNetTestCases, można wykorzystać do zweryfikowania działania pod kątem spójności ze starym modułem UID.

Testy ręczne

system/netd/ są dostępne testy jednostkowe (netd_unit_test, netd_integration_test i libbpf_test). Aby ręcznie sprawdzić stan, możesz użyć narzędzia dumpsys. Polecenie dumpsys netd pokazuje podstawowy stan modułu trafficController oraz to, czy funkcja eBPF jest prawidłowo włączona. Jeśli eBPF jest włączone, polecenie dumpsys netd trafficcontroller wyświetla szczegółowe informacje o każdej mapie eBPF, w tym informacje o otagowanych gniazdach, statystyki dotyczące tagów, UID i interfejsów oraz dopasowanie UID właściciela.

Testowanie lokalizacji

Testy CTS znajdują się pod tymi adresami:

Testy VTS znajdują się pod adresem https://android.googlesource.com/kernel/tests/+/main/net/test/bpf_test.py.

Testy jednostkowe znajdują się w tych miejscach: