• L
    network: force re-creation of iptables private chains on firewalld restart · f5418b42
    Laine Stump 提交于
    When firewalld is stopped, it removes *all* iptables rules and chains,
    including those added by libvirt. Since restarting firewalld means
    stopping and then starting it, any time it is restarted, libvirt needs
    to recreate all the private iptables chains it uses, along with all
    the rules it adds.
    
    We already have code in place to call networkReloadFirewallRules() any
    time we're notified of a firewalld start, and
    networkReloadFirewallRules() will call
    networkPreReloadFirewallRules(), which calls
    networkSetupPrivateChains(); unfortunately that last call is called
    using virOnce(), meaning that it will only be called the first time
    through networkPreReloadFirewallRules() after libvirtd starts - so of
    course when firewalld is later restarted, the call to
    networkSetupPrivateChains() is skipped.
    
    The neat and tidy way to fix this would be if there was a standard way
    to reset a pthread_once_t object so that the next time virOnce was
    called, it would think the function hadn't been called, and call it
    again. Unfortunately, there isn't any official way of doing that (we
    *could* just fill it with 0 and hope for the best, but that doesn't
    seem very safe.
    
    So instead, this patch just adds a static variable called
    chainInitDone, which is set to true after networkSetupPrivateChains()
    is called for the first time, and then during calls to
    networkPreReloadFirewallRules(), if chainInitDone is set, we call
    networkSetupPrivateChains() directly instead of via virOnce().
    
    It may seem unsafe to directly call a function that is meant to be
    called only once, but I think in this case we're safe - there's
    nothing in the function that is inherently "once only" - it doesn't
    initialize anything that can't safely be re-initialized (as long as
    two threads don't try to do it at the same time), and it only happens
    when responding to a dbus message that firewalld has been started (and
    I don't think it's possible for us to be processing two of those at
    once), and even then only if the initial call to the function has
    already been completed (so we're safe if we receive a firewalld
    restart call at a time when we haven't yet called it, or even if
    another thread is already in the process of executing it. The only
    problematic bit I can think of is if another thread is in the process
    of adding an iptable rule at the time we're executing this function,
    but 1) none of those threads will be trying to add chains, and 2) if
    there was a concurrency problem with other threads adding iptables
    rules while firewalld was being restarted, it would still be a problem
    even without this change.
    
    This is yet another patch that fixes an occurrence of this error:
    
    COMMAND_FAILED: '/usr/sbin/iptables -w10 -w --table filter --insert LIBVIRT_INP --in-interface virbr0 --protocol tcp --destination-port 67 --jump ACCEPT' failed: iptables: No chain/target/match by that name.
    
    In particular, this resolves: https://bugzilla.redhat.com/1813830Signed-off-by: NLaine Stump <laine@redhat.com>
    Reviewed-by: NDaniel P. Berrangé <berrange@redhat.com>
    f5418b42
bridge_driver_platform.h 2.1 KB