diff -r f527656d334f -r ee0fb1eabcbf components/net-snmp/sun/agent/modules/healthMonitor/healthMonitor.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/components/net-snmp/sun/agent/modules/healthMonitor/healthMonitor.c Fri May 20 12:17:45 2011 +0530 @@ -0,0 +1,3388 @@ + +/* + * 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 +#include +#include +#include "healthMonitor.h" +#include + + +/* + * 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(¬ification_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(¬ification_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(¬ification_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(¬ification_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(¬ification_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(¬ification_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(¬ification_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(¬ification_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(¬ification_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..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; + +}