2 * collectd - src/snmp.c
3 * Copyright (C) 2007-2012 Florian octo Forster
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Florian octo Forster <octo at collectd.org>
25 #include "utils_complain.h"
29 #include <net-snmp/net-snmp-config.h>
30 #include <net-snmp/net-snmp-includes.h>
33 * Private data structes
40 typedef struct oid_s oid_t;
44 char string[DATA_MAX_NAME_LEN];
47 typedef union instance_u instance_t;
49 struct data_definition_s
51 char *name; /* used to reference this from the `Collect' option */
52 char *type; /* used to find the data_set */
55 char *instance_prefix;
60 struct data_definition_s *next;
62 typedef struct data_definition_s data_definition_t;
64 struct host_definition_s
70 /* snmpv1/2 options */
73 /* snmpv3 security options */
76 size_t auth_protocol_len;
77 char *auth_passphrase;
79 size_t priv_protocol_len;
80 char *priv_passphrase;
85 c_complain_t complaint;
87 data_definition_t **data_list;
90 typedef struct host_definition_s host_definition_t;
92 /* These two types are used to cache values in `csnmp_read_table' to handle
94 struct csnmp_list_instances_s
97 char instance[DATA_MAX_NAME_LEN];
98 struct csnmp_list_instances_s *next;
100 typedef struct csnmp_list_instances_s csnmp_list_instances_t;
102 struct csnmp_table_values_s
106 struct csnmp_table_values_s *next;
108 typedef struct csnmp_table_values_s csnmp_table_values_t;
113 static data_definition_t *data_head = NULL;
118 static int csnmp_read_host (user_data_t *ud);
123 static void csnmp_oid_init (oid_t *dst, oid const *src, size_t n)
125 assert (n <= STATIC_ARRAY_SIZE (dst->oid));
126 memcpy (dst->oid, src, sizeof (*src) * n);
130 static int csnmp_oid_compare (oid_t const *left, oid_t const *right)
132 return (snmp_oid_compare (left->oid, left->oid_len,
133 right->oid, right->oid_len));
136 static int csnmp_oid_suffix (oid_t *dst, oid_t const *src,
139 /* Make sure "src" is in "root"s subtree. */
140 if (src->oid_len <= root->oid_len)
142 if (snmp_oid_ncompare (root->oid, root->oid_len,
143 src->oid, src->oid_len,
144 /* n = */ root->oid_len) != 0)
147 memset (dst, 0, sizeof (*dst));
148 dst->oid_len = src->oid_len - root->oid_len;
149 memcpy (dst->oid, &src->oid[root->oid_len],
150 dst->oid_len * sizeof (dst->oid[0]));
154 static int csnmp_oid_to_string (char *buffer, size_t buffer_size,
157 char oid_str[MAX_OID_LEN][16];
158 char *oid_str_ptr[MAX_OID_LEN];
161 for (i = 0; i < o->oid_len; i++)
163 ssnprintf (oid_str[i], sizeof (oid_str[i]), "%lu", (unsigned long) o->oid[i]);
164 oid_str_ptr[i] = oid_str[i];
167 return (strjoin (buffer, buffer_size,
168 oid_str_ptr, o->oid_len, /* separator = */ "."));
171 static void csnmp_host_close_session (host_definition_t *host) /* {{{ */
173 if (host->sess_handle == NULL)
176 snmp_sess_close (host->sess_handle);
177 host->sess_handle = NULL;
178 } /* }}} void csnmp_host_close_session */
180 static void csnmp_host_definition_destroy (void *arg) /* {{{ */
182 host_definition_t *hd;
189 if (hd->name != NULL)
191 DEBUG ("snmp plugin: Destroying host definition for host `%s'.",
195 csnmp_host_close_session (hd);
199 sfree (hd->community);
200 sfree (hd->username);
201 sfree (hd->auth_passphrase);
202 sfree (hd->priv_passphrase);
204 sfree (hd->data_list);
207 } /* }}} void csnmp_host_definition_destroy */
209 /* Many functions to handle the configuration. {{{ */
210 /* First there are many functions which do configuration stuff. It's a big
211 * bloated and messy, I'm afraid. */
214 * Callgraph for the config stuff:
216 * +-> call_snmp_init_once
217 * +-> csnmp_config_add_data
218 * ! +-> csnmp_config_add_data_type
219 * ! +-> csnmp_config_add_data_table
220 * ! +-> csnmp_config_add_data_instance
221 * ! +-> csnmp_config_add_data_instance_prefix
222 * ! +-> csnmp_config_add_data_values
223 * +-> csnmp_config_add_host
224 * +-> csnmp_config_add_host_address
225 * +-> csnmp_config_add_host_community
226 * +-> csnmp_config_add_host_version
227 * +-> csnmp_config_add_host_collect
228 * +-> csnmp_config_add_host_username
229 * +-> csnmp_config_add_host_auth_protocol
230 * +-> csnmp_config_add_host_priv_protocol
231 * +-> csnmp_config_add_host_auth_passphrase
232 * +-> csnmp_config_add_host_priv_passphrase
233 * +-> csnmp_config_add_host_security_level
234 * +-> esnmp_config_add_host_context
236 static void call_snmp_init_once (void)
238 static int have_init = 0;
241 init_snmp (PACKAGE_NAME);
243 } /* void call_snmp_init_once */
245 static int csnmp_config_add_data_type (data_definition_t *dd, oconfig_item_t *ci)
247 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
249 WARNING ("snmp plugin: `Type' needs exactly one string argument.");
254 dd->type = strdup (ci->values[0].value.string);
255 if (dd->type == NULL)
259 } /* int csnmp_config_add_data_type */
261 static int csnmp_config_add_data_table (data_definition_t *dd, oconfig_item_t *ci)
263 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
265 WARNING ("snmp plugin: `Table' needs exactly one boolean argument.");
269 dd->is_table = ci->values[0].value.boolean ? 1 : 0;
272 } /* int csnmp_config_add_data_table */
274 static int csnmp_config_add_data_instance (data_definition_t *dd, oconfig_item_t *ci)
276 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
278 WARNING ("snmp plugin: `Instance' needs exactly one string argument.");
284 /* Instance is an OID */
285 dd->instance.oid.oid_len = MAX_OID_LEN;
287 if (!read_objid (ci->values[0].value.string,
288 dd->instance.oid.oid, &dd->instance.oid.oid_len))
290 ERROR ("snmp plugin: read_objid (%s) failed.",
291 ci->values[0].value.string);
297 /* Instance is a simple string */
298 sstrncpy (dd->instance.string, ci->values[0].value.string,
299 sizeof (dd->instance.string));
303 } /* int csnmp_config_add_data_instance */
305 static int csnmp_config_add_data_instance_prefix (data_definition_t *dd,
308 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
310 WARNING ("snmp plugin: `InstancePrefix' needs exactly one string argument.");
316 WARNING ("snmp plugin: data %s: InstancePrefix is ignored when `Table' "
317 "is set to `false'.", dd->name);
321 sfree (dd->instance_prefix);
322 dd->instance_prefix = strdup (ci->values[0].value.string);
323 if (dd->instance_prefix == NULL)
327 } /* int csnmp_config_add_data_instance_prefix */
329 static int csnmp_config_add_data_values (data_definition_t *dd, oconfig_item_t *ci)
333 if (ci->values_num < 1)
335 WARNING ("snmp plugin: `Values' needs at least one argument.");
339 for (i = 0; i < ci->values_num; i++)
340 if (ci->values[i].type != OCONFIG_TYPE_STRING)
342 WARNING ("snmp plugin: `Values' needs only string argument.");
348 dd->values = (oid_t *) malloc (sizeof (oid_t) * ci->values_num);
349 if (dd->values == NULL)
351 dd->values_len = ci->values_num;
353 for (i = 0; i < ci->values_num; i++)
355 dd->values[i].oid_len = MAX_OID_LEN;
357 if (NULL == snmp_parse_oid (ci->values[i].value.string,
358 dd->values[i].oid, &dd->values[i].oid_len))
360 ERROR ("snmp plugin: snmp_parse_oid (%s) failed.",
361 ci->values[i].value.string);
370 } /* int csnmp_config_add_data_instance */
372 static int csnmp_config_add_data_shift (data_definition_t *dd, oconfig_item_t *ci)
374 if ((ci->values_num != 1)
375 || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
377 WARNING ("snmp plugin: The `Shift' config option needs exactly one number argument.");
381 dd->shift = ci->values[0].value.number;
384 } /* int csnmp_config_add_data_shift */
386 static int csnmp_config_add_data_scale (data_definition_t *dd, oconfig_item_t *ci)
388 if ((ci->values_num != 1)
389 || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
391 WARNING ("snmp plugin: The `Scale' config option needs exactly one number argument.");
395 dd->scale = ci->values[0].value.number;
398 } /* int csnmp_config_add_data_scale */
400 static int csnmp_config_add_data (oconfig_item_t *ci)
402 data_definition_t *dd;
406 if ((ci->values_num != 1)
407 || (ci->values[0].type != OCONFIG_TYPE_STRING))
409 WARNING ("snmp plugin: The `Data' config option needs exactly one string argument.");
413 dd = (data_definition_t *) malloc (sizeof (data_definition_t));
416 memset (dd, '\0', sizeof (data_definition_t));
418 dd->name = strdup (ci->values[0].value.string);
419 if (dd->name == NULL)
427 for (i = 0; i < ci->children_num; i++)
429 oconfig_item_t *option = ci->children + i;
432 if (strcasecmp ("Type", option->key) == 0)
433 status = csnmp_config_add_data_type (dd, option);
434 else if (strcasecmp ("Table", option->key) == 0)
435 status = csnmp_config_add_data_table (dd, option);
436 else if (strcasecmp ("Instance", option->key) == 0)
437 status = csnmp_config_add_data_instance (dd, option);
438 else if (strcasecmp ("InstancePrefix", option->key) == 0)
439 status = csnmp_config_add_data_instance_prefix (dd, option);
440 else if (strcasecmp ("Values", option->key) == 0)
441 status = csnmp_config_add_data_values (dd, option);
442 else if (strcasecmp ("Shift", option->key) == 0)
443 status = csnmp_config_add_data_shift (dd, option);
444 else if (strcasecmp ("Scale", option->key) == 0)
445 status = csnmp_config_add_data_scale (dd, option);
448 WARNING ("snmp plugin: Option `%s' not allowed here.", option->key);
454 } /* for (ci->children) */
458 if (dd->type == NULL)
460 WARNING ("snmp plugin: `Type' not given for data `%s'", dd->name);
464 if (dd->values == NULL)
466 WARNING ("snmp plugin: No `Value' given for data `%s'", dd->name);
472 } /* while (status == 0) */
477 sfree (dd->instance_prefix);
483 DEBUG ("snmp plugin: dd = { name = %s, type = %s, is_table = %s, values_len = %i }",
484 dd->name, dd->type, (dd->is_table != 0) ? "true" : "false", dd->values_len);
486 if (data_head == NULL)
490 data_definition_t *last;
492 while (last->next != NULL)
498 } /* int csnmp_config_add_data */
500 static int csnmp_config_add_host_address (host_definition_t *hd, oconfig_item_t *ci)
502 if ((ci->values_num != 1)
503 || (ci->values[0].type != OCONFIG_TYPE_STRING))
505 WARNING ("snmp plugin: The `Address' config option needs exactly one string argument.");
509 if (hd->address == NULL)
512 hd->address = strdup (ci->values[0].value.string);
513 if (hd->address == NULL)
516 DEBUG ("snmp plugin: host = %s; host->address = %s;",
517 hd->name, hd->address);
520 } /* int csnmp_config_add_host_address */
522 static int csnmp_config_add_host_community (host_definition_t *hd, oconfig_item_t *ci)
524 if ((ci->values_num != 1)
525 || (ci->values[0].type != OCONFIG_TYPE_STRING))
527 WARNING ("snmp plugin: The `Community' config option needs exactly one string argument.");
531 if (hd->community == NULL)
532 free (hd->community);
534 hd->community = strdup (ci->values[0].value.string);
535 if (hd->community == NULL)
538 DEBUG ("snmp plugin: host = %s; host->community = %s;",
539 hd->name, hd->community);
542 } /* int csnmp_config_add_host_community */
544 static int csnmp_config_add_host_version (host_definition_t *hd, oconfig_item_t *ci)
548 if ((ci->values_num != 1)
549 || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
551 WARNING ("snmp plugin: The `Version' config option needs exactly one number argument.");
555 version = (int) ci->values[0].value.number;
556 if ((version < 1) || (version > 3))
558 WARNING ("snmp plugin: `Version' must either be `1', `2', or `3'.");
562 hd->version = version;
565 } /* int csnmp_config_add_host_address */
567 static int csnmp_config_add_host_collect (host_definition_t *host,
570 data_definition_t *data;
571 data_definition_t **data_list;
575 if (ci->values_num < 1)
577 WARNING ("snmp plugin: `Collect' needs at least one argument.");
581 for (i = 0; i < ci->values_num; i++)
582 if (ci->values[i].type != OCONFIG_TYPE_STRING)
584 WARNING ("snmp plugin: All arguments to `Collect' must be strings.");
588 data_list_len = host->data_list_len + ci->values_num;
589 data_list = (data_definition_t **) realloc (host->data_list,
590 sizeof (data_definition_t *) * data_list_len);
591 if (data_list == NULL)
593 host->data_list = data_list;
595 for (i = 0; i < ci->values_num; i++)
597 for (data = data_head; data != NULL; data = data->next)
598 if (strcasecmp (ci->values[i].value.string, data->name) == 0)
603 WARNING ("snmp plugin: No such data configured: `%s'",
604 ci->values[i].value.string);
608 DEBUG ("snmp plugin: Collect: host = %s, data[%i] = %s;",
609 host->name, host->data_list_len, data->name);
611 host->data_list[host->data_list_len] = data;
612 host->data_list_len++;
613 } /* for (values_num) */
616 } /* int csnmp_config_add_host_collect */
618 static int csnmp_config_add_host_username (host_definition_t *hd, oconfig_item_t *ci)
620 if ((ci->values_num != 1)
621 || (ci->values[0].type != OCONFIG_TYPE_STRING))
623 WARNING ("snmp plugin: The `Username' config option needs exactly one string argument.");
628 hd->username = strdup (ci->values[0].value.string);
629 if (hd->username == NULL)
632 DEBUG ("snmp plugin: host = %s; host->username = %s;",
633 hd->name, hd->username);
636 } /* int csnmp_config_add_host_username */
638 static int csnmp_config_add_host_auth_protocol (host_definition_t *hd, oconfig_item_t *ci)
640 if ((ci->values_num != 1)
641 || (ci->values[0].type != OCONFIG_TYPE_STRING)
642 || ((strcasecmp("MD5", ci->values[0].value.string) != 0)
643 && (strcasecmp("SHA", ci->values[0].value.string) != 0)))
645 WARNING ("snmp plugin: The `AuthProtocol' config option must be `MD5' or `SHA'.");
649 if (strcasecmp("MD5", ci->values[0].value.string) == 0) {
650 hd->auth_protocol = usmHMACMD5AuthProtocol;
651 hd->auth_protocol_len = sizeof(usmHMACMD5AuthProtocol)/sizeof(oid);
653 else if (strcasecmp("SHA", ci->values[0].value.string) == 0) {
654 hd->auth_protocol = usmHMACSHA1AuthProtocol;
655 hd->auth_protocol_len = sizeof(usmHMACSHA1AuthProtocol)/sizeof(oid);
658 DEBUG ("snmp plugin: host = %s; host->auth_protocol = %s;",
659 hd->name, hd->auth_protocol == usmHMACMD5AuthProtocol ? "MD5" : "SHA");
662 } /* int csnmp_config_add_host_auth_protocol */
664 static int csnmp_config_add_host_priv_protocol (host_definition_t *hd, oconfig_item_t *ci)
666 if ((ci->values_num != 1)
667 || (ci->values[0].type != OCONFIG_TYPE_STRING)
668 || ((strcasecmp("AES", ci->values[0].value.string) != 0)
669 && (strcasecmp("DES", ci->values[0].value.string) != 0)))
671 WARNING ("snmp plugin: The `PrivProtocol' config option must be `AES' or `DES'.");
675 if (strcasecmp("AES", ci->values[0].value.string) == 0) {
676 hd->priv_protocol = usmAESPrivProtocol;
677 hd->priv_protocol_len = sizeof(usmAESPrivProtocol)/sizeof(oid);
679 else if (strcasecmp("DES", ci->values[0].value.string) == 0) {
680 hd->priv_protocol = usmDESPrivProtocol;
681 hd->priv_protocol_len = sizeof(usmDESPrivProtocol)/sizeof(oid);
684 DEBUG ("snmp plugin: host = %s; host->priv_protocol = %s;",
685 hd->name, hd->priv_protocol == usmAESPrivProtocol ? "AES" : "DES");
688 } /* int csnmp_config_add_host_priv_protocol */
690 static int csnmp_config_add_host_auth_passphrase (host_definition_t *hd, oconfig_item_t *ci)
692 if ((ci->values_num != 1)
693 || (ci->values[0].type != OCONFIG_TYPE_STRING))
695 WARNING ("snmp plugin: The `AuthPassphrase' config option needs exactly one string argument.");
699 free (hd->auth_passphrase);
700 hd->auth_passphrase = strdup (ci->values[0].value.string);
701 if (hd->auth_passphrase == NULL)
704 DEBUG ("snmp plugin: host = %s; host->auth_passphrase = %s;",
705 hd->name, hd->auth_passphrase);
708 } /* int csnmp_config_add_host_auth_passphrase */
710 static int csnmp_config_add_host_priv_passphrase (host_definition_t *hd, oconfig_item_t *ci)
712 if ((ci->values_num != 1)
713 || (ci->values[0].type != OCONFIG_TYPE_STRING))
715 WARNING ("snmp plugin: The `PrivacyPassphrase' config option needs exactly one string argument.");
719 free (hd->priv_passphrase);
720 hd->priv_passphrase = strdup (ci->values[0].value.string);
721 if (hd->priv_passphrase == NULL)
724 DEBUG ("snmp plugin: host = %s; host->priv_passphrase = %s;",
725 hd->name, hd->priv_passphrase);
728 } /* int csnmp_config_add_host_priv_passphrase */
730 static int csnmp_config_add_host_security_level (host_definition_t *hd, oconfig_item_t *ci)
732 if ((ci->values_num != 1)
733 || (ci->values[0].type != OCONFIG_TYPE_STRING)
734 || ((strcasecmp("noAuthNoPriv", ci->values[0].value.string) != 0)
735 && (strcasecmp("authNoPriv", ci->values[0].value.string) != 0)
736 && (strcasecmp("authPriv", ci->values[0].value.string) != 0)))
738 WARNING ("snmp plugin: The `SecurityLevel' config option must be `noAuthNoPriv', `authNoPriv', or `authPriv'.");
742 if (strcasecmp("noAuthNoPriv", ci->values[0].value.string) == 0)
743 hd->security_level = SNMP_SEC_LEVEL_NOAUTH;
744 else if (strcasecmp("authNoPriv", ci->values[0].value.string) == 0)
745 hd->security_level = SNMP_SEC_LEVEL_AUTHNOPRIV;
746 else if (strcasecmp("authPriv", ci->values[0].value.string) == 0)
747 hd->security_level = SNMP_SEC_LEVEL_AUTHPRIV;
749 DEBUG ("snmp plugin: host = %s; host->security_level = %d;",
750 hd->name, hd->security_level);
753 } /* int csnmp_config_add_host_security_level */
755 static int csnmp_config_add_host_context (host_definition_t *hd, oconfig_item_t *ci)
757 if ((ci->values_num != 1)
758 || (ci->values[0].type != OCONFIG_TYPE_STRING))
760 WARNING ("snmp plugin: The `Context' config option needs exactly one string argument.");
765 hd->context = strdup (ci->values[0].value.string);
766 if (hd->context == NULL)
769 DEBUG ("snmp plugin: host = %s; host->context = %s;",
770 hd->name, hd->context);
773 } /* int csnmp_config_add_host_context */
777 static int csnmp_config_add_host (oconfig_item_t *ci)
779 host_definition_t *hd;
783 /* Registration stuff. */
784 char cb_name[DATA_MAX_NAME_LEN];
786 struct timespec cb_interval;
788 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
790 WARNING ("snmp plugin: `Host' needs exactly one string argument.");
794 hd = (host_definition_t *) malloc (sizeof (host_definition_t));
797 memset (hd, '\0', sizeof (host_definition_t));
799 C_COMPLAIN_INIT (&hd->complaint);
801 hd->name = strdup (ci->values[0].value.string);
802 if (hd->name == NULL)
808 hd->sess_handle = NULL;
811 for (i = 0; i < ci->children_num; i++)
813 oconfig_item_t *option = ci->children + i;
816 if (strcasecmp ("Address", option->key) == 0)
817 status = csnmp_config_add_host_address (hd, option);
818 else if (strcasecmp ("Community", option->key) == 0)
819 status = csnmp_config_add_host_community (hd, option);
820 else if (strcasecmp ("Version", option->key) == 0)
821 status = csnmp_config_add_host_version (hd, option);
822 else if (strcasecmp ("Collect", option->key) == 0)
823 csnmp_config_add_host_collect (hd, option);
824 else if (strcasecmp ("Interval", option->key) == 0)
825 cf_util_get_cdtime (option, &hd->interval);
826 else if (strcasecmp ("Username", option->key) == 0)
827 status = csnmp_config_add_host_username (hd, option);
828 else if (strcasecmp ("AuthProtocol", option->key) == 0)
829 status = csnmp_config_add_host_auth_protocol (hd, option);
830 else if (strcasecmp ("PrivacyProtocol", option->key) == 0)
831 status = csnmp_config_add_host_priv_protocol (hd, option);
832 else if (strcasecmp ("AuthPassphrase", option->key) == 0)
833 status = csnmp_config_add_host_auth_passphrase (hd, option);
834 else if (strcasecmp ("PrivacyPassphrase", option->key) == 0)
835 status = csnmp_config_add_host_priv_passphrase (hd, option);
836 else if (strcasecmp ("SecurityLevel", option->key) == 0)
837 status = csnmp_config_add_host_security_level (hd, option);
838 else if (strcasecmp ("Context", option->key) == 0)
839 status = csnmp_config_add_host_context (hd, option);
842 WARNING ("snmp plugin: csnmp_config_add_host: Option `%s' not allowed here.", option->key);
848 } /* for (ci->children) */
852 if (hd->address == NULL)
854 WARNING ("snmp plugin: `Address' not given for host `%s'", hd->name);
858 if (hd->community == NULL && hd->version < 3)
860 WARNING ("snmp plugin: `Community' not given for host `%s'", hd->name);
864 if (hd->version == 3)
866 if (hd->username == NULL)
868 WARNING ("snmp plugin: `Username' not given for host `%s'", hd->name);
872 if (hd->security_level == 0)
874 WARNING ("snmp plugin: `SecurityLevel' not given for host `%s'", hd->name);
878 if (hd->security_level == SNMP_SEC_LEVEL_AUTHNOPRIV || hd->security_level == SNMP_SEC_LEVEL_AUTHPRIV)
880 if (hd->auth_protocol == NULL)
882 WARNING ("snmp plugin: `AuthProtocol' not given for host `%s'", hd->name);
886 if (hd->auth_passphrase == NULL)
888 WARNING ("snmp plugin: `AuthPassphrase' not given for host `%s'", hd->name);
893 if (hd->security_level == SNMP_SEC_LEVEL_AUTHPRIV)
895 if (hd->priv_protocol == NULL)
897 WARNING ("snmp plugin: `PrivacyProtocol' not given for host `%s'", hd->name);
901 if (hd->priv_passphrase == NULL)
903 WARNING ("snmp plugin: `PrivacyPassphrase' not given for host `%s'", hd->name);
911 } /* while (status == 0) */
915 csnmp_host_definition_destroy (hd);
919 DEBUG ("snmp plugin: hd = { name = %s, address = %s, community = %s, version = %i }",
920 hd->name, hd->address, hd->community, hd->version);
922 ssnprintf (cb_name, sizeof (cb_name), "snmp-%s", hd->name);
924 memset (&cb_data, 0, sizeof (cb_data));
926 cb_data.free_func = csnmp_host_definition_destroy;
928 CDTIME_T_TO_TIMESPEC (hd->interval, &cb_interval);
930 status = plugin_register_complex_read (/* group = */ NULL, cb_name,
931 csnmp_read_host, /* interval = */ &cb_interval,
932 /* user_data = */ &cb_data);
935 ERROR ("snmp plugin: Registering complex read function failed.");
936 csnmp_host_definition_destroy (hd);
941 } /* int csnmp_config_add_host */
943 static int csnmp_config (oconfig_item_t *ci)
947 call_snmp_init_once ();
949 for (i = 0; i < ci->children_num; i++)
951 oconfig_item_t *child = ci->children + i;
952 if (strcasecmp ("Data", child->key) == 0)
953 csnmp_config_add_data (child);
954 else if (strcasecmp ("Host", child->key) == 0)
955 csnmp_config_add_host (child);
958 WARNING ("snmp plugin: Ignoring unknown config option `%s'.", child->key);
960 } /* for (ci->children) */
963 } /* int csnmp_config */
965 /* }}} End of the config stuff. Now the interesting part begins */
967 static void csnmp_host_open_session (host_definition_t *host)
969 struct snmp_session sess;
972 if (host->sess_handle != NULL)
973 csnmp_host_close_session (host);
975 snmp_sess_init (&sess);
976 sess.peername = host->address;
977 switch (host->version)
980 sess.version = SNMP_VERSION_1;
983 sess.version = SNMP_VERSION_3;
986 sess.version = SNMP_VERSION_2c;
990 if (host->version == 3)
992 sess.securityName = host->username;
993 sess.securityNameLen = strlen (host->username);
994 sess.securityLevel = host->security_level;
996 if (sess.securityLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || sess.securityLevel == SNMP_SEC_LEVEL_AUTHPRIV)
998 sess.securityAuthProto = host->auth_protocol;
999 sess.securityAuthProtoLen = host->auth_protocol_len;
1000 sess.securityAuthKeyLen = USM_AUTH_KU_LEN;
1001 error = generate_Ku (sess.securityAuthProto,
1002 sess.securityAuthProtoLen,
1003 (u_char *) host->auth_passphrase,
1004 strlen(host->auth_passphrase),
1005 sess.securityAuthKey,
1006 &sess.securityAuthKeyLen);
1007 if (error != SNMPERR_SUCCESS) {
1008 ERROR ("snmp plugin: host %s: Error generating Ku from auth_passphrase. (Error %d)", host->name, error);
1012 if (sess.securityLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1014 sess.securityPrivProto = host->priv_protocol;
1015 sess.securityPrivProtoLen = host->priv_protocol_len;
1016 sess.securityPrivKeyLen = USM_PRIV_KU_LEN;
1017 error = generate_Ku (sess.securityAuthProto,
1018 sess.securityAuthProtoLen,
1019 (u_char *) host->priv_passphrase,
1020 strlen(host->priv_passphrase),
1021 sess.securityPrivKey,
1022 &sess.securityPrivKeyLen);
1023 if (error != SNMPERR_SUCCESS) {
1024 ERROR ("snmp plugin: host %s: Error generating Ku from priv_passphrase. (Error %d)", host->name, error);
1028 if (host->context != NULL)
1030 sess.contextName = host->context;
1031 sess.contextNameLen = strlen (host->context);
1034 else /* SNMPv1/2 "authenticates" with community string */
1036 sess.community = (u_char *) host->community;
1037 sess.community_len = strlen (host->community);
1040 /* snmp_sess_open will copy the `struct snmp_session *'. */
1041 host->sess_handle = snmp_sess_open (&sess);
1043 if (host->sess_handle == NULL)
1045 char *errstr = NULL;
1047 snmp_error (&sess, NULL, NULL, &errstr);
1049 ERROR ("snmp plugin: host %s: snmp_sess_open failed: %s",
1050 host->name, (errstr == NULL) ? "Unknown problem" : errstr);
1053 } /* void csnmp_host_open_session */
1055 /* TODO: Check if negative values wrap around. Problem: negative temperatures. */
1056 static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
1057 double scale, double shift,
1058 const char *host_name, const char *data_name)
1061 uint64_t tmp_unsigned = 0;
1062 int64_t tmp_signed = 0;
1064 /* Set to true when the original SNMP type appears to have been signed. */
1065 _Bool prefer_signed = 0;
1067 if ((vl->type == ASN_INTEGER)
1068 || (vl->type == ASN_UINTEGER)
1069 || (vl->type == ASN_COUNTER)
1070 #ifdef ASN_TIMETICKS
1071 || (vl->type == ASN_TIMETICKS)
1073 || (vl->type == ASN_GAUGE))
1075 tmp_unsigned = (uint32_t) *vl->val.integer;
1076 tmp_signed = (int32_t) *vl->val.integer;
1078 if ((vl->type == ASN_INTEGER)
1079 || (vl->type == ASN_GAUGE))
1082 DEBUG ("snmp plugin: Parsed int32 value is %"PRIu64".", tmp_unsigned);
1084 else if (vl->type == ASN_COUNTER64)
1086 tmp_unsigned = (uint32_t) vl->val.counter64->high;
1087 tmp_unsigned = tmp_unsigned << 32;
1088 tmp_unsigned += (uint32_t) vl->val.counter64->low;
1089 tmp_signed = (int64_t) tmp_unsigned;
1090 DEBUG ("snmp plugin: Parsed int64 value is %"PRIu64".", tmp_unsigned);
1092 else if (vl->type == ASN_OCTET_STR)
1094 /* We'll handle this later.. */
1098 char oid_buffer[1024];
1100 memset (oid_buffer, 0, sizeof (oid_buffer));
1101 snprint_objid (oid_buffer, sizeof (oid_buffer) - 1,
1102 vl->name, vl->name_length);
1105 if (vl->type == ASN_NULL)
1106 INFO ("snmp plugin: OID \"%s\" is undefined (type ASN_NULL)",
1110 WARNING ("snmp plugin: I don't know the ASN type #%i "
1111 "(OID: \"%s\", data block \"%s\", host block \"%s\")",
1112 (int) vl->type, oid_buffer,
1113 (data_name != NULL) ? data_name : "UNKNOWN",
1114 (host_name != NULL) ? host_name : "UNKNOWN");
1119 if (vl->type == ASN_OCTET_STR)
1123 if (vl->val.string != NULL)
1126 size_t string_length;
1128 string_length = sizeof (string) - 1;
1129 if (vl->val_len < string_length)
1130 string_length = vl->val_len;
1132 /* The strings we get from the Net-SNMP library may not be null
1133 * terminated. That is why we're using `memcpy' here and not `strcpy'.
1134 * `string_length' is set to `vl->val_len' which holds the length of the
1136 memcpy (string, vl->val.string, string_length);
1137 string[string_length] = 0;
1139 status = parse_value (string, &ret, type);
1142 ERROR ("snmp plugin: csnmp_value_list_to_value: Parsing string as %s failed: %s",
1143 DS_TYPE_TO_STRING (type), string);
1151 case DS_TYPE_COUNTER:
1152 case DS_TYPE_DERIVE:
1153 case DS_TYPE_ABSOLUTE:
1154 memset (&ret, 0, sizeof (ret));
1162 ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown "
1163 "data source type: %i.", type);
1167 } /* if (vl->type == ASN_OCTET_STR) */
1168 else if (type == DS_TYPE_COUNTER)
1170 ret.counter = tmp_unsigned;
1172 else if (type == DS_TYPE_GAUGE)
1176 else if (prefer_signed)
1177 ret.gauge = (scale * tmp_signed) + shift;
1179 ret.gauge = (scale * tmp_unsigned) + shift;
1181 else if (type == DS_TYPE_DERIVE)
1184 ret.derive = (derive_t) tmp_signed;
1186 ret.derive = (derive_t) tmp_unsigned;
1188 else if (type == DS_TYPE_ABSOLUTE)
1190 ret.absolute = (absolute_t) tmp_unsigned;
1194 ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown data source "
1200 } /* value_t csnmp_value_list_to_value */
1202 static int csnmp_strvbcopy_hexstring (char *dst, /* {{{ */
1203 const struct variable_list *vb, size_t dst_size)
1210 buffer_free = dst_size;
1212 for (i = 0; i < vb->val_len; i++)
1216 status = snprintf (buffer_ptr, buffer_free,
1217 (i == 0) ? "%02x" : ":%02x", (unsigned int) vb->val.bitstring[i]);
1219 if (status >= buffer_free)
1221 buffer_ptr += (buffer_free - 1);
1223 return (dst_size + (buffer_free - status));
1225 else /* if (status < buffer_free) */
1227 buffer_ptr += status;
1228 buffer_free -= status;
1232 return ((int) (dst_size - buffer_free));
1233 } /* }}} int csnmp_strvbcopy_hexstring */
1235 static int csnmp_strvbcopy (char *dst, /* {{{ */
1236 const struct variable_list *vb, size_t dst_size)
1242 if (vb->type == ASN_OCTET_STR)
1243 src = (char *) vb->val.string;
1244 else if (vb->type == ASN_BIT_STR)
1245 src = (char *) vb->val.bitstring;
1252 num_chars = dst_size - 1;
1253 if (num_chars > vb->val_len)
1254 num_chars = vb->val_len;
1256 for (i = 0; i < num_chars; i++)
1258 /* Check for control characters. */
1259 if ((unsigned char)src[i] < 32)
1260 return (csnmp_strvbcopy_hexstring (dst, vb, dst_size));
1265 return ((int) vb->val_len);
1266 } /* }}} int csnmp_strvbcopy */
1268 static int csnmp_instance_list_add (csnmp_list_instances_t **head,
1269 csnmp_list_instances_t **tail,
1270 const struct snmp_pdu *res,
1271 const host_definition_t *hd, const data_definition_t *dd)
1273 csnmp_list_instances_t *il;
1274 struct variable_list *vb;
1278 /* Set vb on the last variable */
1279 for (vb = res->variables;
1280 (vb != NULL) && (vb->next_variable != NULL);
1281 vb = vb->next_variable)
1286 csnmp_oid_init (&vb_name, vb->name, vb->name_length);
1288 il = malloc (sizeof (*il));
1291 ERROR ("snmp plugin: malloc failed.");
1294 memset (il, 0, sizeof (*il));
1297 status = csnmp_oid_suffix (&il->suffix, &vb_name, &dd->instance.oid);
1304 /* Get instance name */
1305 if ((vb->type == ASN_OCTET_STR) || (vb->type == ASN_BIT_STR))
1309 csnmp_strvbcopy (il->instance, vb, sizeof (il->instance));
1311 for (ptr = il->instance; *ptr != '\0'; ptr++)
1313 if ((*ptr > 0) && (*ptr < 32))
1315 else if (*ptr == '/')
1318 DEBUG ("snmp plugin: il->instance = `%s';", il->instance);
1322 value_t val = csnmp_value_list_to_value (vb, DS_TYPE_COUNTER,
1323 /* scale = */ 1.0, /* shift = */ 0.0, hd->name, dd->name);
1324 ssnprintf (il->instance, sizeof (il->instance),
1325 "%llu", val.counter);
1328 /* TODO: Debugging output */
1337 } /* int csnmp_instance_list_add */
1339 static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *data,
1340 csnmp_list_instances_t *instance_list,
1341 csnmp_table_values_t **value_table)
1343 const data_set_t *ds;
1344 value_list_t vl = VALUE_LIST_INIT;
1346 csnmp_list_instances_t *instance_list_ptr;
1347 csnmp_table_values_t **value_table_ptr;
1351 oid_t current_suffix;
1353 ds = plugin_get_ds (data->type);
1356 ERROR ("snmp plugin: DataSet `%s' not defined.", data->type);
1359 assert (ds->ds_num == data->values_len);
1361 instance_list_ptr = instance_list;
1363 value_table_ptr = malloc (sizeof (*value_table_ptr) * data->values_len);
1364 if (value_table_ptr == NULL)
1366 for (i = 0; i < data->values_len; i++)
1367 value_table_ptr[i] = value_table[i];
1369 vl.values_len = ds->ds_num;
1370 vl.values = malloc (sizeof (*vl.values) * vl.values_len);
1371 if (vl.values == NULL)
1373 ERROR ("snmp plugin: malloc failed.");
1374 sfree (value_table_ptr);
1378 sstrncpy (vl.host, host->name, sizeof (vl.host));
1379 sstrncpy (vl.plugin, "snmp", sizeof (vl.plugin));
1381 vl.interval = host->interval;
1384 memset (¤t_suffix, 0, sizeof (current_suffix));
1387 _Bool suffix_skipped = 0;
1389 /* Determine next suffix to handle. */
1390 if (instance_list != NULL)
1392 if (instance_list_ptr == NULL)
1398 memcpy (¤t_suffix, &instance_list_ptr->suffix, sizeof (current_suffix));
1400 else /* no instance configured */
1402 csnmp_table_values_t *ptr = value_table_ptr[0];
1409 memcpy (¤t_suffix, &ptr->suffix, sizeof (current_suffix));
1412 /* Update all the value_table_ptr to point at the entry with the same
1413 * trailing partial OID */
1414 for (i = 0; i < data->values_len; i++)
1416 while ((value_table_ptr[i] != NULL)
1417 && (csnmp_oid_compare (&value_table_ptr[i]->suffix, ¤t_suffix) < 0))
1418 value_table_ptr[i] = value_table_ptr[i]->next;
1420 if (value_table_ptr[i] == NULL)
1425 else if (csnmp_oid_compare (&value_table_ptr[i]->suffix, ¤t_suffix) > 0)
1427 /* This suffix is missing in the subtree. Indicate this with the
1428 * "suffix_skipped" flag and try the next instance / suffix. */
1432 } /* for (i = 0; i < columns; i++) */
1437 /* Matching the values failed. Start from the beginning again. */
1440 if (instance_list != NULL)
1441 instance_list_ptr = instance_list_ptr->next;
1443 value_table_ptr[0] = value_table_ptr[0]->next;
1448 /* if we reach this line, all value_table_ptr[i] are non-NULL and are set
1449 * to the same subid. instance_list_ptr is either NULL or points to the
1450 * same subid, too. */
1452 for (i = 1; i < data->values_len; i++)
1454 assert (value_table_ptr[i] != NULL);
1455 assert (csnmp_oid_compare (&value_table_ptr[i-1]->suffix,
1456 &value_table_ptr[i]->suffix) == 0);
1458 assert ((instance_list_ptr == NULL)
1459 || (csnmp_oid_compare (&instance_list_ptr->suffix,
1460 &value_table_ptr[0]->suffix) == 0));
1463 sstrncpy (vl.type, data->type, sizeof (vl.type));
1466 char temp[DATA_MAX_NAME_LEN];
1468 if (instance_list_ptr == NULL)
1469 csnmp_oid_to_string (temp, sizeof (temp), ¤t_suffix);
1471 sstrncpy (temp, instance_list_ptr->instance, sizeof (temp));
1473 if (data->instance_prefix == NULL)
1474 sstrncpy (vl.type_instance, temp, sizeof (vl.type_instance));
1476 ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s%s",
1477 data->instance_prefix, temp);
1480 for (i = 0; i < data->values_len; i++)
1481 vl.values[i] = value_table_ptr[i]->value;
1483 /* If we get here `vl.type_instance' and all `vl.values' have been set */
1484 plugin_dispatch_values (&vl);
1486 if (instance_list != NULL)
1487 instance_list_ptr = instance_list_ptr->next;
1489 value_table_ptr[0] = value_table_ptr[0]->next;
1490 } /* while (have_more) */
1493 sfree (value_table_ptr);
1496 } /* int csnmp_dispatch_table */
1498 static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
1500 struct snmp_pdu *req;
1501 struct snmp_pdu *res;
1502 struct variable_list *vb;
1504 const data_set_t *ds;
1506 uint32_t oid_list_len = (uint32_t) (data->values_len + 1);
1507 /* Holds the last OID returned by the device. We use this in the GETNEXT
1508 * request to proceed. */
1509 oid_t oid_list[oid_list_len];
1510 /* Set to false when an OID has left its subtree so we don't re-request it
1512 _Bool oid_list_todo[oid_list_len];
1518 /* `value_list_head' and `value_list_tail' implement a linked list for each
1519 * value. `instance_list_head' and `instance_list_tail' implement a linked list of
1520 * instance names. This is used to jump gaps in the table. */
1521 csnmp_list_instances_t *instance_list_head;
1522 csnmp_list_instances_t *instance_list_tail;
1523 csnmp_table_values_t **value_list_head;
1524 csnmp_table_values_t **value_list_tail;
1526 DEBUG ("snmp plugin: csnmp_read_table (host = %s, data = %s)",
1527 host->name, data->name);
1529 if (host->sess_handle == NULL)
1531 DEBUG ("snmp plugin: csnmp_read_table: host->sess_handle == NULL");
1535 ds = plugin_get_ds (data->type);
1538 ERROR ("snmp plugin: DataSet `%s' not defined.", data->type);
1542 if (ds->ds_num != data->values_len)
1544 ERROR ("snmp plugin: DataSet `%s' requires %i values, but config talks about %i",
1545 data->type, ds->ds_num, data->values_len);
1549 /* We need a copy of all the OIDs, because GETNEXT will destroy them. */
1550 memcpy (oid_list, data->values, data->values_len * sizeof (oid_t));
1551 if (data->instance.oid.oid_len > 0)
1552 memcpy (oid_list + data->values_len, &data->instance.oid, sizeof (oid_t));
1553 else /* no InstanceFrom option specified. */
1556 for (j = 0; j < oid_list_len; j++)
1557 oid_list_todo[j] = 1;
1559 /* We're going to construct n linked lists, one for each "value".
1560 * value_list_head will contain pointers to the heads of these linked lists,
1561 * value_list_tail will contain pointers to the tail of the lists. */
1562 value_list_head = calloc (data->values_len, sizeof (*value_list_head));
1563 value_list_tail = calloc (data->values_len, sizeof (*value_list_tail));
1564 if ((value_list_head == NULL) || (value_list_tail == NULL))
1566 ERROR ("snmp plugin: csnmp_read_table: calloc failed.");
1567 sfree (value_list_head);
1568 sfree (value_list_tail);
1572 instance_list_head = NULL;
1573 instance_list_tail = NULL;
1578 int oid_list_todo_num;
1580 req = snmp_pdu_create (SNMP_MSG_GETNEXT);
1583 ERROR ("snmp plugin: snmp_pdu_create failed.");
1588 oid_list_todo_num = 0;
1589 for (j = 0; j < oid_list_len; j++)
1591 /* Do not rerequest already finished OIDs */
1592 if (!oid_list_todo[j])
1594 oid_list_todo_num++;
1595 snmp_add_null_var (req, oid_list[j].oid, oid_list[j].oid_len);
1598 if (oid_list_todo_num == 0)
1600 /* The request is still empty - so we are finished */
1601 DEBUG ("snmp plugin: all variables have left their subtree");
1607 status = snmp_sess_synch_response (host->sess_handle, req, &res);
1608 if ((status != STAT_SUCCESS) || (res == NULL))
1610 char *errstr = NULL;
1612 snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
1614 c_complain (LOG_ERR, &host->complaint,
1615 "snmp plugin: host %s: snmp_sess_synch_response failed: %s",
1616 host->name, (errstr == NULL) ? "Unknown problem" : errstr);
1619 snmp_free_pdu (res);
1623 csnmp_host_close_session (host);
1630 assert (res != NULL);
1631 c_release (LOG_INFO, &host->complaint,
1632 "snmp plugin: host %s: snmp_sess_synch_response successful.",
1635 vb = res->variables;
1642 for (vb = res->variables, i = 0; (vb != NULL); vb = vb->next_variable, i++)
1644 /* Calculate value index from todo list */
1645 while (!oid_list_todo[i] && (i < oid_list_len))
1648 /* An instance is configured and the res variable we process is the
1649 * instance value (last index) */
1650 if ((data->instance.oid.oid_len > 0) && (i == data->values_len))
1652 if ((vb->type == SNMP_ENDOFMIBVIEW)
1653 || (snmp_oid_ncompare (data->instance.oid.oid,
1654 data->instance.oid.oid_len,
1655 vb->name, vb->name_length,
1656 data->instance.oid.oid_len) != 0))
1658 DEBUG ("snmp plugin: host = %s; data = %s; Instance left its subtree.",
1659 host->name, data->name);
1660 oid_list_todo[i] = 0;
1664 /* Allocate a new `csnmp_list_instances_t', insert the instance name and
1665 * add it to the list */
1666 if (csnmp_instance_list_add (&instance_list_head, &instance_list_tail,
1667 res, host, data) != 0)
1669 ERROR ("snmp plugin: csnmp_instance_list_add failed.");
1674 else /* The variable we are processing is a normal value */
1676 csnmp_table_values_t *vt;
1680 csnmp_oid_init (&vb_name, vb->name, vb->name_length);
1682 /* Calculate the current suffix. This is later used to check that the
1683 * suffix is increasing. This also checks if we left the subtree */
1684 status = csnmp_oid_suffix (&suffix, &vb_name, data->values + i);
1687 DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
1688 "Value probably left its subtree.",
1689 host->name, data->name, i);
1690 oid_list_todo[i] = 0;
1694 /* Make sure the OIDs returned by the agent are increasing. Otherwise our
1695 * table matching algorithm will get confused. */
1696 if ((value_list_tail[i] != NULL)
1697 && (csnmp_oid_compare (&suffix, &value_list_tail[i]->suffix) <= 0))
1699 DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
1700 "Suffix is not increasing.",
1701 host->name, data->name, i);
1702 oid_list_todo[i] = 0;
1706 vt = malloc (sizeof (*vt));
1709 ERROR ("snmp plugin: malloc failed.");
1713 memset (vt, 0, sizeof (*vt));
1715 vt->value = csnmp_value_list_to_value (vb, ds->ds[i].type,
1716 data->scale, data->shift, host->name, data->name);
1717 memcpy (&vt->suffix, &suffix, sizeof (vt->suffix));
1720 if (value_list_tail[i] == NULL)
1721 value_list_head[i] = vt;
1723 value_list_tail[i]->next = vt;
1724 value_list_tail[i] = vt;
1727 /* Copy OID to oid_list[i] */
1728 memcpy (oid_list[i].oid, vb->name, sizeof (oid) * vb->name_length);
1729 oid_list[i].oid_len = vb->name_length;
1731 } /* for (vb = res->variables ...) */
1734 snmp_free_pdu (res);
1736 } /* while (status == 0) */
1739 snmp_free_pdu (res);
1743 csnmp_dispatch_table (host, data, instance_list_head, value_list_head);
1745 /* Free all allocated variables here */
1746 while (instance_list_head != NULL)
1748 csnmp_list_instances_t *next = instance_list_head->next;
1749 sfree (instance_list_head);
1750 instance_list_head = next;
1753 for (i = 0; i < data->values_len; i++)
1755 while (value_list_head[i] != NULL)
1757 csnmp_table_values_t *next = value_list_head[i]->next;
1758 sfree (value_list_head[i]);
1759 value_list_head[i] = next;
1763 sfree (value_list_head);
1764 sfree (value_list_tail);
1767 } /* int csnmp_read_table */
1769 static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
1771 struct snmp_pdu *req;
1772 struct snmp_pdu *res;
1773 struct variable_list *vb;
1775 const data_set_t *ds;
1776 value_list_t vl = VALUE_LIST_INIT;
1781 DEBUG ("snmp plugin: csnmp_read_value (host = %s, data = %s)",
1782 host->name, data->name);
1784 if (host->sess_handle == NULL)
1786 DEBUG ("snmp plugin: csnmp_read_table: host->sess_handle == NULL");
1790 ds = plugin_get_ds (data->type);
1793 ERROR ("snmp plugin: DataSet `%s' not defined.", data->type);
1797 if (ds->ds_num != data->values_len)
1799 ERROR ("snmp plugin: DataSet `%s' requires %i values, but config talks about %i",
1800 data->type, ds->ds_num, data->values_len);
1804 vl.values_len = ds->ds_num;
1805 vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
1806 if (vl.values == NULL)
1808 for (i = 0; i < vl.values_len; i++)
1810 if (ds->ds[i].type == DS_TYPE_COUNTER)
1811 vl.values[i].counter = 0;
1813 vl.values[i].gauge = NAN;
1816 sstrncpy (vl.host, host->name, sizeof (vl.host));
1817 sstrncpy (vl.plugin, "snmp", sizeof (vl.plugin));
1818 sstrncpy (vl.type, data->type, sizeof (vl.type));
1819 sstrncpy (vl.type_instance, data->instance.string, sizeof (vl.type_instance));
1821 vl.interval = host->interval;
1823 req = snmp_pdu_create (SNMP_MSG_GET);
1826 ERROR ("snmp plugin: snmp_pdu_create failed.");
1831 for (i = 0; i < data->values_len; i++)
1832 snmp_add_null_var (req, data->values[i].oid, data->values[i].oid_len);
1835 status = snmp_sess_synch_response (host->sess_handle, req, &res);
1837 if ((status != STAT_SUCCESS) || (res == NULL))
1839 char *errstr = NULL;
1841 snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
1842 ERROR ("snmp plugin: host %s: snmp_sess_synch_response failed: %s",
1843 host->name, (errstr == NULL) ? "Unknown problem" : errstr);
1846 snmp_free_pdu (res);
1850 csnmp_host_close_session (host);
1856 for (vb = res->variables; vb != NULL; vb = vb->next_variable)
1860 snprint_variable (buffer, sizeof (buffer),
1861 vb->name, vb->name_length, vb);
1862 DEBUG ("snmp plugin: Got this variable: %s", buffer);
1863 #endif /* COLLECT_DEBUG */
1865 for (i = 0; i < data->values_len; i++)
1866 if (snmp_oid_compare (data->values[i].oid, data->values[i].oid_len,
1867 vb->name, vb->name_length) == 0)
1868 vl.values[i] = csnmp_value_list_to_value (vb, ds->ds[i].type,
1869 data->scale, data->shift, host->name, data->name);
1870 } /* for (res->variables) */
1873 snmp_free_pdu (res);
1876 DEBUG ("snmp plugin: -> plugin_dispatch_values (&vl);");
1877 plugin_dispatch_values (&vl);
1881 } /* int csnmp_read_value */
1883 static int csnmp_read_host (user_data_t *ud)
1885 host_definition_t *host;
1886 cdtime_t time_start;
1894 if (host->interval == 0)
1895 host->interval = plugin_get_interval ();
1897 time_start = cdtime ();
1899 if (host->sess_handle == NULL)
1900 csnmp_host_open_session (host);
1902 if (host->sess_handle == NULL)
1906 for (i = 0; i < host->data_list_len; i++)
1908 data_definition_t *data = host->data_list[i];
1911 status = csnmp_read_table (host, data);
1913 status = csnmp_read_value (host, data);
1919 time_end = cdtime ();
1920 if ((time_end - time_start) > host->interval)
1922 WARNING ("snmp plugin: Host `%s' should be queried every %.3f "
1923 "seconds, but reading all values takes %.3f seconds.",
1925 CDTIME_T_TO_DOUBLE (host->interval),
1926 CDTIME_T_TO_DOUBLE (time_end - time_start));
1933 } /* int csnmp_read_host */
1935 static int csnmp_init (void)
1937 call_snmp_init_once ();
1940 } /* int csnmp_init */
1942 static int csnmp_shutdown (void)
1944 data_definition_t *data_this;
1945 data_definition_t *data_next;
1947 /* When we get here, the read threads have been stopped and all the
1948 * `host_definition_t' will be freed. */
1949 DEBUG ("snmp plugin: Destroying all data definitions.");
1951 data_this = data_head;
1953 while (data_this != NULL)
1955 data_next = data_this->next;
1957 sfree (data_this->name);
1958 sfree (data_this->type);
1959 sfree (data_this->values);
1962 data_this = data_next;
1966 } /* int csnmp_shutdown */
1968 void module_register (void)
1970 plugin_register_complex_config ("snmp", csnmp_config);
1971 plugin_register_init ("snmp", csnmp_init);
1972 plugin_register_shutdown ("snmp", csnmp_shutdown);
1973 } /* void module_register */
1976 * vim: shiftwidth=2 softtabstop=2 tabstop=8 fdm=marker