Ir al contenido

La capa de la API de RouterOS

Además de la capa del kernel que extrae del agente, forward puede mantener una sesión persistente con la API binaria de RouterOS para la capa de la API (una segunda cuando la propia capa del kernel llega por el relay) y leer lo que el contenedor no ve. Esta página responde a qué lee esa capa, qué parte ya cubre el agente, cómo elegir cuánto de ella ejecutar y qué significa un valor que falta.

Casi todo lo que la capa de la API puede obtener lo lee el propio agente:

  • /system/resource y /system/resource/cpu son la media de un segundo que hace RouterOS de los mismos jiffies de /proc/stat que el agente diferencia a 10 Hz.
  • La temperatura de /system/health es /sys/class/thermal, legible desde el contenedor.
  • El número de conexiones es la caché slab global nf_conntrack, que el agente lee con privileged=yes; consulta conntrack sin la API.

Lo que queda son los bytes y paquetes por interfaz. Viven en el espacio de nombres de red del router y quedan fuera de alcance se le dé lo que se le dé al contenedor; consulta la CPU del router, la red del contenedor.

/system/resource publica cpu-load como un porcentaje entero, y esta página lo llama media de un segundo. Eso está medido, no supuesto: la serie de la API se correlacionó con la propia proporción de ocupación por núcleo del agente, que son los mismos jiffies de /proc/stat leídos a 10 Hz, en dos horas distintas.

El mejor ajuste es una media móvil de 1,0 s con 0,6 s de retardo, r = 0,9825 sobre 3.499 muestras de la API, y 1,1 s con 0,1 s de retardo, r = 0,9734 sobre 3.594 en la segunda hora. Ensanchar la ventana solo empeora el ajuste: 1,5 s da 0,955; 2 s da 0,919; 5 s da 0,822; y 8 s da 0,791.

Una media de sesenta segundos queda descartada por partida doble. Su correlación es 0,238, y la respuesta al escalón no tiene rampa: en el mayor salto de carga del día el kernel pasó de 5 % a 27 % en un segundo y cpu-load pasó de 5 a 26 en ese mismo segundo, y de 22 % a 6 % al bajar con la misma rapidez. Una media de un minuto habría necesitado un minuto para recorrer cualquiera de los dos caminos.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 · Linux 5.6.3 · · /system/resource consultado a 1 Hz frente a la proporción de ocupación por núcleo del agente a 10 Hz, en dos horas distintas

Así que el número es lo que dice ser. Lo que sigue sin poder hacer es resolver nada más corto que su propio segundo, que es justo la razón por la que este proyecto lee el kernel.

--api-mode elige un preajuste. Es full salvo que digas otra cosa, y un --api-every, --no-health o --conntrack-every explícito sigue mandando sobre él.

Modo Lo que hace Úsalo cuando
off sin capa de la API: --api-every 0 en producción, cuando el tráfico por interfaz ya viene de otro sitio
slow una ronda cada 10 s, sin /system/health y sin el número de conexiones; /system/resource, monitor-traffic y los contadores de puerto siguen ejecutándose en cada ronda en producción, cuando también quieres las tasas de las interfaces
full una ronda por segundo, con /system/health; contadores de puerto cada 10 s; el número de conexiones solo si --conntrack-every lo pide experimentos y ejecuciones de record

off es el modo que renuncia al tráfico por interfaz; slow es el que lo conserva a bajo coste. Con slow hay dos paneles vacíos por configuración y no por el equipo — /system/health y el número de conexiones de RouterOS — y nombran la opción que los rellena.

Cada orden de la capa de la API se ejecuta en la única sesión de esa capa, de una en una, con un tiempo de espera de 15 s cada una. Las cadencias más lentas se comprueban en cada ronda, así que ninguna se ejecuta más a menudo que --api-every.

Orden Pide Se ejecuta Apagada cuando
/system/resource/print cpu-load, free-memory, total-memory, free-hdd-space, uptime, version en cada ronda la capa está apagada
/system/health/print name, value en cada ronda --no-health, o slow
/interface/monitor-traffic con interface=<list> y once las cuatro tasas de tráfico y las tasas de pérdidas que devuelva el router en cada ronda, una llamada para todas las interfaces --interfaces está vacío
/interface/print con .proplist=name,default-name,type,comment,actual-mtu qué es cada interfaz: su nombre actual, el nombre de fábrica de la placa, su tipo, su comentario y su MTU al arrancar, antes de la primera extracción del kernel, y luego cada --labels-every (5 min) la capa está apagada
/interface/list/member/print con .proplist=list,interface qué listas de interfaces nombran cada interfaz, que es su rol con la lectura de arriba la capa está apagada
/interface/bridge/port/print con .proplist=interface,bridge a qué bridge pertenece cada puerto con la lectura de arriba la capa está apagada
/interface/ethernet/print stats y /interface/print stats-detail cada contador numérico de todas las interfaces cada --counters-every (10 s) --counters-every 0
/ip/firewall/connection/print count-only el número de conexiones cada --conntrack-every --conntrack-every 0, el valor por defecto

