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 sempre estará 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 que foram enviados originalmente com a versão P PRECISAM usar a contabilidade 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 requer 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 entre o design do monitoramento de tráfego legados e o eBPF

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

O novo design do trafficController é baseado no filtro eBPF por cgroup, bem como no módulo xt_bpf netfilter dentro do kernel. Esses filtros eBPF são aplicados na tx/rx do pacote quando passam pelo filtro. O filtro eBPF cgroup está localizado na camada de transporte e é responsável por contar o tráfego com o 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 contar o tráfego na interface correta.

No momento da inicialização, o processo do espaço do usuário trafficController cria os mapas eBPF usados para a 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á uma única cgroup raiz para todo o tráfego. Portanto, todo o processo precisa ser incluído nessa cgroup por padrão.

No momento da execução, o trafficController pode marcar/remover a marcação de um soquete escrevendo no 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 com base no UID é uma substituição do módulo xt_owner no 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 legada do módulo xt_qtaguid. Portanto, TrafficController e NetworkStatsService serão executados com a implementação legada ou nova. Se o app usa APIs públicas, não haverá diferença se as ferramentas xt_qtaguid ou eBPF forem 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 as seguintes 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 do VTS é útil para verificar se a configuração correta está ativada.

Processo de descontinuação do xt_qtaguid legado

A nova ferramenta eBPF está substituindo o módulo xt_qtaguid e o módulo xt_owner em que ela 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 é 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 de rede do app. Apps com o nível 28 do SDK e mais recentes são bloqueados de acessar arquivos de processo 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á totalmente bloqueado, e 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 base do Android para essa versão do kernel para desativar explicitamente o módulo xt_qtaguid. O módulo xt_qtaguid será descontinuado completamente 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 que vêm com um kernel compatível com ferramentas eBPF, recomendamos atualizar para o novo recurso eBPF ao fazer upgrade para a versão do Android 9. Não há um teste CTS para aplicar essa atualização.

Validação

Você precisa usar patches regularmente de kernels comuns do Android e do Android AOSP principal. Verifique se a implementação passou nos testes de VTS e CTS aplicáveis, o netd_unit_test e o libbpf_test.

Teste

kernel net_tests para garantir que os recursos necessários estejam ativados e que os patches do kernel necessários sejam enviados de volta. 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 têm suporte na versão 9 do Android, não há um 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 superior a 4.9 que são enviados originalmente com a versão do Android 9 (ou seja, o primeiro nível da API >= 28), há testes do CTS na GSI para validar se o novo módulo está configurado corretamente. Testes antigos do CTS, 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 a dumpsys para verificar manualmente o status. 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 vai mostrar o conteúdo detalhado de cada mapa eBPF, incluindo informações de soquete marcadas, estatísticas por tag, UID e iface e correspondência de UID do proprietário.

Testar locais

Os testes do CTS estão localizados em:

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

Os testes de unidade estão localizados em: