SNMP How-To¶
Simulate SNMP devices¶
SNMP is a protocol for gathering metrics from network devices, but automated testing of the integration would not be practical nor reliable if we used actual devices.
Our approach is to use a simulated SNMP device that responds to SNMP queries using simulation data.
This simulated device is brought up as a Docker container when starting the SNMP test environment using:
ddev env start snmp [...]
Test SNMP profiles locally¶
Once the environment is up and running, you can modify the instance configuration to test profiles that support simulated metrics.
The following is an example of an instance configured to use the Cisco Nexus profile.
init_config:
profiles:
cisco_nexus:
definition_file: cisco-nexus.yaml
instances:
- community_string: cisco_nexus # (1.)
ip_address: <IP_ADDRESS_OF_SNMP_CONTAINER> # (2.)
profile: cisco_nexus
name: localhost
port: 1161
- The
community_string
must match the corresponding device.snmprec
file name. For example,myprofile.snmprec
givescommunity_string: myprofile
. This also applies to walk files:myprofile.snmpwalk
givescommunity_string: myprofile
. - To find the IP address of the SNMP container, run:
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' dd-snmp
Run SNMP queries¶
With the test environment is up and running, we can issue SNMP queries to the simulated device using a command line SNMP client.
Prerequisites¶
Make sure you have the Net-SNMP tools installed on your machine. These should come pre-installed by default on Linux and macOS. If necessary, you can download them on the Net-SNMP website.
Available commands¶
The Net-SNMP tools provide a number of commands to interact with SNMP devices.
The most commonly used commands are:
snmpget
: to issue an SNMP GET query.snmpgetnext
: to issue an SNMP GETNEXT query.snmpwalk
: to query an entire OID sub-tree at once.snmptable
: to query rows in an SNMP table.
Examples¶
GET query¶
To query a specific OID from a device, we can use the snmpget
command.
For example, the following command will query sysDescr
OID of an SNMP device, which returns its human-readable description:
$ snmpget -v 2c -c public -IR 127.0.0.1:1161 system.sysDescr.0
SNMPv2-MIB::sysDescr.0 = STRING: Linux 41ba948911b9 4.9.87-linuxkit-aufs #1 SMP Wed Mar 14 15:12:16 UTC 2018 x86_64
SNMPv2-MIB::sysORUpTime.1 = Timeticks: (9) 0:00:00.09
Let's break this command down:
snmpget
: this command sends an SNMP GET request, and can be used to query the value of an OID. Here, we are requesting thesystem.sysDescr.0
OID.-v 2c
: instructs your SNMP client to send the request using SNMP version 2c. See SNMP Versions.-c public
: instructs the SNMP client to send the community stringpublic
along with our request. (This is a form of authentication provided by SNMP v2. See SNMP Versions.)127.0.0.1:1161
: this is the host and port where the simulated SNMP agent is available at. (Confirm the port used by the ddev environment by inspecting the Docker port mapping via$ docker ps
.)system.sysDescr.0
: this is the OID that the client should request. In practice this can refer to either a fully-resolved OID (e.g.1.3.6.1.4.1[...]
), or a label (e.g.sysDescr.0
).-IR
: this option allows us to use labels for OIDs that aren't in the generic1.3.6.1.2.1.*
sub-tree (see: The OID tree). TL;DR: always use this option when working with OIDs coming from vendor-specific MIBs.
Tip
If the above command fails, try using the explicit OID like so:
$ snmpget -v 2c -c public -IR 127.0.0.1:1161 iso.3.6.1.2.1.1.1.0
Table query¶
For tables, use the snmptable
command, which will output the rows in the table in a tabular format. Its arguments and options are similar to snmpget
.
$ snmptable -v 2c -c public -IR -Os 127.0.0.1:1161 hrStorageTable
SNMP table: hrStorageTable
hrStorageIndex hrStorageType hrStorageDescr hrStorageAllocationUnits hrStorageSize hrStorageUsed hrStorageAllocationFailures
1 hrStorageRam Physical memory 1024 Bytes 2046940 1969964 ?
3 hrStorageVirtualMemory Virtual memory 1024 Bytes 3095512 1969964 ?
6 hrStorageOther Memory buffers 1024 Bytes 2046940 73580 ?
7 hrStorageOther Cached memory 1024 Bytes 1577648 1577648 ?
8 hrStorageOther Shared memory 1024 Bytes 2940 2940 ?
10 hrStorageVirtualMemory Swap space 1024 Bytes 1048572 0 ?
33 hrStorageFixedDisk /dev 4096 Bytes 16384 0 ?
36 hrStorageFixedDisk /sys/fs/cgroup 4096 Bytes 255867 0 ?
52 hrStorageFixedDisk /etc/resolv.conf 4096 Bytes 16448139 6493059 ?
53 hrStorageFixedDisk /etc/hostname 4096 Bytes 16448139 6493059 ?
54 hrStorageFixedDisk /etc/hosts 4096 Bytes 16448139 6493059 ?
55 hrStorageFixedDisk /dev/shm 4096 Bytes 16384 0 ?
61 hrStorageFixedDisk /proc/kcore 4096 Bytes 16384 0 ?
62 hrStorageFixedDisk /proc/keys 4096 Bytes 16384 0 ?
63 hrStorageFixedDisk /proc/timer_list 4096 Bytes 16384 0 ?
64 hrStorageFixedDisk /proc/sched_debug 4096 Bytes 16384 0 ?
65 hrStorageFixedDisk /sys/firmware 4096 Bytes 255867 0 ?
(In this case, we added the -Os
option which prints only the last symbolic element and reduces the output of hrStorageTypes
.)
Walk query¶
A walk query can be used to query all OIDs in a given sub-tree.
The snmpwalk
command can be used to perform a walk query.
To facilitate usage of walk files for debugging, the following options are recommended: -ObentU
. Here's what each option does:
b
: do not break OID indexes down.e
: print enums numerically (for example,24
instead ofsoftwareLoopback(24)
).n
: print OIDs numerically (for example,.1.3.6.1.2.1.2.2.1.1.1
instead ofIF-MIB::ifIndex.1
).t
: print timeticks numerically (for example,4226041
instead ofTimeticks: (4226041) 11:44:20.41
).U
: don't print units.
For example, the following command gets a walk of the 1.3.6.1.2.1.1
(system
) sub-tree:
$ snmpwalk -v 2c -c public -ObentU 127.0.0.1:1161 1.3.6.1.2.1.1
.1.3.6.1.2.1.1.1.0 = STRING: Linux 41ba948911b9 4.9.87-linuxkit-aufs #1 SMP Wed Mar 14 15:12:16 UTC 2018 x86_64
.1.3.6.1.2.1.1.2.0 = OID: .1.3.6.1.4.1.8072.3.2.10
.1.3.6.1.2.1.1.3.0 = 4226041
.1.3.6.1.2.1.1.4.0 = STRING: root@localhost
.1.3.6.1.2.1.1.5.0 = STRING: 41ba948911b9
.1.3.6.1.2.1.1.6.0 = STRING: Unknown
.1.3.6.1.2.1.1.8.0 = 9
.1.3.6.1.2.1.1.9.1.2.1 = OID: .1.3.6.1.6.3.11.3.1.1
.1.3.6.1.2.1.1.9.1.2.2 = OID: .1.3.6.1.6.3.15.2.1.1
.1.3.6.1.2.1.1.9.1.2.3 = OID: .1.3.6.1.6.3.10.3.1.1
.1.3.6.1.2.1.1.9.1.2.4 = OID: .1.3.6.1.6.3.1
.1.3.6.1.2.1.1.9.1.2.5 = OID: .1.3.6.1.2.1.49
.1.3.6.1.2.1.1.9.1.2.6 = OID: .1.3.6.1.2.1.4
.1.3.6.1.2.1.1.9.1.2.7 = OID: .1.3.6.1.2.1.50
.1.3.6.1.2.1.1.9.1.2.8 = OID: .1.3.6.1.6.3.16.2.2.1
.1.3.6.1.2.1.1.9.1.2.9 = OID: .1.3.6.1.6.3.13.3.1.3
.1.3.6.1.2.1.1.9.1.2.10 = OID: .1.3.6.1.2.1.92
.1.3.6.1.2.1.1.9.1.3.1 = STRING: The MIB for Message Processing and Dispatching.
.1.3.6.1.2.1.1.9.1.3.2 = STRING: The management information definitions for the SNMP User-based Security Model.
.1.3.6.1.2.1.1.9.1.3.3 = STRING: The SNMP Management Architecture MIB.
.1.3.6.1.2.1.1.9.1.3.4 = STRING: The MIB module for SNMPv2 entities
.1.3.6.1.2.1.1.9.1.3.5 = STRING: The MIB module for managing TCP implementations
.1.3.6.1.2.1.1.9.1.3.6 = STRING: The MIB module for managing IP and ICMP implementations
.1.3.6.1.2.1.1.9.1.3.7 = STRING: The MIB module for managing UDP implementations
.1.3.6.1.2.1.1.9.1.3.8 = STRING: View-based Access Control Model for SNMP.
.1.3.6.1.2.1.1.9.1.3.9 = STRING: The MIB modules for managing SNMP Notification, plus filtering.
.1.3.6.1.2.1.1.9.1.3.10 = STRING: The MIB module for logging SNMP Notifications.
.1.3.6.1.2.1.1.9.1.4.1 = 9
.1.3.6.1.2.1.1.9.1.4.2 = 9
.1.3.6.1.2.1.1.9.1.4.3 = 9
.1.3.6.1.2.1.1.9.1.4.4 = 9
.1.3.6.1.2.1.1.9.1.4.5 = 9
.1.3.6.1.2.1.1.9.1.4.6 = 9
.1.3.6.1.2.1.1.9.1.4.7 = 9
.1.3.6.1.2.1.1.9.1.4.8 = 9
.1.3.6.1.2.1.1.9.1.4.9 = 9
.1.3.6.1.2.1.1.9.1.4.10 = 9
As you can see, all OIDs that the device has available in the .1.3.6.1.2.1.1.*
sub-tree are returned. In particular, one can recognize:
sysObjectID
(.1.3.6.1.2.1.1.2.0 = OID: .1.3.6.1.4.1.8072.3.2.10
)sysUpTime
(.1.3.6.1.2.1.1.3.0 = 4226041
)sysName
(.1.3.6.1.2.1.1.5.0 = STRING: 41ba948911b9
).
Here is another example that queries the entire contents of ifTable
(the table in IF-MIB
that contains information about network interfaces):
snmpwalk -v 2c -c public -OentU 127.0.0.1:1161 1.3.6.1.2.1.2.2
.1.3.6.1.2.1.2.2.1.1.1 = INTEGER: 1
.1.3.6.1.2.1.2.2.1.1.90 = INTEGER: 90
.1.3.6.1.2.1.2.2.1.2.1 = STRING: lo
.1.3.6.1.2.1.2.2.1.2.90 = STRING: eth0
.1.3.6.1.2.1.2.2.1.3.1 = INTEGER: 24
.1.3.6.1.2.1.2.2.1.3.90 = INTEGER: 6
.1.3.6.1.2.1.2.2.1.4.1 = INTEGER: 65536
.1.3.6.1.2.1.2.2.1.4.90 = INTEGER: 1500
.1.3.6.1.2.1.2.2.1.5.1 = Gauge32: 10000000
.1.3.6.1.2.1.2.2.1.5.90 = Gauge32: 4294967295
.1.3.6.1.2.1.2.2.1.6.1 = STRING:
.1.3.6.1.2.1.2.2.1.6.90 = STRING: 2:42:ac:11:0:2
.1.3.6.1.2.1.2.2.1.7.1 = INTEGER: 1
.1.3.6.1.2.1.2.2.1.7.90 = INTEGER: 1
.1.3.6.1.2.1.2.2.1.8.1 = INTEGER: 1
.1.3.6.1.2.1.2.2.1.8.90 = INTEGER: 1
.1.3.6.1.2.1.2.2.1.9.1 = 0
.1.3.6.1.2.1.2.2.1.9.90 = 0
.1.3.6.1.2.1.2.2.1.10.1 = Counter32: 5300203
.1.3.6.1.2.1.2.2.1.10.90 = Counter32: 2928
.1.3.6.1.2.1.2.2.1.11.1 = Counter32: 63808
.1.3.6.1.2.1.2.2.1.11.90 = Counter32: 40
.1.3.6.1.2.1.2.2.1.12.1 = Counter32: 0
.1.3.6.1.2.1.2.2.1.12.90 = Counter32: 0
.1.3.6.1.2.1.2.2.1.13.1 = Counter32: 0
.1.3.6.1.2.1.2.2.1.13.90 = Counter32: 0
.1.3.6.1.2.1.2.2.1.14.1 = Counter32: 0
.1.3.6.1.2.1.2.2.1.14.90 = Counter32: 0
.1.3.6.1.2.1.2.2.1.15.1 = Counter32: 0
.1.3.6.1.2.1.2.2.1.15.90 = Counter32: 0
.1.3.6.1.2.1.2.2.1.16.1 = Counter32: 5300203
.1.3.6.1.2.1.2.2.1.16.90 = Counter32: 0
.1.3.6.1.2.1.2.2.1.17.1 = Counter32: 63808
.1.3.6.1.2.1.2.2.1.17.90 = Counter32: 0
.1.3.6.1.2.1.2.2.1.18.1 = Counter32: 0
.1.3.6.1.2.1.2.2.1.18.90 = Counter32: 0
.1.3.6.1.2.1.2.2.1.19.1 = Counter32: 0
.1.3.6.1.2.1.2.2.1.19.90 = Counter32: 0
.1.3.6.1.2.1.2.2.1.20.1 = Counter32: 0
.1.3.6.1.2.1.2.2.1.20.90 = Counter32: 0
.1.3.6.1.2.1.2.2.1.21.1 = Gauge32: 0
.1.3.6.1.2.1.2.2.1.21.90 = Gauge32: 0
.1.3.6.1.2.1.2.2.1.22.1 = OID: .0.0
.1.3.6.1.2.1.2.2.1.22.90 = OID: .0.0
Generate table simulation data¶
To generate simulation data for tables automatically, use the mib2dev.py
tool shipped with snmpsim
. This tool will be renamed as snmpsim-record-mibs
in the upcoming 1.0 release of the library.
First, install snmpsim:
pip install snmpsim
Then run the tool, specifying the MIB with the start and stop OIDs (which can correspond to .e.g the first and last columns in the table respectively).
For example:
mib2dev.py --mib-module=<MIB> --start-oid=1.3.6.1.4.1.674.10892.1.400.20 --stop-oid=1.3.6.1.4.1.674.10892.1.600.12 > /path/to/mytable.snmprec
The following command generates 4 rows for the IF-MIB:ifTable (1.3.6.1.2.1.2.2)
:
mib2dev.py --mib-module=IF-MIB --start-oid=1.3.6.1.2.1.2.2 --stop-oid=1.3.6.1.2.1.2.3 --table-size=4 > /path/to/mytable.snmprec
Known issues¶
mib2dev
has a known issue with IF-MIB::ifPhysAddress
, that is expected to contain an hexadecimal string, but mib2dev
fills it with a string. To fix this, provide a valid hextring when prompted on the command line:
# Synthesizing row #1 of table 1.3.6.1.2.1.2.2.1
*** Inconsistent value: Display format eval failure: b'driving kept zombies quaintly forward zombies': invalid literal for int() with base 16: 'driving kept zombies quaintly forward zombies'caused by <class 'ValueError'>: invalid literal for int() with base 16: 'driving kept zombies quaintly forward zombies'
*** See constraints and suggest a better one for:
# Table IF-MIB::ifTable
# Row IF-MIB::ifEntry
# Index IF-MIB::ifIndex (type InterfaceIndex)
# Column IF-MIB::ifPhysAddress (type PhysAddress)
# Value ['driving kept zombies quaintly forward zombies'] ? 001122334455
Generate simulation data from a walk¶
As an alternative to .snmprec
files, it is possible to use a walk as simulation data. This is especially useful when debugging live devices, since you can export the device walk and use this real data locally.
To do so, paste the output of a walk query into a .snmpwalk
file, and add this file to the test data directory. Then, pass the name of the walk file as the community_string
. For more information, see Test SNMP profiles locally.
Find where MIBs are installed on your machine¶
See the Using and loading MIBs Net-SNMP tutorial.
Browse locally installed MIBs¶
Since community resources that list MIBs and OIDs are best effort, the MIB you are investigating may not be present or may not be available in its the latest version.
In that case, you can use the snmptranslate
CLI tool to output similar information for MIBs installed on your system. This tool is part of Net-SNMP - see SNMP queries prerequisites.
Steps
- Run
$ snmptranslate -m <MIBNAME> -Tz -On
to get a complete list of OIDs in the<MIBNAME>
MIB along with their labels. - Redirect to a file for nicer formatting as needed.
Example:
$ snmptranslate -m IF-MIB -Tz -On > out.log
$ cat out.log
"org" "1.3"
"dod" "1.3.6"
"internet" "1.3.6.1"
"directory" "1.3.6.1.1"
"mgmt" "1.3.6.1.2"
"mib-2" "1.3.6.1.2.1"
"system" "1.3.6.1.2.1.1"
"sysDescr" "1.3.6.1.2.1.1.1"
"sysObjectID" "1.3.6.1.2.1.1.2"
"sysUpTime" "1.3.6.1.2.1.1.3"
"sysContact" "1.3.6.1.2.1.1.4"
"sysName" "1.3.6.1.2.1.1.5"
"sysLocation" "1.3.6.1.2.1.1.6"
[...]
Tip
Use the -M <DIR>
option to specify the directory where snmptranslate
should look for MIBs. Useful if you want to inspect a MIB you've just downloaded but not moved to the default MIB directory.
Tip
Use -Tp
for an alternative tree-like formatting.