/*
* Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; If not, see .
*/
package xenlight
/*
#cgo LDFLAGS: -lxenlight -lyajl -lxentoollog
#include
#include
*/
import "C"
/*
* Other flags that may be needed at some point:
* -lnl-route-3 -lnl-3
*
* To get back to static linking:
* #cgo LDFLAGS: -lxenlight -lyajl_s -lxengnttab -lxenstore -lxenguest -lxentoollog -lxenevtchn -lxenctrl -lblktapctl -lxenforeignmemory -lxencall -lz -luuid -lutil
*/
import (
"fmt"
"time"
"unsafe"
)
/*
* Errors
*/
type Error int
const (
ErrorNonspecific = Error(-C.ERROR_NONSPECIFIC)
ErrorVersion = Error(-C.ERROR_VERSION)
ErrorFail = Error(-C.ERROR_FAIL)
ErrorNi = Error(-C.ERROR_NI)
ErrorNomem = Error(-C.ERROR_NOMEM)
ErrorInval = Error(-C.ERROR_INVAL)
ErrorBadfail = Error(-C.ERROR_BADFAIL)
ErrorGuestTimedout = Error(-C.ERROR_GUEST_TIMEDOUT)
ErrorTimedout = Error(-C.ERROR_TIMEDOUT)
ErrorNoparavirt = Error(-C.ERROR_NOPARAVIRT)
ErrorNotReady = Error(-C.ERROR_NOT_READY)
ErrorOseventRegFail = Error(-C.ERROR_OSEVENT_REG_FAIL)
ErrorBufferfull = Error(-C.ERROR_BUFFERFULL)
ErrorUnknownChild = Error(-C.ERROR_UNKNOWN_CHILD)
ErrorLockFail = Error(-C.ERROR_LOCK_FAIL)
ErrorJsonConfigEmpty = Error(-C.ERROR_JSON_CONFIG_EMPTY)
ErrorDeviceExists = Error(-C.ERROR_DEVICE_EXISTS)
ErrorCheckpointDevopsDoesNotMatch = Error(-C.ERROR_CHECKPOINT_DEVOPS_DOES_NOT_MATCH)
ErrorCheckpointDeviceNotSupported = Error(-C.ERROR_CHECKPOINT_DEVICE_NOT_SUPPORTED)
ErrorVnumaConfigInvalid = Error(-C.ERROR_VNUMA_CONFIG_INVALID)
ErrorDomainNotfound = Error(-C.ERROR_DOMAIN_NOTFOUND)
ErrorAborted = Error(-C.ERROR_ABORTED)
ErrorNotfound = Error(-C.ERROR_NOTFOUND)
ErrorDomainDestroyed = Error(-C.ERROR_DOMAIN_DESTROYED)
ErrorFeatureRemoved = Error(-C.ERROR_FEATURE_REMOVED)
)
var errors = [...]string{
ErrorNonspecific: "Non-specific error",
ErrorVersion: "Wrong version",
ErrorFail: "Failed",
ErrorNi: "Not Implemented",
ErrorNomem: "No memory",
ErrorInval: "Invalid argument",
ErrorBadfail: "Bad Fail",
ErrorGuestTimedout: "Guest timed out",
ErrorTimedout: "Timed out",
ErrorNoparavirt: "No Paravirtualization",
ErrorNotReady: "Not ready",
ErrorOseventRegFail: "OS event registration failed",
ErrorBufferfull: "Buffer full",
ErrorUnknownChild: "Unknown child",
ErrorLockFail: "Lock failed",
ErrorJsonConfigEmpty: "JSON config empty",
ErrorDeviceExists: "Device exists",
ErrorCheckpointDevopsDoesNotMatch: "Checkpoint devops does not match",
ErrorCheckpointDeviceNotSupported: "Checkpoint device not supported",
ErrorVnumaConfigInvalid: "VNUMA config invalid",
ErrorDomainNotfound: "Domain not found",
ErrorAborted: "Aborted",
ErrorNotfound: "Not found",
ErrorDomainDestroyed: "Domain destroyed",
ErrorFeatureRemoved: "Feature removed",
}
func (e Error) Error() string {
if 0 < int(e) && int(e) < len(errors) {
s := errors[e]
if s != "" {
return s
}
}
return fmt.Sprintf("libxl error: %d", -e)
}
/*
* Types: Builtins
*/
type Domid uint32
type MemKB uint64
type Uuid C.libxl_uuid
type Context struct {
ctx *C.libxl_ctx
logger *C.xentoollog_logger_stdiostream
}
type Hwcap []C.uint32_t
func (chwcap C.libxl_hwcap) toGo() (ghwcap Hwcap) {
// Alloc a Go slice for the bytes
size := 8
ghwcap = make([]C.uint32_t, size)
// Make a slice pointing to the C array
mapslice := (*[1 << 30]C.uint32_t)(unsafe.Pointer(&chwcap[0]))[:size:size]
// And copy the C array into the Go array
copy(ghwcap, mapslice)
return
}
// typedef struct {
// uint32_t size; /* number of bytes in map */
// uint8_t *map;
// } libxl_bitmap;
// Implement the Go bitmap type such that the underlying data can
// easily be copied in and out. NB that we still have to do copies
// both directions, because cgo runtime restrictions forbid passing to
// a C function a pointer to a Go-allocated structure which contains a
// pointer.
type Bitmap struct {
bitmap []C.uint8_t
}
/*
* Types: IDL
*
* FIXME: Generate these automatically from the IDL
*/
type Physinfo struct {
ThreadsPerCore uint32
CoresPerSocket uint32
MaxCpuId uint32
NrCpus uint32
CpuKhz uint32
TotalPages uint64
FreePages uint64
ScrubPages uint64
OutstandingPages uint64
SharingFreedPages uint64
SharingUsedFrames uint64
NrNodes uint32
HwCap Hwcap
CapHvm bool
CapHvmDirectio bool
}
func (cphys *C.libxl_physinfo) toGo() (physinfo *Physinfo) {
physinfo = &Physinfo{}
physinfo.ThreadsPerCore = uint32(cphys.threads_per_core)
physinfo.CoresPerSocket = uint32(cphys.cores_per_socket)
physinfo.MaxCpuId = uint32(cphys.max_cpu_id)
physinfo.NrCpus = uint32(cphys.nr_cpus)
physinfo.CpuKhz = uint32(cphys.cpu_khz)
physinfo.TotalPages = uint64(cphys.total_pages)
physinfo.FreePages = uint64(cphys.free_pages)
physinfo.ScrubPages = uint64(cphys.scrub_pages)
physinfo.ScrubPages = uint64(cphys.scrub_pages)
physinfo.SharingFreedPages = uint64(cphys.sharing_freed_pages)
physinfo.SharingUsedFrames = uint64(cphys.sharing_used_frames)
physinfo.NrNodes = uint32(cphys.nr_nodes)
physinfo.HwCap = cphys.hw_cap.toGo()
physinfo.CapHvm = bool(cphys.cap_hvm)
physinfo.CapHvmDirectio = bool(cphys.cap_hvm_directio)
return
}
type VersionInfo struct {
XenVersionMajor int
XenVersionMinor int
XenVersionExtra string
Compiler string
CompileBy string
CompileDomain string
CompileDate string
Capabilities string
Changeset string
VirtStart uint64
Pagesize int
Commandline string
BuildId string
}
func (cinfo *C.libxl_version_info) toGo() (info *VersionInfo) {
info = &VersionInfo{}
info.XenVersionMajor = int(cinfo.xen_version_major)
info.XenVersionMinor = int(cinfo.xen_version_minor)
info.XenVersionExtra = C.GoString(cinfo.xen_version_extra)
info.Compiler = C.GoString(cinfo.compiler)
info.CompileBy = C.GoString(cinfo.compile_by)
info.CompileDomain = C.GoString(cinfo.compile_domain)
info.CompileDate = C.GoString(cinfo.compile_date)
info.Capabilities = C.GoString(cinfo.capabilities)
info.Changeset = C.GoString(cinfo.changeset)
info.VirtStart = uint64(cinfo.virt_start)
info.Pagesize = int(cinfo.pagesize)
info.Commandline = C.GoString(cinfo.commandline)
info.BuildId = C.GoString(cinfo.build_id)
return
}
type ShutdownReason int32
const (
ShutdownReasonUnknown = ShutdownReason(C.LIBXL_SHUTDOWN_REASON_UNKNOWN)
ShutdownReasonPoweroff = ShutdownReason(C.LIBXL_SHUTDOWN_REASON_POWEROFF)
ShutdownReasonReboot = ShutdownReason(C.LIBXL_SHUTDOWN_REASON_REBOOT)
ShutdownReasonSuspend = ShutdownReason(C.LIBXL_SHUTDOWN_REASON_SUSPEND)
ShutdownReasonCrash = ShutdownReason(C.LIBXL_SHUTDOWN_REASON_CRASH)
ShutdownReasonWatchdog = ShutdownReason(C.LIBXL_SHUTDOWN_REASON_WATCHDOG)
ShutdownReasonSoftReset = ShutdownReason(C.LIBXL_SHUTDOWN_REASON_SOFT_RESET)
)
func (sr ShutdownReason) String() (str string) {
cstr := C.libxl_shutdown_reason_to_string(C.libxl_shutdown_reason(sr))
str = C.GoString(cstr)
return
}
type DomainType int32
const (
DomainTypeInvalid = DomainType(C.LIBXL_DOMAIN_TYPE_INVALID)
DomainTypeHvm = DomainType(C.LIBXL_DOMAIN_TYPE_HVM)
DomainTypePv = DomainType(C.LIBXL_DOMAIN_TYPE_PV)
)
func (dt DomainType) String() (str string) {
cstr := C.libxl_domain_type_to_string(C.libxl_domain_type(dt))
str = C.GoString(cstr)
return
}
type Dominfo struct {
Uuid Uuid
Domid Domid
Ssidref uint32
SsidLabel string
Running bool
Blocked bool
Paused bool
Shutdown bool
Dying bool
NeverStop bool
ShutdownReason int32
OutstandingMemkb MemKB
CurrentMemkb MemKB
SharedMemkb MemKB
PagedMemkb MemKB
MaxMemkb MemKB
CpuTime time.Duration
VcpuMaxId uint32
VcpuOnline uint32
Cpupool uint32
DomainType int32
}
func (cdi *C.libxl_dominfo) toGo() (di *Dominfo) {
di = &Dominfo{}
di.Uuid = Uuid(cdi.uuid)
di.Domid = Domid(cdi.domid)
di.Ssidref = uint32(cdi.ssidref)
di.SsidLabel = C.GoString(cdi.ssid_label)
di.Running = bool(cdi.running)
di.Blocked = bool(cdi.blocked)
di.Paused = bool(cdi.paused)
di.Shutdown = bool(cdi.shutdown)
di.Dying = bool(cdi.dying)
di.NeverStop = bool(cdi.never_stop)
di.ShutdownReason = int32(cdi.shutdown_reason)
di.OutstandingMemkb = MemKB(cdi.outstanding_memkb)
di.CurrentMemkb = MemKB(cdi.current_memkb)
di.SharedMemkb = MemKB(cdi.shared_memkb)
di.PagedMemkb = MemKB(cdi.paged_memkb)
di.MaxMemkb = MemKB(cdi.max_memkb)
di.CpuTime = time.Duration(cdi.cpu_time)
di.VcpuMaxId = uint32(cdi.vcpu_max_id)
di.VcpuOnline = uint32(cdi.vcpu_online)
di.Cpupool = uint32(cdi.cpupool)
di.DomainType = int32(cdi.domain_type)
return
}
// # Consistent with values defined in domctl.h
// # Except unknown which we have made up
// libxl_scheduler = Enumeration("scheduler", [
// (0, "unknown"),
// (4, "sedf"),
// (5, "credit"),
// (6, "credit2"),
// (7, "arinc653"),
// (8, "rtds"),
// ])
type Scheduler int
var (
SchedulerUnknown Scheduler = C.LIBXL_SCHEDULER_UNKNOWN
SchedulerSedf Scheduler = C.LIBXL_SCHEDULER_SEDF
SchedulerCredit Scheduler = C.LIBXL_SCHEDULER_CREDIT
SchedulerCredit2 Scheduler = C.LIBXL_SCHEDULER_CREDIT2
SchedulerArinc653 Scheduler = C.LIBXL_SCHEDULER_ARINC653
SchedulerRTDS Scheduler = C.LIBXL_SCHEDULER_RTDS
)
// const char *libxl_scheduler_to_string(libxl_scheduler p);
func (s Scheduler) String() string {
cs := C.libxl_scheduler_to_string(C.libxl_scheduler(s))
// No need to free const return value
return C.GoString(cs)
}
// int libxl_scheduler_from_string(const char *s, libxl_scheduler *e);
func (s *Scheduler) FromString(gstr string) (err error) {
*s, err = SchedulerFromString(gstr)
return
}
func SchedulerFromString(name string) (s Scheduler, err error) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
var cs C.libxl_scheduler
ret := C.libxl_scheduler_from_string(cname, &cs)
if ret != 0 {
err = Error(-ret)
return
}
s = Scheduler(cs)
return
}
// libxl_cpupoolinfo = Struct("cpupoolinfo", [
// ("poolid", uint32),
// ("pool_name", string),
// ("sched", libxl_scheduler),
// ("n_dom", uint32),
// ("cpumap", libxl_bitmap)
// ], dir=DIR_OUT)
type CpupoolInfo struct {
Poolid uint32
PoolName string
Scheduler Scheduler
DomainCount int
Cpumap Bitmap
}
func (cci C.libxl_cpupoolinfo) toGo() (gci CpupoolInfo) {
gci.Poolid = uint32(cci.poolid)
gci.PoolName = C.GoString(cci.pool_name)
gci.Scheduler = Scheduler(cci.sched)
gci.DomainCount = int(cci.n_dom)
gci.Cpumap = cci.cpumap.toGo()
return
}
// libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
// void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nb_pool);
func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
err := Ctx.CheckOpen()
if err != nil {
return
}
var nbPool C.int
c_cpupool_list := C.libxl_list_cpupool(Ctx.ctx, &nbPool)
defer C.libxl_cpupoolinfo_list_free(c_cpupool_list, nbPool)
if int(nbPool) == 0 {
return
}
// Magic
cpupoolListSlice := (*[1 << 30]C.libxl_cpupoolinfo)(unsafe.Pointer(c_cpupool_list))[:nbPool:nbPool]
for i := range cpupoolListSlice {
info := cpupoolListSlice[i].toGo()
list = append(list, info)
}
return
}
// int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t poolid);
func (Ctx *Context) CpupoolInfo(Poolid uint32) (pool CpupoolInfo) {
err := Ctx.CheckOpen()
if err != nil {
return
}
var c_cpupool C.libxl_cpupoolinfo
ret := C.libxl_cpupool_info(Ctx.ctx, &c_cpupool, C.uint32_t(Poolid))
if ret != 0 {
err = Error(-ret)
return
}
defer C.libxl_cpupoolinfo_dispose(&c_cpupool)
pool = c_cpupool.toGo()
return
}
// int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
// libxl_scheduler sched,
// libxl_bitmap cpumap, libxl_uuid *uuid,
// uint32_t *poolid);
// FIXME: uuid
// FIXME: Setting poolid
func (Ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap Bitmap) (err error, Poolid uint32) {
err = Ctx.CheckOpen()
if err != nil {
return
}
poolid := C.uint32_t(C.LIBXL_CPUPOOL_POOLID_ANY)
name := C.CString(Name)
defer C.free(unsafe.Pointer(name))
// For now, just do what xl does, and make a new uuid every time we create the pool
var uuid C.libxl_uuid
C.libxl_uuid_generate(&uuid)
cbm := Cpumap.toC()
defer C.libxl_bitmap_dispose(&cbm)
ret := C.libxl_cpupool_create(Ctx.ctx, name, C.libxl_scheduler(Scheduler),
cbm, &uuid, &poolid)
if ret != 0 {
err = Error(-ret)
return
}
Poolid = uint32(poolid)
return
}
// int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid);
func (Ctx *Context) CpupoolDestroy(Poolid uint32) (err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ret := C.libxl_cpupool_destroy(Ctx.ctx, C.uint32_t(Poolid))
if ret != 0 {
err = Error(-ret)
return
}
return
}
// int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu);
func (Ctx *Context) CpupoolCpuadd(Poolid uint32, Cpu int) (err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ret := C.libxl_cpupool_cpuadd(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
if ret != 0 {
err = Error(-ret)
return
}
return
}
// int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
// const libxl_bitmap *cpumap);
func (Ctx *Context) CpupoolCpuaddCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
cbm := Cpumap.toC()
defer C.libxl_bitmap_dispose(&cbm)
ret := C.libxl_cpupool_cpuadd_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
if ret != 0 {
err = Error(-ret)
return
}
return
}
// int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu);
func (Ctx *Context) CpupoolCpuremove(Poolid uint32, Cpu int) (err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ret := C.libxl_cpupool_cpuremove(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
if ret != 0 {
err = Error(-ret)
return
}
return
}
// int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
// const libxl_bitmap *cpumap);
func (Ctx *Context) CpupoolCpuremoveCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
cbm := Cpumap.toC()
defer C.libxl_bitmap_dispose(&cbm)
ret := C.libxl_cpupool_cpuremove_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
if ret != 0 {
err = Error(-ret)
return
}
return
}
// int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid);
func (Ctx *Context) CpupoolRename(Name string, Poolid uint32) (err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
name := C.CString(Name)
defer C.free(unsafe.Pointer(name))
ret := C.libxl_cpupool_rename(Ctx.ctx, name, C.uint32_t(Poolid))
if ret != 0 {
err = Error(-ret)
return
}
return
}
// int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
func (Ctx *Context) CpupoolCpuaddNode(Poolid uint32, Node int) (Cpus int, err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ccpus := C.int(0)
ret := C.libxl_cpupool_cpuadd_node(Ctx.ctx, C.uint32_t(Poolid), C.int(Node), &ccpus)
if ret != 0 {
err = Error(-ret)
return
}
Cpus = int(ccpus)
return
}
// int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
func (Ctx *Context) CpupoolCpuremoveNode(Poolid uint32, Node int) (Cpus int, err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ccpus := C.int(0)
ret := C.libxl_cpupool_cpuremove_node(Ctx.ctx, C.uint32_t(Poolid), C.int(Node), &ccpus)
if ret != 0 {
err = Error(-ret)
return
}
Cpus = int(ccpus)
return
}
// int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid);
func (Ctx *Context) CpupoolMovedomain(Poolid uint32, Id Domid) (err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ret := C.libxl_cpupool_movedomain(Ctx.ctx, C.uint32_t(Poolid), C.uint32_t(Id))
if ret != 0 {
err = Error(-ret)
return
}
return
}
//
// Utility functions
//
func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found bool) {
plist := Ctx.ListCpupool()
for i := range plist {
if plist[i].PoolName == name {
found = true
info = plist[i]
return
}
}
return
}
func (Ctx *Context) CpupoolMakeFree(Cpumap Bitmap) (err error) {
plist := Ctx.ListCpupool()
for i := range plist {
var Intersection Bitmap
Intersection = Cpumap.And(plist[i].Cpumap)
if !Intersection.IsEmpty() {
err = Ctx.CpupoolCpuremoveCpumap(plist[i].Poolid, Intersection)
if err != nil {
return
}
}
}
return
}
/*
* Bitmap operations
*/
// Return a Go bitmap which is a copy of the referred C bitmap.
func (cbm C.libxl_bitmap) toGo() (gbm Bitmap) {
// Alloc a Go slice for the bytes
size := int(cbm.size)
gbm.bitmap = make([]C.uint8_t, size)
// Make a slice pointing to the C array
mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
// And copy the C array into the Go array
copy(gbm.bitmap, mapslice)
return
}
// Must be C.libxl_bitmap_dispose'd of afterwards
func (gbm Bitmap) toC() (cbm C.libxl_bitmap) {
C.libxl_bitmap_init(&cbm)
size := len(gbm.bitmap)
cbm._map = (*C.uint8_t)(C.malloc(C.size_t(size)))
cbm.size = C.uint32_t(size)
if cbm._map == nil {
panic("C.calloc failed!")
}
// Make a slice pointing to the C array
mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
// And copy the Go array into the C array
copy(mapslice, gbm.bitmap)
return
}
func (bm *Bitmap) Test(bit int) bool {
ubit := uint(bit)
if bit > bm.Max() || bm.bitmap == nil {
return false
}
return (bm.bitmap[bit/8] & (1 << (ubit & 7))) != 0
}
func (bm *Bitmap) Set(bit int) {
ibit := bit / 8
if ibit+1 > len(bm.bitmap) {
bm.bitmap = append(bm.bitmap, make([]C.uint8_t, ibit+1-len(bm.bitmap))...)
}
bm.bitmap[ibit] |= 1 << (uint(bit) & 7)
}
func (bm *Bitmap) SetRange(start int, end int) {
for i := start; i <= end; i++ {
bm.Set(i)
}
}
func (bm *Bitmap) Clear(bit int) {
ubit := uint(bit)
if bit > bm.Max() || bm.bitmap == nil {
return
}
bm.bitmap[bit/8] &= ^(1 << (ubit & 7))
}
func (bm *Bitmap) ClearRange(start int, end int) {
for i := start; i <= end; i++ {
bm.Clear(i)
}
}
func (bm *Bitmap) Max() int {
return len(bm.bitmap)*8 - 1
}
func (bm *Bitmap) IsEmpty() bool {
for i := 0; i < len(bm.bitmap); i++ {
if bm.bitmap[i] != 0 {
return false
}
}
return true
}
func (a Bitmap) And(b Bitmap) (c Bitmap) {
var max, min int
if len(a.bitmap) > len(b.bitmap) {
max = len(a.bitmap)
min = len(b.bitmap)
} else {
max = len(b.bitmap)
min = len(a.bitmap)
}
c.bitmap = make([]C.uint8_t, max)
for i := 0; i < min; i++ {
c.bitmap[i] = a.bitmap[i] & b.bitmap[i]
}
return
}
func (bm Bitmap) String() (s string) {
lastOnline := false
crange := false
printed := false
var i int
/// --x-xxxxx-x -> 2,4-8,10
/// --x-xxxxxxx -> 2,4-10
for i = 0; i <= bm.Max(); i++ {
if bm.Test(i) {
if !lastOnline {
// Switching offline -> online, print this cpu
if printed {
s += ","
}
s += fmt.Sprintf("%d", i)
printed = true
} else if !crange {
// last was online, but we're not in a range; print -
crange = true
s += "-"
} else {
// last was online, we're in a range, nothing else to do
}
lastOnline = true
} else {
if lastOnline {
// Switching online->offline; do we need to end a range?
if crange {
s += fmt.Sprintf("%d", i-1)
}
}
lastOnline = false
crange = false
}
}
if lastOnline {
// Switching online->offline; do we need to end a range?
if crange {
s += fmt.Sprintf("%d", i-1)
}
}
return
}
/*
* Context
*/
var Ctx Context
func (Ctx *Context) IsOpen() bool {
return Ctx.ctx != nil
}
func (Ctx *Context) Open() (err error) {
if Ctx.ctx != nil {
return
}
Ctx.logger = C.xtl_createlogger_stdiostream(C.stderr, C.XTL_ERROR, 0)
if Ctx.logger == nil {
err = fmt.Errorf("Cannot open stdiostream")
return
}
ret := C.libxl_ctx_alloc(&Ctx.ctx, C.LIBXL_VERSION,
0, unsafe.Pointer(Ctx.logger))
if ret != 0 {
err = Error(-ret)
}
return
}
func (Ctx *Context) Close() (err error) {
ret := C.libxl_ctx_free(Ctx.ctx)
Ctx.ctx = nil
if ret != 0 {
err = Error(-ret)
}
C.xtl_logger_destroy(unsafe.Pointer(Ctx.logger))
return
}
func (Ctx *Context) CheckOpen() (err error) {
if Ctx.ctx == nil {
err = fmt.Errorf("Context not opened")
}
return
}
//int libxl_get_max_cpus(libxl_ctx *ctx);
func (Ctx *Context) GetMaxCpus() (maxCpus int, err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ret := C.libxl_get_max_cpus(Ctx.ctx)
if ret < 0 {
err = Error(-ret)
return
}
maxCpus = int(ret)
return
}
//int libxl_get_online_cpus(libxl_ctx *ctx);
func (Ctx *Context) GetOnlineCpus() (onCpus int, err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ret := C.libxl_get_online_cpus(Ctx.ctx)
if ret < 0 {
err = Error(-ret)
return
}
onCpus = int(ret)
return
}
//int libxl_get_max_nodes(libxl_ctx *ctx);
func (Ctx *Context) GetMaxNodes() (maxNodes int, err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ret := C.libxl_get_max_nodes(Ctx.ctx)
if ret < 0 {
err = Error(-ret)
return
}
maxNodes = int(ret)
return
}
//int libxl_get_free_memory(libxl_ctx *ctx, uint64_t *memkb);
func (Ctx *Context) GetFreeMemory() (memkb uint64, err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
var cmem C.uint64_t
ret := C.libxl_get_free_memory(Ctx.ctx, &cmem)
if ret < 0 {
err = Error(-ret)
return
}
memkb = uint64(cmem)
return
}
//int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
func (Ctx *Context) GetPhysinfo() (physinfo *Physinfo, err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
var cphys C.libxl_physinfo
C.libxl_physinfo_init(&cphys)
defer C.libxl_physinfo_dispose(&cphys)
ret := C.libxl_get_physinfo(Ctx.ctx, &cphys)
if ret < 0 {
err = Error(ret)
return
}
physinfo = cphys.toGo()
return
}
//const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx);
func (Ctx *Context) GetVersionInfo() (info *VersionInfo, err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
var cinfo *C.libxl_version_info
cinfo = C.libxl_get_version_info(Ctx.ctx)
info = cinfo.toGo()
return
}
func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
var cdi C.libxl_dominfo
C.libxl_dominfo_init(&cdi)
defer C.libxl_dominfo_dispose(&cdi)
ret := C.libxl_domain_info(Ctx.ctx, &cdi, C.uint32_t(Id))
if ret != 0 {
err = Error(-ret)
return
}
di = cdi.toGo()
return
}
func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ret := C.libxl_domain_unpause(Ctx.ctx, C.uint32_t(Id))
if ret != 0 {
err = Error(-ret)
}
return
}
//int libxl_domain_pause(libxl_ctx *ctx, uint32_t domain);
func (Ctx *Context) DomainPause(id Domid) (err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ret := C.libxl_domain_pause(Ctx.ctx, C.uint32_t(id))
if ret != 0 {
err = Error(-ret)
}
return
}
//int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid);
func (Ctx *Context) DomainShutdown(id Domid) (err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ret := C.libxl_domain_shutdown(Ctx.ctx, C.uint32_t(id))
if ret != 0 {
err = Error(-ret)
}
return
}
//int libxl_domain_reboot(libxl_ctx *ctx, uint32_t domid);
func (Ctx *Context) DomainReboot(id Domid) (err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
ret := C.libxl_domain_reboot(Ctx.ctx, C.uint32_t(id))
if ret != 0 {
err = Error(-ret)
}
return
}
//libxl_dominfo * libxl_list_domain(libxl_ctx*, int *nb_domain_out);
//void libxl_dominfo_list_free(libxl_dominfo *list, int nb_domain);
func (Ctx *Context) ListDomain() (glist []Dominfo) {
err := Ctx.CheckOpen()
if err != nil {
return
}
var nbDomain C.int
clist := C.libxl_list_domain(Ctx.ctx, &nbDomain)
defer C.libxl_dominfo_list_free(clist, nbDomain)
if int(nbDomain) == 0 {
return
}
gslice := (*[1 << 30]C.libxl_dominfo)(unsafe.Pointer(clist))[:nbDomain:nbDomain]
for i := range gslice {
info := gslice[i].toGo()
glist = append(glist, *info)
}
return
}
type Vcpuinfo struct {
Vcpuid uint32
Cpu uint32
Online bool
Blocked bool
Running bool
VCpuTime time.Duration
Cpumap Bitmap
CpumapSoft Bitmap
}
func (cvci C.libxl_vcpuinfo) toGo() (gvci Vcpuinfo) {
gvci.Vcpuid = uint32(cvci.vcpuid)
gvci.Cpu = uint32(cvci.cpu)
gvci.Online = bool(cvci.online)
gvci.Blocked = bool(cvci.blocked)
gvci.Running = bool(cvci.running)
gvci.VCpuTime = time.Duration(cvci.vcpu_time)
gvci.Cpumap = cvci.cpumap.toGo()
gvci.CpumapSoft = cvci.cpumap_soft.toGo()
return
}
//libxl_vcpuinfo *libxl_list_vcpu(libxl_ctx *ctx, uint32_t domid,
// int *nb_vcpu, int *nr_cpus_out);
//void libxl_vcpuinfo_list_free(libxl_vcpuinfo *, int nr_vcpus);
func (Ctx *Context) ListVcpu(id Domid) (glist []Vcpuinfo) {
err := Ctx.CheckOpen()
if err != nil {
return
}
var nbVcpu C.int
var nrCpu C.int
clist := C.libxl_list_vcpu(Ctx.ctx, C.uint32_t(id), &nbVcpu, &nrCpu)
defer C.libxl_vcpuinfo_list_free(clist, nbVcpu)
if int(nbVcpu) == 0 {
return
}
gslice := (*[1 << 30]C.libxl_vcpuinfo)(unsafe.Pointer(clist))[:nbVcpu:nbVcpu]
for i := range gslice {
info := gslice[i].toGo()
glist = append(glist, info)
}
return
}
type ConsoleType int
const (
ConsoleTypeUnknown = ConsoleType(C.LIBXL_CONSOLE_TYPE_UNKNOWN)
ConsoleTypeSerial = ConsoleType(C.LIBXL_CONSOLE_TYPE_SERIAL)
ConsoleTypePV = ConsoleType(C.LIBXL_CONSOLE_TYPE_PV)
)
func (ct ConsoleType) String() (str string) {
cstr := C.libxl_console_type_to_string(C.libxl_console_type(ct))
str = C.GoString(cstr)
return
}
//int libxl_console_get_tty(libxl_ctx *ctx, uint32_t domid, int cons_num,
//libxl_console_type type, char **path);
func (Ctx *Context) ConsoleGetTty(id Domid, consNum int, conType ConsoleType) (path string, err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
var cpath *C.char
ret := C.libxl_console_get_tty(Ctx.ctx, C.uint32_t(id), C.int(consNum), C.libxl_console_type(conType), &cpath)
if ret != 0 {
err = Error(-ret)
return
}
defer C.free(cpath)
path = C.GoString(cpath)
return
}
//int libxl_primary_console_get_tty(libxl_ctx *ctx, uint32_t domid_vm,
// char **path);
func (Ctx *Context) PrimaryConsoleGetTty(domid uint32) (path string, err error) {
err = Ctx.CheckOpen()
if err != nil {
return
}
var cpath *C.char
ret := C.libxl_primary_console_get_tty(Ctx.ctx, C.uint32_t(domid), &cpath)
if ret != 0 {
err = Error(-ret)
return
}
defer C.free(cpath)
path = C.GoString(cpath)
return
}