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