SNMP MIB Implementation

From OpenCircuits
Jump to navigation Jump to search

This wiki describe how to generate a MIB (Management Information Base) for SNMP agent.

Steps

  1. Create a ASN.1 MIB script foo.mib (an ASCII text file) for the tree structure.
  2. Convert foo.mib to binary file using mib2bin
  3. Build snmp's PDU use BER (Base encoding rules) encoder and decoder library to process data that's transfer between NMS and agents.
  4. 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).
  5. Build binary MIB file reader library.
  6. Build functions service oid tree.
  7. Merge MIB ANS.1 file to NMS.


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>} ...]

Since [siblingOffset] and [distantSiblingOffset] can be combined to 1 field, can I represent the above as:

 <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

  • Format of OID:
  oid1 char(16)
  oid2 char(16)
  ....
  • if oid_i < 255: oid_i = char (oid_i)
  • else oid_i = char(256) + char(length of oid_i base 256) + oid_i (base 256) + char(16)
  • where
    • char(x) that's mean get ascii of x.
    • char(16) is used to separate two oids.
    • char(255) is determined that oid geater than 254.
    • "length of oid_i" is length string of oid_i that's converted base 256.
  • The microchip format only supports OIDs upto 255. The above is an workaround to store OID greater than 255
  • 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  =>  char(oid_1) = 0x04
          oid_2 = 2  =>  char(oid_2) = 0x01

0x04 is not the ASCII of 4. The ASCII of 4 should be 0x34. I think you are saying the hexadecimal representation of 4. In such case, I think you can use HEX(.) instead of char(.)

  • In the example, i use the hexadecimal to easier to read. When i write to a file oid_1 = 4 will be fourth character in ASCII table (isn't the hexadecimal representation of 4). So i use char(oid_i), where: oid_i is number 4, isn't character '4'. Therefore, char(oid_i) = oid_i.
          oid_3 = 17095  => char(256) = 0xFF char(length of oid_3 base 256) = 0x02  char(oid_3) = 0xC742 (In little-endian format)
          char(16) = 0x10

So, "length of oid_3 base 255" means the number of bytes representing oid_3? How can you calculate 0x0A43 from 17095? I still don't quite understand the meaning of "oid_i (base 255)"

  • The meaning of "oid_i base 256" (i changed 255 to 256 follow little-endian format): the integer oid_i is wrote to a file in little-endian format and "length of oid_3 base 256" means number of bytes of the integer oid_i in little-endian format. So, 17095 = 0x42*0x100 + 0xC7.
   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).

How can it be combined? Any example?

  • Example:
  In mchip.txt file,the nodes have no sibling and only has one child: private (4), enterprises (1), microchip (17095). 
  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.
  • So, can siblingOffset and distantSiblingOffset be combined to 1 field?
  yes, they can be combined to 1 field.

[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>}]

  • If this record is sequence (an order list of objects), index_number is number of INDEXes in sequence.
    • [{<IndexCount>, <IndexNodeInfo>, <IndexDataType>}]
  • If this record is sequence
    • <IndexCount>: is oid of index node in table
    • <IndexNodeInfo>: is info of index node
    • <IndexDataType>: is data type of index node
  • Example:
  mchip.txt file has trap node is a sequence. This sequence has two INDEXes, so we have:
     IndexNumber = 0x2
     with the 1st INDEX:
         IndexCount = 0x04
         IndexNodeInfo = 0xCC
         IndexDataType = 0x02
     with the 2nd INDEX:
         IndexCount = 0x01
         IndexNodeInfo = 0x80
         IndexDataType = 0x03
  • What does this trap use for? What does the different values of IndexCount, IndexNodeInfo, and IndexDataType mean?:
  This is an example, How to use trap by agents to asynchronously inform the NMS of a significant event (an extraordinary event has occurred at an agent).
  In this example, trap is a table 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 in the table. So, we need index node to determine row. A table need at least one index. 
  This example has two INDEXes: the 1st INDEX node is istrapCommunity (4) and the 2nd INDEX node trapReceiverNumber (1).
  In the fact, need only trapReceiverNumber (1) INDEX to determine a row in example. (two INDEXes case is used to test complier).
  Each INDEX is a node, so it has OID, info, data type.
  In this binary file format:
     IndexCount is oid of index node.
     IndexNodeInfo is info of index node.
     IndexDataType is data type of index node.
  The 1st INDEX node istrapCommunity has OID = 4, info is 0xCC and data type is INTEGER (0x02). so
         IndexCount = 0x04
         IndexNodeInfo = 0xCC
         IndexDataType = 0x02
  The 2nd INDEX node trapReceiverNumber has OID = 1, info is 0x80 and data type is DisplayString (0x03). so
         IndexCount = 0x01
         IndexNodeInfo = 0x80
         IndexDataType = 0x03

Example

  • The example mchip.txt describe the OID tree given below:
Snmp mib oid tree example.jpg
  • The corresponding binary file is mchip.bin and it has data describe in table below:
Snmp mib binary example.jpg
  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 illuminated by structure diagram below:
Snmp mib binary detail example.jpg
  The hidden linear is oid tree structure.
  The red and green continue linear is pointer  of data.
  The dist field point to next sibling record. After parent record is it's children.