3 #ifdef INTERNAL_PLUGIN_NFACCT
4 #include <libmnl/libmnl.h>
5 #include <libnetfilter_acct/libnetfilter_acct.h>
19 struct nfacct_data *next;
22 static struct nfacct_list {
23 struct nfacct *nfacct_buffer;
24 struct nfacct_data *nfacct_metrics;
26 .nfacct_buffer = NULL,
27 .nfacct_metrics = NULL
30 static inline struct nfacct_data *nfacct_data_get(const char *name, uint32_t hash) {
31 struct nfacct_data *d = NULL, *last = NULL;
32 for(d = nfacct_root.nfacct_metrics; d ; last = d, d = d->next) {
33 if(unlikely(d->hash == hash && !strcmp(d->name, name)))
37 d = callocz(1, sizeof(struct nfacct_data));
38 d->name = strdupz(name);
42 d->next = nfacct_root.nfacct_metrics;
43 nfacct_root.nfacct_metrics = d;
53 static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
56 if(nfacct_nlmsg_parse_payload(nlh, nfacct_root.nfacct_buffer) < 0) {
57 error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
61 const char *name = nfacct_attr_get_str(nfacct_root.nfacct_buffer, NFACCT_ATTR_NAME);
62 uint32_t hash = simple_hash(name);
64 struct nfacct_data *d = nfacct_data_get(name, hash);
66 d->pkts = nfacct_attr_get_u64(nfacct_root.nfacct_buffer, NFACCT_ATTR_PKTS);
67 d->bytes = nfacct_attr_get_u64(nfacct_root.nfacct_buffer, NFACCT_ATTR_BYTES);
73 void *nfacct_main(void *ptr) {
74 struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
76 info("NFACCT thread created with task id %d", gettid());
78 if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
79 error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
81 if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
82 error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
84 nfacct_root.nfacct_buffer = nfacct_alloc();
85 if(!nfacct_root.nfacct_buffer)
86 fatal("nfacct.plugin: nfacct_alloc() failed.");
88 char buf[MNL_SOCKET_BUFFER_SIZE];
89 struct mnl_socket *nl = NULL;
90 struct nlmsghdr *nlh = NULL;
91 unsigned int seq = 0, portid = 0;
93 seq = (unsigned int)now_realtime_sec() - 1;
95 nl = mnl_socket_open(NETLINK_NETFILTER);
97 error("nfacct.plugin: mnl_socket_open() failed");
101 if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
102 error("nfacct.plugin: mnl_socket_bind() failed");
105 portid = mnl_socket_get_portid(nl);
107 // ------------------------------------------------------------------------
109 RRDSET *st_bytes = NULL, *st_packets = NULL;
111 // ------------------------------------------------------------------------
113 int update_every = (int)config_get_number("plugin:nfacct", "update every", localhost->rrd_update_every);
114 if(update_every < localhost->rrd_update_every)
115 update_every = localhost->rrd_update_every;
117 usec_t step = update_every * USEC_PER_SEC;
121 heartbeat_dt_usec(&hb);
122 heartbeat_next(&hb, step);
124 if(unlikely(netdata_exit)) break;
128 nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, (uint32_t)seq);
130 error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
134 if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
135 error("nfacct.plugin: mnl_socket_send");
140 while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
141 if((ret = mnl_cb_run(buf, (size_t)ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
145 error("nfacct.plugin: error communicating with kernel. NFACCT plugin can only work when netdata runs as root.");
149 // --------------------------------------------------------------------
151 if(nfacct_root.nfacct_metrics) {
152 struct nfacct_data *d;
155 st_packets = rrdset_create_localhost(
161 , "Netfilter Accounting Packets"
165 , RRDSET_TYPE_STACKED
168 else rrdset_next(st_packets);
170 for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
171 if(likely(d->updated)) {
172 if(unlikely(!d->rd_packets))
173 d->rd_packets = rrddim_add(
179 , RRD_ALGORITHM_INCREMENTAL
182 rrddim_set_by_pointer(
185 , (collected_number)d->pkts
190 rrdset_done(st_packets);
192 // ----------------------------------------------------------------
194 st_bytes = rrdset_find_bytype_localhost("netfilter", "nfacct_bytes");
196 st_bytes = rrdset_create_localhost(
202 , "Netfilter Accounting Bandwidth"
206 , RRDSET_TYPE_STACKED
209 else rrdset_next(st_bytes);
211 for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
212 if(likely(d->updated)) {
213 if(unlikely(!d->rd_bytes))
214 d->rd_bytes = rrddim_add(
219 , 1000 * update_every
220 , RRD_ALGORITHM_INCREMENTAL
223 rrddim_set_by_pointer(
226 , (collected_number)d->bytes
231 rrdset_done(st_bytes);
234 // ----------------------------------------------------------------
235 // prepare for the next loop
237 for(d = nfacct_root.nfacct_metrics; d ; d = d->next)
243 info("NFACCT thread exiting");
245 if(nl) mnl_socket_close(nl);
247 static_thread->enabled = 0;