Narzędzie ruchu sieciowego eBPF wykorzystuje kombinację implementacji jądra i przestrzeni użytkownika do monitorowania wykorzystania sieci na urządzeniu od ostatniego uruchomienia urządzenia. Zapewnia dodatkowe funkcje, takie jak tagowanie gniazd, oddzielanie ruchu na pierwszym planie/w tle oraz zapora sieciowa dla poszczególnych UID, aby blokować dostęp aplikacji do sieci w zależności od stanu telefonu. Statystyki zebrane z narzędzia są przechowywane w strukturze danych jądra zwanej eBPF maps
a wyniki są wykorzystywane przez usługi takie jak NetworkStatsService
do dostarczania stał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
. Rozwój odbywa się w 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 frameworka dotyczą również framework/base/
i system/core
.
Realizacja
Począwszy od Androida 9, urządzenia Android działające na jądrze 4.9 lub wyższym i oryginalnie dostarczane z wydaniem P MUSZĄ używać opartego na eBPF rozliczania monitorowania ruchu sieciowego zamiast xt_qtaguid
. Nowa infrastruktura jest bardziej elastyczna i łatwiejsza w utrzymaniu oraz nie wymaga żadnego kodu jądra spoza drzewa.
Główne różnice projektowe między monitorowaniem ruchu starszego i eBPF przedstawiono na rysunku 1.
Rysunek 1. Różnice w projektowaniu monitorowania ruchu starszego (po lewej) i eBPF (po prawej)
Nowy projekt trafficController
oparty jest na cgroup
oraz module xt_bpf
netfilter wewnątrz jądra. Te filtry eBPF są nakładane na pakiet tx/rx, gdy przechodzą przez filtr. cgroup
cgroup znajduje się w warstwie transportowej i odpowiada za zliczanie ruchu według właściwego UID w zależności od UID gniazda oraz ustawienia przestrzeni użytkownika. xt_bpf
jest podpięty do łańcucha bw_raw_PREROUTING
i bw_mangle_POSTROUTING
i jest odpowiedzialny za zliczanie ruchu z poprawnym interfejsem.
W czasie rozruchu proces trafficController
w przestrzeni użytkownika tworzy mapy eBPF używane do zbierania danych i przypina wszystkie mapy jako wirtualny plik w sys/fs/bpf
. Następnie proces uprzywilejowany bpfloader
ładuje prekompilowany program eBPF do jądra i dołącza go do odpowiedniej cgroup
. Istnieje jedna główna cgroup
dla całego ruchu, więc cały proces powinien być domyślnie zawarty w tej cgroup
.
W czasie wykonywania trafficController
może oznaczać/odznaczać gniazdo, pisząc do traffic_cookie_tag_map
i traffic_uid_counterSet_map
. NetworkStatsService
może odczytywać statystyki ruchu z traffic_tag_stats_map
, traffic_uid_stats_map
i traffic_iface_stats_map
. Oprócz funkcji zbierania statystyk ruchu, trafficController
i filtr cgroup
eBPF są również odpowiedzialne za blokowanie ruchu z niektórych UID w zależności od ustawień telefonu. Funkcja blokowania ruchu sieciowego oparta na UID jest zamiennikiem modułu xt_owner
wewnątrz jądra, a tryb szczegółowy można skonfigurować, pisząc do 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 TrafficController
i NetworkStatsService
będą działały ze starszą lub nową implementacją. Jeśli aplikacja korzysta z publicznych interfejsów API, nie powinno być żadnej różnicy, czy w tle używane są narzędzia xt_qtaguid
czy eBPF.
Jeśli jądro urządzenia jest oparte na wspólnym jądrze systemu Android 4.9 (SHA 39c856663dcc81739e52b02b77d6af259eb838f6 lub nowszym), do wdrożenia nowego narzędzia eBPF nie są wymagane żadne modyfikacje warstw HAL, sterowników ani kodu jądra.
Wymagania
Konfiguracja jądra MUSI mieć włączone następujące konfiguracje:
-
CONFIG_CGROUP_BPF=y
-
CONFIG_BPF=y
-
CONFIG_BPF_SYSCALL=y
-
CONFIG_NETFILTER_XT_MATCH_BPF=y
-
CONFIG_INET_UDP_DIAG=y
Test konfiguracji jądra VTS jest pomocny przy sprawdzaniu, czy włączona jest poprawna konfiguracja.
-
Urządzenie
MEM_LOCK
rlimit MUSI być ustawione na 8 MB lub więcej.
Starszy proces wycofywania xt_qtaguid
Nowe narzędzie eBPF zastępuje moduł xt_qtaguid
oraz moduł xt_owner
, na którym 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 proc modułu xt_qtaguid
, są przenoszone do usługi NetworkManagement
Service. W zależności od wersji jądra urządzenia i pierwszego poziomu interfejsu API, NetworkManagement
Service wie, czy narzędzia eBPF są włączone i wybiera odpowiedni moduł, aby uzyskać dla każdej statystyki użycia sieci aplikacji. Aplikacje z poziomem SDK 28 i wyższym są blokowane przed dostępem do plików proc xt_qtaguid
przez sepolicy.
W następnej wersji Androida po 9, dostęp aplikacji do tych plików proc xt_qtaguid
zostanie całkowicie zablokowany. Zaczniemy usuwać moduł xt_qtaguid
z nowych wspólnych jąder Androida. Po jego usunięciu zaktualizujemy podstawową konfigurację Androida dla tej wersji jądra, aby jawnie wyłączyć moduł xt_qtaguid
. Moduł xt_qtaguid
zostanie całkowicie przestarzały, gdy minimalna wymagana wersja jądra dla wersji Androida to 4.9 lub nowsza.
W wersji Android 9 tylko urządzenia uruchamiane z wersją Android 9 muszą mieć nową funkcję eBPF. W przypadku urządzeń dostarczanych z jądrem, które obsługuje narzędzia eBPF, zalecamy aktualizację do nowej funkcji eBPF podczas aktualizacji do wersji Androida 9. Nie ma testu CTS, który wymusiłby tę aktualizację.
Walidacja
Powinieneś regularnie pobierać łatki z popularnych jąder Androida i mastera AOSP Androida. Upewnij się, że implementacja przeszła odpowiednie testy VTS i CTS, netd_unit_test
i libbpf_test
.
Testowanie
Istnieją testy net_tests jądra, które zapewniają, że masz włączone wymagane funkcje i przeniesione wymagane łaty jądra. Testy są zintegrowane w ramach testów VTS w wersji Android 9. Istnieje kilka testów jednostkowych w system/netd/
( netd_unit_test
i libbpf_test
). Istnieje kilka testów w netd_integration_test
, aby sprawdzić ogólne zachowanie nowego narzędzia.
Weryfikator CTS i CTS
Ponieważ oba moduły monitorowania ruchu są obsługiwane w wersji Android 9, nie ma testu CTS, który wymusiłby wdrożenie nowego modułu na wszystkich urządzeniach. Jednak dla urządzeń z wersją jądra wyższą niż 4.9, które oryginalnie dostarczane jest z wydaniem Androida 9 (tj. pierwszy poziom API >= 28), istnieją testy CTS na GSI, aby sprawdzić, czy nowy moduł jest poprawnie 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.
Testowanie ręczne
Istnieje kilka testów jednostkowych w system/netd/
( netd_unit_test
, netd_integration_test
i libbpf_test
). Dostępna jest obsługa dumpsys do ręcznego sprawdzania stanu. Polecenie dumpsys netd
pokazuje podstawowy stan modułu trafficController
i czy eBPF jest poprawnie włączony. Jeśli eBPF jest włączony, polecenie dumpsys netd trafficcontroller
pokazuje szczegółową zawartość każdej mapy eBPF, w tym informacje o oznaczonych gniazdach, statystyki na tag, UID i iface oraz dopasowanie UID właściciela.
Lokalizacje testowe
Testy CTS znajdują się pod adresem:
- https://android.googlesource.com/platform/cts/+/master/tests/tests/net/src/android/net/cts/TrafficStatsTest.java {: .external}
- https://android.googlesource.com/platform/cts/+/master/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java {: .external}
- https://android.googlesource.com/platform/system/netd/+/master/tests/bpf_base_test.cpp {: .external}
Testy VTS znajdują się pod adresem https://android.googlesource.com/kernel/tests/+/master/net/test/bpf_test.py .
Testy jednostkowe znajdują się w:
- https://android.googlesource.com/platform/system/netd/+/master/libbpf/BpfNetworkStatsTest.cpp {: .external}
- https://android.googlesource.com/platform/system/netd/+/master/server/TrafficControllerTest.cpp {: .external}