@cryptotaxi247 / netdata-1 / commits / fa57c9e50

added connection tracking information via netlink

Costa Tsaousis (ktsaou) committed Mar 18, 2017 at 00:55 UTC fa57c9e50d49f3b51dcd9a5f7ec8798153af5992
2 files changed +570 -142
configure.ac
+15
@@ -363,12 +363,21 @@ AM_CONDITIONAL([ENABLE_PLUGIN_FREEIPMI], [test "${enable_plugin_freeipmi}" = "ye
363 # -----------------------------------------------------------------------------
364 # nfacct.plugin - libmnl, libnetfilter_acct
365
366 +AC_CHECK_HEADERS_ONCE([linux/netfilter/nfnetlink_conntrack.h])
367 +
368 PKG_CHECK_MODULES(
369 [NFACCT],
370 [libnetfilter_acct],
371 [have_libnetfilter_acct=yes],
372 [have_libnetfilter_acct=no]
373 )
374 +
375 +if test "${have_libnetfilter_acct}" = "yes"; then
376 + AC_DEFINE([HAVE_LIBNETFILTER_ACCT], [1], [libnetfilter_acct usability])
377 + OPTIONAL_NFACCT_CLFAGS="${OPTIONAL_NFACCT_CLFAGS} ${NFACCT_CFLAGS}"
378 + OPTIONAL_NFACCT_LIBS="${OPTIONAL_NFACCT_LIBS} ${NFACCT_LIBS}"
379 +fi
380 +
381 PKG_CHECK_MODULES(
382 [LIBMNL],
383 [libmnl],
@@ -376,6 +385,12 @@ PKG_CHECK_MODULES(
385 [have_libmnl=no]
386 )
387
388 +if test "${have_libmnl}" = "yes"; then
389 + AC_DEFINE([HAVE_LIBMNL], [1], [libmnl usability])
390 + OPTIONAL_NFACCT_CLFAGS="${OPTIONAL_NFACCT_CLFAGS} ${LIBMNL_CFLAGS}"
391 + OPTIONAL_NFACCT_LIBS="${OPTIONAL_NFACCT_LIBS} ${LIBMNL_LIBS}"
392 +fi
393 +
394 test "${enable_plugin_nfacct}" = "yes" -a "${have_libnetfilter_acct}" != "yes" && \
395 AC_MSG_ERROR([netfilter_acct required but not found])
396
src/plugin_nfacct.c
+555 -142
@@ -1,7 +1,334 @@
1 #include "common.h"
2
3 #ifdef INTERNAL_PLUGIN_NFACCT
4 +
5 +#ifdef HAVE_LIBMNL
6 #include <libmnl/libmnl.h>
7 +
8 +
9 +// ----------------------------------------------------------------------------
10 +// DO_NFSTAT - collect netfilter connection tracker statistics via netlink
11 +// example: https://github.com/formorer/pkg-conntrack-tools/blob/master/src/conntrack.c
12 +
13 +#ifdef HAVE_LINUX_NETFILTER_NFNETLINK_CONNTRACK_H
14 +#define DO_NFSTAT 1
15 +
16 +#include <linux/netfilter/nfnetlink_conntrack.h>
17 +
18 +static struct {
19 + int update_every;
20 + char *buf;
21 + size_t buf_size;
22 + struct mnl_socket *mnl;
23 + struct nlmsghdr *nlh;
24 + struct nfgenmsg *nfh;
25 + unsigned int seq;
26 + uint32_t portid;
27 + struct nlattr *tb[CTA_STATS_MAX+1];
28 + const char *attr2name[CTA_STATS_MAX+1];
29 + kernel_uint_t metrics[CTA_STATS_MAX+1];
30 +} nfstat_root = {
31 + .update_every = 1,
32 + .buf = NULL,
33 + .buf_size = 0,
34 + .mnl = NULL,
35 + .nlh = NULL,
36 + .nfh = NULL,
37 + .seq = 0,
38 + .portid = 0,
39 + .tb = {},
40 + .attr2name = {
41 + [CTA_STATS_SEARCHED] = "searched",
42 + [CTA_STATS_FOUND] = "found",
43 + [CTA_STATS_NEW] = "new",
44 + [CTA_STATS_INVALID] = "invalid",
45 + [CTA_STATS_IGNORE] = "ignore",
46 + [CTA_STATS_DELETE] = "delete",
47 + [CTA_STATS_DELETE_LIST] = "delete_list",
48 + [CTA_STATS_INSERT] = "insert",
49 + [CTA_STATS_INSERT_FAILED] = "insert_failed",
50 + [CTA_STATS_DROP] = "drop",
51 + [CTA_STATS_EARLY_DROP] = "early_drop",
52 + [CTA_STATS_ERROR] = "icmp_error",
53 + [CTA_STATS_SEARCH_RESTART] = "search_restart",
54 + },
55 + .metrics = {}
56 +};
57 +
58 +
59 +static int nfstat_init(int update_every) {
60 + nfstat_root.update_every = update_every;
61 +
62 + nfstat_root.buf_size = (size_t)MNL_SOCKET_BUFFER_SIZE;
63 + nfstat_root.buf = mallocz(nfstat_root.buf_size);
64 +
65 + nfstat_root.mnl = mnl_socket_open(NETLINK_NETFILTER);
66 + if(!nfstat_root.mnl) {
67 + error("NFSTAT: mnl_socket_open() failed");
68 + return 1;
69 + }
70 +
71 + nfstat_root.seq = (unsigned int)now_realtime_sec() - 1;
72 +
73 + if(mnl_socket_bind(nfstat_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
74 + error("NFSTAT: mnl_socket_bind() failed");
75 + return 1;
76 + }
77 + nfstat_root.portid = mnl_socket_get_portid(nfstat_root.mnl);
78 +
79 + return 0;
80 +}
81 +
82 +static void nfstat_cleanup() {
83 + if(nfstat_root.mnl) {
84 + mnl_socket_close(nfstat_root.mnl);
85 + nfstat_root.mnl = NULL;
86 + }
87 +
88 + freez(nfstat_root.buf);
89 + nfstat_root.buf = NULL;
90 + nfstat_root.buf_size = 0;
91 +}
92 +
93 +static int nfct_stats_attr_cb(const struct nlattr *attr, void *data) {
94 + const struct nlattr **tb = data;
95 + int type = mnl_attr_get_type(attr);
96 +
97 + if (mnl_attr_type_valid(attr, CTA_STATS_MAX) < 0)
98 + return MNL_CB_OK;
99 +
100 + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
101 + error("NFSTAT: mnl_attr_validate() failed");
102 + return MNL_CB_ERROR;
103 + }
104 +
105 + tb[type] = attr;
106 + return MNL_CB_OK;
107 +}
108 +
109 +static int nfstat_callback(const struct nlmsghdr *nlh, void *data) {
110 + (void)data;
111 +
112 + struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
113 +
114 + mnl_attr_parse(nlh, sizeof(*nfg), nfct_stats_attr_cb, nfstat_root.tb);
115 +
116 + // printf("cpu=%-4u\t", ntohs(nfg->res_id));
117 +
118 + int i;
119 + // add the metrics of this CPU into the metrics
120 + for (i = 0; i < CTA_STATS_MAX+1; i++) {
121 + if (nfstat_root.tb[i]) {
122 + // printf("%s=%u ", nfstat_root.attr2name[i], ntohl(mnl_attr_get_u32(nfstat_root.tb[i])));
123 + nfstat_root.metrics[i] += ntohl(mnl_attr_get_u32(nfstat_root.tb[i]));
124 + }
125 + }
126 + // printf("\n");
127 +
128 + return MNL_CB_OK;
129 +}
130 +
131 +static int nfstat_collect() {
132 + int i;
133 +
134 + // zero all metrics - we will sum the metrics of all CPUs later
135 + for (i = 0; i < CTA_STATS_MAX+1; i++)
136 + nfstat_root.metrics[i] = 0;
137 +
138 + // prepare the request
139 + nfstat_root.nlh = mnl_nlmsg_put_header(nfstat_root.buf);
140 + nfstat_root.nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET_STATS_CPU;
141 + nfstat_root.nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
142 + nfstat_root.nlh->nlmsg_seq = nfstat_root.seq++;
143 +
144 + nfstat_root.nfh = mnl_nlmsg_put_extra_header(nfstat_root.nlh, sizeof(struct nfgenmsg));
145 + nfstat_root.nfh->nfgen_family = AF_UNSPEC;
146 + nfstat_root.nfh->version = NFNETLINK_V0;
147 + nfstat_root.nfh->res_id = 0;
148 +
149 + // send the request
150 + if(mnl_socket_sendto(nfstat_root.mnl, nfstat_root.nlh, nfstat_root.nlh->nlmsg_len) < 0) {
151 + error("NFSTAT: mnl_socket_sendto() failed");
152 + return 1;
153 + }
154 +
155 + // get the reply
156 + ssize_t ret;
157 + while ((ret = mnl_socket_recvfrom(nfstat_root.mnl, nfstat_root.buf, nfstat_root.buf_size)) > 0) {
158 + if(mnl_cb_run(
159 + nfstat_root.buf
160 + , (size_t)ret
161 + , nfstat_root.nlh->nlmsg_seq
162 + , nfstat_root.portid
163 + , nfstat_callback
164 + , NULL
165 + ) <= MNL_CB_STOP)
166 + break;
167 + }
168 +
169 + // verify we run without issues
170 + if (ret == -1) {
171 + error("NFSTAT: error communicating with kernel. This plugin can only work when netdata runs as root.");
172 + return 1;
173 + }
174 +
175 + return 0;
176 +}
177 +
178 +#define RRD_TYPE_NET_STAT_NETFILTER "netfilter2"
179 +#define RRD_TYPE_NET_STAT_CONNTRACK "conntrack2"
180 +
181 +static void nfstat_send_metrics() {
182 +
183 + {
184 + static RRDSET *st_new = NULL;
185 + static RRDDIM *rd_new = NULL, *rd_ignore = NULL, *rd_invalid = NULL;
186 +
187 + if(!st_new) {
188 + st_new = rrdset_create_localhost(
189 + RRD_TYPE_NET_STAT_NETFILTER
190 + , RRD_TYPE_NET_STAT_CONNTRACK "_new"
191 + , NULL
192 + , RRD_TYPE_NET_STAT_CONNTRACK
193 + , NULL
194 + , "Connection Tracker New Connections"
195 + , "connections/s"
196 + , 3001
197 + , nfstat_root.update_every
198 + , RRDSET_TYPE_LINE
199 + );
200 +
201 + rd_new = rrddim_add(st_new, nfstat_root.attr2name[CTA_STATS_NEW], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
202 + rd_ignore = rrddim_add(st_new, nfstat_root.attr2name[CTA_STATS_IGNORE], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
203 + rd_invalid = rrddim_add(st_new, nfstat_root.attr2name[CTA_STATS_INVALID], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
204 + }
205 + else
206 + rrdset_next(st_new);
207 +
208 + rrddim_set_by_pointer(st_new, rd_new, (collected_number) nfstat_root.metrics[CTA_STATS_NEW]);
209 + rrddim_set_by_pointer(st_new, rd_ignore, (collected_number) nfstat_root.metrics[CTA_STATS_IGNORE]);
210 + rrddim_set_by_pointer(st_new, rd_invalid, (collected_number) nfstat_root.metrics[CTA_STATS_INVALID]);
211 +
212 + rrdset_done(st_new);
213 + }
214 +
215 + // ----------------------------------------------------------------
216 +
217 + {
218 + static RRDSET *st_changes = NULL;
219 + static RRDDIM *rd_inserted = NULL, *rd_deleted = NULL, *rd_delete_list = NULL;
220 +
221 + if(!st_changes) {
222 + st_changes = rrdset_create_localhost(
223 + RRD_TYPE_NET_STAT_NETFILTER
224 + , RRD_TYPE_NET_STAT_CONNTRACK "_changes"
225 + , NULL
226 + , RRD_TYPE_NET_STAT_CONNTRACK
227 + , NULL
228 + , "Connection Tracker Changes"
229 + , "changes/s"
230 + , 3002
231 + , nfstat_root.update_every
232 + , RRDSET_TYPE_LINE
233 + );
234 + rrdset_flag_set(st_changes, RRDSET_FLAG_DETAIL);
235 +
236 + rd_inserted = rrddim_add(st_changes, nfstat_root.attr2name[CTA_STATS_INSERT], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
237 + rd_deleted = rrddim_add(st_changes, nfstat_root.attr2name[CTA_STATS_DELETE], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
238 + rd_delete_list = rrddim_add(st_changes, nfstat_root.attr2name[CTA_STATS_DELETE_LIST], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
239 + }
240 + else
241 + rrdset_next(st_changes);
242 +
243 + rrddim_set_by_pointer(st_changes, rd_inserted, (collected_number) nfstat_root.metrics[CTA_STATS_INSERT]);
244 + rrddim_set_by_pointer(st_changes, rd_deleted, (collected_number) nfstat_root.metrics[CTA_STATS_DELETE]);
245 + rrddim_set_by_pointer(st_changes, rd_delete_list, (collected_number) nfstat_root.metrics[CTA_STATS_DELETE_LIST]);
246 +
247 + rrdset_done(st_changes);
248 + }
249 +
250 + // ----------------------------------------------------------------
251 +
252 + {
253 + static RRDSET *st_search = NULL;
254 + static RRDDIM *rd_searched = NULL, *rd_restarted = NULL, *rd_found = NULL;
255 +
256 + if(!st_search) {
257 + st_search = rrdset_create_localhost(
258 + RRD_TYPE_NET_STAT_NETFILTER
259 + , RRD_TYPE_NET_STAT_CONNTRACK "_search"
260 + , NULL
261 + , RRD_TYPE_NET_STAT_CONNTRACK
262 + , NULL
263 + , "Connection Tracker Searches"
264 + , "searches/s"
265 + , 3010
266 + , nfstat_root.update_every
267 + , RRDSET_TYPE_LINE
268 + );
269 + rrdset_flag_set(st_search, RRDSET_FLAG_DETAIL);
270 +
271 + rd_searched = rrddim_add(st_search, nfstat_root.attr2name[CTA_STATS_SEARCHED], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
272 + rd_restarted = rrddim_add(st_search, nfstat_root.attr2name[CTA_STATS_SEARCH_RESTART], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
273 + rd_found = rrddim_add(st_search, nfstat_root.attr2name[CTA_STATS_FOUND], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
274 + }
275 + else
276 + rrdset_next(st_search);
277 +
278 + rrddim_set_by_pointer(st_search, rd_searched, (collected_number) nfstat_root.metrics[CTA_STATS_SEARCHED]);
279 + rrddim_set_by_pointer(st_search, rd_restarted, (collected_number) nfstat_root.metrics[CTA_STATS_SEARCH_RESTART]);
280 + rrddim_set_by_pointer(st_search, rd_found, (collected_number) nfstat_root.metrics[CTA_STATS_FOUND]);
281 +
282 + rrdset_done(st_search);
283 + }
284 +
285 + // ----------------------------------------------------------------
286 +
287 + {
288 + static RRDSET *st_errors = NULL;
289 + static RRDDIM *rd_error = NULL, *rd_insert_failed = NULL, *rd_drop = NULL, *rd_early_drop = NULL;
290 +
291 + if(!st_errors) {
292 + st_errors = rrdset_create_localhost(
293 + RRD_TYPE_NET_STAT_NETFILTER
294 + , RRD_TYPE_NET_STAT_CONNTRACK "_errors"
295 + , NULL
296 + , RRD_TYPE_NET_STAT_CONNTRACK
297 + , NULL
298 + , "Connection Tracker Errors"
299 + , "events/s"
300 + , 3005
301 + , nfstat_root.update_every
302 + , RRDSET_TYPE_LINE
303 + );
304 + rrdset_flag_set(st_errors, RRDSET_FLAG_DETAIL);
305 +
306 + rd_error = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_ERROR], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
307 + rd_insert_failed = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_INSERT_FAILED], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
308 + rd_drop = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_DROP], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
309 + rd_early_drop = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_EARLY_DROP], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
310 + }
311 + else
312 + rrdset_next(st_errors);
313 +
314 + rrddim_set_by_pointer(st_errors, rd_error, (collected_number) nfstat_root.metrics[CTA_STATS_ERROR]);
315 + rrddim_set_by_pointer(st_errors, rd_insert_failed, (collected_number) nfstat_root.metrics[CTA_STATS_INSERT_FAILED]);
316 + rrddim_set_by_pointer(st_errors, rd_drop, (collected_number) nfstat_root.metrics[CTA_STATS_DROP]);
317 + rrddim_set_by_pointer(st_errors, rd_early_drop, (collected_number) nfstat_root.metrics[CTA_STATS_EARLY_DROP]);
318 +
319 + rrdset_done(st_errors);
320 + }
321 +}
322 +
323 +#endif // HAVE_LINUX_NETFILTER_NFNETLINK_CONNTRACK_H
324 +
325 +
326 +// ----------------------------------------------------------------------------
327 +// DO_NFACCT - collect netfilter accounting statistics via netlink
328 +
329 +#ifdef HAVE_LIBNETFILTER_ACCT
330 +#define DO_NFACCT 1
331 +
332 #include <libnetfilter_acct/libnetfilter_acct.h>
333
334 struct nfacct_data {
@@ -19,10 +346,24 @@ struct nfacct_data {
346 struct nfacct_data *next;
347 };
348
22 -static struct nfacct_list {
349 +static struct {
350 + int update_every;
351 + char *buf;
352 + size_t buf_size;
353 + struct mnl_socket *mnl;
354 + struct nlmsghdr *nlh;
355 + unsigned int seq;
356 + uint32_t portid;
357 struct nfacct *nfacct_buffer;
358 struct nfacct_data *nfacct_metrics;
359 } nfacct_root = {
360 + .update_every = 1,
361 + .buf = NULL,
362 + .buf_size = 0,
363 + .mnl = NULL,
364 + .nlh = NULL,
365 + .seq = 0,
366 + .portid = 0,
367 .nfacct_buffer = NULL,
368 .nfacct_metrics = NULL
369 };
@@ -50,11 +391,58 @@ static inline struct nfacct_data *nfacct_data_get(const char *name, uint32_t has
391 return d;
392 }
393
394 +static int nfacct_init(int update_every) {
395 + nfacct_root.update_every = update_every;
396 +
397 + nfacct_root.buf_size = (size_t)MNL_SOCKET_BUFFER_SIZE;
398 + nfacct_root.buf = mallocz(nfacct_root.buf_size);
399 +
400 + nfacct_root.nfacct_buffer = nfacct_alloc();
401 + if(!nfacct_root.nfacct_buffer) {
402 + error("nfacct.plugin: nfacct_alloc() failed.");
403 + return 0;
404 + }
405 +
406 + nfacct_root.seq = (unsigned int)now_realtime_sec() - 1;
407 +
408 + nfacct_root.mnl = mnl_socket_open(NETLINK_NETFILTER);
409 + if(!nfacct_root.mnl) {
410 + error("nfacct.plugin: mnl_socket_open() failed");
411 + return 1;
412 + }
413 +
414 + if(mnl_socket_bind(nfacct_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
415 + error("nfacct.plugin: mnl_socket_bind() failed");
416 + return 1;
417 + }
418 + nfacct_root.portid = mnl_socket_get_portid(nfacct_root.mnl);
419 +
420 + return 0;
421 +}
422 +
423 +static void nfacct_cleanup() {
424 + if(nfacct_root.mnl) {
425 + mnl_socket_close(nfacct_root.mnl);
426 + nfacct_root.mnl = NULL;
427 + }
428 +
429 + if(nfacct_root.nfacct_buffer) {
430 + nfacct_free(nfacct_root.nfacct_buffer);
431 + nfacct_root.nfacct_buffer = NULL;
432 + }
433 +
434 + freez(nfacct_root.buf);
435 + nfacct_root.buf = NULL;
436 + nfacct_root.buf_size = 0;
437 +
438 + // FIXME: cleanup the metrics linked list
439 +}
440 +
441 static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
442 (void)data;
443
444 if(nfacct_nlmsg_parse_payload(nlh, nfacct_root.nfacct_buffer) < 0) {
57 - error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
445 + error("NFACCT: nfacct_nlmsg_parse_payload() failed.");
446 return MNL_CB_OK;
447 }
448
@@ -70,50 +458,166 @@ static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
458 return MNL_CB_OK;
459 }
460
73 -void *nfacct_main(void *ptr) {
74 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
461 +static int nfacct_collect() {
462 + // mark all old metrics as not-updated
463 + struct nfacct_data *d;
464 + for(d = nfacct_root.nfacct_metrics; d ; d = d->next)
465 + d->updated = 0;
466 +
467 + // prepare the request
468 + nfacct_root.seq++;
469 + nfacct_root.nlh = nfacct_nlmsg_build_hdr(nfacct_root.buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, (uint32_t)nfacct_root.seq);
470 + if(!nfacct_root.nlh) {
471 + error("NFACCT: nfacct_nlmsg_build_hdr() failed");
472 + return 1;
473 + }
474
76 - info("NFACCT thread created with task id %d", gettid());
475 + // send the request
476 + if(mnl_socket_sendto(nfacct_root.mnl, nfacct_root.nlh, nfacct_root.nlh->nlmsg_len) < 0) {
477 + error("NFACCT: mnl_socket_sendto() failed");
478 + return 1;
479 + }
480
78 - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
79 - error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
481 + // get the reply
482 + ssize_t ret;
483 + while((ret = mnl_socket_recvfrom(nfacct_root.mnl, nfacct_root.buf, nfacct_root.buf_size)) > 0) {
484 + if(mnl_cb_run(
485 + nfacct_root.buf
486 + , (size_t)ret
487 + , nfacct_root.seq
488 + , nfacct_root.portid
489 + , nfacct_callback
490 + , NULL
491 + ) <= 0)
492 + break;
493 + }
494
81 - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
82 - error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
495 + // verify we run without issues
496 + if (ret == -1) {
497 + error("NFACCT: error communicating with kernel. This plugin can only work when netdata runs as root.");
498 + return 1;
499 + }
500
84 - nfacct_root.nfacct_buffer = nfacct_alloc();
85 - if(!nfacct_root.nfacct_buffer)
86 - fatal("nfacct.plugin: nfacct_alloc() failed.");
501 + return 0;
502 +}
503
88 - char buf[MNL_SOCKET_BUFFER_SIZE];
89 - struct mnl_socket *nl = NULL;
90 - struct nlmsghdr *nlh = NULL;
91 - unsigned int seq = 0, portid = 0;
504 +static void nfacct_send_metrics() {
505 + static RRDSET *st_bytes = NULL, *st_packets = NULL;
506 +
507 + if(!nfacct_root.nfacct_metrics) return;
508 + struct nfacct_data *d;
509 +
510 + if(!st_packets) {
511 + st_packets = rrdset_create_localhost(
512 + "netfilter"
513 + , "nfacct_packets"
514 + , NULL
515 + , "nfacct"
516 + , NULL
517 + , "Netfilter Accounting Packets"
518 + , "packets/s"
519 + , 3206
520 + , nfacct_root.update_every
521 + , RRDSET_TYPE_STACKED
522 + );
523 + }
524 + else rrdset_next(st_packets);
525 +
526 + for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
527 + if(likely(d->updated)) {
528 + if(unlikely(!d->rd_packets))
529 + d->rd_packets = rrddim_add(
530 + st_packets
531 + , d->name
532 + , NULL
533 + , 1
534 + , nfacct_root.update_every
535 + , RRD_ALGORITHM_INCREMENTAL
536 + );
537
93 - seq = (unsigned int)now_realtime_sec() - 1;
538 + rrddim_set_by_pointer(
539 + st_packets
540 + , d->rd_packets
541 + , (collected_number)d->pkts
542 + );
543 + }
544 + }
545
95 - nl = mnl_socket_open(NETLINK_NETFILTER);
96 - if(!nl) {
97 - error("nfacct.plugin: mnl_socket_open() failed");
98 - goto cleanup;
546 + rrdset_done(st_packets);
547 +
548 + // ----------------------------------------------------------------
549 +
550 + st_bytes = rrdset_find_bytype_localhost("netfilter", "nfacct_bytes");
551 + if(!st_bytes) {
552 + st_bytes = rrdset_create_localhost(
553 + "netfilter"
554 + , "nfacct_bytes"
555 + , NULL
556 + , "nfacct"
557 + , NULL
558 + , "Netfilter Accounting Bandwidth"
559 + , "kilobytes/s"
560 + , 3207
561 + , nfacct_root.update_every
562 + , RRDSET_TYPE_STACKED
563 + );
564 }
565 + else rrdset_next(st_bytes);
566 +
567 + for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
568 + if(likely(d->updated)) {
569 + if(unlikely(!d->rd_bytes))
570 + d->rd_bytes = rrddim_add(
571 + st_bytes
572 + , d->name
573 + , NULL
574 + , 1
575 + , 1000 * nfacct_root.update_every
576 + , RRD_ALGORITHM_INCREMENTAL
577 + );
578
101 - if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
102 - error("nfacct.plugin: mnl_socket_bind() failed");
103 - goto cleanup;
579 + rrddim_set_by_pointer(
580 + st_bytes
581 + , d->rd_bytes
582 + , (collected_number)d->bytes
583 + );
584 + }
585 }
105 - portid = mnl_socket_get_portid(nl);
586
107 - // ------------------------------------------------------------------------
587 + rrdset_done(st_bytes);
588 +}
589
109 - RRDSET *st_bytes = NULL, *st_packets = NULL;
590 +#endif // HAVE_LIBNETFILTER_ACCT
591 +#endif // HAVE_LIBMNL
592
111 - // ------------------------------------------------------------------------
593 +// ----------------------------------------------------------------------------
594 +
595 +void *nfacct_main(void *ptr) {
596 + struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
597 +
598 + info("NETFILTER thread created with task id %d", gettid());
599
113 - int update_every = (int)config_get_number("plugin:nfacct", "update every", localhost->rrd_update_every);
600 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
601 + error("NETFILTER: Cannot set pthread cancel type to DEFERRED.");
602 +
603 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
604 + error("NETFILTER: Cannot set pthread cancel state to ENABLE.");
605 +
606 +
607 + int update_every = (int)config_get_number("plugin:netfilter", "update every", localhost->rrd_update_every);
608 if(update_every < localhost->rrd_update_every)
609 update_every = localhost->rrd_update_every;
610
611 +#ifdef DO_NFACCT
612 + int nfacct = !nfacct_init(update_every);
613 +#endif
614 +
615 +#ifdef DO_NFSTAT
616 + int nfstat = !nfstat_init(update_every);
617 +#endif
618 +
619 + // ------------------------------------------------------------------------
620 +
621 usec_t step = update_every * USEC_PER_SEC;
622 heartbeat_t hb;
623 heartbeat_init(&hb);
@@ -123,129 +627,38 @@ void *nfacct_main(void *ptr) {
627
628 if(unlikely(netdata_exit)) break;
629
126 - seq++;
127 -
128 - nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, (uint32_t)seq);
129 - if(!nlh) {
130 - error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
131 - goto cleanup;
132 - }
630 +#ifdef DO_NFACCT
631 + if(likely(nfacct)) {
632 + nfacct = !nfacct_collect();
633
134 - if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
135 - error("nfacct.plugin: mnl_socket_send");
136 - goto cleanup;
634 + if(likely(nfacct))
635 + nfacct_send_metrics();
636 }
637 +#endif
638
139 - ssize_t ret;
140 - while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
141 - if((ret = mnl_cb_run(buf, (size_t)ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
142 - }
639 +#ifdef DO_NFSTAT
640 + if(likely(nfstat)) {
641 + nfstat = !nfstat_collect();
642
144 - if (ret == -1) {
145 - error("nfacct.plugin: error communicating with kernel. NFACCT plugin can only work when netdata runs as root.");
146 - goto cleanup;
147 - }
148 -
149 - // --------------------------------------------------------------------
150 -
151 - if(nfacct_root.nfacct_metrics) {
152 - struct nfacct_data *d;
153 -
154 - if(!st_packets) {
155 - st_packets = rrdset_create_localhost(
156 - "netfilter"
157 - , "nfacct_packets"
158 - , NULL
159 - , "nfacct"
160 - , NULL
161 - , "Netfilter Accounting Packets"
162 - , "packets/s"
163 - , 3206
164 - , update_every
165 - , RRDSET_TYPE_STACKED
166 - );
167 - }
168 - else rrdset_next(st_packets);
169 -
170 - for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
171 - if(likely(d->updated)) {
172 - if(unlikely(!d->rd_packets))
173 - d->rd_packets = rrddim_add(
174 - st_packets
175 - , d->name
176 - , NULL
177 - , 1
178 - , update_every
179 - , RRD_ALGORITHM_INCREMENTAL
180 - );
181 -
182 - rrddim_set_by_pointer(
183 - st_packets
184 - , d->rd_packets
185 - , (collected_number)d->pkts
186 - );
187 - }
188 - }
189 -
190 - rrdset_done(st_packets);
191 -
192 - // ----------------------------------------------------------------
193 -
194 - st_bytes = rrdset_find_bytype_localhost("netfilter", "nfacct_bytes");
195 - if(!st_bytes) {
196 - st_bytes = rrdset_create_localhost(
197 - "netfilter"
198 - , "nfacct_bytes"
199 - , NULL
200 - , "nfacct"
201 - , NULL
202 - , "Netfilter Accounting Bandwidth"
203 - , "kilobytes/s"
204 - , 3207
205 - , update_every
206 - , RRDSET_TYPE_STACKED
207 - );
208 - }
209 - else rrdset_next(st_bytes);
210 -
211 - for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
212 - if(likely(d->updated)) {
213 - if(unlikely(!d->rd_bytes))
214 - d->rd_bytes = rrddim_add(
215 - st_bytes
216 - , d->name
217 - , NULL
218 - , 1
219 - , 1000 * update_every
220 - , RRD_ALGORITHM_INCREMENTAL
221 - );
222 -
223 - rrddim_set_by_pointer(
224 - st_bytes
225 - , d->rd_bytes
226 - , (collected_number)d->bytes
227 - );
228 - }
229 - }
230 -
231 - rrdset_done(st_bytes);
232 -
233 -
234 - // ----------------------------------------------------------------
235 - // prepare for the next loop
236 -
237 - for(d = nfacct_root.nfacct_metrics; d ; d = d->next)
238 - d->updated = 0;
643 + if(likely(nfstat))
644 + nfstat_send_metrics();
645 }
646 +#endif
647 }
648
242 -cleanup:
243 - info("NFACCT thread exiting");
649 + info("NETFILTER thread exiting");
650
245 - if(nl) mnl_socket_close(nl);
651 +#ifdef DO_NFACCT
652 + nfacct_cleanup();
653 +#endif
654 +
655 +#ifdef DO_NFSTAT
656 + nfstat_cleanup();
657 +#endif
658
659 static_thread->enabled = 0;
660 pthread_exit(NULL);
661 return NULL;
662 }
251 -#endif
663 +
664 +#endif // INTERNAL_PLUGIN_NFACCT