net snmp

1.Architecture

1.1 Agent Architecture

Upon starting, the agent goes through the following steps (in SnmpDaemonMain()):

  • reads command line options
  • decides whether it’s a master or subagent
  • calls init_agent()
    • initializes the mib-module registration tree
    • registers its own configuration file tokens and callbacks
    • initializes the Agent Helpers
  • initializes all the compiled-in mib modules
  • initializes the base libnetsnmp library
  • opens all the required ports to listen on
  • forks
  • saves persistent data (it’s likely at least something has changed already)
  • sends a coldStart trap
  • invokes receive() to perform the main packet handling

Reference: Agent_Architecture

1.2 snmpget snmpset snmpwalk snmptrap

Reference: mib2c_General_Overview

* snmptranslate: learning about the MIB tree.
* snmpget:       retrieving data from a host.
* snmpgetnext:   retrieving unknown indexed data.
* snmpwalk:      retrieving lots of data at once!
* snmptable:     displaying a table.
* snmpset:       peforming write operations.
* snmpbulkget:   communicates with a network entity using SNMP GETBULK request
* snmpbulkwalk:  retrieve a sub-tree of management values using SNMP GETBULK requests.
* snmptrap:      sending traps messages, and acting upon them.
* snmptrapd:     receive and logs SNMP TRAP and INFORM messages.  

for more, use 'man' command to see usage.

example:

#### snmpwalk
[dennis@localhost ~]$ snmpwalk -v2c -c public 192.168.110.98 .1.3.6.1.4.1.50369
...
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.3.1 = INTEGER: 856398
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.4.1 = INTEGER: 432164
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.5.1 = INTEGER: 424234
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.6.1 = INTEGER: 1
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.7.1 = INTEGER: 3
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.8.1 = STRING: "0:1 0:2 0:3 "
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.9.1 = INTEGER: 3
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.10.1 = INTEGER: 0
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.11.1 = INTEGER: 4
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.12.1 = INTEGER: 0
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.13.1 = INTEGER: 5

#### snmpget
[dennis@localhost ~]$ snmpget -v2c -c public 192.168.110.98 .1.3.6.1.4.1.50369.1.1.2.5.1.3.1
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.3.1 = INTEGER: 856398

[dennis@localhost ~]$ snmpget -v2c -c public 192.168.110.98 .1.3.6.1.4.1.50369.1.1.2.5.1.8.1
SNMPv2-SMI::enterprises.50369.1.1.2.5.1.8.1 = STRING: "0:1 0:2 0:3 "

#### snmpset
[dennis@localhost ~]$ snmpset -v2c -c private 192.168.110.98 .1.3.6.1.4.1.50369.1.1.1.3.1.0 i 2
SNMPv2-SMI::enterprises.50369.1.1.1.3.1.0 = INTEGER: 2

[dennis@localhost ~]$ snmpset -v2c -c private 192.168.110.98 .1.3.6.1.4.1.50369.1.1.1.3.2.0 s "2013-08-16 15:32:40"
SNMPv2-SMI::enterprises.50369.1.1.1.3.2.0 = STRING: "2013-08-16 15:32:40"

#### snmptrap
# use snmptrapd to receive trap message.
# 1.first create file "touch /usr/local/share/snmp/snmptrapd.conf" 
# 2.then add "authcommunity execute,log,net public" to the file to access 
#   receive trap message.
# (use command 'snmpconf' to create and config is another choise)
# use root to start snmptrapd 
[root@localhost ~]# snmptrapd -f -Le -F "%02.2h:%02.2j TRAP%w.%q from %b\n %v\n"
NET-SNMP version 5.7.2
14:30 TRAP0.0 from UDP: [192.168.110.39]:52222->[192.168.50.63]:162
 DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (1) 0:00:00.01    SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-SMI::enterprises.50369.1.3.0.1    SNMPv2-SMI::enterprises.50369.1.1.2 = INTEGER: 1
15:38 TRAP0.0 from UDP: [172.16.110.39]:35505->[172.16.50.63]:162
 SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-SMI::enterprises.50369    SNMPv2-SMI::enterprises.50369.1.1.2 = STRING: "string value test"    

root:~# snmptrap -v 2c -c public 192.168.50.63 1 .1.3.6.1.4.1.50369.1.3.0.1 .1.3.6.1.4.1.50369.1.1.2 i 1
root:~# snmptrap -v 2c -c public 192.168.50.63 "abc" .1.3.6.1.4.1.50369 .1.3.6.1.4.1.50369.1.1.2 s "string value test"

2. Install

2.1 Yum

install snmp
su -c 'yum install net-snmp'

install mib2c
su -c 'yum install net-snmp-perl'

install utils tools:snmpwalk, snmpget,…
su -c 'yum install net-snmp-utils'

