]> 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