Updates nwfilterbinding.rng to support the 'backend' XML element. Defaults the def->backend field to the existing ebiptables firewall backend inside nwfilter_gentech_driver.c. This new element allows us to check the definition's firewall backend against the current firewall backend and remove old existing rules via the previous firewall backend. This switch between firewall backends happens inside virNWFilterSwitchTechDriver.
Updated virnwfilterbindingxml2xmltest to test parsing and formatting of the new nwfilterbinding backend element. Signed-off-by: Dion Bosschieter <[email protected]> --- src/conf/schemas/nwfilterbinding.rng | 7 ++ src/conf/virnwfilterbindingdef.c | 17 +++- src/conf/virnwfilterbindingdef.h | 1 + src/nwfilter/nwfilter_driver.c | 1 + src/nwfilter/nwfilter_gentech_driver.c | 79 +++++++++++++++---- .../filter-vars.xml | 1 + .../simple-backend.xml | 10 +++ tests/virnwfilterbindingxml2xmltest.c | 1 + 8 files changed, 100 insertions(+), 17 deletions(-) create mode 100644 tests/virnwfilterbindingxml2xmldata/simple-backend.xml 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..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, "<backend name='%s'/>\n", 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); } 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 @@ <filterref filter='clean-traffic'> <parameter name='MAC' value='52:54:00:7b:35:93'/> </filterref> + <backend name='iptables'/> </filterbinding> 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 @@ +<filterbinding> + <owner> + <name>memtest</name> + <uuid>d54df46f-1ab5-4a22-8618-4560ef5fac2c</uuid> + </owner> + <portdev name='vnet0'/> + <mac address='52:54:00:7b:35:93'/> + <filterref filter='clean-traffic'/> + <backend name='iptables'/> +</filterbinding> 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; -- 2.43.0
