From e8f857a5a1514c3e7d0d8ea0f7d2d571f0e37bd1 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Thu, 23 Jun 2016 18:44:06 -0600 Subject: 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 Signed-off-by: Pablo Neira Ayuso --- iptables/xshared.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 8 deletions(-) (limited to 'iptables/xshared.c') diff --git a/iptables/xshared.c b/iptables/xshared.c index 81c2581f..cccb8aec 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -9,12 +9,15 @@ #include #include #include +#include #include #include #include +#include #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) 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"); +} -- cgit v1.2.3