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.
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.
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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * The SNMP picl plugin connects to the agent on the SP and creates
29 * and populates the /physical-platform subtree in picl tree for use
51 #include "libpiclsnmp.h"
52 #include "snmpplugin.h"
54 #pragma init(snmpplugin_register) /* place in .init section */
56 picld_plugin_reg_t snmpplugin_reg
= {
57 PICLD_PLUGIN_VERSION_1
,
58 PICLD_PLUGIN_NON_CRITICAL
,
64 static picl_snmphdl_t hdl
;
67 * The stale_tree_rwlp protects the stale_xxx vars. The 'stale_tree' flag
68 * and the 'rebuild_tree' flag below are both initialized to B_TRUE to
69 * let the tree_builder() thread build the initial tree without blocking.
71 static rwlock_t stale_tree_rwlp
;
72 static boolean_t stale_tree
= B_TRUE
;
75 * vol_props, volprop_ndx and n_vol_props are protected by the stale_tree
76 * flag. They are read only when the stale_tree flag is B_FALSE and written
77 * to only when the flag is B_TRUE.
79 * The change_time (last changed time) is read by only one thread at a
80 * time when stale_tree is B_FALSE (protected by stale_tree_rwlp). It is
81 * written by only one thread (the tree builder) when stale_tree is B_TRUE.
83 * Note that strictly speaking, change_time should be uint_t (timeticks32).
84 * But keeping it as int is fine, since we don't do any arithmetic on it
85 * except equality check.
87 static vol_prophdl_t
*vol_props
= NULL
;
88 static int volprop_ndx
= 0, n_vol_props
= 0;
89 static int change_time
= 0;
90 static time_t change_time_check
;
93 * The rebuild_tree_lock and cv are used by the tree builder thread.
94 * rebuild_tree has to be initialized to B_TRUE to let the tree_builder
95 * do the first build without blocking.
97 static mutex_t rebuild_tree_lock
;
98 static cond_t rebuild_tree_cv
;
99 static boolean_t rebuild_tree
= B_TRUE
;
100 static boolean_t tree_builder_thr_exit
= B_FALSE
;
101 static thread_t tree_builder_thr_id
;
104 * The cache_refresh thread periodically queries the snmp cache refresh work
105 * queue and processes jobs from it to keep cache entries from expiring. It
106 * attempts to run in cycles of CACHE_REFRESH_CYCLE seconds each, first
107 * processing cache refresh jobs and then sleeping for the remainder of the
108 * cycle once the next refresh job expiration is at least
109 * CACHE_REFRESH_MIN_WINDOW seconds in the future.
111 * NOTE: By using a thread to keep the SNMP cache refreshed in the background,
112 * we are both adding load to the system and reducing the system's ability to
113 * operate in power-saving mode when there is minimal load. While these
114 * tradeoffs are acceptable at this time in light of customer concerns about
115 * performance, it may be desirable in the future to move this work into the
116 * firmware. Also, while the current cycle times performed well on the largest
117 * sun4v config currently available (Batoka), they may need to be revisited for
118 * future systems if the number of sensors increases significantly.
120 #define CACHE_REFRESH_CYCLE 60
121 #define CACHE_REFRESH_MIN_WINDOW 75
122 static mutex_t cache_refresh_lock
;
123 static cond_t cache_refresh_cv
;
124 static boolean_t cache_refresh_thr_exit
= B_FALSE
;
125 static thread_t cache_refresh_thr_id
;
128 * These two should really not be global
130 static picl_nodehdl_t
*physplat_nodes
= NULL
;
131 static int n_physplat_nodes
= 0;
133 static char *group1
[] = {
134 OID_entPhysicalDescr
,
135 OID_entPhysicalContainedIn
,
136 OID_entPhysicalClass
,
138 OID_entPhysicalHardwareRev
,
139 OID_entPhysicalFirmwareRev
,
140 OID_entPhysicalSerialNum
,
141 OID_entPhysicalMfgName
,
142 OID_entPhysicalModelName
,
143 OID_entPhysicalIsFRU
,
147 static char *group2
[] = {
148 OID_sunPlatEquipmentHolderAcceptableTypes
,
149 OID_sunPlatCircuitPackReplaceable
,
150 OID_sunPlatCircuitPackHotSwappable
,
151 OID_sunPlatPhysicalClass
,
152 OID_sunPlatSensorClass
,
153 OID_sunPlatSensorType
,
154 OID_sunPlatAlarmType
,
155 OID_sunPlatPowerSupplyClass
,
159 static char *group3
[] = {
160 OID_sunPlatNumericSensorEnabledThresholds
,
161 OID_sunPlatNumericSensorBaseUnits
,
162 OID_sunPlatNumericSensorRateUnits
,
166 static char *group4
[] = {
167 OID_sunPlatBinarySensorInterpretTrue
,
168 OID_sunPlatBinarySensorInterpretFalse
,
172 static char *volgroup1
[] = {
173 OID_sunPlatBinarySensorCurrent
,
174 OID_sunPlatBinarySensorExpected
,
178 static char *volgroup2
[] = {
179 OID_sunPlatNumericSensorExponent
,
180 OID_sunPlatNumericSensorCurrent
,
181 OID_sunPlatNumericSensorLowerThresholdFatal
,
182 OID_sunPlatNumericSensorLowerThresholdCritical
,
183 OID_sunPlatNumericSensorLowerThresholdNonCritical
,
184 OID_sunPlatNumericSensorUpperThresholdNonCritical
,
185 OID_sunPlatNumericSensorUpperThresholdCritical
,
186 OID_sunPlatNumericSensorUpperThresholdFatal
,
190 static char *volgroup3
[] = {
191 OID_sunPlatEquipmentOperationalState
,
195 static char *volgroup4
[] = {
196 OID_sunPlatAlarmState
,
200 static char *volgroup5
[] = {
201 OID_sunPlatBatteryStatus
,
206 * The following two items must match the Sun Platform MIB specification
207 * in their indices and values.
209 static char *sensor_baseunits
[] = {
210 "", "other", "unknown", "degC", "degF", "degK", "volts", "amps",
211 "watts", "joules", "coulombs", "va", "nits", "lumens", "lux",
212 "candelas", "kPa", "psi", "newtons", "cfm", "rpm", "hertz",
213 "seconds", "minutes", "hours", "days", "weeks", "mils", "inches",
214 "feet", "cubicInches", "cubicFeet", "meters", "cubicCentimeters",
215 "cubicMeters", "liters", "fluidOunces", "radians", "steradians",
216 "revolutions", "cycles", "gravities", "ounces", "pounds", "footPounds",
217 "ounceInches", "gauss", "gilberts", "henries", "farads", "ohms",
218 "siemens", "moles", "becquerels", "ppm", "decibels", "dBA", "dbC",
219 "grays", "sieverts", "colorTemperatureDegK", "bits", "bytes", "words",
220 "doubleWords", "quadWords", "percentage"
222 static const int n_baseunits
= sizeof (sensor_baseunits
) / sizeof (char *);
224 static char *sensor_rateunits
[] = {
237 static const int n_rateunits
= sizeof (sensor_rateunits
) / sizeof (char *);
242 static void snmpplugin_register(void);
243 static void register_group(char **g
, int is_volatile
);
244 static void *tree_builder(void *arg
);
245 static int build_physplat(picl_nodehdl_t
*subtree_rootp
);
246 static void free_resources(picl_nodehdl_t subtree_root
);
248 static picl_nodehdl_t
make_node(picl_nodehdl_t subtree_root
, int row
,
250 static void save_nodeh(picl_nodehdl_t nodeh
, int row
);
251 static picl_nodehdl_t
lookup_nodeh(int row
);
253 static void save_volprop(picl_prophdl_t prop
, char *oidstr
, int row
,
255 static void check_for_stale_data(boolean_t nocache
);
256 static int read_volprop(ptree_rarg_t
*parg
, void *buf
);
258 static void threshold(picl_nodehdl_t node
, char *oidstr
, int row
,
259 char *propname
, int *snmp_syserr_p
);
260 static void add_thresholds(picl_nodehdl_t node
, int row
, int *snmp_syserr_p
);
262 static char *get_slot_type(int row
, int *snmp_syserr_p
);
263 static int add_volatile_prop(picl_nodehdl_t nodeh
, char *name
,
264 int type
, int access
, int size
, int (*rdfunc
)(ptree_rarg_t
*, void *),
265 int (*wrfunc
)(ptree_warg_t
*, const void *), picl_prophdl_t
*propp
);
266 static int add_string_prop(picl_nodehdl_t node
, char *propname
, char *propval
);
267 static int add_void_prop(picl_nodehdl_t node
, char *propname
);
268 static void add_prop(picl_nodehdl_t nodeh
, picl_prophdl_t
*php
, char *label
,
269 int row
, sp_propid_t pp
, int *snmp_syserr_p
);
271 static void *cache_refresher(void *arg
);
272 static void cache_refresher_fini(void);
274 static void log_msg(int pri
, const char *fmt
, ...);
276 #ifdef SNMPPLUGIN_DEBUG
277 static mutex_t snmpplugin_dbuf_lock
;
278 static char *snmpplugin_dbuf
= NULL
;
279 static char *snmpplugin_dbuf_curp
= NULL
;
280 static int snmpplugin_dbuf_sz
= 0;
281 static int snmpplugin_dbuf_overflow
= 0;
282 static char snmpplugin_lbuf
[SNMPPLUGIN_DMAX_LINE
];
284 static void snmpplugin_log_init(void);
285 static void snmpplugin_log(const char *fmt
, ...);
286 static void snmpplugin_log_append(void);
287 static void snmpplugin_dbuf_realloc(void);
291 snmpplugin_register(void)
293 (void) picld_plugin_register(&snmpplugin_reg
);
297 register_group(char **g
, int is_volatile
)
303 for (i
= 0; g
[i
]; i
++)
304 len
+= strlen(g
[i
]) + 1;
307 if ((oidstrs
= (char *)calloc(1, len
)) == NULL
)
310 for (p
= oidstrs
, i
= 0; g
[i
]; i
++) {
311 (void) strcpy(p
, g
[i
]);
312 p
+= strlen(g
[i
]) + 1;
315 snmp_register_group(hdl
, oidstrs
, n_oids
, is_volatile
);
320 snmpplugin_init(void)
324 (void) mutex_init(&rebuild_tree_lock
, USYNC_THREAD
, NULL
);
325 (void) cond_init(&rebuild_tree_cv
, USYNC_THREAD
, NULL
);
326 (void) rwlock_init(&stale_tree_rwlp
, USYNC_THREAD
, NULL
);
327 tree_builder_thr_exit
= B_FALSE
;
332 * Create the tree-builder thread and let it take over
334 LOGPRINTF("Tree-builder thread being created.\n");
335 if ((ret
= thr_create(NULL
, NULL
, tree_builder
, NULL
,
336 THR_BOUND
, &tree_builder_thr_id
)) < 0) {
337 log_msg(LOG_ERR
, SNMPP_CANT_CREATE_TREE_BUILDER
, ret
);
340 (void) rwlock_destroy(&stale_tree_rwlp
);
341 (void) cond_destroy(&rebuild_tree_cv
);
342 (void) mutex_destroy(&rebuild_tree_lock
);
343 tree_builder_thr_exit
= B_TRUE
;
349 * While the cache refresher thread does improve performance, it is not
350 * integral to the proper function of the plugin. If we fail to create
351 * the thread for some reason, we will simply continue without
354 (void) mutex_init(&cache_refresh_lock
, USYNC_THREAD
, NULL
);
355 (void) cond_init(&cache_refresh_cv
, USYNC_THREAD
, NULL
);
356 cache_refresh_thr_exit
= B_FALSE
;
358 LOGPRINTF("Cache refresher thread being created.\n");
359 if (thr_create(NULL
, NULL
, cache_refresher
, NULL
, THR_BOUND
,
360 &cache_refresh_thr_id
) < 0) {
361 (void) cond_destroy(&cache_refresh_cv
);
362 (void) mutex_destroy(&cache_refresh_lock
);
363 cache_refresh_thr_exit
= B_TRUE
;
368 snmpplugin_fini(void)
371 if (tree_builder_thr_exit
== B_TRUE
)
375 * Make reads of volatile properties return PICL_PROPUNAVAILABLE
376 * since we're about to recycle the plug-in. No need to worry
377 * about removing /physical-platform since tree_builder() will
378 * take care of recycling it for us.
380 (void) rw_wrlock(&stale_tree_rwlp
);
388 (void) rw_unlock(&stale_tree_rwlp
);
390 /* clean up the cache_refresher thread and structures */
391 cache_refresher_fini();
393 /* wake up the tree_builder thread, tell it to exit */
394 (void) mutex_lock(&rebuild_tree_lock
);
395 rebuild_tree
= B_TRUE
;
396 tree_builder_thr_exit
= B_TRUE
;
397 (void) cond_signal(&rebuild_tree_cv
);
398 (void) mutex_unlock(&rebuild_tree_lock
);
400 /* send SIGUSR1 to get tree_builder out of a blocked system call */
401 (void) thr_kill(tree_builder_thr_id
, SIGUSR1
);
403 /* reap the thread */
404 (void) thr_join(tree_builder_thr_id
, NULL
, NULL
);
406 /* close the channel */
412 /* finish cleanup... */
413 (void) rwlock_destroy(&stale_tree_rwlp
);
414 (void) cond_destroy(&rebuild_tree_cv
);
415 (void) mutex_destroy(&rebuild_tree_lock
);
420 usr1_handler(int sig
, siginfo_t
*siginfo
, void *sigctx
)
423 * Nothing to do here.
424 * The act of catching the signal causes any cond_wait() or blocked
425 * system call to return EINTR. This is used to trigger early exit from
426 * the tree builder thread which may be blocked in snmp_init. More work
427 * would be required to allow early exit if the tree builder thread is
428 * already in its main processing loop and not blocked in cond_wait.
434 tree_builder(void *arg
)
437 picl_nodehdl_t root_node
;
438 picl_nodehdl_t physplat_root
;
439 picl_nodehdl_t old_physplat_root
;
440 struct sigaction act
;
443 * catch SIGUSR1 to allow early exit from snmp_init which may block
444 * indefinitely in a guest domain.
446 act
.sa_sigaction
= usr1_handler
;
447 (void) sigemptyset(&act
.sa_mask
);
449 if (sigaction(SIGUSR1
, &act
, NULL
) == -1) {
450 syslog(LOG_ERR
, SIGACT_FAILED
, strsignal(SIGUSR1
),
455 * Initialize SNMP service
457 LOGPRINTF("Initializing SNMP service.\n");
458 if ((hdl
= snmp_init()) == NULL
) {
459 log_msg(LOG_ERR
, SNMPP_CANT_INIT
);
464 * Register OID groupings for BULKGET optimizations
466 LOGPRINTF("Registering OID groups.\n");
467 register_group(group1
, 0);
468 register_group(group2
, 0);
469 register_group(group3
, 0);
470 register_group(group4
, 0);
471 register_group(volgroup1
, 1);
472 register_group(volgroup2
, 1);
473 register_group(volgroup3
, 1);
474 register_group(volgroup4
, 1);
475 register_group(volgroup5
, 1);
477 (void) mutex_lock(&rebuild_tree_lock
);
480 LOGPRINTF("tree_builder: check whether to rebuild subtree\n");
481 while (rebuild_tree
== B_FALSE
)
482 (void) cond_wait(&rebuild_tree_cv
, &rebuild_tree_lock
);
484 LOGPRINTF("tree_builder: woke up\n");
486 if (tree_builder_thr_exit
== B_TRUE
) {
487 (void) mutex_unlock(&rebuild_tree_lock
);
488 LOGPRINTF("tree_builder: time to exit\n");
492 old_physplat_root
= NULL
;
493 physplat_root
= NULL
;
495 LOGPRINTF("tree_builder: getting root node\n");
496 if ((ret
= ptree_get_root(&root_node
)) != PICL_SUCCESS
) {
497 (void) mutex_unlock(&rebuild_tree_lock
);
498 log_msg(LOG_ERR
, SNMPP_NO_ROOT
, ret
);
502 LOGPRINTF("tree_builder: getting existing physplat node\n");
503 rv
= ptree_find_node(root_node
, PICL_PROP_NAME
,
504 PICL_PTYPE_CHARSTRING
, PICL_NODE_PHYSPLAT
,
505 sizeof (PICL_NODE_PHYSPLAT
), &old_physplat_root
);
507 LOGPRINTF("tree_builder: building physical-platform\n");
508 if ((ret
= build_physplat(&physplat_root
)) < 0) {
509 (void) mutex_unlock(&rebuild_tree_lock
);
510 log_msg(LOG_ERR
, SNMPP_CANT_CREATE_PHYSPLAT
, ret
);
511 cache_refresher_fini();
517 if (rv
== PICL_SUCCESS
&& old_physplat_root
!= NULL
) {
518 LOGPRINTF("tree_builder: destroying existing nodes\n");
519 ptree_delete_node(old_physplat_root
);
520 ptree_destroy_node(old_physplat_root
);
523 LOGPRINTF("tree_builder: attaching new subtree\n");
524 if ((ret
= ptree_add_node(root_node
, physplat_root
)) < 0) {
525 (void) mutex_unlock(&rebuild_tree_lock
);
526 free_resources(physplat_root
);
527 log_msg(LOG_ERR
, SNMPP_CANT_CREATE_PHYSPLAT
, ret
);
528 cache_refresher_fini();
534 LOGPRINTF("tree_builder: setting stale_tree to FALSE\n");
535 (void) rw_wrlock(&stale_tree_rwlp
);
536 stale_tree
= B_FALSE
;
537 (void) rw_unlock(&stale_tree_rwlp
);
539 LOGPRINTF("tree_builder: setting rebuild_tree to FALSE\n");
540 rebuild_tree
= B_FALSE
;
548 build_physplat(picl_nodehdl_t
*subtree_rootp
)
552 int clr_linkreset
= 0;
557 (void) snmp_reinit(hdl
, clr_linkreset
);
561 * Record LastChangeTime before we start building the tree
563 ret
= snmp_get_int(hdl
, OID_entLastChangeTime
, 0,
564 &change_time1
, &snmp_syserr
);
566 if (snmp_syserr
== ECANCELED
) {
567 LOGPRINTF(SNMPP_LINK_RESET
);
571 log_msg(LOG_WARNING
, SNMPP_CANT_FETCH_OBJECT_VAL
,
572 snmp_syserr
? snmp_syserr
: ret
, OID_entLastChangeTime
, 0);
576 * Create the physical-platform node
578 ret
= ptree_create_node(PICL_NODE_PHYSPLAT
, PICL_CLASS_PICL
,
580 if (ret
!= PICL_SUCCESS
)
584 * Scan entPhysicalTable and build the "physical-platform" subtree
587 for (row
= -1; ret
== 0; row
= nxtrow
) {
588 ret
= snmp_get_nextrow(hdl
, OID_entPhysicalDescr
,
589 row
, &nxtrow
, &snmp_syserr
);
591 (void) make_node(*subtree_rootp
, nxtrow
, &snmp_syserr
);
592 switch (snmp_syserr
) {
595 * If we get this error, a link reset must've
596 * happened and we need to throw away everything
597 * we have now and rebuild the tree again.
599 log_msg(LOG_WARNING
, SNMPP_LINK_RESET
);
600 free_resources(*subtree_rootp
);
605 case ENOSPC
: /* end of MIB */
606 LOGPRINTF("build_physplat: end of MIB\n");
608 case ENOENT
: /* end of table */
609 LOGPRINTF("build_physplat: end of table\n");
613 * make_node() will print messages so don't
614 * repeat that exercise here.
618 SNMPP_CANT_FETCH_OBJECT_VAL
,
619 snmp_syserr
? snmp_syserr
: ret
,
620 OID_entPhysicalDescr
, row
);
626 * Record LastChangeTime after we're done building the tree
628 ret
= snmp_get_int(hdl
, OID_entLastChangeTime
, 0,
629 &change_time
, &snmp_syserr
);
631 if (snmp_syserr
== ECANCELED
) {
632 log_msg(LOG_WARNING
, SNMPP_LINK_RESET
);
633 free_resources(*subtree_rootp
);
637 log_msg(LOG_WARNING
, SNMPP_CANT_FETCH_OBJECT_VAL
,
638 snmp_syserr
? snmp_syserr
: ret
,
639 OID_entLastChangeTime
, row
);
643 * If they don't match, some hotplugging must've happened,
644 * free resources we've created and still holding, then go
647 if (change_time
!= change_time1
) {
648 LOGPRINTF("build_physplat: entLastChangeTime has changed!\n");
649 free_resources(*subtree_rootp
);
650 change_time1
= change_time
;
655 * The physplat_nodes table is no longer needed, free it
657 if (physplat_nodes
) {
658 free(physplat_nodes
);
659 physplat_nodes
= NULL
;
660 n_physplat_nodes
= 0;
667 * Destroy all resources that were created during the building
671 free_resources(picl_nodehdl_t subtree_root
)
673 if (physplat_nodes
) {
674 free(physplat_nodes
);
675 physplat_nodes
= NULL
;
676 n_physplat_nodes
= 0;
680 (void) ptree_delete_node(subtree_root
);
681 (void) ptree_destroy_node(subtree_root
);
692 static picl_nodehdl_t
693 make_node(picl_nodehdl_t subtree_root
, int row
, int *snmp_syserr_p
)
695 picl_nodehdl_t nodeh
, parenth
;
696 picl_prophdl_t proph
;
697 char *phys_name
, *node_name
;
699 int ent_physclass
, sunplat_physclass
;
700 int sensor_class
, sensor_type
;
706 * If we've already created this picl node, just return it
708 if ((nodeh
= lookup_nodeh(row
)) != NULL
)
712 * If we are creating it only now, make sure we have the parent
713 * created first; if there's no parent, then parent it to the
714 * subtree's root node
716 ret
= snmp_get_int(hdl
, OID_entPhysicalContainedIn
, row
,
717 &parent_row
, snmp_syserr_p
);
718 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
719 if (ret
< 0 || parent_row
<= 0)
720 parenth
= subtree_root
;
722 parenth
= make_node(subtree_root
, parent_row
, snmp_syserr_p
);
723 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
725 parenth
= subtree_root
;
729 * Figure out the physical-platform node name from entPhysicalName;
730 * all rows in the MIB that have a valid entPhysicalIndex should
731 * have a physical name.
733 ret
= snmp_get_str(hdl
, OID_entPhysicalName
, row
,
734 &phys_name
, snmp_syserr_p
);
735 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
736 if (ret
< 0 || phys_name
== NULL
) {
737 log_msg(LOG_WARNING
, SNMPP_NO_ENTPHYSNAME
, row
);
741 node_name
= basename(phys_name
);
743 ret
= snmp_get_int(hdl
, OID_entPhysicalClass
, row
,
744 &ent_physclass
, snmp_syserr_p
);
745 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
747 log_msg(LOG_WARNING
, SNMPP_CANT_FETCH_OBJECT_VAL
,
748 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
749 OID_entPhysicalClass
, row
);
754 switch (ent_physclass
) {
756 ret
= snmp_get_int(hdl
, OID_sunPlatPhysicalClass
, row
,
757 &sunplat_physclass
, snmp_syserr_p
);
758 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
760 log_msg(LOG_WARNING
, SNMPP_CANT_FETCH_OBJECT_VAL
,
761 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
762 OID_sunPlatPhysicalClass
, row
);
767 if (sunplat_physclass
== SSPC_ALARM
) {
768 ret
= snmp_get_int(hdl
, OID_sunPlatAlarmType
,
769 row
, &alarm_type
, snmp_syserr_p
);
770 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
773 SNMPP_CANT_FETCH_OBJECT_VAL
,
774 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
775 OID_sunPlatAlarmType
, row
);
780 if (alarm_type
== SSAT_VISIBLE
) {
781 ADD_NODE(PICL_CLASS_LED
)
783 ADD_NODE(PICL_CLASS_ALARM
)
786 add_prop(nodeh
, &proph
, node_name
, row
, PP_STATE
,
788 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
790 ADD_NODE(PICL_CLASS_OTHER
)
793 add_prop(nodeh
, &proph
, node_name
, row
, PP_OPSTATUS
,
795 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
799 ADD_NODE(PICL_CLASS_UNKNOWN
)
803 ADD_NODE(PICL_CLASS_CHASSIS
)
804 add_prop(nodeh
, &proph
, node_name
, row
, PP_OPSTATUS
,
806 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
810 ADD_NODE(PICL_CLASS_BACKPLANE
)
811 add_prop(nodeh
, &proph
, node_name
, row
, PP_OPSTATUS
,
813 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
817 ADD_NODE(PICL_CLASS_CONTAINER
)
819 add_prop(nodeh
, &proph
, node_name
, row
, PP_OPSTATUS
,
821 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
823 add_prop(nodeh
, &proph
, node_name
, row
, PP_SLOT_TYPE
,
825 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
828 case SPC_POWERSUPPLY
:
829 ret
= snmp_get_int(hdl
, OID_sunPlatPowerSupplyClass
,
830 row
, &ps_class
, snmp_syserr_p
);
831 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
833 log_msg(LOG_WARNING
, SNMPP_CANT_FETCH_OBJECT_VAL
,
834 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
835 OID_sunPlatPowerSupplyClass
, row
);
840 if (ps_class
== SSPSC_BATTERY
) {
841 ADD_NODE(PICL_CLASS_BATTERY
)
842 add_prop(nodeh
, &proph
, node_name
, row
,
843 PP_BATT_STATUS
, snmp_syserr_p
);
844 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
846 ADD_NODE(PICL_CLASS_POWERSUPPLY
)
848 add_prop(nodeh
, &proph
, node_name
, row
, PP_OPSTATUS
,
850 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
854 ADD_NODE(PICL_CLASS_FAN
)
855 add_prop(nodeh
, &proph
, node_name
, row
, PP_OPSTATUS
,
857 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
861 ret
= snmp_get_int(hdl
, OID_sunPlatSensorClass
,
862 row
, &sensor_class
, snmp_syserr_p
);
863 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
865 log_msg(LOG_WARNING
, SNMPP_CANT_FETCH_OBJECT_VAL
,
866 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
867 OID_sunPlatSensorClass
, row
);
872 ret
= snmp_get_int(hdl
, OID_sunPlatSensorType
,
873 row
, &sensor_type
, snmp_syserr_p
);
874 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
876 log_msg(LOG_WARNING
, SNMPP_CANT_FETCH_OBJECT_VAL
,
877 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
878 OID_sunPlatSensorType
, row
);
883 if (sensor_class
== SSSC_NUMERIC
) {
884 if (sensor_type
== SSST_TEMPERATURE
) {
885 ADD_NODE(PICL_CLASS_TEMPERATURE_SENSOR
)
886 add_prop(nodeh
, &proph
, node_name
, row
,
887 PP_TEMPERATURE
, snmp_syserr_p
);
888 } else if (sensor_type
== SSST_VOLTAGE
) {
889 ADD_NODE(PICL_CLASS_VOLTAGE_SENSOR
)
890 add_prop(nodeh
, &proph
, node_name
, row
,
891 PP_VOLTAGE
, snmp_syserr_p
);
892 } else if (sensor_type
== SSST_CURRENT
) {
893 ADD_NODE(PICL_CLASS_CURRENT_SENSOR
)
894 add_prop(nodeh
, &proph
, node_name
, row
,
895 PP_CURRENT
, snmp_syserr_p
);
896 } else if (sensor_type
== SSST_TACHOMETER
) {
897 ADD_NODE(PICL_CLASS_RPM_SENSOR
)
898 add_prop(nodeh
, &proph
, node_name
, row
,
899 PP_SPEED
, snmp_syserr_p
);
901 ADD_NODE(PICL_CLASS_SENSOR
)
902 add_prop(nodeh
, &proph
, node_name
, row
,
903 PP_SENSOR_VALUE
, snmp_syserr_p
);
905 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
907 add_prop(nodeh
, &proph
, node_name
, row
,
908 PP_OPSTATUS
, snmp_syserr_p
);
909 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
911 add_prop(nodeh
, &proph
, node_name
, row
,
912 PP_BASE_UNITS
, snmp_syserr_p
);
913 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
915 add_prop(nodeh
, &proph
, node_name
, row
,
916 PP_EXPONENT
, snmp_syserr_p
);
917 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
919 add_prop(nodeh
, &proph
, node_name
, row
,
920 PP_RATE_UNITS
, snmp_syserr_p
);
921 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
923 add_thresholds(nodeh
, row
, snmp_syserr_p
);
924 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
926 } else if (sensor_class
== SSSC_BINARY
) {
927 if (sensor_type
== SSST_TEMPERATURE
) {
928 ADD_NODE(PICL_CLASS_TEMPERATURE_INDICATOR
)
929 } else if (sensor_type
== SSST_VOLTAGE
) {
930 ADD_NODE(PICL_CLASS_VOLTAGE_INDICATOR
)
931 } else if (sensor_type
== SSST_CURRENT
) {
932 ADD_NODE(PICL_CLASS_CURRENT_INDICATOR
)
933 } else if (sensor_type
== SSST_TACHOMETER
) {
934 ADD_NODE(PICL_CLASS_RPM_INDICATOR
)
935 } else if (sensor_type
== SSST_PRESENCE
) {
936 ADD_NODE(PICL_CLASS_PRESENCE_INDICATOR
)
938 ADD_NODE(PICL_CLASS_INDICATOR
)
941 add_prop(nodeh
, &proph
, node_name
, row
, PP_OPSTATUS
,
943 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
945 add_prop(nodeh
, &proph
, node_name
, row
, PP_CONDITION
,
947 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
949 add_prop(nodeh
, &proph
, node_name
, row
, PP_EXPECTED
,
951 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
954 SNMPP_UNSUPP_SENSOR_CLASS
, sensor_class
, row
);
960 ADD_NODE(PICL_CLASS_MODULE
)
962 add_prop(nodeh
, &proph
, node_name
, row
, PP_OPSTATUS
,
964 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
966 add_prop(nodeh
, &proph
, node_name
, row
, PP_REPLACEABLE
,
968 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
970 add_prop(nodeh
, &proph
, node_name
, row
, PP_HOTSWAPPABLE
,
972 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
976 ADD_NODE(PICL_CLASS_PORT
)
980 ADD_NODE(PICL_CLASS_STACK
)
985 SNMPP_UNKNOWN_ENTPHYSCLASS
, ent_physclass
, row
);
990 add_prop(nodeh
, &proph
, node_name
, row
, PP_DESCRIPTION
, snmp_syserr_p
);
991 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
993 add_prop(nodeh
, &proph
, node_name
, row
, PP_LABEL
, snmp_syserr_p
);
994 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
996 add_prop(nodeh
, &proph
, node_name
, row
, PP_HW_REVISION
, snmp_syserr_p
);
997 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
999 add_prop(nodeh
, &proph
, node_name
, row
, PP_FW_REVISION
, snmp_syserr_p
);
1000 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
1002 add_prop(nodeh
, &proph
, node_name
, row
, PP_SERIAL_NUM
, snmp_syserr_p
);
1003 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
1005 add_prop(nodeh
, &proph
, node_name
, row
, PP_MFG_NAME
, snmp_syserr_p
);
1006 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
1008 add_prop(nodeh
, &proph
, node_name
, row
, PP_MODEL_NAME
, snmp_syserr_p
);
1009 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
1011 add_prop(nodeh
, &proph
, node_name
, row
, PP_IS_FRU
, snmp_syserr_p
);
1012 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
1015 save_nodeh(nodeh
, row
);
1021 * Saves the node handle and the row id into physplat_nodes[]. If we're
1022 * doing this in response to a hotplug event, we should've freed the
1023 * old physplat_nodes before entering here to save the first node of the
1024 * new physplat subtree.
1027 save_nodeh(picl_nodehdl_t nodeh
, int row
)
1032 if (row
>= n_physplat_nodes
) {
1033 count
= (((size_t)row
>> NODE_BLOCK_SHIFT
) + 1) *
1034 N_ELEMS_IN_NODE_BLOCK
;
1035 sz
= count
* sizeof (picl_nodehdl_t
);
1037 p
= (picl_nodehdl_t
*)calloc(count
, sizeof (picl_nodehdl_t
));
1039 log_msg(LOG_ERR
, SNMPP_NO_MEM
, sz
);
1043 if (physplat_nodes
) {
1044 (void) memcpy((void *) p
, (void *) physplat_nodes
,
1045 n_physplat_nodes
* sizeof (picl_nodehdl_t
));
1046 free((void *) physplat_nodes
);
1050 n_physplat_nodes
= count
;
1053 physplat_nodes
[row
] = nodeh
;
1056 static picl_nodehdl_t
1057 lookup_nodeh(int row
)
1059 if (row
>= n_physplat_nodes
)
1062 return (physplat_nodes
[row
]);
1066 * We enter this routine only when we are building the physical-platform
1067 * subtree, whether for the first time or in response to a hotplug event.
1068 * If we're here for rebuilding the tree, we have already set stale_tree
1069 * to be B_TRUE, so no one else would be accessing vol_props, n_vol_props
1070 * or volprop_ndx. If we're here to build the tree for the first time,
1071 * picld hasn't yet created doors and is running single-threaded, so no
1072 * one else would be accessing them anyway.
1075 save_volprop(picl_prophdl_t prop
, char *oidstr
, int row
, int proptype
)
1080 if (volprop_ndx
== n_vol_props
) {
1081 count
= n_vol_props
+ N_ELEMS_IN_VOLPROP_BLOCK
;
1082 p
= (vol_prophdl_t
*)calloc(count
, sizeof (vol_prophdl_t
));
1084 log_msg(LOG_ERR
, SNMPP_NO_MEM
,
1085 count
* sizeof (vol_prophdl_t
));
1090 (void) memcpy((void *) p
, (void *) vol_props
,
1091 n_vol_props
* sizeof (vol_prophdl_t
));
1092 free((void *) vol_props
);
1096 n_vol_props
+= N_ELEMS_IN_VOLPROP_BLOCK
;
1099 vol_props
[volprop_ndx
].prop
= prop
;
1100 vol_props
[volprop_ndx
].oidstr
= oidstr
;
1101 vol_props
[volprop_ndx
].row
= row
;
1102 vol_props
[volprop_ndx
].proptype
= proptype
;
1108 check_for_stale_data(boolean_t nocache
)
1110 int cur_change_time
;
1114 (void) rw_wrlock(&stale_tree_rwlp
);
1117 * Check if some other thread beat us to it
1119 if (stale_tree
== B_TRUE
) {
1120 (void) rw_unlock(&stale_tree_rwlp
);
1125 * Cache OID_entLastChangeTime for up to 10 seconds before
1126 * fetching it from ILOM again. This prevents us from fetching
1127 * this value from ILOM when the we're filling or refreshing a
1128 * whole bunch of items in the cache around the same time.
1130 if (nocache
== B_FALSE
&& time(NULL
) - change_time_check
<= 10) {
1131 (void) rw_unlock(&stale_tree_rwlp
);
1136 * Check if mib data has changed (hotplug? link-reset?)
1140 ret
= snmp_get_int(hdl
, OID_entLastChangeTime
, 0,
1141 &cur_change_time
, &snmp_syserr
);
1142 (void) time(&change_time_check
);
1143 if ((ret
== 0) && (cur_change_time
== change_time
)) {
1144 (void) rw_unlock(&stale_tree_rwlp
);
1147 } while (ret
!= 0 && snmp_syserr
== EINTR
);
1150 * If we can't read entLastChangeTime we assume we need to rebuild
1151 * the tree. This will also cover the case when we need to rebuild
1152 * the tree because a link reset had happened.
1154 LOGPRINTF2("check_for_stale_data: LastChange times have changed, "
1155 "(%#x != %#x)\n", change_time
, cur_change_time
);
1158 * If the mib data has changed, we need to rebuild the physical-platform
1159 * subtree. To do this, we set a flag to mark the tree stale,
1160 * so that any future reads to get value of volatile properties will
1161 * return PICL_PROPVALUNAVAILABLE, until the stale_tree flag
1162 * is reset by the tree builder thread.
1164 stale_tree
= B_TRUE
;
1172 (void) rw_unlock(&stale_tree_rwlp
);
1174 (void) mutex_lock(&rebuild_tree_lock
);
1175 rebuild_tree
= B_TRUE
;
1176 (void) cond_signal(&rebuild_tree_cv
);
1177 LOGPRINTF("check_for_stale_data: signalled tree builder\n");
1178 (void) mutex_unlock(&rebuild_tree_lock
);
1182 * This is the critical routine. This callback is invoked by picl whenever
1183 * it needs to fetch the value of a volatile property. The first thing we
1184 * must do, however, is to see if there has been a hotplug or a link-reset
1185 * event since the last time we built the tree and whether we need to
1186 * rebuild the tree. If so, we do whatever is necessary to make that happen,
1187 * but return PICL_PROPVALUNAVAILABLE for now, without making any further
1188 * snmp requests or accessing any globals.
1191 read_volprop(ptree_rarg_t
*parg
, void *buf
)
1197 int snmp_syserr
= 0;
1200 * First check for any event that would make us throw away
1201 * the existing /physical-platform subtree and rebuild
1202 * another one. If we are rebuilding the subtree, we just
1203 * return the stale value until the tree is fully built.
1205 check_for_stale_data(B_FALSE
);
1207 (void) rw_rdlock(&stale_tree_rwlp
);
1209 if (stale_tree
== B_TRUE
) {
1210 (void) rw_unlock(&stale_tree_rwlp
);
1211 return (PICL_PROPVALUNAVAILABLE
);
1214 for (i
= 0; i
< volprop_ndx
; i
++) {
1215 if (vol_props
[i
].prop
== parg
->proph
) {
1220 if (i
== volprop_ndx
) {
1221 (void) rw_unlock(&stale_tree_rwlp
);
1222 log_msg(LOG_ERR
, SNMPP_CANT_FIND_VOLPROP
, parg
->proph
);
1223 return (PICL_FAILURE
);
1227 * If we can't read the value, return failure. Even if this was
1228 * due to a link reset, between the check for stale data and now,
1229 * the next volatile callback by picl will initiate a tree-rebuild.
1231 ret
= snmp_get_int(hdl
, vol_props
[ndx
].oidstr
, vol_props
[ndx
].row
,
1232 &propval
, &snmp_syserr
);
1234 (void) rw_unlock(&stale_tree_rwlp
);
1235 check_for_stale_data(B_TRUE
);
1236 if (stale_tree
== B_TRUE
) {
1237 return (PICL_PROPVALUNAVAILABLE
);
1239 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1240 snmp_syserr
? snmp_syserr
: ret
,
1241 vol_props
[ndx
].oidstr
, vol_props
[ndx
].row
);
1242 return (PICL_FAILURE
);
1245 switch (vol_props
[ndx
].proptype
) {
1246 case VPT_PLATOPSTATE
:
1247 if (propval
== SSOS_DISABLED
) {
1248 (void) strlcpy(buf
, STR_SSOS_DISABLED
, MAX_OPSTATE_LEN
);
1249 } else if (propval
== SSOS_ENABLED
) {
1250 (void) strlcpy(buf
, STR_SSOS_ENABLED
, MAX_OPSTATE_LEN
);
1252 (void) rw_unlock(&stale_tree_rwlp
);
1253 log_msg(LOG_ERR
, SNMPP_INV_PLAT_EQUIP_OPSTATE
,
1254 propval
, vol_props
[ndx
].row
);
1255 return (PICL_FAILURE
);
1260 (void) memcpy(buf
, &propval
, sizeof (propval
));
1264 if (propval
== ST_TRUE
) {
1265 ret
= snmp_get_str(hdl
,
1266 OID_sunPlatBinarySensorInterpretTrue
,
1267 vol_props
[ndx
].row
, &pstr
, &snmp_syserr
);
1268 if (snmp_syserr
== ECANCELED
) {
1269 (void) rw_unlock(&stale_tree_rwlp
);
1271 return (PICL_FAILURE
);
1273 if (ret
< 0 || pstr
== NULL
) {
1274 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1275 snmp_syserr
? snmp_syserr
: ret
,
1276 OID_sunPlatBinarySensorInterpretTrue
,
1277 vol_props
[ndx
].row
);
1278 (void) strlcpy(buf
, STR_ST_TRUE
,
1281 (void) strlcpy(buf
, pstr
, MAX_TRUTHVAL_LEN
);
1284 } else if (propval
== ST_FALSE
) {
1285 ret
= snmp_get_str(hdl
,
1286 OID_sunPlatBinarySensorInterpretFalse
,
1287 vol_props
[ndx
].row
, &pstr
, &snmp_syserr
);
1288 if (snmp_syserr
== ECANCELED
) {
1289 (void) rw_unlock(&stale_tree_rwlp
);
1291 return (PICL_FAILURE
);
1293 if (ret
< 0 || pstr
== NULL
) {
1294 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1295 snmp_syserr
? snmp_syserr
: ret
,
1296 OID_sunPlatBinarySensorInterpretFalse
,
1297 vol_props
[ndx
].row
);
1298 (void) strlcpy(buf
, STR_ST_FALSE
,
1301 (void) strlcpy(buf
, pstr
, MAX_TRUTHVAL_LEN
);
1305 (void) rw_unlock(&stale_tree_rwlp
);
1306 log_msg(LOG_ERR
, SNMPP_INV_PLAT_BINSNSR_CURRENT
,
1307 propval
, vol_props
[ndx
].row
);
1308 return (PICL_FAILURE
);
1312 case VPT_ALARMSTATE
:
1313 if (propval
== SSAS_OFF
) {
1314 (void) strlcpy(buf
, STR_SSAS_OFF
, MAX_ALARMSTATE_LEN
);
1315 } else if (propval
== SSAS_STEADY
) {
1316 (void) strlcpy(buf
, STR_SSAS_STEADY
,
1317 MAX_ALARMSTATE_LEN
);
1318 } else if (propval
== SSAS_ALTERNATING
) {
1319 (void) strlcpy(buf
, STR_SSAS_ALTERNATING
,
1320 MAX_ALARMSTATE_LEN
);
1322 (void) strlcpy(buf
, STR_SSAS_UNKNOWN
,
1323 MAX_ALARMSTATE_LEN
);
1327 case VPT_BATTERYSTATUS
:
1330 (void) strlcpy(buf
, STR_SSBS_OTHER
,
1331 MAX_BATTERYSTATUS_LEN
);
1333 case SSBS_FULLYCHARGED
:
1334 (void) strlcpy(buf
, STR_SSBS_FULLYCHARGED
,
1335 MAX_BATTERYSTATUS_LEN
);
1338 (void) strlcpy(buf
, STR_SSBS_LOW
,
1339 MAX_BATTERYSTATUS_LEN
);
1342 (void) strlcpy(buf
, STR_SSBS_CRITICAL
,
1343 MAX_BATTERYSTATUS_LEN
);
1346 (void) strlcpy(buf
, STR_SSBS_CHARGING
,
1347 MAX_BATTERYSTATUS_LEN
);
1349 case SSBS_CHARGING_AND_LOW
:
1350 (void) strlcpy(buf
, STR_SSBS_CHARGING_AND_LOW
,
1351 MAX_BATTERYSTATUS_LEN
);
1353 case SSBS_CHARGING_AND_HIGH
:
1354 (void) strlcpy(buf
, STR_SSBS_CHARGING_AND_HIGH
,
1355 MAX_BATTERYSTATUS_LEN
);
1357 case SSBS_CHARGING_AND_CRITICAL
:
1358 (void) strlcpy(buf
, STR_SSBS_CHARGING_AND_CRITICAL
,
1359 MAX_BATTERYSTATUS_LEN
);
1361 case SSBS_UNDEFINED
:
1362 (void) strlcpy(buf
, STR_SSBS_UNDEFINED
,
1363 MAX_BATTERYSTATUS_LEN
);
1365 case SSBS_PARTIALLY_CHARGED
:
1366 (void) strlcpy(buf
, STR_SSBS_PARTIALLY_CHARGED
,
1367 MAX_BATTERYSTATUS_LEN
);
1371 (void) strlcpy(buf
, STR_SSBS_UNKNOWN
,
1372 MAX_BATTERYSTATUS_LEN
);
1378 (void) rw_unlock(&stale_tree_rwlp
);
1380 return (PICL_SUCCESS
);
1384 threshold(picl_nodehdl_t node
, char *oidstr
, int row
, char *propname
,
1387 picl_prophdl_t prop
;
1391 if ((err
= snmp_get_int(hdl
, oidstr
, row
, &val
, snmp_syserr_p
)) != -1) {
1392 err
= add_volatile_prop(node
, propname
, PICL_PTYPE_INT
,
1393 PICL_READ
, sizeof (int), read_volprop
, NULL
, &prop
);
1394 if (err
== PICL_SUCCESS
)
1395 save_volprop(prop
, oidstr
, row
, VPT_NUMSENSOR
);
1397 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1398 *snmp_syserr_p
? *snmp_syserr_p
: err
, oidstr
, row
);
1402 add_thresholds(picl_nodehdl_t node
, int row
, int *snmp_syserr_p
)
1404 uchar_t
*bitstr
= NULL
;
1409 ret
= snmp_get_str(hdl
,
1410 OID_sunPlatNumericSensorEnabledThresholds
,
1411 row
, (char **)&bitstr
, snmp_syserr_p
);
1413 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1414 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
1415 OID_sunPlatNumericSensorEnabledThresholds
, row
);
1417 nbytes
= strlen((const char *)bitstr
);
1420 CHECK_LINKRESET_VOID(snmp_syserr_p
);
1423 * No bit string of threshold masks was returned, so we can't
1424 * assume that any thresholds exist.
1426 * This mask prevents us from attempting to fetch thresholds
1427 * which don't apply to the sensor or that aren't there anyway,
1428 * That speeds up the plug-in significantly since otherwise it
1429 * takes several seconds to time out.
1431 if (ret
< 0 || bitstr
== NULL
|| nbytes
== 0 || 2 < nbytes
) {
1434 } else if (nbytes
== 1) {
1436 * The ALOM snmp agent doesn't adhere to the BER rules for
1437 * encoding bit strings. While the BER states that bitstrings
1438 * must begin from the second octet after length, and the
1439 * first octet after length must indicate the number of unused
1440 * bits in the last octet, the snmp agent simply sends the
1441 * bitstring data as if it were octet string -- that is, the
1442 * "unused bits" octet is missing.
1444 enabled
= bitstr
[0];
1445 } else if (nbytes
== 2)
1446 enabled
= bitstr
[1];
1452 if (enabled
& LOWER_FATAL
) {
1454 OID_sunPlatNumericSensorLowerThresholdFatal
, row
,
1455 PICL_PROP_LOW_POWER_OFF
, snmp_syserr_p
);
1456 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1458 if (enabled
& LOWER_CRITICAL
) {
1460 OID_sunPlatNumericSensorLowerThresholdCritical
, row
,
1461 PICL_PROP_LOW_SHUTDOWN
, snmp_syserr_p
);
1462 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1464 if (enabled
& LOWER_NON_CRITICAL
) {
1466 OID_sunPlatNumericSensorLowerThresholdNonCritical
, row
,
1467 PICL_PROP_LOW_WARNING
, snmp_syserr_p
);
1468 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1470 if (enabled
& UPPER_NON_CRITICAL
) {
1472 OID_sunPlatNumericSensorUpperThresholdNonCritical
, row
,
1473 PICL_PROP_HIGH_WARNING
, snmp_syserr_p
);
1474 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1476 if (enabled
& UPPER_CRITICAL
) {
1478 OID_sunPlatNumericSensorUpperThresholdCritical
, row
,
1479 PICL_PROP_HIGH_SHUTDOWN
, snmp_syserr_p
);
1480 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1482 if (enabled
& UPPER_FATAL
) {
1484 OID_sunPlatNumericSensorUpperThresholdFatal
, row
,
1485 PICL_PROP_HIGH_POWER_OFF
, snmp_syserr_p
);
1486 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1491 get_slot_type(int row
, int *snmp_syserr_p
)
1497 ret
= snmp_get_str(hdl
, OID_sunPlatEquipmentHolderAcceptableTypes
,
1498 row
, &p
, snmp_syserr_p
);
1499 CHECK_LINKRESET(snmp_syserr_p
, NULL
)
1501 if ((ret
== 0) && p
&& *p
) {
1503 if ((p
= strchr(slott
, '\n')) != NULL
)
1506 log_msg(LOG_WARNING
, SNMPP_NO_SLOT_TYPE
, row
);
1516 * Create and add the specified volatile property
1519 add_volatile_prop(picl_nodehdl_t node
, char *name
, int type
, int access
,
1520 int size
, int (*rdfunc
)(ptree_rarg_t
*, void *),
1521 int (*wrfunc
)(ptree_warg_t
*, const void *), picl_prophdl_t
*propp
)
1523 ptree_propinfo_t propinfo
;
1524 picl_prophdl_t prop
;
1527 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
1528 type
, (access
|PICL_VOLATILE
), size
, name
, rdfunc
, wrfunc
);
1529 if (err
!= PICL_SUCCESS
) {
1530 log_msg(LOG_ERR
, SNMPP_CANT_INIT_PROPINFO
, err
);
1534 err
= ptree_create_and_add_prop(node
, &propinfo
, NULL
, &prop
);
1535 if (err
!= PICL_SUCCESS
) {
1536 log_msg(LOG_ERR
, SNMPP_CANT_ADD_PROP
, err
, node
);
1543 return (PICL_SUCCESS
);
1547 * Add the specified string property to the node
1550 add_string_prop(picl_nodehdl_t node
, char *propname
, char *propval
)
1552 ptree_propinfo_t propinfo
;
1555 if (*propval
== '\0')
1556 return (PICL_SUCCESS
);
1558 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
1559 PICL_PTYPE_CHARSTRING
, PICL_READ
, strlen(propval
) + 1,
1560 propname
, NULL
, NULL
);
1561 if (err
!= PICL_SUCCESS
) {
1562 log_msg(LOG_ERR
, SNMPP_CANT_INIT_STR_PROPINFO
, err
);
1566 err
= ptree_create_and_add_prop(node
, &propinfo
, propval
, NULL
);
1567 if (err
!= PICL_SUCCESS
) {
1568 log_msg(LOG_ERR
, SNMPP_CANT_ADD_STR_PROP
, err
, node
);
1572 return (PICL_SUCCESS
);
1576 * Add the specified void property to the node
1579 add_void_prop(picl_nodehdl_t node
, char *propname
)
1581 ptree_propinfo_t propinfo
;
1584 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
1585 PICL_PTYPE_VOID
, PICL_READ
, 0, propname
, NULL
, NULL
);
1586 if (err
!= PICL_SUCCESS
) {
1587 log_msg(LOG_ERR
, SNMPP_CANT_INIT_VOID_PROPINFO
, err
);
1591 err
= ptree_create_and_add_prop(node
, &propinfo
, NULL
, NULL
);
1592 if (err
!= PICL_SUCCESS
) {
1593 log_msg(LOG_ERR
, SNMPP_CANT_ADD_VOID_PROP
, err
, node
);
1597 return (PICL_SUCCESS
);
1601 add_prop(picl_nodehdl_t nodeh
, picl_prophdl_t
*php
, char *label
,
1602 int row
, sp_propid_t pp
, int *snmp_syserr_p
)
1606 char *fw_revision
, *hw_revision
;
1607 char *mfg_name
, *model_name
;
1614 ret
= snmp_get_str(hdl
, OID_entPhysicalSerialNum
,
1615 row
, &serial_num
, snmp_syserr_p
);
1616 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1617 if ((ret
== 0) && serial_num
) {
1618 (void) add_string_prop(nodeh
,
1619 PICL_PROP_SERIAL_NUMBER
, serial_num
);
1620 free((void *) serial_num
);
1623 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1624 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
1625 OID_entPhysicalSerialNum
, row
);
1629 if ((slot_type
= get_slot_type(row
, snmp_syserr_p
)) == NULL
) {
1630 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1631 (void) add_string_prop(nodeh
,
1632 PICL_PROP_SLOT_TYPE
, DEFAULT_SLOT_TYPE
);
1634 (void) add_string_prop(nodeh
,
1635 PICL_PROP_SLOT_TYPE
, slot_type
);
1636 free((void *) slot_type
);
1641 ret
= add_volatile_prop(nodeh
, PICL_PROP_STATE
,
1642 PICL_PTYPE_CHARSTRING
, PICL_READ
, MAX_ALARMSTATE_LEN
,
1643 read_volprop
, NULL
, php
);
1644 if (ret
== PICL_SUCCESS
) {
1645 save_volprop(*php
, OID_sunPlatAlarmState
, row
,
1651 ret
= add_volatile_prop(nodeh
, PICL_PROP_OPERATIONAL_STATUS
,
1652 PICL_PTYPE_CHARSTRING
, PICL_READ
, MAX_OPSTATE_LEN
,
1653 read_volprop
, NULL
, php
);
1654 if (ret
== PICL_SUCCESS
) {
1656 OID_sunPlatEquipmentOperationalState
, row
,
1661 case PP_BATT_STATUS
:
1662 ret
= add_volatile_prop(nodeh
, PICL_PROP_BATTERY_STATUS
,
1663 PICL_PTYPE_CHARSTRING
, PICL_READ
, MAX_BATTERYSTATUS_LEN
,
1664 read_volprop
, NULL
, php
);
1665 if (ret
== PICL_SUCCESS
) {
1666 save_volprop(*php
, OID_sunPlatBatteryStatus
, row
,
1671 case PP_TEMPERATURE
:
1672 ret
= add_volatile_prop(nodeh
, PICL_PROP_TEMPERATURE
,
1673 PICL_PTYPE_INT
, PICL_READ
, sizeof (int), read_volprop
,
1675 if (ret
== PICL_SUCCESS
) {
1676 save_volprop(*php
, OID_sunPlatNumericSensorCurrent
,
1677 row
, VPT_NUMSENSOR
);
1682 ret
= add_volatile_prop(nodeh
, PICL_PROP_VOLTAGE
,
1683 PICL_PTYPE_INT
, PICL_READ
, sizeof (int), read_volprop
,
1685 if (ret
== PICL_SUCCESS
) {
1686 save_volprop(*php
, OID_sunPlatNumericSensorCurrent
,
1687 row
, VPT_NUMSENSOR
);
1692 ret
= add_volatile_prop(nodeh
, PICL_PROP_CURRENT
,
1693 PICL_PTYPE_INT
, PICL_READ
, sizeof (int), read_volprop
,
1695 if (ret
== PICL_SUCCESS
) {
1696 save_volprop(*php
, OID_sunPlatNumericSensorCurrent
,
1697 row
, VPT_NUMSENSOR
);
1702 ret
= add_volatile_prop(nodeh
, PICL_PROP_SPEED
, PICL_PTYPE_INT
,
1703 PICL_READ
, sizeof (int), read_volprop
, NULL
, php
);
1704 if (ret
== PICL_SUCCESS
) {
1705 save_volprop(*php
, OID_sunPlatNumericSensorCurrent
,
1706 row
, VPT_NUMSENSOR
);
1710 case PP_SENSOR_VALUE
:
1711 ret
= add_volatile_prop(nodeh
, PICL_PROP_SENSOR_VALUE
,
1712 PICL_PTYPE_INT
, PICL_READ
, sizeof (int), read_volprop
,
1714 if (ret
== PICL_SUCCESS
) {
1715 save_volprop(*php
, OID_sunPlatNumericSensorCurrent
,
1716 row
, VPT_NUMSENSOR
);
1721 ret
= add_volatile_prop(nodeh
, PICL_PROP_CONDITION
,
1722 PICL_PTYPE_CHARSTRING
, PICL_READ
, MAX_TRUTHVAL_LEN
,
1723 read_volprop
, NULL
, php
);
1724 if (ret
== PICL_SUCCESS
) {
1725 save_volprop(*php
, OID_sunPlatBinarySensorCurrent
,
1726 row
, VPT_BINSENSOR
);
1731 ret
= add_volatile_prop(nodeh
, PICL_PROP_EXPECTED
,
1732 PICL_PTYPE_CHARSTRING
, PICL_READ
, MAX_TRUTHVAL_LEN
,
1733 read_volprop
, NULL
, php
);
1734 if (ret
== PICL_SUCCESS
) {
1735 save_volprop(*php
, OID_sunPlatBinarySensorExpected
,
1736 row
, VPT_BINSENSOR
);
1741 ret
= add_volatile_prop(nodeh
, PICL_PROP_EXPONENT
,
1742 PICL_PTYPE_INT
, PICL_READ
, sizeof (int), read_volprop
,
1744 if (ret
== PICL_SUCCESS
) {
1745 save_volprop(*php
, OID_sunPlatNumericSensorExponent
,
1746 row
, VPT_NUMSENSOR
);
1750 case PP_REPLACEABLE
:
1751 ret
= snmp_get_int(hdl
, OID_sunPlatCircuitPackReplaceable
,
1752 row
, &val
, snmp_syserr_p
);
1753 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1754 if ((ret
== 0) && (val
== ST_TRUE
))
1755 (void) add_void_prop(nodeh
, PICL_PROP_IS_REPLACEABLE
);
1757 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1758 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
1759 OID_sunPlatCircuitPackReplaceable
, row
);
1762 case PP_HOTSWAPPABLE
:
1763 ret
= snmp_get_int(hdl
, OID_sunPlatCircuitPackHotSwappable
,
1764 row
, &val
, snmp_syserr_p
);
1765 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1766 if ((ret
== 0) && (val
== ST_TRUE
))
1767 (void) add_void_prop(nodeh
, PICL_PROP_IS_HOT_SWAPPABLE
);
1769 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1770 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
1771 OID_sunPlatCircuitPackHotSwappable
, row
);
1775 ret
= snmp_get_int(hdl
, OID_entPhysicalIsFRU
, row
,
1776 &val
, snmp_syserr_p
);
1777 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1778 if ((ret
== 0) && (val
== ST_TRUE
))
1779 (void) add_void_prop(nodeh
, PICL_PROP_IS_FRU
);
1781 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1782 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
1783 OID_entPhysicalIsFRU
, row
);
1786 case PP_HW_REVISION
:
1787 ret
= snmp_get_str(hdl
, OID_entPhysicalHardwareRev
,
1788 row
, &hw_revision
, snmp_syserr_p
);
1789 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1790 if ((ret
== 0) && hw_revision
) {
1791 (void) add_string_prop(nodeh
,
1792 PICL_PROP_HW_REVISION
, hw_revision
);
1793 free((void *) hw_revision
);
1796 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1797 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
1798 OID_entPhysicalHardwareRev
, row
);
1801 case PP_FW_REVISION
:
1802 ret
= snmp_get_str(hdl
, OID_entPhysicalFirmwareRev
,
1803 row
, &fw_revision
, snmp_syserr_p
);
1804 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1805 if ((ret
== 0) && fw_revision
) {
1806 (void) add_string_prop(nodeh
,
1807 PICL_PROP_FW_REVISION
, fw_revision
);
1808 free((void *) fw_revision
);
1811 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1812 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
1813 OID_entPhysicalFirmwareRev
, row
);
1817 ret
= snmp_get_str(hdl
, OID_entPhysicalMfgName
,
1818 row
, &mfg_name
, snmp_syserr_p
);
1819 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1820 if ((ret
== 0) && mfg_name
) {
1821 (void) add_string_prop(nodeh
,
1822 PICL_PROP_MFG_NAME
, mfg_name
);
1823 free((void *) mfg_name
);
1826 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1827 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
1828 OID_entPhysicalMfgName
, row
);
1832 ret
= snmp_get_str(hdl
, OID_entPhysicalModelName
,
1833 row
, &model_name
, snmp_syserr_p
);
1834 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1835 if ((ret
== 0) && model_name
) {
1836 (void) add_string_prop(nodeh
,
1837 PICL_PROP_MODEL_NAME
, model_name
);
1838 free((void *) model_name
);
1841 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1842 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
1843 OID_entPhysicalModelName
, row
);
1846 case PP_DESCRIPTION
:
1847 ret
= snmp_get_str(hdl
, OID_entPhysicalDescr
,
1848 row
, &phys_descr
, snmp_syserr_p
);
1849 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1850 if ((ret
== 0) && phys_descr
) {
1851 (void) add_string_prop(nodeh
,
1852 PICL_PROP_PHYS_DESCRIPTION
, phys_descr
);
1853 free((void *) phys_descr
);
1856 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1857 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
1858 OID_entPhysicalDescr
, row
);
1862 if (label
&& *label
)
1863 (void) add_string_prop(nodeh
, PICL_PROP_LABEL
, label
);
1867 ret
= snmp_get_int(hdl
, OID_sunPlatNumericSensorBaseUnits
,
1868 row
, &val
, snmp_syserr_p
);
1869 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1870 if ((ret
== 0) && (val
> 0) && (val
< n_baseunits
)) {
1871 (void) add_string_prop(nodeh
,
1872 PICL_PROP_BASE_UNITS
, sensor_baseunits
[val
]);
1875 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1876 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
1877 OID_sunPlatNumericSensorBaseUnits
, row
);
1881 ret
= snmp_get_int(hdl
, OID_sunPlatNumericSensorRateUnits
,
1882 row
, &val
, snmp_syserr_p
);
1883 CHECK_LINKRESET_VOID(snmp_syserr_p
)
1884 if ((ret
== 0) && (val
> 0) && (val
< n_rateunits
)) {
1885 (void) add_string_prop(nodeh
,
1886 PICL_PROP_RATE_UNITS
, sensor_rateunits
[val
]);
1889 log_msg(LOG_ERR
, SNMPP_CANT_FETCH_OBJECT_VAL
,
1890 *snmp_syserr_p
? *snmp_syserr_p
: ret
,
1891 OID_sunPlatNumericSensorRateUnits
, row
);
1897 * Initialize the SNMP library's cache refresh subsystem, then periodically
1898 * process refresh job to prevent cache entries from expiring.
1902 cache_refresher(void *arg
)
1905 int next_expiration
;
1907 hrtime_t cycle_start
, cycle_elapsed
;
1910 * Initialize refresh subsystem
1912 LOGPRINTF("Initializing SNMP refresh subsystem.\n");
1913 if (snmp_refresh_init() < 0) {
1914 return ((void *)-1);
1917 (void) mutex_lock(&cache_refresh_lock
);
1921 cycle_start
= gethrtime();
1924 * Process jobs from the snmp cache refresh work queue until one
1925 * of the following conditions is true:
1926 * 1) we are told to exit, or
1927 * 2) we have processed at least as many jobs as recommended by
1928 * the library, and the next job expiration is at least
1929 * CACHE_REFRESH_MIN_WINDOW * seconds away.
1931 jobs
= snmp_refresh_get_cycle_hint(CACHE_REFRESH_CYCLE
);
1932 while ((cache_refresh_thr_exit
== B_FALSE
) && (jobs
> 0)) {
1933 (void) snmp_refresh_process_job();
1937 next_expiration
= snmp_refresh_get_next_expiration();
1938 while ((cache_refresh_thr_exit
== B_FALSE
) &&
1939 ((next_expiration
>= 0) &&
1940 (next_expiration
< CACHE_REFRESH_MIN_WINDOW
))) {
1941 (void) snmp_refresh_process_job();
1942 next_expiration
= snmp_refresh_get_next_expiration();
1946 * As long as we haven't been told to exit, sleep for
1947 * CACHE_REFRESH_CYCLE seconds minus the amount of time that has
1948 * elapsed since this cycle started. If the elapsed time is
1949 * equal to or greater than 60 seconds, skip sleeping entirely.
1951 cycle_elapsed
= (gethrtime() - cycle_start
) / NANOSEC
;
1952 if ((cache_refresh_thr_exit
== B_FALSE
) &&
1953 (cycle_elapsed
< CACHE_REFRESH_CYCLE
)) {
1954 to
.tv_sec
= CACHE_REFRESH_CYCLE
- cycle_elapsed
;
1956 (void) cond_reltimedwait(&cache_refresh_cv
,
1957 &cache_refresh_lock
, &to
);
1961 * If we have been told to exit, clean up and bail out.
1963 if (cache_refresh_thr_exit
== B_TRUE
) {
1964 snmp_refresh_fini();
1965 (void) mutex_unlock(&cache_refresh_lock
);
1966 LOGPRINTF("cache_refresher: time to exit\n");
1977 * Check to see if the cache_refresher thread is running. If it is, signal it
1978 * to terminate and clean up associated data structures.
1981 cache_refresher_fini(void)
1983 /* if the thread isn't running, there is nothing to do */
1984 if (cache_refresh_thr_exit
== B_TRUE
)
1987 /* wake up the cache_refresher thread, tell it to exit */
1988 (void) mutex_lock(&cache_refresh_lock
);
1989 cache_refresh_thr_exit
= B_TRUE
;
1990 (void) cond_signal(&cache_refresh_cv
);
1991 (void) mutex_unlock(&cache_refresh_lock
);
1993 /* reap the thread */
1994 (void) thr_join(cache_refresh_thr_id
, NULL
, NULL
);
1996 /* finish cleanup... */
1997 (void) cond_destroy(&cache_refresh_cv
);
1998 (void) mutex_destroy(&cache_refresh_lock
);
2003 log_msg(int pri
, const char *fmt
, ...)
2008 vsyslog(pri
, fmt
, ap
);
2012 #ifdef SNMPPLUGIN_DEBUG
2015 snmpplugin_log_init(void)
2017 (void) mutex_init(&snmpplugin_dbuf_lock
, USYNC_THREAD
, NULL
);
2021 snmpplugin_log(const char *fmt
, ...)
2025 (void) mutex_lock(&snmpplugin_dbuf_lock
);
2028 (void) vsnprintf(snmpplugin_lbuf
, SNMPPLUGIN_DMAX_LINE
, fmt
, ap
);
2029 snmpplugin_log_append();
2032 (void) mutex_unlock(&snmpplugin_dbuf_lock
);
2036 snmpplugin_log_append(void)
2040 len
= strlen(snmpplugin_lbuf
);
2042 if ((snmpplugin_dbuf_curp
+ len
) >=
2043 (snmpplugin_dbuf
+ snmpplugin_dbuf_sz
)) {
2044 snmpplugin_dbuf_realloc();
2045 if (snmpplugin_dbuf
== NULL
) {
2050 (void) strcpy(snmpplugin_dbuf_curp
, snmpplugin_lbuf
);
2051 snmpplugin_dbuf_curp
+= len
;
2055 snmpplugin_dbuf_realloc(void)
2061 count
= snmpplugin_dbuf_sz
+ SNMPPLUGIN_DBLOCK_SZ
;
2062 if ((p
= (char *)calloc(count
, 1)) == NULL
) {
2063 snmpplugin_dbuf_overflow
++;
2064 snmpplugin_dbuf_curp
= snmpplugin_dbuf
;
2068 if (snmpplugin_dbuf
) {
2069 offset
= snmpplugin_dbuf_curp
- snmpplugin_dbuf
;
2070 (void) memcpy(p
, snmpplugin_dbuf
, snmpplugin_dbuf_sz
);
2071 free(snmpplugin_dbuf
);
2074 snmpplugin_dbuf
= p
;
2075 snmpplugin_dbuf_sz
+= SNMPPLUGIN_DBLOCK_SZ
;
2077 snmpplugin_dbuf_curp
= snmpplugin_dbuf
+ offset
;