/*
* Copyright (c) 2003, 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.
*
*/
/*
* Note: this file originally auto-generated by mib2c using :
* mib2c.scalar.conf,v 1.5 2002/07/18 14:18:52 dts12 Exp $
*/
/*
* This Module implements all the nodes in health-monitor-mib.mib.
* mib2c.scalar.conf is used to generate template for all nodes except the
* hmDiskGroup mib2c.iterate.conf is used to generate template for
* hmDiskGroup (which contains a Table) The two templates are merged so that
* all the implementation for health-monitor-mib is present as one module.
* Template functions are filled and new functions are added to do the
* following: 1) Data Acquisition, 2) Automatic refresh, 3) trap generation,
* 4) subscribe for thresholds from health_monitor.conf file.
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "healthMonitor.h"
#include <netdb.h>
/*
* DATA: Following are the variables in which data collected for various
* nodes is stored. The values are refreshed every "refresh interval"
* (default 60 seconds). The value stored in this variable is returned
* whenever a "get" request comes.
*/
/* Data for SWAP node */
int swapavail_data, swapresv_data, swapalloc_data, swapused_data,
swaptotal_data;
/* Data for Kernel node */
ulong sum_smtx = 0;
int ncpus;
/* Data for NFS node */
double calls;
int badcalls, retrans, badxids, timeouts, newcreds, badverfs,
timers, nomem, cantsend, interrupts;
char callsStr[8];
/* Data for CPU node */
int runque, waiting, swapque;
/* Data for RAM node */
int handspread, scan;
/*
* Data for KMEM node . Only alloc_fail and mem_free are published through
* the MIB
*/
int alloc, alloc_fail=0, buf_size, buf_avail, buf_total, buf_max;
int mem_avail=0, mem_inuse=0, mem_free=0;
/*
* Data for DNLC node . hits, misses, hitrate and refrate are published
* through the MIB. Rest of variables are temp data used for processing alarm
* conditions.
*/
int firsttime = 1;
int lasthits = 0;
int lastmisses = 0;
int prevhits = 0;
int prevmisses = 0;
long prevtime = 0;
long hits, misses;
long hitrate, refrate;
/*
* Data for diskGroup. We maintain the disk table in memory as a linked list
* of hmDiskTable objects "head" points to the first memeber of the linked
* list
*/
hmDiskTable *head;
int diskCount;
/*
* Following are the variables that hold threshold's used to determine alarm
* conditions. The variables are updated with threshold settings in
* health_monitor.conf file, when module is initialized.
*/
/* Thresholds and States for SWAP node */
int threshold_swapavail_info = 500000, threshold_swapavail_warning = 100000,
threshold_swapavail_error = 40000;
int prev_SWAP_state = OK;
int new_SWAP_state = OK;
int SWAP_rule_state = NOTINIT;
/* Thresholds for Kernel node */
ulong threshold_mutex_info = 200, threshold_mutex_warning = 500;
int prev_mutex_state = OK;
int new_mutex_state = OK;
int Kernel_rule_state = NOTINIT;
/* Thresholds for NFS node */
float threshold_mincalls = 0.1, threshold_badxids = 0.0, threshold_timeouts = 5.0;
int prev_NFS_state = OK;
int new_NFS_state = OK;
int NFS_rule_state = NOTINIT;
/* Thresholds for CPU node */
float threshold_cpuload_info = 1.0, threshold_cpuload_warning = 2.0,
threshold_cpuload_error = 3.0;
int prev_cpuload_state = OK;
int new_cpuload_state = OK;
int CPU_rule_state = NOTINIT;
/* Thresholds for RAM node */
int threshold_restime_long = 600, threshold_restime_ok = 40,
threshold_restime_error = 20;
int prev_restime_state = OK;
int new_restime_state = OK;
int RAM_rule_state = NOTINIT;
/* Thresholds for KMEM node */
int threshold_freemem_low = 1;
int firstkmemerrs = 0, lastkmemerrs = 0; /* These must be Global
* variables and
* preserved across
* invocation of
* check_state_KMEM()
* function */
int prev_kmem_state = OK;
int new_kmem_state = OK;
int KMEM_rule_state = NOTINIT;
/* Thresholds for DNLC node */
float threshold_dnlc_active = 100.0, threshold_dnlc_warning = 80;
int prev_dnlc_state = OK;
int new_dnlc_state = OK;
int DNLC_rule_state = NOTINIT;
/* Thresholds for diskGroup */
long disk_busy_warning = 10.0, disk_busy_problem = 30.0, disk_svc_t_warning = 20.0,
disk_svc_t_problem = 30.0;
/* COMMON data variables */
u_char hostName[MAXHOSTNAMELEN], moduleName[15], statusOIDContext[5];
int hm_refresh_interval=60;
time_t hm_prev_ref_time=1;
time_t hm_prev_disk_ref=1;
/** Initializes the healthMonitor module */
void
init_healthMonitor(void)
{
int retCode;
static oid hmSpinsOnMutexes_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 2, 1, 1, 0};
static oid hmTotProcInRunQueue_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 4, 1, 1, 0};
static oid hmTotRPCCalls_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 1, 0};
static oid hmUsedSwapSpace_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 1, 1, 4, 0};
static oid hmDNLCMisses_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 8, 1, 2, 0};
static oid hmReservedSwapSpace_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 1, 1, 2, 0};
static oid hmTotMemAllocFails_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 9, 0};
static oid hmAvailableSwapSpace_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 1, 1, 1, 0};
static oid hmDNLCHitRate_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 8, 1, 3, 0};
static oid hmDNLCHits_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 8, 1, 1, 0};
static oid hmAllocatedSwapSpace_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 1, 1, 3, 0};
static oid hmTotNumOfCPUs_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 2, 1, 2, 0};
static oid hmPageScanRate_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 6, 1, 2, 0};
static oid hmTimers_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 8, 0};
static oid hmTotBadRPCCalls_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 2, 0};
static oid hmDNLCRefRate_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 8, 1, 4, 0};
static oid hmTotSendFails_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 10, 0};
static oid hmTotFailedCallsBV_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 7, 0};
static oid hmTotNumOfAuthRefresh_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 6, 0};
static oid hmHandspread_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 6, 1, 1, 0};
static oid hmTotRPCRetransmissions_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 3, 0};
static oid hmKmemFreeMem_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 7, 1, 2, 0};
static oid hmTotBadRPCReplies_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 4, 0};
static oid hmKmemErrors_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 7, 1, 1, 0};
static oid hmTotProcReadyInSwap_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 4, 1, 3, 0};
static oid hmTotProcBlocked_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 4, 1, 2, 0};
static oid hmTotRPCCallsTimedOut_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 5, 0};
DEBUGMSGTL(("healthMonitor", "Initializing\n"));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmSpinsOnMutexes",
get_hmSpinsOnMutexes,
hmSpinsOnMutexes_oid,
OID_LENGTH(hmSpinsOnMutexes_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotProcInRunQueue",
get_hmTotProcInRunQueue,
hmTotProcInRunQueue_oid,
OID_LENGTH(hmTotProcInRunQueue_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotRPCCalls",
get_hmTotRPCCalls,
hmTotRPCCalls_oid,
OID_LENGTH(hmTotRPCCalls_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmUsedSwapSpace",
get_hmUsedSwapSpace,
hmUsedSwapSpace_oid,
OID_LENGTH(hmUsedSwapSpace_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmDNLCMisses",
get_hmDNLCMisses,
hmDNLCMisses_oid,
OID_LENGTH(hmDNLCMisses_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmReservedSwapSpace",
get_hmReservedSwapSpace,
hmReservedSwapSpace_oid,
OID_LENGTH(hmReservedSwapSpace_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotMemAllocFails",
get_hmTotMemAllocFails,
hmTotMemAllocFails_oid,
OID_LENGTH(hmTotMemAllocFails_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmAvailableSwapSpace",
get_hmAvailableSwapSpace,
hmAvailableSwapSpace_oid,
OID_LENGTH(hmAvailableSwapSpace_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmDNLCHitRate",
get_hmDNLCHitRate,
hmDNLCHitRate_oid,
OID_LENGTH(hmDNLCHitRate_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmDNLCHits",
get_hmDNLCHits,
hmDNLCHits_oid,
OID_LENGTH(hmDNLCHits_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmAllocatedSwapSpace",
get_hmAllocatedSwapSpace,
hmAllocatedSwapSpace_oid,
OID_LENGTH(hmAllocatedSwapSpace_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotNumOfCPUs",
get_hmTotNumOfCPUs,
hmTotNumOfCPUs_oid,
OID_LENGTH(hmTotNumOfCPUs_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmPageScanRate",
get_hmPageScanRate,
hmPageScanRate_oid,
OID_LENGTH(hmPageScanRate_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTimers",
get_hmTimers,
hmTimers_oid,
OID_LENGTH(hmTimers_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotBadRPCCalls",
get_hmTotBadRPCCalls,
hmTotBadRPCCalls_oid,
OID_LENGTH(hmTotBadRPCCalls_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmDNLCRefRate",
get_hmDNLCRefRate,
hmDNLCRefRate_oid,
OID_LENGTH(hmDNLCRefRate_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotSendFails",
get_hmTotSendFails,
hmTotSendFails_oid,
OID_LENGTH(hmTotSendFails_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotFailedCallsBV",
get_hmTotFailedCallsBV,
hmTotFailedCallsBV_oid,
OID_LENGTH(hmTotFailedCallsBV_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotNumOfAuthRefresh",
get_hmTotNumOfAuthRefresh,
hmTotNumOfAuthRefresh_oid,
OID_LENGTH(hmTotNumOfAuthRefresh_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmHandspread",
get_hmHandspread,
hmHandspread_oid,
OID_LENGTH(hmHandspread_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotRPCRetransmissions",
get_hmTotRPCRetransmissions,
hmTotRPCRetransmissions_oid,
OID_LENGTH(hmTotRPCRetransmissions_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmKmemFreeMem",
get_hmKmemFreeMem,
hmKmemFreeMem_oid,
OID_LENGTH(hmKmemFreeMem_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotBadRPCReplies",
get_hmTotBadRPCReplies,
hmTotBadRPCReplies_oid,
OID_LENGTH(hmTotBadRPCReplies_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmKmemErrors",
get_hmKmemErrors,
hmKmemErrors_oid,
OID_LENGTH(hmKmemErrors_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotProcReadyInSwap",
get_hmTotProcReadyInSwap,
hmTotProcReadyInSwap_oid,
OID_LENGTH(hmTotProcReadyInSwap_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotProcBlocked",
get_hmTotProcBlocked,
hmTotProcBlocked_oid,
OID_LENGTH(hmTotProcBlocked_oid),
HANDLER_CAN_RONLY));
netsnmp_register_read_only_instance(netsnmp_create_handler_registration
("hmTotRPCCallsTimedOut",
get_hmTotRPCCallsTimedOut,
hmTotRPCCallsTimedOut_oid,
OID_LENGTH(hmTotRPCCallsTimedOut_oid),
HANDLER_CAN_RONLY));
/* Initialize Disk stuff */
/* here we initialize all the tables we're planning on supporting */
initialize_table_hmDiskTable();
/*
* Additions to init function to register callbacks for tokens. Whenever
* a token is encountered in health_monitor.conf file, the function
* read_health_monitor_thresholds is called by the agent
*/
register_config_handler("health_monitor", "hm_refresh_interval",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_swapavail_info",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_swapavail_warning",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_swapavail_error",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_mutex_info",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_mutex_warning",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_mincalls",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_badxids",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_timeouts",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_cpuload_info",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_cpuload_warning",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_cpuload_error",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_restime_long",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_restime_ok",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_restime_error",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_freemem_low",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_dnlc_active",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "threshold_dnlc_warning",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "disk_busy_warning",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "disk_busy_problem",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "disk_svc_t_warning",
read_health_monitor_thresholds, NULL, NULL);
register_config_handler("health_monitor", "disk_svc_t_problem",
read_health_monitor_thresholds, NULL, NULL);
/*
* Initialize data that's required in the trap - The hostname,
* modulenaem, statusOIDContext
*/
retCode = gethostname((char *) hostName, MAXHOSTNAMELEN);
if (retCode != 0)
strcpy((char *) hostName, "null\0");
strcpy((char *) moduleName, "Health-Monitor\0");
strcpy((char *) statusOIDContext, "null\0");
snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_POST_READ_CONFIG,
hm_post_read_config, NULL);
}
/** Initialize the hmDiskTable table by defining its contents and how it's structured */
void
initialize_table_hmDiskTable(void)
{
static oid hmDiskTable_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 5, 1};
netsnmp_table_registration_info *table_info;
netsnmp_handler_registration *my_handler;
netsnmp_iterator_info *iinfo;
/* create the table structure itself */
table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
/*
* if your table is read only, it's easiest to change the
* HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY
*/
my_handler = netsnmp_create_handler_registration("hmDiskTable",
hmDiskTable_handler,
hmDiskTable_oid,
OID_LENGTH(hmDiskTable_oid),
HANDLER_CAN_RONLY);
if (!my_handler || !table_info || !iinfo)
return; /* mallocs failed */
/***************************************************
* Setting up the table's definition
*/
netsnmp_table_helper_add_indexes(table_info,
ASN_OCTET_STR, /* index: hmDiskName */
0);
table_info->min_column = 1;
table_info->max_column = 5;
/* iterator access routines */
iinfo->get_first_data_point = hmDiskTable_get_first_data_point;
iinfo->get_next_data_point = hmDiskTable_get_next_data_point;
iinfo->table_reginfo = table_info;
/***************************************************
* registering the table with the master agent
*/
DEBUGMSGTL(("initialize_table_hmDiskTable",
"Registering table hmDiskTable as a table iterator\n"));
netsnmp_register_table_iterator(my_handler, iinfo);
}
int
get_hmSpinsOnMutexes(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:
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & sum_smtx, sizeof(sum_smtx));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotProcInRunQueue(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.
*/
long runque_long;
switch (reqinfo->mode) {
case MODE_GET:
runque_long = (long) runque;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & runque_long, sizeof(runque_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotRPCCalls(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:
snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) callsStr, strlen(callsStr) );
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmUsedSwapSpace(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.
*/
long swapused_data_long;
switch (reqinfo->mode) {
case MODE_GET:
swapused_data_long = (long)swapused_data;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & swapused_data_long, sizeof(swapused_data_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmDNLCMisses(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:
snmp_set_var_typed_value(requests->requestvb, ASN_UNSIGNED, (u_char *) & misses, sizeof(misses));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmReservedSwapSpace(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.
*/
long swapresv_data_long;
switch (reqinfo->mode) {
case MODE_GET:
swapresv_data_long = (long) swapresv_data;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & swapresv_data_long, sizeof(swapresv_data_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotMemAllocFails(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.
*/
long nomem_long;
switch (reqinfo->mode) {
case MODE_GET:
nomem_long = (long) nomem;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & nomem_long, sizeof(nomem_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmAvailableSwapSpace(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) {
long swapavail_data_long;
case MODE_GET:
swapavail_data_long = (long) swapavail_data;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & swapavail_data_long, sizeof(swapavail_data_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmDNLCHitRate(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:
snmp_set_var_typed_value(requests->requestvb, ASN_UNSIGNED, (u_char *) & hitrate, sizeof(hitrate));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmDNLCHits(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:
snmp_set_var_typed_value(requests->requestvb, ASN_UNSIGNED, (u_char *) & hits, sizeof(hits));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmAllocatedSwapSpace(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.
*/
long swapalloc_data_long;
switch (reqinfo->mode) {
case MODE_GET:
swapalloc_data_long = (long) swapalloc_data;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & swapalloc_data_long, sizeof(swapalloc_data_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotNumOfCPUs(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.
*/
long ncpus_long;
switch (reqinfo->mode) {
case MODE_GET:
ncpus_long = (long)ncpus;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & ncpus_long, sizeof(ncpus_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmPageScanRate(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.
*/
long scan_long;
switch (reqinfo->mode) {
case MODE_GET:
scan_long = (long) scan;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & scan_long, sizeof(scan_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTimers(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.
*/
long timers_long;
switch (reqinfo->mode) {
case MODE_GET:
timers_long = (long) timers;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & timers_long, sizeof(timers_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotBadRPCCalls(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.
*/
long badcalls_long;
switch (reqinfo->mode) {
case MODE_GET:
badcalls_long = (long) badcalls ;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & badcalls_long, sizeof(badcalls_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmDNLCRefRate(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:
snmp_set_var_typed_value(requests->requestvb, ASN_UNSIGNED, (u_char *) & refrate, sizeof(refrate));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotSendFails(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.
*/
long cantsend_long;
switch (reqinfo->mode) {
case MODE_GET:
cantsend_long = (long) cantsend;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & cantsend_long, sizeof(cantsend_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotFailedCallsBV(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.
*/
long badxids_long;
switch (reqinfo->mode) {
case MODE_GET:
badxids_long = (long) badxids;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & badxids_long, sizeof(badxids_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotNumOfAuthRefresh(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.
*/
long newcreds_long;
switch (reqinfo->mode) {
case MODE_GET:
newcreds_long = (long) newcreds;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & newcreds_long, sizeof(newcreds_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmHandspread(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.
*/
long handspread_long;
switch (reqinfo->mode) {
case MODE_GET:
handspread_long = (long) handspread;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & handspread_long, sizeof(handspread_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotRPCRetransmissions(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.
*/
long interrupts_long;
switch (reqinfo->mode) {
case MODE_GET:
interrupts_long = (long) interrupts;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & interrupts_long, sizeof(interrupts_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmKmemFreeMem(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.
*/
long mem_free_long;
switch (reqinfo->mode) {
case MODE_GET:
mem_free_long = (long) mem_free;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & mem_free_long, sizeof(mem_free_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotBadRPCReplies(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.
*/
long badverfs_long;
switch (reqinfo->mode) {
case MODE_GET:
badverfs_long = (long) badverfs;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & badverfs_long, sizeof(badverfs_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmKmemErrors(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.
*/
long alloc_fail_long;
switch (reqinfo->mode) {
case MODE_GET:
alloc_fail_long = (long) alloc_fail;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & alloc_fail_long, sizeof(alloc_fail_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotProcReadyInSwap(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.
*/
long swapque_long;
switch (reqinfo->mode) {
case MODE_GET:
swapque_long = (long) swapque;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & swapque_long, sizeof(swapque_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotProcBlocked(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.
*/
long waiting_long;
switch (reqinfo->mode) {
case MODE_GET:
waiting_long = (long) waiting;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & waiting_long, sizeof(waiting_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
get_hmTotRPCCallsTimedOut(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.
*/
long timeouts_long;
switch (reqinfo->mode) {
case MODE_GET:
timeouts_long = (long) timeouts;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & timeouts_long, sizeof(timeouts_long));
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int hm_post_read_config(int a, int b, void *c, void *d)
{
/*
* Refresh the HealthMonitor module data every 60 seconds. Every 60
* seconds, the function refresh_all_HM_data is called automatically by
* the agent. Also, load data into nodes now by calling the refresh
* function once
*/
construct_DISK_table();
refresh_all_HM_data(0, NULL);
snmp_alarm_register(hm_refresh_interval, SA_REPEAT, refresh_DISK_table, NULL);
snmp_alarm_register(hm_refresh_interval, SA_REPEAT, refresh_all_HM_data, NULL);
}
hmDiskTable *
get_first_node()
{
return head;
}
/** returns the first data point within the hmDiskTable table data.
Set the my_loop_context variable to the first data point structure
of your choice (from which you can find the next one). This could
be anything from the first node in a linked list, to an integer
pointer containing the beginning of an array variable.
Set the my_data_context variable to something to be returned to
you later that will provide you with the data to return in a given
row. This could be the same pointer as what my_loop_context is
set to, or something different.
The put_index_data variable contains a list of snmp variable
bindings, one for each index in your table. Set the values of
each appropriately according to the data matching the first row
and return the put_index_data variable at the end of the function.
*/
netsnmp_variable_list *
hmDiskTable_get_first_data_point(void **my_loop_context, void **my_data_context,
netsnmp_variable_list * put_index_data,
netsnmp_iterator_info * mydata)
{
netsnmp_variable_list *vptr;
hmDiskTable *firstNode = get_first_node();
if (!firstNode) {
return NULL;
}
*my_loop_context = firstNode;
*my_data_context = firstNode;
vptr = put_index_data;
snmp_set_var_value(vptr, (u_char *) firstNode->hmDiskName, strlen(firstNode->hmDiskName) /* XXX: length of
hmDiskName data */ );
vptr = vptr->next_variable;
return put_index_data;
}
/** functionally the same as hmDiskTable_get_first_data_point, but
my_loop_context has already been set to a previous value and should
be updated to the next in the list. For example, if it was a
linked list, you might want to cast it and the return
my_loop_context->next. The my_data_context pointer should be set
to something you need later and the indexes in put_index_data
updated again. */
netsnmp_variable_list *
hmDiskTable_get_next_data_point(void **my_loop_context, void **my_data_context,
netsnmp_variable_list * put_index_data,
netsnmp_iterator_info * mydata)
{
netsnmp_variable_list *vptr;
hmDiskTable *nextNode = (hmDiskTable *) * my_loop_context;
/* This check is not really required */
if(!nextNode) {
snmp_log(LOG_DEBUG,"No data returned in get_next\n");
return NULL;
}
nextNode = nextNode->pNext;
if (!nextNode) {
snmp_log(LOG_DEBUG,"No data returned in get_next\n");
return NULL;
}
*my_loop_context = nextNode;
*my_data_context = nextNode;
vptr = put_index_data;
snmp_set_var_value(vptr, (u_char *) nextNode->hmDiskName /* XXX: hmDiskName data */ , strlen(nextNode->hmDiskName) /* XXX: length of
hmDiskName data */ );
vptr = vptr->next_variable;
return put_index_data;
}
/** handles requests for the hmDiskTable table, if anything else needs to be done */
int
hmDiskTable_handler(
netsnmp_mib_handler * handler,
netsnmp_handler_registration * reginfo,
netsnmp_agent_request_info * reqinfo,
netsnmp_request_info * requests)
{
netsnmp_request_info *request;
netsnmp_table_request_info *table_info;
netsnmp_variable_list *var;
hmDiskTable *data;
for (request = requests; request; request = request->next) {
var = request->requestvb;
if (request->processed != 0)
continue;
/*
* perform anything here that you need to do before each request is
* processed.
*/
/*
* the following extracts the my_data_context pointer set in the loop
* functions above. You can then use the results to help return data
* for the columns of the hmDiskTable table in question
*/
data = (hmDiskTable *) netsnmp_extract_iterator_context(request);
if (data == NULL) {
if (reqinfo->mode == MODE_GET) {
netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE);
continue;
}
/*
* XXX: no row existed, if you support creation and this is a
* set, start dealing with it here, else continue
*/
}
/* extracts the information about the table from the request */
table_info = netsnmp_extract_table_info(request);
/* table_info->colnum contains the column number requested */
/*
* table_info->indexes contains a linked list of snmp variable
* bindings for the indexes of the table. Values in the list have
* been set corresponding to the indexes of the request
*/
if (table_info == NULL) {
continue;
}
switch (reqinfo->mode) {
/*
* the table_iterator helper should change all GETNEXTs into GETs
* for you automatically, so you don't have to worry about the
* GETNEXT case. Only GETs and SETs need to be dealt with here
*/
case MODE_GET:
switch (table_info->colnum) {
case COLUMN_HMDISKNAME:
snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) data->hmDiskName, strlen(data->hmDiskName));
break;
case COLUMN_HMDISKALIASNAME:
snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) data->hmDiskAliasName, strlen(data->hmDiskAliasName));
break;
case COLUMN_HMAVGWAITTRANSACTIONS:
snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) data->hmAvgWaitTransactions, strlen(data->hmAvgWaitTransactions));
break;
case COLUMN_HMDISKBUSYPCNT:
snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) data->hmDiskBusyPcnt, strlen(data->hmDiskBusyPcnt));
break;
case COLUMN_HMAVGDISKSVCTIME:
snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) data->hmAvgDiskSvcTime, strlen(data->hmAvgDiskSvcTime));
break;
default:
/* We shouldn't get here */
snmp_log(LOG_ERR, "problem encountered in hmDiskTable_handler: unknown column\n");
}
break;
case MODE_SET_RESERVE1:
/* set handling... */
default:
snmp_log(LOG_ERR, "problem encountered in hmDiskTable_handler: unsupported mode\n");
}
}
return SNMP_ERR_NOERROR;
}
/*
* *****
* New Functions that are added to the template generated by mib2c
* *****
*/
/*
* The following refresh functions are called every 60 seconds. The data
* nodes are updated with latest data
*/
void
refresh_SWAP_data()
{
int code = 0;
code = krgetswapusage(&swapavail_data, &swapresv_data, &swapalloc_data, &swapused_data, &swaptotal_data);
/*
* code == -1 : Error in swapctl code == 0 : Success Can be verified
* using "swap -s" on shell
*/
if (code != 0) {
snmp_log(LOG_ERR,"Health Monitor Module: errror getting SWAP info\n");
swapavail_data = 0;
swapresv_data = 0;
swapalloc_data = 0;
swapused_data = 0;
}
}
void
refresh_Kernel_data()
{
int code = 0;
code = krgetsmtx(&sum_smtx, &ncpus);
if (code != 0) {
snmp_log(LOG_ERR,"Health Monitor Module: errror getting Kernel info\n");
sum_smtx = 0;
ncpus = 0;
}
}
void
refresh_NFS_data()
{
int code = 0;
code = krgetclientrpcdetail(&calls, &badcalls, &retrans, &badxids, &timeouts, &newcreds, &badverfs, &timers, &nomem, &cantsend);
if (code != 0) {
snmp_log(LOG_ERR,"Health Monitor Module: errror getting NFS info\n");
calls = 0;
badcalls = 0;
retrans = 0;
badxids = 0;
timeouts = 0;
newcreds = 0;
badverfs = 0;
timers = 0;
nomem = 0;
cantsend = 0;
}
/* "calls" is defined as a "DisplayString" in the MIB. So, converting
* it to String
*/
sprintf(callsStr, "%3.1f\0", calls);
}
void
refresh_CPU_data()
{
int code = 0;
code = krgetprocdetail(&runque, &waiting, &swapque);
if (code != 0) {
snmp_log(LOG_ERR,"Health Monitor Module: errror getting CPU info\n");
runque = 0;
waiting = 0;
swapque = 0;
}
}
void
refresh_RAM_data()
{
int code = 0;
code = krgetramdetail(&handspread, &scan);
if (code != 0) {
snmp_log(LOG_ERR,"Health Monitor Module: errror getting RAM info\n");
handspread = 0;
scan = 0;
}
}
void
refresh_KMEM_data()
{
int code = 0;
char char_name[2] = "*\n";
/* char char_name='*'; */
/* The first argument of "*" requests sum of statistics of all caches */
code = krgetkmemdetail(char_name, &alloc, &alloc_fail, &buf_size, &buf_avail, &buf_total, &buf_max);
if (code >= 0)
code = krgetmemusage(&mem_avail, &mem_inuse, &mem_free);
if (code != 0) {
snmp_log(LOG_ERR,"Health Monitor Module: errror getting KMEM info\n");
alloc_fail = 0;
mem_free = 0;
}
}
void
refresh_DNLC_data()
{
int code = 0;
long curtime;
curtime = time(&curtime);
if (prevtime != curtime) {
code = krgetncstatdetail(&hits, &misses);
if (code != 0) {
snmp_log(LOG_ERR,"Health Monitor Module: errror getting DNLC info\n");
hits = 0;
misses = 0;
} /* NOTE : Should we do below even if
* hits=0,misses=0 ? Yes, according to SunMC
* rule */
if (firsttime == 1) {
firsttime = 0;
lasthits = hits;
lastmisses = misses;
} else {
lasthits = prevhits;
lastmisses = prevmisses;
}
prevhits = hits;
prevmisses = misses;
refrate = (hits - lasthits) + (misses - lastmisses);
if (refrate == 0) {
hitrate = 100;
} else {
hitrate = 100 * (hits - lasthits) / refrate;
refrate = refrate / (curtime - prevtime);
}
prevtime = curtime;
}
}
void
construct_DISK_table()
{
hmDiskTable *prevPtr = NULL;
char name[MAXNAMELEN];
char alias[MAXNAMELEN];
double rps, wps, tps, krps, kwps, kps, avw, avr;
double w_pct, r_pct, wserv, rserv, serv;
int code = 0;
/* set to 0 so that we can block any other refresh's */
hm_prev_disk_ref = 0;
/* Keeps track of number of disks */
diskCount = 0;
do {
hmDiskTable *ptr = (hmDiskTable *) malloc(sizeof(hmDiskTable));
if ( ptr == NULL) {
snmp_log(LOG_DEBUG,"malloc failed when constructing DISK table in health monitor module \n");
return;
}
code = krgetdiskdetail(name, alias, &rps, &wps, &tps, &krps, &kwps, &kps, &avw, &avr);
if (code < 0) {
/* Error occured during kstat read */
snmp_log(LOG_ERR,"Health Monitor Module: errror getting disk info\n");
return;
}
code = krgetdisksrv(name, alias, &w_pct, &r_pct, &wserv, &rserv, &serv);
if (code < 0) {
/* Error occured during kstat read */
snmp_log(LOG_ERR,"Health Monitor Module: errror getting disk info\n");
return;
}
/* Allocate required memory to hold each disk data. */
ptr->hmDiskName = (char *) malloc(strlen(name) + 1);
ptr->hmDiskAliasName = (char *) malloc(strlen(alias) + 1);
ptr->hmAvgWaitTransactions = (char *) malloc(DISK_DATA_LEN);
ptr->hmDiskBusyPcnt = (char *) malloc(DISK_DATA_LEN);
ptr->hmAvgDiskSvcTime = (char *) malloc(DISK_DATA_LEN);
if ( ptr->hmAvgDiskSvcTime == NULL) {
snmp_log(LOG_DEBUG,"malloc failed when constructing DISK table in health monitor module \n");
return;
}
strcpy(ptr->hmDiskName,name);
strcpy(ptr->hmDiskAliasName,alias);
sprintf(ptr->hmAvgWaitTransactions, "%3.1f\0", w_pct);
sprintf(ptr->hmDiskBusyPcnt, "%3.1f\0", r_pct);
sprintf(ptr->hmAvgDiskSvcTime, "%3.1f\0", serv);
/* Set the state of Disk to OK. */
ptr->hmDiskState = OK;
diskCount++;
ptr->pNext = NULL;
if (prevPtr == NULL) {
head = prevPtr = ptr;
} else {
prevPtr->pNext = ptr;
prevPtr = ptr;
}
/* code is set to value 0 if there is more disk information */
} while (code == 0);
check_state_DISK();
/* set the time of first refresh */
time(&hm_prev_disk_ref);
}
void
refresh_DISK_table(unsigned int clientreg, void *clientarg)
{
char name[MAXNAMELEN];
char alias[MAXNAMELEN];
double rps, wps, tps, krps, kwps, kps, avw, avr;
double w_pct, r_pct, wserv, rserv, serv;
int code = 0;
hmDiskTable *headPtr;
hmDiskTable *ptr;
hmDiskTable *tailPtr, *p1, *p2;
time_t hm_current_time;
/* Did the previous refresh really finish ??
* This means that previous refresh is still in progress */
if (hm_prev_disk_ref == 0) return;
time(&hm_current_time);
/* Did the previous refresh finish too close to start another refresh ???
* This means that the previous refresh finished relatively closer to current time
* so, another refresh is not necessary. hm_prev_disk_ref is initialized to 1
* during variable declaration. so, the first time refresh is called, it will always
* proceed.
*/
if ( (hm_current_time - hm_prev_disk_ref) < (hm_refresh_interval / 4) ) return;
/* set to 0 so that we can block any other refresh's */
hm_prev_disk_ref = 0;
diskCount=0;
/* Set tailPtr to the last structure
* set "hmTraversed" to 0 for all disks
*/
tailPtr = head;
while (tailPtr->pNext != NULL) {
tailPtr->hmTraversed=0;
tailPtr = tailPtr->pNext;
}
if(tailPtr != NULL) tailPtr->hmTraversed=0;
do {
int hit = 0;
code = krgetdiskdetail(name, alias, &rps, &wps, &tps, &krps, &kwps, &kps, &avw, &avr);
if (code < 0) {
/* Error occured during kstat read */
snmp_log(LOG_ERR,"Health Monitor Module: errror getting disk info\n");
return;
}
code = krgetdisksrv(name, alias, &w_pct, &r_pct, &wserv, &rserv, &serv);
if (code < 0) {
/* Error occured during kstat read */
snmp_log(LOG_ERR,"Health Monitor Module: errror getting disk info\n");
return;
}
/* For each row in the table, refresh the data */
headPtr = head;
while ((headPtr != NULL) && (hit == 0)) {
if (strncmp(headPtr->hmDiskName, name, strlen(name)) == 0) {
/*
* This Disk is already part of the list. Just update the
* data
*/
hit = 1;
strcpy(headPtr->hmDiskAliasName,alias);
sprintf(headPtr->hmAvgWaitTransactions, "%3.1f\0", w_pct);
sprintf(headPtr->hmDiskBusyPcnt, "%3.1f\0", r_pct);
sprintf(headPtr->hmAvgDiskSvcTime, "%3.1f\0", serv);
/*
* Don't change the hmDiskState here because existing
* diskState should be maintained
*/
headPtr->hmTraversed=1;
}
headPtr = headPtr->pNext;
} /* End of while loop around each row */
if (hit != 1) {
/* A new Disk is found in this refresh cycle . How likely ? */
ptr = (hmDiskTable *) malloc(sizeof(hmDiskTable));
ptr->hmDiskName = (char *) malloc(strlen(name) + 1);
ptr->hmDiskAliasName = (char *) malloc(strlen(alias) + 1);
ptr->hmAvgWaitTransactions = (char *) malloc(DISK_DATA_LEN);
ptr->hmDiskBusyPcnt = (char *) malloc(DISK_DATA_LEN);
ptr->hmAvgDiskSvcTime = (char *) malloc(DISK_DATA_LEN);
if ( ptr->hmAvgDiskSvcTime == NULL) {
snmp_log(LOG_DEBUG,"malloc failed when refreshing DISK table in health monitor module \n");
return;
}
strcpy(ptr->hmDiskName,name);
strcpy(ptr->hmDiskAliasName,alias);
sprintf(ptr->hmAvgWaitTransactions, "%3.1f\0", w_pct);
sprintf(ptr->hmDiskBusyPcnt, "%3.1f\0", r_pct);
sprintf(ptr->hmAvgDiskSvcTime, "%3.1f\0", serv);
/* Set the state of Disk to OK. */
ptr->hmDiskState = OK;
/* Set Traversed to 1 */
ptr->hmTraversed=1;
ptr->pNext = NULL;
if (tailPtr == NULL) {
head = tailPtr = ptr;
} else {
tailPtr->pNext = ptr;
tailPtr = ptr;
}
}
diskCount++;
} while (code == 0);
/* Any disk that is not "touched" previously (i.e, has
* hmTraversal value of 0, means that it's a removed disk.
* Traverse through the whole list again and remove those
* entries from the list.
*/
p1=head;
p2=head;
while( p2 != NULL) {
if (p2->hmTraversed == 0) {
/* Take care of removing this disk */
if(p2->pNext != NULL) {
p1->pNext = p2->pNext;
free(p2);
p2=p1->pNext;
} else {
p1->pNext=NULL;
free(p2);
p2=NULL;
}
} else {
/* Extend pointers by 1 step */
if(p2->pNext != NULL) {
p1=p2;
p2=p2->pNext;
} else {
p2=p2->pNext;
}
}
}
check_state_DISK();
time(&hm_prev_disk_ref);
}
/*
* Function: refresh_all_HM_data. This function collects the data for all
* nodes in the module and stores the data in the data variables. The
* function is called every "refresh-interval" automatically. After the data
* is refreshed, the alarm condition is checked and a trap is sent if the
* conditions are met.
*/
void
refresh_all_HM_data(unsigned int clientreg, void *clientarg)
{
time_t hm_current_time;
/* Did the previous refresh really finish ??
* This means that previous refresh is still in progress */
if (hm_prev_ref_time == 0) return;
time(&hm_current_time);
/* Did the previous refresh finish too close to start another refresh ???
* This means that the previous refresh finished relatively closer to current time
* so, another refresh is not necessary. hm_prev_ref_time is initialized to 1
* during variable declaration. so, the first time refresh is called, it will always
* proceed.
*/
/* printf("%u %u %u\n",hm_current_time, hm_prev_ref_time, hm_refresh_interval/4);*/
if ( (hm_current_time - hm_prev_ref_time) < (hm_refresh_interval / 4) ) return;
/* set to 0 so that we can block any other refresh's */
hm_prev_ref_time = 0;
/* refresh data for SWAP nodes and check alarm condition */
refresh_SWAP_data();
hm_handle_rule(&SWAP_rule_state, &SWAP_rule);
/* Acquire data for Kernel nodes */
refresh_Kernel_data();
hm_handle_rule(&Kernel_rule_state, &Kernel_rule);
/* Acquire data for NFS nodes */
refresh_NFS_data();
hm_handle_rule(&NFS_rule_state, &NFS_rule);
/* Acquire data for CPU nodes */
refresh_CPU_data();
hm_handle_rule(&CPU_rule_state, &CPU_rule);
/* Acquire data for RAM nodes */
refresh_RAM_data();
hm_handle_rule(&RAM_rule_state, &RAM_rule);
/* Acquire data for KMEM nodes */
refresh_KMEM_data();
hm_handle_rule(&KMEM_rule_state, &KMEM_rule);
/* Acquire data for DNLC nodes */
refresh_DNLC_data();
hm_handle_rule(&DNLC_rule_state, &DNLC_rule);
/* End of Data acquisition for HM module */
time(&hm_prev_ref_time);
return;
}
/*
* Function: read_health_monitor_thresholds: This function is called whenever
* a registered token is encountered in health_monitor.conf file. The
* function simply stores the token's value in the appropriate threshold
* variable.
*/
void
read_health_monitor_thresholds(const char *token, char *cptr)
{
if (strcmp(token, "hm_refresh_interval") == 0) {
hm_refresh_interval = atoi(cptr);
} else if (strcmp(token, "threshold_swapavail_info") == 0) {
threshold_swapavail_info = atoi(cptr);
} else if (strcmp(token, "threshold_swapavail_warning") == 0) {
threshold_swapavail_warning = atoi(cptr);
} else if (strcmp(token, "threshold_swapavail_error") == 0) {
threshold_swapavail_error = atoi(cptr);
} else if (strcmp(token, "threshold_mutex_info") == 0) {
threshold_mutex_info = atol(cptr);
} else if (strcmp(token, "threshold_mutex_warning") == 0) {
threshold_mutex_warning = atol(cptr);
} else if (strcmp(token, "threshold_mincalls") == 0) {
threshold_mincalls = atof(cptr);
} else if (strcmp(token, "threshold_badxids") == 0) {
threshold_badxids = atof(cptr);
} else if (strcmp(token, "threshold_timeouts") == 0) {
threshold_timeouts = atof(cptr);
} else if (strcmp(token, "threshold_cpuload_info") == 0) {
threshold_cpuload_info = atof(cptr);
} else if (strcmp(token, "threshold_cpuload_warning") == 0) {
threshold_cpuload_warning = atof(cptr);
} else if (strcmp(token, "threshold_cpuload_error") == 0) {
threshold_cpuload_error = atof(cptr);
} else if (strcmp(token, "threshold_restime_long") == 0) {
threshold_restime_long = atoi(cptr);
} else if (strcmp(token, "threshold_restime_ok") == 0) {
threshold_restime_ok = atoi(cptr);
} else if (strcmp(token, "threshold_restime_error") == 0) {
threshold_restime_error = atoi(cptr);
} else if (strcmp(token, "threshold_freemem_low") == 0) {
threshold_freemem_low = atoi(cptr);
} else if (strcmp(token, "threshold_dnlc_active") == 0) {
threshold_dnlc_active = atof(cptr);
} else if (strcmp(token, "threshold_dnlc_warning") == 0) {
threshold_dnlc_warning = atof(cptr);
} else if (strcmp(token, "disk_busy_warning") == 0) {
disk_busy_warning = atol(cptr);
} else if (strcmp(token, "disk_busy_problem") == 0) {
disk_busy_problem = atol(cptr);
} else if (strcmp(token, "disk_svc_t_warning") == 0) {
disk_svc_t_warning = atol(cptr);
} else if (strcmp(token, "disk_svc_t_problem") == 0) {
disk_svc_t_problem = atol(cptr);
} else {
/* Do nothing */
}
return;
}
/*
* hm_handle_rule:
*
* arguments: rule_state = previous state of the rule rule = Function
* pointer to the actual rule
*
* This function first determines the new state of the rule by calling
* rule(CONDITION).
*
* In the switch loop, depending on the previous rule state (the rule_state) and
* new state, the rule function is again called appropriately. For example,
* if the previous state is INIT and the new state is > OK, then rule(OPEN)
* is called.
*
*/
void
hm_handle_rule(int *rule_state, int (*rule) (int))
{
int new_alarm_state;
if (*rule_state == NOTINIT) {
*rule_state = INIT;
rule(INIT);
}
new_alarm_state = rule(CONDITION);
switch (*rule_state) {
case INIT:
if (new_alarm_state > OK) {
*rule_state = OPEN;
rule(OPEN);
}
return;
case OPEN:
if (new_alarm_state == OK) {
*rule_state = CLOSE;
rule(CLOSE);
} else {
*rule_state = CONTINUE;
rule(CONTINUE);
}
return;
case CONTINUE:
if (new_alarm_state == OK) {
*rule_state = CLOSE;
rule(CLOSE);
} else {
*rule_state = CONTINUE;
rule(CONTINUE);
}
return;
case CLOSE:
if (new_alarm_state > OK) {
*rule_state = OPEN;
rule(OPEN);
}
return;
}
}
/*
* Function: send_trap : This function sends a *statusChange* trap with
* appropriate varbind's see SMA trap mib for detailed trap notification
* definition.
*
* hostname - Name of host on which alarm occured ; modulename - Name of the
* module generating the trap ; moduleContext - The context of the module, if
* any; statusOID - The trapoid; size - The size of trapoid (not included in
* the trap); status - status of the node; description - description of the
* trap; dvalue - value of the node on which trap occured; dtype - data type of
* the value
*/
void
send_trap(u_char * hostname, u_char * modulename, u_char * moduleContext, oid * trapoid, int size, u_char * status, u_char * description, u_char * dvalue, int dtype)
{
/* This is the notification type itself. This is statusChange trap */
oid notification_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 0, 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, 3, 1, 1, 0};
size_t hostname_oid_len = OID_LENGTH(hostname_oid);
oid modulename_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 2, 0};
size_t modulename_oid_len = OID_LENGTH(modulename_oid);
oid nodeoid_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 3, 0};
size_t nodeoid_oid_len = OID_LENGTH(nodeoid_oid);
oid moduleContext_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 4, 0};
size_t moduleContext_oid_len = OID_LENGTH(moduleContext_oid);
oid status_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 5, 0};
size_t status_oid_len = OID_LENGTH(status_oid);
oid description_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 6, 0};
size_t description_oid_len = OID_LENGTH(description_oid);
oid dvalue_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 7, 0};
size_t dvalue_oid_len = OID_LENGTH(dvalue_oid);
oid dtype_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 8, 0};
size_t dtype_oid_len = OID_LENGTH(dtype_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,
moduleContext_oid, moduleContext_oid_len,
/*
* value type is an OID
*/
ASN_OCTET_STR,
/*
* value contents is our notification OID
*/
(u_char *) moduleContext,
/*
* size in bytes = oid length * sizeof(oid)
*/
strlen((char *) moduleContext));
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));
snmp_varlist_add_variable(&notification_vars,
dvalue_oid, dvalue_oid_len,
/*
* value type is an OID
*/
ASN_OCTET_STR,
/*
* value contents is our notification OID
*/
(u_char *) dvalue,
/*
* size in bytes = oid length * sizeof(oid)
*/
strlen((char *) dvalue));
snmp_varlist_add_variable(&notification_vars,
dtype_oid, dtype_oid_len,
/*
* value type is an OID
*/
ASN_INTEGER,
/*
* value contents is our notification OID
*/
(u_char *) & dtype,
/*
* size in bytes = oid length * sizeof(oid)
*/
sizeof(dtype));
/* 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;
}
/*
* Function: conv_alarm_state : This function returns appropriate charecter
* string for each integer alarm type
*/
char *
conv_alarm_state(int state)
{
switch (state) {
case OK:
return "OK\0";
case INFO:
return "INFO\0";
case WARNING:
return "WARNING\0";
case ERROR:
return "ERROR\0";
default:
return "INVALID\0";
}
}
/*
* Function: SWAP_rule : This function checks the state of SWAP nodes and
* issues trap if necessary
*/
int
SWAP_rule(int action)
{
/* This is the OID of hmAvailableSwapSpace */
oid trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 1, 1, 1, 0};
u_char status[8];
u_char description[] = "Available Swap space on the system is low";
int size;
u_char dvalue[15];
/* The value of dtype is 1 here becuase swapavail_data is of "int" type */
int dtype = 1;
sprintf((char *) dvalue, "%d\0", swapavail_data);
size = sizeof(trapoid) / sizeof(oid);
switch (action) {
case CONDITION:
/*
* Quite straightforward. Depending on the threshold that is crossed,
* assign the new state
*/
if ((swapavail_data <= threshold_swapavail_info) && (swapavail_data > threshold_swapavail_warning)) {
new_SWAP_state = INFO;
return INFO;
} else if ((swapavail_data <= threshold_swapavail_warning) && (swapavail_data > threshold_swapavail_error)) {
new_SWAP_state = WARNING;
return WARNING;
} else if (swapavail_data <= threshold_swapavail_error) {
new_SWAP_state = ERROR;
return ERROR;
}
new_SWAP_state = OK;
return OK;
case OPEN:
strcpy((char *) status, conv_alarm_state(new_SWAP_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
return 0;
case CONTINUE:
strcpy((char *) status, conv_alarm_state(new_SWAP_state));
if (new_SWAP_state > prev_SWAP_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
prev_SWAP_state = new_SWAP_state;
}
return 0;
case CLOSE:
strcpy((char *) status, conv_alarm_state(new_SWAP_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
default:
return 0;
}
}
/*
* Function: Kernel_rule : This function checks the state of Kernel nodes and
* issues trap if necessary
*/
int
Kernel_rule(int action)
{
int mutexrate;
/* This is the OID of hmSpinsOnMutexes */
oid trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 2, 1, 1, 0};
u_char status[8];
u_char description[] = "Mutex contention rate is high , kernel overload \0";
int size;
u_char dvalue[15];
/*
* dtype is set to 1 because the hmSpinsOnMutexes node is defined as
* Integer32 in the mib
*/
int dtype = 1;
sprintf((char *) dvalue, "%lu\0", sum_smtx);
size = sizeof(trapoid) / sizeof(oid);
switch (action) {
case CONDITION:
if (ncpus == 0) {
/* this happens only during initialization */
new_mutex_state = OK;
return OK;
}
mutexrate = sum_smtx / ncpus;
/* Determine if there is a new Alarm state */
if (mutexrate < threshold_mutex_info) {
if (mutexrate == 0) {
/*
* This is a change from existing rule. It makes more sense
* that if mutexrate is 0, then the state should be OK. i.e,
* no problems
*/
new_mutex_state = OK;
return OK;
} else {
new_mutex_state = INFO;
return INFO;
}
} else if (mutexrate < threshold_mutex_warning) {
new_mutex_state = WARNING;
return WARNING;
} else {
new_mutex_state = ERROR;
return WARNING;
}
case OPEN:
strcpy((char *) status, conv_alarm_state(new_mutex_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
return 0;
case CONTINUE:
strcpy((char *) status, conv_alarm_state(new_mutex_state));
if (new_mutex_state > prev_mutex_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
prev_mutex_state = new_mutex_state;
}
return 0;
case CLOSE:
strcpy((char *) status, conv_alarm_state(new_mutex_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
default:
return 0;
}
}
/*
* Function: NFS_rule : This function checks the state of NFS nodes and
* issues trap if necessary
*/
int
NFS_rule(int action)
{
float maxtimeout, maxbadxid;
/*
* This is the OID of hmNFSClientRPCGroup. Note that this rule uses data
* from more than one node to determine the alarm state
*/
oid trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1};
u_char status[8];
u_char description[] = "Bad Network or Server is slow. May need to increase timeout \0 ";
int size;
u_char dvalue[15];
int dtype = 1;
/*
* It's tricky which "value" should be put in dvalue field. More than one
* node's data is looked at to determine alarm state.
*/
sprintf((char *) dvalue, "%d\0", timeouts);
size = sizeof(trapoid) / sizeof(oid);
switch (action) {
case CONDITION:
if (calls <= threshold_mincalls) {
/*
* This is a change from existing rule (which has INFO). It makes
* sense that no trap is sent when calls is < threshold_mincalls.
*/
new_NFS_state = OK;
return OK;
} else {
maxtimeout = threshold_timeouts * calls / 100.0;
if (timeouts < maxtimeout) {
/*
* This is a change from existing rule (which has INFO). It
* makes sense that no trap is sent when timeouts is <
* maxtimeout
*/
new_NFS_state = OK;
return OK;
} else {
maxbadxid = threshold_badxids * timeouts / 100.0;
if ((maxtimeout <= timeouts) && (badxids <= maxbadxid)) {
new_NFS_state = WARNING;
return WARNING;
} else {
/*
* This will be the case when timeout >= maxtimeout AND
* badxids > maxbadxid
*/
new_NFS_state = ERROR;
return ERROR;
}
}
}
case OPEN:
strcpy((char *) status, conv_alarm_state(new_NFS_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
return 0;
case CONTINUE:
strcpy((char *) status, conv_alarm_state(new_NFS_state));
if (new_NFS_state > prev_NFS_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
prev_NFS_state = new_NFS_state;
}
return 0;
case CLOSE:
strcpy((char *) status, conv_alarm_state(new_NFS_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
default:
return 0;
}
}
/*
* Function: CPU_rule : This function checks the state of CPU nodes and
* issues trap if necessary
*/
int
CPU_rule(int action)
{
/* This is the OID for hmTotProcInRunQueue */
oid trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 4, 1, 1, 0};
u_char status[8];
u_char description[] = "CPU overloaded \0";
int size;
u_char dvalue[15];
/* dtype is given a value of 1 because runque is of "int" type */
int dtype = 1;
float cpuload;
sprintf((char *) dvalue, "%d\0", runque);
size = sizeof(trapoid) / sizeof(oid);
switch (action) {
case CONDITION:
/*
* Added this If statement to existing rule. From Kernel_rule, it
* looks like ncpus may be 0 during initialization
*/
if (ncpus == 0) {
/* this happens only during initialization */
new_cpuload_state = OK;
return OK;
}
cpuload = runque / ncpus;
/*
* Quite straightforward. If the threshold is crossed, set the state
* accordingly
*/
if (cpuload < threshold_cpuload_info) {
new_cpuload_state = OK;
return OK;
} else if (cpuload < threshold_cpuload_warning) {
new_cpuload_state = INFO;
return INFO;
} else if (cpuload < threshold_cpuload_error) {
new_cpuload_state = WARNING;
return WARNING;
} else {
new_cpuload_state = ERROR;
return ERROR;
}
case OPEN:
strcpy((char *) status, conv_alarm_state(new_cpuload_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
return 0;
case CONTINUE:
strcpy((char *) status, conv_alarm_state(new_cpuload_state));
if (new_cpuload_state > prev_cpuload_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
prev_cpuload_state = new_cpuload_state;
}
return 0;
case CLOSE:
strcpy((char *) status, conv_alarm_state(new_cpuload_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
default:
return 0;
}
}
/*
* Function: RAM_rule : This function checks the state of RAM nodes and
* issues trap if necessary
*/
int
RAM_rule(int action)
{
/*
* This is the OID of hmRamMemoryPagingGroup. Note that this rule uses
* data from more than one node to determine the alarm state
*/
oid trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 6, 1};
u_char status[8];
u_char description[] = "RAM shortage \0";
int size;
u_char dvalue[15];
/* dtype is given a value of 1 because scan is of "int" type */
int dtype = 1;
float restime;
/*
* It's tricky which "value" should be put in dvalue field. More than one
* node's data is looked at to determine alarm state.
*/
sprintf((char *) dvalue, "%d\0", scan);
size = sizeof(trapoid) / sizeof(oid);
switch (action) {
case CONDITION:
if (scan == 0) {
restime = threshold_restime_long;
} else {
restime = handspread / scan;
}
if (restime > threshold_restime_long) {
restime = threshold_restime_long;
}
if (restime >= threshold_restime_long) {
/* This is a change from existing rule (which has INFO). */
new_restime_state = OK;
return OK;
} else {
if (restime > threshold_restime_ok) {
new_restime_state = INFO;
return INFO;
} else {
if (restime > threshold_restime_error) {
new_restime_state = WARNING;
return WARNING;
} else {
new_restime_state = ERROR;
return ERROR;
}
}
}
case OPEN:
strcpy((char *) status, conv_alarm_state(new_restime_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
return 0;
case CONTINUE:
strcpy((char *) status, conv_alarm_state(new_restime_state));
if (new_restime_state > prev_restime_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
prev_restime_state = new_restime_state;
}
return 0;
case CLOSE:
strcpy((char *) status, conv_alarm_state(new_restime_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
default:
return 0;
}
}
/*
* Function: KMEM_rule : This function checks the state of KMEM nodes and
* issues trap if necessary
*/
int
KMEM_rule(int action)
{
/*
* This is the OID of hmKmemStatisticsGroup. Note that this rule uses
* data from more than one node to determine the alarm state
*/
oid trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 7, 1};
u_char status[8];
u_char description[] = "Kernel Memory allocation errors \0";
int size;
u_char dvalue[15];
/* dtype is given a value of 1 because alloc_fail is of "int" type */
int dtype = 1;
int firsterrs, lasterrs;
/*
* It's tricky which "value" should be put in dvalue field. More than one
* node's data is looked at to determine alarm state.
*/
sprintf((char *) dvalue, "%d\0", alloc_fail);
size = sizeof(trapoid) / sizeof(oid);
switch (action) {
case CONDITION:
/* This is a slightly confusing rule */
firsterrs = firstkmemerrs;
lasterrs = lastkmemerrs;
if (alloc_fail == firsterrs) {
if (alloc_fail == 0) {
/*
* This is a change from existing rule (which has INFO). It
* makes sense that an OK state should be returned when
* alloc_fail is 0
*/
new_kmem_state = OK;
return OK;
} else {
new_kmem_state = INFO;
return INFO;
}
} else {
if (alloc_fail == lasterrs) {
new_kmem_state = WARNING;
return WARNING;
} else {
new_kmem_state = ERROR;
lastkmemerrs = alloc_fail;
if (mem_free > threshold_freemem_low) {
/*
* Kernel memory allocation problem. The state is already
* set to ERROR.
*/
} else {
/*
* Kernel memory allocation problem. The state is already
* set to ERROR.
*/
}
return ERROR;
}
}
case OPEN:
firstkmemerrs = alloc_fail;
lastkmemerrs = alloc_fail;
strcpy((char *) status, conv_alarm_state(new_kmem_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
firstkmemerrs = 0;
lastkmemerrs = 0;
return 0;
case CONTINUE:
strcpy((char *) status, conv_alarm_state(new_kmem_state));
if (new_kmem_state > prev_kmem_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
prev_kmem_state = new_kmem_state;
}
return 0;
case CLOSE:
strcpy((char *) status, conv_alarm_state(new_kmem_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
default:
return 0;
}
}
/*
* Function: DNLC_rule : This function checks the state of DNLC nodes and
* issues trap if necessary
*/
int
DNLC_rule(int action)
{
/* This is the OID for hmDNLCStatGroup */
oid trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 8, 1};
u_char status[8];
u_char description[] = "Poor DNLC Hit rate \0";
int size;
u_char dvalue[15];
/* dtype is given a value of 1 because hitrate is of "int" type */
int dtype = 1;
/*
* It's tricky which "value" should be put in dvalue field. More than one
* node's data is looked at to determine alarm state.
*/
sprintf((char *) dvalue, "%d\0", hitrate);
size = sizeof(trapoid) / sizeof(oid);
switch (action) {
case CONDITION:
/*
* Changed the rule from existing rule. Used OK instead of INFO when
* there is no problem
*/
if (refrate < threshold_dnlc_active) {
new_dnlc_state = OK;
return OK;
} else {
if (hitrate > threshold_dnlc_warning) {
new_dnlc_state = OK;
return OK;
} else {
new_dnlc_state = WARNING;
return WARNING;
}
}
case OPEN:
strcpy((char *) status, conv_alarm_state(new_dnlc_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
return 0;
case CONTINUE:
strcpy((char *) status, conv_alarm_state(new_dnlc_state));
if (new_dnlc_state > prev_dnlc_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
prev_dnlc_state = new_dnlc_state;
}
return 0;
case CLOSE:
strcpy((char *) status, conv_alarm_state(new_dnlc_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
default:
return 0;
}
}
void
check_state_DISK()
{
/* TRAP STUFF */
oid *trapoid;
u_char status[8];
u_char description[] = "Disk Loaded \0";
/*
* A value of 12 is given to dtype because the diskName is of
* "DisplayString" type. Disk Name is used for dvalue because multiple
* values are used to determine trap state. No single value can be used
*/
int dtype = 12;
/* Maintain a pointer to diskTable called headPtr */
hmDiskTable *headPtr;
int nameSize;
headPtr = head;
/* For each row in the table, determine if there is a new Alarm Condition */
while (headPtr != NULL) {
/* For each disk, set the new state back to OK again */
int new_disk_state = OK;
int i;
long wait = atol(headPtr->hmAvgWaitTransactions);
long svcTime = atol(headPtr->hmAvgDiskSvcTime);
long busyTime = atol(headPtr->hmDiskBusyPcnt);
/* For cases where busyTime < disk_busy_warning, svcTime < disk_svc_t_warning,
state is set to OK instead of INFO (as in existing rule);
*/
if (busyTime < disk_busy_warning) {
new_disk_state = OK;
} else {
if (svcTime < disk_svc_t_warning) {
new_disk_state = OK;
} else {
if (disk_busy_problem <= busyTime) {
if ((disk_svc_t_warning <= svcTime) && (svcTime < disk_svc_t_problem)) {
new_disk_state = WARNING;
} else {
if (disk_svc_t_problem <= svcTime) {
new_disk_state = ERROR;
}
}
} else {
new_disk_state = WARNING;
}
}
}
nameSize = strlen(headPtr->hmDiskName);
/*
* Compose the trap OID here. It is:
* 1.3.6.1.4.1.42.2.12.2.2.11.5.1.1.1.<size-of-index>.index
*/
trapoid = malloc((16 * sizeof(oid)) + sizeof(oid) + (nameSize * sizeof(oid)));
if ( trapoid == NULL) {
snmp_log(LOG_DEBUG,"malloc failed when constructing trapoid in health monitor module \n");
return;
}
trapoid[0] = 1;
trapoid[1] = 3;
trapoid[2] = 6;
trapoid[3] = 1;
trapoid[4] = 4;
trapoid[5] = 1;
trapoid[6] = 42;
trapoid[7] = 2;
trapoid[8] = 12;
trapoid[9] = 2;
trapoid[10] = 2;
trapoid[11] = 11;
trapoid[12] = 5;
trapoid[13] = 1;
trapoid[14] = 1;
trapoid[15] = 1;
trapoid[16] = nameSize;
for (i = 1; i <= nameSize; i++) {
trapoid[16 + i] = headPtr->hmDiskName[i - 1];
}
/* Depending on the new state, send trap if necessary */
if (new_disk_state > headPtr->hmDiskState) {
/* Send trap */
strcpy((char *) status, conv_alarm_state(new_disk_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, 17 + nameSize, status, description, (u_char *) headPtr->hmDiskName, dtype);
headPtr->hmDiskState = new_disk_state;
} else if (new_disk_state == headPtr->hmDiskState) {
/* No Change in state .. Do nothing */
} else if (new_disk_state < headPtr->hmDiskState) {
if (new_disk_state == OK) {
/* Send OK trap */
strcpy((char *) status, conv_alarm_state(new_disk_state));
send_trap(hostName, moduleName, statusOIDContext, trapoid, 17 + nameSize, status, description, (u_char *) headPtr->hmDiskName, dtype);
headPtr->hmDiskState = OK;
}
}
headPtr = headPtr->pNext;
} /* End of while loop that traverses each row */
return;
}