Print this page
NEX-18417 bring back UUID-based OIDs for FM traps
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-17772 libfmd_snmp should learn about new FmProblem fields
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-16536 SUN-IREPORT-MIB is broken
NEX-16537 enhance FM traps
NEX-16545 SMF dict should have obsolete entries removed
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
Reviewed by: Alexander Eremin <alexander.eremin@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-14494 FMA related SNMP traps should add description
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>

@@ -21,28 +21,36 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
+/*
+ * Copyright 2018 Nexenta Systems, Inc.
+ */
+
 #include <sys/fm/protocol.h>
+
 #include <fm/fmd_snmp.h>
 #include <fm/fmd_msg.h>
 #include <fm/libfmevent.h>
+
 #include <net-snmp/net-snmp-config.h>
 #include <net-snmp/net-snmp-includes.h>
 #include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include <alloca.h>
 #include <errno.h>
+#include <limits.h>
 #include <locale.h>
 #include <netdb.h>
+#include <priv_utils.h>
 #include <signal.h>
-#include <strings.h>
 #include <stdlib.h>
+#include <strings.h>
 #include <unistd.h>
-#include <limits.h>
-#include <alloca.h>
-#include <priv_utils.h>
 #include <zone.h>
+
 #include "libfmnotify.h"
 
 /*
  * Debug messages can be enabled by setting the debug property to true
  *

@@ -49,21 +57,33 @@
  * # svccfg -s svc:/system/fm/snmp-notify setprop config/debug=true
  */
 #define SVCNAME         "system/fm/snmp-notify"
 
 typedef struct ireport_trap {
+        long long tstamp;
         char *host;
         char *msgid;
+        char *severity;
         char *desc;
-        long long tstamp;
         char *fmri;
         uint32_t from_state;
         uint32_t to_state;
         char *reason;
         boolean_t is_stn_event;
 } ireport_trap_t;
 
+typedef struct fmproblem_trap {
+        char *uuid;
+        char *host;
+        char *code;
+        char *type;
+        char *severity;
+        char *url;
+        char *descr;
+        char *fmri;
+} fmproblem_trap_t;
+
 static nd_hdl_t *nhdl;
 static const char optstr[] = "dfR:";
 static const char SNMP_SUPPCONF[] = "fmd-trapgen";
 static char hostname[MAXHOSTNAMELEN + 1];
 

@@ -163,10 +183,12 @@
 
         static const oid sunIreportHostname_oid[] =
             { SUNIREPORTHOSTNAME_OID };
         static const oid sunIreportMsgid_oid[] =
             { SUNIREPORTMSGID_OID };
+        static const oid sunIreportSeverity_oid[] =
+            { SUNIREPORTSEVERITY_OID };
         static const oid sunIreportDescription_oid[] =
             { SUNIREPORTDESCRIPTION_OID };
         static const oid sunIreportTime_oid[] =
             { SUNIREPORTTIME_OID };
 

@@ -179,12 +201,13 @@
         static const oid sunIreportSmfTransitionReason_oid[] =
             { SUNIREPORTTRANSITIONREASON_OID };
         const size_t
             sunIreport_base_len = OID_LENGTH(sunIreportHostname_oid);
 
+        size_t oid_len = sunIreport_base_len * sizeof (oid);
         size_t var_len = sunIreport_base_len + 1;
-        oid var_name[MAX_OID_LEN];
+        oid var_name[MAX_OID_LEN] = { 0 };
 
         netsnmp_variable_list *notification_vars = NULL;
 
         size_t dt_len;
         uchar_t dt[11], *tdt;

@@ -202,57 +225,52 @@
                 nd_error(nhdl, "var_len %d > MAX_OID_LEN %d\n", var_len,
                     MAX_OID_LEN);
                 return;
         }
 
-        (void) memcpy(var_name, sunIreportHostname_oid, sunIreport_base_len *
-            sizeof (oid));
+        (void) memcpy(var_name, sunIreportHostname_oid, oid_len);
         (void) snmp_varlist_add_variable(&notification_vars, var_name,
-            sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->host,
-            strlen(t->host));
+            var_len, ASN_OCTET_STR, (uchar_t *)t->host, strlen(t->host));
 
-        (void) memcpy(var_name, sunIreportMsgid_oid,
-            sunIreport_base_len * sizeof (oid));
+        (void) memcpy(var_name, sunIreportMsgid_oid, oid_len);
         (void) snmp_varlist_add_variable(&notification_vars, var_name,
-            sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->msgid,
-            strlen(t->msgid));
+            var_len, ASN_OCTET_STR, (uchar_t *)t->msgid, strlen(t->msgid));
 
-        (void) memcpy(var_name, sunIreportDescription_oid,
-            sunIreport_base_len * sizeof (oid));
+        (void) memcpy(var_name, sunIreportSeverity_oid, oid_len);
         (void) snmp_varlist_add_variable(&notification_vars, var_name,
-            sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->desc,
-            strlen(t->desc));
+            var_len, ASN_OCTET_STR, (uchar_t *)t->severity,
+            strlen(t->severity));
 
-        (void) memcpy(var_name, sunIreportTime_oid, sunIreport_base_len *
-            sizeof (oid));
+        (void) memcpy(var_name, sunIreportDescription_oid, oid_len);
         (void) snmp_varlist_add_variable(&notification_vars, var_name,
-            sunIreport_base_len + 1, ASN_OCTET_STR, dt, dt_len);
+            var_len, ASN_OCTET_STR, (uchar_t *)t->desc, strlen(t->desc));
 
+        (void) memcpy(var_name, sunIreportTime_oid, oid_len);
+        (void) snmp_varlist_add_variable(&notification_vars, var_name,
+            var_len, ASN_OCTET_STR, dt, dt_len);
+
         if (t->is_stn_event) {
-                (void) memcpy(var_name, sunIreportSmfFmri_oid,
-                    sunIreport_base_len * sizeof (oid));
+                (void) memcpy(var_name, sunIreportSmfFmri_oid, oid_len);
                 (void) snmp_varlist_add_variable(&notification_vars, var_name,
-                    sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->fmri,
+                    var_len, ASN_OCTET_STR, (uchar_t *)t->fmri,
                     strlen(t->fmri));
 
-                (void) memcpy(var_name, sunIreportSmfFromState_oid,
-                    sunIreport_base_len * sizeof (oid));
+                (void) memcpy(var_name, sunIreportSmfFromState_oid, oid_len);
                 (void) snmp_varlist_add_variable(&notification_vars, var_name,
-                    sunIreport_base_len + 1, ASN_INTEGER,
-                    (uchar_t *)&t->from_state, sizeof (uint32_t));
+                    var_len, ASN_INTEGER, (uchar_t *)&t->from_state,
+                    sizeof (uint32_t));
 
-                (void) memcpy(var_name, sunIreportSmfToState_oid,
-                    sunIreport_base_len * sizeof (oid));
+                (void) memcpy(var_name, sunIreportSmfToState_oid, oid_len);
                 (void) snmp_varlist_add_variable(&notification_vars, var_name,
-                    sunIreport_base_len + 1, ASN_INTEGER,
-                    (uchar_t *)&t->to_state, sizeof (uint32_t));
+                    var_len, ASN_INTEGER, (uchar_t *)&t->to_state,
+                    sizeof (uint32_t));
 
                 (void) memcpy(var_name, sunIreportSmfTransitionReason_oid,
-                    sunIreport_base_len * sizeof (oid));
+                    oid_len);
                 (void) snmp_varlist_add_variable(&notification_vars, var_name,
-                    sunIreport_base_len + 1, ASN_OCTET_STR,
-                    (uchar_t *)t->reason, strlen(t->reason));
+                    var_len, ASN_OCTET_STR, (uchar_t *)t->reason,
+                    strlen(t->reason));
         }
 
         /*
          * This function is capable of sending both v1 and v2/v3 traps.
          * Which is sent to a specific destination is determined by the

@@ -263,30 +281,39 @@
             (oid *)sunIreportTrap_oid, sunIreportTrap_len - 2,
             notification_vars);
         nd_debug(nhdl, "Sent SNMP trap for %s", t->msgid);
 
         snmp_free_varbind(notification_vars);
-
 }
 
-/*ARGSUSED*/
 static void
-send_fm_trap(const char *uuid, const char *code, const char *url)
+send_fm_trap(fmproblem_trap_t *t)
 {
         static const oid sunFmProblemTrap_oid[] = { SUNFMPROBLEMTRAP_OID };
         const size_t sunFmProblemTrap_len = OID_LENGTH(sunFmProblemTrap_oid);
 
         static const oid sunFmProblemUUID_oid[] =
             { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_UUID };
+        static const oid sunFmProblemHostname_oid[] =
+            { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_HOSTNAME };
         static const oid sunFmProblemCode_oid[] =
             { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_CODE };
+        static const oid sunFmProblemType_oid[] =
+            { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_TYPE };
+        static const oid sunFmProblemSeverity_oid[] =
+            { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_SEVERITY };
         static const oid sunFmProblemURL_oid[] =
             { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_URL };
+        static const oid sunFmProblemDescr_oid[] =
+            { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_DESC };
+        static const oid sunFmProblemFMRI_oid[] =
+            { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_FMRI };
 
         const size_t sunFmProblem_base_len = OID_LENGTH(sunFmProblemUUID_oid);
 
-        size_t uuid_len = strlen(uuid);
+        size_t oid_len = sunFmProblem_base_len * sizeof (oid);
+        size_t uuid_len = strlen(t->uuid);
         size_t var_len = sunFmProblem_base_len + 1 + uuid_len;
         oid var_name[MAX_OID_LEN];
 
         netsnmp_variable_list *notification_vars = NULL;
 

@@ -308,43 +335,65 @@
         if (var_len > MAX_OID_LEN)
                 return;
 
         var_name[sunFmProblem_base_len] = (oid)uuid_len;
         for (int i = 0; i < uuid_len; i++)
-                var_name[i + sunFmProblem_base_len + 1] = (oid)uuid[i];
+                var_name[i + sunFmProblem_base_len + 1] = (oid)t->uuid[i];
 
         /*
          * Ordinarily, we would need to add the OID of the trap itself
          * to the head of the variable list; this is required by SNMP v2.
          * However, send_enterprise_trap_vars does this for us as a part
          * of converting between v1 and v2 traps, so we skip directly to
          * the objects we're sending.
          */
 
-        (void) memcpy(var_name, sunFmProblemUUID_oid,
-            sunFmProblem_base_len * sizeof (oid));
+        (void) memcpy(var_name, sunFmProblemUUID_oid, oid_len);
         (void) snmp_varlist_add_variable(&notification_vars, var_name, var_len,
-            ASN_OCTET_STR, (uchar_t *)uuid, strlen(uuid));
-        (void) memcpy(var_name, sunFmProblemCode_oid,
-            sunFmProblem_base_len * sizeof (oid));
+            ASN_OCTET_STR, (uchar_t *)t->uuid, strlen(t->uuid));
+
+        (void) memcpy(var_name, sunFmProblemHostname_oid, oid_len);
         (void) snmp_varlist_add_variable(&notification_vars, var_name, var_len,
-            ASN_OCTET_STR, (uchar_t *)code, strlen(code));
-        (void) memcpy(var_name, sunFmProblemURL_oid,
-            sunFmProblem_base_len * sizeof (oid));
+            ASN_OCTET_STR, (uchar_t *)t->host, strlen(t->host));
+
+        (void) memcpy(var_name, sunFmProblemCode_oid, oid_len);
         (void) snmp_varlist_add_variable(&notification_vars, var_name, var_len,
-            ASN_OCTET_STR, (uchar_t *)url, strlen(url));
+            ASN_OCTET_STR, (uchar_t *)t->code, strlen(t->code));
 
+        (void) memcpy(var_name, sunFmProblemType_oid, oid_len);
+        (void) snmp_varlist_add_variable(&notification_vars, var_name, var_len,
+            ASN_OCTET_STR, (uchar_t *)t->type, strlen(t->type));
+
+        (void) memcpy(var_name, sunFmProblemSeverity_oid, oid_len);
+        (void) snmp_varlist_add_variable(&notification_vars, var_name, var_len,
+            ASN_OCTET_STR, (uchar_t *)t->severity, strlen(t->severity));
+
+        (void) memcpy(var_name, sunFmProblemURL_oid, oid_len);
+        (void) snmp_varlist_add_variable(&notification_vars, var_name, var_len,
+            ASN_OCTET_STR, (uchar_t *)t->url, strlen(t->url));
+
+        (void) memcpy(var_name, sunFmProblemDescr_oid, oid_len);
+        (void) snmp_varlist_add_variable(&notification_vars, var_name, var_len,
+            ASN_OCTET_STR, (uchar_t *)t->descr, strlen(t->descr));
+
+        if (strcmp(t->fmri, ND_UNKNOWN) != 0) {
+                (void) memcpy(var_name, sunFmProblemFMRI_oid, oid_len);
+                (void) snmp_varlist_add_variable(&notification_vars, var_name,
+                    var_len, ASN_OCTET_STR, (uchar_t *)t->fmri,
+                    strlen(t->fmri));
+        }
+
         /*
          * This function is capable of sending both v1 and v2/v3 traps.
          * Which is sent to a specific destination is determined by the
          * configuration file(s).
          */
         send_enterprise_trap_vars(SNMP_TRAP_ENTERPRISESPECIFIC,
             sunFmProblemTrap_oid[sunFmProblemTrap_len - 1],
             (oid *)sunFmProblemTrap_oid, sunFmProblemTrap_len - 2,
             notification_vars);
-        nd_debug(nhdl, "Sent SNMP trap for %s", code);
+        nd_debug(nhdl, "Sent SNMP trap for %s", t->code);
 
         snmp_free_varbind(notification_vars);
 }
 
 /*

@@ -353,11 +402,11 @@
  *
  * offline(0), online(1), degraded(2), disabled(3), maintenance(4),
  * uninitialized(5)
  *
  * This function converts a string representation of an SMF service state
- * to it's corresponding enum val.
+ * to its corresponding enum val.
  */
 static int
 state_to_val(char *statestr, uint32_t *stateval)
 {
         if (strcmp(statestr, "offline") == 0)

@@ -408,10 +457,11 @@
         if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0)
                 goto irpt_done;
 
         swtrap.host = hostname;
         swtrap.msgid = ev_info->ei_diagcode;
+        swtrap.severity = ev_info->ei_severity;
         swtrap.desc = ev_info->ei_descr;
         swtrap.tstamp = (time_t)fmev_time_sec(ev);
 
         if (strncmp(class, "ireport.os.smf", 14) == 0) {
                 swtrap.fmri = ev_info->ei_fmri;

@@ -434,14 +484,14 @@
 
 /*ARGSUSED*/
 static void
 list_cb(fmev_t ev, const char *class, nvlist_t *nvl, void *arg)
 {
-        char *uuid;
         uint8_t version;
         nd_ev_info_t *ev_info = NULL;
         nvlist_t **pref_nvl = NULL;
+        fmproblem_trap_t fmtrap;
         uint_t npref;
         int ret;
         boolean_t domsg;
 
         nd_debug(nhdl, "Received event of class %s", class);

@@ -473,23 +523,26 @@
             &domsg) == 0 && !domsg) {
                 nd_debug(nhdl, "Messaging suppressed for this event");
                 goto listcb_done;
         }
 
-        if (nvlist_lookup_uint8(ev_info->ei_payload, FM_VERSION, &version)
-            != 0 || version > FM_SUSPECT_VERSION) {
+        if (nvlist_lookup_uint8(ev_info->ei_payload, FM_VERSION,
+            &version) != 0 || version > FM_SUSPECT_VERSION) {
                 nd_error(nhdl, "invalid event version: %u", version);
                 goto listcb_done;
         }
 
-        (void) nvlist_lookup_string(ev_info->ei_payload, FM_SUSPECT_UUID,
-            &uuid);
+        fmtrap.uuid = ev_info->ei_uuid;
+        fmtrap.host = hostname;
+        fmtrap.code = ev_info->ei_diagcode;
+        fmtrap.type = ev_info->ei_type;
+        fmtrap.severity = ev_info->ei_severity;
+        fmtrap.url = ev_info->ei_url;
+        fmtrap.descr = ev_info->ei_descr;
+        fmtrap.fmri = ev_info->ei_fmri;
 
-        if (strcmp(ev_info->ei_url, ND_UNKNOWN) != 0)
-                send_fm_trap(uuid, ev_info->ei_diagcode, ev_info->ei_url);
-        else
-                nd_error(nhdl, "failed to format url for %s", uuid);
+        send_fm_trap(&fmtrap);
 listcb_done:
         nd_free_nvlarray(pref_nvl, npref);
         if (ev_info)
                 nd_free_event_info(ev_info);
 }