Adapted version of
commit b3b451d6f8946986b8f50c8bcddeef50ed7a5f8f
Author: Jiri Popelka <jpopelka@redhat.com>
Date: Mon Oct 27 17:45:46 2014 +0100
ipXtables: use -w or -w2 if supported
iptables (since 1.4.20) has a locking mechanism [1],
which prevents multiple instances of the program from running concurrently.
It can happen that some other daemon (libvirtd [2], docker [3])
is calling iptables at the same time as firewalld.
In that case the second one which calls iptables fails with:
"Another app is currently holding the xtables lock.
Perhaps you want to use the -w option?"
The easiest work-around is the use the suggested "-w" option,
which makes the second iptables instance wait till the lock is released.
Even better is to use "-w2" [2] which makes it wait for max 2 seconds.
[1] https://git.netfilter.org/iptables/commit/?id=93587a04d0f2511e108bbc4d87a8b9d28a5c5dd8
[2] https://bugzilla.redhat.com/show_bug.cgi?id=1098281
[3] https://bugzilla.redhat.com/show_bug.cgi?id=1151067
[4] https://git.netfilter.org/iptables/commit/?id=aaa4ace72ba1d195bbf436134a336816c33f7bd0
diff --git a/src/firewall/core/ipXtables.py b/src/firewall/core/ipXtables.py
index 8f61bb8..e8381f2 100644
--- a/src/firewall/core/ipXtables.py
+++ b/src/firewall/core/ipXtables.py
@@ -125,10 +125,14 @@ class ip4tables:
def __init__(self):
self._command = COMMAND[self.ipv]
+ self.wait_option = self._detect_wait_option()
def __run(self, args):
# convert to string list
- _args = ["%s" % item for item in args]
+ if self.wait_option:
+ _args = [self.wait_option] + ["%s" % item for item in args]
+ else:
+ _args = ["%s" % item for item in args]
log.debug2("%s: %s %s", self.__class__, self._command, " ".join(_args))
(status, ret) = runProg(self._command, _args)
if status != 0:
@@ -170,6 +174,18 @@ class ip4tables:
return tables
+ def _detect_wait_option(self):
+ wait_option = ""
+ (status, ret) = runProg(self._command, ["-w", "-L"]) # since iptables-1.4.20
+ if status == 0:
+ wait_option = "-w" # wait for xtables lock
+ (status, ret) = runProg(self._command, ["-w2", "-L"]) # since iptables > 1.4.21
+ if status == 0:
+ wait_option = "-w2" # wait max 2 seconds
+ log.debug2("%s: %s will be using %s option.", self.__class__, self._command, wait_option)
+
+ return wait_option
+
def flush(self):
tables = self.used_tables()
for table in tables: