/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
*
* U.S. Government Rights - Commercial software. Government users are subject to
* the Sun Microsystems, Inc. standard license agreement and applicable
* provisions of the FAR and its supplements.
*
*
* This distribution may include materials developed by third parties. Sun, Sun
* Microsystems, the Sun logo and Solaris are trademarks or registered
* trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
*
*/
/*
* demo_module_4:
*
* This module is based on the SDK-DEMO4-MIB.txt MIB. It implements the
* me4LoadGroup objects.
*
* This example module demonstrates following features: - Automatic Refresh of
* data in regular intervals - Check for alarm condition in regular intervals
* and generate trap if necessary. - Read threshold values from an external
* configuration file called demo_module_4.conf
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "me4LoadGroup.h"
#include <sys/loadavg.h>
#include <netdb.h>
/*
* Data for demo_module_4: loadavg1 stores data for me4SystemLoadAvg1min
* loadavg5 stores data for me4SystemLoadAvg5min loadavg15 stores data for
* me4SystemLoadAvg15min
*/
char *loadavg1, *loadavg5, *loadavg15;
/* Alarm thresholds for demo_module_4 */
float threshold_loadavg1 = 1.0, threshold_loadavg5 = 2.0, threshold_loadavg15 = 3.0;
/* Maintain previous alarm states for comparison */
int prev_loadavg1_state = OK;
int prev_loadavg5_state = OK;
int prev_loadavg15_state = OK;
/* Common variables for information to be included in traps */
u_char hostName[MAXHOSTNAMELEN], moduleName[15];
/** Initializes the demo_module_4 module
* This is the Init function which is called when the module is loaded by the agent.
*
* Note: The name of this function has been changed from "init_me4LoadGroup" to
* "init_demo_module_4" to give unique names to example modules across the SMA
* SDK.
*/
void
init_demo_module_4(void)
{
int retCode;
static oid me4SystemLoadAvg15min_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 4, 1, 3, 0};
static oid me4SystemLoadAvg1min_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 4, 1, 1, 0};
static oid me4SystemLoadAvg5min_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 4, 1, 2, 0};
DEBUGMSGTL(("me4LoadGroup", "Initializing\n"));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("me4SystemLoadAvg15min",
get_me4SystemLoadAvg15min,
me4SystemLoadAvg15min_oid,
OID_LENGTH(me4SystemLoadAvg15min_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("me4SystemLoadAvg1min",
get_me4SystemLoadAvg1min,
me4SystemLoadAvg1min_oid,
OID_LENGTH(me4SystemLoadAvg1min_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("me4SystemLoadAvg5min",
get_me4SystemLoadAvg5min,
me4SystemLoadAvg5min_oid,
OID_LENGTH(me4SystemLoadAvg5min_oid),
HANDLER_CAN_RONLY));
/* Initialize some common data */
retCode = gethostname((char *) hostName, MAXHOSTNAMELEN);
if (retCode != 0)
strcpy((char *) hostName, "null\0");
strcpy((char *) moduleName, "demo_module_4\0");
/* Allocate memory once. These variables will hold load data */
loadavg1 = malloc(10 * sizeof(char));
loadavg5 = malloc(10 * sizeof(char));
loadavg15 = malloc(10 * sizeof(char));
/*
* Register for thresholds. When a token (say threshold_loadavg1) is
* found in demo_module_4.conf file, the read_load_thresholds function is
* called by the agent
*/
register_config_handler("demo_module_4", "threshold_loadavg1",
read_load_thresholds, NULL, NULL);
register_config_handler("demo_module_4", "threshold_loadavg5",
read_load_thresholds, NULL, NULL);
register_config_handler("demo_module_4", "threshold_loadavg15",
read_load_thresholds, NULL, NULL);
snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_POST_READ_CONFIG,
demo_4_post_read_config, NULL);
}
/**
* The callback function that is called after the configuration files are
* read by the agent ( the thresholds are loaded into the module )
*/
int
demo_4_post_read_config(int a, int b, void *c, void *d)
{
/* Refresh the load data every 60 seconds */
snmp_alarm_register(60, SA_REPEAT, refreshLoadAvg, NULL);
/* Acquire the data first time */
refreshLoadAvg(0, NULL);
return 1;
}
/*
* This function is generated by mib2c. It is called when an SNMP "get"
* request arrives for the node me4SystemLoadAvg15min
*
*/
int
get_me4SystemLoadAvg15min(netsnmp_mib_handler * handler,
netsnmp_handler_registration * reginfo,
netsnmp_agent_request_info * reqinfo,
netsnmp_request_info * requests)
{
/*
* We are never called for a GETNEXT if it's registered as a "instance",
* as it's "magically" handled for us.
*/
/*
* a instance handler also only hands us one request at a time, so we
* don't need to loop over a list of requests; we'll only get one.
*/
/* Refresh the load data by calling the refresh function */
refreshLoadAvg(0, NULL);
switch (reqinfo->mode) {
case MODE_GET:
refreshLoadAvg(0, NULL);
snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) loadavg15, strlen(loadavg15));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
/*
* This function is generated by mib2c. It is called when an SNMP "get"
* request arrives for the node me4SystemLoadAvg1min
*
*/
int
get_me4SystemLoadAvg1min(netsnmp_mib_handler * handler,
netsnmp_handler_registration * reginfo,
netsnmp_agent_request_info * reqinfo,
netsnmp_request_info * requests)
{
/*
* We are never called for a GETNEXT if it's registered as a "instance",
* as it's "magically" handled for us.
*/
/*
* a instance handler also only hands us one request at a time, so we
* don't need to loop over a list of requests; we'll only get one.
*/
switch (reqinfo->mode) {
case MODE_GET:
refreshLoadAvg(0, NULL);
snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) loadavg1, strlen(loadavg1));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
/*
* This function is generated by mib2c. It is called when an SNMP "get"
* request arrives for the node me4SystemLoadAvg5min
*
*/
int
get_me4SystemLoadAvg5min(netsnmp_mib_handler * handler,
netsnmp_handler_registration * reginfo,
netsnmp_agent_request_info * reqinfo,
netsnmp_request_info * requests)
{
/*
* We are never called for a GETNEXT if it's registered as a "instance",
* as it's "magically" handled for us.
*/
/*
* a instance handler also only hands us one request at a time, so we
* don't need to loop over a list of requests; we'll only get one.
*/
refreshLoadAvg(0, NULL);
switch (reqinfo->mode) {
case MODE_GET:
refreshLoadAvg(0, NULL);
snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) loadavg5, strlen(loadavg5));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
/*
* refreshLoadAvg: This is the function which "refreshes" the load data using
* the system call "getloadavg". The data is stored in the 3 variables
* loadavg1, loadavg5, loadavg15. Once the data is refreshed, the "check"
* functions are called to check for alarm conditions
*/
void
refreshLoadAvg(unsigned int clientreg, void *clientarg)
{
double loadavg[3];
int numOfSamples = getloadavg(loadavg, 3);
sprintf(loadavg1, "%.3f\0", loadavg[LOADAVG_1MIN]);
sprintf(loadavg5, "%.3f\0", loadavg[LOADAVG_5MIN]);
sprintf(loadavg15, "%.3f\0", loadavg[LOADAVG_15MIN]);
check_loadavg1_state();
check_loadavg5_state();
check_loadavg15_state();
}
/*
* Function: conv_alarm_state : This function returns appropriate charecter
* string for each integer alarm type
*/
char *
conv_alarm_state(int state)
{
switch (state) {
case 0:
return "OK\0";
case 1:
return "ERROR\0";
default:
return "NULL\0";
}
}
/*
* read_load_thresholds: This function is called when a registered token (see
* Init_demo_module_4 function) is found in the appropriate configuration
* file. The token's values (thresholds) are then stored in some variables.
*/
void
read_load_thresholds(const char *token, char *cptr)
{
if (strcmp(token, "threshold_loadavg1") == 0) {
threshold_loadavg1 = atof(cptr);
} else if (strcmp(token, "threshold_loadavg5") == 0) {
threshold_loadavg5 = atof(cptr);
} else if (strcmp(token, "threshold_loadavg15") == 0) {
threshold_loadavg15 = atof(cptr);
} else {
/* Do nothing */
}
return;
}
/* send_trap: This function generates an snmpv2 trap */
void
send_trap(u_char * hostname, u_char * modulename, oid * trapoid, int size, u_char * status, u_char * description)
{
/* This is the notification type itself. This is statusChange trap */
oid notification_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 4, 2, 1};
size_t notification_oid_len = OID_LENGTH(notification_oid);
/*
* In the notification, we have to assign our notification OID to the
* snmpTrapOID.0 object. Here is it's definition.
*/
oid objid_snmptrap[] = {1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0};
size_t objid_snmptrap_len = OID_LENGTH(objid_snmptrap);
/*
* here is where we store the variables to be sent in the trap
*/
netsnmp_variable_list *notification_vars = NULL;
oid hostname_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 4, 3, 1, 0};
size_t hostname_oid_len = OID_LENGTH(hostname_oid);
oid modulename_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 4, 3, 2, 0};
size_t modulename_oid_len = OID_LENGTH(modulename_oid);
oid nodeoid_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 4, 3, 3, 0};
size_t nodeoid_oid_len = OID_LENGTH(nodeoid_oid);
oid status_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 4, 3, 4, 0};
size_t status_oid_len = OID_LENGTH(status_oid);
oid description_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 4, 3, 5, 0};
size_t description_oid_len = OID_LENGTH(description_oid);
/*
* add in the trap definition object
*/
snmp_varlist_add_variable(&notification_vars,
/*
* the snmpTrapOID.0 variable
*/
objid_snmptrap, objid_snmptrap_len,
/*
* value type is an OID
*/
ASN_OBJECT_ID,
/*
* value contents is our notification OID
*/
(u_char *) notification_oid,
/*
* size in bytes = oid length * sizeof(oid)
*/
notification_oid_len * sizeof(oid));
/*
* if we wanted to insert additional objects, we'd do it here
*/
snmp_varlist_add_variable(&notification_vars,
hostname_oid, hostname_oid_len,
/*
* value type is an OID
*/
ASN_OCTET_STR,
/*
* value contents is our notification OID
*/
(u_char *) hostname,
/*
* size in bytes = oid length * sizeof(oid)
*/
strlen((char *) hostname));
snmp_varlist_add_variable(&notification_vars,
modulename_oid, modulename_oid_len,
/*
* value type is an OID
*/
ASN_OCTET_STR,
/*
* value contents is our notification OID
*/
(u_char *) modulename,
/*
* size in bytes = oid length * sizeof(oid)
*/
strlen((char *) modulename));
snmp_varlist_add_variable(&notification_vars,
nodeoid_oid, nodeoid_oid_len,
/*
* value type is an OID
*/
ASN_OBJECT_ID,
/*
* value contents is our notification OID
*/
(u_char *) trapoid,
/*
* size in bytes = oid length * sizeof(oid)
*/
size * sizeof(oid));
snmp_varlist_add_variable(&notification_vars,
status_oid, status_oid_len,
/*
* value type is an OID
*/
ASN_OCTET_STR,
/*
* value contents is our notification OID
*/
(u_char *) status,
/*
* size in bytes = oid length * sizeof(oid)
*/
strlen((char *) status));
snmp_varlist_add_variable(&notification_vars,
description_oid, description_oid_len,
/*
* value type is an OID
*/
ASN_OCTET_STR,
/*
* value contents is our notification OID
*/
(u_char *) description,
/*
* size in bytes = oid length * sizeof(oid)
*/
strlen((char *) description));
/* SEND THE TRAP !!!! */
send_v2trap(notification_vars);
/*
* free the created notification variable list
*/
DEBUGMSGTL(("example_notification", "cleaning up\n"));
snmp_free_varbind(notification_vars);
return;
}
/*
* check_loadavg1_state: This function does 2 things: step-1) Determine the
* current alarm state of the node by comparing it's value with threshold.
* step-2) Depending on the new state of the node, generate a trap
*/
void
check_loadavg1_state()
{
/* Trap stuff */
oid trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 4, 1, 1, 0};
u_char status[8];
u_char description[] = "Load Average over last 1 minute crossed the threshold \0";
int size;
int new_loadavg1_state = OK;
float currentLoad = atof(loadavg1);
/* Step-1 */
/* If threshold is crossed, set state to ERROR */
if (currentLoad > threshold_loadavg1) {
new_loadavg1_state = ERROR;
}
/* Step-2 */
/* Depending on the new state, send trap if necessary */
size = sizeof(trapoid) / sizeof(oid);
strcpy((char *) status, conv_alarm_state(new_loadavg1_state));
if (new_loadavg1_state > prev_loadavg1_state) {
/* Send trap */
send_trap(hostName, moduleName, trapoid, size, status, description);
prev_loadavg1_state = new_loadavg1_state;
} else if (new_loadavg1_state == prev_loadavg1_state) {
/* No Change in state .. Do nothing */
} else if (new_loadavg1_state < prev_loadavg1_state) {
if (new_loadavg1_state == OK) {
/* Send OK trap */
prev_loadavg1_state = OK;
send_trap(hostName, moduleName, trapoid, size, status, description);
}
}
}
/*
* check_loadavg5_state: This function does 2 things: step-1) Determine the
* current alarm state of the node by comparing it's value with threshold.
* step-2) Depending on the new state of the node, generate a trap
*/
void
check_loadavg5_state()
{
/* Trap stuff */
oid trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 4, 1, 2, 0};
u_char status[8];
u_char description[] = "Load Average over last 5 minute crossed the threshold \0";
int size;
int new_loadavg5_state = OK;
double currentLoad = atof(loadavg5);
/* If threshold is crossed, set state to ERROR */
if (currentLoad > threshold_loadavg5)
new_loadavg5_state = ERROR;
/* Depending on the new state, send trap if necessary */
size = sizeof(trapoid) / sizeof(oid);
strcpy((char *) status, conv_alarm_state(new_loadavg5_state));
if (new_loadavg5_state > prev_loadavg5_state) {
/* Send trap */
send_trap(hostName, moduleName, trapoid, size, status, description);
prev_loadavg5_state = new_loadavg5_state;
} else if (new_loadavg5_state == prev_loadavg5_state) {
/* No Change in state .. Do nothing */
} else if (new_loadavg5_state < prev_loadavg5_state) {
if (new_loadavg5_state == OK) {
/* Send OK trap */
prev_loadavg5_state = OK;
send_trap(hostName, moduleName, trapoid, size, status, description);
}
}
}
/*
* check_loadavg15_state: This function does 2 things: step-1) Determine the
* current alarm state of the node by comparing it's value with threshold.
* step-2) Depending on the new state of the node, generate a trap
*/
void
check_loadavg15_state()
{
/* Trap stuff */
oid trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 4, 1, 3, 0};
u_char status[8];
u_char description[] = "Load Average over last 15 minute crossed the threshold \0";
int size;
int new_loadavg15_state = OK;
double currentLoad = atof(loadavg15);
/* If threshold is crossed, set state to ERROR */
if (currentLoad > threshold_loadavg15)
new_loadavg15_state = ERROR;
/* Depending on the new state, send trap if necessary */
size = sizeof(trapoid) / sizeof(oid);
strcpy((char *) status, conv_alarm_state(new_loadavg15_state));
if (new_loadavg15_state > prev_loadavg15_state) {
/* Send trap */
prev_loadavg15_state = new_loadavg15_state;
send_trap(hostName, moduleName, trapoid, size, status, description);
} else if (new_loadavg15_state == prev_loadavg15_state) {
/* No Change in state .. Do nothing */
} else if (new_loadavg15_state < prev_loadavg15_state) {
if (new_loadavg15_state == OK) {
/* Send OK trap */
prev_loadavg15_state = OK;
send_trap(hostName, moduleName, trapoid, size, status, description);
}
}
}