Blame SOURCES/0005-monitor-Use-libnftables-JSON-output.patch

9ff721
From 53693c43d94dddf1ae1a0e69bfa953fba2c098e0 Mon Sep 17 00:00:00 2001
9ff721
From: Phil Sutter <phil@nwl.cc>
9ff721
Date: Thu, 11 Oct 2018 17:49:00 +0200
9ff721
Subject: [PATCH] monitor: Use libnftables JSON output
9ff721
9ff721
This switches 'nft monitor' JSON output from using libnftnl's to
9ff721
libnftables' implementation.
9ff721
9ff721
Signed-off-by: Phil Sutter <phil@nwl.cc>
9ff721
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
9ff721
(cherry picked from commit 9e88aae28e9f44d010f3ecf7577357f4c0e7d622)
9ff721
Signed-off-by: Phil Sutter <psutter@redhat.com>
9ff721
---
9ff721
 include/json.h |  51 +++++++++
9ff721
 src/json.c     |  57 ++++++++++
9ff721
 src/monitor.c  | 281 +++++++++++++++++++++++++------------------------
9ff721
 src/rule.c     |   2 -
9ff721
 4 files changed, 251 insertions(+), 140 deletions(-)
9ff721
9ff721
diff --git a/include/json.h b/include/json.h
9ff721
index ae3938142aeac..af0f72f13dd60 100644
9ff721
--- a/include/json.h
9ff721
+++ b/include/json.h
9ff721
@@ -9,9 +9,11 @@ struct expr;
9ff721
 struct netlink_ctx;
9ff721
 struct rule;
9ff721
 struct set;
9ff721
+struct obj;
9ff721
 struct stmt;
9ff721
 struct symbol_table;
9ff721
 struct table;
9ff721
+struct netlink_mon_handler;
9ff721
 
9ff721
 #ifdef HAVE_LIBJANSSON
9ff721
 
9ff721
@@ -81,6 +83,19 @@ int nft_parse_json_buffer(struct nft_ctx *nft, char *buf, size_t buflen,
9ff721
 int nft_parse_json_filename(struct nft_ctx *nft, const char *filename,
9ff721
 			    struct list_head *msgs, struct list_head *cmds);
9ff721
 
9ff721
+void monitor_print_table_json(struct netlink_mon_handler *monh,
9ff721
+			      const char *cmd, struct table *t);
9ff721
+void monitor_print_chain_json(struct netlink_mon_handler *monh,
9ff721
+			      const char *cmd, struct chain *c);
9ff721
+void monitor_print_set_json(struct netlink_mon_handler *monh,
9ff721
+			    const char *cmd, struct set *s);
9ff721
+void monitor_print_element_json(struct netlink_mon_handler *monh,
9ff721
+				const char *cmd, struct set *s);
9ff721
+void monitor_print_obj_json(struct netlink_mon_handler *monh,
9ff721
+			    const char *cmd, struct obj *o);
9ff721
+void monitor_print_rule_json(struct netlink_mon_handler *monh,
9ff721
+			     const char *cmd, struct rule *r);
9ff721
+
9ff721
 #else /* ! HAVE_LIBJANSSON */
9ff721
 
9ff721
 typedef void json_t;
9ff721
@@ -176,6 +191,42 @@ nft_parse_json_filename(struct nft_ctx *nft, const char *filename,
9ff721
 	return -EINVAL;
9ff721
 }
9ff721
 
9ff721
+static inline void monitor_print_table_json(struct netlink_mon_handler *monh,
9ff721
+					    const char *cmd, struct table *t)
9ff721
+{
9ff721
+	/* empty */
9ff721
+}
9ff721
+
9ff721
+static inline void monitor_print_chain_json(struct netlink_mon_handler *monh,
9ff721
+					    const char *cmd, struct chain *c)
9ff721
+{
9ff721
+	/* empty */
9ff721
+}
9ff721
+
9ff721
+static inline void monitor_print_set_json(struct netlink_mon_handler *monh,
9ff721
+					  const char *cmd, struct set *s)
9ff721
+{
9ff721
+	/* empty */
9ff721
+}
9ff721
+
9ff721
+static inline void monitor_print_element_json(struct netlink_mon_handler *monh,
9ff721
+					      const char *cmd, struct set *s)
9ff721
+{
9ff721
+	/* empty */
9ff721
+}
9ff721
+
9ff721
+static inline void monitor_print_obj_json(struct netlink_mon_handler *monh,
9ff721
+					  const char *cmd, struct obj *o)
9ff721
+{
9ff721
+	/* empty */
9ff721
+}
9ff721
+
9ff721
+static inline void monitor_print_rule_json(struct netlink_mon_handler *monh,
9ff721
+					   const char *cmd, struct rule *r)
9ff721
+{
9ff721
+	/* empty */
9ff721
+}
9ff721
+
9ff721
 #endif /* HAVE_LIBJANSSON */
9ff721
 
9ff721
 #endif /* NFTABLES_JSON_H */
9ff721
diff --git a/src/json.c b/src/json.c
9ff721
index af157212c081e..7d89754bd666d 100644
9ff721
--- a/src/json.c
9ff721
+++ b/src/json.c
9ff721
@@ -147,6 +147,19 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
9ff721
 	return json_pack("{s:o}", type, root);
9ff721
 }
9ff721
 
9ff721
+/* XXX: Merge with set_print_json()? */
9ff721
+static json_t *element_print_json(struct output_ctx *octx,
9ff721
+				  const struct set *set)
9ff721
+{
9ff721
+	json_t *root = expr_print_json(set->init, octx);
9ff721
+
9ff721
+	return json_pack("{s: {s:s, s:s, s:s, s:o}}", "element",
9ff721
+			 "family", family2str(set->handle.family),
9ff721
+			 "table", set->handle.table.name,
9ff721
+			 "name", set->handle.set.name,
9ff721
+			 "elem", root);
9ff721
+}
9ff721
+
9ff721
 static json_t *stmt_print_json(const struct stmt *stmt, struct output_ctx *octx)
9ff721
 {
9ff721
 	char buf[1024];
9ff721
@@ -1554,3 +1567,47 @@ int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
9ff721
 	json_decref(root);
9ff721
 	return 0;
9ff721
 }
9ff721
+
9ff721
+static void monitor_print_json(struct netlink_mon_handler *monh,
9ff721
+			       const char *cmd, json_t *obj)
9ff721
+{
9ff721
+	obj = json_pack("{s:o}", cmd, obj);
9ff721
+	json_dumpf(obj, monh->ctx->octx->output_fp, 0);
9ff721
+	json_decref(obj);
9ff721
+}
9ff721
+
9ff721
+void monitor_print_table_json(struct netlink_mon_handler *monh,
9ff721
+			      const char *cmd, struct table *t)
9ff721
+{
9ff721
+	monitor_print_json(monh, cmd, table_print_json(monh->ctx->octx, t));
9ff721
+}
9ff721
+
9ff721
+void monitor_print_chain_json(struct netlink_mon_handler *monh,
9ff721
+			      const char *cmd, struct chain *c)
9ff721
+{
9ff721
+	monitor_print_json(monh, cmd, chain_print_json(monh->ctx->octx, c));
9ff721
+}
9ff721
+
9ff721
+void monitor_print_set_json(struct netlink_mon_handler *monh,
9ff721
+			    const char *cmd, struct set *s)
9ff721
+{
9ff721
+	monitor_print_json(monh, cmd, set_print_json(monh->ctx->octx, s));
9ff721
+}
9ff721
+
9ff721
+void monitor_print_element_json(struct netlink_mon_handler *monh,
9ff721
+				const char *cmd, struct set *s)
9ff721
+{
9ff721
+	monitor_print_json(monh, cmd, element_print_json(monh->ctx->octx, s));
9ff721
+}
9ff721
+
9ff721
+void monitor_print_obj_json(struct netlink_mon_handler *monh,
9ff721
+			    const char *cmd, struct obj *o)
9ff721
+{
9ff721
+	monitor_print_json(monh, cmd, obj_print_json(monh->ctx->octx, o));
9ff721
+}
9ff721
+
9ff721
+void monitor_print_rule_json(struct netlink_mon_handler *monh,
9ff721
+			     const char *cmd, struct rule *r)
9ff721
+{
9ff721
+	monitor_print_json(monh, cmd, rule_print_json(monh->ctx->octx, r));
9ff721
+}
9ff721
diff --git a/src/monitor.c b/src/monitor.c
9ff721
index 3e70b89f0b2ab..213c40d119b4c 100644
9ff721
--- a/src/monitor.c
9ff721
+++ b/src/monitor.c
9ff721
@@ -38,6 +38,7 @@
9ff721
 #include <utils.h>
9ff721
 #include <erec.h>
9ff721
 #include <iface.h>
9ff721
+#include <json.h>
9ff721
 
9ff721
 #define nft_mon_print(monh, ...) nft_print(monh->ctx->octx, __VA_ARGS__)
9ff721
 
9ff721
@@ -127,18 +128,39 @@ static uint32_t netlink_msg2nftnl_of(uint32_t msg)
9ff721
 	case NFT_MSG_NEWSET:
9ff721
 	case NFT_MSG_NEWSETELEM:
9ff721
 	case NFT_MSG_NEWRULE:
9ff721
+	case NFT_MSG_NEWOBJ:
9ff721
+	case NFT_MSG_NEWFLOWTABLE:
9ff721
 		return NFTNL_OF_EVENT_NEW;
9ff721
 	case NFT_MSG_DELTABLE:
9ff721
 	case NFT_MSG_DELCHAIN:
9ff721
 	case NFT_MSG_DELSET:
9ff721
 	case NFT_MSG_DELSETELEM:
9ff721
 	case NFT_MSG_DELRULE:
9ff721
+	case NFT_MSG_DELOBJ:
9ff721
+	case NFT_MSG_DELFLOWTABLE:
9ff721
 		return NFTNL_OF_EVENT_DEL;
9ff721
 	}
9ff721
 
9ff721
 	return 0;
9ff721
 }
9ff721
 
9ff721
+static const char *nftnl_of2cmd(uint32_t of)
9ff721
+{
9ff721
+	switch (of) {
9ff721
+	case NFTNL_OF_EVENT_NEW:
9ff721
+		return "add";
9ff721
+	case NFTNL_OF_EVENT_DEL:
9ff721
+		return "delete";
9ff721
+	default:
9ff721
+		return "???";
9ff721
+	}
9ff721
+}
9ff721
+
9ff721
+static const char *netlink_msg2cmd(uint32_t msg)
9ff721
+{
9ff721
+	return nftnl_of2cmd(netlink_msg2nftnl_of(msg));
9ff721
+}
9ff721
+
9ff721
 static void nlr_for_each_set(struct nftnl_rule *nlr,
9ff721
 			     void (*cb)(struct set *s, void *data),
9ff721
 			     void *data, struct nft_cache *cache)
9ff721
@@ -179,34 +201,29 @@ static int netlink_events_table_cb(const struct nlmsghdr *nlh, int type,
9ff721
 				   struct netlink_mon_handler *monh)
9ff721
 {
9ff721
 	struct nftnl_table *nlt;
9ff721
-	uint32_t family;
9ff721
+	struct table *t;
9ff721
+	const char *cmd;
9ff721
 
9ff721
 	nlt = netlink_table_alloc(nlh);
9ff721
+	t = netlink_delinearize_table(monh->ctx, nlt);
9ff721
+	cmd = netlink_msg2cmd(type);
9ff721
 
9ff721
 	switch (monh->format) {
9ff721
 	case NFTNL_OUTPUT_DEFAULT:
9ff721
-		if (type == NFT_MSG_NEWTABLE) {
9ff721
-			nft_mon_print(monh, "add table ");
9ff721
-		} else {
9ff721
-			nft_mon_print(monh, "delete table ");
9ff721
-		}
9ff721
+		nft_mon_print(monh, "%s table ", cmd);
9ff721
 
9ff721
-		family = nftnl_table_get_u32(nlt, NFTNL_TABLE_FAMILY);
9ff721
-
9ff721
-		nft_mon_print(monh, "%s %s", family2str(family),
9ff721
-		       nftnl_table_get_str(nlt, NFTNL_TABLE_NAME));
9ff721
+		nft_mon_print(monh, "%s %s", family2str(t->handle.family),
9ff721
+			      t->handle.table.name);
9ff721
 		if (monh->ctx->octx->handle > 0)
9ff721
 			nft_mon_print(monh, " # handle %" PRIu64 "",
9ff721
-				      nftnl_table_get_u64(nlt, NFTNL_TABLE_HANDLE));
9ff721
-		nft_mon_print(monh, "\n");
9ff721
+				      t->handle.handle.id);
9ff721
 		break;
9ff721
 	case NFTNL_OUTPUT_JSON:
9ff721
-		nftnl_table_fprintf(monh->ctx->octx->output_fp, nlt,
9ff721
-				    monh->format, netlink_msg2nftnl_of(type));
9ff721
-		nft_mon_print(monh, "\n");
9ff721
+		monitor_print_table_json(monh, cmd, t);
9ff721
 		break;
9ff721
 	}
