Print this page
NEX-18695 libfmd_snmp is unable to handle multiple OIDs in GET request
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-17777 snmptable produces bogus output for FM tables
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-3125 libfmd_snmp should compile with newer net-snmp
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
*** 22,40 ****
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <fm/fmd_adm.h>
#include <fm/fmd_snmp.h>
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-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;
--- 22,47 ----
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+ /*
+ * Copyright 2018 Nexenta Systems, Inc.
+ */
+
#include <fm/fmd_adm.h>
#include <fm/fmd_snmp.h>
+
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
!
#include <errno.h>
#include <libuutil.h>
+ #include <pthread.h>
+ #include <stddef.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;
*** 43,54 ****
#define VALID_AVL_STATE (rsrc_fmri_avl_pool != NULL && \
rsrc_index_avl_pool != NULL && rsrc_fmri_avl != NULL && \
rsrc_index_avl != NULL)
- #define UPDATE_WAIT_MILLIS 10 /* poll interval in milliseconds */
-
/*
* Update types: single-index and all are mutually exclusive; a count
* update is optional.
*/
#define UCT_INDEX 0x1
--- 50,59 ----
*** 56,74 ****
#define UCT_COUNT 0x4
#define UCT_FLAGS 0x7
#define RESOURCE_DATA_VALID(d) ((d)->d_valid == valid_stamp)
- /*
- * Locking strategy is described in module.c.
- */
static ulong_t max_index;
static int valid_stamp;
static uint32_t rsrc_count;
static pthread_mutex_t update_lock;
- static pthread_cond_t update_cv;
- static volatile enum { US_QUIET, US_NEEDED, US_INPROGRESS } update_status;
static Netsnmp_Node_Handler sunFmResourceTable_handler;
static Netsnmp_Node_Handler sunFmResourceCount_handler;
static sunFmResource_data_t *
--- 61,74 ----
*** 263,316 ****
}
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.
*/
- sunFmResource_update_ctx_t uc;
uc.uc_host = NULL;
uc.uc_prog = FMD_ADM_PROGRAM;
uc.uc_version = FMD_ADM_VERSION;
uc.uc_all = 0;
uc.uc_index = 0;
uc.uc_type = UCT_ALL;
- for (;;) {
- (void) pthread_mutex_lock(&update_lock);
- update_status = US_QUIET;
- while (update_status == US_QUIET)
- (void) pthread_cond_wait(&update_cv, &update_lock);
- update_status = US_INPROGRESS;
- (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;
- }
- update_status = US_NEEDED;
- (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)
{
sunFmResource_data_t *l_data = (sunFmResource_data_t *)l;
--- 263,295 ----
}
return (SNMP_ERR_NOERROR);
}
static void
! request_update(void)
{
+ sunFmResource_update_ctx_t uc;
+
/*
* 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.
*/
uc.uc_host = NULL;
uc.uc_prog = FMD_ADM_PROGRAM;
uc.uc_version = FMD_ADM_VERSION;
uc.uc_all = 0;
uc.uc_index = 0;
uc.uc_type = UCT_ALL;
(void) rsrcinfo_update(&uc);
}
/*ARGSUSED*/
static int
resource_compare_fmri(const void *l, const void *r, void *private)
{
sunFmResource_data_t *l_data = (sunFmResource_data_t *)l;
*** 346,368 ****
if ((err = pthread_mutex_init(&update_lock, NULL)) != 0) {
(void) snmp_log(LOG_ERR, MODNAME_STR ": mutex_init failure: "
"%s\n", strerror(err));
return (MIB_REGISTRATION_FAILED);
}
- if ((err = pthread_cond_init(&update_cv, NULL)) != 0) {
- (void) snmp_log(LOG_ERR, MODNAME_STR ": cond_init failure: "
- "%s\n", strerror(err));
- return (MIB_REGISTRATION_FAILED);
- }
- if ((err = pthread_create(NULL, NULL, (void *(*)(void *))update_thread,
- NULL)) != 0) {
- (void) snmp_log(LOG_ERR, MODNAME_STR ": error creating update "
- "thread: %s\n", strerror(err));
- return (MIB_REGISTRATION_FAILED);
- }
-
if ((table_info =
SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL)
return (MIB_REGISTRATION_FAILED);
if ((handler = netsnmp_create_handler_registration("sunFmResourceTable",
--- 325,335 ----
*** 459,474 ****
return (MIB_REGISTERED_OK);
}
/*
! * These two functions form the core of GET/GETNEXT/GETBULK handling (the
* 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;
! * for GETNEXT/GETBULK it always requires some work.
* - 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.
*/
--- 426,441 ----
return (MIB_REGISTERED_OK);
}
/*
! * These two functions form the core of GET/GETNEXT handling (the
* 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;
! * for GETNEXT it always requires some work.
* - 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.
*/
*** 557,598 ****
return (resource_lookup_index_exact(table_info->index_oid[0]));
}
/*ARGSUSED*/
! static void
! sunFmResourceTable_return(unsigned int reg, void *arg)
{
- netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *)arg;
- netsnmp_request_info *request;
- netsnmp_agent_request_info *reqinfo;
- netsnmp_handler_registration *reginfo;
netsnmp_table_request_info *table_info;
sunFmResource_data_t *data;
ulong_t rsrcstate;
! ASSERT(netsnmp_handler_check_cache(cache) != NULL);
(void) pthread_mutex_lock(&update_lock);
! if (update_status != US_QUIET) {
! struct timeval tv;
! tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
! tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
!
! (void) snmp_alarm_register_hr(tv, 0, sunFmResourceTable_return,
! cache);
! (void) pthread_mutex_unlock(&update_lock);
! return;
! }
!
! request = cache->requests;
! reqinfo = cache->reqinfo;
! reginfo = cache->reginfo;
!
table_info = netsnmp_extract_table_info(request);
! request->delegated = 0;
ASSERT(table_info->colnum >= SUNFMRESOURCE_COLMIN);
ASSERT(table_info->colnum <= SUNFMRESOURCE_COLMAX);
/*
--- 524,556 ----
return (resource_lookup_index_exact(table_info->index_oid[0]));
}
/*ARGSUSED*/
! static int
! sunFmResourceTable_handler(netsnmp_mib_handler *handler,
! netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo,
! netsnmp_request_info *request)
{
netsnmp_table_request_info *table_info;
sunFmResource_data_t *data;
ulong_t rsrcstate;
+ int ret = SNMP_ERR_NOERROR;
! /*
! * We don't support MODE_GETBULK directly, so all bulk requests should
! * come through bulk_to_next helper. Make sure it stays that way.
! */
! ASSERT(reqinfo->mode == MODE_GET || reqinfo->mode == MODE_GETNEXT);
(void) pthread_mutex_lock(&update_lock);
! request_update();
! for (; request != NULL; request = request->next) {
table_info = netsnmp_extract_table_info(request);
! if (table_info == NULL)
! continue;
ASSERT(table_info->colnum >= SUNFMRESOURCE_COLMIN);
ASSERT(table_info->colnum <= SUNFMRESOURCE_COLMAX);
/*
*** 607,647 ****
* - 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.
*/
-
switch (reqinfo->mode) {
case MODE_GET:
! if ((data = sunFmResourceTable_rsrc(reginfo, table_info)) ==
! NULL) {
! netsnmp_free_delegated_cache(cache);
! (void) pthread_mutex_unlock(&update_lock);
! return;
! }
break;
case MODE_GETNEXT:
! case MODE_GETBULK:
! if ((data = sunFmResourceTable_nextrsrc(reginfo, table_info)) ==
! NULL) {
! netsnmp_free_delegated_cache(cache);
! (void) pthread_mutex_unlock(&update_lock);
! return;
! }
break;
default:
! (void) snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request "
! "mode %d\n", reqinfo->mode);
! netsnmp_free_delegated_cache(cache);
! (void) pthread_mutex_unlock(&update_lock);
! return;
}
switch (table_info->colnum) {
case SUNFMRESOURCE_COL_FMRI:
! (void) netsnmp_table_build_result(reginfo, request, table_info,
! ASN_OCTET_STR, (uchar_t *)data->d_ari_fmri,
strlen(data->d_ari_fmri));
break;
case SUNFMRESOURCE_COL_STATUS:
switch (data->d_ari_flags &
(FMD_ADM_RSRC_FAULTY|FMD_ADM_RSRC_UNUSABLE)) {
--- 565,597 ----
* - 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.
*/
switch (reqinfo->mode) {
case MODE_GET:
! data = sunFmResourceTable_rsrc(reginfo, table_info);
! if (data == NULL)
! goto out;
break;
case MODE_GETNEXT:
! data = sunFmResourceTable_nextrsrc(reginfo, table_info);
! if (data == NULL)
! goto out;
break;
default:
! (void) snmp_log(LOG_ERR, MODNAME_STR
! ": unsupported request mode %d\n", reqinfo->mode);
! ret = SNMP_ERR_GENERR;
! goto out;
}
switch (table_info->colnum) {
case SUNFMRESOURCE_COL_FMRI:
! (void) netsnmp_table_build_result(reginfo, request,
! table_info, ASN_OCTET_STR,
! (uchar_t *)data->d_ari_fmri,
strlen(data->d_ari_fmri));
break;
case SUNFMRESOURCE_COL_STATUS:
switch (data->d_ari_flags &
(FMD_ADM_RSRC_FAULTY|FMD_ADM_RSRC_UNUSABLE)) {
*** 656,791 ****
break;
case FMD_ADM_RSRC_FAULTY | FMD_ADM_RSRC_UNUSABLE:
rsrcstate = SUNFMRESOURCE_STATE_FAULTED;
break;
}
! (void) netsnmp_table_build_result(reginfo, request, table_info,
! ASN_INTEGER, (uchar_t *)&rsrcstate,
sizeof (rsrcstate));
break;
case SUNFMRESOURCE_COL_DIAGNOSISUUID:
! (void) netsnmp_table_build_result(reginfo, request, table_info,
! ASN_OCTET_STR, (uchar_t *)data->d_ari_case,
strlen(data->d_ari_case));
break;
default:
break;
}
! netsnmp_free_delegated_cache(cache);
(void) pthread_mutex_unlock(&update_lock);
}
static int
! sunFmResourceTable_handler(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo,
! netsnmp_request_info *requests)
{
- netsnmp_request_info *request;
- struct timeval tv;
-
- tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
- tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
-
- request_update();
-
- for (request = requests; request; request = request->next) {
- if (request->processed != 0)
- continue;
-
- if (netsnmp_extract_table_info(request) == NULL)
- continue;
-
- request->delegated = 1;
- (void) snmp_alarm_register_hr(tv, 0, sunFmResourceTable_return,
- (void *) netsnmp_create_delegated_cache(handler, reginfo,
- reqinfo, request, NULL));
- }
-
- return (SNMP_ERR_NOERROR);
- }
-
- /*ARGSUSED*/
- static void
- sunFmResourceCount_return(unsigned int reg, void *arg)
- {
- netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *)arg;
- netsnmp_request_info *request;
- netsnmp_agent_request_info *reqinfo;
ulong_t rsrc_count_long;
! ASSERT(netsnmp_handler_check_cache(cache) != NULL);
(void) pthread_mutex_lock(&update_lock);
! if (update_status != US_QUIET) {
! struct timeval tv;
! tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
! tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
!
! (void) snmp_alarm_register_hr(tv, 0, sunFmResourceCount_return,
! cache);
! (void) pthread_mutex_unlock(&update_lock);
! return;
! }
!
! request = cache->requests;
! reqinfo = cache->reqinfo;
!
! request->delegated = 0;
!
switch (reqinfo->mode) {
/*
! * 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:
! DEBUGMSGTL((MODNAME_STR, "resource count is %u\n", rsrc_count));
rsrc_count_long = (ulong_t)rsrc_count;
! (void) snmp_set_var_typed_value(request->requestvb, ASN_GAUGE,
! (uchar_t *)&rsrc_count_long, sizeof (rsrc_count_long));
break;
default:
! (void) snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request "
! "mode %d\n", reqinfo->mode);
}
- netsnmp_free_delegated_cache(cache);
(void) pthread_mutex_unlock(&update_lock);
! }
!
! static int
! sunFmResourceCount_handler(netsnmp_mib_handler *handler,
! netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo,
! netsnmp_request_info *requests)
! {
! struct timeval tv;
!
! tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
! tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
!
! request_update();
!
! /*
! * 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.
! */
!
! if (requests->processed != 0)
! return (SNMP_ERR_NOERROR);
!
! requests->delegated = 1;
! (void) snmp_alarm_register_hr(tv, 0, sunFmResourceCount_return,
! (void *) netsnmp_create_delegated_cache(handler, reginfo,
! reqinfo, requests, NULL));
!
! return (SNMP_ERR_NOERROR);
}
--- 606,681 ----
break;
case FMD_ADM_RSRC_FAULTY | FMD_ADM_RSRC_UNUSABLE:
rsrcstate = SUNFMRESOURCE_STATE_FAULTED;
break;
}
! (void) netsnmp_table_build_result(reginfo, request,
! table_info, ASN_INTEGER, (uchar_t *)&rsrcstate,
sizeof (rsrcstate));
break;
case SUNFMRESOURCE_COL_DIAGNOSISUUID:
! (void) netsnmp_table_build_result(reginfo, request,
! table_info, ASN_OCTET_STR,
! (uchar_t *)data->d_ari_case,
strlen(data->d_ari_case));
break;
default:
break;
}
! }
!
! out:
(void) pthread_mutex_unlock(&update_lock);
+ return (ret);
}
+ /*ARGSUSED*/
static int
! sunFmResourceCount_handler(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo,
! netsnmp_request_info *request)
{
ulong_t rsrc_count_long;
+ int ret = SNMP_ERR_NOERROR;
! /*
! * We don't support MODE_GETBULK directly, so all bulk requests should
! * come through bulk_to_next helper. Make sure it stays that way.
! */
! ASSERT(reqinfo->mode == MODE_GET || reqinfo->mode == MODE_GETNEXT);
(void) pthread_mutex_lock(&update_lock);
! request_update();
! for (; request != NULL; request = request->next) {
switch (reqinfo->mode) {
/*
! * 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:
! DEBUGMSGTL((MODNAME_STR, "resource count is %u\n",
! rsrc_count));
rsrc_count_long = (ulong_t)rsrc_count;
! (void) snmp_set_var_typed_value(request->requestvb,
! ASN_GAUGE, (uchar_t *)&rsrc_count_long,
! sizeof (rsrc_count_long));
break;
default:
! (void) snmp_log(LOG_ERR, MODNAME_STR
! ": unsupported request mode: %d\n", reqinfo->mode);
! ret = SNMP_ERR_GENERR;
}
+ }
(void) pthread_mutex_unlock(&update_lock);
! return (ret);
}