X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fsnmp.c;h=3e6cb9119cb7a8a40a24f330f2398b00e3b1d104;hp=dacdedea5bdd060ded6d5d6e893f44f88996314a;hb=96e0f2341bace029acefe0a88bab96ae326c0ff5;hpb=0afea60611f115a28b8ec331aba610e3038c1ef2 diff --git a/src/snmp.c b/src/snmp.c index dacdedea..3e6cb911 100644 --- a/src/snmp.c +++ b/src/snmp.c @@ -69,7 +69,7 @@ struct host_definition_s int version; void *sess_handle; c_complain_t complaint; - uint32_t interval; + cdtime_t interval; data_definition_t **data_list; int data_list_len; }; @@ -108,7 +108,7 @@ static int csnmp_read_host (user_data_t *ud); */ static void csnmp_oid_init (oid_t *dst, oid const *src, size_t n) { - assert (n <= STATIC_ARRAY_LEN (dst->oid)); + assert (n <= STATIC_ARRAY_SIZE (dst->oid)); memcpy (dst->oid, src, sizeof (*src) * n); dst->oid_len = n; } @@ -207,7 +207,6 @@ static void csnmp_host_definition_destroy (void *arg) /* {{{ */ * +-> csnmp_config_add_host_community * +-> csnmp_config_add_host_version * +-> csnmp_config_add_host_collect - * +-> csnmp_config_add_host_interval */ static void call_snmp_init_once (void) { @@ -591,22 +590,6 @@ static int csnmp_config_add_host_collect (host_definition_t *host, return (0); } /* int csnmp_config_add_host_collect */ -static int csnmp_config_add_host_interval (host_definition_t *hd, oconfig_item_t *ci) -{ - if ((ci->values_num != 1) - || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) - { - WARNING ("snmp plugin: The `Interval' config option needs exactly one number argument."); - return (-1); - } - - hd->interval = ci->values[0].value.number >= 0 - ? (uint32_t) ci->values[0].value.number - : 0; - - return (0); -} /* int csnmp_config_add_host_interval */ - static int csnmp_config_add_host (oconfig_item_t *ci) { host_definition_t *hd; @@ -655,7 +638,7 @@ static int csnmp_config_add_host (oconfig_item_t *ci) else if (strcasecmp ("Collect", option->key) == 0) csnmp_config_add_host_collect (hd, option); else if (strcasecmp ("Interval", option->key) == 0) - csnmp_config_add_host_interval (hd, option); + cf_util_get_cdtime (option, &hd->interval); else { WARNING ("snmp plugin: csnmp_config_add_host: Option `%s' not allowed here.", option->key); @@ -699,9 +682,7 @@ static int csnmp_config_add_host (oconfig_item_t *ci) cb_data.data = hd; cb_data.free_func = csnmp_host_definition_destroy; - memset (&cb_interval, 0, sizeof (cb_interval)); - if (hd->interval != 0) - cb_interval.tv_sec = (time_t) hd->interval; + CDTIME_T_TO_TIMESPEC (hd->interval, &cb_interval); status = plugin_register_complex_read (/* group = */ NULL, cb_name, csnmp_read_host, /* interval = */ &cb_interval, @@ -770,7 +751,8 @@ static void csnmp_host_open_session (host_definition_t *host) /* TODO: Check if negative values wrap around. Problem: negative temperatures. */ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type, - double scale, double shift) + double scale, double shift, + const char *host_name, const char *data_name) { value_t ret; uint64_t tmp_unsigned = 0; @@ -822,8 +804,11 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type, oid_buffer); else #endif - WARNING ("snmp plugin: I don't know the ASN type \"%i\" (OID: %s)", - (int) vl->type, oid_buffer); + WARNING ("snmp plugin: I don't know the ASN type #%i " + "(OID: \"%s\", data block \"%s\", host block \"%s\")", + (int) vl->type, oid_buffer, + (data_name != NULL) ? data_name : "UNKNOWN", + (host_name != NULL) ? host_name : "UNKNOWN"); defined = 0; } @@ -911,71 +896,6 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type, return (ret); } /* value_t csnmp_value_list_to_value */ -/* Returns true if all OIDs have left their subtree */ -static int csnmp_check_res_left_subtree (const host_definition_t *host, - const data_definition_t *data, - struct snmp_pdu *res) -{ - struct variable_list *vb; - int num_checked; - int num_left_subtree; - int i; - - vb = res->variables; - if (vb == NULL) - return (-1); - - num_checked = 0; - num_left_subtree = 0; - - /* check all the variables and count how many have left their subtree */ - for (vb = res->variables, i = 0; - (vb != NULL) && (i < data->values_len); - vb = vb->next_variable, i++) - { - num_checked++; - - if ((vb->type == SNMP_ENDOFMIBVIEW) - || (snmp_oid_ncompare (data->values[i].oid, - data->values[i].oid_len, - vb->name, vb->name_length, - data->values[i].oid_len) != 0)) - num_left_subtree++; - } - - /* check if enough variables have been returned */ - if (i < data->values_len) - { - ERROR ("snmp plugin: host %s: Expected %i variables, but got only %i", - host->name, data->values_len, i); - return (-1); - } - - if (data->instance.oid.oid_len > 0) - { - if (vb == NULL) - { - ERROR ("snmp plugin: host %s: Expected one more variable for " - "the instance..", host->name); - return (-1); - } - - num_checked++; - if (snmp_oid_ncompare (data->instance.oid.oid, - data->instance.oid.oid_len, - vb->name, vb->name_length, - data->instance.oid.oid_len) != 0) - num_left_subtree++; - } - - DEBUG ("snmp plugin: csnmp_check_res_left_subtree: %i of %i variables have " - "left their subtree", - num_left_subtree, num_checked); - if (num_left_subtree >= num_checked) - return (1); - return (0); -} /* int csnmp_check_res_left_subtree */ - static int csnmp_strvbcopy_hexstring (char *dst, /* {{{ */ const struct variable_list *vb, size_t dst_size) { @@ -1044,8 +964,8 @@ static int csnmp_strvbcopy (char *dst, /* {{{ */ static int csnmp_instance_list_add (csnmp_list_instances_t **head, csnmp_list_instances_t **tail, - struct snmp_pdu const *res, - oid_t const *root) + const struct snmp_pdu *res, + const host_definition_t *hd, const data_definition_t *dd) { csnmp_list_instances_t *il; struct variable_list *vb; @@ -1071,7 +991,7 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head, memset (il, 0, sizeof (*il)); il->next = NULL; - status = csnmp_oid_suffix (&il->suffix, &vb_name, root); + status = csnmp_oid_suffix (&il->suffix, &vb_name, &dd->instance.oid); if (status != 0) { sfree (il); @@ -1096,7 +1016,8 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head, } else { - value_t val = csnmp_value_list_to_value (vb, DS_TYPE_COUNTER, 1.0, 0.0); + value_t val = csnmp_value_list_to_value (vb, DS_TYPE_COUNTER, + /* scale = */ 1.0, /* shift = */ 0.0, hd->name, dd->name); ssnprintf (il->instance, sizeof (il->instance), "%llu", val.counter); } @@ -1278,11 +1199,18 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) struct variable_list *vb; const data_set_t *ds; - oid_t *oid_list; - uint32_t oid_list_len; + + uint32_t oid_list_len = (uint32_t) (data->values_len + 1); + /* Holds the last OID returned by the device. We use this in the GETNEXT + * request to proceed. */ + oid_t oid_list[oid_list_len]; + /* Set to false when an OID has left its subtree so we don't re-request it + * again. */ + _Bool oid_list_todo[oid_list_len]; int status; int i; + uint32_t j; /* `value_list_head' and `value_list_tail' implement a linked list for each * value. `instance_list_head' and `instance_list_tail' implement a linked list of @@ -1316,19 +1244,15 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) } /* We need a copy of all the OIDs, because GETNEXT will destroy them. */ - oid_list_len = data->values_len + 1; - oid_list = (oid_t *) malloc (sizeof (oid_t) * (oid_list_len)); - if (oid_list == NULL) - { - ERROR ("snmp plugin: csnmp_read_table: malloc failed."); - return (-1); - } memcpy (oid_list, data->values, data->values_len * sizeof (oid_t)); if (data->instance.oid.oid_len > 0) memcpy (oid_list + data->values_len, &data->instance.oid, sizeof (oid_t)); - else + else /* no InstanceFrom option specified. */ oid_list_len--; + for (j = 0; j < oid_list_len; j++) + oid_list_todo[j] = 1; + /* We're going to construct n linked lists, one for each "value". * value_list_head will contain pointers to the heads of these linked lists, * value_list_tail will contain pointers to the tail of the lists. */ @@ -1337,7 +1261,6 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) if ((value_list_head == NULL) || (value_list_tail == NULL)) { ERROR ("snmp plugin: csnmp_read_table: calloc failed."); - sfree (oid_list); sfree (value_list_head); sfree (value_list_tail); return (-1); @@ -1349,6 +1272,8 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) status = 0; while (status == 0) { + int oid_list_todo_num; + req = snmp_pdu_create (SNMP_MSG_GETNEXT); if (req == NULL) { @@ -1357,12 +1282,26 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) break; } - for (i = 0; (uint32_t) i < oid_list_len; i++) - snmp_add_null_var (req, oid_list[i].oid, oid_list[i].oid_len); + oid_list_todo_num = 0; + for (j = 0; j < oid_list_len; j++) + { + /* Do not rerequest already finished OIDs */ + if (!oid_list_todo[j]) + continue; + oid_list_todo_num++; + snmp_add_null_var (req, oid_list[j].oid, oid_list[j].oid_len); + } + + if (oid_list_todo_num == 0) + { + /* The request is still empty - so we are finished */ + DEBUG ("snmp plugin: all variables have left their subtree"); + status = 0; + break; + } res = NULL; status = snmp_sess_synch_response (host->sess_handle, req, &res); - if ((status != STAT_SUCCESS) || (res == NULL)) { char *errstr = NULL; @@ -1383,6 +1322,7 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) status = -1; break; } + status = 0; assert (res != NULL); c_release (LOG_INFO, &host->complaint, @@ -1396,103 +1336,97 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) break; } - /* Check if all values (and possibly the instance) have left their - * subtree */ - if (csnmp_check_res_left_subtree (host, data, res) != 0) + for (vb = res->variables, i = 0; (vb != NULL); vb = vb->next_variable, i++) { - status = 0; - break; - } + /* Calculate value index from todo list */ + while (!oid_list_todo[i] && (i < oid_list_len)) + i++; - /* Copy the OID of the value used as instance to oid_list, if an instance - * is configured. */ - if (data->instance.oid.oid_len > 0) - { - /* Allocate a new `csnmp_list_instances_t', insert the instance name and - * add it to the list */ - if (csnmp_instance_list_add (&instance_list_head, &instance_list_tail, - res, &data->instance.oid) != 0) + /* An instance is configured and the res variable we process is the + * instance value (last index) */ + if ((data->instance.oid.oid_len > 0) && (i == data->values_len)) { - ERROR ("snmp plugin: csnmp_instance_list_add failed."); - status = -1; - break; - } - - /* The instance OID is added to the list of OIDs to GET from the - * snmp agent last, so set vb on the last variable returned and copy - * that OID. */ - for (vb = res->variables; - (vb != NULL) && (vb->next_variable != NULL); - vb = vb->next_variable) - /* do nothing */; - assert (vb != NULL); - - /* Copy the OID of the instance value to oid_list[data->values_len]. - * "oid_list" is used for the next GETNEXT request. */ - memcpy (oid_list[data->values_len].oid, vb->name, - sizeof (oid) * vb->name_length); - oid_list[data->values_len].oid_len = vb->name_length; - } - - /* Iterate over all the (non-instance) values returned by the agent. The - * (i < value_len) check will make sure we're not handling the instance OID - * twice. */ - for (vb = res->variables, i = 0; - (vb != NULL) && (i < data->values_len); - vb = vb->next_variable, i++) - { - csnmp_table_values_t *vt; - oid_t vb_name; - oid_t suffix; - - csnmp_oid_init (&vb_name, vb->name, vb->name_length); - - /* Calculate the current suffix. This is later used to check that the - * suffix is increasing. This also checks if we left the subtree */ - status = csnmp_oid_suffix (&suffix, &vb_name, data->values + i); - if (status != 0) - { - DEBUG ("snmp plugin: host = %s; data = %s; Value %i failed. " - "It probably left its subtree.", - host->name, data->name, i); - continue; - } - - /* Make sure the OIDs returned by the agent are increasing. Otherwise our - * table matching algorithm will get confused. */ - if ((value_list_tail[i] != NULL) - && (csnmp_oid_compare (&suffix, &value_list_tail[i]->suffix) <= 0)) - { - DEBUG ("snmp plugin: host = %s; data = %s; i = %i; " - "Suffix is not increasing.", - host->name, data->name, i); - continue; + if ((vb->type == SNMP_ENDOFMIBVIEW) + || (snmp_oid_ncompare (data->instance.oid.oid, + data->instance.oid.oid_len, + vb->name, vb->name_length, + data->instance.oid.oid_len) != 0)) + { + DEBUG ("snmp plugin: host = %s; data = %s; Instance left its subtree.", + host->name, data->name); + oid_list_todo[i] = 0; + continue; + } + + /* Allocate a new `csnmp_list_instances_t', insert the instance name and + * add it to the list */ + if (csnmp_instance_list_add (&instance_list_head, &instance_list_tail, + res, host, data) != 0) + { + ERROR ("snmp plugin: csnmp_instance_list_add failed."); + status = -1; + break; + } } - - vt = malloc (sizeof (*vt)); - if (vt == NULL) + else /* The variable we are processing is a normal value */ { - ERROR ("snmp plugin: malloc failed."); - status = -1; - break; + csnmp_table_values_t *vt; + oid_t vb_name; + oid_t suffix; + int ret; + + csnmp_oid_init (&vb_name, vb->name, vb->name_length); + + /* Calculate the current suffix. This is later used to check that the + * suffix is increasing. This also checks if we left the subtree */ + ret = csnmp_oid_suffix (&suffix, &vb_name, data->values + i); + if (ret != 0) + { + DEBUG ("snmp plugin: host = %s; data = %s; i = %i; " + "Value probably left its subtree.", + host->name, data->name, i); + oid_list_todo[i] = 0; + continue; + } + + /* Make sure the OIDs returned by the agent are increasing. Otherwise our + * table matching algorithm will get confused. */ + if ((value_list_tail[i] != NULL) + && (csnmp_oid_compare (&suffix, &value_list_tail[i]->suffix) <= 0)) + { + DEBUG ("snmp plugin: host = %s; data = %s; i = %i; " + "Suffix is not increasing.", + host->name, data->name, i); + oid_list_todo[i] = 0; + continue; + } + + vt = malloc (sizeof (*vt)); + if (vt == NULL) + { + ERROR ("snmp plugin: malloc failed."); + status = -1; + break; + } + memset (vt, 0, sizeof (*vt)); + + vt->value = csnmp_value_list_to_value (vb, ds->ds[i].type, + data->scale, data->shift, host->name, data->name); + memcpy (&vt->suffix, &suffix, sizeof (vt->suffix)); + vt->next = NULL; + + if (value_list_tail[i] == NULL) + value_list_head[i] = vt; + else + value_list_tail[i]->next = vt; + value_list_tail[i] = vt; } - memset (vt, 0, sizeof (*vt)); - - vt->value = csnmp_value_list_to_value (vb, ds->ds[i].type, - data->scale, data->shift); - memcpy (&vt->suffix, &suffix, sizeof (vt->suffix)); - vt->next = NULL; - if (value_list_tail[i] == NULL) - value_list_head[i] = vt; - else - value_list_tail[i]->next = vt; - value_list_tail[i] = vt; - - /* Copy OID to oid_list[i + 1] */ + /* Copy OID to oid_list[i] */ memcpy (oid_list[i].oid, vb->name, sizeof (oid) * vb->name_length); oid_list[i].oid_len = vb->name_length; - } /* for (i = data->values_len) */ + + } /* for (vb = res->variables ...) */ if (res != NULL) snmp_free_pdu (res); @@ -1530,7 +1464,6 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) sfree (value_list_head); sfree (value_list_tail); - sfree (oid_list); return (0); } /* int csnmp_read_table */ @@ -1635,7 +1568,7 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data) if (snmp_oid_compare (data->values[i].oid, data->values[i].oid_len, vb->name, vb->name_length) == 0) vl.values[i] = csnmp_value_list_to_value (vb, ds->ds[i].type, - data->scale, data->shift); + data->scale, data->shift, host->name, data->name); } /* for (res->variables) */ if (res != NULL) @@ -1652,8 +1585,8 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data) static int csnmp_read_host (user_data_t *ud) { host_definition_t *host; - time_t time_start; - time_t time_end; + cdtime_t time_start; + cdtime_t time_end; int status; int success; int i; @@ -1661,11 +1594,9 @@ static int csnmp_read_host (user_data_t *ud) host = ud->data; if (host->interval == 0) - host->interval = interval_g; + host->interval = plugin_get_interval (); - time_start = time (NULL); - DEBUG ("snmp plugin: csnmp_read_host (%s) started at %u;", host->name, - (unsigned int) time_start); + time_start = cdtime (); if (host->sess_handle == NULL) csnmp_host_open_session (host); @@ -1687,14 +1618,14 @@ static int csnmp_read_host (user_data_t *ud) success++; } - time_end = time (NULL); - DEBUG ("snmp plugin: csnmp_read_host (%s) finished at %u;", host->name, - (unsigned int) time_end); - if ((uint32_t) (time_end - time_start) > host->interval) + time_end = cdtime (); + if ((time_end - time_start) > host->interval) { - WARNING ("snmp plugin: Host `%s' should be queried every %"PRIu32 - " seconds, but reading all values takes %u seconds.", - host->name, host->interval, (unsigned int) (time_end - time_start)); + WARNING ("snmp plugin: Host `%s' should be queried every %.3f " + "seconds, but reading all values takes %.3f seconds.", + host->name, + CDTIME_T_TO_DOUBLE (host->interval), + CDTIME_T_TO_DOUBLE (time_end - time_start)); } if (success == 0)