libxl_driver.c 195.1 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/>.
J
Jim Fehlig 已提交
21 22 23 24
 */

#include <config.h>

25
#include <math.h>
J
Jim Fehlig 已提交
26
#include <libxl.h>
27
#include <libxl_utils.h>
28
#include <xenstore.h>
29
#include <fcntl.h>
30
#include <regex.h>
J
Jim Fehlig 已提交
31 32

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

#define VIR_FROM_THIS VIR_FROM_LIBXL

63 64
VIR_LOG_INIT("libxl.libxl_driver");

J
Jim Fehlig 已提交
65 66 67 68 69 70
#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

71
#define LIBXL_NB_TOTAL_CPU_STAT_PARAM 1
72
#define LIBXL_NB_TOTAL_BLK_STAT_PARAM 6
73

74
#define HYPERVISOR_CAPABILITIES "/proc/xen/capabilities"
R
Roman Bogorodskiy 已提交
75
#define HYPERVISOR_XENSTORED "/dev/xen/xenstored"
76

77 78 79
/* Number of Xen scheduler parameters */
#define XEN_SCHED_CREDIT_NPARAM   2

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

89

90
static libxlDriverPrivatePtr libxl_driver;
J
Jim Fehlig 已提交
91

92 93 94 95 96 97 98 99 100
/* 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;
};

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
/* 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 已提交
120
/* Function declarations */
121 122
static int
libxlDomainManagedSaveLoad(virDomainObjPtr vm,
123 124
                           void *opaque);

J
Jim Fehlig 已提交
125 126

/* Function definitions */
127 128 129 130 131 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
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 已提交
304 305 306 307 308 309 310
static virDomainObjPtr
libxlDomObjFromDomain(virDomainPtr dom)
{
    virDomainObjPtr vm;
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

311
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
J
Jim Fehlig 已提交
312 313 314 315 316 317 318 319 320 321 322
    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;
}

323 324
static int
libxlAutostartDomain(virDomainObjPtr vm,
325 326 327
                     void *opaque)
{
    libxlDriverPrivatePtr driver = opaque;
328
    int ret = -1;
329

W
Wang Yufei 已提交
330
    virObjectRef(vm);
331
    virObjectLock(vm);
332 333
    virResetLastError();

W
Wang Yufei 已提交
334 335
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;
336

337
    if (vm->autostart && !virDomainObjIsActive(vm) &&
338
        libxlDomainStartNew(driver, vm, false) < 0) {
339 340 341
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to autostart VM '%s': %s"),
                       vm->def->name, virGetLastErrorMessage());
342
        goto endjob;
343 344
    }

345
    ret = 0;
346 347

 endjob:
W
Wang Yufei 已提交
348 349 350
    libxlDomainObjEndJob(driver, vm);
 cleanup:
    virDomainObjEndAPI(&vm);
351

352
    return ret;
353 354
}

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

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

378
    virObjectRef(vm);
379
    virObjectLock(vm);
J
Jim Fehlig 已提交
380

381 382
    libxl_dominfo_init(&d_info);

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

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

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

403 404
    libxlLoggerOpenFile(cfg->logger, vm->def->id, vm->def->name, NULL);

405
    /* Update hostdev state */
406
    if (virHostdevUpdateActiveDomainDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
407
                                            vm->def, hostdev_flags) < 0)
408
        goto error;
409

410 411 412 413 414 415 416 417 418 419 420
    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);

421
    if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback)
422 423
        driver->inhibitCallback(true, driver->inhibitOpaque);

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

C
Cédric Bosdonnat 已提交
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
    /* 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;
        }
    }

448 449 450
    ret = 0;

 cleanup:
451
    libxl_dominfo_dispose(&d_info);
452
    virObjectUnlock(vm);
453
    virObjectUnref(vm);
J
Jim Fehlig 已提交
454
    virObjectUnref(cfg);
455
    return ret;
J
Jim Fehlig 已提交
456

457
 error:
458
    libxlDomainCleanup(driver, vm);
459
    if (!vm->persistent)
460
        virDomainObjListRemoveLocked(driver->domains, vm);
461
    goto cleanup;
J
Jim Fehlig 已提交
462 463 464 465 466
}

static void
libxlReconnectDomains(libxlDriverPrivatePtr driver)
{
467
    virDomainObjListForEach(driver->domains, libxlReconnectDomain, driver);
J
Jim Fehlig 已提交
468 469 470
}

static int
471
libxlStateCleanup(void)
J
Jim Fehlig 已提交
472 473 474 475
{
    if (!libxl_driver)
        return -1;

476
    virObjectUnref(libxl_driver->hostdevMgr);
477
    virObjectUnref(libxl_driver->config);
478
    virObjectUnref(libxl_driver->xmlopt);
479
    virObjectUnref(libxl_driver->domains);
480 481
    virPortAllocatorRangeFree(libxl_driver->reservedGraphicsPorts);
    virPortAllocatorRangeFree(libxl_driver->migrationPorts);
482
    virLockManagerPluginUnref(libxl_driver->lockManager);
J
Jim Fehlig 已提交
483

484
    virObjectUnref(libxl_driver->domainEventState);
485
    virSysinfoDefFree(libxl_driver->hostsysinfo);
486

J
Jim Fehlig 已提交
487 488 489 490 491 492
    virMutexDestroy(&libxl_driver->lock);
    VIR_FREE(libxl_driver);

    return 0;
}

493 494
static bool
libxlDriverShouldLoad(bool privileged)
495
{
496
    bool ret = false;
J
Jim Fehlig 已提交
497

498
    /* Don't load if non-root */
J
Jim Fehlig 已提交
499
    if (!privileged) {
500
        VIR_INFO("Not running privileged, disabling libxenlight driver");
501
        return ret;
J
Jim Fehlig 已提交
502 503
    }

R
Roman Bogorodskiy 已提交
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
    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");
525 526 527 528
        return ret;
    }

    /* Don't load if legacy xen toolstack (xend) is in use */
529 530 531 532 533 534 535 536 537 538 539
    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);
540 541
    } else {
        ret = true;
J
Jim Fehlig 已提交
542 543
    }

544 545 546
    return ret;
}

547 548 549 550 551 552 553 554 555 556
/* 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,
};

557 558 559 560 561 562 563 564
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
};

565 566 567 568 569 570
const struct libxl_event_hooks ev_hooks = {
    .event_occurs_mask = LIBXL_EVENTMASK_ALL,
    .event_occurs = libxlDomainEventHandler,
    .disaster = NULL,
};

J
Jim Fehlig 已提交
571 572 573 574 575 576 577 578
static int
libxlAddDom0(libxlDriverPrivatePtr driver)
{
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr oldDef = NULL;
    libxl_dominfo d_info;
579
    unsigned long long maxmem;
J
Jim Fehlig 已提交
580 581 582 583 584 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
    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 已提交
611
    vm->persistent = 1;
J
Jim Fehlig 已提交
612
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
613
    if (virDomainDefSetVcpusMax(vm->def, d_info.vcpu_max_id + 1, driver->xmlopt))
614 615
        goto cleanup;

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

    ret = 0;

 cleanup:
    libxl_dominfo_dispose(&d_info);
    virDomainDefFree(def);
    virDomainDefFree(oldDef);
629
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
630 631 632 633
    virObjectUnref(cfg);
    return ret;
}

634 635 636 637 638
static int
libxlStateInitialize(bool privileged,
                     virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                     void *opaque ATTRIBUTE_UNUSED)
{
639
    libxlDriverConfigPtr cfg;
640
    char *driverConf = NULL;
641 642 643 644 645
    char ebuf[1024];

    if (!libxlDriverShouldLoad(privileged))
        return 0;

J
Jim Fehlig 已提交
646 647 648 649
    if (VIR_ALLOC(libxl_driver) < 0)
        return -1;

    if (virMutexInit(&libxl_driver->lock) < 0) {
650 651
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot initialize mutex"));
J
Jim Fehlig 已提交
652 653 654 655 656
        VIR_FREE(libxl_driver);
        return -1;
    }

    /* Allocate bitmap for vnc port reservation */
657
    if (!(libxl_driver->reservedGraphicsPorts =
658 659
          virPortAllocatorRangeNew(_("VNC"),
                                   LIBXL_VNC_PORT_MIN,
660
                                   LIBXL_VNC_PORT_MAX)))
661
        goto error;
J
Jim Fehlig 已提交
662

J
Jim Fehlig 已提交
663 664
    /* Allocate bitmap for migration port reservation */
    if (!(libxl_driver->migrationPorts =
665 666
          virPortAllocatorRangeNew(_("migration"),
                                   LIBXL_MIGRATION_PORT_MIN,
667
                                   LIBXL_MIGRATION_PORT_MAX)))
J
Jim Fehlig 已提交
668 669
        goto error;

670 671
    if (!(libxl_driver->domains = virDomainObjListNew()))
        goto error;
J
Jim Fehlig 已提交
672

673 674 675
    if (!(libxl_driver->hostdevMgr = virHostdevManagerGetDefault()))
        goto error;

676
    if (!(cfg = libxlDriverConfigNew()))
677
        goto error;
J
Jim Fehlig 已提交
678

679 680 681 682 683 684 685
    if (virAsprintf(&driverConf, "%s/libxl.conf", cfg->configBaseDir) < 0)
        goto error;

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

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

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

692 693 694
    /* Register callback to handle domain events */
    libxl_event_register_callbacks(cfg->ctx, &ev_hooks, libxl_driver);

695 696
    libxl_driver->config = cfg;
    if (virFileMakePath(cfg->stateDir) < 0) {
697 698
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create state dir '%s': %s"),
699
                       cfg->stateDir,
700
                       virStrerror(errno, ebuf, sizeof(ebuf)));
J
Jim Fehlig 已提交
701 702
        goto error;
    }
703
    if (virFileMakePath(cfg->libDir) < 0) {
704 705
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create lib dir '%s': %s"),
706
                       cfg->libDir,
707
                       virStrerror(errno, ebuf, sizeof(ebuf)));
J
Jim Fehlig 已提交
708 709
        goto error;
    }
710
    if (virFileMakePath(cfg->saveDir) < 0) {
711 712
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create save dir '%s': %s"),
713
                       cfg->saveDir,
714
                       virStrerror(errno, ebuf, sizeof(ebuf)));
J
Jim Fehlig 已提交
715 716
        goto error;
    }
717 718 719 720 721 722 723
    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 已提交
724 725 726 727 728 729 730
    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 已提交
731

732 733 734 735 736 737 738 739
    if (!(libxl_driver->lockManager =
          virLockManagerPluginNew(cfg->lockManagerName ?
                                  cfg->lockManagerName : "nop",
                                  "libxl",
                                  cfg->configBaseDir,
                                  0)))
        goto error;

740
    /* read the host sysinfo */
741
    libxl_driver->hostsysinfo = virSysinfoRead();
742

743
    libxl_driver->domainEventState = virObjectEventStateNew();
E
Eric Blake 已提交
744
    if (!libxl_driver->domainEventState)
745 746
        goto error;

747
    if ((cfg->caps = libxlMakeCapabilities(cfg->ctx)) == NULL) {
748 749
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot create capabilities for libxenlight"));
J
Jim Fehlig 已提交
750 751 752
        goto error;
    }

753
    if (!(libxl_driver->xmlopt = libxlCreateXMLConf()))
754
        goto error;
J
Jim Fehlig 已提交
755

J
Jim Fehlig 已提交
756 757 758 759
    /* Add Domain-0 */
    if (libxlAddDom0(libxl_driver) < 0)
        goto error;

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

    libxlReconnectDomains(libxl_driver);

    /* Then inactive persistent configs */
773
    if (virDomainObjListLoadAllConfigs(libxl_driver->domains,
774 775
                                       cfg->configDir,
                                       cfg->autostartDir,
776
                                       false,
777
                                       cfg->caps,
778
                                       libxl_driver->xmlopt,
779
                                       NULL, NULL) < 0)
J
Jim Fehlig 已提交
780 781
        goto error;

782 783
    virDomainObjListForEach(libxl_driver->domains, libxlDomainManagedSaveLoad,
                            libxl_driver);
784

J
Jim Fehlig 已提交
785 786
    return 0;

787
 error:
788
    VIR_FREE(driverConf);
789
    libxlStateCleanup();
790
    return -1;
J
Jim Fehlig 已提交
791 792
}

793 794 795 796 797 798 799 800 801 802
static void
libxlStateAutoStart(void)
{
    if (!libxl_driver)
        return;

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

J
Jim Fehlig 已提交
803
static int
804
libxlStateReload(void)
J
Jim Fehlig 已提交
805
{
806 807
    libxlDriverConfigPtr cfg;

J
Jim Fehlig 已提交
808 809 810
    if (!libxl_driver)
        return 0;

811 812
    cfg = libxlDriverConfigGet(libxl_driver);

813
    virDomainObjListLoadAllConfigs(libxl_driver->domains,
814 815
                                   cfg->configDir,
                                   cfg->autostartDir,
816
                                   true,
817
                                   cfg->caps,
818
                                   libxl_driver->xmlopt,
819 820
                                   NULL, libxl_driver);

821 822
    virDomainObjListForEach(libxl_driver->domains, libxlAutostartDomain,
                            libxl_driver);
823

824
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
825 826 827 828
    return 0;
}


829 830 831 832 833 834 835 836 837 838
static int
libxlConnectURIProbe(char **uri)
{
    if (libxl_driver == NULL)
        return 0;

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


J
Jim Fehlig 已提交
839
static virDrvOpenStatus
840 841
libxlConnectOpen(virConnectPtr conn,
                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
842
                 virConfPtr conf ATTRIBUTE_UNUSED,
843
                 unsigned int flags)
J
Jim Fehlig 已提交
844
{
E
Eric Blake 已提交
845 846
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

847 848 849 850 851 852
    /* 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 已提交
853

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

864 865 866
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

J
Jim Fehlig 已提交
867 868 869 870 871 872
    conn->privateData = libxl_driver;

    return VIR_DRV_OPEN_SUCCESS;
};

static int
873
libxlConnectClose(virConnectPtr conn ATTRIBUTE_UNUSED)
J
Jim Fehlig 已提交
874 875 876 877 878 879
{
    conn->privateData = NULL;
    return 0;
}

static const char *
880
libxlConnectGetType(virConnectPtr conn)
J
Jim Fehlig 已提交
881
{
882 883 884
    if (virConnectGetTypeEnsureACL(conn) < 0)
        return NULL;

J
Jim Fehlig 已提交
885
    return "Xen";
J
Jim Fehlig 已提交
886 887 888
}

static int
889
libxlConnectGetVersion(virConnectPtr conn, unsigned long *version)
J
Jim Fehlig 已提交
890 891
{
    libxlDriverPrivatePtr driver = conn->privateData;
892
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
893

894 895 896
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return 0;

897 898 899
    cfg = libxlDriverConfigGet(driver);
    *version = cfg->version;
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
900 901 902
    return 0;
}

903

904
static char *libxlConnectGetHostname(virConnectPtr conn)
905
{
906 907 908
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

909 910 911
    return virGetHostname();
}

912 913 914 915 916 917 918 919
static char *
libxlConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virCheckFlags(0, NULL);

920 921 922
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

923 924 925 926 927 928 929 930
    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;
931
    if (virBufferCheckError(&buf) < 0)
932 933 934
        return NULL;
    return virBufferContentAndReset(&buf);
}
935

J
Jim Fehlig 已提交
936
static int
937
libxlConnectGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED)
J
Jim Fehlig 已提交
938 939 940
{
    int ret;
    libxlDriverPrivatePtr driver = conn->privateData;
941
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
942

943 944 945
    if (virConnectGetMaxVcpusEnsureACL(conn) < 0)
        return -1;

946 947
    cfg = libxlDriverConfigGet(driver);
    ret = libxl_get_max_cpus(cfg->ctx);
948 949 950 951 952
    /* 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)
953
        ret = -1;
J
Jim Fehlig 已提交
954

955
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
956 957 958 959 960 961
    return ret;
}

static int
libxlNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
{
962 963 964
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

965
    return libxlDriverNodeGetInfo(conn->privateData, info);
J
Jim Fehlig 已提交
966 967 968
}

static char *
969
libxlConnectGetCapabilities(virConnectPtr conn)
J
Jim Fehlig 已提交
970 971 972
{
    libxlDriverPrivatePtr driver = conn->privateData;
    char *xml;
973
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
974

975 976 977
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

978
    cfg = libxlDriverConfigGet(driver);
979
    xml = virCapabilitiesFormatXML(cfg->caps);
J
Jim Fehlig 已提交
980

981
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
982 983 984 985
    return xml;
}

static int
986
libxlConnectListDomains(virConnectPtr conn, int *ids, int nids)
J
Jim Fehlig 已提交
987 988 989 990
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

991 992 993
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

994 995
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
J
Jim Fehlig 已提交
996 997 998 999 1000

    return n;
}

static int
1001
libxlConnectNumOfDomains(virConnectPtr conn)
J
Jim Fehlig 已提交
1002 1003 1004 1005
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

1006 1007 1008
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

1009 1010
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
J
Jim Fehlig 已提交
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022

    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;
1023
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1024
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
J
Jim Fehlig 已提交
1025

1026 1027 1028 1029
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
                  VIR_DOMAIN_START_VALIDATE, NULL);

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

1032
    if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt,
1033
                                        NULL, parse_flags)))
J
Jim Fehlig 已提交
1034 1035
        goto cleanup;

1036 1037 1038
    if (virDomainCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

1039
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1040
                                   driver->xmlopt,
1041
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1042 1043
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
J
Jim Fehlig 已提交
1044 1045 1046
        goto cleanup;
    def = NULL;

1047
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) {
1048
        if (!vm->persistent)
1049 1050 1051 1052
            virDomainObjListRemove(driver->domains, vm);
        goto cleanup;
    }

1053 1054
    if (libxlDomainStartNew(driver, vm,
                         (flags & VIR_DOMAIN_START_PAUSED) != 0) < 0) {
1055
        if (!vm->persistent)
1056
            virDomainObjListRemove(driver->domains, vm);
1057
        goto endjob;
J
Jim Fehlig 已提交
1058 1059
    }

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

1062
 endjob:
W
Wang Yufei 已提交
1063
    libxlDomainObjEndJob(driver, vm);
1064

1065
 cleanup:
J
Jim Fehlig 已提交
1066
    virDomainDefFree(def);
W
Wang Yufei 已提交
1067
    virDomainObjEndAPI(&vm);
1068
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
    return dom;
}

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

1079
    vm = virDomainObjListFindByID(driver->domains, id);
J
Jim Fehlig 已提交
1080
    if (!vm) {
1081
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
1082 1083 1084
        goto cleanup;
    }

1085 1086 1087
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

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

1090
 cleanup:
1091
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
    return dom;
}

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

1102
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
J
Jim Fehlig 已提交
1103
    if (!vm) {
1104
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
1105 1106 1107
        goto cleanup;
    }

1108 1109 1110
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

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

1113
 cleanup:
1114
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
    return dom;
}

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

1125
    vm = virDomainObjListFindByName(driver->domains, name);
J
Jim Fehlig 已提交
1126
    if (!vm) {
1127
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
1128 1129 1130
        goto cleanup;
    }

1131 1132 1133
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

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

1136
 cleanup:
1137
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1138 1139 1140
    return dom;
}

1141 1142 1143 1144
static int
libxlDomainSuspend(virDomainPtr dom)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1145
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1146
    virDomainObjPtr vm;
1147
    virObjectEventPtr event = NULL;
1148 1149
    int ret = -1;

J
Jim Fehlig 已提交
1150
    if (!(vm = libxlDomObjFromDomain(dom)))
1151
        goto cleanup;
1152

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

1155 1156 1157
    if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

1161
    if (virDomainObjCheckActive(vm) < 0)
1162
        goto endjob;
1163

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

J
Jiri Denemark 已提交
1172
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
1173

1174
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
1175 1176 1177
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

1178
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
1179
        goto endjob;
1180 1181 1182

    ret = 0;

1183
 endjob:
W
Wang Yufei 已提交
1184
    libxlDomainObjEndJob(driver, vm);
1185

1186
 cleanup:
W
Wang Yufei 已提交
1187
    virDomainObjEndAPI(&vm);
1188
    virObjectEventStateQueue(driver->domainEventState, event);
1189
    virObjectUnref(cfg);
1190 1191 1192 1193 1194 1195 1196 1197
    return ret;
}


static int
libxlDomainResume(virDomainPtr dom)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1198
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1199
    virDomainObjPtr vm;
1200
    virObjectEventPtr event = NULL;
1201 1202
    int ret = -1;

J
Jim Fehlig 已提交
1203
    if (!(vm = libxlDomObjFromDomain(dom)))
1204 1205
        goto cleanup;

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

1208 1209 1210
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

1214
    if (virDomainObjCheckActive(vm) < 0)
1215
        goto endjob;
1216

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

J
Jiri Denemark 已提交
1225 1226
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
1227

1228
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_RESUMED,
1229 1230 1231
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

1232
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
1233
        goto endjob;
1234 1235 1236

    ret = 0;

1237
 endjob:
W
Wang Yufei 已提交
1238
    libxlDomainObjEndJob(driver, vm);
1239

1240
 cleanup:
W
Wang Yufei 已提交
1241
    virDomainObjEndAPI(&vm);
1242
    virObjectEventStateQueue(driver->domainEventState, event);
1243
    virObjectUnref(cfg);
1244 1245 1246
    return ret;
}

J
Jim Fehlig 已提交
1247
static int
1248
libxlDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
1249
{
J
Jim Fehlig 已提交
1250 1251
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1252 1253 1254
    virDomainObjPtr vm;
    int ret = -1;

1255 1256 1257 1258 1259
    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;
1260

J
Jim Fehlig 已提交
1261
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1262 1263
        goto cleanup;

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

1266
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
1267 1268
        goto cleanup;

1269
    if (virDomainObjCheckActive(vm) < 0)
J
Jim Fehlig 已提交
1270 1271
        goto cleanup;

1272
    if (flags & VIR_DOMAIN_SHUTDOWN_PARAVIRT) {
J
Jim Fehlig 已提交
1273
        ret = libxl_domain_shutdown(cfg->ctx, vm->def->id);
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287
        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 已提交
1288
        ret = libxl_send_trigger(cfg->ctx, vm->def->id,
1289 1290 1291 1292
                                 LIBXL_TRIGGER_POWER, 0);
        if (ret == 0)
            goto cleanup;

1293 1294
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to shutdown domain '%d' with libxenlight"),
1295
                       vm->def->id);
1296
        ret = -1;
J
Jim Fehlig 已提交
1297 1298
    }

1299
 cleanup:
1300
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1301
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1302 1303 1304
    return ret;
}

1305 1306 1307 1308 1309 1310 1311
static int
libxlDomainShutdown(virDomainPtr dom)
{
    return libxlDomainShutdownFlags(dom, 0);
}


J
Jim Fehlig 已提交
1312
static int
E
Eric Blake 已提交
1313
libxlDomainReboot(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
1314
{
J
Jim Fehlig 已提交
1315 1316
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1317 1318 1319
    virDomainObjPtr vm;
    int ret = -1;

J
Jim Fehlig 已提交
1320 1321 1322
    virCheckFlags(VIR_DOMAIN_REBOOT_PARAVIRT, -1);
    if (flags == 0)
        flags = VIR_DOMAIN_REBOOT_PARAVIRT;
E
Eric Blake 已提交
1323

J
Jim Fehlig 已提交
1324
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1325 1326
        goto cleanup;

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

1329
    if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
1330 1331
        goto cleanup;

1332
    if (virDomainObjCheckActive(vm) < 0)
J
Jim Fehlig 已提交
1333 1334
        goto cleanup;

J
Jim Fehlig 已提交
1335
    if (flags & VIR_DOMAIN_REBOOT_PARAVIRT) {
J
Jim Fehlig 已提交
1336
        ret = libxl_domain_reboot(cfg->ctx, vm->def->id);
J
Jim Fehlig 已提交
1337 1338 1339
        if (ret == 0)
            goto cleanup;

1340 1341
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to reboot domain '%d' with libxenlight"),
1342
                       vm->def->id);
J
Jim Fehlig 已提交
1343
        ret = -1;
J
Jim Fehlig 已提交
1344 1345
    }

1346
 cleanup:
1347
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1348
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1349 1350 1351 1352
    return ret;
}

static int
1353 1354
libxlDomainDestroyFlags(virDomainPtr dom,
                        unsigned int flags)
J
Jim Fehlig 已提交
1355 1356
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
J
Jim Fehlig 已提交
1357
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1358 1359
    virDomainObjPtr vm;
    int ret = -1;
1360
    virObjectEventPtr event = NULL;
J
Jim Fehlig 已提交
1361

1362 1363
    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
1364
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1365 1366
        goto cleanup;

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

1369 1370 1371
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

1375
    if (virDomainObjCheckActive(vm) < 0)
1376
        goto endjob;
J
Jim Fehlig 已提交
1377

1378
    if (libxlDomainDestroyInternal(driver, vm) < 0) {
1379
        virReportError(VIR_ERR_INTERNAL_ERROR,
1380
                       _("Failed to destroy domain '%d'"), vm->def->id);
1381
        goto endjob;
J
Jim Fehlig 已提交
1382 1383
    }

1384 1385 1386 1387 1388 1389 1390
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
                         VIR_DOMAIN_SHUTOFF_DESTROYED);

    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);

    libxlDomainCleanup(driver, vm);
1391
    if (!vm->persistent)
1392
        virDomainObjListRemove(driver->domains, vm);
J
Jim Fehlig 已提交
1393 1394 1395

    ret = 0;

1396
 endjob:
W
Wang Yufei 已提交
1397
    libxlDomainObjEndJob(driver, vm);
1398

1399
 cleanup:
W
Wang Yufei 已提交
1400
    virDomainObjEndAPI(&vm);
1401
    virObjectEventStateQueue(driver->domainEventState, event);
J
Jim Fehlig 已提交
1402
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1403 1404 1405
    return ret;
}

1406 1407 1408 1409 1410 1411
static int
libxlDomainDestroy(virDomainPtr dom)
{
    return libxlDomainDestroyFlags(dom, 0);
}

1412 1413 1414 1415 1416 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
#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);
1525 1526 1527
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                              VIR_DOMAIN_EVENT_STOPPED_FAILED);
    libxlDomainCleanup(driver, vm);
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537

 endjob:
    libxlDomainObjEndJob(driver, vm);

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

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

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

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

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

1553
 cleanup:
1554
    virDomainObjEndAPI(&vm);
1555 1556 1557
    return type;
}

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

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

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

1570
    ret = virDomainDefGetMemoryTotal(vm->def);
1571

1572
 cleanup:
1573
    virDomainObjEndAPI(&vm);
1574 1575 1576
    return ret;
}

1577 1578 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

/*
 * 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;
}


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

    virCheckFlags(VIR_DOMAIN_MEM_LIVE |
1618 1619
                  VIR_DOMAIN_MEM_CONFIG |
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
1620

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

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

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

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

1634 1635
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */
1636

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

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

1656 1657
    } else {
        /* resize the current memory */
1658

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

        if (flags & VIR_DOMAIN_MEM_LIVE) {
1666 1667 1668 1669
            int res;

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

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

1690 1691
    ret = 0;

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

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

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

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

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

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

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

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

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

        libxl_dominfo_dispose(&d_info);
1745 1746
    }

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

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

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

    virCheckFlags(0, -1);

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

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

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

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

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

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

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

1813
    if ((xml = virDomainDefFormat(vm->def, cfg->caps, 0)) == NULL)
1814 1815 1816 1817 1818 1819 1820 1821 1822
        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)) {
1823 1824
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Failed to write save file header"));
1825 1826 1827 1828
        goto cleanup;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ret = 0;
1913

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

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

1922
static int
1923 1924 1925 1926 1927 1928 1929 1930
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)
1931 1932
{
    libxlDriverPrivatePtr driver = conn->privateData;
1933
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1934 1935 1936 1937 1938
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    libxlSavefileHeader hdr;
    int fd = -1;
    int ret = -1;
1939

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

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

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

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

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

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

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

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

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

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

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

    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH, -1);

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

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

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

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

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

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

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

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

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

    ret = 0;

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

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

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

2087 2088 2089 2090 2091 2092 2093 2094 2095 2096
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 已提交
2097
    if (!(vm = libxlDomObjFromDomain(dom)))
2098 2099
        goto cleanup;

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

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

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

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

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

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

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

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

    ret = 0;
2129

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

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

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

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

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

    vm->hasManagedSave = virFileExists(name);

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

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

    virCheckFlags(0, -1);

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

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

2175
    ret = vm->hasManagedSave;
2176

2177
 cleanup:
2178
    virDomainObjEndAPI(&vm);
2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191
    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 已提交
2192
    if (!(vm = libxlDomObjFromDomain(dom)))
2193 2194
        goto cleanup;

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

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

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

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

2211 2212 2213 2214 2215
static int
libxlDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                         unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
2216
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2217 2218
    virDomainDefPtr def;
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
2219
    libxl_bitmap map;
2220 2221
    uint8_t *bitmask = NULL;
    unsigned int maplen;
2222 2223
    size_t i;
    unsigned int pos;
2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235
    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)) {
2236 2237
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid flag combination: (0x%x)"), flags);
2238 2239 2240 2241
        return -1;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ret = 0;

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

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

2351
 cleanup:
2352
    VIR_FREE(bitmask);
W
Wang Yufei 已提交
2353 2354
    virDomainObjEndAPI(&vm);
    virObjectUnref(cfg);
2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369
    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;
2370
    bool active;
2371 2372 2373 2374 2375

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

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

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

2382 2383 2384 2385 2386 2387 2388 2389 2390
    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)) {
2391 2392
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid flag combination: (0x%x)"), flags);
2393 2394 2395
        return -1;
    }

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

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

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

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

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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
2444

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

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

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

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

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

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

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

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

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

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

2489 2490
    ret = 0;

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

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

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

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

2515 2516 2517 2518 2519 2520 2521 2522 2523
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;
2524
    int ret = -1;
2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538

    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;

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

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

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

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

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

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

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

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

J
Jim Fehlig 已提交
2576
    if ((vcpuinfo = libxl_list_vcpu(cfg->ctx, vm->def->id, &maxcpu,
2577
                                    &hostcpus)) == NULL) {
2578 2579
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to list vcpus for domain '%d' with libxenlight"),
2580
                       vm->def->id);
2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602
        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 已提交
2603
        libxl_vcpuinfo_dispose(&vcpuinfo[i]);
2604 2605 2606 2607 2608
    }
    VIR_FREE(vcpuinfo);

    ret = maxinfo;

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

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

2624
    virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
2625

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    virCheckFlags(VIR_DOMAIN_START_PAUSED, -1);

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

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

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

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

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

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

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

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

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

2844 2845 2846
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

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

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

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

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

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

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

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

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

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

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

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

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

2908 2909
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE, -1);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    virDomainDiskDefFree(disk);

    ret = 0;

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

static int
J
Jim Fehlig 已提交
3023
libxlDomainAttachDeviceDiskLive(virDomainObjPtr vm, virDomainDeviceDefPtr dev)
3024
{
J
Jim Fehlig 已提交
3025
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(libxl_driver);
3026 3027 3028 3029 3030 3031
    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 已提交
3032
            ret = libxlDomainChangeEjectableMedia(vm, l_disk);
3033 3034 3035
            break;
        case VIR_DOMAIN_DISK_DEVICE_DISK:
            if (l_disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
3036
                if (virDomainDiskIndexByName(vm->def, l_disk->dst, true) >= 0) {
3037 3038
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("target %s already exists"), l_disk->dst);
3039 3040 3041
                    goto cleanup;
                }

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

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

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

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

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

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

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

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

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

3105 3106
    libxl_device_pci_init(&pcidev);

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

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

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

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

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

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

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

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

3148
#ifdef LIBXL_HAVE_PVUSB
3149 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
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;
}

3203 3204 3205 3206 3207 3208 3209 3210 3211
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;
3212 3213
    size_t i;
    int ports = 0, usbdevs = 0;
3214 3215 3216 3217 3218 3219 3220

    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;

3221 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
    /* 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;
        }
    }

3251 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
    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

3284 3285 3286
static int
libxlDomainAttachHostDevice(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3287
                            virDomainHostdevDefPtr hostdev)
3288 3289 3290 3291 3292 3293 3294 3295 3296 3297
{
    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 已提交
3298
        if (libxlDomainAttachHostPCIDevice(driver, vm, hostdev) < 0)
C
Chunyan Liu 已提交
3299
            return -1;
3300 3301
        break;

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

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

    return 0;
}

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

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

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

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

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

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

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

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

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

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

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

3390 3391
    libxl_device_nic_init(&nic);

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

    /* 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.
     */
3400
    if (virDomainNetAllocateActualDevice(vm->def, net) < 0)
3401
        goto cleanup;
3402 3403 3404

    actualType = virDomainNetGetActualType(net);

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

3412
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423
        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;

3424 3425 3426
        /* 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
3427
         * the nets list if successful.
3428
         */
3429
        ret = libxlDomainAttachHostDevice(driver, vm, hostdev);
3430
        goto cleanup;
3431 3432
    }

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

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

    ret = 0;

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

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

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

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

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

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

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

    return ret;
}

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

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

3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540
        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;

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

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

3557 3558 3559 3560 3561 3562
            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:
3563
                return -1;
3564
            }
3565 3566

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

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

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

static int
3586 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
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 已提交
3619
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3620
    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
3621
    virDomainHostdevSubsysPCIPtr pcisrc = &subsys->u.pci;
3622 3623 3624 3625
    libxl_device_pci pcidev;
    virDomainHostdevDefPtr detach;
    int idx;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
J
Jim Fehlig 已提交
3626
    int ret = -1;
3627

3628 3629
    libxl_device_pci_init(&pcidev);

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

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


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

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


    virDomainHostdevRemove(vm->def, idx);

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

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

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

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

3677
#ifdef LIBXL_HAVE_PVUSB
3678 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
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;
}

3729 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
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,
3777 3778
                       _("libxenlight failed to detach USB device "
                         "Busnum: %3x, Devnum: %3x"),
3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797
                       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

3798 3799 3800
static int
libxlDomainDetachHostDevice(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3801
                            virDomainHostdevDefPtr hostdev)
3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813
{
    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 已提交
3814
            return libxlDomainDetachHostPCIDevice(driver, vm, hostdev);
3815

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

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

    return -1;
}

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

3842 3843
    libxl_device_nic_init(&nic);

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

    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 已提交
3853
        ret = libxlDomainDetachHostDevice(driver, vm,
3854
                                          virDomainNetGetActualHostdev(detach));
3855
        goto cleanup;
3856 3857
    }

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

J
Jim Fehlig 已提交
3862
    if (libxl_device_nic_remove(cfg->ctx, vm->def->id, &nic, 0)) {
3863 3864 3865 3866 3867 3868 3869 3870 3871
        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 已提交
3872
    if (!ret) {
3873
        virDomainNetReleaseActualDevice(vm->def, detach);
J
Jim Fehlig 已提交
3874 3875
        virDomainNetRemove(vm->def, detachidx);
    }
J
Jim Fehlig 已提交
3876
    virObjectUnref(cfg);
3877 3878 3879
    return ret;
}

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

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

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

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

3904
        case VIR_DOMAIN_DEVICE_HOSTDEV:
3905 3906 3907 3908 3909 3910 3911 3912 3913 3914
            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);
3915 3916
            break;

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

    return ret;
}

3927

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

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

3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959
        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;

3960 3961 3962 3963 3964 3965 3966 3967 3968
        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;

3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980
        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;
        }

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

3987
    return 0;
3988 3989 3990
}

static int
J
Jim Fehlig 已提交
3991
libxlDomainUpdateDeviceLive(virDomainObjPtr vm, virDomainDeviceDefPtr dev)
3992 3993 3994 3995 3996 3997 3998 3999 4000
{
    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 已提交
4001
                    ret = libxlDomainChangeEjectableMedia(vm, disk);
4002 4003 4004 4005
                    if (ret == 0)
                        dev->data.disk = NULL;
                    break;
                default:
4006 4007 4008
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("disk bus '%s' cannot be updated."),
                                   virDomainDiskBusTypeToString(disk->bus));
4009 4010 4011 4012
                    break;
            }
            break;
        default:
4013 4014 4015
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be updated"),
                           virDomainDeviceTypeToString(dev->type));
4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031
            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;
4032
            if (!(orig = virDomainDiskByName(vmdef, disk->dst, false))) {
4033 4034
                virReportError(VIR_ERR_INVALID_ARG,
                               _("target %s doesn't exist."), disk->dst);
4035 4036 4037
                goto cleanup;
            }
            if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM)) {
4038 4039
                virReportError(VIR_ERR_INVALID_ARG, "%s",
                               _("this disk doesn't support update"));
4040 4041 4042
                goto cleanup;
            }

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

    ret = 0;

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


static int
4064 4065
libxlDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                             unsigned int flags)
4066 4067
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4068
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4069 4070 4071 4072 4073 4074 4075 4076
    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 已提交
4077
    if (!(vm = libxlDomObjFromDomain(dom)))
4078 4079
        goto cleanup;

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

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

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

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

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

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

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

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

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

4123 4124
    ret = 0;

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

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

4137
 cleanup:
4138 4139
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
W
Wang Yufei 已提交
4140
    virDomainObjEndAPI(&vm);
4141
    virObjectUnref(cfg);
4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155
    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)
{
4156
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4157
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4158 4159 4160 4161 4162 4163 4164 4165
    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 已提交
4166
    if (!(vm = libxlDomObjFromDomain(dom)))
4167 4168
        goto cleanup;

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

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

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

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

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

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

    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,
4198
                                            cfg->caps, driver->xmlopt,
4199 4200
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                            VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
4201
            goto endjob;
4202

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

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

4214 4215
    ret = 0;

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

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

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

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)
{
4247
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4248
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4249 4250 4251 4252 4253 4254 4255 4256
    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 已提交
4257
    if (!(vm = libxlDomObjFromDomain(dom)))
4258 4259
        goto cleanup;

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

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

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

        /* Make a copy for updated domain. */
4273
        if (!(vmdef = virDomainObjCopyPersistentDef(vm, cfg->caps,
4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286
                                                    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,
4287
                                            cfg->caps, driver->xmlopt,
4288
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
4289 4290
            goto cleanup;

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

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

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

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

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

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

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

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

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

4345 4346 4347 4348 4349 4350 4351 4352 4353 4354
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;
4355
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4356 4357

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

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

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

    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;
    }
4384

4385 4386
    ret = numCells;

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

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

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

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

4409
    return 0;
4410 4411 4412 4413
}


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

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

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

4427
    return 0;
4428 4429
}

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

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

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

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

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

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

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

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

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

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

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

    autostart = (autostart != 0);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static int
4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648
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)
4649
{
4650
    libxlDriverPrivatePtr driver = dom->conn->privateData;
J
Jim Fehlig 已提交
4651
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4652
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
4653
    libxl_domain_sched_params sc_info;
4654
    int sched_id;
4655
    size_t i;
4656 4657
    int ret = -1;

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

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

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

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

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

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

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

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

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

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

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

    ret = 0;

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

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

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

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 已提交
4735
    if (!(vm = libxlDomObjFromDomain(dom)))
B
Bamvor Jian Zhang 已提交
4736 4737
        goto cleanup;

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

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

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

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

B
Bob Liu 已提交
4750 4751 4752 4753 4754 4755 4756
        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 已提交
4757
        chr = vm->def->consoles[0];
4758 4759 4760
        if (chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
            chr = vm->def->serials[0];
    }
B
Bamvor Jian Zhang 已提交
4761 4762 4763 4764 4765 4766 4767 4768

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

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

    /* handle mutually exclusive access to console devices */
    ret = virChrdevOpen(priv->devs,
4778
                        chr->source,
B
Bamvor Jian Zhang 已提交
4779 4780 4781 4782 4783 4784 4785 4786 4787
                        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;
    }

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

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

4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812
/* 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 已提交
4813 4814
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830
    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;

4831 4832
    libxl_bitmap_init(&nodemap);

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

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

4839
    if (virDomainObjCheckActive(vm) < 0)
4840 4841 4842 4843 4844 4845 4846 4847 4848 4849
        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];
4850
        int numnodes;
4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868

        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 已提交
4869
            numnodes = libxl_get_max_nodes(cfg->ctx);
4870 4871 4872
            if (numnodes <= 0)
                goto cleanup;

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

J
Jim Fehlig 已提交
4880
            rc = libxl_domain_get_nodeaffinity(cfg->ctx,
4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899
                                               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;
                }
            }

4900
            if (!(nodeset = virBitmapFormat(nodes)))
4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916
                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;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4977 4978
    ret = vm->updated;

4979
 cleanup:
4980
    virDomainObjEndAPI(&vm);
4981 4982 4983
    return ret;
}

4984 4985
static int
libxlDomainInterfaceStats(virDomainPtr dom,
4986
                          const char *device,
4987 4988 4989 4990
                          virDomainInterfaceStatsPtr stats)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
M
Michal Privoznik 已提交
4991
    virDomainNetDefPtr net = NULL;
4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002
    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;

5003
    if (virDomainObjCheckActive(vm) < 0)
5004 5005
        goto endjob;

5006
    if (!(net = virDomainNetFind(vm->def, device)))
M
Michal Privoznik 已提交
5007 5008
        goto endjob;

5009
    if (virNetDevTapInterfaceStats(net->ifname, stats,
5010
                                   !virDomainNetTypeSharesHostView(net)) < 0)
M
Michal Privoznik 已提交
5011 5012 5013
        goto endjob;

    ret = 0;
5014 5015

 endjob:
W
Wang Yufei 已提交
5016
    libxlDomainObjEndJob(driver, vm);
5017 5018

 cleanup:
W
Wang Yufei 已提交
5019
    virDomainObjEndAPI(&vm);
5020 5021 5022
    return ret;
}

5023 5024 5025 5026 5027 5028
static int
libxlDomainGetTotalCPUStats(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
                            virTypedParameterPtr params,
                            unsigned int nparams)
{
J
Jim Fehlig 已提交
5029
    libxlDriverConfigPtr cfg;
5030 5031 5032 5033 5034 5035
    libxl_dominfo d_info;
    int ret = -1;

    if (nparams == 0)
        return LIBXL_NB_TOTAL_CPU_STAT_PARAM;

J
Jim Fehlig 已提交
5036 5037 5038
    libxl_dominfo_init(&d_info);
    cfg = libxlDriverConfigGet(driver);

5039 5040 5041 5042
    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 已提交
5043
        goto cleanup;
5044 5045 5046 5047 5048 5049 5050 5051 5052 5053
    }

    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 已提交
5054
    virObjectUnref(cfg);
5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068
    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 已提交
5069
    libxlDriverConfigPtr cfg;
5070 5071 5072 5073 5074
    int ret = -1;

    if (nparams == 0 && ncpus != 0)
        return LIBXL_NB_TOTAL_CPU_STAT_PARAM;
    else if (nparams == 0)
5075
        return virDomainDefGetVcpusMax(vm->def);
5076

J
Jim Fehlig 已提交
5077
    cfg = libxlDriverConfigGet(driver);
5078 5079 5080 5081 5082
    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 已提交
5083
        goto cleanup;
5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095
    }

    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 已提交
5096 5097 5098
    if (vcpuinfo)
        libxl_vcpuinfo_list_free(vcpuinfo, maxcpu);
    virObjectUnref(cfg);
5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121
    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;

5122
    if (virDomainObjCheckActive(vm) < 0)
5123 5124 5125 5126 5127 5128 5129 5130 5131
        goto cleanup;

    if (start_cpu == -1)
        ret = libxlDomainGetTotalCPUStats(driver, vm, params, nparams);
    else
        ret = libxlDomainGetPerCPUStats(driver, vm, params, nparams,
                                          start_cpu, ncpus);

 cleanup:
5132
    virDomainObjEndAPI(&vm);
5133 5134 5135
    return ret;
}

5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149
#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 已提交
5150
    libxlDriverConfigPtr cfg;
5151 5152 5153 5154 5155 5156 5157 5158
    virDomainObjPtr vm;
    libxl_dominfo d_info;
    unsigned mem, maxmem;
    size_t i = 0;
    int ret = -1;

    virCheckFlags(0, -1);

5159
    libxl_dominfo_init(&d_info);
J
Jim Fehlig 已提交
5160 5161
    cfg = libxlDriverConfigGet(driver);

5162 5163 5164 5165 5166 5167 5168 5169 5170
    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;

5171
    if (virDomainObjCheckActive(vm) < 0)
5172 5173 5174 5175 5176 5177 5178 5179 5180
        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;
5181
    maxmem = virDomainDefGetMemoryTotal(vm->def);
5182 5183 5184 5185 5186 5187 5188

    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 已提交
5189
    libxlDomainObjEndJob(driver, vm);
5190 5191

 cleanup:
5192
    libxl_dominfo_dispose(&d_info);
W
Wang Yufei 已提交
5193
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
5194
    virObjectUnref(cfg);
5195 5196 5197 5198 5199
    return ret;
}

#undef LIBXL_SET_MEMSTAT

5200 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
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:
5232
    virDomainObjEndAPI(&vm);
5233 5234 5235
    return ret;
}

5236 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
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:
5283
    virDomainObjEndAPI(&vm);
5284 5285
    return ret;
}
5286

R
Roman Bogorodskiy 已提交
5287
#ifdef __linux__
5288 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
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;
}

5335
# define LIBXL_VBD_SECTOR_SIZE 512
5336 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

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;
5386
    unsigned long long status;
5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409

    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;
    }

5410
# define LIBXL_SET_VBDSTAT(FIELD, VAR, MUL) \
5411
    if ((virAsprintf(&name, "%s/"FIELD, path) < 0) || \
5412 5413 5414 5415 5416 5417 5418 5419
        (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); \
5420 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
    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")) {
5473
        if (disk_fmt != VIR_STORAGE_FILE_RAW) {
5474 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
            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;

5530
    if (virDomainObjCheckActive(vm) < 0)
5531 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
        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;

5580
    if (virDomainObjCheckActive(vm) < 0)
5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595
        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;

5596 5597 5598
#define LIBXL_BLKSTAT_ASSIGN_PARAM(VAR, NAME) \
    if (nstats < *nparams && (blkstats.VAR) != -1) { \
        if (virTypedParameterAssign(params + nstats, NAME, \
5599
                                    VIR_TYPED_PARAM_LLONG, (blkstats.VAR)) < 0) \
5600 5601
            goto endjob; \
        nstats++; \
5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626
    }

    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;
}

5627
static int
5628 5629 5630
libxlConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID,
                                   virConnectDomainEventGenericCallback callback,
                                   void *opaque, virFreeCallback freecb)
5631 5632 5633 5634
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int ret;

5635 5636 5637
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

5638 5639 5640 5641
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID, callback, opaque,
                                      freecb, &ret) < 0)
5642
        ret = -1;
5643 5644 5645 5646 5647 5648

    return ret;
}


static int
5649
libxlConnectDomainEventDeregisterAny(virConnectPtr conn, int callbackID)
5650 5651 5652
{
    libxlDriverPrivatePtr driver = conn->privateData;

5653 5654 5655
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

5656 5657
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
5658
                                        callbackID, true) < 0)
5659
        return -1;
5660

5661
    return 0;
5662 5663
}

J
Jim Fehlig 已提交
5664

5665
static int
5666
libxlConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
5667 5668 5669 5670
{
    return 1;
}

5671
static int
5672 5673 5674
libxlConnectListAllDomains(virConnectPtr conn,
                           virDomainPtr **domains,
                           unsigned int flags)
5675 5676 5677 5678
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
5679
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
5680

5681 5682 5683
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

5684 5685
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
5686 5687 5688 5689

    return ret;
}

5690 5691 5692 5693 5694 5695 5696
/* Which features are supported by this driver? */
static int
libxlConnectSupportsFeature(virConnectPtr conn, int feature)
{
    if (virConnectSupportsFeatureEnsureACL(conn) < 0)
        return -1;

5697
    switch ((virDrvFeature) feature) {
5698
    case VIR_DRV_FEATURE_MIGRATION_V3:
5699
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
J
Jim Fehlig 已提交
5700
    case VIR_DRV_FEATURE_MIGRATION_PARAMS:
J
Joao Martins 已提交
5701
    case VIR_DRV_FEATURE_MIGRATION_P2P:
5702
        return 1;
5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713
    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:
5714 5715 5716 5717
    default:
        return 0;
    }
}
5718

5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729
static int
libxlNodeDeviceGetPCIInfo(virNodeDeviceDefPtr def,
                          unsigned *domain,
                          unsigned *bus,
                          unsigned *slot,
                          unsigned *function)
{
    virNodeDevCapsDefPtr cap;

    cap = def->caps;
    while (cap) {
5730
        if (cap->data.type == VIR_NODE_DEV_CAP_PCI_DEV) {
5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743
            *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 已提交
5744
        return -1;
5745 5746
    }

C
Chunyan Liu 已提交
5747
    return 0;
5748 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
}

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")) {
5784
        virPCIDeviceSetStubDriver(pci, VIR_PCI_STUB_DRIVER_XEN);
5785 5786 5787 5788 5789 5790 5791 5792 5793 5794
    } else {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported driver name '%s'"), driverName);
        goto cleanup;
    }

    if (virHostdevPCINodeDeviceDetach(hostdev_mgr, pci) < 0)
        goto cleanup;

    ret = 0;
5795
 cleanup:
5796 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
    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 已提交
5838
        goto cleanup;
5839 5840

    ret = 0;
C
Chunyan Liu 已提交
5841

5842
 cleanup:
C
Chunyan Liu 已提交
5843
    virPCIDeviceFree(pci);
5844 5845 5846 5847 5848 5849 5850 5851
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
libxlNodeDeviceReset(virNodeDevicePtr dev)
{
C
Chunyan Liu 已提交
5852
    virPCIDevicePtr pci = NULL;
5853 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
    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 已提交
5879
        goto cleanup;
5880 5881

    ret = 0;
C
Chunyan Liu 已提交
5882

5883
 cleanup:
C
Chunyan Liu 已提交
5884
    virPCIDeviceFree(pci);
5885 5886 5887 5888 5889
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

J
Jim Fehlig 已提交
5890 5891 5892 5893
static char *
libxlDomainMigrateBegin3Params(virDomainPtr domain,
                               virTypedParameterPtr params,
                               int nparams,
5894 5895
                               char **cookieout,
                               int *cookieoutlen,
J
Jim Fehlig 已提交
5896 5897 5898 5899
                               unsigned int flags)
{
    const char *xmlin = NULL;
    virDomainObjPtr vm = NULL;
5900
    char *xmlout = NULL;
J
Jim Fehlig 已提交
5901

5902 5903 5904 5905 5906
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return NULL;
#endif

J
Jim Fehlig 已提交
5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918
    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 已提交
5919
    if (STREQ_NULLABLE(vm->def->name, "Domain-0")) {
5920 5921 5922
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain-0 cannot be migrated"));
        goto cleanup;
J
Jim Fehlig 已提交
5923 5924
    }

5925 5926
    if (virDomainMigrateBegin3ParamsEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;
J
Jim Fehlig 已提交
5927

5928
    if (virDomainObjCheckActive(vm) < 0)
5929
        goto cleanup;
J
Jim Fehlig 已提交
5930

5931 5932
    xmlout = libxlDomainMigrationSrcBegin(domain->conn, vm, xmlin,
                                          cookieout, cookieoutlen);
5933 5934 5935 5936

 cleanup:
    virDomainObjEndAPI(&vm);
    return xmlout;
J
Jim Fehlig 已提交
5937 5938
}

B
Bob Liu 已提交
5939 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
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;

5977
    if (!(def = libxlDomainMigrationDstPrepareDef(driver, dom_xml, dname)))
B
Bob Liu 已提交
5978 5979 5980 5981 5982
        goto error;

    if (virDomainMigratePrepareTunnel3ParamsEnsureACL(dconn, def) < 0)
        goto error;

5983 5984
    if (libxlDomainMigrationDstPrepareTunnel3(dconn, st, &def, cookiein,
                                              cookieinlen, flags) < 0)
B
Bob Liu 已提交
5985 5986 5987 5988 5989 5990 5991 5992 5993
        goto error;

    return 0;

 error:
    virDomainDefFree(def);
    return -1;
}

J
Jim Fehlig 已提交
5994 5995 5996 5997
static int
libxlDomainMigratePrepare3Params(virConnectPtr dconn,
                                 virTypedParameterPtr params,
                                 int nparams,
5998 5999
                                 const char *cookiein,
                                 int cookieinlen,
J
Jim Fehlig 已提交
6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010
                                 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;

6011 6012 6013 6014 6015
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031
    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;

6032
    if (!(def = libxlDomainMigrationDstPrepareDef(driver, dom_xml, dname)))
J
Jim Fehlig 已提交
6033 6034 6035 6036 6037
        goto error;

    if (virDomainMigratePrepare3ParamsEnsureACL(dconn, def) < 0)
        goto error;

6038 6039
    if (libxlDomainMigrationDstPrepare(dconn, &def, uri_in, uri_out,
                                       cookiein, cookieinlen, flags) < 0)
J
Jim Fehlig 已提交
6040 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
        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;

6067 6068 6069 6070 6071
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093
    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 已提交
6094
    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
6095 6096
        if (libxlDomainMigrationSrcPerformP2P(driver, vm, dom->conn, dom_xml,
                                              dconnuri, uri, dname, flags) < 0)
J
Joao Martins 已提交
6097 6098
            goto cleanup;
    } else {
6099 6100
        if (libxlDomainMigrationSrcPerform(driver, vm, dom_xml, dconnuri,
                                           uri, dname, flags) < 0)
J
Joao Martins 已提交
6101 6102
            goto cleanup;
    }
J
Jim Fehlig 已提交
6103 6104 6105 6106

    ret = 0;

 cleanup:
6107
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124
    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;
6125
    virDomainPtr ret = NULL;
J
Jim Fehlig 已提交
6126

6127 6128 6129 6130 6131
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return NULL;
#endif

J
Jim Fehlig 已提交
6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151
    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) {
6152
        virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
6153 6154 6155
        return NULL;
    }

6156
    ret = libxlDomainMigrationDstFinish(dconn, vm, flags, cancelled);
6157

6158
    virDomainObjEndAPI(&vm);
6159 6160

    return ret;
J
Jim Fehlig 已提交
6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173
}

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;
6174
    int ret = -1;
J
Jim Fehlig 已提交
6175

6176 6177 6178 6179 6180
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
6181 6182 6183 6184 6185 6186 6187
    virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        return -1;

    if (!(vm = libxlDomObjFromDomain(domain)))
        return -1;

6188 6189
    if (virDomainMigrateConfirm3ParamsEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;
J
Jim Fehlig 已提交
6190

6191
    ret = libxlDomainMigrationSrcConfirm(driver, vm, flags, cancelled);
6192 6193 6194 6195

 cleanup:
    virDomainObjEndAPI(&vm);
    return ret;
J
Jim Fehlig 已提交
6196 6197
}

6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214
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;
}
6215

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
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;

6331
    if (virDomainObjCheckActive(vm) < 0)
6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351
        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;
}


6352 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
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) {
6400 6401 6402
        if (STRNEQ(machine, "xenpv") &&
            STRNEQ(machine, "xenpvh") &&
            STRNEQ(machine, "xenfv")) {
6403
            virReportError(VIR_ERR_INVALID_ARG, "%s",
6404
                           _("Xen only supports 'xenpv', 'xenpvh' and 'xenfv' machines"));
6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426
            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;
}


6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446
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 已提交
6447 6448
    ret = virCPUCompareXML(cfg->caps->host.arch, cfg->caps->host.cpu,
                           xmlDesc, failIncompatible);
6449 6450 6451 6452 6453

    virObjectUnref(cfg);
    return ret;
}

6454 6455 6456 6457 6458 6459
static char *
libxlConnectBaselineCPU(virConnectPtr conn,
                        const char **xmlCPUs,
                        unsigned int ncpus,
                        unsigned int flags)
{
J
Jiri Denemark 已提交
6460 6461 6462
    virCPUDefPtr *cpus = NULL;
    virCPUDefPtr cpu = NULL;
    char *cpustr = NULL;
6463 6464 6465 6466 6467 6468 6469

    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL);

    if (virConnectBaselineCPUEnsureACL(conn) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
6470 6471 6472
    if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST)))
        goto cleanup;

6473
    if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, NULL,
6474
                               !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE))))
J
Jiri Denemark 已提交
6475 6476 6477 6478 6479 6480
        goto cleanup;

    if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) &&
        virCPUExpandFeatures(cpus[0]->arch, cpu) < 0)
        goto cleanup;

6481
    cpustr = virCPUDefFormat(cpu, NULL);
6482 6483

 cleanup:
J
Jiri Denemark 已提交
6484 6485 6486 6487
    virCPUDefListFree(cpus);
    virCPUDefFree(cpu);

    return cpustr;
6488 6489
}

