Simple Network Management Protocol provides a way for devices to make state information available to interested parties and to send notifications of events.
SNMP defines two types of devices. Agents are devices that contain the state information and send notifications. Managers are devices that query state information and receive notifications.
SnmpSharpNet library focuses on the manager operation. To enable users to use the library, basic understanding of SNMP agent operation is required.
Over the years SNMP has been updated and has moved through version 1, 2c and 3. While it would not be unreasonable to expect that newer versions of a protocol supersede the older one, that is not the case with SNMP. You are more likely to run into an agent running protocol version 1 then version 3.
As a general rule you can reasonable expect that agents support SNMP version 1 and 2c. Version 3 is supported by ever expanding number of agents but it’s still not used widely outside of organizations with strict risk requirements necessitating version 3.
Here is a high level comparison between SNMP protocol versions:
|Feature||Version 1||Version 2c||Version 3|
|Community based security||Yes||Yes||No|
|User based security||No||No||Yes|
|Message Encryption (privacy)||No||No||Yes|
Introduction to Object Identifiers
Agents store state information in a tree like structure that is indexed using a list of integer values called object identifiers. Example object identifier is .220.127.116.11.18.104.22.168.0.
Object identifier individual values are identifiers or instances. For example, a single value is referred as Oid .22.214.171.124.126.96.36.199 with the instance 0 so the full “path” to the value is .188.8.131.52.184.108.40.206.0 and that is what you would query to get a sysDescr value from a device.
SNMP agents can also provide table information. To demonstrate we’ll have a look at ifTable. Interface table contains information about device interfaces. ifTable has a base table Oid of
220.127.116.11.18.104.22.168, ifTable has entries under ifEntry which adds instance 1 to the table oid so the new ifTable.ifEntry oid is:
22.214.171.124.126.96.36.199.1. Each interface entry (ifEntry) contains individual interface values. For example, interface name is stored undef ifDescr object id which can be represented as ifTable.ifEntry.ifDescr or numerically as
188.8.131.52.184.108.40.206.1.2. Similarly, interface speed is ifTable.ifEntry.ifSpeed or
Now that you understand how individual table entries are accessed we need to talk how multiple rows within a table are accessed. As mentioned earlier individual values are accessed using unique identifiers. So in the interface table example above, we would have first interface referenced using instance value 1, second with instance value 2, etc. That means that first interface name will have object id:
It is not a requirement that instance id be a single value. In some cases instance value can contain multiple id values. For this reason it is always best to check how many Id’s are following the value object id you are retrieving.
So let’s try to represent this in a more visual way:
I am hoping that you can follow the above and that indexing of SNMP values on an agent makes sense. Just to clear up one thing that seams to confuse a lot of people. Object identifiers are numerical values. Names like ifTable, ifEntry, etc. are used when writing MIB files and are in no way part of the SNMP protocol itself. They are just a human readable “helper”.
SNMP Value Types
Now that you understand how information is organized on the agent, lets talk about what kind of information is stored by the agent.
Data values that object identifiers point to are of a few base types. Data types available in Snmp#Net library are:
|Integer32||signed 32-bit integer|
|Counter32||same as Integer32, signed 32-bit integer (equivalent to Counter in SMIv1)|
|Gauge32||unsigned 32-bit integer (equivalent to Gauge in SMIv1)|
|OctetString||byte array used to store both binary data and text strings|
|ObjectId||integer array representing an object identifier|
|Counter64||signed 64-bit integer (only available in SMIv2)|
|TimeTicks||unsigned 32-bit integer representing time in 1/100 of seconds (10ms)|
|Null||Empty or no value|
Each Oid in the MIB is matched with a value. Value can be any of the above listed types (including another Oid or a Null value).
Oid and Value pair are known as VariableBinding. Each SNMP request and reply consists of one or more VariableBindings.
So a simple exchange between a manager and an agent would look like:
manager => GET Oid(220.127.116.11.18.104.22.168.0) agent => RESPONSE Oid(22.214.171.124.126.96.36.199.0) OctetString(my servers sysDescription)
SNMP Request Types
Every version of Simple Network Management Protocol supports the following 3 request types:
- GET – request a single value by its Object identifier
- GET-NEXT – request a single value that is next in the lexical order from the requested Object Identifier
- SET – request for agent to set the Object Identifier variable to the supplied value
SNMP versions 2c and 3 support an additional request type called GET-BULK.
GetBulk request performs multiple GetNext requests and returns the result in a single response. Besides the request Oid that is in every SNMP request type, GetBulk introduces two additional options. They are non-repeaters, tells the agent how many Oid’s in the request should be treated as Get request variables, and max-repetitions, telling the agent how many GetNext operations to perform on each request variable (that is not covered by the non-repeaters option) and return the values in a single reply.
This is a little much to understand so here is an example you will probably need to use. Lets assume you wish to collect utilization information for all interfaces on an agent. One of the issues with utilization information is that you need a reliable time information so you can calculate the returned value delta between two retrieved utilization values. You cannot use the clock on the manager system because delay between replies can vary request by request (network delay can be 50ms one request and then 150ms on the next and then 2 second) making the delta value very unreliable.
To work around the reliable clock issue you can use sysUpTime value on the agent. This is the value representing the time since agent started in 1/100 of a second (10 milliseconds).
So now your request will need to retrieve sysUpTime and utilization information for all interfaces.
For this example we will assume that device has 10 interfaces with consecutive instance values.
This is what your request would look like:
Request-GetBulk non-repeaters = 1 max-repetitions = 10 sysUpTime.0 ifInOctets
Agent will respond to this request with:
Response: sysUpTime.0 : (TimeTicks)<some value> ifInOctets.1 : (Counter32)<some value> ifInOctets.2 : (Counter32)<some value> ifInOctets.3 : (Counter32)<some value> ifInOctets.4 : (Counter32)<some value> ifInOctets.5 : (Counter32)<some value> ifInOctets.6 : (Counter32)<some value> ifInOctets.7 : (Counter32)<some value> ifInOctets.8 : (Counter32)<some value> ifInOctets.9 : (Counter32)<some value> ifInOctets.10: (Counter32)<some value>
As you can see from the above, non-repeaters value has instructed the agent to treat the first Oid in the request (sysUpTime.0) as a Get request. Remaining Oid(s) in the request had GetNext operation performed max-repetitions times (in this case 10) and all values were returned in a single reponse.
GetBulk is considerably more efficient then other operations when multiple consecutive values need to be retrieved and you should use them whenever possible since, in the example above you have retrieved data that would require 1 x Get and 10 x GetNext requests to perform without GetBulk.
On a side note, if all you wish to perform are consecutive GetNext operation in a GetBulk request, set the non-repeaters value to 0.
Protocol Data Unit
Each request is contained in an appropriate (for the request) Protocol Data Unit.
Protocol Data Unit contains the type value, identifying operation type, ErrorStatus value, status of the operation (0 = noError, != 0 error), ErrorIndex, index of the value that is the cause of the error RequestId, unique identifier that helps to match requests and replies, and VariableBinding list that contains Oid to value mappings that are part of the request or reply.
Notifications are state or event updates sent by the agent to pre-configured receivers. There 2 types of notifications available in the SNMP standard, traps and informs.
Only difference between traps and informs is that traps and unacknowledged (kind of send and forget) messages sent by agents. Informs are expected to be acknowledged by receivers and sender agent will perform pre-configured number of retries before giving up.
SNMP Traps are supported in all versions of SNMP. Informs are supported in SNMP versions 2c and 3.
SNMP version 1 trap packet format is different from packets used in SNMP versions 2c and 3. When SNMP version 1 protocol standard was released notifications were viewed as needing a completely separate packet format from request/reply packets to perform their function. With SNMP version 2c traps start using standard request/reply packet format to send notifications.
SNMP Trap example
To demonstrate how notifications work, lets use a simple example. On a router agent interface goes down. This is an event that requires a notification be sent. Agent constructs a notification packet (either trap or inform) and sends it to all pre-configured destinations. When packet is received by the manager application, if notification is an inform response is constructed and send back to the agent. If packet is trap notification is processed by the manager without any kind of acknowledgement sent back to the agent.
SNMP Inform example
SNMP Version 1 Traps
SNMP version 1 has a distinct packet format. Two values that SNMP version 1 trap packet contains are Generic Error code and Specific Error code. Generic Error is used to send a notification about a limited number of predefined events. Things like LinkUp, LinkDown are pre-defined.
One of the Generic Error codes is a value (EnterpriseSpecific) that specifies that notification refers to a vendor specific value. When Generic Event value is set to this, Specific Event specifies vendor specific error codes.
SNMP Version 2c and 3 Traps
With the introduction of SNMP version 2c dedicated SNMP Trap packet that was used in version 1 of the protocol has been obsoleted. Standard SNMP request/reply packet is used with two values that have to be added to the beginning of the variable binding list.
SNMP version 2 trap variable binding list starts with the sysUpTime.0 value and trapObjectID.0 value. trapObjectID.0 value is an Oid value that tells the receiver what kind of event has occurred. Additional Oid/Value pairs follow the two mandated values further describing the event.
SNMP v2c and v3 traps are unacknowledged notifications. Agent has no idea if any of the notification receivers that it sent traps to have received them and it doesn’t care.