SNMP MIB Implementation
This wiki describe how to generate a MIB (Management Information Base) for SNMP agent.
Contents
Steps
- Create a ASN.1 MIB script foo.mib (an ASCII text file) for the tree structure.
- Convert foo.mib to binary file using mib2bin
- Build snmp's PDU use BER (Base encoding rules) encoder and decoder library to process data that's transfer between NMS and agents.
- Build snmp API use uIP-stack to communicate between NMS and Agents (open two ports: The manager speak to agents on one port, the agent responds manager on the other port).
- Build binary MIB file reader library.
- Build functions service oid tree.
- Merge MIB ANS.1 file to NMS.
Create ASN.1 MIB Script
- Build MIB file's written in ANS.1 notation.
- Tutorial: Understanding SNMP Stack to create ASN.1 MIB Script.
- Tools to create ASN.1 MIB Script
Abstract Syntax Notation
- Each MIB variable contains several attributes, such as data type, access type and object identifier.
- Abstract Syntax Notation version 1 (ASN.1) is a language to define these attributes in SNMP.
Convert MIB to Binary File
- mib2bin tool is modified from net-snmp to convert ASN.1 format file to three files, because the microchip mib2bib converter only supports upto 255 OIDs.
MIB compiler tools: mib2bin foo.mib (ANS.1 format) -----------------------------------> foo.bin + foo.h + foo_data.h
- Syntax to use mib2bin tool:
mib2bin <MIBfile>...
- where MIBfile file is ASN.1 format file. MIBfile = <name>.<type>
- <name>.bin is the binary file storing information of OID tree. This file can be placed on an SD media card to be read by the FAT16 file system.
- <name>_data.h is C header file storing information of OID tree. This file is generated by converting mchip.bin file to the C header file. It's only used when a system don't have system file and place on program memory.
- <name>.h is C header file storing ID that's reference to function service of OID.
- Note:
- Subfolder mibs containing the basics MIB files (e.g.: RFC1155-SMI, RFC1213-MIB, RFC-1215, SNMPv2-MIB ... for us MIB file), must be present under the directory of execution.
- If the three files exist, mib2bin tool will overwrite the files.
Binary File Format
- The binary file is an image of MIB file. It is generated by mib2bin tool. Agents will read binary file to respond NMS request.
- In the binary file, A parent is stored first, followed by its last-child to first-child. Next, the structure of next this parent is stored. This structure is repeated until the entire tree is stored.
- A parent or child is a record. Single record of binary file have format:
<oid>, <nodeInfo>, [id], [siblingOffset]/[distantSiblingOffset], [dataType], [dataLen], [data], [{<IndexNumber>},{<IndexCount>, <IndexNodeInfo>, <IndexDataType>} ...]
- where:
- fields indicated by angle brackets (< >) are always present
- fields in square brackets ([ ]) are optional depending on characteristics of the current node.
- fields in braces ({ }) are optional but always occur together.
<oid> field
- The microchip format only supports OIDs upto 255. The following is an workaround to store OID greater than 255.
- Format of OID:
oid_1 <0x10> oid_2 <0x10> ....
- if (oid_i < 0xFF): oid_i = BYTE (oid_i)
- else: oid_i = <0xFF> + BYTE (length) + BYTE (oid_i.B0) + BYTE (oid_i.B1) + ...
- where
- BYTE (x) mean the byte representation of x.
- <0x10> is the OID separator.
- <0xFF> is used to indicate that the OID is greater than 254.
- length is the number of bytes of oid_i that follows.
- oid_i.Bj is j-th byte of oid_i in hexadecimal representation, j = 0 corresponds to the Least Significant Byte (LSB), i.e. little-endian format.
- Example:
The OID for a node is 4.1.17095. After compiling to binary, the OID is represented as: The OID: 4 . 1 . 17095 . The result: 0x04 0x10 0x10 0x10 0xFF 0x02 0xC7 0x42 0x10 where: oid_1 = 4 => BYTE (oid_1) = 0x04 oid_2 = 2 => BYTE (oid_2) = 0x01 oid_3 = 17095 = 0x42C7 => 0xFF BYTE (length) = 0x02 BYTE (oid_3.B0) BYTE (oid_3.B1) = 0xC7 0x42 (In little-endian format) Note: When a node have no sibling and only has one child, the node's OID will be merged with its child's OID (reduce data's stored). For example, in case of private (4) -> enterprises (1) -> microchip (17095), where private has no sibling and only has one child, and enterprises also has no sibling and only has one child, they can combined to a record has oid field is 4.1.17095.
<nodeInfo> field
- information of node
bit when (set = 1) 0 Node is a parent (0: node is a leaf) 1 Node is sequence 2 Node is readable 3 Node is writable 4 Node is able to create 5 Node has default data 6 (if node is sequence, this is mean implied index node) 7 always set 1
[id] field
- If this record is leaf, id that's reference to function services the record.
[distantSiblingOffset] field
- If this record is a node [distantSiblingOffset] is enabled. Point to next node sibling.
- In little-endian format.
- The last node's distant offset is set to 0x00000000.
[siblingOffset] field
- If this record is a leaf [siblingOffset] is enabled. Point to next leaf sibling.
siblingOffset and distantSiblingOffset in this format is same function (point to next node sibling). They're only differences: siblingOffset use with leaf node. distantSiblingOffset use with node. so it's same value.
[dataType], [dataLen], [data] fields
- If this record is a leaf and has default data
- [dataType] is type of leaf's data.
- [dataLen] is length of data.
- [data] is data on string.
- The tool supports the following base data types defined in SNMPv1:
- INTEGER: The integer data type is a signed integer in the range of -2,147,483,648 to 2,147,483,647.
- OCTETSTRING: Octet strings are ordered sequences of 0 to 65,535 octets.
- Gauge: Nonnegative integers that can increase or decrease but retain the maximum value reached. The limit of 2^32 -1.
- TimeTicks: A hundredth of a second since some event. The limit of 2^32 -1.
- Counter: Nonnegative integers that increase until they reach a maximum value (2^32 -1); then, the integers return to zero.
- DisplayString: a special case of the octet string type where all the bytes are printable ASCII characters, include formatting characters such as CR and LF, and the C programming language string terminator character zero.
- IpAddress: A four byte octet string in network order.
- NetworkAddress: Used to indicate an address choice from one of the possible protocol families. Currently, only IP addresses are supported.
- Opaque: An arbitrary encoding that is used to pass arbitrary information strings that do not conform to the strict data typing used by the mib.
- SEQUENCE: An ordered list of objects, somewhat like a struct in the C language. Type of objects in sequence is same type of node.
[{<IndexNumber>}] and [{<IndexCount>, <IndexNodeInfo>, <IndexDataType>}] fields
- If this record is sequence (an order list of objects),
- <IndexNumber> is the number of INDEXes in sequence.
- <IndexCount>: is OID of index node in table
- <IndexNodeInfo>: is info of index node
- <IndexDataType>: is data type of index node
- See example of accessing data in a table
- Example:
- trap node is a sequence to inform the NMS of a significant event (an extraordinary event has occurred at an agent) asynchronously. This sequence has two INDEXes, so we have:
<IndexNumber> = 0x02 with the 1st INDEX: <IndexCount> = 0x04 <IndexNodeInfo> = 0xCC <IndexDataType> = 0x02 with the 2nd INDEX: <IndexCount> = 0x01 <IndexNodeInfo> = 0x80 <IndexDataType> = 0x03 In this example, trap is a table which has 4 columns: trapReceiverNumber (1), trapEnabled (2), trapReceiverIPAddress (3), trapCommunity(4). trapReceiverNumber (1), trapEnabled (2), trapReceiverIPAddress (3), trapCommunity(4). trapReceiverNumber (1), trapEnabled (2), trapReceiverIPAddress (3), trapCommunity(4). Each significant event will be a row defined in the trap table. This example has two INDEXes: the 1st INDEX node is trapCommunity (4) and the 2nd INDEX node trapReceiverNumber (1) Each INDEX is a node, so it has OID, info, data type. The 1st INDEX node is trapCommunity, which has OID = 4, info is 0xCC and data type is INTEGER (0x02). so IndexCount = 0x04 IndexNodeInfo = 0xCC IndexDataType = 0x02 The 2nd INDEX node is trapReceiverNumber, which has OID = 1, info is 0x80 and data type is DisplayString (0x03). so IndexCount = 0x01 IndexNodeInfo = 0x80 IndexDataType = 0x03
Example
OID Tree
- An example OID tree is given below:
Binary File
- The corresponding binary file is mchip.bin and it has data describe in table below:
- oid is <oid> fields.
- info is <nodeInfo> fields.
- dist is [distantSiblingOffset]/[siblingOffset] fields.
- id is [id] fields.
- defval is data fields, include [dataType], [dataLen], [data] fields.
- index is index fields of sequence, include [{index_number} , {<IndexCount>, <IndexNodeInfo>, <indexDataType>, ...}].
- The detail description of mchip.bin is illustrated in the diagram below:
- The black arrow lines represent the OID tree structure.
- The red and green lines represent pointers to data.
- The dist field points to next sibling record. After parent record is it's children.