Introducción
Tras actualizar el kernel de un nodo de computación de OpenStack (Neutron 16.4.x con OVN) a un kernel 6.x (por ejemplo 6.12.X), el servicio neutron-ovn-metadata-agent dejó de funcionar. El checker openstack_astack_checker de Core-Admin empezó a mostrar este error:
Fallo en el software de OpenStack
Software 'Nova-Comp' has errors
* ERROR * - NOVACOMP_OVNHA_RUN: OVN Metadata HAProxy is not running
Este artículo explica el origen del problema, a qué afecta y cómo corregirlo antes de actualizar el kernel en el resto de nodos de computación.
Resumen: la librería
python3-pyroute20.5.x, la que trae OpenStack, hace todas las operaciones de borrado de red con unos flags que, desde el kernel 5.19, significan “borrado masivo”. El kernel 6.x las rechaza conOperation not supported. La solución es corregir esos flags en pyroute2, un cambio de pocas líneas.
Síntomas
- El checker marca
NOVACOMP_OVNHA_RUN: OVN Metadata HAProxy is not running. -
systemctl status neutron-ovn-metadata-agentmuestra el servicio activo, pero siempre con pocos segundos de antigüedad: systemd lo reinicia en bucle. - En
/var/log/neutron/neutron-ovn-metadata-agent.logse repite en cada arranque:
CRITICAL neutron [-] Unhandled error: neutron.privileged.agent.linux.ip_lib.InterfaceOperationNotSupported:
Operation not supported on interface tapXXXXXXXX-11, namespace ovnmeta-XXXXXXXX-....
...
File ".../neutron/agent/ovn/metadata/agent.py", line 481, in provision_datapath
ip2.addr.delete(ipaddr)
...
INFO oslo_service.service [-] Parent process has died unexpectedly, exiting
- Las instancias de ese nodo no reciben metadatos (
http://169.254.169.254). Esto afecta a cloud-init, a la inyección de claves SSH, etc.
Para confirmar el bucle de reinicios:
systemctl show neutron-ovn-metadata-agent -p NRestarts -p ActiveEnterTimestamp
grep -c InterfaceOperationNotSupported /var/log/neutron/neutron-ovn-metadata-agent.log
Causa
Qué hace el agente
Al arrancar, el metadata agent revisa el namespace ovnmeta-<red> de cada red y compara las direcciones de la interfaz tap<red>-11 con las que debe tener el puerto de metadata. Borra las que sobran.
Con IPv6 activo en el host, que es lo que viene por defecto, esa interfaz siempre tiene una dirección link-local fe80::…. Esa dirección no pertenece al puerto de metadata, así que el agente la borra en cada arranque. Con el kernel 5.4 el borrado funciona sin problemas. Con el kernel 6.x falla, y como el agente no captura ese error, se detiene del todo antes de lanzar los procesos haproxy.
Por qué falla el borrado con kernel 6.x
pyroute2 0.5.x manda todos los borrados netlink (RTM_DELADDR, RTM_DELLINK, RTM_DELROUTE, RTM_DELNEIGH, RTM_DELRULE, RTM_DELQDISC…) con los mismos flags que las altas:
NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL
En un borrado, NLM_F_CREATE y NLM_F_EXCL no tienen sentido, y los kernels antiguos simplemente los ignoraban. Pero desde el kernel 5.19 existe el borrado masivo (NLM_F_BULK), que usa el mismo bit que NLM_F_EXCL (0x200). Un kernel 6.x interpreta entonces que pyroute2 pide borrar de forma masiva y lo rechaza:
Bulk delete is not supported -> EOPNOTSUPP (95, 'Operation not supported')
La herramienta ip (iproute2) manda los borrados solo con NLM_F_REQUEST | NLM_F_ACK. Por eso ip addr del … funciona en el mismo nodo donde el agente falla, y eso despista bastante durante el diagnóstico.
A qué afecta
No es un problema de IPv6 ni solo del metadata agent. En un nodo con kernel ≥ 5.19 y pyroute2 0.5.x falla cualquier borrado de red hecho con pyroute2:
| Operación | Quién la usa en un nodo de computación | Efecto |
|---|---|---|
| Borrar dirección IPv6/IPv4 | metadata agent al montar el namespace | el agente se reinicia en bucle y no hay metadatos |
| Borrar dirección IPv4 | metadata agent al cambiar subredes o IPs del puerto de metadata | el agente vuelve a caer |
| Borrar interfaz (veth/tap) | metadata agent al desmontar una red; os-vif/nova al borrar o migrar instancias | pueden quedar interfaces huérfanas o fallar operaciones |
| Borrar rutas, reglas, vecinos, qdisc | privsep de neutron/nova según la operación | error en la operación concreta |
Mientras no se aplique la corrección, cualquier nodo de computación con OpenStack que arranque con un kernel 6.x tendrá este problema.
Diagnóstico: ¿está afectado mi nodo?
Esta prueba se hace en un namespace desechable. No toca nada de producción ni afecta a OVS ni a las instancias.
Crear el entorno de prueba:
ip netns add crad-test ; ip link add crt-a type veth peer name crt-b netns crad-test
ip -n crad-test link set crt-b up ; ip link set crt-a up ; sleep 3 ; ip -n crad-test addr add 10.99.99.1/24 dev crt-b
Intentar borrar una IPv4 igual que lo hace Neutron:
python3 -c "import socket; from pyroute2 import NetNS; ns = NetNS('crad-test'); i = ns.link_lookup(ifname='crt-b')[0]; ns.addr('delete', i, address='10.99.99.1', mask=24, family=socket.AF_INET); print('delete OK')"
Limpiar:
ip netns del crad-test ; ip link del crt-a 2>/dev/null
Cómo interpretar el resultado:
-
delete OK: el nodo no está afectado, ya sea porque el kernel es antiguo o porque pyroute2 ya está corregido. -
NetlinkError: (95, 'Operation not supported'): el nodo está afectado. Aplica la corrección.
Corrección
El arreglo consiste en que pyroute2 mande los borrados solo con NLM_F_REQUEST | NLM_F_ACK, igual que iproute2 y las versiones modernas de pyroute2. El cambio:
- funciona igual con kernel 5.4 y con 6.x, así que se puede aplicar antes de actualizar el kernel;
- corrige todos los borrados, no solo el caso del metadata agent;
- no modifica Neutron ni el kernel.
Subir pyroute2 a una versión nueva no se recomienda: Neutron depende de la API 0.5.x y el cambio podría romper otras partes del agente.
Todos los pasos se hacen como root en el nodo de computación.
Cuidado al copiar y pegar líneas muy largas: se han visto casos en los que se perdía un espacio en el punto donde el navegador corta la línea. Eso rompe el patrón del
sedsin dar ningún error. Por eso se comprueba siempre después congrepydiff.
1. Localizar el fichero y hacer una copia de seguridad
F=$(python3 -c "import pyroute2.iproute.linux as m; print(m.__file__)") ; echo $F
python3 -c "import pyroute2; print(pyroute2.__version__)"
La versión debe ser 0.5.x. Si es otra, revisa el fichero a mano antes de seguir: las líneas pueden ser diferentes.
cp -a $F $F.orig-pre-6.12
Si el fichero .orig-pre-6.12 ya existe de un intento anterior, no lo sobrescribas: podrías guardar como “original” un fichero modificado a medias.
2. Corregir los flags de los borrados
sed -i -E 's/\((RTM_DEL[A-Z]+), flags_make\)/(\1, flags_base)/' $F
sed -i 's/(RTM_DELLINK, flags_create)/(RTM_DELLINK, flags_req)/' $F
sed -i 's/(RTM_DELADDR, flags_create)/(RTM_DELADDR, NLM_F_REQUEST | NLM_F_ACK)/' $F
3. Comprobar el cambio
El grep no debe devolver nada, el diff solo debe mostrar líneas RTM_DEL… y debe salir COMPILE-OK:
grep -nE "RTM_DEL[A-Z]+, flags_(make|create)" $F ; diff $F.orig-pre-6.12 $F ; python3 -m py_compile $F && echo COMPILE-OK
Si el grep devuelve alguna línea, uno de los sed no se ha aplicado. Lo más habitual es un espacio perdido al copiar: repite ese sed. Si el diff muestra cambios en líneas que no son RTM_DEL…, restaura la copia con cp -a $F.orig-pre-6.12 $F y revisa.
4. Probar
Repite la prueba de la sección Diagnóstico. Ahora debe responder delete OK, incluso con kernel 6.x.
5. Fijar el paquete
apt-mark hold python3-pyroute2
Así una actualización de python3-pyroute2 no deshace la corrección.
6. Reiniciar los servicios
Los demonios privsep conservan el código antiguo en memoria hasta que se reinicia el servicio que los lanza. Reiniciar nova-compute no afecta a las instancias en ejecución.
systemctl restart neutron-ovn-metadata-agent nova-compute ; sleep 10 ; systemctl is-active neutron-ovn-metadata-agent nova-compute
Verificación
Tras aplicar la corrección en un nodo que ya tiene el kernel 6.x, lo más fiable es volver a crear el namespace de metadata. Así se reproduce exactamente lo que pasa tras un reinicio del nodo. Los metadatos de ese nodo se cortan unos segundos. Sustituye <red> por el identificador de tu red; ip netns list | grep ovnmeta muestra los que hay.
systemctl stop neutron-ovn-metadata-agent ; ip netns del ovnmeta-<red> ; ip link del tap<red8>-10 2>/dev/null
systemctl start neutron-ovn-metadata-agent ; sleep 20 ; ip netns exec ovnmeta-<red> ip -br addr ; pgrep -af "haproxy -f"
(<red8> son los 8 primeros caracteres del identificador de la red, igual que aparece en el nombre de la interfaz tap.)
Resultado correcto:
- la interfaz
tap<red8>-11tiene sus direcciones IPv4 y169.254.169.254/16, sinfe80::, porque el agente ha podido borrarla; - hay un proceso
haproxy -f /var/lib/neutron/ovn-metadata-proxy/<red>.confpor red; - el contador de
InterfaceOperationNotSupporteden el log no sube; - el checker
openstack_astack_checkervuelve a OK en su siguiente ejecución.
Procedimiento recomendado para actualizar el kernel de los nodos
- Aplicar la corrección de pyroute2 en el nodo (sección Corrección), todavía con el kernel antiguo. Es compatible.
- Comprobar que el
grepdel paso 3 no devuelve nada, que la prueba de diagnóstico dadelete OKy queapt-mark showholdmuestrapython3-pyroute2. - Vaciar el nodo de instancias con drain, instalar el kernel nuevo y reiniciar.
- Repetir la prueba de diagnóstico, ya con el kernel 6.x, y revisar el checker
openstack_astack_checker.
Nunca arranques un nodo de computación OpenStack con kernel ≥ 5.19 sin haber corregido antes pyroute2.
Solución de emergencia sin corregir pyroute2
Si un nodo ya está en el bucle y necesitas recuperar los metadatos de inmediato, puedes borrar a mano la link-local que bloquea al agente:
ip netns exec ovnmeta-<red> ip -6 addr show dev tap<red8>-11
ip netns exec ovnmeta-<red> ip addr del <fe80::…/64> dev tap<red8>-11
En el siguiente reinicio automático el agente montará el namespace completo. Esto no corrige el problema: en cuanto se vuelva a crear el namespace, por ejemplo tras un reinicio del nodo, o el agente tenga que borrar cualquier otra dirección, volverá a fallar. Aplica la corrección en cuanto puedas.
Preguntas frecuentes
¿Por qué no desactivar IPv6 para que no aparezca la link-local?
No resuelve la causa. Fallaría igualmente cualquier otro borrado, como una IPv4 al cambiar subredes o una interfaz al borrar instancias. Además, el sysctl net.ipv6.conf.default.disable_ipv6 del host no se aplica a las interfaces que se crean directamente dentro de un namespace nuevo, porque los namespaces nuevos parten de los valores IPv6 por defecto.
¿Afecta a los nodos con kernel 5.4?
No. En esos kernels el bit 0x200 no tiene significado en un borrado y los flags de más se ignoran. Aun así, conviene aplicar la corrección en todos los nodos antes de actualizar el kernel.
¿Qué pasa si se actualiza python3-pyroute2?
La corrección se perdería. Por eso se fija el paquete con apt-mark hold python3-pyroute2. Si quitas el hold y actualizas el paquete, vuelve a aplicar los pasos de la sección Corrección. Es normal que debsums o dpkg --verify marquen el fichero como modificado.
¿Hay que reiniciar las instancias?
No. Solo hay que reiniciar neutron-ovn-metadata-agent y nova-compute, y las instancias en ejecución no se ven afectadas.
¿Cómo vuelvo atrás?
Restaura la copia de seguridad, quita el hold y reinicia los servicios:
F=$(python3 -c "import pyroute2.iproute.linux as m; print(m.__file__)") ; cp -a $F.orig-pre-6.12 $F
apt-mark unhold python3-pyroute2 ; systemctl restart neutron-ovn-metadata-agent nova-compute