3. Steps

3.1 net-snmp中如何加自定义的mib库

  • Write your self-defined mibs
  • Copy to /usr/local/share/snmp/mibs
  • 用snmptranslate -Ts -m ALL 就可以看到所以OID的输出了,当然也包括你新加的。
    如果写的mib文件不正确,应该不能输出,你可以找第三方工具来验证你的文件格式是否正确。
  • 编写相关的函数。
    • 为你的mib新建一个c文件,可以使用mib2c这样的工具来完成。
    • 如果该OID是只读的,那就在该文件里编写一个只读的函数(mib2c应该会生成的);如果可写,也应该有一个写的函数(相样是生成的)

3.2 Self-defined Mib

I don’t find any good tools for generate mibs, what I do is hacking by hand; if
you know some good tool, don’t forget to tell me.

--============================================================
-- Dennis Sample Management Information Base (MIB)
--============================================================

DENNIS-MIB DEFINITIONS ::= BEGIN

IMPORTS
    DisplayString,
    PhysAddress,
    MacAddress,
    DateAndTime,
    RowStatus,
    TEXTUAL-CONVENTION
        FROM SNMPv2-TC
    MODULE-IDENTITY,
    OBJECT-TYPE,
    NOTIFICATION-TYPE,
    Integer32,
    IpAddress,
    TimeTicks,
    Unsigned32
        FROM SNMPv2-SMI;

--============================================================
-- MODULE IDENTITY : dennis
--============================================================

dennis MODULE-IDENTITY
    LAST-UPDATED "201308160000Z"
    ORGANIZATION "MIB"
    CONTACT-INFO
        "Shenzhen, China, Earth village, Solar system
         http://matrix207.github.com
         E-mail: dennis.cpp@gmail.com"
    DESCRIPTION
        "Sample MIB Definition  for
        iso(1).org(3).dod(6).internet(1).private(4).enterprises(1).dennis(9913)"
    ::= { 1  3  6  1  4  1  9913 }


--============================================================
-- Definition of the Sample MIB Common Objects
--============================================================

dennisSampleMib OBJECT IDENTIFIER       ::= { dennis 1 }

--============================================================
-- Definition of the Information Group
--============================================================


dennisSystemInformation OBJECT IDENTIFIER  ::= { dennisSampleMib 1 }

--============================================================
-- Definition of the Information Group (Object type: scalar)
--============================================================

dennisSysInfoEntry OBJECT IDENTIFIER  ::= { dennisSystemInformation 1 }

dennisSystemOSVersion OBJECT-TYPE
    SYNTAX  DisplayString (SIZE (64))
    MAX-ACCESS read-only
    STATUS  current
    DESCRIPTION
        "This object show the operator system version."
    ::= { dennisSysInfoEntry 1 }


dennisSystemOSBit OBJECT-TYPE
    SYNTAX  Integer32
    MAX-ACCESS read-only
    STATUS  current
    DESCRIPTION
        "This object show the operator system bit"
    ::= { dennisSysInfoEntry 2 }


dennisSystemCPU OBJECT-TYPE
    SYNTAX  Integer32
    MAX-ACCESS read-only
    STATUS  current
    DESCRIPTION
        "The speed of processor, unit: MHZ"
    ::= { dennisSysInfoEntry 3 }


dennisSystemMemory OBJECT-TYPE
    SYNTAX  Integer32
    MAX-ACCESS read-only
    STATUS  current
    DESCRIPTION
        "The total number of memory, unit: MB"
    ::= { dennisSysInfoEntry 4 }


dennisSystemDiskSizy OBJECT-TYPE
    SYNTAX     Integer32
    MAX-ACCESS read-only
    STATUS     current
    DESCRIPTION
        "The total size of disks"
    ::= { dennisSysInfoEntry 5 }


--============================================================
-- Definition of the Directory Group Mount on Root (Object type: table)
--============================================================

dennisSubDirOfRootInformationTable    OBJECT-TYPE
    SYNTAX    SEQUENCE OF DennisSubDirOfRootInformationEntry
    MAX-ACCESS    not-accessible
    STATUS    current
    DESCRIPTION
        "A list of expander chassis information."
    ::= { dennisSampleMib 2 }


dennisSubDirOfRootInformationEntry    OBJECT-TYPE
    SYNTAX    DennisSubDirOfRootInformationEntry
    MAX-ACCESS    not-accessible
    STATUS    current
    DESCRIPTION
        "A expander chassis information entry"
    INDEX    { dennisSubDirOfRootIndex }
    ::= { dennisSubDirOfRootInformationTable 1 }


