Monitoramento de tráfego eBPF

A ferramenta de tráfego de rede eBPF usa uma combinação de kernel e implementação de espaço do usuário para monitorar o uso da rede no dispositivo desde a última inicialização do aparelho. Ela oferece outras funcionalidades, como inclusão de tag em soquetes, separação de tráfego em primeiro e segundo plano e firewall por UID para impedir que apps acessem a rede, dependendo do estado do smartphone. As estatísticas coletadas pela ferramenta são armazenadas em uma estrutura de dados do kernel chamada eBPF maps, e o resultado é usado por serviços como NetworkStatsService para fornecer estatísticas de tráfego persistentes desde a última inicialização.

Exemplos e origem

As mudanças no espaço do usuário estão principalmente nos projetos system/netd e framework/base. O desenvolvimento está sendo feito no AOSP, então o código do AOSP estará sempre atualizado. A origem está localizada principalmente em system/netd/server/TrafficController*, system/netd/bpfloader, e system/netd/libbpf/. Algumas mudanças necessárias no framework também estão em framework/base/ e system/core.

Implementação

A partir do Android 9, os dispositivos Android que executam o kernel 4.9 ou mais recente e foram enviados originalmente com a versão P precisam usar a contabilização de monitoramento de tráfego de rede baseada em eBPF em vez de xt_qtaguid. A nova infraestrutura é mais flexível e fácil de manter e não exige nenhum código de kernel fora da árvore.

As principais diferenças de design entre o monitoramento de tráfego legado e o eBPF são ilustradas na Figura 1.

Diferenças de design entre o monitoramento de tráfego legado e o eBPF

Figura 1. Diferenças de design de monitoramento de tráfego legado (à esquerda) e eBPF (à direita)

O novo design trafficController é baseado no filtro eBPF por cgroup, bem como no módulo de netfilter xt_bpf dentro do kernel. Esses filtros eBPF são aplicados no tx/rx de pacotes quando eles passam pelo filtro. O filtro eBPF cgroup está localizado na camada de transporte e é responsável por contabilizar o tráfego em relação ao UID correto, dependendo do UID do soquete e da configuração do espaço do usuário. O netfilter xt_bpf é conectado à cadeia bw_raw_PREROUTING e bw_mangle_POSTROUTING e é responsável por contabilizar o tráfego na interface correta.

No momento da inicialização, o processo de espaço do usuário trafficController cria os mapas eBPF usados para coleta de dados e fixa todos os mapas como um arquivo virtual em sys/fs/bpf. Em seguida, o processo privilegiado bpfloader carrega o programa eBPF pré-compilado no kernel e o anexa ao cgroup correto. Há um único cgroup raiz para todo o tráfego, então todos os processos precisam ser incluídos nesse cgroup por padrão.

No momento da execução, o trafficController pode marcar/desmarcar um soquete gravando em traffic_cookie_tag_map e traffic_uid_counterSet_map. O NetworkStatsService pode ler os dados de estatísticas de tráfego de traffic_tag_stats_map, traffic_uid_stats_map e traffic_iface_stats_map. Além da função de coleta de estatísticas de tráfego, o filtro eBPF trafficController e cgroup também são responsáveis por bloquear o tráfego de determinados UIDs, dependendo das configurações do smartphone. O recurso de bloqueio de tráfego de rede baseado em UID é uma substituição do módulo xt_owner dentro do kernel, e o modo de detalhes pode ser configurado gravando em traffic_powersave_uid_map, traffic_standby_uid_map e traffic_dozable_uid_map.

A nova implementação segue a implementação do módulo xt_qtaguid legado, então TrafficController e NetworkStatsService serão executados com a implementação legada ou nova. Se o app usar APIs públicas, ele não vai apresentar nenhuma diferença, seja xt_qtaguid ou ferramentas eBPF usadas em segundo plano.

Se o kernel do dispositivo for baseado no kernel comum do Android 4.9 (SHA 39c856663dcc81739e52b02b77d6af259eb838f6 ou mais recente), nenhuma modificação em HALs, drivers ou código do kernel será necessária para implementar a nova ferramenta eBPF.

Requisitos

  1. A configuração do kernel precisa ter estas configurações ativadas:

    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

    O teste de configuração do kernel VTS é útil ao verificar se a configuração correta está ativada.

Processo de suspensão de uso do xt_qtaguid legado

A nova ferramenta eBPF está substituindo o módulo xt_qtaguid e o módulo xt_owner em que ele se baseia. Vamos começar a remover o módulo xt_qtaguid do kernel do Android e desativar as configurações desnecessárias.

Na versão do Android 9, o módulo xt_qtaguid está ativado em todos os dispositivos, mas todas as APIs públicas que leem diretamente o arquivo proc do módulo xt_qtaguid são movidas para o serviço NetworkManagement. Dependendo da versão do kernel do dispositivo e do primeiro nível da API, o serviço NetworkManagement sabe se as ferramentas eBPF estão ativadas e escolhe o módulo certo para cada estatística de uso da rede do app. Os apps com o nível 28 do SDK e mais recentes são impedidos de acessar arquivos proc xt_qtaguid por sepolicy.

Na próxima versão do Android após a 9, o acesso do app a esses arquivos proc xt_qtaguid será completamente bloqueado. Vamos começar a remover o módulo xt_qtaguid dos novos kernels comuns do Android. Depois que ele for removido, vamos atualizar a configuração de base do Android para essa versão do kernel para desativar explicitamente o módulo xt_qtaguid. O módulo xt_qtaguid será totalmente suspenso quando o requisito mínimo de versão do kernel para uma versão do Android for 4.9 ou mais recente.

Na versão do Android 9, apenas os dispositivos lançados com a versão do Android 9 precisam ter o novo recurso eBPF. Para dispositivos enviados com um kernel que possa oferecer suporte a ferramentas eBPF, recomendamos atualizá-lo para o novo recurso eBPF ao fazer upgrade para a versão do Android 9. Não há teste CTS para aplicar essa atualização.

Validação

É necessário receber patches regularmente dos kernels comuns do Android e do Android AOSP main. Verifique se a implementação passa nos testes VTS e CTS aplicáveis, no netd_unit_test e no libbpf_test.

Teste

net_tests do kernel para garantir que você tenha os recursos necessários ativados e os patches de kernel necessários portados. Os testes são integrados como parte dos testes VTS da versão do Android 9. Há alguns testes de unidade em system/netd/ (netd_unit_test e libbpf_test). Há alguns testes em netd_integration_test para validar o comportamento geral da nova ferramenta.

CTS e verificador do CTS

Como os dois módulos de monitoramento de tráfego são compatíveis com a versão do Android 9, não há teste CTS para forçar a implementação do novo módulo em todos os dispositivos. No entanto, para dispositivos com versão do kernel mais recente que 4.9 que foram enviados originalmente com a versão do Android 9 (ou seja, o primeiro nível da API >= 28), há testes CTS na GSI para validar se o novo módulo está configurado corretamente. Testes CTS antigos, como TrafficStatsTest, NetworkUsageStatsTest e CtsNativeNetTestCases, podem ser usados para verificar se o comportamento é consistente com o módulo UID antigo.

Teste manual

Há alguns testes de unidade em system/netd/ (netd_unit_test, netd_integration_test e libbpf_test). Há suporte para dumpsys para verificar o status manualmente. O comando dumpsys netd mostra o status básico do módulo trafficController e se o eBPF está ativado corretamente. Se o eBPF estiver ativado, o comando dumpsys netd trafficcontroller mostrará o conteúdo detalhado de cada mapa eBPF, incluindo informações de soquete marcado, estatísticas por tag, UID e iface e correspondência de UID do proprietário.

Locais de teste

Os testes CTS estão localizados em:

Os testes VTS estão localizados em https://android.googlesource.com/kernel/tests/+/android17-release/net/test/bpf_test.py.

Os testes de unidade estão localizados em: