nwfilter: add used firewall backend to nwfilterbinding

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 <dionbosschieter@gmail.com>
This commit is contained in:
Dion Bosschieter authored and Daniel P. Berrangé committed 2026-09-03 14:36:46 +01:00
1 parent eb65962fb6
commit 78b183d578
8 files changed
+100 -17

No files matched your search

+7
View File
@@ -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>
+15 -2
View File
@@ -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");
+1
View File
@@ -36,6 +36,7 @@ struct _virNWFilterBindingDef {
virMacAddr mac;
char *filter;
GHashTable *filterparams;
char *backend;
};
+1
View File
@@ -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;
+64 -15
View File
@@ -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);
}
@@ -8,4 +8,5 @@
<filterref filter='clean-traffic'>
<parameter name='MAC' value='52:54:00:7b:35:93'/>
</filterref>
<backend name='iptables'/>
</filterbinding>
@@ -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>
+1
View File
@@ -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;