[PATCH 7/8] util: synchronize with firewalld before we start calling iptables directly
Daniel Henrique Barboza
danielhb413 at gmail.com
Tue Nov 24 11:46:33 UTC 2020
On 11/24/20 12:30 AM, Laine Stump wrote:
> When it is starting up, firewalld will delete all existing iptables
> rules and chains before adding its own rules. If libvirtd were to try
> to directly add iptables rules during the time before firewalld has
> finished initializing, firewalld would end up deleting the rules that
> libvirtd has just added.
>
> Currently this isn't a problem, since libvirtd only adds iptables
> rules via the firewalld "passthrough command" API, and so firewalld is
> able to properly serialize everything. However, we will soon be
> changing libvirtd to add its iptables and ebtables rules by directly
> calling iptables/ebtables rather than via firewalld, thus removing the
> serialization of libvirtd adding rules vs. firewalld deleting rules.
>
> This will especially apparent (if we don't fix it in advance, as this
> patch does) when libvirtd is responding to the dbus NameOwnerChanged
> event, which is used to learn when firewalld has been restarted. In
> that case, dbus sends the event before firewalld has been able to
> complete its initialization, so when libvirt responds to the event by
> adding back its iptables rules (with direct calls to
> /usr/bin/iptables), some of those rules are added before firewalld has
> a chance to do its "remove everything" startup protocol. The usual
> result of this is that libvirt will successfully add its private
> chains (e.g. LIBVIRT_INP, etc), but then fail when it tries to add a
> rule jumping to one of those chains (because in the interim, firewalld
> has deleted the new chains).
>
> The solution is for libvirt to preface it's direct calling to iptables
> with a iptables command sent via firewalld's passthrough command
> API. Since cmmands sent to firewalld are completed synchronously, and
s/cmmands/commands
> since firewalld won't service them until it has completed its own
> initialization, this will assure that by the time libvirt starts
> calling iptables to add rules, that firewalld will not be following up
> by deleting any of those rules.
>
> To minimize the amount of extra overhead, we request the simplest
> iptables command possible: "iptables -V" (and aside from logging a
> debug message, we ignore the result, for good measure).
>
> (This patch is being done *before* the patch that switches to calling
> iptables directly, so that everything will function properly with any
> fractional part of the series applied).
>
> Signed-off-by: Laine Stump <laine at redhat.com>
> ---
> src/libvirt_private.syms | 1 +
> src/util/virfirewall.c | 30 ++++++++++++++++++++++++++++++
> src/util/virfirewall.h | 2 ++
> src/util/viriptables.c | 7 +++++++
> 4 files changed, 40 insertions(+)
>
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 5684cd3316..2cd046df8b 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -2148,6 +2148,7 @@ virFileCacheSetPriv;
> # util/virfirewall.h
> virFirewallAddRuleFull;
> virFirewallApply;
> +virFirewallBackendSynchronize;
> virFirewallFree;
> virFirewallNew;
> virFirewallRemoveRule;
> diff --git a/src/util/virfirewall.c b/src/util/virfirewall.c
> index 0b022b14af..307825331d 100644
> --- a/src/util/virfirewall.c
> +++ b/src/util/virfirewall.c
> @@ -649,6 +649,36 @@ virFirewallApplyRuleFirewallD(virFirewallRulePtr rule,
> return virFirewallDApplyRule(rule->layer, rule->args, rule->argsLen, ignoreErrors, output);
> }
>
> +
> +void
> +virFirewallBackendSynchronize(void)
> +{
> + const char *arg = "-V";
> + g_autofree char *output = NULL;
> +
> + switch (currentBackend) {
> + case VIR_FIREWALL_BACKEND_DIRECT:
> + /* nobody to synchronize with */
> + break;
> + case VIR_FIREWALL_BACKEND_FIREWALLD:
> + /* Send a simple rule via firewalld's passthrough iptables
> + * command so that we'll be sure firewalld has fully
> + * initialized and caught up with its internal queue of
> + * iptables commands. Waiting for this will prevent our own
> + * directly-executed iptables commands from being run while
> + * firewalld is still initializing.
> + */
> + ignore_value(virFirewallDApplyRule(VIR_FIREWALL_LAYER_IPV4,
> + (char **)&arg, 1, true, &output));
> + VIR_DEBUG("Result of 'iptables -V' via firewalld: %s", NULLSTR(output));
> + break;
> + case VIR_FIREWALL_BACKEND_AUTOMATIC:
> + case VIR_FIREWALL_BACKEND_LAST:
> + break;
> + }
> +}
> +
> +
> static int
> virFirewallApplyRule(virFirewallPtr firewall,
> virFirewallRulePtr rule,
> diff --git a/src/util/virfirewall.h b/src/util/virfirewall.h
> index fda3cdec01..3db0864380 100644
> --- a/src/util/virfirewall.h
> +++ b/src/util/virfirewall.h
> @@ -111,4 +111,6 @@ void virFirewallStartRollback(virFirewallPtr firewall,
>
> int virFirewallApply(virFirewallPtr firewall);
>
> +void virFirewallBackendSynchronize(void);
> +
> G_DEFINE_AUTOPTR_CLEANUP_FUNC(virFirewall, virFirewallFree);
> diff --git a/src/util/viriptables.c b/src/util/viriptables.c
> index 9cfbc9f2aa..5fbb77fd5b 100644
> --- a/src/util/viriptables.c
> +++ b/src/util/viriptables.c
> @@ -150,6 +150,13 @@ iptablesSetupPrivateChains(virFirewallLayer layer)
> };
> size_t i;
>
> + /* When the backend is firewalld, we need to make sure that
> + * firewalld has been fully started and completed its
> + * initialization, otherwise firewalld might delete our rules soon
> + * after we add them!
> + */
> + virFirewallBackendSynchronize();
> +
> virFirewallStartTransaction(fw, 0);
>
> for (i = 0; i < G_N_ELEMENTS(data); i++)
>
More information about the libvir-list
mailing list