4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <fm/fmd_adm.h>
28 #include <fm/fmd_snmp.h>
29 #include <net-snmp/net-snmp-config.h>
30 #include <net-snmp/net-snmp-includes.h>
31 #include <net-snmp/agent/net-snmp-agent-includes.h>
36 #include "sunFM_impl.h"
39 static uu_avl_pool_t
*rsrc_fmri_avl_pool
;
40 static uu_avl_pool_t
*rsrc_index_avl_pool
;
41 static uu_avl_t
*rsrc_fmri_avl
;
42 static uu_avl_t
*rsrc_index_avl
;
44 #define VALID_AVL_STATE (rsrc_fmri_avl_pool != NULL && \
45 rsrc_index_avl_pool != NULL && rsrc_fmri_avl != NULL && \
46 rsrc_index_avl != NULL)
48 #define UPDATE_WAIT_MILLIS 10 /* poll interval in milliseconds */
51 * Update types: single-index and all are mutually exclusive; a count
59 #define RESOURCE_DATA_VALID(d) ((d)->d_valid == valid_stamp)
62 * Locking strategy is described in module.c.
64 static ulong_t max_index
;
65 static int valid_stamp
;
66 static uint32_t rsrc_count
;
67 static pthread_mutex_t update_lock
;
68 static pthread_cond_t update_cv
;
69 static volatile enum { US_QUIET
, US_NEEDED
, US_INPROGRESS
} update_status
;
71 static Netsnmp_Node_Handler sunFmResourceTable_handler
;
72 static Netsnmp_Node_Handler sunFmResourceCount_handler
;
74 static sunFmResource_data_t
*
75 key_build(const char *fmri
, const ulong_t index
)
77 static sunFmResource_data_t key
;
81 (void) strlcpy(key
.d_ari_fmri
, fmri
, sizeof (key
.d_ari_fmri
));
83 key
.d_ari_fmri
[0] = '\0';
89 * If fmri is the fmri of a resource we have previously seen and indexed, return
90 * data for it. Otherwise, return NULL. Note that the resource may not be
91 * valid; that is, it may have been removed from the fault manager since its
92 * information was last updated.
94 static sunFmResource_data_t
*
95 resource_lookup_fmri(const char *fmri
)
97 sunFmResource_data_t
*key
;
99 key
= key_build(fmri
, 0);
100 return (uu_avl_find(rsrc_fmri_avl
, key
, NULL
, NULL
));
104 * If index corresponds to a resource we have previously seen and indexed,
105 * return data for it. Otherwise, return NULL. Note that the resource may
106 * not be valid; that is, it may have been expired from the fault manager
107 * since its information was last updated.
109 static sunFmResource_data_t
*
110 resource_lookup_index_exact(const ulong_t index
)
112 sunFmResource_data_t
*key
;
114 key
= key_build(NULL
, index
);
115 return (uu_avl_find(rsrc_index_avl
, key
, NULL
, NULL
));
119 * If index corresponds to a valid (that is, extant as of latest information
120 * from the fault manager) resource, return the data for that resource.
121 * Otherwise, return the data for the valid resource whose index is as close as
122 * possible to index but not lower. This preserves the lexicographical
123 * ordering required for GETNEXT processing.
125 static sunFmResource_data_t
*
126 resource_lookup_index_nextvalid(const ulong_t index
)
128 sunFmResource_data_t
*key
, *data
;
131 key
= key_build(NULL
, index
);
133 if ((data
= uu_avl_find(rsrc_index_avl
, key
, NULL
, &idx
)) != NULL
&&
134 RESOURCE_DATA_VALID(data
))
137 data
= uu_avl_nearest_next(rsrc_index_avl
, idx
);
139 while (data
!= NULL
&& !RESOURCE_DATA_VALID(data
))
140 data
= uu_avl_next(rsrc_index_avl
, data
);
146 * Possible update the contents of a single resource within the cache. This
147 * is our callback from fmd_rsrc_iter.
150 rsrcinfo_update_one(const fmd_adm_rsrcinfo_t
*rsrcinfo
, void *arg
)
152 const sunFmResource_update_ctx_t
*update_ctx
=
153 (sunFmResource_update_ctx_t
*)arg
;
154 sunFmResource_data_t
*data
= resource_lookup_fmri(rsrcinfo
->ari_fmri
);
159 * A resource we haven't seen before. We're obligated to index
160 * it and link it into our cache so that we can find it, but we're
161 * not obligated to fill it in completely unless we're doing a
162 * full update or this is the resource we were asked for. This
163 * avoids unnecessary iteration and memory manipulation for data
164 * we're not going to return for this request.
169 DEBUGMSGTL((MODNAME_STR
, "found new resource %s\n",
170 rsrcinfo
->ari_fmri
));
171 if ((data
= SNMP_MALLOC_TYPEDEF(sunFmResource_data_t
)) ==
173 (void) snmp_log(LOG_ERR
, MODNAME_STR
": Out of memory "
174 "for new resource data at %s:%d\n", __FILE__
,
179 * We allocate indices sequentially and never reuse them.
180 * This ensures we can always return valid GETNEXT responses
181 * without having to reindex, and it provides the user a
182 * more consistent view of the fault manager.
184 data
->d_index
= ++max_index
;
185 DEBUGMSGTL((MODNAME_STR
, "index %lu is %s@%p\n", data
->d_index
,
186 rsrcinfo
->ari_fmri
, data
));
188 (void) strlcpy(data
->d_ari_fmri
, rsrcinfo
->ari_fmri
,
189 sizeof (data
->d_ari_fmri
));
191 uu_avl_node_init(data
, &data
->d_fmri_avl
, rsrc_fmri_avl_pool
);
192 (void) uu_avl_find(rsrc_fmri_avl
, data
, NULL
, &idx
);
193 uu_avl_insert(rsrc_fmri_avl
, data
, idx
);
195 uu_avl_node_init(data
, &data
->d_index_avl
, rsrc_index_avl_pool
);
196 (void) uu_avl_find(rsrc_index_avl
, data
, NULL
, &idx
);
197 uu_avl_insert(rsrc_index_avl
, data
, idx
);
199 DEBUGMSGTL((MODNAME_STR
, "completed new resource %lu/%s@%p\n",
200 data
->d_index
, data
->d_ari_fmri
, data
));
203 data
->d_valid
= valid_stamp
;
205 DEBUGMSGTL((MODNAME_STR
, "timestamp updated for %lu/%s@%p: %d\n",
206 data
->d_index
, data
->d_ari_fmri
, data
, data
->d_valid
));
208 if ((update_ctx
->uc_type
& UCT_ALL
) ||
209 update_ctx
->uc_index
== data
->d_index
) {
210 (void) strlcpy(data
->d_ari_case
, rsrcinfo
->ari_case
,
211 sizeof (data
->d_ari_case
));
212 data
->d_ari_flags
= rsrcinfo
->ari_flags
;
215 return (!(update_ctx
->uc_type
& UCT_ALL
) &&
216 update_ctx
->uc_index
== data
->d_index
);
220 * Update some or all resource data from fmd. If type includes UCT_ALL, all
221 * resources will be indexed and their data cached. If type includes
222 * UCT_INDEX, updates will stop once the resource matching index has been
223 * updated. If UCT_COUNT is set, the number of faulted resources will be
226 * Returns appropriate SNMP error codes.
229 rsrcinfo_update(sunFmResource_update_ctx_t
*update_ctx
)
234 ASSERT(update_ctx
!= NULL
);
235 ASSERT((update_ctx
->uc_type
& (UCT_ALL
|UCT_INDEX
)) !=
236 (UCT_ALL
|UCT_INDEX
));
237 ASSERT((update_ctx
->uc_type
& ~UCT_FLAGS
) == 0);
238 ASSERT(VALID_AVL_STATE
);
240 if ((adm
= fmd_adm_open(update_ctx
->uc_host
, update_ctx
->uc_prog
,
241 update_ctx
->uc_version
)) == NULL
) {
242 (void) snmp_log(LOG_ERR
, MODNAME_STR
": Communication with fmd "
243 "failed: %s\n", strerror(errno
));
244 return (SNMP_ERR_RESOURCEUNAVAILABLE
);
247 if (update_ctx
->uc_type
== UCT_COUNT
) {
248 err
= fmd_adm_rsrc_count(adm
, update_ctx
->uc_all
, &rsrc_count
);
252 err
= fmd_adm_rsrc_iter(adm
, update_ctx
->uc_all
,
253 rsrcinfo_update_one
, update_ctx
);
254 DEBUGMSGTL((MODNAME_STR
, "resource iteration completed\n"));
260 (void) snmp_log(LOG_ERR
, MODNAME_STR
": fmd resource "
261 "information update failed: %s\n", fmd_adm_errmsg(adm
));
262 return (SNMP_ERR_RESOURCEUNAVAILABLE
);
265 return (SNMP_ERR_NOERROR
);
270 update_thread(void *arg
)
273 * The current rsrcinfo_update implementation offers minimal savings
274 * for the use of index-only updates; therefore we always do a full
275 * update. If it becomes advantageous to limit updates to a single
276 * index, the contexts can be queued by the handler instead.
278 sunFmResource_update_ctx_t uc
;
281 uc
.uc_prog
= FMD_ADM_PROGRAM
;
282 uc
.uc_version
= FMD_ADM_VERSION
;
286 uc
.uc_type
= UCT_ALL
;
289 (void) pthread_mutex_lock(&update_lock
);
290 update_status
= US_QUIET
;
291 while (update_status
== US_QUIET
)
292 (void) pthread_cond_wait(&update_cv
, &update_lock
);
293 update_status
= US_INPROGRESS
;
294 (void) pthread_mutex_unlock(&update_lock
);
295 (void) rsrcinfo_update(&uc
);
302 (void) pthread_mutex_lock(&update_lock
);
303 if (update_status
!= US_QUIET
) {
304 (void) pthread_mutex_unlock(&update_lock
);
307 update_status
= US_NEEDED
;
308 (void) pthread_cond_signal(&update_cv
);
309 (void) pthread_mutex_unlock(&update_lock
);
314 resource_compare_fmri(const void *l
, const void *r
, void *private)
316 sunFmResource_data_t
*l_data
= (sunFmResource_data_t
*)l
;
317 sunFmResource_data_t
*r_data
= (sunFmResource_data_t
*)r
;
319 ASSERT(l_data
!= NULL
&& r_data
!= NULL
);
321 return (strcmp(l_data
->d_ari_fmri
, r_data
->d_ari_fmri
));
326 resource_compare_index(const void *l
, const void *r
, void *private)
328 sunFmResource_data_t
*l_data
= (sunFmResource_data_t
*)l
;
329 sunFmResource_data_t
*r_data
= (sunFmResource_data_t
*)r
;
331 ASSERT(l_data
!= NULL
&& r_data
!= NULL
);
333 return (l_data
->d_index
< r_data
->d_index
? -1 :
334 l_data
->d_index
> r_data
->d_index
? 1 : 0);
338 sunFmResourceTable_init(void)
340 static oid sunFmResourceTable_oid
[] = { SUNFMRESOURCETABLE_OID
};
341 static oid sunFmResourceCount_oid
[] = { SUNFMRESOURCECOUNT_OID
, 0 };
342 netsnmp_table_registration_info
*table_info
;
343 netsnmp_handler_registration
*handler
;
346 if ((err
= pthread_mutex_init(&update_lock
, NULL
)) != 0) {
347 (void) snmp_log(LOG_ERR
, MODNAME_STR
": mutex_init failure: "
348 "%s\n", strerror(err
));
349 return (MIB_REGISTRATION_FAILED
);
351 if ((err
= pthread_cond_init(&update_cv
, NULL
)) != 0) {
352 (void) snmp_log(LOG_ERR
, MODNAME_STR
": cond_init failure: "
353 "%s\n", strerror(err
));
354 return (MIB_REGISTRATION_FAILED
);
357 if ((err
= pthread_create(NULL
, NULL
, (void *(*)(void *))update_thread
,
359 (void) snmp_log(LOG_ERR
, MODNAME_STR
": error creating update "
360 "thread: %s\n", strerror(err
));
361 return (MIB_REGISTRATION_FAILED
);
365 SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info
)) == NULL
)
366 return (MIB_REGISTRATION_FAILED
);
368 if ((handler
= netsnmp_create_handler_registration("sunFmResourceTable",
369 sunFmResourceTable_handler
, sunFmResourceTable_oid
,
370 OID_LENGTH(sunFmResourceTable_oid
), HANDLER_CAN_RONLY
)) == NULL
) {
371 SNMP_FREE(table_info
);
372 return (MIB_REGISTRATION_FAILED
);
376 * The Net-SNMP template uses add_indexes here, but that
377 * function is unsafe because it does not check for failure.
379 if (netsnmp_table_helper_add_index(table_info
, ASN_UNSIGNED
) == NULL
) {
380 SNMP_FREE(table_info
);
382 return (MIB_REGISTRATION_FAILED
);
385 table_info
->min_column
= SUNFMRESOURCE_COLMIN
;
386 table_info
->max_column
= SUNFMRESOURCE_COLMAX
;
388 if ((rsrc_fmri_avl_pool
= uu_avl_pool_create("rsrc_fmri",
389 sizeof (sunFmResource_data_t
),
390 offsetof(sunFmResource_data_t
, d_fmri_avl
), resource_compare_fmri
,
391 UU_AVL_DEBUG
)) == NULL
) {
392 (void) snmp_log(LOG_ERR
, MODNAME_STR
": rsrc_fmri avl pool "
393 "creation failed: %s\n", uu_strerror(uu_error()));
394 snmp_free_varbind(table_info
->indexes
);
395 SNMP_FREE(table_info
);
399 if ((rsrc_fmri_avl
= uu_avl_create(rsrc_fmri_avl_pool
, NULL
,
400 UU_AVL_DEBUG
)) == NULL
) {
401 (void) snmp_log(LOG_ERR
, MODNAME_STR
": rsrc_fmri avl creation "
402 "failed: %s\n", uu_strerror(uu_error()));
403 snmp_free_varbind(table_info
->indexes
);
404 SNMP_FREE(table_info
);
406 uu_avl_pool_destroy(rsrc_fmri_avl_pool
);
407 return (MIB_REGISTRATION_FAILED
);
410 if ((rsrc_index_avl_pool
= uu_avl_pool_create("rsrc_index",
411 sizeof (sunFmResource_data_t
),
412 offsetof(sunFmResource_data_t
, d_index_avl
),
413 resource_compare_index
, UU_AVL_DEBUG
)) == NULL
) {
414 (void) snmp_log(LOG_ERR
, MODNAME_STR
": rsrc_index avl pool "
415 "creation failed: %s\n", uu_strerror(uu_error()));
416 snmp_free_varbind(table_info
->indexes
);
417 SNMP_FREE(table_info
);
419 uu_avl_destroy(rsrc_fmri_avl
);
420 uu_avl_pool_destroy(rsrc_fmri_avl_pool
);
423 if ((rsrc_index_avl
= uu_avl_create(rsrc_index_avl_pool
, NULL
,
424 UU_AVL_DEBUG
)) == NULL
) {
425 (void) snmp_log(LOG_ERR
, MODNAME_STR
": rsrc_index avl "
426 "creation failed: %s\n", uu_strerror(uu_error()));
427 snmp_free_varbind(table_info
->indexes
);
428 SNMP_FREE(table_info
);
430 uu_avl_destroy(rsrc_fmri_avl
);
431 uu_avl_pool_destroy(rsrc_fmri_avl_pool
);
432 uu_avl_pool_destroy(rsrc_index_avl_pool
);
433 return (MIB_REGISTRATION_FAILED
);
436 if ((err
= netsnmp_register_table(handler
, table_info
)) !=
438 snmp_free_varbind(table_info
->indexes
);
439 SNMP_FREE(table_info
);
441 uu_avl_destroy(rsrc_fmri_avl
);
442 uu_avl_pool_destroy(rsrc_fmri_avl_pool
);
443 uu_avl_destroy(rsrc_index_avl
);
444 uu_avl_pool_destroy(rsrc_index_avl_pool
);
448 if ((err
= netsnmp_register_read_only_instance(
449 netsnmp_create_handler_registration("sunFmResourceCount",
450 sunFmResourceCount_handler
, sunFmResourceCount_oid
,
451 OID_LENGTH(sunFmResourceCount_oid
), HANDLER_CAN_RONLY
))) !=
454 * There's no way to unregister the table handler, so we
455 * can't free any of the data, either.
460 return (MIB_REGISTERED_OK
);
464 * These two functions form the core of GET/GETNEXT/GETBULK handling (the
465 * only kind we do). They perform two functions:
467 * - First, frob the request to set all the index variables to correspond
468 * to the value that's going to be returned. For GET, this is a nop;
469 * for GETNEXT/GETBULK it always requires some work.
470 * - Second, find and return the fmd resource information corresponding to
471 * the (possibly updated) indices.
473 * These should be as fast as possible; they run in the agent thread.
475 static sunFmResource_data_t
*
476 sunFmResourceTable_nextrsrc(netsnmp_handler_registration
*reginfo
,
477 netsnmp_table_request_info
*table_info
)
479 sunFmResource_data_t
*data
;
480 netsnmp_variable_list
*var
;
484 * If we have no index, we must make one.
486 if (table_info
->number_indexes
< 1) {
487 oid tmpoid
[MAX_OID_LEN
];
490 DEBUGMSGTL((MODNAME_STR
, "nextrsrc: no indexes given\n"));
491 var
= SNMP_MALLOC_TYPEDEF(netsnmp_variable_list
);
492 (void) snmp_set_var_typed_value(var
, ASN_UNSIGNED
,
493 (uchar_t
*)&index
, sizeof (index
));
494 (void) memcpy(tmpoid
, reginfo
->rootoid
,
495 reginfo
->rootoid_len
* sizeof (oid
));
496 tmpoid
[reginfo
->rootoid_len
] = 1;
497 tmpoid
[reginfo
->rootoid_len
+ 1] = table_info
->colnum
;
498 if (build_oid(&var
->name
, &var
->name_length
, tmpoid
,
499 reginfo
->rootoid_len
+ 2, var
) != SNMPERR_SUCCESS
) {
500 snmp_free_varbind(var
);
503 DEBUGMSGTL((MODNAME_STR
, "nextrsrc: built fake index:\n"));
504 DEBUGMSGVAR((MODNAME_STR
, var
));
505 DEBUGMSG((MODNAME_STR
, "\n"));
507 var
= snmp_clone_varbind(table_info
->indexes
);
508 index
= *var
->val
.integer
;
509 DEBUGMSGTL((MODNAME_STR
, "nextrsrc: received index:\n"));
510 DEBUGMSGVAR((MODNAME_STR
, var
));
511 DEBUGMSG((MODNAME_STR
, "\n"));
515 snmp_free_varbind(table_info
->indexes
);
516 table_info
->indexes
= NULL
;
517 table_info
->number_indexes
= 0;
519 if ((data
= resource_lookup_index_nextvalid(index
)) == NULL
) {
520 DEBUGMSGTL((MODNAME_STR
, "nextrsrc: exact match not found for "
521 "index %lu; trying next column\n", index
));
522 if (table_info
->colnum
>=
523 netsnmp_find_table_registration_info(reginfo
)->max_column
) {
524 snmp_free_varbind(var
);
525 DEBUGMSGTL((MODNAME_STR
, "nextrsrc: out of columns\n"));
528 table_info
->colnum
++;
531 data
= resource_lookup_index_nextvalid(index
);
535 DEBUGMSGTL((MODNAME_STR
, "nextrsrc: exact match not found for "
536 "index %lu; stopping\n", index
));
537 snmp_free_varbind(var
);
541 *var
->val
.integer
= data
->d_index
;
542 table_info
->indexes
= var
;
543 table_info
->number_indexes
= 1;
545 DEBUGMSGTL((MODNAME_STR
, "matching data is %lu/%s@%p\n", data
->d_index
,
546 data
->d_ari_fmri
, data
));
552 static sunFmResource_data_t
*
553 sunFmResourceTable_rsrc(netsnmp_handler_registration
*reginfo
,
554 netsnmp_table_request_info
*table_info
)
556 ASSERT(table_info
->number_indexes
== 1);
558 return (resource_lookup_index_exact(table_info
->index_oid
[0]));
563 sunFmResourceTable_return(unsigned int reg
, void *arg
)
565 netsnmp_delegated_cache
*cache
= (netsnmp_delegated_cache
*)arg
;
566 netsnmp_request_info
*request
;
567 netsnmp_agent_request_info
*reqinfo
;
568 netsnmp_handler_registration
*reginfo
;
569 netsnmp_table_request_info
*table_info
;
570 sunFmResource_data_t
*data
;
573 ASSERT(netsnmp_handler_check_cache(cache
) != NULL
);
575 (void) pthread_mutex_lock(&update_lock
);
576 if (update_status
!= US_QUIET
) {
579 tv
.tv_sec
= UPDATE_WAIT_MILLIS
/ 1000;
580 tv
.tv_usec
= (UPDATE_WAIT_MILLIS
% 1000) * 1000;
582 (void) snmp_alarm_register_hr(tv
, 0, sunFmResourceTable_return
,
584 (void) pthread_mutex_unlock(&update_lock
);
588 request
= cache
->requests
;
589 reqinfo
= cache
->reqinfo
;
590 reginfo
= cache
->reginfo
;
592 table_info
= netsnmp_extract_table_info(request
);
593 request
->delegated
= 0;
595 ASSERT(table_info
->colnum
>= SUNFMRESOURCE_COLMIN
);
596 ASSERT(table_info
->colnum
<= SUNFMRESOURCE_COLMAX
);
599 * table_info->colnum contains the column number requested.
600 * table_info->indexes contains a linked list of snmp variable
601 * bindings for the indexes of the table. Values in the list
602 * have been set corresponding to the indexes of the
603 * request. We have other guarantees as well:
605 * - The column number is always within range.
606 * - If we have no index data, table_info->index_oid_len is 0.
607 * - We will never receive requests outside our table nor
608 * those with the first subid anything other than 1 (Entry)
609 * nor those without a column number. This is true even
610 * for GETNEXT requests.
613 switch (reqinfo
->mode
) {
615 if ((data
= sunFmResourceTable_rsrc(reginfo
, table_info
)) ==
617 netsnmp_free_delegated_cache(cache
);
618 (void) pthread_mutex_unlock(&update_lock
);
624 if ((data
= sunFmResourceTable_nextrsrc(reginfo
, table_info
)) ==
626 netsnmp_free_delegated_cache(cache
);
627 (void) pthread_mutex_unlock(&update_lock
);
632 (void) snmp_log(LOG_ERR
, MODNAME_STR
": Unsupported request "
633 "mode %d\n", reqinfo
->mode
);
634 netsnmp_free_delegated_cache(cache
);
635 (void) pthread_mutex_unlock(&update_lock
);
639 switch (table_info
->colnum
) {
640 case SUNFMRESOURCE_COL_FMRI
:
641 (void) netsnmp_table_build_result(reginfo
, request
, table_info
,
642 ASN_OCTET_STR
, (uchar_t
*)data
->d_ari_fmri
,
643 strlen(data
->d_ari_fmri
));
645 case SUNFMRESOURCE_COL_STATUS
:
646 switch (data
->d_ari_flags
&
647 (FMD_ADM_RSRC_FAULTY
|FMD_ADM_RSRC_UNUSABLE
)) {
649 rsrcstate
= SUNFMRESOURCE_STATE_OK
;
651 case FMD_ADM_RSRC_FAULTY
:
652 rsrcstate
= SUNFMRESOURCE_STATE_DEGRADED
;
654 case FMD_ADM_RSRC_UNUSABLE
:
655 rsrcstate
= SUNFMRESOURCE_STATE_UNKNOWN
;
657 case FMD_ADM_RSRC_FAULTY
| FMD_ADM_RSRC_UNUSABLE
:
658 rsrcstate
= SUNFMRESOURCE_STATE_FAULTED
;
661 (void) netsnmp_table_build_result(reginfo
, request
, table_info
,
662 ASN_INTEGER
, (uchar_t
*)&rsrcstate
,
665 case SUNFMRESOURCE_COL_DIAGNOSISUUID
:
666 (void) netsnmp_table_build_result(reginfo
, request
, table_info
,
667 ASN_OCTET_STR
, (uchar_t
*)data
->d_ari_case
,
668 strlen(data
->d_ari_case
));
673 netsnmp_free_delegated_cache(cache
);
674 (void) pthread_mutex_unlock(&update_lock
);
678 sunFmResourceTable_handler(netsnmp_mib_handler
*handler
,
679 netsnmp_handler_registration
*reginfo
, netsnmp_agent_request_info
*reqinfo
,
680 netsnmp_request_info
*requests
)
682 netsnmp_request_info
*request
;
685 tv
.tv_sec
= UPDATE_WAIT_MILLIS
/ 1000;
686 tv
.tv_usec
= (UPDATE_WAIT_MILLIS
% 1000) * 1000;
690 for (request
= requests
; request
; request
= request
->next
) {
691 if (request
->processed
!= 0)
694 if (netsnmp_extract_table_info(request
) == NULL
)
697 request
->delegated
= 1;
698 (void) snmp_alarm_register_hr(tv
, 0, sunFmResourceTable_return
,
699 (void *) netsnmp_create_delegated_cache(handler
, reginfo
,
700 reqinfo
, request
, NULL
));
703 return (SNMP_ERR_NOERROR
);
708 sunFmResourceCount_return(unsigned int reg
, void *arg
)
710 netsnmp_delegated_cache
*cache
= (netsnmp_delegated_cache
*)arg
;
711 netsnmp_request_info
*request
;
712 netsnmp_agent_request_info
*reqinfo
;
713 ulong_t rsrc_count_long
;
715 ASSERT(netsnmp_handler_check_cache(cache
) != NULL
);
717 (void) pthread_mutex_lock(&update_lock
);
718 if (update_status
!= US_QUIET
) {
721 tv
.tv_sec
= UPDATE_WAIT_MILLIS
/ 1000;
722 tv
.tv_usec
= (UPDATE_WAIT_MILLIS
% 1000) * 1000;
724 (void) snmp_alarm_register_hr(tv
, 0, sunFmResourceCount_return
,
726 (void) pthread_mutex_unlock(&update_lock
);
730 request
= cache
->requests
;
731 reqinfo
= cache
->reqinfo
;
733 request
->delegated
= 0;
735 switch (reqinfo
->mode
) {
737 * According to the documentation, it's not possible for us ever to
738 * be called with MODE_GETNEXT. However, Net-SNMP does the following:
739 * - set reqinfo->mode to MODE_GET
740 * - invoke the handler
741 * - set reqinfo->mode to MODE_GETNEXT (even if the request was not
742 * actually processed; i.e. it's been delegated)
743 * Since we're called back later with the same reqinfo, we see
744 * GETNEXT. Therefore this case is needed to work around the
749 DEBUGMSGTL((MODNAME_STR
, "resource count is %u\n", rsrc_count
));
750 rsrc_count_long
= (ulong_t
)rsrc_count
;
751 (void) snmp_set_var_typed_value(request
->requestvb
, ASN_GAUGE
,
752 (uchar_t
*)&rsrc_count_long
, sizeof (rsrc_count_long
));
755 (void) snmp_log(LOG_ERR
, MODNAME_STR
": Unsupported request "
756 "mode %d\n", reqinfo
->mode
);
759 netsnmp_free_delegated_cache(cache
);
760 (void) pthread_mutex_unlock(&update_lock
);
764 sunFmResourceCount_handler(netsnmp_mib_handler
*handler
,
765 netsnmp_handler_registration
*reginfo
, netsnmp_agent_request_info
*reqinfo
,
766 netsnmp_request_info
*requests
)
770 tv
.tv_sec
= UPDATE_WAIT_MILLIS
/ 1000;
771 tv
.tv_usec
= (UPDATE_WAIT_MILLIS
% 1000) * 1000;
776 * We are never called for a GETNEXT when registered as an
777 * instance; it's handled for us and converted to a GET.
778 * Also, an instance handler is given only one request at a time, so
779 * we don't need to loop over a list of requests.
782 if (requests
->processed
!= 0)
783 return (SNMP_ERR_NOERROR
);
785 requests
->delegated
= 1;
786 (void) snmp_alarm_register_hr(tv
, 0, sunFmResourceCount_return
,
787 (void *) netsnmp_create_delegated_cache(handler
, reginfo
,
788 reqinfo
, requests
, NULL
));
790 return (SNMP_ERR_NOERROR
);