123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885 |
- // SPDX-License-Identifier: GPL-3.0-or-later
- #include "libnetdata/libnetdata.h"
- #include "libnetdata/required_dummies.h"
- #include <linux/netfilter/nfnetlink_conntrack.h>
- #include <libmnl/libmnl.h>
- #include <libnetfilter_acct/libnetfilter_acct.h>
- #define PLUGIN_NFACCT_NAME "nfacct.plugin"
- #define NETDATA_CHART_PRIO_NETFILTER_NEW 8701
- #define NETDATA_CHART_PRIO_NETFILTER_CHANGES 8702
- #define NETDATA_CHART_PRIO_NETFILTER_EXPECT 8703
- #define NETDATA_CHART_PRIO_NETFILTER_ERRORS 8705
- #define NETDATA_CHART_PRIO_NETFILTER_SEARCH 8710
- #define NETDATA_CHART_PRIO_NETFILTER_PACKETS 8906
- #define NETDATA_CHART_PRIO_NETFILTER_BYTES 8907
- static inline size_t mnl_buffer_size() {
- long s = MNL_SOCKET_BUFFER_SIZE;
- if(s <= 0) return 8192;
- return (size_t)s;
- }
- // variables
- static int debug = 0;
- static int netdata_update_every = 1;
- #define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
- #define RRD_TYPE_NET_STAT_CONNTRACK "netlink"
- static struct {
- int update_every;
- char *buf;
- size_t buf_size;
- struct mnl_socket *mnl;
- struct nlmsghdr *nlh;
- struct nfgenmsg *nfh;
- unsigned int seq;
- uint32_t portid;
- struct nlattr *tb[CTA_STATS_MAX+1];
- const char *attr2name[CTA_STATS_MAX+1];
- kernel_uint_t metrics[CTA_STATS_MAX+1];
- struct nlattr *tb_exp[CTA_STATS_EXP_MAX+1];
- const char *attr2name_exp[CTA_STATS_EXP_MAX+1];
- kernel_uint_t metrics_exp[CTA_STATS_EXP_MAX+1];
- } nfstat_root = {
- .update_every = 1,
- .buf = NULL,
- .buf_size = 0,
- .mnl = NULL,
- .nlh = NULL,
- .nfh = NULL,
- .seq = 0,
- .portid = 0,
- .tb = {},
- .attr2name = {
- [CTA_STATS_SEARCHED] = "searched",
- [CTA_STATS_FOUND] = "found",
- [CTA_STATS_NEW] = "new",
- [CTA_STATS_INVALID] = "invalid",
- [CTA_STATS_IGNORE] = "ignore",
- [CTA_STATS_DELETE] = "delete",
- [CTA_STATS_DELETE_LIST] = "delete_list",
- [CTA_STATS_INSERT] = "insert",
- [CTA_STATS_INSERT_FAILED] = "insert_failed",
- [CTA_STATS_DROP] = "drop",
- [CTA_STATS_EARLY_DROP] = "early_drop",
- [CTA_STATS_ERROR] = "icmp_error",
- [CTA_STATS_SEARCH_RESTART] = "search_restart",
- },
- .metrics = {},
- .tb_exp = {},
- .attr2name_exp = {
- [CTA_STATS_EXP_NEW] = "new",
- [CTA_STATS_EXP_CREATE] = "created",
- [CTA_STATS_EXP_DELETE] = "deleted",
- },
- .metrics_exp = {}
- };
- static int nfstat_init(int update_every) {
- nfstat_root.update_every = update_every;
- nfstat_root.buf_size = mnl_buffer_size();
- nfstat_root.buf = mallocz(nfstat_root.buf_size);
- nfstat_root.mnl = mnl_socket_open(NETLINK_NETFILTER);
- if(!nfstat_root.mnl) {
- error("NFSTAT: mnl_socket_open() failed");
- return 1;
- }
- nfstat_root.seq = (unsigned int)now_realtime_sec() - 1;
- if(mnl_socket_bind(nfstat_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
- error("NFSTAT: mnl_socket_bind() failed");
- return 1;
- }
- nfstat_root.portid = mnl_socket_get_portid(nfstat_root.mnl);
- return 0;
- }
- static struct nlmsghdr * nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type, uint8_t family, uint32_t seq) {
- struct nlmsghdr *nlh;
- struct nfgenmsg *nfh;
- nlh = mnl_nlmsg_put_header(buf);
- nlh->nlmsg_type = (subsys << 8) | type;
- nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
- nlh->nlmsg_seq = seq;
- nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
- nfh->nfgen_family = family;
- nfh->version = NFNETLINK_V0;
- nfh->res_id = 0;
- return nlh;
- }
- static int nfct_stats_attr_cb(const struct nlattr *attr, void *data) {
- const struct nlattr **tb = data;
- int type = mnl_attr_get_type(attr);
- if (mnl_attr_type_valid(attr, CTA_STATS_MAX) < 0)
- return MNL_CB_OK;
- if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
- error("NFSTAT: mnl_attr_validate() failed");
- return MNL_CB_ERROR;
- }
- tb[type] = attr;
- return MNL_CB_OK;
- }
- static int nfstat_callback(const struct nlmsghdr *nlh, void *data) {
- (void)data;
- struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
- mnl_attr_parse(nlh, sizeof(*nfg), nfct_stats_attr_cb, nfstat_root.tb);
- // printf("cpu=%-4u\t", ntohs(nfg->res_id));
- int i;
- // add the metrics of this CPU into the metrics
- for (i = 0; i < CTA_STATS_MAX+1; i++) {
- if (nfstat_root.tb[i]) {
- // printf("%s=%u ", nfstat_root.attr2name[i], ntohl(mnl_attr_get_u32(nfstat_root.tb[i])));
- nfstat_root.metrics[i] += ntohl(mnl_attr_get_u32(nfstat_root.tb[i]));
- }
- }
- // printf("\n");
- return MNL_CB_OK;
- }
- static int nfstat_collect_conntrack() {
- // zero all metrics - we will sum the metrics of all CPUs later
- int i;
- for (i = 0; i < CTA_STATS_MAX+1; i++)
- nfstat_root.metrics[i] = 0;
- // prepare the request
- nfstat_root.nlh = nfct_mnl_nlmsghdr_put(nfstat_root.buf, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_STATS_CPU, AF_UNSPEC, nfstat_root.seq);
- // send the request
- if(mnl_socket_sendto(nfstat_root.mnl, nfstat_root.nlh, nfstat_root.nlh->nlmsg_len) < 0) {
- error("NFSTAT: mnl_socket_sendto() failed");
- return 1;
- }
- // get the reply
- ssize_t ret;
- while ((ret = mnl_socket_recvfrom(nfstat_root.mnl, nfstat_root.buf, nfstat_root.buf_size)) > 0) {
- if(mnl_cb_run(
- nfstat_root.buf
- , (size_t)ret
- , nfstat_root.nlh->nlmsg_seq
- , nfstat_root.portid
- , nfstat_callback
- , NULL
- ) <= MNL_CB_STOP)
- break;
- }
- // verify we run without issues
- if (ret == -1) {
- error("NFSTAT: error communicating with kernel. This plugin can only work when netdata runs as root.");
- return 1;
- }
- return 0;
- }
- static int nfexp_stats_attr_cb(const struct nlattr *attr, void *data)
- {
- const struct nlattr **tb = data;
- int type = mnl_attr_get_type(attr);
- if (mnl_attr_type_valid(attr, CTA_STATS_EXP_MAX) < 0)
- return MNL_CB_OK;
- if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
- error("NFSTAT EXP: mnl_attr_validate() failed");
- return MNL_CB_ERROR;
- }
- tb[type] = attr;
- return MNL_CB_OK;
- }
- static int nfstat_callback_exp(const struct nlmsghdr *nlh, void *data) {
- (void)data;
- struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
- mnl_attr_parse(nlh, sizeof(*nfg), nfexp_stats_attr_cb, nfstat_root.tb_exp);
- int i;
- for (i = 0; i < CTA_STATS_EXP_MAX+1; i++) {
- if (nfstat_root.tb_exp[i]) {
- nfstat_root.metrics_exp[i] += ntohl(mnl_attr_get_u32(nfstat_root.tb_exp[i]));
- }
- }
- return MNL_CB_OK;
- }
- static int nfstat_collect_conntrack_expectations() {
- // zero all metrics - we will sum the metrics of all CPUs later
- int i;
- for (i = 0; i < CTA_STATS_EXP_MAX+1; i++)
- nfstat_root.metrics_exp[i] = 0;
- // prepare the request
- nfstat_root.nlh = nfct_mnl_nlmsghdr_put(nfstat_root.buf, NFNL_SUBSYS_CTNETLINK_EXP, IPCTNL_MSG_EXP_GET_STATS_CPU, AF_UNSPEC, nfstat_root.seq);
- // send the request
- if(mnl_socket_sendto(nfstat_root.mnl, nfstat_root.nlh, nfstat_root.nlh->nlmsg_len) < 0) {
- error("NFSTAT: mnl_socket_sendto() failed");
- return 1;
- }
- // get the reply
- ssize_t ret;
- while ((ret = mnl_socket_recvfrom(nfstat_root.mnl, nfstat_root.buf, nfstat_root.buf_size)) > 0) {
- if(mnl_cb_run(
- nfstat_root.buf
- , (size_t)ret
- , nfstat_root.nlh->nlmsg_seq
- , nfstat_root.portid
- , nfstat_callback_exp
- , NULL
- ) <= MNL_CB_STOP)
- break;
- }
- // verify we run without issues
- if (ret == -1) {
- error("NFSTAT: error communicating with kernel. This plugin can only work when netdata runs as root.");
- return 1;
- }
- return 0;
- }
- static int nfstat_collect() {
- nfstat_root.seq++;
- if(nfstat_collect_conntrack())
- return 1;
- if(nfstat_collect_conntrack_expectations())
- return 1;
- return 0;
- }
- static void nfstat_send_metrics() {
- static int new_chart_generated = 0, changes_chart_generated = 0, search_chart_generated = 0, errors_chart_generated = 0, expect_chart_generated = 0;
- if(!new_chart_generated) {
- new_chart_generated = 1;
- printf("CHART %s.%s '' 'Connection Tracker New Connections' 'connections/s' %s '' line %d %d %s\n"
- , RRD_TYPE_NET_STAT_NETFILTER
- , RRD_TYPE_NET_STAT_CONNTRACK "_new"
- , RRD_TYPE_NET_STAT_CONNTRACK
- , NETDATA_CHART_PRIO_NETFILTER_NEW
- , nfstat_root.update_every
- , PLUGIN_NFACCT_NAME
- );
- printf("DIMENSION %s '' incremental 1 1\n", nfstat_root.attr2name[CTA_STATS_NEW]);
- printf("DIMENSION %s '' incremental -1 1\n", nfstat_root.attr2name[CTA_STATS_IGNORE]);
- printf("DIMENSION %s '' incremental -1 1\n", nfstat_root.attr2name[CTA_STATS_INVALID]);
- }
- printf(
- "BEGIN %s.%s\n"
- , RRD_TYPE_NET_STAT_NETFILTER
- , RRD_TYPE_NET_STAT_CONNTRACK "_new"
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_NEW]
- , (collected_number) nfstat_root.metrics[CTA_STATS_NEW]
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_IGNORE]
- , (collected_number) nfstat_root.metrics[CTA_STATS_IGNORE]
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_INVALID]
- , (collected_number) nfstat_root.metrics[CTA_STATS_INVALID]
- );
- printf("END\n");
- // ----------------------------------------------------------------
- if(!changes_chart_generated) {
- changes_chart_generated = 1;
- printf("CHART %s.%s '' 'Connection Tracker Changes' 'changes/s' %s '' line %d %d detail %s\n"
- , RRD_TYPE_NET_STAT_NETFILTER
- , RRD_TYPE_NET_STAT_CONNTRACK "_changes"
- , RRD_TYPE_NET_STAT_CONNTRACK
- , NETDATA_CHART_PRIO_NETFILTER_CHANGES
- , nfstat_root.update_every
- , PLUGIN_NFACCT_NAME
- );
- printf("DIMENSION %s '' incremental 1 1\n", nfstat_root.attr2name[CTA_STATS_INSERT]);
- printf("DIMENSION %s '' incremental -1 1\n", nfstat_root.attr2name[CTA_STATS_DELETE]);
- printf("DIMENSION %s '' incremental -1 1\n", nfstat_root.attr2name[CTA_STATS_DELETE_LIST]);
- }
- printf(
- "BEGIN %s.%s\n"
- , RRD_TYPE_NET_STAT_NETFILTER
- , RRD_TYPE_NET_STAT_CONNTRACK "_changes"
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_INSERT]
- , (collected_number) nfstat_root.metrics[CTA_STATS_INSERT]
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_DELETE]
- , (collected_number) nfstat_root.metrics[CTA_STATS_DELETE]
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_DELETE_LIST]
- , (collected_number) nfstat_root.metrics[CTA_STATS_DELETE_LIST]
- );
- printf("END\n");
- // ----------------------------------------------------------------
- if(!search_chart_generated) {
- search_chart_generated = 1;
- printf("CHART %s.%s '' 'Connection Tracker Searches' 'searches/s' %s '' line %d %d detail %s\n"
- , RRD_TYPE_NET_STAT_NETFILTER
- , RRD_TYPE_NET_STAT_CONNTRACK "_search"
- , RRD_TYPE_NET_STAT_CONNTRACK
- , NETDATA_CHART_PRIO_NETFILTER_SEARCH
- , nfstat_root.update_every
- , PLUGIN_NFACCT_NAME
- );
- printf("DIMENSION %s '' incremental 1 1\n", nfstat_root.attr2name[CTA_STATS_SEARCHED]);
- printf("DIMENSION %s '' incremental -1 1\n", nfstat_root.attr2name[CTA_STATS_SEARCH_RESTART]);
- printf("DIMENSION %s '' incremental 1 1\n", nfstat_root.attr2name[CTA_STATS_FOUND]);
- }
- printf(
- "BEGIN %s.%s\n"
- , RRD_TYPE_NET_STAT_NETFILTER
- , RRD_TYPE_NET_STAT_CONNTRACK "_search"
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_SEARCHED]
- , (collected_number) nfstat_root.metrics[CTA_STATS_SEARCHED]
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_SEARCH_RESTART]
- , (collected_number) nfstat_root.metrics[CTA_STATS_SEARCH_RESTART]
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_FOUND]
- , (collected_number) nfstat_root.metrics[CTA_STATS_FOUND]
- );
- printf("END\n");
- // ----------------------------------------------------------------
- if(!errors_chart_generated) {
- errors_chart_generated = 1;
- printf("CHART %s.%s '' 'Connection Tracker Errors' 'events/s' %s '' line %d %d detail %s\n"
- , RRD_TYPE_NET_STAT_NETFILTER
- , RRD_TYPE_NET_STAT_CONNTRACK "_errors"
- , RRD_TYPE_NET_STAT_CONNTRACK
- , NETDATA_CHART_PRIO_NETFILTER_ERRORS
- , nfstat_root.update_every
- , PLUGIN_NFACCT_NAME
- );
- printf("DIMENSION %s '' incremental 1 1\n", nfstat_root.attr2name[CTA_STATS_ERROR]);
- printf("DIMENSION %s '' incremental -1 1\n", nfstat_root.attr2name[CTA_STATS_INSERT_FAILED]);
- printf("DIMENSION %s '' incremental -1 1\n", nfstat_root.attr2name[CTA_STATS_DROP]);
- printf("DIMENSION %s '' incremental -1 1\n", nfstat_root.attr2name[CTA_STATS_EARLY_DROP]);
- }
- printf(
- "BEGIN %s.%s\n"
- , RRD_TYPE_NET_STAT_NETFILTER
- , RRD_TYPE_NET_STAT_CONNTRACK "_errors"
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_ERROR]
- , (collected_number) nfstat_root.metrics[CTA_STATS_ERROR]
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_INSERT_FAILED]
- , (collected_number) nfstat_root.metrics[CTA_STATS_INSERT_FAILED]
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_DROP]
- , (collected_number) nfstat_root.metrics[CTA_STATS_DROP]
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_EARLY_DROP]
- , (collected_number) nfstat_root.metrics[CTA_STATS_EARLY_DROP]
- );
- printf("END\n");
- // ----------------------------------------------------------------
- if(!expect_chart_generated) {
- expect_chart_generated = 1;
- printf("CHART %s.%s '' 'Connection Tracker Expectations' 'expectations/s' %s '' line %d %d detail %s\n"
- , RRD_TYPE_NET_STAT_NETFILTER
- , RRD_TYPE_NET_STAT_CONNTRACK "_expect"
- , RRD_TYPE_NET_STAT_CONNTRACK
- , NETDATA_CHART_PRIO_NETFILTER_EXPECT
- , nfstat_root.update_every
- , PLUGIN_NFACCT_NAME
- );
- printf("DIMENSION %s '' incremental 1 1\n", nfstat_root.attr2name[CTA_STATS_EXP_CREATE]);
- printf("DIMENSION %s '' incremental -1 1\n", nfstat_root.attr2name[CTA_STATS_EXP_DELETE]);
- printf("DIMENSION %s '' incremental 1 1\n", nfstat_root.attr2name[CTA_STATS_EXP_NEW]);
- }
- printf(
- "BEGIN %s.%s\n"
- , RRD_TYPE_NET_STAT_NETFILTER
- , RRD_TYPE_NET_STAT_CONNTRACK "_expect"
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_EXP_CREATE]
- , (collected_number) nfstat_root.metrics[CTA_STATS_EXP_CREATE]
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_EXP_DELETE]
- , (collected_number) nfstat_root.metrics[CTA_STATS_EXP_DELETE]
- );
- printf(
- "SET %s = %lld\n"
- , nfstat_root.attr2name[CTA_STATS_EXP_NEW]
- , (collected_number) nfstat_root.metrics[CTA_STATS_EXP_NEW]
- );
- printf("END\n");
- }
- struct nfacct_data {
- char *name;
- uint32_t hash;
- uint64_t pkts;
- uint64_t bytes;
- int packets_dimension_added;
- int bytes_dimension_added;
- int updated;
- struct nfacct_data *next;
- };
- static struct {
- int update_every;
- char *buf;
- size_t buf_size;
- struct mnl_socket *mnl;
- struct nlmsghdr *nlh;
- unsigned int seq;
- uint32_t portid;
- struct nfacct *nfacct_buffer;
- struct nfacct_data *nfacct_metrics;
- } nfacct_root = {
- .update_every = 1,
- .buf = NULL,
- .buf_size = 0,
- .mnl = NULL,
- .nlh = NULL,
- .seq = 0,
- .portid = 0,
- .nfacct_buffer = NULL,
- .nfacct_metrics = NULL
- };
- static inline struct nfacct_data *nfacct_data_get(const char *name, uint32_t hash) {
- struct nfacct_data *d = NULL, *last = NULL;
- for(d = nfacct_root.nfacct_metrics; d ; last = d, d = d->next) {
- if(unlikely(d->hash == hash && !strcmp(d->name, name)))
- return d;
- }
- d = callocz(1, sizeof(struct nfacct_data));
- d->name = strdupz(name);
- d->hash = hash;
- if(!last) {
- d->next = nfacct_root.nfacct_metrics;
- nfacct_root.nfacct_metrics = d;
- }
- else {
- d->next = last->next;
- last->next = d;
- }
- return d;
- }
- static int nfacct_init(int update_every) {
- nfacct_root.update_every = update_every;
- nfacct_root.buf_size = mnl_buffer_size();
- nfacct_root.buf = mallocz(nfacct_root.buf_size);
- nfacct_root.nfacct_buffer = nfacct_alloc();
- if(!nfacct_root.nfacct_buffer) {
- error("nfacct.plugin: nfacct_alloc() failed.");
- return 0;
- }
- nfacct_root.seq = (unsigned int)now_realtime_sec() - 1;
- nfacct_root.mnl = mnl_socket_open(NETLINK_NETFILTER);
- if(!nfacct_root.mnl) {
- error("nfacct.plugin: mnl_socket_open() failed");
- return 1;
- }
- if(mnl_socket_bind(nfacct_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
- error("nfacct.plugin: mnl_socket_bind() failed");
- return 1;
- }
- nfacct_root.portid = mnl_socket_get_portid(nfacct_root.mnl);
- return 0;
- }
- static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
- (void)data;
- if(nfacct_nlmsg_parse_payload(nlh, nfacct_root.nfacct_buffer) < 0) {
- error("NFACCT: nfacct_nlmsg_parse_payload() failed.");
- return MNL_CB_OK;
- }
- const char *name = nfacct_attr_get_str(nfacct_root.nfacct_buffer, NFACCT_ATTR_NAME);
- uint32_t hash = simple_hash(name);
- struct nfacct_data *d = nfacct_data_get(name, hash);
- d->pkts = nfacct_attr_get_u64(nfacct_root.nfacct_buffer, NFACCT_ATTR_PKTS);
- d->bytes = nfacct_attr_get_u64(nfacct_root.nfacct_buffer, NFACCT_ATTR_BYTES);
- d->updated = 1;
- return MNL_CB_OK;
- }
- static int nfacct_collect() {
- // mark all old metrics as not-updated
- struct nfacct_data *d;
- for(d = nfacct_root.nfacct_metrics; d ; d = d->next)
- d->updated = 0;
- // prepare the request
- nfacct_root.seq++;
- nfacct_root.nlh = nfacct_nlmsg_build_hdr(nfacct_root.buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, (uint32_t)nfacct_root.seq);
- if(!nfacct_root.nlh) {
- error("NFACCT: nfacct_nlmsg_build_hdr() failed");
- return 1;
- }
- // send the request
- if(mnl_socket_sendto(nfacct_root.mnl, nfacct_root.nlh, nfacct_root.nlh->nlmsg_len) < 0) {
- error("NFACCT: mnl_socket_sendto() failed");
- return 1;
- }
- // get the reply
- ssize_t ret;
- while((ret = mnl_socket_recvfrom(nfacct_root.mnl, nfacct_root.buf, nfacct_root.buf_size)) > 0) {
- if(mnl_cb_run(
- nfacct_root.buf
- , (size_t)ret
- , nfacct_root.seq
- , nfacct_root.portid
- , nfacct_callback
- , NULL
- ) <= 0)
- break;
- }
- // verify we run without issues
- if (ret == -1) {
- error("NFACCT: error communicating with kernel. This plugin can only work when netdata runs as root.");
- return 1;
- }
- return 0;
- }
- static void nfacct_send_metrics() {
- static int bytes_chart_generated = 0, packets_chart_generated = 0;
- if(!nfacct_root.nfacct_metrics) return;
- struct nfacct_data *d;
- if(!packets_chart_generated) {
- packets_chart_generated = 1;
- printf("CHART netfilter.nfacct_packets '' 'Netfilter Accounting Packets' 'packets/s' 'nfacct' '' stacked %d %d %s\n"
- , NETDATA_CHART_PRIO_NETFILTER_PACKETS
- , nfacct_root.update_every
- , PLUGIN_NFACCT_NAME
- );
- }
- for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
- if(likely(d->updated)) {
- if(unlikely(!d->packets_dimension_added)) {
- d->packets_dimension_added = 1;
- printf(
- "CHART netfilter.nfacct_packets '' 'Netfilter Accounting Packets' 'packets/s' 'nfacct' '' stacked %d %d %s\n",
- NETDATA_CHART_PRIO_NETFILTER_PACKETS,
- nfacct_root.update_every,
- PLUGIN_NFACCT_NAME);
- printf("DIMENSION %s '' incremental 1 %d\n", d->name, nfacct_root.update_every);
- }
- }
- }
- printf("BEGIN netfilter.nfacct_packets\n");
- for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
- if(likely(d->updated)) {
- printf("SET %s = %lld\n"
- , d->name
- , (collected_number)d->pkts
- );
- }
- }
- printf("END\n");
- // ----------------------------------------------------------------
- if(!bytes_chart_generated) {
- bytes_chart_generated = 1;
- printf("CHART netfilter.nfacct_bytes '' 'Netfilter Accounting Bandwidth' 'kilobytes/s' 'nfacct' '' stacked %d %d %s\n"
- , NETDATA_CHART_PRIO_NETFILTER_BYTES
- , nfacct_root.update_every
- , PLUGIN_NFACCT_NAME
- );
- }
- for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
- if(likely(d->updated)) {
- if(unlikely(!d->bytes_dimension_added)) {
- d->bytes_dimension_added = 1;
- printf(
- "CHART netfilter.nfacct_bytes '' 'Netfilter Accounting Bandwidth' 'kilobytes/s' 'nfacct' '' stacked %d %d %s\n",
- NETDATA_CHART_PRIO_NETFILTER_BYTES,
- nfacct_root.update_every,
- PLUGIN_NFACCT_NAME);
- printf("DIMENSION %s '' incremental 1 %d\n", d->name, 1000 * nfacct_root.update_every);
- }
- }
- }
- printf("BEGIN netfilter.nfacct_bytes\n");
- for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
- if(likely(d->updated)) {
- printf("SET %s = %lld\n"
- , d->name
- , (collected_number)d->bytes
- );
- }
- }
- printf("END\n");
- }
- static void nfacct_signal_handler(int signo)
- {
- exit((signo == SIGPIPE)?1:0);
- }
- // When Netdata crashes this plugin was becoming zombie,
- // this function was added to remove it when sigpipe and other signals are received.
- void nfacct_signals()
- {
- int signals[] = { SIGPIPE, SIGINT, SIGTERM, 0};
- int i;
- struct sigaction sa;
- sa.sa_flags = 0;
- sa.sa_handler = nfacct_signal_handler;
- // ignore all signals while we run in a signal handler
- sigfillset(&sa.sa_mask);
- for (i = 0; signals[i]; i++) {
- if(sigaction(signals[i], &sa, NULL) == -1)
- error("Cannot add the handler to signal %d", signals[i]);
- }
- }
- int main(int argc, char **argv) {
- // ------------------------------------------------------------------------
- // initialization of netdata plugin
- program_name = "nfacct.plugin";
- // disable syslog
- error_log_syslog = 0;
- // set errors flood protection to 100 logs per hour
- error_log_errors_per_period = 100;
- error_log_throttle_period = 3600;
- // ------------------------------------------------------------------------
- // parse command line parameters
- int i, freq = 0;
- for(i = 1; i < argc ; i++) {
- if(isdigit(*argv[i]) && !freq) {
- int n = str2i(argv[i]);
- if(n > 0 && n < 86400) {
- freq = n;
- continue;
- }
- }
- else if(strcmp("version", argv[i]) == 0 || strcmp("-version", argv[i]) == 0 || strcmp("--version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
- printf("nfacct.plugin %s\n", VERSION);
- exit(0);
- }
- else if(strcmp("debug", argv[i]) == 0) {
- debug = 1;
- continue;
- }
- else if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
- fprintf(stderr,
- "\n"
- " netdata nfacct.plugin %s\n"
- " Copyright (C) 2015-2017 Costa Tsaousis <costa@tsaousis.gr>\n"
- " Released under GNU General Public License v3 or later.\n"
- " All rights reserved.\n"
- "\n"
- " This program is a data collector plugin for netdata.\n"
- "\n"
- " Available command line options:\n"
- "\n"
- " COLLECTION_FREQUENCY data collection frequency in seconds\n"
- " minimum: %d\n"
- "\n"
- " debug enable verbose output\n"
- " default: disabled\n"
- "\n"
- " -v\n"
- " -V\n"
- " --version print version and exit\n"
- "\n"
- " -h\n"
- " --help print this message and exit\n"
- "\n"
- " For more information:\n"
- " https://github.com/netdata/netdata/tree/master/collectors/nfacct.plugin\n"
- "\n"
- , VERSION
- , netdata_update_every
- );
- exit(1);
- }
- error("nfacct.plugin: ignoring parameter '%s'", argv[i]);
- }
- nfacct_signals();
- errno = 0;
- if(freq >= netdata_update_every)
- netdata_update_every = freq;
- else if(freq)
- error("update frequency %d seconds is too small for NFACCT. Using %d.", freq, netdata_update_every);
- if (debug)
- fprintf(stderr, "nfacct.plugin: calling nfacct_init()\n");
- int nfacct = !nfacct_init(netdata_update_every);
- if (debug)
- fprintf(stderr, "nfacct.plugin: calling nfstat_init()\n");
- int nfstat = !nfstat_init(netdata_update_every);
- // ------------------------------------------------------------------------
- // the main loop
- if(debug) fprintf(stderr, "nfacct.plugin: starting data collection\n");
- time_t started_t = now_monotonic_sec();
- size_t iteration;
- usec_t step = netdata_update_every * USEC_PER_SEC;
- heartbeat_t hb;
- heartbeat_init(&hb);
- for(iteration = 0; 1; iteration++) {
- usec_t dt = heartbeat_next(&hb, step);
- if(unlikely(netdata_exit)) break;
- if(debug && iteration)
- fprintf(stderr, "nfacct.plugin: iteration %zu, dt %llu usec\n"
- , iteration
- , dt
- );
- if(likely(nfacct)) {
- if(debug) fprintf(stderr, "nfacct.plugin: calling nfacct_collect()\n");
- nfacct = !nfacct_collect();
- if(likely(nfacct)) {
- if(debug) fprintf(stderr, "nfacct.plugin: calling nfacct_send_metrics()\n");
- nfacct_send_metrics();
- }
- }
- if(likely(nfstat)) {
- if(debug) fprintf(stderr, "nfacct.plugin: calling nfstat_collect()\n");
- nfstat = !nfstat_collect();
- if(likely(nfstat)) {
- if(debug) fprintf(stderr, "nfacct.plugin: calling nfstat_send_metrics()\n");
- nfstat_send_metrics();
- }
- }
- fflush(stdout);
- // restart check (14400 seconds)
- if(now_monotonic_sec() - started_t > 14400) break;
- }
- info("NFACCT process exiting");
- }
|