Полный мониторинг роутера Mikrotik через SNMP и VizIoT

Профессиональное сетевое оборудование, такое как роутеры Mikrotik, предоставляет огромное количество данных о своём состоянии: от температуры процессора и скорости вентиляторов до трафика на каждом из десятков портов. Но как собрать всю эту информацию в одном месте и превратить её в наглядные графики для анализа?

В этой статье мы создадим комплексную систему мониторинга для роутера Mikrotik с помощью протокола SNMP, а все собранные данные будем отправлять в VizIoT для построения информативной панели. Вы сможете в реальном времени отслеживать состояние оборудования, нагрузку на сеть и быстро выявлять проблемы.

Конечный результат: Ваша собственная панель управления сетью

Прежде чем мы начнём, взгляните, какую мощную и наглядную панель мониторинга мы создадим. Она позволит отслеживать всё: от общего времени работы и статуса блоков питания до детальной загрузки каждого SFP-порта.

  • Общее состояние: Uptime, температура, скорость вентиляторов, статус блоков питания.
  • Суммарный трафик: Агрегированная скорость приёма и передачи данных по всем портам.
  • Детальная загрузка портов: Индивидуальные графики для каждого SFP и SFP+ порта, позволяющие видеть, какие каналы наиболее загружены.

Заинтересовались? Давайте настроим такую систему. Это проще, чем кажется.


Что потребуется

Оборудование и ПО

  • Роутер Mikrotik: С включенным SNMP-сервером.
  • Компьютер для сбора данных: Любое устройство с Linux или Windows, которое будет постоянно включено (например, Raspberry Pi или небольшой сервер).
  • NodeJS: Среда для запуска нашего скрипта-сборщика.
  • PM2: Менеджер процессов для надёжного автозапуска скрипта.

Шаг 1: Включение SNMP на роутере Mikrotik

Протокол SNMP (Simple Network Management Protocol) — это стандартный способ для сетевых устройств предоставлять информацию о своём состоянии.

  1. Зайдите в панель управления вашего роутера Mikrotik (например, через WinBox или веб-интерфейс).
  2. Перейдите в раздел IP -> SNMP.
  3. Поставьте галочку Enabled.
  4. В поле Community по умолчанию используется public. Это имя сообщества, которое работает как пароль. Вы можете оставить его или изменить, но убедитесь, что оно совпадает с настройками в нашем скрипте.
  5. Нажмите Apply.

Теперь ваш роутер готов отдавать данные по SNMP.


Шаг 2: Настройка устройства в VizIoT

  1. Создайте новое устройство, например, Mikrotik Router.
  2. В разделе Основные настройки скопируйте Ключ доступа и Пароль доступа. Они понадобятся нашему скрипту.

Шаг 3: Подготовка среды и создание скрипта

На компьютере, который будет собирать данные, установим всё необходимое.

Установка NodeJS через NVM

Подробная документация: https://nodejs.org

  1. Установите NVM:
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
  2. Активируйте NVM (без перезахода в систему):
    \. "$HOME/.nvm/nvm.sh"
  3. Установите последнюю версию Node.js:
    nvm install 24
  4. Проверьте установку:
    node -v
    npm -v

Создание проекта

  1. Создайте директорию для проекта:
    mkdir mikrotik-monitor
    cd mikrotik-monitor
  2. Инициализируйте NodeJS-проект:
    npm init -y
  3. Установите необходимые библиотеки:
    npm install net-snmp big-integer viziot-mqtt-client-nodejs

Создание скрипта-сборщика

Создайте файл index.js:

nano index.js

Вставьте в него следующий код. Не забудьте указать ваши данные в секции CONFIG.

const snmp = require("net-snmp");
const bigInt = require("big-integer");
const viziotMQTT = require("viziot-mqtt-client-nodejs");

// Конфигурация
const CONFIG = {
  keyDevice: "ВАШ_КЛЮЧ_УСТРОЙСТВА", // Ключ устройства VizIoT
  passDevice: "ВАШ_ПАРОЛЬ_УСТРОЙСТВА", // Пароль устройства VizIoT
  intervalSendData: 30000, // Интервал опроса в миллисекундах (30 секунд)
  ipRouter: "192.168.0.25", // IP-адрес вашего роутера Mikrotik
  snmpCommunity: "public", // Имя SNMP-сообщества (должно совпадать с настройками роутера)
};

// Конвертеры значений
const hexToBigInt = (value) => +bigInt(`0x${value.toString('hex')}`).toString(10)
const divideBy10 = (value) => value / 10
const divideBy100ToDay = (value) => value / 100 / 60 / 60 / 24
const identity = (value) => value

