]> arthur.barton.de Git - netdata.git/blob - src/plugin_nfacct.c
Merge pull request #1952 from ktsaou/master
[netdata.git] / src / plugin_nfacct.c
1 #include "common.h"
2
3 #ifdef INTERNAL_PLUGIN_NFACCT
4 #include <libmnl/libmnl.h>
5 #include <libnetfilter_acct/libnetfilter_acct.h>
6
7 struct mynfacct {
8     const char *name;
9     uint64_t pkts;
10     uint64_t bytes;
11     struct nfacct *nfacct;
12 };
13
14 struct nfacct_list {
15     int size;
16     int len;
17     struct mynfacct data[];
18 } *nfacct_list = NULL;
19
20 static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
21     if(data) {};
22
23     if(!nfacct_list || nfacct_list->len == nfacct_list->size) {
24         int size = (nfacct_list) ? nfacct_list->size : 0;
25         int len = (nfacct_list) ? nfacct_list->len : 0;
26         size++;
27
28         info("nfacct.plugin: increasing nfacct_list to size %d", size);
29
30         nfacct_list = reallocz(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
31
32         nfacct_list->data[len].nfacct = nfacct_alloc();
33         if(!nfacct_list->data[size - 1].nfacct) {
34             error("nfacct.plugin: nfacct_alloc() failed.");
35             free(nfacct_list);
36             nfacct_list = NULL;
37             return MNL_CB_OK;
38         }
39
40         nfacct_list->size = size;
41         nfacct_list->len = len;
42     }
43
44     if(nfacct_nlmsg_parse_payload(nlh, nfacct_list->data[nfacct_list->len].nfacct) < 0) {
45         error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
46         return MNL_CB_OK;
47     }
48
49     nfacct_list->data[nfacct_list->len].name  = nfacct_attr_get_str(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_NAME);
50     nfacct_list->data[nfacct_list->len].pkts  = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_PKTS);
51     nfacct_list->data[nfacct_list->len].bytes = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_BYTES);
52
53     nfacct_list->len++;
54     return MNL_CB_OK;
55 }
56
57 void *nfacct_main(void *ptr) {
58     struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
59
60     info("NFACCT thread created with task id %d", gettid());
61
62     if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
63         error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
64
65     if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
66         error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
67
68     char buf[MNL_SOCKET_BUFFER_SIZE];
69     struct mnl_socket *nl = NULL;
70     struct nlmsghdr *nlh = NULL;
71     unsigned int seq = 0, portid = 0;
72
73     seq = now_realtime_sec() - 1;
74
75     nl  = mnl_socket_open(NETLINK_NETFILTER);
76     if(!nl) {
77         error("nfacct.plugin: mnl_socket_open() failed");
78         goto cleanup;
79     }
80
81     if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
82         error("nfacct.plugin: mnl_socket_bind() failed");
83         goto cleanup;
84     }
85     portid = mnl_socket_get_portid(nl);
86
87     // ------------------------------------------------------------------------
88
89     struct timeval last, now;
90     usec_t usec = 0, susec = 0;
91     RRDSET *st = NULL;
92
93     now_realtime_timeval(&last);
94
95     // ------------------------------------------------------------------------
96
97     while(1) {
98         if(unlikely(netdata_exit)) break;
99
100         seq++;
101
102         nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, seq);
103         if(!nlh) {
104             error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
105             goto cleanup;
106         }
107
108         if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
109             error("nfacct.plugin: mnl_socket_send");
110             goto cleanup;
111         }
112
113         if(nfacct_list) nfacct_list->len = 0;
114
115         int ret;
116         while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
117             if((ret = mnl_cb_run(buf, ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
118         }
119
120         if (ret == -1) {
121             error("nfacct.plugin: error communicating with kernel.");
122             goto cleanup;
123         }
124
125         // --------------------------------------------------------------------
126
127         now_realtime_timeval(&now);
128         usec = dt_usec(&now, &last) - susec;
129         debug(D_NFACCT_LOOP, "nfacct.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).", usec + susec, usec, susec);
130
131         if(usec < (default_rrd_update_every * 1000000ULL / 2ULL)) susec = (default_rrd_update_every * 1000000ULL) - usec;
132         else susec = default_rrd_update_every * 1000000ULL / 2ULL;
133
134
135         // --------------------------------------------------------------------
136
137         if(nfacct_list && nfacct_list->len) {
138             int i;
139
140             st = rrdset_find_bytype("netfilter", "nfacct_packets");
141             if(!st) {
142                 st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 3206, default_rrd_update_every, RRDSET_TYPE_STACKED);
143
144                 for(i = 0; i < nfacct_list->len ; i++)
145                     rrddim_add(st, nfacct_list->data[i].name, NULL, 1, default_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
146             }
147             else rrdset_next(st);
148
149             for(i = 0; i < nfacct_list->len ; i++) {
150                 RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
151
152                 if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, default_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
153                 if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].pkts);
154             }
155
156             rrdset_done(st);
157
158             // ----------------------------------------------------------------
159
160             st = rrdset_find_bytype("netfilter", "nfacct_bytes");
161             if(!st) {
162                 st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 3207, default_rrd_update_every, RRDSET_TYPE_STACKED);
163
164                 for(i = 0; i < nfacct_list->len ; i++)
165                     rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * default_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
166             }
167             else rrdset_next(st);
168
169             for(i = 0; i < nfacct_list->len ; i++) {
170                 RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
171
172                 if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * default_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
173                 if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].bytes);
174             }
175
176             rrdset_done(st);
177         }
178
179         // --------------------------------------------------------------------
180
181         usleep(susec);
182
183         // copy current to last
184         memmove(&last, &now, sizeof(struct timeval));
185     }
186
187 cleanup:
188     info("NFACCT thread exiting");
189
190     if(nl) mnl_socket_close(nl);
191
192     static_thread->enabled = 0;
193     pthread_exit(NULL);
194     return NULL;
195 }
196 #endif