const char *libxl__domain_device_model(libxl__gc *gc, const libxl_domain_build_info *info) { libxl_ctx *ctx = libxl__gc_owner(gc); const char *dm; if (libxl_defbool_val(info->device_model_stubdomain)) return NULL; if (info->device_model) { dm = libxl__strdup(gc, info->device_model); } else { switch (info->device_model_version) { case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL: dm = libxl__abs_path(gc, "qemu-dm", libxl__libexec_path()); break; case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN: dm = libxl__abs_path(gc, "qemu-system-i386", libxl__libexec_path()); break; default: LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "invalid device model version %d\n", info->device_model_version); dm = NULL; break; } } return dm; }
static int libxl_build_xenpv_qemu_args(libxl__gc *gc, uint32_t domid, libxl_device_vfb *vfb, libxl_device_model_info *info) { libxl_ctx *ctx = libxl__gc_owner(gc); memset(info, 0x00, sizeof(libxl_device_model_info)); if (vfb != NULL) { info->vnc = vfb->vnc; if (vfb->vnclisten) info->vnclisten = libxl__strdup(gc, vfb->vnclisten); info->vncdisplay = vfb->vncdisplay; info->vncunused = vfb->vncunused; if (vfb->vncpasswd) info->vncpasswd = vfb->vncpasswd; if (vfb->keymap) info->keymap = libxl__strdup(gc, vfb->keymap); info->sdl = vfb->sdl; info->opengl = vfb->opengl; } else info->nographic = 1; info->domid = domid; info->dom_name = libxl_domid_to_name(ctx, domid); info->device_model = libxl__abs_path(gc, "qemu-dm", libxl_libexec_path()); info->type = XENPV; return 0; }
static const char *qemu_xen_path(libxl__gc *gc) { #ifdef QEMU_XEN_PATH return QEMU_XEN_PATH; #else return libxl__abs_path(gc, "qemu-system-i386", libxl__libexec_path()); #endif }
static void bootloader_disk_attached_cb(libxl__egc *egc, libxl__disk_local_state *dls, int rc) { STATE_AO_GC(dls->ao); libxl__bootloader_state *bl = CONTAINER_OF(dls, *bl, dls); const libxl_domain_build_info *info = bl->info; const char *bootloader; if (rc) { LOG(ERROR, "failed to attach local disk for bootloader execution"); goto out; } LOG(DEBUG, "Config bootloader value: %s", info->u.pv.bootloader); if ( !strcmp(info->u.pv.bootloader, "/usr/bin/pygrub") ) LOG(WARN, "bootloader='/usr/bin/pygrub' is deprecated; use " \ "bootloader='pygrub' instead"); bootloader = info->u.pv.bootloader; /* If the full path is not specified, check in the libexec path */ if ( bootloader[0] != '/' ) { const char *bltmp; struct stat st; bltmp = libxl__abs_path(gc, bootloader, libxl__private_bindir_path()); /* Check to see if the file exists in this location; if not, * fall back to checking the path */ LOG(DEBUG, "Checking for bootloader in libexec path: %s", bltmp); if ( lstat(bltmp, &st) ) LOG(DEBUG, "%s doesn't exist, falling back to config path", bltmp); else bootloader = bltmp; } make_bootloader_args(gc, bl, bootloader); bl->openpty.ao = ao; bl->openpty.callback = bootloader_gotptys; bl->openpty.count = 2; bl->openpty.results = bl->ptys; rc = libxl__openptys(&bl->openpty, 0,0); if (rc) goto out; return; out: assert(rc); bootloader_callback(egc, bl, rc); }
void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state *sdss) { STATE_AO_GC(sdss->dm.spawn.ao); libxl_ctx *ctx = libxl__gc_owner(gc); int ret; libxl_device_vfb *vfb; libxl_device_vkb *vkb; char **args; struct xs_permissions perm[2]; xs_transaction_t t; /* convenience aliases */ libxl_domain_config *const dm_config = &sdss->dm_config; libxl_domain_config *const guest_config = sdss->dm.guest_config; const int guest_domid = sdss->dm.guest_domid; libxl__domain_build_state *const d_state = sdss->dm.build_state; libxl__domain_build_state *const stubdom_state = &sdss->dm_state; if (guest_config->b_info.device_model_version != LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL) { ret = ERROR_INVAL; goto out; } sdss->pvqemu.guest_domid = 0; libxl_domain_create_info_init(&dm_config->c_info); dm_config->c_info.type = LIBXL_DOMAIN_TYPE_PV; dm_config->c_info.name = libxl__stub_dm_name(gc, libxl__domid_to_name(gc, guest_domid)); dm_config->c_info.ssidref = guest_config->b_info.device_model_ssidref; libxl_uuid_generate(&dm_config->c_info.uuid); libxl_domain_build_info_init(&dm_config->b_info); libxl_domain_build_info_init_type(&dm_config->b_info, LIBXL_DOMAIN_TYPE_PV); dm_config->b_info.max_vcpus = 1; dm_config->b_info.max_memkb = 32 * 1024; dm_config->b_info.target_memkb = dm_config->b_info.max_memkb; dm_config->b_info.u.pv.features = ""; dm_config->b_info.device_model_version = guest_config->b_info.device_model_version; dm_config->b_info.device_model = guest_config->b_info.device_model; dm_config->b_info.extra = guest_config->b_info.extra; dm_config->b_info.extra_pv = guest_config->b_info.extra_pv; dm_config->b_info.extra_hvm = guest_config->b_info.extra_hvm; dm_config->disks = guest_config->disks; dm_config->num_disks = guest_config->num_disks; libxl__dm_vifs_from_hvm_guest_config(gc, guest_config, dm_config); dm_config->c_info.run_hotplug_scripts = guest_config->c_info.run_hotplug_scripts; ret = libxl__domain_create_info_setdefault(gc, &dm_config->c_info); if (ret) goto out; ret = libxl__domain_build_info_setdefault(gc, &dm_config->b_info); if (ret) goto out; GCNEW(vfb); GCNEW(vkb); libxl__vfb_and_vkb_from_hvm_guest_config(gc, guest_config, vfb, vkb); dm_config->vfbs = vfb; dm_config->num_vfbs = 1; dm_config->vkbs = vkb; dm_config->num_vkbs = 1; stubdom_state->pv_kernel.path = libxl__abs_path(gc, "ioemu-stubdom.gz", libxl__xenfirmwaredir_path()); stubdom_state->pv_cmdline = libxl__sprintf(gc, " -d %d", guest_domid); stubdom_state->pv_ramdisk.path = ""; /* fixme: this function can leak the stubdom if it fails */ ret = libxl__domain_make(gc, &dm_config->c_info, &sdss->pvqemu.guest_domid); if (ret) goto out; uint32_t dm_domid = sdss->pvqemu.guest_domid; ret = libxl__domain_build(gc, dm_config, dm_domid, stubdom_state); if (ret) goto out; args = libxl__build_device_model_args(gc, "stubdom-dm", guest_domid, guest_config, d_state); if (!args) { ret = ERROR_FAIL; goto out; } libxl__write_stub_dmargs(gc, dm_domid, guest_domid, args); libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/image/device-model-domid", libxl__xs_get_dompath(gc, guest_domid)), "%d", dm_domid); libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/target", libxl__xs_get_dompath(gc, dm_domid)), "%d", guest_domid); ret = xc_domain_set_target(ctx->xch, dm_domid, guest_domid); if (ret<0) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "setting target domain %d -> %d", dm_domid, guest_domid); ret = ERROR_FAIL; goto out; } xs_set_target(ctx->xsh, dm_domid, guest_domid); perm[0].id = dm_domid; perm[0].perms = XS_PERM_NONE; perm[1].id = guest_domid; perm[1].perms = XS_PERM_READ; retry_transaction: t = xs_transaction_start(ctx->xsh); xs_mkdir(ctx->xsh, t, libxl__sprintf(gc, "/local/domain/0/device-model/%d", guest_domid)); xs_set_permissions(ctx->xsh, t, libxl__sprintf(gc, "/local/domain/0/device-model/%d", guest_domid), perm, ARRAY_SIZE(perm)); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; libxl__multidev_begin(ao, &sdss->multidev); sdss->multidev.callback = spawn_stub_launch_dm; libxl__add_disks(egc, ao, dm_domid, dm_config, &sdss->multidev); libxl__multidev_prepared(egc, &sdss->multidev, 0); return; out: assert(ret); spawn_stubdom_pvqemu_cb(egc, &sdss->pvqemu, ret); }
static void libxl__device_nic_add(libxl__egc *egc, uint32_t domid, libxl_device_nic *nic, libxl__ao_device *aodev) { STATE_AO_GC(aodev->ao); flexarray_t *front; flexarray_t *back; libxl__device *device; int rc; xs_transaction_t t = XBT_NULL; libxl_domain_config d_config; libxl_device_nic nic_saved; libxl__domain_userdata_lock *lock = NULL; libxl_domain_config_init(&d_config); libxl_device_nic_init(&nic_saved); libxl_device_nic_copy(CTX, &nic_saved, nic); rc = libxl__device_nic_setdefault(gc, nic, domid, aodev->update_json); if (rc) goto out; front = flexarray_make(gc, 16, 1); back = flexarray_make(gc, 18, 1); if (nic->devid == -1) { if ((nic->devid = libxl__device_nextid(gc, domid, "vif")) < 0) { rc = ERROR_FAIL; goto out; } } libxl__update_config_nic(gc, &nic_saved, nic); GCNEW(device); rc = libxl__device_from_nic(gc, domid, nic, device); if ( rc != 0 ) goto out; flexarray_append(back, "frontend-id"); flexarray_append(back, GCSPRINTF("%d", domid)); flexarray_append(back, "online"); flexarray_append(back, "1"); flexarray_append(back, "state"); flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising)); if (nic->script) flexarray_append_pair(back, "script", libxl__abs_path(gc, nic->script, libxl__xen_script_dir_path())); if (nic->ifname) { flexarray_append(back, "vifname"); flexarray_append(back, nic->ifname); } if (nic->coloft_forwarddev) { flexarray_append(back, "forwarddev"); flexarray_append(back, nic->coloft_forwarddev); } flexarray_append(back, "mac"); flexarray_append(back,GCSPRINTF(LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac))); if (nic->ip) { flexarray_append(back, "ip"); flexarray_append(back, libxl__strdup(gc, nic->ip)); } if (nic->gatewaydev) { flexarray_append(back, "gatewaydev"); flexarray_append(back, libxl__strdup(gc, nic->gatewaydev)); } if (nic->rate_interval_usecs > 0) { flexarray_append(back, "rate"); flexarray_append(back, GCSPRINTF("%"PRIu64",%"PRIu32"", nic->rate_bytes_per_interval, nic->rate_interval_usecs)); } flexarray_append(back, "bridge"); flexarray_append(back, libxl__strdup(gc, nic->bridge)); flexarray_append(back, "handle"); flexarray_append(back, GCSPRINTF("%d", nic->devid)); flexarray_append(back, "type"); flexarray_append(back, libxl__strdup(gc, libxl_nic_type_to_string(nic->nictype))); flexarray_append(front, "backend-id"); flexarray_append(front, GCSPRINTF("%d", nic->backend_domid)); flexarray_append(front, "state"); flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising)); flexarray_append(front, "handle"); flexarray_append(front, GCSPRINTF("%d", nic->devid)); flexarray_append(front, "mac"); flexarray_append(front, GCSPRINTF( LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac))); if (aodev->update_json) { lock = libxl__lock_domain_userdata(gc, domid); if (!lock) { rc = ERROR_LOCK_FAIL; goto out; } rc = libxl__get_domain_configuration(gc, domid, &d_config); if (rc) goto out; DEVICE_ADD(nic, nics, domid, &nic_saved, COMPARE_DEVID, &d_config); rc = libxl__dm_check_start(gc, &d_config, domid); if (rc) goto out; } for (;;) { rc = libxl__xs_transaction_start(gc, &t); if (rc) goto out; rc = libxl__device_exists(gc, t, device); if (rc < 0) goto out; if (rc == 1) { /* already exists in xenstore */ LOG(ERROR, "device already exists in xenstore"); aodev->action = LIBXL__DEVICE_ACTION_ADD; /* for error message */ rc = ERROR_DEVICE_EXISTS; goto out; } if (aodev->update_json) { rc = libxl__set_domain_configuration(gc, domid, &d_config); if (rc) goto out; } libxl__device_generic_add(gc, t, device, libxl__xs_kvs_of_flexarray(gc, back, back->count), libxl__xs_kvs_of_flexarray(gc, front, front->count), NULL); rc = libxl__xs_transaction_commit(gc, &t); if (!rc) break; if (rc < 0) goto out; } aodev->dev = device; aodev->action = LIBXL__DEVICE_ACTION_ADD; libxl__wait_device_connection(egc, aodev); rc = 0; out: libxl__xs_transaction_abort(gc, &t); if (lock) libxl__unlock_domain_userdata(lock); libxl_device_nic_dispose(&nic_saved); libxl_domain_config_dispose(&d_config); aodev->rc = rc; if (rc) aodev->callback(egc, aodev); return; }
int libxl__create_device_model(libxl_ctx *ctx, libxl_device_model_info *info, libxl_device_disk *disks, int num_disks, libxl_device_nic *vifs, int num_vifs, libxl__device_model_starting **starting_r) { libxl__gc gc = LIBXL_INIT_GC(ctx); char *path, *logfile; int logfile_w, null; int rc; char **args; libxl__device_model_starting buf_starting, *p; xs_transaction_t t; char *vm_path; char **pass_stuff; if (strstr(info->device_model, "stubdom-dm")) { libxl_device_vfb vfb; libxl_device_vkb vkb; libxl_vfb_and_vkb_from_device_model_info(ctx, info, &vfb, &vkb); rc = libxl_create_stubdom(ctx, info, disks, num_disks, vifs, num_vifs, &vfb, &vkb, starting_r); goto out; } args = libxl_build_device_model_args(&gc, info, vifs, num_vifs); if (!args) { rc = ERROR_FAIL; goto out; } path = libxl__sprintf(&gc, "/local/domain/0/device-model/%d", info->domid); xs_mkdir(ctx->xsh, XBT_NULL, path); libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/disable_pf", path), "%d", !info->xen_platform_pci); libxl_create_logfile(ctx, libxl__sprintf(&gc, "qemu-dm-%s", info->dom_name), &logfile); logfile_w = open(logfile, O_WRONLY|O_CREAT, 0644); free(logfile); null = open("/dev/null", O_RDONLY); if (starting_r) { rc = ERROR_NOMEM; *starting_r = calloc(sizeof(libxl__device_model_starting), 1); if (!*starting_r) goto out_close; p = *starting_r; p->for_spawn = calloc(sizeof(libxl__spawn_starting), 1); } else { p = &buf_starting; p->for_spawn = NULL; } p->domid = info->domid; p->dom_path = libxl__xs_get_dompath(&gc, info->domid); if (!p->dom_path) { rc = ERROR_FAIL; goto out_close; } if (info->vncpasswd) { retry_transaction: /* Find uuid and the write the vnc password to xenstore for qemu. */ t = xs_transaction_start(ctx->xsh); vm_path = libxl__xs_read(&gc,t,libxl__sprintf(&gc, "%s/vm", p->dom_path)); if (vm_path) { /* Now write the vncpassword into it. */ pass_stuff = libxl__calloc(&gc, 3, sizeof(char *)); pass_stuff[0] = "vncpasswd"; pass_stuff[1] = info->vncpasswd; libxl__xs_writev(&gc,t,vm_path,pass_stuff); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; } } rc = libxl__spawn_spawn(ctx, p, "device model", dm_xenstore_record_pid); if (rc < 0) goto out_close; if (!rc) { /* inner child */ setsid(); libxl__exec(null, logfile_w, logfile_w, libxl__abs_path(&gc, info->device_model, libxl_libexec_path()), args); } rc = 0; out_close: close(null); close(logfile_w); free(args); out: libxl__free_all(&gc); return rc; }
static int libxl_create_stubdom(libxl_ctx *ctx, libxl_device_model_info *info, libxl_device_disk *disks, int num_disks, libxl_device_nic *vifs, int num_vifs, libxl_device_vfb *vfb, libxl_device_vkb *vkb, libxl__device_model_starting **starting_r) { libxl__gc gc = LIBXL_INIT_GC(ctx); int i, num_console = STUBDOM_SPECIAL_CONSOLES, ret; libxl_device_console *console; libxl_domain_create_info c_info; libxl_domain_build_info b_info; libxl_domain_build_state state; uint32_t domid; char **args; struct xs_permissions perm[2]; xs_transaction_t t; libxl__device_model_starting *dm_starting = 0; args = libxl_build_device_model_args(&gc, info, vifs, num_vifs); if (!args) { ret = ERROR_FAIL; goto out; } memset(&c_info, 0x00, sizeof(libxl_domain_create_info)); c_info.hvm = 0; c_info.name = libxl__sprintf(&gc, "%s-dm", libxl__domid_to_name(&gc, info->domid)); libxl_uuid_copy(&c_info.uuid, &info->uuid); memset(&b_info, 0x00, sizeof(libxl_domain_build_info)); b_info.max_vcpus = 1; b_info.max_memkb = 32 * 1024; b_info.target_memkb = b_info.max_memkb; b_info.kernel.path = libxl__abs_path(&gc, "ioemu-stubdom.gz", libxl_xenfirmwaredir_path()); b_info.u.pv.cmdline = libxl__sprintf(&gc, " -d %d", info->domid); b_info.u.pv.ramdisk.path = ""; b_info.u.pv.features = ""; b_info.hvm = 0; /* fixme: this function can leak the stubdom if it fails */ ret = libxl__domain_make(ctx, &c_info, &domid); if (ret) goto out_free; ret = libxl__domain_build(ctx, &b_info, domid, &state); if (ret) goto out_free; libxl_write_dmargs(ctx, domid, info->domid, args); libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/image/device-model-domid", libxl__xs_get_dompath(&gc, info->domid)), "%d", domid); libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/target", libxl__xs_get_dompath(&gc, domid)), "%d", info->domid); ret = xc_domain_set_target(ctx->xch, domid, info->domid); if (ret<0) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "setting target domain %d -> %d", domid, info->domid); ret = ERROR_FAIL; goto out_free; } xs_set_target(ctx->xsh, domid, info->domid); perm[0].id = domid; perm[0].perms = XS_PERM_NONE; perm[1].id = info->domid; perm[1].perms = XS_PERM_READ; retry_transaction: t = xs_transaction_start(ctx->xsh); xs_mkdir(ctx->xsh, t, libxl__sprintf(&gc, "/local/domain/0/device-model/%d", info->domid)); xs_set_permissions(ctx->xsh, t, libxl__sprintf(&gc, "/local/domain/0/device-model/%d", info->domid), perm, ARRAY_SIZE(perm)); xs_mkdir(ctx->xsh, t, libxl__sprintf(&gc, "/local/domain/%d/device/vfs", domid)); xs_set_permissions(ctx->xsh, t, libxl__sprintf(&gc, "/local/domain/%d/device/vfs",domid), perm, ARRAY_SIZE(perm)); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; for (i = 0; i < num_disks; i++) { disks[i].domid = domid; ret = libxl_device_disk_add(ctx, domid, &disks[i]); if (ret) goto out_free; } for (i = 0; i < num_vifs; i++) { vifs[i].domid = domid; ret = libxl_device_nic_add(ctx, domid, &vifs[i]); if (ret) goto out_free; } vfb->domid = domid; ret = libxl_device_vfb_add(ctx, domid, vfb); if (ret) goto out_free; vkb->domid = domid; ret = libxl_device_vkb_add(ctx, domid, vkb); if (ret) goto out_free; if (info->serial) num_console++; console = libxl__calloc(&gc, num_console, sizeof(libxl_device_console)); if (!console) { ret = ERROR_NOMEM; goto out_free; } for (i = 0; i < num_console; i++) { console[i].devid = i; console[i].consback = LIBXL_CONSBACK_IOEMU; console[i].domid = domid; /* STUBDOM_CONSOLE_LOGGING (console 0) is for minios logging * STUBDOM_CONSOLE_SAVE (console 1) is for writing the save file * STUBDOM_CONSOLE_RESTORE (console 2) is for reading the save file */ switch (i) { char *filename; char *name; case STUBDOM_CONSOLE_LOGGING: name = libxl__sprintf(&gc, "qemu-dm-%s", libxl_domid_to_name(ctx, info->domid)); libxl_create_logfile(ctx, name, &filename); console[i].output = libxl__sprintf(&gc, "file:%s", filename); console[i].build_state = &state; free(filename); break; case STUBDOM_CONSOLE_SAVE: console[i].output = libxl__sprintf(&gc, "file:"SAVEFILE".%d", info->domid); break; case STUBDOM_CONSOLE_RESTORE: if (info->saved_state) console[i].output = libxl__sprintf(&gc, "pipe:%s", info->saved_state); break; default: console[i].output = "pty"; break; } ret = libxl_device_console_add(ctx, domid, &console[i]); if (ret) goto out_free; } if (libxl__create_xenpv_qemu(ctx, domid, vfb, &dm_starting) < 0) { ret = ERROR_FAIL; goto out_free; } if (libxl__confirm_device_model_startup(ctx, dm_starting) < 0) { ret = ERROR_FAIL; goto out_free; } libxl_domain_unpause(ctx, domid); if (starting_r) { *starting_r = calloc(sizeof(libxl__device_model_starting), 1); (*starting_r)->domid = info->domid; (*starting_r)->dom_path = libxl__xs_get_dompath(&gc, info->domid); (*starting_r)->for_spawn = NULL; } ret = 0; out_free: free(args); out: libxl__free_all(&gc); return ret; }