4 #ifdef INTERNAL_PLUGIN_NFACCT
16 #include <libmnl/libmnl.h>
17 #include <libnetfilter_acct/libnetfilter_acct.h>
20 #include "global_statistics.h"
22 #include "appconfig.h"
25 #include "plugin_proc.h"
31 struct nfacct *nfacct;
37 struct mynfacct data[];
38 } *nfacct_list = NULL;
40 static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
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;
48 info("nfacct.plugin: increasing nfacct_list to size %d", size);
50 nfacct_list = realloc(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
52 error("nfacct.plugin: cannot allocate nfacct_list.");
56 nfacct_list->data[len].nfacct = nfacct_alloc();
57 if(!nfacct_list->data[size - 1].nfacct) {
58 error("nfacct.plugin: nfacct_alloc() failed.");
64 nfacct_list->size = size;
65 nfacct_list->len = len;
68 if(nfacct_nlmsg_parse_payload(nlh, nfacct_list->data[nfacct_list->len].nfacct) < 0) {
69 error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
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);
81 void *nfacct_main(void *ptr) {
84 info("NFACCT thread created with task id %d", gettid());
86 if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
87 error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
89 if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
90 error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
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;
99 nl = mnl_socket_open(NETLINK_NETFILTER);
101 error("nfacct.plugin: mnl_socket_open() failed");
106 if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
107 mnl_socket_close(nl);
108 error("nfacct.plugin: mnl_socket_bind() failed");
112 portid = mnl_socket_get_portid(nl);
114 // ------------------------------------------------------------------------
116 struct timeval last, now;
117 unsigned long long usec = 0, susec = 0;
120 gettimeofday(&last, NULL);
122 // ------------------------------------------------------------------------
125 if(unlikely(netdata_exit)) break;
129 nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, seq);
131 mnl_socket_close(nl);
132 error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
137 if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
138 error("nfacct.plugin: mnl_socket_send");
143 if(nfacct_list) nfacct_list->len = 0;
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;
151 error("nfacct.plugin: error communicating with kernel.");
156 // --------------------------------------------------------------------
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);
162 if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
163 else susec = rrd_update_every * 1000000ULL / 2ULL;
166 // --------------------------------------------------------------------
168 if(nfacct_list && nfacct_list->len) {
171 st = rrdset_find_bytype("netfilter", "nfacct_packets");
173 st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 1006, rrd_update_every, RRDSET_TYPE_STACKED);
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);
178 else rrdset_next(st);
180 for(i = 0; i < nfacct_list->len ; i++) {
181 RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
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);
189 // ----------------------------------------------------------------
191 st = rrdset_find_bytype("netfilter", "nfacct_bytes");
193 st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);
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);
198 else rrdset_next(st);
200 for(i = 0; i < nfacct_list->len ; i++) {
201 RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
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);
210 // --------------------------------------------------------------------
214 // copy current to last
215 bcopy(&now, &last, sizeof(struct timeval));
218 mnl_socket_close(nl);