nfacct: Add patches for direct JSON output format

Rather than parsing the existing XML or standard output of the nfacct
utility, and then piping that into a perl/python script for formatting
to JSON, we teach nfacct to generate JSON directly.  This seems like
the proper way to do it.  The patches will be submitted mainline.
This commit is contained in:
Harald Welte 2015-05-19 22:21:41 +02:00
parent 88f39279bc
commit d3ae677639
4 changed files with 341 additions and 0 deletions

View File

@ -0,0 +1,95 @@
From 1ac986e0bee1cbfc8039c259617bb9bdba1d6e75 Mon Sep 17 00:00:00 2001
From: Harald Welte <laforge@gnumonks.org>
Date: Tue, 19 May 2015 22:09:45 +0200
Subject: [PATCH] add JSON output format
the original output format looks a bit like JSON, but isn't. The XML
output is useful if you deal with XML, but a lot of applications prefer
more lightweight formats like YAML/JSON.
This adds the JSON output format to libnetfilter_acct, which will
subsequently be used by a similar change in the nfacct utility.
---
include/libnetfilter_acct/libnetfilter_acct.h | 1 +
src/libnetfilter_acct.c | 46 +++++++++++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/include/libnetfilter_acct/libnetfilter_acct.h b/include/libnetfilter_acct/libnetfilter_acct.h
index c6ed858..647490f 100644
--- a/include/libnetfilter_acct/libnetfilter_acct.h
+++ b/include/libnetfilter_acct/libnetfilter_acct.h
@@ -41,6 +41,7 @@ int nfacct_nlmsg_parse_payload(const struct nlmsghdr *nlh, struct nfacct *nfacct
#define NFACCT_SNPRINTF_T_PLAIN 0
#define NFACCT_SNPRINTF_T_XML 1
+#define NFACCT_SNPRINTF_T_JSON 2
int nfacct_snprintf(char *buf, size_t size, struct nfacct *nfacct, uint16_t type, uint16_t flags);
diff --git a/src/libnetfilter_acct.c b/src/libnetfilter_acct.c
index bb15c68..b0bcf67 100644
--- a/src/libnetfilter_acct.c
+++ b/src/libnetfilter_acct.c
@@ -297,6 +297,49 @@ nfacct_snprintf_plain(char *buf, size_t rem, struct nfacct *nfacct,
return len;
}
+static int
+nfacct_snprintf_json(char *buf, size_t rem, struct nfacct *nfacct,
+ uint16_t flags)
+{
+ int ret = 0, offset = 0, len = 0;
+
+ if (flags & NFACCT_SNPRINTF_F_FULL) {
+ ret = snprintf(buf, rem,
+ " { \"pkts\" : %"PRIu64", \"bytes\" : %"PRIu64"",
+ nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS),
+ nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES));
+ SNPRINTF_CHECK(ret, rem, offset, len);
+
+ if (nfacct->flags) {
+ uint32_t mode;
+ char *mode_name;
+
+ mode = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_FLAGS);
+ if (mode & NFACCT_F_QUOTA_PKTS)
+ mode_name = "packet";
+ else if (mode & NFACCT_F_QUOTA_BYTES)
+ mode_name = "byte";
+ else
+ mode_name = "unknown";
+
+ ret = snprintf(buf + offset, rem,
+ ", \"quota\" : %"PRIu64", \"mode\" = \"%s\""\
+ ", \"overquota\" = %u",
+ nfacct_attr_get_u64(nfacct, NFACCT_ATTR_QUOTA),
+ mode_name,
+ mode & NFACCT_F_OVERQUOTA ? 1 : 0);
+ SNPRINTF_CHECK(ret, rem, offset, len);
+ }
+
+ ret = snprintf(buf + offset, rem, ", \"name\" : \"%s\" }",
+ nfacct_attr_get_str(nfacct, NFACCT_ATTR_NAME));
+ }
+ /* non-F_FULL doesn't seem to make sense in JSON */
+ SNPRINTF_CHECK(ret, rem, offset, len);
+
+ return len;
+}
+
#define BUFFER_SIZE(ret, size, rem, offset) \
size += ret; \
if (ret > rem) \
@@ -393,6 +436,9 @@ int nfacct_snprintf(char *buf, size_t size, struct nfacct *nfacct,
case NFACCT_SNPRINTF_T_XML:
ret = nfacct_snprintf_xml(buf, size, nfacct, flags);
break;
+ case NFACCT_SNPRINTF_T_JSON:
+ ret = nfacct_snprintf_json(buf, size, nfacct, flags);
+ break;
default:
ret = -1;
break;
--
2.1.4

View File

@ -0,0 +1,16 @@
SUMMARY = "libnetfilter_acct is the userspace library providing interface to extended accounting infrastructure."
HOMEPAGE = "http://www.netfilter.org/projects/libnetfilter_acct/index.html"
LICENSE = "LGPLv2.1+"
LIC_FILES_CHKSUM = "file://COPYING;md5=4fbd65380cdd255951079008b364516c"
PV="1.0.2+git${SRCPV}"
PR = "r0"
DEPENDS = "libmnl"
SRC_URI = "git://git.netfilter.org/libnetfilter_acct;branch=master \
file://0001-add-JSON-output-format.patch \
"
SRCREV = "a9fea38024e6bde9118cc12bc8417b207ffc4da9"
S = "${WORKDIR}/git"
inherit autotools pkgconfig

View File

@ -0,0 +1,213 @@
From aefba0f03444345dd5384631203f61647637175d Mon Sep 17 00:00:00 2001
From: Harald Welte <laforge@gnumonks.org>
Date: Tue, 19 May 2015 22:12:06 +0200
Subject: [PATCH] Add JSON output formatting to nfacct utility
This is based on the JSON support patch of libnetfilter_acct.
---
nfacct.8 | 2 ++
src/nfacct.c | 87 ++++++++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 66 insertions(+), 23 deletions(-)
diff --git a/nfacct.8 b/nfacct.8
index 0c3249c..bf563ae 100644
--- a/nfacct.8
+++ b/nfacct.8
@@ -47,6 +47,8 @@ That atomically obtains and resets the counters.
.TP
.BI "xml "
That displays the output in XML format.
+.BI "json "
+That displays the output in JSON format.
.PP
.SH SEE ALSO
.BR iptables (8)
diff --git a/src/nfacct.c b/src/nfacct.c
index 2546a6e..a55655a 100644
--- a/src/nfacct.c
+++ b/src/nfacct.c
@@ -137,13 +137,13 @@ int main(int argc, char *argv[])
return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
-static bool xml_header = false;
+static bool fmt_header = false;
static int nfacct_cb(const struct nlmsghdr *nlh, void *data)
{
struct nfacct *nfacct;
char buf[4096];
- bool *xml = (bool *)data;
+ int *fmt = (int *)data;
nfacct = nfacct_alloc();
if (nfacct == NULL) {
@@ -156,17 +156,36 @@ static int nfacct_cb(const struct nlmsghdr *nlh, void *data)
goto err_free;
}
- if (*xml && !xml_header) {
- printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
- "<nfacct>\n");
- xml_header = true;
+ switch (*fmt) {
+ case NFACCT_SNPRINTF_T_XML:
+ if (!fmt_header) {
+ printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<nfacct>\n");
+ fmt_header = true;
+ }
+ break;
+ case NFACCT_SNPRINTF_T_JSON:
+ if (!fmt_header) {
+ printf("{ \"nfacct_counters\" : [\n");
+ fmt_header = true;
+ } else
+ printf(",\n");
+ break;
+ default:
+ break;
}
- nfacct_snprintf(buf, sizeof(buf), nfacct,
- *xml ? NFACCT_SNPRINTF_T_XML :
- NFACCT_SNPRINTF_T_PLAIN,
+ nfacct_snprintf(buf, sizeof(buf), nfacct, *fmt,
NFACCT_SNPRINTF_F_FULL);
- printf("%s\n", buf);
+ printf("%s", buf);
+ switch (*fmt) {
+ case NFACCT_SNPRINTF_T_JSON:
+ /* no newline in JSON case */
+ break;
+ default:
+ putchar('\n');
+ break;
+ }
err_free:
nfacct_free(nfacct);
@@ -174,9 +193,26 @@ err:
return MNL_CB_OK;
}
+static void _print_footer(int fmt)
+{
+ if (fmt_header) {
+ switch (fmt) {
+ case NFACCT_SNPRINTF_T_XML:
+ printf("</nfacct>\n");
+ break;
+ case NFACCT_SNPRINTF_T_JSON:
+ printf("\n] }\n");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
static int nfacct_cmd_list(int argc, char *argv[])
{
- bool zeroctr = false, xml = false;
+ bool zeroctr = false;
+ int fmt = NFACCT_SNPRINTF_T_PLAIN;
struct mnl_socket *nl;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
@@ -190,9 +226,13 @@ static int nfacct_cmd_list(int argc, char *argv[])
duparg(argv[i]);
zeroctr = true;
} else if (strncmp(argv[i], "xml", strlen(argv[i])) == 0) {
- if (xml)
+ if (fmt)
+ duparg(argv[i]);
+ fmt = NFACCT_SNPRINTF_T_XML;
+ } else if (strncmp(argv[i], "json", strlen(argv[i])) == 0) {
+ if (fmt)
duparg(argv[i]);
- xml = true;
+ fmt = NFACCT_SNPRINTF_T_JSON;
} else if (strncmp(argv[i], "counters", strlen(argv[i])) == 0) {
if (mask || value)
duparg(argv[i]);
@@ -251,7 +291,7 @@ static int nfacct_cmd_list(int argc, char *argv[])
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
while (ret > 0) {
- ret = mnl_cb_run(buf, ret, seq, portid, nfacct_cb, &xml);
+ ret = mnl_cb_run(buf, ret, seq, portid, nfacct_cb, &fmt);
if (ret <= 0)
break;
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
@@ -262,8 +302,7 @@ static int nfacct_cmd_list(int argc, char *argv[])
}
mnl_socket_close(nl);
- if (xml_header)
- printf("</nfacct>\n");
+ _print_footer(fmt);
return 0;
}
@@ -444,7 +483,8 @@ static int nfacct_cmd_delete(int argc, char *argv[])
static int nfacct_cmd_get(int argc, char *argv[])
{
- bool zeroctr = false, xml = false;
+ bool zeroctr = false;
+ int fmt = NFACCT_SNPRINTF_T_PLAIN;
struct mnl_socket *nl;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
@@ -460,7 +500,9 @@ static int nfacct_cmd_get(int argc, char *argv[])
if (strncmp(argv[i], "reset", strlen(argv[i])) == 0) {
zeroctr = true;
} else if (strncmp(argv[i], "xml", strlen(argv[i])) == 0) {
- xml = true;
+ fmt = NFACCT_SNPRINTF_T_XML;
+ } else if (strncmp(argv[i], "json", strlen(argv[i])) == 0) {
+ fmt = NFACCT_SNPRINTF_T_JSON;
} else {
nfacct_perror("unknown argument");
return -1;
@@ -503,7 +545,7 @@ static int nfacct_cmd_get(int argc, char *argv[])
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
while (ret > 0) {
- ret = mnl_cb_run(buf, ret, seq, portid, nfacct_cb, &xml);
+ ret = mnl_cb_run(buf, ret, seq, portid, nfacct_cb, &fmt);
if (ret <= 0)
break;
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
@@ -514,8 +556,7 @@ static int nfacct_cmd_get(int argc, char *argv[])
}
mnl_socket_close(nl);
- if (xml_header)
- printf("</nfacct>\n");
+ _print_footer(fmt);
return 0;
}
@@ -660,7 +701,7 @@ static int nfacct_cmd_restore(int argc, char *argv[])
static int nfacct_cmd_monitor(int argc, char *argv[])
{
struct mnl_socket *nl;
- bool xml = false;
+ int fmt = NFACCT_SNPRINTF_T_PLAIN;
char buf[MNL_SOCKET_BUFFER_SIZE];
int ret, option = NFNLGRP_ACCT_QUOTA;
@@ -685,7 +726,7 @@ static int nfacct_cmd_monitor(int argc, char *argv[])
break;
}
- ret = mnl_cb_run(buf, ret, 0, 0, nfacct_cb, &xml);
+ ret = mnl_cb_run(buf, ret, 0, 0, nfacct_cb, &fmt);
if (ret <= 0)
break;
}
--
2.1.4

View File

@ -0,0 +1,17 @@
SUMMARY = "nfacct is the command line tool to create/retrieve/delete accounting objects"
HOMEPAGE = "http://www.netfilter.org/projects/nfacct/downloads.html"
LICENSE = "GPLv2+"
LIC_FILES_CHKSUM = "file://COPYING;md5=8ca43cbc842c2336e835926c2166c28b"
PV="1.0.1+git${SRCPV}"
DEPENDS = "libmnl libnetfilter-acct"
SRC_URI = "git://git.netfilter.org/nfacct;branch=master \
file://0001-Add-JSON-output-formatting-to-nfacct-utility.patch \
"
SRCREV = "4437682babe86de7435d4fc839437f99e998b79c"
S = "${WORKDIR}/git"
RDEPENDS_${PN} += "kernel-module-xt-nfacct kernel-module-nfnetlink-acct"
inherit autotools pkgconfig