Инструмент 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.
Рисунок 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, драйверы или код ядра.
Требования
В конфигурации ядра должны быть включены следующие параметры:
CONFIG_CGROUP_BPF=yCONFIG_BPF=yCONFIG_BPF_SYSCALL=yCONFIG_NETFILTER_XT_MATCH_BPF=yCONFIG_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 находятся в следующих каталогах:
- https://android.googlesource.com/platform/cts/+/android17-release/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
- https://android.googlesource.com/platform/cts/+/android17-release/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
- https://android.googlesource.com/platform/system/netd/+/android17-release/tests/bpf_base_test.cpp
Тесты VTS находятся по адресу https://android.googlesource.com/kernel/tests/+/android17-release/net/test/bpf_test.py.
Модульные тесты находятся по следующему пути: