xen_internal.c 9.9 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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
static virDriver xenHypervisorDriver = {
    "Xen",
    NULL, /* init */
    xenHypervisorOpen, /* open */
    xenHypervisorClose, /* close */
    NULL, /* type */
    xenHypervisorGetVersion, /* version */
    NULL, /* listDomains */
    NULL, /* numOfDomains */
    NULL, /* domainCreateLinux */
    NULL, /* domainLookupByID */
    NULL, /* domainLookupByUUID */
    NULL, /* domainLookupByName */
    xenHypervisorPauseDomain, /* domainSuspend */
    xenHypervisorResumeDomain, /* domainResume */
    NULL, /* domainShutdown */
    xenHypervisorDestroyDomain, /* domainDestroy */
    NULL, /* domainFree */
    NULL, /* domainGetName */
    NULL, /* domainGetID */
    NULL, /* domainGetUUID */
    NULL, /* domainGetOSType */
    NULL, /* domainGetMaxMemory */
    xenHypervisorSetMaxMemory, /* domainSetMaxMemory */
    xenHypervisorGetDomainInfo, /* domainGetInfo */
    NULL, /* domainSave */
    NULL /* domainRestore */
};

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

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

95 96 97 98 99
    if (error == VIR_ERR_OK)
        return;

    errmsg = __virErrorMsg(error, info);
    __virRaiseError(NULL, NULL, VIR_FROM_XEN, error, VIR_ERR_ERROR,
100
                    errmsg, info, NULL, value, 0, errmsg, info, value);
101 102
}

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

118 119 120 121 122
    if ((name != NULL) && (strcmp(name, "xen")))
        return(-1);

    conn->handle = -1;

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

131
    return (ret);
132 133 134 135
}

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

147
    if ((conn == NULL) || (conn->handle < 0))
148
        return (-1);
149

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

/**
 * 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
166 167
xenHypervisorDoOp(int handle, dom0_op_t * op)
{
168
    int ret;
169
    unsigned int cmd;
170 171 172 173
    hypercall_t hc;

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

176 177
    if (mlock(op, sizeof(dom0_op_t)) < 0) {
        virXenError(VIR_ERR_XEN_CALL, " locking", sizeof(dom0_op_t));
178
        return (-1);
179
    }
180

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

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

    if (ret < 0)
193 194 195
        return (-1);

    return (0);
196 197
}

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

214 215 216 217
    if ((conn == NULL) || (conn->handle < 0) || (hvVer == NULL))
        return (-1);
    *hvVer = 0;

218
    hc.op = __HYPERVISOR_xen_version;
219
    hc.arg[0] = (unsigned long) XENVER_version;
220 221 222
    hc.arg[1] = 0;

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

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

233 234
/**
 * xenHypervisorGetDomainInfo:
235
 * @domain: pointer to the domain block
236 237 238 239 240 241 242
 * @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
243
xenHypervisorGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info)
244
{
245
    dom0_op_t op;
246
    dom0_getdomaininfo_t dominfo;
247 248
    int ret;

249 250
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0) || (info == NULL))
251
        return (-1);
252

253 254
    memset(info, 0, sizeof(virDomainInfo));
    memset(&dominfo, 0, sizeof(dom0_getdomaininfo_t));
255

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

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

269
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
270

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

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

    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;
309
    return (0);
310 311
}

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

326 327 328 329
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0))
        return (-1);

330
    op.cmd = DOM0_PAUSEDOMAIN;
331
    op.u.pausedomain.domain = (domid_t) domain->handle;
332

333
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
334 335

    if (ret < 0)
336 337
        return (-1);
    return (0);
338 339 340 341
}

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

354 355 356 357
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0))
        return (-1);

358
    op.cmd = DOM0_UNPAUSEDOMAIN;
359
    op.u.unpausedomain.domain = (domid_t) domain->handle;
360

361
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
362 363

    if (ret < 0)
364 365
        return (-1);
    return (0);
366 367 368 369
}

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

382 383 384 385
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0))
        return (-1);

386
    op.cmd = DOM0_DESTROYDOMAIN;
387
    op.u.destroydomain.domain = (domid_t) domain->handle;
388

389
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
390 391

    if (ret < 0)
392 393
        return (-1);
    return (0);
394 395
}

396 397
/**
 * xenHypervisorSetMaxMemory:
398
 * @domain: pointer to the domain block
399 400 401 402 403 404 405
 * @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
406
xenHypervisorSetMaxMemory(virDomainPtr domain, unsigned long memory)
407
{
408 409 410
    dom0_op_t op;
    int ret;

411 412 413 414
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0))
        return (-1);

415
    op.cmd = DOM0_SETDOMAINMAXMEM;
416
    op.u.setdomainmaxmem.domain = (domid_t) domain->handle;
417 418
    op.u.setdomainmaxmem.max_memkb = memory;

419
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
420 421

    if (ret < 0)
422 423
        return (-1);
    return (0);
424
}