Print this page
    
5835 fix printf tokens for net-snmp 5.7.2
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/fm/libfmd_snmp/common/module.c
          +++ new/usr/src/lib/fm/libfmd_snmp/common/module.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   */
  26   26  
  27   27  #include <fm/fmd_adm.h>
  28   28  #include <fm/fmd_snmp.h>
  29   29  #include <net-snmp/net-snmp-config.h>
  30   30  #include <net-snmp/net-snmp-includes.h>
  31   31  #include <net-snmp/agent/net-snmp-agent-includes.h>
  32   32  #include <pthread.h>
  33   33  #include <stddef.h>
  34   34  #include <errno.h>
  35   35  #include <libuutil.h>
  36   36  #include "sunFM_impl.h"
  37   37  #include "module.h"
  38   38  
  39   39  static uu_avl_pool_t    *mod_name_avl_pool;
  40   40  static uu_avl_pool_t    *mod_index_avl_pool;
  41   41  static uu_avl_t         *mod_name_avl;
  42   42  static uu_avl_t         *mod_index_avl;
  43   43  
  44   44  #define VALID_AVL_STATE (mod_name_avl_pool != NULL &&           \
  45   45          mod_index_avl_pool != NULL && mod_name_avl != NULL &&   \
  46   46          mod_index_avl != NULL)
  47   47  
  48   48  #define UPDATE_WAIT_MILLIS      10      /* poll interval in milliseconds */
  49   49  
  50   50  /*
  51   51   * Update types.  Single-index and all are mutually exclusive.
  52   52   */
  53   53  #define UCT_INDEX       0x1
  54   54  #define UCT_ALL         0x2
  55   55  #define UCT_FLAGS       0x3
  56   56  
  57   57  #define MODULE_DATA_VALID(d)    ((d)->d_valid == valid_stamp)
  58   58  
  59   59  /*
  60   60   * Locking rules are straightforward.  There is only one updater thread
  61   61   * for each table, and requests for update that are received while
  62   62   * another update is in progress are ignored.  The single per-table lock
  63   63   * protects all the data for the table, the valid_stamp and max_index
  64   64   * tags for new data, and - importantly - all the hidden static data
  65   65   * used by the Net-SNMP library.  The result return callbacks are always
  66   66   * called in the master agent thread; holding the table lock is
  67   67   * therefore sufficient since only one table's callback can be run at
  68   68   * any one time.  Finer-grained locking is possible here but
  69   69   * substantially more difficult because nearly all Net-SNMP functions
  70   70   * are unsafe.
  71   71   *
  72   72   * In practice this is more than adequate, since the purpose of
  73   73   * threading out the update is to prevent excessively time-consuming
  74   74   * data collection from bottlenecking the entire agent, not to improve
  75   75   * result throughput (SNMP is not intended to be used for applications
  76   76   * requiring high throughput anyway).  If the agent itself ever becomes
  77   77   * multithreaded, locking requirements become limited to our local
  78   78   * per-table data (the tree, max_index, and valid_stamp), and the
  79   79   * implementation could be revisited for better performance.
  80   80   */
  81   81  
  82   82  static ulong_t          max_index;
  83   83  static int              valid_stamp;
  84   84  static pthread_mutex_t  update_lock;
  85   85  static pthread_cond_t   update_cv;
  86   86  static volatile enum { US_QUIET, US_NEEDED, US_INPROGRESS } update_status;
  87   87  
  88   88  static Netsnmp_Node_Handler     sunFmModuleTable_handler;
  89   89  
  90   90  static sunFmModule_data_t *
  91   91  key_build(const char *name, const ulong_t index)
  92   92  {
  93   93          static sunFmModule_data_t       key;
  94   94  
  95   95          key.d_index = index;
  96   96          if (name)
  97   97                  (void) strlcpy(key.d_ami_name, name, sizeof (key.d_ami_name));
  98   98          else
  99   99                  key.d_ami_name[0] = '\0';
 100  100  
 101  101          return (&key);
 102  102  }
 103  103  
 104  104  /*
 105  105   * If name is the name of a module we have previously seen and indexed, return
 106  106   * data for it.  Otherwise, return NULL.  Note that the module may not be
 107  107   * valid; that is, it may have been removed from the fault manager since its
 108  108   * information was last updated.
 109  109   */
 110  110  static sunFmModule_data_t *
 111  111  module_lookup_name(const char *name)
 112  112  {
 113  113          sunFmModule_data_t      *key;
 114  114  
 115  115          key = key_build(name, 0);
 116  116          return (uu_avl_find(mod_name_avl, key, NULL, NULL));
 117  117  }
 118  118  
 119  119  /*
 120  120   * If index corresponds to a module we have previously seen and indexed, return
 121  121   * data for it.  Otherwise, return NULL.  Note that the module may not be
 122  122   * valid; that is, it may have been removed from the fault manager since its
 123  123   * information was last updated.
 124  124   */
 125  125  static sunFmModule_data_t *
 126  126  module_lookup_index_exact(const ulong_t index)
 127  127  {
 128  128          sunFmModule_data_t      *key;
 129  129  
 130  130          key = key_build(NULL, index);
 131  131          return (uu_avl_find(mod_index_avl, key, NULL, NULL));
 132  132  }
 133  133  
 134  134  /*
 135  135   * If index corresponds to a valid (that is, extant as of latest information
 136  136   * from the fault manager) fmd module, return the data for that module.
 137  137   * Otherwise, return the data for the valid module whose index is as close as
 138  138   * possible to index but not lower.  This preserves the lexicographical
 139  139   * ordering required for GETNEXT processing.
 140  140   */
 141  141  static sunFmModule_data_t *
 142  142  module_lookup_index_nextvalid(const ulong_t index)
 143  143  {
 144  144          sunFmModule_data_t      *key, *data;
 145  145          uu_avl_index_t          idx;
 146  146  
 147  147          key = key_build(NULL, index);
 148  148  
 149  149          if ((data = uu_avl_find(mod_index_avl, key, NULL, &idx)) != NULL &&
 150  150              MODULE_DATA_VALID(data))
 151  151                  return (data);
 152  152  
 153  153          data = uu_avl_nearest_next(mod_index_avl, idx);
 154  154  
 155  155          while (data != NULL && !MODULE_DATA_VALID(data))
 156  156                  data = uu_avl_next(mod_index_avl, data);
 157  157  
 158  158          return (data);
 159  159  }
 160  160  
 161  161  /*
 162  162   * Possible update the contents of a single module within the cache.  This
 163  163   * is our callback from fmd_module_iter.
 164  164   */
 165  165  static int
 166  166  modinfo_update_one(const fmd_adm_modinfo_t *modinfo, void *arg)
 167  167  {
 168  168          const sunFmModule_update_ctx_t *update_ctx =
 169  169              (sunFmModule_update_ctx_t *)arg;
 170  170          sunFmModule_data_t *data = module_lookup_name(modinfo->ami_name);
 171  171  
 172  172          /*
 173  173           * An fmd module we haven't seen before.  We're obligated to index
 174  174           * it and link it into our cache so that we can find it, but we're
 175  175           * not obligated to fill it in completely unless we're doing a
 176  176           * thorough update or this is the module we were asked for.  This
 177  177           * avoids unnecessary iteration and memory manipulation for data
 178  178           * we're not going to return for this request.
 179  179           */
 180  180          if (data == NULL) {
 181  181                  uu_avl_index_t idx;
 182  182  
 183  183                  DEBUGMSGTL((MODNAME_STR, "found new fmd module %s\n",
 184  184                      modinfo->ami_name));
 185  185                  if ((data = SNMP_MALLOC_TYPEDEF(sunFmModule_data_t)) == NULL) {
 186  186                          (void) snmp_log(LOG_ERR, MODNAME_STR ": Out of memory "
 187  187                              "for new module data at %s:%d\n", __FILE__,
 188  188                              __LINE__);
 189  189                          return (1);
 190  190                  }
 191  191                  /*
 192  192                   * We allocate indices sequentially and never reuse them.
 193  193                   * This ensures we can always return valid GETNEXT responses
 194  194                   * without having to reindex, and it provides the user a
 195  195                   * more consistent view of the fault manager.
 196  196                   */
 197  197                  data->d_index = ++max_index;
 198  198                  DEBUGMSGTL((MODNAME_STR, "index %lu is %s@%p\n", data->d_index,
 199  199                      modinfo->ami_name, data));
 200  200  
 201  201                  (void) strlcpy(data->d_ami_name, modinfo->ami_name,
 202  202                      sizeof (data->d_ami_name));
 203  203  
 204  204                  uu_avl_node_init(data, &data->d_name_avl, mod_name_avl_pool);
 205  205                  (void) uu_avl_find(mod_name_avl, data, NULL, &idx);
 206  206                  uu_avl_insert(mod_name_avl, data, idx);
 207  207  
  
    | 
      ↓ open down ↓ | 
    207 lines elided | 
    
      ↑ open up ↑ | 
  
 208  208                  uu_avl_node_init(data, &data->d_index_avl, mod_index_avl_pool);
 209  209                  (void) uu_avl_find(mod_index_avl, data, NULL, &idx);
 210  210                  uu_avl_insert(mod_index_avl, data, idx);
 211  211  
 212  212                  DEBUGMSGTL((MODNAME_STR, "completed new module %lu/%s@%p\n",
 213  213                      data->d_index, data->d_ami_name, data));
 214  214          }
 215  215  
 216  216          data->d_valid = valid_stamp;
 217  217  
 218      -        DEBUGMSGTL((MODNAME_STR, "timestamp updated for %lu/%s@%p: %lu\n",
      218 +        DEBUGMSGTL((MODNAME_STR, "timestamp updated for %lu/%s@%p: %d\n",
 219  219              data->d_index, data->d_ami_name, data, data->d_valid));
 220  220  
 221  221          if ((update_ctx->uc_type & UCT_ALL) ||
 222  222              update_ctx->uc_index == data->d_index) {
 223  223                  (void) strlcpy(data->d_ami_vers, modinfo->ami_vers,
 224  224                      sizeof (data->d_ami_vers));
 225  225                  (void) strlcpy(data->d_ami_desc, modinfo->ami_desc,
 226  226                      sizeof (data->d_ami_desc));
 227  227                  data->d_ami_flags = modinfo->ami_flags;
 228  228          }
 229  229  
 230  230          return (!(update_ctx->uc_type & UCT_ALL) &&
 231  231              update_ctx->uc_index == data->d_index);
 232  232  }
 233  233  
 234  234  /*
 235  235   * Update some or all module data from fmd.  If thorough is set, all modules
 236  236   * will be indexed and their data cached.  Otherwise, updates will stop once
 237  237   * the module matching index has been updated.
 238  238   *
 239  239   * Returns appropriate SNMP error codes.
 240  240   */
 241  241  static int
 242  242  modinfo_update(sunFmModule_update_ctx_t *update_ctx)
 243  243  {
 244  244          fmd_adm_t *adm;
 245  245  
 246  246          ASSERT(update_ctx != NULL);
 247  247          ASSERT((update_ctx->uc_type & (UCT_INDEX|UCT_ALL)) !=
 248  248              (UCT_INDEX|UCT_ALL));
 249  249          ASSERT((update_ctx->uc_type & ~UCT_FLAGS) == 0);
 250  250          ASSERT(VALID_AVL_STATE);
 251  251  
 252  252          if ((adm = fmd_adm_open(update_ctx->uc_host, update_ctx->uc_prog,
 253  253              update_ctx->uc_version)) == NULL) {
 254  254                  (void) snmp_log(LOG_ERR, MODNAME_STR ": Communication with fmd "
 255  255                      "failed: %s\n", strerror(errno));
 256  256                  return (SNMP_ERR_RESOURCEUNAVAILABLE);
 257  257          }
 258  258  
 259  259          ++valid_stamp;
 260  260          if (fmd_adm_module_iter(adm, modinfo_update_one, update_ctx) != 0) {
 261  261                  (void) snmp_log(LOG_ERR, MODNAME_STR ": fmd module information "
 262  262                      "update failed: %s\n", fmd_adm_errmsg(adm));
 263  263                  fmd_adm_close(adm);
 264  264                  return (SNMP_ERR_RESOURCEUNAVAILABLE);
 265  265          }
 266  266  
 267  267          DEBUGMSGTL((MODNAME_STR, "module iteration completed\n"));
 268  268  
 269  269          fmd_adm_close(adm);
 270  270          return (SNMP_ERR_NOERROR);
 271  271  }
 272  272  
 273  273  /*ARGSUSED*/
 274  274  static void
 275  275  update_thread(void *arg)
 276  276  {
 277  277          /*
 278  278           * The current modinfo_update implementation offers minimal savings
 279  279           * for the use of index-only updates; therefore we always do a full
 280  280           * update.  If it becomes advantageous to limit updates to a single
 281  281           * index, the contexts can be queued by the handler instead.
 282  282           */
 283  283          sunFmModule_update_ctx_t        uc;
 284  284  
 285  285          uc.uc_host = NULL;
 286  286          uc.uc_prog = FMD_ADM_PROGRAM;
 287  287          uc.uc_version = FMD_ADM_VERSION;
 288  288  
 289  289          uc.uc_index = 0;
 290  290          uc.uc_type = UCT_ALL;
 291  291  
 292  292          for (;;) {
 293  293                  (void) pthread_mutex_lock(&update_lock);
 294  294                  update_status = US_QUIET;
 295  295                  while (update_status == US_QUIET)
 296  296                          (void) pthread_cond_wait(&update_cv, &update_lock);
 297  297                  update_status = US_INPROGRESS;
 298  298                  (void) pthread_mutex_unlock(&update_lock);
 299  299                  (void) modinfo_update(&uc);
 300  300          }
 301  301  }
 302  302  
 303  303  static void
 304  304  request_update(void)
 305  305  {
 306  306          (void) pthread_mutex_lock(&update_lock);
 307  307          if (update_status != US_QUIET) {
 308  308                  (void) pthread_mutex_unlock(&update_lock);
 309  309                  return;
 310  310          }
 311  311          update_status = US_NEEDED;
 312  312          (void) pthread_cond_signal(&update_cv);
 313  313          (void) pthread_mutex_unlock(&update_lock);
 314  314  }
 315  315  
 316  316  /*ARGSUSED*/
 317  317  static int
 318  318  module_compare_name(const void *l, const void *r, void *private)
 319  319  {
 320  320          sunFmModule_data_t      *l_data = (sunFmModule_data_t *)l;
 321  321          sunFmModule_data_t      *r_data = (sunFmModule_data_t *)r;
 322  322  
 323  323          ASSERT(l_data != NULL && r_data != NULL);
 324  324  
 325  325          return (strcmp(l_data->d_ami_name, r_data->d_ami_name));
 326  326  }
 327  327  
 328  328  /*ARGSUSED*/
 329  329  static int
 330  330  module_compare_index(const void *l, const void *r, void *private)
 331  331  {
 332  332          sunFmModule_data_t      *l_data = (sunFmModule_data_t *)l;
 333  333          sunFmModule_data_t      *r_data = (sunFmModule_data_t *)r;
 334  334  
 335  335          ASSERT(l_data != NULL && r_data != NULL);
 336  336  
 337  337          return (l_data->d_index < r_data->d_index ? -1 :
 338  338              l_data->d_index > r_data->d_index ? 1 : 0);
 339  339  }
 340  340  
 341  341  int
 342  342  sunFmModuleTable_init(void)
 343  343  {
 344  344          static oid sunFmModuleTable_oid[] = { SUNFMMODULETABLE_OID };
 345  345          netsnmp_table_registration_info *table_info;
 346  346          netsnmp_handler_registration *handler;
 347  347          int err;
 348  348  
 349  349          if ((err = pthread_mutex_init(&update_lock, NULL)) != 0) {
 350  350                  (void) snmp_log(LOG_ERR, MODNAME_STR ": mutex_init failure: "
 351  351                      "%s\n", strerror(err));
 352  352                  return (MIB_REGISTRATION_FAILED);
 353  353          }
 354  354          if ((err = pthread_cond_init(&update_cv, NULL)) != 0) {
 355  355                  (void) snmp_log(LOG_ERR, MODNAME_STR ": cond_init failure: "
 356  356                      "%s\n", strerror(err));
 357  357                  return (MIB_REGISTRATION_FAILED);
 358  358          }
 359  359  
 360  360          if ((err = pthread_create(NULL, NULL, (void *(*)(void *))update_thread,
 361  361              NULL)) != 0) {
 362  362                  (void) snmp_log(LOG_ERR, MODNAME_STR ": error creating update "
 363  363                      "thread: %s\n", strerror(err));
 364  364                  return (MIB_REGISTRATION_FAILED);
 365  365          }
 366  366  
 367  367          if ((table_info =
 368  368              SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL)
 369  369                  return (MIB_REGISTRATION_FAILED);
 370  370  
 371  371          if ((handler = netsnmp_create_handler_registration("sunFmModuleTable",
 372  372              sunFmModuleTable_handler, sunFmModuleTable_oid,
 373  373              OID_LENGTH(sunFmModuleTable_oid), HANDLER_CAN_RONLY)) == NULL) {
 374  374                  SNMP_FREE(table_info);
 375  375                  return (MIB_REGISTRATION_FAILED);
 376  376          }
 377  377  
 378  378          /*
 379  379           * The Net-SNMP template uses add_indexes here, but that
 380  380           * function is unsafe because it does not check for failure.
 381  381           */
 382  382          if (netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED) == NULL) {
 383  383                  SNMP_FREE(table_info);
 384  384                  SNMP_FREE(handler);
 385  385                  return (MIB_REGISTRATION_FAILED);
 386  386          }
 387  387  
 388  388          table_info->min_column = SUNFMMODULE_COLMIN;
 389  389          table_info->max_column = SUNFMMODULE_COLMAX;
 390  390  
 391  391          if ((mod_name_avl_pool = uu_avl_pool_create("mod_name",
 392  392              sizeof (sunFmModule_data_t),
 393  393              offsetof(sunFmModule_data_t, d_name_avl), module_compare_name,
 394  394              UU_AVL_DEBUG)) == NULL) {
 395  395                  snmp_free_varbind(table_info->indexes);
 396  396                  SNMP_FREE(table_info);
 397  397                  SNMP_FREE(handler);
 398  398          }
 399  399  
 400  400          if ((mod_name_avl = uu_avl_create(mod_name_avl_pool, NULL,
 401  401              UU_AVL_DEBUG)) == NULL) {
 402  402                  (void) snmp_log(LOG_ERR, MODNAME_STR ": mod_name_avl creation "
 403  403                      "failed: %s\n", uu_strerror(uu_error()));
 404  404                  snmp_free_varbind(table_info->indexes);
 405  405                  SNMP_FREE(table_info);
 406  406                  SNMP_FREE(handler);
 407  407                  uu_avl_pool_destroy(mod_name_avl_pool);
 408  408                  return (MIB_REGISTRATION_FAILED);
 409  409          }
 410  410  
 411  411          if ((mod_index_avl_pool = uu_avl_pool_create("mod_index",
 412  412              sizeof (sunFmModule_data_t),
 413  413              offsetof(sunFmModule_data_t, d_index_avl),
 414  414              module_compare_index, UU_AVL_DEBUG)) == NULL) {
 415  415                  snmp_free_varbind(table_info->indexes);
 416  416                  SNMP_FREE(table_info);
 417  417                  SNMP_FREE(handler);
 418  418                  uu_avl_destroy(mod_name_avl);
 419  419                  uu_avl_pool_destroy(mod_name_avl_pool);
 420  420          }
 421  421  
 422  422          if ((mod_index_avl = uu_avl_create(mod_index_avl_pool, NULL,
 423  423              UU_AVL_DEBUG)) == NULL) {
 424  424                  (void) snmp_log(LOG_ERR, MODNAME_STR ": mod_index_avl creation "
 425  425                      "failed: %s\n", uu_strerror(uu_error()));
 426  426                  snmp_free_varbind(table_info->indexes);
 427  427                  SNMP_FREE(table_info);
 428  428                  SNMP_FREE(handler);
 429  429                  uu_avl_destroy(mod_name_avl);
 430  430                  uu_avl_pool_destroy(mod_name_avl_pool);
 431  431                  uu_avl_pool_destroy(mod_index_avl_pool);
 432  432                  return (MIB_REGISTRATION_FAILED);
 433  433          }
 434  434  
 435  435          if ((err = netsnmp_register_table(handler, table_info)) !=
 436  436              MIB_REGISTERED_OK) {
 437  437                  snmp_free_varbind(table_info->indexes);
 438  438                  SNMP_FREE(table_info);
 439  439                  SNMP_FREE(handler);
 440  440                  uu_avl_destroy(mod_name_avl);
 441  441                  uu_avl_pool_destroy(mod_name_avl_pool);
 442  442                  uu_avl_destroy(mod_index_avl);
 443  443                  uu_avl_pool_destroy(mod_index_avl_pool);
 444  444                  return (err);
 445  445          }
 446  446  
 447  447          return (MIB_REGISTERED_OK);
 448  448  }
 449  449  
 450  450  /*
 451  451   * These two functions form the core of GET/GETNEXT/GETBULK handling (the
 452  452   * only kind we do).  They perform two functions:
 453  453   *
 454  454   * - First, frob the request to set all the index variables to correspond
 455  455   *   to the value that's going to be returned.  For GET, this is a nop;
 456  456   *   for GETNEXT/GETBULK it always requires some work.
 457  457   * - Second, find and return the fmd module information corresponding to
 458  458   *   the (possibly updated) indices.
 459  459   *
 460  460   * These should be as fast as possible; they run in the agent thread.
 461  461   */
 462  462  static sunFmModule_data_t *
 463  463  sunFmModuleTable_nextmod(netsnmp_handler_registration *reginfo,
 464  464      netsnmp_table_request_info *table_info)
 465  465  {
 466  466          sunFmModule_data_t      *data;
 467  467          netsnmp_variable_list   *var;
 468  468          ulong_t index;
 469  469  
 470  470          /*
 471  471           * If we have no index, we must make one.
 472  472           */
 473  473          if (table_info->number_indexes < 1) {
 474  474                  oid tmpoid[MAX_OID_LEN];
 475  475                  index = 1;
 476  476  
 477  477                  DEBUGMSGTL((MODNAME_STR, "nextmod: no indexes given\n"));
 478  478                  var = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
 479  479                  (void) snmp_set_var_typed_value(var, ASN_UNSIGNED,
 480  480                      (uchar_t *)&index, sizeof (index));
 481  481                  (void) memcpy(tmpoid, reginfo->rootoid,
 482  482                      reginfo->rootoid_len * sizeof (oid));
 483  483                  tmpoid[reginfo->rootoid_len] = 1;       /* Entry is .1 */
 484  484                  tmpoid[reginfo->rootoid_len + 1] = table_info->colnum;
 485  485                  if (build_oid(&var->name, &var->name_length, tmpoid,
 486  486                      reginfo->rootoid_len + 2, var) != SNMPERR_SUCCESS) {
 487  487                          snmp_free_varbind(var);
 488  488                          return (NULL);
 489  489                  }
 490  490                  DEBUGMSGTL((MODNAME_STR, "nextmod: built fake index:\n"));
 491  491                  DEBUGMSGVAR((MODNAME_STR, var));
 492  492                  DEBUGMSG((MODNAME_STR, "\n"));
 493  493          } else {
 494  494                  var = snmp_clone_varbind(table_info->indexes);
 495  495                  index = *var->val.integer;
 496  496                  DEBUGMSGTL((MODNAME_STR, "nextmod: received index:\n"));
 497  497                  DEBUGMSGVAR((MODNAME_STR, var));
 498  498                  DEBUGMSG((MODNAME_STR, "\n"));
 499  499                  index++;
 500  500          }
 501  501  
 502  502          snmp_free_varbind(table_info->indexes);
 503  503          table_info->indexes = NULL;
 504  504          table_info->number_indexes = 0;
 505  505  
 506  506          if ((data = module_lookup_index_nextvalid(index)) == NULL) {
 507  507                  DEBUGMSGTL((MODNAME_STR, "nextmod: exact match not found for "
 508  508                      "index %lu; trying next column\n", index));
 509  509                  if (table_info->colnum >=
 510  510                      netsnmp_find_table_registration_info(reginfo)->max_column) {
 511  511                          snmp_free_varbind(var);
 512  512                          DEBUGMSGTL((MODNAME_STR, "nextmod: out of columns\n"));
 513  513                          return (NULL);
 514  514                  }
 515  515                  table_info->colnum++;
 516  516                  index = 1;
 517  517  
 518  518                  data = module_lookup_index_nextvalid(index);
 519  519          }
 520  520  
 521  521          if (data == NULL) {
 522  522                  DEBUGMSGTL((MODNAME_STR, "nextmod: exact match not found for "
 523  523                      "index %lu; stopping\n", index));
 524  524                  snmp_free_varbind(var);
 525  525                  return (NULL);
 526  526          }
 527  527  
 528  528          *var->val.integer = data->d_index;
 529  529          table_info->indexes = var;
 530  530          table_info->number_indexes = 1;
 531  531  
 532  532          DEBUGMSGTL((MODNAME_STR, "matching data is %lu/%s@%p\n", data->d_index,
 533  533              data->d_ami_name, data));
 534  534  
 535  535          return (data);
 536  536  }
 537  537  
 538  538  /*ARGSUSED*/
 539  539  static sunFmModule_data_t *
 540  540  sunFmModuleTable_mod(netsnmp_handler_registration *reginfo,
 541  541      netsnmp_table_request_info *table_info)
 542  542  {
 543  543          ASSERT(table_info->number_indexes == 1);
 544  544  
 545  545          return (module_lookup_index_exact(table_info->index_oid[0]));
 546  546  }
 547  547  
 548  548  /*ARGSUSED*/
 549  549  static void
 550  550  sunFmModuleTable_return(unsigned int reg, void *arg)
 551  551  {
 552  552          netsnmp_delegated_cache         *cache = (netsnmp_delegated_cache *)arg;
 553  553          netsnmp_request_info            *request;
 554  554          netsnmp_agent_request_info      *reqinfo;
 555  555          netsnmp_handler_registration    *reginfo;
 556  556          netsnmp_table_request_info      *table_info;
 557  557          sunFmModule_data_t              *data;
 558  558          ulong_t                         modstate;
 559  559  
 560  560          ASSERT(netsnmp_handler_check_cache(cache) != NULL);
 561  561  
 562  562          (void) pthread_mutex_lock(&update_lock);
 563  563          if (update_status != US_QUIET) {
 564  564                  struct timeval                  tv;
 565  565  
 566  566                  tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
 567  567                  tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
 568  568  
 569  569                  (void) snmp_alarm_register_hr(tv, 0, sunFmModuleTable_return,
 570  570                      cache);
 571  571                  (void) pthread_mutex_unlock(&update_lock);
 572  572                  return;
 573  573          }
 574  574  
 575  575          request = cache->requests;
 576  576          reqinfo = cache->reqinfo;
 577  577          reginfo = cache->reginfo;
 578  578  
 579  579          table_info = netsnmp_extract_table_info(request);
 580  580          request->delegated = 0;
 581  581  
 582  582          ASSERT(table_info->colnum >= SUNFMMODULE_COLMIN);
 583  583          ASSERT(table_info->colnum <= SUNFMMODULE_COLMAX);
 584  584  
 585  585          /*
 586  586           * table_info->colnum contains the column number requested.
 587  587           * table_info->indexes contains a linked list of snmp variable
 588  588           * bindings for the indexes of the table.  Values in the list
 589  589           * have been set corresponding to the indexes of the
 590  590           * request.  We have other guarantees as well:
 591  591           *
 592  592           * - The column number is always within range.
 593  593           * - If we have no index data, table_info->index_oid_len is 0.
 594  594           * - We will never receive requests outside our table nor
 595  595           *   those with the first subid anything other than 1 (Entry)
 596  596           *   nor those without a column number.  This is true even
 597  597           *   for GETNEXT requests.
 598  598           */
 599  599  
 600  600          switch (reqinfo->mode) {
 601  601          case MODE_GET:
 602  602                  if ((data = sunFmModuleTable_mod(reginfo, table_info)) ==
 603  603                      NULL) {
 604  604                          netsnmp_free_delegated_cache(cache);
 605  605                          (void) pthread_mutex_unlock(&update_lock);
 606  606                          return;
 607  607                  }
 608  608                  break;
 609  609          case MODE_GETNEXT:
 610  610          case MODE_GETBULK:
 611  611                  if ((data = sunFmModuleTable_nextmod(reginfo, table_info)) ==
 612  612                      NULL) {
 613  613                          netsnmp_free_delegated_cache(cache);
 614  614                          (void) pthread_mutex_unlock(&update_lock);
 615  615                          return;
 616  616                  }
 617  617                  break;
 618  618          default:
 619  619                  (void) snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request "
 620  620                      "mode %d\n", reqinfo->mode);
 621  621                  netsnmp_free_delegated_cache(cache);
 622  622                  (void) pthread_mutex_unlock(&update_lock);
 623  623                  return;
 624  624          }
 625  625  
 626  626          switch (table_info->colnum) {
 627  627          case SUNFMMODULE_COL_NAME:
 628  628                  (void) netsnmp_table_build_result(reginfo, request, table_info,
 629  629                      ASN_OCTET_STR, (uchar_t *)data->d_ami_name,
 630  630                      strlen(data->d_ami_name));
 631  631                  break;
 632  632          case SUNFMMODULE_COL_VERSION:
 633  633                  (void) netsnmp_table_build_result(reginfo, request, table_info,
 634  634                      ASN_OCTET_STR, (uchar_t *)data->d_ami_vers,
 635  635                      strlen(data->d_ami_vers));
 636  636                  break;
 637  637          case SUNFMMODULE_COL_STATUS:
 638  638                  modstate = (data->d_ami_flags & FMD_ADM_MOD_FAILED) ?
 639  639                      SUNFMMODULE_STATE_FAILED : SUNFMMODULE_STATE_ACTIVE;
 640  640                  (void) netsnmp_table_build_result(reginfo, request, table_info,
 641  641                      ASN_INTEGER, (uchar_t *)&modstate,
 642  642                      sizeof (modstate));
 643  643                  break;
 644  644          case SUNFMMODULE_COL_DESCRIPTION:
 645  645                  (void) netsnmp_table_build_result(reginfo, request, table_info,
 646  646                      ASN_OCTET_STR, (uchar_t *)data->d_ami_desc,
 647  647                      strlen(data->d_ami_desc));
 648  648                  break;
 649  649          default:
 650  650                  break;
 651  651          }
 652  652          netsnmp_free_delegated_cache(cache);
 653  653          (void) pthread_mutex_unlock(&update_lock);
 654  654  }
 655  655  
 656  656  static int
 657  657  sunFmModuleTable_handler(netsnmp_mib_handler *handler,
 658  658      netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo,
 659  659      netsnmp_request_info *requests)
 660  660  {
 661  661          netsnmp_request_info            *request;
 662  662          struct timeval                  tv;
 663  663  
 664  664          tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
 665  665          tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
 666  666  
 667  667          request_update();
 668  668  
 669  669          for (request = requests; request; request = request->next) {
 670  670                  if (request->processed != 0)
 671  671                          continue;
 672  672  
 673  673                  if (netsnmp_extract_table_info(request) == NULL)
 674  674                          continue;
 675  675  
 676  676                  request->delegated = 1;
 677  677                  (void) snmp_alarm_register_hr(tv, 0, sunFmModuleTable_return,
 678  678                      (void *) netsnmp_create_delegated_cache(handler, reginfo,
 679  679                      reqinfo, request, NULL));
 680  680          }
 681  681  
 682  682          return (SNMP_ERR_NOERROR);
 683  683  }
  
    | 
      ↓ open down ↓ | 
    455 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX