Monitoring UniFi Access Points using SNMP, Telegraf, Influx and Grafana

Monitoring your network is useful but also fun for many reasons. It can help you to detect anomalies but also show interesting facts about your network. And finally it is just fun to have everything monitored. This post will talk about how I use my existing monitoring setup to get statistics about my recently installed UniFi nanoHD access point.

First, I shouldn’t have to mention that this post covers monitoring in my setup. However, the SNMP MIBs and OIDs can be used to get information without having Telegraf, Influx or Grafana set up as I have. Therefore, let’s start by getting information without all of these tools.

SNMP crash course

For everyone that hasn’t heard of SNMP here is a short introduction. SNMP is an abbrevation for Simple Network Management Protocol. Therefore it was designed for management, and not for monitoring exclusively. It is designed around Object Identifiers (OIDs) which are used to address properties in a device. They are managed centrally and therefore do not overlap between manufacturers.

There are different representations of them. One being numerical, e.g.

.1.3.6.1.4.1.41112.1.6.3.3.0

and another one is textual:

UBNT-UniFi-MIB::unifiApSystemModel

They are defined in a Management Information Base (MIB). These MIBs are used to define the OIDs. For the textual example the suffix is the MIB’s name. At this point, this is all you need to know for the remainder of this post.

snmpwalk

There are many snmp tools such as snmpstatus, snmptable, snmpget and even snmpset (which you need for actual management tasks). snmpwalk is the most important one in my opinion, as it let’s you walk through the SNMP tree. To install these tools, you should install both the snmp package and the snmp-mibs-downloader package.

Let’s have a look at snmpwalk and use the example from above. The command looks like this:

snmpwalk -v2c -c public 0.0.0.0 UBNT-UniFi-MIB::unifiApSystemModel

Which then returns

UBNT-UniFi-MIB::unifiApSystemModel.0 = STRING: UAP-nanoHD

Cool! We can already read the AP’s system model. But well, I have to confess, you need to know two more details for snmpwalk.
First, there are different versions of SNMP, in this case we use 2c. And second, the community string, that is used to define access rights, which is public in the example. Be careful here, as the versions can be enabled separately and the community string can be changed, as you can see below in the settings of the UniFi controller:

UniFi Controller settings to enable SNMP (Settings -> Services -> SNMP)

With snmpwalk you can now even omit the OID, but be aware that this produces a lot of output (and traffic depending on your uplink!). I will omit both the command and output here. I will however talk about the some of the output. When scrolling throughthere, you might find lines such as:

IF-MIB::ifName.2 = STRING: eth0
IF-MIB::ifHCOutOctets.31 = Counter64: 35484074
IF-MIB::ifConnectorPresent.2 = INTEGER: true(1)

As you should know from before IF-MIB::ifName.2 is the full IOD and IF-MIB is the MIB. IF stands for interface in this case, and returns information about one or more interfaces present on the device. From the output above there is a interface eth0, which has send 35484074 bytes and it has a connector! At this point you could go ahead, enable SNMP on all your devices (if possible), and see what information they return.
But careful, snmpwalk does not include vendor specific MIBs, such as those from Cisco, UniFi and others. It will only traverse to the common OID tree here. We did confirm though, that the UniFi APs also support IF-MIB, a commonly used MIB for information about interfaces. The MIB contents can be looked up at different sites. So let’s talk about the MIBs.

Available MIBs: IF-MIB & UBNT-UniFi-MIB

IF-MIB is supported by the UniFi AP as we have seen through snmpwalk. As mentioned above, there are also vendor specific MIBs. For UBNT there are UBNT-MIB and UBNT-UniFi-MIB and they can be downloaded here:

http://dl.ubnt-ut.com/snmp/UBNT-MIB
http://dl.ubnt-ut.com/snmp/UBNT-UniFi-MIB

Those might have to be downloaded and saved on your system. You can either put them locally in $HOME/.snmp/mibs/ or in /usr/share/snmp/mibs. Please note, that there are many more locations, which you can see using snmpwalk –help. The mibs downloader should download them as required automatically, is possible. But putting them there puts you in a safe space.

Now that we have installed all the MIBs, we can talk about their contents and information they give us. I will only talk about two types of information here, one being single information such hostname or uptime of your system. The other one is called a table. Each table contains one or more entries. For fun, you can have a look at the following command (note that we are using smnptable here and for this to work the MIB has to be installed!):

snmptable -v2c -c public 0.0.0.0 IF-MIB::ifXTable

The command above should give you a table-like overview of all available interfaces on your UniFi AP! Important: I use ifXTable and not ifTable here. The difference is quite small but very important! ifTable and ifXTable both store information about transmitted, received and dropped packets and bytes. The advantage of ifXtable is that it uses 64bit counters, while ifTable only uses 32bit counters, which will overflow much faster. Therefore you should always use ifXTable if possible! Some of the information available are:

OID nameDescription
ifNameName of the interface
ifHCInOctetsReceived bytes
ifHCOutOctetsTransmitted bytes
ifConnectorPresentIndicator of a connector
ifAliasAlias for the interface (not importanthere)

For most network devices this is all you need to monitor interfaces. But there are many more vendor specific MIBs that we have a look at next.

UBNT-UniFi-MIB

Far more interesting for this post is the UBNT-UniFi-MIB. It contains a lot of information which can be separated into three groups that are defined in the MIB:

  • unifiApWireless
  • unifiApIf
  • unifiApSystem

unifiApIf is ignored from this point on, as IF-MIB::ifXTable gives a lot more information, especially if you plan on using VLANs for your SSIDs.
Let’s have a look at unifiApSystem first, as the only really unique information here is unifiApSystemUptime, which gives you the system’s uptime.
More interesting is unifiApWireless, which gives you a lot of information about the wireless interfaces:

OID name Description
unifiVapEssId Wireless SSID
unifiVapNumStations Number of clients
unifiVapRadio na or ng for 2.4 GHz or 5 GHz
unifiVapRxBytes Received Bytes
unifiVapTxBytes Transmitted Bytes
unifiVapChannel Channel
unifiVapUsage Policy (user or guest)
unifiVapTxPower Transmit Power
unifiVapUp State
unifiVapName Internal Interface Name

Setting up system information

With these information we can finally start monitoring our APs. But before actually setting up Telegraf for the SNMP monitoring, we have to setup each APs information. First, you should not only set the device name correctly, but also its location and contact name. In my monitoring I use the location as the primary name, as it turns out that spaces in the device’s name are not correctly reflected by SNMP. Using the location instead works even with spaces! In the image below you can see the device’s settings.

Unifi device list and settings of a single Access Point

Putting it together

Now that we have setup the AP with the information required, we can start monitoring it. In my setup I use three tools for this purpose:

  1. Telegraf for data collection
  2. Influx for data storage
  3. Grafana for visualization

Following from now on, I will only talk about the Telegraf configuration files. If you want to know more about the further processing and visualization, please read my coming article about my monitoring setup.

In Telegraf we can use the snmp input module to query information about each AP. Below you can see my configuration file to monitor the uptime.

unifi_ap.conf

# configure snmp module
[[inputs.snmp]]
  agents = [ "0.0.0.0" ]
  version = 2
  community = "public"
  interval = "60s"
  timeout = "30s"
  name = "unifi_ap"

# tags
[[inputs.snmp.field]]
  oid = "RFC1213-MIB::sysName.0"
  name = "name"
  is_tag = true

[[inputs.snmp.field]]
  oid = "RFC1213-MIB::sysLocation.0"
  name = "location"
  is_tag = true

# fields
[[inputs.snmp.field]]
  oid = "UBNT-UniFi-MIB::unifiApSystemUptime.0"
  name = "uptime"

Line two contains all IP address of your APs. Line seven defines the name of the target (e.g. influx measurement name). Line 12 define the oid. If name in line 13 was omitted, the target name would be sysName, but I prefer using my own names here! This continues for all fields. In the above example I use both the sysName and sysLocation as tags, as these are meta information I can do filtering on. The only actual metric that changes over time is the uptime!

Testing telegraf configuration files

You can go ahead and test it by using the following command:

telegraf --test --config unifi_ap.conf

And tadaaaa, we have a working monitoring for our access point:

2019-06-01T19:47:40Z I! Starting Telegraf 1.9.0
> unifi_ap,agent_host=1.1.1.1,host=kuschelpi,location=Dachboden\ Nord,name=Dachboden-Nord uptime=188760i 1559418461000000000

Next on the list is IF-MIB. Once again you will find the configuration below. This time we are using some more advanced features. First of all, we don’t use a name for the snmp module this time, as we use a table. But before that, we have defined two tags, that we want to automatically added to our data. The definition is identical to the one from above.

The table is defines with inputs.snmp.table, note that we have set the inherit_tags property, so all entries in the table are correctly tagged. The table is then followed by the target name (unifi_ap_if) in line 27. And finally, all fields and tags have been defined. Once again, I put everything as tags, which shouldn’t change very often, and can be used for filtering later. In the example below, the only thing that should change is the number of bytes received and transmitted.

unifi_ap_if.conf

# general information
[[inputs.snmp]]
  agents = [ "0.0.0.0" ]
  version = 2
  community = "public"
  interval = "60s"
  timeout = "30s"

# meta information
# this will be added automatically as a tag to the next snmp.table
[[inputs.snmp.field]]
  oid = "RFC1213-MIB::sysName.0"
  name = "ap_name"
  is_tag = true

[[inputs.snmp.field]]
  oid = "RFC1213-MIB::sysLocation.0"
  name = "ap_location"
  is_tag = true

# table
[[inputs.snmp.table]]
# Using the oid here will query all fields automatically!
# Be careful when using the oid on inputs.snmp.table as this will
# produce a lot of information
# oid = "IF-MIB::ifXTable"
  name = "unifi_ap_if"
  inherit_tags = ["ap_name", "ap_location"]

# fields
[[inputs.snmp.table.field]]
  oid = "IF-MIB::ifName"
  name = "name"
  is_tag = true

[[inputs.snmp.table.field]]
  oid = "IF-MIB::ifOperStatus"
  name = "status"
  is_tag = true

[[inputs.snmp.table.field]]
  oid = "IF-MIB::ifAlias"
  name = "ifAlias"
  is_tag = true

[[inputs.snmp.table.field]]
  oid = "IF-MIB::ifPromiscuousMode"
  name = "promiscuous_mode"
  is_tag = true

[[inputs.snmp.table.field]]
  oid = "IF-MIB::ifConnectorPresent"
  name = "has_connector"
  is_tag = true

[[inputs.snmp.table.field]]
  oid = "IF-MIB::ifPhysAddress"
  name = "mac"
  conversion = "hwaddr"
  is_tag = true

[[inputs.snmp.table.field]]
  oid = "IF-MIB::ifHCInOctets"
  name = "rx_bytes"

[[inputs.snmp.table.field]]
  oid = "IF-MIB::ifHCOutOctets"
  name = "tx_bytes"

unifi_ap_radio.conf

At last we have the most interesting configuration file. Once again we use some meta data information and a table. But this time we use the unifiApWireless from above. It tells many information about the SSIDs. Below there is my example configuration file I use in production.

[[inputs.snmp]]
  agents = [ "0.0.0.0" ]
  version = 2
  community = "public"
  interval = "60s"
  timeout = "30s"

# Meta information
[[inputs.snmp.field]]
  oid = "RFC1213-MIB::sysName.0"
  name = "name"
  is_tag = true

[[inputs.snmp.field]]
  oid = "RFC1213-MIB::sysLocation.0"
  name = "location"
  is_tag = true

# Table definition for radio
[[inputs.snmp.table]]
  name = "unifi_ap_radio"
  index_as_tag = true
  inherit_tags = ["name", "location"]

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapUsage"
  name = "usage"
  is_tag = true

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapName"
  name = "name"
  is_tag = true

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapRadio"
  name = "radio"
  is_tag = true

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapUp"
  name = "is_up"

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapTxPower"
  name = "tx_power"

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapChannel"
  name = "channel"

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapNumStations"
  name = "clients"

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapRxBytes"
  name = "rx_bytes"

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapRxDropped"
  name = "rx_dropped"

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapRxErrors"
  name = "rx_errors"

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapRxPackets"
  name = "rx_packets"

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapTxBytes"
  name = "tx_bytes"

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapTxDropped"
  name = "tx_dropped"

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapTxErrors"
  name = "tx_errors"

[[inputs.snmp.table.field]]
  oid = "UBNT-UniFi-MIB::unifiVapTxPackets"
  name = "tx_packets"

This concludes this post about how to use SNMP to query information about UniFi access points. If you want to read more about my monitoring, check out other blog posts and check back frequently if new posts have been published. In the mean time feel free to ask questions in the comments below.