Auto-Merge pull request #2826 from rpv-tomsk/collectd-master
authorcollectd bot <32910397+collectd-bot@users.noreply.github.com>
Tue, 19 Jun 2018 11:57:21 +0000 (13:57 +0200)
committerGitHub <noreply@github.com>
Tue, 19 Jun 2018 11:57:21 +0000 (13:57 +0200)
Automatically merged due to "Automerge" label

Makefile.am
src/collectd-snmp.pod
src/collectd.conf.in
src/snmp.c
src/snmp_agent.c
src/snmp_agent_test.c

index 83b76a0..190ce8e 100644 (file)
@@ -1558,7 +1558,7 @@ pkglib_LTLIBRARIES += snmp.la
 snmp_la_SOURCES = src/snmp.c
 snmp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBNETSNMP_CPPFLAGS)
 snmp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBNETSNMP_LDFLAGS)
-snmp_la_LIBADD = $(BUILD_WITH_LIBNETSNMP_LIBS)
+snmp_la_LIBADD = libignorelist.la $(BUILD_WITH_LIBNETSNMP_LIBS)
 endif
 
 if BUILD_PLUGIN_SNMP_AGENT
index 1415cb1..9d508d1 100644 (file)
@@ -26,6 +26,8 @@ collectd-snmp - Documentation of collectd's C<snmp plugin>
       Table true
       Type "if_octets"
       TypeInstanceOID "IF-MIB::ifDescr"
+      #FilterOID "IF-MIB::ifOperStatus"
+      #FilterValues "1", "2"
       Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
     </Data>
 
@@ -113,8 +115,9 @@ queried using the C<GET> SNMP command (see L<snmpget(1)>) and transmitted to
 collectd. B<One> value list is dispatched and, eventually, one file will be
 written.
 
-When B<Table> is set to B<true>, the OIDs given to B<Values> (see below) are
-queried using the C<GETNEXT> SNMP command until the subtree is left. After all
+When B<Table> is set to B<true>, the OIDs given to B<Values>, B<TypeInstanceOID>,
+B<PluginInstanceOID>, B<HostOID> and B<FilterOID> (see below) are queried using
+the C<GETNEXT> SNMP command until the subtree is left. After all
 the lists (think: all columns of the table) have been read B<several> values
 sets will be dispatches and, eventually, several files will be written. If you
 configure a B<Type> (see above) which needs more than one data source (for
@@ -167,23 +170,42 @@ Defaults to an empty string.
 
 =item B<PluginInstanceOID> I<OID>
 
+=item B<HostOID> I<OID>
+
 If B<Table> is set to I<true>, I<OID> is interpreted as an SNMP-prefix that will
-return a list of values. Those values are then used as the actual type-instance
-or plugin-instance of dispatched metrics. An example would be the
+return a list of values. Those values are then used as the actual type-instance,
+plugin-instance or host of dispatched metrics. An example would be the
 C<IF-MIB::ifDescr> subtree. L<variables(5)> from the SNMP distribution describes
-the format of OIDs. When set to empty string, then "SUBID" will be used as the
-instance.
+the format of OIDs. When option is set to empty string, then "SUBID" will be used
+as the value.
 
-Prefix may be set for values with use of B<InstancePrefix> option.
+Prefix may be set for values with use of appropriate B<TypeInstancePrefix>,
+B<PluginInstancePrefix> and B<HostPrefix> options.
 
 When B<Table> is set to I<false> these options has no effect.
-Only one of these options may be used in the same B<Data> block.
-
-Defaults:
 
+Defaults: When no one of these options is configured explicitly,
 B<TypeInstanceOID> defaults to an empty string.
 
-B<PluginInstanceOID> is not configured.
+=item B<TypeInstancePrefix>
+
+=item B<PluginInstancePrefix>
+
+=item B<HostPrefix>
+
+These options are intented to be used together with B<TypeInstanceOID>,
+B<PluginInstanceOID> and B<HostOID> respectively.
+
+If set, I<String> is preprended to values received by querying the agent.
+
+When B<Table> is set to I<false> these options has no effect.
+
+The C<UPS-MIB> is an example where you need this setting: It has voltages of
+the inlets, outlets and the battery of an UPS. However, it doesn't provide a
+descriptive column for these voltages. In this case having 1, 2,E<nbsp>... as
+instances is not enough, because the inlet voltages and outlet voltages may
+both have the subids 1, 2,E<nbsp>... You can use this setting to distinguish
+between the different voltages.
 
 =item B<Instance> I<Instance>
 
@@ -201,17 +223,8 @@ Note what B<Table> option must be set before setting B<Instance>.
 
 =item B<InstancePrefix> I<String>
 
-If B<Table> is set to I<true>, you may feel the need to add something to the
-instance of the files. If set, I<String> is prepended to the instance as
-determined by querying the agent. When B<Table> is set to I<false> this option
-has no effect.
-
-The C<UPS-MIB> is an example where you need this setting: It has voltages of
-the inlets, outlets and the battery of an UPS. However, it doesn't provide a
-descriptive column for these voltages. In this case having 1, 2,E<nbsp>... as
-instances is not enough, because the inlet voltages and outlet voltages may
-both have the subids 1, 2,E<nbsp>... You can use this setting to distinguish
-between the different voltages.
+Attention: this option exists for backwards compatibility only and will be
+removed in next major release. Please use B<TypeInstancePrefix> instead.
 
 =item B<Values> I<OID> [I<OID> ...]
 
@@ -249,16 +262,39 @@ This value is not applied to counter-values.
 
 =item B<Ignore> I<Value> [, I<Value> ...]
 
-The ignore values allows one to ignore Instances based on their name and the
-patterns specified by the various values you've entered. The match is a
+The ignore values allows one to ignore TypeInstances based on their name and
+the patterns specified by the various values you've entered. The match is a
 glob-type shell matching.
 
+When B<Table> is set to I<false> then this option has no effect.
+
 =item B<InvertMatch> I<true|false(default)>
 
 The invertmatch value should be use in combination of the Ignore option.
 It changes the behaviour of the Ignore option, from a blacklist behaviour
 when InvertMatch is set to false, to a whitelist when specified to true.
 
+=item B<FilterOID> I<OID>
+
+=item B<FilterValues> I<Value> [, I<Value> ...]
+
+=item B<FilterIgnoreSelected> I<true|false(default)>
+
+When B<Table> is set to I<true>, these options allow to configure filtering
+based on MIB values.
+
+The B<FilterOID> declares I<OID> to fill table column with values.
+The B<FilterValues> declares values list to do match. Whether table row will be
+collected or ignored depends on the B<FilterIgnoreSelected> setting.
+As with other plugins that use the daemon's ignorelist functionality, a string
+that starts and ends with a slash is interpreted as a regular expression.
+
+If no selection is configured at all, B<all> table rows are selected.
+
+When B<Table> is set to I<false> then these options has no effect.
+
+See B<Table> and F</"IGNORELISTS"> for details.
+
 =back
 
 =head2 The Host block
index ee89e94..74b6c88 100644 (file)
 #       Table true
 #       Type "if_octets"
 #       TypeInstanceOID "IF-MIB::ifDescr"
-#       #InstancePrefix "port"
+#       #TypeInstancePrefix "port"
 #       Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
+#       #FilterOID "IF-MIB::ifOperStatus"
+#       #FilterValues "1", "2"
 #   </Data>
 #   <Data "interface_traffic">
 #       Table true
index dde6079..6c018da 100644 (file)
@@ -29,6 +29,7 @@
 #include "common.h"
 #include "plugin.h"
 #include "utils_complain.h"
+#include "utils_ignorelist.h"
 
 #include <net-snmp/net-snmp-config.h>
 #include <net-snmp/net-snmp-includes.h>
@@ -46,8 +47,9 @@ typedef struct oid_s oid_t;
 
 struct instance_s {
   bool configured;
-  bool is_plugin;
   oid_t oid;
+  char *prefix;
+  char *value;
 };
 typedef struct instance_s instance_t;
 
@@ -55,11 +57,12 @@ struct data_definition_s {
   char *name; /* used to reference this from the `Collect' option */
   char *type; /* used to find the data_set */
   bool is_table;
-  instance_t instance;
+  instance_t type_instance;
+  instance_t plugin_instance;
+  instance_t host;
+  oid_t filter_oid;
+  ignorelist_t *ignorelist;
   char *plugin_name;
-  char *plugin_instance;
-  char *type_instance;
-  char *instance_prefix;
   oid_t *values;
   size_t values_len;
   double scale;
@@ -102,19 +105,28 @@ typedef struct host_definition_s host_definition_t;
 
 /* These two types are used to cache values in `csnmp_read_table' to handle
  * gaps in tables. */
-struct csnmp_list_instances_s {
+struct csnmp_cell_char_s {
   oid_t suffix;
-  char instance[DATA_MAX_NAME_LEN];
-  struct csnmp_list_instances_s *next;
+  char value[DATA_MAX_NAME_LEN];
+  struct csnmp_cell_char_s *next;
 };
-typedef struct csnmp_list_instances_s csnmp_list_instances_t;
+typedef struct csnmp_cell_char_s csnmp_cell_char_t;
 
-struct csnmp_table_values_s {
+struct csnmp_cell_value_s {
   oid_t suffix;
   value_t value;
-  struct csnmp_table_values_s *next;
+  struct csnmp_cell_value_s *next;
 };
-typedef struct csnmp_table_values_s csnmp_table_values_t;
+typedef struct csnmp_cell_value_s csnmp_cell_value_t;
+
+typedef enum {
+  OID_TYPE_SKIP = 0,
+  OID_TYPE_VARIABLE,
+  OID_TYPE_TYPEINSTANCE,
+  OID_TYPE_PLUGININSTANCE,
+  OID_TYPE_HOST,
+  OID_TYPE_FILTER,
+} csnmp_oid_type_t;
 
 /*
  * Private variables
@@ -203,6 +215,22 @@ static void csnmp_host_definition_destroy(void *arg) /* {{{ */
   sfree(hd);
 } /* }}} void csnmp_host_definition_destroy */
 
+static void csnmp_data_definition_destroy(data_definition_t *dd) {
+  sfree(dd->name);
+  sfree(dd->type);
+  sfree(dd->plugin_name);
+  sfree(dd->plugin_instance.prefix);
+  sfree(dd->plugin_instance.value);
+  sfree(dd->type_instance.prefix);
+  sfree(dd->type_instance.value);
+  sfree(dd->host.prefix);
+  sfree(dd->host.value);
+  sfree(dd->values);
+  sfree(dd->ignores);
+  ignorelist_free(dd->ignorelist);
+  sfree(dd);
+} /* void csnmp_data_definition_destroy */
+
 /* Many functions to handle the configuration. {{{ */
 /* First there are many functions which do configuration stuff. It's a big
  * bloated and messy, I'm afraid. */
@@ -212,7 +240,7 @@ static void csnmp_host_definition_destroy(void *arg) /* {{{ */
  *  csnmp_config
  *  +-> call_snmp_init_once
  *  +-> csnmp_config_add_data
- *  !   +-> csnmp_config_add_data_instance
+ *  !   +-> csnmp_config_configure_data_instance
  *  !   +-> csnmp_config_add_data_values
  *  +-> csnmp_config_add_host
  *      +-> csnmp_config_add_host_version
@@ -229,38 +257,29 @@ static void call_snmp_init_once(void) {
   have_init = 1;
 } /* void call_snmp_init_once */
 
-static int csnmp_config_add_data_instance_oid(data_definition_t *dd,
-                                              oconfig_item_t *ci,
-                                              bool is_plugin) {
+static int csnmp_config_configure_data_instance(instance_t *instance,
+                                                oconfig_item_t *ci) {
   char buffer[DATA_MAX_NAME_LEN];
-  int status;
 
-  status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
+  int status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
   if (status != 0)
     return status;
 
-  if (dd->instance.configured) {
-    ERROR("snmp plugin: Only one of options `TypeInstanceOID', "
-          "`PluginInstanceOID' or `Instance' can be used in `Data' block.");
-    return -1;
-  }
-
-  dd->instance.is_plugin = is_plugin;
-  dd->instance.configured = true;
+  instance->configured = true;
 
   if (strlen(buffer) == 0) {
     return 0;
   }
 
-  dd->instance.oid.oid_len = MAX_OID_LEN;
+  instance->oid.oid_len = MAX_OID_LEN;
 
-  if (!read_objid(buffer, dd->instance.oid.oid, &dd->instance.oid.oid_len)) {
+  if (!read_objid(buffer, instance->oid.oid, &instance->oid.oid_len)) {
     ERROR("snmp plugin: read_objid (%s) failed.", buffer);
     return -1;
   }
 
   return 0;
-} /* int csnmp_config_add_data_instance_oid */
+} /* int csnmp_config_configure_data_instance */
 
 static int csnmp_config_add_data_values(data_definition_t *dd,
                                         oconfig_item_t *ci) {
@@ -297,7 +316,7 @@ static int csnmp_config_add_data_values(data_definition_t *dd,
   }
 
   return 0;
-} /* int csnmp_config_add_data_instance */
+} /* int csnmp_config_configure_data_instance */
 
 static int csnmp_config_add_data_blacklist(data_definition_t *dd,
                                            oconfig_item_t *ci) {
@@ -322,6 +341,41 @@ static int csnmp_config_add_data_blacklist(data_definition_t *dd,
   return 0;
 } /* int csnmp_config_add_data_blacklist */
 
+static int csnmp_config_add_data_filter_values(data_definition_t *data,
+                                               oconfig_item_t *ci) {
+  if (ci->values_num < 1) {
+    WARNING("snmp plugin: `FilterValues' needs at least one argument.");
+    return -1;
+  }
+
+  for (int i = 0; i < ci->values_num; i++) {
+    if (ci->values[i].type != OCONFIG_TYPE_STRING) {
+      WARNING("snmp plugin: All arguments to `FilterValues' must be strings.");
+      return -1;
+    }
+    ignorelist_add(data->ignorelist, ci->values[i].value.string);
+  }
+
+  return 0;
+} /* int csnmp_config_add_data_filter_values */
+
+static int csnmp_config_add_data_filter_oid(data_definition_t *data,
+                                            oconfig_item_t *ci) {
+
+  char buffer[DATA_MAX_NAME_LEN];
+  int status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
+  if (status != 0)
+    return status;
+
+  data->filter_oid.oid_len = MAX_OID_LEN;
+
+  if (!read_objid(buffer, data->filter_oid.oid, &data->filter_oid.oid_len)) {
+    ERROR("snmp plugin: read_objid (%s) failed.", buffer);
+    return -1;
+  }
+  return 0;
+} /* int csnmp_config_add_data_filter_oid */
+
 static int csnmp_config_add_data(oconfig_item_t *ci) {
   data_definition_t *dd = calloc(1, sizeof(*dd));
   if (dd == NULL)
@@ -338,6 +392,14 @@ static int csnmp_config_add_data(oconfig_item_t *ci) {
   dd->ignores_len = 0;
   dd->ignores = NULL;
 
+  dd->ignorelist = ignorelist_create(/* invert = */ 1);
+  if (dd->ignorelist == NULL) {
+    sfree(dd->name);
+    sfree(dd);
+    ERROR("snmp plugin: ignorelist_create() failed.");
+    return ENOMEM;
+  }
+
   dd->plugin_name = strdup("snmp");
   if (dd->plugin_name == NULL) {
     ERROR("snmp plugin: Can't allocate memory");
@@ -356,30 +418,42 @@ static int csnmp_config_add_data(oconfig_item_t *ci) {
     else if (strcasecmp("Instance", option->key) == 0) {
       if (dd->is_table) {
         /* Instance is OID */
-        WARNING("snmp plugin: Option `Instance' is deprecated, please update "
-                "Data \"%s\" block to use option `TypeInstanceOID'.",
-                dd->name);
-        status = csnmp_config_add_data_instance_oid(dd, option,
-                                                    false /* type instance */);
+        WARNING(
+            "snmp plugin: data %s: Option `Instance' is deprecated, please use "
+            "option `TypeInstanceOID'.",
+            dd->name);
+        status =
+            csnmp_config_configure_data_instance(&dd->type_instance, option);
       } else {
         /* Instance is a simple string */
-        WARNING("snmp plugin: Option `Instance' is deprecated, please update "
-                "Data \"%s\" block to use option `TypeInstance'.",
-                dd->name);
-        status = cf_util_get_string(option, &dd->type_instance);
+        WARNING(
+            "snmp plugin: data %s: Option `Instance' is deprecated, please use "
+            "option `TypeInstance'.",
+            dd->name);
+        status = cf_util_get_string(option, &dd->type_instance.value);
       }
+    } else if (strcasecmp("InstancePrefix", option->key) == 0) {
+      WARNING("snmp plugin: data %s: Option `InstancePrefix' is deprecated, "
+              "please use option `TypeInstancePrefix'.",
+              dd->name);
+      status = cf_util_get_string(option, &dd->type_instance.prefix);
     } else if (strcasecmp("PluginInstance", option->key) == 0)
-      status = cf_util_get_string(option, &dd->plugin_instance);
+      status = cf_util_get_string(option, &dd->plugin_instance.value);
     else if (strcasecmp("TypeInstance", option->key) == 0)
-      status = cf_util_get_string(option, &dd->type_instance);
+      status = cf_util_get_string(option, &dd->type_instance.value);
     else if (strcasecmp("PluginInstanceOID", option->key) == 0)
-      status = csnmp_config_add_data_instance_oid(dd, option,
-                                                  true /* plugin instance */);
+      status =
+          csnmp_config_configure_data_instance(&dd->plugin_instance, option);
+    else if (strcasecmp("PluginInstancePrefix", option->key) == 0)
+      status = cf_util_get_string(option, &dd->plugin_instance.prefix);
     else if (strcasecmp("TypeInstanceOID", option->key) == 0)
-      status = csnmp_config_add_data_instance_oid(dd, option,
-                                                  false /* type instance */);
-    else if (strcasecmp("InstancePrefix", option->key) == 0)
-      status = cf_util_get_string(option, &dd->instance_prefix);
+      status = csnmp_config_configure_data_instance(&dd->type_instance, option);
+    else if (strcasecmp("TypeInstancePrefix", option->key) == 0)
+      status = cf_util_get_string(option, &dd->type_instance.prefix);
+    else if (strcasecmp("HostOID", option->key) == 0)
+      status = csnmp_config_configure_data_instance(&dd->host, option);
+    else if (strcasecmp("HostPrefix", option->key) == 0)
+      status = cf_util_get_string(option, &dd->host.prefix);
     else if (strcasecmp("Values", option->key) == 0)
       status = csnmp_config_add_data_values(dd, option);
     else if (strcasecmp("Shift", option->key) == 0)
@@ -390,8 +464,18 @@ static int csnmp_config_add_data(oconfig_item_t *ci) {
       status = csnmp_config_add_data_blacklist(dd, option);
     else if (strcasecmp("InvertMatch", option->key) == 0)
       status = cf_util_get_boolean(option, &dd->invert_match);
-    else {
-      WARNING("snmp plugin: Option `%s' not allowed here.", option->key);
+    else if (strcasecmp("FilterOID", option->key) == 0) {
+      status = csnmp_config_add_data_filter_oid(dd, option);
+    } else if (strcasecmp("FilterValues", option->key) == 0) {
+      status = csnmp_config_add_data_filter_values(dd, option);
+    } else if (strcasecmp("FilterIgnoreSelected", option->key) == 0) {
+      bool t;
+      status = cf_util_get_boolean(option, &t);
+      if (status == 0)
+        ignorelist_set_invert(dd->ignorelist, /* invert = */ !t);
+    } else {
+      WARNING("snmp plugin: data %s: Option `%s' not allowed here.", dd->name,
+              option->key);
       status = -1;
     }
 
@@ -401,34 +485,62 @@ static int csnmp_config_add_data(oconfig_item_t *ci) {
 
   while (status == 0) {
     if (dd->is_table) {
-      if (dd->plugin_instance && dd->instance.is_plugin) {
-        WARNING("snmp plugin: Option `PluginInstance' will be ignored for "
-                "Data `%s'",
+      /* Set type_instance to SUBID by default */
+      if (!dd->plugin_instance.configured && !dd->host.configured)
+        dd->type_instance.configured = true;
+
+      if (dd->plugin_instance.value && dd->plugin_instance.configured) {
+        WARNING(
+            "snmp plugin: data %s: Option `PluginInstance' will be ignored.",
+            dd->name);
+      }
+      if (dd->type_instance.value && dd->type_instance.configured) {
+        WARNING("snmp plugin: data %s: Option `TypeInstance' will be ignored.",
+                dd->name);
+      }
+      if (dd->type_instance.prefix && !dd->type_instance.configured) {
+        WARNING("snmp plugin: data %s: Option `TypeInstancePrefix' will be "
+                "ignored.",
+                dd->name);
+      }
+      if (dd->plugin_instance.prefix && !dd->plugin_instance.configured) {
+        WARNING("snmp plugin: data %s: Option `PluginInstancePrefix' will be "
+                "ignored.",
                 dd->name);
       }
-      if (dd->type_instance && !dd->instance.is_plugin) {
-        WARNING("snmp plugin: Option `TypeInstance' will be ignored for Data "
-                "`%s'",
+      if (dd->host.prefix && !dd->host.configured) {
+        WARNING("snmp plugin: data %s: Option `HostPrefix' will be ignored.",
                 dd->name);
       }
     } else {
-      if (dd->instance.configured) {
-        if (dd->instance.is_plugin) {
-          WARNING("snmp plugin: Option `PluginInstanceOID' will be ignored for "
-                  "Data `%s'",
-                  dd->name);
-        } else {
-          WARNING("snmp plugin: Option `TypeInstanceOID' will be ignored for "
-                  "Data `%s'",
-                  dd->name);
-        }
+      if (dd->plugin_instance.oid.oid_len > 0) {
+        WARNING("snmp plugin: data %s: Option `PluginInstanceOID' will be "
+                "ignored.",
+                dd->name);
       }
-
-      if (dd->instance_prefix) {
-        WARNING("snmp plugin: data %s: InstancePrefix is ignored when `Table' "
-                "is set to `false'.",
+      if (dd->type_instance.oid.oid_len > 0) {
+        WARNING(
+            "snmp plugin: data %s: Option `TypeInstanceOID' will be ignored.",
+            dd->name);
+      }
+      if (dd->type_instance.prefix) {
+        WARNING("snmp plugin: data %s: Option `TypeInstancePrefix' is ignored "
+                "when `Table' "
+                "set to `false'.",
                 dd->name);
       }
+      if (dd->plugin_instance.prefix) {
+        WARNING("snmp plugin: data %s: Option `PluginInstancePrefix' is "
+                "ignored when "
+                "`Table' set to `false'.",
+                dd->name);
+      }
+      if (dd->host.prefix) {
+        WARNING(
+            "snmp plugin: data %s: Option `HostPrefix' is ignored when `Table' "
+            "set to `false'.",
+            dd->name);
+      }
     }
 
     if (dd->type == NULL) {
@@ -446,15 +558,7 @@ static int csnmp_config_add_data(oconfig_item_t *ci) {
   } /* while (status == 0) */
 
   if (status != 0) {
-    sfree(dd->name);
-    sfree(dd->type);
-    sfree(dd->plugin_name);
-    sfree(dd->plugin_instance);
-    sfree(dd->type_instance);
-    sfree(dd->instance_prefix);
-    sfree(dd->values);
-    sfree(dd->ignores);
-    sfree(dd);
+    csnmp_data_definition_destroy(dd);
     return -1;
   }
 
@@ -463,11 +567,16 @@ static int csnmp_config_add_data(oconfig_item_t *ci) {
         dd->name, dd->type, (dd->is_table) ? "true" : "false", dd->values_len);
 
   DEBUG("snmp plugin:        plugin_instance = %s, type_instance = %s,",
-        dd->plugin_instance, dd->type_instance);
+        dd->plugin_instance.value, dd->type_instance.value);
 
-  DEBUG("snmp plugin:        instance_by_oid = %s, to_plugin_instance = %s }",
-        (dd->instance.oid.oid_len > 0) ? "true" : "SUBID",
-        (dd->instance.is_plugin) ? "true" : "false");
+  DEBUG("snmp plugin:        type_instance_by_oid = %s, plugin_instance_by_oid "
+        "= %s }",
+        (dd->type_instance.oid.oid_len > 0)
+            ? "true"
+            : ((dd->type_instance.configured) ? "SUBID" : "false"),
+        (dd->plugin_instance.oid.oid_len > 0)
+            ? "true"
+            : ((dd->plugin_instance.configured) ? "SUBID" : "false"));
 
   if (data_head == NULL)
     data_head = dd;
@@ -501,7 +610,7 @@ static int csnmp_config_add_host_version(host_definition_t *hd,
   hd->version = version;
 
   return 0;
-} /* int csnmp_config_add_host_address */
+} /* int csnmp_config_add_host_version */
 
 static int csnmp_config_add_host_collect(host_definition_t *host,
                                          oconfig_item_t *ci) {
@@ -889,8 +998,8 @@ static void csnmp_host_open_session(host_definition_t *host) {
 
 /* TODO: Check if negative values wrap around. Problem: negative temperatures.
  */
-static value_t csnmp_value_list_to_value(struct variable_list *vl, int type,
-                                         double scale, double shift,
+static value_t csnmp_value_list_to_value(const struct variable_list *vl,
+                                         int type, double scale, double shift,
                                          const char *host_name,
                                          const char *data_name) {
   value_t ret;
@@ -1093,96 +1202,99 @@ static int csnmp_strvbcopy(char *dst, /* {{{ */
   return 0;
 } /* }}} int csnmp_strvbcopy */
 
-static int csnmp_instance_list_add(csnmp_list_instances_t **head,
-                                   csnmp_list_instances_t **tail,
-                                   const struct snmp_pdu *res,
-                                   const host_definition_t *hd,
-                                   const data_definition_t *dd) {
-  csnmp_list_instances_t *il;
-  struct variable_list *vb;
-  oid_t vb_name;
-  int status;
+static csnmp_cell_char_t *csnmp_get_char_cell(const struct variable_list *vb,
+                                              const oid_t *root_oid,
+                                              const host_definition_t *hd,
+                                              const data_definition_t *dd) {
 
-  /* Set vb on the last variable */
-  for (vb = res->variables; (vb != NULL) && (vb->next_variable != NULL);
-       vb = vb->next_variable)
-    /* do nothing */;
   if (vb == NULL)
-    return -1;
-
-  csnmp_oid_init(&vb_name, vb->name, vb->name_length);
+    return NULL;
 
-  il = calloc(1, sizeof(*il));
+  csnmp_cell_char_t *il = calloc(1, sizeof(*il));
   if (il == NULL) {
     ERROR("snmp plugin: calloc failed.");
-    return -1;
+    return NULL;
   }
   il->next = NULL;
 
-  status = csnmp_oid_suffix(&il->suffix, &vb_name, &dd->instance.oid);
-  if (status != 0) {
+  oid_t vb_name;
+  csnmp_oid_init(&vb_name, vb->name, vb->name_length);
+
+  if (csnmp_oid_suffix(&il->suffix, &vb_name, root_oid) != 0) {
     sfree(il);
-    return status;
+    return NULL;
   }
 
-  /* Get instance name */
+  /* Get value */
   if ((vb->type == ASN_OCTET_STR) || (vb->type == ASN_BIT_STR) ||
       (vb->type == ASN_IPADDRESS)) {
-    char *ptr;
-
-    csnmp_strvbcopy(il->instance, vb, sizeof(il->instance));
-    bool is_matched = 0;
-    for (uint32_t i = 0; i < dd->ignores_len; i++) {
-      status = fnmatch(dd->ignores[i], il->instance, 0);
-      if (status == 0) {
-        if (!dd->invert_match) {
-          sfree(il);
-          return 0;
-        } else {
-          is_matched = 1;
-          break;
-        }
-      }
-    }
-    if (dd->invert_match && !is_matched) {
-      sfree(il);
-      return 0;
-    }
-    for (ptr = il->instance; *ptr != '\0'; ptr++) {
-      if ((*ptr > 0) && (*ptr < 32))
-        *ptr = ' ';
-      else if (*ptr == '/')
-        *ptr = '_';
-    }
-    DEBUG("snmp plugin: il->instance = `%s';", il->instance);
+
+    csnmp_strvbcopy(il->value, vb, sizeof(il->value));
+
   } else {
     value_t val = csnmp_value_list_to_value(
         vb, DS_TYPE_COUNTER,
         /* scale = */ 1.0, /* shift = */ 0.0, hd->name, dd->name);
-    snprintf(il->instance, sizeof(il->instance), "%" PRIu64,
-             (uint64_t)val.counter);
+    snprintf(il->value, sizeof(il->value), "%" PRIu64, (uint64_t)val.counter);
   }
 
-  /* TODO: Debugging output */
+  return il;
+} /* csnmp_cell_char_t csnmp_get_char_cell */
 
+static void csnmp_cells_append(csnmp_cell_char_t **head,
+                               csnmp_cell_char_t **tail,
+                               csnmp_cell_char_t *il) {
   if (*head == NULL)
     *head = il;
   else
     (*tail)->next = il;
   *tail = il;
-
+} /* void csnmp_cells_append */
+
+static bool csnmp_ignore_instance(csnmp_cell_char_t *cell,
+                                  const data_definition_t *dd) {
+  bool is_matched = 0;
+  for (uint32_t i = 0; i < dd->ignores_len; i++) {
+    int status = fnmatch(dd->ignores[i], cell->value, 0);
+    if (status == 0) {
+      if (!dd->invert_match) {
+        return 1;
+      } else {
+        is_matched = 1;
+        break;
+      }
+    }
+  }
+  if (dd->invert_match && !is_matched) {
+    return 1;
+  }
   return 0;
-} /* int csnmp_instance_list_add */
+} /* bool csnmp_ignore_instance */
+
+static void csnmp_cell_replace_reserved_chars(csnmp_cell_char_t *cell) {
+  for (char *ptr = cell->value; *ptr != '\0'; ptr++) {
+    if ((*ptr > 0) && (*ptr < 32))
+      *ptr = ' ';
+    else if (*ptr == '/')
+      *ptr = '_';
+  }
+} /* void csnmp_cell_replace_reserved_chars */
 
 static int csnmp_dispatch_table(host_definition_t *host,
                                 data_definition_t *data,
-                                csnmp_list_instances_t *instance_list,
-                                csnmp_table_values_t **value_table) {
+                                csnmp_cell_char_t *type_instance_cells,
+                                csnmp_cell_char_t *plugin_instance_cells,
+                                csnmp_cell_char_t *hostname_cells,
+                                csnmp_cell_char_t *filter_cells,
+                                csnmp_cell_value_t **value_cells) {
   const data_set_t *ds;
   value_list_t vl = VALUE_LIST_INIT;
 
-  csnmp_list_instances_t *instance_list_ptr;
-  csnmp_table_values_t *value_table_ptr[data->values_len];
+  csnmp_cell_char_t *type_instance_cell_ptr = type_instance_cells;
+  csnmp_cell_char_t *plugin_instance_cell_ptr = plugin_instance_cells;
+  csnmp_cell_char_t *hostname_cell_ptr = hostname_cells;
+  csnmp_cell_char_t *filter_cell_ptr = filter_cells;
+  csnmp_cell_value_t *value_cell_ptr[data->values_len];
 
   size_t i;
   bool have_more;
@@ -1196,13 +1308,11 @@ static int csnmp_dispatch_table(host_definition_t *host,
   assert(ds->ds_num == data->values_len);
   assert(data->values_len > 0);
 
-  instance_list_ptr = instance_list;
-
   for (i = 0; i < data->values_len; i++)
-    value_table_ptr[i] = value_table[i];
+    value_cell_ptr[i] = value_cells[i];
 
-  sstrncpy(vl.host, host->name, sizeof(vl.host));
   sstrncpy(vl.plugin, data->plugin_name, sizeof(vl.plugin));
+  sstrncpy(vl.type, data->type, sizeof(vl.type));
 
   vl.interval = host->interval;
 
@@ -1211,17 +1321,17 @@ static int csnmp_dispatch_table(host_definition_t *host,
     bool suffix_skipped = 0;
 
     /* Determine next suffix to handle. */
-    if (instance_list != NULL) {
-      if (instance_list_ptr == NULL) {
+    if (type_instance_cells != NULL) {
+      if (type_instance_cell_ptr == NULL) {
         have_more = 0;
         continue;
       }
 
-      memcpy(&current_suffix, &instance_list_ptr->suffix,
+      memcpy(&current_suffix, &type_instance_cell_ptr->suffix,
              sizeof(current_suffix));
     } else {
       /* no instance configured */
-      csnmp_table_values_t *ptr = value_table_ptr[0];
+      csnmp_cell_value_t *ptr = value_cell_ptr[0];
       if (ptr == NULL) {
         have_more = 0;
         continue;
@@ -1230,18 +1340,82 @@ static int csnmp_dispatch_table(host_definition_t *host,
       memcpy(&current_suffix, &ptr->suffix, sizeof(current_suffix));
     }
 
-    /* Update all the value_table_ptr to point at the entry with the same
+    /*
+    char oid_buffer[1024] = {0};
+    snprint_objid(oid_buffer, sizeof(oid_buffer) - 1, current_suffix.oid,
+                          current_suffix.oid_len);
+    DEBUG("SNMP PLUGIN: SUFFIX %s", oid_buffer);
+    */
+
+    /* Update plugin_instance_cell_ptr to point expected suffix */
+    if (plugin_instance_cells != NULL) {
+      while ((plugin_instance_cell_ptr != NULL) &&
+             (csnmp_oid_compare(&plugin_instance_cell_ptr->suffix,
+                                &current_suffix) < 0))
+        plugin_instance_cell_ptr = plugin_instance_cell_ptr->next;
+
+      if (plugin_instance_cell_ptr == NULL) {
+        have_more = 0;
+        continue;
+      }
+
+      if (csnmp_oid_compare(&plugin_instance_cell_ptr->suffix,
+                            &current_suffix) > 0) {
+        /* This suffix is missing in the subtree. Indicate this with the
+         * "suffix_skipped" flag and try the next instance / suffix. */
+        suffix_skipped = 1;
+      }
+    }
+
+    /* Update hostname_cell_ptr to point expected suffix */
+    if (hostname_cells != NULL) {
+      while (
+          (hostname_cell_ptr != NULL) &&
+          (csnmp_oid_compare(&hostname_cell_ptr->suffix, &current_suffix) < 0))
+        hostname_cell_ptr = hostname_cell_ptr->next;
+
+      if (hostname_cell_ptr == NULL) {
+        have_more = 0;
+        continue;
+      }
+
+      if (csnmp_oid_compare(&hostname_cell_ptr->suffix, &current_suffix) > 0) {
+        /* This suffix is missing in the subtree. Indicate this with the
+         * "suffix_skipped" flag and try the next instance / suffix. */
+        suffix_skipped = 1;
+      }
+    }
+
+    /* Update filter_cell_ptr to point expected suffix */
+    if (filter_cells != NULL) {
+      while ((filter_cell_ptr != NULL) &&
+             (csnmp_oid_compare(&filter_cell_ptr->suffix, &current_suffix) < 0))
+        filter_cell_ptr = filter_cell_ptr->next;
+
+      if (filter_cell_ptr == NULL) {
+        have_more = 0;
+        continue;
+      }
+
+      if (csnmp_oid_compare(&filter_cell_ptr->suffix, &current_suffix) > 0) {
+        /* This suffix is missing in the subtree. Indicate this with the
+         * "suffix_skipped" flag and try the next instance / suffix. */
+        suffix_skipped = 1;
+      }
+    }
+
+    /* Update all the value_cell_ptr to point at the entry with the same
      * trailing partial OID */
     for (i = 0; i < data->values_len; i++) {
       while (
-          (value_table_ptr[i] != NULL) &&
-          (csnmp_oid_compare(&value_table_ptr[i]->suffix, &current_suffix) < 0))
-        value_table_ptr[i] = value_table_ptr[i]->next;
+          (value_cell_ptr[i] != NULL) &&
+          (csnmp_oid_compare(&value_cell_ptr[i]->suffix, &current_suffix) < 0))
+        value_cell_ptr[i] = value_cell_ptr[i]->next;
 
-      if (value_table_ptr[i] == NULL) {
+      if (value_cell_ptr[i] == NULL) {
         have_more = 0;
         break;
-      } else if (csnmp_oid_compare(&value_table_ptr[i]->suffix,
+      } else if (csnmp_oid_compare(&value_cell_ptr[i]->suffix,
                                    &current_suffix) > 0) {
         /* This suffix is missing in the subtree. Indicate this with the
          * "suffix_skipped" flag and try the next instance / suffix. */
@@ -1255,59 +1429,98 @@ static int csnmp_dispatch_table(host_definition_t *host,
 
     /* Matching the values failed. Start from the beginning again. */
     if (suffix_skipped) {
-      if (instance_list != NULL)
-        instance_list_ptr = instance_list_ptr->next;
+      if (type_instance_cells != NULL)
+        type_instance_cell_ptr = type_instance_cell_ptr->next;
       else
-        value_table_ptr[0] = value_table_ptr[0]->next;
+        value_cell_ptr[0] = value_cell_ptr[0]->next;
 
       continue;
     }
 
-/* if we reach this line, all value_table_ptr[i] are non-NULL and are set
- * to the same subid. instance_list_ptr is either NULL or points to the
+/* if we reach this line, all value_cell_ptr[i] are non-NULL and are set
+ * to the same subid. type_instance_cell_ptr is either NULL or points to the
  * same subid, too. */
 #if COLLECT_DEBUG
     for (i = 1; i < data->values_len; i++) {
-      assert(value_table_ptr[i] != NULL);
-      assert(csnmp_oid_compare(&value_table_ptr[i - 1]->suffix,
-                               &value_table_ptr[i]->suffix) == 0);
+      assert(value_cell_ptr[i] != NULL);
+      assert(csnmp_oid_compare(&value_cell_ptr[i - 1]->suffix,
+                               &value_cell_ptr[i]->suffix) == 0);
     }
-    assert((instance_list_ptr == NULL) ||
-           (csnmp_oid_compare(&instance_list_ptr->suffix,
-                              &value_table_ptr[0]->suffix) == 0));
+    assert((type_instance_cell_ptr == NULL) ||
+           (csnmp_oid_compare(&type_instance_cell_ptr->suffix,
+                              &value_cell_ptr[0]->suffix) == 0));
+    assert((plugin_instance_cell_ptr == NULL) ||
+           (csnmp_oid_compare(&plugin_instance_cell_ptr->suffix,
+                              &value_cell_ptr[0]->suffix) == 0));
+    assert((hostname_cell_ptr == NULL) ||
+           (csnmp_oid_compare(&hostname_cell_ptr->suffix,
+                              &value_cell_ptr[0]->suffix) == 0));
+    assert((filter_cell_ptr == NULL) ||
+           (csnmp_oid_compare(&filter_cell_ptr->suffix,
+                              &value_cell_ptr[0]->suffix) == 0));
 #endif
 
-    sstrncpy(vl.type, data->type, sizeof(vl.type));
+    /* Check the value in filter column */
+    if (filter_cell_ptr &&
+        ignorelist_match(data->ignorelist, filter_cell_ptr->value) != 0) {
+      if (type_instance_cells != NULL)
+        type_instance_cell_ptr = type_instance_cell_ptr->next;
+      else
+        value_cell_ptr[0] = value_cell_ptr[0]->next;
 
-    {
+      continue;
+    }
+
+    /* set vl.host */
+    if (data->host.configured) {
       char temp[DATA_MAX_NAME_LEN];
+      if (hostname_cell_ptr == NULL)
+        csnmp_oid_to_string(temp, sizeof(temp), &current_suffix);
+      else
+        sstrncpy(temp, hostname_cell_ptr->value, sizeof(temp));
 
-      if (instance_list_ptr == NULL)
+      if (data->host.prefix == NULL)
+        sstrncpy(vl.host, temp, sizeof(vl.host));
+      else
+        snprintf(vl.host, sizeof(vl.host), "%s%s", data->host.prefix, temp);
+    } else {
+      sstrncpy(vl.host, host->name, sizeof(vl.host));
+    }
+
+    /* set vl.type_instance */
+    if (data->type_instance.configured) {
+      char temp[DATA_MAX_NAME_LEN];
+      if (type_instance_cell_ptr == NULL)
         csnmp_oid_to_string(temp, sizeof(temp), &current_suffix);
       else
-        sstrncpy(temp, instance_list_ptr->instance, sizeof(temp));
+        sstrncpy(temp, type_instance_cell_ptr->value, sizeof(temp));
 
-      if (data->instance.is_plugin) {
-        if (data->instance_prefix == NULL)
-          sstrncpy(vl.plugin_instance, temp, sizeof(vl.plugin_instance));
-        else
-          snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s%s",
-                   data->instance_prefix, temp);
+      if (data->type_instance.prefix == NULL)
+        sstrncpy(vl.type_instance, temp, sizeof(vl.type_instance));
+      else
+        snprintf(vl.type_instance, sizeof(vl.type_instance), "%s%s",
+                 data->type_instance.prefix, temp);
+    } else if (data->type_instance.value) {
+      sstrncpy(vl.type_instance, data->type_instance.value,
+               sizeof(vl.type_instance));
+    }
 
-        if (data->type_instance)
-          sstrncpy(vl.type_instance, data->type_instance,
-                   sizeof(vl.type_instance));
-      } else {
-        if (data->instance_prefix == NULL)
-          sstrncpy(vl.type_instance, temp, sizeof(vl.type_instance));
-        else
-          snprintf(vl.type_instance, sizeof(vl.type_instance), "%s%s",
-                   data->instance_prefix, temp);
+    /* set vl.plugin_instance */
+    if (data->plugin_instance.configured) {
+      char temp[DATA_MAX_NAME_LEN];
+      if (plugin_instance_cell_ptr == NULL)
+        csnmp_oid_to_string(temp, sizeof(temp), &current_suffix);
+      else
+        sstrncpy(temp, plugin_instance_cell_ptr->value, sizeof(temp));
 
-        if (data->plugin_instance)
-          sstrncpy(vl.plugin_instance, data->plugin_instance,
-                   sizeof(vl.plugin_instance));
-      }
+      if (data->plugin_instance.prefix == NULL)
+        sstrncpy(vl.plugin_instance, temp, sizeof(vl.plugin_instance));
+      else
+        snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s%s",
+                 data->plugin_instance.prefix, temp);
+    } else if (data->plugin_instance.value) {
+      sstrncpy(vl.plugin_instance, data->plugin_instance.value,
+               sizeof(vl.plugin_instance));
     }
 
     vl.values_len = data->values_len;
@@ -1315,7 +1528,7 @@ static int csnmp_dispatch_table(host_definition_t *host,
     vl.values = values;
 
     for (i = 0; i < data->values_len; i++)
-      vl.values[i] = value_table_ptr[i]->value;
+      vl.values[i] = value_cell_ptr[i]->value;
 
     plugin_dispatch_values(&vl);
 
@@ -1323,10 +1536,10 @@ static int csnmp_dispatch_table(host_definition_t *host,
     vl.values_len = 0;
     vl.values = NULL;
 
-    if (instance_list != NULL)
-      instance_list_ptr = instance_list_ptr->next;
+    if (type_instance_cells != NULL)
+      type_instance_cell_ptr = type_instance_cell_ptr->next;
     else
-      value_table_ptr[0] = value_table_ptr[0]->next;
+      value_cell_ptr[0] = value_cell_ptr[0]->next;
   } /* while (have_more) */
 
   return (0);
@@ -1339,25 +1552,43 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
 
   const data_set_t *ds;
 
-  size_t oid_list_len = data->values_len + 1;
+  size_t oid_list_len = data->values_len;
+
+  if (data->type_instance.oid.oid_len > 0)
+    oid_list_len++;
+
+  if (data->plugin_instance.oid.oid_len > 0)
+    oid_list_len++;
+
+  if (data->host.oid.oid_len > 0)
+    oid_list_len++;
+
+  if (data->filter_oid.oid_len > 0)
+    oid_list_len++;
+
   /* Holds the last OID returned by the device. We use this in the GETNEXT
    * request to proceed. */
   oid_t oid_list[oid_list_len];
   /* Set to false when an OID has left its subtree so we don't re-request it
    * again. */
-  bool oid_list_todo[oid_list_len];
+  csnmp_oid_type_t oid_list_todo[oid_list_len];
 
   int status;
   size_t i;
 
-  /* `value_list_head' and `value_list_tail' implement a linked list for each
-   * value. `instance_list_head' and `instance_list_tail' implement a linked
-   * list of
-   * instance names. This is used to jump gaps in the table. */
-  csnmp_list_instances_t *instance_list_head;
-  csnmp_list_instances_t *instance_list_tail;
-  csnmp_table_values_t **value_list_head;
-  csnmp_table_values_t **value_list_tail;
+  /* `value_list_head' and `value_cells_tail' implement a linked list for each
+   * value. `instance_cells_head' and `instance_cells_tail' implement a linked
+   * list of instance names. This is used to jump gaps in the table. */
+  csnmp_cell_char_t *type_instance_cells_head = NULL;
+  csnmp_cell_char_t *type_instance_cells_tail = NULL;
+  csnmp_cell_char_t *plugin_instance_cells_head = NULL;
+  csnmp_cell_char_t *plugin_instance_cells_tail = NULL;
+  csnmp_cell_char_t *hostname_cells_head = NULL;
+  csnmp_cell_char_t *hostname_cells_tail = NULL;
+  csnmp_cell_char_t *filter_cells_head = NULL;
+  csnmp_cell_char_t *filter_cells_tail = NULL;
+  csnmp_cell_value_t **value_cells_head;
+  csnmp_cell_value_t **value_cells_tail;
 
   DEBUG("snmp plugin: csnmp_read_table (host = %s, data = %s)", host->name,
         data->name);
@@ -1382,31 +1613,48 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
   }
   assert(data->values_len > 0);
 
+  for (i = 0; i < data->values_len; i++)
+    oid_list_todo[i] = OID_TYPE_VARIABLE;
+
   /* We need a copy of all the OIDs, because GETNEXT will destroy them. */
   memcpy(oid_list, data->values, data->values_len * sizeof(oid_t));
-  if (data->instance.oid.oid_len > 0)
-    memcpy(oid_list + data->values_len, &data->instance.oid, sizeof(oid_t));
-  else /* no InstanceFrom option specified. */
-    oid_list_len--;
 
-  for (i = 0; i < oid_list_len; i++)
-    oid_list_todo[i] = 1;
+  if (data->type_instance.oid.oid_len > 0) {
+    memcpy(oid_list + i, &data->type_instance.oid, sizeof(oid_t));
+    oid_list_todo[i] = OID_TYPE_TYPEINSTANCE;
+    i++;
+  }
+
+  if (data->plugin_instance.oid.oid_len > 0) {
+    memcpy(oid_list + i, &data->plugin_instance.oid, sizeof(oid_t));
+    oid_list_todo[i] = OID_TYPE_PLUGININSTANCE;
+    i++;
+  }
+
+  if (data->host.oid.oid_len > 0) {
+    memcpy(oid_list + i, &data->host.oid, sizeof(oid_t));
+    oid_list_todo[i] = OID_TYPE_HOST;
+    i++;
+  }
+
+  if (data->filter_oid.oid_len > 0) {
+    memcpy(oid_list + i, &data->filter_oid, sizeof(oid_t));
+    oid_list_todo[i] = OID_TYPE_FILTER;
+    i++;
+  }
 
   /* We're going to construct n linked lists, one for each "value".
-   * value_list_head will contain pointers to the heads of these linked lists,
-   * value_list_tail will contain pointers to the tail of the lists. */
-  value_list_head = calloc(data->values_len, sizeof(*value_list_head));
-  value_list_tail = calloc(data->values_len, sizeof(*value_list_tail));
-  if ((value_list_head == NULL) || (value_list_tail == NULL)) {
+   * value_cells_head will contain pointers to the heads of these linked lists,
+   * value_cells_tail will contain pointers to the tail of the lists. */
+  value_cells_head = calloc(data->values_len, sizeof(*value_cells_head));
+  value_cells_tail = calloc(data->values_len, sizeof(*value_cells_tail));
+  if ((value_cells_head == NULL) || (value_cells_tail == NULL)) {
     ERROR("snmp plugin: csnmp_read_table: calloc failed.");
-    sfree(value_list_head);
-    sfree(value_list_tail);
+    sfree(value_cells_head);
+    sfree(value_cells_tail);
     return -1;
   }
 
-  instance_list_head = NULL;
-  instance_list_tail = NULL;
-
   status = 0;
   while (status == 0) {
     req = snmp_pdu_create(SNMP_MSG_GETNEXT);
@@ -1519,30 +1767,126 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
       }
 
       /* An instance is configured and the res variable we process is the
-       * instance value (last index) */
-      if ((data->instance.oid.oid_len > 0) && (i == data->values_len)) {
+       * instance value */
+      if (oid_list_todo[i] == OID_TYPE_TYPEINSTANCE) {
+        if ((vb->type == SNMP_ENDOFMIBVIEW) ||
+            (snmp_oid_ncompare(data->type_instance.oid.oid,
+                               data->type_instance.oid.oid_len, vb->name,
+                               vb->name_length,
+                               data->type_instance.oid.oid_len) != 0)) {
+          DEBUG("snmp plugin: host = %s; data = %s; TypeInstance left its "
+                "subtree.",
+                host->name, data->name);
+          oid_list_todo[i] = 0;
+          continue;
+        }
+
+        /* Allocate a new `csnmp_cell_char_t', insert the instance name and
+         * add it to the list */
+        csnmp_cell_char_t *cell =
+            csnmp_get_char_cell(vb, &data->type_instance.oid, host, data);
+        if (cell == NULL) {
+          ERROR("snmp plugin: host %s: csnmp_get_char_cell() failed.",
+                host->name);
+          status = -1;
+          break;
+        }
+
+        if (csnmp_ignore_instance(cell, data)) {
+          sfree(cell);
+        } else {
+          csnmp_cell_replace_reserved_chars(cell);
+
+          DEBUG("snmp plugin: il->type_instance = `%s';", cell->value);
+          csnmp_cells_append(&type_instance_cells_head,
+                             &type_instance_cells_tail, cell);
+        }
+      } else if (oid_list_todo[i] == OID_TYPE_PLUGININSTANCE) {
+        if ((vb->type == SNMP_ENDOFMIBVIEW) ||
+            (snmp_oid_ncompare(data->plugin_instance.oid.oid,
+                               data->plugin_instance.oid.oid_len, vb->name,
+                               vb->name_length,
+                               data->plugin_instance.oid.oid_len) != 0)) {
+          DEBUG("snmp plugin: host = %s; data = %s; TypeInstance left its "
+                "subtree.",
+                host->name, data->name);
+          oid_list_todo[i] = 0;
+          continue;
+        }
+
+        /* Allocate a new `csnmp_cell_char_t', insert the instance name and
+         * add it to the list */
+        csnmp_cell_char_t *cell =
+            csnmp_get_char_cell(vb, &data->plugin_instance.oid, host, data);
+        if (cell == NULL) {
+          ERROR("snmp plugin: host %s: csnmp_get_char_cell() failed.",
+                host->name);
+          status = -1;
+          break;
+        }
+
+        csnmp_cell_replace_reserved_chars(cell);
+
+        DEBUG("snmp plugin: il->plugin_instance = `%s';", cell->value);
+        csnmp_cells_append(&plugin_instance_cells_head,
+                           &plugin_instance_cells_tail, cell);
+      } else if (oid_list_todo[i] == OID_TYPE_HOST) {
+        if ((vb->type == SNMP_ENDOFMIBVIEW) ||
+            (snmp_oid_ncompare(data->host.oid.oid, data->host.oid.oid_len,
+                               vb->name, vb->name_length,
+                               data->host.oid.oid_len) != 0)) {
+          DEBUG("snmp plugin: host = %s; data = %s; Host left its subtree.",
+                host->name, data->name);
+          oid_list_todo[i] = 0;
+          continue;
+        }
+
+        /* Allocate a new `csnmp_cell_char_t', insert the instance name and
+         * add it to the list */
+        csnmp_cell_char_t *cell =
+            csnmp_get_char_cell(vb, &data->host.oid, host, data);
+        if (cell == NULL) {
+          ERROR("snmp plugin: host %s: csnmp_get_char_cell() failed.",
+                host->name);
+          status = -1;
+          break;
+        }
+
+        csnmp_cell_replace_reserved_chars(cell);
+
+        DEBUG("snmp plugin: il->hostname = `%s';", cell->value);
+        csnmp_cells_append(&hostname_cells_head, &hostname_cells_tail, cell);
+      } else if (oid_list_todo[i] == OID_TYPE_FILTER) {
         if ((vb->type == SNMP_ENDOFMIBVIEW) ||
-            (snmp_oid_ncompare(
-                 data->instance.oid.oid, data->instance.oid.oid_len, vb->name,
-                 vb->name_length, data->instance.oid.oid_len) != 0)) {
-          DEBUG("snmp plugin: host = %s; data = %s; Instance left its subtree.",
+            (snmp_oid_ncompare(data->filter_oid.oid, data->filter_oid.oid_len,
+                               vb->name, vb->name_length,
+                               data->filter_oid.oid_len) != 0)) {
+          DEBUG("snmp plugin: host = %s; data = %s; Host left its subtree.",
                 host->name, data->name);
           oid_list_todo[i] = 0;
           continue;
         }
 
-        /* Allocate a new `csnmp_list_instances_t', insert the instance name and
+        /* Allocate a new `csnmp_cell_char_t', insert the instance name and
          * add it to the list */
-        if (csnmp_instance_list_add(&instance_list_head, &instance_list_tail,
-                                    res, host, data) != 0) {
-          ERROR("snmp plugin: host %s: csnmp_instance_list_add failed.",
+        csnmp_cell_char_t *cell =
+            csnmp_get_char_cell(vb, &data->filter_oid, host, data);
+        if (cell == NULL) {
+          ERROR("snmp plugin: host %s: csnmp_get_char_cell() failed.",
                 host->name);
           status = -1;
           break;
         }
+
+        csnmp_cell_replace_reserved_chars(cell);
+
+        DEBUG("snmp plugin: il->filter = `%s';", cell->value);
+        csnmp_cells_append(&filter_cells_head, &filter_cells_tail, cell);
       } else /* The variable we are processing is a normal value */
       {
-        csnmp_table_values_t *vt;
+        assert(oid_list_todo[i] == OID_TYPE_VARIABLE);
+
+        csnmp_cell_value_t *vt;
         oid_t vb_name;
         oid_t suffix;
         int ret;
@@ -1561,10 +1905,9 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
         }
 
         /* Make sure the OIDs returned by the agent are increasing. Otherwise
-         * our
-         * table matching algorithm will get confused. */
-        if ((value_list_tail[i] != NULL) &&
-            (csnmp_oid_compare(&suffix, &value_list_tail[i]->suffix) <= 0)) {
+         * our table matching algorithm will get confused. */
+        if ((value_cells_tail[i] != NULL) &&
+            (csnmp_oid_compare(&suffix, &value_cells_tail[i]->suffix) <= 0)) {
           DEBUG("snmp plugin: host = %s; data = %s; i = %" PRIsz "; "
                 "Suffix is not increasing.",
                 host->name, data->name, i);
@@ -1585,11 +1928,11 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
         memcpy(&vt->suffix, &suffix, sizeof(vt->suffix));
         vt->next = NULL;
 
-        if (value_list_tail[i] == NULL)
-          value_list_head[i] = vt;
+        if (value_cells_tail[i] == NULL)
+          value_cells_head[i] = vt;
         else
-          value_list_tail[i]->next = vt;
-        value_list_tail[i] = vt;
+          value_cells_tail[i]->next = vt;
+        value_cells_tail[i] = vt;
       }
 
       /* Copy OID to oid_list[i] */
@@ -1608,25 +1951,45 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) {
   res = NULL;
 
   if (status == 0)
-    csnmp_dispatch_table(host, data, instance_list_head, value_list_head);
+    csnmp_dispatch_table(host, data, type_instance_cells_head,
+                         plugin_instance_cells_head, hostname_cells_head,
+                         filter_cells_head, value_cells_head);
 
   /* Free all allocated variables here */
-  while (instance_list_head != NULL) {
-    csnmp_list_instances_t *next = instance_list_head->next;
-    sfree(instance_list_head);
-    instance_list_head = next;
+  while (type_instance_cells_head != NULL) {
+    csnmp_cell_char_t *next = type_instance_cells_head->next;
+    sfree(type_instance_cells_head);
+    type_instance_cells_head = next;
+  }
+
+  while (plugin_instance_cells_head != NULL) {
+    csnmp_cell_char_t *next = plugin_instance_cells_head->next;
+    sfree(plugin_instance_cells_head);
+    plugin_instance_cells_head = next;
+  }
+
+  while (hostname_cells_head != NULL) {
+    csnmp_cell_char_t *next = hostname_cells_head->next;
+    sfree(hostname_cells_head);
+    hostname_cells_head = next;
+  }
+
+  while (filter_cells_head != NULL) {
+    csnmp_cell_char_t *next = filter_cells_head->next;
+    sfree(filter_cells_head);
+    filter_cells_head = next;
   }
 
   for (i = 0; i < data->values_len; i++) {
-    while (value_list_head[i] != NULL) {
-      csnmp_table_values_t *next = value_list_head[i]->next;
-      sfree(value_list_head[i]);
-      value_list_head[i] = next;
+    while (value_cells_head[i] != NULL) {
+      csnmp_cell_value_t *next = value_cells_head[i]->next;
+      sfree(value_cells_head[i]);
+      value_cells_head[i] = next;
     }
   }
 
-  sfree(value_list_head);
-  sfree(value_list_tail);
+  sfree(value_cells_head);
+  sfree(value_cells_tail);
 
   return 0;
 } /* int csnmp_read_table */
@@ -1678,10 +2041,11 @@ static int csnmp_read_value(host_definition_t *host, data_definition_t *data) {
   sstrncpy(vl.host, host->name, sizeof(vl.host));
   sstrncpy(vl.plugin, data->plugin_name, sizeof(vl.plugin));
   sstrncpy(vl.type, data->type, sizeof(vl.type));
-  if (data->type_instance)
-    sstrncpy(vl.type_instance, data->type_instance, sizeof(vl.type_instance));
-  if (data->plugin_instance)
-    sstrncpy(vl.plugin_instance, data->plugin_instance,
+  if (data->type_instance.value)
+    sstrncpy(vl.type_instance, data->type_instance.value,
+             sizeof(vl.type_instance));
+  if (data->plugin_instance.value)
+    sstrncpy(vl.plugin_instance, data->plugin_instance.value,
              sizeof(vl.plugin_instance));
 
   vl.interval = host->interval;
@@ -1794,15 +2158,7 @@ static int csnmp_shutdown(void) {
   while (data_this != NULL) {
     data_next = data_this->next;
 
-    sfree(data_this->name);
-    sfree(data_this->type);
-    sfree(data_this->plugin_name);
-    sfree(data_this->plugin_instance);
-    sfree(data_this->type_instance);
-    sfree(data_this->instance_prefix);
-    sfree(data_this->values);
-    sfree(data_this->ignores);
-    sfree(data_this);
+    csnmp_data_definition_destroy(data_this);
 
     data_this = data_next;
   }
index 3c042a8..d65af1f 100644 (file)
@@ -383,11 +383,20 @@ static int snmp_agent_create_token(char const *input, int t_off, int n,
   int ret = 0;
 
   token->key = index_key;
-  token->str = strndup(input + t_off, n);
 
+  /* copy at most n bytes from input with offset t_off into token->str */
+  input += t_off;
+  size_t len = strlen(input);
+  if (n < len)
+    len = n;
+
+  token->str = malloc(len + 1);
   if (token->str == NULL)
     goto free_offset_error;
 
+  memcpy(token->str, input, len);
+  token->str[len] = '\0';
+
   *offset = t_off;
   ret = c_avl_insert(tree, (void *)offset, (void *)token);
 
@@ -522,7 +531,7 @@ static int snmp_agent_fill_index_list(table_definition_t *td,
 
     /* Parsing input string if necessary */
     if (td->index_keys[i].regex) {
-      regmatch_t m = {-1, -1};
+      regmatch_t m;
 
       /* Parsing input string */
       ret = snmp_agent_parse_index_key(ptr, &td->index_keys[i].regex_info,
index 68389fa..bd500fc 100644 (file)
@@ -663,9 +663,15 @@ DEF_TEST(get_token) {
 }
 
 DEF_TEST(tokenize) {
-  regmatch_t m[3] = {{5, 6},    /* "1" */
-                     {12, 13},  /* "2" */
-                     {19, 20}}; /* "3" */
+  regmatch_t m[3];
+
+  m[0].rm_so = 5;
+  m[0].rm_eo = 6;
+  m[1].rm_so = 12;
+  m[1].rm_eo = 13;
+  m[2].rm_so = 19;
+  m[2].rm_eo = 20;
+
   c_avl_tree_t *tokens =
       c_avl_create((int (*)(const void *, const void *))num_compare);
   const char input[] = "testA1-testB2-testC3";