X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fsnmp.c;h=7d340d18c2398a8a26fb845d7b0e03352b53f903;hb=51a4e62d7d0e73d8d5822efaef1e3218b5ad0373;hp=16fd48aaaf5d3df87ace94b0f358df63f15dbc2f;hpb=33e60ef35f745c56b1a5936272b1dd8b0cf63d12;p=collectd.git diff --git a/src/snmp.c b/src/snmp.c index 16fd48aa..7d340d18 100644 --- a/src/snmp.c +++ b/src/snmp.c @@ -896,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) { @@ -1264,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 @@ -1302,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. */ @@ -1323,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); @@ -1335,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) { @@ -1343,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; @@ -1363,12 +1316,15 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) snmp_free_pdu (res); res = NULL; + /* snmp_synch_response already freed our PDU */ + req = NULL; sfree (errstr); csnmp_host_close_session (host); status = -1; break; } + status = 0; assert (res != NULL); c_release (LOG_INFO, &host->complaint, @@ -1382,103 +1338,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) - { - status = 0; - break; - } - - /* 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, host, data) != 0) - { - 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++) + for (vb = res->variables, i = 0; (vb != NULL); 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 value index from todo list */ + while (!oid_list_todo[i] && (i < oid_list_len)) + i++; - /* 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) + /* 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)) { - DEBUG ("snmp plugin: host = %s; data = %s; Value %i failed. " - "It probably left its subtree.", - 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; + } } - - /* 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)) + else /* The variable we are processing is a normal value */ { - DEBUG ("snmp plugin: host = %s; data = %s; i = %i; " - "Suffix is not increasing.", - host->name, data->name, i); - continue; - } + 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 = malloc (sizeof (*vt)); - if (vt == NULL) - { - ERROR ("snmp plugin: malloc failed."); - status = -1; - break; + 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, 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; - - /* 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); @@ -1489,6 +1439,10 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) snmp_free_pdu (res); res = NULL; + if (req != NULL) + snmp_free_pdu (req); + req = NULL; + if (status == 0) csnmp_dispatch_table (host, data, instance_list_head, value_list_head); @@ -1512,7 +1466,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 */ @@ -1671,10 +1624,10 @@ static int csnmp_read_host (user_data_t *ud) if ((time_end - time_start) > host->interval) { 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)); + "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)