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 de 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 fonte 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 versões mais recentes e foram originalmente enviados com a versão P PRECISAM usar a contabilização do 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, além de não exigir 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 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 transmissão/recepção de pacotes quando eles passam pelo filtro. O filtro cgroup eBPF está localizado na camada de transporte e é responsável por contar 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 às cadeias bw_raw_PREROUTING e bw_mangle_POSTROUTING e é responsável por contar o tráfego na interface correta.

Na inicialização, o processo do 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. Portanto, todo o processo precisa ser incluído nesse cgroup por padrão.

No tempo de execução, o trafficController pode adicionar/remover uma tag de um soquete gravando no traffic_cookie_tag_map e no 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 trafficController e cgroup eBPF também é responsável 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 substitui o módulo xt_owner no kernel, e o modo detalhado 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. Assim, TrafficController e NetworkStatsService serão executados com a implementação legada ou nova. Se o app usar 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), não será necessário fazer modificações em HALs, drivers ou código do kernel para implementar a nova ferramenta eBPF.

Requisitos

  1. A configuração do kernel PRECISA ter estas opçõ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 removendo o módulo xt_qtaguid do kernel do Android e desativando as configurações desnecessárias.

No lançamento 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 receber cada estatística de uso da rede do app. Os apps com nível 28 do SDK e mais recentes não podem acessar arquivos proc xt_qtaguid pela 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 da remoção, vamos atualizar a configuração básica do Android para essa versão do kernel e desativar explicitamente o módulo xt_qtaguid. O módulo xt_qtaguid será totalmente descontinuado quando o requisito mínimo de versão do kernel para um lançamento do Android for 4.9 ou superior.

No Android 9, apenas os dispositivos lançados com essa versão precisam ter o novo recurso eBPF. Para dispositivos enviados com um kernel que pode oferecer suporte a ferramentas eBPF, recomendamos atualizar para o novo recurso eBPF ao fazer upgrade para o Android 9. Não há teste do CTS para forçar essa atualização.

Validação

Você precisa receber patches regularmente dos kernels comuns do Android e da ramificação principal do AOSP do Android. Verifique se a implementação passa nos testes aplicáveis de VTS e CTS, no netd_unit_test e no libbpf_test.

Teste

kernel net_tests para garantir que os recursos necessários estejam ativados e que os patches de kernel necessários tenham sido portados para versões anteriores. 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á um teste do 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 foram lançados originalmente com o 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 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 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, além de correspondência de UID do proprietário.

Locais de teste

Os testes do CTS estão localizados em:

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

Os testes de unidade estão localizados em: