diff --git a/src/conf/nwfilter_params.c b/src/conf/nwfilter_params.c index 3ac130390b..7254519a2c 100644 --- a/src/conf/nwfilter_params.c +++ b/src/conf/nwfilter_params.c @@ -795,6 +795,27 @@ err_exit: return -1; } +/* The general purpose function virNWFilterVarValueEqual returns a + * bool, but the comparison callback for virHashEqual (called below) + * needs to return an int of 0 for == and non-0 for != + */ +static int +virNWFilterVarValueCompare(const void *a, const void *b) +{ + return virNWFilterVarValueEqual((const virNWFilterVarValuePtr) a, + (const virNWFilterVarValuePtr) b) ? 0 : 1; +} + +bool +virNWFilterHashTableEqual(virNWFilterHashTablePtr a, + virNWFilterHashTablePtr b) +{ + if (!(a || b)) + return true; + if (!(a && b)) + return false; + return virHashEqual(a->hashTable, b->hashTable, virNWFilterVarValueCompare); +} static bool isValidVarName(const char *var) diff --git a/src/conf/nwfilter_params.h b/src/conf/nwfilter_params.h index 96d3033ecb..6c3ce54352 100644 --- a/src/conf/nwfilter_params.h +++ b/src/conf/nwfilter_params.h @@ -1,7 +1,7 @@ /* * nwfilter_params.h: parsing and data maintenance of filter parameters * - * Copyright (C) 2011 Red Hat, Inc. + * Copyright (C) 2011-2012 Red Hat, Inc. * Copyright (C) 2010 IBM Corporation * * This library is free software; you can redistribute it and/or @@ -87,6 +87,8 @@ void *virNWFilterHashTableRemoveEntry(virNWFilterHashTablePtr table, const char *name); int virNWFilterHashTablePutAll(virNWFilterHashTablePtr src, virNWFilterHashTablePtr dest); +bool virNWFilterHashTableEqual(virNWFilterHashTablePtr a, + virNWFilterHashTablePtr b); # define VALID_VARNAME \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 51c76a549b..41e262900c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -959,6 +959,7 @@ virNWFilterIPAddrMapShutdown; # nwfilter_params.h virNWFilterHashTableCreate; +virNWFilterHashTableEqual; virNWFilterHashTableFree; virNWFilterHashTablePut; virNWFilterHashTablePutAll; diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 2d4a822416..fbd60de5bb 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1330,6 +1330,43 @@ cleanup: return ret; } +static int +qemuDomainChangeNetFilter(virConnectPtr conn, + virDomainObjPtr vm, + virDomainNetDefPtr olddev, + virDomainNetDefPtr newdev) +{ + /* make sure this type of device supports filters. */ + switch (virDomainNetGetActualType(newdev)) { + case VIR_DOMAIN_NET_TYPE_ETHERNET: + case VIR_DOMAIN_NET_TYPE_BRIDGE: + case VIR_DOMAIN_NET_TYPE_NETWORK: + break; + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("filters not supported on interfaces of type %s"), + virDomainNetTypeToString(virDomainNetGetActualType(newdev))); + return -1; + } + + virDomainConfNWFilterTeardown(olddev); + + if (virDomainConfNWFilterInstantiate(conn, vm->def->uuid, newdev) < 0) { + virErrorPtr errobj; + + virReportError(VIR_ERR_OPERATION_FAILED, + _("failed to add new filter rules to '%s' " + "- attempting to restore old rules"), + olddev->ifname); + errobj = virSaveLastError(); + ignore_value(virDomainConfNWFilterInstantiate(conn, vm->def->uuid, olddev)); + virSetError(errobj); + virFreeError(errobj); + return -1; + } + return 0; +} + int qemuDomainChangeNetLinkState(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainNetDefPtr dev, @@ -1373,6 +1410,7 @@ qemuDomainChangeNet(virQEMUDriverPtr driver, int oldType, newType; bool needReconnect = false; bool needBridgeChange = false; + bool needFilterChange = false; bool needLinkStateChange = false; bool needReplaceDevDef = false; int ret = -1; @@ -1506,8 +1544,10 @@ qemuDomainChangeNet(virQEMUDriverPtr driver, } /* (end of device info checks) */ - if (STRNEQ_NULLABLE(olddev->filter, newdev->filter)) - needReconnect = true; + if (STRNEQ_NULLABLE(olddev->filter, newdev->filter) || + !virNWFilterHashTableEqual(olddev->filterparams, newdev->filterparams)) { + needFilterChange = true; + } /* bandwidth can be modified, and will be checked later */ /* vlan can be modified, and will be checked later */ @@ -1665,7 +1705,16 @@ qemuDomainChangeNet(virQEMUDriverPtr driver, goto cleanup; /* we successfully switched to the new bridge, and we've * determined that the rest of newdev is equivalent to olddev, - * so move newdev into place, so that the */ + * so move newdev into place */ + needReplaceDevDef = true; + } + + if (needFilterChange) { + if (qemuDomainChangeNetFilter(dom->conn, vm, olddev, newdev) < 0) + goto cleanup; + /* we successfully switched to the new filter, and we've + * determined that the rest of newdev is equivalent to olddev, + * so move newdev into place */ needReplaceDevDef = true; }