xen_internal.c 9.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * 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>
#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>

#include <xen/dom0_ops.h>
22
#include <xen/version.h>
23 24 25
#include <xen/xen.h>

#ifndef __LINUX_PUBLIC_PRIVCMD_H__
26
typedef struct hypercall_struct {
27 28 29 30 31 32 33
    unsigned long op;
    unsigned long arg[5];
} hypercall_t;
#endif


#include "internal.h"
34
#include "driver.h"
35 36 37 38
#include "xen_internal.h"

#define XEN_HYPERVISOR_SOCKET "/proc/xen/privcmd"

39 40 41 42 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
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 */
};

68 69 70 71 72 73 74 75 76
/**
 * virXenError:
 * @conn: the connection if available
 * @error: the error number
 * @info: extra information string
 *
 * Handle an error at the xend daemon interface
 */
static void
77 78
virXenError(virErrorNumber error, const char *info, int value)
{
79
    const char *errmsg;
80

81 82 83 84 85
    if (error == VIR_ERR_OK)
        return;

    errmsg = __virErrorMsg(error, info);
    __virRaiseError(NULL, NULL, VIR_FROM_XEN, error, VIR_ERR_ERROR,
86
                    errmsg, info, NULL, value, 0, errmsg, info, value);
87 88
}

89 90
/**
 * xenHypervisorOpen:
91 92 93
 * @conn: pointer to the connection block
 * @name: URL for the target, NULL for local
 * @flags: combination of virDrvOpenFlag(s)
94 95 96
 *
 * Connects to the Xen hypervisor.
 *
97
 * Returns 0 or -1 in case of error.
98
 */
99
int
100
xenHypervisorOpen(virConnectPtr conn, const char *name, int flags)
101
{
102 103
    int ret;

104 105 106 107 108
    if ((name != NULL) && (strcmp(name, "xen")))
        return(-1);

    conn->handle = -1;

109
    ret = open(XEN_HYPERVISOR_SOCKET, O_RDWR);
110
    if (ret < 0) {
111
        if (!(flags & VIR_DRV_OPEN_QUIET))
112 113
            virXenError(VIR_ERR_NO_XEN, XEN_HYPERVISOR_SOCKET, 0);
        return (-1);
114
    }
115
    conn->handle = ret;
116

117
    return (ret);
118 119 120 121
}

/**
 * xenHypervisorClose:
122
 * @conn: pointer to the connection block
123 124 125 126 127
 *
 * Close the connection to the Xen hypervisor.
 *
 * Returns 0 in case of success or -1 in case of error.
 */
128
int
129
xenHypervisorClose(virConnectPtr conn)
130
{
131 132
    int ret;

133
    if ((conn == NULL) || (conn->handle < 0))
134
        return (-1);
135

136
    ret = close(conn->handle);
137
    if (ret < 0)
138 139
        return (-1);
    return (0);
140 141 142 143 144 145 146 147 148 149 150 151
}

/**
 * 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
152 153
xenHypervisorDoOp(int handle, dom0_op_t * op)
{
154
    int ret;
155
    unsigned int cmd;
156 157 158 159
    hypercall_t hc;

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

162 163
    if (mlock(op, sizeof(dom0_op_t)) < 0) {
        virXenError(VIR_ERR_XEN_CALL, " locking", sizeof(dom0_op_t));
164
        return (-1);
165
    }
166

167 168
    cmd = _IOC(_IOC_NONE, 'P', 0, sizeof(hc));
    ret = ioctl(handle, cmd, (unsigned long) &hc);
169 170 171
    if (ret < 0) {
        virXenError(VIR_ERR_XEN_CALL, " ioctl ", cmd);
    }
172

173 174
    if (munlock(op, sizeof(dom0_op_t)) < 0) {
        virXenError(VIR_ERR_XEN_CALL, " releasing", sizeof(dom0_op_t));
175
        ret = -1;
176
    }
177 178

    if (ret < 0)
179 180 181
        return (-1);

    return (0);
182 183
}

184 185
/**
 * xenHypervisorGetVersion:
186 187
 * @conn: pointer to the connection block
 * @hvVer: where to store the version
188 189 190
 *
 * Call the hypervisor to extracts his own internal API version
 *
191
 * Returns 0 in case of success, -1 in case of error
192
 */
193 194
int
xenHypervisorGetVersion(virConnectPtr conn, unsigned long *hvVer)
195
{
196 197 198 199
    int ret;
    unsigned int cmd;
    hypercall_t hc;

200 201 202 203
    if ((conn == NULL) || (conn->handle < 0) || (hvVer == NULL))
        return (-1);
    *hvVer = 0;

204
    hc.op = __HYPERVISOR_xen_version;
205
    hc.arg[0] = (unsigned long) XENVER_version;
206 207 208
    hc.arg[1] = 0;

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

211 212
    if (ret < 0) {
        virXenError(VIR_ERR_XEN_CALL, " getting version ", XENVER_version);
213
        return (-1);
214
    }
215 216
    *hvVer = (ret >> 16) * 1000000 + (ret & 0xFFFF) * 1000;
    return(0);
217 218
}

219 220
/**
 * xenHypervisorGetDomainInfo:
221
 * @domain: pointer to the domain block
222 223 224 225 226 227 228
 * @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
229
xenHypervisorGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info)
230
{
231
    dom0_op_t op;
232
    dom0_getdomaininfo_t dominfo;
233 234
    int ret;

235 236
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0) || (info == NULL))
237
        return (-1);
238

239 240
    memset(info, 0, sizeof(virDomainInfo));
    memset(&dominfo, 0, sizeof(dom0_getdomaininfo_t));
241

242
    if (mlock(info, sizeof(dom0_getdomaininfo_t)) < 0) {
243 244 245
        virXenError(VIR_ERR_XEN_CALL, " locking",
                    sizeof(dom0_getdomaininfo_t));
        return (-1);
246
    }
247 248

    op.cmd = DOM0_GETDOMAININFOLIST;
249
    op.u.getdomaininfolist.first_domain = (domid_t) domain->handle;
250
    op.u.getdomaininfolist.max_domains = 1;
251
    op.u.getdomaininfolist.buffer = &dominfo;
252
    op.u.getdomaininfolist.num_domains = 1;
253
    dominfo.domain = domain->handle;
254

255
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
256

257
    if (munlock(info, sizeof(dom0_getdomaininfo_t)) < 0) {
258 259
        virXenError(VIR_ERR_XEN_CALL, " release",
                    sizeof(dom0_getdomaininfo_t));
260
        ret = -1;
261
    }
262

263
    if (ret < 0)
264
        return (-1);
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

    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;
295
    return (0);
296 297
}

298 299
/**
 * xenHypervisorPauseDomain:
300
 * @domain: pointer to the domain block
301 302 303 304 305 306
 *
 * Do an hypervisor call to pause the given domain
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
307
xenHypervisorPauseDomain(virDomainPtr domain)
308
{
309 310 311
    dom0_op_t op;
    int ret;

312 313 314 315
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0))
        return (-1);

316
    op.cmd = DOM0_PAUSEDOMAIN;
317
    op.u.pausedomain.domain = (domid_t) domain->handle;
318

319
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
320 321

    if (ret < 0)
322 323
        return (-1);
    return (0);
324 325 326 327
}

/**
 * xenHypervisorResumeDomain:
328
 * @domain: pointer to the domain block
329 330 331 332 333 334
 *
 * Do an hypervisor call to resume the given domain
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
335
xenHypervisorResumeDomain(virDomainPtr domain)
336
{
337 338 339
    dom0_op_t op;
    int ret;

340 341 342 343
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0))
        return (-1);

344
    op.cmd = DOM0_UNPAUSEDOMAIN;
345
    op.u.unpausedomain.domain = (domid_t) domain->handle;
346

347
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
348 349

    if (ret < 0)
350 351
        return (-1);
    return (0);
352 353 354 355
}

/**
 * xenHypervisorDestroyDomain:
356
 * @domain: pointer to the domain block
357 358 359 360 361 362
 *
 * Do an hypervisor call to destroy the given domain
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
363
xenHypervisorDestroyDomain(virDomainPtr domain)
364
{
365 366 367
    dom0_op_t op;
    int ret;

368 369 370 371
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0))
        return (-1);

372
    op.cmd = DOM0_DESTROYDOMAIN;
373
    op.u.destroydomain.domain = (domid_t) domain->handle;
374

375
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
376 377

    if (ret < 0)
378 379
        return (-1);
    return (0);
380 381
}

382 383
/**
 * xenHypervisorSetMaxMemory:
384
 * @domain: pointer to the domain block
385 386 387 388 389 390 391
 * @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
392
xenHypervisorSetMaxMemory(virDomainPtr domain, unsigned long memory)
393
{
394 395 396
    dom0_op_t op;
    int ret;

397 398 399 400
    if ((domain == NULL) || (domain->conn == NULL) ||
        (domain->conn->handle < 0))
        return (-1);

401
    op.cmd = DOM0_SETDOMAINMAXMEM;
402
    op.u.setdomainmaxmem.domain = (domid_t) domain->handle;
403 404
    op.u.setdomainmaxmem.max_memkb = memory;

405
    ret = xenHypervisorDoOp(domain->conn->handle, &op);
406 407

    if (ret < 0)
408 409
        return (-1);
    return (0);
410
}