3 #ifdef INTERNAL_PLUGIN_NFACCT
4 #include <libmnl/libmnl.h>
5 #include <libnetfilter_acct/libnetfilter_acct.h>
23 struct mynfacct data[];
24 } *nfacct_list = NULL;
26 static inline void nfacct_list_grow() {
27 if(!nfacct_list || nfacct_list->len == nfacct_list->size) {
28 int size = (nfacct_list) ? nfacct_list->size : 0;
29 int len = (nfacct_list) ? nfacct_list->len : 0;
32 info("nfacct.plugin: increasing nfacct_list to size %d", size);
34 nfacct_list = reallocz(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
36 nfacct_list->data[len].rd_bytes = NULL;
37 nfacct_list->data[len].rd_packets = NULL;
38 nfacct_list->data[len].updated = 0;
40 nfacct_list->size = size;
41 nfacct_list->len = len;
45 static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
48 static struct nfacct *nfacct = NULL;
50 if(unlikely(!nfacct)) {
51 nfacct = nfacct_alloc();
53 error("nfacct.plugin: nfacct_alloc() failed.");
58 if(nfacct_nlmsg_parse_payload(nlh, nfacct) < 0) {
59 error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
63 const char *name = nfacct_attr_get_str(nfacct, NFACCT_ATTR_NAME);
64 uint32_t hash = simple_hash(name);
67 struct mynfacct *mynfacct = NULL;
68 for(i = 0; i < nfacct_list->len; i++) {
69 if(nfacct_list->data[i].hash == hash && !strcmp(nfacct_list->data[i].name, name)) {
70 mynfacct = &nfacct_list->data[i];
77 mynfacct = &nfacct_list->data[nfacct_list->len++];
78 mynfacct->name = name;
79 mynfacct->hash = hash;
82 mynfacct->pkts = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS);
83 mynfacct->bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
84 mynfacct->updated = 1;
90 void *nfacct_main(void *ptr) {
91 struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
93 info("NFACCT thread created with task id %d", gettid());
95 if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
96 error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
98 if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
99 error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
101 char buf[MNL_SOCKET_BUFFER_SIZE];
102 struct mnl_socket *nl = NULL;
103 struct nlmsghdr *nlh = NULL;
104 unsigned int seq = 0, portid = 0;
106 seq = (unsigned int)now_realtime_sec() - 1;
108 nl = mnl_socket_open(NETLINK_NETFILTER);
110 error("nfacct.plugin: mnl_socket_open() failed");
114 if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
115 error("nfacct.plugin: mnl_socket_bind() failed");
118 portid = mnl_socket_get_portid(nl);
120 // ------------------------------------------------------------------------
122 RRDSET *st_bytes = NULL, *st_packets = NULL;
124 // ------------------------------------------------------------------------
126 int update_every = (int)config_get_number("plugin:nfacct", "update every", localhost->rrd_update_every);
127 if(update_every < localhost->rrd_update_every)
128 update_every = localhost->rrd_update_every;
130 usec_t step = update_every * USEC_PER_SEC;
134 heartbeat_dt_usec(&hb);
135 heartbeat_next(&hb, step);
137 if(unlikely(netdata_exit)) break;
141 nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, (uint32_t)seq);
143 error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
147 if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
148 error("nfacct.plugin: mnl_socket_send");
153 while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
154 if((ret = mnl_cb_run(buf, (size_t)ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
158 error("nfacct.plugin: error communicating with kernel. NFACCT plugin can only work when netdata runs as root.");
162 // --------------------------------------------------------------------
164 if(nfacct_list && nfacct_list->len) {
168 st_packets = rrdset_create_localhost(
174 , "Netfilter Accounting Packets"
178 , RRDSET_TYPE_STACKED
181 else rrdset_next(st_packets);
183 for(i = 0; i < nfacct_list->len ; i++) {
184 if(nfacct_list->data[i].updated) {
185 if(unlikely(!nfacct_list->data[i].rd_packets))
186 nfacct_list->data[i].rd_packets = rrddim_add(
188 , nfacct_list->data[i].name
192 , RRD_ALGORITHM_INCREMENTAL
195 rrddim_set_by_pointer(
197 , nfacct_list->data[i].rd_packets
198 , (collected_number)nfacct_list->data[i].pkts
203 rrdset_done(st_packets);
205 // ----------------------------------------------------------------
207 st_bytes = rrdset_find_bytype_localhost("netfilter", "nfacct_bytes");
209 st_bytes = rrdset_create_localhost(
215 , "Netfilter Accounting Bandwidth"
219 , RRDSET_TYPE_STACKED
222 else rrdset_next(st_bytes);
224 for(i = 0; i < nfacct_list->len ; i++) {
225 if(nfacct_list->data[i].updated) {
226 if(unlikely(!nfacct_list->data[i].rd_bytes))
227 nfacct_list->data[i].rd_bytes = rrddim_add(
229 , nfacct_list->data[i].name
232 , 1000 * update_every
233 , RRD_ALGORITHM_INCREMENTAL
236 rrddim_set_by_pointer(
238 , nfacct_list->data[i].rd_bytes
239 , (collected_number)nfacct_list->data[i].bytes
244 rrdset_done(st_bytes);
247 // ----------------------------------------------------------------
248 // prepare for the next loop
250 for(i = 0; i < nfacct_list->len ; i++)
251 nfacct_list->data[i].updated = 0;
256 info("NFACCT thread exiting");
258 if(nl) mnl_socket_close(nl);
260 static_thread->enabled = 0;