resource.c revision 545758327e65fa2c3d514152f4c010e8faddfa6d
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <fm/fmd_snmp.h>
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <pthread.h>
#include <stddef.h>
#include <errno.h>
#include <libuutil.h>
#include "sunFM_impl.h"
#include "resource.h"
static uu_avl_pool_t *rsrc_fmri_avl_pool;
static uu_avl_pool_t *rsrc_index_avl_pool;
static uu_avl_t *rsrc_fmri_avl;
static uu_avl_t *rsrc_index_avl;
rsrc_index_avl != NULL)
/*
* Update types: single-index and all are mutually exclusive; a count
* update is optional.
*/
#define UCT_INDEX 0x1
#define UCT_ALL 0x2
#define UCT_COUNT 0x4
#define UCT_FLAGS 0x7
/*
* Locking strategy is described in module.c.
*/
static int valid_stamp;
static uint32_t rsrc_count;
static pthread_mutex_t update_lock;
static pthread_cond_t update_cv;
static sunFmResource_data_t *
{
static sunFmResource_data_t key;
if (fmri)
else
return (&key);
}
/*
* If fmri is the fmri of a resource we have previously seen and indexed, return
* data for it. Otherwise, return NULL. Note that the resource may not be
* valid; that is, it may have been removed from the fault manager since its
* information was last updated.
*/
static sunFmResource_data_t *
resource_lookup_fmri(const char *fmri)
{
}
/*
* If index corresponds to a resource we have previously seen and indexed,
* return data for it. Otherwise, return NULL. Note that the resource may
* not be valid; that is, it may have been expired from the fault manager
* since its information was last updated.
*/
static sunFmResource_data_t *
{
}
/*
* If index corresponds to a valid (that is, extant as of latest information
* from the fault manager) resource, return the data for that resource.
* Otherwise, return the data for the valid resource whose index is as close as
* possible to index but not lower. This preserves the lexicographical
* ordering required for GETNEXT processing.
*/
static sunFmResource_data_t *
{
return (data);
return (data);
}
/*
* Possible update the contents of a single resource within the cache. This
* is our callback from fmd_rsrc_iter.
*/
static int
{
const sunFmResource_update_ctx_t *update_ctx =
++rsrc_count;
/*
* A resource we haven't seen before. We're obligated to index
* it and link it into our cache so that we can find it, but we're
* not obligated to fill it in completely unless we're doing a
* full update or this is the resource we were asked for. This
* avoids unnecessary iteration and memory manipulation for data
* we're not going to return for this request.
*/
NULL) {
"for new resource data at %s:%d\n", __FILE__,
__LINE__);
return (1);
}
/*
* We allocate indices sequentially and never reuse them.
* This ensures we can always return valid GETNEXT responses
* without having to reindex, and it provides the user a
* more consistent view of the fault manager.
*/
sizeof (data->d_ari_fmri));
}
sizeof (data->d_ari_case));
}
}
/*
* Update some or all resource data from fmd. If type includes UCT_ALL, all
* resources will be indexed and their data cached. If type includes
* UCT_INDEX, updates will stop once the resource matching index has been
* updated. If UCT_COUNT is set, the number of faulted resources will be
* set.
*
* Returns appropriate SNMP error codes.
*/
static int
{
int err;
return (SNMP_ERR_RESOURCEUNAVAILABLE);
}
} else {
++valid_stamp;
rsrc_count = 0;
}
if (err != 0) {
return (SNMP_ERR_RESOURCEUNAVAILABLE);
}
return (SNMP_ERR_NOERROR);
}
/*ARGSUSED*/
static void
update_thread(void *arg)
{
/*
* The current rsrcinfo_update implementation offers minimal savings
* for the use of index-only updates; therefore we always do a full
* update. If it becomes advantageous to limit updates to a single
* index, the contexts can be queued by the handler instead.
*/
for (;;) {
(void) pthread_mutex_lock(&update_lock);
while (update_status == US_QUIET)
(void) pthread_mutex_unlock(&update_lock);
(void) rsrcinfo_update(&uc);
}
}
static void
request_update(void)
{
(void) pthread_mutex_lock(&update_lock);
if (update_status != US_QUIET) {
(void) pthread_mutex_unlock(&update_lock);
return;
}
(void) pthread_cond_signal(&update_cv);
(void) pthread_mutex_unlock(&update_lock);
}
/*ARGSUSED*/
static int
resource_compare_fmri(const void *l, const void *r, void *private)
{
}
/*ARGSUSED*/
static int
resource_compare_index(const void *l, const void *r, void *private)
{
}
int
sunFmResourceTable_init(void)
{
int err;
return (MIB_REGISTRATION_FAILED);
}
return (MIB_REGISTRATION_FAILED);
}
NULL)) != 0) {
return (MIB_REGISTRATION_FAILED);
}
if ((table_info =
return (MIB_REGISTRATION_FAILED);
return (MIB_REGISTRATION_FAILED);
}
/*
* The Net-SNMP template uses add_indexes here, but that
* function is unsafe because it does not check for failure.
*/
return (MIB_REGISTRATION_FAILED);
}
sizeof (sunFmResource_data_t),
UU_AVL_DEBUG)) == NULL) {
}
UU_AVL_DEBUG)) == NULL) {
return (MIB_REGISTRATION_FAILED);
}
sizeof (sunFmResource_data_t),
}
UU_AVL_DEBUG)) == NULL) {
return (MIB_REGISTRATION_FAILED);
}
return (err);
}
netsnmp_create_handler_registration("sunFmResourceCount",
/*
* There's no way to unregister the table handler, so we
* can't free any of the data, either.
*/
return (err);
}
return (MIB_REGISTERED_OK);
}
/*
* only kind we do). They perform two functions:
*
* - First, frob the request to set all the index variables to correspond
* to the value that's going to be returned. For GET, this is a nop;
* - Second, find and return the fmd resource information corresponding to
* the (possibly updated) indices.
*
* These should be as fast as possible; they run in the agent thread.
*/
static sunFmResource_data_t *
{
/*
* If we have no index, we must make one.
*/
index = 1;
return (NULL);
}
} else {
index++;
}
table_info->number_indexes = 0;
"index %lu; trying next column\n", index));
if (table_info->colnum >=
return (NULL);
}
table_info->colnum++;
index = 1;
}
"index %lu; stopping\n", index));
return (NULL);
}
return (data);
}
/*ARGSUSED*/
static sunFmResource_data_t *
{
}
/*ARGSUSED*/
static void
{
(void) pthread_mutex_lock(&update_lock);
if (update_status != US_QUIET) {
cache);
(void) pthread_mutex_unlock(&update_lock);
return;
}
/*
* table_info->colnum contains the column number requested.
* table_info->indexes contains a linked list of snmp variable
* bindings for the indexes of the table. Values in the list
* have been set corresponding to the indexes of the
* request. We have other guarantees as well:
*
* - The column number is always within range.
* - If we have no index data, table_info->index_oid_len is 0.
* - We will never receive requests outside our table nor
* those with the first subid anything other than 1 (Entry)
* nor those without a column number. This is true even
* for GETNEXT requests.
*/
case MODE_GET:
NULL) {
(void) pthread_mutex_unlock(&update_lock);
return;
}
break;
case MODE_GETNEXT:
case MODE_GETBULK:
NULL) {
(void) pthread_mutex_unlock(&update_lock);
return;
}
break;
default:
(void) pthread_mutex_unlock(&update_lock);
return;
}
switch (table_info->colnum) {
case SUNFMRESOURCE_COL_FMRI:
break;
case SUNFMRESOURCE_COL_STATUS:
switch (data->d_ari_flags &
default:
break;
case FMD_ADM_RSRC_FAULTY:
break;
case FMD_ADM_RSRC_UNUSABLE:
break;
break;
}
sizeof (rsrcstate));
break;
break;
default:
break;
}
(void) pthread_mutex_unlock(&update_lock);
}
static int
{
continue;
continue;
}
return (SNMP_ERR_NOERROR);
}
/*ARGSUSED*/
static void
{
(void) pthread_mutex_lock(&update_lock);
if (update_status != US_QUIET) {
cache);
(void) pthread_mutex_unlock(&update_lock);
return;
}
/*
* According to the documentation, it's not possible for us ever to
* be called with MODE_GETNEXT. However, Net-SNMP does the following:
* - set reqinfo->mode to MODE_GET
* - invoke the handler
* - set reqinfo->mode to MODE_GETNEXT (even if the request was not
* actually processed; i.e. it's been delegated)
* Since we're called back later with the same reqinfo, we see
* GETNEXT. Therefore this case is needed to work around the
* Net-SNMP bug.
*/
case MODE_GET:
case MODE_GETNEXT:
break;
default:
}
(void) pthread_mutex_unlock(&update_lock);
}
static int
{
/*
* We are never called for a GETNEXT when registered as an
* instance; it's handled for us and converted to a GET.
* Also, an instance handler is given only one request at a time, so
* we don't need to loop over a list of requests.
*/
return (SNMP_ERR_NOERROR);
return (SNMP_ERR_NOERROR);
}