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