Simple Network Managment Protocol lets us collect information about devices on IP networks, including routers, switches, printers, etc. It’s also possible to write configurations using (some versions of) SNMP.

SNMP has three major versions: SNMPv1, SNMPv2c, and SNMPv3. The version are incompatible with each other. SNMPv3 offers improved security. SNMPv1 is still the most widely used.

A manager running on a Network Management Station collects information from agents running on Managed Devices.

SNMP agents expose data organized as hierarchies of key-value pairs. The hierarchy for a particular device is described in a Management Information Base (MIB). Each key/value in that hierarchy is known as an OID (Object Identifier).

The SNMP manager sends requests to UDP port 161 of the managed devices (or port 10161 with TLS). The manager receives notifications (traps and InformRequests) on port 162 (or 10162 for TLS).

The only real security in SNMP versions 1 and 2 is the secret community name, which is itself susceptible to sniffing.

SNMP traps allow agents to send notifications to managers, usually triggered by an event on the managed device (e.g. a predefined threshold exceeded).

Debian has a package with several SNMP tools/utilities (snmpwalk, snmptable, snmptest, snmpset, snmptranslate, etc.):

%  sudo apt-get install snmp snmp-mibs-downloader
%  snmpwalk -c foo_community -v 1 -m ALL

What the values returned by snmpwalk represent may not be obvious. They vary by device. Some devices are better than other at making the values decipherable. A MIB module (definition file) from the device vendor may provide better information. Having the MIB module means the difference between snmpwalk returning the raw numeric key versus descriptive key:

iso. = INTEGER: 3
IF-MIB::ifRcvAddressType.1."....,*" = INTEGER: nonVolatile(3)

This may or may not be helpful.

The numbering of the tree is actually defined in the ISO standard. We’re usually going to be looking at OIDs under ., where 1 = iso, 3 = org, 6 = dod, 1 = internet, 2 = mgmt, 1 = mib, 1 = system…. These two commands are equivalent, for example:

%  snmpwalk -c foo_community -v 1 -m ALL .
%  snmpwalk -c foo_community -v 1 -m ALL

RFC 1213, RFC 2863, and RFC 3418 define a number of standard OIDs found in most devices (e.g. ‘system.sysDescr’, ‘system.sysUpTime’, ‘interfaces.ifNumber’).

%  snmpwalk -c foo_community -v 1 -m ALL ifDescr && snmpwalk -c foo_community -v 1 -m ALL ifOperStatus

Or just:

%  snmpwalk -c foo_community -m ALL -v 1 interfaces

snmpwalk can translate between names and numeric OIDs (and do other formatting) using the -O flag:

%  snmpwalk -c foo_community -m ALL -v 2c BEGEMOT-PF-MIB::pfStateTableCount -On
. = Gauge32: 7182
%  snmpwalk -c foo -m ALL -v 2c BEGEMOT-PF-MIB::pfStateTableCount -Of = Gauge32: 7753

For general CPU info, try the UCD-SNMP-MIB::systemStats:

%  snmpwalk -c foo -m ALL -v 2c .

For general memory info, try the UCD-SNMP-MIB::memory:

%  snmpwalk -c foo -m ALL -v 2c .

Or for load, try UCD-SNMP-MIB::laLoad:

%  snmpwalk -c foo -m ALL -v 2c UCD-SNMP-MIB::laLoad

The 1-minute load average is OID “.”.


Traps let an agent send notifications to a manager.

To find pre-defined traps an agent supports, search the MIB for “TRAP-TYPE” (SMIv1) or “NOTIFICATION-TYPE” (SMIv2). Traps are either generic or enterprise-specific. There are seven types of traps: coldStart (0), warmStart (1), linkDown (2), linkUp (3), authenticationFailure (4), egpNeighborLoss (5), and enterpriseSpecific (6).

Example Scenario

We want to use collectd to monitor the bandwidth usage of interfaces on a pfSense box. Assume collectd is installed and working of our network management station, and that we’ve turned on the SNMP service on pfSense.

We may want to grab the MIBs from, and save them in $HOME/.snmp/mibs/ or /usr/share/snmp/mibs/. And

It’s often useful to browse MIBs (which are structured plain text) to find interesting OIDs, which should all have DESCRIPTION values.

We check what OIDs are available (output condensed to the interesting OIDs):

%  snmpwalk -c foo -m ALL -v 1 interfaces
IF-MIB::ifDescr.1 = STRING: em0
IF-MIB::ifDescr.2 = STRING: em1
IF-MIB::ifDescr.3 = STRING: em2
IF-MIB::ifDescr.4 = STRING: re0
IF-MIB::ifSpeed.1 = Gauge32: 100000000
IF-MIB::ifSpeed.2 = Gauge32: 100000000
IF-MIB::ifSpeed.3 = Gauge32: 100000000
IF-MIB::ifSpeed.4 = Gauge32: 1000000000
IF-MIB::ifOperStatus.1 = INTEGER: up(1)
IF-MIB::ifOperStatus.2 = INTEGER: up(1)
IF-MIB::ifOperStatus.3 = INTEGER: up(1)
IF-MIB::ifOperStatus.4 = INTEGER: up(1)
IF-MIB::ifInOctets.1 = Counter32: 367188816
IF-MIB::ifInOctets.2 = Counter32: 1123779670
IF-MIB::ifInOctets.3 = Counter32: 2528514260
IF-MIB::ifInOctets.4 = Counter32: 1251233569
IF-MIB::ifOutOctets.1 = Counter32: 2085484005
IF-MIB::ifOutOctets.2 = Counter32: 1263498734
IF-MIB::ifOutOctets.3 = Counter32: 1508835003
IF-MIB::ifOutOctets.4 = Counter32: 1282653750

%  snmpwalk -c foo -m ALL -v 2c BEGEMOT-PF-MIB::pfStateTableCount
BEGEMOT-PF-MIB::pfStateTableCount.0 = Gauge32: 8154
%  snmpwalk -c foo -m ALL -v 2c BEGEMOT-PF-MIB::pfInterfacesIfDescr
BEGEMOT-PF-MIB::pfInterfacesIfDescr.6 = STRING: "em0"
BEGEMOT-PF-MIB::pfInterfacesIfDescr.7 = STRING: "em1"
BEGEMOT-PF-MIB::pfInterfacesIfDescr.8 = STRING: "em2"
BEGEMOT-PF-MIB::pfInterfacesIfDescr.9 = STRING: "enc"
BEGEMOT-PF-MIB::pfInterfacesIfDescr.19 = STRING: "re0"
%  snmpwalk -c foo -m ALL -v 2c BEGEMOT-PF-MIB::pfInterfacesIf4PktsInBlock
BEGEMOT-PF-MIB::pfInterfacesIf4PktsInBlock.6 = Counter64: 1053480
BEGEMOT-PF-MIB::pfInterfacesIf4PktsInBlock.7 = Counter64: 426391
BEGEMOT-PF-MIB::pfInterfacesIf4PktsInBlock.8 = Counter64: 3523982
BEGEMOT-PF-MIB::pfInterfacesIf4PktsInBlock.19 = Counter64: 492

In the NMS’s /etc/collectd/collectd.conf:

LoadPlugin snmp
<Plugin snmp>
	<Data "fergus_wan_t1_em0">
		Type "if_octets"
		Table false
		Instance "fergus_wan_t1_em0"
		Values "IF-MIB::ifInOctets.1" "IF-MIB::ifOutOctets.1"
	<Data "fergus_wan_cable_em1">
		Type "if_octets"
		Table false
		Instance "fergust_wan_cable_em1"
		Values "IF-MIB::ifInOctets.2" "IF-MIB::ifOutOctets.2"
	<Data "fergus_lan_em2">
		Type "if_octets"
		Table false
		Instance "fergus_lan_em2"
		Values "IF-MIB::ifInOctets.3" "IF-MIB::ifOutOctets.3"
	<Data "fergus_dmz_re0">
		Type "if_octets"
		Table false
		Instance "fergus_dmz_re0"
		Values "IF-MIB::ifInOctets.4" "IF-MIB::ifOutOctets.4"
	<Data "pf_state_table_count">
		Type "pf_states"
		Table false
		Instance "pf_state_table_count"
		Values "."
	<Data "load_avg">
		Type "load"
		Table false
		Instance "load_avg"
		Values "." "." "."
	<Host "fergus">
		Version 1
		Community "foo"
		Collect "fergus_wan_t1_em0" "fergus_wan_cable_em1" "fergus_lan_em2" "fergus_dmz_re0" "pf_state_table_count" "load_avg"