DennisSubDirOfRootInformationEntry    ::=
    SEQUENCE {
       dennisSubDirOfRootIndex Integer32,
       dennisSubDirOfRootName  DisplayString,
       dennisSubDirOfRootSize  Integer32,           
       dennisSubDirOfRootDate  DisplayString }

dennisSubDirOfRootIndex OBJECT-TYPE
    SYNTAX    Integer32
    MAX-ACCESS    read-only
    STATUS    current
    DESCRIPTION
        "The index."
    ::= { dennisSubDirOfRootInformationEntry 1 }

dennisSubDirOfRootName OBJECT-TYPE
    SYNTAX    DisplayString (SIZE (64)) 
    MAX-ACCESS    read-only
    STATUS    current
    DESCRIPTION
        "The type of expander chassis."
    ::= { dennisSubDirOfRootInformationEntry 2 }

dennisSubDirOfRootSize OBJECT-TYPE
    SYNTAX    Integer32
    MAX-ACCESS    read-only
    STATUS    current
    DESCRIPTION
        "The expander chassis manufacturer's id."
    ::= { dennisSubDirOfRootInformationEntry 3 }

dennisSubDirOfRootDate OBJECT-TYPE
    SYNTAX    DisplayString
    MAX-ACCESS    read-only
    STATUS    current
    DESCRIPTION
        "The total number of physical slots for physical
        disk on the chassis."
    ::= { dennisSubDirOfRootInformationEntry 4 }


--============================================================
-- Definition of access object (Object type: scalar)
--============================================================
dennisAccessObject OBJECT IDENTIFIER  ::= { dennisSampleMib 3 }

dennisShutdownType OBJECT-TYPE
    SYNTAX  Integer32
    MAX-ACCESS read-write
    STATUS  current
    DESCRIPTION
        "Use for shudown operator system, 1:shutdown 2:reboot"
        ::= { dennisAccessObject 1 }


--============================================================
-- End Definition
--============================================================
END

3.3 Check mib

[root@localhost mib]# snmptranslate -Tp -m DENNIS-MIB
+--iso(1)
   |
   +--anonymous#0(3)
      |
      +--anonymous#1(6)
         |
         +--anonymous#2(1)
            |
            +--anonymous#3(4)
               |
               +--anonymous#4(1)
                  |
                  +--dennis(9913)
                     |
                     +--dennisSampleMib(1)
                        |
                        +--dennisSystemInformation(1)
                        |  |
                        |  +--dennisSysInfoEntry(1)
                        |     |
                        |     +-- -R-- String    dennisSystemOSVersion(1)
                        |     |        Textual Convention: DisplayString
                        |     |        Size: 64
                        |     +-- -R-- Integer32 dennisSystemOSBit(2)
                        |     +-- -R-- Integer32 dennisSystemCPU(3)
                        |     +-- -R-- Integer32 dennisSystemMemory(4)
                        |     +-- -R-- Integer32 dennisSystemDiskSizy(5)
                        |
                        +--dennisSubDirOfRootInformationTable(2)
                        |  |
                        |  +--dennisSubDirOfRootInformationEntry(1)
                        |     |  Index: dennisSubDirOfRootIndex
                        |     |
                        |     +-- -R-- Integer32 dennisSubDirOfRootIndex(1)
                        |     +-- -R-- String    dennisSubDirOfRootName(2)
                        |     |        Textual Convention: DisplayString
                        |     |        Size: 64
                        |     +-- -R-- Integer32 dennisSubDirOfRootSize(3)
                        |     +-- -R-- String    dennisSubDirOfRootDate(4)
                        |              Textual Convention: DisplayString
                        |              Size: 0..255
                        |
                        +--dennisAccessObject(3)
                           |
                           +-- -RW- Integer32 dennisShutdownType(1)

4. Use mib2c

4.1 mib object

scalar: int, string, time and so on.
table : table has row and column, like table in database.

4.2 use mib2c to create source file

append string “DENNIS-MIB” to config file: snmpd.conf
su -c 'vim /etc/snmp/snmpd.conf'

copy mib file to mibs directory(depend on which directory mib2c installed)
su -c 'cp DENNIS-MIB.txt /usr/local/share/snmp/mibs/'

generate c source file by mib2c
mib2c -c mib2c.scalar.conf DENNIS-MIB::dennis for scalar object
mib2c -c mib2c.old-api.conf DENNIS-MIB::dennis for scalar object
mib2c -c mib2c.iterate.conf DENNIS-MIB::dennis for table object (choise 2)
mib2c -c mib2c.notify.conf DENNIS-MIB::dennis for trapping message
if failed to translate, check the mibs directory again, or look the output message.

more configure files, look as below:

[dennis@localhost net-snmp-5.4.2]$ ls /usr/local/share/snmp/*.conf
/usr/local/share/snmp/mib2c.access_functions.conf    
/usr/local/share/snmp/mib2c.int_watch.conf
/usr/local/share/snmp/mib2c.array-user.conf          
/usr/local/share/snmp/mib2c.iterate_access.conf
/usr/local/share/snmp/mib2c.check_values.conf        
/usr/local/share/snmp/mib2c.iterate.conf
/usr/local/share/snmp/mib2c.check_values_local.conf  
/usr/local/share/snmp/mib2c.mfd.conf
/usr/local/share/snmp/mib2c.column_defines.conf      
/usr/local/share/snmp/mib2c.notify.conf
/usr/local/share/snmp/mib2c.column_enums.conf        
/usr/local/share/snmp/mib2c.old-api.conf
/usr/local/share/snmp/mib2c.column_storage.conf      
/usr/local/share/snmp/mib2c.perl.conf
/usr/local/share/snmp/mib2c.conf                     
/usr/local/share/snmp/mib2c.raw-table.conf
/usr/local/share/snmp/mib2c.container.conf           
/usr/local/share/snmp/mib2c.scalar.conf
/usr/local/share/snmp/mib2c.create-dataset.conf      
/usr/local/share/snmp/mib2c.table_data.conf
/usr/local/share/snmp/mib2c.genhtml.conf             
/usr/local/share/snmp/snmptrapd.conf

5. Add self-defined mib library

5.1 steps:

使用net-snmp扩展私有MIB的大致方法
参考: net-snmp tutorial

step 1. 首先需要使用net-snmp的相关API编写MIB相关C代码,

1. MFD/mib2c:这是一种通过net-snmp提供的mib2c程序自动生成相关代码的方式
2. A simple scalar attached to a variable:适合于简单变量类型的object
3. A simple scalar with the value returned from code:适用于任何变量类型的object

step 2. 然后将刚写的MIB C code编译进net-snmp,有几种方法:

1. compile it into master agent:
  1)将刚编写的码加入net-snmp的src目录,
  2)通过configure的option指示make编译该mib,
     如./configure --with-mib-modules="myobject" 
  3)make
  4)make install
  这样,你的MIB就已经被内置如snmp服务程序中了,MIB的生效也就理所当然

2. compile your code into a “subagent”:
  这种方式可以将subagent通过agentx协议与master agent通信,
  参考: http://net-snmp.sourceforge.net/tutorial/tutorial-5/toolkit/demon/index.html
  这种情况subagent最终是一个独立的application,包含两种生成方式,
  1).是通过net-snmp-config工具生成;
  2).是自己编写程序控制调用;
  后者更为灵活,subagent功能可以被集成在其它application中。

3. compile your code into pluggable shared object and tell the snmpd agent to load it
  这种方式最后生成一个.so的共享库,用户启动snmpd服务时可以通过指定参数的方式
  加载该共享库以扩展MIB,
  参考: http://net-snmp.sourceforge.net/tutorial/tutorial-5/toolkit/dlmod/index.html 

5.2 compile net-snmp by shell script

cd /home/dennis/net-snmp-5.4.2/
cp -f /home/dennis/dennis.{h,c} ./agent/mibgroup
./configure --prefix=/usr --with-mib-modules="dennis"
make clean
make
make install

5.3 update mib

copy "net-snmp-5.4.2/agent/.libs/libnetsnmpmibs.so" to "/usr/lib/",  
64bit system is to "/usr/lib64/"

5.4 check the so had have the interfaces which you implement

[root@ ~]# which snmpd
/usr/sbin/snmpd
[root@ ~]# ldd /usr/sbin/snmpd | grep libnetsnmpmib
    libnetsnmpmibs.so.15 => /usr/lib64/libnetsnmpmibs.so.15 (0x0000003655600000)
[root@ ~]# nm /usr/lib64/libnetsnmpmibs.so.15 | grep "YOUR_INTERFACE_KEY"

5.5 check config file

check the file /etc/snmp/snmpd.conf, append `rwcommunity private` to it to 
make access authority for `snmpset`.

5.6 restart snmp

/usr/sbin/snmpd -c /etc/snmp/snmpd.conf -Le

6. Improve speed

When snmp agent receive lots of request, and if do some I/O operation of each
request, that will show a low performance.
One not-bad solution is use a thread do the I/O job, and store the information
to memory (using global variable, array, structure …), then fill info and
return to client when get the request.

6.1 add thread function to mib file

Add include #include <pthread.h> to the mib file
Write thread function like this: void *update_all_info (void *parm);

6.2 modify Makefile

Add link library(-lpthread) to agent/Makefile (line:199):
LOCAL_LIBS = -L../snmplib/.libs -L../snmplib -L./.libs -L./helpers/.libs -L./helpers -lpthread

7. Reference