Ubuntu 24.04: desconexiones aleatorias — depura pérdidas de NIC y offloads sin superstición

¿Te fue útil?

Las desconexiones aleatorias en un servidor son un tipo especial de dolor: nada está “caído” el tiempo suficiente para activar al equipo de redes, pero todo está roto el tiempo suficiente para que parezcas poco fiable. SSH se atasca. RPC agota tiempos. Los montajes de almacenamiento se detienen como si estuvieran reflexionando sobre su vida. Y cuando inicias sesión, el enlace está “bien”.

Aquí es donde nace la superstición. La gente desactiva offloads como si apagara un interruptor embrujado. Reinician. Culpan a “actualizaciones de Ubuntu”. Puedes hacerlo mejor. El objetivo no es encontrar un sysctl mágico. El objetivo es demostrar dónde se pierden los paquetes: en el cable, en el switch, en la NIC, en el driver, en la ruta de recepción del kernel o en tu propia configuración.

Un modelo mental útil: dónde ocurren realmente las “desconexiones”

La mayoría de las “desconexiones aleatorias” no son desconexiones. Son pérdidas transitorias, reordenamientos, bloqueos o renegociaciones breves de enlace que tu aplicación interpreta como un fallo. Necesitas separar modos de fallo:

  • Flaps de enlace: el enlace físico baja/sube (cable, SFP, puerto del switch, autonegociación). Linux frecuentemente lo registra claramente.
  • Resets de driver/NIC: el dispositivo permanece “up” pero el driver reinicia colas, firmware o DMA. Parece un parpadeo; los logs pueden ser sutiles.
  • Sobrecarga en la ruta de recepción: el enlace está up, pero los anillos RX se desbordan o el backlog de softnet descarta paquetes. No se requieren errores físicos.
  • Interacciones de offload/características: checksum offload, GRO/LRO, TSO/GSO, VLAN offload o XDP pueden generar comportamientos extraños con ciertos switches, túneles o revisiones de NIC.
  • Huecos de Path MTU: el enlace está bien; PMTU discovery falla. Ciertos flujos se atascan; los pings “funcionan”.
  • Problemas con bonding/LACP/VLAN/bridge: montaste algo ingenioso y ahora ocasionalmente se come paquetes.

Tu trabajo es etiquetar el evento correctamente. Una vez hecho, la solución se vuelve embarazosamente sencilla.

Idea parafraseada (con atribución): John Allspaw ha sostenido durante mucho tiempo que la fiabilidad viene de tratar la operación como una ciencia de la evidencia, no como un teatro de la culpa.

Guía de diagnóstico rápida (primero/segundo/tercero)

Cuando estás de guardia, no tienes tiempo para admirar gráficos de paquetes. Empieza aquí. El objetivo es averiguar qué capa te está mintiendo.

Primero: confirma si es flap de enlace, reinicio del driver o congestión/pérdidas

  1. Logs del kernel alrededor de la ventana del evento: enlace abajo/arriba vs reset vs timeout de cola.
  2. Contadores de la NIC: errores CRC y de alineación indican capa física; RX_missed_errors y rx_no_buffer indican anillos/interrupts.
  3. Softnet drops: si el kernel está descartando antes de que tu app vea los paquetes, lo encontrarás aquí.

Segundo: aisla la “rareza de offload” del “problema real de capacidad”

  1. Comprueba el estado de offloads y las versiones de driver/firmware.
  2. Reproduce con una prueba de tráfico controlada (incluso un iperf3 básico) y observa los contadores.
  3. Si deshabilitar un offload “arregla” el problema, demuestra por qué: cambian los contadores, cesan los resets o deja de fallar una encapsulación específica.

Tercero: valida switch, ópticas y cableado como un adulto

  1. Busca errores de FEC/CRC, errores de símbolo y renegociaciones en ambos extremos.
  2. Intercambia ópticas/cable para descartar lo físico. No es glamuroso, pero es rápido.
  3. Confirma la configuración LACP del partner y el MTU extremo a extremo.

Regla de decisión: Si el SO muestra enlace abajo/arriba, empieza por lo físico y la configuración del puerto del switch. Si el enlace permanece up pero los contadores suben y los softnet drops se disparan, ajusta el host. Si la NIC se reinicia, ve a driver/firmware y salud de energía/PCIe.

Hechos y contexto que desearías conocer antes

  • Hecho 1: “Errores de checksum” en capturas pueden ser artefactos: con TX checksum offload, los paquetes pueden parecer incorrectos en el host antes de que la NIC los corrija en el cable.
  • Hecho 2: GRO (Generic Receive Offload) en Linux es un mecanismo por software; LRO lo impulsa la NIC y históricamente tiende a fallar más con túneles y ciertos patrones de tráfico.
  • Hecho 3: La pila de red de Linux lleva tiempo con receive-side scaling (RSS), pero mapear colas a núcleos CPU sigue siendo una autocomplicación común en sistemas multi-socket.
  • Hecho 4: Muchos “drops aleatorios” atribuidos a kernels fueron en realidad microbursts en switches: picos cortos que desbordan buffers más rápido de lo que tu intervalo de monitorización admite.
  • Hecho 5: Energy Efficient Ethernet (EEE) tiene un historial largo de “bien en teoría” y “misteriosamente espigado en la práctica” en equipos de distintos fabricantes.
  • Hecho 6: En NICs modernas, el firmware forma parte de tu superficie de fiabilidad. Una actualización de driver sin actualizar firmware puede dejarte con bugs nuevos y microcódigo antiguo.
  • Hecho 7: Disputas de autonegociación no son un relicto de los años 90. Aparecen hoy por DACs defectuosos, ópticas marginales o configuraciones forzadas en un extremo.
  • Hecho 8: Bonding (LACP) es robusto, pero solo si ambos extremos coinciden en hashing, modo LACP y en qué significa “up”. Si no, falla de manera deliciosamente intermitente.
  • Hecho 9: Los huecos de PMTU siguen siendo comunes porque filtrar ICMP se sigue tratando como “seguridad”, aunque a menudo actúa como “generador de cortes aleatorios”.

Tareas prácticas (comandos + significado + decisión)

A continuación están las tareas de campo que puedes ejecutar en Ubuntu 24.04. Cada una incluye qué significa la salida y qué deberías hacer después. Copiar/pegar está permitido. Las vibras no.

Tarea 1: Identifica la NIC, el driver y el firmware que estás usando

cr0x@server:~$ sudo ethtool -i eno1
driver: ixgbe
version: 6.8.0-31-generic
firmware-version: 0x800003e7
expansion-rom-version:
bus-info: 0000:3b:00.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: yes

Significado: Ahora tienes una tupla precisa: versión del kernel, nombre del driver, versión del firmware, bus PCI. Esa tupla es lo que correlacionas con resets y peculiaridades conocidas. “Intel 10G” no es una tupla.

Decisión: Si las desconexiones coinciden con actualizaciones recientes del kernel, guarda esta salida en las notas del incidente. Si el firmware es muy antiguo respecto a tu flota, planifica una actualización de firmware. Si el driver está en-tree pero el fabricante recomienda un driver fuera del árbol más reciente, trátalo como hipótesis, no como religión.

Tarea 2: Busca flaps de enlace y resets del driver en el log del kernel

cr0x@server:~$ sudo journalctl -k --since "2 hours ago" | egrep -i "eno1|link is|down|up|reset|watchdog|tx timeout|nic"
[ 7432.112233] ixgbe 0000:3b:00.0 eno1: NIC Link is Down
[ 7435.556677] ixgbe 0000:3b:00.0 eno1: NIC Link is Up 10 Gbps, Flow Control: RX/TX
[ 8121.000111] ixgbe 0000:3b:00.0 eno1: Detected Tx Unit Hang
[ 8121.000222] ixgbe 0000:3b:00.0 eno1: Reset adapter

Significado: El primer par es un flap genuino de enlace. Las últimas líneas indican un colgado del Tx y reset del driver/NIC—una clase de problema distinta.

Decisión: Enlace down/up te dirige a ópticas/cable/puerto del switch/autoneg/EEE. Tx hang/reset te dirige a driver/firmware/PCIe/gestión de energía y comportamiento de colas/interrupts.

Tarea 3: Observa en vivo el estado del enlace y los parámetros negociados

cr0x@server:~$ sudo ethtool eno1 | egrep -i "Speed|Duplex|Auto-negotiation|Link detected"
Speed: 10000Mb/s
Duplex: Full
Auto-negotiation: on
Link detected: yes

Significado: Este es tu punto de referencia. Si ves la velocidad cambiando (10G a 1G) o autoneg off en un extremo, tienes un problema de configuración o físico.

Decisión: Si los flaps coinciden con renegociación o cambios de velocidad, deja de tocar offloads. Habla con el equipo de switches y cambia componentes.

Tarea 4: Extrae contadores de NIC que revelan pérdidas físicas vs del host

cr0x@server:~$ sudo ethtool -S eno1 | egrep -i "crc|align|symbol|discard|drop|miss|overrun|timeout" | head -n 30
rx_crc_errors: 0
rx_align_errors: 0
rx_symbol_err: 0
rx_discards: 124
rx_dropped: 0
rx_missed_errors: 98765
tx_timeout_count: 3

Significado: CRC/align/symbol indican corrupción en la capa física. rx_missed_errors suele indicar que la NIC no pudo DMAear paquetes en los buffers del host lo bastante rápido (hambre del anillo / moderación de interrupts / planificación de CPU).

Decisión: Si los errores físicos son distintos de cero y aumentan durante incidentes, trátalo como cable/ópticas/puerto del switch. Si missed errors suben mientras los errores físicos se mantienen en cero, céntrate en anillos RX, IRQs, NAPI y contención de CPU.

Tarea 5: Inspecciona los softnet drops (kernel descartando antes de la capa socket)

cr0x@server:~$ awk '{print NR-1, $1, $2, $3, $4, $5}' /proc/net/softnet_stat | head
0 0000001a 00000000 0000003f 00000000 00000000
1 00000020 00000000 00000110 00000000 00000000

Significado: El campo 1 son paquetes procesados, el campo 2 son paquetes descartados (en hex), el campo 3 es time_squeeze. Drops/time_squeeze indican que CPU/softirq no pudieron mantenerse al día.

Decisión: Si los drops aumentan durante desconexiones, no estás ante un “misterio”. Estás ante sobrecarga o mala colocación de CPU/IRQ. Pasa a tareas de IRQ/RSS.

Tarea 6: Confirma si las interrupciones de la NIC están mapeadas sensatamente

cr0x@server:~$ grep -i eno1 /proc/interrupts | head -n 10
  98:  12345678   0   0   0  IR-PCI-MSI 524288-edge  eno1-TxRx-0
  99:         12   0   0   0  IR-PCI-MSI 524289-edge  eno1-TxRx-1
100:         10   0   0   0  IR-PCI-MSI 524290-edge  eno1-TxRx-2

Significado: La cola 0 está haciendo todo el trabajo mientras otras colas están inactivas. Eso puede ocurrir por mala configuración de RSS, tipos de flujo o un problema de afinidad.

Decisión: Si una cola está caliente y otras frías, corrige RSS/cantidad de colas y considera afinidad de IRQ. Si el host es multi-socket, asegúrate de que las colas de la NIC residan en núcleos NUMA locales.

Tarea 7: Comprueba RSS y número de canales combinados

cr0x@server:~$ sudo ethtool -l eno1
Channel parameters for eno1:
Pre-set maximums:
RX:		0
TX:		0
Other:		0
Combined:	64
Current hardware settings:
RX:		0
TX:		0
Other:		0
Combined:	8

Significado: Esta NIC soporta hasta 64 colas combinadas, actualmente configurada en 8. No es “incorrecto”, pero debería coincidir con tus núcleos CPU y carga de trabajo.

Decisión: Si ves missed errors o softnet drops y tienes margen de CPU, aumentar canales combinados puede ayudar. Si ya estás limitado por la CPU, más colas pueden añadir sobrecarga. Ajusta deliberadamente.

Tarea 8: Cambia el conteo de canales (temporalmente) para probar una hipótesis

cr0x@server:~$ sudo ethtool -L eno1 combined 16
cr0x@server:~$ sudo ethtool -l eno1 | tail -n +1
Channel parameters for eno1:
Pre-set maximums:
RX:		0
TX:		0
Other:		0
Combined:	64
Current hardware settings:
RX:		0
TX:		0
Other:		0
Combined:	16

Significado: Has aumentado el paralelismo de colas. Si los drops desaparecen bajo carga, encontraste un cuello de botella en recepción. Si la latencia empeora y la CPU sube, te pasaste.

Decisión: Mantén el cambio solo si puedes probar mejoría mediante contadores y síntomas de la aplicación. Hazlo persistente usando hooks de systemd-networkd/NetworkManager o reglas udev, no confiando en que sobreviva al reinicio.

Tarea 9: Comprueba las funciones de offload actualmente habilitadas

cr0x@server:~$ sudo ethtool -k eno1 | egrep -i "rx-checksumming|tx-checksumming|tso|gso|gro|lro|rx-vlan-offload|tx-vlan-offload|ntuple"
rx-checksumming: on
tx-checksumming: 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
ntuple-filters: off

Significado: GRO/TSO/GSO/checksum offloads están activados. LRO está desactivado (a menudo una buena predeterminación). VLAN offload está activado.

Decisión: No desactives todo “por seguridad”. Desactiva una característica a la vez, solo para validar una interacción sospechada. Si desactivas checksumming, espera aumento de CPU y posiblemente peor rendimiento; estás intercambiando hipótesis de corrección por coste medible.

Tarea 10: Alterna un único offload para probar un bug (y observa contadores)

cr0x@server:~$ sudo ethtool -K eno1 gro off
cr0x@server:~$ sudo ethtool -k eno1 | grep -i generic-receive-offload
generic-receive-offload: off

Significado: GRO está desactivado. Si tu problema está relacionado con GRO (a menudo con túneles/encapsulación o algunas combinaciones buggy de NIC/driver), los síntomas pueden cambiar rápidamente.

Decisión: Si desactivar GRO elimina los bloqueos pero aumenta la CPU y reduce el rendimiento, probablemente encontraste un caso límite del kernel/driver. Entonces o (a) mantienes GRO desactivado para esa interfaz, (b) cambias kernel/driver/firmware, o (c) rediseñas la encapsulación. Elige según restricciones de negocio, no por orgullo.

Tarea 11: Comprueba MTU y si accidentalmente estás fragmentando o produciendo un agujero negro

cr0x@server:~$ ip -br link show eno1
eno1             UP             10.10.0.12/24 fe80::1234:56ff:fe78:9abc/64
cr0x@server:~$ ip link show eno1 | egrep -i "mtu|state"
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UP mode DEFAULT group default qlen 1000

Significado: MTU es 9000. Si el camino en el switch o el peer es 1500, ahora tienes una falla intermitente reproducible: los paquetes pequeños funcionan, las transferencias grandes se atascan o fragmentan de forma extraña, y lo “aleatorio” empieza a mostrar tendencia.

Decisión: Valida el MTU extremo a extremo. Para túneles, recuerda que hay overhead. Si no puedes garantizar jumbo frames a través del camino, no los uses a medias.

Tarea 12: Prueba PMTU con ping “do not fragment”

cr0x@server:~$ ping -M do -s 8972 -c 3 10.10.0.1
PING 10.10.0.1 (10.10.0.1) 8972(9000) bytes of data.
From 10.10.0.12 icmp_seq=1 Frag needed and DF set (mtu = 1500)
From 10.10.0.12 icmp_seq=2 Frag needed and DF set (mtu = 1500)
From 10.10.0.12 icmp_seq=3 Frag needed and DF set (mtu = 1500)

--- 10.10.0.1 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2043ms

Significado: El camino no puede transportar tramas de 9000 bytes. Esto no es sutil. Tu MTU de interfaz está configurado mayor que lo que admite el camino.

Decisión: Corrige la discrepancia de MTU. O bien establece MTU 1500 en el host o habilita jumbo frames end-to-end (incluyendo bonds, bridges, subinterfaces VLAN y puertos del switch).

Tarea 13: Comprueba retransmisiones TCP y estadísticas de red del kernel

cr0x@server:~$ nstat -az | egrep -i "TcpRetransSegs|TcpTimeouts|IpInDiscards|IpOutDiscards"
IpInDiscards                    120
IpOutDiscards                   0
TcpTimeouts                     18
TcpRetransSegs                  3490

Significado: Retransmisiones y timeouts confirman pérdida/estancamiento real experimentado por TCP, no solo queja de la aplicación. Los descartes IP sugieren drops en capas superiores.

Decisión: Si las retransmisiones suben durante incidentes mientras el enlace sigue up, correlaciona con softnet drops, missed errors de la NIC y buffers del puerto del switch. Luego elige: ajuste del host o remediación de red.

Tarea 14: Confirma si NetworkManager/systemd-networkd está rebotando la interfaz

cr0x@server:~$ systemctl status NetworkManager --no-pager
● NetworkManager.service - Network Manager
     Loaded: loaded (/usr/lib/systemd/system/NetworkManager.service; enabled; preset: enabled)
     Active: active (running) since Mon 2025-12-29 09:12:10 UTC; 3h 2min ago
       Docs: man:NetworkManager(8)
cr0x@server:~$ sudo journalctl -u NetworkManager --since "2 hours ago" | egrep -i "eno1|carrier|down|up|deactivat|activat"
Dec 29 10:41:12 server NetworkManager[1023]: <info>  [....] device (eno1): carrier: link connected
Dec 29 10:41:13 server NetworkManager[1023]: <info>  [....] device (eno1): state change: activated -> deactivating (reason 'carrier-changed')
Dec 29 10:41:14 server NetworkManager[1023]: <info>  [....] device (eno1): state change: deactivating -> activated (reason 'carrier-changed')

Significado: El carrier está cambiando; NM está reaccionando. Normalmente eso refleja un evento real de enlace, no que NM sea “aleatorio”.

Decisión: No te enfrentes al network manager. Soluciona la inestabilidad del carrier (físico/switch) o los resets del driver que provocan cambios de carrier.

Tarea 15: Valida pistas de salud PCIe (los errores AER pueden parecer “problemas aleatorios de NIC”)

cr0x@server:~$ sudo journalctl -k --since "24 hours ago" | egrep -i "AER|pcieport|Corrected error|Uncorrected|DMAR|IOMMU" | head -n 30
[ 8120.998877] pcieport 0000:3a:00.0: AER: Corrected error received: 0000:3a:00.0
[ 8120.998900] pcieport 0000:3a:00.0: PCIe Bus Error: severity=Corrected, type=Physical Layer, (Receiver ID)

Significado: Errores PCIe corregidos pueden preceder a fallos o resets de dispositivo, especialmente bajo carga o con slots/risers marginales.

Decisión: Si los logs AER correlacionan con resets de NIC, deja de discutir sobre GRO y empieza a revisar el host físico: asiento de la tarjeta, risers, gestión de energía PCIe en BIOS y firmware de plataforma.

Offloads sin superstición: cuándo ayudan y cuándo perjudican

Los offloads no son malvados. Son características de rendimiento diseñadas para mover trabajo de la CPU a la NIC (o para amortiguar trabajo en el kernel). También son un chivo expiatorio frecuente porque desactivarlos es fácil y los síntomas son intermitentes. El hecho de que un toggle cambie el síntoma no significa que entendiste la causa.

Sabe qué estás desactivando

  • TX checksum offload: el kernel entrega el paquete con checksum “a rellenar”; la NIC calcula el checksum. Las capturas en el host pueden mostrar “checksum malo” porque aún no se ha calculado.
  • TSO/GSO: grandes segmentos TCP creados por la pila y segmentados después (por la NIC o el kernel). Genial para throughput; puede amplificar ráfagas.
  • GRO: agrupa paquetes recibidos en SKBs mayores antes de pasar al stack. Ahorra CPU; puede cambiar características de latencia.
  • LRO: concepto similar pero impulsado por la NIC; puede interactuar mal con encapsulación y romper más fácilmente la semántica de paquetes.
  • VLAN offloads: la NIC maneja operaciones de etiqueta VLAN; normalmente está bien, ocasionalmente doloroso con bridging u odd switch behavior.

Enfoque adulto: trata los offloads como variables en un experimento. Alterna uno, mide contadores, mide síntomas de la aplicación y decide si encontraste un bug real o simplemente cambiaste el cuello de botella.

Cuándo es apropiado deshabilitar offloads

Desactiva un offload temporalmente cuando:

  • Tienes evidencia de resets del driver correlacionados con una función (por ejemplo, Tx hang con TSO bajo tráfico específico).
  • Estás depurando capturas y necesitas checksums en host para que sean significativos.
  • Tratas con encapsulación/túneles (VXLAN/Geneve) y sospechas que la ruta de offload está rota en esa NIC/driver.

Y mantenlo desactivado solo cuando no puedas actualizar driver/firmware/kernel a tiempo y el coste en CPU sea aceptable.

Cuándo desactivar offloads es culto cargo

Desactivar offloads es cargo cult cuando:

  • El síntoma es enlace down/up (offloads no hacen flap a tu cable).
  • Los errores CRC de RX son distintos de cero (checksum offload no crea errores CRC en el cable).
  • Los drops de softnet son el problema real (desactivar offloads suele aumentar trabajo en CPU y empeorar).

Broma #1: Apagar todos los offloads es como sacar las pilas del detector de humo porque hace ruido. El fuego sigue ganando.

IRQs, RSS, buffers de anillos y la trampa de “drops sin errores”

Uno de los patrones de desconexión más comunes en NICs rápidas es: el enlace está estable, sin errores CRC, el switch parece limpio, pero las aplicaciones reportan timeouts. Bajo el capó, el host está descartando paquetes porque no puede atender interrupts y vaciar anillos lo suficientemente rápido. Esto no es teórico; es lo que sucede cuando una NIC de 10/25/40/100G se encuentra con una CPU ocupada en cualquier otra cosa.

