eBPFトラフィックモニタリング

eBPF ネットワーク トラフィック ツールは、カーネルとユーザー空間の実装の組み合わせを使用して、デバイスの最後の起動以降のデバイスのネットワーク使用状況を監視します。ソケットのタグ付け、フォアグラウンド/バックグラウンド トラフィックの分離、UID ごとのファイアウォールなどの追加機能を提供して、電話の状態に応じてネットワーク アクセスからアプリをブロックします。ツールから収集された統計は、 eBPF mapsと呼ばれるカーネル データ構造に保存され、その結果はNetworkStatsServiceなどのサービスによって使用され、最後の起動以降の永続的なトラフィック統計が提供されます。

例とソース

ユーザー空間の変更は、主にsystem/netdおよびframework/baseプロジェクトにあります。開発は AOSP で行われているため、AOSP コードは常に最新の状態になります。ソースは主にsystem/netd/server/TrafficController*system/netd/bpfloader 、およびsystem/netd/libbpf/にあります。必要なフレームワークの変更は、 framework/base/system/coreにもあります。

実装

Android 9 以降、カーネル 4.9 以降で実行され、元々 P リリースに同梱されていた Android デバイスは、 xt_qtaguid の代わりにxt_qtaguidベースのネットワーク トラフィック モニタリング アカウンティングを使用する必要があります。新しいインフラストラクチャは、より柔軟で保守しやすく、ツリー外のカーネル コードを必要としません。

レガシー トラフィック モニタリングと eBPF トラフィック モニタリングの主な設計上の違いを図 1 に示します。

レガシーと eBPF トラフィック モニタリングの設計の違い

図 1.レガシー (左) と eBPF (右) のトラフィック監視設計の違い

新しいtrafficControllerの設計は、カーネル内のcgroup eBPF フィルターとxt_bpf netfilter モジュールに基づいています。これらの eBPF フィルターは、フィルターを通過するときにパケット tx/rx に適用されます。 cgroup eBPF フィルターはトランスポート層にあり、ソケット UID とユーザー空間設定に応じて、正しい UID に対してトラフィックをカウントします。 xt_bpf netfilter はbw_raw_PREROUTINGおよびbw_mangle_POSTROUTINGチェーンにフックされ、正しいインターフェイスに対してトラフィックをカウントします。

ブート時に、ユーザー空間プロセスのtrafficControllerは、データ収集に使用される eBPF マップを作成し、すべてのマップを仮想ファイルとしてsys/fs/bpfに固定します。次に、特権プロセスbpfloaderがプリコンパイル済み eBPF プログラムをカーネルにロードし、正しいcgroupにアタッチします。すべてのトラフィックに対して単一のルートcgroupがあるため、すべてのプロセスがデフォルトでそのcgroupに含まれる必要があります。

実行時に、 trafficControllerは、 traffic_cookie_tag_mapおよびtraffic_uid_counterSet_mapに書き込むことにより、ソケットのタグ付け/タグ解除を行うことができます。 NetworkStatsServiceは、 traffic_tag_stats_maptraffic_uid_stats_map 、およびtraffic_iface_stats_mapからトラフィック統計データを読み取ることができます。トラフィック統計収集機能に加えて、 trafficControllercgroup eBPF フィルターも、電話の設定に応じて特定の UID からのトラフィックをブロックする役割を果たします。 UID ベースのネットワーク トラフィック ブロック機能は、カーネル内のxt_ownerモジュールの置き換えであり、詳細モードは、 traffic_powersave_uid_maptraffic_standby_uid_map 、およびtraffic_dozable_uid_mapに書き込むことで構成できます。

新しい実装は従来のxt_qtaguidモジュールの実装に従っているため、 TrafficControllerNetworkStatsServiceは従来の実装でも新しい実装でも実行されます。アプリがパブリック API を使用する場合、 xt_qtaguidまたは eBPF ツールがバックグラウンドで使用されているかどうかに違いはありません。

デバイス カーネルが Android 共通カーネル 4.9 (SHA 39c856663dcc81739e52b02b77d6af259eb838f6 以降) に基づいている場合、新しい eBPF ツールを実装するために HAL、ドライバー、またはカーネル コードを変更する必要はありません。

