diff --git a/src/conf/schemas/nwfilterbinding.rng b/src/conf/schemas/nwfilterbinding.rng
index c91312b09d..16ed745e0f 100644
--- a/src/conf/schemas/nwfilterbinding.rng
+++ b/src/conf/schemas/nwfilterbinding.rng
@@ -44,6 +44,13 @@
+
+
+
+
+
+
+
diff --git a/src/conf/virnwfilterbindingdef.c b/src/conf/virnwfilterbindingdef.c
index fe45c84347..ddd8a7e0a9 100644
--- a/src/conf/virnwfilterbindingdef.c
+++ b/src/conf/virnwfilterbindingdef.c
@@ -26,7 +26,6 @@
#include "virnwfilterbindingdef.h"
#include "viruuid.h"
-
#define VIR_FROM_THIS VIR_FROM_NWFILTER
void
@@ -40,6 +39,7 @@ virNWFilterBindingDefFree(virNWFilterBindingDef *def)
g_free(def->linkdevname);
g_free(def->filter);
g_clear_pointer(&def->filterparams, g_hash_table_unref);
+ g_free(def->backend);
g_free(def);
}
@@ -67,6 +67,8 @@ virNWFilterBindingDefCopy(virNWFilterBindingDef *src)
if (virNWFilterHashTablePutAll(src->filterparams, ret->filterparams) < 0)
return NULL;
+ ret->backend = g_strdup(src->backend);
+
return g_steal_pointer(&ret);
}
@@ -143,8 +145,18 @@ virNWFilterBindingDefParseXML(xmlXPathContextPtr ctxt)
node = virXPathNode("./filterref", ctxt);
if (node &&
- !(ret->filterparams = virNWFilterParseParamAttributes(node)))
+ !(ret->filterparams = virNWFilterParseParamAttributes(node))) {
goto cleanup;
+ }
+
+ if (virXPathNode("./backend", ctxt)) {
+ ret->backend = virXPathString("string(./backend/@name)", ctxt);
+ if (!ret->backend) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("filter binding has no firewall backend name"));
+ goto cleanup;
+ }
+ }
return ret;
@@ -211,6 +223,7 @@ virNWFilterBindingDefFormatBuf(virBuffer *buf,
if (virNWFilterFormatParamAttributes(buf, def->filterparams, def->filter) < 0)
return -1;
+ virBufferEscapeString(buf, "\n", def->backend);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "\n");
diff --git a/src/conf/virnwfilterbindingdef.h b/src/conf/virnwfilterbindingdef.h
index 272ad686a0..16465df56d 100644
--- a/src/conf/virnwfilterbindingdef.h
+++ b/src/conf/virnwfilterbindingdef.h
@@ -36,6 +36,7 @@ struct _virNWFilterBindingDef {
virMacAddr mac;
char *filter;
GHashTable *filterparams;
+ char *backend;
};
diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c
index 66f5fa7c18..9b981ddcbf 100644
--- a/src/nwfilter/nwfilter_driver.c
+++ b/src/nwfilter/nwfilter_driver.c
@@ -725,6 +725,7 @@ nwfilterBindingCreateXML(virConnectPtr conn,
def = virNWFilterBindingDefParse(xml, NULL, flags);
if (!def)
return NULL;
+ def->backend = g_strdup(virFirewallBackendTypeToString(cfg->firewallBackend));
if (virNWFilterBindingCreateXMLEnsureACL(conn, def) < 0)
goto cleanup;
diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c
index 29f80a8677..9dc99e848b 100644
--- a/src/nwfilter/nwfilter_gentech_driver.c
+++ b/src/nwfilter/nwfilter_gentech_driver.c
@@ -70,6 +70,20 @@ int virNWFilterTechDriversInit(bool privileged, virNWFilterDriverConfig *config)
}
+static virNWFilterTechDriver *
+virNWFilterTechDriversByName(const char *firewallBackend)
+{
+ size_t i = 0;
+
+ for (i = 0; i < G_N_ELEMENTS(filter_tech_drivers); i++) {
+ if (STREQ(filter_tech_drivers[i]->name, firewallBackend))
+ return filter_tech_drivers[i];
+ }
+
+ return 0;
+}
+
+
void virNWFilterTechDriversShutdown(void)
{
size_t i = 0;
@@ -786,6 +800,33 @@ virNWFilterRollbackUpdateFilter(virNWFilterBindingDef *binding)
return techdriver->tearNewRules(binding->portdevname);
}
+static int
+virNWFilterSwitchTechDriver(virNWFilterDriverState *driver,
+ virNWFilterBindingObj *binding,
+ virNWFilterBindingDef *def)
+{
+ int ret = 0;
+ virNWFilterTechDriver *oldTechDriver = virNWFilterTechDriversByName(def->backend);
+ g_autoptr(virNWFilterDriverConfig) cfg = virNWFilterDriverGetConfig(driver);
+
+ VIR_DEBUG("Detected change in nwfilter firewall backend '%1$s' -> '%2$s', cleaning up '%1$s'",
+ def->backend,
+ virFirewallBackendTypeToString(driver->config->firewallBackend));
+
+ // first we'll apply the rules with the new tech driver
+ if ((ret = virNWFilterInstantiateFilter(driver, def)) < 0)
+ return ret;
+
+ // then we'll cleanup the rules from the old driver
+ if ((ret = oldTechDriver->allTeardown(def->portdevname)) < 0)
+ return ret;
+
+ // update binding backend
+ def->backend = g_strdup(virFirewallBackendTypeToString(driver->config->firewallBackend));
+
+ // save changed binding xml file
+ return virNWFilterBindingObjSave(binding, cfg->bindingDir);
+}
static int
virNWFilterTearOldFilter(virNWFilterBindingDef *binding)
@@ -854,40 +895,49 @@ enum {
static int
virNWFilterBuildOne(virNWFilterDriverState *driver,
- virNWFilterBindingDef *binding,
+ virNWFilterBindingObj *binding,
GHashTable *skipInterfaces,
int step)
{
bool skipIface;
int ret = 0;
- VIR_DEBUG("Building filter for portdev=%s step=%d", binding->portdevname, step);
+ virNWFilterBindingDef *def = virNWFilterBindingObjGetDef(binding);
+
+ VIR_DEBUG("Building filter for portdev=%s step=%d", def->portdevname, step);
switch (step) {
case STEP_APPLY_NEW:
ret = virNWFilterUpdateInstantiateFilter(driver,
- binding,
+ def,
&skipIface);
if (ret == 0 && skipIface) {
/* filter tree unchanged -- no update needed */
ret = virHashAddEntry(skipInterfaces,
- binding->portdevname,
+ def->portdevname,
(void *)~0);
}
break;
-
case STEP_ROLLBACK:
- if (!virHashLookup(skipInterfaces, binding->portdevname))
- ret = virNWFilterRollbackUpdateFilter(binding);
+ if (!virHashLookup(skipInterfaces, def->portdevname))
+ ret = virNWFilterRollbackUpdateFilter(def);
break;
-
case STEP_SWITCH:
- if (!virHashLookup(skipInterfaces, binding->portdevname))
- ret = virNWFilterTearOldFilter(binding);
+ if (!virHashLookup(skipInterfaces, def->portdevname))
+ ret = virNWFilterTearOldFilter(def);
break;
-
case STEP_APPLY_CURRENT:
- ret = virNWFilterInstantiateFilter(driver,
- binding);
+ // prev is always ebiptables if unset
+ if (def->backend == NULL)
+ def->backend = g_strdup(ebiptables_driver.name);
+
+ // detect change in backend
+ if (STRNEQ(def->backend,
+ virFirewallBackendTypeToString(driver->config->firewallBackend))) {
+ ret = virNWFilterSwitchTechDriver(driver, binding, def);
+ } else {
+ ret = virNWFilterInstantiateFilter(driver, def);
+ }
+
break;
}
@@ -905,9 +955,8 @@ static int
virNWFilterBuildIter(virNWFilterBindingObj *binding, void *opaque)
{
struct virNWFilterBuildData *data = opaque;
- virNWFilterBindingDef *def = virNWFilterBindingObjGetDef(binding);
- return virNWFilterBuildOne(data->driver, def,
+ return virNWFilterBuildOne(data->driver, binding,
data->skipInterfaces, data->step);
}
diff --git a/tests/virnwfilterbindingxml2xmldata/filter-vars.xml b/tests/virnwfilterbindingxml2xmldata/filter-vars.xml
index dcff9640ce..5d4cb2bebf 100644
--- a/tests/virnwfilterbindingxml2xmldata/filter-vars.xml
+++ b/tests/virnwfilterbindingxml2xmldata/filter-vars.xml
@@ -8,4 +8,5 @@
+
diff --git a/tests/virnwfilterbindingxml2xmldata/simple-backend.xml b/tests/virnwfilterbindingxml2xmldata/simple-backend.xml
new file mode 100644
index 0000000000..7b91448fbb
--- /dev/null
+++ b/tests/virnwfilterbindingxml2xmldata/simple-backend.xml
@@ -0,0 +1,10 @@
+
+
+ memtest
+ d54df46f-1ab5-4a22-8618-4560ef5fac2c
+
+
+
+
+
+
diff --git a/tests/virnwfilterbindingxml2xmltest.c b/tests/virnwfilterbindingxml2xmltest.c
index bde21968fe..907755bd56 100644
--- a/tests/virnwfilterbindingxml2xmltest.c
+++ b/tests/virnwfilterbindingxml2xmltest.c
@@ -92,6 +92,7 @@ mymain(void)
} while (0)
DO_TEST("simple");
+ DO_TEST("simple-backend");
DO_TEST("filter-vars");
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;