[libvirt] [RFC] New API to retrieve node CPU map
by Viktor Mihajlovski
Hi,
in order to use the APIs listed below it is necessary for a client to
know the maximum number of node CPUs which is passed via the maplen
argument.
virDomainGetEmulatorPinInfo
virDomainGetVcpuPinInfo
virDomainGetVcpus
virDomainPinEmulator
virDomainPinVcpu
virDomainPinVcpuFlags
The current approach uses virNodeGetInfo to determine the maximum CPU
number. This can lead to incorrect results if not all node CPUs are
online. The maximum CPU number should always be the number of CPUs
present on the host, regardless of their online/offline state.
The following example illustrates the issue:
Host has 3 logical CPUs, 1 socket, 3 cores, 1 thread.
Guest has 1 virtual CPU and is started while all 3 host CPUs are
online.
$ virsh vcpuinfo guest
VCPU: 0
CPU: 0
State: running
CPU time: 35.4s
CPU Affinity: yyy
$ echo 0 > /sys/devices/system/cpu/cpu1/online
$ virsh vcpuinfo guest
VCPU: 0
CPU: 0
State: running
CPU time: 35.5s
CPU Affinity: y-
The correct display for CPU affinity would have been y-y, as the guest
continues to use CPUs 0 and 2.
This is not a display problem only, because it is also not possible to
explicitly pin the virtual CPU to host CPUs 0 and 2, due to the
truncated CPU mask.
PROPOSAL:
To help solve the issue above I suggest two new public API functions:
int
virNodeGetCpuNum(virConnectPtr conn);
returning the number of present CPUs on the host or -1 upon failure
and
int
virNodeGetCpuMap(virConnectPtr conn, unsigned char * cpumap, int maplen);
returning the number of present CPUs or -1 on failure and storing a bit
map of real CPUs as described in virDomainPinVcpu in cpumap. The bits in
the bit map are set to 1 for online CPUs and set to 0 for offline CPUs.
Implementation is facilitated by the function nodeGetCPUmap in nodeinfo.c.
Clients can use virNodeGetCpuNum to properly determine the maximum
number of node CPUs and the online/offline information.
Thanks for your comments.
--
Mit freundlichen Grüßen/Kind Regards
Viktor Mihajlovski
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschäftsführung: Dirk Wittkopp
Sitz der Gesellschaft: Böblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294
11 years, 7 months
[libvirt] [PATCH v2 1/1][RESEND] Add NVRAM device
by Li Zhang
From: Li Zhang <zhlcindy(a)linux.vnet.ibm.com>
For pSeries guest in QEMU, NVRAM is one kind of spapr-vio device.
Users are allowed to specify spapr-vio devices'address.
But NVRAM is not supported in libvirt. So this patch is to
add NVRAM device to allow users to specify its address.
In QEMU, NVRAM device's address is specified by
"-global spapr-nvram.reg=xxxxx".
In libvirt, XML file is defined as the following:
<nvram>
<address type='spapr-vio' reg='0x3000'/>
</nvram>
Signed-off-by: Li Zhang <zhlcindy(a)linux.vnet.ibm.com>
---
* v2 -> v1:
Add NVRAM parameters parsing in qemuParseCommandLine.
src/conf/domain_conf.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 10 ++++++
src/qemu/qemu_command.c | 48 +++++++++++++++++++++++++++
src/qemu/qemu_command.h | 2 ++
4 files changed, 142 insertions(+), 1 deletion(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 10f361c..8c1e8ae 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -175,7 +175,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
"redirdev",
"smartcard",
"chr",
- "memballoon")
+ "memballoon",
+ "nvram")
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
"none",
@@ -1442,6 +1443,16 @@ void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def)
VIR_FREE(def);
}
+void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def)
+{
+ if (!def)
+ return;
+
+ virDomainDeviceInfoClear(&def->info);
+
+ VIR_FREE(def);
+}
+
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
{
if (!def)
@@ -1602,6 +1613,7 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_CHR:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
+ case VIR_DOMAIN_DEVICE_NVRAM:
case VIR_DOMAIN_DEVICE_LAST:
break;
}
@@ -1791,6 +1803,7 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainWatchdogDefFree(def->watchdog);
virDomainMemballoonDefFree(def->memballoon);
+ virDomainNVRAMDefFree(def->nvram);
for (i = 0; i < def->nseclabels; i++)
virSecurityLabelDefFree(def->seclabels[i]);
@@ -2342,6 +2355,12 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
if (cb(def, &device, &def->memballoon->info, opaque) < 0)
return -1;
}
+ if (def->nvram) {
+ device.type = VIR_DOMAIN_DEVICE_NVRAM;
+ device.data.nvram = def->nvram;
+ if (cb(def, &device, &def->nvram->info, opaque) < 0)
+ return -1;
+ }
device.type = VIR_DOMAIN_DEVICE_HUB;
for (i = 0; i < def->nhubs ; i++) {
device.data.hub = def->hubs[i];
@@ -7461,6 +7480,23 @@ error:
goto cleanup;
}
+static virDomainNVRAMDefPtr
+virDomainNVRAMDefParseXML(const xmlNodePtr node,
+ unsigned int flags)
+{
+ virDomainNVRAMDefPtr def;
+
+ if (VIR_ALLOC(def) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ if ( virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0 )
+ return NULL;
+
+ return def;
+}
+
static virSysinfoDefPtr
virSysinfoParseXML(const xmlNodePtr node,
xmlXPathContextPtr ctxt)
@@ -10572,6 +10608,32 @@ virDomainDefParseXML(virCapsPtr caps,
}
}
+ def->nvram = NULL;
+ if ((n = virXPathNodeSet("./devices/nvram", ctxt, &nodes)) < 0) {
+ goto error;
+ }
+
+ if (n > 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("only a single nvram device is supported"));
+ goto error;
+ }
+
+ if (n > 0) {
+ virDomainNVRAMDefPtr nvram =
+ virDomainNVRAMDefParseXML(nodes[0], flags);
+ if (!nvram)
+ goto error;
+ def->nvram = nvram;
+ VIR_FREE(nodes);
+ } else {
+ virDomainNVRAMDefPtr nvram;
+ if (VIR_ALLOC(nvram) < 0)
+ goto no_memory;
+ nvram->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
+ def->nvram = nvram;
+ }
+
/* analysis of the hub devices */
if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0) {
goto error;
@@ -13547,6 +13609,21 @@ virDomainMemballoonDefFormat(virBufferPtr buf,
}
static int
+virDomainNVRAMDefFormat(virBufferPtr buf,
+ virDomainNVRAMDefPtr def,
+ unsigned int flags)
+{
+ virBufferAsprintf(buf, " <nvram>\n");
+ if (virDomainDeviceInfoIsSet(&def->info, flags))
+ if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
+ return -1;
+
+ virBufferAddLit(buf, " </nvram>\n");
+
+ return 0;
+}
+
+static int
virDomainSysinfoDefFormat(virBufferPtr buf,
virSysinfoDefPtr def)
{
@@ -14787,6 +14864,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
if (def->memballoon)
virDomainMemballoonDefFormat(buf, def->memballoon, flags);
+ if (def->nvram)
+ virDomainNVRAMDefFormat(buf, def->nvram, flags);
+
virBufferAddLit(buf, " </devices>\n");
virBufferAdjustIndent(buf, 2);
@@ -16061,6 +16141,7 @@ virDomainDeviceDefCopy(virCapsPtr caps,
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_CHR:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
+ case VIR_DOMAIN_DEVICE_NVRAM:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Copying definition of '%d' type "
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 4ffa4aa..8e5f1d8 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -108,6 +108,9 @@ typedef virDomainChrDef *virDomainChrDefPtr;
typedef struct _virDomainMemballoonDef virDomainMemballoonDef;
typedef virDomainMemballoonDef *virDomainMemballoonDefPtr;
+typedef struct _virDomainNVRAMDef virDomainNVRAMDef;
+typedef virDomainNVRAMDef *virDomainNVRAMDefPtr;
+
typedef struct _virDomainSnapshotObj virDomainSnapshotObj;
typedef virDomainSnapshotObj *virDomainSnapshotObjPtr;
@@ -133,6 +136,7 @@ typedef enum {
VIR_DOMAIN_DEVICE_SMARTCARD,
VIR_DOMAIN_DEVICE_CHR,
VIR_DOMAIN_DEVICE_MEMBALLOON,
+ VIR_DOMAIN_DEVICE_NVRAM,
VIR_DOMAIN_DEVICE_LAST
} virDomainDeviceType;
@@ -158,6 +162,7 @@ struct _virDomainDeviceDef {
virDomainSmartcardDefPtr smartcard;
virDomainChrDefPtr chr;
virDomainMemballoonDefPtr memballoon;
+ virDomainNVRAMDefPtr nvram;
} data;
};
@@ -1418,6 +1423,9 @@ struct _virDomainMemballoonDef {
virDomainDeviceInfo info;
};
+struct _virDomainNVRAMDef {
+ virDomainDeviceInfo info;
+};
enum virDomainSmbiosMode {
VIR_DOMAIN_SMBIOS_NONE,
@@ -1849,6 +1857,7 @@ struct _virDomainDef {
/* Only 1 */
virDomainWatchdogDefPtr watchdog;
virDomainMemballoonDefPtr memballoon;
+ virDomainNVRAMDefPtr nvram;
virCPUDefPtr cpu;
virSysinfoDefPtr sysinfo;
virDomainRedirFilterDefPtr redirfilter;
@@ -1951,6 +1960,7 @@ int virDomainChrSourceDefCopy(virDomainChrSourceDefPtr src,
void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def);
void virDomainSoundDefFree(virDomainSoundDefPtr def);
void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def);
+void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def);
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def);
void virDomainVideoDefFree(virDomainVideoDefPtr def);
virDomainHostdevDefPtr virDomainHostdevDefAlloc(void);
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index dee493f..30694d6 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -941,6 +941,13 @@ int qemuDomainAssignSpaprVIOAddresses(virDomainDefPtr def,
goto cleanup;
}
+ if (def->os.arch == VIR_ARCH_PPC64 &&
+ STREQ(def->os.machine, "pseries"))
+ def->nvram->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO;
+ if (qemuAssignSpaprVIOAddress(def, &def->nvram->info,
+ 0x3000ul) < 0)
+ goto cleanup;
+
/* No other devices are currently supported on spapr-vio */
ret = 0;
@@ -3406,6 +3413,17 @@ error:
return NULL;
}
+char *
+qemuBuildNVRAMDevStr(virDomainNVRAMDefPtr dev)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ if (dev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO &&
+ dev->info.addr.spaprvio.has_reg)
+ virBufferAsprintf(&buf, "spapr-nvram.reg=0x%llx",
+ dev->info.addr.spaprvio.reg);
+
+ return virBufferContentAndReset(&buf);
+}
char *
qemuBuildUSBInputDevStr(virDomainInputDefPtr dev,
@@ -7006,6 +7024,19 @@ qemuBuildCommandLine(virConnectPtr conn,
}
}
+ if (def->nvram &&
+ def->os.arch == VIR_ARCH_PPC64 &&
+ STREQ(def->os.machine, "pseries")) {
+ char *optstr;
+ virCommandAddArg(cmd, "-global");
+ optstr = qemuBuildNVRAMDevStr(def->nvram);
+ if (!optstr)
+ goto error;
+ if (optstr)
+ virCommandAddArg(cmd, optstr);
+ VIR_FREE(optstr);
+ }
+
if (snapshot)
virCommandAddArgList(cmd, "-loadvm", snapshot->def->name, NULL);
@@ -9139,6 +9170,23 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr qemuCaps,
goto error;
}
+ } else if (STREQ(arg, "-global") &&
+ STRPREFIX(progargv[i + 1], "spapr-nvram.reg=")) {
+
+ WANT_VALUE();
+
+ if (VIR_ALLOC(def->nvram) < 0)
+ goto no_memory;
+
+ val += strlen("spapr-nvram.reg=");
+ if (virStrToLong_ull(val, NULL, 16,
+ &def->nvram->info.addr.spaprvio.reg) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("invalid value for spapr-nvram.reg :"
+ "'%s'"), val);
+ goto error;
+ }
+
} else if (STREQ(arg, "-S")) {
/* ignore, always added by libvirt */
} else {
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index e4db000..7a0fe17 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -118,6 +118,8 @@ char * qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev,
char * qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev,
virQEMUCapsPtr qemuCaps);
+char * qemuBuildNVRAMDevStr(virDomainNVRAMDefPtr dev);
+
char * qemuBuildUSBInputDevStr(virDomainInputDefPtr dev,
virQEMUCapsPtr qemuCaps);
--
1.7.10.1
11 years, 7 months
[libvirt] [PATCH 0/5] qemu: invoke qemu-bridge-helper from libvirtd
by Paolo Bonzini
The <interface type='bridge'> is working mostly because of a bad design
decision in Linux. Ideally, QEMU would run with an empty capability
bounding set and would not be able to do any privileged operation
(not even by running a helper program). This is not the case because
dropping capabilities from the bounding set requires a capability of its
own, CAP_SETPCAP; thus QEMU does *not* run with an empty bounding set if
invoked via qemu:///session.
This series lets libvirtd invoke the privileged helper program on its own,
which is a cleaner design that would work even if the above Linux bug
was not there. Also, this adds a <target dev='tap0'/> element to the
XML of an active domain using <interface type='bridge'>.
libvirt now needs to know the path to the helper (patch
3), and must not set permitted/effective capabilities on children when
running unprivileged (patches 1/2). Apart from this, the recvfd and
virCommand APIs make the task almost trivial.
Paolo Bonzini (5):
util: simplify virSetUIDGIDWithCaps
util: allow using virCommandAllowCap with setuid helpers
qemu_conf: add new configuration key bridge_helper
virnetdevtap: add virNetDevTapGetName
qemu: launch bridge helper from libvirtd
src/libvirt_private.syms | 1 +
src/qemu/libvirtd_qemu.aug | 1 +
src/qemu/qemu.conf | 8 +++
src/qemu/qemu_command.c | 133 +++++++++++++++++++++++++++----------
src/qemu/qemu_command.h | 1 -
src/qemu/qemu_conf.c | 3 +
src/qemu/qemu_conf.h | 1 +
src/qemu/qemu_hotplug.c | 25 +++----
src/qemu/test_libvirtd_qemu.aug.in | 1 +
src/util/virnetdevtap.c | 33 +++++++++
src/util/virnetdevtap.h | 3 +
src/util/virutil.c | 36 +++++++---
12 files changed, 183 insertions(+), 63 deletions(-)
--
1.8.1.4
11 years, 8 months
[libvirt] [PATCHv2] Configure native vlan modes on Open vSwitch ports
by james robson
This patch adds functionality to allow libvirt to configure the
'native-tagged' and 'native-untagged' modes on openvswitch networks.
v2 changes:
Fix problems reported by Eric Blake
---
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index ffcc33e..a5054cc 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -3209,6 +3209,12 @@ qemu-kvm -net nic,model=? /dev/null
<parameters
interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/>
</virtualport>
</interface>
+ <interface type='bridge'>
+ <b><vlan trunk='yes' native_mode='tagged'
native_tag='123'></b>
+ <b><tag id='42'/></b>
+ <b></vlan></b>
+ ...
+ </interface>
<devices>
...</pre>
@@ -3234,7 +3240,17 @@ qemu-kvm -net nic,model=? /dev/null
attribute <code>trunk='yes'</code> can be added to the toplevel
vlan element.
</p>
-
+ <p>
+ For network connections using openvswitch it is possible to
+ configure the 'native-tagged' and 'native-untagged' vlan modes
+ <span class="since">(Since 1.0.3).</span> This uses the optional
+ <code>native_mode</code> and <code>native_tag</code> attributes
+ on the <code><vlan></code> element:
<code>native_mode</code>
+ may be set to 'tagged' or 'untagged', <code>native_tag</code>
+ sets the id of the native vlan. Setting a native vlan implies
+ this is a trunk port, so <code>trunk='yes'</code> will be added
if not
+ explicitly set.
+ </p>
<h5><a name="elementLink">Modifying virtual link state</a></h5>
<pre>
...
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 7b42529..68c562b 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -396,6 +396,12 @@
<parameters
interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/>
</virtualport>
</interface>
+ <interface type='bridge'>
+ <b><vlan trunk='yes' native_mode='tagged'
native_tag='123'></b>
+ <b><tag id='42'/></b>
+ <b></vlan></b>
+ ...
+ </interface>
<devices>
...</pre>
diff --git a/docs/schemas/networkcommon.rng
b/docs/schemas/networkcommon.rng
index 51ff759..4696f43 100644
--- a/docs/schemas/networkcommon.rng
+++ b/docs/schemas/networkcommon.rng
@@ -197,6 +197,21 @@
<value>yes</value>
</attribute>
</optional>
+ <optional>
+ <attribute name="native_mode">
+ <choice>
+ <value>tagged</value>
+ <value>untagged</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="native_tag">
+ <data type="unsignedInt">
+ <param name="maxInclusive">4095</param>
+ </data>
+ </attribute>
+ </optional>
<oneOrMore>
<element name="tag">
<attribute name="id">
diff --git a/src/conf/netdev_vlan_conf.c b/src/conf/netdev_vlan_conf.c
index 13ba8c6..618eb4c 100644
--- a/src/conf/netdev_vlan_conf.c
+++ b/src/conf/netdev_vlan_conf.c
@@ -17,6 +17,7 @@
*
* Authors:
* Laine Stump <laine(a)redhat.com>
+ * James Robson <jrobson(a)websense.com>
*/
#include <config.h>
@@ -33,6 +34,8 @@ virNetDevVlanParse(xmlNodePtr node, xmlXPathContextPtr
ctxt, virNetDevVlanPtr de
int ret = -1;
xmlNodePtr save = ctxt->node;
const char *trunk = NULL;
+ const char *nativeMode;
+ unsigned int nativeTag;
xmlNodePtr *tagNodes = NULL;
int nTags, ii;
@@ -73,16 +76,44 @@ virNetDevVlanParse(xmlNodePtr node,
xmlXPathContextPtr ctxt, virNetDevVlanPtr de
def->nTags = nTags;
- /* now that we know how many tags there are, look for an explicit
- * trunk setting.
- */
- if (nTags > 1)
- def->trunk = true;
+ def->nativeMode = 0;
+ def->nativeTag = 0;
ctxt->node = node;
+ if ((nativeMode = virXPathString("string(./@native_mode)", ctxt)) !
= NULL) {
+ if (STRCASENEQ(nativeMode, "tagged") && STRCASENEQ(nativeMode,
"untagged")) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid \"native_mode='%s'\" in <vlan> -
"
+ "native_mode must be 'tagged' or
'untagged'"), nativeMode);
+ goto error;
+ }
+ if (virXPathUInt("string(./@native_tag)", ctxt, &nativeTag) <
0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing or invalid native_tag
attribute"));
+ goto error;
+ }
+ if (nativeTag > 4095) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("native_tag %u too large (maximum 4095)"),
nativeTag);
+ goto error;
+ }
+ def->nativeMode = STRCASEEQ(nativeMode, "tagged") ? 1 : 2;
+ def->nativeTag = nativeTag;
+ }
+
+ /* def->trunk will be set to true if:
+ * "trunk='yes'" is set in xml
+ * a native-* vlan mode has been set
+ * >1 tag has been set */
if ((trunk = virXPathString("string(./@trunk)", ctxt)) != NULL) {
def->trunk = STRCASEEQ(trunk, "yes");
if (!def->trunk) {
+ if (def->nativeMode > 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid configuration in <vlan> -
\"trunk='no'\" is "
+ "not allowed with native_mode"));
+ goto error;
+ }
if (nTags > 1) {
virReportError(VIR_ERR_XML_ERROR,
_("invalid \"trunk='%s'\" in <vlan> -
trunk='yes' "
@@ -97,6 +128,8 @@ virNetDevVlanParse(xmlNodePtr node,
xmlXPathContextPtr ctxt, virNetDevVlanPtr de
goto error;
}
}
+ } else if (nTags > 1 || def->nativeMode > 0) {
+ def->trunk = true;
}
ret = 0;
@@ -122,8 +155,11 @@ virNetDevVlanFormat(virNetDevVlanPtr def,
virBufferPtr buf)
_("missing vlan tag data"));
return -1;
}
-
- virBufferAsprintf(buf, "<vlan%s>\n", def->trunk ? " trunk='yes'" :
"");
+ if (def->nativeMode == 0) {
+ virBufferAsprintf(buf, "<vlan%s>\n", def->trunk ? "
trunk='yes'" : "");
+ } else {
+ virBufferAsprintf(buf, "<vlan trunk='yes' native_mode='%s'
native_tag='%u'>\n", def->nativeMode == 1 ? "tagged" : "untagged",
def->nativeTag);
+ }
for (ii = 0; ii < def->nTags; ii++) {
virBufferAsprintf(buf, " <tag id='%u'/>\n", def->tag[ii]);
}
diff --git a/src/util/virnetdevopenvswitch.c
b/src/util/virnetdevopenvswitch.c
index 4fe077a..87122b0 100644
--- a/src/util/virnetdevopenvswitch.c
+++ b/src/util/virnetdevopenvswitch.c
@@ -19,6 +19,7 @@
* Dan Wendlandt <dan(a)nicira.com>
* Kyle Mestery <kmestery(a)cisco.com>
* Ansis Atteka <aatteka(a)nicira.com>
+ * James Robson <jrobson(a)websense.com>
*/
#include <config.h>
@@ -108,9 +109,13 @@ int virNetDevOpenvswitchAddPort(const char *brname,
const char *ifname,
virCommandAddArgList(cmd, "--timeout=5", "--", "--may-exist",
"add-port",
brname, ifname, NULL);
- if (virBufferUse(&buf) != 0)
+ if (virBufferUse(&buf) != 0) {
+ if (virtVlan->nativeMode > 0) {
+ virCommandAddArgFormat(cmd, "vlan_mode=%s",
virtVlan->nativeMode == 1 ? "native-tagged" : "native-untagged");
+ virCommandAddArgFormat(cmd, "tag=%d", virtVlan->nativeTag);
+ }
virCommandAddArgList(cmd, virBufferCurrentContent(&buf), NULL);
-
+ }
if (ovsport->profileID[0] == '\0') {
virCommandAddArgList(cmd,
"--", "set", "Interface", ifname,
attachedmac_ex_id,
diff --git a/src/util/virnetdevvlan.c b/src/util/virnetdevvlan.c
index 2fe2017..298673d 100644
--- a/src/util/virnetdevvlan.c
+++ b/src/util/virnetdevvlan.c
@@ -17,6 +17,7 @@
*
* Authors:
* Laine Stump <laine(a)redhat.com>
+ * James Robson <jrobson(a)websense.com>
*/
#include <config.h>
@@ -33,6 +34,8 @@ virNetDevVlanClear(virNetDevVlanPtr vlan)
{
VIR_FREE(vlan->tag);
vlan->nTags = 0;
+ vlan->nativeMode = 0;
+ vlan->nativeTag = -1;
}
void
@@ -54,7 +57,9 @@ virNetDevVlanEqual(const virNetDevVlanPtr a, const
virNetDevVlanPtr b)
return false;
if (a->trunk != b->trunk ||
- a->nTags != b->nTags) {
+ a->nTags != b->nTags ||
+ a->nativeMode != b->nativeMode ||
+ a->nativeTag != b->nativeTag) {
return false;
}
@@ -89,6 +94,8 @@ virNetDevVlanCopy(virNetDevVlanPtr dst, const
virNetDevVlanPtr src)
dst->trunk = src->trunk;
dst->nTags = src->nTags;
+ dst->nativeMode = src->nativeMode;
+ dst->nativeTag = src->nativeTag;
memcpy(dst->tag, src->tag, src->nTags * sizeof(*src->tag));
return 0;
}
diff --git a/src/util/virnetdevvlan.h b/src/util/virnetdevvlan.h
index c6b16ef..f0f78f0 100644
--- a/src/util/virnetdevvlan.h
+++ b/src/util/virnetdevvlan.h
@@ -17,6 +17,7 @@
*
* Authors:
* Laine Stump <laine(a)redhat.com>
+ * James Robson <jrobson(a)websense.com>
*/
#ifndef __VIR_NETDEV_VLAN_H__
@@ -25,6 +26,8 @@
typedef struct _virNetDevVlan virNetDevVlan;
typedef virNetDevVlan *virNetDevVlanPtr;
struct _virNetDevVlan {
+ short int nativeMode; /* 0=off, 1=tagged, 2=untagged */
+ unsigned int nativeTag;
bool trunk; /* true if this is a trunk */
int nTags; /* number of tags in array */
unsigned int *tag; /* pointer to array of tags */
diff --git a/tests/networkxml2xmlin/openvswitch-net.xml
b/tests/networkxml2xmlin/openvswitch-net.xml
index a3d82b1..93c49d5 100644
--- a/tests/networkxml2xmlin/openvswitch-net.xml
+++ b/tests/networkxml2xmlin/openvswitch-net.xml
@@ -21,4 +21,13 @@
<parameters profileid='alice-profile'/>
</virtualport>
</portgroup>
+ <portgroup name='tagged'>
+ <vlan native_mode='tagged' native_tag='123'>
+ <tag id='555'/>
+ <tag id='444'/>
+ </vlan>
+ <virtualport>
+ <parameters profileid='tagged-profile'/>
+ </virtualport>
+ </portgroup>
</network>
diff --git a/tests/networkxml2xmlout/openvswitch-net.xml
b/tests/networkxml2xmlout/openvswitch-net.xml
index a3d82b1..ab3d797 100644
--- a/tests/networkxml2xmlout/openvswitch-net.xml
+++ b/tests/networkxml2xmlout/openvswitch-net.xml
@@ -21,4 +21,13 @@
<parameters profileid='alice-profile'/>
</virtualport>
</portgroup>
+ <portgroup name='tagged'>
+ <vlan trunk='yes' native_mode='tagged' native_tag='123'>
+ <tag id='555'/>
+ <tag id='444'/>
+ </vlan>
+ <virtualport>
+ <parameters profileid='tagged-profile'/>
+ </virtualport>
+ </portgroup>
</network>
Protected by Websense Hosted Email Security -- www.websense.com
11 years, 8 months
[libvirt] doc: write separate module for hostdev passthrough and in-use tracking
by Chunyan Liu
Hi, List,
As the mail I've sent a week before:
https://www.redhat.com/archives/libvir-list/2013-March/msg00730.html
I'm willing to push this work forward so that the passthrough APIs
could be reused by qemu driver and libxl driver (which doesn't support
pci passthrough yet and tries to add this function recently), or other
drivers.
But since this work affacts a lot, I'm not sure if I can control it in
a correct way. I write a draft to describe what I'm considering how to
do, as in the following and in attachment. Hope to get your review,
comment and guidence to improve the work before start coding. Any
feedback will be very appreciated!
Thanks!
Chunyan
------------------------
DRAFT:
Write separate module for hostdev passthrough
1. Purposes:
* Move hostdev passthrough APIs from qemu_hostdev.ch to separate module so
that they could be reused by other hypervisors too
* Maintain global in-use state of hostdevs
2. Module design (draft):
* New module name: hostdev_driver
* New module files: hostdev_driver.ch hostdev_conf.ch
* New Definitions:
## [src/driver.h]
typedef struct _virHostdevDriver virHostdevDriver;
typedef virHostdevDriver *virHostdevDriverPtr;
struct _virHosedevDriver {
const char *name;
virDrvOpen open;
virDrvClose close;
virDrvPrepareHostdevs prepareHostdevs;
virDrvPreparePciHostdevs preparePciHostdevs;
virDrvprepareUsbHostdevs prepareUsbHostdevs;
virDrvReattachHostdevs reattachHostdevs;
virDrvReattachPciHostdevs reattachPciHostdevs;
virDrvReattachUsbHostdevs reattachUsbHostdevs;
virDrvGetActivePciHostdevList getActivePciHostdevList;
virDrvGetActiveUsbHostdevList getActiveUsbHostdevList;
virDrvGetDomainActivePciHostdevList
getDomainActivePciHostdevList;
virDrvGetDomainActiveUsbHostdevList
getDomainActiveUsbHostdevList;
};
## [src/hostdev/hostdev_conf.h]
typedef struct _virHostdevDriverState virHostdevDriverState;
typedef virHostdevDriverState *virHostdevDriverStatePtr;
struct _virHostdevDriverState {
virMutex lock;
virPCIDeviceListPtr activePciHostdevs;
virPCIDeviceListPtr inactivePciHostdevs;
virUSBDeviceListPtr activeUsbHostdevs;
};
## [src/hostdev/hostdev_driver.c]
static virHostdevDriver hostdevDriver = {
.name = "hostdev",
.open = hostdevDriverOpen,
.close = hostdevDriverClose,
.prepareHostdevs = virPrepareHostdevs,
.preparePciHostdevs = virPreparePciHostdevs,
.prepareUsbHostdevs = virPrepareUsbHostdevs
.reattachHostdevs = virReattachHostdevs,
.reattachPciHostdevs = virReattachPciHostdevs,
.reattachUsbHostdevs = virReattachUsbHostdevs,
.getActivePciHostdevList = virGetActivePciHostdevList,
.getActiveUsbHostdevList = virGetActiveUsbHostdevList,
.getDomainActivePciHostdevList = virGetDomainActivePciHostdevList,
.getDomainActiveUsbHostdevList = virGetDomainActiveUsbHostdevList,
};
static virStateDriver hostdevStateDriver = {
.name = "hostdev",
.initialize = hostdevDriverStartup,
.cleanup = hostdevDriverCleanup,
.reload = hostdevDriverReload,
};
* Changed Definitions:
struct _virPCIDevice {
......
--- const char *used_by; /* The domain which uses the device */
+++ virDomainObjPtr used_by; /* include domname and conn info */
......
};
struct _virUSBDevice {
......
--- const char *used_by; /* name of the domain using this dev */
+++ virDomainObjPtr used_by; /* include domname and conn info */
};
* APIs:
typedef int
(*virDrvPrepareHostdevs)(virHostdevDriverPtr driver,
virDomainObjPtr vm,
unsigned int flags);
/*
- workflow:
call PrepareHostdevPciDevices and PrepareHostdevUsbDevices
to do specific work.
- reference:
int qemuPrepareHostDevices(virQEMUDriverPtr driver,
virDomainDefPtr def,
bool coldBoot);
- new parameter:
- flags:
- could set "coldBoot" for usb usage
- could set hypervisor tag since for qemu it will use
pci-stub, for libxl, it will use pciback.
*/
typedef int
(*virDrvPreparePciHostdevs)(virHostdevDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs,
unsigned int flags);
/*
- workflow:
1. check things (e.g. assignability to non-managed device)
2. detach managed device and reset work
3. set usedby to 'vm', update activePciHostdevs and
inactivePciHostdevs
- reference:
int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
const char *name,
const unsigned char *uuid,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs);
*/
typedef int
(*virDrvprepareUsbHostdevs)((virHostdevDriverPtr driver,
virDomainObjPtr vm,
virUSBDeviceListPtr list);
/*
- workflow:
check usb device, set usedby to 'vm', update activeUsbHostdevs
- reference:
int qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver,
const char *name,
virUSBDeviceListPtr list);
*/
typedef void
(*virDrvReattachHostdevs)(virHostdevDriverPtr driver,
virDomainObjPtr vm);
/*
- workflow:
call reattachPciHostDevices and reattachUsbHostDevices to
do specific work.
- reference:
void qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
virDomainDefPtr def)
*/
typedef void
(*virDrvReattachPciHostdevs) (virHostdevDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs);
/*
- workflow:
unbind and bind to original driver, free
usedby, activePciHostdevs and inactivePciHostdevs.
- reference:
void qemuDomainReAttachHostdevDevices(virQEMUDriverPtrdriver,
const char *name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs)
*/
typedef void
(*virDrvReattachUsbHostdevs) (virHostdevDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs);
/*
- workflow:
free usedby, activePciHostdevs and inactivePciHostdevs.
- reference:
static void
qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver,
const char *name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs)
*/
typedef virPCIDeviceListPtr
(*virDrvGetActivePciHostdevList) (virHostdevDriverPtr driver);
/*
- could be used to check if a pci hostdev is already in-use.
*/
typedef virUSBDeviceListPtr
(*virDrvGetActiveUsbHostdevList) (virHostdevDriverPtr driver);
/*
- could be used to check if a usb hostdev is already in-use.
*/
typedef virPCIDeviceListPtr
(*virDrvGetDomainActivePciHostdevList) (virHostdevDriverPtr driver);
/*
- could be used to reattach all in-use pci hostdevs by a
domain (e.g. when a domain shutdown)
*/
typedef virPCIDeviceListPtr
(*virDrvGetDomainActiveUsbHostdevList) (virHostdevDriverPtr driver);
/*
- could be used to reattach all in-use usb hostdevs by a
domain
*/
3. Use the module
* Register hostdev driver
- define 'virHostdevDriverTab' and 'virHostdevDriverTabCount'
- add hostdev driver register work in libvirtd.c daemonInitialize()
* add hostdev driver areas to _virConnect
struct _virConnect {
.......
virNWFilterDriverPtr nwfilterDriver;
+++ virHostdevDriverPtr hostdevDriver;
.......
void * nwfilterPrivateData;
+++ void * hostdevPrivateData;
.......
}
* add conn->hostdevDriver parser in libvirt.c: do_open()
Then hypervisor drivers can get use of hostdev driver APIs.
* moments that could be affacted:
- domain start/shutoff
- attach/detach hostdev to domain
--------------------------------------------
11 years, 8 months
[libvirt] [PATCH] docs: Add detailed notes snapshots, blockcommit, blockpull
by Kashyap Chamarthy
More elaborate notes on snapshots, blockpull, blockcommit. Much of this
is derived from various dicussions with Eric Blake, Jeff Cody, Kevin Wolf
(thanks a lot!) & several others on IRC and mailing lists and a lot of adhoc
testing. I didn't wanted this to get lost.
I also plan to add notes for 'blockcopy' once I complete testing with upstream
libvirt/qemu git.
NOTE: This document is formatted using reStructuredText. And can be trivially
converted to HTML using:
# rst2html snapshots-blockcommit-blockpull.rst > snapshots-blockcommit-blockpull.html
('rst2html' is part of python-docutils package.)
I didn't send an html PATCH directly, as I thought, this'd be more readable.
Any comments, criticisms more than welcome.
---
docs/snapshots-blockcommit-blockpull.rst | 646 ++++++++++++++++++++++++++++++
1 files changed, 646 insertions(+), 0 deletions(-)
create mode 100644 docs/snapshots-blockcommit-blockpull.rst
diff --git a/docs/snapshots-blockcommit-blockpull.rst b/docs/snapshots-blockcommit-blockpull.rst
new file mode 100644
index 0000000000000000000000000000000000000000..99c30223a004ee5291e2914b788ac7fe04eee3c8
--- /dev/null
+++ b/docs/snapshots-blockcommit-blockpull.rst
@@ -0,0 +1,646 @@
+.. ----------------------------------------------------------------------
+ Note: All these tests were performed with latest qemu-git,libvirt-git (as of
+ 20-Oct-2012 on a Fedora-18 alpha machine
+.. ----------------------------------------------------------------------
+
+
+Introduction
+============
+
+A virtual machine snapshot is a view of a virtual machine(its OS & all its
+applications) at a given point in time. So that, one can revert to a known sane
+state, or take backups while the guest is running live. So, before we dive into
+snapshots, let's have an understanding of backing files and overlays.
+
+
+
+QCOW2 backing files & overlays
+------------------------------
+
+In essence, QCOW2(Qemu Copy-On-Write) gives you an ability to create a base-image,
+and create several 'disposable' copy-on-write overlay disk images on top of the
+base image(also called backing file). Backing files and overlays are
+extremely useful to rapidly instantiate thin-privisoned virtual machines(more on
+it below). Especially quite useful in development & test environments, so that
+one could quickly revert to a known state & discard the overlay.
+
+**Figure-1**
+
+::
+
+ .--------------. .-------------. .-------------. .-------------.
+ | | | | | | | |
+ | RootBase |<---| Overlay-1 |<---| Overlay-1A <--- | Overlay-1B |
+ | (raw/qcow2) | | (qcow2) | | (qcow2) | | (qcow2) |
+ '--------------' '-------------' '-------------' '-------------'
+
+The above figure illustrates - RootBase is the backing file for Overlay-1, which
+in turn is backing file for Overlay-2, which in turn is backing file for
+Overlay-3.
+
+**Figure-2**
+::
+
+ .-----------. .-----------. .------------. .------------. .------------.
+ | | | | | | | | | |
+ | RootBase |<--- Overlay-1 |<--- Overlay-1A <--- Overlay-1B <--- Overlay-1C |
+ | | | | | | | | | (Active) |
+ '-----------' '-----------' '------------' '------------' '------------'
+ ^ ^
+ | |
+ | | .-----------. .------------.
+ | | | | | |
+ | '-------| Overlay-2 |<---| Overlay-2A |
+ | | | | (Active) |
+ | '-----------' '------------'
+ |
+ |
+ | .-----------. .------------.
+ | | | | |
+ '------------| Overlay-3 |<---| Overlay-3A |
+ | | | (Active) |
+ '-----------' '------------'
+
+The above figure is just another representation which indicates, we can use a
+'single' backing file, and create several overlays -- which can be used further,
+to create overlays on top of them.
+
+
+**NOTE**: Backing files are always opened **read-only**. In other words, once
+ an overlay is created, its backing file should not be modified(as the
+ overlay depends on a particular state of the backing file). Refer
+ below ('blockcommit' section) for relevant info on this.
+
+
+**Example** :
+
+::
+
+ [FedoraBase.img] ----- <- [Fedora-guest-1.qcow2] <- [Fed-w-updates.qcow2] <- [Fedora-guest-with-updates-1A]
+ \
+ \--- <- [Fedora-guest-2.qcow2] <- [Fed-w-updates.qcow2] <- [Fedora-guest-with-updates-2A]
+
+(Arrow to be read as Fed-w-updates.qcow2 has Fedora-guest-1.qcow2 as its backing file.)
+
+In the above example, say, *FedoraBase.img* has a freshly installed Fedora-17 OS on it,
+and let's establish it as our backing file. Now, FedoraBase can be used as a
+read-only 'template' to quickly instantiate two(or more) thinly provisioned
+Fedora-17 guests(say Fedora-guest-1.qcow2, Fedora-guest-2.qcow2) by creating
+QCOW2 overlay files pointing to our backing file. Also, the example & *Figure-2*
+above illustrate that a single root-base image(FedoraBase.img) can be used
+to create multiple overlays -- which can subsequently have their own overlays.
+
+
+ To create two thinly-provisioned Fedora clones(or overlays) using a single
+ backing file, we can invoke qemu-img as below: ::
+
+
+ # qemu-img create -b /export/vmimages/RootBase.img -f qcow2 \
+ /export/vmimages/Fedora-guest-1.qcow2
+
+ # qemu-img create -b /export/vmimages/RootBase.img -f qcow2 \
+ /export/vmimages/Fedora-guest-2.qcow2
+
+ Now, both the above images *Fedora-guest-1* & *Fedora-guest-2* are ready to
+ boot. Continuting with our example, say, now you want to instantiate a
+ Fedora-17 guest, but this time, with full Fedora updates. This can be
+ accomplished by creating another overlay(Fedora-guest-with-updates-1A) - but
+ this overly would point to 'Fed-w-updates.qcow2' as its backing file (which
+ has the full Fedora updates) ::
+
+ # qemu-img create -b /export/vmimages/Fed-w-updates.qcow2 -f qcow2 \
+ /export/vmimages/Fedora-guest-with-updates-1A.qcow2
+
+
+ Information about a disk image, like virtual size, disk size, backing file(if it
+ exists) can be obtained by using 'qemu-img' as below:
+ ::
+
+ # qemu-img info /export/vmimages/Fedora-guest-with-updates-1A.qcow2
+
+ NOTE: With latest qemu, an entire backing chain can be recursively
+ enumerated by doing:
+ ::
+
+ # qemu-img info --backing-chain /export/vmimages/Fedora-guest-with-updates-1A.qcow2
+
+
+
+Snapshot Terminology:
+---------------------
+
+ - **Internal Snapshots** -- A single qcow2 image file holds both the saved state
+ & the delta since that saved point. This can be further classified as :-
+
+ (1) **Internal disk snapshot**: The state of the virtual disk at a given
+ point in time. Both the snapshot & delta since the snapshot are
+ stored in the same qcow2 file. Can be taken when the guest is 'live'
+ or 'offline'.
+
+ - Libvirt uses QEMU's 'qemu-img' command when the guest is 'offline'.
+ - Libvirt uses QEMU's 'savevm' command when the guest is 'live'.
+
+ (2) **Internal system checkpoint**: RAM state, device state & the
+ disk-state of a running guest, are all stored in the same originial
+ qcow2 file. Can be taken when the guest is running 'live'.
+
+ - Libvirt uses QEMU's 'savevm' command when the guest is 'live'
+
+
+ - **External Snapshots** -- Here, when a snapshot is taken, the saved state will
+ be stored in one file(from that point, it becomes a read-only backing
+ file) & a new file(overlay) will track the deltas from that saved state.
+ This can be further classified as :-
+
+ (1) **External disk snapshot**: The snapshot of the disk is saved in one
+ file, and the delta since the snapshot is tracked in a new qcow2
+ file. Can be taken when the guest is 'live' or 'offline'.
+
+ - Libvirt uses QEMU's 'transaction' cmd under the hood, when the
+ guest is 'live'.
+
+ - Libvirt uses QEMU's 'qemu-img' cmd under the hood when the
+ guest is 'offline'(this implementation is in progress, as of
+ writing this).
+
+ (2) **External system checkpoint**: Here, the guest's disk-state will be
+ saved in one file, its RAM & device-state will be saved in another
+ new file (This implementation is in progress upstream libvirt, as of
+ writing this).
+
+
+
+ - **VM State**: Saves the RAM & device state of a running guest(not 'disk-state') to
+ a file, so that it can be restored later. This simliar to doing hibernate
+ of the system. (NOTE: The disk-state should be unmodified at the time of
+ restoration.)
+
+ - Libvirt uses QEMU's 'migrate' (to file) cmd under the hood.
+
+
+
+Creating snapshots
+==================
+ - Whenever an 'external' snapshot is issued, a /new/ overlay image is
+ created to facilitate guest writes, and the previous image becomes a
+ snapshot.
+
+ - **Create a disk-only internal snapshot**
+
+ (1) If I have a guest named 'f17vm1', to create an offline or online
+ 'internal' snapshot called 'snap1' with description 'snap1-desc' ::
+
+ # virsh snapshot-create-as f17vm1 snap1 snap1-desc
+
+ (2) List the snapshot ; and query using *qemu-img* tool to view
+ the image info & its internal snapshot details ::
+
+ # virsh snapshot-list f17vm1
+ # qemu-img info /home/kashyap/vmimages/f17vm1.qcow2
+
+
+
+ - **Create a disk-only external snapshot** :
+
+ (1) List the block device associated with the guest. ::
+
+ # virsh domblklist f17-base
+ Target Source
+ ---------------------------------------------
+ vda /export/vmimages/f17-base.qcow2
+
+ #
+
+ (2) Create external disk-only snapshot (while the guest is *running*). ::
+
+ # virsh snapshot-create-as --domain f17-base snap1 snap1-desc \
+ --disk-only --diskspec vda,snapshot=external,file=/export/vmimages/sn1-of-f17-base.qcow2 \
+ --atomic
+ Domain snapshot snap1 created
+ #
+
+ * Once the above command is issued, the original disk-image
+ of f17-base will become the backing_file & a new overlay
+ image is created to track the new changes. Here on, libvirt
+ will use this overlay for further write operations(while
+ using the original image as a read-only backing_file).
+
+ (3) Now, list the block device associated(use cmd from step-1, above)
+ with the guest,again, to ensure it reflects the new overlay image as
+ the current block device in use. ::
+
+ # virsh domblklist f17-base
+ Target Source
+ ----------------------------------------------------
+ vda /export/vmimages/sn1-of-f17-base.qcow2
+
+ #
+
+
+
+
+Reverting to snapshots
+======================
+As of writing this, reverting to 'Internal Snapshots'(system checkpoint or
+disk-only) is possible.
+
+ To revert to a snapshot named 'snap1' of domain f17vm1 ::
+
+ # virsh snapshot-revert --domain f17vm1 snap1
+
+Reverting to 'external disk snapshots' using *snapshot-revert* is a little more
+tricky, as it involves slightly complicated process of dealing with additional
+snapshot files - whether to merge 'base' images into 'top' or to merge other way
+round ('top' into 'base').
+
+That said, there are a couple of ways to deal with external snapshot files by
+merging them to reduce the external snapshot disk image chain by performing
+either a **blockpull** or **blockcommit** (more on this below).
+
+Further improvements on this front is in work upstream libvirt as of writing
+this.
+
+
+
+Merging snapshot files
+======================
+External snapshots are incredibly useful. But, with plenty of external snapshot
+files, there comes a problem of maintaining and tracking all these inidivdual
+files. At a later point in time, we might want to 'merge' some of these snapshot
+files (either backing_files into overlays or vice-versa) to reduce the length of
+the image chain. To accomplish that, there are two mechanisms:
+
+ + blockcommit: merges data from **top** into **base** (in other
+ words, merge overlays into backing files).
+
+
+ + blockpull: Populates a disk image with data from its backing file. Or
+ merges data from **base** into **top** (in other words, merge backing files
+ into overlays).
+
+
+blockcommit
+-----------
+
+Block Commit allows you to merge from a 'top' image(within a disk backing file
+chain) into a lower-level 'base' image. To rephrase, it allows you to
+merge overlays into backing files. Once the **blockcommit** operation is finished,
+any portion that depends on the 'top' image, will now be pointing to the 'base'.
+
+This is useful in flattening(or collapsing or reducing) backing file chain
+length after taking several external snapshots.
+
+
+Let's understand with an illustration below:
+
+We have a base image called 'RootBase', which has a disk image chain with 4
+external snapshots. With 'Active' as the current active-layer, where 'live' guest
+writes happen. There are a few possibilities of resulting image chains that we
+can end up with, using 'blockcommit' :
+
+ (1) Data from Snap-1, Snap-2 and Snap-3 can be merged into 'RootBase'
+ (resulting in RootBase becoming the backing_file of 'Active', and thus
+ invalidating Snap-1, Snap-2, & Snap-3).
+
+ (2) Data from Snap-1 and Snap-2 can be merged into RootBase(resulting in
+ Rootbase becoming the backing_file of Snap-3, and thus invalidating
+ Snap-1 & Snap-2).
+
+ (3) Data from Snap-1 can be merged into RootBase(resulting in RootBase
+ becoming the backing_file of Snap-2, and thus invalidating Snap-1).
+
+ (4) Data from Snap-2 can be merged into Snap-1(resulting in Snap-1 becoming
+ the backing_file of Snap-3, and thus invalidating Snap-2).
+
+ (5) Data from Snap-3 can be merged into Snap-2(resulting in Snap-2 becoming
+ the backing_file for 'Active', and thus invalidating Snap-3).
+
+ (6) Data from Snap-2 and Snap-3 can be merged into Snap-1(resulting in
+ Snap-1 becoming the backing_file of 'Active', and thus invalidating
+ Snap-2 & Snap-3).
+
+ NOTE: Eventually(not supported in qemu as of writing this), we can also
+ merge down the 'Active' layer(the top-most overlay) into its
+ backing_files. Once it is supported, the 'top' argument can become
+ optional, and default to active layer.
+
+
+(The below figure illustrates case (6) from the above)
+
+**Figure-3**
+::
+
+ .------------. .------------. .------------. .------------. .------------.
+ | | | | | | | | | |
+ | RootBase <--- Snap-1 <--- Snap-2 <--- Snap-3 <--- Snap-4 |
+ | | | | | | | | | (Active) |
+ '------------' '------------' '------------' '------------' '------------'
+ / |
+ / |
+ / commit data |
+ / |
+ / |
+ / |
+ v commit data |
+ .------------. .------------. <--------------------' .------------.
+ | | | | | |
+ | RootBase <--- Snap-1 |<---------------------------------| Snap-4 |
+ | | | | Backing File | (Active) |
+ '------------' '------------' '------------'
+
+For instance, if we have the below scenario:
+
+ Actual: [base] <- sn1 <- sn2 <- sn3 <- sn4(this is active)
+
+ Desired: [base] <- sn1 <- sn4 (thus invalidating sn2,sn3)
+
+ Any of the below two methods is valid (as of 17-Oct-2012 qemu-git). With
+ method-a, operation will be faster & correct if we don't care about
+ sn2(because, it'll be invalidated). Note that, method-b is slower, but sn2
+ will remain valid. (Also note that, the guest is 'live' in all these cases).
+
+ **(method-a)**:
+ ::
+
+ # virsh blockcommit --domain f17 vda --base /export/vmimages/sn1.qcow2 --top /export/vmimages/sn3.qcow2 --wait --verbose
+
+ [OR]
+
+ **(method-b)**:
+ ::
+
+ # virsh blockcommit --domain f17 vda --base /export/vmimages/sn2.qcow2 --top /export/vmimages/sn3.qcow2 --wait --verbose
+ # virsh blockcommit --domain f17 vda --base /export/vmimages/sn1.qcow2 --top /export/vmimages/sn2.qcow2 --wait --verbose
+
+ NOTE: If we had to do manually with *qemu-img* cmd, we can only do method-b at the moment.
+
+
+**Figure-4**
+::
+
+ .------------. .------------. .------------. .------------. .------------.
+ | | | | | | | | | |
+ | RootBase <--- Snap-1 <--- Snap-2 <--- Snap-3 <--- Snap-4 |
+ | | | | | | | | | (Active) |
+ '------------' '------------' '------------' '------------' '------------'
+ / | |
+ / | |
+ / | |
+ commit data / commit data | |
+ / | |
+ / | commit data |
+ v | |
+ .------------.<----------------------|-------------' .------------.
+ | |<----------------------' | |
+ | RootBase | | Snap-4 |
+ | |<-------------------------------------------------| (Active) |
+ '------------' Backing File '------------'
+
+
+The above figure is another representation of reducing the disk image chain
+using blockcommit. Data from Snap-1, Snap-2, Snap-3 are merged(/committed)
+into RootBase, & now the current 'Active' image now pointing to 'RootBase' as its
+backing file(instead of Snap-3, which was the case *before* blockcommit). Note
+that, now intermediate images Snap-1, Snap-1, Snap-3 will be invalidated(as they were
+dependent on a particular state of RootBase).
+
+blockpull
+---------
+Block Pull(also called 'Block Stream' in QEMU's paralance) allows you to merge
+into 'base' from a 'top' image(within a disk backing file chain). To rephrase it
+allows merging backing files into an overlay(active). This works in the
+opposite side of 'blockcommit' to flatten the snapshot chain. At the moment,
+**blockpull** can pull only into the active layer(the top-most image). It's
+worth noting here that, intermediate images are not invalidated once a blockpull
+operation is complete (while blockcommit, invalidates them).
+
+
+Consider the below illustration:
+
+**Figure-5**
+::
+
+ .------------. .------------. .------------. .------------. .------------.
+ | | | | | | | | | |
+ | RootBase <--- Snap-1 <--- Snap-2 <--- Snap-3 <--- Snap-4 |
+ | | | | | | | | | (Active) |
+ '------------' '------------' '------------' '------------' '------------'
+ | | \
+ | | \
+ | | \
+ | | \ stream data
+ | | stream data \
+ | stream data | \
+ | | v
+ .------------. | '---------------> .------------.
+ | | '---------------------------------> | |
+ | RootBase | | Snap-4 |
+ | | <---------------------------------------- | (Active) |
+ '------------' Backing File '------------'
+
+
+
+The above figure illustrates that, using block-copy we can pull data from
+Snap-1, Snap-2 and Snap-3 into the 'Active' layer, resulting in 'RootBase'
+becoming the backing file for the 'Active' image (instead of 'Snap-3', which was
+the case before doing the blockpull operation).
+
+The command flow would be:
+ (1) Assuming a external disk-only snapshot was created as mentioned in
+ *Creating Snapshots* section:
+
+ (2) A blockpull operation can be issued this way, to achieve the desired
+ state of *Figure-5*-- [RootBase] <- [Active]. ::
+
+ # virsh blockpull --domain RootBase --path var/lib/libvirt/images/active.qcow2 --base /var/lib/libvirt/images/RootBase.qcow2 --wait --verbose
+
+
+ As a follow up, we can do the below to clean-up the snapshot *tracking*
+ metadata by libvirt (note: the below does not 'remove' the files, it
+ just cleans up the snapshot tracking metadata). ::
+
+ # virsh snapshot-delete --domain RootBase Snap-3 --metadata
+ # virsh snapshot-delete --domain RootBase Snap-2 --metadata
+ # virsh snapshot-delete --domain RootBase Snap-1 --metadata
+
+
+
+
+**Figure-6**
+::
+
+ .------------. .------------. .------------. .------------. .------------.
+ | | | | | | | | | |
+ | RootBase <--- Snap-1 <--- Snap-2 <--- Snap-3 <--- Snap-4 |
+ | | | | | | | | | (Active) |
+ '------------' '------------' '------------' '------------' '------------'
+ | | | \
+ | | | \
+ | | | \ stream data
+ | | | stream data \
+ | | | \
+ | | stream data | \
+ | stream data | '------------------> v
+ | | .--------------.
+ | '---------------------------------> | |
+ | | Snap-4 |
+ '----------------------------------------------------> | (Active) |
+ '--------------'
+ 'Standalone'
+ (w/o backing
+ file)
+
+The above figure illustrates, once blockpull operation is complete, by
+pulling/streaming data from RootBase, Snap-1, Snap-2, Snap-3 into 'Active', all
+the backing files can be discarded and 'Active' now will be a standalone image
+without any backing files.
+
+Command flow would be:
+ (0) Assuming 4 external disk-only (live) snapshots were created as
+ mentioned in *Creating Snapshots* section,
+
+ (1) Let's check the snapshot overlay images size *before* blockpull operation (note the image of 'Active'):
+ ::
+
+ # ls -lash /var/lib/libvirt/images/RootBase.img
+ 608M -rw-r--r--. 1 qemu qemu 1.0G Oct 11 17:54 /var/lib/libvirt/images/RootBase.img
+
+ # ls -lash /var/lib/libvirt/images/*Snap*
+ 840K -rw-------. 1 qemu qemu 896K Oct 11 17:56 /var/lib/libvirt/images/Snap-1.qcow2
+ 392K -rw-------. 1 qemu qemu 448K Oct 11 17:56 /var/lib/libvirt/images/Snap-2.qcow2
+ 456K -rw-------. 1 qemu qemu 512K Oct 11 17:56 /var/lib/libvirt/images/Snap-3.qcow2
+ 2.9M -rw-------. 1 qemu qemu 3.0M Oct 11 18:10 /var/lib/libvirt/images/Active.qcow2
+
+ (2) Also, check the disk image information of 'Active'. It can noticed that
+ 'Active' has Snap-3 as its backing file. ::
+
+ # qemu-img info /var/lib/libvirt/images/Active.qcow2
+ image: /var/lib/libvirt/images/Active.qcow2
+ file format: qcow2
+ virtual size: 1.0G (1073741824 bytes)
+ disk size: 2.9M
+ cluster_size: 65536
+ backing file: /var/lib/libvirt/images/Snap-3.qcow2
+
+ (3) Do the **blockpull** operation. ::
+
+ # virsh blockpull --domain ptest2-base --path /var/lib/libvirt/images/Active.qcow2 --wait --verbose
+ Block Pull: [100 %]
+ Pull complete
+
+ (4) Let's again check the snapshot overlay images size *after*
+ blockpull operation. It can be noticed, 'Active' is now considerably larger. ::
+
+ # ls -lash /var/lib/libvirt/images/*Snap*
+ 840K -rw-------. 1 qemu qemu 896K Oct 11 17:56 /var/lib/libvirt/images/Snap-1.qcow2
+ 392K -rw-------. 1 qemu qemu 448K Oct 11 17:56 /var/lib/libvirt/images/Snap-2.qcow2
+ 456K -rw-------. 1 qemu qemu 512K Oct 11 17:56 /var/lib/libvirt/images/Snap-3.qcow2
+ 1011M -rw-------. 1 qemu qemu 3.0M Oct 11 18:29 /var/lib/libvirt/images/Active.qcow2
+
+
+ (5) Also, check the disk image information of 'Active'. It can now be
+ noticed that 'Active' is a standalone image without any backing file -
+ which is the desired state of *Figure-6*.::
+
+ # qemu-img info /var/lib/libvirt/images/Active.qcow2
+ image: /var/lib/libvirt/images/Active.qcow2
+ file format: qcow2
+ virtual size: 1.0G (1073741824 bytes)
+ disk size: 1.0G
+ cluster_size: 65536
+
+ (6) We can now clean-up the snapshot tracking metadata by libvirt to
+ reflect the new reality ::
+
+ # virsh snapshot-delete --domain RootBase Snap-3 --metadata
+
+ (7) Optionally, one can check, the guest disk contents by invoking
+ *guestfish* tool(part of *libguestfs*) **READ-ONLY** (*--ro* option
+ below does it) as below ::
+
+ # guestfish --ro -i -a /var/lib/libvirt/images/Active.qcow2
+
+
+Deleting snapshots (and 'offline commit')
+=========================================
+
+Deleting (live/offline) *Internal Snapshots* (where the originial & all the named snapshots
+are stored in a single QCOW2 file), is quite straight forward. ::
+
+ # virsh snapshot-delete --domain f17vm --snapshotname snap6
+
+ [OR]
+
+ # virsh snapshot-delete f17vm snap6
+
+Deleting External snapshots (offline), Libvirt has not acquired the capability.
+But, it can be done via *qemu-img* manipulation.
+
+Say, we have this image chain(the guest is *offline* here): **base <- sn1 <- sn2 <- sn3**
+(arrow to be read as 'sn3 has sn2 as its backing file').
+
+
+And, we want to delete the second snapshot(sn2). It's possible to do it in two
+ways:
+
+
+ - **Method (1)**: **base <- sn1 <- sn3** (by copying sn2 into sn1)
+ - **Method (2)**: **base <- sn1 <- sn3** (by copying sn2 into sn3)
+
+Method (1)
+----------
+To end up with this image chain : **base <- sn1 <- sn3** (by copying *sn2* into *sn1*)
+
+**NOTE**: This is only possible *if* sn1 isn't used by more images as their backing
+file, or they'd get corrupted!!
+
+ (a) We're doing an *offline commit* (similar to what *blockcommit* can do
+ to an *online* guest). ::
+
+ # qemu-img commit sn2.qcow2
+
+ - This will *commit* the changes from sn2 into its backing file(which is
+ sn1).
+
+ (b) Now that we've comitted changes from sn2 into sn1, let's change the
+ backing file link in sn3 to point to sn1. ::
+
+ # qemu-img rebase -u -b sn1.qcow2 sn3.qcow2
+
+ - **NOTE**: This is 'Unsafe mode' -- in this mode, only the backing file
+ name is changed w/o any checks on the file contents. The user must
+ take care of specifying the correct new backing file, or the
+ guest-visible. This mode is useful for renaming or moving the
+ backing file to somewhere else. It can be used without an
+ accessible old backing file, i.e. you can use it to fix an image
+ whose backing file has already been moved/renamed.
+
+
+ (c) Now, we can delete the sn2 disk image(as the changes are now committed
+ to sn1). ::
+
+ # rm sn2.qcow2
+
+
+Method (2)
+----------
+To end up with this image chain : **base <- sn1 <- sn3** (by copying *sn2* into *sn3*)
+
+ (a) Copy contents of sn2(the old backing file) into sn3, and change the backing file link of sn3 to sn1::
+
+ # qemu-img rebase -b sn1.qcow2 sn3.qcow2
+
+ - Apart from changing backing file link of sn3 to sn1, the above cmd
+ will it also /copy/ the contents from sn2 into sn3).
+
+ - In other words: This is 'Safe mode', which is the default --
+ any clusters that differ between the new backing_file(in this
+ case, sn1) and the old backing file(in this case, sn2) of
+ filename(in this case, sn3) are merged into filename(sn3), before
+ actually changing the backing file.
+
+ (b) Now, we can delete the sn2 disk image(as the changes are now committed to
+ sn1). ::
+
+ # rm sn2.qcow2
+
--
1.7.7.6
11 years, 8 months
[libvirt] Google Summer of Code 2013 ideas wiki open
by Stefan Hajnoczi
I have created the Google Summer of Code 2013 wiki page where you can
add project ideas:
http://wiki.qemu.org/Google_Summer_of_Code_2013
Please add project ideas you are willing to mentor. If you have an
idea but cannot mentor this year, feel free to add it but please try
to find a mentor for it.
If you want to be a mentor, please see
http://wiki.qemu.org/Google_Summer_of_Code_2013#Information_for_mentors.
Background on Google Summer of Code:
Google Summer of Code is a scheme where Google funds university
students to work on open source projects for 12 weeks during the
summer. It has been held annually since 2005.
GSoC is an opportunity for students to experience open source
development. Organizations sometimes find long-term contributors, and
either way it's a fun experience.
Open source organizations can apply to take part. Those chosen will
be able to take on one or more students for the summer. Each student
is paired with a mentor who helps them and evaluates their progress.
Last year QEMU was not accepted but we were successful in years before
that. I believe Google will announce GSoC again this year (there is
no guarantee though) and I have created the wiki page so we can begin
organizing project ideas that students can choose from.
This way we'll be ready to put together a good organization application.
Stefan
11 years, 8 months
[libvirt] [PATCH 0/5] VirtualBox version 4.2 support for libvirt vbox driver
by ryan woodsmall
This patch set adds VirtualBox 4.2 initial support for the libvirt vbox driver.
I've tested enough to check capabilities, create a VM, destroy it, etc. Five
patches total:
- Patch 1 is the C API header file from Oracle, cleaned up for libvirt.
- Patch 2 is the version specific source file for version dependency.
- Patch 3 is the src/Makefile.am change to pick up the two new files.
- Patch 4 is the vbox driver support for the new VirtualBox API/version.
- Patch 5 is the vbox_tmpl.c template support for the new version.
A few things have changed in the VirtualBox API - some small (capitalizations
of things in function names like Ip to IP and Dhcp to DHCP) and some much larger
(FindMedium is superceded by OpenMedium). The biggest change for the sake of this
patch set is the signature of CreateMachine is quite a bit different. Using the
Oracle source as a guide, to spin up a VM with a given UUID, it looks like a text
flag has to be passed in a new argument to CreateMachine. This flag is built in the
VirtualBox 4.2 specific ifdefs and is kind of ugly but works. Additionally, there
is now (unused) VM groups support in CreateMachine and the previous 'osTypeId' arg
is currently set to nsnull as in the Oracle code.
The FindMedium to OpenMedium changes were more straightforward and are pretty clear.
The rest of the vbox template changes are basically spelling/capitalization changes
from the looks of things.
This probably isn't perfect, but it works on git and patched against 0.10.2 for a
few quick tests. Not currently on the list, so ping me directly if you need any
other info on these, or if anything could use additional work. Thanks! -r
ryan woodsmall (5):
vbox C API header for VirtualBox v4.2
vbox version-specific C file for VirtualBox v4.2
Makefile.am additions for VirtualBox v4.2
vbox driver support for VirtualBox v4.2
vbox template support for VirtualBox v4.2
src/Makefile.am | 3 +-
src/vbox/vbox_CAPI_v4_2.h | 8855 +++++++++++++++++++++++++++++++++++++++++++++
src/vbox/vbox_V4_2.c | 13 +
src/vbox/vbox_driver.c | 8 +
src/vbox/vbox_tmpl.c | 90 +-
5 files changed, 8958 insertions(+), 11 deletions(-)
create mode 100644 src/vbox/vbox_CAPI_v4_2.h
create mode 100644 src/vbox/vbox_V4_2.c
11 years, 8 months
[libvirt] [PATCH v3 1/3] Add NVRAM device
by Li Zhang
From: Li Zhang <zhlcindy(a)linux.vnet.ibm.com>
For pSeries guest in QEMU, NVRAM is one kind of spapr-vio device.
Users are allowed to specify spapr-vio devices'address.
But NVRAM is not supported in libvirt. So this patch is to
add NVRAM device to allow users to specify its address.
In QEMU, NVRAM device's address is specified by
"-global spapr-nvram.reg=xxxxx".
In libvirt, XML file is defined as the following:
<nvram>
<address type='spapr-vio' reg='0x3000'/>
</nvram>
Signed-off-by: Li Zhang <zhlcindy(a)linux.vnet.ibm.com>
---
v3 -> v2:
* Add NVRAM in domaincommon.rng and formatdomain.xml.in suggested by Daniel P.Berrange
* Add NVRAM test cases suggested by Daniel P.Berrange
* Remove nvram allocation when it is not specified suggested by Daniel P.Berrange
* Add several error reports suggested by Daniel P.Berrange
v2 -> v1:
* Add NVRAM parameters parsing in qemuParseCommandLine
src/conf/domain_conf.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 10 +++++++
src/qemu/qemu_command.c | 67 +++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_command.h | 2 ++
4 files changed, 155 insertions(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 3278e9c..c37487c 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -190,6 +190,7 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
"smartcard",
"chr",
"memballoon",
+ "nvram",
"rng")
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
@@ -1515,6 +1516,16 @@ void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def)
VIR_FREE(def);
}
+void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def)
+{
+ if (!def)
+ return;
+
+ virDomainDeviceInfoClear(&def->info);
+
+ VIR_FREE(def);
+}
+
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
{
if (!def)
@@ -1678,6 +1689,7 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_CHR:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
+ case VIR_DOMAIN_DEVICE_NVRAM:
case VIR_DOMAIN_DEVICE_LAST:
break;
}
@@ -1869,6 +1881,7 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainWatchdogDefFree(def->watchdog);
virDomainMemballoonDefFree(def->memballoon);
+ virDomainNVRAMDefFree(def->nvram);
for (i = 0; i < def->nseclabels; i++)
virSecurityLabelDefFree(def->seclabels[i]);
@@ -2429,6 +2442,12 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
if (cb(def, &device, &def->rng->info, opaque) < 0)
return -1;
}
+ if (def->nvram) {
+ device.type = VIR_DOMAIN_DEVICE_NVRAM;
+ device.data.nvram = def->nvram;
+ if (cb(def, &device, &def->nvram->info, opaque) < 0)
+ return -1;
+ }
device.type = VIR_DOMAIN_DEVICE_HUB;
for (i = 0; i < def->nhubs ; i++) {
device.data.hub = def->hubs[i];
@@ -2460,6 +2479,7 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_CHR:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
+ case VIR_DOMAIN_DEVICE_NVRAM:
case VIR_DOMAIN_DEVICE_LAST:
case VIR_DOMAIN_DEVICE_RNG:
break;
@@ -7703,6 +7723,23 @@ error:
goto cleanup;
}
+static virDomainNVRAMDefPtr
+virDomainNVRAMDefParseXML(const xmlNodePtr node,
+ unsigned int flags)
+{
+ virDomainNVRAMDefPtr def;
+
+ if (VIR_ALLOC(def) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ if ( virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0 )
+ return NULL;
+
+ return def;
+}
+
static virSysinfoDefPtr
virSysinfoParseXML(const xmlNodePtr node,
xmlXPathContextPtr ctxt)
@@ -10844,6 +10881,26 @@ virDomainDefParseXML(virCapsPtr caps,
VIR_FREE(nodes);
}
+ def->nvram = NULL;
+ if ((n = virXPathNodeSet("./devices/nvram", ctxt, &nodes)) < 0) {
+ goto error;
+ }
+
+ if (n > 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("only a single nvram device is supported"));
+ goto error;
+ }
+
+ if (n > 0) {
+ virDomainNVRAMDefPtr nvram =
+ virDomainNVRAMDefParseXML(nodes[0], flags);
+ if (!nvram)
+ goto error;
+ def->nvram = nvram;
+ VIR_FREE(nodes);
+ }
+
/* analysis of the hub devices */
if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0) {
goto error;
@@ -13854,6 +13911,21 @@ virDomainMemballoonDefFormat(virBufferPtr buf,
}
static int
+virDomainNVRAMDefFormat(virBufferPtr buf,
+ virDomainNVRAMDefPtr def,
+ unsigned int flags)
+{
+ virBufferAsprintf(buf, " <nvram>\n");
+ if (virDomainDeviceInfoIsSet(&def->info, flags))
+ if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
+ return -1;
+
+ virBufferAddLit(buf, " </nvram>\n");
+
+ return 0;
+}
+
+static int
virDomainSysinfoDefFormat(virBufferPtr buf,
virSysinfoDefPtr def)
{
@@ -15161,6 +15233,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
if (def->rng)
virDomainRNGDefFormat(buf, def->rng, flags);
+ if (def->nvram)
+ virDomainNVRAMDefFormat(buf, def->nvram, flags);
+
virBufferAddLit(buf, " </devices>\n");
virBufferAdjustIndent(buf, 2);
@@ -16443,6 +16518,7 @@ virDomainDeviceDefCopy(virCapsPtr caps,
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_CHR:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
+ case VIR_DOMAIN_DEVICE_NVRAM:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Copying definition of '%d' type "
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 96f11ba..03b7c9a 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -108,6 +108,9 @@ typedef virDomainChrDef *virDomainChrDefPtr;
typedef struct _virDomainMemballoonDef virDomainMemballoonDef;
typedef virDomainMemballoonDef *virDomainMemballoonDefPtr;
+typedef struct _virDomainNVRAMDef virDomainNVRAMDef;
+typedef virDomainNVRAMDef *virDomainNVRAMDefPtr;
+
typedef struct _virDomainSnapshotObj virDomainSnapshotObj;
typedef virDomainSnapshotObj *virDomainSnapshotObjPtr;
@@ -136,6 +139,7 @@ typedef enum {
VIR_DOMAIN_DEVICE_SMARTCARD,
VIR_DOMAIN_DEVICE_CHR,
VIR_DOMAIN_DEVICE_MEMBALLOON,
+ VIR_DOMAIN_DEVICE_NVRAM,
VIR_DOMAIN_DEVICE_RNG,
VIR_DOMAIN_DEVICE_LAST
@@ -162,6 +166,7 @@ struct _virDomainDeviceDef {
virDomainSmartcardDefPtr smartcard;
virDomainChrDefPtr chr;
virDomainMemballoonDefPtr memballoon;
+ virDomainNVRAMDefPtr nvram;
virDomainRNGDefPtr rng;
} data;
};
@@ -1423,6 +1428,9 @@ struct _virDomainMemballoonDef {
virDomainDeviceInfo info;
};
+struct _virDomainNVRAMDef {
+ virDomainDeviceInfo info;
+};
enum virDomainSmbiosMode {
VIR_DOMAIN_SMBIOS_NONE = 0,
@@ -1883,6 +1891,7 @@ struct _virDomainDef {
/* Only 1 */
virDomainWatchdogDefPtr watchdog;
virDomainMemballoonDefPtr memballoon;
+ virDomainNVRAMDefPtr nvram;
virCPUDefPtr cpu;
virSysinfoDefPtr sysinfo;
virDomainRedirFilterDefPtr redirfilter;
@@ -2015,6 +2024,7 @@ int virDomainChrSourceDefCopy(virDomainChrSourceDefPtr src,
void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def);
void virDomainSoundDefFree(virDomainSoundDefPtr def);
void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def);
+void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def);
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def);
void virDomainVideoDefFree(virDomainVideoDefPtr def);
virDomainHostdevDefPtr virDomainHostdevDefAlloc(void);
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 4891b65..26c3001 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1169,6 +1169,15 @@ int qemuDomainAssignSpaprVIOAddresses(virDomainDefPtr def,
goto cleanup;
}
+ if (def->nvram) {
+ if (def->os.arch == VIR_ARCH_PPC64 &&
+ STREQ(def->os.machine, "pseries"))
+ def->nvram->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO;
+ if (qemuAssignSpaprVIOAddress(def, &def->nvram->info,
+ 0x3000ul) < 0)
+ goto cleanup;
+ }
+
/* No other devices are currently supported on spapr-vio */
ret = 0;
@@ -3809,6 +3818,32 @@ error:
return NULL;
}
+char *
+qemuBuildNVRAMDevStr(virDomainNVRAMDefPtr dev)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (dev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO &&
+ dev->info.addr.spaprvio.has_reg) {
+ virBufferAsprintf(&buf, "spapr-nvram.reg=0x%llx",
+ dev->info.addr.spaprvio.reg);
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("NVRAM device address is not supported.\n"));
+ goto error;
+ }
+
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ goto error;
+ }
+
+ return virBufferContentAndReset(&buf);
+
+error:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
char *
qemuBuildUSBInputDevStr(virDomainInputDefPtr dev,
@@ -7492,6 +7527,21 @@ qemuBuildCommandLine(virConnectPtr conn,
goto error;
}
+ if (def->nvram) {
+ if (def->os.arch == VIR_ARCH_PPC64 &&
+ STREQ(def->os.machine, "pseries")) {
+ char *optstr;
+ virCommandAddArg(cmd, "-global");
+ optstr = qemuBuildNVRAMDevStr(def->nvram);
+ if (!optstr)
+ goto error;
+ if (optstr)
+ virCommandAddArg(cmd, optstr);
+ VIR_FREE(optstr);
+ } else
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("NVRAM device is not supported"));
+ }
if (snapshot)
virCommandAddArgList(cmd, "-loadvm", snapshot->def->name, NULL);
@@ -9584,6 +9634,23 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr qemuCaps,
goto error;
}
+ } else if (STREQ(arg, "-global") &&
+ STRPREFIX(progargv[i + 1], "spapr-nvram.reg=")) {
+
+ WANT_VALUE();
+
+ if (VIR_ALLOC(def->nvram) < 0)
+ goto no_memory;
+
+ val += strlen("spapr-nvram.reg=");
+ if (virStrToLong_ull(val, NULL, 16,
+ &def->nvram->info.addr.spaprvio.reg) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("invalid value for spapr-nvram.reg :"
+ "'%s'"), val);
+ goto error;
+ }
+
} else if (STREQ(arg, "-S")) {
/* ignore, always added by libvirt */
} else {
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 17687f4..2b60997 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -118,6 +118,8 @@ char * qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev,
char * qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev,
virQEMUCapsPtr qemuCaps);
+char * qemuBuildNVRAMDevStr(virDomainNVRAMDefPtr dev);
+
char * qemuBuildUSBInputDevStr(virDomainInputDefPtr dev,
virQEMUCapsPtr qemuCaps);
--
1.7.10.1
11 years, 8 months