Adapted version of commit b3b451d6f8946986b8f50c8bcddeef50ed7a5f8f Author: Jiri Popelka 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: