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