debuggers.hg

view tools/libxl/libxl.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents b59f04eb8978
children eefb8e971be5
line source
1 /*
2 * Copyright (C) 2009 Citrix Ltd.
3 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
4 * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; version 2.1 only. with the special
9 * exception on linking described in file LICENSE.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 */
17 #include "libxl_osdeps.h"
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <sys/select.h>
26 #include <sys/wait.h>
27 #include <sys/time.h>
28 #include <signal.h>
29 #include <unistd.h> /* for write, unlink and close */
30 #include <stdint.h>
31 #include <inttypes.h>
32 #include <assert.h>
34 #include "libxl.h"
35 #include "libxl_utils.h"
36 #include "libxl_internal.h"
37 #include "flexarray.h"
39 #define PAGE_TO_MEMKB(pages) ((pages) * 4)
41 int libxl_ctx_init(libxl_ctx *ctx, int version, xentoollog_logger *lg)
42 {
43 if (version != LIBXL_VERSION)
44 return ERROR_VERSION;
45 memset(ctx, 0, sizeof(libxl_ctx));
46 ctx->lg = lg;
47 memset(&ctx->version_info, 0, sizeof(libxl_version_info));
49 ctx->xch = xc_interface_open(lg,lg,0);
50 if (!ctx->xch) {
51 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, errno,
52 "cannot open libxc handle");
53 return ERROR_FAIL;
54 }
56 ctx->xsh = xs_daemon_open();
57 if (!ctx->xsh)
58 ctx->xsh = xs_domain_open();
59 if (!ctx->xsh) {
60 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, errno,
61 "cannot connect to xenstore");
62 xc_interface_close(ctx->xch);
63 return ERROR_FAIL;
64 }
65 return 0;
66 }
68 int libxl_ctx_free(libxl_ctx *ctx)
69 {
70 if (ctx->xch) xc_interface_close(ctx->xch);
71 libxl_version_info_destroy(&ctx->version_info);
72 if (ctx->xsh) xs_daemon_close(ctx->xsh);
73 return 0;
74 }
76 void libxl_string_list_destroy(libxl_string_list *psl)
77 {
78 int i;
79 libxl_string_list sl = *psl;
81 if (!sl)
82 return;
84 for (i = 0; sl[i] != NULL; i++)
85 free(sl[i]);
86 free(sl);
87 }
89 void libxl_key_value_list_destroy(libxl_key_value_list *pkvl)
90 {
91 int i;
92 libxl_key_value_list kvl = *pkvl;
94 if (!kvl)
95 return;
97 for (i = 0; kvl[i] != NULL; i += 2) {
98 free(kvl[i]);
99 if (kvl[i + 1])
100 free(kvl[i + 1]);
101 }
102 free(kvl);
103 }
105 /******************************************************************************/
108 int libxl_domain_rename(libxl_ctx *ctx, uint32_t domid,
109 const char *old_name, const char *new_name,
110 xs_transaction_t trans)
111 {
112 libxl__gc gc = LIBXL_INIT_GC(ctx);
113 char *dom_path = 0;
114 const char *name_path;
115 char *got_old_name;
116 unsigned int got_old_len;
117 xs_transaction_t our_trans = 0;
118 int rc;
120 dom_path = libxl__xs_get_dompath(&gc, domid);
121 if (!dom_path) goto x_nomem;
123 name_path= libxl__sprintf(&gc, "%s/name", dom_path);
124 if (!name_path) goto x_nomem;
126 retry_transaction:
127 if (!trans) {
128 trans = our_trans = xs_transaction_start(ctx->xsh);
129 if (!our_trans) {
130 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, errno,
131 "create xs transaction for domain (re)name");
132 goto x_fail;
133 }
134 }
136 if (old_name) {
137 got_old_name = xs_read(ctx->xsh, trans, name_path, &got_old_len);
138 if (!got_old_name) {
139 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, errno, "check old name"
140 " for domain %"PRIu32" allegedly named `%s'",
141 domid, old_name);
142 goto x_fail;
143 }
144 if (strcmp(old_name, got_old_name)) {
145 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "domain %"PRIu32" allegedly named "
146 "`%s' is actually named `%s' - racing ?",
147 domid, old_name, got_old_name);
148 free(got_old_name);
149 goto x_fail;
150 }
151 free(got_old_name);
152 }
153 if (!xs_write(ctx->xsh, trans, name_path,
154 new_name, strlen(new_name))) {
155 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "failed to write new name `%s'"
156 " for domain %"PRIu32" previously named `%s'",
157 new_name, domid, old_name);
158 goto x_fail;
159 }
161 if (our_trans) {
162 if (!xs_transaction_end(ctx->xsh, our_trans, 0)) {
163 trans = our_trans = 0;
164 if (errno != EAGAIN) {
165 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "failed to commit new name `%s'"
166 " for domain %"PRIu32" previously named `%s'",
167 new_name, domid, old_name);
168 goto x_fail;
169 }
170 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "need to retry rename transaction"
171 " for domain %"PRIu32" (name_path=\"%s\", new_name=\"%s\")",
172 domid, name_path, new_name);
173 goto retry_transaction;
174 }
175 our_trans = 0;
176 }
178 rc = 0;
179 x_rc:
180 if (our_trans) xs_transaction_end(ctx->xsh, our_trans, 1);
181 libxl__free_all(&gc);
182 return rc;
184 x_fail: rc = ERROR_FAIL; goto x_rc;
185 x_nomem: rc = ERROR_NOMEM; goto x_rc;
186 }
188 int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid)
189 {
190 libxl__gc gc = LIBXL_INIT_GC(ctx);
191 int rc = 0;
193 if (libxl__domain_is_hvm(ctx, domid)) {
194 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Called domain_resume on "
195 "non-cooperative hvm domain %u", domid);
196 rc = ERROR_NI;
197 goto out;
198 }
199 if (xc_domain_resume(ctx->xch, domid, 1)) {
200 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
201 "xc_domain_resume failed for domain %u",
202 domid);
203 rc = ERROR_FAIL;
204 goto out;
205 }
206 if (!xs_resume_domain(ctx->xsh, domid)) {
207 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
208 "xs_resume_domain failed for domain %u",
209 domid);
210 rc = ERROR_FAIL;
211 }
212 out:
213 libxl__free_all(&gc);
214 return 0;
215 }
217 /*
218 * Preserves a domain but rewrites xenstore etc to make it unique so
219 * that the domain can be restarted.
220 *
221 * Does not modify info so that it may be reused.
222 */
223 int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid,
224 libxl_domain_create_info *info, const char *name_suffix, libxl_uuid new_uuid)
225 {
226 libxl__gc gc = LIBXL_INIT_GC(ctx);
227 struct xs_permissions roperm[2];
228 xs_transaction_t t;
229 char *preserved_name;
230 char *uuid_string;
231 char *vm_path;
232 char *dom_path;
234 int rc;
236 preserved_name = libxl__sprintf(&gc, "%s%s", info->name, name_suffix);
237 if (!preserved_name) {
238 libxl__free_all(&gc);
239 return ERROR_NOMEM;
240 }
242 uuid_string = libxl__uuid2string(&gc, new_uuid);
243 if (!uuid_string) {
244 libxl__free_all(&gc);
245 return ERROR_NOMEM;
246 }
248 dom_path = libxl__xs_get_dompath(&gc, domid);
249 if (!dom_path) {
250 libxl__free_all(&gc);
251 return ERROR_FAIL;
252 }
254 vm_path = libxl__sprintf(&gc, "/vm/%s", uuid_string);
255 if (!vm_path) {
256 libxl__free_all(&gc);
257 return ERROR_FAIL;
258 }
260 roperm[0].id = 0;
261 roperm[0].perms = XS_PERM_NONE;
262 roperm[1].id = domid;
263 roperm[1].perms = XS_PERM_READ;
265 retry_transaction:
266 t = xs_transaction_start(ctx->xsh);
268 xs_rm(ctx->xsh, t, vm_path);
269 xs_mkdir(ctx->xsh, t, vm_path);
270 xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
272 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/vm", dom_path), vm_path, strlen(vm_path));
273 rc = libxl_domain_rename(ctx, domid, info->name, preserved_name, t);
274 if (rc) {
275 libxl__free_all(&gc);
276 return rc;
277 }
279 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
281 if (!xs_transaction_end(ctx->xsh, t, 0))
282 if (errno == EAGAIN)
283 goto retry_transaction;
285 libxl__free_all(&gc);
286 return 0;
287 }
289 static void xcinfo2xlinfo(const xc_domaininfo_t *xcinfo,
290 libxl_dominfo *xlinfo)
291 {
292 memcpy(&(xlinfo->uuid), xcinfo->handle, sizeof(xen_domain_handle_t));
293 xlinfo->domid = xcinfo->domain;
295 xlinfo->dying = !!(xcinfo->flags&XEN_DOMINF_dying);
296 xlinfo->shutdown = !!(xcinfo->flags&XEN_DOMINF_shutdown);
297 xlinfo->paused = !!(xcinfo->flags&XEN_DOMINF_paused);
298 xlinfo->blocked = !!(xcinfo->flags&XEN_DOMINF_blocked);
299 xlinfo->running = !!(xcinfo->flags&XEN_DOMINF_running);
301 if (xlinfo->shutdown || xlinfo->dying)
302 xlinfo->shutdown_reason = (xcinfo->flags>>XEN_DOMINF_shutdownshift) & XEN_DOMINF_shutdownmask;
303 else
304 xlinfo->shutdown_reason = ~0;
306 xlinfo->current_memkb = PAGE_TO_MEMKB(xcinfo->tot_pages);
307 xlinfo->max_memkb = PAGE_TO_MEMKB(xcinfo->max_pages);
308 xlinfo->cpu_time = xcinfo->cpu_time;
309 xlinfo->vcpu_max_id = xcinfo->max_vcpu_id;
310 xlinfo->vcpu_online = xcinfo->nr_online_vcpus;
311 }
313 libxl_dominfo * libxl_list_domain(libxl_ctx *ctx, int *nb_domain)
314 {
315 libxl_dominfo *ptr;
316 int i, ret;
317 xc_domaininfo_t info[1024];
318 int size = 1024;
320 ptr = calloc(size, sizeof(libxl_dominfo));
321 if (!ptr) {
322 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "allocating domain info");
323 return NULL;
324 }
326 ret = xc_domain_getinfolist(ctx->xch, 0, 1024, info);
327 if (ret<0) {
328 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "geting domain info list");
329 return NULL;
330 }
332 for (i = 0; i < ret; i++) {
333 xcinfo2xlinfo(&info[i], &ptr[i]);
334 }
335 *nb_domain = ret;
336 return ptr;
337 }
339 int libxl_domain_info(libxl_ctx *ctx, libxl_dominfo *info_r,
340 uint32_t domid) {
341 xc_domaininfo_t xcinfo;
342 int ret;
344 ret = xc_domain_getinfolist(ctx->xch, domid, 1, &xcinfo);
345 if (ret<0) {
346 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "geting domain info list");
347 return ERROR_FAIL;
348 }
349 if (ret==0 || xcinfo.domain != domid) return ERROR_INVAL;
351 xcinfo2xlinfo(&xcinfo, info_r);
352 return 0;
353 }
355 libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx *ctx, int *nb_pool)
356 {
357 libxl_cpupoolinfo *ptr, *tmp;
358 int i;
359 xc_cpupoolinfo_t *info;
360 uint32_t poolid;
362 ptr = NULL;
364 poolid = 0;
365 for (i = 0;; i++) {
366 info = xc_cpupool_getinfo(ctx->xch, poolid);
367 if (info == NULL)
368 break;
369 tmp = realloc(ptr, (i + 1) * sizeof(libxl_cpupoolinfo));
370 if (!tmp) {
371 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "allocating cpupool info");
372 free(ptr);
373 xc_cpupool_infofree(ctx->xch, info);
374 return NULL;
375 }
376 ptr = tmp;
377 ptr[i].poolid = info->cpupool_id;
378 ptr[i].sched_id = info->sched_id;
379 ptr[i].n_dom = info->n_dom;
380 if (libxl_cpumap_alloc(ctx, &ptr[i].cpumap)) {
381 xc_cpupool_infofree(ctx->xch, info);
382 break;
383 }
384 memcpy(ptr[i].cpumap.map, info->cpumap, ptr[i].cpumap.size);
385 poolid = info->cpupool_id + 1;
386 xc_cpupool_infofree(ctx->xch, info);
387 }
389 *nb_pool = i;
390 return ptr;
391 }
393 /* this API call only list VM running on this host. a VM can be an aggregate of multiple domains. */
394 libxl_vminfo * libxl_list_vm(libxl_ctx *ctx, int *nb_vm)
395 {
396 libxl_vminfo *ptr;
397 int index, i, ret;
398 xc_domaininfo_t info[1024];
399 int size = 1024;
401 ptr = calloc(size, sizeof(libxl_dominfo));
402 if (!ptr)
403 return NULL;
405 ret = xc_domain_getinfolist(ctx->xch, 1, 1024, info);
406 if (ret<0) {
407 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "geting domain info list");
408 return NULL;
409 }
410 for (index = i = 0; i < ret; i++) {
411 if (libxl_is_stubdom(ctx, info[i].domain, NULL))
412 continue;
413 memcpy(&(ptr[index].uuid), info[i].handle, sizeof(xen_domain_handle_t));
414 ptr[index].domid = info[i].domain;
416 index++;
417 }
418 *nb_vm = index;
419 return ptr;
420 }
422 int libxl_domain_suspend(libxl_ctx *ctx, libxl_domain_suspend_info *info,
423 uint32_t domid, int fd)
424 {
425 int hvm = libxl__domain_is_hvm(ctx, domid);
426 int live = info != NULL && info->flags & XL_SUSPEND_LIVE;
427 int debug = info != NULL && info->flags & XL_SUSPEND_DEBUG;
428 int rc = 0;
430 rc = libxl__domain_suspend_common(ctx, domid, fd, hvm, live, debug);
431 if (!rc && hvm)
432 rc = libxl__domain_save_device_model(ctx, domid, fd);
433 return rc;
434 }
436 int libxl_domain_pause(libxl_ctx *ctx, uint32_t domid)
437 {
438 int ret;
439 ret = xc_domain_pause(ctx->xch, domid);
440 if (ret<0) {
441 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "pausing domain %d", domid);
442 return ERROR_FAIL;
443 }
444 return 0;
445 }
447 int libxl_domain_core_dump(libxl_ctx *ctx, uint32_t domid,
448 const char *filename)
449 {
450 int ret;
451 ret = xc_domain_dumpcore(ctx->xch, domid, filename);
452 if (ret<0) {
453 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "core dumping domain %d to %s",
454 domid, filename);
455 return ERROR_FAIL;
456 }
457 return 0;
458 }
460 int libxl_domain_unpause(libxl_ctx *ctx, uint32_t domid)
461 {
462 libxl__gc gc = LIBXL_INIT_GC(ctx);
463 char *path;
464 char *state;
465 int ret, rc = 0;
467 if (libxl__domain_is_hvm(ctx, domid)) {
468 path = libxl__sprintf(&gc, "/local/domain/0/device-model/%d/state", domid);
469 state = libxl__xs_read(&gc, XBT_NULL, path);
470 if (state != NULL && !strcmp(state, "paused")) {
471 libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/0/device-model/%d/command", domid), "continue");
472 libxl__wait_for_device_model(ctx, domid, "running", NULL, NULL);
473 }
474 }
475 ret = xc_domain_unpause(ctx->xch, domid);
476 if (ret<0) {
477 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unpausing domain %d", domid);
478 rc = ERROR_FAIL;
479 }
480 libxl__free_all(&gc);
481 return rc;
482 }
484 static char *req_table[] = {
485 [0] = "poweroff",
486 [1] = "reboot",
487 [2] = "suspend",
488 [3] = "crash",
489 [4] = "halt",
490 };
492 int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid, int req)
493 {
494 libxl__gc gc = LIBXL_INIT_GC(ctx);
495 char *shutdown_path;
496 char *dom_path;
498 if (req > ARRAY_SIZE(req_table)) {
499 libxl__free_all(&gc);
500 return ERROR_INVAL;
501 }
503 dom_path = libxl__xs_get_dompath(&gc, domid);
504 if (!dom_path) {
505 libxl__free_all(&gc);
506 return ERROR_FAIL;
507 }
509 if (libxl__domain_is_hvm(ctx,domid)) {
510 unsigned long pvdriver = 0;
511 int ret;
512 ret = xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver);
513 if (ret<0) {
514 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting HVM callback IRQ");
515 libxl__free_all(&gc);
516 return ERROR_FAIL;
517 }
518 if (!pvdriver) {
519 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "HVM domain without PV drivers:"
520 " graceful shutdown not possible, use destroy");
521 libxl__free_all(&gc);
522 return ERROR_FAIL;
523 }
524 }
526 shutdown_path = libxl__sprintf(&gc, "%s/control/shutdown", dom_path);
527 xs_write(ctx->xsh, XBT_NULL, shutdown_path, req_table[req], strlen(req_table[req]));
529 libxl__free_all(&gc);
530 return 0;
531 }
533 int libxl_get_wait_fd(libxl_ctx *ctx, int *fd)
534 {
535 *fd = xs_fileno(ctx->xsh);
536 return 0;
537 }
539 int libxl_wait_for_domain_death(libxl_ctx *ctx, uint32_t domid, libxl_waiter *waiter)
540 {
541 waiter->path = strdup("@releaseDomain");
542 if (asprintf(&(waiter->token), "%d", LIBXL_EVENT_DOMAIN_DEATH) < 0)
543 return -1;
544 if (!xs_watch(ctx->xsh, waiter->path, waiter->token))
545 return -1;
546 return 0;
547 }
549 int libxl_wait_for_disk_ejects(libxl_ctx *ctx, uint32_t guest_domid, libxl_device_disk *disks, int num_disks, libxl_waiter *waiter)
550 {
551 libxl__gc gc = LIBXL_INIT_GC(ctx);
552 int i, rc = -1;
553 uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid);
555 if (!domid)
556 domid = guest_domid;
558 for (i = 0; i < num_disks; i++) {
559 if (asprintf(&(waiter[i].path), "%s/device/vbd/%d/eject",
560 libxl__xs_get_dompath(&gc, domid),
561 libxl__device_disk_dev_number(disks[i].virtpath)) < 0)
562 goto out;
563 if (asprintf(&(waiter[i].token), "%d", LIBXL_EVENT_DISK_EJECT) < 0)
564 goto out;
565 xs_watch(ctx->xsh, waiter->path, waiter->token);
566 }
567 rc = 0;
568 out:
569 libxl__free_all(&gc);
570 return rc;
571 }
573 int libxl_get_event(libxl_ctx *ctx, libxl_event *event)
574 {
575 unsigned int num;
576 char **events = xs_read_watch(ctx->xsh, &num);
577 if (num != 2) {
578 free(events);
579 return ERROR_FAIL;
580 }
581 event->path = strdup(events[XS_WATCH_PATH]);
582 event->token = strdup(events[XS_WATCH_TOKEN]);
583 event->type = atoi(event->token);
584 free(events);
585 return 0;
586 }
588 int libxl_stop_waiting(libxl_ctx *ctx, libxl_waiter *waiter)
589 {
590 if (!xs_unwatch(ctx->xsh, waiter->path, waiter->token))
591 return ERROR_FAIL;
592 else
593 return 0;
594 }
596 int libxl_free_event(libxl_event *event)
597 {
598 free(event->path);
599 free(event->token);
600 return 0;
601 }
603 int libxl_free_waiter(libxl_waiter *waiter)
604 {
605 free(waiter->path);
606 free(waiter->token);
607 return 0;
608 }
610 int libxl_event_get_domain_death_info(libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_dominfo *info)
611 {
612 if (libxl_domain_info(ctx, info, domid) < 0)
613 return 0;
615 if (info->running || (!info->shutdown && !info->dying))
616 return ERROR_INVAL;
618 return 1;
619 }
621 int libxl_event_get_disk_eject_info(libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk)
622 {
623 libxl__gc gc = LIBXL_INIT_GC(ctx);
624 char *path;
625 char *backend;
626 char *value;
628 value = libxl__xs_read(&gc, XBT_NULL, event->path);
630 if (!value || strcmp(value, "eject")) {
631 libxl__free_all(&gc);
632 return 0;
633 }
635 path = strdup(event->path);
636 path[strlen(path) - 6] = '\0';
637 backend = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend", path));
639 disk->backend_domid = 0;
640 disk->domid = domid;
641 disk->physpath = NULL;
642 disk->phystype = 0;
643 /* this value is returned to the user: do not free right away */
644 disk->virtpath = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/dev", backend));
645 disk->unpluggable = 1;
646 disk->readwrite = 0;
647 disk->is_cdrom = 1;
649 free(path);
650 libxl__free_all(&gc);
651 return 1;
652 }
654 int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, int force)
655 {
656 libxl__gc gc = LIBXL_INIT_GC(ctx);
657 char *dom_path;
658 char *vm_path;
659 int rc, dm_present;
661 if (libxl__domain_is_hvm(ctx, domid)) {
662 dm_present = 1;
663 } else {
664 char *pid;
665 pid = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/%d/image/device-model-pid", domid));
666 dm_present = (pid != NULL);
667 }
669 dom_path = libxl__xs_get_dompath(&gc, domid);
670 if (!dom_path) {
671 rc = ERROR_FAIL;
672 goto out;
673 }
675 if (libxl_device_pci_shutdown(ctx, domid) < 0)
676 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "pci shutdown failed for domid %d", domid);
677 rc = xc_domain_pause(ctx->xch, domid);
678 if (rc < 0) {
679 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_pause failed for %d", domid);
680 }
681 if (dm_present) {
682 if (libxl__destroy_device_model(ctx, domid) < 0)
683 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "libxl__destroy_device_model failed for %d", domid);
684 }
685 if (libxl__devices_destroy(ctx, domid, force) < 0)
686 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "libxl_destroy_devices failed for %d", domid);
688 vm_path = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dom_path));
689 if (vm_path)
690 if (!xs_rm(ctx->xsh, XBT_NULL, vm_path))
691 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xs_rm failed for %s", vm_path);
693 if (!xs_rm(ctx->xsh, XBT_NULL, dom_path))
694 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xs_rm failed for %s", dom_path);
696 libxl__userdata_destroyall(ctx, domid);
698 rc = xc_domain_destroy(ctx->xch, domid);
699 if (rc < 0) {
700 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_destroy failed for %d", domid);
701 rc = ERROR_FAIL;
702 goto out;
703 }
704 rc = 0;
705 out:
706 libxl__free_all(&gc);
707 return 0;
708 }
710 int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num, libxl_console_constype type)
711 {
712 libxl__gc gc = LIBXL_INIT_GC(ctx);
713 char *p = libxl__sprintf(&gc, "%s/xenconsole", libxl_private_bindir_path());
714 char *domid_s = libxl__sprintf(&gc, "%d", domid);
715 char *cons_num_s = libxl__sprintf(&gc, "%d", cons_num);
716 char *cons_type_s;
718 switch (type) {
719 case LIBXL_CONSTYPE_PV:
720 cons_type_s = "pv";
721 break;
722 case LIBXL_CONSTYPE_SERIAL:
723 cons_type_s = "serial";
724 break;
725 default:
726 goto out;
727 }
729 execl(p, p, domid_s, "--num", cons_num_s, "--type", cons_type_s, (void *)NULL);
731 out:
732 libxl__free_all(&gc);
733 return ERROR_FAIL;
734 }
736 int libxl_primary_console_exec(libxl_ctx *ctx, uint32_t domid_vm)
737 {
738 uint32_t stubdomid = libxl_get_stubdom_id(ctx, domid_vm);
739 if (stubdomid)
740 return libxl_console_exec(ctx, stubdomid,
741 STUBDOM_CONSOLE_SERIAL, LIBXL_CONSTYPE_PV);
742 else {
743 if (libxl__domain_is_hvm(ctx, domid_vm))
744 return libxl_console_exec(ctx, domid_vm, 0, LIBXL_CONSTYPE_SERIAL);
745 else
746 return libxl_console_exec(ctx, domid_vm, 0, LIBXL_CONSTYPE_PV);
747 }
748 }
750 int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass)
751 {
752 libxl__gc gc = LIBXL_INIT_GC(ctx);
753 const char *vnc_port, *vfb_back;
754 const char *vnc_listen = NULL, *vnc_pass = NULL;
755 int port = 0, autopass_fd = -1;
756 char *vnc_bin, *args[] = {
757 "vncviewer",
758 NULL, /* hostname:display */
759 NULL, /* -autopass */
760 NULL,
761 };
763 vnc_port = libxl__xs_read(&gc, XBT_NULL,
764 libxl__sprintf(&gc,
765 "/local/domain/%d/console/vnc-port", domid));
766 if ( vnc_port )
767 port = atoi(vnc_port) - 5900;
769 vfb_back = libxl__xs_read(&gc, XBT_NULL,
770 libxl__sprintf(&gc,
771 "/local/domain/%d/device/vfb/0/backend", domid));
772 if ( vfb_back ) {
773 vnc_listen = libxl__xs_read(&gc, XBT_NULL,
774 libxl__sprintf(&gc,
775 "/local/domain/%d/console/vnc-listen", domid));
776 if ( autopass )
777 vnc_pass = libxl__xs_read(&gc, XBT_NULL,
778 libxl__sprintf(&gc,
779 "/local/domain/%d/console/vnc-pass", domid));
780 }
782 if ( NULL == vnc_listen )
783 vnc_listen = "localhost";
785 if ( (vnc_bin = getenv("VNCVIEWER")) )
786 args[0] = vnc_bin;
788 args[1] = libxl__sprintf(&gc, "%s:%d", vnc_listen, port);
790 if ( vnc_pass ) {
791 char tmpname[] = "/tmp/vncautopass.XXXXXX";
792 autopass_fd = mkstemp(tmpname);
793 if ( autopass_fd < 0 )
794 goto skip_autopass;
796 if ( unlink(tmpname) )
797 /* should never happen */
798 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unlink %s failed", tmpname);
800 if ( libxl_write_exactly(ctx, autopass_fd, vnc_pass, strlen(vnc_pass),
801 tmpname, "vnc password") ) {
802 do { close(autopass_fd); } while(errno == EINTR);
803 goto skip_autopass;
804 }
806 args[2] = "-autopass";
807 }
809 skip_autopass:
810 libxl__free_all(&gc);
811 libxl__exec(autopass_fd, -1, -1, args[0], args);
812 return 0;
813 }
815 /******************************************************************************/
817 int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
818 {
819 libxl__gc gc = LIBXL_INIT_GC(ctx);
820 flexarray_t *front;
821 flexarray_t *back;
822 char *backend_type;
823 int devid;
824 libxl__device device;
825 int major, minor, rc;
827 front = flexarray_make(16, 1);
828 if (!front) {
829 rc = ERROR_NOMEM;
830 goto out;
831 }
832 back = flexarray_make(16, 1);
833 if (!back) {
834 rc = ERROR_NOMEM;
835 goto out_free;
836 }
838 backend_type = libxl__device_disk_backend_type_of_phystype(disk->phystype);
839 devid = libxl__device_disk_dev_number(disk->virtpath);
840 if (devid==-1) {
841 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Invalid or unsupported"
842 " virtual disk identifier %s", disk->virtpath);
843 rc = ERROR_INVAL;
844 goto out_free;
845 }
847 device.backend_devid = devid;
848 device.backend_domid = disk->backend_domid;
849 device.devid = devid;
850 device.domid = disk->domid;
851 device.kind = DEVICE_VBD;
853 switch (disk->phystype) {
854 case PHYSTYPE_PHY: {
856 libxl__device_physdisk_major_minor(disk->physpath, &major, &minor);
857 flexarray_append(back, "physical-device");
858 flexarray_append(back, libxl__sprintf(&gc, "%x:%x", major, minor));
860 flexarray_append(back, "params");
861 flexarray_append(back, disk->physpath);
863 device.backend_kind = DEVICE_VBD;
864 break;
865 }
866 case PHYSTYPE_FILE:
867 /* let's pretend is tap:aio for the moment */
868 disk->phystype = PHYSTYPE_AIO;
869 case PHYSTYPE_AIO:
870 case PHYSTYPE_QCOW:
871 case PHYSTYPE_QCOW2:
872 case PHYSTYPE_VHD:
873 if (libxl__blktap_enabled(&gc)) {
874 const char *dev = libxl__blktap_devpath(&gc,
875 disk->physpath, disk->phystype);
876 if (!dev) {
877 rc = ERROR_FAIL;
878 goto out_free;
879 }
880 flexarray_append(back, "tapdisk-params");
881 flexarray_append(back, libxl__sprintf(&gc, "%s:%s", libxl__device_disk_string_of_phystype(disk->phystype), disk->physpath));
882 flexarray_append(back, "params");
883 flexarray_append(back, libxl__strdup(&gc, dev));
884 backend_type = "phy";
885 libxl__device_physdisk_major_minor(dev, &major, &minor);
886 flexarray_append(back, "physical-device");
887 flexarray_append(back, libxl__sprintf(&gc, "%x:%x", major, minor));
888 device.backend_kind = DEVICE_VBD;
890 break;
891 }
892 flexarray_append(back, "params");
893 flexarray_append(back, libxl__sprintf(&gc, "%s:%s",
894 libxl__device_disk_string_of_phystype(disk->phystype), disk->physpath));
896 if (libxl__blktap_enabled(&gc))
897 device.backend_kind = DEVICE_TAP;
898 else
899 device.backend_kind = DEVICE_QDISK;
900 break;
902 default:
903 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unrecognized disk physical type: %d\n", disk->phystype);
904 rc = ERROR_INVAL;
905 goto out_free;
906 }
908 flexarray_append(back, "frontend-id");
909 flexarray_append(back, libxl__sprintf(&gc, "%d", disk->domid));
910 flexarray_append(back, "online");
911 flexarray_append(back, "1");
912 flexarray_append(back, "removable");
913 flexarray_append(back, libxl__sprintf(&gc, "%d", (disk->unpluggable) ? 1 : 0));
914 flexarray_append(back, "bootable");
915 flexarray_append(back, libxl__sprintf(&gc, "%d", 1));
916 flexarray_append(back, "state");
917 flexarray_append(back, libxl__sprintf(&gc, "%d", 1));
918 flexarray_append(back, "dev");
919 flexarray_append(back, disk->virtpath);
920 flexarray_append(back, "type");
921 flexarray_append(back, backend_type);
922 flexarray_append(back, "mode");
923 flexarray_append(back, disk->readwrite ? "w" : "r");
925 flexarray_append(front, "backend-id");
926 flexarray_append(front, libxl__sprintf(&gc, "%d", disk->backend_domid));
927 flexarray_append(front, "state");
928 flexarray_append(front, libxl__sprintf(&gc, "%d", 1));
929 flexarray_append(front, "virtual-device");
930 flexarray_append(front, libxl__sprintf(&gc, "%d", devid));
931 flexarray_append(front, "device-type");
932 flexarray_append(front, disk->is_cdrom ? "cdrom" : "disk");
934 if (0 /* protocol != native*/) {
935 flexarray_append(front, "protocol");
936 flexarray_append(front, "x86_32-abi"); /* hardcoded ! */
937 }
939 libxl__device_generic_add(ctx, &device,
940 libxl__xs_kvs_of_flexarray(&gc, back, back->count),
941 libxl__xs_kvs_of_flexarray(&gc, front, front->count));
943 rc = 0;
945 out_free:
946 flexarray_free(back);
947 flexarray_free(front);
948 out:
949 libxl__free_all(&gc);
950 return rc;
951 }
953 int libxl_device_disk_del(libxl_ctx *ctx,
954 libxl_device_disk *disk, int wait)
955 {
956 libxl__device device;
957 int devid;
959 devid = libxl__device_disk_dev_number(disk->virtpath);
960 device.backend_domid = disk->backend_domid;
961 device.backend_devid = devid;
962 device.backend_kind =
963 (disk->phystype == PHYSTYPE_PHY) ? DEVICE_VBD : DEVICE_TAP;
964 device.domid = disk->domid;
965 device.devid = devid;
966 device.kind = DEVICE_VBD;
967 return libxl__device_del(ctx, &device, wait);
968 }
970 char * libxl_device_disk_local_attach(libxl_ctx *ctx, libxl_device_disk *disk)
971 {
972 libxl__gc gc = LIBXL_INIT_GC(ctx);
973 const char *dev = NULL;
974 char *ret;
975 int phystype = disk->phystype;
976 switch (phystype) {
977 case PHYSTYPE_PHY: {
978 fprintf(stderr, "attaching PHY disk %s to domain 0\n", disk->physpath);
979 dev = disk->physpath;
980 break;
981 }
982 case PHYSTYPE_FILE:
983 /* let's pretend is tap:aio for the moment */
984 phystype = PHYSTYPE_AIO;
985 case PHYSTYPE_AIO:
986 case PHYSTYPE_QCOW:
987 case PHYSTYPE_QCOW2:
988 case PHYSTYPE_VHD:
989 if (libxl__blktap_enabled(&gc))
990 dev = libxl__blktap_devpath(&gc, disk->physpath, phystype);
991 break;
993 default:
994 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unrecognized disk physical type: %d\n", phystype);
995 break;
996 }
997 ret = strdup(dev);
998 libxl__free_all(&gc);
999 return ret;
1002 int libxl_device_disk_local_detach(libxl_ctx *ctx, libxl_device_disk *disk)
1004 /* Nothing to do for PHYSTYPE_PHY. */
1006 /*
1007 * For other device types assume that the blktap2 process is
1008 * needed by the soon to be started domain and do nothing.
1009 */
1011 return 0;
1014 /******************************************************************************/
1015 int libxl_device_nic_init(libxl_device_nic *nic_info, int devnum)
1017 const uint8_t *r;
1018 libxl_uuid uuid;
1020 libxl_uuid_generate(&uuid);
1021 r = libxl_uuid_bytearray(&uuid);
1022 memset(nic_info, '\0', sizeof(*nic_info));
1024 nic_info->backend_domid = 0;
1025 nic_info->domid = 0;
1026 nic_info->devid = devnum;
1027 nic_info->mtu = 1492;
1028 nic_info->model = strdup("e1000");
1029 nic_info->mac[0] = 0x00;
1030 nic_info->mac[1] = 0x16;
1031 nic_info->mac[2] = 0x3e;
1032 nic_info->mac[3] = r[0] & 0x7f;
1033 nic_info->mac[4] = r[1];
1034 nic_info->mac[5] = r[2];
1035 nic_info->ifname = NULL;
1036 nic_info->bridge = strdup("xenbr0");
1037 if ( asprintf(&nic_info->script, "%s/vif-bridge",
1038 libxl_xen_script_dir_path()) < 0 )
1039 return ERROR_FAIL;
1040 nic_info->nictype = NICTYPE_IOEMU;
1041 return 0;
1044 int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
1046 libxl__gc gc = LIBXL_INIT_GC(ctx);
1047 flexarray_t *front;
1048 flexarray_t *back;
1049 libxl__device device;
1050 char *dompath, **l;
1051 unsigned int nb, rc;
1053 front = flexarray_make(16, 1);
1054 if (!front) {
1055 rc = ERROR_NOMEM;
1056 goto out;
1058 back = flexarray_make(16, 1);
1059 if (!back) {
1060 rc = ERROR_NOMEM;
1061 goto out_free;
1064 if (nic->devid == -1) {
1065 if (!(dompath = libxl__xs_get_dompath(&gc, domid))) {
1066 rc = ERROR_FAIL;
1067 goto out_free;
1069 if (!(l = libxl__xs_directory(&gc, XBT_NULL,
1070 libxl__sprintf(&gc, "%s/device/vif", dompath), &nb))) {
1071 nic->devid = 0;
1072 } else {
1073 nic->devid = strtoul(l[nb - 1], NULL, 10) + 1;
1077 device.backend_devid = nic->devid;
1078 device.backend_domid = nic->backend_domid;
1079 device.backend_kind = DEVICE_VIF;
1080 device.devid = nic->devid;
1081 device.domid = nic->domid;
1082 device.kind = DEVICE_VIF;
1084 flexarray_append(back, "frontend-id");
1085 flexarray_append(back, libxl__sprintf(&gc, "%d", nic->domid));
1086 flexarray_append(back, "online");
1087 flexarray_append(back, "1");
1088 flexarray_append(back, "state");
1089 flexarray_append(back, libxl__sprintf(&gc, "%d", 1));
1090 flexarray_append(back, "script");
1091 flexarray_append(back, nic->script);
1092 flexarray_append(back, "mac");
1093 flexarray_append(back, libxl__sprintf(&gc, "%02x:%02x:%02x:%02x:%02x:%02x",
1094 nic->mac[0], nic->mac[1], nic->mac[2],
1095 nic->mac[3], nic->mac[4], nic->mac[5]));
1096 flexarray_append(back, "bridge");
1097 flexarray_append(back, libxl__strdup(&gc, nic->bridge));
1098 flexarray_append(back, "handle");
1099 flexarray_append(back, libxl__sprintf(&gc, "%d", nic->devid));
1101 flexarray_append(front, "backend-id");
1102 flexarray_append(front, libxl__sprintf(&gc, "%d", nic->backend_domid));
1103 flexarray_append(front, "state");
1104 flexarray_append(front, libxl__sprintf(&gc, "%d", 1));
1105 flexarray_append(front, "handle");
1106 flexarray_append(front, libxl__sprintf(&gc, "%d", nic->devid));
1107 flexarray_append(front, "mac");
1108 flexarray_append(front, libxl__sprintf(&gc, "%02x:%02x:%02x:%02x:%02x:%02x",
1109 nic->mac[0], nic->mac[1], nic->mac[2],
1110 nic->mac[3], nic->mac[4], nic->mac[5]));
1111 if (0 /* protocol != native*/) {
1112 flexarray_append(front, "protocol");
1113 flexarray_append(front, "x86_32-abi"); /* hardcoded ! */
1116 libxl__device_generic_add(ctx, &device,
1117 libxl__xs_kvs_of_flexarray(&gc, back, back->count),
1118 libxl__xs_kvs_of_flexarray(&gc, front, front->count));
1120 /* FIXME: wait for plug */
1121 rc = 0;
1122 out_free:
1123 flexarray_free(back);
1124 flexarray_free(front);
1125 out:
1126 libxl__free_all(&gc);
1127 return rc;
1130 int libxl_device_nic_del(libxl_ctx *ctx,
1131 libxl_device_nic *nic, int wait)
1133 libxl__device device;
1135 device.backend_devid = nic->devid;
1136 device.backend_domid = nic->backend_domid;
1137 device.backend_kind = DEVICE_VIF;
1138 device.devid = nic->devid;
1139 device.domid = nic->domid;
1140 device.kind = DEVICE_VIF;
1142 return libxl__device_del(ctx, &device, wait);
1145 libxl_nicinfo *libxl_list_nics(libxl_ctx *ctx, uint32_t domid, unsigned int *nb)
1147 libxl__gc gc = LIBXL_INIT_GC(ctx);
1148 char *dompath, *nic_path_fe;
1149 char **l, **list;
1150 char *val, *tok;
1151 unsigned int nb_nics, i;
1152 libxl_nicinfo *res, *nics;
1154 dompath = libxl__xs_get_dompath(&gc, domid);
1155 if (!dompath)
1156 goto err;
1157 list = l = libxl__xs_directory(&gc, XBT_NULL,
1158 libxl__sprintf(&gc, "%s/device/vif", dompath), &nb_nics);
1159 if (!l)
1160 goto err;
1161 nics = res = calloc(nb_nics, sizeof (libxl_device_nic));
1162 if (!res)
1163 goto err;
1164 for (*nb = nb_nics; nb_nics > 0; --nb_nics, ++l, ++nics) {
1165 nic_path_fe = libxl__sprintf(&gc, "%s/device/vif/%s", dompath, *l);
1167 nics->backend = xs_read(ctx->xsh, XBT_NULL,
1168 libxl__sprintf(&gc, "%s/backend", nic_path_fe), NULL);
1169 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", nic_path_fe));
1170 nics->backend_id = val ? strtoul(val, NULL, 10) : -1;
1172 nics->devid = strtoul(*l, NULL, 10);
1173 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/state", nic_path_fe));
1174 nics->state = val ? strtoul(val, NULL, 10) : -1;
1175 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/mac", nic_path_fe));
1176 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
1177 ++i, tok = strtok(NULL, ":")) {
1178 nics->mac[i] = strtoul(tok, NULL, 16);
1180 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/event-channel", nic_path_fe));
1181 nics->evtch = val ? strtol(val, NULL, 10) : -1;
1182 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/tx-ring-ref", nic_path_fe));
1183 nics->rref_tx = val ? strtol(val, NULL, 10) : -1;
1184 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/rx-ring-ref", nic_path_fe));
1185 nics->rref_rx = val ? strtol(val, NULL, 10) : -1;
1186 nics->frontend = xs_read(ctx->xsh, XBT_NULL,
1187 libxl__sprintf(&gc, "%s/frontend", nics->backend), NULL);
1188 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/frontend-id", nics->backend));
1189 nics->frontend_id = val ? strtoul(val, NULL, 10) : -1;
1190 nics->script = xs_read(ctx->xsh, XBT_NULL,
1191 libxl__sprintf(&gc, "%s/script", nics->backend), NULL);
1194 libxl__free_all(&gc);
1195 return res;
1196 err:
1197 libxl__free_all(&gc);
1198 return NULL;
1201 /******************************************************************************/
1202 void libxl_device_net2_init(libxl_device_net2 *net2_info, int devnum)
1204 const uint8_t *r;
1205 libxl_uuid uuid;
1207 libxl_uuid_generate(&uuid);
1208 r = libxl_uuid_bytearray(&uuid);
1209 memset(net2_info, '\0', sizeof(*net2_info));
1211 net2_info->devid = devnum;
1212 net2_info->front_mac[0] = 0x00;
1213 net2_info->front_mac[1] = 0x16;
1214 net2_info->front_mac[2] = 0x3e;;
1215 net2_info->front_mac[3] = 0x7f & r[0];
1216 net2_info->front_mac[4] = r[1];
1217 net2_info->front_mac[5] = r[2];
1218 net2_info->back_mac[0] = 0x00;
1219 net2_info->back_mac[1] = 0x16;
1220 net2_info->back_mac[2] = 0x3e;
1221 net2_info->back_mac[3] = 0x7f & r[3];
1222 net2_info->back_mac[4] = r[4];
1223 net2_info->back_mac[5] = r[5];
1224 net2_info->back_trusted = 1;
1225 net2_info->filter_mac = 1;
1226 net2_info->max_bypasses = 5;
1227 net2_info->bridge = strdup("xenbr0");
1230 int libxl_device_net2_add(libxl_ctx *ctx, uint32_t domid, libxl_device_net2 *net2)
1232 libxl__gc gc = LIBXL_INIT_GC(ctx);
1233 flexarray_t *front, *back;
1234 libxl__device device;
1235 char *dompath, *dom, **l;
1236 unsigned int nb;
1237 int rc;
1239 front = flexarray_make(16, 1);
1240 if (!front) {
1241 rc = ERROR_NOMEM;
1242 goto err;
1244 back = flexarray_make(16, 1);
1245 if (!back) {
1246 rc = ERROR_NOMEM;
1247 goto err_free;
1250 if (!(dompath = libxl__xs_get_dompath(&gc, domid))) {
1251 rc = ERROR_FAIL;
1252 goto err_free;
1254 dom = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/name", dompath));
1256 if (net2->devid == -1) {
1257 if (!(l = libxl__xs_directory(&gc, XBT_NULL,
1258 libxl__sprintf(&gc, "%s/device/vif2", dompath), &nb))) {
1259 net2->devid = 0;
1260 } else {
1261 net2->devid = strtoul(l[nb - 1], NULL, 10) + 1;
1265 device.backend_devid = net2->devid;
1266 device.backend_domid = net2->backend_domid;
1267 device.backend_kind = DEVICE_VIF2;
1268 device.devid = net2->devid;
1269 device.domid = net2->domid;
1270 device.kind = DEVICE_VIF2;
1272 flexarray_append(back, "domain");
1273 flexarray_append(back, dom);
1274 flexarray_append(back, "frontend-id");
1275 flexarray_append(back, libxl__sprintf(&gc, "%d", net2->domid));
1277 flexarray_append(back, "local-trusted");
1278 flexarray_append(back, libxl__sprintf(&gc, "%d", net2->back_trusted));
1279 flexarray_append(back, "mac");
1280 flexarray_append(back, libxl__sprintf(&gc, "%02x:%02x:%02x:%02x:%02x:%02x",
1281 net2->back_mac[0], net2->back_mac[1],
1282 net2->back_mac[2], net2->back_mac[3],
1283 net2->back_mac[4], net2->back_mac[5]));
1285 flexarray_append(back, "remote-trusted");
1286 flexarray_append(back, libxl__sprintf(&gc, "%d", net2->trusted));
1287 flexarray_append(back, "remote-mac");
1288 flexarray_append(back, libxl__sprintf(&gc, "%02x:%02x:%02x:%02x:%02x:%02x",
1289 net2->front_mac[0], net2->front_mac[1],
1290 net2->front_mac[2], net2->front_mac[3],
1291 net2->front_mac[4], net2->front_mac[5]));
1293 flexarray_append(back, "max-bypasses");
1294 flexarray_append(back, libxl__sprintf(&gc, "%d", net2->max_bypasses));
1295 flexarray_append(back, "filter-mac");
1296 flexarray_append(back, libxl__sprintf(&gc, "%d", !!(net2->filter_mac)));
1297 flexarray_append(back, "handle");
1298 flexarray_append(back, libxl__sprintf(&gc, "%d", net2->devid));
1299 flexarray_append(back, "online");
1300 flexarray_append(back, "1");
1301 flexarray_append(back, "state");
1302 flexarray_append(back, "1");
1304 flexarray_append(front, "backend-id");
1305 flexarray_append(front, libxl__sprintf(&gc, "%d", net2->backend_domid));
1307 flexarray_append(front, "local-trusted");
1308 flexarray_append(front, libxl__sprintf(&gc, "%d", net2->trusted));
1309 flexarray_append(front, "mac");
1310 flexarray_append(front, libxl__sprintf(&gc, "%02x:%02x:%02x:%02x:%02x:%02x",
1311 net2->front_mac[0], net2->front_mac[1],
1312 net2->front_mac[2], net2->front_mac[3],
1313 net2->front_mac[4], net2->front_mac[5]));
1315 flexarray_append(front, "remote-trusted");
1316 flexarray_append(front, libxl__sprintf(&gc, "%d", net2->back_trusted));
1317 flexarray_append(front, "remote-mac");
1318 flexarray_append(front, libxl__sprintf(&gc, "%02x:%02x:%02x:%02x:%02x:%02x",
1319 net2->back_mac[0], net2->back_mac[1],
1320 net2->back_mac[2], net2->back_mac[3],
1321 net2->back_mac[4], net2->back_mac[5]));
1323 flexarray_append(front, "filter-mac");
1324 flexarray_append(front, libxl__sprintf(&gc, "%d", !!(net2->filter_mac)));
1325 flexarray_append(front, "state");
1326 flexarray_append(front, "1");
1328 libxl__device_generic_add(ctx, &device,
1329 libxl__xs_kvs_of_flexarray(&gc, back, back->count),
1330 libxl__xs_kvs_of_flexarray(&gc, front, front->count));
1332 /* FIXME: wait for plug */
1333 rc = 0;
1334 err_free:
1335 flexarray_free(back);
1336 flexarray_free(front);
1337 err:
1338 libxl__free_all(&gc);
1339 return rc;
1342 libxl_net2info *libxl_device_net2_list(libxl_ctx *ctx, uint32_t domid, unsigned int *nb)
1344 libxl__gc gc = LIBXL_INIT_GC(ctx);
1345 char *dompath, *net2_path_fe;
1346 char **l;
1347 char *val, *tok;
1348 unsigned int nb_net2s, i;
1349 libxl_net2info *res, *net2s;
1351 dompath = libxl__xs_get_dompath(&gc, domid);
1352 if (!dompath)
1353 goto err;
1354 l = libxl__xs_directory(&gc, XBT_NULL,
1355 libxl__sprintf(&gc, "%s/device/vif2", dompath), &nb_net2s);
1356 if (!l)
1357 goto err;
1358 res = calloc(nb_net2s, sizeof (libxl_net2info));
1359 if (!res)
1360 goto err;
1361 net2s = res;
1362 for (*nb = nb_net2s; nb_net2s > 0; --nb_net2s, ++l, ++net2s) {
1363 net2_path_fe = libxl__sprintf(&gc, "%s/device/vif2/%s", dompath, *l);
1365 net2s->backend = libxl__xs_read(&gc, XBT_NULL,
1366 libxl__sprintf(&gc, "%s/backend", net2_path_fe));
1367 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", net2_path_fe));
1368 net2s->backend_id = val ? strtoul(val, NULL, 10) : -1;
1370 net2s->devid = strtoul(*l, NULL, 10);
1371 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/state", net2_path_fe));
1372 net2s->state = val ? strtoul(val, NULL, 10) : -1;
1374 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/mac", net2_path_fe));
1375 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
1376 ++i, tok = strtok(NULL, ":")) {
1377 net2s->mac[i] = strtoul(tok, NULL, 16);
1379 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/remote-trusted", net2_path_fe));
1380 net2s->trusted = val ? strtoul(val, NULL, 10) : -1;
1382 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/remote-mac", net2_path_fe));
1383 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
1384 ++i, tok = strtok(NULL, ":")) {
1385 net2s->back_mac[i] = strtoul(tok, NULL, 16);
1387 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/filter-mac", net2_path_fe));
1388 net2s->filter_mac = val ? strtoul(val, NULL, 10) : -1;
1390 net2s->frontend = libxl__xs_read(&gc, XBT_NULL,
1391 libxl__sprintf(&gc, "%s/frontend", net2s->backend));
1392 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/frontend-id", net2s->backend));
1393 net2s->frontend_id = val ? strtoul(val, NULL, 10) : -1;
1396 libxl__free_all(&gc);
1397 return res;
1398 err:
1399 libxl__free_all(&gc);
1400 return NULL;
1403 int libxl_device_net2_del(libxl_ctx *ctx, libxl_device_net2 *net2, int wait)
1405 libxl__device device;
1407 device.backend_devid = net2->devid;
1408 device.backend_domid = net2->backend_domid;
1409 device.backend_kind = DEVICE_VIF2;
1410 device.devid = net2->devid;
1411 device.domid = net2->domid;
1412 device.kind = DEVICE_VIF2;
1414 return libxl__device_del(ctx, &device, wait);
1418 /******************************************************************************/
1419 int libxl_device_console_add(libxl_ctx *ctx, uint32_t domid, libxl_device_console *console)
1421 libxl__gc gc = LIBXL_INIT_GC(ctx);
1422 flexarray_t *front;
1423 flexarray_t *back;
1424 libxl__device device;
1425 int rc;
1427 front = flexarray_make(16, 1);
1428 if (!front) {
1429 rc = ERROR_NOMEM;
1430 goto out;
1432 back = flexarray_make(16, 1);
1433 if (!back) {
1434 rc = ERROR_NOMEM;
1435 goto out_free;
1438 device.backend_devid = console->devid;
1439 device.backend_domid = console->backend_domid;
1440 device.backend_kind = DEVICE_CONSOLE;
1441 device.devid = console->devid;
1442 device.domid = console->domid;
1443 device.kind = DEVICE_CONSOLE;
1445 flexarray_append(back, "frontend-id");
1446 flexarray_append(back, libxl__sprintf(&gc, "%d", console->domid));
1447 flexarray_append(back, "online");
1448 flexarray_append(back, "1");
1449 flexarray_append(back, "state");
1450 flexarray_append(back, libxl__sprintf(&gc, "%d", 1));
1451 flexarray_append(back, "domain");
1452 flexarray_append(back, libxl__domid_to_name(&gc, domid));
1453 flexarray_append(back, "protocol");
1454 flexarray_append(back, LIBXL_XENCONSOLE_PROTOCOL);
1456 flexarray_append(front, "backend-id");
1457 flexarray_append(front, libxl__sprintf(&gc, "%d", console->backend_domid));
1458 flexarray_append(front, "limit");
1459 flexarray_append(front, libxl__sprintf(&gc, "%d", LIBXL_XENCONSOLE_LIMIT));
1460 flexarray_append(front, "type");
1461 if (console->consback == LIBXL_CONSBACK_XENCONSOLED)
1462 flexarray_append(front, "xenconsoled");
1463 else
1464 flexarray_append(front, "ioemu");
1465 flexarray_append(front, "output");
1466 flexarray_append(front, console->output);
1468 if (device.devid == 0) {
1469 if (console->build_state == NULL) {
1470 rc = ERROR_INVAL;
1471 goto out_free;
1473 flexarray_append(front, "port");
1474 flexarray_append(front, libxl__sprintf(&gc, "%"PRIu32, console->build_state->console_port));
1475 flexarray_append(front, "ring-ref");
1476 flexarray_append(front, libxl__sprintf(&gc, "%lu", console->build_state->console_mfn));
1477 } else {
1478 flexarray_append(front, "state");
1479 flexarray_append(front, libxl__sprintf(&gc, "%d", 1));
1480 flexarray_append(front, "protocol");
1481 flexarray_append(front, LIBXL_XENCONSOLE_PROTOCOL);
1484 libxl__device_generic_add(ctx, &device,
1485 libxl__xs_kvs_of_flexarray(&gc, back, back->count),
1486 libxl__xs_kvs_of_flexarray(&gc, front, front->count));
1487 rc = 0;
1488 out_free:
1489 flexarray_free(back);
1490 flexarray_free(front);
1491 out:
1492 libxl__free_all(&gc);
1493 return rc;
1496 /******************************************************************************/
1497 void libxl_device_vkb_init(libxl_device_vkb *vkb, int dev_num)
1499 memset(vkb, 0x00, sizeof(libxl_device_vkb));
1500 vkb->devid = dev_num;
1503 int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb)
1505 libxl__gc gc = LIBXL_INIT_GC(ctx);
1506 flexarray_t *front;
1507 flexarray_t *back;
1508 libxl__device device;
1509 int rc;
1511 front = flexarray_make(16, 1);
1512 if (!front) {
1513 rc = ERROR_NOMEM;
1514 goto out;
1516 back = flexarray_make(16, 1);
1517 if (!back) {
1518 rc = ERROR_NOMEM;
1519 goto out_free;
1522 device.backend_devid = vkb->devid;
1523 device.backend_domid = vkb->backend_domid;
1524 device.backend_kind = DEVICE_VKBD;
1525 device.devid = vkb->devid;
1526 device.domid = vkb->domid;
1527 device.kind = DEVICE_VKBD;
1529 flexarray_append(back, "frontend-id");
1530 flexarray_append(back, libxl__sprintf(&gc, "%d", vkb->domid));
1531 flexarray_append(back, "online");
1532 flexarray_append(back, "1");
1533 flexarray_append(back, "state");
1534 flexarray_append(back, libxl__sprintf(&gc, "%d", 1));
1535 flexarray_append(back, "domain");
1536 flexarray_append(back, libxl__domid_to_name(&gc, domid));
1538 flexarray_append(front, "backend-id");
1539 flexarray_append(front, libxl__sprintf(&gc, "%d", vkb->backend_domid));
1540 flexarray_append(front, "state");
1541 flexarray_append(front, libxl__sprintf(&gc, "%d", 1));
1543 libxl__device_generic_add(ctx, &device,
1544 libxl__xs_kvs_of_flexarray(&gc, back, back->count),
1545 libxl__xs_kvs_of_flexarray(&gc, front, front->count));
1546 rc = 0;
1547 out_free:
1548 flexarray_free(back);
1549 flexarray_free(front);
1550 out:
1551 libxl__free_all(&gc);
1552 return rc;
1555 int libxl_device_vkb_clean_shutdown(libxl_ctx *ctx, uint32_t domid)
1557 return ERROR_NI;
1560 int libxl_device_vkb_hard_shutdown(libxl_ctx *ctx, uint32_t domid)
1562 return ERROR_NI;
1565 static unsigned int libxl_append_disk_list_of_type(libxl_ctx *ctx,
1566 uint32_t domid,
1567 const char *type,
1568 libxl_device_disk **disks,
1569 unsigned int *ndisks)
1571 libxl__gc gc = LIBXL_INIT_GC(ctx);
1572 char *be_path = NULL;
1573 char **dir = NULL;
1574 unsigned int n = 0, len = 0;
1575 libxl_device_disk *pdisk = NULL, *pdisk_end = NULL;
1576 char *physpath_tmp = NULL;
1578 be_path = libxl__sprintf(&gc, "%s/backend/%s/%d",
1579 libxl__xs_get_dompath(&gc, 0), type, domid);
1580 dir = libxl__xs_directory(&gc, XBT_NULL, be_path, &n);
1581 if (dir) {
1582 *disks = realloc(*disks, sizeof (libxl_device_disk) * (*ndisks + n));
1583 pdisk = *disks + *ndisks;
1584 *ndisks += n;
1585 pdisk_end = *disks + *ndisks;
1586 for (; pdisk < pdisk_end; pdisk++, dir++) {
1587 pdisk->backend_domid = 0;
1588 pdisk->domid = domid;
1589 physpath_tmp = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "%s/%s/params", be_path, *dir), &len);
1590 if (strchr(physpath_tmp, ':')) {
1591 pdisk->physpath = strdup(strchr(physpath_tmp, ':') + 1);
1592 free(physpath_tmp);
1593 } else {
1594 pdisk->physpath = physpath_tmp;
1596 libxl_string_to_phystype(ctx, libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/%s/type", be_path, *dir)), &(pdisk->phystype));
1597 pdisk->virtpath = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "%s/%s/dev", be_path, *dir), &len);
1598 pdisk->unpluggable = atoi(libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/%s/removable", be_path, *dir)));
1599 if (!strcmp(libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/%s/mode", be_path, *dir)), "w"))
1600 pdisk->readwrite = 1;
1601 else
1602 pdisk->readwrite = 0;
1603 type = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/device-type", libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/%s/frontend", be_path, *dir))));
1604 pdisk->is_cdrom = !strcmp(type, "cdrom");
1608 libxl__free_all(&gc);
1609 return n;
1612 libxl_device_disk *libxl_device_disk_list(libxl_ctx *ctx, uint32_t domid, int *num)
1614 libxl_device_disk *disks = NULL;
1615 unsigned int ndisks = 0;
1617 *num = libxl_append_disk_list_of_type(ctx, domid, "vbd", &disks, &ndisks);
1618 *num += libxl_append_disk_list_of_type(ctx, domid, "tap", &disks, &ndisks);
1619 *num += libxl_append_disk_list_of_type(ctx, domid, "qdisk", &disks, &ndisks);
1621 return disks;
1624 int libxl_device_disk_getinfo(libxl_ctx *ctx, uint32_t domid,
1625 libxl_device_disk *disk, libxl_diskinfo *diskinfo)
1627 libxl__gc gc = LIBXL_INIT_GC(ctx);
1628 char *dompath, *diskpath;
1629 char *val;
1631 dompath = libxl__xs_get_dompath(&gc, domid);
1632 diskinfo->devid = libxl__device_disk_dev_number(disk->virtpath);
1634 /* tap devices entries in xenstore are written as vbd devices. */
1635 diskpath = libxl__sprintf(&gc, "%s/device/vbd/%d", dompath, diskinfo->devid);
1636 diskinfo->backend = xs_read(ctx->xsh, XBT_NULL,
1637 libxl__sprintf(&gc, "%s/backend", diskpath), NULL);
1638 if (!diskinfo->backend) {
1639 libxl__free_all(&gc);
1640 return ERROR_FAIL;
1642 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", diskpath));
1643 diskinfo->backend_id = val ? strtoul(val, NULL, 10) : -1;
1644 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/state", diskpath));
1645 diskinfo->state = val ? strtoul(val, NULL, 10) : -1;
1646 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/event-channel", diskpath));
1647 diskinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
1648 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/ring-ref", diskpath));
1649 diskinfo->rref = val ? strtoul(val, NULL, 10) : -1;
1650 diskinfo->frontend = xs_read(ctx->xsh, XBT_NULL,
1651 libxl__sprintf(&gc, "%s/frontend", diskinfo->backend), NULL);
1652 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/frontend-id", diskinfo->backend));
1653 diskinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1;
1655 libxl__free_all(&gc);
1656 return 0;
1659 int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
1661 int num, i;
1662 uint32_t stubdomid;
1663 libxl_device_disk *disks;
1664 int ret = ERROR_FAIL;
1666 if (!disk->physpath) {
1667 disk->physpath = strdup("");
1668 disk->phystype = PHYSTYPE_PHY;
1670 disks = libxl_device_disk_list(ctx, domid, &num);
1671 for (i = 0; i < num; i++) {
1672 if (disks[i].is_cdrom && !strcmp(disk->virtpath, disks[i].virtpath))
1673 /* found */
1674 break;
1676 if (i == num) {
1677 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Virtual device not found");
1678 goto out;
1681 ret = 0;
1683 libxl_device_disk_del(ctx, disks + i, 1);
1684 libxl_device_disk_add(ctx, domid, disk);
1685 stubdomid = libxl_get_stubdom_id(ctx, domid);
1686 if (stubdomid) {
1687 disks[i].domid = stubdomid;
1688 libxl_device_disk_del(ctx, disks + i, 1);
1689 disk->domid = stubdomid;
1690 libxl_device_disk_add(ctx, stubdomid, disk);
1691 disk->domid = domid;
1693 out:
1694 for (i = 0; i < num; i++)
1695 libxl_device_disk_destroy(&disks[i]);
1696 free(disks);
1697 return ret;
1700 /******************************************************************************/
1701 void libxl_device_vfb_init(libxl_device_vfb *vfb, int dev_num)
1703 memset(vfb, 0x00, sizeof(libxl_device_vfb));
1704 vfb->devid = dev_num;
1705 vfb->display = NULL;
1706 vfb->xauthority = NULL;
1707 vfb->vnc = 1;
1708 vfb->vncpasswd = NULL;
1709 vfb->vnclisten = strdup("127.0.0.1");
1710 vfb->vncdisplay = 0;
1711 vfb->vncunused = 1;
1712 vfb->keymap = NULL;
1713 vfb->sdl = 0;
1714 vfb->opengl = 0;
1717 int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb)
1719 libxl__gc gc = LIBXL_INIT_GC(ctx);
1720 flexarray_t *front;
1721 flexarray_t *back;
1722 libxl__device device;
1723 int rc;
1725 front = flexarray_make(16, 1);
1726 if (!front) {
1727 rc = ERROR_NOMEM;
1728 goto out;
1730 back = flexarray_make(16, 1);
1731 if (!back) {
1732 rc = ERROR_NOMEM;
1733 goto out_free;
1736 device.backend_devid = vfb->devid;
1737 device.backend_domid = vfb->backend_domid;
1738 device.backend_kind = DEVICE_VFB;
1739 device.devid = vfb->devid;
1740 device.domid = vfb->domid;
1741 device.kind = DEVICE_VFB;
1743 flexarray_vappend(back, "frontend-id", libxl__sprintf(&gc, "%d", vfb->domid), NULL);
1744 flexarray_vappend(back, "online", "1", NULL);
1745 flexarray_vappend(back, "state", libxl__sprintf(&gc, "%d", 1), NULL);
1746 flexarray_vappend(back, "domain", libxl__domid_to_name(&gc, domid), NULL);
1747 flexarray_vappend(back, "vnc", libxl__sprintf(&gc, "%d", vfb->vnc), NULL);
1748 flexarray_vappend(back, "vnclisten", vfb->vnclisten, NULL);
1749 flexarray_append(back, "vncpasswd");
1750 flexarray_append(back, vfb->vncpasswd);
1751 flexarray_vappend(back, "vncdisplay", libxl__sprintf(&gc, "%d", vfb->vncdisplay), NULL);
1752 flexarray_vappend(back, "vncunused", libxl__sprintf(&gc, "%d", vfb->vncunused), NULL);
1753 flexarray_vappend(back, "sdl", libxl__sprintf(&gc, "%d", vfb->sdl), NULL);
1754 flexarray_vappend(back, "opengl", libxl__sprintf(&gc, "%d", vfb->opengl), NULL);
1755 if (vfb->xauthority) {
1756 flexarray_vappend(back, "xauthority", vfb->xauthority, NULL);
1758 if (vfb->display) {
1759 flexarray_vappend(back, "display", vfb->display, NULL);
1762 flexarray_vappend(front, "backend-id", libxl__sprintf(&gc, "%d", vfb->backend_domid), NULL);
1763 flexarray_vappend(front, "state", libxl__sprintf(&gc, "%d", 1), NULL);
1765 libxl__device_generic_add(ctx, &device,
1766 libxl__xs_kvs_of_flexarray(&gc, back, back->count),
1767 libxl__xs_kvs_of_flexarray(&gc, front, front->count));
1768 rc = 0;
1769 out_free:
1770 flexarray_free(front);
1771 flexarray_free(back);
1772 out:
1773 libxl__free_all(&gc);
1774 return rc;
1777 int libxl_device_vfb_clean_shutdown(libxl_ctx *ctx, uint32_t domid)
1779 return ERROR_NI;
1782 int libxl_device_vfb_hard_shutdown(libxl_ctx *ctx, uint32_t domid)
1784 return ERROR_NI;
1787 /******************************************************************************/
1789 int libxl_domain_setmaxmem(libxl_ctx *ctx, uint32_t domid, uint32_t max_memkb)
1791 libxl__gc gc = LIBXL_INIT_GC(ctx);
1792 char *mem, *endptr;
1793 uint32_t memorykb;
1794 char *dompath = libxl__xs_get_dompath(&gc, domid);
1795 int rc = 1;
1797 mem = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/memory/target", dompath));
1798 if (!mem) {
1799 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "cannot get memory info from %s/memory/target\n", dompath);
1800 goto out;
1802 memorykb = strtoul(mem, &endptr, 10);
1803 if (*endptr != '\0') {
1804 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "invalid memory %s from %s/memory/target\n", mem, dompath);
1805 goto out;
1808 if (max_memkb < memorykb) {
1809 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "memory_static_max must be greater than or or equal to memory_dynamic_max\n");
1810 goto out;
1813 rc = 0;
1814 out:
1815 libxl__free_all(&gc);
1816 return rc;
1819 static int libxl__fill_dom0_memory_info(libxl__gc *gc, uint32_t *target_memkb)
1821 int rc;
1822 libxl_dominfo info;
1823 libxl_physinfo physinfo;
1824 char *target = NULL, *staticmax = NULL, *freememslack = NULL, *endptr = NULL;
1825 char *target_path = "/local/domain/0/memory/target";
1826 char *max_path = "/local/domain/0/memory/static-max";
1827 char *free_mem_slack_path = "/local/domain/0/memory/freemem-slack";
1828 xs_transaction_t t;
1829 libxl_ctx *ctx = libxl__gc_owner(gc);
1830 uint32_t free_mem_slack_kb = 0;
1832 retry_transaction:
1833 t = xs_transaction_start(ctx->xsh);
1835 target = libxl__xs_read(gc, t, target_path);
1836 staticmax = libxl__xs_read(gc, t, max_path);
1837 freememslack = libxl__xs_read(gc, t, free_mem_slack_path);
1838 if (target && staticmax && freememslack) {
1839 rc = 0;
1840 goto out;
1843 if (target) {
1844 *target_memkb = strtoul(target, &endptr, 10);
1845 if (*endptr != '\0') {
1846 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
1847 "invalid memory target %s from %s\n", target, target_path);
1848 rc = ERROR_FAIL;
1849 goto out;
1853 rc = libxl_domain_info(ctx, &info, 0);
1854 if (rc < 0)
1855 goto out;
1857 rc = libxl_get_physinfo(ctx, &physinfo);
1858 if (rc < 0)
1859 goto out;
1861 if (target == NULL) {
1862 libxl__xs_write(gc, t, target_path, "%"PRIu32,
1863 (uint32_t) info.current_memkb);
1864 *target_memkb = (uint32_t) info.current_memkb;
1866 if (staticmax == NULL)
1867 libxl__xs_write(gc, t, max_path, "%"PRIu32,
1868 (uint32_t) info.max_memkb);
1870 if (freememslack == NULL) {
1871 free_mem_slack_kb = (uint32_t) (PAGE_TO_MEMKB(physinfo.total_pages) -
1872 info.current_memkb);
1873 /* From empirical measurements the free_mem_slack shouldn't be more
1874 * than 15% of the total memory present on the system. */
1875 if (free_mem_slack_kb > PAGE_TO_MEMKB(physinfo.total_pages) * 0.15)
1876 free_mem_slack_kb = PAGE_TO_MEMKB(physinfo.total_pages) * 0.15;
1877 libxl__xs_write(gc, t, free_mem_slack_path, "%"PRIu32, free_mem_slack_kb);
1879 rc = 0;
1881 out:
1882 if (!xs_transaction_end(ctx->xsh, t, 0)) {
1883 if (errno == EAGAIN)
1884 goto retry_transaction;
1885 else
1886 rc = ERROR_FAIL;
1890 return rc;
1893 /* returns how much memory should be left free in the system */
1894 static int libxl__get_free_memory_slack(libxl__gc *gc, uint32_t *free_mem_slack)
1896 int rc;
1897 char *free_mem_slack_path = "/local/domain/0/memory/freemem-slack";
1898 char *free_mem_slack_s, *endptr;
1899 uint32_t target_memkb;
1901 retry:
1902 free_mem_slack_s = libxl__xs_read(gc, XBT_NULL, free_mem_slack_path);
1903 if (!free_mem_slack_s) {
1904 rc = libxl__fill_dom0_memory_info(gc, &target_memkb);
1905 if (rc < 0)
1906 return rc;
1907 goto retry;
1908 } else {
1909 *free_mem_slack = strtoul(free_mem_slack_s, &endptr, 10);
1910 if (*endptr != '\0') {
1911 LIBXL__LOG_ERRNO(gc->owner, LIBXL__LOG_ERROR,
1912 "invalid free_mem_slack %s from %s\n",
1913 free_mem_slack_s, free_mem_slack_path);
1914 return ERROR_FAIL;
1917 return 0;
1920 int libxl_set_memory_target(libxl_ctx *ctx, uint32_t domid,
1921 int32_t target_memkb, int relative, int enforce)
1923 libxl__gc gc = LIBXL_INIT_GC(ctx);
1924 int rc = 1, abort = 0;
1925 uint32_t memorykb = 0, videoram = 0;
1926 uint32_t current_target_memkb = 0, new_target_memkb = 0;
1927 char *memmax, *endptr, *videoram_s = NULL, *target = NULL;
1928 char *dompath = libxl__xs_get_dompath(&gc, domid);
1929 xc_domaininfo_t info;
1930 libxl_dominfo ptr;
1931 char *uuid;
1932 xs_transaction_t t;
1934 retry_transaction:
1935 t = xs_transaction_start(ctx->xsh);
1937 target = libxl__xs_read(&gc, t, libxl__sprintf(&gc,
1938 "%s/memory/target", dompath));
1939 if (!target && !domid) {
1940 xs_transaction_end(ctx->xsh, t, 1);
1941 rc = libxl__fill_dom0_memory_info(&gc, &current_target_memkb);
1942 if (rc < 0) {
1943 abort = 1;
1944 goto out;
1946 goto retry_transaction;
1947 } else if (!target) {
1948 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
1949 "cannot get target memory info from %s/memory/target\n",
1950 dompath);
1951 abort = 1;
1952 goto out;
1953 } else {
1954 current_target_memkb = strtoul(target, &endptr, 10);
1955 if (*endptr != '\0') {
1956 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
1957 "invalid memory target %s from %s/memory/target\n",
1958 target, dompath);
1959 abort = 1;
1960 goto out;
1963 memmax = libxl__xs_read(&gc, t, libxl__sprintf(&gc,
1964 "%s/memory/static-max", dompath));
1965 if (!memmax) {
1966 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
1967 "cannot get memory info from %s/memory/static-max\n",
1968 dompath);
1969 abort = 1;
1970 goto out;
1972 memorykb = strtoul(memmax, &endptr, 10);
1973 if (*endptr != '\0') {
1974 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
1975 "invalid max memory %s from %s/memory/static-max\n",
1976 memmax, dompath);
1977 abort = 1;
1978 goto out;
1981 if (relative)
1982 new_target_memkb = current_target_memkb + target_memkb;
1983 else
1984 new_target_memkb = target_memkb;
1985 if (new_target_memkb > memorykb) {
1986 LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
1987 "memory_dynamic_max must be less than or equal to"
1988 " memory_static_max\n");
1989 abort = 1;
1990 goto out;
1993 if (!domid && new_target_memkb < LIBXL_MIN_DOM0_MEM) {
1994 LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
1995 "new target %d for dom0 is below the minimum threshold\n",
1996 new_target_memkb);
1997 abort = 1;
1998 goto out;
2000 videoram_s = libxl__xs_read(&gc, t, libxl__sprintf(&gc,
2001 "%s/memory/videoram", dompath));
2002 videoram = videoram_s ? atoi(videoram_s) : 0;
2004 if (enforce) {
2005 memorykb = new_target_memkb;
2006 rc = xc_domain_setmaxmem(ctx->xch, domid, memorykb +
2007 LIBXL_MAXMEM_CONSTANT);
2008 if (rc != 0) {
2009 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
2010 "xc_domain_setmaxmem domid=%d memkb=%d failed "
2011 "rc=%d\n", domid, memorykb + LIBXL_MAXMEM_CONSTANT, rc);
2012 abort = 1;
2013 goto out;
2017 new_target_memkb -= videoram;
2018 rc = xc_domain_set_pod_target(ctx->xch, domid,
2019 new_target_memkb / 4, NULL, NULL, NULL);
2020 if (rc != 0) {
2021 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
2022 "xc_domain_set_pod_target domid=%d, memkb=%d "
2023 "failed rc=%d\n", domid, new_target_memkb / 4,
2024 rc);
2025 abort = 1;
2026 goto out;
2029 libxl__xs_write(&gc, t, libxl__sprintf(&gc, "%s/memory/target",
2030 dompath), "%"PRIu32, new_target_memkb);
2031 rc = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
2032 if (rc != 1 || info.domain != domid) {
2033 abort = 1;
2034 goto out;
2036 xcinfo2xlinfo(&info, &ptr);
2037 uuid = libxl__uuid2string(&gc, ptr.uuid);
2038 libxl__xs_write(&gc, t, libxl__sprintf(&gc, "/vm/%s/memory", uuid),
2039 "%"PRIu32, new_target_memkb / 1024);
2041 out:
2042 if (!xs_transaction_end(ctx->xsh, t, abort) && !abort)
2043 if (errno == EAGAIN)
2044 goto retry_transaction;
2046 libxl__free_all(&gc);
2047 return rc;
2050 int libxl_get_memory_target(libxl_ctx *ctx, uint32_t domid, uint32_t *out_target)
2052 libxl__gc gc = LIBXL_INIT_GC(ctx);
2053 int rc = 1;
2054 char *target = NULL, *endptr = NULL;
2055 char *dompath = libxl__xs_get_dompath(&gc, domid);
2056 uint32_t target_memkb;
2058 target = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc,
2059 "%s/memory/target", dompath));
2060 if (!target && !domid) {
2061 rc = libxl__fill_dom0_memory_info(&gc, &target_memkb);
2062 if (rc < 0)
2063 goto out;
2064 } else if (!target) {
2065 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
2066 "cannot get target memory info from %s/memory/target\n",
2067 dompath);
2068 goto out;
2069 } else {
2070 target_memkb = strtoul(target, &endptr, 10);
2071 if (*endptr != '\0') {
2072 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
2073 "invalid memory target %s from %s/memory/target\n",
2074 target, dompath);
2075 goto out;
2078 *out_target = target_memkb;
2079 rc = 0;
2081 out:
2082 libxl__free_all(&gc);
2083 return rc;
2086 int libxl_domain_need_memory(libxl_ctx *ctx, libxl_domain_build_info *b_info,
2087 libxl_device_model_info *dm_info, uint32_t *need_memkb)
2089 *need_memkb = b_info->target_memkb;
2090 if (b_info->hvm) {
2091 *need_memkb += b_info->shadow_memkb + LIBXL_HVM_EXTRA_MEMORY;
2092 if (strstr(dm_info->device_model, "stubdom-dm"))
2093 *need_memkb += 32 * 1024;
2094 } else
2095 *need_memkb += b_info->shadow_memkb + LIBXL_PV_EXTRA_MEMORY;
2096 if (*need_memkb % (2 * 1024))
2097 *need_memkb += (2 * 1024) - (*need_memkb % (2 * 1024));
2098 return 0;
2101 int libxl_get_free_memory(libxl_ctx *ctx, uint32_t *memkb)
2103 int rc = 0;
2104 libxl_physinfo info;
2105 uint32_t freemem_slack;
2106 libxl__gc gc = LIBXL_INIT_GC(ctx);
2108 rc = libxl_get_physinfo(ctx, &info);
2109 if (rc < 0)
2110 goto out;
2111 rc = libxl__get_free_memory_slack(&gc, &freemem_slack);
2112 if (rc < 0)
2113 goto out;
2115 if ((info.free_pages + info.scrub_pages) * 4 > freemem_slack)
2116 *memkb = (info.free_pages + info.scrub_pages) * 4 - freemem_slack;
2117 else
2118 *memkb = 0;
2120 out:
2121 libxl__free_all(&gc);
2122 return rc;
2125 int libxl_wait_for_free_memory(libxl_ctx *ctx, uint32_t domid, uint32_t
2126 memory_kb, int wait_secs)
2128 int rc = 0;
2129 libxl_physinfo info;
2130 uint32_t freemem_slack;
2131 libxl__gc gc = LIBXL_INIT_GC(ctx);
2133 rc = libxl__get_free_memory_slack(&gc, &freemem_slack);
2134 if (rc < 0)
2135 goto out;
2136 while (wait_secs > 0) {
2137 rc = libxl_get_physinfo(ctx, &info);
2138 if (rc < 0)
2139 goto out;
2140 if (info.free_pages * 4 - freemem_slack >= memory_kb) {
2141 rc = 0;
2142 goto out;
2144 wait_secs--;
2145 sleep(1);
2147 rc = ERROR_NOMEM;
2149 out:
2150 libxl__free_all(&gc);
2151 return rc;
2154 int libxl_wait_for_memory_target(libxl_ctx *ctx, uint32_t domid, int wait_secs)
2156 int rc = 0;
2157 uint32_t target_memkb = 0;
2158 libxl_dominfo info;
2160 do {
2161 wait_secs--;
2162 sleep(1);
2164 rc = libxl_get_memory_target(ctx, domid, &target_memkb);
2165 if (rc < 0)
2166 goto out;
2168 rc = libxl_domain_info(ctx, &info, domid);
2169 if (rc < 0)
2170 return rc;
2171 } while (wait_secs > 0 && info.current_memkb > target_memkb);
2173 if (info.current_memkb <= target_memkb)
2174 rc = 0;
2175 else
2176 rc = ERROR_FAIL;
2178 out:
2179 return 0;
2182 int libxl_button_press(libxl_ctx *ctx, uint32_t domid, libxl_button button)
2184 int rc = -1;
2186 switch (button) {
2187 case POWER_BUTTON:
2188 rc = xc_domain_send_trigger(ctx->xch, domid, XEN_DOMCTL_SENDTRIGGER_POWER, 0);
2189 break;
2190 case SLEEP_BUTTON:
2191 rc = xc_domain_send_trigger(ctx->xch, domid, XEN_DOMCTL_SENDTRIGGER_SLEEP, 0);
2192 break;
2193 default:
2194 break;
2197 return rc;
2200 int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
2202 xc_physinfo_t xcphysinfo = { 0 };
2203 int rc;
2205 rc = xc_physinfo(ctx->xch, &xcphysinfo);
2206 if (rc != 0) {
2207 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting physinfo");
2208 return ERROR_FAIL;
2210 physinfo->threads_per_core = xcphysinfo.threads_per_core;
2211 physinfo->cores_per_socket = xcphysinfo.cores_per_socket;
2212 physinfo->max_cpu_id = xcphysinfo.max_cpu_id;
2213 physinfo->nr_cpus = xcphysinfo.nr_cpus;
2214 physinfo->cpu_khz = xcphysinfo.cpu_khz;
2215 physinfo->total_pages = xcphysinfo.total_pages;
2216 physinfo->free_pages = xcphysinfo.free_pages;
2217 physinfo->scrub_pages = xcphysinfo.scrub_pages;
2218 physinfo->nr_nodes = xcphysinfo.nr_nodes;
2219 memcpy(physinfo->hw_cap,xcphysinfo.hw_cap, sizeof(physinfo->hw_cap));
2220 physinfo->phys_cap = xcphysinfo.capabilities;
2222 return 0;
2225 int libxl_get_topologyinfo(libxl_ctx *ctx, libxl_topologyinfo *info)
2227 xc_topologyinfo_t tinfo;
2228 DECLARE_HYPERCALL_BUFFER(xc_cpu_to_core_t, coremap);
2229 DECLARE_HYPERCALL_BUFFER(xc_cpu_to_socket_t, socketmap);
2230 DECLARE_HYPERCALL_BUFFER(xc_cpu_to_node_t, nodemap);
2231 int i;
2232 int rc = 0;
2234 rc += libxl_cpuarray_alloc(ctx, &info->coremap);
2235 rc += libxl_cpuarray_alloc(ctx, &info->socketmap);
2236 rc += libxl_cpuarray_alloc(ctx, &info->nodemap);
2237 if (rc)
2238 goto fail;
2240 coremap = xc_hypercall_buffer_alloc(ctx->xch, coremap, sizeof(*coremap) * info->coremap.entries);
2241 socketmap = xc_hypercall_buffer_alloc(ctx->xch, socketmap, sizeof(*socketmap) * info->socketmap.entries);
2242 nodemap = xc_hypercall_buffer_alloc(ctx->xch, nodemap, sizeof(*nodemap) * info->nodemap.entries);
2243 if ((coremap == NULL) || (socketmap == NULL) || (nodemap == NULL))
2244 goto fail;
2246 set_xen_guest_handle(tinfo.cpu_to_core, coremap);
2247 set_xen_guest_handle(tinfo.cpu_to_socket, socketmap);
2248 set_xen_guest_handle(tinfo.cpu_to_node, nodemap);
2249 tinfo.max_cpu_index = info->coremap.entries - 1;
2250 if (xc_topologyinfo(ctx->xch, &tinfo) != 0)
2251 goto fail;
2253 for (i = 0; i <= tinfo.max_cpu_index; i++) {
2254 if (i < info->coremap.entries)
2255 info->coremap.array[i] = (coremap[i] == INVALID_TOPOLOGY_ID) ?
2256 LIBXL_CPUARRAY_INVALID_ENTRY : coremap[i];
2257 if (i < info->socketmap.entries)
2258 info->socketmap.array[i] = (socketmap[i] == INVALID_TOPOLOGY_ID) ?
2259 LIBXL_CPUARRAY_INVALID_ENTRY : socketmap[i];
2260 if (i < info->nodemap.entries)
2261 info->nodemap.array[i] = (nodemap[i] == INVALID_TOPOLOGY_ID) ?
2262 LIBXL_CPUARRAY_INVALID_ENTRY : nodemap[i];
2265 xc_hypercall_buffer_free(ctx->xch, coremap);
2266 xc_hypercall_buffer_free(ctx->xch, socketmap);
2267 xc_hypercall_buffer_free(ctx->xch, nodemap);
2268 return 0;
2270 fail:
2271 xc_hypercall_buffer_free(ctx->xch, coremap);
2272 xc_hypercall_buffer_free(ctx->xch, socketmap);
2273 xc_hypercall_buffer_free(ctx->xch, nodemap);
2274 libxl_topologyinfo_destroy(info);
2275 return ERROR_FAIL;
2278 const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx)
2280 union {
2281 xen_extraversion_t xen_extra;
2282 xen_compile_info_t xen_cc;
2283 xen_changeset_info_t xen_chgset;
2284 xen_capabilities_info_t xen_caps;
2285 xen_platform_parameters_t p_parms;
2286 xen_commandline_t xen_commandline;
2287 } u;
2288 long xen_version;
2289 libxl_version_info *info = &ctx->version_info;
2291 if (info->xen_version_extra != NULL)
2292 return info;
2294 xen_version = xc_version(ctx->xch, XENVER_version, NULL);
2295 info->xen_version_major = xen_version >> 16;
2296 info->xen_version_minor = xen_version & 0xFF;
2298 xc_version(ctx->xch, XENVER_extraversion, &u.xen_extra);
2299 info->xen_version_extra = strdup(u.xen_extra);
2301 xc_version(ctx->xch, XENVER_compile_info, &u.xen_cc);
2302 info->compiler = strdup(u.xen_cc.compiler);
2303 info->compile_by = strdup(u.xen_cc.compile_by);
2304 info->compile_domain = strdup(u.xen_cc.compile_domain);
2305 info->compile_date = strdup(u.xen_cc.compile_date);
2307 xc_version(ctx->xch, XENVER_capabilities, &u.xen_caps);
2308 info->capabilities = strdup(u.xen_caps);
2310 xc_version(ctx->xch, XENVER_changeset, &u.xen_chgset);
2311 info->changeset = strdup(u.xen_chgset);
2313 xc_version(ctx->xch, XENVER_platform_parameters, &u.p_parms);
2314 info->virt_start = u.p_parms.virt_start;
2316 info->pagesize = xc_version(ctx->xch, XENVER_pagesize, NULL);
2318 xc_version(ctx->xch, XENVER_commandline, &u.xen_commandline);
2319 info->commandline = strdup(u.xen_commandline);
2321 return info;
2324 libxl_vcpuinfo *libxl_list_vcpu(libxl_ctx *ctx, uint32_t domid,
2325 int *nb_vcpu, int *nrcpus)
2327 libxl_vcpuinfo *ptr, *ret;
2328 xc_domaininfo_t domaininfo;
2329 xc_vcpuinfo_t vcpuinfo;
2331 if (xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo) != 1) {
2332 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting infolist");
2333 return NULL;
2335 *nrcpus = libxl_get_max_cpus(ctx);
2336 ret = ptr = calloc(domaininfo.max_vcpu_id + 1, sizeof (libxl_vcpuinfo));
2337 if (!ptr) {
2338 return NULL;
2341 for (*nb_vcpu = 0; *nb_vcpu <= domaininfo.max_vcpu_id; ++*nb_vcpu, ++ptr) {
2342 if (libxl_cpumap_alloc(ctx, &ptr->cpumap)) {
2343 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "allocating cpumap");
2344 return NULL;
2346 if (xc_vcpu_getinfo(ctx->xch, domid, *nb_vcpu, &vcpuinfo) == -1) {
2347 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting vcpu info");
2348 return NULL;
2350 if (xc_vcpu_getaffinity(ctx->xch, domid, *nb_vcpu, ptr->cpumap.map) == -1) {
2351 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting vcpu affinity");
2352 return NULL;
2354 ptr->vcpuid = *nb_vcpu;
2355 ptr->cpu = vcpuinfo.cpu;
2356 ptr->online = !!vcpuinfo.online;
2357 ptr->blocked = !!vcpuinfo.blocked;
2358 ptr->running = !!vcpuinfo.running;
2359 ptr->vcpu_time = vcpuinfo.cpu_time;
2361 return ret;
2364 int libxl_set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid, uint32_t vcpuid,
2365 libxl_cpumap *cpumap)
2367 if (xc_vcpu_setaffinity(ctx->xch, domid, vcpuid, cpumap->map)) {
2368 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "setting vcpu affinity");
2369 return ERROR_FAIL;
2371 return 0;
2374 int libxl_set_vcpuonline(libxl_ctx *ctx, uint32_t domid, uint32_t bitmask)
2376 libxl__gc gc = LIBXL_INIT_GC(ctx);
2377 libxl_dominfo info;
2378 char *dompath;
2379 xs_transaction_t t;
2380 int i, rc = ERROR_FAIL;
2382 if (libxl_domain_info(ctx, &info, domid) < 0) {
2383 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting domain info list");
2384 goto out;
2386 if (!(dompath = libxl__xs_get_dompath(&gc, domid)))
2387 goto out;
2389 retry_transaction:
2390 t = xs_transaction_start(ctx->xsh);
2391 for (i = 0; i <= info.vcpu_max_id; i++)
2392 libxl__xs_write(&gc, t,
2393 libxl__sprintf(&gc, "%s/cpu/%u/availability", dompath, i),
2394 "%s", ((1 << i) & bitmask) ? "online" : "offline");
2395 if (!xs_transaction_end(ctx->xsh, t, 0)) {
2396 if (errno == EAGAIN)
2397 goto retry_transaction;
2398 } else
2399 rc = 0;
2400 out:
2401 libxl__free_all(&gc);
2402 return rc;
2405 /*
2406 * returns one of the XEN_SCHEDULER_* constants from public/domctl.h
2407 */
2408 int libxl_get_sched_id(libxl_ctx *ctx)
2410 int sched, ret;
2412 if ((ret = xc_sched_id(ctx->xch, &sched)) != 0) {
2413 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting domain info list");
2414 return ERROR_FAIL;
2416 return sched;
2419 int libxl_sched_credit_domain_get(libxl_ctx *ctx, uint32_t domid, libxl_sched_credit *scinfo)
2421 struct xen_domctl_sched_credit sdom;
2422 int rc;
2424 rc = xc_sched_credit_domain_get(ctx->xch, domid, &sdom);
2425 if (rc != 0) {
2426 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "setting domain sched credit");
2427 return ERROR_FAIL;
2430 scinfo->weight = sdom.weight;
2431 scinfo->cap = sdom.cap;
2433 return 0;
2436 int libxl_sched_credit_domain_set(libxl_ctx *ctx, uint32_t domid, libxl_sched_credit *scinfo)
2438 struct xen_domctl_sched_credit sdom;
2439 xc_domaininfo_t domaininfo;
2440 int rc;
2442 rc = xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo);
2443 if (rc < 0) {
2444 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting domain info list");
2445 return ERROR_FAIL;
2447 if (rc != 1 || domaininfo.domain != domid)
2448 return ERROR_INVAL;
2451 if (scinfo->weight < 1 || scinfo->weight > 65535) {
2452 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2453 "Cpu weight out of range, valid values are within range from 1 to 65535");
2454 return ERROR_INVAL;
2457 if (scinfo->cap < 0 || scinfo->cap > (domaininfo.max_vcpu_id + 1) * 100) {
2458 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2459 "Cpu cap out of range, valid range is from 0 to %d for specified number of vcpus",
2460 ((domaininfo.max_vcpu_id + 1) * 100));
2461 return ERROR_INVAL;
2464 sdom.weight = scinfo->weight;
2465 sdom.cap = scinfo->cap;
2467 rc = xc_sched_credit_domain_set(ctx->xch, domid, &sdom);
2468 if ( rc < 0 ) {
2469 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "setting domain sched credit");
2470 return ERROR_FAIL;
2473 return 0;
2476 static int trigger_type_from_string(char *trigger_name)
2478 if (!strcmp(trigger_name, "nmi"))
2479 return XEN_DOMCTL_SENDTRIGGER_NMI;
2480 else if (!strcmp(trigger_name, "reset"))
2481 return XEN_DOMCTL_SENDTRIGGER_RESET;
2482 else if (!strcmp(trigger_name, "init"))
2483 return XEN_DOMCTL_SENDTRIGGER_INIT;
2484 else if (!strcmp(trigger_name, "power"))
2485 return XEN_DOMCTL_SENDTRIGGER_POWER;
2486 else if (!strcmp(trigger_name, "sleep"))
2487 return XEN_DOMCTL_SENDTRIGGER_SLEEP;
2488 else
2489 return -1;
2492 int libxl_send_trigger(libxl_ctx *ctx, uint32_t domid, char *trigger_name, uint32_t vcpuid)
2494 int rc = -1;
2495 int trigger_type = trigger_type_from_string(trigger_name);
2497 if (trigger_type == -1) {
2498 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, -1,
2499 "Invalid trigger, valid triggers are <nmi|reset|init|power|sleep>");
2500 return ERROR_INVAL;
2503 rc = xc_domain_send_trigger(ctx->xch, domid, trigger_type, vcpuid);
2504 if (rc != 0) {
2505 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2506 "Send trigger '%s' failed", trigger_name);
2507 return ERROR_FAIL;
2510 return 0;
2513 int libxl_send_sysrq(libxl_ctx *ctx, uint32_t domid, char sysrq)
2515 libxl__gc gc = LIBXL_INIT_GC(ctx);
2516 char *dompath = libxl__xs_get_dompath(&gc, domid);
2518 libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/control/sysrq", dompath), "%c", sysrq);
2520 libxl__free_all(&gc);
2521 return 0;
2524 int libxl_send_debug_keys(libxl_ctx *ctx, char *keys)
2526 int ret;
2527 ret = xc_send_debug_keys(ctx->xch, keys);
2528 if ( ret < 0 ) {
2529 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "sending debug keys");
2530 return ERROR_FAIL;
2532 return 0;
2535 libxl_xen_console_reader *
2536 libxl_xen_console_read_start(libxl_ctx *ctx, int clear)
2538 libxl_xen_console_reader *cr;
2539 unsigned int size = 16384;
2540 char *buf = malloc(size);
2542 if (!buf) {
2543 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "cannot malloc buffer for libxl_xen_console_reader,"
2544 " size is %u", size);
2545 return NULL;
2548 cr = malloc(sizeof(libxl_xen_console_reader));
2549 if (!cr) {
2550 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "cannot malloc libxl_xen_console_reader");
2551 return NULL;
2554 memset(cr, 0, sizeof(libxl_xen_console_reader));
2555 cr->buffer = buf;
2556 cr->size = size;
2557 cr->count = size;
2558 cr->clear = clear;
2559 cr->incremental = 1;
2561 return cr;
2564 /* return values: *line_r
2565 * 1 success, whole line obtained from buffer non-0
2566 * 0 no more lines available right now 0
2567 * negative error code ERROR_* 0
2568 * On success *line_r is updated to point to a nul-terminated
2569 * string which is valid until the next call on the same console
2570 * reader. The libxl caller may overwrite parts of the string
2571 * if it wishes. */
2572 int libxl_xen_console_read_line(libxl_ctx *ctx,
2573 libxl_xen_console_reader *cr,
2574 char **line_r)
2576 int ret;
2578 memset(cr->buffer, 0, cr->size);
2579 ret = xc_readconsolering(ctx->xch, cr->buffer, &cr->count,
2580 cr->clear, cr->incremental, &cr->index);
2581 if (ret < 0) {
2582 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "reading console ring buffer");
2583 return ERROR_FAIL;
2585 if (!ret) {
2586 if (cr->count) {
2587 *line_r = cr->buffer;
2588 ret = 1;
2589 } else {
2590 *line_r = NULL;
2591 ret = 0;
2595 return ret;
2598 void libxl_xen_console_read_finish(libxl_ctx *ctx,
2599 libxl_xen_console_reader *cr)
2601 free(cr->buffer);
2602 free(cr);
2605 uint32_t libxl_vm_get_start_time(libxl_ctx *ctx, uint32_t domid)
2607 libxl__gc gc = LIBXL_INIT_GC(ctx);
2608 char *dompath = libxl__xs_get_dompath(&gc, domid);
2609 char *vm_path, *start_time;
2610 uint32_t ret;
2612 vm_path = libxl__xs_read(
2613 &gc, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dompath));
2614 start_time = libxl__xs_read(
2615 &gc, XBT_NULL, libxl__sprintf(&gc, "%s/start_time", vm_path));
2616 if (start_time == NULL) {
2617 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, -1,
2618 "Can't get start time of domain '%d'", domid);
2619 ret = -1;
2620 }else{
2621 ret = strtoul(start_time, NULL, 10);
2623 libxl__free_all(&gc);
2624 return ret;
2627 char *libxl_tmem_list(libxl_ctx *ctx, uint32_t domid, int use_long)
2629 int rc;
2630 char _buf[32768];
2632 rc = xc_tmem_control(ctx->xch, -1, TMEMC_LIST, domid, 32768, use_long,
2633 0, _buf);
2634 if (rc < 0) {
2635 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2636 "Can not get tmem list");
2637 return NULL;
2640 return strdup(_buf);
2643 int libxl_tmem_freeze(libxl_ctx *ctx, uint32_t domid)
2645 int rc;
2647 rc = xc_tmem_control(ctx->xch, -1, TMEMC_FREEZE, domid, 0, 0,
2648 0, NULL);
2649 if (rc < 0) {
2650 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2651 "Can not freeze tmem pools");
2652 return ERROR_FAIL;
2655 return rc;
2658 int libxl_tmem_destroy(libxl_ctx *ctx, uint32_t domid)
2660 int rc;
2662 rc = xc_tmem_control(ctx->xch, -1, TMEMC_DESTROY, domid, 0, 0,
2663 0, NULL);
2664 if (rc < 0) {
2665 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2666 "Can not destroy tmem pools");
2667 return ERROR_FAIL;
2670 return rc;
2673 int libxl_tmem_thaw(libxl_ctx *ctx, uint32_t domid)
2675 int rc;
2677 rc = xc_tmem_control(ctx->xch, -1, TMEMC_THAW, domid, 0, 0,
2678 0, NULL);
2679 if (rc < 0) {
2680 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2681 "Can not thaw tmem pools");
2682 return ERROR_FAIL;
2685 return rc;
2688 static int32_t tmem_setop_from_string(char *set_name)
2690 if (!strcmp(set_name, "weight"))
2691 return TMEMC_SET_WEIGHT;
2692 else if (!strcmp(set_name, "cap"))
2693 return TMEMC_SET_CAP;
2694 else if (!strcmp(set_name, "compress"))
2695 return TMEMC_SET_COMPRESS;
2696 else
2697 return -1;
2700 int libxl_tmem_set(libxl_ctx *ctx, uint32_t domid, char* name, uint32_t set)
2702 int rc;
2703 int32_t subop = tmem_setop_from_string(name);
2705 if (subop == -1) {
2706 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, -1,
2707 "Invalid set, valid sets are <weight|cap|compress>");
2708 return ERROR_INVAL;
2710 rc = xc_tmem_control(ctx->xch, -1, subop, domid, set, 0, 0, NULL);
2711 if (rc < 0) {
2712 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2713 "Can not set tmem %s", name);
2714 return ERROR_FAIL;
2717 return rc;
2720 int libxl_tmem_shared_auth(libxl_ctx *ctx, uint32_t domid,
2721 char* uuid, int auth)
2723 int rc;
2725 rc = xc_tmem_auth(ctx->xch, domid, uuid, auth);
2726 if (rc < 0) {
2727 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2728 "Can not set tmem shared auth");
2729 return ERROR_FAIL;
2732 return rc;
2735 int libxl_tmem_freeable(libxl_ctx *ctx)
2737 int rc;
2739 rc = xc_tmem_control(ctx->xch, -1, TMEMC_QUERY_FREEABLE_MB, -1, 0, 0, 0, 0);
2740 if (rc < 0) {
2741 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2742 "Can not get tmem freeable memory");
2743 return ERROR_FAIL;
2746 return rc;
2749 void libxl_file_reference_destroy(libxl_file_reference *f)
2751 libxl__file_reference_unmap(f);
2752 free(f->path);
2755 int libxl_get_freecpus(libxl_ctx *ctx, libxl_cpumap *cpumap)
2757 int ncpus;
2759 ncpus = libxl_get_max_cpus(ctx);
2760 if (ncpus == 0)
2761 return ERROR_FAIL;
2763 cpumap->map = xc_cpupool_freeinfo(ctx->xch);
2764 if (cpumap->map == NULL)
2765 return ERROR_FAIL;
2767 cpumap->size = (ncpus + 7) / 8;
2769 return 0;
2772 int libxl_create_cpupool(libxl_ctx *ctx, const char *name, int schedid,
2773 libxl_cpumap cpumap, libxl_uuid *uuid,
2774 uint32_t *poolid)
2776 libxl__gc gc = LIBXL_INIT_GC(ctx);
2777 int rc;
2778 int i;
2779 xs_transaction_t t;
2780 char *uuid_string;
2782 uuid_string = libxl__uuid2string(&gc, *uuid);
2783 if (!uuid_string) {
2784 libxl__free_all(&gc);
2785 return ERROR_NOMEM;
2788 rc = xc_cpupool_create(ctx->xch, poolid, schedid);
2789 if (rc) {
2790 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2791 "Could not create cpupool");
2792 libxl__free_all(&gc);
2793 return ERROR_FAIL;
2796 libxl_for_each_cpu(i, cpumap)
2797 if (libxl_cpumap_test(&cpumap, i)) {
2798 rc = xc_cpupool_addcpu(ctx->xch, *poolid, i);
2799 if (rc) {
2800 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2801 "Error moving cpu to cpupool");
2802 libxl_destroy_cpupool(ctx, *poolid);
2803 libxl__free_all(&gc);
2804 return ERROR_FAIL;
2808 for (;;) {
2809 t = xs_transaction_start(ctx->xsh);
2811 xs_mkdir(ctx->xsh, t, libxl__sprintf(&gc, "/local/pool/%d", *poolid));
2812 libxl__xs_write(&gc, t,
2813 libxl__sprintf(&gc, "/local/pool/%d/uuid", *poolid),
2814 "%s", uuid_string);
2815 libxl__xs_write(&gc, t,
2816 libxl__sprintf(&gc, "/local/pool/%d/name", *poolid),
2817 "%s", name);
2819 if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN)) {
2820 libxl__free_all(&gc);
2821 return 0;
2826 int libxl_destroy_cpupool(libxl_ctx *ctx, uint32_t poolid)
2828 libxl__gc gc = LIBXL_INIT_GC(ctx);
2829 int rc, i;
2830 xc_cpupoolinfo_t *info;
2831 xs_transaction_t t;
2832 libxl_cpumap cpumap;
2834 info = xc_cpupool_getinfo(ctx->xch, poolid);
2835 if (info == NULL) {
2836 libxl__free_all(&gc);
2837 return ERROR_NOMEM;
2840 rc = ERROR_INVAL;
2841 if ((info->cpupool_id != poolid) || (info->n_dom))
2842 goto out;
2844 rc = ERROR_NOMEM;
2845 if (libxl_cpumap_alloc(ctx, &cpumap))
2846 goto out;
2848 memcpy(cpumap.map, info->cpumap, cpumap.size);
2849 libxl_for_each_cpu(i, cpumap)
2850 if (libxl_cpumap_test(&cpumap, i)) {
2851 rc = xc_cpupool_removecpu(ctx->xch, poolid, i);
2852 if (rc) {
2853 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2854 "Error removing cpu from cpupool");
2855 rc = ERROR_FAIL;
2856 goto out1;
2860 rc = xc_cpupool_destroy(ctx->xch, poolid);
2861 if (rc) {
2862 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "Could not destroy cpupool");
2863 rc = ERROR_FAIL;
2864 goto out1;
2867 for (;;) {
2868 t = xs_transaction_start(ctx->xsh);
2870 xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "/local/pool/%d", poolid));
2872 if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN))
2873 break;
2876 rc = 0;
2878 out1:
2879 libxl_cpumap_destroy(&cpumap);
2880 out:
2881 xc_cpupool_infofree(ctx->xch, info);
2882 libxl__free_all(&gc);
2884 return rc;
2887 int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid)
2889 libxl__gc gc = LIBXL_INIT_GC(ctx);
2890 xs_transaction_t t;
2891 xc_cpupoolinfo_t *info;
2892 int rc;
2894 info = xc_cpupool_getinfo(ctx->xch, poolid);
2895 if (info == NULL) {
2896 libxl__free_all(&gc);
2897 return ERROR_NOMEM;
2900 rc = ERROR_INVAL;
2901 if (info->cpupool_id != poolid)
2902 goto out;
2904 rc = 0;
2906 for (;;) {
2907 t = xs_transaction_start(ctx->xsh);
2909 libxl__xs_write(&gc, t,
2910 libxl__sprintf(&gc, "/local/pool/%d/name", poolid),
2911 "%s", name);
2913 if (xs_transaction_end(ctx->xsh, t, 0))
2914 break;
2916 if (errno == EAGAIN)
2917 continue;
2919 rc = ERROR_FAIL;
2920 break;
2923 out:
2924 xc_cpupool_infofree(ctx->xch, info);
2925 libxl__free_all(&gc);
2927 return rc;
2930 int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu)
2932 int rc;
2934 rc = xc_cpupool_addcpu(ctx->xch, poolid, cpu);
2935 if (rc) {
2936 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2937 "Error moving cpu to cpupool");
2938 return ERROR_FAIL;
2940 return 0;
2943 int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus)
2945 int rc = 0;
2946 int cpu;
2947 libxl_cpumap freemap;
2948 libxl_topologyinfo topology;
2950 if (libxl_get_freecpus(ctx, &freemap)) {
2951 return ERROR_FAIL;
2954 if (libxl_get_topologyinfo(ctx, &topology)) {
2955 rc = ERROR_FAIL;
2956 goto out;
2959 *cpus = 0;
2960 for (cpu = 0; cpu < topology.nodemap.entries; cpu++) {
2961 if (libxl_cpumap_test(&freemap, cpu) &&
2962 (topology.nodemap.array[cpu] == node) &&
2963 !libxl_cpupool_cpuadd(ctx, poolid, cpu)) {
2964 (*cpus)++;
2968 libxl_topologyinfo_destroy(&topology);
2970 out:
2971 libxl_cpumap_destroy(&freemap);
2972 return rc;
2975 int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu)
2977 int rc;
2979 rc = xc_cpupool_removecpu(ctx->xch, poolid, cpu);
2980 if (rc) {
2981 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
2982 "Error removing cpu from cpupool");
2983 return ERROR_FAIL;
2985 return 0;
2988 int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus)
2990 int ret = 0;
2991 int n_pools;
2992 int p;
2993 int cpu;
2994 libxl_topologyinfo topology;
2995 libxl_cpupoolinfo *poolinfo;
2997 poolinfo = libxl_list_cpupool(ctx, &n_pools);
2998 if (!poolinfo) {
2999 return ERROR_NOMEM;
3002 if (libxl_get_topologyinfo(ctx, &topology)) {
3003 ret = ERROR_FAIL;
3004 goto out;
3007 *cpus = 0;
3008 for (p = 0; p < n_pools; p++) {
3009 if (poolinfo[p].poolid == poolid) {
3010 for (cpu = 0; cpu < topology.nodemap.entries; cpu++) {
3011 if ((topology.nodemap.array[cpu] == node) &&
3012 libxl_cpumap_test(&poolinfo[p].cpumap, cpu) &&
3013 !libxl_cpupool_cpuremove(ctx, poolid, cpu)) {
3014 (*cpus)++;
3020 libxl_topologyinfo_destroy(&topology);
3022 out:
3023 for (p = 0; p < n_pools; p++) {
3024 libxl_cpupoolinfo_destroy(poolinfo + p);
3027 return ret;
3030 int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid)
3032 libxl__gc gc = LIBXL_INIT_GC(ctx);
3033 int rc;
3034 char *dom_path;
3035 char *vm_path;
3036 char *poolname;
3037 xs_transaction_t t;
3039 dom_path = libxl__xs_get_dompath(&gc, domid);
3040 if (!dom_path) {
3041 libxl__free_all(&gc);
3042 return ERROR_FAIL;
3045 rc = xc_cpupool_movedomain(ctx->xch, poolid, domid);
3046 if (rc) {
3047 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3048 "Error moving domain to cpupool");
3049 libxl__free_all(&gc);
3050 return ERROR_FAIL;
3053 for (;;) {
3054 t = xs_transaction_start(ctx->xsh);
3056 poolname = libxl__cpupoolid_to_name(&gc, poolid);
3057 vm_path = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dom_path));
3058 if (!vm_path)
3059 break;
3061 libxl__xs_write(&gc, t, libxl__sprintf(&gc, "%s/pool_name", vm_path),
3062 "%s", poolname);
3064 if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN))
3065 break;
3068 libxl__free_all(&gc);
3069 return 0;