Adds support for the new API. While starting a qemu link state
cannot be set with an command line argument and therefore is done
by entering monitor.
---
src/qemu/qemu_driver.c | 228 +++++++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_process.c | 37 ++++++++
2 files changed, 265 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 19e749f..a6a76be 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6887,6 +6887,232 @@ qemudDomainInterfaceStats (virDomainPtr dom,
#endif
static int
+qemudDomainInterfaceLinkGetState (virDomainPtr dom,
+ const char *path,
+ unsigned int flags)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int i;
+ int ret = -1;
+ unsigned char mac[VIR_MAC_BUFLEN];
+ virDomainDefPtr def = NULL;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
+ VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+ qemuDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ qemuDriverUnlock(driver);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ qemuReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"),
uuidstr);
+ goto cleanup;
+ }
+
+ if (virParseMacAddr(path, mac) < 0) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("Couldn't parse MAC address: %s"), path);
+ goto cleanup;
+ }
+
+ if (virDomainObjIsActive(vm)) {
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ if (!(def = virDomainObjGetPersistentDef(driver->caps, vm))) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("Couldn't get persistent domain
configuration"));
+ goto cleanup;
+ }
+ } else {
+ def = vm->def;
+ }
+ } else {
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ goto cleanup;
+ }
+ if (!(def = virDomainObjGetPersistentDef(driver->caps, vm))) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("Couldn't get persistent domain
configuration"));
+ goto cleanup;
+ }
+ }
+
+ /* Check the path is one of the domain's network interfaces. */
+ /* Qemu does not support reading the link state, report saved state */
+ for (i = 0 ; i < def->nnets ; i++) {
+ if (memcmp(def->nets[i]->mac, mac, VIR_MAC_BUFLEN) == 0) {
+ ret = def->nets[i]->linkstate;
+ break;
+ }
+ }
+
+ if (ret < 0)
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("invalid path, '%s' is not a known
interface"), path);
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+
+}
+
+static int
+qemudDomainInterfaceLinkSetState (virDomainPtr dom,
+ const char *path,
+ unsigned int state,
+ unsigned int flags)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ qemuDomainObjPrivatePtr priv = NULL;
+ virDomainObjPtr vm;
+ virDomainDefPtr def = NULL;
+ virDomainDefPtr persistentDef = NULL;
+
+ bool isActive;
+ int i;
+ int ret = -1;
+ bool found = false;
+ unsigned char mac[VIR_MAC_BUFLEN];
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
+ VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+ qemuDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ qemuDriverUnlock(driver);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ qemuReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"),
uuidstr);
+ goto cleanup;
+ }
+
+ priv = vm->privateData;
+
+ if (virParseMacAddr(path, mac) < 0) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("Couldn't parse MAC address: %s"), path);
+ goto cleanup;
+ }
+
+ if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+ goto cleanup;
+
+ isActive = virDomainObjIsActive(vm);
+
+ if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
+ if (isActive)
+ flags |= VIR_DOMAIN_AFFECT_LIVE;
+ else
+ flags |= VIR_DOMAIN_AFFECT_CONFIG;
+ }
+
+ if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ _("domain is not running"));
+ goto endjob;
+ }
+
+ if (!vm->persistent && (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ _("cannot change persistent config of a transient
domain"));
+ goto endjob;
+ }
+
+ def = vm->def;
+ if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm))) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("Couldn't get persistent domain
configuration"));
+ goto endjob;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ for (i = 0; i < persistentDef->nnets; i++) {
+ if (memcmp(persistentDef->nets[i]->mac, mac, VIR_MAC_BUFLEN) == 0) {
+ found = true;
+ persistentDef->nets[i]->linkstate = state;
+ break;
+ }
+ }
+
+ if (!found) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("Interface %s not found"), path);
+ goto endjob;
+ }
+ }
+
+ found = false;
+
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ for (i = 0; i < def->nnets; i++) {
+ if (memcmp(def->nets[i]->mac, mac, VIR_MAC_BUFLEN) == 0) {
+ if (def->nets[i]->info.alias) {
+
+ if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_LINK_SET)) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("This qemu doesn't support setting
link state"));
+ goto endjob;
+ }
+
+ qemuDomainObjEnterMonitor(driver, vm);
+ ret = qemuMonitorSetLink(priv->mon,
def->nets[i]->info.alias, state);
+ qemuDomainObjExitMonitor(driver, vm);
+ } else {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("Device alias not found. (QEMU probably
doesn't support device naming)"));
+ goto endjob;
+ }
+
+ found = true;
+ if (ret == 0)
+ def->nets[i]->linkstate = state;
+
+ break;
+ }
+ }
+
+ if (!found) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("Interface %s not found"), path);
+ goto endjob;
+ }
+
+ if (ret < 0)
+ goto endjob;
+ }
+
+ /* one or both configurations successfuly altered */
+
+ if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
+ virDomainSaveConfig(driver->configDir, persistentDef) < 0)
+ goto endjob;
+
+ /* everything went well */
+ ret = 0;
+
+endjob:
+ if (qemuDomainObjEndJob(driver, vm) == 0)
+ vm = NULL;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+
+ return ret;
+}
+
+static int
qemudDomainMemoryStats (virDomainPtr dom,
struct _virDomainMemoryStat *stats,
unsigned int nr_stats,
@@ -9473,6 +9699,8 @@ static virDriver qemuDriver = {
.domainMigratePerform = qemudDomainMigratePerform, /* 0.5.0 */
.domainBlockStats = qemudDomainBlockStats, /* 0.4.1 */
.domainInterfaceStats = qemudDomainInterfaceStats, /* 0.4.1 */
+ .domainInterfaceLinkGetState = qemudDomainInterfaceLinkGetState, /* 0.9.5 */
+ .domainInterfaceLinkSetState = qemudDomainInterfaceLinkSetState, /* 0.9.5 */
.domainMemoryStats = qemudDomainMemoryStats, /* 0.7.5 */
.domainBlockPeek = qemudDomainBlockPeek, /* 0.4.4 */
.domainMemoryPeek = qemudDomainMemoryPeek, /* 0.4.4 */
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 30c8b28..c0bf30b 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1441,6 +1441,29 @@ qemuProcessInitCpuAffinity(virDomainObjPtr vm)
return 0;
}
+/* set link states to down on interfaces at qemu start */
+static int
+qemuProcessSetLinkStates(virDomainObjPtr vm)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ virDomainDefPtr def = vm->def;
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < def->nnets; i++) {
+ if (def->nets[i]->linkstate == VIR_LINK_STATE_DOWN) {
+ ret = qemuMonitorSetLink(priv->mon,
+ def->nets[i]->info.alias,
+ VIR_LINK_STATE_DOWN);
+
+ if (ret != 0)
+ break;
+ }
+ }
+
+ return ret;
+}
+
/* Set CPU affinites for vcpus if vcpupin xml provided. */
static int
qemuProcessSetVcpuAffinites(virConnectPtr conn,
@@ -2980,6 +3003,20 @@ int qemuProcessStart(virConnectPtr conn,
goto cleanup;
}
+ /* set default link states */
+ /* qemu doesn't support setting this on the command line, so
+ * enter the monitor */
+ if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_LINK_SET)) {
+ VIR_DEBUG("Setting network link states");
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ if (qemuProcessSetLinkStates(vm) < 0) {
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+ goto cleanup;
+ }
+
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+ }
+
/* Technically, qemuProcessStart can be called from inside
* QEMU_ASYNC_JOB_MIGRATION_IN, but we are okay treating this like
* a sync job since no other job can call into the domain until
--
1.7.6