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