]> arthur.barton.de Git - netdata.git/blob - src/plugin_nfacct.c
45a65b4347beeb3cd38270ab701e6680835de0c6
[netdata.git] / src / plugin_nfacct.c
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4 #ifdef INTERNAL_PLUGIN_NFACCT
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/types.h>
9 #include <dirent.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <time.h>
14 #include <errno.h>
15
16 #include <libmnl/libmnl.h>
17 #include <libnetfilter_acct/libnetfilter_acct.h>
18
19 #include "main.h"
20 #include "global_statistics.h"
21 #include "common.h"
22 #include "appconfig.h"
23 #include "log.h"
24 #include "rrd.h"
25 #include "plugin_proc.h"
26
27 struct mynfacct {
28         const char *name;
29         uint64_t pkts;
30         uint64_t bytes;
31         struct nfacct *nfacct;
32 };
33
34 struct nfacct_list {
35         int size;
36         int len;
37         struct mynfacct data[];
38 } *nfacct_list = NULL;
39
40 static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
41         if(data) {};
42
43         if(!nfacct_list || nfacct_list->len == nfacct_list->size) {
44                 int size = (nfacct_list) ? nfacct_list->size : 0;
45                 int len = (nfacct_list) ? nfacct_list->len : 0;
46                 size++;
47
48                 info("nfacct.plugin: increasing nfacct_list to size %d", size);
49
50                 nfacct_list = realloc(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
51                 if(!nfacct_list) {
52                         error("nfacct.plugin: cannot allocate nfacct_list.");
53                         return MNL_CB_OK;
54                 }
55
56                 nfacct_list->data[len].nfacct = nfacct_alloc();
57                 if(!nfacct_list->data[size - 1].nfacct) {
58                         error("nfacct.plugin: nfacct_alloc() failed.");
59                         free(nfacct_list);
60                         nfacct_list = NULL;
61                         return MNL_CB_OK;
62                 }
63
64                 nfacct_list->size = size;
65                 nfacct_list->len = len;
66         }
67
68         if(nfacct_nlmsg_parse_payload(nlh, nfacct_list->data[nfacct_list->len].nfacct) < 0) {
69                 error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
70                 return MNL_CB_OK;
71         }
72
73         nfacct_list->data[nfacct_list->len].name  = nfacct_attr_get_str(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_NAME);
74         nfacct_list->data[nfacct_list->len].pkts  = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_PKTS);
75         nfacct_list->data[nfacct_list->len].bytes = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_BYTES);
76
77         nfacct_list->len++;
78         return MNL_CB_OK;
79 }
80
81 void *nfacct_main(void *ptr) {
82         if(ptr) { ; }
83
84         info("NFACCT thread created with task id %d", gettid());
85
86         if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
87                 error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
88
89         if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
90                 error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
91
92         char buf[MNL_SOCKET_BUFFER_SIZE];
93         struct mnl_socket *nl = NULL;
94         struct nlmsghdr *nlh = NULL;
95         unsigned int seq = 0, portid = 0;
96
97         seq = time(NULL) - 1;
98
99         nl  = mnl_socket_open(NETLINK_NETFILTER);
100         if(!nl) {
101                 error("nfacct.plugin: mnl_socket_open() failed");
102                 pthread_exit(NULL);
103                 return NULL;
104         }
105
106         if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
107                 mnl_socket_close(nl);
108                 error("nfacct.plugin: mnl_socket_bind() failed");
109                 pthread_exit(NULL);
110                 return NULL;
111         }
112         portid = mnl_socket_get_portid(nl);
113
114         // ------------------------------------------------------------------------
115
116         struct timeval last, now;
117         unsigned long long usec = 0, susec = 0;
118         RRDSET *st = NULL;
119
120         gettimeofday(&last, NULL);
121
122         // ------------------------------------------------------------------------
123
124         while(1) {
125                 if(unlikely(netdata_exit)) break;
126
127                 seq++;
128
129                 nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, seq);
130                 if(!nlh) {
131                         mnl_socket_close(nl);
132                         error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
133                         pthread_exit(NULL);
134                         return NULL;
135                 }
136
137                 if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
138                         error("nfacct.plugin: mnl_socket_send");
139                         pthread_exit(NULL);
140                         return NULL;
141                 }
142
143                 if(nfacct_list) nfacct_list->len = 0;
144
145                 int ret;
146                 while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
147                         if((ret = mnl_cb_run(buf, ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
148                 }
149
150                 if (ret == -1) {
151                         error("nfacct.plugin: error communicating with kernel.");
152                         pthread_exit(NULL);
153                         return NULL;
154                 }
155
156                 // --------------------------------------------------------------------
157
158                 gettimeofday(&now, NULL);
159                 usec = usecdiff(&now, &last) - susec;
160                 debug(D_NFACCT_LOOP, "nfacct.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).", usec + susec, usec, susec);
161
162                 if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
163                 else susec = rrd_update_every * 1000000ULL / 2ULL;
164
165
166                 // --------------------------------------------------------------------
167
168                 if(nfacct_list && nfacct_list->len) {
169                         int i;
170
171                         st = rrdset_find_bytype("nfacct", "packets");
172                         if(!st) {
173                                 st = rrdset_create("nfacct", "packets", NULL, "netfilter", NULL, "Netfilter Accounting Packets", "packets/s", 1006, 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, 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, rrd_update_every, RRDDIM_INCREMENTAL);
184                                 if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].pkts);
185                         }
186
187                         rrdset_done(st);
188
189                         // ----------------------------------------------------------------
190
191                         st = rrdset_find_bytype("nfacct", "bytes");
192                         if(!st) {
193                                 st = rrdset_create("nfacct", "bytes", NULL, "netfilter", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);
194
195                                 for(i = 0; i < nfacct_list->len ; i++)
196                                         rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
197                         }
198                         else rrdset_next(st);
199
200                         for(i = 0; i < nfacct_list->len ; i++) {
201                                 RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
202
203                                 if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
204                                 if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].bytes);
205                         }
206
207                         rrdset_done(st);
208                 }
209
210                 // --------------------------------------------------------------------
211
212                 usleep(susec);
213
214                 // copy current to last
215                 bcopy(&now, &last, sizeof(struct timeval));
216         }
217
218         mnl_socket_close(nl);
219         pthread_exit(NULL);
220         return NULL;
221 }
222 #endif