From: mjw@wray-m-3.hpl.hp.com Date: Wed, 30 Jun 2004 09:52:59 +0000 (+0000) Subject: bitkeeper revision 1.1034 (40e28d7bx0XoTn2USwCDCvPvUTLZjQ) X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~18087 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=5d9ba6096cd2847852ce931d51e428cc3745b6b6;p=xen.git bitkeeper revision 1.1034 (40e28d7bx0XoTn2USwCDCvPvUTLZjQ) Rename ext to lowlevel. --- diff --git a/.rootkeys b/.rootkeys index 833c2f0cd2..5045bae458 100644 --- a/.rootkeys +++ b/.rootkeys @@ -240,13 +240,11 @@ 40c9c468icGyC5RAF1bRKsCXPDCvsA tools/python/Makefile 40c9c469n2RRwCmjWdjdyyVRWKmgWg tools/python/setup.py 40dc4076hGpwa8-sWRN0jtXZeQJuKg tools/python/xen/__init__.py -40dfd40aMOhnw_cQLve9462UR5yYxQ tools/python/xen/ext/__init__.py -3fbd0a3dTwnDcfdw0-v46dPbX98zDw tools/python/xen/ext/xc/Makefile -3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/python/xen/ext/xc/setup.py -3fbd0a42l40lM0IICw2jXbQBVZSdZg tools/python/xen/ext/xc/xc.c -40dc4076St6AmPTmQPrtQ6LGHPxGmw tools/python/xen/ext/xu/__init__.py -40dc4076pVeE1kEEWzcUaNZin65kCA tools/python/xen/ext/xu/domain_controller.h -40dc4076CwBYRTUQDdbdU1L6KcLgSw tools/python/xen/ext/xu/xu.c +40dfd40aMOhnw_cQLve9462UR5yYxQ tools/python/xen/lowlevel/__init__.py +3fbd0a42l40lM0IICw2jXbQBVZSdZg tools/python/xen/lowlevel/xc/xc.c +40dc4076St6AmPTmQPrtQ6LGHPxGmw tools/python/xen/lowlevel/xu/__init__.py +40dc4076pVeE1kEEWzcUaNZin65kCA tools/python/xen/lowlevel/xu/domain_controller.h +40dc4076CwBYRTUQDdbdU1L6KcLgSw tools/python/xen/lowlevel/xu/xu.c 40d8915cyoVA0hJxiBFNymL7YvDaRg tools/python/xen/util/Brctl.py 40dfd40aGqGkiopOOgJxSF4iCbHM0Q tools/python/xen/util/__init__.py 4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/python/xen/util/console_client.py diff --git a/tools/Make.defs b/tools/Make.defs index 051baef2fc..938b6cccb4 100644 --- a/tools/Make.defs +++ b/tools/Make.defs @@ -1,7 +1,7 @@ # -*- mode: Makefile; -*- XEN_HYPERVISOR_IFS = $(XEN_ROOT)/xen/include/hypervisor-ifs XEN_LINUX_INCLUDE = $(XEN_ROOT)/linux-xen-sparse/include -XEN_XU = $(XEN_ROOT)/tools/python/xen/ext/xu -XEN_XC = $(XEN_ROOT)/tools/python/xen/ext/xc +XEN_XU = $(XEN_ROOT)/tools/python/xen/lowlevel/xu +XEN_XC = $(XEN_ROOT)/tools/python/xen/lowlevel/xc XEN_LIBXC = $(XEN_ROOT)/tools/libxc XEN_LIBXUTIL = $(XEN_ROOT)/tools/libxutil diff --git a/tools/python/setup.py b/tools/python/setup.py index 0b8efce0fd..93e7cad00c 100644 --- a/tools/python/setup.py +++ b/tools/python/setup.py @@ -8,7 +8,7 @@ extra_compile_args = [ "-fno-strict-aliasing", "-Wall", "-Werror" ] include_dirs = [ XEN_ROOT + "/xen/include/hypervisor-ifs", XEN_ROOT + "/linux-xen-sparse/include", - XEN_ROOT + "/tools/python/xen/ext/xu", + XEN_ROOT + "/tools/python/xen/lowlevel/xu", XEN_ROOT + "/tools/libxc", XEN_ROOT + "/tools/libxutil", ] @@ -21,28 +21,28 @@ libraries = [ "xc", "xutil" ] xc = Extension("xc", extra_compile_args = extra_compile_args, - include_dirs = include_dirs + [ "xen/ext/xc" ], + include_dirs = include_dirs + [ "xen/lowlevel/xc" ], library_dirs = library_dirs, libraries = libraries, - sources = [ "xen/ext/xc/xc.c" ]) + sources = [ "xen/lowlevel/xc/xc.c" ]) xu = Extension("xu", extra_compile_args = extra_compile_args, - include_dirs = include_dirs + [ "xen/ext/xu" ], + include_dirs = include_dirs + [ "xen/lowlevel/xu" ], library_dirs = library_dirs, libraries = libraries, - sources = [ "xen/ext/xu/xu.c" ]) + sources = [ "xen/lowlevel/xu/xu.c" ]) setup(name = 'xen', version = '2.0', description = 'Xen', packages = ['xen', - 'xen.ext', + 'xen.lowlevel', 'xen.util', 'xen.xend', 'xen.xend.server', 'xen.xm', ], - ext_package = "xen.ext", + ext_package = "xen.lowlevel", ext_modules = [ xc, xu ] ) diff --git a/tools/python/xen/ext/__init__.py b/tools/python/xen/ext/__init__.py deleted file mode 100644 index 8d1c8b69c3..0000000000 --- a/tools/python/xen/ext/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tools/python/xen/ext/xc/Makefile b/tools/python/xen/ext/xc/Makefile deleted file mode 100644 index 7dc74a1072..0000000000 --- a/tools/python/xen/ext/xc/Makefile +++ /dev/null @@ -1,15 +0,0 @@ - -all: - python setup.py build - -install: all - if [ "$(prefix)" = "" ]; then \ - python setup.py install; \ - elif [ "$(dist)" = "yes" ]; then \ - python setup.py install --home="$(prefix)"; \ - else \ - python setup.py install --root="$(prefix)"; \ - fi - -clean: - rm -rf build *.pyc *.pyo *.o *.a *~ diff --git a/tools/python/xen/ext/xc/setup.py b/tools/python/xen/ext/xc/setup.py deleted file mode 100644 index 8efe5ca1a0..0000000000 --- a/tools/python/xen/ext/xc/setup.py +++ /dev/null @@ -1,19 +0,0 @@ - -from distutils.core import setup, Extension - -module = Extension("xc", - extra_compile_args = ["-fno-strict-aliasing"], - include_dirs = ["../lib", - "../../../xen/include/hypervisor-ifs", - "../../../linux-xen-sparse/include", - "../../xu/lib", - "../../lib" ], - library_dirs = ["../lib", - "../../lib" ], - libraries = ["xc"], - sources = ["Xc.c"]) - -setup(name = "xc", - version = "2.0", - ext_package = "xen.ext", - ext_modules = [module]) diff --git a/tools/python/xen/ext/xc/xc.c b/tools/python/xen/ext/xc/xc.c deleted file mode 100644 index 003e1fad35..0000000000 --- a/tools/python/xen/ext/xc/xc.c +++ /dev/null @@ -1,1184 +0,0 @@ -/****************************************************************************** - * Xc.c - * - * Copyright (c) 2003-2004, K A Fraser (University of Cambridge) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "xc_private.h" -#include "gzip_stream.h" - -/* Needed for Python versions earlier than 2.3. */ -#ifndef PyMODINIT_FUNC -#define PyMODINIT_FUNC DL_EXPORT(void) -#endif - -#define XENPKG "xen.ext.xc" - -static PyObject *xc_error, *zero; - -typedef struct { - PyObject_HEAD; - int xc_handle; -} XcObject; - -/* - * Definitions for the 'xc' object type. - */ - -static PyObject *pyxc_domain_create(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - unsigned int mem_kb = 0; - char *name = "(anon)"; - int cpu = -1; - u32 dom; - int ret; - - static char *kwd_list[] = { "mem_kb", "name", "cpu", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|isi", kwd_list, - &mem_kb, &name, &cpu) ) - return NULL; - - if ( (ret = xc_domain_create(xc->xc_handle, mem_kb, name, cpu, &dom)) < 0 ) - return PyErr_SetFromErrno(xc_error); - - return PyInt_FromLong(dom); -} - -static PyObject *pyxc_domain_pause(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - - static char *kwd_list[] = { "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) - return NULL; - - if ( xc_domain_pause(xc->xc_handle, dom) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_domain_unpause(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - - static char *kwd_list[] = { "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) - return NULL; - - if ( xc_domain_unpause(xc->xc_handle, dom) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_domain_destroy(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - - static char *kwd_list[] = { "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) - return NULL; - - if ( xc_domain_destroy(xc->xc_handle, dom) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_domain_pincpu(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - int cpu = -1; - - static char *kwd_list[] = { "dom", "cpu", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, - &dom, &cpu) ) - return NULL; - - if ( xc_domain_pincpu(xc->xc_handle, dom, cpu) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_domain_getinfo(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - PyObject *list; - - u32 first_dom = 0; - int max_doms = 1024, nr_doms, i; - xc_dominfo_t *info; - - static char *kwd_list[] = { "first_dom", "max_doms", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, - &first_dom, &max_doms) ) - return NULL; - - if ( (info = malloc(max_doms * sizeof(xc_dominfo_t))) == NULL ) - return PyErr_NoMemory(); - - nr_doms = xc_domain_getinfo(xc->xc_handle, first_dom, max_doms, info); - - list = PyList_New(nr_doms); - for ( i = 0 ; i < nr_doms; i++ ) - { - PyList_SetItem( - list, i, - Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i" - ",s:l,s:L,s:s,s:l,s:i}", - "dom", info[i].domid, - "cpu", info[i].cpu, - "dying", info[i].dying, - "crashed", info[i].crashed, - "shutdown", info[i].shutdown, - "paused", info[i].paused, - "blocked", info[i].blocked, - "running", info[i].running, - "mem_kb", info[i].nr_pages*4, - "cpu_time", info[i].cpu_time, - "name", info[i].name, - "maxmem_kb", info[i].max_memkb, - "shutdown_reason", info[i].shutdown_reason - )); - } - - free(info); - - return list; -} - -static int file_save(XcObject *xc, XcIOContext *ctxt, char *state_file) -{ - int rc = -1; - int fd = -1; - int open_flags = (O_CREAT | O_EXCL | O_WRONLY); - int open_mode = 0644; - - printf("%s>\n", __FUNCTION__); - - if ( (fd = open(state_file, open_flags, open_mode)) < 0 ) - { - xcio_perror(ctxt, "Could not open file for writing"); - goto exit; - } - - printf("%s>gzip_stream_fdopen... \n", __FUNCTION__); - - /* Compression rate 1: we want speed over compression. - * We're mainly going for those zero pages, after all. - */ - ctxt->io = gzip_stream_fdopen(fd, "wb1"); - if ( ctxt->io == NULL ) - { - xcio_perror(ctxt, "Could not allocate compression state"); - goto exit; - } - - printf("%s> xc_linux_save...\n", __FUNCTION__); - - rc = xc_linux_save(xc->xc_handle, ctxt); - - exit: - if ( ctxt->io != NULL ) - IOStream_close(ctxt->io); - if ( fd >= 0 ) - close(fd); - unlink(state_file); - printf("%s> rc=%d\n", __FUNCTION__, rc); - return rc; -} - -static PyObject *pyxc_linux_save(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - char *state_file; - int progress = 1, debug = 0; - PyObject *val = NULL; - int rc = -1; - XcIOContext ioctxt = { .info = iostdout, .err = iostderr }; - - static char *kwd_list[] = { "dom", "state_file", "vmconfig", "progress", "debug", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is|sii", kwd_list, - &ioctxt.domain, - &state_file, - &ioctxt.vmconfig, - &progress, - &debug) ) - goto exit; - - ioctxt.vmconfig_n = (ioctxt.vmconfig ? strlen(ioctxt.vmconfig) : 0); - - if ( progress ) - ioctxt.flags |= XCFLAGS_VERBOSE; - if ( debug ) - ioctxt.flags |= XCFLAGS_DEBUG; - - if ( (state_file == NULL) || (state_file[0] == '\0') ) - goto exit; - - rc = file_save(xc, &ioctxt, state_file); - if ( rc != 0 ) - { - PyErr_SetFromErrno(xc_error); - goto exit; - } - - Py_INCREF(zero); - val = zero; - - exit: - return val; -} - - -static int file_restore(XcObject *xc, XcIOContext *ioctxt, char *state_file) -{ - int rc = -1; - - ioctxt->io = gzip_stream_fopen(state_file, "rb"); - if ( ioctxt->io == NULL ) - { - xcio_perror(ioctxt, "Could not open file for reading"); - return rc; - } - - rc = xc_linux_restore(xc->xc_handle, ioctxt); - - IOStream_close(ioctxt->io); - - return rc; -} - -static PyObject *pyxc_linux_restore(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - char *state_file; - int progress = 1, debug = 0; - PyObject *val = NULL; - XcIOContext ioctxt = { .info = iostdout, .err = iostderr }; - int rc =-1; - - static char *kwd_list[] = { "state_file", "progress", "debug", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is|ii", kwd_list, - &ioctxt.domain, - &state_file, - &progress, - &debug) ) - goto exit; - - if ( progress ) - ioctxt.flags |= XCFLAGS_VERBOSE; - if ( debug ) - ioctxt.flags |= XCFLAGS_DEBUG; - - if ( (state_file == NULL) || (state_file[0] == '\0') ) - goto exit; - - rc = file_restore(xc, &ioctxt, state_file); - if ( rc != 0 ) - { - PyErr_SetFromErrno(xc_error); - goto exit; - } - - val = Py_BuildValue("{s:i,s:s}", - "dom", ioctxt.domain, - "vmconfig", ioctxt.vmconfig); - - exit: - return val; -} - -static PyObject *pyxc_linux_build(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - char *image, *ramdisk = NULL, *cmdline = ""; - int control_evtchn, flags = 0; - - static char *kwd_list[] = { "dom", "control_evtchn", - "image", "ramdisk", "cmdline", "flags", - NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list, - &dom, &control_evtchn, - &image, &ramdisk, &cmdline, &flags) ) - return NULL; - - if ( xc_linux_build(xc->xc_handle, dom, image, - ramdisk, cmdline, control_evtchn, flags) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_netbsd_build(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - char *image, *ramdisk = NULL, *cmdline = ""; - int control_evtchn; - - static char *kwd_list[] = { "dom", "control_evtchn", - "image", "ramdisk", "cmdline", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list, - &dom, &control_evtchn, - &image, &ramdisk, &cmdline) ) - return NULL; - - if ( xc_netbsd_build(xc->xc_handle, dom, image, - cmdline, control_evtchn) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_bvtsched_global_set(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - unsigned long ctx_allow; - - static char *kwd_list[] = { "ctx_allow", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "l", kwd_list, &ctx_allow) ) - return NULL; - - if ( xc_bvtsched_global_set(xc->xc_handle, ctx_allow) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_bvtsched_global_get(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - unsigned long ctx_allow; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( xc_bvtsched_global_get(xc->xc_handle, &ctx_allow) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("s:l", "ctx_allow", ctx_allow); -} - -static PyObject *pyxc_bvtsched_domain_set(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - unsigned long mcuadv, warp, warpl, warpu; - - static char *kwd_list[] = { "dom", "mcuadv", "warp", "warpl", - "warpu", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "illll", kwd_list, - &dom, &mcuadv, &warp, &warpl, &warpu) ) - return NULL; - - if ( xc_bvtsched_domain_set(xc->xc_handle, dom, mcuadv, - warp, warpl, warpu) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_bvtsched_domain_get(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u32 dom; - unsigned long mcuadv, warp, warpl, warpu; - - static char *kwd_list[] = { "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) - return NULL; - - if ( xc_bvtsched_domain_get(xc->xc_handle, dom, &mcuadv, &warp, - &warpl, &warpu) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("{s:i,s:l,s:l,s:l,s:l}", - "domain", dom, - "mcuadv", mcuadv, - "warp", warp, - "warpl", warpl, - "warpu", warpu); -} - -static PyObject *pyxc_evtchn_bind_interdomain(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom1 = DOMID_SELF, dom2 = DOMID_SELF; - int port1, port2; - - static char *kwd_list[] = { "dom1", "dom2", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, - &dom1, &dom2) ) - return NULL; - - if ( xc_evtchn_bind_interdomain(xc->xc_handle, dom1, - dom2, &port1, &port2) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("{s:i,s:i}", - "port1", port1, - "port2", port2); -} - -static PyObject *pyxc_evtchn_bind_virq(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - int virq, port; - - static char *kwd_list[] = { "virq", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &virq) ) - return NULL; - - if ( xc_evtchn_bind_virq(xc->xc_handle, virq, &port) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return PyInt_FromLong(port); -} - -static PyObject *pyxc_evtchn_close(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom = DOMID_SELF; - int port; - - static char *kwd_list[] = { "port", "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, - &port, &dom) ) - return NULL; - - if ( xc_evtchn_close(xc->xc_handle, dom, port) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_evtchn_send(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - int port; - - static char *kwd_list[] = { "port", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &port) ) - return NULL; - - if ( xc_evtchn_send(xc->xc_handle, port) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_evtchn_status(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - PyObject *dict; - - u32 dom = DOMID_SELF; - int port, ret; - xc_evtchn_status_t status; - - static char *kwd_list[] = { "port", "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, - &port, &dom) ) - return NULL; - - ret = xc_evtchn_status(xc->xc_handle, dom, port, &status); - if ( ret != 0 ) - return PyErr_SetFromErrno(xc_error); - - switch ( status.status ) - { - case EVTCHNSTAT_closed: - dict = Py_BuildValue("{s:s}", - "status", "closed"); - break; - case EVTCHNSTAT_unbound: - dict = Py_BuildValue("{s:s}", - "status", "unbound"); - break; - case EVTCHNSTAT_interdomain: - dict = Py_BuildValue("{s:s,s:i,s:i}", - "status", "interdomain", - "dom", status.u.interdomain.dom, - "port", status.u.interdomain.port); - break; - case EVTCHNSTAT_pirq: - dict = Py_BuildValue("{s:s,s:i}", - "status", "pirq", - "irq", status.u.pirq); - break; - case EVTCHNSTAT_virq: - dict = Py_BuildValue("{s:s,s:i}", - "status", "virq", - "irq", status.u.virq); - break; - default: - dict = Py_BuildValue("{}"); - break; - } - - return dict; -} - -static PyObject *pyxc_physdev_pci_access_modify(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u32 dom; - int bus, dev, func, enable, ret; - - static char *kwd_list[] = { "dom", "bus", "dev", "func", "enable", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiii", kwd_list, - &dom, &bus, &dev, &func, &enable) ) - return NULL; - - ret = xc_physdev_pci_access_modify( - xc->xc_handle, dom, bus, dev, func, enable); - if ( ret != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_readconsolering(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - unsigned int clear = 0; - char str[32768]; - int ret; - - static char *kwd_list[] = { "clear", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) ) - return NULL; - - ret = xc_readconsolering(xc->xc_handle, str, sizeof(str), clear); - if ( ret < 0 ) - return PyErr_SetFromErrno(xc_error); - - return PyString_FromStringAndSize(str, ret); -} - -static PyObject *pyxc_physinfo(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - xc_physinfo_t info; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( xc_physinfo(xc->xc_handle, &info) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("{s:i,s:i,s:l,s:l,s:l}", - "ht_per_core", info.ht_per_core, - "cores", info.cores, - "total_pages", info.total_pages, - "free_pages", info.free_pages, - "cpu_khz", info.cpu_khz); -} - -static PyObject *pyxc_atropos_domain_set(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u32 domid; - u64 period, slice, latency; - int xtratime; - - static char *kwd_list[] = { "dom", "period", "slice", "latency", - "xtratime", NULL }; - - if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLLLi", kwd_list, &domid, - &period, &slice, &latency, &xtratime) ) - return NULL; - - if ( xc_atropos_domain_set(xc->xc_handle, domid, period, slice, - latency, xtratime) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_atropos_domain_get(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u32 domid; - u64 period, slice, latency; - int xtratime; - - static char *kwd_list[] = { "dom", NULL }; - - if( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &domid) ) - return NULL; - - if ( xc_atropos_domain_get( xc->xc_handle, domid, &period, - &slice, &latency, &xtratime ) ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i}", - "domain", domid, - "period", period, - "slice", slice, - "latency", latency, - "xtratime", xtratime); -} - - -static PyObject *pyxc_rrobin_global_set(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u64 slice; - - static char *kwd_list[] = { "slice", NULL }; - - if( !PyArg_ParseTupleAndKeywords(args, kwds, "L", kwd_list, &slice) ) - return NULL; - - if ( xc_rrobin_global_set(xc->xc_handle, slice) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_shadow_control(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - int op=0; - - static char *kwd_list[] = { "dom", "op", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, - &dom, &op) ) - return NULL; - - if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, NULL) < 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_rrobin_global_get(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u64 slice; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( xc_rrobin_global_get(xc->xc_handle, &slice) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("{s:L}", "slice", slice); -} - -static PyObject *pyxc_domain_setname(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u32 dom; - char *name; - - static char *kwd_list[] = { "dom", "name", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list, - &dom, &name) ) - return NULL; - - if ( xc_domain_setname(xc->xc_handle, dom, name) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_domain_setmaxmem(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - unsigned long max_memkb; - - static char *kwd_list[] = { "dom", "max_memkb", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list, - &dom, &max_memkb) ) - return NULL; - - if ( xc_domain_setmaxmem(xc->xc_handle, dom, max_memkb) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - - -static PyMethodDef pyxc_methods[] = { - { "domain_create", - (PyCFunction)pyxc_domain_create, - METH_VARARGS | METH_KEYWORDS, "\n" - "Create a new domain.\n" - " mem_kb [int, 0]: Memory allocation, in kilobytes.\n" - " name [str, '(anon)']: Informative textual name.\n\n" - "Returns: [int] new domain identifier; -1 on error.\n" }, - - { "domain_pause", - (PyCFunction)pyxc_domain_pause, - METH_VARARGS | METH_KEYWORDS, "\n" - "Temporarily pause execution of a domain.\n" - " dom [int]: Identifier of domain to be paused.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "domain_unpause", - (PyCFunction)pyxc_domain_unpause, - METH_VARARGS | METH_KEYWORDS, "\n" - "(Re)start execution of a domain.\n" - " dom [int]: Identifier of domain to be unpaused.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "domain_destroy", - (PyCFunction)pyxc_domain_destroy, - METH_VARARGS | METH_KEYWORDS, "\n" - "Destroy a domain.\n" - " dom [int]: Identifier of domain to be destroyed.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "domain_pincpu", - (PyCFunction)pyxc_domain_pincpu, - METH_VARARGS | METH_KEYWORDS, "\n" - "Pin a domain to a specified CPU.\n" - " dom [int]: Identifier of domain to be pinned.\n" - " cpu [int, -1]: CPU to pin to, or -1 to unpin\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "domain_getinfo", - (PyCFunction)pyxc_domain_getinfo, - METH_VARARGS | METH_KEYWORDS, "\n" - "Get information regarding a set of domains, in increasing id order.\n" - " first_dom [int, 0]: First domain to retrieve info about.\n" - " max_doms [int, 1024]: Maximum number of domains to retrieve info" - " about.\n\n" - "Returns: [list of dicts] if list length is less than 'max_doms'\n" - " parameter then there was an error, or the end of the\n" - " domain-id space was reached.\n" - " dom [int]: Identifier of domain to which this info pertains\n" - " cpu [int]: CPU to which this domain is bound\n" - " dying [int]: Bool - is the domain dying?\n" - " crashed [int]: Bool - has the domain crashed?\n" - " shutdown [int]: Bool - has the domain shut itself down?\n" - " paused [int]: Bool - is the domain paused by control software?\n" - " blocked [int]: Bool - is the domain blocked waiting for an event?\n" - " running [int]: Bool - is the domain currently running?\n" - " mem_kb [int]: Memory reservation, in kilobytes\n" - " cpu_time [long]: CPU time consumed, in nanoseconds\n" - " name [str]: Identifying name\n" - " shutdown_reason [int]: Numeric code from guest OS, explaining " - "reason why it shut itself down.\n" }, - - { "linux_save", - (PyCFunction)pyxc_linux_save, - METH_VARARGS | METH_KEYWORDS, "\n" - "Save the CPU and memory state of a Linux guest OS.\n" - " dom [int]: Identifier of domain to be saved.\n" - " state_file [str]: Name of state file. Must not currently exist.\n" - " progress [int, 1]: Bool - display a running progress indication?\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "linux_restore", - (PyCFunction)pyxc_linux_restore, - METH_VARARGS | METH_KEYWORDS, "\n" - "Restore the CPU and memory state of a Linux guest OS.\n" - " state_file [str]: Name of state file. Must not currently exist.\n" - " progress [int, 1]: Bool - display a running progress indication?\n\n" - "Returns: [int] new domain identifier on success; -1 on error.\n" }, - - { "linux_build", - (PyCFunction)pyxc_linux_build, - METH_VARARGS | METH_KEYWORDS, "\n" - "Build a new Linux guest OS.\n" - " dom [int]: Identifier of domain to build into.\n" - " image [str]: Name of kernel image file. May be gzipped.\n" - " ramdisk [str, n/a]: Name of ramdisk file, if any.\n" - " cmdline [str, n/a]: Kernel parameters, if any.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "netbsd_build", - (PyCFunction)pyxc_netbsd_build, - METH_VARARGS | METH_KEYWORDS, "\n" - "Build a new NetBSD guest OS.\n" - " dom [int]: Identifier of domain to build into.\n" - " image [str]: Name of kernel image file. May be gzipped.\n" - " cmdline [str, n/a]: Kernel parameters, if any.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "bvtsched_global_set", - (PyCFunction)pyxc_bvtsched_global_set, - METH_VARARGS | METH_KEYWORDS, "\n" - "Set global tuning parameters for Borrowed Virtual Time scheduler.\n" - " ctx_allow [int]: Minimal guaranteed quantum.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "bvtsched_global_get", - (PyCFunction)pyxc_bvtsched_global_get, - METH_KEYWORDS, "\n" - "Get global tuning parameters for BVT scheduler.\n" - "Returns: [dict]:\n" - " ctx_allow [int]: context switch allowance\n" }, - - { "bvtsched_domain_set", - (PyCFunction)pyxc_bvtsched_domain_set, - METH_VARARGS | METH_KEYWORDS, "\n" - "Set per-domain tuning parameters for Borrowed Virtual Time scheduler.\n" - " dom [int]: Identifier of domain to be tuned.\n" - " mcuadv [int]: Proportional to the inverse of the domain's weight.\n" - " warp [int]: How far to warp domain's EVT on unblock.\n" - " warpl [int]: How long the domain can run warped.\n" - " warpu [int]: How long before the domain can warp again.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "bvtsched_domain_get", - (PyCFunction)pyxc_bvtsched_domain_get, - METH_KEYWORDS, "\n" - "Get per-domain tuning parameters under the BVT scheduler.\n" - " dom [int]: Identifier of domain to be queried.\n" - "Returns [dict]:\n" - " domain [int]: Domain ID.\n" - " mcuadv [long]: MCU Advance.\n" - " warp [long]: Warp.\n" - " warpu [long]: Unwarp requirement.\n" - " warpl [long]: Warp limit,\n" - }, - - { "atropos_domain_set", - (PyCFunction)pyxc_atropos_domain_set, - METH_KEYWORDS, "\n" - "Set the scheduling parameters for a domain when running with Atropos.\n" - " dom [int]: domain to set\n" - " period [long]: domain's scheduling period\n" - " slice [long]: domain's slice per period\n" - " latency [long]: wakeup latency hint\n" - " xtratime [int]: boolean\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "atropos_domain_get", - (PyCFunction)pyxc_atropos_domain_get, - METH_KEYWORDS, "\n" - "Get the current scheduling parameters for a domain when running with\n" - "the Atropos scheduler." - " dom [int]: domain to query\n" - "Returns: [dict]\n" - " domain [int]: domain ID\n" - " period [long]: scheduler period\n" - " slice [long]: CPU reservation per period\n" - " latency [long]: unblocking latency hint\n" - " xtratime [int] : 0 if not using slack time, nonzero otherwise\n" }, - - { "rrobin_global_set", - (PyCFunction)pyxc_rrobin_global_set, - METH_KEYWORDS, "\n" - "Set Round Robin scheduler slice.\n" - " slice [long]: Round Robin scheduler slice\n" - "Returns: [int] 0 on success, throws an exception on failure\n" }, - - { "rrobin_global_get", - (PyCFunction)pyxc_rrobin_global_get, - METH_KEYWORDS, "\n" - "Get Round Robin scheduler settings\n" - "Returns [dict]:\n" - " slice [long]: Scheduler time slice.\n" }, - - { "evtchn_bind_interdomain", - (PyCFunction)pyxc_evtchn_bind_interdomain, - METH_VARARGS | METH_KEYWORDS, "\n" - "Open an event channel between two domains.\n" - " dom1 [int, SELF]: First domain to be connected.\n" - " dom2 [int, SELF]: Second domain to be connected.\n\n" - "Returns: [dict] dictionary is empty on failure.\n" - " port1 [int]: Port-id for endpoint at dom1.\n" - " port2 [int]: Port-id for endpoint at dom2.\n" }, - - { "evtchn_bind_virq", - (PyCFunction)pyxc_evtchn_bind_virq, - METH_VARARGS | METH_KEYWORDS, "\n" - "Bind an event channel to the specified VIRQ.\n" - " virq [int]: VIRQ to bind.\n\n" - "Returns: [int] Bound event-channel port.\n" }, - - { "evtchn_close", - (PyCFunction)pyxc_evtchn_close, - METH_VARARGS | METH_KEYWORDS, "\n" - "Close an event channel.\n" - " dom [int, SELF]: Dom-id of one endpoint of the channel.\n" - " port [int]: Port-id of one endpoint of the channel.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "evtchn_send", - (PyCFunction)pyxc_evtchn_send, - METH_VARARGS | METH_KEYWORDS, "\n" - "Send an event along a locally-connected event channel.\n" - " port [int]: Port-id of a local channel endpoint.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "evtchn_status", - (PyCFunction)pyxc_evtchn_status, - METH_VARARGS | METH_KEYWORDS, "\n" - "Query the status of an event channel.\n" - " dom [int, SELF]: Dom-id of one endpoint of the channel.\n" - " port [int]: Port-id of one endpoint of the channel.\n\n" - "Returns: [dict] dictionary is empty on failure.\n" - " status [str]: 'closed', 'unbound', 'interdomain', 'pirq'," - " or 'virq'.\n" - "The following are returned if 'status' is 'interdomain':\n" - " dom [int]: Dom-id of remote endpoint.\n" - " port [int]: Port-id of remote endpoint.\n" - "The following are returned if 'status' is 'pirq' or 'virq':\n" - " irq [int]: IRQ number.\n" }, - - { "physdev_pci_access_modify", - (PyCFunction)pyxc_physdev_pci_access_modify, - METH_VARARGS | METH_KEYWORDS, "\n" - "Allow a domain access to a PCI device\n" - " dom [int]: Identifier of domain to be allowed access.\n" - " bus [int]: PCI bus\n" - " dev [int]: PCI slot\n" - " func [int]: PCI function\n" - " enable [int]: Non-zero means enable access; else disable access\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "readconsolering", - (PyCFunction)pyxc_readconsolering, - METH_VARARGS | METH_KEYWORDS, "\n" - "Read Xen's console ring.\n" - " clear [int, 0]: Bool - clear the ring after reading from it?\n\n" - "Returns: [str] string is empty on failure.\n" }, - - { "physinfo", - (PyCFunction)pyxc_physinfo, - METH_VARARGS, "\n" - "Get information about the physical host machine\n" - "Returns [dict]: information about the hardware" - " [None]: on failure.\n" }, - - { "shadow_control", - (PyCFunction)pyxc_shadow_control, - METH_VARARGS | METH_KEYWORDS, "\n" - "Set parameter for shadow pagetable interface\n" - " dom [int]: Identifier of domain.\n" - " op [int, 0]: operation\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "domain_setname", - (PyCFunction)pyxc_domain_setname, - METH_VARARGS | METH_KEYWORDS, "\n" - "Set domain informative textual name\n" - " dom [int]: Identifier of domain.\n" - " name [str]: Text string.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "domain_setmaxmem", - (PyCFunction)pyxc_domain_setmaxmem, - METH_VARARGS | METH_KEYWORDS, "\n" - "Set a domain's memory limit\n" - " dom [int]: Identifier of domain.\n" - " max_memkb [long]: .\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { NULL, NULL, 0, NULL } -}; - - -/* - * Definitions for the 'Xc' module wrapper. - */ - -staticforward PyTypeObject PyXcType; - -static PyObject *PyXc_new(PyObject *self, PyObject *args) -{ - XcObject *xc; - - if ( !PyArg_ParseTuple(args, ":new") ) - return NULL; - - xc = PyObject_New(XcObject, &PyXcType); - - if ( (xc->xc_handle = xc_interface_open()) == -1 ) - { - PyObject_Del((PyObject *)xc); - return PyErr_SetFromErrno(xc_error); - } - - return (PyObject *)xc; -} - -static PyObject *PyXc_getattr(PyObject *obj, char *name) -{ - return Py_FindMethod(pyxc_methods, obj, name); -} - -static void PyXc_dealloc(PyObject *self) -{ - XcObject *xc = (XcObject *)self; - (void)xc_interface_close(xc->xc_handle); - PyObject_Del(self); -} - -static PyTypeObject PyXcType = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "Xc", - sizeof(XcObject), - 0, - PyXc_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ - PyXc_getattr, /* tp_getattr */ - NULL, /* tp_setattr */ - NULL, /* tp_compare */ - NULL, /* tp_repr */ - NULL, /* tp_as_number */ - NULL, /* tp_as_sequence */ - NULL, /* tp_as_mapping */ - NULL /* tp_hash */ -}; - -static PyMethodDef PyXc_methods[] = { - { "new", PyXc_new, METH_VARARGS, "Create a new " XENPKG " object." }, - { NULL, NULL, 0, NULL } -}; - -PyMODINIT_FUNC initxc(void) -{ - PyObject *m, *d; - - m = Py_InitModule(XENPKG, PyXc_methods); - - d = PyModule_GetDict(m); - xc_error = PyErr_NewException(XENPKG ".error", NULL, NULL); - PyDict_SetItemString(d, "error", xc_error); - - zero = PyInt_FromLong(0); -} diff --git a/tools/python/xen/ext/xu/__init__.py b/tools/python/xen/ext/xu/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tools/python/xen/ext/xu/domain_controller.h b/tools/python/xen/ext/xu/domain_controller.h deleted file mode 100644 index 76dd164fcb..0000000000 --- a/tools/python/xen/ext/xu/domain_controller.h +++ /dev/null @@ -1,532 +0,0 @@ -/****************************************************************************** - * domain_controller.h - * - * Interface to server controller (e.g., 'xend'). This header file defines the - * interface that is shared with guest OSes. - * - * Copyright (c) 2004, K A Fraser - */ - -#ifndef __DOMAIN_CONTROLLER_H__ -#define __DOMAIN_CONTROLLER_H__ - - -#ifndef BASIC_START_INFO -#error "Xen header file hypervisor-if.h must already be included here." -#endif - - -/* - * EXTENDED BOOTSTRAP STRUCTURE FOR NEW DOMAINS. - */ - -typedef struct { - BASIC_START_INFO; - u16 domain_controller_evtchn; /* 320 */ -} PACKED extended_start_info_t; /* 322 bytes */ -#define SIF_BLK_BE_DOMAIN (1<<4) /* Is this a block backend domain? */ -#define SIF_NET_BE_DOMAIN (1<<5) /* Is this a net backend domain? */ - - -/* - * Reason codes for SCHEDOP_shutdown. These are opaque to Xen but may be - * interpreted by control software to determine the appropriate action. These - * are only really advisories: the controller can actually do as it likes. - */ -#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */ -#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */ -#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */ - - -/* - * CONTROLLER MESSAGING INTERFACE. - */ - -typedef struct { - u8 type; /* 0: echoed in response */ - u8 subtype; /* 1: echoed in response */ - u8 id; /* 2: echoed in response */ - u8 length; /* 3: number of bytes in 'msg' */ - u8 msg[60]; /* 4: type-specific message data */ -} PACKED control_msg_t; /* 64 bytes */ - -#define CONTROL_RING_SIZE 8 -typedef u32 CONTROL_RING_IDX; -#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1)) - -typedef struct { - control_msg_t tx_ring[CONTROL_RING_SIZE]; /* 0: guest -> controller */ - control_msg_t rx_ring[CONTROL_RING_SIZE]; /* 512: controller -> guest */ - CONTROL_RING_IDX tx_req_prod, tx_resp_prod; /* 1024, 1028 */ - CONTROL_RING_IDX rx_req_prod, rx_resp_prod; /* 1032, 1036 */ -} PACKED control_if_t; /* 1040 bytes */ - -/* - * Top-level command types. - */ -#define CMSG_CONSOLE 0 /* Console */ -#define CMSG_BLKIF_BE 1 /* Block-device backend */ -#define CMSG_BLKIF_FE 2 /* Block-device frontend */ -#define CMSG_NETIF_BE 3 /* Network-device backend */ -#define CMSG_NETIF_FE 4 /* Network-device frontend */ -#define CMSG_SHUTDOWN 6 /* Shutdown messages */ - - -/****************************************************************************** - * CONSOLE DEFINITIONS - */ - -/* - * Subtypes for console messages. - */ -#define CMSG_CONSOLE_DATA 0 - - -/****************************************************************************** - * BLOCK-INTERFACE FRONTEND DEFINITIONS - */ - -/* Messages from domain controller to guest. */ -#define CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED 0 - -/* Messages from guest to domain controller. */ -#define CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED 32 -#define CMSG_BLKIF_FE_INTERFACE_CONNECT 33 -#define CMSG_BLKIF_FE_INTERFACE_DISCONNECT 34 - -/* These are used by both front-end and back-end drivers. */ -#define blkif_vdev_t u16 -#define blkif_pdev_t u16 -#define blkif_sector_t u64 - -/* - * CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED: - * Notify a guest about a status change on one of its block interfaces. - * If the interface is DESTROYED or DOWN then the interface is disconnected: - * 1. The shared-memory frame is available for reuse. - * 2. Any unacknowledged messgaes pending on the interface were dropped. - */ -#define BLKIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */ -#define BLKIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */ -#define BLKIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */ -typedef struct { - u32 handle; /* 0 */ - u32 status; /* 4 */ - u16 evtchn; /* 8: (only if status == BLKIF_INTERFACE_STATUS_CONNECTED). */ -} PACKED blkif_fe_interface_status_changed_t; /* 10 bytes */ - -/* - * CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED: - * Notify the domain controller that the front-end driver is DOWN or UP. - * When the driver goes DOWN then the controller will send no more - * status-change notifications. When the driver comes UP then the controller - * will send a notification for each interface that currently exists. - * If the driver goes DOWN while interfaces are still UP, the domain - * will automatically take the interfaces DOWN. - */ -#define BLKIF_DRIVER_STATUS_DOWN 0 -#define BLKIF_DRIVER_STATUS_UP 1 -typedef struct { - /* IN */ - u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */ - /* OUT */ - /* - * Tells driver how many interfaces it should expect to immediately - * receive notifications about. - */ - u32 nr_interfaces; /* 4 */ -} PACKED blkif_fe_driver_status_changed_t; /* 8 bytes */ - -/* - * CMSG_BLKIF_FE_INTERFACE_CONNECT: - * If successful, the domain controller will acknowledge with a - * STATUS_CONNECTED message. - */ -typedef struct { - u32 handle; /* 0 */ - u32 __pad; - memory_t shmem_frame; /* 8 */ - MEMORY_PADDING; -} PACKED blkif_fe_interface_connect_t; /* 16 bytes */ - -/* - * CMSG_BLKIF_FE_INTERFACE_DISCONNECT: - * If successful, the domain controller will acknowledge with a - * STATUS_DISCONNECTED message. - */ -typedef struct { - u32 handle; /* 0 */ -} PACKED blkif_fe_interface_disconnect_t; /* 4 bytes */ - - -/****************************************************************************** - * BLOCK-INTERFACE BACKEND DEFINITIONS - */ - -/* Messages from domain controller. */ -#define CMSG_BLKIF_BE_CREATE 0 /* Create a new block-device interface. */ -#define CMSG_BLKIF_BE_DESTROY 1 /* Destroy a block-device interface. */ -#define CMSG_BLKIF_BE_CONNECT 2 /* Connect i/f to remote driver. */ -#define CMSG_BLKIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */ -#define CMSG_BLKIF_BE_VBD_CREATE 4 /* Create a new VBD for an interface. */ -#define CMSG_BLKIF_BE_VBD_DESTROY 5 /* Delete a VBD from an interface. */ -#define CMSG_BLKIF_BE_VBD_GROW 6 /* Append an extent to a given VBD. */ -#define CMSG_BLKIF_BE_VBD_SHRINK 7 /* Remove last extent from a given VBD. */ - -/* Messages to domain controller. */ -#define CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED 32 - -/* - * Message request/response definitions for block-device messages. - */ - -typedef struct { - blkif_sector_t sector_start; /* 0 */ - blkif_sector_t sector_length; /* 8 */ - blkif_pdev_t device; /* 16 */ - u16 __pad; /* 18 */ -} PACKED blkif_extent_t; /* 20 bytes */ - -/* Non-specific 'okay' return. */ -#define BLKIF_BE_STATUS_OKAY 0 -/* Non-specific 'error' return. */ -#define BLKIF_BE_STATUS_ERROR 1 -/* The following are specific error returns. */ -#define BLKIF_BE_STATUS_INTERFACE_EXISTS 2 -#define BLKIF_BE_STATUS_INTERFACE_NOT_FOUND 3 -#define BLKIF_BE_STATUS_INTERFACE_CONNECTED 4 -#define BLKIF_BE_STATUS_VBD_EXISTS 5 -#define BLKIF_BE_STATUS_VBD_NOT_FOUND 6 -#define BLKIF_BE_STATUS_OUT_OF_MEMORY 7 -#define BLKIF_BE_STATUS_EXTENT_NOT_FOUND 8 -#define BLKIF_BE_STATUS_MAPPING_ERROR 9 - -/* This macro can be used to create an array of descriptive error strings. */ -#define BLKIF_BE_STATUS_ERRORS { \ - "Okay", \ - "Non-specific error", \ - "Interface already exists", \ - "Interface not found", \ - "Interface is still connected", \ - "VBD already exists", \ - "VBD not found", \ - "Out of memory", \ - "Extent not found for VBD", \ - "Could not map domain memory" } - -/* - * CMSG_BLKIF_BE_CREATE: - * When the driver sends a successful response then the interface is fully - * created. The controller will send a DOWN notification to the front-end - * driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Domain attached to new interface. */ - u32 blkif_handle; /* 4: Domain-specific interface handle. */ - /* OUT */ - u32 status; /* 8 */ -} PACKED blkif_be_create_t; /* 12 bytes */ - -/* - * CMSG_BLKIF_BE_DESTROY: - * When the driver sends a successful response then the interface is fully - * torn down. The controller will send a DESTROYED notification to the - * front-end driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Identify interface to be destroyed. */ - u32 blkif_handle; /* 4: ...ditto... */ - /* OUT */ - u32 status; /* 8 */ -} PACKED blkif_be_destroy_t; /* 12 bytes */ - -/* - * CMSG_BLKIF_BE_CONNECT: - * When the driver sends a successful response then the interface is fully - * connected. The controller will send a CONNECTED notification to the - * front-end driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Domain attached to new interface. */ - u32 blkif_handle; /* 4: Domain-specific interface handle. */ - memory_t shmem_frame; /* 8: Page cont. shared comms window. */ - MEMORY_PADDING; - u32 evtchn; /* 16: Event channel for notifications. */ - /* OUT */ - u32 status; /* 20 */ -} PACKED blkif_be_connect_t; /* 24 bytes */ - -/* - * CMSG_BLKIF_BE_DISCONNECT: - * When the driver sends a successful response then the interface is fully - * disconnected. The controller will send a DOWN notification to the front-end - * driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Domain attached to new interface. */ - u32 blkif_handle; /* 4: Domain-specific interface handle. */ - /* OUT */ - u32 status; /* 8 */ -} PACKED blkif_be_disconnect_t; /* 12 bytes */ - -/* CMSG_BLKIF_BE_VBD_CREATE */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Identify blkdev interface. */ - u32 blkif_handle; /* 4: ...ditto... */ - blkif_vdev_t vdevice; /* 8: Interface-specific id for this VBD. */ - u16 readonly; /* 10: Non-zero -> VBD isn't writeable. */ - /* OUT */ - u32 status; /* 12 */ -} PACKED blkif_be_vbd_create_t; /* 16 bytes */ - -/* CMSG_BLKIF_BE_VBD_DESTROY */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Identify blkdev interface. */ - u32 blkif_handle; /* 4: ...ditto... */ - blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */ - u16 __pad; /* 10 */ - /* OUT */ - u32 status; /* 12 */ -} PACKED blkif_be_vbd_destroy_t; /* 16 bytes */ - -/* CMSG_BLKIF_BE_VBD_GROW */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Identify blkdev interface. */ - u32 blkif_handle; /* 4: ...ditto... */ - blkif_extent_t extent; /* 8: Physical extent to append to VBD. */ - blkif_vdev_t vdevice; /* 28: Interface-specific id of the VBD. */ - u16 __pad; /* 30 */ - /* OUT */ - u32 status; /* 32 */ -} PACKED blkif_be_vbd_grow_t; /* 36 bytes */ - -/* CMSG_BLKIF_BE_VBD_SHRINK */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Identify blkdev interface. */ - u32 blkif_handle; /* 4: ...ditto... */ - blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */ - u16 __pad; /* 10 */ - /* OUT */ - u32 status; /* 12 */ -} PACKED blkif_be_vbd_shrink_t; /* 16 bytes */ - -/* - * CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: - * Notify the domain controller that the back-end driver is DOWN or UP. - * If the driver goes DOWN while interfaces are still UP, the controller - * will automatically send DOWN notifications. - */ -typedef struct { - u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */ -} PACKED blkif_be_driver_status_changed_t; /* 4 bytes */ - - -/****************************************************************************** - * NETWORK-INTERFACE FRONTEND DEFINITIONS - */ - -/* Messages from domain controller to guest. */ -#define CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED 0 - -/* Messages from guest to domain controller. */ -#define CMSG_NETIF_FE_DRIVER_STATUS_CHANGED 32 -#define CMSG_NETIF_FE_INTERFACE_CONNECT 33 -#define CMSG_NETIF_FE_INTERFACE_DISCONNECT 34 - -/* - * CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED: - * Notify a guest about a status change on one of its network interfaces. - * If the interface is DESTROYED or DOWN then the interface is disconnected: - * 1. The shared-memory frame is available for reuse. - * 2. Any unacknowledged messgaes pending on the interface were dropped. - */ -#define NETIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */ -#define NETIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */ -#define NETIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */ -typedef struct { - u32 handle; /* 0 */ - u32 status; /* 4 */ - u16 evtchn; /* 8: status == NETIF_INTERFACE_STATUS_CONNECTED */ - u8 mac[6]; /* 10: status == NETIF_INTERFACE_STATUS_CONNECTED */ -} PACKED netif_fe_interface_status_changed_t; /* 16 bytes */ - -/* - * CMSG_NETIF_FE_DRIVER_STATUS_CHANGED: - * Notify the domain controller that the front-end driver is DOWN or UP. - * When the driver goes DOWN then the controller will send no more - * status-change notifications. When the driver comes UP then the controller - * will send a notification for each interface that currently exists. - * If the driver goes DOWN while interfaces are still UP, the domain - * will automatically take the interfaces DOWN. - */ -#define NETIF_DRIVER_STATUS_DOWN 0 -#define NETIF_DRIVER_STATUS_UP 1 -typedef struct { - /* IN */ - u32 status; /* 0: NETIF_DRIVER_STATUS_??? */ - /* OUT */ - /* - * Tells driver how many interfaces it should expect to immediately - * receive notifications about. - */ - u32 nr_interfaces; /* 4 */ -} PACKED netif_fe_driver_status_changed_t; /* 8 bytes */ - -/* - * CMSG_NETIF_FE_INTERFACE_CONNECT: - * If successful, the domain controller will acknowledge with a - * STATUS_CONNECTED message. - */ -typedef struct { - u32 handle; /* 0 */ - u32 __pad; /* 4 */ - memory_t tx_shmem_frame; /* 8 */ - MEMORY_PADDING; - memory_t rx_shmem_frame; /* 16 */ - MEMORY_PADDING; -} PACKED netif_fe_interface_connect_t; /* 24 bytes */ - -/* - * CMSG_NETIF_FE_INTERFACE_DISCONNECT: - * If successful, the domain controller will acknowledge with a - * STATUS_DISCONNECTED message. - */ -typedef struct { - u32 handle; /* 0 */ -} PACKED netif_fe_interface_disconnect_t; /* 4 bytes */ - - -/****************************************************************************** - * NETWORK-INTERFACE BACKEND DEFINITIONS - */ - -/* Messages from domain controller. */ -#define CMSG_NETIF_BE_CREATE 0 /* Create a new net-device interface. */ -#define CMSG_NETIF_BE_DESTROY 1 /* Destroy a net-device interface. */ -#define CMSG_NETIF_BE_CONNECT 2 /* Connect i/f to remote driver. */ -#define CMSG_NETIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */ - -/* Messages to domain controller. */ -#define CMSG_NETIF_BE_DRIVER_STATUS_CHANGED 32 - -/* - * Message request/response definitions for net-device messages. - */ - -/* Non-specific 'okay' return. */ -#define NETIF_BE_STATUS_OKAY 0 -/* Non-specific 'error' return. */ -#define NETIF_BE_STATUS_ERROR 1 -/* The following are specific error returns. */ -#define NETIF_BE_STATUS_INTERFACE_EXISTS 2 -#define NETIF_BE_STATUS_INTERFACE_NOT_FOUND 3 -#define NETIF_BE_STATUS_INTERFACE_CONNECTED 4 -#define NETIF_BE_STATUS_OUT_OF_MEMORY 5 -#define NETIF_BE_STATUS_MAPPING_ERROR 6 - -/* This macro can be used to create an array of descriptive error strings. */ -#define NETIF_BE_STATUS_ERRORS { \ - "Okay", \ - "Non-specific error", \ - "Interface already exists", \ - "Interface not found", \ - "Interface is still connected", \ - "Out of memory", \ - "Could not map domain memory" } - -/* - * CMSG_NETIF_BE_CREATE: - * When the driver sends a successful response then the interface is fully - * created. The controller will send a DOWN notification to the front-end - * driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Domain attached to new interface. */ - u32 netif_handle; /* 4: Domain-specific interface handle. */ - u8 mac[6]; /* 8 */ - u16 __pad; /* 14 */ - /* OUT */ - u32 status; /* 16 */ -} PACKED netif_be_create_t; /* 20 bytes */ - -/* - * CMSG_NETIF_BE_DESTROY: - * When the driver sends a successful response then the interface is fully - * torn down. The controller will send a DESTROYED notification to the - * front-end driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Identify interface to be destroyed. */ - u32 netif_handle; /* 4: ...ditto... */ - /* OUT */ - u32 status; /* 8 */ -} PACKED netif_be_destroy_t; /* 12 bytes */ - -/* - * CMSG_NETIF_BE_CONNECT: - * When the driver sends a successful response then the interface is fully - * connected. The controller will send a CONNECTED notification to the - * front-end driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Domain attached to new interface. */ - u32 netif_handle; /* 4: Domain-specific interface handle. */ - memory_t tx_shmem_frame; /* 8: Page cont. tx shared comms window. */ - MEMORY_PADDING; - memory_t rx_shmem_frame; /* 16: Page cont. rx shared comms window. */ - MEMORY_PADDING; - u16 evtchn; /* 24: Event channel for notifications. */ - u16 __pad; /* 26 */ - /* OUT */ - u32 status; /* 28 */ -} PACKED netif_be_connect_t; /* 32 bytes */ - -/* - * CMSG_NETIF_BE_DISCONNECT: - * When the driver sends a successful response then the interface is fully - * disconnected. The controller will send a DOWN notification to the front-end - * driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Domain attached to new interface. */ - u32 netif_handle; /* 4: Domain-specific interface handle. */ - /* OUT */ - u32 status; /* 8 */ -} PACKED netif_be_disconnect_t; /* 12 bytes */ - -/* - * CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: - * Notify the domain controller that the back-end driver is DOWN or UP. - * If the driver goes DOWN while interfaces are still UP, the domain - * will automatically send DOWN notifications. - */ -typedef struct { - u32 status; /* 0: NETIF_DRIVER_STATUS_??? */ -} PACKED netif_be_driver_status_changed_t; /* 4 bytes */ - - -/****************************************************************************** - * SHUTDOWN DEFINITIONS - */ - -/* - * Subtypes for shutdown messages. - */ -#define CMSG_SHUTDOWN_POWEROFF 0 /* Clean shutdown (SHUTDOWN_poweroff). */ -#define CMSG_SHUTDOWN_REBOOT 1 /* Clean shutdown (SHUTDOWN_reboot). */ -#define CMSG_SHUTDOWN_SUSPEND 2 /* Create suspend info, then */ - /* SHUTDOWN_suspend. */ - -#endif /* __DOMAIN_CONTROLLER_H__ */ diff --git a/tools/python/xen/ext/xu/xu.c b/tools/python/xen/ext/xu/xu.c deleted file mode 100644 index 48c975912d..0000000000 --- a/tools/python/xen/ext/xu/xu.c +++ /dev/null @@ -1,1386 +0,0 @@ -/****************************************************************************** - * utils.c - * - * Copyright (c) 2004, K A Fraser - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "domain_controller.h" - -#include - -#define XENPKG "xen.ext.xu" - -/* Needed for Python versions earlier than 2.3. */ -#ifndef PyMODINIT_FUNC -#define PyMODINIT_FUNC DL_EXPORT(void) -#endif - -/* NB. The following should be kept in sync with the kernel's evtchn driver. */ -#define EVTCHN_DEV_NAME "/dev/xen/evtchn" -#define EVTCHN_DEV_MAJOR 10 -#define EVTCHN_DEV_MINOR 200 -#define PORT_NORMAL 0x0000 /* A standard event notification. */ -#define PORT_EXCEPTION 0x8000 /* An exceptional notification. */ -#define PORTIDX_MASK 0x7fff /* Strip subtype to obtain port index. */ -/* /dev/xen/evtchn ioctls: */ -/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */ -#define EVTCHN_RESET _IO('E', 1) -/* EVTCHN_BIND: Bind to teh specified event-channel port. */ -#define EVTCHN_BIND _IO('E', 2) -/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */ -#define EVTCHN_UNBIND _IO('E', 3) - -/* Size of a machine page frame. */ -#define PAGE_SIZE 4096 - - -/* - * *********************** NOTIFIER *********************** - */ - -typedef struct { - PyObject_HEAD; - int evtchn_fd; -} xu_notifier_object; - -static PyObject *xu_notifier_read(PyObject *self, PyObject *args) -{ - xu_notifier_object *xun = (xu_notifier_object *)self; - u16 v; - int bytes; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - while ( (bytes = read(xun->evtchn_fd, &v, sizeof(v))) == -1 ) - { - if ( errno == EINTR ) - continue; - if ( errno == EAGAIN ) - goto none; - return PyErr_SetFromErrno(PyExc_IOError); - } - - if ( bytes == sizeof(v) ) - return Py_BuildValue("(i,i)", v&PORTIDX_MASK, v&~PORTIDX_MASK); - - none: - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_notifier_unmask(PyObject *self, PyObject *args) -{ - xu_notifier_object *xun = (xu_notifier_object *)self; - u16 v; - int idx; - - if ( !PyArg_ParseTuple(args, "i", &idx) ) - return NULL; - - v = (u16)idx; - - (void)write(xun->evtchn_fd, &v, sizeof(v)); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_notifier_bind(PyObject *self, PyObject *args) -{ - xu_notifier_object *xun = (xu_notifier_object *)self; - int idx; - - if ( !PyArg_ParseTuple(args, "i", &idx) ) - return NULL; - - if ( ioctl(xun->evtchn_fd, EVTCHN_BIND, idx) != 0 ) - return PyErr_SetFromErrno(PyExc_IOError); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args) -{ - xu_notifier_object *xun = (xu_notifier_object *)self; - int idx; - - if ( !PyArg_ParseTuple(args, "i", &idx) ) - return NULL; - - if ( ioctl(xun->evtchn_fd, EVTCHN_UNBIND, idx) != 0 ) - return PyErr_SetFromErrno(PyExc_IOError); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args) -{ - xu_notifier_object *xun = (xu_notifier_object *)self; - return PyInt_FromLong(xun->evtchn_fd); -} - -static PyMethodDef xu_notifier_methods[] = { - { "read", - (PyCFunction)xu_notifier_read, - METH_VARARGS, - "Read a (@port, @type) pair.\n" }, - - { "unmask", - (PyCFunction)xu_notifier_unmask, - METH_VARARGS, - "Unmask notifications for a @port.\n" }, - - { "bind", - (PyCFunction)xu_notifier_bind, - METH_VARARGS, - "Get notifications for a @port.\n" }, - - { "unbind", - (PyCFunction)xu_notifier_unbind, - METH_VARARGS, - "No longer get notifications for a @port.\n" }, - - { "fileno", - (PyCFunction)xu_notifier_fileno, - METH_VARARGS, - "Return the file descriptor for the notification channel.\n" }, - - { NULL, NULL, 0, NULL } -}; - -staticforward PyTypeObject xu_notifier_type; - -static PyObject *xu_notifier_new(PyObject *self, PyObject *args) -{ - xu_notifier_object *xun; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - xun = PyObject_New(xu_notifier_object, &xu_notifier_type); - - reopen: - xun->evtchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR); - if ( xun->evtchn_fd == -1 ) - { - if ( (errno == ENOENT) && - ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) && - (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600, - (EVTCHN_DEV_MAJOR << 8) | EVTCHN_DEV_MINOR) == 0) ) - goto reopen; - PyObject_Del((PyObject *)xun); - return PyErr_SetFromErrno(PyExc_IOError); - } - - return (PyObject *)xun; -} - -static PyObject *xu_notifier_getattr(PyObject *obj, char *name) -{ - if ( strcmp(name, "EXCEPTION") == 0 ) - return PyInt_FromLong(PORT_EXCEPTION); - if ( strcmp(name, "NORMAL") == 0 ) - return PyInt_FromLong(PORT_NORMAL); - return Py_FindMethod(xu_notifier_methods, obj, name); -} - -static void xu_notifier_dealloc(PyObject *self) -{ - xu_notifier_object *xun = (xu_notifier_object *)self; - (void)close(xun->evtchn_fd); - PyObject_Del(self); -} - -static PyTypeObject xu_notifier_type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "notifier", - sizeof(xu_notifier_object), - 0, - xu_notifier_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ - xu_notifier_getattr, /* tp_getattr */ - NULL, /* tp_setattr */ - NULL, /* tp_compare */ - NULL, /* tp_repr */ - NULL, /* tp_as_number */ - NULL, /* tp_as_sequence */ - NULL, /* tp_as_mapping */ - NULL /* tp_hash */ -}; - - - -/* - * *********************** MESSAGE *********************** - */ - -#define TYPE(_x,_y) (((_x)<<8)|(_y)) -#define P2C(_struct, _field, _ctype) \ - do { \ - PyObject *obj; \ - if ( (obj = PyDict_GetItemString(payload, #_field)) != NULL ) \ - { \ - if ( PyInt_Check(obj) ) \ - { \ - ((_struct *)&xum->msg.msg[0])->_field = \ - (_ctype)PyInt_AsLong(obj); \ - dict_items_parsed++; \ - } \ - else if ( PyLong_Check(obj) ) \ - { \ - ((_struct *)&xum->msg.msg[0])->_field = \ - (_ctype)PyLong_AsUnsignedLongLong(obj); \ - dict_items_parsed++; \ - } \ - } \ - xum->msg.length = sizeof(_struct); \ - } while ( 0 ) -#define C2P(_struct, _field, _pytype, _ctype) \ - do { \ - PyObject *obj = Py ## _pytype ## _From ## _ctype \ - (((_struct *)&xum->msg.msg[0])->_field); \ - if ( dict == NULL ) dict = PyDict_New(); \ - PyDict_SetItemString(dict, #_field, obj); \ - } while ( 0 ) - -typedef struct { - PyObject_HEAD; - control_msg_t msg; -} xu_message_object; - -static PyObject *xu_message_append_payload(PyObject *self, PyObject *args) -{ - xu_message_object *xum = (xu_message_object *)self; - char *str; - int len; - - if ( !PyArg_ParseTuple(args, "s#", &str, &len) ) - return NULL; - - if ( (len + xum->msg.length) > sizeof(xum->msg.msg) ) - { - PyErr_SetString(PyExc_RuntimeError, "out of space in control message"); - return NULL; - } - - memcpy(&xum->msg.msg[xum->msg.length], str, len); - xum->msg.length += len; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_message_set_response_fields(PyObject *self, PyObject *args) -{ - xu_message_object *xum = (xu_message_object *)self; - PyObject *payload; - int dict_items_parsed = 0; - - if ( !PyArg_ParseTuple(args, "O", &payload) ) - return NULL; - - if ( !PyDict_Check(payload) ) - { - PyErr_SetString(PyExc_TypeError, "payload is not a dictionary"); - return NULL; - } - - switch ( TYPE(xum->msg.type, xum->msg.subtype) ) - { - case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED): - P2C(blkif_fe_driver_status_changed_t, nr_interfaces, u32); - break; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): - P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32); - break; - } - - if ( dict_items_parsed != PyDict_Size(payload) ) - { - PyErr_SetString(PyExc_TypeError, "payload contains bad items"); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_message_get_payload(PyObject *self, PyObject *args) -{ - xu_message_object *xum = (xu_message_object *)self; - PyObject *dict = NULL; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - switch ( TYPE(xum->msg.type, xum->msg.subtype) ) - { - case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED): - C2P(blkif_fe_interface_status_changed_t, handle, Int, Long); - C2P(blkif_fe_interface_status_changed_t, status, Int, Long); - C2P(blkif_fe_interface_status_changed_t, evtchn, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED): - C2P(blkif_fe_driver_status_changed_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT): - C2P(blkif_fe_interface_connect_t, handle, Int, Long); - C2P(blkif_fe_interface_connect_t, shmem_frame, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_DISCONNECT): - C2P(blkif_fe_interface_disconnect_t, handle, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE): - C2P(blkif_be_create_t, domid, Int, Long); - C2P(blkif_be_create_t, blkif_handle, Int, Long); - C2P(blkif_be_create_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY): - C2P(blkif_be_destroy_t, domid, Int, Long); - C2P(blkif_be_destroy_t, blkif_handle, Int, Long); - C2P(blkif_be_destroy_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT): - C2P(blkif_be_connect_t, domid, Int, Long); - C2P(blkif_be_connect_t, blkif_handle, Int, Long); - C2P(blkif_be_connect_t, shmem_frame, Int, Long); - C2P(blkif_be_connect_t, evtchn, Int, Long); - C2P(blkif_be_connect_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT): - C2P(blkif_be_disconnect_t, domid, Int, Long); - C2P(blkif_be_disconnect_t, blkif_handle, Int, Long); - C2P(blkif_be_disconnect_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE): - C2P(blkif_be_vbd_create_t, domid, Int, Long); - C2P(blkif_be_vbd_create_t, blkif_handle, Int, Long); - C2P(blkif_be_vbd_create_t, vdevice, Int, Long); - C2P(blkif_be_vbd_create_t, readonly, Int, Long); - C2P(blkif_be_vbd_create_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY): - C2P(blkif_be_vbd_destroy_t, domid, Int, Long); - C2P(blkif_be_vbd_destroy_t, blkif_handle, Int, Long); - C2P(blkif_be_vbd_destroy_t, vdevice, Int, Long); - C2P(blkif_be_vbd_destroy_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW): - C2P(blkif_be_vbd_grow_t, domid, Int, Long); - C2P(blkif_be_vbd_grow_t, blkif_handle, Int, Long); - C2P(blkif_be_vbd_grow_t, vdevice, Int, Long); - C2P(blkif_be_vbd_grow_t, extent.sector_start, - Long, UnsignedLongLong); - C2P(blkif_be_vbd_grow_t, extent.sector_length, - Long, UnsignedLongLong); - C2P(blkif_be_vbd_grow_t, extent.device, Int, Long); - C2P(blkif_be_vbd_grow_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK): - C2P(blkif_be_vbd_shrink_t, domid, Int, Long); - C2P(blkif_be_vbd_shrink_t, blkif_handle, Int, Long); - C2P(blkif_be_vbd_shrink_t, vdevice, Int, Long); - C2P(blkif_be_vbd_shrink_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED): - C2P(blkif_be_driver_status_changed_t, status, Int, Long); - return dict; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED): - C2P(netif_fe_interface_status_changed_t, handle, Int, Long); - C2P(netif_fe_interface_status_changed_t, status, Int, Long); - C2P(netif_fe_interface_status_changed_t, evtchn, Int, Long); - return dict; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): - C2P(netif_fe_driver_status_changed_t, status, Int, Long); - C2P(netif_fe_driver_status_changed_t, nr_interfaces, Int, Long); - return dict; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT): - C2P(netif_fe_interface_connect_t, handle, Int, Long); - C2P(netif_fe_interface_connect_t, tx_shmem_frame, Int, Long); - C2P(netif_fe_interface_connect_t, rx_shmem_frame, Int, Long); - return dict; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_DISCONNECT): - C2P(netif_fe_interface_disconnect_t, handle, Int, Long); - return dict; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE): - C2P(netif_be_create_t, domid, Int, Long); - C2P(netif_be_create_t, netif_handle, Int, Long); - C2P(netif_be_create_t, status, Int, Long); - return dict; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY): - C2P(netif_be_destroy_t, domid, Int, Long); - C2P(netif_be_destroy_t, netif_handle, Int, Long); - C2P(netif_be_destroy_t, status, Int, Long); - return dict; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT): - C2P(netif_be_connect_t, domid, Int, Long); - C2P(netif_be_connect_t, netif_handle, Int, Long); - C2P(netif_be_connect_t, tx_shmem_frame, Int, Long); - C2P(netif_be_connect_t, rx_shmem_frame, Int, Long); - C2P(netif_be_connect_t, evtchn, Int, Long); - C2P(netif_be_connect_t, status, Int, Long); - return dict; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT): - C2P(netif_be_disconnect_t, domid, Int, Long); - C2P(netif_be_disconnect_t, netif_handle, Int, Long); - C2P(netif_be_disconnect_t, status, Int, Long); - return dict; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED): - C2P(netif_be_driver_status_changed_t, status, Int, Long); - return dict; - } - - return PyString_FromStringAndSize(xum->msg.msg, xum->msg.length); -} - -static PyObject *xu_message_get_header(PyObject *self, PyObject *args) -{ - xu_message_object *xum = (xu_message_object *)self; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - return Py_BuildValue("{s:i,s:i,s:i}", - "type", xum->msg.type, - "subtype", xum->msg.subtype, - "id", xum->msg.id); -} - -static PyMethodDef xu_message_methods[] = { - { "append_payload", - (PyCFunction)xu_message_append_payload, - METH_VARARGS, - "Append @str to the message payload.\n" }, - - { "set_response_fields", - (PyCFunction)xu_message_set_response_fields, - METH_VARARGS, - "Fill in the response fields in a message that was passed to us.\n" }, - - { "get_payload", - (PyCFunction)xu_message_get_payload, - METH_VARARGS, - "Return the message payload in string form.\n" }, - - { "get_header", - (PyCFunction)xu_message_get_header, - METH_VARARGS, - "Returns a dictionary of values for @type, @subtype, and @id.\n" }, - - { NULL, NULL, 0, NULL } -}; - -staticforward PyTypeObject xu_message_type; - -static PyObject *xu_message_new(PyObject *self, PyObject *args) -{ - xu_message_object *xum; - int type, subtype, id, dict_items_parsed = 0; - PyObject *payload = NULL; - - if ( !PyArg_ParseTuple(args, "iii|O", &type, &subtype, &id, &payload) ) - return NULL; - - xum = PyObject_New(xu_message_object, &xu_message_type); - - xum->msg.type = type; - xum->msg.subtype = subtype; - xum->msg.id = id; - xum->msg.length = 0; - - if ( payload == NULL ) - return (PyObject *)xum; - - if ( !PyDict_Check(payload) ) - { - PyErr_SetString(PyExc_TypeError, "payload is not a dictionary"); - PyObject_Del((PyObject *)xum); - return NULL; - } - - switch ( TYPE(type, subtype) ) - { - case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED): - P2C(blkif_fe_interface_status_changed_t, handle, u32); - P2C(blkif_fe_interface_status_changed_t, status, u32); - P2C(blkif_fe_interface_status_changed_t, evtchn, u16); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE): - P2C(blkif_be_create_t, domid, u32); - P2C(blkif_be_create_t, blkif_handle, u32); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY): - P2C(blkif_be_destroy_t, domid, u32); - P2C(blkif_be_destroy_t, blkif_handle, u32); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT): - P2C(blkif_be_connect_t, domid, u32); - P2C(blkif_be_connect_t, blkif_handle, u32); - P2C(blkif_be_connect_t, shmem_frame, memory_t); - P2C(blkif_be_connect_t, evtchn, u16); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT): - P2C(blkif_be_disconnect_t, domid, u32); - P2C(blkif_be_disconnect_t, blkif_handle, u32); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE): - P2C(blkif_be_vbd_create_t, domid, u32); - P2C(blkif_be_vbd_create_t, blkif_handle, u32); - P2C(blkif_be_vbd_create_t, vdevice, blkif_vdev_t); - P2C(blkif_be_vbd_create_t, readonly, u16); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY): - P2C(blkif_be_vbd_destroy_t, domid, u32); - P2C(blkif_be_vbd_destroy_t, blkif_handle, u32); - P2C(blkif_be_vbd_destroy_t, vdevice, blkif_vdev_t); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW): - P2C(blkif_be_vbd_grow_t, domid, u32); - P2C(blkif_be_vbd_grow_t, blkif_handle, u32); - P2C(blkif_be_vbd_grow_t, vdevice, blkif_vdev_t); - P2C(blkif_be_vbd_grow_t, extent.sector_start, blkif_sector_t); - P2C(blkif_be_vbd_grow_t, extent.sector_length, blkif_sector_t); - P2C(blkif_be_vbd_grow_t, extent.device, blkif_pdev_t); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK): - P2C(blkif_be_vbd_shrink_t, domid, u32); - P2C(blkif_be_vbd_shrink_t, blkif_handle, u32); - P2C(blkif_be_vbd_shrink_t, vdevice, blkif_vdev_t); - break; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED): - P2C(netif_fe_interface_status_changed_t, handle, u32); - P2C(netif_fe_interface_status_changed_t, status, u32); - P2C(netif_fe_interface_status_changed_t, evtchn, u16); - P2C(netif_fe_interface_status_changed_t, mac[0], u8); - P2C(netif_fe_interface_status_changed_t, mac[1], u8); - P2C(netif_fe_interface_status_changed_t, mac[2], u8); - P2C(netif_fe_interface_status_changed_t, mac[3], u8); - P2C(netif_fe_interface_status_changed_t, mac[4], u8); - P2C(netif_fe_interface_status_changed_t, mac[5], u8); - break; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE): - P2C(netif_be_create_t, domid, u32); - P2C(netif_be_create_t, netif_handle, u32); - P2C(netif_be_create_t, mac[0], u8); - P2C(netif_be_create_t, mac[1], u8); - P2C(netif_be_create_t, mac[2], u8); - P2C(netif_be_create_t, mac[3], u8); - P2C(netif_be_create_t, mac[4], u8); - P2C(netif_be_create_t, mac[5], u8); - break; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY): - P2C(netif_be_destroy_t, domid, u32); - P2C(netif_be_destroy_t, netif_handle, u32); - break; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT): - P2C(netif_be_connect_t, domid, u32); - P2C(netif_be_connect_t, netif_handle, u32); - P2C(netif_be_connect_t, tx_shmem_frame, memory_t); - P2C(netif_be_connect_t, rx_shmem_frame, memory_t); - P2C(netif_be_connect_t, evtchn, u16); - break; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT): - P2C(netif_be_disconnect_t, domid, u32); - P2C(netif_be_disconnect_t, netif_handle, u32); - break; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): - P2C(netif_fe_driver_status_changed_t, status, u32); - P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32); - break; - } - - if ( dict_items_parsed != PyDict_Size(payload) ) - { - PyErr_SetString(PyExc_TypeError, "payload contains bad items"); - PyObject_Del((PyObject *)xum); - return NULL; - } - - return (PyObject *)xum; -} - -static PyObject *xu_message_getattr(PyObject *obj, char *name) -{ - xu_message_object *xum; - if ( strcmp(name, "MAX_PAYLOAD") == 0 ) - return PyInt_FromLong(sizeof(xum->msg.msg)); - return Py_FindMethod(xu_message_methods, obj, name); -} - -static void xu_message_dealloc(PyObject *self) -{ - PyObject_Del(self); -} - -static PyTypeObject xu_message_type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "message", - sizeof(xu_message_object), - 0, - xu_message_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ - xu_message_getattr, /* tp_getattr */ - NULL, /* tp_setattr */ - NULL, /* tp_compare */ - NULL, /* tp_repr */ - NULL, /* tp_as_number */ - NULL, /* tp_as_sequence */ - NULL, /* tp_as_mapping */ - NULL /* tp_hash */ -}; - - - -/* - * *********************** PORT *********************** - */ - -static control_if_t *map_control_interface(int fd, unsigned long pfn) -{ - char *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, - MAP_SHARED, fd, pfn * PAGE_SIZE); - if ( vaddr == MAP_FAILED ) - return NULL; - return (control_if_t *)(vaddr + 2048); -} -static void unmap_control_interface(int fd, control_if_t *c) -{ - char *vaddr = (char *)c - 2048; - (void)munmap(vaddr, PAGE_SIZE); -} - -typedef struct xu_port_object { - PyObject_HEAD; - int mem_fd; - int xc_handle; - u32 remote_dom; - int local_port, remote_port; - control_if_t *interface; - CONTROL_RING_IDX tx_req_cons, tx_resp_prod; - CONTROL_RING_IDX rx_req_prod, rx_resp_cons; -} xu_port_object; - -static PyObject *port_error; - -static int xup_connect(xu_port_object *xup, domid_t dom, - int local_port, int remote_port){ - // From our prespective rx = producer, tx = consumer. - int err = 0; - printf("%s> dom=%u %d:%d\n", __FUNCTION__, (unsigned int)dom, - local_port, remote_port); - - // Consumer = tx. - //xup->interface->tx_resp_prod = 0; - //xup->interface->tx_req_prod = 0; - xup->tx_resp_prod = xup->interface->tx_resp_prod; - xup->tx_req_cons = xup->interface->tx_resp_prod; - printf("%s> tx: %u %u : %u %u\n", __FUNCTION__, - (unsigned int)xup->interface->tx_resp_prod, - (unsigned int)xup->tx_resp_prod, - (unsigned int)xup->tx_req_cons, - (unsigned int)xup->interface->tx_req_prod); - - // Producer = rx. - //xup->interface->rx_req_prod = 0; - //xup->interface->rx_resp_prod = 0; - xup->rx_req_prod = xup->interface->rx_req_prod; - xup->rx_resp_cons = xup->interface->rx_resp_prod; - printf("%s> rx: %u %u : %u %u\n", __FUNCTION__, - (unsigned int)xup->rx_resp_cons, - (unsigned int)xup->interface->rx_resp_prod, - (unsigned int)xup->interface->rx_req_prod, - (unsigned int)xup->rx_req_prod); - - xup->remote_dom = dom; - xup->local_port = local_port; - xup->remote_port = remote_port; - - printf("%s< err=%d\n", __FUNCTION__, err); - return err; -} - -static PyObject *xu_port_notify(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - (void)xc_evtchn_send(xup->xc_handle, xup->local_port); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_port_read_request(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - xu_message_object *xum; - CONTROL_RING_IDX c = xup->tx_req_cons; - control_if_t *cif = xup->interface; - control_msg_t *cmsg; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( (c == cif->tx_req_prod) || - ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) ) - { - PyErr_SetString(port_error, "no request to read"); - return NULL; - } - - cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)]; - xum = PyObject_New(xu_message_object, &xu_message_type); - memcpy(&xum->msg, cmsg, sizeof(*cmsg)); - if ( xum->msg.length > sizeof(xum->msg.msg) ) - xum->msg.length = sizeof(xum->msg.msg); - xup->tx_req_cons++; - return (PyObject *)xum; -} - -static PyObject *xu_port_write_request(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - xu_message_object *xum; - CONTROL_RING_IDX p = xup->rx_req_prod; - control_if_t *cif = xup->interface; - control_msg_t *cmsg; - - if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) ) - return NULL; - - if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) ) - { - PyErr_SetString(PyExc_TypeError, "expected a " XENPKG ".message"); - return NULL; - } - - if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) ) - { - PyErr_SetString(port_error, "no space to write request"); - return NULL; - } - - cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)]; - memcpy(cmsg, &xum->msg, sizeof(*cmsg)); - - xup->rx_req_prod = cif->rx_req_prod = p + 1; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_port_read_response(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - xu_message_object *xum; - CONTROL_RING_IDX c = xup->rx_resp_cons; - control_if_t *cif = xup->interface; - control_msg_t *cmsg; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) ) - { - PyErr_SetString(port_error, "no response to read"); - return NULL; - } - - cmsg = &cif->rx_ring[MASK_CONTROL_IDX(c)]; - xum = PyObject_New(xu_message_object, &xu_message_type); - memcpy(&xum->msg, cmsg, sizeof(*cmsg)); - if ( xum->msg.length > sizeof(xum->msg.msg) ) - xum->msg.length = sizeof(xum->msg.msg); - xup->rx_resp_cons++; - return (PyObject *)xum; -} - -static PyObject *xu_port_write_response(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - xu_message_object *xum; - CONTROL_RING_IDX p = xup->tx_resp_prod; - control_if_t *cif = xup->interface; - control_msg_t *cmsg; - - if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) ) - return NULL; - - if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) ) - { - PyErr_SetString(PyExc_TypeError, "expected a " XENPKG ".message"); - return NULL; - } - - if ( p == xup->tx_req_cons ) - { - PyErr_SetString(port_error, "no space to write response"); - return NULL; - } - - cmsg = &cif->tx_ring[MASK_CONTROL_IDX(p)]; - memcpy(cmsg, &xum->msg, sizeof(*cmsg)); - - xup->tx_resp_prod = cif->tx_resp_prod = p + 1; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_port_request_to_read(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - CONTROL_RING_IDX c = xup->tx_req_cons; - control_if_t *cif = xup->interface; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( (c == cif->tx_req_prod) || - ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) ) - return PyInt_FromLong(0); - - return PyInt_FromLong(1); -} - -static PyObject *xu_port_space_to_write_request(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - CONTROL_RING_IDX p = xup->rx_req_prod; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) ) - return PyInt_FromLong(0); - - return PyInt_FromLong(1); -} - -static PyObject *xu_port_response_to_read(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - CONTROL_RING_IDX c = xup->rx_resp_cons; - control_if_t *cif = xup->interface; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) ) - return PyInt_FromLong(0); - - return PyInt_FromLong(1); -} - -static PyObject *xu_port_space_to_write_response( - PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - CONTROL_RING_IDX p = xup->tx_resp_prod; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( p == xup->tx_req_cons ) - return PyInt_FromLong(0); - - return PyInt_FromLong(1); -} - -static PyMethodDef xu_port_methods[] = { - { "notify", - (PyCFunction)xu_port_notify, - METH_VARARGS, - "Send a notification to the remote end.\n" }, - - { "read_request", - (PyCFunction)xu_port_read_request, - METH_VARARGS, - "Read a request message from the control interface.\n" }, - - { "write_request", - (PyCFunction)xu_port_write_request, - METH_VARARGS, - "Write a request message to the control interface.\n" }, - - { "read_response", - (PyCFunction)xu_port_read_response, - METH_VARARGS, - "Read a response message from the control interface.\n" }, - - { "write_response", - (PyCFunction)xu_port_write_response, - METH_VARARGS, - "Write a response message to the control interface.\n" }, - - { "request_to_read", - (PyCFunction)xu_port_request_to_read, - METH_VARARGS, - "Returns TRUE if there is a request message to read.\n" }, - - { "space_to_write_request", - (PyCFunction)xu_port_space_to_write_request, - METH_VARARGS, - "Returns TRUE if there is space to write a request message.\n" }, - - { "response_to_read", - (PyCFunction)xu_port_response_to_read, - METH_VARARGS, - "Returns TRUE if there is a response message to read.\n" }, - - { "space_to_write_response", - (PyCFunction)xu_port_space_to_write_response, - METH_VARARGS, - "Returns TRUE if there is space to write a response message.\n" }, - - { NULL, NULL, 0, NULL } -}; - -staticforward PyTypeObject xu_port_type; - -static PyObject *xu_port_new(PyObject *self, PyObject *args) -{ - xu_port_object *xup; - u32 dom; - int port1, port2; - xc_dominfo_t info; - - if ( !PyArg_ParseTuple(args, "i", &dom) ) - return NULL; - - xup = PyObject_New(xu_port_object, &xu_port_type); - - if ( (xup->mem_fd = open("/dev/mem", O_RDWR)) == -1 ) - { - PyErr_SetString(port_error, "Could not open '/dev/mem'"); - goto fail1; - } - - /* Set the General-Purpose Subject whose page frame will be mapped. */ - (void)ioctl(xup->mem_fd, _IO('M', 1), (unsigned long)dom); - - if ( (xup->xc_handle = xc_interface_open()) == -1 ) - { - PyErr_SetString(port_error, "Could not open Xen control interface"); - goto fail2; - } - - if ( dom == 0 ) - { - /* - * The control-interface event channel for DOM0 is already set up. - * We use an ioctl to discover the port at our end of the channel. - */ - port1 = ioctl(xup->xc_handle, IOCTL_PRIVCMD_INITDOMAIN_EVTCHN, NULL); - port2 = -1; /* We don't need the remote end of the DOM0 link. */ - if ( port1 < 0 ) - { - PyErr_SetString(port_error, "Could not open channel to DOM0"); - goto fail3; - } - } - else if ( xc_evtchn_bind_interdomain(xup->xc_handle, - DOMID_SELF, dom, - &port1, &port2) != 0 ) - { - PyErr_SetString(port_error, "Could not open channel to domain"); - goto fail3; - } - - if ( (xc_domain_getinfo(xup->xc_handle, dom, 1, &info) != 1) || - (info.domid != dom) ) - { - PyErr_SetString(port_error, "Failed to obtain domain status"); - goto fail4; - } - - xup->interface = - map_control_interface(xup->mem_fd, info.shared_info_frame); - if ( xup->interface == NULL ) - { - PyErr_SetString(port_error, "Failed to map domain control interface"); - goto fail4; - } - - xup_connect(xup, dom, port1, port2); - return (PyObject *)xup; - - - fail4: - (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, port1); - fail3: - (void)xc_interface_close(xup->xc_handle); - fail2: - (void)close(xup->mem_fd); - fail1: - PyObject_Del((PyObject *)xup); - return NULL; -} - -static PyObject *xu_port_getattr(PyObject *obj, char *name) -{ - xu_port_object *xup = (xu_port_object *)obj; - if ( strcmp(name, "local_port") == 0 ) - return PyInt_FromLong(xup->local_port); - if ( strcmp(name, "remote_port") == 0 ) - return PyInt_FromLong(xup->remote_port); - if ( strcmp(name, "remote_dom") == 0 ) - return PyInt_FromLong(xup->remote_dom); - return Py_FindMethod(xu_port_methods, obj, name); -} - -static void xu_port_dealloc(PyObject *self) -{ - xu_port_object *xup = (xu_port_object *)self; - unmap_control_interface(xup->mem_fd, xup->interface); - if ( xup->remote_dom != 0 ) - (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, xup->local_port); - (void)xc_interface_close(xup->xc_handle); - (void)close(xup->mem_fd); - PyObject_Del(self); -} - -static PyTypeObject xu_port_type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "port", - sizeof(xu_port_object), - 0, - xu_port_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ - xu_port_getattr, /* tp_getattr */ - NULL, /* tp_setattr */ - NULL, /* tp_compare */ - NULL, /* tp_repr */ - NULL, /* tp_as_number */ - NULL, /* tp_as_sequence */ - NULL, /* tp_as_mapping */ - NULL /* tp_hash */ -}; - - - -/* - * *********************** BUFFER *********************** - */ - -#define BUFSZ 65536 -#define MASK_BUF_IDX(_i) ((_i)&(BUFSZ-1)) -typedef unsigned int BUF_IDX; - -typedef struct { - PyObject_HEAD; - char *buf; - unsigned int prod, cons; -} xu_buffer_object; - -static PyObject *__xu_buffer_peek(xu_buffer_object *xub, int max) -{ - PyObject *str1, *str2; - int len1, len2, c = MASK_BUF_IDX(xub->cons); - - len1 = xub->prod - xub->cons; - if ( len1 > (BUFSZ - c) ) /* clip to ring wrap */ - len1 = BUFSZ - c; - if ( len1 > max ) /* clip to specified maximum */ - len1 = max; - if ( len1 < 0 ) /* sanity */ - len1 = 0; - - if ( (str1 = PyString_FromStringAndSize(&xub->buf[c], len1)) == NULL ) - return NULL; - - if ( (len1 < (xub->prod - xub->cons)) && (len1 < max) ) - { - len2 = max - len1; - if ( len2 > MASK_BUF_IDX(xub->prod) ) - len2 = MASK_BUF_IDX(xub->prod); - if ( len2 > 0 ) - { - str2 = PyString_FromStringAndSize(&xub->buf[0], len2); - if ( str2 == NULL ) - return NULL; - PyString_ConcatAndDel(&str1, str2); - if ( str1 == NULL ) - return NULL; - } - } - - return str1; -} - -static PyObject *xu_buffer_peek(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - int max = 1024; - - if ( !PyArg_ParseTuple(args, "|i", &max) ) - return NULL; - - return __xu_buffer_peek(xub, max); -} - -static PyObject *xu_buffer_read(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - PyObject *str; - int max = 1024; - - if ( !PyArg_ParseTuple(args, "|i", &max) ) - return NULL; - - if ( (str = __xu_buffer_peek(xub, max)) != NULL ) - xub->cons += PyString_Size(str); - - return str; -} - -static PyObject *xu_buffer_discard(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - int max, len; - - if ( !PyArg_ParseTuple(args, "i", &max) ) - return NULL; - - len = xub->prod - xub->cons; - if ( len > max ) - len = max; - if ( len < 0 ) - len = 0; - - xub->cons += len; - - return PyInt_FromLong(len); -} - -static PyObject *xu_buffer_write(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - char *str; - int len, len1, len2; - - if ( !PyArg_ParseTuple(args, "s#", &str, &len) ) - return NULL; - - len1 = len; - if ( len1 > (BUFSZ - MASK_BUF_IDX(xub->prod)) ) - len1 = BUFSZ - MASK_BUF_IDX(xub->prod); - if ( len1 > (BUFSZ - (xub->prod - xub->cons)) ) - len1 = BUFSZ - (xub->prod - xub->cons); - - if ( len1 == 0 ) - return PyInt_FromLong(0); - - memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[0], len1); - xub->prod += len1; - - if ( len1 < len ) - { - len2 = len - len1; - if ( len2 > (BUFSZ - MASK_BUF_IDX(xub->prod)) ) - len2 = BUFSZ - MASK_BUF_IDX(xub->prod); - if ( len2 > (BUFSZ - (xub->prod - xub->cons)) ) - len2 = BUFSZ - (xub->prod - xub->cons); - if ( len2 != 0 ) - { - memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[len1], len2); - xub->prod += len2; - return PyInt_FromLong(len1 + len2); - } - } - - return PyInt_FromLong(len1); -} - -static PyObject *xu_buffer_empty(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( xub->cons == xub->prod ) - return PyInt_FromLong(1); - - return PyInt_FromLong(0); -} - -static PyObject *xu_buffer_full(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( (xub->prod - xub->cons) == BUFSZ ) - return PyInt_FromLong(1); - - return PyInt_FromLong(0); -} - -static PyMethodDef xu_buffer_methods[] = { - { "peek", - (PyCFunction)xu_buffer_peek, - METH_VARARGS, - "Peek up to @max bytes from the buffer. Returns a string.\n" }, - - { "read", - (PyCFunction)xu_buffer_read, - METH_VARARGS, - "Read up to @max bytes from the buffer. Returns a string.\n" }, - - { "discard", - (PyCFunction)xu_buffer_discard, - METH_VARARGS, - "Discard up to @max bytes from the buffer. Returns number of bytes.\n" }, - - { "write", - (PyCFunction)xu_buffer_write, - METH_VARARGS, - "Write @string into buffer. Return number of bytes written.\n" }, - - { "empty", - (PyCFunction)xu_buffer_empty, - METH_VARARGS, - "Return TRUE if the buffer is empty.\n" }, - - { "full", - (PyCFunction)xu_buffer_full, - METH_VARARGS, - "Return TRUE if the buffer is full.\n" }, - - { NULL, NULL, 0, NULL } -}; - -staticforward PyTypeObject xu_buffer_type; - -static PyObject *xu_buffer_new(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - xub = PyObject_New(xu_buffer_object, &xu_buffer_type); - - if ( (xub->buf = malloc(BUFSZ)) == NULL ) - { - PyObject_Del((PyObject *)xub); - return NULL; - } - - xub->prod = xub->cons = 0; - - return (PyObject *)xub; -} - -static PyObject *xu_buffer_getattr(PyObject *obj, char *name) -{ - return Py_FindMethod(xu_buffer_methods, obj, name); -} - -static void xu_buffer_dealloc(PyObject *self) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - free(xub->buf); - PyObject_Del(self); -} - -static PyTypeObject xu_buffer_type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "buffer", - sizeof(xu_buffer_object), - 0, - xu_buffer_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ - xu_buffer_getattr, /* tp_getattr */ - NULL, /* tp_setattr */ - NULL, /* tp_compare */ - NULL, /* tp_repr */ - NULL, /* tp_as_number */ - NULL, /* tp_as_sequence */ - NULL, /* tp_as_mapping */ - NULL /* tp_hash */ -}; - - - -/* - * *********************** MODULE WRAPPER *********************** - */ - -static void handle_child_death(int dummy) -{ - while ( waitpid(-1, NULL, WNOHANG) > 0 ) - continue; -} - -static PyObject *xu_autoreap(PyObject *self, PyObject *args) -{ - struct sigaction sa; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = handle_child_death; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; - (void)sigaction(SIGCHLD, &sa, NULL); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef xu_methods[] = { - { "notifier", xu_notifier_new, METH_VARARGS, - "Create a new notifier." }, - { "message", xu_message_new, METH_VARARGS, - "Create a new communications message." }, - { "port", xu_port_new, METH_VARARGS, - "Create a new communications port." }, - { "buffer", xu_buffer_new, METH_VARARGS, - "Create a new ring buffer." }, - { "autoreap", xu_autoreap, METH_VARARGS, - "Ensure that zombie children are automatically reaped by the OS." }, - { NULL, NULL, 0, NULL } -}; - -PyMODINIT_FUNC initxu(void) -{ - PyObject *m, *d; - - m = Py_InitModule(XENPKG, xu_methods); - - d = PyModule_GetDict(m); - port_error = PyErr_NewException(XENPKG ".PortError", NULL, NULL); - PyDict_SetItemString(d, "PortError", port_error); -} diff --git a/tools/python/xen/lowlevel/__init__.py b/tools/python/xen/lowlevel/__init__.py new file mode 100644 index 0000000000..8d1c8b69c3 --- /dev/null +++ b/tools/python/xen/lowlevel/__init__.py @@ -0,0 +1 @@ + diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c new file mode 100644 index 0000000000..9cce7b060d --- /dev/null +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -0,0 +1,1184 @@ +/****************************************************************************** + * Xc.c + * + * Copyright (c) 2003-2004, K A Fraser (University of Cambridge) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xc_private.h" +#include "gzip_stream.h" + +/* Needed for Python versions earlier than 2.3. */ +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC DL_EXPORT(void) +#endif + +#define XENPKG "xen.lowlevel.xc" + +static PyObject *xc_error, *zero; + +typedef struct { + PyObject_HEAD; + int xc_handle; +} XcObject; + +/* + * Definitions for the 'xc' object type. + */ + +static PyObject *pyxc_domain_create(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + unsigned int mem_kb = 0; + char *name = "(anon)"; + int cpu = -1; + u32 dom; + int ret; + + static char *kwd_list[] = { "mem_kb", "name", "cpu", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|isi", kwd_list, + &mem_kb, &name, &cpu) ) + return NULL; + + if ( (ret = xc_domain_create(xc->xc_handle, mem_kb, name, cpu, &dom)) < 0 ) + return PyErr_SetFromErrno(xc_error); + + return PyInt_FromLong(dom); +} + +static PyObject *pyxc_domain_pause(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + + static char *kwd_list[] = { "dom", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) + return NULL; + + if ( xc_domain_pause(xc->xc_handle, dom) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_domain_unpause(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + + static char *kwd_list[] = { "dom", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) + return NULL; + + if ( xc_domain_unpause(xc->xc_handle, dom) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_domain_destroy(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + + static char *kwd_list[] = { "dom", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) + return NULL; + + if ( xc_domain_destroy(xc->xc_handle, dom) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_domain_pincpu(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + int cpu = -1; + + static char *kwd_list[] = { "dom", "cpu", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, + &dom, &cpu) ) + return NULL; + + if ( xc_domain_pincpu(xc->xc_handle, dom, cpu) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_domain_getinfo(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + PyObject *list; + + u32 first_dom = 0; + int max_doms = 1024, nr_doms, i; + xc_dominfo_t *info; + + static char *kwd_list[] = { "first_dom", "max_doms", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, + &first_dom, &max_doms) ) + return NULL; + + if ( (info = malloc(max_doms * sizeof(xc_dominfo_t))) == NULL ) + return PyErr_NoMemory(); + + nr_doms = xc_domain_getinfo(xc->xc_handle, first_dom, max_doms, info); + + list = PyList_New(nr_doms); + for ( i = 0 ; i < nr_doms; i++ ) + { + PyList_SetItem( + list, i, + Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i" + ",s:l,s:L,s:s,s:l,s:i}", + "dom", info[i].domid, + "cpu", info[i].cpu, + "dying", info[i].dying, + "crashed", info[i].crashed, + "shutdown", info[i].shutdown, + "paused", info[i].paused, + "blocked", info[i].blocked, + "running", info[i].running, + "mem_kb", info[i].nr_pages*4, + "cpu_time", info[i].cpu_time, + "name", info[i].name, + "maxmem_kb", info[i].max_memkb, + "shutdown_reason", info[i].shutdown_reason + )); + } + + free(info); + + return list; +} + +static int file_save(XcObject *xc, XcIOContext *ctxt, char *state_file) +{ + int rc = -1; + int fd = -1; + int open_flags = (O_CREAT | O_EXCL | O_WRONLY); + int open_mode = 0644; + + printf("%s>\n", __FUNCTION__); + + if ( (fd = open(state_file, open_flags, open_mode)) < 0 ) + { + xcio_perror(ctxt, "Could not open file for writing"); + goto exit; + } + + printf("%s>gzip_stream_fdopen... \n", __FUNCTION__); + + /* Compression rate 1: we want speed over compression. + * We're mainly going for those zero pages, after all. + */ + ctxt->io = gzip_stream_fdopen(fd, "wb1"); + if ( ctxt->io == NULL ) + { + xcio_perror(ctxt, "Could not allocate compression state"); + goto exit; + } + + printf("%s> xc_linux_save...\n", __FUNCTION__); + + rc = xc_linux_save(xc->xc_handle, ctxt); + + exit: + if ( ctxt->io != NULL ) + IOStream_close(ctxt->io); + if ( fd >= 0 ) + close(fd); + unlink(state_file); + printf("%s> rc=%d\n", __FUNCTION__, rc); + return rc; +} + +static PyObject *pyxc_linux_save(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + char *state_file; + int progress = 1, debug = 0; + PyObject *val = NULL; + int rc = -1; + XcIOContext ioctxt = { .info = iostdout, .err = iostderr }; + + static char *kwd_list[] = { "dom", "state_file", "vmconfig", "progress", "debug", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is|sii", kwd_list, + &ioctxt.domain, + &state_file, + &ioctxt.vmconfig, + &progress, + &debug) ) + goto exit; + + ioctxt.vmconfig_n = (ioctxt.vmconfig ? strlen(ioctxt.vmconfig) : 0); + + if ( progress ) + ioctxt.flags |= XCFLAGS_VERBOSE; + if ( debug ) + ioctxt.flags |= XCFLAGS_DEBUG; + + if ( (state_file == NULL) || (state_file[0] == '\0') ) + goto exit; + + rc = file_save(xc, &ioctxt, state_file); + if ( rc != 0 ) + { + PyErr_SetFromErrno(xc_error); + goto exit; + } + + Py_INCREF(zero); + val = zero; + + exit: + return val; +} + + +static int file_restore(XcObject *xc, XcIOContext *ioctxt, char *state_file) +{ + int rc = -1; + + ioctxt->io = gzip_stream_fopen(state_file, "rb"); + if ( ioctxt->io == NULL ) + { + xcio_perror(ioctxt, "Could not open file for reading"); + return rc; + } + + rc = xc_linux_restore(xc->xc_handle, ioctxt); + + IOStream_close(ioctxt->io); + + return rc; +} + +static PyObject *pyxc_linux_restore(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + char *state_file; + int progress = 1, debug = 0; + PyObject *val = NULL; + XcIOContext ioctxt = { .info = iostdout, .err = iostderr }; + int rc =-1; + + static char *kwd_list[] = { "state_file", "progress", "debug", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is|ii", kwd_list, + &ioctxt.domain, + &state_file, + &progress, + &debug) ) + goto exit; + + if ( progress ) + ioctxt.flags |= XCFLAGS_VERBOSE; + if ( debug ) + ioctxt.flags |= XCFLAGS_DEBUG; + + if ( (state_file == NULL) || (state_file[0] == '\0') ) + goto exit; + + rc = file_restore(xc, &ioctxt, state_file); + if ( rc != 0 ) + { + PyErr_SetFromErrno(xc_error); + goto exit; + } + + val = Py_BuildValue("{s:i,s:s}", + "dom", ioctxt.domain, + "vmconfig", ioctxt.vmconfig); + + exit: + return val; +} + +static PyObject *pyxc_linux_build(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + char *image, *ramdisk = NULL, *cmdline = ""; + int control_evtchn, flags = 0; + + static char *kwd_list[] = { "dom", "control_evtchn", + "image", "ramdisk", "cmdline", "flags", + NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list, + &dom, &control_evtchn, + &image, &ramdisk, &cmdline, &flags) ) + return NULL; + + if ( xc_linux_build(xc->xc_handle, dom, image, + ramdisk, cmdline, control_evtchn, flags) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_netbsd_build(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + char *image, *ramdisk = NULL, *cmdline = ""; + int control_evtchn; + + static char *kwd_list[] = { "dom", "control_evtchn", + "image", "ramdisk", "cmdline", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list, + &dom, &control_evtchn, + &image, &ramdisk, &cmdline) ) + return NULL; + + if ( xc_netbsd_build(xc->xc_handle, dom, image, + cmdline, control_evtchn) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_bvtsched_global_set(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + unsigned long ctx_allow; + + static char *kwd_list[] = { "ctx_allow", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "l", kwd_list, &ctx_allow) ) + return NULL; + + if ( xc_bvtsched_global_set(xc->xc_handle, ctx_allow) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_bvtsched_global_get(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + unsigned long ctx_allow; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( xc_bvtsched_global_get(xc->xc_handle, &ctx_allow) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("s:l", "ctx_allow", ctx_allow); +} + +static PyObject *pyxc_bvtsched_domain_set(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + unsigned long mcuadv, warp, warpl, warpu; + + static char *kwd_list[] = { "dom", "mcuadv", "warp", "warpl", + "warpu", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "illll", kwd_list, + &dom, &mcuadv, &warp, &warpl, &warpu) ) + return NULL; + + if ( xc_bvtsched_domain_set(xc->xc_handle, dom, mcuadv, + warp, warpl, warpu) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_bvtsched_domain_get(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 dom; + unsigned long mcuadv, warp, warpl, warpu; + + static char *kwd_list[] = { "dom", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) + return NULL; + + if ( xc_bvtsched_domain_get(xc->xc_handle, dom, &mcuadv, &warp, + &warpl, &warpu) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:i,s:l,s:l,s:l,s:l}", + "domain", dom, + "mcuadv", mcuadv, + "warp", warp, + "warpl", warpl, + "warpu", warpu); +} + +static PyObject *pyxc_evtchn_bind_interdomain(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom1 = DOMID_SELF, dom2 = DOMID_SELF; + int port1, port2; + + static char *kwd_list[] = { "dom1", "dom2", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, + &dom1, &dom2) ) + return NULL; + + if ( xc_evtchn_bind_interdomain(xc->xc_handle, dom1, + dom2, &port1, &port2) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:i,s:i}", + "port1", port1, + "port2", port2); +} + +static PyObject *pyxc_evtchn_bind_virq(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + int virq, port; + + static char *kwd_list[] = { "virq", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &virq) ) + return NULL; + + if ( xc_evtchn_bind_virq(xc->xc_handle, virq, &port) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return PyInt_FromLong(port); +} + +static PyObject *pyxc_evtchn_close(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom = DOMID_SELF; + int port; + + static char *kwd_list[] = { "port", "dom", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, + &port, &dom) ) + return NULL; + + if ( xc_evtchn_close(xc->xc_handle, dom, port) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_evtchn_send(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + int port; + + static char *kwd_list[] = { "port", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &port) ) + return NULL; + + if ( xc_evtchn_send(xc->xc_handle, port) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_evtchn_status(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + PyObject *dict; + + u32 dom = DOMID_SELF; + int port, ret; + xc_evtchn_status_t status; + + static char *kwd_list[] = { "port", "dom", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, + &port, &dom) ) + return NULL; + + ret = xc_evtchn_status(xc->xc_handle, dom, port, &status); + if ( ret != 0 ) + return PyErr_SetFromErrno(xc_error); + + switch ( status.status ) + { + case EVTCHNSTAT_closed: + dict = Py_BuildValue("{s:s}", + "status", "closed"); + break; + case EVTCHNSTAT_unbound: + dict = Py_BuildValue("{s:s}", + "status", "unbound"); + break; + case EVTCHNSTAT_interdomain: + dict = Py_BuildValue("{s:s,s:i,s:i}", + "status", "interdomain", + "dom", status.u.interdomain.dom, + "port", status.u.interdomain.port); + break; + case EVTCHNSTAT_pirq: + dict = Py_BuildValue("{s:s,s:i}", + "status", "pirq", + "irq", status.u.pirq); + break; + case EVTCHNSTAT_virq: + dict = Py_BuildValue("{s:s,s:i}", + "status", "virq", + "irq", status.u.virq); + break; + default: + dict = Py_BuildValue("{}"); + break; + } + + return dict; +} + +static PyObject *pyxc_physdev_pci_access_modify(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 dom; + int bus, dev, func, enable, ret; + + static char *kwd_list[] = { "dom", "bus", "dev", "func", "enable", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiii", kwd_list, + &dom, &bus, &dev, &func, &enable) ) + return NULL; + + ret = xc_physdev_pci_access_modify( + xc->xc_handle, dom, bus, dev, func, enable); + if ( ret != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_readconsolering(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + unsigned int clear = 0; + char str[32768]; + int ret; + + static char *kwd_list[] = { "clear", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) ) + return NULL; + + ret = xc_readconsolering(xc->xc_handle, str, sizeof(str), clear); + if ( ret < 0 ) + return PyErr_SetFromErrno(xc_error); + + return PyString_FromStringAndSize(str, ret); +} + +static PyObject *pyxc_physinfo(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + xc_physinfo_t info; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( xc_physinfo(xc->xc_handle, &info) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:i,s:i,s:l,s:l,s:l}", + "ht_per_core", info.ht_per_core, + "cores", info.cores, + "total_pages", info.total_pages, + "free_pages", info.free_pages, + "cpu_khz", info.cpu_khz); +} + +static PyObject *pyxc_atropos_domain_set(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 domid; + u64 period, slice, latency; + int xtratime; + + static char *kwd_list[] = { "dom", "period", "slice", "latency", + "xtratime", NULL }; + + if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLLLi", kwd_list, &domid, + &period, &slice, &latency, &xtratime) ) + return NULL; + + if ( xc_atropos_domain_set(xc->xc_handle, domid, period, slice, + latency, xtratime) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_atropos_domain_get(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 domid; + u64 period, slice, latency; + int xtratime; + + static char *kwd_list[] = { "dom", NULL }; + + if( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &domid) ) + return NULL; + + if ( xc_atropos_domain_get( xc->xc_handle, domid, &period, + &slice, &latency, &xtratime ) ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i}", + "domain", domid, + "period", period, + "slice", slice, + "latency", latency, + "xtratime", xtratime); +} + + +static PyObject *pyxc_rrobin_global_set(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u64 slice; + + static char *kwd_list[] = { "slice", NULL }; + + if( !PyArg_ParseTupleAndKeywords(args, kwds, "L", kwd_list, &slice) ) + return NULL; + + if ( xc_rrobin_global_set(xc->xc_handle, slice) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_shadow_control(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + int op=0; + + static char *kwd_list[] = { "dom", "op", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, + &dom, &op) ) + return NULL; + + if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, NULL) < 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_rrobin_global_get(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u64 slice; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( xc_rrobin_global_get(xc->xc_handle, &slice) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:L}", "slice", slice); +} + +static PyObject *pyxc_domain_setname(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 dom; + char *name; + + static char *kwd_list[] = { "dom", "name", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list, + &dom, &name) ) + return NULL; + + if ( xc_domain_setname(xc->xc_handle, dom, name) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_domain_setmaxmem(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + unsigned long max_memkb; + + static char *kwd_list[] = { "dom", "max_memkb", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list, + &dom, &max_memkb) ) + return NULL; + + if ( xc_domain_setmaxmem(xc->xc_handle, dom, max_memkb) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + + +static PyMethodDef pyxc_methods[] = { + { "domain_create", + (PyCFunction)pyxc_domain_create, + METH_VARARGS | METH_KEYWORDS, "\n" + "Create a new domain.\n" + " mem_kb [int, 0]: Memory allocation, in kilobytes.\n" + " name [str, '(anon)']: Informative textual name.\n\n" + "Returns: [int] new domain identifier; -1 on error.\n" }, + + { "domain_pause", + (PyCFunction)pyxc_domain_pause, + METH_VARARGS | METH_KEYWORDS, "\n" + "Temporarily pause execution of a domain.\n" + " dom [int]: Identifier of domain to be paused.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_unpause", + (PyCFunction)pyxc_domain_unpause, + METH_VARARGS | METH_KEYWORDS, "\n" + "(Re)start execution of a domain.\n" + " dom [int]: Identifier of domain to be unpaused.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_destroy", + (PyCFunction)pyxc_domain_destroy, + METH_VARARGS | METH_KEYWORDS, "\n" + "Destroy a domain.\n" + " dom [int]: Identifier of domain to be destroyed.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_pincpu", + (PyCFunction)pyxc_domain_pincpu, + METH_VARARGS | METH_KEYWORDS, "\n" + "Pin a domain to a specified CPU.\n" + " dom [int]: Identifier of domain to be pinned.\n" + " cpu [int, -1]: CPU to pin to, or -1 to unpin\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_getinfo", + (PyCFunction)pyxc_domain_getinfo, + METH_VARARGS | METH_KEYWORDS, "\n" + "Get information regarding a set of domains, in increasing id order.\n" + " first_dom [int, 0]: First domain to retrieve info about.\n" + " max_doms [int, 1024]: Maximum number of domains to retrieve info" + " about.\n\n" + "Returns: [list of dicts] if list length is less than 'max_doms'\n" + " parameter then there was an error, or the end of the\n" + " domain-id space was reached.\n" + " dom [int]: Identifier of domain to which this info pertains\n" + " cpu [int]: CPU to which this domain is bound\n" + " dying [int]: Bool - is the domain dying?\n" + " crashed [int]: Bool - has the domain crashed?\n" + " shutdown [int]: Bool - has the domain shut itself down?\n" + " paused [int]: Bool - is the domain paused by control software?\n" + " blocked [int]: Bool - is the domain blocked waiting for an event?\n" + " running [int]: Bool - is the domain currently running?\n" + " mem_kb [int]: Memory reservation, in kilobytes\n" + " cpu_time [long]: CPU time consumed, in nanoseconds\n" + " name [str]: Identifying name\n" + " shutdown_reason [int]: Numeric code from guest OS, explaining " + "reason why it shut itself down.\n" }, + + { "linux_save", + (PyCFunction)pyxc_linux_save, + METH_VARARGS | METH_KEYWORDS, "\n" + "Save the CPU and memory state of a Linux guest OS.\n" + " dom [int]: Identifier of domain to be saved.\n" + " state_file [str]: Name of state file. Must not currently exist.\n" + " progress [int, 1]: Bool - display a running progress indication?\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "linux_restore", + (PyCFunction)pyxc_linux_restore, + METH_VARARGS | METH_KEYWORDS, "\n" + "Restore the CPU and memory state of a Linux guest OS.\n" + " state_file [str]: Name of state file. Must not currently exist.\n" + " progress [int, 1]: Bool - display a running progress indication?\n\n" + "Returns: [int] new domain identifier on success; -1 on error.\n" }, + + { "linux_build", + (PyCFunction)pyxc_linux_build, + METH_VARARGS | METH_KEYWORDS, "\n" + "Build a new Linux guest OS.\n" + " dom [int]: Identifier of domain to build into.\n" + " image [str]: Name of kernel image file. May be gzipped.\n" + " ramdisk [str, n/a]: Name of ramdisk file, if any.\n" + " cmdline [str, n/a]: Kernel parameters, if any.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "netbsd_build", + (PyCFunction)pyxc_netbsd_build, + METH_VARARGS | METH_KEYWORDS, "\n" + "Build a new NetBSD guest OS.\n" + " dom [int]: Identifier of domain to build into.\n" + " image [str]: Name of kernel image file. May be gzipped.\n" + " cmdline [str, n/a]: Kernel parameters, if any.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "bvtsched_global_set", + (PyCFunction)pyxc_bvtsched_global_set, + METH_VARARGS | METH_KEYWORDS, "\n" + "Set global tuning parameters for Borrowed Virtual Time scheduler.\n" + " ctx_allow [int]: Minimal guaranteed quantum.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "bvtsched_global_get", + (PyCFunction)pyxc_bvtsched_global_get, + METH_KEYWORDS, "\n" + "Get global tuning parameters for BVT scheduler.\n" + "Returns: [dict]:\n" + " ctx_allow [int]: context switch allowance\n" }, + + { "bvtsched_domain_set", + (PyCFunction)pyxc_bvtsched_domain_set, + METH_VARARGS | METH_KEYWORDS, "\n" + "Set per-domain tuning parameters for Borrowed Virtual Time scheduler.\n" + " dom [int]: Identifier of domain to be tuned.\n" + " mcuadv [int]: Proportional to the inverse of the domain's weight.\n" + " warp [int]: How far to warp domain's EVT on unblock.\n" + " warpl [int]: How long the domain can run warped.\n" + " warpu [int]: How long before the domain can warp again.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "bvtsched_domain_get", + (PyCFunction)pyxc_bvtsched_domain_get, + METH_KEYWORDS, "\n" + "Get per-domain tuning parameters under the BVT scheduler.\n" + " dom [int]: Identifier of domain to be queried.\n" + "Returns [dict]:\n" + " domain [int]: Domain ID.\n" + " mcuadv [long]: MCU Advance.\n" + " warp [long]: Warp.\n" + " warpu [long]: Unwarp requirement.\n" + " warpl [long]: Warp limit,\n" + }, + + { "atropos_domain_set", + (PyCFunction)pyxc_atropos_domain_set, + METH_KEYWORDS, "\n" + "Set the scheduling parameters for a domain when running with Atropos.\n" + " dom [int]: domain to set\n" + " period [long]: domain's scheduling period\n" + " slice [long]: domain's slice per period\n" + " latency [long]: wakeup latency hint\n" + " xtratime [int]: boolean\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "atropos_domain_get", + (PyCFunction)pyxc_atropos_domain_get, + METH_KEYWORDS, "\n" + "Get the current scheduling parameters for a domain when running with\n" + "the Atropos scheduler." + " dom [int]: domain to query\n" + "Returns: [dict]\n" + " domain [int]: domain ID\n" + " period [long]: scheduler period\n" + " slice [long]: CPU reservation per period\n" + " latency [long]: unblocking latency hint\n" + " xtratime [int] : 0 if not using slack time, nonzero otherwise\n" }, + + { "rrobin_global_set", + (PyCFunction)pyxc_rrobin_global_set, + METH_KEYWORDS, "\n" + "Set Round Robin scheduler slice.\n" + " slice [long]: Round Robin scheduler slice\n" + "Returns: [int] 0 on success, throws an exception on failure\n" }, + + { "rrobin_global_get", + (PyCFunction)pyxc_rrobin_global_get, + METH_KEYWORDS, "\n" + "Get Round Robin scheduler settings\n" + "Returns [dict]:\n" + " slice [long]: Scheduler time slice.\n" }, + + { "evtchn_bind_interdomain", + (PyCFunction)pyxc_evtchn_bind_interdomain, + METH_VARARGS | METH_KEYWORDS, "\n" + "Open an event channel between two domains.\n" + " dom1 [int, SELF]: First domain to be connected.\n" + " dom2 [int, SELF]: Second domain to be connected.\n\n" + "Returns: [dict] dictionary is empty on failure.\n" + " port1 [int]: Port-id for endpoint at dom1.\n" + " port2 [int]: Port-id for endpoint at dom2.\n" }, + + { "evtchn_bind_virq", + (PyCFunction)pyxc_evtchn_bind_virq, + METH_VARARGS | METH_KEYWORDS, "\n" + "Bind an event channel to the specified VIRQ.\n" + " virq [int]: VIRQ to bind.\n\n" + "Returns: [int] Bound event-channel port.\n" }, + + { "evtchn_close", + (PyCFunction)pyxc_evtchn_close, + METH_VARARGS | METH_KEYWORDS, "\n" + "Close an event channel.\n" + " dom [int, SELF]: Dom-id of one endpoint of the channel.\n" + " port [int]: Port-id of one endpoint of the channel.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "evtchn_send", + (PyCFunction)pyxc_evtchn_send, + METH_VARARGS | METH_KEYWORDS, "\n" + "Send an event along a locally-connected event channel.\n" + " port [int]: Port-id of a local channel endpoint.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "evtchn_status", + (PyCFunction)pyxc_evtchn_status, + METH_VARARGS | METH_KEYWORDS, "\n" + "Query the status of an event channel.\n" + " dom [int, SELF]: Dom-id of one endpoint of the channel.\n" + " port [int]: Port-id of one endpoint of the channel.\n\n" + "Returns: [dict] dictionary is empty on failure.\n" + " status [str]: 'closed', 'unbound', 'interdomain', 'pirq'," + " or 'virq'.\n" + "The following are returned if 'status' is 'interdomain':\n" + " dom [int]: Dom-id of remote endpoint.\n" + " port [int]: Port-id of remote endpoint.\n" + "The following are returned if 'status' is 'pirq' or 'virq':\n" + " irq [int]: IRQ number.\n" }, + + { "physdev_pci_access_modify", + (PyCFunction)pyxc_physdev_pci_access_modify, + METH_VARARGS | METH_KEYWORDS, "\n" + "Allow a domain access to a PCI device\n" + " dom [int]: Identifier of domain to be allowed access.\n" + " bus [int]: PCI bus\n" + " dev [int]: PCI slot\n" + " func [int]: PCI function\n" + " enable [int]: Non-zero means enable access; else disable access\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "readconsolering", + (PyCFunction)pyxc_readconsolering, + METH_VARARGS | METH_KEYWORDS, "\n" + "Read Xen's console ring.\n" + " clear [int, 0]: Bool - clear the ring after reading from it?\n\n" + "Returns: [str] string is empty on failure.\n" }, + + { "physinfo", + (PyCFunction)pyxc_physinfo, + METH_VARARGS, "\n" + "Get information about the physical host machine\n" + "Returns [dict]: information about the hardware" + " [None]: on failure.\n" }, + + { "shadow_control", + (PyCFunction)pyxc_shadow_control, + METH_VARARGS | METH_KEYWORDS, "\n" + "Set parameter for shadow pagetable interface\n" + " dom [int]: Identifier of domain.\n" + " op [int, 0]: operation\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_setname", + (PyCFunction)pyxc_domain_setname, + METH_VARARGS | METH_KEYWORDS, "\n" + "Set domain informative textual name\n" + " dom [int]: Identifier of domain.\n" + " name [str]: Text string.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_setmaxmem", + (PyCFunction)pyxc_domain_setmaxmem, + METH_VARARGS | METH_KEYWORDS, "\n" + "Set a domain's memory limit\n" + " dom [int]: Identifier of domain.\n" + " max_memkb [long]: .\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { NULL, NULL, 0, NULL } +}; + + +/* + * Definitions for the 'Xc' module wrapper. + */ + +staticforward PyTypeObject PyXcType; + +static PyObject *PyXc_new(PyObject *self, PyObject *args) +{ + XcObject *xc; + + if ( !PyArg_ParseTuple(args, ":new") ) + return NULL; + + xc = PyObject_New(XcObject, &PyXcType); + + if ( (xc->xc_handle = xc_interface_open()) == -1 ) + { + PyObject_Del((PyObject *)xc); + return PyErr_SetFromErrno(xc_error); + } + + return (PyObject *)xc; +} + +static PyObject *PyXc_getattr(PyObject *obj, char *name) +{ + return Py_FindMethod(pyxc_methods, obj, name); +} + +static void PyXc_dealloc(PyObject *self) +{ + XcObject *xc = (XcObject *)self; + (void)xc_interface_close(xc->xc_handle); + PyObject_Del(self); +} + +static PyTypeObject PyXcType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "Xc", + sizeof(XcObject), + 0, + PyXc_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + PyXc_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + +static PyMethodDef PyXc_methods[] = { + { "new", PyXc_new, METH_VARARGS, "Create a new " XENPKG " object." }, + { NULL, NULL, 0, NULL } +}; + +PyMODINIT_FUNC initxc(void) +{ + PyObject *m, *d; + + m = Py_InitModule(XENPKG, PyXc_methods); + + d = PyModule_GetDict(m); + xc_error = PyErr_NewException(XENPKG ".error", NULL, NULL); + PyDict_SetItemString(d, "error", xc_error); + + zero = PyInt_FromLong(0); +} diff --git a/tools/python/xen/lowlevel/xu/__init__.py b/tools/python/xen/lowlevel/xu/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/python/xen/lowlevel/xu/domain_controller.h b/tools/python/xen/lowlevel/xu/domain_controller.h new file mode 100644 index 0000000000..76dd164fcb --- /dev/null +++ b/tools/python/xen/lowlevel/xu/domain_controller.h @@ -0,0 +1,532 @@ +/****************************************************************************** + * domain_controller.h + * + * Interface to server controller (e.g., 'xend'). This header file defines the + * interface that is shared with guest OSes. + * + * Copyright (c) 2004, K A Fraser + */ + +#ifndef __DOMAIN_CONTROLLER_H__ +#define __DOMAIN_CONTROLLER_H__ + + +#ifndef BASIC_START_INFO +#error "Xen header file hypervisor-if.h must already be included here." +#endif + + +/* + * EXTENDED BOOTSTRAP STRUCTURE FOR NEW DOMAINS. + */ + +typedef struct { + BASIC_START_INFO; + u16 domain_controller_evtchn; /* 320 */ +} PACKED extended_start_info_t; /* 322 bytes */ +#define SIF_BLK_BE_DOMAIN (1<<4) /* Is this a block backend domain? */ +#define SIF_NET_BE_DOMAIN (1<<5) /* Is this a net backend domain? */ + + +/* + * Reason codes for SCHEDOP_shutdown. These are opaque to Xen but may be + * interpreted by control software to determine the appropriate action. These + * are only really advisories: the controller can actually do as it likes. + */ +#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */ +#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */ +#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */ + + +/* + * CONTROLLER MESSAGING INTERFACE. + */ + +typedef struct { + u8 type; /* 0: echoed in response */ + u8 subtype; /* 1: echoed in response */ + u8 id; /* 2: echoed in response */ + u8 length; /* 3: number of bytes in 'msg' */ + u8 msg[60]; /* 4: type-specific message data */ +} PACKED control_msg_t; /* 64 bytes */ + +#define CONTROL_RING_SIZE 8 +typedef u32 CONTROL_RING_IDX; +#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1)) + +typedef struct { + control_msg_t tx_ring[CONTROL_RING_SIZE]; /* 0: guest -> controller */ + control_msg_t rx_ring[CONTROL_RING_SIZE]; /* 512: controller -> guest */ + CONTROL_RING_IDX tx_req_prod, tx_resp_prod; /* 1024, 1028 */ + CONTROL_RING_IDX rx_req_prod, rx_resp_prod; /* 1032, 1036 */ +} PACKED control_if_t; /* 1040 bytes */ + +/* + * Top-level command types. + */ +#define CMSG_CONSOLE 0 /* Console */ +#define CMSG_BLKIF_BE 1 /* Block-device backend */ +#define CMSG_BLKIF_FE 2 /* Block-device frontend */ +#define CMSG_NETIF_BE 3 /* Network-device backend */ +#define CMSG_NETIF_FE 4 /* Network-device frontend */ +#define CMSG_SHUTDOWN 6 /* Shutdown messages */ + + +/****************************************************************************** + * CONSOLE DEFINITIONS + */ + +/* + * Subtypes for console messages. + */ +#define CMSG_CONSOLE_DATA 0 + + +/****************************************************************************** + * BLOCK-INTERFACE FRONTEND DEFINITIONS + */ + +/* Messages from domain controller to guest. */ +#define CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED 0 + +/* Messages from guest to domain controller. */ +#define CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED 32 +#define CMSG_BLKIF_FE_INTERFACE_CONNECT 33 +#define CMSG_BLKIF_FE_INTERFACE_DISCONNECT 34 + +/* These are used by both front-end and back-end drivers. */ +#define blkif_vdev_t u16 +#define blkif_pdev_t u16 +#define blkif_sector_t u64 + +/* + * CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED: + * Notify a guest about a status change on one of its block interfaces. + * If the interface is DESTROYED or DOWN then the interface is disconnected: + * 1. The shared-memory frame is available for reuse. + * 2. Any unacknowledged messgaes pending on the interface were dropped. + */ +#define BLKIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */ +#define BLKIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */ +#define BLKIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */ +typedef struct { + u32 handle; /* 0 */ + u32 status; /* 4 */ + u16 evtchn; /* 8: (only if status == BLKIF_INTERFACE_STATUS_CONNECTED). */ +} PACKED blkif_fe_interface_status_changed_t; /* 10 bytes */ + +/* + * CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED: + * Notify the domain controller that the front-end driver is DOWN or UP. + * When the driver goes DOWN then the controller will send no more + * status-change notifications. When the driver comes UP then the controller + * will send a notification for each interface that currently exists. + * If the driver goes DOWN while interfaces are still UP, the domain + * will automatically take the interfaces DOWN. + */ +#define BLKIF_DRIVER_STATUS_DOWN 0 +#define BLKIF_DRIVER_STATUS_UP 1 +typedef struct { + /* IN */ + u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */ + /* OUT */ + /* + * Tells driver how many interfaces it should expect to immediately + * receive notifications about. + */ + u32 nr_interfaces; /* 4 */ +} PACKED blkif_fe_driver_status_changed_t; /* 8 bytes */ + +/* + * CMSG_BLKIF_FE_INTERFACE_CONNECT: + * If successful, the domain controller will acknowledge with a + * STATUS_CONNECTED message. + */ +typedef struct { + u32 handle; /* 0 */ + u32 __pad; + memory_t shmem_frame; /* 8 */ + MEMORY_PADDING; +} PACKED blkif_fe_interface_connect_t; /* 16 bytes */ + +/* + * CMSG_BLKIF_FE_INTERFACE_DISCONNECT: + * If successful, the domain controller will acknowledge with a + * STATUS_DISCONNECTED message. + */ +typedef struct { + u32 handle; /* 0 */ +} PACKED blkif_fe_interface_disconnect_t; /* 4 bytes */ + + +/****************************************************************************** + * BLOCK-INTERFACE BACKEND DEFINITIONS + */ + +/* Messages from domain controller. */ +#define CMSG_BLKIF_BE_CREATE 0 /* Create a new block-device interface. */ +#define CMSG_BLKIF_BE_DESTROY 1 /* Destroy a block-device interface. */ +#define CMSG_BLKIF_BE_CONNECT 2 /* Connect i/f to remote driver. */ +#define CMSG_BLKIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */ +#define CMSG_BLKIF_BE_VBD_CREATE 4 /* Create a new VBD for an interface. */ +#define CMSG_BLKIF_BE_VBD_DESTROY 5 /* Delete a VBD from an interface. */ +#define CMSG_BLKIF_BE_VBD_GROW 6 /* Append an extent to a given VBD. */ +#define CMSG_BLKIF_BE_VBD_SHRINK 7 /* Remove last extent from a given VBD. */ + +/* Messages to domain controller. */ +#define CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED 32 + +/* + * Message request/response definitions for block-device messages. + */ + +typedef struct { + blkif_sector_t sector_start; /* 0 */ + blkif_sector_t sector_length; /* 8 */ + blkif_pdev_t device; /* 16 */ + u16 __pad; /* 18 */ +} PACKED blkif_extent_t; /* 20 bytes */ + +/* Non-specific 'okay' return. */ +#define BLKIF_BE_STATUS_OKAY 0 +/* Non-specific 'error' return. */ +#define BLKIF_BE_STATUS_ERROR 1 +/* The following are specific error returns. */ +#define BLKIF_BE_STATUS_INTERFACE_EXISTS 2 +#define BLKIF_BE_STATUS_INTERFACE_NOT_FOUND 3 +#define BLKIF_BE_STATUS_INTERFACE_CONNECTED 4 +#define BLKIF_BE_STATUS_VBD_EXISTS 5 +#define BLKIF_BE_STATUS_VBD_NOT_FOUND 6 +#define BLKIF_BE_STATUS_OUT_OF_MEMORY 7 +#define BLKIF_BE_STATUS_EXTENT_NOT_FOUND 8 +#define BLKIF_BE_STATUS_MAPPING_ERROR 9 + +/* This macro can be used to create an array of descriptive error strings. */ +#define BLKIF_BE_STATUS_ERRORS { \ + "Okay", \ + "Non-specific error", \ + "Interface already exists", \ + "Interface not found", \ + "Interface is still connected", \ + "VBD already exists", \ + "VBD not found", \ + "Out of memory", \ + "Extent not found for VBD", \ + "Could not map domain memory" } + +/* + * CMSG_BLKIF_BE_CREATE: + * When the driver sends a successful response then the interface is fully + * created. The controller will send a DOWN notification to the front-end + * driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Domain attached to new interface. */ + u32 blkif_handle; /* 4: Domain-specific interface handle. */ + /* OUT */ + u32 status; /* 8 */ +} PACKED blkif_be_create_t; /* 12 bytes */ + +/* + * CMSG_BLKIF_BE_DESTROY: + * When the driver sends a successful response then the interface is fully + * torn down. The controller will send a DESTROYED notification to the + * front-end driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Identify interface to be destroyed. */ + u32 blkif_handle; /* 4: ...ditto... */ + /* OUT */ + u32 status; /* 8 */ +} PACKED blkif_be_destroy_t; /* 12 bytes */ + +/* + * CMSG_BLKIF_BE_CONNECT: + * When the driver sends a successful response then the interface is fully + * connected. The controller will send a CONNECTED notification to the + * front-end driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Domain attached to new interface. */ + u32 blkif_handle; /* 4: Domain-specific interface handle. */ + memory_t shmem_frame; /* 8: Page cont. shared comms window. */ + MEMORY_PADDING; + u32 evtchn; /* 16: Event channel for notifications. */ + /* OUT */ + u32 status; /* 20 */ +} PACKED blkif_be_connect_t; /* 24 bytes */ + +/* + * CMSG_BLKIF_BE_DISCONNECT: + * When the driver sends a successful response then the interface is fully + * disconnected. The controller will send a DOWN notification to the front-end + * driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Domain attached to new interface. */ + u32 blkif_handle; /* 4: Domain-specific interface handle. */ + /* OUT */ + u32 status; /* 8 */ +} PACKED blkif_be_disconnect_t; /* 12 bytes */ + +/* CMSG_BLKIF_BE_VBD_CREATE */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Identify blkdev interface. */ + u32 blkif_handle; /* 4: ...ditto... */ + blkif_vdev_t vdevice; /* 8: Interface-specific id for this VBD. */ + u16 readonly; /* 10: Non-zero -> VBD isn't writeable. */ + /* OUT */ + u32 status; /* 12 */ +} PACKED blkif_be_vbd_create_t; /* 16 bytes */ + +/* CMSG_BLKIF_BE_VBD_DESTROY */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Identify blkdev interface. */ + u32 blkif_handle; /* 4: ...ditto... */ + blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */ + u16 __pad; /* 10 */ + /* OUT */ + u32 status; /* 12 */ +} PACKED blkif_be_vbd_destroy_t; /* 16 bytes */ + +/* CMSG_BLKIF_BE_VBD_GROW */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Identify blkdev interface. */ + u32 blkif_handle; /* 4: ...ditto... */ + blkif_extent_t extent; /* 8: Physical extent to append to VBD. */ + blkif_vdev_t vdevice; /* 28: Interface-specific id of the VBD. */ + u16 __pad; /* 30 */ + /* OUT */ + u32 status; /* 32 */ +} PACKED blkif_be_vbd_grow_t; /* 36 bytes */ + +/* CMSG_BLKIF_BE_VBD_SHRINK */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Identify blkdev interface. */ + u32 blkif_handle; /* 4: ...ditto... */ + blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */ + u16 __pad; /* 10 */ + /* OUT */ + u32 status; /* 12 */ +} PACKED blkif_be_vbd_shrink_t; /* 16 bytes */ + +/* + * CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: + * Notify the domain controller that the back-end driver is DOWN or UP. + * If the driver goes DOWN while interfaces are still UP, the controller + * will automatically send DOWN notifications. + */ +typedef struct { + u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */ +} PACKED blkif_be_driver_status_changed_t; /* 4 bytes */ + + +/****************************************************************************** + * NETWORK-INTERFACE FRONTEND DEFINITIONS + */ + +/* Messages from domain controller to guest. */ +#define CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED 0 + +/* Messages from guest to domain controller. */ +#define CMSG_NETIF_FE_DRIVER_STATUS_CHANGED 32 +#define CMSG_NETIF_FE_INTERFACE_CONNECT 33 +#define CMSG_NETIF_FE_INTERFACE_DISCONNECT 34 + +/* + * CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED: + * Notify a guest about a status change on one of its network interfaces. + * If the interface is DESTROYED or DOWN then the interface is disconnected: + * 1. The shared-memory frame is available for reuse. + * 2. Any unacknowledged messgaes pending on the interface were dropped. + */ +#define NETIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */ +#define NETIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */ +#define NETIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */ +typedef struct { + u32 handle; /* 0 */ + u32 status; /* 4 */ + u16 evtchn; /* 8: status == NETIF_INTERFACE_STATUS_CONNECTED */ + u8 mac[6]; /* 10: status == NETIF_INTERFACE_STATUS_CONNECTED */ +} PACKED netif_fe_interface_status_changed_t; /* 16 bytes */ + +/* + * CMSG_NETIF_FE_DRIVER_STATUS_CHANGED: + * Notify the domain controller that the front-end driver is DOWN or UP. + * When the driver goes DOWN then the controller will send no more + * status-change notifications. When the driver comes UP then the controller + * will send a notification for each interface that currently exists. + * If the driver goes DOWN while interfaces are still UP, the domain + * will automatically take the interfaces DOWN. + */ +#define NETIF_DRIVER_STATUS_DOWN 0 +#define NETIF_DRIVER_STATUS_UP 1 +typedef struct { + /* IN */ + u32 status; /* 0: NETIF_DRIVER_STATUS_??? */ + /* OUT */ + /* + * Tells driver how many interfaces it should expect to immediately + * receive notifications about. + */ + u32 nr_interfaces; /* 4 */ +} PACKED netif_fe_driver_status_changed_t; /* 8 bytes */ + +/* + * CMSG_NETIF_FE_INTERFACE_CONNECT: + * If successful, the domain controller will acknowledge with a + * STATUS_CONNECTED message. + */ +typedef struct { + u32 handle; /* 0 */ + u32 __pad; /* 4 */ + memory_t tx_shmem_frame; /* 8 */ + MEMORY_PADDING; + memory_t rx_shmem_frame; /* 16 */ + MEMORY_PADDING; +} PACKED netif_fe_interface_connect_t; /* 24 bytes */ + +/* + * CMSG_NETIF_FE_INTERFACE_DISCONNECT: + * If successful, the domain controller will acknowledge with a + * STATUS_DISCONNECTED message. + */ +typedef struct { + u32 handle; /* 0 */ +} PACKED netif_fe_interface_disconnect_t; /* 4 bytes */ + + +/****************************************************************************** + * NETWORK-INTERFACE BACKEND DEFINITIONS + */ + +/* Messages from domain controller. */ +#define CMSG_NETIF_BE_CREATE 0 /* Create a new net-device interface. */ +#define CMSG_NETIF_BE_DESTROY 1 /* Destroy a net-device interface. */ +#define CMSG_NETIF_BE_CONNECT 2 /* Connect i/f to remote driver. */ +#define CMSG_NETIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */ + +/* Messages to domain controller. */ +#define CMSG_NETIF_BE_DRIVER_STATUS_CHANGED 32 + +/* + * Message request/response definitions for net-device messages. + */ + +/* Non-specific 'okay' return. */ +#define NETIF_BE_STATUS_OKAY 0 +/* Non-specific 'error' return. */ +#define NETIF_BE_STATUS_ERROR 1 +/* The following are specific error returns. */ +#define NETIF_BE_STATUS_INTERFACE_EXISTS 2 +#define NETIF_BE_STATUS_INTERFACE_NOT_FOUND 3 +#define NETIF_BE_STATUS_INTERFACE_CONNECTED 4 +#define NETIF_BE_STATUS_OUT_OF_MEMORY 5 +#define NETIF_BE_STATUS_MAPPING_ERROR 6 + +/* This macro can be used to create an array of descriptive error strings. */ +#define NETIF_BE_STATUS_ERRORS { \ + "Okay", \ + "Non-specific error", \ + "Interface already exists", \ + "Interface not found", \ + "Interface is still connected", \ + "Out of memory", \ + "Could not map domain memory" } + +/* + * CMSG_NETIF_BE_CREATE: + * When the driver sends a successful response then the interface is fully + * created. The controller will send a DOWN notification to the front-end + * driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Domain attached to new interface. */ + u32 netif_handle; /* 4: Domain-specific interface handle. */ + u8 mac[6]; /* 8 */ + u16 __pad; /* 14 */ + /* OUT */ + u32 status; /* 16 */ +} PACKED netif_be_create_t; /* 20 bytes */ + +/* + * CMSG_NETIF_BE_DESTROY: + * When the driver sends a successful response then the interface is fully + * torn down. The controller will send a DESTROYED notification to the + * front-end driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Identify interface to be destroyed. */ + u32 netif_handle; /* 4: ...ditto... */ + /* OUT */ + u32 status; /* 8 */ +} PACKED netif_be_destroy_t; /* 12 bytes */ + +/* + * CMSG_NETIF_BE_CONNECT: + * When the driver sends a successful response then the interface is fully + * connected. The controller will send a CONNECTED notification to the + * front-end driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Domain attached to new interface. */ + u32 netif_handle; /* 4: Domain-specific interface handle. */ + memory_t tx_shmem_frame; /* 8: Page cont. tx shared comms window. */ + MEMORY_PADDING; + memory_t rx_shmem_frame; /* 16: Page cont. rx shared comms window. */ + MEMORY_PADDING; + u16 evtchn; /* 24: Event channel for notifications. */ + u16 __pad; /* 26 */ + /* OUT */ + u32 status; /* 28 */ +} PACKED netif_be_connect_t; /* 32 bytes */ + +/* + * CMSG_NETIF_BE_DISCONNECT: + * When the driver sends a successful response then the interface is fully + * disconnected. The controller will send a DOWN notification to the front-end + * driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Domain attached to new interface. */ + u32 netif_handle; /* 4: Domain-specific interface handle. */ + /* OUT */ + u32 status; /* 8 */ +} PACKED netif_be_disconnect_t; /* 12 bytes */ + +/* + * CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: + * Notify the domain controller that the back-end driver is DOWN or UP. + * If the driver goes DOWN while interfaces are still UP, the domain + * will automatically send DOWN notifications. + */ +typedef struct { + u32 status; /* 0: NETIF_DRIVER_STATUS_??? */ +} PACKED netif_be_driver_status_changed_t; /* 4 bytes */ + + +/****************************************************************************** + * SHUTDOWN DEFINITIONS + */ + +/* + * Subtypes for shutdown messages. + */ +#define CMSG_SHUTDOWN_POWEROFF 0 /* Clean shutdown (SHUTDOWN_poweroff). */ +#define CMSG_SHUTDOWN_REBOOT 1 /* Clean shutdown (SHUTDOWN_reboot). */ +#define CMSG_SHUTDOWN_SUSPEND 2 /* Create suspend info, then */ + /* SHUTDOWN_suspend. */ + +#endif /* __DOMAIN_CONTROLLER_H__ */ diff --git a/tools/python/xen/lowlevel/xu/xu.c b/tools/python/xen/lowlevel/xu/xu.c new file mode 100644 index 0000000000..ae11ce6885 --- /dev/null +++ b/tools/python/xen/lowlevel/xu/xu.c @@ -0,0 +1,1386 @@ +/****************************************************************************** + * utils.c + * + * Copyright (c) 2004, K A Fraser + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "domain_controller.h" + +#include + +#define XENPKG "xen.lowlevel.xu" + +/* Needed for Python versions earlier than 2.3. */ +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC DL_EXPORT(void) +#endif + +/* NB. The following should be kept in sync with the kernel's evtchn driver. */ +#define EVTCHN_DEV_NAME "/dev/xen/evtchn" +#define EVTCHN_DEV_MAJOR 10 +#define EVTCHN_DEV_MINOR 200 +#define PORT_NORMAL 0x0000 /* A standard event notification. */ +#define PORT_EXCEPTION 0x8000 /* An exceptional notification. */ +#define PORTIDX_MASK 0x7fff /* Strip subtype to obtain port index. */ +/* /dev/xen/evtchn ioctls: */ +/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */ +#define EVTCHN_RESET _IO('E', 1) +/* EVTCHN_BIND: Bind to teh specified event-channel port. */ +#define EVTCHN_BIND _IO('E', 2) +/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */ +#define EVTCHN_UNBIND _IO('E', 3) + +/* Size of a machine page frame. */ +#define PAGE_SIZE 4096 + + +/* + * *********************** NOTIFIER *********************** + */ + +typedef struct { + PyObject_HEAD; + int evtchn_fd; +} xu_notifier_object; + +static PyObject *xu_notifier_read(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + u16 v; + int bytes; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + while ( (bytes = read(xun->evtchn_fd, &v, sizeof(v))) == -1 ) + { + if ( errno == EINTR ) + continue; + if ( errno == EAGAIN ) + goto none; + return PyErr_SetFromErrno(PyExc_IOError); + } + + if ( bytes == sizeof(v) ) + return Py_BuildValue("(i,i)", v&PORTIDX_MASK, v&~PORTIDX_MASK); + + none: + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_notifier_unmask(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + u16 v; + int idx; + + if ( !PyArg_ParseTuple(args, "i", &idx) ) + return NULL; + + v = (u16)idx; + + (void)write(xun->evtchn_fd, &v, sizeof(v)); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_notifier_bind(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + int idx; + + if ( !PyArg_ParseTuple(args, "i", &idx) ) + return NULL; + + if ( ioctl(xun->evtchn_fd, EVTCHN_BIND, idx) != 0 ) + return PyErr_SetFromErrno(PyExc_IOError); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + int idx; + + if ( !PyArg_ParseTuple(args, "i", &idx) ) + return NULL; + + if ( ioctl(xun->evtchn_fd, EVTCHN_UNBIND, idx) != 0 ) + return PyErr_SetFromErrno(PyExc_IOError); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + return PyInt_FromLong(xun->evtchn_fd); +} + +static PyMethodDef xu_notifier_methods[] = { + { "read", + (PyCFunction)xu_notifier_read, + METH_VARARGS, + "Read a (@port, @type) pair.\n" }, + + { "unmask", + (PyCFunction)xu_notifier_unmask, + METH_VARARGS, + "Unmask notifications for a @port.\n" }, + + { "bind", + (PyCFunction)xu_notifier_bind, + METH_VARARGS, + "Get notifications for a @port.\n" }, + + { "unbind", + (PyCFunction)xu_notifier_unbind, + METH_VARARGS, + "No longer get notifications for a @port.\n" }, + + { "fileno", + (PyCFunction)xu_notifier_fileno, + METH_VARARGS, + "Return the file descriptor for the notification channel.\n" }, + + { NULL, NULL, 0, NULL } +}; + +staticforward PyTypeObject xu_notifier_type; + +static PyObject *xu_notifier_new(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + xun = PyObject_New(xu_notifier_object, &xu_notifier_type); + + reopen: + xun->evtchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR); + if ( xun->evtchn_fd == -1 ) + { + if ( (errno == ENOENT) && + ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) && + (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600, + (EVTCHN_DEV_MAJOR << 8) | EVTCHN_DEV_MINOR) == 0) ) + goto reopen; + PyObject_Del((PyObject *)xun); + return PyErr_SetFromErrno(PyExc_IOError); + } + + return (PyObject *)xun; +} + +static PyObject *xu_notifier_getattr(PyObject *obj, char *name) +{ + if ( strcmp(name, "EXCEPTION") == 0 ) + return PyInt_FromLong(PORT_EXCEPTION); + if ( strcmp(name, "NORMAL") == 0 ) + return PyInt_FromLong(PORT_NORMAL); + return Py_FindMethod(xu_notifier_methods, obj, name); +} + +static void xu_notifier_dealloc(PyObject *self) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + (void)close(xun->evtchn_fd); + PyObject_Del(self); +} + +static PyTypeObject xu_notifier_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "notifier", + sizeof(xu_notifier_object), + 0, + xu_notifier_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + xu_notifier_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + + + +/* + * *********************** MESSAGE *********************** + */ + +#define TYPE(_x,_y) (((_x)<<8)|(_y)) +#define P2C(_struct, _field, _ctype) \ + do { \ + PyObject *obj; \ + if ( (obj = PyDict_GetItemString(payload, #_field)) != NULL ) \ + { \ + if ( PyInt_Check(obj) ) \ + { \ + ((_struct *)&xum->msg.msg[0])->_field = \ + (_ctype)PyInt_AsLong(obj); \ + dict_items_parsed++; \ + } \ + else if ( PyLong_Check(obj) ) \ + { \ + ((_struct *)&xum->msg.msg[0])->_field = \ + (_ctype)PyLong_AsUnsignedLongLong(obj); \ + dict_items_parsed++; \ + } \ + } \ + xum->msg.length = sizeof(_struct); \ + } while ( 0 ) +#define C2P(_struct, _field, _pytype, _ctype) \ + do { \ + PyObject *obj = Py ## _pytype ## _From ## _ctype \ + (((_struct *)&xum->msg.msg[0])->_field); \ + if ( dict == NULL ) dict = PyDict_New(); \ + PyDict_SetItemString(dict, #_field, obj); \ + } while ( 0 ) + +typedef struct { + PyObject_HEAD; + control_msg_t msg; +} xu_message_object; + +static PyObject *xu_message_append_payload(PyObject *self, PyObject *args) +{ + xu_message_object *xum = (xu_message_object *)self; + char *str; + int len; + + if ( !PyArg_ParseTuple(args, "s#", &str, &len) ) + return NULL; + + if ( (len + xum->msg.length) > sizeof(xum->msg.msg) ) + { + PyErr_SetString(PyExc_RuntimeError, "out of space in control message"); + return NULL; + } + + memcpy(&xum->msg.msg[xum->msg.length], str, len); + xum->msg.length += len; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_message_set_response_fields(PyObject *self, PyObject *args) +{ + xu_message_object *xum = (xu_message_object *)self; + PyObject *payload; + int dict_items_parsed = 0; + + if ( !PyArg_ParseTuple(args, "O", &payload) ) + return NULL; + + if ( !PyDict_Check(payload) ) + { + PyErr_SetString(PyExc_TypeError, "payload is not a dictionary"); + return NULL; + } + + switch ( TYPE(xum->msg.type, xum->msg.subtype) ) + { + case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED): + P2C(blkif_fe_driver_status_changed_t, nr_interfaces, u32); + break; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): + P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32); + break; + } + + if ( dict_items_parsed != PyDict_Size(payload) ) + { + PyErr_SetString(PyExc_TypeError, "payload contains bad items"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_message_get_payload(PyObject *self, PyObject *args) +{ + xu_message_object *xum = (xu_message_object *)self; + PyObject *dict = NULL; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + switch ( TYPE(xum->msg.type, xum->msg.subtype) ) + { + case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED): + C2P(blkif_fe_interface_status_changed_t, handle, Int, Long); + C2P(blkif_fe_interface_status_changed_t, status, Int, Long); + C2P(blkif_fe_interface_status_changed_t, evtchn, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED): + C2P(blkif_fe_driver_status_changed_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT): + C2P(blkif_fe_interface_connect_t, handle, Int, Long); + C2P(blkif_fe_interface_connect_t, shmem_frame, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_DISCONNECT): + C2P(blkif_fe_interface_disconnect_t, handle, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE): + C2P(blkif_be_create_t, domid, Int, Long); + C2P(blkif_be_create_t, blkif_handle, Int, Long); + C2P(blkif_be_create_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY): + C2P(blkif_be_destroy_t, domid, Int, Long); + C2P(blkif_be_destroy_t, blkif_handle, Int, Long); + C2P(blkif_be_destroy_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT): + C2P(blkif_be_connect_t, domid, Int, Long); + C2P(blkif_be_connect_t, blkif_handle, Int, Long); + C2P(blkif_be_connect_t, shmem_frame, Int, Long); + C2P(blkif_be_connect_t, evtchn, Int, Long); + C2P(blkif_be_connect_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT): + C2P(blkif_be_disconnect_t, domid, Int, Long); + C2P(blkif_be_disconnect_t, blkif_handle, Int, Long); + C2P(blkif_be_disconnect_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE): + C2P(blkif_be_vbd_create_t, domid, Int, Long); + C2P(blkif_be_vbd_create_t, blkif_handle, Int, Long); + C2P(blkif_be_vbd_create_t, vdevice, Int, Long); + C2P(blkif_be_vbd_create_t, readonly, Int, Long); + C2P(blkif_be_vbd_create_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY): + C2P(blkif_be_vbd_destroy_t, domid, Int, Long); + C2P(blkif_be_vbd_destroy_t, blkif_handle, Int, Long); + C2P(blkif_be_vbd_destroy_t, vdevice, Int, Long); + C2P(blkif_be_vbd_destroy_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW): + C2P(blkif_be_vbd_grow_t, domid, Int, Long); + C2P(blkif_be_vbd_grow_t, blkif_handle, Int, Long); + C2P(blkif_be_vbd_grow_t, vdevice, Int, Long); + C2P(blkif_be_vbd_grow_t, extent.sector_start, + Long, UnsignedLongLong); + C2P(blkif_be_vbd_grow_t, extent.sector_length, + Long, UnsignedLongLong); + C2P(blkif_be_vbd_grow_t, extent.device, Int, Long); + C2P(blkif_be_vbd_grow_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK): + C2P(blkif_be_vbd_shrink_t, domid, Int, Long); + C2P(blkif_be_vbd_shrink_t, blkif_handle, Int, Long); + C2P(blkif_be_vbd_shrink_t, vdevice, Int, Long); + C2P(blkif_be_vbd_shrink_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED): + C2P(blkif_be_driver_status_changed_t, status, Int, Long); + return dict; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED): + C2P(netif_fe_interface_status_changed_t, handle, Int, Long); + C2P(netif_fe_interface_status_changed_t, status, Int, Long); + C2P(netif_fe_interface_status_changed_t, evtchn, Int, Long); + return dict; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): + C2P(netif_fe_driver_status_changed_t, status, Int, Long); + C2P(netif_fe_driver_status_changed_t, nr_interfaces, Int, Long); + return dict; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT): + C2P(netif_fe_interface_connect_t, handle, Int, Long); + C2P(netif_fe_interface_connect_t, tx_shmem_frame, Int, Long); + C2P(netif_fe_interface_connect_t, rx_shmem_frame, Int, Long); + return dict; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_DISCONNECT): + C2P(netif_fe_interface_disconnect_t, handle, Int, Long); + return dict; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE): + C2P(netif_be_create_t, domid, Int, Long); + C2P(netif_be_create_t, netif_handle, Int, Long); + C2P(netif_be_create_t, status, Int, Long); + return dict; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY): + C2P(netif_be_destroy_t, domid, Int, Long); + C2P(netif_be_destroy_t, netif_handle, Int, Long); + C2P(netif_be_destroy_t, status, Int, Long); + return dict; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT): + C2P(netif_be_connect_t, domid, Int, Long); + C2P(netif_be_connect_t, netif_handle, Int, Long); + C2P(netif_be_connect_t, tx_shmem_frame, Int, Long); + C2P(netif_be_connect_t, rx_shmem_frame, Int, Long); + C2P(netif_be_connect_t, evtchn, Int, Long); + C2P(netif_be_connect_t, status, Int, Long); + return dict; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT): + C2P(netif_be_disconnect_t, domid, Int, Long); + C2P(netif_be_disconnect_t, netif_handle, Int, Long); + C2P(netif_be_disconnect_t, status, Int, Long); + return dict; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED): + C2P(netif_be_driver_status_changed_t, status, Int, Long); + return dict; + } + + return PyString_FromStringAndSize(xum->msg.msg, xum->msg.length); +} + +static PyObject *xu_message_get_header(PyObject *self, PyObject *args) +{ + xu_message_object *xum = (xu_message_object *)self; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + return Py_BuildValue("{s:i,s:i,s:i}", + "type", xum->msg.type, + "subtype", xum->msg.subtype, + "id", xum->msg.id); +} + +static PyMethodDef xu_message_methods[] = { + { "append_payload", + (PyCFunction)xu_message_append_payload, + METH_VARARGS, + "Append @str to the message payload.\n" }, + + { "set_response_fields", + (PyCFunction)xu_message_set_response_fields, + METH_VARARGS, + "Fill in the response fields in a message that was passed to us.\n" }, + + { "get_payload", + (PyCFunction)xu_message_get_payload, + METH_VARARGS, + "Return the message payload in string form.\n" }, + + { "get_header", + (PyCFunction)xu_message_get_header, + METH_VARARGS, + "Returns a dictionary of values for @type, @subtype, and @id.\n" }, + + { NULL, NULL, 0, NULL } +}; + +staticforward PyTypeObject xu_message_type; + +static PyObject *xu_message_new(PyObject *self, PyObject *args) +{ + xu_message_object *xum; + int type, subtype, id, dict_items_parsed = 0; + PyObject *payload = NULL; + + if ( !PyArg_ParseTuple(args, "iii|O", &type, &subtype, &id, &payload) ) + return NULL; + + xum = PyObject_New(xu_message_object, &xu_message_type); + + xum->msg.type = type; + xum->msg.subtype = subtype; + xum->msg.id = id; + xum->msg.length = 0; + + if ( payload == NULL ) + return (PyObject *)xum; + + if ( !PyDict_Check(payload) ) + { + PyErr_SetString(PyExc_TypeError, "payload is not a dictionary"); + PyObject_Del((PyObject *)xum); + return NULL; + } + + switch ( TYPE(type, subtype) ) + { + case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED): + P2C(blkif_fe_interface_status_changed_t, handle, u32); + P2C(blkif_fe_interface_status_changed_t, status, u32); + P2C(blkif_fe_interface_status_changed_t, evtchn, u16); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE): + P2C(blkif_be_create_t, domid, u32); + P2C(blkif_be_create_t, blkif_handle, u32); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY): + P2C(blkif_be_destroy_t, domid, u32); + P2C(blkif_be_destroy_t, blkif_handle, u32); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT): + P2C(blkif_be_connect_t, domid, u32); + P2C(blkif_be_connect_t, blkif_handle, u32); + P2C(blkif_be_connect_t, shmem_frame, memory_t); + P2C(blkif_be_connect_t, evtchn, u16); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT): + P2C(blkif_be_disconnect_t, domid, u32); + P2C(blkif_be_disconnect_t, blkif_handle, u32); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE): + P2C(blkif_be_vbd_create_t, domid, u32); + P2C(blkif_be_vbd_create_t, blkif_handle, u32); + P2C(blkif_be_vbd_create_t, vdevice, blkif_vdev_t); + P2C(blkif_be_vbd_create_t, readonly, u16); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY): + P2C(blkif_be_vbd_destroy_t, domid, u32); + P2C(blkif_be_vbd_destroy_t, blkif_handle, u32); + P2C(blkif_be_vbd_destroy_t, vdevice, blkif_vdev_t); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW): + P2C(blkif_be_vbd_grow_t, domid, u32); + P2C(blkif_be_vbd_grow_t, blkif_handle, u32); + P2C(blkif_be_vbd_grow_t, vdevice, blkif_vdev_t); + P2C(blkif_be_vbd_grow_t, extent.sector_start, blkif_sector_t); + P2C(blkif_be_vbd_grow_t, extent.sector_length, blkif_sector_t); + P2C(blkif_be_vbd_grow_t, extent.device, blkif_pdev_t); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK): + P2C(blkif_be_vbd_shrink_t, domid, u32); + P2C(blkif_be_vbd_shrink_t, blkif_handle, u32); + P2C(blkif_be_vbd_shrink_t, vdevice, blkif_vdev_t); + break; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED): + P2C(netif_fe_interface_status_changed_t, handle, u32); + P2C(netif_fe_interface_status_changed_t, status, u32); + P2C(netif_fe_interface_status_changed_t, evtchn, u16); + P2C(netif_fe_interface_status_changed_t, mac[0], u8); + P2C(netif_fe_interface_status_changed_t, mac[1], u8); + P2C(netif_fe_interface_status_changed_t, mac[2], u8); + P2C(netif_fe_interface_status_changed_t, mac[3], u8); + P2C(netif_fe_interface_status_changed_t, mac[4], u8); + P2C(netif_fe_interface_status_changed_t, mac[5], u8); + break; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE): + P2C(netif_be_create_t, domid, u32); + P2C(netif_be_create_t, netif_handle, u32); + P2C(netif_be_create_t, mac[0], u8); + P2C(netif_be_create_t, mac[1], u8); + P2C(netif_be_create_t, mac[2], u8); + P2C(netif_be_create_t, mac[3], u8); + P2C(netif_be_create_t, mac[4], u8); + P2C(netif_be_create_t, mac[5], u8); + break; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY): + P2C(netif_be_destroy_t, domid, u32); + P2C(netif_be_destroy_t, netif_handle, u32); + break; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT): + P2C(netif_be_connect_t, domid, u32); + P2C(netif_be_connect_t, netif_handle, u32); + P2C(netif_be_connect_t, tx_shmem_frame, memory_t); + P2C(netif_be_connect_t, rx_shmem_frame, memory_t); + P2C(netif_be_connect_t, evtchn, u16); + break; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT): + P2C(netif_be_disconnect_t, domid, u32); + P2C(netif_be_disconnect_t, netif_handle, u32); + break; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): + P2C(netif_fe_driver_status_changed_t, status, u32); + P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32); + break; + } + + if ( dict_items_parsed != PyDict_Size(payload) ) + { + PyErr_SetString(PyExc_TypeError, "payload contains bad items"); + PyObject_Del((PyObject *)xum); + return NULL; + } + + return (PyObject *)xum; +} + +static PyObject *xu_message_getattr(PyObject *obj, char *name) +{ + xu_message_object *xum; + if ( strcmp(name, "MAX_PAYLOAD") == 0 ) + return PyInt_FromLong(sizeof(xum->msg.msg)); + return Py_FindMethod(xu_message_methods, obj, name); +} + +static void xu_message_dealloc(PyObject *self) +{ + PyObject_Del(self); +} + +static PyTypeObject xu_message_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "message", + sizeof(xu_message_object), + 0, + xu_message_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + xu_message_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + + + +/* + * *********************** PORT *********************** + */ + +static control_if_t *map_control_interface(int fd, unsigned long pfn) +{ + char *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, + MAP_SHARED, fd, pfn * PAGE_SIZE); + if ( vaddr == MAP_FAILED ) + return NULL; + return (control_if_t *)(vaddr + 2048); +} +static void unmap_control_interface(int fd, control_if_t *c) +{ + char *vaddr = (char *)c - 2048; + (void)munmap(vaddr, PAGE_SIZE); +} + +typedef struct xu_port_object { + PyObject_HEAD; + int mem_fd; + int xc_handle; + u32 remote_dom; + int local_port, remote_port; + control_if_t *interface; + CONTROL_RING_IDX tx_req_cons, tx_resp_prod; + CONTROL_RING_IDX rx_req_prod, rx_resp_cons; +} xu_port_object; + +static PyObject *port_error; + +static int xup_connect(xu_port_object *xup, domid_t dom, + int local_port, int remote_port){ + // From our prespective rx = producer, tx = consumer. + int err = 0; + printf("%s> dom=%u %d:%d\n", __FUNCTION__, (unsigned int)dom, + local_port, remote_port); + + // Consumer = tx. + //xup->interface->tx_resp_prod = 0; + //xup->interface->tx_req_prod = 0; + xup->tx_resp_prod = xup->interface->tx_resp_prod; + xup->tx_req_cons = xup->interface->tx_resp_prod; + printf("%s> tx: %u %u : %u %u\n", __FUNCTION__, + (unsigned int)xup->interface->tx_resp_prod, + (unsigned int)xup->tx_resp_prod, + (unsigned int)xup->tx_req_cons, + (unsigned int)xup->interface->tx_req_prod); + + // Producer = rx. + //xup->interface->rx_req_prod = 0; + //xup->interface->rx_resp_prod = 0; + xup->rx_req_prod = xup->interface->rx_req_prod; + xup->rx_resp_cons = xup->interface->rx_resp_prod; + printf("%s> rx: %u %u : %u %u\n", __FUNCTION__, + (unsigned int)xup->rx_resp_cons, + (unsigned int)xup->interface->rx_resp_prod, + (unsigned int)xup->interface->rx_req_prod, + (unsigned int)xup->rx_req_prod); + + xup->remote_dom = dom; + xup->local_port = local_port; + xup->remote_port = remote_port; + + printf("%s< err=%d\n", __FUNCTION__, err); + return err; +} + +static PyObject *xu_port_notify(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + (void)xc_evtchn_send(xup->xc_handle, xup->local_port); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_port_read_request(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + xu_message_object *xum; + CONTROL_RING_IDX c = xup->tx_req_cons; + control_if_t *cif = xup->interface; + control_msg_t *cmsg; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( (c == cif->tx_req_prod) || + ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) ) + { + PyErr_SetString(port_error, "no request to read"); + return NULL; + } + + cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)]; + xum = PyObject_New(xu_message_object, &xu_message_type); + memcpy(&xum->msg, cmsg, sizeof(*cmsg)); + if ( xum->msg.length > sizeof(xum->msg.msg) ) + xum->msg.length = sizeof(xum->msg.msg); + xup->tx_req_cons++; + return (PyObject *)xum; +} + +static PyObject *xu_port_write_request(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + xu_message_object *xum; + CONTROL_RING_IDX p = xup->rx_req_prod; + control_if_t *cif = xup->interface; + control_msg_t *cmsg; + + if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) ) + return NULL; + + if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) ) + { + PyErr_SetString(PyExc_TypeError, "expected a " XENPKG ".message"); + return NULL; + } + + if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) ) + { + PyErr_SetString(port_error, "no space to write request"); + return NULL; + } + + cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)]; + memcpy(cmsg, &xum->msg, sizeof(*cmsg)); + + xup->rx_req_prod = cif->rx_req_prod = p + 1; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_port_read_response(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + xu_message_object *xum; + CONTROL_RING_IDX c = xup->rx_resp_cons; + control_if_t *cif = xup->interface; + control_msg_t *cmsg; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) ) + { + PyErr_SetString(port_error, "no response to read"); + return NULL; + } + + cmsg = &cif->rx_ring[MASK_CONTROL_IDX(c)]; + xum = PyObject_New(xu_message_object, &xu_message_type); + memcpy(&xum->msg, cmsg, sizeof(*cmsg)); + if ( xum->msg.length > sizeof(xum->msg.msg) ) + xum->msg.length = sizeof(xum->msg.msg); + xup->rx_resp_cons++; + return (PyObject *)xum; +} + +static PyObject *xu_port_write_response(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + xu_message_object *xum; + CONTROL_RING_IDX p = xup->tx_resp_prod; + control_if_t *cif = xup->interface; + control_msg_t *cmsg; + + if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) ) + return NULL; + + if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) ) + { + PyErr_SetString(PyExc_TypeError, "expected a " XENPKG ".message"); + return NULL; + } + + if ( p == xup->tx_req_cons ) + { + PyErr_SetString(port_error, "no space to write response"); + return NULL; + } + + cmsg = &cif->tx_ring[MASK_CONTROL_IDX(p)]; + memcpy(cmsg, &xum->msg, sizeof(*cmsg)); + + xup->tx_resp_prod = cif->tx_resp_prod = p + 1; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_port_request_to_read(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + CONTROL_RING_IDX c = xup->tx_req_cons; + control_if_t *cif = xup->interface; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( (c == cif->tx_req_prod) || + ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) ) + return PyInt_FromLong(0); + + return PyInt_FromLong(1); +} + +static PyObject *xu_port_space_to_write_request(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + CONTROL_RING_IDX p = xup->rx_req_prod; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) ) + return PyInt_FromLong(0); + + return PyInt_FromLong(1); +} + +static PyObject *xu_port_response_to_read(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + CONTROL_RING_IDX c = xup->rx_resp_cons; + control_if_t *cif = xup->interface; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) ) + return PyInt_FromLong(0); + + return PyInt_FromLong(1); +} + +static PyObject *xu_port_space_to_write_response( + PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + CONTROL_RING_IDX p = xup->tx_resp_prod; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( p == xup->tx_req_cons ) + return PyInt_FromLong(0); + + return PyInt_FromLong(1); +} + +static PyMethodDef xu_port_methods[] = { + { "notify", + (PyCFunction)xu_port_notify, + METH_VARARGS, + "Send a notification to the remote end.\n" }, + + { "read_request", + (PyCFunction)xu_port_read_request, + METH_VARARGS, + "Read a request message from the control interface.\n" }, + + { "write_request", + (PyCFunction)xu_port_write_request, + METH_VARARGS, + "Write a request message to the control interface.\n" }, + + { "read_response", + (PyCFunction)xu_port_read_response, + METH_VARARGS, + "Read a response message from the control interface.\n" }, + + { "write_response", + (PyCFunction)xu_port_write_response, + METH_VARARGS, + "Write a response message to the control interface.\n" }, + + { "request_to_read", + (PyCFunction)xu_port_request_to_read, + METH_VARARGS, + "Returns TRUE if there is a request message to read.\n" }, + + { "space_to_write_request", + (PyCFunction)xu_port_space_to_write_request, + METH_VARARGS, + "Returns TRUE if there is space to write a request message.\n" }, + + { "response_to_read", + (PyCFunction)xu_port_response_to_read, + METH_VARARGS, + "Returns TRUE if there is a response message to read.\n" }, + + { "space_to_write_response", + (PyCFunction)xu_port_space_to_write_response, + METH_VARARGS, + "Returns TRUE if there is space to write a response message.\n" }, + + { NULL, NULL, 0, NULL } +}; + +staticforward PyTypeObject xu_port_type; + +static PyObject *xu_port_new(PyObject *self, PyObject *args) +{ + xu_port_object *xup; + u32 dom; + int port1, port2; + xc_dominfo_t info; + + if ( !PyArg_ParseTuple(args, "i", &dom) ) + return NULL; + + xup = PyObject_New(xu_port_object, &xu_port_type); + + if ( (xup->mem_fd = open("/dev/mem", O_RDWR)) == -1 ) + { + PyErr_SetString(port_error, "Could not open '/dev/mem'"); + goto fail1; + } + + /* Set the General-Purpose Subject whose page frame will be mapped. */ + (void)ioctl(xup->mem_fd, _IO('M', 1), (unsigned long)dom); + + if ( (xup->xc_handle = xc_interface_open()) == -1 ) + { + PyErr_SetString(port_error, "Could not open Xen control interface"); + goto fail2; + } + + if ( dom == 0 ) + { + /* + * The control-interface event channel for DOM0 is already set up. + * We use an ioctl to discover the port at our end of the channel. + */ + port1 = ioctl(xup->xc_handle, IOCTL_PRIVCMD_INITDOMAIN_EVTCHN, NULL); + port2 = -1; /* We don't need the remote end of the DOM0 link. */ + if ( port1 < 0 ) + { + PyErr_SetString(port_error, "Could not open channel to DOM0"); + goto fail3; + } + } + else if ( xc_evtchn_bind_interdomain(xup->xc_handle, + DOMID_SELF, dom, + &port1, &port2) != 0 ) + { + PyErr_SetString(port_error, "Could not open channel to domain"); + goto fail3; + } + + if ( (xc_domain_getinfo(xup->xc_handle, dom, 1, &info) != 1) || + (info.domid != dom) ) + { + PyErr_SetString(port_error, "Failed to obtain domain status"); + goto fail4; + } + + xup->interface = + map_control_interface(xup->mem_fd, info.shared_info_frame); + if ( xup->interface == NULL ) + { + PyErr_SetString(port_error, "Failed to map domain control interface"); + goto fail4; + } + + xup_connect(xup, dom, port1, port2); + return (PyObject *)xup; + + + fail4: + (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, port1); + fail3: + (void)xc_interface_close(xup->xc_handle); + fail2: + (void)close(xup->mem_fd); + fail1: + PyObject_Del((PyObject *)xup); + return NULL; +} + +static PyObject *xu_port_getattr(PyObject *obj, char *name) +{ + xu_port_object *xup = (xu_port_object *)obj; + if ( strcmp(name, "local_port") == 0 ) + return PyInt_FromLong(xup->local_port); + if ( strcmp(name, "remote_port") == 0 ) + return PyInt_FromLong(xup->remote_port); + if ( strcmp(name, "remote_dom") == 0 ) + return PyInt_FromLong(xup->remote_dom); + return Py_FindMethod(xu_port_methods, obj, name); +} + +static void xu_port_dealloc(PyObject *self) +{ + xu_port_object *xup = (xu_port_object *)self; + unmap_control_interface(xup->mem_fd, xup->interface); + if ( xup->remote_dom != 0 ) + (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, xup->local_port); + (void)xc_interface_close(xup->xc_handle); + (void)close(xup->mem_fd); + PyObject_Del(self); +} + +static PyTypeObject xu_port_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "port", + sizeof(xu_port_object), + 0, + xu_port_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + xu_port_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + + + +/* + * *********************** BUFFER *********************** + */ + +#define BUFSZ 65536 +#define MASK_BUF_IDX(_i) ((_i)&(BUFSZ-1)) +typedef unsigned int BUF_IDX; + +typedef struct { + PyObject_HEAD; + char *buf; + unsigned int prod, cons; +} xu_buffer_object; + +static PyObject *__xu_buffer_peek(xu_buffer_object *xub, int max) +{ + PyObject *str1, *str2; + int len1, len2, c = MASK_BUF_IDX(xub->cons); + + len1 = xub->prod - xub->cons; + if ( len1 > (BUFSZ - c) ) /* clip to ring wrap */ + len1 = BUFSZ - c; + if ( len1 > max ) /* clip to specified maximum */ + len1 = max; + if ( len1 < 0 ) /* sanity */ + len1 = 0; + + if ( (str1 = PyString_FromStringAndSize(&xub->buf[c], len1)) == NULL ) + return NULL; + + if ( (len1 < (xub->prod - xub->cons)) && (len1 < max) ) + { + len2 = max - len1; + if ( len2 > MASK_BUF_IDX(xub->prod) ) + len2 = MASK_BUF_IDX(xub->prod); + if ( len2 > 0 ) + { + str2 = PyString_FromStringAndSize(&xub->buf[0], len2); + if ( str2 == NULL ) + return NULL; + PyString_ConcatAndDel(&str1, str2); + if ( str1 == NULL ) + return NULL; + } + } + + return str1; +} + +static PyObject *xu_buffer_peek(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + int max = 1024; + + if ( !PyArg_ParseTuple(args, "|i", &max) ) + return NULL; + + return __xu_buffer_peek(xub, max); +} + +static PyObject *xu_buffer_read(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + PyObject *str; + int max = 1024; + + if ( !PyArg_ParseTuple(args, "|i", &max) ) + return NULL; + + if ( (str = __xu_buffer_peek(xub, max)) != NULL ) + xub->cons += PyString_Size(str); + + return str; +} + +static PyObject *xu_buffer_discard(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + int max, len; + + if ( !PyArg_ParseTuple(args, "i", &max) ) + return NULL; + + len = xub->prod - xub->cons; + if ( len > max ) + len = max; + if ( len < 0 ) + len = 0; + + xub->cons += len; + + return PyInt_FromLong(len); +} + +static PyObject *xu_buffer_write(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + char *str; + int len, len1, len2; + + if ( !PyArg_ParseTuple(args, "s#", &str, &len) ) + return NULL; + + len1 = len; + if ( len1 > (BUFSZ - MASK_BUF_IDX(xub->prod)) ) + len1 = BUFSZ - MASK_BUF_IDX(xub->prod); + if ( len1 > (BUFSZ - (xub->prod - xub->cons)) ) + len1 = BUFSZ - (xub->prod - xub->cons); + + if ( len1 == 0 ) + return PyInt_FromLong(0); + + memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[0], len1); + xub->prod += len1; + + if ( len1 < len ) + { + len2 = len - len1; + if ( len2 > (BUFSZ - MASK_BUF_IDX(xub->prod)) ) + len2 = BUFSZ - MASK_BUF_IDX(xub->prod); + if ( len2 > (BUFSZ - (xub->prod - xub->cons)) ) + len2 = BUFSZ - (xub->prod - xub->cons); + if ( len2 != 0 ) + { + memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[len1], len2); + xub->prod += len2; + return PyInt_FromLong(len1 + len2); + } + } + + return PyInt_FromLong(len1); +} + +static PyObject *xu_buffer_empty(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( xub->cons == xub->prod ) + return PyInt_FromLong(1); + + return PyInt_FromLong(0); +} + +static PyObject *xu_buffer_full(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( (xub->prod - xub->cons) == BUFSZ ) + return PyInt_FromLong(1); + + return PyInt_FromLong(0); +} + +static PyMethodDef xu_buffer_methods[] = { + { "peek", + (PyCFunction)xu_buffer_peek, + METH_VARARGS, + "Peek up to @max bytes from the buffer. Returns a string.\n" }, + + { "read", + (PyCFunction)xu_buffer_read, + METH_VARARGS, + "Read up to @max bytes from the buffer. Returns a string.\n" }, + + { "discard", + (PyCFunction)xu_buffer_discard, + METH_VARARGS, + "Discard up to @max bytes from the buffer. Returns number of bytes.\n" }, + + { "write", + (PyCFunction)xu_buffer_write, + METH_VARARGS, + "Write @string into buffer. Return number of bytes written.\n" }, + + { "empty", + (PyCFunction)xu_buffer_empty, + METH_VARARGS, + "Return TRUE if the buffer is empty.\n" }, + + { "full", + (PyCFunction)xu_buffer_full, + METH_VARARGS, + "Return TRUE if the buffer is full.\n" }, + + { NULL, NULL, 0, NULL } +}; + +staticforward PyTypeObject xu_buffer_type; + +static PyObject *xu_buffer_new(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + xub = PyObject_New(xu_buffer_object, &xu_buffer_type); + + if ( (xub->buf = malloc(BUFSZ)) == NULL ) + { + PyObject_Del((PyObject *)xub); + return NULL; + } + + xub->prod = xub->cons = 0; + + return (PyObject *)xub; +} + +static PyObject *xu_buffer_getattr(PyObject *obj, char *name) +{ + return Py_FindMethod(xu_buffer_methods, obj, name); +} + +static void xu_buffer_dealloc(PyObject *self) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + free(xub->buf); + PyObject_Del(self); +} + +static PyTypeObject xu_buffer_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "buffer", + sizeof(xu_buffer_object), + 0, + xu_buffer_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + xu_buffer_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + + + +/* + * *********************** MODULE WRAPPER *********************** + */ + +static void handle_child_death(int dummy) +{ + while ( waitpid(-1, NULL, WNOHANG) > 0 ) + continue; +} + +static PyObject *xu_autoreap(PyObject *self, PyObject *args) +{ + struct sigaction sa; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handle_child_death; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; + (void)sigaction(SIGCHLD, &sa, NULL); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef xu_methods[] = { + { "notifier", xu_notifier_new, METH_VARARGS, + "Create a new notifier." }, + { "message", xu_message_new, METH_VARARGS, + "Create a new communications message." }, + { "port", xu_port_new, METH_VARARGS, + "Create a new communications port." }, + { "buffer", xu_buffer_new, METH_VARARGS, + "Create a new ring buffer." }, + { "autoreap", xu_autoreap, METH_VARARGS, + "Ensure that zombie children are automatically reaped by the OS." }, + { NULL, NULL, 0, NULL } +}; + +PyMODINIT_FUNC initxu(void) +{ + PyObject *m, *d; + + m = Py_InitModule(XENPKG, xu_methods); + + d = PyModule_GetDict(m); + port_error = PyErr_NewException(XENPKG ".PortError", NULL, NULL); + PyDict_SetItemString(d, "PortError", port_error); +} diff --git a/tools/python/xen/xend/XendConsole.py b/tools/python/xen/xend/XendConsole.py index 4420c388f2..440b627562 100644 --- a/tools/python/xen/xend/XendConsole.py +++ b/tools/python/xen/xend/XendConsole.py @@ -1,8 +1,8 @@ # Copyright (C) 2004 Mike Wray import socket -import xen.ext.xc -xc = xen.ext.xc.new() +import xen.lowlevel.xc +xc = xen.lowlevel.xc.new() import sxp import XendRoot diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 3aaf080c36..328450a6b5 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -8,7 +8,7 @@ import sys from twisted.internet import defer -import xen.ext.xc; xc = xen.ext.xc.new() +import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() import sxp import XendRoot @@ -36,7 +36,6 @@ class XendDomain: self.xconsole = XendConsole.instance() # Table of domain info indexed by domain id. self.db = XendDB.XendDB(self.dbpath) - #self.domain = {} self.domain_db = self.db.fetchall("") if xroot.get_rebooted(): print 'XendDomain> rebooted: removing all domain info' @@ -45,6 +44,8 @@ class XendDomain: self.initial_refresh() def onVirq(self, event, val): + """Event handler for virq. + """ print 'XendDomain> virq', val self.reap() @@ -102,28 +103,12 @@ class XendDomain: def _new_domain(self, savedinfo, info): """Create a domain entry from saved info. + + savedinfo saved info from the db + info domain info from xen + + returns deferred """ -## console = None -## kernel = None -## id = sxp.child_value(info, 'id') -## dom = int(id) -## name = sxp.child_value(info, 'name') -## memory = int(sxp.child_value(info, 'memory')) -## consoleinfo = sxp.child(info, 'console') -## if consoleinfo: -## consoleid = sxp.child_value(consoleinfo, 'id') -## console = self.xconsole.console_get(consoleid) -## if dom and console is None: -## # Try to connect a console. -## console = self.xconsole.console_create(dom) -## config = sxp.child(info, 'config') -## if config: -## image = sxp.child(info, 'image') -## if image: -## image = sxp.child0(image) -## kernel = sxp.child_value(image, 'kernel') -## dominfo = XendDomainInfo.XendDomainInfo( -## config, dom, name, memory, kernel, console) config = sxp.child_value(savedinfo, 'config') deferred = XendDomainInfo.vm_recreate(config, info) def fn(dominfo): @@ -132,12 +117,23 @@ class XendDomain: return deferred def _add_domain(self, id, info, notify=1): + """Add a domain entry to the tables. + + id domain id + info domain info object + notify send a domain created event if true + """ self.domain[id] = info self.domain_db[id] = info.sxpr() self.sync_domain(id) if notify: eserver.inject('xend.domain.created', id) def _delete_domain(self, id, notify=1): + """Remove a domain from the tables. + + id domain id + notify send a domain died event if true + """ if id in self.domain: if notify: eserver.inject('xend.domain.died', id) del self.domain[id] @@ -146,14 +142,13 @@ class XendDomain: self.db.delete(id) def reap(self): - """Go through the domains looking for ones that have crashed or stopped. + """Look for domains that have crashed or stopped. Tidy them up. """ print 'XendDomain>reap>' domlist = xc.domain_getinfo() casualties = [] for d in domlist: - #print 'dom', d dead = 0 dead = dead or (d['crashed'] or d['shutdown']) dead = dead or (d['dying'] and @@ -163,9 +158,6 @@ class XendDomain: for d in casualties: id = str(d['dom']) print 'XendDomain>reap> died id=', id, d - dominfo = self.domain.get(id) - if not dominfo: continue - dominfo.died() self.domain_destroy(id, refresh=0) print 'XendDomain>reap<' @@ -181,9 +173,6 @@ class XendDomain: doms[id] = d if id not in self.domain: config = None - #image = None - #newinfo = XendDomainInfo.XendDomainInfo( - # config, d['dom'], d['name'], d['mem_kb']/1024, image=image, info=d) deferred = XendDomainInfo.vm_recreate(config, d) def fn(dominfo): self._add_domain(dominfo.id, dominfo) @@ -198,6 +187,10 @@ class XendDomain: self.reap() def refresh_domain(self, id): + """Refresh information for a single domain. + + id domain id + """ dom = int(id) dominfo = xc.domain_getinfo(dom, 1) if dominfo == [] or dominfo[0]['dom'] != dom: @@ -213,17 +206,28 @@ class XendDomain: d.update(dominfo[0]) def domain_ls(self): - # List domains. - # Update info from kernel first. + """Get list of domain ids. + + return domain ids + """ self.refresh() return self.domain.keys() def domains(self): + """Get list of domain objects. + + return domain objects + """ self.refresh() return self.domain.values() def domain_create(self, config): - # Create domain, log it. + """Create a domain from a configuration. + + config configuration + + returns deferred + """ deferred = XendDomainInfo.vm_create(config) def fn(dominfo): self._add_domain(dominfo.id, dominfo) @@ -232,12 +236,19 @@ class XendDomain: return deferred def domain_get(self, id): + """Get up-to-date info about a domain. + + id domain id + returns domain object (or None) + """ id = str(id) self.refresh_domain(id) return self.domain.get(id) def domain_unpause(self, id): - """(Re)start domain running. + """Unpause domain execution. + + id domain id """ dom = int(id) eserver.inject('xend.domain.unpause', id) @@ -245,6 +256,8 @@ class XendDomain: def domain_pause(self, id): """Pause domain execution. + + id domain id """ dom = int(id) eserver.inject('xend.domain.pause', id) @@ -252,6 +265,9 @@ class XendDomain: def domain_shutdown(self, id, reason='poweroff'): """Shutdown domain (nicely). + + id domain id + reason shutdown type: poweroff, reboot, halt """ dom = int(id) if dom <= 0: @@ -263,23 +279,37 @@ class XendDomain: def domain_destroy(self, id, refresh=1): """Terminate domain immediately. + + id domain id + refresh send a domain destroy event if true """ dom = int(id) if dom <= 0: return 0 eserver.inject('xend.domain.destroy', id) - val = xc.domain_destroy(dom=dom) + dominfo = self.domain.get(id) + if dominfo: + val = dominfo.destroy() + else: + val = xc.domain_destroy(dom=dom) if refresh: self.refresh() return val def domain_migrate(self, id, dst): """Start domain migration. + + id domain id """ # Need a cancel too? pass def domain_save(self, id, dst, progress=0): - """Save domain state to file, destroy domain. + """Save domain state to file, destroy domain on success. + Leave domain running on error. + + id domain id + dst destination file + progress output progress if true """ dom = int(id) dominfo = self.domain_get(id) @@ -288,79 +318,140 @@ class XendDomain: vmconfig = sxp.to_string(dominfo.sxpr()) self.domain_pause(id) eserver.inject('xend.domain.save', id) - rc = xc.linux_save(dom=dom, state_file=dst, vmconfig=vmconfig, progress=progress) + try: + rc = xc.linux_save(dom=dom, state_file=dst, + vmconfig=vmconfig, progress=progress) + except: + rc = -1 if rc == 0: self.domain_destroy(id) + else: + self.domain_unpause(id) return rc def domain_restore(self, src, progress=0): """Restore domain from file. + + src source file + progress output progress if true + + returns domain object """ dominfo = XendDomainInfo.vm_restore(src, progress=progress) self._add_domain(dominfo.id, dominfo) return dominfo - #============================================================================ - # Backward compatibility stuff from here on. - def domain_pincpu(self, dom, cpu): + """Pin a domain to a cpu. + + dom domain + cpu cpu number + """ dom = int(dom) return xc.domain_pincpu(dom, cpu) def domain_cpu_bvt_set(self, dom, mcuadv, warp, warpl, warpu): + """Set BVT (Borrowed Virtual Time) scheduler parameters for a domain. + """ dom = int(dom) return xc.bvtsched_domain_set(dom=dom, mcuadv=mcuadv, warp=warp, warpl=warpl, warpu=warpu) def domain_cpu_bvt_get(self, dom): + """Get BVT (Borrowed Virtual Time) scheduler parameters for a domain. + """ dom = int(dom) return xc.bvtsched_domain_get(dom) def domain_cpu_atropos_set(self, dom, period, slice, latency, xtratime): + """Set Atropos scheduler parameters for a domain. + """ dom = int(dom) return xc.atropos_domain_set(dom, period, slice, latency, xtratime) def domain_cpu_atropos_get(self, dom): + """Get Atropos scheduler parameters for a domain. + """ dom = int(dom) return xc.atropos_domain_get(dom) - def domain_vif_ls(self, dom): + def domain_devtype_ls(self, dom, type): + """Get list of device indexes for a domain. + + dom domain + type device type + + returns device indexes + """ dominfo = self.domain_get(dom) if not dominfo: return None - devs = dominfo.get_devices('vif') + devs = dominfo.get_devices(type) return range(0, len(devs)) - def domain_vif_get(self, dom, vif): + def domain_devtype_get(self, dom, type, idx): + """Get a device from a domain. + + dom domain + type device type + idx device index + + returns device object (or None) + """ dominfo = self.domain_get(dom) if not dominfo: return None - return dominfo.get_device_by_index(vif) + return dominfo.get_device_by_index(type, idx) + + def domain_vif_ls(self, dom): + """Get list of virtual network interface (vif) indexes for a domain. + + dom domain + + returns vif indexes + """ + return self.domain_devtype_ls(dom, 'vif') -## def domain_vif_ip_add(self, dom, vif, ip): -## dom = int(dom) -## return xenctl.ip.setup_vfr_rules_for_vif(dom, vif, ip) + def domain_vif_get(self, dom, vif): + """Get a virtual network interface (vif) from a domain. + + dom domain + vif vif index + + returns vif device object (or None) + """ + return self.domain_devtype_get(dom, 'vif', vif) def domain_vbd_ls(self, dom): - dominfo = self.domain_get(dom) - if not dominfo: return [] - devs = dominfo.get_devices('vbd') - return [ sxp.child_value(v, 'dev') for v in devs ] + """Get list of virtual block device (vbd) indexes for a domain. + + dom domain + + returns vbd indexes + """ + return self.domain_devtype_ls(dom, 'vbd') def domain_vbd_get(self, dom, vbd): - dominfo = self.domain_get(dom) - if not dominfo: return None - devs = dominfo.get_devices('vbd') - for v in devs: - if sxp.child_value(v, 'dev') == vbd: - return v - return None + """Get a virtual block device (vbd) from a domain. + + dom domain + vbd vbd index + + returns vbd device (or None) + """ + return self.domain_devtype_get(dom, 'vbd', vbd) def domain_shadow_control(self, dom, op): + """Shadow page control. + + dom domain + op operation + """ dom = int(dom) return xc.shadow_control(dom, op) - #============================================================================ def instance(): + """Singleton constructor. Use this instead of the class constructor. + """ global inst try: inst diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index a7e5aa3b2f..c43dcfe892 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -1,4 +1,3 @@ -#!/usr/bin/python # Copyright (C) 2004 Mike Wray """Representation of a single domain. @@ -16,7 +15,7 @@ import os from twisted.internet import defer -import xen.ext.xc; xc = xen.ext.xc.new() +import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() import xen.util.ip import sxp @@ -333,6 +332,9 @@ def _vm_configure2(val, vm): class XendDomainInfo: """Virtual machine object.""" + STATE_OK = "ok" + STATE_TERMINATED = "terminated" + def __init__(self): self.recreate = 0 self.config = None @@ -351,7 +353,7 @@ class XendDomainInfo: self.blkif_backend = 0 self.netif_backend = 0 #todo: state: running, suspended - self.state = 'running' + self.state = self.STATE_OK #todo: set to migrate info if migrating self.migrate = None @@ -490,21 +492,42 @@ class XendDomainInfo: self.configs.append(val) def destroy(self): - if self.dom <= 0: - return 0 + """Completely destroy the vm. + """ + self.cleanup() + return self.destroy_domain() + + def destroy_domain(self): + """Destroy the vm's domain. + The domain will not finally go away unless all vm + devices have been released. + """ + if self.dom is None: return 0 return xc.domain_destroy(dom=self.dom) - def died(self): - print 'died>', self.dom + def cleanup(self): + """Cleanup vm resources: release devices. + """ + print 'cleanup>', self.dom + self.state = self.STATE_TERMINATED self.release_devices() + def is_terminated(self): + """Check if a domain has been terminated. + """ + return self.state == self.STATE_TERMINATED + def release_devices(self): + """Release all vm devices. + """ print 'release_devices>', self.dom self.release_vifs() self.release_vbds() self.devices = {} def release_vifs(self): + """Release vm virtual network devices (vifs). + """ print 'release_vifs>', self.dom if self.dom is None: return ctrl = xend.netif_get(self.dom) @@ -512,6 +535,8 @@ class XendDomainInfo: ctrl.destroy() def release_vbds(self): + """Release vm virtual block devices (vbds). + """ print 'release_vbds>', self.dom if self.dom is None: return ctrl = xend.blkif_get(self.dom) diff --git a/tools/python/xen/xend/XendNode.py b/tools/python/xen/xend/XendNode.py index 7221785aff..27ea8ef187 100644 --- a/tools/python/xen/xend/XendNode.py +++ b/tools/python/xen/xend/XendNode.py @@ -8,12 +8,12 @@ """ import os -import xen.ext.xc +import xen.lowlevel.xc class XendNode: def __init__(self): - self.xc = xen.ext.xc.new() + self.xc = xen.lowlevel.xc.new() def shutdown(self): return 0 diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index c8284dc485..31ace1b84e 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -23,7 +23,7 @@ from twisted.internet import protocol from twisted.internet import abstract from twisted.internet import defer -from xen.ext import xu +from xen.lowlevel import xu from xen.xend import sxp from xen.xend import PrettyPrint diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py index be98a37fd5..d68f84fa37 100755 --- a/tools/python/xen/xend/server/channel.py +++ b/tools/python/xen/xend/server/channel.py @@ -1,5 +1,5 @@ -import xen.ext.xc; xc = xen.ext.xc.new() -from xen.ext import xu +import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() +from xen.lowlevel import xu from messages import msgTypeName VIRQ_MISDIRECT = 0 # Catch-all interrupt for unbound VIRQs. diff --git a/tools/python/xen/xend/server/console.py b/tools/python/xen/xend/server/console.py index ab8b22e41e..3227dc1b5e 100755 --- a/tools/python/xen/xend/server/console.py +++ b/tools/python/xen/xend/server/console.py @@ -3,7 +3,7 @@ from twisted.internet import reactor from twisted.internet import protocol from twisted.protocols import telnet -from xen.ext import xu +from xen.lowlevel import xu from xen.xend import EventServer eserver = EventServer.instance() diff --git a/tools/python/xen/xend/server/messages.py b/tools/python/xen/xend/server/messages.py index e12d7b6e24..f3257ca832 100644 --- a/tools/python/xen/xend/server/messages.py +++ b/tools/python/xen/xend/server/messages.py @@ -1,6 +1,6 @@ import struct -from xen.ext import xu +from xen.lowlevel import xu DEBUG = 0