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