netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH libnftnl 1/3] expr: nat: use 'nat_type' instead of 'type' in the parser
@ 2014-11-10 13:26 Pablo Neira Ayuso
  2014-11-10 13:26 ` [PATCH libnftnl 2/3 v2] src: consolidate XML/JSON exportation Pablo Neira Ayuso
  2014-11-10 13:26 ` [PATCH libnftnl 3/3] expr: data_reg: use 'reg' instead of 'data_reg' Pablo Neira Ayuso
  0 siblings, 2 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2014-11-10 13:26 UTC (permalink / raw)
  To: netfilter-devel; +Cc: arturo.borrero.glez, alvaroneay

'type' is already used from the expression.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/expr/nat.c                  |    2 +-
 tests/xmlfiles/32-rule-nat6.xml |    2 +-
 tests/xmlfiles/33-rule-nat4.xml |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/expr/nat.c b/src/expr/nat.c
index 811286c..60623a6 100644
--- a/src/expr/nat.c
+++ b/src/expr/nat.c
@@ -284,7 +284,7 @@ static int nft_rule_expr_nat_xml_parse(struct nft_rule_expr *e, mxml_node_t *tre
 	uint32_t reg_addr_min, reg_addr_max;
 	uint32_t reg_proto_min, reg_proto_max;
 
-	nat_type = nft_mxml_str_parse(tree, "type", MXML_DESCEND_FIRST,
+	nat_type = nft_mxml_str_parse(tree, "nat_type", MXML_DESCEND_FIRST,
 				      NFT_XML_MAND, err);
 	if (nat_type == NULL)
 		return -1;
diff --git a/tests/xmlfiles/32-rule-nat6.xml b/tests/xmlfiles/32-rule-nat6.xml
index f96b7d8..8fc52e8 100644
--- a/tests/xmlfiles/32-rule-nat6.xml
+++ b/tests/xmlfiles/32-rule-nat6.xml
@@ -1 +1 @@
-<nftables><rule><family>ip6</family><table>nat</table><chain>OUTPUT</chain><handle>100</handle><expr type="nat"><type>snat</type><family>ip6</family><sreg_addr_min>1</sreg_addr_min><sreg_addr_max>2</sreg_addr_max><sreg_proto_min>3</sreg_proto_min><sreg_proto_max>4</sreg_proto_max></expr></rule></nftables>
+<nftables><rule><family>ip6</family><table>nat</table><chain>OUTPUT</chain><handle>100</handle><expr type="nat"><nat_type>snat</nat_type><family>ip6</family><sreg_addr_min>1</sreg_addr_min><sreg_addr_max>2</sreg_addr_max><sreg_proto_min>3</sreg_proto_min><sreg_proto_max>4</sreg_proto_max></expr></rule></nftables>
diff --git a/tests/xmlfiles/33-rule-nat4.xml b/tests/xmlfiles/33-rule-nat4.xml
index 233c44e..b7b6cb6 100644
--- a/tests/xmlfiles/33-rule-nat4.xml
+++ b/tests/xmlfiles/33-rule-nat4.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>INPUT</chain><handle>100</handle><expr type="nat"><type>dnat</type><family>ip</family><sreg_addr_min>1</sreg_addr_min><sreg_addr_max>2</sreg_addr_max><sreg_proto_min>3</sreg_proto_min><sreg_proto_max>4</sreg_proto_max><flags>12</flags></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>INPUT</chain><handle>100</handle><expr type="nat"><nat_type>dnat</nat_type><family>ip</family><sreg_addr_min>1</sreg_addr_min><sreg_addr_max>2</sreg_addr_max><sreg_proto_min>3</sreg_proto_min><sreg_proto_max>4</sreg_proto_max><flags>12</flags></expr></rule></nftables>
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH libnftnl 2/3 v2] src: consolidate XML/JSON exportation
  2014-11-10 13:26 [PATCH libnftnl 1/3] expr: nat: use 'nat_type' instead of 'type' in the parser Pablo Neira Ayuso
@ 2014-11-10 13:26 ` Pablo Neira Ayuso
  2014-11-10 13:26 ` [PATCH libnftnl 3/3] expr: data_reg: use 'reg' instead of 'data_reg' Pablo Neira Ayuso
  1 sibling, 0 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2014-11-10 13:26 UTC (permalink / raw)
  To: netfilter-devel; +Cc: arturo.borrero.glez, alvaroneay

Add new buffer class to consolidate the existing code to export objects
in XML/JSON and use it. We save ~700 LOC with this change.

The rule and set objects are not yet consolidated. It seems this would
require some specific glue code per representation type since lists are
arranged differently.

This also consolidates the tag names, so we make sure the same are used
from XML and JSON by placing them in include/buffer.h.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/Makefile.am           |    3 +-
 include/buffer.h              |   80 +++++++++++++++++++
 src/Makefile.am               |    1 +
 src/buffer.c                  |  160 +++++++++++++++++++++++++++++++++++++
 src/chain.c                   |  174 ++++++++---------------------------------
 src/expr/bitwise.c            |  112 ++++----------------------
 src/expr/byteorder.c          |  101 +++++++-----------------
 src/expr/cmp.c                |   65 +++++----------
 src/expr/counter.c            |   48 +++---------
 src/expr/ct.c                 |   73 ++++-------------
 src/expr/exthdr.c             |   75 ++++--------------
 src/expr/immediate.c          |   71 ++++-------------
 src/expr/limit.c              |   50 +++---------
 src/expr/log.c                |   98 +++++------------------
 src/expr/lookup.c             |   56 +++----------
 src/expr/masq.c               |   33 ++------
 src/expr/match.c              |   35 +++------
 src/expr/meta.c               |   64 +++------------
 src/expr/nat.c                |  102 ++++++------------------
 src/expr/payload.c            |   69 ++++------------
 src/expr/queue.c              |   65 +++------------
 src/expr/redir.c              |   64 +++------------
 src/expr/reject.c             |   51 +++---------
 src/expr/target.c             |   35 +++------
 src/table.c                   |   86 ++++----------------
 tests/jsonfiles/11-chain.json |    2 +-
 tests/jsonfiles/12-chain.json |    2 +-
 tests/jsonfiles/13-chain.json |    2 +-
 tests/xmlfiles/10-chain.xml   |    2 +-
 tests/xmlfiles/11-chain.xml   |    2 +-
 tests/xmlfiles/12-chain.xml   |    2 +-
 31 files changed, 573 insertions(+), 1210 deletions(-)
 create mode 100644 include/buffer.h
 create mode 100644 src/buffer.c

diff --git a/include/Makefile.am b/include/Makefile.am
index 5976bbd..102d5ab 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,3 +1,4 @@
 SUBDIRS = libnftnl linux
 
-noinst_HEADERS = linux_list.h
+noinst_HEADERS = linux_list.h	\
+		 buffer.h
diff --git a/include/buffer.h b/include/buffer.h
new file mode 100644
index 0000000..2b497f2
--- /dev/null
+++ b/include/buffer.h
@@ -0,0 +1,80 @@
+#ifndef _NFT_BUFFER_H_
+#define _NFT_BUFFER_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+struct nft_buf {
+	char		*buf;
+	size_t		size;
+	size_t		len;
+	uint32_t	off;
+	bool		fail;
+};
+
+#define NFT_BUF_INIT(__b, __buf, __len)			\
+	struct nft_buf __b = {				\
+		.buf	= __buf,			\
+		.len	= __len,			\
+	};
+
+int nft_buf_update(struct nft_buf *b, int ret);
+int nft_buf_done(struct nft_buf *b);
+
+union nft_data_reg;
+
+int nft_buf_open(struct nft_buf *b, int type, const char *tag);
+int nft_buf_close(struct nft_buf *b, int type, const char *tag);
+
+int nft_buf_u32(struct nft_buf *b, int type, uint32_t value, const char *tag);
+int nft_buf_s32(struct nft_buf *b, int type, uint32_t value, const char *tag);
+int nft_buf_u64(struct nft_buf *b, int type, uint64_t value, const char *tag);
+int nft_buf_str(struct nft_buf *b, int type, const char *str, const char *tag);
+int nft_buf_reg(struct nft_buf *b, int type, union nft_data_reg *reg,
+		int reg_type, const char *tag);
+
+#define BASE			"base"
+#define BYTES			"bytes"
+#define CHAIN			"chain"
+#define CODE			"code"
+#define DATA			"data"
+#define DIR			"dir"
+#define DREG			"dreg"
+#define EXTHDR_TYPE		"exthdr_type"
+#define FAMILY			"family"
+#define FLAGS			"flags"
+#define GROUP			"group"
+#define HANDLE			"handle"
+#define HOOKNUM			"hooknum"
+#define KEY			"key"
+#define LEN			"len"
+#define LEVEL			"level"
+#define MASK			"mask"
+#define NAT_TYPE		"nat_type"
+#define NAME			"name"
+#define NUM			"num"
+#define OFFSET			"offset"
+#define OP			"op"
+#define PACKETS			"packets"
+#define PKTS			"pkts"
+#define POLICY			"policy"
+#define PREFIX			"prefix"
+#define PRIO			"prio"
+#define QTHRESH			"qthreshold"
+#define RATE			"rate"
+#define SET			"set"
+#define SIZE			"size"
+#define SNAPLEN			"snaplen"
+#define SREG_ADDR_MAX		"sreg_addr_max"
+#define SREG_ADDR_MIN		"sreg_addr_min"
+#define SREG_PROTO_MAX		"sreg_proto_max"
+#define SREG_PROTO_MIN		"sreg_proto_min"
+#define SREG			"sreg"
+#define TABLE			"table"
+#define TOTAL			"total"
+#define TYPE			"type"
+#define UNIT			"unit"
+#define USE			"use"
+#define XOR			"xor"
+
+#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index 941e69e..c77c3cc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,6 +6,7 @@ libnftnl_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnftnl.map	\
 		      -version-info $(LIBVERSION)
 
 libnftnl_la_SOURCES = utils.c		\
+		      buffer.c		\
 		      common.c		\
 		      gen.c		\
 		      table.c		\
diff --git a/src/buffer.c b/src/buffer.c
new file mode 100644
index 0000000..4fac110
--- /dev/null
+++ b/src/buffer.c
@@ -0,0 +1,160 @@
+/*
+ * (C) 2012-2014 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <buffer.h>
+#include <libnftnl/common.h>
+#include "internal.h"
+
+int nft_buf_update(struct nft_buf *b, int ret)
+{
+	if (ret < 0) {
+		b->fail = true;
+	} else {
+		b->off += ret;
+		if (ret > b->len)
+			ret = b->len;
+		b->size += ret;
+		b->len -= ret;
+	}
+
+	return ret;
+}
+
+int nft_buf_done(struct nft_buf *b)
+{
+	if (b->fail)
+		return -1;
+
+	/* Remove trailing comma in json */
+	if (b->size > 0 && b->buf[b->size - 1] == ',') {
+		b->off--;
+		b->size--;
+		b->len++;
+	}
+
+	return b->off;
+}
+
+static int nft_buf_put(struct nft_buf *b, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = vsnprintf(b->buf + b->off, b->len, fmt, ap);
+	ret = nft_buf_update(b, ret);
+	va_end(ap);
+
+	return ret;
+}
+
+int nft_buf_open(struct nft_buf *b, int type, const char *tag)
+{
+	switch (type) {
+	case NFT_OUTPUT_XML:
+		return nft_buf_put(b, "<%s>", tag);
+	case NFT_OUTPUT_JSON:
+		return nft_buf_put(b, "{\"%s\":{", tag);
+	default:
+		return 0;
+	}
+}
+
+int nft_buf_close(struct nft_buf *b, int type, const char *tag)
+{
+	switch (type) {
+	case NFT_OUTPUT_XML:
+		return nft_buf_put(b, "</%s>");
+	case NFT_OUTPUT_JSON:
+		/* Remove trailing comma in json */
+		if (b->size > 0 && b->buf[b->size - 1] == ',') {
+			b->off--;
+			b->size--;
+			b->len++;
+		}
+
+		return nft_buf_put(b, "}}");
+	default:
+		return 0;
+	}
+}
+
+int nft_buf_u32(struct nft_buf *b, int type, uint32_t value, const char *tag)
+{
+	switch (type) {
+	case NFT_OUTPUT_XML:
+		return nft_buf_put(b, "<%s>%u</%s>", tag, value, tag);
+	case NFT_OUTPUT_JSON:
+		return nft_buf_put(b, "\"%s\":%u,", tag, value);
+	default:
+		return 0;
+	}
+}
+
+int nft_buf_s32(struct nft_buf *b, int type, uint32_t value, const char *tag)
+{
+	switch (type) {
+	case NFT_OUTPUT_XML:
+		return nft_buf_put(b, "<%s>%d</%s>", tag, value, tag);
+	case NFT_OUTPUT_JSON:
+		return nft_buf_put(b, "\"%s\":%d,", tag, value);
+	default:
+		return 0;
+	}
+}
+
+int nft_buf_u64(struct nft_buf *b, int type, uint64_t value, const char *tag)
+{
+	switch (type) {
+	case NFT_OUTPUT_XML:
+		return nft_buf_put(b, "<%s>%"PRIu64"</%s>", tag, value, tag);
+	case NFT_OUTPUT_JSON:
+		return nft_buf_put(b, "\"%s\":%"PRIu64",", tag, value);
+	default:
+		return 0;
+	}
+}
+
+int nft_buf_str(struct nft_buf *b, int type, const char *str, const char *tag)
+{
+	switch (type) {
+	case NFT_OUTPUT_XML:
+		return nft_buf_put(b, "<%s>%s</%s>", tag, str, tag);
+	case NFT_OUTPUT_JSON:
+		return nft_buf_put(b, "\"%s\":\"%s\",", tag, str);
+	default:
+		return 0;
+	}
+}
+
+int nft_buf_reg(struct nft_buf *b, int type, union nft_data_reg *reg,
+		int reg_type, const char *tag)
+{
+	int ret;
+
+	switch (type) {
+	case NFT_OUTPUT_XML:
+		ret = nft_buf_put(b, "<%s>", tag);
+		ret = nft_data_reg_snprintf(b->buf + b->off, b->len, reg,
+                                    NFT_OUTPUT_XML, 0, reg_type);
+		nft_buf_update(b, ret);
+		return nft_buf_put(b, "</%s>", tag);
+	case NFT_OUTPUT_JSON:
+		nft_buf_put(b, "\"%s\":{", tag);
+		ret = nft_data_reg_snprintf(b->buf + b->off, b->len, reg,
+					    NFT_OUTPUT_JSON, 0, reg_type);
+		nft_buf_update(b, ret);
+		return nft_buf_put(b, "},");
+	}
+	return 0;
+}
diff --git a/src/chain.c b/src/chain.c
index a056bab..b67385e 100644
--- a/src/chain.c
+++ b/src/chain.c
@@ -27,6 +27,7 @@
 #include <linux/netfilter_arp.h>
 
 #include <libnftnl/chain.h>
