xen_unified.c 27.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * xen_unified.c: Unified Xen driver.
 *
 * Copyright (C) 2007 Red Hat, Inc.
 *
 * See COPYING.LIB for the License of this software
 *
 * Richard W.M. Jones <rjones@redhat.com>
 */

#ifdef WITH_XEN

/* Note:
 *
 * This driver provides a unified interface to the five
 * separate underlying Xen drivers (xen_internal, proxy_internal,
 * xend_internal, xs_internal and xm_internal).  Historically
 * the body of libvirt.c handled the five Xen drivers,
 * and contained Xen-specific code.
 */

#include <stdint.h>
#include <unistd.h>
24
#include <string.h>
25
#include <errno.h>
26 27
#include <sys/types.h>
#include <xen/dom0_ops.h>
28
#include <libxml/uri.h>
29 30 31 32 33 34 35 36 37 38 39 40

#include "internal.h"

#include "xen_unified.h"

#include "xen_internal.h"
#include "proxy_internal.h"
#include "xend_internal.h"
#include "xs_internal.h"
#include "xm_internal.h"

/* The five Xen drivers below us. */
41 42 43 44 45 46
static struct xenUnifiedDriver *drivers[XEN_UNIFIED_NR_DRIVERS] = {
    [XEN_UNIFIED_HYPERVISOR_OFFSET] = &xenHypervisorDriver,
    [XEN_UNIFIED_PROXY_OFFSET] = &xenProxyDriver,
    [XEN_UNIFIED_XEND_OFFSET] = &xenDaemonDriver,
    [XEN_UNIFIED_XS_OFFSET] = &xenStoreDriver,
    [XEN_UNIFIED_XM_OFFSET] = &xenXMDriver,
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
};

/**
 * xenUnifiedError:
 * @conn: the connection
 * @error: the error number
 * @info: extra information string
 *
 * Handle an error at the xend daemon interface
 */
static void
xenUnifiedError (virConnectPtr conn, virErrorNumber error, const char *info)
{
    const char *errmsg;

    errmsg = __virErrorMsg (error, info);
    __virRaiseError (conn, NULL, NULL, VIR_FROM_XEN, error, VIR_ERR_ERROR,
64
                     errmsg, info, NULL, 0, 0, errmsg, info);
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
}

/*----- Dispatch functions. -----*/

/* These dispatch functions follow the model used historically
 * by libvirt.c -- trying each low-level Xen driver in turn
 * until one succeeds.  However since we know what low-level
 * drivers can perform which functions, it is probably better
 * in future to optimise these dispatch functions to just call
 * the single function (or small number of appropriate functions)
 * in the low level drivers directly.
 */

static int
xenUnifiedOpen (virConnectPtr conn, const char *name, int flags)
{
81 82
    int i, j;
    xenUnifiedPrivatePtr priv;
83
    xmlURIPtr uri;
84

85 86 87 88 89
    uri = xmlParseURI(name);
    if (uri == NULL) {
        return VIR_DRV_OPEN_DECLINED;
    }

90
    /* Refuse any scheme which isn't "xen://" or "http://". */
91 92
    if (uri->scheme &&
        strcasecmp(uri->scheme, "xen") != 0 &&
93 94 95 96 97 98 99 100 101 102 103
        strcasecmp(uri->scheme, "http") != 0) {
        xmlFreeURI(uri);
        return VIR_DRV_OPEN_DECLINED;
    }

    /* xmlParseURI will parse a naked string like "foo" as a URI with
     * a NULL scheme.  That's not useful for us because we want to only
     * allow full pathnames (eg. ///var/lib/xen/xend-socket).  Decline
     * anything else.
     */
    if (!uri->scheme && name[0] != '/') {
104
        xmlFreeURI(uri);
105
        return VIR_DRV_OPEN_DECLINED;
106 107 108
    }

    /* Refuse any xen:// URI with a server specified - allow remote to do it */
109
    if (uri->scheme && strcasecmp(uri->scheme, "xen") == 0 && uri->server) {
110 111 112
        xmlFreeURI(uri);
        return VIR_DRV_OPEN_DECLINED;
    }
113

114
    xmlFreeURI(uri);
115 116

    /* Allocate per-connection private data. */
117
    priv = calloc (1, sizeof *priv);
118
    if (!priv) {
119
        xenUnifiedError (NULL, VIR_ERR_NO_MEMORY, "allocating private data");
120 121 122 123
        return VIR_DRV_OPEN_ERROR;
    }
    conn->privateData = priv;

124 125 126 127 128 129 130
    priv->name = strdup (name);
    if (!priv->name) {
        xenUnifiedError (NULL, VIR_ERR_NO_MEMORY, "allocating priv->name");
        free (priv);
        return VIR_DRV_OPEN_ERROR;
    }

131 132 133 134 135 136 137 138
    priv->handle = -1;
    priv->xendConfigVersion = -1;
    priv->type = -1;
    priv->len = -1;
    priv->addr = NULL;
    priv->xshandle = NULL;
    priv->proxy = -1;

139 140
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) {
        priv->opened[i] = 0;
141

142 143 144 145 146
        /* Only use XM driver for Xen <= 3.0.3 (ie xendConfigVersion <= 2) */
        if (drivers[i] == &xenXMDriver &&
            priv->xendConfigVersion > 2)
            continue;

147
        /* Ignore proxy for root */
148
        if (i == XEN_UNIFIED_PROXY_OFFSET && getuid() == 0)
149 150
            continue;

151 152 153 154 155 156 157 158 159 160 161
        if (drivers[i]->open) {
#ifdef ENABLE_DEBUG
            fprintf (stderr, "libvirt: xenUnifiedOpen: trying Xen sub-driver %d\n", i);
#endif
            if (drivers[i]->open (conn, name, flags) == VIR_DRV_OPEN_SUCCESS)
                priv->opened[i] = 1;
#ifdef ENABLE_DEBUG
            fprintf (stderr, "libvirt: xenUnifiedOpen: Xen sub-driver %d open %s\n",
                     i, priv->opened[i] ? "ok" : "failed");
#endif
        }
162 163 164

        /* If as root, then all drivers must succeed.
           If non-root, then only proxy must succeed */
165 166
        if (!priv->opened[i] &&
            (getuid() == 0 || i == XEN_UNIFIED_PROXY_OFFSET)) {
167
            for (j = 0; j < i; ++j)
168
                if (priv->opened[j]) drivers[j]->close (conn);
169 170 171 172 173
            free (priv->name);
            free (priv);
            /* The assumption is that one of the underlying drivers
             * has set virterror already.
             */
174 175
            return VIR_DRV_OPEN_ERROR;
        }
176 177
    }

178
    return VIR_DRV_OPEN_SUCCESS;
179 180
}

181 182 183
#define GET_PRIVATE(conn) \
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) (conn)->privateData

184 185 186
static int
xenUnifiedClose (virConnectPtr conn)
{
187
    GET_PRIVATE(conn);
188
    int i;
189

190 191
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->close)
192
            (void) drivers[i]->close (conn);
193

194
    free (priv->name);
195 196
    free (conn->privateData);
    conn->privateData = NULL;
197

198
    return 0;
199 200 201 202 203
}

static const char *
xenUnifiedType (virConnectPtr conn)
{
204
    GET_PRIVATE(conn);
205 206
    int i;
    const char *ret;
207

208 209
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->type) {
210 211 212
            ret = drivers[i]->type (conn);
            if (ret) return ret;
        }
213

214
    return NULL;
215 216 217 218 219
}

static int
xenUnifiedVersion (virConnectPtr conn, unsigned long *hvVer)
{
220
    GET_PRIVATE(conn);
221
    int i;
222

223 224 225
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] &&
            drivers[i]->version &&
226 227
            drivers[i]->version (conn, hvVer) == 0)
            return 0;
228

229
    return -1;
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
/* NB: Even if connected to the proxy, we're still on the
 * same machine.
 */
static char *
xenUnifiedGetHostname (virConnectPtr conn)
{
    int r;
    char hostname [HOST_NAME_MAX+1], *str;

    r = gethostname (hostname, HOST_NAME_MAX+1);
    if (r == -1) {
        xenUnifiedError (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
        return NULL;
    }
    str = strdup (hostname);
    if (str == NULL) {
        xenUnifiedError (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
        return NULL;
    }
    return str;
}

/* The name is recorded (canonicalised) in xenUnifiedOpen. */
static char *
xenUnifiedGetURI (virConnectPtr conn)
{
    GET_PRIVATE(conn);
    char *str;

    str = strdup (priv->name);
    if (str == NULL) {
        xenUnifiedError (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
        return NULL;
    }
    return str;
}

269 270 271
static int
xenUnifiedGetMaxVcpus (virConnectPtr conn, const char *type)
{
272
    GET_PRIVATE(conn);
273

274 275 276 277
    if (type && STRCASENEQ (type, "Xen")) {
        xenUnifiedError (conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
        return -1;
    }
278

279 280 281 282 283 284
    if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET])
        return xenHypervisorGetMaxVcpus (conn, type);
    else {
        xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
        return -1;
    }
285 286 287 288 289
}

static int
xenUnifiedNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info)
{
290
    GET_PRIVATE(conn);
291
    int i;
292

293 294 295
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] &&
            drivers[i]->nodeGetInfo &&
296 297
            drivers[i]->nodeGetInfo (conn, info) == 0)
            return 0;
298

299
    return -1;
300 301 302 303 304
}

static char *
xenUnifiedGetCapabilities (virConnectPtr conn)
{
305
    GET_PRIVATE(conn);
306 307
    int i;
    char *ret;
308

309 310
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->getCapabilities) {
311 312 313
            ret = drivers[i]->getCapabilities (conn);
            if (ret) return ret;
        }
314

315
    return NULL;
316 317 318 319 320
}

static int
xenUnifiedListDomains (virConnectPtr conn, int *ids, int maxids)
{
321
    GET_PRIVATE(conn);
322
    int i, ret;
323

324 325
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->listDomains) {
326 327 328
            ret = drivers[i]->listDomains (conn, ids, maxids);
            if (ret >= 0) return ret;
        }
329

330
    return -1;
331 332 333 334 335
}

static int
xenUnifiedNumOfDomains (virConnectPtr conn)
{
336
    GET_PRIVATE(conn);
337
    int i, ret;
338

339 340
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->numOfDomains) {
341 342 343
            ret = drivers[i]->numOfDomains (conn);
            if (ret >= 0) return ret;
        }
344

345
    return -1;
346 347 348 349
}

static virDomainPtr
xenUnifiedDomainCreateLinux (virConnectPtr conn,
350
                             const char *xmlDesc, unsigned int flags)
351
{
352
    GET_PRIVATE(conn);
353 354
    int i;
    virDomainPtr ret;
355

356 357
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->domainCreateLinux) {
358 359 360
            ret = drivers[i]->domainCreateLinux (conn, xmlDesc, flags);
            if (ret) return ret;
        }
361

362
    return NULL;
363 364
}

365 366 367 368
/* Assumption made in underlying drivers:
 * If the domain is "not found" and there is no other error, then
 * the Lookup* functions return a NULL but do not set virterror.
 */
369 370 371
static virDomainPtr
xenUnifiedDomainLookupByID (virConnectPtr conn, int id)
{
372
    GET_PRIVATE(conn);
373
    virDomainPtr ret;
374

375 376 377 378 379
    /* Reset any connection-level errors in virterror first, in case
     * there is one hanging around from a previous call.
     */
    virConnResetLastError (conn);

380 381 382 383 384 385 386
    /* Try hypervisor/xenstore combo. */
    if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) {
        ret = xenHypervisorLookupDomainByID (conn, id);
        if (ret || conn->err.code != VIR_ERR_OK)
            return ret;
    }

387 388 389 390 391 392 393 394 395 396 397 398 399
    /* Try proxy. */
    if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) {
        ret = xenProxyLookupByID (conn, id);
        if (ret || conn->err.code != VIR_ERR_OK)
            return ret;
    }

    /* Try xend. */
    if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
        ret = xenDaemonLookupByID (conn, id);
        if (ret || conn->err.code != VIR_ERR_OK)
            return ret;
    }
400

401 402
    /* Not found. */
    xenUnifiedError (conn, VIR_ERR_NO_DOMAIN, __FUNCTION__);
403
    return NULL;
404 405 406 407
}

static virDomainPtr
xenUnifiedDomainLookupByUUID (virConnectPtr conn,
408
                              const unsigned char *uuid)
409
{
410
    GET_PRIVATE(conn);
411
    virDomainPtr ret;
412

413 414 415 416 417
    /* Reset any connection-level errors in virterror first, in case
     * there is one hanging around from a previous call.
     */
    virConnResetLastError (conn);

418 419 420 421 422 423 424
    /* Try hypervisor/xenstore combo. */
    if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) {
        ret = xenHypervisorLookupDomainByUUID (conn, uuid);
        if (ret || conn->err.code != VIR_ERR_OK)
            return ret;
    }

425 426 427 428 429 430 431 432 433 434 435 436 437
    /* Try proxy. */
    if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) {
        ret = xenProxyLookupByUUID (conn, uuid);
        if (ret || conn->err.code != VIR_ERR_OK)
            return ret;
    }

    /* Try xend. */
    if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
        ret = xenDaemonLookupByUUID (conn, uuid);
        if (ret || conn->err.code != VIR_ERR_OK)
            return ret;
    }
438

439 440 441 442 443 444 445 446 447
    /* Try XM for inactive domains. */
    if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
        ret = xenXMDomainLookupByUUID (conn, uuid);
        if (ret || conn->err.code != VIR_ERR_OK)
            return ret;
    }

    /* Not found. */
    xenUnifiedError (conn, VIR_ERR_NO_DOMAIN, __FUNCTION__);
448
    return NULL;
449 450 451 452
}

static virDomainPtr
xenUnifiedDomainLookupByName (virConnectPtr conn,
453
                              const char *name)
454
{
455
    GET_PRIVATE(conn);
456
    virDomainPtr ret;
457

458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
    /* Reset any connection-level errors in virterror first, in case
     * there is one hanging around from a previous call.
     */
    virConnResetLastError (conn);

    /* Try proxy. */
    if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) {
        ret = xenProxyLookupByName (conn, name);
        if (ret || conn->err.code != VIR_ERR_OK)
            return ret;
    }

    /* Try xend. */
    if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
        ret = xenDaemonLookupByName (conn, name);
        if (ret || conn->err.code != VIR_ERR_OK)
            return ret;
    }

    /* Try xenstore for inactive domains. */
    if (priv->opened[XEN_UNIFIED_XS_OFFSET]) {
        ret = xenStoreLookupByName (conn, name);
        if (ret || conn->err.code != VIR_ERR_OK)
            return ret;
    }

    /* Try XM for inactive domains. */
    if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
        ret = xenXMDomainLookupByName (conn, name);
        if (ret || conn->err.code != VIR_ERR_OK)
            return ret;
    }
490

491 492
    /* Not found. */
    xenUnifiedError (conn, VIR_ERR_NO_DOMAIN, __FUNCTION__);
493
    return NULL;
494 495 496 497 498
}

static int
xenUnifiedDomainSuspend (virDomainPtr dom)
{
499
    GET_PRIVATE(dom->conn);
500
    int i;
501

502 503 504
    /* Try non-hypervisor methods first, then hypervisor direct method
     * as a last resort.
     */
505
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
506
        if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
507
            priv->opened[i] &&
508 509 510
            drivers[i]->domainSuspend &&
            drivers[i]->domainSuspend (dom) == 0)
            return 0;
511

512 513 514
    if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
        drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSuspend &&
        drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSuspend (dom) == 0)
515
        return 0;
516

517
    return -1;
518 519 520 521 522
}

static int
xenUnifiedDomainResume (virDomainPtr dom)
{
523
    GET_PRIVATE(dom->conn);
524
    int i;
525

526 527 528
    /* Try non-hypervisor methods first, then hypervisor direct method
     * as a last resort.
     */
529
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
530
        if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
531
            priv->opened[i] &&
532 533 534
            drivers[i]->domainResume &&
            drivers[i]->domainResume (dom) == 0)
            return 0;
535

536 537 538
    if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
        drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainResume &&
        drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainResume (dom) == 0)
539
        return 0;
540

541
    return -1;
542 543 544 545 546
}

static int
xenUnifiedDomainShutdown (virDomainPtr dom)
{
547
    GET_PRIVATE(dom->conn);
548
    int i;
549

550 551 552
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] &&
            drivers[i]->domainShutdown &&
553 554
            drivers[i]->domainShutdown (dom) == 0)
            return 0;
555

556
    return -1;
557 558 559 560 561
}

static int
xenUnifiedDomainReboot (virDomainPtr dom, unsigned int flags)
{
562
    GET_PRIVATE(dom->conn);
563
    int i;
564

565 566 567
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] &&
            drivers[i]->domainReboot &&
568 569
            drivers[i]->domainReboot (dom, flags) == 0)
            return 0;
570

571
    return -1;
572 573 574 575 576
}

static int
xenUnifiedDomainDestroy (virDomainPtr dom)
{
577
    GET_PRIVATE(dom->conn);
578
    int i;
579

580 581 582
    /* Try non-hypervisor methods first, then hypervisor direct method
     * as a last resort.
     */
583
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
584
        if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
585
            priv->opened[i] &&
586 587 588
            drivers[i]->domainDestroy &&
            drivers[i]->domainDestroy (dom) == 0)
            return 0;
589

590
    if (priv->opened[i] &&
591 592
        drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainDestroy &&
        drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainDestroy (dom) == 0)
593
        return 0;
594

595
    return -1;
596 597 598 599 600
}

static char *
xenUnifiedDomainGetOSType (virDomainPtr dom)
{
601
    GET_PRIVATE(dom->conn);
602 603
    int i;
    char *ret;
604

605 606
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->domainGetOSType) {
607 608 609
            ret = drivers[i]->domainGetOSType (dom);
            if (ret) return ret;
        }
610

611
    return NULL;
612 613 614 615 616
}

static unsigned long
xenUnifiedDomainGetMaxMemory (virDomainPtr dom)
{
617
    GET_PRIVATE(dom->conn);
618 619
    int i;
    unsigned long ret;
620

621 622
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->domainGetMaxMemory) {
623 624 625
            ret = drivers[i]->domainGetMaxMemory (dom);
            if (ret != 0) return ret;
        }
626

627
    return 0;
628 629 630 631 632
}

static int
xenUnifiedDomainSetMaxMemory (virDomainPtr dom, unsigned long memory)
{
633
    GET_PRIVATE(dom->conn);
634
    int i;
635

636 637 638
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] &&
            drivers[i]->domainSetMaxMemory &&
639 640
            drivers[i]->domainSetMaxMemory (dom, memory) == 0)
            return 0;
641

642
    return -1;
643 644 645 646 647
}

static int
xenUnifiedDomainSetMemory (virDomainPtr dom, unsigned long memory)
{
648
    GET_PRIVATE(dom->conn);
649
    int i;
650

651 652 653
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] &&
            drivers[i]->domainSetMemory &&
654 655
            drivers[i]->domainSetMemory (dom, memory) == 0)
            return 0;
656

657
    return -1;
658 659 660 661 662
}

static int
xenUnifiedDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info)
{
663
    GET_PRIVATE(dom->conn);
664
    int i;
665

666 667 668
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] &&
            drivers[i]->domainGetInfo &&
669 670
            drivers[i]->domainGetInfo (dom, info) == 0)
            return 0;
671

672
    return -1;
673 674 675 676 677
}

static int
xenUnifiedDomainSave (virDomainPtr dom, const char *to)
{
678
    GET_PRIVATE(dom->conn);
679
    int i;
680

681 682 683
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] &&
            drivers[i]->domainSave &&
684 685
            drivers[i]->domainSave (dom, to) == 0)
            return 0;
686

687
    return -1;
688 689 690 691 692
}

static int
xenUnifiedDomainRestore (virConnectPtr conn, const char *from)
{
693
    GET_PRIVATE(conn);
694
    int i;
695

696 697 698
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] &&
            drivers[i]->domainRestore &&
699 700
            drivers[i]->domainRestore (conn, from) == 0)
            return 0;
701

702
    return -1;
703 704 705 706 707
}

static int
xenUnifiedDomainCoreDump (virDomainPtr dom, const char *to, int flags)
{
708
    GET_PRIVATE(dom->conn);
709
    int i;
710

711 712 713
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] &&
            drivers[i]->domainCoreDump &&
714 715
            drivers[i]->domainCoreDump (dom, to, flags) == 0)
            return 0;
716

717
    return -1;
718 719 720 721 722
}

static int
xenUnifiedDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus)
{
723
    GET_PRIVATE(dom->conn);
724
    int i;
725

726 727 728
    /* Try non-hypervisor methods first, then hypervisor direct method
     * as a last resort.
     */
729
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
730
        if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
731
            priv->opened[i] &&
732 733 734
            drivers[i]->domainSetVcpus &&
            drivers[i]->domainSetVcpus (dom, nvcpus) == 0)
            return 0;
735

736 737 738
    if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
        drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSetVcpus &&
        drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSetVcpus (dom, nvcpus) == 0)
739
        return 0;
740

741
    return -1;
742 743 744 745
}

static int
xenUnifiedDomainPinVcpu (virDomainPtr dom, unsigned int vcpu,
746
                         unsigned char *cpumap, int maplen)
747
{
748
    GET_PRIVATE(dom->conn);
749
    int i;
750

751 752 753
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] &&
            drivers[i]->domainPinVcpu &&
754 755
            drivers[i]->domainPinVcpu (dom, vcpu, cpumap, maplen) == 0)
            return 0;
756

757
    return -1;
758 759 760 761
}

static int
xenUnifiedDomainGetVcpus (virDomainPtr dom,
762 763
                          virVcpuInfoPtr info, int maxinfo,
                          unsigned char *cpumaps, int maplen)
764
{
765
    GET_PRIVATE(dom->conn);
766
    int i, ret;
767

768 769
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->domainGetVcpus) {
770 771 772 773
            ret = drivers[i]->domainGetVcpus (dom, info, maxinfo, cpumaps, maplen);
            if (ret > 0)
                return ret;
        }
774
    return -1;
775 776 777 778 779
}

static int
xenUnifiedDomainGetMaxVcpus (virDomainPtr dom)
{
780
    GET_PRIVATE(dom->conn);
781
    int i, ret;
782

783 784
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->domainGetMaxVcpus) {
785 786 787
            ret = drivers[i]->domainGetMaxVcpus (dom);
            if (ret != 0) return ret;
        }
788

789
    return -1;
790 791 792 793 794
}

static char *
xenUnifiedDomainDumpXML (virDomainPtr dom, int flags)
{
795
    GET_PRIVATE(dom->conn);
796 797
    int i;
    char *ret;
798

799 800
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->domainDumpXML) {
801 802 803
            ret = drivers[i]->domainDumpXML (dom, flags);
            if (ret) return ret;
        }
804

805
    return NULL;
806 807 808 809
}

static int
xenUnifiedListDefinedDomains (virConnectPtr conn, char **const names,
810
                              int maxnames)
811
{
812
    GET_PRIVATE(conn);
813 814
    int i;
    int ret;
815

816 817
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->listDefinedDomains) {
818 819 820
            ret = drivers[i]->listDefinedDomains (conn, names, maxnames);
            if (ret >= 0) return ret;
        }
821

822
    return -1;
823 824 825 826 827
}

static int
xenUnifiedNumOfDefinedDomains (virConnectPtr conn)
{
828
    GET_PRIVATE(conn);
829 830
    int i;
    int ret;
831

832 833
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->numOfDefinedDomains) {
834 835 836
            ret = drivers[i]->numOfDefinedDomains (conn);
            if (ret >= 0) return ret;
        }
837

838
    return -1;
839 840 841 842 843
}

static int
xenUnifiedDomainCreate (virDomainPtr dom)
{
844
    GET_PRIVATE(dom->conn);
845
    int i;
846

847 848
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->domainCreate &&
849 850
            drivers[i]->domainCreate (dom) == 0)
            return 0;
851

852
    return -1;
853 854 855 856 857
}

static virDomainPtr
xenUnifiedDomainDefineXML (virConnectPtr conn, const char *xml)
{
858
    GET_PRIVATE(conn);
859 860
    int i;
    virDomainPtr ret;
861

862 863
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->domainDefineXML) {
864 865 866
            ret = drivers[i]->domainDefineXML (conn, xml);
            if (ret) return ret;
        }
867

868
    return NULL;
869 870 871 872 873
}

static int
xenUnifiedDomainUndefine (virDomainPtr dom)
{
874
    GET_PRIVATE(dom->conn);
875
    int i;
876

877 878
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->domainUndefine &&
879 880
            drivers[i]->domainUndefine (dom) == 0)
            return 0;
881

882
    return -1;
883 884 885 886 887
}

static int
xenUnifiedDomainAttachDevice (virDomainPtr dom, char *xml)
{
888
    GET_PRIVATE(dom->conn);
889
    int i;
890

891 892
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->domainAttachDevice &&
893 894
            drivers[i]->domainAttachDevice (dom, xml) == 0)
            return 0;
895

896
    return -1;
897 898 899 900 901
}

static int
xenUnifiedDomainDetachDevice (virDomainPtr dom, char *xml)
{
902
    GET_PRIVATE(dom->conn);
903
    int i;
904

905 906
    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
        if (priv->opened[i] && drivers[i]->domainDetachDevice &&
907 908
            drivers[i]->domainDetachDevice (dom, xml) == 0)
            return 0;
909

910
    return -1;
911 912
}

913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
static char *
xenUnifiedDomainGetSchedulerType (virDomainPtr dom, int *nparams)
{
    GET_PRIVATE(dom->conn);
    int i;
    char *schedulertype;

    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; i++) {
        if (priv->opened[i] && drivers[i]->domainGetSchedulerType) {
            schedulertype = drivers[i]->domainGetSchedulerType (dom, nparams);
	    if (schedulertype != NULL)
		return(schedulertype); 
        }
    }
    return(NULL);
}

static int
xenUnifiedDomainGetSchedulerParameters (virDomainPtr dom,
                    virSchedParameterPtr params, int *nparams)
{
    GET_PRIVATE(dom->conn);
    int i, ret;

    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) {
        if (priv->opened[i] && drivers[i]->domainGetSchedulerParameters) {
           ret = drivers[i]->domainGetSchedulerParameters(dom, params, nparams);
	   if (ret == 0)
	       return(0);
	}
    }
    return(-1);
}

static int
xenUnifiedDomainSetSchedulerParameters (virDomainPtr dom,
                    virSchedParameterPtr params, int nparams)
{
    GET_PRIVATE(dom->conn);
    int i, ret;

    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) {
        if (priv->opened[i] && drivers[i]->domainSetSchedulerParameters) {
           ret = drivers[i]->domainSetSchedulerParameters(dom, params, nparams);
	   if (ret == 0)
	       return 0;
	}
    }

    return(-1);
}

965 966
/*----- Register with libvirt.c, and initialise Xen drivers. -----*/

967 968 969
#define VERSION ((DOM0_INTERFACE_VERSION >> 24) * 1000000 +         \
                 ((DOM0_INTERFACE_VERSION >> 16) & 0xFF) * 1000 +	\
                 (DOM0_INTERFACE_VERSION & 0xFFFF))
970 971 972

/* The interface which we export upwards to libvirt.c. */
static virDriver xenUnifiedDriver = {
973
    .no = VIR_DRV_XEN_UNIFIED,
974
    .name = "Xen",
975 976 977 978 979
    .ver = VERSION,
    .open 			= xenUnifiedOpen,
    .close 			= xenUnifiedClose,
    .type 			= xenUnifiedType,
    .version 			= xenUnifiedVersion,
980 981
    .getHostname    = xenUnifiedGetHostname,
    .getURI         = xenUnifiedGetURI,
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
    .getMaxVcpus 			= xenUnifiedGetMaxVcpus,
    .nodeGetInfo 			= xenUnifiedNodeGetInfo,
    .getCapabilities 		= xenUnifiedGetCapabilities,
    .listDomains 			= xenUnifiedListDomains,
    .numOfDomains 		= xenUnifiedNumOfDomains,
    .domainCreateLinux 		= xenUnifiedDomainCreateLinux,
    .domainLookupByID 		= xenUnifiedDomainLookupByID,
    .domainLookupByUUID 		= xenUnifiedDomainLookupByUUID,
    .domainLookupByName 		= xenUnifiedDomainLookupByName,
    .domainSuspend 		= xenUnifiedDomainSuspend,
    .domainResume 		= xenUnifiedDomainResume,
    .domainShutdown 		= xenUnifiedDomainShutdown,
    .domainReboot 		= xenUnifiedDomainReboot,
    .domainDestroy 		= xenUnifiedDomainDestroy,
    .domainGetOSType 		= xenUnifiedDomainGetOSType,
    .domainGetMaxMemory 		= xenUnifiedDomainGetMaxMemory,
    .domainSetMaxMemory 		= xenUnifiedDomainSetMaxMemory,
    .domainSetMemory 		= xenUnifiedDomainSetMemory,
    .domainGetInfo 		= xenUnifiedDomainGetInfo,
    .domainSave 			= xenUnifiedDomainSave,
    .domainRestore 		= xenUnifiedDomainRestore,
    .domainCoreDump 		= xenUnifiedDomainCoreDump,
    .domainSetVcpus 		= xenUnifiedDomainSetVcpus,
    .domainPinVcpu 		= xenUnifiedDomainPinVcpu,
    .domainGetVcpus 		= xenUnifiedDomainGetVcpus,
    .domainGetMaxVcpus 		= xenUnifiedDomainGetMaxVcpus,
    .domainDumpXML 		= xenUnifiedDomainDumpXML,
    .listDefinedDomains 		= xenUnifiedListDefinedDomains,
    .numOfDefinedDomains 		= xenUnifiedNumOfDefinedDomains,
    .domainCreate 		= xenUnifiedDomainCreate,
    .domainDefineXML 		= xenUnifiedDomainDefineXML,
    .domainUndefine 		= xenUnifiedDomainUndefine,
    .domainAttachDevice 		= xenUnifiedDomainAttachDevice,
    .domainDetachDevice 		= xenUnifiedDomainDetachDevice,
1016 1017 1018
    .domainGetSchedulerType	= xenUnifiedDomainGetSchedulerType,
    .domainGetSchedulerParameters	= xenUnifiedDomainGetSchedulerParameters,
    .domainSetSchedulerParameters	= xenUnifiedDomainSetSchedulerParameters,
1019 1020
};

1021 1022 1023 1024 1025 1026 1027
/**
 * xenUnifiedRegister:
 *
 * Register xen related drivers
 *
 * Returns the driver priority or -1 in case of error.
 */
1028 1029 1030
int
xenUnifiedRegister (void)
{
1031 1032 1033 1034 1035 1036
    /* Ignore failures here. */
    (void) xenHypervisorInit ();
    (void) xenProxyInit ();
    (void) xenDaemonInit ();
    (void) xenStoreInit ();
    (void) xenXMInit ();
1037

1038
    return virRegisterDriver (&xenUnifiedDriver);
1039 1040 1041
}

#endif /* WITH_XEN */
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055

/*
 * vim: set tabstop=4:
 * vim: set shiftwidth=4:
 * vim: set expandtab:
 */
/*
 * Local variables:
 *  indent-tabs-mode: nil
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 * End:
 */