Access Point Registration Table

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску

Таблица уровней клиентов для точек доступа Cisco

Задача

Собирать данные о траффике и уровне сигнала с точек доступа

  • Клиенты динамические, их мак-адреса заранее не известны
  • SSID добавляются и удаляются по мере необходимости
  • Точки могут иметь как один интерфейс так и два


Для того что бы получить информацию по SNMP о клиентах подключенных к точке доступа, существует специальный MIB CISCO-DOT11-ASSOCIATION-MIB
Он доступен достаточно давно, как минимум он работает на точках 1200 и 1100 серий, ну и на более современных тоже.


Просмотр OID

Пример с использованием display-hint

# snmpwalk -v2c -c MON 192.168.77.2  .1.3.6.1.4.1.9.9.273.1.3.1   -OX
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientCurrentTxRateSet[1]["450"][STRING: da:20:60:64:36:95] = Hex-STRING: 07
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientCurrentTxRateSet[2]["450"][STRING: a4:45:19:5a:ef:48] = Hex-STRING: 01
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientUpTime[1]["450"][STRING: da:20:60:64:36:95] = Gauge32: 15898 second
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientUpTime[2]["450"][STRING: a4:45:19:5a:ef:48] = Gauge32: 425 second
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientSignalStrength[1]["450"][STRING: da:20:60:64:36:95] = INTEGER: -64 dBm
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientSignalStrength[2]["450"][STRING: a4:45:19:5a:ef:48] = INTEGER: -89 dBm
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientSigQuality[1]["450"][STRING: da:20:60:64:36:95] = Gauge32: 24 percentage
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientSigQuality[2]["450"][STRING: a4:45:19:5a:ef:48] = Gauge32: 9 percentage
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientAgingLeft[1]["450"][STRING: da:20:60:64:36:95] = Gauge32: 58 second
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientAgingLeft[2]["450"][STRING: a4:45:19:5a:ef:48] = Gauge32: 34 second
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientPacketsReceived[1]["450"][STRING: da:20:60:64:36:95] = Counter32: 149529 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientPacketsReceived[2]["450"][STRING: a4:45:19:5a:ef:48] = Counter32: 346 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientBytesReceived[1]["450"][STRING: da:20:60:64:36:95] = Counter32: 23101125 byte
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientBytesReceived[2]["450"][STRING: a4:45:19:5a:ef:48] = Counter32: 113287 byte
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientPacketsSent[1]["450"][STRING: da:20:60:64:36:95] = Counter32: 617733 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientPacketsSent[2]["450"][STRING: a4:45:19:5a:ef:48] = Counter32: 251 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientBytesSent[1]["450"][STRING: da:20:60:64:36:95] = Counter32: 745190393 byte
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientBytesSent[2]["450"][STRING: a4:45:19:5a:ef:48] = Counter32: 47693 byte
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientDuplicates[1]["450"][STRING: da:20:60:64:36:95] = Counter32: 2389 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientDuplicates[2]["450"][STRING: a4:45:19:5a:ef:48] = Counter32: 12 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientMsduRetries[1]["450"][STRING: da:20:60:64:36:95] = Counter32: 159859 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientMsduRetries[2]["450"][STRING: a4:45:19:5a:ef:48] = Counter32: 331 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientMsduFails[1]["450"][STRING: da:20:60:64:36:95] = Counter32: 0 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientMsduFails[2]["450"][STRING: a4:45:19:5a:ef:48] = Counter32: 0 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientWepErrors[1]["450"][STRING: da:20:60:64:36:95] = Counter32: 0 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientWepErrors[2]["450"][STRING: a4:45:19:5a:ef:48] = Counter32: 0 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientMicErrors[1]["450"][STRING: da:20:60:64:36:95] = Counter32: 0 error
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientMicErrors[2]["450"][STRING: a4:45:19:5a:ef:48] = Counter32: 0 error
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientMicMissingFrames[1]["450"][STRING: da:20:60:64:36:95] = Counter32: 0 packet
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientMicMissingFrames[2]["450"][STRING: a4:45:19:5a:ef:48] = Counter32: 0 packet

Или без использования

# snmpwalk -v2c -c MON 192.168.77.2  .1.3.6.1.4.1.9.9.273.1.3.1   -On
.1.3.6.1.4.1.9.9.273.1.3.1.1.1.1.3.52.53.48.218.32.96.100.54.149 = Hex-STRING: 05
.1.3.6.1.4.1.9.9.273.1.3.1.1.1.2.3.52.53.48.164.69.25.90.239.72 = Hex-STRING: 01
.1.3.6.1.4.1.9.9.273.1.3.1.1.2.1.3.52.53.48.218.32.96.100.54.149 = Gauge32: 15911 second
.1.3.6.1.4.1.9.9.273.1.3.1.1.2.2.3.52.53.48.164.69.25.90.239.72 = Gauge32: 439 second
.1.3.6.1.4.1.9.9.273.1.3.1.1.3.1.3.52.53.48.218.32.96.100.54.149 = INTEGER: -63 dBm
.1.3.6.1.4.1.9.9.273.1.3.1.1.3.2.3.52.53.48.164.69.25.90.239.72 = INTEGER: -89 dBm
.1.3.6.1.4.1.9.9.273.1.3.1.1.4.1.3.52.53.48.218.32.96.100.54.149 = Gauge32: 31 percentage
.1.3.6.1.4.1.9.9.273.1.3.1.1.4.2.3.52.53.48.164.69.25.90.239.72 = Gauge32: 10 percentage
.1.3.6.1.4.1.9.9.273.1.3.1.1.5.1.3.52.53.48.218.32.96.100.54.149 = Gauge32: 58 second
.1.3.6.1.4.1.9.9.273.1.3.1.1.5.2.3.52.53.48.164.69.25.90.239.72 = Gauge32: 51 second
.1.3.6.1.4.1.9.9.273.1.3.1.1.6.1.3.52.53.48.218.32.96.100.54.149 = Counter32: 149587 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.6.2.3.52.53.48.164.69.25.90.239.72 = Counter32: 347 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.7.1.3.52.53.48.218.32.96.100.54.149 = Counter32: 23109939 byte
.1.3.6.1.4.1.9.9.273.1.3.1.1.7.2.3.52.53.48.164.69.25.90.239.72 = Counter32: 113333 byte
.1.3.6.1.4.1.9.9.273.1.3.1.1.8.1.3.52.53.48.218.32.96.100.54.149 = Counter32: 618046 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.8.2.3.52.53.48.164.69.25.90.239.72 = Counter32: 251 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.9.1.3.52.53.48.218.32.96.100.54.149 = Counter32: 745583754 byte
.1.3.6.1.4.1.9.9.273.1.3.1.1.9.2.3.52.53.48.164.69.25.90.239.72 = Counter32: 47693 byte
.1.3.6.1.4.1.9.9.273.1.3.1.1.10.1.3.52.53.48.218.32.96.100.54.149 = Counter32: 2392 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.10.2.3.52.53.48.164.69.25.90.239.72 = Counter32: 12 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.11.1.3.52.53.48.218.32.96.100.54.149 = Counter32: 159964 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.11.2.3.52.53.48.164.69.25.90.239.72 = Counter32: 331 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.12.1.3.52.53.48.218.32.96.100.54.149 = Counter32: 0 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.12.2.3.52.53.48.164.69.25.90.239.72 = Counter32: 0 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.13.1.3.52.53.48.218.32.96.100.54.149 = Counter32: 0 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.13.2.3.52.53.48.164.69.25.90.239.72 = Counter32: 0 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.14.1.3.52.53.48.218.32.96.100.54.149 = Counter32: 0 error
.1.3.6.1.4.1.9.9.273.1.3.1.1.14.2.3.52.53.48.164.69.25.90.239.72 = Counter32: 0 error
.1.3.6.1.4.1.9.9.273.1.3.1.1.15.1.3.52.53.48.218.32.96.100.54.149 = Counter32: 0 packet
.1.3.6.1.4.1.9.9.273.1.3.1.1.15.2.3.52.53.48.164.69.25.90.239.72 = Counter32: 0 packet