+#include <buffer.h>
 
 struct nft_chain {
 	struct list_head head;
@@ -787,150 +788,41 @@ int nft_chain_parse_file(struct nft_chain *c, enum nft_parse_type type,
 }
 EXPORT_SYMBOL(nft_chain_parse_file);
 
-static int nft_chain_snprintf_json(char *buf, size_t size, struct nft_chain *c)
+static int nft_chain_export(char *buf, size_t size, struct nft_chain *c,
+			    int type)
 {
-	int ret, len = size, offset = 0;
-
-	ret = snprintf(buf, len, "{\"chain\":{");
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	ret = 0;
-
-	if (c->flags & (1 << NFT_CHAIN_ATTR_NAME)) {
-		ret = snprintf(buf + offset, len, "\"name\":\"%s\",", c->name);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_HANDLE)) {
-		ret = snprintf(buf + offset, len, "\"handle\":%"PRIu64",",
-			       c->handle);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_BYTES)) {
-		ret = snprintf(buf + offset, len, "\"bytes\":%"PRIu64",",
-			       c->bytes);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_PACKETS)) {
-		ret = snprintf(buf + offset, len, "\"packets\":%"PRIu64",",
-			       c->packets);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_FAMILY)) {
-		ret = snprintf(buf + offset, len, "\"family\":\"%s\",",
-			       nft_family2str(c->family));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_FAMILY)) {
-		ret = snprintf(buf + offset, len, "\"table\":\"%s\",",
-			       c->table);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_USE)) {
-		ret = snprintf(buf + offset, len, "\"use\":%d,", c->use);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_HOOKNUM)) {
-		if (c->flags & (1 << NFT_CHAIN_ATTR_TYPE)) {
-			ret = snprintf(buf + offset, len, "\"type\":\"%s\",",
-				       c->type);
-			SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-		}
+	NFT_BUF_INIT(b, buf, size);
 
-		ret = snprintf(buf + offset, len, "\"hooknum\":\"%s\",",
-			       nft_hooknum2str(c->family, c->hooknum));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-		if (c->flags & (1 << NFT_CHAIN_ATTR_PRIO)) {
-			ret = snprintf(buf + offset, len, "\"prio\":%d,",
-				       c->prio);
-			SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-		}
-		if (c->flags & (1 << NFT_CHAIN_ATTR_POLICY)) {
-			ret = snprintf(buf + offset, len, "\"policy\":\"%s\",",
-				       nft_verdict2str(c->policy));
-			SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-		}
-	}
-
-	/* If ret is not 0, some values are printed. So, It's necessary to
-	 * delete the last comma character
-	 */
-	if (ret > 0)
-		offset--;
-
-	ret = snprintf(buf + offset, len, "}}");
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	return offset;
-}
-
-static int nft_chain_snprintf_xml(char *buf, size_t size, struct nft_chain *c)
-{
-	int ret, len = size, offset = 0;
-
-	ret = snprintf(buf, len, "<chain>");
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	if (c->flags & (1 << NFT_CHAIN_ATTR_NAME)) {
-		ret = snprintf(buf + offset, len, "<name>%s</name>", c->name);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_HANDLE)) {
-		ret = snprintf(buf + offset, len, "<handle>%"PRIu64"</handle>",
-			       c->handle);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_BYTES)) {
-		ret = snprintf(buf + offset, len, "<bytes>%"PRIu64"</bytes>",
-			       c->bytes);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_PACKETS)) {
-		ret = snprintf(buf + offset, len, "<packets>%"PRIu64"</packets>",
-			       c->packets);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_TABLE)) {
-		ret = snprintf(buf + offset, len, "<table>%s</table>",
-			       c->table);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_USE)) {
-		ret = snprintf(buf + offset, len, "<use>%u</use>", c->use);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
+	nft_buf_open(&b, type, CHAIN);
+	if (c->flags & (1 << NFT_CHAIN_ATTR_NAME))
+		nft_buf_str(&b, type, c->name, NAME);
+	if (c->flags & (1 << NFT_CHAIN_ATTR_HANDLE))
+		nft_buf_u64(&b, type, c->handle, HANDLE);
+	if (c->flags & (1 << NFT_CHAIN_ATTR_BYTES))
+		nft_buf_u64(&b, type, c->bytes, BYTES);
+	if (c->flags & (1 << NFT_CHAIN_ATTR_PACKETS))
+		nft_buf_u64(&b, type, c->packets, PACKETS);
+	if (c->flags & (1 << NFT_CHAIN_ATTR_TABLE))
+		nft_buf_str(&b, type, c->table, TABLE);
+	if (c->flags & (1 << NFT_CHAIN_ATTR_FAMILY))
+		nft_buf_str(&b, type, nft_family2str(c->family), FAMILY);
+	if (c->flags & (1 << NFT_CHAIN_ATTR_USE))
+		nft_buf_u32(&b, type, c->use, USE);
 	if (c->flags & (1 << NFT_CHAIN_ATTR_HOOKNUM)) {
-		if (c->flags & (1 << NFT_CHAIN_ATTR_TYPE)) {
-			ret = snprintf(buf + offset, len, "<type>%s</type>",
-				       c->type);
-			SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-		}
-
-		ret = snprintf(buf + offset, len, "<hooknum>%s</hooknum>",
-			       nft_hooknum2str(c->family, c->hooknum));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-		if (c->flags & (1 << NFT_CHAIN_ATTR_PRIO)) {
-			ret = snprintf(buf + offset, len, "<prio>%d</prio>",
-				       c->prio);
-			SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-		}
-		if (c->flags & (1 << NFT_CHAIN_ATTR_POLICY)) {
-			ret = snprintf(buf + offset, len, "<policy>%s</policy>",
-				       nft_verdict2str(c->policy));
-			SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-		}
-	}
-	if (c->flags & (1 << NFT_CHAIN_ATTR_FAMILY)) {
-		ret = snprintf(buf + offset, len, "<family>%s</family>",
-			       nft_family2str(c->family));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+		if (c->flags & (1 << NFT_CHAIN_ATTR_TYPE))
+			nft_buf_str(&b, type, c->type, TYPE);
+		if (c->flags & (1 << NFT_CHAIN_ATTR_HOOKNUM))
+			nft_buf_str(&b, type, nft_hooknum2str(c->family,
+					 c->hooknum), HOOKNUM);
+		if (c->flags & (1 << NFT_CHAIN_ATTR_PRIO))
+			nft_buf_s32(&b, type, c->prio, PRIO);
+		if (c->flags & (1 << NFT_CHAIN_ATTR_POLICY))
+			nft_buf_str(&b, type, nft_verdict2str(c->policy), POLICY);
 	}
 
-	ret = snprintf(buf + offset, len, "</chain>");
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	nft_buf_close(&b, type, CHAIN);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int nft_chain_snprintf_default(char *buf, size_t size,
@@ -963,15 +855,13 @@ int nft_chain_snprintf(char *buf, size_t size, struct nft_chain *c,
 	ret = nft_event_header_snprintf(buf+offset, len, type, flags);
 	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		ret = nft_chain_snprintf_default(buf+offset, len, c);
 		break;
 	case NFT_OUTPUT_XML:
-		ret = nft_chain_snprintf_xml(buf+offset, len, c);
-		break;
 	case NFT_OUTPUT_JSON:
-		ret = nft_chain_snprintf_json(buf+offset, len, c);
+		ret = nft_chain_export(buf+offset, len, c, type);
 		break;
 	default:
 		return -1;
diff --git a/src/expr/bitwise.c b/src/expr/bitwise.c
index b575c7a..a299cd4 100644
--- a/src/expr/bitwise.c
+++ b/src/expr/bitwise.c
@@ -22,6 +22,7 @@
 #include <libnftnl/rule.h>
 #include "data_reg.h"
 #include "expr_ops.h"
+#include <buffer.h>
 
 struct nft_expr_bitwise {
 	enum nft_registers	sreg;
@@ -252,102 +253,24 @@ nft_rule_expr_bitwise_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
 #endif
 }
 
-static int nft_rule_expr_bitwise_snprintf_json(char *buf, size_t size,
-					       struct nft_rule_expr *e)
-{
-	int len = size, offset = 0, ret;
-	struct nft_expr_bitwise *bitwise = nft_expr_data(e);
-
-	if (e->flags & (1 << NFT_EXPR_BITWISE_SREG)) {
-		ret = snprintf(buf + offset, len, "\"sreg\":%u,",
-			       bitwise->sreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BITWISE_DREG)) {
-		ret = snprintf(buf + offset, len, "\"dreg\":%u,",
-			       bitwise->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BITWISE_LEN)) {
-		ret = snprintf(buf + offset, len, "\"len\":%u,",
-			       bitwise->len);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BITWISE_MASK)) {
-		ret = snprintf(buf + offset, len, "\"mask\":{");
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-		ret = nft_data_reg_snprintf(buf+offset, len, &bitwise->mask,
-					    NFT_OUTPUT_JSON, 0, DATA_VALUE);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-		ret = snprintf(buf + offset, len, "},");
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	}
-	if (e->flags & (1 << NFT_EXPR_BITWISE_XOR)) {
-		ret = snprintf(buf+offset, len, "\"xor\":{");
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-		ret = nft_data_reg_snprintf(buf+offset, len, &bitwise->xor,
-					    NFT_OUTPUT_JSON, 0, DATA_VALUE);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-		ret = snprintf(buf+offset, len, "},");
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (offset > 0)
-		offset--;
-
-	return offset;
-}
-
-static int nft_rule_expr_bitwise_snprintf_xml(char *buf, size_t size,
-					      struct nft_rule_expr *e)
+static int nft_rule_expr_bitwise_export(char *buf, size_t size,
+					struct nft_rule_expr *e, int type)
 {
 	struct nft_expr_bitwise *bitwise = nft_expr_data(e);
-	int len = size, offset = 0, ret;
-
-	if (e->flags & (1 << NFT_EXPR_BITWISE_SREG)) {
-		ret = snprintf(buf + offset, len, "<sreg>%u</sreg>",
-			       bitwise->sreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BITWISE_DREG)) {
-		ret = snprintf(buf + offset, len, "<dreg>%u</dreg>",
-			       bitwise->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BITWISE_LEN)) {
-		ret = snprintf(buf + offset, len, "<len>%u</len>",
-			       bitwise->len);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BITWISE_MASK)) {
-		ret = snprintf(buf + offset, len, "<mask>");
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	NFT_BUF_INIT(b, buf, size);
 
-		ret = nft_data_reg_snprintf(buf + offset, len, &bitwise->mask,
-					    NFT_OUTPUT_XML, 0, DATA_VALUE);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-		ret = snprintf(buf + offset, len, "</mask>");
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BITWISE_XOR)) {
-		ret = snprintf(buf + offset, len, "<xor>");
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-		ret = nft_data_reg_snprintf(buf + offset, len, &bitwise->xor,
-					    NFT_OUTPUT_XML, 0, DATA_VALUE);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-		ret = snprintf(buf + offset, len, "</xor>");
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
+	if (e->flags & (1 << NFT_EXPR_BITWISE_SREG))
+		nft_buf_u32(&b, type, bitwise->sreg, SREG);
+	if (e->flags & (1 << NFT_EXPR_BITWISE_DREG))
+		nft_buf_u32(&b, type, bitwise->dreg, DREG);
+	if (e->flags & (1 << NFT_EXPR_BITWISE_LEN))
+		nft_buf_u32(&b, type, bitwise->len, LEN);
+	if (e->flags & (1 << NFT_EXPR_BITWISE_MASK))
+		nft_buf_reg(&b, type, &bitwise->mask, DATA_VALUE, MASK);
+	if (e->flags & (1 << NFT_EXPR_BITWISE_XOR))
+		nft_buf_reg(&b, type, &bitwise->xor, DATA_VALUE, XOR);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int nft_rule_expr_bitwise_snprintf_default(char *buf, size_t size,
@@ -378,13 +301,12 @@ static int
 nft_rule_expr_bitwise_snprintf(char *buf, size_t size, uint32_t type,
 			       uint32_t flags, struct nft_rule_expr *e)
 {
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_bitwise_snprintf_default(buf, size, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_bitwise_snprintf_xml(buf, size, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_bitwise_snprintf_json(buf, size, e);
+		return nft_rule_expr_bitwise_export(buf, size, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/byteorder.c b/src/expr/byteorder.c
index ad28bc4..77680d2 100644
--- a/src/expr/byteorder.c
+++ b/src/expr/byteorder.c
@@ -22,6 +22,7 @@
 #include <libnftnl/rule.h>
 #include "data_reg.h"
 #include "expr_ops.h"
+#include <buffer.h>
 
 struct nft_expr_byteorder {
 	enum nft_registers	sreg;
@@ -179,6 +180,14 @@ static char *expr_byteorder_str[] = {
 	[NFT_BYTEORDER_NTOH] = "ntoh",
 };
 
+static const char *bo2str(uint32_t type)
+{
+	if (type > NFT_BYTEORDER_HTON)
+		return "unknown";
+
+	return expr_byteorder_str[type];
+}
+
 static inline int nft_str2ntoh(const char *op)
 {
 	if (strcmp(op, "ntoh") == 0)
@@ -270,77 +279,24 @@ nft_rule_expr_byteorder_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
 #endif
 }
 
-static int nft_rule_expr_byteorder_snprintf_json(char *buf, size_t size,
-						 struct nft_rule_expr *e)
-{
-	struct nft_expr_byteorder *byteorder = nft_expr_data(e);
-	int len = size, offset = 0, ret;
-
-	if (e->flags & (1 << NFT_EXPR_BYTEORDER_SREG)) {
-		ret = snprintf(buf + offset, len, "\"sreg\":%u,",
-			       byteorder->sreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BYTEORDER_DREG)) {
-		ret = snprintf(buf + offset, len, "\"dreg\":%u,",
-			       byteorder->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BYTEORDER_OP)) {
-		ret = snprintf(buf + offset, len, "\"op\":\"%s\",",
-			       expr_byteorder_str[byteorder->op]);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BYTEORDER_LEN)) {
-		ret = snprintf(buf + offset, len, "\"len\":%u,",
-			       byteorder->len);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BYTEORDER_SIZE)) {
-		ret = snprintf(buf + offset, len, "\"size\":%u,",
-			       byteorder->size);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (offset > 0)
-		offset--;
-
-	return offset;
-}
-
-static int nft_rule_expr_byteorder_snprintf_xml(char *buf, size_t size,
-						struct nft_rule_expr *e)
+static int nft_rule_expr_byteorder_export(char *buf, size_t size,
+					  struct nft_rule_expr *e, int type)
 {
 	struct nft_expr_byteorder *byteorder = nft_expr_data(e);
-	int len = size, offset = 0, ret;
-
-	if (e->flags & (1 << NFT_EXPR_BYTEORDER_SREG)) {
-		ret = snprintf(buf + offset, len, "<sreg>%u</sreg>",
-			       byteorder->sreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BYTEORDER_DREG)) {
-		ret = snprintf(buf + offset, len, "<dreg>%u</dreg>",
-			       byteorder->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BYTEORDER_OP)) {
-		ret = snprintf(buf + offset, len, "<op>%s</op>",
-			       expr_byteorder_str[byteorder->op]);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BYTEORDER_LEN)) {
-		ret = snprintf(buf + offset, len, "<len>%u</len>",
-			       byteorder->len);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_BYTEORDER_SIZE)) {
-		ret = snprintf(buf + offset, len, "<size>%u</size>",
-			       byteorder->size);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	return offset;
+	NFT_BUF_INIT(b, buf, size);
+
+	if (e->flags & (1 << NFT_EXPR_BYTEORDER_SREG))
+		nft_buf_u32(&b, type, byteorder->sreg, SREG);
+	if (e->flags & (1 << NFT_EXPR_BYTEORDER_DREG))
+		nft_buf_u32(&b, type, byteorder->dreg, DREG);
+	if (e->flags & (1 << NFT_EXPR_BYTEORDER_OP))
+		nft_buf_str(&b, type, bo2str(byteorder->op), OP);
+	if (e->flags & (1 << NFT_EXPR_BYTEORDER_LEN))
+		nft_buf_u32(&b, type, byteorder->len, LEN);
+	if (e->flags & (1 << NFT_EXPR_BYTEORDER_SIZE))
+		nft_buf_u32(&b, type, byteorder->size, SIZE);
+
+	return nft_buf_done(&b);
 }
 
 static int nft_rule_expr_byteorder_snprintf_default(char *buf, size_t size,
@@ -350,7 +306,7 @@ static int nft_rule_expr_byteorder_snprintf_default(char *buf, size_t size,
 	int len = size, offset = 0, ret;
 
 	ret = snprintf(buf, len, "reg %u = %s(reg %u, %u, %u) ",
-		       byteorder->dreg, expr_byteorder_str[byteorder->op],
+		       byteorder->dreg, bo2str(byteorder->op),
 		       byteorder->sreg, byteorder->size, byteorder->len);
 	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
@@ -361,13 +317,12 @@ static int
 nft_rule_expr_byteorder_snprintf(char *buf, size_t size, uint32_t type,
 				 uint32_t flags, struct nft_rule_expr *e)
 {
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_byteorder_snprintf_default(buf, size, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_byteorder_snprintf_xml(buf, size, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_byteorder_snprintf_json(buf, size, e);
+		return nft_rule_expr_byteorder_export(buf, size, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/cmp.c b/src/expr/cmp.c
index 6ecab7d..b186df0 100644
--- a/src/expr/cmp.c
+++ b/src/expr/cmp.c
@@ -23,6 +23,7 @@
 #include <libnftnl/rule.h>
 #include "expr_ops.h"
 #include "data_reg.h"
+#include <buffer.h>
 
 struct nft_expr_cmp {
 	union nft_data_reg	data;
@@ -150,6 +151,14 @@ static char *expr_cmp_str[] = {
 	[NFT_CMP_GTE]	= "gte",
 };
 
+static const char *cmp2str(uint32_t op)
+{
+	if (op > NFT_CMP_GTE)
+		return "unknown";
+
+	return expr_cmp_str[op];
+}
+
 static inline int nft_str2cmp(const char *op)
 {
 	if (strcmp(op, "eq") == 0)
@@ -238,51 +247,20 @@ static int nft_rule_expr_cmp_xml_parse(struct nft_rule_expr *e, mxml_node_t *tre
 #endif
 }
 
-static int nft_rule_expr_cmp_snprintf_json(char *buf, size_t size,
-					   struct nft_rule_expr *e)
+static int nft_rule_expr_cmp_export(char *buf, size_t size,
+				    struct nft_rule_expr *e, int type)
 {
 	struct nft_expr_cmp *cmp = nft_expr_data(e);
-	int len = size, offset = 0, ret;
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_CMP_SREG)) {
-		ret = snprintf(buf + offset, len, "\"sreg\":%u,", cmp->sreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_CMP_OP)) {
-		ret = snprintf(buf + offset, len, "\"op\":\"%s\",",
-			       expr_cmp_str[cmp->op]);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	ret = nft_data_reg_snprintf(buf + offset, len, &cmp->data,
-				    NFT_OUTPUT_JSON, 0, DATA_VALUE);
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	return offset;
-}
-
-static int nft_rule_expr_cmp_snprintf_xml(char *buf, size_t size,
-					  struct nft_rule_expr *e)
-{
-	struct nft_expr_cmp *cmp = nft_expr_data(e);
-	int len = size, offset = 0, ret;
-
-	if (e->flags & (1 << NFT_EXPR_CMP_SREG)) {
-		ret = snprintf(buf, len, "<sreg>%u</sreg>",
-			       cmp->sreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (e->flags & (1 << NFT_EXPR_CMP_SREG)) {
-		ret = snprintf(buf + offset, len, "<op>%s</op>",
-			       expr_cmp_str[cmp->op]);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	ret = nft_data_reg_snprintf(buf + offset, len, &cmp->data,
-				    NFT_OUTPUT_XML, 0, DATA_VALUE);
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	if (e->flags & (1 << NFT_EXPR_CMP_SREG))
+		nft_buf_u32(&b, type, cmp->sreg, SREG);
+	if (e->flags & (1 << NFT_EXPR_CMP_OP))
+		nft_buf_str(&b, type, cmp2str(cmp->op), OP);
+	if (e->flags & (1 << NFT_EXPR_CMP_DATA))
+		nft_buf_reg(&b, type, &cmp->data, DATA_VALUE, DATA);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int nft_rule_expr_cmp_snprintf_default(char *buf, size_t size,
@@ -306,13 +284,12 @@ static int
 nft_rule_expr_cmp_snprintf(char *buf, size_t size, uint32_t type,
 			   uint32_t flags, struct nft_rule_expr *e)
 {
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_cmp_snprintf_default(buf, size, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_cmp_snprintf_xml(buf, size, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_cmp_snprintf_json(buf, size, e);
+		return nft_rule_expr_cmp_export(buf, size, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/counter.c b/src/expr/counter.c
index 82d1939..e9abc5b 100644
--- a/src/expr/counter.c
+++ b/src/expr/counter.c
@@ -22,6 +22,7 @@
 #include <libnftnl/expr.h>
 #include <libnftnl/rule.h>
 #include "expr_ops.h"
+#include <buffer.h>
 
 struct nft_expr_counter {
 	uint64_t	pkts;
@@ -159,45 +160,19 @@ nft_rule_expr_counter_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
 	return -1;
 #endif
 }
-static int nft_rule_expr_counter_snprintf_json(char *buf, size_t len,
-					       struct nft_rule_expr *e)
-{
-	int ret, size = len, offset = 0;
-	struct nft_expr_counter *ctr = nft_expr_data(e);
 
-	if (e->flags & (1 << NFT_EXPR_CTR_PACKETS)) {
-		ret = snprintf(buf, len,"\"pkts\":%"PRIu64",", ctr->pkts);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_CTR_BYTES)) {
-		ret = snprintf(buf + offset, len, "\"bytes\":%"PRIu64",", ctr->bytes);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	/* Remove the last comma characther */
-	if (offset > 0)
-		offset--;
-
-	return offset;
-}
-
-static int nft_rule_expr_counter_snprintf_xml(char *buf, size_t len,
-					      struct nft_rule_expr *e)
+static int nft_rule_expr_counter_export(char *buf, size_t size,
+					struct nft_rule_expr *e, int type)
 {
-	int ret, size = len, offset = 0;
 	struct nft_expr_counter *ctr = nft_expr_data(e);
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_CTR_PACKETS)) {
-		ret = snprintf(buf, len, "<pkts>%"PRIu64"</pkts>", ctr->pkts);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_CTR_BYTES)) {
-		ret = snprintf(buf + offset, len, "<bytes>%"PRIu64"</bytes>",
-			       ctr->bytes);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
+	if (e->flags & (1 << NFT_EXPR_CTR_PACKETS))
+		nft_buf_u64(&b, type, ctr->pkts, PKTS);
+	if (e->flags & (1 << NFT_EXPR_CTR_BYTES))
+		nft_buf_u64(&b, type, ctr->bytes, BYTES);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int nft_rule_expr_counter_snprintf_default(char *buf, size_t len,
@@ -213,13 +188,12 @@ static int nft_rule_expr_counter_snprintf(char *buf, size_t len, uint32_t type,
 					  uint32_t flags,
 					  struct nft_rule_expr *e)
 {
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_counter_snprintf_default(buf, len, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_counter_snprintf_xml(buf, len, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_counter_snprintf_json(buf, len, e);
+		return nft_rule_expr_counter_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/ct.c b/src/expr/ct.c
index d443c1e..12d96d5 100644
--- a/src/expr/ct.c
+++ b/src/expr/ct.c
@@ -21,6 +21,7 @@
 #include <libnftnl/expr.h>
 #include <libnftnl/rule.h>
 #include "expr_ops.h"
+#include <buffer.h>
 
 struct nft_expr_ct {
 	enum nft_ct_keys        key;
@@ -310,66 +311,21 @@ err:
 }
 
 static int
-nft_expr_ct_snprintf_json(char *buf, size_t size, struct nft_rule_expr *e)
+nft_expr_ct_export(char *buf, size_t size, struct nft_rule_expr *e, int type)
 {
-	int ret, len = size, offset = 0;
-	struct nft_expr_ct *ct = nft_expr_data(e);
-
-	if (e->flags & (1 << NFT_EXPR_CT_DREG)) {
-		ret = snprintf(buf+offset, len, "\"dreg\":%u,", ct->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (e->flags & (1 << NFT_EXPR_CT_SREG)) {
-		ret = snprintf(buf+offset, len, "\"sreg:\":%u,", ct->sreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (e->flags & (1 << NFT_EXPR_CT_KEY)) {
-		ret = snprintf(buf+offset, len, "\"key\":\"%s\",",
-						ctkey2str(ct->key));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (nft_rule_expr_is_set(e, NFT_EXPR_CT_DIR)) {
-		ret = snprintf(buf+offset, len, "\"dir\":\"%s\",",
-			       ctdir2str(ct->dir));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	/* Remove the last separator characther  */
-	if (offset > 0)
-		offset--;
-
-	return offset;
-}
-
-static int
-nft_expr_ct_snprintf_xml(char *buf, size_t size, struct nft_rule_expr *e)
-{
-	int ret, len = size, offset = 0;
 	struct nft_expr_ct *ct = nft_expr_data(e);
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_CT_DREG)) {
-		ret = snprintf(buf + offset, len, "<dreg>%u</dreg>", ct->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_CT_SREG)) {
-		ret = snprintf(buf + offset, len, "<sreg>%u</sreg>", ct->sreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_CT_KEY)) {
-		ret = snprintf(buf + offset, len, "<key>%s</key>",
-			       ctkey2str(ct->key));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (nft_rule_expr_is_set(e, NFT_EXPR_CT_DIR)) {
-		ret = snprintf(buf + offset, len, "<dir>%s</dir>",
-			       ctdir2str(ct->dir));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
+	if (e->flags & (1 << NFT_EXPR_CT_SREG))
+		nft_buf_u32(&b, type, ct->sreg, SREG);
+	if (e->flags & (1 << NFT_EXPR_CT_DREG))
+		nft_buf_u32(&b, type, ct->dreg, DREG);
+	if (e->flags & (1 << NFT_EXPR_CT_KEY))
+		nft_buf_str(&b, type, ctkey2str(ct->key), KEY);
+	if (e->flags & (1 << NFT_EXPR_CT_DIR))
+		nft_buf_str(&b, type, ctdir2str(ct->dir), DIR);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int
@@ -403,13 +359,12 @@ static int
 nft_rule_expr_ct_snprintf(char *buf, size_t len, uint32_t type,
 			    uint32_t flags, struct nft_rule_expr *e)
 {
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		return nft_expr_ct_snprintf_default(buf, len, e);
 	case NFT_OUTPUT_XML:
-		return nft_expr_ct_snprintf_xml(buf, len, e);
 	case NFT_OUTPUT_JSON:
-		return nft_expr_ct_snprintf_json(buf, len, e);
+		return nft_expr_ct_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/exthdr.c b/src/expr/exthdr.c
index 369727c..2135148 100644
--- a/src/expr/exthdr.c
+++ b/src/expr/exthdr.c
@@ -25,6 +25,7 @@
 #include <libnftnl/rule.h>
 
 #include "expr_ops.h"
+#include <buffer.h>
 
 #ifndef IPPROTO_MH
 #define IPPROTO_MH 135
@@ -154,7 +155,7 @@ nft_rule_expr_exthdr_parse(struct nft_rule_expr *e, struct nlattr *attr)
 	return 0;
 }
 
-static const char *exthdr_type2str(uint32_t type)
+static const char *type2str(uint32_t type)
 {
 	switch (type) {
 	case IPPROTO_HOPOPTS:
@@ -262,65 +263,22 @@ nft_rule_expr_exthdr_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
 #endif
 }
 
-static int nft_rule_expr_exthdr_snprintf_json(char *buf, size_t len,
-					      struct nft_rule_expr *e)
+static int nft_rule_expr_exthdr_export(char *buf, size_t len,
+				       struct nft_rule_expr *e, int type)
 {
 	struct nft_expr_exthdr *exthdr = nft_expr_data(e);
-	int ret, size = len, offset = 0;
+	NFT_BUF_INIT(b, buf, len);
 
-	if (e->flags & (1 << NFT_EXPR_EXTHDR_DREG)) {
-		ret = snprintf(buf, len, "\"dreg\":%u,", exthdr->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_EXTHDR_TYPE)) {
-		ret = snprintf(buf + offset, len, "\"exthdr_type\":\"%s\",",
-			       exthdr_type2str(exthdr->type));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_EXTHDR_OFFSET)) {
-		ret = snprintf(buf + offset, len, "\"offset\":%u,",
-			       exthdr->offset);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_EXTHDR_LEN)) {
-		ret = snprintf(buf + offset, len, "\"len\":%u,",
-			       exthdr->len);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	/* Remove the last comma characther */
-	if (offset > 0)
-		offset--;
-
-	return offset;
-}
-
-static int nft_rule_expr_exthdr_snprintf_xml(char *buf, size_t len,
-					     struct nft_rule_expr *e)
-{
-	struct nft_expr_exthdr *exthdr = nft_expr_data(e);
-	int ret, size = len, offset = 0;
-
-	if (e->flags & (1 << NFT_EXPR_EXTHDR_DREG)) {
-		ret = snprintf(buf, len, "<dreg>%u</dreg>", exthdr->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_EXTHDR_TYPE)) {
-		ret = snprintf(buf + offset, len,
-			       "<exthdr_type>%s</exthdr_type>",
-			       exthdr_type2str(exthdr->type));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_EXTHDR_OFFSET)) {
-		ret = snprintf(buf + offset, len, "<offset>%u</offset>",
-			       exthdr->offset);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_EXTHDR_LEN)) {
-		ret = snprintf(buf + offset, len, "<len>%u</len>", exthdr->len);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
+	if (e->flags & (1 << NFT_EXPR_EXTHDR_DREG))
+		nft_buf_u32(&b, type, exthdr->dreg, DREG);
+	if (e->flags & (1 << NFT_EXPR_EXTHDR_TYPE))
+		nft_buf_str(&b, type, type2str(exthdr->type), EXTHDR_TYPE);
+	if (e->flags & (1 << NFT_EXPR_EXTHDR_OFFSET))
+		nft_buf_u32(&b, type, exthdr->offset, OFFSET);
+	if (e->flags & (1 << NFT_EXPR_EXTHDR_LEN))
+		nft_buf_u32(&b, type, exthdr->len, LEN);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int nft_rule_expr_exthdr_snprintf_default(char *buf, size_t len,
@@ -337,13 +295,12 @@ static int
 nft_rule_expr_exthdr_snprintf(char *buf, size_t len, uint32_t type,
 			       uint32_t flags, struct nft_rule_expr *e)
 {
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_exthdr_snprintf_default(buf, len, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_exthdr_snprintf_xml(buf, len, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_exthdr_snprintf_json(buf, len, e);
+		return nft_rule_expr_exthdr_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/immediate.c b/src/expr/immediate.c
index 5f54129..be70445 100644
--- a/src/expr/immediate.c
+++ b/src/expr/immediate.c
@@ -21,6 +21,7 @@
 #include <libnftnl/rule.h>
 #include "expr_ops.h"
 #include "data_reg.h"
+#include <buffer.h>
 
 struct nft_expr_immediate {
 	union nft_data_reg	data;
@@ -248,63 +249,22 @@ nft_rule_expr_immediate_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
 }
 
 static int
-nft_rule_expr_immediate_snprintf_json(char *buf, size_t len,
-				     struct nft_rule_expr *e, uint32_t flags)
+nft_rule_expr_immediate_export(char *buf, size_t size, struct nft_rule_expr *e,
+			       int type)
 {
-	int size = len, offset = 0, ret;
 	struct nft_expr_immediate *imm = nft_expr_data(e);
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_IMM_DREG)) {
-		ret = snprintf(buf, len, "\"dreg\":%u,", imm->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_IMM_DATA)) {
-		ret = nft_data_reg_snprintf(buf + offset, len, &imm->data,
-					    NFT_OUTPUT_JSON, flags, DATA_VALUE);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	} else if (e->flags & (1 << NFT_EXPR_IMM_VERDICT)) {
-		ret = nft_data_reg_snprintf(buf + offset, len, &imm->data,
-					  NFT_OUTPUT_JSON, flags, DATA_VERDICT);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	} else if (e->flags & (1 << NFT_EXPR_IMM_CHAIN)) {
-		ret = nft_data_reg_snprintf(buf + offset, len, &imm->data,
-					    NFT_OUTPUT_JSON, flags, DATA_CHAIN);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	return offset;
-}
-
-static int
-nft_rule_expr_immediate_snprintf_xml(char *buf, size_t len,
-				     struct nft_rule_expr *e, uint32_t flags)
-{
-	int size = len, offset = 0, ret;
-	struct nft_expr_immediate *imm = nft_expr_data(e);
-
-	if (e->flags & (1 << NFT_EXPR_IMM_DREG)) {
-		ret = snprintf(buf, len, "<dreg>%u</dreg>", imm->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_IMM_DATA)) {
-		ret = nft_data_reg_snprintf(buf + offset, len, &imm->data,
-					    NFT_OUTPUT_XML, flags, DATA_VALUE);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	} else if (e->flags & (1 << NFT_EXPR_IMM_VERDICT)) {
-		ret = nft_data_reg_snprintf(buf + offset, len, &imm->data,
-					  NFT_OUTPUT_XML, flags, DATA_VERDICT);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	} else if (e->flags & (1 << NFT_EXPR_IMM_CHAIN)) {
-		ret = nft_data_reg_snprintf(buf + offset, len, &imm->data,
-					    NFT_OUTPUT_XML, flags, DATA_CHAIN);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	return offset;
+	if (e->flags & (1 << NFT_EXPR_IMM_DREG))
+		nft_buf_u32(&b, type, imm->dreg, DREG);
+	if (e->flags & (1 << NFT_EXPR_IMM_DATA))
+		nft_buf_reg(&b, type, &imm->data, DATA_VALUE, DATA);
+	if (e->flags & (1 << NFT_EXPR_IMM_VERDICT))
+		nft_buf_reg(&b, type, &imm->data, DATA_VERDICT, DATA);
+	if (e->flags & (1 << NFT_EXPR_IMM_CHAIN))
+		nft_buf_reg(&b, type, &imm->data, DATA_CHAIN, DATA);
+
+	return nft_buf_done(&b);
 }
 
 static int
@@ -344,9 +304,8 @@ nft_rule_expr_immediate_snprintf(char *buf, size_t len, uint32_t type,
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_immediate_snprintf_default(buf, len, e, flags);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_immediate_snprintf_xml(buf, len, e, flags);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_immediate_snprintf_json(buf, len, e, flags);
+		return nft_rule_expr_immediate_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/limit.c b/src/expr/limit.c
index 68cfa37..375e6e0 100644
--- a/src/expr/limit.c
+++ b/src/expr/limit.c
@@ -22,6 +22,7 @@
 #include <libnftnl/expr.h>
 #include <libnftnl/rule.h>
 #include "expr_ops.h"
+#include <buffer.h>
 
 struct nft_expr_limit {
 	uint64_t		rate;
@@ -169,48 +170,18 @@ static const char *get_unit(uint64_t u)
 	return "error";
 }
 
-static int nft_rule_expr_limit_snprintf_xml(char *buf, size_t len,
-					    struct nft_rule_expr *e)
+static int nft_rule_expr_limit_export(char *buf, size_t size,
+				      struct nft_rule_expr *e, int type)
 {
 	struct nft_expr_limit *limit = nft_expr_data(e);
-	int ret, size = len, offset = 0;
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_LIMIT_RATE)) {
-		ret = snprintf(buf + offset, len, "<rate>%"PRIu64"</rate>",
-			       limit->rate);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LIMIT_UNIT)) {
-		ret = snprintf(buf + offset, len, "<unit>%"PRIu64"</unit>",
-			       limit->unit);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	return offset;
-}
-
-static int nft_rule_expr_limit_snprintf_json(char *buf, size_t len,
-					    struct nft_rule_expr *e)
-{
-	struct nft_expr_limit *limit = nft_expr_data(e);
-	int ret, size = len, offset = 0;
-
-	if (e->flags & (1 << NFT_EXPR_LIMIT_RATE)) {
-		ret = snprintf(buf + offset, len, "\"rate\":%"PRIu64",",
-			       limit->rate);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LIMIT_UNIT)) {
-		ret = snprintf(buf + offset, len, "\"unit\":%"PRIu64",",
-			       limit->unit);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	/* Remove the last comma characther */
-	if (offset > 0)
-		offset--;
+	if (e->flags & (1 << NFT_EXPR_LIMIT_RATE))
+		nft_buf_u64(&b, type, limit->rate, RATE);
+	if (e->flags & (1 << NFT_EXPR_LIMIT_UNIT))
+		nft_buf_u64(&b, type, limit->unit, UNIT);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int nft_rule_expr_limit_snprintf_default(char *buf, size_t len,
@@ -231,9 +202,8 @@ nft_rule_expr_limit_snprintf(char *buf, size_t len, uint32_t type,
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_limit_snprintf_default(buf, len, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_limit_snprintf_xml(buf, len, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_limit_snprintf_json(buf, len, e);
+		return nft_rule_expr_limit_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/log.c b/src/expr/log.c
index 98481c9..0a324c4 100644
--- a/src/expr/log.c
+++ b/src/expr/log.c
@@ -21,6 +21,7 @@
 #include <libnftnl/expr.h>
 #include <libnftnl/rule.h>
 #include "expr_ops.h"
+#include <buffer.h>
 
 struct nft_expr_log {
 	uint32_t		snaplen;
@@ -288,90 +289,28 @@ static int nft_rule_expr_log_snprintf_default(char *buf, size_t size,
 	return offset;
 }
 
-static int nft_rule_expr_log_snprintf_xml(char *buf, size_t size,
-					  struct nft_rule_expr *e)
+static int nft_rule_expr_log_export(char *buf, size_t size,
+				    struct nft_rule_expr *e, int type)
 {
-	int ret, len = size, offset = 0;
 	struct nft_expr_log *log = nft_expr_data(e);
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_LOG_PREFIX)) {
-		ret = snprintf(buf + offset, len, "<prefix>%s</prefix>",
-			       log->prefix);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOG_GROUP)) {
-		ret = snprintf(buf + offset, len, "<group>%u</group>",
-			       log->group);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOG_SNAPLEN)) {
-		ret = snprintf(buf + offset, len, "<snaplen>%u</snaplen>",
-			       log->snaplen);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOG_QTHRESHOLD)) {
-		ret = snprintf(buf + offset, len, "<qthreshold>%u</qthreshold>",
-			       log->qthreshold);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOG_LEVEL)) {
-		ret = snprintf(buf + offset, len, "<level>%u</level>",
-			       log->level);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOG_FLAGS)) {
-		ret = snprintf(buf + offset, len, "<flags>%u</flags>",
-			       log->flags);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	return offset;
-}
-
-static int nft_rule_expr_log_snprintf_json(char *buf, size_t len,
-					   struct nft_rule_expr *e)
-{
-	int ret, size = len, offset = 0;
-	struct nft_expr_log *log = nft_expr_data(e);
-
-	if (e->flags & (1 << NFT_EXPR_LOG_PREFIX)) {
-		ret = snprintf(buf + offset, len, "\"prefix\":\"%s\",",
-			       log->prefix);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOG_GROUP)) {
-		ret = snprintf(buf + offset, len, "\"group\":%u,",
-			       log->group);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOG_SNAPLEN)) {
-		ret = snprintf(buf + offset, len, "\"snaplen\":%u,",
-			       log->snaplen);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOG_QTHRESHOLD)) {
-		ret = snprintf(buf + offset, len, "\"qthreshold\":%u,",
-			       log->qthreshold);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOG_LEVEL)) {
-		ret = snprintf(buf + offset, len, "\"level\":%u,",
-			       log->level);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOG_FLAGS)) {
-		ret = snprintf(buf + offset, len, "\"flags\":%u,",
-			       log->flags);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	/* Remove the last comma characther */
-	if (offset > 0)
-		offset--;
+	if (e->flags & (1 << NFT_EXPR_LOG_PREFIX))
+		nft_buf_str(&b, type, log->prefix, PREFIX);
+	if (e->flags & (1 << NFT_EXPR_LOG_GROUP))
+		nft_buf_u32(&b, type, log->group, GROUP);
+	if (e->flags & (1 << NFT_EXPR_LOG_SNAPLEN))
+		nft_buf_u32(&b, type, log->snaplen, SNAPLEN);
+	if (e->flags & (1 << NFT_EXPR_LOG_QTHRESHOLD))
+		nft_buf_u32(&b, type, log->qthreshold, QTHRESH);
+	if (e->flags & (1 << NFT_EXPR_LOG_LEVEL))
+		nft_buf_u32(&b, type, log->level, LEVEL);
+	if (e->flags & (1 << NFT_EXPR_LOG_FLAGS))
+		nft_buf_u32(&b, type, log->level, FLAGS);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
-
 static int
 nft_rule_expr_log_snprintf(char *buf, size_t len, uint32_t type,
 			    uint32_t flags, struct nft_rule_expr *e)
@@ -380,9 +319,8 @@ nft_rule_expr_log_snprintf(char *buf, size_t len, uint32_t type,
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_log_snprintf_default(buf, len, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_log_snprintf_xml(buf, len, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_log_snprintf_json(buf, len, e);
+		return nft_rule_expr_log_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/lookup.c b/src/expr/lookup.c
index 625bc58..29daa30 100644
--- a/src/expr/lookup.c
+++ b/src/expr/lookup.c
@@ -22,6 +22,7 @@
 #include <libnftnl/expr.h>
 #include "data_reg.h"
 #include "expr_ops.h"
+#include <buffer.h>
 
 #ifndef IFNAMSIZ
 #define IFNAMSIZ	16
@@ -208,52 +209,20 @@ nft_rule_expr_lookup_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
 }
 
 static int
-nft_rule_expr_lookup_snprintf_json(char *buf, size_t size,
-				   struct nft_rule_expr *e)
+nft_rule_expr_lookup_export(char *buf, size_t size,
+			    struct nft_rule_expr *e, int type)
 {
-	int len = size, offset = 0, ret;
-	struct nft_expr_lookup *l = nft_expr_data(e);
-
-	if (e->flags & (1 << NFT_EXPR_LOOKUP_SET)) {
-		ret = snprintf(buf, len, "\"set\":\"%s\",", l->set_name);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOOKUP_SREG)) {
-		ret = snprintf(buf + offset, len, "\"sreg\":%u,", l->sreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOOKUP_DREG)) {
-		ret = snprintf(buf + offset, len, "\"dreg\":%u,", l->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	/* Remove the last comma characther */
-	if (offset > 0)
-		offset--;
-
-	return offset;
-}
-
-static int
-nft_rule_expr_lookup_snprintf_xml(char *buf, size_t size,
-				  struct nft_rule_expr *e)
-{
-	int len = size, offset = 0, ret;
 	struct nft_expr_lookup *l = nft_expr_data(e);
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_LOOKUP_SET)) {
-		ret = snprintf(buf, len, "<set>%s</set>", l->set_name);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOOKUP_SREG)) {
-		ret = snprintf(buf + offset, len, "<sreg>%u</sreg>", l->sreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_LOOKUP_DREG)) {
-		ret = snprintf(buf + offset, len, "<dreg>%u</dreg>", l->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
+	if (e->flags & (1 << NFT_EXPR_LOOKUP_SET))
+		nft_buf_str(&b, type, l->set_name, SET);
+	if (e->flags & (1 << NFT_EXPR_LOOKUP_SREG))
+		nft_buf_u32(&b, type, l->sreg, SREG);
+	if (e->flags & (1 << NFT_EXPR_LOOKUP_DREG))
+		nft_buf_u32(&b, type, l->dreg, DREG);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int
@@ -284,9 +253,8 @@ nft_rule_expr_lookup_snprintf(char *buf, size_t size, uint32_t type,
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_lookup_snprintf_default(buf, size, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_lookup_snprintf_xml(buf, size, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_lookup_snprintf_json(buf, size, e);
+		return nft_rule_expr_lookup_export(buf, size, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/masq.c b/src/expr/masq.c
index b39a43a..869fd45 100644
--- a/src/expr/masq.c
+++ b/src/expr/masq.c
@@ -20,6 +20,7 @@
 #include <libnftnl/expr.h>
 #include <libnftnl/rule.h>
 #include "expr_ops.h"
+#include <buffer.h>
 
 struct nft_expr_masq {
 	uint32_t	flags;
@@ -135,33 +136,16 @@ nft_rule_expr_masq_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
 	return -1;
 #endif
 }
-static int nft_rule_expr_masq_snprintf_json(char *buf, size_t len,
-					    struct nft_rule_expr *e)
+static int nft_rule_expr_masq_export(char *buf, size_t size,
+				     struct nft_rule_expr *e, int type)
 {
-	int ret, size = len, offset = 0;
 	struct nft_expr_masq *masq = nft_expr_data(e);
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_MASQ_FLAGS)) {
-		ret = snprintf(buf + offset, len, "\"flags\":%u", masq->flags);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	return offset;
-}
-
-static int nft_rule_expr_masq_snprintf_xml(char *buf, size_t len,
-					   struct nft_rule_expr *e)
-{
-	int ret, size = len, offset = 0;
-	struct nft_expr_masq *masq = nft_expr_data(e);
-
-	if (e->flags & (1 << NFT_EXPR_MASQ_FLAGS)) {
-		ret = snprintf(buf + offset, len, "<flags>%u</flags>",
-			       masq->flags);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
+	if (e->flags & (1 << NFT_EXPR_MASQ_FLAGS))
+		nft_buf_u32(&b, type, masq->flags, FLAGS);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int nft_rule_expr_masq_snprintf_default(char *buf, size_t len,
@@ -182,9 +166,8 @@ static int nft_rule_expr_masq_snprintf(char *buf, size_t len, uint32_t type,
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_masq_snprintf_default(buf, len, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_masq_snprintf_xml(buf, len, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_masq_snprintf_json(buf, len, e);
+		return nft_rule_expr_masq_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/match.c b/src/expr/match.c
index dc66585..26a368f 100644
--- a/src/expr/match.c
+++ b/src/expr/match.c
@@ -25,6 +25,7 @@
 #include <libnftnl/rule.h>
 
 #include "expr_ops.h"
+#include <buffer.h>
 
 /* From include/linux/netfilter/x_tables.h */
 #define XT_EXTENSION_MAXNAMELEN 29
@@ -204,33 +205,16 @@ static int nft_rule_expr_match_xml_parse(struct nft_rule_expr *e, mxml_node_t *t
 #endif
 }
 
-static int nft_rule_expr_match_snprintf_json(char *buf, size_t len,
-					     struct nft_rule_expr *e)
+static int nft_rule_expr_match_export(char *buf, size_t size,
+				      struct nft_rule_expr *e, int type)
 {
 	struct nft_expr_match *mt = nft_expr_data(e);
-	int ret, size = len, offset = 0;
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_MT_NAME)) {
-		ret = snprintf(buf, len, "\"name\":\"%s\"", mt->name);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	return offset;
-}
-
-static int nft_rule_expr_match_snprintf_xml(char *buf, size_t len,
-					    struct nft_rule_expr *e)
-{
-	struct nft_expr_match *mt = nft_expr_data(e);
-	int ret, size=len;
-	int offset = 0;
-
-	if (e->flags & (1 << NFT_EXPR_MT_NAME)) {
-		ret = snprintf(buf, len, "<name>%s</name>", mt->name);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
+	if (e->flags & (1 << NFT_EXPR_MT_NAME))
+		nft_buf_str(&b, type, mt->name, NAME);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int
@@ -239,14 +223,13 @@ nft_rule_expr_match_snprintf(char *buf, size_t len, uint32_t type,
 {
 	struct nft_expr_match *match = nft_expr_data(e);
 
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		return snprintf(buf, len, "name %s rev %u ",
 				match->name, match->rev);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_match_snprintf_xml(buf, len, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_match_snprintf_json(buf, len, e);
+		return nft_rule_expr_match_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/meta.c b/src/expr/meta.c
index 5b5159f..51e9924 100644
--- a/src/expr/meta.c
+++ b/src/expr/meta.c
@@ -21,6 +21,7 @@
 #include <libnftnl/expr.h>
 #include <libnftnl/rule.h>
 #include "expr_ops.h"
+#include <buffer.h>
 
 #ifndef NFT_META_MAX
 #define NFT_META_MAX (NFT_META_OIFGROUP + 1)
@@ -263,71 +264,32 @@ nft_rule_expr_meta_snprintf_default(char *buf, size_t len,
 	return 0;
 }
 
-static int
-nft_rule_expr_meta_snprintf_xml(char *buf, size_t size,
-				struct nft_rule_expr *e)
-{
-	int ret, len = size, offset = 0;
-	struct nft_expr_meta *meta = nft_expr_data(e);
-
-	if (e->flags & (1 << NFT_EXPR_META_DREG)) {
-		ret = snprintf(buf, len, "<dreg>%u</dreg>", meta->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_META_KEY)) {
-		ret = snprintf(buf + offset, len, "<key>%s</key>",
-			       meta_key2str(meta->key));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_META_SREG)) {
-		ret = snprintf(buf + offset, len, "<sreg>%u</sreg>",
-			       meta->sreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	return offset;
-}
-
-static int
-nft_rule_expr_meta_snprintf_json(char *buf, size_t size,
-				 struct nft_rule_expr *e)
+static int nft_rule_expr_meta_export(char *buf, size_t size,
+				     struct nft_rule_expr *e, int type)
 {
-	int ret, len = size, offset = 0;
 	struct nft_expr_meta *meta = nft_expr_data(e);
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_META_DREG)) {
-		ret = snprintf(buf + offset, len, "\"dreg\":%u,",
-			       meta->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_META_KEY)) {
-		ret = snprintf(buf + offset, len, "\"key\":\"%s\",",
-			       meta_key2str(meta->key));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_META_SREG)) {
-		ret = snprintf(buf + offset, len, "\"sreg\":%u,",
-			       meta->sreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	/* Remove the last comma separator */
-	if (offset > 0)
-		offset--;
+	if (e->flags & (1 << NFT_EXPR_META_DREG))
+		nft_buf_u32(&b, type, meta->dreg, DREG);
+	if (e->flags & (1 << NFT_EXPR_META_KEY))
+		nft_buf_str(&b, type, meta_key2str(meta->key), KEY);
+	if (e->flags & (1 << NFT_EXPR_META_SREG))
+		nft_buf_u32(&b, type, meta->sreg, SREG);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int
 nft_rule_expr_meta_snprintf(char *buf, size_t len, uint32_t type,
 			    uint32_t flags, struct nft_rule_expr *e)
 {
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_meta_snprintf_default(buf, len, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_meta_snprintf_xml(buf, len, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_meta_snprintf_json(buf, len, e);
+		return nft_rule_expr_meta_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/nat.c b/src/expr/nat.c
index 60623a6..c9e05af 100644
--- a/src/expr/nat.c
+++ b/src/expr/nat.c
@@ -1,4 +1,5 @@
 /*
+ * (C) 2012-2014 Pablo Neira Ayuso <pablo@netfilter.org>
  * (C) 2012 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
@@ -23,6 +24,7 @@
 #include <libnftnl/expr.h>
 #include <libnftnl/rule.h>
 #include "expr_ops.h"
+#include <buffer.h>
 
 struct nft_expr_nat {
 	enum nft_registers sreg_addr_min;
@@ -196,7 +198,7 @@ nft_rule_expr_nat_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
 		mnl_attr_put_u32(nlh, NFTA_NAT_FLAGS, htonl(nat->flags));
 }
 
-static inline const char *nft_nat2str(uint16_t nat)
+static inline const char *nat2str(uint16_t nat)
 {
 	switch (nat) {
 	case NFT_NAT_SNAT:
@@ -329,85 +331,28 @@ static int nft_rule_expr_nat_xml_parse(struct nft_rule_expr *e, mxml_node_t *tre
 #endif
 }
 
-static int
-nft_rule_expr_nat_snprintf_json(char *buf, size_t size,
-				struct nft_rule_expr *e)
+static int nft_rule_expr_nat_export(char *buf, size_t size,
+				    struct nft_rule_expr *e, int type)
 {
 	struct nft_expr_nat *nat = nft_expr_data(e);
-	int len = size, offset = 0, ret = 0;
-
-	ret = snprintf(buf, len, "\"nat_type\":\"%s\",",
-		       nft_nat2str(nat->type));
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	ret = snprintf(buf+offset, len, "\"family\":\"%s\",",
-		       nft_family2str(nat->family));
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	if (e->flags & (1 << NFT_EXPR_NAT_REG_ADDR_MIN)) {
-		ret = snprintf(buf+offset, len, "\"sreg_addr_min\":%u,"
-						"\"sreg_addr_max\":%u,",
-			       nat->sreg_addr_min, nat->sreg_addr_max);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (e->flags & (1 << NFT_EXPR_NAT_REG_PROTO_MIN)) {
-		ret = snprintf(buf+offset, len, "\"sreg_proto_min\":%u,"
-						"\"sreg_proto_max\":%u,",
-		       nat->sreg_proto_min, nat->sreg_proto_max);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (e->flags & (1 << NFT_EXPR_NAT_FLAGS)) {
-		ret = snprintf(buf+offset, len, "\"flags\":%u,", nat->flags);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	/* Remove the last comma separator */
-	if (offset > 0)
-		offset--;
-
-	return offset;
-}
+	NFT_BUF_INIT(b, buf, size);
 
+	if (e->flags & (1 << NFT_EXPR_NAT_TYPE))
+		nft_buf_str(&b, type, nat2str(nat->type), NAT_TYPE);
+	if (e->flags & (1 << NFT_EXPR_NAT_FAMILY))
+		nft_buf_str(&b, type, nft_family2str(nat->family), FAMILY);
+	if (e->flags & (1 << NFT_EXPR_NAT_REG_ADDR_MIN))
+		nft_buf_u32(&b, type, nat->sreg_addr_min, SREG_ADDR_MIN);
+	if (e->flags & (1 << NFT_EXPR_NAT_REG_ADDR_MAX))
+		nft_buf_u32(&b, type, nat->sreg_addr_max, SREG_ADDR_MAX);
+	if (e->flags & (1 << NFT_EXPR_NAT_REG_PROTO_MIN))
+		nft_buf_u32(&b, type, nat->sreg_proto_min, SREG_PROTO_MIN);
+	if (e->flags & (1 << NFT_EXPR_NAT_REG_PROTO_MAX))
+		nft_buf_u32(&b, type, nat->sreg_proto_max, SREG_PROTO_MAX);
+	if (e->flags & (1 << NFT_EXPR_NAT_FLAGS))
+		nft_buf_u32(&b, type, nat->flags, FLAGS);
 
-static int
-nft_rule_expr_nat_snprintf_xml(char *buf, size_t size,
-				struct nft_rule_expr *e)
-{
-	struct nft_expr_nat *nat = nft_expr_data(e);
-	int len = size, offset = 0, ret = 0;
-
-	ret = snprintf(buf, len, "<type>%s</type>", nft_nat2str(nat->type));
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	ret = snprintf(buf+offset, len, "<family>%s</family>",
-		       nft_family2str(nat->family));
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	if (e->flags & (1 << NFT_EXPR_NAT_REG_ADDR_MIN)) {
-		ret = snprintf(buf+offset, len,
-				"<sreg_addr_min>%u</sreg_addr_min>"
-				"<sreg_addr_max>%u</sreg_addr_max>",
-			       nat->sreg_addr_min, nat->sreg_addr_max);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (e->flags & (1 << NFT_EXPR_NAT_REG_PROTO_MIN)) {
-		ret = snprintf(buf+offset, len,
-				"<sreg_proto_min>%u</sreg_proto_min>"
-				"<sreg_proto_max>%u</sreg_proto_max>",
-		       nat->sreg_proto_min, nat->sreg_proto_max);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (e->flags & (1 << NFT_EXPR_NAT_FLAGS)) {
-		ret = snprintf(buf+offset, len, "<flags>%u</flags>",
-			       nat->flags);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int
@@ -417,7 +362,7 @@ nft_rule_expr_nat_snprintf_default(char *buf, size_t size,
 	struct nft_expr_nat *nat = nft_expr_data(e);
 	int len = size, offset = 0, ret = 0;
 
-	ret = snprintf(buf, len, "%s ", nft_nat2str(nat->type));
+	ret = snprintf(buf, len, "%s ", nat2str(nat->type));
 	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
 	ret = snprintf(buf+offset, len, "%s ", nft_family2str(nat->family));
@@ -453,9 +398,8 @@ nft_rule_expr_nat_snprintf(char *buf, size_t size, uint32_t type,
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_nat_snprintf_default(buf, size, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_nat_snprintf_xml(buf, size, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_nat_snprintf_json(buf, size, e);
+		return nft_rule_expr_nat_export(buf, size, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/payload.c b/src/expr/payload.c
index 717cdac..1aa20bd 100644
--- a/src/expr/payload.c
+++ b/src/expr/payload.c
@@ -25,6 +25,7 @@
 #include <libnftnl/rule.h>
 
 #include "expr_ops.h"
+#include <buffer.h>
 
 struct nft_expr_payload {
 	enum nft_registers	dreg;
@@ -161,34 +162,6 @@ static const char *base2str(enum nft_payload_bases base)
 	return base2str_array[base];
 }
 
-static int
-nft_rule_expr_payload_snprintf_json(char *buf, size_t len, uint32_t flags,
-				   struct nft_rule_expr *e)
-{
-	struct nft_expr_payload *payload = nft_expr_data(e);
-	int size = len, offset = 0, ret;
-
-	if (e->flags & (1 << NFT_EXPR_PAYLOAD_DREG)) {
-		ret = snprintf(buf, len, "\"dreg\":%u,", payload->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_PAYLOAD_OFFSET)) {
-		ret = snprintf(buf + offset, len, "\"offset\":%u,",
-			       payload->offset);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_PAYLOAD_LEN)) {
-		ret = snprintf(buf + offset, len, "\"len\":%u,", payload->len);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_PAYLOAD_BASE)) {
-		ret = snprintf(buf + offset, len, "\"base\":\"%s\"",
-			       base2str(payload->base));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	return offset;
-}
-
 static inline int nft_str2base(const char *base)
 {
 	if (strcmp(base, "link") == 0)
@@ -277,33 +250,22 @@ nft_rule_expr_payload_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
 #endif
 }
 
-static int
-nft_rule_expr_payload_snprintf_xml(char *buf, size_t len, uint32_t flags,
-				   struct nft_rule_expr *e)
+static int nft_rule_expr_payload_export(char *buf, size_t size, uint32_t flags,
+					struct nft_rule_expr *e, int type)
 {
 	struct nft_expr_payload *payload = nft_expr_data(e);
-	int size = len, offset = 0, ret;
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_PAYLOAD_DREG)) {
-		ret = snprintf(buf, len, "<dreg>%u</dreg>", payload->dreg);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_PAYLOAD_OFFSET)) {
-		ret = snprintf(buf + offset, len, "<offset>%u</offset>",
-			       payload->offset);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_PAYLOAD_LEN)) {
-		ret = snprintf(buf + offset, len, "<len>%u</len>", payload->len);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_PAYLOAD_BASE)) {
-		ret = snprintf(buf + offset, len, "<base>%s</base>",
-			       base2str(payload->base));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
+	if (e->flags & (1 << NFT_EXPR_PAYLOAD_DREG))
+		nft_buf_u32(&b, type, payload->dreg, DREG);
+	if (e->flags & (1 << NFT_EXPR_PAYLOAD_OFFSET))
+		nft_buf_u32(&b, type, payload->offset, OFFSET);
+	if (e->flags & (1 << NFT_EXPR_PAYLOAD_LEN))
+		nft_buf_u32(&b, type, payload->len, LEN);
+	if (e->flags & (1 << NFT_EXPR_PAYLOAD_BASE))
+		nft_buf_str(&b, type, base2str(payload->base), BASE);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int
@@ -312,15 +274,14 @@ nft_rule_expr_payload_snprintf(char *buf, size_t len, uint32_t type,
 {
 	struct nft_expr_payload *payload = nft_expr_data(e);
 
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		return snprintf(buf, len, "load %ub @ %s header + %u => reg %u ",
 				payload->len, base2str(payload->base),
 				payload->offset, payload->dreg);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_payload_snprintf_xml(buf, len, flags, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_payload_snprintf_json(buf, len, flags, e);
+		return nft_rule_expr_payload_export(buf, len, flags, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/queue.c b/src/expr/queue.c
index 64eb3cb..a4f0b88 100644
--- a/src/expr/queue.c
+++ b/src/expr/queue.c
@@ -20,6 +20,7 @@
 #include <libnftnl/expr.h>
 #include <libnftnl/rule.h>
 #include "expr_ops.h"
+#include <buffer.h>
 
 struct nft_expr_queue {
 	uint16_t		queuenum;
@@ -211,59 +212,20 @@ static int nft_rule_expr_queue_snprintf_default(char *buf, size_t len,
 	return offset;
 }
 
-static int nft_rule_expr_queue_snprintf_xml(char *buf, size_t len,
-					    struct nft_rule_expr *e)
+static int nft_rule_expr_queue_export(char *buf, size_t size,
+				      struct nft_rule_expr *e, int type)
 {
-	int ret, size = len, offset = 0;
-	struct nft_expr_queue *queue = nft_expr_data(e);
-
-	if (e->flags & (1 << NFT_EXPR_QUEUE_NUM)) {
-		ret = snprintf(buf + offset, len, "<num>%u</num>",
-			       queue->queuenum);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (e->flags & (1 << NFT_EXPR_QUEUE_TOTAL)) {
-		ret = snprintf(buf + offset, len, "<total>%u</total>",
-			       queue->queues_total);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_QUEUE_FLAGS)) {
-		ret = snprintf(buf + offset, len, "<flags>%u</flags>",
-			       queue->flags);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	return offset;
-}
-
-static int nft_rule_expr_queue_snprintf_json(char *buf, size_t len,
-					     struct nft_rule_expr *e)
-{
-	int ret, size = len, offset = 0;
 	struct nft_expr_queue *queue = nft_expr_data(e);
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_QUEUE_NUM)) {
-		ret = snprintf(buf + offset, len, "\"num\":%u,",
-			       queue->queuenum);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (e->flags & (1 << NFT_EXPR_QUEUE_TOTAL)) {
-		ret = snprintf(buf + offset, len, "\"total\":%u,",
-			       queue->queues_total);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_QUEUE_FLAGS)) {
-		ret = snprintf(buf + offset, len, "\"flags\":%u,",
-			       queue->flags);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	/* Remove the last comma characther */
-	if (offset > 0)
-		offset--;
+	if (e->flags & (1 << NFT_EXPR_QUEUE_NUM))
+		nft_buf_u32(&b, type, queue->queuenum, NUM);
+	if (e->flags & (1 << NFT_EXPR_QUEUE_TOTAL))
+		nft_buf_u32(&b, type, queue->queues_total, TOTAL);
+	if (e->flags & (1 << NFT_EXPR_QUEUE_FLAGS))
+		nft_buf_u32(&b, type, queue->flags, FLAGS);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int
@@ -271,13 +233,12 @@ nft_rule_expr_queue_snprintf(char *buf, size_t len, uint32_t type,
 			      uint32_t flags, struct nft_rule_expr *e)
 {
 
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_queue_snprintf_default(buf, len, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_queue_snprintf_xml(buf, len, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_queue_snprintf_json(buf, len, e);
+		return nft_rule_expr_queue_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/redir.c b/src/expr/redir.c
index 98e8850..02cd3a6 100644
--- a/src/expr/redir.c
+++ b/src/expr/redir.c
@@ -20,6 +20,7 @@
 #include <libnftnl/expr.h>
 #include <libnftnl/rule.h>
 #include "expr_ops.h"
+#include <buffer.h>
 
 struct nft_expr_redir {
 	enum nft_registers sreg_proto_min;
@@ -184,60 +185,20 @@ nft_rule_expr_redir_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
 #endif
 }
 
-static int nft_rule_expr_redir_snprintf_json(char *buf, size_t len,
-					     struct nft_rule_expr *e)
+static int nft_rule_expr_redir_export(char *buf, size_t size,
+				      struct nft_rule_expr *e, int type)
 {
-	int ret, size = len, offset = 0;
 	struct nft_expr_redir *redir = nft_expr_data(e);
+        NFT_BUF_INIT(b, buf, size);
 
-	if (nft_rule_expr_is_set(e, NFT_EXPR_REDIR_REG_PROTO_MIN)) {
-		ret = snprintf(buf + offset, len, "\"sreg_proto_min\":%u,",
-			       redir->sreg_proto_min);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (nft_rule_expr_is_set(e, NFT_EXPR_REDIR_REG_PROTO_MAX)) {
-		ret = snprintf(buf + offset, len, "\"sreg_proto_max\":%u,",
-			       redir->sreg_proto_max);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (nft_rule_expr_is_set(e, NFT_EXPR_REDIR_FLAGS)) {
-		ret = snprintf(buf + offset, len, "\"flags\":%u",
-			       redir->flags);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	return offset;
-}
-
-static int nft_rule_expr_redir_snprintf_xml(char *buf, size_t len,
-					    struct nft_rule_expr *e)
-{
-	int ret, size = len, offset = 0;
-	struct nft_expr_redir *redir = nft_expr_data(e);
-
-	if (nft_rule_expr_is_set(e, NFT_EXPR_REDIR_REG_PROTO_MIN)) {
-		ret = snprintf(buf + offset, len,
-			       "<sreg_proto_min>%u<sreg_proto_min>",
-			       redir->sreg_proto_min);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (nft_rule_expr_is_set(e, NFT_EXPR_REDIR_REG_PROTO_MAX)) {
-		ret = snprintf(buf + offset, len,
-			       "<sreg_proto_max>%u</sreg_proto_max>",
-			       redir->sreg_proto_max);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (nft_rule_expr_is_set(e, NFT_EXPR_REDIR_FLAGS)) {
-		ret = snprintf(buf + offset, len, "<flags>%u</flags>",
-			       redir->flags);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
+	if (e->flags & (1 << NFT_EXPR_REDIR_REG_PROTO_MIN))
+		nft_buf_u32(&b, type, redir->sreg_proto_min, SREG_PROTO_MIN);
+	if (e->flags & (1 << NFT_EXPR_REDIR_REG_PROTO_MAX))
+		nft_buf_u32(&b, type, redir->sreg_proto_max, SREG_PROTO_MAX);
+	if (e->flags & (1 << NFT_EXPR_REDIR_FLAGS))
+		nft_buf_u32(&b, type, redir->flags, FLAGS);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int nft_rule_expr_redir_snprintf_default(char *buf, size_t len,
@@ -275,9 +236,8 @@ nft_rule_expr_redir_snprintf(char *buf, size_t len, uint32_t type,
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_redir_snprintf_default(buf, len, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_redir_snprintf_xml(buf, len, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_redir_snprintf_json(buf, len, e);
+		return nft_rule_expr_redir_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/reject.c b/src/expr/reject.c
index fb88cf5..fe18368 100644
--- a/src/expr/reject.c
+++ b/src/expr/reject.c
@@ -21,6 +21,7 @@
 #include <libnftnl/expr.h>
 #include <libnftnl/rule.h>
 #include "expr_ops.h"
+#include <buffer.h>
 
 struct nft_expr_reject {
 	uint32_t		type;
@@ -170,60 +171,30 @@ static int nft_rule_expr_reject_snprintf_default(char *buf, size_t len,
 			reject->type, reject->icmp_code);
 }
 
-static int nft_rule_expr_reject_snprintf_xml(char *buf, size_t len,
-					     struct nft_rule_expr *e)
+static int nft_rule_expr_reject_export(char *buf, size_t size,
+				       struct nft_rule_expr *e, int type)
 {
-	int ret, size = len, offset = 0;
 	struct nft_expr_reject *reject = nft_expr_data(e);
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_REJECT_TYPE)) {
-		ret = snprintf(buf+offset, len, "<type>%u</type>",
-			       reject->type);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_REJECT_CODE)) {
-		ret = snprintf(buf+offset, len, "<code>%u</code>",
-			       reject->icmp_code);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	return offset;
-}
-
-static int nft_rule_expr_reject_snprintf_json(char *buf, size_t len,
-					      struct nft_rule_expr *e)
-{
-	int ret, size = len, offset = 0;
-	struct nft_expr_reject *reject = nft_expr_data(e);
-
-	if (e->flags & (1 << NFT_EXPR_REJECT_TYPE)) {
-		ret = snprintf(buf+offset, len, "\"type\":%u,",
-			       reject->type);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (e->flags & (1 << NFT_EXPR_REJECT_CODE)) {
-		ret = snprintf(buf+offset, len, "\"code\":%u,",
-			       reject->icmp_code);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	if (offset > 0)
-		offset--;
+	if (e->flags & (1 << NFT_EXPR_REJECT_TYPE))
+		nft_buf_u32(&b, type, reject->type, TYPE);
+	if (e->flags & (1 << NFT_EXPR_REJECT_CODE))
+		nft_buf_u32(&b, type, reject->icmp_code, CODE);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int
 nft_rule_expr_reject_snprintf(char *buf, size_t len, uint32_t type,
 			      uint32_t flags, struct nft_rule_expr *e)
 {
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		return nft_rule_expr_reject_snprintf_default(buf, len, e);
 	case NFT_OUTPUT_XML:
-		return nft_rule_expr_reject_snprintf_xml(buf, len, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_expr_reject_snprintf_json(buf, len, e);
+		return nft_rule_expr_reject_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/expr/target.c b/src/expr/target.c
index bfff513..a79bc9e 100644
--- a/src/expr/target.c
+++ b/src/expr/target.c
@@ -25,6 +25,7 @@
 #include <libnftnl/rule.h>
 
 #include "expr_ops.h"
+#include <buffer.h>
 
 /* From include/linux/netfilter/x_tables.h */
 #define XT_EXTENSION_MAXNAMELEN 29
@@ -205,33 +206,16 @@ nft_rule_expr_target_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
 #endif
 }
 
-static int nft_rule_exp_target_snprintf_json(char *buf, size_t len,
-					     struct nft_rule_expr *e)
+static int nft_rule_exp_target_export(char *buf, size_t size,
+				      struct nft_rule_expr *e, int type)
 {
 	struct nft_expr_target *target = nft_expr_data(e);
-	int ret, size = len, offset = 0;
+	NFT_BUF_INIT(b, buf, size);
 
-	if (e->flags & (1 << NFT_EXPR_TG_NAME)) {
-		ret = snprintf(buf, len, "\"name\":\"%s\"", target->name);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	return offset;
-}
-
-static int nft_rule_exp_target_snprintf_xml(char *buf, size_t len,
-					    struct nft_rule_expr *e)
-{
-	struct nft_expr_target *target = nft_expr_data(e);
-	int ret, size=len;
-	int offset = 0;
-
-	if (e->flags & (1 << NFT_EXPR_TG_NAME)) {
-		ret = snprintf(buf, len, "<name>%s</name>", target->name);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
+	if (e->flags & (1 << NFT_EXPR_TG_NAME))
+		nft_buf_str(&b, type, target->name, NAME);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int
@@ -240,14 +224,13 @@ nft_rule_expr_target_snprintf(char *buf, size_t len, uint32_t type,
 {
 	struct nft_expr_target *target = nft_expr_data(e);
 
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		return snprintf(buf, len, "name %s rev %u ",
 				target->name, target->rev);
 	case NFT_OUTPUT_XML:
-		return nft_rule_exp_target_snprintf_xml(buf, len, e);
 	case NFT_OUTPUT_JSON:
-		return nft_rule_exp_target_snprintf_json(buf, len, e);
+		return nft_rule_exp_target_export(buf, len, e, type);
 	default:
 		break;
 	}
diff --git a/src/table.c b/src/table.c
index 53f6a4d..c93e6fb 100644
--- a/src/table.c
+++ b/src/table.c
@@ -24,6 +24,7 @@
 #include <linux/netfilter/nf_tables.h>
 
 #include <libnftnl/table.h>
+#include <buffer.h>
 
 struct nft_table {
 	struct list_head head;
@@ -391,75 +392,24 @@ int nft_table_parse_file(struct nft_table *t, enum nft_parse_type type,
 }
 EXPORT_SYMBOL(nft_table_parse_file);
 
-static int nft_table_snprintf_json(char *buf, size_t size, struct nft_table *t)
+static int nft_table_export(char *buf, size_t size, struct nft_table *t,
+			    int type)
 {
-	int ret, len = size, offset = 0;
-
-	ret = snprintf(buf, size, "{\"table\":{");
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	ret = 0;
-
-	if (t->flags & (1 << NFT_TABLE_ATTR_NAME)) {
-		ret = snprintf(buf + offset, size, "\"name\":\"%s\",", t->name);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (t->flags & (1 << NFT_TABLE_ATTR_FAMILY)) {
-		ret = snprintf(buf + offset, size, "\"family\":\"%s\",",
-			       nft_family2str(t->family));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (t->flags & (1 << NFT_TABLE_ATTR_FLAGS)) {
-		ret = snprintf(buf + offset, size, "\"flags\":%u,",
-			       t->table_flags);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (t->flags & (1 << NFT_TABLE_ATTR_USE)) {
-		ret = snprintf(buf + offset, size, "\"use\":%u,", t->use);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-
-	/* If  some values is set, ret is not 0. So, It's needed to remove the
-	 * last comma characther
-	 */
-	if (ret > 0)
-		offset--;
-
-	ret = snprintf(buf + offset, size, "}}");
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-
-	return offset;
-}
-
-static int nft_table_snprintf_xml(char *buf, size_t size, struct nft_table *t)
-{
-	int ret, len = size, offset = 0;
-
-	ret = snprintf(buf, size, "<table>");
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	NFT_BUF_INIT(b, buf, size);
 
-	if (t->flags & (1 << NFT_TABLE_ATTR_NAME)) {
-		ret = snprintf(buf + offset, size, "<name>%s</name>", t->name);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (t->flags & (1 << NFT_TABLE_ATTR_FAMILY)) {
-		ret = snprintf(buf + offset, size, "<family>%s</family>",
-			       nft_family2str(t->family));
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (t->flags & (1 << NFT_TABLE_ATTR_FLAGS)) {
-		ret = snprintf(buf + offset, size, "<flags>%u</flags>",
-			       t->table_flags);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
-	if (t->flags & (1 << NFT_TABLE_ATTR_USE)) {
-		ret = snprintf(buf + offset, size, "<use>%u</use>", t->use);
-		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-	}
+	nft_buf_open(&b, type, TABLE);
+	if (t->flags & (1 << NFT_TABLE_ATTR_NAME))
+		nft_buf_str(&b, type, t->name, NAME);
+	if (t->flags & (1 << NFT_TABLE_ATTR_FAMILY))
+		nft_buf_str(&b, type, nft_family2str(t->family), FAMILY);
+	if (t->flags & (1 << NFT_TABLE_ATTR_FLAGS))
+		nft_buf_u32(&b, type, t->table_flags, FLAGS);
+	if (t->flags & (1 << NFT_TABLE_ATTR_USE))
+		nft_buf_u32(&b, type, t->use, USE);
 
-	ret = snprintf(buf + offset, size, "</table>");
-	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	nft_buf_close(&b, type, TABLE);
 
-	return offset;
+	return nft_buf_done(&b);
 }
 
 static int nft_table_snprintf_default(char *buf, size_t size, struct nft_table *t)
@@ -477,15 +427,13 @@ int nft_table_snprintf(char *buf, size_t size, struct nft_table *t,
 	ret = nft_event_header_snprintf(buf+offset, len, type, flags);
 	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
-	switch(type) {
+	switch (type) {
 	case NFT_OUTPUT_DEFAULT:
 		ret = nft_table_snprintf_default(buf+offset, len, t);
 		break;
 	case NFT_OUTPUT_XML:
-		ret = nft_table_snprintf_xml(buf+offset, len, t);
-		break;
 	case NFT_OUTPUT_JSON:
-		ret = nft_table_snprintf_json(buf+offset, len, t);
+		ret = nft_table_export(buf+offset, len, t, type);
 		break;
 	default:
 		return -1;
diff --git a/tests/jsonfiles/11-chain.json b/tests/jsonfiles/11-chain.json
index 2610b79..731ed1f 100644
--- a/tests/jsonfiles/11-chain.json
+++ b/tests/jsonfiles/11-chain.json
@@ -1 +1 @@
-{"nftables":[{"chain":{"name":"input","handle":1,"bytes":1375696,"packets":4136,"family":"ip","table":"filter","use":0,"type":"filter","hooknum":"input","prio":0,"policy":"accept"}}]}
+{"nftables":[{"chain":{"name":"input","handle":1,"bytes":1375696,"packets":4136,"table":"filter","family":"ip","use":0,"type":"filter","hooknum":"input","prio":0,"policy":"accept"}}]}
diff --git a/tests/jsonfiles/12-chain.json b/tests/jsonfiles/12-chain.json
index 3d15982..2d344eb 100644
--- a/tests/jsonfiles/12-chain.json
+++ b/tests/jsonfiles/12-chain.json
@@ -1 +1 @@
-{"nftables":[{"chain":{"name":"forward","handle":2,"bytes":0,"packets":0,"family":"ip","table":"filter","use":0,"type":"filter","hooknum":"forward","prio":0,"policy":"accept"}}]}
+{"nftables":[{"chain":{"name":"forward","handle":2,"bytes":0,"packets":0,"table":"filter","family":"ip","use":0,"type":"filter","hooknum":"forward","prio":0,"policy":"accept"}}]}
diff --git a/tests/jsonfiles/13-chain.json b/tests/jsonfiles/13-chain.json
index e3a17f0..5a6ddd1 100644
--- a/tests/jsonfiles/13-chain.json
+++ b/tests/jsonfiles/13-chain.json
@@ -1 +1 @@
-{"nftables":[{"chain":{"name":"output","handle":3,"bytes":454786,"packets":2681,"family":"ip","table":"filter","use":0,"type":"filter","hooknum":"output","prio":0,"policy":"accept"}}]}
+{"nftables":[{"chain":{"name":"output","handle":3,"bytes":454786,"packets":2681,"table":"filter","family":"ip","use":0,"type":"filter","hooknum":"output","prio":0,"policy":"accept"}}]}
diff --git a/tests/xmlfiles/10-chain.xml b/tests/xmlfiles/10-chain.xml
index 9c00eda..6ac54ab 100644
--- a/tests/xmlfiles/10-chain.xml
+++ b/tests/xmlfiles/10-chain.xml
@@ -1 +1 @@
-<nftables><chain><name>test</name><handle>0</handle><bytes>0</bytes><packets>0</packets><table>filter</table><type>filter</type><hooknum>input</hooknum><prio>0</prio><policy>accept</policy><family>ip</family></chain></nftables>
+<nftables><chain><name>test</name><handle>0</handle><bytes>0</bytes><packets>0</packets><table>filter</table><family>ip</family><type>filter</type><hooknum>input</hooknum><prio>0</prio><policy>accept</policy></chain></nftables>
diff --git a/tests/xmlfiles/11-chain.xml b/tests/xmlfiles/11-chain.xml
index 3d9978e..34d99dd 100644
--- a/tests/xmlfiles/11-chain.xml
+++ b/tests/xmlfiles/11-chain.xml
@@ -1 +1 @@
-<nftables><chain><name>test</name><handle>0</handle><bytes>59</bytes><packets>1</packets><table>filter</table><type>filter</type><hooknum>forward</hooknum><prio>0</prio><policy>drop</policy><family>ip6</family></chain></nftables>
+<nftables><chain><name>test</name><handle>0</handle><bytes>59</bytes><packets>1</packets><table>filter</table><family>ip6</family><type>filter</type><hooknum>forward</hooknum><prio>0</prio><policy>drop</policy></chain></nftables>
diff --git a/tests/xmlfiles/12-chain.xml b/tests/xmlfiles/12-chain.xml
index db0f56c..f53f252 100644
--- a/tests/xmlfiles/12-chain.xml
+++ b/tests/xmlfiles/12-chain.xml
@@ -1 +1 @@
-<nftables><chain><name>foo</name><handle>100</handle><bytes>59264154979</bytes><packets>2548796325</packets><table>nat</table><type>nat</type><hooknum>postrouting</hooknum><prio>0</prio><policy>accept</policy><family>ip</family></chain></nftables>
+<nftables><chain><name>foo</name><handle>100</handle><bytes>59264154979</bytes><packets>2548796325</packets><table>nat</table><family>ip</family><type>nat</type><hooknum>postrouting</hooknum><prio>0</prio><policy>accept</policy></chain></nftables>
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH libnftnl 3/3] expr: data_reg: use 'reg' instead of 'data_reg'
  2014-11-10 13:26 [PATCH libnftnl 1/3] expr: nat: use 'nat_type' instead of 'type' in the parser Pablo Neira Ayuso
  2014-11-10 13:26 ` [PATCH libnftnl 2/3 v2] src: consolidate XML/JSON exportation Pablo Neira Ayuso
@ 2014-11-10 13:26 ` Pablo Neira Ayuso
  1 sibling, 0 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2014-11-10 13:26 UTC (permalink / raw)
  To: netfilter-devel; +Cc: arturo.borrero.glez, alvaroneay

data_reg is unnecessarily long name and it always has to be
wrapped by another data node. This will allow us to represent
data not only as registers if needed.

Get rid of 'cmpdata' and 'immediatedata' too and use 'data'
instead to wrap 'reg' so these are consistent with the bitwise
expression. No reason for such specific tag per expression.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/expr/cmp.c                           |    4 ++--
 src/expr/data_reg.c                      |   27 ++++++++-------------------
 src/expr/immediate.c                     |    4 ++--
 src/jansson.c                            |    4 ++--
 tests/jsonfiles/14-chain.json            |    2 +-
 tests/jsonfiles/20-rule-bitwise.json     |    2 +-
 tests/jsonfiles/22-rule-cmp.json         |    2 +-
 tests/jsonfiles/24-rule-ct.json          |    2 +-
 tests/jsonfiles/26-rule-immediate.json   |    2 +-
 tests/jsonfiles/31-rule-meta.json        |    2 +-
 tests/jsonfiles/34-rule-payload.json     |    2 +-
 tests/jsonfiles/36-rule-real.json        |    2 +-
 tests/jsonfiles/37-rule-real.json        |    2 +-
 tests/jsonfiles/38-rule-real.json        |    2 +-
 tests/jsonfiles/39-rule-real.json        |    2 +-
 tests/jsonfiles/40-rule-real.json        |    2 +-
 tests/jsonfiles/41-rule-real.json        |    2 +-
 tests/jsonfiles/42-rule-real.json        |    2 +-
 tests/jsonfiles/43-rule-real.json        |    2 +-
 tests/jsonfiles/44-rule-real.json        |    2 +-
 tests/jsonfiles/45-rule-real.json        |    2 +-
 tests/jsonfiles/46-rule-real.json        |    2 +-
 tests/jsonfiles/47-rule-real.json        |    2 +-
 tests/jsonfiles/48-rule-real.json        |    2 +-
 tests/jsonfiles/49-rule-real.json        |    2 +-
 tests/jsonfiles/50-rule-real.json        |    2 +-
 tests/jsonfiles/51-rule-real.json        |    2 +-
 tests/jsonfiles/52-rule-real.json        |    2 +-
 tests/jsonfiles/53-rule-real.json        |    2 +-
 tests/jsonfiles/54-rule-real.json        |    2 +-
 tests/jsonfiles/55-rule-real.json        |    2 +-
 tests/jsonfiles/56-rule-real.json        |    2 +-
 tests/jsonfiles/57-rule-real.json        |    2 +-
 tests/jsonfiles/58-rule-real.json        |    2 +-
 tests/jsonfiles/59-rule-real.json        |    2 +-
 tests/jsonfiles/60-rule-real.json        |    2 +-
 tests/jsonfiles/61-rule-real.json        |    2 +-
 tests/jsonfiles/62-set.json              |    2 +-
 tests/jsonfiles/63-set.json              |    2 +-
 tests/jsonfiles/64-ruleset.json          |    2 +-
 tests/jsonfiles/65-rule-meta-target.json |    2 +-
 tests/xmlfiles/20-rule-bitwise.xml       |    2 +-
 tests/xmlfiles/22-rule-cmp.xml           |    2 +-
 tests/xmlfiles/26-rule-immediate.xml     |    2 +-
 tests/xmlfiles/36-rule-real.xml          |    2 +-
 tests/xmlfiles/37-rule-real.xml          |    2 +-
 tests/xmlfiles/38-rule-real.xml          |    2 +-
 tests/xmlfiles/39-rule-real.xml          |    2 +-
 tests/xmlfiles/40-rule-real.xml          |    2 +-
 tests/xmlfiles/41-rule-real.xml          |    2 +-
 tests/xmlfiles/42-rule-real.xml          |    2 +-
 tests/xmlfiles/43-rule-real.xml          |    2 +-
 tests/xmlfiles/44-rule-real.xml          |    2 +-
 tests/xmlfiles/45-rule-real.xml          |    2 +-
 tests/xmlfiles/46-rule-real.xml          |    2 +-
 tests/xmlfiles/47-rule-real.xml          |    2 +-
 tests/xmlfiles/48-rule-real.xml          |    2 +-
 tests/xmlfiles/49-rule-real.xml          |    2 +-
 tests/xmlfiles/50-rule-real.xml          |    2 +-
 tests/xmlfiles/51-rule-real.xml          |    2 +-
 tests/xmlfiles/52-rule-real.xml          |    2 +-
 tests/xmlfiles/53-rule-real.xml          |    2 +-
 tests/xmlfiles/54-rule-real.xml          |    2 +-
 tests/xmlfiles/55-rule-real.xml          |    2 +-
 tests/xmlfiles/56-rule-real.xml          |    2 +-
 tests/xmlfiles/57-rule-real.xml          |    2 +-
 tests/xmlfiles/58-rule-real.xml          |    2 +-
 tests/xmlfiles/59-rule-real.xml          |    2 +-
 tests/xmlfiles/60-rule-real.xml          |    2 +-
 tests/xmlfiles/61-rule-real.xml          |    2 +-
 tests/xmlfiles/62-rule-real.xml          |    2 +-
 tests/xmlfiles/63-rule-real.xml          |    2 +-
 tests/xmlfiles/64-rule-real.xml          |    2 +-
 tests/xmlfiles/65-rule-real.xml          |    2 +-
 tests/xmlfiles/66-rule-real.xml          |    2 +-
 tests/xmlfiles/67-rule-real.xml          |    2 +-
 tests/xmlfiles/68-rule-real.xml          |    2 +-
 tests/xmlfiles/70-rule-real.xml          |    2 +-
 tests/xmlfiles/71-rule-real.xml          |    2 +-
 tests/xmlfiles/73-set.xml                |    2 +-
 tests/xmlfiles/74-set.xml                |    2 +-
 tests/xmlfiles/75-ruleset.xml            |    2 +-
 82 files changed, 92 insertions(+), 103 deletions(-)

diff --git a/src/expr/cmp.c b/src/expr/cmp.c
index b186df0..3ca4b08 100644
--- a/src/expr/cmp.c
+++ b/src/expr/cmp.c
@@ -201,7 +201,7 @@ static int nft_rule_expr_cmp_json_parse(struct nft_rule_expr *e, json_t *root,
 		nft_rule_expr_set_u32(e, NFT_EXPR_CMP_OP, base);
 	}
 
-	if (nft_jansson_data_reg_parse(root, "cmpdata",
+	if (nft_jansson_data_reg_parse(root, "data",
 				       &cmp->data, err) == DATA_VALUE)
 		e->flags |= (1 << NFT_EXPR_CMP_DATA);
 
@@ -235,7 +235,7 @@ static int nft_rule_expr_cmp_xml_parse(struct nft_rule_expr *e, mxml_node_t *tre
 		nft_rule_expr_set_u32(e, NFT_EXPR_CMP_OP, op_value);
 	}
 
-	if (nft_mxml_data_reg_parse(tree, "cmpdata",
+	if (nft_mxml_data_reg_parse(tree, "data",
 				    &cmp->data, NFT_XML_MAND,
 				    err) == DATA_VALUE)
 		e->flags |= (1 << NFT_EXPR_CMP_DATA);
diff --git a/src/expr/data_reg.c b/src/expr/data_reg.c
index 28ad164..33b3346 100644
--- a/src/expr/data_reg.c
+++ b/src/expr/data_reg.c
@@ -145,21 +145,10 @@ static int nft_data_reg_value_xml_parse(union nft_data_reg *reg,
 	int i;
 	char node_name[6];
 
-	/*
-	* <data_reg type="value">
-	*    <len>16</len>
-	*    <data0>0xc09a002a</data0>
-	*    <data1>0x2700cac1</data1>
-	*    <data2>0x00000000</data2>
-	*    <data3>0x08000000</data3>
-	* </data_reg>
-	*/
-
 	if (nft_mxml_num_parse(tree, "len", MXML_DESCEND_FIRST, BASE_DEC,
 			       &reg->len, NFT_TYPE_U8, NFT_XML_MAND, err) != 0)
 		return DATA_NONE;
 
-	/* Get and set <dataN> */
 	for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) {
 		sprintf(node_name, "data%d", i);
 
@@ -180,7 +169,7 @@ int nft_data_reg_xml_parse(union nft_data_reg *reg, mxml_node_t *tree,
 	const char *type;
 	mxml_node_t *node;
 
-	node = mxmlFindElement(tree, tree, "data_reg", "type", NULL,
+	node = mxmlFindElement(tree, tree, "reg", "type", NULL,
 			       MXML_DESCEND_FIRST);
 	if (node == NULL)
 		goto err;
@@ -198,7 +187,7 @@ int nft_data_reg_xml_parse(union nft_data_reg *reg, mxml_node_t *tree,
 	return DATA_NONE;
 err:
 	errno = EINVAL;
-	err->node_name = "data_reg";
+	err->node_name = "reg";
 	err->error = NFT_PARSE_EMISSINGNODE;
 	return DATA_NONE;
 #else
@@ -216,7 +205,7 @@ nft_data_reg_value_snprintf_json(char *buf, size_t size,
 	uint32_t utemp;
 	uint8_t *tmp;
 
-	ret = snprintf(buf, len, "\"data_reg\":{\"type\":\"value\",");
+	ret = snprintf(buf, len, "\"reg\":{\"type\":\"value\",");
 	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
 	ret = snprintf(buf+offset, len, "\"len\":%u,", reg->len);
@@ -252,7 +241,7 @@ int nft_data_reg_value_snprintf_xml(char *buf, size_t size,
 	uint32_t be;
 	uint8_t *tmp;
 
-	ret = snprintf(buf, len, "<data_reg type=\"value\">");
+	ret = snprintf(buf, len, "<reg type=\"value\">");
 	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
 	ret = snprintf(buf+offset, len, "<len>%u</len>", reg->len);
@@ -274,7 +263,7 @@ int nft_data_reg_value_snprintf_xml(char *buf, size_t size,
 		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 	}
 
-	ret = snprintf(buf+offset, len, "</data_reg>");
+	ret = snprintf(buf+offset, len, "</reg>");
 	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
 	return offset;
@@ -317,7 +306,7 @@ nft_data_reg_verdict_snprintf_xml(char *buf, size_t size,
 {
 	int len = size, offset = 0, ret = 0;
 
-	ret = snprintf(buf, size, "<data_reg type=\"verdict\">"
+	ret = snprintf(buf, size, "<reg type=\"verdict\">"
 		       "<verdict>%s</verdict>", nft_verdict2str(reg->verdict));
 	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
@@ -327,7 +316,7 @@ nft_data_reg_verdict_snprintf_xml(char *buf, size_t size,
 		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 	}
 
-	ret = snprintf(buf+offset, len, "</data_reg>");
+	ret = snprintf(buf+offset, len, "</reg>");
 	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
 	return offset;
@@ -339,7 +328,7 @@ nft_data_reg_verdict_snprintf_json(char *buf, size_t size,
 {
 	int len = size, offset = 0, ret = 0;
 
-	ret = snprintf(buf, size, "\"data_reg\":{\"type\":\"verdict\","
+	ret = snprintf(buf, size, "\"reg\":{\"type\":\"verdict\","
 		       "\"verdict\":\"%s\"", nft_verdict2str(reg->verdict));
 	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
diff --git a/src/expr/immediate.c b/src/expr/immediate.c
index be70445..3d4e48c 100644
--- a/src/expr/immediate.c
+++ b/src/expr/immediate.c
@@ -186,7 +186,7 @@ nft_rule_expr_immediate_json_parse(struct nft_rule_expr *e, json_t *root,
 	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg, err) == 0)
 		nft_rule_expr_set_u32(e, NFT_EXPR_IMM_DREG, reg);
 
-	datareg_type = nft_jansson_data_reg_parse(root, "immediatedata",
+	datareg_type = nft_jansson_data_reg_parse(root, "data",
 						  &imm->data, err);
 	if (datareg_type >= 0) {
 		switch (datareg_type) {
@@ -223,7 +223,7 @@ nft_rule_expr_immediate_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
 			       NFT_XML_MAND, err) == 0)
 		nft_rule_expr_set_u32(e, NFT_EXPR_IMM_DREG, reg);
 
-	datareg_type = nft_mxml_data_reg_parse(tree, "immediatedata",
+	datareg_type = nft_mxml_data_reg_parse(tree, "data",
 					       &imm->data, NFT_XML_MAND, err);
 	if (datareg_type >= 0) {
 		switch (datareg_type) {
diff --git a/src/jansson.c b/src/jansson.c
index 4c7968a..b17d8a9 100644
--- a/src/jansson.c
+++ b/src/jansson.c
@@ -227,10 +227,10 @@ int nft_jansson_data_reg_parse(json_t *root, const char *node_name,
 	if (data == NULL)
 		data = root;
 
-	data = json_object_get(data, "data_reg");
+	data = json_object_get(data, "reg");
 	if (data == NULL) {
 		err->error = NFT_PARSE_EMISSINGNODE;
-		err->node_name = "data_reg";
+		err->node_name = "reg";
 		errno = EINVAL;
 		return -1;
 	}
diff --git a/tests/jsonfiles/14-chain.json b/tests/jsonfiles/14-chain.json
index d98dc94..6642615 100644
--- a/tests/jsonfiles/14-chain.json
+++ b/tests/jsonfiles/14-chain.json
@@ -1 +1 @@
-{"nftables":[{"chain":{"name":"chain1","handle":4,"bytes":0,"packets":0,"family":"ip","table":"filter","use":0}}]}
+{"nftables":[{"chain":{"name":"chain1","handle":4,"bytes":0,"packets":0,"table":"filter","family":"ip","use":0}}]}
diff --git a/tests/jsonfiles/20-rule-bitwise.json b/tests/jsonfiles/20-rule-bitwise.json
index de3d9ec..af53851 100644
--- a/tests/jsonfiles/20-rule-bitwise.json
+++ b/tests/jsonfiles/20-rule-bitwise.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"input","handle":20,"expr":[{"type":"bitwise","sreg":1,"dreg":1,"len":4,"mask":{"data_reg":{"type":"value","len":4,"data0":"0x0000000a"}},"xor":{"data_reg":{"type":"value","len":4,"data0":"0x00000000"}}}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"input","handle":20,"expr":[{"type":"bitwise","sreg":1,"dreg":1,"len":4,"mask":{"reg":{"type":"value","len":4,"data0":"0x0000000a"}},"xor":{"reg":{"type":"value","len":4,"data0":"0x00000000"}}}]}}]}
diff --git a/tests/jsonfiles/22-rule-cmp.json b/tests/jsonfiles/22-rule-cmp.json
index 8269b00..2a6565a 100644
--- a/tests/jsonfiles/22-rule-cmp.json
+++ b/tests/jsonfiles/22-rule-cmp.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"forward","handle":22,"expr":[{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":16,"data0":"0x00000000","data1":"0x6e6f6200","data2":"0x2e303164","data3":"0x00393331"}}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"forward","handle":22,"expr":[{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":16,"data0":"0x00000000","data1":"0x6e6f6200","data2":"0x2e303164","data3":"0x00393331"}}}]}}]}
diff --git a/tests/jsonfiles/24-rule-ct.json b/tests/jsonfiles/24-rule-ct.json
index 40cfe9b..091d885 100644
--- a/tests/jsonfiles/24-rule-ct.json
+++ b/tests/jsonfiles/24-rule-ct.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"input","handle":24,"expr":[{"type":"ct","dreg":1,"key":"state"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x00000008"}}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"input","handle":24,"expr":[{"type":"ct","dreg":1,"key":"state"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x00000008"}}}]}}]}
diff --git a/tests/jsonfiles/26-rule-immediate.json b/tests/jsonfiles/26-rule-immediate.json
index d416928..767052e 100644
--- a/tests/jsonfiles/26-rule-immediate.json
+++ b/tests/jsonfiles/26-rule-immediate.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"input","handle":26,"expr":[{"type":"immediate","dreg":0,"data_reg":{"type":"verdict","verdict":"accept"}}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"input","handle":26,"expr":[{"type":"immediate","dreg":0,"data":{"reg":{"type":"verdict","verdict":"accept"}}}]}}]}
diff --git a/tests/jsonfiles/31-rule-meta.json b/tests/jsonfiles/31-rule-meta.json
index 971a034..d39a6ed 100644
--- a/tests/jsonfiles/31-rule-meta.json
+++ b/tests/jsonfiles/31-rule-meta.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":8,"expr":[{"type":"meta","dreg":1,"key":"protocol"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x000003e8"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":8,"expr":[{"type":"meta","dreg":1,"key":"protocol"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x000003e8"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/34-rule-payload.json b/tests/jsonfiles/34-rule-payload.json
index 5cb566d..eec5dc9 100644
--- a/tests/jsonfiles/34-rule-payload.json
+++ b/tests/jsonfiles/34-rule-payload.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"input","handle":26,"expr":[{"type":"payload","dreg":1,"offset":9,"len":1,"base":"network"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":1,"data0":"0x00000006"}},{"type":"payload","dreg":1,"offset":2,"len":2,"base":"transport"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":2,"data0":"0x00001600"}},{"type":"immediate","dreg":0,"data_reg":{"type":"verdict","verdict":"accept"}}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"input","handle":26,"expr":[{"type":"payload","dreg":1,"offset":9,"len":1,"base":"network"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":1,"data0":"0x00000006"}}},{"type":"payload","dreg":1,"offset":2,"len":2,"base":"transport"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":2,"data0":"0x00001600"}}},{"type":"immediate","dreg":0,"data":{"reg":{"type":"verdict","verdict":"accept"}}}]}}]}
diff --git a/tests/jsonfiles/36-rule-real.json b/tests/jsonfiles/36-rule-real.json
index 2910a67..56d6794 100644
--- a/tests/jsonfiles/36-rule-real.json
+++ b/tests/jsonfiles/36-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":36,"expr":[{"type":"payload","dreg":1,"offset":12,"len":8,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":8,"data0":"0x0100a8c0","data1":"0x6400a8c0"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":36,"expr":[{"type":"payload","dreg":1,"offset":12,"len":8,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":8,"data0":"0x0100a8c0","data1":"0x6400a8c0"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/37-rule-real.json b/tests/jsonfiles/37-rule-real.json
index 0dc73fc..6eb8c7d 100644
--- a/tests/jsonfiles/37-rule-real.json
+++ b/tests/jsonfiles/37-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":37,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x0100a8c0"}}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":37,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x0100a8c0"}}}]}}]}
diff --git a/tests/jsonfiles/38-rule-real.json b/tests/jsonfiles/38-rule-real.json
index ffdf054..e0da26f 100644
--- a/tests/jsonfiles/38-rule-real.json
+++ b/tests/jsonfiles/38-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":38,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x0100a8c0"}}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":38,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x0100a8c0"}}}]}}]}
diff --git a/tests/jsonfiles/39-rule-real.json b/tests/jsonfiles/39-rule-real.json
index c555b02..b80bf42 100644
--- a/tests/jsonfiles/39-rule-real.json
+++ b/tests/jsonfiles/39-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":39,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"gte","data_reg":{"type":"value","len":4,"data0":"0x0100a8c0"}},{"type":"cmp","sreg":1,"op":"lte","data_reg":{"type":"value","len":4,"data0":"0xfa00a8c0"}}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":39,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"gte","data":{"reg":{"type":"value","len":4,"data0":"0x0100a8c0"}}},{"type":"cmp","sreg":1,"op":"lte","data":{"reg":{"type":"value","len":4,"data0":"0xfa00a8c0"}}}]}}]}
diff --git a/tests/jsonfiles/40-rule-real.json b/tests/jsonfiles/40-rule-real.json
index 0068325..38a8497 100644
--- a/tests/jsonfiles/40-rule-real.json
+++ b/tests/jsonfiles/40-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":40,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x0100a8c0"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":40,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x0100a8c0"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/41-rule-real.json b/tests/jsonfiles/41-rule-real.json
index 8e15a45..58bc9c0 100644
--- a/tests/jsonfiles/41-rule-real.json
+++ b/tests/jsonfiles/41-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":41,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x0100a8c0"}},{"type":"counter","pkts":0,"bytes":0},{"type":"immediate","dreg":0,"data_reg":{"type":"verdict","verdict":"drop"}}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":41,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x0100a8c0"}}},{"type":"counter","pkts":0,"bytes":0},{"type":"immediate","dreg":0,"data":{"reg":{"type":"verdict","verdict":"drop"}}}]}}]}
diff --git a/tests/jsonfiles/42-rule-real.json b/tests/jsonfiles/42-rule-real.json
index 4d21547..025d351 100644
--- a/tests/jsonfiles/42-rule-real.json
+++ b/tests/jsonfiles/42-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":42,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x0100a8c0"}},{"type":"counter","pkts":0,"bytes":0},{"type":"log","prefix":"(null)","group":0,"snaplen":0,"qthreshold":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":42,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x0100a8c0"}}},{"type":"counter","pkts":0,"bytes":0},{"type":"log","prefix":"(null)","group":0,"snaplen":0,"qthreshold":0}]}}]}
diff --git a/tests/jsonfiles/43-rule-real.json b/tests/jsonfiles/43-rule-real.json
index dcde606..ff4fedb 100644
--- a/tests/jsonfiles/43-rule-real.json
+++ b/tests/jsonfiles/43-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":43,"expr":[{"type":"payload","dreg":1,"offset":9,"len":1,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":1,"data0":"0x00000006"}},{"type":"payload","dreg":1,"offset":2,"len":2,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":2,"data0":"0x00001600"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":43,"expr":[{"type":"payload","dreg":1,"offset":9,"len":1,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":1,"data0":"0x00000006"}}},{"type":"payload","dreg":1,"offset":2,"len":2,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":2,"data0":"0x00001600"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/44-rule-real.json b/tests/jsonfiles/44-rule-real.json
index 79bc711..14c6e34 100644
--- a/tests/jsonfiles/44-rule-real.json
+++ b/tests/jsonfiles/44-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":44,"expr":[{"type":"payload","dreg":1,"offset":9,"len":1,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":1,"data0":"0x00000006"}},{"type":"payload","dreg":1,"offset":0,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x16000004"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":44,"expr":[{"type":"payload","dreg":1,"offset":9,"len":1,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":1,"data0":"0x00000006"}}},{"type":"payload","dreg":1,"offset":0,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x16000004"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/45-rule-real.json b/tests/jsonfiles/45-rule-real.json
index e6732fb..81841a7 100644
--- a/tests/jsonfiles/45-rule-real.json
+++ b/tests/jsonfiles/45-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":45,"expr":[{"type":"payload","dreg":1,"offset":12,"len":8,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":8,"data0":"0x0100a8c0","data1":"0x6400a8c0"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":45,"expr":[{"type":"payload","dreg":1,"offset":12,"len":8,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":8,"data0":"0x0100a8c0","data1":"0x6400a8c0"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/46-rule-real.json b/tests/jsonfiles/46-rule-real.json
index 7f97a55..3cfb290 100644
--- a/tests/jsonfiles/46-rule-real.json
+++ b/tests/jsonfiles/46-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":46,"expr":[{"type":"payload","dreg":1,"offset":9,"len":1,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":1,"data0":"0x00000006"}},{"type":"payload","dreg":1,"offset":0,"len":8,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":8,"data0":"0x16000004","data1":"0x00000000"}}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":46,"expr":[{"type":"payload","dreg":1,"offset":9,"len":1,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":1,"data0":"0x00000006"}}},{"type":"payload","dreg":1,"offset":0,"len":8,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":8,"data0":"0x16000004","data1":"0x00000000"}}}]}}]}
diff --git a/tests/jsonfiles/47-rule-real.json b/tests/jsonfiles/47-rule-real.json
index 556d2e0..e4160dd 100644
--- a/tests/jsonfiles/47-rule-real.json
+++ b/tests/jsonfiles/47-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":47,"expr":[{"type":"payload","dreg":1,"offset":9,"len":1,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":1,"data0":"0x00000006"}},{"type":"payload","dreg":1,"offset":0,"len":8,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":8,"data0":"0x16000004","data1":"0x00000000"}}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":47,"expr":[{"type":"payload","dreg":1,"offset":9,"len":1,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":1,"data0":"0x00000006"}}},{"type":"payload","dreg":1,"offset":0,"len":8,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":8,"data0":"0x16000004","data1":"0x00000000"}}}]}}]}
diff --git a/tests/jsonfiles/48-rule-real.json b/tests/jsonfiles/48-rule-real.json
index 6a0b288..95e2b38 100644
--- a/tests/jsonfiles/48-rule-real.json
+++ b/tests/jsonfiles/48-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":48,"expr":[{"type":"meta","dreg":1,"key":"len"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x000003e8"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":48,"expr":[{"type":"meta","dreg":1,"key":"len"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x000003e8"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/49-rule-real.json b/tests/jsonfiles/49-rule-real.json
index 53cca09..da0c0c5 100644
--- a/tests/jsonfiles/49-rule-real.json
+++ b/tests/jsonfiles/49-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":49,"expr":[{"type":"meta","dreg":1,"key":"mark"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x00000000"}},{"type":"counter","pkts":55,"bytes":11407}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":49,"expr":[{"type":"meta","dreg":1,"key":"mark"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x00000000"}}},{"type":"counter","pkts":55,"bytes":11407}]}}]}
diff --git a/tests/jsonfiles/50-rule-real.json b/tests/jsonfiles/50-rule-real.json
index 3979d2a..4dbc553 100644
--- a/tests/jsonfiles/50-rule-real.json
+++ b/tests/jsonfiles/50-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":50,"expr":[{"type":"meta","dreg":1,"key":"iif"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x00000001"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":50,"expr":[{"type":"meta","dreg":1,"key":"iif"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x00000001"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/51-rule-real.json b/tests/jsonfiles/51-rule-real.json
index 1afbf82..7d510ab 100644
--- a/tests/jsonfiles/51-rule-real.json
+++ b/tests/jsonfiles/51-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":51,"expr":[{"type":"meta","dreg":1,"key":"iifname"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":16,"data0":"0x00000000","data1":"0x00000000","data2":"0x65000000","data3":"0x00306874"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":51,"expr":[{"type":"meta","dreg":1,"key":"iifname"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":16,"data0":"0x00000000","data1":"0x00000000","data2":"0x65000000","data3":"0x00306874"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/52-rule-real.json b/tests/jsonfiles/52-rule-real.json
index 911ddd3..2809478 100644
--- a/tests/jsonfiles/52-rule-real.json
+++ b/tests/jsonfiles/52-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":52,"expr":[{"type":"meta","dreg":1,"key":"oif"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x00000001"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":52,"expr":[{"type":"meta","dreg":1,"key":"oif"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x00000001"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/53-rule-real.json b/tests/jsonfiles/53-rule-real.json
index 6d49b19..329945c 100644
--- a/tests/jsonfiles/53-rule-real.json
+++ b/tests/jsonfiles/53-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":53,"expr":[{"type":"meta","dreg":1,"key":"oifname"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":16,"data0":"0x00000000","data1":"0x00000000","data2":"0x65000000","data3":"0x00306874"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":53,"expr":[{"type":"meta","dreg":1,"key":"oifname"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":16,"data0":"0x00000000","data1":"0x00000000","data2":"0x65000000","data3":"0x00306874"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/54-rule-real.json b/tests/jsonfiles/54-rule-real.json
index 668bf75..b9b2383 100644
--- a/tests/jsonfiles/54-rule-real.json
+++ b/tests/jsonfiles/54-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":54,"expr":[{"type":"meta","dreg":1,"key":"skuid"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x000003e8"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":54,"expr":[{"type":"meta","dreg":1,"key":"skuid"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x000003e8"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/55-rule-real.json b/tests/jsonfiles/55-rule-real.json
index 5338611..e79552d 100644
--- a/tests/jsonfiles/55-rule-real.json
+++ b/tests/jsonfiles/55-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":55,"expr":[{"type":"meta","dreg":1,"key":"skgid"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x000003e8"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":55,"expr":[{"type":"meta","dreg":1,"key":"skgid"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x000003e8"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/56-rule-real.json b/tests/jsonfiles/56-rule-real.json
index ff5d4ee..a2c4b9c 100644
--- a/tests/jsonfiles/56-rule-real.json
+++ b/tests/jsonfiles/56-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":56,"expr":[{"type":"meta","dreg":1,"key":"secmark"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x00000000"}},{"type":"counter","pkts":55,"bytes":11407}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":56,"expr":[{"type":"meta","dreg":1,"key":"secmark"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x00000000"}}},{"type":"counter","pkts":55,"bytes":11407}]}}]}
diff --git a/tests/jsonfiles/57-rule-real.json b/tests/jsonfiles/57-rule-real.json
index f578573..b233f59 100644
--- a/tests/jsonfiles/57-rule-real.json
+++ b/tests/jsonfiles/57-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":57,"expr":[{"type":"meta","dreg":1,"key":"len"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x000003e8"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":57,"expr":[{"type":"meta","dreg":1,"key":"len"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x000003e8"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/58-rule-real.json b/tests/jsonfiles/58-rule-real.json
index a5e7ec5..f98efd3 100644
--- a/tests/jsonfiles/58-rule-real.json
+++ b/tests/jsonfiles/58-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":58,"expr":[{"type":"meta","dreg":1,"key":"protocol"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":2,"data0":"0x00000008"}},{"type":"counter","pkts":55,"bytes":11407}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":58,"expr":[{"type":"meta","dreg":1,"key":"protocol"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":2,"data0":"0x00000008"}}},{"type":"counter","pkts":55,"bytes":11407}]}}]}
diff --git a/tests/jsonfiles/59-rule-real.json b/tests/jsonfiles/59-rule-real.json
index 46a470b..0f92ade 100644
--- a/tests/jsonfiles/59-rule-real.json
+++ b/tests/jsonfiles/59-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":59,"expr":[{"type":"meta","dreg":1,"key":"mark"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x00000000"}},{"type":"counter","pkts":55,"bytes":11407}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":59,"expr":[{"type":"meta","dreg":1,"key":"mark"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x00000000"}}},{"type":"counter","pkts":55,"bytes":11407}]}}]}
diff --git a/tests/jsonfiles/60-rule-real.json b/tests/jsonfiles/60-rule-real.json
index 1efef1f..0a98726 100644
--- a/tests/jsonfiles/60-rule-real.json
+++ b/tests/jsonfiles/60-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":60,"expr":[{"type":"meta","dreg":1,"key":"iif"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x00000001"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":60,"expr":[{"type":"meta","dreg":1,"key":"iif"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x00000001"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/61-rule-real.json b/tests/jsonfiles/61-rule-real.json
index 1f15c84..8b57338 100644
--- a/tests/jsonfiles/61-rule-real.json
+++ b/tests/jsonfiles/61-rule-real.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":61,"expr":[{"type":"meta","dreg":1,"key":"iifname"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":16,"data0":"0x00000000","data1":"0x00000000","data2":"0x65000000","data3":"0x00306874"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":61,"expr":[{"type":"meta","dreg":1,"key":"iifname"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":16,"data0":"0x00000000","data1":"0x00000000","data2":"0x65000000","data3":"0x00306874"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/jsonfiles/62-set.json b/tests/jsonfiles/62-set.json
index 8a8d99c..58db88b 100644
--- a/tests/jsonfiles/62-set.json
+++ b/tests/jsonfiles/62-set.json
@@ -1 +1 @@
-{"nftables":[{"set":{"name":"set0","table":"filter","flags":3,"family":"ip","key_type":12,"key_len":2,"set_elem":[{"flags":0,"key":{"data_reg":{"type":"value","len":2,"data0":"0x00001700"}}},{"flags":0,"key":{"data_reg":{"type":"value","len":2,"data0":"0x00001600"}}}]}}]}
+{"nftables":[{"set":{"name":"set0","table":"filter","flags":3,"family":"ip","key_type":12,"key_len":2,"set_elem":[{"flags":0,"key":{"reg":{"type":"value","len":2,"data0":"0x00001700"}}},{"flags":0,"key":{"reg":{"type":"value","len":2,"data0":"0x00001600"}}}]}}]}
diff --git a/tests/jsonfiles/63-set.json b/tests/jsonfiles/63-set.json
index 62ccd2f..d63c1cf 100644
--- a/tests/jsonfiles/63-set.json
+++ b/tests/jsonfiles/63-set.json
@@ -1 +1 @@
-{"nftables":[{"set":{"name":"map0","table":"f","flags":11,"family":"ip","key_type":12,"key_len":2,"data_type":4294967040,"data_len":16,"set_elem":[{"flags":0,"key":{"data_reg":{"type":"value","len":2,"data0":"0x00001700"}},"data":{"data_reg":{"type":"verdict","verdict":"goto","chain":"o"}}},{"flags":0,"key":{"data_reg":{"type":"value","len":2,"data0":"0x00001600"}},"data":{"data_reg":{"type":"verdict","verdict":"accept"}}}]}}]}
+{"nftables":[{"set":{"name":"map0","table":"f","flags":11,"family":"ip","key_type":12,"key_len":2,"data_type":4294967040,"data_len":16,"set_elem":[{"flags":0,"key":{"reg":{"type":"value","len":2,"data0":"0x00001700"}},"data":{"reg":{"type":"verdict","verdict":"goto","chain":"o"}}},{"flags":0,"key":{"reg":{"type":"value","len":2,"data0":"0x00001600"}},"data":{"reg":{"type":"verdict","verdict":"accept"}}}]}}]}
diff --git a/tests/jsonfiles/64-ruleset.json b/tests/jsonfiles/64-ruleset.json
index 5755cff..9b6e611 100644
--- a/tests/jsonfiles/64-ruleset.json
+++ b/tests/jsonfiles/64-ruleset.json
@@ -1 +1 @@
-{"nftables":[{"table":{"name":"filter","family":"ip","flags":0,"use":0}},{"table":{"name":"filter2","family":"ip6","flags":0,"use":0}},{"chain":{"name":"input","handle":1,"bytes":10681449,"packets":16216,"family":"ip","table":"filter","use":0,"type":"filter","hooknum":"input","prio":0,"policy":"accept"}},{"chain":{"name":"forward","handle":2,"bytes":0,"packets":0,"family":"ip","table":"filter","use":0,"type":"filter","hooknum":"forward","prio":0,"policy":"accept"}},{"chain":{"name":"output","handle":3,"bytes":2375830,"packets":15184,"family":"ip","table":"filter","use":0,"type":"filter","hooknum":"output","prio":0,"policy":"accept"}},{"chain":{"name":"chain1","handle":4,"bytes":0,"packets":0,"family":"ip","table":"filter","use":0}},{"set":{"name":"set0","table":"filter","flags":3,"family"
 :"ip","key_type":12,"key_len":2}},{"rule":{"family":"ip","table":"filter","chain":"output","handle":6,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x0100a8c0"}},{"type":"counter","pkts":0,"bytes":0},{"type":"immediate","dreg":0,"data_reg":{"type":"verdict","verdict":"drop"}}]}},{"rule":{"family":"ip","table":"filter","chain":"output","handle":9,"expr":[{"type":"payload","dreg":1,"offset":9,"len":1,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":1,"data0":"0x00000006"}},{"type":"payload","dreg":1,"offset":2,"len":2,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":2,"data0":"0x00001600"}},{"type":"counter","pkts":0,"bytes":0}
 ]}},{"rule":{"family":"ip","table":"filter","chain":"output","handle":10,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x0100a8c0"}},{"type":"counter","pkts":0,"bytes":0}]}},{"rule":{"family":"ip","table":"filter","chain":"output","handle":11,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x0100a8c0"}},{"type":"counter","pkts":0,"bytes":0},{"type":"immediate","dreg":0,"data_reg":{"type":"verdict","verdict":"drop"}}]}}]}
+{"nftables":[{"table":{"name":"filter","family":"ip","flags":0,"use":0}},{"table":{"name":"filter2","family":"ip6","flags":0,"use":0}},{"chain":{"name":"input","handle":1,"bytes":10681449,"packets":16216,"table":"filter","family":"ip","use":0,"type":"filter","hooknum":"input","prio":0,"policy":"accept"}},{"chain":{"name":"forward","handle":2,"bytes":0,"packets":0,"table":"filter","family":"ip","use":0,"type":"filter","hooknum":"forward","prio":0,"policy":"accept"}},{"chain":{"name":"output","handle":3,"bytes":2375830,"packets":15184,"table":"filter","family":"ip","use":0,"type":"filter","hooknum":"output","prio":0,"policy":"accept"}},{"chain":{"name":"chain1","handle":4,"bytes":0,"packets":0,"table":"filter","family":"ip","use":0}},{"set":{"name":"set0","table":"filter","flags":3,"family"
 :"ip","key_type":12,"key_len":2}},{"rule":{"family":"ip","table":"filter","chain":"output","handle":6,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x0100a8c0"}}},{"type":"counter","pkts":0,"bytes":0},{"type":"immediate","dreg":0,"data":{"reg":{"type":"verdict","verdict":"drop"}}}]}},{"rule":{"family":"ip","table":"filter","chain":"output","handle":9,"expr":[{"type":"payload","dreg":1,"offset":9,"len":1,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":1,"data0":"0x00000006"}}},{"type":"payload","dreg":1,"offset":2,"len":2,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":2,"data0":"0x00001600"}}},{"type":"counter","pk
 ts":0,"bytes":0}]}},{"rule":{"family":"ip","table":"filter","chain":"output","handle":10,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x0100a8c0"}}},{"type":"counter","pkts":0,"bytes":0}]}},{"rule":{"family":"ip","table":"filter","chain":"output","handle":11,"expr":[{"type":"payload","dreg":1,"offset":16,"len":4,"base":"link"},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x0100a8c0"}}},{"type":"counter","pkts":0,"bytes":0},{"type":"immediate","dreg":0,"data":{"reg":{"type":"verdict","verdict":"drop"}}}]}}]}
diff --git a/tests/jsonfiles/65-rule-meta-target.json b/tests/jsonfiles/65-rule-meta-target.json
index bf1bcaa..e6180d6 100644
--- a/tests/jsonfiles/65-rule-meta-target.json
+++ b/tests/jsonfiles/65-rule-meta-target.json
@@ -1 +1 @@
-{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":1,"expr":[{"type":"meta","key":"mark","sreg":1},{"type":"cmp","sreg":1,"op":"eq","data_reg":{"type":"value","len":4,"data0":"0x000003e8"}},{"type":"counter","pkts":0,"bytes":0}]}}]}
+{"nftables":[{"rule":{"family":"ip","table":"filter","chain":"output","handle":1,"expr":[{"type":"meta","key":"mark","sreg":1},{"type":"cmp","sreg":1,"op":"eq","data":{"reg":{"type":"value","len":4,"data0":"0x000003e8"}}},{"type":"counter","pkts":0,"bytes":0}]}}]}
diff --git a/tests/xmlfiles/20-rule-bitwise.xml b/tests/xmlfiles/20-rule-bitwise.xml
index 756b22c..9b38437 100644
--- a/tests/xmlfiles/20-rule-bitwise.xml
+++ b/tests/xmlfiles/20-rule-bitwise.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>INPUT</chain><handle>100</handle><expr type="bitwise"><sreg>1</sreg><dreg>1</dreg><len>4</len><mask><data_reg type="value"><len>4</len><data0>0x0000000a</data0></data_reg></mask><xor><data_reg type="value"><len>4</len><data0>0x00000000</data0></data_reg></xor></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>INPUT</chain><handle>100</handle><expr type="bitwise"><sreg>1</sreg><dreg>1</dreg><len>4</len><mask><reg type="value"><len>4</len><data0>0x0000000a</data0></reg></mask><xor><reg type="value"><len>4</len><data0>0x00000000</data0></reg></xor></expr></rule></nftables>
diff --git a/tests/xmlfiles/22-rule-cmp.xml b/tests/xmlfiles/22-rule-cmp.xml
index a0371a3..4e66993 100644
--- a/tests/xmlfiles/22-rule-cmp.xml
+++ b/tests/xmlfiles/22-rule-cmp.xml
@@ -1 +1 @@
-<nftables><rule><family>ip6</family><table>filter</table><chain>test</chain><handle>36</handle><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>16</len><data0>0x00000000</data0><data1>0x6e6f6200</data1><data2>0x2e303164</data2><data3>0x00393331</data3></data_reg></expr></rule></nftables>
+<nftables><rule><family>ip6</family><table>filter</table><chain>test</chain><handle>36</handle><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>16</len><data0>0x00000000</data0><data1>0x6e6f6200</data1><data2>0x2e303164</data2><data3>0x00393331</data3></reg></data></expr></rule></nftables>
diff --git a/tests/xmlfiles/26-rule-immediate.xml b/tests/xmlfiles/26-rule-immediate.xml
index 0079504..3eed652 100644
--- a/tests/xmlfiles/26-rule-immediate.xml
+++ b/tests/xmlfiles/26-rule-immediate.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>input</chain><handle>32</handle><expr type="immediate"><dreg>0</dreg><data_reg type="verdict"><verdict>accept</verdict></data_reg></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>input</chain><handle>32</handle><expr type="immediate"><dreg>0</dreg><data><reg type="verdict"><verdict>accept</verdict></reg></data></expr></rule></nftables>
diff --git a/tests/xmlfiles/36-rule-real.xml b/tests/xmlfiles/36-rule-real.xml
index 89a37f6..6ebc8ea 100644
--- a/tests/xmlfiles/36-rule-real.xml
+++ b/tests/xmlfiles/36-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>22</handle><expr type="payload"><dreg>1</dreg><offset>12</offset><len>8</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>8</len><data0>0x0100a8c0</data0><data1>0x6400a8c0</data1></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>22</handle><expr type="payload"><dreg>1</dreg><offset>12</offset><len>8</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>8</len><data0>0x0100a8c0</data0><data1>0x6400a8c0</data1></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/37-rule-real.xml b/tests/xmlfiles/37-rule-real.xml
index 7896bbb..8506f19 100644
--- a/tests/xmlfiles/37-rule-real.xml
+++ b/tests/xmlfiles/37-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>INPUT</chain><handle>25</handle><expr type="meta"><dreg>1</dreg><key>iifname</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>16</len><data0>0x00000000</data0><data1>0x00000000</data1><data2>0x65000000</data2><data3>0x00306874</data3></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000006</data0></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>2</len><data0>0x00001600</data0></data_reg></expr><expr type="ct"><dreg>1</
 dreg><key>state</key><dir>original</dir></expr><expr type="bitwise"><sreg>1</sreg><dreg>1</dreg><len>4</len><mask><data_reg type="value"><len>4</len><data0>0x0000000a</data0></data_reg></mask><xor><data_reg type="value"><len>4</len><data0>0x00000000</data0></data_reg></xor></expr><expr type="cmp"><sreg>1</sreg><op>neq</op><data_reg type="value"><len>4</len><data0>0x00000000</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="log"><prefix>testprefix</prefix><group>1</group></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>INPUT</chain><handle>25</handle><expr type="meta"><dreg>1</dreg><key>iifname</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>16</len><data0>0x00000000</data0><data1>0x00000000</data1><data2>0x65000000</data2><data3>0x00306874</data3></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000006</data0></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>2</len><data0>0x00001600</data0></reg></data></expr><expr type="ct">
 <dreg>1</dreg><key>state</key><dir>original</dir></expr><expr type="bitwise"><sreg>1</sreg><dreg>1</dreg><len>4</len><mask><reg type="value"><len>4</len><data0>0x0000000a</data0></reg></mask><xor><reg type="value"><len>4</len><data0>0x00000000</data0></reg></xor></expr><expr type="cmp"><sreg>1</sreg><op>neq</op><data><reg type="value"><len>4</len><data0>0x00000000</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="log"><prefix>testprefix</prefix><group>1</group></expr></rule></nftables>
diff --git a/tests/xmlfiles/38-rule-real.xml b/tests/xmlfiles/38-rule-real.xml
index 612383f..51b1130 100644
--- a/tests/xmlfiles/38-rule-real.xml
+++ b/tests/xmlfiles/38-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>INPUT</chain><handle>30</handle><expr type="payload"><dreg>1</dreg><offset>16</offset><len>4</len><base>network</base></expr><expr type="lookup"><set>set3</set><sreg>1</sreg><dreg>0</dreg></expr><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000006</data0></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>2</len><data0>0x0000bb01</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="immediate"><dreg>0</dreg><data_reg type="verd
 ict"><verdict>accept</verdict></data_reg></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>INPUT</chain><handle>30</handle><expr type="payload"><dreg>1</dreg><offset>16</offset><len>4</len><base>network</base></expr><expr type="lookup"><set>set3</set><sreg>1</sreg><dreg>0</dreg></expr><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000006</data0></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>2</len><data0>0x0000bb01</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="immediate"><dreg>0</dreg><data><reg typ
 e="verdict"><verdict>accept</verdict></reg></data></expr></rule></nftables>
diff --git a/tests/xmlfiles/39-rule-real.xml b/tests/xmlfiles/39-rule-real.xml
index 7b67a10..35b6004 100644
--- a/tests/xmlfiles/39-rule-real.xml
+++ b/tests/xmlfiles/39-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip6</family><table>filter</table><chain>test</chain><handle>31</handle><expr type="meta"><dreg>1</dreg><key>iifname</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>16</len><data0>0x00000000</data0><data1>0x00000000</data1><data2>0x6f620000</data2><data3>0x0030646e</data3></data_reg></expr><expr type="meta"><dreg>1</dreg><key>oifname</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>16</len><data0>0x00000000</data0><data1>0x62000000</data1><data2>0x31646e6f</data2><data3>0x0037322e</data3></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>8</offset><len>16</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>16</len><data0>0xc09a002a</data0><d
 ata1>0x2700cac1</data1><data2>0x00000000</data2><data3>0x50010000</data3></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>6</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000011</data0></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>2</len><data0>0x00003500</data0></data_reg></expr><expr type="ct"><dreg>1</dreg><key>status</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x00000001</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="log"><prefix>dns_d
 rop</prefix><group>2</group></expr><expr type="immediate"><dreg>0</dreg><data_reg type="verdict"><verdict>drop</verdict></data_reg></expr></rule></nftables>
+<nftables><rule><family>ip6</family><table>filter</table><chain>test</chain><handle>31</handle><expr type="meta"><dreg>1</dreg><key>iifname</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>16</len><data0>0x00000000</data0><data1>0x00000000</data1><data2>0x6f620000</data2><data3>0x0030646e</data3></reg></data></expr><expr type="meta"><dreg>1</dreg><key>oifname</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>16</len><data0>0x00000000</data0><data1>0x62000000</data1><data2>0x31646e6f</data2><data3>0x0037322e</data3></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>8</offset><len>16</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>16</len><data0>0xc09a002a</d
 ata0><data1>0x2700cac1</data1><data2>0x00000000</data2><data3>0x50010000</data3></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>6</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000011</data0></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>2</len><data0>0x00003500</data0></reg></data></expr><expr type="ct"><dreg>1</dreg><key>status</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x00000001</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="
 log"><prefix>dns_drop</prefix><group>2</group></expr><expr type="immediate"><dreg>0</dreg><data><reg type="verdict"><verdict>drop</verdict></reg></data></expr></rule></nftables>
diff --git a/tests/xmlfiles/40-rule-real.xml b/tests/xmlfiles/40-rule-real.xml
index 33fb75f..d516164 100644
--- a/tests/xmlfiles/40-rule-real.xml
+++ b/tests/xmlfiles/40-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>2</handle><expr type="payload"><dreg>1</dreg><offset>16</offset><len>4</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x0100a8c0</data0></data_reg></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>2</handle><expr type="payload"><dreg>1</dreg><offset>16</offset><len>4</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x0100a8c0</data0></reg></data></expr></rule></nftables>
diff --git a/tests/xmlfiles/41-rule-real.xml b/tests/xmlfiles/41-rule-real.xml
index 0f7b752..3736404 100644
--- a/tests/xmlfiles/41-rule-real.xml
+++ b/tests/xmlfiles/41-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>3</handle><expr type="payload"><dreg>1</dreg><offset>16</offset><len>4</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>gte</op><data_reg type="value"><len>4</len><data0>0x0100a8c0</data0></data_reg></expr><expr type="cmp"><sreg>1</sreg><op>lte</op><data_reg type="value"><len>4</len><data0>0xfa00a8c0</data0></data_reg></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>3</handle><expr type="payload"><dreg>1</dreg><offset>16</offset><len>4</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>gte</op><data><reg type="value"><len>4</len><data0>0x0100a8c0</data0></reg></data></expr><expr type="cmp"><sreg>1</sreg><op>lte</op><data><reg type="value"><len>4</len><data0>0xfa00a8c0</data0></reg></data></expr></rule></nftables>
diff --git a/tests/xmlfiles/42-rule-real.xml b/tests/xmlfiles/42-rule-real.xml
index e76c6aa..e88d695 100644
--- a/tests/xmlfiles/42-rule-real.xml
+++ b/tests/xmlfiles/42-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>4</handle><expr type="payload"><dreg>1</dreg><offset>16</offset><len>4</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x0100a8c0</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>4</handle><expr type="payload"><dreg>1</dreg><offset>16</offset><len>4</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x0100a8c0</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/43-rule-real.xml b/tests/xmlfiles/43-rule-real.xml
index 907bfa5..4f6219f 100644
--- a/tests/xmlfiles/43-rule-real.xml
+++ b/tests/xmlfiles/43-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>5</handle><expr type="payload"><dreg>1</dreg><offset>16</offset><len>4</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x0100a8c0</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="immediate"><dreg>0</dreg><data_reg type="verdict"><verdict>drop</verdict></data_reg></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>5</handle><expr type="payload"><dreg>1</dreg><offset>16</offset><len>4</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x0100a8c0</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="immediate"><dreg>0</dreg><data><reg type="verdict"><verdict>drop</verdict></reg></data></expr></rule></nftables>
diff --git a/tests/xmlfiles/44-rule-real.xml b/tests/xmlfiles/44-rule-real.xml
index a9bc8d9..4f12c01 100644
--- a/tests/xmlfiles/44-rule-real.xml
+++ b/tests/xmlfiles/44-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>6</handle><expr type="payload"><dreg>1</dreg><offset>16</offset><len>4</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x0100a8c0</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="log"></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>6</handle><expr type="payload"><dreg>1</dreg><offset>16</offset><len>4</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x0100a8c0</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="log"></expr></rule></nftables>
diff --git a/tests/xmlfiles/45-rule-real.xml b/tests/xmlfiles/45-rule-real.xml
index fa2afac..fd2fda2 100644
--- a/tests/xmlfiles/45-rule-real.xml
+++ b/tests/xmlfiles/45-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>7</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000006</data0></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>2</len><data0>0x00001600</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>7</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000006</data0></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>2</len><data0>0x00001600</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/46-rule-real.xml b/tests/xmlfiles/46-rule-real.xml
index a5155bc..58ebedc 100644
--- a/tests/xmlfiles/46-rule-real.xml
+++ b/tests/xmlfiles/46-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>8</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000006</data0></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>0</offset><len>4</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x16000004</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>8</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000006</data0></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>0</offset><len>4</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x16000004</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/47-rule-real.xml b/tests/xmlfiles/47-rule-real.xml
index 798f4f3..44f2a68 100644
--- a/tests/xmlfiles/47-rule-real.xml
+++ b/tests/xmlfiles/47-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>9</handle><expr type="payload"><dreg>1</dreg><offset>12</offset><len>8</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>8</len><data0>0x0100a8c0</data0><data1>0x6400a8c0</data1></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>9</handle><expr type="payload"><dreg>1</dreg><offset>12</offset><len>8</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>8</len><data0>0x0100a8c0</data0><data1>0x6400a8c0</data1></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/48-rule-real.xml b/tests/xmlfiles/48-rule-real.xml
index 509a299..7f8562f 100644
--- a/tests/xmlfiles/48-rule-real.xml
+++ b/tests/xmlfiles/48-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>10</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000006</data0></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>0</offset><len>8</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>8</len><data0>0x16000004</data0><data1>0x00000000</data1></data_reg></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>10</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000006</data0></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>0</offset><len>8</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>8</len><data0>0x16000004</data0><data1>0x00000000</data1></reg></data></expr></rule></nftables>
diff --git a/tests/xmlfiles/49-rule-real.xml b/tests/xmlfiles/49-rule-real.xml
index bc1a6ad..ce73edc 100644
--- a/tests/xmlfiles/49-rule-real.xml
+++ b/tests/xmlfiles/49-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>11</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000006</data0></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>0</offset><len>8</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>8</len><data0>0x16000004</data0><data1>0x00000000</data1></data_reg></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>11</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000006</data0></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>0</offset><len>8</len><base>transport</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>8</len><data0>0x16000004</data0><data1>0x00000000</data1></reg></data></expr></rule></nftables>
diff --git a/tests/xmlfiles/50-rule-real.xml b/tests/xmlfiles/50-rule-real.xml
index 5b100e6..0df5270 100644
--- a/tests/xmlfiles/50-rule-real.xml
+++ b/tests/xmlfiles/50-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>12</handle><expr type="ct"><dreg>1</dreg><key>state</key><dir>original</dir></expr><expr type="bitwise"><sreg>1</sreg><dreg>1</dreg><len>4</len><mask><data_reg type="value"><len>4</len><data0>0x0000000a</data0></data_reg></mask><xor><data_reg type="value"><len>4</len><data0>0x00000000</data0></data_reg></xor></expr><expr type="cmp"><sreg>1</sreg><op>neq</op><data_reg type="value"><len>4</len><data0>0x00000000</data0></data_reg></expr><expr type="counter"><pkts>55</pkts><bytes>11407</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>12</handle><expr type="ct"><dreg>1</dreg><key>state</key><dir>original</dir></expr><expr type="bitwise"><sreg>1</sreg><dreg>1</dreg><len>4</len><mask><reg type="value"><len>4</len><data0>0x0000000a</data0></reg></mask><xor><reg type="value"><len>4</len><data0>0x00000000</data0></reg></xor></expr><expr type="cmp"><sreg>1</sreg><op>neq</op><data><reg type="value"><len>4</len><data0>0x00000000</data0></reg></data></expr><expr type="counter"><pkts>55</pkts><bytes>11407</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/51-rule-real.xml b/tests/xmlfiles/51-rule-real.xml
index 555dddd..f00ee71 100644
--- a/tests/xmlfiles/51-rule-real.xml
+++ b/tests/xmlfiles/51-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>13</handle><expr type="ct"><dreg>1</dreg><key>direction</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000000</data0></data_reg></expr><expr type="counter"><pkts>5</pkts><bytes>160</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>13</handle><expr type="ct"><dreg>1</dreg><key>direction</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000000</data0></reg></data></expr><expr type="counter"><pkts>5</pkts><bytes>160</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/52-rule-real.xml b/tests/xmlfiles/52-rule-real.xml
index f86ad01..0205214 100644
--- a/tests/xmlfiles/52-rule-real.xml
+++ b/tests/xmlfiles/52-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>14</handle><expr type="ct"><dreg>1</dreg><key>direction</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000001</data0></data_reg></expr><expr type="counter"><pkts>50</pkts><bytes>11247</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>14</handle><expr type="ct"><dreg>1</dreg><key>direction</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000001</data0></reg></data></expr><expr type="counter"><pkts>50</pkts><bytes>11247</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/53-rule-real.xml b/tests/xmlfiles/53-rule-real.xml
index d257fa6..cfdac8f 100644
--- a/tests/xmlfiles/53-rule-real.xml
+++ b/tests/xmlfiles/53-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>15</handle><expr type="ct"><dreg>1</dreg><key>status</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x00000001</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>15</handle><expr type="ct"><dreg>1</dreg><key>status</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x00000001</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/54-rule-real.xml b/tests/xmlfiles/54-rule-real.xml
index 55280d6..7451d5f 100644
--- a/tests/xmlfiles/54-rule-real.xml
+++ b/tests/xmlfiles/54-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>16</handle><expr type="ct"><dreg>1</dreg><key>mark</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x00000064</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>16</handle><expr type="ct"><dreg>1</dreg><key>mark</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x00000064</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/55-rule-real.xml b/tests/xmlfiles/55-rule-real.xml
index e3333a1..c35eef0 100644
--- a/tests/xmlfiles/55-rule-real.xml
+++ b/tests/xmlfiles/55-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>17</handle><expr type="ct"><dreg>1</dreg><key>secmark</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x00000000</data0></data_reg></expr><expr type="counter"><pkts>55</pkts><bytes>11407</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>17</handle><expr type="ct"><dreg>1</dreg><key>secmark</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x00000000</data0></reg></data></expr><expr type="counter"><pkts>55</pkts><bytes>11407</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/56-rule-real.xml b/tests/xmlfiles/56-rule-real.xml
index 90d91f1..3f30f5e 100644
--- a/tests/xmlfiles/56-rule-real.xml
+++ b/tests/xmlfiles/56-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>18</handle><expr type="ct"><dreg>1</dreg><key>expiration</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x0000001e</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>18</handle><expr type="ct"><dreg>1</dreg><key>expiration</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x0000001e</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/57-rule-real.xml b/tests/xmlfiles/57-rule-real.xml
index 61d662f..1c5f4c0 100644
--- a/tests/xmlfiles/57-rule-real.xml
+++ b/tests/xmlfiles/57-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>19</handle><expr type="ct"><dreg>1</dreg><key>helper</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x00707466</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>19</handle><expr type="ct"><dreg>1</dreg><key>helper</key><dir>original</dir></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x00707466</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/58-rule-real.xml b/tests/xmlfiles/58-rule-real.xml
index 5a7f5d7..14787f6 100644
--- a/tests/xmlfiles/58-rule-real.xml
+++ b/tests/xmlfiles/58-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>20</handle><expr type="meta"><dreg>1</dreg><key>len</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x000003e8</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>20</handle><expr type="meta"><dreg>1</dreg><key>len</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x000003e8</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/59-rule-real.xml b/tests/xmlfiles/59-rule-real.xml
index a596479..92ad83f 100644
--- a/tests/xmlfiles/59-rule-real.xml
+++ b/tests/xmlfiles/59-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>21</handle><expr type="meta"><dreg>1</dreg><key>protocol</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>2</len><data0>0x00000008</data0></data_reg></expr><expr type="counter"><pkts>55</pkts><bytes>11407</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>21</handle><expr type="meta"><dreg>1</dreg><key>protocol</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>2</len><data0>0x00000008</data0></reg></data></expr><expr type="counter"><pkts>55</pkts><bytes>11407</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/60-rule-real.xml b/tests/xmlfiles/60-rule-real.xml
index 7c8437f..70234a6 100644
--- a/tests/xmlfiles/60-rule-real.xml
+++ b/tests/xmlfiles/60-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>22</handle><expr type="meta"><dreg>1</dreg><key>mark</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x00000000</data0></data_reg></expr><expr type="counter"><pkts>55</pkts><bytes>11407</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>22</handle><expr type="meta"><dreg>1</dreg><key>mark</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x00000000</data0></reg></data></expr><expr type="counter"><pkts>55</pkts><bytes>11407</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/61-rule-real.xml b/tests/xmlfiles/61-rule-real.xml
index 2ed9517..786e84a 100644
--- a/tests/xmlfiles/61-rule-real.xml
+++ b/tests/xmlfiles/61-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>23</handle><expr type="meta"><dreg>1</dreg><key>iif</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x00000001</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>23</handle><expr type="meta"><dreg>1</dreg><key>iif</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x00000001</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/62-rule-real.xml b/tests/xmlfiles/62-rule-real.xml
index 1bcf040..86d3499 100644
--- a/tests/xmlfiles/62-rule-real.xml
+++ b/tests/xmlfiles/62-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>24</handle><expr type="meta"><dreg>1</dreg><key>iifname</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>16</len><data0>0x00000000</data0><data1>0x00000000</data1><data2>0x65000000</data2><data3>0x00306874</data3></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>24</handle><expr type="meta"><dreg>1</dreg><key>iifname</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>16</len><data0>0x00000000</data0><data1>0x00000000</data1><data2>0x65000000</data2><data3>0x00306874</data3></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/63-rule-real.xml b/tests/xmlfiles/63-rule-real.xml
index 153cd8f..af0b87d 100644
--- a/tests/xmlfiles/63-rule-real.xml
+++ b/tests/xmlfiles/63-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>25</handle><expr type="meta"><dreg>1</dreg><key>oif</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x00000001</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>25</handle><expr type="meta"><dreg>1</dreg><key>oif</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x00000001</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/64-rule-real.xml b/tests/xmlfiles/64-rule-real.xml
index 85f2cfc..f14c95c 100644
--- a/tests/xmlfiles/64-rule-real.xml
+++ b/tests/xmlfiles/64-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>26</handle><expr type="meta"><dreg>1</dreg><key>oifname</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>16</len><data0>0x00000000</data0><data1>0x00000000</data1><data2>0x65000000</data2><data3>0x00306874</data3></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>26</handle><expr type="meta"><dreg>1</dreg><key>oifname</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>16</len><data0>0x00000000</data0><data1>0x00000000</data1><data2>0x65000000</data2><data3>0x00306874</data3></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/65-rule-real.xml b/tests/xmlfiles/65-rule-real.xml
index 74a1ae3..b3d37b1 100644
--- a/tests/xmlfiles/65-rule-real.xml
+++ b/tests/xmlfiles/65-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>27</handle><expr type="meta"><dreg>1</dreg><key>skuid</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x000003e8</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>27</handle><expr type="meta"><dreg>1</dreg><key>skuid</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x000003e8</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/66-rule-real.xml b/tests/xmlfiles/66-rule-real.xml
index db93413..95ea4cd 100644
--- a/tests/xmlfiles/66-rule-real.xml
+++ b/tests/xmlfiles/66-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>28</handle><expr type="meta"><dreg>1</dreg><key>skgid</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x000003e8</data0></data_reg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>28</handle><expr type="meta"><dreg>1</dreg><key>skgid</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x000003e8</data0></reg></data></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/67-rule-real.xml b/tests/xmlfiles/67-rule-real.xml
index 9fa0bd2..197be85 100644
--- a/tests/xmlfiles/67-rule-real.xml
+++ b/tests/xmlfiles/67-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>29</handle><expr type="meta"><dreg>1</dreg><key>secmark</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>4</len><data0>0x00000000</data0></data_reg></expr><expr type="counter"><pkts>55</pkts><bytes>11407</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>29</handle><expr type="meta"><dreg>1</dreg><key>secmark</key></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>4</len><data0>0x00000000</data0></reg></data></expr><expr type="counter"><pkts>55</pkts><bytes>11407</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/68-rule-real.xml b/tests/xmlfiles/68-rule-real.xml
index 07f6066..a09698d 100644
--- a/tests/xmlfiles/68-rule-real.xml
+++ b/tests/xmlfiles/68-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>32</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000006</data0></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="lookup"><set>set0</set><sreg>1</sreg><dreg>0</dreg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>32</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000006</data0></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="lookup"><set>set0</set><sreg>1</sreg><dreg>0</dreg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr></rule></nftables>
diff --git a/tests/xmlfiles/70-rule-real.xml b/tests/xmlfiles/70-rule-real.xml
index 3b882b0..d35a252 100644
--- a/tests/xmlfiles/70-rule-real.xml
+++ b/tests/xmlfiles/70-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>34</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000006</data0></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="lookup"><set>map0</set><sreg>1</sreg><dreg>0</dreg></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>34</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000006</data0></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="lookup"><set>map0</set><sreg>1</sreg><dreg>0</dreg></expr></rule></nftables>
diff --git a/tests/xmlfiles/71-rule-real.xml b/tests/xmlfiles/71-rule-real.xml
index dffa2a6..c838a60 100644
--- a/tests/xmlfiles/71-rule-real.xml
+++ b/tests/xmlfiles/71-rule-real.xml
@@ -1 +1 @@
-<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>35</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000006</data0></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="lookup"><set>map1</set><sreg>1</sreg><dreg>0</dreg></expr></rule></nftables>
+<nftables><rule><family>ip</family><table>filter</table><chain>output</chain><handle>35</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000006</data0></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="lookup"><set>map1</set><sreg>1</sreg><dreg>0</dreg></expr></rule></nftables>
diff --git a/tests/xmlfiles/73-set.xml b/tests/xmlfiles/73-set.xml
index 1af61fa..856e1f9 100644
--- a/tests/xmlfiles/73-set.xml
+++ b/tests/xmlfiles/73-set.xml
@@ -1 +1 @@
-<nftables><set><family>ip</family><table>filter</table><name>set0</name><key_type>0</key_type><key_len>0</key_len><data_type>0</data_type><data_len>0</data_len><set_elem><key><data_reg type="value"><len>4</len><data0>0x0300a8c0</data0></data_reg></key></set_elem><set_elem><key><data_reg type="value"><len>4</len><data0>0x0200a8c0</data0></data_reg></key></set_elem><set_elem><key><data_reg type="value"><len>4</len><data0>0x0100a8c0</data0></data_reg></key></set_elem></set></nftables>
+<nftables><set><family>ip</family><table>filter</table><name>set0</name><key_type>0</key_type><key_len>0</key_len><data_type>0</data_type><data_len>0</data_len><set_elem><key><reg type="value"><len>4</len><data0>0x0300a8c0</data0></reg></key></set_elem><set_elem><key><reg type="value"><len>4</len><data0>0x0200a8c0</data0></reg></key></set_elem><set_elem><key><reg type="value"><len>4</len><data0>0x0100a8c0</data0></reg></key></set_elem></set></nftables>
diff --git a/tests/xmlfiles/74-set.xml b/tests/xmlfiles/74-set.xml
index a8cabaf..c5be4e5 100644
--- a/tests/xmlfiles/74-set.xml
+++ b/tests/xmlfiles/74-set.xml
@@ -1 +1 @@
-<nftables><set><family>ip6</family><table>filter</table><name>set0</name><key_type>0</key_type><key_len>0</key_len><data_type>0</data_type><data_len>0</data_len><set_elem><key><data_reg type="value"><len>16</len><data0>0xc09a002a</data0><data1>0x2700cac1</data1><data2>0x00000000</data2><data3>0x70010000</data3></data_reg></key></set_elem><set_elem><key><data_reg type="value"><len>16</len><data0>0xc09a002a</data0><data1>0x2700cac1</data1><data2>0x00000000</data2><data3>0x50010000</data3></data_reg></key></set_elem></set></nftables>
+<nftables><set><family>ip6</family><table>filter</table><name>set0</name><key_type>0</key_type><key_len>0</key_len><data_type>0</data_type><data_len>0</data_len><set_elem><key><reg type="value"><len>16</len><data0>0xc09a002a</data0><data1>0x2700cac1</data1><data2>0x00000000</data2><data3>0x70010000</data3></reg></key></set_elem><set_elem><key><reg type="value"><len>16</len><data0>0xc09a002a</data0><data1>0x2700cac1</data1><data2>0x00000000</data2><data3>0x50010000</data3></reg></key></set_elem></set></nftables>
diff --git a/tests/xmlfiles/75-ruleset.xml b/tests/xmlfiles/75-ruleset.xml
index 0eb4075..363a567 100644
--- a/tests/xmlfiles/75-ruleset.xml
+++ b/tests/xmlfiles/75-ruleset.xml
@@ -1 +1 @@
-<nftables><table><name>filter</name><family>ip</family><flags>0</flags><use>0</use></table><table><name>filter</name><family>ip6</family><flags>0</flags><use>0</use></table><chain><name>input</name><handle>1</handle><bytes>0</bytes><packets>0</packets><table>filter</table><family>ip</family></chain><chain><name>output</name><handle>2</handle><bytes>0</bytes><packets>0</packets><table>filter</table><family>ip</family></chain><chain><name>forward</name><handle>1</handle><bytes>0</bytes><packets>0</packets><table>filter</table><family>ip6</family></chain><set><family>ip6</family><table>filter</table><name>set0</name><flags>3</flags><key_type>12</key_type><key_len>2</key_len><data_type>0</data_type><data_len>0</data_len><set_elem><key><data_reg type="value"><len>2</len><data0>0x00004300</data
 0></data_reg></key></set_elem><set_elem><key><data_reg type="value"><len>2</len><data0>0x00003500</data0></data_reg></key></set_elem></set><set><family>ip</family><table>filter</table><name>map0</name><flags>11</flags><key_type>12</key_type><key_len>2</key_len><data_type>4294967040</data_type><data_len>16</data_len><set_elem><key><data_reg type="value"><len>2</len><data0>0x00005000</data0></data_reg></key><data><data_reg type="verdict"><verdict>drop</verdict></data_reg></data></set_elem><set_elem><key><data_reg type="value"><len>2</len><data0>0x00001600</data0></data_reg></key><data><data_reg type="verdict"><verdict>accept</verdict></data_reg></data></set_elem></set><rule><family>ip</family><table>filter</table><chain>input</chain><handle>8</handle><expr type="counter"><pkts>0</pkts><byt
 es>0</bytes></expr><expr type="immediate"><dreg>0</dreg><data_reg type="verdict"><verdict>accept</verdict></data_reg></expr></rule><rule><family>ip</family><table>filter</table><chain>output</chain><handle>9</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000006</data0></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="lookup"><set>map0</set><sreg>1</sreg><dreg>0</dreg></expr></rule><rule><family>ip6</family><table>filter</table><chain>forward</chain><handle>2</handle><expr type="payload"><dreg>1</dreg><offset>6</offset><len>1</len><base>network</base></expr><expr type="cmp"><sr
 eg>1</sreg><op>eq</op><data_reg type="value"><len>1</len><data0>0x00000011</data0></data_reg></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="lookup"><set>set0</set><sreg>1</sreg><dreg>0</dreg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="immediate"><dreg>0</dreg><data_reg type="verdict"><verdict>accept</verdict></data_reg></expr></rule></nftables>
+<nftables><table><name>filter</name><family>ip</family><flags>0</flags><use>0</use></table><table><name>filter</name><family>ip6</family><flags>0</flags><use>0</use></table><chain><name>input</name><handle>1</handle><bytes>0</bytes><packets>0</packets><table>filter</table><family>ip</family></chain><chain><name>output</name><handle>2</handle><bytes>0</bytes><packets>0</packets><table>filter</table><family>ip</family></chain><chain><name>forward</name><handle>1</handle><bytes>0</bytes><packets>0</packets><table>filter</table><family>ip6</family></chain><set><family>ip6</family><table>filter</table><name>set0</name><flags>3</flags><key_type>12</key_type><key_len>2</key_len><data_type>0</data_type><data_len>0</data_len><set_elem><key><reg type="value"><len>2</len><data0>0x00004300</data0></r
 eg></key></set_elem><set_elem><key><reg type="value"><len>2</len><data0>0x00003500</data0></reg></key></set_elem></set><set><family>ip</family><table>filter</table><name>map0</name><flags>11</flags><key_type>12</key_type><key_len>2</key_len><data_type>4294967040</data_type><data_len>16</data_len><set_elem><key><reg type="value"><len>2</len><data0>0x00005000</data0></reg></key><data><reg type="verdict"><verdict>drop</verdict></reg></data></set_elem><set_elem><key><reg type="value"><len>2</len><data0>0x00001600</data0></reg></key><data><reg type="verdict"><verdict>accept</verdict></reg></data></set_elem></set><rule><family>ip</family><table>filter</table><chain>input</chain><handle>8</handle><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="immediate"><dreg>0</dreg><dat
 a><reg type="verdict"><verdict>accept</verdict></reg></data></expr></rule><rule><family>ip</family><table>filter</table><chain>output</chain><handle>9</handle><expr type="payload"><dreg>1</dreg><offset>9</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</len><data0>0x00000006</data0></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="lookup"><set>map0</set><sreg>1</sreg><dreg>0</dreg></expr></rule><rule><family>ip6</family><table>filter</table><chain>forward</chain><handle>2</handle><expr type="payload"><dreg>1</dreg><offset>6</offset><len>1</len><base>network</base></expr><expr type="cmp"><sreg>1</sreg><op>eq</op><data><reg type="value"><len>1</
 len><data0>0x00000011</data0></reg></data></expr><expr type="payload"><dreg>1</dreg><offset>2</offset><len>2</len><base>transport</base></expr><expr type="lookup"><set>set0</set><sreg>1</sreg><dreg>0</dreg></expr><expr type="counter"><pkts>0</pkts><bytes>0</bytes></expr><expr type="immediate"><dreg>0</dreg><data><reg type="verdict"><verdict>accept</verdict></reg></data></expr></rule></nftables>
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2014-11-10 13:24 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-10 13:26 [PATCH libnftnl 1/3] expr: nat: use 'nat_type' instead of 'type' in the parser Pablo Neira Ayuso
2014-11-10 13:26 ` [PATCH libnftnl 2/3 v2] src: consolidate XML/JSON exportation Pablo Neira Ayuso
2014-11-10 13:26 ` [PATCH libnftnl 3/3] expr: data_reg: use 'reg' instead of 'data_reg' Pablo Neira Ayuso

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).