/*
*
* 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 "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 */
/* Data for Kernel node */
int ncpus;
/* Data for NFS node */
double calls;
/* Data for CPU node */
/* Data for RAM node */
/*
* Data for KMEM node . Only alloc_fail and mem_free are published through
* the MIB
*/
/*
* 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 lasthits = 0;
int lastmisses = 0;
int prevhits = 0;
int prevmisses = 0;
long prevtime = 0;
/*
* 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
*/
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 */
/* Thresholds for Kernel node */
/* Thresholds for NFS node */
/* Thresholds for CPU node */
/* Thresholds for RAM node */
/* Thresholds for KMEM node */
* variables and
* preserved across
* invocation of
* check_state_KMEM()
* function */
/* Thresholds for DNLC node */
/* Thresholds for diskGroup */
/* COMMON data variables */
/** Initializes the healthMonitor module */
void
init_healthMonitor(void)
{
int retCode;
("hmSpinsOnMutexes",
("hmTotProcInRunQueue",
("hmTotRPCCalls",
("hmUsedSwapSpace",
("hmDNLCMisses",
("hmReservedSwapSpace",
("hmTotMemAllocFails",
("hmAvailableSwapSpace",
("hmDNLCHitRate",
("hmDNLCHits",
("hmAllocatedSwapSpace",
("hmTotNumOfCPUs",
("hmPageScanRate",
("hmTimers",
("hmTotBadRPCCalls",
("hmDNLCRefRate",
("hmTotSendFails",
("hmTotFailedCallsBV",
("hmTotNumOfAuthRefresh",
("hmHandspread",
("hmTotRPCRetransmissions",
("hmKmemFreeMem",
("hmTotBadRPCReplies",
("hmKmemErrors",
("hmTotProcReadyInSwap",
("hmTotProcBlocked",
("hmTotRPCCallsTimedOut",
/* Initialize Disk stuff */
/* here we initialize all the tables we're planning on supporting */
/*
* 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
*/
/*
* Initialize data that's required in the trap - The hostname,
* modulenaem, statusOIDContext
*/
if (retCode != 0)
}
/** Initialize the hmDiskTable table by defining its contents and how it's structured */
void
{
/* create the table structure itself */
/*
* if your table is read only, it's easiest to change the
* HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY
*/
return; /* mallocs failed */
/***************************************************
* Setting up the table's definition
*/
ASN_OCTET_STR, /* index: hmDiskName */
0);
/* iterator access routines */
/***************************************************
* registering the table with the master agent
*/
DEBUGMSGTL(("initialize_table_hmDiskTable",
"Registering table hmDiskTable as a table iterator\n"));
}
int
{
/*
* 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.
*/
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
{
/*
* 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;
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
{
/*
* 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.
*/
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
{
/*
* 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;
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
{
/*
* 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.
*/
case MODE_GET:
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
{
/*
* 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;
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
{
/*
* 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;
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
{
/*
* 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 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
{
/*
* 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.
*/
case MODE_GET:
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
{
/*
* 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.
*/
case MODE_GET:
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
{
/*
* 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;
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
{
/*
* 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;
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
{
/*
* 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;
case MODE_GET:
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
{
/*
* 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;
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
{
/*
* 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;
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
{
/*
* 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.
*/
case MODE_GET:
break;
default:
/* we should never get here, so this is a really bad error */
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
int
{
/*
* 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;
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
{
/*
* 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;
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
{
/*
* 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;
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
{
/*
* 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;
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
{
/*
* 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;
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
{
/*
* 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;
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
{
/*
* 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;
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
{
/*
* 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;
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
{
/*
* 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;
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
{
/*
* 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;
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
{
/*
* 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;
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
*/
refresh_all_HM_data(0, NULL);
}
{
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.
*/
{
if (!firstNode) {
return NULL;
}
snmp_set_var_value(vptr, (u_char *) firstNode->hmDiskName, strlen(firstNode->hmDiskName) /* XXX: length of
hmDiskName data */ );
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. */
{
/* This check is not really required */
if(!nextNode) {
return NULL;
}
if (!nextNode) {
return NULL;
}
snmp_set_var_value(vptr, (u_char *) nextNode->hmDiskName /* XXX: hmDiskName data */ , strlen(nextNode->hmDiskName) /* XXX: length of
hmDiskName data */ );
return put_index_data;
}
/** handles requests for the hmDiskTable table, if anything else needs to be done */
int
{
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
*/
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->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;
}
/*
* 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;
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 */
}
break;
case MODE_SET_RESERVE1:
/* set handling... */
default:
}
}
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
{
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) {
swapavail_data = 0;
swapresv_data = 0;
swapalloc_data = 0;
swapused_data = 0;
}
}
void
{
int code = 0;
if (code != 0) {
sum_smtx = 0;
ncpus = 0;
}
}
void
{
int code = 0;
code = krgetclientrpcdetail(&calls, &badcalls, &retrans, &badxids, &timeouts, &newcreds, &badverfs, &timers, &nomem, &cantsend);
if (code != 0) {
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
*/
}
void
{
int code = 0;
if (code != 0) {
runque = 0;
waiting = 0;
swapque = 0;
}
}
void
{
int code = 0;
if (code != 0) {
handspread = 0;
scan = 0;
}
}
void
{
int code = 0;
/* 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)
if (code != 0) {
alloc_fail = 0;
mem_free = 0;
}
}
void
{
int code = 0;
long curtime;
if (code != 0) {
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;
lastmisses = misses;
} else {
}
prevmisses = misses;
if (refrate == 0) {
hitrate = 100;
} else {
}
}
}
void
{
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 {
return;
}
if (code < 0) {
/* Error occured during kstat read */
return;
}
if (code < 0) {
/* Error occured during kstat read */
return;
}
/* Allocate required memory to hold each disk data. */
return;
}
/* Set the state of Disk to OK. */
diskCount++;
} else {
}
/* code is set to value 0 if there is more disk information */
} while (code == 0);
/* set the time of first refresh */
}
void
{
int code = 0;
/* Did the previous refresh really finish ??
* This means that previous refresh is still in progress */
if (hm_prev_disk_ref == 0) return;
/* 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.
*/
/* 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->hmTraversed=0;
}
do {
int hit = 0;
if (code < 0) {
/* Error occured during kstat read */
return;
}
if (code < 0) {
/* Error occured during kstat read */
return;
}
/* For each row in the table, refresh the data */
/*
* This Disk is already part of the list. Just update the
* data
*/
hit = 1;
/*
* Don't change the hmDiskState here because existing
* diskState should be maintained
*/
}
} /* End of while loop around each row */
if (hit != 1) {
/* A new Disk is found in this refresh cycle . How likely ? */
return;
}
/* Set the state of Disk to OK. */
/* Set Traversed to 1 */
} else {
}
}
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.
*/
if (p2->hmTraversed == 0) {
/* Take care of removing this disk */
} else {
}
} else {
/* Extend pointers by 1 step */
} else {
}
}
}
}
/*
* 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
{
/* Did the previous refresh really finish ??
* This means that previous refresh is still in progress */
if (hm_prev_ref_time == 0) return;
/* 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);*/
/* 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 */
/* Acquire data for Kernel nodes */
/* Acquire data for NFS nodes */
/* Acquire data for CPU nodes */
/* Acquire data for RAM nodes */
/* Acquire data for KMEM nodes */
/* Acquire data for DNLC nodes */
/* End of Data acquisition for HM module */
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
{
} 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
{
int new_alarm_state;
if (*rule_state == NOTINIT) {
*rule_state = INIT;
}
switch (*rule_state) {
case INIT:
if (new_alarm_state > OK) {
*rule_state = OPEN;
}
return;
case OPEN:
if (new_alarm_state == OK) {
*rule_state = CLOSE;
} else {
*rule_state = CONTINUE;
}
return;
case CONTINUE:
if (new_alarm_state == OK) {
*rule_state = CLOSE;
} else {
*rule_state = CONTINUE;
}
return;
case CLOSE:
if (new_alarm_state > OK) {
*rule_state = 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 */
/*
* In the notification, we have to assign our notification OID to the
* snmpTrapOID.0 object. Here is it's definition.
*/
/*
* here is where we store the variables to be sent in the trap
*/
/*
* add in the trap definition object
*/
/*
* the snmpTrapOID.0 variable
*/
/*
* value type is an OID
*/
/*
* 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
*/
/*
* value type is an OID
*/
/*
* value contents is our notification OID
*/
/*
* size in bytes = oid length * sizeof(oid)
*/
/*
* value type is an OID
*/
/*
* value contents is our notification OID
*/
(u_char *) modulename,
/*
* size in bytes = oid length * sizeof(oid)
*/
strlen((char *) modulename));
/*
* value type is an OID
*/
/*
* value contents is our notification OID
*/
/*
* size in bytes = oid length * sizeof(oid)
*/
/*
* value type is an OID
*/
/*
* value contents is our notification OID
*/
(u_char *) moduleContext,
/*
* size in bytes = oid length * sizeof(oid)
*/
strlen((char *) moduleContext));
/*
* value type is an OID
*/
/*
* value contents is our notification OID
*/
/*
* size in bytes = oid length * sizeof(oid)
*/
/*
* value type is an OID
*/
/*
* value contents is our notification OID
*/
(u_char *) description,
/*
* size in bytes = oid length * sizeof(oid)
*/
strlen((char *) description));
/*
* value type is an OID
*/
/*
* value contents is our notification OID
*/
/*
* size in bytes = oid length * sizeof(oid)
*/
/*
* value type is an OID
*/
/*
* value contents is our notification OID
*/
/*
* size in bytes = oid length * sizeof(oid)
*/
sizeof(dtype));
/* SEND THE TRAP !!!! */
/*
* free the created notification variable list
*/
return;
}
/*
* Function: conv_alarm_state : This function returns appropriate charecter
* string for each integer alarm type
*/
char *
{
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
{
/* This is the OID of hmAvailableSwapSpace */
int size;
/* The value of dtype is 1 here becuase swapavail_data is of "int" type */
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)) {
return INFO;
} else if ((swapavail_data <= threshold_swapavail_warning) && (swapavail_data > threshold_swapavail_error)) {
return WARNING;
} else if (swapavail_data <= threshold_swapavail_error) {
return ERROR;
}
new_SWAP_state = OK;
return OK;
case OPEN:
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
return 0;
case CONTINUE:
if (new_SWAP_state > prev_SWAP_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
}
return 0;
case CLOSE:
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
{
int mutexrate;
/* This is the OID of hmSpinsOnMutexes */
int size;
/*
* dtype is set to 1 because the hmSpinsOnMutexes node is defined as
* Integer32 in the mib
*/
switch (action) {
case CONDITION:
if (ncpus == 0) {
/* this happens only during initialization */
return OK;
}
/* 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
*/
return OK;
} else {
return INFO;
}
} else if (mutexrate < threshold_mutex_warning) {
return WARNING;
} else {
return WARNING;
}
case OPEN:
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
return 0;
case CONTINUE:
if (new_mutex_state > prev_mutex_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
}
return 0;
case CLOSE:
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
{
/*
* This is the OID of hmNFSClientRPCGroup. Note that this rule uses data
* from more than one node to determine the alarm state
*/
int size;
/*
* It's tricky which "value" should be put in dvalue field. More than one
* node's data is looked at to determine alarm state.
*/
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 {
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 {
return WARNING;
} else {
/*
* This will be the case when timeout >= maxtimeout AND
* badxids > maxbadxid
*/
return ERROR;
}
}
}
case OPEN:
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
return 0;
case CONTINUE:
if (new_NFS_state > prev_NFS_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
}
return 0;
case CLOSE:
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
{
/* This is the OID for hmTotProcInRunQueue */
int size;
/* dtype is given a value of 1 because runque is of "int" type */
float cpuload;
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 */
return OK;
}
/*
* Quite straightforward. If the threshold is crossed, set the state
* accordingly
*/
if (cpuload < threshold_cpuload_info) {
return OK;
} else if (cpuload < threshold_cpuload_warning) {
return INFO;
} else if (cpuload < threshold_cpuload_error) {
return WARNING;
} else {
return ERROR;
}
case OPEN:
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
return 0;
case CONTINUE:
if (new_cpuload_state > prev_cpuload_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
}
return 0;
case CLOSE:
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
{
/*
* This is the OID of hmRamMemoryPagingGroup. Note that this rule uses
* data from more than one node to determine the alarm state
*/
int size;
/* dtype is given a value of 1 because scan is of "int" type */
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.
*/
switch (action) {
case CONDITION:
if (scan == 0) {
} else {
}
if (restime > threshold_restime_long) {
}
if (restime >= threshold_restime_long) {
/* This is a change from existing rule (which has INFO). */
return OK;
} else {
if (restime > threshold_restime_ok) {
return INFO;
} else {
if (restime > threshold_restime_error) {
return WARNING;
} else {
return ERROR;
}
}
}
case OPEN:
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
return 0;
case CONTINUE:
if (new_restime_state > prev_restime_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
}
return 0;
case CLOSE:
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
{
/*
* This is the OID of hmKmemStatisticsGroup. Note that this rule uses
* data from more than one node to determine the alarm state
*/
int size;
/* dtype is given a value of 1 because alloc_fail is of "int" type */
/*
* It's tricky which "value" should be put in dvalue field. More than one
* node's data is looked at to determine alarm state.
*/
switch (action) {
case CONDITION:
/* This is a slightly confusing rule */
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 {
return INFO;
}
} else {
if (alloc_fail == lasterrs) {
return WARNING;
} else {
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:
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
firstkmemerrs = 0;
lastkmemerrs = 0;
return 0;
case CONTINUE:
if (new_kmem_state > prev_kmem_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
}
return 0;
case CLOSE:
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
{
/* This is the OID for hmDNLCStatGroup */
int size;
/* dtype is given a value of 1 because hitrate is of "int" type */
/*
* It's tricky which "value" should be put in dvalue field. More than one
* node's data is looked at to determine alarm state.
*/
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 {
return WARNING;
}
}
case OPEN:
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
case INIT:
return 0;
case CONTINUE:
if (new_dnlc_state > prev_dnlc_state) {
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
}
return 0;
case CLOSE:
send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
return 0;
default:
return 0;
}
}
void
{
/* TRAP STUFF */
/*
* 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
*/
/* Maintain a pointer to diskTable called headPtr */
int nameSize;
/* For each row in the table, determine if there is a new Alarm Condition */
/* For each disk, set the new state back to OK again */
int i;
/* 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) {
} else {
if (disk_svc_t_problem <= svcTime) {
}
}
} else {
}
}
}
/*
* 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
*/
return;
}
trapoid[0] = 1;
for (i = 1; i <= nameSize; i++) {
}
/* Depending on the new state, send trap if necessary */
/* Send trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, 17 + nameSize, status, description, (u_char *) headPtr->hmDiskName, dtype);
/* No Change in state .. Do nothing */
if (new_disk_state == OK) {
/* Send OK trap */
send_trap(hostName, moduleName, statusOIDContext, trapoid, 17 + nameSize, status, description, (u_char *) headPtr->hmDiskName, dtype);
}
}
} /* End of while loop that traverses each row */
return;
}