New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
snmp_agent: Implement SNMP Agent plugin. #2105
Conversation
|
Did you forget to check-in snmp.agent.c and snmp_agent.h? |
|
Hi @rubenk, snmp_agent.c is already there. Working on compilation fix. |
|
Hi @octo, buildbot/collectd-solaris10-i386 task is in pending state more than 2 days but in Details it shows that is has finished successfully. Could you please take a look? Should I perform any actions? |
|
@rkorynkx the build finished successfully but the status change didn't make it to GitHub. :-( |
src/snmp_agent.c
Outdated
| #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) && \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have expected the default to be 1 in the "type" case. If this is intentional, please add a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @rkorynkx, thank you very much for this, I love the idea!
Unfortunately, my train ride comes to an end, so I'll publish the review comments I have to far and will come back to you later. Overall it looks pretty good, thank you!
Best regards,
—octo
src/snmp_agent.c
Outdated
| 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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At your option: the explicit cast is not required when assigning a void * to a variable of different pointer type. Assignment without a cast may be easier to read.
| @@ -0,0 +1,1513 @@ | |||
| /** | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please reformat this file with:
clang-format -style=LLVM
That will re-order includes. Be sure to add an empty line after "collectd.h" and, presumably, <net-snmp/net-snmp-config.h>.
src/snmp_agent.c
Outdated
| DEBUG(PLUGIN_NAME ": Removed row for '%s' table [%d, %s].", td->name, *index, | ||
| ins); | ||
|
|
||
| notification_t n = {NOTIF_WARNING, cdtime(), "", "", PLUGIN_NAME, "", "", "", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a job for C99's Designated Initializers:
notification_t n = {
.severity = NOTIF_WARNING,
.time = cdtime(),
.plugin = PLUGIN_NAME,
};| sfree((*dd)->type_instance); | ||
| sfree((*dd)->oids); | ||
|
|
||
| sfree(*dd); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This leaks (*dd)->table.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it's not. dd is not the owner of the table as it does not allocate it. It holds the reference to the table it belongs to. I will make it const for better understanding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation, I didn't realize that this was a back reference. How about we rename data_definition_t to column_definition_t? That would make it more intuitive for me. Also it would then match the name of the "columns" field in table_definition_t.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
data_definition_t is used not only for table data type, it's also used for scalar data type. And in this case columns won't be the proper name.
src/snmp_agent.c
Outdated
| 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 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't you just call snmp_agent_free_table((*dd)->table) here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
snmp_agent_free_data() frees scalar and tabular data. If data is tabular it will remove all rows of table for specified column. For example, we have unicast and broadcast packets counters as columns in the table, so if to call this function with broadcast dd as a parameter it will free data for each interface for broadcast counter only. In turn, snmp_agent_free_table() iterates through all columns (dd) and calls snmp_agent_free_data().
src/snmp_agent.c
Outdated
| DEBUG(PLUGIN_NAME ": Identifier '%s'", temp); | ||
|
|
||
| value_t *values; | ||
| size_t values_num; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please initialize values and values_num to NULL / zero so that it's obvious that they are never used uninitialized.
src/snmp_agent.c
Outdated
| int index = oid.oid[oid.oid_len - 1]; | ||
| char *instance; | ||
|
|
||
| int ret = c_avl_get(td->index_instance, &index, (void **)&instance); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Compound literals are great for when you need to pass a pointer but don't actually need about the value that's assigned. By using an anonymous variable, you're signaling to the reader that you don't care what's assigned.
int ret = c_avl_get(td->index_instance, &index, &(void *){NULL});
src/snmp_agent.c
Outdated
|
|
||
| snmp_agent_oid_to_string(temp, sizeof(temp), &oid); | ||
|
|
||
| DEBUG(PLUGIN_NAME ": Get request received for scalar OID '%s'.", temp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above: s/temp/oid_str/?
src/snmp_agent.c
Outdated
|
|
||
|
|
||
| static int | ||
| snmp_agent_scalar_oid_handler(struct netsnmp_mib_handler_s *handler, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function has a lot of duplicate code that's also in snmp_agent_table_oid_handler(). Is it possible to deduplicate this a bit?
src/snmp_agent.c
Outdated
| return (0); | ||
| } | ||
|
|
||
| static int snmp_agent_config_data(oconfig_item_t *ci) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This duplicates a lot of code from snmp_agent_config_table_data(). Could this be simplified?
|
Hi @octo, I'm seeing Makefile.am has changed and currently there are conflicts. Should I rebase the branch with the latest master to solve this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @rkorynkx,
thank you for following up on this! I have a few more comments, when they're addressed, it would be good if you could rebase on master to fix the merge conflicts. I'm afraid that Ruben's automake work conflicts with this :\ If you need any help resolving conflicts, please let me know. Once that's done, this should be good to go.
Best regards,
—octo
| sfree((*dd)->type_instance); | ||
| sfree((*dd)->oids); | ||
|
|
||
| sfree(*dd); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation, I didn't realize that this was a back reference. How about we rename data_definition_t to column_definition_t? That would make it more intuitive for me. Also it would then match the name of the "columns" field in table_definition_t.
src/snmp_agent.c
Outdated
| 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]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please rename "buf" to "name"? For me, "buf" implies that it is a very short lived temporary variable, but it is actually read multiple times.
src/snmp_agent.c
Outdated
| 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a configuration error that the user should be told about. Since you cannot continue, this should be an ERROR() instead.
src/snmp_agent.c
Outdated
| return (-ENOMEM); | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should check that td.index_oid.oid_len != 0 here – it appears the implementation can't really function without it and the manpage implies that this is a required setting.
src/snmp_agent.c
Outdated
| if (ret != 0) | ||
| continue; | ||
|
|
||
| if (!td->index_oid.oid_len) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can do this right after initializing td and avoid two nested loops that will never be able to perform any useful action.
|
Hi @octo, thanks for quick review. I'll fix the review comments. Have one question, should I do rebase and merge conflicts as a separate commit after new patch (with fixed review comments) will be uploaded? What is the procedure? Thanks, |
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 <http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/> Change-Id: I0e82131685f2138e1af0a9283b06f85dd2028878 Signed-off-by: Korynkevych, RomanX <romanx.korynkevych@intel.com>
Change-Id: Ic57c14abb8b6b31547e97e6c394b8c3147b1e6b2 Signed-off-by: Korynkevych, RomanX <romanx.korynkevych@intel.com>
Change-Id: I697d80d39d8f37d9bd36280bad874a1f4d600518 Signed-off-by: Korynkevych, RomanX <romanx.korynkevych@intel.com>
Performed code cleanup and optimizations: - Reformat file using clang-format. - Removed duplicate code. Change-Id: Ia6d7cde0e44cb5d3639df11e712fe655becd9712 Signed-off-by: Korynkevych, RomanX <romanx.korynkevych@intel.com>
Additional validation and variable names changes. Change-Id: Ic6c3c3226e2ee6586c03b64d063822b99c242af3 Signed-off-by: Korynkevych, RomanX <romanx.korynkevych@intel.com>
The location of SNMP Agent sources in Makefile.am is `src/*` folder now. Signed-off-by: Roman Korynkevych <romanx.korynkevych@intel.com>
|
Hi @octo, I've fixed the review comments, did the rebase and merged the conflicts. Could you please take a look? Thanks, |
|
Hi @octo, just a reminder that review comments have been fixed, waiting for your feedback. |
Segmentation fault caused by c_avl_pick() occurs when NULL iterator is passed. Change-Id: I3dc960f80b556e18616717ca53fd992c8cf9d78b Signed-off-by: Korynkevych, RomanX <romanx.korynkevych@intel.com>
…ex 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 <romanx.korynkevych@intel.com>
|
Hi folks |
|
Hi, sorry for the long delay, I lost sight of this :( The code looks good now. I've done some minor cleanups (re-ran clang-format; removed parenthesis around return values, see #2277). I'll push those and merge once the CI build is complete. Thanks again for all your work! This is a really awesome addition to collectd! |
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 http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/