1749f21d3Swesolows /* 2749f21d3Swesolows * CDDL HEADER START 3749f21d3Swesolows * 4749f21d3Swesolows * The contents of this file are subject to the terms of the 5749f21d3Swesolows * Common Development and Distribution License (the "License"). 6749f21d3Swesolows * You may not use this file except in compliance with the License. 7749f21d3Swesolows * 8749f21d3Swesolows * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9749f21d3Swesolows * or http://www.opensolaris.org/os/licensing. 10749f21d3Swesolows * See the License for the specific language governing permissions 11749f21d3Swesolows * and limitations under the License. 12749f21d3Swesolows * 13749f21d3Swesolows * When distributing Covered Code, include this CDDL HEADER in each 14749f21d3Swesolows * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15749f21d3Swesolows * If applicable, add the following below this CDDL HEADER, with the 16749f21d3Swesolows * fields enclosed by brackets "[]" replaced with your own identifying 17749f21d3Swesolows * information: Portions Copyright [yyyy] [name of copyright owner] 18749f21d3Swesolows * 19749f21d3Swesolows * CDDL HEADER END 20749f21d3Swesolows */ 21749f21d3Swesolows 22749f21d3Swesolows /* 23888e0559SRobert Johnston * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24749f21d3Swesolows * Use is subject to license terms. 25749f21d3Swesolows */ 26749f21d3Swesolows 27749f21d3Swesolows #include <fm/fmd_adm.h> 28749f21d3Swesolows #include <fm/fmd_snmp.h> 29749f21d3Swesolows #include <net-snmp/net-snmp-config.h> 30749f21d3Swesolows #include <net-snmp/net-snmp-includes.h> 31749f21d3Swesolows #include <net-snmp/agent/net-snmp-agent-includes.h> 32749f21d3Swesolows #include <pthread.h> 33749f21d3Swesolows #include <stddef.h> 34749f21d3Swesolows #include <errno.h> 35749f21d3Swesolows #include <libuutil.h> 36749f21d3Swesolows #include "sunFM_impl.h" 37749f21d3Swesolows #include "resource.h" 38749f21d3Swesolows 39749f21d3Swesolows static uu_avl_pool_t *rsrc_fmri_avl_pool; 40749f21d3Swesolows static uu_avl_pool_t *rsrc_index_avl_pool; 41749f21d3Swesolows static uu_avl_t *rsrc_fmri_avl; 42749f21d3Swesolows static uu_avl_t *rsrc_index_avl; 43749f21d3Swesolows 44749f21d3Swesolows #define VALID_AVL_STATE (rsrc_fmri_avl_pool != NULL && \ 45749f21d3Swesolows rsrc_index_avl_pool != NULL && rsrc_fmri_avl != NULL && \ 46749f21d3Swesolows rsrc_index_avl != NULL) 47749f21d3Swesolows 48749f21d3Swesolows #define UPDATE_WAIT_MILLIS 10 /* poll interval in milliseconds */ 49749f21d3Swesolows 50749f21d3Swesolows /* 51749f21d3Swesolows * Update types: single-index and all are mutually exclusive; a count 52749f21d3Swesolows * update is optional. 53749f21d3Swesolows */ 54749f21d3Swesolows #define UCT_INDEX 0x1 55749f21d3Swesolows #define UCT_ALL 0x2 56749f21d3Swesolows #define UCT_COUNT 0x4 57749f21d3Swesolows #define UCT_FLAGS 0x7 58749f21d3Swesolows 59749f21d3Swesolows #define RESOURCE_DATA_VALID(d) ((d)->d_valid == valid_stamp) 60749f21d3Swesolows 61749f21d3Swesolows /* 62749f21d3Swesolows * Locking strategy is described in module.c. 63749f21d3Swesolows */ 64749f21d3Swesolows static ulong_t max_index; 65749f21d3Swesolows static int valid_stamp; 66749f21d3Swesolows static uint32_t rsrc_count; 67749f21d3Swesolows static pthread_mutex_t update_lock; 68749f21d3Swesolows static pthread_cond_t update_cv; 69749f21d3Swesolows static volatile enum { US_QUIET, US_NEEDED, US_INPROGRESS } update_status; 70749f21d3Swesolows 71749f21d3Swesolows static Netsnmp_Node_Handler sunFmResourceTable_handler; 72749f21d3Swesolows static Netsnmp_Node_Handler sunFmResourceCount_handler; 73749f21d3Swesolows 74749f21d3Swesolows static sunFmResource_data_t * 75749f21d3Swesolows key_build(const char *fmri, const ulong_t index) 76749f21d3Swesolows { 77749f21d3Swesolows static sunFmResource_data_t key; 78749f21d3Swesolows 79749f21d3Swesolows key.d_index = index; 80749f21d3Swesolows if (fmri) 8130698f33Swesolows (void) strlcpy(key.d_ari_fmri, fmri, sizeof (key.d_ari_fmri)); 82749f21d3Swesolows else 83749f21d3Swesolows key.d_ari_fmri[0] = '\0'; 84749f21d3Swesolows 85749f21d3Swesolows return (&key); 86749f21d3Swesolows } 87749f21d3Swesolows 88749f21d3Swesolows /* 89749f21d3Swesolows * If fmri is the fmri of a resource we have previously seen and indexed, return 90749f21d3Swesolows * data for it. Otherwise, return NULL. Note that the resource may not be 91749f21d3Swesolows * valid; that is, it may have been removed from the fault manager since its 92749f21d3Swesolows * information was last updated. 93749f21d3Swesolows */ 94749f21d3Swesolows static sunFmResource_data_t * 95749f21d3Swesolows resource_lookup_fmri(const char *fmri) 96749f21d3Swesolows { 97749f21d3Swesolows sunFmResource_data_t *key; 98749f21d3Swesolows 99749f21d3Swesolows key = key_build(fmri, 0); 100749f21d3Swesolows return (uu_avl_find(rsrc_fmri_avl, key, NULL, NULL)); 101749f21d3Swesolows } 102749f21d3Swesolows 103749f21d3Swesolows /* 104749f21d3Swesolows * If index corresponds to a resource we have previously seen and indexed, 105749f21d3Swesolows * return data for it. Otherwise, return NULL. Note that the resource may 106749f21d3Swesolows * not be valid; that is, it may have been expired from the fault manager 107749f21d3Swesolows * since its information was last updated. 108749f21d3Swesolows */ 109749f21d3Swesolows static sunFmResource_data_t * 110749f21d3Swesolows resource_lookup_index_exact(const ulong_t index) 111749f21d3Swesolows { 112749f21d3Swesolows sunFmResource_data_t *key; 113749f21d3Swesolows 114749f21d3Swesolows key = key_build(NULL, index); 115749f21d3Swesolows return (uu_avl_find(rsrc_index_avl, key, NULL, NULL)); 116749f21d3Swesolows } 117749f21d3Swesolows 118749f21d3Swesolows /* 119749f21d3Swesolows * If index corresponds to a valid (that is, extant as of latest information 120749f21d3Swesolows * from the fault manager) resource, return the data for that resource. 121749f21d3Swesolows * Otherwise, return the data for the valid resource whose index is as close as 122749f21d3Swesolows * possible to index but not lower. This preserves the lexicographical 123749f21d3Swesolows * ordering required for GETNEXT processing. 124749f21d3Swesolows */ 125749f21d3Swesolows static sunFmResource_data_t * 126749f21d3Swesolows resource_lookup_index_nextvalid(const ulong_t index) 127749f21d3Swesolows { 128749f21d3Swesolows sunFmResource_data_t *key, *data; 129749f21d3Swesolows uu_avl_index_t idx; 130749f21d3Swesolows 131749f21d3Swesolows key = key_build(NULL, index); 132749f21d3Swesolows 133749f21d3Swesolows if ((data = uu_avl_find(rsrc_index_avl, key, NULL, &idx)) != NULL && 134749f21d3Swesolows RESOURCE_DATA_VALID(data)) 135749f21d3Swesolows return (data); 136749f21d3Swesolows 137749f21d3Swesolows data = uu_avl_nearest_next(rsrc_index_avl, idx); 138749f21d3Swesolows 1391fe76c0bSwesolows while (data != NULL && !RESOURCE_DATA_VALID(data)) 1401fe76c0bSwesolows data = uu_avl_next(rsrc_index_avl, data); 141749f21d3Swesolows 142749f21d3Swesolows return (data); 143749f21d3Swesolows } 144749f21d3Swesolows 145749f21d3Swesolows /* 146749f21d3Swesolows * Possible update the contents of a single resource within the cache. This 147749f21d3Swesolows * is our callback from fmd_rsrc_iter. 148749f21d3Swesolows */ 149749f21d3Swesolows static int 150749f21d3Swesolows rsrcinfo_update_one(const fmd_adm_rsrcinfo_t *rsrcinfo, void *arg) 151749f21d3Swesolows { 152749f21d3Swesolows const sunFmResource_update_ctx_t *update_ctx = 153749f21d3Swesolows (sunFmResource_update_ctx_t *)arg; 154749f21d3Swesolows sunFmResource_data_t *data = resource_lookup_fmri(rsrcinfo->ari_fmri); 155749f21d3Swesolows 156749f21d3Swesolows ++rsrc_count; 157749f21d3Swesolows 158749f21d3Swesolows /* 159749f21d3Swesolows * A resource we haven't seen before. We're obligated to index 160749f21d3Swesolows * it and link it into our cache so that we can find it, but we're 161749f21d3Swesolows * not obligated to fill it in completely unless we're doing a 162749f21d3Swesolows * full update or this is the resource we were asked for. This 163749f21d3Swesolows * avoids unnecessary iteration and memory manipulation for data 164749f21d3Swesolows * we're not going to return for this request. 165749f21d3Swesolows */ 166749f21d3Swesolows if (data == NULL) { 167749f21d3Swesolows uu_avl_index_t idx; 168749f21d3Swesolows 169749f21d3Swesolows DEBUGMSGTL((MODNAME_STR, "found new resource %s\n", 170749f21d3Swesolows rsrcinfo->ari_fmri)); 171749f21d3Swesolows if ((data = SNMP_MALLOC_TYPEDEF(sunFmResource_data_t)) == 172749f21d3Swesolows NULL) { 173888e0559SRobert Johnston (void) snmp_log(LOG_ERR, MODNAME_STR ": Out of memory " 174888e0559SRobert Johnston "for new resource data at %s:%d\n", __FILE__, 175888e0559SRobert Johnston __LINE__); 176749f21d3Swesolows return (1); 177749f21d3Swesolows } 178749f21d3Swesolows /* 179749f21d3Swesolows * We allocate indices sequentially and never reuse them. 180749f21d3Swesolows * This ensures we can always return valid GETNEXT responses 181749f21d3Swesolows * without having to reindex, and it provides the user a 182749f21d3Swesolows * more consistent view of the fault manager. 183749f21d3Swesolows */ 184749f21d3Swesolows data->d_index = ++max_index; 185749f21d3Swesolows DEBUGMSGTL((MODNAME_STR, "index %lu is %s@%p\n", data->d_index, 186749f21d3Swesolows rsrcinfo->ari_fmri, data)); 187749f21d3Swesolows 18830698f33Swesolows (void) strlcpy(data->d_ari_fmri, rsrcinfo->ari_fmri, 189749f21d3Swesolows sizeof (data->d_ari_fmri)); 190749f21d3Swesolows 191749f21d3Swesolows uu_avl_node_init(data, &data->d_fmri_avl, rsrc_fmri_avl_pool); 192749f21d3Swesolows (void) uu_avl_find(rsrc_fmri_avl, data, NULL, &idx); 193749f21d3Swesolows uu_avl_insert(rsrc_fmri_avl, data, idx); 194749f21d3Swesolows 195749f21d3Swesolows uu_avl_node_init(data, &data->d_index_avl, rsrc_index_avl_pool); 196749f21d3Swesolows (void) uu_avl_find(rsrc_index_avl, data, NULL, &idx); 197749f21d3Swesolows uu_avl_insert(rsrc_index_avl, data, idx); 198749f21d3Swesolows 199749f21d3Swesolows DEBUGMSGTL((MODNAME_STR, "completed new resource %lu/%s@%p\n", 200749f21d3Swesolows data->d_index, data->d_ari_fmri, data)); 201749f21d3Swesolows } 202749f21d3Swesolows 203749f21d3Swesolows data->d_valid = valid_stamp; 204749f21d3Swesolows 205*54575832SDan McDonald DEBUGMSGTL((MODNAME_STR, "timestamp updated for %lu/%s@%p: %d\n", 206749f21d3Swesolows data->d_index, data->d_ari_fmri, data, data->d_valid)); 207749f21d3Swesolows 208749f21d3Swesolows if ((update_ctx->uc_type & UCT_ALL) || 209749f21d3Swesolows update_ctx->uc_index == data->d_index) { 21030698f33Swesolows (void) strlcpy(data->d_ari_case, rsrcinfo->ari_case, 211749f21d3Swesolows sizeof (data->d_ari_case)); 212749f21d3Swesolows data->d_ari_flags = rsrcinfo->ari_flags; 213749f21d3Swesolows } 214749f21d3Swesolows 215749f21d3Swesolows return (!(update_ctx->uc_type & UCT_ALL) && 216749f21d3Swesolows update_ctx->uc_index == data->d_index); 217749f21d3Swesolows } 218749f21d3Swesolows 219749f21d3Swesolows /* 220749f21d3Swesolows * Update some or all resource data from fmd. If type includes UCT_ALL, all 221749f21d3Swesolows * resources will be indexed and their data cached. If type includes 222749f21d3Swesolows * UCT_INDEX, updates will stop once the resource matching index has been 223749f21d3Swesolows * updated. If UCT_COUNT is set, the number of faulted resources will be 224749f21d3Swesolows * set. 225749f21d3Swesolows * 226749f21d3Swesolows * Returns appropriate SNMP error codes. 227749f21d3Swesolows */ 228749f21d3Swesolows static int 229749f21d3Swesolows rsrcinfo_update(sunFmResource_update_ctx_t *update_ctx) 230749f21d3Swesolows { 231749f21d3Swesolows fmd_adm_t *adm; 232749f21d3Swesolows int err; 233749f21d3Swesolows 234749f21d3Swesolows ASSERT(update_ctx != NULL); 235749f21d3Swesolows ASSERT((update_ctx->uc_type & (UCT_ALL|UCT_INDEX)) != 236749f21d3Swesolows (UCT_ALL|UCT_INDEX)); 237749f21d3Swesolows ASSERT((update_ctx->uc_type & ~UCT_FLAGS) == 0); 238749f21d3Swesolows ASSERT(VALID_AVL_STATE); 239749f21d3Swesolows 240749f21d3Swesolows if ((adm = fmd_adm_open(update_ctx->uc_host, update_ctx->uc_prog, 241749f21d3Swesolows update_ctx->uc_version)) == NULL) { 242888e0559SRobert Johnston (void) snmp_log(LOG_ERR, MODNAME_STR ": Communication with fmd " 243749f21d3Swesolows "failed: %s\n", strerror(errno)); 244749f21d3Swesolows return (SNMP_ERR_RESOURCEUNAVAILABLE); 245749f21d3Swesolows } 246749f21d3Swesolows 247749f21d3Swesolows if (update_ctx->uc_type == UCT_COUNT) { 248749f21d3Swesolows err = fmd_adm_rsrc_count(adm, update_ctx->uc_all, &rsrc_count); 249749f21d3Swesolows } else { 250749f21d3Swesolows ++valid_stamp; 251749f21d3Swesolows rsrc_count = 0; 252749f21d3Swesolows err = fmd_adm_rsrc_iter(adm, update_ctx->uc_all, 253749f21d3Swesolows rsrcinfo_update_one, update_ctx); 254749f21d3Swesolows DEBUGMSGTL((MODNAME_STR, "resource iteration completed\n")); 255749f21d3Swesolows } 256749f21d3Swesolows 257749f21d3Swesolows fmd_adm_close(adm); 258749f21d3Swesolows 259749f21d3Swesolows if (err != 0) { 260888e0559SRobert Johnston (void) snmp_log(LOG_ERR, MODNAME_STR ": fmd resource " 261888e0559SRobert Johnston "information update failed: %s\n", fmd_adm_errmsg(adm)); 262749f21d3Swesolows return (SNMP_ERR_RESOURCEUNAVAILABLE); 263749f21d3Swesolows } 264749f21d3Swesolows 265749f21d3Swesolows return (SNMP_ERR_NOERROR); 266749f21d3Swesolows } 267749f21d3Swesolows 268749f21d3Swesolows /*ARGSUSED*/ 269749f21d3Swesolows static void 270749f21d3Swesolows update_thread(void *arg) 271749f21d3Swesolows { 272749f21d3Swesolows /* 273749f21d3Swesolows * The current rsrcinfo_update implementation offers minimal savings 274749f21d3Swesolows * for the use of index-only updates; therefore we always do a full 275749f21d3Swesolows * update. If it becomes advantageous to limit updates to a single 276749f21d3Swesolows * index, the contexts can be queued by the handler instead. 277749f21d3Swesolows */ 278749f21d3Swesolows sunFmResource_update_ctx_t uc; 279749f21d3Swesolows 280749f21d3Swesolows uc.uc_host = NULL; 281749f21d3Swesolows uc.uc_prog = FMD_ADM_PROGRAM; 282749f21d3Swesolows uc.uc_version = FMD_ADM_VERSION; 283749f21d3Swesolows 28430698f33Swesolows uc.uc_all = 0; 285749f21d3Swesolows uc.uc_index = 0; 286749f21d3Swesolows uc.uc_type = UCT_ALL; 287749f21d3Swesolows 288749f21d3Swesolows for (;;) { 289749f21d3Swesolows (void) pthread_mutex_lock(&update_lock); 290749f21d3Swesolows update_status = US_QUIET; 291749f21d3Swesolows while (update_status == US_QUIET) 292749f21d3Swesolows (void) pthread_cond_wait(&update_cv, &update_lock); 293749f21d3Swesolows update_status = US_INPROGRESS; 294749f21d3Swesolows (void) pthread_mutex_unlock(&update_lock); 295749f21d3Swesolows (void) rsrcinfo_update(&uc); 296749f21d3Swesolows } 297749f21d3Swesolows } 298749f21d3Swesolows 299749f21d3Swesolows static void 300749f21d3Swesolows request_update(void) 301749f21d3Swesolows { 302749f21d3Swesolows (void) pthread_mutex_lock(&update_lock); 303749f21d3Swesolows if (update_status != US_QUIET) { 304749f21d3Swesolows (void) pthread_mutex_unlock(&update_lock); 305749f21d3Swesolows return; 306749f21d3Swesolows } 307749f21d3Swesolows update_status = US_NEEDED; 308749f21d3Swesolows (void) pthread_cond_signal(&update_cv); 309749f21d3Swesolows (void) pthread_mutex_unlock(&update_lock); 310749f21d3Swesolows } 311749f21d3Swesolows 312749f21d3Swesolows /*ARGSUSED*/ 313749f21d3Swesolows static int 314749f21d3Swesolows resource_compare_fmri(const void *l, const void *r, void *private) 315749f21d3Swesolows { 316749f21d3Swesolows sunFmResource_data_t *l_data = (sunFmResource_data_t *)l; 317749f21d3Swesolows sunFmResource_data_t *r_data = (sunFmResource_data_t *)r; 318749f21d3Swesolows 319749f21d3Swesolows ASSERT(l_data != NULL && r_data != NULL); 320749f21d3Swesolows 321749f21d3Swesolows return (strcmp(l_data->d_ari_fmri, r_data->d_ari_fmri)); 322749f21d3Swesolows } 323749f21d3Swesolows 324749f21d3Swesolows /*ARGSUSED*/ 325749f21d3Swesolows static int 326749f21d3Swesolows resource_compare_index(const void *l, const void *r, void *private) 327749f21d3Swesolows { 328749f21d3Swesolows sunFmResource_data_t *l_data = (sunFmResource_data_t *)l; 329749f21d3Swesolows sunFmResource_data_t *r_data = (sunFmResource_data_t *)r; 330749f21d3Swesolows 331749f21d3Swesolows ASSERT(l_data != NULL && r_data != NULL); 332749f21d3Swesolows 333749f21d3Swesolows return (l_data->d_index < r_data->d_index ? -1 : 334749f21d3Swesolows l_data->d_index > r_data->d_index ? 1 : 0); 335749f21d3Swesolows } 336749f21d3Swesolows 337749f21d3Swesolows int 338749f21d3Swesolows sunFmResourceTable_init(void) 339749f21d3Swesolows { 340749f21d3Swesolows static oid sunFmResourceTable_oid[] = { SUNFMRESOURCETABLE_OID }; 341749f21d3Swesolows static oid sunFmResourceCount_oid[] = { SUNFMRESOURCECOUNT_OID, 0 }; 342749f21d3Swesolows netsnmp_table_registration_info *table_info; 343749f21d3Swesolows netsnmp_handler_registration *handler; 344749f21d3Swesolows int err; 345749f21d3Swesolows 346749f21d3Swesolows if ((err = pthread_mutex_init(&update_lock, NULL)) != 0) { 347888e0559SRobert Johnston (void) snmp_log(LOG_ERR, MODNAME_STR ": mutex_init failure: " 348888e0559SRobert Johnston "%s\n", strerror(err)); 349749f21d3Swesolows return (MIB_REGISTRATION_FAILED); 350749f21d3Swesolows } 351749f21d3Swesolows if ((err = pthread_cond_init(&update_cv, NULL)) != 0) { 352888e0559SRobert Johnston (void) snmp_log(LOG_ERR, MODNAME_STR ": cond_init failure: " 353888e0559SRobert Johnston "%s\n", strerror(err)); 354749f21d3Swesolows return (MIB_REGISTRATION_FAILED); 355749f21d3Swesolows } 356749f21d3Swesolows 357749f21d3Swesolows if ((err = pthread_create(NULL, NULL, (void *(*)(void *))update_thread, 358749f21d3Swesolows NULL)) != 0) { 359888e0559SRobert Johnston (void) snmp_log(LOG_ERR, MODNAME_STR ": error creating update " 360749f21d3Swesolows "thread: %s\n", strerror(err)); 361749f21d3Swesolows return (MIB_REGISTRATION_FAILED); 362749f21d3Swesolows } 363749f21d3Swesolows 364749f21d3Swesolows if ((table_info = 365749f21d3Swesolows SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL) 366749f21d3Swesolows return (MIB_REGISTRATION_FAILED); 367749f21d3Swesolows 368749f21d3Swesolows if ((handler = netsnmp_create_handler_registration("sunFmResourceTable", 369749f21d3Swesolows sunFmResourceTable_handler, sunFmResourceTable_oid, 370749f21d3Swesolows OID_LENGTH(sunFmResourceTable_oid), HANDLER_CAN_RONLY)) == NULL) { 371749f21d3Swesolows SNMP_FREE(table_info); 372749f21d3Swesolows return (MIB_REGISTRATION_FAILED); 373749f21d3Swesolows } 374749f21d3Swesolows 375749f21d3Swesolows /* 376749f21d3Swesolows * The Net-SNMP template uses add_indexes here, but that 377749f21d3Swesolows * function is unsafe because it does not check for failure. 378749f21d3Swesolows */ 379749f21d3Swesolows if (netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED) == NULL) { 380749f21d3Swesolows SNMP_FREE(table_info); 381749f21d3Swesolows SNMP_FREE(handler); 382749f21d3Swesolows return (MIB_REGISTRATION_FAILED); 383749f21d3Swesolows } 384749f21d3Swesolows 385749f21d3Swesolows table_info->min_column = SUNFMRESOURCE_COLMIN; 386749f21d3Swesolows table_info->max_column = SUNFMRESOURCE_COLMAX; 387749f21d3Swesolows 388749f21d3Swesolows if ((rsrc_fmri_avl_pool = uu_avl_pool_create("rsrc_fmri", 389749f21d3Swesolows sizeof (sunFmResource_data_t), 390749f21d3Swesolows offsetof(sunFmResource_data_t, d_fmri_avl), resource_compare_fmri, 391749f21d3Swesolows UU_AVL_DEBUG)) == NULL) { 392888e0559SRobert Johnston (void) snmp_log(LOG_ERR, MODNAME_STR ": rsrc_fmri avl pool " 393888e0559SRobert Johnston "creation failed: %s\n", uu_strerror(uu_error())); 394749f21d3Swesolows snmp_free_varbind(table_info->indexes); 395749f21d3Swesolows SNMP_FREE(table_info); 396749f21d3Swesolows SNMP_FREE(handler); 397749f21d3Swesolows } 398749f21d3Swesolows 399749f21d3Swesolows if ((rsrc_fmri_avl = uu_avl_create(rsrc_fmri_avl_pool, NULL, 400749f21d3Swesolows UU_AVL_DEBUG)) == NULL) { 401888e0559SRobert Johnston (void) snmp_log(LOG_ERR, MODNAME_STR ": rsrc_fmri avl creation " 402749f21d3Swesolows "failed: %s\n", uu_strerror(uu_error())); 403749f21d3Swesolows snmp_free_varbind(table_info->indexes); 404749f21d3Swesolows SNMP_FREE(table_info); 405749f21d3Swesolows SNMP_FREE(handler); 406749f21d3Swesolows uu_avl_pool_destroy(rsrc_fmri_avl_pool); 407749f21d3Swesolows return (MIB_REGISTRATION_FAILED); 408749f21d3Swesolows } 409749f21d3Swesolows 410749f21d3Swesolows if ((rsrc_index_avl_pool = uu_avl_pool_create("rsrc_index", 411749f21d3Swesolows sizeof (sunFmResource_data_t), 412749f21d3Swesolows offsetof(sunFmResource_data_t, d_index_avl), 413749f21d3Swesolows resource_compare_index, UU_AVL_DEBUG)) == NULL) { 414888e0559SRobert Johnston (void) snmp_log(LOG_ERR, MODNAME_STR ": rsrc_index avl pool " 415888e0559SRobert Johnston "creation failed: %s\n", uu_strerror(uu_error())); 416749f21d3Swesolows snmp_free_varbind(table_info->indexes); 417749f21d3Swesolows SNMP_FREE(table_info); 418749f21d3Swesolows SNMP_FREE(handler); 419749f21d3Swesolows uu_avl_destroy(rsrc_fmri_avl); 420749f21d3Swesolows uu_avl_pool_destroy(rsrc_fmri_avl_pool); 421749f21d3Swesolows } 422749f21d3Swesolows 423749f21d3Swesolows if ((rsrc_index_avl = uu_avl_create(rsrc_index_avl_pool, NULL, 424749f21d3Swesolows UU_AVL_DEBUG)) == NULL) { 425888e0559SRobert Johnston (void) snmp_log(LOG_ERR, MODNAME_STR ": rsrc_index avl " 426888e0559SRobert Johnston "creation failed: %s\n", uu_strerror(uu_error())); 427749f21d3Swesolows snmp_free_varbind(table_info->indexes); 428749f21d3Swesolows SNMP_FREE(table_info); 429749f21d3Swesolows SNMP_FREE(handler); 430749f21d3Swesolows uu_avl_destroy(rsrc_fmri_avl); 431749f21d3Swesolows uu_avl_pool_destroy(rsrc_fmri_avl_pool); 432749f21d3Swesolows uu_avl_pool_destroy(rsrc_index_avl_pool); 433749f21d3Swesolows return (MIB_REGISTRATION_FAILED); 434749f21d3Swesolows } 435749f21d3Swesolows 436749f21d3Swesolows if ((err = netsnmp_register_table(handler, table_info)) != 437749f21d3Swesolows MIB_REGISTERED_OK) { 438749f21d3Swesolows snmp_free_varbind(table_info->indexes); 439749f21d3Swesolows SNMP_FREE(table_info); 440749f21d3Swesolows SNMP_FREE(handler); 441749f21d3Swesolows uu_avl_destroy(rsrc_fmri_avl); 442749f21d3Swesolows uu_avl_pool_destroy(rsrc_fmri_avl_pool); 443749f21d3Swesolows uu_avl_destroy(rsrc_index_avl); 444749f21d3Swesolows uu_avl_pool_destroy(rsrc_index_avl_pool); 445749f21d3Swesolows return (err); 446749f21d3Swesolows } 447749f21d3Swesolows 448749f21d3Swesolows if ((err = netsnmp_register_read_only_instance( 449749f21d3Swesolows netsnmp_create_handler_registration("sunFmResourceCount", 450749f21d3Swesolows sunFmResourceCount_handler, sunFmResourceCount_oid, 451749f21d3Swesolows OID_LENGTH(sunFmResourceCount_oid), HANDLER_CAN_RONLY))) != 452749f21d3Swesolows MIB_REGISTERED_OK) { 453749f21d3Swesolows /* 454749f21d3Swesolows * There's no way to unregister the table handler, so we 455749f21d3Swesolows * can't free any of the data, either. 456749f21d3Swesolows */ 457749f21d3Swesolows return (err); 458749f21d3Swesolows } 459749f21d3Swesolows 460749f21d3Swesolows return (MIB_REGISTERED_OK); 461749f21d3Swesolows } 462749f21d3Swesolows 463749f21d3Swesolows /* 464749f21d3Swesolows * These two functions form the core of GET/GETNEXT/GETBULK handling (the 465749f21d3Swesolows * only kind we do). They perform two functions: 466749f21d3Swesolows * 467749f21d3Swesolows * - First, frob the request to set all the index variables to correspond 468749f21d3Swesolows * to the value that's going to be returned. For GET, this is a nop; 469749f21d3Swesolows * for GETNEXT/GETBULK it always requires some work. 470749f21d3Swesolows * - Second, find and return the fmd resource information corresponding to 471749f21d3Swesolows * the (possibly updated) indices. 472749f21d3Swesolows * 473749f21d3Swesolows * These should be as fast as possible; they run in the agent thread. 474749f21d3Swesolows */ 475749f21d3Swesolows static sunFmResource_data_t * 476749f21d3Swesolows sunFmResourceTable_nextrsrc(netsnmp_handler_registration *reginfo, 477749f21d3Swesolows netsnmp_table_request_info *table_info) 478749f21d3Swesolows { 479749f21d3Swesolows sunFmResource_data_t *data; 480749f21d3Swesolows netsnmp_variable_list *var; 481749f21d3Swesolows ulong_t index; 482749f21d3Swesolows 483749f21d3Swesolows /* 484749f21d3Swesolows * If we have no index, we must make one. 485749f21d3Swesolows */ 486749f21d3Swesolows if (table_info->number_indexes < 1) { 487749f21d3Swesolows oid tmpoid[MAX_OID_LEN]; 488749f21d3Swesolows index = 1; 489749f21d3Swesolows 490749f21d3Swesolows DEBUGMSGTL((MODNAME_STR, "nextrsrc: no indexes given\n")); 491749f21d3Swesolows var = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list); 492888e0559SRobert Johnston (void) snmp_set_var_typed_value(var, ASN_UNSIGNED, 493888e0559SRobert Johnston (uchar_t *)&index, sizeof (index)); 49430698f33Swesolows (void) memcpy(tmpoid, reginfo->rootoid, 495749f21d3Swesolows reginfo->rootoid_len * sizeof (oid)); 496749f21d3Swesolows tmpoid[reginfo->rootoid_len] = 1; 497749f21d3Swesolows tmpoid[reginfo->rootoid_len + 1] = table_info->colnum; 498749f21d3Swesolows if (build_oid(&var->name, &var->name_length, tmpoid, 499749f21d3Swesolows reginfo->rootoid_len + 2, var) != SNMPERR_SUCCESS) { 500749f21d3Swesolows snmp_free_varbind(var); 501749f21d3Swesolows return (NULL); 502749f21d3Swesolows } 503749f21d3Swesolows DEBUGMSGTL((MODNAME_STR, "nextrsrc: built fake index:\n")); 504749f21d3Swesolows DEBUGMSGVAR((MODNAME_STR, var)); 505749f21d3Swesolows DEBUGMSG((MODNAME_STR, "\n")); 506749f21d3Swesolows } else { 50730698f33Swesolows var = snmp_clone_varbind(table_info->indexes); 508749f21d3Swesolows index = *var->val.integer; 509749f21d3Swesolows DEBUGMSGTL((MODNAME_STR, "nextrsrc: received index:\n")); 510749f21d3Swesolows DEBUGMSGVAR((MODNAME_STR, var)); 511749f21d3Swesolows DEBUGMSG((MODNAME_STR, "\n")); 512749f21d3Swesolows index++; 513749f21d3Swesolows } 514749f21d3Swesolows 51530698f33Swesolows snmp_free_varbind(table_info->indexes); 51630698f33Swesolows table_info->indexes = NULL; 51730698f33Swesolows table_info->number_indexes = 0; 51830698f33Swesolows 519749f21d3Swesolows if ((data = resource_lookup_index_nextvalid(index)) == NULL) { 520749f21d3Swesolows DEBUGMSGTL((MODNAME_STR, "nextrsrc: exact match not found for " 521749f21d3Swesolows "index %lu; trying next column\n", index)); 52230698f33Swesolows if (table_info->colnum >= 52330698f33Swesolows netsnmp_find_table_registration_info(reginfo)->max_column) { 524749f21d3Swesolows snmp_free_varbind(var); 525749f21d3Swesolows DEBUGMSGTL((MODNAME_STR, "nextrsrc: out of columns\n")); 526749f21d3Swesolows return (NULL); 527749f21d3Swesolows } 528749f21d3Swesolows table_info->colnum++; 529749f21d3Swesolows index = 1; 530749f21d3Swesolows 531749f21d3Swesolows data = resource_lookup_index_nextvalid(index); 532749f21d3Swesolows } 533749f21d3Swesolows 534749f21d3Swesolows if (data == NULL) { 535749f21d3Swesolows DEBUGMSGTL((MODNAME_STR, "nextrsrc: exact match not found for " 536749f21d3Swesolows "index %lu; stopping\n", index)); 537749f21d3Swesolows snmp_free_varbind(var); 538749f21d3Swesolows return (NULL); 539749f21d3Swesolows } 540749f21d3Swesolows 5411fe76c0bSwesolows *var->val.integer = data->d_index; 542749f21d3Swesolows table_info->indexes = var; 54330698f33Swesolows table_info->number_indexes = 1; 544749f21d3Swesolows 545749f21d3Swesolows DEBUGMSGTL((MODNAME_STR, "matching data is %lu/%s@%p\n", data->d_index, 546749f21d3Swesolows data->d_ari_fmri, data)); 547749f21d3Swesolows 548749f21d3Swesolows return (data); 549749f21d3Swesolows } 550749f21d3Swesolows 551749f21d3Swesolows /*ARGSUSED*/ 552749f21d3Swesolows static sunFmResource_data_t * 553749f21d3Swesolows sunFmResourceTable_rsrc(netsnmp_handler_registration *reginfo, 554749f21d3Swesolows netsnmp_table_request_info *table_info) 555749f21d3Swesolows { 556749f21d3Swesolows ASSERT(table_info->number_indexes == 1); 557749f21d3Swesolows 558749f21d3Swesolows return (resource_lookup_index_exact(table_info->index_oid[0])); 559749f21d3Swesolows } 560749f21d3Swesolows 56130698f33Swesolows /*ARGSUSED*/ 562749f21d3Swesolows static void 563749f21d3Swesolows sunFmResourceTable_return(unsigned int reg, void *arg) 564749f21d3Swesolows { 565749f21d3Swesolows netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *)arg; 566749f21d3Swesolows netsnmp_request_info *request; 567749f21d3Swesolows netsnmp_agent_request_info *reqinfo; 568749f21d3Swesolows netsnmp_handler_registration *reginfo; 569749f21d3Swesolows netsnmp_table_request_info *table_info; 570749f21d3Swesolows sunFmResource_data_t *data; 571749f21d3Swesolows ulong_t rsrcstate; 572749f21d3Swesolows 573749f21d3Swesolows ASSERT(netsnmp_handler_check_cache(cache) != NULL); 574749f21d3Swesolows 575749f21d3Swesolows (void) pthread_mutex_lock(&update_lock); 576749f21d3Swesolows if (update_status != US_QUIET) { 577749f21d3Swesolows struct timeval tv; 578749f21d3Swesolows 579749f21d3Swesolows tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 580749f21d3Swesolows tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 581749f21d3Swesolows 582749f21d3Swesolows (void) snmp_alarm_register_hr(tv, 0, sunFmResourceTable_return, 583749f21d3Swesolows cache); 584749f21d3Swesolows (void) pthread_mutex_unlock(&update_lock); 585749f21d3Swesolows return; 586749f21d3Swesolows } 587749f21d3Swesolows 588749f21d3Swesolows request = cache->requests; 589749f21d3Swesolows reqinfo = cache->reqinfo; 590749f21d3Swesolows reginfo = cache->reginfo; 591749f21d3Swesolows 592749f21d3Swesolows table_info = netsnmp_extract_table_info(request); 593749f21d3Swesolows request->delegated = 0; 594749f21d3Swesolows 595749f21d3Swesolows ASSERT(table_info->colnum >= SUNFMRESOURCE_COLMIN); 596749f21d3Swesolows ASSERT(table_info->colnum <= SUNFMRESOURCE_COLMAX); 597749f21d3Swesolows 598749f21d3Swesolows /* 599749f21d3Swesolows * table_info->colnum contains the column number requested. 600749f21d3Swesolows * table_info->indexes contains a linked list of snmp variable 601749f21d3Swesolows * bindings for the indexes of the table. Values in the list 602749f21d3Swesolows * have been set corresponding to the indexes of the 603749f21d3Swesolows * request. We have other guarantees as well: 604749f21d3Swesolows * 605749f21d3Swesolows * - The column number is always within range. 606749f21d3Swesolows * - If we have no index data, table_info->index_oid_len is 0. 607749f21d3Swesolows * - We will never receive requests outside our table nor 608749f21d3Swesolows * those with the first subid anything other than 1 (Entry) 609749f21d3Swesolows * nor those without a column number. This is true even 610749f21d3Swesolows * for GETNEXT requests. 611749f21d3Swesolows */ 612749f21d3Swesolows 613749f21d3Swesolows switch (reqinfo->mode) { 614749f21d3Swesolows case MODE_GET: 615749f21d3Swesolows if ((data = sunFmResourceTable_rsrc(reginfo, table_info)) == 616749f21d3Swesolows NULL) { 617749f21d3Swesolows netsnmp_free_delegated_cache(cache); 618749f21d3Swesolows (void) pthread_mutex_unlock(&update_lock); 619749f21d3Swesolows return; 620749f21d3Swesolows } 621749f21d3Swesolows break; 622749f21d3Swesolows case MODE_GETNEXT: 623749f21d3Swesolows case MODE_GETBULK: 624749f21d3Swesolows if ((data = sunFmResourceTable_nextrsrc(reginfo, table_info)) == 625749f21d3Swesolows NULL) { 626749f21d3Swesolows netsnmp_free_delegated_cache(cache); 627749f21d3Swesolows (void) pthread_mutex_unlock(&update_lock); 628749f21d3Swesolows return; 629749f21d3Swesolows } 630749f21d3Swesolows break; 631749f21d3Swesolows default: 632888e0559SRobert Johnston (void) snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request " 633888e0559SRobert Johnston "mode %d\n", reqinfo->mode); 634749f21d3Swesolows netsnmp_free_delegated_cache(cache); 635749f21d3Swesolows (void) pthread_mutex_unlock(&update_lock); 636749f21d3Swesolows return; 637749f21d3Swesolows } 638749f21d3Swesolows 639749f21d3Swesolows switch (table_info->colnum) { 640749f21d3Swesolows case SUNFMRESOURCE_COL_FMRI: 641888e0559SRobert Johnston (void) netsnmp_table_build_result(reginfo, request, table_info, 642749f21d3Swesolows ASN_OCTET_STR, (uchar_t *)data->d_ari_fmri, 643749f21d3Swesolows strlen(data->d_ari_fmri)); 644749f21d3Swesolows break; 645749f21d3Swesolows case SUNFMRESOURCE_COL_STATUS: 646749f21d3Swesolows switch (data->d_ari_flags & 647749f21d3Swesolows (FMD_ADM_RSRC_FAULTY|FMD_ADM_RSRC_UNUSABLE)) { 648749f21d3Swesolows default: 649749f21d3Swesolows rsrcstate = SUNFMRESOURCE_STATE_OK; 650749f21d3Swesolows break; 651749f21d3Swesolows case FMD_ADM_RSRC_FAULTY: 652749f21d3Swesolows rsrcstate = SUNFMRESOURCE_STATE_DEGRADED; 653749f21d3Swesolows break; 654749f21d3Swesolows case FMD_ADM_RSRC_UNUSABLE: 655749f21d3Swesolows rsrcstate = SUNFMRESOURCE_STATE_UNKNOWN; 656749f21d3Swesolows break; 657749f21d3Swesolows case FMD_ADM_RSRC_FAULTY | FMD_ADM_RSRC_UNUSABLE: 658749f21d3Swesolows rsrcstate = SUNFMRESOURCE_STATE_FAULTED; 659749f21d3Swesolows break; 660749f21d3Swesolows } 661888e0559SRobert Johnston (void) netsnmp_table_build_result(reginfo, request, table_info, 662749f21d3Swesolows ASN_INTEGER, (uchar_t *)&rsrcstate, 663749f21d3Swesolows sizeof (rsrcstate)); 664749f21d3Swesolows break; 665749f21d3Swesolows case SUNFMRESOURCE_COL_DIAGNOSISUUID: 666888e0559SRobert Johnston (void) netsnmp_table_build_result(reginfo, request, table_info, 667749f21d3Swesolows ASN_OCTET_STR, (uchar_t *)data->d_ari_case, 668749f21d3Swesolows strlen(data->d_ari_case)); 669749f21d3Swesolows break; 670749f21d3Swesolows default: 671749f21d3Swesolows break; 672749f21d3Swesolows } 673749f21d3Swesolows netsnmp_free_delegated_cache(cache); 674749f21d3Swesolows (void) pthread_mutex_unlock(&update_lock); 675749f21d3Swesolows } 676749f21d3Swesolows 677749f21d3Swesolows static int 678749f21d3Swesolows sunFmResourceTable_handler(netsnmp_mib_handler *handler, 679749f21d3Swesolows netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, 680749f21d3Swesolows netsnmp_request_info *requests) 681749f21d3Swesolows { 682749f21d3Swesolows netsnmp_request_info *request; 683749f21d3Swesolows struct timeval tv; 684749f21d3Swesolows 685749f21d3Swesolows tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 686749f21d3Swesolows tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 687749f21d3Swesolows 688749f21d3Swesolows request_update(); 689749f21d3Swesolows 690749f21d3Swesolows for (request = requests; request; request = request->next) { 691749f21d3Swesolows if (request->processed != 0) 692749f21d3Swesolows continue; 693749f21d3Swesolows 694749f21d3Swesolows if (netsnmp_extract_table_info(request) == NULL) 695749f21d3Swesolows continue; 696749f21d3Swesolows 697749f21d3Swesolows request->delegated = 1; 698749f21d3Swesolows (void) snmp_alarm_register_hr(tv, 0, sunFmResourceTable_return, 699749f21d3Swesolows (void *) netsnmp_create_delegated_cache(handler, reginfo, 700749f21d3Swesolows reqinfo, request, NULL)); 701749f21d3Swesolows } 702749f21d3Swesolows 703749f21d3Swesolows return (SNMP_ERR_NOERROR); 704749f21d3Swesolows } 705749f21d3Swesolows 70630698f33Swesolows /*ARGSUSED*/ 707749f21d3Swesolows static void 708749f21d3Swesolows sunFmResourceCount_return(unsigned int reg, void *arg) 709749f21d3Swesolows { 710749f21d3Swesolows netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *)arg; 711749f21d3Swesolows netsnmp_request_info *request; 712749f21d3Swesolows netsnmp_agent_request_info *reqinfo; 713749f21d3Swesolows ulong_t rsrc_count_long; 714749f21d3Swesolows 715749f21d3Swesolows ASSERT(netsnmp_handler_check_cache(cache) != NULL); 716749f21d3Swesolows 717749f21d3Swesolows (void) pthread_mutex_lock(&update_lock); 718749f21d3Swesolows if (update_status != US_QUIET) { 719749f21d3Swesolows struct timeval tv; 720749f21d3Swesolows 721749f21d3Swesolows tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 722749f21d3Swesolows tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 723749f21d3Swesolows 724749f21d3Swesolows (void) snmp_alarm_register_hr(tv, 0, sunFmResourceCount_return, 725749f21d3Swesolows cache); 726749f21d3Swesolows (void) pthread_mutex_unlock(&update_lock); 727749f21d3Swesolows return; 728749f21d3Swesolows } 729749f21d3Swesolows 730749f21d3Swesolows request = cache->requests; 731749f21d3Swesolows reqinfo = cache->reqinfo; 732749f21d3Swesolows 733749f21d3Swesolows request->delegated = 0; 734749f21d3Swesolows 735749f21d3Swesolows switch (reqinfo->mode) { 73630698f33Swesolows /* 73730698f33Swesolows * According to the documentation, it's not possible for us ever to 73830698f33Swesolows * be called with MODE_GETNEXT. However, Net-SNMP does the following: 73930698f33Swesolows * - set reqinfo->mode to MODE_GET 74030698f33Swesolows * - invoke the handler 74130698f33Swesolows * - set reqinfo->mode to MODE_GETNEXT (even if the request was not 74230698f33Swesolows * actually processed; i.e. it's been delegated) 74330698f33Swesolows * Since we're called back later with the same reqinfo, we see 74430698f33Swesolows * GETNEXT. Therefore this case is needed to work around the 74530698f33Swesolows * Net-SNMP bug. 74630698f33Swesolows */ 747749f21d3Swesolows case MODE_GET: 74830698f33Swesolows case MODE_GETNEXT: 749749f21d3Swesolows DEBUGMSGTL((MODNAME_STR, "resource count is %u\n", rsrc_count)); 750749f21d3Swesolows rsrc_count_long = (ulong_t)rsrc_count; 751888e0559SRobert Johnston (void) snmp_set_var_typed_value(request->requestvb, ASN_GAUGE, 752749f21d3Swesolows (uchar_t *)&rsrc_count_long, sizeof (rsrc_count_long)); 753749f21d3Swesolows break; 754749f21d3Swesolows default: 755888e0559SRobert Johnston (void) snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request " 756888e0559SRobert Johnston "mode %d\n", reqinfo->mode); 757749f21d3Swesolows } 758749f21d3Swesolows 759749f21d3Swesolows netsnmp_free_delegated_cache(cache); 760749f21d3Swesolows (void) pthread_mutex_unlock(&update_lock); 761749f21d3Swesolows } 762749f21d3Swesolows 763749f21d3Swesolows static int 764749f21d3Swesolows sunFmResourceCount_handler(netsnmp_mib_handler *handler, 765749f21d3Swesolows netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, 766749f21d3Swesolows netsnmp_request_info *requests) 767749f21d3Swesolows { 768749f21d3Swesolows struct timeval tv; 769749f21d3Swesolows 770749f21d3Swesolows tv.tv_sec = UPDATE_WAIT_MILLIS / 1000; 771749f21d3Swesolows tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000; 772749f21d3Swesolows 773749f21d3Swesolows request_update(); 774749f21d3Swesolows 775749f21d3Swesolows /* 776749f21d3Swesolows * We are never called for a GETNEXT when registered as an 777749f21d3Swesolows * instance; it's handled for us and converted to a GET. 778749f21d3Swesolows * Also, an instance handler is given only one request at a time, so 779749f21d3Swesolows * we don't need to loop over a list of requests. 780749f21d3Swesolows */ 781749f21d3Swesolows 782749f21d3Swesolows if (requests->processed != 0) 783749f21d3Swesolows return (SNMP_ERR_NOERROR); 784749f21d3Swesolows 785749f21d3Swesolows requests->delegated = 1; 786749f21d3Swesolows (void) snmp_alarm_register_hr(tv, 0, sunFmResourceCount_return, 787749f21d3Swesolows (void *) netsnmp_create_delegated_cache(handler, reginfo, 788749f21d3Swesolows reqinfo, requests, NULL)); 789749f21d3Swesolows 790749f21d3Swesolows return (SNMP_ERR_NOERROR); 791749f21d3Swesolows } 792