diff mbox series

[v3,3/8] conntrack: per-command entries counters

Message ID 20210129212452.45352-4-mikhail.sennikovskii@cloud.ionos.com
State Under Review
Delegated to: Pablo Neira
Headers show
Series conntrack: save output format | expand

Commit Message

Mikhail Sennikovsky Jan. 29, 2021, 9:24 p.m. UTC
As a multicommand support preparation entry counters need
to be made per-command as well, e.g. for the case -D and -I
can be executed in a single batch, and we want to have separate
counters for them.

Signed-off-by: Mikhail Sennikovsky <mikhail.sennikovskii@cloud.ionos.com>
---
 src/conntrack.c | 117 +++++++++++++++++++++++++++++++++---------------
 1 file changed, 81 insertions(+), 36 deletions(-)
diff mbox series

Patch

diff --git a/src/conntrack.c b/src/conntrack.c
index a090542..4783825 100644
--- a/src/conntrack.c
+++ b/src/conntrack.c
@@ -1663,8 +1663,48 @@  nfct_filter(const struct ct_cmd *cmd,
 	return 0;
 }
 
-static int counter;
 static int dump_xml_header_done = 1;
+static unsigned int cmd_executed = 0;
+static const unsigned int cmd_no_entries_ok = 0
+						| CT_LIST
+						| EXP_LIST
+						;
+static unsigned int cmd_counters[NUMBER_OF_CMD];
+
+static int
+print_cmd_counters(void)
+{
+	int i, ret = EXIT_FAILURE;
+
+	if (!cmd_executed)
+		return EXIT_SUCCESS;
+
+	for (i = 0;
+		i < (int)(sizeof(cmd_counters) / sizeof(cmd_counters[0]));
+		++i) {
+		if (cmd_executed & 1 << i) {
+			if (exit_msg[i][0]) {
+				fprintf(stderr, "%s v%s (conntrack-tools): ",
+							PROGNAME, VERSION);
+				fprintf(stderr, exit_msg[i], cmd_counters[i]);
+			}
+			/*
+			 * If there is at least one command which is supposed
+			 * to return success, EXIT_SUCCESS is returned.
+			 * I.e. for the --load-file case this would ensure that
+			 * e.g. -D followed by a series of -I's
+			 * would return success in case there are no entries
+			 * to be deleted with the -D command preceding the -I's
+			 */
+			if (!exit_msg[i][0]
+					|| cmd_counters[i] != 0
+					|| cmd_no_entries_ok & 1 << i)
+				ret &= EXIT_SUCCESS;
+		}
+	}
+	return ret;
+}
+
 
 static void __attribute__((noreturn))
 event_sighandler(int s)
@@ -1674,8 +1714,7 @@  event_sighandler(int s)
 		fflush(stdout);
 	}
 
-	fprintf(stderr, "%s v%s (conntrack-tools): ", PROGNAME, VERSION);
-	fprintf(stderr, "%d flow events have been shown.\n", counter);
+	print_cmd_counters();
 	mnl_socket_close(sock.mnl);
 	exit(0);
 }
@@ -1688,8 +1727,7 @@  exp_event_sighandler(int s)
 		fflush(stdout);
 	}
 
-	fprintf(stderr, "%s v%s (conntrack-tools): ", PROGNAME, VERSION);
-	fprintf(stderr, "%d expectation events have been shown.\n", counter);
+	print_cmd_counters();
 	nfct_close(cth);
 	exit(0);
 }
@@ -1938,7 +1976,7 @@  done:
 	}
 	fflush(stdout);
 
-	counter++;
+	cmd_counters[cmd->cmd]++;
 out:
 	nfct_destroy(ct);
 	return MNL_CB_OK;
@@ -1981,7 +2019,7 @@  static int dump_cb(enum nf_conntrack_msg_type type,
 done:
 	printf("%s\n", buf);
 
-	counter++;
+	cmd_counters[cmd->cmd]++;
 
 	return NFCT_CB_CONTINUE;
 }
@@ -2022,7 +2060,7 @@  static int delete_cb(enum nf_conntrack_msg_type type,
 done:
 	printf("%s\n", buf);
 
-	counter++;
+	cmd_counters[cmd->cmd]++;
 
 	return NFCT_CB_CONTINUE;
 }
@@ -2207,7 +2245,7 @@  static int update_cb(enum nf_conntrack_msg_type type,
 	nfct_destroy(tmp);
 	nfct_callback_unregister(ith);
 
-	counter++;
+	cmd_counters[cmd->cmd]++;
 
 	return NFCT_CB_CONTINUE;
 }
@@ -2217,6 +2255,7 @@  static int dump_exp_cb(enum nf_conntrack_msg_type type,
 		      void *data)
 {
 	char buf[1024];
+	struct ct_cmd *cmd = data;
 	unsigned int op_type = NFCT_O_DEFAULT;
 	unsigned int op_flags = 0;
 
@@ -2239,7 +2278,7 @@  static int dump_exp_cb(enum nf_conntrack_msg_type type,
 
 	nfexp_snprintf(buf,sizeof(buf), exp, NFCT_T_UNKNOWN, op_type, op_flags);
 	printf("%s\n", buf);
-	counter++;
+	cmd_counters[cmd->cmd]++;
 
 	return NFCT_CB_CONTINUE;
 }
@@ -2248,6 +2287,7 @@  static int event_exp_cb(enum nf_conntrack_msg_type type,
 			struct nf_expect *exp, void *data)
 {
 	char buf[1024];
+	struct ct_cmd *cmd = data;
 	unsigned int op_type = NFCT_O_DEFAULT;
 	unsigned int op_flags = 0;
 
@@ -2271,7 +2311,7 @@  static int event_exp_cb(enum nf_conntrack_msg_type type,
 	nfexp_snprintf(buf,sizeof(buf), exp, type, op_type, op_flags);
 	printf("%s\n", buf);
 	fflush(stdout);
-	counter++;
+	cmd_counters[cmd->cmd]++;
 
 	return NFCT_CB_CONTINUE;
 }
@@ -2280,7 +2320,9 @@  static int count_exp_cb(enum nf_conntrack_msg_type type,
 			struct nf_expect *exp,
 			void *data)
 {
-	counter++;
+	struct ct_cmd *cmd = data;
+
+	cmd_counters[cmd->cmd]++;
 	return NFCT_CB_CONTINUE;
 }
 
@@ -2396,7 +2438,9 @@  static void nfct_mnl_socket_close(void)
 }
 
 static int
-nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family)
+nfct_mnl_dump(uint16_t subsys, uint16_t type,
+		      mnl_cb_t cb, void *data,
+		      uint8_t family)
 {
 	char buf[MNL_SOCKET_BUFFER_SIZE];
 	struct nlmsghdr *nlh;
@@ -2411,7 +2455,7 @@  nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family)
 	res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf));
 	while (res > 0) {
 		res = mnl_cb_run(buf, res, nlh->nlmsg_seq, sock.portid,
-					 cb, NULL);
+					 cb, data);
 		if (res <= MNL_CB_STOP)
 			break;
 
@@ -2581,6 +2625,7 @@  static int mnl_nfct_dump_cb(const struct nlmsghdr *nlh, void *data)
 {
 	struct nf_conntrack *ct;
 	char buf[4096];
+	struct ct_cmd *cmd = data;
 
 	ct = nfct_new();
 	if (ct == NULL)
@@ -2593,7 +2638,7 @@  static int mnl_nfct_dump_cb(const struct nlmsghdr *nlh, void *data)
 
 	nfct_destroy(ct);
 
-	counter++;
+	cmd_counters[cmd->cmd]++;
 
 	return MNL_CB_OK;
 }
@@ -3051,6 +3096,10 @@  static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[])
 		}
 	}
 
+	if (!command)
+		/* invalid args */
+		exit_error(PARAMETER_PROBLEM, "invalid cmd line syntax");
+
 	/* default family only for the following commands */
 	if (family == AF_UNSPEC) {
 		switch (command) {
@@ -3106,11 +3155,14 @@  static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[])
 	ct_cmd->socketbuffersize = socketbuffersize;
 }
 
-static int do_command_ct(const char *progname, struct ct_cmd *cmd)
+static void do_command_ct(const char *progname, struct ct_cmd *cmd)
 {
 	struct nfct_filter_dump *filter_dump;
 	int res = 0;
 
+	assert(cmd->cmd < sizeof(cmd_counters) / sizeof(cmd_counters[0]));
+	cmd_executed |= cmd->command;
+
 	switch(cmd->command) {
 	case CT_LIST:
 		if (cmd->type == CT_TABLE_DYING) {
@@ -3119,7 +3171,7 @@  static int do_command_ct(const char *progname, struct ct_cmd *cmd)
 
 			res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK,
 					    IPCTNL_MSG_CT_GET_DYING,
-					    mnl_nfct_dump_cb, cmd->family);
+					    mnl_nfct_dump_cb, cmd, cmd->family);
 
 			nfct_mnl_socket_close();
 			break;
@@ -3129,7 +3181,7 @@  static int do_command_ct(const char *progname, struct ct_cmd *cmd)
 
 			res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK,
 					    IPCTNL_MSG_CT_GET_UNCONFIRMED,
-					    mnl_nfct_dump_cb, cmd->family);
+					    mnl_nfct_dump_cb, cmd, cmd->family);
 
 			nfct_mnl_socket_close();
 			break;
