[PATCH v5 12/30] network: support setting firewallBackend from network.conf

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



It still can have only one useful value ("iptables"), but once a 2nd
value is supported, it will be selectable by setting
"firewall_backend=nftables" in /etc/libvirt/network.conf.

If firewall_backend isn't set in network.conf, then libvirt will check
to see if FIREWALL_BACKEND_DEFAULT_1 is available and, if so, set
that. (Since FIREWALL_BACKEND_DEFAULT_1 is currently "iptables", this
means checking to see it the iptables binary is present on the
system).  If the default backend isn't available, that is considered a
fatal error (since no networks can be started anyway), so an error is
logged and startup of the network driver fails.

NB: network.conf is itself created from network.conf.in at build time,
and the advertised default setting of firewall_backend (in a commented
out line) is set from the meson_options.txt setting
"firewall_backend_default_1". This way the conf file will have correct
information no matter what ordering is chosen for default backend at
build time (as more backends are added, settings will be added for
"firewall_backend_default_n", and those will be settable in
meson_options.txt and on the meson commandline to change the ordering
of the auto-detection when no backend is set in network.conf).

virNetworkLoadDriverConfig() may look more complicated than necessary,
but as additional backends are added, it will be easier to add checks
for those backends (and to re-order the checks based on builders'
preferences).

Signed-off-by: Laine Stump <laine@xxxxxxxxxx>
---
 meson.build                              |  4 ++
 meson_options.txt                        |  1 +
 src/network/bridge_driver.c              | 22 +++----
 src/network/bridge_driver_conf.c         | 75 +++++++++++++++++++++---
 src/network/bridge_driver_conf.h         |  3 +
 src/network/bridge_driver_linux.c        |  6 +-
 src/network/bridge_driver_nop.c          |  6 +-
 src/network/bridge_driver_platform.h     |  6 +-
 src/network/libvirtd_network.aug         |  5 +-
 src/network/meson.build                  | 22 ++++++-
 src/network/network.conf.in              |  8 +++
 src/network/test_libvirtd_network.aug.in |  3 +
 tests/networkxml2firewalltest.c          |  2 +-
 13 files changed, 134 insertions(+), 29 deletions(-)

diff --git a/meson.build b/meson.build
index 063233e05e..af3719a734 100644
--- a/meson.build
+++ b/meson.build
@@ -1638,6 +1638,10 @@ endif
 
 if not get_option('driver_network').disabled() and conf.has('WITH_LIBVIRTD')
   conf.set('WITH_NETWORK', 1)
+  firewall_backend_default_1 = get_option('firewall_backend_default_1')
+  firewall_backend_default_conf = firewall_backend_default_1
+  firewall_backend_default_1 = 'VIR_FIREWALL_BACKEND_' + firewall_backend_default_1.to_upper()
+  conf.set('FIREWALL_BACKEND_DEFAULT_1', firewall_backend_default_1)
 elif get_option('driver_network').enabled()
   error('libvirtd must be enabled to build the network driver')
 endif
