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;