CoreOS: tcpdump resuelve misteriosamente un problema de red (se usa un número excesivo de sockets)

14

Hoy tengo un misterio para ti. Ejecutamos un pequeño clúster Elasticsearch de tres nodos basado en CoreOS (2023.5.0 / Linux 4.19.25-coreos) en Azure. Elasticsearch se ejecuta dentro de un contenedor acoplable en modo de red host. Después de ejecutar casi sin mantenimiento durante más de un año, hemos visto cómo las máquinas entran en un estado muy interesante.

Actualizar

Este problema se resolvió mediante una solución a un controlador en el kernel de Linux . Ver la respuesta a continuación.

Síntomas

Básicamente, la red entre la máquina afectada y los otros dos nodos muere. Todos están en la misma red virtual y la misma subred y pueden comunicarse habitualmente con otros. Todavía se puede llegar al nodo afectado desde otras subredes (puedo ingresar en él) y desde una red virtual diferente. La máquina también tiene una conexión (muy irregular) a Internet, pero la mayoría de las solicitudes solo tienen tiempo de espera.

Hemos observado que en un nodo afectado, el número de "sockets utilizados" reportados /proc/net/sockstates muy alto (~ 4.5k en lugar de ~ 300 en un nodo sano). El monitoreo muestra que este número aumenta rápidamente desde el momento en que el nodo deja de estar disponible.

Lo divertido es que parece que no podemos identificar la fuente de estos enchufes usados:

# cat /proc/net/sockstat
sockets: used 4566
TCP: inuse 2 orphan 0 tw 2 alloc 98 mem 4
UDP: inuse 1 mem 0
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0

# cat /proc/net/sockstat6
TCP6: inuse 98
UDP6: inuse 1
UDPLITE6: inuse 0
RAW6: inuse 1
FRAG6: inuse 0 memory 0

Aparte de eso, la máquina parece estar bien. No hay procesos sospechosos en ejecución, el uso de la CPU es mínimo y hay mucha memoria disponible.

Hacer ping a una máquina virtual "inalcanzable" en la misma subred da como resultado algunas EAGAINrespuestas recvmsgy luego se cruza para ENOBUFSregresar sendmsg. strace salida de ping aquí

Recopilé algunos resultados adicionales (antes de que se hicieran modificaciones al sistema) y los publiqué en este resumen: https://gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c

Análisis

Intentamos apagar todo lo que se nos ocurre en el servidor, siendo Elasticsearch el primer sospechoso. Pero cerrar el contenedor de búsqueda elástica no libera los enchufes usados. Lo mismo para todos los procesos relacionados con CoreOS (motor de actualización, cerrajero, ...) o incluso todo el tiempo de ejecución de Docker o cosas específicas de Azure. Nada parecía ayudar.

Pero ahora se vuelve aún más extraño: intentamos correr tcpdumpen la máquina para ver qué está pasando. Y he aquí: el problema se resolvió solo, se restableció la conectividad. Nuestra teoría era que tcpdump realiza algún tipo de syscall que lo resuelve. Ejecutamos tcpdump con gdb y establecimos puntos de interrupción en todas las llamadas al sistema. Después de pasar por un montón de puntos de interrupción, finalmente descubrimos que el acto de establecer el modo promisorio en el socket de captura (específicamente esta línea en libpcap ) es lo que restablece el contador de sockets usados ​​y nos devuelve a un estado normal.

Hallazgos adicionales

  • Hemos verificado que la ejecución tcpdumpcon el -p/--no-promiscuous-modeindicador no borra los contadores de sockets usados ​​y devuelve la máquina a un estado utilizable.
  • La ejecución ifconfig eth0 txqueuelen 1001restablece el contador de sockets utilizados, pero la conectividad no se restaura.
  • Establecer el modo de promisc manualmente con ip link set eth0 promisc ontampoco restaura la conectividad.
    • net.ipv4.xfrm4_gc_thresh está configurado en 32768 y aumentarlo ligeramente no resuelve el problema.

enchufes utilizados

Hemos estado en contacto con Azure, que estamos tan desconcertados como nosotros. Entiendo que probablemente este no sea el problema, sino solo un síntoma. Pero es lo único tangible que encontré hasta ahora. Mi esperanza es que al comprender el síntoma pueda acercarme a la causa raíz. Las interfaces de red en Azure se ejecutan con este controlador de red .

Tal vez CoreOS / Kernel es el culpable?

Desde el punto de vista de la línea de tiempo, los problemas comenzaron el 2019-03-11, que es el día en que CoreOS se actualizó automáticamente a la última versión. De acuerdo con las notas de la versión , esta actualización contenía una actualización del kernel de 4.15.23 a 4.19.25 . Todavía estoy revisando los registros de cambios para ver si algo podría ser un problema allí. Hasta ahora solo he descubierto que el controlador de red Hyperv ha recibido bastantes actualizaciones en los últimos meses , y no todas parecen ser parte de 4.19.25. El conjunto de parches que CoreOS aplicó a 4.19.25 no es tan impresionante , pero el parche que introduce un módulo falso nf_conntrack_ipv4 es nuevo.

Actualización: ¿ Posible parche de kernel entrante relacionado?

¡Ayuda!

Hasta ahora, las preguntas que tenemos son las siguientes:

  • ¿Qué podría causar que esta métrica de "enchufes usados" se dispare? He leído las fuentes del kernel para esta métrica y parece ser solo un contador sin referencia a qué tipo de sockets son realmente o qué los creó.

  • ¿Por qué el número es plano en aproximadamente 4.5k? ¿Qué límite estaría causando esto?

  • ¿Cambió algo significativo entre el kernel 4.14.96 y 4.19.25?

  • ¿Por qué la setsockopt()llamada en libpcap restablece el estado?

Error relacionado de CoreOS: https://github.com/coreos/bugs/issues/2572

Stephan Klein
fuente
Los sockets abiertos son un problema resultante, no el problema raíz en mi humilde opinión. Tuve este comportamiento en un sistema Linux con dispositivos macvlan (con sus propias direcciones mac) en un dispositivo puente. Establecer el puente a promisc hizo que los dispositivos macvlan funcionen. No sé coreos o azul. El problema es que una capa subyacente no conoce las direcciones mac en los niveles superiores.
AndreasM
¡Gracias por tu comentario! Me doy cuenta de que una gran cantidad de tomas utilizadas no es la causa principal, solo me estoy aferrando a la única cosa tangible que puedo identificar como anormal en la máquina.
Stephan Klein
Hola stephan ¿Hay noticias? informe 1) ¿está habilitado WOL? 2) ¿se resuelve sysctl -w net.ipv4.route.flush = 1? 3) ¿cuál es el caché de arp sin estado de funcionamiento? en estado de trabajo?
Massimo

Respuestas:

4

Antes que nada, ¡gracias por una pregunta muy bien escrita!

Como el nivel de detalle que describió es muy alto y ya está en el nivel de gdb, supongo que mi respuesta no será de mucha utilidad para usted. De todos modos, aquí hay un intento:

  • Presumiblemente ya has intentado algo como ss -aey lsof -n?
  • ¿ dmesgDevuelve algo interesante cuando esto sucede?
  • ¿Usas iptables en el servidor?
  • Si configura el modo promiscuo de otra manera que no sea tcpdump (digamos, ip link set [interface] promisc on), ¿esto también soluciona el problema?
  • ¿Ha verificado si hay procesos sospechosos, archivos u otra actividad extraña? ¿Solo pensando que tal vez algún proceso desagradable no invitado está al acecho en las sombras escondiéndose, y se queda en silencio cada vez que se establece el modo promiscuo?
  • Si deja tcpdump ejecutándose en segundo plano, ¿volverá este problema?

Espero que esto ayude.

Janne Pikkarainen
fuente
1
¡Gracias por su respuesta! De hecho, he recopilado la salida de algunos de los comandos a los que hace referencia. Ahora también están vinculados en la pregunta ( gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c ). Lo extraño es que se obtienen menos sockets desde ss, lsofy netstatdesde "sockets utilizados" en /proc/net/sockstat. Solo el recuento total (que parece leerse de ese archivo) es el mismo. iptablesse ejecuta pero no tiene reglas especiales (vea lo esencial), no he intentado configurar el modo promisorio yo mismo o ejecutar tcpdump continuamente. Lo haré la próxima vez.
Stephan Klein
He agregado el resultado de ss -aepimi colección de resultados: gist.github.com/privatwolke/… - Lamentablemente, dmesg no devuelve exactamente nada cuando esto sucede. De hecho, la última entrada antes del incidente tiene 5 días.
Stephan Klein
dmesg / journalctl -kSalida agregada .
Stephan Klein
He verificado que ip link set eth0 promisc onsolo no restaura la máquina a un estado utilizable.
Stephan Klein
Hola, ¿Has echado un vistazo a esta otra pregunta en este sitio? serverfault.com/questions/614453/… Parece implicar que podría estar agotando el caché de destino xfrm4. Puede aumentarlo con esta configuración del kernel: xfrm4_gc_thresh - INTEGER The threshold at which we will start garbage collecting for IPv4 destination cache entries. At twice this value the system will refuse new allocations. Hasta donde puedo decir, está relacionado con IPsec, que tampoco parece estar ejecutando aquí.
Pedro Pérez
0

Esto fue causado por un error en el controlador hv_netsvc en el kernel de Linux. Podríamos resolver esto con un desarrollador de Microsoft y logramos aplicar la solución en sentido ascendente.

Citaré el mensaje de confirmación aquí, ya que resume el problema bastante bien:

Cuando el búfer de anillo está casi lleno debido a los mensajes de finalización de RX, un paquete TX puede alcanzar la "marca de agua baja" y hacer que la cola se detenga. Si la finalización de TX llega antes de que se detenga la cola, se puede perder la activación.

Este parche mueve la verificación del último paquete pendiente para cubrir los casos EAGAIN y de éxito, por lo que la cola se activará de manera confiable cuando sea necesario.

Para referencia futura, la confirmación que corrige esto es https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f .

Stephan Klein
fuente