Sunday, March 7, 2010

Using Net-SNMP - 2

This is the second part of the N part series for understanding and working with Netsnmp.

See http://ashokachakra.blogspot.com/2010/03/using-net-snmp-1.html for details

We had configured and set up Netsnmp in the previous post. Now lets go ahead with writing our MIB

Ok, if you now ask me......whats a MIB....then you are in the wrong place. I assume that you already know what SNMP is, and what MIBs are and what an agent and a Manager does. You can refer to Stallings for more gyan....or else wikipedia and the netsnmp wiki ought to give you a basic idea

Our first MIB will have two scalar values, for which we try and get the values. I have borrowed an enterprises number from another blog I found on the net. Thanks for the same.

MY-COMPANY-MIB DEFINITIONS ::= BEGIN

IMPORTS
MODULE-IDENTITY, OBJECT-TYPE, enterprises, Integer32 FROM SNMPv2-SMI;

-- root of our MIB will point to enterprises

myCompanyMIB MODULE-IDENTITY
LAST-UPDATED
"200804230000Z"
ORGANIZATION
"asholachakra.blogspot.com"
CONTACT-INFO
"email: billgates@gmail.com"
DESCRIPTION
"Example MIB"
REVISION
"200804230000Z"
DESCRIPTION
"First and hopefully not the final revision"
::= { enterprises 3011 }

-- lets group all scalarValues in one node of our MIB

scalarValues OBJECT IDENTIFIER ::= { myCompanyMIB 1 }

-- time to define scalar values

hostLoggedUsers OBJECT-TYPE
SYNTAX Integer32 (0..65535)
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"Number of actually logged users on"
::= { scalarValues 1 }

hostName OBJECT-TYPE
SYNTAX OCTET STRING
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"Actual hostname"
::= { scalarValues 2 }

END


Writing modules for MIBs is a long and sometimes troublesome process, much like writing a parser. And just like writing a parser, you don't have to do everything by hand: MIBs can already be processed by computers pretty well, so there is no need to start from square one every time. The tool to convert an existing MIB to some C code is called mib2c and is part of the Net-SNMP distribution


Ok.....now that you have the MIB
At the command prompt, run mib2c as shown

linux-725y:~/.snmp/mib2cdata # mib2c scalarValues
writing to -
mib2c has multiple configuration files depending on the type of
code you need to write. You must pick one depending on your need.

You requested mib2c to be run on the following part of the MIB tree:
OID: scalarValues
numeric translation: .1.3.6.1.4.1.3011.1
number of scalars within: 2
number of tables within: 0
number of notifications within: 0

First, do you want to generate code that is compatible with the
ucd-snmp 4.X line of code, or code for the newer Net-SNMP 5.X code
base (which provides a much greater choice of APIs to pick from):

1) ucd-snmp style code
2) Net-SNMP style code

Select your choice : 2

**********************************************************************
GENERATING CODE FOR SCALAR OBJECTS:
**********************************************************************

It looks like you have some scalars in the mib you requested, so I
will now generate code for them if you wish. You have two choices
for scalar API styles currently. Pick between them, or choose not
to generate any code for the scalars:

1) If you're writing code for some generic scalars
(by hand use: "mib2c -c mib2c.scalar.conf scalarValues")

2) If you want to magically "tie" integer variables to integer
scalars
(by hand use: "mib2c -c mib2c.int_watch.conf scalarValues")

3) Don't generate any code for the scalars

Select your choice: 1
using the mib2c.scalar.conf configuration file to generate your code.
writing to scalarValues.h
writing to scalarValues.c



**********************************************************************
* NOTE WELL: The code generated by mib2c is only a template. *YOU* *
* must fill in the code before it'll work most of the time. In many *
* cases, spots that MUST be edited within the files are marked with *
* /* XXX */ or /* TODO */ comments. *
**********************************************************************
running indent on scalarValues.c
running indent on scalarValues.h
linux-725y:~/.snmp/mib2cdata #


If you now do an........... ls........... on that directory, you will see two files, scalarvalues.c and scalarvalues.h being generated.

mib2c has generated these two files which are, let's say, the framework to create valid SNMP handler.

We need to improve those files in order to support our SNMP queries: hostName, hostLoggedUsers.

