ia64/xen-unstable

view tools/python/xen/xend/XendDomain.py @ 7639:c352591ebfdf

Add support for the ioport_permission dom0 op to xend and xm

xm now accepts a parameter 'ioports' that accepts a hex ioport
or ioport range, in the form 02f8[-02ff]

Signed-off-by: Jody Belka <knew (at) pimb (dot) org>
author kaf24@firebug.cl.cam.ac.uk
date Sun Nov 06 16:40:33 2005 +0100 (2005-11-06)
parents 94cee9a918de
children 270469d40f02
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
16 # Copyright (C) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
17 # Copyright (C) 2005 XenSource Ltd
18 #============================================================================
20 """Handler for domain operations.
21 Nothing here is persistent (across reboots).
22 Needs to be persistent for one uptime.
23 """
25 import logging
26 import os
27 import sys
28 import threading
30 import xen.lowlevel.xc
32 import XendDomainInfo
34 from xen.xend import XendRoot
35 from xen.xend import XendCheckpoint
36 from xen.xend.XendError import XendError
37 from xen.xend.XendLogging import log
38 from xen.xend.server import relocate
41 xc = xen.lowlevel.xc.new()
42 xroot = XendRoot.instance()
45 __all__ = [ "XendDomain" ]
47 PRIV_DOMAIN = 0
49 class XendDomain:
50 """Index of all domains. Singleton.
51 """
53 ## public:
55 def __init__(self):
56 # Hack alert. Python does not support mutual imports, but XendDomainInfo
57 # needs access to the XendDomain instance to look up domains. Attempting
58 # to import XendDomain from XendDomainInfo causes unbounded recursion.
59 # So we stuff the XendDomain instance (self) into xroot's components.
60 xroot.add_component("xen.xend.XendDomain", self)
61 self.domains = {}
62 self.domains_lock = threading.RLock()
63 self.watchReleaseDomain()
65 self.domains_lock.acquire()
66 try:
67 self._add_domain(
68 XendDomainInfo.recreate(self.xen_domains()[PRIV_DOMAIN],
69 True))
70 self.dom0_setup()
71 self.refresh(True)
72 finally:
73 self.domains_lock.release()
76 def list(self):
77 """Get list of domain objects.
79 @return: domain objects
80 """
81 self.domains_lock.acquire()
82 try:
83 self.refresh()
84 return self.domains.values()
85 finally:
86 self.domains_lock.release()
89 def list_sorted(self):
90 """Get list of domain objects, sorted by name.
92 @return: domain objects
93 """
94 doms = self.list()
95 doms.sort(lambda x, y: cmp(x.getName(), y.getName()))
96 return doms
98 def list_names(self):
99 """Get list of domain names.
101 @return: domain names
102 """
103 doms = self.list_sorted()
104 return map(lambda x: x.getName(), doms)
107 ## private:
109 def onReleaseDomain(self):
110 self.domains_lock.acquire()
111 try:
112 self.refresh()
113 finally:
114 self.domains_lock.release()
117 def watchReleaseDomain(self):
118 from xen.xend.xenstore.xswatch import xswatch
119 self.releaseDomain = xswatch("@releaseDomain", self.onReleaseDomain)
122 def xen_domains(self):
123 """Get table of domains indexed by id from xc. Expects to be
124 protected by the domains_lock.
125 """
126 domlist = xc.domain_getinfo()
127 doms = {}
128 for d in domlist:
129 domid = d['dom']
130 doms[domid] = d
131 return doms
134 def dom0_setup(self):
135 """Expects to be protected by the domains_lock."""
136 dom0 = self.domains[PRIV_DOMAIN]
138 # get max number of vcpus to use for dom0 from config
139 target = int(xroot.get_dom0_vcpus())
140 log.debug("number of vcpus to use is %d", target)
142 # target == 0 means use all processors
143 if target > 0:
144 dom0.setVCpuCount(target)
147 def _add_domain(self, info):
148 """Add the given domain entry to this instance's internal cache.
149 Expects to be protected by the domains_lock.
150 """
151 self.domains[info.getDomid()] = info
154 def _delete_domain(self, domid):
155 """Remove the given domain from this instance's internal cache.
156 Expects to be protected by the domains_lock.
157 """
158 info = self.domains.get(domid)
159 if info:
160 del self.domains[domid]
161 info.cleanupDomain()
164 def refresh(self, initialising = False):
165 """Refresh domain list from Xen. Expects to be protected by the
166 domains_lock.
168 @param initialising True if this is the first refresh after starting
169 Xend. This does not change this method's behaviour, except for
170 logging.
171 """
172 doms = self.xen_domains()
173 for d in self.domains.values():
174 info = doms.get(d.getDomid())
175 if info:
176 d.update(info)
177 else:
178 self._delete_domain(d.getDomid())
179 for d in doms:
180 if d not in self.domains:
181 if doms[d]['dying']:
182 log.log(initialising and logging.ERROR or logging.DEBUG,
183 'Cannot recreate information for dying domain %d.'
184 ' Xend will ignore this domain from now on.',
185 doms[d]['dom'])
186 elif d == PRIV_DOMAIN:
187 log.fatal(
188 "No record of privileged domain %d! Terminating.", d)
189 sys.exit(1)
190 else:
191 try:
192 self._add_domain(
193 XendDomainInfo.recreate(doms[d], False))
194 except:
195 log.exception(
196 "Failed to recreate information for domain "
197 "%d. Destroying it in the hope of "
198 "recovery.", d)
199 try:
200 xc.domain_destroy(dom = d)
201 except:
202 log.exception('Destruction of %d failed.', d)
205 ## public:
207 def domain_create(self, config):
208 """Create a domain from a configuration.
210 @param config: configuration
211 @return: domain
212 """
213 self.domains_lock.acquire()
214 try:
215 dominfo = XendDomainInfo.create(config)
216 self._add_domain(dominfo)
217 return dominfo
218 finally:
219 self.domains_lock.release()
222 def domain_configure(self, config):
223 """Configure an existing domain.
225 @param vmconfig: vm configuration
226 """
227 # !!!
228 raise XendError("Unsupported")
230 def domain_restore(self, src):
231 """Restore a domain from file.
233 @param src: source file
234 """
236 try:
237 fd = os.open(src, os.O_RDONLY)
238 try:
239 return self.domain_restore_fd(fd)
240 finally:
241 os.close(fd)
242 except OSError, ex:
243 raise XendError("can't read guest state file %s: %s" %
244 (src, ex[1]))
246 def domain_restore_fd(self, fd):
247 """Restore a domain from the given file descriptor."""
249 try:
250 return XendCheckpoint.restore(self, fd)
251 except:
252 # I don't really want to log this exception here, but the error
253 # handling in the relocation-socket handling code (relocate.py) is
254 # poor, so we need to log this for debugging.
255 log.exception("Restore failed")
256 raise
259 def restore_(self, config):
260 """Create a domain as part of the restore process. This is called
261 only from {@link XendCheckpoint}.
263 A restore request comes into XendDomain through {@link
264 #domain_restore} or {@link #domain_restore_fd}. That request is
265 forwarded immediately to XendCheckpoint which, when it is ready, will
266 call this method. It is necessary to come through here rather than go
267 directly to {@link XendDomainInfo.restore} because we need to
268 serialise the domain creation process, but cannot lock
269 domain_restore_fd as a whole, otherwise we will deadlock waiting for
270 the old domain to die.
271 """
272 self.domains_lock.acquire()
273 try:
274 dominfo = XendDomainInfo.restore(config)
275 self._add_domain(dominfo)
276 return dominfo
277 finally:
278 self.domains_lock.release()
281 def domain_lookup(self, domid):
282 self.domains_lock.acquire()
283 try:
284 self.refresh()
285 return self.domains.get(domid)
286 finally:
287 self.domains_lock.release()
290 def domain_lookup_nr(self, domid):
291 self.domains_lock.acquire()
292 try:
293 return self.domains.get(domid)
294 finally:
295 self.domains_lock.release()
298 def domain_lookup_by_name_or_id(self, name):
299 self.domains_lock.acquire()
300 try:
301 self.refresh()
302 return self.domain_lookup_by_name_or_id_nr(name)
303 finally:
304 self.domains_lock.release()
307 def domain_lookup_by_name_or_id_nr(self, name):
308 self.domains_lock.acquire()
309 try:
310 dominfo = self.domain_lookup_by_name_nr(name)
312 if dominfo:
313 return dominfo
314 else:
315 try:
316 return self.domains.get(int(name))
317 except ValueError:
318 return None
319 finally:
320 self.domains_lock.release()
323 def domain_lookup_by_name_nr(self, name):
324 self.domains_lock.acquire()
325 try:
326 matching = filter(lambda d: d.getName() == name,
327 self.domains.values())
328 n = len(matching)
329 if n == 1:
330 return matching[0]
331 return None
332 finally:
333 self.domains_lock.release()
336 def privilegedDomain(self):
337 self.domains_lock.acquire()
338 try:
339 return self.domains[PRIV_DOMAIN]
340 finally:
341 self.domains_lock.release()
344 def domain_unpause(self, domid):
345 """Unpause domain execution."""
346 try:
347 dominfo = self.domain_lookup(domid)
348 log.info("Domain %s (%d) unpaused.", dominfo.getName(),
349 dominfo.getDomid())
350 return dominfo.unpause()
351 except Exception, ex:
352 raise XendError(str(ex))
355 def domain_pause(self, domid):
356 """Pause domain execution."""
357 try:
358 dominfo = self.domain_lookup(domid)
359 log.info("Domain %s (%d) paused.", dominfo.getName(),
360 dominfo.getDomid())
361 return dominfo.pause()
362 except Exception, ex:
363 raise XendError(str(ex))
366 def domain_destroy(self, domid):
367 """Terminate domain immediately."""
369 if domid == PRIV_DOMAIN:
370 raise XendError("Cannot destroy privileged domain %i" % domid)
372 dominfo = self.domain_lookup(domid)
373 if dominfo:
374 val = dominfo.destroy()
375 else:
376 try:
377 val = xc.domain_destroy(dom=domid)
378 except Exception, ex:
379 raise XendError(str(ex))
380 return val
382 def domain_migrate(self, domid, dst, live=False, resource=0):
383 """Start domain migration."""
385 dominfo = self.domain_lookup(domid)
387 port = xroot.get_xend_relocation_port()
388 sock = relocate.setupRelocation(dst, port)
390 XendCheckpoint.save(sock.fileno(), dominfo, live)
393 def domain_save(self, domid, dst):
394 """Start saving a domain to file.
396 @param dst: destination file
397 """
399 try:
400 dominfo = self.domain_lookup(domid)
402 fd = os.open(dst, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
403 try:
404 # For now we don't support 'live checkpoint'
405 return XendCheckpoint.save(fd, dominfo, False)
406 finally:
407 os.close(fd)
408 except OSError, ex:
409 raise XendError("can't write guest state file %s: %s" %
410 (dst, ex[1]))
412 def domain_pincpu(self, domid, vcpu, cpumap):
413 """Set which cpus vcpu can use
415 @param cpumap: string repr of list of usable cpus
416 """
417 dominfo = self.domain_lookup(domid)
418 # convert cpumap string into a list of ints
419 cpumap = map(lambda x: int(x),
420 cpumap.replace("[", "").replace("]", "").split(","))
421 try:
422 return xc.domain_pincpu(dominfo.getDomid(), vcpu, cpumap)
423 except Exception, ex:
424 raise XendError(str(ex))
426 def domain_cpu_bvt_set(self, domid, mcuadv, warpback, warpvalue, warpl,
427 warpu):
428 """Set BVT (Borrowed Virtual Time) scheduler parameters for a domain.
429 """
430 dominfo = self.domain_lookup(domid)
431 try:
432 return xc.bvtsched_domain_set(dom=dominfo.getDomid(),
433 mcuadv=mcuadv,
434 warpback=warpback,
435 warpvalue=warpvalue,
436 warpl=warpl, warpu=warpu)
437 except Exception, ex:
438 raise XendError(str(ex))
440 def domain_cpu_bvt_get(self, domid):
441 """Get BVT (Borrowed Virtual Time) scheduler parameters for a domain.
442 """
443 dominfo = self.domain_lookup(domid)
444 try:
445 return xc.bvtsched_domain_get(dominfo.getDomid())
446 except Exception, ex:
447 raise XendError(str(ex))
450 def domain_cpu_sedf_set(self, domid, period, slice_, latency, extratime,
451 weight):
452 """Set Simple EDF scheduler parameters for a domain.
453 """
454 dominfo = self.domain_lookup(domid)
455 try:
456 return xc.sedf_domain_set(dominfo.getDomid(), period, slice_,
457 latency, extratime, weight)
458 except Exception, ex:
459 raise XendError(str(ex))
461 def domain_cpu_sedf_get(self, domid):
462 """Get Simple EDF scheduler parameters for a domain.
463 """
464 dominfo = self.domain_lookup(domid)
465 try:
466 return xc.sedf_domain_get(dominfo.getDomid())
467 except Exception, ex:
468 raise XendError(str(ex))
471 def domain_vif_limit_set(self, domid, vif, credit, period):
472 """Limit the vif's transmission rate
473 """
474 dominfo = self.domain_lookup(domid)
475 dev = dominfo.getDevice('vif', vif)
476 if not dev:
477 raise XendError("invalid vif")
478 return dev.setCreditLimit(credit, period)
481 def domain_maxmem_set(self, domid, mem):
482 """Set the memory limit for a domain.
484 @param mem: memory limit (in MiB)
485 @return: 0 on success, -1 on error
486 """
487 dominfo = self.domain_lookup(domid)
488 maxmem = int(mem) * 1024
489 try:
490 return xc.domain_setmaxmem(dominfo.getDomid(),
491 maxmem_kb = maxmem)
492 except Exception, ex:
493 raise XendError(str(ex))
495 def domain_ioport_range_enable(self, domid, first, last):
496 """Enable access to a range of IO ports for a domain
498 @param first: first IO port
499 @param last: last IO port
500 @return: 0 on success, -1 on error
501 """
502 dominfo = self.domain_lookup(domid)
503 nr_ports = last - first + 1
504 try:
505 return xc.domain_ioport_permission(dominfo.getDomid(),
506 first_port = first,
507 nr_ports = nr_ports,
508 allow_access = 1)
509 except Exception, ex:
510 raise XendError(str(ex))
512 def domain_ioport_range_disable(self, domid, first, last):
513 """Disable access to a range of IO ports for a domain
515 @param first: first IO port
516 @param last: last IO port
517 @return: 0 on success, -1 on error
518 """
519 dominfo = self.domain_lookup(domid)
520 nr_ports = last - first + 1
521 try:
522 return xc.domain_ioport_permission(dominfo.getDomid(),
523 first_port = first,
524 nr_ports = nr_ports,
525 allow_access = 0)
526 except Exception, ex:
527 raise XendError(str(ex))
530 def instance():
531 """Singleton constructor. Use this instead of the class constructor.
532 """
533 global inst
534 try:
535 inst
536 except:
537 inst = XendDomain()
538 return inst