Blame SOURCES/iptables-1.4.21-wait-interval.patch

9c64ad
Adapted version of
9c64ad
9c64ad
commit e8f857a5a1514c3e7d0d8ea0f7d2d571f0e37bd1
9c64ad
Author: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
9c64ad
Date:   Thu Jun 23 18:44:06 2016 -0600
9c64ad
9c64ad
    xtables: Add an interval option for xtables lock wait
9c64ad
    
9c64ad
    ip[6]tables currently waits for 1 second for the xtables lock to be
9c64ad
    freed if the -w option is used. We have seen that the lock is held
9c64ad
    much less than that resulting in unnecessary delay when trying to
9c64ad
    acquire the lock. This problem is even severe in case of latency
9c64ad
    sensitive applications.
9c64ad
    
9c64ad
    Introduce a new option 'W' to specify the wait interval in microseconds.
9c64ad
    If this option is not specified, the command sleeps for 1 second by
9c64ad
    default.
9c64ad
    
9c64ad
    v1->v2: Change behavior to take millisecond sleep as an argument to
9c64ad
    -w as suggested by Pablo. Also maintain current behavior for -w to
9c64ad
    sleep for 1 second as mentioned by Liping.
9c64ad
    
9c64ad
    v2->v3: Move the millisecond behavior to a new option as suggested
9c64ad
    by Pablo.
9c64ad
    
9c64ad
    v3->v4: Use select instead of usleep. Sleep every iteration for
9c64ad
    the time specified in the "-W" argument. Update man page.
9c64ad
    
9c64ad
    v4->v5: Fix compilation error when enabling nftables
9c64ad
    
9c64ad
    v5->v6: Simplify -W so it only takes the interval wait in microseconds.
9c64ad
    Bail out if -W is specific but -w is not.
9c64ad
    
9c64ad
    Joint work with Pablo Neira.
9c64ad
    
9c64ad
    Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
9c64ad
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
9c64ad
9c64ad
diff -up iptables-1.4.21/iptables/ip6tables.c.wait-interval iptables-1.4.21/iptables/ip6tables.c
9c64ad
--- iptables-1.4.21/iptables/ip6tables.c.wait-interval	2017-04-05 14:04:04.560346651 +0200
9c64ad
+++ iptables-1.4.21/iptables/ip6tables.c	2017-04-05 14:04:04.562346670 +0200
9c64ad
@@ -103,6 +103,7 @@ static struct option original_opts[] = {
9c64ad
 	{.name = "out-interface", .has_arg = 1, .val = 'o'},
9c64ad
 	{.name = "verbose",       .has_arg = 0, .val = 'v'},
9c64ad
 	{.name = "wait",          .has_arg = 2, .val = 'w'},
9c64ad
+	{.name = "wait-interval", .has_arg = 2, .val = 'W'},
9c64ad
 	{.name = "exact",         .has_arg = 0, .val = 'x'},
9c64ad
 	{.name = "version",       .has_arg = 0, .val = 'V'},
9c64ad
 	{.name = "help",          .has_arg = 2, .val = 'h'},
9c64ad
@@ -258,7 +259,10 @@ exit_printhelp(const struct xtables_rule
9c64ad
 "				network interface name ([+] for wildcard)\n"
9c64ad
 "  --table	-t table	table to manipulate (default: `filter')\n"
9c64ad
 "  --verbose	-v		verbose mode\n"
9c64ad
-"  --wait	-w [seconds]	wait for the xtables lock\n"
9c64ad
+"  --wait	-w [seconds]	maximum wait to acquire xtables lock before give up\n"
9c64ad
+"  --wait-interval -W [usecs]	wait time to try to acquire xtables lock\n"
9c64ad
+"				interval to wait for xtables lock\n"
9c64ad
+"				default is 1 second\n"
9c64ad
 "  --line-numbers		print line numbers when listing\n"
9c64ad
 "  --exact	-x		expand numbers (display exact values)\n"
9c64ad
 /*"[!] --fragment	-f		match second or further fragments only\n"*/
9c64ad
@@ -1323,6 +1327,10 @@ int do_command6(int argc, char *argv[],
9c64ad
 
9c64ad
 	int verbose = 0;
9c64ad
 	int wait = 0;
9c64ad
+	struct timeval wait_interval = {
9c64ad
+		.tv_sec	= 1,
9c64ad
+	};
9c64ad
+	bool wait_interval_set = false;
9c64ad
 	const char *chain = NULL;
9c64ad
 	const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
9c64ad
 	const char *policy = NULL, *newname = NULL;
9c64ad
@@ -1358,7 +1366,7 @@ int do_command6(int argc, char *argv[],
9c64ad
 
9c64ad
 	opts = xt_params->orig_opts;
9c64ad
 	while ((cs.c = getopt_long(argc, argv,
9c64ad
-	   "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvw::nt:m:xc:g:46",
9c64ad
+	   "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvw::W::nt:m:xc:g:46",
9c64ad
 					   opts, NULL)) != -1) {
9c64ad
 		switch (cs.c) {
9c64ad
 			/*
9c64ad
@@ -1614,6 +1622,23 @@ int do_command6(int argc, char *argv[],
9c64ad
 						"wait seconds not numeric");
9c64ad
 			break;
9c64ad
 
9c64ad
+		case 'W':
9c64ad
+			if (restore) {
9c64ad
+				xtables_error(PARAMETER_PROBLEM,
9c64ad
+					      "You cannot use `-W' from "
9c64ad
+					      "ip6tables-restore");
9c64ad
+			}
9c64ad
+			if (optarg)
9c64ad
+				parse_wait_interval(optarg, &wait_interval);
9c64ad
+			else if (optind < argc &&
9c64ad
+				argv[optind][0] != '-' &&
9c64ad
+				argv[optind][0] != '!')
9c64ad
+				parse_wait_interval(argv[optind++],
9c64ad
+						    &wait_interval);
9c64ad
+
9c64ad
+			wait_interval_set = true;
9c64ad
+			break;
9c64ad
+
9c64ad
 		case 'm':
9c64ad
 			command_match(&cs);
9c64ad
 			break;
9c64ad
@@ -1718,6 +1743,10 @@ int do_command6(int argc, char *argv[],
9c64ad
 		cs.invert = FALSE;
9c64ad
 	}
9c64ad
 
9c64ad
+	if (!wait && wait_interval_set)
9c64ad
+		xtables_error(PARAMETER_PROBLEM,
9c64ad
+			      "--wait-interval only makes sense with --wait\n");
9c64ad
+
9c64ad
 	if (strcmp(*table, "nat") == 0 &&
9c64ad
 	    ((policy != NULL && strcmp(policy, "DROP") == 0) ||
9c64ad
 	    (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0)))
9c64ad
@@ -1768,7 +1797,7 @@ int do_command6(int argc, char *argv[],
9c64ad
 	generic_opt_check(command, cs.options);
9c64ad
 
9c64ad
 	/* Attempt to acquire the xtables lock */
9c64ad
-	if (!restore && !xtables_lock(wait)) {
9c64ad
+	if (!restore && !xtables_lock(wait, &wait_interval)) {
9c64ad
 		fprintf(stderr, "Another app is currently holding the xtables lock. ");
9c64ad
 		if (wait == 0)
9c64ad
 			fprintf(stderr, "Perhaps you want to use the -w option?\n");
9c64ad
diff -up iptables-1.4.21/iptables/iptables.8.in.wait-interval iptables-1.4.21/iptables/iptables.8.in
9c64ad
--- iptables-1.4.21/iptables/iptables.8.in.wait-interval	2017-04-05 14:04:04.555346605 +0200
9c64ad
+++ iptables-1.4.21/iptables/iptables.8.in	2017-04-05 14:04:04.562346670 +0200
9c64ad
@@ -369,6 +369,13 @@ the program will exit if the lock cannot
9c64ad
 make the program wait (indefinitely or for optional \fIseconds\fP) until
9c64ad
 the exclusive lock can be obtained.
9c64ad
 .TP
9c64ad
+\fB\-W\fP, \fB\-\-wait-interval\fP \fImicroseconds\fP
9c64ad
+Interval to wait per each iteration.
9c64ad
+When running latency sensitive applications, waiting for the xtables lock
9c64ad
+for extended durations may not be acceptable. This option will make each
9c64ad
+iteration take the amount of time specified. The default interval is
9c64ad
+1 second. This option only works with \fB\-w\fP.
9c64ad
+.TP
9c64ad
 \fB\-n\fP, \fB\-\-numeric\fP
9c64ad
 Numeric output.
9c64ad
 IP addresses and port numbers will be printed in numeric format.
9c64ad
diff -up iptables-1.4.21/iptables/iptables.c.wait-interval iptables-1.4.21/iptables/iptables.c
9c64ad
--- iptables-1.4.21/iptables/iptables.c.wait-interval	2017-04-05 14:04:04.555346605 +0200
9c64ad
+++ iptables-1.4.21/iptables/iptables.c	2017-04-05 14:04:04.563346679 +0200
9c64ad
@@ -100,6 +100,7 @@ static struct option original_opts[] = {
9c64ad
 	{.name = "out-interface", .has_arg = 1, .val = 'o'},
9c64ad
 	{.name = "verbose",       .has_arg = 0, .val = 'v'},
9c64ad
 	{.name = "wait",          .has_arg = 2, .val = 'w'},
9c64ad
+	{.name = "wait-interval", .has_arg = 2, .val = 'W'},
9c64ad
 	{.name = "exact",         .has_arg = 0, .val = 'x'},
9c64ad
 	{.name = "fragments",     .has_arg = 0, .val = 'f'},
9c64ad
 	{.name = "version",       .has_arg = 0, .val = 'V'},
9c64ad
@@ -252,7 +253,9 @@ exit_printhelp(const struct xtables_rule
9c64ad
 "				network interface name ([+] for wildcard)\n"
9c64ad
 "  --table	-t table	table to manipulate (default: `filter')\n"
9c64ad
 "  --verbose	-v		verbose mode\n"
9c64ad
-"  --wait	-w [seconds]	wait for the xtables lock\n"
9c64ad
+"  --wait	-w [seconds]	maximum wait to acquire xtables lock before give up\n"
9c64ad
+"  --wait-interval -W [usecs]	wait time to try to acquire xtables lock\n"
9c64ad
+"				default is 1 second\n"
9c64ad
 "  --line-numbers		print line numbers when listing\n"
9c64ad
 "  --exact	-x		expand numbers (display exact values)\n"
9c64ad
 "[!] --fragment	-f		match second or further fragments only\n"
9c64ad
@@ -1316,7 +1319,10 @@ int do_command4(int argc, char *argv[],
9c64ad
 	unsigned int nsaddrs = 0, ndaddrs = 0;
9c64ad
 	struct in_addr *saddrs = NULL, *smasks = NULL;
9c64ad
 	struct in_addr *daddrs = NULL, *dmasks = NULL;
9c64ad
-
9c64ad
+	struct timeval wait_interval = {
9c64ad
+		.tv_sec = 1,
9c64ad
+	};
9c64ad
+	bool wait_interval_set = false;
9c64ad
 	int verbose = 0;
9c64ad
 	int wait = 0;
9c64ad
 	const char *chain = NULL;
9c64ad
@@ -1353,7 +1359,7 @@ int do_command4(int argc, char *argv[],
9c64ad
 	opterr = 0;
9c64ad
 	opts = xt_params->orig_opts;
9c64ad
 	while ((cs.c = getopt_long(argc, argv,
9c64ad
-	   "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::nt:m:xc:g:46",
9c64ad
+	   "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46",
9c64ad
 					   opts, NULL)) != -1) {
9c64ad
 		switch (cs.c) {
9c64ad
 			/*
9c64ad
@@ -1607,6 +1613,23 @@ int do_command4(int argc, char *argv[],
9c64ad
 						"wait seconds not numeric");
9c64ad
 			break;
9c64ad
 
9c64ad
+		case 'W':
9c64ad
+			if (restore) {
9c64ad
+				xtables_error(PARAMETER_PROBLEM,
9c64ad
+					      "You cannot use `-W' from "
9c64ad
+					      "iptables-restore");
9c64ad
+			}
9c64ad
+			if (optarg)
9c64ad
+				parse_wait_interval(optarg, &wait_interval);
9c64ad
+			else if (optind < argc &&
9c64ad
+				 argv[optind][0] != '-' &&
9c64ad
+				 argv[optind][0] != '!')
9c64ad
+				parse_wait_interval(argv[optind++],
9c64ad
+						    &wait_interval);
9c64ad
+
9c64ad
+			wait_interval_set = true;
9c64ad
+			break;
9c64ad
+
9c64ad
 		case 'm':
9c64ad
 			command_match(&cs);
9c64ad
 			break;
9c64ad
@@ -1707,6 +1730,10 @@ int do_command4(int argc, char *argv[],
9c64ad
 		cs.invert = FALSE;
9c64ad
 	}
9c64ad
 
9c64ad
+	if (!wait && wait_interval_set)
9c64ad
+		xtables_error(PARAMETER_PROBLEM,
9c64ad
+			      "--wait-interval only makes sense with --wait\n");
9c64ad
+
9c64ad
 	if (strcmp(*table, "nat") == 0 &&
9c64ad
 	    ((policy != NULL && strcmp(policy, "DROP") == 0) ||
9c64ad
 	    (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0)))
9c64ad
@@ -1757,7 +1784,7 @@ int do_command4(int argc, char *argv[],
9c64ad
 	generic_opt_check(command, cs.options);
9c64ad
 
9c64ad
 	/* Attempt to acquire the xtables lock */
9c64ad
-	if (!restore && !xtables_lock(wait)) {
9c64ad
+	if (!restore && !xtables_lock(wait, &wait_interval)) {
9c64ad
 		fprintf(stderr, "Another app is currently holding the xtables lock. ");
9c64ad
 		if (wait == 0)
9c64ad
 			fprintf(stderr, "Perhaps you want to use the -w option?\n");
9c64ad
diff -up iptables-1.4.21/iptables/xshared.c.wait-interval iptables-1.4.21/iptables/xshared.c
9c64ad
--- iptables-1.4.21/iptables/xshared.c.wait-interval	2017-04-05 14:04:04.557346624 +0200
9c64ad
+++ iptables-1.4.21/iptables/xshared.c	2017-04-05 14:04:04.563346679 +0200
9c64ad
@@ -9,12 +9,15 @@
9c64ad
 #include <sys/file.h>
9c64ad
 #include <sys/socket.h>
9c64ad
 #include <sys/un.h>
9c64ad
+#include <sys/time.h>
9c64ad
 #include <unistd.h>
9c64ad
 #include <fcntl.h>
9c64ad
 #include <xtables.h>
9c64ad
+#include <math.h>
9c64ad
 #include "xshared.h"
9c64ad
 
9c64ad
 #define XT_LOCK_NAME	"/run/xtables.lock"
9c64ad
+#define BASE_MICROSECONDS	100000
9c64ad
 
9c64ad
 /*
9c64ad
  * Print out any special helps. A user might like to be able to add a --help
9c64ad
@@ -244,9 +247,15 @@ void xs_init_match(struct xtables_match
9c64ad
 		match->init(match->m);
9c64ad
 }
9c64ad
 
9c64ad
-bool xtables_lock(int wait)
9c64ad
+bool xtables_lock(int wait, struct timeval *wait_interval)
9c64ad
 {
9c64ad
-	int fd, waited = 0, i = 0;
9c64ad
+	struct timeval time_left, wait_time, waited_time;
9c64ad
+	int fd, i = 0;
9c64ad
+
9c64ad
+	time_left.tv_sec = wait;
9c64ad
+	time_left.tv_usec = 0;
9c64ad
+	waited_time.tv_sec = 0;
9c64ad
+	waited_time.tv_usec = 0;
9c64ad
 
9c64ad
 	fd = open(XT_LOCK_NAME, O_CREAT, 0600);
9c64ad
 	if (fd < 0)
9c64ad
@@ -255,12 +264,43 @@ bool xtables_lock(int wait)
9c64ad
 	while (1) {
9c64ad
 		if (flock(fd, LOCK_EX | LOCK_NB) == 0)
9c64ad
 			return true;
9c64ad
-		else if (wait >= 0 && waited >= wait)
9c64ad
+		if (++i % 10 == 0) {
9c64ad
+			if (wait != -1)
9c64ad
+				fprintf(stderr, "Another app is currently holding the xtables lock; "
9c64ad
+					"still %lds %ldus time ahead to have a chance to grab the lock...\n",
9c64ad
+					time_left.tv_sec, time_left.tv_usec);
9c64ad
+			else
9c64ad
+				fprintf(stderr, "Another app is currently holding the xtables lock; "
9c64ad
+						"waiting for it to exit...\n");
9c64ad
+		}
9c64ad
+
9c64ad
+		wait_time = *wait_interval;
9c64ad
+		select(0, NULL, NULL, NULL, &wait_time);
9c64ad
+		if (wait == -1)
9c64ad
+			continue;
9c64ad
+
9c64ad
+		timeradd(&waited_time, wait_interval, &waited_time);
9c64ad
+		timersub(&time_left, wait_interval, &time_left);
9c64ad
+		if (!timerisset(&time_left))
9c64ad
 			return false;
9c64ad
-		if (++i % 2 == 0)
9c64ad
-			fprintf(stderr, "Another app is currently holding the xtables lock; "
9c64ad
-				"waiting (%ds) for it to exit...\n", waited);
9c64ad
-		waited++;
9c64ad
-		sleep(1);
9c64ad
 	}
9c64ad
 }
9c64ad
+
9c64ad
+void parse_wait_interval(const char *str, struct timeval *wait_interval)
9c64ad
+{
9c64ad
+	unsigned int usec;
9c64ad
+	int ret;
9c64ad
+
9c64ad
+	ret = sscanf(str, "%u", &usec);
9c64ad
+	if (ret == 1) {
9c64ad
+		if (usec > 999999)
9c64ad
+			xtables_error(PARAMETER_PROBLEM,
9c64ad
+				      "too long usec wait %u > 999999 usec",
9c64ad
+				      usec);
9c64ad
+
9c64ad
+		wait_interval->tv_sec = 0;
9c64ad
+		wait_interval->tv_usec = usec;
9c64ad
+		return;
9c64ad
+	}
9c64ad
+	xtables_error(PARAMETER_PROBLEM, "wait interval not numeric");
9c64ad
+}
9c64ad
diff -up iptables-1.4.21/iptables/xshared.h.wait-interval iptables-1.4.21/iptables/xshared.h
9c64ad
--- iptables-1.4.21/iptables/xshared.h.wait-interval	2017-04-05 14:04:04.555346605 +0200
9c64ad
+++ iptables-1.4.21/iptables/xshared.h	2017-04-05 14:04:04.563346679 +0200
9c64ad
@@ -84,7 +84,9 @@ extern struct xtables_match *load_proto(
9c64ad
 extern int subcmd_main(int, char **, const struct subcommand *);
9c64ad
 extern void xs_init_target(struct xtables_target *);
9c64ad
 extern void xs_init_match(struct xtables_match *);
9c64ad
-extern bool xtables_lock(int wait);
9c64ad
+bool xtables_lock(int wait, struct timeval *wait_interval);
9c64ad
+
9c64ad
+void parse_wait_interval(const char *str, struct timeval *wait_interval);
9c64ad
 
9c64ad
 extern const struct xtables_afinfo *afinfo;
9c64ad