6490
static virHypervisorDriver libxlHypervisorDriver = {
6491
    .name = LIBXL_DRIVER_NAME,
6492
    .connectURIProbe = libxlConnectURIProbe,
6493 6494 6495 6496
    .connectOpen = libxlConnectOpen, /* 0.9.0 */
    .connectClose = libxlConnectClose, /* 0.9.0 */
    .connectGetType = libxlConnectGetType, /* 0.9.0 */
    .connectGetVersion = libxlConnectGetVersion, /* 0.9.0 */
6497
    .connectGetHostname = libxlConnectGetHostname, /* 0.9.0 */
6498
    .connectGetSysinfo = libxlConnectGetSysinfo, /* 1.1.0 */
6499
    .connectGetMaxVcpus = libxlConnectGetMaxVcpus, /* 0.9.0 */
6500
    .nodeGetInfo = libxlNodeGetInfo, /* 0.9.0 */
6501 6502 6503 6504
    .connectGetCapabilities = libxlConnectGetCapabilities, /* 0.9.0 */
    .connectListDomains = libxlConnectListDomains, /* 0.9.0 */
    .connectNumOfDomains = libxlConnectNumOfDomains, /* 0.9.0 */
    .connectListAllDomains = libxlConnectListAllDomains, /* 0.9.13 */
6505 6506 6507 6508 6509 6510 6511
    .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 */
6512
    .domainShutdownFlags = libxlDomainShutdownFlags, /* 0.9.10 */
6513 6514
    .domainReboot = libxlDomainReboot, /* 0.9.0 */
    .domainDestroy = libxlDomainDestroy, /* 0.9.0 */
6515
    .domainDestroyFlags = libxlDomainDestroyFlags, /* 0.9.4 */
6516 6517 6518 6519
#ifdef LIBXL_HAVE_DOMAIN_SUSPEND_ONLY
    .domainPMSuspendForDuration = libxlDomainPMSuspendForDuration, /* 4.8.0 */
#endif
    .domainPMWakeup = libxlDomainPMWakeup, /* 4.8.0 */
6520 6521
    .domainGetOSType = libxlDomainGetOSType, /* 0.9.0 */
    .domainGetMaxMemory = libxlDomainGetMaxMemory, /* 0.9.0 */
6522
    .domainSetMaxMemory = libxlDomainSetMaxMemory, /* 0.9.2 */
6523 6524 6525 6526
    .domainSetMemory = libxlDomainSetMemory, /* 0.9.0 */
    .domainSetMemoryFlags = libxlDomainSetMemoryFlags, /* 0.9.0 */
    .domainGetInfo = libxlDomainGetInfo, /* 0.9.0 */
    .domainGetState = libxlDomainGetState, /* 0.9.2 */
6527
    .domainSave = libxlDomainSave, /* 0.9.2 */
6528
    .domainSaveFlags = libxlDomainSaveFlags, /* 0.9.4 */
6529
    .domainRestore = libxlDomainRestore, /* 0.9.2 */
6530
    .domainRestoreFlags = libxlDomainRestoreFlags, /* 0.9.4 */
6531
    .domainCoreDump = libxlDomainCoreDump, /* 0.9.2 */
6532 6533 6534
    .domainSetVcpus = libxlDomainSetVcpus, /* 0.9.0 */
    .domainSetVcpusFlags = libxlDomainSetVcpusFlags, /* 0.9.0 */
    .domainGetVcpusFlags = libxlDomainGetVcpusFlags, /* 0.9.0 */
6535
    .domainGetMaxVcpus = libxlDomainGetMaxVcpus, /* 3.0.0 */
6536
    .domainPinVcpu = libxlDomainPinVcpu, /* 0.9.0 */
6537
    .domainPinVcpuFlags = libxlDomainPinVcpuFlags, /* 1.2.1 */
6538
    .domainGetVcpus = libxlDomainGetVcpus, /* 0.9.0 */
6539
    .domainGetVcpuPinInfo = libxlDomainGetVcpuPinInfo, /* 1.2.1 */
6540
    .domainGetXMLDesc = libxlDomainGetXMLDesc, /* 0.9.0 */
6541 6542 6543 6544
    .connectDomainXMLFromNative = libxlConnectDomainXMLFromNative, /* 0.9.0 */
    .connectDomainXMLToNative = libxlConnectDomainXMLToNative, /* 0.9.0 */
    .connectListDefinedDomains = libxlConnectListDefinedDomains, /* 0.9.0 */
    .connectNumOfDefinedDomains = libxlConnectNumOfDefinedDomains, /* 0.9.0 */
6545 6546 6547
    .domainCreate = libxlDomainCreate, /* 0.9.0 */
    .domainCreateWithFlags = libxlDomainCreateWithFlags, /* 0.9.0 */
    .domainDefineXML = libxlDomainDefineXML, /* 0.9.0 */
6548
    .domainDefineXMLFlags = libxlDomainDefineXMLFlags, /* 1.2.12 */
6549
    .domainUndefine = libxlDomainUndefine, /* 0.9.0 */
6550
    .domainUndefineFlags = libxlDomainUndefineFlags, /* 0.9.4 */
6551 6552 6553 6554 6555
    .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 */
6556 6557 6558 6559
    .domainGetAutostart = libxlDomainGetAutostart, /* 0.9.0 */
    .domainSetAutostart = libxlDomainSetAutostart, /* 0.9.0 */
    .domainGetSchedulerType = libxlDomainGetSchedulerType, /* 0.9.0 */
    .domainGetSchedulerParameters = libxlDomainGetSchedulerParameters, /* 0.9.0 */
6560
    .domainGetSchedulerParametersFlags = libxlDomainGetSchedulerParametersFlags, /* 0.9.2 */
6561
    .domainSetSchedulerParameters = libxlDomainSetSchedulerParameters, /* 0.9.0 */
6562
    .domainSetSchedulerParametersFlags = libxlDomainSetSchedulerParametersFlags, /* 0.9.2 */
6563 6564 6565
#ifdef LIBXL_HAVE_DOMAIN_NODEAFFINITY
    .domainGetNumaParameters = libxlDomainGetNumaParameters, /* 1.1.1 */
#endif
6566
    .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
6567
    .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
6568
    .domainGetJobInfo = libxlDomainGetJobInfo, /* 1.3.1 */
6569
    .domainGetJobStats = libxlDomainGetJobStats, /* 1.3.1 */
P
Pavel Hrdina 已提交
6570 6571
    .domainMemoryStats = libxlDomainMemoryStats, /* 1.3.0 */
    .domainGetCPUStats = libxlDomainGetCPUStats, /* 1.3.0 */
6572
    .domainInterfaceStats = libxlDomainInterfaceStats, /* 1.3.2 */
6573 6574
    .domainBlockStats = libxlDomainBlockStats, /* 2.1.0 */
    .domainBlockStatsFlags = libxlDomainBlockStatsFlags, /* 2.1.0 */
6575 6576
    .connectDomainEventRegister = libxlConnectDomainEventRegister, /* 0.9.0 */
    .connectDomainEventDeregister = libxlConnectDomainEventDeregister, /* 0.9.0 */
6577 6578 6579
    .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */
    .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.2 */
    .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.2 */
B
Bamvor Jian Zhang 已提交
6580
    .domainOpenConsole = libxlDomainOpenConsole, /* 1.1.2 */
6581 6582 6583
    .domainIsActive = libxlDomainIsActive, /* 0.9.0 */
    .domainIsPersistent = libxlDomainIsPersistent, /* 0.9.0 */
    .domainIsUpdated = libxlDomainIsUpdated, /* 0.9.0 */
6584 6585 6586
    .connectDomainEventRegisterAny = libxlConnectDomainEventRegisterAny, /* 0.9.0 */
    .connectDomainEventDeregisterAny = libxlConnectDomainEventDeregisterAny, /* 0.9.0 */
    .connectIsAlive = libxlConnectIsAlive, /* 0.9.8 */
6587
    .connectSupportsFeature = libxlConnectSupportsFeature, /* 1.1.1 */
6588 6589 6590 6591
    .nodeDeviceDettach = libxlNodeDeviceDettach, /* 1.2.3 */
    .nodeDeviceDetachFlags = libxlNodeDeviceDetachFlags, /* 1.2.3 */
    .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.2.3 */
    .nodeDeviceReset = libxlNodeDeviceReset, /* 1.2.3 */
6592 6593
    .domainMigrateBegin3Params = libxlDomainMigrateBegin3Params, /* 1.2.6 */
    .domainMigratePrepare3Params = libxlDomainMigratePrepare3Params, /* 1.2.6 */
B
Bob Liu 已提交
6594
    .domainMigratePrepareTunnel3Params = libxlDomainMigratePrepareTunnel3Params, /* 3.1.0 */
6595 6596 6597
    .domainMigratePerform3Params = libxlDomainMigratePerform3Params, /* 1.2.6 */
    .domainMigrateFinish3Params = libxlDomainMigrateFinish3Params, /* 1.2.6 */
    .domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.6 */
6598
    .nodeGetSecurityModel = libxlNodeGetSecurityModel, /* 1.2.16 */
6599
    .domainInterfaceAddresses = libxlDomainInterfaceAddresses, /* 1.3.5 */
6600
    .connectGetDomainCapabilities = libxlConnectGetDomainCapabilities, /* 2.0.0 */
6601
    .connectCompareCPU = libxlConnectCompareCPU, /* 2.3.0 */
6602
    .connectBaselineCPU = libxlConnectBaselineCPU, /* 2.3.0 */
J
Jim Fehlig 已提交
6603 6604
};

6605
static virConnectDriver libxlConnectDriver = {
6606
    .localOnly = true,
6607
    .uriSchemes = (const char *[]){ "xen", NULL },
6608 6609 6610
    .hypervisorDriver = &libxlHypervisorDriver,
};

J
Jim Fehlig 已提交
6611 6612
static virStateDriver libxlStateDriver = {
    .name = "LIBXL",
6613
    .stateInitialize = libxlStateInitialize,
6614
    .stateAutoStart = libxlStateAutoStart,
6615 6616
    .stateCleanup = libxlStateCleanup,
    .stateReload = libxlStateReload,
J
Jim Fehlig 已提交
6617 6618 6619 6620 6621 6622
};


int
libxlRegister(void)
{
6623 6624
    if (virRegisterConnectDriver(&libxlConnectDriver,
                                 true) < 0)
J
Jim Fehlig 已提交
6625 6626 6627 6628 6629 6630
        return -1;
    if (virRegisterStateDriver(&libxlStateDriver) < 0)
        return -1;

    return 0;
}