3 #ifdef INTERNAL_PLUGIN_NFACCT
6 #include <libmnl/libmnl.h>
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
13 #ifdef HAVE_LINUX_NETFILTER_NFNETLINK_CONNTRACK_H
16 #include <linux/netfilter/nfnetlink_conntrack.h>
22 struct mnl_socket *mnl;
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];
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",
59 static int nfstat_init(int update_every) {
60 nfstat_root.update_every = update_every;
62 nfstat_root.buf_size = (size_t)MNL_SOCKET_BUFFER_SIZE;
63 nfstat_root.buf = mallocz(nfstat_root.buf_size);
65 nfstat_root.mnl = mnl_socket_open(NETLINK_NETFILTER);
66 if(!nfstat_root.mnl) {
67 error("NFSTAT: mnl_socket_open() failed");
71 nfstat_root.seq = (unsigned int)now_realtime_sec() - 1;
73 if(mnl_socket_bind(nfstat_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
74 error("NFSTAT: mnl_socket_bind() failed");
77 nfstat_root.portid = mnl_socket_get_portid(nfstat_root.mnl);
82 static void nfstat_cleanup() {
84 mnl_socket_close(nfstat_root.mnl);
85 nfstat_root.mnl = NULL;
88 freez(nfstat_root.buf);
89 nfstat_root.buf = NULL;
90 nfstat_root.buf_size = 0;
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);
97 if (mnl_attr_type_valid(attr, CTA_STATS_MAX) < 0)
100 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
101 error("NFSTAT: mnl_attr_validate() failed");
109 static int nfstat_callback(const struct nlmsghdr *nlh, void *data) {
112 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
114 mnl_attr_parse(nlh, sizeof(*nfg), nfct_stats_attr_cb, nfstat_root.tb);
116 // printf("cpu=%-4u\t", ntohs(nfg->res_id));
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]));
131 static int nfstat_collect() {
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;
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++;
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;
150 if(mnl_socket_sendto(nfstat_root.mnl, nfstat_root.nlh, nfstat_root.nlh->nlmsg_len) < 0) {
151 error("NFSTAT: mnl_socket_sendto() failed");
157 while ((ret = mnl_socket_recvfrom(nfstat_root.mnl, nfstat_root.buf, nfstat_root.buf_size)) > 0) {
161 , nfstat_root.nlh->nlmsg_seq
169 // verify we run without issues
171 error("NFSTAT: error communicating with kernel. This plugin can only work when netdata runs as root.");
178 #define RRD_TYPE_NET_STAT_NETFILTER "netfilter2"
179 #define RRD_TYPE_NET_STAT_CONNTRACK "conntrack2"
181 static void nfstat_send_metrics() {
184 static RRDSET *st_new = NULL;
185 static RRDDIM *rd_new = NULL, *rd_ignore = NULL, *rd_invalid = NULL;
188 st_new = rrdset_create_localhost(
189 RRD_TYPE_NET_STAT_NETFILTER
190 , RRD_TYPE_NET_STAT_CONNTRACK "_new"
192 , RRD_TYPE_NET_STAT_CONNTRACK
194 , "Connection Tracker New Connections"
197 , nfstat_root.update_every
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);
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]);
215 // ----------------------------------------------------------------
218 static RRDSET *st_changes = NULL;
219 static RRDDIM *rd_inserted = NULL, *rd_deleted = NULL, *rd_delete_list = NULL;
222 st_changes = rrdset_create_localhost(
223 RRD_TYPE_NET_STAT_NETFILTER
224 , RRD_TYPE_NET_STAT_CONNTRACK "_changes"
226 , RRD_TYPE_NET_STAT_CONNTRACK
228 , "Connection Tracker Changes"
231 , nfstat_root.update_every
234 rrdset_flag_set(st_changes, RRDSET_FLAG_DETAIL);
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);
241 rrdset_next(st_changes);
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]);
247 rrdset_done(st_changes);
250 // ----------------------------------------------------------------
253 static RRDSET *st_search = NULL;
254 static RRDDIM *rd_searched = NULL, *rd_restarted = NULL, *rd_found = NULL;
257 st_search = rrdset_create_localhost(
258 RRD_TYPE_NET_STAT_NETFILTER
259 , RRD_TYPE_NET_STAT_CONNTRACK "_search"
261 , RRD_TYPE_NET_STAT_CONNTRACK
263 , "Connection Tracker Searches"
266 , nfstat_root.update_every
269 rrdset_flag_set(st_search, RRDSET_FLAG_DETAIL);
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);
276 rrdset_next(st_search);
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]);
282 rrdset_done(st_search);
285 // ----------------------------------------------------------------
288 static RRDSET *st_errors = NULL;
289 static RRDDIM *rd_error = NULL, *rd_insert_failed = NULL, *rd_drop = NULL, *rd_early_drop = NULL;
292 st_errors = rrdset_create_localhost(
293 RRD_TYPE_NET_STAT_NETFILTER
294 , RRD_TYPE_NET_STAT_CONNTRACK "_errors"
296 , RRD_TYPE_NET_STAT_CONNTRACK
298 , "Connection Tracker Errors"
301 , nfstat_root.update_every
304 rrdset_flag_set(st_errors, RRDSET_FLAG_DETAIL);
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);
312 rrdset_next(st_errors);
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]);
319 rrdset_done(st_errors);
323 #endif // HAVE_LINUX_NETFILTER_NFNETLINK_CONNTRACK_H
326 // ----------------------------------------------------------------------------
327 // DO_NFACCT - collect netfilter accounting statistics via netlink
329 #ifdef HAVE_LIBNETFILTER_ACCT
332 #include <libnetfilter_acct/libnetfilter_acct.h>
346 struct nfacct_data *next;
353 struct mnl_socket *mnl;
354 struct nlmsghdr *nlh;
357 struct nfacct *nfacct_buffer;
358 struct nfacct_data *nfacct_metrics;
367 .nfacct_buffer = NULL,
368 .nfacct_metrics = NULL
371 static inline struct nfacct_data *nfacct_data_get(const char *name, uint32_t hash) {
372 struct nfacct_data *d = NULL, *last = NULL;
373 for(d = nfacct_root.nfacct_metrics; d ; last = d, d = d->next) {
374 if(unlikely(d->hash == hash && !strcmp(d->name, name)))
378 d = callocz(1, sizeof(struct nfacct_data));
379 d->name = strdupz(name);
383 d->next = nfacct_root.nfacct_metrics;
384 nfacct_root.nfacct_metrics = d;
387 d->next = last->next;
394 static int nfacct_init(int update_every) {
395 nfacct_root.update_every = update_every;
397 nfacct_root.buf_size = (size_t)MNL_SOCKET_BUFFER_SIZE;
398 nfacct_root.buf = mallocz(nfacct_root.buf_size);
400 nfacct_root.nfacct_buffer = nfacct_alloc();
401 if(!nfacct_root.nfacct_buffer) {
402 error("nfacct.plugin: nfacct_alloc() failed.");
406 nfacct_root.seq = (unsigned int)now_realtime_sec() - 1;
408 nfacct_root.mnl = mnl_socket_open(NETLINK_NETFILTER);
409 if(!nfacct_root.mnl) {
410 error("nfacct.plugin: mnl_socket_open() failed");
414 if(mnl_socket_bind(nfacct_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
415 error("nfacct.plugin: mnl_socket_bind() failed");
418 nfacct_root.portid = mnl_socket_get_portid(nfacct_root.mnl);
423 static void nfacct_cleanup() {
424 if(nfacct_root.mnl) {
425 mnl_socket_close(nfacct_root.mnl);
426 nfacct_root.mnl = NULL;
429 if(nfacct_root.nfacct_buffer) {
430 nfacct_free(nfacct_root.nfacct_buffer);
431 nfacct_root.nfacct_buffer = NULL;
434 freez(nfacct_root.buf);
435 nfacct_root.buf = NULL;
436 nfacct_root.buf_size = 0;
438 // FIXME: cleanup the metrics linked list
441 static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
444 if(nfacct_nlmsg_parse_payload(nlh, nfacct_root.nfacct_buffer) < 0) {
445 error("NFACCT: nfacct_nlmsg_parse_payload() failed.");
449 const char *name = nfacct_attr_get_str(nfacct_root.nfacct_buffer, NFACCT_ATTR_NAME);
450 uint32_t hash = simple_hash(name);
452 struct nfacct_data *d = nfacct_data_get(name, hash);
454 d->pkts = nfacct_attr_get_u64(nfacct_root.nfacct_buffer, NFACCT_ATTR_PKTS);
455 d->bytes = nfacct_attr_get_u64(nfacct_root.nfacct_buffer, NFACCT_ATTR_BYTES);
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)
467 // prepare the request
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");
476 if(mnl_socket_sendto(nfacct_root.mnl, nfacct_root.nlh, nfacct_root.nlh->nlmsg_len) < 0) {
477 error("NFACCT: mnl_socket_sendto() failed");
483 while((ret = mnl_socket_recvfrom(nfacct_root.mnl, nfacct_root.buf, nfacct_root.buf_size)) > 0) {
495 // verify we run without issues
497 error("NFACCT: error communicating with kernel. This plugin can only work when netdata runs as root.");
504 static void nfacct_send_metrics() {
505 static RRDSET *st_bytes = NULL, *st_packets = NULL;
507 if(!nfacct_root.nfacct_metrics) return;
508 struct nfacct_data *d;
511 st_packets = rrdset_create_localhost(
517 , "Netfilter Accounting Packets"
520 , nfacct_root.update_every
521 , RRDSET_TYPE_STACKED
524 else rrdset_next(st_packets);
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(
534 , nfacct_root.update_every
535 , RRD_ALGORITHM_INCREMENTAL
538 rrddim_set_by_pointer(
541 , (collected_number)d->pkts
546 rrdset_done(st_packets);
548 // ----------------------------------------------------------------
550 st_bytes = rrdset_find_bytype_localhost("netfilter", "nfacct_bytes");
552 st_bytes = rrdset_create_localhost(
558 , "Netfilter Accounting Bandwidth"
561 , nfacct_root.update_every
562 , RRDSET_TYPE_STACKED
565 else rrdset_next(st_bytes);
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(
575 , 1000 * nfacct_root.update_every
576 , RRD_ALGORITHM_INCREMENTAL
579 rrddim_set_by_pointer(
582 , (collected_number)d->bytes
587 rrdset_done(st_bytes);
590 #endif // HAVE_LIBNETFILTER_ACCT
591 #endif // HAVE_LIBMNL
593 // ----------------------------------------------------------------------------
595 void *nfacct_main(void *ptr) {
596 struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
598 info("NETFILTER thread created with task id %d", gettid());
600 if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
601 error("NETFILTER: Cannot set pthread cancel type to DEFERRED.");
603 if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
604 error("NETFILTER: Cannot set pthread cancel state to ENABLE.");
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;
612 int nfacct = !nfacct_init(update_every);
616 int nfstat = !nfstat_init(update_every);
619 // ------------------------------------------------------------------------
621 usec_t step = update_every * USEC_PER_SEC;
625 heartbeat_dt_usec(&hb);
626 heartbeat_next(&hb, step);
628 if(unlikely(netdata_exit)) break;
632 nfacct = !nfacct_collect();
635 nfacct_send_metrics();
641 nfstat = !nfstat_collect();
644 nfstat_send_metrics();
649 info("NETFILTER thread exiting");
659 static_thread->enabled = 0;
664 #endif // INTERNAL_PLUGIN_NFACCT