Control de tráfico de eBPF

La herramienta de tráfico de red de eBPF usa una combinación de implementación de espacio del usuario y kernel para supervisar el uso de red en el dispositivo desde el último inicio del dispositivo. Proporciona funcionalidades adicionales, como etiquetado de socket, separación de tráfico en primer plano y en segundo plano, y firewall por UID para bloquear apps y que no accedan a la red según el estado del teléfono. Las estadísticas recopiladas de la herramienta se almacenan en una estructura de datos del kernel llamada eBPF maps, y el resultado es utilizado por servicios como NetworkStatsService para proporcionar estadísticas de tráfico persistentes desde el último inicio.

Ejemplos y fuente

Los cambios en el espacio de usuario se encuentran principalmente en los proyectos system/netd y framework/base. El desarrollo se realiza en AOSP, por lo que el código de AOSP siempre estará actualizado. La fuente se encuentra principalmente en system/netd/server/TrafficController*, system/netd/bpfloader y system/netd/libbpf/. Algunos cambios de framework necesarios también se encuentran en framework/base/ y system/core.

Implementación

A partir de Android 9, los dispositivos Android que se ejecutan en el kernel 4.9 o versiones posteriores y que originalmente se enviaron con la versión P DEBEN usar la contabilidad de supervisión de tráfico de red basada en eBPF en lugar de xt_qtaguid. La nueva infraestructura es más flexible y fácil de mantener, y no requiere código de kernel fuera del árbol.

En la Figura 1, se ilustran las principales diferencias de diseño entre la supervisión de tráfico heredado y la de eBPF.

Diferencias en el diseño de la supervisión de tráfico heredada y de eBPF

Figura 1: Diferencias de diseño entre el control de tráfico heredado (izquierda) y eBPF (derecha)

El nuevo diseño de trafficController se basa en un filtro de eBPF por cgroup y en el módulo netfilter xt_bpf dentro del kernel. Estos filtros de eBPF se aplican en la transmisión y recepción de paquetes cuando pasan por el filtro. El filtro eBPF cgroup se encuentra en la capa de transporte y es responsable de contar el tráfico en función del UID correcto según el UID del socket y la configuración del espacio de usuario. El netfilter xt_bpf está conectado a la cadena bw_raw_PREROUTING y bw_mangle_POSTROUTING, y es responsable de registrar el tráfico en la interfaz correcta.

En el momento del inicio, el proceso del espacio de usuario trafficController crea los mapas de eBPF que se usan para la recopilación de datos y fija todos los mapas como un archivo virtual en sys/fs/bpf. Luego, el proceso con privilegios bpfloader carga el programa eBPF precompilado en el kernel y lo adjunta al cgroup correcto. Existe una única raíz cgroup para todo el tráfico, por lo que todo el proceso debe incluirse en ese cgroup de forma predeterminada.

Durante el tiempo de ejecución, trafficController puede etiquetar o des etiquetar un socket escribiendo en traffic_cookie_tag_map y traffic_uid_counterSet_map. NetworkStatsService puede leer los datos de estadísticas de tráfico de traffic_tag_stats_map, traffic_uid_stats_map y traffic_iface_stats_map. Además de la función de recopilación de estadísticas de tráfico, el filtro eBPF trafficController y cgroup también es responsable de bloquear el tráfico de ciertos UID según la configuración del teléfono. La función de bloqueo de tráfico de red basada en UID es un reemplazo del módulo xt_owner dentro del kernel, y el modo de detalles se puede configurar escribiendo en traffic_powersave_uid_map, traffic_standby_uid_map y traffic_dozable_uid_map.

La nueva implementación sigue la implementación del módulo xt_qtaguid heredado, por lo que TrafficController y NetworkStatsService se ejecutarán con la implementación heredada o la nueva. Si la app usa APIs públicas, no debería experimentar ninguna diferencia si se usan herramientas de xt_qtaguid o eBPF en segundo plano.

Si el kernel del dispositivo se basa en el kernel común de Android 4.9 (SHA39c856663dcc81739e52b02b77d6af259eb838f6 o versiones posteriores), no se requieren modificaciones en las HAL, los controladores ni el código del kernel para implementar la nueva herramienta eBPF.

Requisitos

  1. La configuración del kernel DEBE tener activadas las siguientes opciones:

    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

    La prueba de configuración del kernel de VTS es útil para verificar que se haya activado la configuración correcta.

Proceso de baja del atributo heredado xt_qtaguid

La nueva herramienta eBPF reemplazará los módulos xt_qtaguid y xt_owner en los que se basa. Comenzaremos a quitar el módulo xt_qtaguid del kernel de Android y a inhabilitar sus parámetros de configuración innecesarios.

En la versión de Android 9, el módulo xt_qtaguid se activa en todos los dispositivos, pero todas las APIs públicas que leen directamente el archivo proc del módulo xt_qtaguid se mueven al servicio NetworkManagement. Según la versión del kernel del dispositivo y el primer nivel de API, el servicio NetworkManagement sabe si las herramientas de eBPF están activadas y elige el módulo correcto para obtener cada estadística de uso de red de la app. Sepolicy bloquea el acceso de las apps con el nivel de SDK 28 y versiones posteriores a los archivos proc de xt_qtaguid.

En la próxima versión de Android después de la 9, el acceso de las apps a esos archivos de proc xt_qtaguid se bloqueará por completo. Comenzaremos a quitar el módulo xt_qtaguid de los nuevos kernels comunes de Android. Después de quitarlo, actualizaremos la configuración base de Android para esa versión del kernel para desactivar el módulo xt_qtaguid de forma explícita. El módulo xt_qtaguid dejará de estar disponible por completo cuando el requisito de versión mínima del kernel para una versión de Android sea 4.9 o superior.

En la versión de Android 9, solo los dispositivos que se inician con la versión de Android 9 deben tener la nueva función de eBPF. En el caso de los dispositivos que se enviaron con un kernel que puede admitir herramientas de eBPF, te recomendamos que lo actualices a la nueva función de eBPF cuando realices la actualización a la versión de Android 9. No hay una prueba de CTS para aplicar esa actualización.

Validación

Debes tomar parches de los kernels comunes de Android y de la versión principal de AOSP de Android con regularidad. Asegúrate de que tu implementación pase las pruebas de VTS y CTS correspondientes, netd_unit_test y libbpf_test.

Prueba

Hay net_tests del kernel para garantizar que tengas las funciones requeridas activadas y los parches del kernel necesarios con portabilidad a versiones anteriores. Las pruebas se integran como parte de las pruebas de VTS de la versión de Android 9. Hay algunas pruebas de unidades en system/netd/ (netd_unit_test y libbpf_test). Hay algunas pruebas en netd_integration_test para validar el comportamiento general de la nueva herramienta.

CTS y verificador de CTS

Como ambos módulos de supervisión de tráfico son compatibles con la versión de Android 9, no hay una prueba de CTS para forzar la implementación del módulo nuevo en todos los dispositivos. Sin embargo, en el caso de los dispositivos con una versión de kernel superior a 4.9 que se envían originalmente con la versión de Android 9 (es decir, el primer nivel de API >= 28), hay pruebas de CTS en GSI para validar que el nuevo módulo esté configurado correctamente. Las pruebas de CTS anteriores, como TrafficStatsTest, NetworkUsageStatsTest y CtsNativeNetTestCases, se pueden usar para verificar que el comportamiento sea coherente con el módulo de UID anterior.

Pruebas manuales

Hay algunas pruebas de unidades en system/netd/ (netd_unit_test, netd_integration_test y libbpf_test). Hay compatibilidad con dumpsys para verificar el estado de forma manual. El comando dumpsys netd muestra el estado básico del módulo trafficController y si eBPF se activó correctamente. Si eBPF está activado, el comando dumpsys netd trafficcontroller muestra el contenido detallado de cada mapa de eBPF, incluida la información de los sockets etiquetados, las estadísticas por etiqueta, el UID y la interfaz, y la coincidencia del UID del propietario.

Ubicaciones de prueba

Las pruebas de CTS se encuentran en los siguientes lugares:

Las pruebas de VTS se encuentran en https://android.googlesource.com/kernel/tests/+/main/net/test/bpf_test.py.

Las pruebas de unidades se encuentran en: