1/*
2 * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation;
7 * version 2.1 of the License.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
16 */
17
18// Package xenlight provides bindings to Xen's libxl C library.
19package xenlight
20
21/*
22
23#cgo LDFLAGS: -lxenlight -lyajl -lxentoollog
24#include <stdlib.h>
25#include <libxl.h>
26#include <libxl_utils.h>
27
28#define INVALID_DOMID_TYPED ((uint32_t) INVALID_DOMID)
29
30static const libxl_childproc_hooks childproc_hooks = { .chldowner = libxl_sigchld_owner_mainloop };
31
32void xenlight_set_chldproc(libxl_ctx *ctx) {
33	libxl_childproc_setmode(ctx, &childproc_hooks, NULL);
34}
35*/
36import "C"
37
38/*
39 * Other flags that may be needed at some point:
40 *  -lnl-route-3 -lnl-3
41 *
42 * To get back to static linking:
43 * #cgo LDFLAGS: -lxenlight -lyajl_s -lxengnttab -lxenstore -lxenguest -lxentoollog -lxenevtchn -lxenctrl -lxenforeignmemory -lxencall -lz -luuid -lutil
44 */
45
46import (
47	"fmt"
48	"os"
49	"os/signal"
50	"syscall"
51	"unsafe"
52)
53
54var libxlErrors = map[Error]string{
55	ErrorNonspecific:                  "Non-specific error",
56	ErrorVersion:                      "Wrong version",
57	ErrorFail:                         "Failed",
58	ErrorNi:                           "Not Implemented",
59	ErrorNomem:                        "No memory",
60	ErrorInval:                        "Invalid argument",
61	ErrorBadfail:                      "Bad Fail",
62	ErrorGuestTimedout:                "Guest timed out",
63	ErrorTimedout:                     "Timed out",
64	ErrorNoparavirt:                   "No Paravirtualization",
65	ErrorNotReady:                     "Not ready",
66	ErrorOseventRegFail:               "OS event registration failed",
67	ErrorBufferfull:                   "Buffer full",
68	ErrorUnknownChild:                 "Unknown child",
69	ErrorLockFail:                     "Lock failed",
70	ErrorJsonConfigEmpty:              "JSON config empty",
71	ErrorDeviceExists:                 "Device exists",
72	ErrorCheckpointDevopsDoesNotMatch: "Checkpoint devops does not match",
73	ErrorCheckpointDeviceNotSupported: "Checkpoint device not supported",
74	ErrorVnumaConfigInvalid:           "VNUMA config invalid",
75	ErrorDomainNotfound:               "Domain not found",
76	ErrorAborted:                      "Aborted",
77	ErrorNotfound:                     "Not found",
78	ErrorDomainDestroyed:              "Domain destroyed",
79	ErrorFeatureRemoved:               "Feature removed",
80}
81
82const (
83	DomidInvalid Domid = Domid(C.INVALID_DOMID_TYPED)
84)
85
86func (e Error) Error() string {
87	if s, ok := libxlErrors[e]; ok {
88		return s
89	}
90
91	return fmt.Sprintf("libxl error: %d", e)
92}
93
94// Context represents a libxl_ctx.
95type Context struct {
96	ctx         *C.libxl_ctx
97	logger      *C.xentoollog_logger_stdiostream
98	sigchld     chan os.Signal
99	sigchldDone chan struct{}
100}
101
102// Golang always unmasks SIGCHLD, and internally has ways of
103// distributing SIGCHLD to multiple recipients.  libxl has provision
104// for this model: just tell it when a SIGCHLD happened, and it will
105// look after its own processes.
106//
107// This should "play nicely" with other users of SIGCHLD as long as
108// they don't reap libxl's processes.
109//
110// Every context needs to be notified on each SIGCHLD; so spin up a
111// new goroutine for each context.  If there are a large number of
112// contexts, this means each context will be woken up looking through
113// its own list of children.
114//
115// The alternate would be to register a fork callback, such that the
116// xenlight package can make a single list of all children, and only
117// notify the specific libxl context(s) that have children woken.  But
118// it's not clear to me this will be much more work than having the
119// xenlight go library do the same thing; doing it in separate go
120// threads has the potential to do it in parallel.  Leave that as an
121// optimization for later if it turns out to be a bottleneck.
122func sigchldHandler(ctx *Context) {
123	for _ = range ctx.sigchld {
124		C.libxl_childproc_sigchld_occurred(ctx.ctx)
125	}
126	close(ctx.sigchldDone)
127}
128
129// NewContext returns a new Context.
130func NewContext() (ctx *Context, err error) {
131	ctx = &Context{}
132
133	defer func() {
134		if err != nil {
135			ctx.Close()
136			ctx = nil
137		}
138	}()
139
140	// Create a logger
141	ctx.logger = C.xtl_createlogger_stdiostream(C.stderr, C.XTL_ERROR, 0)
142
143	// Allocate a context
144	ret := C.libxl_ctx_alloc(&ctx.ctx, C.LIBXL_VERSION, 0,
145		(*C.xentoollog_logger)(unsafe.Pointer(ctx.logger)))
146	if ret != 0 {
147		return ctx, Error(ret)
148	}
149
150	// Tell libxl that we'll be dealing with SIGCHLD...
151	C.xenlight_set_chldproc(ctx.ctx)
152
153	// ...and arrange to keep that promise.
154	ctx.sigchld = make(chan os.Signal, 2)
155	ctx.sigchldDone = make(chan struct{}, 1)
156	signal.Notify(ctx.sigchld, syscall.SIGCHLD)
157
158	// This goroutine will run until the ctx.sigchld is closed in
159	// ctx.Close(); at which point it will close ctx.sigchldDone.
160	go sigchldHandler(ctx)
161
162	return ctx, nil
163}
164
165// Close closes the Context.
166func (ctx *Context) Close() error {
167	// Tell our SIGCHLD notifier to shut down, and wait for it to exit
168	// before we free the context.
169	if ctx.sigchld != nil {
170		signal.Stop(ctx.sigchld)
171		close(ctx.sigchld)
172
173		<-ctx.sigchldDone
174
175		ctx.sigchld = nil
176		ctx.sigchldDone = nil
177	}
178
179	if ctx.ctx != nil {
180		ret := C.libxl_ctx_free(ctx.ctx)
181		if ret != 0 {
182			return Error(ret)
183		}
184		ctx.ctx = nil
185	}
186
187	if ctx.logger != nil {
188		C.xtl_logger_destroy((*C.xentoollog_logger)(unsafe.Pointer(ctx.logger)))
189		ctx.logger = nil
190	}
191
192	return nil
193}
194
195/*
196 * Types: Builtins
197 */
198
199type Domid uint32
200
201// NameToDomid returns the Domid for a domain, given its name, if it exists.
202//
203// NameToDomid does not guarantee that the domid associated with name at
204// the time NameToDomid is called is the same as the domid associated with
205// name at the time NameToDomid returns.
206func (ctx *Context) NameToDomid(name string) (Domid, error) {
207	var domid C.uint32_t
208
209	cname := C.CString(name)
210	defer C.free(unsafe.Pointer(cname))
211
212	if ret := C.libxl_name_to_domid(ctx.ctx, cname, &domid); ret != 0 {
213		return DomidInvalid, Error(ret)
214	}
215
216	return Domid(domid), nil
217}
218
219// DomidToName returns the name for a domain, given its domid. If there
220// is no domain with the given domid, DomidToName will return the empty
221// string.
222//
223// DomidToName does not guarantee that the name (if any) associated with domid
224// at the time DomidToName is called is the same as the name (if any) associated
225// with domid at the time DomidToName returns.
226func (ctx *Context) DomidToName(domid Domid) string {
227	cname := C.libxl_domid_to_name(ctx.ctx, C.uint32_t(domid))
228	defer C.free(unsafe.Pointer(cname))
229
230	return C.GoString(cname)
231}
232
233// Devid is a device ID.
234type Devid int
235
236// Uuid is a domain UUID.
237type Uuid [16]byte
238
239// String formats a Uuid in the form "xxxx-xx-xx-xx-xxxxxx".
240func (u Uuid) String() string {
241	s := "%x%x%x%x-%x%x-%x%x-%x%x-%x%x%x%x%x%x"
242	opts := make([]interface{}, 16)
243
244	for i, v := range u {
245		opts[i] = v
246	}
247
248	return fmt.Sprintf(s, opts...)
249}
250
251func (u *Uuid) fromC(c *C.libxl_uuid) error {
252	for i := range *u {
253		u[i] = byte(c.uuid[i])
254	}
255
256	return nil
257}
258
259func (u *Uuid) toC(cu *C.libxl_uuid) error {
260	for i, v := range u {
261		cu.uuid[i] = C.uint8_t(v)
262	}
263
264	return nil
265}
266
267// defboolVal represents a defbool value.
268type defboolVal int
269
270const (
271	defboolDefault defboolVal = 0
272	defboolFalse   defboolVal = -1
273	defboolTrue    defboolVal = 1
274)
275
276// Defbool represents a libxl_defbool.
277type Defbool struct {
278	val defboolVal
279}
280
281func (d Defbool) String() string {
282	switch d.val {
283	case defboolDefault:
284		return "<default>"
285	case defboolFalse:
286		return "False"
287	case defboolTrue:
288		return "True"
289	}
290
291	return ""
292}
293
294// Set sets the value of the Defbool.
295func (d *Defbool) Set(b bool) {
296	if b {
297		d.val = defboolTrue
298		return
299	}
300	d.val = defboolFalse
301}
302
303// Unset resets the Defbool to default value.
304func (d *Defbool) Unset() {
305	d.val = defboolDefault
306}
307
308// SetIfDefault sets the value of Defbool only if
309// its current value is default.
310func (d *Defbool) SetIfDefault(b bool) {
311	if d.IsDefault() {
312		d.Set(b)
313	}
314}
315
316// IsDefault returns true if the value of Defbool
317// is default, returns false otherwise.
318func (d *Defbool) IsDefault() bool {
319	return d.val == defboolDefault
320}
321
322// Val returns the boolean value associated with the
323// Defbool value. An error is returned if the value
324// is default.
325func (d *Defbool) Val() (bool, error) {
326	if d.IsDefault() {
327		return false, fmt.Errorf("%v: cannot take value of default defbool", ErrorInval)
328	}
329
330	return (d.val > 0), nil
331}
332
333func (d *Defbool) fromC(c *C.libxl_defbool) error {
334	if C.libxl_defbool_is_default(*c) {
335		d.val = defboolDefault
336		return nil
337	}
338
339	if C.libxl_defbool_val(*c) {
340		d.val = defboolTrue
341		return nil
342	}
343
344	d.val = defboolFalse
345
346	return nil
347}
348
349func (d *Defbool) toC(cd *C.libxl_defbool) error {
350	if !d.IsDefault() {
351		val, _ := d.Val()
352		C.libxl_defbool_set(cd, C.bool(val))
353	}
354
355	return nil
356}
357
358// Mac represents a libxl_mac, or simply a MAC address.
359type Mac [6]byte
360
361// String formats a Mac address to string representation.
362func (mac Mac) String() string {
363	s := "%02x:%02x:%02x:%02x:%02x:%02x"
364	opts := make([]interface{}, 6)
365
366	for i, v := range mac {
367		opts[i] = v
368	}
369
370	return fmt.Sprintf(s, opts...)
371}
372
373func (mac *Mac) fromC(cmac *C.libxl_mac) error {
374	for i := range *mac {
375		mac[i] = byte(cmac[i])
376	}
377
378	return nil
379}
380
381func (mac Mac) toC(cm *C.libxl_mac) error {
382	for i, v := range mac {
383		(*cm)[i] = C.uint8_t(v)
384	}
385
386	return nil
387}
388
389// MsVmGenid represents a libxl_ms_vm_genid.
390type MsVmGenid [int(C.LIBXL_MS_VM_GENID_LEN)]byte
391
392func (mvg *MsVmGenid) fromC(cmvg *C.libxl_ms_vm_genid) error {
393	for i := range *mvg {
394		mvg[i] = byte(cmvg.bytes[i])
395	}
396
397	return nil
398}
399
400func (mvg *MsVmGenid) toC(cmvg *C.libxl_ms_vm_genid) error {
401	for i, v := range mvg {
402		cmvg.bytes[i] = C.uint8_t(v)
403	}
404
405	return nil
406}
407
408// EvLink represents a libxl_ev_link.
409//
410// Represented as an empty struct for now, as there is no
411// apparent need for the internals of this type to be exposed
412// through the Go package.
413type EvLink struct{}
414
415func (el *EvLink) fromC(cel *C.libxl_ev_link) error     { return nil }
416func (el *EvLink) toC(cel *C.libxl_ev_link) (err error) { return }
417
418// CpuidPolicyList represents a libxl_cpuid_policy_list.
419//
420// The value of CpuidPolicyList is honored when used as input to libxl. If
421// a struct contains a field of type CpuidPolicyList, that field will be left
422// empty when it is returned from libxl.
423type CpuidPolicyList string
424
425func (cpl *CpuidPolicyList) fromC(ccpl *C.libxl_cpuid_policy_list) error { *cpl = ""; return nil }
426
427func (cpl CpuidPolicyList) toC(ccpl *C.libxl_cpuid_policy_list) error {
428	if cpl == "" {
429		*ccpl = nil
430		return nil
431	}
432
433	s := C.CString(string(cpl))
434	defer C.free(unsafe.Pointer(s))
435
436	ret := C.libxl_cpuid_parse_config(ccpl, s)
437	if ret != 0 {
438		C.libxl_cpuid_dispose(ccpl)
439
440		// libxl_cpuid_parse_config doesn't return a normal libxl error.
441		return ErrorInval
442	}
443
444	return nil
445}
446
447// Hwcap represents a libxl_hwcap.
448type Hwcap [8]uint32
449
450func (hwcap *Hwcap) fromC(chwcap *C.libxl_hwcap) error {
451	for i := range *hwcap {
452		hwcap[i] = uint32(chwcap[i])
453	}
454
455	return nil
456}
457
458func (hwcap *Hwcap) toC(chwcap *C.libxl_hwcap) error {
459	for i, v := range hwcap {
460		(*chwcap)[i] = C.uint32_t(v)
461	}
462
463	return nil
464}
465
466// KeyValueList represents a libxl_key_value_list.
467//
468// Represented as an empty struct for now, as there is no
469// apparent need for this type to be exposed through the
470// Go package.
471type KeyValueList struct{}
472
473func (kvl KeyValueList) fromC(ckvl *C.libxl_key_value_list) error     { return nil }
474func (kvl KeyValueList) toC(ckvl *C.libxl_key_value_list) (err error) { return }
475
476// StringList represents a libxl_string_list.
477type StringList []string
478
479func (sl *StringList) fromC(csl *C.libxl_string_list) error {
480	size := int(C.libxl_string_list_length(csl))
481	list := (*[1 << 30]*C.char)(unsafe.Pointer(csl))[:size:size]
482
483	*sl = make([]string, size)
484
485	for i, v := range list {
486		(*sl)[i] = C.GoString(v)
487	}
488
489	return nil
490}
491
492func (sl StringList) toC(csl *C.libxl_string_list) error {
493	var char *C.char
494	size := len(sl) + 1
495	*csl = (C.libxl_string_list)(C.malloc(C.ulong(size) * C.ulong(unsafe.Sizeof(char))))
496	clist := (*[1 << 30]*C.char)(unsafe.Pointer(*csl))[:size:size]
497
498	for i, v := range sl {
499		clist[i] = C.CString(v)
500	}
501	clist[len(clist)-1] = nil
502
503	return nil
504}
505
506// Bitmap represents a libxl_bitmap.
507//
508// Implement the Go bitmap type such that the underlying data can
509// easily be copied in and out.  NB that we still have to do copies
510// both directions, because cgo runtime restrictions forbid passing to
511// a C function a pointer to a Go-allocated structure which contains a
512// pointer.
513type Bitmap struct {
514	// typedef struct {
515	//     uint32_t size;          /* number of bytes in map */
516	//     uint8_t *map;
517	// } libxl_bitmap;
518	bitmap []C.uint8_t
519}
520
521func (bm *Bitmap) fromC(cbm *C.libxl_bitmap) error {
522	bm.bitmap = nil
523	if size := int(cbm.size); size > 0 {
524		// Alloc a Go slice for the bytes
525		bm.bitmap = make([]C.uint8_t, size)
526
527		// Make a slice pointing to the C array
528		cs := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
529
530		// And copy the C array into the Go array
531		copy(bm.bitmap, cs)
532	}
533
534	return nil
535}
536
537func (bm *Bitmap) toC(cbm *C.libxl_bitmap) error {
538	size := len(bm.bitmap)
539	cbm.size = C.uint32_t(size)
540	if cbm.size > 0 {
541		cbm._map = (*C.uint8_t)(C.malloc(C.ulong(cbm.size) * C.sizeof_uint8_t))
542		cs := (*[1 << 31]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
543
544		copy(cs, bm.bitmap)
545	}
546
547	return nil
548}
549
550func (sr ShutdownReason) String() (str string) {
551	cstr := C.libxl_shutdown_reason_to_string(C.libxl_shutdown_reason(sr))
552	str = C.GoString(cstr)
553
554	return
555}
556
557func (dt DomainType) String() (str string) {
558	cstr := C.libxl_domain_type_to_string(C.libxl_domain_type(dt))
559	str = C.GoString(cstr)
560
561	return
562}
563
564// const char *libxl_scheduler_to_string(libxl_scheduler p);
565
566func (s Scheduler) String() string {
567	cs := C.libxl_scheduler_to_string(C.libxl_scheduler(s))
568	// No need to free const return value
569
570	return C.GoString(cs)
571}
572
573// int libxl_scheduler_from_string(const char *s, libxl_scheduler *e);
574
575func (s *Scheduler) FromString(gstr string) (err error) {
576	*s, err = SchedulerFromString(gstr)
577	return
578}
579
580func SchedulerFromString(name string) (s Scheduler, err error) {
581	cname := C.CString(name)
582	defer C.free(unsafe.Pointer(cname))
583
584	var cs C.libxl_scheduler
585
586	ret := C.libxl_scheduler_from_string(cname, &cs)
587	if ret != 0 {
588		err = Error(ret)
589		return
590	}
591
592	s = Scheduler(cs)
593
594	return
595}
596
597// libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
598// void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nb_pool);
599
600func (ctx *Context) ListCpupool() (list []Cpupoolinfo) {
601	var nbPool C.int
602
603	c_cpupool_list := C.libxl_list_cpupool(ctx.ctx, &nbPool)
604
605	defer C.libxl_cpupoolinfo_list_free(c_cpupool_list, nbPool)
606
607	if int(nbPool) == 0 {
608		return
609	}
610
611	// Magic
612	cpupoolListSlice := (*[1 << 30]C.libxl_cpupoolinfo)(unsafe.Pointer(c_cpupool_list))[:nbPool:nbPool]
613	for i := range cpupoolListSlice {
614		var info Cpupoolinfo
615		_ = info.fromC(&cpupoolListSlice[i])
616		list = append(list, info)
617	}
618
619	return
620}
621
622// int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t poolid);
623
624func (ctx *Context) CpupoolInfo(Poolid uint32) (pool Cpupoolinfo, err error) {
625	var c_cpupool C.libxl_cpupoolinfo
626
627	ret := C.libxl_cpupool_info(ctx.ctx, &c_cpupool, C.uint32_t(Poolid))
628	if ret != 0 {
629		err = Error(ret)
630		return
631	}
632	defer C.libxl_cpupoolinfo_dispose(&c_cpupool)
633
634	err = pool.fromC(&c_cpupool)
635
636	return
637}
638
639// int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
640//                          libxl_scheduler sched,
641//                          libxl_bitmap cpumap, libxl_uuid *uuid,
642//                          uint32_t *poolid);
643// FIXME: uuid
644// FIXME: Setting poolid
645
646func (ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap Bitmap) (err error, Poolid uint32) {
647	poolid := C.uint32_t(C.LIBXL_CPUPOOL_POOLID_ANY)
648	name := C.CString(Name)
649	defer C.free(unsafe.Pointer(name))
650
651	// For now, just do what xl does, and make a new uuid every time we create the pool
652	var uuid C.libxl_uuid
653	C.libxl_uuid_generate(&uuid)
654
655	var cbm C.libxl_bitmap
656	if err = Cpumap.toC(&cbm); err != nil {
657		return
658	}
659	defer C.libxl_bitmap_dispose(&cbm)
660
661	ret := C.libxl_cpupool_create(ctx.ctx, name, C.libxl_scheduler(Scheduler),
662		cbm, &uuid, &poolid)
663	if ret != 0 {
664		err = Error(ret)
665		return
666	}
667
668	Poolid = uint32(poolid)
669
670	return
671}
672
673// int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid);
674
675func (ctx *Context) CpupoolDestroy(Poolid uint32) (err error) {
676	ret := C.libxl_cpupool_destroy(ctx.ctx, C.uint32_t(Poolid))
677	if ret != 0 {
678		err = Error(ret)
679		return
680	}
681
682	return
683}
684
685// int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu);
686
687func (ctx *Context) CpupoolCpuadd(Poolid uint32, Cpu int) (err error) {
688	ret := C.libxl_cpupool_cpuadd(ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
689	if ret != 0 {
690		err = Error(ret)
691		return
692	}
693
694	return
695}
696
697// int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
698//                                 const libxl_bitmap *cpumap);
699
700func (ctx *Context) CpupoolCpuaddCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
701	var cbm C.libxl_bitmap
702	if err = Cpumap.toC(&cbm); err != nil {
703		return
704	}
705	defer C.libxl_bitmap_dispose(&cbm)
706
707	ret := C.libxl_cpupool_cpuadd_cpumap(ctx.ctx, C.uint32_t(Poolid), &cbm)
708	if ret != 0 {
709		err = Error(ret)
710		return
711	}
712
713	return
714}
715
716// int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu);
717
718func (ctx *Context) CpupoolCpuremove(Poolid uint32, Cpu int) (err error) {
719	ret := C.libxl_cpupool_cpuremove(ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
720	if ret != 0 {
721		err = Error(ret)
722		return
723	}
724
725	return
726}
727
728// int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
729//                                    const libxl_bitmap *cpumap);
730
731func (ctx *Context) CpupoolCpuremoveCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
732	var cbm C.libxl_bitmap
733	if err = Cpumap.toC(&cbm); err != nil {
734		return
735	}
736	defer C.libxl_bitmap_dispose(&cbm)
737
738	ret := C.libxl_cpupool_cpuremove_cpumap(ctx.ctx, C.uint32_t(Poolid), &cbm)
739	if ret != 0 {
740		err = Error(ret)
741		return
742	}
743
744	return
745}
746
747// int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid);
748
749func (ctx *Context) CpupoolRename(Name string, Poolid uint32) (err error) {
750	name := C.CString(Name)
751	defer C.free(unsafe.Pointer(name))
752
753	ret := C.libxl_cpupool_rename(ctx.ctx, name, C.uint32_t(Poolid))
754	if ret != 0 {
755		err = Error(ret)
756		return
757	}
758
759	return
760}
761
762// int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
763
764func (ctx *Context) CpupoolCpuaddNode(Poolid uint32, Node int) (Cpus int, err error) {
765	ccpus := C.int(0)
766
767	ret := C.libxl_cpupool_cpuadd_node(ctx.ctx, C.uint32_t(Poolid), C.int(Node), &ccpus)
768	if ret != 0 {
769		err = Error(ret)
770		return
771	}
772
773	Cpus = int(ccpus)
774
775	return
776}
777
778// int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
779
780func (ctx *Context) CpupoolCpuremoveNode(Poolid uint32, Node int) (Cpus int, err error) {
781	ccpus := C.int(0)
782
783	ret := C.libxl_cpupool_cpuremove_node(ctx.ctx, C.uint32_t(Poolid), C.int(Node), &ccpus)
784	if ret != 0 {
785		err = Error(ret)
786		return
787	}
788
789	Cpus = int(ccpus)
790
791	return
792}
793
794// int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid);
795
796func (ctx *Context) CpupoolMovedomain(Poolid uint32, Id Domid) (err error) {
797	ret := C.libxl_cpupool_movedomain(ctx.ctx, C.uint32_t(Poolid), C.uint32_t(Id))
798	if ret != 0 {
799		err = Error(ret)
800		return
801	}
802
803	return
804}
805
806//
807// Utility functions
808//
809
810func (ctx *Context) CpupoolFindByName(name string) (info Cpupoolinfo, found bool) {
811	plist := ctx.ListCpupool()
812
813	for i := range plist {
814		if plist[i].PoolName == name {
815			found = true
816			info = plist[i]
817			return
818		}
819	}
820	return
821}
822
823func (ctx *Context) CpupoolMakeFree(Cpumap Bitmap) (err error) {
824	plist := ctx.ListCpupool()
825
826	for i := range plist {
827		var Intersection Bitmap
828		Intersection = Cpumap.And(plist[i].Cpumap)
829		if !Intersection.IsEmpty() {
830			err = ctx.CpupoolCpuremoveCpumap(plist[i].Poolid, Intersection)
831			if err != nil {
832				return
833			}
834		}
835	}
836	return
837}
838
839/*
840 * Bitmap operations
841 */
842
843func (bm *Bitmap) Test(bit int) bool {
844	ubit := uint(bit)
845	if bit > bm.Max() || bm.bitmap == nil {
846		return false
847	}
848
849	return (bm.bitmap[bit/8] & (1 << (ubit & 7))) != 0
850}
851
852func (bm *Bitmap) Set(bit int) {
853	ibit := bit / 8
854	if ibit+1 > len(bm.bitmap) {
855		bm.bitmap = append(bm.bitmap, make([]C.uint8_t, ibit+1-len(bm.bitmap))...)
856	}
857
858	bm.bitmap[ibit] |= 1 << (uint(bit) & 7)
859}
860
861func (bm *Bitmap) SetRange(start int, end int) {
862	for i := start; i <= end; i++ {
863		bm.Set(i)
864	}
865}
866
867func (bm *Bitmap) Clear(bit int) {
868	ubit := uint(bit)
869	if bit > bm.Max() || bm.bitmap == nil {
870		return
871	}
872
873	bm.bitmap[bit/8] &= ^(1 << (ubit & 7))
874}
875
876func (bm *Bitmap) ClearRange(start int, end int) {
877	for i := start; i <= end; i++ {
878		bm.Clear(i)
879	}
880}
881
882func (bm *Bitmap) Max() int {
883	return len(bm.bitmap)*8 - 1
884}
885
886func (bm *Bitmap) IsEmpty() bool {
887	for i := 0; i < len(bm.bitmap); i++ {
888		if bm.bitmap[i] != 0 {
889			return false
890		}
891	}
892	return true
893}
894
895func (a Bitmap) And(b Bitmap) (c Bitmap) {
896	var max, min int
897	if len(a.bitmap) > len(b.bitmap) {
898		max = len(a.bitmap)
899		min = len(b.bitmap)
900	} else {
901		max = len(b.bitmap)
902		min = len(a.bitmap)
903	}
904	c.bitmap = make([]C.uint8_t, max)
905
906	for i := 0; i < min; i++ {
907		c.bitmap[i] = a.bitmap[i] & b.bitmap[i]
908	}
909	return
910}
911
912func (bm Bitmap) String() (s string) {
913	lastOnline := false
914	crange := false
915	printed := false
916	var i int
917	/// --x-xxxxx-x -> 2,4-8,10
918	/// --x-xxxxxxx -> 2,4-10
919	for i = 0; i <= bm.Max(); i++ {
920		if bm.Test(i) {
921			if !lastOnline {
922				// Switching offline -> online, print this cpu
923				if printed {
924					s += ","
925				}
926				s += fmt.Sprintf("%d", i)
927				printed = true
928			} else if !crange {
929				// last was online, but we're not in a range; print -
930				crange = true
931				s += "-"
932			} else {
933				// last was online, we're in a range,  nothing else to do
934			}
935			lastOnline = true
936		} else {
937			if lastOnline {
938				// Switching online->offline; do we need to end a range?
939				if crange {
940					s += fmt.Sprintf("%d", i-1)
941				}
942			}
943			lastOnline = false
944			crange = false
945		}
946	}
947	if lastOnline {
948		// Switching online->offline; do we need to end a range?
949		if crange {
950			s += fmt.Sprintf("%d", i-1)
951		}
952	}
953
954	return
955}
956
957//int libxl_get_max_cpus(libxl_ctx *ctx);
958
959func (ctx *Context) GetMaxCpus() (maxCpus int, err error) {
960	ret := C.libxl_get_max_cpus(ctx.ctx)
961	if ret < 0 {
962		err = Error(ret)
963		return
964	}
965	maxCpus = int(ret)
966	return
967}
968
969//int libxl_get_online_cpus(libxl_ctx *ctx);
970
971func (ctx *Context) GetOnlineCpus() (onCpus int, err error) {
972	ret := C.libxl_get_online_cpus(ctx.ctx)
973	if ret < 0 {
974		err = Error(ret)
975		return
976	}
977	onCpus = int(ret)
978	return
979}
980
981//int libxl_get_max_nodes(libxl_ctx *ctx);
982
983func (ctx *Context) GetMaxNodes() (maxNodes int, err error) {
984	ret := C.libxl_get_max_nodes(ctx.ctx)
985	if ret < 0 {
986		err = Error(ret)
987		return
988	}
989	maxNodes = int(ret)
990	return
991}
992
993//int libxl_get_free_memory(libxl_ctx *ctx, uint64_t *memkb);
994
995func (ctx *Context) GetFreeMemory() (memkb uint64, err error) {
996	var cmem C.uint64_t
997	ret := C.libxl_get_free_memory(ctx.ctx, &cmem)
998
999	if ret < 0 {
1000		err = Error(ret)
1001		return
1002	}
1003
1004	memkb = uint64(cmem)
1005	return
1006
1007}
1008
1009//int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
1010
1011func (ctx *Context) GetPhysinfo() (physinfo *Physinfo, err error) {
1012	var cphys C.libxl_physinfo
1013	C.libxl_physinfo_init(&cphys)
1014	defer C.libxl_physinfo_dispose(&cphys)
1015
1016	ret := C.libxl_get_physinfo(ctx.ctx, &cphys)
1017
1018	if ret < 0 {
1019		err = Error(ret)
1020		return
1021	}
1022	physinfo = &Physinfo{}
1023	err = physinfo.fromC(&cphys)
1024
1025	return
1026}
1027
1028//const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx);
1029
1030func (ctx *Context) GetVersionInfo() (info *VersionInfo, err error) {
1031	var cinfo *C.libxl_version_info
1032
1033	cinfo = C.libxl_get_version_info(ctx.ctx)
1034
1035	info = &VersionInfo{}
1036	err = info.fromC(cinfo)
1037
1038	return
1039}
1040
1041func (ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
1042	var cdi C.libxl_dominfo
1043	C.libxl_dominfo_init(&cdi)
1044	defer C.libxl_dominfo_dispose(&cdi)
1045
1046	ret := C.libxl_domain_info(ctx.ctx, &cdi, C.uint32_t(Id))
1047
1048	if ret != 0 {
1049		err = Error(ret)
1050		return
1051	}
1052
1053	di = &Dominfo{}
1054	err = di.fromC(&cdi)
1055
1056	return
1057}
1058
1059func (ctx *Context) DomainUnpause(Id Domid) (err error) {
1060	ret := C.libxl_domain_unpause(ctx.ctx, C.uint32_t(Id), nil)
1061
1062	if ret != 0 {
1063		err = Error(ret)
1064	}
1065	return
1066}
1067
1068//int libxl_domain_pause(libxl_ctx *ctx, uint32_t domain);
1069
1070func (ctx *Context) DomainPause(id Domid) (err error) {
1071	ret := C.libxl_domain_pause(ctx.ctx, C.uint32_t(id), nil)
1072
1073	if ret != 0 {
1074		err = Error(ret)
1075	}
1076	return
1077}
1078
1079//int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid);
1080
1081func (ctx *Context) DomainShutdown(id Domid) (err error) {
1082	ret := C.libxl_domain_shutdown(ctx.ctx, C.uint32_t(id), nil)
1083
1084	if ret != 0 {
1085		err = Error(ret)
1086	}
1087	return
1088}
1089
1090//int libxl_domain_reboot(libxl_ctx *ctx, uint32_t domid);
1091
1092func (ctx *Context) DomainReboot(id Domid) (err error) {
1093	ret := C.libxl_domain_reboot(ctx.ctx, C.uint32_t(id), nil)
1094
1095	if ret != 0 {
1096		err = Error(ret)
1097	}
1098	return
1099}
1100
1101//libxl_dominfo * libxl_list_domain(libxl_ctx*, int *nb_domain_out);
1102//void libxl_dominfo_list_free(libxl_dominfo *list, int nb_domain);
1103
1104func (ctx *Context) ListDomain() (glist []Dominfo) {
1105	var nbDomain C.int
1106	clist := C.libxl_list_domain(ctx.ctx, &nbDomain)
1107	defer C.libxl_dominfo_list_free(clist, nbDomain)
1108
1109	if int(nbDomain) == 0 {
1110		return
1111	}
1112
1113	gslice := (*[1 << 30]C.libxl_dominfo)(unsafe.Pointer(clist))[:nbDomain:nbDomain]
1114	for i := range gslice {
1115		var info Dominfo
1116		_ = info.fromC(&gslice[i])
1117		glist = append(glist, info)
1118	}
1119
1120	return
1121}
1122
1123//libxl_vcpuinfo *libxl_list_vcpu(libxl_ctx *ctx, uint32_t domid,
1124//				int *nb_vcpu, int *nr_cpus_out);
1125//void libxl_vcpuinfo_list_free(libxl_vcpuinfo *, int nr_vcpus);
1126
1127func (ctx *Context) ListVcpu(id Domid) (glist []Vcpuinfo) {
1128	var nbVcpu C.int
1129	var nrCpu C.int
1130
1131	clist := C.libxl_list_vcpu(ctx.ctx, C.uint32_t(id), &nbVcpu, &nrCpu)
1132	defer C.libxl_vcpuinfo_list_free(clist, nbVcpu)
1133
1134	if int(nbVcpu) == 0 {
1135		return
1136	}
1137
1138	gslice := (*[1 << 30]C.libxl_vcpuinfo)(unsafe.Pointer(clist))[:nbVcpu:nbVcpu]
1139	for i := range gslice {
1140		var info Vcpuinfo
1141		_ = info.fromC(&gslice[i])
1142		glist = append(glist, info)
1143	}
1144
1145	return
1146}
1147
1148func (ct ConsoleType) String() (str string) {
1149	cstr := C.libxl_console_type_to_string(C.libxl_console_type(ct))
1150	str = C.GoString(cstr)
1151
1152	return
1153}
1154
1155//int libxl_console_get_tty(libxl_ctx *ctx, uint32_t domid, int cons_num,
1156//libxl_console_type type, char **path);
1157
1158func (ctx *Context) ConsoleGetTty(id Domid, consNum int, conType ConsoleType) (path string, err error) {
1159	var cpath *C.char
1160	ret := C.libxl_console_get_tty(ctx.ctx, C.uint32_t(id), C.int(consNum), C.libxl_console_type(conType), &cpath)
1161	if ret != 0 {
1162		err = Error(ret)
1163		return
1164	}
1165	defer C.free(unsafe.Pointer(cpath))
1166
1167	path = C.GoString(cpath)
1168	return
1169}
1170
1171//int libxl_primary_console_get_tty(libxl_ctx *ctx, uint32_t domid_vm,
1172//					char **path);
1173
1174func (ctx *Context) PrimaryConsoleGetTty(domid uint32) (path string, err error) {
1175	var cpath *C.char
1176	ret := C.libxl_primary_console_get_tty(ctx.ctx, C.uint32_t(domid), &cpath)
1177	if ret != 0 {
1178		err = Error(ret)
1179		return
1180	}
1181	defer C.free(unsafe.Pointer(cpath))
1182
1183	path = C.GoString(cpath)
1184	return
1185}
1186
1187// DeviceNicAdd adds a nic to a domain.
1188func (ctx *Context) DeviceNicAdd(domid Domid, nic *DeviceNic) error {
1189	var cnic C.libxl_device_nic
1190
1191	if err := nic.toC(&cnic); err != nil {
1192		return err
1193	}
1194	defer C.libxl_device_nic_dispose(&cnic)
1195
1196	ret := C.libxl_device_nic_add(ctx.ctx, C.uint32_t(domid), &cnic, nil)
1197	if ret != 0 {
1198		return Error(ret)
1199	}
1200
1201	return nil
1202}
1203
1204// DeviceNicRemove removes a nic from a domain.
1205func (ctx *Context) DeviceNicRemove(domid Domid, nic *DeviceNic) error {
1206	var cnic C.libxl_device_nic
1207
1208	if err := nic.toC(&cnic); err != nil {
1209		return err
1210	}
1211	defer C.libxl_device_nic_dispose(&cnic)
1212
1213	ret := C.libxl_device_nic_remove(ctx.ctx, C.uint32_t(domid), &cnic, nil)
1214	if ret != 0 {
1215		return Error(ret)
1216	}
1217
1218	return nil
1219}
1220
1221// DevicePciAdd is used to passthrough a PCI device to a domain.
1222func (ctx *Context) DevicePciAdd(domid Domid, pci *DevicePci) error {
1223	var cpci C.libxl_device_pci
1224
1225	if err := pci.toC(&cpci); err != nil {
1226		return err
1227	}
1228	defer C.libxl_device_pci_dispose(&cpci)
1229
1230	ret := C.libxl_device_pci_add(ctx.ctx, C.uint32_t(domid), &cpci, nil)
1231	if ret != 0 {
1232		return Error(ret)
1233	}
1234
1235	return nil
1236}
1237
1238// DevicePciRemove removes a PCI device from a domain.
1239func (ctx *Context) DevicePciRemove(domid Domid, pci *DevicePci) error {
1240	var cpci C.libxl_device_pci
1241
1242	if err := pci.toC(&cpci); err != nil {
1243		return err
1244	}
1245	defer C.libxl_device_pci_dispose(&cpci)
1246
1247	ret := C.libxl_device_pci_remove(ctx.ctx, C.uint32_t(domid), &cpci, nil)
1248	if ret != 0 {
1249		return Error(ret)
1250	}
1251
1252	return nil
1253}
1254
1255// DeviceUsbdevAdd adds a USB device to a domain.
1256func (ctx *Context) DeviceUsbdevAdd(domid Domid, usbdev *DeviceUsbdev) error {
1257	var cusbdev C.libxl_device_usbdev
1258
1259	if err := usbdev.toC(&cusbdev); err != nil {
1260		return err
1261	}
1262	defer C.libxl_device_usbdev_dispose(&cusbdev)
1263
1264	ret := C.libxl_device_usbdev_add(ctx.ctx, C.uint32_t(domid), &cusbdev, nil)
1265	if ret != 0 {
1266		return Error(ret)
1267	}
1268
1269	return nil
1270}
1271
1272// DeviceUsbdevRemove removes a USB device from a domain.
1273func (ctx *Context) DeviceUsbdevRemove(domid Domid, usbdev *DeviceUsbdev) error {
1274	var cusbdev C.libxl_device_usbdev
1275
1276	if err := usbdev.toC(&cusbdev); err != nil {
1277		return err
1278	}
1279	defer C.libxl_device_usbdev_dispose(&cusbdev)
1280
1281	ret := C.libxl_device_usbdev_remove(ctx.ctx, C.uint32_t(domid), &cusbdev, nil)
1282	if ret != 0 {
1283		return Error(ret)
1284	}
1285
1286	return nil
1287}
1288
1289// DomainCreateNew creates a new domain.
1290func (ctx *Context) DomainCreateNew(config *DomainConfig) (Domid, error) {
1291	var cdomid C.uint32_t
1292	var cconfig C.libxl_domain_config
1293	err := config.toC(&cconfig)
1294	if err != nil {
1295		return Domid(0), fmt.Errorf("converting domain config to C: %v", err)
1296	}
1297	defer C.libxl_domain_config_dispose(&cconfig)
1298
1299	ret := C.libxl_domain_create_new(ctx.ctx, &cconfig, &cdomid, nil, nil)
1300	if ret != 0 {
1301		return Domid(0), Error(ret)
1302	}
1303
1304	return Domid(cdomid), nil
1305}
1306
1307// DomainDestroy destroys a domain given a domid.
1308func (ctx *Context) DomainDestroy(domid Domid) error {
1309	ret := C.libxl_domain_destroy(ctx.ctx, C.uint32_t(domid), nil)
1310	if ret != 0 {
1311		return Error(ret)
1312	}
1313
1314	return nil
1315}
1316
1317// SendTrigger sends a Trigger to the domain specified by domid.
1318func (ctx *Context) SendTrigger(domid Domid, trigger Trigger, vcpuid int) error {
1319	ret := C.libxl_send_trigger(ctx.ctx, C.uint32_t(domid),
1320		C.libxl_trigger(trigger), C.uint32_t(vcpuid), nil)
1321	if ret != 0 {
1322		return Error(ret)
1323	}
1324
1325	return nil
1326}
1327