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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 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 30 * by picl consumers. 31 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <syslog.h> 37 #include <stdarg.h> 38 #include <libgen.h> 39 #include <libintl.h> 40 #include <thread.h> 41 #include <synch.h> 42 #include <errno.h> 43 #include <time.h> 44 45 #include <picldefs.h> 46 #include <picl.h> 47 #include <picltree.h> 48 49 #include "picloids.h" 50 #include "libpiclsnmp.h" 51 #include "snmpplugin.h" 52 53 #pragma init(snmpplugin_register) /* place in .init section */ 54 55 picld_plugin_reg_t snmpplugin_reg = { 56 PICLD_PLUGIN_VERSION_1, 57 PICLD_PLUGIN_NON_CRITICAL, 58 "snmp_plugin", 59 snmpplugin_init, 60 snmpplugin_fini 61 }; 62 63 static picl_snmphdl_t hdl; 64 65 /* 66 * The stale_tree_rwlp protects the stale_xxx vars. The 'stale_tree' flag 67 * and the 'rebuild_tree' flag below are both initialized to B_TRUE to 68 * let the tree_builder() thread build the initial tree without blocking. 69 */ 70 static rwlock_t stale_tree_rwlp; 71 static boolean_t stale_tree = B_TRUE; 72 73 /* 74 * vol_props, volprop_ndx and n_vol_props are protected by the stale_tree 75 * flag. They are read only when the stale_tree flag is B_FALSE and written 76 * to only when the flag is B_TRUE. 77 * 78 * The change_time (last changed time) is read by only one thread at a 79 * time when stale_tree is B_FALSE (protected by stale_tree_rwlp). It is 80 * written by only one thread (the tree builder) when stale_tree is B_TRUE. 81 * 82 * Note that strictly speaking, change_time should be uint_t (timeticks32). 83 * But keeping it as int is fine, since we don't do any arithmetic on it 84 * except equality check. 85 */ 86 static vol_prophdl_t *vol_props = NULL; 87 static int volprop_ndx = 0, n_vol_props = 0; 88 static int change_time = 0; 89 static time_t change_time_check; 90 91 /* 92 * The rebuild_tree_lock and cv are used by the tree builder thread. 93 * rebuild_tree has to be initialized to B_TRUE to let the tree_builder 94 * do the first build without blocking. 95 */ 96 static mutex_t rebuild_tree_lock; 97 static cond_t rebuild_tree_cv; 98 static boolean_t rebuild_tree = B_TRUE; 99 static boolean_t tree_builder_thr_exit = B_FALSE; 100 static thread_t tree_builder_thr_id; 101 102 /* 103 * The cache_refresh thread periodically queries the snmp cache refresh work 104 * queue and processes jobs from it to keep cache entries from expiring. It 105 * attempts to run in cycles of CACHE_REFRESH_CYCLE seconds each, first 106 * processing cache refresh jobs and then sleeping for the remainder of the 107 * cycle once the next refresh job expiration is at least 108 * CACHE_REFRESH_MIN_WINDOW seconds in the future. 109 * 110 * NOTE: By using a thread to keep the SNMP cache refreshed in the background, 111 * we are both adding load to the system and reducing the system's ability to 112 * operate in power-saving mode when there is minimal load. While these 113 * tradeoffs are acceptable at this time in light of customer concerns about 114 * performance, it may be desirable in the future to move this work into the 115 * firmware. Also, while the current cycle times performed well on the largest 116 * sun4v config currently available (Batoka), they may need to be revisited for 117 * future systems if the number of sensors increases significantly. 118 */ 119 #define CACHE_REFRESH_CYCLE 60 120 #define CACHE_REFRESH_MIN_WINDOW 75 121 static mutex_t cache_refresh_lock; 122 static cond_t cache_refresh_cv; 123 static boolean_t cache_refresh_thr_exit = B_FALSE; 124 static thread_t cache_refresh_thr_id; 125 126 /* 127 * These two should really not be global 128 */ 129 static picl_nodehdl_t *physplat_nodes = NULL; 130 static int n_physplat_nodes = 0; 131 132 static char *group1[] = { 133 OID_entPhysicalDescr, 134 OID_entPhysicalContainedIn, 135 OID_entPhysicalClass, 136 OID_entPhysicalName, 137 OID_entPhysicalHardwareRev, 138 OID_entPhysicalFirmwareRev, 139 OID_entPhysicalSerialNum, 140 OID_entPhysicalMfgName, 141 OID_entPhysicalModelName, 142 OID_entPhysicalIsFRU, 143 0 144 }; 145 146 static char *group2[] = { 147 OID_sunPlatEquipmentHolderAcceptableTypes, 148 OID_sunPlatCircuitPackReplaceable, 149 OID_sunPlatCircuitPackHotSwappable, 150 OID_sunPlatPhysicalClass, 151 OID_sunPlatSensorClass, 152 OID_sunPlatSensorType, 153 OID_sunPlatAlarmType, 154 OID_sunPlatPowerSupplyClass, 155 0 156 }; 157 158 static char *group3[] = { 159 OID_sunPlatNumericSensorEnabledThresholds, 160 OID_sunPlatNumericSensorBaseUnits, 161 OID_sunPlatNumericSensorRateUnits, 162 0 163 }; 164 165 static char *group4[] = { 166 OID_sunPlatBinarySensorInterpretTrue, 167 OID_sunPlatBinarySensorInterpretFalse, 168 0 169 }; 170 171 static char *volgroup1[] = { 172 OID_sunPlatBinarySensorCurrent, 173 OID_sunPlatBinarySensorExpected, 174 0 175 }; 176 177 static char *volgroup2[] = { 178 OID_sunPlatNumericSensorExponent, 179 OID_sunPlatNumericSensorCurrent, 180 OID_sunPlatNumericSensorLowerThresholdFatal, 181 OID_sunPlatNumericSensorLowerThresholdCritical, 182 OID_sunPlatNumericSensorLowerThresholdNonCritical, 183 OID_sunPlatNumericSensorUpperThresholdNonCritical, 184 OID_sunPlatNumericSensorUpperThresholdCritical, 185 OID_sunPlatNumericSensorUpperThresholdFatal, 186 0 187 }; 188 189 static char *volgroup3[] = { 190 OID_sunPlatEquipmentOperationalState, 191 0 192 }; 193 194 static char *volgroup4[] = { 195 OID_sunPlatAlarmState, 196 0 197 }; 198 199 static char *volgroup5[] = { 200 OID_sunPlatBatteryStatus, 201 0 202 }; 203 204 /* 205 * The following two items must match the Sun Platform MIB specification 206 * in their indices and values. 207 */ 208 static char *sensor_baseunits[] = { 209 "", "other", "unknown", "degC", "degF", "degK", "volts", "amps", 210 "watts", "joules", "coulombs", "va", "nits", "lumens", "lux", 211 "candelas", "kPa", "psi", "newtons", "cfm", "rpm", "hertz", 212 "seconds", "minutes", "hours", "days", "weeks", "mils", "inches", 213 "feet", "cubicInches", "cubicFeet", "meters", "cubicCentimeters", 214 "cubicMeters", "liters", "fluidOunces", "radians", "steradians", 215 "revolutions", "cycles", "gravities", "ounces", "pounds", "footPounds", 216 "ounceInches", "gauss", "gilberts", "henries", "farads", "ohms", 217 "siemens", "moles", "becquerels", "ppm", "decibels", "dBA", "dbC", 218 "grays", "sieverts", "colorTemperatureDegK", "bits", "bytes", "words", 219 "doubleWords", "quadWords", "percentage" 220 }; 221 static const int n_baseunits = sizeof (sensor_baseunits) / sizeof (char *); 222 223 static char *sensor_rateunits[] = { 224 "", 225 "none", 226 "perMicroSecond", 227 "perMilliSecond", 228 "perSecond", 229 "perMinute", 230 "perHour", 231 "perDay", 232 "perWeek", 233 "perMonth", 234 "perYear" 235 }; 236 static const int n_rateunits = sizeof (sensor_rateunits) / sizeof (char *); 237 238 /* 239 * Local declarations 240 */ 241 static void snmpplugin_register(void); 242 static void register_group(char **g, int is_volatile); 243 static void *tree_builder(void *arg); 244 static int build_physplat(picl_nodehdl_t *subtree_rootp); 245 static void free_resources(picl_nodehdl_t subtree_root); 246 247 static picl_nodehdl_t make_node(picl_nodehdl_t subtree_root, int row, 248 int *snmp_syserr_p); 249 static void save_nodeh(picl_nodehdl_t nodeh, int row); 250 static picl_nodehdl_t lookup_nodeh(int row); 251 252 static void save_volprop(picl_prophdl_t prop, char *oidstr, int row, 253 int proptype); 254 static void check_for_stale_data(boolean_t nocache); 255 static int read_volprop(ptree_rarg_t *parg, void *buf); 256 257 static void threshold(picl_nodehdl_t node, char *oidstr, int row, 258 char *propname, int *snmp_syserr_p); 259 static void add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p); 260 261 static char *get_slot_type(int row, int *snmp_syserr_p); 262 static int add_volatile_prop(picl_nodehdl_t nodeh, char *name, 263 int type, int access, int size, int (*rdfunc)(ptree_rarg_t *, void *), 264 int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp); 265 static int add_string_prop(picl_nodehdl_t node, char *propname, char *propval); 266 static int add_void_prop(picl_nodehdl_t node, char *propname); 267 static void add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label, 268 int row, sp_propid_t pp, int *snmp_syserr_p); 269 270 static void *cache_refresher(void *arg); 271 static void cache_refresher_fini(void); 272 273 static void log_msg(int pri, const char *fmt, ...); 274 275 #ifdef SNMPPLUGIN_DEBUG 276 static mutex_t snmpplugin_dbuf_lock; 277 static char *snmpplugin_dbuf = NULL; 278 static char *snmpplugin_dbuf_curp = NULL; 279 static int snmpplugin_dbuf_sz = 0; 280 static int snmpplugin_dbuf_overflow = 0; 281 static char snmpplugin_lbuf[SNMPPLUGIN_DMAX_LINE]; 282 283 static void snmpplugin_log_init(void); 284 static void snmpplugin_log(const char *fmt, ...); 285 static void snmpplugin_log_append(void); 286 static void snmpplugin_dbuf_realloc(void); 287 #endif 288 289 static void 290 snmpplugin_register(void) 291 { 292 (void) picld_plugin_register(&snmpplugin_reg); 293 } 294 295 static void 296 register_group(char **g, int is_volatile) 297 { 298 int i, len = 0; 299 int n_oids; 300 char *p, *oidstrs; 301 302 for (i = 0; g[i]; i++) 303 len += strlen(g[i]) + 1; 304 n_oids = i; 305 306 if ((oidstrs = (char *)calloc(1, len)) == NULL) 307 return; 308 309 for (p = oidstrs, i = 0; g[i]; i++) { 310 (void) strcpy(p, g[i]); 311 p += strlen(g[i]) + 1; 312 } 313 314 snmp_register_group(hdl, oidstrs, n_oids, is_volatile); 315 free(oidstrs); 316 } 317 318 void 319 snmpplugin_init(void) 320 { 321 int ret; 322 323 (void) mutex_init(&rebuild_tree_lock, USYNC_THREAD, NULL); 324 (void) cond_init(&rebuild_tree_cv, USYNC_THREAD, NULL); 325 (void) rwlock_init(&stale_tree_rwlp, USYNC_THREAD, NULL); 326 tree_builder_thr_exit = B_FALSE; 327 328 LOGINIT(); 329 330 /* 331 * Create the tree-builder thread and let it take over 332 */ 333 LOGPRINTF("Tree-builder thread being created.\n"); 334 if ((ret = thr_create(NULL, NULL, tree_builder, NULL, 335 THR_BOUND, &tree_builder_thr_id)) < 0) { 336 log_msg(LOG_ERR, SNMPP_CANT_CREATE_TREE_BUILDER, ret); 337 snmp_fini(hdl); 338 hdl = NULL; 339 (void) rwlock_destroy(&stale_tree_rwlp); 340 (void) cond_destroy(&rebuild_tree_cv); 341 (void) mutex_destroy(&rebuild_tree_lock); 342 tree_builder_thr_exit = B_TRUE; 343 344 return; 345 } 346 347 /* 348 * While the cache refresher thread does improve performance, it is not 349 * integral to the proper function of the plugin. If we fail to create 350 * the thread for some reason, we will simply continue without 351 * refreshing. 352 */ 353 (void) mutex_init(&cache_refresh_lock, USYNC_THREAD, NULL); 354 (void) cond_init(&cache_refresh_cv, USYNC_THREAD, NULL); 355 cache_refresh_thr_exit = B_FALSE; 356 357 LOGPRINTF("Cache refresher thread being created.\n"); 358 if (thr_create(NULL, NULL, cache_refresher, NULL, THR_BOUND, 359 &cache_refresh_thr_id) < 0) { 360 (void) cond_destroy(&cache_refresh_cv); 361 (void) mutex_destroy(&cache_refresh_lock); 362 cache_refresh_thr_exit = B_TRUE; 363 } 364 } 365 366 void 367 snmpplugin_fini(void) 368 { 369 370 if (tree_builder_thr_exit == B_TRUE) 371 return; 372 373 /* 374 * Make reads of volatile properties return PICL_PROPUNAVAILABLE 375 * since we're about to recycle the plug-in. No need to worry 376 * about removing /physical-platform since tree_builder() will 377 * take care of recycling it for us. 378 */ 379 (void) rw_wrlock(&stale_tree_rwlp); 380 stale_tree = B_TRUE; 381 if (vol_props) { 382 free(vol_props); 383 } 384 vol_props = NULL; 385 volprop_ndx = 0; 386 n_vol_props = 0; 387 (void) rw_unlock(&stale_tree_rwlp); 388 389 /* clean up the cache_refresher thread and structures */ 390 cache_refresher_fini(); 391 392 /* wake up the tree_builder thread, tell it to exit */ 393 (void) mutex_lock(&rebuild_tree_lock); 394 rebuild_tree = B_TRUE; 395 tree_builder_thr_exit = B_TRUE; 396 (void) cond_signal(&rebuild_tree_cv); 397 (void) mutex_unlock(&rebuild_tree_lock); 398 399 /* reap the thread */ 400 (void) thr_join(tree_builder_thr_id, NULL, NULL); 401 402 /* close the channel */ 403 if (hdl != NULL) { 404 snmp_fini(hdl); 405 hdl = NULL; 406 } 407 408 /* finish cleanup... */ 409 (void) rwlock_destroy(&stale_tree_rwlp); 410 (void) cond_destroy(&rebuild_tree_cv); 411 (void) mutex_destroy(&rebuild_tree_lock); 412 } 413 414 /*ARGSUSED*/ 415 static void * 416 tree_builder(void *arg) 417 { 418 int ret, rv; 419 picl_nodehdl_t root_node; 420 picl_nodehdl_t physplat_root; 421 picl_nodehdl_t old_physplat_root; 422 423 /* 424 * Initialize SNMP service 425 */ 426 LOGPRINTF("Initializing SNMP service.\n"); 427 if ((hdl = snmp_init()) == NULL) { 428 log_msg(LOG_ERR, SNMPP_CANT_INIT); 429 return ((void *)-1); 430 } 431 432 /* 433 * Register OID groupings for BULKGET optimizations 434 */ 435 LOGPRINTF("Registering OID groups.\n"); 436 register_group(group1, 0); 437 register_group(group2, 0); 438 register_group(group3, 0); 439 register_group(group4, 0); 440 register_group(volgroup1, 1); 441 register_group(volgroup2, 1); 442 register_group(volgroup3, 1); 443 register_group(volgroup4, 1); 444 register_group(volgroup5, 1); 445 446 (void) mutex_lock(&rebuild_tree_lock); 447 448 for (;;) { 449 LOGPRINTF("tree_builder: check whether to rebuild subtree\n"); 450 while (rebuild_tree == B_FALSE) 451 (void) cond_wait(&rebuild_tree_cv, &rebuild_tree_lock); 452 453 LOGPRINTF("tree_builder: woke up\n"); 454 455 if (tree_builder_thr_exit == B_TRUE) { 456 (void) mutex_unlock(&rebuild_tree_lock); 457 LOGPRINTF("tree_builder: time to exit\n"); 458 return (NULL); 459 } 460 461 old_physplat_root = NULL; 462 physplat_root = NULL; 463 464 LOGPRINTF("tree_builder: getting root node\n"); 465 if ((ret = ptree_get_root(&root_node)) != PICL_SUCCESS) { 466 (void) mutex_unlock(&rebuild_tree_lock); 467 log_msg(LOG_ERR, SNMPP_NO_ROOT, ret); 468 return ((void *)-2); 469 } 470 471 LOGPRINTF("tree_builder: getting existing physplat node\n"); 472 rv = ptree_find_node(root_node, PICL_PROP_NAME, 473 PICL_PTYPE_CHARSTRING, PICL_NODE_PHYSPLAT, 474 sizeof (PICL_NODE_PHYSPLAT), &old_physplat_root); 475 476 LOGPRINTF("tree_builder: building physical-platform\n"); 477 if ((ret = build_physplat(&physplat_root)) < 0) { 478 (void) mutex_unlock(&rebuild_tree_lock); 479 log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret); 480 cache_refresher_fini(); 481 snmp_fini(hdl); 482 hdl = NULL; 483 return ((void *)-3); 484 } 485 486 if (rv == PICL_SUCCESS && old_physplat_root != NULL) { 487 LOGPRINTF("tree_builder: destroying existing nodes\n"); 488 ptree_delete_node(old_physplat_root); 489 ptree_destroy_node(old_physplat_root); 490 } 491 492 LOGPRINTF("tree_builder: attaching new subtree\n"); 493 if ((ret = ptree_add_node(root_node, physplat_root)) < 0) { 494 (void) mutex_unlock(&rebuild_tree_lock); 495 free_resources(physplat_root); 496 log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret); 497 cache_refresher_fini(); 498 snmp_fini(hdl); 499 hdl = NULL; 500 return ((void *)-4); 501 } 502 503 LOGPRINTF("tree_builder: setting stale_tree to FALSE\n"); 504 (void) rw_wrlock(&stale_tree_rwlp); 505 stale_tree = B_FALSE; 506 (void) rw_unlock(&stale_tree_rwlp); 507 508 LOGPRINTF("tree_builder: setting rebuild_tree to FALSE\n"); 509 rebuild_tree = B_FALSE; 510 } 511 512 /*NOTREACHED*/ 513 return (NULL); 514 } 515 516 static int 517 build_physplat(picl_nodehdl_t *subtree_rootp) 518 { 519 int change_time1; 520 int row, nxtrow; 521 int clr_linkreset = 0; 522 int ret = 0; 523 int snmp_syserr = 0; 524 525 retry: 526 (void) snmp_reinit(hdl, clr_linkreset); 527 clr_linkreset = 0; 528 529 /* 530 * Record LastChangeTime before we start building the tree 531 */ 532 ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, 533 &change_time1, &snmp_syserr); 534 if (ret < 0) { 535 if (snmp_syserr == ECANCELED) { 536 LOGPRINTF(SNMPP_LINK_RESET); 537 clr_linkreset = 1; 538 goto retry; 539 } 540 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 541 snmp_syserr ? snmp_syserr : ret, OID_entLastChangeTime, 0); 542 } 543 544 /* 545 * Create the physical-platform node 546 */ 547 ret = ptree_create_node(PICL_NODE_PHYSPLAT, PICL_CLASS_PICL, 548 subtree_rootp); 549 if (ret != PICL_SUCCESS) 550 return (-1); 551 552 /* 553 * Scan entPhysicalTable and build the "physical-platform" subtree 554 */ 555 ret = 0; 556 for (row = -1; ret == 0; row = nxtrow) { 557 ret = snmp_get_nextrow(hdl, OID_entPhysicalDescr, 558 row, &nxtrow, &snmp_syserr); 559 if (ret == 0) 560 (void) make_node(*subtree_rootp, nxtrow, &snmp_syserr); 561 switch (snmp_syserr) { 562 case ECANCELED: 563 /* 564 * If we get this error, a link reset must've 565 * happened and we need to throw away everything 566 * we have now and rebuild the tree again. 567 */ 568 log_msg(LOG_WARNING, SNMPP_LINK_RESET); 569 free_resources(*subtree_rootp); 570 clr_linkreset = 1; 571 goto retry; 572 /*NOTREACHED*/ 573 break; 574 case ENOSPC: /* end of MIB */ 575 LOGPRINTF("build_physplat: end of MIB\n"); 576 break; 577 case ENOENT: /* end of table */ 578 LOGPRINTF("build_physplat: end of table\n"); 579 break; 580 default: 581 /* 582 * make_node() will print messages so don't 583 * repeat that exercise here. 584 */ 585 if (ret == -1) { 586 log_msg(LOG_WARNING, 587 SNMPP_CANT_FETCH_OBJECT_VAL, 588 snmp_syserr ? snmp_syserr : ret, 589 OID_entPhysicalDescr, row); 590 } 591 } 592 } 593 594 /* 595 * Record LastChangeTime after we're done building the tree 596 */ 597 ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, 598 &change_time, &snmp_syserr); 599 if (ret < 0) { 600 if (snmp_syserr == ECANCELED) { 601 log_msg(LOG_WARNING, SNMPP_LINK_RESET); 602 free_resources(*subtree_rootp); 603 clr_linkreset = 1; 604 goto retry; 605 } else 606 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 607 snmp_syserr ? snmp_syserr : ret, 608 OID_entLastChangeTime, row); 609 } 610 611 /* 612 * If they don't match, some hotplugging must've happened, 613 * free resources we've created and still holding, then go 614 * back and retry 615 */ 616 if (change_time != change_time1) { 617 LOGPRINTF("build_physplat: entLastChangeTime has changed!\n"); 618 free_resources(*subtree_rootp); 619 change_time1 = change_time; 620 goto retry; 621 } 622 623 /* 624 * The physplat_nodes table is no longer needed, free it 625 */ 626 if (physplat_nodes) { 627 free(physplat_nodes); 628 physplat_nodes = NULL; 629 n_physplat_nodes = 0; 630 } 631 632 return (0); 633 } 634 635 /* 636 * Destroy all resources that were created during the building 637 * of the subtree 638 */ 639 static void 640 free_resources(picl_nodehdl_t subtree_root) 641 { 642 if (physplat_nodes) { 643 free(physplat_nodes); 644 physplat_nodes = NULL; 645 n_physplat_nodes = 0; 646 } 647 648 if (subtree_root) { 649 (void) ptree_delete_node(subtree_root); 650 (void) ptree_destroy_node(subtree_root); 651 } 652 653 if (vol_props) { 654 free(vol_props); 655 n_vol_props = 0; 656 volprop_ndx = 0; 657 } 658 } 659 660 static picl_nodehdl_t 661 make_node(picl_nodehdl_t subtree_root, int row, int *snmp_syserr_p) 662 { 663 picl_nodehdl_t nodeh, parenth; 664 picl_prophdl_t proph; 665 char *phys_name, *node_name; 666 int parent_row; 667 int ent_physclass, sunplat_physclass; 668 int sensor_class, sensor_type; 669 int alarm_type; 670 int ps_class; 671 int ret; 672 673 /* 674 * If we've already created this picl node, just return it 675 */ 676 if ((nodeh = lookup_nodeh(row)) != NULL) 677 return (nodeh); 678 679 /* 680 * If we are creating it only now, make sure we have the parent 681 * created first; if there's no parent, then parent it to the 682 * subtree's root node 683 */ 684 ret = snmp_get_int(hdl, OID_entPhysicalContainedIn, row, 685 &parent_row, snmp_syserr_p); 686 CHECK_LINKRESET(snmp_syserr_p, NULL) 687 if (ret < 0 || parent_row <= 0) 688 parenth = subtree_root; 689 else { 690 parenth = make_node(subtree_root, parent_row, snmp_syserr_p); 691 CHECK_LINKRESET(snmp_syserr_p, NULL) 692 if (parenth == NULL) 693 parenth = subtree_root; 694 } 695 696 /* 697 * Figure out the physical-platform node name from entPhysicalName; 698 * all rows in the MIB that have a valid entPhysicalIndex should 699 * have a physical name. 700 */ 701 ret = snmp_get_str(hdl, OID_entPhysicalName, row, 702 &phys_name, snmp_syserr_p); 703 CHECK_LINKRESET(snmp_syserr_p, NULL) 704 if (ret < 0 || phys_name == NULL) { 705 log_msg(LOG_WARNING, SNMPP_NO_ENTPHYSNAME, row); 706 return (NULL); 707 } 708 709 node_name = basename(phys_name); 710 711 ret = snmp_get_int(hdl, OID_entPhysicalClass, row, 712 &ent_physclass, snmp_syserr_p); 713 CHECK_LINKRESET(snmp_syserr_p, NULL) 714 if (ret < 0) { 715 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 716 *snmp_syserr_p ? *snmp_syserr_p : ret, 717 OID_entPhysicalClass, row); 718 free(phys_name); 719 return (NULL); 720 } 721 722 switch (ent_physclass) { 723 case SPC_OTHER: 724 ret = snmp_get_int(hdl, OID_sunPlatPhysicalClass, row, 725 &sunplat_physclass, snmp_syserr_p); 726 CHECK_LINKRESET(snmp_syserr_p, NULL) 727 if (ret < 0) { 728 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 729 *snmp_syserr_p ? *snmp_syserr_p : ret, 730 OID_sunPlatPhysicalClass, row); 731 free(phys_name); 732 return (NULL); 733 } 734 735 if (sunplat_physclass == SSPC_ALARM) { 736 ret = snmp_get_int(hdl, OID_sunPlatAlarmType, 737 row, &alarm_type, snmp_syserr_p); 738 CHECK_LINKRESET(snmp_syserr_p, NULL) 739 if (ret < 0) { 740 log_msg(LOG_WARNING, 741 SNMPP_CANT_FETCH_OBJECT_VAL, 742 *snmp_syserr_p ? *snmp_syserr_p : ret, 743 OID_sunPlatAlarmType, row); 744 free(phys_name); 745 return (NULL); 746 } 747 748 if (alarm_type == SSAT_VISIBLE) { 749 ADD_NODE(PICL_CLASS_LED) 750 } else { 751 ADD_NODE(PICL_CLASS_ALARM) 752 } 753 754 add_prop(nodeh, &proph, node_name, row, PP_STATE, 755 snmp_syserr_p); 756 CHECK_LINKRESET(snmp_syserr_p, NULL) 757 } else { 758 ADD_NODE(PICL_CLASS_OTHER) 759 } 760 761 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 762 snmp_syserr_p); 763 CHECK_LINKRESET(snmp_syserr_p, NULL) 764 break; 765 766 case SPC_UNKNOWN: 767 ADD_NODE(PICL_CLASS_UNKNOWN) 768 break; 769 770 case SPC_CHASSIS: 771 ADD_NODE(PICL_CLASS_CHASSIS) 772 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 773 snmp_syserr_p); 774 CHECK_LINKRESET(snmp_syserr_p, NULL) 775 break; 776 777 case SPC_BACKPLANE: 778 ADD_NODE(PICL_CLASS_BACKPLANE) 779 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 780 snmp_syserr_p); 781 CHECK_LINKRESET(snmp_syserr_p, NULL) 782 break; 783 784 case SPC_CONTAINER: 785 ADD_NODE(PICL_CLASS_CONTAINER) 786 787 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 788 snmp_syserr_p); 789 CHECK_LINKRESET(snmp_syserr_p, NULL) 790 791 add_prop(nodeh, &proph, node_name, row, PP_SLOT_TYPE, 792 snmp_syserr_p); 793 CHECK_LINKRESET(snmp_syserr_p, NULL) 794 break; 795 796 case SPC_POWERSUPPLY: 797 ret = snmp_get_int(hdl, OID_sunPlatPowerSupplyClass, 798 row, &ps_class, snmp_syserr_p); 799 CHECK_LINKRESET(snmp_syserr_p, NULL) 800 if (ret < 0) { 801 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 802 *snmp_syserr_p ? *snmp_syserr_p : ret, 803 OID_sunPlatPowerSupplyClass, row); 804 free(phys_name); 805 return (NULL); 806 } 807 808 if (ps_class == SSPSC_BATTERY) { 809 ADD_NODE(PICL_CLASS_BATTERY) 810 add_prop(nodeh, &proph, node_name, row, 811 PP_BATT_STATUS, snmp_syserr_p); 812 CHECK_LINKRESET(snmp_syserr_p, NULL) 813 } else { 814 ADD_NODE(PICL_CLASS_POWERSUPPLY) 815 } 816 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 817 snmp_syserr_p); 818 CHECK_LINKRESET(snmp_syserr_p, NULL) 819 break; 820 821 case SPC_FAN: 822 ADD_NODE(PICL_CLASS_FAN) 823 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 824 snmp_syserr_p); 825 CHECK_LINKRESET(snmp_syserr_p, NULL) 826 break; 827 828 case SPC_SENSOR: 829 ret = snmp_get_int(hdl, OID_sunPlatSensorClass, 830 row, &sensor_class, snmp_syserr_p); 831 CHECK_LINKRESET(snmp_syserr_p, NULL) 832 if (ret < 0) { 833 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 834 *snmp_syserr_p ? *snmp_syserr_p : ret, 835 OID_sunPlatSensorClass, row); 836 free(phys_name); 837 return (NULL); 838 } 839 840 ret = snmp_get_int(hdl, OID_sunPlatSensorType, 841 row, &sensor_type, snmp_syserr_p); 842 CHECK_LINKRESET(snmp_syserr_p, NULL) 843 if (ret < 0) { 844 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 845 *snmp_syserr_p ? *snmp_syserr_p : ret, 846 OID_sunPlatSensorType, row); 847 free(phys_name); 848 return (NULL); 849 } 850 851 if (sensor_class == SSSC_NUMERIC) { 852 if (sensor_type == SSST_TEMPERATURE) { 853 ADD_NODE(PICL_CLASS_TEMPERATURE_SENSOR) 854 add_prop(nodeh, &proph, node_name, row, 855 PP_TEMPERATURE, snmp_syserr_p); 856 } else if (sensor_type == SSST_VOLTAGE) { 857 ADD_NODE(PICL_CLASS_VOLTAGE_SENSOR) 858 add_prop(nodeh, &proph, node_name, row, 859 PP_VOLTAGE, snmp_syserr_p); 860 } else if (sensor_type == SSST_CURRENT) { 861 ADD_NODE(PICL_CLASS_CURRENT_SENSOR) 862 add_prop(nodeh, &proph, node_name, row, 863 PP_CURRENT, snmp_syserr_p); 864 } else if (sensor_type == SSST_TACHOMETER) { 865 ADD_NODE(PICL_CLASS_RPM_SENSOR) 866 add_prop(nodeh, &proph, node_name, row, 867 PP_SPEED, snmp_syserr_p); 868 } else { 869 ADD_NODE(PICL_CLASS_SENSOR) 870 add_prop(nodeh, &proph, node_name, row, 871 PP_SENSOR_VALUE, snmp_syserr_p); 872 } 873 CHECK_LINKRESET(snmp_syserr_p, NULL) 874 875 add_prop(nodeh, &proph, node_name, row, 876 PP_OPSTATUS, snmp_syserr_p); 877 CHECK_LINKRESET(snmp_syserr_p, NULL) 878 879 add_prop(nodeh, &proph, node_name, row, 880 PP_BASE_UNITS, snmp_syserr_p); 881 CHECK_LINKRESET(snmp_syserr_p, NULL) 882 883 add_prop(nodeh, &proph, node_name, row, 884 PP_EXPONENT, snmp_syserr_p); 885 CHECK_LINKRESET(snmp_syserr_p, NULL) 886 887 add_prop(nodeh, &proph, node_name, row, 888 PP_RATE_UNITS, snmp_syserr_p); 889 CHECK_LINKRESET(snmp_syserr_p, NULL) 890 891 add_thresholds(nodeh, row, snmp_syserr_p); 892 CHECK_LINKRESET(snmp_syserr_p, NULL) 893 894 } else if (sensor_class == SSSC_BINARY) { 895 if (sensor_type == SSST_TEMPERATURE) { 896 ADD_NODE(PICL_CLASS_TEMPERATURE_INDICATOR) 897 } else if (sensor_type == SSST_VOLTAGE) { 898 ADD_NODE(PICL_CLASS_VOLTAGE_INDICATOR) 899 } else if (sensor_type == SSST_CURRENT) { 900 ADD_NODE(PICL_CLASS_CURRENT_INDICATOR) 901 } else if (sensor_type == SSST_TACHOMETER) { 902 ADD_NODE(PICL_CLASS_RPM_INDICATOR) 903 } else if (sensor_type == SSST_PRESENCE) { 904 ADD_NODE(PICL_CLASS_PRESENCE_INDICATOR) 905 } else { 906 ADD_NODE(PICL_CLASS_INDICATOR) 907 } 908 909 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 910 snmp_syserr_p); 911 CHECK_LINKRESET(snmp_syserr_p, NULL) 912 913 add_prop(nodeh, &proph, node_name, row, PP_CONDITION, 914 snmp_syserr_p); 915 CHECK_LINKRESET(snmp_syserr_p, NULL) 916 917 add_prop(nodeh, &proph, node_name, row, PP_EXPECTED, 918 snmp_syserr_p); 919 CHECK_LINKRESET(snmp_syserr_p, NULL) 920 } else { 921 log_msg(LOG_ERR, 922 SNMPP_UNSUPP_SENSOR_CLASS, sensor_class, row); 923 return (NULL); 924 } 925 break; 926 927 case SPC_MODULE: 928 ADD_NODE(PICL_CLASS_MODULE) 929 930 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 931 snmp_syserr_p); 932 CHECK_LINKRESET(snmp_syserr_p, NULL) 933 934 add_prop(nodeh, &proph, node_name, row, PP_REPLACEABLE, 935 snmp_syserr_p); 936 CHECK_LINKRESET(snmp_syserr_p, NULL) 937 938 add_prop(nodeh, &proph, node_name, row, PP_HOTSWAPPABLE, 939 snmp_syserr_p); 940 CHECK_LINKRESET(snmp_syserr_p, NULL) 941 break; 942 943 case SPC_PORT: 944 ADD_NODE(PICL_CLASS_PORT) 945 break; 946 947 case SPC_STACK: 948 ADD_NODE(PICL_CLASS_STACK) 949 break; 950 951 default: 952 log_msg(LOG_WARNING, 953 SNMPP_UNKNOWN_ENTPHYSCLASS, ent_physclass, row); 954 free(phys_name); 955 return (NULL); 956 } 957 958 add_prop(nodeh, &proph, node_name, row, PP_DESCRIPTION, snmp_syserr_p); 959 CHECK_LINKRESET(snmp_syserr_p, NULL) 960 961 add_prop(nodeh, &proph, node_name, row, PP_LABEL, snmp_syserr_p); 962 CHECK_LINKRESET(snmp_syserr_p, NULL) 963 964 add_prop(nodeh, &proph, node_name, row, PP_HW_REVISION, snmp_syserr_p); 965 CHECK_LINKRESET(snmp_syserr_p, NULL) 966 967 add_prop(nodeh, &proph, node_name, row, PP_FW_REVISION, snmp_syserr_p); 968 CHECK_LINKRESET(snmp_syserr_p, NULL) 969 970 add_prop(nodeh, &proph, node_name, row, PP_SERIAL_NUM, snmp_syserr_p); 971 CHECK_LINKRESET(snmp_syserr_p, NULL) 972 973 add_prop(nodeh, &proph, node_name, row, PP_MFG_NAME, snmp_syserr_p); 974 CHECK_LINKRESET(snmp_syserr_p, NULL) 975 976 add_prop(nodeh, &proph, node_name, row, PP_MODEL_NAME, snmp_syserr_p); 977 CHECK_LINKRESET(snmp_syserr_p, NULL) 978 979 add_prop(nodeh, &proph, node_name, row, PP_IS_FRU, snmp_syserr_p); 980 CHECK_LINKRESET(snmp_syserr_p, NULL) 981 982 free(phys_name); 983 save_nodeh(nodeh, row); 984 985 return (nodeh); 986 } 987 988 /* 989 * Saves the node handle and the row id into physplat_nodes[]. If we're 990 * doing this in response to a hotplug event, we should've freed the 991 * old physplat_nodes before entering here to save the first node of the 992 * new physplat subtree. 993 */ 994 static void 995 save_nodeh(picl_nodehdl_t nodeh, int row) 996 { 997 size_t sz, count; 998 picl_nodehdl_t *p; 999 1000 if (row >= n_physplat_nodes) { 1001 count = (((size_t)row >> NODE_BLOCK_SHIFT) + 1) * 1002 N_ELEMS_IN_NODE_BLOCK; 1003 sz = count * sizeof (picl_nodehdl_t); 1004 1005 p = (picl_nodehdl_t *)calloc(count, sizeof (picl_nodehdl_t)); 1006 if (p == NULL) { 1007 log_msg(LOG_ERR, SNMPP_NO_MEM, sz); 1008 return; 1009 } 1010 1011 if (physplat_nodes) { 1012 (void) memcpy((void *) p, (void *) physplat_nodes, 1013 n_physplat_nodes * sizeof (picl_nodehdl_t)); 1014 free((void *) physplat_nodes); 1015 } 1016 1017 physplat_nodes = p; 1018 n_physplat_nodes = count; 1019 } 1020 1021 physplat_nodes[row] = nodeh; 1022 } 1023 1024 static picl_nodehdl_t 1025 lookup_nodeh(int row) 1026 { 1027 if (row >= n_physplat_nodes) 1028 return (NULL); 1029 1030 return (physplat_nodes[row]); 1031 } 1032 1033 /* 1034 * We enter this routine only when we are building the physical-platform 1035 * subtree, whether for the first time or in response to a hotplug event. 1036 * If we're here for rebuilding the tree, we have already set stale_tree 1037 * to be B_TRUE, so no one else would be accessing vol_props, n_vol_props 1038 * or volprop_ndx. If we're here to build the tree for the first time, 1039 * picld hasn't yet created doors and is running single-threaded, so no 1040 * one else would be accessing them anyway. 1041 */ 1042 static void 1043 save_volprop(picl_prophdl_t prop, char *oidstr, int row, int proptype) 1044 { 1045 vol_prophdl_t *p; 1046 int count; 1047 1048 if (volprop_ndx == n_vol_props) { 1049 count = n_vol_props + N_ELEMS_IN_VOLPROP_BLOCK; 1050 p = (vol_prophdl_t *)calloc(count, sizeof (vol_prophdl_t)); 1051 if (p == NULL) { 1052 log_msg(LOG_ERR, SNMPP_NO_MEM, 1053 count * sizeof (vol_prophdl_t)); 1054 return; 1055 } 1056 1057 if (vol_props) { 1058 (void) memcpy((void *) p, (void *) vol_props, 1059 n_vol_props * sizeof (vol_prophdl_t)); 1060 free((void *) vol_props); 1061 } 1062 1063 vol_props = p; 1064 n_vol_props += N_ELEMS_IN_VOLPROP_BLOCK; 1065 } 1066 1067 vol_props[volprop_ndx].prop = prop; 1068 vol_props[volprop_ndx].oidstr = oidstr; 1069 vol_props[volprop_ndx].row = row; 1070 vol_props[volprop_ndx].proptype = proptype; 1071 1072 volprop_ndx++; 1073 } 1074 1075 static void 1076 check_for_stale_data(boolean_t nocache) 1077 { 1078 int cur_change_time; 1079 int ret; 1080 int snmp_syserr; 1081 1082 (void) rw_wrlock(&stale_tree_rwlp); 1083 1084 /* 1085 * Check if some other thread beat us to it 1086 */ 1087 if (stale_tree == B_TRUE) { 1088 (void) rw_unlock(&stale_tree_rwlp); 1089 return; 1090 } 1091 1092 /* 1093 * Cache OID_entLastChangeTime for up to 10 seconds before 1094 * fetching it from ILOM again. This prevents us from fetching 1095 * this value from ILOM when the we're filling or refreshing a 1096 * whole bunch of items in the cache around the same time. 1097 */ 1098 if (nocache == B_FALSE && time(NULL) - change_time_check <= 10) { 1099 (void) rw_unlock(&stale_tree_rwlp); 1100 return; 1101 } 1102 1103 /* 1104 * Check if mib data has changed (hotplug? link-reset?) 1105 */ 1106 do { 1107 snmp_syserr = 0; 1108 ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, 1109 &cur_change_time, &snmp_syserr); 1110 (void) time(&change_time_check); 1111 if ((ret == 0) && (cur_change_time == change_time)) { 1112 (void) rw_unlock(&stale_tree_rwlp); 1113 return; 1114 } 1115 } while (ret != 0 && snmp_syserr == EINTR); 1116 1117 /* 1118 * If we can't read entLastChangeTime we assume we need to rebuild 1119 * the tree. This will also cover the case when we need to rebuild 1120 * the tree because a link reset had happened. 1121 */ 1122 LOGPRINTF2("check_for_stale_data: LastChange times have changed, " 1123 "(%#x != %#x)\n", change_time, cur_change_time); 1124 1125 /* 1126 * If the mib data has changed, we need to rebuild the physical-platform 1127 * subtree. To do this, we set a flag to mark the tree stale, 1128 * so that any future reads to get value of volatile properties will 1129 * return PICL_PROPVALUNAVAILABLE, until the stale_tree flag 1130 * is reset by the tree builder thread. 1131 */ 1132 stale_tree = B_TRUE; 1133 if (vol_props) { 1134 free(vol_props); 1135 } 1136 vol_props = NULL; 1137 volprop_ndx = 0; 1138 n_vol_props = 0; 1139 1140 (void) rw_unlock(&stale_tree_rwlp); 1141 1142 (void) mutex_lock(&rebuild_tree_lock); 1143 rebuild_tree = B_TRUE; 1144 (void) cond_signal(&rebuild_tree_cv); 1145 LOGPRINTF("check_for_stale_data: signalled tree builder\n"); 1146 (void) mutex_unlock(&rebuild_tree_lock); 1147 } 1148 1149 /* 1150 * This is the critical routine. This callback is invoked by picl whenever 1151 * it needs to fetch the value of a volatile property. The first thing we 1152 * must do, however, is to see if there has been a hotplug or a link-reset 1153 * event since the last time we built the tree and whether we need to 1154 * rebuild the tree. If so, we do whatever is necessary to make that happen, 1155 * but return PICL_PROPVALUNAVAILABLE for now, without making any further 1156 * snmp requests or accessing any globals. 1157 */ 1158 static int 1159 read_volprop(ptree_rarg_t *parg, void *buf) 1160 { 1161 char *pstr; 1162 int propval; 1163 int i, ndx; 1164 int ret; 1165 int snmp_syserr = 0; 1166 1167 /* 1168 * First check for any event that would make us throw away 1169 * the existing /physical-platform subtree and rebuild 1170 * another one. If we are rebuilding the subtree, we just 1171 * return the stale value until the tree is fully built. 1172 */ 1173 check_for_stale_data(B_FALSE); 1174 1175 (void) rw_rdlock(&stale_tree_rwlp); 1176 1177 if (stale_tree == B_TRUE) { 1178 (void) rw_unlock(&stale_tree_rwlp); 1179 return (PICL_PROPVALUNAVAILABLE); 1180 } 1181 1182 for (i = 0; i < volprop_ndx; i++) { 1183 if (vol_props[i].prop == parg->proph) { 1184 ndx = i; 1185 break; 1186 } 1187 } 1188 if (i == volprop_ndx) { 1189 (void) rw_unlock(&stale_tree_rwlp); 1190 log_msg(LOG_ERR, SNMPP_CANT_FIND_VOLPROP, parg->proph); 1191 return (PICL_FAILURE); 1192 } 1193 1194 /* 1195 * If we can't read the value, return failure. Even if this was 1196 * due to a link reset, between the check for stale data and now, 1197 * the next volatile callback by picl will initiate a tree-rebuild. 1198 */ 1199 ret = snmp_get_int(hdl, vol_props[ndx].oidstr, vol_props[ndx].row, 1200 &propval, &snmp_syserr); 1201 if (ret < 0) { 1202 (void) rw_unlock(&stale_tree_rwlp); 1203 check_for_stale_data(B_TRUE); 1204 if (stale_tree == B_TRUE) { 1205 return (PICL_PROPVALUNAVAILABLE); 1206 } 1207 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1208 snmp_syserr ? snmp_syserr : ret, 1209 vol_props[ndx].oidstr, vol_props[ndx].row); 1210 return (PICL_FAILURE); 1211 } 1212 1213 switch (vol_props[ndx].proptype) { 1214 case VPT_PLATOPSTATE: 1215 if (propval == SSOS_DISABLED) { 1216 (void) strlcpy(buf, STR_SSOS_DISABLED, MAX_OPSTATE_LEN); 1217 } else if (propval == SSOS_ENABLED) { 1218 (void) strlcpy(buf, STR_SSOS_ENABLED, MAX_OPSTATE_LEN); 1219 } else { 1220 (void) rw_unlock(&stale_tree_rwlp); 1221 log_msg(LOG_ERR, SNMPP_INV_PLAT_EQUIP_OPSTATE, 1222 propval, vol_props[ndx].row); 1223 return (PICL_FAILURE); 1224 } 1225 break; 1226 1227 case VPT_NUMSENSOR: 1228 (void) memcpy(buf, &propval, sizeof (propval)); 1229 break; 1230 1231 case VPT_BINSENSOR: 1232 if (propval == ST_TRUE) { 1233 ret = snmp_get_str(hdl, 1234 OID_sunPlatBinarySensorInterpretTrue, 1235 vol_props[ndx].row, &pstr, &snmp_syserr); 1236 if (snmp_syserr == ECANCELED) { 1237 (void) rw_unlock(&stale_tree_rwlp); 1238 if (pstr) 1239 free(pstr); 1240 return (PICL_FAILURE); 1241 } 1242 if (ret < 0 || pstr == NULL) { 1243 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1244 snmp_syserr ? snmp_syserr : ret, 1245 OID_sunPlatBinarySensorInterpretTrue, 1246 vol_props[ndx].row); 1247 (void) strlcpy(buf, STR_ST_TRUE, 1248 MAX_TRUTHVAL_LEN); 1249 } else { 1250 (void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN); 1251 } 1252 if (pstr) 1253 free(pstr); 1254 } else if (propval == ST_FALSE) { 1255 ret = snmp_get_str(hdl, 1256 OID_sunPlatBinarySensorInterpretFalse, 1257 vol_props[ndx].row, &pstr, &snmp_syserr); 1258 if (snmp_syserr == ECANCELED) { 1259 (void) rw_unlock(&stale_tree_rwlp); 1260 if (pstr) 1261 free(pstr); 1262 return (PICL_FAILURE); 1263 } 1264 if (ret < 0 || pstr == NULL) { 1265 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1266 snmp_syserr ? snmp_syserr : ret, 1267 OID_sunPlatBinarySensorInterpretFalse, 1268 vol_props[ndx].row); 1269 (void) strlcpy(buf, STR_ST_FALSE, 1270 MAX_TRUTHVAL_LEN); 1271 } else { 1272 (void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN); 1273 } 1274 if (pstr) 1275 free(pstr); 1276 } else { 1277 (void) rw_unlock(&stale_tree_rwlp); 1278 log_msg(LOG_ERR, SNMPP_INV_PLAT_BINSNSR_CURRENT, 1279 propval, vol_props[ndx].row); 1280 return (PICL_FAILURE); 1281 } 1282 break; 1283 1284 case VPT_ALARMSTATE: 1285 if (propval == SSAS_OFF) { 1286 (void) strlcpy(buf, STR_SSAS_OFF, MAX_ALARMSTATE_LEN); 1287 } else if (propval == SSAS_STEADY) { 1288 (void) strlcpy(buf, STR_SSAS_STEADY, 1289 MAX_ALARMSTATE_LEN); 1290 } else if (propval == SSAS_ALTERNATING) { 1291 (void) strlcpy(buf, STR_SSAS_ALTERNATING, 1292 MAX_ALARMSTATE_LEN); 1293 } else { 1294 (void) strlcpy(buf, STR_SSAS_UNKNOWN, 1295 MAX_ALARMSTATE_LEN); 1296 } 1297 break; 1298 1299 case VPT_BATTERYSTATUS: 1300 switch (propval) { 1301 case SSBS_OTHER: 1302 (void) strlcpy(buf, STR_SSBS_OTHER, 1303 MAX_BATTERYSTATUS_LEN); 1304 break; 1305 case SSBS_FULLYCHARGED: 1306 (void) strlcpy(buf, STR_SSBS_FULLYCHARGED, 1307 MAX_BATTERYSTATUS_LEN); 1308 break; 1309 case SSBS_LOW: 1310 (void) strlcpy(buf, STR_SSBS_LOW, 1311 MAX_BATTERYSTATUS_LEN); 1312 break; 1313 case SSBS_CRITICAL: 1314 (void) strlcpy(buf, STR_SSBS_CRITICAL, 1315 MAX_BATTERYSTATUS_LEN); 1316 break; 1317 case SSBS_CHARGING: 1318 (void) strlcpy(buf, STR_SSBS_CHARGING, 1319 MAX_BATTERYSTATUS_LEN); 1320 break; 1321 case SSBS_CHARGING_AND_LOW: 1322 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_LOW, 1323 MAX_BATTERYSTATUS_LEN); 1324 break; 1325 case SSBS_CHARGING_AND_HIGH: 1326 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_HIGH, 1327 MAX_BATTERYSTATUS_LEN); 1328 break; 1329 case SSBS_CHARGING_AND_CRITICAL: 1330 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_CRITICAL, 1331 MAX_BATTERYSTATUS_LEN); 1332 break; 1333 case SSBS_UNDEFINED: 1334 (void) strlcpy(buf, STR_SSBS_UNDEFINED, 1335 MAX_BATTERYSTATUS_LEN); 1336 break; 1337 case SSBS_PARTIALLY_CHARGED: 1338 (void) strlcpy(buf, STR_SSBS_PARTIALLY_CHARGED, 1339 MAX_BATTERYSTATUS_LEN); 1340 break; 1341 case SSBS_UNKNOWN: 1342 default: 1343 (void) strlcpy(buf, STR_SSBS_UNKNOWN, 1344 MAX_BATTERYSTATUS_LEN); 1345 break; 1346 } 1347 break; 1348 } 1349 1350 (void) rw_unlock(&stale_tree_rwlp); 1351 1352 return (PICL_SUCCESS); 1353 } 1354 1355 static void 1356 threshold(picl_nodehdl_t node, char *oidstr, int row, char *propname, 1357 int *snmp_syserr_p) 1358 { 1359 picl_prophdl_t prop; 1360 int err; 1361 int val; 1362 1363 if ((err = snmp_get_int(hdl, oidstr, row, &val, snmp_syserr_p)) != -1) { 1364 err = add_volatile_prop(node, propname, PICL_PTYPE_INT, 1365 PICL_READ, sizeof (int), read_volprop, NULL, &prop); 1366 if (err == PICL_SUCCESS) 1367 save_volprop(prop, oidstr, row, VPT_NUMSENSOR); 1368 } else 1369 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1370 *snmp_syserr_p ? *snmp_syserr_p : err, oidstr, row); 1371 } 1372 1373 static void 1374 add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p) 1375 { 1376 uchar_t *bitstr = NULL; 1377 uchar_t enabled; 1378 uint_t nbytes; 1379 int ret; 1380 1381 ret = snmp_get_str(hdl, 1382 OID_sunPlatNumericSensorEnabledThresholds, 1383 row, (char **)&bitstr, snmp_syserr_p); 1384 if (ret == -1) { 1385 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1386 *snmp_syserr_p ? *snmp_syserr_p : ret, 1387 OID_sunPlatNumericSensorEnabledThresholds, row); 1388 } else { 1389 nbytes = strlen((const char *)bitstr); 1390 } 1391 1392 CHECK_LINKRESET_VOID(snmp_syserr_p); 1393 1394 /* 1395 * No bit string of threshold masks was returned, so we can't 1396 * assume that any thresholds exist. 1397 * 1398 * This mask prevents us from attempting to fetch thresholds 1399 * which don't apply to the sensor or that aren't there anyway, 1400 * That speeds up the plug-in significantly since otherwise it 1401 * takes several seconds to time out. 1402 */ 1403 if (ret < 0 || bitstr == NULL || nbytes == 0 || 2 < nbytes) { 1404 if (bitstr) 1405 free(bitstr); 1406 return; 1407 } else if (nbytes == 1) { 1408 /* 1409 * The ALOM snmp agent doesn't adhere to the BER rules for 1410 * encoding bit strings. While the BER states that bitstrings 1411 * must begin from the second octet after length, and the 1412 * first octet after length must indicate the number of unused 1413 * bits in the last octet, the snmp agent simply sends the 1414 * bitstring data as if it were octet string -- that is, the 1415 * "unused bits" octet is missing. 1416 */ 1417 enabled = bitstr[0]; 1418 } else if (nbytes == 2) 1419 enabled = bitstr[1]; 1420 1421 if (bitstr) { 1422 free(bitstr); 1423 } 1424 1425 if (enabled & LOWER_FATAL) { 1426 threshold(node, 1427 OID_sunPlatNumericSensorLowerThresholdFatal, row, 1428 PICL_PROP_LOW_POWER_OFF, snmp_syserr_p); 1429 CHECK_LINKRESET_VOID(snmp_syserr_p) 1430 } 1431 if (enabled & LOWER_CRITICAL) { 1432 threshold(node, 1433 OID_sunPlatNumericSensorLowerThresholdCritical, row, 1434 PICL_PROP_LOW_SHUTDOWN, snmp_syserr_p); 1435 CHECK_LINKRESET_VOID(snmp_syserr_p) 1436 } 1437 if (enabled & LOWER_NON_CRITICAL) { 1438 threshold(node, 1439 OID_sunPlatNumericSensorLowerThresholdNonCritical, row, 1440 PICL_PROP_LOW_WARNING, snmp_syserr_p); 1441 CHECK_LINKRESET_VOID(snmp_syserr_p) 1442 } 1443 if (enabled & UPPER_NON_CRITICAL) { 1444 threshold(node, 1445 OID_sunPlatNumericSensorUpperThresholdNonCritical, row, 1446 PICL_PROP_HIGH_WARNING, snmp_syserr_p); 1447 CHECK_LINKRESET_VOID(snmp_syserr_p) 1448 } 1449 if (enabled & UPPER_CRITICAL) { 1450 threshold(node, 1451 OID_sunPlatNumericSensorUpperThresholdCritical, row, 1452 PICL_PROP_HIGH_SHUTDOWN, snmp_syserr_p); 1453 CHECK_LINKRESET_VOID(snmp_syserr_p) 1454 } 1455 if (enabled & UPPER_FATAL) { 1456 threshold(node, 1457 OID_sunPlatNumericSensorUpperThresholdFatal, row, 1458 PICL_PROP_HIGH_POWER_OFF, snmp_syserr_p); 1459 CHECK_LINKRESET_VOID(snmp_syserr_p) 1460 } 1461 } 1462 1463 static char * 1464 get_slot_type(int row, int *snmp_syserr_p) 1465 { 1466 char *p; 1467 char *slott = NULL; 1468 int ret; 1469 1470 ret = snmp_get_str(hdl, OID_sunPlatEquipmentHolderAcceptableTypes, 1471 row, &p, snmp_syserr_p); 1472 CHECK_LINKRESET(snmp_syserr_p, NULL) 1473 1474 if ((ret == 0) && p && *p) { 1475 slott = p; 1476 if ((p = strchr(slott, '\n')) != NULL) 1477 *p = 0; 1478 } else { 1479 log_msg(LOG_WARNING, SNMPP_NO_SLOT_TYPE, row); 1480 if (p) { 1481 free(p); 1482 } 1483 } 1484 1485 return (slott); 1486 } 1487 1488 /* 1489 * Create and add the specified volatile property 1490 */ 1491 static int 1492 add_volatile_prop(picl_nodehdl_t node, char *name, int type, int access, 1493 int size, int (*rdfunc)(ptree_rarg_t *, void *), 1494 int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp) 1495 { 1496 ptree_propinfo_t propinfo; 1497 picl_prophdl_t prop; 1498 int err; 1499 1500 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1501 type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc); 1502 if (err != PICL_SUCCESS) { 1503 log_msg(LOG_ERR, SNMPP_CANT_INIT_PROPINFO, err); 1504 return (err); 1505 } 1506 1507 err = ptree_create_and_add_prop(node, &propinfo, NULL, &prop); 1508 if (err != PICL_SUCCESS) { 1509 log_msg(LOG_ERR, SNMPP_CANT_ADD_PROP, err, node); 1510 return (err); 1511 } 1512 1513 if (propp) 1514 *propp = prop; 1515 1516 return (PICL_SUCCESS); 1517 } 1518 1519 /* 1520 * Add the specified string property to the node 1521 */ 1522 static int 1523 add_string_prop(picl_nodehdl_t node, char *propname, char *propval) 1524 { 1525 ptree_propinfo_t propinfo; 1526 int err; 1527 1528 if (*propval == '\0') 1529 return (PICL_SUCCESS); 1530 1531 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1532 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(propval) + 1, 1533 propname, NULL, NULL); 1534 if (err != PICL_SUCCESS) { 1535 log_msg(LOG_ERR, SNMPP_CANT_INIT_STR_PROPINFO, err); 1536 return (err); 1537 } 1538 1539 err = ptree_create_and_add_prop(node, &propinfo, propval, NULL); 1540 if (err != PICL_SUCCESS) { 1541 log_msg(LOG_ERR, SNMPP_CANT_ADD_STR_PROP, err, node); 1542 return (err); 1543 } 1544 1545 return (PICL_SUCCESS); 1546 } 1547 1548 /* 1549 * Add the specified void property to the node 1550 */ 1551 static int 1552 add_void_prop(picl_nodehdl_t node, char *propname) 1553 { 1554 ptree_propinfo_t propinfo; 1555 int err; 1556 1557 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1558 PICL_PTYPE_VOID, PICL_READ, 0, propname, NULL, NULL); 1559 if (err != PICL_SUCCESS) { 1560 log_msg(LOG_ERR, SNMPP_CANT_INIT_VOID_PROPINFO, err); 1561 return (err); 1562 } 1563 1564 err = ptree_create_and_add_prop(node, &propinfo, NULL, NULL); 1565 if (err != PICL_SUCCESS) { 1566 log_msg(LOG_ERR, SNMPP_CANT_ADD_VOID_PROP, err, node); 1567 return (err); 1568 } 1569 1570 return (PICL_SUCCESS); 1571 } 1572 1573 static void 1574 add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label, 1575 int row, sp_propid_t pp, int *snmp_syserr_p) 1576 { 1577 char *serial_num; 1578 char *slot_type; 1579 char *fw_revision, *hw_revision; 1580 char *mfg_name, *model_name; 1581 char *phys_descr; 1582 int val; 1583 int ret; 1584 1585 switch (pp) { 1586 case PP_SERIAL_NUM: 1587 ret = snmp_get_str(hdl, OID_entPhysicalSerialNum, 1588 row, &serial_num, snmp_syserr_p); 1589 CHECK_LINKRESET_VOID(snmp_syserr_p) 1590 if ((ret == 0) && serial_num) { 1591 (void) add_string_prop(nodeh, 1592 PICL_PROP_SERIAL_NUMBER, serial_num); 1593 free((void *) serial_num); 1594 } 1595 if (ret == -1) 1596 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1597 *snmp_syserr_p ? *snmp_syserr_p : ret, 1598 OID_entPhysicalSerialNum, row); 1599 break; 1600 1601 case PP_SLOT_TYPE: 1602 if ((slot_type = get_slot_type(row, snmp_syserr_p)) == NULL) { 1603 CHECK_LINKRESET_VOID(snmp_syserr_p) 1604 (void) add_string_prop(nodeh, 1605 PICL_PROP_SLOT_TYPE, DEFAULT_SLOT_TYPE); 1606 } else { 1607 (void) add_string_prop(nodeh, 1608 PICL_PROP_SLOT_TYPE, slot_type); 1609 free((void *) slot_type); 1610 } 1611 break; 1612 1613 case PP_STATE: 1614 ret = add_volatile_prop(nodeh, PICL_PROP_STATE, 1615 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_ALARMSTATE_LEN, 1616 read_volprop, NULL, php); 1617 if (ret == PICL_SUCCESS) { 1618 save_volprop(*php, OID_sunPlatAlarmState, row, 1619 VPT_ALARMSTATE); 1620 } 1621 break; 1622 1623 case PP_OPSTATUS: 1624 ret = add_volatile_prop(nodeh, PICL_PROP_OPERATIONAL_STATUS, 1625 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_OPSTATE_LEN, 1626 read_volprop, NULL, php); 1627 if (ret == PICL_SUCCESS) { 1628 save_volprop(*php, 1629 OID_sunPlatEquipmentOperationalState, row, 1630 VPT_PLATOPSTATE); 1631 } 1632 break; 1633 1634 case PP_BATT_STATUS: 1635 ret = add_volatile_prop(nodeh, PICL_PROP_BATTERY_STATUS, 1636 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_BATTERYSTATUS_LEN, 1637 read_volprop, NULL, php); 1638 if (ret == PICL_SUCCESS) { 1639 save_volprop(*php, OID_sunPlatBatteryStatus, row, 1640 VPT_BATTERYSTATUS); 1641 } 1642 break; 1643 1644 case PP_TEMPERATURE: 1645 ret = add_volatile_prop(nodeh, PICL_PROP_TEMPERATURE, 1646 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1647 NULL, php); 1648 if (ret == PICL_SUCCESS) { 1649 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1650 row, VPT_NUMSENSOR); 1651 } 1652 break; 1653 1654 case PP_VOLTAGE: 1655 ret = add_volatile_prop(nodeh, PICL_PROP_VOLTAGE, 1656 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1657 NULL, php); 1658 if (ret == PICL_SUCCESS) { 1659 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1660 row, VPT_NUMSENSOR); 1661 } 1662 break; 1663 1664 case PP_CURRENT: 1665 ret = add_volatile_prop(nodeh, PICL_PROP_CURRENT, 1666 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1667 NULL, php); 1668 if (ret == PICL_SUCCESS) { 1669 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1670 row, VPT_NUMSENSOR); 1671 } 1672 break; 1673 1674 case PP_SPEED: 1675 ret = add_volatile_prop(nodeh, PICL_PROP_SPEED, PICL_PTYPE_INT, 1676 PICL_READ, sizeof (int), read_volprop, NULL, php); 1677 if (ret == PICL_SUCCESS) { 1678 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1679 row, VPT_NUMSENSOR); 1680 } 1681 break; 1682 1683 case PP_SENSOR_VALUE: 1684 ret = add_volatile_prop(nodeh, PICL_PROP_SENSOR_VALUE, 1685 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1686 NULL, php); 1687 if (ret == PICL_SUCCESS) { 1688 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1689 row, VPT_NUMSENSOR); 1690 } 1691 break; 1692 1693 case PP_CONDITION: 1694 ret = add_volatile_prop(nodeh, PICL_PROP_CONDITION, 1695 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN, 1696 read_volprop, NULL, php); 1697 if (ret == PICL_SUCCESS) { 1698 save_volprop(*php, OID_sunPlatBinarySensorCurrent, 1699 row, VPT_BINSENSOR); 1700 } 1701 break; 1702 1703 case PP_EXPECTED: 1704 ret = add_volatile_prop(nodeh, PICL_PROP_EXPECTED, 1705 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN, 1706 read_volprop, NULL, php); 1707 if (ret == PICL_SUCCESS) { 1708 save_volprop(*php, OID_sunPlatBinarySensorExpected, 1709 row, VPT_BINSENSOR); 1710 } 1711 break; 1712 1713 case PP_EXPONENT: 1714 ret = add_volatile_prop(nodeh, PICL_PROP_EXPONENT, 1715 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1716 NULL, php); 1717 if (ret == PICL_SUCCESS) { 1718 save_volprop(*php, OID_sunPlatNumericSensorExponent, 1719 row, VPT_NUMSENSOR); 1720 } 1721 break; 1722 1723 case PP_REPLACEABLE: 1724 ret = snmp_get_int(hdl, OID_sunPlatCircuitPackReplaceable, 1725 row, &val, snmp_syserr_p); 1726 CHECK_LINKRESET_VOID(snmp_syserr_p) 1727 if ((ret == 0) && (val == ST_TRUE)) 1728 (void) add_void_prop(nodeh, PICL_PROP_IS_REPLACEABLE); 1729 if (ret == -1) 1730 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1731 *snmp_syserr_p ? *snmp_syserr_p : ret, 1732 OID_sunPlatCircuitPackReplaceable, row); 1733 break; 1734 1735 case PP_HOTSWAPPABLE: 1736 ret = snmp_get_int(hdl, OID_sunPlatCircuitPackHotSwappable, 1737 row, &val, snmp_syserr_p); 1738 CHECK_LINKRESET_VOID(snmp_syserr_p) 1739 if ((ret == 0) && (val == ST_TRUE)) 1740 (void) add_void_prop(nodeh, PICL_PROP_IS_HOT_SWAPPABLE); 1741 if (ret == -1) 1742 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1743 *snmp_syserr_p ? *snmp_syserr_p : ret, 1744 OID_sunPlatCircuitPackHotSwappable, row); 1745 break; 1746 1747 case PP_IS_FRU: 1748 ret = snmp_get_int(hdl, OID_entPhysicalIsFRU, row, 1749 &val, snmp_syserr_p); 1750 CHECK_LINKRESET_VOID(snmp_syserr_p) 1751 if ((ret == 0) && (val == ST_TRUE)) 1752 (void) add_void_prop(nodeh, PICL_PROP_IS_FRU); 1753 if (ret == -1) 1754 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1755 *snmp_syserr_p ? *snmp_syserr_p : ret, 1756 OID_entPhysicalIsFRU, row); 1757 break; 1758 1759 case PP_HW_REVISION: 1760 ret = snmp_get_str(hdl, OID_entPhysicalHardwareRev, 1761 row, &hw_revision, snmp_syserr_p); 1762 CHECK_LINKRESET_VOID(snmp_syserr_p) 1763 if ((ret == 0) && hw_revision) { 1764 (void) add_string_prop(nodeh, 1765 PICL_PROP_HW_REVISION, hw_revision); 1766 free((void *) hw_revision); 1767 } 1768 if (ret == -1) 1769 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1770 *snmp_syserr_p ? *snmp_syserr_p : ret, 1771 OID_entPhysicalHardwareRev, row); 1772 break; 1773 1774 case PP_FW_REVISION: 1775 ret = snmp_get_str(hdl, OID_entPhysicalFirmwareRev, 1776 row, &fw_revision, snmp_syserr_p); 1777 CHECK_LINKRESET_VOID(snmp_syserr_p) 1778 if ((ret == 0) && fw_revision) { 1779 (void) add_string_prop(nodeh, 1780 PICL_PROP_FW_REVISION, fw_revision); 1781 free((void *) fw_revision); 1782 } 1783 if (ret == -1) 1784 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1785 *snmp_syserr_p ? *snmp_syserr_p : ret, 1786 OID_entPhysicalFirmwareRev, row); 1787 break; 1788 1789 case PP_MFG_NAME: 1790 ret = snmp_get_str(hdl, OID_entPhysicalMfgName, 1791 row, &mfg_name, snmp_syserr_p); 1792 CHECK_LINKRESET_VOID(snmp_syserr_p) 1793 if ((ret == 0) && mfg_name) { 1794 (void) add_string_prop(nodeh, 1795 PICL_PROP_MFG_NAME, mfg_name); 1796 free((void *) mfg_name); 1797 } 1798 if (ret == -1) 1799 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1800 *snmp_syserr_p ? *snmp_syserr_p : ret, 1801 OID_entPhysicalMfgName, row); 1802 break; 1803 1804 case PP_MODEL_NAME: 1805 ret = snmp_get_str(hdl, OID_entPhysicalModelName, 1806 row, &model_name, snmp_syserr_p); 1807 CHECK_LINKRESET_VOID(snmp_syserr_p) 1808 if ((ret == 0) && model_name) { 1809 (void) add_string_prop(nodeh, 1810 PICL_PROP_MODEL_NAME, model_name); 1811 free((void *) model_name); 1812 } 1813 if (ret == -1) 1814 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1815 *snmp_syserr_p ? *snmp_syserr_p : ret, 1816 OID_entPhysicalModelName, row); 1817 break; 1818 1819 case PP_DESCRIPTION: 1820 ret = snmp_get_str(hdl, OID_entPhysicalDescr, 1821 row, &phys_descr, snmp_syserr_p); 1822 CHECK_LINKRESET_VOID(snmp_syserr_p) 1823 if ((ret == 0) && phys_descr) { 1824 (void) add_string_prop(nodeh, 1825 PICL_PROP_PHYS_DESCRIPTION, phys_descr); 1826 free((void *) phys_descr); 1827 } 1828 if (ret == -1) 1829 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1830 *snmp_syserr_p ? *snmp_syserr_p : ret, 1831 OID_entPhysicalDescr, row); 1832 break; 1833 1834 case PP_LABEL: 1835 if (label && *label) 1836 (void) add_string_prop(nodeh, PICL_PROP_LABEL, label); 1837 break; 1838 1839 case PP_BASE_UNITS: 1840 ret = snmp_get_int(hdl, OID_sunPlatNumericSensorBaseUnits, 1841 row, &val, snmp_syserr_p); 1842 CHECK_LINKRESET_VOID(snmp_syserr_p) 1843 if ((ret == 0) && (val > 0) && (val < n_baseunits)) { 1844 (void) add_string_prop(nodeh, 1845 PICL_PROP_BASE_UNITS, sensor_baseunits[val]); 1846 } 1847 if (ret == -1) 1848 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1849 *snmp_syserr_p ? *snmp_syserr_p : ret, 1850 OID_sunPlatNumericSensorBaseUnits, row); 1851 break; 1852 1853 case PP_RATE_UNITS: 1854 ret = snmp_get_int(hdl, OID_sunPlatNumericSensorRateUnits, 1855 row, &val, snmp_syserr_p); 1856 CHECK_LINKRESET_VOID(snmp_syserr_p) 1857 if ((ret == 0) && (val > 0) && (val < n_rateunits)) { 1858 (void) add_string_prop(nodeh, 1859 PICL_PROP_RATE_UNITS, sensor_rateunits[val]); 1860 } 1861 if (ret == -1) 1862 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1863 *snmp_syserr_p ? *snmp_syserr_p : ret, 1864 OID_sunPlatNumericSensorRateUnits, row); 1865 break; 1866 } 1867 } 1868 1869 /* 1870 * Initialize the SNMP library's cache refresh subsystem, then periodically 1871 * process refresh job to prevent cache entries from expiring. 1872 */ 1873 /*ARGSUSED*/ 1874 static void * 1875 cache_refresher(void *arg) 1876 { 1877 int jobs; 1878 int next_expiration; 1879 timestruc_t to; 1880 hrtime_t cycle_start, cycle_elapsed; 1881 1882 /* 1883 * Initialize refresh subsystem 1884 */ 1885 LOGPRINTF("Initializing SNMP refresh subsystem.\n"); 1886 if (snmp_refresh_init() < 0) { 1887 return ((void *)-1); 1888 } 1889 1890 (void) mutex_lock(&cache_refresh_lock); 1891 1892 1893 for (;;) { 1894 cycle_start = gethrtime(); 1895 1896 /* 1897 * Process jobs from the snmp cache refresh work queue until one 1898 * of the following conditions is true: 1899 * 1) we are told to exit, or 1900 * 2) we have processed at least as many jobs as recommended by 1901 * the library, and the next job expiration is at least 1902 * CACHE_REFRESH_MIN_WINDOW * seconds away. 1903 */ 1904 jobs = snmp_refresh_get_cycle_hint(CACHE_REFRESH_CYCLE); 1905 while ((cache_refresh_thr_exit == B_FALSE) && (jobs > 0)) { 1906 (void) snmp_refresh_process_job(); 1907 jobs--; 1908 } 1909 1910 next_expiration = snmp_refresh_get_next_expiration(); 1911 while ((cache_refresh_thr_exit == B_FALSE) && 1912 ((next_expiration >= 0) && 1913 (next_expiration < CACHE_REFRESH_MIN_WINDOW))) { 1914 (void) snmp_refresh_process_job(); 1915 next_expiration = snmp_refresh_get_next_expiration(); 1916 } 1917 1918 /* 1919 * As long as we haven't been told to exit, sleep for 1920 * CACHE_REFRESH_CYCLE seconds minus the amount of time that has 1921 * elapsed since this cycle started. If the elapsed time is 1922 * equal to or greater than 60 seconds, skip sleeping entirely. 1923 */ 1924 cycle_elapsed = (gethrtime() - cycle_start) / NANOSEC; 1925 if ((cache_refresh_thr_exit == B_FALSE) && 1926 (cycle_elapsed < CACHE_REFRESH_CYCLE)) { 1927 to.tv_sec = CACHE_REFRESH_CYCLE - cycle_elapsed; 1928 to.tv_nsec = 0; 1929 (void) cond_reltimedwait(&cache_refresh_cv, 1930 &cache_refresh_lock, &to); 1931 } 1932 1933 /* 1934 * If we have been told to exit, clean up and bail out. 1935 */ 1936 if (cache_refresh_thr_exit == B_TRUE) { 1937 snmp_refresh_fini(); 1938 (void) mutex_unlock(&cache_refresh_lock); 1939 LOGPRINTF("cache_refresher: time to exit\n"); 1940 return (NULL); 1941 } 1942 1943 } 1944 1945 /*NOTREACHED*/ 1946 return (NULL); 1947 } 1948 1949 /* 1950 * Check to see if the cache_refresher thread is running. If it is, signal it 1951 * to terminate and clean up associated data structures. 1952 */ 1953 void 1954 cache_refresher_fini(void) 1955 { 1956 /* if the thread isn't running, there is nothing to do */ 1957 if (cache_refresh_thr_exit == B_TRUE) 1958 return; 1959 1960 /* wake up the cache_refresher thread, tell it to exit */ 1961 (void) mutex_lock(&cache_refresh_lock); 1962 cache_refresh_thr_exit = B_TRUE; 1963 (void) cond_signal(&cache_refresh_cv); 1964 (void) mutex_unlock(&cache_refresh_lock); 1965 1966 /* reap the thread */ 1967 (void) thr_join(cache_refresh_thr_id, NULL, NULL); 1968 1969 /* finish cleanup... */ 1970 (void) cond_destroy(&cache_refresh_cv); 1971 (void) mutex_destroy(&cache_refresh_lock); 1972 } 1973 1974 /*VARARGS2*/ 1975 static void 1976 log_msg(int pri, const char *fmt, ...) 1977 { 1978 va_list ap; 1979 1980 va_start(ap, fmt); 1981 vsyslog(pri, fmt, ap); 1982 va_end(ap); 1983 } 1984 1985 #ifdef SNMPPLUGIN_DEBUG 1986 1987 static void 1988 snmpplugin_log_init(void) 1989 { 1990 (void) mutex_init(&snmpplugin_dbuf_lock, USYNC_THREAD, NULL); 1991 } 1992 1993 static void 1994 snmpplugin_log(const char *fmt, ...) 1995 { 1996 va_list ap; 1997 1998 (void) mutex_lock(&snmpplugin_dbuf_lock); 1999 2000 va_start(ap, fmt); 2001 (void) vsnprintf(snmpplugin_lbuf, SNMPPLUGIN_DMAX_LINE, fmt, ap); 2002 snmpplugin_log_append(); 2003 va_end(ap); 2004 2005 (void) mutex_unlock(&snmpplugin_dbuf_lock); 2006 } 2007 2008 static void 2009 snmpplugin_log_append(void) 2010 { 2011 int len; 2012 2013 len = strlen(snmpplugin_lbuf); 2014 2015 if ((snmpplugin_dbuf_curp + len) >= 2016 (snmpplugin_dbuf + snmpplugin_dbuf_sz)) { 2017 snmpplugin_dbuf_realloc(); 2018 if (snmpplugin_dbuf == NULL) { 2019 return; 2020 } 2021 } 2022 2023 (void) strcpy(snmpplugin_dbuf_curp, snmpplugin_lbuf); 2024 snmpplugin_dbuf_curp += len; 2025 } 2026 2027 static void 2028 snmpplugin_dbuf_realloc(void) 2029 { 2030 char *p; 2031 size_t offset = 0; 2032 size_t count; 2033 2034 count = snmpplugin_dbuf_sz + SNMPPLUGIN_DBLOCK_SZ; 2035 if ((p = (char *)calloc(count, 1)) == NULL) { 2036 snmpplugin_dbuf_overflow++; 2037 snmpplugin_dbuf_curp = snmpplugin_dbuf; 2038 return; 2039 } 2040 2041 if (snmpplugin_dbuf) { 2042 offset = snmpplugin_dbuf_curp - snmpplugin_dbuf; 2043 (void) memcpy(p, snmpplugin_dbuf, snmpplugin_dbuf_sz); 2044 free(snmpplugin_dbuf); 2045 } 2046 2047 snmpplugin_dbuf = p; 2048 snmpplugin_dbuf_sz += SNMPPLUGIN_DBLOCK_SZ; 2049 2050 snmpplugin_dbuf_curp = snmpplugin_dbuf + offset; 2051 } 2052 #endif 2053