You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

239 lines
7.1 KiB

  1. From: Nick Hainke <vincent@systemli.org>
  2. Date: Mon, 7 Dec 2020 19:29:54 +0100
  3. Subject: [PATCH] snmp6: add ipv6 statistics
  4. ChangeLog: snmp6 plugin: Add plugin for parsing IPv6 statistics
  5. We would like to have pure ipv6 interface statistics. To get them,
  6. we parse the snmp6 interface.
  7. Signed-off-by: Nick Hainke <vincent@systemli.org>
  8. ---
  9. Makefile.am | 8 +++
  10. README | 4 ++
  11. configure.ac | 2 +
  12. src/collectd.conf.in | 6 ++
  13. src/snmp6.c | 135 +++++++++++++++++++++++++++++++++++++++++++
  14. src/types.db | 2 +
  15. 6 files changed, 157 insertions(+)
  16. create mode 100644 src/snmp6.c
  17. --- a/Makefile.am
  18. +++ b/Makefile.am
  19. @@ -1964,6 +1964,14 @@ TESTS += test_plugin_snmp_agent
  20. endif
  21. +if BUILD_PLUGIN_SNMP6
  22. +pkglib_LTLIBRARIES += snmp6.la
  23. +snmp6_la_SOURCES = src/snmp6.c
  24. +snmp6_la_CFLAGS = $(AM_CFLAGS)
  25. +snmp6_la_LDFLAGS = $(PLUGIN_LDFLAGS)
  26. +snmp6_la_LIBADD = libignorelist.la
  27. +endif # BUILD_PLUGIN_SNMP6
  28. +
  29. if BUILD_PLUGIN_STATSD
  30. pkglib_LTLIBRARIES += statsd.la
  31. statsd_la_SOURCES = src/statsd.c
  32. --- a/README
  33. +++ b/README
  34. @@ -422,6 +422,10 @@ Features
  35. network devices such as switches, routers, thermometers, rack monitoring
  36. servers, etc. See collectd-snmp(5).
  37. + - snmp6
  38. + Read values from SNMP6 (Simple Network Management Protocol). Supports pure
  39. + IPv6 interface statistics.
  40. +
  41. - statsd
  42. Acts as a StatsD server, reading values sent over the network from StatsD
  43. clients and calculating rates and other aggregates out of these values.
  44. --- a/configure.ac
  45. +++ b/configure.ac
  46. @@ -7162,6 +7162,7 @@ AC_PLUGIN([slurm], [$with_
  47. AC_PLUGIN([smart], [$plugin_smart], [SMART statistics])
  48. AC_PLUGIN([snmp], [$with_libnetsnmp], [SNMP querying plugin])
  49. AC_PLUGIN([snmp_agent], [$with_libnetsnmpagent], [SNMP agent plugin])
  50. +AC_PLUGIN([snmp6], [yes], [IPv6 Interface traffic statistics via snmp6])
  51. AC_PLUGIN([statsd], [yes], [StatsD plugin])
  52. AC_PLUGIN([swap], [$plugin_swap], [Swap usage statistics])
  53. AC_PLUGIN([synproxy], [$plugin_synproxy], [Synproxy stats plugin])
  54. @@ -7611,6 +7612,7 @@ AC_MSG_RESULT([ slurm . . . . . . . .
  55. AC_MSG_RESULT([ smart . . . . . . . . $enable_smart])
  56. AC_MSG_RESULT([ snmp . . . . . . . . $enable_snmp])
  57. AC_MSG_RESULT([ snmp_agent . . . . . $enable_snmp_agent])
  58. +AC_MSG_RESULT([ snmp6 . . . . . . . . $enable_snmp6])
  59. AC_MSG_RESULT([ statsd . . . . . . . $enable_statsd])
  60. AC_MSG_RESULT([ swap . . . . . . . . $enable_swap])
  61. AC_MSG_RESULT([ synproxy . . . . . . $enable_synproxy])
  62. --- a/src/collectd.conf.in
  63. +++ b/src/collectd.conf.in
  64. @@ -207,6 +207,7 @@
  65. #@BUILD_PLUGIN_SMART_TRUE@LoadPlugin smart
  66. #@BUILD_PLUGIN_SNMP_TRUE@LoadPlugin snmp
  67. #@BUILD_PLUGIN_SNMP_AGENT_TRUE@LoadPlugin snmp_agent
  68. +#@BUILD_PLUGIN_SNMP6_TRUE@LoadPlugin snmp6
  69. #@BUILD_PLUGIN_STATSD_TRUE@LoadPlugin statsd
  70. #@BUILD_PLUGIN_SWAP_TRUE@LoadPlugin swap
  71. #@BUILD_PLUGIN_SYSEVENT_TRUE@LoadPlugin sysevent
  72. @@ -1718,6 +1719,11 @@
  73. # </Table>
  74. #</Plugin>
  75. +#<Plugin snmp6>
  76. +# Interface "eth0"
  77. +# IgnoreSelected false
  78. +#</Plugin>
  79. +
  80. #<Plugin statsd>
  81. # Host "::"
  82. # Port "8125"
  83. --- /dev/null
  84. +++ b/src/snmp6.c
  85. @@ -0,0 +1,135 @@
  86. +/*
  87. + This Plugin is based opn the interface.c Plugin.
  88. +*/
  89. +#include <stdint.h>
  90. +#include <stdlib.h>
  91. +#include <string.h>
  92. +#include <errno.h>
  93. +#include <stdbool.h>
  94. +#include <stdio.h>
  95. +
  96. +#include <net/if.h>
  97. +#include <sys/types.h>
  98. +#include <ifaddrs.h>
  99. +
  100. +#include "plugin.h"
  101. +#include "utils/cmds/putval.h"
  102. +#include "utils/common/common.h"
  103. +#include "utils/ignorelist/ignorelist.h"
  104. +
  105. +static const char *config_keys[] = {
  106. + "Interface",
  107. + "IgnoreSelected",
  108. +};
  109. +static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
  110. +
  111. +static ignorelist_t *ignorelist;
  112. +
  113. +static int snmp6_config(const char *key, const char *value) {
  114. + if (ignorelist == NULL)
  115. + ignorelist = ignorelist_create(/* invert = */ 1);
  116. +
  117. + if (strcasecmp(key, "Interface") == 0) {
  118. + ignorelist_add(ignorelist, value);
  119. + } else if (strcasecmp(key, "IgnoreSelected") == 0) {
  120. + int invert = 1;
  121. + if (IS_TRUE(value))
  122. + invert = 0;
  123. + ignorelist_set_invert(ignorelist, invert);
  124. + }
  125. +
  126. + return 0;
  127. +}
  128. +
  129. +/* Copied from interface.c */
  130. +static void snmp6_submit(const char *dev, const char *type, derive_t rx,
  131. + derive_t tx) {
  132. + value_list_t vl = VALUE_LIST_INIT;
  133. + value_t values[] = {
  134. + {.derive = rx},
  135. + {.derive = tx},
  136. + };
  137. +
  138. + vl.values = values;
  139. + vl.values_len = STATIC_ARRAY_SIZE(values);
  140. + sstrncpy(vl.plugin, "snmp6", sizeof(vl.plugin));
  141. + sstrncpy(vl.plugin_instance, dev, sizeof(vl.plugin_instance));
  142. + sstrncpy(vl.type, type, sizeof(vl.type));
  143. +
  144. + plugin_dispatch_values(&vl);
  145. +} /* void if_submit */
  146. +
  147. +int snmp_read(char *ifname) {
  148. + FILE *fh;
  149. + char buffer[1024];
  150. + char *fields[2];
  151. + int numfields;
  152. + int currline = 0;
  153. + derive_t data[76];
  154. + char procpath[1024];
  155. + int offset = 0;
  156. +
  157. + if (ignorelist_match(ignorelist, ifname) != 0)
  158. + return 0;
  159. +
  160. + if (strncmp("all", ifname, strlen("all")) == 0) {
  161. + snprintf(procpath, 1024, "/proc/net/snmp6");
  162. + offset = 1;
  163. + } else {
  164. + snprintf(procpath, 1024, "/proc/net/dev_snmp6/%s", ifname);
  165. + }
  166. +
  167. + if ((fh = fopen(procpath, "r")) == NULL) {
  168. + WARNING("snmp6 plugin: try opening %s : fopen: %s", procpath, STRERRNO);
  169. + return -1;
  170. + }
  171. +
  172. + while (fgets(buffer, 1024, fh) != NULL) {
  173. + numfields = strsplit(buffer, fields, 2);
  174. +
  175. + if (numfields < 2)
  176. + return -1;
  177. +
  178. + data[currline++] = atoll(fields[1]);
  179. + }
  180. +
  181. + fclose(fh);
  182. +
  183. + if (currline < 28) {
  184. + return -1;
  185. + }
  186. +
  187. + snmp6_submit(ifname, "if_octets", data[23 - offset], data[24 - offset]);
  188. + snmp6_submit(ifname, "if_octets_mcast", data[25 - offset], data[26 - offset]);
  189. + snmp6_submit(ifname, "if_octets_bcast", data[27 - offset], data[28 - offset]);
  190. + return 0;
  191. +}
  192. +
  193. +int read_all_interfaces(void) {
  194. +#ifndef HAVE_IFADDRS_H
  195. + return -1;
  196. +#else
  197. +
  198. + // getifaddrs is not working all the time (e.g. wireguard interfaces)
  199. + // instead we use if_nameindex() syscall as suggested in:
  200. + // https://stackoverflow.com/a/45796495/8474618
  201. + struct if_nameindex *if_nidxs, *intf;
  202. +
  203. + if_nidxs = if_nameindex();
  204. +
  205. + if (if_nidxs != NULL) {
  206. + for (intf = if_nidxs; intf->if_index != 0 || intf->if_name != NULL; intf++) {
  207. + snmp_read(intf->if_name);
  208. + }
  209. + if_freenameindex(if_nidxs);
  210. + }
  211. +
  212. + snmp_read("all");
  213. + return 0;
  214. +#endif
  215. +}
  216. +
  217. +void module_register(void) {
  218. + plugin_register_config("snmp6", snmp6_config, config_keys, config_keys_num);
  219. + plugin_register_read("snmp6", read_all_interfaces);
  220. +} /* void module_register */
  221. --- a/src/types.db
  222. +++ b/src/types.db
  223. @@ -132,6 +132,8 @@ if_dropped rx:DERIVE:0:U, t
  224. if_errors rx:DERIVE:0:U, tx:DERIVE:0:U
  225. if_multicast value:DERIVE:0:U
  226. if_octets rx:DERIVE:0:U, tx:DERIVE:0:U
  227. +if_octets_mcast rx:DERIVE:0:U, tx:DERIVE:0:U
  228. +if_octets_bcast rx:DERIVE:0:U, tx:DERIVE:0:U
  229. if_packets rx:DERIVE:0:U, tx:DERIVE:0:U
  230. if_rx_dropped value:DERIVE:0:U
  231. if_rx_errors value:DERIVE:0:U