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