1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2019 Joyent, Inc.
  28  */
  29 
  30 #include <sys/types.h>
  31 #include <strings.h>
  32 #include <fm/fmd_api.h>
  33 #include <sys/fm/protocol.h>
  34 #include <sys/fm/util.h>
  35 #include <sys/sysevent.h>
  36 
  37 #include "fmevt.h"
  38 
  39 static evchan_t *fmevt_outbound_chan;
  40 
  41 static struct fmevt_outbound_stats {
  42         fmd_stat_t recv_calls;
  43         fmd_stat_t recv_list;
  44         fmd_stat_t recv_ireport;
  45         fmd_stat_t recv_other;
  46         fmd_stat_t fwd_success;
  47         fmd_stat_t fwd_failure;
  48 } outbound_stats = {
  49         { "outbound_recv_calls", FMD_TYPE_UINT64,
  50             "total events received for forwarding" },
  51         { "outbound_cat1class_list", FMD_TYPE_UINT64,
  52             "events received matching list.*" },
  53         { "outbound_cat1class_ireport", FMD_TYPE_UINT64,
  54             "events received matching ireport.*" },
  55         { "outbound_cat1class_other", FMD_TYPE_UINT64,
  56             "events of other classes" },
  57         { "outbound_fwd_success", FMD_TYPE_UINT64,
  58             "events forwarded successfully" },
  59         { "outbound_fwd_failure", FMD_TYPE_UINT64,
  60             "events we failed to forward" }
  61 };
  62 
  63 #define BUMPSTAT(stat)  outbound_stats.stat.fmds_value.ui64++
  64 
  65 /*
  66  * In the .conf file we subscribe to list.* and ireport.* event classes.
  67  * Any additions to that set could cause some unexpected behaviour.
  68  * For example adding fault.foo won't work (since we don't publish
  69  * faults directly but only within a list.suspect) but we will get
  70  * any list.* including fault.foo as a suspect.
  71  */
  72 /*ARGSUSED*/
  73 void
  74 fmevt_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
  75 {
  76         BUMPSTAT(recv_calls);
  77 
  78         if (strncmp(class, "list.", 5) == 0)
  79                 BUMPSTAT(recv_list);
  80         else if (strncmp(class, "ireport.", 8) == 0)
  81                 BUMPSTAT(recv_ireport);
  82         else
  83                 BUMPSTAT(recv_other);
  84 
  85         if (sysevent_evc_publish(fmevt_outbound_chan, class, "",
  86             SUNW_VENDOR, FM_PUB, nvl, EVCH_SLEEP) == 0) {
  87                 BUMPSTAT(fwd_success);
  88         } else {
  89                 BUMPSTAT(fwd_failure);
  90                 fmd_hdl_debug(hdl, "sysevent_evc_publish failed:");
  91         }
  92 }
  93 
  94 void
  95 fmevt_init_outbound(fmd_hdl_t *hdl)
  96 {
  97         int32_t channel_depth;
  98         char *channel_name;
  99         nvlist_t *nvl;
 100 
 101         if (fmd_prop_get_int32(hdl, "protocol_forward_disable") == B_TRUE) {
 102                 fmd_hdl_debug(hdl, "protocol forwarding disabled "
 103                     "through .conf file setting\n");
 104                 return;
 105         }
 106 
 107         (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (outbound_stats) /
 108             sizeof (fmd_stat_t), (fmd_stat_t *)&outbound_stats);
 109 
 110         /*
 111          * Allow simulation environment to change outbound channel name.
 112          */
 113         channel_name = fmd_prop_get_string(hdl, "outbound_channel");
 114 
 115         if (sysevent_evc_bind(channel_name, &fmevt_outbound_chan,
 116             EVCH_CREAT | EVCH_HOLD_PEND_INDEF) != 0) {
 117                 fmd_hdl_abort(hdl, "Unable to bind channel %s",
 118                     channel_name);
 119         }
 120 
 121         channel_depth = fmd_prop_get_int32(hdl, "outbound_channel_depth");
 122 
 123         if (sysevent_evc_control(fmevt_outbound_chan, EVCH_SET_CHAN_LEN,
 124             (uint32_t)channel_depth) != 0) {
 125                 fmd_hdl_abort(hdl, "Unable to set depth of channel %s to %d",
 126                     channel_name, channel_depth);
 127         }
 128         fmd_prop_free_string(hdl, channel_name);
 129 
 130         nvl = fmd_nvl_alloc(hdl, FMD_SLEEP);
 131         (void) nvlist_add_nvlist(nvl, "fmdauth",
 132             (nvlist_t *)fmd_hdl_fmauth(hdl));
 133         (void) sysevent_evc_setpropnvl(fmevt_outbound_chan, nvl);
 134         nvlist_free(nvl);
 135 
 136 }
 137 
 138 /*ARGSUSED*/
 139 void
 140 fmevt_fini_outbound(fmd_hdl_t *hdl)
 141 {
 142         if (fmevt_outbound_chan != NULL) {
 143                 (void) sysevent_evc_unbind(fmevt_outbound_chan);
 144                 fmevt_outbound_chan = NULL;
 145         }
 146 }