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 #include <sys/fm/protocol.h> 28 #include <fm/fmd_adm.h> 29 #include <fm/fmd_snmp.h> 30 #include <net-snmp/net-snmp-config.h> 31 #include <net-snmp/net-snmp-includes.h> 32 #include <net-snmp/agent/net-snmp-agent-includes.h> 33 #include <pthread.h> 34 #include <stddef.h> 35 #include <errno.h> 36 #include <alloca.h> 37 #include <locale.h> 38 #include <libuutil.h> 39 #include <libnvpair.h> 40 #include "sunFM_impl.h" 41 #include "problem.h" 42 43 /* 44 * We assume that the number of suspect fault events associated with a 45 * particular case will generally be sufficiently small that the overhead 46 * associated with indexing them in a tree would exceed the gain from 47 * not traversing the fault list for each request. 48 */ 49 static uu_avl_pool_t *problem_uuid_avl_pool; 50 static uu_avl_t *problem_uuid_avl; 51 52 #define VALID_AVL_STATE (problem_uuid_avl_pool != NULL && \ 53 problem_uuid_avl != NULL) 54 55 #define UPDATE_WAIT_MILLIS 10 /* poll interval in milliseconds */ 56 57 /* 58 * Update types. Single-index and all are mutually exclusive. 59 */ 60 #define UCT_INDEX 0x1 61 #define UCT_ALL 0x2 62 #define UCT_FLAGS 0x3 63 64 /* 65 * Locking strategy is described in module.c. 66 */ 67 static int valid_stamp; 68 static pthread_mutex_t update_lock; 69 static pthread_cond_t update_cv; 70 static volatile enum { US_QUIET, US_NEEDED, US_INPROGRESS } update_status; 71 72 static Netsnmp_Node_Handler sunFmProblemTable_handler; 73 static Netsnmp_Node_Handler sunFmFaultEventTable_handler; 74 75 static sunFmProblem_data_t * 76 problem_key_build(const char *uuid) 77 { 78 static sunFmProblem_data_t key; 79 80 key.d_aci_uuid = uuid; 81 82 return (&key); 83 } 84 85 static sunFmProblem_data_t * 86 problem_lookup_uuid_exact(const char *uuid) 87 { 88 sunFmProblem_data_t *key, *data; 89 90 key = problem_key_build(uuid); 91 92 DEBUGMSGTL((MODNAME_STR, "lookup_exact for uuid %s\n", uuid)); 93 data = uu_avl_find(problem_uuid_avl, key, NULL, NULL); 94 95 return (data); 96 } 97 98 static sunFmProblem_data_t * 99 problem_lookup_uuid_next(const char *uuid) 100 { 101 sunFmProblem_data_t *key, *data; 102 uu_avl_index_t idx; 103 104 key = problem_key_build(uuid); 105 106 DEBUGMSGTL((MODNAME_STR, "lookup_next for uuid %s\n", uuid)); 107 (void) uu_avl_find(problem_uuid_avl, key, NULL, &idx); 108 109 data = uu_avl_nearest_next(problem_uuid_avl, idx); 110 111 DEBUGMSGTL((MODNAME_STR, "lookup_next: entry is %p\n", data)); 112 113 return (data); 114 } 115 116 static sunFmFaultEvent_data_t * 117 faultevent_lookup_index_exact(sunFmProblem_data_t *data, ulong_t index) 118 { 119 if (index > data->d_nsuspects) 120 return (NULL); 121 122 if (data->d_suspects == NULL) 123 return (NULL); 124 125 return (data->d_suspects[index - 1]); 126 } 127 128 static sunFmFaultStatus_data_t 129 faultstatus_lookup_index_exact(sunFmProblem_data_t *data, ulong_t index) 130 { 131 if (index > data->d_nsuspects) 132 return (0); 133 134 if (data->d_statuses == NULL) 135 return (0); 136 137 if (data->d_valid != valid_stamp) 138 return (0); 139 140 return (data->d_statuses[index - 1]); 141 } 142 143 /*ARGSUSED*/ 144 static int 145 problem_update_one(const fmd_adm_caseinfo_t *acp, void *arg) 146 { 147 sunFmProblem_data_t *data; 148 nvlist_t *nvl; 149 int64_t *diag_time; 150 uint_t nelem; 151 uint32_t nsusp; 152 int err; 153 154 DEBUGMSGTL((MODNAME_STR, "update_one\n")); 155 156 ASSERT(acp->aci_uuid != NULL); 157 158 if ((data = problem_lookup_uuid_exact(acp->aci_uuid)) == NULL) { 159 uu_avl_index_t idx; 160 161 DEBUGMSGTL((MODNAME_STR, "found new problem %s\n", 162 acp->aci_uuid)); 163 if ((data = SNMP_MALLOC_TYPEDEF(sunFmProblem_data_t)) == NULL) { 164 (void) snmp_log(LOG_ERR, MODNAME_STR ": Out of memory " 165 "for new problem data at %s:%d\n", __FILE__, 166 __LINE__); 167 return (0); 168 } 169 if ((err = nvlist_dup(acp->aci_event, &data->d_aci_event, 0)) 170 != 0) { 171 (void) snmp_log(LOG_ERR, MODNAME_STR ": Problem data " 172 "setup failed: %s\n", strerror(err)); 173 SNMP_FREE(data); 174 return (0); 175 } 176 177 data->d_aci_uuid = data->d_aci_code = data->d_aci_url = "-"; 178 (void) nvlist_lookup_string(data->d_aci_event, FM_SUSPECT_UUID, 179 (char **)&data->d_aci_uuid); 180 (void) nvlist_lookup_string(data->d_aci_event, 181 FM_SUSPECT_DIAG_CODE, (char **)&data->d_aci_code); 182 data->d_aci_url = strdup(acp->aci_url); 183 184 if (nvlist_lookup_nvlist(data->d_aci_event, FM_SUSPECT_DE, 185 &nvl) == 0) 186 if ((data->d_diag_engine = sunFm_nvl2str(nvl)) == NULL) 187 data->d_diag_engine = "-"; 188 189 if (nvlist_lookup_int64_array(data->d_aci_event, 190 FM_SUSPECT_DIAG_TIME, &diag_time, &nelem) == 0 && 191 nelem >= 2) { 192 data->d_diag_time.tv_sec = (long)diag_time[0]; 193 data->d_diag_time.tv_usec = (long)diag_time[1]; 194 } 195 196 (void) nvlist_lookup_uint32(data->d_aci_event, 197 FM_SUSPECT_FAULT_SZ, &nsusp); 198 data->d_nsuspects = (ulong_t)nsusp; 199 200 (void) nvlist_lookup_nvlist_array(data->d_aci_event, 201 FM_SUSPECT_FAULT_LIST, &data->d_suspects, &nelem); 202 203 ASSERT(nelem == data->d_nsuspects); 204 205 (void) nvlist_lookup_uint8_array(data->d_aci_event, 206 FM_SUSPECT_FAULT_STATUS, &data->d_statuses, &nelem); 207 208 ASSERT(nelem == data->d_nsuspects); 209 210 uu_avl_node_init(data, &data->d_uuid_avl, 211 problem_uuid_avl_pool); 212 (void) uu_avl_find(problem_uuid_avl, data, NULL, &idx); 213 uu_avl_insert(problem_uuid_avl, data, idx); 214 215 data->d_valid = valid_stamp; 216 217 DEBUGMSGTL((MODNAME_STR, "completed new problem %s@%p\n", 218 data->d_aci_uuid, data)); 219 } else { 220 uint8_t *statuses; 221 int i; 222 223 (void) nvlist_lookup_uint8_array(acp->aci_event, 224 FM_SUSPECT_FAULT_STATUS, &statuses, &nelem); 225 226 ASSERT(nelem == data->d_nsuspects); 227 228 for (i = 0; i < nelem; i++) 229 data->d_statuses[i] = statuses[i]; 230 231 data->d_valid = valid_stamp; 232 } 233 234 /* 235 * We don't touch problems we've seen before; they shouldn't change 236 * in any way we care about, since they've already been solved. The 237 * state, however, could change, and if we later expose that to the 238 * client we need to update it here. 239 */ 240 241 return (0); 242 } 243 244 static int 245 problem_update(sunFmProblem_update_ctx_t *update_ctx) 246 { 247 fmd_adm_t *adm; 248 249 ASSERT(update_ctx != NULL); 250 ASSERT((update_ctx->uc_type & (UCT_INDEX|UCT_ALL)) != 251 (UCT_INDEX|UCT_ALL)); 252 ASSERT((update_ctx->uc_type & ~UCT_FLAGS) == 0); 253 ASSERT(VALID_AVL_STATE); 254 255 if ((adm = fmd_adm_open(update_ctx->uc_host, update_ctx->uc_prog, 256 update_ctx->uc_version)) == NULL) { 257 (void) snmp_log(LOG_ERR, MODNAME_STR ": Communication with fmd " 258 "failed: %s\n", strerror(errno)); 259 return (SNMP_ERR_RESOURCEUNAVAILABLE); 260 } 261 262 ++valid_stamp; 263 if (fmd_adm_case_iter(adm, SNMP_URL_MSG, problem_update_one, 264 update_ctx) != 0) { 265 (void) snmp_log(LOG_ERR, MODNAME_STR ": fmd case information " 266 "update failed: %s\n", fmd_adm_errmsg(adm)); 267 fmd_adm_close(adm); 268 return (SNMP_ERR_RESOURCEUNAVAILABLE); 269 } 270 271 DEBUGMSGTL((MODNAME_STR, "case iteration completed\n")); 272 273 fmd_adm_close(adm); 274 return (SNMP_ERR_NOERROR); 275 } 276 277 __NORETURN static void * 278 update_thread(void *arg __unused) 279 { 280 /* 281 * The current problem_update implementation offers minimal savings 282 * for the use of index-only updates; therefore we always do a full 283 * update. If it becomes advantageous to limit updates to a single 284 * index, the contexts can be queued by the handler instead. 285 */ 286 sunFmProblem_update_ctx_t uc; 287 288 uc.uc_host = NULL; 289 uc.uc_prog = FMD_ADM_PROGRAM; 290 uc.uc_version = FMD_ADM_VERSION; 291 292 uc.uc_index = NULL; 293 uc.uc_type = UCT_ALL; 294 295 for (;;) { 296 (void) pthread_mutex_lock(&update_lock); 297 update_status = US_QUIET; 298 while (update_status == US_QUIET) 299 (void) pthread_cond_wait(&update_cv, &update_lock); 300 update_status = US_INPROGRESS; 301 (void) pthread_mutex_unlock(&update_lock); 302 (void) problem_update(&uc); 303 } 304 } 305 306 static void 307 request_update(void) 308 { 309 (void) pthread_mutex_lock(&update_lock); 310 if (update_status != US_QUIET) { 311 (void) pthread_mutex_unlock(&update_lock); 312 return; 313 } 314 update_status = US_NEEDED; 315 (void) pthread_cond_signal(&update_cv); 316 (void) pthread_mutex_unlock(&update_lock); 317 } 318 319 /*ARGSUSED*/ 320 static int 321 problem_compare_uuid(const void *l, const void *r, void *private) 322 { 323 sunFmProblem_data_t *l_data = (sunFmProblem_data_t *)l; 324 sunFmProblem_data_t *r_data = (sunFmProblem_data_t *)r; 325 326 ASSERT(l_data != NULL && r_data != NULL); 327 328 return (strcmp(l_data->d_aci_uuid, r_data->d_aci_uuid)); 329 } 330 331 int 332 sunFmProblemTable_init(void) 333 { 334 static oid sunFmProblemTable_oid[] = { SUNFMPROBLEMTABLE_OID }; 335 netsnmp_table_registration_info *table_info; 336 netsnmp_handler_registration *handler; 337 int err; 338 339 if ((err = pthread_mutex_init(&update_lock, NULL)) != 0) { 340 (void) snmp_log(LOG_ERR, MODNAME_STR ": mutex_init failure: " 341 "%s\n", strerror(err)); 342 return (MIB_REGISTRATION_FAILED); 343 } 344 if ((err = pthread_cond_init(&update_cv, NULL)) != 0) { 345 (void) snmp_log(LOG_ERR, MODNAME_STR ": cond_init failure: " 346 "%s\n", strerror(err)); 347 return (MIB_REGISTRATION_FAILED); 348 } 349 350 if ((err = pthread_create(NULL, NULL, update_thread, NULL)) != 0) { 351 (void) snmp_log(LOG_ERR, MODNAME_STR ": error creating update " 352 "thread: %s\n", strerror(err)); 353 return (MIB_REGISTRATION_FAILED); 354 } 355 356 if ((table_info = 357 SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL) 358 return (MIB_REGISTRATION_FAILED); 359 360 if ((handler = netsnmp_create_handler_registration("sunFmProblemTable", 361 sunFmProblemTable_handler, sunFmProblemTable_oid, 362 OID_LENGTH(sunFmProblemTable_oid), HANDLER_CAN_RONLY)) == NULL) { 363 SNMP_FREE(table_info); 364 return (MIB_REGISTRATION_FAILED); 365 } 366 367 /* 368 * The Net-SNMP template uses add_indexes here, but that 369 * function is unsafe because it does not check for failure. 370 */ 371 if (netsnmp_table_helper_add_index(table_info, ASN_OCTET_STR) == NULL) { 372 SNMP_FREE(table_info); 373 SNMP_FREE(handler); 374 return (MIB_REGISTRATION_FAILED); 375 } 376 377 table_info->min_column = SUNFMPROBLEM_COLMIN; 378 table_info->max_column = SUNFMPROBLEM_COLMAX; 379 380 if ((problem_uuid_avl_pool = uu_avl_pool_create("problem_uuid", 381 sizeof (sunFmProblem_data_t), 382 offsetof(sunFmProblem_data_t, d_uuid_avl), problem_compare_uuid, 383 UU_AVL_DEBUG)) == NULL) { 384 (void) snmp_log(LOG_ERR, MODNAME_STR ": problem_uuid avl pool " 385 "creation failed: %s\n", uu_strerror(uu_error())); 386 snmp_free_varbind(table_info->indexes); 387 SNMP_FREE(table_info); 388 SNMP_FREE(handler); 389 return (MIB_REGISTRATION_FAILED); 390 } 391 392 if ((problem_uuid_avl = uu_avl_create(problem_uuid_avl_pool, NULL, 393 UU_AVL_DEBUG)) == NULL) { 394 (void) snmp_log(LOG_ERR, MODNAME_STR ": problem_uuid avl " 395 "creation failed: %s\n", uu_strerror(uu_error())); 396 snmp_free_varbind(table_info->indexes); 397 SNMP_FREE(table_info); 398 SNMP_FREE(handler); 399 uu_avl_pool_destroy(problem_uuid_avl_pool); 400 return (MIB_REGISTRATION_FAILED); 401 } 402 403 if ((err = netsnmp_register_table(handler, table_info)) != 404 MIB_REGISTERED_OK) { 405 snmp_free_varbind(table_info->indexes); 406 SNMP_FREE(table_info); 407 SNMP_FREE(handler); 408 uu_avl_destroy(problem_uuid_avl); 409 uu_avl_pool_destroy(problem_uuid_avl_pool); 410 return (err); 411 } 412 413 return (MIB_REGISTERED_OK); 414 } 415 416 int 417 sunFmFaultEventTable_init(void) 418 { 419 static oid sunFmFaultEventTable_oid[] = { SUNFMFAULTEVENTTABLE_OID }; 420 netsnmp_table_registration_info *table_info; 421 netsnmp_handler_registration *handler; 422 int err; 423 424 if ((table_info = 425 SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL) 426 return (MIB_REGISTRATION_FAILED); 427 428 if ((handler = 429 netsnmp_create_handler_registration("sunFmFaultEventTable", 430 sunFmFaultEventTable_handler, sunFmFaultEventTable_oid, 431 OID_LENGTH(sunFmFaultEventTable_oid), HANDLER_CAN_RONLY)) == NULL) { 432 SNMP_FREE(table_info); 433 return (MIB_REGISTRATION_FAILED); 434 } 435 436 /* 437 * The Net-SNMP template uses add_indexes here, but that 438 * function is unsafe because it does not check for failure. 439 */ 440 if (netsnmp_table_helper_add_index(table_info, ASN_OCTET_STR) == NULL) { 441 SNMP_FREE(table_info); 442 SNMP_FREE(handler); 443 return (MIB_REGISTRATION_FAILED); 444 } 445 if (netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED) == NULL) { 446 snmp_free_varbind(table_info->indexes); 447 SNMP_FREE(table_info); 448 SNMP_FREE(handler); 449 return (MIB_REGISTRATION_FAILED); 450 } 451 452 table_info->min_column = SUNFMFAULTEVENT_COLMIN; 453 table_info->max_column = SUNFMFAULTEVENT_COLMAX; 454 455 if ((err = netsnmp_register_table(handler, table_info)) != 456 MIB_REGISTERED_OK) { 457 snmp_free_varbind(table_info->indexes); 458 SNMP_FREE(table_info); 459 SNMP_FREE(handler); 460 return (err); 461 } 462 463 return (MIB_REGISTERED_OK); 464 } 465 466 /* 467 * Returns the problem data for the problem whose uuid is next according 468 * to ASN.1 lexical ordering after the request in table_info. Indexes are 469 * updated to reflect the OID of the value being returned. This allows 470 * us to implement GETNEXT. 471 */ 472 static sunFmProblem_data_t * 473 sunFmProblemTable_nextpr(netsnmp_handler_registration *reginfo, 474 netsnmp_table_request_info *table_info) 475 { 476 sunFmProblem_data_t *data; 477 char *uuid = ""; 478 479 if (table_info->number_indexes < 1) { 480 oid tmpoid[MAX_OID_LEN]; 481 482 DEBUGMSGTL((MODNAME_STR, "nextpr: no indexes given\n")); 483 484 snmp_free_varbind(table_info->indexes); 485 table_info->indexes = 486 SNMP_MALLOC_TYPEDEF(netsnmp_variable_list); 487 (void) snmp_set_var_typed_value(table_info->indexes, 488 ASN_OCTET_STR, (const uchar_t *)uuid, 0); 489 (void) memcpy(tmpoid, reginfo->rootoid, 490 reginfo->rootoid_len * sizeof (oid)); 491 tmpoid[reginfo->rootoid_len] = 1; 492 tmpoid[reginfo->rootoid_len + 1] = table_info->colnum; 493 if (build_oid_segment(table_info->indexes) != SNMPERR_SUCCESS) { 494 snmp_free_varbind(table_info->indexes); 495 return (NULL); 496 } 497 table_info->number_indexes = 1; 498 table_info->index_oid_len = table_info->indexes->name_length; 499 (void) memcpy(table_info->index_oid, table_info->indexes->name, 500 table_info->indexes->name_length); 501 502 DEBUGMSGTL((MODNAME_STR, "nextpr: built fake index:\n")); 503 DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 504 DEBUGMSG((MODNAME_STR, "\n")); 505 } else { 506 /* 507 * Construct the next possible UUID to look for. We can 508 * simply increment the least significant byte of the last 509 * UUID because (a) that preserves SNMP lex order and (b) 510 * the characters that may appear in a UUID do not include 511 * 127 nor 255. 512 */ 513 uuid = alloca(table_info->indexes->val_len + 1); 514 (void) strlcpy(uuid, 515 (const char *)table_info->indexes->val.string, 516 table_info->indexes->val_len + 1); 517 ++uuid[table_info->indexes->val_len - 1]; 518 519 DEBUGMSGTL((MODNAME_STR, "nextpr: received index:\n")); 520 DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 521 DEBUGMSG((MODNAME_STR, "\n")); 522 } 523 524 if ((data = problem_lookup_uuid_next(uuid)) == NULL) { 525 DEBUGMSGTL((MODNAME_STR, "nextpr: next match not found for " 526 "%s; trying next column\n", uuid)); 527 if (table_info->colnum >= 528 netsnmp_find_table_registration_info(reginfo)->max_column) { 529 snmp_free_varbind(table_info->indexes); 530 table_info->indexes = NULL; 531 table_info->number_indexes = 0; 532 DEBUGMSGTL((MODNAME_STR, "nextpr: out of columns\n")); 533 return (NULL); 534 } 535 table_info->colnum++; 536 DEBUGMSGTL((MODNAME_STR, "nextpr: search for col %u empty " 537 "uuid\n", table_info->colnum)); 538 539 if ((data = problem_lookup_uuid_next("")) == NULL) { 540 DEBUGMSGTL((MODNAME_STR, "nextpr: next match not found " 541 "for empty uuid; stopping\n")); 542 snmp_free_varbind(table_info->indexes); 543 table_info->indexes = NULL; 544 table_info->number_indexes = 0; 545 return (NULL); 546 } 547 } 548 549 (void) snmp_set_var_typed_value(table_info->indexes, ASN_OCTET_STR, 550 (uchar_t *)data->d_aci_uuid, strlen(data->d_aci_uuid)); 551 table_info->number_indexes = 1; 552 553 DEBUGMSGTL((MODNAME_STR, "matching data is %s@%p\n", data->d_aci_uuid, 554 data)); 555 556 return (data); 557 } 558 559 /* 560 * Returns the problem data corresponding to the request in table_info. 561 * All request parameters are unmodified. 562 */ 563 /*ARGSUSED*/ 564 static sunFmProblem_data_t * 565 sunFmProblemTable_pr(netsnmp_handler_registration *reginfo, 566 netsnmp_table_request_info *table_info) 567 { 568 char *uuid; 569 570 ASSERT(table_info->number_indexes >= 1); 571 572 uuid = alloca(table_info->indexes->val_len + 1); 573 (void) strlcpy(uuid, (const char *)table_info->indexes->val.string, 574 table_info->indexes->val_len + 1); 575 576 return (problem_lookup_uuid_exact(uuid)); 577 } 578 579 /* 580 * Returns the ASN.1 lexicographically first fault event after the one 581 * identified by table_info. Indexes are updated to reflect the OID 582 * of the data returned. This allows us to implement GETNEXT. 583 */ 584 static sunFmFaultEvent_data_t * 585 sunFmFaultEventTable_nextfe(netsnmp_handler_registration *reginfo, 586 netsnmp_table_request_info *table_info, sunFmFaultStatus_data_t *statusp) 587 { 588 sunFmProblem_data_t *data; 589 sunFmFaultEvent_data_t *rv; 590 netsnmp_variable_list *var; 591 ulong_t index; 592 593 for (;;) { 594 switch (table_info->number_indexes) { 595 case 2: 596 default: 597 DEBUGMSGTL((MODNAME_STR, "nextfe: 2 indices:\n")); 598 DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 599 DEBUGMSG((MODNAME_STR, "\n")); 600 DEBUGMSGVAR((MODNAME_STR, 601 table_info->indexes->next_variable)); 602 DEBUGMSG((MODNAME_STR, "\n")); 603 index = *(ulong_t *) 604 table_info->indexes->next_variable->val.integer + 1; 605 606 if ((data = sunFmProblemTable_pr(reginfo, 607 table_info)) != NULL && 608 (*statusp = faultstatus_lookup_index_exact(data, 609 index)) != 0 && 610 (rv = faultevent_lookup_index_exact(data, index)) != 611 NULL) { 612 (void) snmp_set_var_typed_value( 613 table_info->indexes->next_variable, 614 ASN_UNSIGNED, (uchar_t *)&index, 615 sizeof (index)); 616 return (rv); 617 } 618 619 if (sunFmProblemTable_nextpr(reginfo, table_info) == 620 NULL) 621 return (NULL); 622 break; 623 case 1: 624 if ((data = sunFmProblemTable_pr(reginfo, 625 table_info)) != NULL) { 626 oid tmpoid[MAX_OID_LEN]; 627 index = 0; 628 629 DEBUGMSGTL((MODNAME_STR, "nextfe: 1 index:\n")); 630 DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 631 DEBUGMSG((MODNAME_STR, "\n")); 632 var = 633 SNMP_MALLOC_TYPEDEF(netsnmp_variable_list); 634 (void) snmp_set_var_typed_value(var, 635 ASN_UNSIGNED, (uchar_t *)&index, 636 sizeof (index)); 637 (void) memcpy(tmpoid, reginfo->rootoid, 638 reginfo->rootoid_len * sizeof (oid)); 639 tmpoid[reginfo->rootoid_len] = 1; 640 tmpoid[reginfo->rootoid_len + 1] = 641 table_info->colnum; 642 if (build_oid_segment(var) != SNMPERR_SUCCESS) { 643 snmp_free_varbind(var); 644 return (NULL); 645 } 646 snmp_free_varbind( 647 table_info->indexes->next_variable); 648 table_info->indexes->next_variable = var; 649 table_info->number_indexes = 2; 650 DEBUGMSGTL((MODNAME_STR, "nextfe: built fake " 651 "index:\n")); 652 DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); 653 DEBUGMSG((MODNAME_STR, "\n")); 654 DEBUGMSGVAR((MODNAME_STR, 655 table_info->indexes->next_variable)); 656 DEBUGMSG((MODNAME_STR, "\n")); 657 } else { 658 if (sunFmProblemTable_nextpr(reginfo, 659 table_info) == NULL) 660 return (NULL); 661 } 662 break; 663 case 0: 664 if (sunFmProblemTable_nextpr(reginfo, table_info) == 665 NULL) 666 return (NULL); 667 break; 668 } 669 } 670 } 671 672 static sunFmFaultEvent_data_t * 673 sunFmFaultEventTable_fe(netsnmp_handler_registration *reginfo, 674 netsnmp_table_request_info *table_info, sunFmFaultStatus_data_t *statusp) 675 { 676 sunFmProblem_data_t *data; 677 678 ASSERT(table_info->number_indexes == 2); 679 680 if ((data = sunFmProblemTable_pr(reginfo, table_info)) == NULL) 681 return (NULL); 682 683 *statusp = faultstatus_lookup_index_exact(data, 684 *(ulong_t *)table_info->indexes->next_variable->val.integer); 685 if (*statusp == 0) 686 return (NULL); 687 return (faultevent_lookup_index_exact(data, 688 *(ulong_t *)table_info->indexes->next_variable->val.integer)); 689 } 690 691 /*ARGSUSED*/ 692 static void 693 sunFmProblemTable_return(unsigned int reg, void *arg) 694 { 695 netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *)arg; 696 netsnmp_request_info *request; 697 netsnmp_agent_request_info *reqinfo; 698 netsnmp_handler_registration *reginfo; 699 netsnmp_table_request_info *table_info; 700 sunFmProblem_data_t *data; 701 702 ASSERT(netsnmp_handler_check_cache(cache) != NULL); 703 704 (void) pthread_mutex_lock(&update_lock); 705 if (update_status != US_QUIET) { 706 struct timeval tv; 707 708 tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 709 tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 710 711 (void) snmp_alarm_register_hr(tv, 0, sunFmProblemTable_return, 712 cache); 713 (void) pthread_mutex_unlock(&update_lock); 714 return; 715 } 716 717 request = cache->requests; 718 reqinfo = cache->reqinfo; 719 reginfo = cache->reginfo; 720 721 table_info = netsnmp_extract_table_info(request); 722 request->delegated = 0; 723 724 ASSERT(table_info->colnum >= SUNFMPROBLEM_COLMIN); 725 ASSERT(table_info->colnum <= SUNFMPROBLEM_COLMAX); 726 727 /* 728 * table_info->colnum contains the column number requested. 729 * table_info->indexes contains a linked list of snmp variable 730 * bindings for the indexes of the table. Values in the list 731 * have been set corresponding to the indexes of the 732 * request. We have other guarantees as well: 733 * 734 * - The column number is always within range. 735 * - If we have no index data, table_info->index_oid_len is 0. 736 * - We will never receive requests outside our table nor 737 * those with the first subid anything other than 1 (Entry) 738 * nor those without a column number. This is true even 739 * for GETNEXT requests. 740 */ 741 742 switch (reqinfo->mode) { 743 case MODE_GET: 744 if ((data = sunFmProblemTable_pr(reginfo, table_info)) == 745 NULL) { 746 netsnmp_free_delegated_cache(cache); 747 (void) pthread_mutex_unlock(&update_lock); 748 return; 749 } 750 break; 751 case MODE_GETNEXT: 752 case MODE_GETBULK: 753 if ((data = sunFmProblemTable_nextpr(reginfo, table_info)) == 754 NULL) { 755 netsnmp_free_delegated_cache(cache); 756 (void) pthread_mutex_unlock(&update_lock); 757 return; 758 } 759 break; 760 default: 761 (void) snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request " 762 "mode %d\n", reqinfo->mode); 763 netsnmp_free_delegated_cache(cache); 764 (void) pthread_mutex_unlock(&update_lock); 765 return; 766 } 767 768 switch (table_info->colnum) { 769 case SUNFMPROBLEM_COL_UUID: 770 { 771 (void) netsnmp_table_build_result(reginfo, request, table_info, 772 ASN_OCTET_STR, (uchar_t *)data->d_aci_uuid, 773 strlen(data->d_aci_uuid)); 774 break; 775 } 776 case SUNFMPROBLEM_COL_CODE: 777 { 778 (void) netsnmp_table_build_result(reginfo, request, table_info, 779 ASN_OCTET_STR, (uchar_t *)data->d_aci_code, 780 strlen(data->d_aci_code)); 781 break; 782 } 783 case SUNFMPROBLEM_COL_URL: 784 { 785 (void) netsnmp_table_build_result(reginfo, request, table_info, 786 ASN_OCTET_STR, (uchar_t *)data->d_aci_url, 787 strlen(data->d_aci_url)); 788 break; 789 } 790 case SUNFMPROBLEM_COL_DIAGENGINE: 791 { 792 (void) netsnmp_table_build_result(reginfo, request, table_info, 793 ASN_OCTET_STR, (uchar_t *)data->d_diag_engine, 794 strlen(data->d_diag_engine)); 795 break; 796 } 797 case SUNFMPROBLEM_COL_DIAGTIME: 798 { 799 /* 800 * The date_n_time function is not Y2038-safe; this may 801 * need to be updated when a suitable Y2038-safe Net-SNMP 802 * API is available. 803 */ 804 size_t dt_size; 805 time_t dt_time = (time_t)data->d_diag_time.tv_sec; 806 uchar_t *dt = date_n_time(&dt_time, &dt_size); 807 808 (void) netsnmp_table_build_result(reginfo, request, table_info, 809 ASN_OCTET_STR, dt, dt_size); 810 break; 811 } 812 case SUNFMPROBLEM_COL_SUSPECTCOUNT: 813 { 814 (void) netsnmp_table_build_result(reginfo, request, table_info, 815 ASN_UNSIGNED, (uchar_t *)&data->d_nsuspects, 816 sizeof (data->d_nsuspects)); 817 break; 818 } 819 default: 820 break; 821 } 822 823 netsnmp_free_delegated_cache(cache); 824 (void) pthread_mutex_unlock(&update_lock); 825 } 826 827 static int 828 sunFmProblemTable_handler(netsnmp_mib_handler *handler, 829 netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, 830 netsnmp_request_info *requests) 831 { 832 netsnmp_request_info *request; 833 struct timeval tv; 834 835 tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 836 tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 837 838 request_update(); 839 840 for (request = requests; request; request = request->next) { 841 if (request->processed != 0) 842 continue; 843 844 if (netsnmp_extract_table_info(request) == NULL) 845 continue; 846 847 request->delegated = 1; 848 (void) snmp_alarm_register_hr(tv, 0, 849 sunFmProblemTable_return, 850 (void *) netsnmp_create_delegated_cache(handler, reginfo, 851 reqinfo, request, NULL)); 852 } 853 854 return (SNMP_ERR_NOERROR); 855 } 856 857 /*ARGSUSED*/ 858 static void 859 sunFmFaultEventTable_return(unsigned int reg, void *arg) 860 { 861 netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *)arg; 862 netsnmp_request_info *request; 863 netsnmp_agent_request_info *reqinfo; 864 netsnmp_handler_registration *reginfo; 865 netsnmp_table_request_info *table_info; 866 sunFmProblem_data_t *pdata; 867 sunFmFaultEvent_data_t *data; 868 sunFmFaultStatus_data_t status; 869 870 ASSERT(netsnmp_handler_check_cache(cache) != NULL); 871 872 (void) pthread_mutex_lock(&update_lock); 873 if (update_status != US_QUIET) { 874 struct timeval tv; 875 876 tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 877 tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 878 879 (void) snmp_alarm_register_hr(tv, 0, 880 sunFmFaultEventTable_return, cache); 881 (void) pthread_mutex_unlock(&update_lock); 882 return; 883 } 884 885 request = cache->requests; 886 reqinfo = cache->reqinfo; 887 reginfo = cache->reginfo; 888 889 table_info = netsnmp_extract_table_info(request); 890 request->delegated = 0; 891 892 ASSERT(table_info->colnum >= SUNFMFAULTEVENT_COLMIN); 893 ASSERT(table_info->colnum <= SUNFMFAULTEVENT_COLMAX); 894 895 /* 896 * table_info->colnum contains the column number requested. 897 * table_info->indexes contains a linked list of snmp variable 898 * bindings for the indexes of the table. Values in the list 899 * have been set corresponding to the indexes of the 900 * request. We have other guarantees as well: 901 * 902 * - The column number is always within range. 903 * - If we have no index data, table_info->index_oid_len is 0. 904 * - We will never receive requests outside our table nor 905 * those with the first subid anything other than 1 (Entry) 906 * nor those without a column number. This is true even 907 * for GETNEXT requests. 908 */ 909 910 switch (reqinfo->mode) { 911 case MODE_GET: 912 if ((data = sunFmFaultEventTable_fe(reginfo, table_info, 913 &status)) == NULL) { 914 netsnmp_free_delegated_cache(cache); 915 (void) pthread_mutex_unlock(&update_lock); 916 return; 917 } 918 break; 919 case MODE_GETNEXT: 920 case MODE_GETBULK: 921 if ((data = sunFmFaultEventTable_nextfe(reginfo, table_info, 922 &status)) == NULL) { 923 netsnmp_free_delegated_cache(cache); 924 (void) pthread_mutex_unlock(&update_lock); 925 return; 926 } 927 break; 928 default: 929 (void) snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request " 930 "mode %d\n", reqinfo->mode); 931 netsnmp_free_delegated_cache(cache); 932 (void) pthread_mutex_unlock(&update_lock); 933 return; 934 } 935 936 switch (table_info->colnum) { 937 case SUNFMFAULTEVENT_COL_PROBLEMUUID: 938 { 939 if ((pdata = sunFmProblemTable_pr(reginfo, table_info)) 940 == NULL) { 941 (void) netsnmp_table_build_result(reginfo, request, 942 table_info, ASN_OCTET_STR, NULL, 0); 943 break; 944 } 945 (void) netsnmp_table_build_result(reginfo, request, table_info, 946 ASN_OCTET_STR, (uchar_t *)pdata->d_aci_uuid, 947 strlen(pdata->d_aci_uuid)); 948 break; 949 } 950 case SUNFMFAULTEVENT_COL_CLASS: 951 { 952 char *class = "-"; 953 954 (void) nvlist_lookup_string(data, FM_CLASS, &class); 955 (void) netsnmp_table_build_result(reginfo, request, table_info, 956 ASN_OCTET_STR, (uchar_t *)class, strlen(class)); 957 break; 958 } 959 case SUNFMFAULTEVENT_COL_CERTAINTY: 960 { 961 uint8_t pct = 0; 962 ulong_t pl; 963 964 (void) nvlist_lookup_uint8(data, FM_FAULT_CERTAINTY, 965 &pct); 966 pl = (ulong_t)pct; 967 (void) netsnmp_table_build_result(reginfo, request, table_info, 968 ASN_UNSIGNED, (uchar_t *)&pl, sizeof (pl)); 969 break; 970 } 971 case SUNFMFAULTEVENT_COL_ASRU: 972 { 973 nvlist_t *asru = NULL; 974 char *fmri, *str; 975 976 (void) nvlist_lookup_nvlist(data, FM_FAULT_ASRU, &asru); 977 if ((str = sunFm_nvl2str(asru)) == NULL) 978 fmri = "-"; 979 else 980 fmri = str; 981 982 (void) netsnmp_table_build_result(reginfo, request, table_info, 983 ASN_OCTET_STR, (uchar_t *)fmri, strlen(fmri)); 984 free(str); 985 break; 986 } 987 case SUNFMFAULTEVENT_COL_FRU: 988 { 989 nvlist_t *fru = NULL; 990 char *fmri, *str; 991 992 (void) nvlist_lookup_nvlist(data, FM_FAULT_FRU, &fru); 993 if ((str = sunFm_nvl2str(fru)) == NULL) 994 fmri = "-"; 995 else 996 fmri = str; 997 998 (void) netsnmp_table_build_result(reginfo, request, table_info, 999 ASN_OCTET_STR, (uchar_t *)fmri, strlen(fmri)); 1000 free(str); 1001 break; 1002 } 1003 case SUNFMFAULTEVENT_COL_RESOURCE: 1004 { 1005 nvlist_t *rsrc = NULL; 1006 char *fmri, *str; 1007 1008 (void) nvlist_lookup_nvlist(data, FM_FAULT_RESOURCE, &rsrc); 1009 if ((str = sunFm_nvl2str(rsrc)) == NULL) 1010 fmri = "-"; 1011 else 1012 fmri = str; 1013 1014 (void) netsnmp_table_build_result(reginfo, request, table_info, 1015 ASN_OCTET_STR, (uchar_t *)fmri, strlen(fmri)); 1016 free(str); 1017 break; 1018 } 1019 case SUNFMFAULTEVENT_COL_STATUS: 1020 { 1021 ulong_t pl = SUNFMFAULTEVENT_STATE_OTHER; 1022 1023 if (status & FM_SUSPECT_FAULTY) 1024 pl = SUNFMFAULTEVENT_STATE_FAULTY; 1025 else if (status & FM_SUSPECT_NOT_PRESENT) 1026 pl = SUNFMFAULTEVENT_STATE_REMOVED; 1027 else if (status & FM_SUSPECT_REPLACED) 1028 pl = SUNFMFAULTEVENT_STATE_REPLACED; 1029 else if (status & FM_SUSPECT_REPAIRED) 1030 pl = SUNFMFAULTEVENT_STATE_REPAIRED; 1031 else if (status & FM_SUSPECT_ACQUITTED) 1032 pl = SUNFMFAULTEVENT_STATE_ACQUITTED; 1033 (void) netsnmp_table_build_result(reginfo, request, table_info, 1034 ASN_INTEGER, (uchar_t *)&pl, sizeof (pl)); 1035 break; 1036 } 1037 case SUNFMFAULTEVENT_COL_LOCATION: 1038 { 1039 char *location = "-"; 1040 1041 (void) nvlist_lookup_string(data, FM_FAULT_LOCATION, &location); 1042 (void) netsnmp_table_build_result(reginfo, request, table_info, 1043 ASN_OCTET_STR, (uchar_t *)location, strlen(location)); 1044 break; 1045 } 1046 default: 1047 break; 1048 } 1049 1050 netsnmp_free_delegated_cache(cache); 1051 (void) pthread_mutex_unlock(&update_lock); 1052 } 1053 1054 static int 1055 sunFmFaultEventTable_handler(netsnmp_mib_handler *handler, 1056 netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, 1057 netsnmp_request_info *requests) 1058 { 1059 netsnmp_request_info *request; 1060 struct timeval tv; 1061 1062 tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 1063 tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 1064 1065 request_update(); 1066 1067 for (request = requests; request; request = request->next) { 1068 if (request->processed != 0) 1069 continue; 1070 1071 if (netsnmp_extract_table_info(request) == NULL) 1072 continue; 1073 1074 request->delegated = 1; 1075 (void) snmp_alarm_register_hr(tv, 0, 1076 sunFmFaultEventTable_return, 1077 (void *) netsnmp_create_delegated_cache(handler, reginfo, 1078 reqinfo, request, NULL)); 1079 } 1080 1081 return (SNMP_ERR_NOERROR); 1082 } 1083