Разбор OID

Как можно видеть, сам OID состоит из нескольких частей Для определенности рассмотрим уровни сигнала:

.1.3.6.1.4.1.9.9.273.1.3.1.1.3.1.3.52.53.48.218.32.96.100.54.149 = INTEGER: -63 dBm
.1.3.6.1.4.1.9.9.273.1.3.1.1.3.2.3.52.53.48.164.69.25.90.239.72 = INTEGER: -89 dBm
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientSignalStrength[1]["450"][STRING: da:20:60:64:36:95] = INTEGER: -64 dBm
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientSignalStrength[2]["450"][STRING: a4:45:19:5a:ef:48] = INTEGER: -89 dBm

Часть .1.3.6.1.4.1.9.9.273.1.3.1.1.3 это и есть OID CISCO-DOT11-ASSOCIATION и она общая Далее в самом OID закодировано значение "кому принадлежит сигнал", т е какому клиенту


Выделенное значение и его описание:

  • 2.3.52.53.48.164.69.25.90.239.72 - номер интерфейса, он же ifIndex, dot11Radio0 (1), или dot11Radio1 (2), в примере клиент подключен к 5Ghz интерфейсу (dot11Radio1)
  • 2.3.52.53.48.164.69.25.90.239.72 - Длинна SSID в байтах, в пример 3 символа (SSID в примере "450")
  • 2.3.52.53.48.164.69.25.90.239.72 - коды ASCII символов SSID, их три - "450"
  • 2.3.52.53.48.164.69.25.90.239.72 - мак-адрес, 6 байт, записаны в деятичной форме, "a4:45:19:5a:ef:48", например 164(десятичное) = a4(hex), 69(десятичное) = 45 (hex) и так далее.

Интеграция с Zabbix

SNMP autodiscovery

Есть дока но мне она не нравится =)

В моем случае правило автообнаружения выглядит так:
Zabbix Discovery.png

В целом идея такая:

  • В поле SNMP OID указываю discovery[{#S},1.3.6.1.4.1.9.9.273.1.3.1.1.3]
  • Заббикс сам делает snmpwalk 1.3.6.1.4.1.9.9.273.1.3.1.1.3 и в результате получает список клиентов и их сигналы
snmpwalk -v2c -c MON 192.168.77.2   1.3.6.1.4.1.9.9.273.1.3.1.1.3   -OX
Bad operator (INTEGER): At line 73 in /usr/share/snmp/mibs/ietf/SNMPv2-PDU
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientSignalStrength[1]["450"][STRING: 0:8:ca:2b:1:24] = INTEGER: -65 dBm
CISCO-DOT11-ASSOCIATION-MIB::cDot11ClientSignalStrength[2]["450"][STRING: a4:45:19:5a:ef:48] = INTEGER: -67 dBm

и на выходе формирует JSON в котором есть поля "{#SNMPINDEX}" - это часть которую нужно дописать к OID указанному в discovery что бы получить значение

[
  {
    "{#SNMPINDEX}": "1.3.52.53.48.0.8.202.43.1.36",
    "{#S}": "-66"
  },
  {
    "{#SNMPINDEX}": "2.3.52.53.48.164.69.25.90.239.72",
    "{#S}": "-66"
  }
] 

Это выглядит странновато, но суть этого - получить список суффиксов, которые потом можно использовать для получения других значений
В поле "{#S}" записан сигнал и его значение я нигде не использую, но в общем случае (для других MIB/OID) тут может быть что-то что можно использовать (в оригинальной документации это имена интерфейсов)
В общем случае можно указать несколько OID которые нужно обходить snmpwalk-ом, но при этом нужно держать в голове что SNMPINDEX должен совпадать - так работает для таблицы интерфейсов где по разным префиксам но с одним и тем же ifIndex можно получить данные с интерфейса - имя, дескрипшен, байты и т.п.

Если же указать 2 OID с разной структурой (например интерфейсы и таблицу регистрации клиентов) то ничего хорошего не получится - данные будут перемешаны (подробно я не смотрел код как именно и почему )


Далее при создании прототипов элементов данных можно использовать "{#SNMPINDEX}" и тогда все остальные переменны в JSON полученном при discovery будут доступны

Например, если при создании прототипа данныхь указать OID=.1.3.6.1.4.1.9.9.273.1.3.1.1.2.{#SNMPINDEX} то (для моего примера будет автоматически создано 2 элемента данных, в именах которых можно использовать например значение макроса "{$S}". Это хорошо ложиться на пример с интерфейсом, но в моем случае этот макрос как и остальные совершенно бесполезен так как вся статическая информация закодирована в OID который собственно доступен через макрос "{SNMPINDEX}"

Processing

Для того что бы получить нужные данные в удобном виде полученный при discovery JSON можно редактировать с помошью встроенного JavaScript

В моем случае на скорую руку вышел вот такой скрипт:

var records = JSON.parse(value);

for (i = 0; i < records.length; i++) {
    var OID = records[i]["{#SNMPINDEX}"].split('.')
    // IFINDEX AND IFNAME
    var dot1RadioIfIndex = OID.shift();
    records[i]['{#DOT1RADIO_IFINDEX}'] = dot1RadioIfIndex
    records[i]['{#DOT1RADIO_IFNAME}'] = "Dot11Radio" + (parseInt(dot1RadioIfIndex) - 1).toString()

    // get mac as 6 last digits converted dec -> hex and joined with ':'
    var MAC = ""
    var MACDigitHex
    for (j = 0; j < 6; j++) {
        MACDigitDec = OID.pop();

        MACDigitHex = parseInt(MACDigitDec).toString(16);
        MAC = MACDigitHex + " " + MAC
    }
    records[i]['{#MAC}'] = MAC.trim().split(" ").join(":")

    // SSID. The first octet is length, others are ASCII characters 
    SSID = ""
    ssidLength = OID.shift();
    
    for (j = 0; j < ssidLength; j++) {
      SSID += String.fromCharCode(parseInt(OID[j]));

    }
    records[i]['{#SSID}'] = SSID
}
return JSON.stringify(records);

Идея в том что бы добавить поля построенные на основе SNMPINDEX в Json, и в дальнейшем они будут доступны при создании элементов данных


В результате из исходного JSON получаю такой

[
  {
    "{#SNMPINDEX}": "1.3.52.53.48.0.8.202.43.1.36",
    "{#S}": "-62",
    "{#DOT1RADIO_IFINDEX}": "1",
    "{#DOT1RADIO_IFNAME}": "Dot11Radio0",
    "{#MAC}": "0:8:ca:2b:1:24",
    "{#SSID}": "450"
  },
  {
    "{#SNMPINDEX}": "2.3.52.53.48.164.69.25.90.239.72",
    "{#S}": "-79",
    "{#DOT1RADIO_IFINDEX}": "2",
    "{#DOT1RADIO_IFNAME}": "Dot11Radio1",
    "{#MAC}": "a4:45:19:5a:ef:48",
    "{#SSID}": "450"
  }
]

который уже содержит статическую информацию о клиенте и который можно использовать для создания элеметов данных

Прототпипы жлементов данных

Формируем имя и ключ на основе данных из Json, например

Name cDot11ClientSignalStrength [ {#MAC}@{#DOT1RADIO_IFNAME}:{#SSID} ]

где для кажого клиента будет создан отдельный элемент данных, при этом используются три уникальных значения, клиент с тем же маком но подключившись в другом диапазоне (другой интерфейс) рассматривается как другой клиент даже если используется один SSID для разных частот)

Готовый Темплейт