[PATCH 4/5] nwfilter: allow use of nftables nwfilter driver via nwfilter.conf

Dion Bosschieter posted 5 patches 1 month, 1 week ago
There is a newer version of this series
[PATCH 4/5] nwfilter: allow use of nftables nwfilter driver via nwfilter.conf
Posted by Dion Bosschieter 1 month, 1 week ago
Change the nwfilter driver loading mechanism to read from nwfilter.conf.
By default, it will use the existing ebiptables driver, which can be
replaced in the future to remove the {eb,ip}tables dependency.

Added nftables to *filter_tech_drivers as an available driver option
for users to choose from.

Signed-off-by: Dion Bosschieter <dionbosschieter@gmail.com>
---
 src/nwfilter/nwfilter_driver.c         | 49 +++++++++++++++++++--
 src/nwfilter/nwfilter_gentech_driver.c | 60 +++++++++++---------------
 src/nwfilter/nwfilter_gentech_driver.h |  4 +-
 3 files changed, 73 insertions(+), 40 deletions(-)

diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c
index 522cfda022..18d322574d 100644
--- a/src/nwfilter/nwfilter_driver.c
+++ b/src/nwfilter/nwfilter_driver.c
@@ -26,9 +26,7 @@
 
 #include "virgdbus.h"
 #include "virlog.h"
-
 #include "internal.h"
-
 #include "virerror.h"
 #include "datatypes.h"
 #include "nwfilter_driver.h"
@@ -36,7 +34,6 @@
 #include "configmake.h"
 #include "virpidfile.h"
 #include "viraccessapicheck.h"
-
 #include "nwfilter_ipaddrmap.h"
 #include "nwfilter_dhcpsnoop.h"
 #include "nwfilter_learnipaddr.h"
@@ -203,6 +200,41 @@ nwfilterStateCleanup(void)
 }
 
 
+/**
+ * virNWFilterLoadGentechDriverFromConfig:
+ *
+ * Loading driver name from nwfilter.conf config file
+ */
+static char *
+virNWFilterLoadGentechDriverFromConfig(const char *configfile)
+{
+    g_autoptr(virConf) conf = NULL;
+    g_autofree char *drivername = NULL;
+
+    if (access(configfile, R_OK) == 0) {
+
+        conf = virConfReadFile(configfile, 0);
+        if (!conf)
+            return NULL;
+
+        if (virConfGetValueString(conf, "driver", &drivername) < 0)
+            return NULL;
+
+        if (drivername) {
+            VIR_DEBUG("nwfilter driver setting requested from config file %s: '%s'",
+                      configfile, drivername);
+        }
+    }
+
+    if (!drivername) {
+        drivername = g_strdup(NWFILTER_DEFAULT_DRIVER);
+    }
+
+
+    return g_steal_pointer(&drivername);
+}
+
+
 /**
  * nwfilterStateInitialize:
  *
@@ -217,6 +249,8 @@ nwfilterStateInitialize(bool privileged,
 {
     VIR_LOCK_GUARD lock = virLockGuardLock(&driverMutex);
     GDBusConnection *sysbus = NULL;
+    g_autofree char *configfile = NULL;
+    char *gentechdrivername = NULL;
 
     if (root != NULL) {
         virReportError(VIR_ERR_INVALID_ARG, "%s",
@@ -266,7 +300,14 @@ nwfilterStateInitialize(bool privileged,
     if (virNWFilterDHCPSnoopInit() < 0)
         goto error;
 
-    if (virNWFilterTechDriversInit(privileged) < 0)
+    configfile = g_strdup(SYSCONFDIR "/libvirt/nwfilter.conf");
+
+    /* get chosen driver from config file */
+    gentechdrivername = virNWFilterLoadGentechDriverFromConfig(configfile);
+    if (gentechdrivername == NULL)
+        goto error;
+
+    if (virNWFilterTechDriversInit(privileged, gentechdrivername) < 0)
         goto error;
 
     if (virNWFilterConfLayerInit(virNWFilterTriggerRebuildImpl, driver) < 0)
diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c
index 1465734a54..adb96acca6 100644
--- a/src/nwfilter/nwfilter_gentech_driver.c
+++ b/src/nwfilter/nwfilter_gentech_driver.c
@@ -32,6 +32,7 @@
 #include "nwfilter_dhcpsnoop.h"
 #include "nwfilter_ipaddrmap.h"
 #include "nwfilter_learnipaddr.h"
+#include "nwfilter_nftables_driver.h"
 #include "virnetdev.h"
 
 #define VIR_FROM_THIS VIR_FROM_NWFILTER
@@ -48,18 +49,20 @@ static int _virNWFilterTeardownFilter(const char *ifname);
 
 static virNWFilterTechDriver *filter_tech_drivers[] = {
     &ebiptables_driver,
-    NULL
+    &nftables_driver,
 };
 
-int virNWFilterTechDriversInit(bool privileged)
+int virNWFilterTechDriversInit(bool privileged, const char *drivername)
 {
     size_t i = 0;
-    VIR_DEBUG("Initializing NWFilter technology drivers");
-    while (filter_tech_drivers[i]) {
-        if (!(filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED))
+    VIR_DEBUG("Initializing NWFilter technology drivers, chosen %s", drivername);
+
+    for (i = 0; i < G_N_ELEMENTS(filter_tech_drivers); i++) {
+        if (!(filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED)
+            && STREQ(filter_tech_drivers[i]->name, drivername))
             filter_tech_drivers[i]->init(privileged);
-        i++;
     }
+
     return 0;
 }
 
@@ -67,25 +70,20 @@ int virNWFilterTechDriversInit(bool privileged)
 void virNWFilterTechDriversShutdown(void)
 {
     size_t i = 0;
-    while (filter_tech_drivers[i]) {
+    for (i = 0; i < G_N_ELEMENTS(filter_tech_drivers); i++) {
         if ((filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED))
             filter_tech_drivers[i]->shutdown();
-        i++;
     }
 }
 
 
 static virNWFilterTechDriver *
-virNWFilterTechDriverForName(const char *name)
+virNWFilterInitializedTechDriver(void)
 {
     size_t i = 0;
-    while (filter_tech_drivers[i]) {
-        if (STREQ(filter_tech_drivers[i]->name, name)) {
-            if ((filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED) == 0)
-                break;
+    for (i = 0; i < G_N_ELEMENTS(filter_tech_drivers); i++) {
+        if ((filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED))
             return filter_tech_drivers[i];
-        }
-        i++;
     }
     return NULL;
 }
@@ -617,7 +615,6 @@ virNWFilterInstantiateFilterUpdate(virNWFilterDriverState *driver,
                                    bool *foundNewFilter)
 {
     int rc = -1;
-    const char *drvname = EBIPTABLES_DRIVER_ID;
     virNWFilterTechDriver *techdriver;
     virNWFilterObj *obj;
     virNWFilterDef *filter;
@@ -625,12 +622,11 @@ virNWFilterInstantiateFilterUpdate(virNWFilterDriverState *driver,
     char vmmacaddr[VIR_MAC_STRING_BUFLEN] = {0};
     virNWFilterVarValue *ipaddr;
 
-    techdriver = virNWFilterTechDriverForName(drvname);
+    techdriver = virNWFilterInitializedTechDriver();
 
     if (!techdriver) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Could not get access to ACL tech driver '%1$s'"),
-                       drvname);
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not get access to ACL tech driver"));
         return -1;
     }
 
@@ -768,15 +764,13 @@ virNWFilterUpdateInstantiateFilter(virNWFilterDriverState *driver,
 static int
 virNWFilterRollbackUpdateFilter(virNWFilterBindingDef *binding)
 {
-    const char *drvname = EBIPTABLES_DRIVER_ID;
     int ifindex;
     virNWFilterTechDriver *techdriver;
 
-    techdriver = virNWFilterTechDriverForName(drvname);
+    techdriver = virNWFilterInitializedTechDriver();
     if (!techdriver) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Could not get access to ACL tech driver '%1$s'"),
-                       drvname);
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not get access to ACL tech driver"));
         return -1;
     }
 
@@ -793,15 +787,13 @@ virNWFilterRollbackUpdateFilter(virNWFilterBindingDef *binding)
 static int
 virNWFilterTearOldFilter(virNWFilterBindingDef *binding)
 {
-    const char *drvname = EBIPTABLES_DRIVER_ID;
     int ifindex;
     virNWFilterTechDriver *techdriver;
 
-    techdriver = virNWFilterTechDriverForName(drvname);
+    techdriver = virNWFilterInitializedTechDriver();
     if (!techdriver) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Could not get access to ACL tech driver '%1$s'"),
-                       drvname);
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not get access to ACL tech driver"));
         return -1;
     }
 
@@ -818,14 +810,12 @@ virNWFilterTearOldFilter(virNWFilterBindingDef *binding)
 static int
 _virNWFilterTeardownFilter(const char *ifname)
 {
-    const char *drvname = EBIPTABLES_DRIVER_ID;
     virNWFilterTechDriver *techdriver;
-    techdriver = virNWFilterTechDriverForName(drvname);
+    techdriver = virNWFilterInitializedTechDriver();
 
     if (!techdriver) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Could not get access to ACL tech driver '%1$s'"),
-                       drvname);
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not get access to ACL tech driver"));
         return -1;
     }
 
diff --git a/src/nwfilter/nwfilter_gentech_driver.h b/src/nwfilter/nwfilter_gentech_driver.h
index 946d5d3d56..8f6f4d164a 100644
--- a/src/nwfilter/nwfilter_gentech_driver.h
+++ b/src/nwfilter/nwfilter_gentech_driver.h
@@ -25,7 +25,9 @@
 #include "virnwfilterobj.h"
 #include "virnwfilterbindingdef.h"
 
-int virNWFilterTechDriversInit(bool privileged);
+#define NWFILTER_DEFAULT_DRIVER "ebiptables"
+
+int virNWFilterTechDriversInit(bool privileged, const char *drivername);
 void virNWFilterTechDriversShutdown(void);
 
 enum instCase {
-- 
2.43.0
Re: [PATCH 4/5] nwfilter: allow use of nftables nwfilter driver via nwfilter.conf
Posted by Daniel P. Berrangé via Devel 1 month ago
On Fri, Oct 31, 2025 at 01:05:44PM +0100, Dion Bosschieter wrote:
> Change the nwfilter driver loading mechanism to read from nwfilter.conf.
> By default, it will use the existing ebiptables driver, which can be
> replaced in the future to remove the {eb,ip}tables dependency.
> 
> Added nftables to *filter_tech_drivers as an available driver option
> for users to choose from.
> 
> Signed-off-by: Dion Bosschieter <dionbosschieter@gmail.com>
> ---
>  src/nwfilter/nwfilter_driver.c         | 49 +++++++++++++++++++--
>  src/nwfilter/nwfilter_gentech_driver.c | 60 +++++++++++---------------
>  src/nwfilter/nwfilter_gentech_driver.h |  4 +-
>  3 files changed, 73 insertions(+), 40 deletions(-)

Adding a config file makes sense, but we need todo a bit more.

The default file should be in git as src/nwfilter/nwfilter.conf.in
so we show (& thus document) the available config options, and
installed by meson.

Also there needs to be augeas files for parsing the config file.
For a trivial example, follow what's done for the virtual network
driver with src/network/libvirtd_network.aug  and
src/network/test_libvirtd_network.aug.in. Also see the meson
file for how to invoke the test file as part of unit tests.


> 
> diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c
> index 522cfda022..18d322574d 100644
> --- a/src/nwfilter/nwfilter_driver.c
> +++ b/src/nwfilter/nwfilter_driver.c
> @@ -26,9 +26,7 @@
>  
>  #include "virgdbus.h"
>  #include "virlog.h"
> -
>  #include "internal.h"
> -
>  #include "virerror.h"
>  #include "datatypes.h"
>  #include "nwfilter_driver.h"
> @@ -36,7 +34,6 @@
>  #include "configmake.h"
>  #include "virpidfile.h"
>  #include "viraccessapicheck.h"
> -
>  #include "nwfilter_ipaddrmap.h"
>  #include "nwfilter_dhcpsnoop.h"
>  #include "nwfilter_learnipaddr.h"
> @@ -203,6 +200,41 @@ nwfilterStateCleanup(void)
>  }
>  
>  
> +/**
> + * virNWFilterLoadGentechDriverFromConfig:
> + *
> + * Loading driver name from nwfilter.conf config file
> + */
> +static char *
> +virNWFilterLoadGentechDriverFromConfig(const char *configfile)
> +{
> +    g_autoptr(virConf) conf = NULL;
> +    g_autofree char *drivername = NULL;
> +
> +    if (access(configfile, R_OK) == 0) {
> +
> +        conf = virConfReadFile(configfile, 0);
> +        if (!conf)
> +            return NULL;
> +
> +        if (virConfGetValueString(conf, "driver", &drivername) < 0)
> +            return NULL;
> +
> +        if (drivername) {
> +            VIR_DEBUG("nwfilter driver setting requested from config file %s: '%s'",
> +                      configfile, drivername);
> +        }
> +    }
> +
> +    if (!drivername) {
> +        drivername = g_strdup(NWFILTER_DEFAULT_DRIVER);
> +    }

Rather than harcoding this, we should try to auto-detect the right
option, and we should honour the existing 'firewall_backend_priority'
meson option that is used for the network driver.

Take a look at src/network/bridge_driver_conf.c which can be used
as a template for the nwfilter driver - worth putting it into
separate nwfilter_driver_conf.{h,c} files to match the common
pattern we use in other drivers.

> +
> +
> +    return g_steal_pointer(&drivername);
> +}
> +
> +
>  /**
>   * nwfilterStateInitialize:
>   *
> @@ -217,6 +249,8 @@ nwfilterStateInitialize(bool privileged,
>  {
>      VIR_LOCK_GUARD lock = virLockGuardLock(&driverMutex);
>      GDBusConnection *sysbus = NULL;
> +    g_autofree char *configfile = NULL;
> +    char *gentechdrivername = NULL;
>  
>      if (root != NULL) {
>          virReportError(VIR_ERR_INVALID_ARG, "%s",
> @@ -266,7 +300,14 @@ nwfilterStateInitialize(bool privileged,
>      if (virNWFilterDHCPSnoopInit() < 0)
>          goto error;
>  
> -    if (virNWFilterTechDriversInit(privileged) < 0)
> +    configfile = g_strdup(SYSCONFDIR "/libvirt/nwfilter.conf");
> +
> +    /* get chosen driver from config file */
> +    gentechdrivername = virNWFilterLoadGentechDriverFromConfig(configfile);
> +    if (gentechdrivername == NULL)
> +        goto error;
> +
> +    if (virNWFilterTechDriversInit(privileged, gentechdrivername) < 0)
>          goto error;
>  
>      if (virNWFilterConfLayerInit(virNWFilterTriggerRebuildImpl, driver) < 0)
> diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c
> index 1465734a54..adb96acca6 100644
> --- a/src/nwfilter/nwfilter_gentech_driver.c
> +++ b/src/nwfilter/nwfilter_gentech_driver.c
> @@ -32,6 +32,7 @@
>  #include "nwfilter_dhcpsnoop.h"
>  #include "nwfilter_ipaddrmap.h"
>  #include "nwfilter_learnipaddr.h"
> +#include "nwfilter_nftables_driver.h"
>  #include "virnetdev.h"
>  
>  #define VIR_FROM_THIS VIR_FROM_NWFILTER
> @@ -48,18 +49,20 @@ static int _virNWFilterTeardownFilter(const char *ifname);
>  
>  static virNWFilterTechDriver *filter_tech_drivers[] = {
>      &ebiptables_driver,
> -    NULL
> +    &nftables_driver,
>  };
>  
> -int virNWFilterTechDriversInit(bool privileged)
> +int virNWFilterTechDriversInit(bool privileged, const char *drivername)
>  {
>      size_t i = 0;
> -    VIR_DEBUG("Initializing NWFilter technology drivers");
> -    while (filter_tech_drivers[i]) {
> -        if (!(filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED))
> +    VIR_DEBUG("Initializing NWFilter technology drivers, chosen %s", drivername);
> +
> +    for (i = 0; i < G_N_ELEMENTS(filter_tech_drivers); i++) {
> +        if (!(filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED)
> +            && STREQ(filter_tech_drivers[i]->name, drivername))
>              filter_tech_drivers[i]->init(privileged);
> -        i++;
>      }
> +
>      return 0;
>  }
>  
> @@ -67,25 +70,20 @@ int virNWFilterTechDriversInit(bool privileged)
>  void virNWFilterTechDriversShutdown(void)
>  {
>      size_t i = 0;
> -    while (filter_tech_drivers[i]) {
> +    for (i = 0; i < G_N_ELEMENTS(filter_tech_drivers); i++) {
>          if ((filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED))
>              filter_tech_drivers[i]->shutdown();
> -        i++;
>      }
>  }
>  
>  
>  static virNWFilterTechDriver *
> -virNWFilterTechDriverForName(const char *name)
> +virNWFilterInitializedTechDriver(void)
>  {
>      size_t i = 0;
> -    while (filter_tech_drivers[i]) {
> -        if (STREQ(filter_tech_drivers[i]->name, name)) {
> -            if ((filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED) == 0)
> -                break;
> +    for (i = 0; i < G_N_ELEMENTS(filter_tech_drivers); i++) {
> +        if ((filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED))
>              return filter_tech_drivers[i];
> -        }
> -        i++;
>      }
>      return NULL;
>  }
> @@ -617,7 +615,6 @@ virNWFilterInstantiateFilterUpdate(virNWFilterDriverState *driver,
>                                     bool *foundNewFilter)
>  {
>      int rc = -1;
> -    const char *drvname = EBIPTABLES_DRIVER_ID;
>      virNWFilterTechDriver *techdriver;
>      virNWFilterObj *obj;
>      virNWFilterDef *filter;
> @@ -625,12 +622,11 @@ virNWFilterInstantiateFilterUpdate(virNWFilterDriverState *driver,
>      char vmmacaddr[VIR_MAC_STRING_BUFLEN] = {0};
>      virNWFilterVarValue *ipaddr;
>  
> -    techdriver = virNWFilterTechDriverForName(drvname);
> +    techdriver = virNWFilterInitializedTechDriver();
>  
>      if (!techdriver) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR,
> -                       _("Could not get access to ACL tech driver '%1$s'"),
> -                       drvname);
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("Could not get access to ACL tech driver"));
>          return -1;
>      }
>  
> @@ -768,15 +764,13 @@ virNWFilterUpdateInstantiateFilter(virNWFilterDriverState *driver,
>  static int
>  virNWFilterRollbackUpdateFilter(virNWFilterBindingDef *binding)
>  {
> -    const char *drvname = EBIPTABLES_DRIVER_ID;
>      int ifindex;
>      virNWFilterTechDriver *techdriver;
>  
> -    techdriver = virNWFilterTechDriverForName(drvname);
> +    techdriver = virNWFilterInitializedTechDriver();
>      if (!techdriver) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR,
> -                       _("Could not get access to ACL tech driver '%1$s'"),
> -                       drvname);
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("Could not get access to ACL tech driver"));
>          return -1;
>      }
>  
> @@ -793,15 +787,13 @@ virNWFilterRollbackUpdateFilter(virNWFilterBindingDef *binding)
>  static int
>  virNWFilterTearOldFilter(virNWFilterBindingDef *binding)
>  {
> -    const char *drvname = EBIPTABLES_DRIVER_ID;
>      int ifindex;
>      virNWFilterTechDriver *techdriver;
>  
> -    techdriver = virNWFilterTechDriverForName(drvname);
> +    techdriver = virNWFilterInitializedTechDriver();
>      if (!techdriver) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR,
> -                       _("Could not get access to ACL tech driver '%1$s'"),
> -                       drvname);
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("Could not get access to ACL tech driver"));
>          return -1;
>      }
>  
> @@ -818,14 +810,12 @@ virNWFilterTearOldFilter(virNWFilterBindingDef *binding)
>  static int
>  _virNWFilterTeardownFilter(const char *ifname)
>  {
> -    const char *drvname = EBIPTABLES_DRIVER_ID;
>      virNWFilterTechDriver *techdriver;
> -    techdriver = virNWFilterTechDriverForName(drvname);
> +    techdriver = virNWFilterInitializedTechDriver();
>  
>      if (!techdriver) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR,
> -                       _("Could not get access to ACL tech driver '%1$s'"),
> -                       drvname);
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("Could not get access to ACL tech driver"));
>          return -1;
>      }
>  
> diff --git a/src/nwfilter/nwfilter_gentech_driver.h b/src/nwfilter/nwfilter_gentech_driver.h
> index 946d5d3d56..8f6f4d164a 100644
> --- a/src/nwfilter/nwfilter_gentech_driver.h
> +++ b/src/nwfilter/nwfilter_gentech_driver.h
> @@ -25,7 +25,9 @@
>  #include "virnwfilterobj.h"
>  #include "virnwfilterbindingdef.h"
>  
> -int virNWFilterTechDriversInit(bool privileged);
> +#define NWFILTER_DEFAULT_DRIVER "ebiptables"
> +
> +int virNWFilterTechDriversInit(bool privileged, const char *drivername);
>  void virNWFilterTechDriversShutdown(void);
>  
>  enum instCase {
> -- 
> 2.43.0
> 

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|