--- title: "Introducción a eBPF en Ubuntu 24.04: bpftrace, BCC y XDP" description: "Descubre qué es eBPF y úsalo en Ubuntu 24.04: traza procesos y syscalls con bpftrace y BCC, inspecciona programas con bpftool y filtra paquetes ICMP con XDP." category: "Temas Avanzados" language: es source: https://cubepath.com/es/docs/temas-avanzados/ebpf-introduccion-y-casos-de-uso updated: 2026-09-25 --- # Introducción a eBPF en Ubuntu 24.04: bpftrace, BCC y XDP eBPF permite ejecutar pequeños programas dentro del kernel de Linux sin modificar su código ni cargar módulos. El kernel verifica cada programa antes de cargarlo (que termine, que no acceda a memoria no válida) y lo compila a código nativo, así que es seguro y muy rápido. Herramientas como Cilium, Falco, Pixie o las de observabilidad de Brendan Gregg están construidas sobre eBPF. En este tutorial usarás eBPF en Ubuntu 24.04 de tres formas: trazando el sistema con bpftrace, con las herramientas ya hechas de BCC y escribiendo y cargando tu propio programa XDP que filtra paquetes. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. Su kernel 6.8 incluye todo lo necesario, incluida la información de tipos BTF. - Un usuario no root con privilegios `sudo`. Cargar programas eBPF requiere privilegios de root. - Conocimientos básicos de C para la parte de XDP. ## Tipos de programas eBPF Un programa eBPF se engancha a un evento del kernel y se ejecuta cada vez que ocurre. Los tipos más usados son: | Punto de enganche | Qué intercepta | Uso típico | |---|---|---| | `tracepoint` | Puntos estables definidos por el kernel (syscalls, planificador, red) | Trazado y métricas | | `kprobe` / `kretprobe` | Entrada o salida de casi cualquier función del kernel | Depuración profunda | | `uprobe` | Funciones de programas de usuario | Perfilado de aplicaciones | | XDP | Paquetes recibidos, antes de que el kernel los procese | Firewall, balanceo, mitigación DDoS | | `tc` | Paquetes en la capa de control de tráfico, entrada y salida | Políticas de red de contenedores | Los programas guardan y comparten datos mediante **mapas** (tablas hash, arrays, buffers circulares) que también se pueden leer desde el espacio de usuario. ## Paso 1: Instalar las herramientas Instala bpftrace, las herramientas de BCC, las cabeceras del kernel que usa BCC y bpftool, que en Ubuntu se distribuye dentro de los paquetes `linux-tools`: ```bash sudo apt update sudo apt install bpftrace bpfcc-tools linux-headers-$(uname -r) linux-tools-common linux-tools-$(uname -r) ``` Instala también el compilador y las cabeceras de libbpf, que usarás en la parte de XDP: ```bash sudo apt install clang llvm libbpf-dev linux-libc-dev ``` Comprueba que las herramientas responden: ```bash bpftrace --version sudo bpftool version ``` ```output bpftrace v0.20.2 bpftool v7.4.0 using libbpf v1.4 features: llvm, skeletons ``` Las versiones exactas pueden variar según las actualizaciones de Ubuntu. ## Paso 2: Trazar el sistema con bpftrace bpftrace es un lenguaje de alto nivel para escribir programas eBPF de una línea, similar a awk. Primero lista los tracepoints disponibles, por ejemplo los de la llamada al sistema `execve`: ```bash sudo bpftrace -l 'tracepoint:syscalls:sys_enter_exec*' ``` ```output tracepoint:syscalls:sys_enter_execve tracepoint:syscalls:sys_enter_execveat ``` Muestra en tiempo real cada programa que se ejecuta en el servidor y qué proceso lo lanza: ```bash sudo bpftrace -e 'tracepoint:syscalls:sys_enter_execve { printf("%-6d %-16s %s\n", pid, comm, str(args->filename)); }' ``` Abre otra sesión SSH y ejecuta cualquier comando, por ejemplo `ls`. En la primera aparecerá: ```output Attaching 1 probe... 48213 bash /usr/bin/ls ``` Pulsa `Ctrl+C` para salir. Ese programa se ha cargado en el kernel, ha funcionado y se ha descargado sin dejar rastro. Los mapas de bpftrace (variables que empiezan por `@`) agregan datos dentro del kernel y los muestran al salir. Cuenta las llamadas al sistema por proceso durante unos segundos: ```bash sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }' ``` ```output Attaching 1 probe... ^C @[systemd-journal]: 112 @[sshd]: 845 @[bpftrace]: 1320 ``` Y dibuja un histograma del tamaño de las lecturas que realizan los procesos: ```bash sudo bpftrace -e 'tracepoint:syscalls:sys_exit_read /args->ret > 0/ { @bytes = hist(args->ret); }' ``` ```output @bytes: [1] 24 |@@@@ | [2, 4) 3 | | [4, 8) 41 |@@@@@@@ | [8, 16) 288 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| ... ``` El filtro `/args->ret > 0/` solo cuenta las lecturas que devolvieron datos. Agregar en el kernel es lo que hace a eBPF tan eficiente: solo el resultado final cruza al espacio de usuario, no cada evento. ## Paso 3: Usar las herramientas de BCC BCC incluye decenas de herramientas listas para diagnosticar problemas de rendimiento. En Ubuntu se instalan con el sufijo `-bpfcc`. Estas son las más útiles en un servidor: | Herramienta | Qué muestra | |---|---| | `execsnoop-bpfcc` | Procesos nuevos, incluidos los de vida muy corta | | `opensnoop-bpfcc` | Archivos que abre cada proceso | | `tcpconnect-bpfcc` | Conexiones TCP salientes | | `tcplife-bpfcc` | Conexiones TCP cerradas con su duración y bytes | | `biolatency-bpfcc` | Histograma de latencia de disco | | `runqlat-bpfcc` | Tiempo que los procesos esperan a tener CPU | Por ejemplo, para ver qué conexiones salientes abre el servidor: ```bash sudo tcpconnect-bpfcc ``` Desde otra sesión, ejecuta `curl -s https://www.kernel.org > /dev/null` y verás la conexión: ```output Tracing connect ... Hit Ctrl-C to end PID COMM IP SADDR DADDR DPORT 51234 curl 4 203.0.113.10 139.178.84.217 443 ``` Para medir la latencia del disco durante 10 segundos y mostrar un histograma: ```bash sudo biolatency-bpfcc 10 1 ``` ```output Tracing block device I/O... Hit Ctrl-C to end. usecs : count distribution 64 -> 127 : 12 |***** | 128 -> 255 : 87 |****************************************| 256 -> 511 : 35 |**************** | ``` Si la mayoría de operaciones caen en milisegundos en lugar de microsegundos, el disco es un cuello de botella. Cada herramienta tiene su página de manual (`man tcpconnect-bpfcc`) con ejemplos. ## Paso 4: Inspeccionar programas y mapas con bpftool `bpftool` muestra todos los programas eBPF cargados en el sistema, incluidos los de systemd, Docker o Cilium. Deja un one-liner de bpftrace corriendo en otra sesión y lista los programas: ```bash sudo bpftool prog list ``` ```output ... 312: tracepoint name sys_enter_execve tag 7c2d8b9a1e4f5d60 gpl loaded_at 2026-09-25T10:15:03+0000 uid 0 xlated 312B jited 190B memlock 4096B map_ids 45 ``` Cada programa tiene un identificador, un tipo, el tamaño del bytecode traducido (`xlated`) y del código nativo (`jited`), y los mapas que usa. Para ver los mapas: ```bash sudo bpftool map list ``` Y para ver las instrucciones de un programa concreto, usa su identificador: ```bash sudo bpftool prog dump xlated id 312 ``` ## Paso 5: Escribir un programa XDP que descarta ICMP XDP ejecuta el programa en cuanto la tarjeta de red recibe un paquete, antes de que el kernel reserve memoria para él. Por eso se usa para mitigar ataques DDoS y para balanceadores de carga. Aquí escribirás un programa que descarta todos los paquetes ICMP (ping) y deja pasar el resto. Para no arriesgarte a perder el acceso SSH, lo probarás en una interfaz virtual conectada a un network namespace. Crea el entorno de pruebas: ```bash sudo ip netns add xdptest sudo ip link add veth-host type veth peer name veth-ns netns xdptest sudo ip addr add 10.77.0.1/24 dev veth-host sudo ip link set veth-host up sudo ip -n xdptest addr add 10.77.0.2/24 dev veth-ns sudo ip -n xdptest link set veth-ns up ``` Comprueba que el ping funciona antes de cargar nada: ```bash sudo ip netns exec xdptest ping -c 2 10.77.0.1 ``` ```output 2 packets transmitted, 2 received, 0% packet loss, time 1002ms ``` Crea un directorio de trabajo y el código fuente: ```bash mkdir -p ~/xdp && cd ~/xdp nano xdp_drop_icmp.c ``` ```c #include #include #include #include #include #include SEC("xdp") int xdp_drop_icmp(struct xdp_md *ctx) { void *data = (void *)(long)ctx->data; void *data_end = (void *)(long)ctx->data_end; struct ethhdr *eth = data; if ((void *)(eth + 1) > data_end) return XDP_PASS; if (eth->h_proto != bpf_htons(ETH_P_IP)) return XDP_PASS; struct iphdr *ip = (void *)(eth + 1); if ((void *)(ip + 1) > data_end) return XDP_PASS; if (ip->protocol == IPPROTO_ICMP) return XDP_DROP; return XDP_PASS; } char LICENSE[] SEC("license") = "GPL"; ``` Cada acceso a una cabecera va precedido de una comprobación contra `data_end`. No es opcional: el verificador del kernel rechaza cualquier programa que pueda leer fuera del paquete. `XDP_DROP` descarta el paquete y `XDP_PASS` lo entrega al kernel con normalidad. Compila el programa a bytecode eBPF. La opción `-I` añade el directorio de cabeceras específicas de la arquitectura, que clang no busca por su cuenta cuando el destino es `bpf`: ```bash clang -O2 -g -target bpf -I/usr/include/$(uname -m)-linux-gnu -c xdp_drop_icmp.c -o xdp_drop_icmp.o ``` Comprueba que el objeto contiene la sección `xdp`: ```bash llvm-objdump -h xdp_drop_icmp.o | grep xdp ``` ```output 2 xdp 00000060 0000000000000000 TEXT ``` ## Paso 6: Cargar y probar el programa XDP Carga el programa en `veth-host` con `ip`. El modo `xdpgeneric` funciona con cualquier interfaz, aunque su controlador no soporte XDP nativo: ```bash sudo ip link set dev veth-host xdpgeneric obj xdp_drop_icmp.o sec xdp ``` Comprueba que está enganchado: ```bash ip link show dev veth-host ``` ```output 5: veth-host@if2: mtu 1500 xdpgeneric qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 7a:3e:91:0c:5d:21 brd ff:ff:ff:ff:ff:ff link-netns xdptest prog/xdp id 327 name xdp_drop_icmp tag 5b1e7c9d3a2f8e41 jited ``` Repite el ping desde el namespace. Los paquetes ICMP que llegan a `veth-host` se descartan: ```bash sudo ip netns exec xdptest ping -c 3 -W 1 10.77.0.1 ``` ```output 3 packets transmitted, 0 received, 100% packet loss, time 2046ms ``` El programa también aparece en `sudo bpftool prog list` con el tipo `xdp`, y `sudo bpftool net list` muestra en qué interfaz está enganchado. Descarga el programa y comprueba que el ping vuelve a funcionar: ```bash sudo ip link set dev veth-host xdpgeneric off sudo ip netns exec xdptest ping -c 2 10.77.0.1 ``` ```output 2 packets transmitted, 2 received, 0% packet loss, time 1001ms ``` Cuando termines, borra el entorno de pruebas: ```bash sudo ip netns delete xdptest ``` > Advertencia: Si cargas un programa XDP en la interfaz pública del servidor, un error en su lógica puede descartar también el tráfico SSH. Prueba siempre en una interfaz virtual primero y ten a mano la consola del servidor. ## Solución de problemas **`fatal error: 'asm/types.h' file not found` al compilar**: falta la ruta de cabeceras de la arquitectura. Añade `-I/usr/include/$(uname -m)-linux-gnu` al comando de `clang` y comprueba que `linux-libc-dev` está instalado. **El verificador rechaza el programa (`invalid access to packet`)**: algún acceso a una cabecera no está protegido por una comprobación contra `data_end`. Añade `verbose` al final del comando `ip link set ... sec xdp` para ver el registro completo del verificador, que indica la instrucción que falla. **`ERROR: Could not resolve symbol` o `failed to compile` en herramientas BCC**: BCC compila sus programas al vuelo con las cabeceras del kernel en ejecución. Instala `linux-headers-$(uname -r)`; si acabas de actualizar el kernel, reinicia antes para que coincidan. **`bpftool: command not found` o `WARNING: bpftool not found for kernel`**: falta el paquete `linux-tools` de tu versión exacta del kernel. Instala `linux-tools-$(uname -r)`. **`Operation not permitted` al ejecutar cualquier herramienta**: Ubuntu no permite cargar programas eBPF a usuarios sin privilegios (`kernel.unprivileged_bpf_disabled`). Ejecuta las herramientas con `sudo`. ## Conclusión Has trazado procesos y llamadas al sistema con bpftrace, diagnosticado red y disco con las herramientas de BCC, inspeccionado programas cargados con bpftool y escrito, compilado y cargado un filtro XDP propio. Con esto tienes la base para entender herramientas construidas sobre eBPF. Como siguientes pasos puedes: - Ampliar el programa XDP con un mapa hash de direcciones IP bloqueadas que puedas actualizar con `bpftool map update`. - Explorar el resto de herramientas de BCC (`ls /usr/sbin/*-bpfcc`) y los scripts de ejemplo del repositorio de bpftrace. - Probar Cilium como plugin de red en un clúster de Kubernetes para ver eBPF aplicado a redes de contenedores.