module.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 "module.h"
static uu_avl_pool_t *mod_name_avl_pool;
static uu_avl_pool_t *mod_index_avl_pool;
static uu_avl_t *mod_name_avl;
static uu_avl_t *mod_index_avl;
mod_index_avl != NULL)
/*
* Update types. Single-index and all are mutually exclusive.
*/
#define UCT_INDEX 0x1
#define UCT_ALL 0x2
#define UCT_FLAGS 0x3
/*
* Locking rules are straightforward. There is only one updater thread
* for each table, and requests for update that are received while
* another update is in progress are ignored. The single per-table lock
* protects all the data for the table, the valid_stamp and max_index
* tags for new data, and - importantly - all the hidden static data
* used by the Net-SNMP library. The result return callbacks are always
* called in the master agent thread; holding the table lock is
* therefore sufficient since only one table's callback can be run at
* any one time. Finer-grained locking is possible here but
* substantially more difficult because nearly all Net-SNMP functions
* are unsafe.
*
* In practice this is more than adequate, since the purpose of
* threading out the update is to prevent excessively time-consuming
* data collection from bottlenecking the entire agent, not to improve
* result throughput (SNMP is not intended to be used for applications
* requiring high throughput anyway). If the agent itself ever becomes
* multithreaded, locking requirements become limited to our local
* per-table data (the tree, max_index, and valid_stamp), and the
* implementation could be revisited for better performance.
*/
static int valid_stamp;
static pthread_mutex_t update_lock;
static pthread_cond_t update_cv;
static sunFmModule_data_t *
{
static sunFmModule_data_t key;
if (name)
else
return (&key);
}
/*
* If name is the name of a module we have previously seen and indexed, return
* data for it. Otherwise, return NULL. Note that the module may not be
* valid; that is, it may have been removed from the fault manager since its
* information was last updated.
*/
static sunFmModule_data_t *
module_lookup_name(const char *name)
{
}
/*
* If index corresponds to a module we have previously seen and indexed, return
* data for it. Otherwise, return NULL. Note that the module may not be
* valid; that is, it may have been removed from the fault manager since its
* information was last updated.
*/
static sunFmModule_data_t *
{
}
/*
* If index corresponds to a valid (that is, extant as of latest information
* from the fault manager) fmd module, return the data for that module.
* Otherwise, return the data for the valid module whose index is as close as
* possible to index but not lower. This preserves the lexicographical
* ordering required for GETNEXT processing.
*/
static sunFmModule_data_t *
{
return (data);
return (data);
}
/*
* Possible update the contents of a single module within the cache. This
* is our callback from fmd_module_iter.
*/
static int
{
const sunFmModule_update_ctx_t *update_ctx =
/*
* An fmd module 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
* thorough update or this is the module we were asked for. This
* avoids unnecessary iteration and memory manipulation for data
* we're not going to return for this request.
*/
"for new module 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_ami_name));
}
sizeof (data->d_ami_vers));
sizeof (data->d_ami_desc));
}
}
/*
* Update some or all module data from fmd. If thorough is set, all modules
* will be indexed and their data cached. Otherwise, updates will stop once
* the module matching index has been updated.
*
* Returns appropriate SNMP error codes.
*/
static int
{
return (SNMP_ERR_RESOURCEUNAVAILABLE);
}
++valid_stamp;
return (SNMP_ERR_RESOURCEUNAVAILABLE);
}
return (SNMP_ERR_NOERROR);
}
/*ARGSUSED*/
static void
update_thread(void *arg)
{
/*
* The current modinfo_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) modinfo_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
module_compare_name(const void *l, const void *r, void *private)
{
}
/*ARGSUSED*/
static int
module_compare_index(const void *l, const void *r, void *private)
{
}
int
sunFmModuleTable_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 (sunFmModule_data_t),
UU_AVL_DEBUG)) == NULL) {
}
UU_AVL_DEBUG)) == NULL) {
return (MIB_REGISTRATION_FAILED);
}
sizeof (sunFmModule_data_t),
}
UU_AVL_DEBUG)) == NULL) {
return (MIB_REGISTRATION_FAILED);
}
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 module information corresponding to
* the (possibly updated) indices.
*
* These should be as fast as possible; they run in the agent thread.
*/
static sunFmModule_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 sunFmModule_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 SUNFMMODULE_COL_NAME:
break;
case SUNFMMODULE_COL_VERSION:
break;
case SUNFMMODULE_COL_STATUS:
sizeof (modstate));
break;
break;
default:
break;
}
(void) pthread_mutex_unlock(&update_lock);
}
static int
{
continue;
continue;
}
return (SNMP_ERR_NOERROR);
}