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 @@
<element name="filterref">
<ref name="filterref-node-attributes"/>
</element>
+
+ <optional>
+ <element name="backend">
+ <attribute name="name"/>
+ <empty/>
+ </element>
+ </optional>
</interleave>
</element>
</define>
diff --git a/src/conf/virnwfilterbindingdef.c b/src/conf/
virnwfilterbindingdef.c
index fe45c84347..a91a54032c 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
@@ -143,8 +142,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 +220,7 @@ virNWFilterBindingDefFormatBuf(virBuffer *buf,
if (virNWFilterFormatParamAttributes(buf, def->filterparams, def-
>filter) < 0)
return -1;
+ virBufferAsprintf(buf, "<backend name='%s'/>", def->backend);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</filterbinding>\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);
}