Please note that scalarValues.h does not need any changes, so I only modified scalarValues.c as follows.

#include
#include
#include
#include "scalarValues.h"

struct HostStates
{
int loggedUsers;
char hostname[20];

} hostStates;

void
init_scalarValues(void)
{
static oid hostLoggedUsers_oid[] =
{ 1, 3, 6, 1, 4, 1,3011, 1, 1 };
static oid hostName_oid[] =
{ 1, 3, 6, 1, 4, 1,3011, 1, 2 };

netsnmp_register_scalar(
netsnmp_create_handler_registration("hostLoggedUsers", handle_hostLoggedUsers,
hostLoggedUsers_oid, OID_LENGTH(hostLoggedUsers_oid),
HANDLER_CAN_RONLY
));
netsnmp_register_scalar(
netsnmp_create_handler_registration("hostName", handle_hostName,
hostName_oid, OID_LENGTH(hostName_oid),
HANDLER_CAN_RONLY
));
}
int
handle_hostLoggedUsers(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
// obtain number of logged users here
hostStates.loggedUsers = 4;

switch(reqinfo->mode) {

case MODE_GET:
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
(u_char *) &hostStates.loggedUsers, sizeof(hostStates.loggedUsers));
break;
default:
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
handle_hostName(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
// obtain hostname here
strcpy(hostStates.hostname, "flechetHost");

switch(reqinfo->mode) {

case MODE_GET:
snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
(u_char *) &hostStates.hostname, strlen(hostStates.hostname));
break;
default:
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;



Ok, so what has changed ?? Mib2c does not know how we want to define the data, it is up to us to use individual data types or a user defined data structure. I have used a user defined data structure to store values for the integer and the octet string, and provided the pointer in memory for the same.

All I am doing at the moment is hardcoding the values of hostLoggedUsers and hostName. Lets get this working first and then see how we can obtain the same dynamically.

After that we will see how to do it for tables (using similar procedure)

Next steps will be to compile the c code into the agent and try to obtain the value.

Now it's time to compile ;) I will compile scalarValues.c to shared library libSnmpHandler.so and than I will install library in /usr/lib directory.

# gcc -shared -fPIC scalarValues.c -o libSnmpHandler.so
#cp libSnmpHandler.so /usr/lib

We can now configure net-snmp daemon to dynamically load our libSnmpHandler.so library on startup. In order to do this we need to create /etc/snmp/snmpd.conf file with following entries.
rocommunity public
rwcommunity public

dlmod scalarValues /usr/lib/libSnmpHandler.so



In snmpd.conf I also added rwcommunity and rocommunity entries. Both are simple passwords used by net-snmp daemon to authenticate SNMP clients. Of course it's possible to protect SNMP in a better way, but it's not area of this article. We're about to finish. Finally we can start net-snmp daemon with command:
# /etc/init.d/snmpd start
* Starting net-snmpd ...

Now it's time to verify if everything is working fine. We can use snmpget and snmpwalk tools to verify our work.
# snmpwalk -v 2c -c public localhost .1.3.6.1.4.1.3011.1
MY-COMPANY-MIB::hostLoggedUsers.0 = INTEGER: 4
MY-COMPANY-MIB::hostName.0 = STRING: "
flechetHost"

# snmpwalk -v 2c -c public localhost scalarValues
MY-COMPANY-MIB::hostLoggedUsers.0 = INTEGER: 4
MY-COMPANY-MIB::hostName.0 = STRING: "
flechetHost"

# snmpwalk -v 2c -c public localhost hostLoggedUsers
MY-COMPANY-MIB::hostLoggedUsers.0 = INTEGER: 4

# snmpget -v 2c -c public localhost hostLoggedUsers.0
MY-COMPANY-MIB::hostLoggedUsers.0 = INTEGER: 4



It's working fine! Now it's easy to add another queries to our MIB and libSnmpHandler.so. Possible enhancement are processor temperature, file system state, CPU usage and more and more. With net-snmp we can easily monitor all aspects of Linux box.

1 comment:

Siddharth Anand said...

Its a cool tutorial.....
but i m getting following error:

Unknown Object Identifier (Sub-id not found: (top) -> hostLoggedUsers)

Please help to get out of this....