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