From 8aba9d6e33dea747e4e27e35457f00c287e2c678 Mon Sep 17 00:00:00 2001 From: "Korynkevych, RomanX" Date: Wed, 14 Dec 2016 10:37:05 +0000 Subject: [PATCH 01/11] snmp_agent: Implement SNMP Agent plugin. The SNMP Agent plugin is an AgentX subagent that receives and handles queries from SNMP master agent and returns the data collected by read plugins. The SNMP Agent plugin handles requests only for OIDs specified in configuration file. To handle SNMP queries the plugin gets data from collectd and translates requested values from collectd's internal format to SNMP format. This plugin is a generic plugin and cannot work without configuration. For more details on AgentX subagent see Change-Id: I0e82131685f2138e1af0a9283b06f85dd2028878 Signed-off-by: Korynkevych, RomanX --- Makefile.am | 8 + README | 13 +- configure.ac | 22 + src/collectd.conf.in | 25 + src/collectd.conf.pod | 109 +++ src/daemon/utils_cache.c | 69 ++ src/daemon/utils_cache.h | 2 + src/snmp_agent.c | 1509 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 1756 insertions(+), 1 deletion(-) create mode 100644 src/snmp_agent.c diff --git a/Makefile.am b/Makefile.am index 3460cf601e..d60a78bf92 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1456,6 +1456,14 @@ snmp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBNETSNMP_LDFLAGS) snmp_la_LIBADD = $(BUILD_WITH_LIBNETSNMP_LIBS) endif +if BUILD_PLUGIN_SNMP_AGENT +pkglib_LTLIBRARIES += snmp_agent.la +snmp_agent_la_SOURCES = snmp_agent.c snmp_agent.h +snmp_agent_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBNETSNMP_CPPFLAGS) +snmp_agent_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBNETSNMP_LDFLAGS) +snmp_agent_la_LIBADD = $(BUILD_WITH_LIBNETSNMP_LIBS) +endif + if BUILD_PLUGIN_STATSD pkglib_LTLIBRARIES += statsd.la statsd_la_SOURCES = src/statsd.c diff --git a/README b/README index fb3aa27df2..c497b7118c 100644 --- a/README +++ b/README @@ -490,6 +490,13 @@ Features updates to the files and write a bunch of updates at once, which lessens system load a lot. + - snmp_agent + Receives and handles queries from SNMP master agent and returns the data + collected by read plugins. Handles requests only for OIDs specified in + configuration file. To handle SNMP queries the plugin gets data from + collectd and translates requested values from collectd's internal format + to SNMP format. + - unixsock One can query the values from the unixsock plugin whenever they're needed. Please read collectd-unixsock(5) for a description on how that's @@ -817,7 +824,11 @@ Prerequisites This library is part of the “Manage ONTAP SDK” published by NetApp. * libnetsnmp (optional) - For the `snmp' plugin. + For the `snmp' and 'snmp_agent' plugins. + + + * libnetsnmpagent (optional) + Required for the 'snmp_agent' plugin. * libnotify (optional) diff --git a/configure.ac b/configure.ac index c0fe54e848..efa54c51da 100644 --- a/configure.ac +++ b/configure.ac @@ -3643,6 +3643,7 @@ AC_SUBST([LIBNETAPP_LIBS]) # }}} # --with-libnetsnmp {{{ +with_libnetsnmpagent="no" AC_ARG_WITH(libnetsnmp, [AS_HELP_STRING([--with-libnetsnmp@<:@=PREFIX@:>@], [Path to the Net-SNMPD library.])], [ if test "x$withval" = "xno" @@ -3655,6 +3656,7 @@ AC_ARG_WITH(libnetsnmp, [AS_HELP_STRING([--with-libnetsnmp@<:@=PREFIX@:>@], [Pat with_libnetsnmp_cppflags="-I$withval/include" with_libnetsnmp_ldflags="-I$withval/lib" with_libnetsnmp="yes" + with_libnetsnmpagent="yes" fi; fi ], [with_libnetsnmp="yes"]) @@ -3667,6 +3669,10 @@ then [with_libnetsnmp="yes"], [with_libnetsnmp="no (net-snmp/net-snmp-config.h not found)"] ) + AC_CHECK_HEADERS(net-snmp/agent/agent_module_config.h, + [], + [with_libnetsnmpagent="no (net-snmp/agent/agent_module_config.h not found)"] + ) CPPFLAGS="$SAVE_CPPFLAGS" fi @@ -3680,6 +3686,11 @@ then [with_libnetsnmp="no (libnetsnmp not found)"], [$with_snmp_libs]) + AC_CHECK_LIB(netsnmpagent, init_agent, + [with_libnetsnmpagent="yes"], + [with_libnetsnmpagent="no (libnetsnmpagent not found)"], + [$with_snmp_libs]) + LDFLAGS="$SAVE_LDFLAGS" fi if test "x$with_libnetsnmp" = "xyes" @@ -3688,6 +3699,10 @@ then BUILD_WITH_LIBNETSNMP_LDFLAGS="$with_libnetsnmp_ldflags" BUILD_WITH_LIBNETSNMP_LIBS="-lnetsnmp" fi +if test "x$with_libnetsnmpagent" = "xyes" +then + BUILD_WITH_LIBNETSNMP_LIBS+=" -lnetsnmpagent" +fi AC_SUBST(BUILD_WITH_LIBNETSNMP_CPPFLAGS) AC_SUBST(BUILD_WITH_LIBNETSNMP_LDFLAGS) AC_SUBST(BUILD_WITH_LIBNETSNMP_LIBS) @@ -5899,6 +5914,7 @@ plugin_processes="no" plugin_protocols="no" plugin_python="no" plugin_serial="no" +plugin_snmp_agent="no" plugin_smart="no" plugin_swap="no" plugin_tape="no" @@ -6191,6 +6207,10 @@ if test "x$with_kvm_getswapinfo" = "xyes"; then plugin_swap="yes" fi +if test "x$with_libnetsnmp" = "xyes" && test "x$with_libnetsnmpagent" = "xyes"; then + plugin_snmp_agent="yes" +fi + if test "x$have_swapctl" = "xyes" && test "x$c_cv_have_swapctl_two_args" = "xyes"; then plugin_swap="yes" fi @@ -6350,6 +6370,7 @@ AC_PLUGIN([serial], [$plugin_serial], [serial port traffic AC_PLUGIN([sigrok], [$with_libsigrok], [sigrok acquisition sources]) AC_PLUGIN([smart], [$plugin_smart], [SMART statistics]) AC_PLUGIN([snmp], [$with_libnetsnmp], [SNMP querying plugin]) +AC_PLUGIN([snmp_agent], [$plugin_snmp_agent], [SNMP agent plugin]) AC_PLUGIN([statsd], [yes], [StatsD plugin]) AC_PLUGIN([swap], [$plugin_swap], [Swap usage statistics]) AC_PLUGIN([syslog], [$have_syslog], [Syslog logging plugin]) @@ -6774,6 +6795,7 @@ AC_MSG_RESULT([ serial . . . . . . . $enable_serial]) AC_MSG_RESULT([ sigrok . . . . . . . $enable_sigrok]) AC_MSG_RESULT([ smart . . . . . . . . $enable_smart]) AC_MSG_RESULT([ snmp . . . . . . . . $enable_snmp]) +AC_MSG_RESULT([ snmp_agent . . . . . $enable_snmp_agent]) AC_MSG_RESULT([ statsd . . . . . . . $enable_statsd]) AC_MSG_RESULT([ swap . . . . . . . . $enable_swap]) AC_MSG_RESULT([ syslog . . . . . . . $enable_syslog]) diff --git a/src/collectd.conf.in b/src/collectd.conf.in index 1cc86af488..3a25b12be5 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -186,6 +186,7 @@ #@BUILD_PLUGIN_SIGROK_TRUE@LoadPlugin sigrok #@BUILD_PLUGIN_SMART_TRUE@LoadPlugin smart #@BUILD_PLUGIN_SNMP_TRUE@LoadPlugin snmp +#@BUILD_PLUGIN_SNMP_AGENT_TRUE@LoadPlugin snmp_agent #@BUILD_PLUGIN_STATSD_TRUE@LoadPlugin statsd #@BUILD_PLUGIN_SWAP_TRUE@LoadPlugin swap #@BUILD_PLUGIN_TABLE_TRUE@LoadPlugin table @@ -1228,6 +1229,30 @@ # # +# +# +# Plugin "memory" +# Type "memory" +# TypeInstance "free" +# OIDs "1.3.6.1.4.1.2021.4.6.0" +# +# +# IndexOID "IF-MIB::ifIndex" +# SizeOID "IF-MIB::ifNumber" +# +# Instance true +# Plugin "interface" +# OIDs "IF-MIB::ifDescr" +# +# +# Plugin "interface" +# Type "if_octets" +# TypeInstance "" +# OIDs "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets" +# +#
+#
+ # # Host "::" # Port "8125" diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 51fe68d238..03ca2ce9bc 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -6930,6 +6930,115 @@ Since the configuration of the C is a little more complicated than other plugins, its documentation has been moved to an own manpage, L. Please see there for details. +=head2 Plugin C + +The I plugin is an AgentX subagent that receives and handles queries +from SNMP master agent and returns the data collected by read plugins. +The I plugin handles requests only for OIDs specified in +configuration file. To handle SNMP queries the plugin gets data from collectd +and translates requested values from collectd's internal format to SNMP format. +This plugin is a generic plugin and cannot work without configuration. +For more details on AgentX subagent see + + +B + + + + Plugin "memory" + Type "memory" + TypeInstance "free" + OIDs "1.3.6.1.4.1.2021.4.6.0" + + + IndexOID "IF-MIB::ifIndex" + SizeOID "IF-MIB::ifNumber" + + Instance true + Plugin "interface" + OIDs "IF-MIB::ifDescr" + + + Plugin "interface" + Type "if_octets" + TypeInstance "" + OIDs "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets" + +
+
+ +There are two types of blocks that can be contained in the +CPluginE snmp_agentE> block: B and B: + +=head3 The B block + +The B block defines a list OIDs that are to be handled. This block can +define scalar or table OIDs. If B block is defined inside of B
+block it reperesents table OIDs. +The following options can be set: + +=over 4 + +=item B I + +When B is set to B, the value for requested OID is copied from +plugin instance field of corresponding collectd value. If B block defines +scalar data type B has no effect and can be omitted. + +=item B I + +Read plugin name whose collected data will be mapped to specified OIDs. + +=item B I + +Collectd's type that is to be used for specified OID, e.Eg. "if_octets" +for example. The types are read from the B (see L). + +=item B I + +Collectd's type-instance that is to be used for specified OID. + +=item B I [I ...] + +Configures the OIDs to be handled by I plugin. Values for these OIDs +are taken from collectd data type specified by B, B, +B fields of this B block. Number of the OIDs configured +should correspond to number of values in specified B. +For example two OIDs "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets" can be mapped to +"rx" and "tx" values of "if_octets" type. + +=item B I + +The values taken from collectd are multiplied by I. The field is optional +and the default is B<1.0>. + +=item B I + +I is added to values from collectd after they have been multiplied by +B value. The field is optional and the default value is B<0.0>. + +=back + +=head3 The B
block + +The B
block defines a collection of B blocks that belong to one +snmp table. In addition to multiple B blocks the following options can be +set: + +=over 4 + +=item B I + +OID that is handled by the plugin and is mapped to numerical index value that is +generated by the plugin for each table record. + +=item B I + +OID that is handled by the plugin. Returned value is the number of records in +the table. The field is optional. + +=back + =head2 Plugin C The I listens to a UDP socket, reads "events" in the statsd diff --git a/src/daemon/utils_cache.c b/src/daemon/utils_cache.c index 0caf22c550..17118e0663 100644 --- a/src/daemon/utils_cache.c +++ b/src/daemon/utils_cache.c @@ -477,6 +477,75 @@ gauge_t *uc_get_rate(const data_set_t *ds, const value_list_t *vl) { return (ret); } /* gauge_t *uc_get_rate */ +int uc_get_value_by_name(const char *name, value_t **ret_values, + size_t *ret_values_num) { + value_t *ret = NULL; + size_t ret_num = 0; + cache_entry_t *ce = NULL; + int status = 0; + + pthread_mutex_lock(&cache_lock); + + if (c_avl_get(cache_tree, name, (void *) &ce) == 0) { + assert(ce != NULL); + + /* remove missing values from getval */ + if (ce->state == STATE_MISSING) { + status = -1; + } else { + ret_num = ce->values_num; + ret = malloc(ret_num * sizeof(*ret)); + if (ret == NULL) { + ERROR("utils_cache: uc_get_value_by_name: malloc failed."); + status = -1; + } else { + memcpy(ret, ce->values_raw, ret_num * sizeof(value_t)); + } + } + } + else { + DEBUG("utils_cache: uc_get_value_by_name: No such value: %s", name); + status = -1; + } + + pthread_mutex_unlock(&cache_lock); + + if (status == 0) { + *ret_values = ret; + *ret_values_num = ret_num; + } + + return (status); +} /* int uc_get_value_by_name */ + +value_t *uc_get_value(const data_set_t *ds, const value_list_t *vl) { + char name[6 * DATA_MAX_NAME_LEN]; + value_t *ret = NULL; + size_t ret_num = 0; + int status; + + if (FORMAT_VL(name, sizeof(name), vl) != 0) { + ERROR("utils_cache: uc_get_value: FORMAT_VL failed."); + return (NULL); + } + + status = uc_get_value_by_name(name, &ret, &ret_num); + if (status != 0) + return (NULL); + + /* This is important - the caller has no other way of knowing how many + * values are returned. */ + if (ret_num != (size_t) ds->ds_num) { + ERROR("utils_cache: uc_get_value: ds[%s] has %zu values, " + "but uc_get_value_by_name returned %zu.", ds->type, ds->ds_num, + ret_num); + sfree(ret); + return (NULL); + } + + return (ret); +} /* value_t *uc_get_value */ + size_t uc_get_size(void) { size_t size_arrays = 0; diff --git a/src/daemon/utils_cache.h b/src/daemon/utils_cache.h index 24c58ff77c..8ba7133ab2 100644 --- a/src/daemon/utils_cache.h +++ b/src/daemon/utils_cache.h @@ -42,6 +42,8 @@ int uc_update(const data_set_t *ds, const value_list_t *vl); int uc_get_rate_by_name(const char *name, gauge_t **ret_values, size_t *ret_values_num); gauge_t *uc_get_rate(const data_set_t *ds, const value_list_t *vl); +int uc_get_value_by_name(const char *name, value_t **ret_values, size_t *ret_values_num); +value_t *uc_get_value(const data_set_t *ds, const value_list_t *vl); size_t uc_get_size(void); int uc_get_names(char ***ret_names, cdtime_t **ret_times, size_t *ret_number); diff --git a/src/snmp_agent.c b/src/snmp_agent.c new file mode 100644 index 0000000000..4b963d0046 --- /dev/null +++ b/src/snmp_agent.c @@ -0,0 +1,1509 @@ +/** + * collectd - src/snmp_agent.c + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Roman Korynkevych + * Serhiy Pshyk + **/ + +#include "collectd.h" +#include "common.h" +#include "utils_avltree.h" +#include "utils_llist.h" +#include "utils_cache.h" + +#include +#include +#include + +#define PLUGIN_NAME "snmp_agent" +#define ERR_BUF_SIZE 1024 +#define TYPE_STRING -1 + +struct oid_s { + oid oid[MAX_OID_LEN]; + size_t oid_len; + u_char type; +}; +typedef struct oid_s oid_t; + +struct table_definition_s { + char *name; + oid_t index_oid; + oid_t size_oid; + llist_t *columns; + c_avl_tree_t *instance_index; + c_avl_tree_t *index_instance; +}; +typedef struct table_definition_s table_definition_t; + +struct data_definition_s { + char *name; + char *plugin; + char *plugin_instance; + char *type; + char *type_instance; + table_definition_t *table; + _Bool is_instance; + oid_t *oids; + size_t oids_len; + double scale; + double shift; +}; +typedef struct data_definition_s data_definition_t; + +struct snmp_agent_ctx_s { + pthread_t thread; + pthread_mutex_t lock; + pthread_mutex_t agentx_lock; + struct tree *tp; + + llist_t *tables; + llist_t *scalars; +}; +typedef struct snmp_agent_ctx_s snmp_agent_ctx_t; + +snmp_agent_ctx_t *g_agent = NULL; + +#define CHECK_DD_TYPE(_dd, _p, _pi, _t, _ti) \ + (_dd->plugin ? !strcmp(_dd->plugin, _p) : 0) && \ + (_dd->plugin_instance ? !strcmp(_dd->plugin_instance, _pi) : 1) && \ + (_dd->type ? !strcmp(_dd->type, _t) : 1) && \ + (_dd->type_instance ? !strcmp(_dd->type_instance, _ti) : 1) + +static void *snmp_agent_thread_run(void *arg); +static int snmp_agent_register_oid(oid_t *oid, Netsnmp_Node_Handler *handler); +static int snmp_agent_set_vardata(void *dst_buf, size_t *dst_buf_len, + u_char asn_type, double scale, double shift, + const void *value, size_t len, int type); +static int snmp_agent_unregister_oid_index(oid_t *oid, int index); + +static u_char snmp_agent_get_asn_type(oid *oid, size_t oid_len) { + struct tree *node = get_tree(oid, oid_len, g_agent->tp); + + return (node != NULL ? mib_to_asn_type(node->type) : 0); +} + +static char *snmp_agent_get_oid_name(oid *oid, size_t oid_len) { + struct tree *node = get_tree(oid, oid_len, g_agent->tp); + + return (node != NULL ? node->label : NULL); +} + +static int snmp_agent_oid_to_string(char *buf, size_t buf_size, + oid_t const *o) { + char oid_str[MAX_OID_LEN][16]; + char *oid_str_ptr[MAX_OID_LEN]; + + for (size_t i = 0; i < o->oid_len; i++) { + ssnprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]); + oid_str_ptr[i] = oid_str[i]; + } + + return (strjoin(buf, buf_size, oid_str_ptr, o->oid_len, ".")); +} + +static void snmp_agent_dump_data(void) { +#if COLLECT_DEBUG + char temp[DATA_MAX_NAME_LEN]; + + for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { + table_definition_t *td = (table_definition_t *)te->value; + + DEBUG(PLUGIN_NAME ": Table:"); + DEBUG(PLUGIN_NAME ": Name: %s", td->name); + if (td->index_oid.oid_len != 0) { + snmp_agent_oid_to_string(temp, sizeof(temp), &td->index_oid); + DEBUG(PLUGIN_NAME ": IndexOID: %s", temp); + } + if (td->size_oid.oid_len != 0) { + snmp_agent_oid_to_string(temp, sizeof(temp), &td->size_oid); + DEBUG(PLUGIN_NAME ": SizeOID: %s", temp); + } + + for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { + data_definition_t *dd = (data_definition_t *)de->value; + + DEBUG(PLUGIN_NAME ": Column:"); + DEBUG(PLUGIN_NAME ": Name: %s", dd->name); + if (dd->plugin) + DEBUG(PLUGIN_NAME ": Plugin: %s", dd->plugin); + if (dd->plugin_instance) + DEBUG(PLUGIN_NAME ": PluginInstance: %s", dd->plugin_instance); + if (dd->is_instance) + DEBUG(PLUGIN_NAME ": Instance: true"); + if (dd->type) + DEBUG(PLUGIN_NAME ": Type: %s", dd->type); + if (dd->type_instance) + DEBUG(PLUGIN_NAME ": TypeInstance: %s", dd->type_instance); + for (int i = 0; i < dd->oids_len; i++) { + snmp_agent_oid_to_string(temp, sizeof(temp), &dd->oids[i]); + DEBUG(PLUGIN_NAME ": OID[%d]: %s", i, temp); + } + DEBUG(PLUGIN_NAME ": Scale: %g", dd->scale); + DEBUG(PLUGIN_NAME ": Shift: %g", dd->shift); + } + } + + for (llentry_t *e = llist_head(g_agent->scalars); e != NULL; e = e->next) { + data_definition_t *dd = (data_definition_t *)e->value; + + DEBUG(PLUGIN_NAME ": Scalar:"); + DEBUG(PLUGIN_NAME ": Name: %s", dd->name); + if (dd->plugin) + DEBUG(PLUGIN_NAME ": Plugin: %s", dd->plugin); + if (dd->plugin_instance) + DEBUG(PLUGIN_NAME ": PluginInstance: %s", dd->plugin_instance); + if (dd->is_instance) + DEBUG(PLUGIN_NAME ": Instance: true"); + if (dd->type) + DEBUG(PLUGIN_NAME ": Type: %s", dd->type); + if (dd->type_instance) + DEBUG(PLUGIN_NAME ": TypeInstance: %s", dd->type_instance); + for (int i = 0; i < dd->oids_len; i++) { + snmp_agent_oid_to_string(temp, sizeof(temp), &dd->oids[i]); + DEBUG(PLUGIN_NAME ": OID[%d]: %s", i, temp); + } + DEBUG(PLUGIN_NAME ": Scale: %g", dd->scale); + DEBUG(PLUGIN_NAME ": Shift: %g", dd->shift); + } +#endif /* COLLECT_DEBUG */ +} + +static int snmp_agent_validate_data(void) { + + snmp_agent_dump_data(); + + for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { + table_definition_t *td = (table_definition_t *)te->value; + + for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { + data_definition_t *dd = (data_definition_t *)de->value; + + if (!dd->plugin) { + ERROR(PLUGIN_NAME ": Plugin not defined for '%s'.'%s'", td->name, + dd->name); + return (-EINVAL); + } + + if (dd->plugin_instance) { + ERROR(PLUGIN_NAME ": PluginInstance should not be defined for table " + "data type '%s'.'%s'", + td->name, dd->name); + return (-EINVAL); + } + + if (dd->oids_len == 0) { + ERROR(PLUGIN_NAME ": No OIDs defined for '%s'.'%s'", td->name, + dd->name); + return (-EINVAL); + } + + if (dd->is_instance) { + + if (dd->type || dd->type_instance) { + ERROR(PLUGIN_NAME ": Type and TypeInstance are not valid for " + "instance data '%s'.'%s'", + td->name, dd->name); + return (-EINVAL); + } + + if (dd->oids_len > 1) { + ERROR( + PLUGIN_NAME + ": Only one OID should be specified for instance data '%s'.'%s'", + td->name, dd->name); + return (-EINVAL); + } + } else { + + if (!dd->type) { + ERROR(PLUGIN_NAME ": Type not defined for data '%s'.'%s'", td->name, + dd->name); + return (-EINVAL); + } + } + } + } + + for (llentry_t *e = llist_head(g_agent->scalars); e != NULL; e = e->next) { + data_definition_t *dd = (data_definition_t *)e->value; + + if (!dd->plugin) { + ERROR(PLUGIN_NAME ": Plugin not defined for '%s'", dd->name); + return (-EINVAL); + } + + if (dd->oids_len == 0) { + ERROR(PLUGIN_NAME ": No OIDs defined for '%s'", dd->name); + return (-EINVAL); + } + + if (dd->is_instance) { + ERROR(PLUGIN_NAME + ": Instance flag can't be specified for scalar data '%s'", + dd->name); + return (-EINVAL); + } + + if (!dd->type) { + ERROR(PLUGIN_NAME ": Type not defined for data '%s'", dd->name); + return (-EINVAL); + } + } + + return (0); +} + +static int snmp_agent_table_row_remove(table_definition_t *td, + const char *instance) { + int *index; + char *ins; + + if ((c_avl_get(td->instance_index, instance, (void**) &index) != 0) || + (c_avl_get(td->index_instance, index, (void**) &ins) != 0)) + return (0); + + pthread_mutex_lock(&g_agent->agentx_lock); + + for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { + data_definition_t *dd = (data_definition_t *)de->value; + + for (int i = 0; i < dd->oids_len; i++) + snmp_agent_unregister_oid_index(&dd->oids[i], *index); + } + + snmp_agent_unregister_oid_index(&td->index_oid, *index); + + pthread_mutex_unlock(&g_agent->agentx_lock); + + DEBUG(PLUGIN_NAME ": Removed row for '%s' table [%d, %s].", td->name, *index, + ins); + + notification_t n = {NOTIF_WARNING, cdtime(), "", "", PLUGIN_NAME, "", "", "", + NULL}; + sstrncpy(n.host, hostname_g, sizeof(n.host)); + sstrncpy(n.plugin_instance, ins, sizeof(n.plugin_instance)); + ssnprintf(n.message, sizeof(n.message), + "Removed data row from table %s instance %s index %d", td->name, + ins, *index); + plugin_dispatch_notification(&n); + + c_avl_remove(td->index_instance, index, NULL, (void**) &ins); + c_avl_remove(td->instance_index, instance, NULL, (void**) &index); + sfree(index); + sfree(ins); + + return (0); +} + +static int snmp_agent_clear_missing(const value_list_t *vl, + __attribute__((unused)) user_data_t *ud) { + if (vl == NULL) + return (-EINVAL); + + for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { + table_definition_t *td = (table_definition_t *)te->value; + + for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { + data_definition_t *dd = (data_definition_t *)de->value; + + if (!dd->is_instance) { + if (CHECK_DD_TYPE(dd, vl->plugin, vl->plugin_instance, vl->type, + vl->type_instance)) { + snmp_agent_table_row_remove(td, vl->plugin_instance); + return (0); + } + } + } + } + + return (0); +} + +static void snmp_agent_free_data(data_definition_t **dd) { + + if (dd == NULL || *dd == NULL) + return; + + /* unregister scalar type OID */ + if ((*dd)->table == NULL) { + for (int i = 0; i < (*dd)->oids_len; i++) + unregister_mib((*dd)->oids[i].oid, (*dd)->oids[i].oid_len); + } else { + /* unregister all table OIDs */ + int *index; + char *value; + + c_avl_iterator_t *iter = c_avl_get_iterator((*dd)->table->index_instance); + while (c_avl_iterator_next(iter, (void *)&index, (void *)&value) == 0) { + for (int i = 0; i < (*dd)->oids_len; i++) + snmp_agent_unregister_oid_index(&(*dd)->oids[i], *index); + } + c_avl_iterator_destroy(iter); + } + + sfree((*dd)->name); + sfree((*dd)->plugin); + sfree((*dd)->plugin_instance); + sfree((*dd)->type); + sfree((*dd)->type_instance); + sfree((*dd)->oids); + + sfree(*dd); + + return; +} + +static void snmp_agent_free_table(table_definition_t **td) { + + if (td == NULL || *td == NULL) + return; + + if ((*td)->size_oid.oid_len) + unregister_mib((*td)->size_oid.oid, (*td)->size_oid.oid_len); + + if ((*td)->index_oid.oid_len) { + int *index; + char *value; + + c_avl_iterator_t *iter = c_avl_get_iterator((*td)->index_instance); + while (c_avl_iterator_next(iter, (void *)&index, (void *)&value) == 0) + snmp_agent_unregister_oid_index(&(*td)->index_oid, *index); + + c_avl_iterator_destroy(iter); + } + + for (llentry_t *de = llist_head((*td)->columns); de != NULL; de = de->next) { + data_definition_t *dd = (data_definition_t *)de->value; + snmp_agent_free_data(&dd); + } + + llist_destroy((*td)->columns); + + void *key = NULL; + void *value = NULL; + + c_avl_destroy((*td)->index_instance); + (*td)->index_instance = NULL; + + while (c_avl_pick((*td)->instance_index, &key, &value) == 0) { + sfree(key); + sfree(value); + } + c_avl_destroy((*td)->instance_index); + (*td)->instance_index = NULL; + + sfree((*td)->name); + sfree(*td); + + return; +} + +static int +snmp_agent_table_oid_handler(struct netsnmp_mib_handler_s *handler, + struct netsnmp_handler_registration_s *reginfo, + struct netsnmp_agent_request_info_s *reqinfo, + struct netsnmp_request_info_s *requests) { + + if (reqinfo->mode != MODE_GET && reqinfo->mode != MODE_GETNEXT) { + DEBUG(PLUGIN_NAME ": Not supported request mode (%d).", reqinfo->mode); + return SNMP_ERR_NOERROR; + } + + oid_t oid; + char temp[DATA_MAX_NAME_LEN]; + + pthread_mutex_lock(&g_agent->lock); + + memcpy(oid.oid, requests->requestvb->name, + sizeof(oid.oid[0]) * requests->requestvb->name_length); + oid.oid_len = requests->requestvb->name_length; + + snmp_agent_oid_to_string(temp, sizeof(temp), &oid); + + DEBUG(PLUGIN_NAME ": Get request received for table OID '%s'.", temp); + + for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { + table_definition_t *td = (table_definition_t *)te->value; + + for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { + data_definition_t *dd = (data_definition_t *)de->value; + + for (int i = 0; i < dd->oids_len; i++) { + + int ret = snmp_oid_ncompare(oid.oid, oid.oid_len, + dd->oids[i].oid, dd->oids[i].oid_len, + MIN(oid.oid_len, dd->oids[i].oid_len)); + if (ret != 0) continue; + + if (td->index_oid.oid_len) { + int index = oid.oid[oid.oid_len - 1]; + char *instance; + + ret = c_avl_get(td->index_instance, &index, (void **)&instance); + if (ret != 0) { + DEBUG(PLUGIN_NAME ": Nonexisting index '%d' requested.", index); + pthread_mutex_unlock(&g_agent->lock); + return SNMP_NOSUCHINSTANCE; + } + + if (dd->is_instance) { + + requests->requestvb->type = ASN_OCTET_STR; + snmp_set_var_typed_value(requests->requestvb, + requests->requestvb->type, instance, + strlen((instance))); + + pthread_mutex_unlock(&g_agent->lock); + + return SNMP_ERR_NOERROR; + } + + format_name(temp, sizeof(temp), hostname_g, dd->plugin, instance, + dd->type, dd->type_instance); + DEBUG(PLUGIN_NAME ": Identifier '%s'", temp); + + value_t *values; + size_t values_num; + const data_set_t *ds; + + ds = plugin_get_ds(dd->type); + if (ds == NULL) { + DEBUG(PLUGIN_NAME ": Data set not found for '%s' type.", dd->type); + pthread_mutex_unlock(&g_agent->lock); + return SNMP_NOSUCHINSTANCE; + } + + ret = uc_get_value_by_name(temp, &values, &values_num); + + if (ret != 0) { + ERROR(PLUGIN_NAME ": Failed to get value for '%s'.", temp); + pthread_mutex_unlock(&g_agent->lock); + return SNMP_NOSUCHINSTANCE; + } + + assert(ds->ds_num == values_num); + assert(i < values_num); + + char data[DATA_MAX_NAME_LEN]; + size_t data_len = sizeof(data); + ret = snmp_agent_set_vardata(data, &data_len, dd->oids[i].type, + dd->scale, dd->shift, &values[i], + sizeof(values[i]), ds->ds[i].type); + + sfree(values); + values_num = 0; + + if (ret != 0) { + ERROR(PLUGIN_NAME ": Failed to convert '%s' value to snmp data.", + temp); + pthread_mutex_unlock(&g_agent->lock); + return SNMP_NOSUCHINSTANCE; + } + + requests->requestvb->type = dd->oids[i].type; + snmp_set_var_typed_value(requests->requestvb, + requests->requestvb->type, data, data_len); + + pthread_mutex_unlock(&g_agent->lock); + + return SNMP_ERR_NOERROR; + + } else { + DEBUG(PLUGIN_NAME ": %s:%d NOT IMPLEMENTED.", __FUNCTION__, __LINE__); + } + } + } + } + + pthread_mutex_unlock(&g_agent->lock); + + return SNMP_NOSUCHINSTANCE; +} + +static int +snmp_agent_table_index_oid_handler(struct netsnmp_mib_handler_s *handler, + struct netsnmp_handler_registration_s *reginfo, + struct netsnmp_agent_request_info_s *reqinfo, + struct netsnmp_request_info_s *requests) { + + if (reqinfo->mode != MODE_GET && reqinfo->mode != MODE_GETNEXT) { + DEBUG(PLUGIN_NAME ": Not supported request mode (%d).", reqinfo->mode); + return SNMP_ERR_NOERROR; + } + + oid_t oid; + + pthread_mutex_lock(&g_agent->lock); + + memcpy(oid.oid, requests->requestvb->name, + sizeof(oid.oid[0]) * requests->requestvb->name_length); + oid.oid_len = requests->requestvb->name_length; + + for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { + table_definition_t *td = (table_definition_t *)te->value; + + if (td->index_oid.oid_len && + (snmp_oid_ncompare(oid.oid, oid.oid_len, td->index_oid.oid, + td->index_oid.oid_len, + MIN(oid.oid_len, td->index_oid.oid_len)) == 0)) { + + DEBUG(PLUGIN_NAME ": Handle '%s' table index OID.", td->name); + + int index = oid.oid[oid.oid_len - 1]; + char *instance; + + int ret = c_avl_get(td->index_instance, &index, (void **)&instance); + if (ret != 0) { + /* nonexisting index requested */ + pthread_mutex_unlock(&g_agent->lock); + return SNMP_NOSUCHINSTANCE; + } + + requests->requestvb->type = ASN_INTEGER; + snmp_set_var_typed_value(requests->requestvb, requests->requestvb->type, + &index, sizeof(index)); + + pthread_mutex_unlock(&g_agent->lock); + + return SNMP_ERR_NOERROR; + } + } + + pthread_mutex_unlock(&g_agent->lock); + + return SNMP_NOSUCHINSTANCE; +} + +static int +snmp_agent_table_size_oid_handler(struct netsnmp_mib_handler_s *handler, + struct netsnmp_handler_registration_s *reginfo, + struct netsnmp_agent_request_info_s *reqinfo, + struct netsnmp_request_info_s *requests) { + + if (reqinfo->mode != MODE_GET && reqinfo->mode != MODE_GETNEXT) { + DEBUG(PLUGIN_NAME ": Not supported request mode (%d).", reqinfo->mode); + return SNMP_ERR_NOERROR; + } + + oid_t oid; + + pthread_mutex_lock(&g_agent->lock); + + memcpy(oid.oid, requests->requestvb->name, + sizeof(oid.oid[0]) * requests->requestvb->name_length); + oid.oid_len = requests->requestvb->name_length; + + DEBUG(PLUGIN_NAME ": Get request received for table size OID."); + + for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { + table_definition_t *td = (table_definition_t *)te->value; + + if (td->size_oid.oid_len && + (snmp_oid_ncompare(oid.oid, oid.oid_len, td->size_oid.oid, + td->size_oid.oid_len, + MIN(oid.oid_len, td->size_oid.oid_len)) == 0)) { + DEBUG(PLUGIN_NAME ": Handle '%s' table size OID.", td->name); + + long size = c_avl_size(td->index_instance); + + requests->requestvb->type = td->size_oid.type; + snmp_set_var_typed_value(requests->requestvb, requests->requestvb->type, + &size, sizeof(size)); + + pthread_mutex_unlock(&g_agent->lock); + + return SNMP_ERR_NOERROR; + } + } + + pthread_mutex_unlock(&g_agent->lock); + + return SNMP_NOSUCHINSTANCE; +} + + +static int +snmp_agent_scalar_oid_handler(struct netsnmp_mib_handler_s *handler, + struct netsnmp_handler_registration_s *reginfo, + struct netsnmp_agent_request_info_s *reqinfo, + struct netsnmp_request_info_s *requests) { + + if (reqinfo->mode != MODE_GET && reqinfo->mode != MODE_GETNEXT) { + DEBUG(PLUGIN_NAME ": Not supported request mode (%d).", reqinfo->mode); + return SNMP_ERR_NOERROR; + } + + int ret; + oid_t oid; + char temp[DATA_MAX_NAME_LEN]; + + pthread_mutex_lock(&g_agent->lock); + + memcpy(oid.oid, requests->requestvb->name, + sizeof(oid.oid[0]) * requests->requestvb->name_length); + oid.oid_len = requests->requestvb->name_length; + + snmp_agent_oid_to_string(temp, sizeof(temp), &oid); + + DEBUG(PLUGIN_NAME ": Get request received for scalar OID '%s'.", temp); + + for (llentry_t *de = llist_head(g_agent->scalars); de != NULL; de = de->next) { + data_definition_t *dd = (data_definition_t *)de->value; + + for (int i = 0; i < dd->oids_len; i++) { + + ret = snmp_oid_compare(oid.oid, oid.oid_len, + dd->oids[i].oid, dd->oids[i].oid_len); + if (ret != 0) continue; + + format_name(temp, sizeof(temp), hostname_g, dd->plugin, + dd->plugin_instance, dd->type, dd->type_instance); + DEBUG(PLUGIN_NAME ": Identifier '%s'", temp); + + value_t *values; + size_t values_num; + const data_set_t *ds; + + ds = plugin_get_ds(dd->type); + if (ds == NULL) { + DEBUG(PLUGIN_NAME ": Data set not found for '%s' type", dd->type); + pthread_mutex_unlock(&g_agent->lock); + return SNMP_NOSUCHINSTANCE; + } + + ret = uc_get_value_by_name(temp, &values, &values_num); + + if (ret != 0) { + ERROR(PLUGIN_NAME ": Failed to get value for '%s'.", temp); + pthread_mutex_unlock(&g_agent->lock); + return SNMP_NOSUCHINSTANCE; + } + + assert(ds->ds_num == values_num); + assert(i < values_num); + + char data[DATA_MAX_NAME_LEN]; + size_t data_len = sizeof(data); + ret = snmp_agent_set_vardata(data, &data_len, dd->oids[i].type, + dd->scale, dd->shift, &values[i], + sizeof(values[i]), ds->ds[i].type); + + sfree(values); + values_num = 0; + + if (ret != 0) { + ERROR(PLUGIN_NAME ": Failed to convert '%s' value to snmp data.", temp); + pthread_mutex_unlock(&g_agent->lock); + return SNMP_NOSUCHINSTANCE; + } + + requests->requestvb->type = dd->oids[i].type; + snmp_set_var_typed_value(requests->requestvb, requests->requestvb->type, + data, data_len); + + pthread_mutex_unlock(&g_agent->lock); + + return SNMP_ERR_NOERROR; + } + } + + pthread_mutex_unlock(&g_agent->lock); + + return SNMP_NOSUCHINSTANCE; +} + +static int snmp_agent_register_table_oids(void) { + + for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { + table_definition_t *td = (table_definition_t *)te->value; + + if (td->size_oid.oid_len != 0) { + td->size_oid.type = + snmp_agent_get_asn_type(td->size_oid.oid, td->size_oid.oid_len); + td->size_oid.oid_len++; + int ret = snmp_agent_register_oid(&td->size_oid, + snmp_agent_table_size_oid_handler); + if (ret != 0) + return ret; + } + + for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { + data_definition_t *dd = (data_definition_t *)de->value; + + for (int i = 0; i < dd->oids_len; i++) { + dd->oids[i].type = + snmp_agent_get_asn_type(dd->oids[i].oid, dd->oids[i].oid_len); + } + } + } + + return (0); +} + +static int snmp_agent_register_scalar_oids(void) { + + for (llentry_t *e = llist_head(g_agent->scalars); e != NULL; e = e->next) { + data_definition_t *dd = (data_definition_t *)e->value; + + for (int i = 0; i < dd->oids_len; i++) { + + dd->oids[i].type = + snmp_agent_get_asn_type(dd->oids[i].oid, dd->oids[i].oid_len); + + int ret = + snmp_agent_register_oid(&dd->oids[i], snmp_agent_scalar_oid_handler); + if (ret != 0) + return ret; + } + } + + return (0); +} + +static int snmp_agent_config_data_oids(data_definition_t *dd, + oconfig_item_t *ci) { + if (ci->values_num < 1) { + WARNING(PLUGIN_NAME ": `OIDs' needs at least one argument."); + return (-EINVAL); + } + + for (int i = 0; i < ci->values_num; i++) + if (ci->values[i].type != OCONFIG_TYPE_STRING) { + WARNING(PLUGIN_NAME ": `OIDs' needs only string argument."); + return (-EINVAL); + } + + if (dd->oids != NULL) + sfree(dd->oids); + dd->oids_len = 0; + dd->oids = calloc(ci->values_num, sizeof(*dd->oids)); + if (dd->oids == NULL) + return (-ENOMEM); + dd->oids_len = (size_t)ci->values_num; + + for (int i = 0; i < ci->values_num; i++) { + dd->oids[i].oid_len = MAX_OID_LEN; + + if (NULL == snmp_parse_oid(ci->values[i].value.string, dd->oids[i].oid, + &dd->oids[i].oid_len)) { + ERROR(PLUGIN_NAME ": snmp_parse_oid (%s) failed.", + ci->values[i].value.string); + sfree(dd->oids); + dd->oids_len = 0; + return (-1); + } + } + + return (0); +} + +static int snmp_agent_config_table_size_oid(table_definition_t *td, + oconfig_item_t *ci) { + if (ci->values_num < 1) { + WARNING(PLUGIN_NAME ": `TableSizeOID' is empty."); + return (-EINVAL); + } + + if (ci->values[0].type != OCONFIG_TYPE_STRING) { + WARNING(PLUGIN_NAME ": `TableSizeOID' needs only string argument."); + return (-EINVAL); + } + + td->size_oid.oid_len = MAX_OID_LEN; + + if (NULL == snmp_parse_oid(ci->values[0].value.string, td->size_oid.oid, + &td->size_oid.oid_len)) { + ERROR(PLUGIN_NAME ": Failed to parse table size OID (%s)", + ci->values[0].value.string); + td->size_oid.oid_len = 0; + return (-EINVAL); + } + + return (0); +} + +static int snmp_agent_config_table_index_oid(table_definition_t *td, + oconfig_item_t *ci) { + + if (ci->values_num < 1) { + WARNING(PLUGIN_NAME ": `IndexOID' is empty."); + return (-EINVAL); + } + + if (ci->values[0].type != OCONFIG_TYPE_STRING) { + WARNING(PLUGIN_NAME ": `IndexOID' needs only string argument."); + return (-EINVAL); + } + + td->index_oid.oid_len = MAX_OID_LEN; + + if (NULL == snmp_parse_oid(ci->values[0].value.string, td->index_oid.oid, + &td->index_oid.oid_len)) { + ERROR(PLUGIN_NAME ": Failed to parse table index OID (%s)", + ci->values[0].value.string); + td->index_oid.oid_len = 0; + return (-EINVAL); + } + + return (0); +} + +static int snmp_agent_config_table_data(table_definition_t *td, + oconfig_item_t *ci) { + data_definition_t *dd; + int ret = 0; + + assert(ci != NULL); + + dd = calloc(1, sizeof(*dd)); + if (dd == NULL) { + ERROR(PLUGIN_NAME ": Failed to allocate memory for table data definition"); + return (-ENOMEM); + } + + ret = cf_util_get_string(ci, &dd->name); + if (ret != 0) { + sfree(dd); + return (-1); + } + + dd->scale = 1.0; + dd->shift = 0.0; + + dd->table = td; + + for (int i = 0; i < ci->children_num; i++) { + oconfig_item_t *option = ci->children + i; + + if (strcasecmp("Instance", option->key) == 0) + ret = cf_util_get_boolean(option, &dd->is_instance); + else if (strcasecmp("Plugin", option->key) == 0) + ret = cf_util_get_string(option, &dd->plugin); + else if (strcasecmp("PluginInstance", option->key) == 0) + ret = cf_util_get_string(option, &dd->plugin_instance); + else if (strcasecmp("Type", option->key) == 0) + ret = cf_util_get_string(option, &dd->type); + else if (strcasecmp("TypeInstance", option->key) == 0) + ret = cf_util_get_string(option, &dd->type_instance); + else if (strcasecmp("Shift", option->key) == 0) + ret = cf_util_get_double(option, &dd->shift); + else if (strcasecmp("Scale", option->key) == 0) + ret = cf_util_get_double(option, &dd->scale); + else if (strcasecmp("OIDs", option->key) == 0) + ret = snmp_agent_config_data_oids(dd, option); + else { + WARNING(PLUGIN_NAME ": Option `%s' not allowed here.", option->key); + ret = -1; + } + + if (ret != 0) { + snmp_agent_free_data(&dd); + return (-1); + } + } + + llentry_t *entry = llentry_create(dd->name, dd); + if (entry == NULL) { + snmp_agent_free_data(&dd); + return (-ENOMEM); + } + + llist_append(td->columns, entry); + + return (0); +} + +static int snmp_agent_config_data(oconfig_item_t *ci) { + data_definition_t *dd; + int ret = 0; + + assert(ci != NULL); + + dd = calloc(1, sizeof(*dd)); + if (dd == NULL) { + ERROR(PLUGIN_NAME ": Failed to allocate memory for data definition"); + return (-ENOMEM); + } + + ret = cf_util_get_string(ci, &dd->name); + if (ret != 0) { + free(dd); + return (-1); + } + + dd->scale = 1.0; + dd->shift = 0.0; + + for (int i = 0; i < ci->children_num; i++) { + oconfig_item_t *option = ci->children + i; + + if (strcasecmp("Instance", option->key) == 0) + ret = cf_util_get_boolean(option, &dd->is_instance); + else if (strcasecmp("Plugin", option->key) == 0) + ret = cf_util_get_string(option, &dd->plugin); + else if (strcasecmp("PluginInstance", option->key) == 0) + ret = cf_util_get_string(option, &dd->plugin_instance); + else if (strcasecmp("Type", option->key) == 0) + ret = cf_util_get_string(option, &dd->type); + else if (strcasecmp("TypeInstance", option->key) == 0) + ret = cf_util_get_string(option, &dd->type_instance); + else if (strcasecmp("Shift", option->key) == 0) + ret = cf_util_get_double(option, &dd->shift); + else if (strcasecmp("Scale", option->key) == 0) + ret = cf_util_get_double(option, &dd->scale); + else if (strcasecmp("OIDs", option->key) == 0) + ret = snmp_agent_config_data_oids(dd, option); + else { + WARNING(PLUGIN_NAME ": Option `%s' not allowed here.", option->key); + ret = -1; + } + + if (ret != 0) { + snmp_agent_free_data(&dd); + return (-1); + } + } + + llentry_t *entry = llentry_create(dd->name, dd); + if (entry == NULL) { + snmp_agent_free_data(&dd); + return (-ENOMEM); + } + + llist_append(g_agent->scalars, entry); + + return (0); +} + +static int num_compare(const int *a, const int *b) { + assert((a != NULL) && (b != NULL)); + if (*a < *b) + return (-1); + else if (*a > *b) + return (1); + else + return (0); +} + +static int snmp_agent_config_table(oconfig_item_t *ci) { + table_definition_t *td; + int ret = 0; + + assert(ci != NULL); + + td = calloc(1, sizeof(*td)); + if (td == NULL) { + ERROR(PLUGIN_NAME ": Failed to allocate memory for table definition."); + return (-ENOMEM); + } + + ret = cf_util_get_string(ci, &td->name); + if (ret != 0) { + sfree(td); + return (-1); + } + + td->columns = llist_create(); + if (td->columns == NULL) { + ERROR(PLUGIN_NAME ": Failed to allocate memory for columns list."); + snmp_agent_free_table(&td); + return (-ENOMEM); + } + + for (int i = 0; i < ci->children_num; i++) { + oconfig_item_t *option = ci->children + i; + + if (strcasecmp("IndexOID", option->key) == 0) + ret = snmp_agent_config_table_index_oid(td, option); + else if (strcasecmp("SizeOID", option->key) == 0) + ret = snmp_agent_config_table_size_oid(td, option); + else if (strcasecmp("Data", option->key) == 0) + ret = snmp_agent_config_table_data(td, option); + else { + WARNING(PLUGIN_NAME ": Option `%s' not allowed here.", option->key); + ret = -1; + } + + if (ret != 0) { + snmp_agent_free_table(&td); + return (-ENOMEM); + } + } + + llentry_t *entry = llentry_create(td->name, td); + if (entry == NULL) { + snmp_agent_free_table(&td); + return (-ENOMEM); + } + + td->instance_index = + c_avl_create((int (*)(const void *, const void *))strcmp); + if (td->instance_index == NULL) { + snmp_agent_free_table(&td); + return (-ENOMEM); + } + + td->index_instance = + c_avl_create((int (*)(const void *, const void *))num_compare); + if (td->index_instance == NULL) { + snmp_agent_free_table(&td); + return (-ENOMEM); + } + + llist_append(g_agent->tables, entry); + + return (0); +} + +static int snmp_agent_get_value_from_ds_type(const value_t *val, int type, + double scale, double shift, + long *value) { + switch (type) { + case DS_TYPE_COUNTER: + *value = (long)((val->counter * scale) + shift); + break; + case DS_TYPE_ABSOLUTE: + *value = (long)((val->absolute * scale) + shift); + break; + case DS_TYPE_DERIVE: + *value = (long)((val->derive * scale) + shift); + break; + case DS_TYPE_GAUGE: + *value = (long)((val->gauge * scale) + shift); + break; + case TYPE_STRING: + break; + default: + ERROR(PLUGIN_NAME ": Unknown data source type: %i.", type); + return (-EINVAL); + } + + return (0); +} + +static int snmp_agent_set_vardata(void *data, size_t *data_len, u_char asn_type, + double scale, double shift, const void *value, + size_t len, int type) { + + int ret; + netsnmp_vardata var; + const value_t *val; + long new_value = 0; + + val = value; + var.string = (u_char *)data; + + ret = snmp_agent_get_value_from_ds_type(val, type, scale, shift, &new_value); + if (ret != 0) + return ret; + + switch (asn_type) { + case ASN_INTEGER: + case ASN_UINTEGER: + case ASN_COUNTER: + case ASN_TIMETICKS: + case ASN_GAUGE: + if (*data_len < sizeof(*var.integer)) + return (-EINVAL); + *var.integer = new_value; + *data_len = sizeof(*var.integer); + break; + case ASN_COUNTER64: + if (*data_len < sizeof(*var.counter64)) + return (-EINVAL); + var.counter64->high = (u_long)((int64_t)new_value >> 32); + var.counter64->low = (u_long)((int64_t)new_value & 0xFFFFFFFF); + *data_len = sizeof(*var.counter64); + break; + case ASN_OCTET_STR: + if (type == DS_TYPE_GAUGE) { + char buf[DATA_MAX_NAME_LEN]; + snprintf(buf, sizeof(buf), "%.2f", val->gauge); + if (*data_len < strlen(buf)) + return (-EINVAL); + *data_len = strlen(buf); + memcpy(var.string, buf, *data_len); + } else { + ERROR(PLUGIN_NAME ": Failed to convert %d ds type to %d asn type.", type, + asn_type); + return (-EINVAL); + } + break; + default: + ERROR(PLUGIN_NAME ": Failed to convert %d ds type to %d asn type.", type, + asn_type); + return (-EINVAL); + } + + return (0); +} + +static int snmp_agent_register_oid_index(oid_t *oid, int index, + Netsnmp_Node_Handler *handler) { + oid_t new_oid; + memcpy(&new_oid, oid, sizeof(*oid)); + new_oid.oid[new_oid.oid_len++] = index; + return snmp_agent_register_oid(&new_oid, handler); +} + +static int snmp_agent_unregister_oid_index(oid_t *oid, int index) { + oid_t new_oid; + memcpy(&new_oid, oid, sizeof(*oid)); + new_oid.oid[new_oid.oid_len++] = index; + return unregister_mib(new_oid.oid, new_oid.oid_len); +} + +static int snmp_agent_update_index(table_definition_t *td, + const char *instance) { + + if (c_avl_get(td->instance_index, instance, NULL) == 0) + return (0); + + int ret; + int *index; + char *ins; + + ins = strdup(instance); + if (ins == NULL) + return (-ENOMEM); + + index = calloc(1, sizeof(*index)); + if (index == NULL) { + sfree(ins); + return (-ENOMEM); + } + + *index = c_avl_size(td->instance_index) + 1; + + ret = c_avl_insert(td->instance_index, ins, index); + if (ret != 0) { + sfree(ins); + sfree(index); + return ret; + } + + ret = c_avl_insert(td->index_instance, index, ins); + if (ret < 0) { + DEBUG(PLUGIN_NAME ": Failed to update index_instance for '%s' table.", + td->name); + return ret; + } + + DEBUG(PLUGIN_NAME ": Updated index for '%s' table [%d, %s].", td->name, + *index, ins); + + /* need to generate index for the table */ + if (td->index_oid.oid_len) { + + ret = snmp_agent_register_oid_index(&td->index_oid, *index, + snmp_agent_table_index_oid_handler); + if (ret != 0) + return ret; + + /* register new oids for all columns */ + for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { + data_definition_t *dd = (data_definition_t *)de->value; + + for (int i = 0; i < dd->oids_len; i++) { + ret = snmp_agent_register_oid_index(&dd->oids[i], *index, + snmp_agent_table_oid_handler); + if (ret != 0) + return ret; + } + } + } + + notification_t n = {NOTIF_OKAY, cdtime(), "", "", PLUGIN_NAME, "", "", "", + NULL}; + sstrncpy(n.host, hostname_g, sizeof(n.host)); + sstrncpy(n.plugin_instance, ins, sizeof(n.plugin_instance)); + ssnprintf(n.message, sizeof(n.message), + "Data row added to table %s instance %s index %d", td->name, ins, + *index); + plugin_dispatch_notification(&n); + + return (0); +} + +static int snmp_agent_write(value_list_t const *vl) { + + if (vl == NULL) + return (-EINVAL); + + for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { + table_definition_t *td = (table_definition_t *)te->value; + + for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { + data_definition_t *dd = (data_definition_t *)de->value; + + if (!dd->is_instance) { + if (CHECK_DD_TYPE(dd, vl->plugin, vl->plugin_instance, vl->type, + vl->type_instance)) { + snmp_agent_update_index(td, vl->plugin_instance); + return (0); + } + } + } + } + + return (0); +} + +static int snmp_agent_collect(const data_set_t *ds, const value_list_t *vl, + user_data_t __attribute__((unused)) * user_data) { + + pthread_mutex_lock(&g_agent->lock); + + snmp_agent_write(vl); + + pthread_mutex_unlock(&g_agent->lock); + + return (0); +} + +static int snmp_agent_preinit(void) { + if (g_agent != NULL) { + /* already initialized if config callback was called before init callback */ + return (0); + } + + g_agent = calloc(1, sizeof(*g_agent)); + if (g_agent == NULL) { + ERROR(PLUGIN_NAME ": Failed to allocate memory for snmp agent context."); + return (-ENOMEM); + } + + g_agent->tables = llist_create(); + g_agent->scalars = llist_create(); + + int err; + /* make us a agentx client. */ + err = netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, + 1); + if (err != 0) { + ERROR(PLUGIN_NAME ": Failed to set agent role (%d)", err); + return (-1); + } + + /* + * For SNMP debug purposes uses snmp_set_do_debugging(1); + */ + + /* initialize the agent library */ + err = init_agent(PLUGIN_NAME); + if (err != 0) { + ERROR(PLUGIN_NAME ": Failed to initialize the agent library (%d)", err); + return (-1); + } + + init_snmp(PLUGIN_NAME); + + g_agent->tp = read_all_mibs(); + + return (0); +} + +static int snmp_agent_init(void) { + int ret; + + ret = snmp_agent_preinit(); + if (ret != 0) + return ret; + + ret = snmp_agent_register_scalar_oids(); + if (ret != 0) + return ret; + + ret = snmp_agent_register_table_oids(); + if (ret != 0) + return ret; + + /* create a second thread to listen for requests from AgentX*/ + ret = pthread_create(&g_agent->thread, NULL, &snmp_agent_thread_run, NULL); + if (ret != 0) { + ERROR(PLUGIN_NAME ": Failed to create a separate thread, err %u", ret); + return ret; + } + + ret = pthread_mutex_init(&g_agent->lock, NULL); + if (ret != 0) { + ERROR(PLUGIN_NAME ": Failed to initialize mutex, err %u", ret); + return ret; + } + + ret = pthread_mutex_init(&g_agent->agentx_lock, NULL); + if (ret != 0) { + ERROR(PLUGIN_NAME ": Failed to initialize AgentX mutex, err %u", ret); + return ret; + } + + return (0); +} + +static void *snmp_agent_thread_run(void __attribute__((unused)) * arg) { + INFO(PLUGIN_NAME ": Thread is up and running"); + + for (;;) { + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + + pthread_mutex_lock(&g_agent->agentx_lock); + agent_check_and_process(0); /* 0 == don't block */ + pthread_mutex_unlock(&g_agent->agentx_lock); + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + usleep(10); + } + + pthread_exit(0); +} + +static int snmp_agent_register_oid(oid_t *oid, Netsnmp_Node_Handler *handler) { + netsnmp_handler_registration *reg; + char temp[DATA_MAX_NAME_LEN]; + char *oid_name = snmp_agent_get_oid_name(oid->oid, oid->oid_len - 1); + + snmp_agent_oid_to_string(temp, sizeof(temp), oid); + + if (oid_name == NULL) { + WARNING(PLUGIN_NAME + ": Skipped registration: OID (%s) is not found in main tree", temp); + return (0); + } + + reg = netsnmp_create_handler_registration(oid_name, handler, oid->oid, + oid->oid_len, HANDLER_CAN_RONLY); + if (reg == NULL) { + ERROR(PLUGIN_NAME ": Failed to create handler registration for OID (%s)", + temp); + return (-1); + } + + pthread_mutex_lock(&g_agent->agentx_lock); + + if (netsnmp_register_instance(reg) != MIB_REGISTERED_OK) { + ERROR(PLUGIN_NAME ": Failed to register handler for OID (%s)", temp); + pthread_mutex_unlock(&g_agent->agentx_lock); + return (-1); + } + + pthread_mutex_unlock(&g_agent->agentx_lock); + + DEBUG(PLUGIN_NAME ": Registered handler for OID (%s)", temp); + + return (0); +} + +static int snmp_agent_free_config(void) { + + if (g_agent == NULL) + return (-EINVAL); + + for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) + snmp_agent_free_table((table_definition_t **)&te->value); + llist_destroy(g_agent->tables); + + for (llentry_t *de = llist_head(g_agent->scalars); de != NULL; de = de->next) + snmp_agent_free_data((data_definition_t **)&de->value); + llist_destroy(g_agent->scalars); + + return (0); +} + +static int snmp_agent_shutdown(void) { + int ret = 0; + + DEBUG(PLUGIN_NAME ": snmp_agent_shutdown."); + + if (g_agent == NULL) { + ERROR(PLUGIN_NAME ": snmp_agent_shutdown: plugin not initialized."); + return (-EINVAL); + } + + if (pthread_cancel(g_agent->thread) != 0) + ERROR(PLUGIN_NAME ": snmp_agent_shutdown: failed to cancel the thread."); + + if (pthread_join(g_agent->thread, NULL) != 0) + ERROR(PLUGIN_NAME ": snmp_agent_shutdown: failed to join the thread."); + + snmp_agent_free_config(); + + snmp_shutdown(PLUGIN_NAME); + + pthread_mutex_destroy(&g_agent->lock); + pthread_mutex_destroy(&g_agent->agentx_lock); + + sfree(g_agent); + + return ret; +} + +static int snmp_agent_config(oconfig_item_t *ci) { + + int ret = snmp_agent_preinit(); + + if (ret != 0) { + sfree(g_agent); + return (-EINVAL); + } + + for (int i = 0; i < ci->children_num; i++) { + oconfig_item_t *child = ci->children + i; + if (strcasecmp("Data", child->key) == 0) { + ret = snmp_agent_config_data(child); + } else if (strcasecmp("Table", child->key) == 0) { + ret = snmp_agent_config_table(child); + } else { + ERROR(PLUGIN_NAME ": Unknown configuration option `%s'.", child->key); + ret = (-EINVAL); + } + + if (ret != 0) { + ERROR(PLUGIN_NAME ": Failed to parse configuration."); + snmp_agent_free_config(); + snmp_shutdown(PLUGIN_NAME); + sfree(g_agent); + return (-EINVAL); + } + } + + ret = snmp_agent_validate_data(); + if (ret != 0) { + ERROR(PLUGIN_NAME ": Invalid configuration provided."); + snmp_agent_free_config(); + snmp_shutdown(PLUGIN_NAME); + sfree(g_agent); + return (-EINVAL); + } + + return (0); +} + +void module_register(void) { + plugin_register_init(PLUGIN_NAME, snmp_agent_init); + plugin_register_complex_config(PLUGIN_NAME, snmp_agent_config); + plugin_register_write(PLUGIN_NAME, snmp_agent_collect, NULL); + plugin_register_missing(PLUGIN_NAME, snmp_agent_clear_missing, NULL); + plugin_register_shutdown(PLUGIN_NAME, snmp_agent_shutdown); +} From 4fd753b3eb64b5e3130eb10b9783f219b909df2d Mon Sep 17 00:00:00 2001 From: "Korynkevych, RomanX" Date: Wed, 14 Dec 2016 11:11:28 +0000 Subject: [PATCH 02/11] snmp_agent: define MIN macro if not defined. Change-Id: Ic57c14abb8b6b31547e97e6c394b8c3147b1e6b2 Signed-off-by: Korynkevych, RomanX --- src/snmp_agent.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/snmp_agent.c b/src/snmp_agent.c index 4b963d0046..8c7b822884 100644 --- a/src/snmp_agent.c +++ b/src/snmp_agent.c @@ -40,6 +40,10 @@ #define ERR_BUF_SIZE 1024 #define TYPE_STRING -1 +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif + struct oid_s { oid oid[MAX_OID_LEN]; size_t oid_len; From 8ad2f8434b503efed3a63752dc5a447a14eee33c Mon Sep 17 00:00:00 2001 From: "Korynkevych, RomanX" Date: Wed, 14 Dec 2016 17:05:10 +0000 Subject: [PATCH 03/11] snmp_agent: removed references to snmp_agent.h file from Makefile. Change-Id: I697d80d39d8f37d9bd36280bad874a1f4d600518 Signed-off-by: Korynkevych, RomanX --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index d60a78bf92..af849fffd4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1458,7 +1458,7 @@ endif if BUILD_PLUGIN_SNMP_AGENT pkglib_LTLIBRARIES += snmp_agent.la -snmp_agent_la_SOURCES = snmp_agent.c snmp_agent.h +snmp_agent_la_SOURCES = snmp_agent.c snmp_agent_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBNETSNMP_CPPFLAGS) snmp_agent_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBNETSNMP_LDFLAGS) snmp_agent_la_LIBADD = $(BUILD_WITH_LIBNETSNMP_LIBS) From ad9a924705b31c591dae8181c7173a7716f68743 Mon Sep 17 00:00:00 2001 From: "Korynkevych, RomanX" Date: Mon, 26 Dec 2016 15:01:57 +0000 Subject: [PATCH 04/11] snmp_agent: Addressing PR comments. Performed code cleanup and optimizations: - Reformat file using clang-format. - Removed duplicate code. Change-Id: Ia6d7cde0e44cb5d3639df11e712fe655becd9712 Signed-off-by: Korynkevych, RomanX --- src/snmp_agent.c | 441 ++++++++++++++++++++++------------------------- 1 file changed, 203 insertions(+), 238 deletions(-) diff --git a/src/snmp_agent.c b/src/snmp_agent.c index 8c7b822884..c732bb68b1 100644 --- a/src/snmp_agent.c +++ b/src/snmp_agent.c @@ -27,10 +27,11 @@ **/ #include "collectd.h" + #include "common.h" #include "utils_avltree.h" -#include "utils_llist.h" #include "utils_cache.h" +#include "utils_llist.h" #include #include @@ -67,7 +68,7 @@ struct data_definition_s { char *plugin_instance; char *type; char *type_instance; - table_definition_t *table; + const table_definition_t *table; _Bool is_instance; oid_t *oids; size_t oids_len; @@ -92,7 +93,7 @@ snmp_agent_ctx_t *g_agent = NULL; #define CHECK_DD_TYPE(_dd, _p, _pi, _t, _ti) \ (_dd->plugin ? !strcmp(_dd->plugin, _p) : 0) && \ (_dd->plugin_instance ? !strcmp(_dd->plugin_instance, _pi) : 1) && \ - (_dd->type ? !strcmp(_dd->type, _t) : 1) && \ + (_dd->type ? !strcmp(_dd->type, _t) : 0) && \ (_dd->type_instance ? !strcmp(_dd->type_instance, _ti) : 1) static void *snmp_agent_thread_run(void *arg); @@ -129,24 +130,24 @@ static int snmp_agent_oid_to_string(char *buf, size_t buf_size, static void snmp_agent_dump_data(void) { #if COLLECT_DEBUG - char temp[DATA_MAX_NAME_LEN]; + char oid_str[DATA_MAX_NAME_LEN]; for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { - table_definition_t *td = (table_definition_t *)te->value; + table_definition_t *td = te->value; DEBUG(PLUGIN_NAME ": Table:"); DEBUG(PLUGIN_NAME ": Name: %s", td->name); if (td->index_oid.oid_len != 0) { - snmp_agent_oid_to_string(temp, sizeof(temp), &td->index_oid); - DEBUG(PLUGIN_NAME ": IndexOID: %s", temp); + snmp_agent_oid_to_string(oid_str, sizeof(oid_str), &td->index_oid); + DEBUG(PLUGIN_NAME ": IndexOID: %s", oid_str); } if (td->size_oid.oid_len != 0) { - snmp_agent_oid_to_string(temp, sizeof(temp), &td->size_oid); - DEBUG(PLUGIN_NAME ": SizeOID: %s", temp); + snmp_agent_oid_to_string(oid_str, sizeof(oid_str), &td->size_oid); + DEBUG(PLUGIN_NAME ": SizeOID: %s", oid_str); } for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { - data_definition_t *dd = (data_definition_t *)de->value; + data_definition_t *dd = de->value; DEBUG(PLUGIN_NAME ": Column:"); DEBUG(PLUGIN_NAME ": Name: %s", dd->name); @@ -161,8 +162,8 @@ static void snmp_agent_dump_data(void) { if (dd->type_instance) DEBUG(PLUGIN_NAME ": TypeInstance: %s", dd->type_instance); for (int i = 0; i < dd->oids_len; i++) { - snmp_agent_oid_to_string(temp, sizeof(temp), &dd->oids[i]); - DEBUG(PLUGIN_NAME ": OID[%d]: %s", i, temp); + snmp_agent_oid_to_string(oid_str, sizeof(oid_str), &dd->oids[i]); + DEBUG(PLUGIN_NAME ": OID[%d]: %s", i, oid_str); } DEBUG(PLUGIN_NAME ": Scale: %g", dd->scale); DEBUG(PLUGIN_NAME ": Shift: %g", dd->shift); @@ -170,7 +171,7 @@ static void snmp_agent_dump_data(void) { } for (llentry_t *e = llist_head(g_agent->scalars); e != NULL; e = e->next) { - data_definition_t *dd = (data_definition_t *)e->value; + data_definition_t *dd = e->value; DEBUG(PLUGIN_NAME ": Scalar:"); DEBUG(PLUGIN_NAME ": Name: %s", dd->name); @@ -185,8 +186,8 @@ static void snmp_agent_dump_data(void) { if (dd->type_instance) DEBUG(PLUGIN_NAME ": TypeInstance: %s", dd->type_instance); for (int i = 0; i < dd->oids_len; i++) { - snmp_agent_oid_to_string(temp, sizeof(temp), &dd->oids[i]); - DEBUG(PLUGIN_NAME ": OID[%d]: %s", i, temp); + snmp_agent_oid_to_string(oid_str, sizeof(oid_str), &dd->oids[i]); + DEBUG(PLUGIN_NAME ": OID[%d]: %s", i, oid_str); } DEBUG(PLUGIN_NAME ": Scale: %g", dd->scale); DEBUG(PLUGIN_NAME ": Shift: %g", dd->shift); @@ -199,10 +200,10 @@ static int snmp_agent_validate_data(void) { snmp_agent_dump_data(); for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { - table_definition_t *td = (table_definition_t *)te->value; + table_definition_t *td = te->value; for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { - data_definition_t *dd = (data_definition_t *)de->value; + data_definition_t *dd = de->value; if (!dd->plugin) { ERROR(PLUGIN_NAME ": Plugin not defined for '%s'.'%s'", td->name, @@ -251,7 +252,7 @@ static int snmp_agent_validate_data(void) { } for (llentry_t *e = llist_head(g_agent->scalars); e != NULL; e = e->next) { - data_definition_t *dd = (data_definition_t *)e->value; + data_definition_t *dd = e->value; if (!dd->plugin) { ERROR(PLUGIN_NAME ": Plugin not defined for '%s'", dd->name); @@ -284,14 +285,14 @@ static int snmp_agent_table_row_remove(table_definition_t *td, int *index; char *ins; - if ((c_avl_get(td->instance_index, instance, (void**) &index) != 0) || - (c_avl_get(td->index_instance, index, (void**) &ins) != 0)) + if ((c_avl_get(td->instance_index, instance, (void **)&index) != 0) || + (c_avl_get(td->index_instance, index, (void **)&ins) != 0)) return (0); pthread_mutex_lock(&g_agent->agentx_lock); for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { - data_definition_t *dd = (data_definition_t *)de->value; + data_definition_t *dd = de->value; for (int i = 0; i < dd->oids_len; i++) snmp_agent_unregister_oid_index(&dd->oids[i], *index); @@ -301,11 +302,14 @@ static int snmp_agent_table_row_remove(table_definition_t *td, pthread_mutex_unlock(&g_agent->agentx_lock); - DEBUG(PLUGIN_NAME ": Removed row for '%s' table [%d, %s].", td->name, *index, + DEBUG(PLUGIN_NAME ": Removed row for '%s' table [%d, %s]", td->name, *index, ins); - notification_t n = {NOTIF_WARNING, cdtime(), "", "", PLUGIN_NAME, "", "", "", - NULL}; + notification_t n = { + .severity = NOTIF_WARNING, + .time = cdtime(), + .plugin = PLUGIN_NAME + }; sstrncpy(n.host, hostname_g, sizeof(n.host)); sstrncpy(n.plugin_instance, ins, sizeof(n.plugin_instance)); ssnprintf(n.message, sizeof(n.message), @@ -313,8 +317,8 @@ static int snmp_agent_table_row_remove(table_definition_t *td, ins, *index); plugin_dispatch_notification(&n); - c_avl_remove(td->index_instance, index, NULL, (void**) &ins); - c_avl_remove(td->instance_index, instance, NULL, (void**) &index); + c_avl_remove(td->index_instance, index, NULL, (void **)&ins); + c_avl_remove(td->instance_index, instance, NULL, (void **)&index); sfree(index); sfree(ins); @@ -327,10 +331,10 @@ static int snmp_agent_clear_missing(const value_list_t *vl, return (-EINVAL); for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { - table_definition_t *td = (table_definition_t *)te->value; + table_definition_t *td = te->value; for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { - data_definition_t *dd = (data_definition_t *)de->value; + data_definition_t *dd = de->value; if (!dd->is_instance) { if (CHECK_DD_TYPE(dd, vl->plugin, vl->plugin_instance, vl->type, @@ -399,7 +403,7 @@ static void snmp_agent_free_table(table_definition_t **td) { } for (llentry_t *de = llist_head((*td)->columns); de != NULL; de = de->next) { - data_definition_t *dd = (data_definition_t *)de->value; + data_definition_t *dd = de->value; snmp_agent_free_data(&dd); } @@ -408,6 +412,7 @@ static void snmp_agent_free_table(table_definition_t **td) { void *key = NULL; void *value = NULL; + /* index_instance and instance_index contain the same pointers */ c_avl_destroy((*td)->index_instance); (*td)->index_instance = NULL; @@ -424,6 +429,53 @@ static void snmp_agent_free_table(table_definition_t **td) { return; } +static int snmp_agent_form_reply(struct netsnmp_request_info_s *requests, + data_definition_t *dd, char *instance, + int oid_index) { + char buf[DATA_MAX_NAME_LEN]; + format_name(buf, sizeof(buf), hostname_g, dd->plugin, + instance ? instance : dd->plugin_instance, dd->type, + dd->type_instance); + DEBUG(PLUGIN_NAME ": Identifier '%s'", buf); + + value_t *values; + size_t values_num; + const data_set_t *ds = plugin_get_ds(dd->type); + if (ds == NULL) { + DEBUG(PLUGIN_NAME ": Data set not found for '%s' type", dd->type); + return SNMP_NOSUCHINSTANCE; + } + + int ret = uc_get_value_by_name(buf, &values, &values_num); + + if (ret != 0) { + ERROR(PLUGIN_NAME ": Failed to get value for '%s'", buf); + return SNMP_NOSUCHINSTANCE; + } + + assert(ds->ds_num == values_num); + assert(oid_index < values_num); + + char data[DATA_MAX_NAME_LEN]; + size_t data_len = sizeof(data); + ret = snmp_agent_set_vardata( + data, &data_len, dd->oids[oid_index].type, dd->scale, dd->shift, + &values[oid_index], sizeof(values[oid_index]), ds->ds[oid_index].type); + + sfree(values); + + if (ret != 0) { + ERROR(PLUGIN_NAME ": Failed to convert '%s' value to snmp data", buf); + return SNMP_NOSUCHINSTANCE; + } + + requests->requestvb->type = dd->oids[oid_index].type; + snmp_set_var_typed_value(requests->requestvb, requests->requestvb->type, data, + data_len); + + return SNMP_ERR_NOERROR; +} + static int snmp_agent_table_oid_handler(struct netsnmp_mib_handler_s *handler, struct netsnmp_handler_registration_s *reginfo, @@ -431,112 +483,67 @@ snmp_agent_table_oid_handler(struct netsnmp_mib_handler_s *handler, struct netsnmp_request_info_s *requests) { if (reqinfo->mode != MODE_GET && reqinfo->mode != MODE_GETNEXT) { - DEBUG(PLUGIN_NAME ": Not supported request mode (%d).", reqinfo->mode); + DEBUG(PLUGIN_NAME ": Not supported request mode (%d)", reqinfo->mode); return SNMP_ERR_NOERROR; } - oid_t oid; - char temp[DATA_MAX_NAME_LEN]; - pthread_mutex_lock(&g_agent->lock); + oid_t oid; memcpy(oid.oid, requests->requestvb->name, sizeof(oid.oid[0]) * requests->requestvb->name_length); oid.oid_len = requests->requestvb->name_length; - snmp_agent_oid_to_string(temp, sizeof(temp), &oid); - - DEBUG(PLUGIN_NAME ": Get request received for table OID '%s'.", temp); +#if COLLECT_DEBUG + char oid_str[DATA_MAX_NAME_LEN]; + snmp_agent_oid_to_string(oid_str, sizeof(oid_str), &oid); + DEBUG(PLUGIN_NAME ": Get request received for table OID '%s'", oid_str); +#endif for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { - table_definition_t *td = (table_definition_t *)te->value; + table_definition_t *td = te->value; for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { - data_definition_t *dd = (data_definition_t *)de->value; + data_definition_t *dd = de->value; for (int i = 0; i < dd->oids_len; i++) { + int ret = snmp_oid_ncompare(oid.oid, oid.oid_len, dd->oids[i].oid, + dd->oids[i].oid_len, + MIN(oid.oid_len, dd->oids[i].oid_len)); + if (ret != 0) + continue; + + if (!td->index_oid.oid_len) { + DEBUG(PLUGIN_NAME ": %s:%d NOT IMPLEMENTED", __FUNCTION__, __LINE__); + continue; + } - int ret = snmp_oid_ncompare(oid.oid, oid.oid_len, - dd->oids[i].oid, dd->oids[i].oid_len, - MIN(oid.oid_len, dd->oids[i].oid_len)); - if (ret != 0) continue; - - if (td->index_oid.oid_len) { - int index = oid.oid[oid.oid_len - 1]; - char *instance; - - ret = c_avl_get(td->index_instance, &index, (void **)&instance); - if (ret != 0) { - DEBUG(PLUGIN_NAME ": Nonexisting index '%d' requested.", index); - pthread_mutex_unlock(&g_agent->lock); - return SNMP_NOSUCHINSTANCE; - } - - if (dd->is_instance) { - - requests->requestvb->type = ASN_OCTET_STR; - snmp_set_var_typed_value(requests->requestvb, - requests->requestvb->type, instance, - strlen((instance))); - - pthread_mutex_unlock(&g_agent->lock); - - return SNMP_ERR_NOERROR; - } - - format_name(temp, sizeof(temp), hostname_g, dd->plugin, instance, - dd->type, dd->type_instance); - DEBUG(PLUGIN_NAME ": Identifier '%s'", temp); - - value_t *values; - size_t values_num; - const data_set_t *ds; - - ds = plugin_get_ds(dd->type); - if (ds == NULL) { - DEBUG(PLUGIN_NAME ": Data set not found for '%s' type.", dd->type); - pthread_mutex_unlock(&g_agent->lock); - return SNMP_NOSUCHINSTANCE; - } - - ret = uc_get_value_by_name(temp, &values, &values_num); - - if (ret != 0) { - ERROR(PLUGIN_NAME ": Failed to get value for '%s'.", temp); - pthread_mutex_unlock(&g_agent->lock); - return SNMP_NOSUCHINSTANCE; - } - - assert(ds->ds_num == values_num); - assert(i < values_num); - - char data[DATA_MAX_NAME_LEN]; - size_t data_len = sizeof(data); - ret = snmp_agent_set_vardata(data, &data_len, dd->oids[i].type, - dd->scale, dd->shift, &values[i], - sizeof(values[i]), ds->ds[i].type); - - sfree(values); - values_num = 0; - - if (ret != 0) { - ERROR(PLUGIN_NAME ": Failed to convert '%s' value to snmp data.", - temp); - pthread_mutex_unlock(&g_agent->lock); - return SNMP_NOSUCHINSTANCE; - } - - requests->requestvb->type = dd->oids[i].type; + int index = oid.oid[oid.oid_len - 1]; + char *instance; + + ret = c_avl_get(td->index_instance, &index, (void **)&instance); + if (ret != 0) { + DEBUG(PLUGIN_NAME ": Nonexisting index '%d' requested", index); + pthread_mutex_unlock(&g_agent->lock); + return SNMP_NOSUCHINSTANCE; + } + + if (dd->is_instance) { + requests->requestvb->type = ASN_OCTET_STR; snmp_set_var_typed_value(requests->requestvb, - requests->requestvb->type, data, data_len); + requests->requestvb->type, instance, + strlen((instance))); pthread_mutex_unlock(&g_agent->lock); return SNMP_ERR_NOERROR; - - } else { - DEBUG(PLUGIN_NAME ": %s:%d NOT IMPLEMENTED.", __FUNCTION__, __LINE__); } + + ret = snmp_agent_form_reply(requests, dd, instance, i); + + pthread_mutex_unlock(&g_agent->lock); + + return ret; } } } @@ -546,39 +553,37 @@ snmp_agent_table_oid_handler(struct netsnmp_mib_handler_s *handler, return SNMP_NOSUCHINSTANCE; } -static int -snmp_agent_table_index_oid_handler(struct netsnmp_mib_handler_s *handler, - struct netsnmp_handler_registration_s *reginfo, - struct netsnmp_agent_request_info_s *reqinfo, - struct netsnmp_request_info_s *requests) { +static int snmp_agent_table_index_oid_handler( + struct netsnmp_mib_handler_s *handler, + struct netsnmp_handler_registration_s *reginfo, + struct netsnmp_agent_request_info_s *reqinfo, + struct netsnmp_request_info_s *requests) { if (reqinfo->mode != MODE_GET && reqinfo->mode != MODE_GETNEXT) { - DEBUG(PLUGIN_NAME ": Not supported request mode (%d).", reqinfo->mode); + DEBUG(PLUGIN_NAME ": Not supported request mode (%d)", reqinfo->mode); return SNMP_ERR_NOERROR; } - oid_t oid; - pthread_mutex_lock(&g_agent->lock); + oid_t oid; memcpy(oid.oid, requests->requestvb->name, sizeof(oid.oid[0]) * requests->requestvb->name_length); oid.oid_len = requests->requestvb->name_length; for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { - table_definition_t *td = (table_definition_t *)te->value; + table_definition_t *td = te->value; if (td->index_oid.oid_len && - (snmp_oid_ncompare(oid.oid, oid.oid_len, td->index_oid.oid, - td->index_oid.oid_len, - MIN(oid.oid_len, td->index_oid.oid_len)) == 0)) { + (snmp_oid_ncompare(oid.oid, oid.oid_len, td->index_oid.oid, + td->index_oid.oid_len, + MIN(oid.oid_len, td->index_oid.oid_len)) == 0)) { - DEBUG(PLUGIN_NAME ": Handle '%s' table index OID.", td->name); + DEBUG(PLUGIN_NAME ": Handle '%s' table index OID", td->name); int index = oid.oid[oid.oid_len - 1]; - char *instance; - int ret = c_avl_get(td->index_instance, &index, (void **)&instance); + int ret = c_avl_get(td->index_instance, &index, &(void *){NULL}); if (ret != 0) { /* nonexisting index requested */ pthread_mutex_unlock(&g_agent->lock); @@ -600,35 +605,34 @@ snmp_agent_table_index_oid_handler(struct netsnmp_mib_handler_s *handler, return SNMP_NOSUCHINSTANCE; } -static int -snmp_agent_table_size_oid_handler(struct netsnmp_mib_handler_s *handler, - struct netsnmp_handler_registration_s *reginfo, - struct netsnmp_agent_request_info_s *reqinfo, - struct netsnmp_request_info_s *requests) { +static int snmp_agent_table_size_oid_handler( + struct netsnmp_mib_handler_s *handler, + struct netsnmp_handler_registration_s *reginfo, + struct netsnmp_agent_request_info_s *reqinfo, + struct netsnmp_request_info_s *requests) { if (reqinfo->mode != MODE_GET && reqinfo->mode != MODE_GETNEXT) { - DEBUG(PLUGIN_NAME ": Not supported request mode (%d).", reqinfo->mode); + DEBUG(PLUGIN_NAME ": Not supported request mode (%d)", reqinfo->mode); return SNMP_ERR_NOERROR; } - oid_t oid; - pthread_mutex_lock(&g_agent->lock); + oid_t oid; memcpy(oid.oid, requests->requestvb->name, sizeof(oid.oid[0]) * requests->requestvb->name_length); oid.oid_len = requests->requestvb->name_length; - DEBUG(PLUGIN_NAME ": Get request received for table size OID."); + DEBUG(PLUGIN_NAME ": Get request received for table size OID"); for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { - table_definition_t *td = (table_definition_t *)te->value; + table_definition_t *td = te->value; if (td->size_oid.oid_len && (snmp_oid_ncompare(oid.oid, oid.oid_len, td->size_oid.oid, td->size_oid.oid_len, MIN(oid.oid_len, td->size_oid.oid_len)) == 0)) { - DEBUG(PLUGIN_NAME ": Handle '%s' table size OID.", td->name); + DEBUG(PLUGIN_NAME ": Handle '%s' table size OID", td->name); long size = c_avl_size(td->index_instance); @@ -647,7 +651,6 @@ snmp_agent_table_size_oid_handler(struct netsnmp_mib_handler_s *handler, return SNMP_NOSUCHINSTANCE; } - static int snmp_agent_scalar_oid_handler(struct netsnmp_mib_handler_s *handler, struct netsnmp_handler_registration_s *reginfo, @@ -655,81 +658,39 @@ snmp_agent_scalar_oid_handler(struct netsnmp_mib_handler_s *handler, struct netsnmp_request_info_s *requests) { if (reqinfo->mode != MODE_GET && reqinfo->mode != MODE_GETNEXT) { - DEBUG(PLUGIN_NAME ": Not supported request mode (%d).", reqinfo->mode); + DEBUG(PLUGIN_NAME ": Not supported request mode (%d)", reqinfo->mode); return SNMP_ERR_NOERROR; } - int ret; - oid_t oid; - char temp[DATA_MAX_NAME_LEN]; - pthread_mutex_lock(&g_agent->lock); + oid_t oid; memcpy(oid.oid, requests->requestvb->name, sizeof(oid.oid[0]) * requests->requestvb->name_length); oid.oid_len = requests->requestvb->name_length; - snmp_agent_oid_to_string(temp, sizeof(temp), &oid); - - DEBUG(PLUGIN_NAME ": Get request received for scalar OID '%s'.", temp); +#if COLLECT_DEBUG + char oid_str[DATA_MAX_NAME_LEN]; + snmp_agent_oid_to_string(oid_str, sizeof(oid_str), &oid); + DEBUG(PLUGIN_NAME ": Get request received for scalar OID '%s'", oid_str); +#endif - for (llentry_t *de = llist_head(g_agent->scalars); de != NULL; de = de->next) { - data_definition_t *dd = (data_definition_t *)de->value; + for (llentry_t *de = llist_head(g_agent->scalars); de != NULL; + de = de->next) { + data_definition_t *dd = de->value; for (int i = 0; i < dd->oids_len; i++) { - ret = snmp_oid_compare(oid.oid, oid.oid_len, - dd->oids[i].oid, dd->oids[i].oid_len); - if (ret != 0) continue; - - format_name(temp, sizeof(temp), hostname_g, dd->plugin, - dd->plugin_instance, dd->type, dd->type_instance); - DEBUG(PLUGIN_NAME ": Identifier '%s'", temp); - - value_t *values; - size_t values_num; - const data_set_t *ds; - - ds = plugin_get_ds(dd->type); - if (ds == NULL) { - DEBUG(PLUGIN_NAME ": Data set not found for '%s' type", dd->type); - pthread_mutex_unlock(&g_agent->lock); - return SNMP_NOSUCHINSTANCE; - } - - ret = uc_get_value_by_name(temp, &values, &values_num); - - if (ret != 0) { - ERROR(PLUGIN_NAME ": Failed to get value for '%s'.", temp); - pthread_mutex_unlock(&g_agent->lock); - return SNMP_NOSUCHINSTANCE; - } - - assert(ds->ds_num == values_num); - assert(i < values_num); - - char data[DATA_MAX_NAME_LEN]; - size_t data_len = sizeof(data); - ret = snmp_agent_set_vardata(data, &data_len, dd->oids[i].type, - dd->scale, dd->shift, &values[i], - sizeof(values[i]), ds->ds[i].type); - - sfree(values); - values_num = 0; - - if (ret != 0) { - ERROR(PLUGIN_NAME ": Failed to convert '%s' value to snmp data.", temp); - pthread_mutex_unlock(&g_agent->lock); - return SNMP_NOSUCHINSTANCE; - } + int ret = snmp_oid_compare(oid.oid, oid.oid_len, dd->oids[i].oid, + dd->oids[i].oid_len); + if (ret != 0) + continue; - requests->requestvb->type = dd->oids[i].type; - snmp_set_var_typed_value(requests->requestvb, requests->requestvb->type, - data, data_len); + ret = snmp_agent_form_reply(requests, dd, NULL, i); pthread_mutex_unlock(&g_agent->lock); - return SNMP_ERR_NOERROR; + return ret; } } @@ -741,7 +702,7 @@ snmp_agent_scalar_oid_handler(struct netsnmp_mib_handler_s *handler, static int snmp_agent_register_table_oids(void) { for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { - table_definition_t *td = (table_definition_t *)te->value; + table_definition_t *td = te->value; if (td->size_oid.oid_len != 0) { td->size_oid.type = @@ -754,7 +715,7 @@ static int snmp_agent_register_table_oids(void) { } for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { - data_definition_t *dd = (data_definition_t *)de->value; + data_definition_t *dd = de->value; for (int i = 0; i < dd->oids_len; i++) { dd->oids[i].type = @@ -769,7 +730,7 @@ static int snmp_agent_register_table_oids(void) { static int snmp_agent_register_scalar_oids(void) { for (llentry_t *e = llist_head(g_agent->scalars); e != NULL; e = e->next) { - data_definition_t *dd = (data_definition_t *)e->value; + data_definition_t *dd = e->value; for (int i = 0; i < dd->oids_len; i++) { @@ -789,13 +750,13 @@ static int snmp_agent_register_scalar_oids(void) { static int snmp_agent_config_data_oids(data_definition_t *dd, oconfig_item_t *ci) { if (ci->values_num < 1) { - WARNING(PLUGIN_NAME ": `OIDs' needs at least one argument."); + WARNING(PLUGIN_NAME ": `OIDs' needs at least one argument"); return (-EINVAL); } for (int i = 0; i < ci->values_num; i++) if (ci->values[i].type != OCONFIG_TYPE_STRING) { - WARNING(PLUGIN_NAME ": `OIDs' needs only string argument."); + WARNING(PLUGIN_NAME ": `OIDs' needs only string argument"); return (-EINVAL); } @@ -812,7 +773,7 @@ static int snmp_agent_config_data_oids(data_definition_t *dd, if (NULL == snmp_parse_oid(ci->values[i].value.string, dd->oids[i].oid, &dd->oids[i].oid_len)) { - ERROR(PLUGIN_NAME ": snmp_parse_oid (%s) failed.", + ERROR(PLUGIN_NAME ": snmp_parse_oid (%s) failed", ci->values[i].value.string); sfree(dd->oids); dd->oids_len = 0; @@ -826,12 +787,12 @@ static int snmp_agent_config_data_oids(data_definition_t *dd, static int snmp_agent_config_table_size_oid(table_definition_t *td, oconfig_item_t *ci) { if (ci->values_num < 1) { - WARNING(PLUGIN_NAME ": `TableSizeOID' is empty."); + WARNING(PLUGIN_NAME ": `TableSizeOID' is empty"); return (-EINVAL); } if (ci->values[0].type != OCONFIG_TYPE_STRING) { - WARNING(PLUGIN_NAME ": `TableSizeOID' needs only string argument."); + WARNING(PLUGIN_NAME ": `TableSizeOID' needs only string argument"); return (-EINVAL); } @@ -852,12 +813,12 @@ static int snmp_agent_config_table_index_oid(table_definition_t *td, oconfig_item_t *ci) { if (ci->values_num < 1) { - WARNING(PLUGIN_NAME ": `IndexOID' is empty."); + WARNING(PLUGIN_NAME ": `IndexOID' is empty"); return (-EINVAL); } if (ci->values[0].type != OCONFIG_TYPE_STRING) { - WARNING(PLUGIN_NAME ": `IndexOID' needs only string argument."); + WARNING(PLUGIN_NAME ": `IndexOID' needs only string argument"); return (-EINVAL); } @@ -918,7 +879,7 @@ static int snmp_agent_config_table_data(table_definition_t *td, else if (strcasecmp("OIDs", option->key) == 0) ret = snmp_agent_config_data_oids(dd, option); else { - WARNING(PLUGIN_NAME ": Option `%s' not allowed here.", option->key); + WARNING(PLUGIN_NAME ": Option `%s' not allowed here", option->key); ret = -1; } @@ -980,7 +941,7 @@ static int snmp_agent_config_data(oconfig_item_t *ci) { else if (strcasecmp("OIDs", option->key) == 0) ret = snmp_agent_config_data_oids(dd, option); else { - WARNING(PLUGIN_NAME ": Option `%s' not allowed here.", option->key); + WARNING(PLUGIN_NAME ": Option `%s' not allowed here", option->key); ret = -1; } @@ -1019,7 +980,7 @@ static int snmp_agent_config_table(oconfig_item_t *ci) { td = calloc(1, sizeof(*td)); if (td == NULL) { - ERROR(PLUGIN_NAME ": Failed to allocate memory for table definition."); + ERROR(PLUGIN_NAME ": Failed to allocate memory for table definition"); return (-ENOMEM); } @@ -1031,7 +992,7 @@ static int snmp_agent_config_table(oconfig_item_t *ci) { td->columns = llist_create(); if (td->columns == NULL) { - ERROR(PLUGIN_NAME ": Failed to allocate memory for columns list."); + ERROR(PLUGIN_NAME ": Failed to allocate memory for columns list"); snmp_agent_free_table(&td); return (-ENOMEM); } @@ -1046,7 +1007,7 @@ static int snmp_agent_config_table(oconfig_item_t *ci) { else if (strcasecmp("Data", option->key) == 0) ret = snmp_agent_config_table_data(td, option); else { - WARNING(PLUGIN_NAME ": Option `%s' not allowed here.", option->key); + WARNING(PLUGIN_NAME ": Option `%s' not allowed here", option->key); ret = -1; } @@ -1100,7 +1061,7 @@ static int snmp_agent_get_value_from_ds_type(const value_t *val, int type, case TYPE_STRING: break; default: - ERROR(PLUGIN_NAME ": Unknown data source type: %i.", type); + ERROR(PLUGIN_NAME ": Unknown data source type: %i", type); return (-EINVAL); } @@ -1150,13 +1111,13 @@ static int snmp_agent_set_vardata(void *data, size_t *data_len, u_char asn_type, *data_len = strlen(buf); memcpy(var.string, buf, *data_len); } else { - ERROR(PLUGIN_NAME ": Failed to convert %d ds type to %d asn type.", type, + ERROR(PLUGIN_NAME ": Failed to convert %d ds type to %d asn type", type, asn_type); return (-EINVAL); } break; default: - ERROR(PLUGIN_NAME ": Failed to convert %d ds type to %d asn type.", type, + ERROR(PLUGIN_NAME ": Failed to convert %d ds type to %d asn type", type, asn_type); return (-EINVAL); } @@ -1210,13 +1171,13 @@ static int snmp_agent_update_index(table_definition_t *td, ret = c_avl_insert(td->index_instance, index, ins); if (ret < 0) { - DEBUG(PLUGIN_NAME ": Failed to update index_instance for '%s' table.", + DEBUG(PLUGIN_NAME ": Failed to update index_instance for '%s' table", td->name); return ret; } - DEBUG(PLUGIN_NAME ": Updated index for '%s' table [%d, %s].", td->name, - *index, ins); + DEBUG(PLUGIN_NAME ": Updated index for '%s' table [%d, %s]", td->name, *index, + ins); /* need to generate index for the table */ if (td->index_oid.oid_len) { @@ -1228,7 +1189,7 @@ static int snmp_agent_update_index(table_definition_t *td, /* register new oids for all columns */ for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { - data_definition_t *dd = (data_definition_t *)de->value; + data_definition_t *dd = de->value; for (int i = 0; i < dd->oids_len; i++) { ret = snmp_agent_register_oid_index(&dd->oids[i], *index, @@ -1239,8 +1200,11 @@ static int snmp_agent_update_index(table_definition_t *td, } } - notification_t n = {NOTIF_OKAY, cdtime(), "", "", PLUGIN_NAME, "", "", "", - NULL}; + notification_t n = { + .severity = NOTIF_OKAY, + .time = cdtime(), + .plugin = PLUGIN_NAME + }; sstrncpy(n.host, hostname_g, sizeof(n.host)); sstrncpy(n.plugin_instance, ins, sizeof(n.plugin_instance)); ssnprintf(n.message, sizeof(n.message), @@ -1257,10 +1221,10 @@ static int snmp_agent_write(value_list_t const *vl) { return (-EINVAL); for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { - table_definition_t *td = (table_definition_t *)te->value; + table_definition_t *td = te->value; for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { - data_definition_t *dd = (data_definition_t *)de->value; + data_definition_t *dd = de->value; if (!dd->is_instance) { if (CHECK_DD_TYPE(dd, vl->plugin, vl->plugin_instance, vl->type, @@ -1295,7 +1259,7 @@ static int snmp_agent_preinit(void) { g_agent = calloc(1, sizeof(*g_agent)); if (g_agent == NULL) { - ERROR(PLUGIN_NAME ": Failed to allocate memory for snmp agent context."); + ERROR(PLUGIN_NAME ": Failed to allocate memory for snmp agent context"); return (-ENOMEM); } @@ -1385,14 +1349,15 @@ static void *snmp_agent_thread_run(void __attribute__((unused)) * arg) { static int snmp_agent_register_oid(oid_t *oid, Netsnmp_Node_Handler *handler) { netsnmp_handler_registration *reg; - char temp[DATA_MAX_NAME_LEN]; char *oid_name = snmp_agent_get_oid_name(oid->oid, oid->oid_len - 1); + char oid_str[DATA_MAX_NAME_LEN]; - snmp_agent_oid_to_string(temp, sizeof(temp), oid); + snmp_agent_oid_to_string(oid_str, sizeof(oid_str), oid); if (oid_name == NULL) { WARNING(PLUGIN_NAME - ": Skipped registration: OID (%s) is not found in main tree", temp); + ": Skipped registration: OID (%s) is not found in main tree", + oid_str); return (0); } @@ -1400,21 +1365,21 @@ static int snmp_agent_register_oid(oid_t *oid, Netsnmp_Node_Handler *handler) { oid->oid_len, HANDLER_CAN_RONLY); if (reg == NULL) { ERROR(PLUGIN_NAME ": Failed to create handler registration for OID (%s)", - temp); + oid_str); return (-1); } pthread_mutex_lock(&g_agent->agentx_lock); if (netsnmp_register_instance(reg) != MIB_REGISTERED_OK) { - ERROR(PLUGIN_NAME ": Failed to register handler for OID (%s)", temp); + ERROR(PLUGIN_NAME ": Failed to register handler for OID (%s)", oid_str); pthread_mutex_unlock(&g_agent->agentx_lock); return (-1); } pthread_mutex_unlock(&g_agent->agentx_lock); - DEBUG(PLUGIN_NAME ": Registered handler for OID (%s)", temp); + DEBUG(PLUGIN_NAME ": Registered handler for OID (%s)", oid_str); return (0); } @@ -1438,18 +1403,18 @@ static int snmp_agent_free_config(void) { static int snmp_agent_shutdown(void) { int ret = 0; - DEBUG(PLUGIN_NAME ": snmp_agent_shutdown."); + DEBUG(PLUGIN_NAME ": snmp_agent_shutdown"); if (g_agent == NULL) { - ERROR(PLUGIN_NAME ": snmp_agent_shutdown: plugin not initialized."); + ERROR(PLUGIN_NAME ": snmp_agent_shutdown: plugin not initialized"); return (-EINVAL); } if (pthread_cancel(g_agent->thread) != 0) - ERROR(PLUGIN_NAME ": snmp_agent_shutdown: failed to cancel the thread."); + ERROR(PLUGIN_NAME ": snmp_agent_shutdown: failed to cancel the thread"); if (pthread_join(g_agent->thread, NULL) != 0) - ERROR(PLUGIN_NAME ": snmp_agent_shutdown: failed to join the thread."); + ERROR(PLUGIN_NAME ": snmp_agent_shutdown: failed to join the thread"); snmp_agent_free_config(); @@ -1479,12 +1444,12 @@ static int snmp_agent_config(oconfig_item_t *ci) { } else if (strcasecmp("Table", child->key) == 0) { ret = snmp_agent_config_table(child); } else { - ERROR(PLUGIN_NAME ": Unknown configuration option `%s'.", child->key); + ERROR(PLUGIN_NAME ": Unknown configuration option `%s'", child->key); ret = (-EINVAL); } if (ret != 0) { - ERROR(PLUGIN_NAME ": Failed to parse configuration."); + ERROR(PLUGIN_NAME ": Failed to parse configuration"); snmp_agent_free_config(); snmp_shutdown(PLUGIN_NAME); sfree(g_agent); @@ -1494,7 +1459,7 @@ static int snmp_agent_config(oconfig_item_t *ci) { ret = snmp_agent_validate_data(); if (ret != 0) { - ERROR(PLUGIN_NAME ": Invalid configuration provided."); + ERROR(PLUGIN_NAME ": Invalid configuration provided"); snmp_agent_free_config(); snmp_shutdown(PLUGIN_NAME); sfree(g_agent); From 8cb75222e06009109fff0750d5b28ca4597438e9 Mon Sep 17 00:00:00 2001 From: "Korynkevych, RomanX" Date: Fri, 30 Dec 2016 16:45:06 +0000 Subject: [PATCH 05/11] snmp_agent: addressing PR comments. Additional validation and variable names changes. Change-Id: Ic6c3c3226e2ee6586c03b64d063822b99c242af3 Signed-off-by: Korynkevych, RomanX --- src/snmp_agent.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/snmp_agent.c b/src/snmp_agent.c index c732bb68b1..74c2d0b027 100644 --- a/src/snmp_agent.c +++ b/src/snmp_agent.c @@ -432,24 +432,24 @@ static void snmp_agent_free_table(table_definition_t **td) { static int snmp_agent_form_reply(struct netsnmp_request_info_s *requests, data_definition_t *dd, char *instance, int oid_index) { - char buf[DATA_MAX_NAME_LEN]; - format_name(buf, sizeof(buf), hostname_g, dd->plugin, + char name[DATA_MAX_NAME_LEN]; + format_name(name, sizeof(name), hostname_g, dd->plugin, instance ? instance : dd->plugin_instance, dd->type, dd->type_instance); - DEBUG(PLUGIN_NAME ": Identifier '%s'", buf); + DEBUG(PLUGIN_NAME ": Identifier '%s'", name); value_t *values; size_t values_num; const data_set_t *ds = plugin_get_ds(dd->type); if (ds == NULL) { - DEBUG(PLUGIN_NAME ": Data set not found for '%s' type", dd->type); + ERROR(PLUGIN_NAME ": Data set not found for '%s' type", dd->type); return SNMP_NOSUCHINSTANCE; } - int ret = uc_get_value_by_name(buf, &values, &values_num); + int ret = uc_get_value_by_name(name, &values, &values_num); if (ret != 0) { - ERROR(PLUGIN_NAME ": Failed to get value for '%s'", buf); + ERROR(PLUGIN_NAME ": Failed to get value for '%s'", name); return SNMP_NOSUCHINSTANCE; } @@ -465,7 +465,7 @@ static int snmp_agent_form_reply(struct netsnmp_request_info_s *requests, sfree(values); if (ret != 0) { - ERROR(PLUGIN_NAME ": Failed to convert '%s' value to snmp data", buf); + ERROR(PLUGIN_NAME ": Failed to convert '%s' value to snmp data", name); return SNMP_NOSUCHINSTANCE; } @@ -503,6 +503,11 @@ snmp_agent_table_oid_handler(struct netsnmp_mib_handler_s *handler, for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { table_definition_t *td = te->value; + if (!td->index_oid.oid_len) { + DEBUG(PLUGIN_NAME ": %s:%d NOT IMPLEMENTED", __FUNCTION__, __LINE__); + continue; + } + for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { data_definition_t *dd = de->value; @@ -513,11 +518,6 @@ snmp_agent_table_oid_handler(struct netsnmp_mib_handler_s *handler, if (ret != 0) continue; - if (!td->index_oid.oid_len) { - DEBUG(PLUGIN_NAME ": %s:%d NOT IMPLEMENTED", __FUNCTION__, __LINE__); - continue; - } - int index = oid.oid[oid.oid_len - 1]; char *instance; @@ -1017,6 +1017,12 @@ static int snmp_agent_config_table(oconfig_item_t *ci) { } } + if (td->index_oid.oid_len == 0) { + ERROR(PLUGIN_NAME ": Table %s Index OID is not specified", td->name); + snmp_agent_free_table(&td); + return (-1); + } + llentry_t *entry = llentry_create(td->name, td); if (entry == NULL) { snmp_agent_free_table(&td); From 0b852c1a4283a6e7a1217ca2f0b94ff9f58ddb54 Mon Sep 17 00:00:00 2001 From: Roman Korynkevych Date: Tue, 3 Jan 2017 15:02:20 +0000 Subject: [PATCH 06/11] snmp_agent: fix root Makefile.am The location of SNMP Agent sources in Makefile.am is `src/*` folder now. Signed-off-by: Roman Korynkevych --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index af849fffd4..619159c6cc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1458,7 +1458,7 @@ endif if BUILD_PLUGIN_SNMP_AGENT pkglib_LTLIBRARIES += snmp_agent.la -snmp_agent_la_SOURCES = snmp_agent.c +snmp_agent_la_SOURCES = src/snmp_agent.c snmp_agent_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBNETSNMP_CPPFLAGS) snmp_agent_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBNETSNMP_LDFLAGS) snmp_agent_la_LIBADD = $(BUILD_WITH_LIBNETSNMP_LIBS) From 9e30a0c8227538cc11a3f83f021fb944c1279c2c Mon Sep 17 00:00:00 2001 From: "Korynkevych, RomanX" Date: Thu, 12 Jan 2017 11:24:27 +0000 Subject: [PATCH 07/11] snmp_agent: fix c_avl_pick() segmentation fault. Segmentation fault caused by c_avl_pick() occurs when NULL iterator is passed. Change-Id: I3dc960f80b556e18616717ca53fd992c8cf9d78b Signed-off-by: Korynkevych, RomanX --- src/daemon/utils_avltree.c | 2 ++ src/snmp_agent.c | 14 ++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/daemon/utils_avltree.c b/src/daemon/utils_avltree.c index 92259ae19d..1cf3edfcfd 100644 --- a/src/daemon/utils_avltree.c +++ b/src/daemon/utils_avltree.c @@ -534,6 +534,8 @@ int c_avl_pick(c_avl_tree_t *t, void **key, void **value) { c_avl_node_t *n; c_avl_node_t *p; + assert(t != NULL); + if ((key == NULL) || (value == NULL)) return (-1); if (t->root == NULL) diff --git a/src/snmp_agent.c b/src/snmp_agent.c index 74c2d0b027..5f8ed290a1 100644 --- a/src/snmp_agent.c +++ b/src/snmp_agent.c @@ -1,7 +1,7 @@ /** * collectd - src/snmp_agent.c * - * Copyright(c) 2016 Intel Corporation. All rights reserved. + * Copyright(c) 2017 Intel Corporation. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in @@ -416,12 +416,14 @@ static void snmp_agent_free_table(table_definition_t **td) { c_avl_destroy((*td)->index_instance); (*td)->index_instance = NULL; - while (c_avl_pick((*td)->instance_index, &key, &value) == 0) { - sfree(key); - sfree(value); + if ((*td)->instance_index != NULL) { + while (c_avl_pick((*td)->instance_index, &key, &value) == 0) { + sfree(key); + sfree(value); + } + c_avl_destroy((*td)->instance_index); + (*td)->instance_index = NULL; } - c_avl_destroy((*td)->instance_index); - (*td)->instance_index = NULL; sfree((*td)->name); sfree(*td); From be8bfcd18bd7740b8e76bf373e0bd6202644326b Mon Sep 17 00:00:00 2001 From: "Korynkevych, RomanX" Date: Thu, 16 Mar 2017 17:21:31 +0000 Subject: [PATCH 08/11] snmp_agent: generate table OID based on instance as a key in case index is not specfified. Based on the SNMP rules when table column is represented as a key of string type, key should be used while generating OID for each row. When index is not specified, then it's assumed that instance value is the key for the specified table. Change-Id: I9f3fbd9aa018bc9037bd3202e2ed107a302fe1b3 Signed-off-by: Korynkevych, RomanX --- src/snmp_agent.c | 224 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 159 insertions(+), 65 deletions(-) diff --git a/src/snmp_agent.c b/src/snmp_agent.c index 5f8ed290a1..af22312227 100644 --- a/src/snmp_agent.c +++ b/src/snmp_agent.c @@ -280,30 +280,87 @@ static int snmp_agent_validate_data(void) { return (0); } +static void snmp_agent_generate_oid2string(oid_t *oid, int offset, char *key) { + int key_len = oid->oid[offset]; + int i; + + for (i = 0; i < key_len && offset < oid->oid_len; i++) + key[i] = oid->oid[++offset]; + + key[i] = '\0'; +} + +static int snmp_agent_generate_string2oid(oid_t *oid, const char *key) { + int key_len = strlen(key); + + oid->oid[oid->oid_len++] = key_len; + for (int i = 0; i < key_len; i++) { + oid->oid[oid->oid_len++] = key[i]; + if (oid->oid_len >= MAX_OID_LEN) { + ERROR(PLUGIN_NAME ": Conversion key string %s to OID failed", key); + return (-EINVAL); + } + } + + return 0; +} + +static int snmp_agent_register_oid_string(oid_t *oid, const char *key, + Netsnmp_Node_Handler *handler) { + oid_t new_oid; + + memcpy(&new_oid, oid, sizeof(*oid)); + int ret = snmp_agent_generate_string2oid(&new_oid, key); + if (ret != 0) + return ret; + + return snmp_agent_register_oid(&new_oid, handler); +} + +static int snmp_agent_unregister_oid_string(oid_t *oid, const char *key) { + oid_t new_oid; + + memcpy(&new_oid, oid, sizeof(*oid)); + int ret = snmp_agent_generate_string2oid(&new_oid, key); + if (ret != 0) + return ret; + + return unregister_mib(new_oid.oid, new_oid.oid_len); +} + static int snmp_agent_table_row_remove(table_definition_t *td, const char *instance) { - int *index; - char *ins; + int *index = NULL; + char *ins = NULL; - if ((c_avl_get(td->instance_index, instance, (void **)&index) != 0) || - (c_avl_get(td->index_instance, index, (void **)&ins) != 0)) - return (0); + if (td->index_oid.oid_len) { + if ((c_avl_get(td->instance_index, instance, (void **)&index) != 0) || + (c_avl_get(td->index_instance, index, (void **)&ins) != 0)) + return (0); + } else { + if (c_avl_get(td->instance_index, instance, (void **)&ins) != 0) + return (0); + } pthread_mutex_lock(&g_agent->agentx_lock); + if (td->index_oid.oid_len) + snmp_agent_unregister_oid_index(&td->index_oid, *index); + for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { data_definition_t *dd = de->value; for (int i = 0; i < dd->oids_len; i++) - snmp_agent_unregister_oid_index(&dd->oids[i], *index); + if (td->index_oid.oid_len) + snmp_agent_unregister_oid_index(&dd->oids[i], *index); + else + snmp_agent_unregister_oid_string(&dd->oids[i], ins); } - snmp_agent_unregister_oid_index(&td->index_oid, *index); - pthread_mutex_unlock(&g_agent->agentx_lock); - DEBUG(PLUGIN_NAME ": Removed row for '%s' table [%d, %s]", td->name, *index, - ins); + DEBUG(PLUGIN_NAME ": Removed row for '%s' table [%d, %s]", td->name, + (index != NULL) ? *index : -1, ins); notification_t n = { .severity = NOTIF_WARNING, @@ -314,13 +371,18 @@ static int snmp_agent_table_row_remove(table_definition_t *td, sstrncpy(n.plugin_instance, ins, sizeof(n.plugin_instance)); ssnprintf(n.message, sizeof(n.message), "Removed data row from table %s instance %s index %d", td->name, - ins, *index); + ins, (index != NULL) ? *index : -1); plugin_dispatch_notification(&n); - c_avl_remove(td->index_instance, index, NULL, (void **)&ins); - c_avl_remove(td->instance_index, instance, NULL, (void **)&index); - sfree(index); - sfree(ins); + if (td->index_oid.oid_len) { + c_avl_remove(td->index_instance, index, NULL, (void **)&ins); + c_avl_remove(td->instance_index, instance, NULL, (void **)&index); + sfree(index); + sfree(ins); + } else { + c_avl_remove(td->instance_index, instance, NULL, (void **)&ins); + sfree(ins); + } return (0); } @@ -358,6 +420,16 @@ static void snmp_agent_free_data(data_definition_t **dd) { if ((*dd)->table == NULL) { for (int i = 0; i < (*dd)->oids_len; i++) unregister_mib((*dd)->oids[i].oid, (*dd)->oids[i].oid_len); + } + if (!(*dd)->table->index_oid.oid_len) { + char *instance; + + c_avl_iterator_t *iter = c_avl_get_iterator((*dd)->table->instance_index); + while (c_avl_iterator_next(iter, (void *)&instance, (void *)&instance) == 0) { + for (int i = 0; i < (*dd)->oids_len; i++) + snmp_agent_unregister_oid_string(&(*dd)->oids[i], instance); + } + c_avl_iterator_destroy(iter); } else { /* unregister all table OIDs */ int *index; @@ -418,7 +490,8 @@ static void snmp_agent_free_table(table_definition_t **td) { if ((*td)->instance_index != NULL) { while (c_avl_pick((*td)->instance_index, &key, &value) == 0) { - sfree(key); + if (key != value) + sfree(key); sfree(value); } c_avl_destroy((*td)->instance_index); @@ -505,11 +578,6 @@ snmp_agent_table_oid_handler(struct netsnmp_mib_handler_s *handler, for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { table_definition_t *td = te->value; - if (!td->index_oid.oid_len) { - DEBUG(PLUGIN_NAME ": %s:%d NOT IMPLEMENTED", __FUNCTION__, __LINE__); - continue; - } - for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { data_definition_t *dd = de->value; @@ -520,14 +588,31 @@ snmp_agent_table_oid_handler(struct netsnmp_mib_handler_s *handler, if (ret != 0) continue; - int index = oid.oid[oid.oid_len - 1]; char *instance; - ret = c_avl_get(td->index_instance, &index, (void **)&instance); - if (ret != 0) { - DEBUG(PLUGIN_NAME ": Nonexisting index '%d' requested", index); - pthread_mutex_unlock(&g_agent->lock); - return SNMP_NOSUCHINSTANCE; + if (!td->index_oid.oid_len) { + char key[MAX_OID_LEN]; + + memset(key, 0, sizeof(key)); + snmp_agent_generate_oid2string(&oid, MIN(oid.oid_len, + dd->oids[i].oid_len), key); + + ret = c_avl_get(td->instance_index, key, (void **)&instance); + if (ret != 0) { + DEBUG(PLUGIN_NAME ": Nonexisting index string '%s' requested", + key); + pthread_mutex_unlock(&g_agent->lock); + return SNMP_NOSUCHINSTANCE; + } + } else { + int index = oid.oid[oid.oid_len - 1]; + + ret = c_avl_get(td->index_instance, &index, (void **)&instance); + if (ret != 0) { + DEBUG(PLUGIN_NAME ": Nonexisting index '%d' requested", index); + pthread_mutex_unlock(&g_agent->lock); + return SNMP_NOSUCHINSTANCE; + } } if (dd->is_instance) { @@ -1019,12 +1104,6 @@ static int snmp_agent_config_table(oconfig_item_t *ci) { } } - if (td->index_oid.oid_len == 0) { - ERROR(PLUGIN_NAME ": Table %s Index OID is not specified", td->name); - snmp_agent_free_table(&td); - return (-1); - } - llentry_t *entry = llentry_create(td->name, td); if (entry == NULL) { snmp_agent_free_table(&td); @@ -1155,59 +1234,74 @@ static int snmp_agent_update_index(table_definition_t *td, return (0); int ret; - int *index; + int *index = NULL; char *ins; ins = strdup(instance); if (ins == NULL) return (-ENOMEM); - index = calloc(1, sizeof(*index)); - if (index == NULL) { - sfree(ins); - return (-ENOMEM); - } - - *index = c_avl_size(td->instance_index) + 1; - - ret = c_avl_insert(td->instance_index, ins, index); - if (ret != 0) { - sfree(ins); - sfree(index); - return ret; - } + /* need to generate index for the table */ + if (td->index_oid.oid_len) { + index = calloc(1, sizeof(*index)); + if (index == NULL) { + sfree(ins); + return (-ENOMEM); + } - ret = c_avl_insert(td->index_instance, index, ins); - if (ret < 0) { - DEBUG(PLUGIN_NAME ": Failed to update index_instance for '%s' table", - td->name); - return ret; - } + *index = c_avl_size(td->instance_index) + 1; - DEBUG(PLUGIN_NAME ": Updated index for '%s' table [%d, %s]", td->name, *index, - ins); + ret = c_avl_insert(td->instance_index, ins, index); + if (ret != 0) { + sfree(ins); + sfree(index); + return ret; + } - /* need to generate index for the table */ - if (td->index_oid.oid_len) { + ret = c_avl_insert(td->index_instance, index, ins); + if (ret < 0) { + DEBUG(PLUGIN_NAME ": Failed to update index_instance for '%s' table", + td->name); + c_avl_remove(td->instance_index, ins, NULL, (void **)&index); + sfree(ins); + sfree(index); + return ret; + } ret = snmp_agent_register_oid_index(&td->index_oid, *index, snmp_agent_table_index_oid_handler); if (ret != 0) return ret; + } else { + /* instance as a key is required for any table */ + ret = c_avl_insert(td->instance_index, ins, ins); + if (ret != 0) { + sfree(ins); + return ret; + } + } - /* register new oids for all columns */ - for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { - data_definition_t *dd = de->value; + /* register new oids for all columns */ + for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { + data_definition_t *dd = de->value; - for (int i = 0; i < dd->oids_len; i++) { + for (int i = 0; i < dd->oids_len; i++) { + if (td->index_oid.oid_len) { ret = snmp_agent_register_oid_index(&dd->oids[i], *index, snmp_agent_table_oid_handler); - if (ret != 0) - return ret; + } else { + ret = snmp_agent_register_oid_string(&dd->oids[i], ins, + snmp_agent_table_oid_handler); } + + if (ret != 0) + return ret; } } + DEBUG(PLUGIN_NAME ": Updated index for '%s' table [%d, %s]", td->name, + (index != NULL) ? *index : -1, ins); + notification_t n = { .severity = NOTIF_OKAY, .time = cdtime(), @@ -1217,7 +1311,7 @@ static int snmp_agent_update_index(table_definition_t *td, sstrncpy(n.plugin_instance, ins, sizeof(n.plugin_instance)); ssnprintf(n.message, sizeof(n.message), "Data row added to table %s instance %s index %d", td->name, ins, - *index); + (index != NULL) ? *index : -1); plugin_dispatch_notification(&n); return (0); From 7dde174f50a4f096392ff2ad773d8a0f87bfe6de Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Wed, 17 May 2017 11:28:27 +0200 Subject: [PATCH 09/11] snmp_agent plugin: Format with clang-format. --- src/snmp_agent.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/snmp_agent.c b/src/snmp_agent.c index af22312227..4e9c1d0014 100644 --- a/src/snmp_agent.c +++ b/src/snmp_agent.c @@ -3,15 +3,15 @@ * * Copyright(c) 2017 Intel Corporation. All rights reserved. * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, @@ -34,7 +34,9 @@ #include "utils_llist.h" #include + #include + #include #define PLUGIN_NAME "snmp_agent" @@ -363,15 +365,12 @@ static int snmp_agent_table_row_remove(table_definition_t *td, (index != NULL) ? *index : -1, ins); notification_t n = { - .severity = NOTIF_WARNING, - .time = cdtime(), - .plugin = PLUGIN_NAME - }; + .severity = NOTIF_WARNING, .time = cdtime(), .plugin = PLUGIN_NAME}; sstrncpy(n.host, hostname_g, sizeof(n.host)); sstrncpy(n.plugin_instance, ins, sizeof(n.plugin_instance)); ssnprintf(n.message, sizeof(n.message), "Removed data row from table %s instance %s index %d", td->name, - ins, (index != NULL) ? *index : -1); + ins, (index != NULL) ? *index : -1); plugin_dispatch_notification(&n); if (td->index_oid.oid_len) { @@ -425,7 +424,8 @@ static void snmp_agent_free_data(data_definition_t **dd) { char *instance; c_avl_iterator_t *iter = c_avl_get_iterator((*dd)->table->instance_index); - while (c_avl_iterator_next(iter, (void *)&instance, (void *)&instance) == 0) { + while (c_avl_iterator_next(iter, (void *)&instance, (void *)&instance) == + 0) { for (int i = 0; i < (*dd)->oids_len; i++) snmp_agent_unregister_oid_string(&(*dd)->oids[i], instance); } @@ -594,13 +594,12 @@ snmp_agent_table_oid_handler(struct netsnmp_mib_handler_s *handler, char key[MAX_OID_LEN]; memset(key, 0, sizeof(key)); - snmp_agent_generate_oid2string(&oid, MIN(oid.oid_len, - dd->oids[i].oid_len), key); + snmp_agent_generate_oid2string( + &oid, MIN(oid.oid_len, dd->oids[i].oid_len), key); ret = c_avl_get(td->instance_index, key, (void **)&instance); if (ret != 0) { - DEBUG(PLUGIN_NAME ": Nonexisting index string '%s' requested", - key); + DEBUG(PLUGIN_NAME ": Nonexisting index string '%s' requested", key); pthread_mutex_unlock(&g_agent->lock); return SNMP_NOSUCHINSTANCE; } @@ -1291,7 +1290,7 @@ static int snmp_agent_update_index(table_definition_t *td, snmp_agent_table_oid_handler); } else { ret = snmp_agent_register_oid_string(&dd->oids[i], ins, - snmp_agent_table_oid_handler); + snmp_agent_table_oid_handler); } if (ret != 0) @@ -1303,10 +1302,7 @@ static int snmp_agent_update_index(table_definition_t *td, (index != NULL) ? *index : -1, ins); notification_t n = { - .severity = NOTIF_OKAY, - .time = cdtime(), - .plugin = PLUGIN_NAME - }; + .severity = NOTIF_OKAY, .time = cdtime(), .plugin = PLUGIN_NAME}; sstrncpy(n.host, hostname_g, sizeof(n.host)); sstrncpy(n.plugin_instance, ins, sizeof(n.plugin_instance)); ssnprintf(n.message, sizeof(n.message), From be87504ec76853427750ae06c8cb4a333821bec7 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Wed, 17 May 2017 11:30:18 +0200 Subject: [PATCH 10/11] snmp_agent plugin: Remove parenthesis around return values. See also: #2277 --- src/snmp_agent.c | 180 +++++++++++++++++++++++------------------------ 1 file changed, 90 insertions(+), 90 deletions(-) diff --git a/src/snmp_agent.c b/src/snmp_agent.c index 4e9c1d0014..89718bd033 100644 --- a/src/snmp_agent.c +++ b/src/snmp_agent.c @@ -108,13 +108,13 @@ static int snmp_agent_unregister_oid_index(oid_t *oid, int index); static u_char snmp_agent_get_asn_type(oid *oid, size_t oid_len) { struct tree *node = get_tree(oid, oid_len, g_agent->tp); - return (node != NULL ? mib_to_asn_type(node->type) : 0); + return (node != NULL) ? mib_to_asn_type(node->type) : 0; } static char *snmp_agent_get_oid_name(oid *oid, size_t oid_len) { struct tree *node = get_tree(oid, oid_len, g_agent->tp); - return (node != NULL ? node->label : NULL); + return (node != NULL) ? node->label : NULL; } static int snmp_agent_oid_to_string(char *buf, size_t buf_size, @@ -127,7 +127,7 @@ static int snmp_agent_oid_to_string(char *buf, size_t buf_size, oid_str_ptr[i] = oid_str[i]; } - return (strjoin(buf, buf_size, oid_str_ptr, o->oid_len, ".")); + return strjoin(buf, buf_size, oid_str_ptr, o->oid_len, "."); } static void snmp_agent_dump_data(void) { @@ -210,20 +210,20 @@ static int snmp_agent_validate_data(void) { if (!dd->plugin) { ERROR(PLUGIN_NAME ": Plugin not defined for '%s'.'%s'", td->name, dd->name); - return (-EINVAL); + return -EINVAL; } if (dd->plugin_instance) { ERROR(PLUGIN_NAME ": PluginInstance should not be defined for table " "data type '%s'.'%s'", td->name, dd->name); - return (-EINVAL); + return -EINVAL; } if (dd->oids_len == 0) { ERROR(PLUGIN_NAME ": No OIDs defined for '%s'.'%s'", td->name, dd->name); - return (-EINVAL); + return -EINVAL; } if (dd->is_instance) { @@ -232,7 +232,7 @@ static int snmp_agent_validate_data(void) { ERROR(PLUGIN_NAME ": Type and TypeInstance are not valid for " "instance data '%s'.'%s'", td->name, dd->name); - return (-EINVAL); + return -EINVAL; } if (dd->oids_len > 1) { @@ -240,14 +240,14 @@ static int snmp_agent_validate_data(void) { PLUGIN_NAME ": Only one OID should be specified for instance data '%s'.'%s'", td->name, dd->name); - return (-EINVAL); + return -EINVAL; } } else { if (!dd->type) { ERROR(PLUGIN_NAME ": Type not defined for data '%s'.'%s'", td->name, dd->name); - return (-EINVAL); + return -EINVAL; } } } @@ -258,28 +258,28 @@ static int snmp_agent_validate_data(void) { if (!dd->plugin) { ERROR(PLUGIN_NAME ": Plugin not defined for '%s'", dd->name); - return (-EINVAL); + return -EINVAL; } if (dd->oids_len == 0) { ERROR(PLUGIN_NAME ": No OIDs defined for '%s'", dd->name); - return (-EINVAL); + return -EINVAL; } if (dd->is_instance) { ERROR(PLUGIN_NAME ": Instance flag can't be specified for scalar data '%s'", dd->name); - return (-EINVAL); + return -EINVAL; } if (!dd->type) { ERROR(PLUGIN_NAME ": Type not defined for data '%s'", dd->name); - return (-EINVAL); + return -EINVAL; } } - return (0); + return 0; } static void snmp_agent_generate_oid2string(oid_t *oid, int offset, char *key) { @@ -300,7 +300,7 @@ static int snmp_agent_generate_string2oid(oid_t *oid, const char *key) { oid->oid[oid->oid_len++] = key[i]; if (oid->oid_len >= MAX_OID_LEN) { ERROR(PLUGIN_NAME ": Conversion key string %s to OID failed", key); - return (-EINVAL); + return -EINVAL; } } @@ -338,10 +338,10 @@ static int snmp_agent_table_row_remove(table_definition_t *td, if (td->index_oid.oid_len) { if ((c_avl_get(td->instance_index, instance, (void **)&index) != 0) || (c_avl_get(td->index_instance, index, (void **)&ins) != 0)) - return (0); + return 0; } else { if (c_avl_get(td->instance_index, instance, (void **)&ins) != 0) - return (0); + return 0; } pthread_mutex_lock(&g_agent->agentx_lock); @@ -383,13 +383,13 @@ static int snmp_agent_table_row_remove(table_definition_t *td, sfree(ins); } - return (0); + return 0; } static int snmp_agent_clear_missing(const value_list_t *vl, __attribute__((unused)) user_data_t *ud) { if (vl == NULL) - return (-EINVAL); + return -EINVAL; for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { table_definition_t *td = te->value; @@ -401,13 +401,13 @@ static int snmp_agent_clear_missing(const value_list_t *vl, if (CHECK_DD_TYPE(dd, vl->plugin, vl->plugin_instance, vl->type, vl->type_instance)) { snmp_agent_table_row_remove(td, vl->plugin_instance); - return (0); + return 0; } } } } - return (0); + return 0; } static void snmp_agent_free_data(data_definition_t **dd) { @@ -810,7 +810,7 @@ static int snmp_agent_register_table_oids(void) { } } - return (0); + return 0; } static int snmp_agent_register_scalar_oids(void) { @@ -830,20 +830,20 @@ static int snmp_agent_register_scalar_oids(void) { } } - return (0); + return 0; } static int snmp_agent_config_data_oids(data_definition_t *dd, oconfig_item_t *ci) { if (ci->values_num < 1) { WARNING(PLUGIN_NAME ": `OIDs' needs at least one argument"); - return (-EINVAL); + return -EINVAL; } for (int i = 0; i < ci->values_num; i++) if (ci->values[i].type != OCONFIG_TYPE_STRING) { WARNING(PLUGIN_NAME ": `OIDs' needs only string argument"); - return (-EINVAL); + return -EINVAL; } if (dd->oids != NULL) @@ -851,7 +851,7 @@ static int snmp_agent_config_data_oids(data_definition_t *dd, dd->oids_len = 0; dd->oids = calloc(ci->values_num, sizeof(*dd->oids)); if (dd->oids == NULL) - return (-ENOMEM); + return -ENOMEM; dd->oids_len = (size_t)ci->values_num; for (int i = 0; i < ci->values_num; i++) { @@ -863,23 +863,23 @@ static int snmp_agent_config_data_oids(data_definition_t *dd, ci->values[i].value.string); sfree(dd->oids); dd->oids_len = 0; - return (-1); + return -1; } } - return (0); + return 0; } static int snmp_agent_config_table_size_oid(table_definition_t *td, oconfig_item_t *ci) { if (ci->values_num < 1) { WARNING(PLUGIN_NAME ": `TableSizeOID' is empty"); - return (-EINVAL); + return -EINVAL; } if (ci->values[0].type != OCONFIG_TYPE_STRING) { WARNING(PLUGIN_NAME ": `TableSizeOID' needs only string argument"); - return (-EINVAL); + return -EINVAL; } td->size_oid.oid_len = MAX_OID_LEN; @@ -889,10 +889,10 @@ static int snmp_agent_config_table_size_oid(table_definition_t *td, ERROR(PLUGIN_NAME ": Failed to parse table size OID (%s)", ci->values[0].value.string); td->size_oid.oid_len = 0; - return (-EINVAL); + return -EINVAL; } - return (0); + return 0; } static int snmp_agent_config_table_index_oid(table_definition_t *td, @@ -900,12 +900,12 @@ static int snmp_agent_config_table_index_oid(table_definition_t *td, if (ci->values_num < 1) { WARNING(PLUGIN_NAME ": `IndexOID' is empty"); - return (-EINVAL); + return -EINVAL; } if (ci->values[0].type != OCONFIG_TYPE_STRING) { WARNING(PLUGIN_NAME ": `IndexOID' needs only string argument"); - return (-EINVAL); + return -EINVAL; } td->index_oid.oid_len = MAX_OID_LEN; @@ -915,10 +915,10 @@ static int snmp_agent_config_table_index_oid(table_definition_t *td, ERROR(PLUGIN_NAME ": Failed to parse table index OID (%s)", ci->values[0].value.string); td->index_oid.oid_len = 0; - return (-EINVAL); + return -EINVAL; } - return (0); + return 0; } static int snmp_agent_config_table_data(table_definition_t *td, @@ -931,13 +931,13 @@ static int snmp_agent_config_table_data(table_definition_t *td, dd = calloc(1, sizeof(*dd)); if (dd == NULL) { ERROR(PLUGIN_NAME ": Failed to allocate memory for table data definition"); - return (-ENOMEM); + return -ENOMEM; } ret = cf_util_get_string(ci, &dd->name); if (ret != 0) { sfree(dd); - return (-1); + return -1; } dd->scale = 1.0; @@ -971,19 +971,19 @@ static int snmp_agent_config_table_data(table_definition_t *td, if (ret != 0) { snmp_agent_free_data(&dd); - return (-1); + return -1; } } llentry_t *entry = llentry_create(dd->name, dd); if (entry == NULL) { snmp_agent_free_data(&dd); - return (-ENOMEM); + return -ENOMEM; } llist_append(td->columns, entry); - return (0); + return 0; } static int snmp_agent_config_data(oconfig_item_t *ci) { @@ -995,13 +995,13 @@ static int snmp_agent_config_data(oconfig_item_t *ci) { dd = calloc(1, sizeof(*dd)); if (dd == NULL) { ERROR(PLUGIN_NAME ": Failed to allocate memory for data definition"); - return (-ENOMEM); + return -ENOMEM; } ret = cf_util_get_string(ci, &dd->name); if (ret != 0) { free(dd); - return (-1); + return -1; } dd->scale = 1.0; @@ -1033,29 +1033,29 @@ static int snmp_agent_config_data(oconfig_item_t *ci) { if (ret != 0) { snmp_agent_free_data(&dd); - return (-1); + return -1; } } llentry_t *entry = llentry_create(dd->name, dd); if (entry == NULL) { snmp_agent_free_data(&dd); - return (-ENOMEM); + return -ENOMEM; } llist_append(g_agent->scalars, entry); - return (0); + return 0; } static int num_compare(const int *a, const int *b) { assert((a != NULL) && (b != NULL)); if (*a < *b) - return (-1); + return -1; else if (*a > *b) - return (1); + return 1; else - return (0); + return 0; } static int snmp_agent_config_table(oconfig_item_t *ci) { @@ -1067,20 +1067,20 @@ static int snmp_agent_config_table(oconfig_item_t *ci) { td = calloc(1, sizeof(*td)); if (td == NULL) { ERROR(PLUGIN_NAME ": Failed to allocate memory for table definition"); - return (-ENOMEM); + return -ENOMEM; } ret = cf_util_get_string(ci, &td->name); if (ret != 0) { sfree(td); - return (-1); + return -1; } td->columns = llist_create(); if (td->columns == NULL) { ERROR(PLUGIN_NAME ": Failed to allocate memory for columns list"); snmp_agent_free_table(&td); - return (-ENOMEM); + return -ENOMEM; } for (int i = 0; i < ci->children_num; i++) { @@ -1099,33 +1099,33 @@ static int snmp_agent_config_table(oconfig_item_t *ci) { if (ret != 0) { snmp_agent_free_table(&td); - return (-ENOMEM); + return -ENOMEM; } } llentry_t *entry = llentry_create(td->name, td); if (entry == NULL) { snmp_agent_free_table(&td); - return (-ENOMEM); + return -ENOMEM; } td->instance_index = c_avl_create((int (*)(const void *, const void *))strcmp); if (td->instance_index == NULL) { snmp_agent_free_table(&td); - return (-ENOMEM); + return -ENOMEM; } td->index_instance = c_avl_create((int (*)(const void *, const void *))num_compare); if (td->index_instance == NULL) { snmp_agent_free_table(&td); - return (-ENOMEM); + return -ENOMEM; } llist_append(g_agent->tables, entry); - return (0); + return 0; } static int snmp_agent_get_value_from_ds_type(const value_t *val, int type, @@ -1148,10 +1148,10 @@ static int snmp_agent_get_value_from_ds_type(const value_t *val, int type, break; default: ERROR(PLUGIN_NAME ": Unknown data source type: %i", type); - return (-EINVAL); + return -EINVAL; } - return (0); + return 0; } static int snmp_agent_set_vardata(void *data, size_t *data_len, u_char asn_type, @@ -1177,13 +1177,13 @@ static int snmp_agent_set_vardata(void *data, size_t *data_len, u_char asn_type, case ASN_TIMETICKS: case ASN_GAUGE: if (*data_len < sizeof(*var.integer)) - return (-EINVAL); + return -EINVAL; *var.integer = new_value; *data_len = sizeof(*var.integer); break; case ASN_COUNTER64: if (*data_len < sizeof(*var.counter64)) - return (-EINVAL); + return -EINVAL; var.counter64->high = (u_long)((int64_t)new_value >> 32); var.counter64->low = (u_long)((int64_t)new_value & 0xFFFFFFFF); *data_len = sizeof(*var.counter64); @@ -1193,22 +1193,22 @@ static int snmp_agent_set_vardata(void *data, size_t *data_len, u_char asn_type, char buf[DATA_MAX_NAME_LEN]; snprintf(buf, sizeof(buf), "%.2f", val->gauge); if (*data_len < strlen(buf)) - return (-EINVAL); + return -EINVAL; *data_len = strlen(buf); memcpy(var.string, buf, *data_len); } else { ERROR(PLUGIN_NAME ": Failed to convert %d ds type to %d asn type", type, asn_type); - return (-EINVAL); + return -EINVAL; } break; default: ERROR(PLUGIN_NAME ": Failed to convert %d ds type to %d asn type", type, asn_type); - return (-EINVAL); + return -EINVAL; } - return (0); + return 0; } static int snmp_agent_register_oid_index(oid_t *oid, int index, @@ -1230,7 +1230,7 @@ static int snmp_agent_update_index(table_definition_t *td, const char *instance) { if (c_avl_get(td->instance_index, instance, NULL) == 0) - return (0); + return 0; int ret; int *index = NULL; @@ -1238,14 +1238,14 @@ static int snmp_agent_update_index(table_definition_t *td, ins = strdup(instance); if (ins == NULL) - return (-ENOMEM); + return -ENOMEM; /* need to generate index for the table */ if (td->index_oid.oid_len) { index = calloc(1, sizeof(*index)); if (index == NULL) { sfree(ins); - return (-ENOMEM); + return -ENOMEM; } *index = c_avl_size(td->instance_index) + 1; @@ -1310,13 +1310,13 @@ static int snmp_agent_update_index(table_definition_t *td, (index != NULL) ? *index : -1); plugin_dispatch_notification(&n); - return (0); + return 0; } static int snmp_agent_write(value_list_t const *vl) { if (vl == NULL) - return (-EINVAL); + return -EINVAL; for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) { table_definition_t *td = te->value; @@ -1328,13 +1328,13 @@ static int snmp_agent_write(value_list_t const *vl) { if (CHECK_DD_TYPE(dd, vl->plugin, vl->plugin_instance, vl->type, vl->type_instance)) { snmp_agent_update_index(td, vl->plugin_instance); - return (0); + return 0; } } } } - return (0); + return 0; } static int snmp_agent_collect(const data_set_t *ds, const value_list_t *vl, @@ -1346,19 +1346,19 @@ static int snmp_agent_collect(const data_set_t *ds, const value_list_t *vl, pthread_mutex_unlock(&g_agent->lock); - return (0); + return 0; } static int snmp_agent_preinit(void) { if (g_agent != NULL) { /* already initialized if config callback was called before init callback */ - return (0); + return 0; } g_agent = calloc(1, sizeof(*g_agent)); if (g_agent == NULL) { ERROR(PLUGIN_NAME ": Failed to allocate memory for snmp agent context"); - return (-ENOMEM); + return -ENOMEM; } g_agent->tables = llist_create(); @@ -1370,7 +1370,7 @@ static int snmp_agent_preinit(void) { 1); if (err != 0) { ERROR(PLUGIN_NAME ": Failed to set agent role (%d)", err); - return (-1); + return -1; } /* @@ -1381,14 +1381,14 @@ static int snmp_agent_preinit(void) { err = init_agent(PLUGIN_NAME); if (err != 0) { ERROR(PLUGIN_NAME ": Failed to initialize the agent library (%d)", err); - return (-1); + return -1; } init_snmp(PLUGIN_NAME); g_agent->tp = read_all_mibs(); - return (0); + return 0; } static int snmp_agent_init(void) { @@ -1425,7 +1425,7 @@ static int snmp_agent_init(void) { return ret; } - return (0); + return 0; } static void *snmp_agent_thread_run(void __attribute__((unused)) * arg) { @@ -1456,7 +1456,7 @@ static int snmp_agent_register_oid(oid_t *oid, Netsnmp_Node_Handler *handler) { WARNING(PLUGIN_NAME ": Skipped registration: OID (%s) is not found in main tree", oid_str); - return (0); + return 0; } reg = netsnmp_create_handler_registration(oid_name, handler, oid->oid, @@ -1464,7 +1464,7 @@ static int snmp_agent_register_oid(oid_t *oid, Netsnmp_Node_Handler *handler) { if (reg == NULL) { ERROR(PLUGIN_NAME ": Failed to create handler registration for OID (%s)", oid_str); - return (-1); + return -1; } pthread_mutex_lock(&g_agent->agentx_lock); @@ -1472,20 +1472,20 @@ static int snmp_agent_register_oid(oid_t *oid, Netsnmp_Node_Handler *handler) { if (netsnmp_register_instance(reg) != MIB_REGISTERED_OK) { ERROR(PLUGIN_NAME ": Failed to register handler for OID (%s)", oid_str); pthread_mutex_unlock(&g_agent->agentx_lock); - return (-1); + return -1; } pthread_mutex_unlock(&g_agent->agentx_lock); DEBUG(PLUGIN_NAME ": Registered handler for OID (%s)", oid_str); - return (0); + return 0; } static int snmp_agent_free_config(void) { if (g_agent == NULL) - return (-EINVAL); + return -EINVAL; for (llentry_t *te = llist_head(g_agent->tables); te != NULL; te = te->next) snmp_agent_free_table((table_definition_t **)&te->value); @@ -1495,7 +1495,7 @@ static int snmp_agent_free_config(void) { snmp_agent_free_data((data_definition_t **)&de->value); llist_destroy(g_agent->scalars); - return (0); + return 0; } static int snmp_agent_shutdown(void) { @@ -1505,7 +1505,7 @@ static int snmp_agent_shutdown(void) { if (g_agent == NULL) { ERROR(PLUGIN_NAME ": snmp_agent_shutdown: plugin not initialized"); - return (-EINVAL); + return -EINVAL; } if (pthread_cancel(g_agent->thread) != 0) @@ -1532,7 +1532,7 @@ static int snmp_agent_config(oconfig_item_t *ci) { if (ret != 0) { sfree(g_agent); - return (-EINVAL); + return -EINVAL; } for (int i = 0; i < ci->children_num; i++) { @@ -1551,7 +1551,7 @@ static int snmp_agent_config(oconfig_item_t *ci) { snmp_agent_free_config(); snmp_shutdown(PLUGIN_NAME); sfree(g_agent); - return (-EINVAL); + return -EINVAL; } } @@ -1561,10 +1561,10 @@ static int snmp_agent_config(oconfig_item_t *ci) { snmp_agent_free_config(); snmp_shutdown(PLUGIN_NAME); sfree(g_agent); - return (-EINVAL); + return -EINVAL; } - return (0); + return 0; } void module_register(void) { From 1634cdf408671dc430d2860bc98acd1d8a3f84e6 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Wed, 17 May 2017 11:31:25 +0200 Subject: [PATCH 11/11] snmp_agent plugin: Don't export the g_agent variable. --- src/snmp_agent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/snmp_agent.c b/src/snmp_agent.c index 89718bd033..6cbe881a04 100644 --- a/src/snmp_agent.c +++ b/src/snmp_agent.c @@ -90,7 +90,7 @@ struct snmp_agent_ctx_s { }; typedef struct snmp_agent_ctx_s snmp_agent_ctx_t; -snmp_agent_ctx_t *g_agent = NULL; +static snmp_agent_ctx_t *g_agent = NULL; #define CHECK_DD_TYPE(_dd, _p, _pi, _t, _ti) \ (_dd->plugin ? !strcmp(_dd->plugin, _p) : 0) && \