xen_internal.c 10.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * xen_internal.c: direct access to Xen hypervisor level
 *
 * Copyright (C) 2005 Red Hat, Inc.
 *
 * See COPYING.LIB for the License of this software
 *
 * Daniel Veillard <veillard@redhat.com>
 */

#include <stdio.h>
#include <string.h>
13
/* required for uint8_t, uint32_t, etc ... */
14 15 16 17 18 19 20 21
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

22 23 24
#include <stdint.h>

/* required for dom0_getdomaininfo_t */
25
#include <xen/dom0_ops.h>
26
#include <xen/version.h>
27 28 29
#include <xen/xen.h>

#ifndef __LINUX_PUBLIC_PRIVCMD_H__
30
typedef struct hypercall_struct {
31 32 33 34 35 36 37
    unsigned long op;
    unsigned long arg[5];
} hypercall_t;
#endif


#include "internal.h"
38
#include "driver.h"
39 40 41 42
#include "xen_internal.h"

#define XEN_HYPERVISOR_SOCKET "/proc/xen/privcmd"

43 44 45 46 47 48 49
static virDriver xenHypervisorDriver = {
    "Xen",
    NULL, /* init */
    xenHypervisorOpen, /* open */
    xenHypervisorClose, /* close */
    NULL, /* type */
    xenHypervisorGetVersion, /* version */
50
    NULL, /* nodeGetInfo */
51 52 53 54 55 56 57 58 59
    NULL, /* listDomains */
    NULL, /* numOfDomains */
    NULL, /* domainCreateLinux */
    NULL, /* domainLookupByID */
    NULL, /* domainLookupByUUID */
    NULL, /* domainLookupByName */
    xenHypervisorPauseDomain, /* domainSuspend */
    xenHypervisorResumeDomain, /* domainResume */
    NULL, /* domainShutdown */
60
    NULL, /* domainReboot */
61 62 63 64 65 66 67 68
    xenHypervisorDestroyDomain, /* domainDestroy */
    NULL, /* domainFree */
    NULL, /* domainGetName */
    NULL, /* domainGetID */
    NULL, /* domainGetUUID */
    NULL, /* domainGetOSType */
    NULL, /* domainGetMaxMemory */
    xenHypervisorSetMaxMemory, /* domainSetMaxMemory */
69
    NULL, /* domainSetMemory */
70 71 72 73 74
    xenHypervisorGetDomainInfo, /* domainGetInfo */
    NULL, /* domainSave */
    NULL /* domainRestore */
};

75 76 77 78 79 80 81 82 83 84
/**
 * xenHypervisorRegister:
 *
 * Registers the xenHypervisor driver
 */
void xenHypervisorRegister(void)
{
    virRegisterDriver(&xenHypervisorDriver);
}

85 86 87 88 89 90 91 92 93
/**
 * virXenError:
 * @conn: the connection if available
 * @error: the error number
 * @info: extra information string
 *
 * Handle an error at the xend daemon interface
 */
static void
94 95
virXenError(virErrorNumber error, const char *info, int value)
{
96
    const char *errmsg;
97

98 99 100 101 102
    if (error == VIR_ERR_OK)
        return;

    errmsg = __virErrorMsg(error, info);
    __virRaiseError(NULL, NULL, VIR_FROM_XEN, error, VIR_ERR_ERROR,
103
                    errmsg, info, NULL, value, 0, errmsg, info, value);
104 105
}

106 107
/**
 * xenHypervisorOpen:
108 109 110
 * @conn: pointer to the connection block
 * @name: URL for the target, NULL for local
 * @flags: combination of virDrvOpenFlag(s)
111 112 113
 *
 * Connects to the Xen hypervisor.
 *
114
 * Returns 0 or -1 in case of error.
115
 */
116
int
117
xenHypervisorOpen(virConnectPtr conn, const char *name, int flags)
118
{
119 120
    int ret;

121 122 123 124 125
    if ((name != NULL) && (strcmp(name, "xen")))
        return(-1);

    conn->handle = -1;

126
    ret = open(XEN_HYPERVISOR_SOCKET, O_RDWR);
127
    if (ret < 0) {
128
        if (!(flags & VIR_DRV_OPEN_QUIET))
129 130
            virXenError(VIR_ERR_NO_XEN, XEN_HYPERVISOR_SOCKET, 0);
        return (-1);
131
    }
132
    conn->handle = ret;
133

134
    return (ret);
135 136 137 138
}

/**
 * xenHypervisorClose:
139
 * @conn: pointer to the connection block
140 141 142 143 144
 *
 * Close the connection to the Xen hypervisor.
 *
 * Returns 0 in case of success or -1 in case of error.
 */
145
int
146
xenHypervisorClose(virConnectPtr conn)
147
{
148 149
    int ret;

150
    if ((conn == NULL) || (conn->handle < 0))
151
        return (-1);
152

153
    ret = close(conn->handle);
154
    if (ret < 0)
155 156
        return (-1);
    return (0);
157 158 159 160 161 162 163 164 165 166 167 168
}

/**
 * xenHypervisorDoOp:
 * @handle: the handle to the Xen hypervisor
 * @op: pointer to the hyperviros operation structure
 *
 * Do an hypervisor operation, this leads to an hypervisor call through ioctl.
 *
 * Returns 0 in case of success and -1 in case of error.
 */
static int
169 170
xenHypervisorDoOp(int handle, dom0_op_t * op)
{
171
    int ret;
172
    unsigned int cmd;
173 174 175 176
    hypercall_t hc;

    op->interface_version = DOM0_INTERFACE_VERSION;
    hc.op = __HYPERVISOR_dom0_op;
177
    hc.arg[0] = (unsigned long) op;
178

179 180
    if (mlock(op, sizeof(dom0_op_t)) < 0) {
        virXenError(VIR_ERR_XEN_CALL, " locking", sizeof(dom0_op_t));
181
        return (-1);
182
    }
183

184 185
    cmd = _IOC(_IOC_NONE, 'P', 0, sizeof(hc));
    ret = ioctl(handle, cmd, (unsigned long) &hc);
186 187 188
    if (ret < 0) {
        virXenError(VIR_ERR_XEN_CALL, " ioctl ", cmd);
    }
189

190 191
    if (munlock(op, sizeof(dom0_op_t)) < 0) {
        virXenError(VIR_ERR_XEN_CALL, " releasing", sizeof(dom0_op_t));
192
        ret = -1;
193
    }
194 195

    if (ret < 0)
196 197 198
        return (-1);

    return (0);
199 200
}

201 202
/**
 * xenHypervisorGetVersion:
203 204
 * @conn: pointer to the connection block
 * @hvVer: where to store the version
205 206 207
 *
 * Call the hypervisor to extracts his own internal API version
 *
208
 * Returns 0 in case of success, -1 in case of error
209
 */
210 211
int
xenHypervisorGetVersion(virConnectPtr conn, unsigned long *hvVer)
212
{
213 214 215 216
    int ret;
    unsigned int cmd;
    hypercall_t hc;

217 218 219 220
    if ((conn == NULL) || (conn->handle < 0) || (hvVer == NULL))
        return (-1);
    *hvVer = 0;

221
    hc.op = __HYPERVISOR_xen_version;
222
    hc.arg[0] = (unsigned long) XENVER_version;
223 224 225
    hc.arg[1] = 0;

    cmd = _IOC(_IOC_NONE, 'P', 0, sizeof(hc));
226
    ret = ioctl(conn->handle, cmd, (unsigned long) &hc);
227

228 229
    if (ret < 0) {
        virXenError(VIR_ERR_XEN_CALL, " getting version ", XENVER_version);
230
        return (-1);
231
    }
232 233
    *hvVer = (ret >> 16) * 1000000 + (ret & 0xFFFF) * 1000;
    return(0);
234 235
}

236 237
/**
 * xenHypervisorGetDomainInfo:
238
 * @domain: pointer to the domain block
239 240 241 242 243 244 245
 * @info: the place where informations should be stored
 *
 * Do an hypervisor call to get the related set of domain informations.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
246
xenHypervisorGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info)
247
{
248
    dom0_op_t op;
249
    dom0_getdomaininfo_t dominfo;
250 251
    int ret;

252 253
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0) || (info == NULL))
254
        return (-1);
255

256 257
    memset(info, 0, sizeof(virDomainInfo));
    memset(&dominfo, 0, sizeof(dom0_getdomaininfo_t));
258

259
    if (mlock(info, sizeof(dom0_getdomaininfo_t)) < 0) {
260 261 262
        virXenError(VIR_ERR_XEN_CALL, " locking",
                    sizeof(dom0_getdomaininfo_t));
        return (-1);
263
    }
264 265

    op.cmd = DOM0_GETDOMAININFOLIST;
266
    op.u.getdomaininfolist.first_domain = (domid_t) domain->handle;
267
    op.u.getdomaininfolist.max_domains = 1;
268
    op.u.getdomaininfolist.buffer = &dominfo;
269
    op.u.getdomaininfolist.num_domains = 1;
270
    dominfo.domain = domain->handle;
271

272
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
273

274
    if (munlock(info, sizeof(dom0_getdomaininfo_t)) < 0) {
275 276
        virXenError(VIR_ERR_XEN_CALL, " release",
                    sizeof(dom0_getdomaininfo_t));
277
        ret = -1;
278
    }
279

280
    if (ret < 0)
281
        return (-1);
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311

    switch (dominfo.flags & 0xFF) {
	case DOMFLAGS_DYING:
	    info->state = VIR_DOMAIN_SHUTDOWN;
	    break;
	case DOMFLAGS_SHUTDOWN:
	    info->state = VIR_DOMAIN_SHUTOFF;
	    break;
	case DOMFLAGS_PAUSED:
	    info->state = VIR_DOMAIN_PAUSED;
	    break;
	case DOMFLAGS_BLOCKED:
	    info->state = VIR_DOMAIN_BLOCKED;
	    break;
	case DOMFLAGS_RUNNING:
	    info->state = VIR_DOMAIN_RUNNING;
	    break;
	default:
	    info->state = VIR_DOMAIN_NONE;
    }

    /*
     * the API brings back the cpu time in nanoseconds,
     * convert to microseconds, same thing convert to
     * kilobytes from page counts
     */
    info->cpuTime = dominfo.cpu_time;
    info->memory = dominfo.tot_pages * 4;
    info->maxMem = dominfo.max_pages * 4;
    info->nrVirtCpu = dominfo.nr_online_vcpus;
312
    return (0);
313 314
}

315 316
/**
 * xenHypervisorPauseDomain:
317
 * @domain: pointer to the domain block
318 319 320 321 322 323
 *
 * Do an hypervisor call to pause the given domain
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
324
xenHypervisorPauseDomain(virDomainPtr domain)
325
{
326 327 328
    dom0_op_t op;
    int ret;

329 330 331 332
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0))
        return (-1);

333
    op.cmd = DOM0_PAUSEDOMAIN;
334
    op.u.pausedomain.domain = (domid_t) domain->handle;
335

336
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
337 338

    if (ret < 0)
339 340
        return (-1);
    return (0);
341 342 343 344
}

/**
 * xenHypervisorResumeDomain:
345
 * @domain: pointer to the domain block
346 347 348 349 350 351
 *
 * Do an hypervisor call to resume the given domain
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
352
xenHypervisorResumeDomain(virDomainPtr domain)
353
{
354 355 356
    dom0_op_t op;
    int ret;

357 358 359 360
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0))
        return (-1);

361
    op.cmd = DOM0_UNPAUSEDOMAIN;
362
    op.u.unpausedomain.domain = (domid_t) domain->handle;
363

364
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
365 366

    if (ret < 0)
367 368
        return (-1);
    return (0);
369 370 371 372
}

/**
 * xenHypervisorDestroyDomain:
373
 * @domain: pointer to the domain block
374 375 376 377 378 379
 *
 * Do an hypervisor call to destroy the given domain
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
380
xenHypervisorDestroyDomain(virDomainPtr domain)
381
{
382 383 384
    dom0_op_t op;
    int ret;

385 386 387 388
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0))
        return (-1);

389
    op.cmd = DOM0_DESTROYDOMAIN;
390
    op.u.destroydomain.domain = (domid_t) domain->handle;
391

392
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
393 394

    if (ret < 0)
395 396
        return (-1);
    return (0);
397 398
}

399 400
/**
 * xenHypervisorSetMaxMemory:
401
 * @domain: pointer to the domain block
402 403 404 405 406 407 408
 * @memory: the max memory size in kilobytes.
 *
 * Do an hypervisor call to change the maximum amount of memory used
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
409
xenHypervisorSetMaxMemory(virDomainPtr domain, unsigned long memory)
410
{
411 412 413
    dom0_op_t op;
    int ret;

414 415 416 417
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0))
        return (-1);

418
    op.cmd = DOM0_SETDOMAINMAXMEM;
419
    op.u.setdomainmaxmem.domain = (domid_t) domain->handle;
420 421
    op.u.setdomainmaxmem.max_memkb = memory;

422
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
423 424

    if (ret < 0)
425 426
        return (-1);
    return (0);
427
}