Qué suelen significar “rx_missed_errors” y “rx_no_buffer”

Estos contadores típicamente significan que la NIC tenía tramas para entregar pero no pudo ponerlas en memoria del host porque el anillo de recepción estaba lleno o no había buffers disponibles. Causas incluyen:

  • Demasiados pocos descriptores RX (tamaño de anillo demasiado pequeño para ráfagas).
  • Moderación de interrupts demasiado agresiva (los paquetes se acumulan y luego se desbordan).
  • CPU starvación del contexto ksoftirqd/softirq.
  • Mala afinidad de IRQ (todas las colas asignadas a una CPU, a menudo CPU0, porque el mundo es cruel).
  • Desajuste NUMA (interrupts de la NIC atendidos en un socket remoto).

Tamaños de anillo: instrumento tosco pero efectivo

cr0x@server:~$ sudo ethtool -g eno1
Ring parameters for eno1:
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: Estás usando 512 descriptores mientras la NIC soporta 4096. No es incorrecto, pero no es resistente a ráfagas.

Decisión: Si ves ráfagas/microbursts y missed errors, aumenta anillos a algo sensato (por ejemplo, 2048) y mide impacto en memoria y latencia.

cr0x@server:~$ sudo ethtool -G eno1 rx 2048 tx 2048

Significado: Has aumentado la capacidad de buffering en el límite de la NIC. Esto puede reducir drops durante ráfagas, a costa de algo de latencia por buffering y uso de memoria.

Decisión: Si tu problema son drops por microbursts, esto suele ayudar rápido. Si el problema es sobrecarga sostenida, solo lo pospone.

Moderación de interrupts: la compensación latencia/CPU que nadie documenta en tu organización

El coalescing de interruptos reduce la sobrecarga de CPU agrupando interrupts. Pero si coalesces demasiado, puedes introducir picos de latencia y crear desbordos de anillo durante ráfagas.

cr0x@server:~$ sudo ethtool -c eno1 | head -n 40
Coalesce parameters for eno1:
Adaptive RX: on  TX: on
rx-usecs: 50
rx-frames: 64
tx-usecs: 50
tx-frames: 64

Significado: Coalescing adaptativo está activado, y hay umbrales base en microsegundos/frames. Los modos adaptativos pueden ser geniales, o pueden oscilar bajo ciertas cargas.

Decisión: Si persigues bloqueos breves, considera desactivar coalescing adaptativo temporalmente y establecer valores fijos conservadores. Mide latencia en la cola y drops. No “optimes” a oscuras.

Afinidad de IRQ: cuando el valor por defecto es “esperanza”

Ubuntu puede ejecutar irqbalance que intenta distribuir interrupciones. A veces funciona. A veces tu carga es tan sensible que quieres colocación determinista, especialmente en sistemas NUMA.

cr0x@server:~$ systemctl status irqbalance --no-pager
● irqbalance.service - irqbalance daemon
     Loaded: loaded (/usr/lib/systemd/system/irqbalance.service; enabled; preset: enabled)
     Active: active (running) since Mon 2025-12-29 09:12:12 UTC; 3h 1min ago

Significado: irqbalance está activo. Eso está bien, pero no siempre es óptimo.

Decisión: Si ves una cola caliente o interrupts NUMA remotos, considera fijar IRQs de la NIC a CPUs locales y excluir esas CPUs de vecinos ruidosos. Esto es especialmente importante en servidores de almacenamiento e hipervisores.

Broma #2: Afinar IRQs es como los planes de asiento en la oficina: todos coinciden en que importa, y nadie quiere la reunión donde lo cambian.

Linux recibe la culpa porque sus logs son legibles y los logs del switch están detrás de un ticket. Aun así, la capa física y el switch son culpables comunes. Especialmente cuando la falla es intermitente.

Indicadores físicos que deberían acabar el debate “es el kernel”

  • Errores CRC/alineación/símbolo que aumentan durante incidentes.
  • Correcciones FEC que suben (común en velocidades altas; corrección intensa puede preceder a pérdidas).
  • Bucle de autonegociación visible como repetidos bajadas/subidas del enlace.
  • Renegociación de velocidad/duplex o sorpresas de “link is up 1Gbps”.

En el host no siempre puedes ver detalles de FEC, pero puedes ver lo suficiente para justificar la escalada.

EEE y gestión de energía: muerte por valores predeterminados “verdes”

Si ves microcaídas periódicas y todo lo demás parece limpio, comprueba si Energy Efficient Ethernet (EEE) está habilitado. Hardware mixto puede comportarse mal.

cr0x@server:~$ sudo ethtool --show-eee eno1
EEE Settings for eno1:
EEE status: enabled - active
Tx LPI: 1 (on)
Supported EEE link modes:  1000baseT/Full 10000baseT/Full
Advertised EEE link modes:  1000baseT/Full 10000baseT/Full
Link partner advertised EEE link modes:  1000baseT/Full 10000baseT/Full

Significado: EEE está activo. Eso no es automáticamente incorrecto, pero es una variable común en latencia intermitente y pequeños bloqueos.

Decisión: Si sospechas de EEE, desactívalo en ambos extremos durante una ventana de prueba y observa si los bloqueos desaparecen.

cr0x@server:~$ sudo ethtool --set-eee eno1 eee off

Bonding y LACP: fiables si están configurados, caóticos si se asumen

Las fallas de bonding a menudo parecen desconexiones aleatorias porque el hashing envía algunos flujos por un camino roto mientras otros aciertan. Verás “algunos servicios inestables” en lugar de “host caído”.

cr0x@server:~$ cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v6.8.0-31-generic

Bonding Mode: IEEE 802.3ad Dynamic link aggregation
Transmit Hash Policy: layer3+4 (1)
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0

Slave Interface: eno1
MII Status: up
Aggregator ID: 2
Actor Churn State: churned
Partner Churn State: churned

Slave Interface: eno2
MII Status: up
Aggregator ID: 1
Actor Churn State: churned
Partner Churn State: churned

Significado: Estados churned indican inestabilidad en la negociación LACP. Eso no es un problema de offload de Linux; es un problema del plano de control de agregación de enlaces.

Decisión: Involucra al equipo de switches con esta evidencia. Verifica modo LACP (active/passive), trunking VLAN y que ambos enlaces terminen en el mismo grupo LACP. También confirma timers y que el switch no esté bloqueando silenciosamente un miembro por errores.

Tres mini-historias corporativas (anonimizadas, dolorosamente plausibles)

Mini-historia 1: El incidente causado por una suposición equivocada

Una compañía mediana ejecutaba un clúster interno de almacenamiento de objetos en servidores Ubuntu. El síntoma fueron “desconexiones aleatorias” entre nodos gateway y nodos de almacenamiento backend. Ocurría mayormente durante horas laborales, lo que hizo sospechar a todos de “carga” pero a nadie le dio coraje cuantificarla.

La primera suposición fue clásica: “Es una regresión del kernel”. El equipo había movido recientemente a un kernel y a un driver de NIC más nuevos, y el timing parecía culpable. Revirtieron dos hosts. El problema persistió. Revirtieron otros dos. Siguió. Ahora corrían una flota mixta con comportamiento inconsistente y sin causa raíz. La fiabilidad no mejoró; solo se volvió más difícil razonar.

Cuando alguien finalmente ejecutó ethtool -S contadores, notaron que rx_crc_errors no era cero. Era pequeño, pero subía exactamente durante las quejas de “desconexión”. Eso rompió la narrativa. Los errores CRC no vienen de sysctls. Los errores CRC vienen de la capa física.

La causa real fue dolorosamente mundana: un lote de cables DAC marginales a 10G en una disposición de rack con curvas cerradas y conectores estresados. Bajo cambios de temperatura, los errores aumentaban, LACP churneaba y algunos flujos se quedaban en agujero negro el tiempo suficiente para romper sesiones de almacenamiento. La solución fue cambiar cables y reinsertar ópticas. Más tarde se revirtió la reversión del kernel, después de que todos dejaron de ponerse nerviosos.

La lección no fue “revisa cables”. La lección fue: no empieces por la teoría más emocionalmente satisfactoria. Empieza por los contadores que puedan falsarla.

Mini-historia 2: La optimización que salió mal

Un equipo SaaS tenía un problema de latencia en una capa de API, y alguien decidió que la tasa de interrupts de la NIC era “demasiado alta”. Hicieron coalescing agresivo de interrupts y lo ajustaron hasta que los gráficos de CPU se veían más tranquilos. Celebraron. El uso de CPU bajó. Escribieron un breve post interno sobre “ganar rendimiento”.

Dos semanas después, los clientes reportaron bloqueos ocasionales de 1–2 segundos durante tráfico pico. No aparecía en la latencia media, solo en la latencia cola (tail). Las retransmisiones aumentaron ligeramente, pero no lo suficiente para disparar las alertas existentes. El servicio lucía sano en la mayoría de dashboards, que es como la latencia cola le gusta operar: se oculta en las medias como un profesional.

En los hosts afectados, rx_missed_errors subía lentamente. Los softnet drops se disparaban durante microbursts. La NIC no era “demasiado interruptiva”. Hacía su trabajo. Los nuevos ajustes de coalescing retrasaban el procesamiento RX lo suficiente como para que los buffers de anillo se desbordaran durante ráfagas breves. La optimización funcionó para los gráficos de CPU y falló para los usuarios.

La solución fue revertir a coalescing adaptativo con límites conservadores y aumentar modestamente el tamaño del anillo RX. También añadieron monitorización de softnet drops y missed errors de NIC, porque “reduje interrupts” no es un SLO orientado al usuario.

Mini-historia 3: La práctica aburrida pero correcta que salvó el día

Una organización relacionada con finanzas ejecutaba un conjunto de hipervisores KVM Ubuntu 24.04 alojando cargas críticas internas. Llegaron reportes de desconexiones aleatorias de múltiples tenants: breve pérdida de paquetes, stalls TCP ocasionales, nada consistente. El equipo de redes estaba listo para culpar al switching virtual. El equipo de plataforma estaba listo para culpar a los switches ToR. Todos estaban listos para culparse entre sí.

Lo que los salvó no fue genialidad. Fue disciplina. Tenían una práctica establecida: cada host enviaba logs del kernel, estadísticas de NIC y contadores softnet a un sistema central con cadencia de 30 segundos, y guardaban unos días de historial de alta resolución. No se necesitó depuración heroica. Los datos ya existían.

Cuando ocurrieron incidentes, correlacionaron tres señales: (1) errores corrected AER en journalctl, (2) mensajes “Reset adapter” de la NIC, y (3) pequeñas caídas en el throughput de las VMs. El patrón se repitió en un subconjunto de hosts—mismo modelo de hardware, misma revisión de BIOS.

Resultó ser un problema de firmware de plataforma interactuando con gestión de energía PCIe. Bajo ciertos estados, la NIC se comportaba mal brevemente, se reiniciaba y se recuperaba. La solución fue una actualización de firmware del proveedor más desactivar una opción ASPM PCIe específica en BIOS como mitigación a corto plazo. Sin toggles de offload. Sin intercambio de cables a medianoche. Solo evidencia aburrida y una ventana de cambio.

Lo mejor: pudieron demostrar que la solución funcionó porque las mismas señales se silenciaron. Nada de correos de cierre basados en vibras.

Errores comunes: síntoma → causa raíz → solución

  • Síntoma: “Desconexiones de red”, y journalctl -k muestra NIC Link is Down/Up.
    Causa raíz: Flap de enlace físico (cable/DAC malo, ópticas, autoneg mismatch, errores en puerto del switch, rarezas de EEE).
    Solución: Revisa ethtool -S para errores CRC/símbolo, desactiva EEE para una prueba, cambia cable/óptica, valida config del puerto del switch.
  • Síntoma: El enlace permanece up, pero ves Detected Tx Unit Hang / Reset adapter.
    Causa raíz: Bug en driver/firmware de NIC, problemas PCIe/AER, o caso esquina de colas/interrupts bajo carga.
    Solución: Recopila la tupla driver/firmware, correlaciona con logs AER, actualiza firmware, prueba kernel/HWE más nuevo, ajusta coalescing/anillos, considera driver del proveedor si está disponible.
  • Síntoma: No hay flap de enlace, no hay errores CRC, pero timeouts TCP y retransmisiones se disparan.
    Causa raíz: Drops en host (softnet drops, overflow de anillo RX, CPU starvación), o microbursts aguas arriba.
    Solución: Revisa /proc/net/softnet_stat, missed errors en ethtool -S, ajusta anillos/colas/afinidad de IRQ, y valida buffering del switch.
  • Síntoma: Paquetes pequeños funcionan, grandes transferencias se atascan; pings tienen éxito; SSH “a veces se congela”.
    Causa raíz: Desajuste de MTU o agujero PMTU (ICMP bloqueado).
    Solución: Auditoría MTU extremo a extremo; ejecuta ping -M do; permite ICMP fragmentation-needed; ajusta MTU en túneles y VLANs.
  • Síntoma: Solo fallan algunos flujos, especialmente detrás de un bond; problemas aparecen “aleatorios” entre clientes.
    Causa raíz: Hashing LACP envía algunos flujos a un miembro roto; churn/desajuste del partner.
    Solución: Inspecciona /proc/net/bonding; verifica grupo LACP del switch y hashing; revisa errores por miembro; considera quitar el miembro defectuoso hasta repararlo.
  • Síntoma: Captura de paquetes muestra “checksum malo” y la gente entra en pánico.
    Causa raíz: Artefacto de checksum offload en la ruta de captura.
    Solución: Valida con captura on-wire (SPAN/TAP) o desactiva temporalmente TX checksum offload solo para depuración.
  • Síntoma: Desactivar GRO “arregla” algo pero la CPU se dispara y el throughput cae.
    Causa raíz: Enmascaraste un problema más profundo (bug de driver o sobrecarga) cambiando el comportamiento de batching.
    Solución: Tómalo como una pista diagnóstica; busca fixes de driver/firmware/kernel o ajusta coalescing/anillos; mantén GRO desactivado solo como mitigación documentada.

Listas de verificación / plan paso a paso

Checklist A: Captura evidencia durante el próximo incidente (15 minutos, sin conjeturas)

  1. Registra la ventana temporal de los síntomas (inicio/fin). Si no tienes ventana, no tienes incidente.
  2. Recopila mensajes del kernel:
    cr0x@server:~$ sudo journalctl -k --since "30 minutes ago" > /tmp/kern.log
    

    Decisión: Flap de enlace vs reset vs nada registrado te dice a dónde ir después.

  3. Haz snapshot de contadores de NIC antes y después de una reproducción:
    cr0x@server:~$ sudo ethtool -S eno1 > /tmp/eno1.stats.before
    
    cr0x@server:~$ sleep 60; sudo ethtool -S eno1 > /tmp/eno1.stats.after
    

    Decisión: Aumento de CRC/símbolo = físico; aumento de missed/no_buffer = ruta de recepción del host.

  4. Snapshot de softnet:
    cr0x@server:~$ cat /proc/net/softnet_stat > /tmp/softnet.before
    
    cr0x@server:~$ sleep 60; cat /proc/net/softnet_stat > /tmp/softnet.after
    

    Decisión: Drops/time_squeeze crecientes significan que el kernel no puede mantenerse al día.

  5. Revisa retransmisiones/timeouts:
    cr0x@server:~$ nstat -az | egrep -i "TcpRetransSegs|TcpTimeouts"
    TcpTimeouts                     18
    TcpRetransSegs                  3490
    

    Decisión: Si TCP lo ve, es pérdida/estancamiento real, no solo bug de la app.

Checklist B: Cambios de offload y tuning sin empeorar las cosas

  1. Haz un cambio a la vez. No negociable.
  2. Antes de cambiar, registra configuraciones actuales:
    cr0x@server:~$ sudo ethtool -k eno1 > /tmp/eno1.offloads.before
    
    cr0x@server:~$ sudo ethtool -c eno1 > /tmp/eno1.coalesce.before
    
    cr0x@server:~$ sudo ethtool -g eno1 > /tmp/eno1.rings.before
    

    Decisión: Ahora puedes deshacer cambios y comparar.

  3. Escoge el cambio más pequeño relevante (por ejemplo, deshabilitar GRO, no “todos los offloads”).
  4. Reproduce bajo carga similar y compara contadores y síntomas.
  5. Si el cambio ayuda, decide si es mitigación o solución final. Las mitigaciones necesitan documentación y un plan para retirarlas.

Checklist C: Validación física y del switch que puedes solicitar con precisión

  1. Proporciona al equipo de switches: timestamps, interfaz del servidor, velocidad/duplex negociada y si Linux registró enlace down/up.
  2. Pide: contadores de errores del puerto (CRC/FCS), estadísticas FEC, historial de renegociación de enlace, estado LACP y contadores de buffer/drop.
  3. Planifica una prueba de intercambio: mueve el cable/óptica a un puerto conocido bueno o intercambia ópticas entre un host bueno y uno malo.
  4. Después del intercambio, verifica si los errores siguen al componente o permanecen con el puerto.

Preguntas frecuentes (FAQ)

1) ¿Por qué mi app dice “desconectado” cuando la interfaz nunca bajó?

Porque TCP puede agotar tiempo sin un flap de enlace. Pérdida de paquetes, microbursts, overflow de anillo RX o agujeros PMTU pueden atascar flujos el tiempo suficiente para que la app se rinda. Revisa retransmisiones (nstat), softnet drops y missed errors de la NIC.

2) ¿Debo desactivar GRO/TSO/checksum offloads para arreglar drops aleatorios?

No como primer movimiento. Si tienes flaps de enlace o errores físicos, los offloads son irrelevantes. Si sospechas un bug de offload, desactiva una característica temporalmente y demuestra el efecto con contadores y logs. Ten en cuenta el coste en CPU.

3) tcpdump muestra checksums malos. ¿La NIC está corrompiendo paquetes?

A menudo no. Con checksum offload, el kernel entrega paquetes a la NIC antes de que se calcule el checksum; tcpdump puede observarlos “pre-checksum”. Confirma con una captura on-wire o desactiva temporalmente TX checksum offload para depuración.

4) ¿Cuál es la forma más rápida de distinguir “cable/switch” vs “tuning del host”?

Errores CRC/alineación/símbolo y mensajes explícitos de enlace down/up son tus indicadores físicos rápidos. Missed errors, softnet drops y enlace estable apuntan a la ruta de recepción del host y ajuste de CPU/IRQ/anillos.

5) ¿Por qué veo drops pero no errores en ip -s link?

Los contadores de ip -s link no siempre exponen razones específicas de drops del driver de la NIC. Usa ethtool -S para contadores detallados y /proc/net/softnet_stat para drops del kernel.

6) ¿Puede irqbalance causar desconexiones aleatorias?

Puede contribuir si las interrupciones quedan concentradas o mal asignadas en un sistema NUMA, especialmente bajo carga. Rara vez es la única causa, pero puede convertir “funciona” en “flaky” cuando el margen es pequeño. Verifica distribución de colas vía /proc/interrupts.

7) Ejecuto bonding (LACP). ¿Por qué solo algunos clientes se ven afectados?

Por hashing. Algunos flujos caen en un miembro malo mientras otros caen en uno sano. Revisa /proc/net/bonding/bond0 por churn y confirma la configuración LACP lado switch y errores por miembro.

8) ¿Cómo hago persistentes las opciones de ethtool después de reinicio en Ubuntu 24.04?

No confíes en comandos manuales. Usa una unidad systemd, regla udev o los hooks nativos del gestor de red para aplicar ethtool -K, -G, -L y -C al levantar la interfaz. El método exacto depende de si usas NetworkManager, systemd-networkd o netplan.

9) ¿Las actualizaciones de kernel en Ubuntu 24.04 suelen causar inestabilidad de NIC?

Pueden, pero “suelen” sería exagerado. Con más frecuencia, las actualizaciones cambian temporizaciones (interrupts, batching, defaults de gestión de energía) y exponen una capa física marginal o un bug de firmware. Trata el cambio de kernel como correlación y luego demuestra el mecanismo con logs y contadores.

10) ¿Y si todo parece limpio pero los usuarios siguen reportando bloqueos?

Entonces tu visibilidad es insuficiente. Añade métricas de mayor resolución: softnet drops, missed errors de NIC, retransmisiones y drops lado switch. Muchos de estos problemas ocurren en ráfagas sub-minuto que los promedios de 5 minutos borran educadamente.

Conclusión: próximos pasos que puedes desplegar esta semana

Las desconexiones aleatorias no son aleatorias. Simplemente ocurren en la brecha entre tus suposiciones y tu evidencia. Cierra la brecha y el problema normalmente se pliega.

  1. Instrumenta primero: empieza a recopilar extractos de journalctl -k, contadores ethtool -S y snapshots de /proc/net/softnet_stat alrededor de incidentes.
  2. Clasifica el modo de fallo: flap de enlace vs reset de NIC vs drops del host vs MTU/PMTU vs LACP/bridging.
  3. Haz un cambio a la vez: tamaños de anillo, conteo de colas, coalescing o un único offload. Mide antes/después con contadores y retransmisiones.
  4. Escala con pruebas: si tienes errores CRC/símbolo o churn LACP, lleva eso al equipo de switches con timestamps. No “pides que miren”, presentas un caso.
  5. Estabiliza a largo plazo: alinea actualizaciones de driver/firmware con actualizaciones de kernel, y monitoriza los contadores que realmente predicen dolor (missed errors, softnet drops, retransmisiones, eventos de enlace).

Si haces solo una cosa: deja de tratar los offloads como un ritual. Trátalos como un experimento. La red te respetará más. Tu pager también.

← Anterior
Por qué la parte baja del mercado de GPU es más importante de lo que crees
Siguiente →
Docker «conexión rechazada» entre servicios: arregla redes, no síntomas

Deja un comentario