要件

  1. カーネル構成では、次の構成がオンになっている必要があります。

    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

    VTS カーネル構成テストは、正しい構成がオンになっていることを確認するときに役立ちます。

  2. デバイスのMEM_LOCK rlimit は 8 MB 以上に設定する必要があります。

従来の xt_qtaguid 非推奨プロセス

新しい eBPF ツールは、 xt_qtaguidモジュールとそのベースとなっているxt_ownerモジュールを置き換えます。 Android カーネルからxt_qtaguidモジュールの削除を開始し、不要な構成を無効にします。

Android 9 リリースでは、 xt_qtaguidモジュールがすべてのデバイスで有効になっていますが、 xt_qtaguidモジュールの proc ファイルを直接読み取るすべてのパブリック API はNetworkManagement Service に移動されています。デバイスのカーネル バージョンと最初の API レベルに応じて、 NetworkManagement Service は eBPF ツールがオンになっているかどうかを認識し、各アプリのネットワーク使用統計情報を取得するための適切なモジュールを選択します。 SDK レベル 28 以降のアプリは、sepolicy によってxt_qtaguid proc ファイルへのアクセスがブロックされます。

9 以降の次の Android リリースでは、これらのxt_qtaguid proc ファイルへのアプリ アクセスは完全にブロックされ、新しい Android 共通カーネルからxt_qtaguidモジュールの削除を開始します。削除後、そのカーネル バージョンの Android ベース構成を更新して、 xt_qtaguidモジュールを明示的にオフにします。 Android リリースの最小カーネル バージョン要件が 4.9 以上の場合、 xt_qtaguidモジュールは完全に非推奨になります。

Android 9 リリースでは、Android 9 リリースで起動するデバイスのみが新しい eBPF 機能を持つ必要があります。 eBPF ツールをサポートできるカーネルが付属しているデバイスの場合、Android 9 リリースにアップグレードするときに、新しい eBPF 機能に更新することをお勧めします。その更新を実施するための CTS テストはありません。

検証

Android 共通カーネルと Android AOSP マスターから定期的にパッチを適用する必要があります。実装が該当する VTS および CTS テスト、 netd_unit_test 、およびlibbpf_testに合格することを確認します。

テスト

必要な機能がオンになっており、必要なカーネル パッチがバックポートされていることを確認するためのカーネル net_testsがあります。テストは、Android 9 リリース VTS テストの一部として統合されています。 system/netd/にはいくつかの単体テストがあります ( netd_unit_testおよびlibbpf_test )。 netd_integration_testには、新しいツールの全体的な動作を検証するためのテストがいくつかあります。

CTS と CTS ベリファイア

Android 9 リリースでは両方のトラフィック モニタリング モジュールがサポートされているため、すべてのデバイスに新しいモジュールを強制的に実装するための CTS テストはありません。ただし、元々 Android 9 リリースに同梱されていたカーネル バージョン 4.9 以降のデバイス (つまり、最初の API レベル >= 28) の場合、GSI で CTS テストを実行して、新しいモジュールが正しく構成されていることを検証します。 TrafficStatsTestNetworkUsageStatsTestCtsNativeNetTestCasesなどの古い CTS テストを使用して、動作が古い UID モジュールと一致していることを確認できます。

手動テスト

system/netd/にはいくつかの単体テストがあります ( netd_unit_testnetd_integration_test 、およびlibbpf_test )。ステータスを手動でチェックするための dumpsys サポートがあります。コマンドdumpsys netdは、 trafficControllerモジュールの基本ステータスと、eBPF が正しくオンになっているかどうかを示します。 eBPF がオンになっている場合、コマンドdumpsys netd trafficcontrollerは、タグ付きソケット情報、タグごとの統計、UID と iface、所有者 UID の一致など、各 eBPF マップの詳細な内容を表示します。

テスト場所

CTS テストは次の場所にあります。

VTS テストはhttps://android.googlesource.com/kernel/tests/+/master/net/test/bpf_test.pyにあります。

単体テストは次の場所にあります。