[PATCH xtables 3/3] xtables: remove error reporting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



keep table/chain/rule object around after commiting a batch.
If we get errors, we can correlate them with the line numbers
of the restore file.

Currently uses fprintf, xtables_error() would be more appropriate,
but then it exits after first error.

We probably need ot add xtables_warn() and use that.

Signed-off-by: Florian Westphal <fw@xxxxxxxxx>
---
 iptables/nft.c             | 175 +++++++++++++++++++++++++++++++++++++++------
 iptables/nft.h             |   5 ++
 iptables/xtables-restore.c |   1 +
 3 files changed, 159 insertions(+), 22 deletions(-)

diff --git a/iptables/nft.c b/iptables/nft.c
index b6426a96de18..d7c57f1042b4 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -81,6 +81,7 @@ int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
 	return 0;
 }
 
+static LIST_HEAD(err_list);
 static LIST_HEAD(batch_page_list);
 static int batch_num_pages;
 
@@ -190,6 +191,23 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl)
 	return ret;
 }
 
+struct mnl_err {
+	struct list_head        head;
+	int                     err;
+	uint32_t                seqnum;
+};
+
+static void mnl_err_list_node_add(int error, int seqnum)
+{
+	struct mnl_err *err = malloc(sizeof(struct mnl_err));
+
+	if (err) {
+		err->seqnum = seqnum;
+		err->err = error;
+		list_add_tail(&err->head, &err_list);
+	}
+}
+
 static int mnl_nftnl_batch_talk(struct nft_handle *h)
 {
 	int ret, fd = mnl_socket_get_fd(h->nl);
@@ -214,6 +232,8 @@ static int mnl_nftnl_batch_talk(struct nft_handle *h)
 		return -1;
 
 	while (ret > 0 && FD_ISSET(fd, &readfds)) {
+		struct nlmsghdr *nlh = (struct nlmsghdr *)rcv_buf;
+
 		ret = mnl_socket_recvfrom(h->nl, rcv_buf, sizeof(rcv_buf));
 		if (ret == -1)
 			return -1;
@@ -222,8 +242,11 @@ static int mnl_nftnl_batch_talk(struct nft_handle *h)
 		/* Annotate first error and continue, make sure we get all
 		 * acknoledgments.
 		 */
-		if (!err && ret == -1)
-			err = errno;
+		if (ret == -1) {
+			mnl_err_list_node_add(errno, nlh->nlmsg_seq);
+			if (!err)
+				err = errno;
+		}
 
 		ret = select(fd+1, &readfds, NULL, NULL, &tv);
 		if (ret == -1)
@@ -274,14 +297,80 @@ enum obj_action {
 struct obj_update {
 	struct list_head	head;
 	enum obj_update_type	type;
+	int			seq;
 	union {
 		struct nftnl_table	*table;
 		struct nftnl_chain	*chain;
-		struct nftnl_rule		*rule;
+		struct nftnl_rule	*rule;
 		void			*ptr;
 	};
+	struct {
+		unsigned int		lineno;
+	} error;
 };
 
+static void mnl_show_error(const struct nft_handle *h,
+			   const struct obj_update *o,
+			   const struct mnl_err *err)
+{
+	const char *prog = xt_params->program_name;
+	static const char *type_name[] = {
+		[NFT_COMPAT_TABLE_ADD] = "TABLE_ADD",
+		[NFT_COMPAT_TABLE_FLUSH] = "TABLE_FLUSH",
+		[NFT_COMPAT_CHAIN_ADD] = "CHAIN_ADD",
+		[NFT_COMPAT_CHAIN_USER_ADD] = "CHAIN_USER_ADD",
+		[NFT_COMPAT_CHAIN_USER_DEL] = "CHAIN_USER_DEL",
+		[NFT_COMPAT_CHAIN_USER_FLUSH] = "CHAIN_USER_FLUSH",
+		[NFT_COMPAT_CHAIN_UPDATE] = "CHAIN_UPDATE",
+		[NFT_COMPAT_CHAIN_RENAME] = "CHAIN_RENAME",
+		[NFT_COMPAT_RULE_APPEND] = "RULE_APPEND",
+		[NFT_COMPAT_RULE_INSERT] = "RULE_INSERT",
+		[NFT_COMPAT_RULE_REPLACE] = "RULE_REPLACE",
+		[NFT_COMPAT_RULE_DELETE] = "RULE_DELETE",
+		[NFT_COMPAT_RULE_FLUSH] = "RULE_FLUSH",
+	};
+	char errmsg[256];
+	char tcr[128];
+
+	snprintf(errmsg, sizeof(errmsg), "%s: line %u: %s failed (%s): ",
+		 prog, o->error.lineno, type_name[o->type], strerror(err->err));
+
+	switch (o->type) {
+	case NFT_COMPAT_TABLE_ADD:
+	case NFT_COMPAT_TABLE_FLUSH:
+		snprintf(tcr, sizeof(tcr), "table %s",
+			 nftnl_table_get_str(o->table, NFTNL_TABLE_NAME));
+		break;
+	case NFT_COMPAT_CHAIN_ADD:
+	case NFT_COMPAT_CHAIN_USER_ADD:
+	case NFT_COMPAT_CHAIN_USER_DEL:
+	case NFT_COMPAT_CHAIN_USER_FLUSH:
+	case NFT_COMPAT_CHAIN_UPDATE:
+	case NFT_COMPAT_CHAIN_RENAME:
+		snprintf(tcr, sizeof(tcr), "chain %s",
+			 nftnl_chain_get_str(o->chain, NFTNL_CHAIN_NAME));
+		break;
+	case NFT_COMPAT_RULE_APPEND:
+	case NFT_COMPAT_RULE_INSERT:
+	case NFT_COMPAT_RULE_REPLACE:
+	case NFT_COMPAT_RULE_DELETE:
+	case NFT_COMPAT_RULE_FLUSH:
+		snprintf(tcr, sizeof(tcr), "rule in chain %s",
+			 nftnl_rule_get_str(o->rule, NFTNL_RULE_CHAIN));
+#if 0
+		{
+			struct iptables_command_state cs = {};
+			nft_rule_to_iptables_command_state(o->rule, &cs);
+			nft_rule_print_save(&cs, o->rule, NFT_RULE_APPEND, FMT_NOCOUNTS);
+		}
+#endif
+		break;
+	}
+
+	xtables_error
+	fprintf(stderr, "%s: %s", errmsg, tcr);
+}
+
 static int batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr)
 {
 	struct obj_update *obj;
@@ -291,6 +380,7 @@ static int batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr)
 		return -1;
 
 	obj->ptr = ptr;
+	obj->error.lineno = h->error.lineno;
 	obj->type = type;
 	list_add_tail(&obj->head, &h->obj_list);
 	h->obj_list_num++;
@@ -2288,7 +2378,6 @@ static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type,
 	nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(h->batch),
 					type, h->family, flags, seq);
 	nftnl_table_nlmsg_build_payload(nlh, table);
-	nftnl_table_free(table);
 }
 
 static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
@@ -2301,7 +2390,6 @@ static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
 					type, h->family, flags, seq);
 	nftnl_chain_nlmsg_build_payload(nlh, chain);
 	nft_chain_print_debug(chain, nlh);
-	nftnl_chain_free(chain);
 }
 
 static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
@@ -2314,84 +2402,110 @@ static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
 				       type, h->family, flags, seq);
 	nftnl_rule_nlmsg_build_payload(nlh, rule);
 	nft_rule_print_debug(rule, nlh);
-	nftnl_rule_free(rule);
+}
+
+static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
+{
+	switch (o->type) {
+	case NFT_COMPAT_TABLE_ADD:
+	case NFT_COMPAT_TABLE_FLUSH:
+		nftnl_table_free(o->table);
+		break;
+	case NFT_COMPAT_CHAIN_ADD:
+	case NFT_COMPAT_CHAIN_USER_ADD:
+	case NFT_COMPAT_CHAIN_USER_DEL:
+	case NFT_COMPAT_CHAIN_USER_FLUSH:
+	case NFT_COMPAT_CHAIN_UPDATE:
+	case NFT_COMPAT_CHAIN_RENAME:
+		nftnl_chain_free(o->chain);
+		break;
+	case NFT_COMPAT_RULE_APPEND:
+	case NFT_COMPAT_RULE_INSERT:
+	case NFT_COMPAT_RULE_REPLACE:
+	case NFT_COMPAT_RULE_DELETE:
+	case NFT_COMPAT_RULE_FLUSH:
+		nftnl_rule_free(o->rule);
+		break;
+	}
+	h->obj_list_num--;
+	list_del(&o->head);
+	free(o);
 }
 
 static int nft_action(struct nft_handle *h, int action)
 {
 	struct obj_update *n, *tmp;
+	struct mnl_err *err;
 	uint32_t seq = 1;
 	int ret = 0;
 
 	mnl_nftnl_batch_begin(h->batch, seq++);
 
-	list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
+	list_for_each_entry(n, &h->obj_list, head) {
+		n->seq = seq++;
 		switch (n->type) {
 		case NFT_COMPAT_TABLE_ADD:
 			nft_compat_table_batch_add(h, NFT_MSG_NEWTABLE,
-						   NLM_F_CREATE, seq++,
+						   NLM_F_CREATE, n->seq,
 						   n->table);
 			break;
 		case NFT_COMPAT_TABLE_FLUSH:
 			nft_compat_table_batch_add(h, NFT_MSG_DELTABLE,
 						   0,
-						   seq++, n->table);
+						   n->seq, n->table);
 			break;
 		case NFT_COMPAT_CHAIN_ADD:
 			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
-						   NLM_F_CREATE, seq++,
+						   NLM_F_CREATE, n->seq,
 						   n->chain);
 			break;
 		case NFT_COMPAT_CHAIN_USER_ADD:
 			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
-						   NLM_F_EXCL, seq++,
+						   NLM_F_EXCL, n->seq,
 						   n->chain);
 			break;
 		case NFT_COMPAT_CHAIN_USER_DEL:
 			nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
-						   NLM_F_NONREC, seq++,
+						   NLM_F_NONREC, n->seq,
 						   n->chain);
 			break;
 		case NFT_COMPAT_CHAIN_USER_FLUSH:
 			nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
-						   0, seq++,
+						   0, n->seq,
 						   n->chain);
 			break;
 		case NFT_COMPAT_CHAIN_UPDATE:
 			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
 						   h->restore ?
 						     NLM_F_CREATE : 0,
-						   seq++, n->chain);
+						   n->seq, n->chain);
 			break;
 		case NFT_COMPAT_CHAIN_RENAME:
 			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, 0,
-						   seq++, n->chain);
+						   n->seq, n->chain);
 			break;
 		case NFT_COMPAT_RULE_APPEND:
 			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
 						  NLM_F_CREATE | NLM_F_APPEND,
-						  seq++, n->rule);
+						  n->seq, n->rule);
 			break;
 		case NFT_COMPAT_RULE_INSERT:
 			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
-						  NLM_F_CREATE, seq++,
+						  NLM_F_CREATE, n->seq,
 						  n->rule);
 			break;
 		case NFT_COMPAT_RULE_REPLACE:
 			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
 						  NLM_F_CREATE | NLM_F_REPLACE,
-						  seq++, n->rule);
+						  n->seq, n->rule);
 			break;
 		case NFT_COMPAT_RULE_DELETE:
 		case NFT_COMPAT_RULE_FLUSH:
 			nft_compat_rule_batch_add(h, NFT_MSG_DELRULE, 0,
-						  seq++, n->rule);
+						  n->seq, n->rule);
 			break;
 		}
 
-		h->obj_list_num--;
-		list_del(&n->head);
-		free(n);
 
 		if (!mnl_nlmsg_batch_next(h->batch))
 			h->batch = mnl_nftnl_batch_page_add(h->batch);
@@ -2410,6 +2524,23 @@ static int nft_action(struct nft_handle *h, int action)
 
 	ret = mnl_nftnl_batch_talk(h);
 
+	list_for_each_entry(err, &err_list, head) {
+		list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
+			bool next_err = false;
+
+			if (err->seqnum == n->seq) {
+				mnl_show_error(h, n, err);
+				next_err = true;
+			}
+			batch_obj_del(h, n);
+			if (next_err)
+				break;
+		}
+	}
+
+	list_for_each_entry_safe(n, tmp, &h->obj_list, head)
+		batch_obj_del(h, n);
+
 	mnl_nlmsg_batch_reset(h->batch);
 
 	return ret == 0 ? 1 : 0;
diff --git a/iptables/nft.h b/iptables/nft.h
index 5d0576c8ee45..3606ef034796 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -37,6 +37,11 @@ struct nft_handle {
 	struct builtin_table	*tables;
 	struct nftnl_rule_list	*rule_cache;
 	bool			restore;
+
+	/* meta data, for error reporting */
+	struct {
+		unsigned int	lineno;
+	} error;
 };
 
 extern struct builtin_table xtables_ipv4[TABLES_MAX];
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index d977dabfae50..57b8c8b68d4d 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -228,6 +228,7 @@ void xtables_restore_parse(struct nft_handle *h,
 		int ret = 0;
 
 		line++;
+		h->error.lineno = line;
 		if (buffer[0] == '\n')
 			continue;
 		else if (buffer[0] == '#') {
-- 
2.16.1

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux