[libvirt] [PATCH] 0/4 Add SMBIOS settings to domain definition
by Daniel Veillard
The SMBIOS data are a standardized set of data structures available
in the BIOS area of PCs. Those blocks of data describe things like
BIOS version informations, machine vendor, model and identifiers,
as well as various parts of the machine capability. On a linux
machine running dmidecode allows to dump those informations.
Spec available at the DMTF: http://dmtf.org/standards/smbios
From a virtualization POV, it's mostly the first block describing
the BIOS named "type 0" and the second block describing the machine
named "type 1" which are of interest. Those data are usually accessed
either from the OS or from management application, and being able to
override the default setings may be needed for such management.
The suggested XML description follows the logical structure of the
data, one top smbios description, with one or more blocks, each
containing the entries, the example below gives an idea:
<smbios>
<table type="0">
<entry name="Vendor">QEmu/KVM</entry>
<entry name="Version">0.13</entry>
</table>
<table type="1">
<entry name="Manufacturer">Fedora</entry>
<entry name="Product">Virt-Manager</entry>
<entry name="Version">0.8.2-3.fc14</entry>
<entry name="UUID">c7a5fdbdedaf9455926ad65c16db1809</entry>
</table>
</smbios>
The patch serie includes:
- the change to the doamin schemas
- the code to parse this in config structure
- the QEmu driver part
- a test example
Currently missing is the conf code to save the data back, and
documentation for the domain extension. I think it's possible
set some of those settings in Xen too, but I don't know if I will
take the time of a driver for it. For ESX it seems there is an option
to inherit some of the SMBIOS data from the host on the guest but
I'm not sure some of the fields can be manipulated directly. I don't
know what VirtualBox can set there either,
Daniel
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel(a)veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
14 years
[libvirt] [PATCH V2] virsh: rework command parsing
by Lai Jiangshan
Old virsh command parsing mashes all the args back into a string and
miss the quotes, this patch fixes it. It is also needed for introducing
qemu-monitor-command which is very useful.
This patch split the command-parsing into 2 phrases:
1) parse command string and make it into <args, argv> style arguments.
2) parse <args, argv> style arguments and make it into vshCmd structure.
The first step is needed when we use virsh as a shell.
And the usage was changed:
old:
virsh [options] [commands]
new:
virsh [options]... [<command_name> args...]
virsh [options]... <command_string>
So we still support commands like:
# virsh "define D.xml; dumpxml D"
"define D.xml; dumpxml D" was parsed as a commands-string.
and support commands like:
# virsh qemu-monitor-command f13guest "info cpus"
we will not mash them into a string, we just skip the step 1 parsing
and goto the step 2 parsing directly.
But we don't support the command like:
# virsh "define D.xml; dumpxml" D
"define D.xml; dumpxml" was parsed as a command-name, but we have no such command-name.
Misc changed behavior:
1) support escape '\'
2) a better quoting support, the following commands are now supported:
virsh # dumpxml --"update-cpu" vm1
virsh # dumpxml --update-cpu vm"1"
3) better handling the boolean options, in old code the following commands are equivalent:
virsh # dumpxml --update-cpu=vm1
virsh # dumpxml --update-cpu vm1
after this patch applied, the first one will become illegal.
The idea of this patch is from Daniel P. Berrange.
changed from V1:
changed the usage as Eric Blake suggested.
Signed-off-by: Lai Jiangshan <laijs(a)cn.fujitsu.com>
---
virsh.c | 351 ++++++++++++++++++++++++++++++----------------------------------
1 file changed, 170 insertions(+), 181 deletions(-)
--- libvirt-0.8.4.old/tools/virsh.c 2010-09-10 20:47:06.000000000 +0800
+++ libvirt-0.8.4/tools/virsh.c 2010-09-16 17:13:55.000000000 +0800
@@ -10162,90 +10162,166 @@ vshCommandRun(vshControl *ctl, const vsh
* Command string parsing
* ---------------
*/
-#define VSH_TK_ERROR -1
-#define VSH_TK_NONE 0
-#define VSH_TK_OPTION 1
-#define VSH_TK_DATA 2
-#define VSH_TK_END 3
-static int
-vshCommandGetToken(vshControl *ctl, char *str, char **end, char **res)
+static char *
+vshCmdStrGetArg(vshControl *ctl, char *str, char **end, int *last_arg)
{
- int tk = VSH_TK_NONE;
- int quote = FALSE;
- int sz = 0;
+ int quote = 0;
char *p = str;
- char *tkstr = NULL;
+ char *argstr = NULL;
+ char *res = NULL;
*end = NULL;
+ *last_arg = 0;
while (p && *p && (*p == ' ' || *p == '\t'))
p++;
if (p == NULL || *p == '\0')
- return VSH_TK_END;
+ return NULL;
+
if (*p == ';') {
- *end = ++p; /* = \0 or begin of next command */
- return VSH_TK_END;
+ *end = p + 1; /* = \0 or begin of next command */
+ return NULL;
}
+
+ res = argstr = p;
while (*p) {
- /* end of token is blank space or ';' */
- if ((quote == FALSE && (*p == ' ' || *p == '\t')) || *p == ';')
+ if (*p == '\\') { /* escape */
+ p++;
+ if (*p == '\0')
+ break;
+ } else if (*p == '"') { /* quote */
+ quote = !quote;
+ p++;
+ continue;
+ } else if ((!quote && (*p == ' ' || *p == '\t')) || *p == ';')
break;
- /* end of option name could be '=' */
- if (tk == VSH_TK_OPTION && *p == '=') {
- p++; /* skip '=' */
- break;
- }
+ *argstr++ = *p++;
+ }
+
+ if (*p != '\0') {
+ if (*p == ';')
+ *last_arg = 1;
+ *end = p + 1; /* skip the \0 braught by *argstr = '\0' */
+ } else
+ *end = p;
+ *argstr = '\0';
+
+ if (quote) {
+ vshError(ctl, "%s", _("missing \""));
+ return NULL;
+ }
+
+ return res;
+}
- if (tk == VSH_TK_NONE) {
- if (*p == '-' && *(p + 1) == '-' && *(p + 2)
+static vshCmd *
+vshCommandParseArgv(vshControl *ctl, int args, char *argv[])
+{
+ vshCmdOpt *first = NULL, *last = NULL;
+ const vshCmdDef *cmd;
+ vshCmd *c;
+ int i;
+ int data_ct = 0;
+
+ if (!(cmd = vshCmddefSearch(argv[0]))) {
+ vshError(ctl, _("unknown command: '%s'"), argv[0]);
+ goto syntaxError; /* ... or ignore this command only? */
+ }
+
+ for (i = 1; i < args; i++) {
+ vshCmdOpt *arg;
+ const vshCmdOptDef *opt;
+ char *p, *q;
+
+ p = vshStrdup(ctl, argv[i]);
+ if (*p == '-' && *(p + 1) == '-' && *(p + 2)
&& c_isalnum(*(p + 2))) {
- tk = VSH_TK_OPTION;
- p += 2;
- } else {
- tk = VSH_TK_DATA;
- if (*p == '"') {
- quote = TRUE;
- p++;
- } else {
- quote = FALSE;
+ q = strchr(p + 2, '=');
+ if (q) {
+ *q = '\0';
+ q = vshStrdup(ctl, q + 1);
+ }
+
+ if (!(opt = vshCmddefGetOption(cmd, p + 2))) {
+ vshError(ctl,
+ _("command '%s' doesn't support option --%s"),
+ cmd->name, p);
+ VIR_FREE(p);
+ VIR_FREE(q);
+ goto syntaxError;
+ }
+ VIR_FREE(p);
+
+ if (opt->type == VSH_OT_BOOL) {
+ if (q) {
+ vshError(ctl, _("invalid '=' after option --%s"),
+ opt->name);
+ VIR_FREE(q);
+ goto syntaxError;
}
+ } else if (!q) {
+ i++;
+ if (i == args) {
+ vshError(ctl,
+ _("expected syntax: --%s <%s>"),
+ opt->name,
+ opt->type ==
+ VSH_OT_INT ? _("number") : _("string"));
+ goto syntaxError;
+ }
+ q = vshStrdup(ctl, argv[i]);
+ }
+ } else {
+ q = p;
+ if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
+ vshError(ctl, _("unexpected data '%s'"), q);
+ VIR_FREE(q);
+ goto syntaxError;
}
- tkstr = p; /* begin of token */
- } else if (quote && *p == '"') {
- quote = FALSE;
- p++;
- break; /* end of "..." token */
}
- p++;
- sz++;
+
+ arg = vshMalloc(ctl, sizeof(vshCmdOpt));
+ arg->def = opt;
+ arg->data = q;
+ arg->next = NULL;
+
+ if (!first)
+ first = arg;
+ if (last)
+ last->next = arg;
+ last = arg;
+
+ vshDebug(ctl, 4, "%s: %s(%s): %s\n", cmd->name, opt->name,
+ arg->data != p ? _("OPTION") : _("DATA"), arg->data);
}
- if (quote) {
- vshError(ctl, "%s", _("missing \""));
- return VSH_TK_ERROR;
+
+ c = vshMalloc(ctl, sizeof(vshCmd));
+
+ c->opts = first;
+ c->def = cmd;
+ c->next = NULL;
+
+ if (!vshCommandCheckOpts(ctl, c)) {
+ VIR_FREE(c);
+ goto syntaxError;
}
- if (tkstr == NULL || *tkstr == '\0' || p == NULL)
- return VSH_TK_END;
- if (sz == 0)
- return VSH_TK_END;
-
- *res = vshMalloc(ctl, sz + 1);
- memcpy(*res, tkstr, sz);
- *(*res + sz) = '\0';
+ return c;
- *end = p;
- return tk;
+syntaxError:
+ if (first)
+ vshCommandOptFree(first);
+ return NULL;
}
+
static int
vshCommandParse(vshControl *ctl, char *cmdstr)
{
char *str;
- char *tkdata = NULL;
vshCmd *clast = NULL;
- vshCmdOpt *first = NULL;
if (ctl->cmd) {
vshCommandFree(ctl->cmd);
@@ -10257,130 +10333,42 @@ vshCommandParse(vshControl *ctl, char *c
str = cmdstr;
while (str && *str) {
- vshCmdOpt *last = NULL;
- const vshCmdDef *cmd = NULL;
- int tk = VSH_TK_NONE;
- int data_ct = 0;
-
- first = NULL;
-
- while (tk != VSH_TK_END) {
- char *end = NULL;
- const vshCmdOptDef *opt = NULL;
-
- tkdata = NULL;
-
- /* get token */
- tk = vshCommandGetToken(ctl, str, &end, &tkdata);
-
- str = end;
-
- if (tk == VSH_TK_END) {
- VIR_FREE(tkdata);
- break;
- }
- if (tk == VSH_TK_ERROR)
+ vshCmd *c;
+ int args = 0;
+ char *argv[20];
+ char *arg;
+ int last_arg = 0;
+
+ while ((arg = vshCmdStrGetArg(ctl, str, &str, &last_arg)) != NULL) {
+ if (args == sizeof(argv) / sizeof(argv[0])) {
+ vshError(ctl, _("too many args"));
goto syntaxError;
-
- if (cmd == NULL) {
- /* first token must be command name */
- if (tk != VSH_TK_DATA) {
- vshError(ctl,
- _("unexpected token (command name): '%s'"),
- tkdata);
- goto syntaxError;
- }
- if (!(cmd = vshCmddefSearch(tkdata))) {
- vshError(ctl, _("unknown command: '%s'"), tkdata);
- goto syntaxError; /* ... or ignore this command only? */
- }
- VIR_FREE(tkdata);
- } else if (tk == VSH_TK_OPTION) {
- if (!(opt = vshCmddefGetOption(cmd, tkdata))) {
- vshError(ctl,
- _("command '%s' doesn't support option --%s"),
- cmd->name, tkdata);
- goto syntaxError;
- }
- VIR_FREE(tkdata); /* option name */
-
- if (opt->type != VSH_OT_BOOL) {
- /* option data */
- tk = vshCommandGetToken(ctl, str, &end, &tkdata);
- str = end;
- if (tk == VSH_TK_ERROR)
- goto syntaxError;
- if (tk != VSH_TK_DATA) {
- vshError(ctl,
- _("expected syntax: --%s <%s>"),
- opt->name,
- opt->type ==
- VSH_OT_INT ? _("number") : _("string"));
- goto syntaxError;
- }
- }
- } else if (tk == VSH_TK_DATA) {
- if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
- vshError(ctl, _("unexpected data '%s'"), tkdata);
- goto syntaxError;
- }
- }
- if (opt) {
- /* save option */
- vshCmdOpt *arg = vshMalloc(ctl, sizeof(vshCmdOpt));
-
- arg->def = opt;
- arg->data = tkdata;
- arg->next = NULL;
- tkdata = NULL;
-
- if (!first)
- first = arg;
- if (last)
- last->next = arg;
- last = arg;
-
- vshDebug(ctl, 4, "%s: %s(%s): %s\n",
- cmd->name,
- opt->name,
- tk == VSH_TK_OPTION ? _("OPTION") : _("DATA"),
- arg->data);
}
- if (!str)
+ argv[args++] = arg;
+ if (last_arg)
break;
}
+ if (args == 0)
+ continue;
- /* command parsed -- allocate new struct for the command */
- if (cmd) {
- vshCmd *c = vshMalloc(ctl, sizeof(vshCmd));
-
- c->opts = first;
- c->def = cmd;
- c->next = NULL;
-
- if (!vshCommandCheckOpts(ctl, c)) {
- VIR_FREE(c);
- goto syntaxError;
- }
-
- if (!ctl->cmd)
- ctl->cmd = c;
- if (clast)
- clast->next = c;
- clast = c;
- }
+ c = vshCommandParseArgv(ctl, args, argv);
+ if (!c)
+ goto syntaxError;
+
+ if (!ctl->cmd)
+ ctl->cmd = c;
+ if (clast)
+ clast->next = c;
+ clast = c;
}
return TRUE;
- syntaxError:
+syntaxError:
if (ctl->cmd) {
vshCommandFree(ctl->cmd);
ctl->cmd = NULL;
}
- if (first)
- vshCommandOptFree(first);
- VIR_FREE(tkdata);
return FALSE;
}
@@ -10939,7 +10927,8 @@ static void
vshUsage(void)
{
const vshCmdDef *cmd;
- fprintf(stdout, _("\n%s [options] [commands]\n\n"
+ fprintf(stdout, _("\n%s [options]... [<command_name> args...]"
+ "\n%s [options]... <command_string>\n\n"
" options:\n"
" -c | --connect <uri> hypervisor connection URI\n"
" -r | --readonly connect readonly\n"
@@ -10949,7 +10938,7 @@ vshUsage(void)
" -t | --timing print timing information\n"
" -l | --log <file> output logging to file\n"
" -v | --version program version\n\n"
- " commands (non interactive mode):\n"), progname);
+ " commands (non interactive mode):\n"), progname, progname);
for (cmd = commands; cmd->name; cmd++)
fprintf(stdout,
@@ -11069,25 +11058,25 @@ vshParseArgv(vshControl *ctl, int argc,
if (argc > end) {
/* parse command */
- char *cmdstr;
- int sz = 0, ret;
+ int ret = TRUE;
ctl->imode = FALSE;
- for (i = end; i < argc; i++)
- sz += strlen(argv[i]) + 1; /* +1 is for blank space between items */
-
- cmdstr = vshCalloc(ctl, sz + 1, 1);
-
- for (i = end; i < argc; i++) {
- strncat(cmdstr, argv[i], sz);
- sz -= strlen(argv[i]);
- strncat(cmdstr, " ", sz--);
+ if (argc - end == 1) {
+ char *cmdstr = vshStrdup(ctl, argv[end]);
+ vshDebug(ctl, 2, "commands: \"%s\"\n", cmdstr);
+ ret = vshCommandParse(ctl, cmdstr);
+ VIR_FREE(cmdstr);
+ } else {
+ if (ctl->cmd) {
+ vshCommandFree(ctl->cmd);
+ ctl->cmd = NULL;
+ }
+ ctl->cmd = vshCommandParseArgv(ctl, argc - end, argv + end);
+ if (!ctl->cmd)
+ ret = FALSE;
}
- vshDebug(ctl, 2, "command: \"%s\"\n", cmdstr);
- ret = vshCommandParse(ctl, cmdstr);
- VIR_FREE(cmdstr);
return ret;
}
return TRUE;
14 years
[libvirt] [PATCH] qemu: record timestamps in qemu guest log
by Osier Yang
Currently only record timestamps for domain start and shutdown, for
domain start, record timestamps before qemu command line, for domain
shutdown, just says it's shutting down.
* src/qemu/qemu_driver.c (qemudStartVMDaemon, qemudShutdownVMDaemon)
---
src/qemu/qemu_driver.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 60 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1eea3a9..89b4d11 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3828,6 +3828,10 @@ static int qemudStartVMDaemon(virConnectPtr conn,
char ebuf[1024];
char *pidfile = NULL;
int logfile = -1;
+ struct timeval cur_time;
+ struct tm time_info;
+ char timestr[100];
+ char *timestamp;
qemuDomainObjPrivatePtr priv = vm->privateData;
struct qemudHookData hookData;
@@ -4015,7 +4019,27 @@ static int qemudStartVMDaemon(virConnectPtr conn,
goto cleanup;
}
+ gettimeofday(&cur_time, NULL);
+ localtime_r(&cur_time.tv_sec, &time_info);
+
+ strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", &time_info);
+
+ if (virAsprintf(×tamp, "%s.%3d: ",
+ timestr, (int) cur_time.tv_usec / 1000) < 0) {
+ VIR_FREE(timestamp);
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (safewrite(logfile, timestamp, strlen(timestamp)) < 0) {
+ VIR_WARN("Unable to write timestamp to logfile: %s",
+ virStrerror(errno, ebuf, sizeof ebuf));
+ }
+
+ VIR_FREE(timestamp);
+
tmp = progenv;
+
while (*tmp) {
if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
VIR_WARN("Unable to write envv to logfile: %s",
@@ -4166,7 +4190,6 @@ cleanup:
return -1;
}
-
static void qemudShutdownVMDaemon(struct qemud_driver *driver,
virDomainObjPtr vm,
int migrated) {
@@ -4176,6 +4199,42 @@ static void qemudShutdownVMDaemon(struct qemud_driver *driver,
virErrorPtr orig_err;
virDomainDefPtr def;
int i;
+ int logfile = -1;
+ char timestr[100];
+ char *timestamp;
+ char ebuf[1024];
+ struct timeval cur_time;
+ struct tm time_info;
+
+ VIR_DEBUG0("Creating domain log file");
+ if ((logfile = qemudLogFD(driver, vm->def->name)) < 0) {
+ /* To not break the normal domain shutdown process, skip the
+ * timestamp log writing if failed on opening log file. */
+ VIR_WARN("Unable to open logfile: %s",
+ virStrerror(errno, ebuf, sizeof ebuf));
+ } else {
+ gettimeofday(&cur_time, NULL);
+ localtime_r(&cur_time.tv_sec, &time_info);
+
+ strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", &time_info);
+
+ if (virAsprintf(×tamp, "%s.%3d: shutting down\n",
+ timestr, (int) cur_time.tv_usec / 1000) < 0) {
+ VIR_FREE(timestamp);
+ virReportOOMError();
+ }
+
+ if (close(logfile) < 0)
+ VIR_WARN("Unable to close logfile: %s",
+ virStrerror(errno, ebuf, sizeof ebuf));
+ }
+
+ if (safewrite(logfile, timestamp, strlen(timestamp)) < 0) {
+ VIR_WARN("Unable to write timestamp to logfile: %s",
+ virStrerror(errno, ebuf, sizeof ebuf));
+ }
+
+ VIR_FREE(timestamp);
VIR_DEBUG("Shutting down VM '%s' pid=%d migrated=%d",
vm->def->name, vm->pid, migrated);
@@ -4315,7 +4374,6 @@ retry:
}
}
-
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED) {
--
1.7.2.3
14 years
[libvirt] Allow nbd-backed disk images?
by Adam Litke
I am trying to use a qcow image with libvirt where the backing 'file' is
a qemu-nbd server. Unfortunately the security code assumes that
backingStore is always a real file so something like 'nbd:0:3333' is
rejected because a file with that name cannot be accessed. A simple
patch like the following works around the problem -- are there any
suggestions on how to do this properly? Note that I am not worried
about directly using nbd images. That would require a new disk type
with XML markup, etc. I only want it to be permitted as a backingStore.
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
index 6f48b10..7c0ea9a 100644
--- a/src/util/storage_file.c
+++ b/src/util/storage_file.c
@@ -292,6 +292,13 @@ qcowXGetBackingStore(char **res,
return BACKING_STORE_INVALID;
if (size + 1 == 0)
return BACKING_STORE_INVALID;
+
+ /* Short-circuit nbd backing files */
+ if (size >= 4 && STRPREFIX((const char *)(buf + offset), "nbd:")) {
+ return BACKING_STORE_OK;
+ }
+
if (VIR_ALLOC_N(*res, size + 1) < 0) {
virReportOOMError();
return BACKING_STORE_ERROR;
--
Thanks,
Adam
14 years
[libvirt] Changing the default for qcow2 creation
by Matthew Booth
I've recently been investigating a severe performance issue I noticed
when writing to a qcow2-backed image. When virt-v2v is doing a format
conversion from raw to qcow2, it does the following:
1. Create a new qcow2 image
2. Launch a libguestfs appliance (kvm) using the new image
3. Write the source raw data to the appliance's block device
I noticed that the same process writing to a raw image rather than a
qcow2 image was adequately fast, and decided to do some testing. I've
attached my simple test program.[1] It does the following:
1. Start an appliance with test.img as a disk.
2. Format test.img with ext2.
3. Create a file /test
4. Write 256M of data to /test in 2M chunks
Only step 4 is timed. I ran the program against test.img prepared in 4
different ways:
1. A sparse raw file: 15.3 seconds
truncate --size 300M test.img
2. A preallocated raw file: 14.8 seconds
fallocate -l 300M test.img
3. A sparse qcow2 file: 223.0 seconds
qemu-img create -f qcow2 test.img 300M
4. A metadata preallocated qcow2 file: 14.5 seconds
qemu-img create -f qcow2 -o preallocated=metadata test.img 300M
With the exception of (3), I ran the test 3 times and took the middle
time rounded to 1DP. I saw about 5-10% variation. I only ran the test
against (3) once.
The precise ordering of 1, 2 and 4 is surprising, but given the
variation probably not that interesting: they're all about the same. The
interesting thing is that the overhead of qcow2 metadata creation during
the test seems to account for a 15x performance penalty.
I had a cursory look at metadata preallocation, which I hadn't been
aware of before today. Creating a qcow2 image of any size with no
preallocation results in a 136k file. If you preallocate the metadata, a
sparse file is created large enough to accomodate the entire image, with
>136k actually used. In the above 300M case this is 204k. On a slightly
more practical 20G image, 3.3M is preallocated. It's also worth noting
that the image takes considerably longer to create. On my laptop,
creation without preallocation is 'instantaneous' at any size. With
preallocation, a 20G image takes 6 seconds to create, and a 100G image
takes 26 seconds.
libvirt's qemu driver doesn't currently preallocate qcow2 metadata when
creating a new image. Given the tiny disk space overhead of the metadata
(0.02%) and the small processing overhead of pre-creation relative to
subsequent creation on-the-fly, I suggest that the libvirt qemu driver
is updated to pre-allocate metadata by default.
Thoughts?
Matt
[1] Note that I'm running this against libguestfs from git, which uses
virtio-serial rather than usermode networking for appliance<->host
communication. This change alone improved the performance of this test
by about 10x. If your numbers don't match mine, that's probably why. I
don't know off the top of my head if this change has made it into F14
yet. It's definitely not in F13.
--
Matthew Booth, RHCA, RHCSS
Red Hat Engineering, Virtualisation Team
GPG ID: D33C3490
GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
14 years
[libvirt] [PATCH] xen: work with ia64 MAX_VIRT_CPUS of 64
by Eric Blake
* src/xen/xen_hypervisor.c (MAX_VIRT_CPUS): Move...
* src/xen/xen_driver.h (MAX_VIRT_CPUS): ...so all xen code can see
same value.
* src/xen/xend_internal.c (sexpr_to_xend_domain_info)
(xenDaemonDomainGetVcpusFlags, xenDaemonParseSxpr)
(xenDaemonFormatSxpr): Work if MAX_VIRT_CPUS is 64 on a platform
where long is 64-bits.
* src/xen/xm_internal.c (xenXMDomainConfigParse)
(xenXMDomainConfigFormat): Likewise.
---
On at least the xen/stable branch of
git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git
we have the case where MAX_VIRT_CPUS is 32 for x86 but 64 for ia64.
That branch does not have XEN_LEGACY_MAX_VCPUS. But according
to our comments, other branches had only XEN_LEGACY_MAX_VCPUS,
which means that xm_internal.c would fail to compile without this
patch, when targetting xen headers that lack MAX_VIRT_CPUS.
src/xen/xen_driver.h | 8 ++++++++
src/xen/xen_hypervisor.c | 8 --------
src/xen/xend_internal.c | 17 +++++++++--------
src/xen/xm_internal.c | 9 +++++----
4 files changed, 22 insertions(+), 20 deletions(-)
diff --git a/src/xen/xen_driver.h b/src/xen/xen_driver.h
index 53f97d4..16d22f1 100644
--- a/src/xen/xen_driver.h
+++ b/src/xen/xen_driver.h
@@ -29,6 +29,14 @@
# include <winsock2.h>
# endif
+/* xen-unstable changeset 19788 removed MAX_VIRT_CPUS from public
+ * headers. Its semantic was retained with XEN_LEGACY_MAX_VCPUS.
+ * Ensure MAX_VIRT_CPUS is defined accordingly.
+ */
+# if !defined(MAX_VIRT_CPUS) && defined(XEN_LEGACY_MAX_VCPUS)
+# define MAX_VIRT_CPUS XEN_LEGACY_MAX_VCPUS
+# endif
+
extern int xenRegister (void);
# define XEN_UNIFIED_HYPERVISOR_OFFSET 0
diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c
index 3797865..ec726fe 100644
--- a/src/xen/xen_hypervisor.c
+++ b/src/xen/xen_hypervisor.c
@@ -109,14 +109,6 @@ typedef privcmd_hypercall_t hypercall_t;
# define SYS_IFACE_MIN_VERS_NUMA 4
#endif
-/* xen-unstable changeset 19788 removed MAX_VIRT_CPUS from public
- * headers. Its semanitc was retained with XEN_LEGACY_MAX_VCPUS.
- * Ensure MAX_VIRT_CPUS is defined accordingly.
- */
-#if !defined(MAX_VIRT_CPUS) && defined(XEN_LEGACY_MAX_VCPUS)
-# define MAX_VIRT_CPUS XEN_LEGACY_MAX_VCPUS
-#endif
-
static int xen_ioctl_hypercall_cmd = 0;
static int initialized = 0;
static int in_init = 0;
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
index 974e96b..614c036 100644
--- a/src/xen/xend_internal.c
+++ b/src/xen/xend_internal.c
@@ -2192,7 +2192,7 @@ xenDaemonParseSxpr(virConnectPtr conn,
}
def->maxvcpus = sexpr_int(root, "domain/vcpus");
- def->vcpus = count_one_bits(sexpr_int(root, "domain/vcpu_avail"));
+ def->vcpus = count_one_bits_l(sexpr_u64(root, "domain/vcpu_avail"));
if (!def->vcpus || def->maxvcpus < def->vcpus)
def->vcpus = def->maxvcpus;
@@ -2468,7 +2468,7 @@ sexpr_to_xend_domain_info(virDomainPtr domain, const struct sexpr *root,
}
info->cpuTime = sexpr_float(root, "domain/cpu_time") * 1000000000;
vcpus = sexpr_int(root, "domain/vcpus");
- info->nrVirtCpu = count_one_bits(sexpr_int(root, "domain/vcpu_avail"));
+ info->nrVirtCpu = count_one_bits_l(sexpr_u64(root, "domain/vcpu_avail"));
if (!info->nrVirtCpu || vcpus < info->nrVirtCpu)
info->nrVirtCpu = vcpus;
@@ -3706,7 +3706,7 @@ xenDaemonDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
ret = sexpr_int(root, "domain/vcpus");
if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM)) {
- int vcpus = count_one_bits(sexpr_int(root, "domain/vcpu_avail"));
+ int vcpus = count_one_bits_l(sexpr_u64(root, "domain/vcpu_avail"));
if (vcpus)
ret = MIN(vcpus, ret);
}
@@ -5770,10 +5770,11 @@ xenDaemonFormatSxpr(virConnectPtr conn,
virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)",
def->mem.cur_balloon/1024, def->mem.max_balloon/1024);
virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
- /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is 32. */
- verify(MAX_VIRT_CPUS <= sizeof(1U) * CHAR_BIT);
+ /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is
+ either 32, or 64 on a platform where long is big enough. */
+ verify(MAX_VIRT_CPUS <= sizeof(1UL) * CHAR_BIT);
if (def->vcpus < def->maxvcpus)
- virBufferVSprintf(&buf, "(vcpu_avail %u)", (1U << def->vcpus) - 1);
+ virBufferVSprintf(&buf, "(vcpu_avail %lu)", (1UL << def->vcpus) - 1);
if (def->cpumask) {
char *ranges = virDomainCpuSetFormat(def->cpumask, def->cpumasklen);
@@ -5870,8 +5871,8 @@ xenDaemonFormatSxpr(virConnectPtr conn,
virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
if (def->vcpus < def->maxvcpus)
- virBufferVSprintf(&buf, "(vcpu_avail %u)",
- (1U << def->vcpus) - 1);
+ virBufferVSprintf(&buf, "(vcpu_avail %lu)",
+ (1UL << def->vcpus) - 1);
for (i = 0 ; i < def->os.nBootDevs ; i++) {
switch (def->os.bootDevs[i]) {
diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
index f80e252..6c5df0f 100644
--- a/src/xen/xm_internal.c
+++ b/src/xen/xm_internal.c
@@ -776,7 +776,7 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
def->maxvcpus = count;
if (xenXMConfigGetULong(conf, "vcpu_avail", &count, -1) < 0)
goto cleanup;
- def->vcpus = MIN(count_one_bits(count), def->maxvcpus);
+ def->vcpus = MIN(count_one_bits_l(count), def->maxvcpus);
if (xenXMConfigGetString(conf, "cpus", &str, NULL) < 0)
goto cleanup;
@@ -2336,10 +2336,11 @@ virConfPtr xenXMDomainConfigFormat(virConnectPtr conn,
if (xenXMConfigSetInt(conf, "vcpus", def->maxvcpus) < 0)
goto no_memory;
- /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is 32. */
- verify(MAX_VIRT_CPUS <= sizeof(1U) * CHAR_BIT);
+ /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is
+ either 32, or 64 on a platform where long is big enough. */
+ verify(MAX_VIRT_CPUS <= sizeof(1UL) * CHAR_BIT);
if (def->vcpus < def->maxvcpus &&
- xenXMConfigSetInt(conf, "vcpu_avail", (1U << def->vcpus) - 1) < 0)
+ xenXMConfigSetInt(conf, "vcpu_avail", (1UL << def->vcpus) - 1) < 0)
goto no_memory;
if ((def->cpumask != NULL) &&
--
1.7.2.3
14 years
[libvirt] [PATCH] [TCK] network: create networks and check for exected results
by Stefan Berger
Derived from the nwfilter test program, this one works with libvirt's
networks. It creates networks from provided xml files and checks for
expected configuration in iptables, running processes and virsh output
using provided data files with commands to execute and the expected
results for after creating the network and after tearing it down
(*.post.dat). 3 tests are currently not passing due to a bug in
libvirt...
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
---
Build.PL | 2
scripts/networks/100-apply-verify-host.t | 10
scripts/networks/networkApplyTest.sh | 343 +++++++++++++
scripts/networks/networkxml2hostout/tck-testnet-1.dat | 11
scripts/networks/networkxml2hostout/tck-testnet-1.post.dat | 4
scripts/networks/networkxml2hostout/tck-testnet-2.dat | 8
scripts/networks/networkxml2hostout/tck-testnet-2.post.dat | 4
scripts/networks/networkxml2xmlin/tck-testnet-1.xml | 12
scripts/networks/networkxml2xmlin/tck-testnet-2.xml | 12
9 files changed, 405 insertions(+), 1 deletion(-)
Index: libvirt-tck/scripts/networks/networkApplyTest.sh
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/networks/networkApplyTest.sh
@@ -0,0 +1,343 @@
+#!/bin/bash
+
+VIRSH=virsh
+
+uri=
+if [ "x${LIBVIRT_TCK_CONFIG}x" != "xx" ]; then
+ uri_exp=`cat ${LIBVIRT_TCK_CONFIG} | grep "^uri\s*=" | sed -e 's/uri\s*=\s*//' | tail -n 1`
+ if [ "x${uri_exp}x" != "xx" ]; then
+ eval "uri=${uri_exp}"
+ fi
+ if [ "x${uri}x" == "xx" ]; then
+ uri="qemu:///system"
+ fi
+else
+ uri="qemu:///system"
+fi
+LIBVIRT_URI=${uri}
+
+
+FLAG_WAIT="$((1<<0))"
+FLAG_VERBOSE="$((1<<2))"
+FLAG_LIBVIRT_TEST="$((1<<3))"
+FLAG_TAP_TEST="$((1<<4))"
+FLAG_FORCE_CLEAN="$((1<<5))"
+
+failctr=0
+passctr=0
+attachfailctr=0
+attachctr=0
+
+TAP_FAIL_LIST=""
+TAP_FAIL_CTR=0
+TAP_TOT_CTR=0
+
+function usage() {
+ local cmd="$0"
+cat <<EOF
+Usage: ${cmd} [--help|-h|-?] [--noattach] [--wait] [--verbose]
+ [--libvirt-test] [--tap-test]
+
+Options:
+ --help,-h,-? : Display this help screen.
+ --wait : Wait for the user to press the enter key once an error
+ was detected
+ --verbose : Verbose output
+ --libvirt-test : Use the libvirt test output format
+ --tap-test : TAP format output
+ --force : Allow the automatic cleaning of VMs and networks
+ previously created by the TCK test suite
+
+This test creates libvirt 'networks' and checks for expected results
+(iptables, running processes (dnsmasq)) using provided xml and data
+file respectively.
+EOF
+}
+
+
+function tap_fail() {
+ echo "not ok $1 - ${2:0:66}"
+ TAP_FAIL_LIST+="$1 "
+ ((TAP_FAIL_CTR++))
+ ((TAP_TOT_CTR++))
+}
+
+function tap_pass() {
+ echo "ok $1 - ${2:0:70}"
+ ((TAP_TOT_CTR++))
+}
+
+function tap_final() {
+ local okay
+
+ [ -n "${TAP_FAIL_LIST}" ] && echo "FAILED tests ${TAP_FAIL_LIST}"
+
+ okay=`echo "($TAP_TOT_CTR-$TAP_FAIL_CTR)*100/$TAP_TOT_CTR" | bc -l`
+ echo "Failed ${TAP_FAIL_CTR}/${TAP_TOT_CTR} tests, ${okay:0:5}% okay"
+}
+
+# A wrapper for mktemp in case it does not exist
+# Echos the name of a temporary file.
+function mktmpfile() {
+ local tmp
+ type -P mktemp > /dev/null
+ if [ $? -eq 0 ]; then
+ tmp=$(mktemp -t nwfvmtest.XXXXXX)
+ echo ${tmp}
+ else
+ while :; do
+ tmp="/tmp/nwfvmtest.${RANDOM}"
+ if [ ! -f ${tmp} ]; then
+ touch ${tmp}
+ chmod 666 ${tmp}
+ echo ${tmp}
+ break
+ fi
+ done
+ fi
+ return 0
+}
+
+
+function checkExpectedOutput() {
+ local xmlfile="$1"
+ local datafile="$2"
+ local flags="$3"
+ local skipregex="$4"
+ local cmd line tmpfile tmpfile2 skip
+
+ tmpfile=`mktmpfile`
+ tmpfile2=`mktmpfile`
+
+ exec 4<${datafile}
+
+ read <&4
+ line="${REPLY}"
+
+ while [ "x${line}x" != "xx" ]; do
+ cmd=`echo ${line##\#}`
+
+ skip=0
+ if [ "x${skipregex}x" != "xx" ]; then
+ skip=`echo ${cmd} | grep -c -E ${skipregex}`
+ fi
+
+ eval ${cmd} 2>&1 | tee ${tmpfile} 1>/dev/null
+
+ rm ${tmpfile2} 2>/dev/null
+ touch ${tmpfile2}
+
+ while [ 1 ]; do
+ read <&4
+ line="${REPLY}"
+
+ if [ "${line:0:1}" == "#" ] || [ "x${line}x" == "xx" ]; then
+
+ if [ ${skip} -ne 0 ]; then
+ break
+ fi
+
+ diff ${tmpfile} ${tmpfile2} >/dev/null
+
+ if [ $? -ne 0 ]; then
+ if [ $((flags & FLAG_VERBOSE)) -ne 0 ]; then
+ echo "FAIL ${xmlfile} : ${cmd}"
+ diff ${tmpfile} ${tmpfile2}
+ fi
+ ((failctr++))
+ if [ $((flags & FLAG_WAIT)) -ne 0 ]; then
+ echo "tmp files: $tmpfile, $tmpfile2"
+ echo "Press enter"
+ read
+ fi
+ [ $((flags & FLAG_LIBVIRT_TEST)) -ne 0 ] && \
+ test_result $((passctr+failctr)) "" 1
+ [ $((flags & FLAG_TAP_TEST)) -ne 0 ] && \
+ tap_fail $((passctr+failctr)) "${xmlfile} : ${cmd}"
+ else
+ ((passctr++))
+ [ $((flags & FLAG_VERBOSE)) -ne 0 ] && \
+ echo "PASS ${xmlfile} : ${cmd}"
+ [ $((flags & FLAG_LIBVIRT_TEST)) -ne 0 ] && \
+ test_result $((passctr+failctr)) "" 0
+ [ $((flags & FLAG_TAP_TEST)) -ne 0 ] && \
+ tap_pass $((passctr+failctr)) "${xmlfile} : ${cmd}"
+ fi
+
+ break
+
+ fi
+ echo "${line}" >> ${tmpfile2}
+ done
+ done
+
+ exec 4>&-
+
+ rm -rf "${tmpfile}" "${tmpfile2}" 2>/dev/null
+}
+
+
+function doTest() {
+ local xmlfile="$1"
+ local datafile="$2"
+ local postdatafile="$3"
+ local flags="$4"
+ local netname
+
+ if [ ! -r "${xmlfile}" ]; then
+ echo "FAIL : Cannot access filter XML file ${xmlfile}."
+ return 1
+ fi
+
+ netname=`cat "${xmlfile}" | sed -n 's/.*<name>\([[:print:]]*\)<.*/\1/p'`
+
+ ${VIRSH} net-create "${xmlfile}" > /dev/null
+
+ checkExpectedOutput "${xmlfile}" "${datafile}" "${flags}" ""
+
+ ${VIRSH} net-destroy "${netname}" > /dev/null
+
+ if [ -r ${postdatafile} ]; then
+ checkExpectedOutput "${xmlfile}" "${postdatafile}" "${flags}" ""
+ fi
+
+ return 0
+}
+
+
+function runTests() {
+ local xmldir="$1"
+ local hostoutdir="$2"
+ local flags="$3"
+ local datafiles f c
+ local tap_total=0 ctr=0
+
+ pushd ${PWD} > /dev/null
+ cd ${hostoutdir}
+ datafiles=`ls *.dat`
+ popd > /dev/null
+
+ if [ $((flags & FLAG_TAP_TEST)) -ne 0 ]; then
+ # Need to count the number of total tests
+ for fil in ${datafiles}; do
+ c=$(grep -c "^#" ${hostoutdir}/${fil})
+ ((tap_total+=c))
+ ((ctr++))
+ done
+ echo "1..${tap_total}"
+ fi
+
+ for fil in `echo "${datafiles}" | grep -v "\.post\.dat$"`; do
+ f=${fil%%.dat}
+ doTest "${xmldir}/${f}.xml" "${hostoutdir}/${fil}" \
+ "${hostoutdir}/${f}.post.dat" "${flags}"
+ done
+
+ if [ $((flags & FLAG_LIBVIRT_TEST)) -ne 0 ]; then
+ test_final $((passctr+failctr)) $failctr
+ elif [ $((flags & FLAG_TAP_TEST)) -ne 0 ]; then
+ tap_final
+ else
+ echo ""
+ echo "Summary: ${failctr} failures, ${passctr} passes,"
+ if [ ${attachctr} -ne 0 ]; then
+ echo " ${attachfailctr} interface attachment failures with ${attachctr} attempts"
+ fi
+ fi
+}
+
+
+function main() {
+ local prgname="$0"
+ local vm1 vm2
+ local xmldir="networkxml2xmlin"
+ local hostoutdir="networkxml2hostout"
+ local res rc
+ local flags
+
+ while [ $# -ne 0 ]; do
+ case "$1" in
+ --help|-h|-\?) usage ${prgname}; exit 0;;
+ --wait) ((flags |= FLAG_WAIT ));;
+ --verbose) ((flags |= FLAG_VERBOSE ));;
+ --libvirt-test) ((flags |= FLAG_LIBVIRT_TEST ));;
+ --tap-test) ((flags |= FLAG_TAP_TEST ));;
+ --force) ((flags |= FLAG_FORCE_CLEAN ));;
+ *) usage ${prgname}; exit 1;;
+ esac
+ shift 1
+ done
+
+ if [ `uname` != "Linux" ]; then
+ if [ $((flags & FLAG_TAP_TEST)) -ne 0 ]; then
+ echo "1..0 # Skipped: Only valid on Linux hosts"
+ else
+ echo "This script will only run on Linux."
+ fi
+ exit 1;
+ fi
+
+ if [ $((flags & FLAG_TAP_TEST)) -ne 0 ]; then
+ if [ "${LIBVIRT_URI}" != "qemu:///system" ]; then
+ echo "1..0 # Skipped: Only valid for Qemu system driver"
+ exit 0
+ fi
+
+ for name in `virsh list | awk '{print $2}'`
+ do
+ case ${name} in
+ tck*)
+ if [ "x${LIBVIRT_TCK_AUTOCLEAN}" == "x1" -o \
+ $((flags & FLAG_FORCE_CLEAN)) -ne 0 ]; then
+ res=$(virsh destroy ${name} 2>&1)
+ res=$(virsh undefine ${name} 2>&1)
+ if [ $? -ne 0 ]; then
+ echo "Bail out! Could not undefine VM ${name}: ${res}"
+ exit 0
+ fi
+ else
+ echo "Bail out! TCK VMs from previous tests still exist, use --force to clean"
+ exit 1
+ fi
+ esac
+ done
+
+ for name in `virsh net-list | sed -n '3,$p'`
+ do
+ case ${name} in
+ tck*)
+ if [ "x${LIBVIRT_TCK_AUTOCLEAN}" == "x1" -o \
+ $((flags & FLAG_FORCE_CLEAN)) -ne 0 ]; then
+ res=$(virsh net-destroy ${name} 2>&1)
+ rc=$?
+ res=$(virsh net-undefine ${name} 2>&1)
+ if [ $rc -ne 0 -a $? -ne 0 ]; then
+ echo "Bail out! Could not destroy/undefine network ${name}: ${res}"
+ exit 1
+ fi
+ else
+ echo "Bail out! Network ${name} already exists, use --force to clean"
+ exit 1
+ fi
+ esac
+ done
+ fi
+
+ if [ $((flags & FLAG_LIBVIRT_TEST)) -ne 0 ]; then
+ pushd ${PWD} > /dev/null
+ . test-lib.sh
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ test_intro $this_test
+ popd > /dev/null
+ fi
+
+ res=$(${VIRSH} capabilities 2>&1)
+
+ runTests "${xmldir}" "${hostoutdir}" "${flags}"
+
+ return 0
+}
+
+main "$@"
Index: libvirt-tck/scripts/networks/networkxml2hostout/tck-testnet-1.dat
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/networks/networkxml2hostout/tck-testnet-1.dat
@@ -0,0 +1,11 @@
+#iptables -t nat -L -n | grep 10.1.2
+MASQUERADE tcp -- 10.1.2.0/24 !10.1.2.0/24 masq ports: 1024-65535
+MASQUERADE udp -- 10.1.2.0/24 !10.1.2.0/24 masq ports: 1024-65535
+MASQUERADE all -- 10.1.2.0/24 !10.1.2.0/24
+#iptables -n -L FORWARD | grep 10.1.2
+ACCEPT all -- anywhere 10.1.2.0/24 state RELATED,ESTABLISHED
+ACCEPT all -- 10.1.2.0/24 anywhere
+#ps aux | grep dnsmasq | grep 10.1.2 | sed -n 's/.*\\(dnsmasq[[:print:]*]\\)/\\1/p'
+dnsmasq --strict-order --bind-interfaces --pid-file=/var/run/libvirt/network/tck-testnet.pid --conf-file= --listen-address 10.1.2.1 --except-interface lo --dhcp-range 10.1.2.2,10.1.2.254 --dhcp-lease-max=253 --dhcp-no-override
+#virsh net-list | grep tck-testnet
+tck-testnet active no
Index: libvirt-tck/scripts/networks/networkxml2xmlin/tck-testnet-1.xml
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/networks/networkxml2xmlin/tck-testnet-1.xml
@@ -0,0 +1,12 @@
+<network>
+ <name>tck-testnet</name>
+ <uuid>aadc8920-502a-4774-ac2b-cd382a204d06</uuid>
+ <forward mode='nat'/>
+ <bridge name='testbr' stp='on' delay='0' />
+ <ip address='10.1.2.1' netmask='255.255.255.0'>
+ <dhcp>
+ <range start='10.1.2.2' end='10.1.2.254' />
+ </dhcp>
+ </ip>
+</network>
+
Index: libvirt-tck/scripts/networks/networkxml2hostout/tck-testnet-2.dat
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/networks/networkxml2hostout/tck-testnet-2.dat
@@ -0,0 +1,8 @@
+#iptables -L FORWARD | grep 10.1.2
+ACCEPT all -- anywhere 10.1.2.0/24
+ACCEPT all -- 10.1.2.0/24 anywhere
+#iptables -t nat -L | grep 10.1.2
+#ps aux | grep dnsmasq | grep 10.1.2 | sed -n 's/.*\\(dnsmasq[[:print:]*]\\)/\\1/p'
+dnsmasq --strict-order --bind-interfaces --pid-file=/var/run/libvirt/network/tck-testnet.pid --conf-file= --listen-address 10.1.2.1 --except-interface lo --dhcp-range 10.1.2.2,10.1.2.254 --dhcp-lease-max=253 --dhcp-no-override
+#virsh net-list | grep tck-testnet
+tck-testnet active no
Index: libvirt-tck/scripts/networks/networkxml2xmlin/tck-testnet-2.xml
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/networks/networkxml2xmlin/tck-testnet-2.xml
@@ -0,0 +1,12 @@
+<network>
+ <name>tck-testnet</name>
+ <uuid>aadc8920-502a-4774-ac2b-cd382a204d06</uuid>
+ <forward mode='route'/>
+ <bridge name='testbr' stp='on' delay='0' />
+ <ip address='10.1.2.1' netmask='255.255.255.0'>
+ <dhcp>
+ <range start='10.1.2.2' end='10.1.2.254' />
+ </dhcp>
+ </ip>
+</network>
+
Index: libvirt-tck/scripts/networks/100-apply-verify-host.t
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/networks/100-apply-verify-host.t
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+pwd=$(dirname $0)
+
+pushd ${PWD} > /dev/null
+
+cd ${pwd}
+bash ./networkApplyTest.sh --tap-test
+
+popd > /dev/null
Index: libvirt-tck/scripts/networks/networkxml2hostout/tck-testnet-1.post.dat
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/networks/networkxml2hostout/tck-testnet-1.post.dat
@@ -0,0 +1,4 @@
+#iptables -t nat -L -n | grep 10.1.2
+#iptables -n -L FORWARD | grep 10.1.2
+#ps aux | grep dnsmasq | grep 10.1.2 | sed -n 's/.*\\(dnsmasq[[:print:]*]\\)/\\1/p'
+#virsh net-list | grep tck-testnet
Index: libvirt-tck/scripts/networks/networkxml2hostout/tck-testnet-2.post.dat
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/networks/networkxml2hostout/tck-testnet-2.post.dat
@@ -0,0 +1,4 @@
+#iptables -t nat -L -n | grep 10.1.2
+#iptables -n -L FORWARD | grep 10.1.2
+#ps aux | grep dnsmasq | grep 10.1.2 | sed -n 's/.*\\(dnsmasq[[:print:]*]\\)/\\1/p'
+#virsh net-list | grep tck-testnet
Index: libvirt-tck/Build.PL
===================================================================
--- libvirt-tck.orig/Build.PL
+++ libvirt-tck/Build.PL
@@ -29,7 +29,7 @@ sub process_pkgdata_files {
my $name = $File::Find::name;
if (-d) {
$tck_dirs{$name} = [];
- } elsif (-f && (/\.t$/ || /\.sh$/ || /\.fwall$/ || /\.xml$/)) {
+ } elsif (-f && /\.(t|sh|fwall|xml|dat)$/) {
push @{$tck_dirs{$dir}}, $name;
}
};
14 years
[libvirt] [PATCH] qemu: add the USB devices to the cgroup whitelist
by Diego Elio Pettenò
Add a new interface to hostusb.h to add an USB device abstraction to a
cgroup whitelist; then use it both when attaching a new USB device and when
adding it to the commandline so that the device can be accessed by the
QEmu-specific cgroup.
---
src/libvirt_private.syms | 1 +
src/qemu/qemu_driver.c | 36 ++++++++++++++++++++++++++++++++++++
src/util/hostusb.c | 6 ++++++
src/util/hostusb.h | 4 +++-
4 files changed, 46 insertions(+), 1 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index cf06256..0c6f308 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -707,6 +707,7 @@ virMutexUnlock;
# usb.h
+usbAllowDeviceCgroup;
usbDeviceFileIterate;
usbDeviceGetBus;
usbDeviceGetDevno;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1eea3a9..acf319e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3505,6 +3505,23 @@ static int qemuSetupCgroup(struct qemud_driver *driver,
qemuSetupChardevCgroup,
cgroup) < 0)
goto cleanup;
+
+ for (i = 0; i < vm->def->nhostdevs; i++) {
+ virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i];
+ usbDevice *usb;
+
+ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+ continue;
+ if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
+ continue;
+
+ if ((usb = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
+ hostdev->source.subsys.u.usb.product)) == NULL)
+ goto cleanup;
+
+ if (usbAllowDeviceCgroup(usb, cgroup) < 0)
+ goto cleanup;
+ }
}
if ((rc = qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY))) {
@@ -8454,6 +8471,25 @@ static int qemudDomainAttachHostUsbDevice(struct qemud_driver *driver,
goto error;
}
+ if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
+ virCgroupPtr cgroup = NULL;
+ usbDevice *usb;
+
+ if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) !=0 ) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to find cgroup for %s\n"),
+ vm->def->name);
+ goto error;
+ }
+
+ if ((usb = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
+ hostdev->source.subsys.u.usb.product)) == NULL)
+ goto error;
+
+ if (usbAllowDeviceCgroup(usb, cgroup) < 0)
+ goto error;
+ }
+
qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
ret = qemuMonitorAddDevice(priv->mon, devstr);
diff --git a/src/util/hostusb.c b/src/util/hostusb.c
index 2d6e414..2cbe1fb 100644
--- a/src/util/hostusb.c
+++ b/src/util/hostusb.c
@@ -225,3 +225,9 @@ int usbDeviceFileIterate(usbDevice *dev,
{
return (actor)(dev, dev->path, opaque);
}
+
+int usbAllowDeviceCgroup(usbDevice *dev,
+ virCgroupPtr group)
+{
+ return virCgroupAllowDevicePath(group, dev->path);
+}
diff --git a/src/util/hostusb.h b/src/util/hostusb.h
index f4a13ca..12269ad 100644
--- a/src/util/hostusb.h
+++ b/src/util/hostusb.h
@@ -23,6 +23,7 @@
# define __VIR_USB_H__
# include "internal.h"
+# include "cgroup.h"
typedef struct _usbDevice usbDevice;
@@ -48,6 +49,7 @@ typedef int (*usbDeviceFileActor)(usbDevice *dev,
int usbDeviceFileIterate(usbDevice *dev,
usbDeviceFileActor actor,
void *opaque);
-
+int usbAllowDeviceCgroup(usbDevice *dev,
+ virCgroupPtr group);
#endif /* __VIR_USB_H__ */
--
1.7.3.2
14 years
Re: [libvirt] Node.GetInfo error
by arnaud.champion@devatom.fr
?Ok,
at first GetLastError return an Error object. So you should anything like :
Errors.Error err = Errors.GetLastError();
MessageBox.Show(err.Message);
For the NodeInfo structure, I think the problem is the same that was for DomainInfo, I'll check marshaling. Then respond you with the correct infos.
Arnaud
PS : can you also put libvirt-list(a)redhat.com in copy of your mails, to keep everyone in the loop ?
From: 黄亮
Sent: Sunday, October 31, 2010 8:20 AM
To: arnaud.champion
Subject: Node.GetInfo error
Hi,
Sorry for disturbing again. But I get error while using Node.GetInfo.
Code:
NodeInfo aNodeInfo = new NodeInfo();
if (Node.GetInfo(con, aNodeInfo) < 0)
{
//MessageBox.Show("Node Info Error");
MessageBox.Show(Errors.GetLastError().ToString());
return 0f;
}
I'm sure con != IntPtr.Zero. I tried to use Errors.GetLastError(), it returns int. But I don't know what to do with it.
So, any suggestions ? Thanks
Regards
2010-10-31
--------------------------------------------------------------------------------
Lancer
14 years