Understanding SNMP Stack
Understanding SNMP Stack
Following acticle is excerpted from various references and presents only what i deemed as relevant for my
knowledge. It does not start from the basics of what SNMP is but deals with only those points which i think
i can look back to for reference. Thats why its a notes on SNMP and no tutorial. In the references section an
absolute beginner may find some useful links which will be more enlightening for him. The main purpose
behind this notes is to learn how an SNMP stack (for atleast version 1 of SNMP) is coded. To this end, i
started with the basics of SNMP data types, the PDU format, MIB syntax (though very briefly touched
upon just to illustrate the usage of the SNMP data types), and the different SNMP versions, their value-
additions to the protocol. After the basics i will cover the implementation of SNMP stack taking one freely
available core SNMP stack which does not have the agent (extensible or otherwise) built into it nor does it
have a MIB parsing module because they are deemed only as utilities to the core of the Stack for bulding
applications.
- Compiled By -
Watsh Rajneesh
Software Engineer, Quark (R&D Labs)
wrajneesh@bigfoot.com
Contents
1. Understanding SNMP
b. Understanding of an SNMP Stack (Refer to the TCP/IP Illustrated Vol. II and one of the Java SNMP
Stacks you have preferably the Westhawk one.)
c. A brief intro on SNMP versions and basics (refer to FAQ you have and the network_doc.html explaning
network management concepts for Solistice EM Solution of Sun Micro.).
d. If time permits and coding seems to be not too much then code a stack in C++. (Refer to the smaller Java
SNMP stack you have.Study it well, identify the objects and code it in C++.) The aim is to understand how
the stack is written and not to reinvent the wheel by rewriting the algos.
Understanding SNMP
How does SNMP use ASN.1?
ASN.1 is a interface definition language which defines the contract between the client and server
applications. In SNMP, a subset of the ASN.1 language is used and its feature to define new textual
conventions (eg. DisplayString, IpAddress,etc.) An SNMP MIB file is written in this subset of ASN.1 and
thus the MIB defines the interface for the SNMP client (manager) and the SNMP server (agent).
The Structure of Management Information (SMI) defines the rules for describing management
information, using Abstract Syntax Notation One (ASN.1). The SNMPv1 SMI is defined in RFC 1155. The
SMI makes three key specifications:
Three simple data types are defined in the SNMPv1 SMI, all of which are unique values:
• integers, The integer data type is a signed integer in the range of -2,147,483,648 to 2,147,483,647.
• octet strings, Octet strings are ordered sequences of 0 to 65,535 octets.
• object IDs. Object IDs come from the set of all object identifiers allocated according to the rules
specified in ASN.1.
• Network addresses—Represent addresses from a protocol family. SNMPv1 supports only 32-bit
IP addresses.
• Counters—Nonnegative integers that increase until they reach a maximum value; then, the
integers return to zero. In SNMPv1, a 32-bit counter size is specified.
• Gauges—Nonnegative integers that can increase or decrease but retain the maximum value
reached.
• Time ticks—A hundredth of a second since some event.
• Opaques—An arbitrary encoding that is used to pass arbitrary information strings that do not
conform to the strict data typing used by the SMI.
• Integers—Signed integer-valued information. This data type redefines the integer data type,
which has arbitrary precision in ASN.1 but bounded precision in the SMI.
• Unsigned integers—Unsigned integer-valued information that is useful when values are always
nonnegative. This data type redefines the integer data type, which has arbitrary precision in ASN.1
but bounded precision in the SMI.
SNMP MIB Tables: The SNMPv1 SMI defines structured tables that are used to group the instances of
a tabular object (an object that contains multiple variables). Tables contain zero or more rows that are
indexed to allow SNMP to retrieve or alter an entire row with a single Get, GetNext, or Set command.
SNMP is a simple request-response protocol. The NMS issues a request, and managed devices return
responses. This behavior is implemented by using one of four protocol operations:
• Get—Used by the NMS to retrieve the value of one or more object instances from an agent. If the
agent responding to the Get operation cannot provide values for all the object instances in a list,
the agent does not provide any values.
• GetNext—Used by the NMS to retrieve the value of the next object instance in a table or list
within an agent (appearing next in the lexicographical order of OID).
• Set—Used by the NMS to set the values of object instances within an agent.
• Trap—Used by agents to asynchronously inform the NMS of a significant event.
SNMP v2
In theory, SNMPv2 offers a number of improvements to SNMPv1, including additional protocol operations.
The SNMPv2 SMI is described in RFC 1902. It makes certain additions and enhancements to the SNMPv1
SMI-specific data types, such as including
• bit strings, Bit strings are defined only in SNMPv2 and comprise zero or more named bits that
specify a value.
• network addresses, Network addresses represent an address from a particular protocol family.
SNMPv1 supports only 32-bit IP addresses, but SNMPv2 can support other types of addresses as
well.
• counters. Counters are non-negative integers that increase until they reach a maximum value and
then return to zero. In SNMPv1, a 32-bit counter size is specified. In SNMPv2, 32-bit and 64-bit
counters are defined.
The SNMPv2 SMI specifies information modules, which include a group of related definitions. Three types
of SMI information modules exist:
The Get, GetNext, and Set operations used in SNMPv1 are exactly the same as those used in SNMPv2.
SNMPv2, however, adds and enhances protocol operations. The SNMPv2 trap operation, for example,
serves the same function as the one used in SNMPv1. However, a different message format is used.
SNMPv2 also defines two new protocol operations:
• GetBulk—Used by the NMS to efficiently retrieve large blocks of data, such as multiple rows in a
table. GetBulk fills a response message with as much of the requested data as fits.
• Inform—Allows one NMS to send trap information to another NMS and receive a response. If the
agent responding to GetBulk operations cannot provide values for all the variables in a list, the
agent provides partial results.
SNMP Interoperability
As presently specified, SNMPv2 is incompatible with SNMPv1 in two key areas: message formats and
protocol operations. SNMPv2 messages use different header and protocol data unit (PDU) formats than
SNMPv1 messages. SNMPv2 also uses two protocol operations that are not specified in SNMPv1.
Furthermore, RFC 1908 defines two possible SNMPv1/v2 coexistence strategies: proxy agents and
bilingual network-management systems.
Proxy Agents: An SNMPv2 agent can act as a proxy agent on behalf of SNMPv1 managed devices, as
follows:
SNMPv1 messages contain two parts: a message header and a protocol data unit (PDU). Figure 56-4
illustrates the basic format of an SNMPv1 message. SNMPv1 message headers contain two fields: Version
Number and Community Name.
• Version number—Specifies the version of SNMP used.
• Community name—Defines an access environment for a group of NMSs. NMSs within the
community are said to exist within the same administrative domain. Community names serve as a
weak form of authentication because devices that do not know the proper community name are
precluded from SNMP operations.
SNMPv1 PDUs contain a specific command (Get, Set, and so on) and operands that indicate the object
instances involved in the transaction. SNMPv1 PDU fields are variable in length, as prescribed by ASN.1.
SNMPv1 Get, GetNext, Response, and Set PDUs Contain the Same Fields and is shown below:
• ColdStart (0)
• Warmstart (1)
• LinkDown (2)
• LinkUp (3)
• AuthenticationFailure (4)
• EgpNeighborLoss (5)
• EnterpriseSpecific (6)
• Non repeaters—Specifies the number of object instances in the variable bindings field that should
be retrieved no more than once from the beginning of the request. This field is used when some of
the instances are scalar objects with only one variable.
• Max repetitions—Defines the maximum number of times that other variables beyond those
specified by the Non repeaters field should be retrieved.
• Variable bindings—Serves as the data field of the SNMPv2 PDU. Each variable binding
associates a particular object instance with its current value (with the exception of Get and
GetNext requests, for which the value is ignored).
ifAdminStatus OBJECT-TYPE
SYNTAX INTEGER {
up(1), -- ready to pass packets
down(2),
testing(3) -- in some test mode
}
ACCESS read-write
STATUS mandatory
DESCRIPTION
"The desired state of the interface. The
testing(3) state indicates that no operational
packets can be passed."
::= { ifEntry 7 }
The MIB structure is hierarchical, like a file system, but at the bottom are the OIDs, which are like
variables, constants, volitoles etc., not files. The MIB files provide ASN.1 definitions of blocks of OIDs,
extending the MIB structure as needed.
• Configuration Management: names all elements in a network and specifies their characteristics
and state. This includes the information needed so maps of the network can be drawn, and
exploded diagrams of device components can be shown by network management station
application programs.
• Performance Management: determines the effective utilization of the network and components
of network devices. Performance analysis helps network managers monitor network availability,
response time, throughput, and resource usage.
• Fault Management: detects, isolates, and corrects network problems.
• Security Management: controls access and protection of information on the network from
disclosure or modification.
• Accounting: measures usage and computes costs based on specified policies. This information
can be used for billing applications.
Managed devices are ones that can be monitored and controlled and are capable of reporting events. A MIB
defines managed objects using a framework called the SMI. The SMI
defines how management information is grouped and named; allowed operations; permitted data types; and
the syntax for specifying MIBs. Managed objects are abstractions of resources on systems that exist
independently of their need to be managed. The MIB for these objects does not define the actual realization
of these resources. Some objects (such as the location of a system) have only one instance, while others
(such as network connections) have multiple instances. Related objects that have the same type of instance
are organized into conceptual tables in SNMP MIBs. The identity of an object together with its associated
instance is called an SNMP variable.
The SMI is similar to the schema for a database system. It defines the model of managed objects and the
operations that can be performed on the objects, as well as data types that are permitted for the objects. The
OSI approach is similar to an object-oriented model, while the SNMP approach is similar to a relational
database model. That is why we have object to relational tools which map the managed objects (identified
as objects of an OOPS language) to tables in the RDBMS databases. So each object's state is both kept in
members of the object and also in a persistent form in the relational tables.
OIDs: Objects are unambiguously identified (or named) in SNMP by assigning them an object identifier
(OID). Globally unique for all space and time, OIDs are a sequence of nonnegative integers organized
hierarchically like UNIX or PC-DOS file system names. For ease of use, a textual name is associated with
each sequence element, or component, of an OID. The last component name is used by itself as a shorthand
way of naming an object. To help make sure there is no confusion in naming an object since the shorthand
names do not have to be unique, all textual names of objects defined by IETF working groups are, by
convention, made unique by using a different prefix for objects in each new MIB. SNMP uses an encoded
form of the numeric value, not the textual name. OIDs are written in one of the following formats:
Syntax:
"{" { {<name>["("<number>")"]} | <number>}... "}"
or
<number> ["."<number>]...
Where
<name> is a component name; and
<number> is a component value.
Eg:
{ iso org(3) dod(6) internet(1) } or 1.3.6.1
{ internet 4 } or 1.3.6.1.4
{ tcp 4 } or 1.3.6.1.2.1.6.4
The precise syntax to specify an OID depends on where the OID is used. These examples illustrate a
shorthand specification of OIDs. The first <name> in the OID can be any name in the hierarchical OID tree
as long as it is unique within the context that it is used. There is no shorthand for specifying OIDs in the
numeric form. The use of <name>"("<number>")", by convention, is not used in IETF developed MIBs.
OIDs can be used to uniquely identify anything, not just managed objects. Some OIDs are used just as
placeholders to help organize the OID hierarchy. In SNMPv2, the traps are also having trapoids. Thats how
the SNMPv2 trap PDU has differed from SNMPv1 trap PDU.
The following OID prefixes that are important when writing an SNMP MIB:
internet which is defined as { iso(1) org(3) dod(6) 1 }
mgmt which is defined as { internet 2 }
experimental which is defined as { internet 3 }
private which is defined as { internet 4 }
mib, mib-1, and mib-2 which are defined as { mgmt 1 }
enterprises which is defined as { private 1 }
Objects for standard SNMP MIBs are defined under the "mib" branch of the hierarchy. The existence of
"mib-1" and "mib-2" are the result of a versioning scheme that didn't quite work out. Present day MIBs
hould reference "mib-2". Experimental MIBs being developed by IETF working groups define objects
under the "experimental" branch. Proprietary MIBs define objects within an organization's subtree located
under the "enterprises" branch. To get a number under the enterprises branch, simply contact the Internet
Assigned Numbers Authority (IANA) and request an enterprise number. The assignment of numbers within
an enterprise is determined locally. IETF working groups should obtain a number under the experimental
branch through coordination with the network management area director and the IANA.
MIB Modules: The MIB for SNMP is defined by a collection of module definitions that may be
contained in one or more documents. MIB-I and MIB-II are the first and second generations of the core
definitions for TCP/IP hosts and routers. Additional MIBs have been defined for routing protocols such as
OSPF and BGP, interface types such as token ring and DS1, protocol stacks such as DECnet, and device
types such as bridges and terminal servers. Proprietary MIBs have been defined to extend existing MIBs or
to specify areas not covered by IETF-authored MIBs. Modules are a mechanism to scope names. As long as
the module names are unique and all object names within a module unique, then it is allowable to have
duplicate object names in separate modules. (Using duplicate names should be avoided where possible.)
MIB module names must start with an uppercase letter that is followed by an arbitrary number of letters,
digits, and hyphens. A hyphen can not be the last character nor can a hyphen be immediately followed by
another hyphen(which means a comment statement!). However, MIB compilers or network management
station software may put length restrictions on names. Within a module are defined registration points
in the OID tree, SNMP managed objects, values for items that have syntax type of object identifier,
traps, sequences, and textual conventions.
Syntax:
<mib> = <module>...
<module> =
<ModName> [ <modId> ] "DEFINITIONS" "::=" "BEGIN"
[ "IMPORTS" <importList>... ";" ]
[ <smiItem>... ]
[ <textConvItem>... ]
{ <oidItem> | <objectItem> |
<seqItem> | <trapItem> }...
"END"
<importList> = <importItem> [ "," <importItem> ]...
"FROM" <ImportModName>
Where
<ModName> is the name of a MIB module;
<modId> is a now obsolete method to assign an object identifier to a
module;
<smiItem> is a definition for SMI items such as syntax types, the
OBJECT-TYPE and TRAP-TYPE macros;
<importItem> is an item defined in another MIB module;
<ImportModName> is the name of another previously defined MIB module;
<textConvItem> is a definition of a textual convention;
<oidItem> is a definition of an object identifier;
<objectItem> is a definition of an item with the OBJECT-TYPE macro;
<seqItem> is a definition of a sequence; and
<trapItem> is a definition of an item with the TRAP-TYPE macro.
A new MIB may not define any additional SMI items such as new syntax types or ASN.1 macros. The
IMPORTS clause allows items defined in other modules to be used in the module being defined. This is
useful (and necessary) to pick up the definitions of the OBJECT-TYPE macro from the Concise MIB RFC
or the syntax types defined in the SMI
RFC. An item may only be imported if the module has been previously defined. Textual conventions are a
"conforming" mechanism to extend the SMI syntax types without adding a new syntax type encoding.
Object identifier items are registration points in the OID tree, values for items that have the syntax of object
identifier, and groups for SNMP objects. The OBJECT-TYPE macro is used to define tables, rows, and
simple and columnar objects. Sequences are used in defining "conceptual" tables. Lastly, the TRAP-TYPE
macro is used to define traps. Within a MIB definition, ASN.1 comments may be used to provide additional
insight into the organization and definition of items within the MIB.
Comments begin with two hyphens and end with the end of the line.
Typically a MIB is "extracted" from its defining document to be used in a managment station.The position
in the OID tree of the objects defined in the module must be determined before writing a MIB
module. For MIBs developed by IETF working groups, a branch should be assigned under the "internet
experimental" branch. For private MIBs, a branch needs to be assigned under an "enterprises"
branch in the "internet private" tree. Local customs determine the scheme used for assignments under
each "enterprises" branch. One local custom is to create both an "experimental" branch and a branch for
each released MIB module. Branches can be created within the experimental branch for testing and
prototyping. Once a MIB is published, items cannot be changed; they can only be obsoleted and re-created.
Thus, the standard practice is to design a MIB under an "experimental" branch, test it out, and then move it
to a "standard" branch when the MIB document is published.
MIB modules almost always start with the same format. A unique name is chosen for the module followed
by imports for the registration point objects; for syntax types used within the module; and for the OBJECT-
TYPE and TRAP-TYPE macros. Items should be imported only when used within a module.
1. Object Identifier Items: In SNMP MIBs, items defined as object identifiers are high-level
registration points in the object identifier tree, groups, or values for items that have the syntax type
of object identifier. Names of object identifier items must start with a lowercase letter that is
followed by an arbitrary number of letters, digits, and
hyphens. A hyphen can not be the last character nor can a hyphen be immediately followed by
another hyphen. However, MIB compilers or network management station software may put
length restrictions on names. A special type of placeholder is an SNMP group is used to
organize MIB objects together. For example, in MIB-II, "system" is a group containing
objects specifying descriptive, high-level information about a managed device such as
location. Besides organizing together similar objects, groups are also used to specify units of
conformance. Groups can be either mandatory or optional. When they are mandatory, all contained
objects must be present for a device to claim conformance to the MIB defining the group. When
they are optional, the entire set of contained objects must be present when the capability described
by the objects is present, and all contained objects should be absent when the capability described
by the objects is not present. For example, if a managed device is a router that implements the
EGP routing protocol, then it must implement the EGP group to claim conformance to MIB-II.
Finally, items may be defined as object identifiers so that they may be returned as the value
of an item that has the syntax type of object identifier. For example, the item sysObjectID
which is defined in the MIB-II RFC has the syntax type of object identifier. The value of this item
specifies the type of device that is being managed. Each vendor should define object identifier
items for each type of SNMP-managed device it produces.
Syntax:
<oidItem> = <oidName> "OBJECT" "IDENTIFIER" "::=" "{" <parent>
<number> "}"
Where:
<oidName> is the name of the OID item being defined;
<parent> is the name of the directly containing item
in the OID tree; and
<number> is the value of the last component of the
item being defined.
Example:
egp OBJECT IDENTIFIER ::= { mib-2 8 }
2. Managed Object Definitions: Three types of objects that can be defined using the OBJECT-
TYPE macro: tables, rows, and leaf objects (simple and column). The names of these items
must start with a lowercase letter that is followed by an arbitrary number of letters, digits, and
hyphens. A hyphen can not be the last character nor can a hyphen be immediately followed by
another hyphen. However, MIB compilers or network management station software may put
length restrictions on names.
Syntax:
Where:
<objectName> is the name of the item being defined;
<parent> is the name of the directly containing item in the OID
tree;
<number> is the value of the last component of the item being
defined; and Values for <access>, <status>,<leafSyntax>, etc.
are defined later
o Table Objects: A table consists of rows. Table construction is somewhat strange due to
the history of the definition of the SNMP SMI. A table is not retrievable via SNMP; only
the "columnar" objects within a table can be retrieved. The syntax for a table must be
"SEQUENCE OF <sequence>". By convention, tables are
named with the suffix "Table". By convention also, the name of the associated sequence
is the prefix of the table name (without the "Table" suffix) and the first letter is changed
to uppercase. The suffix of the sequence, by convention, is set to "Entry". For example, if
"fooTable" was the name of a table, then the associated sequence would be named
"FooEntry". The access for tables must be "not-accessible".
Syntax:
<tableName> "OBJECT-TYPE"
"SYNTAX" "SEQUENCE" "OF" <SequenceName>
"ACCESS" "not-accessible"
"STATUS" <status>
[ "DESCRIPTION" <description> ]
[ "REFERENCE" <reference> ]
"::=" "{" <parent> <number> "}"
<tableName> = <name>"Table"
<SequenceName> = <Name>"Entry"
Where:
<name> is the prefix of the table being defined;
<Name> is the prefix of the associated sequence;
<parent> is the name of the directly containing item in the
OID tree;
<number> is the value of the last component of the item
being defined; and Values for <status>, <description>, etc.
are defined later.
Example:
ifTable OBJECT-TYPE
SYNTAX SEQUENCE OF IfEntry
ACCESS not-accessible
STATUS mandatory
::= { interfaces 2 }
o Row Objects: A row consists of columns. A row is not retrievable via SNMP; only the
"columnar" objects within a row can be retrieved. A get or getnext request can be used to
get all the columns for a selected row. The name of a row, by convention, is taken as the
name of the associated table with the "Table" suffix replaced by "Entry". The syntax
type for a row must be the sequence used by the associated table. The access for the
row must be "not-accessible". The OID value for the row must be the same as the
associated table with the addition of a single component of value 1. The INDEX
clause must be used to specify rules for "instance" construction of the columnar objects
of the table. Index is like a primary key(s) of a relational table.
Syntax:
<rowName> "OBJECT-TYPE"
"SYNTAX" <SequenceName>
"ACCESS" "not-accessible"
"STATUS" <status>
[ "DESCRIPTION" <description> ]
[ "REFERENCE" <reference> ]
"INDEX" "{" <indexItems> "}"
"::=" "{" <tableName> 1 "}"
<rowName> = <name>"Entry"
<SequenceName> = <Name>"Entry"
<tableName> = <name>"Table"
<indexItems> = <indexItem> [ "," <indexItem> ]...
Where:
<name> is the prefix of the row being defined and the
prefix of the associated table;
<Name> is the prefix of the associated sequence;
<indexItem> is the name of an item in the sequence for the
row (or a syntax type name); and Values for <status>,
<description>, etc are defined later.
Example:
ifEntry OBJECT-TYPE
SYNTAX IfEntry
ACCESS not-accessible
STATUS mandatory
DESCRIPTION
"An interface entry containing
objects at the
subnetwork layer and below for a
particular
interface."
INDEX { ifIndex }
::= { ifTable 1 }
IfEntry ::=
SEQUENCE {
ifIndex
INTEGER,
ifDescr
DisplayString,
ifType
INTEGER,
ifMtu
INTEGER,
ifSpeed
Gauge,
ifPhysAddress
PhysAddress,
ifAdminStatus
INTEGER,
ifOperStatus
INTEGER,
ifLastChange
TimeTicks,
ifInOctets
Counter,
ifInUcastPkts
Counter,
ifInNUcastPkts
Counter,
ifInDiscards
Counter,
ifInErrors
Counter,
ifInUnknownProtos
Counter,
ifOutOctets
Counter,
ifOutUcastPkts
Counter,
ifOutNUcastPkts
Counter,
ifOutDiscards
Counter,
ifOutErrors
Counter,
ifOutQLen
Gauge,
ifSpecific
OBJECT IDENTIFIER
}
3. Sequence Definitions: A sequence is used to specify the "columns" in a row. The name of a
sequence must start with an uppercase letter that is followed by an arbitrary number of letters,
digits, and hyphens. A hyphen can not be the last character nor can a hyphen be immediately
followed by another hyphen. However, MIB compilers or network management station software
may put length restrictions on names.For most tables and rows the items of the sequence are the
"children" of the row object. However, if the table is an extension to an existing table, all or a
subset of the columnar objects from the existing table may additionally be added to the
sequence.In addition to the names of the columnar items for the row, the syntax for these items
must be specified. Instead of a word-for-word match of the item's syntax, a simplified version
should be given. The size and range clauses, if used in the definition of the item, do not have to be
specified. If they are, the values must match the definition. The values for enumerated integers
may not be specified. The name of the sequence should, by convention, be the same as the row
name with the first letter changed to uppercase. A sequence can be used with only one table and
row. Also, a sequence may not be imported from another module.
Syntax:
<seqItem> = <SequenceName> "::=" "SEQUENCE" "{"
<columnItem> <leafSyntax>
{ "," <columnItem> <leafSyntax> }...
"}"
<SyntaxName> = <Name>"Entry"
Where:
<Name> is the prefix of the sequence being defined;
<columnItem> is name on an item in the sequence; and
<leafSyntax> is the simplified syntax for the item.
Example:
ipAddrEntry ::= SEQUENCE {
ipAdEntAddr IpAddress,
ipAdEntIfIndex INTEGER,
ipAdEntNetMask IpAddress,
ipAdEntBcastAddr INTEGER,
ipAdEntReasmMaxSize INTEGER
}
Leaf Objects: A leaf object is the smallest grouping of information. Together, an object's
identity and associated "instance" locate one piece of information, called an SNMP variable. These
are the operands in SNMP operations. "Simple" leaf objects such as the number of interfaces in a
device, have only a single instance. In this case, the instance is specified as one component with a
value of zero. "Columnar" leaf objects are organized into conceptual tables. This is done because it
is possible to have none, one, or multiple instances of the information, such as TCP connections to
a device. The instance format for a columnar object is determined by the value of the INDEX
clause for the containing row. Simple objects are organized under a group and are usually given
the same prefix as the group. Columnar objects are organized under a row and are usually given
the same prefix as the row.
Syntax:
<leafName> "OBJECT-TYPE"
"SYNTAX" <leafSyntax>
"ACCESS" <access>
"STATUS" <status>
[ "DESCRIPTION" <description> ]
[ "REFERENCE" <reference> ]
[ "DEFVAL" "{" <defaultValue> "}" ]
"::=" "{" <parent> <number> "}"
Where:
<leafName> is the name of the leaf object being defined;
<parent> is the name of the directly containing item in the OID
tree (a row or a group);
<number> is the value of the last component of the item being
defined; and Values for <leafSyntax>, <access>, <status>, etc.
are defined later.
Examples:
sysUpTime OBJECT-TYPE
SYNTAX TimeTicks
ACCESS read-only
STATUS mandatory
::= { system 2 }
ipAdEntAddr OBJECT-TYPE
SYNTAX IpAddress
ACCESS read-only
STATUS mandatory
::= { ipAddrEntry 1 }
Where:
<textConvName> is the name of the textual convention being
defined; and
<leafSyntax> is any defined syntax type including a textual
convention.
Examples:
5. Value for SYNTAX: The value for <syntax> determines the type of the managed object. As
specified earlier, table objects have a value of "SEQUENCE OF <SequenceName>". Row objects
have a value of "<SequenceName>". Note that the first character of the sequence's name is
uppercase. Leaf objects can not specify the name of a sequence for their syntax. Their value for
<syntax> is defined by <leafSyntax> as shown below:
Syntax:
<leafSyntax> = { "INTEGER" [ <range> | <enums> ] } |
{ "OCTET" "STRING" [ <size> ] } |
{ "OBJECT" "IDENTIFIER" } |
{ <smiApplType> } |
{ <textConvName> [ <range> | <size> ] }
Where:
<lower> and <higher> may be positive or negative integers,
bitstring constants, or hexstring constants;
<enumName> starts with a lowercase letter followed by arbitrary
number of letters, digits, and hyphens.A hyphen can not be the
last character nor can a hyphen be immediately followed by
another hyphen;
<enumValue> is a positive integer, bitstring, or hexstring
constant not having a value of zero; and
<smallest> and <largest> may be non-negative integers, bitstring
constants, or hexstring constants.
o INTEGER: Integers which may have an associated value range assigned to them.
Integers by convention must fit into 32 bits. (Note: The range of the integer should be,
but is not always, specified. This indicates the implementation characteristics to both the
agent and manager writers.) Newer MIBs are starting to use hex
constants to specify the range when doing so makes the range more obvious. If so, these
values are assumed to be positive numbers.
examples:
SYNTAX INTEGER (0..65535)
SYNTAX INTEGER (0..'ffff'h)
SYNTAX INTEGER (0..'ff'H)
o <enumerated>: A special case of integer. Zero and negative numbers are not
permitted values according to the SMI RFC[3]. However, proprietary MIBs may
incorrectly use these values. The object must take only those values that are listed in the
enumeration. A value called "other" should be provided, but is not always
present in older MIBs. The object's DESCRIPTION clause should describe the values
that are not obvious.
examples:
SYNTAX INTEGER {
gateway(1),
host(2) }
SYNTAX INTEGER {
other(1),
invalid(2),
direct(3),
indirect(4) }
o <integerBitstring>: A special case of the integer. (Note: This is also called a "sum".)
This is usually used for short bit strings that are 32 or fewer bits long. Bit numbering
starts at zero, which is positioned at the low order end of the integer. The DESCRIPTION
clause should specify the position (i.e., value) of each bit.
Descriptions of the bit values are typically written using 2 raised to the power of the bit
number.
example:
SYNTAX INTEGER (0..127)
o OCTET STRING: A string of bytes that may have an associated size assigned to
them. (Note: The size of the string should be, but is not always, specified. This indicates
the implementation characteristics to both the agent and manager writers.) Items defined
as an octet string are intended to be binary bytes of data. The
size is fixed if only one "size" is specified and is varying if no "size" or two "sizes" are
specified.
examples:
SYNTAX OCTET STRING (SIZE (0..9)) -- varying
SYNTAX OCTET STRING -- varying
SYNTAX OCTET STRING (SIZE (6)) -- fixed
o <octetBitstring>: A special case of the octet string type. This is usually used for long
bit strings (i.e. those longer than 32 bits). Bits are numbered starting with zero, which is
positioned as the high order bit of the first byte. Bits are packed eight to a byte. Any
unused bits in the last byte should be set to zero, but must be
ignored. The DESCRIPTION clause should describe each bit, with the size specified as a
constant number of octets. There may be some applications where the size may be
variable.
example:
SYNTAX OCTET STRING (SIZE (4))
o DisplayString: A well known textual convention which is a special case of the octet
string type where all the bytes are printable ASCII characters. Sometimes,
incorrectly, a variable may include formatting characters such as CR and LF, and the C
programming language string terminator character zero. (Note: The size of the String
should be, but is not always, specified. This indicates the implementation characteristics
to both the agent and manager writers.)
example:
SYNTAX DisplayString (SIZE (0..256))
o PhysAddress: A well known textual convention which is a special case of the octet
string type where all the bytes are the binary in "network order" of a media- or
physical-level address. (Note: The size of the string should be, but is not always,
specified. This indicates the implementation characteristics to both the agent and manager
writers.)
example:
SYNTAX PhysAddress (SIZE (6))
o OBJECT IDENTIFIER: An object identifier value.
example:
SYNTAX OBJECT IDENTIFIER
o <ObjectName>: Special case of the object identifier, where the value is restricted to the
OIDs of MIB objects and trees.
o NetworkAddress: Used to indicate an address choice from one of the possible
protocol families. Currently, only IP addresses are supported. Use of this type is being
discontinued.
o IpAddress: A four byte octet string in network order.
o Counter: A nonnegative integer that counts up to 2^ 32 -1 and wraps back to zero. A
range may not be specified.
o Gauge: A nonnegative integer that may increase or decrease but which latches at its
maximum value of 2 32 -1. A range may not be specified.
o TimeTick: A nonnegative integer that counts time in hundredths of seconds since some
epoch with a limit of 2 32 -1. (The description of its use must identify the
reference epoch.) A range may not be specified.
o Opaque: A data type to encapsulate an arbitrary ASN.1 encoded data item. This is
usually used to hold data types for private MIBs that are not a type defined
above. This results in the original data being double-wrapped. (Note: Use of this type is
strongly discouraged.)
6. Values for ACCESS: The values for the ACCESS clause are specified as "read-only", "read-
write", "write-only", and "not-accessible" in the SMI RFC[3]. However, in SNMP MIBs,
tables and rows must have the value of "not-accessible" and leaf objects must have either "read-
only" or "read-write" values. An SNMP "MIB-view"
may add additional restrictions (or capabilities) to leaf objects so that <access> can be changed
from "read-write" to "read-only" or "not-accessible". Each object in a conformant MIB must have
at least one "MIB-view" that implements the <access> one-for-one with the MIB specification.
Note: a read-create access also exists in which case a new row can be created with values settable
for those columns for which the access is read-create. For others, the values are probably
generated within the agent application. For example:
--
-- GSMP ATM Encapsulation Table
--
gsmpAtmEncapTable OBJECT-TYPE
gsmpAtmEncapEntry OBJECT-TYPE
SYNTAX GsmpAtmEncapEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"An entry in the table showing
the encapsulation data for a specific
Switch Controller entity or Switch entity."
INDEX { gsmpAtmEncapEntityId }
::= { gsmpAtmEncapTable 1 }
gsmpAtmEncapEntityId OBJECT-TYPE
SYNTAX GsmpNameType
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"The Controller Id or Switch Id that is unique
within the operational context of the device. "
::= { gsmpAtmEncapEntry 1 }
gsmpAtmEncapIfIndex OBJECT-TYPE
SYNTAX InterfaceIndex
MAX-ACCESS read-create
STATUS current
DESCRIPTION
"The interface index for the virtual channel over
which
the GSMP session is established, i.e., the GSMP
control
channel for LLC/SNAP encapsulated GSMP messages on an
ATM data link layer."
::= { gsmpAtmEncapEntry 2 }
gsmpAtmEncapVpi OBJECT-TYPE
SYNTAX AtmVpIdentifier
MAX-ACCESS read-create
STATUS current
DESCRIPTION
" The VPI value for the virtual channel over which
the
GSMP session is established, i.e., the GSMP control
channel for LLC/SNAP encapsulated GSMP messages on an
gsmpAtmEncapVci OBJECT-TYPE
SYNTAX AtmVcIdentifier
MAX-ACCESS read-create
STATUS current
DESCRIPTION
" The VCI value for the virtual channel over which
the
GSMP session is established, i.e., the GSMP control
channel for LLC/SNAP encapsulated GSMP messages on
an
ATM data link layer."
DEFVAL { 15 }
::= { gsmpAtmEncapEntry 4 }
gsmpAtmEncapStorageType OBJECT-TYPE
SYNTAX StorageType
MAX-ACCESS read-create
STATUS current
DESCRIPTION
"The storage type for this entry. It should have
the same
value as the StorageType in the referring Switch
Controller entity or Switch entity."
DEFVAL { nonVolatile }
::= { gsmpAtmEncapEntry 5 }
gsmpAtmEncapRowStatus OBJECT-TYPE
SYNTAX RowStatus
MAX-ACCESS read-create
STATUS current
DESCRIPTION
"An object that allows entries in this table to
be created and deleted using the RowStatus
convention.
While the row is in active state it's not
possible to modify the value of any object
for that row except the gsmpAtmEncapRowStatus
object."
::= { gsmpAtmEncapEntry 6 }
7. Values for STATUS: The values for the STATUS clause are specified as "mandatory",
"optional", "obsolete", and "deprecated" by the SMI RFC[3]. However, in SNMP MIBs,
"optional" is not allowed. A whole subsection (group) may be optional, but individual objects can
not be labeled as "optional". An implementation of an agent
may not have access to the value of a "mandatory" object. In this case, gets and sets to the object
should return "noSuchName" errors and getnexts should simply return the next lexicographically
ordered object. Unimplemented objects in a mandatory group result in the agent being labeled as
"non-conformant" to that MIB group. An agent that returns "benign" values for readable objects or
does not change writable objects is also labeled as "non-conformant". The "obsolete" value is
meant to document the existence of an object that is no longer supported. However, the current
practice is to remove obsolete objects from a MIB and leave only a comment to indicate that they
are no longer used. Objects for which support will soon be dropped are given the value
"deprecated". These objects are mandatory until they are made "obsolete".
8. Value for DESCRIPTION: The actual value for the DESCRIPTION clause is a string enclosed
in double quotes that may be continued across multiple lines. It may not contain double quotes. It
is customary to line up continuation lines of a multiline quote in the same starting column and
leave the right edge ragged with no hyphenation. If quotes are needed within the quoted text, then
single quotes (ASCII apostrophes) are used. It is meant as information for agent and manager
writers and not as the "help text" for manager users.
9. Values for REFERENCE: The value for the REFERENCE clause is a "textual cross-reference"
to another document that describes the same object. This is used when converting MIBs from
other formats such as IEEE or OSI to SNMP MIBs. A reference citation in the text should write
out the name of the reference document.
10. Values for INDEX: It lists the columns of the row that are used as the instance specifiers. The
order of the items in the INDEX clause indicates the order that instance components are used in
constructing the instance information for columnar objects in the containing table.
11. Values for DEFVAL: The DEFVAL clause may only be included for leaf objects that are
columns in tables that are not used as the instance items. The value should be used as a hint for the
agent implementation when a row is created and the set request creating the row does not contain
values for all the writable columns in the row. The DEFVAL clause may only be included for leaf
objects that are columns in tables that are not used as the instance items. The value should be used
as a hint for the agent implementation when a row is created and the set request creating the row
does not contain values for all the writable columns in the row.
12. Instances: An SNMP variable is an object's identity and its instance value encoded as an OID.
Objects that are not in a table (i.e., simple objects) are given an instance with a single component
whose value is zero. For example, the SNMP variable for "sysDescr" (which is not in a table) is:
1.3.6.1.2.1.1.1.0 or sysDescr.0
For objects within a table, the definition of the row object must indicate with the INDEX clause
the columns and the order in which they must be used to specify instance values for items in the
row. (Note: instances must be defined as columns within the table (or use the discouraged practice
of a syntax type name).) Below listing gives the encoding rules for each base syntax type of an
instance item.
o Integer: A single component is used (note that only columns with nonnegative integer
values are valid).
simple object - sysDescr.0 or 1.3.6.1.2.1.1.1.0
(The instance is one component with value zero.)
o Fixed length string: "n" components are used, one for each byte in the string. The column
must be defined as a fixed size octet string or a textual convention that resolves to a fixed
size octet string.
columnar object - ifSpeed.1 or 1.3.6.1.2.1.2.2.1.5.1
(The instance is one component with the integer value of
ifIndex.)
o Varying length string: "n+1" components are used. The first component has the string
length and each byte of the string uses an OID component.
o IP address: Four components are used. Each byte of the IP address in network order uses
a component.
o Object identifier: "n+1" components are used. The first is the number of components in
the OID value. Each component in the value uses a component in the instance.
columnar object - partyTDomain.9.1.3.6.1.4.1.999.4.1
o Network Address: Five components are used. The first component has the value "1" to
indicate an IP address. The next four components store the four bytes of an IP address in
network order.
columnar object - atPhysAddress.3.1.4.5.6.7
• Put objects into logical groups. Use hierarchical subgrouping for more detailed arrangement.
Remember that a complete group may be designated as optional or mandatory. A placeholder
object (which is not itself a managed object) may be defined as an OID for the group. The IETF
MIB-II defines the following groups: system, interfaces, at, ip, icmp, tcp, udp, egp, transmission,
and snmp.
• No SNMP-managed object defined in the "mib" subtree may have an OID component with a value
of 0. Items that are not SNMP-managed objects that are identified by OIDs can use 0 as a
component value. (Note: SNMP variables may have 0 as a component value in the instance part.)
• The OID for a table's row object should be one level below the table and have the last component
with a value of 1. No other OIDs should be defined as siblings of the row object. The OIDs for the
columns in the row should be one level below the row object.
• In SNMP, aggregate objects are defined as tables. One or more columns of the table are
designated as the indices of the rows in the table. Tables cannot be defined within tables.
Therefore, potentially nested tables should be elevated to the same level as the original table.
Columns that are the indices from the original table should be added to the elevated table using a
different name. The indices of the elevated table will be the "added and renamed" indices from the
original table plus the natural indices. (The procedure to construct SNMP tables from more
complex programming language data structures is not described in this article.)
• Tables that allow row creation and deletion should have a column named "xxxType" or
"xxxStatus" which is an enumerated value. By convention, the first value should be called "other"
(or "valid") and the second value should be called "invalid". (This is not always followed.) A row
is removed by a single set operation that specifies the value of the "xxxType" (or "xxxStatus")
variable as "invalid". A new row is added by using a single set operation. The variables in the set
operation are the required columns in the new row using the new instance. The DESCRIPTION
clause should describe the complete semantics of create and delete operations. More complex
tables may have additional values for the "xxxType" (or "xxxStatus") column so that rows can be
"constructed" using several set operations instead of just one. The RMON MIB[11] has
"xxxStatus" objects in tables that may have four values, instead of two. One value called
"underCreation" is used to indicate that the row exists, but the values of columns in the row may
not be consistent and associated resources may not be allocated. This article does not cover these
kinds of complex MIB tables. • The DESCRIPTION clause should be included with each leaf
object to describe its function and use.
• All names defined within a MIB module must be unique. Object names must start with a
lowercase letter. The names of objects that are counters should end in the letter "s".
• Objects that are printable strings should be defined as DisplayString. Objects that contain pure
binary information should be defined as octet strings.
• Objects that are media- or physical-level addresses should be defined as PhysAddress instead of
as an octet string.
• Objects should be designed so that an SNMP operation can be performed twice in a row without
disastrous results. SNMP runs on top of an unreliable transport service that may cause SNMP
requests to be duplicated or responses to be dropped. Applications may retry when no response is
received.
• The number of columns in a table should be kept small enough so that the entire row can be
retrieved with one SNMP request operation.
The following guidelines, which are summarized from the the Concise MIB RFC[6], are general rules for
deciding how many and which objects to manage:
• Too much information creates as much a problem as not enough information. Begin slowly and try
to specify only the key objects to be managed.
• Start with the objects that are essential for fault or configuration management.
• Objects must have demonstrated current use and should not be defined as placeholders for future
implementation.
• Redundancy should be avoided by not defining variables that can be derived from others (for
example, through arithmetic means.)
• Case diagrams[10] should be used to show the relationships between counters. (These proved
invaluable in determining the counters for MIB-I[4].)
• Objects should be chosen that are general in nature and can be used for other products.
• Critical sections of code should not be heavily instrumented.
• After a device has network management added, it must still be able to function effectively in its
primary role.
Traps are used to signal a manager that an extraordinary event has occurred at an agent. Unfortunately, the
syntax for traps is one of the weaker points of the SNMP protocol. Instead of using OIDs to identify traps, a
flat-numbering scheme was chosen for the six events associated with the MIB-I definitions, and an
extension mechanism was specified. This mechanism is triggered when the generic-trap field has the value
"enterpriseSpecific(6)". When this occurs, the values of the specific-trap and enterprise fields are
used together to determine the event.
Syntax:
<trapItem> = <trapName> "TRAP-TYPE"
"ENTERPRISE" <oidName>
[ "VARIABLES" "{" <varName> ["," <varName>]... "}" ]
[ "DESCRIPTION" <description> ]
[ "REFERENCE" <reference> ]
"::=" <value>
Where:
<trapName> is the name of the trap being defined;
<oidName> is either "snmp" or the value to return in the "enterprise"
field;
<value> is the value of the trap returned in either the "generic-trap"
or "specific-trap" fields; and Values for <varName>, <description>, and
<reference> are defined later.
The required ENTERPRISE clause determines the value to be returned in the enterprise field of the
returned trap. If the value specified in the macro is "snmp", then the value returned is the value of the
sysObjectID object at the agent generating the trap (and the trap will be an SNMP-generic trap). If the
value in the macro is not "snmp", then the value from the ENTERPRISE clause is the one that must be
returned (and the trap must be an enterprise-specific trap). The optional VARIABLES clause names the
interesting SNMP-managed objects that must be returned in the trap. The DESCRIPTION clause must
indicate the instance for each object to be returned. The agent implementer may choose to return additional
variables. Care should be taken to choose variables so that the trap can be returned in no more than 484
octets. Network management systems must be able to interpret any returned variables, not just those
specified in the trap definition.
The TRAP-TYPE macro value and the enterprise value together determine the values to be returned in the
generic-trap and specific-trap fields in a trap. As previously specified, if the value for the ENTERPRISE
clause is "snmp", then the trap being defined is a generic trap. In this case, the value for the trap-type macro
is one of the values (i.e., 0 thru 5) for generic traps. This number is returned in the generic-trap field, and
the specific-trap field is returned as zero. (Note: no new generic traps may be defined.) For specific traps,
the trap-type macro specifies the value of the specific-trap field. The generic-trap field must be returned
with value "enterpriseSpecific(6)" by the agent.
Examples:
coldStart TRAP-TYPE
ENTERPRISE snmp
::= 0
fooTrap TRAP-TYPE
ENTERPRISE foo
::= 45
Where
coldStart is a generic trap;
and fooTrap is an enterprise-specific trap.
Drawbacks of SNMPv1 trap PDU format: SNMP traps are not confirmed or uniquely identified (i.e., no
request-id field). Therefore, it is not possible for an agent to determine if a manager has received a trap nor
for a manager to determine if a trap is a duplicate.
Lexicographic ordering among names: ASN.1 defines a lexicographic ordering among names that
provides a fundamental part of the SNMP functionality. The lexical ordering allows clients to ask a server
for the set of currently available variables and to search a table without knowing its size or to specify an
approximate oid and ask for the next oid's value (useful for iteratively loop through all the table elements
without knowing the actual size of the table using a getnext command). Lexicographic ordering among
names of MIB variables is defined using the numeric representation of ASN.1 object identifiers. Two
names are lexically equal if they have identical representations. A name is lexically less than another if it is
a prefix (ie it has a numerically lower value in the first label that differs). To state this mathematically;
Let n1,n2,n3.... denote the numeric labels in name n and m1,m2,m3..... denote the numeric labels in name
m. Find the first label i for which ni differs from mi.
If ni < mi, then n is lexically less than m.
Prefix Removal: SNMP software improves performance by storing and manipulating suffixes of MIB
names. It adds the common prefix before sending a name in a message to another machine, and removes
the common prefix (after verifying it) when a message arrives.
A client can issue three basic commands to the server: Two of them (get and set requests) require straight
forward mapping. Before the server can perform these requests the server must map the numerically
encoded ASN.1 names found in the incoming request into the appropriate internal variables that store
values for those names. In the third type of request, viz a get-next request, the client does not specify the
name of an item to retrieve. Instead it specifies a name and asks the server to respond with the name and
value of the variable that occurs next in the lexical sequence. The server finds the next variable with a name
lexically greater than the specified name, and performs a get-request operation on that variable to obtain the
value. Get-next request is useful for accessing values in a table of unknown size. A client can continually
issue a get-next request and have the server mobe through the values in the table automatically. Each
request specifies the name of the variable returned in the previous reponse, allowing the server to specify
the name of the next item in its response. This process of stepping through enteries one at a time is called
walking a table or MIB walk or SNMP walk.
Names for tables: To facilitate the use of get-next request commands, some MIB names correspond to
entire tables instead of individual items. These names dont have individual values and clients cannot use
them directly in get-request commands! However, clients can specify the name of a table in a get-next
request command to retrieve the first item in the table without knowing the name of the previous MIB
variable.
Servers only return values of simple variables (or scalars) in response to a get-next request command,
they must skip empty tables when the request arrives. A get-next request always skips to the next
simple variable in the lexicographical ordering. More important, the current contents of variables available
at a given server determine the set of names that the server skips. In particular, a get-next request command
always skips an empty table. As a consequence, the server cannot simply use a lexically ordered list of MIB
variables to determine which variable satisfies a get-next request command. Instead, it must contain code
that examines items in the lexical ordering, skips any that are empty, and finds the first simple variable in
the next non-empty item.
Threading of the Name Hierarchy: If MIB variables are arranged in a hierarchy according to their
ASN.1 names, they define a tree. The definition of lexically next can be thought of as a set of threads in
the tree.
The first phase will be more of a proof-of-concept type of prototyping implementation. You may even
choose to depict only some MOs as a part of your initial MIB. Anyway in the second phase you will need
to implement the total thing after you have successfully implemented the distinct types of MOs you have
identified. It have even be the case that by the time you are in the second phase you may get some
enhanced requirements which demand implementing some more MOs than what you started with. In the
first part, it is better if you choose to have a simpler MIB so that the actual work of extending the agent and
implementing the test client and at the end to test the communication happening derieves the deserved
focus.
PhaseII:
1. Incorporate any changes to MIB and implement it for agent and client. This is necessary in case when the
MIB has undergone any change at all.
2. Port the agent implementation on RTOS running with your hardware (in case you wanted actual agent
and not a proxy).
The second phase will majorily concentrate on refining the first phase design first and then move the
perfected code to the RTOS.
A simple client in Java using Westhawk SNMP stack.
package com.rwatsh.snmpjapp;
import uk.co.westhawk.snmp.stack.*;
import uk.co.westhawk.snmp.pdu.*;
import java.awt.Graphics;
import java.awt.Event;
import java.util.*;
import java.net.*;
try
{
context = new SnmpContextv2c(host, port, socketType);
context.setCommunity(community);
/**
* Implementing the Observer interface. Receiving the response from
* the Pdu.
* Note, what is different from SNMPv1 is that it tests for a (new)
* <code>'end of MIB view'</code> element.
*
* @param obs the OneGetNextPdu variable
* @param ov the varbind
*
* @see uk.co.westhawk.snmp.pdu.OneGetNextPdu
* @see uk.co.westhawk.snmp.stack.varbind
* @see SnmpConstants#SNMP_VAR_ENDOFMIBVIEW
*/
public void update(Observable obs, Object ov)
{
boolean isFinished = false;
if (pdu.getErrorStatus() == AsnObject.SNMP_ERR_NOERROR)
{
varbind var = (varbind) ov;
AsnObject obj = var.getValue();
if (obj.getRespType() != AsnObject.SNMP_VAR_ENDOFMIBVIEW)
{
System.out.println("Response: " + var.toString());
}
// members.
final static String SYSNAME = "1.3.6.1.2.1.1.4";
SNMP Jargon
CMIP over TCP/IP (CMOT)
Common Management Information Protocol (CMIP)
References
1. SNMP Overview from Cisco: http://www.cisco.com/univercd/cc/td/doc/cisintwk/ito_doc/snmp.htm
2. ASN.1 Complete: A very elaborate book by John Larmouth. Its freely downloadable -- search on
google.com for a site.
3. Some useful SNMP links:
4. Internetworking with TCP/IP by Douglas E. Comer & David L. Stevens (Prentice Hall Publication)
ISBN-81-203-0927-8. This has been the source of my initial learning of how the SNMP software is
structured. It has detailed explanation of the theory and also supported by code blocks (including data
structures and functions). Unfortunately the book only covers the SNMP v1. But then, after you have
understood the concepts behind the implementation of one version you can very well appreciate the
possible additions which can be made to the code to implement an enhanced version.
5. Understanding SNMP MIBs by David Perkins. An ultimate reference book for those who plan to write
an enterprise mib of their own. Also a very good treatment to SNMP in general. A must buy for serious
SNMP junkies! An abriged version is available for free on the net. Search on google for a site. A must read
article!
~ The End ~