Ir al contenido

Nombres de puertos

El log del kernel nombra netdevs (eth0, eth5), RouterOS nombra interfaces (ether1, sfp-sfpplus1) y no coinciden: eth1 en el log no es ether1. Relaciona un registro del log del kernel con el cable al que se refiere, como tuvo que hacer el caso del bucle.

RouterOS no expone ninguna correspondencia, y el contenedor no puede leer una. Los dispositivos de red están en su namespace, así que /sys/class/net dentro del contenedor solo muestra lo y la veth, y /sys/class/mdio_bus y /sys/class/phy tampoco nombran ningún puerto. privileged=yes no cambia eso (comprobado). Los nombres de RouterOS viven en la configuración de RouterOS, no en el kernel.

Apaga y enciende un puerto que no lleve nada y lee el nombre que escribe el kernel. Es un paso seguro: un puerto muerto no interrumpe ningún tráfico.

  1. Busca un puerto realmente muerto, con cero paquetes en ambos sentidos en toda su vida:

    /interface/print stats where name="ether6" or name="ether7"
  2. Con el agente en marcha, apágalo y enciéndelo:

    /interface/ethernet/disable [find name="ether6"]
    :delay 4s
    /interface/ethernet/enable [find name="ether6"]
  3. Lee los registros del kernel de ese momento. Nombran el netdev:

    [6] br0: port 7(eth5) entered blocking state
    [4] eth5: set isolation from 0 to 1
    [4] eth5: set isolation from 1 to 0

    Aquí ether6 de RouterOS es eth5 del kernel.

  4. Repítelo en un segundo puerto muerto. ether7 dio eth6: un desfase de −1, visto en dos puntos.

La tabla del agente usa como clave la cadena exacta de /proc/device-tree/model. En la placa de abajo la correspondencia es un desplazamiento de uno — RouterOS numera los puertos desde 1 y el kernel desde 0, chip del switch incluido (switch0 es el switch=switch1 que declaran todos los puertos):

Placa (/proc/device-tree/model) RouterOS kernel cómo se sabe
RB5009 ether1 eth0 deducido
RB5009 ether2 eth1 medido — el bucle del caso de estudio
RB5009 ether3 … ether5 eth2 … eth4 deducido
RB5009 ether6 eth5 medido — apagado y encendido
RB5009 ether7 eth6 medido — apagado y encendido
RB5009 ether8 eth7 deducido
RB5009 sfp-sfpplus1 eth8 deducido, el último de la enumeración
RB5009 switch1 switch0 deducido

Se midieron tres pares, todos con el mismo desplazamiento de uno; los seis puertos deducidos y el switch se apoyan en él (cómo se midió cada par). Los pares deducidos se apoyan en dos observaciones de un /interface/ethernet/print de solo lectura: los nueve puertos llevan direcciones MAC consecutivas, de …:55 para ether1 a …:5D para sfp-sfpplus1, en el orden de enumeración del propio RouterOS; y los nueve declaran switch=switch1 frente al único switch0 del kernel.

Una correspondencia vale solo para su propia placa. El desplazamiento de uno, la posición de la jaula SFP+ y la reutilización de port 7 no se afirman para ninguna otra placa, y el agente no los aplica a ninguna (no probado en otras).

  • El nombre es fiable; el número de puerto del bridge, no. Los dos apagados dieron port 7, porque el kernel reutiliza las posiciones de puerto cuando un puerto sale del bridge y vuelve a entrar. Compara con eth5, nunca con port 7.
  • El desfase es una propiedad del driver de este modelo, no una regla. Vuelve a medirlo en otro equipo en lugar de suponerlo, y ten cuidado con la intuición de que el SFP+ tiene que ser eth0 — aquí es el último, no el primero. El device tree tampoco ayuda: muestra el ethernet@0 del SoC con tres MAC, solo eth0 habilitada (el enlace de subida de 10 G) y eth1/eth2 deshabilitadas, mientras que los nueve puertos del frontal son netdevs que el driver del switch crea en tiempo de ejecución. Los nombres del log del kernel son los de tiempo de ejecución.

El agente lee el modelo de placa de /proc/device-tree/model al arrancar, cosa que funciona incluso sin privilegios, y, en una placa que está en su tabla, nombra los puertos sin preguntar a RouterOS:

  • todo registro del log del kernel cuyo texto nombra un puerto lleva los dos nombres y lo que le ha pasado a ese puerto: iface, ros_iface y kind en el suceso, etiquetas port y kind en las filas de InfluxDB e iface=eth1 ros_iface=ether2 port_event=own-address en una línea de Loki;
  • el /metrics del colector lleva la familia mikroscope_kmsg_port_records_total{port,kind,level}, construida a partir de esos registros, con el nombre de RouterOS como port en una placa que está en la tabla, el nombre del kernel en una placa que no lo está, y ninguna serie de puerto en un equipo cuyo device tree no declara modelo. Es un subconjunto de mikroscope_kmsg_records_total, no una partición: los registros que no nombran ningún puerto no aparecen en él;
  • la detección link-flap del colector usa el nombre de puerto como clave y lee esa misma clasificación: un parpadeo son registros link-up y link-down de un puerto, contados, con el mismo clasificador y no releyendo el texto;
  • mikroscope status muestra la placa y si tiene correspondencia, por ejemplo eth1 (ether2); /healthz y /capabilities llevan la placa, y /capabilities y mikroscope_device_info llevan la cadena de evidencia de la tabla como ports_from, para que nadie tenga que fiarse de la correspondencia a ciegas.

mikroscope doctor, que es la CLI y no el agente, lee esos mismos registros del anillo del agente en marcha: el anillo entero cuando no guarda más de 10 000 muestras, y si no las 10 000 más recientes; 60 s por defecto (el BUFFER_S del agente). Vuelve a clasificar cada registro del log del kernel a partir de su texto, con la placa que el agente declara en /healthz, en lugar de fiarse del kind del agente: de lo contrario, un agente que envía registros sin él haría pasar todas las comprobaciones de puerto sin decir nada. En un equipo cuyo device tree no declara modelo también clasifica, y nombra el puerto del kernel. Por cada puerto de RouterOS informa de layer2-loop con tres o más registros own-address en la ventana, de stp-churn cuando el puerto entró en learning al menos tres veces más de las que llegó a forwarding, y de link-flap con dos o más registros link-down; softnet-drops se informa por CPU, no por puerto.

Una placa desconocida no recibe nombres de puerto, ni siquiera adivinados. El desplazamiento de uno no se aplica a una placa que nadie ha medido, porque un nombre de puerto equivocado señala el cable equivocado. En una placa así, status lo dice y pide el par: baja un puerto, mira qué ethN nombra el log y envía ese par junto con la cadena de la placa en un informe de placa.

El nombre del puerto por sí solo no dice qué le ha pasado, así que todo registro que nombra uno se clasifica también, con procfs.KmsgKind sobre el texto del registro. Las clases, y los registros que escribe un kernel de RouterOS para cada una (dónde se vieron):

kind el registro
link-up eth8: link up, 1Gbps, full-duplex, eth1: Link is Up - 1Gbps/Full, eth1: phy link up
link-down eth1: link down
stp-<state> br0: port 2(eth1) entered blocking state — blocking, listening, learning, forwarding, disabled
own-address br0: received packet on eth1 with own address as source address (addr:…, vlan:0) — la firma del bucle de nivel 2
other cualquier otra cosa que nombre un puerto, incluido eth1: link becomes ready, que es la configuración de direcciones IPv6 dándose cuenta de la portadora y no una transición propia

El agente clasifica en el momento de leer y envía kind dentro del registro. Un colector que tiene delante un agente cuyos registros no lo llevan los clasifica él mismo, con la misma función.

Cuatro registros no son cuatro fallos. A un link-up normal le siguen stp-blocking, stp-learning y stp-forwarding mientras el bridge devuelve el puerto al servicio.

La tabla corresponde a los nombres por defecto de RouterOS. Un puerto renombrado en el router (ether5 → WAN) tiene un nombre que la tabla no puede conocer, así que el colector se lo pregunta a la capa de la API. Su inventario de interfaces —leído una vez antes del primer sondeo del kernel y otra vez cada --labels-every, cinco minutos por defecto— guarda de cada interfaz su nombre de fábrica, su nombre actual, su comentario y sus listas de interfaces, y el colector lo usa en cada registro que nombra un puerto para:

  • sustituir el nombre por defecto por el actual, de modo que quien haya renombrado ether5 como WAN lea WAN en el suceso, en la etiqueta port de InfluxDB, en la línea de Loki y en la clave de link-flap;
  • añadir label, el comentario del puerto, y role, sus listas de interfaces — así el parpadeo de eth5 llega como ether6, etiqueta Unused, y no como un número de netdev que alguien tiene que buscar.

Sin capa de la API el registro se queda con el nombre por defecto de la placa y sin etiqueta, que es lo que puede sostener.

Dos paneles de la fila Kernel log de los dashboards son donde se juntan el nombre, la clase y el comentario:

  • Port events from the kernel log, per port and kind — barras por intervalo, una serie por puerto y clase, con sum by (port, kind) (increase(mikroscope_kmsg_port_records_total[$__interval])) en Prometheus y con las etiquetas port/kind en InfluxDB;
  • Port events in the window, per port — una tabla con una fila por puerto que el log haya nombrado: el puerto, su label y su role, y una columna por clase (link down, link up, own address (loop), STP blocking, STP disabled, STP learning, STP forwarding, other).

Los dos son paneles que se sabe que pueden salir vacíos —un conjunto de puertos callado es el estado sano— y la forma de Prometheus de cada uno lee el /metrics del colector, cuya copia de la familia lleva un kind en todo registro de puerto venga como venga del agente. En un almacén InfluxDB la columna kind no existe hasta que se escribe el primer registro de puerto clasificado por clase; hasta entonces, las dos consultas de InfluxDB fallan al planificarse.

Junto a ellos se publican dos reglas de alerta, en los ficheros de aprovisionamiento de InfluxDB y Prometheus; el de PostgreSQL no tiene ninguna, porque ese almacén guarda cada registro del log del kernel como una fila y no como un recuento. Las dos leen /dev/kmsg a través del agente y no preguntan nada a RouterOS:

  • mikroscope-l2-loop, crítica: cualquier registro own-address en cinco minutos. Esa firma puede correr durante horas mientras todos los contadores de RouterOS parecen sanos, como en el caso del bucle.
  • mikroscope-port-link-down, aviso: cualquier registro link-down en cinco minutos — el suceso suelto, ya que de las repeticiones se ocupa link-flap.

La forma de InfluxDB de cada una necesita un almacén que ya haya guardado un registro de puerto clasificado por clase; antes de eso la consulta falla al planificarse.

Las dos tienen umbral 0 con gt. Las consultas de InfluxDB de las dos reglas devuelven un valor de disparo sobre registros que un router escribió de verdad (comprobado). Que una regla pase a pendiente, salte y se resuelva en la evaluación de Grafana no está probado (Probado en), que es el hueco que señala Reglas de alerta.