Skip to content
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

Merged
merged 11 commits into from May 18, 2017
Merged

Conversation

rkorynkx
Copy link
Contributor

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/

@rubenk
Copy link
Contributor

rubenk commented Dec 14, 2016

Did you forget to check-in snmp.agent.c and snmp_agent.h?

@rkorynkx
Copy link
Contributor Author

Hi @rubenk, snmp_agent.c is already there. Working on compilation fix.

@rkorynkx
Copy link
Contributor Author

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?

@octo
Copy link
Member

octo commented Dec 16, 2016

@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) && \
Copy link
Member

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.

Copy link
Member

@octo octo left a 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;
Copy link
Member

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 @@
/**
Copy link
Member

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, "", "", "",
Copy link
Member

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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This leaks (*dd)->table.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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 */
Copy link
Member

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?

Copy link
Contributor Author

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;
Copy link
Member

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);
Copy link
Member

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);
Copy link
Member

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,
Copy link
Member

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) {
Copy link
Member

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?

@rkorynkx
Copy link
Contributor Author

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?

Copy link
Member

@octo octo left a 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);
Copy link
Member

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];
Copy link
Member

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);
Copy link
Member

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);
}
}

Copy link
Member

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) {
Copy link
Member

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.

@rkorynkx
Copy link
Contributor Author

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,
Roman.

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>
@rkorynkx
Copy link
Contributor Author

rkorynkx commented Jan 5, 2017

Hi @octo, I've fixed the review comments, did the rebase and merged the conflicts. Could you please take a look?

Thanks,
Roman.

@rkorynkx
Copy link
Contributor Author

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>
@maryamtahhan
Copy link
Contributor

Hi folks
would appreciate any additional feedback here

@octo
Copy link
Member

octo commented May 18, 2017

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!
—octo

@octo octo self-assigned this May 18, 2017
@octo octo merged commit 1634cdf into collectd:master May 18, 2017
@rkorynkx rkorynkx deleted the feat_snmp branch May 18, 2017 09:11
@octo octo added this to the 5.8 milestone Oct 11, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants