Actualizaste a Ubuntu 24.04, la tarjeta de red parece sana, la CPU está ociosa y, sin embargo, la aplicación va lenta: picos de latencia raros, conexiones inestables, capturas de paquetes que mienten o replicación de almacenamiento que de repente “necesita más ancho de banda” mientras usa menos. Alguien dice “apaga los offloads”. Otro dice “nunca toques los offloads”. Ambos tienen razón a medias, y eso es lo más peligroso.
Esta es la guía de campo para probar cuándo GRO/LRO/TSO (y amigos) son el problema, cómo desactivarlos sin empeorar la situación y cómo hacerlo de modo que puedas revertir a las 3 a.m. con la dignidad intacta.
Qué hacen realmente GRO/LRO/TSO (y por qué rompen cosas)
Los offloads de NIC son una ganga: mover trabajo por paquete desde la CPU a la NIC te da mayor rendimiento y menor uso de CPU. La factura llega cuando el “paquete” que el SO cree que vio no es lo que realmente cruzó el cable, o cuando alguna capa intermedia asume que está viendo segmentos de tamaño normal pero en realidad ve un monstruo coalescido.
GRO: Generic Receive Offload
GRO es una característica de software de Linux que fusiona varios paquetes entrantes en un “super-paquete” más grande antes de pasarlo a la pila. Reduce el procesamiento por paquete y las interrupciones. Genial para rendimiento. Malo cuando necesitas temporización precisa por paquete, cuando tus herramientas de captura esperan que el mundo se parezca a la realidad, o cuando un bug en el driver/kernel maneja mal los límites de segmentación.
GRO no es una característica del cable. Es una optimización local. El cable sigue transportando tramas con MTU normal. Tu host puede mostrar paquetes y contadores más grandes y en menor número porque la pila los fusionó.
LRO: Large Receive Offload
LRO suele ser coalescencia de recepción en la NIC/driver. Puede ser aún más agresivo que GRO. También es más problemático en presencia de enrutamiento, túneles, VLANs y cualquier cosa que espere límites estrictos de paquete. Muchos entornos simplemente mantienen LRO apagado, especialmente en redes virtualizadas o con muchas overlays.
TSO/GSO: segmentación en transmisión (hardware o software)
TSO (TCP Segmentation Offload) permite al kernel entregar una gran carga TCP a la NIC y que la NIC la corte en segmentos del tamaño MSS y calcule checksums. GSO (Generic Segmentation Offload) es el equivalente en software para protocolos que la NIC no conoce. Esto suele ser seguro y beneficioso—hasta que no lo es: bugs de driver, fallos en checksums, interacciones extrañas con túneles, o equipos en el camino que se comportan mal bajo ciertos patrones de ráfaga/segmento.
Offloads de checksum: el travieso sutil
El offload de checksum Rx/Tx significa que las checksums pueden ser calculadas/validadas por el hardware de la NIC. Las capturas de paquetes tomadas en el host pueden mostrar “checksum malo” porque la checksum aún no se había rellenado en el punto de captura. Eso no es necesariamente una red rota; es una suposición rota.
Una idea parafraseada de John Allspaw (operaciones/confiabilidad): “Los incidentes ocurren cuando la realidad diverge de nuestro modelo mental.” Los offloads son una máquina para fabricar esa divergencia.
Broma #1: Los offloads son como contratar becarios para hacer tu papeleo—rápidos y baratos hasta que “optimizan” tu sistema de archivos en arte moderno.
Hechos e historia: por qué esto sigue ocurriendo
- Hecho 1: LRO antecede a GRO y se deshabilitó ampliamente en escenarios de enrutamiento/túneles porque puede fusionar paquetes de maneras que rompen las suposiciones de reenvío.
- Hecho 2: GRO se introdujo como una alternativa más segura y consciente de la pila a LRO, pero aún cambia la visibilidad de paquetes para herramientas como tcpdump y consumidores AF_PACKET.
- Hecho 3: TSO se volvió común cuando 1 Gbit/s pasó a 10/25/40/100+ Gbit/s; las CPUs no pueden permitirse la sobrecarga por paquete a velocidades de línea modernas.
- Hecho 4: “Checksum malo” en tcpdump en el host emisor suele ser un artefacto de captura con checksum offload, no una falla real en el cable.
- Hecho 5: Muchas CNIs y pilas de overlay (VXLAN/Geneve) han tenido periodos donde combinaciones de offloads eran buggy hasta que drivers y kernels maduraron.
- Hecho 6: RSS (Receive Side Scaling) y RPS/XPS se desarrollaron porque el procesamiento de recepción en un solo núcleo se volvió un cuello de botella mucho antes que el ancho de banda de la NIC.
- Hecho 7: La moderación/coalescencia de IRQ puede causar picos de latencia con tráfico ligero incluso cuando mejora el rendimiento con tráfico intenso.
- Hecho 8: La virtualización añadió otra capa: virtio-net y vhost pueden hacer su propio batching/coalescing, lo que agrava los efectos de offloads.
- Hecho 9: La exactitud de la captura de paquetes siempre ha sido “mejor esfuerzo” una vez que agregas offloads; capturar en un SPAN/TAP o en un router a menudo cuenta una historia distinta que capturar en el endpoint.
Guion rápido de diagnóstico (primero/segundo/tercero)
Primero: decide si estás depurando corrección o rendimiento
Si tienes corrupción de datos, sesiones rotas, reinicios extraños o comportamiento que “solo falla bajo carga”, trátalo como corrección hasta que se demuestre lo contrario. El ajuste de rendimiento puede esperar. Desactivar offloads es una prueba válida de corrección aunque cueste rendimiento.
Segundo: encuentra el punto de estrangulamiento en una pasada
- Busca retransmisiones, drops y resets. Si las retransmisiones TCP se disparan mientras la utilización de enlace es baja, tienes pérdida o reordenamiento (real o aparente).
- Revisa la saturación por softirq en la CPU. Si ksoftirqd o un solo núcleo de CPU se dispara, estás limitado por la tasa de paquetes o un desvío incorrecto (problema de RSS/afinidad de IRQ).
- Compara contadores a nivel host vs contadores del switch. Si el host dice “drops” pero el puerto del switch no, tu problema probablemente está en la pila/driver/offload del host.
Tercero: ejecuta dos pruebas controladas A/B
- A/B offloads: alterna GRO/LRO/TSO de forma acotada, mide latencia/retransmisiones/rendimiento.
- A/B MTU y camino: prueba MTU estándar vs jumbo, y directo host-a-host vs a través de overlay/VPN.
Tu objetivo no es “hacer los números más grandes.” Tu objetivo es: demostrar causalidad, luego aplicar el arreglo más pequeño que elimine el modo de fallo.
Tareas prácticas: comandos, salidas, decisiones (12+)
Estos no son comandos de juguete. Son las cosas que ejecutas cuando estás de guardia y tu gráfico te está mintiendo. Cada tarea incluye qué observar y qué decisión tomar.
Tarea 1: Identificar la interfaz real y el driver
cr0x@server:~$ ip -br link
lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
enp5s0f0 UP 3c:fd:fe:aa:bb:cc <BROADCAST,MULTICAST,UP,LOWER_UP>
enp5s0f1 DOWN 3c:fd:fe:aa:bb:cd <BROADCAST,MULTICAST>
Significado: Elige la interfaz que transporta el tráfico (aquí: enp5s0f0). “UP, LOWER_UP” significa que el enlace está activo.
Decisión: Toca offloads solo en la interfaz activa. No hagas cambios a lo loco en todas las NICs a menos que disfrutes de juegos de adivinanza.
cr0x@server:~$ sudo ethtool -i enp5s0f0
driver: ixgbe
version: 6.8.0-41-generic
firmware-version: 0x800003e7
bus-info: 0000:05:00.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: no
Significado: Driver y firmware importan. “Funcionó en 22.04” no es una prueba; es una memoria.
Decisión: Si los problemas comenzaron tras un cambio de kernel/firmware, mantén eso en tu lista de hipótesis.
Tarea 2: Inventario de las configuraciones actuales de offload (línea base)
cr0x@server:~$ sudo ethtool -k enp5s0f0
Features for enp5s0f0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: on
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
Significado: Este es tu punto de partida. Nota lo que ya está apagado (LRO a menudo lo está).
Decisión: Copia esto en tus notas del incidente. Cuando reviertas, reviertes a hechos, no a impresiones.
Tarea 3: Comprueba si ves retransmisiones (a menudo la primera pista de “offload lo rompió”)
cr0x@server:~$ nstat -az | egrep 'Tcp(RetransSegs|ExtTCPSynRetrans|OutRsts|InErrs)'
TcpRetransSegs 1842 0.0
TcpExtTCPSynRetrans 17 0.0
TcpOutRsts 92 0.0
IpInErrs 0 0.0
Significado: Un aumento de TcpRetransSegs durante una carga apunta a pérdida, reordenamiento o rarezas del camino.
Decisión: Si las retransmisiones suben mientras CPU y utilización del enlace parecen bien, sospecha interacciones driver/offload/túnel antes de culpar “a la red.”
Tarea 4: Prueba si las pérdidas están en la NIC, en la pila o en otra parte
cr0x@server:~$ ip -s link show enp5s0f0
2: enp5s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 3c:fd:fe:aa:bb:cc brd ff:ff:ff:ff:ff:ff
RX: bytes packets errors dropped missed mcast
9876543210 9123456 0 18421 0 1234
TX: bytes packets errors dropped carrier collsns
8765432109 8234567 0 0 0 0
Significado: Las caídas RX aquí son visibles por el host. Podrían ser desbordes de anillo, acumulación en CPU o comportamiento del driver.
Decisión: Si las caídas RX suben bajo carga, debes mirar tamaños de anillo, distribución de IRQ y GRO/LRO antes de ajustar timeouts de la aplicación.
Tarea 5: Ver si softirq es el verdadero cuello de botella
cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.8.0-41-generic (server) 12/30/2025 _x86_64_ (32 CPU)
12:00:01 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
12:00:02 AM all 4.2 0.0 6.1 0.1 0.3 7.8 0.0 0.0 0.0 81.5
12:00:02 AM 7 2.1 0.0 4.9 0.0 0.2 48.7 0.0 0.0 0.0 44.1
Significado: Un CPU con %soft muy alto indica procesamiento de recepción concentrado en una cola/IRQ.
Decisión: Antes de desactivar offloads “porque sí”, revisa RSS/afinidad de IRQ. Los offloads no son tu única palanca.
Tarea 6: Comprueba la distribución de interrupciones y si una cola está acaparando
cr0x@server:~$ awk '/enp5s0f0/ {print}' /proc/interrupts | head
74: 1283921 2031 1888 1999 2101 1902 1988 2010 PCI-MSI 524288-edge enp5s0f0-TxRx-0
75: 1932 1290033 1890 2011 1998 1887 2002 2017 PCI-MSI 524289-edge enp5s0f0-TxRx-1
Significado: Esto parece relativamente balanceado. Si ves un conteo de IRQ que eclipsa a los demás, RSS o afinidad está mal.
Decisión: Arregla el steering (RSS/afinidad) antes de apagar GRO y accidentalmente empujar la tasa de paquetes contra un muro de CPU.
Tarea 7: Verificar tamaños de anillo (las pérdidas pueden ser simple falta de buffer)
cr0x@server:~$ sudo ethtool -g enp5s0f0
Ring parameters for enp5s0f0:
Pre-set maximums:
RX: 4096
RX Mini: 0
RX Jumbo: 0
TX: 4096
Current hardware settings:
RX: 512
RX Mini: 0
RX Jumbo: 0
TX: 512
Significado: Los anillos actuales son más pequeños que el máximo.
Decisión: Si tienes caídas RX bajo cargas en ráfaga, aumenta los anillos antes de culpar a GRO. Anillos más grandes aumentan la latencia un poco pero pueden prevenir pérdida.
Tarea 8: Confirmar velocidad/duplex del enlace y detectar comportamiento raro de autoneg
cr0x@server:~$ sudo ethtool enp5s0f0 | egrep 'Speed|Duplex|Auto-negotiation|Link detected'
Speed: 10000Mb/s
Duplex: Full
Auto-negotiation: on
Link detected: yes
Significado: Obvio, pero te sorprendería cuán a menudo un “bug de red” es una degradación a 1G.
Decisión: Si la velocidad es incorrecta, detente. Arregla el enlace/óptica/cable/puerto del switch antes de perseguir offloads.
Tarea 9: Usar tcpdump correctamente cuando hay offloads involucrados
cr0x@server:~$ sudo tcpdump -i enp5s0f0 -nn -s 96 tcp and port 443 -c 5
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp5s0f0, link-type EN10MB (Ethernet), snapshot length 96 bytes
12:00:10.123456 IP 10.0.0.10.51532 > 10.0.0.20.443: Flags [S], seq 123456789, win 64240, options [mss 1460,sackOK,TS val 111 ecr 0,nop,wscale 7], length 0
12:00:10.123789 IP 10.0.0.20.443 > 10.0.0.10.51532: Flags [S.], seq 987654321, ack 123456790, win 65160, options [mss 1460,sackOK,TS val 222 ecr 111,nop,wscale 7], length 0
Significado: tcpdump en el endpoint sigue siendo útil para el handshake y la temporización. Pero la segmentación de payload y los checksums pueden engañarte.
Decisión: Si estás diagnosticando pérdida de paquetes o problemas de MTU, considera capturar en un SPAN/TAP del switch o desactiva GRO temporalmente durante la ventana de captura.
Tarea 10: Comprobar problemas de ruta MTU (los offloads a veces los enmascaran/activan)
cr0x@server:~$ ping -c 3 -M do -s 8972 10.0.0.20
PING 10.0.0.20 (10.0.0.20) 8972(9000) bytes of data.
ping: local error: message too long, mtu=1500
ping: local error: message too long, mtu=1500
ping: local error: message too long, mtu=1500
--- 10.0.0.20 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2049ms
Significado: Tu MTU de interfaz es 1500, así que el ping jumbo falla localmente. Eso está bien si esperas 1500.
Decisión: No mezcles supuestos de jumbo con expectativas de TSO/GSO. Si necesitas jumbo, configúralo en todas partes y luego vuelve a probar los offloads.
Tarea 11: Medir throughput y CPU con iperf3 (línea base antes de cambiar offloads)
cr0x@server:~$ iperf3 -c 10.0.0.20 -P 4 -t 10
Connecting to host 10.0.0.20, port 5201
[SUM] 0.00-10.00 sec 10.9 GBytes 9.35 Gbits/sec 0 sender
[SUM] 0.00-10.00 sec 10.8 GBytes 9.29 Gbits/sec receiver
Significado: Buena línea base. Si los offloads están rotos, a menudo ves colapso de throughput con retransmisiones o CPU desbocada.
Decisión: Registra esto. Cualquier cambio que hagas debe superarlo o resolver la corrección sin regresión inaceptable.
Tarea 12: Desactiva GRO temporalmente y ve si los síntomas cambian
cr0x@server:~$ sudo ethtool -K enp5s0f0 gro off
cr0x@server:~$ sudo ethtool -k enp5s0f0 | egrep 'generic-receive-offload|large-receive-offload'
generic-receive-offload: off
large-receive-offload: off
Significado: GRO ahora está apagado. LRO sigue apagado.
Decisión: Vuelve a probar la carga fallida y observa retransmisiones/latencia. Si la corrección mejora de inmediato, GRO fue al menos parte del modo de fallo.
Tarea 13: Desactiva TSO/GSO (con precaución: puede aumentar CPU/tasa de paquetes)
cr0x@server:~$ sudo ethtool -K enp5s0f0 tso off gso off
cr0x@server:~$ sudo ethtool -k enp5s0f0 | egrep 'tcp-segmentation-offload|generic-segmentation-offload'
tcp-segmentation-offload: off
generic-segmentation-offload: off
Significado: La segmentación en transmisión ocurrirá en trozos más pequeños o será totalmente por software, dependiendo de la pila y la NIC.
Decisión: Si esto arregla bloqueos/retransmisiones en ciertos caminos (especialmente túneles), considera mantenerlo como una fuerte señal de interacción driver/firmware/overlay. Luego decide cómo acotar el cambio.
Tarea 14: Revisa las estadísticas a nivel driver por señales de alarma (drops, missed, errors)
cr0x@server:~$ sudo ethtool -S enp5s0f0 | egrep -i 'drop|dropped|miss|error|timeout' | head -n 20
rx_missed_errors: 0
rx_no_buffer_count: 124
rx_errors: 0
tx_timeout_count: 0
Significado: rx_no_buffer_count sugiere inanición de buffers de recepción; eso suele ser tamaño de anillo, CPU o comportamiento en ráfagas.
Decisión: Aumenta anillos, ajusta moderación de IRQ o reduce la ráfaga antes de desactivar permanentemente offloads en toda la flota.
Tarea 15: Observa qdisc y encolamiento (los picos de latencia pueden ser locales)
cr0x@server:~$ tc -s qdisc show dev enp5s0f0
qdisc mq 0: root
qdisc fq_codel 0: parent :1 limit 10240p flows 1024 quantum 1514 target 5.0ms interval 100.0ms memory_limit 32Mb ecn
Sent 812345678 bytes 8234567 pkt (dropped 0, overlimits 0 requeues 12)
backlog 0b 0p requeues 12
Significado: Las estadísticas de la disciplina de cola muestran drops/requeues. No todo el dolor está en el cable.
Decisión: Si ves drops locales en qdisc, desactivar GRO no te salvará; tienes problemas de encolamiento/bufferbloat o de shaping.
Tarea 16: Valida conntrack o la ruta de firewall (a menudo se culpa a offloads)
cr0x@server:~$ sudo conntrack -S | egrep 'insert_failed|drop|invalid'
insert_failed=0
drop=0
invalid=0
Significado: Conntrack no se está viniendo abajo. Bien.
Decisión: Si drop/insert_failed de conntrack sube, tienes un problema de tabla de estado; no lo “arregles” alternando GRO.
Cómo desactivar offloads de forma segura (temporal, persistente, con alcance)
El enfoque seguro es aburrido: aislar, probar, medir, persistir solo lo necesario y documentar el rollback. Desactivar offloads puede arreglar problemas reales. También puede convertir un problema de throughput en un incidente de CPU y entonces disfrutarás de dos incidentes por el precio de uno.
Cambios temporales (solo en runtime)
Usa ethtool -K para una prueba A/B inmediata. Esto no sobrevive a un reinicio. Eso es una característica cuando estás experimentando.
cr0x@server:~$ sudo ethtool -K enp5s0f0 gro off lro off tso off gso off rx off tx off
Cannot change rx-checksumming
Cannot change tx-checksumming
Significado: Algunas características no pueden togglearse en ciertos drivers/NICs. Eso es normal.
Decisión: No luches contra el hardware. Alterna lo que puedas y ajusta tu plan de pruebas. A menudo los toggles de GRO/TSO son los más impactantes de todos modos.
Cambios persistentes con systemd-networkd (la forma nativa sensata en Ubuntu 24.04)
En Ubuntu 24.04, muchos servidores funcionan con systemd-networkd por debajo incluso si usas netplan para definir la configuración. El punto: quieres que los offloads se apliquen en el levantado del enlace, no por un script que “alguien” olvidó instalar en la mitad de la flota.
Crea un archivo .link para hacer match con la interfaz por nombre o MAC y aplica ajustes de offload. Ejemplo haciendo match por nombre:
cr0x@server:~$ sudo tee /etc/systemd/network/10-enp5s0f0.link >/dev/null <<'EOF'
[Match]
OriginalName=enp5s0f0
[Link]
GenericReceiveOffload=false
TCPSegmentationOffload=false
GenericSegmentationOffload=false
LargeReceiveOffload=false
EOF
cr0x@server:~$ sudo systemctl restart systemd-networkd
cr0x@server:~$ sudo ethtool -k enp5s0f0 | egrep 'generic-receive-offload|tcp-segmentation-offload|generic-segmentation-offload|large-receive-offload'
tcp-segmentation-offload: off
generic-segmentation-offload: off
generic-receive-offload: off
large-receive-offload: off
Significado: Los offloads se aplican después del reinicio/renegociación del enlace.
Decisión: Si la configuración persistente se aplica correctamente y arregla el problema sin costo de CPU inaceptable, puedes desplegarla gradualmente.
Cambios persistentes con una unidad systemd oneshot (funciona en todas partes, menos elegante)
Si no puedes confiar en la configuración de enlaces de systemd-networkd (entornos mixtos, nombrado de NIC personalizado, o si simplemente quieres algo contundente), usa una unidad systemd oneshot que se ejecute después de que la red esté arriba.
cr0x@server:~$ sudo tee /etc/systemd/system/ethtool-offloads@.service >/dev/null <<'EOF'
[Unit]
Description=Set NIC offloads for %I
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/sbin/ethtool -K %I gro off lro off tso off gso off
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
cr0x@server:~$ sudo systemctl enable --now ethtool-offloads@enp5s0f0.service
Created symlink /etc/systemd/system/multi-user.target.wants/ethtool-offloads@enp5s0f0.service → /etc/systemd/system/ethtool-offloads@.service.
Significado: Offloads establecidos al arrancar para esa interfaz.
Decisión: Usa esto cuando necesites comportamiento predecible rápido. Luego reemplázalo con una configuración de enlace más limpia.
Acótalo: desactiva solo lo estrictamente necesario
En la práctica:
- Si las capturas de paquetes son engañosas o un consumidor en espacio de usuario está confundido: desactiva GRO (y a veces checksum offload) temporalmente para diagnóstico.
- Si túneles/overlays se comportan mal: prueba a desactivar TSO/GSO primero, luego GRO.
- Si haces enrutamiento/bridging: mantiene LRO apagado. La mayoría de entornos de producción nunca lo activan.
Verifica que no “arreglaste” creando inanición de CPU
Después de desactivar offloads, vuelve a ejecutar la carga y observa:
- %soft de CPU (carga por softirq)
- RX drops y
rx_no_buffer_count - latencia p99 y retransmisiones
Broma #2: La forma más rápida de demostrar que los offloads “lo arreglaron” es crear un nuevo cuello de botella de CPU—la naturaleza aborrece el vacío, y también la red de Linux.
Tres microhistorias del mundo corporativo (anonimizadas, plausibles, técnicamente exactas)
1) Incidente causado por una suposición errónea: “Checksums malos significan que la red corrompe paquetes”
Un equipo de pagos notó fallos TLS intermitentes tras mover un servicio a nuevos hosts con Ubuntu 24.04. Una captura de paquetes desde el host cliente mostró un desfile de advertencias de “checksum malo”. La conclusión inmediata fue predecible: el equipo de red estaba mutilando paquetes. Se activó el equipo de red, se abrió una war room y todos empezaron a cazar fantasmas.
La primera suposición fue el error: que una advertencia de checksum en una captura del host prueba una corrupción a nivel de cable. En Linux moderno, con TX checksum offload activado, tcpdump puede capturar paquetes antes de que la NIC complete la checksum. El paquete en el cable está bien; el paquete en tu captura está incompleto en ese punto de tap.
El segundo error fue escalar por captura de pantalla. Un ingeniero sénior finalmente pidió dos cosas: una captura desde un puerto SPAN del switch y la salida de ethtool -k. La captura SPAN mostró checksums válidos. La captura en el endpoint parecía “mala” solo cuando los offloads estaban activados.
El problema real terminó siendo no relacionado con checksums: una tabla conntrack mal dimensionada en un host gateway compartido descartaba conexiones bajo carga en ráfaga. Los offloads eran inocentes; la herramienta de captura era la que engañaba.
Lo que cambió la toma de decisiones: actualizaron el runbook de on-call para tratar “checksum malo” como un artefacto diagnóstico a menos que se confirme fuera del host. También estandarizaron un método: “capturar con offloads desactivados por 2 minutos” cuando se requieren capturas en endpoints.
2) Optimización que salió mal: “Habilitar todos los offloads para máximo rendimiento”
Un grupo de plataforma que ejecutaba contenedores tenía el mandato de mejorar la densidad de nodos. Alguien notó que algunos nodos tenían LRO deshabilitado y decidió “normalizar” la flota para throughput. Empujaron un cambio para habilitar todo lo que la NIC anunciaba. Los benchmarks de throughput se veían geniales en una prueba sintética. El cambio llegó a producción.
Dos días después, la cola de soporte se llenó de rarezas: streams gRPC atascándose, timeouts esporádicos entre pods y un patrón donde las fallas eran más comunes en nodos con mucho tráfico east-west. La CPU estaba bien. La red estaba bien. Los logs no ayudaban. El incidente olía a: todo normal salvo la experiencia del usuario.
El culpable fue LRO interactuando mal con tráfico encapsulado y la forma en que algunos componentes observaban límites de paquete. El sistema no estaba “perdiendo paquetes” tanto como creando comportamiento de agregación raro que exponía bugs marginales en la ruta de overlay. Desactivar LRO lo arregló de inmediato.
La lección fue simple: los offloads no son “flags de rendimiento gratis.” Son cambios de comportamiento. Si tu entorno usa overlays, middleboxes o datapaths avanzados, trata los offloads como actualizaciones de kernel: pruébalos con tráfico representativo, no solo con iperf.
Revirtieron a una línea base conservadora: LRO apagado en todas partes, mantener TSO/GSO activados salvo que demuestren ser dañinos, y permitir GRO solo donde no interfiera con la observabilidad o componentes de procesamiento de paquetes.
3) Práctica aburrida pero correcta que salvó el día: “Prueba A/B con un host y temporizador de reversión”
Un equipo de almacenamiento con tráfico de replicación sobre enlaces 25G comenzó a ver picos de retraso en replicación tras una actualización de SO. No había pérdida obvia de paquetes, pero el retraso era real y se correlacionaba con periodos ocupados. La primera impulsión fue ajustar la aplicación y añadir ancho de banda. Resistieron.
Su líder SRE insistió en un experimento de un solo host: escoger un emisor y un receptor, aislar el camino y alternar offloads en una matriz controlada (solo GRO, solo TSO, ambos). Cada cambio tenía el comando de reversión preescrito, y usaron un job temporizado para revertir ajustes tras 20 minutos salvo que se cancelara explícitamente. Aburrido. Correcto.
El experimento mostró algo accionable: desactivar TSO/GSO eliminó los picos de retraso pero aumentó la CPU de forma notable. Desactivar GRO tuvo efecto mínimo. Eso acotó el culpable a interacciones de segmentación de transmisión, no a la coalescencia de recepción.
Con esa evidencia, actualizaron el firmware de la NIC en el modelo afectado y volvieron a probar. Tras la actualización, TSO/GSO pudieron permanecer activados. Evitaron un impuesto de CPU permanente y no tuvieron que re-arquitectar la topología de almacenamiento.
La práctica que salvó el día no fue un sysctl ingenioso. Fue disciplina: un cambio, un host, un resultado medible y reversión garantizada.
Errores comunes: síntoma → causa raíz → solución
1) Síntoma: tcpdump muestra “checksum malo” en paquetes salientes
Causa raíz: TX checksum offload; tcpdump capturó antes de que se calcule la checksum.
Solución: Captura en SPAN/TAP o desactiva TX checksum offload brevemente para la captura (ethtool -K IFACE tx off) y vuelve a comprobar.
2) Síntoma: p99 latencia con picos en tráfico ligero, throughput bien en tráfico pesado
Causa raíz: Moderación/coalescencia de interrupciones ajustada para throughput; despierta la CPU con menos frecuencia y añade latencia.
Solución: Ajusta la coalescencia de interrupciones de la NIC (ethtool -c/-C), y solo entonces considera cambios en GRO.
3) Síntoma: networking de pod-a-pod en Kubernetes inestable tras actualización
Causa raíz: Interacción offload + overlay/túnel (TSO/GSO/GRO con VXLAN/Geneve), a veces específica de driver.
Solución: A/B desactiva TSO/GSO primero en los nodos afectados; mantiene LRO apagado. Confirma con retransmisiones y pruebas de carga.
4) Síntoma: RX drops suben en el host durante ráfagas, el switch muestra contadores limpios
Causa raíz: Inanición de buffer/anillo de recepción o backlog de softirq; no es necesariamente pérdida externa.
Solución: Aumenta tamaño de anillo RX (ethtool -G), confirma distribución IRQ/RSS y luego revisa GRO/TSO si es necesario.
5) Síntoma: Después de desactivar offloads, el rendimiento colapsa y la CPU se dispara
Causa raíz: Quitaste el batching, aumentaste la tasa de paquetes y la sobrecarga por paquete, y tocaste límites de CPU/softirq.
Solución: Vuelve a habilitar TSO/GSO, mantiene LRO apagado, considera dejar GRO activo. Mejora steering (RSS), tamaños de anillo y afinidad de IRQ.
6) Síntoma: Las capturas muestran “paquetes” gigantes mayores que la MTU
Causa raíz: GRO/LRO presentando skbs coalesced al punto de captura; no es una violación de MTU en el cable.
Solución: Desactiva GRO/LRO durante la ventana de captura, o captura fuera del host.
7) Síntoma: Replicación de almacenamiento o iSCSI/NFS funciona peor con “más optimización”
Causa raíz: Backpressure y patrones de ráfaga cambiados por offloads; bugs de driver bajo segmentos grandes sostenidos.
Solución: A/B prueba TSO/GSO; observa retransmisiones y CPU. Si desactivar ayuda, revisa firmware/driver y considera acotar cambios de offload a VLANs/interfaces de almacenamiento.
Listas de verificación / plan paso a paso
Paso a paso: demuestra que los offloads son el problema (no solo “diferente”)
- Línea base: registra
ethtool -k,ethtool -i,ip -s link,nstat. - Reproduce: ejecuta la carga real, no solo iperf. Captura latencia p95/p99, retransmisiones y contadores de error.
- Toggle único: desactiva solo GRO. Vuelve a probar. Si el cambio es visible, continúa; si no, revierte.
- Segundo toggle: desactiva TSO/GSO. Vuelve a probar. Observa CPU y softirq.
- Decide alcance: si solo una clase de tráfico falla (overlay, VLAN de almacenamiento), prefiere acotar el cambio a esos nodos o interfaces.
- Plan de reversión: escribe los comandos exactos de revert y verifica que funcionan.
Lista de control de cambio (aka cómo no convertirte en el incidente)
- Hazlo en un host primero. Luego en una pequeña piscina canaria. Luego expande.
- Mantén LRO apagado salvo que tengas una razón medida y un camino L2/L3 simple.
- No desactives todo de una vez. GRO y TSO afectan lados distintos de la pila.
- Monitorea CPU softirq y RX drops después de cambios. Si suben, moviste el cuello de botella.
- Persiste la configuración usando archivos .link de systemd o unidades systemd, no folklore rc.local.
- Documenta: interfaz, driver, firmware, versión de kernel, matriz de offloads y resultado medido.
Checklist de reversión (escríbelo antes de cambiar nada)
cr0x@server:~$ sudo ethtool -K enp5s0f0 gro on lro off tso on gso on
Significado: Ejemplo de reversión a una línea base conservadora: mantiene LRO apagado, vuelve a habilitar GRO/TSO/GSO.
Decisión: Si la reversión no restaura el comportamiento, aprendiste que los offloads no eran la causa raíz. Deja de cambiar offloads y amplía la búsqueda.
Opcional: cambio de tamaño de anillo (solo si las caídas apuntan allí)
cr0x@server:~$ sudo ethtool -G enp5s0f0 rx 2048 tx 2048
cr0x@server:~$ sudo ethtool -g enp5s0f0 | egrep 'Current hardware settings|RX:|TX:' -A4
Current hardware settings:
RX: 2048
RX Mini: 0
RX Jumbo: 0
TX: 2048
Significado: Anillos más grandes reducen drops bajo ráfagas pero pueden incrementar buffering/latencia.
Decisión: Si tu problema es “caídas bajo microráfagas”, esto suele ser más correcto que desactivar GRO.
Preguntas frecuentes
1) ¿Debo desactivar GRO/LRO/TSO por defecto en Ubuntu 24.04?
No. Los offloads por defecto suelen ser correctos para cargas de trabajo comunes. Desactívalos solo cuando puedas demostrar un problema de corrección o una regresión de rendimiento medible ligada a offloads.
2) ¿Por qué desactivar offloads a veces arregla pérdida de paquetes que “no es real”?
Porque estás cambiando la temporización, el batching y los patrones de segmentación. Si una ruta driver/firmware tiene un bug bajo ciertos tamaños de segmento o patrones de ráfaga, cambiar offloads puede evitar disparar ese bug.
3) Si LRO es tan dudoso, ¿por qué existe?
Se diseñó para throughput en caminos más simples, a menudo en entornos antiguos o más controlados. Las redes modernas (overlays, virtualización, enrutamiento en hosts) hicieron sus casos límite más costosos que sus beneficios para muchas organizaciones.
4) ¿“Checksum malo” en tcpdump siempre es inofensivo?
No siempre, pero a menudo es un artefacto de offload. Valida capturando off-host o desactivando checksum offload brevemente. Si el problema se reproduce off-host con checksums malas, entonces es real.
5) ¿Cuál es la diferencia entre TSO y GSO en la práctica?
TSO es segmentación TCP por hardware realizada por la NIC. GSO es un marco genérico en software que permite al kernel segmentar de forma similar para otros protocolos o cuando el hardware no puede hacerlo.
6) ¿Desactivar TSO/GSO aumentará la latencia?
Puede ir en cualquier dirección. A menudo aumenta trabajo de CPU y la tasa de paquetes, lo que puede incrementar el encolamiento bajo carga. Pero puede reducir la ráfaga y evitar ciertos problemas de driver/túnel, mejorando la latencia tail en escenarios específicos.
7) He desactivado GRO y mis capturas ahora se ven “normales”. ¿Arreglé producción?
Arreglaste la observabilidad. Eso es valioso, pero no es lo mismo que arreglar el comportamiento en producción. Vuelve a habilitar GRO después de capturar a menos que tengas evidencia de que GRO causaba problemas visibles para usuarios.
8) ¿Puedo desactivar offloads solo para una VLAN, bridge o túnel?
Los offloads típicamente se configuran por interfaz física o virtual. Puedes aplicar ajustes a la interfaz que termina tu tráfico (p. ej., la NIC física, el bond o el veth/bridge en algunos casos), pero la granularidad “por VLAN” es limitada y depende del driver.
9) ¿Cómo sé si estoy limitado por CPU después de desactivar offloads?
Observa mpstat para un %soft alto, verifica /proc/interrupts por desequilibrios y busca subidas en RX drops o rx_no_buffer_count. Si esos suben, cambiaste un problema de red por uno de procesamiento en host.
10) ¿Ubuntu 24.04 cambia por sí mismo los offloads comparado con 22.04?
El cambio más significativo es el kernel, los drivers y cómo tu firmware de NIC interactúa con ellos. Las releases de Ubuntu pueden cambiar defaults, pero la mayoría de historias de “cambió tras la actualización” son realmente shifts de comportamiento de driver/firmware bajo las mismas banderas nominales.
Conclusión: próximos pasos que puedes desplegar
GRO/LRO/TSO no son villanos. Son herramientas potentes. Si las usas sin entender qué cambian, tarde o temprano cortarás tu propio modelo mental y perderás tiempo en una war room.
- Ejecuta el guion rápido de diagnóstico y decide si persigues corrección o throughput.
- Toma una línea base con
ethtool -k,nstat,ip -s linky estadísticas de softirq de CPU. - Prueba A/B un toggle a la vez: GRO primero para observabilidad/comportamiento de recepción, TSO/GSO para rarezas en transmisión/overlay.
- Persiste el cambio más pequeño usando un archivo .link de systemd o una unidad oneshot, y haz canary.
- Verifica que no creaste un cuello de botella de CPU y que las retransmisiones/caídas realmente mejoraron.
Si te llevas una regla opinada: mantén LRO apagado, no desactives TSO/GSO a la ligera y trata a GRO como tanto un ajuste de rendimiento como un riesgo para la observabilidad. Prueba como si te importara.