// Генератор OID для rx и tx портов
const generatePortOIDs = () => {
    const oids = {}
    const rxBase = '1.3.6.1.4.1.14988.1.1.14.1.1.31'
    const txBase = '1.3.6.1.4.1.14988.1.1.14.1.1.61'

    // SFPP1 порт
    oids[`${rxBase}.1`] = { key: 'rx_sfpp1', convert: hexToBigInt }
    oids[`${txBase}.1`] = { key: 'tx_sfpp1', convert: hexToBigInt }

    // SFP порты 1-12
    for (let i = 1; i <= 12; i++) {
        oids[`${rxBase}.${i + 1}`] = { key: `rx_sfp${i}`, convert: hexToBigInt }
        oids[`${txBase}.${i + 1}`] = { key: `tx_sfp${i}`, convert: hexToBigInt }
    }

    return oids
}

// Генератор OID для загрузки CPU
const generateProcessorLoadOIDs = () => {
    const oids = {}

    const base = '1.3.6.1.2.1.25.3.3.1.2.'

    // 16-ти ядерный процессор
    for (let i = 1; i <= 16; i++) {
        oids[`${base}.${i}`] = { key: `cpu${i}`, convert: identity }
    }

    return oids
}

// SNMP OID конфигурация
const SNMP_OIDS = {
    '1.3.6.1.2.1.1.3.0': { key: 'uptime', convert: divideBy100ToDay },
    ...generatePortOIDs(),
    '1.3.6.1.4.1.14988.1.1.3.11.0': { key: 'processorTemp', convert: divideBy10 },
    '1.3.6.1.4.1.14988.1.1.3.15.0': { key: 'power1State', convert: identity },
    '1.3.6.1.4.1.14988.1.1.3.16.0': { key: 'power2State', convert: identity },
    '1.3.6.1.4.1.14988.1.1.3.17.0': { key: 'fan1RPM', convert: identity },
    '1.3.6.1.4.1.14988.1.1.3.18.0': { key: 'fan2RPM', convert: identity },
    ...generateProcessorLoadOIDs(),
}

// Класс для работы с SNMP данными
class SNMPMonitor {
    constructor() {
        this.prevResult = null
        this.mqttClient = new viziotMQTT(CONFIG.keyDevice, CONFIG.passDevice)
        this.intervalId = null
    }

    start() {
        this.mqttClient.connect(() => {
            console.log(new Date(), 'MQTT подключен')
            this.startPolling()
        })
    }

    startPolling() {
        if (this.intervalId) {
            clearInterval(this.intervalId)
        }
        this.intervalId = setInterval(() => this.poll(), CONFIG.intervalSendData)
    }

    async poll() {
        try {
            const result = await this.getSNMPData()

            if (!result) {
                console.log(new Date(), 'SNMP результат пустой')
                return
            }

            if (!this.prevResult) {
                this.prevResult = result
                console.log(new Date(), 'Получен первый SNMP результат')
                return
            }

            const packet = this.buildPacket(result)
            this.prevResult = result

            //   console.log(packet)

            this.mqttClient.sendDataToVizIoT(packet, (err) => {
                if (!err) console.log(new Date(), 'Пакет отправлен')
            })
        } catch (error) {
            console.error(new Date(), 'Ошибка опроса:', error)
        }
    }

    getSNMPData() {
        return new Promise((resolve) => {
            const session = snmp.createSession(CONFIG.ipRouter, CONFIG.snmpCommunity)
            const oids = Object.keys(SNMP_OIDS)

            session.get(oids, (error, varbinds) => {
                session.close()

                if (error) {
                    console.error(new Date(), 'SNMP varbinds:', varbinds)
                    console.error(new Date(), 'SNMP ошибка:', error)
                    resolve(null)
                    return
                }

                const result = { timeGet: Date.now() }

                varbinds.forEach((varbind) => {
                    if (snmp.isVarbindError(varbind)) {
                        console.error(new Date(), snmp.varbindError(varbind))
                        return
                    }

                    const config = SNMP_OIDS[varbind.oid]
                    if (config) {
                        result[config.key] = config.convert(varbind.value)
                    }
                })

                resolve(result)
            })
        })
    }