9ff721
-
9ff721
+	nft_mon_print(monh, "\n");
9ff721
+	table_free(t);
9ff721
 	nftnl_table_free(nlt);
9ff721
 	return MNL_CB_OK;
9ff721
 }
9ff721
@@ -216,35 +233,34 @@ static int netlink_events_chain_cb(const struct nlmsghdr *nlh, int type,
9ff721
 {
9ff721
 	struct nftnl_chain *nlc;
9ff721
 	struct chain *c;
9ff721
-	uint32_t family;
9ff721
+	const char *cmd;
9ff721
 
9ff721
 	nlc = netlink_chain_alloc(nlh);
9ff721
+	c = netlink_delinearize_chain(monh->ctx, nlc);
9ff721
+	cmd = netlink_msg2cmd(type);
9ff721
 
9ff721
 	switch (monh->format) {
9ff721
 	case NFTNL_OUTPUT_DEFAULT:
9ff721
+		nft_mon_print(monh, "%s ", cmd);
9ff721
+
9ff721
 		switch (type) {
9ff721
 		case NFT_MSG_NEWCHAIN:
9ff721
-			nft_mon_print(monh, "add ");
9ff721
-
9ff721
-			c = netlink_delinearize_chain(monh->ctx, nlc);
9ff721
 			chain_print_plain(c, monh->ctx->octx);
9ff721
-			chain_free(c);
9ff721
 			break;
9ff721
 		case NFT_MSG_DELCHAIN:
9ff721
-			family = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY);
9ff721
-			nft_mon_print(monh, "delete chain %s %s %s\n", family2str(family),
9ff721
-			       nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE),
9ff721
-			       nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME));
9ff721
+			nft_mon_print(monh, "chain %s %s %s",
9ff721
+				      family2str(c->handle.family),
9ff721
+				      c->handle.table.name,
9ff721
+				      c->handle.chain.name);
9ff721
 			break;
9ff721
 		}
9ff721
 		break;
9ff721
 	case NFTNL_OUTPUT_JSON:
9ff721
-		nftnl_chain_fprintf(monh->ctx->octx->output_fp, nlc,
9ff721
-				    monh->format, netlink_msg2nftnl_of(type));
9ff721
-		nft_mon_print(monh, "\n");
9ff721
+		monitor_print_chain_json(monh, cmd, c);
9ff721
 		break;
9ff721
 	}
9ff721
-
9ff721
+	nft_mon_print(monh, "\n");
9ff721
+	chain_free(c);
9ff721
 	nftnl_chain_free(nlc);
9ff721
 	return MNL_CB_OK;
9ff721
 }
9ff721
@@ -253,43 +269,44 @@ static int netlink_events_set_cb(const struct nlmsghdr *nlh, int type,
9ff721
 				 struct netlink_mon_handler *monh)
9ff721
 {
9ff721
 	struct nftnl_set *nls;
9ff721
+	const char *family, *cmd;
9ff721
 	struct set *set;
9ff721
-	uint32_t family, flags;
9ff721
+	uint32_t flags;
9ff721
 
9ff721
 	nls = netlink_set_alloc(nlh);
9ff721
 	flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
9ff721
 	if (flags & NFT_SET_ANONYMOUS)
9ff721
 		goto out;
9ff721
 
9ff721
+	set = netlink_delinearize_set(monh->ctx, nls);
9ff721
+	if (set == NULL) {
9ff721
+		nftnl_set_free(nls);
9ff721
+		return MNL_CB_ERROR;
9ff721
+	}
9ff721
+	family = family2str(set->handle.family);
9ff721
+	cmd = netlink_msg2cmd(type);
9ff721
+
9ff721
 	switch (monh->format) {
9ff721
 	case NFTNL_OUTPUT_DEFAULT:
9ff721
+		nft_mon_print(monh, "%s ", cmd);
9ff721
+
9ff721
 		switch (type) {
9ff721
 		case NFT_MSG_NEWSET:
9ff721
-			nft_mon_print(monh, "add ");
9ff721
-			set = netlink_delinearize_set(monh->ctx, nls);
9ff721
-			if (set == NULL) {
9ff721
-				nftnl_set_free(nls);
9ff721
-				return MNL_CB_ERROR;
9ff721
-			}
9ff721
 			set_print_plain(set, monh->ctx->octx);
9ff721
-			set_free(set);
9ff721
-			nft_mon_print(monh, "\n");
9ff721
 			break;
9ff721
 		case NFT_MSG_DELSET:
9ff721
-			family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
9ff721
-			nft_mon_print(monh, "delete set %s %s %s\n",
9ff721
-			       family2str(family),
9ff721
-			       nftnl_set_get_str(nls, NFTNL_SET_TABLE),
9ff721
-			       nftnl_set_get_str(nls, NFTNL_SET_NAME));
9ff721
+			nft_mon_print(monh, "set %s %s %s", family,
9ff721
+				      set->handle.table.name,
9ff721
+				      set->handle.set.name);
9ff721
 			break;
9ff721
 		}
9ff721
 		break;
9ff721
 	case NFTNL_OUTPUT_JSON:
9ff721
-		nftnl_set_fprintf(monh->ctx->octx->output_fp, nls,
9ff721
-				  monh->format, netlink_msg2nftnl_of(type));
9ff721
-		nft_mon_print(monh, "\n");
9ff721
+		monitor_print_set_json(monh, cmd, set);
9ff721
 		break;
9ff721
 	}
9ff721
+	nft_mon_print(monh, "\n");
9ff721
+	set_free(set);
9ff721
 out:
9ff721
 	nftnl_set_free(nls);
9ff721
 	return MNL_CB_OK;
9ff721
@@ -360,13 +377,14 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
9ff721
 	struct nftnl_set *nls;
9ff721
 	struct set *dummyset;
9ff721
 	struct set *set;
9ff721
-	const char *setname, *table;
9ff721
+	const char *setname, *table, *cmd;
9ff721
 	uint32_t family;
9ff721
 
9ff721
 	nls = netlink_setelem_alloc(nlh);
9ff721
 	table = nftnl_set_get_str(nls, NFTNL_SET_TABLE);
9ff721
 	setname = nftnl_set_get_str(nls, NFTNL_SET_NAME);
9ff721
 	family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
9ff721
+	cmd = netlink_msg2cmd(type);
9ff721
 
9ff721
 	set = set_lookup_global(family, table, setname, monh->cache);
9ff721
 	if (set == NULL) {
9ff721
@@ -374,70 +392,63 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
9ff721
 		goto out;
9ff721
 	}
9ff721
 
9ff721
-	switch (monh->format) {
9ff721
-	case NFTNL_OUTPUT_DEFAULT:
9ff721
-		if (set->flags & NFT_SET_ANONYMOUS)
9ff721
-			goto out;
9ff721
-
9ff721
-		/* we want to 'delinearize' the set_elem, but don't
9ff721
-		 * modify the original cached set. This path is only
9ff721
-		 * used by named sets, so use a dummy set.
9ff721
-		 */
9ff721
-		dummyset = set_alloc(monh->loc);
9ff721
-		dummyset->key = expr_clone(set->key);
9ff721
-		dummyset->datatype = set->datatype;
9ff721
-		dummyset->flags = set->flags;
9ff721
-		dummyset->init = set_expr_alloc(monh->loc, set);
9ff721
+	if (set->flags & NFT_SET_ANONYMOUS)
9ff721
+		goto out;
9ff721
 
9ff721
-		nlsei = nftnl_set_elems_iter_create(nls);
9ff721
-		if (nlsei == NULL)
9ff721
-			memory_allocation_error();
9ff721
+	/* we want to 'delinearize' the set_elem, but don't
9ff721
+	 * modify the original cached set. This path is only
9ff721
+	 * used by named sets, so use a dummy set.
9ff721
+	 */
9ff721
+	dummyset = set_alloc(monh->loc);
9ff721
+	dummyset->key = expr_clone(set->key);
9ff721
+	dummyset->datatype = set->datatype;
9ff721
+	dummyset->flags = set->flags;
9ff721
+	dummyset->init = set_expr_alloc(monh->loc, set);
9ff721
 
9ff721
-		nlse = nftnl_set_elems_iter_next(nlsei);
9ff721
-		while (nlse != NULL) {
9ff721
-			if (netlink_event_ignore_range_event(nlse)) {
9ff721
-				set_free(dummyset);
9ff721
-				nftnl_set_elems_iter_destroy(nlsei);
9ff721
-				goto out;
9ff721
-			}
9ff721
-			if (netlink_delinearize_setelem(nlse, dummyset,
9ff721
-							monh->cache) < 0) {
9ff721
-				set_free(dummyset);
9ff721
-				nftnl_set_elems_iter_destroy(nlsei);
9ff721
-				goto out;
9ff721
-			}
9ff721
-			nlse = nftnl_set_elems_iter_next(nlsei);
9ff721
-		}
9ff721
-		nftnl_set_elems_iter_destroy(nlsei);
9ff721
+	nlsei = nftnl_set_elems_iter_create(nls);
9ff721
+	if (nlsei == NULL)
9ff721
+		memory_allocation_error();
9ff721
 
9ff721
-		if (netlink_event_range_cache(set, dummyset)) {
9ff721
+	nlse = nftnl_set_elems_iter_next(nlsei);
9ff721
+	while (nlse != NULL) {
9ff721
+		if (netlink_event_ignore_range_event(nlse)) {
9ff721
 			set_free(dummyset);
9ff721
+			nftnl_set_elems_iter_destroy(nlsei);
9ff721
 			goto out;
9ff721
 		}
9ff721
-
9ff721
-		switch (type) {
9ff721
-		case NFT_MSG_NEWSETELEM:
9ff721
-			nft_mon_print(monh, "add ");
9ff721
-			break;
9ff721
-		case NFT_MSG_DELSETELEM:
9ff721
-			nft_mon_print(monh, "delete ");
9ff721
-			break;
9ff721
-		default:
9ff721
+		if (netlink_delinearize_setelem(nlse, dummyset,
9ff721
+						monh->cache) < 0) {
9ff721
 			set_free(dummyset);
9ff721
+			nftnl_set_elems_iter_destroy(nlsei);
9ff721
 			goto out;
9ff721
 		}
9ff721
-		nft_mon_print(monh, "element %s %s %s ", family2str(family), table, setname);
9ff721
-		expr_print(dummyset->init, monh->ctx->octx);
9ff721
-		nft_mon_print(monh, "\n");
9ff721
+		nlse = nftnl_set_elems_iter_next(nlsei);
9ff721
+	}
9ff721
+	nftnl_set_elems_iter_destroy(nlsei);
9ff721
 
9ff721
+	if (netlink_event_range_cache(set, dummyset)) {
9ff721
 		set_free(dummyset);
9ff721
+		goto out;
9ff721
+	}
9ff721
+
9ff721
+	switch (monh->format) {
9ff721
+	case NFTNL_OUTPUT_DEFAULT:
9ff721
+		nft_mon_print(monh, "%s element %s %s %s ",
9ff721
+			      cmd, family2str(family), table, setname);
9ff721
+		expr_print(dummyset->init, monh->ctx->octx);
9ff721
 		break;
9ff721
 	case NFTNL_OUTPUT_JSON:
9ff721
-		nftnl_set_fprintf(monh->ctx->octx->output_fp, nls,
9ff721
-				  monh->format, netlink_msg2nftnl_of(type));
9ff721
-		nft_mon_print(monh, "\n");
9ff721
+		dummyset->handle.family = family;
9ff721
+		dummyset->handle.set.name = setname;
9ff721
+		dummyset->handle.table.name = table;
9ff721
+		monitor_print_element_json(monh, cmd, dummyset);
9ff721
+		/* prevent set_free() from trying to free those */
9ff721
+		dummyset->handle.set.name = NULL;
9ff721
+		dummyset->handle.table.name = NULL;
9ff721
 		break;
9ff721
 	}
9ff721
+	nft_mon_print(monh, "\n");
9ff721
+	set_free(dummyset);
9ff721
 out:
9ff721
 	nftnl_set_free(nls);
9ff721
 	return MNL_CB_OK;
9ff721
@@ -446,43 +457,43 @@ out:
9ff721
 static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type,
9ff721
 				 struct netlink_mon_handler *monh)
9ff721
 {
9ff721
+	const char *family, *cmd;
9ff721
 	struct nftnl_obj *nlo;
9ff721
-	uint32_t family;
9ff721
 	struct obj *obj;
9ff721
 
9ff721
 	nlo = netlink_obj_alloc(nlh);
9ff721
 
9ff721
+	obj = netlink_delinearize_obj(monh->ctx, nlo);
9ff721
+	if (obj == NULL) {
9ff721
+		nftnl_obj_free(nlo);
9ff721
+		return MNL_CB_ERROR;
9ff721
+	}
9ff721
+	family = family2str(obj->handle.family);
9ff721
+	cmd = netlink_msg2cmd(type);
9ff721
+
9ff721
 	switch (monh->format) {
9ff721
 	case NFTNL_OUTPUT_DEFAULT:
9ff721
+		nft_mon_print(monh, "%s ", cmd);
9ff721
+
9ff721
 		switch (type) {
9ff721
 		case NFT_MSG_NEWOBJ:
9ff721
-			nft_mon_print(monh, "add ");
9ff721
-			obj = netlink_delinearize_obj(monh->ctx, nlo);
9ff721
-			if (obj == NULL) {
9ff721
-				nftnl_obj_free(nlo);
9ff721
-				return MNL_CB_ERROR;
9ff721
-			}
9ff721
 			obj_print_plain(obj, monh->ctx->octx);
9ff721
-			obj_free(obj);
9ff721
-			nft_mon_print(monh, "\n");
9ff721
 			break;
9ff721
 		case NFT_MSG_DELOBJ:
9ff721
-			family = nftnl_obj_get_u32(nlo, NFTNL_OBJ_FAMILY);
9ff721
-			nft_mon_print(monh, "delete %s %s %s %s\n",
9ff721
-			       obj_type_name(nftnl_obj_get_u32(nlo, NFTNL_OBJ_TYPE)),
9ff721
-			       family2str(family),
9ff721
-			       nftnl_obj_get_str(nlo, NFTNL_OBJ_TABLE),
9ff721
-			       nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME));
9ff721
+			nft_mon_print(monh, "%s %s %s %s",
9ff721
+			       obj_type_name(obj->type),
9ff721
+			       family,
9ff721
+			       obj->handle.table.name,
9ff721
+			       obj->handle.obj.name);
9ff721
 			break;
9ff721
 		}
9ff721
 		break;
9ff721
 	case NFTNL_OUTPUT_JSON:
9ff721
-		nftnl_obj_fprintf(monh->ctx->octx->output_fp, nlo,
9ff721
-				  monh->format, netlink_msg2nftnl_of(type));
9ff721
-		nft_mon_print(monh, "\n");
9ff721
+		monitor_print_obj_json(monh, cmd, obj);
9ff721
 		break;
9ff721
 	}
9ff721
-
9ff721
+	nft_mon_print(monh, "\n");
9ff721
+	obj_free(obj);
9ff721
 	nftnl_obj_free(nlo);
9ff721
 	return MNL_CB_OK;
9ff721
 }
9ff721
@@ -496,48 +507,42 @@ static void rule_map_decompose_cb(struct set *s, void *data)
9ff721
 static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
9ff721
 				  struct netlink_mon_handler *monh)
9ff721
 {
9ff721
+	const char *family, *cmd;
9ff721
 	struct nftnl_rule *nlr;
9ff721
-	const char *family;
9ff721
-	const char *table;
9ff721
-	const char *chain;
9ff721
 	struct rule *r;
9ff721
-	uint64_t handle;
9ff721
-	uint32_t fam;
9ff721
 
9ff721
 	nlr = netlink_rule_alloc(nlh);
9ff721
+	r = netlink_delinearize_rule(monh->ctx, nlr);
9ff721
+	nlr_for_each_set(nlr, rule_map_decompose_cb, NULL, monh->cache);
9ff721
+	cmd = netlink_msg2cmd(type);
9ff721
+
9ff721
 	switch (monh->format) {
9ff721
 	case NFTNL_OUTPUT_DEFAULT:
9ff721
-		fam = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
9ff721
-		family = family2str(fam);
9ff721
-		table = nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE);
9ff721
-		chain = nftnl_rule_get_str(nlr, NFTNL_RULE_CHAIN);
9ff721
-		handle = nftnl_rule_get_u64(nlr, NFTNL_RULE_HANDLE);
9ff721
+		family = family2str(r->handle.family);
9ff721
+
9ff721
+		nft_mon_print(monh, "%s rule %s %s %s ",
9ff721
+			      cmd,
9ff721
+			      family,
9ff721
+			      r->handle.table.name,
9ff721
+			      r->handle.chain.name);
9ff721
 
9ff721
 		switch (type) {
9ff721
 		case NFT_MSG_NEWRULE:
9ff721
-			r = netlink_delinearize_rule(monh->ctx, nlr);
9ff721
-			nlr_for_each_set(nlr, rule_map_decompose_cb, NULL,
9ff721
-					 monh->cache);
9ff721
-
9ff721
-			nft_mon_print(monh, "add rule %s %s %s ", family, table, chain);
9ff721
 			rule_print(r, monh->ctx->octx);
9ff721
-			nft_mon_print(monh, "\n");
9ff721
 
9ff721
-			rule_free(r);
9ff721
 			break;
9ff721
 		case NFT_MSG_DELRULE:
9ff721
-			nft_mon_print(monh, "delete rule %s %s %s handle %u\n",
9ff721
-			       family, table, chain, (unsigned int)handle);
9ff721
+			nft_mon_print(monh, "handle %" PRIu64,
9ff721
+				      r->handle.handle.id);
9ff721
 			break;
9ff721
 		}
9ff721
 		break;
9ff721
 	case NFTNL_OUTPUT_JSON:
9ff721
-		nftnl_rule_fprintf(monh->ctx->octx->output_fp, nlr,
9ff721
-				   monh->format, netlink_msg2nftnl_of(type));
9ff721
-		nft_mon_print(monh, "\n");
9ff721
+		monitor_print_rule_json(monh, cmd, r);
9ff721
 		break;
9ff721
 	}
9ff721
-
9ff721
+	nft_mon_print(monh, "\n");
9ff721
+	rule_free(r);
9ff721
 	nftnl_rule_free(nlr);
9ff721
 	return MNL_CB_OK;
9ff721
 }
9ff721
diff --git a/src/rule.c b/src/rule.c
9ff721
index eb06302d4f223..3065cc5474bbf 100644
9ff721
--- a/src/rule.c
9ff721
+++ b/src/rule.c
9ff721
@@ -812,8 +812,6 @@ void chain_print_plain(const struct chain *chain, struct output_ctx *octx)
9ff721
 	}
9ff721
 	if (octx->handle > 0)
9ff721
 		nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id);
9ff721
-
9ff721
-	nft_print(octx, "\n");
9ff721
 }
9ff721
 
9ff721
 struct table *table_alloc(void)
9ff721
-- 
bacbc8
2.21.0
9ff721