]> arthur.barton.de Git - netdata.git/blobdiff - src/plugin_nfacct.c
update nfacct plugin to match current netdata development
[netdata.git] / src / plugin_nfacct.c
index 45a65b4347beeb3cd38270ab701e6680835de0c6..cf59f31cf648ef2c83983b0a55e6a2eb18ed27da 100644 (file)
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#ifdef INTERNAL_PLUGIN_NFACCT
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <time.h>
-#include <errno.h>
+#include "common.h"
 
+#ifdef INTERNAL_PLUGIN_NFACCT
 #include <libmnl/libmnl.h>
 #include <libnetfilter_acct/libnetfilter_acct.h>
 
-#include "main.h"
-#include "global_statistics.h"
-#include "common.h"
-#include "appconfig.h"
-#include "log.h"
-#include "rrd.h"
-#include "plugin_proc.h"
-
 struct mynfacct {
-       const char *name;
-       uint64_t pkts;
-       uint64_t bytes;
-       struct nfacct *nfacct;
+    const char *name;
+    uint64_t pkts;
+    uint64_t bytes;
+
+    RRDDIM *rd_bytes;
+    RRDDIM *rd_packets;
+
+    int updated;
+
+    struct nfacct *nfacct;
 };
 
 struct nfacct_list {
-       int size;
-       int len;
-       struct mynfacct data[];
+    int size;
+    int len;
+    struct mynfacct data[];
 } *nfacct_list = NULL;
 
 static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
-       if(data) {};
-
-       if(!nfacct_list || nfacct_list->len == nfacct_list->size) {
-               int size = (nfacct_list) ? nfacct_list->size : 0;
-               int len = (nfacct_list) ? nfacct_list->len : 0;
-               size++;
-
-               info("nfacct.plugin: increasing nfacct_list to size %d", size);
-
-               nfacct_list = realloc(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
-               if(!nfacct_list) {
-                       error("nfacct.plugin: cannot allocate nfacct_list.");
-                       return MNL_CB_OK;
-               }
-
-               nfacct_list->data[len].nfacct = nfacct_alloc();
-               if(!nfacct_list->data[size - 1].nfacct) {
-                       error("nfacct.plugin: nfacct_alloc() failed.");
-                       free(nfacct_list);
-                       nfacct_list = NULL;
-                       return MNL_CB_OK;
-               }
-
-               nfacct_list->size = size;
-               nfacct_list->len = len;
-       }
-
-       if(nfacct_nlmsg_parse_payload(nlh, nfacct_list->data[nfacct_list->len].nfacct) < 0) {
-               error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
-               return MNL_CB_OK;
-       }
-
-       nfacct_list->data[nfacct_list->len].name  = nfacct_attr_get_str(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_NAME);
-       nfacct_list->data[nfacct_list->len].pkts  = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_PKTS);
-       nfacct_list->data[nfacct_list->len].bytes = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_BYTES);
-
-       nfacct_list->len++;
-       return MNL_CB_OK;
-}
-
-void *nfacct_main(void *ptr) {
-       if(ptr) { ; }
-
-       info("NFACCT thread created with task id %d", gettid());
-
-       if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
-               error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
-
-       if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-               error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
-
-       char buf[MNL_SOCKET_BUFFER_SIZE];
-       struct mnl_socket *nl = NULL;
-       struct nlmsghdr *nlh = NULL;
-       unsigned int seq = 0, portid = 0;
-
-       seq = time(NULL) - 1;
-
-       nl  = mnl_socket_open(NETLINK_NETFILTER);
-       if(!nl) {
-               error("nfacct.plugin: mnl_socket_open() failed");
-               pthread_exit(NULL);
-               return NULL;
-       }
-
-       if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
-               mnl_socket_close(nl);
-               error("nfacct.plugin: mnl_socket_bind() failed");
-               pthread_exit(NULL);
-               return NULL;
-       }
-       portid = mnl_socket_get_portid(nl);
-
-       // ------------------------------------------------------------------------
-
-       struct timeval last, now;
-       unsigned long long usec = 0, susec = 0;
-       RRDSET *st = NULL;
-
-       gettimeofday(&last, NULL);
+    (void)data;
 
-       // ------------------------------------------------------------------------
+    if(!nfacct_list || nfacct_list->len == nfacct_list->size) {
+        int size = (nfacct_list) ? nfacct_list->size : 0;
+        int len = (nfacct_list) ? nfacct_list->len : 0;
+        size++;
 
-       while(1) {
-               if(unlikely(netdata_exit)) break;
+        info("nfacct.plugin: increasing nfacct_list to size %d", size);
 
-               seq++;
+        nfacct_list = reallocz(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
 
-               nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, seq);
-               if(!nlh) {
-                       mnl_socket_close(nl);
-                       error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
-                       pthread_exit(NULL);
-                       return NULL;
-               }
+        nfacct_list->data[len].nfacct = nfacct_alloc();
+        if(!nfacct_list->data[len].nfacct) {
+            error("nfacct.plugin: nfacct_alloc() failed.");
+            free(nfacct_list);
+            nfacct_list = NULL;
+            return MNL_CB_OK;
+        }
 
-               if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
-                       error("nfacct.plugin: mnl_socket_send");
-                       pthread_exit(NULL);
-                       return NULL;
-               }
+        nfacct_list->data[len].rd_bytes = NULL;
+        nfacct_list->data[len].rd_packets = NULL;
+        nfacct_list->data[len].updated = 0;
 
-               if(nfacct_list) nfacct_list->len = 0;
+        nfacct_list->size = size;
+        nfacct_list->len = len;
+    }
 
-               int ret;
-               while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
-                       if((ret = mnl_cb_run(buf, ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
-               }
+    if(nfacct_nlmsg_parse_payload(nlh, nfacct_list->data[nfacct_list->len].nfacct) < 0) {
+        error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
+        return MNL_CB_OK;
+    }
 
-               if (ret == -1) {
-                       error("nfacct.plugin: error communicating with kernel.");
-                       pthread_exit(NULL);
-                       return NULL;
-               }
+    nfacct_list->data[nfacct_list->len].name  = nfacct_attr_get_str(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_NAME);
+    nfacct_list->data[nfacct_list->len].pkts  = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_PKTS);
+    nfacct_list->data[nfacct_list->len].bytes = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_BYTES);
+    nfacct_list->data[nfacct_list->len].updated = 1;
 
-               // --------------------------------------------------------------------
-
-               gettimeofday(&now, NULL);
-               usec = usecdiff(&now, &last) - susec;
-               debug(D_NFACCT_LOOP, "nfacct.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).", usec + susec, usec, susec);
-
-               if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
-               else susec = rrd_update_every * 1000000ULL / 2ULL;
-
-
-               // --------------------------------------------------------------------
-
-               if(nfacct_list && nfacct_list->len) {
-                       int i;
-
-                       st = rrdset_find_bytype("nfacct", "packets");
-                       if(!st) {
-                               st = rrdset_create("nfacct", "packets", NULL, "netfilter", NULL, "Netfilter Accounting Packets", "packets/s", 1006, rrd_update_every, RRDSET_TYPE_STACKED);
-
-                               for(i = 0; i < nfacct_list->len ; i++)
-                                       rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       for(i = 0; i < nfacct_list->len ; i++) {
-                               RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
-
-                               if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
-                               if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].pkts);
-                       }
-
-                       rrdset_done(st);
-
-                       // ----------------------------------------------------------------
-
-                       st = rrdset_find_bytype("nfacct", "bytes");
-                       if(!st) {
-                               st = rrdset_create("nfacct", "bytes", NULL, "netfilter", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);
-
-                               for(i = 0; i < nfacct_list->len ; i++)
-                                       rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       for(i = 0; i < nfacct_list->len ; i++) {
-                               RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
-
-                               if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
-                               if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].bytes);
-                       }
-
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               usleep(susec);
-
-               // copy current to last
-               bcopy(&now, &last, sizeof(struct timeval));
-       }
+    nfacct_list->len++;
+    return MNL_CB_OK;
+}
 
-       mnl_socket_close(nl);
-       pthread_exit(NULL);
-       return NULL;
+void *nfacct_main(void *ptr) {
+    struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
+
+    info("NFACCT thread created with task id %d", gettid());
+
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
+
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
+
+    char buf[MNL_SOCKET_BUFFER_SIZE];
+    struct mnl_socket *nl = NULL;
+    struct nlmsghdr *nlh = NULL;
+    unsigned int seq = 0, portid = 0;
+
+    seq = (unsigned int)now_realtime_sec() - 1;
+
+    nl  = mnl_socket_open(NETLINK_NETFILTER);
+    if(!nl) {
+        error("nfacct.plugin: mnl_socket_open() failed");
+        goto cleanup;
+    }
+
+    if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+        error("nfacct.plugin: mnl_socket_bind() failed");
+        goto cleanup;
+    }
+    portid = mnl_socket_get_portid(nl);
+
+    // ------------------------------------------------------------------------
+
+    RRDSET *st_bytes = NULL, *st_packets = NULL;
+
+    // ------------------------------------------------------------------------
+
+    int update_every = (int)config_get_number("plugin:nfacct", "update every", localhost->rrd_update_every);
+    if(update_every < localhost->rrd_update_every)
+        update_every = localhost->rrd_update_every;
+
+    usec_t step = update_every * USEC_PER_SEC;
+    heartbeat_t hb;
+    heartbeat_init(&hb);
+    for(;;) {
+        heartbeat_dt_usec(&hb);
+        heartbeat_next(&hb, step);
+
+        if(unlikely(netdata_exit)) break;
+
+        seq++;
+
+        nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, (uint32_t)seq);
+        if(!nlh) {
+            error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
+            goto cleanup;
+        }
+
+        if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+            error("nfacct.plugin: mnl_socket_send");
+            goto cleanup;
+        }
+
+        if(nfacct_list) nfacct_list->len = 0;
+
+        ssize_t ret;
+        while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
+            if((ret = mnl_cb_run(buf, (size_t)ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
+        }
+
+        if (ret == -1) {
+            error("nfacct.plugin: error communicating with kernel. NFACCT plugin can only work when netdata runs as root.");
+            goto cleanup;
+        }
+
+        // --------------------------------------------------------------------
+
+        if(nfacct_list && nfacct_list->len) {
+            int i;
+
+            if(!st_packets) {
+                st_packets = rrdset_create_localhost(
+                        "netfilter"
+                        , "nfacct_packets"
+                        , NULL
+                        , "nfacct"
+                        , NULL
+                        , "Netfilter Accounting Packets"
+                        , "packets/s"
+                        , 3206
+                        , update_every
+                        , RRDSET_TYPE_STACKED
+                );
+            }
+            else rrdset_next(st_packets);
+
+            for(i = 0; i < nfacct_list->len ; i++) {
+                if(nfacct_list->data[i].updated) {
+                    if(unlikely(!nfacct_list->data[i].rd_packets))
+                        nfacct_list->data[i].rd_packets = rrddim_add(
+                                st_packets
+                                , nfacct_list->data[i].name
+                                , NULL
+                                , 1
+                                , update_every
+                                , RRD_ALGORITHM_INCREMENTAL
+                        );
+
+                    rrddim_set_by_pointer(
+                            st_packets
+                            , nfacct_list->data[i].rd_packets
+                            , (collected_number)nfacct_list->data[i].pkts
+                    );
+                }
+            }
+
+            rrdset_done(st_packets);
+
+            // ----------------------------------------------------------------
+
+            st_bytes = rrdset_find_bytype_localhost("netfilter", "nfacct_bytes");
+            if(!st_bytes) {
+                st_bytes = rrdset_create_localhost(
+                        "netfilter"
+                        , "nfacct_bytes"
+                        , NULL
+                        , "nfacct"
+                        , NULL
+                        , "Netfilter Accounting Bandwidth"
+                        , "kilobytes/s"
+                        , 3207
+                        , update_every
+                        , RRDSET_TYPE_STACKED
+                );
+            }
+            else rrdset_next(st_bytes);
+
+            for(i = 0; i < nfacct_list->len ; i++) {
+                if(nfacct_list->data[i].updated) {
+                    if(unlikely(!nfacct_list->data[i].rd_bytes))
+                        nfacct_list->data[i].rd_bytes = rrddim_add(
+                                st_bytes
+                                , nfacct_list->data[i].name
+                                , NULL
+                                , 1
+                                , 1000 * update_every
+                                , RRD_ALGORITHM_INCREMENTAL
+                        );
+
+                    rrddim_set_by_pointer(
+                            st_bytes
+                            , nfacct_list->data[i].rd_bytes
+                            , (collected_number)nfacct_list->data[i].bytes
+                    );
+                }
+            }
+
+            rrdset_done(st_bytes);
+
+
+            // ----------------------------------------------------------------
+            // prepare for the next loop
+
+            for(i = 0; i < nfacct_list->len ; i++)
+                nfacct_list->data[i].updated = 0;
+        }
+    }
+
+cleanup:
+    info("NFACCT thread exiting");
+
+    if(nl) mnl_socket_close(nl);
+
+    static_thread->enabled = 0;
+    pthread_exit(NULL);
+    return NULL;
 }
 #endif