libxl_driver.c 194.9 KB
Newer Older
1 2 3
/*
 * libxl_driver.c: core driver methods for managing libxenlight domains
 *
4
 * Copyright (C) 2006-2015 Red Hat, Inc.
5
 * Copyright (C) 2011-2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
6
 * Copyright (C) 2011 Univention GmbH.
J
Jim Fehlig 已提交
7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library.  If not, see
O
Osier Yang 已提交
20
 * <http://www.gnu.org/licenses/>.
M
Markus Groß 已提交
21 22 23 24 25
 *
 * Authors:
 *     Jim Fehlig <jfehlig@novell.com>
 *     Markus Groß <gross@univention.de>
 *     Daniel P. Berrange <berrange@redhat.com>
J
Jim Fehlig 已提交
26 27 28 29
 */

#include <config.h>

30
#include <math.h>
J
Jim Fehlig 已提交
31
#include <libxl.h>
32
#include <libxl_utils.h>
33
#include <xenstore.h>
34
#include <fcntl.h>
35
#include <regex.h>
J
Jim Fehlig 已提交
36 37

#include "internal.h"
38
#include "virlog.h"
39
#include "virerror.h"
40
#include "virconf.h"
J
Jim Fehlig 已提交
41
#include "datatypes.h"
E
Eric Blake 已提交
42
#include "virfile.h"
43
#include "viralloc.h"
44
#include "viruuid.h"
C
Cédric Bosdonnat 已提交
45
#include "virhook.h"
46
#include "vircommand.h"
J
Jim Fehlig 已提交
47
#include "libxl_domain.h"
J
Jim Fehlig 已提交
48 49
#include "libxl_driver.h"
#include "libxl_conf.h"
50
#include "libxl_capabilities.h"
J
Jim Fehlig 已提交
51
#include "libxl_migration.h"
52
#include "xen_xm.h"
53
#include "xen_sxpr.h"
54
#include "xen_xl.h"
55
#include "virtypedparam.h"
M
Martin Kletzander 已提交
56
#include "viruri.h"
57
#include "virstring.h"
58
#include "virsysinfo.h"
59
#include "viraccessapicheck.h"
60
#include "viratomic.h"
61
#include "virhostdev.h"
62
#include "locking/domain_lock.h"
63
#include "virnetdevtap.h"
64
#include "cpu/cpu.h"
J
Jim Fehlig 已提交
65 66 67

#define VIR_FROM_THIS VIR_FROM_LIBXL

68 69
VIR_LOG_INIT("libxl.libxl_driver");

J
Jim Fehlig 已提交
70 71 72 73 74 75
#define LIBXL_DOM_REQ_POWEROFF 0
#define LIBXL_DOM_REQ_REBOOT   1
#define LIBXL_DOM_REQ_SUSPEND  2
#define LIBXL_DOM_REQ_CRASH    3
#define LIBXL_DOM_REQ_HALT     4

76
#define LIBXL_NB_TOTAL_CPU_STAT_PARAM 1
77
#define LIBXL_NB_TOTAL_BLK_STAT_PARAM 6
78

79
#define HYPERVISOR_CAPABILITIES "/proc/xen/capabilities"
R
Roman Bogorodskiy 已提交
80
#define HYPERVISOR_XENSTORED "/dev/xen/xenstored"
81

82 83 84
/* Number of Xen scheduler parameters */
#define XEN_SCHED_CREDIT_NPARAM   2

85 86 87 88
#define LIBXL_CHECK_DOM0_GOTO(name, label) \
    do { \
        if (STREQ_NULLABLE(name, "Domain-0")) { \
            virReportError(VIR_ERR_OPERATION_INVALID, "%s", \
J
Jim Fehlig 已提交
89
                           _("Domain-0 does not support requested operation")); \
90 91
            goto label; \
        } \
J
Jim Fehlig 已提交
92 93
    } while (0)

94

95
static libxlDriverPrivatePtr libxl_driver;
J
Jim Fehlig 已提交
96

97 98 99 100 101 102 103 104 105
/* Object used to store info related to libxl event registrations */
typedef struct _libxlOSEventHookInfo libxlOSEventHookInfo;
typedef libxlOSEventHookInfo *libxlOSEventHookInfoPtr;
struct _libxlOSEventHookInfo {
    libxl_ctx *ctx;
    void *xl_priv;
    int id;
};

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
/* Object used to store disk statistics across multiple xen backends */
typedef struct _libxlBlockStats libxlBlockStats;
typedef libxlBlockStats *libxlBlockStatsPtr;
struct _libxlBlockStats {
    long long rd_req;
    long long rd_bytes;
    long long wr_req;
    long long wr_bytes;
    long long f_req;

    char *backend;
    union {
        struct {
            long long ds_req;
            long long oo_req;
        } vbd;
    } u;
};

J
Jim Fehlig 已提交
125
/* Function declarations */
126 127
static int
libxlDomainManagedSaveLoad(virDomainObjPtr vm,
128 129
                           void *opaque);

J
Jim Fehlig 已提交
130 131

/* Function definitions */
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
static void
libxlOSEventHookInfoFree(void *obj)
{
    VIR_FREE(obj);
}

static void
libxlFDEventCallback(int watch ATTRIBUTE_UNUSED,
                     int fd,
                     int vir_events,
                     void *fd_info)
{
    libxlOSEventHookInfoPtr info = fd_info;
    int events = 0;

    if (vir_events & VIR_EVENT_HANDLE_READABLE)
        events |= POLLIN;
    if (vir_events & VIR_EVENT_HANDLE_WRITABLE)
        events |= POLLOUT;
    if (vir_events & VIR_EVENT_HANDLE_ERROR)
        events |= POLLERR;
    if (vir_events & VIR_EVENT_HANDLE_HANGUP)
        events |= POLLHUP;

    libxl_osevent_occurred_fd(info->ctx, info->xl_priv, fd, 0, events);
}

static int
libxlFDRegisterEventHook(void *priv,
                         int fd,
                         void **hndp,
                         short events,
                         void *xl_priv)
{
    int vir_events = VIR_EVENT_HANDLE_ERROR;
    libxlOSEventHookInfoPtr info;

    if (VIR_ALLOC(info) < 0)
        return -1;

    info->ctx = priv;
    info->xl_priv = xl_priv;

    if (events & POLLIN)
        vir_events |= VIR_EVENT_HANDLE_READABLE;
    if (events & POLLOUT)
        vir_events |= VIR_EVENT_HANDLE_WRITABLE;

    info->id = virEventAddHandle(fd, vir_events, libxlFDEventCallback,
                                 info, libxlOSEventHookInfoFree);
    if (info->id < 0) {
        VIR_FREE(info);
        return -1;
    }

    *hndp = info;

    return 0;
}

static int
libxlFDModifyEventHook(void *priv ATTRIBUTE_UNUSED,
                       int fd ATTRIBUTE_UNUSED,
                       void **hndp,
                       short events)
{
    libxlOSEventHookInfoPtr info = *hndp;
    int vir_events = VIR_EVENT_HANDLE_ERROR;

    if (events & POLLIN)
        vir_events |= VIR_EVENT_HANDLE_READABLE;
    if (events & POLLOUT)
        vir_events |= VIR_EVENT_HANDLE_WRITABLE;

    virEventUpdateHandle(info->id, vir_events);

    return 0;
}

static void
libxlFDDeregisterEventHook(void *priv ATTRIBUTE_UNUSED,
                           int fd ATTRIBUTE_UNUSED,
                           void *hnd)
{
    libxlOSEventHookInfoPtr info = hnd;

    virEventRemoveHandle(info->id);
}

static void
libxlTimerCallback(int timer ATTRIBUTE_UNUSED, void *timer_info)
{
    libxlOSEventHookInfoPtr info = timer_info;

    /*
     * libxl expects the event to be deregistered when calling
     * libxl_osevent_occurred_timeout, but we dont want the event info
     * destroyed.  Disable the timeout and only remove it after returning
     * from libxl.
     */
    virEventUpdateTimeout(info->id, -1);
    libxl_osevent_occurred_timeout(info->ctx, info->xl_priv);
    virEventRemoveTimeout(info->id);
}

static int
libxlTimeoutRegisterEventHook(void *priv,
                              void **hndp,
                              struct timeval abs_t,
                              void *xl_priv)
{
    libxlOSEventHookInfoPtr info;
    struct timeval now;
    struct timeval res;
    static struct timeval zero;
    int timeout;

    if (VIR_ALLOC(info) < 0)
        return -1;

    info->ctx = priv;
    info->xl_priv = xl_priv;

    gettimeofday(&now, NULL);
    timersub(&abs_t, &now, &res);
    /* Ensure timeout is not overflowed */
    if (timercmp(&res, &zero, <)) {
        timeout = 0;
    } else if (res.tv_sec > INT_MAX / 1000) {
        timeout = INT_MAX;
    } else {
        timeout = res.tv_sec * 1000 + (res.tv_usec + 999) / 1000;
    }
    info->id = virEventAddTimeout(timeout, libxlTimerCallback,
                                  info, libxlOSEventHookInfoFree);
    if (info->id < 0) {
        VIR_FREE(info);
        return -1;
    }

    *hndp = info;

    return 0;
}

/*
 * Note:  There are two changes wrt timeouts starting with xen-unstable
 * changeset 26469:
 *
 * 1. Timeout modify callbacks will only be invoked with an abs_t of {0,0},
 * i.e. make the timeout fire immediately.  Prior to this commit, timeout
 * modify callbacks were never invoked.
 *
 * 2. Timeout deregister hooks will no longer be called.
 */
static int
libxlTimeoutModifyEventHook(void *priv ATTRIBUTE_UNUSED,
                            void **hndp,
                            struct timeval abs_t ATTRIBUTE_UNUSED)
{
    libxlOSEventHookInfoPtr info = *hndp;

    /* Make the timeout fire */
    virEventUpdateTimeout(info->id, 0);

    return 0;
}

static void
libxlTimeoutDeregisterEventHook(void *priv ATTRIBUTE_UNUSED,
                                void *hnd)
{
    libxlOSEventHookInfoPtr info = hnd;

    virEventRemoveTimeout(info->id);
}

J
Jim Fehlig 已提交
309 310 311 312 313 314 315
static virDomainObjPtr
libxlDomObjFromDomain(virDomainPtr dom)
{
    virDomainObjPtr vm;
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

316
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
J
Jim Fehlig 已提交
317 318 319 320 321 322 323 324 325 326 327
    if (!vm) {
        virUUIDFormat(dom->uuid, uuidstr);
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s' (%s)"),
                       uuidstr, dom->name);
        return NULL;
    }

    return vm;
}

328 329
static int
libxlAutostartDomain(virDomainObjPtr vm,
330 331 332
                     void *opaque)
{
    libxlDriverPrivatePtr driver = opaque;
333
    int ret = -1;
334

W
Wang Yufei 已提交
335
    virObjectRef(vm);
336
    virObjectLock(vm);
337 338
    virResetLastError();

W
Wang Yufei 已提交
339 340
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;
341

342
    if (vm->autostart && !virDomainObjIsActive(vm) &&
343
        libxlDomainStartNew(driver, vm, false) < 0) {
344 345 346
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to autostart VM '%s': %s"),
                       vm->def->name, virGetLastErrorMessage());
347
        goto endjob;
348 349
    }

350
    ret = 0;
351 352

 endjob:
W
Wang Yufei 已提交
353 354 355
    libxlDomainObjEndJob(driver, vm);
 cleanup:
    virDomainObjEndAPI(&vm);
356

357
    return ret;
358 359
}

J
Jim Fehlig 已提交
360 361 362 363
/*
 * Reconnect to running domains that were previously started/created
 * with libxenlight driver.
 */
364 365
static int
libxlReconnectDomain(virDomainObjPtr vm,
J
Jim Fehlig 已提交
366 367 368
                     void *opaque)
{
    libxlDriverPrivatePtr driver = opaque;
369
    libxlDomainObjPrivatePtr priv = vm->privateData;
J
Jim Fehlig 已提交
370
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
371 372 373 374
    int rc;
    libxl_dominfo d_info;
    int len;
    uint8_t *data = NULL;
375
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
376
    unsigned int hostdev_flags = VIR_HOSTDEV_SP_PCI;
377
    int ret = -1;
378 379 380 381

#ifdef LIBXL_HAVE_PVUSB
    hostdev_flags |= VIR_HOSTDEV_SP_USB;
#endif
J
Jim Fehlig 已提交
382

383
    virObjectRef(vm);
384
    virObjectLock(vm);
J
Jim Fehlig 已提交
385

386 387
    libxl_dominfo_init(&d_info);

J
Jim Fehlig 已提交
388
    /* Does domain still exist? */
J
Jim Fehlig 已提交
389
    rc = libxl_domain_info(cfg->ctx, &d_info, vm->def->id);
J
Jim Fehlig 已提交
390
    if (rc == ERROR_INVAL) {
391
        goto error;
J
Jim Fehlig 已提交
392 393 394
    } else if (rc != 0) {
        VIR_DEBUG("libxl_domain_info failed (code %d), ignoring domain %d",
                  rc, vm->def->id);
395
        goto error;
J
Jim Fehlig 已提交
396 397 398
    }

    /* Is this a domain that was under libvirt control? */
J
Jim Fehlig 已提交
399
    if (libxl_userdata_retrieve(cfg->ctx, vm->def->id,
J
Jim Fehlig 已提交
400 401
                                "libvirt-xml", &data, &len)) {
        VIR_DEBUG("libxl_userdata_retrieve failed, ignoring domain %d", vm->def->id);
402
        goto error;
J
Jim Fehlig 已提交
403 404 405 406
    }

    /* Update domid in case it changed (e.g. reboot) while we were gone? */
    vm->def->id = d_info.domid;
407

408 409
    libxlLoggerOpenFile(cfg->logger, vm->def->id, vm->def->name, NULL);

410
    /* Update hostdev state */
411
    if (virHostdevUpdateActiveDomainDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
412
                                            vm->def, hostdev_flags) < 0)
413
        goto error;
414

415 416 417 418 419 420 421 422 423 424 425
    if (d_info.shutdown &&
            d_info.shutdown_reason == LIBXL_SHUTDOWN_REASON_SUSPEND)
        virDomainObjSetState(vm, VIR_DOMAIN_PMSUSPENDED,
                             VIR_DOMAIN_PMSUSPENDED_UNKNOWN);
    else if (d_info.paused)
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
                             VIR_DOMAIN_PAUSED_UNKNOWN);
    else
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNKNOWN);

426
    if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback)
427 428
        driver->inhibitCallback(true, driver->inhibitOpaque);

429
    /* Enable domain death events */
J
Jim Fehlig 已提交
430
    libxl_evenable_domain_death(cfg->ctx, vm->def->id, 0, &priv->deathW);
431

C
Cédric Bosdonnat 已提交
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
    /* now that we know it's reconnected call the hook if present */
    if (virHookPresent(VIR_HOOK_DRIVER_LIBXL) &&
        STRNEQ("Domain-0", vm->def->name)) {
        char *xml = virDomainDefFormat(vm->def, cfg->caps, 0);
        int hookret;

        /* we can't stop the operation even if the script raised an error */
        hookret = virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
                              VIR_HOOK_LIBXL_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN,
                              NULL, xml, NULL);
        VIR_FREE(xml);
        if (hookret < 0) {
            /* Stop the domain if the hook failed */
            if (virDomainObjIsActive(vm)) {
                libxlDomainDestroyInternal(driver, vm);
                virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED);
            }
            goto error;
        }
    }

453 454 455
    ret = 0;

 cleanup:
456
    libxl_dominfo_dispose(&d_info);
457
    virObjectUnlock(vm);
458
    virObjectUnref(vm);
J
Jim Fehlig 已提交
459
    virObjectUnref(cfg);
460
    return ret;
J
Jim Fehlig 已提交
461

462
 error:
463
    libxlDomainCleanup(driver, vm);
464
    if (!vm->persistent)
465
        virDomainObjListRemoveLocked(driver->domains, vm);
466
    goto cleanup;
J
Jim Fehlig 已提交
467 468 469 470 471
}

static void
libxlReconnectDomains(libxlDriverPrivatePtr driver)
{
472
    virDomainObjListForEach(driver->domains, libxlReconnectDomain, driver);
J
Jim Fehlig 已提交
473 474 475
}

static int
476
libxlStateCleanup(void)
J
Jim Fehlig 已提交
477 478 479 480
{
    if (!libxl_driver)
        return -1;

481
    virObjectUnref(libxl_driver->hostdevMgr);
482
    virObjectUnref(libxl_driver->config);
483
    virObjectUnref(libxl_driver->xmlopt);
484
    virObjectUnref(libxl_driver->domains);
485 486
    virPortAllocatorRangeFree(libxl_driver->reservedGraphicsPorts);
    virPortAllocatorRangeFree(libxl_driver->migrationPorts);
487
    virLockManagerPluginUnref(libxl_driver->lockManager);
J
Jim Fehlig 已提交
488

489
    virObjectUnref(libxl_driver->domainEventState);
490
    virSysinfoDefFree(libxl_driver->hostsysinfo);
491

J
Jim Fehlig 已提交
492 493 494 495 496 497
    virMutexDestroy(&libxl_driver->lock);
    VIR_FREE(libxl_driver);

    return 0;
}

498 499
static bool
libxlDriverShouldLoad(bool privileged)
500
{
501
    bool ret = false;
J
Jim Fehlig 已提交
502

503
    /* Don't load if non-root */
J
Jim Fehlig 已提交
504
    if (!privileged) {
505
        VIR_INFO("Not running privileged, disabling libxenlight driver");
506
        return ret;
J
Jim Fehlig 已提交
507 508
    }

R
Roman Bogorodskiy 已提交
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
    if (virFileExists(HYPERVISOR_CAPABILITIES)) {
        int status;
        char *output = NULL;
        /*
         * Don't load if not running on a Xen control domain (dom0). It is not
         * sufficient to check for the file to exist as any guest can mount
         * xenfs to /proc/xen.
         */
        status = virFileReadAll(HYPERVISOR_CAPABILITIES, 10, &output);
        if (status >= 0)
            status = strncmp(output, "control_d", 9);
        VIR_FREE(output);
        if (status) {
            VIR_INFO("No Xen capabilities detected, probably not running "
                     "in a Xen Dom0.  Disabling libxenlight driver");

            return ret;
        }
    } else if (!virFileExists(HYPERVISOR_XENSTORED)) {
        VIR_INFO("Disabling driver as neither " HYPERVISOR_CAPABILITIES
                 " nor " HYPERVISOR_XENSTORED " exist");
530 531 532 533
        return ret;
    }

    /* Don't load if legacy xen toolstack (xend) is in use */
534 535 536 537 538 539 540 541 542 543 544
    if (virFileExists("/usr/sbin/xend")) {
        virCommandPtr cmd;

        cmd = virCommandNewArgList("/usr/sbin/xend", "status", NULL);
        if (virCommandRun(cmd, NULL) == 0) {
            VIR_INFO("Legacy xen tool stack seems to be in use, disabling "
                     "libxenlight driver.");
        } else {
            ret = true;
        }
        virCommandFree(cmd);
545 546
    } else {
        ret = true;
J
Jim Fehlig 已提交
547 548
    }

549 550 551
    return ret;
}

552 553 554 555 556 557 558 559 560 561
/* Callbacks wrapping libvirt's event loop interface */
static const libxl_osevent_hooks libxl_osevent_callbacks = {
    .fd_register = libxlFDRegisterEventHook,
    .fd_modify = libxlFDModifyEventHook,
    .fd_deregister = libxlFDDeregisterEventHook,
    .timeout_register = libxlTimeoutRegisterEventHook,
    .timeout_modify = libxlTimeoutModifyEventHook,
    .timeout_deregister = libxlTimeoutDeregisterEventHook,
};

562 563 564 565 566 567 568 569
static const libxl_childproc_hooks libxl_child_hooks = {
#ifdef LIBXL_HAVE_SIGCHLD_OWNER_SELECTIVE_REAP
    .chldowner = libxl_sigchld_owner_libxl_always_selective_reap,
#else
    .chldowner = libxl_sigchld_owner_libxl,
#endif
};

570 571 572 573 574 575
const struct libxl_event_hooks ev_hooks = {
    .event_occurs_mask = LIBXL_EVENTMASK_ALL,
    .event_occurs = libxlDomainEventHandler,
    .disaster = NULL,
};

J
Jim Fehlig 已提交
576 577 578 579 580 581 582 583
static int
libxlAddDom0(libxlDriverPrivatePtr driver)
{
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr oldDef = NULL;
    libxl_dominfo d_info;
584
    unsigned long long maxmem;
J
Jim Fehlig 已提交
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
    int ret = -1;

    libxl_dominfo_init(&d_info);

    /* Ensure we have a dom0 */
    if (libxl_domain_info(cfg->ctx, &d_info, 0) != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unable to get Domain-0 information from libxenlight"));
        goto cleanup;
    }

    if (!(def = virDomainDefNew()))
        goto cleanup;

    def->id = 0;
    def->virtType = VIR_DOMAIN_VIRT_XEN;
    if (VIR_STRDUP(def->name, "Domain-0") < 0)
        goto cleanup;

    def->os.type = VIR_DOMAIN_OSTYPE_XEN;

    if (virUUIDParse("00000000-0000-0000-0000-000000000000", def->uuid) < 0)
        goto cleanup;

    if (!(vm = virDomainObjListAdd(driver->domains, def,
                                   driver->xmlopt,
                                   0,
                                   &oldDef)))
        goto cleanup;
    def = NULL;

J
Jim Fehlig 已提交
616
    vm->persistent = 1;
J
Jim Fehlig 已提交
617
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
618
    if (virDomainDefSetVcpusMax(vm->def, d_info.vcpu_max_id + 1, driver->xmlopt))
619 620
        goto cleanup;

621 622
    if (virDomainDefSetVcpus(vm->def, d_info.vcpu_online) < 0)
        goto cleanup;
J
Jim Fehlig 已提交
623
    vm->def->mem.cur_balloon = d_info.current_memkb;
624 625 626
    if (libxlDriverGetDom0MaxmemConf(cfg, &maxmem) < 0)
        maxmem = d_info.current_memkb;
    virDomainDefSetMemoryTotal(vm->def, maxmem);
J
Jim Fehlig 已提交
627 628 629 630 631 632 633

    ret = 0;

 cleanup:
    libxl_dominfo_dispose(&d_info);
    virDomainDefFree(def);
    virDomainDefFree(oldDef);
634
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
635 636 637 638
    virObjectUnref(cfg);
    return ret;
}

639 640 641 642 643
static int
libxlStateInitialize(bool privileged,
                     virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                     void *opaque ATTRIBUTE_UNUSED)
{
644
    libxlDriverConfigPtr cfg;
645
    char *driverConf = NULL;
646 647 648 649 650
    char ebuf[1024];

    if (!libxlDriverShouldLoad(privileged))
        return 0;

J
Jim Fehlig 已提交
651 652 653 654
    if (VIR_ALLOC(libxl_driver) < 0)
        return -1;

    if (virMutexInit(&libxl_driver->lock) < 0) {
655 656
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot initialize mutex"));
J
Jim Fehlig 已提交
657 658 659 660 661
        VIR_FREE(libxl_driver);
        return -1;
    }

    /* Allocate bitmap for vnc port reservation */
662
    if (!(libxl_driver->reservedGraphicsPorts =
663 664
          virPortAllocatorRangeNew(_("VNC"),
                                   LIBXL_VNC_PORT_MIN,
665
                                   LIBXL_VNC_PORT_MAX)))
666
        goto error;
J
Jim Fehlig 已提交
667

J
Jim Fehlig 已提交
668 669
    /* Allocate bitmap for migration port reservation */
    if (!(libxl_driver->migrationPorts =
670 671
          virPortAllocatorRangeNew(_("migration"),
                                   LIBXL_MIGRATION_PORT_MIN,
672
                                   LIBXL_MIGRATION_PORT_MAX)))
J
Jim Fehlig 已提交
673 674
        goto error;

675 676
    if (!(libxl_driver->domains = virDomainObjListNew()))
        goto error;
J
Jim Fehlig 已提交
677

678 679 680
    if (!(libxl_driver->hostdevMgr = virHostdevManagerGetDefault()))
        goto error;

681
    if (!(cfg = libxlDriverConfigNew()))
682
        goto error;
J
Jim Fehlig 已提交
683

684 685 686 687 688 689 690
    if (virAsprintf(&driverConf, "%s/libxl.conf", cfg->configBaseDir) < 0)
        goto error;

    if (libxlDriverConfigLoadFile(cfg, driverConf) < 0)
        goto error;
    VIR_FREE(driverConf);

691 692 693
    /* Register the callbacks providing access to libvirt's event loop */
    libxl_osevent_register_hooks(cfg->ctx, &libxl_osevent_callbacks, cfg->ctx);

694 695 696
    /* Setup child process handling.  See $xen-src/tools/libxl/libxl_event.h */
    libxl_childproc_setmode(cfg->ctx, &libxl_child_hooks, cfg->ctx);

697 698 699
    /* Register callback to handle domain events */
    libxl_event_register_callbacks(cfg->ctx, &ev_hooks, libxl_driver);

700 701
    libxl_driver->config = cfg;
    if (virFileMakePath(cfg->stateDir) < 0) {
702 703
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create state dir '%s': %s"),
704
                       cfg->stateDir,
705
                       virStrerror(errno, ebuf, sizeof(ebuf)));
J
Jim Fehlig 已提交
706 707
        goto error;
    }
708
    if (virFileMakePath(cfg->libDir) < 0) {
709 710
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create lib dir '%s': %s"),
711
                       cfg->libDir,
712
                       virStrerror(errno, ebuf, sizeof(ebuf)));
J
Jim Fehlig 已提交
713 714
        goto error;
    }
715
    if (virFileMakePath(cfg->saveDir) < 0) {
716 717
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create save dir '%s': %s"),
718
                       cfg->saveDir,
719
                       virStrerror(errno, ebuf, sizeof(ebuf)));
J
Jim Fehlig 已提交
720 721
        goto error;
    }
722 723 724 725 726 727 728
    if (virFileMakePath(cfg->autoDumpDir) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create dump dir '%s': %s"),
                       cfg->autoDumpDir,
                       virStrerror(errno, ebuf, sizeof(ebuf)));
        goto error;
    }
J
Joao Martins 已提交
729 730 731 732 733 734 735
    if (virFileMakePath(cfg->channelDir) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create channel dir '%s': %s"),
                       cfg->channelDir,
                       virStrerror(errno, ebuf, sizeof(ebuf)));
        goto error;
    }
J
Jim Fehlig 已提交
736

737 738 739 740 741 742 743 744
    if (!(libxl_driver->lockManager =
          virLockManagerPluginNew(cfg->lockManagerName ?
                                  cfg->lockManagerName : "nop",
                                  "libxl",
                                  cfg->configBaseDir,
                                  0)))
        goto error;

745
    /* read the host sysinfo */
746
    libxl_driver->hostsysinfo = virSysinfoRead();
747

748
    libxl_driver->domainEventState = virObjectEventStateNew();
E
Eric Blake 已提交
749
    if (!libxl_driver->domainEventState)
750 751
        goto error;

752
    if ((cfg->caps = libxlMakeCapabilities(cfg->ctx)) == NULL) {
753 754
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot create capabilities for libxenlight"));
J
Jim Fehlig 已提交
755 756 757
        goto error;
    }

758
    if (!(libxl_driver->xmlopt = libxlCreateXMLConf()))
759
        goto error;
J
Jim Fehlig 已提交
760

J
Jim Fehlig 已提交
761 762 763 764
    /* Add Domain-0 */
    if (libxlAddDom0(libxl_driver) < 0)
        goto error;

J
Jim Fehlig 已提交
765
    /* Load running domains first. */
766
    if (virDomainObjListLoadAllConfigs(libxl_driver->domains,
767 768
                                       cfg->stateDir,
                                       cfg->autostartDir,
769
                                       true,
770
                                       cfg->caps,
771
                                       libxl_driver->xmlopt,
772
                                       NULL, NULL) < 0)
J
Jim Fehlig 已提交
773 774 775 776 777
        goto error;

    libxlReconnectDomains(libxl_driver);

    /* Then inactive persistent configs */
778
    if (virDomainObjListLoadAllConfigs(libxl_driver->domains,
779 780
                                       cfg->configDir,
                                       cfg->autostartDir,
781
                                       false,
782
                                       cfg->caps,
783
                                       libxl_driver->xmlopt,
784
                                       NULL, NULL) < 0)
J
Jim Fehlig 已提交
785 786
        goto error;

787 788
    virDomainObjListForEach(libxl_driver->domains, libxlDomainManagedSaveLoad,
                            libxl_driver);
789

J
Jim Fehlig 已提交
790 791
    return 0;

792
 error:
793
    VIR_FREE(driverConf);
794
    libxlStateCleanup();
795
    return -1;
J
Jim Fehlig 已提交
796 797
}

798 799 800 801 802 803 804 805 806 807
static void
libxlStateAutoStart(void)
{
    if (!libxl_driver)
        return;

    virDomainObjListForEach(libxl_driver->domains, libxlAutostartDomain,
                            libxl_driver);
}

J
Jim Fehlig 已提交
808
static int
809
libxlStateReload(void)
J
Jim Fehlig 已提交
810
{
811 812
    libxlDriverConfigPtr cfg;

J
Jim Fehlig 已提交
813 814 815
    if (!libxl_driver)
        return 0;

816 817
    cfg = libxlDriverConfigGet(libxl_driver);

818
    virDomainObjListLoadAllConfigs(libxl_driver->domains,
819 820
                                   cfg->configDir,
                                   cfg->autostartDir,
821
                                   true,
822
                                   cfg->caps,
823
                                   libxl_driver->xmlopt,
824 825
                                   NULL, libxl_driver);

826 827
    virDomainObjListForEach(libxl_driver->domains, libxlAutostartDomain,
                            libxl_driver);
828

829
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
830 831 832 833
    return 0;
}


834 835 836 837 838 839 840 841 842 843
static int
libxlConnectURIProbe(char **uri)
{
    if (libxl_driver == NULL)
        return 0;

    return VIR_STRDUP(*uri, "xen:///system");
}


J
Jim Fehlig 已提交
844
static virDrvOpenStatus
845 846
libxlConnectOpen(virConnectPtr conn,
                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
847
                 virConfPtr conf ATTRIBUTE_UNUSED,
848
                 unsigned int flags)
J
Jim Fehlig 已提交
849
{
E
Eric Blake 已提交
850 851
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

852 853 854 855 856 857
    /* Error if xen or libxl scheme specified but driver not started. */
    if (libxl_driver == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight state driver is not active"));
        return VIR_DRV_OPEN_ERROR;
    }
J
Jim Fehlig 已提交
858

859
    /* /session isn't supported in libxenlight */
860
    if (STRNEQ(conn->uri->path, "") &&
861 862 863 864
        STRNEQ(conn->uri->path, "/") &&
        STRNEQ(conn->uri->path, "/system")) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected Xen URI path '%s', try xen:///system"),
865
                       conn->uri->path);
866
        return VIR_DRV_OPEN_ERROR;
J
Jim Fehlig 已提交
867 868
    }

869 870 871
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

J
Jim Fehlig 已提交
872 873 874 875 876 877
    conn->privateData = libxl_driver;

    return VIR_DRV_OPEN_SUCCESS;
};

static int
878
libxlConnectClose(virConnectPtr conn ATTRIBUTE_UNUSED)
J
Jim Fehlig 已提交
879 880 881 882 883 884
{
    conn->privateData = NULL;
    return 0;
}

static const char *
885
libxlConnectGetType(virConnectPtr conn)
J
Jim Fehlig 已提交
886
{
887 888 889
    if (virConnectGetTypeEnsureACL(conn) < 0)
        return NULL;

J
Jim Fehlig 已提交
890
    return "Xen";
J
Jim Fehlig 已提交
891 892 893
}

static int
894
libxlConnectGetVersion(virConnectPtr conn, unsigned long *version)
J
Jim Fehlig 已提交
895 896
{
    libxlDriverPrivatePtr driver = conn->privateData;
897
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
898

899 900 901
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return 0;

902 903 904
    cfg = libxlDriverConfigGet(driver);
    *version = cfg->version;
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
905 906 907
    return 0;
}

908

909
static char *libxlConnectGetHostname(virConnectPtr conn)
910
{
911 912 913
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

914 915 916
    return virGetHostname();
}

917 918 919 920 921 922 923 924
static char *
libxlConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virCheckFlags(0, NULL);

925 926 927
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

928 929 930 931 932 933 934 935
    if (!driver->hostsysinfo) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Host SMBIOS information is not available"));
        return NULL;
    }

    if (virSysinfoFormat(&buf, driver->hostsysinfo) < 0)
        return NULL;
936
    if (virBufferCheckError(&buf) < 0)
937 938 939
        return NULL;
    return virBufferContentAndReset(&buf);
}
940

J
Jim Fehlig 已提交
941
static int
942
libxlConnectGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED)
J
Jim Fehlig 已提交
943 944 945
{
    int ret;
    libxlDriverPrivatePtr driver = conn->privateData;
946
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
947

948 949 950
    if (virConnectGetMaxVcpusEnsureACL(conn) < 0)
        return -1;

951 952
    cfg = libxlDriverConfigGet(driver);
    ret = libxl_get_max_cpus(cfg->ctx);
953 954 955 956 957
    /* On failure, libxl_get_max_cpus() will return ERROR_FAIL from Xen 4.4
     * onward, but it ever returning 0 is obviously wrong too (and it is
     * what happens, on failure, on Xen 4.3 and earlier). Therefore, a 'less
     * or equal' is the catchall we want. */
    if (ret <= 0)
958
        ret = -1;
J
Jim Fehlig 已提交
959

960
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
961 962 963 964 965 966
    return ret;
}

static int
libxlNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
{
967 968 969
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

970
    return libxlDriverNodeGetInfo(conn->privateData, info);
J
Jim Fehlig 已提交
971 972 973
}

static char *
974
libxlConnectGetCapabilities(virConnectPtr conn)
J
Jim Fehlig 已提交
975 976 977
{
    libxlDriverPrivatePtr driver = conn->privateData;
    char *xml;
978
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
979

980 981 982
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

983
    cfg = libxlDriverConfigGet(driver);
984
    xml = virCapabilitiesFormatXML(cfg->caps);
J
Jim Fehlig 已提交
985

986
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
987 988 989 990
    return xml;
}

static int
991
libxlConnectListDomains(virConnectPtr conn, int *ids, int nids)
J
Jim Fehlig 已提交
992 993 994 995
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

996 997 998
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

999 1000
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
J
Jim Fehlig 已提交
1001 1002 1003 1004 1005

    return n;
}

static int
1006
libxlConnectNumOfDomains(virConnectPtr conn)
J
Jim Fehlig 已提交
1007 1008 1009 1010
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

1011 1012 1013
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

1014 1015
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
J
Jim Fehlig 已提交
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027

    return n;
}

static virDomainPtr
libxlDomainCreateXML(virConnectPtr conn, const char *xml,
                     unsigned int flags)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virDomainDefPtr def;
    virDomainObjPtr vm = NULL;
    virDomainPtr dom = NULL;
1028
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1029
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
J
Jim Fehlig 已提交
1030

1031 1032 1033 1034
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
                  VIR_DOMAIN_START_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_START_VALIDATE)
1035
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
J
Jim Fehlig 已提交
1036

1037
    if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt,
1038
                                        NULL, parse_flags)))
J
Jim Fehlig 已提交
1039 1040
        goto cleanup;

1041 1042 1043
    if (virDomainCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

1044
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1045
                                   driver->xmlopt,
1046
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1047 1048
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
J
Jim Fehlig 已提交
1049 1050 1051
        goto cleanup;
    def = NULL;

1052
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) {
1053
        if (!vm->persistent)
1054 1055 1056 1057
            virDomainObjListRemove(driver->domains, vm);
        goto cleanup;
    }

1058 1059
    if (libxlDomainStartNew(driver, vm,
                         (flags & VIR_DOMAIN_START_PAUSED) != 0) < 0) {
1060
        if (!vm->persistent)
1061
            virDomainObjListRemove(driver->domains, vm);
1062
        goto endjob;
J
Jim Fehlig 已提交
1063 1064
    }

1065
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
J
Jim Fehlig 已提交
1066

1067
 endjob:
W
Wang Yufei 已提交
1068
    libxlDomainObjEndJob(driver, vm);
1069

1070
 cleanup:
J
Jim Fehlig 已提交
1071
    virDomainDefFree(def);
W
Wang Yufei 已提交
1072
    virDomainObjEndAPI(&vm);
1073
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
    return dom;
}

static virDomainPtr
libxlDomainLookupByID(virConnectPtr conn, int id)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

1084
    vm = virDomainObjListFindByID(driver->domains, id);
J
Jim Fehlig 已提交
1085
    if (!vm) {
1086
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
1087 1088 1089
        goto cleanup;
    }

1090 1091 1092
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1093
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
J
Jim Fehlig 已提交
1094

1095
 cleanup:
1096
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
    return dom;
}

static virDomainPtr
libxlDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

1107
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
J
Jim Fehlig 已提交
1108
    if (!vm) {
1109
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
1110 1111 1112
        goto cleanup;
    }

1113 1114 1115
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1116
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
J
Jim Fehlig 已提交
1117

1118
 cleanup:
1119
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
    return dom;
}

static virDomainPtr
libxlDomainLookupByName(virConnectPtr conn, const char *name)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

1130
    vm = virDomainObjListFindByName(driver->domains, name);
J
Jim Fehlig 已提交
1131
    if (!vm) {
1132
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
1133 1134 1135
        goto cleanup;
    }

1136 1137 1138
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1139
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
J
Jim Fehlig 已提交
1140

1141
 cleanup:
1142
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1143 1144 1145
    return dom;
}

1146 1147 1148 1149
static int
libxlDomainSuspend(virDomainPtr dom)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1150
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1151
    virDomainObjPtr vm;
1152
    virObjectEventPtr event = NULL;
1153 1154
    int ret = -1;

J
Jim Fehlig 已提交
1155
    if (!(vm = libxlDomObjFromDomain(dom)))
1156
        goto cleanup;
1157

J
Jim Fehlig 已提交
1158 1159
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

1160 1161 1162
    if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1163 1164 1165
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1166
    if (virDomainObjCheckActive(vm) < 0)
1167
        goto endjob;
1168

J
Jiri Denemark 已提交
1169
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
J
Jim Fehlig 已提交
1170
        if (libxl_domain_pause(cfg->ctx, vm->def->id) != 0) {
1171 1172
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to suspend domain '%d' with libxenlight"),
1173
                           vm->def->id);
1174
            goto endjob;
1175 1176
        }

J
Jiri Denemark 已提交
1177
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
1178

1179
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
1180 1181 1182
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

1183
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
1184
        goto endjob;
1185 1186 1187

    ret = 0;

1188
 endjob:
W
Wang Yufei 已提交
1189
    libxlDomainObjEndJob(driver, vm);
1190

1191
 cleanup:
W
Wang Yufei 已提交
1192
    virDomainObjEndAPI(&vm);
1193
    virObjectEventStateQueue(driver->domainEventState, event);
1194
    virObjectUnref(cfg);
1195 1196 1197 1198 1199 1200 1201 1202
    return ret;
}


static int
libxlDomainResume(virDomainPtr dom)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1203
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1204
    virDomainObjPtr vm;
1205
    virObjectEventPtr event = NULL;
1206 1207
    int ret = -1;

J
Jim Fehlig 已提交
1208
    if (!(vm = libxlDomObjFromDomain(dom)))
1209 1210
        goto cleanup;

J
Jim Fehlig 已提交
1211 1212
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

1213 1214 1215
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1216 1217 1218
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1219
    if (virDomainObjCheckActive(vm) < 0)
1220
        goto endjob;
1221

J
Jiri Denemark 已提交
1222
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
J
Jim Fehlig 已提交
1223
        if (libxl_domain_unpause(cfg->ctx, vm->def->id) != 0) {
1224 1225
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to resume domain '%d' with libxenlight"),
1226
                           vm->def->id);
1227
            goto endjob;
1228 1229
        }

J
Jiri Denemark 已提交
1230 1231
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
1232

1233
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_RESUMED,
1234 1235 1236
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

1237
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
1238
        goto endjob;
1239 1240 1241

    ret = 0;

1242
 endjob:
W
Wang Yufei 已提交
1243
    libxlDomainObjEndJob(driver, vm);
1244

1245
 cleanup:
W
Wang Yufei 已提交
1246
    virDomainObjEndAPI(&vm);
1247
    virObjectEventStateQueue(driver->domainEventState, event);
1248
    virObjectUnref(cfg);
1249 1250 1251
    return ret;
}

J
Jim Fehlig 已提交
1252
static int
1253
libxlDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
1254
{
J
Jim Fehlig 已提交
1255 1256
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1257 1258 1259
    virDomainObjPtr vm;
    int ret = -1;

1260 1261 1262 1263 1264
    virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
                  VIR_DOMAIN_SHUTDOWN_PARAVIRT, -1);
    if (flags == 0)
        flags = VIR_DOMAIN_SHUTDOWN_PARAVIRT |
            VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN;
1265

J
Jim Fehlig 已提交
1266
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1267 1268
        goto cleanup;

J
Jim Fehlig 已提交
1269 1270
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

1271
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
1272 1273
        goto cleanup;

1274
    if (virDomainObjCheckActive(vm) < 0)
J
Jim Fehlig 已提交
1275 1276
        goto cleanup;

1277
    if (flags & VIR_DOMAIN_SHUTDOWN_PARAVIRT) {
J
Jim Fehlig 已提交
1278
        ret = libxl_domain_shutdown(cfg->ctx, vm->def->id);
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
        if (ret == 0)
            goto cleanup;

        if (ret != ERROR_NOPARAVIRT) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to shutdown domain '%d' with libxenlight"),
                           vm->def->id);
            ret = -1;
            goto cleanup;
        }
        ret = -1;
    }

    if (flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) {
J
Jim Fehlig 已提交
1293
        ret = libxl_send_trigger(cfg->ctx, vm->def->id,
1294 1295 1296 1297
                                 LIBXL_TRIGGER_POWER, 0);
        if (ret == 0)
            goto cleanup;

1298 1299
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to shutdown domain '%d' with libxenlight"),
1300
                       vm->def->id);
1301
        ret = -1;
J
Jim Fehlig 已提交
1302 1303
    }

1304
 cleanup:
1305
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1306
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1307 1308 1309
    return ret;
}

1310 1311 1312 1313 1314 1315 1316
static int
libxlDomainShutdown(virDomainPtr dom)
{
    return libxlDomainShutdownFlags(dom, 0);
}


J
Jim Fehlig 已提交
1317
static int
E
Eric Blake 已提交
1318
libxlDomainReboot(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
1319
{
J
Jim Fehlig 已提交
1320 1321
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1322 1323 1324
    virDomainObjPtr vm;
    int ret = -1;

J
Jim Fehlig 已提交
1325 1326 1327
    virCheckFlags(VIR_DOMAIN_REBOOT_PARAVIRT, -1);
    if (flags == 0)
        flags = VIR_DOMAIN_REBOOT_PARAVIRT;
E
Eric Blake 已提交
1328

J
Jim Fehlig 已提交
1329
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1330 1331
        goto cleanup;

J
Jim Fehlig 已提交
1332 1333
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

1334
    if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
1335 1336
        goto cleanup;

1337
    if (virDomainObjCheckActive(vm) < 0)
J
Jim Fehlig 已提交
1338 1339
        goto cleanup;

J
Jim Fehlig 已提交
1340
    if (flags & VIR_DOMAIN_REBOOT_PARAVIRT) {
J
Jim Fehlig 已提交
1341
        ret = libxl_domain_reboot(cfg->ctx, vm->def->id);
J
Jim Fehlig 已提交
1342 1343 1344
        if (ret == 0)
            goto cleanup;

1345 1346
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to reboot domain '%d' with libxenlight"),
1347
                       vm->def->id);
J
Jim Fehlig 已提交
1348
        ret = -1;
J
Jim Fehlig 已提交
1349 1350
    }

1351
 cleanup:
1352
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1353
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1354 1355 1356 1357
    return ret;
}

static int
1358 1359
libxlDomainDestroyFlags(virDomainPtr dom,
                        unsigned int flags)
J
Jim Fehlig 已提交
1360 1361
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
J
Jim Fehlig 已提交
1362
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1363 1364
    virDomainObjPtr vm;
    int ret = -1;
1365
    virObjectEventPtr event = NULL;
J
Jim Fehlig 已提交
1366

1367 1368
    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
1369
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1370 1371
        goto cleanup;

J
Jim Fehlig 已提交
1372 1373
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

1374 1375 1376
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1377 1378 1379
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1380
    if (virDomainObjCheckActive(vm) < 0)
1381
        goto endjob;
J
Jim Fehlig 已提交
1382

1383
    if (libxlDomainDestroyInternal(driver, vm) < 0) {
1384
        virReportError(VIR_ERR_INTERNAL_ERROR,
1385
                       _("Failed to destroy domain '%d'"), vm->def->id);
1386
        goto endjob;
J
Jim Fehlig 已提交
1387 1388
    }

1389 1390 1391 1392 1393 1394 1395
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
                         VIR_DOMAIN_SHUTOFF_DESTROYED);

    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);

    libxlDomainCleanup(driver, vm);
1396
    if (!vm->persistent)
1397
        virDomainObjListRemove(driver->domains, vm);
J
Jim Fehlig 已提交
1398 1399 1400

    ret = 0;

1401
 endjob:
W
Wang Yufei 已提交
1402
    libxlDomainObjEndJob(driver, vm);
1403

1404
 cleanup:
W
Wang Yufei 已提交
1405
    virDomainObjEndAPI(&vm);
1406
    virObjectEventStateQueue(driver->domainEventState, event);
J
Jim Fehlig 已提交
1407
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1408 1409 1410
    return ret;
}

1411 1412 1413 1414 1415 1416
static int
libxlDomainDestroy(virDomainPtr dom)
{
    return libxlDomainDestroyFlags(dom, 0);
}

1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539
#ifdef LIBXL_HAVE_DOMAIN_SUSPEND_ONLY
static int
libxlDomainPMSuspendForDuration(virDomainPtr dom,
                                unsigned int target,
                                unsigned long long duration,
                                unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);

    virCheckFlags(0, -1);
    if (target != VIR_NODE_SUSPEND_TARGET_MEM) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
                _("PMSuspend type %d not supported by libxenlight driver"),
                target);
        return -1;
    }

    if (duration != 0) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                _("Duration not supported. Use 0 for now"));
        return -1;
    }

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainPMSuspendForDurationEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

    if (!virDomainObjCheckActive(vm))
        goto endjob;

    /* Unlock virDomainObjPtr to not deadlock with even handler, which will try
     * to send lifecycle event
     */
    virObjectUnlock(vm);
    ret = libxl_domain_suspend_only(cfg->ctx, vm->def->id, NULL);
    virObjectLock(vm);

    if (ret < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to suspend domain '%d'"), vm->def->id);
        goto endjob;
    }

    ret = 0;

 endjob:
    libxlDomainObjEndJob(driver, vm);

 cleanup:
    virDomainObjEndAPI(&vm);
    return ret;
}
#endif

static int
libxlDomainPMWakeup(virDomainPtr dom, unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    virObjectEventPtr event = NULL;
    libxlDomainObjPrivatePtr priv;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);

    virCheckFlags(0, -1);

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainPMWakeupEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PMSUSPENDED) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not suspended"));
        goto endjob;
    }


    priv = vm->privateData;
    if (libxl_domain_resume(cfg->ctx, vm->def->id, 1, NULL) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to resume domain '%d'"), vm->def->id);
        goto endjob;
    }
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_WAKEUP);
    /* reenable death event - libxl reports it only once */
    if (priv->deathW)
        libxl_evdisable_domain_death(cfg->ctx, priv->deathW);
    if (libxl_evenable_domain_death(cfg->ctx, vm->def->id, 0, &priv->deathW))
        goto destroy_dom;

    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_WAKEUP);

    ret = 0;
    goto endjob;

 destroy_dom:
    libxlDomainDestroyInternal(driver, vm);
    vm->def->id = -1;
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED);

 endjob:
    libxlDomainObjEndJob(driver, vm);

 cleanup:
    virDomainObjEndAPI(&vm);
    virObjectEventStateQueue(driver->domainEventState, event);
    return ret;
}

1540 1541 1542 1543 1544 1545
static char *
libxlDomainGetOSType(virDomainPtr dom)
{
    virDomainObjPtr vm;
    char *type = NULL;

J
Jim Fehlig 已提交
1546
    if (!(vm = libxlDomObjFromDomain(dom)))
1547 1548
        goto cleanup;

1549 1550 1551
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1552
    if (VIR_STRDUP(type, virDomainOSTypeToString(vm->def->os.type)) < 0)
1553
        goto cleanup;
1554

1555
 cleanup:
1556
    virDomainObjEndAPI(&vm);
1557 1558 1559
    return type;
}

1560
static unsigned long long
1561 1562 1563
libxlDomainGetMaxMemory(virDomainPtr dom)
{
    virDomainObjPtr vm;
1564
    unsigned long long ret = 0;
1565

J
Jim Fehlig 已提交
1566
    if (!(vm = libxlDomObjFromDomain(dom)))
1567
        goto cleanup;
1568 1569 1570 1571

    if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1572
    ret = virDomainDefGetMemoryTotal(vm->def);
1573

1574
 cleanup:
1575
    virDomainObjEndAPI(&vm);
1576 1577 1578
    return ret;
}

1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608

/*
 * Helper method for --current, --live, and --config options, and check
 * whether domain is active or can get persistent domain configuration.
 *
 * Return 0 if success, also change the flags and get the persistent
 * domain configuration if needed. Return -1 on error.
 */
static int
virDomainLiveConfigHelperMethod(virCapsPtr caps,
                                virDomainXMLOptionPtr xmlopt,
                                virDomainObjPtr dom,
                                unsigned int *flags,
                                virDomainDefPtr *persistentDef)
{
    if (virDomainObjUpdateModificationImpact(dom, flags) < 0)
        return -1;

    if (*flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (!(*persistentDef = virDomainObjGetPersistentDef(caps, xmlopt, dom))) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Get persistent config failed"));
            return -1;
        }
    }

    return 0;
}


1609
static int
1610
libxlDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
1611 1612 1613
                          unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1614
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1615
    virDomainObjPtr vm;
1616
    virDomainDefPtr persistentDef = NULL;
1617 1618 1619
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_MEM_LIVE |
1620 1621
                  VIR_DOMAIN_MEM_CONFIG |
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
1622

J
Jim Fehlig 已提交
1623
    if (!(vm = libxlDomObjFromDomain(dom)))
1624 1625
        goto cleanup;

1626 1627 1628
    if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

1629 1630 1631
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1632 1633
    if (virDomainLiveConfigHelperMethod(cfg->caps, driver->xmlopt, vm, &flags,
                                        &persistentDef) < 0)
1634
        goto endjob;
1635

1636 1637
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */
1638

1639
        if (flags & VIR_DOMAIN_MEM_LIVE) {
J
Jim Fehlig 已提交
1640
            if (libxl_domain_setmaxmem(cfg->ctx, vm->def->id, newmem) < 0) {
1641 1642
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to set maximum memory for domain '%d'"
1643
                                 " with libxenlight"), vm->def->id);
1644
                goto endjob;
1645 1646 1647 1648 1649 1650
            }
        }

        if (flags & VIR_DOMAIN_MEM_CONFIG) {
            /* Help clang 2.8 decipher the logic flow.  */
            sa_assert(persistentDef);
1651
            virDomainDefSetMemoryTotal(persistentDef, newmem);
1652 1653
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
1654
            ret = virDomainSaveConfig(cfg->configDir, cfg->caps, persistentDef);
1655
            goto endjob;
1656 1657
        }

1658 1659
    } else {
        /* resize the current memory */
1660

1661
        if (newmem > virDomainDefGetMemoryTotal(vm->def)) {
1662 1663
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("cannot set memory higher than max memory"));
1664
            goto endjob;
1665 1666 1667
        }

        if (flags & VIR_DOMAIN_MEM_LIVE) {
1668 1669 1670 1671
            int res;

            /* Unlock virDomainObj while ballooning memory */
            virObjectUnlock(vm);
J
Jim Fehlig 已提交
1672
            res = libxl_set_memory_target(cfg->ctx, vm->def->id, newmem, 0,
1673 1674 1675
                                          /* force */ 1);
            virObjectLock(vm);
            if (res < 0) {
1676 1677
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to set memory for domain '%d'"
1678
                                 " with libxenlight"), vm->def->id);
1679
                goto endjob;
1680 1681 1682 1683 1684 1685
            }
        }

        if (flags & VIR_DOMAIN_MEM_CONFIG) {
            sa_assert(persistentDef);
            persistentDef->mem.cur_balloon = newmem;
1686
            ret = virDomainSaveConfig(cfg->configDir, cfg->caps, persistentDef);
1687
            goto endjob;
1688
        }
1689 1690
    }

1691 1692
    ret = 0;

1693
 endjob:
W
Wang Yufei 已提交
1694
    libxlDomainObjEndJob(driver, vm);
1695

1696
 cleanup:
W
Wang Yufei 已提交
1697
    virDomainObjEndAPI(&vm);
1698
    virObjectUnref(cfg);
1699 1700 1701 1702 1703 1704 1705 1706 1707
    return ret;
}

static int
libxlDomainSetMemory(virDomainPtr dom, unsigned long memory)
{
    return libxlDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_LIVE);
}

1708 1709 1710 1711 1712 1713
static int
libxlDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
{
    return libxlDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
}

J
Jim Fehlig 已提交
1714 1715 1716
static int
libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
J
Jim Fehlig 已提交
1717 1718
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1719
    virDomainObjPtr vm;
1720
    libxl_dominfo d_info;
J
Jim Fehlig 已提交
1721 1722
    int ret = -1;

J
Jim Fehlig 已提交
1723
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1724 1725
        goto cleanup;

1726 1727 1728
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1729
    info->maxMem = virDomainDefGetMemoryTotal(vm->def);
1730 1731 1732 1733
    if (!virDomainObjIsActive(vm)) {
        info->cpuTime = 0;
        info->memory = vm->def->mem.cur_balloon;
    } else {
1734 1735
        libxl_dominfo_init(&d_info);

J
Jim Fehlig 已提交
1736
        if (libxl_domain_info(cfg->ctx, &d_info, vm->def->id) != 0) {
1737
            virReportError(VIR_ERR_INTERNAL_ERROR,
1738 1739
                           _("libxl_domain_info failed for domain '%d'"),
                           vm->def->id);
1740 1741 1742 1743
            goto cleanup;
        }
        info->cpuTime = d_info.cpu_time;
        info->memory = d_info.current_memkb;
1744 1745

        libxl_dominfo_dispose(&d_info);
1746 1747
    }

J
Jiri Denemark 已提交
1748
    info->state = virDomainObjGetState(vm, NULL);
1749
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
J
Jim Fehlig 已提交
1750 1751
    ret = 0;

1752
 cleanup:
1753
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1754
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1755 1756 1757
    return ret;
}

1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768
static int
libxlDomainGetState(virDomainPtr dom,
                    int *state,
                    int *reason,
                    unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
1769
    if (!(vm = libxlDomObjFromDomain(dom)))
1770 1771
        goto cleanup;

1772 1773 1774
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1775
    *state = virDomainObjGetState(vm, reason);
1776 1777
    ret = 0;

1778
 cleanup:
1779
    virDomainObjEndAPI(&vm);
1780 1781 1782
    return ret;
}

1783 1784 1785
/*
 * virDomainObjPtr must be locked on invocation
 */
1786
static int
1787 1788 1789 1790
libxlDoDomainSave(libxlDriverPrivatePtr driver,
                  virDomainObjPtr vm,
                  const char *to,
                  bool managed)
1791
{
J
Jim Fehlig 已提交
1792
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1793
    libxlSavefileHeader hdr;
1794
    virObjectEventPtr event = NULL;
1795 1796
    char *xml = NULL;
    uint32_t xml_len;
1797
    int fd = -1;
1798 1799 1800
    int ret = -1;

    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
1801 1802 1803
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain '%d' has to be running because libxenlight will"
                         " suspend it"), vm->def->id);
1804 1805 1806 1807
        goto cleanup;
    }

    if ((fd = virFileOpenAs(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR,
L
Laine Stump 已提交
1808
                            -1, -1, 0)) < 0) {
1809 1810 1811 1812 1813
        virReportSystemError(-fd,
                             _("Failed to create domain save file '%s'"), to);
        goto cleanup;
    }

1814
    if ((xml = virDomainDefFormat(vm->def, cfg->caps, 0)) == NULL)
1815 1816 1817 1818 1819 1820 1821 1822 1823
        goto cleanup;
    xml_len = strlen(xml) + 1;

    memset(&hdr, 0, sizeof(hdr));
    memcpy(hdr.magic, LIBXL_SAVE_MAGIC, sizeof(hdr.magic));
    hdr.version = LIBXL_SAVE_VERSION;
    hdr.xmlLen = xml_len;

    if (safewrite(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
1824 1825
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Failed to write save file header"));
1826 1827 1828 1829
        goto cleanup;
    }

    if (safewrite(fd, xml, xml_len) != xml_len) {
1830 1831
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Failed to write xml description"));
1832 1833 1834
        goto cleanup;
    }

1835 1836
    /* Unlock virDomainObj while saving domain */
    virObjectUnlock(vm);
J
Jim Fehlig 已提交
1837
    ret = libxl_domain_suspend(cfg->ctx, vm->def->id, fd, 0, NULL);
1838 1839 1840
    virObjectLock(vm);

    if (ret != 0) {
1841 1842 1843
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to save domain '%d' with libxenlight"),
                       vm->def->id);
1844
        ret = -1;
1845 1846 1847
        goto cleanup;
    }

1848 1849 1850
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
                         VIR_DOMAIN_SHUTOFF_SAVED);

1851
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
1852 1853
                                         VIR_DOMAIN_EVENT_STOPPED_SAVED);

1854
    if (libxlDomainDestroyInternal(driver, vm) < 0) {
1855 1856
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to destroy domain '%d'"), vm->def->id);
1857 1858 1859
        goto cleanup;
    }

1860
    libxlDomainCleanup(driver, vm);
1861
    vm->hasManagedSave = managed;
1862 1863
    ret = 0;

1864
 cleanup:
1865 1866 1867
    VIR_FREE(xml);
    if (VIR_CLOSE(fd) < 0)
        virReportSystemError(errno, "%s", _("cannot close file"));
1868
    virObjectEventStateQueue(driver->domainEventState, event);
J
Jim Fehlig 已提交
1869
    virObjectUnref(cfg);
1870 1871 1872 1873
    return ret;
}

static int
1874 1875
libxlDomainSaveFlags(virDomainPtr dom, const char *to, const char *dxml,
                     unsigned int flags)
1876
{
1877 1878
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
1879 1880
    int ret = -1;

1881 1882 1883 1884 1885
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

1886 1887
    virCheckFlags(0, -1);
    if (dxml) {
1888 1889
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("xml modification unsupported"));
1890 1891 1892
        return -1;
    }

J
Jim Fehlig 已提交
1893
    if (!(vm = libxlDomObjFromDomain(dom)))
1894 1895
        goto cleanup;

J
Jim Fehlig 已提交
1896 1897
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

1898 1899 1900
    if (virDomainSaveFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1901 1902 1903
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1904
    if (virDomainObjCheckActive(vm) < 0)
1905
        goto endjob;
1906

1907
    if (libxlDoDomainSave(driver, vm, to, false) < 0)
1908
        goto endjob;
1909

1910
    if (!vm->persistent)
1911
        virDomainObjListRemove(driver->domains, vm);
1912 1913

    ret = 0;
1914

1915
 endjob:
W
Wang Yufei 已提交
1916
    libxlDomainObjEndJob(driver, vm);
1917

1918
 cleanup:
W
Wang Yufei 已提交
1919
    virDomainObjEndAPI(&vm);
1920 1921
    return ret;
}
1922

1923
static int
1924 1925 1926 1927 1928 1929 1930 1931
libxlDomainSave(virDomainPtr dom, const char *to)
{
    return libxlDomainSaveFlags(dom, to, NULL, 0);
}

static int
libxlDomainRestoreFlags(virConnectPtr conn, const char *from,
                        const char *dxml, unsigned int flags)
1932 1933
{
    libxlDriverPrivatePtr driver = conn->privateData;
1934
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1935 1936 1937 1938 1939
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    libxlSavefileHeader hdr;
    int fd = -1;
    int ret = -1;
1940

1941 1942 1943 1944 1945
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

1946
    virCheckFlags(VIR_DOMAIN_SAVE_PAUSED, -1);
1947
    if (dxml) {
1948 1949
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("xml modification unsupported"));
1950 1951 1952
        return -1;
    }

1953
    fd = libxlDomainSaveImageOpen(driver, cfg, from, &def, &hdr);
1954
    if (fd < 0)
1955
        goto cleanup;
1956

1957
    if (virDomainRestoreFlagsEnsureACL(conn, def) < 0)
1958
        goto cleanup;
1959

1960
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1961
                                   driver->xmlopt,
1962 1963 1964
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1965
        goto cleanup;
1966 1967
    def = NULL;

1968
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) {
1969
        if (!vm->persistent)
1970 1971 1972 1973
            virDomainObjListRemove(driver->domains, vm);
        goto cleanup;
    }

1974 1975 1976
    ret = libxlDomainStartRestore(driver, vm,
                                  (flags & VIR_DOMAIN_SAVE_PAUSED) != 0,
                                  fd, hdr.version);
1977
    if (ret < 0 && !vm->persistent)
1978
        virDomainObjListRemove(driver->domains, vm);
1979

W
Wang Yufei 已提交
1980
    libxlDomainObjEndJob(driver, vm);
1981

1982
 cleanup:
1983 1984
    if (VIR_CLOSE(fd) < 0)
        virReportSystemError(errno, "%s", _("cannot close file"));
1985
    virDomainDefFree(def);
W
Wang Yufei 已提交
1986
    virDomainObjEndAPI(&vm);
1987
    virObjectUnref(cfg);
1988 1989 1990
    return ret;
}

1991 1992 1993 1994 1995 1996
static int
libxlDomainRestore(virConnectPtr conn, const char *from)
{
    return libxlDomainRestoreFlags(conn, from, NULL, 0);
}

1997
static int
1998
libxlDomainCoreDump(virDomainPtr dom, const char *to, unsigned int flags)
1999 2000
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
J
Jim Fehlig 已提交
2001
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2002
    virDomainObjPtr vm;
2003
    virObjectEventPtr event = NULL;
2004 2005 2006 2007 2008
    bool paused = false;
    int ret = -1;

    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH, -1);

J
Jim Fehlig 已提交
2009
    if (!(vm = libxlDomObjFromDomain(dom)))
2010 2011
        goto cleanup;

J
Jim Fehlig 已提交
2012 2013
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

2014 2015 2016
    if (virDomainCoreDumpEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2017 2018 2019
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

2020
    if (virDomainObjCheckActive(vm) < 0)
2021
        goto endjob;
2022 2023 2024

    if (!(flags & VIR_DUMP_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
J
Jim Fehlig 已提交
2025
        if (libxl_domain_pause(cfg->ctx, vm->def->id) != 0) {
2026 2027 2028
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Before dumping core, failed to suspend domain '%d'"
                             " with libxenlight"),
2029
                           vm->def->id);
2030
            goto endjob;
2031 2032 2033 2034 2035
        }
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_DUMP);
        paused = true;
    }

2036 2037
    /* Unlock virDomainObj while dumping core */
    virObjectUnlock(vm);
J
Jim Fehlig 已提交
2038
    ret = libxl_domain_core_dump(cfg->ctx, vm->def->id, to, NULL);
2039 2040
    virObjectLock(vm);
    if (ret != 0) {
2041 2042
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to dump core of domain '%d' with libxenlight"),
2043
                       vm->def->id);
2044 2045
        ret = -1;
        goto unpause;
2046 2047 2048
    }

    if (flags & VIR_DUMP_CRASH) {
2049
        if (libxlDomainDestroyInternal(driver, vm) < 0) {
2050
            virReportError(VIR_ERR_INTERNAL_ERROR,
2051
                           _("Failed to destroy domain '%d'"), vm->def->id);
2052
            goto unpause;
2053 2054
        }

2055 2056 2057
        libxlDomainCleanup(driver, vm);
        virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
                             VIR_DOMAIN_SHUTOFF_CRASHED);
2058
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
2059
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
2060
        if (!vm->persistent)
2061
            virDomainObjListRemove(driver->domains, vm);
2062 2063 2064 2065
    }

    ret = 0;

2066
 unpause:
2067
    if (virDomainObjIsActive(vm) && paused) {
J
Jim Fehlig 已提交
2068
        if (libxl_domain_unpause(cfg->ctx, vm->def->id) != 0) {
2069 2070
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("After dumping core, failed to resume domain '%d' with"
2071
                             " libxenlight"), vm->def->id);
2072 2073 2074 2075 2076
        } else {
            virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                                 VIR_DOMAIN_RUNNING_UNPAUSED);
        }
    }
2077

2078
 endjob:
W
Wang Yufei 已提交
2079
    libxlDomainObjEndJob(driver, vm);
2080

2081
 cleanup:
W
Wang Yufei 已提交
2082
    virDomainObjEndAPI(&vm);
2083
    virObjectEventStateQueue(driver->domainEventState, event);
J
Jim Fehlig 已提交
2084
    virObjectUnref(cfg);
2085 2086 2087
    return ret;
}

2088 2089 2090 2091 2092 2093 2094 2095 2096 2097
static int
libxlDomainManagedSave(virDomainPtr dom, unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    char *name = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
2098
    if (!(vm = libxlDomObjFromDomain(dom)))
2099 2100
        goto cleanup;

J
Jim Fehlig 已提交
2101 2102
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

2103 2104 2105
    if (virDomainManagedSaveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2106 2107 2108
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

2109
    if (virDomainObjCheckActive(vm) < 0)
2110
        goto endjob;
2111
    if (!vm->persistent) {
2112 2113
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot do managed save for transient domain"));
2114
        goto endjob;
2115
    }
2116 2117 2118

    name = libxlDomainManagedSavePath(driver, vm);
    if (name == NULL)
2119
        goto endjob;
2120 2121 2122

    VIR_INFO("Saving state to %s", name);

2123
    if (libxlDoDomainSave(driver, vm, name, true) < 0)
2124
        goto endjob;
2125

2126
    if (!vm->persistent)
2127
        virDomainObjListRemove(driver->domains, vm);
2128 2129

    ret = 0;
2130

2131
 endjob:
W
Wang Yufei 已提交
2132
    libxlDomainObjEndJob(driver, vm);
2133

2134
 cleanup:
W
Wang Yufei 已提交
2135
    virDomainObjEndAPI(&vm);
2136 2137 2138 2139
    VIR_FREE(name);
    return ret;
}

2140 2141
static int
libxlDomainManagedSaveLoad(virDomainObjPtr vm,
2142 2143 2144 2145
                           void *opaque)
{
    libxlDriverPrivatePtr driver = opaque;
    char *name;
2146
    int ret = -1;
2147

2148
    virObjectLock(vm);
2149 2150 2151 2152 2153 2154

    if (!(name = libxlDomainManagedSavePath(driver, vm)))
        goto cleanup;

    vm->hasManagedSave = virFileExists(name);

2155
    ret = 0;
2156
 cleanup:
2157
    virObjectUnlock(vm);
2158
    VIR_FREE(name);
2159
    return ret;
2160 2161
}

2162 2163 2164 2165 2166 2167 2168 2169
static int
libxlDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
2170
    if (!(vm = libxlDomObjFromDomain(dom)))
2171 2172
        goto cleanup;

2173 2174 2175
    if (virDomainHasManagedSaveImageEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2176
    ret = vm->hasManagedSave;
2177

2178
 cleanup:
2179
    virDomainObjEndAPI(&vm);
2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192
    return ret;
}

static int
libxlDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    char *name = NULL;

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
2193
    if (!(vm = libxlDomObjFromDomain(dom)))
2194 2195
        goto cleanup;

2196 2197 2198
    if (virDomainManagedSaveRemoveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2199 2200 2201 2202 2203
    name = libxlDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    ret = unlink(name);
2204
    vm->hasManagedSave = false;
2205

2206
 cleanup:
2207
    VIR_FREE(name);
2208
    virDomainObjEndAPI(&vm);
2209 2210 2211
    return ret;
}

2212 2213 2214 2215 2216
static int
libxlDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                         unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
2217
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2218 2219
    virDomainDefPtr def;
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
2220
    libxl_bitmap map;
2221 2222
    uint8_t *bitmask = NULL;
    unsigned int maplen;
2223 2224
    size_t i;
    unsigned int pos;
2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236
    int max;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

    /* At least one of LIVE or CONFIG must be set.  MAXIMUM cannot be
     * mixed with LIVE.  */
    if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0 ||
        (flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) ==
         (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) {
2237 2238
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid flag combination: (0x%x)"), flags);
2239 2240 2241 2242
        return -1;
    }

    if (!nvcpus) {
2243
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("nvcpus is zero"));
2244 2245 2246
        return -1;
    }

J
Jim Fehlig 已提交
2247
    if (!(vm = libxlDomObjFromDomain(dom)))
2248 2249
        goto cleanup;

2250 2251 2252
    if (virDomainSetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

2253 2254 2255
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

2256
    if (!virDomainObjIsActive(vm) && (flags & VIR_DOMAIN_VCPU_LIVE)) {
2257 2258
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot set vcpus on an inactive domain"));
2259
        goto endjob;
2260 2261 2262
    }

    if (!vm->persistent && (flags & VIR_DOMAIN_VCPU_CONFIG)) {
2263 2264
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot change persistent config of a transient domain"));
2265
        goto endjob;
2266 2267
    }

2268
    if ((max = libxlConnectGetMaxVcpus(dom->conn, NULL)) < 0) {
2269 2270
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not determine max vcpus for the domain"));
2271
        goto endjob;
2272 2273
    }

2274 2275
    if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM) && virDomainDefGetVcpusMax(vm->def) < max)
        max = virDomainDefGetVcpusMax(vm->def);
2276 2277

    if (nvcpus > max) {
2278 2279 2280
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the domain: %d > %d"), nvcpus, max);
2281
        goto endjob;
2282 2283
    }

2284
    if (!(def = virDomainObjGetPersistentDef(cfg->caps, driver->xmlopt, vm)))
2285
        goto endjob;
2286

E
Eric Blake 已提交
2287
    maplen = VIR_CPU_MAPLEN(nvcpus);
2288
    if (VIR_ALLOC_N(bitmask, maplen) < 0)
2289
        goto endjob;
2290 2291

    for (i = 0; i < nvcpus; ++i) {
E
Eric Blake 已提交
2292
        pos = i / 8;
2293 2294 2295 2296 2297 2298 2299 2300
        bitmask[pos] |= 1 << (i % 8);
    }

    map.size = maplen;
    map.map = bitmask;

    switch (flags) {
    case VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_CONFIG:
2301
        if (virDomainDefSetVcpusMax(def, nvcpus, driver->xmlopt) < 0)
2302
            goto cleanup;
2303 2304 2305
        break;

    case VIR_DOMAIN_VCPU_CONFIG:
2306 2307
        if (virDomainDefSetVcpus(def, nvcpus) < 0)
            goto cleanup;
2308 2309 2310
        break;

    case VIR_DOMAIN_VCPU_LIVE:
J
Jim Fehlig 已提交
2311
        if (libxl_set_vcpuonline(cfg->ctx, vm->def->id, &map) != 0) {
2312 2313
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to set vcpus for domain '%d'"
2314
                             " with libxenlight"), vm->def->id);
2315
            goto endjob;
2316
        }
2317 2318
        if (virDomainDefSetVcpus(vm->def, nvcpus) < 0)
            goto endjob;
2319 2320 2321
        break;

    case VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG:
J
Jim Fehlig 已提交
2322
        if (libxl_set_vcpuonline(cfg->ctx, vm->def->id, &map) != 0) {
2323 2324
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to set vcpus for domain '%d'"
2325
                             " with libxenlight"), vm->def->id);
2326
            goto endjob;
2327
        }
2328 2329 2330
        if (virDomainDefSetVcpus(vm->def, nvcpus) < 0 ||
            virDomainDefSetVcpus(def, nvcpus) < 0)
            goto endjob;
2331 2332 2333 2334 2335
        break;
    }

    ret = 0;

2336
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
2337
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0) {
2338 2339 2340 2341 2342
            VIR_WARN("Unable to save status on vm %s after changing vcpus",
                     vm->def->name);
        }
    }
    if (flags & VIR_DOMAIN_VCPU_CONFIG) {
2343
        if (virDomainSaveConfig(cfg->configDir, cfg->caps, def) < 0) {
2344 2345 2346 2347
            VIR_WARN("Unable to save configuration of vm %s after changing vcpus",
                     vm->def->name);
        }
    }
2348

2349
 endjob:
W
Wang Yufei 已提交
2350
    libxlDomainObjEndJob(driver, vm);
2351

2352
 cleanup:
2353
    VIR_FREE(bitmask);
W
Wang Yufei 已提交
2354 2355
    virDomainObjEndAPI(&vm);
    virObjectUnref(cfg);
2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370
    return ret;
}

static int
libxlDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
    return libxlDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
}

static int
libxlDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
    virDomainObjPtr vm;
    virDomainDefPtr def;
    int ret = -1;
2371
    bool active;
2372 2373 2374 2375 2376

    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

J
Jim Fehlig 已提交
2377
    if (!(vm = libxlDomObjFromDomain(dom)))
2378 2379
        goto cleanup;

2380
    if (virDomainGetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
2381 2382
        goto cleanup;

2383 2384 2385 2386 2387 2388 2389 2390 2391
    active = virDomainObjIsActive(vm);

    if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0) {
        if (active)
            flags |= VIR_DOMAIN_VCPU_LIVE;
        else
            flags |= VIR_DOMAIN_VCPU_CONFIG;
    }
    if ((flags & VIR_DOMAIN_VCPU_LIVE) && (flags & VIR_DOMAIN_VCPU_CONFIG)) {
2392 2393
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid flag combination: (0x%x)"), flags);
2394 2395 2396
        return -1;
    }

2397
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
2398
        if (!active) {
2399 2400
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("Domain is not running"));
2401 2402 2403 2404
            goto cleanup;
        }
        def = vm->def;
    } else {
2405
        if (!vm->persistent) {
2406 2407
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is transient"));
2408 2409
            goto cleanup;
        }
2410 2411 2412
        def = vm->newDef ? vm->newDef : vm->def;
    }

2413 2414 2415
    if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
        ret = virDomainDefGetVcpusMax(def);
    else
2416
        ret = virDomainDefGetVcpus(def);
2417

2418
 cleanup:
2419
    virDomainObjEndAPI(&vm);
2420 2421 2422
    return ret;
}

2423 2424 2425 2426 2427 2428 2429
static int
libxlDomainGetMaxVcpus(virDomainPtr dom)
{
    return libxlDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
                                          VIR_DOMAIN_VCPU_MAXIMUM));
}

2430
static int
2431 2432 2433
libxlDomainPinVcpuFlags(virDomainPtr dom, unsigned int vcpu,
                        unsigned char *cpumap, int maplen,
                        unsigned int flags)
2434 2435
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
2436
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2437
    virDomainDefPtr targetDef = NULL;
2438
    virBitmapPtr pcpumap = NULL;
2439
    virDomainVcpuDefPtr vcpuinfo;
2440 2441
    virDomainObjPtr vm;
    int ret = -1;
2442 2443 2444

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
2445

J
Jim Fehlig 已提交
2446
    if (!(vm = libxlDomObjFromDomain(dom)))
2447 2448
        goto cleanup;

2449
    if (virDomainPinVcpuFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
2450 2451
        goto cleanup;

2452 2453 2454
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

2455 2456
    if (virDomainLiveConfigHelperMethod(cfg->caps, driver->xmlopt, vm,
                                        &flags, &targetDef) < 0)
2457
        goto endjob;
2458

2459
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
2460 2461 2462 2463 2464
        targetDef = vm->def;

    /* Make sure coverity knows targetDef is valid at this point. */
    sa_assert(targetDef);

2465 2466
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
2467
        goto endjob;
2468

2469 2470 2471 2472 2473 2474 2475
    if (!(vcpuinfo = virDomainDefGetVcpu(targetDef, vcpu)) ||
        !vcpuinfo->online) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("vcpu '%u' is not active"), vcpu);
        goto endjob;
    }

2476 2477
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        libxl_bitmap map = { .size = maplen, .map = cpumap };
J
Jim Fehlig 已提交
2478
        if (libxl_set_vcpuaffinity(cfg->ctx, vm->def->id, vcpu, &map, NULL) != 0) {
2479 2480 2481
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to pin vcpu '%d' with libxenlight"),
                           vcpu);
2482
            goto endjob;
2483
        }
2484
    }
2485

2486 2487 2488
    virBitmapFree(vcpuinfo->cpumask);
    vcpuinfo->cpumask = pcpumap;
    pcpumap = NULL;
2489

2490 2491
    ret = 0;

2492
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2493
        ret = virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps);
2494
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2495
        ret = virDomainSaveConfig(cfg->configDir, cfg->caps, targetDef);
2496 2497
    }

2498
 endjob:
W
Wang Yufei 已提交
2499
    libxlDomainObjEndJob(driver, vm);
2500

2501
 cleanup:
W
Wang Yufei 已提交
2502
    virDomainObjEndAPI(&vm);
2503
    virBitmapFree(pcpumap);
2504
    virObjectUnref(cfg);
2505 2506 2507
    return ret;
}

2508 2509 2510 2511 2512 2513 2514 2515
static int
libxlDomainPinVcpu(virDomainPtr dom, unsigned int vcpu, unsigned char *cpumap,
                   int maplen)
{
    return libxlDomainPinVcpuFlags(dom, vcpu, cpumap, maplen,
                                   VIR_DOMAIN_AFFECT_LIVE);
}

2516 2517 2518 2519 2520 2521 2522 2523 2524
static int
libxlDomainGetVcpuPinInfo(virDomainPtr dom, int ncpumaps,
                          unsigned char *cpumaps, int maplen,
                          unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    virDomainObjPtr vm = NULL;
    virDomainDefPtr targetDef = NULL;
2525
    int ret = -1;
2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainGetVcpuPinInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (virDomainLiveConfigHelperMethod(cfg->caps, driver->xmlopt, vm,
                                        &flags, &targetDef) < 0)
        goto cleanup;

2540
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
2541 2542 2543 2544 2545
        targetDef = vm->def;

    /* Make sure coverity knows targetDef is valid at this point. */
    sa_assert(targetDef);

2546 2547
    ret = virDomainDefGetVcpuPinInfoHelper(targetDef, maplen, ncpumaps, cpumaps,
                                           libxl_get_max_cpus(cfg->ctx), NULL);
2548

2549
 cleanup:
2550
    virDomainObjEndAPI(&vm);
2551 2552 2553
    virObjectUnref(cfg);
    return ret;
}
2554 2555 2556 2557 2558

static int
libxlDomainGetVcpus(virDomainPtr dom, virVcpuInfoPtr info, int maxinfo,
                    unsigned char *cpumaps, int maplen)
{
J
Jim Fehlig 已提交
2559 2560
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2561 2562 2563 2564
    virDomainObjPtr vm;
    int ret = -1;
    libxl_vcpuinfo *vcpuinfo;
    int maxcpu, hostcpus;
2565
    size_t i;
2566 2567
    unsigned char *cpumap;

J
Jim Fehlig 已提交
2568
    if (!(vm = libxlDomObjFromDomain(dom)))
2569 2570
        goto cleanup;

2571 2572 2573
    if (virDomainGetVcpusEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2574
    if (virDomainObjCheckActive(vm) < 0)
2575 2576
        goto cleanup;

J
Jim Fehlig 已提交
2577
    if ((vcpuinfo = libxl_list_vcpu(cfg->ctx, vm->def->id, &maxcpu,
2578
                                    &hostcpus)) == NULL) {
2579 2580
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to list vcpus for domain '%d' with libxenlight"),
2581
                       vm->def->id);
2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603
        goto cleanup;
    }

    if (cpumaps && maplen > 0)
        memset(cpumaps, 0, maplen * maxinfo);
    for (i = 0; i < maxcpu && i < maxinfo; ++i) {
        info[i].number = vcpuinfo[i].vcpuid;
        info[i].cpu = vcpuinfo[i].cpu;
        info[i].cpuTime = vcpuinfo[i].vcpu_time;
        if (vcpuinfo[i].running)
            info[i].state = VIR_VCPU_RUNNING;
        else if (vcpuinfo[i].blocked)
            info[i].state = VIR_VCPU_BLOCKED;
        else
            info[i].state = VIR_VCPU_OFFLINE;

        if (cpumaps && maplen > 0) {
            cpumap = VIR_GET_CPUMAP(cpumaps, maplen, i);
            memcpy(cpumap, vcpuinfo[i].cpumap.map,
                   MIN(maplen, vcpuinfo[i].cpumap.size));
        }

J
Jim Fehlig 已提交
2604
        libxl_vcpuinfo_dispose(&vcpuinfo[i]);
2605 2606 2607 2608 2609
    }
    VIR_FREE(vcpuinfo);

    ret = maxinfo;

2610
 cleanup:
2611
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
2612
    virObjectUnref(cfg);
2613 2614 2615
    return ret;
}

J
Jim Fehlig 已提交
2616
static char *
2617
libxlDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
2618
{
2619 2620
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
2621
    virDomainObjPtr vm;
2622
    virDomainDefPtr def;
J
Jim Fehlig 已提交
2623 2624
    char *ret = NULL;

2625 2626
    /* Flags checked by virDomainDefFormat */

J
Jim Fehlig 已提交
2627
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
2628 2629
        goto cleanup;

2630 2631 2632
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

2633 2634 2635 2636 2637
    if ((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef)
        def = vm->newDef;
    else
        def = vm->def;

2638
    ret = virDomainDefFormat(def, cfg->caps,
2639
                             virDomainDefFormatConvertXMLFlags(flags));
J
Jim Fehlig 已提交
2640

2641
 cleanup:
2642
    virDomainObjEndAPI(&vm);
2643
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
2644 2645 2646
    return ret;
}

2647
static char *
2648 2649 2650
libxlConnectDomainXMLFromNative(virConnectPtr conn,
                                const char *nativeFormat,
                                const char *nativeConfig,
2651
                                unsigned int flags)
2652 2653
{
    libxlDriverPrivatePtr driver = conn->privateData;
2654
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2655 2656 2657 2658
    virDomainDefPtr def = NULL;
    virConfPtr conf = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2659 2660
    virCheckFlags(0, NULL);

2661 2662 2663
    if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0)
        goto cleanup;

2664
    if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XL)) {
J
Ján Tomko 已提交
2665
        if (!(conf = virConfReadString(nativeConfig, 0)))
2666 2667 2668
            goto cleanup;
        if (!(def = xenParseXL(conf,
                               cfg->caps,
2669
                               driver->xmlopt)))
2670
            goto cleanup;
2671
    } else if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XM)) {
J
Ján Tomko 已提交
2672
        if (!(conf = virConfReadString(nativeConfig, 0)))
2673 2674 2675
            goto cleanup;

        if (!(def = xenParseXM(conf,
2676 2677
                               cfg->caps,
                               driver->xmlopt)))
2678
            goto cleanup;
2679
    } else if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_SEXPR)) {
2680 2681 2682
        /* only support latest xend config format */
        if (!(def = xenParseSxprString(nativeConfig,
                                       NULL,
2683 2684 2685
                                       -1,
                                       cfg->caps,
                                       driver->xmlopt))) {
2686 2687 2688 2689 2690
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("parsing sxpr config failed"));
            goto cleanup;
        }
    } else {
2691 2692
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), nativeFormat);
2693 2694 2695
        goto cleanup;
    }

2696
    xml = virDomainDefFormat(def, cfg->caps, VIR_DOMAIN_DEF_FORMAT_INACTIVE);
2697

2698
 cleanup:
2699 2700 2701
    virDomainDefFree(def);
    if (conf)
        virConfFree(conf);
2702
    virObjectUnref(cfg);
2703 2704 2705 2706 2707
    return xml;
}

#define MAX_CONFIG_SIZE (1024 * 65)
static char *
2708 2709 2710
libxlConnectDomainXMLToNative(virConnectPtr conn, const char * nativeFormat,
                              const char * domainXml,
                              unsigned int flags)
2711 2712
{
    libxlDriverPrivatePtr driver = conn->privateData;
2713
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2714 2715 2716 2717 2718
    virDomainDefPtr def = NULL;
    virConfPtr conf = NULL;
    int len = MAX_CONFIG_SIZE;
    char *ret = NULL;

E
Eric Blake 已提交
2719 2720
    virCheckFlags(0, NULL);

2721 2722 2723
    if (virConnectDomainXMLToNativeEnsureACL(conn) < 0)
        goto cleanup;

2724
    if (!(def = virDomainDefParseString(domainXml,
2725
                                        cfg->caps, driver->xmlopt, NULL,
2726
                                        VIR_DOMAIN_DEF_PARSE_INACTIVE)))
2727 2728
        goto cleanup;

2729
    if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XL)) {
2730
        if (!(conf = xenFormatXL(def, conn)))
2731
            goto cleanup;
2732
    } else if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XM)) {
2733
        if (!(conf = xenFormatXM(conn, def)))
2734 2735 2736 2737 2738
            goto cleanup;
    } else {

        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), nativeFormat);
2739
        goto cleanup;
2740
    }
2741

2742
    if (VIR_ALLOC_N(ret, len) < 0)
2743 2744 2745 2746 2747 2748 2749
        goto cleanup;

    if (virConfWriteMem(ret, &len, conf) < 0) {
        VIR_FREE(ret);
        goto cleanup;
    }

2750
 cleanup:
2751 2752 2753
    virDomainDefFree(def);
    if (conf)
        virConfFree(conf);
2754
    virObjectUnref(cfg);
2755 2756 2757
    return ret;
}

J
Jim Fehlig 已提交
2758
static int
2759 2760
libxlConnectListDefinedDomains(virConnectPtr conn,
                               char **const names, int nnames)
J
Jim Fehlig 已提交
2761 2762 2763 2764
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

2765 2766 2767
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

2768 2769
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         virConnectListDefinedDomainsCheckACL, conn);
J
Jim Fehlig 已提交
2770 2771 2772 2773
    return n;
}

static int
2774
libxlConnectNumOfDefinedDomains(virConnectPtr conn)
J
Jim Fehlig 已提交
2775 2776 2777 2778
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

2779 2780 2781
    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        return -1;

2782
    n = virDomainObjListNumOfDomains(driver->domains, false,
2783 2784
                                     virConnectNumOfDefinedDomainsCheckACL,
                                     conn);
J
Jim Fehlig 已提交
2785 2786 2787 2788 2789
    return n;
}

static int
libxlDomainCreateWithFlags(virDomainPtr dom,
E
Eric Blake 已提交
2790
                           unsigned int flags)
J
Jim Fehlig 已提交
2791 2792 2793 2794 2795 2796 2797
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_START_PAUSED, -1);

J
Jim Fehlig 已提交
2798
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
2799 2800
        goto cleanup;

2801 2802 2803
    if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2804 2805 2806
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
2807
    if (virDomainObjIsActive(vm)) {
2808 2809
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is already running"));
2810
        goto endjob;
J
Jim Fehlig 已提交
2811 2812
    }

2813 2814
    ret = libxlDomainStartNew(driver, vm,
                              (flags & VIR_DOMAIN_START_PAUSED) != 0);
2815
    if (ret < 0)
2816
        goto endjob;
2817
    dom->id = vm->def->id;
J
Jim Fehlig 已提交
2818

2819
 endjob:
W
Wang Yufei 已提交
2820
    libxlDomainObjEndJob(driver, vm);
2821

2822
 cleanup:
W
Wang Yufei 已提交
2823
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
2824 2825 2826 2827 2828 2829 2830 2831 2832 2833
    return ret;
}

static int
libxlDomainCreate(virDomainPtr dom)
{
    return libxlDomainCreateWithFlags(dom, 0);
}

static virDomainPtr
2834
libxlDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
J
Jim Fehlig 已提交
2835 2836
{
    libxlDriverPrivatePtr driver = conn->privateData;
2837
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
2838 2839 2840
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    virDomainPtr dom = NULL;
2841
    virObjectEventPtr event = NULL;
2842
    virDomainDefPtr oldDef = NULL;
2843
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
J
Jim Fehlig 已提交
2844

2845 2846 2847
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
2848
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
2849

2850
    if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt,
2851
                                        NULL, parse_flags)))
2852
        goto cleanup;
J
Jim Fehlig 已提交
2853

2854 2855 2856
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        goto cleanup;

2857
    if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
2858
        goto cleanup;
2859

2860
    if (!(vm = virDomainObjListAdd(driver->domains, def,
2861
                                   driver->xmlopt,
2862 2863
                                   0,
                                   &oldDef)))
2864
        goto cleanup;
J
Jim Fehlig 已提交
2865
    def = NULL;
2866

J
Jim Fehlig 已提交
2867 2868
    vm->persistent = 1;

2869
    if (virDomainSaveConfig(cfg->configDir,
2870
                            cfg->caps,
J
Jim Fehlig 已提交
2871
                            vm->newDef ? vm->newDef : vm->def) < 0) {
2872
        virDomainObjListRemove(driver->domains, vm);
J
Jim Fehlig 已提交
2873 2874 2875
        goto cleanup;
    }

2876
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
J
Jim Fehlig 已提交
2877

2878
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_DEFINED,
2879
                                     !oldDef ?
2880 2881 2882
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

2883
 cleanup:
J
Jim Fehlig 已提交
2884
    virDomainDefFree(def);
2885
    virDomainDefFree(oldDef);
2886
    virDomainObjEndAPI(&vm);
2887
    virObjectEventStateQueue(driver->domainEventState, event);
2888
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
2889 2890 2891
    return dom;
}

2892 2893 2894 2895 2896 2897
static virDomainPtr
libxlDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return libxlDomainDefineXMLFlags(conn, xml, 0);
}

J
Jim Fehlig 已提交
2898
static int
2899 2900
libxlDomainUndefineFlags(virDomainPtr dom,
                         unsigned int flags)
J
Jim Fehlig 已提交
2901 2902
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
2903
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
2904
    virDomainObjPtr vm;
2905
    virObjectEventPtr event = NULL;
2906
    char *name = NULL;
J
Jim Fehlig 已提交
2907 2908
    int ret = -1;

2909 2910
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE, -1);

J
Jim Fehlig 已提交
2911
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
2912 2913
        goto cleanup;

2914 2915 2916
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
2917
    if (!vm->persistent) {
2918 2919
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
J
Jim Fehlig 已提交
2920 2921 2922
        goto cleanup;
    }

2923 2924 2925 2926 2927 2928 2929
    name = libxlDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    if (virFileExists(name)) {
        if (flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE) {
            if (unlink(name) < 0) {
2930 2931
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to remove domain managed save image"));
2932 2933 2934
                goto cleanup;
            }
        } else {
2935 2936 2937
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Refusing to undefine while domain managed "
                             "save image exists"));
2938 2939 2940 2941
            goto cleanup;
        }
    }

2942
    if (virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm) < 0)
J
Jim Fehlig 已提交
2943 2944
        goto cleanup;

2945
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_UNDEFINED,
2946 2947
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

2948
    if (virDomainObjIsActive(vm))
2949
        vm->persistent = 0;
2950
    else
2951
        virDomainObjListRemove(driver->domains, vm);
2952

J
Jim Fehlig 已提交
2953 2954
    ret = 0;

2955
 cleanup:
2956
    VIR_FREE(name);
2957
    virDomainObjEndAPI(&vm);
2958
    virObjectEventStateQueue(driver->domainEventState, event);
2959
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
2960 2961 2962
    return ret;
}

2963 2964 2965 2966 2967 2968
static int
libxlDomainUndefine(virDomainPtr dom)
{
    return libxlDomainUndefineFlags(dom, 0);
}

2969
static int
J
Jim Fehlig 已提交
2970
libxlDomainChangeEjectableMedia(virDomainObjPtr vm, virDomainDiskDefPtr disk)
2971
{
J
Jim Fehlig 已提交
2972
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(libxl_driver);
2973 2974
    virDomainDiskDefPtr origdisk = NULL;
    libxl_device_disk x_disk;
2975
    size_t i;
2976 2977
    int ret = -1;

2978
    for (i = 0; i < vm->def->ndisks; i++) {
2979 2980 2981 2982 2983 2984 2985 2986
        if (vm->def->disks[i]->bus == disk->bus &&
            STREQ(vm->def->disks[i]->dst, disk->dst)) {
            origdisk = vm->def->disks[i];
            break;
        }
    }

    if (!origdisk) {
2987 2988 2989
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No device with bus '%s' and target '%s'"),
                       virDomainDiskBusTypeToString(disk->bus), disk->dst);
2990 2991 2992 2993
        goto cleanup;
    }

    if (origdisk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
2994 2995 2996
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Removable media not supported for %s device"),
                       virDomainDiskDeviceTypeToString(disk->device));
2997 2998 2999
        return -1;
    }

J
Jim Fehlig 已提交
3000
    if (libxlMakeDisk(disk, &x_disk) < 0)
3001 3002
        goto cleanup;

J
Jim Fehlig 已提交
3003
    if ((ret = libxl_cdrom_insert(cfg->ctx, vm->def->id, &x_disk, NULL)) < 0) {
3004 3005 3006
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to change media for disk '%s'"),
                       disk->dst);
3007 3008 3009
        goto cleanup;
    }

3010 3011 3012
    if (virDomainDiskSetSource(origdisk, virDomainDiskGetSource(disk)) < 0)
        goto cleanup;
    virDomainDiskSetType(origdisk, virDomainDiskGetType(disk));
3013 3014 3015 3016 3017

    virDomainDiskDefFree(disk);

    ret = 0;

3018
 cleanup:
J
Jim Fehlig 已提交
3019
    virObjectUnref(cfg);
3020 3021 3022 3023
    return ret;
}

static int
J
Jim Fehlig 已提交
3024
libxlDomainAttachDeviceDiskLive(virDomainObjPtr vm, virDomainDeviceDefPtr dev)
3025
{
J
Jim Fehlig 已提交
3026
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(libxl_driver);
3027 3028 3029 3030 3031 3032
    virDomainDiskDefPtr l_disk = dev->data.disk;
    libxl_device_disk x_disk;
    int ret = -1;

    switch (l_disk->device)  {
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
J
Jim Fehlig 已提交
3033
            ret = libxlDomainChangeEjectableMedia(vm, l_disk);
3034 3035 3036
            break;
        case VIR_DOMAIN_DISK_DEVICE_DISK:
            if (l_disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
3037
                if (virDomainDiskIndexByName(vm->def, l_disk->dst, true) >= 0) {
3038 3039
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("target %s already exists"), l_disk->dst);
3040 3041 3042
                    goto cleanup;
                }

3043
                if (!virDomainDiskGetSource(l_disk)) {
3044 3045
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("disk source path is missing"));
3046 3047 3048
                    goto cleanup;
                }

3049
                if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
3050 3051
                    goto cleanup;

J
Jim Fehlig 已提交
3052
                if (libxlMakeDisk(l_disk, &x_disk) < 0)
3053 3054
                    goto cleanup;

3055 3056 3057 3058 3059
                if (virDomainLockDiskAttach(libxl_driver->lockManager,
                                            "xen:///system",
                                            vm, l_disk) < 0)
                    goto cleanup;

J
Jim Fehlig 已提交
3060
                if ((ret = libxl_device_disk_add(cfg->ctx, vm->def->id,
J
Jim Fehlig 已提交
3061
                                                &x_disk, NULL)) < 0) {
3062 3063 3064
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("libxenlight failed to attach disk '%s'"),
                                   l_disk->dst);
3065 3066 3067 3068 3069
                    if (virDomainLockDiskDetach(libxl_driver->lockManager,
                                                vm, l_disk) < 0) {
                        VIR_WARN("Unable to release lock on %s",
                                 virDomainDiskGetSource(l_disk));
                    }
3070 3071 3072
                    goto cleanup;
                }

3073
                libxlUpdateDiskDef(l_disk, &x_disk);
3074 3075 3076
                virDomainDiskInsertPreAlloced(vm->def, l_disk);

            } else {
3077 3078 3079
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("disk bus '%s' cannot be hotplugged."),
                               virDomainDiskBusTypeToString(l_disk->bus));
3080 3081 3082
            }
            break;
        default:
3083 3084 3085
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("disk device type '%s' cannot be hotplugged"),
                           virDomainDiskDeviceTypeToString(l_disk->device));
3086 3087 3088
            break;
    }

3089
 cleanup:
J
Jim Fehlig 已提交
3090
    virObjectUnref(cfg);
3091 3092 3093
    return ret;
}

3094 3095 3096 3097 3098
static int
libxlDomainAttachHostPCIDevice(libxlDriverPrivatePtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
J
Jim Fehlig 已提交
3099
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3100
    libxl_device_pci pcidev;
3101 3102
    virDomainHostdevDefPtr found;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
3103
    virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
J
Jim Fehlig 已提交
3104
    int ret = -1;
3105

3106 3107
    libxl_device_pci_init(&pcidev);

3108 3109 3110
    if (virDomainHostdevFind(vm->def, hostdev, &found) >= 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("target pci device %.4x:%.2x:%.2x.%.1x already exists"),
3111 3112
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
J
Jim Fehlig 已提交
3113
        goto cleanup;
3114 3115 3116
    }

    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
J
Jim Fehlig 已提交
3117
        goto cleanup;
3118 3119 3120 3121

    if (virHostdevPreparePCIDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                    vm->def->name, vm->def->uuid,
                                    &hostdev, 1, 0) < 0)
J
Jim Fehlig 已提交
3122
        goto cleanup;
3123

3124
    if (libxlMakePCI(hostdev, &pcidev) < 0)
C
Chunyan Liu 已提交
3125
        goto error;
3126

J
Jim Fehlig 已提交
3127
    if (libxl_device_pci_add(cfg->ctx, vm->def->id, &pcidev, 0) < 0) {
3128 3129
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to attach pci device %.4x:%.2x:%.2x.%.1x"),
3130 3131
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
C
Chunyan Liu 已提交
3132
        goto error;
3133 3134 3135
    }

    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
J
Jim Fehlig 已提交
3136 3137
    ret = 0;
    goto cleanup;
3138

3139
 error:
3140 3141
    virHostdevReAttachPCIDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                 vm->def->name, &hostdev, 1, NULL);
J
Jim Fehlig 已提交
3142 3143 3144

 cleanup:
    virObjectUnref(cfg);
3145
    libxl_device_pci_dispose(&pcidev);
J
Jim Fehlig 已提交
3146
    return ret;
3147 3148
}

3149
#ifdef LIBXL_HAVE_PVUSB
3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203
static int
libxlDomainAttachControllerDevice(libxlDriverPrivatePtr driver,
                                  virDomainObjPtr vm,
                                  virDomainControllerDefPtr controller)
{
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    const char *type = virDomainControllerTypeToString(controller->type);
    libxl_device_usbctrl usbctrl;
    int ret = -1;

    libxl_device_usbctrl_init(&usbctrl);

    if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_USB) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot plugged."),
                       type);
        goto cleanup;
    }

    if (controller->idx == -1)
        controller->idx = virDomainControllerFindUnusedIndex(vm->def,
                                                             controller->type);

    if (controller->opts.usbopts.ports == -1)
        controller->opts.usbopts.ports = 8;

    if (virDomainControllerFind(vm->def, controller->type, controller->idx) >= 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("target %s:%d already exists"),
                       type, controller->idx);
        goto cleanup;
    }

    if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers + 1) < 0)
        goto cleanup;

    if (libxlMakeUSBController(controller, &usbctrl) < 0)
        goto cleanup;

    if (libxl_device_usbctrl_add(cfg->ctx, vm->def->id, &usbctrl, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight failed to attach USB controller"));
        goto cleanup;
    }

    virDomainControllerInsertPreAlloced(vm->def, controller);
    ret = 0;

 cleanup:
    virObjectUnref(cfg);
    libxl_device_usbctrl_dispose(&usbctrl);
    return ret;
}

3204 3205 3206 3207 3208 3209 3210 3211 3212
static int
libxlDomainAttachHostUSBDevice(libxlDriverPrivatePtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    libxl_device_usbdev usbdev;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
    int ret = -1;
3213 3214
    size_t i;
    int ports = 0, usbdevs = 0;
3215 3216 3217 3218 3219 3220 3221

    libxl_device_usbdev_init(&usbdev);

    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
        hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
        goto cleanup;

3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251
    /* search for available controller:port */
    for (i = 0; i < vm->def->ncontrollers; i++)
        ports += vm->def->controllers[i]->opts.usbopts.ports;

    for (i = 0; i < vm->def->nhostdevs; i++) {
        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
            usbdevs++;
    }

    if (ports <= usbdevs) {
        /* no free ports, we will create a new usb controller */
        virDomainControllerDefPtr controller;

        if (!(controller = virDomainControllerDefNew(VIR_DOMAIN_CONTROLLER_TYPE_USB)))
            goto cleanup;

        controller->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2;
        controller->idx = -1;
        controller->opts.usbopts.ports = 8;

        if (libxlDomainAttachControllerDevice(driver, vm, controller) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No available USB controller and port, and "
                             "failed to attach a new one"));
            virDomainControllerDefFree(controller);
            goto cleanup;
        }
    }

3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
        goto cleanup;

    if (virHostdevPrepareUSBDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                    vm->def->name, &hostdev, 1, 0) < 0)
        goto cleanup;

    if (libxlMakeUSB(hostdev, &usbdev) < 0)
        goto reattach;

    if (libxl_device_usbdev_add(cfg->ctx, vm->def->id, &usbdev, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to attach usb device Busnum:%3x, Devnum:%3x"),
                       hostdev->source.subsys.u.usb.bus,
                       hostdev->source.subsys.u.usb.device);
        goto reattach;
    }

    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
    ret = 0;
    goto cleanup;

 reattach:
    virHostdevReAttachUSBDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                 vm->def->name, &hostdev, 1);

 cleanup:
    virObjectUnref(cfg);
    libxl_device_usbdev_dispose(&usbdev);
    return ret;
}
#endif

3285 3286 3287
static int
libxlDomainAttachHostDevice(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3288
                            virDomainHostdevDefPtr hostdev)
3289 3290 3291 3292 3293 3294 3295 3296 3297 3298
{
    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("hostdev mode '%s' not supported"),
                       virDomainHostdevModeTypeToString(hostdev->mode));
        return -1;
    }

    switch (hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
J
Jim Fehlig 已提交
3299
        if (libxlDomainAttachHostPCIDevice(driver, vm, hostdev) < 0)
C
Chunyan Liu 已提交
3300
            return -1;
3301 3302
        break;

3303 3304 3305 3306 3307 3308 3309
#ifdef LIBXL_HAVE_PVUSB
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        if (libxlDomainAttachHostUSBDevice(driver, vm, hostdev) < 0)
            return -1;
        break;
#endif

3310 3311 3312 3313
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("hostdev subsys type '%s' not supported"),
                       virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
C
Chunyan Liu 已提交
3314
        return -1;
3315 3316 3317 3318 3319
    }

    return 0;
}

3320
static int
J
Jim Fehlig 已提交
3321
libxlDomainDetachDeviceDiskLive(virDomainObjPtr vm, virDomainDeviceDefPtr dev)
3322
{
J
Jim Fehlig 已提交
3323
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(libxl_driver);
3324 3325
    virDomainDiskDefPtr l_disk = NULL;
    libxl_device_disk x_disk;
3326
    int idx;
3327 3328 3329 3330 3331 3332
    int ret = -1;

    switch (dev->data.disk->device)  {
        case VIR_DOMAIN_DISK_DEVICE_DISK:
            if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {

3333 3334 3335
                if ((idx = virDomainDiskIndexByName(vm->def,
                                                    dev->data.disk->dst,
                                                    false)) < 0) {
3336 3337
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("disk %s not found"), dev->data.disk->dst);
3338 3339 3340
                    goto cleanup;
                }

3341
                l_disk = vm->def->disks[idx];
3342

J
Jim Fehlig 已提交
3343
                if (libxlMakeDisk(l_disk, &x_disk) < 0)
3344 3345
                    goto cleanup;

J
Jim Fehlig 已提交
3346
                if ((ret = libxl_device_disk_remove(cfg->ctx, vm->def->id,
J
Jim Fehlig 已提交
3347
                                                    &x_disk, NULL)) < 0) {
3348 3349 3350
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("libxenlight failed to detach disk '%s'"),
                                   l_disk->dst);
3351 3352 3353
                    goto cleanup;
                }

3354 3355 3356 3357 3358
                if (virDomainLockDiskDetach(libxl_driver->lockManager,
                                            vm, l_disk) < 0)
                    VIR_WARN("Unable to release lock on %s",
                             virDomainDiskGetSource(l_disk));

3359
                virDomainDiskRemove(vm->def, idx);
3360 3361 3362
                virDomainDiskDefFree(l_disk);

            } else {
3363 3364 3365
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("disk bus '%s' cannot be hot unplugged."),
                               virDomainDiskBusTypeToString(dev->data.disk->bus));
3366 3367 3368
            }
            break;
        default:
3369 3370 3371
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot hot unplugged"),
                           virDomainDiskDeviceTypeToString(dev->data.disk->device));
3372 3373 3374
            break;
    }

3375
 cleanup:
J
Jim Fehlig 已提交
3376
    virObjectUnref(cfg);
3377 3378 3379
    return ret;
}

3380 3381 3382 3383 3384
static int
libxlDomainAttachNetDevice(libxlDriverPrivatePtr driver,
                           virDomainObjPtr vm,
                           virDomainNetDefPtr net)
{
J
Jim Fehlig 已提交
3385
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3386
    virDomainNetType actualType;
3387 3388
    libxl_device_nic nic;
    int ret = -1;
3389
    char mac[VIR_MAC_STRING_BUFLEN];
3390

3391 3392
    libxl_device_nic_init(&nic);

3393 3394
    /* preallocate new slot for device */
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
3395
        goto cleanup;
3396 3397 3398 3399 3400

    /* If appropriate, grab a physical device from the configured
     * network's pool of devices, or resolve bridge device name
     * to the one defined in the network definition.
     */
3401
    if (virDomainNetAllocateActualDevice(vm->def, net) < 0)
3402
        goto cleanup;
3403 3404 3405

    actualType = virDomainNetGetActualType(net);

3406 3407 3408 3409
    if (virDomainHasNet(vm->def, net)) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("network device with mac %s already exists"),
                       virMacAddrFormat(&net->mac, mac));
3410
        goto cleanup;
3411 3412
    }

3413
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424
        virDomainHostdevDefPtr hostdev = virDomainNetGetActualHostdev(net);
        virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;

        /* For those just allocated from a network pool whose backend is
         * still VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, we need to set
         * backend correctly.
         */
        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
            pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN;

3425 3426 3427
        /* This is really a "smart hostdev", so it should be attached
         * as a hostdev (the hostdev code will reach over into the
         * netdev-specific code as appropriate), then also added to
3428
         * the nets list if successful.
3429
         */
3430
        ret = libxlDomainAttachHostDevice(driver, vm, hostdev);
3431
        goto cleanup;
3432 3433
    }

3434
    if (libxlMakeNic(vm->def, net, &nic, true) < 0)
3435 3436
        goto cleanup;

J
Jim Fehlig 已提交
3437
    if (libxl_device_nic_add(cfg->ctx, vm->def->id, &nic, 0)) {
3438 3439 3440 3441 3442 3443 3444 3445 3446
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight failed to attach network device"));
        goto cleanup;
    }

    ret = 0;

 cleanup:
    libxl_device_nic_dispose(&nic);
3447 3448 3449
    if (!ret) {
        vm->def->nets[vm->def->nnets++] = net;
    } else {
3450
        virDomainNetRemoveHostdev(vm->def, net);
3451
        virDomainNetReleaseActualDevice(vm->def, net);
3452
    }
J
Jim Fehlig 已提交
3453
    virObjectUnref(cfg);
3454 3455 3456
    return ret;
}

3457
static int
3458 3459
libxlDomainAttachDeviceLive(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3460 3461 3462 3463 3464 3465
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
J
Jim Fehlig 已提交
3466
            ret = libxlDomainAttachDeviceDiskLive(vm, dev);
3467 3468 3469 3470
            if (!ret)
                dev->data.disk = NULL;
            break;

3471
#ifdef LIBXL_HAVE_PVUSB
3472 3473 3474 3475 3476
        case VIR_DOMAIN_DEVICE_CONTROLLER:
            ret = libxlDomainAttachControllerDevice(driver, vm, dev->data.controller);
            if (!ret)
                dev->data.controller = NULL;
            break;
3477
#endif
3478

3479
        case VIR_DOMAIN_DEVICE_NET:
J
Jim Fehlig 已提交
3480
            ret = libxlDomainAttachNetDevice(driver, vm,
3481 3482 3483 3484 3485
                                             dev->data.net);
            if (!ret)
                dev->data.net = NULL;
            break;

3486
        case VIR_DOMAIN_DEVICE_HOSTDEV:
J
Jim Fehlig 已提交
3487
            ret = libxlDomainAttachHostDevice(driver, vm,
3488
                                              dev->data.hostdev);
3489 3490 3491 3492
            if (!ret)
                dev->data.hostdev = NULL;
            break;

3493
        default:
3494 3495 3496
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be attached"),
                           virDomainDeviceTypeToString(dev->type));
3497 3498 3499 3500 3501 3502 3503 3504 3505 3506
            break;
    }

    return ret;
}

static int
libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{
    virDomainDiskDefPtr disk;
3507
    virDomainNetDefPtr net;
3508
    virDomainHostdevDefPtr hostdev;
3509
    virDomainControllerDefPtr controller;
3510
    virDomainHostdevDefPtr found;
3511
    char mac[VIR_MAC_STRING_BUFLEN];
3512 3513 3514 3515

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            disk = dev->data.disk;
3516
            if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
3517 3518
                virReportError(VIR_ERR_INVALID_ARG,
                               _("target %s already exists."), disk->dst);
3519 3520
                return -1;
            }
3521
            if (virDomainDiskInsert(vmdef, disk))
3522 3523 3524 3525
                return -1;
            /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
            dev->data.disk = NULL;
            break;
3526

3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541
        case VIR_DOMAIN_DEVICE_CONTROLLER:
            controller = dev->data.controller;
            if (controller->idx != -1 &&
                virDomainControllerFind(vmdef, controller->type,
                                        controller->idx) >= 0) {
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("Target already exists"));
                return -1;
            }

            if (virDomainControllerInsert(vmdef, controller) < 0)
                return -1;
            dev->data.controller = NULL;
            break;

3542 3543
        case VIR_DOMAIN_DEVICE_NET:
            net = dev->data.net;
3544 3545 3546 3547 3548 3549
            if (virDomainHasNet(vmdef, net)) {
                virReportError(VIR_ERR_INVALID_ARG,
                               _("network device with mac %s already exists"),
                               virMacAddrFormat(&net->mac, mac));
                return -1;
            }
3550 3551 3552 3553 3554
            if (virDomainNetInsert(vmdef, net))
                return -1;
            dev->data.net = NULL;
            break;

3555 3556 3557
        case VIR_DOMAIN_DEVICE_HOSTDEV:
            hostdev = dev->data.hostdev;

3558 3559 3560 3561 3562 3563
            switch (hostdev->source.subsys.type) {
            case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
#ifndef LIBXL_HAVE_PVUSB
            case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
#endif
            case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
3564
                return -1;
3565
            }
3566 3567

            if (virDomainHostdevFind(vmdef, hostdev, &found) >= 0) {
3568 3569
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("device is already in the domain configuration"));
3570 3571 3572
                return -1;
            }

3573 3574
            if (virDomainHostdevInsert(vmdef, hostdev) < 0)
                return -1;
3575
            dev->data.hostdev = NULL;
3576
            break;
3577 3578

        default:
3579 3580
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("persistent attach of device is not supported"));
3581 3582 3583 3584 3585 3586
            return -1;
    }
    return 0;
}

static int
3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619
libxlComparePCIDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
                      virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
                      virDomainDeviceInfoPtr info1,
                      void *opaque)
{
    virDomainDeviceInfoPtr info2 = opaque;

    if (info1->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
        info2->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
        return 0;

    if (info1->addr.pci.domain == info2->addr.pci.domain &&
        info1->addr.pci.bus == info2->addr.pci.bus &&
        info1->addr.pci.slot == info2->addr.pci.slot &&
        info1->addr.pci.function != info2->addr.pci.function)
        return -1;
    return 0;
}

static bool
libxlIsMultiFunctionDevice(virDomainDefPtr def,
                           virDomainDeviceInfoPtr dev)
{
    if (virDomainDeviceInfoIterate(def, libxlComparePCIDevice, dev) < 0)
        return true;
    return false;
}

static int
libxlDomainDetachHostPCIDevice(libxlDriverPrivatePtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
J
Jim Fehlig 已提交
3620
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3621
    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
3622
    virDomainHostdevSubsysPCIPtr pcisrc = &subsys->u.pci;
3623 3624 3625 3626
    libxl_device_pci pcidev;
    virDomainHostdevDefPtr detach;
    int idx;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
J
Jim Fehlig 已提交
3627
    int ret = -1;
3628

3629 3630
    libxl_device_pci_init(&pcidev);

3631 3632 3633 3634
    idx = virDomainHostdevFind(vm->def, hostdev, &detach);
    if (idx < 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("host pci device %.4x:%.2x:%.2x.%.1x not found"),
3635 3636
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
J
Jim Fehlig 已提交
3637
        goto cleanup;
3638 3639 3640 3641 3642
    }

    if (libxlIsMultiFunctionDevice(vm->def, detach->info)) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("cannot hot unplug multifunction PCI device: %.4x:%.2x:%.2x.%.1x"),
3643 3644
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
C
Chunyan Liu 已提交
3645
        goto error;
3646 3647 3648
    }


3649
    if (libxlMakePCI(detach, &pcidev) < 0)
C
Chunyan Liu 已提交
3650
        goto error;
3651

J
Jim Fehlig 已提交
3652
    if (libxl_device_pci_remove(cfg->ctx, vm->def->id, &pcidev, 0) < 0) {
3653 3654 3655
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to detach pci device\
                          %.4x:%.2x:%.2x.%.1x"),
3656 3657
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
C
Chunyan Liu 已提交
3658
        goto error;
3659 3660 3661 3662 3663 3664 3665 3666
    }


    virDomainHostdevRemove(vm->def, idx);

    virHostdevReAttachPCIDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                 vm->def->name, &hostdev, 1, NULL);

J
Jim Fehlig 已提交
3667
    ret = 0;
3668

3669
 error:
3670
    virDomainHostdevDefFree(detach);
J
Jim Fehlig 已提交
3671 3672 3673

 cleanup:
    virObjectUnref(cfg);
3674
    libxl_device_pci_dispose(&pcidev);
J
Jim Fehlig 已提交
3675
    return ret;
3676 3677
}

3678
#ifdef LIBXL_HAVE_PVUSB
3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729
static int
libxlDomainDetachControllerDevice(libxlDriverPrivatePtr driver,
                                  virDomainObjPtr vm,
                                  virDomainDeviceDefPtr dev)
{
    int idx, ret = -1;
    virDomainControllerDefPtr detach = NULL;
    virDomainControllerDefPtr controller = dev->data.controller;
    const char *type = virDomainControllerTypeToString(controller->type);
    libxl_device_usbctrl usbctrl;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);

    libxl_device_usbctrl_init(&usbctrl);

    if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_USB) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot plugged."),
                       type);
        goto cleanup;
    }

    if ((idx = virDomainControllerFind(vm->def,
                                       controller->type,
                                       controller->idx)) < 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("controller %s:%d not found"),
                       type, controller->idx);
        goto cleanup;
    }

    detach = vm->def->controllers[idx];

    if (libxlMakeUSBController(controller, &usbctrl) < 0)
        goto cleanup;

    if (libxl_device_usbctrl_remove(cfg->ctx, vm->def->id, &usbctrl, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight failed to detach USB controller"));
        goto cleanup;
    }

    virDomainControllerRemove(vm->def, idx);
    ret = 0;

 cleanup:
    virDomainControllerDefFree(detach);
    virObjectUnref(cfg);
    libxl_device_usbctrl_dispose(&usbctrl);
    return ret;
}

3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798
static int
libxlDomainDetachHostUSBDevice(libxlDriverPrivatePtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
    virDomainHostdevSubsysUSBPtr usbsrc = &subsys->u.usb;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
    libxl_device_usbdev usbdev;
    libxl_device_usbdev *usbdevs = NULL;
    int num = 0;
    virDomainHostdevDefPtr detach;
    int idx;
    size_t i;
    bool found = false;
    int ret = -1;

    libxl_device_usbdev_init(&usbdev);

    idx = virDomainHostdevFind(vm->def, hostdev, &detach);
    if (idx < 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("host USB device Busnum: %3x, Devnum: %3x not found"),
                       usbsrc->bus, usbsrc->device);
        goto cleanup;
    }

    usbdevs = libxl_device_usbdev_list(cfg->ctx, vm->def->id, &num);
    for (i = 0; i < num; i++) {
        if (usbdevs[i].u.hostdev.hostbus == usbsrc->bus &&
            usbdevs[i].u.hostdev.hostaddr == usbsrc->device) {
            libxl_device_usbdev_copy(cfg->ctx, &usbdev, &usbdevs[i]);
            found = true;
            break;
        }
    }
    libxl_device_usbdev_list_free(usbdevs, num);

    if (!found) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("host USB device Busnum: %3x, Devnum: %3x not found"),
                       usbsrc->bus, usbsrc->device);
        goto cleanup;
    }

    if (libxl_device_usbdev_remove(cfg->ctx, vm->def->id, &usbdev, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to detach USB device\
                          Busnum: %3x, Devnum: %3x"),
                       usbsrc->bus, usbsrc->device);
        goto cleanup;
    }

    virDomainHostdevRemove(vm->def, idx);

    virHostdevReAttachUSBDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                 vm->def->name, &hostdev, 1);

    ret = 0;

 cleanup:
    virDomainHostdevDefFree(detach);
    virObjectUnref(cfg);
    libxl_device_usbdev_dispose(&usbdev);
    return ret;
}
#endif

3799 3800 3801
static int
libxlDomainDetachHostDevice(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3802
                            virDomainHostdevDefPtr hostdev)
3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814
{
    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;

    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("hostdev mode '%s' not supported"),
                       virDomainHostdevModeTypeToString(hostdev->mode));
        return -1;
    }

    switch (subsys->type) {
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
J
Jim Fehlig 已提交
3815
            return libxlDomainDetachHostPCIDevice(driver, vm, hostdev);
3816

3817 3818 3819 3820 3821
#ifdef LIBXL_HAVE_PVUSB
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
            return libxlDomainDetachHostUSBDevice(driver, vm, hostdev);
#endif

3822 3823 3824 3825 3826 3827 3828 3829 3830
        default:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected hostdev type %d"), subsys->type);
            break;
    }

    return -1;
}

3831 3832 3833 3834 3835
static int
libxlDomainDetachNetDevice(libxlDriverPrivatePtr driver,
                           virDomainObjPtr vm,
                           virDomainNetDefPtr net)
{
J
Jim Fehlig 已提交
3836
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3837 3838 3839 3840 3841 3842
    int detachidx;
    virDomainNetDefPtr detach = NULL;
    libxl_device_nic nic;
    char mac[VIR_MAC_STRING_BUFLEN];
    int ret = -1;

3843 3844
    libxl_device_nic_init(&nic);

3845
    if ((detachidx = virDomainNetFindIdx(vm->def, net)) < 0)
3846
        goto cleanup;
3847 3848 3849 3850 3851 3852 3853

    detach = vm->def->nets[detachidx];

    if (virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* This is really a "smart hostdev", so it should be attached as a
         * hostdev, then also removed from nets list (see out:) if successful.
         */
J
Jim Fehlig 已提交
3854
        ret = libxlDomainDetachHostDevice(driver, vm,
3855
                                          virDomainNetGetActualHostdev(detach));
3856
        goto cleanup;
3857 3858
    }

J
Jim Fehlig 已提交
3859
    if (libxl_mac_to_device_nic(cfg->ctx, vm->def->id,
3860 3861 3862
                                virMacAddrFormat(&detach->mac, mac), &nic))
        goto cleanup;

J
Jim Fehlig 已提交
3863
    if (libxl_device_nic_remove(cfg->ctx, vm->def->id, &nic, 0)) {
3864 3865 3866 3867 3868 3869 3870 3871 3872
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight failed to detach network device"));
        goto cleanup;
    }

    ret = 0;

 cleanup:
    libxl_device_nic_dispose(&nic);
J
Jim Fehlig 已提交
3873
    if (!ret) {
3874
        virDomainNetReleaseActualDevice(vm->def, detach);
J
Jim Fehlig 已提交
3875 3876
        virDomainNetRemove(vm->def, detachidx);
    }
J
Jim Fehlig 已提交
3877
    virObjectUnref(cfg);
3878 3879 3880
    return ret;
}

3881 3882 3883
static int
libxlDomainDetachDeviceLive(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3884 3885
                            virDomainDeviceDefPtr dev)
{
3886
    virDomainHostdevDefPtr hostdev;
3887 3888 3889 3890
    int ret = -1;

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
J
Jim Fehlig 已提交
3891
            ret = libxlDomainDetachDeviceDiskLive(vm, dev);
3892 3893
            break;

3894
#ifdef LIBXL_HAVE_PVUSB
3895 3896 3897
        case VIR_DOMAIN_DEVICE_CONTROLLER:
            ret = libxlDomainDetachControllerDevice(driver, vm, dev);
            break;
3898
#endif
3899

3900
        case VIR_DOMAIN_DEVICE_NET:
J
Jim Fehlig 已提交
3901
            ret = libxlDomainDetachNetDevice(driver, vm,
3902 3903 3904
                                             dev->data.net);
            break;

3905
        case VIR_DOMAIN_DEVICE_HOSTDEV:
3906 3907 3908 3909 3910 3911 3912 3913 3914 3915
            hostdev = dev->data.hostdev;

            /* If this is a network hostdev, we need to use the higher-level
             * detach function so that mac address / virtualport are reset
             */
            if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET)
                ret = libxlDomainDetachNetDevice(driver, vm,
                                                 hostdev->parent.data.net);
            else
                ret = libxlDomainDetachHostDevice(driver, vm, hostdev);
3916 3917
            break;

3918
        default:
3919 3920 3921
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be detached"),
                           virDomainDeviceTypeToString(dev->type));
3922 3923 3924 3925 3926 3927
            break;
    }

    return ret;
}

3928

3929 3930 3931
static int
libxlDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{
3932
    virDomainDiskDefPtr disk, detach;
3933
    virDomainHostdevDefPtr hostdev, det_hostdev;
3934
    virDomainControllerDefPtr cont, det_cont;
3935
    virDomainNetDefPtr net;
3936
    int idx;
3937 3938 3939 3940

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            disk = dev->data.disk;
3941
            if (!(detach = virDomainDiskRemoveByName(vmdef, disk->dst))) {
3942 3943
                virReportError(VIR_ERR_INVALID_ARG,
                               _("no target device %s"), disk->dst);
3944
                return -1;
3945
            }
3946
            virDomainDiskDefFree(detach);
3947
            break;
3948

3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960
        case VIR_DOMAIN_DEVICE_CONTROLLER:
            cont = dev->data.controller;
            if ((idx = virDomainControllerFind(vmdef, cont->type,
                                               cont->idx)) < 0) {
                virReportError(VIR_ERR_INVALID_ARG, "%s",
                               _("device not present in domain configuration"));
                return -1;
            }
            det_cont = virDomainControllerRemove(vmdef, idx);
            virDomainControllerDefFree(det_cont);
            break;

3961 3962 3963 3964 3965 3966 3967 3968 3969
        case VIR_DOMAIN_DEVICE_NET:
            net = dev->data.net;
            if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
                return -1;

            /* this is guaranteed to succeed */
            virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
            break;

3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981
        case VIR_DOMAIN_DEVICE_HOSTDEV: {
            hostdev = dev->data.hostdev;
            if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
                virReportError(VIR_ERR_INVALID_ARG, "%s",
                               _("device not present in domain configuration"));
                return -1;
            }
            virDomainHostdevRemove(vmdef, idx);
            virDomainHostdevDefFree(det_hostdev);
            break;
        }

3982
        default:
3983 3984
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("persistent detach of device is not supported"));
3985
            return -1;
3986 3987
    }

3988
    return 0;
3989 3990 3991
}

static int
J
Jim Fehlig 已提交
3992
libxlDomainUpdateDeviceLive(virDomainObjPtr vm, virDomainDeviceDefPtr dev)
3993 3994 3995 3996 3997 3998 3999 4000 4001
{
    virDomainDiskDefPtr disk;
    int ret = -1;

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            disk = dev->data.disk;
            switch (disk->device) {
                case VIR_DOMAIN_DISK_DEVICE_CDROM:
J
Jim Fehlig 已提交
4002
                    ret = libxlDomainChangeEjectableMedia(vm, disk);
4003 4004 4005 4006
                    if (ret == 0)
                        dev->data.disk = NULL;
                    break;
                default:
4007 4008 4009
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("disk bus '%s' cannot be updated."),
                                   virDomainDiskBusTypeToString(disk->bus));
4010 4011 4012 4013
                    break;
            }
            break;
        default:
4014 4015 4016
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be updated"),
                           virDomainDeviceTypeToString(dev->type));
4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032
            break;
    }

    return ret;
}

static int
libxlDomainUpdateDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{
    virDomainDiskDefPtr orig;
    virDomainDiskDefPtr disk;
    int ret = -1;

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            disk = dev->data.disk;
4033
            if (!(orig = virDomainDiskByName(vmdef, disk->dst, false))) {
4034 4035
                virReportError(VIR_ERR_INVALID_ARG,
                               _("target %s doesn't exist."), disk->dst);
4036 4037 4038
                goto cleanup;
            }
            if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM)) {
4039 4040
                virReportError(VIR_ERR_INVALID_ARG, "%s",
                               _("this disk doesn't support update"));
4041 4042 4043
                goto cleanup;
            }

4044 4045 4046 4047 4048 4049
            if (virDomainDiskSetSource(orig, virDomainDiskGetSource(disk)) < 0)
                goto cleanup;
            virDomainDiskSetType(orig, virDomainDiskGetType(disk));
            virDomainDiskSetFormat(orig, virDomainDiskGetFormat(disk));
            if (virDomainDiskSetDriver(orig, virDomainDiskGetDriver(disk)) < 0)
                goto cleanup;
4050 4051
            break;
        default:
4052 4053
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("persistent update of device is not supported"));
4054 4055 4056 4057 4058
            goto cleanup;
    }

    ret = 0;

4059
 cleanup:
4060 4061 4062 4063 4064
    return ret;
}


static int
4065 4066
libxlDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                             unsigned int flags)
4067 4068
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4069
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4070 4071 4072 4073 4074 4075 4076 4077
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

J
Jim Fehlig 已提交
4078
    if (!(vm = libxlDomObjFromDomain(dom)))
4079 4080
        goto cleanup;

4081 4082 4083
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4084 4085 4086
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

4087 4088
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;
4089 4090

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
4091
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
4092
                                            cfg->caps, driver->xmlopt,
4093
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
4094
            goto endjob;
4095 4096

        /* Make a copy for updated domain. */
4097
        if (!(vmdef = virDomainObjCopyPersistentDef(vm, cfg->caps,
4098
                                                    driver->xmlopt)))
4099
            goto endjob;
4100

4101
        if (libxlDomainAttachDeviceConfig(vmdef, dev) < 0)
4102
            goto endjob;
4103
    }
4104 4105 4106 4107

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
        /* If dev exists it was created to modify the domain config. Free it. */
        virDomainDeviceDefFree(dev);
4108
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
4109
                                            cfg->caps, driver->xmlopt,
4110
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
4111
            goto endjob;
4112

J
Jim Fehlig 已提交
4113
        if (libxlDomainAttachDeviceLive(driver, vm, dev) < 0)
4114
            goto endjob;
4115

4116 4117 4118 4119
        /*
         * update domain status forcibly because the domain status may be
         * changed even if we attach the device failed.
         */
4120
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
4121
            goto endjob;
4122 4123
    }

4124 4125
    ret = 0;

4126
    /* Finally, if no error until here, we can save config. */
4127
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
4128
        ret = virDomainSaveConfig(cfg->configDir, cfg->caps, vmdef);
4129
        if (!ret) {
4130
            virDomainObjAssignDef(vm, vmdef, false, NULL);
4131 4132 4133 4134
            vmdef = NULL;
        }
    }

4135
 endjob:
W
Wang Yufei 已提交
4136
    libxlDomainObjEndJob(driver, vm);
4137

4138
 cleanup:
4139 4140
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
W
Wang Yufei 已提交
4141
    virDomainObjEndAPI(&vm);
4142
    virObjectUnref(cfg);
4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156
    return ret;
}

static int
libxlDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    return libxlDomainAttachDeviceFlags(dom, xml,
                                        VIR_DOMAIN_DEVICE_MODIFY_LIVE);
}

static int
libxlDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                             unsigned int flags)
{
4157
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4158
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4159 4160 4161 4162 4163 4164 4165 4166
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

J
Jim Fehlig 已提交
4167
    if (!(vm = libxlDomObjFromDomain(dom)))
4168 4169
        goto cleanup;

4170 4171 4172
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4173 4174 4175
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

4176 4177
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;
4178 4179 4180

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
4181
                                            cfg->caps, driver->xmlopt,
4182 4183
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                            VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
4184
            goto endjob;
4185 4186

        /* Make a copy for updated domain. */
4187
        if (!(vmdef = virDomainObjCopyPersistentDef(vm, cfg->caps,
4188
                                                    driver->xmlopt)))
4189
            goto endjob;
4190

4191
        if (libxlDomainDetachDeviceConfig(vmdef, dev) < 0)
4192
            goto endjob;
4193 4194 4195 4196 4197 4198
    }

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
        /* If dev exists it was created to modify the domain config. Free it. */
        virDomainDeviceDefFree(dev);
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
4199
                                            cfg->caps, driver->xmlopt,
4200 4201
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                            VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
4202
            goto endjob;
4203

J
Jim Fehlig 已提交
4204
        if (libxlDomainDetachDeviceLive(driver, vm, dev) < 0)
4205
            goto endjob;
4206 4207 4208 4209 4210

        /*
         * update domain status forcibly because the domain status may be
         * changed even if we attach the device failed.
         */
4211
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
4212
            goto endjob;
4213 4214
    }

4215 4216
    ret = 0;

4217
    /* Finally, if no error until here, we can save config. */
4218
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
4219
        ret = virDomainSaveConfig(cfg->configDir, cfg->caps, vmdef);
4220 4221 4222 4223 4224 4225
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

4226
 endjob:
W
Wang Yufei 已提交
4227
    libxlDomainObjEndJob(driver, vm);
4228

4229
 cleanup:
4230 4231
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
W
Wang Yufei 已提交
4232
    virDomainObjEndAPI(&vm);
4233
    virObjectUnref(cfg);
4234
    return ret;
4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247
}

static int
libxlDomainDetachDevice(virDomainPtr dom, const char *xml)
{
    return libxlDomainDetachDeviceFlags(dom, xml,
                                        VIR_DOMAIN_DEVICE_MODIFY_LIVE);
}

static int
libxlDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
                             unsigned int flags)
{
4248
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4249
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4250 4251 4252 4253 4254 4255 4256 4257
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

J
Jim Fehlig 已提交
4258
    if (!(vm = libxlDomObjFromDomain(dom)))
4259 4260
        goto cleanup;

4261 4262 4263
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4264 4265
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto cleanup;
4266 4267 4268

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
4269
                                            cfg->caps, driver->xmlopt,
4270
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
4271 4272 4273
            goto cleanup;

        /* Make a copy for updated domain. */
4274
        if (!(vmdef = virDomainObjCopyPersistentDef(vm, cfg->caps,
4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287
                                                    driver->xmlopt)))
            goto cleanup;

        if ((ret = libxlDomainUpdateDeviceConfig(vmdef, dev)) < 0)
            goto cleanup;
    } else {
        ret = 0;
    }

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
        /* If dev exists it was created to modify the domain config. Free it. */
        virDomainDeviceDefFree(dev);
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
4288
                                            cfg->caps, driver->xmlopt,
4289
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
4290 4291
            goto cleanup;

J
Jim Fehlig 已提交
4292
        if ((ret = libxlDomainUpdateDeviceLive(vm, dev)) < 0)
4293 4294 4295 4296 4297 4298
            goto cleanup;

        /*
         * update domain status forcibly because the domain status may be
         * changed even if we attach the device failed.
         */
4299
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
4300 4301 4302 4303 4304
            ret = -1;
    }

    /* Finally, if no error until here, we can save config. */
    if (!ret && (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG)) {
4305
        ret = virDomainSaveConfig(cfg->configDir, cfg->caps, vmdef);
4306 4307 4308 4309 4310 4311
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

4312
 cleanup:
4313 4314
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
4315
    virDomainObjEndAPI(&vm);
4316
    virObjectUnref(cfg);
4317
    return ret;
4318 4319
}

4320 4321 4322 4323 4324
static unsigned long long
libxlNodeGetFreeMemory(virConnectPtr conn)
{
    libxl_physinfo phy_info;
    libxlDriverPrivatePtr driver = conn->privateData;
4325 4326
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    unsigned long long ret = 0;
4327

4328
    libxl_physinfo_init(&phy_info);
4329
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
4330
        goto cleanup;
4331

4332
    if (libxl_get_physinfo(cfg->ctx, &phy_info)) {
4333 4334
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxl_get_physinfo_info failed"));
4335
        goto cleanup;
4336 4337
    }

4338 4339
    ret = phy_info.free_pages * cfg->verInfo->pagesize;

4340
 cleanup:
4341
    libxl_physinfo_dispose(&phy_info);
4342 4343
    virObjectUnref(cfg);
    return ret;
4344 4345
}

4346 4347 4348 4349 4350 4351 4352 4353 4354 4355
static int
libxlNodeGetCellsFreeMemory(virConnectPtr conn,
                            unsigned long long *freeMems,
                            int startCell,
                            int maxCells)
{
    int n, lastCell, numCells;
    int ret = -1, nr_nodes = 0;
    libxl_numainfo *numa_info = NULL;
    libxlDriverPrivatePtr driver = conn->privateData;
4356
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4357 4358

    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
4359
        goto cleanup;
4360

4361
    numa_info = libxl_get_numainfo(cfg->ctx, &nr_nodes);
4362
    if (numa_info == NULL || nr_nodes == 0) {
4363 4364 4365
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxl_get_numainfo failed"));
        goto cleanup;
4366 4367 4368
    }

    /* Check/sanitize the cell range */
4369
    if (startCell >= nr_nodes) {
4370 4371
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("start cell %d out of range (0-%d)"),
4372
                       startCell, nr_nodes - 1);
4373 4374 4375
        goto cleanup;
    }
    lastCell = startCell + maxCells - 1;
4376 4377
    if (lastCell >= nr_nodes)
        lastCell = nr_nodes - 1;
4378 4379 4380 4381 4382 4383 4384

    for (numCells = 0, n = startCell; n <= lastCell; n++) {
        if (numa_info[n].size == LIBXL_NUMAINFO_INVALID_ENTRY)
            freeMems[numCells++] = 0;
        else
            freeMems[numCells++] = numa_info[n].free;
    }
4385

4386 4387
    ret = numCells;

4388
 cleanup:
4389
    libxl_numainfo_list_free(numa_info, nr_nodes);
4390
    virObjectUnref(cfg);
4391 4392 4393
    return ret;
}

4394
static int
4395
libxlConnectDomainEventRegister(virConnectPtr conn,
4396 4397
                                virConnectDomainEventCallback callback,
                                void *opaque,
4398
                                virFreeCallback freecb)
4399 4400 4401
{
    libxlDriverPrivatePtr driver = conn->privateData;

4402 4403 4404
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

4405 4406 4407 4408
    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        return -1;
4409

4410
    return 0;
4411 4412 4413 4414
}


static int
4415 4416
libxlConnectDomainEventDeregister(virConnectPtr conn,
                                  virConnectDomainEventCallback callback)
4417 4418 4419
{
    libxlDriverPrivatePtr driver = conn->privateData;

4420 4421 4422
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

4423 4424 4425 4426
    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        return -1;
4427

4428
    return 0;
4429 4430
}

4431 4432 4433 4434 4435 4436
static int
libxlDomainGetAutostart(virDomainPtr dom, int *autostart)
{
    virDomainObjPtr vm;
    int ret = -1;

J
Jim Fehlig 已提交
4437
    if (!(vm = libxlDomObjFromDomain(dom)))
4438 4439
        goto cleanup;

4440 4441 4442
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4443 4444 4445
    *autostart = vm->autostart;
    ret = 0;

4446
 cleanup:
4447
    virDomainObjEndAPI(&vm);
4448 4449 4450 4451 4452 4453 4454
    return ret;
}

static int
libxlDomainSetAutostart(virDomainPtr dom, int autostart)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4455
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4456 4457 4458 4459
    virDomainObjPtr vm;
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

J
Jim Fehlig 已提交
4460
    if (!(vm = libxlDomObjFromDomain(dom)))
4461 4462
        goto cleanup;

J
Jim Fehlig 已提交
4463 4464
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

4465 4466 4467
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4468 4469 4470
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

4471
    if (!vm->persistent) {
4472 4473
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient domain"));
4474
        goto endjob;
4475 4476 4477 4478 4479
    }

    autostart = (autostart != 0);

    if (vm->autostart != autostart) {
4480
        if (!(configFile = virDomainConfigFile(cfg->configDir, vm->def->name)))
4481
            goto endjob;
4482
        if (!(autostartLink = virDomainConfigFile(cfg->autostartDir, vm->def->name)))
4483
            goto endjob;
4484 4485

        if (autostart) {
4486
            if (virFileMakePath(cfg->autostartDir) < 0) {
4487
                virReportSystemError(errno,
4488
                                     _("cannot create autostart directory %s"),
4489
                                     cfg->autostartDir);
4490
                goto endjob;
4491 4492 4493 4494 4495 4496
            }

            if (symlink(configFile, autostartLink) < 0) {
                virReportSystemError(errno,
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
4497
                goto endjob;
4498 4499 4500 4501 4502 4503
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
                virReportSystemError(errno,
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
4504
                goto endjob;
4505 4506 4507 4508 4509 4510 4511
            }
        }

        vm->autostart = autostart;
    }
    ret = 0;

4512
 endjob:
W
Wang Yufei 已提交
4513
    libxlDomainObjEndJob(driver, vm);
4514

4515
 cleanup:
4516 4517
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
W
Wang Yufei 已提交
4518
    virDomainObjEndAPI(&vm);
4519
    virObjectUnref(cfg);
4520 4521 4522
    return ret;
}

4523 4524 4525
static char *
libxlDomainGetSchedulerType(virDomainPtr dom, int *nparams)
{
J
Jim Fehlig 已提交
4526 4527
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4528 4529
    virDomainObjPtr vm;
    char * ret = NULL;
4530
    const char *name = NULL;
J
Jim Fehlig 已提交
4531
    libxl_scheduler sched_id;
4532

J
Jim Fehlig 已提交
4533
    if (!(vm = libxlDomObjFromDomain(dom)))
4534 4535
        goto cleanup;

4536 4537 4538
    if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4539
    if (virDomainObjCheckActive(vm) < 0)
4540 4541
        goto cleanup;

J
Jim Fehlig 已提交
4542
    sched_id = libxl_get_scheduler(cfg->ctx);
4543

4544 4545
    if (nparams)
        *nparams = 0;
4546
    switch ((int)sched_id) {
J
Jim Fehlig 已提交
4547
    case LIBXL_SCHEDULER_SEDF:
4548
        name = "sedf";
4549
        break;
J
Jim Fehlig 已提交
4550
    case LIBXL_SCHEDULER_CREDIT:
4551
        name = "credit";
4552 4553
        if (nparams)
            *nparams = XEN_SCHED_CREDIT_NPARAM;
4554
        break;
J
Jim Fehlig 已提交
4555
    case LIBXL_SCHEDULER_CREDIT2:
4556
        name = "credit2";
4557
        break;
J
Jim Fehlig 已提交
4558
    case LIBXL_SCHEDULER_ARINC653:
4559
        name = "arinc653";
4560 4561
        break;
    default:
J
Jim Fehlig 已提交
4562 4563
        virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Failed to get scheduler id for domain '%d'"
4564
                     " with libxenlight"), vm->def->id);
4565 4566 4567
        goto cleanup;
    }

4568
    ignore_value(VIR_STRDUP(ret, name));
4569

4570
 cleanup:
4571
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
4572
    virObjectUnref(cfg);
4573 4574 4575
    return ret;
}

4576
static int
4577 4578 4579 4580
libxlDomainGetSchedulerParametersFlags(virDomainPtr dom,
                                       virTypedParameterPtr params,
                                       int *nparams,
                                       unsigned int flags)
4581
{
J
Jim Fehlig 已提交
4582 4583
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4584
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
4585 4586
    libxl_domain_sched_params sc_info;
    libxl_scheduler sched_id;
4587 4588
    int ret = -1;

4589 4590 4591 4592
    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
4593

J
Jim Fehlig 已提交
4594
    if (!(vm = libxlDomObjFromDomain(dom)))
4595 4596
        goto cleanup;

4597 4598 4599
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4600
    if (virDomainObjCheckActive(vm) < 0)
4601 4602
        goto cleanup;

J
Jim Fehlig 已提交
4603
    sched_id = libxl_get_scheduler(cfg->ctx);
4604

J
Jim Fehlig 已提交
4605
    if (sched_id != LIBXL_SCHEDULER_CREDIT) {
4606 4607
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Only 'credit' scheduler is supported"));
4608 4609 4610
        goto cleanup;
    }

J
Jim Fehlig 已提交
4611
    if (libxl_domain_sched_params_get(cfg->ctx, vm->def->id, &sc_info) != 0) {
4612 4613
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to get scheduler parameters for domain '%d'"
4614
                         " with libxenlight"), vm->def->id);
4615 4616 4617
        goto cleanup;
    }

4618 4619
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_WEIGHT,
                                VIR_TYPED_PARAM_UINT, sc_info.weight) < 0)
4620 4621
        goto cleanup;

4622
    if (*nparams > 1) {
4623
        if (virTypedParameterAssign(&params[1], VIR_DOMAIN_SCHEDULER_CAP,
4624
                                    VIR_TYPED_PARAM_UINT, sc_info.cap) < 0)
4625
            goto cleanup;
4626 4627
    }

4628 4629
    if (*nparams > XEN_SCHED_CREDIT_NPARAM)
        *nparams = XEN_SCHED_CREDIT_NPARAM;
4630 4631
    ret = 0;

4632
 cleanup:
4633
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
4634
    virObjectUnref(cfg);
4635 4636 4637 4638
    return ret;
}

static int
4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649
libxlDomainGetSchedulerParameters(virDomainPtr dom, virTypedParameterPtr params,
                                  int *nparams)
{
    return libxlDomainGetSchedulerParametersFlags(dom, params, nparams, 0);
}

static int
libxlDomainSetSchedulerParametersFlags(virDomainPtr dom,
                                       virTypedParameterPtr params,
                                       int nparams,
                                       unsigned int flags)
4650
{
4651
    libxlDriverPrivatePtr driver = dom->conn->privateData;
J
Jim Fehlig 已提交
4652
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4653
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
4654
    libxl_domain_sched_params sc_info;
4655
    int sched_id;
4656
    size_t i;
4657 4658
    int ret = -1;

4659
    virCheckFlags(0, -1);
4660 4661 4662 4663 4664 4665
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_SCHEDULER_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
                               VIR_DOMAIN_SCHEDULER_CAP,
                               VIR_TYPED_PARAM_UINT,
                               NULL) < 0)
4666
        return -1;
4667

J
Jim Fehlig 已提交
4668
    if (!(vm = libxlDomObjFromDomain(dom)))
4669 4670
        goto cleanup;

4671 4672 4673
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4674 4675 4676
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

4677
    if (virDomainObjCheckActive(vm) < 0)
4678
        goto endjob;
4679

J
Jim Fehlig 已提交
4680
    sched_id = libxl_get_scheduler(cfg->ctx);
4681

J
Jim Fehlig 已提交
4682
    if (sched_id != LIBXL_SCHEDULER_CREDIT) {
4683 4684
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Only 'credit' scheduler is supported"));
4685
        goto endjob;
4686 4687
    }

J
Jim Fehlig 已提交
4688
    if (libxl_domain_sched_params_get(cfg->ctx, vm->def->id, &sc_info) != 0) {
4689 4690
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to get scheduler parameters for domain '%d'"
4691
                         " with libxenlight"), vm->def->id);
4692
        goto endjob;
4693 4694 4695
    }

    for (i = 0; i < nparams; ++i) {
4696
        virTypedParameterPtr param = &params[i];
4697

4698
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_WEIGHT))
4699
            sc_info.weight = params[i].value.ui;
4700
        else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CAP))
4701 4702 4703
            sc_info.cap = params[i].value.ui;
    }

J
Jim Fehlig 已提交
4704
    if (libxl_domain_sched_params_set(cfg->ctx, vm->def->id, &sc_info) != 0) {
4705 4706
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to set scheduler parameters for domain '%d'"
4707
                         " with libxenlight"), vm->def->id);
4708
        goto endjob;
4709 4710 4711 4712
    }

    ret = 0;

4713
 endjob:
W
Wang Yufei 已提交
4714
    libxlDomainObjEndJob(driver, vm);
4715

4716
 cleanup:
W
Wang Yufei 已提交
4717
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
4718
    virObjectUnref(cfg);
4719 4720 4721
    return ret;
}

B
Bamvor Jian Zhang 已提交
4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735

static int
libxlDomainOpenConsole(virDomainPtr dom,
                       const char *dev_name,
                       virStreamPtr st,
                       unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
    libxlDomainObjPrivatePtr priv;

    virCheckFlags(VIR_DOMAIN_CONSOLE_FORCE, -1);

J
Jim Fehlig 已提交
4736
    if (!(vm = libxlDomObjFromDomain(dom)))
B
Bamvor Jian Zhang 已提交
4737 4738
        goto cleanup;

J
Jim Fehlig 已提交
4739 4740
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

B
Bamvor Jian Zhang 已提交
4741 4742 4743
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4744
    if (virDomainObjCheckActive(vm) < 0)
B
Bamvor Jian Zhang 已提交
4745 4746 4747
        goto cleanup;

    priv = vm->privateData;
B
Bob Liu 已提交
4748 4749
    if (dev_name) {
        size_t i;
B
Bamvor Jian Zhang 已提交
4750

B
Bob Liu 已提交
4751 4752 4753 4754 4755 4756 4757
        for (i = 0; !chr && i < vm->def->nserials; i++) {
            if (STREQ(dev_name, vm->def->serials[i]->info.alias)) {
                chr = vm->def->serials[i];
                break;
            }
        }
    } else if (vm->def->nconsoles) {
I
Ian Campbell 已提交
4758
        chr = vm->def->consoles[0];
4759 4760 4761
        if (chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
            chr = vm->def->serials[0];
    }
B
Bamvor Jian Zhang 已提交
4762 4763 4764 4765 4766 4767 4768 4769

    if (!chr) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find character device %s"),
                       NULLSTR(dev_name));
        goto cleanup;
    }

4770
    if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY) {
B
Bamvor Jian Zhang 已提交
4771 4772
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("character device %s is not using a PTY"),
4773
                       dev_name ? dev_name : NULLSTR(chr->info.alias));
B
Bamvor Jian Zhang 已提交
4774 4775 4776 4777 4778
        goto cleanup;
    }

    /* handle mutually exclusive access to console devices */
    ret = virChrdevOpen(priv->devs,
4779
                        chr->source,
B
Bamvor Jian Zhang 已提交
4780 4781 4782 4783 4784 4785 4786 4787 4788
                        st,
                        (flags & VIR_DOMAIN_CONSOLE_FORCE) != 0);

    if (ret == 1) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Active console session exists for this domain"));
        ret = -1;
    }

4789
 cleanup:
4790
    virDomainObjEndAPI(&vm);
B
Bamvor Jian Zhang 已提交
4791 4792 4793
    return ret;
}

4794 4795 4796 4797 4798 4799 4800
static int
libxlDomainSetSchedulerParameters(virDomainPtr dom, virTypedParameterPtr params,
                                  int nparams)
{
    return libxlDomainSetSchedulerParametersFlags(dom, params, nparams, 0);
}

4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813
/* NUMA node affinity information is available through libxl
 * starting from Xen 4.3. */
#ifdef LIBXL_HAVE_DOMAIN_NODEAFFINITY

/* Number of Xen NUMA parameters */
# define LIBXL_NUMA_NPARAM 2

static int
libxlDomainGetNumaParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
{
J
Jim Fehlig 已提交
4814 4815
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831
    virDomainObjPtr vm;
    libxl_bitmap nodemap;
    virBitmapPtr nodes = NULL;
    char *nodeset = NULL;
    int rc, ret = -1;
    size_t i, j;

    /* In Xen 4.3, it is possible to query the NUMA node affinity of a domain
     * via libxl, but not to change it. We therefore only allow AFFECT_LIVE. */
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    /* We blindly return a string, and let libvirt.c and remote_driver.c do
     * the filtering on behalf of older clients that can't parse it. */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

4832 4833
    libxl_bitmap_init(&nodemap);

J
Jim Fehlig 已提交
4834
    if (!(vm = libxlDomObjFromDomain(dom)))
4835 4836 4837 4838 4839
        goto cleanup;

    if (virDomainGetNumaParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4840
    if (virDomainObjCheckActive(vm) < 0)
4841 4842 4843 4844 4845 4846 4847 4848 4849 4850
        goto cleanup;

    if ((*nparams) == 0) {
        *nparams = LIBXL_NUMA_NPARAM;
        ret = 0;
        goto cleanup;
    }

    for (i = 0; i < LIBXL_NUMA_NPARAM && i < *nparams; i++) {
        virMemoryParameterPtr param = &params[i];
4851
        int numnodes;
4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869

        switch (i) {
        case 0:
            /* NUMA mode */

            /* Xen implements something that is really close to numactl's
             * 'interleave' policy (see `man 8 numactl' for details). */
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE,
                                        VIR_TYPED_PARAM_INT,
                                        VIR_DOMAIN_NUMATUNE_MEM_INTERLEAVE) < 0)
                goto cleanup;

            break;

        case 1:
            /* Node affinity */

            /* Let's allocate both libxl and libvirt bitmaps */
J
Jim Fehlig 已提交
4870
            numnodes = libxl_get_max_nodes(cfg->ctx);
4871 4872 4873
            if (numnodes <= 0)
                goto cleanup;

J
Jim Fehlig 已提交
4874
            if (libxl_node_bitmap_alloc(cfg->ctx, &nodemap, 0)) {
4875 4876 4877
                virReportOOMError();
                goto cleanup;
            }
J
Ján Tomko 已提交
4878 4879
            if (!(nodes = virBitmapNew(numnodes)))
                goto cleanup;
4880

J
Jim Fehlig 已提交
4881
            rc = libxl_domain_get_nodeaffinity(cfg->ctx,
4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900
                                               vm->def->id,
                                               &nodemap);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get numa affinity"));
                goto cleanup;
            }

            /* First, we convert libxl_bitmap into virBitmap. After that,
             * we format virBitmap as a string that can be returned. */
            virBitmapClearAll(nodes);
            libxl_for_each_set_bit(j, nodemap) {
                if (virBitmapSetBit(nodes, j)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Node %zu out of range"), j);
                    goto cleanup;
                }
            }

4901
            if (!(nodeset = virBitmapFormat(nodes)))
4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917
                goto cleanup;

            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_NODESET,
                                        VIR_TYPED_PARAM_STRING, nodeset) < 0)
                goto cleanup;

            nodeset = NULL;

            break;
        }
    }

    if (*nparams > LIBXL_NUMA_NPARAM)
        *nparams = LIBXL_NUMA_NPARAM;
    ret = 0;

4918
 cleanup:
4919 4920 4921
    VIR_FREE(nodeset);
    virBitmapFree(nodes);
    libxl_bitmap_dispose(&nodemap);
4922
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
4923
    virObjectUnref(cfg);
4924 4925 4926 4927
    return ret;
}
#endif

J
Jim Fehlig 已提交
4928 4929 4930 4931 4932 4933
static int
libxlDomainIsActive(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

J
Jim Fehlig 已提交
4934
    if (!(obj = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
4935
        goto cleanup;
4936 4937 4938 4939

    if (virDomainIsActiveEnsureACL(dom->conn, obj->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
4940 4941
    ret = virDomainObjIsActive(obj);

4942
 cleanup:
4943
    virDomainObjEndAPI(&obj);
J
Jim Fehlig 已提交
4944 4945 4946 4947 4948 4949 4950 4951 4952
    return ret;
}

static int
libxlDomainIsPersistent(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

J
Jim Fehlig 已提交
4953
    if (!(obj = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
4954
        goto cleanup;
4955 4956 4957 4958

    if (virDomainIsPersistentEnsureACL(dom->conn, obj->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
4959 4960
    ret = obj->persistent;

4961
 cleanup:
4962
    virDomainObjEndAPI(&obj);
J
Jim Fehlig 已提交
4963 4964 4965
    return ret;
}

4966 4967 4968 4969 4970 4971
static int
libxlDomainIsUpdated(virDomainPtr dom)
{
    virDomainObjPtr vm;
    int ret = -1;

J
Jim Fehlig 已提交
4972
    if (!(vm = libxlDomObjFromDomain(dom)))
4973
        goto cleanup;
4974 4975 4976 4977

    if (virDomainIsUpdatedEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4978 4979
    ret = vm->updated;

4980
 cleanup:
4981
    virDomainObjEndAPI(&vm);
4982 4983 4984
    return ret;
}

4985 4986
static int
libxlDomainInterfaceStats(virDomainPtr dom,
4987
                          const char *device,
4988 4989 4990 4991
                          virDomainInterfaceStatsPtr stats)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
M
Michal Privoznik 已提交
4992
    virDomainNetDefPtr net = NULL;
4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003
    int ret = -1;

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainInterfaceStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_QUERY) < 0)
        goto cleanup;

5004
    if (virDomainObjCheckActive(vm) < 0)
5005 5006
        goto endjob;

5007
    if (!(net = virDomainNetFind(vm->def, device)))
M
Michal Privoznik 已提交
5008 5009
        goto endjob;

5010
    if (virNetDevTapInterfaceStats(net->ifname, stats,
5011
                                   !virDomainNetTypeSharesHostView(net)) < 0)
M
Michal Privoznik 已提交
5012 5013 5014
        goto endjob;

    ret = 0;
5015 5016

 endjob:
W
Wang Yufei 已提交
5017
    libxlDomainObjEndJob(driver, vm);
5018 5019

 cleanup:
W
Wang Yufei 已提交
5020
    virDomainObjEndAPI(&vm);
5021 5022 5023
    return ret;
}

5024 5025 5026 5027 5028 5029
static int
libxlDomainGetTotalCPUStats(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
                            virTypedParameterPtr params,
                            unsigned int nparams)
{
J
Jim Fehlig 已提交
5030
    libxlDriverConfigPtr cfg;
5031 5032 5033 5034 5035 5036
    libxl_dominfo d_info;
    int ret = -1;

    if (nparams == 0)
        return LIBXL_NB_TOTAL_CPU_STAT_PARAM;

J
Jim Fehlig 已提交
5037 5038 5039
    libxl_dominfo_init(&d_info);
    cfg = libxlDriverConfigGet(driver);

5040 5041 5042 5043
    if (libxl_domain_info(cfg->ctx, &d_info, vm->def->id) != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxl_domain_info failed for domain '%d'"),
                       vm->def->id);
J
Jim Fehlig 已提交
5044
        goto cleanup;
5045 5046 5047 5048 5049 5050 5051 5052 5053 5054
    }

    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_CPU_STATS_CPUTIME,
                                VIR_TYPED_PARAM_ULLONG, d_info.cpu_time) < 0)
        goto cleanup;

    ret = nparams;

 cleanup:
    libxl_dominfo_dispose(&d_info);
J
Jim Fehlig 已提交
5055
    virObjectUnref(cfg);
5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069
    return ret;
}

static int
libxlDomainGetPerCPUStats(libxlDriverPrivatePtr driver,
                          virDomainObjPtr vm,
                          virTypedParameterPtr params,
                          unsigned int nparams,
                          int start_cpu,
                          unsigned int ncpus)
{
    libxl_vcpuinfo *vcpuinfo;
    int maxcpu, hostcpus;
    size_t i;
J
Jim Fehlig 已提交
5070
    libxlDriverConfigPtr cfg;
5071 5072 5073 5074 5075
    int ret = -1;

    if (nparams == 0 && ncpus != 0)
        return LIBXL_NB_TOTAL_CPU_STAT_PARAM;
    else if (nparams == 0)
5076
        return virDomainDefGetVcpusMax(vm->def);
5077

J
Jim Fehlig 已提交
5078
    cfg = libxlDriverConfigGet(driver);
5079 5080 5081 5082 5083
    if ((vcpuinfo = libxl_list_vcpu(cfg->ctx, vm->def->id, &maxcpu,
                                    &hostcpus)) == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to list vcpus for domain '%d' with libxenlight"),
                       vm->def->id);
J
Jim Fehlig 已提交
5084
        goto cleanup;
5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096
    }

    for (i = start_cpu; i < maxcpu && i < ncpus; ++i) {
        if (virTypedParameterAssign(&params[(i-start_cpu)],
                                    VIR_DOMAIN_CPU_STATS_CPUTIME,
                                    VIR_TYPED_PARAM_ULLONG,
                                    vcpuinfo[i].vcpu_time) < 0)
            goto cleanup;
    }
    ret = nparams;

 cleanup:
J
Jim Fehlig 已提交
5097 5098 5099
    if (vcpuinfo)
        libxl_vcpuinfo_list_free(vcpuinfo, maxcpu);
    virObjectUnref(cfg);
5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122
    return ret;
}

static int
libxlDomainGetCPUStats(virDomainPtr dom,
                       virTypedParameterPtr params,
                       unsigned int nparams,
                       int start_cpu,
                       unsigned int ncpus,
                       unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainGetCPUStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

5123
    if (virDomainObjCheckActive(vm) < 0)
5124 5125 5126 5127 5128 5129 5130 5131 5132
        goto cleanup;

    if (start_cpu == -1)
        ret = libxlDomainGetTotalCPUStats(driver, vm, params, nparams);
    else
        ret = libxlDomainGetPerCPUStats(driver, vm, params, nparams,
                                          start_cpu, ncpus);

 cleanup:
5133
    virDomainObjEndAPI(&vm);
5134 5135 5136
    return ret;
}

5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150
#define LIBXL_SET_MEMSTAT(TAG, VAL) \
        if (i < nr_stats) { \
            stats[i].tag = TAG; \
            stats[i].val = VAL; \
            i++; \
        }

static int
libxlDomainMemoryStats(virDomainPtr dom,
                       virDomainMemoryStatPtr stats,
                       unsigned int nr_stats,
                       unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
J
Jim Fehlig 已提交
5151
    libxlDriverConfigPtr cfg;
5152 5153 5154 5155 5156 5157 5158 5159
    virDomainObjPtr vm;
    libxl_dominfo d_info;
    unsigned mem, maxmem;
    size_t i = 0;
    int ret = -1;

    virCheckFlags(0, -1);

5160
    libxl_dominfo_init(&d_info);
J
Jim Fehlig 已提交
5161 5162
    cfg = libxlDriverConfigGet(driver);

5163 5164 5165 5166 5167 5168 5169 5170 5171
    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainMemoryStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_QUERY) < 0)
        goto cleanup;

5172
    if (virDomainObjCheckActive(vm) < 0)
5173 5174 5175 5176 5177 5178 5179 5180 5181
        goto endjob;

    if (libxl_domain_info(cfg->ctx, &d_info, vm->def->id) != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxl_domain_info failed for domain '%d'"),
                       vm->def->id);
        goto endjob;
    }
    mem = d_info.current_memkb;
5182
    maxmem = virDomainDefGetMemoryTotal(vm->def);
5183 5184 5185 5186 5187 5188 5189

    LIBXL_SET_MEMSTAT(VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON, mem);
    LIBXL_SET_MEMSTAT(VIR_DOMAIN_MEMORY_STAT_AVAILABLE, maxmem);

    ret = i;

 endjob:
W
Wang Yufei 已提交
5190
    libxlDomainObjEndJob(driver, vm);
5191 5192

 cleanup:
5193
    libxl_dominfo_dispose(&d_info);
W
Wang Yufei 已提交
5194
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
5195
    virObjectUnref(cfg);
5196 5197 5198 5199 5200
    return ret;
}

#undef LIBXL_SET_MEMSTAT

5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232
static int
libxlDomainGetJobInfo(virDomainPtr dom,
                      virDomainJobInfoPtr info)
{
    libxlDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainGetJobInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    priv = vm->privateData;
    if (!priv->job.active) {
        memset(info, 0, sizeof(*info));
        info->type = VIR_DOMAIN_JOB_NONE;
        ret = 0;
        goto cleanup;
    }

    /* In libxl we don't have an estimated completion time
     * thus we always set to unbounded and update time
     * for the active job. */
    if (libxlDomainJobUpdateTime(&priv->job) < 0)
        goto cleanup;

    memcpy(info, priv->job.current, sizeof(virDomainJobInfo));
    ret = 0;

 cleanup:
5233
    virDomainObjEndAPI(&vm);
5234 5235 5236
    return ret;
}

5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283
static int
libxlDomainGetJobStats(virDomainPtr dom,
                       int *type,
                       virTypedParameterPtr *params,
                       int *nparams,
                       unsigned int flags)
{
    libxlDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    virDomainJobInfoPtr jobInfo;
    int ret = -1;
    int maxparams = 0;

    /* VIR_DOMAIN_JOB_STATS_COMPLETED not supported yet */
    virCheckFlags(0, -1);

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainGetJobStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    priv = vm->privateData;
    jobInfo = priv->job.current;
    if (!priv->job.active) {
        *type = VIR_DOMAIN_JOB_NONE;
        *params = NULL;
        *nparams = 0;
        ret = 0;
        goto cleanup;
    }

    /* In libxl we don't have an estimated completion time
     * thus we always set to unbounded and update time
     * for the active job. */
    if (libxlDomainJobUpdateTime(&priv->job) < 0)
        goto cleanup;

    if (virTypedParamsAddULLong(params, nparams, &maxparams,
                                VIR_DOMAIN_JOB_TIME_ELAPSED,
                                jobInfo->timeElapsed) < 0)
        goto cleanup;

    *type = jobInfo->type;
    ret = 0;

 cleanup:
5284
    virDomainObjEndAPI(&vm);
5285 5286
    return ret;
}
5287

R
Roman Bogorodskiy 已提交
5288
#ifdef __linux__
5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335
static int
libxlDiskPathToID(const char *virtpath)
{
    static char const* drive_prefix[] = {"xvd", "hd", "sd"};
    int disk, partition, chrused;
    int fmt, id;
    size_t i;

    fmt = id = -1;

    /* Find any disk prefixes we know about */
    for (i = 0; i < ARRAY_CARDINALITY(drive_prefix); i++) {
        if (STRPREFIX(virtpath, drive_prefix[i]) &&
            !virDiskNameParse(virtpath, &disk, &partition)) {
            fmt = i;
            break;
        }
    }

    /* Handle it same way as xvd */
    if (fmt < 0 &&
        (sscanf(virtpath, "d%ip%i%n", &disk, &partition, &chrused) >= 2
         && chrused == strlen(virtpath)))
        fmt = 0;

    /* Test indexes ranges and calculate the device id */
    switch (fmt) {
    case 0: /* xvd */
        if (disk <= 15 && partition <= 15)
            id = (202 << 8) | (disk << 4) | partition;
        else if ((disk <= ((1<<20)-1)) || partition <= 255)
            id = (1 << 28) | (disk << 8) | partition;
        break;
    case 1: /* hd */
        if (disk <= 3 && partition <= 63)
            id = ((disk < 2 ? 3 : 22) << 8) | ((disk & 1) << 6) | partition;
        break;
    case 2: /* sd */
        if (disk <= 15 && (partition <= 15))
            id = (8 << 8) | (disk << 4) | partition;
        break;
    default: /* invalid */
        break;
    }
    return id;
}

5336
# define LIBXL_VBD_SECTOR_SIZE 512
5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386

static int
libxlDiskSectorSize(int domid, int devno)
{
    char *path, *val;
    struct xs_handle *handle;
    int ret = LIBXL_VBD_SECTOR_SIZE;
    unsigned int len;

    handle = xs_daemon_open_readonly();
    if (!handle) {
        VIR_WARN("cannot read sector size");
        return ret;
    }

    path = val = NULL;
    if (virAsprintf(&path, "/local/domain/%d/device/vbd/%d/backend",
                    domid, devno) < 0)
        goto cleanup;

    if ((val = xs_read(handle, XBT_NULL, path, &len)) == NULL)
        goto cleanup;

    VIR_FREE(path);
    if (virAsprintf(&path, "%s/physical-sector-size", val) < 0)
        goto cleanup;

    VIR_FREE(val);
    if ((val = xs_read(handle, XBT_NULL, path, &len)) == NULL)
        goto cleanup;

    if (sscanf(val, "%d", &ret) != 1)
        ret = LIBXL_VBD_SECTOR_SIZE;

 cleanup:
    VIR_FREE(val);
    VIR_FREE(path);
    xs_daemon_close(handle);
    return ret;
}

static int
libxlDomainBlockStatsVBD(virDomainObjPtr vm,
                         const char *dev,
                         libxlBlockStatsPtr stats)
{
    int ret = -1;
    int devno = libxlDiskPathToID(dev);
    int size;
    char *path, *name, *val;
5387
    unsigned long long status;
5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410

    path = name = val = NULL;
    if (devno < 0) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot find device number"));
        return ret;
    }

    size = libxlDiskSectorSize(vm->def->id, devno);

    if (VIR_STRDUP(stats->backend, "vbd") < 0)
        return ret;

    if (virAsprintf(&path, "/sys/bus/xen-backend/devices/vbd-%d-%d/statistics",
                    vm->def->id, devno) < 0)
        return ret;

    if (!virFileExists(path)) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("cannot open bus path"));
        goto cleanup;
    }

5411
# define LIBXL_SET_VBDSTAT(FIELD, VAR, MUL) \
5412
    if ((virAsprintf(&name, "%s/"FIELD, path) < 0) || \
5413 5414 5415 5416 5417 5418 5419 5420
        (virFileReadAll(name, 256, &val) < 0) || \
        (sscanf(val, "%llu", &status) != 1)) { \
        virReportError(VIR_ERR_OPERATION_FAILED, \
                       _("cannot read %s"), name); \
        goto cleanup; \
    } \
    VAR += (status * MUL); \
    VIR_FREE(name); \
5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473
    VIR_FREE(val);

    LIBXL_SET_VBDSTAT("f_req",  stats->f_req,  1)
    LIBXL_SET_VBDSTAT("wr_req", stats->wr_req, 1)
    LIBXL_SET_VBDSTAT("rd_req", stats->rd_req, 1)
    LIBXL_SET_VBDSTAT("wr_sect", stats->wr_bytes, size)
    LIBXL_SET_VBDSTAT("rd_sect", stats->rd_bytes, size)

    LIBXL_SET_VBDSTAT("ds_req", stats->u.vbd.ds_req, size)
    LIBXL_SET_VBDSTAT("oo_req", stats->u.vbd.oo_req, 1)
    ret = 0;

 cleanup:
    VIR_FREE(name);
    VIR_FREE(path);
    VIR_FREE(val);

# undef LIBXL_SET_VBDSTAT

    return ret;
}
#else
static int
libxlDomainBlockStatsVBD(virDomainObjPtr vm ATTRIBUTE_UNUSED,
                         const char *dev ATTRIBUTE_UNUSED,
                         libxlBlockStatsPtr stats ATTRIBUTE_UNUSED)
{
    virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                   "%s", _("platform unsupported"));
    return -1;
}
#endif

static int
libxlDomainBlockStatsGatherSingle(virDomainObjPtr vm,
                                  const char *path,
                                  libxlBlockStatsPtr stats)
{
    virDomainDiskDefPtr disk;
    const char *disk_drv;
    int ret = -1, disk_fmt;

    if (!(disk = virDomainDiskByName(vm->def, path, false))) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("invalid path: %s"), path);
        return ret;
    }

    disk_fmt = virDomainDiskGetFormat(disk);
    if (!(disk_drv = virDomainDiskGetDriver(disk)))
        disk_drv = "qemu";

    if (STREQ(disk_drv, "phy")) {
5474
        if (disk_fmt != VIR_STORAGE_FILE_RAW) {
5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                           _("unsupported format %s"),
                           virStorageFileFormatTypeToString(disk_fmt));
            return ret;
        }

        ret = libxlDomainBlockStatsVBD(vm, disk->dst, stats);
    } else {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("unsupported disk driver %s"),
                       disk_drv);
    }
    return ret;
}

static int
libxlDomainBlockStatsGather(virDomainObjPtr vm,
                            const char *path,
                            libxlBlockStatsPtr stats)
{
    int ret = -1;

    if (*path) {
        if (libxlDomainBlockStatsGatherSingle(vm, path, stats) < 0)
            return ret;
    } else {
        size_t i;

        for (i = 0; i < vm->def->ndisks; ++i) {
            if (libxlDomainBlockStatsGatherSingle(vm, vm->def->disks[i]->dst,
                                                  stats) < 0)
                return ret;
        }
    }
    return 0;
}

static int
libxlDomainBlockStats(virDomainPtr dom,
                      const char *path,
                      virDomainBlockStatsPtr stats)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    libxlBlockStats blkstats;
    int ret = -1;

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainBlockStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_QUERY) < 0)
        goto cleanup;

5531
    if (virDomainObjCheckActive(vm) < 0)
5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580
        goto endjob;

    memset(&blkstats, 0, sizeof(libxlBlockStats));
    if ((ret = libxlDomainBlockStatsGather(vm, path, &blkstats)) < 0)
        goto endjob;

    stats->rd_req = blkstats.rd_req;
    stats->rd_bytes = blkstats.rd_bytes;
    stats->wr_req = blkstats.wr_req;
    stats->wr_bytes = blkstats.wr_bytes;
    if (STREQ_NULLABLE(blkstats.backend, "vbd"))
        stats->errs = blkstats.u.vbd.oo_req;
    else
        stats->errs = -1;

 endjob:
    libxlDomainObjEndJob(driver, vm);

 cleanup:
    virDomainObjEndAPI(&vm);
    return ret;
}

static int
libxlDomainBlockStatsFlags(virDomainPtr dom,
                           const char *path,
                           virTypedParameterPtr params,
                           int *nparams,
                           unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    libxlBlockStats blkstats;
    int nstats;
    int ret = -1;

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainBlockStatsFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_QUERY) < 0)
        goto cleanup;

5581
    if (virDomainObjCheckActive(vm) < 0)
5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596
        goto endjob;

    /* return count of supported stats */
    if (*nparams == 0) {
        *nparams = LIBXL_NB_TOTAL_BLK_STAT_PARAM;
        ret = 0;
        goto endjob;
    }

    memset(&blkstats, 0, sizeof(libxlBlockStats));
    if ((ret = libxlDomainBlockStatsGather(vm, path, &blkstats)) < 0)
        goto endjob;

    nstats = 0;

5597 5598 5599
#define LIBXL_BLKSTAT_ASSIGN_PARAM(VAR, NAME) \
    if (nstats < *nparams && (blkstats.VAR) != -1) { \
        if (virTypedParameterAssign(params + nstats, NAME, \
5600
                                    VIR_TYPED_PARAM_LLONG, (blkstats.VAR)) < 0) \
5601 5602
            goto endjob; \
        nstats++; \
5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627
    }

    LIBXL_BLKSTAT_ASSIGN_PARAM(wr_bytes, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES);
    LIBXL_BLKSTAT_ASSIGN_PARAM(wr_req, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ);

    LIBXL_BLKSTAT_ASSIGN_PARAM(rd_bytes, VIR_DOMAIN_BLOCK_STATS_READ_BYTES);
    LIBXL_BLKSTAT_ASSIGN_PARAM(rd_req, VIR_DOMAIN_BLOCK_STATS_READ_REQ);

    LIBXL_BLKSTAT_ASSIGN_PARAM(f_req, VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ);

    if (STREQ_NULLABLE(blkstats.backend, "vbd"))
        LIBXL_BLKSTAT_ASSIGN_PARAM(u.vbd.oo_req, VIR_DOMAIN_BLOCK_STATS_ERRS);

    *nparams = nstats;

#undef LIBXL_BLKSTAT_ASSIGN_PARAM

 endjob:
    libxlDomainObjEndJob(driver, vm);

 cleanup:
    virDomainObjEndAPI(&vm);
    return ret;
}

5628
static int
5629 5630 5631
libxlConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID,
                                   virConnectDomainEventGenericCallback callback,
                                   void *opaque, virFreeCallback freecb)
5632 5633 5634 5635
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int ret;

5636 5637 5638
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

5639 5640 5641 5642
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID, callback, opaque,
                                      freecb, &ret) < 0)
5643
        ret = -1;
5644 5645 5646 5647 5648 5649

    return ret;
}


static int
5650
libxlConnectDomainEventDeregisterAny(virConnectPtr conn, int callbackID)
5651 5652 5653
{
    libxlDriverPrivatePtr driver = conn->privateData;

5654 5655 5656
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

5657 5658
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
5659
                                        callbackID, true) < 0)
5660
        return -1;
5661

5662
    return 0;
5663 5664
}

J
Jim Fehlig 已提交
5665

5666
static int
5667
libxlConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
5668 5669 5670 5671
{
    return 1;
}

5672
static int
5673 5674 5675
libxlConnectListAllDomains(virConnectPtr conn,
                           virDomainPtr **domains,
                           unsigned int flags)
5676 5677 5678 5679
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
5680
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
5681

5682 5683 5684
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

5685 5686
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
5687 5688 5689 5690

    return ret;
}

5691 5692 5693 5694 5695 5696 5697
/* Which features are supported by this driver? */
static int
libxlConnectSupportsFeature(virConnectPtr conn, int feature)
{
    if (virConnectSupportsFeatureEnsureACL(conn) < 0)
        return -1;

5698
    switch ((virDrvFeature) feature) {
5699
    case VIR_DRV_FEATURE_MIGRATION_V3:
5700
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
J
Jim Fehlig 已提交
5701
    case VIR_DRV_FEATURE_MIGRATION_PARAMS:
J
Joao Martins 已提交
5702
    case VIR_DRV_FEATURE_MIGRATION_P2P:
5703
        return 1;
5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714
    case VIR_DRV_FEATURE_FD_PASSING:
    case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
    case VIR_DRV_FEATURE_MIGRATION_DIRECT:
    case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
    case VIR_DRV_FEATURE_MIGRATION_V1:
    case VIR_DRV_FEATURE_MIGRATION_V2:
    case VIR_DRV_FEATURE_PROGRAM_KEEPALIVE:
    case VIR_DRV_FEATURE_REMOTE:
    case VIR_DRV_FEATURE_REMOTE_CLOSE_CALLBACK:
    case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK:
    case VIR_DRV_FEATURE_XML_MIGRATABLE:
5715 5716 5717 5718
    default:
        return 0;
    }
}
5719

5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730
static int
libxlNodeDeviceGetPCIInfo(virNodeDeviceDefPtr def,
                          unsigned *domain,
                          unsigned *bus,
                          unsigned *slot,
                          unsigned *function)
{
    virNodeDevCapsDefPtr cap;

    cap = def->caps;
    while (cap) {
5731
        if (cap->data.type == VIR_NODE_DEV_CAP_PCI_DEV) {
5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744
            *domain   = cap->data.pci_dev.domain;
            *bus      = cap->data.pci_dev.bus;
            *slot     = cap->data.pci_dev.slot;
            *function = cap->data.pci_dev.function;
            break;
        }

        cap = cap->next;
    }

    if (!cap) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("device %s is not a PCI device"), def->name);
C
Chunyan Liu 已提交
5745
        return -1;
5746 5747
    }

C
Chunyan Liu 已提交
5748
    return 0;
5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784
}

static int
libxlNodeDeviceDetachFlags(virNodeDevicePtr dev,
                           const char *driverName,
                           unsigned int flags)
{
    virPCIDevicePtr pci = NULL;
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
    int ret = -1;
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
    libxlDriverPrivatePtr driver = dev->conn->privateData;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;

    virCheckFlags(0, -1);

    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto cleanup;

    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
    if (!def)
        goto cleanup;

    if (virNodeDeviceDetachFlagsEnsureACL(dev->conn, def) < 0)
        goto cleanup;

    if (libxlNodeDeviceGetPCIInfo(def, &domain, &bus, &slot, &function) < 0)
        goto cleanup;

    pci = virPCIDeviceNew(domain, bus, slot, function);
    if (!pci)
        goto cleanup;

    if (!driverName || STREQ(driverName, "xen")) {
5785
        virPCIDeviceSetStubDriver(pci, VIR_PCI_STUB_DRIVER_XEN);
5786 5787 5788 5789 5790 5791 5792 5793 5794 5795
    } else {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported driver name '%s'"), driverName);
        goto cleanup;
    }

    if (virHostdevPCINodeDeviceDetach(hostdev_mgr, pci) < 0)
        goto cleanup;

    ret = 0;
5796
 cleanup:
5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838
    virPCIDeviceFree(pci);
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
libxlNodeDeviceDettach(virNodeDevicePtr dev)
{
    return libxlNodeDeviceDetachFlags(dev, NULL, 0);
}

static int
libxlNodeDeviceReAttach(virNodeDevicePtr dev)
{
    virPCIDevicePtr pci = NULL;
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
    int ret = -1;
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
    libxlDriverPrivatePtr driver = dev->conn->privateData;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;

    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto cleanup;

    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
    if (!def)
        goto cleanup;

    if (virNodeDeviceReAttachEnsureACL(dev->conn, def) < 0)
        goto cleanup;

    if (libxlNodeDeviceGetPCIInfo(def, &domain, &bus, &slot, &function) < 0)
        goto cleanup;

    pci = virPCIDeviceNew(domain, bus, slot, function);
    if (!pci)
        goto cleanup;

    if (virHostdevPCINodeDeviceReAttach(hostdev_mgr, pci) < 0)
C
Chunyan Liu 已提交
5839
        goto cleanup;
5840 5841

    ret = 0;
C
Chunyan Liu 已提交
5842

5843
 cleanup:
C
Chunyan Liu 已提交
5844
    virPCIDeviceFree(pci);
5845 5846 5847 5848 5849 5850 5851 5852
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
libxlNodeDeviceReset(virNodeDevicePtr dev)
{
C
Chunyan Liu 已提交
5853
    virPCIDevicePtr pci = NULL;
5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
    int ret = -1;
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
    libxlDriverPrivatePtr driver = dev->conn->privateData;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;

    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto cleanup;

    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
    if (!def)
        goto cleanup;

    if (virNodeDeviceResetEnsureACL(dev->conn, def) < 0)
        goto cleanup;

    if (libxlNodeDeviceGetPCIInfo(def, &domain, &bus, &slot, &function) < 0)
        goto cleanup;

    pci = virPCIDeviceNew(domain, bus, slot, function);
    if (!pci)
        goto cleanup;

    if (virHostdevPCINodeDeviceReset(hostdev_mgr, pci) < 0)
C
Chunyan Liu 已提交
5880
        goto cleanup;
5881 5882

    ret = 0;
C
Chunyan Liu 已提交
5883

5884
 cleanup:
C
Chunyan Liu 已提交
5885
    virPCIDeviceFree(pci);
5886 5887 5888 5889 5890
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

J
Jim Fehlig 已提交
5891 5892 5893 5894
static char *
libxlDomainMigrateBegin3Params(virDomainPtr domain,
                               virTypedParameterPtr params,
                               int nparams,
5895 5896
                               char **cookieout,
                               int *cookieoutlen,
J
Jim Fehlig 已提交
5897 5898 5899 5900
                               unsigned int flags)
{
    const char *xmlin = NULL;
    virDomainObjPtr vm = NULL;
5901
    char *xmlout = NULL;
J
Jim Fehlig 已提交
5902

5903 5904 5905 5906 5907
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return NULL;
#endif

J
Jim Fehlig 已提交
5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919
    virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        return NULL;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_XML,
                                &xmlin) < 0)
        return NULL;

    if (!(vm = libxlDomObjFromDomain(domain)))
        return NULL;

J
Jim Fehlig 已提交
5920
    if (STREQ_NULLABLE(vm->def->name, "Domain-0")) {
5921 5922 5923
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain-0 cannot be migrated"));
        goto cleanup;
J
Jim Fehlig 已提交
5924 5925
    }

5926 5927
    if (virDomainMigrateBegin3ParamsEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;
J
Jim Fehlig 已提交
5928

5929
    if (virDomainObjCheckActive(vm) < 0)
5930
        goto cleanup;
J
Jim Fehlig 已提交
5931

5932 5933
    xmlout = libxlDomainMigrationSrcBegin(domain->conn, vm, xmlin,
                                          cookieout, cookieoutlen);
5934 5935 5936 5937

 cleanup:
    virDomainObjEndAPI(&vm);
    return xmlout;
J
Jim Fehlig 已提交
5938 5939
}

B
Bob Liu 已提交
5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977
static int
libxlDomainMigratePrepareTunnel3Params(virConnectPtr dconn,
                                       virStreamPtr st,
                                       virTypedParameterPtr params,
                                       int nparams,
                                       const char *cookiein,
                                       int cookieinlen,
                                       char **cookieout ATTRIBUTE_UNUSED,
                                       int *cookieoutlen ATTRIBUTE_UNUSED,
                                       unsigned int flags)
{
    libxlDriverPrivatePtr driver = dconn->privateData;
    virDomainDefPtr def = NULL;
    const char *dom_xml = NULL;
    const char *dname = NULL;
    const char *uri_in = NULL;

#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

    virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        goto error;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_XML,
                                &dom_xml) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_NAME,
                                &dname) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_URI,
                                &uri_in) < 0)

        goto error;

5978
    if (!(def = libxlDomainMigrationDstPrepareDef(driver, dom_xml, dname)))
B
Bob Liu 已提交
5979 5980 5981 5982 5983
        goto error;

    if (virDomainMigratePrepareTunnel3ParamsEnsureACL(dconn, def) < 0)
        goto error;

5984 5985
    if (libxlDomainMigrationDstPrepareTunnel3(dconn, st, &def, cookiein,
                                              cookieinlen, flags) < 0)
B
Bob Liu 已提交
5986 5987 5988 5989 5990 5991 5992 5993 5994
        goto error;

    return 0;

 error:
    virDomainDefFree(def);
    return -1;
}

J
Jim Fehlig 已提交
5995 5996 5997 5998
static int
libxlDomainMigratePrepare3Params(virConnectPtr dconn,
                                 virTypedParameterPtr params,
                                 int nparams,
5999 6000
                                 const char *cookiein,
                                 int cookieinlen,
J
Jim Fehlig 已提交
6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011
                                 char **cookieout ATTRIBUTE_UNUSED,
                                 int *cookieoutlen ATTRIBUTE_UNUSED,
                                 char **uri_out,
                                 unsigned int flags)
{
    libxlDriverPrivatePtr driver = dconn->privateData;
    virDomainDefPtr def = NULL;
    const char *dom_xml = NULL;
    const char *dname = NULL;
    const char *uri_in = NULL;

6012 6013 6014 6015 6016
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032
    virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        goto error;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_XML,
                                &dom_xml) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_NAME,
                                &dname) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_URI,
                                &uri_in) < 0)

        goto error;

6033
    if (!(def = libxlDomainMigrationDstPrepareDef(driver, dom_xml, dname)))
J
Jim Fehlig 已提交
6034 6035 6036 6037 6038
        goto error;

    if (virDomainMigratePrepare3ParamsEnsureACL(dconn, def) < 0)
        goto error;

6039 6040
    if (libxlDomainMigrationDstPrepare(dconn, &def, uri_in, uri_out,
                                       cookiein, cookieinlen, flags) < 0)
J
Jim Fehlig 已提交
6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067
        goto error;

    return 0;

 error:
    virDomainDefFree(def);
    return -1;
}

static int
libxlDomainMigratePerform3Params(virDomainPtr dom,
                                 const char *dconnuri,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 const char *cookiein ATTRIBUTE_UNUSED,
                                 int cookieinlen ATTRIBUTE_UNUSED,
                                 char **cookieout ATTRIBUTE_UNUSED,
                                 int *cookieoutlen ATTRIBUTE_UNUSED,
                                 unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    const char *dom_xml = NULL;
    const char *dname = NULL;
    const char *uri = NULL;
    int ret = -1;

6068 6069 6070 6071 6072
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094
    virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        goto cleanup;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_XML,
                                &dom_xml) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_NAME,
                                &dname) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_URI,
                                &uri) < 0)

        goto cleanup;

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainMigratePerform3ParamsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

B
Bob Liu 已提交
6095
    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
6096 6097
        if (libxlDomainMigrationSrcPerformP2P(driver, vm, dom->conn, dom_xml,
                                              dconnuri, uri, dname, flags) < 0)
J
Joao Martins 已提交
6098 6099
            goto cleanup;
    } else {
6100 6101
        if (libxlDomainMigrationSrcPerform(driver, vm, dom_xml, dconnuri,
                                           uri, dname, flags) < 0)
J
Joao Martins 已提交
6102 6103
            goto cleanup;
    }
J
Jim Fehlig 已提交
6104 6105 6106 6107

    ret = 0;

 cleanup:
6108
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125
    return ret;
}

static virDomainPtr
libxlDomainMigrateFinish3Params(virConnectPtr dconn,
                                virTypedParameterPtr params,
                                int nparams,
                                const char *cookiein ATTRIBUTE_UNUSED,
                                int cookieinlen ATTRIBUTE_UNUSED,
                                char **cookieout ATTRIBUTE_UNUSED,
                                int *cookieoutlen ATTRIBUTE_UNUSED,
                                unsigned int flags,
                                int cancelled)
{
    libxlDriverPrivatePtr driver = dconn->privateData;
    virDomainObjPtr vm = NULL;
    const char *dname = NULL;
6126
    virDomainPtr ret = NULL;
J
Jim Fehlig 已提交
6127

6128 6129 6130 6131 6132
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return NULL;
#endif

J
Jim Fehlig 已提交
6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152
    virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        return NULL;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_NAME,
                                &dname) < 0)
        return NULL;

    if (!dname ||
        !(vm = virDomainObjListFindByName(driver->domains, dname))) {
        /* Migration obviously failed if the domain doesn't exist */
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Migration failed. No domain on destination host "
                         "with matching name '%s'"),
                       NULLSTR(dname));
        return NULL;
    }

    if (virDomainMigrateFinish3ParamsEnsureACL(dconn, vm->def) < 0) {
6153
        virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
6154 6155 6156
        return NULL;
    }

6157
    ret = libxlDomainMigrationDstFinish(dconn, vm, flags, cancelled);
6158

6159
    virDomainObjEndAPI(&vm);
6160 6161

    return ret;
J
Jim Fehlig 已提交
6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174
}

static int
libxlDomainMigrateConfirm3Params(virDomainPtr domain,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 const char *cookiein ATTRIBUTE_UNUSED,
                                 int cookieinlen ATTRIBUTE_UNUSED,
                                 unsigned int flags,
                                 int cancelled)
{
    libxlDriverPrivatePtr driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
6175
    int ret = -1;
J
Jim Fehlig 已提交
6176

6177 6178 6179 6180 6181
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
6182 6183 6184 6185 6186 6187 6188
    virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        return -1;

    if (!(vm = libxlDomObjFromDomain(domain)))
        return -1;

6189 6190
    if (virDomainMigrateConfirm3ParamsEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;
J
Jim Fehlig 已提交
6191

6192
    ret = libxlDomainMigrationSrcConfirm(driver, vm, flags, cancelled);
6193 6194 6195 6196

 cleanup:
    virDomainObjEndAPI(&vm);
    return ret;
J
Jim Fehlig 已提交
6197 6198
}

6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215
static int libxlNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
{
    memset(secmodel, 0, sizeof(*secmodel));

    if (virNodeGetSecurityModelEnsureACL(conn) < 0)
        return -1;

    /*
     * Currently the libxl driver does not support security model.
     * Similar to the qemu driver, treat this as success and simply
     * return no data in secmodel.  Avoids spamming the libvirt log
     * with "this function is not supported by the connection driver:
     * virNodeGetSecurityModel"
     */
    return 0;
}
6216

6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331
static int
libxlGetDHCPInterfaces(virDomainPtr dom,
                       virDomainObjPtr vm,
                       virDomainInterfacePtr **ifaces)
{
    int rv = -1;
    int n_leases = 0;
    size_t i, j;
    size_t ifaces_count = 0;
    virNetworkPtr network = NULL;
    char macaddr[VIR_MAC_STRING_BUFLEN];
    virDomainInterfacePtr iface = NULL;
    virNetworkDHCPLeasePtr *leases = NULL;
    virDomainInterfacePtr *ifaces_ret = NULL;

    if (!dom->conn->networkDriver ||
        !dom->conn->networkDriver->networkGetDHCPLeases) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Network driver does not support DHCP lease query"));
        return -1;
    }

    for (i = 0; i < vm->def->nnets; i++) {
        if (vm->def->nets[i]->type != VIR_DOMAIN_NET_TYPE_NETWORK)
            continue;

        virMacAddrFormat(&(vm->def->nets[i]->mac), macaddr);
        virObjectUnref(network);
        network = virNetworkLookupByName(dom->conn,
                                         vm->def->nets[i]->data.network.name);

        if ((n_leases = virNetworkGetDHCPLeases(network, macaddr,
                                                &leases, 0)) < 0)
            goto error;

        if (n_leases) {
            if (VIR_EXPAND_N(ifaces_ret, ifaces_count, 1) < 0)
                goto error;

            if (VIR_ALLOC(ifaces_ret[ifaces_count - 1]) < 0)
                goto error;

            iface = ifaces_ret[ifaces_count - 1];
            /* Assuming each lease corresponds to a separate IP */
            iface->naddrs = n_leases;

            if (VIR_ALLOC_N(iface->addrs, iface->naddrs) < 0)
                goto error;

            if (VIR_STRDUP(iface->name, vm->def->nets[i]->ifname) < 0)
                goto cleanup;

            if (VIR_STRDUP(iface->hwaddr, macaddr) < 0)
                goto cleanup;
        }

        for (j = 0; j < n_leases; j++) {
            virNetworkDHCPLeasePtr lease = leases[j];
            virDomainIPAddressPtr ip_addr = &iface->addrs[j];

            if (VIR_STRDUP(ip_addr->addr, lease->ipaddr) < 0)
                goto cleanup;

            ip_addr->type = lease->type;
            ip_addr->prefix = lease->prefix;
        }

        for (j = 0; j < n_leases; j++)
            virNetworkDHCPLeaseFree(leases[j]);

        VIR_FREE(leases);
    }

    *ifaces = ifaces_ret;
    ifaces_ret = NULL;
    rv = ifaces_count;

 cleanup:
    virObjectUnref(network);
    if (leases) {
        for (i = 0; i < n_leases; i++)
            virNetworkDHCPLeaseFree(leases[i]);
    }
    VIR_FREE(leases);

    return rv;

 error:
    if (ifaces_ret) {
        for (i = 0; i < ifaces_count; i++)
            virDomainInterfaceFree(ifaces_ret[i]);
    }
    VIR_FREE(ifaces_ret);

    goto cleanup;
}


static int
libxlDomainInterfaceAddresses(virDomainPtr dom,
                              virDomainInterfacePtr **ifaces,
                              unsigned int source,
                              unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainInterfaceAddressesEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

6332
    if (virDomainObjCheckActive(vm) < 0)
6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352
        goto cleanup;

    switch (source) {
    case VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE:
        ret = libxlGetDHCPInterfaces(dom, vm, ifaces);
        break;

    default:
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
                       _("Unsupported IP address data source %d"),
                       source);
        break;
    }

 cleanup:
    virDomainObjEndAPI(&vm);
    return ret;
}


6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400
static char *
libxlConnectGetDomainCapabilities(virConnectPtr conn,
                                  const char *emulatorbin,
                                  const char *arch_str,
                                  const char *machine,
                                  const char *virttype_str,
                                  unsigned int flags)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    libxlDriverConfigPtr cfg;
    char *ret = NULL;
    int virttype = VIR_DOMAIN_VIRT_XEN;
    virDomainCapsPtr domCaps = NULL;
    int arch = virArchFromHost(); /* virArch */

    virCheckFlags(0, ret);

    if (virConnectGetDomainCapabilitiesEnsureACL(conn) < 0)
        return ret;

    cfg = libxlDriverConfigGet(driver);

    if (virttype_str &&
        (virttype = virDomainVirtTypeFromString(virttype_str)) < 0) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown virttype: %s"),
                       virttype_str);
        goto cleanup;
    }

    if (virttype != VIR_DOMAIN_VIRT_XEN) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown virttype: %s"),
                       virttype_str);
        goto cleanup;
    }

    if (arch_str && (arch = virArchFromString(arch_str)) == VIR_ARCH_NONE) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown architecture: %s"),
                       arch_str);
        goto cleanup;
    }

    if (emulatorbin == NULL)
        emulatorbin = "/usr/bin/qemu-system-x86_64";

    if (machine) {
6401 6402 6403
        if (STRNEQ(machine, "xenpv") &&
            STRNEQ(machine, "xenpvh") &&
            STRNEQ(machine, "xenfv")) {
6404
            virReportError(VIR_ERR_INVALID_ARG, "%s",
6405
                           _("Xen only supports 'xenpv', 'xenpvh' and 'xenfv' machines"));
6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427
            goto cleanup;
        }
    } else {
        machine = "xenpv";
    }

    if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype)))
        goto cleanup;

    if (libxlMakeDomainCapabilities(domCaps, cfg->firmwares,
                                    cfg->nfirmwares) < 0)
        goto cleanup;

    ret = virDomainCapsFormat(domCaps);

 cleanup:
    virObjectUnref(domCaps);
    virObjectUnref(cfg);
    return ret;
}


6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447
static int
libxlConnectCompareCPU(virConnectPtr conn,
                       const char *xmlDesc,
                       unsigned int flags)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    libxlDriverConfigPtr cfg;
    int ret = VIR_CPU_COMPARE_ERROR;
    bool failIncompatible;

    virCheckFlags(VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE,
                  VIR_CPU_COMPARE_ERROR);

    if (virConnectCompareCPUEnsureACL(conn) < 0)
        return ret;

    failIncompatible = !!(flags & VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE);

    cfg = libxlDriverConfigGet(driver);

J
Jiri Denemark 已提交
6448 6449
    ret = virCPUCompareXML(cfg->caps->host.arch, cfg->caps->host.cpu,
                           xmlDesc, failIncompatible);
6450 6451 6452 6453 6454

    virObjectUnref(cfg);
    return ret;
}

6455 6456 6457 6458 6459 6460
static char *
libxlConnectBaselineCPU(virConnectPtr conn,
                        const char **xmlCPUs,
                        unsigned int ncpus,
                        unsigned int flags)
{
J
Jiri Denemark 已提交
6461 6462 6463
    virCPUDefPtr *cpus = NULL;
    virCPUDefPtr cpu = NULL;
    char *cpustr = NULL;
6464 6465 6466 6467 6468 6469 6470

    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL);

    if (virConnectBaselineCPUEnsureACL(conn) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
6471 6472 6473
    if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST)))
        goto cleanup;

6474
    if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, NULL,
6475
                               !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE))))
J
Jiri Denemark 已提交
6476 6477 6478 6479 6480 6481
        goto cleanup;

    if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) &&
        virCPUExpandFeatures(cpus[0]->arch, cpu) < 0)
        goto cleanup;

6482
    cpustr = virCPUDefFormat(cpu, NULL);
6483 6484

 cleanup:
J
Jiri Denemark 已提交
6485 6486 6487 6488
    virCPUDefListFree(cpus);
    virCPUDefFree(cpu);

    return cpustr;
6489 6490
}

6491
static virHypervisorDriver libxlHypervisorDriver = {
6492
    .name = LIBXL_DRIVER_NAME,
6493
    .connectURIProbe = libxlConnectURIProbe,
6494 6495 6496 6497
    .connectOpen = libxlConnectOpen, /* 0.9.0 */
    .connectClose = libxlConnectClose, /* 0.9.0 */
    .connectGetType = libxlConnectGetType, /* 0.9.0 */
    .connectGetVersion = libxlConnectGetVersion, /* 0.9.0 */
6498
    .connectGetHostname = libxlConnectGetHostname, /* 0.9.0 */
6499
    .connectGetSysinfo = libxlConnectGetSysinfo, /* 1.1.0 */
6500
    .connectGetMaxVcpus = libxlConnectGetMaxVcpus, /* 0.9.0 */
6501
    .nodeGetInfo = libxlNodeGetInfo, /* 0.9.0 */
6502 6503 6504 6505
    .connectGetCapabilities = libxlConnectGetCapabilities, /* 0.9.0 */
    .connectListDomains = libxlConnectListDomains, /* 0.9.0 */
    .connectNumOfDomains = libxlConnectNumOfDomains, /* 0.9.0 */
    .connectListAllDomains = libxlConnectListAllDomains, /* 0.9.13 */
6506 6507 6508 6509 6510 6511 6512
    .domainCreateXML = libxlDomainCreateXML, /* 0.9.0 */
    .domainLookupByID = libxlDomainLookupByID, /* 0.9.0 */
    .domainLookupByUUID = libxlDomainLookupByUUID, /* 0.9.0 */
    .domainLookupByName = libxlDomainLookupByName, /* 0.9.0 */
    .domainSuspend = libxlDomainSuspend, /* 0.9.0 */
    .domainResume = libxlDomainResume, /* 0.9.0 */
    .domainShutdown = libxlDomainShutdown, /* 0.9.0 */
6513
    .domainShutdownFlags = libxlDomainShutdownFlags, /* 0.9.10 */
6514 6515
    .domainReboot = libxlDomainReboot, /* 0.9.0 */
    .domainDestroy = libxlDomainDestroy, /* 0.9.0 */
6516
    .domainDestroyFlags = libxlDomainDestroyFlags, /* 0.9.4 */
6517 6518 6519 6520
#ifdef LIBXL_HAVE_DOMAIN_SUSPEND_ONLY
    .domainPMSuspendForDuration = libxlDomainPMSuspendForDuration, /* 4.8.0 */
#endif
    .domainPMWakeup = libxlDomainPMWakeup, /* 4.8.0 */
6521 6522
    .domainGetOSType = libxlDomainGetOSType, /* 0.9.0 */
    .domainGetMaxMemory = libxlDomainGetMaxMemory, /* 0.9.0 */
6523
    .domainSetMaxMemory = libxlDomainSetMaxMemory, /* 0.9.2 */
6524 6525 6526 6527
    .domainSetMemory = libxlDomainSetMemory, /* 0.9.0 */
    .domainSetMemoryFlags = libxlDomainSetMemoryFlags, /* 0.9.0 */
    .domainGetInfo = libxlDomainGetInfo, /* 0.9.0 */
    .domainGetState = libxlDomainGetState, /* 0.9.2 */
6528
    .domainSave = libxlDomainSave, /* 0.9.2 */
6529
    .domainSaveFlags = libxlDomainSaveFlags, /* 0.9.4 */
6530
    .domainRestore = libxlDomainRestore, /* 0.9.2 */
6531
    .domainRestoreFlags = libxlDomainRestoreFlags, /* 0.9.4 */
6532
    .domainCoreDump = libxlDomainCoreDump, /* 0.9.2 */
6533 6534 6535
    .domainSetVcpus = libxlDomainSetVcpus, /* 0.9.0 */
    .domainSetVcpusFlags = libxlDomainSetVcpusFlags, /* 0.9.0 */
    .domainGetVcpusFlags = libxlDomainGetVcpusFlags, /* 0.9.0 */
6536
    .domainGetMaxVcpus = libxlDomainGetMaxVcpus, /* 3.0.0 */
6537
    .domainPinVcpu = libxlDomainPinVcpu, /* 0.9.0 */
6538
    .domainPinVcpuFlags = libxlDomainPinVcpuFlags, /* 1.2.1 */
6539
    .domainGetVcpus = libxlDomainGetVcpus, /* 0.9.0 */
6540
    .domainGetVcpuPinInfo = libxlDomainGetVcpuPinInfo, /* 1.2.1 */
6541
    .domainGetXMLDesc = libxlDomainGetXMLDesc, /* 0.9.0 */
6542 6543 6544 6545
    .connectDomainXMLFromNative = libxlConnectDomainXMLFromNative, /* 0.9.0 */
    .connectDomainXMLToNative = libxlConnectDomainXMLToNative, /* 0.9.0 */
    .connectListDefinedDomains = libxlConnectListDefinedDomains, /* 0.9.0 */
    .connectNumOfDefinedDomains = libxlConnectNumOfDefinedDomains, /* 0.9.0 */
6546 6547 6548
    .domainCreate = libxlDomainCreate, /* 0.9.0 */
    .domainCreateWithFlags = libxlDomainCreateWithFlags, /* 0.9.0 */
    .domainDefineXML = libxlDomainDefineXML, /* 0.9.0 */
6549
    .domainDefineXMLFlags = libxlDomainDefineXMLFlags, /* 1.2.12 */
6550
    .domainUndefine = libxlDomainUndefine, /* 0.9.0 */
6551
    .domainUndefineFlags = libxlDomainUndefineFlags, /* 0.9.4 */
6552 6553 6554 6555 6556
    .domainAttachDevice = libxlDomainAttachDevice, /* 0.9.2 */
    .domainAttachDeviceFlags = libxlDomainAttachDeviceFlags, /* 0.9.2 */
    .domainDetachDevice = libxlDomainDetachDevice,    /* 0.9.2 */
    .domainDetachDeviceFlags = libxlDomainDetachDeviceFlags, /* 0.9.2 */
    .domainUpdateDeviceFlags = libxlDomainUpdateDeviceFlags, /* 0.9.2 */
6557 6558 6559 6560
    .domainGetAutostart = libxlDomainGetAutostart, /* 0.9.0 */
    .domainSetAutostart = libxlDomainSetAutostart, /* 0.9.0 */
    .domainGetSchedulerType = libxlDomainGetSchedulerType, /* 0.9.0 */
    .domainGetSchedulerParameters = libxlDomainGetSchedulerParameters, /* 0.9.0 */
6561
    .domainGetSchedulerParametersFlags = libxlDomainGetSchedulerParametersFlags, /* 0.9.2 */
6562
    .domainSetSchedulerParameters = libxlDomainSetSchedulerParameters, /* 0.9.0 */
6563
    .domainSetSchedulerParametersFlags = libxlDomainSetSchedulerParametersFlags, /* 0.9.2 */
6564 6565 6566
#ifdef LIBXL_HAVE_DOMAIN_NODEAFFINITY
    .domainGetNumaParameters = libxlDomainGetNumaParameters, /* 1.1.1 */
#endif
6567
    .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
6568
    .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
6569
    .domainGetJobInfo = libxlDomainGetJobInfo, /* 1.3.1 */
6570
    .domainGetJobStats = libxlDomainGetJobStats, /* 1.3.1 */
P
Pavel Hrdina 已提交
6571 6572
    .domainMemoryStats = libxlDomainMemoryStats, /* 1.3.0 */
    .domainGetCPUStats = libxlDomainGetCPUStats, /* 1.3.0 */
6573
    .domainInterfaceStats = libxlDomainInterfaceStats, /* 1.3.2 */
6574 6575
    .domainBlockStats = libxlDomainBlockStats, /* 2.1.0 */
    .domainBlockStatsFlags = libxlDomainBlockStatsFlags, /* 2.1.0 */
6576 6577
    .connectDomainEventRegister = libxlConnectDomainEventRegister, /* 0.9.0 */
    .connectDomainEventDeregister = libxlConnectDomainEventDeregister, /* 0.9.0 */
6578 6579 6580
    .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */
    .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.2 */
    .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.2 */
B
Bamvor Jian Zhang 已提交
6581
    .domainOpenConsole = libxlDomainOpenConsole, /* 1.1.2 */
6582 6583 6584
    .domainIsActive = libxlDomainIsActive, /* 0.9.0 */
    .domainIsPersistent = libxlDomainIsPersistent, /* 0.9.0 */
    .domainIsUpdated = libxlDomainIsUpdated, /* 0.9.0 */
6585 6586 6587
    .connectDomainEventRegisterAny = libxlConnectDomainEventRegisterAny, /* 0.9.0 */
    .connectDomainEventDeregisterAny = libxlConnectDomainEventDeregisterAny, /* 0.9.0 */
    .connectIsAlive = libxlConnectIsAlive, /* 0.9.8 */
6588
    .connectSupportsFeature = libxlConnectSupportsFeature, /* 1.1.1 */
6589 6590 6591 6592
    .nodeDeviceDettach = libxlNodeDeviceDettach, /* 1.2.3 */
    .nodeDeviceDetachFlags = libxlNodeDeviceDetachFlags, /* 1.2.3 */
    .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.2.3 */
    .nodeDeviceReset = libxlNodeDeviceReset, /* 1.2.3 */
6593 6594
    .domainMigrateBegin3Params = libxlDomainMigrateBegin3Params, /* 1.2.6 */
    .domainMigratePrepare3Params = libxlDomainMigratePrepare3Params, /* 1.2.6 */
B
Bob Liu 已提交
6595
    .domainMigratePrepareTunnel3Params = libxlDomainMigratePrepareTunnel3Params, /* 3.1.0 */
6596 6597 6598
    .domainMigratePerform3Params = libxlDomainMigratePerform3Params, /* 1.2.6 */
    .domainMigrateFinish3Params = libxlDomainMigrateFinish3Params, /* 1.2.6 */
    .domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.6 */
6599
    .nodeGetSecurityModel = libxlNodeGetSecurityModel, /* 1.2.16 */
6600
    .domainInterfaceAddresses = libxlDomainInterfaceAddresses, /* 1.3.5 */
6601
    .connectGetDomainCapabilities = libxlConnectGetDomainCapabilities, /* 2.0.0 */
6602
    .connectCompareCPU = libxlConnectCompareCPU, /* 2.3.0 */
6603
    .connectBaselineCPU = libxlConnectBaselineCPU, /* 2.3.0 */
J
Jim Fehlig 已提交
6604 6605
};

6606
static virConnectDriver libxlConnectDriver = {
6607
    .localOnly = true,
6608
    .uriSchemes = (const char *[]){ "xen", NULL },
6609 6610 6611
    .hypervisorDriver = &libxlHypervisorDriver,
};

J
Jim Fehlig 已提交
6612 6613
static virStateDriver libxlStateDriver = {
    .name = "LIBXL",
6614
    .stateInitialize = libxlStateInitialize,
6615
    .stateAutoStart = libxlStateAutoStart,
6616 6617
    .stateCleanup = libxlStateCleanup,
    .stateReload = libxlStateReload,
J
Jim Fehlig 已提交
6618 6619 6620 6621 6622 6623
};


int
libxlRegister(void)
{
6624 6625
    if (virRegisterConnectDriver(&libxlConnectDriver,
                                 true) < 0)
J
Jim Fehlig 已提交
6626 6627 6628 6629 6630 6631
        return -1;
    if (virRegisterStateDriver(&libxlStateDriver) < 0)
        return -1;

    return 0;
}