    // Вычисление статистики по загрузке CPU
    calculateCPUStats(current) {
        const cpuLoads = []

        // Собираем значения загрузки всех ядер
        for (let i = 1; i <= 16; i++) {
            const cpuKey = `cpu${i}`
            if (current[cpuKey] !== undefined) {
                cpuLoads.push(current[cpuKey])
            }
        }

        if (cpuLoads.length === 0) {
            return { avg: 0, min: 0, max: 0 }
        }

        // Вычисляем среднее, минимум и максимум
        const sum = cpuLoads.reduce((acc, val) => acc + val, 0)
        const avg = Math.round((sum / cpuLoads.length) * 100) / 100
        const min = Math.min(...cpuLoads)
        const max = Math.max(...cpuLoads)

        return { avg, min, max }
    }

    buildPacket(current) {
        const elapsedSec = Math.round((current.timeGet - this.prevResult.timeGet) / 1000)

        // Вычисляем статистику CPU
        const cpuStats = this.calculateCPUStats(current)

        const packet = {
            date: Math.floor(Date.now() / 1000),
            uptime: current.uptime,
            processorTemp: current.processorTemp,
            cpuAvg: cpuStats.avg, // Средняя загрузка CPU
            cpuMin: cpuStats.min, // Минимальная загрузка по ядрам
            cpuMax: cpuStats.max, // Максимальная загрузка по ядрам
            power1State: current.power1State,
            power2State: current.power2State,
            fan1RPM: current.fan1RPM,
            fan2RPM: current.fan2RPM,
            aggRxMb: 0,
            aggTxMb: 0,
        }

        // Расчет скоростей для всех портов
        const ports = ['sfpp1', ...Array.from({ length: 12 }, (_, i) => `sfp${i + 1}`)]

        ports.forEach((port) => {
            const rxKey = `rx_${port}`
            const txKey = `tx_${port}`

            if (current[rxKey] !== undefined && this.prevResult[rxKey] !== undefined) {
                const rxMb = this.calcBandwidth(current[rxKey], this.prevResult[rxKey], elapsedSec)
                const txMb = this.calcBandwidth(current[txKey], this.prevResult[txKey], elapsedSec)

                const portName = port.charAt(0).toUpperCase() + port.slice(1)
                packet[`rx${portName}Mb`] = rxMb
                packet[`tx${portName}Mb`] = txMb

                packet.aggRxMb += rxMb
                packet.aggTxMb += txMb
            }
        })

        return packet
    }

    calcBandwidth(current, previous, seconds) {
        return ((current - previous) / seconds / 1024 / 1024) * 8
    }

    stop() {
        if (this.intervalId) {
            clearInterval(this.intervalId)
            this.intervalId = null
        }
    }
}

// Запуск мониторинга
const monitor = new SNMPMonitor()
monitor.start()

// Обработка завершения процесса
process.on('SIGINT', () => {
    console.log('\nОстановка мониторинга...')
    monitor.stop()
    process.exit(0)
})

Шаг 4: Автоматический запуск через PM2

Чтобы скрипт работал 24/7, используем менеджер процессов PM2.

  1. Установите PM2 глобально:

    npm install pm2 -g
  2. Запустите скрипт через PM2:

    pm2 start index.js --name "mikrotik-monitor"
  3. Настройте автозапуск PM2 при старте системы:

    pm2 startup

    Скопируйте и выполните команду, которую выдаст PM2.

  4. Сохраните текущий список процессов:

    pm2 save

Теперь ваш скрипт-сборщик будет надёжно работать в фоновом режиме.


Шаг 5: Создание панели мониторинга в VizIoT

Самая интересная часть! Данные поступают, и теперь мы можем их визуализировать.

  1. Создайте новую панель с именем "Mikrotik Router".

  2. Начните добавлять виджеты. VizIoT автоматически создаст параметры при получении первых данных. Вот несколько идей для виджетов:

    • Виджет "Последние значения": Отобразите uptime, power1State, power2State.
    • Виджет "Спидометр" (Gauge): Отлично подойдёт для processorTemp или fan1RPM.
    • Виджет "График":
      • Суммарный трафик: Добавьте на один график параметры aggRxMb (входящий) и aggTxMb (исходящий).
      • Температура и вентиляторы: На другом графике можно совместить processorTemp, fan1RPM, fan2RPM.
      • Трафик по портам: Создайте отдельные графики для каждого важного порта или группы портов, добавляя на них соответствующие rx...Mb и tx...Mb параметры.

Экспериментируйте с типами виджетов и компоновкой, чтобы создать панель, которая будет идеально соответствовать вашим задачам.

Готово!

Вы создали мощную и гибкую систему мониторинга для вашего роутера Mikrotik. Теперь вы всегда будете в курсе состояния вашего сетевого оборудования и сможете оперативно реагировать на любые аномалии в трафике или работе устройства.