From adf97edda203ed6e48134029c0acc00164bb5934 Mon Sep 17 00:00:00 2001 From: Anthony Perard Date: Mon, 9 Aug 2010 16:46:00 +0100 Subject: [PATCH 01/10] libxl, Fix name of tap device. From: Anthony PERARD Currently, tap device names for a domain begin at tap42.-1, but it must be tap42.0. Signed-off-by: Anthony PERARD Signed-off-by: Stefano Stabellini --- tools/libxl/libxl.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) --- tools/libxl/libxl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 732772c12b..97cca38a69 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -1070,7 +1070,7 @@ static char ** libxl_build_device_model_args(libxl_ctx *ctx, vifs[i].mac[0], vifs[i].mac[1], vifs[i].mac[2], vifs[i].mac[3], vifs[i].mac[4], vifs[i].mac[5]); if (!vifs[i].ifname) - vifs[i].ifname = libxl_sprintf(ctx, "tap%d.%d", info->domid, vifs[i].devid - 1); + vifs[i].ifname = libxl_sprintf(ctx, "tap%d.%d", info->domid, vifs[i].devid); flexarray_set(dm_args, num++, "-net"); flexarray_set(dm_args, num++, libxl_sprintf(ctx, "nic,vlan=%d,macaddr=%s,model=%s", vifs[i].devid, smac, vifs[i].model)); From 2d50ecfbf6aca65552d6864c80c00116f81230af Mon Sep 17 00:00:00 2001 From: Anthony Perard Date: Mon, 9 Aug 2010 16:46:01 +0100 Subject: [PATCH 02/10] libxl, Introduce the command line handler for the new qemu. From: Anthony PERARD This patch adds a function to check the version of the device model. Depending on the version of the DM, the command line arguments will be built differently. Signed-off-by: Anthony PERARD Signed-off-by: Stefano Stabellini --- tools/libxl/libxl.c | 160 ++++++++++++++++++++++++++++++++++++++++++++- tools/libxl/libxl_utils.c | 78 ++++++++++++++++++++++ tools/libxl/libxl_utils.h | 6 ++ 3 files changed, 243 insertions(+), 1 deletions(-) --- tools/libxl/libxl.c | 162 +++++++++++++++++++++++++++++++++++++- tools/libxl/libxl_utils.c | 78 ++++++++++++++++++ tools/libxl/libxl_utils.h | 6 ++ 3 files changed, 244 insertions(+), 2 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 97cca38a69..53b5499098 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -964,7 +964,7 @@ skip_autopass: return 0; } -static char ** libxl_build_device_model_args(libxl_ctx *ctx, +static char ** libxl_build_device_model_args_old(libxl_ctx *ctx, libxl_device_model_info *info, libxl_device_nic *vifs, int num_vifs) @@ -1098,10 +1098,168 @@ static char ** libxl_build_device_model_args(libxl_ctx *ctx, else flexarray_set(dm_args, num++, "xenfv"); flexarray_set(dm_args, num++, NULL); - return (char **) flexarray_contents(dm_args); } +static char ** libxl_build_device_model_args_new(libxl_ctx *ctx, + libxl_device_model_info *info, + libxl_device_nic *vifs, + int num_vifs) +{ + int num = 0, i; + flexarray_t *dm_args; + int nb; + libxl_device_disk *disks; + + dm_args = flexarray_make(16, 1); + if (!dm_args) + return NULL; + + flexarray_set(dm_args, num++, "qemu-system-xen"); + flexarray_set(dm_args, num++, "-xen-domid"); + + flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->domid)); + + if (info->dom_name) { + flexarray_set(dm_args, num++, "-name"); + flexarray_set(dm_args, num++, info->dom_name); + } + if (info->vnc || info->vncdisplay || info->vnclisten || info->vncunused) { + int display = 0; + const char *listen = "127.0.0.1"; + + flexarray_set(dm_args, num++, "-vnc"); + + if (info->vncdisplay) { + display = info->vncdisplay; + if (info->vnclisten && strchr(info->vnclisten, ':') == NULL) { + listen = info->vnclisten; + } + } else if (info->vnclisten) { + listen = info->vnclisten; + } + + if (strchr(listen, ':') != NULL) + flexarray_set(dm_args, num++, + libxl_sprintf(ctx, "%s%s", listen, + info->vncunused ? ",to=99" : "")); + else + flexarray_set(dm_args, num++, + libxl_sprintf(ctx, "%s:%d%s", listen, display, + info->vncunused ? ",to=99" : "")); + } + if (info->sdl) { + flexarray_set(dm_args, num++, "-sdl"); + } + if (info->keymap) { + flexarray_set(dm_args, num++, "-k"); + flexarray_set(dm_args, num++, info->keymap); + } + if (info->nographic && (!info->sdl && !info->vnc)) { + flexarray_set(dm_args, num++, "-nographic"); + } + if (info->serial) { + flexarray_set(dm_args, num++, "-serial"); + flexarray_set(dm_args, num++, info->serial); + } + if (info->type == XENFV) { + int ioemu_vifs = 0; + + if (info->stdvga) { + flexarray_set(dm_args, num++, "-vga"); + flexarray_set(dm_args, num++, "std"); + } + + if (info->boot) { + flexarray_set(dm_args, num++, "-boot"); + flexarray_set(dm_args, num++, libxl_sprintf(ctx, "order=%s", info->boot)); + } + if (info->usb || info->usbdevice) { + flexarray_set(dm_args, num++, "-usb"); + if (info->usbdevice) { + flexarray_set(dm_args, num++, "-usbdevice"); + flexarray_set(dm_args, num++, info->usbdevice); + } + } + if (info->soundhw) { + flexarray_set(dm_args, num++, "-soundhw"); + flexarray_set(dm_args, num++, info->soundhw); + } + if (!info->apic) { + flexarray_set(dm_args, num++, "-no-acpi"); + } + if (info->vcpus > 1) { + flexarray_set(dm_args, num++, "-smp"); + if (info->vcpu_avail) + flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d,maxcpus=%d", info->vcpus, info->vcpu_avail)); + else + flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->vcpus)); + } + for (i = 0; i < num_vifs; i++) { + if (vifs[i].nictype == NICTYPE_IOEMU) { + char *smac = libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x", + vifs[i].mac[0], vifs[i].mac[1], vifs[i].mac[2], + vifs[i].mac[3], vifs[i].mac[4], vifs[i].mac[5]); + if (!vifs[i].ifname) + vifs[i].ifname = libxl_sprintf(ctx, "tap%d.%d", info->domid, vifs[i].devid); + flexarray_set(dm_args, num++, "-net"); + flexarray_set(dm_args, num++, libxl_sprintf(ctx, "nic,vlan=%d,macaddr=%s,model=%s", + vifs[i].devid, smac, vifs[i].model)); + flexarray_set(dm_args, num++, "-net"); + flexarray_set(dm_args, num++, libxl_sprintf(ctx, "tap,vlan=%d,ifname=%s,script=%s", + vifs[i].devid, vifs[i].ifname, "/etc/xen/scripts/qemu-ifup")); + ioemu_vifs++; + } + } + /* If we have no emulated nics, tell qemu not to create any */ + if ( ioemu_vifs == 0 ) { + flexarray_set(dm_args, num++, "-net"); + flexarray_set(dm_args, num++, "none"); + } + } + if (info->saved_state) { + flexarray_set(dm_args, num++, "-loadvm"); + flexarray_set(dm_args, num++, info->saved_state); + } + for (i = 0; info->extra && info->extra[i] != NULL; i++) + flexarray_set(dm_args, num++, info->extra[i]); + flexarray_set(dm_args, num++, "-M"); + if (info->type == XENPV) + flexarray_set(dm_args, num++, "xenpv"); + else + flexarray_set(dm_args, num++, "xenfv"); + + disks = libxl_device_disk_list(ctx, info->domid, &nb); + for (; nb > 0; --nb, ++disks) { + if ( disks->is_cdrom ) { + flexarray_set(dm_args, num++, "-cdrom"); + flexarray_set(dm_args, num++, disks->physpath); + }else{ + flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-%s", disks->virtpath)); + flexarray_set(dm_args, num++, disks->physpath); + } + } + + flexarray_set(dm_args, num++, NULL); + return (char **) flexarray_contents(dm_args); +} + +static char ** libxl_build_device_model_args(libxl_ctx *ctx, + libxl_device_model_info *info, + libxl_device_nic *vifs, + int num_vifs) +{ + int new_qemu; + + new_qemu = libxl_check_device_model_version(ctx, info->device_model); + + if (new_qemu == 1) { + return libxl_build_device_model_args_new(ctx, info, vifs, num_vifs); + } else { + return libxl_build_device_model_args_old(ctx, info, vifs, num_vifs); + } +} + void dm_xenstore_record_pid(void *for_spawn, pid_t innerchild) { libxl_device_model_starting *starting = for_spawn; diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c index f6021c3147..f54744de12 100644 --- a/tools/libxl/libxl_utils.c +++ b/tools/libxl/libxl_utils.c @@ -538,3 +538,81 @@ int libxl_strtomac(const char *mac_s, uint8_t *mac) } return 0; } + +#define QEMU_VERSION_STR "QEMU emulator version " + + +int libxl_check_device_model_version(libxl_ctx *ctx, char *path) +{ + pid_t pid = -1; + int pipefd[2]; + char buf[100]; + ssize_t i, count = 0; + int status; + char *abs_path = NULL; + + abs_path = libxl_abs_path(ctx, path, libxl_private_bindir_path()); + + if (pipe(pipefd)) + return -1; + + pid = fork(); + if (pid == -1) { + return -1; + } + + if (!pid) { + close(pipefd[0]); + if (dup2(pipefd[1], STDOUT_FILENO) == -1) + exit(1); + execlp(abs_path, abs_path, "-h", NULL); + + close(pipefd[1]); + exit(127); + } + + close(pipefd[1]); + if (abs_path != path) + libxl_free(ctx, abs_path); + + /* attempt to get the first line of `qemu -h` */ + while ((i = read(pipefd[0], buf + count, 99 - count)) > 0) { + if (i + count > 90) + break; + for (int j = 0; j < i; j++) { + if (buf[j + count] == '\n') + break; + } + count += i; + } + count += i; + close(pipefd[0]); + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + return -1; + } + + /* Check if we have the forked qemu-xen. */ + /* QEMU-DM emulator version 0.10.2, ... */ + if (strncmp("QEMU-DM ", buf, 7) == 0) { + return 0; + } + + /* Check if the version is above 12.0 */ + /* The first line is : QEMU emulator version 0.12.50, ... */ + if (strncmp(QEMU_VERSION_STR, buf, strlen(QEMU_VERSION_STR)) == 0) { + int major, minor; + char *endptr = NULL; + char *v = buf + strlen(QEMU_VERSION_STR); + + major = strtol(v, &endptr, 10); + if (major == 0 && endptr && *endptr == '.') { + v = endptr + 1; + minor = strtol(v, &endptr, 10); + if (minor >= 12) + return 1; + } + } + + return -1; +} diff --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h index 98a912cad4..5de2137102 100644 --- a/tools/libxl/libxl_utils.h +++ b/tools/libxl/libxl_utils.h @@ -68,5 +68,11 @@ int libxl_strtomac(const char *mac_s, uint8_t *mac); int libxl_devid_to_device_net2(libxl_ctx *ctx, uint32_t domid, const char *devid, libxl_device_net2 *net2); +/* check the version of qemu + * return 1 if is the new one + * return 0 if is the old one + * return -1 if there are an error */ +int libxl_check_device_model_version(libxl_ctx *ctx, char *path); + #endif From 025e84f126fcc3acdc75f7706a6e8ceac71b8d86 Mon Sep 17 00:00:00 2001 From: Anthony Perard Date: Mon, 9 Aug 2010 16:46:02 +0100 Subject: [PATCH 03/10] tools/hotplug, Use udev rules instead of qemu script to setup the bridge. From: Anthony PERARD This patch adds a second argument to vif-bridge script. It can be "vif" or "tap". "vif" give the default behavior and "tap" just add the interface to the found bridge when the action is "add". Signed-off-by: Anthony PERARD Signed-off-by: Stefano Stabellini --- tools/hotplug/Linux/vif-bridge | 20 ++++++--- tools/hotplug/Linux/vif-common.sh | 70 ++++++++++++++++++++++++--------- tools/hotplug/Linux/xen-backend.rules | 5 +- tools/libxl/libxl.c | 6 +- 4 files changed, 70 insertions(+), 31 deletions(-) --- tools/hotplug/Linux/vif-bridge | 20 +++++--- tools/hotplug/Linux/vif-common.sh | 70 +++++++++++++++++++-------- tools/hotplug/Linux/xen-backend.rules | 5 +- tools/libxl/libxl.c | 6 +-- 4 files changed, 70 insertions(+), 31 deletions(-) diff --git a/tools/hotplug/Linux/vif-bridge b/tools/hotplug/Linux/vif-bridge index d35144e1e9..82ba676202 100644 --- a/tools/hotplug/Linux/vif-bridge +++ b/tools/hotplug/Linux/vif-bridge @@ -81,20 +81,26 @@ fi case "$command" in online) - setup_bridge_port "$vif" - add_to_bridge "$bridge" "$vif" + setup_bridge_port "$dev" + add_to_bridge "$bridge" "$dev" ;; offline) - do_without_error brctl delif "$bridge" "$vif" - do_without_error ifconfig "$vif" down + do_without_error brctl delif "$bridge" "$dev" + do_without_error ifconfig "$dev" down + ;; + + add) + add_to_bridge "$bridge" "$dev" ;; esac -handle_iptable +if [ "$type_if" = vif ]; then + handle_iptable +fi -log debug "Successful vif-bridge $command for $vif, bridge $bridge." -if [ "$command" == "online" ] +log debug "Successful vif-bridge $command for $dev, bridge $bridge." +if [ "$type_if" = vif -a "$command" = "online" ] then success fi diff --git a/tools/hotplug/Linux/vif-common.sh b/tools/hotplug/Linux/vif-common.sh index 44dd342acf..780cc718ab 100644 --- a/tools/hotplug/Linux/vif-common.sh +++ b/tools/hotplug/Linux/vif-common.sh @@ -31,12 +31,6 @@ then exit 1 fi -case "$command" in - add | remove) - exit 0 - ;; -esac - # Parameters may be read from the environment, the command line arguments, and # the store, with overriding in that order. The environment is given by the @@ -45,24 +39,62 @@ esac evalVariables "$@" -ip=${ip:-} -ip=$(xenstore_read_default "$XENBUS_PATH/ip" "$ip") +# Older versions of Xen do not pass in the type as an argument, +# so the default value is vif. +: ${type_if:=vif} -# Check presence of compulsory args. -XENBUS_PATH="${XENBUS_PATH:?}" -vif="${vif:?}" +case "$type_if" in + vif) + dev=$vif + ;; + tap) + dev=$INTERFACE + ;; + *) + log err "unknown interface type $type_if" + exit 1 + ;; +esac + +case "$command" in + online | offline) + test "$type_if" != vif && exit 0 + ;; + add | remove) + test "$type_if" != tap && exit 0 + ;; +esac -vifname=$(xenstore_read_default "$XENBUS_PATH/vifname" "") -if [ "$vifname" ] -then - if [ "$command" == "online" ] && ! ip link show "$vifname" >&/dev/null - then - do_or_die ip link set "$vif" name "$vifname" - fi - vif="$vifname" +if [ "$type_if" = vif ]; then + # Check presence of compulsory args. + XENBUS_PATH="${XENBUS_PATH:?}" + vif="${vif:?}" + + vifname=$(xenstore_read_default "$XENBUS_PATH/vifname" "") + if [ "$vifname" ] + then + if [ "$command" == "online" ] && ! ip link show "$vifname" >&/dev/null + then + do_or_die ip link set "$vif" name "$vifname" + fi + vif="$vifname" + fi +elif [ "$type_if" = tap ]; then + # Check presence of compulsory args. + : ${INTERFACE:?} + + # Get xenbus_path from device name. + # The name is built like that: "tap${domid}.${devid}". + dev_=${dev#tap} + domid=${dev_%.*} + devid=${dev_#*.} + + XENBUS_PATH="/local/domain/0/backend/vif/$domid/$devid" fi +ip=${ip:-} +ip=$(xenstore_read_default "$XENBUS_PATH/ip" "$ip") frob_iptable() { diff --git a/tools/hotplug/Linux/xen-backend.rules b/tools/hotplug/Linux/xen-backend.rules index 2d844a15bd..ccbe508f48 100644 --- a/tools/hotplug/Linux/xen-backend.rules +++ b/tools/hotplug/Linux/xen-backend.rules @@ -2,10 +2,11 @@ SUBSYSTEM=="xen-backend", KERNEL=="tap*", RUN+="/etc/xen/scripts/blktap $env{ACT SUBSYSTEM=="xen-backend", KERNEL=="vbd*", RUN+="/etc/xen/scripts/block $env{ACTION}" SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm $env{ACTION}" SUBSYSTEM=="xen-backend", KERNEL=="vif2-*", RUN+="/etc/xen/scripts/vif2 $env{ACTION}" -SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="online", RUN+="/etc/xen/scripts/vif-setup online" -SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="offline", RUN+="/etc/xen/scripts/vif-setup offline" +SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="online", RUN+="/etc/xen/scripts/vif-setup online type_if=vif" +SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="offline", RUN+="/etc/xen/scripts/vif-setup offline type_if=vif" SUBSYSTEM=="xen-backend", KERNEL=="vscsi*", RUN+="/etc/xen/scripts/vscsi $env{ACTION}" SUBSYSTEM=="xen-backend", ACTION=="remove", RUN+="/etc/xen/scripts/xen-hotplug-cleanup" KERNEL=="evtchn", NAME="xen/%k" KERNEL=="blktap[0-9]*", NAME="xen/%k" KERNEL=="pci_iomul", NAME="xen/%k" +SUBSYSTEM=="net", KERNEL=="tap*", ACTION=="add", RUN+="/etc/xen/scripts/vif-setup $env{ACTION} type_if=tap" diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 53b5499098..2f92732ac6 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -1075,7 +1075,7 @@ static char ** libxl_build_device_model_args_old(libxl_ctx *ctx, flexarray_set(dm_args, num++, libxl_sprintf(ctx, "nic,vlan=%d,macaddr=%s,model=%s", vifs[i].devid, smac, vifs[i].model)); flexarray_set(dm_args, num++, "-net"); - flexarray_set(dm_args, num++, libxl_sprintf(ctx, "tap,vlan=%d,ifname=%s,bridge=%s", + flexarray_set(dm_args, num++, libxl_sprintf(ctx, "tap,vlan=%d,ifname=%s,bridge=%s,script=no", vifs[i].devid, vifs[i].ifname, vifs[i].bridge)); ioemu_vifs++; } @@ -1206,8 +1206,8 @@ static char ** libxl_build_device_model_args_new(libxl_ctx *ctx, flexarray_set(dm_args, num++, libxl_sprintf(ctx, "nic,vlan=%d,macaddr=%s,model=%s", vifs[i].devid, smac, vifs[i].model)); flexarray_set(dm_args, num++, "-net"); - flexarray_set(dm_args, num++, libxl_sprintf(ctx, "tap,vlan=%d,ifname=%s,script=%s", - vifs[i].devid, vifs[i].ifname, "/etc/xen/scripts/qemu-ifup")); + flexarray_set(dm_args, num++, libxl_sprintf(ctx, "tap,vlan=%d,ifname=%s,script=no", + vifs[i].devid, vifs[i].ifname)); ioemu_vifs++; } } From 9c8fd24b3fe70f0e00d1c9a6f73523d0f4150b76 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Mon, 9 Aug 2010 16:33:55 +0100 Subject: [PATCH 04/10] libxl_check_device_model_version should return 0 or 1 Signed-off-by: Stefano Stabellini --- tools/libxl/libxl_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c index f54744de12..4ccca2f271 100644 --- a/tools/libxl/libxl_utils.c +++ b/tools/libxl/libxl_utils.c @@ -614,5 +614,5 @@ int libxl_check_device_model_version(libxl_ctx *ctx, char *path) } } - return -1; + return 0; } From 4d52a08194c3ec7c0e8693af8dc1f11aa799fd69 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Mon, 9 Aug 2010 17:05:51 +0100 Subject: [PATCH 05/10] formatting of "# xl list -h" is off (due to missing \n) Signed-off-by: Andre Przywara Signed-off-by: Stefano Stabellini --- tools/libxl/xl_cmdtable.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c index 94e2cc9961..90125d9cd0 100644 --- a/tools/libxl/xl_cmdtable.c +++ b/tools/libxl/xl_cmdtable.c @@ -35,8 +35,8 @@ struct cmd_spec cmd_table[] = { &main_list, "List information about all/some domains", "[options] [Domain]\n", - "-l, --long Output all VM details" - "-v, --verbose Prints out UUIDs", + "-l, --long Output all VM details\n" + "-v, --verbose Prints out UUIDs", }, { "destroy", &main_destroy, From 8b3be172a3f225539a807711318c23001e84f359 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Mon, 9 Aug 2010 17:07:50 +0100 Subject: [PATCH 06/10] xl: tell the user about non-existent domains The error message when one wants to list a non-existent domain is at best misleading (libxl_domain_info failed (code -5)). This patch catches this specific error and tells the user that the requested domain does not exist: Error: Domain '42' does not exist. Signed-off-by: Andre Przywara Signed-off-by: Stefano Stabellini --- tools/libxl/xl_cmdimpl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index e42ad69cbe..a2ccfe2c16 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -3003,6 +3003,11 @@ int main_list(int argc, char **argv) } else if (optind == argc-1) { find_domain(argv[optind]); rc = libxl_domain_info(&ctx, &info_buf, domid); + if (rc == ERROR_INVAL) { + fprintf(stderr, "Error: Domain \'%s\' does not exist.\n", + argv[optind]); + return -rc; + } if (rc) { fprintf(stderr, "libxl_domain_info failed (code %d).\n", rc); return -rc; From 6d7a71986d206dcfea48a936b02401097572bf8d Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Mon, 9 Aug 2010 17:20:39 +0100 Subject: [PATCH 07/10] Do not try to retrieve userdata for dom0 There is no userdata available regarding dom0, do not try to retrieve it Signed-off-by: Stefano Stabellini --- tools/libxl/xl_cmdimpl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index a2ccfe2c16..638289ba12 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -2127,6 +2127,9 @@ void list_domains_details(const libxl_dominfo *info, int nb_domain) libxl_device_model_info dm_info; for (i = 0; i < nb_domain; i++) { + /* no detailed info available on dom0 */ + if (info[i].domid == 0) + continue; rc = libxl_userdata_retrieve(&ctx, info[i].domid, "xl", &data, &len); if (rc) continue; From 8493e199f833705eb480e91b2dd4d0328202e525 Mon Sep 17 00:00:00 2001 From: Gianni Tedesco Date: Mon, 9 Aug 2010 17:43:18 +0100 Subject: [PATCH 08/10] xc: fix segfault in pv domain create if kernel is an invalid image If libelf calls elf_err() or elf_msg() before elf_set_log() has been called then it could potentially read an uninitialised log handling callback function pointer from struct elf_binary. Fix this in libxc by zeroing the structure before calling elf_init(). Signed-off-by: Gianni Tedesco Signed-off-by: Stefano Stabellini --- tools/libxc/xc_hvm_build.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/libxc/xc_hvm_build.c b/tools/libxc/xc_hvm_build.c index 7bdd50b1f3..03e81a9e1b 100644 --- a/tools/libxc/xc_hvm_build.c +++ b/tools/libxc/xc_hvm_build.c @@ -142,6 +142,7 @@ static int setup_guest(xc_interface *xch, if ( memsize > target ) pod_mode = 1; + memset(&elf, 0, sizeof(elf)); if ( elf_init(&elf, image, image_size) != 0 ) goto error_out; elf_parse_binary(&elf); From ba8ae70f8e72a1f164cbbb2487b0f24c8dd6ccd3 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Mon, 9 Aug 2010 17:44:01 +0100 Subject: [PATCH 09/10] xl: support backend domid in config file for vifs Allow specification of backend domains for vifs, either in the config file or via network-attach. Signed-off-by: Mihir Nanavati Signed-off-by: Stefano Stabellini --- tools/libxl/xl_cmdimpl.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 638289ba12..b1f8d71d36 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -833,6 +833,11 @@ static void parse_config_data(const char *configfile_filename_report, nic->script = strdup(p2 + 1); } else if (!strcmp(p, "vifname")) { nic->ifname = strdup(p2 + 1); + } else if (!strcmp(p, "backend")) { + if(libxl_name_to_domid(&ctx, (p2 + 1), &(nic->backend_domid))) { + fprintf(stderr, "Specified backend domain does not exist, defaulting to Dom0\n"); + nic->backend_domid = 0; + } } else if (!strcmp(p, "rate")) { fprintf(stderr, "the rate parameter for vifs is currently not supported\n"); } else if (!strcmp(p, "accel")) { @@ -4012,10 +4017,9 @@ int main_networkattach(int argc, char **argv) } else if (!strncmp("script=", *argv, 6)) { nic.script = (*argv) + 6; } else if (!strncmp("backend=", *argv, 8)) { - val = strtoul((*argv) + 8, &endptr, 10); - if (((*argv) + 8) == endptr) { - fprintf(stderr, "Invalid parameter `backend'.\n"); - return 1; + if(libxl_name_to_domid(&ctx, ((*argv) + 8), &val)) { + fprintf(stderr, "Specified backend domain does not exist, defaulting to Dom0\n"); + val = 0; } nic.backend_domid = val; } else if (!strncmp("vifname=", *argv, 8)) { From 1d05a5dafbb1fd1ca0872f61a374c0bc12f618b5 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Mon, 9 Aug 2010 17:46:39 +0100 Subject: [PATCH 10/10] xl: pci multi-function passthrough v2 Implement PCI pass-through for multi-function devices. The supported BDF notation is: BB:DD.* - therefore passing-through a subset of functions or remapping the function numbers is not supported except for when passing through a single function which will be a virtual function 0. Letting qemu automatically select the virtual slot is not supported in multi-function passthrough since the qemu-dm protocol can not actually handle that case. Also fix format error in xl pci-list-assignable. Signed-off-by: Gianni Tedesco Signed-off-by: Stefano Stabellini --- tools/libxl/libxl.h | 2 + tools/libxl/libxl_pci.c | 149 ++++++++++++++++++++++++++++++++++++--- tools/libxl/xl_cmdimpl.c | 2 +- 3 files changed, 141 insertions(+), 12 deletions(-) diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 46b949d6fa..93c855aa57 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -310,6 +310,8 @@ typedef struct { }; unsigned int domain; unsigned int vdevfn; +#define LIBXL_PCI_FUNC_ALL (~0U) + unsigned int vfunc_mask; bool msitranslate; bool power_mgmt; } libxl_device_pci; diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c index c4dc0e4146..41dba62572 100644 --- a/tools/libxl/libxl_pci.c +++ b/tools/libxl/libxl_pci.c @@ -136,8 +136,13 @@ int libxl_device_pci_parse_bdf(libxl_ctx *ctx, libxl_device_pci *pcidev, const c break; } *ptr = '\0'; - if ( hex_convert(tok, &func, 0x7) ) - goto parse_error; + if ( !strcmp(tok, "*") ) { + pcidev->vfunc_mask = LIBXL_PCI_FUNC_ALL; + }else{ + if ( hex_convert(tok, &func, 0x7) ) + goto parse_error; + pcidev->vfunc_mask = (1 << 0); + } tok = ptr + 1; } break; @@ -187,7 +192,6 @@ int libxl_device_pci_parse_bdf(libxl_ctx *ctx, libxl_device_pci *pcidev, const c return 0; parse_error: - printf("parse error: %s\n", str); return ERROR_INVAL; } @@ -531,6 +535,55 @@ int libxl_device_pci_list_assignable(libxl_ctx *ctx, libxl_device_pci **list, in return 0; } +/* + * This function checks that all functions of a device are bound to pciback + * driver. It also initialises a bit-mask of which function numbers are present + * on that device. +*/ +static int pci_multifunction_check(libxl_ctx *ctx, libxl_device_pci *pcidev, unsigned int *func_mask) +{ + struct dirent *de; + DIR *dir; + + *func_mask = 0; + + dir = opendir(SYSFS_PCI_DEV); + if ( NULL == dir ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't open %s", SYSFS_PCI_DEV); + return -1; + } + + while( (de = readdir(dir)) ) { + unsigned dom, bus, dev, func; + struct stat st; + char *path; + + if ( sscanf(de->d_name, PCI_BDF, &dom, &bus, &dev, &func) != 4 ) + continue; + if ( pcidev->domain != dom ) + continue; + if ( pcidev->bus != bus ) + continue; + if ( pcidev->dev != dev ) + continue; + + path = libxl_sprintf(ctx, "%s/" PCI_BDF, SYSFS_PCIBACK_DRIVER, dom, bus, dev, func); + if ( lstat(path, &st) ) { + if ( errno == ENOENT ) + XL_LOG(ctx, XL_LOG_ERROR, PCI_BDF " is not assigned to pciback driver", + dom, bus, dev, func); + else + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't lstat %s", path); + closedir(dir); + return -1; + } + (*func_mask) |= (1 << func); + } + + closedir(dir); + return 0; +} + static int pci_ins_check(libxl_ctx *ctx, uint32_t domid, const char *state, void *priv) { char *orig_state = priv; @@ -652,8 +705,9 @@ out: int libxl_device_pci_add(libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) { + unsigned int orig_vdev, pfunc_mask; libxl_device_pci *assigned; - int num_assigned, rc; + int num_assigned, rc, i; int stubdomid = 0; rc = get_all_assigned_devices(ctx, &assigned, &num_assigned); @@ -679,10 +733,43 @@ int libxl_device_pci_add(libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcide return rc; } - return do_pci_add(ctx, domid, pcidev); + orig_vdev = pcidev->vdevfn & ~7U; + + if ( pcidev->vfunc_mask == LIBXL_PCI_FUNC_ALL ) { + if ( !(pcidev->vdevfn >> 3) ) { + XL_LOG(ctx, XL_LOG_ERROR, "Must specify a v-slot for multi-function devices"); + return ERROR_INVAL; + } + if ( pci_multifunction_check(ctx, pcidev, &pfunc_mask) ) { + return ERROR_FAIL; + } + pcidev->vfunc_mask &= pfunc_mask; + /* so now vfunc_mask == pfunc_mask */ + }else{ + pfunc_mask = (1 << pcidev->func); + } + + for(i = 7; i >= 0; --i) { + if ( (1 << i) & pfunc_mask ) { + if ( pcidev->vfunc_mask == pfunc_mask ) { + pcidev->func = i; + pcidev->vdevfn = orig_vdev | i; + }else{ + /* if not passing through multiple devices in a block make + * sure that virtual function number 0 is always used otherwise + * guest won't see the device + */ + pcidev->vdevfn = orig_vdev; + } + if ( do_pci_add(ctx, domid, pcidev) ) + rc = ERROR_FAIL; + } + } + + return rc; } -int libxl_device_pci_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) +static int do_pci_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) { libxl_device_pci *assigned; char *path; @@ -711,10 +798,15 @@ int libxl_device_pci_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pc libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func); path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid); - xs_write(ctx->xsh, XBT_NULL, path, "pci-rem", strlen("pci-rem")); - if (libxl_wait_for_device_model(ctx, domid, "pci-removed", NULL, NULL) < 0) { - XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time"); - return ERROR_FAIL; + + /* Remove all functions at once atomically by only signalling + * device-model for function 0 */ + if ( (pcidev->vdevfn & 0x7) == 0 ) { + xs_write(ctx->xsh, XBT_NULL, path, "pci-rem", strlen("pci-rem")); + if (libxl_wait_for_device_model(ctx, domid, "pci-removed", NULL, NULL) < 0) { + XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time"); + return ERROR_FAIL; + } } path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid); xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state)); @@ -769,7 +861,10 @@ skip1: fclose(f); } out: - libxl_device_pci_reset(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func); + /* don't do multiple resets while some functions are still passed through */ + if ( (pcidev->vdevfn & 0x7) == 0 ) { + libxl_device_pci_reset(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func); + } if (!libxl_is_stubdom(ctx, domid, NULL)) { rc = xc_deassign_device(ctx->xch, domid, pcidev->value); @@ -786,6 +881,38 @@ out: return 0; } +int libxl_device_pci_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) +{ + unsigned int orig_vdev, pfunc_mask; + int i, rc; + + orig_vdev = pcidev->vdevfn & ~7U; + + if ( pcidev->vfunc_mask == LIBXL_PCI_FUNC_ALL ) { + if ( pci_multifunction_check(ctx, pcidev, &pfunc_mask) ) { + return ERROR_FAIL; + } + pcidev->vfunc_mask &= pfunc_mask; + }else{ + pfunc_mask = (1 << pcidev->func); + } + + for(i = 7; i >= 0; --i) { + if ( (1 << i) & pfunc_mask ) { + if ( pcidev->vfunc_mask == pfunc_mask ) { + pcidev->func = i; + pcidev->vdevfn = orig_vdev | i; + }else{ + pcidev->vdevfn = orig_vdev; + } + if ( do_pci_remove(ctx, domid, pcidev) ) + rc = ERROR_FAIL; + } + } + + return rc; +} + int libxl_device_pci_list_assigned(libxl_ctx *ctx, libxl_device_pci **list, uint32_t domid, int *num) { char *be_path, *num_devs, *xsdev, *xsvdevfn, *xsopts; diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index b1f8d71d36..f576bb3fdc 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -1931,7 +1931,7 @@ void pcilist_assignable(void) if ( libxl_device_pci_list_assignable(&ctx, &pcidevs, &num) ) return; for (i = 0; i < num; i++) { - printf("%04x:%02x:%02x:%01x\n", + printf("%04x:%02x:%02x.%01x\n", pcidevs[i].domain, pcidevs[i].bus, pcidevs[i].dev, pcidevs[i].func); } free(pcidevs);