1*1303Swesolows /* 2*1303Swesolows * CDDL HEADER START 3*1303Swesolows * 4*1303Swesolows * The contents of this file are subject to the terms of the 5*1303Swesolows * Common Development and Distribution License (the "License"). 6*1303Swesolows * You may not use this file except in compliance with the License. 7*1303Swesolows * 8*1303Swesolows * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1303Swesolows * or http://www.opensolaris.org/os/licensing. 10*1303Swesolows * See the License for the specific language governing permissions 11*1303Swesolows * and limitations under the License. 12*1303Swesolows * 13*1303Swesolows * When distributing Covered Code, include this CDDL HEADER in each 14*1303Swesolows * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1303Swesolows * If applicable, add the following below this CDDL HEADER, with the 16*1303Swesolows * fields enclosed by brackets "[]" replaced with your own identifying 17*1303Swesolows * information: Portions Copyright [yyyy] [name of copyright owner] 18*1303Swesolows * 19*1303Swesolows * CDDL HEADER END 20*1303Swesolows */ 21*1303Swesolows 22*1303Swesolows /* 23*1303Swesolows * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*1303Swesolows * Use is subject to license terms. 25*1303Swesolows */ 26*1303Swesolows 27*1303Swesolows #pragma ident "%Z%%M% %I% %E% SMI" 28*1303Swesolows 29*1303Swesolows #include <fm/fmd_adm.h> 30*1303Swesolows #include <fm/fmd_snmp.h> 31*1303Swesolows #include <net-snmp/net-snmp-config.h> 32*1303Swesolows #include <net-snmp/net-snmp-includes.h> 33*1303Swesolows #include <net-snmp/agent/net-snmp-agent-includes.h> 34*1303Swesolows #include <pthread.h> 35*1303Swesolows #include <stddef.h> 36*1303Swesolows #include <errno.h> 37*1303Swesolows #include <libuutil.h> 38*1303Swesolows #include "sunFM_impl.h" 39*1303Swesolows #include "resource.h" 40*1303Swesolows 41*1303Swesolows static uu_avl_pool_t *rsrc_fmri_avl_pool; 42*1303Swesolows static uu_avl_pool_t *rsrc_index_avl_pool; 43*1303Swesolows static uu_avl_t *rsrc_fmri_avl; 44*1303Swesolows static uu_avl_t *rsrc_index_avl; 45*1303Swesolows 46*1303Swesolows #define VALID_AVL_STATE (rsrc_fmri_avl_pool != NULL && \ 47*1303Swesolows rsrc_index_avl_pool != NULL && rsrc_fmri_avl != NULL && \ 48*1303Swesolows rsrc_index_avl != NULL) 49*1303Swesolows 50*1303Swesolows #define UPDATE_WAIT_MILLIS 10 /* poll interval in milliseconds */ 51*1303Swesolows 52*1303Swesolows /* 53*1303Swesolows * Update types: single-index and all are mutually exclusive; a count 54*1303Swesolows * update is optional. 55*1303Swesolows */ 56*1303Swesolows #define UCT_INDEX 0x1 57*1303Swesolows #define UCT_ALL 0x2 58*1303Swesolows #define UCT_COUNT 0x4 59*1303Swesolows #define UCT_FLAGS 0x7 60*1303Swesolows 61*1303Swesolows #define RESOURCE_DATA_VALID(d) ((d)->d_valid == valid_stamp) 62*1303Swesolows 63*1303Swesolows /* 64*1303Swesolows * Locking strategy is described in module.c. 65*1303Swesolows */ 66*1303Swesolows static ulong_t max_index; 67*1303Swesolows static int valid_stamp; 68*1303Swesolows static uint32_t rsrc_count; 69*1303Swesolows static pthread_mutex_t update_lock; 70*1303Swesolows static pthread_cond_t update_cv; 71*1303Swesolows static volatile enum { US_QUIET, US_NEEDED, US_INPROGRESS } update_status; 72*1303Swesolows 73*1303Swesolows static Netsnmp_Node_Handler sunFmResourceTable_handler; 74*1303Swesolows static Netsnmp_Node_Handler sunFmResourceCount_handler; 75*1303Swesolows 76*1303Swesolows static sunFmResource_data_t * 77*1303Swesolows key_build(const char *fmri, const ulong_t index) 78*1303Swesolows { 79*1303Swesolows static sunFmResource_data_t key; 80*1303Swesolows 81*1303Swesolows key.d_index = index; 82*1303Swesolows if (fmri) 83*1303Swesolows strlcpy(key.d_ari_fmri, fmri, sizeof (key.d_ari_fmri)); 84*1303Swesolows else 85*1303Swesolows key.d_ari_fmri[0] = '\0'; 86*1303Swesolows 87*1303Swesolows return (&key); 88*1303Swesolows } 89*1303Swesolows 90*1303Swesolows /* 91*1303Swesolows * If fmri is the fmri of a resource we have previously seen and indexed, return 92*1303Swesolows * data for it. Otherwise, return NULL. Note that the resource may not be 93*1303Swesolows * valid; that is, it may have been removed from the fault manager since its 94*1303Swesolows * information was last updated. 95*1303Swesolows */ 96*1303Swesolows static sunFmResource_data_t * 97*1303Swesolows resource_lookup_fmri(const char *fmri) 98*1303Swesolows { 99*1303Swesolows sunFmResource_data_t *key; 100*1303Swesolows 101*1303Swesolows key = key_build(fmri, 0); 102*1303Swesolows return (uu_avl_find(rsrc_fmri_avl, key, NULL, NULL)); 103*1303Swesolows } 104*1303Swesolows 105*1303Swesolows /* 106*1303Swesolows * If index corresponds to a resource we have previously seen and indexed, 107*1303Swesolows * return data for it. Otherwise, return NULL. Note that the resource may 108*1303Swesolows * not be valid; that is, it may have been expired from the fault manager 109*1303Swesolows * since its information was last updated. 110*1303Swesolows */ 111*1303Swesolows static sunFmResource_data_t * 112*1303Swesolows resource_lookup_index_exact(const ulong_t index) 113*1303Swesolows { 114*1303Swesolows sunFmResource_data_t *key; 115*1303Swesolows 116*1303Swesolows key = key_build(NULL, index); 117*1303Swesolows return (uu_avl_find(rsrc_index_avl, key, NULL, NULL)); 118*1303Swesolows } 119*1303Swesolows 120*1303Swesolows /* 121*1303Swesolows * If index corresponds to a valid (that is, extant as of latest information 122*1303Swesolows * from the fault manager) resource, return the data for that resource. 123*1303Swesolows * Otherwise, return the data for the valid resource whose index is as close as 124*1303Swesolows * possible to index but not lower. This preserves the lexicographical 125*1303Swesolows * ordering required for GETNEXT processing. 126*1303Swesolows */ 127*1303Swesolows static sunFmResource_data_t * 128*1303Swesolows resource_lookup_index_nextvalid(const ulong_t index) 129*1303Swesolows { 130*1303Swesolows sunFmResource_data_t *key, *data; 131*1303Swesolows uu_avl_index_t idx; 132*1303Swesolows 133*1303Swesolows key = key_build(NULL, index); 134*1303Swesolows 135*1303Swesolows if ((data = uu_avl_find(rsrc_index_avl, key, NULL, &idx)) != NULL && 136*1303Swesolows RESOURCE_DATA_VALID(data)) 137*1303Swesolows return (data); 138*1303Swesolows 139*1303Swesolows data = uu_avl_nearest_next(rsrc_index_avl, idx); 140*1303Swesolows 141*1303Swesolows while (data != NULL && !RESOURCE_DATA_VALID(data)) { 142*1303Swesolows (void) uu_avl_find(rsrc_index_avl, data, NULL, &idx); 143*1303Swesolows data = uu_avl_nearest_next(rsrc_index_avl, idx); 144*1303Swesolows } 145*1303Swesolows 146*1303Swesolows return (data); 147*1303Swesolows } 148*1303Swesolows 149*1303Swesolows /* 150*1303Swesolows * Possible update the contents of a single resource within the cache. This 151*1303Swesolows * is our callback from fmd_rsrc_iter. 152*1303Swesolows */ 153*1303Swesolows static int 154*1303Swesolows rsrcinfo_update_one(const fmd_adm_rsrcinfo_t *rsrcinfo, void *arg) 155*1303Swesolows { 156*1303Swesolows const sunFmResource_update_ctx_t *update_ctx = 157*1303Swesolows (sunFmResource_update_ctx_t *)arg; 158*1303Swesolows sunFmResource_data_t *data = resource_lookup_fmri(rsrcinfo->ari_fmri); 159*1303Swesolows 160*1303Swesolows ++rsrc_count; 161*1303Swesolows 162*1303Swesolows /* 163*1303Swesolows * A resource we haven't seen before. We're obligated to index 164*1303Swesolows * it and link it into our cache so that we can find it, but we're 165*1303Swesolows * not obligated to fill it in completely unless we're doing a 166*1303Swesolows * full update or this is the resource we were asked for. This 167*1303Swesolows * avoids unnecessary iteration and memory manipulation for data 168*1303Swesolows * we're not going to return for this request. 169*1303Swesolows */ 170*1303Swesolows if (data == NULL) { 171*1303Swesolows uu_avl_index_t idx; 172*1303Swesolows 173*1303Swesolows DEBUGMSGTL((MODNAME_STR, "found new resource %s\n", 174*1303Swesolows rsrcinfo->ari_fmri)); 175*1303Swesolows if ((data = SNMP_MALLOC_TYPEDEF(sunFmResource_data_t)) == 176*1303Swesolows NULL) { 177*1303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": Out of memory for " 178*1303Swesolows "new resource data at %s:%d\n", __FILE__, __LINE__); 179*1303Swesolows return (1); 180*1303Swesolows } 181*1303Swesolows /* 182*1303Swesolows * We allocate indices sequentially and never reuse them. 183*1303Swesolows * This ensures we can always return valid GETNEXT responses 184*1303Swesolows * without having to reindex, and it provides the user a 185*1303Swesolows * more consistent view of the fault manager. 186*1303Swesolows */ 187*1303Swesolows data->d_index = ++max_index; 188*1303Swesolows DEBUGMSGTL((MODNAME_STR, "index %lu is %s@%p\n", data->d_index, 189*1303Swesolows rsrcinfo->ari_fmri, data)); 190*1303Swesolows 191*1303Swesolows strlcpy(data->d_ari_fmri, rsrcinfo->ari_fmri, 192*1303Swesolows sizeof (data->d_ari_fmri)); 193*1303Swesolows 194*1303Swesolows uu_avl_node_init(data, &data->d_fmri_avl, rsrc_fmri_avl_pool); 195*1303Swesolows (void) uu_avl_find(rsrc_fmri_avl, data, NULL, &idx); 196*1303Swesolows uu_avl_insert(rsrc_fmri_avl, data, idx); 197*1303Swesolows 198*1303Swesolows uu_avl_node_init(data, &data->d_index_avl, rsrc_index_avl_pool); 199*1303Swesolows (void) uu_avl_find(rsrc_index_avl, data, NULL, &idx); 200*1303Swesolows uu_avl_insert(rsrc_index_avl, data, idx); 201*1303Swesolows 202*1303Swesolows DEBUGMSGTL((MODNAME_STR, "completed new resource %lu/%s@%p\n", 203*1303Swesolows data->d_index, data->d_ari_fmri, data)); 204*1303Swesolows } 205*1303Swesolows 206*1303Swesolows data->d_valid = valid_stamp; 207*1303Swesolows 208*1303Swesolows DEBUGMSGTL((MODNAME_STR, "timestamp updated for %lu/%s@%p: %lu\n", 209*1303Swesolows data->d_index, data->d_ari_fmri, data, data->d_valid)); 210*1303Swesolows 211*1303Swesolows if ((update_ctx->uc_type & UCT_ALL) || 212*1303Swesolows update_ctx->uc_index == data->d_index) { 213*1303Swesolows strlcpy(data->d_ari_case, rsrcinfo->ari_case, 214*1303Swesolows sizeof (data->d_ari_case)); 215*1303Swesolows data->d_ari_flags = rsrcinfo->ari_flags; 216*1303Swesolows } 217*1303Swesolows 218*1303Swesolows return (!(update_ctx->uc_type & UCT_ALL) && 219*1303Swesolows update_ctx->uc_index == data->d_index); 220*1303Swesolows } 221*1303Swesolows 222*1303Swesolows /* 223*1303Swesolows * Update some or all resource data from fmd. If type includes UCT_ALL, all 224*1303Swesolows * resources will be indexed and their data cached. If type includes 225*1303Swesolows * UCT_INDEX, updates will stop once the resource matching index has been 226*1303Swesolows * updated. If UCT_COUNT is set, the number of faulted resources will be 227*1303Swesolows * set. 228*1303Swesolows * 229*1303Swesolows * Returns appropriate SNMP error codes. 230*1303Swesolows */ 231*1303Swesolows static int 232*1303Swesolows rsrcinfo_update(sunFmResource_update_ctx_t *update_ctx) 233*1303Swesolows { 234*1303Swesolows fmd_adm_t *adm; 235*1303Swesolows int err; 236*1303Swesolows 237*1303Swesolows ASSERT(update_ctx != NULL); 238*1303Swesolows ASSERT((update_ctx->uc_type & (UCT_ALL|UCT_INDEX)) != 239*1303Swesolows (UCT_ALL|UCT_INDEX)); 240*1303Swesolows ASSERT((update_ctx->uc_type & ~UCT_FLAGS) == 0); 241*1303Swesolows ASSERT(VALID_AVL_STATE); 242*1303Swesolows 243*1303Swesolows if ((adm = fmd_adm_open(update_ctx->uc_host, update_ctx->uc_prog, 244*1303Swesolows update_ctx->uc_version)) == NULL) { 245*1303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": Communication with fmd " 246*1303Swesolows "failed: %s\n", strerror(errno)); 247*1303Swesolows return (SNMP_ERR_RESOURCEUNAVAILABLE); 248*1303Swesolows } 249*1303Swesolows 250*1303Swesolows if (update_ctx->uc_type == UCT_COUNT) { 251*1303Swesolows err = fmd_adm_rsrc_count(adm, update_ctx->uc_all, &rsrc_count); 252*1303Swesolows } else { 253*1303Swesolows ++valid_stamp; 254*1303Swesolows rsrc_count = 0; 255*1303Swesolows err = fmd_adm_rsrc_iter(adm, update_ctx->uc_all, 256*1303Swesolows rsrcinfo_update_one, update_ctx); 257*1303Swesolows DEBUGMSGTL((MODNAME_STR, "resource iteration completed\n")); 258*1303Swesolows } 259*1303Swesolows 260*1303Swesolows fmd_adm_close(adm); 261*1303Swesolows 262*1303Swesolows if (err != 0) { 263*1303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": fmd resource information " 264*1303Swesolows "update failed: %s\n", fmd_adm_errmsg(adm)); 265*1303Swesolows return (SNMP_ERR_RESOURCEUNAVAILABLE); 266*1303Swesolows } 267*1303Swesolows 268*1303Swesolows return (SNMP_ERR_NOERROR); 269*1303Swesolows } 270*1303Swesolows 271*1303Swesolows /*ARGSUSED*/ 272*1303Swesolows static void 273*1303Swesolows update_thread(void *arg) 274*1303Swesolows { 275*1303Swesolows /* 276*1303Swesolows * The current rsrcinfo_update implementation offers minimal savings 277*1303Swesolows * for the use of index-only updates; therefore we always do a full 278*1303Swesolows * update. If it becomes advantageous to limit updates to a single 279*1303Swesolows * index, the contexts can be queued by the handler instead. 280*1303Swesolows */ 281*1303Swesolows sunFmResource_update_ctx_t uc; 282*1303Swesolows 283*1303Swesolows uc.uc_host = NULL; 284*1303Swesolows uc.uc_prog = FMD_ADM_PROGRAM; 285*1303Swesolows uc.uc_version = FMD_ADM_VERSION; 286*1303Swesolows 287*1303Swesolows uc.uc_index = 0; 288*1303Swesolows uc.uc_type = UCT_ALL; 289*1303Swesolows 290*1303Swesolows for (;;) { 291*1303Swesolows (void) pthread_mutex_lock(&update_lock); 292*1303Swesolows update_status = US_QUIET; 293*1303Swesolows while (update_status == US_QUIET) 294*1303Swesolows (void) pthread_cond_wait(&update_cv, &update_lock); 295*1303Swesolows update_status = US_INPROGRESS; 296*1303Swesolows (void) pthread_mutex_unlock(&update_lock); 297*1303Swesolows (void) rsrcinfo_update(&uc); 298*1303Swesolows } 299*1303Swesolows } 300*1303Swesolows 301*1303Swesolows static void 302*1303Swesolows request_update(void) 303*1303Swesolows { 304*1303Swesolows (void) pthread_mutex_lock(&update_lock); 305*1303Swesolows if (update_status != US_QUIET) { 306*1303Swesolows (void) pthread_mutex_unlock(&update_lock); 307*1303Swesolows return; 308*1303Swesolows } 309*1303Swesolows update_status = US_NEEDED; 310*1303Swesolows (void) pthread_cond_signal(&update_cv); 311*1303Swesolows (void) pthread_mutex_unlock(&update_lock); 312*1303Swesolows } 313*1303Swesolows 314*1303Swesolows /*ARGSUSED*/ 315*1303Swesolows static int 316*1303Swesolows resource_compare_fmri(const void *l, const void *r, void *private) 317*1303Swesolows { 318*1303Swesolows sunFmResource_data_t *l_data = (sunFmResource_data_t *)l; 319*1303Swesolows sunFmResource_data_t *r_data = (sunFmResource_data_t *)r; 320*1303Swesolows 321*1303Swesolows ASSERT(l_data != NULL && r_data != NULL); 322*1303Swesolows 323*1303Swesolows return (strcmp(l_data->d_ari_fmri, r_data->d_ari_fmri)); 324*1303Swesolows } 325*1303Swesolows 326*1303Swesolows /*ARGSUSED*/ 327*1303Swesolows static int 328*1303Swesolows resource_compare_index(const void *l, const void *r, void *private) 329*1303Swesolows { 330*1303Swesolows sunFmResource_data_t *l_data = (sunFmResource_data_t *)l; 331*1303Swesolows sunFmResource_data_t *r_data = (sunFmResource_data_t *)r; 332*1303Swesolows 333*1303Swesolows ASSERT(l_data != NULL && r_data != NULL); 334*1303Swesolows 335*1303Swesolows return (l_data->d_index < r_data->d_index ? -1 : 336*1303Swesolows l_data->d_index > r_data->d_index ? 1 : 0); 337*1303Swesolows } 338*1303Swesolows 339*1303Swesolows int 340*1303Swesolows sunFmResourceTable_init(void) 341*1303Swesolows { 342*1303Swesolows static oid sunFmResourceTable_oid[] = { SUNFMRESOURCETABLE_OID }; 343*1303Swesolows static oid sunFmResourceCount_oid[] = { SUNFMRESOURCECOUNT_OID, 0 }; 344*1303Swesolows netsnmp_table_registration_info *table_info; 345*1303Swesolows netsnmp_handler_registration *handler; 346*1303Swesolows int err; 347*1303Swesolows 348*1303Swesolows if ((err = pthread_mutex_init(&update_lock, NULL)) != 0) { 349*1303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": mutex_init failure: %s\n", 350*1303Swesolows strerror(err)); 351*1303Swesolows return (MIB_REGISTRATION_FAILED); 352*1303Swesolows } 353*1303Swesolows if ((err = pthread_cond_init(&update_cv, NULL)) != 0) { 354*1303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": cond_init failure: %s\n", 355*1303Swesolows strerror(err)); 356*1303Swesolows return (MIB_REGISTRATION_FAILED); 357*1303Swesolows } 358*1303Swesolows 359*1303Swesolows if ((err = pthread_create(NULL, NULL, (void *(*)(void *))update_thread, 360*1303Swesolows NULL)) != 0) { 361*1303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": error creating update " 362*1303Swesolows "thread: %s\n", strerror(err)); 363*1303Swesolows return (MIB_REGISTRATION_FAILED); 364*1303Swesolows } 365*1303Swesolows 366*1303Swesolows if ((table_info = 367*1303Swesolows SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL) 368*1303Swesolows return (MIB_REGISTRATION_FAILED); 369*1303Swesolows 370*1303Swesolows if ((handler = netsnmp_create_handler_registration("sunFmResourceTable", 371*1303Swesolows sunFmResourceTable_handler, sunFmResourceTable_oid, 372*1303Swesolows OID_LENGTH(sunFmResourceTable_oid), HANDLER_CAN_RONLY)) == NULL) { 373*1303Swesolows SNMP_FREE(table_info); 374*1303Swesolows return (MIB_REGISTRATION_FAILED); 375*1303Swesolows } 376*1303Swesolows 377*1303Swesolows /* 378*1303Swesolows * The Net-SNMP template uses add_indexes here, but that 379*1303Swesolows * function is unsafe because it does not check for failure. 380*1303Swesolows */ 381*1303Swesolows if (netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED) == NULL) { 382*1303Swesolows SNMP_FREE(table_info); 383*1303Swesolows SNMP_FREE(handler); 384*1303Swesolows return (MIB_REGISTRATION_FAILED); 385*1303Swesolows } 386*1303Swesolows 387*1303Swesolows table_info->min_column = SUNFMRESOURCE_COLMIN; 388*1303Swesolows table_info->max_column = SUNFMRESOURCE_COLMAX; 389*1303Swesolows 390*1303Swesolows if ((rsrc_fmri_avl_pool = uu_avl_pool_create("rsrc_fmri", 391*1303Swesolows sizeof (sunFmResource_data_t), 392*1303Swesolows offsetof(sunFmResource_data_t, d_fmri_avl), resource_compare_fmri, 393*1303Swesolows UU_AVL_DEBUG)) == NULL) { 394*1303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": rsrc_fmri avl pool creation " 395*1303Swesolows "failed: %s\n", uu_strerror(uu_error())); 396*1303Swesolows snmp_free_varbind(table_info->indexes); 397*1303Swesolows SNMP_FREE(table_info); 398*1303Swesolows SNMP_FREE(handler); 399*1303Swesolows } 400*1303Swesolows 401*1303Swesolows if ((rsrc_fmri_avl = uu_avl_create(rsrc_fmri_avl_pool, NULL, 402*1303Swesolows UU_AVL_DEBUG)) == NULL) { 403*1303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": rsrc_fmri avl creation " 404*1303Swesolows "failed: %s\n", uu_strerror(uu_error())); 405*1303Swesolows snmp_free_varbind(table_info->indexes); 406*1303Swesolows SNMP_FREE(table_info); 407*1303Swesolows SNMP_FREE(handler); 408*1303Swesolows uu_avl_pool_destroy(rsrc_fmri_avl_pool); 409*1303Swesolows return (MIB_REGISTRATION_FAILED); 410*1303Swesolows } 411*1303Swesolows 412*1303Swesolows if ((rsrc_index_avl_pool = uu_avl_pool_create("rsrc_index", 413*1303Swesolows sizeof (sunFmResource_data_t), 414*1303Swesolows offsetof(sunFmResource_data_t, d_index_avl), 415*1303Swesolows resource_compare_index, UU_AVL_DEBUG)) == NULL) { 416*1303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": rsrc_index avl pool creation " 417*1303Swesolows "failed: %s\n", uu_strerror(uu_error())); 418*1303Swesolows snmp_free_varbind(table_info->indexes); 419*1303Swesolows SNMP_FREE(table_info); 420*1303Swesolows SNMP_FREE(handler); 421*1303Swesolows uu_avl_destroy(rsrc_fmri_avl); 422*1303Swesolows uu_avl_pool_destroy(rsrc_fmri_avl_pool); 423*1303Swesolows } 424*1303Swesolows 425*1303Swesolows if ((rsrc_index_avl = uu_avl_create(rsrc_index_avl_pool, NULL, 426*1303Swesolows UU_AVL_DEBUG)) == NULL) { 427*1303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": rsrc_index avl creation " 428*1303Swesolows "failed: %s\n", uu_strerror(uu_error())); 429*1303Swesolows snmp_free_varbind(table_info->indexes); 430*1303Swesolows SNMP_FREE(table_info); 431*1303Swesolows SNMP_FREE(handler); 432*1303Swesolows uu_avl_destroy(rsrc_fmri_avl); 433*1303Swesolows uu_avl_pool_destroy(rsrc_fmri_avl_pool); 434*1303Swesolows uu_avl_pool_destroy(rsrc_index_avl_pool); 435*1303Swesolows return (MIB_REGISTRATION_FAILED); 436*1303Swesolows } 437*1303Swesolows 438*1303Swesolows if ((err = netsnmp_register_table(handler, table_info)) != 439*1303Swesolows MIB_REGISTERED_OK) { 440*1303Swesolows snmp_free_varbind(table_info->indexes); 441*1303Swesolows SNMP_FREE(table_info); 442*1303Swesolows SNMP_FREE(handler); 443*1303Swesolows uu_avl_destroy(rsrc_fmri_avl); 444*1303Swesolows uu_avl_pool_destroy(rsrc_fmri_avl_pool); 445*1303Swesolows uu_avl_destroy(rsrc_index_avl); 446*1303Swesolows uu_avl_pool_destroy(rsrc_index_avl_pool); 447*1303Swesolows return (err); 448*1303Swesolows } 449*1303Swesolows 450*1303Swesolows if ((err = netsnmp_register_read_only_instance( 451*1303Swesolows netsnmp_create_handler_registration("sunFmResourceCount", 452*1303Swesolows sunFmResourceCount_handler, sunFmResourceCount_oid, 453*1303Swesolows OID_LENGTH(sunFmResourceCount_oid), HANDLER_CAN_RONLY))) != 454*1303Swesolows MIB_REGISTERED_OK) { 455*1303Swesolows /* 456*1303Swesolows * There's no way to unregister the table handler, so we 457*1303Swesolows * can't free any of the data, either. 458*1303Swesolows */ 459*1303Swesolows return (err); 460*1303Swesolows } 461*1303Swesolows 462*1303Swesolows return (MIB_REGISTERED_OK); 463*1303Swesolows } 464*1303Swesolows 465*1303Swesolows /* 466*1303Swesolows * These two functions form the core of GET/GETNEXT/GETBULK handling (the 467*1303Swesolows * only kind we do). They perform two functions: 468*1303Swesolows * 469*1303Swesolows * - First, frob the request to set all the index variables to correspond 470*1303Swesolows * to the value that's going to be returned. For GET, this is a nop; 471*1303Swesolows * for GETNEXT/GETBULK it always requires some work. 472*1303Swesolows * - Second, find and return the fmd resource information corresponding to 473*1303Swesolows * the (possibly updated) indices. 474*1303Swesolows * 475*1303Swesolows * These should be as fast as possible; they run in the agent thread. 476*1303Swesolows */ 477*1303Swesolows static sunFmResource_data_t * 478*1303Swesolows sunFmResourceTable_nextrsrc(netsnmp_handler_registration *reginfo, 479*1303Swesolows netsnmp_table_request_info *table_info) 480*1303Swesolows { 481*1303Swesolows sunFmResource_data_t *data; 482*1303Swesolows netsnmp_variable_list *var; 483*1303Swesolows ulong_t index; 484*1303Swesolows 485*1303Swesolows /* 486*1303Swesolows * If we have no index, we must make one. 487*1303Swesolows */ 488*1303Swesolows if (table_info->number_indexes < 1) { 489*1303Swesolows oid tmpoid[MAX_OID_LEN]; 490*1303Swesolows index = 1; 491*1303Swesolows 492*1303Swesolows DEBUGMSGTL((MODNAME_STR, "nextrsrc: no indexes given\n")); 493*1303Swesolows var = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list); 494*1303Swesolows snmp_set_var_typed_value(var, ASN_UNSIGNED, (uchar_t *)&index, 495*1303Swesolows sizeof (index)); 496*1303Swesolows memcpy(tmpoid, reginfo->rootoid, 497*1303Swesolows reginfo->rootoid_len * sizeof (oid)); 498*1303Swesolows tmpoid[reginfo->rootoid_len] = 1; 499*1303Swesolows tmpoid[reginfo->rootoid_len + 1] = table_info->colnum; 500*1303Swesolows if (build_oid(&var->name, &var->name_length, tmpoid, 501*1303Swesolows reginfo->rootoid_len + 2, var) != SNMPERR_SUCCESS) { 502*1303Swesolows snmp_free_varbind(var); 503*1303Swesolows return (NULL); 504*1303Swesolows } 505*1303Swesolows DEBUGMSGTL((MODNAME_STR, "nextrsrc: built fake index:\n")); 506*1303Swesolows DEBUGMSGVAR((MODNAME_STR, var)); 507*1303Swesolows DEBUGMSG((MODNAME_STR, "\n")); 508*1303Swesolows } else { 509*1303Swesolows var = table_info->indexes; 510*1303Swesolows index = *var->val.integer; 511*1303Swesolows DEBUGMSGTL((MODNAME_STR, "nextrsrc: received index:\n")); 512*1303Swesolows DEBUGMSGVAR((MODNAME_STR, var)); 513*1303Swesolows DEBUGMSG((MODNAME_STR, "\n")); 514*1303Swesolows index++; 515*1303Swesolows } 516*1303Swesolows 517*1303Swesolows if ((data = resource_lookup_index_nextvalid(index)) == NULL) { 518*1303Swesolows DEBUGMSGTL((MODNAME_STR, "nextrsrc: exact match not found for " 519*1303Swesolows "index %lu; trying next column\n", index)); 520*1303Swesolows if (table_info->colnum >= SUNFMRESOURCE_COLMAX) { 521*1303Swesolows snmp_free_varbind(var); 522*1303Swesolows table_info->indexes = NULL; 523*1303Swesolows table_info->number_indexes = 0; 524*1303Swesolows DEBUGMSGTL((MODNAME_STR, "nextrsrc: out of columns\n")); 525*1303Swesolows return (NULL); 526*1303Swesolows } 527*1303Swesolows table_info->colnum++; 528*1303Swesolows index = 1; 529*1303Swesolows 530*1303Swesolows data = resource_lookup_index_nextvalid(index); 531*1303Swesolows } 532*1303Swesolows 533*1303Swesolows if (data == NULL) { 534*1303Swesolows DEBUGMSGTL((MODNAME_STR, "nextrsrc: exact match not found for " 535*1303Swesolows "index %lu; stopping\n", index)); 536*1303Swesolows snmp_free_varbind(var); 537*1303Swesolows table_info->indexes = NULL; 538*1303Swesolows table_info->number_indexes = 0; 539*1303Swesolows return (NULL); 540*1303Swesolows } 541*1303Swesolows 542*1303Swesolows *var->val.integer = index; 543*1303Swesolows table_info->indexes = var; 544*1303Swesolows 545*1303Swesolows DEBUGMSGTL((MODNAME_STR, "matching data is %lu/%s@%p\n", data->d_index, 546*1303Swesolows data->d_ari_fmri, data)); 547*1303Swesolows 548*1303Swesolows return (data); 549*1303Swesolows } 550*1303Swesolows 551*1303Swesolows /*ARGSUSED*/ 552*1303Swesolows static sunFmResource_data_t * 553*1303Swesolows sunFmResourceTable_rsrc(netsnmp_handler_registration *reginfo, 554*1303Swesolows netsnmp_table_request_info *table_info) 555*1303Swesolows { 556*1303Swesolows sunFmResource_data_t *data; 557*1303Swesolows netsnmp_variable_list *var; 558*1303Swesolows 559*1303Swesolows ASSERT(table_info->number_indexes == 1); 560*1303Swesolows 561*1303Swesolows return (resource_lookup_index_exact(table_info->index_oid[0])); 562*1303Swesolows } 563*1303Swesolows 564*1303Swesolows static void 565*1303Swesolows sunFmResourceTable_return(unsigned int reg, void *arg) 566*1303Swesolows { 567*1303Swesolows netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *)arg; 568*1303Swesolows netsnmp_request_info *request; 569*1303Swesolows netsnmp_agent_request_info *reqinfo; 570*1303Swesolows netsnmp_handler_registration *reginfo; 571*1303Swesolows netsnmp_mib_handler *handler; 572*1303Swesolows netsnmp_table_request_info *table_info; 573*1303Swesolows netsnmp_variable_list *var; 574*1303Swesolows sunFmResource_data_t *data; 575*1303Swesolows ulong_t rsrcstate; 576*1303Swesolows 577*1303Swesolows ASSERT(netsnmp_handler_check_cache(cache) != NULL); 578*1303Swesolows 579*1303Swesolows (void) pthread_mutex_lock(&update_lock); 580*1303Swesolows if (update_status != US_QUIET) { 581*1303Swesolows struct timeval tv; 582*1303Swesolows 583*1303Swesolows tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 584*1303Swesolows tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 585*1303Swesolows 586*1303Swesolows (void) snmp_alarm_register_hr(tv, 0, sunFmResourceTable_return, 587*1303Swesolows cache); 588*1303Swesolows (void) pthread_mutex_unlock(&update_lock); 589*1303Swesolows return; 590*1303Swesolows } 591*1303Swesolows 592*1303Swesolows request = cache->requests; 593*1303Swesolows reqinfo = cache->reqinfo; 594*1303Swesolows reginfo = cache->reginfo; 595*1303Swesolows handler = cache->handler; 596*1303Swesolows 597*1303Swesolows var = request->requestvb; 598*1303Swesolows table_info = netsnmp_extract_table_info(request); 599*1303Swesolows request->delegated = 0; 600*1303Swesolows 601*1303Swesolows ASSERT(table_info->colnum >= SUNFMRESOURCE_COLMIN); 602*1303Swesolows ASSERT(table_info->colnum <= SUNFMRESOURCE_COLMAX); 603*1303Swesolows 604*1303Swesolows /* 605*1303Swesolows * table_info->colnum contains the column number requested. 606*1303Swesolows * table_info->indexes contains a linked list of snmp variable 607*1303Swesolows * bindings for the indexes of the table. Values in the list 608*1303Swesolows * have been set corresponding to the indexes of the 609*1303Swesolows * request. We have other guarantees as well: 610*1303Swesolows * 611*1303Swesolows * - The column number is always within range. 612*1303Swesolows * - If we have no index data, table_info->index_oid_len is 0. 613*1303Swesolows * - We will never receive requests outside our table nor 614*1303Swesolows * those with the first subid anything other than 1 (Entry) 615*1303Swesolows * nor those without a column number. This is true even 616*1303Swesolows * for GETNEXT requests. 617*1303Swesolows */ 618*1303Swesolows 619*1303Swesolows switch (reqinfo->mode) { 620*1303Swesolows case MODE_GET: 621*1303Swesolows if ((data = sunFmResourceTable_rsrc(reginfo, table_info)) == 622*1303Swesolows NULL) { 623*1303Swesolows netsnmp_free_delegated_cache(cache); 624*1303Swesolows (void) pthread_mutex_unlock(&update_lock); 625*1303Swesolows return; 626*1303Swesolows } 627*1303Swesolows break; 628*1303Swesolows case MODE_GETNEXT: 629*1303Swesolows case MODE_GETBULK: 630*1303Swesolows if ((data = sunFmResourceTable_nextrsrc(reginfo, table_info)) == 631*1303Swesolows NULL) { 632*1303Swesolows netsnmp_free_delegated_cache(cache); 633*1303Swesolows (void) pthread_mutex_unlock(&update_lock); 634*1303Swesolows return; 635*1303Swesolows } 636*1303Swesolows break; 637*1303Swesolows default: 638*1303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request mode %d\n", 639*1303Swesolows reqinfo->mode); 640*1303Swesolows netsnmp_free_delegated_cache(cache); 641*1303Swesolows (void) pthread_mutex_unlock(&update_lock); 642*1303Swesolows return; 643*1303Swesolows } 644*1303Swesolows 645*1303Swesolows switch (table_info->colnum) { 646*1303Swesolows case SUNFMRESOURCE_COL_FMRI: 647*1303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 648*1303Swesolows ASN_OCTET_STR, (uchar_t *)data->d_ari_fmri, 649*1303Swesolows strlen(data->d_ari_fmri)); 650*1303Swesolows break; 651*1303Swesolows case SUNFMRESOURCE_COL_STATUS: 652*1303Swesolows switch (data->d_ari_flags & 653*1303Swesolows (FMD_ADM_RSRC_FAULTY|FMD_ADM_RSRC_UNUSABLE)) { 654*1303Swesolows default: 655*1303Swesolows rsrcstate = SUNFMRESOURCE_STATE_OK; 656*1303Swesolows break; 657*1303Swesolows case FMD_ADM_RSRC_FAULTY: 658*1303Swesolows rsrcstate = SUNFMRESOURCE_STATE_DEGRADED; 659*1303Swesolows break; 660*1303Swesolows case FMD_ADM_RSRC_UNUSABLE: 661*1303Swesolows rsrcstate = SUNFMRESOURCE_STATE_UNKNOWN; 662*1303Swesolows break; 663*1303Swesolows case FMD_ADM_RSRC_FAULTY | FMD_ADM_RSRC_UNUSABLE: 664*1303Swesolows rsrcstate = SUNFMRESOURCE_STATE_FAULTED; 665*1303Swesolows break; 666*1303Swesolows } 667*1303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 668*1303Swesolows ASN_INTEGER, (uchar_t *)&rsrcstate, 669*1303Swesolows sizeof (rsrcstate)); 670*1303Swesolows break; 671*1303Swesolows case SUNFMRESOURCE_COL_DIAGNOSISUUID: 672*1303Swesolows netsnmp_table_build_result(reginfo, request, table_info, 673*1303Swesolows ASN_OCTET_STR, (uchar_t *)data->d_ari_case, 674*1303Swesolows strlen(data->d_ari_case)); 675*1303Swesolows break; 676*1303Swesolows default: 677*1303Swesolows break; 678*1303Swesolows } 679*1303Swesolows netsnmp_free_delegated_cache(cache); 680*1303Swesolows (void) pthread_mutex_unlock(&update_lock); 681*1303Swesolows } 682*1303Swesolows 683*1303Swesolows static int 684*1303Swesolows sunFmResourceTable_handler(netsnmp_mib_handler *handler, 685*1303Swesolows netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, 686*1303Swesolows netsnmp_request_info *requests) 687*1303Swesolows { 688*1303Swesolows netsnmp_request_info *request; 689*1303Swesolows struct timeval tv; 690*1303Swesolows 691*1303Swesolows tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 692*1303Swesolows tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 693*1303Swesolows 694*1303Swesolows request_update(); 695*1303Swesolows 696*1303Swesolows for (request = requests; request; request = request->next) { 697*1303Swesolows if (request->processed != 0) 698*1303Swesolows continue; 699*1303Swesolows 700*1303Swesolows if (netsnmp_extract_table_info(request) == NULL) 701*1303Swesolows continue; 702*1303Swesolows 703*1303Swesolows request->delegated = 1; 704*1303Swesolows (void) snmp_alarm_register_hr(tv, 0, sunFmResourceTable_return, 705*1303Swesolows (void *) netsnmp_create_delegated_cache(handler, reginfo, 706*1303Swesolows reqinfo, request, NULL)); 707*1303Swesolows } 708*1303Swesolows 709*1303Swesolows return (SNMP_ERR_NOERROR); 710*1303Swesolows } 711*1303Swesolows 712*1303Swesolows static void 713*1303Swesolows sunFmResourceCount_return(unsigned int reg, void *arg) 714*1303Swesolows { 715*1303Swesolows netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *)arg; 716*1303Swesolows netsnmp_request_info *request; 717*1303Swesolows netsnmp_agent_request_info *reqinfo; 718*1303Swesolows netsnmp_handler_registration *reginfo; 719*1303Swesolows netsnmp_mib_handler *handler; 720*1303Swesolows ulong_t rsrc_count_long; 721*1303Swesolows int err; 722*1303Swesolows 723*1303Swesolows ASSERT(netsnmp_handler_check_cache(cache) != NULL); 724*1303Swesolows 725*1303Swesolows (void) pthread_mutex_lock(&update_lock); 726*1303Swesolows if (update_status != US_QUIET) { 727*1303Swesolows struct timeval tv; 728*1303Swesolows 729*1303Swesolows tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 730*1303Swesolows tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 731*1303Swesolows 732*1303Swesolows (void) snmp_alarm_register_hr(tv, 0, sunFmResourceCount_return, 733*1303Swesolows cache); 734*1303Swesolows (void) pthread_mutex_unlock(&update_lock); 735*1303Swesolows return; 736*1303Swesolows } 737*1303Swesolows 738*1303Swesolows request = cache->requests; 739*1303Swesolows reqinfo = cache->reqinfo; 740*1303Swesolows reginfo = cache->reginfo; 741*1303Swesolows handler = cache->handler; 742*1303Swesolows 743*1303Swesolows request->delegated = 0; 744*1303Swesolows 745*1303Swesolows switch (reqinfo->mode) { 746*1303Swesolows case MODE_GET: 747*1303Swesolows DEBUGMSGTL((MODNAME_STR, "resource count is %u\n", rsrc_count)); 748*1303Swesolows rsrc_count_long = (ulong_t)rsrc_count; 749*1303Swesolows snmp_set_var_typed_value(request->requestvb, ASN_GAUGE, 750*1303Swesolows (uchar_t *)&rsrc_count_long, sizeof (rsrc_count_long)); 751*1303Swesolows break; 752*1303Swesolows default: 753*1303Swesolows snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request mode %d\n", 754*1303Swesolows reqinfo->mode); 755*1303Swesolows } 756*1303Swesolows 757*1303Swesolows netsnmp_free_delegated_cache(cache); 758*1303Swesolows (void) pthread_mutex_unlock(&update_lock); 759*1303Swesolows } 760*1303Swesolows 761*1303Swesolows static int 762*1303Swesolows sunFmResourceCount_handler(netsnmp_mib_handler *handler, 763*1303Swesolows netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, 764*1303Swesolows netsnmp_request_info *requests) 765*1303Swesolows { 766*1303Swesolows struct timeval tv; 767*1303Swesolows 768*1303Swesolows tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 769*1303Swesolows tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 770*1303Swesolows 771*1303Swesolows request_update(); 772*1303Swesolows 773*1303Swesolows /* 774*1303Swesolows * We are never called for a GETNEXT when registered as an 775*1303Swesolows * instance; it's handled for us and converted to a GET. 776*1303Swesolows * Also, an instance handler is given only one request at a time, so 777*1303Swesolows * we don't need to loop over a list of requests. 778*1303Swesolows */ 779*1303Swesolows 780*1303Swesolows if (requests->processed != 0) 781*1303Swesolows return (SNMP_ERR_NOERROR); 782*1303Swesolows 783*1303Swesolows requests->delegated = 1; 784*1303Swesolows (void) snmp_alarm_register_hr(tv, 0, sunFmResourceCount_return, 785*1303Swesolows (void *) netsnmp_create_delegated_cache(handler, reginfo, 786*1303Swesolows reqinfo, requests, NULL)); 787*1303Swesolows 788*1303Swesolows return (SNMP_ERR_NOERROR); 789*1303Swesolows } 790