ia64/xen-unstable

view tools/python/xen/xend/image.py @ 17611:36694cae3927

Xend: Fix handling of vnc params.

Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@ab.jp.nec.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu May 08 11:20:04 2008 +0100 (2008-05-08)
parents 18727843db60
children b0d7780794eb
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) 2005 Mike Wray <mike.wray@hp.com>
16 # Copyright (C) 2005-2007 XenSource Ltd
17 #============================================================================
20 import os, os.path, string
21 import re
22 import math
23 import time
24 import signal
26 import xen.lowlevel.xc
27 from xen.xend.XendConstants import *
28 from xen.xend.XendError import VmError, XendError, HVMRequired
29 from xen.xend.XendLogging import log
30 from xen.xend.XendOptions import instance as xenopts
31 from xen.xend.xenstore.xstransact import xstransact
32 from xen.xend.xenstore.xswatch import xswatch
33 from xen.xend import arch
34 from xen.xend import XendOptions
36 xc = xen.lowlevel.xc.xc()
38 MAX_GUEST_CMDLINE = 1024
41 def create(vm, vmConfig):
42 """Create an image handler for a vm.
44 @return ImageHandler instance
45 """
46 return findImageHandlerClass(vmConfig)(vm, vmConfig)
49 class ImageHandler:
50 """Abstract base class for image handlers.
52 createImage() is called to configure and build the domain from its
53 kernel image and ramdisk etc.
55 The method buildDomain() is used to build the domain, and must be
56 defined in a subclass. Usually this is the only method that needs
57 defining in a subclass.
59 The method createDeviceModel() is called to create the domain device
60 model.
62 The method destroyDeviceModel() is called to reap the device model
63 """
65 ostype = None
68 def __init__(self, vm, vmConfig):
69 self.vm = vm
71 self.bootloader = False
72 self.kernel = None
73 self.ramdisk = None
74 self.cmdline = None
76 self.configure(vmConfig)
78 def configure(self, vmConfig):
79 """Config actions common to all unix-like domains."""
80 if '_temp_using_bootloader' in vmConfig:
81 self.bootloader = True
82 self.kernel = vmConfig['_temp_kernel']
83 self.cmdline = vmConfig['_temp_args']
84 self.ramdisk = vmConfig['_temp_ramdisk']
85 else:
86 self.kernel = vmConfig['PV_kernel']
87 self.cmdline = vmConfig['PV_args']
88 self.ramdisk = vmConfig['PV_ramdisk']
89 self.vm.storeVm(("image/ostype", self.ostype),
90 ("image/kernel", self.kernel),
91 ("image/cmdline", self.cmdline),
92 ("image/ramdisk", self.ramdisk))
93 self.vm.permissionsVm("image/cmdline", { 'dom': self.vm.getDomid(), 'read': True } )
95 self.device_model = vmConfig['platform'].get('device_model')
97 self.display = vmConfig['platform'].get('display')
98 self.xauthority = vmConfig['platform'].get('xauthority')
99 self.vncconsole = vmConfig['platform'].get('vncconsole')
100 self.dmargs = self.parseDeviceModelArgs(vmConfig)
101 self.pid = None
102 rtc_timeoffset = vmConfig['platform'].get('rtc_timeoffset')
103 if rtc_timeoffset is not None:
104 xc.domain_set_time_offset(self.vm.getDomid(), int(rtc_timeoffset))
107 def cleanupBootloading(self):
108 if self.bootloader:
109 self.unlink(self.kernel)
110 self.unlink(self.ramdisk)
113 def unlink(self, f):
114 if not f: return
115 try:
116 os.unlink(f)
117 except OSError, ex:
118 log.warning("error removing bootloader file '%s': %s", f, ex)
121 def createImage(self):
122 """Entry point to create domain memory image.
123 Override in subclass if needed.
124 """
125 return self.createDomain()
128 def createDomain(self):
129 """Build the domain boot image.
130 """
131 # Set params and call buildDomain().
133 if self.kernel and not os.path.isfile(self.kernel):
134 raise VmError('Kernel image does not exist: %s' % self.kernel)
135 if self.ramdisk and not os.path.isfile(self.ramdisk):
136 raise VmError('Kernel ramdisk does not exist: %s' % self.ramdisk)
137 if len(self.cmdline) >= MAX_GUEST_CMDLINE:
138 log.warning('kernel cmdline too long, domain %d',
139 self.vm.getDomid())
141 log.info("buildDomain os=%s dom=%d vcpus=%d", self.ostype,
142 self.vm.getDomid(), self.vm.getVCpuCount())
144 result = self.buildDomain()
146 if isinstance(result, dict):
147 return result
148 else:
149 raise VmError('Building domain failed: ostype=%s dom=%d err=%s'
150 % (self.ostype, self.vm.getDomid(), str(result)))
152 def getRequiredAvailableMemory(self, mem_kb):
153 """@param mem_kb The configured maxmem or memory, in KiB.
154 @return The corresponding required amount of memory for the domain,
155 also in KiB. This is normally the given mem_kb, but architecture- or
156 image-specific code may override this to add headroom where
157 necessary."""
158 return mem_kb
160 def getRequiredInitialReservation(self):
161 """@param mem_kb The configured memory, in KiB.
162 @return The corresponding required amount of memory to be free, also
163 in KiB. This is normally the same as getRequiredAvailableMemory, but
164 architecture- or image-specific code may override this to
165 add headroom where necessary."""
166 return self.getRequiredAvailableMemory(self.vm.getMemoryTarget())
168 def getRequiredMaximumReservation(self):
169 """@param mem_kb The maximum possible memory, in KiB.
170 @return The corresponding required amount of memory to be free, also
171 in KiB. This is normally the same as getRequiredAvailableMemory, but
172 architecture- or image-specific code may override this to
173 add headroom where necessary."""
174 return self.getRequiredAvailableMemory(self.vm.getMemoryMaximum())
176 def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
177 """@param shadow_mem_kb The configured shadow memory, in KiB.
178 @param maxmem_kb The configured maxmem, in KiB.
179 @return The corresponding required amount of shadow memory, also in
180 KiB."""
181 # PV domains don't need any shadow memory
182 return 0
184 def buildDomain(self):
185 """Build the domain. Define in subclass."""
186 raise NotImplementedError()
188 def prepareEnvironment(self):
189 """Prepare the environment for the execution of the domain. This
190 method is called before any devices are set up."""
192 domid = self.vm.getDomid()
194 # Delete left-over pipes
195 try:
196 os.unlink('/var/run/tap/qemu-read-%d' % domid)
197 os.unlink('/var/run/tap/qemu-write-%d' % domid)
198 except:
199 pass
201 # No device model, don't create pipes
202 if self.device_model is None:
203 return
205 # If we use a device model, the pipes for communication between
206 # blktapctrl and ioemu must be present before the devices are
207 # created (blktapctrl must access them for new block devices)
209 # mkdir throws an exception if the path already exists
210 try:
211 os.mkdir('/var/run/tap', 0755)
212 except:
213 pass
215 try:
216 os.mkfifo('/var/run/tap/qemu-read-%d' % domid, 0600)
217 os.mkfifo('/var/run/tap/qemu-write-%d' % domid, 0600)
218 except OSError, e:
219 log.warn('Could not create blktap pipes for domain %d' % domid)
220 log.exception(e)
221 pass
224 # Return a list of cmd line args to the device models based on the
225 # xm config file
226 def parseDeviceModelArgs(self, vmConfig):
227 ret = ["-domain-name", str(self.vm.info['name_label'])]
229 # Tell QEMU how large the guest's memory allocation is
230 # to help it when loading the initrd (if neccessary)
231 ret += ["-m", str(self.getRequiredInitialReservation() / 1024)]
233 # Find RFB console device, and if it exists, make QEMU enable
234 # the VNC console.
235 if int(vmConfig['platform'].get('nographic', 0)) != 0:
236 # skip vnc init if nographic is set
237 ret.append('-nographic')
238 return ret
240 vnc_config = {}
241 has_vnc = int(vmConfig['platform'].get('vnc', 0)) != 0
242 has_sdl = int(vmConfig['platform'].get('sdl', 0)) != 0
243 opengl = 1
244 for dev_uuid in vmConfig['console_refs']:
245 dev_type, dev_info = vmConfig['devices'][dev_uuid]
246 if dev_type == 'vfb':
247 vfb_type = dev_info.get('type', {})
248 if vfb_type == 'sdl':
249 self.display = dev_info.get('display', {})
250 self.xauthority = dev_info.get('xauthority', {})
251 opengl = int(dev_info.get('opengl', opengl))
252 has_sdl = True
253 else:
254 vnc_config = dev_info.get('other_config', {})
255 has_vnc = True
256 break
258 keymap = vmConfig['platform'].get("keymap")
259 if keymap:
260 ret.append("-k")
261 ret.append(keymap)
263 if has_vnc:
264 if not vnc_config:
265 for key in ('vncunused', 'vnclisten', 'vncdisplay',
266 'vncpasswd'):
267 if key in vmConfig['platform']:
268 vnc_config[key] = vmConfig['platform'][key]
269 if vnc_config.has_key("vncpasswd"):
270 passwd = vnc_config["vncpasswd"]
271 else:
272 passwd = XendOptions.instance().get_vncpasswd_default()
273 vncopts = ""
274 if passwd:
275 self.vm.storeVm("vncpasswd", passwd)
276 self.vm.permissionsVm("vncpasswd", { 'dom': self.vm.getDomid(), 'read': True } )
277 vncopts = vncopts + ",password"
278 log.debug("Stored a VNC password for vfb access")
279 else:
280 log.debug("No VNC passwd configured for vfb access")
282 if XendOptions.instance().get_vnc_tls():
283 vncx509certdir = XendOptions.instance().get_vnc_x509_cert_dir()
284 vncx509verify = XendOptions.instance().get_vnc_x509_verify()
286 if not os.path.exists(vncx509certdir):
287 raise VmError("VNC x509 certificate dir %s does not exist" % vncx509certdir)
289 if vncx509verify:
290 vncopts = vncopts + ",tls,x509verify=%s" % vncx509certdir
291 else:
292 vncopts = vncopts + ",tls,x509=%s" % vncx509certdir
295 vnclisten = vnc_config.get('vnclisten',
296 XendOptions.instance().get_vnclisten_address())
297 vncdisplay = int(vnc_config.get('vncdisplay', 0))
298 ret.append('-vnc')
299 ret.append("%s:%s%s" % (vnclisten, vncdisplay, vncopts))
301 if int(vnc_config.get('vncunused', 1)) != 0:
302 ret.append('-vncunused')
304 elif has_sdl:
305 # SDL is default in QEMU.
306 if int(vmConfig['platform'].get('opengl', opengl)) != 1 :
307 ret.append('-disable-opengl')
308 else:
309 ret.append('-nographic')
311 if int(vmConfig['platform'].get('monitor', 0)) != 0:
312 ret = ret + ['-monitor', 'vc']
313 return ret
315 def getDeviceModelArgs(self, restore = False):
316 args = [self.device_model]
317 args = args + ([ "-d", "%d" % self.vm.getDomid() ])
318 args = args + self.dmargs
319 return args
321 def createDeviceModel(self, restore = False):
322 if self.device_model is None:
323 return
324 if self.pid:
325 return
326 # Execute device model.
327 #todo: Error handling
328 args = self.getDeviceModelArgs(restore)
329 env = dict(os.environ)
330 if self.display:
331 env['DISPLAY'] = self.display
332 if self.xauthority:
333 env['XAUTHORITY'] = self.xauthority
334 if self.vncconsole:
335 args = args + ([ "-vncviewer" ])
336 xstransact.Mkdir("/local/domain/0/device-model/%i" % self.vm.getDomid())
337 xstransact.SetPermissions("/local/domain/0/device-model/%i" % self.vm.getDomid(),
338 { 'dom': self.vm.getDomid(), 'read': True, 'write': True })
339 log.info("spawning device models: %s %s", self.device_model, args)
340 # keep track of pid and spawned options to kill it later
342 logfile = "/var/log/xen/qemu-dm-%s.log" % str(self.vm.info['name_label'])
343 if os.path.exists(logfile):
344 if os.path.exists(logfile + ".1"):
345 os.unlink(logfile + ".1")
346 os.rename(logfile, logfile + ".1")
348 null = os.open("/dev/null", os.O_RDONLY)
349 logfd = os.open(logfile, os.O_WRONLY|os.O_CREAT|os.O_TRUNC)
351 pid = os.fork()
352 if pid == 0: #child
353 try:
354 os.dup2(null, 0)
355 os.dup2(logfd, 1)
356 os.dup2(logfd, 2)
357 os.close(null)
358 os.close(logfd)
359 try:
360 os.execve(self.device_model, args, env)
361 except:
362 os._exit(127)
363 except:
364 os._exit(127)
365 else:
366 self.pid = pid
367 os.close(null)
368 os.close(logfd)
369 self.vm.storeDom("image/device-model-pid", self.pid)
370 log.info("device model pid: %d", self.pid)
372 def signalDeviceModel(self, cmd, ret, par = None):
373 if self.device_model is None:
374 return
375 # Signal the device model to for action
376 if cmd is '' or ret is '':
377 raise VmError('need valid command and result when signal device model')
379 orig_state = xstransact.Read("/local/domain/0/device-model/%i/state"
380 % self.vm.getDomid())
382 if par is not None:
383 xstransact.Store("/local/domain/0/device-model/%i"
384 % self.vm.getDomid(), ('parameter', par))
386 xstransact.Store("/local/domain/0/device-model/%i"
387 % self.vm.getDomid(), ('command', cmd))
388 # Wait for confirmation. Could do this with a watch but we'd
389 # still end up spinning here waiting for the watch to fire.
390 state = ''
391 count = 0
392 while state != ret:
393 state = xstransact.Read("/local/domain/0/device-model/%i/state"
394 % self.vm.getDomid())
395 time.sleep(0.1)
396 count += 1
397 if count > 100:
398 raise VmError('Timed out waiting for device model action')
400 #resotre orig state
401 xstransact.Store("/local/domain/0/device-model/%i"
402 % self.vm.getDomid(), ('state', orig_state))
403 log.info("signalDeviceModel:restore dm state to %s", orig_state)
405 def saveDeviceModel(self):
406 # Signal the device model to pause itself and save its state
407 self.signalDeviceModel('save', 'paused')
409 def resumeDeviceModel(self):
410 if self.device_model is None:
411 return
412 # Signal the device model to resume activity after pausing to save.
413 xstransact.Store("/local/domain/0/device-model/%i"
414 % self.vm.getDomid(), ('command', 'continue'))
416 def recreate(self):
417 if self.device_model is None:
418 return
419 self.pid = self.vm.gatherDom(('image/device-model-pid', int))
421 def destroyDeviceModel(self):
422 if self.device_model is None:
423 return
424 if self.pid:
425 try:
426 os.kill(self.pid, signal.SIGHUP)
427 except OSError, exn:
428 log.exception(exn)
429 try:
430 # Try to reap the child every 100ms for 10s. Then SIGKILL it.
431 for i in xrange(100):
432 (p, rv) = os.waitpid(self.pid, os.WNOHANG)
433 if p == self.pid:
434 break
435 time.sleep(0.1)
436 else:
437 log.warning("DeviceModel %d took more than 10s "
438 "to terminate: sending SIGKILL" % self.pid)
439 os.kill(self.pid, signal.SIGKILL)
440 os.waitpid(self.pid, 0)
441 except OSError, exn:
442 # This is expected if Xend has been restarted within the
443 # life of this domain. In this case, we can kill the process,
444 # but we can't wait for it because it's not our child.
445 # We just make really sure it's going away (SIGKILL) first.
446 os.kill(self.pid, signal.SIGKILL)
447 self.pid = None
448 state = xstransact.Remove("/local/domain/0/device-model/%i"
449 % self.vm.getDomid())
451 try:
452 os.unlink('/var/run/tap/qemu-read-%d' % self.vm.getDomid())
453 os.unlink('/var/run/tap/qemu-write-%d' % self.vm.getDomid())
454 except:
455 pass
458 class LinuxImageHandler(ImageHandler):
460 ostype = "linux"
461 flags = 0
462 vhpt = 0
464 def configure(self, vmConfig):
465 ImageHandler.configure(self, vmConfig)
467 def buildDomain(self):
468 store_evtchn = self.vm.getStorePort()
469 console_evtchn = self.vm.getConsolePort()
471 mem_mb = self.getRequiredInitialReservation() / 1024
473 log.debug("domid = %d", self.vm.getDomid())
474 log.debug("memsize = %d", mem_mb)
475 log.debug("image = %s", self.kernel)
476 log.debug("store_evtchn = %d", store_evtchn)
477 log.debug("console_evtchn = %d", console_evtchn)
478 log.debug("cmdline = %s", self.cmdline)
479 log.debug("ramdisk = %s", self.ramdisk)
480 log.debug("vcpus = %d", self.vm.getVCpuCount())
481 log.debug("features = %s", self.vm.getFeatures())
482 if arch.type == "ia64":
483 log.debug("vhpt = %d", self.flags)
485 return xc.linux_build(domid = self.vm.getDomid(),
486 memsize = mem_mb,
487 image = self.kernel,
488 store_evtchn = store_evtchn,
489 console_evtchn = console_evtchn,
490 cmdline = self.cmdline,
491 ramdisk = self.ramdisk,
492 features = self.vm.getFeatures(),
493 flags = self.flags,
494 vhpt = self.vhpt)
496 def parseDeviceModelArgs(self, vmConfig):
497 ret = ImageHandler.parseDeviceModelArgs(self, vmConfig)
498 # Equivalent to old xenconsoled behaviour. Should make
499 # it configurable in future
500 ret = ret + ["-serial", "pty"]
501 return ret
503 def getDeviceModelArgs(self, restore = False):
504 args = ImageHandler.getDeviceModelArgs(self, restore)
505 args = args + ([ "-M", "xenpv"])
506 return args
509 class PPC_LinuxImageHandler(LinuxImageHandler):
511 ostype = "linux"
513 def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
514 """@param shadow_mem_kb The configured shadow memory, in KiB.
515 @param maxmem_kb The configured maxmem, in KiB.
516 @return The corresponding required amount of shadow memory, also in
517 KiB.
518 PowerPC currently uses "shadow memory" to refer to the hash table."""
519 return max(maxmem_kb / 64, shadow_mem_kb)
523 class HVMImageHandler(ImageHandler):
525 ostype = "hvm"
527 def __init__(self, vm, vmConfig):
528 ImageHandler.__init__(self, vm, vmConfig)
529 self.shutdownWatch = None
530 self.rebootFeatureWatch = None
532 def configure(self, vmConfig):
533 ImageHandler.configure(self, vmConfig)
535 self.loader = vmConfig['platform'].get('loader')
537 info = xc.xeninfo()
538 if 'hvm' not in info['xen_caps']:
539 raise HVMRequired()
541 rtc_timeoffset = vmConfig['platform'].get('rtc_timeoffset')
543 self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)),
544 ("image/device-model", self.device_model),
545 ("image/display", self.display))
546 self.vm.permissionsVm("image/dmargs", { 'dom': self.vm.getDomid(), 'read': True } )
547 self.vm.storeVm(("rtc/timeoffset", rtc_timeoffset))
548 self.vm.permissionsVm("rtc/timeoffset", { 'dom': self.vm.getDomid(), 'read': True } )
550 self.apic = int(vmConfig['platform'].get('apic', 0))
551 self.acpi = int(vmConfig['platform'].get('acpi', 0))
552 self.guest_os_type = vmConfig['platform'].get('guest_os_type')
554 self.vmConfig = vmConfig
556 def setCpuid(self):
557 xc.domain_set_policy_cpuid(self.vm.getDomid())
559 if 'cpuid' in self.vmConfig:
560 cpuid = self.vmConfig['cpuid']
561 transformed = {}
562 for sinput, regs in cpuid.iteritems():
563 inputs = sinput.split(',')
564 input = long(inputs[0])
565 sub_input = None
566 if len(inputs) == 2:
567 sub_input = long(inputs[1])
568 t = xc.domain_set_cpuid(self.vm.getDomid(),
569 input, sub_input, regs)
570 transformed[sinput] = t
571 self.vmConfig['cpuid'] = transformed
573 if 'cpuid_check' in self.vmConfig:
574 cpuid_check = self.vmConfig['cpuid_check']
575 transformed = {}
576 for sinput, regs_check in cpuid_check.iteritems():
577 inputs = sinput.split(',')
578 input = long(inputs[0])
579 sub_input = None
580 if len(inputs) == 2:
581 sub_input = long(inputs[1])
582 t = xc.domain_check_cpuid(input, sub_input, regs_check)
583 transformed[sinput] = t
584 self.vmConfig['cpuid_check'] = transformed
586 # Return a list of cmd line args to the device models based on the
587 # xm config file
588 def parseDeviceModelArgs(self, vmConfig):
589 ret = ImageHandler.parseDeviceModelArgs(self, vmConfig)
590 ret = ret + ['-vcpus', str(self.vm.getVCpuCount())]
592 if self.kernel:
593 log.debug("kernel = %s", self.kernel)
594 ret = ret + ['-kernel', self.kernel]
595 if self.ramdisk:
596 log.debug("ramdisk = %s", self.ramdisk)
597 ret = ret + ['-initrd', self.ramdisk]
598 if self.cmdline:
599 log.debug("cmdline = %s", self.cmdline)
600 ret = ret + ['-append', self.cmdline]
603 dmargs = [ 'boot', 'fda', 'fdb', 'soundhw',
604 'localtime', 'serial', 'stdvga', 'isa',
605 'acpi', 'usb', 'usbdevice' ]
607 for a in dmargs:
608 v = vmConfig['platform'].get(a)
610 # python doesn't allow '-' in variable names
611 if a == 'stdvga': a = 'std-vga'
612 if a == 'keymap': a = 'k'
614 # Handle booleans gracefully
615 if a in ['localtime', 'std-vga', 'isa', 'usb', 'acpi']:
616 try:
617 if v != None: v = int(v)
618 if v: ret.append("-%s" % a)
619 except (ValueError, TypeError):
620 pass # if we can't convert it to a sane type, ignore it
621 else:
622 if v:
623 ret.append("-%s" % a)
624 ret.append("%s" % v)
626 if a in ['fda', 'fdb']:
627 if v:
628 if not os.path.isabs(v):
629 raise VmError("Floppy file %s does not exist." % v)
630 log.debug("args: %s, val: %s" % (a,v))
632 # Handle disk/network related options
633 mac = None
634 nics = 0
636 for devuuid in vmConfig['vbd_refs']:
637 devinfo = vmConfig['devices'][devuuid][1]
638 uname = devinfo.get('uname')
639 if uname is not None and 'file:' in uname:
640 (_, vbdparam) = string.split(uname, ':', 1)
641 if not os.path.isfile(vbdparam):
642 raise VmError('Disk image does not exist: %s' %
643 vbdparam)
645 for devuuid in vmConfig['vif_refs']:
646 devinfo = vmConfig['devices'][devuuid][1]
647 dtype = devinfo.get('type', 'ioemu')
648 if dtype != 'ioemu':
649 continue
650 nics += 1
651 mac = devinfo.get('mac')
652 if mac is None:
653 raise VmError("MAC address not specified or generated.")
654 bridge = devinfo.get('bridge', 'xenbr0')
655 model = devinfo.get('model', 'rtl8139')
656 ret.append("-net")
657 ret.append("nic,vlan=%d,macaddr=%s,model=%s" %
658 (nics, mac, model))
659 ret.append("-net")
660 ret.append("tap,vlan=%d,ifname=tap%d.%d,bridge=%s" %
661 (nics, self.vm.getDomid(), nics-1, bridge))
663 return ret
665 def getDeviceModelArgs(self, restore = False):
666 args = ImageHandler.getDeviceModelArgs(self, restore)
667 args = args + ([ "-M", "xenfv"])
668 if restore:
669 args = args + ([ "-loadvm", "/var/lib/xen/qemu-save.%d" %
670 self.vm.getDomid() ])
671 return args
673 def buildDomain(self):
674 store_evtchn = self.vm.getStorePort()
676 mem_mb = self.getRequiredInitialReservation() / 1024
678 log.debug("domid = %d", self.vm.getDomid())
679 log.debug("image = %s", self.loader)
680 log.debug("store_evtchn = %d", store_evtchn)
681 log.debug("memsize = %d", mem_mb)
682 log.debug("vcpus = %d", self.vm.getVCpuCount())
683 log.debug("acpi = %d", self.acpi)
684 log.debug("apic = %d", self.apic)
686 rc = xc.hvm_build(domid = self.vm.getDomid(),
687 image = self.loader,
688 memsize = mem_mb,
689 vcpus = self.vm.getVCpuCount(),
690 acpi = self.acpi,
691 apic = self.apic)
692 rc['notes'] = { 'SUSPEND_CANCEL': 1 }
694 rc['store_mfn'] = xc.hvm_get_param(self.vm.getDomid(),
695 HVM_PARAM_STORE_PFN)
696 xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_STORE_EVTCHN,
697 store_evtchn)
699 return rc
702 class IA64_HVM_ImageHandler(HVMImageHandler):
704 def configure(self, vmConfig):
705 HVMImageHandler.configure(self, vmConfig)
706 self.vhpt = int(vmConfig['platform'].get('vhpt', 0))
708 def buildDomain(self):
709 xc.nvram_init(self.vm.getName(), self.vm.getDomid())
710 xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_VHPT_SIZE, self.vhpt)
711 if self.guest_os_type is not None:
712 xc.set_os_type(self.guest_os_type.lower(), self.vm.getDomid())
713 return HVMImageHandler.buildDomain(self)
715 def getRequiredAvailableMemory(self, mem_kb):
716 page_kb = 16
717 # ROM size for guest firmware, io page, xenstore page
718 # buffer io page, buffer pio page and memmap info page
719 extra_pages = 1024 + 5
720 mem_kb += extra_pages * page_kb
721 # Add 8 MiB overhead for QEMU's video RAM.
722 return mem_kb + 8192
724 def getRequiredInitialReservation(self):
725 return self.vm.getMemoryTarget()
727 def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
728 # Explicit shadow memory is not a concept
729 return 0
731 def getDeviceModelArgs(self, restore = False):
732 args = HVMImageHandler.getDeviceModelArgs(self, restore)
733 args = args + ([ "-m", "%s" %
734 (self.getRequiredInitialReservation() / 1024) ])
735 return args
738 class IA64_Linux_ImageHandler(LinuxImageHandler):
740 def configure(self, vmConfig):
741 LinuxImageHandler.configure(self, vmConfig)
742 self.vhpt = int(vmConfig['platform'].get('vhpt', 0))
745 class X86_HVM_ImageHandler(HVMImageHandler):
747 def configure(self, vmConfig):
748 HVMImageHandler.configure(self, vmConfig)
749 self.pae = int(vmConfig['platform'].get('pae', 0))
751 def buildDomain(self):
752 xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_PAE_ENABLED, self.pae)
753 self.setCpuid()
754 return HVMImageHandler.buildDomain(self)
756 def getRequiredAvailableMemory(self, mem_kb):
757 # Add 8 MiB overhead for QEMU's video RAM.
758 return mem_kb + 8192
760 def getRequiredInitialReservation(self):
761 return self.vm.getMemoryTarget()
763 def getRequiredMaximumReservation(self):
764 return self.vm.getMemoryMaximum()
766 def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
767 # 256 pages (1MB) per vcpu,
768 # plus 1 page per MiB of RAM for the P2M map,
769 # plus 1 page per MiB of RAM to shadow the resident processes.
770 # This is higher than the minimum that Xen would allocate if no value
771 # were given (but the Xen minimum is for safety, not performance).
772 return max(4 * (256 * self.vm.getVCpuCount() + 2 * (maxmem_kb / 1024)),
773 shadow_mem_kb)
776 class X86_Linux_ImageHandler(LinuxImageHandler):
778 def buildDomain(self):
779 # set physical mapping limit
780 # add an 8MB slack to balance backend allocations.
781 mem_kb = self.getRequiredMaximumReservation() + (8 * 1024)
782 xc.domain_set_memmap_limit(self.vm.getDomid(), mem_kb)
783 return LinuxImageHandler.buildDomain(self)
785 _handlers = {
786 "powerpc": {
787 "linux": PPC_LinuxImageHandler,
788 },
789 "ia64": {
790 "linux": IA64_Linux_ImageHandler,
791 "hvm": IA64_HVM_ImageHandler,
792 },
793 "x86": {
794 "linux": X86_Linux_ImageHandler,
795 "hvm": X86_HVM_ImageHandler,
796 },
797 }
799 def findImageHandlerClass(image):
800 """Find the image handler class for an image config.
802 @param image config
803 @return ImageHandler subclass or None
804 """
805 image_type = image.image_type()
806 try:
807 return _handlers[arch.type][image_type]
808 except KeyError:
809 raise VmError('unknown image type: ' + image_type)