diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index e8f0dcf7d0..47d5d95678 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -273,7 +273,9 @@ static int networkShutdownNetworkExternal(virNetworkObjPtr obj); static void -networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup); +networkReloadFirewallRules(virNetworkDriverStatePtr driver, + bool startup, + bool force); static void networkRefreshDaemons(virNetworkDriverStatePtr driver); @@ -689,7 +691,7 @@ firewalld_dbus_filter_bridge(DBusConnection *connection G_GNUC_UNUSED, if (reload) { VIR_DEBUG("Reload in bridge_driver because of firewalld."); - networkReloadFirewallRules(driver, false); + networkReloadFirewallRules(driver, false, true); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -798,7 +800,7 @@ networkStateInitialize(bool privileged, virNetworkObjListPrune(network_driver->networks, VIR_CONNECT_LIST_NETWORKS_INACTIVE | VIR_CONNECT_LIST_NETWORKS_TRANSIENT); - networkReloadFirewallRules(network_driver, true); + networkReloadFirewallRules(network_driver, true, false); networkRefreshDaemons(network_driver); if (virDriverShouldAutostart(network_driver->stateDir, &autostart) < 0) @@ -868,7 +870,7 @@ networkStateReload(void) network_driver->networkConfigDir, network_driver->networkAutostartDir, network_driver->xmlopt); - networkReloadFirewallRules(network_driver, false); + networkReloadFirewallRules(network_driver, false, false); networkRefreshDaemons(network_driver); virNetworkObjListForEach(network_driver->networks, networkAutostartConfig, @@ -2201,14 +2203,16 @@ networkReloadFirewallRulesHelper(virNetworkObjPtr obj, static void -networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup) +networkReloadFirewallRules(virNetworkDriverStatePtr driver, + bool startup, + bool force) { VIR_INFO("Reloading iptables rules"); /* Ideally we'd not even register the driver when unprivilegd * but until we untangle the virt driver that's not viable */ if (!driver->privileged) return; - networkPreReloadFirewallRules(driver, startup); + networkPreReloadFirewallRules(driver, startup, force); virNetworkObjListForEach(driver->networks, networkReloadFirewallRulesHelper, NULL); diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c index 80bd2409e1..b0bd207250 100644 --- a/src/network/bridge_driver_linux.c +++ b/src/network/bridge_driver_linux.c @@ -36,11 +36,14 @@ VIR_LOG_INIT("network.bridge_driver_linux"); #define PROC_NET_ROUTE "/proc/net/route" static virOnceControl createdOnce; -static bool createdChains; +static bool chainInitDone; /* true iff networkSetupPrivateChains was ever called */ +static bool createdChains; /* true iff networkSetupPrivateChains created chains during most recent call */ static virErrorPtr errInitV4; static virErrorPtr errInitV6; -/* Only call via virOnce */ +/* Usually only called via virOnce, but can also be called directly in + * response to firewalld reload (if chainInitDone == true) + */ static void networkSetupPrivateChains(void) { int rc; @@ -82,6 +85,8 @@ static void networkSetupPrivateChains(void) VIR_DEBUG("Global IPv6 chains already exist"); } } + + chainInitDone = true; } @@ -111,7 +116,10 @@ networkHasRunningNetworks(virNetworkDriverStatePtr driver) } -void networkPreReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup) +void +networkPreReloadFirewallRules(virNetworkDriverStatePtr driver, + bool startup, + bool force) { /* * If there are any running networks, we need to @@ -130,29 +138,42 @@ void networkPreReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup * of starting the network though as that makes them * more likely to be seen by a human */ - if (!networkHasRunningNetworks(driver)) { - VIR_DEBUG("Delayed global rule setup as no networks are running"); - return; - } + if (chainInitDone && force) { + /* The Private chains have already been initialized once + * during this run of libvirtd, so 1) we can't do it again via + * virOnce(), and 2) we need to re-add the private chains even + * if there are currently no running networks, because the + * next time a network is started, libvirt will expect that + * the chains have already been added. So we call directly + * instead of via virOnce(). + */ + networkSetupPrivateChains(); - ignore_value(virOnce(&createdOnce, networkSetupPrivateChains)); + } else { + if (!networkHasRunningNetworks(driver)) { + VIR_DEBUG("Delayed global rule setup as no networks are running"); + return; + } - /* - * If this is initial startup, and we just created the - * top level private chains we either - * - * - upgraded from old libvirt - * - freshly booted from clean state - * - * In the first case we must delete the old rules from - * the built-in chains, instead of our new private chains. - * In the second case it doesn't matter, since no existing - * rules will be present. Thus we can safely just tell it - * to always delete from the builin chain - */ - if (startup && createdChains) { - VIR_DEBUG("Requesting cleanup of legacy firewall rules"); - iptablesSetDeletePrivate(false); + ignore_value(virOnce(&createdOnce, networkSetupPrivateChains)); + + /* + * If this is initial startup, and we just created the + * top level private chains we either + * + * - upgraded from old libvirt + * - freshly booted from clean state + * + * In the first case we must delete the old rules from + * the built-in chains, instead of our new private chains. + * In the second case it doesn't matter, since no existing + * rules will be present. Thus we can safely just tell it + * to always delete from the builin chain + */ + if (startup && createdChains) { + VIR_DEBUG("Requesting cleanup of legacy firewall rules"); + iptablesSetDeletePrivate(false); + } } } diff --git a/src/network/bridge_driver_nop.c b/src/network/bridge_driver_nop.c index 08d737511f..db89c10023 100644 --- a/src/network/bridge_driver_nop.c +++ b/src/network/bridge_driver_nop.c @@ -20,7 +20,8 @@ #include void networkPreReloadFirewallRules(virNetworkDriverStatePtr driver G_GNUC_UNUSED, - bool startup G_GNUC_UNUSED) + bool startup G_GNUC_UNUSED, + bool force G_GNUC_UNUSED) { } diff --git a/src/network/bridge_driver_platform.h b/src/network/bridge_driver_platform.h index 169417a6c0..48ab52c160 100644 --- a/src/network/bridge_driver_platform.h +++ b/src/network/bridge_driver_platform.h @@ -62,7 +62,7 @@ struct _virNetworkDriverState { typedef struct _virNetworkDriverState virNetworkDriverState; typedef virNetworkDriverState *virNetworkDriverStatePtr; -void networkPreReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup); +void networkPreReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup, bool force); void networkPostReloadFirewallRules(bool startup); int networkCheckRouteCollision(virNetworkDefPtr def);