Una orden que falla deja vacía su parte de la muestra y registra por qué; el resto de la ronda sigue en pie. Los fallos se registran en la salida de error como api tier: …, se escriben como líneas en Loki y filas en SQL, y se cuentan en OTLP — nunca se convierten en un valor. Una lectura de /interface que falla conserva el inventario que ya tenía — un error transitorio no deja en blanco la etiqueta de todos los paneles — y se informa como inventory: …; las lecturas de listas y de bridges son de mejor esfuerzo, y sin ellas el inventario sigue llevando nombres, tipos y comentarios.

La muestra de la capa de la API se marca con el reloj del colector más el desfase medido frente al agente, así que cae en la línea temporal del agente.

Las tres lecturas del inventario responden a lo que los contadores no pueden: a qué pertenecen los números. De cada interfaz dan su nombre actual, el nombre por defecto de la placa (el ether5 de fábrica de un puerto físico, vacío en un bridge, una VLAN o un túnel), el tipo propio de RouterOS (ether, bridge, vlan, pppoe-out, wg, veth, loopback), el comentario, las listas de interfaces a las que pertenece — ordenadas y unidas por comas, WAN o LAN,VPN —, el bridge del que es puerto y el MTU. Un miembro de un bridge que no está en ninguna lista propia hereda las de su bridge, porque así es como lo empareja una regla de firewall de RouterOS, y un puerto de bridge que nombra una lista de interfaces en vez de una interfaz no se etiqueta.

En el RB5009 de referencia (RouterOS 7.24.2, 2026-09-16) las tres lecturas devuelven 17 interfaces. ether1 es un ether de la lista LAN, puerto de bridge, etiquetado «TrueNAS - High Performance Storage», MTU 9000; ether5 es un ether de WAN que no está en ningún bridge, etiquetado «DIGI ONT»; PPPoE_DIGI es pppoe-out, WAN, MTU 1480; VLAN_DIGI es vlan, WAN; wg_devices y wg_trastero son wg en LAN,VPN; ether6 y ether7 llevan el comentario «Unused».

Esto es configuración, no telemetría, así que se lee una vez al arrancar — antes de la primera extracción del kernel, para que un registro del log del kernel lleve etiqueta desde la primera línea — y luego con la cadencia lenta de --labels-every, nunca en cada sondeo. Un comentario editado, o un puerto que cambia de lista, llega al dashboard en minutos y no en el siguiente reinicio del colector, y un comentario borrado en RouterOS desaparece también aquí: la lectura sustituye el inventario entero. Ninguna de las cinco propiedades que pide puede llevar un secreto.

Cada fila de tasas de monitor-traffic y cada fila de contadores por puerto llevan entonces label (el comentario), type, role y bridge, para que un panel diga lo que hay enchufado en vez de un número de puerto, y diga qué números se pueden comparar. Prometheus es la excepción a propósito: un comentario lo edita una persona, y una etiqueta que cambia crearía una serie nueva en cada edición, así que el /metrics del colector lleva una serie informativa por interfaz — mikroscope_api_interface_info{interface,label,type,role,bridge,default_name} 1, para cada interfaz tenga o no comentario — y una consulta las une:

mikroscope_api_interface_counter_total * on(interface) group_left(label, type, role) mikroscope_api_interface_info

El inventario también le da sus nombres al log del kernel. Un registro del kernel nombra un puerto como eth1, la tabla de puertos de la placa lo traduce al nombre por defecto de RouterOS y el inventario traduce ese nombre por defecto al actual, así que quien haya renombrado ether5 a WAN lee WAN en el panel, con la etiqueta y el rol del puerto al lado. Sin la capa de la API un registro del kernel conserva el nombre por defecto de la placa y no recibe etiqueta.

Opción Por defecto Significado
--api host:port MIKROSCOPE_API_ADDR la API binaria de RouterOS, p. ej. 192.168.88.1:8728
--api-mode full off, slow o full, como arriba
--api-every 1s la cadencia de la ronda; 0 desactiva la capa
--interfaces MIKROSCOPE_INTERFACES, vacío interfaces separadas por comas para monitor-traffic, p. ej. bridge,ether1
--counters-every 10s cada cuánto leer los contadores acumulados de cada puerto; 0 nunca
--labels-every 5m cada cuánto releer qué es cada interfaz — comentario, tipo, listas de interfaces, bridge; 0 significa el valor por defecto
--conntrack-every 0 cada cuánto pedir el número de conexiones; 0 nunca, porque es un recorrido de tabla
--no-health desactivada omite /system/health

Sin --api, --api-user y MIKROSCOPE_API_PASSWORD, o cuando la sesión no se puede abrir en 10 s, forward registra api tier disabled: … y ejecuta solo la capa del kernel. Es un aviso, no un fallo: la capa del kernel es lo importante.

En cualquier modo las órdenes de la capa de la API son lecturas: basta un usuario con las políticas read y api. test solo hace falta para /tool fetch, que usa el transporte por relay y nada más de la capa de la API. El grupo, la restricción de dirección y por qué la credencial nunca vive en el router están en el usuario de la API.

La capa de la API guarda exactamente lo que devolvió el router y no se inventa nada para lo que no devolvió.

Tasas de pérdidas. monitor-traffic puede devolver rx-drops, tx-drops, tx-queue-drops, rx-errors y tx-errors por segundo, y un destino escribe cada una solo cuando volvió. En el RB5009 con RouterOS 7.24.2 (2026-09-15) devuelve las tres tasas de descartes y ninguna clave de errores.

Contadores de puerto. Los contadores por puerto son un mapa con los nombres de campo del propio RouterOS, no un conjunto fijo de campos, y solo se conservan los enteros sin signo simples que cuentan algo. mtu, actual-mtu, l2mtu, max-l2mtu y sfp-shutdown-temperature se leen como enteros pero son tamaños y configuración, y todo destino representa este mapa como una familia de contadores, así que se descartan aquí en vez de dejar que cada consumidor lo sepa; el MTU que importa viaja en el inventario. Las dos órdenes se fusionan por interfaz: /interface/ethernet/print stats aporta los errores tipados de la MAC, la familia de colisiones, los intervalos de tamaño de trama y los contadores del driver; /interface/print stats-detail aporta los contadores fp-* del fast path, link-downs, tx-queue-drop y los totales del lado del kernel. Una placa sin contadores de colisiones no produce entradas de colisiones en vez de una fila de ceros que se lee como «sin colisiones».

El motivo es una medida. El 2026-09-15 el ether1 del router de referencia tenía 652 364 eventos rx-overflow, en aumento, y monitor-traffic no devuelve ninguna clave de errores para ese puerto: esa cuenta solo llega a un consumidor por los contadores de puerto. Qué resultaron ser esos desbordamientos está más abajo.

Los contadores cubren todas las interfaces que lista el router, no solo --interfaces: el puerto en el que vive una avería suele ser uno que nadie pensó en vigilar, y el bucle de capa 2 del 2026-09-12 estaba en un puerto que no figuraba en la lista de monitor-traffic.

Son acumulados desde el arranque o desde el último reinicio del puerto, así que un consumidor los diferencia. La derivación que permiten, medida en ether1 (2,5 GbE hacia un NAS, 2026-09-16, desde el último reinicio del contador del puerto): 255,8 GB de rx-bytes en el cable, de los cuales 29,7 GB de driver-rx-byte llegaron a la CPU — el resto lo reenvió el chip de conmutación en hardware, y ningún contador de dentro del contenedor tiene un número para eso. El colector convierte los contadores del fast path que van al lado en una proporción del tráfico que cada interfaz entrega a la CPU.

Un puerto de switch y un bridge cuentan cosas distintas, y por eso el tipo viaja con cada fila. Un ether dentro de un bridge cuenta su cable, incluidas las tramas que el chip de conmutación reenvió sin la CPU; el bridge cuenta su propio lado de CPU; una VLAN o un enlace PPPoE cuentan lo que la CPU envió y recibió. ether1 y bridge son dos planos, ninguno subconjunto del otro: dibujados uno al lado del otro sin su tipo parecen iguales, y sumados cuentan dos veces. No los sumes nunca.

Etiquetas de interfaz. Con qué se etiqueta cada fila — el comentario, el tipo, el rol y el bridge — es el inventario de arriba, y una interfaz que el inventario no lista no lleva ninguna de ellas en vez de una identidad en blanco inventada.

Los contadores de puerto son el único sitio donde aparecen los desbordamientos del ether1 del router de referencia, y en quince horas dicen qué clase de suceso son. Medido el 2026-09-15 entre las 07:13 y las 22:20 UTC, sobre 4.471 lecturas consecutivas de los contadores cada 10 s en ether1 (2,5 Gbps hacia un NAS, MTU 9000):

  • 126 443 sucesos rx-overflow en total, presentes en el 40 % de los intervalos; por intervalo la mediana es 29, el p99 unos 1.036 y el mayor 3.747. En toda la tirada eso es el 0,53 % de los paquetes que envió el NAS.
  • Correlación de rangos sobre los deltas de 10 s: 0,85 con la parte de lo que recibe el NAS que el switch reenvió en hardware (rx-bytes menos driver-rx-byte), 0,00 con la parte que mandó a la CPU (driver-rx-byte).
  • Hacia dónde iba: ether8 (NGINX, 1 Gbps) se lleva casi todo el volumen y ether4 (Mastodon, 1 Gbps) es el destino más frecuente; la jaula SFP+, ether2, ether3 y el camino de la CPU no muestran nada.
  • Las tramas eran grandes: el intervalo de tamaño de trama de 1024 en adelante en ether1 tiene una mediana de 9.331 por intervalo con desbordamiento frente a 1.336 por intervalo sin él.
  • La carga no era alta: la mediana de lo que recibe el NAS en un intervalo con desbordamiento son unos 9 Mbit/s de media en 10 s. Ráfagas, no carga sostenida.
  • Nada del lado de la CPU: softnet descartó 0, time_squeeze correlaciona 0,04 y las interrupciones de switch0 0,05 con los desbordamientos, con los datos a 10 Hz del agente agrupados en intervalos de 10 s. Ninguna trama de pausa en ether1 en ningún sentido.

Leído en conjunto, encaja con ráfagas a la velocidad de línea de 2,5 Gbps conmutadas dentro del chip hacia puertos de 1 Gbps sin control de flujo en juego. Sin verificar: la semántica exacta de los contadores del chip de conmutación y la cuenta de retransmisiones del propio NAS — los contadores son del puerto, no de la conversación.

La capa del kernel no puede ver nada de esto por construcción. Una trama que el chip de conmutación reenvía en hardware nunca llega a la CPU, así que ningún fichero de /proc del router tiene un número para ella; hacen falta los contadores por puerto, y solo la API los tiene.

Medido en el RB5009 de referencia (RouterOS 7.24.2, 2026-09-16) con /tool profile duration=60s cpu=total, una vez con el colector parado y otra con él en marcha con --interfaces bridge,ether1,PPPoE_DIGI --counters-every 10s --api-every 1s. Las cinco primeras instantáneas de un segundo de cada perfil se descartan: llevan la conexión SSH que lo pidió.

Fila del perfil Colector parado Colector en marcha
total 5,93 % 6,04 %
interface-mgmt 0,40 % 0,87 %
config-db unos 0 % 0,15 %

El total se mueve 0,11 puntos, que está dentro del ruido del tráfico de un minuto; las dos filas que responden a las preguntas de la capa se mueven juntas medio punto. En ninguno de los dos perfiles aparece una fila de proceso api: el proceso de la API hace de intermediario y el trabajo cae en el subsistema que responde. Así que una capa que hace una ronda por segundo le cuesta al router en torno al 0,5 % de su CPU total.

Es poco, y aun así el proyecto sigue tratando la API como el camino caro. Los datos por puerto salen del contenedor siempre que el contenedor pueda verlos, y la configuración se lee al arrancar y con la cadencia lenta de las etiquetas, nunca en cada sondeo.

--conntrack-every 10s pregunta /ip/firewall/connection/print count-only con esa cadencia: 1,3 ms con 6 212 entradas en el RB5009 (fecha no registrada). Está apagado por defecto porque es un recorrido de tabla sobre una sesión de API, y con privileged=yes la cuenta slab nf_conntrack del agente es la misma población leída de un fichero a la cadencia del muestreador. Las dos no coinciden exactamente — se muestrean en instantes distintos, y el slab cuenta objetos que el asignador todavía retiene — pero se siguen: la API dijo 6 212 el día antes de que el slab dijera 6 287.