Ir al contenido

Probado en

Dónde se ejecutó, se midió o se comprobó cada parte de mikroscope: el equipo, la versión de RouterOS, la fecha y las condiciones, lo que encontró cada ejecución y lo que no se ha probado. Las guías dicen lo que hace la herramienta y enlazan aquí la prueba. Los veredictos de las funciones se contrastaron con el código de la 1.2.0 y de la 1.2.2 el 2026-09-24, los apartados que vinieron de las guías con el código de la 1.3.1 el 2026-09-26, y lo que esta página dice del código posterior a la 1.3.1, que es el que publica la 1.4.0, con ese código el 2026-09-27, y sus apartados sobre la publicación en Grafana, uninstall y las baterías de pruebas con el código de la 1.5.0 el mismo día; la versión actual es la 1.6.1.

Todas las cifras medidas en hardware de router que aparecen en esta documentación salen de un único MikroTik RB5009UG+S+: arm64, 4 × 1,4 GHz Cortex-A72 (r0p1), 1 GiB de RAM, Linux 5.6.3. Es el router de producción del mantenedor del proyecto, José Manuel Requena Plens, así que nada que necesite un reinicio se hace en él fuera de una ventana de mantenimiento, y no se le provoca ninguna tormenta de conntrack, que puede dejar sin acceso el camino por el que se está trabajando. No hay un segundo equipo físico. El único otro RouterOS que usa el proyecto es el laboratorio virtual. Qué RouterOS tenía en cada momento está en Equipos y versiones.

  • Ficheros de contabilidad (campaña kernel-2026-09-11): no hay /proc/pressure ni /proc/schedstat, y la columna irq de /proc/stat vale siempre 0, así que el tiempo de IRQ hardware se cuenta dentro de system. USER_HZ es 100, un tick de 10 ms.
  • Trazado: un contenedor de descubrimiento privilegiado no encontró el 2026-09-12 ni eBPF, ni kprobes, ni ftrace: ni BTF, ni debugfs, ni tracefs, y los puntos de montaje no existen. Una nueva comprobación el 2026-09-14 encontró /sys/fs/bpf presente y vacío y /proc/modules con 238 módulos cargados, pero ni /lib/modules, ni cabeceras del kernel, ni compilador en el equipo.
  • PMU, desde dentro de un contenedor privilegiado el 2026-09-12 (RouterOS 7.24.2): la prueba abrió cycles, instructions, cache-misses, branch-misses y bus-cycles a nivel de sistema en 4 de 4 CPU. En los datos del propio agente de las 24 h que terminaron el 2026-09-12, seis de los siete contadores que pide informaron en 4 de 4 núcleos, cache-references entre ellos, y branch-instructions no produjo ninguna fila. Los eventos genéricos stalled-frontend y stalled-backend devuelven ENOENT en el A72.
  • El trabajo que el tick no ve: en una muestra de 100,4 ms en la que /proc/stat no marcó ningún tick ocupado en ninguno de los cuatro núcleos, la PMU contó entre 2,2 y 4,6 millones de ciclos y entre 0,8 y 2,1 millones de instrucciones ejecutadas, con una tasa de fallos de caché del 3,8–5,7 % (registrado el 2026-09-12). Durante 2 s ese mismo día, las instrucciones por ciclo fueron de 0,381 en cpu0 a 0,992 en cpu1.
  • Privilegios: perf_event_paranoid vale 2 y no bloquea a un contenedor privilegiado, que conserva CAP_SYS_ADMIN efectiva frente al host (medido el 2026-09-12). Un contenedor sin privilegios ya tiene las 38 capacidades, y su root corresponde al uid 32768 del host, así que /proc/slabinfo y /dev/kmsg devuelven EACCES (RouterOS 7.24.2; la fecha de estas dos lecturas no consta). Con privileged=yes, el log del kernel, /proc/slabinfo, los contadores ECC de la MTD y la PMU se encontraron legibles el 2026-09-12 (RouterOS 7.24.2, kernel 5.6.3).
  • /sys/class/hwmon está vacío, incluso con privilegios. Las dos zonas térmicas, cpu-thermal y soc-thermal, son todo el conjunto de sensores del modelo base, y las dos se leen sin privileged. El /system/health de RouterOS en esta placa informa de exactamente un sensor, cpu-temperature, que es la zona soc-thermal truncada a grados enteros: un desfase medio de +0,55 °C durante los 8 minutos en que existieron las dos series (2026-09-14).
  • Las dos zonas declaran un polling_delay de 1 000 ms y un polling-delay-passive de 250 ms (leído el 2026-09-14), así que el kernel vuelve a leer el sensor a 1 Hz. El punto de disparo crítico declarado es 105 °C, leído de /sys (la fecha no consta). El sensor cuantiza en escalones de unos 0,42 °C (floors-overnight).
  • El gobernador de cpufreq marcaba userspace el 2026-09-14, y los clusters de cpufreq, leídos de related_cpus y affected_cpus dentro del contenedor ese mismo día (RouterOS 7.24.2), son {0,1} y {2,3}.
  • Globales dentro del contenedor (establecido el 2026-09-11, RouterOS 7.24.2, kernel 5.6.3): los ficheros de CPU, interrupciones, memoria y dispositivos de bloques, y /proc/net/softnet_stat. Un contenedor normal leyó además como del router, el 2026-09-12: las dos zonas térmicas, scaling_cur_freq por núcleo, /proc/yaffs y /proc/buddyinfo. /proc/device-tree/model dice RB5009 incluso sin privilegios.
  • Los del propio contenedor (campaña netns-2026-09-12): /proc/net/dev, /proc/net/snmp, /proc/net/netstat y nf_conntrack_count describían la veth del contenedor, 4 paquetes mientras el router reenviaba millones, y privileged=yes no cambió eso. El resto de esa frontera:
Qué Lo que ve el contenedor Leído
/sys/class/net solo lo y la veth; ningún dispositivo para ningún puerto frontal, privilegiado o no 2026-09-14
/sys/class/mdio_bus, /sys/class/phy mdio_bus solo contiene fixed-0; phy está vacío 2026-09-14
netdev_budget, netdev_max_backlog y las demás entradas globales de net.core ausentes; las entradas por espacio de nombres, como somaxconn, están presentes 2026-09-14
ficheros de /proc/net/* creados por módulos los del propio contenedor: fib_trie muestra solo el /30 de la veth, snmp6 cuenta sus paquetes 2026-09-15
nf_conntrack_max el techo real del router, 966 656, el mismo que RouterOS informa como max-entries 2026-09-14
tiempos de expiración de conntrack los valores por defecto de Linux (tcp_timeout_established 432 000 s frente al 1d de RouterOS) 2026-09-14
  • Los montajes del host no cruzan la frontera: ver el hecho verificado del 2026-09-15.
  • El registro de datos del equipo lleva los techos propios de la placa, nunca un número sacado de otro sitio: el techo de conntrack de 966 656 y el límite de memoria de 64 MiB del contenedor.
  • nbd0–nbd15 están presentes e inactivos y mtdblock0–2 dan todo ceros (2026-09-12, RouterOS 7.24.2, kernel 5.6.3; internal/dashboards/panels.go, el panel de E/S en curso de disco). La fila de /proc/yaffs o de /proc/diskstats de un dispositivo solo se guarda cuando su delta no es cero, lo que aquí ocurre unas pocas veces por minuto. El almacén InfluxDB de referencia seguía sin tabla de dispositivos de bloques, y sin tabla de PSI, el 2026-09-25, con RouterOS 7.24.4.
  • Los contadores ECC de la MTD están todos a cero tras años de servicio (la fecha de la lectura no consta).
  • /proc/slabinfo ocupa 13 833 bytes y 129 líneas por lectura (2026-09-14), el mayor análisis por tick, un orden de magnitud por encima de cualquier otro.
  • El log del router tenía 66 217 filas cuando record lo leyó, porque su tema dns registra a disco (la fecha no consta).
  • Tiene un disco tmpfs, que usa --ephemeral. Su cortafuegos raw lleva las dos reglas de descarte defconf: de MikroTik en su forma de listas, in-interface-list=!LAN y src-address-list=!LANs (Listas del firewall).
  • Nombres del kernel frente a nombres de RouterOS (Nombres de puertos): eth1 = ether2 por el bucle de capa 2 del caso real (2026-09-13). eth5 = ether6 y eth6 = ether7 el 2026-09-15: los dos puertos están comentados como Unused y ninguno estaba RUNNING, así que cada uno se apagó y se volvió a encender por la API mientras el agente leía /dev/kmsg. El kernel registró br0: port 7(eth5) entered disabled state dentro de la ventana de ether6 y port 7(eth6) dentro de la de ether7, con nueve segundos entre ellas, lo que descarta leer dos veces el mismo apagado. No se interrumpió ningún tráfico y los dos puertos estaban de vuelta en menos de cuatro segundos. Los seis pares deducidos y el switch se apoyan en un /interface/ethernet/print de solo lectura del 2026-09-13: direcciones MAC consecutivas, de …:55 para ether1 a …:5D para sfp-sfpplus1, en el orden de enumeración de RouterOS, y los nueve puertos declarando switch=switch1 frente al único switch0 del kernel. El device tree, analizado el 2026-09-14, muestra el ethernet@0 del SoC con tres MAC, solo eth0 habilitada (el enlace de subida de 10 G) y eth1/eth2 deshabilitadas; los nueve puertos del frontal son netdevs que el driver del switch crea en tiempo de ejecución. La tabla es la de esta placa, observada con RouterOS 7.24.2.
  • Las formas de registro del log del kernel para cada clase de suceso de puerto se vieron entre el 2026-09-12 y el 2026-09-15 (kernel 5.6.3).
  • Inventario (2026-09-16, RouterOS 7.24.2): las tres lecturas de configuración 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».
  • Contadores: 9 puertos × 45 contadores, y 15 en cada interfaz bridge, VLAN, PPPoE, WireGuard, veth o loopback, contados en las propias filas mikroscope_api_ifcounters del colector el 2026-09-24. La versión de RouterOS no se leyó con ellas; el router tenía 7.24.4 ese día.

El Cloud Hosted Router de MikroTik bajo QEMU, en un contenedor Docker, en la máquina en la que se construyó el laboratorio (x86_64, 12 núcleos, 27 GB de RAM, Docker 29.8, QEMU 10.0.13), aprovisionado en una instantánea limpia con el paquete container y device-mode container=yes. Medido el 2026-09-26 con RouterOS 7.24.4 y la CLI y la imagen del agente 1.3.1 publicadas:

  • CHR x86_64 con KVM: 2 núcleos, kernel 5.6.3-64.
  • CHR arm64 con la emulación TCG de QEMU, cortex-a72, 2 vCPU, 1 GiB: kernel 5.6.3, la arquitectura, la versión del kernel y el modelo de CPU del RB5009, a la velocidad del host.

Lo que muestra: corrección. Las órdenes de RouterOS que envía mikroscope y lo que responde RouterOS, la lectura que hace doctor del router, que RouterOS elija y descargue la imagen de su arquitectura, el arranque y la parada del contenedor, la detección de capacidades del agente, su formato de muestra y su anillo. Las rutas de instalación que se ejecutaron allí están en Rutas de instalación probadas.

Cómo llega el laboratorio a sus agentes: por una ruta estática. El lado LAN del laboratorio, 192.168.88.10/24 dentro del contenedor del laboratorio, tiene su ruta por defecto por el puente de Docker, no por el router, y llega a cada agente por 172.30.0.0/16 via 192.168.88.1, el valor por defecto de LAB_AGENT_ROUTES: el prefijo más amplio de Ruta estática. El 2026-09-27, la 172.30.10.0/30 por defecto y una instalación en 172.30.11.0/30 respondieron ambas a /healthz por ella.

Lo que no puede mostrar:

  • Una placa. No hay chip de switch, flash, sensores ni modelo en el device tree, así que no hay mapa de puertos. Las /capabilities del agente dan cpufreq, mtd, psi, schedstat y thermal ausentes en los dos, perf y kmsg presentes en los dos, y yaffs ausente en x86_64 y presente en arm64, un /proc/yaffs sin flash detrás.
  • Cadencias por encima de 10 Hz. La licencia gratuita de CHR limita lo que envía el router a 1 Mbit/s por interfaz: copiar 2 MiB desde el router por ether2 llevó 15,6 s, unos 1,07 Mbit/s, frente a 0,2 s hacia él. /stream midió 2 526 B por línea en el laboratorio, 0,21 Mbit/s a 10 Hz, así que 50 Hz está en el tope y 100 Hz por encima. No se midió ninguna de las dos.
  • Ningún coste en arm64. Con TCG el reloj del invitado sigue al del host, así que ninguna duración, ninguna cifra de CPU (cpu-load, self.cpu_us, read_ns, wake_ns, la dispersión de dt_ns, slipped), ninguna tasa de interrupciones, softirqs o cambios de contexto y ninguna cuenta de la PMU del laboratorio arm64 mide un Cortex-A72. El agente aguantó allí a 10 Hz, 3 003 ticks en 300,1 s con 1 retrasado y 1 202 en 120,1 s sin ninguno, y su tamaño residente de 14–16 MiB (32 MiB cargados a su cgroup) es solo orientativo.

Un bucle de rutas del propio laboratorio, ya corregido, hacía que el router emulado se arrastrara cada vez que algo sondeaba una dirección de agente sin veth detrás: antes de la corrección, install en arm64 tardó 38,4, 11,8 y 34,1 s, y el primero y el tercero salieron con 1 en una instalación completa. Las cifras de arm64 de aquí son de después de la corrección; las de x86_64 se tomaron antes. Lo que encontró allí la 1.3.1 está en Problemas conocidos.

En la máquina de arriba, desde la instantánea limpia. Cómo se ejecuta cada batería está en Baterías de pruebas.

  • Un arranque desde la instantánea hasta que responde ssh, 2026-09-26: 7 s en x86_64 (6,9, 7,2, 7,4 y 7,4 s) y de 26 a 28 s en arm64 (25,7, 26,6, 27,0 y 27,5 s).
  • make roundtrip, 2026-09-26: doctor, install, status, upgrade y uninstall, cada orden con --ephemeral, y el /export del router resumido con un hash antes y después. De 28 a 34 s en x86_64 en tres ejecuciones y de 40 a 45 s en arm64 en cuatro, con el export idéntico byte a byte todas las veces. Con el código de la 1.4.0, que hace un solo intento de uninstall, el 2026-09-27: 20 s en x86_64 y 35 s en arm64, una ejecución de cada una con los pasos de compilación de make incluidos, con el export idéntico byte a byte. Con el código de la 1.5.0 el mismo día: 21 s en x86_64 y 30 s en arm64, medidos igual, con el export idéntico byte a byte.
  • make test-lab con los escenarios de la 1.3.1, 2026-09-26: de 7 min 21 s a 9 min 49 s en x86_64 en seis ejecuciones y de 12 min 12 s a 16 min 48 s en arm64 en tres, las más lentas de cada una con las dos baterías en paralelo en un anfitrión ocupado. Ninguna instalación falló.
  • make test-lab con los escenarios de las opciones de instalación, con el código posterior a la 1.3.1, 2026-09-27: 28 min 32 s en x86_64 sola, y después 28 min 17 s en x86_64 y 57 min 29 s en arm64 en paralelo. Tras las correcciones que pidió la revisión, 29 min 2 s y 57 min 13 s en paralelo, con todas las pruebas superadas; las veinte desinstalaciones de S9 con un cliente en /stream, diez por arquitectura, quedaron limpias al primer intento, en 8,0 a 12,6 s. Ese mismo día S17 se ejecutó en un laboratorio CHR x86_64 con RouterOS 7.23.7: a doctor le faltó RouterOS 7.24 or later y leyó todas las demás comprobaciones.
  • RouterOS 7.24.4 cambia su propio /export: añade y quita por su cuenta una línea /system keymat-provider … name=default, así que la comparación de la batería deja esa línea fuera (2026-09-26).

El 2026-09-26, un corte de corriente hecho en cuanto una instalación recién hecha respondió no devolvió ningún agente en 90 s en tres de cuatro intentos en el laboratorio arm64. Los dos contenedores que se miraron no podían arrancar (Exec format error, Segmentation fault), muy probablemente porque RouterOS aún no había escrito la instalación en su disco; eso no se examinó. En x86_64 volvieron tres de tres. El escenario del arranque con el router, S7, espera 45 s entre la instalación y su corte, y solo pregunta si ese arranque funciona. S6 corta la corriente bajo una instalación --ephemeral en el disco tmpfs del laboratorio: después el contenedor sigue configurado y detenido, su raíz, su imagen y el manifiesto se han ido con el contenido del disco, el disco sigue ahí y vacío, y nada responde; uninstall --ephemeral no deja después nada en absoluto. Pasó en las dos arquitecturas en las ejecuciones del 2026-09-27.

El 2026-10-05, en el laboratorio x86_64 (CHR, RouterOS 7.24.4, KVM), el colector del código posterior a la 1.5.0 ejecutó forward --api-mode off --stdout json a través de un reinicio hecho con el propio /system/reboot de RouterOS, con el agente 1.5.0 instalado por la descarga de Docker Hub y arranque con el sistema. El agente volvió a responder unos 20 s después del reinicio; el colector registró agent restarted: its newest sample is 439 and the cursor was 1057; resuming from 1, y agent-restart saltó con su resumen de los 30 s anteriores: 300 muestras, CPU ocupada al 0 %, MemAvailable 767,5 MiB de 863,0 MiB, nf_conntrack 24 de 843 776, ninguna caída en softnet y después 16,2 s sin muestras. reboot no saltó: ningún registro del log del kernel tras volver el agente tenía un tiempo desde el arranque menor que el último de antes del reinicio. Una sola ejecución, en un router en reposo.

Más tarde ese mismo día, en el mismo laboratorio, el agente y el colector del código posterior a la 1.5.0 que lee el identificador de arranque del kernel (el agente del tar de la rama, con arranque con el sistema) ejecutaron siete minutos de forward --api-mode off --stdout json a través de una parada y un arranque del contenedor del agente y después un /system/reboot. El agente dentro del contenedor de RouterOS leyó el identificador y lo sirvió en /healthz. Tras /container/stop y /container/start (20,6 s sin muestras) el identificador era el mismo, y agent-restart lo dijo: the kernel's boot id did not change, so the router did not reboot; ningún reboot. Tras /system/reboot (16,5 s sin muestras) el identificador era nuevo: el colector registró router rebooted: the kernel's boot id went from 30b9831d-… to 8d4e19f2-…, y agent-restart y reboot saltaron con la primera muestra del agente con el mismo resumen (300 muestras, CPU ocupada al 0 %, nf_conntrack 24 de 843 776, ninguna caída en softnet). El log del kernel del arranque nuevo no hizo saltar un segundo reboot. Una ejecución de cada caso, en un router en reposo; el laboratorio arm64 no se ejecutó.

Lo que RouterOS escribe sobre un arranque se leyó esa misma tarde por la API, de /log/print, tras cada forma de tumbar el laboratorio x86_64. Tras /system/reboot desde una sesión SSH su buffer de memoria tenía router rebooted by ssh-cmd:admin@192.168.88.10/reboot (topics system,info); desde un script, …/script:rb/reboot; tras /system/shutdown y un arranque, …/shutdown; tras quitar la corriente (power-cycle), router was rebooted without proper shutdown (system,error,critical), y lo mismo tras el system_reset de QEMU (reset-button). Con una acción de logging que mandaba también el topic system a disco, un /log/print sin más devolvió además las líneas del arranque anterior, y /log/print ?buffer=memory solo las de este.

Después el colector del código que lo lee (forward --api-mode slow --stdout json, con la capa de API recibiendo las credenciales del laboratorio mediante LAB_CLI_API=lab) funcionó ocho minutos a través de un /system/reboot y un reset-button. Las dos veces la lectura salió bien en la lectura de salud que notó el identificador de arranque nuevo, antes de que la ronda propia de la capa de API reconectara (la lectura reabrió la conexión), así que reboot saltó con la primera muestra del agente, con RouterOS logged at boot: "router rebooted by ssh-cmd:admin@192.168.88.10/reboot" la primera vez y "router was rebooted without proper shutdown" la segunda, 19,4 s y 22,1 s sin muestras. Una ejecución de cada caso; la espera de dos minutos a una API que no ha vuelto no se ejercitó en un router, solo en las pruebas unitarias.

En el RB5009 (RouterOS 7.24.4), el agente 1.6.0 instalado el 2026-10-06 sirvió el identificador de arranque del kernel en /healthz desde dentro de su contenedor. El agent-restart de esa actualización dijo the kernel's boot id did not change, so the router did not reboot, que era cierto pero no se sabía: el agente 1.5.0 anterior no daba ningún identificador. En el código posterior a la 1.6.0 el primer agente que da un identificador después de uno que no lo daba no afirma nada sobre el kernel.

Un power-cycle del laboratorio no sirve para probar el colector: reinicia el contenedor del laboratorio, y un colector lanzado antes con mikroscope-lab cli conserva el espacio de red del contenedor viejo y no alcanzó nada tras el corte (no route to host hasta que terminó, el mismo día). El reinicio desde dentro conserva la red del laboratorio.

El 2026-10-05, en el laboratorio x86_64 (CHR, RouterOS 7.24.4, KVM), el doctor del código posterior a la 1.5.0 que añade los dos avisos se ejecutó contra el router del laboratorio preparado de tres maneras. Con allow-remote-requests=yes y ninguna regla de cortafuegos, avisó the router does not answer DNS from its uplink (…, uplink ether1: no rule drops a query that comes in on it). Con las dos reglas de input de la configuración por defecto (aceptar established,related,untracked, descartar in-interface-list=!LAN) añadidas diez segundos antes, pasó, nombrando el descarte !LAN; con solo in-interface=ether1 protocol=udp dst-port=53 action=drop también pasó. Con una regla de filter cuya lista de interfaces se había quitado y una regla de raw cuya veth se había quitado, nombró las dos bajo no firewall rule doctor reads is invalid or names a deleted list.

Lo que hace RouterOS con una regla cuya referencia desaparece se leyó por SSH el mismo día. Una lista de interfaces quitada bajo una regla dejó la regla válida, con in-interface-list=!*2000010; crear una lista con el mismo nombre no la cambió, y la regla contó paquetes como una regla que lo coge todo puesta al lado. Un descarte !LAN que se quedó así en la cadena input cortó el SSH del propio laboratorio desde la LAN hasta que se reinició el laboratorio. Una veth quitada bajo una regla dejó la regla inválida (in-interface=*4, about=vprobe not ready), y no contó ningún paquete. Una regla leída justo después de añadirla era inválida sin about, y válida cinco segundos después. RouterOS no deja añadir una regla que nombra una lista que no existe (input does not match any value of interface-list).

Para la colocación de la solución: place-before=0 falló desde una sesión SSH de una sola orden (no such item), y un place-before de la primera regla de la cadena input falló con la cadena vacía y funcionó con una regla en ella. Sin probar: IPv6, y una consulta DNS enviada desde fuera del laboratorio, cuyo enlace de subida es la red de usuario de QEMU; doctor lee las reglas y no envía ningún paquete.

En el RB5009 (RouterOS 7.24.4, 2026-10-06), el doctor de la 1.6.0 leyó 80 reglas activas en raw prerouting y en filter forward e input, ninguna inválida ni que nombrara una lista borrada, y dijo que la comprobación de DNS no tenía enlace de subida que evaluar: la ruta por defecto activa del router va por PPPoE, y su immediate-gw es la interfaz sola (PPPoE_DIGI), que la lectura del enlace de subida no contemplaba; el enlace DHCP del laboratorio se lee 10.0.2.2%ether1. Con esa lectura corregida, el código posterior a la 1.6.0 encontró PPPoE_DIGI en la lista WAN y evaluó las consultas como un quizá, porque la regla accept to local loopback (for CAPsMAN) de la configuración por defecto, dst-address=127.0.0.1, va antes de su drop all not coming from LAN y se leía como una aceptación posible. Tomando un destino de loopback como no coincidente para un paquete que llega de Internet, nombró defconf: drop all not coming from LAN como la regla que descarta las consultas. Cada una de las tres ejecuciones fue una sola conexión de lectura.

El laboratorio opcional que instala RouterOS x86 desde la ISO de MikroTik se ejecutó el 2026-09-26 con RouterOS 7.24.4. El router informó de la placa x86 QEMU Standard PC (Q35 + ICH9, 2009) y de una licencia de prueba sin nivel y con 24 horas por delante. La CLI 1.3.1 y el agente de la rama del laboratorio se comportaron como en CHR x86_64: a doctor le faltaron las mismas dos listas, una instalación desde el tar respondió al momento, status reconoció todos los objetos y uninstall verificó el router limpio, dejando el mismo directorio mikroscope vacío. Las /capabilities del agente fueron las de CHR x86_64.

El flujo se ejecutó por primera vez en los runners de GitHub el 2026-09-26, como el trabajo del laboratorio de la CI en el pull request #69: cuatro ejecuciones x86_64 entre las 21:06 UTC de ese día y las 00:45 UTC del 2026-09-27, cada una con las diez pruebas que tenía entonces la batería superadas (de 471,7 a 485,8 s) en un trabajo de 10 min 30 s a 13 min 30 s. De las tres ejecuciones de abajo, las dos primeras tenían la caché vacía, así que make lab-up descargó RouterOS y lo aprovisionó; la tercera tomó las descargas de la caché y aprovisionó una instantánea nueva.

Ejecución Commit Runner make lab-up Batería Trabajo
arm64, a petición sobre main e7efbbe, el laboratorio tal como se fusionó ubuntu-latest: 4 CPU, 15 989 MB, /dev/kvm presente 4 min 29 s: aprovisionamiento 83 s, un arranque de la instantánea 24 s 638,6 s, las diez pruebas de ese commit superadas 16 min 24 s
x86_64, pull request #70 3c34d9a, las opciones de instalación ubuntu-latest: 4 CPU, 15 989 MB, /dev/kvm usado por KVM 4 min 28 s: aprovisionamiento 46 s, un arranque de la instantánea 8 s 1 591,4 s (26 min 31 s), todas las pruebas superadas; S17 omitida, porque necesita un RouterOS anterior a 7.24 32 min 42 s
x86_64, pull request #70 1826aa5, con la credencial de registro ubuntu-latest, /dev/kvm usado por KVM 1 min 25 s: las descargas desde la caché, aprovisionamiento 76 s 1 633,1 s (27 min 13 s), todas las pruebas superadas; S17 omitida. El router descargó como la cuenta de Docker Hub del repositorio, S2 incluida; S1, S18 y los scripts de Docker Hub y de GHCR de S5 arrancaron sin ella 29 min 52 s

En las dos primeras de esas ejecuciones se cortó una descarga desde MikroTik (connection reset by peer) y se reanudó al primer reintento. La sonda de KVM en el runner arm64 de GitHub encontró ubuntu-24.04-arm con 4 CPU y sin /dev/kvm, así que el laboratorio arm64 sigue emulado en un runner x86_64.

Las dos ejecuciones en el pull request #70 lo retuvieron 30 y 33 min, y por eso lab.yml se ejecuta ahora solo cada semana y a petición, nunca en un pull request ni antes de una publicación.

En el commit de la publicación 1.4.0 (79b7c2f, una ejecución a petición el 2026-09-27, run 36329638066) la batería entera pasó en las dos arquitecturas: 1 517,2 s en x86_64 en un trabajo de 31 min 38 s, y 3 042,6 s en arm64, emulado, en un trabajo de 54 min 52 s. La imagen del agente 1.4.0 aún no estaba publicada, así que los trece casos de referencia que descargan su imagen descargaron la de la 1.3.1, como hace S5 antes de una etiqueta y dice en su registro.

En el commit de la publicación 1.5.0 (e61ffb6, una ejecución a petición el 2026-09-27, run 36344788569) la batería entera volvió a pasar en las dos arquitecturas: 1 573,2 s en x86_64 en un trabajo de 31 min 38 s, y 3 065,8 s en arm64, emulado, en un trabajo de 54 min 55 s. Los trece casos de referencia que descargan su imagen descargaron la de la 1.4.0, porque la de la 1.5.0 aún no estaba publicada, como registró S5.

Equipo Tipo RouterOS Cuándo Qué se ejecutó allí
RB5009UG+S+ hardware, arm64 7.24.1 hasta la actualización del 2026-09-10 el coste de una conexión SSH, 2026-08-26
RB5009UG+S+ hardware, arm64 7.24.2 del 2026-09-10 a más o menos el 2026-09-18 22:43 UTC la mayoría de las campañas, del 2026-09-11 al 2026-09-18
RB5009UG+S+ hardware, arm64 7.24.4 desde más o menos el 2026-09-18 22:43 UTC la campaña de errores de puerto, los tiempos de /stream, las gráficas del almacén de referencia y las órdenes de despliegue desde el 2026-09-21; upgrade con la 1.5.0 y la 1.6.0, doctor con la 1.6.0
CHR x86_64, laboratorio virtual virtual (KVM), amd64 7.24.4 2026-09-26 y 2026-09-27 doctor, plan, tres rutas de instalación, --expose, uninstall con la 1.3.1; la batería entera del laboratorio con el código posterior y en el commit de la 1.4.0
CHR arm64, laboratorio virtual emulado (TCG), arm64 7.24.4 2026-09-26 y 2026-09-27 doctor, plan, tres rutas de instalación, uninstall con la 1.3.1; la batería entera del laboratorio con el código posterior y en el commit de la 1.4.0
CHR x86_64, laboratorio virtual virtual (KVM), amd64 7.23.7 2026-09-27 doctor, que rechaza un RouterOS anterior a 7.24 (S17)
RouterOS x86 desde la ISO, laboratorio virtual virtual (KVM), amd64 7.24.4 2026-09-26 doctor, una instalación desde el tar, status y uninstall con la 1.3.1

Cuándo pasó el RB5009 a 7.24.4. La actualización en sí no quedó anotada, pero está acotada: la fecha de compilación de 7.24.4 es 2026-09-16 11:32:21; el 2026-09-24 el router informó de 7.24.4 con un uptime de 5d15h49m12s, un arranque hacia el 2026-09-18 22:43 UTC; y una actualización de RouterOS lo reinició a las 00:43:30 CEST del 2026-09-19, las 22:43:30 UTC del día anterior, tras lo cual la capa del kernel se reanudó a las 00:45:03. El uptime de la capa de la API en el almacén de referencia crece al ritmo del reloj desde el 2026-09-19 a las 11:13:35 UTC. Así que el router tiene 7.24.4 desde ese arranque como tarde. Las campañas fechadas del 2026-09-16 al 2026-09-18 constan como 7.24.2; la cota ni lo confirma ni lo desmiente. Ninguna de las medidas de 7.24.2 se ha repetido sobre 7.24.4.

Lo que se ejecutó sobre 7.24.4. doctor, plan, install, status y uninstall el 2026-09-21, con el agente instalado funcionando de forma continua desde el 2026-09-19. El 2026-09-23 se reprodujo en solo lectura la forma 1.2.x del aviso de registro de doctor, y su aviso de token con una instalación desechable que se expuso, se actualizó sin token y se retiró, así que upgrade también se ha ejecutado allí. Ese mismo día doctor leyó 600 muestras del anillo del agente en marcha y no encontró nada. El 2026-09-24 se le dio a RouterOS la referencia del agente con su host de registro dentro de remote-image= (dos hechos verificados). La capa de la API funciona sin parar sobre 7.24.4 desde el 2026-09-19; sus lecturas de inventario y de claves de pérdidas y su perfil de coste son de 7.24.2 (2026-09-15 y 16), y su prueba de reconexión y su A/B con 16 interfaces del 2026-09-19, tras la actualización de ese día, sin la versión anotada al lado.

Los ajustes del contenedor que escribe install se verificaron en el RB5009 con RouterOS 7.24.2 y se volvieron a ejercitar sobre 7.24.4; no se probó ninguna otra placa.

El agente del RB5009 se actualizó a 1.0.9 el 2026-09-19, a 1.2.0 a las 08:08:54 UTC del 2026-09-24 y a 1.2.1 y 1.2.2 ese mismo día, a 1.5.0 el 2026-09-27 y a 1.6.0 a las 07:15 UTC del 2026-10-06, cada vez con upgrade --remote-image; la última tardó 11,8 s desde la orden hasta la respuesta de la sonda. Los tiempos de /stream del 2026-09-21 son del agente 1.0.9.

De las cuatro plataformas que publica una versión, arm64 se ha ejecutado en hardware, el RB5009, y emulada en el laboratorio. amd64 solo se ha ejecutado en el laboratorio, en el CHR x86_64 y en RouterOS x86 desde la ISO, ambos bajo KVM, nunca en hardware x86. arm/v7 y arm/v5 nunca se han ejecutado en RouterOS: se compilan de forma cruzada, y la CI arranca cada imagen con -version bajo la emulación de modo usuario de QEMU (make agent-smoke), que no es RouterOS. Qué publica cada versión, y qué números de versión nunca llegaron a publicarse, está en Versiones.

Todo lo siguiente se ejecutó contra el RB5009 salvo que diga la batería de contenedores o el laboratorio: con RouterOS 7.24.2 si está fechado hasta el 2026-09-18, y con 7.24.4 si está fechado desde el 2026-09-19 (Equipos y versiones). Cada parte empieza por su veredicto y la fecha que lo respalda.

El agente funciona en el RB5009: el instalado estaba en marcha allí el 2026-09-23, cuando doctor leyó 600 muestras de su anillo. Lee /proc, /sys, /dev/kmsg y los contadores de perf_event_open del kernel compartido con un temporizador fijo de 1 a 100 Hz (10 Hz por defecto; 10, 20, 50 y 100 Hz medidos), guarda las muestras en un anillo y las sirve: /healthz, /capabilities, /snapshot, /stream, /sampler, y los endpoints de captura por disparo /captures y /capture. No sirve ningún /metrics; la exposición es la del colector.

Las seis órdenes de despliegue se han ejecutado en el RB5009 con RouterOS 7.24.4, las seis a más tardar el 2026-09-23, cada una con la CLI de su fecha. De la 1.4.0 en adelante solo se han ejecutado allí upgrade (la 1.5.0 el 2026-09-27 y la 1.6.0 el 2026-10-06, la segunda leyendo el manifiesto de instalación que escribió la primera) y doctor (1.6.0, 2026-10-06); el resto del código posterior a la 1.3.1, que es el que publica la 1.4.0, solo se ha ejecutado en el laboratorio virtual (2026-09-27). Según su código, la 1.5.0 no cambia ningún paso de las seis órdenes en el router; su uninstall rechaza --grafana-dry-run y lista los objetivos de Grafana y de los almacenes antes de tocar el router, ambas cosas comprobadas solo en pruebas unitarias (uninstall --targets). doctor, plan, install, status, upgrade y uninstall instalan, actualizan y retiran el agente, listando cada escritura antes de hacerla y verificando cada retirada por recuento de propiedad.

  • Ida y vuelta, 2026-09-12: doctor → install → status → upgrade → uninstall dejó el /export del router idéntico byte a byte (verificado). El agente respondió 3 s después de la instalación, con un tiempo de ida y vuelta de 5–7 ms: dos sondeos, 7 ms tras install y 5 ms tras upgrade, y el primero imprimió direct transport ok: agent 4857d0a-dirty, 10 Hz, seq 29, 0 slipped, 7ms round trip. Es una instalación en una red, no una cifra para otra. La ejecución pasó --ephemeral a doctor, install y upgrade, y es anterior a 1.1.0, desde la que uninstall solo retira con --yes. scripts/roundtrip.sh pasa ahora --yes a su desinstalación (hasta 1.2.0 no lo hacía, así que ahí solo listaba y su comprobación del export fallaba) y --ephemeral a todas las órdenes. En esa forma se ejecuta en el laboratorio como make roundtrip (Tiempos del laboratorio), y no se ha ejecutado contra el RB5009, donde es make roundtrip-device.
  • Rutas de instalación: cuatro rutas de principio a fin el 2026-09-17, y las del laboratorio el 2026-09-26, en Rutas de instalación probadas.
  • doctor por sí solo lee además una vez el anillo del agente en marcha y nombra cuatro fallos que las herramientas de RouterOS no muestran: un bucle de capa 2, cambios continuos de STP, un enlace que cae y vuelve y descartes de softnet. Si ningún agente responde en 3 s lo dice y lo omite, y lo que encuentra nunca cambia el código de salida. El 2026-09-23 leyó 600 muestras y no encontró nada; los cuatro fallos los cubren pruebas que reproducen el texto real de los registros y la cadencia de 2,0 s del bucle del RB5009, no un fallo en vivo. Su hallazgo de cambios de STP se apoya en cómo se ve un enlace sano al subir: en el ether7 del RB5009, cinco subidas de enlace el 2026-09-21 registraron cada una tres pasos a learning a la vez y llegaron a forwarding entre 2,1 y 2,8 s después, y en 30 días del almacén de ese router toda subida sana dejó learning menos forwarding en 0.
  • Sus comprobaciones WARN, que no cambian ni el código de salida ni que install siga adelante. Dos son anteriores a la 1.4.0: con --remote-image, un usuario puesto en /container/config cuando registry-url está vacío o nombra un host distinto del que se descarga la imagen; y una instalación con el mismo --name publicada en la LAN sin TOKEN en su entorno. Lee si hay un usuario puesto y cuántas entradas TOKEN existen, nunca un valor. La forma 1.2.x del aviso de registro se reprodujo en solo lectura sobre 7.24.4 el 2026-09-23; la comparación de hosts que la sustituyó solo ha avisado contra respuestas de router falsas en los tests. La 1.4.0 añade un WARN para una descarga en un router ARM de 32 bits, para una descarga con menos de 16 MiB libres por encima del memory-max del contenedor, para el arranque con el router cuando la raíz está en un disco tmpfs, para una regla de cortafuegos que puede descartar las respuestas del agente, para un --lan-address en el enlace de subida, para objetos etiquetados para la instalación que las opciones no seleccionan, y para una tabla de rutas o un cortafuegos que no pudo leer. De ellos, los avisos del tmpfs y de los objetos etiquetados saltaron en el laboratorio en CHR x86_64, RouterOS 7.24.4, el 2026-09-27; ninguno se ha ejecutado en el RB5009.
  • Extracción del tar, 7.24.2, 2026-09-11: un tar de 1,8 MiB, una compilación de esa fecha anterior a 1.0.0, se extrajo en el mismo segundo que su /container/add. La CLI de entonces borraba el tar tras una espera fija; la 1.4.0 espera a que el contenedor marque stopped, con --extract-timeout como límite.
  • Una instalación expuesta actualizada sin su token, 7.24.4, 2026-09-21: el upgrade pasó su comprobación, dejó las dos reglas en su sitio y escribió una envlist sin TOKEN, y /snapshot por la dirección LAN del router pasó de 401 a 200. Desde 1.2.0 doctor señala ese estado, y el código posterior a la 1.3.1 rechaza un upgrade así (laboratorio, 2026-09-27).
  • Un uninstall sin más de una instalación expuesta, 7.24.4, 2026-09-21: retiró todo lo demás, imprimió verified: nothing mikroscope created remains on the router y dejó el dst-nat apuntando a una dirección que ya no existía. El código posterior a la 1.3.1 lee del router la forma de la instalación, y un uninstall sin más retiró las dos reglas en el laboratorio (2026-09-27).

record, mark y plot funcionan de extremo a extremo, como muestra una grabación hecha en el RB5009 el 2026-09-12: 60 s a 10 Hz, exactamente 600 muestras, 0 huecos y −7 ms de desfase de reloj. Lo que mostró está en su campaña.

En el laboratorio el 2026-09-27 (CHR x86_64, RouterOS 7.24.4, la imagen publicada del agente 1.3.1), record --for 60s escribió 600 muestras, seq de 11 a 610, con 0 huecos. Tres notas de mark desde una segunda shell llegaron al mismo .markers.csv mientras record corría, y el resumen de record dijo 0 marker(s): solo cuenta las notas escritas en él. mark --log-markers por la API del laboratorio añadió 7 marcadores del log del router en la ventana, y plot dibujó las 600 muestras y 10 marcadores.

forward se ha ejecutado desde el RB5009 hacia tres de sus once destinos, fichero, Prometheus e InfluxDB 3, los tres a la vez el 2026-09-15; los otros ocho solo se han vuelto a leer desde productos reales en contenedores, desde el 2026-09-16. forward une la capa del kernel con la capa de la API de RouterOS y escribe en once destinos. Por Loki, OTLP, Graphite, Elasticsearch, SQL, PostgreSQL, Telegraf y stdout no han pasado muestras del router; la batería de contenedores escribe en cada producto real y lo vuelve a leer por su propia API (Baterías de pruebas).

  • 2026-09-12, ocho minutos: 4 800 muestras del kernel y 479 de la API reenviadas con 0 huecos y 0 descartes, ejecutando mikroscope forward --for 8m --prom :9124 --influx … --interfaces bridge,ether1,PPPoE_DIGI --conntrack-every 10s.
  • 2026-09-15, cinco ejecuciones de cadencia a 10, 50 y 100 Hz hacia un fichero, una exposición Prometheus e InfluxDB 3 a la vez: todos los destinos informaron de 0 huecos y 0 descartes (rates-2026-09-15).
  • Prometheus: un Prometheus 3.14 hizo scrape de la exposición del colector cada 5 s con el RB5009 alimentando el colector, el 2026-09-12 y de nuevo el 2026-09-15. No consta ningún otro intervalo de scrape ni ninguna otra versión de Prometheus.
  • InfluxDB 3: el primer destino real, el 2026-09-12, respondió 422: would exceed limit of 5 databases, el límite por nodo que InfluxData documenta para Core. Las ejecuciones medidas usaron una instancia de InfluxDB 3 Core propia. El 2026-09-19 el colector pasó a InfluxDB 3 Enterprise 3.11.4 y escribió 44 820 filas en 36 tablas en sus primeros 19 minutos, 0 descartadas y 0 errores. Todo lo anterior a esa fecha se midió contra Core.
  • El colector frente a un agente más rápido, 2026-09-21: con el agente a 100 Hz y otra vez a 50 Hz, /healthz daba rate_hz 100 y 50 y el propio registro del colector repetía esa misma cadencia, mientras que mikroscope_info{rate_hz} valía 10 en los dos casos; mikroscope_cpu_busy_ticks llevaba los cubos le="0" a le="11" más +Inf en los dos; y window="1s", window="10s" y window="60s" estaban los tres presentes en los dos.
  • Detecciones en el almacén de referencia, del 2026-09-19 a las 11:13 UTC al 2026-09-24 a las 08:26 UTC: saltaron cuatro de las once reglas, microburst 116 veces, ipc-collapse 41 (en los cuatro núcleos), link-flap 11 y agent-restart una. Solo de microburst se ha medido el comportamiento contra las muestras (microburst-replay-2026-09-16); las otras tres se contaron, sin cotejarlas con lo que hacía el router. Las 11 filas de link-flap están en ether1, ether2, ether4, ether6 y ether7, cada una con entre 2 y 6 registros de enlace en 60 s, todas sin provocar; no se comprobó cuál se debió a un cable, a un equipo del otro lado o a otra cosa.
  • Reinicios: el reinicio por la actualización de RouterOS del 2026-09-19 ejercitó de verdad la resincronización del colector (la capa del kernel se reanudó a las 00:45:03 CEST). No se comprobó si entonces se escribió una fila de mikroscope_detection para agent-restart, y el almacén que la habría guardado se sustituyó más tarde ese mismo día; el actual empieza a las 11:13 UTC. Guarda una fila de agent-restart, a las 08:08:54 UTC del 2026-09-24, con value 1 frente a threshold 4 338 037, cuando se actualizó el agente a 1.2.0.
  • Datos del equipo: enviados una sola vez al arrancar, los cuatro paneles del equipo muestran «No data» en toda ventana posterior: el 2026-09-17 la última fila de equipo del despliegue de referencia tenía 26 horas y esos paneles llevaban vacíos otro tanto. Repetidos cada cinco minutos, cuestan doce filas por envío en el RB5009.
  • La entrega durante 24 horas, 2026-09-17, en el despliegue de referencia: la mayor interrupción fue de 114,5 s, y la provocamos nosotros, un cambio de contenedor más el minuto que tarda el colector en notar que el agente se ha reiniciado. En funcionamiento normal el colector nunca se quedó atrás. Por eso el anillo guarda 60 s por defecto: cubre un reinicio de cualquiera de los dos lados en una LAN.

La capa de la API ha funcionado en una sola placa, el RB5009, sin parar sobre 7.24.4 desde el 2026-09-19.

  • Reconexión, 2026-09-19, tras la actualización de ese día, sin tocar el router: a un colector que ejecutaba monitor-traffic sobre 16 interfaces (todas salvo lo) a 1 Hz se le destruyó el socket de la API desde el host con ss -K, que es como se ve desde él el lado del router en un reinicio. La capa reabrió la conexión y reintentó dentro de la misma ronda: 0 comandos fallidos, 0 rondas perdidas, 16 interfaces en cada uno de los 108 segundos a ambos lados de la muerte del socket.
  • Lo que devuelve RouterOS: claves de pérdidas, una cuenta de rx-overflow que solo llevan los contadores de puerto, los dos planos de cuenta de un puerto del switch y su bridge, y las horas del log.
  • cpu-load es una media móvil de más o menos un segundo, ajustada contra /proc/stat (cpu-load-window-2026-09-15).
  • Lo que le cuesta al router: Coste de la capa API.

Todos los paneles de los cinco dashboards respondieron sin error en un Grafana real sobre los almacenes de la batería de contenedores (2026-09-17), y los dashboards de InfluxDB y Prometheus superaron dashboards check sobre los datos del propio RB5009 (2026-09-16). Hay uno por almacén, InfluxDB 3, Prometheus, PostgreSQL, Graphite y Elasticsearch, generados a partir de una sola lista de paneles. Graphite y Elasticsearch llevan menos paneles a propósito (39 y 28 frente a 177): Graphite no tiene etiquetas y Elasticsearch no tiene documentos anidados. Los paneles de PostgreSQL son los de InfluxDB reescritos, y la batería de contenedores hace que un PostgreSQL real planifique todas sus consultas. Las versiones de Grafana usadas son la 12.3.2 el 2026-09-12; la 13.2.1 en las pasadas en el navegador del 2026-09-12 y el 2026-09-14, check y renderizado el 2026-09-15, check el 2026-09-16 y la batería de contenedores; la 12.3.0 el 2026-09-21 y en los renderizados del 2026-09-25; y la 13.2.2 el 2026-09-24 y el 2026-09-25. No se ha probado ninguna otra versión.

  • 2026-09-12. En Grafana 12.3.2, el dashboard de InfluxDB contra un InfluxDB 3 Core aislado alimentado por forward desde el RB5009: todos los paneles devolvieron filas, entre 158 y 316 por panel en 10 minutos. El dashboard de Prometheus contra un Prometheus 3.14 haciendo scrape del colector cada 5 s: todos los paneles devolvieron filas, entre 228 y 2 052 en 5 minutos. Sin el campo token de la fuente de datos, los paneles fallaban con flightsql: Unauthenticated. Ese mismo día dashboards check --store influxdb --window 12h pasó en los 125 paneles que recorrió mientras unos 90 eran ilegibles en un navegador: leyendas que decían “value core 0”, dos xycharts atascados en “Loading plugin panel…”, una franja de continuidad que seguía en verde sobre 2 170 ticks perdidos. Un Overview de ocho paneles se renderizó con 2 188 px de alto en una ventana de móvil de 844 px, y 900 puntos de datos es el ancho que envió el navegador para las gráficas.
  • 2026-09-14. Un Overview de once paneles midió 1 052 px de alto en una ventana de navegador de 1 080 px, una pantalla de escritorio; un recorrido de renderizado contra una captura de 10,5 h del RB5009 renderizó 140 paneles de InfluxDB con 0 insignias de error y 0 “No data”; la fuente de datos de InfluxDB escapó $__interval_ms en cinco paneles, en el navegador, convirtiéndolo en un SQL que InfluxDB 3 no podía analizar; y una consulta que nombraba un campo que el almacén nunca había recibido falló al planificarse, No field named limit. Valid fields are …, a través del proxy de la fuente de datos.
  • 2026-09-15, Grafana 13.2.1: check, y un recorrido fila a fila sin interfaz de los dos dashboards en Chromium a 1600x1000, 0 insignias de error y 0 “No data” en 168 paneles de InfluxDB y 130 de Prometheus. No se ha repetido para los tres paneles que no cubrió: los dos de eventos de puerto y “What each interface is: type, role, bridge and label”. El mismo recorrido vio la proporción de fast path oscilar entre 0 y 100 % de una lectura a otra en interfaces que movían pocos paquetes. Regenerar ese día reprodujo byte a byte los ficheros del repositorio.
  • 2026-09-16, Grafana 13.2.1, contra el agente del RB5009 (RouterOS 7.24.2, privilegiado, los disparadores por defecto), forward --prom :9124 --influx … --interfaces bridge,ether1,PPPoE_DIGI --counters-every 10s durante 30 minutos hacia un InfluxDB 3 Core aislado, y un Prometheus 3.14 haciendo scrape del colector cada 5 s y del agente directamente para las familias que el colector no podía recalcular entonces:
Almacén Ventana Paneles Fallan Vacíos conocidos tolerados
InfluxDB 3 30 minutos 171 0 10 (los dos paneles de eventos de puerto, la consulta opcional de conntrack, los dos paneles de disparos, PSI, los cuatro dispositivos de bloques en reposo)
Prometheus 30 minutos 133 0 9 (los dos paneles de eventos de puerto, los dos paneles de conntrack de la API, PSI, los cuatro dispositivos de bloques)

Los 10 y 9 son ese despliegue sobre esa ventana. El SQL de los dos paneles de eventos de puerto se validó ese mismo día contra una tabla sintética en ese mismo InfluxDB 3, porque el almacén en vivo no tenía columna kind hasta que se le escribiera el primer registro de puerto clasificado; la tiene desde el 2026-09-19, con las ocho clases. La página de dashboards de esa fecha registró además que la exposición del propio agente llevaba la etiqueta kind solo cuando el propio agente clasificaba, cosa que el del RB5009 no hacía entonces; hoy los agentes no sirven exposición.

  • 2026-09-17, batería de contenedores: los cinco dashboards importados en un Grafana real sobre los almacenes que llenó la batería, preguntando a cada panel: devolvieron datos 57, 98, 136, 35 y 28 paneles, y no falló ninguno.
  • 2026-09-21, Grafana 12.3.0: import contra el almacén InfluxDB 3 en vivo y después check sobre una ventana de 15 min: 167 paneles devolvieron filas, los 9 vacíos conocidos salieron vacíos, y el indicador de detecciones del Overview salió vacío porque el almacén no tenía ninguna detección en esa ventana, que es el único caso que check señala y que un navegador lee como el «none» sano.
  • 2026-09-24, el Grafana de producción, cuyo endpoint de salud informaba de la 13.2.2 más tarde ese mismo día: el dashboard de InfluxDB importado y capturado a 390x844 y a 1600x1000 para comprobar el texto de 32 px de los paneles stat y la serie temporal de memoria. Con el tamaño automático de Grafana, un simple “0” se dibujaba de unos 60 px de alto a 390x844 y cada panel stat ocupaba cerca de un tercio de la pantalla; con el tamaño fijo, los números se leían a un tamaño normal en los dos. No se hizo recuento de insignias fila a fila, no se midió la altura del Overview y los otros cuatro dashboards no se capturaron.
  • 2026-09-25, Grafana 12.3.0, 13.2.1 y 13.2.2 sobre un InfluxDB 3.11.2 Core desechable:
    • La fila no disponible tal como estaba en 1.3.0 envió cinco consultas y pintó cinco insignias table … not found en 12.3.0 y 13.2.1; con sus consultas publicadas ocultas no envió ninguna ni pintó ninguna, y 13.2.2 hizo lo mismo en un segundo renderizado.
    • Una consulta de detecciones contra una tabla mikroscope_detection que falta no puede escribirse de forma que evite el error de planificación de InfluxDB 3: WHERE false, un UNION ALL y una guarda EXISTS sobre information_schema fallaron todas al planificar. En 13.2.1 la capa que falla no mostró nada en el dashboard y escribió en el log de Grafana una línea de nivel error Partial data response error por carga. 12.3.0 nunca envió la consulta de esa capa, con la tabla o sin ella (problema conocido).
    • Un import con sondeo desde 1.3.0 quitaba las consultas de un panel que faltaba, y Grafana 12.3.0 le da a un panel sin consultas una por defecto: el plugin de InfluxDB le respondió No SQL statements were provided in the query string, como una insignia roja. 13.2.1 no envió nada por ese mismo panel.
    • Elasticsearch 9.5.3: la búsqueda de la variable Host, escrita hasta 1.3.0 como un objeto JSON, salía de 13.2.1 y 13.2.2 como una consulta vacía respondida con 400 invalid query, missing metrics and aggregations, y 12.3.0 no la enviaba; abierto sin ?var-host=, seis paneles del Overview fallaban con Failed to parse query [host.keyword:]. Escrita como la cadena JSON que analiza la fuente de datos, Host se llenó desde el índice y ningún panel mostró insignia en ninguna de las tres.
    • Un panel de InfluxDB que agrupa con $__dateBin con un paso por debajo del segundo dibujó un bin de 0 segundos y volvió vacío, en check y en un navegador con el zoom en unos pocos minutos, en 13.2.1 y 13.2.2.
  • 2026-09-25, el Grafana 13.2.2 de producción contra el almacén InfluxDB 3 de referencia, con una compilación que oculta las consultas de la fila no disponible: dashboards check --window 1h, con el sondeo y con --no-probe, dio 164 paneles con filas, 12 vacíos conocidos tolerados y 1 fallo, “Detections in the window”, porque el almacén no tenía ninguna detección en esa hora. Sin el sondeo, los cinco paneles no disponibles salen como none … rows=0 frames=0 sin texto de error, donde 1.3.0 imprimía 400 … table … not found; los dos paneles de disparos respondieron mikroscope_trigger not found, porque ese almacén no tiene tabla de disparos. El SQL de la anotación de detecciones devolvió 44 filas en 6 horas. Repetido más tarde ese día, después de que los ficheros sin sondeo de los otros cuatro almacenes recuperaran sus consultas de la fila no disponible, dio los mismos recuentos, y la capa de detecciones 32 filas en 6 horas; el fichero de InfluxDB comprobado era idéntico byte a byte al de la primera vez.
  • 2026-09-25, batería de contenedores (Grafana 13.2.1, Prometheus 3.14.0, PostgreSQL 18.6, graphite-statsd 1.1.10-5, Elasticsearch 9.5.3): las consultas no disponibles de los ficheros del repositorio, contra almacenes que no tenían nada para ellas, respondieron todas 200 sin error, y en Elasticsearch todos los puntos fueron 0, tanto si otro router del mismo índice había mapeado el campo como si no. En PostgreSQL la consulta de la capa de detecciones respondió 200 sin filas sobre una ventana anterior a cualquier detección, y 10 filas sobre la de la propia ejecución. Las dos fueron consultas por la API de Grafana, no renderizados.
  • La continuidad se deriva del número de secuencia de cada muestra, y encontró 4 493 ticks perdidos y un reinicio en la captura del 2026-09-11/12 de los que el registro de huecos del colector no decía nada.
  • El rango por defecto es de 3 horas porque now-15m abría 108 paneles vacíos con el agente parado, y con el agente en marcha dibujaba muros de ruido ilegibles de muestras de 100 ms (la fecha no consta).

Solo la forma de InfluxDB 3 de las reglas se ha cargado en Grafana y se ha visto evaluarse, el 2026-09-21 contra el almacén del mantenedor; las formas de Prometheus y PostgreSQL nunca. Las reglas son 14 para InfluxDB 3, 15 para Prometheus y 10 para PostgreSQL.

  • La carga del 2026-09-21, en Grafana 13.2.1 contra el almacén InfluxDB 3 en vivo, tenía las doce reglas de InfluxDB de esa fecha y destapó dos defectos, los dos corregidos en 1.1.0. coalesce() sobre el agregado sin signo que escribe el destino de InfluxDB devolvía HTTP 200 sin marcos, que Grafana lee como NoData y estas reglas como OK: siete de las doce no podían saltar nunca, mikroscope-l2-loop entre ellas, mientras el mismo SQL contra /api/v3/query_sql devolvía 109 con la firma del bucle en vivo. Y la regla de conntrack nombraba limit_objs, la columna del destino SQL, donde el destino de InfluxDB escribe limit; la página de reglas de alerta había predicho ese defecto antes de confirmarse. Tras la corrección las doce devolvieron un valor, y mikroscope-l2-loop pasó a Alerting a las 16:58:50Z con la firma own-address en vivo; la lista de instancias de Grafana para esa regla seguía llevando Normal (NoData) de las 16:56:50Z, de la ejecución anterior a la corrección.
  • Consultas ejecutadas a mano contra el almacén en vivo el 2026-09-21: mikroscope-l2-loop dio 109 en su propia ventana de cinco minutos, con la firma own-address en ether2 corriendo sin parar a unos 0,5 registros/s desde el 2026-09-19; mikroscope-port-link-down dio 3 en la ventana que contiene una caída de enlace real en ether7 a las 16:33:49 y 4 en el grupo de cuatro de ether4 de las 09:19 del 2026-09-20. Las dos tienen umbral 0 con gt, así que las dos condiciones se cumplieron.
  • Las dos reglas que añadió 1.2.0 no estaban en esa carga, y ningún Grafana las ha evaluado desde entonces. Su SQL de InfluxDB se contrastó con datos pasados del almacén de referencia: mikroscope-bridge-port-dark devolvió 1 en tres ventanas dentro del bucle y 0 después, y marcó sfp-sfpplus1 en 204 intervalos de diez minutos y ether2 en 376 entre el 2026-09-19 11:13 y el 2026-09-23 22:44 UTC, las dos fases del bucle de capa 2 de esa semana, y ningún otro puerto. mikroscope-wakeup-storm devolvió 0,94–0,95 en dos ventanas sanas, nunca pasó de 1,81 en 551 ventanas de diez minutos con un día completo detrás (del 2026-09-20 al 23), y se abrió en 35,7 con la tormenta de despertares del 2026-09-23; se apagó cuando la nueva tasa pasó a ser la base, al cabo de unas cuatro horas. Su PromQL solo se comprobó en su sintaxis. De la forma PostgreSQL de la regla de despertares no consta ninguna ejecución, y la regla del puerto oscuro no tiene forma PostgreSQL: la 1.2.1 la quitó, porque la tabla de contadores de interfaz del destino SQL no tiene las columnas que lee.
  • La regla de detecciones ya no salta con microburst ni con ipc-collapse, que describen cómo lleva el tráfico un router sano: del 2026-09-23 10:30 al 2026-09-24 10:30 UTC en el RB5009 fueron 64 de 71 detecciones, y con ellas la regla saltó en 43 de 288 ventanas de cinco minutos; sin ellas, en 6.
  • La regla de salida: un puerto de 1 GbE hacia un servidor perdió 3 337 paquetes en seis ráfagas de un segundo a lo largo de 6,5 h, con picos de 436 paquetes/s (2026-09-19), visible en el panel de cola de salida y, con razón, sin ser una alerta.
  • La regla térmica lee el punto de disparo crítico de la propia zona, 105 °C en el RB5009.

forward --grafana se ha ejecutado contra el Grafana del mantenedor (2026-09-19, InfluxDB 3) y contra el de la batería de contenedores para los cinco almacenes (2026-09-20, y con el código de la 1.5.0 el 2026-09-27). dashboards publish solo se ha ejecutado allí, el 2026-09-27, sobre lo que forward --grafana acababa de crear. El 2026-09-20 se apuntó el colector a un Grafana real y a cada uno de los cinco almacenes por turno, se le dejó crear la fuente de datos, y después dashboards check pasó la consulta de cada panel por la API de Grafana contra la fuente de datos que había construido el colector. Los cinco respondieron sin error de fuente de datos tal como lo leía la prueba de esa fecha: buscaba flightsql: Unauthenticated, el error de TLS que se cita más abajo y err con un espacio a cada lado, que no es ninguna marca que imprima check, así que un error redactado de cualquier otra forma la pasaba. La misma ejecución encontró un defecto que ninguna prueba unitaria tenía: un colector que escribía en un PostgreSQL vivo por --postgres y en nada más no publicaba nada y decía «there is nothing to publish», porque la lista de almacenes solo conocía --sql. Contra un almacén InfluxDB en HTTP plano, una fuente de datos sin insecureGrpc respondía a todos los paneles tls: first record does not look like a TLS handshake mientras el almacén estaba perfectamente (medido el 2026-09-19).

El 2026-09-27 la prueba se ejecutó con el código de la 1.5.0 (el commit ffb934e, cuyo código Go es el de la publicación; la ejecución 36344009521 de e2e.yml) contra Grafana 13.2.1, InfluxDB 3.11.2 Core, Elasticsearch 9.5.3, PostgreSQL 18.6, Prometheus 3.14.0 y graphite-statsd 1.1.10-5, y para entonces fallaba con cualquier línea FAIL de check que llevara un error. Para cada almacén por turno, forward --grafana creó la fuente de datos y publicó el dashboard, check pasó cada panel contra esa fuente de datos sobre una ventana de 15 minutos, y dashboards publish, con las mismas opciones de almacén y de Grafana, salió con código 0, dio la fuente de datos como unchanged e imprimió la dirección del dashboard. Ningún panel que check cuenta como fallido llevaba un error; un panel que se espera vacío se marca none cuando no devuelve filas o devuelve un error, y la prueba solo lee esas líneas en busca de los dos errores de InfluxDB de arriba. La fuente de datos de Elasticsearch fue la del colector, con @timestamp como campo de tiempo (la de la 1.4.0 nombraba time, un campo que no lleva ningún documento), y su check salió con código 0; en InfluxDB, PostgreSQL, Prometheus y Graphite, 5, 20, 33 y 4 paneles no devolvieron filas en la ventana, sin error. No se ha probado en la batería: la cabecera Authorization que envía la fuente de datos de Elasticsearch, porque su Elasticsearch funciona sin autenticación; una fuente de datos que lleve un token o una contraseña, que ningún almacén de allí tiene; ni una ejecución que publique más de un almacén, porque cada ejecución publicó uno.

uninstall --targets retiró solo lo que escribió este proyecto en la batería de contenedores (2026-09-20, y --targets data de nuevo con el código de la 1.5.0 el 2026-09-27), y no se ha ejecutado contra el almacén de producción del mantenedor. La batería comprueba que una tabla que este proyecto no escribió, en la misma base de datos y el mismo esquema, ni se lista ni se borra. Ejecuta la orden solo con --targets data, contra PostgreSQL e InfluxDB 3, sin router y sin Grafana. Lo que la 1.5.0 cambió en la orden fuera de ese camino solo tiene pruebas unitarias: rechaza --grafana-dry-run, lista los objetivos de Grafana y de los almacenes antes de tocar el router, se detiene ante un Grafana que no pudo leer, que la 1.4.0 contaba como uno sin nada que retirar, y lee la dirección de Grafana de GRAFANA_URL cuando MIKROSCOPE_GRAFANA_URL no está definida.

Cuatro baterías no necesitan router: la unitaria y la de extremo a extremo se ejecutan en la CI en Linux, macOS y Windows contra árboles capturados y simulaciones, otra contra nueve almacenes reales en docker compose, completa por primera vez el 2026-09-16, y otra ejecuta la CLI y el agente contra un RouterOS virtual, en verde por primera vez el 2026-09-26 y ejecutada por primera vez en los runners de GitHub el mismo día. Qué demuestra cada una y cómo ejecutarla está en Baterías de pruebas.

  • De extremo a extremo: los dos binarios contra un árbol /proc capturado del RB5009 y un agente simulado, con un receptor por cada protocolo de destino que comprueba los bytes. No necesita router, ni Grafana, ni red, y se ejecuta en la CI tanto en macOS y Windows como en Linux, que es donde se notaría una diferencia en el nombre del ejecutable, en los ficheros que escriben los destinos de fichero y SQL, o en cómo se detiene un proceso hijo. Cada destino se prueba contra un receptor local desde el 2026-09-12, en el equipo de desarrollo amd64. La batería antes hacía scrape del agente y del colector, y ahora comprueba solo el colector.
  • Almacenes (make test-e2e-docker): el colector, contra el mismo agente enlatado y con la capa de la API apagada, hacia Loki 3, el OpenTelemetry Collector, graphite-statsd, Elasticsearch 9, Telegraf 1.39 por HTTP, PostgreSQL 18 (con --sql, y con --postgres desde que ese destino llegó el 2026-09-21), InfluxDB 3 y Prometheus, con el destino de fichero como el oráculo contra el que se comparan los demás. Cada almacén se vuelve a leer por su propia API, después se importan los cinco dashboards en Grafana y la consulta de cada panel pasa por la API de Grafana; la batería hace que forward --grafana publique las cinco fuentes de datos y comprueba sus dashboards contra ellas, después, desde el 2026-09-27, ejecuta dashboards publish con las mismas opciones de almacén y de Grafana, que tiene que salir con código 0 y nombrar la fuente de datos y el dashboard de cada almacén, y vuelve a vaciar los almacenes con uninstall --targets data. Necesita Docker y ningún router: las muestras son enlatadas, así que la ejecución es reproducible en cualquier máquina. La primera ejecución completa, el 2026-09-16, encontró un panel que nombraba dos columnas que el almacén solo tiene cuando se ejecutó la capa de la API: la tabla de eventos de puerto nombra label y role, que el destino escribe en una fila del registro del kernel solo desde el inventario de la capa de la API, y en InfluxDB 3 una columna que no está en la tabla hizo fallar la consulta con Schema error: No field named label, así que el panel no podía dibujarse. Las páginas de destinos registran el colector escribiendo en estos almacenes desde el 2026-09-17. En la máquina de desarrollo, el 2026-09-16, la pila se levantó en 55 a 81 s con las imágenes ya descargadas, y la batería entera tardó de 75 a 100 s desde cero. La batería entró en la ruta de los pull requests el 2026-09-18. Hasta entonces se ejecutaba cada semana, a petición y antes de una publicación, y así llegó la 1.0.5 a main con dos pruebas de la batería leyendo todavía el /metrics del agente, que esa versión había quitado: todos los checks del pull request estaban en verde, y lo encontró la puerta de publicación. En la ejecución de publicación que falló tardó 2 min 37 s desde el inicio del trabajo hasta el resultado, contenedores incluidos; en el pull request #70, el 2026-09-27, 4 min 9 s. El OpenTelemetry Collector, que acepta JSON, es el único receptor OTLP real contra el que se ha ejecutado el destino. El 2026-09-20 los destinos SQL y PostgreSQL, ejecutados en paralelo hacia dos bases de datos, tenían 34 tablas coincidiendo byte a byte, cada columna de cada fila con un hash por fila sumado, más un information_schema.columns idéntico para todo el esquema.
  • Laboratorio virtual de RouterOS (make test-lab): los verbos de despliegue de la CLI y el agente contra el Cloud Hosted Router 7.24.4 de MikroTik en QEMU, x86_64 y arm64 emulado: instalación por las dos vías de imagen, actualización, desinstalación, --ephemeral y start-on-boot a través de un corte de corriente, y cada escenario termina comparando el /export del router con el de su inicio. Prueba que el instalador es correcto; no es una placa, y ninguna cifra de Coste del agente ni de Campañas sale de él. El laboratorio, sus tiempos y sus primeras ejecuciones en los runners de GitHub están en Laboratorio virtual, y sus escenarios en Baterías de pruebas.
  • Fixtures de los destinos, no un router: los tamaños de SQL, OTLP, Graphite, Elasticsearch y Telegraf de Otros destinos salen de fixtures de pruebas de dos núcleos del 2026-09-12. La cabecera SQL de las cuarenta y tres tablas, generada por el propio header() del destino el 2026-09-19, ocupa 10 482 B, 13 966 B con las sentencias de hypertable de TimescaleDB. Doce renderizados de un mapa de 8 nombres dieron 7 órdenes (2026-09-12), registrado en internal/sinks/telegraf.go.
  • El equipo de desarrollo (amd64, kernel 6.12.107): TestParsePressureReadsTheRunningKernel y TestParseSchedstatReadsTheRunningKernel analizan el /proc/pressure/{cpu,memory,io} y el /proc/schedstat del propio equipo y los comparan con una segunda lectura de esos mismos bytes, y se saltan la prueba donde los ficheros no están, que es el caso del RB5009. En ese equipo pasan. Su /proc/pressure/cpu lleva línea full, toda a cero al volver a leerla el 2026-09-24: la documentación de PSI del kernel dice que el full de CPU no está definido para el sistema entero y que se publica desde la 5.13 a cero, así que un kernel más antiguo no tiene esa línea y el analizador acepta las dos formas. Su PMU, registrada el 2026-09-21, tiene seis contadores, cycles, instructions, cache-references, cache-misses, branch-instructions y branch-misses, multiplexados, cada uno funcionando en torno al 84 % del tiempo que estuvo habilitado. Un intervalo de 100,3 ms llevó allí 11 ticks (2026-09-11/12); sample_test.go comprueba que la fracción de ocupación está limitada a 1.
  • El rearme del filtro de cambios, contra el árbol de fixtures el 2026-09-15: las familias de medidores con suelo y mikroscope_slab_limit_objects estaban presentes en 6 de 6 scrapes desde 5 s después del arranque. El comentario de ProcSource.ReArm en internal/agent/source.go registra la misma comprobación como cuatro scrapes desde t+5 s, 0 antes de la corrección y 4 de 4 después; no consta de qué ejecución es cada cuenta.
  • El generador de scripts, 2026-09-27: pnpm run rsc:check renderiza en JavaScript los 20 casos de referencia de la especificación de pasos y compara byte a byte con la salida de Go cada script, las órdenes de cada paso, el orden de retirada, los valores y la línea de órdenes; un cambio de una línea en el renderizador le hizo informar de 72 fallos. pnpm test:generator hizo 168 comprobaciones en Chromium sin interfaz (Playwright 1.63) contra el sitio compilado: los 20 casos puestos con los propios controles del formulario, los errores, el token, copiar, el uso solo con teclado, ninguna petición de red, y las descargas .rsc, que funcionan bajo la CSP meta del sitio. Una comparación puntual con el código de Go sobre 304 juegos de opciones coincidió en 301; los otros tres son entradas que la página rechaza y Go acepta (un prefijo /030, un umbral busy>=.5 y una dirección IPv6 con IPv4 mapeada).
  • El sitio, 2026-09-25: Chromium 153 sin interfaz pidió solo favicon.svg, y resolvió un id de manifiesto ./ a la raíz del origen; en Chromium y WebKit sin interfaz, con los dos esquemas, tras elegir en el selector, tras una elección guardada y una recarga, tras el botón del teléfono y sin JavaScript, la etiqueta theme-color tuvo el color de la cabecera todas las veces, donde el par separado por prefers-color-scheme al que sustituye tenía el color del otro tema tras cada elección.
Ruta RB5009UG+S+ CHR x86_64, laboratorio CHR arm64, laboratorio
Descarga de Docker Hub, --remote-image 2026-09-17, 7.24.2: /healthz a 2 ms; la imagen 1.0.1, enviada sin su host y descargada a través de registry-url. 2026-09-24, 7.24.4: la referencia con su host, con un /container/add escrito a mano, sin arrancar; ningún install completo 2026-09-26: install en 9,6 s, descarga anónima con el /container/config de fábrica; 2026-09-27: S2, S4 y S5 2026-09-26: install en 10,3 y 10,2 s, descarga anónima; 2026-09-27: S2, S4 y S5
Descarga de GHCR, --remote-image 2026-09-21, 7.24.4: falló, auth error 2026-09-26: descarga sin credencial de registro y con el host en remote-image=, /healthz 5 s después de empezar la instalación; 2026-09-27: S18 y S5 2026-09-27: S18 y S5
plan --rsc, con /import 2026-09-17, 7.24.2: /healthz a 15 ms en sus primeras muestras, sin CLI en la instalación 2026-09-26: /healthz 14 s después de empezar la subida; 2026-09-27: S4, y los quince guiones de referencia que el laboratorio puede ejecutar (S5); el script por defecto pegado en el indicador ] >, y un script de tar sin su tar, que se detuvo antes de escribir nada 2026-09-26: /healthz 9,1 y 9,5 s después de empezar la subida; el script era el de x86_64; 2026-09-27: S4 y S5
Tar de la imagen, --agent-tar 2026-09-17, 7.24.2: el tar arm64 publicado, /healthz a 2 ms 2026-09-26: el tar amd64 de la versión, 6 s; 2026-09-27: el tar de la rama, S3 y diez instalaciones seguidas; el tar amd64 de la versión comprobado con sha256sum y cosign verify-blob, y después instalado y actualizado 2026-09-26: el tar arm64 de la versión, suma de comprobación como la publicada, 9,6 y 9,2 s; 2026-09-27: el tar de la rama, S3 y tres instalaciones seguidas
Generador de scripts sin ejecutar 2026-09-27: el script por defecto de la página, igual al de plan --rsc, y un script de tar con otros ajustes, cada uno descargado de la página compilada y pegado en el indicador ] >; el agente respondió cada vez, y el uninstall de la CLI y el script de desinstalación de la página dejaron cada uno el /export como estaba sin ejecutar
Instalación manual, terminal sin ejecutar 2026-09-27: las órdenes de la página una a una, descarga del registro y tar; /healthz respondió, status reconoció la instalación por su manifiesto, y la retirada de la página no dejó nada; de nuevo con las dos reglas de --expose, y con las dos pertenencias omitidas sin ejecutar
Instalación manual, WebFig sin ejecutar 2026-09-27: las dos vías de imagen, cada formulario enviado; /healthz 200 cada vez; la descarga retirada por WebFig, el tar por uninstall leyendo el manifiesto que escribió WebFig; el /export como estaba tras cada una sin ejecutar
Desde el repositorio 2026-09-17, 7.24.2: /healthz a 2 ms; la ida y vuelta del 2026-09-12 sin ejecutar sin ejecutar
--expose 2026-09-11: las dos reglas verificadas; 2026-09-23, 7.24.4: una instalación desechable expuesta, actualizada sin token y retirada 2026-09-26: /healthz 200, /capabilities 401 sin el token y 200 con él; 2026-09-27: S8 y S14 2026-09-27: S8 y S14
uninstall 2026-09-17: verificado por recuento de propiedad tras cada ruta; el /export tras las cuatro, idéntico byte a byte al de antes 2026-09-26, 1.3.1: fallaron 5 de 15 primeros intentos; un segundo lo limpió todo cada vez. 2026-09-27: cada primer intento limpio, tras cada ruta (F4) 2026-09-26, 1.3.1: 8 de 8 primeros intentos limpiaron; con un cliente en /stream falló. 2026-09-27: cada primer intento limpio, tras cada ruta (F4)
  • En el laboratorio, el 2026-09-27, con el código posterior a la 1.3.1 (la sección 1.4.0 del registro de cambios): la batería entera del laboratorio en las dos arquitecturas, con todas las pruebas superadas (Tiempos del laboratorio). Tras cada ruta, las de descarga y tar de la CLI, una instalación desde el tar y después una actualización, un guion de plan --rsc importado, cada guion de referencia que el laboratorio puede ejecutar e instalaciones hechas por la CLI 1.3.1 publicada, uninstall dejó el /export igual al tomado antes de instalar y ninguna ruta de mikroscope en /file. La descarga de GHCR del 2026-09-26 registró registry=ghcr.io, una capa de 3 093 207 bytes y download/extract done 2 s después, con /container/config sin registry-url ni usuario.
  • Las ejecuciones de las páginas de instalación, 2026-09-27, en el laboratorio x86_64, con el código posterior a la 1.3.1 y la imagen y el tar publicados del agente 1.3.1:
    • El script por defecto del generador respondió 8,8 s después de empezar a pegarlo. Su script de tar (nombre gen2, 172.30.11.0/30, puerto 9200, las dos listas none, cadencia 20, disparos busy>=0.9,oom, un token generado en la página, --expose en 192.168.88.1, --restart-max-count 3, --start-on-boot no) era idéntico byte a byte al de plan --rsc para la línea de órdenes de la página, respondió en 172.30.11.2:9200 y borró su tar tras la extracción.
    • El script por defecto de plan --rsc, idéntico byte a byte a pull-dockerhub.rsc, instaló un agente en marcha tanto pegado como subido y después con /import (Script file loaded and executed successfully). El script de tar sin el tar se detuvo con mikroscope: upload mikroscope.tar first y no escribió nada.
    • Las órdenes de la página de instalación manual por terminal, cada una por separado: las dos vías respondieron, la espera de la vía del tar borró el tar tras la extracción, y una instalación manual con tar también la retiró uninstall --yes sin más. Un buscar y reemplazar de los marcadores que también reescribió las claves de la envlist hizo que la retirada dejara la envlist entera, sin avisar, y por eso la página dice que se reemplacen solo los valores.
    • La misma página otra vez, cuando ya escribía un manifiesto por vía de imagen y daba a --expose una sección: una descarga del registro expuesta en 192.168.88.1 con token, una instalación con tar y una descarga del registro con las dos pertenencias omitidas. Cada manifiesto que escribieron sus órdenes fue idéntico byte a byte al de la CLI con los mismos ajustes (pull-dockerhub, expose-token, default-tar, lists-none); status leyó cada uno de su manifiesto, el expuesto con sus dos reglas como de la instalación; /capabilities respondió 401 sin el token y 200 con él; y la retirada de la página, primero las dos reglas, dejó la cuenta de sobrantes en 0 y /export, el residuo y /file iguales a la referencia.
    • Una instalación por WebFig dejó un /export igual al que dejó el /import del script de referencia, en las dos vías, salvo las dos direcciones MAC de la veth, que RouterOS elige al azar; status listó cada uno de sus objetos como de la instalación.
    • Las comprobaciones de la página sin conexión sobre los ficheros publicados de 1.3.1: sha256sum --ignore-missing -c checksums.txt OK y cosign verify-blob (cosign v3.1.3) Verified OK. Después install y upgrade --agent-tar con el tar amd64, 7 053 KiB subidos, y un uninstall limpio.
    • Instalaciones hechas por la CLI publicada 1.3.1: status leyó su forma de las etiquetas, upgrade --remote-image escribió un manifiesto, y uninstall --yes lo retiró todo, el directorio mikroscope/ de 1.3.1 incluido.
    • upgrade sin --remote-image ni --agent-tar buscó Go para compilar el agente: no toma la imagen del manifiesto. Un segundo install en un router ya instalado no creó nada (install done: 0 step(s) created).
  • Las ejecuciones de las páginas de configuración, 2026-09-27, laboratorio x86_64: doctor en un CHR de serie marcó MISSING solo la lista de interfaces LAN, con una solución que ofrece --iface-list none, y con las dos listas en none pasó cada comprobación. Las listas integradas se rechazaron antes de conectar. La comprobación de trampas contra los perfiles advanced-firewall y advanced-firewall-range nombró la regla que descarta las respuestas del agente, y su solución. Una lista de direcciones que no existía la creó la entrada de la instalación y ya no estaba tras uninstall. La primera ida y vuelta del sondeo marcó de 1,02 a 1,03 s en tres de seis instalaciones y 2 ms en las otras tres, y status un segundo después de 1 a 2 ms.
  • En el RB5009, el 2026-09-17, las cuatro rutas se ejecutaron una tras otra, cada una con su propio nombre, su veth y su /30 para no tocar nada de lo que ya había en el equipo, y cada una se retiró antes de la siguiente. /healthz se leyó desde el equipo del colector.
  • GHCR, el 2026-09-21, una segunda instalación junto a la que estaba en marcha, con su propio --name, --veth, --subnet y --port. La CLI de esa fecha ponía en remote-image= solo el resto de la referencia, así que registry-url se apuntó a https://ghcr.io para la ejecución y se restauró después; doctor se negó primero con MISSING registry-url is https://ghcr.io. Con el registro apuntando a GHCR el router creó el contenedor y falló la descarga: download/extract error: fetch manifest failed: getting https://ghcr.io/v2/jmrplens/mikroscope-agent/manifests/1.0.9 failed: auth error. /container/config guarda un único usuario y contraseña para todos los registros, y el del RB5009 es un login de Docker Hub. Desde el equipo del operador ese mismo día, contra el mismo paquete público, sin credencial devolvía 200 una vez obtenido el token anónimo, y con una credencial ajena 403 en el endpoint del token. La ejecución encontró además que una instalación con --remote-image identificaba su contenedor por la referencia del registro, la misma cadena en cualquier instalación, así que una segunda instalación en un router se negaba como si la primera fuera de otro; ahora se identifica por su veth.
  • Los límites de Docker Hub, leídos el 2026-09-24: 100 descargas anónimas cada 6 horas por dirección IPv4 o /64 IPv6, y el token anónimo lleva las mismas 6 h (pull_limit_interval 21600), mientras que la cabecera ratelimit-limit del registro en un HEAD del manifiesto del agente decía 100;w=3600. No se midió cuál de los dos aplica Docker. La cifra de una descarga por instalación sale de la regla de recuento de Docker y de una descarga hecha con curl desde el equipo del operador, no de una descarga de RouterOS.
  • Las fuentes de MikroTik sobre el registro por defecto, leídas el 2026-09-24: el changelog de 7.18 añade registry-url=https://lscr.io, el de 7.21.2 dice “changed default container registry to docker.io”, ningún changelog de 7.21.3 a 7.24.4 menciona el registro, y la documentación de contenedores sigue dando https://lscr.io/. El CHR del laboratorio con 7.24.4 no tenía registry-url ni usuario e informaba assumed-registry-url: docker.io.

Con los valores por defecto de la instalación, 10 Hz, suelos por fuente por defecto y un anillo de 60 s, el agente cuesta 2,69 % de un núcleo y 13,2 MiB de RSS, leídos de su propio cgroup en régimen estacionario con el anillo lleno:

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · ventanas de 300 s en régimen estacionario (con el anillo ya lleno), conjunto completo de fuentes, la configuración que se envía —anillo de 60 s, límite de memoria derivado de él y el tope de contenedor de serie de 64M— con el colector reenviando a InfluxDB 3

Las ejecuciones medidas
cadenciasuelosCPU de un núcleoµs/muestraRSSticks retrasadoshuecos / descartes
10 Hz (por defecto)por defecto2,69 %2 68513,2 MiB00 / 0

Eso está por encima del presupuesto de 2 % de un núcleo y dentro del de 16 MiB de RSS. La campaña del 2026-09-15 estaba por encima en los dos, con un anillo de 300 s y un límite de memoria fijo, antes de que 1.0.6 trajera el anillo de 60 s y el límite derivado. El presupuesto de imagen es 8 MiB; la imagen publicada de 1.2.1 para arm64 mide 6,38 MiB (image). El presupuesto es orientativo, no un contrato: el coste depende del equipo, del conjunto de fuentes y del tamaño del anillo.

Dos reglas mantienen honesta una cifra de coste. Espera primero a que se llene el anillo (BUFFER_S): en el RB5009, con un límite blando de memoria de 14 MiB, una lectura tomada en el primer minuto tras la instalación dio un 1,47 % de un núcleo frente a un 9,38 % en régimen estacionario. Y lee el coste del /metrics del colector, o de cpu_us y rss en mikroscope_self en el almacén que uses, en vez de un /snapshot grande, cuya respuesta de ~1,9 MB tiene que serializar el agente. El procedimiento está en Coste del agente.

Todas las filas se midieron en el mismo RB5009 a 10 Hz, y cada una es una ventana sin dispersión registrada.

Configuración CPU de un núcleo RSS Medido Nota
Cada fuente leída en cada tick 2,43 % no registrado 2026-09-12 por encima del presupuesto
Anillo lleno, MEM_LIMIT_MB 14 9,38 % (9 374 µs/muestra) no registrado 2026-09-12 un anillo de 300 s de líneas de unos 2,4 kB, la línea de esa fecha, ocupa ~7,3 MB; el GC de Go corre sin pausa
Anillo lleno, --mem-limit-mb 40, --memory-max 64M 1,39 % (1 388 µs/muestra) 25,13 MiB 2026-09-12 0 ticks retrasados
Contadores PMU activados, un forward en marcha escribiendo en InfluxDB 1,72 % no registrado 2026-09-12 0 ticks retrasados; 2 400 muestras reenviadas, 0 huecos, 0 descartes
Los valores por defecto de la instalación 2,69 % 13,2 MiB 2026-09-18 la cifra de arriba

Cada campaña en una entrada: el equipo, la versión de RouterOS, la fecha y las condiciones, las cifras que citan de ella las guías y lo que encontró. Una cifra de una guía enlaza aquí su campaña.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · ventanas de 300 s en régimen estacionario (con el anillo ya lleno), conjunto completo de fuentes, la configuración que se envía —anillo de 60 s, límite de memoria derivado de él y el tope de contenedor de serie de 64M— con el colector reenviando a InfluxDB 3

  • read.under2ms 97,7 %
  • read.floorOver5ms 1,45 %
  • read.100hz.meanMs 1,2 ms
  • read.100hz.worstMs 17,9 ms
  • load.ordinary 19 Mbit/s
  • run.10hz.cpu 2,69 %
  • run.10hz.rss 13,2 MiB
  • run.10hz.usPerSample 2 685 µs
  • run.10hz.slippedPct 0,000 %
  • run.20hz.cpu 4,61 %
  • run.20hz.rss 15,4 MiB
  • run.20hz.usPerSample 2 303 µs
  • run.20hz.slippedPct 0,000 %
  • run.50hz.cpu 9,63 %
  • run.50hz.rss 23,3 MiB
  • run.50hz.usPerSample 1 926 µs
  • run.50hz.slippedPct 0,000 %
  • run.100hz.cpu 16,83 %
  • run.100hz.rss 45,7 MiB
  • run.100hz.usPerSample 1 684 µs
  • run.100hz.slippedPct 0,017 %
  • run.50hz-floor.cpu 22,56 %
  • run.50hz-floor.rss 25,1 MiB
  • run.50hz-floor.usPerSample 4 511 µs
  • run.50hz-floor.slippedPct 0,027 %
  • run.100hz-floor.cpu 42,70 %
  • run.100hz-floor.rss 49,5 MiB
  • run.100hz-floor.usPerSample 4 270 µs
  • run.100hz-floor.slippedPct 0,593 %

Seis ventanas de 300 s, a 10, 20, 50 y 100 Hz y a 50 y 100 Hz con FLOOR_HZ, ninguna de las cuales perdió una muestra: Techo de muestreo tiene la tabla. La WAN llevaba de media unos 19 Mbit/s durante los 44 minutos de la campaña, con picos de 933 Mbit/s.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · ventanas de 60 s en régimen estacionario (con el anillo ya lleno), conjunto completo de fuentes, colector reenviando a la vez a fichero, a una exposición Prometheus y a InfluxDB 3

Cinco ejecuciones de cadencia a 10, 50 y 100 Hz con el colector escribiendo a la vez en un fichero, en una exposición Prometheus y en InfluxDB 3; todos los destinos informaron de 0 huecos y 0 descartes. El valor por defecto de la instalación a 10 Hz de esa fecha costaba un 2,85 % de un núcleo y 31,3 MiB de RSS, con un anillo de 300 s y un límite de memoria fijo de 40 MiB; 50 Hz necesitó --memory-max 96M y 100 Hz 128M. La WAN llevaba unos 30 Mbit/s, por la tarde. La cifra de la instalación por defecto que citan las guías es de rates-2026-09-18, no de esta campaña.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · 10 Hz, anillo de 300 s lleno, las mismas fuentes en las dos ejecuciones; solo cambian los límites de memoria

  • gc.tight.cpu 9,38 %
  • gc.tight.us 9 374 µs
  • gc.roomy.cpu 1,39 %
  • gc.roomy.us 1 388 µs

El mismo agente, anillo y fuentes con un límite blando de 14 MiB y después con margen: Coste por configuración tiene las dos filas.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · una línea del anillo con todas las fuentes activas, privileged, 10 Hz, 4 núcleos, IRQ_TOP_K=8 —incluidos el PMU y la propia temporización del muestreador, que la medición del 2026-09-12 no tenía

  • ring.lineKB 3,5 kB
  • ring.lineBytes 3 230 B
  • ring.lineChargedBytes 3 456 B
  • relay.maxBatch 13

3 230 B medidos, cobrados desde la clase de tamaño de 3 456 B de Go. Los 2 439 B del 2026-09-12 subestimaban el anillo un 35 %, y el agente funcionaba con 32,9 MiB de RSS donde bastaban 24,3. Una línea sin PMU cuesta un 35 % menos. El tamaño de las líneas con los suelos por fuente actuales no se ha medido.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · la línea media precodificada del anillo con todas las fuentes de esa fecha, las lentas refrescadas a 1 Hz, privileged, 10 Hz, 4 núcleos, IRQ_TOP_K=8

La línea media antes de que llevara la PMU y la temporización del propio muestreador, redondeada a unos 2,4 kB en las guías de esa fecha.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 · Linux 5.6.3 ·  · un bucle de shell de busybox leyendo a 10 Hz el conjunto de ficheros que leía entonces el agente, siete ficheros, con un fork por iteración, en un contenedor del router; dos ejecuciones de 60 s

  • busybox.cpu 2,40–2,48 %
  • procread.ms 0,77 ms

Dos ejecuciones de 60 s, 2,40 y 2,48 % de un núcleo, del cpu.stat del cgroup frente a /proc/uptime; las lecturas en sí tardaban unos 0,77 ms por muestra. No se ha vuelto a medir con el conjunto de fuentes actual del agente: Coste del agente.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.1 ·  · una conexión ssh, mientras dura

  • ssh.connectCpu 20–27 %

Medido antes de que existiera el agente, con RouterOS 7.24.1. Con 7.24.2, el 2026-09-11, el mismo coste apareció en /tool profile como un 17–33 % en una o dos instantáneas, no en una ventana medida: Coste de SSH.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · /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; descartadas las cinco primeras instantáneas de un segundo de cada perfil, porque llevan la conexión SSH que lo pidió

Un perfil de 60 s por condición, sin dispersión: Coste de la capa API.

· tar de la imagen arm64 de la versión v1.2.1 publicada, el fichero que carga el router

  • image.size 6,38 MiB

Medido con ls -l sobre el artefacto de la versión v1.2.1, con su suma de comprobación verificada contra el checksums.txt firmado: 6 690 304 B, de los que el binario del agente ocupa 6 684 832 B. Los tar de armv5 y armv7 miden 7 214 592 B y el de amd64 7 222 784 B. El trabajo agent-size de la CI mantiene el binario del agente, que es todo lo que lleva la imagen, por debajo de 8 MiB en arm64, armv7 y amd64.

fecha no registrada · tamaño de la imagen del agente de la versión 1.0.0

  • image.size.v100 6,1 MiB

La cifra que dan las notas de la versión 1.0.0; la v1.0.0 se etiquetó el 2026-09-16. Las imágenes entre ella y la 1.2.1 no tienen medida propia.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 · Linux 5.6.3 ·  · /proc/pressure y /proc/schedstat ausentes

La columna irq de /proc/stat vale siempre 0 en este kernel, así que el tiempo de IRQ hardware está dentro de system. USER_HZ es 100, así que un tick son 10 ms y los escalones de ocupación de las guías son aritmética a partir de él. Los ficheros que dentro del contenedor son del router se establecieron ese mismo día (Vista desde el contenedor).

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 · Linux 5.6.3 ·  · un contenedor de descubrimiento privilegiado leyendo una vez el /proc del host, antes de que el agente leyera slabinfo

  • conntrack.slabDiscovery 6 582

La ronda que no encontró ningún camino de trazado (Kernel y PMU), y cuyo slabinfo es el de testdata/proc/rb5009: nf_conntrack 6 582 activos de 8 075.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · privileged=yes no cambia el espacio de nombres de red

Dentro del contenedor /proc/net/dev contaba la veth, 4 paquetes mientras el router reenviaba millones, con privileged=yes y sin él.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 · Linux 5.6.3 ·  · una captura de 10,5 h a 50 Hz durante una noche en reposo, con el reloj fijo

  • thermal.quantumC 0,42 °C

La captura que fijó el suelo de 6 Hz al que se ralentiza /proc/slabinfo, la frecuencia a la que cambiaba su caché más rápida, nf_conntrack. Los niveles de memoria se movían unas 24 veces por segundo. Es una placa, una noche en reposo, con el reloj fijado en el ajuste del mantenedor: «cpufreq nunca cambió» significa que no cambió esa noche.

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

  • cpuLoad.window1 1,0 s
  • cpuLoad.delay1 0,6 s
  • cpuLoad.r1 0,9825
  • cpuLoad.samples1 3 499
  • cpuLoad.window2 1,1 s
  • cpuLoad.delay2 0,1 s
  • cpuLoad.r2 0,9734
  • cpuLoad.samples2 3 594

El mejor ajuste de cada hora: una media móvil de 1,0 s que llegó a la API con 0,6 s de retardo (r = 0,9825 sobre 3 499 muestras de la API), y una media de 1,1 s que llegó con 0,1 s de retardo (r = 0,9734 sobre 3 594). /system/resource publica cpu-load como un porcentaje entero, y la serie de la API se correlacionó con la proporción de ocupación por núcleo del agente, los mismos jiffies de /proc/stat, para una serie de longitudes de ventana y retardos. Ensanchar la ventana solo empeoró el ajuste: 1,5 s dio 0,955; 2 s, 0,919; 5 s, 0,822; y 8 s, 0,791. Una media de sesenta segundos queda descartada dos veces: su correlación es 0,238, y en el mayor salto de carga del día el kernel pasó de 5 % a 27 % en un segundo y cpu-load de 5 a 26 en ese mismo segundo, y de 22 % a 6 % al bajar con la misma rapidez. La documentación de /system/resource de MikroTik define cpu-load como el porcentaje de recursos de CPU usados, sumando todas las CPU, y no nombra ninguna ventana (leída el 2026-09-24).

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · un record de 60 s a 10 Hz, 600 muestras en 59,9 s, un bucle de script de RouterOS lanzado por ssh y el log del router añadido como marcadores

Exactamente 600 muestras, 0 huecos y un desfase de reloj de −7 ms. Un bucle de RouterOS por script (:for … 400 000) se vio como la carga de un núcleo entero al 100 % de t = 21,0 a 25,8 s, con la muestra de 25,8 s marcando alrededor del 60 %, y el inicio y el final resueltos a 100 ms. Los marcadores del log del router explicaron una meseta de 2 s entre 15 y 17 s que nadie había provocado: el planificador ensure-ipv6-nd-prefix. Las horas del log llegaron por la API como fechas completas (verificado).

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · un record de 70 s a 10 Hz, 700 muestras en 69,9 s, el router por lo demás en reposo, tres notas escritas en el terminal de record

La grabación de la que sale el gráfico de Línea base en reposo.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.4 ·  · tres conexiones GET /stream contra el agente instalado a 10 Hz, abiertas desde el equipo del operador en la LAN y mantenidas hasta que el servidor las cerró

  • stream.lifetime 30,01–30,06 s
  • stream.lines 304–306

Agente 1.0.9 a 10 Hz. Cada conexión terminó en el tiempo de escritura de 30 s del servidor, le quedara lo que le quedara por enviar, así que quien consuma /stream reconecta con el último seq que vio.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 · Linux 5.6.3 ·  · /tool fetch output=user llamado por la API binaria; cada llamada tardó o unos 3 ms o alrededor de 1 s, y más o menos la mitad tardó 1 s

  • relay.replyMaxBytes 64 512 B

/tool fetch output=user truncó el cuerpo sin avisar en 64 512 B con cuerpos de 64 K, 256 K, 1 M y 4 M.

Tamaño de una muestra en protocolo de líneas

Sección titulada «Tamaño de una muestra en protocolo de líneas»

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 · Linux 5.6.3 ·  · una muestra del kernel a 10 Hz renderizada en protocolo de líneas de InfluxDB, con el conjunto de fuentes que tenía el agente en esa fecha

Unos 1,2 KiB por muestra, la cifra a partir de la cual los destinos de InfluxDB y Telegraf dimensionan su presupuesto de bytes. No medido por encima de 10 Hz, ni vuelto a medir con el conjunto de fuentes actual.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 · Linux 5.6.3 ·  · agente a 10 Hz en un contenedor privilegiado efímero

  • loop.eventsBefore 1,49 /s
  • loop.eventsAfter 0,03 /s
  • loop.helloGap 2,00–2,01 s
  • conntrack.slab 6 287

Las lecturas sobre las que se construyen los casos reales, de un kernel aarch64 en una placa con 1 GB de RAM; donde se provocó un fallo, el caso real dice cómo. Tres casos llevan además un gráfico del almacén InfluxDB de referencia, cuyo historial empieza el 2026-09-19: la vuelta del bucle, la comprobación cruzada de conntrack y el puerto que pierde tramas. El puerto que pierde tramas es una campaña aparte, una semana después, leída en los contadores de puerto de la capa de la API y no en el agente. time_squeeze no era cero ni siquiera en reposo. Mientras el reflejo de capa 2 estaba activo, el log del kernel iba a 1,49 /s, y una pareja «blocking state» y luego «learning state» llegaba dentro de un mismo tick de 100 ms con el mismo nivel, así que su orden dentro del tick es la señal. La tabla de conntrack tenía 6 287 entradas, un 0,65 % del techo de 966 656 que el kernel informó el 2026-09-14.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · 3 738 704 muestras por CPU en 24 h a 10 Hz, time_squeeze de softnet por muestra, 0 descartes en toda la ventana

  • squeeze.backgroundOne 11,2 %
  • squeeze.backgroundTwo 1,2 %
  • squeeze.exactlyThree 0,21 %

Las 24 h terminaron a las 07:00 UTC del 2026-09-16. time_squeeze era 0 en el 87,3 % de las muestras por CPU, y una ventana móvil de esa distribución tiene un percentil 90 de 1, así que «por encima de p90» lo cumple cualquier 2. El 2026-09-15 una condición de disparo que salta ante cualquier squeeze saltó 92 veces en veinte minutos (RouterOS 7.24.2), y por eso squeeze no es un disparador por defecto.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · la regla reejecutada sobre 6 h de muestras almacenadas, 863 944 filas, 4 CPU

  • microburst.firesPerHourAtTwo 77,7 /h
  • microburst.firesPerHourAtThree 0,5 /h

Con suelo 3 la regla siguió marcando 88 muestras para el contador de ráfagas y para derived.burst.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 · Linux 5.6.3 ·  · la tabla de conexiones contada por la API binaria de RouterOS, /ip/firewall/connection/print count-only, diez llamadas

  • conntrack.api 6 212
  • api.conntrackMs 1,3 ms

La cuenta fue 6 212, el día antes de que el slab del agente marcara 6 287: el mismo orden de magnitud, que no dice nada de si las dos se siguen. Las diez llamadas tardaron una mediana de 1,3 ms, la más rápida 1,1 ms y la primera 71 ms, en frío; la hora no consta.

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · contadores de puerto y de interfaz de RouterOS leídos por la API, acumulados desde el arranque o desde el último reinicio del contador de cada puerto

ether1, 2,5 GbE hacia un NAS, había recibido 255,8 GB por el cable (rx-bytes) y había entregado 29,7 GB de ellos a la CPU (driver-rx-byte) desde el último reinicio del contador del puerto; el resto lo reenvió el chip de conmutación en hardware. Todos los puertos del switch daban una proporción de fast path de alrededor del 100 %, con fp-rx-byte igual a driver-rx-byte con unos pocos kB de diferencia. bridge había pasado por el fast path 211,9 GB de los 663,0 GB que llevó a la CPU desde el arranque (32 %), y PPPoE_DIGI el 99,97 %. fp-tx-byte estaba a 0 en todas las interfaces tras cientos de GB transmitidos (verificado).

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.4 ·  · ether1, el puerto de 2,5 GbE del NAS, en intervalos de contador de 10 s; las cifras de antes son las tres horas previas al arreglo y las de después los 39 minutos siguientes, con la misma carga

  • overflow.shareBefore 0,502 %
  • overflow.perHourBefore 5 399
  • overflow.occupancy 0,36 %
  • overflow.burstRate 8,96 Mbit/s

El caso real es Puerto que pierde tramas.

Medido sin campaña propia: el 2026-09-15 una ráfaga tuvo un pico de 736 paquetes en una muestra de 20 ms, una muestra a 50 Hz, frente a una mediana de 28.

Hechos de sí o no sobre RouterOS en los que se apoyan las guías, cada uno comprobado una vez, con dónde y cuándo.

Por la API binaria, /container/print devolvió todas las propiedades de todos los contenedores, cmd y envlist incluidas, a un usuario con solo read,api, el usuario mikroscope; solo se imprimieron los nombres de las propiedades, y no se comprobó si ese usuario lee los valores de /container/envs (RB5009UG+S+, RouterOS 7.24.2, ).

/tool fetch y /tool profile exigen ambos la política test (RB5009UG+S+, RouterOS 7.24.2, ).

En un find de RouterOS, los atributos de dirección y de puerto solo coinciden cuando su valor va entre comillas, y una palabra suelta se lee como nombre de variable: sobre las mismas 15 reglas dstnat (RouterOS 7.24.4, 2026-09-21), protocol=tcp encontró 0 y protocol="tcp" encontró 10 (RB5009UG+S+, RouterOS 7.24.2, ).

Una regla dst-nat más una regla accept en forward llegan al agente desde la LAN, y las dos se retiran por su etiqueta (RB5009UG+S+, RouterOS 7.24.2, ).

La LAN llega a la veth en cuanto la veth entra en la lista de interfaces LAN y el /30 en la lista de direcciones LANs (RB5009UG+S+, RouterOS 7.24.2, ).

/container/remove vuelve antes de que el contenedor haya desaparecido, y un /file/remove lanzado mientras tanto no hace nada, sin avisar (RB5009UG+S+, RouterOS 7.24.2, ).

Con ignore-remote-image-change=no, borrar el tar de la imagen hace que RouterOS detenga y elimine el contenedor y lo vuelva a extraer minutos después (RB5009UG+S+, RouterOS 7.24.2, ).

doctor, install, status, upgrade y uninstall, en ese orden, dejaron el /export del router idéntico byte a byte, salvo sus líneas de cabecera #, comparado por hash en memoria y sin escribirlo nunca a disco (RB5009UG+S+, RouterOS 7.24.2, ).

Un disco tmpfs aloja el tar de la imagen y la raíz del contenedor sin escribir en la NAND: write-sect-since-reboot se quedó en 58 279 durante la instalación, el funcionamiento y la retirada (RB5009UG+S+, RouterOS 7.24.2, ).

privileged=yes quita el espacio de nombres de usuario del contenedor, pero no el de red ni el de PID (RB5009UG+S+, RouterOS 7.24.2, ).

Un host de registro dentro de remote-image= manda sobre /container/config registry-url, y docker.io se descarga como registry-1.docker.io: con registry-url=https://registry-1.docker.io, una referencia en registry.invalid quedó registrada como registry=registry.invalid y falló con resolving error, mientras que la imagen 1.2.2 del agente escrita como docker.io/… y como registry-1.docker.io/… quedó registrada como registry=registry-1.docker.io y terminó en download/extract done, con su capa arm64 de 2 799 648 bytes; /container/config quedó igual que antes. Los contenedores se crearon en una veth temporal, nunca se arrancaron y se retiraron después (RB5009UG+S+, RouterOS 7.24.4, ).

Con el usuario y la contraseña de /container/config borrados, RouterOS descargó de Docker Hub la imagen 1.2.2 del agente de forma anónima, tanto como remote-image=registry-1.docker.io/… como sin host a través de registry-url=https://registry-1.docker.io, y las dos terminaron en download/extract done 5 s después del alta; después se restauró la configuración y se comprobó que era idéntica (RB5009UG+S+, RouterOS 7.24.4, ).

Por la API, /log/print devuelve el time de una entrada como fecha y hora completas y sin zona, 2026-09-12 02:21:24, y acepta ese formato en una consulta ?>time= (RB5009UG+S+, RouterOS 7.24.2, ).

/interface/monitor-traffic devuelve rx-drops, tx-drops y tx-queue-drops por segundo y ninguna clave de errores (RB5009UG+S+, RouterOS 7.24.2, ).

rx-overflow solo en los contadores de puerto

Sección titulada «rx-overflow solo en los contadores de puerto»

ether1 llevaba 652 364 sucesos rx-overflow, en aumento, en sus contadores de puerto mientras monitor-traffic no devolvía ninguna clave de errores para ese puerto: esa cuenta solo llega a un consumidor por los contadores de puerto (RB5009UG+S+, RouterOS 7.24.2, ).

Un puerto ether de un bridge cuenta su cable, incluidas las tramas que el chip de conmutación reenvió por hardware, y el bridge cuenta su lado de CPU, así que ninguno es un subconjunto del otro: desde el último reinicio del contador del puerto, ether1 había recibido 255,8 GB por el cable (rx-bytes) y había entregado 29,7 GB de ellos a la CPU (driver-rx-byte) (RB5009UG+S+, RouterOS 7.24.2, ).

fp-tx-byte marcaba 0 en todas las interfaces tras cientos de GB transmitidos, mientras fp-rx-byte sí contaba; no está establecido por qué RouterOS lo deja a 0 (RB5009UG+S+, RouterOS 7.24.2, ).

Rutas del host en un contenedor privilegiado

Sección titulada «Rutas del host en un contenedor privilegiado»

Un contenedor privilegiado con /proc, /sys y / del host montados leyó cero PID en el /proc del host y no encontró class/net en su /sys, así que los espacios de nombres aguantaron; el / del host sí se montó, y expuso el sistema de ficheros de la flash de RouterOS, configuración y ficheros, secretos incluidos. Se hizo con el consentimiento del mantenedor (RB5009UG+S+, RouterOS 7.24.2, ).

RouterOS presenta el usuario y la contraseña de /container/config para una referencia cuyo host es registry-url tal como está escrito: con una credencial errónea a propósito, la imagen del agente 1.3.1 nombrada como registry-1.docker.io/jmrplens/mikroscope-agent falló con auth error con registry-url=registry-1.docker.io, y se descargó de forma anónima con https://registry-1.docker.io, el valor de los ejemplos de MikroTik, y con el mismo terminado en barra. Un router al que se dio una credencial no volvió a intentar la descarga de forma anónima (CHR x86_64, RouterOS 7.24.4, ).

WebFig no tiene campo para ignore-remote-image-change

Sección titulada «WebFig no tiene campo para ignore-remote-image-change»

Los formularios New Container y de edición del contenedor de WebFig no muestran campo para ignore-remote-image-change, con File o Remote Image puestos o no; lo pone el terminal (CHR x86_64, RouterOS 7.24.4, ).

Un set del contenedor reinicia restart-policy

Sección titulada «Un set del contenedor reinicia restart-policy»

Un /container/set que no nombra restart-policy (de ignore-remote-image-change, de comment, de logging) la devolvió de on-failure a always sin cambiar nada más de lo que muestra /container/print detail; un set que la nombra la conservó, igual que Apply u OK en el formulario de edición de WebFig. La CLI nunca ejecuta /container/set (CHR x86_64, RouterOS 7.24.4, ).

WebFig muestra en claro el valor de una entrada de /container/envs, en la lista Envs y en su formulario, también con la clave TOKEN (CHR x86_64, RouterOS 7.24.4, ).

El menú System de WebFig no tiene página Device Mode, así que el modo de dispositivo se pone desde el terminal (CHR x86_64, RouterOS 7.24.4, ).

:put ([/tool/fetch url="http://172.30.10.2:9123/healthz" output=user as-value]->"data"), ejecutado en el router, imprimió el JSON de /healthz del agente, en una sesión ssh, en el terminal de WebFig y al final de un script pegado (CHR x86_64, RouterOS 7.24.4, ).

La pregunta de la licencia se lleva las primeras líneas

Sección titulada «La pregunta de la licencia se lleva las primeras líneas»

El primer inicio de sesión interactivo tras un reinicio pregunta Do you want to see the software license? [Y/n]: antes del indicador ] >. Un script pegado en esa pregunta perdió sus primeras líneas: una o dos líneas de comentario de la cabecera, y después un fragmento ejecutado como orden (bad command name . o syntax error); el bloque { … } del script de instalación se ejecutó igualmente e instaló, y el script de desinstalación retiró igualmente todo (CHR x86_64, RouterOS 7.24.4, ).

Lo que no cubre aquí ninguna ejecución, medida ni comprobación. Una guía que afirma una de estas cosas como comportamiento esperado enlaza esta lista.

  • Una segunda placa de cualquier tipo. El hEX S (2025), RouterOS de 32 bits sobre un chip ARM64, que es para lo que existe la compilación linux/arm/v5 del agente, no ha llegado, así que ni la ruta del desbordamiento de contadores de 32 bits ni ninguna de las dos imágenes ARM de 32 bits se han ejecutado en RouterOS. Un informe de placa desde otra placa es lo que cambia esto.
  • RouterOS x86 en hardware: la imagen amd64 solo se ha ejecutado en QEMU, en el CHR x86_64 del laboratorio y en RouterOS x86 instalado desde la ISO de MikroTik.
  • Ningún RouterOS anterior a 7.24 más allá de la comprobación de versión de doctor, que S17 ejecutó en un CHR con 7.23.7, y ninguna de las cifras de 7.24.2 vuelta a medir sobre 7.24.4.
  • Nada que necesite un reinicio del RB5009, que espera a una ventana de mantenimiento. Así que no está probado en hardware que una instalación persistente sobreviva a un reinicio con start-on-boot=yes. En el CHR del laboratorio volvió a responder en menos de 90 s tras un corte de corriente (S7, en las dos arquitecturas).
  • Qué ficheros están en un espacio de nombres en otra versión de RouterOS u otra placa: cada fila de Vista desde el contenedor se leyó en un único RB5009 con 7.24.2.
  • Una placa con sensores hwmon, o un RouterOS posterior que construya los contenedores de otra manera: el conjunto de sensores, las 38 capacidades y la correspondencia de uid se leyeron en un único RB5009 con 7.24.2.
  • La correspondencia de puertos en otra placa: el desplazamiento de uno, la posición de la jaula SFP+ y la reutilización de port 7 se observaron en un RB5009UG+S+ con 7.24.2, y el agente no los aplica a ninguna otra placa.
  • Los caminos de PSI y schedstat en un router: el kernel del RB5009 no tiene ninguno de los dos. El conjunto de contadores de la PMU solo se conoce en el Cortex-A72 del RB5009 y en el equipo de desarrollo amd64.
  • Cualquier cadencia de las fuentes en otro equipo o con otra carga: las cadencias son las del RB5009, con 7.24.2. Vuelve a medirlas con FLOOR_HZ igual a la cadencia del muestreador.
  • Qué claves de pérdidas y qué contadores devuelve otra versión de RouterOS u otra placa.
  • Lo que ahorra --goarm 7 frente a la compilación ARMv5: ningún hardware ARM ha ejecutado ninguna.
  • Las entradas de la envlist en un RouterOS anterior a 7.24: mikroscope escribe key=, porque name= falló en el RB5009 con 7.24.2, y no se probó cómo toma una u otra una 7.x anterior.
  • Un tráfico mayor que la carga corriente del RB5009: unos 19 Mbit/s en la WAN durante la campaña del 2026-09-18. No se afirma ninguna cadencia en otra placa.
  • En el RB5009, una descarga de GHCR sin credencial de registro, y cualquier descarga de GHCR con el host dentro de remote-image=: su única ejecución contra GHCR tomó el host de registry-url. El CHR del laboratorio hizo las dos con 7.24.4 (Rutas de instalación probadas).
  • Qué credencial presenta RouterOS a un host que solo se nombra en remote-image= cuando registry-url nombra otro. La única ejecución con un host distinto del de registry-url, el 2026-09-24, nombraba registry.invalid, que nunca se resolvió. Con el mismo host, el laboratorio mostró que RouterOS solo la presenta cuando registry-url se escribe como el host a secas (verificado).
  • En el RB5009: un install o un upgrade completo que envíe la referencia completa, un registry-url con su valor de fábrica y la referencia completa en cualquier RouterOS que no sea 7.24.4. El CHR del laboratorio ejecutó las dos cosas con la 1.3.1 sobre 7.24.4.
  • Una descarga a través de un espejo o una caché intermedia nombrados en la referencia.
  • install, status y uninstall de la 1.4.0 en adelante en cualquier hardware, y el script con sus guardas: solo se han ejecutado en los CHR del laboratorio. En el RB5009, el upgrade de la 1.6.0 leyó del router el manifiesto de instalación y la arquitectura (--arch auto), y su doctor ejecutó todas las comprobaciones.
  • --ssh-option y MIKROSCOPE_SSH_OPTIONS contra cualquier router: la CLI del laboratorio se conecta con el ssh_config propio del laboratorio, y solo las pruebas unitarias pasan la opción.
  • Que --extract-timeout se agote, lo que conserva el tar, en cualquier router.
  • La comparación de hosts de registro de doctor contra un router real: solo se ha ejecutado contra respuestas de router falsas en los tests.
  • Si un usuario read,api puede leer los valores de la envlist en /container/envs.
  • La ida y vuelta idéntica byte a byte en hardware: en cualquier placa que no sea el RB5009, en el RB5009 con cualquier RouterOS salvo 7.24.2, con install y upgrade sin --ephemeral, o con los ajustes actuales del contenedor (privileged=yes, memory-max=64M, las entradas de la envlist MEM_LIMIT_MB, CAPTURE_MB, TRIGGERS y FLOOR_HZ): en el RB5009 se hizo con memory-max=32M. Desde entonces install, status y uninstall se han ejecutado allí en 7.24.4. En el CHR 7.24.4 del laboratorio, make roundtrip la ejecuta con --ephemeral (2026-09-26); S2 y S3 ejecutan install, upgrade y uninstall sin él, con privileged=yes, memory-max=64M, MEM_LIMIT_MB y CAPTURE_MB, y S5 importa un script que además escribe TRIGGERS y FLOOR_HZ; cada uno termina con el /export igual al de su inicio, salvo la línea keymat-provider de RouterOS (las dos arquitecturas, 2026-09-27).
  • Cortafuegos distintos del del RB5009, donde el 2026-09-11 bastaron las dos pertenencias a listas, y de los perfiles del laboratorio. Un cortafuegos con otras reglas de descarte en raw, input o forward puede descartar el tráfico del contenedor en otro punto, e install no añade nada para eso más allá de las dos pertenencias. No se comprobó si la configuración de fábrica de un router lleva las dos reglas raw.
  • --expose desde fuera de la LAN: solo se probó una máquina de la LAN llegando a la dirección LAN del router. Si algo de fuera de la LAN llega a esa dirección depende del resto del cortafuegos, y no se probó ningún camino así.
  • Winbox: la página de instalación por WebFig dice que Winbox tiene los mismos menús y campos, y no se ejecutó ningún Winbox. Las reglas de --expose por los formularios NAT y Filter Rules de WebFig, un script entero pegado en el terminal de WebFig o de Winbox, y WebFig en cualquier RouterOS salvo 7.24.4.
  • Los scripts del generador, la instalación manual por terminal y la instalación por WebFig en el laboratorio arm64 o en el RB5009.
  • Una grabación por encima de 10 Hz: las ejecuciones sin pérdidas a 20, 50 y 100 Hz fueron del colector, que usa el mismo tamaño de lote. Una grabación a través del relay, a cualquier cadencia.
  • El rendimiento del relay. Con idas y vueltas de /tool fetch de cerca de 1 s en la mitad de las llamadas y unos 3 ms en el resto (medido en el RB5009 con 7.24.2), la aritmética da del orden de 26 muestras por segundo, menos cuando las llamadas lentas se agrupan. El límite del relay y el aviso de arranque están leídos del código (2026-09-15), no medidos en un equipo. El límite del relay y su fracción de 1 s en cualquier RouterOS salvo 7.24.2.
  • El coste de un disparo en el equipo; 3 µs para una ventana de 10 s a 10 Hz es la estimación del diseño. Cómo se comporta el agente bajo una tormenta sostenida de disparos. Cualquier captura a 50 o 100 Hz. Los tamaños de captura de Captura por disparo son aritmética a partir del tamaño de línea, no tamaños de capturas tomadas en el RB5009.
  • Destinos alimentados desde el RB5009 hacia un backend en marcha: solo fichero, Prometheus e InfluxDB 3. Loki, un receptor OTLP, carbon, Elasticsearch, OpenSearch, Telegraf, PostgreSQL y TimescaleDB no han recibido muestras del router en ninguna ejecución registrada. OpenSearch, las hypertables de TimescaleDB y la salida estándar nunca se han probado contra un almacén real; solo los cubren las pruebas de contrato de bytes.
  • Un Elasticsearch u OpenSearch que exija autenticación. El Elasticsearch de la batería de contenedores funciona con la seguridad desactivada, así que la cabecera Authorization que se construye a partir de MIKROSCOPE_ELASTIC_AUTH, autenticación básica para user:password y ApiKey en otro caso, no tiene ninguna ejecución registrada contra uno: ni desde el destino ni desde la fuente de datos de Elasticsearch que construyen --grafana y dashboards publish, que envía la misma cabecera desde la 1.5.0. Las pruebas unitarias fijan ambas formas, y la batería de extremo a extremo el ApiKey del destino contra un receptor simulado. Esa fuente de datos tampoco se ha ejecutado contra un OpenSearch, con autenticación o sin ella.
  • Un TimescaleDB real: las llamadas a create_hypertable siguen la firma documentada de TimescaleDB 2.x y no están verificadas.
  • El tamaño del destino SQL en un router. Las cifras del fixture (1 375 B de SQL para un evento del kernel frente a 716 B de protocolo de líneas, 1 138 B para un evento de la API frente a 608 B, unos 14 KiB/s a 10 Hz más la capa de la API a 1 Hz tras una cabecera de 5,6 KiB, 2 749 B con las fuentes privilegiadas) cubren dieciocho de las cuarenta y tres tablas que escribe el destino: once se añadieron después del fixture, y load, stat, buddy, mtd, api_ifcounter, api_ifinfo, trigger, derived, derived_iface, detection y las cuatro tablas device no se ejercitaron. Son anteriores a las columnas port y kind de mikroscope_event.
  • --sql - | psql con un psql que se queda atrás frente a un agente a 10 Hz, que bloquea el bucle de peticiones.
  • El presupuesto de la salida estándar para json, cuyas líneas son más grandes que las del protocolo de líneas.
  • Un renderizado OTLP de una muestra de cuatro núcleos con un top-K real de interrupciones, una muestra de cuatro núcleos en el formato de Elasticsearch, y el presupuesto de Graphite por encima de 10 Hz.
  • Una escritura en el /api/v2/write de InfluxDB 2. El tamaño en protocolo de líneas por encima de 10 Hz o con el conjunto de fuentes actual. Si desactivar el reenvío propio del cliente HTTP evita los duplicados del 2026-09-13.
  • La entrega de Loki durante una tormenta del log del kernel.
  • Cualquier intervalo de scrape de Prometheus que no sea 5 s, y cualquier Prometheus que no sea 3.14.
  • Los 10 Hz constantes del colector frente a un agente más rápido: la referencia de ráfagas y la poda del top-K están leídas del código; el peso EWMA de 1/600 y el desalojo a las 36 000 muestras no se han visto ocurrir nunca, porque ninguna ejecución hizo que una línea de interrupción cayera del top-K y siguiera fuera.
  • Los deltas a cero que se escriben junto a una proporción de fast path ausente (leído en internal/derive/derive.go), y un cambio de techo o de cadencia sin cambio de hash que llega a los destinos en la siguiente repetición de cinco minutos (leído en capsHash).
  • El coste de PMU por paquete comparado entre dos configuraciones del router. Si los diez segundos de la referencia de ráfagas sirven en otra placa u otra mezcla de tráfico: se ajustó contra un RB5009 en un solo día. Una proporción de fast path de tx a partir de contadores en vivo.
  • Detecciones provocadas con las reglas en marcha: ningún OOM kill en el contenedor, reinicio, flap de enlace, vaciado o tormenta de conntrack, excursión térmica ni colapso de IPC. Si reboot saltó en el reinicio del 2026-09-19. Un flap provocado con link-flap en marcha; los flaps del 2026-09-15 no lo estaban.
  • Si RouterOS calcula la ventana de un segundo de cpu-load sobre un reloj de pared o sobre jiffies. Si la cuenta de conntrack de la API y la del slab se siguen la una a la otra.
  • Ninguna de las seis herramientas de Comparado con alternativas se ejecutó para esa página. Cada celda de sus filas es lo que dice su propia documentación o su código, leído el 2026-09-24: mktxp en el commit 1e4412a (fechado el 2026-09-21), mikrotik-exporter en 428dbfc (fechado el 2026-07-03), y el fichero MIB que MikroTik publica para RouterOS 7.24.4. No se midió lo que le cuesta a un router el sondeo SNMP, The Dude, Graphing, el Profiler, mktxp o mikrotik-exporter, con qué frecuencia puede sondearlo cada uno con utilidad, ni qué pone RouterOS en hrProcessorLoad.
  • Cualquier Grafana que no sea 12.3.0, 12.3.2, 13.2.1 o 13.2.2. En 12.3.0 los únicos renderizados son los del 2026-09-25; el resto del dashboard se comprobó allí solo por consulta.
  • dashboards publish contra cualquier Grafana que no sea 13.2.1, y sobre algo que no sea lo que forward --grafana acababa de crear allí: en la batería de contenedores, el 2026-09-27, se ejecutó una vez por almacén, después del colector, sin credenciales en ninguna fuente de datos, y encontró la carpeta y cada fuente de datos tal como las había dejado el colector, y las dio como unchanged. Con dashboards publish, una ejecución de más de un almacén, un almacén que falla mientras los demás siguen, una fuente de datos que lleva un token o una contraseña (se escribe de nuevo en cada ejecución y se da como updated) y --grafana-dry-run solo se han ejecutado en las pruebas unitarias, contra Grafanas simulados.
  • La altura del Overview de trece paneles en un navegador; el JSON del repositorio le da 31 unidades de cuadrícula.
  • La regeneración byte a byte de los ficheros de dashboard añadidos después del 2026-09-15.
  • Las anotaciones y capas de detecciones de Elasticsearch y Graphite en Grafana: solo se comprueba su JSON generado, con pruebas unitarias.
  • Una pasada de renderizado sobre los dos paneles de eventos de puerto y la tabla de inventario de interfaces.
  • Que una regla se resuelva: el bucle del RB5009 terminó el 2026-09-23, pero no se ha comprobado en el historial de estados de Grafana la vuelta de mikroscope-l2-loop a Normal. No se ha visto a mikroscope-l2-loop ni a mikroscope-port-link-down pasar a pendiente, saltar y resolverse.
  • Las dos reglas que añadió 1.2.0 dentro de cualquier Grafana, su PromQL más allá de la sintaxis y el SQL de PostgreSQL de la regla de despertares.
  • Los ficheros de alertas de Prometheus y PostgreSQL en cualquier Grafana, y cualquier consulta de alerta de PostgreSQL contra un PostgreSQL real: una prueba unitaria lee el esquema, no una base de datos.
  • La entrega de avisos: no se configuró ningún punto de contacto, así que lo que se observó es el estado de cada regla.
  • Un almacén al que le falta una tabla o una columna que lee una regla: se espera que la consulta falle y que se aplique execErrState: Error en lugar de OK. Lo que hace entonces Grafana es su comportamiento de Error y No Data, no probado aquí.

Contrastado con el código el 2026-09-24, y el flujo del resumen final otra vez con la 1.3.1 el 2026-09-26:

  • El resumen final de forward va a stdout, el mismo flujo en el que el destino --stdout escribe los registros, así que forward --stdout=lp | telegraf termina cada ejecución con líneas que el consumidor no puede analizar.
  • Un --token erróneo no hace fallar la ejecución. Cada petición queda registrada como 401 Unauthorized, y la ejecución termina en el plazo de --for con código de salida 0 y forwarded 0 kernel samples. La comprobación de salud que hace forward antes de empezar a pedir datos lee /healthz, que no necesita token, así que la supera. El mensaje es correcto; el código de salida no le dice nada a un fichero de unidad.
  • Números de secuencia duplicados en la ejecución nocturna del 2026-09-13. La ejecución a 50 Hz escribió valores de seq repetidos en InfluxDB; los paneles llaman a esas filas “duplicate sample (seq repeated)”. La explicación más probable, sin verificar, es que el cliente HTTP de Go reenviaba un POST por una conexión reutilizada ya muerta después de que el servidor lo hubiera confirmado. Los destinos InfluxDB, Loki, OTLP, Elasticsearch y Telegraf rechazan ese reenvío, así que una conexión muerta es un error que el destino reintenta y contabiliza. Ninguna ejecución posterior a esa noche muestra si los duplicados han desaparecido.
  • Un tag negado dentro de un OR no devuelve nada, en silencio, en InfluxDB 3. El 2026-09-23, en el almacén de referencia (InfluxDB 3 Enterprise desde el 2026-09-19; la versión no se anotó con la consulta), NOT (port='ether2' AND kind IN (…)) sobre mikroscope_kmsg devolvió 0 filas donde coincidían 14, y lo mismo su forma de De Morgan y el OR explícito. Devolvió 14 en cuanto se filtró también port='ether2' fuera del OR. Los paneles y las reglas que se distribuyen no usan ese patrón.
  • Grafana 12.3.0 nunca envía la consulta de la capa de detecciones de InfluxDB, con la tabla o sin ella: su interruptor se quedó con un indicador de carga, apagarlo, encenderlo y refrescar no envió nada, y no se dibujó ninguna marca, ni en el dashboard completo ni en una copia de un solo panel (2026-09-25). Grafana 13.2.1 la envió en el acto sobre el mismo almacén. Por qué, y si 12.3.2 hace lo mismo, no se ha investigado.

Lo que encontraron la CLI y la imagen del agente 1.3.1 publicadas en el CHR del laboratorio, RouterOS 7.24.4, el 2026-09-26. Cada punto termina con lo que hace el código posterior a la 1.3.1, comprobado en el laboratorio el 2026-09-27; la 1.4.0 publica ese código, y la sección 1.4.0 del registro de cambios recoge cada cambio.

  • doctor con sus valores por defecto falla tres comprobaciones en un CHR. --arch vale arm64 por defecto, lo que falla solo en x86_64; la lista de interfaces LAN no existe; y la comprobación «has entries» de la lista de direcciones LANs falla con una lista vacía o inexistente, aunque su propio arreglo dice que una lista vacía está bien si no existe esa regla. Un router sin esa regla solo pasa dándole una entrada a la lista, o con --no-doctor, que se salta todas las demás comprobaciones. Tras la 1.3.1: --arch vale auto por defecto y lee la arquitectura del router, una lista de direcciones vacía ya no es un fallo, y una lista de interfaces que falta, todavía MISSING con los valores por defecto, tiene un arreglo que ofrece --iface-list none (S1).
  • Una lista de interfaces integrada como static, all o dynamic pasa la comprobación de existencia de doctor, y RouterOS se niega a añadirle un miembro. Tras la 1.3.1: --iface-list rechaza all, dynamic y static; RouterOS responde cannot add to builtin list.
  • --ephemeral necesita un disco tmpfs, y un CHR no lista ningún disco. El arreglo de doctor, /disk/add type=tmpfs tmpfs-max-size=64M slot=tmpfs, funcionó, y la instalación fue a tmpfs/mikroscope/mikroscope con start-on-boot=no. Tras la 1.3.1: igual, y doctor avisa además cuando se fuerza el arranque con el router sobre una raíz en un disco tmpfs, que un reinicio vacía.
  • uninstall compite con la parada del contenedor. Detiene el contenedor, espera 4 s fijos y lo elimina, y el agente tardó 0 s en pararse seis veces, 4 s cuatro veces y 5 s una (log de RouterOS, resolución de 1 s): 5 de 15 primeros intentos en x86_64 fallaron con failure: cannot remove running. Con un cliente en /stream falló siempre en las dos arquitecturas, porque el cierre HTTP del agente lo espera hasta 5 s. Los pasos siguientes se ejecutaron igualmente, y un segundo uninstall lo limpió todo cada vez. Tras la 1.3.1: la retirada espera hasta 30 s mientras el contenedor está running o stopping, y cada primer intento quedó limpio (Tiempos del laboratorio).
  • Un directorio mikroscope vacío se queda en /file después de cada uninstall: el padre del root-dir del contenedor, que el recuento de propiedad no incluye. Tras la 1.3.1: cada vía de instalación escribe un manifiesto de instalación, y uninstall quita lo que lista, y después el manifiesto y el directorio mikroscope/ cuando no queda nada más en él; tras ninguna vía quedó una ruta de mikroscope en /file (F4).
  • El sondeo posterior a install lee mal un contenedor en marcha sobre 7.24.4. Pregunta /container/find … status="running", y status no es una propiedad de /container allí (/container/find status=running responde bad parameter status), mientras que la marca running vale 1. Así que cuando falló el sondeo, la CLI dijo “the container is not running on the router” con el agente en marcha y a punto de responder. Visto dos veces en arm64. Tras la 1.3.1: el sondeo lee la marca running.
  • El listado del plan nombraba un tar con --remote-image: image=mikroscope.tar, un fichero que install nunca sube, e imprimía la subida o la descarga como un paso propio con el número del paso del contenedor, así que dos pasos compartían número. Tras la 1.3.1: image= nombra la referencia que descarga el router, y la descarga o la subida es una línea del paso del contenedor.
  • El token del agente viajaba en la línea de órdenes de ssh, donde la tabla de procesos del anfitrión lo mostraba mientras la orden se ejecutaba: el código de la 1.3.1 lo mostró en dos líneas de órdenes. Tras la 1.3.1 una orden que lo lleva va a ssh por la entrada estándar; leer la tabla de procesos cada 2 ms durante una instalación y una actualización con --expose no lo encontró en ninguna, en las dos arquitecturas.
  • Las palabras de RouterOS se perdían cuando su ssh salía con 1: el error decía ssh "<script>": exit status 1, y el mensaje de RouterOS, en las líneas siguientes, lo descartaba la línea de omisión de uninstall. El ssh de RouterOS salió con 1 o con 0 ante el mismo fallo, más o menos a partes iguales. Tras la 1.3.1 el error empieza con lo que imprimió RouterOS.

Dos ficheros legibles del RB5009, leídos allí el 2026-09-15, no se recogen: /proc/cmdline, que lleva board=5009 ver=7.24.1, una segunda identidad del equipo sin la API, y el watchdog hardware en /sys/class/watchdog/watchdog0.