eBPF-Traffic-Monitoring

Das eBPF-Tool für Netzwerk-Traffic verwendet eine Kombination aus Kernel- und Nutzerbereichsimplementierung, um die Netzwerknutzung auf dem Gerät seit dem letzten Gerätestart zu überwachen. Es bietet zusätzliche Funktionen wie das Taggen von Sockets, das Trennen von Vordergrund- und Hintergrund-Traffic sowie eine Firewall pro UID, um Apps je nach Telefonstatus den Netzwerkzugriff zu verweigern. Die vom Tool erhobenen Statistiken werden in einer Kernel-Datenstruktur namens eBPF maps gespeichert. Das Ergebnis wird von Diensten wie NetworkStatsService verwendet, um seit dem letzten Start persistente Traffic-Statistiken bereitzustellen.

Beispiele und Quelle

Die Änderungen im Nutzerbereich betreffen hauptsächlich die Projekte system/netd und framework/base. Die Entwicklung erfolgt in AOSP, sodass der AOSP-Code immer auf dem neuesten Stand ist. Die Quelle befindet sich hauptsächlich unter system/netd/server/TrafficController*, system/netd/bpfloader und system/netd/libbpf/. Einige erforderliche Framework-Änderungen sind auch in framework/base/ und system/core enthalten.

Implementierung

Ab Android 9 müssen Android-Geräte mit Kernel 4.9 oder höher, die ursprünglich mit der P-Version ausgeliefert wurden, anstelle von xt_qtaguid die eBPF-basierte Abrechnung zur Überwachung des Netzwerkverkehrs verwenden. Die neue Infrastruktur ist flexibler und wartungsfreundlicher und erfordert keinen Kernelcode außerhalb des Baums.

Die wichtigsten Designunterschiede zwischen der Legacy- und der eBPF-basierten Traffic-Überwachung sind in Abbildung 1 dargestellt.

Unterschiede im Design zwischen Legacy- und eBPF-Traffic-Monitoring

Abbildung 1: Unterschiede zwischen dem Design für die Traffic-Überwachung mit Legacy-Methoden (links) und eBPF (rechts)

Das neue trafficController-Design basiert auf dem eBPF-Filter pro cgroup sowie dem xt_bpf-Netfilter-Modul im Kernel. Diese eBPF-Filter werden auf die Paketübertragung/-empfang angewendet, wenn die Pakete den Filter durchlaufen. Der cgroup-eBPF-Filter befindet sich auf der Transportschicht und ist dafür verantwortlich, den Traffic anhand der Socket-UID und der Userspace-Einstellung der richtigen UID zuzuordnen. Der xt_bpf-Netfilter ist an die Kette bw_raw_PREROUTING und bw_mangle_POSTROUTING angehängt und dafür verantwortlich, den Traffic für die richtige Schnittstelle zu zählen.

Beim Booten erstellt der Userspace-Prozess trafficController die eBPF-Maps, die für die Datenerhebung verwendet werden, und pinnt alle Maps als virtuelle Datei unter sys/fs/bpf. Der privilegierte Prozess bpfloader lädt dann das vorkompilierte eBPF-Programm in den Kernel und hängt es an den richtigen cgroup an. Es gibt einen einzelnen Stamm-cgroup für den gesamten Traffic. Daher sollten alle Prozesse standardmäßig in diesem cgroup enthalten sein.

Zur Laufzeit kann das trafficController einen Socket taggen/enttaggen, indem es in traffic_cookie_tag_map und traffic_uid_counterSet_map schreibt. Die NetworkStatsService kann die Daten zu Verkehrsstatistiken aus traffic_tag_stats_map, traffic_uid_stats_map und traffic_iface_stats_map lesen. Neben der Funktion zum Erfassen von Traffic-Statistiken sind die eBPF-Filter trafficController und cgroup auch dafür verantwortlich, Traffic von bestimmten UIDs je nach Telefoneinstellungen zu blockieren. Die UID-basierte Funktion zum Blockieren von Netzwerk-Traffic ersetzt das xt_owner-Modul im Kernel. Der Detailmodus kann durch Schreiben in traffic_powersave_uid_map, traffic_standby_uid_map und traffic_dozable_uid_map konfiguriert werden.

Die neue Implementierung folgt der alten xt_qtaguid-Modulimplementierung. TrafficController und NetworkStatsService werden also entweder mit der alten oder der neuen Implementierung ausgeführt. Wenn die App öffentliche APIs verwendet, sollte es keinen Unterschied machen, ob xt_qtaguid- oder eBPF-Tools im Hintergrund verwendet werden.

Wenn der Geräte-Kernel auf dem gemeinsamen Android-Kernel 4.9 (SHA 39c856663dcc81739e52b02b77d6af259eb838f6 oder höher) basiert, sind keine Änderungen an HALs, Treibern oder Kernelcode erforderlich, um das neue eBPF-Tool zu implementieren.

Voraussetzungen

  1. In der Kernelkonfiguration MÜSSEN die folgenden Konfigurationen aktiviert sein:

    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

    Der VTS-Kernelkonfigurationstest ist hilfreich, um zu prüfen, ob die richtige Konfiguration aktiviert ist.

Einstellung des alten xt_qtaguid

Das neue eBPF-Tool ersetzt das Modul xt_qtaguid und das Modul xt_owner, auf dem es basiert. Wir werden das xt_qtaguid-Modul aus dem Android-Kernel entfernen und die unnötigen Konfigurationen deaktivieren.

In Android 9 ist das xt_qtaguid-Modul auf allen Geräten aktiviert. Alle öffentlichen APIs, die die Proc-Datei des xt_qtaguid-Moduls direkt lesen, werden jedoch in den NetworkManagement-Dienst verschoben. Je nach Gerätekernelversion und erstem API-Level weiß der NetworkManagement-Dienst, ob eBPF-Tools aktiviert sind, und wählt das richtige Modul für jede Statistik zur App-Netzwerknutzung aus. Apps mit SDK-Level 28 und höher wird durch sepolicy der Zugriff auf xt_qtaguid-Proc-Dateien verwehrt.

In der nächsten Android-Version nach Version 9 wird der App-Zugriff auf diese xt_qtaguid-Proc-Dateien vollständig blockiert. Wir werden das xt_qtaguid-Modul aus den neuen gemeinsamen Android-Kerneln entfernen. Nachdem es entfernt wurde, aktualisieren wir die Android-Basiskonfiguration für diese Kernelversion, um das xt_qtaguid-Modul explizit zu deaktivieren. Das xt_qtaguid-Modul wird vollständig eingestellt, wenn die Mindestanforderung an die Kernelversion für eine Android-Version 4.9 oder höher ist.

In der Android 9-Version müssen nur Geräte, die mit der Android 9-Version auf den Markt kommen, die neue eBPF-Funktion haben. Bei Geräten, die mit einem Kernel ausgeliefert wurden, der eBPF-Tools unterstützt, empfehlen wir, beim Upgrade auf Android 9 auf die neue eBPF-Funktion zu aktualisieren. Es gibt keinen CTS-Test, um dieses Update zu erzwingen.

Zertifizierungsstufe

Sie sollten regelmäßig Patches aus den gemeinsamen Android-Kernels und dem Android AOSP-Main-Branch übernehmen. Achten Sie darauf, dass Ihre Implementierung die anwendbaren VTS- und CTS-Tests, die netd_unit_test und die libbpf_test besteht.

Testen

Es gibt Kernel-Netzwerktests, mit denen Sie prüfen können, ob die erforderlichen Funktionen aktiviert und die erforderlichen Kernel-Patches rückportiert wurden. Die Tests sind als Teil der VTS-Tests für Android 9-Releases integriert. In system/netd/ (netd_unit_test und libbpf_test) sind einige Unittests enthalten. In netd_integration_test sind einige Tests enthalten, um das Gesamtverhalten des neuen Tools zu validieren.

CTS und CTS‑Prüfung

Da beide Module zur Traffic-Überwachung in Android 9 unterstützt werden, gibt es keinen CTS-Test, der die Implementierung des neuen Moduls auf allen Geräten erzwingt. Für Geräte mit einer Kernelversion höher als 4.9, die ursprünglich mit Android 9 ausgeliefert wurden (d.h. das erste API-Level >= 28), gibt es jedoch CTS-Tests auf GSI, um zu prüfen, ob das neue Modul richtig konfiguriert ist. Mit alten CTS-Tests wie TrafficStatsTest, NetworkUsageStatsTest und CtsNativeNetTestCases kann überprüft werden, ob das Verhalten mit dem alten UID-Modul übereinstimmt.

Manuelle Tests

Es gibt einige Unittests in system/netd/ (netd_unit_test, netd_integration_test und libbpf_test). Es gibt dumpsys-Unterstützung für die manuelle Überprüfung des Status. Der Befehl dumpsys netd zeigt den grundlegenden Status des trafficController-Moduls und ob eBPF korrekt aktiviert ist. Wenn eBPF aktiviert ist, zeigt der Befehl dumpsys netd trafficcontroller den detaillierten Inhalt jeder eBPF-Karte an, einschließlich der Informationen zu getaggten Sockets, Statistiken pro Tag, UID und iface sowie der Übereinstimmung der Eigentümer-UID.

Teststandorte

CTS-Tests befinden sich unter:

VTS-Tests befinden sich unter https://android.googlesource.com/kernel/tests/+/android16-release/net/test/bpf_test.py.

Unittests befinden sich unter: