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 784
    virDomainObjListForEach(libxl_driver->domains, libxlAutostartDomain,
                            libxl_driver);

785 786
    virDomainObjListForEach(libxl_driver->domains, libxlDomainManagedSaveLoad,
                            libxl_driver);
787

J
Jim Fehlig 已提交
788 789
    return 0;

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

static int
797
libxlStateReload(void)
J
Jim Fehlig 已提交
798
{
799 800
    libxlDriverConfigPtr cfg;

J
Jim Fehlig 已提交
801 802 803
    if (!libxl_driver)
        return 0;

804 805
    cfg = libxlDriverConfigGet(libxl_driver);

806
    virDomainObjListLoadAllConfigs(libxl_driver->domains,
807 808
                                   cfg->configDir,
                                   cfg->autostartDir,
809
                                   true,
810
                                   cfg->caps,
811
                                   libxl_driver->xmlopt,
812 813
                                   NULL, libxl_driver);

814 815
    virDomainObjListForEach(libxl_driver->domains, libxlAutostartDomain,
                            libxl_driver);
816

817
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
818 819 820 821
    return 0;
}


822 823 824 825 826 827 828 829 830 831
static int
libxlConnectURIProbe(char **uri)
{
    if (libxl_driver == NULL)
        return 0;

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


J
Jim Fehlig 已提交
832
static virDrvOpenStatus
833 834
libxlConnectOpen(virConnectPtr conn,
                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
835
                 virConfPtr conf ATTRIBUTE_UNUSED,
836
                 unsigned int flags)
J
Jim Fehlig 已提交
837
{
E
Eric Blake 已提交
838 839
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

840 841 842 843 844 845
    /* 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 已提交
846

847
    /* /session isn't supported in libxenlight */
848
    if (STRNEQ(conn->uri->path, "") &&
849 850 851 852
        STRNEQ(conn->uri->path, "/") &&
        STRNEQ(conn->uri->path, "/system")) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected Xen URI path '%s', try xen:///system"),
853
                       conn->uri->path);
854
        return VIR_DRV_OPEN_ERROR;
J
Jim Fehlig 已提交
855 856
    }

857 858 859
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

J
Jim Fehlig 已提交
860 861 862 863 864 865
    conn->privateData = libxl_driver;

    return VIR_DRV_OPEN_SUCCESS;
};

static int
866
libxlConnectClose(virConnectPtr conn ATTRIBUTE_UNUSED)
J
Jim Fehlig 已提交
867 868 869 870 871 872
{
    conn->privateData = NULL;
    return 0;
}

static const char *
873
libxlConnectGetType(virConnectPtr conn)
J
Jim Fehlig 已提交
874
{
875 876 877
    if (virConnectGetTypeEnsureACL(conn) < 0)
        return NULL;

J
Jim Fehlig 已提交
878
    return "Xen";
J
Jim Fehlig 已提交
879 880 881
}

static int
882
libxlConnectGetVersion(virConnectPtr conn, unsigned long *version)
J
Jim Fehlig 已提交
883 884
{
    libxlDriverPrivatePtr driver = conn->privateData;
885
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
886

887 888 889
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return 0;

890 891 892
    cfg = libxlDriverConfigGet(driver);
    *version = cfg->version;
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
893 894 895
    return 0;
}

896

897
static char *libxlConnectGetHostname(virConnectPtr conn)
898
{
899 900 901
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

902 903 904
    return virGetHostname();
}

905 906 907 908 909 910 911 912
static char *
libxlConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virCheckFlags(0, NULL);

913 914 915
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

916 917 918 919 920 921 922 923
    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;
924
    if (virBufferCheckError(&buf) < 0)
925 926 927
        return NULL;
    return virBufferContentAndReset(&buf);
}
928

J
Jim Fehlig 已提交
929
static int
930
libxlConnectGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED)
J
Jim Fehlig 已提交
931 932 933
{
    int ret;
    libxlDriverPrivatePtr driver = conn->privateData;
934
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
935

936 937 938
    if (virConnectGetMaxVcpusEnsureACL(conn) < 0)
        return -1;

939 940
    cfg = libxlDriverConfigGet(driver);
    ret = libxl_get_max_cpus(cfg->ctx);
941 942 943 944 945
    /* 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)
946
        ret = -1;
J
Jim Fehlig 已提交
947

948
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
949 950 951 952 953 954
    return ret;
}

static int
libxlNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
{
955 956 957
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

958
    return libxlDriverNodeGetInfo(conn->privateData, info);
J
Jim Fehlig 已提交
959 960 961
}

static char *
962
libxlConnectGetCapabilities(virConnectPtr conn)
J
Jim Fehlig 已提交
963 964 965
{
    libxlDriverPrivatePtr driver = conn->privateData;
    char *xml;
966
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
967

968 969 970
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

971
    cfg = libxlDriverConfigGet(driver);
972
    xml = virCapabilitiesFormatXML(cfg->caps);
J
Jim Fehlig 已提交
973

974
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
975 976 977 978
    return xml;
}

static int
979
libxlConnectListDomains(virConnectPtr conn, int *ids, int nids)
J
Jim Fehlig 已提交
980 981 982 983
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

984 985 986
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

987 988
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
J
Jim Fehlig 已提交
989 990 991 992 993

    return n;
}

static int
994
libxlConnectNumOfDomains(virConnectPtr conn)
J
Jim Fehlig 已提交
995 996 997 998
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

999 1000 1001
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

1002 1003
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
J
Jim Fehlig 已提交
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015

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

1019 1020 1021 1022
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
                  VIR_DOMAIN_START_VALIDATE, NULL);

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

1025
    if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt,
1026
                                        NULL, parse_flags)))
J
Jim Fehlig 已提交
1027 1028
        goto cleanup;

1029 1030 1031
    if (virDomainCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

1032
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1033
                                   driver->xmlopt,
1034
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1035 1036
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
J
Jim Fehlig 已提交
1037 1038 1039
        goto cleanup;
    def = NULL;

1040
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) {
1041
        if (!vm->persistent)
1042 1043 1044 1045
            virDomainObjListRemove(driver->domains, vm);
        goto cleanup;
    }

1046 1047
    if (libxlDomainStartNew(driver, vm,
                         (flags & VIR_DOMAIN_START_PAUSED) != 0) < 0) {
1048
        if (!vm->persistent)
1049
            virDomainObjListRemove(driver->domains, vm);
1050
        goto endjob;
J
Jim Fehlig 已提交
1051 1052
    }

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

1055
 endjob:
W
Wang Yufei 已提交
1056
    libxlDomainObjEndJob(driver, vm);
1057

1058
 cleanup:
J
Jim Fehlig 已提交
1059
    virDomainDefFree(def);
W
Wang Yufei 已提交
1060
    virDomainObjEndAPI(&vm);
1061
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
    return dom;
}

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

1072
    vm = virDomainObjListFindByID(driver->domains, id);
J
Jim Fehlig 已提交
1073
    if (!vm) {
1074
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
1075 1076 1077
        goto cleanup;
    }

1078 1079 1080
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

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

1083
 cleanup:
1084
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
    return dom;
}

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

1095
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
J
Jim Fehlig 已提交
1096
    if (!vm) {
1097
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
1098 1099 1100
        goto cleanup;
    }

1101 1102 1103
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

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

1106
 cleanup:
1107
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
    return dom;
}

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

1118
    vm = virDomainObjListFindByName(driver->domains, name);
J
Jim Fehlig 已提交
1119
    if (!vm) {
1120
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
1121 1122 1123
        goto cleanup;
    }

1124 1125 1126
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

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

1129
 cleanup:
1130
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1131 1132 1133
    return dom;
}

1134 1135 1136 1137
static int
libxlDomainSuspend(virDomainPtr dom)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1138
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1139
    virDomainObjPtr vm;
1140
    virObjectEventPtr event = NULL;
1141 1142
    int ret = -1;

J
Jim Fehlig 已提交
1143
    if (!(vm = libxlDomObjFromDomain(dom)))
1144
        goto cleanup;
1145

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

1148 1149 1150
    if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

1154
    if (virDomainObjCheckActive(vm) < 0)
1155
        goto endjob;
1156

J
Jiri Denemark 已提交
1157
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
J
Jim Fehlig 已提交
1158
        if (libxl_domain_pause(cfg->ctx, vm->def->id) != 0) {
1159 1160
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to suspend domain '%d' with libxenlight"),
1161
                           vm->def->id);
1162
            goto endjob;
1163 1164
        }

J
Jiri Denemark 已提交
1165
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
1166

1167
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
1168 1169 1170
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

1171
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
1172
        goto endjob;
1173 1174 1175

    ret = 0;

1176
 endjob:
W
Wang Yufei 已提交
1177
    libxlDomainObjEndJob(driver, vm);
1178

1179
 cleanup:
W
Wang Yufei 已提交
1180
    virDomainObjEndAPI(&vm);
1181
    virObjectEventStateQueue(driver->domainEventState, event);
1182
    virObjectUnref(cfg);
1183 1184 1185 1186 1187 1188 1189 1190
    return ret;
}


static int
libxlDomainResume(virDomainPtr dom)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1191
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1192
    virDomainObjPtr vm;
1193
    virObjectEventPtr event = NULL;
1194 1195
    int ret = -1;

J
Jim Fehlig 已提交
1196
    if (!(vm = libxlDomObjFromDomain(dom)))
1197 1198
        goto cleanup;

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

1201 1202 1203
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

1207
    if (virDomainObjCheckActive(vm) < 0)
1208
        goto endjob;
1209

J
Jiri Denemark 已提交
1210
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
J
Jim Fehlig 已提交
1211
        if (libxl_domain_unpause(cfg->ctx, vm->def->id) != 0) {
1212 1213
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to resume domain '%d' with libxenlight"),
1214
                           vm->def->id);
1215
            goto endjob;
1216 1217
        }

J
Jiri Denemark 已提交
1218 1219
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
1220

1221
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_RESUMED,
1222 1223 1224
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

1225
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
1226
        goto endjob;
1227 1228 1229

    ret = 0;

1230
 endjob:
W
Wang Yufei 已提交
1231
    libxlDomainObjEndJob(driver, vm);
1232

1233
 cleanup:
W
Wang Yufei 已提交
1234
    virDomainObjEndAPI(&vm);
1235
    virObjectEventStateQueue(driver->domainEventState, event);
1236
    virObjectUnref(cfg);
1237 1238 1239
    return ret;
}

J
Jim Fehlig 已提交
1240
static int
1241
libxlDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
1242
{
J
Jim Fehlig 已提交
1243 1244
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1245 1246 1247
    virDomainObjPtr vm;
    int ret = -1;

1248 1249 1250 1251 1252
    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;
1253

J
Jim Fehlig 已提交
1254
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1255 1256
        goto cleanup;

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

1259
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
1260 1261
        goto cleanup;

1262
    if (virDomainObjCheckActive(vm) < 0)
J
Jim Fehlig 已提交
1263 1264
        goto cleanup;

1265
    if (flags & VIR_DOMAIN_SHUTDOWN_PARAVIRT) {
J
Jim Fehlig 已提交
1266
        ret = libxl_domain_shutdown(cfg->ctx, vm->def->id);
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
        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 已提交
1281
        ret = libxl_send_trigger(cfg->ctx, vm->def->id,
1282 1283 1284 1285
                                 LIBXL_TRIGGER_POWER, 0);
        if (ret == 0)
            goto cleanup;

1286 1287
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to shutdown domain '%d' with libxenlight"),
1288
                       vm->def->id);
1289
        ret = -1;
J
Jim Fehlig 已提交
1290 1291
    }

1292
 cleanup:
1293
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1294
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1295 1296 1297
    return ret;
}

1298 1299 1300 1301 1302 1303 1304
static int
libxlDomainShutdown(virDomainPtr dom)
{
    return libxlDomainShutdownFlags(dom, 0);
}


J
Jim Fehlig 已提交
1305
static int
E
Eric Blake 已提交
1306
libxlDomainReboot(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
1307
{
J
Jim Fehlig 已提交
1308 1309
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1310 1311 1312
    virDomainObjPtr vm;
    int ret = -1;

J
Jim Fehlig 已提交
1313 1314 1315
    virCheckFlags(VIR_DOMAIN_REBOOT_PARAVIRT, -1);
    if (flags == 0)
        flags = VIR_DOMAIN_REBOOT_PARAVIRT;
E
Eric Blake 已提交
1316

J
Jim Fehlig 已提交
1317
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1318 1319
        goto cleanup;

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

1322
    if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
1323 1324
        goto cleanup;

1325
    if (virDomainObjCheckActive(vm) < 0)
J
Jim Fehlig 已提交
1326 1327
        goto cleanup;

J
Jim Fehlig 已提交
1328
    if (flags & VIR_DOMAIN_REBOOT_PARAVIRT) {
J
Jim Fehlig 已提交
1329
        ret = libxl_domain_reboot(cfg->ctx, vm->def->id);
J
Jim Fehlig 已提交
1330 1331 1332
        if (ret == 0)
            goto cleanup;

1333 1334
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to reboot domain '%d' with libxenlight"),
1335
                       vm->def->id);
J
Jim Fehlig 已提交
1336
        ret = -1;
J
Jim Fehlig 已提交
1337 1338
    }

1339
 cleanup:
1340
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1341
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1342 1343 1344 1345
    return ret;
}

static int
1346 1347
libxlDomainDestroyFlags(virDomainPtr dom,
                        unsigned int flags)
J
Jim Fehlig 已提交
1348 1349
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
J
Jim Fehlig 已提交
1350
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1351 1352
    virDomainObjPtr vm;
    int ret = -1;
1353
    virObjectEventPtr event = NULL;
J
Jim Fehlig 已提交
1354

1355 1356
    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
1357
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1358 1359
        goto cleanup;

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

1362 1363 1364
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

1368
    if (virDomainObjCheckActive(vm) < 0)
1369
        goto endjob;
J
Jim Fehlig 已提交
1370

1371
    if (libxlDomainDestroyInternal(driver, vm) < 0) {
1372
        virReportError(VIR_ERR_INTERNAL_ERROR,
1373
                       _("Failed to destroy domain '%d'"), vm->def->id);
1374
        goto endjob;
J
Jim Fehlig 已提交
1375 1376
    }

1377 1378 1379 1380 1381 1382 1383
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
                         VIR_DOMAIN_SHUTOFF_DESTROYED);

    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);

    libxlDomainCleanup(driver, vm);
1384
    if (!vm->persistent)
1385
        virDomainObjListRemove(driver->domains, vm);
J
Jim Fehlig 已提交
1386 1387 1388

    ret = 0;

1389
 endjob:
W
Wang Yufei 已提交
1390
    libxlDomainObjEndJob(driver, vm);
1391

1392
 cleanup:
W
Wang Yufei 已提交
1393
    virDomainObjEndAPI(&vm);
1394
    virObjectEventStateQueue(driver->domainEventState, event);
J
Jim Fehlig 已提交
1395
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1396 1397 1398
    return ret;
}

1399 1400 1401 1402 1403 1404
static int
libxlDomainDestroy(virDomainPtr dom)
{
    return libxlDomainDestroyFlags(dom, 0);
}

1405 1406 1407 1408 1409 1410 1411 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
#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);
1518 1519 1520
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                              VIR_DOMAIN_EVENT_STOPPED_FAILED);
    libxlDomainCleanup(driver, vm);
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530

 endjob:
    libxlDomainObjEndJob(driver, vm);

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

1531 1532 1533 1534 1535 1536
static char *
libxlDomainGetOSType(virDomainPtr dom)
{
    virDomainObjPtr vm;
    char *type = NULL;

J
Jim Fehlig 已提交
1537
    if (!(vm = libxlDomObjFromDomain(dom)))
1538 1539
        goto cleanup;

1540 1541 1542
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1543
    if (VIR_STRDUP(type, virDomainOSTypeToString(vm->def->os.type)) < 0)
1544
        goto cleanup;
1545

1546
 cleanup:
1547
    virDomainObjEndAPI(&vm);
1548 1549 1550
    return type;
}

1551
static unsigned long long
1552 1553 1554
libxlDomainGetMaxMemory(virDomainPtr dom)
{
    virDomainObjPtr vm;
1555
    unsigned long long ret = 0;
1556

J
Jim Fehlig 已提交
1557
    if (!(vm = libxlDomObjFromDomain(dom)))
1558
        goto cleanup;
1559 1560 1561 1562

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

1563
    ret = virDomainDefGetMemoryTotal(vm->def);
1564

1565
 cleanup:
1566
    virDomainObjEndAPI(&vm);
1567 1568 1569
    return ret;
}

1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599

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


1600
static int
1601
libxlDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
1602 1603 1604
                          unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1605
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1606
    virDomainObjPtr vm;
1607
    virDomainDefPtr persistentDef = NULL;
1608 1609 1610
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_MEM_LIVE |
1611 1612
                  VIR_DOMAIN_MEM_CONFIG |
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
1613

J
Jim Fehlig 已提交
1614
    if (!(vm = libxlDomObjFromDomain(dom)))
1615 1616
        goto cleanup;

1617 1618 1619
    if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

1623 1624
    if (virDomainLiveConfigHelperMethod(cfg->caps, driver->xmlopt, vm, &flags,
                                        &persistentDef) < 0)
1625
        goto endjob;
1626

1627 1628
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */
1629

1630
        if (flags & VIR_DOMAIN_MEM_LIVE) {
J
Jim Fehlig 已提交
1631
            if (libxl_domain_setmaxmem(cfg->ctx, vm->def->id, newmem) < 0) {
1632 1633
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to set maximum memory for domain '%d'"
1634
                                 " with libxenlight"), vm->def->id);
1635
                goto endjob;
1636 1637 1638 1639 1640 1641
            }
        }

        if (flags & VIR_DOMAIN_MEM_CONFIG) {
            /* Help clang 2.8 decipher the logic flow.  */
            sa_assert(persistentDef);
1642
            virDomainDefSetMemoryTotal(persistentDef, newmem);
1643 1644
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
1645
            ret = virDomainSaveConfig(cfg->configDir, cfg->caps, persistentDef);
1646
            goto endjob;
1647 1648
        }

1649 1650
    } else {
        /* resize the current memory */
1651

1652
        if (newmem > virDomainDefGetMemoryTotal(vm->def)) {
1653 1654
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("cannot set memory higher than max memory"));
1655
            goto endjob;
1656 1657 1658
        }

        if (flags & VIR_DOMAIN_MEM_LIVE) {
1659 1660 1661 1662
            int res;

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

        if (flags & VIR_DOMAIN_MEM_CONFIG) {
            sa_assert(persistentDef);
            persistentDef->mem.cur_balloon = newmem;
1678
            ret = virDomainSaveConfig(cfg->configDir, cfg->caps, persistentDef);
1679
            goto endjob;
1680
        }
1681 1682
    }

1683 1684
    ret = 0;

1685
 endjob:
W
Wang Yufei 已提交
1686
    libxlDomainObjEndJob(driver, vm);
1687

1688
 cleanup:
W
Wang Yufei 已提交
1689
    virDomainObjEndAPI(&vm);
1690
    virObjectUnref(cfg);
1691 1692 1693 1694 1695 1696 1697 1698 1699
    return ret;
}

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

1700 1701 1702 1703 1704 1705
static int
libxlDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
{
    return libxlDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
}

J
Jim Fehlig 已提交
1706 1707 1708
static int
libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
J
Jim Fehlig 已提交
1709 1710
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1711
    virDomainObjPtr vm;
1712
    libxl_dominfo d_info;
J
Jim Fehlig 已提交
1713 1714
    int ret = -1;

J
Jim Fehlig 已提交
1715
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1716 1717
        goto cleanup;

1718 1719 1720
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1721
    info->maxMem = virDomainDefGetMemoryTotal(vm->def);
1722 1723 1724 1725
    if (!virDomainObjIsActive(vm)) {
        info->cpuTime = 0;
        info->memory = vm->def->mem.cur_balloon;
    } else {
1726 1727
        libxl_dominfo_init(&d_info);

J
Jim Fehlig 已提交
1728
        if (libxl_domain_info(cfg->ctx, &d_info, vm->def->id) != 0) {
1729
            virReportError(VIR_ERR_INTERNAL_ERROR,
1730 1731
                           _("libxl_domain_info failed for domain '%d'"),
                           vm->def->id);
1732 1733 1734 1735
            goto cleanup;
        }
        info->cpuTime = d_info.cpu_time;
        info->memory = d_info.current_memkb;
1736 1737

        libxl_dominfo_dispose(&d_info);
1738 1739
    }

J
Jiri Denemark 已提交
1740
    info->state = virDomainObjGetState(vm, NULL);
1741
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
J
Jim Fehlig 已提交
1742 1743
    ret = 0;

1744
 cleanup:
1745
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1746
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1747 1748 1749
    return ret;
}

1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760
static int
libxlDomainGetState(virDomainPtr dom,
                    int *state,
                    int *reason,
                    unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
1761
    if (!(vm = libxlDomObjFromDomain(dom)))
1762 1763
        goto cleanup;

1764 1765 1766
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1767
    *state = virDomainObjGetState(vm, reason);
1768 1769
    ret = 0;

1770
 cleanup:
1771
    virDomainObjEndAPI(&vm);
1772 1773 1774
    return ret;
}

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

    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
1793 1794 1795
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain '%d' has to be running because libxenlight will"
                         " suspend it"), vm->def->id);
1796 1797 1798 1799
        goto cleanup;
    }

    if ((fd = virFileOpenAs(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR,
L
Laine Stump 已提交
1800
                            -1, -1, 0)) < 0) {
1801 1802 1803 1804 1805
        virReportSystemError(-fd,
                             _("Failed to create domain save file '%s'"), to);
        goto cleanup;
    }

1806
    if ((xml = virDomainDefFormat(vm->def, cfg->caps, 0)) == NULL)
1807 1808 1809 1810 1811 1812 1813 1814 1815
        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)) {
1816 1817
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Failed to write save file header"));
1818 1819 1820 1821
        goto cleanup;
    }

    if (safewrite(fd, xml, xml_len) != xml_len) {
1822 1823
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Failed to write xml description"));
1824 1825 1826
        goto cleanup;
    }

1827 1828
    /* Unlock virDomainObj while saving domain */
    virObjectUnlock(vm);
J
Jim Fehlig 已提交
1829
    ret = libxl_domain_suspend(cfg->ctx, vm->def->id, fd, 0, NULL);
1830 1831 1832
    virObjectLock(vm);

    if (ret != 0) {
1833 1834 1835
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to save domain '%d' with libxenlight"),
                       vm->def->id);
1836
        ret = -1;
1837 1838 1839
        goto cleanup;
    }

1840 1841 1842
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
                         VIR_DOMAIN_SHUTOFF_SAVED);

1843
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
1844 1845
                                         VIR_DOMAIN_EVENT_STOPPED_SAVED);

1846
    if (libxlDomainDestroyInternal(driver, vm) < 0) {
1847 1848
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to destroy domain '%d'"), vm->def->id);
1849 1850 1851
        goto cleanup;
    }

1852
    libxlDomainCleanup(driver, vm);
1853
    vm->hasManagedSave = managed;
1854 1855
    ret = 0;

1856
 cleanup:
1857 1858 1859
    VIR_FREE(xml);
    if (VIR_CLOSE(fd) < 0)
        virReportSystemError(errno, "%s", _("cannot close file"));
1860
    virObjectEventStateQueue(driver->domainEventState, event);
J
Jim Fehlig 已提交
1861
    virObjectUnref(cfg);
1862 1863 1864 1865
    return ret;
}

static int
1866 1867
libxlDomainSaveFlags(virDomainPtr dom, const char *to, const char *dxml,
                     unsigned int flags)
1868
{
1869 1870
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
1871 1872
    int ret = -1;

1873 1874 1875 1876 1877
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

1878 1879
    virCheckFlags(0, -1);
    if (dxml) {
1880 1881
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("xml modification unsupported"));
1882 1883 1884
        return -1;
    }

J
Jim Fehlig 已提交
1885
    if (!(vm = libxlDomObjFromDomain(dom)))
1886 1887
        goto cleanup;

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

1890 1891 1892
    if (virDomainSaveFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

1896
    if (virDomainObjCheckActive(vm) < 0)
1897
        goto endjob;
1898

1899
    if (libxlDoDomainSave(driver, vm, to, false) < 0)
1900
        goto endjob;
1901

1902
    if (!vm->persistent)
1903
        virDomainObjListRemove(driver->domains, vm);
1904 1905

    ret = 0;
1906

1907
 endjob:
W
Wang Yufei 已提交
1908
    libxlDomainObjEndJob(driver, vm);
1909

1910
 cleanup:
W
Wang Yufei 已提交
1911
    virDomainObjEndAPI(&vm);
1912 1913
    return ret;
}
1914

1915
static int
1916 1917 1918 1919 1920 1921 1922 1923
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)
1924 1925
{
    libxlDriverPrivatePtr driver = conn->privateData;
1926
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1927 1928 1929 1930 1931
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    libxlSavefileHeader hdr;
    int fd = -1;
    int ret = -1;
1932

1933 1934 1935 1936 1937
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

1938
    virCheckFlags(VIR_DOMAIN_SAVE_PAUSED, -1);
1939
    if (dxml) {
1940 1941
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("xml modification unsupported"));
1942 1943 1944
        return -1;
    }

1945
    fd = libxlDomainSaveImageOpen(driver, cfg, from, &def, &hdr);
1946
    if (fd < 0)
1947
        goto cleanup;
1948

1949
    if (virDomainRestoreFlagsEnsureACL(conn, def) < 0)
1950
        goto cleanup;
1951

1952
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1953
                                   driver->xmlopt,
1954 1955 1956
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1957
        goto cleanup;
1958 1959
    def = NULL;

1960
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) {
1961
        if (!vm->persistent)
1962 1963 1964 1965
            virDomainObjListRemove(driver->domains, vm);
        goto cleanup;
    }

1966 1967 1968
    ret = libxlDomainStartRestore(driver, vm,
                                  (flags & VIR_DOMAIN_SAVE_PAUSED) != 0,
                                  fd, hdr.version);
1969
    if (ret < 0 && !vm->persistent)
1970
        virDomainObjListRemove(driver->domains, vm);
1971

W
Wang Yufei 已提交
1972
    libxlDomainObjEndJob(driver, vm);
1973

1974
 cleanup:
1975 1976
    if (VIR_CLOSE(fd) < 0)
        virReportSystemError(errno, "%s", _("cannot close file"));
1977
    virDomainDefFree(def);
W
Wang Yufei 已提交
1978
    virDomainObjEndAPI(&vm);
1979
    virObjectUnref(cfg);
1980 1981 1982
    return ret;
}

1983 1984 1985 1986 1987 1988
static int
libxlDomainRestore(virConnectPtr conn, const char *from)
{
    return libxlDomainRestoreFlags(conn, from, NULL, 0);
}

1989
static int
1990
libxlDomainCoreDump(virDomainPtr dom, const char *to, unsigned int flags)
1991 1992
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
J
Jim Fehlig 已提交
1993
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1994
    virDomainObjPtr vm;
1995
    virObjectEventPtr event = NULL;
1996 1997 1998 1999 2000
    bool paused = false;
    int ret = -1;

    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH, -1);

J
Jim Fehlig 已提交
2001
    if (!(vm = libxlDomObjFromDomain(dom)))
2002 2003
        goto cleanup;

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

2006 2007 2008
    if (virDomainCoreDumpEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

2012
    if (virDomainObjCheckActive(vm) < 0)
2013
        goto endjob;
2014 2015 2016

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

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

    if (flags & VIR_DUMP_CRASH) {
2041
        if (libxlDomainDestroyInternal(driver, vm) < 0) {
2042
            virReportError(VIR_ERR_INTERNAL_ERROR,
2043
                           _("Failed to destroy domain '%d'"), vm->def->id);
2044
            goto unpause;
2045 2046
        }

2047 2048 2049
        libxlDomainCleanup(driver, vm);
        virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
                             VIR_DOMAIN_SHUTOFF_CRASHED);
2050
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
2051
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
2052
        if (!vm->persistent)
2053
            virDomainObjListRemove(driver->domains, vm);
2054 2055 2056 2057
    }

    ret = 0;

2058
 unpause:
2059
    if (virDomainObjIsActive(vm) && paused) {
J
Jim Fehlig 已提交
2060
        if (libxl_domain_unpause(cfg->ctx, vm->def->id) != 0) {
2061 2062
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("After dumping core, failed to resume domain '%d' with"
2063
                             " libxenlight"), vm->def->id);
2064 2065 2066 2067 2068
        } else {
            virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                                 VIR_DOMAIN_RUNNING_UNPAUSED);
        }
    }
2069

2070
 endjob:
W
Wang Yufei 已提交
2071
    libxlDomainObjEndJob(driver, vm);
2072

2073
 cleanup:
W
Wang Yufei 已提交
2074
    virDomainObjEndAPI(&vm);
2075
    virObjectEventStateQueue(driver->domainEventState, event);
J
Jim Fehlig 已提交
2076
    virObjectUnref(cfg);
2077 2078 2079
    return ret;
}

2080 2081 2082 2083 2084 2085 2086 2087 2088 2089
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 已提交
2090
    if (!(vm = libxlDomObjFromDomain(dom)))
2091 2092
        goto cleanup;

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

2095 2096 2097
    if (virDomainManagedSaveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

2101
    if (virDomainObjCheckActive(vm) < 0)
2102
        goto endjob;
2103
    if (!vm->persistent) {
2104 2105
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot do managed save for transient domain"));
2106
        goto endjob;
2107
    }
2108 2109 2110

    name = libxlDomainManagedSavePath(driver, vm);
    if (name == NULL)
2111
        goto endjob;
2112 2113 2114

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

2115
    if (libxlDoDomainSave(driver, vm, name, true) < 0)
2116
        goto endjob;
2117

2118
    if (!vm->persistent)
2119
        virDomainObjListRemove(driver->domains, vm);
2120 2121

    ret = 0;
2122

2123
 endjob:
W
Wang Yufei 已提交
2124
    libxlDomainObjEndJob(driver, vm);
2125

2126
 cleanup:
W
Wang Yufei 已提交
2127
    virDomainObjEndAPI(&vm);
2128 2129 2130 2131
    VIR_FREE(name);
    return ret;
}

2132 2133
static int
libxlDomainManagedSaveLoad(virDomainObjPtr vm,
2134 2135 2136 2137
                           void *opaque)
{
    libxlDriverPrivatePtr driver = opaque;
    char *name;
2138
    int ret = -1;
2139

2140
    virObjectLock(vm);
2141 2142 2143 2144 2145 2146

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

    vm->hasManagedSave = virFileExists(name);

2147
    ret = 0;
2148
 cleanup:
2149
    virObjectUnlock(vm);
2150
    VIR_FREE(name);
2151
    return ret;
2152 2153
}

2154 2155 2156 2157 2158 2159 2160 2161
static int
libxlDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
2162
    if (!(vm = libxlDomObjFromDomain(dom)))
2163 2164
        goto cleanup;

2165 2166 2167
    if (virDomainHasManagedSaveImageEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2168
    ret = vm->hasManagedSave;
2169

2170
 cleanup:
2171
    virDomainObjEndAPI(&vm);
2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184
    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 已提交
2185
    if (!(vm = libxlDomObjFromDomain(dom)))
2186 2187
        goto cleanup;

2188 2189 2190
    if (virDomainManagedSaveRemoveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2191 2192 2193 2194 2195
    name = libxlDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    ret = unlink(name);
2196
    vm->hasManagedSave = false;
2197

2198
 cleanup:
2199
    VIR_FREE(name);
2200
    virDomainObjEndAPI(&vm);
2201 2202 2203
    return ret;
}

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

    if (!nvcpus) {
2235
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("nvcpus is zero"));
2236 2237 2238
        return -1;
    }

J
Jim Fehlig 已提交
2239
    if (!(vm = libxlDomObjFromDomain(dom)))
2240 2241
        goto cleanup;

2242 2243 2244
    if (virDomainSetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

2248
    if (!virDomainObjIsActive(vm) && (flags & VIR_DOMAIN_VCPU_LIVE)) {
2249 2250
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot set vcpus on an inactive domain"));
2251
        goto endjob;
2252 2253 2254
    }

    if (!vm->persistent && (flags & VIR_DOMAIN_VCPU_CONFIG)) {
2255 2256
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot change persistent config of a transient domain"));
2257
        goto endjob;
2258 2259
    }

2260
    if ((max = libxlConnectGetMaxVcpus(dom->conn, NULL)) < 0) {
2261 2262
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not determine max vcpus for the domain"));
2263
        goto endjob;
2264 2265
    }

2266 2267
    if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM) && virDomainDefGetVcpusMax(vm->def) < max)
        max = virDomainDefGetVcpusMax(vm->def);
2268 2269

    if (nvcpus > max) {
2270 2271 2272
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the domain: %d > %d"), nvcpus, max);
2273
        goto endjob;
2274 2275
    }

2276
    if (!(def = virDomainObjGetPersistentDef(cfg->caps, driver->xmlopt, vm)))
2277
        goto endjob;
2278

E
Eric Blake 已提交
2279
    maplen = VIR_CPU_MAPLEN(nvcpus);
2280
    if (VIR_ALLOC_N(bitmask, maplen) < 0)
2281
        goto endjob;
2282 2283

    for (i = 0; i < nvcpus; ++i) {
E
Eric Blake 已提交
2284
        pos = i / 8;
2285 2286 2287 2288 2289 2290 2291 2292
        bitmask[pos] |= 1 << (i % 8);
    }

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

    switch (flags) {
    case VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_CONFIG:
2293
        if (virDomainDefSetVcpusMax(def, nvcpus, driver->xmlopt) < 0)
2294
            goto cleanup;
2295 2296 2297
        break;

    case VIR_DOMAIN_VCPU_CONFIG:
2298 2299
        if (virDomainDefSetVcpus(def, nvcpus) < 0)
            goto cleanup;
2300 2301 2302
        break;

    case VIR_DOMAIN_VCPU_LIVE:
J
Jim Fehlig 已提交
2303
        if (libxl_set_vcpuonline(cfg->ctx, vm->def->id, &map) != 0) {
2304 2305
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to set vcpus for domain '%d'"
2306
                             " with libxenlight"), vm->def->id);
2307
            goto endjob;
2308
        }
2309 2310
        if (virDomainDefSetVcpus(vm->def, nvcpus) < 0)
            goto endjob;
2311 2312 2313
        break;

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

    ret = 0;

2328
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
2329
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0) {
2330 2331 2332 2333 2334
            VIR_WARN("Unable to save status on vm %s after changing vcpus",
                     vm->def->name);
        }
    }
    if (flags & VIR_DOMAIN_VCPU_CONFIG) {
2335
        if (virDomainSaveConfig(cfg->configDir, cfg->caps, def) < 0) {
2336 2337 2338 2339
            VIR_WARN("Unable to save configuration of vm %s after changing vcpus",
                     vm->def->name);
        }
    }
2340

2341
 endjob:
W
Wang Yufei 已提交
2342
    libxlDomainObjEndJob(driver, vm);
2343

2344
 cleanup:
2345
    VIR_FREE(bitmask);
W
Wang Yufei 已提交
2346 2347
    virDomainObjEndAPI(&vm);
    virObjectUnref(cfg);
2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362
    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;
2363
    bool active;
2364 2365 2366 2367 2368

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

J
Jim Fehlig 已提交
2369
    if (!(vm = libxlDomObjFromDomain(dom)))
2370 2371
        goto cleanup;

2372
    if (virDomainGetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
2373 2374
        goto cleanup;

2375 2376 2377 2378 2379 2380 2381 2382 2383
    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)) {
2384 2385
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid flag combination: (0x%x)"), flags);
2386 2387 2388
        return -1;
    }

2389
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
2390
        if (!active) {
2391 2392
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("Domain is not running"));
2393 2394 2395 2396
            goto cleanup;
        }
        def = vm->def;
    } else {
2397
        if (!vm->persistent) {
2398 2399
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is transient"));
2400 2401
            goto cleanup;
        }
2402 2403 2404
        def = vm->newDef ? vm->newDef : vm->def;
    }

2405 2406 2407
    if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
        ret = virDomainDefGetVcpusMax(def);
    else
2408
        ret = virDomainDefGetVcpus(def);
2409

2410
 cleanup:
2411
    virDomainObjEndAPI(&vm);
2412 2413 2414
    return ret;
}

2415 2416 2417 2418 2419 2420 2421
static int
libxlDomainGetMaxVcpus(virDomainPtr dom)
{
    return libxlDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
                                          VIR_DOMAIN_VCPU_MAXIMUM));
}

2422
static int
2423 2424 2425
libxlDomainPinVcpuFlags(virDomainPtr dom, unsigned int vcpu,
                        unsigned char *cpumap, int maplen,
                        unsigned int flags)
2426 2427
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
2428
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2429
    virDomainDefPtr targetDef = NULL;
2430
    virBitmapPtr pcpumap = NULL;
2431
    virDomainVcpuDefPtr vcpuinfo;
2432 2433
    virDomainObjPtr vm;
    int ret = -1;
2434 2435 2436

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
2437

J
Jim Fehlig 已提交
2438
    if (!(vm = libxlDomObjFromDomain(dom)))
2439 2440
        goto cleanup;

2441
    if (virDomainPinVcpuFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
2442 2443
        goto cleanup;

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

2447 2448
    if (virDomainLiveConfigHelperMethod(cfg->caps, driver->xmlopt, vm,
                                        &flags, &targetDef) < 0)
2449
        goto endjob;
2450

2451
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
2452 2453 2454 2455 2456
        targetDef = vm->def;

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

2457 2458
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
2459
        goto endjob;
2460

2461 2462 2463 2464 2465 2466 2467
    if (!(vcpuinfo = virDomainDefGetVcpu(targetDef, vcpu)) ||
        !vcpuinfo->online) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("vcpu '%u' is not active"), vcpu);
        goto endjob;
    }

2468 2469
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        libxl_bitmap map = { .size = maplen, .map = cpumap };
J
Jim Fehlig 已提交
2470
        if (libxl_set_vcpuaffinity(cfg->ctx, vm->def->id, vcpu, &map, NULL) != 0) {
2471 2472 2473
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to pin vcpu '%d' with libxenlight"),
                           vcpu);
2474
            goto endjob;
2475
        }
2476
    }
2477

2478 2479 2480
    virBitmapFree(vcpuinfo->cpumask);
    vcpuinfo->cpumask = pcpumap;
    pcpumap = NULL;
2481

2482 2483
    ret = 0;

2484
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2485
        ret = virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps);
2486
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2487
        ret = virDomainSaveConfig(cfg->configDir, cfg->caps, targetDef);
2488 2489
    }

2490
 endjob:
W
Wang Yufei 已提交
2491
    libxlDomainObjEndJob(driver, vm);
2492

2493
 cleanup:
W
Wang Yufei 已提交
2494
    virDomainObjEndAPI(&vm);
2495
    virBitmapFree(pcpumap);
2496
    virObjectUnref(cfg);
2497 2498 2499
    return ret;
}

2500 2501 2502 2503 2504 2505 2506 2507
static int
libxlDomainPinVcpu(virDomainPtr dom, unsigned int vcpu, unsigned char *cpumap,
                   int maplen)
{
    return libxlDomainPinVcpuFlags(dom, vcpu, cpumap, maplen,
                                   VIR_DOMAIN_AFFECT_LIVE);
}

2508 2509 2510 2511 2512 2513 2514 2515 2516
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;
2517
    int ret = -1;
2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531

    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;

2532
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
2533 2534 2535 2536 2537
        targetDef = vm->def;

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

2538 2539
    ret = virDomainDefGetVcpuPinInfoHelper(targetDef, maplen, ncpumaps, cpumaps,
                                           libxl_get_max_cpus(cfg->ctx), NULL);
2540

2541
 cleanup:
2542
    virDomainObjEndAPI(&vm);
2543 2544 2545
    virObjectUnref(cfg);
    return ret;
}
2546 2547 2548 2549 2550

static int
libxlDomainGetVcpus(virDomainPtr dom, virVcpuInfoPtr info, int maxinfo,
                    unsigned char *cpumaps, int maplen)
{
J
Jim Fehlig 已提交
2551 2552
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2553 2554 2555 2556
    virDomainObjPtr vm;
    int ret = -1;
    libxl_vcpuinfo *vcpuinfo;
    int maxcpu, hostcpus;
2557
    size_t i;
2558 2559
    unsigned char *cpumap;

J
Jim Fehlig 已提交
2560
    if (!(vm = libxlDomObjFromDomain(dom)))
2561 2562
        goto cleanup;

2563 2564 2565
    if (virDomainGetVcpusEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2566
    if (virDomainObjCheckActive(vm) < 0)
2567 2568
        goto cleanup;

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

    ret = maxinfo;

2602
 cleanup:
2603
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
2604
    virObjectUnref(cfg);
2605 2606 2607
    return ret;
}

J
Jim Fehlig 已提交
2608
static char *
2609
libxlDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
2610
{
2611 2612
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
2613
    virDomainObjPtr vm;
2614
    virDomainDefPtr def;
J
Jim Fehlig 已提交
2615 2616
    char *ret = NULL;

2617
    virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
2618

J
Jim Fehlig 已提交
2619
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
2620 2621
        goto cleanup;

2622 2623 2624
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

2625 2626 2627 2628 2629
    if ((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef)
        def = vm->newDef;
    else
        def = vm->def;

2630
    ret = virDomainDefFormat(def, cfg->caps,
2631
                             virDomainDefFormatConvertXMLFlags(flags));
J
Jim Fehlig 已提交
2632

2633
 cleanup:
2634
    virDomainObjEndAPI(&vm);
2635
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
2636 2637 2638
    return ret;
}

2639
static char *
2640 2641 2642
libxlConnectDomainXMLFromNative(virConnectPtr conn,
                                const char *nativeFormat,
                                const char *nativeConfig,
2643
                                unsigned int flags)
2644 2645
{
    libxlDriverPrivatePtr driver = conn->privateData;
2646
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2647 2648 2649 2650
    virDomainDefPtr def = NULL;
    virConfPtr conf = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2651 2652
    virCheckFlags(0, NULL);

2653 2654 2655
    if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0)
        goto cleanup;

2656
    if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XL)) {
J
Ján Tomko 已提交
2657
        if (!(conf = virConfReadString(nativeConfig, 0)))
2658 2659 2660
            goto cleanup;
        if (!(def = xenParseXL(conf,
                               cfg->caps,
2661
                               driver->xmlopt)))
2662
            goto cleanup;
2663
    } else if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XM)) {
J
Ján Tomko 已提交
2664
        if (!(conf = virConfReadString(nativeConfig, 0)))
2665 2666 2667
            goto cleanup;

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

2688
    xml = virDomainDefFormat(def, cfg->caps, VIR_DOMAIN_DEF_FORMAT_INACTIVE);
2689

2690
 cleanup:
2691 2692 2693
    virDomainDefFree(def);
    if (conf)
        virConfFree(conf);
2694
    virObjectUnref(cfg);
2695 2696 2697 2698 2699
    return xml;
}

#define MAX_CONFIG_SIZE (1024 * 65)
static char *
2700 2701 2702
libxlConnectDomainXMLToNative(virConnectPtr conn, const char * nativeFormat,
                              const char * domainXml,
                              unsigned int flags)
2703 2704
{
    libxlDriverPrivatePtr driver = conn->privateData;
2705
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2706 2707 2708 2709 2710
    virDomainDefPtr def = NULL;
    virConfPtr conf = NULL;
    int len = MAX_CONFIG_SIZE;
    char *ret = NULL;

E
Eric Blake 已提交
2711 2712
    virCheckFlags(0, NULL);

2713 2714 2715
    if (virConnectDomainXMLToNativeEnsureACL(conn) < 0)
        goto cleanup;

2716
    if (!(def = virDomainDefParseString(domainXml,
2717
                                        cfg->caps, driver->xmlopt, NULL,
2718
                                        VIR_DOMAIN_DEF_PARSE_INACTIVE)))
2719 2720
        goto cleanup;

2721
    if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XL)) {
2722
        if (!(conf = xenFormatXL(def, conn)))
2723
            goto cleanup;
2724
    } else if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XM)) {
2725
        if (!(conf = xenFormatXM(conn, def)))
2726 2727 2728 2729 2730
            goto cleanup;
    } else {

        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), nativeFormat);
2731
        goto cleanup;
2732
    }
2733

2734
    if (VIR_ALLOC_N(ret, len) < 0)
2735 2736 2737 2738 2739 2740 2741
        goto cleanup;

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

2742
 cleanup:
2743 2744 2745
    virDomainDefFree(def);
    if (conf)
        virConfFree(conf);
2746
    virObjectUnref(cfg);
2747 2748 2749
    return ret;
}

J
Jim Fehlig 已提交
2750
static int
2751 2752
libxlConnectListDefinedDomains(virConnectPtr conn,
                               char **const names, int nnames)
J
Jim Fehlig 已提交
2753 2754 2755 2756
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

2757 2758 2759
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

2760 2761
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         virConnectListDefinedDomainsCheckACL, conn);
J
Jim Fehlig 已提交
2762 2763 2764 2765
    return n;
}

static int
2766
libxlConnectNumOfDefinedDomains(virConnectPtr conn)
J
Jim Fehlig 已提交
2767 2768 2769 2770
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

2771 2772 2773
    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        return -1;

2774
    n = virDomainObjListNumOfDomains(driver->domains, false,
2775 2776
                                     virConnectNumOfDefinedDomainsCheckACL,
                                     conn);
J
Jim Fehlig 已提交
2777 2778 2779 2780 2781
    return n;
}

static int
libxlDomainCreateWithFlags(virDomainPtr dom,
E
Eric Blake 已提交
2782
                           unsigned int flags)
J
Jim Fehlig 已提交
2783 2784 2785 2786 2787 2788 2789
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_START_PAUSED, -1);

J
Jim Fehlig 已提交
2790
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
2791 2792
        goto cleanup;

2793 2794 2795
    if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

J
Jim Fehlig 已提交
2799
    if (virDomainObjIsActive(vm)) {
2800 2801
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is already running"));
2802
        goto endjob;
J
Jim Fehlig 已提交
2803 2804
    }

2805 2806
    ret = libxlDomainStartNew(driver, vm,
                              (flags & VIR_DOMAIN_START_PAUSED) != 0);
2807
    if (ret < 0)
2808
        goto endjob;
2809
    dom->id = vm->def->id;
J
Jim Fehlig 已提交
2810

2811
 endjob:
W
Wang Yufei 已提交
2812
    libxlDomainObjEndJob(driver, vm);
2813

2814
 cleanup:
W
Wang Yufei 已提交
2815
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
2816 2817 2818 2819 2820 2821 2822 2823 2824 2825
    return ret;
}

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

static virDomainPtr
2826
libxlDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
J
Jim Fehlig 已提交
2827 2828
{
    libxlDriverPrivatePtr driver = conn->privateData;
2829
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
2830 2831 2832
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    virDomainPtr dom = NULL;
2833
    virObjectEventPtr event = NULL;
2834
    virDomainDefPtr oldDef = NULL;
2835
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
J
Jim Fehlig 已提交
2836

2837 2838 2839
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
2840
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
2841

2842
    if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt,
2843
                                        NULL, parse_flags)))
2844
        goto cleanup;
J
Jim Fehlig 已提交
2845

2846 2847 2848
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        goto cleanup;

2849
    if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
2850
        goto cleanup;
2851

2852
    if (!(vm = virDomainObjListAdd(driver->domains, def,
2853
                                   driver->xmlopt,
2854 2855
                                   0,
                                   &oldDef)))
2856
        goto cleanup;
J
Jim Fehlig 已提交
2857
    def = NULL;
2858

J
Jim Fehlig 已提交
2859 2860
    vm->persistent = 1;

2861
    if (virDomainSaveConfig(cfg->configDir,
2862
                            cfg->caps,
J
Jim Fehlig 已提交
2863
                            vm->newDef ? vm->newDef : vm->def) < 0) {
2864
        virDomainObjListRemove(driver->domains, vm);
J
Jim Fehlig 已提交
2865 2866 2867
        goto cleanup;
    }

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

2870
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_DEFINED,
2871
                                     !oldDef ?
2872 2873 2874
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

2875
 cleanup:
J
Jim Fehlig 已提交
2876
    virDomainDefFree(def);
2877
    virDomainDefFree(oldDef);
2878
    virDomainObjEndAPI(&vm);
2879
    virObjectEventStateQueue(driver->domainEventState, event);
2880
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
2881 2882 2883
    return dom;
}

2884 2885 2886 2887 2888 2889
static virDomainPtr
libxlDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return libxlDomainDefineXMLFlags(conn, xml, 0);
}

J
Jim Fehlig 已提交
2890
static int
2891 2892
libxlDomainUndefineFlags(virDomainPtr dom,
                         unsigned int flags)
J
Jim Fehlig 已提交
2893 2894
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
2895
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
2896
    virDomainObjPtr vm;
2897
    virObjectEventPtr event = NULL;
2898
    char *name = NULL;
J
Jim Fehlig 已提交
2899 2900
    int ret = -1;

2901 2902
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE, -1);

J
Jim Fehlig 已提交
2903
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
2904 2905
        goto cleanup;

2906 2907 2908
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
2909
    if (!vm->persistent) {
2910 2911
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
J
Jim Fehlig 已提交
2912 2913 2914
        goto cleanup;
    }

2915 2916 2917 2918 2919 2920 2921
    name = libxlDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    if (virFileExists(name)) {
        if (flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE) {
            if (unlink(name) < 0) {
2922 2923
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to remove domain managed save image"));
2924 2925 2926
                goto cleanup;
            }
        } else {
2927 2928 2929
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Refusing to undefine while domain managed "
                             "save image exists"));
2930 2931 2932 2933
            goto cleanup;
        }
    }

2934
    if (virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm) < 0)
J
Jim Fehlig 已提交
2935 2936
        goto cleanup;

2937
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_UNDEFINED,
2938 2939
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

2940
    if (virDomainObjIsActive(vm))
2941
        vm->persistent = 0;
2942
    else
2943
        virDomainObjListRemove(driver->domains, vm);
2944

J
Jim Fehlig 已提交
2945 2946
    ret = 0;

2947
 cleanup:
2948
    VIR_FREE(name);
2949
    virDomainObjEndAPI(&vm);
2950
    virObjectEventStateQueue(driver->domainEventState, event);
2951
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
2952 2953 2954
    return ret;
}

2955 2956 2957 2958 2959 2960
static int
libxlDomainUndefine(virDomainPtr dom)
{
    return libxlDomainUndefineFlags(dom, 0);
}

2961
static int
J
Jim Fehlig 已提交
2962
libxlDomainChangeEjectableMedia(virDomainObjPtr vm, virDomainDiskDefPtr disk)
2963
{
J
Jim Fehlig 已提交
2964
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(libxl_driver);
2965 2966
    virDomainDiskDefPtr origdisk = NULL;
    libxl_device_disk x_disk;
2967
    size_t i;
2968 2969
    int ret = -1;

2970
    for (i = 0; i < vm->def->ndisks; i++) {
2971 2972 2973 2974 2975 2976 2977 2978
        if (vm->def->disks[i]->bus == disk->bus &&
            STREQ(vm->def->disks[i]->dst, disk->dst)) {
            origdisk = vm->def->disks[i];
            break;
        }
    }

    if (!origdisk) {
2979 2980 2981
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No device with bus '%s' and target '%s'"),
                       virDomainDiskBusTypeToString(disk->bus), disk->dst);
2982 2983 2984 2985
        goto cleanup;
    }

    if (origdisk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
2986 2987 2988
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Removable media not supported for %s device"),
                       virDomainDiskDeviceTypeToString(disk->device));
2989 2990 2991
        return -1;
    }

J
Jim Fehlig 已提交
2992
    if (libxlMakeDisk(disk, &x_disk) < 0)
2993 2994
        goto cleanup;

J
Jim Fehlig 已提交
2995
    if ((ret = libxl_cdrom_insert(cfg->ctx, vm->def->id, &x_disk, NULL)) < 0) {
2996 2997 2998
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to change media for disk '%s'"),
                       disk->dst);
2999 3000 3001
        goto cleanup;
    }

3002 3003 3004
    if (virDomainDiskSetSource(origdisk, virDomainDiskGetSource(disk)) < 0)
        goto cleanup;
    virDomainDiskSetType(origdisk, virDomainDiskGetType(disk));
3005 3006 3007 3008 3009

    virDomainDiskDefFree(disk);

    ret = 0;

3010
 cleanup:
J
Jim Fehlig 已提交
3011
    virObjectUnref(cfg);
3012 3013 3014 3015
    return ret;
}

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

3035
                if (!virDomainDiskGetSource(l_disk)) {
3036 3037
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("disk source path is missing"));
3038 3039 3040
                    goto cleanup;
                }

3041
                if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
3042 3043
                    goto cleanup;

J
Jim Fehlig 已提交
3044
                if (libxlMakeDisk(l_disk, &x_disk) < 0)
3045 3046
                    goto cleanup;

3047 3048 3049
                if (virDomainLockImageAttach(libxl_driver->lockManager,
                                             "xen:///system",
                                             vm, l_disk->src) < 0)
3050 3051
                    goto cleanup;

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

3065
                libxlUpdateDiskDef(l_disk, &x_disk);
3066 3067 3068
                virDomainDiskInsertPreAlloced(vm->def, l_disk);

            } else {
3069 3070 3071
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("disk bus '%s' cannot be hotplugged."),
                               virDomainDiskBusTypeToString(l_disk->bus));
3072 3073 3074
            }
            break;
        default:
3075 3076 3077
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("disk device type '%s' cannot be hotplugged"),
                           virDomainDiskDeviceTypeToString(l_disk->device));
3078 3079 3080
            break;
    }

3081
 cleanup:
J
Jim Fehlig 已提交
3082
    virObjectUnref(cfg);
3083 3084 3085
    return ret;
}

3086 3087 3088 3089 3090
static int
libxlDomainAttachHostPCIDevice(libxlDriverPrivatePtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
J
Jim Fehlig 已提交
3091
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3092
    libxl_device_pci pcidev;
3093 3094
    virDomainHostdevDefPtr found;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
3095
    virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
J
Jim Fehlig 已提交
3096
    int ret = -1;
3097

3098 3099
    libxl_device_pci_init(&pcidev);

3100 3101 3102
    if (virDomainHostdevFind(vm->def, hostdev, &found) >= 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("target pci device %.4x:%.2x:%.2x.%.1x already exists"),
3103 3104
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
J
Jim Fehlig 已提交
3105
        goto cleanup;
3106 3107 3108
    }

    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
J
Jim Fehlig 已提交
3109
        goto cleanup;
3110 3111 3112 3113

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

3116
    if (libxlMakePCI(hostdev, &pcidev) < 0)
C
Chunyan Liu 已提交
3117
        goto error;
3118

J
Jim Fehlig 已提交
3119
    if (libxl_device_pci_add(cfg->ctx, vm->def->id, &pcidev, 0) < 0) {
3120 3121
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to attach pci device %.4x:%.2x:%.2x.%.1x"),
3122 3123
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
C
Chunyan Liu 已提交
3124
        goto error;
3125 3126 3127
    }

    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
J
Jim Fehlig 已提交
3128 3129
    ret = 0;
    goto cleanup;
3130

3131
 error:
3132 3133
    virHostdevReAttachPCIDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                 vm->def->name, &hostdev, 1, NULL);
J
Jim Fehlig 已提交
3134 3135 3136

 cleanup:
    virObjectUnref(cfg);
3137
    libxl_device_pci_dispose(&pcidev);
J
Jim Fehlig 已提交
3138
    return ret;
3139 3140
}

3141
#ifdef LIBXL_HAVE_PVUSB
3142 3143 3144 3145 3146 3147 3148 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
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;
}

3196 3197 3198 3199 3200 3201 3202 3203 3204
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;
3205 3206
    size_t i;
    int ports = 0, usbdevs = 0;
3207 3208 3209 3210 3211 3212 3213

    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;

3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243
    /* 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;
        }
    }

3244 3245 3246 3247 3248 3249 3250 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
    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

3277 3278 3279
static int
libxlDomainAttachHostDevice(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3280
                            virDomainHostdevDefPtr hostdev)
3281 3282 3283 3284 3285 3286 3287 3288 3289 3290
{
    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 已提交
3291
        if (libxlDomainAttachHostPCIDevice(driver, vm, hostdev) < 0)
C
Chunyan Liu 已提交
3292
            return -1;
3293 3294
        break;

3295 3296 3297 3298 3299 3300 3301
#ifdef LIBXL_HAVE_PVUSB
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        if (libxlDomainAttachHostUSBDevice(driver, vm, hostdev) < 0)
            return -1;
        break;
#endif

3302 3303 3304 3305
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("hostdev subsys type '%s' not supported"),
                       virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
C
Chunyan Liu 已提交
3306
        return -1;
3307 3308 3309 3310 3311
    }

    return 0;
}

3312
static int
J
Jim Fehlig 已提交
3313
libxlDomainDetachDeviceDiskLive(virDomainObjPtr vm, virDomainDeviceDefPtr dev)
3314
{
J
Jim Fehlig 已提交
3315
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(libxl_driver);
3316 3317
    virDomainDiskDefPtr l_disk = NULL;
    libxl_device_disk x_disk;
3318
    int idx;
3319 3320 3321 3322 3323 3324
    int ret = -1;

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

3325 3326 3327
                if ((idx = virDomainDiskIndexByName(vm->def,
                                                    dev->data.disk->dst,
                                                    false)) < 0) {
3328 3329
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("disk %s not found"), dev->data.disk->dst);
3330 3331 3332
                    goto cleanup;
                }

3333
                l_disk = vm->def->disks[idx];
3334

J
Jim Fehlig 已提交
3335
                if (libxlMakeDisk(l_disk, &x_disk) < 0)
3336 3337
                    goto cleanup;

J
Jim Fehlig 已提交
3338
                if ((ret = libxl_device_disk_remove(cfg->ctx, vm->def->id,
J
Jim Fehlig 已提交
3339
                                                    &x_disk, NULL)) < 0) {
3340 3341 3342
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("libxenlight failed to detach disk '%s'"),
                                   l_disk->dst);
3343 3344 3345
                    goto cleanup;
                }

3346 3347
                if (virDomainLockImageDetach(libxl_driver->lockManager,
                                             vm, l_disk->src) < 0)
3348 3349 3350
                    VIR_WARN("Unable to release lock on %s",
                             virDomainDiskGetSource(l_disk));

3351
                virDomainDiskRemove(vm->def, idx);
3352 3353 3354
                virDomainDiskDefFree(l_disk);

            } else {
3355 3356 3357
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("disk bus '%s' cannot be hot unplugged."),
                               virDomainDiskBusTypeToString(dev->data.disk->bus));
3358 3359 3360
            }
            break;
        default:
3361 3362 3363
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot hot unplugged"),
                           virDomainDiskDeviceTypeToString(dev->data.disk->device));
3364 3365 3366
            break;
    }

3367
 cleanup:
J
Jim Fehlig 已提交
3368
    virObjectUnref(cfg);
3369 3370 3371
    return ret;
}

3372 3373 3374 3375 3376
static int
libxlDomainAttachNetDevice(libxlDriverPrivatePtr driver,
                           virDomainObjPtr vm,
                           virDomainNetDefPtr net)
{
J
Jim Fehlig 已提交
3377
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3378
    virDomainNetType actualType;
3379 3380
    libxl_device_nic nic;
    int ret = -1;
3381
    char mac[VIR_MAC_STRING_BUFLEN];
3382

3383 3384
    libxl_device_nic_init(&nic);

3385 3386
    /* preallocate new slot for device */
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
3387
        goto cleanup;
3388 3389 3390 3391 3392

    /* 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.
     */
3393 3394
    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        virDomainNetAllocateActualDevice(vm->def, net) < 0)
3395
        goto cleanup;
3396 3397 3398

    actualType = virDomainNetGetActualType(net);

3399 3400 3401 3402
    if (virDomainHasNet(vm->def, net)) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("network device with mac %s already exists"),
                       virMacAddrFormat(&net->mac, mac));
3403
        goto cleanup;
3404 3405
    }

3406
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417
        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;

3418 3419 3420
        /* 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
3421
         * the nets list if successful.
3422
         */
3423
        ret = libxlDomainAttachHostDevice(driver, vm, hostdev);
3424
        goto cleanup;
3425 3426
    }

3427
    if (libxlMakeNic(vm->def, net, &nic, true) < 0)
3428 3429
        goto cleanup;

J
Jim Fehlig 已提交
3430
    if (libxl_device_nic_add(cfg->ctx, vm->def->id, &nic, 0)) {
3431 3432 3433 3434 3435 3436 3437 3438 3439
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight failed to attach network device"));
        goto cleanup;
    }

    ret = 0;

 cleanup:
    libxl_device_nic_dispose(&nic);
3440 3441 3442
    if (!ret) {
        vm->def->nets[vm->def->nnets++] = net;
    } else {
3443
        virDomainNetRemoveHostdev(vm->def, net);
3444 3445
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK)
            virDomainNetReleaseActualDevice(vm->def, net);
3446
    }
J
Jim Fehlig 已提交
3447
    virObjectUnref(cfg);
3448 3449 3450
    return ret;
}

3451
static int
3452 3453
libxlDomainAttachDeviceLive(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3454 3455 3456 3457 3458 3459
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
J
Jim Fehlig 已提交
3460
            ret = libxlDomainAttachDeviceDiskLive(vm, dev);
3461 3462 3463 3464
            if (!ret)
                dev->data.disk = NULL;
            break;

3465
#ifdef LIBXL_HAVE_PVUSB
3466 3467 3468 3469 3470
        case VIR_DOMAIN_DEVICE_CONTROLLER:
            ret = libxlDomainAttachControllerDevice(driver, vm, dev->data.controller);
            if (!ret)
                dev->data.controller = NULL;
            break;
3471
#endif
3472

3473
        case VIR_DOMAIN_DEVICE_NET:
J
Jim Fehlig 已提交
3474
            ret = libxlDomainAttachNetDevice(driver, vm,
3475 3476 3477 3478 3479
                                             dev->data.net);
            if (!ret)
                dev->data.net = NULL;
            break;

3480
        case VIR_DOMAIN_DEVICE_HOSTDEV:
J
Jim Fehlig 已提交
3481
            ret = libxlDomainAttachHostDevice(driver, vm,
3482
                                              dev->data.hostdev);
3483 3484 3485 3486
            if (!ret)
                dev->data.hostdev = NULL;
            break;

3487
        default:
3488 3489 3490
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be attached"),
                           virDomainDeviceTypeToString(dev->type));
3491 3492 3493 3494 3495 3496 3497 3498 3499 3500
            break;
    }

    return ret;
}

static int
libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{
    virDomainDiskDefPtr disk;
3501
    virDomainNetDefPtr net;
3502
    virDomainHostdevDefPtr hostdev;
3503
    virDomainControllerDefPtr controller;
3504
    virDomainHostdevDefPtr found;
3505
    char mac[VIR_MAC_STRING_BUFLEN];
3506 3507 3508 3509

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

3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535
        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;

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

3549 3550 3551
        case VIR_DOMAIN_DEVICE_HOSTDEV:
            hostdev = dev->data.hostdev;

3552 3553 3554 3555 3556 3557
            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:
3558
                return -1;
3559
            }
3560 3561

            if (virDomainHostdevFind(vmdef, hostdev, &found) >= 0) {
3562 3563
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("device is already in the domain configuration"));
3564 3565 3566
                return -1;
            }

3567 3568
            if (virDomainHostdevInsert(vmdef, hostdev) < 0)
                return -1;
3569
            dev->data.hostdev = NULL;
3570
            break;
3571 3572

        default:
3573 3574
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("persistent attach of device is not supported"));
3575 3576 3577 3578 3579 3580
            return -1;
    }
    return 0;
}

static int
3581 3582 3583 3584 3585 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
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 已提交
3614
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3615
    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
3616
    virDomainHostdevSubsysPCIPtr pcisrc = &subsys->u.pci;
3617 3618 3619 3620
    libxl_device_pci pcidev;
    virDomainHostdevDefPtr detach;
    int idx;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
J
Jim Fehlig 已提交
3621
    int ret = -1;
3622

3623 3624
    libxl_device_pci_init(&pcidev);

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

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


3643
    if (libxlMakePCI(detach, &pcidev) < 0)
C
Chunyan Liu 已提交
3644
        goto error;
3645

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


    virDomainHostdevRemove(vm->def, idx);

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

J
Jim Fehlig 已提交
3661
    ret = 0;
3662

3663
 error:
3664
    virDomainHostdevDefFree(detach);
J
Jim Fehlig 已提交
3665 3666 3667

 cleanup:
    virObjectUnref(cfg);
3668
    libxl_device_pci_dispose(&pcidev);
J
Jim Fehlig 已提交
3669
    return ret;
3670 3671
}

3672
#ifdef LIBXL_HAVE_PVUSB
3673 3674 3675 3676 3677 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
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;
}

3724 3725 3726 3727 3728 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
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,
3772 3773
                       _("libxenlight failed to detach USB device "
                         "Busnum: %3x, Devnum: %3x"),
3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792
                       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

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

3811 3812 3813 3814 3815
#ifdef LIBXL_HAVE_PVUSB
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
            return libxlDomainDetachHostUSBDevice(driver, vm, hostdev);
#endif

3816 3817 3818 3819 3820 3821 3822 3823 3824
        default:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected hostdev type %d"), subsys->type);
            break;
    }

    return -1;
}

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

3837 3838
    libxl_device_nic_init(&nic);

3839
    if ((detachidx = virDomainNetFindIdx(vm->def, net)) < 0)
3840
        goto cleanup;
3841 3842 3843 3844 3845 3846 3847

    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 已提交
3848
        ret = libxlDomainDetachHostDevice(driver, vm,
3849
                                          virDomainNetGetActualHostdev(detach));
3850
        goto cleanup;
3851 3852
    }

J
Jim Fehlig 已提交
3853
    if (libxl_mac_to_device_nic(cfg->ctx, vm->def->id,
3854 3855 3856
                                virMacAddrFormat(&detach->mac, mac), &nic))
        goto cleanup;

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

3876 3877 3878
static int
libxlDomainDetachDeviceLive(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3879 3880
                            virDomainDeviceDefPtr dev)
{
3881
    virDomainHostdevDefPtr hostdev;
3882 3883 3884 3885
    int ret = -1;

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

3889
#ifdef LIBXL_HAVE_PVUSB
3890 3891 3892
        case VIR_DOMAIN_DEVICE_CONTROLLER:
            ret = libxlDomainDetachControllerDevice(driver, vm, dev);
            break;
3893
#endif
3894

3895
        case VIR_DOMAIN_DEVICE_NET:
J
Jim Fehlig 已提交
3896
            ret = libxlDomainDetachNetDevice(driver, vm,
3897 3898 3899
                                             dev->data.net);
            break;

3900
        case VIR_DOMAIN_DEVICE_HOSTDEV:
3901 3902 3903 3904 3905 3906 3907 3908 3909 3910
            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);
3911 3912
            break;

3913
        default:
3914 3915 3916
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be detached"),
                           virDomainDeviceTypeToString(dev->type));
3917 3918 3919 3920 3921 3922
            break;
    }

    return ret;
}

3923

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

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

3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955
        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;

3956 3957 3958 3959 3960 3961 3962 3963 3964
        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;

3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976
        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;
        }

3977
        default:
3978 3979
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("persistent detach of device is not supported"));
3980
            return -1;
3981 3982
    }

3983
    return 0;
3984 3985 3986
}

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

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

    ret = 0;

4054
 cleanup:
4055 4056 4057 4058 4059
    return ret;
}


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

4076 4077 4078
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

4082 4083
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;
4084 4085

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
4086
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
4087
                                            cfg->caps, driver->xmlopt,
4088
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
4089
            goto endjob;
4090 4091

        /* Make a copy for updated domain. */
4092
        if (!(vmdef = virDomainObjCopyPersistentDef(vm, cfg->caps,
4093
                                                    driver->xmlopt)))
4094
            goto endjob;
4095

4096
        if (libxlDomainAttachDeviceConfig(vmdef, dev) < 0)
4097
            goto endjob;
4098
    }
4099 4100 4101 4102

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

J
Jim Fehlig 已提交
4108
        if (libxlDomainAttachDeviceLive(driver, vm, dev) < 0)
4109
            goto endjob;
4110

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

4119 4120
    ret = 0;

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

4130
 endjob:
W
Wang Yufei 已提交
4131
    libxlDomainObjEndJob(driver, vm);
4132

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

4165 4166 4167
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

4171 4172
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;
4173 4174 4175

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
4176
                                            cfg->caps, driver->xmlopt,
4177 4178
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                            VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
4179
            goto endjob;
4180 4181

        /* Make a copy for updated domain. */
4182
        if (!(vmdef = virDomainObjCopyPersistentDef(vm, cfg->caps,
4183
                                                    driver->xmlopt)))
4184
            goto endjob;
4185

4186
        if (libxlDomainDetachDeviceConfig(vmdef, dev) < 0)
4187
            goto endjob;
4188 4189 4190 4191 4192 4193
    }

    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,
4194
                                            cfg->caps, driver->xmlopt,
4195 4196
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                            VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
4197
            goto endjob;
4198

J
Jim Fehlig 已提交
4199
        if (libxlDomainDetachDeviceLive(driver, vm, dev) < 0)
4200
            goto endjob;
4201 4202 4203 4204 4205

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

4210 4211
    ret = 0;

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

4221
 endjob:
W
Wang Yufei 已提交
4222
    libxlDomainObjEndJob(driver, vm);
4223

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

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

4256 4257 4258
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4259 4260
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto cleanup;
4261 4262 4263

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
4264
                                            cfg->caps, driver->xmlopt,
4265
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
4266 4267 4268
            goto cleanup;

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

J
Jim Fehlig 已提交
4287
        if ((ret = libxlDomainUpdateDeviceLive(vm, dev)) < 0)
4288 4289 4290 4291 4292 4293
            goto cleanup;

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

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

4307
 cleanup:
4308 4309
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
4310
    virDomainObjEndAPI(&vm);
4311
    virObjectUnref(cfg);
4312
    return ret;
4313 4314
}

4315 4316 4317 4318 4319
static unsigned long long
libxlNodeGetFreeMemory(virConnectPtr conn)
{
    libxl_physinfo phy_info;
    libxlDriverPrivatePtr driver = conn->privateData;
4320 4321
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    unsigned long long ret = 0;
4322

4323
    libxl_physinfo_init(&phy_info);
4324
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
4325
        goto cleanup;
4326

4327
    if (libxl_get_physinfo(cfg->ctx, &phy_info)) {
4328 4329
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxl_get_physinfo_info failed"));
4330
        goto cleanup;
4331 4332
    }

4333 4334
    ret = phy_info.free_pages * cfg->verInfo->pagesize;

4335
 cleanup:
4336
    libxl_physinfo_dispose(&phy_info);
4337 4338
    virObjectUnref(cfg);
    return ret;
4339 4340
}

4341 4342 4343 4344 4345 4346 4347 4348 4349 4350
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;
4351
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4352 4353

    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
4354
        goto cleanup;
4355

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

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

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

4381 4382
    ret = numCells;

4383
 cleanup:
4384
    libxl_numainfo_list_free(numa_info, nr_nodes);
4385
    virObjectUnref(cfg);
4386 4387 4388
    return ret;
}

4389
static int
4390
libxlConnectDomainEventRegister(virConnectPtr conn,
4391 4392
                                virConnectDomainEventCallback callback,
                                void *opaque,
4393
                                virFreeCallback freecb)
4394 4395 4396
{
    libxlDriverPrivatePtr driver = conn->privateData;

4397 4398 4399
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

4400 4401 4402 4403
    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        return -1;
4404

4405
    return 0;
4406 4407 4408 4409
}


static int
4410 4411
libxlConnectDomainEventDeregister(virConnectPtr conn,
                                  virConnectDomainEventCallback callback)
4412 4413 4414
{
    libxlDriverPrivatePtr driver = conn->privateData;

4415 4416 4417
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

4418 4419 4420 4421
    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        return -1;
4422

4423
    return 0;
4424 4425
}

4426 4427 4428 4429 4430 4431
static int
libxlDomainGetAutostart(virDomainPtr dom, int *autostart)
{
    virDomainObjPtr vm;
    int ret = -1;

J
Jim Fehlig 已提交
4432
    if (!(vm = libxlDomObjFromDomain(dom)))
4433 4434
        goto cleanup;

4435 4436 4437
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4438 4439 4440
    *autostart = vm->autostart;
    ret = 0;

4441
 cleanup:
4442
    virDomainObjEndAPI(&vm);
4443 4444 4445 4446 4447 4448 4449
    return ret;
}

static int
libxlDomainSetAutostart(virDomainPtr dom, int autostart)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4450
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4451 4452 4453 4454
    virDomainObjPtr vm;
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

J
Jim Fehlig 已提交
4455
    if (!(vm = libxlDomObjFromDomain(dom)))
4456 4457
        goto cleanup;

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

4460 4461 4462
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

4466
    if (!vm->persistent) {
4467 4468
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient domain"));
4469
        goto endjob;
4470 4471 4472 4473 4474
    }

    autostart = (autostart != 0);

    if (vm->autostart != autostart) {
4475
        if (!(configFile = virDomainConfigFile(cfg->configDir, vm->def->name)))
4476
            goto endjob;
4477
        if (!(autostartLink = virDomainConfigFile(cfg->autostartDir, vm->def->name)))
4478
            goto endjob;
4479 4480

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

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

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

4507
 endjob:
W
Wang Yufei 已提交
4508
    libxlDomainObjEndJob(driver, vm);
4509

4510
 cleanup:
4511 4512
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
W
Wang Yufei 已提交
4513
    virDomainObjEndAPI(&vm);
4514
    virObjectUnref(cfg);
4515 4516 4517
    return ret;
}

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

J
Jim Fehlig 已提交
4528
    if (!(vm = libxlDomObjFromDomain(dom)))
4529 4530
        goto cleanup;

4531 4532 4533
    if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4534
    if (virDomainObjCheckActive(vm) < 0)
4535 4536
        goto cleanup;

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

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

4563
    ignore_value(VIR_STRDUP(ret, name));
4564

4565
 cleanup:
4566
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
4567
    virObjectUnref(cfg);
4568 4569 4570
    return ret;
}

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

4584 4585 4586 4587
    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

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

J
Jim Fehlig 已提交
4589
    if (!(vm = libxlDomObjFromDomain(dom)))
4590 4591
        goto cleanup;

4592 4593 4594
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4595
    if (virDomainObjCheckActive(vm) < 0)
4596 4597
        goto cleanup;

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

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

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

4613 4614
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_WEIGHT,
                                VIR_TYPED_PARAM_UINT, sc_info.weight) < 0)
4615 4616
        goto cleanup;

4617
    if (*nparams > 1) {
4618
        if (virTypedParameterAssign(&params[1], VIR_DOMAIN_SCHEDULER_CAP,
4619
                                    VIR_TYPED_PARAM_UINT, sc_info.cap) < 0)
4620
            goto cleanup;
4621 4622
    }

4623 4624
    if (*nparams > XEN_SCHED_CREDIT_NPARAM)
        *nparams = XEN_SCHED_CREDIT_NPARAM;
4625 4626
    ret = 0;

4627
 cleanup:
4628
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
4629
    virObjectUnref(cfg);
4630 4631 4632 4633
    return ret;
}

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

4654
    virCheckFlags(0, -1);
4655 4656 4657 4658 4659 4660
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_SCHEDULER_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
                               VIR_DOMAIN_SCHEDULER_CAP,
                               VIR_TYPED_PARAM_UINT,
                               NULL) < 0)
4661
        return -1;
4662

J
Jim Fehlig 已提交
4663
    if (!(vm = libxlDomObjFromDomain(dom)))
4664 4665
        goto cleanup;

4666 4667 4668
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

4672
    if (virDomainObjCheckActive(vm) < 0)
4673
        goto endjob;
4674

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

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

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

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

4693
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_WEIGHT))
4694
            sc_info.weight = params[i].value.ui;
4695
        else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CAP))
4696 4697 4698
            sc_info.cap = params[i].value.ui;
    }

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

    ret = 0;

4708
 endjob:
W
Wang Yufei 已提交
4709
    libxlDomainObjEndJob(driver, vm);
4710

4711
 cleanup:
W
Wang Yufei 已提交
4712
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
4713
    virObjectUnref(cfg);
4714 4715 4716
    return ret;
}

B
Bamvor Jian Zhang 已提交
4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730

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

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

B
Bamvor Jian Zhang 已提交
4736 4737 4738
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4739
    if (virDomainObjCheckActive(vm) < 0)
B
Bamvor Jian Zhang 已提交
4740 4741 4742
        goto cleanup;

    priv = vm->privateData;
B
Bob Liu 已提交
4743 4744
    if (dev_name) {
        size_t i;
B
Bamvor Jian Zhang 已提交
4745

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

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

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

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

4784
 cleanup:
4785
    virDomainObjEndAPI(&vm);
B
Bamvor Jian Zhang 已提交
4786 4787 4788
    return ret;
}

4789 4790 4791 4792 4793 4794 4795
static int
libxlDomainSetSchedulerParameters(virDomainPtr dom, virTypedParameterPtr params,
                                  int nparams)
{
    return libxlDomainSetSchedulerParametersFlags(dom, params, nparams, 0);
}

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

4827 4828
    libxl_bitmap_init(&nodemap);

J
Jim Fehlig 已提交
4829
    if (!(vm = libxlDomObjFromDomain(dom)))
4830 4831 4832 4833 4834
        goto cleanup;

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

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

        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 已提交
4865
            numnodes = libxl_get_max_nodes(cfg->ctx);
4866 4867 4868
            if (numnodes <= 0)
                goto cleanup;

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

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

4896
            if (!(nodeset = virBitmapFormat(nodes)))
4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912
                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;

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

J
Jim Fehlig 已提交
4923 4924 4925 4926 4927 4928
static int
libxlDomainIsActive(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

J
Jim Fehlig 已提交
4929
    if (!(obj = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
4930
        goto cleanup;
4931 4932 4933 4934

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

J
Jim Fehlig 已提交
4935 4936
    ret = virDomainObjIsActive(obj);

4937
 cleanup:
4938
    virDomainObjEndAPI(&obj);
J
Jim Fehlig 已提交
4939 4940 4941 4942 4943 4944 4945 4946 4947
    return ret;
}

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

J
Jim Fehlig 已提交
4948
    if (!(obj = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
4949
        goto cleanup;
4950 4951 4952 4953

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

J
Jim Fehlig 已提交
4954 4955
    ret = obj->persistent;

4956
 cleanup:
4957
    virDomainObjEndAPI(&obj);
J
Jim Fehlig 已提交
4958 4959 4960
    return ret;
}

4961 4962 4963 4964 4965 4966
static int
libxlDomainIsUpdated(virDomainPtr dom)
{
    virDomainObjPtr vm;
    int ret = -1;

J
Jim Fehlig 已提交
4967
    if (!(vm = libxlDomObjFromDomain(dom)))
4968
        goto cleanup;
4969 4970 4971 4972

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

4973 4974
    ret = vm->updated;

4975
 cleanup:
4976
    virDomainObjEndAPI(&vm);
4977 4978 4979
    return ret;
}

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

4999
    if (virDomainObjCheckActive(vm) < 0)
5000 5001
        goto endjob;

5002
    if (!(net = virDomainNetFind(vm->def, device)))
M
Michal Privoznik 已提交
5003 5004
        goto endjob;

5005
    if (virNetDevTapInterfaceStats(net->ifname, stats,
5006
                                   !virDomainNetTypeSharesHostView(net)) < 0)
M
Michal Privoznik 已提交
5007 5008 5009
        goto endjob;

    ret = 0;
5010 5011

 endjob:
W
Wang Yufei 已提交
5012
    libxlDomainObjEndJob(driver, vm);
5013 5014

 cleanup:
W
Wang Yufei 已提交
5015
    virDomainObjEndAPI(&vm);
5016 5017 5018
    return ret;
}

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

    if (nparams == 0)
        return LIBXL_NB_TOTAL_CPU_STAT_PARAM;

J
Jim Fehlig 已提交
5032 5033 5034
    libxl_dominfo_init(&d_info);
    cfg = libxlDriverConfigGet(driver);

5035 5036 5037 5038
    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 已提交
5039
        goto cleanup;
5040 5041 5042 5043 5044 5045 5046 5047 5048 5049
    }

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

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

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

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

5118
    if (virDomainObjCheckActive(vm) < 0)
5119 5120 5121 5122 5123 5124 5125 5126 5127
        goto cleanup;

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

 cleanup:
5128
    virDomainObjEndAPI(&vm);
5129 5130 5131
    return ret;
}

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

    virCheckFlags(0, -1);

5155
    libxl_dominfo_init(&d_info);
J
Jim Fehlig 已提交
5156 5157
    cfg = libxlDriverConfigGet(driver);

5158 5159 5160 5161 5162 5163 5164 5165 5166
    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;

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

    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 已提交
5185
    libxlDomainObjEndJob(driver, vm);
5186 5187

 cleanup:
5188
    libxl_dominfo_dispose(&d_info);
W
Wang Yufei 已提交
5189
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
5190
    virObjectUnref(cfg);
5191 5192 5193 5194 5195
    return ret;
}

#undef LIBXL_SET_MEMSTAT

5196 5197 5198 5199 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
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:
5228
    virDomainObjEndAPI(&vm);
5229 5230 5231
    return ret;
}

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

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

5331
# define LIBXL_VBD_SECTOR_SIZE 512
5332 5333 5334 5335 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

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

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

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

5526
    if (virDomainObjCheckActive(vm) < 0)
5527 5528 5529 5530 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
        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;

5576
    if (virDomainObjCheckActive(vm) < 0)
5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591
        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;

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

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

5623
static int
5624 5625 5626
libxlConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID,
                                   virConnectDomainEventGenericCallback callback,
                                   void *opaque, virFreeCallback freecb)
5627 5628 5629 5630
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int ret;

5631 5632 5633
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

5634 5635 5636 5637
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID, callback, opaque,
                                      freecb, &ret) < 0)
5638
        ret = -1;
5639 5640 5641 5642 5643 5644

    return ret;
}


static int
5645
libxlConnectDomainEventDeregisterAny(virConnectPtr conn, int callbackID)
5646 5647 5648
{
    libxlDriverPrivatePtr driver = conn->privateData;

5649 5650 5651
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

5652 5653
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
5654
                                        callbackID, true) < 0)
5655
        return -1;
5656

5657
    return 0;
5658 5659
}

J
Jim Fehlig 已提交
5660

5661
static int
5662
libxlConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
5663 5664 5665 5666
{
    return 1;
}

5667
static int
5668 5669 5670
libxlConnectListAllDomains(virConnectPtr conn,
                           virDomainPtr **domains,
                           unsigned int flags)
5671 5672 5673 5674
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
5675
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
5676

5677 5678 5679
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

5680 5681
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
5682 5683 5684 5685

    return ret;
}

5686 5687 5688 5689 5690 5691 5692
/* Which features are supported by this driver? */
static int
libxlConnectSupportsFeature(virConnectPtr conn, int feature)
{
    if (virConnectSupportsFeatureEnsureACL(conn) < 0)
        return -1;

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

5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725
static int
libxlNodeDeviceGetPCIInfo(virNodeDeviceDefPtr def,
                          unsigned *domain,
                          unsigned *bus,
                          unsigned *slot,
                          unsigned *function)
{
    virNodeDevCapsDefPtr cap;

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

C
Chunyan Liu 已提交
5743
    return 0;
5744 5745 5746 5747 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
}

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

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

    ret = 0;
5791
 cleanup:
5792 5793 5794 5795 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
    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 已提交
5834
        goto cleanup;
5835 5836

    ret = 0;
C
Chunyan Liu 已提交
5837

5838
 cleanup:
C
Chunyan Liu 已提交
5839
    virPCIDeviceFree(pci);
5840 5841 5842 5843 5844 5845 5846 5847
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
libxlNodeDeviceReset(virNodeDevicePtr dev)
{
C
Chunyan Liu 已提交
5848
    virPCIDevicePtr pci = NULL;
5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874
    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 已提交
5875
        goto cleanup;
5876 5877

    ret = 0;
C
Chunyan Liu 已提交
5878

5879
 cleanup:
C
Chunyan Liu 已提交
5880
    virPCIDeviceFree(pci);
5881 5882 5883 5884 5885
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

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

5898 5899 5900 5901 5902
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return NULL;
#endif

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

5921 5922
    if (virDomainMigrateBegin3ParamsEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;
J
Jim Fehlig 已提交
5923

5924
    if (virDomainObjCheckActive(vm) < 0)
5925
        goto cleanup;
J
Jim Fehlig 已提交
5926

5927 5928
    xmlout = libxlDomainMigrationSrcBegin(domain->conn, vm, xmlin,
                                          cookieout, cookieoutlen);
5929 5930 5931 5932

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

B
Bob Liu 已提交
5935 5936 5937 5938 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
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;

5973
    if (!(def = libxlDomainMigrationDstPrepareDef(driver, dom_xml, dname)))
B
Bob Liu 已提交
5974 5975 5976 5977 5978
        goto error;

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

5979 5980
    if (libxlDomainMigrationDstPrepareTunnel3(dconn, st, &def, cookiein,
                                              cookieinlen, flags) < 0)
B
Bob Liu 已提交
5981 5982 5983 5984 5985 5986 5987 5988 5989
        goto error;

    return 0;

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

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

6007 6008 6009 6010 6011
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027
    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;

6028
    if (!(def = libxlDomainMigrationDstPrepareDef(driver, dom_xml, dname)))
J
Jim Fehlig 已提交
6029 6030 6031 6032 6033
        goto error;

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

6034 6035
    if (libxlDomainMigrationDstPrepare(dconn, &def, uri_in, uri_out,
                                       cookiein, cookieinlen, flags) < 0)
J
Jim Fehlig 已提交
6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062
        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;

6063 6064 6065 6066 6067
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

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

    ret = 0;

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

6123 6124 6125 6126 6127
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return NULL;
#endif

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

6152
    ret = libxlDomainMigrationDstFinish(dconn, vm, flags, cancelled);
6153

6154
    virDomainObjEndAPI(&vm);
6155 6156

    return ret;
J
Jim Fehlig 已提交
6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169
}

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

6172 6173 6174 6175 6176
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
6177 6178 6179 6180 6181 6182 6183
    virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        return -1;

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

6184 6185
    if (virDomainMigrateConfirm3ParamsEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;
J
Jim Fehlig 已提交
6186

6187
    ret = libxlDomainMigrationSrcConfirm(driver, vm, flags, cancelled);
6188 6189 6190 6191

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

6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210
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;
}
6211

6212 6213 6214 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
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;

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


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


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

    virObjectUnref(cfg);
    return ret;
}

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

    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL);

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

J
Jiri Denemark 已提交
6466 6467 6468
    if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST)))
        goto cleanup;

6469
    if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, NULL,
6470
                               !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE))))
J
Jiri Denemark 已提交
6471 6472 6473 6474 6475 6476
        goto cleanup;

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

6477
    cpustr = virCPUDefFormat(cpu, NULL);
6478 6479

 cleanup:
J
Jiri Denemark 已提交
6480 6481 6482 6483
    virCPUDefListFree(cpus);
    virCPUDefFree(cpu);

    return cpustr;
6484 6485
}

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

6601
static virConnectDriver libxlConnectDriver = {
6602
    .localOnly = true,
6603
    .uriSchemes = (const char *[]){ "xen", NULL },
6604 6605 6606
    .hypervisorDriver = &libxlHypervisorDriver,
};

J
Jim Fehlig 已提交
6607 6608
static virStateDriver libxlStateDriver = {
    .name = "LIBXL",
6609 6610 6611
    .stateInitialize = libxlStateInitialize,
    .stateCleanup = libxlStateCleanup,
    .stateReload = libxlStateReload,
J
Jim Fehlig 已提交
6612 6613 6614 6615 6616 6617
};


int
libxlRegister(void)
{
6618 6619
    if (virRegisterConnectDriver(&libxlConnectDriver,
                                 true) < 0)
J
Jim Fehlig 已提交
6620 6621 6622 6623 6624 6625
        return -1;
    if (virRegisterStateDriver(&libxlStateDriver) < 0)
        return -1;

    return 0;
}