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.");
57 if(unlikely(!nfacct_list))
61 if(nfacct_nlmsg_parse_payload(nlh, nfacct) < 0) {
62 error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
66 const char *name = nfacct_attr_get_str(nfacct, NFACCT_ATTR_NAME);
67 uint32_t hash = simple_hash(name);
70 struct mynfacct *mynfacct = NULL;
71 for(i = 0; i < nfacct_list->len; i++) {
72 if(nfacct_list->data[i].hash == hash && !strcmp(nfacct_list->data[i].name, name)) {
73 mynfacct = &nfacct_list->data[i];
80 mynfacct = &nfacct_list->data[nfacct_list->len++];
81 mynfacct->name = name;
82 mynfacct->hash = hash;
85 mynfacct->pkts = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS);
86 mynfacct->bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
87 mynfacct->updated = 1;
93 void *nfacct_main(void *ptr) {
94 struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
96 info("NFACCT thread created with task id %d", gettid());
98 if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
99 error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
101 if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
102 error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
104 char buf[MNL_SOCKET_BUFFER_SIZE];
105 struct mnl_socket *nl = NULL;
106 struct nlmsghdr *nlh = NULL;
107 unsigned int seq = 0, portid = 0;
109 seq = (unsigned int)now_realtime_sec() - 1;
111 nl = mnl_socket_open(NETLINK_NETFILTER);
113 error("nfacct.plugin: mnl_socket_open() failed");
117 if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
118 error("nfacct.plugin: mnl_socket_bind() failed");
121 portid = mnl_socket_get_portid(nl);
123 // ------------------------------------------------------------------------
125 RRDSET *st_bytes = NULL, *st_packets = NULL;
127 // ------------------------------------------------------------------------
129 int update_every = (int)config_get_number("plugin:nfacct", "update every", localhost->rrd_update_every);
130 if(update_every < localhost->rrd_update_every)
131 update_every = localhost->rrd_update_every;
133 usec_t step = update_every * USEC_PER_SEC;
137 heartbeat_dt_usec(&hb);
138 heartbeat_next(&hb, step);
140 if(unlikely(netdata_exit)) break;
144 nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, (uint32_t)seq);
146 error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
150 if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
151 error("nfacct.plugin: mnl_socket_send");
156 while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
157 if((ret = mnl_cb_run(buf, (size_t)ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
161 error("nfacct.plugin: error communicating with kernel. NFACCT plugin can only work when netdata runs as root.");
165 // --------------------------------------------------------------------
167 if(nfacct_list && nfacct_list->len) {
171 st_packets = rrdset_create_localhost(
177 , "Netfilter Accounting Packets"
181 , RRDSET_TYPE_STACKED
184 else rrdset_next(st_packets);
186 for(i = 0; i < nfacct_list->len ; i++) {
187 if(nfacct_list->data[i].updated) {
188 if(unlikely(!nfacct_list->data[i].rd_packets))
189 nfacct_list->data[i].rd_packets = rrddim_add(
191 , nfacct_list->data[i].name
195 , RRD_ALGORITHM_INCREMENTAL
198 rrddim_set_by_pointer(
200 , nfacct_list->data[i].rd_packets
201 , (collected_number)nfacct_list->data[i].pkts
206 rrdset_done(st_packets);
208 // ----------------------------------------------------------------
210 st_bytes = rrdset_find_bytype_localhost("netfilter", "nfacct_bytes");
212 st_bytes = rrdset_create_localhost(
218 , "Netfilter Accounting Bandwidth"
222 , RRDSET_TYPE_STACKED
225 else rrdset_next(st_bytes);
227 for(i = 0; i < nfacct_list->len ; i++) {
228 if(nfacct_list->data[i].updated) {
229 if(unlikely(!nfacct_list->data[i].rd_bytes))
230 nfacct_list->data[i].rd_bytes = rrddim_add(
232 , nfacct_list->data[i].name
235 , 1000 * update_every
236 , RRD_ALGORITHM_INCREMENTAL
239 rrddim_set_by_pointer(
241 , nfacct_list->data[i].rd_bytes
242 , (collected_number)nfacct_list->data[i].bytes
247 rrdset_done(st_bytes);
250 // ----------------------------------------------------------------
251 // prepare for the next loop
253 for(i = 0; i < nfacct_list->len ; i++)
254 nfacct_list->data[i].updated = 0;
259 info("NFACCT thread exiting");
261 if(nl) mnl_socket_close(nl);
263 static_thread->enabled = 0;