@@ -3182,7 +3234,7 @@  static int do_command_ct(const char *progname, struct ct_cmd *cmd)
 		if (!cth)
 			exit_error(OTHER_PROBLEM, "Can't open handler");
 
-		nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL);
+		nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, cmd);
 		res = nfexp_query(cth, NFCT_Q_DUMP, &cmd->family);
 		nfct_close(cth);
 
@@ -3211,7 +3263,7 @@  static int do_command_ct(const char *progname, struct ct_cmd *cmd)
 
 		res = nfct_query(cth, NFCT_Q_CREATE, cmd->tmpl.ct);
 		if (res != -1)
-			counter++;
+			cmd_counters[cmd->cmd]++;
 		nfct_close(cth);
 		break;
 
@@ -3303,7 +3355,7 @@  static int do_command_ct(const char *progname, struct ct_cmd *cmd)
 		if (!cth)
 			exit_error(OTHER_PROBLEM, "Can't open handler");
 
-		nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL);
+		nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, cmd);
 		res = nfexp_query(cth, NFCT_Q_GET, cmd->tmpl.exp);
 		nfct_close(cth);
 		break;
@@ -3424,7 +3476,7 @@  static int do_command_ct(const char *progname, struct ct_cmd *cmd)
 			exit_error(OTHER_PROBLEM, "Can't open handler");
 		signal(SIGINT, exp_event_sighandler);
 		signal(SIGTERM, exp_event_sighandler);
-		nfexp_callback_register(cth, NFCT_T_ALL, event_exp_cb, NULL);
+		nfexp_callback_register(cth, NFCT_T_ALL, event_exp_cb, cmd);
 		res = nfexp_catch(cth);
 		nfct_close(cth);
 		break;
@@ -3468,10 +3520,10 @@  try_proc_count:
 		if (!cth)
 			exit_error(OTHER_PROBLEM, "Can't open handler");
 
-		nfexp_callback_register(cth, NFCT_T_ALL, count_exp_cb, NULL);
+		nfexp_callback_register(cth, NFCT_T_ALL, count_exp_cb, cmd);
 		res = nfexp_query(cth, NFCT_Q_DUMP, &cmd->family);
 		nfct_close(cth);
-		printf("%d\n", counter);
+		printf("%d\n", cmd_counters[cmd->cmd]);
 		break;
 	case CT_STATS:
 		/* If we fail with netlink, fall back to /proc to ensure
@@ -3482,7 +3534,7 @@  try_proc_count:
 
 		res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK,
 				    IPCTNL_MSG_CT_GET_STATS_CPU,
-				    nfct_stats_cb, AF_UNSPEC);
+				    nfct_stats_cb, NULL, AF_UNSPEC);
 
 		nfct_mnl_socket_close();
 
@@ -3501,7 +3553,7 @@  try_proc_count:
 
 		res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK_EXP,
 				    IPCTNL_MSG_EXP_GET_STATS_CPU,
-				    nfexp_stats_cb, AF_UNSPEC);
+				    nfexp_stats_cb, NULL, AF_UNSPEC);
 
 		nfct_mnl_socket_close();
 
@@ -3533,15 +3585,6 @@  try_proc:
 	free_options();
 	if (labelmap)
 		nfct_labelmap_destroy(labelmap);
-
-	if (cmd->command && exit_msg[cmd->cmd][0]) {
-		fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION);
-		fprintf(stderr, exit_msg[cmd->cmd], counter);
-		if (counter == 0 && !(cmd->command & (CT_LIST | EXP_LIST)))
-			return EXIT_FAILURE;
-	}
-
-	return EXIT_SUCCESS;
 }
 
 int main(int argc, char *argv[])
@@ -3560,5 +3603,7 @@  int main(int argc, char *argv[])
 
 	do_parse(cmd, argc, argv);
 
-	return do_command_ct(argv[0], cmd);
+	do_command_ct(argv[0], cmd);
+
+	return print_cmd_counters();
 }