Table true
Type "if_octets"
TypeInstanceOID "IF-MIB::ifDescr"
+ #FilterOID "IF-MIB::ifOperStatus"
+ #FilterValues "1", "2"
Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
</Data>
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
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
#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>
instance_t type_instance;
instance_t plugin_instance;
instance_t host;
+ oid_t filter_oid;
+ ignorelist_t *ignorelist;
char *plugin_name;
oid_t *values;
size_t values_len;
OID_TYPE_TYPEINSTANCE,
OID_TYPE_PLUGININSTANCE,
OID_TYPE_HOST,
+ OID_TYPE_FILTER,
} csnmp_oid_type_t;
/*
sfree(dd->host.value);
sfree(dd->values);
sfree(dd->ignores);
+ ignorelist_free(dd->ignorelist);
sfree(dd);
} /* void csnmp_data_definition_destroy */
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)
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");
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 {
+ 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;
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_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;
}
}
+ /* Update filter_cell_ptr to point expected suffix */
+ if (filter_cells != NULL) {
+ while ((filter_cell_ptr != NULL) &&
+ (csnmp_oid_compare(&filter_cell_ptr->suffix, ¤t_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, ¤t_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;
+ NOTICE("snmp plugin: suffix skipped, variable not found for HostOID.");
+ }
+ }
+
/* 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++) {
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
+ 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;
+ }
+
sstrncpy(vl.type, data->type, sizeof(vl.type));
{
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];
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;
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_cells_head will contain pointers to the heads of these linked lists,
* value_cells_tail will contain pointers to the tail of the lists. */
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->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_cell_char_t', insert the instance name and
+ * add it to the list */
+ 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 */
{
assert(oid_list_todo[i] == OID_TYPE_VARIABLE);
if (status == 0)
csnmp_dispatch_table(host, data, type_instance_cells_head,
plugin_instance_cells_head, hostname_cells_head,
- value_cells_head);
+ filter_cells_head, value_cells_head);
/* Free all allocated variables here */
while (type_instance_cells_head != NULL) {
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_cells_head[i] != NULL) {
csnmp_cell_value_t *next = value_cells_head[i]->next;