diff --git a/meson_options.txt b/meson_options.txt
index 6258e50c91..41342793bc 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -115,6 +115,7 @@ option('dtrace', type: 'feature', value: 'auto', description: 'use dtrace for st
 option('firewalld', type: 'feature', value: 'auto', description: 'firewalld support')
 # dep:firewalld
 option('firewalld_zone', type: 'feature', value: 'auto', description: 'whether to install firewalld libvirt zone')
+option('firewall_backend_default_1', type: 'string', value: 'iptables', description: 'first firewall backend to try when none is specified')
 option('host_validate', type: 'feature', value: 'auto', description: 'build virt-host-validate')
 option('init_script', type: 'combo', choices: ['systemd', 'openrc', 'check', 'none'], value: 'check', description: 'Style of init script to install')
 option('loader_nvram', type: 'string', value: '', description: 'Pass list of pairs of <loader>:<nvram> paths. Both pairs and list items are separated by a colon.')
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index e5f9ecf9e8..82e1052978 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -1682,6 +1682,7 @@ static int
 networkReloadFirewallRulesHelper(virNetworkObj *obj,
                                  void *opaque G_GNUC_UNUSED)
 {
+    g_autoptr(virNetworkDriverConfig) cfg = virNetworkDriverGetConfig(networkGetDriver());
     VIR_LOCK_GUARD lock = virObjectLockGuard(obj);
     virNetworkDef *def = virNetworkObjGetDef(obj);
 
@@ -1695,8 +1696,8 @@ networkReloadFirewallRulesHelper(virNetworkObj *obj,
              * network type, forward='open', doesn't need this because it
              * has no iptables rules.
              */
-            networkRemoveFirewallRules(def);
-            ignore_value(networkAddFirewallRules(def));
+            networkRemoveFirewallRules(def, cfg->firewallBackend);
+            ignore_value(networkAddFirewallRules(def, cfg->firewallBackend));
             break;
 
         case VIR_NETWORK_FORWARD_OPEN:
@@ -1948,7 +1949,7 @@ networkStartNetworkVirtual(virNetworkDriverState *driver,
 
     /* Add "once per network" rules */
     if (def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
-        networkAddFirewallRules(def) < 0)
+        networkAddFirewallRules(def, cfg->firewallBackend) < 0)
         goto error;
 
     firewalRulesAdded = true;
@@ -2066,7 +2067,7 @@ networkStartNetworkVirtual(virNetworkDriverState *driver,
 
     if (firewalRulesAdded &&
         def->forward.type != VIR_NETWORK_FORWARD_OPEN)
-        networkRemoveFirewallRules(def);
+        networkRemoveFirewallRules(def, cfg->firewallBackend);
 
     virNetworkObjUnrefMacMap(obj);
 
@@ -2078,7 +2079,8 @@ networkStartNetworkVirtual(virNetworkDriverState *driver,
 
 
 static int
-networkShutdownNetworkVirtual(virNetworkObj *obj)
+networkShutdownNetworkVirtual(virNetworkObj *obj,
+                              virNetworkDriverConfig *cfg)
 {
     virNetworkDef *def = virNetworkObjGetDef(obj);
     pid_t dnsmasqPid;
@@ -2104,7 +2106,7 @@ networkShutdownNetworkVirtual(virNetworkObj *obj)
     ignore_value(virNetDevSetOnline(def->bridge, false));
 
     if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
-        networkRemoveFirewallRules(def);
+        networkRemoveFirewallRules(def, cfg->firewallBackend);
 
     ignore_value(virNetDevBridgeDelete(def->bridge));
 
@@ -2408,7 +2410,7 @@ networkShutdownNetwork(virNetworkDriverState *driver,
     case VIR_NETWORK_FORWARD_NAT:
     case VIR_NETWORK_FORWARD_ROUTE:
     case VIR_NETWORK_FORWARD_OPEN:
-        ret = networkShutdownNetworkVirtual(obj);
+        ret = networkShutdownNetworkVirtual(obj, cfg);
         break;
 
     case VIR_NETWORK_FORWARD_BRIDGE:
@@ -3259,7 +3261,7 @@ networkUpdate(virNetworkPtr net,
                  * old rules (and remember to load new ones after the
                  * update).
                  */
-                networkRemoveFirewallRules(def);
+                networkRemoveFirewallRules(def, cfg->firewallBackend);
                 needFirewallRefresh = true;
                 break;
             default:
@@ -3287,14 +3289,14 @@ networkUpdate(virNetworkPtr net,
                             parentIndex, xml,
                             network_driver->xmlopt, flags) < 0) {
         if (needFirewallRefresh)
-            ignore_value(networkAddFirewallRules(def));
+            ignore_value(networkAddFirewallRules(def, cfg->firewallBackend));
         goto cleanup;
     }
 
     /* @def is replaced */
     def = virNetworkObjGetDef(obj);
 
-    if (needFirewallRefresh && networkAddFirewallRules(def) < 0)
+    if (needFirewallRefresh && networkAddFirewallRules(def, cfg->firewallBackend) < 0)
         goto cleanup;
 
     if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
diff --git a/src/network/bridge_driver_conf.c b/src/network/bridge_driver_conf.c
index a2edafa837..06abab516a 100644
--- a/src/network/bridge_driver_conf.c
+++ b/src/network/bridge_driver_conf.c
@@ -25,6 +25,7 @@
 #include "datatypes.h"
 #include "virlog.h"
 #include "virerror.h"
+#include "virfile.h"
 #include "virutil.h"
 #include "bridge_driver_conf.h"
 
@@ -32,7 +33,6 @@
 
 VIR_LOG_INIT("network.bridge_driver");
 
-
 static virClass *virNetworkDriverConfigClass;
 static void virNetworkDriverConfigDispose(void *obj);
 
@@ -62,18 +62,75 @@ virNetworkLoadDriverConfig(virNetworkDriverConfig *cfg G_GNUC_UNUSED,
                            const char *filename)
 {
     g_autoptr(virConf) conf = NULL;
+    g_autofree char *fwBackendStr = NULL;
+    bool fwBackendSelected = false;
+    size_t i;
+    int fwBackends[] = { FIREWALL_BACKEND_DEFAULT_1 };
+    G_STATIC_ASSERT(G_N_ELEMENTS(fwBackends) == VIR_FIREWALL_BACKEND_LAST);
+
+    if (access(filename, R_OK) == 0) {
+
+        conf = virConfReadFile(filename, 0);
+        if (!conf)
+            return -1;
+
+        /* use virConfGetValue*(conf, ...) functions to read any settings into cfg */
+
+        if (virConfGetValueString(conf, "firewall_backend", &fwBackendStr) < 0)
+            return -1;
+
+        if (fwBackendStr) {
+            fwBackends[0] = virFirewallBackendTypeFromString(fwBackendStr);
+
+            if (fwBackends[0] < 0) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("unrecognized 'firewall_backend = '%1$s' set in network driver config file %2$s"),
+                               fwBackendStr, filename);
+                return -1;
+            }
+            VIR_INFO("firewall_backend setting requested from config file %s: '%s'",
+                     virFirewallBackendTypeToString(fwBackends[0]), filename);
+        }
+    }
 
-    /* if file doesn't exist or is unreadable, ignore the "error" */
-    if (access(filename, R_OK) == -1)
-        return 0;
+    for (i = 0; i < G_N_ELEMENTS(fwBackends) && !fwBackendSelected; i++) {
 
-    conf = virConfReadFile(filename, 0);
-    if (!conf)
-        return -1;
+        switch ((virFirewallBackend)fwBackends[i]) {
+        case VIR_FIREWALL_BACKEND_IPTABLES: {
+            g_autofree char *iptablesInPath = virFindFileInPath(IPTABLES);
 
-    /* use virConfGetValue*(conf, ...) functions to read any settings into cfg */
+            if (iptablesInPath)
+                fwBackendSelected = true;
+            break;
+        }
+        case VIR_FIREWALL_BACKEND_LAST:
+            virReportEnumRangeError(virFirewallBackend, fwBackends[i]);
+            return -1;
+        }
 
-    return 0;
+        if (fwBackendSelected) {
+
+            cfg->firewallBackend = fwBackends[i];
+
+        } else if (fwBackendStr) {
+
+            /* explicitly requested backend not found - this is a failure */
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("requested firewall_backend '%1$s' is not available"),
+                           virFirewallBackendTypeToString(fwBackends[i]));
+            return -1;
+        }
+    }
+
+    if (fwBackendSelected) {
+        VIR_INFO("using firewall_backend: '%s'",
+                 virFirewallBackendTypeToString(cfg->firewallBackend));
+        return 0;
+    } else {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("could not find a usable firewall backend"));
+        return -1;
+    }
 }
 
 
diff --git a/src/network/bridge_driver_conf.h b/src/network/bridge_driver_conf.h
index 426c16198d..8f221f391e 100644
--- a/src/network/bridge_driver_conf.h
+++ b/src/network/bridge_driver_conf.h
@@ -26,6 +26,7 @@
 #include "virdnsmasq.h"
 #include "virnetworkobj.h"
 #include "object_event.h"
+#include "virfirewall.h"
 
 typedef struct _virNetworkDriverConfig virNetworkDriverConfig;
 struct _virNetworkDriverConfig {
@@ -37,6 +38,8 @@ struct _virNetworkDriverConfig {
     char *stateDir;
     char *pidDir;
     char *dnsmasqStateDir;
+
+    virFirewallBackend firewallBackend;
 };
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNetworkDriverConfig, virObjectUnref);
diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c
index 4914d5c903..c2ef27f251 100644
--- a/src/network/bridge_driver_linux.c
+++ b/src/network/bridge_driver_linux.c
@@ -303,7 +303,8 @@ int networkCheckRouteCollision(virNetworkDef *def)
 
 
 int
-networkAddFirewallRules(virNetworkDef *def)
+networkAddFirewallRules(virNetworkDef *def,
+                        virFirewallBackend firewallBackend G_GNUC_UNUSED)
 {
     if (virOnce(&createdOnce, networkSetupPrivateChains) < 0)
         return -1;
@@ -394,7 +395,8 @@ networkAddFirewallRules(virNetworkDef *def)
 
 
 void
-networkRemoveFirewallRules(virNetworkDef *def)
+networkRemoveFirewallRules(virNetworkDef *def,
+                           virFirewallBackend firewallBackend G_GNUC_UNUSED)
 {
     iptablesRemoveFirewallRules(def);
 }
diff --git a/src/network/bridge_driver_nop.c b/src/network/bridge_driver_nop.c
index 6eee6043e6..7d9a061e50 100644
--- a/src/network/bridge_driver_nop.c
+++ b/src/network/bridge_driver_nop.c
@@ -36,11 +36,13 @@ int networkCheckRouteCollision(virNetworkDef *def G_GNUC_UNUSED)
     return 0;
 }
 
-int networkAddFirewallRules(virNetworkDef *def G_GNUC_UNUSED)
+int networkAddFirewallRules(virNetworkDef *def G_GNUC_UNUSED,
+                            virFirewallBackend firewallBackend G_GNUC_UNUSED)
 {
     return 0;
 }
 
-void networkRemoveFirewallRules(virNetworkDef *def G_GNUC_UNUSED)
+void networkRemoveFirewallRules(virNetworkDef *def G_GNUC_UNUSED,
+                               virFirewallBackend firewallBackend G_GNUC_UNUSED)
 {
 }
diff --git a/src/network/bridge_driver_platform.h b/src/network/bridge_driver_platform.h
index b720d343be..7443c3129f 100644
--- a/src/network/bridge_driver_platform.h
+++ b/src/network/bridge_driver_platform.h
@@ -32,6 +32,8 @@ void networkPostReloadFirewallRules(bool startup);
 
 int networkCheckRouteCollision(virNetworkDef *def);
 
-int networkAddFirewallRules(virNetworkDef *def);
+int networkAddFirewallRules(virNetworkDef *def,
+                            virFirewallBackend firewallBackend);
 
-void networkRemoveFirewallRules(virNetworkDef *def);
+void networkRemoveFirewallRules(virNetworkDef *def,
+                                virFirewallBackend firewallBackend);
diff --git a/src/network/libvirtd_network.aug b/src/network/libvirtd_network.aug
index ae153d96a1..5d6d72dd92 100644
--- a/src/network/libvirtd_network.aug
+++ b/src/network/libvirtd_network.aug
@@ -22,11 +22,14 @@ module Libvirtd_network =
    let int_entry       (kw:string) = [ key kw . value_sep . int_val ]
    let str_array_entry (kw:string) = [ key kw . value_sep . str_array_val ]
 
+   let firewall_backend_entry = str_entry "firewall_backend"
+
    (* Each entry in the config is one of the following *)
+   let entry = firewall_backend_entry
    let comment = [ label "#comment" . del /#[ \t]*/ "# " .  store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
    let empty = [ label "#empty" . eol ]
 
-   let record = indent . eol
+   let record = indent . entry . eol
 
    let lns = ( record | comment | empty ) *
 
diff --git a/src/network/meson.build b/src/network/meson.build
index 0336435862..c1934d2e68 100644
--- a/src/network/meson.build
+++ b/src/network/meson.build
@@ -49,16 +49,34 @@ if conf.has('WITH_NETWORK')
     ],
   }
 
+  network_options_conf = configuration_data({
+    'FIREWALL_BACKEND': firewall_backend_default_conf,
+  })
+
   network_conf = configure_file(
     input: 'network.conf.in',
     output: 'network.conf',
-    configuration: configmake_conf,
+    configuration: network_options_conf,
   )
+
+  network_options_hack_conf = configuration_data({
+    'FIREWALL_BACKEND': firewall_backend_default_conf,
+    # This hack is necessary because the output file is going to be
+    # used as input for another configure_file() call later, which
+    # will take care of substituting @CONFIG@ with useful data
+    'CONFIG': '@CONFIG@',
+  })
+  test_libvirtd_network_aug_tmp = configure_file(
+    input: 'test_libvirtd_network.aug.in',
+    output: 'test_libvirtd_network.aug.tmp',
+    configuration: network_options_hack_conf,
+  )
+
   virt_conf_files += network_conf
   virt_aug_files += files('libvirtd_network.aug')
   virt_test_aug_files += {
     'name': 'test_libvirtd_network.aug',
-    'aug': files('test_libvirtd_network.aug.in'),
+    'aug': test_libvirtd_network_aug_tmp,
     'conf': network_conf,
     'test_name': 'libvirtd_network',
     'test_srcdir': meson.current_source_dir(),
diff --git a/src/network/network.conf.in b/src/network/network.conf.in
index 5c84003f6d..ec75e125d8 100644
--- a/src/network/network.conf.in
+++ b/src/network/network.conf.in
@@ -1,3 +1,11 @@
 # Master configuration file for the network driver.
 # All settings described here are optional - if omitted, sensible
 # defaults are used.
+
+# firewall_backend:
+#
+#   determines which subsystem to use to setup firewall packet
+#   filtering rules for virtual networks. Currently the only supported
+#   selection is "iptables".
+#
+#firewall_backend = "@FIREWALL_BACKEND@"
diff --git a/src/network/test_libvirtd_network.aug.in b/src/network/test_libvirtd_network.aug.in
index ffdca520ce..9e29a9192f 100644
--- a/src/network/test_libvirtd_network.aug.in
+++ b/src/network/test_libvirtd_network.aug.in
@@ -1,2 +1,5 @@
 module Test_libvirtd_network =
   @CONFIG@
+
+  test Libvirtd_network.lns get conf =
+{ "firewall_backend" = "@FIREWALL_BACKEND@" }
diff --git a/tests/networkxml2firewalltest.c b/tests/networkxml2firewalltest.c
index cb66a26294..3a9f409e2a 100644
--- a/tests/networkxml2firewalltest.c
+++ b/tests/networkxml2firewalltest.c
@@ -98,7 +98,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
     if (!(def = virNetworkDefParse(NULL, xml, NULL, false)))
         return -1;
 
-    if (networkAddFirewallRules(def) < 0)
+    if (networkAddFirewallRules(def, VIR_FIREWALL_BACKEND_IPTABLES) < 0)
         return -1;
 
     actual = actualargv = virBufferContentAndReset(&buf);
-- 
2.45.0




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux