Мониторинг трафика 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, устройства Android с ядром 4.9 или более поздней версии, изначально выпущенные с версией P, должны использовать учет сетевого трафика на основе eBPF вместо xt_qtaguid. Новая инфраструктура более гибкая и удобная в обслуживании, а также не требует кода ядра вне дерева.

Основные различия в архитектуре между устаревшим и eBPF-мониторингом трафика показаны на рисунке 1.

Различия в архитектуре устаревшего мониторинга трафика и мониторинга на основе eBPF

Рисунок 1. Различия в дизайне устаревшего (слева) и eBPF (справа) мониторинга трафика

Новый дизайн trafficController основан на фильтре eBPF для каждого cgroup, а также на модуле netfilter xt_bpf внутри ядра. Эти фильтры eBPF применяются к пакетам при передаче и получении, когда они проходят через фильтр. Фильтр eBPF cgroup находится на транспортном уровне и отвечает за подсчет трафика для правильного UID в зависимости от UID сокета и настроек пользовательского пространства. Сетевой фильтр xt_bpf подключен к цепочкам 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_map, traffic_uid_stats_map и traffic_iface_stats_map. Помимо сбора статистики трафика, фильтры eBPF trafficController и cgroup также отвечают за блокировку трафика от определенных UID в зависимости от настроек телефона. Функция блокировки сетевого трафика на основе UID заменяет модуль xt_owner в ядре. Подробный режим можно настроить, записав данные в файлы traffic_powersave_uid_map, traffic_standby_uid_map и traffic_dozable_uid_map.

Новая реализация следует принципам работы устаревшего модуля xt_qtaguid, поэтому функции TrafficController и NetworkStatsService будут работать как с устаревшей, так и с новой реализацией. Если приложение использует общедоступные 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.

Процесс прекращения поддержки устаревшего тега xt_qtaguid

Новый инструмент eBPF заменяет модуль xt_qtaguid и модуль xt_owner, на котором он основан. Мы начнем удалять модуль xt_qtaguid из ядра Android и отключать его ненужные конфигурации.

В Android 9 модуль xt_qtaguid включен на всех устройствах, но все общедоступные API, которые напрямую считывают файл proc модуля xt_qtaguid, перенесены в сервис NetworkManagement. В зависимости от версии ядра устройства и первого уровня API сервис NetworkManagement определяет, включены ли инструменты eBPF, и выбирает подходящий модуль для получения статистики использования сети каждым приложением. Приложения с уровнем SDK 28 и выше не могут получить доступ к файлам xt_qtaguid proc из-за sepolicy.

В следующей версии Android после 9 доступ приложений к этим файлам xt_qtaguid proc будет полностью заблокирован, и мы начнем удалять модуль xt_qtaguid из новых общих ядер Android. После этого мы обновим базовую конфигурацию Android для этой версии ядра, чтобы явно отключить модуль xt_qtaguid. Модуль xt_qtaguid будет полностью удален, когда минимальная версия ядра для выпуска Android станет 4.9 или выше.

В Android 9 новая функция eBPF обязательна только для устройств, которые выпускаются с этой версией ОС. Если на устройстве установлена версия ядра, поддерживающая инструменты eBPF, мы рекомендуем обновить ее до новой версии eBPF при переходе на Android 9. В CTS нет теста, который бы обеспечивал это обновление.

Проверка

Рекомендуем регулярно устанавливать исправления из общих ядер Android и основной ветки Android AOSP. Убедитесь, что ваша реализация прошла применимые тесты VTS и CTS, netd_unit_test и libbpf_test.

Тестирование

Существуют тесты ядра net_tests, которые позволяют убедиться, что необходимые функции включены и нужные исправления ядра перенесены в более раннюю версию. Тесты интегрированы в VTS-тесты Android 9. В system/netd/ есть несколько модульных тестов (netd_unit_test и libbpf_test). В netd_integration_test есть тесты, которые проверяют общее поведение нового инструмента.

CTS и CTS Verifier

Поскольку в Android 9 поддерживаются оба модуля мониторинга трафика, CTS-тест, который бы требовал внедрения нового модуля на всех устройствах, отсутствует. Однако для устройств с версией ядра выше 4.9, которые изначально поставляются с Android 9 (т.е. первый уровень API >= 28), в GSI есть тесты CTS, позволяющие проверить, правильно ли настроен новый модуль. Чтобы проверить, соответствует ли поведение старому модулю UID, можно использовать старые тесты CTS, например TrafficStatsTest, NetworkUsageStatsTest и CtsNativeNetTestCases.

Ручное тестирование

В system/netd/ есть несколько модульных тестов (netd_unit_test, netd_integration_test и libbpf_test). Для проверки статуса вручную поддерживается команда dumpsys. Команда dumpsys netd показывает базовый статус модуля trafficController и то, правильно ли включен eBPF. Если eBPF включен, команда dumpsys netd trafficcontroller показывает подробное содержимое каждой карты eBPF, включая информацию о помеченных сокетах, статистику по тегам, UID и интерфейсу, а также совпадение UID владельца.

Тестовые местоположения

Тесты CTS находятся в следующих каталогах:

Тесты VTS находятся по адресу https://android.googlesource.com/kernel/tests/+/android17-release/net/test/bpf_test.py.

Модульные тесты находятся по следующему пути: