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.
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.
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
33
import xen.lowlevel.xc
34
from xen.xend.XendConstants import *
35
from xen.xend.XendError import VmError, XendError, HVMRequired
36
from xen.xend.XendLogging import log
37
from xen.xend.XendOptions import instance as xenopts
38
from xen.xend.xenstore.xstransact import xstransact
39
from xen.xend.xenstore.xswatch import xswatch
40
from xen.xend import arch
41
from xen.xend import XendOptions
42
from xen.util import oshelp
43
from xen.util import utils
44
from xen.xend import osdep
46
xc = xen.lowlevel.xc.xc()
48
MAX_GUEST_CMDLINE = 1024
50
sentinel_path_prefix = '/var/run/xend/dm-'
51
sentinel_fifos_inuse = { }
53
def cleanup_stale_sentinel_fifos():
54
for path in glob.glob(sentinel_path_prefix + '*.fifo'):
55
if path in sentinel_fifos_inuse: continue
58
log.warning('could not delete stale fifo %s: %s',
59
path, utils.exception_string(e))
61
def create(vm, vmConfig):
62
"""Create an image handler for a vm.
64
@return ImageHandler instance
66
return findImageHandlerClass(vmConfig)(vm, vmConfig)
70
"""Abstract base class for image handlers.
72
createImage() is called to configure and build the domain from its
73
kernel image and ramdisk etc.
75
The method buildDomain() is used to build the domain, and must be
76
defined in a subclass. Usually this is the only method that needs
77
defining in a subclass.
79
The method createDeviceModel() is called to create the domain device
82
The method destroyDeviceModel() is called to reap the device model
89
def __init__(self, vm, vmConfig):
92
self.bootloader = False
93
self.use_tmp_kernel = False
94
self.use_tmp_ramdisk = False
99
self.configure(vmConfig)
101
def configure(self, vmConfig):
102
"""Config actions common to all unix-like domains."""
103
if '_temp_using_bootloader' in vmConfig:
104
self.bootloader = True
105
self.kernel = vmConfig['_temp_kernel']
106
self.cmdline = vmConfig['_temp_args']
107
self.ramdisk = vmConfig['_temp_ramdisk']
109
self.kernel = vmConfig['PV_kernel']
110
self.cmdline = vmConfig['PV_args']
111
self.ramdisk = vmConfig['PV_ramdisk']
112
# There a code-paths where use_tmp_xxx is not set at all; but if
113
# this is set, the variable itself is a boolean.
114
if 'use_tmp_kernel' in vmConfig and vmConfig['use_tmp_kernel']:
115
self.use_tmp_kernel = True
116
if 'use_tmp_ramdisk' in vmConfig and vmConfig['use_tmp_ramdisk']:
117
self.use_tmp_ramdisk = True
118
self.vm.storeVm(("image/ostype", self.ostype),
119
("image/kernel", self.kernel),
120
("image/cmdline", self.cmdline),
121
("image/ramdisk", self.ramdisk))
122
self.vm.permissionsVm("image/cmdline", { 'dom': self.vm.getDomid(), 'read': True } )
124
self.device_model = vmConfig['platform'].get('device_model')
126
self.display = vmConfig['platform'].get('display')
127
self.xauthority = vmConfig['platform'].get('xauthority')
128
self.vncconsole = int(vmConfig['platform'].get('vncconsole', 0))
129
self.dmargs = self.parseDeviceModelArgs(vmConfig)
131
rtc_timeoffset = int(vmConfig['platform'].get('rtc_timeoffset', 0))
132
if vmConfig['platform'].get('localtime', 0):
133
if time.localtime(time.time())[8]:
134
rtc_timeoffset -= time.altzone
136
rtc_timeoffset -= time.timezone
137
if rtc_timeoffset != 0:
138
xc.domain_set_time_offset(self.vm.getDomid(), rtc_timeoffset)
141
self.cpuid_check = None
142
if 'cpuid' in vmConfig:
143
self.cpuid = vmConfig['cpuid'];
144
if 'cpuid_check' in vmConfig:
145
self.cpuid_check = vmConfig['cpuid_check']
147
def cleanupTmpImages(self):
148
if self.use_tmp_kernel:
149
self.unlink(self.kernel)
150
if self.use_tmp_ramdisk:
151
self.unlink(self.ramdisk)
158
log.warning("error removing bootloader file '%s': %s", f, ex)
161
def createImage(self):
162
"""Entry point to create domain memory image.
163
Override in subclass if needed.
165
return self.createDomain()
168
def createDomain(self):
169
"""Build the domain boot image.
171
# Set params and call buildDomain().
173
if self.kernel and not os.path.isfile(self.kernel):
174
raise VmError('Kernel image does not exist: %s' % self.kernel)
175
if self.ramdisk and not os.path.isfile(self.ramdisk):
176
raise VmError('Kernel ramdisk does not exist: %s' % self.ramdisk)
177
if len(self.cmdline) >= MAX_GUEST_CMDLINE:
178
log.warning('kernel cmdline too long, domain %d',
181
log.info("buildDomain os=%s dom=%d vcpus=%d", self.ostype,
182
self.vm.getDomid(), self.vm.getVCpuCount())
184
result = self.buildDomain()
186
if isinstance(result, dict):
189
raise VmError('Building domain failed: ostype=%s dom=%d err=%s'
190
% (self.ostype, self.vm.getDomid(), str(result)))
192
def getRequiredAvailableMemory(self, mem_kb):
193
"""@param mem_kb The configured maxmem or memory, in KiB.
194
@return The corresponding required amount of memory for the domain,
195
also in KiB. This is normally the given mem_kb, but architecture- or
196
image-specific code may override this to add headroom where
200
def getRequiredInitialReservation(self):
201
"""@param mem_kb The configured memory, in KiB.
202
@return The corresponding required amount of memory to be free, also
203
in KiB. This is normally the same as getRequiredAvailableMemory, but
204
architecture- or image-specific code may override this to
205
add headroom where necessary."""
206
return self.getRequiredAvailableMemory(self.vm.getMemoryTarget())
208
def getRequiredMaximumReservation(self):
209
"""@param mem_kb The maximum possible memory, in KiB.
210
@return The corresponding required amount of memory to be free, also
211
in KiB. This is normally the same as getRequiredAvailableMemory, but
212
architecture- or image-specific code may override this to
213
add headroom where necessary."""
214
return self.getRequiredAvailableMemory(self.vm.getMemoryMaximum())
216
def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
217
"""@param shadow_mem_kb The configured shadow memory, in KiB.
218
@param maxmem_kb The configured maxmem, in KiB.
219
@return The corresponding required amount of shadow memory, also in
221
# PV domains don't need any shadow memory
224
def buildDomain(self):
225
"""Build the domain. Define in subclass."""
226
raise NotImplementedError()
228
def prepareEnvironment(self):
229
"""Prepare the environment for the execution of the domain. This
230
method is called before any devices are set up."""
232
domid = self.vm.getDomid()
234
# Delete left-over pipes
236
os.unlink('/var/run/tap/qemu-read-%d' % domid)
237
os.unlink('/var/run/tap/qemu-write-%d' % domid)
241
# No device model, don't create pipes
242
if self.device_model is None:
245
if platform.system() != 'SunOS':
246
# If we use a device model, the pipes for communication between
247
# blktapctrl and ioemu must be present before the devices are
248
# created (blktapctrl must access them for new block devices)
251
os.makedirs('/var/run/tap', 0755)
256
os.mkfifo('/var/run/tap/qemu-read-%d' % domid, 0600)
257
os.mkfifo('/var/run/tap/qemu-write-%d' % domid, 0600)
259
log.warn('Could not create blktap pipes for domain %d' % domid)
264
# Return a list of cmd line args to the device models based on the
266
def parseDeviceModelArgs(self, vmConfig):
267
ret = ["-domain-name", str(self.vm.info['name_label'])]
269
xen_extended_power_mgmt = int(vmConfig['platform'].get(
270
'xen_extended_power_mgmt', 0))
271
if xen_extended_power_mgmt != 0:
272
xstransact.Store("/local/domain/0/device-model/%i"
273
% self.vm.getDomid(),
274
('xen_extended_power_mgmt',
275
xen_extended_power_mgmt))
277
# Find RFB console device, and if it exists, make QEMU enable
279
if int(vmConfig['platform'].get('nographic', 0)) != 0:
280
# skip vnc init if nographic is set
281
ret.append('-nographic')
284
vram = str(vmConfig['platform'].get('videoram',4))
285
ret.append('-videoram')
289
has_vnc = int(vmConfig['platform'].get('vnc', 0)) != 0
290
has_sdl = int(vmConfig['platform'].get('sdl', 0)) != 0
292
keymap = vmConfig['platform'].get("keymap")
293
for dev_uuid in vmConfig['console_refs']:
294
dev_type, dev_info = vmConfig['devices'][dev_uuid]
295
if dev_type == 'vfb':
296
if 'keymap' in dev_info:
297
keymap = dev_info.get('keymap',{})
298
if 'monitor' in dev_info:
299
ret.append("-serial")
300
ret.append(dev_info.get('monitor',{}))
301
ret.append("-monitor")
303
if 'serial' in dev_info:
304
ret.append("-serial")
305
ret.append(dev_info.get('serial',{}))
306
if int(dev_info.get('vnc', 0)) != 0 :
308
if int(dev_info.get('sdl', 0)) != 0 :
311
self.display = dev_info.get('display', self.display)
312
self.xauthority = dev_info.get('xauthority', self.xauthority)
313
opengl = int(dev_info.get('opengl', opengl))
315
vnc_config = dev_info.get('other_config', {})
324
for key in ('vncunused', 'vnclisten', 'vncdisplay',
326
if key in vmConfig['platform']:
327
vnc_config[key] = vmConfig['platform'][key]
328
if vnc_config.has_key("vncpasswd"):
329
passwd = vnc_config["vncpasswd"]
331
passwd = XendOptions.instance().get_vncpasswd_default()
334
self.vm.storeVm("vncpasswd", passwd)
335
self.vm.permissionsVm("vncpasswd", { 'dom': self.vm.getDomid(), 'read': True } )
336
vncopts = vncopts + ",password"
337
log.debug("Stored a VNC password for vfb access")
339
log.debug("No VNC passwd configured for vfb access")
341
if XendOptions.instance().get_vnc_tls():
342
vncx509certdir = XendOptions.instance().get_vnc_x509_cert_dir()
343
vncx509verify = XendOptions.instance().get_vnc_x509_verify()
345
if not os.path.exists(vncx509certdir):
346
raise VmError("VNC x509 certificate dir %s does not exist" % vncx509certdir)
349
vncopts = vncopts + ",tls,x509verify=%s" % vncx509certdir
351
vncopts = vncopts + ",tls,x509=%s" % vncx509certdir
354
vnclisten = vnc_config.get('vnclisten',
355
XendOptions.instance().get_vnclisten_address())
356
vncdisplay = int(vnc_config.get('vncdisplay', 0))
358
ret.append("%s:%s%s" % (vnclisten, vncdisplay, vncopts))
360
if int(vnc_config.get('vncunused', 1)) != 0:
361
ret.append('-vncunused')
365
if int(vmConfig['platform'].get('opengl', opengl)) != 1 :
366
ret.append('-disable-opengl')
368
if not has_sdl and not has_vnc :
369
ret.append('-nographic')
371
if vmConfig['platform'].get('parallel'):
372
ret = ret + ["-parallel", vmConfig['platform'].get('parallel')]
374
if int(vmConfig['platform'].get('monitor', 0)) != 0:
375
if vmConfig['platform'].get('monitor_path'):
376
ret = ret + ['-monitor', vmConfig['platform'].get('monitor_path')]
378
ret = ret + ['-monitor', 'vc']
382
def getDeviceModelArgs(self, restore = False):
383
args = [self.device_model]
384
args = args + ([ "-d", "%d" % self.vm.getDomid() ])
385
args = args + self.dmargs
388
def _openSentinel(self, sentinel_path_fifo):
389
self.sentinel_fifo = file(sentinel_path_fifo, 'r')
390
self.sentinel_lock = thread.allocate_lock()
391
oshelp.fcntl_setfd_cloexec(self.sentinel_fifo, True)
392
sentinel_fifos_inuse[sentinel_path_fifo] = 1
393
self.sentinel_path_fifo = sentinel_path_fifo
395
def createDeviceModel(self, restore = False):
396
if self.device_model is None:
400
# Execute device model.
401
#todo: Error handling
402
args = self.getDeviceModelArgs(restore)
403
env = dict(os.environ)
405
env['DISPLAY'] = self.display
407
env['XAUTHORITY'] = self.xauthority
408
unique_id = "%i-%i" % (self.vm.getDomid(), time.time())
409
sentinel_path = sentinel_path_prefix + unique_id
410
sentinel_path_fifo = sentinel_path + '.fifo'
411
os.mkfifo(sentinel_path_fifo, 0600)
412
sentinel_write = file(sentinel_path_fifo, 'r+')
413
self._openSentinel(sentinel_path_fifo)
414
self.vm.storeDom("image/device-model-fifo", sentinel_path_fifo)
415
xstransact.Mkdir("/local/domain/0/device-model/%i" % self.vm.getDomid())
416
xstransact.SetPermissions("/local/domain/0/device-model/%i" % self.vm.getDomid(),
417
{ 'dom': self.vm.getDomid(), 'read': True, 'write': True })
418
log.info("spawning device models: %s %s", self.device_model, args)
419
# keep track of pid and spawned options to kill it later
421
self.logfile = "/var/log/xen/qemu-dm-%s.log" % str(self.vm.info['name_label'])
424
logfile_mode = os.O_WRONLY|os.O_CREAT|os.O_APPEND
425
logrotate_count = XendOptions.instance().get_qemu_dm_logrotate_count()
426
if logrotate_count > 0:
427
logfile_mode |= os.O_TRUNC
428
if os.path.exists("%s.%d" % (self.logfile, logrotate_count)):
429
os.unlink("%s.%d" % (self.logfile, logrotate_count))
430
for n in range(logrotate_count - 1, 0, -1):
431
if os.path.exists("%s.%d" % (self.logfile, n)):
432
os.rename("%s.%d" % (self.logfile, n),
433
"%s.%d" % (self.logfile, (n + 1)))
434
if os.path.exists(self.logfile):
435
os.rename(self.logfile, self.logfile + ".1")
437
null = os.open("/dev/null", os.O_RDONLY)
438
logfd = os.open(self.logfile, logfile_mode, 0666)
441
contract = osdep.prefork("%s:%d" %
442
(self.vm.getName(), self.vm.getDomid()))
446
osdep.postfork(contract)
450
oshelp.close_fds((sentinel_write.fileno(),))
452
os.execve(self.device_model, args, env)
454
print >>sys.stderr, (
455
'failed to set up fds or execute dm %s: %s' %
456
(self.device_model, utils.exception_string(e)))
461
osdep.postfork(contract, abandon=True)
465
sentinel_write.close()
466
self.vm.storeDom("image/device-model-pid", self.pid)
467
log.info("device model pid: %d", self.pid)
468
# we would very much prefer not to have a thread here and instead
469
# have a callback but sadly we don't have Twisted in xend
470
self.sentinel_thread = thread.start_new_thread(self._sentinel_watch,())
471
if self.device_model.find('stubdom-dm') > -1 :
472
from xen.xend import XendDomain
473
domains = XendDomain.instance()
474
domains.domains_lock.release()
478
orig_state = xstransact.Read("/local/domain/0/device-model/%i/state"
479
% self.vm.getDomid())
480
# This can occur right after start-up
481
if orig_state != None:
484
log.debug('createDeviceModel %i: orig_state is None, retrying' % self.vm.getDomid())
491
domains.domains_lock.acquire()
493
def signalDeviceModel(self, cmd, ret, par = None):
494
if self.device_model is None:
496
# Signal the device model to for action
497
if cmd is '' or ret is '':
498
raise VmError('need valid command and result when signal device model')
502
orig_state = xstransact.Read("/local/domain/0/device-model/%i/state"
503
% self.vm.getDomid())
504
# This can occur right after start-up
505
if orig_state != None:
508
log.debug('signalDeviceModel: orig_state is None, retrying')
515
raise VmError('Device model isn\'t ready for commands')
518
xstransact.Store("/local/domain/0/device-model/%i"
519
% self.vm.getDomid(), ('parameter', par))
521
xstransact.Store("/local/domain/0/device-model/%i"
522
% self.vm.getDomid(), ('command', cmd))
523
# Wait for confirmation. Could do this with a watch but we'd
524
# still end up spinning here waiting for the watch to fire.
528
state = xstransact.Read("/local/domain/0/device-model/%i/state"
529
% self.vm.getDomid())
533
raise VmError('Timed out waiting for device model action')
536
xstransact.Store("/local/domain/0/device-model/%i"
537
% self.vm.getDomid(), ('state', orig_state))
538
log.info("signalDeviceModel:restore dm state to %s", orig_state)
540
def saveDeviceModel(self):
541
# Signal the device model to pause itself and save its state
542
self.signalDeviceModel('save', 'paused')
544
def resumeDeviceModel(self):
545
if self.device_model is None:
547
# Signal the device model to resume activity after pausing to save.
548
xstransact.Store("/local/domain/0/device-model/%i"
549
% self.vm.getDomid(), ('command', 'continue'))
551
def _dmfailed(self, message):
552
log.warning("domain %s: %s", self.vm.getName(), message)
554
xc.domain_shutdown(self.vm.getDomid(), DOMAIN_CRASH)
559
if self.device_model is None:
561
name = self.vm.getName()
562
sentinel_path_fifo = self.vm.readDom('image/device-model-fifo')
564
log.debug("rediscovering %s", sentinel_path_fifo)
565
if sentinel_path_fifo is None:
566
log.debug("%s device model no sentinel, cannot rediscover", name)
569
# We open it O_WRONLY because that fails ENXIO if no-one
570
# has it open for reading (see SuSv3). The dm process got
571
# a read/write descriptor from our earlier invocation.
572
fifo_fd = os.open(sentinel_path_fifo, os.O_WRONLY|os.O_NONBLOCK)
574
if e.errno == errno.ENXIO:
575
self._dmfailed("%s device model no longer running"%name)
576
elif e.errno == errno.ENOENT:
577
log.debug("%s device model sentinel %s absent!",
578
name, sentinel_path_fifo)
582
self._openSentinel(sentinel_path_fifo)
584
self.pid = self.vm.gatherDom(('image/device-model-pid', int))
585
log.debug("%s device model rediscovered, pid %s sentinel fifo %s",
586
name, self.pid, sentinel_path_fifo)
587
self.sentinel_thread = thread.start_new_thread(self._sentinel_watch,())
589
def _sentinel_watch(self):
590
log.info("waiting for sentinel_fifo")
591
try: self.sentinel_fifo.read(1)
592
except OSError, e: pass
593
self.sentinel_lock.acquire()
596
(p,st) = os.waitpid(self.pid, os.WNOHANG)
598
message = oshelp.waitstatus_description(st)
600
# obviously it is malfunctioning, kill it now
602
os.kill(self.pid, signal.SIGKILL)
603
message = "malfunctioning (closed sentinel), killed"
605
message = "malfunctioning or died ?"
606
message = "pid %d: %s" % (self.pid, message)
608
message = "waitpid failed: %s" % utils.exception_string(e)
609
message = "device model failure: %s" % message
610
try: message += "; see %s " % self.logfile
612
self._dmfailed(message)
615
log.info("%s device model terminated", self.vm.getName())
616
self.sentinel_lock.release()
618
def destroyDeviceModel(self):
619
if self.device_model is None:
621
self.sentinel_lock.acquire()
623
stubdomid = self.vm.getStubdomDomid()
624
if stubdomid is not None :
625
from xen.xend import XendDomain
626
XendDomain.instance().domain_destroy(stubdomid)
629
os.kill(self.pid, signal.SIGHUP)
632
# Try to reap the child every 100ms for 10s. Then SIGKILL it.
633
for i in xrange(100):
635
(p, rv) = os.waitpid(self.pid, os.WNOHANG)
639
# This is expected if Xend has been restarted within
640
# the life of this domain. In this case, we can kill
641
# the process, but we can't wait for it because it's
642
# not our child. We continue this loop, and after it is
643
# terminated make really sure the process is going away
648
log.warning("DeviceModel %d took more than 10s "
649
"to terminate: sending SIGKILL" % self.pid)
651
os.kill(self.pid, signal.SIGKILL)
652
os.waitpid(self.pid, 0)
654
# This happens if the process doesn't exist.
658
self.sentinel_lock.release()
660
state = xstransact.Remove("/local/domain/0/device-model/%i"
661
% self.vm.getDomid())
663
os.unlink('/var/run/tap/qemu-read-%d' % self.vm.getDomid())
664
os.unlink('/var/run/tap/qemu-write-%d' % self.vm.getDomid())
668
del sentinel_fifos_inuse[self.sentinel_path_fifo]
669
os.unlink(self.sentinel_path_fifo)
674
xc.domain_set_policy_cpuid(self.vm.getDomid())
676
if self.cpuid is not None:
679
for sinput, regs in cpuid.iteritems():
680
inputs = sinput.split(',')
681
input = long(inputs[0])
684
sub_input = long(inputs[1])
685
t = xc.domain_set_cpuid(self.vm.getDomid(),
686
input, sub_input, regs)
687
transformed[sinput] = t
688
self.cpuid = transformed
690
if self.cpuid_check is not None:
691
cpuid_check = self.cpuid_check
693
for sinput, regs_check in cpuid_check.iteritems():
694
inputs = sinput.split(',')
695
input = long(inputs[0])
698
sub_input = long(inputs[1])
699
t = xc.domain_check_cpuid(input, sub_input, regs_check)
700
transformed[sinput] = t
701
self.cpuid_check = transformed
703
class LinuxImageHandler(ImageHandler):
709
def configure(self, vmConfig):
710
ImageHandler.configure(self, vmConfig)
711
self.vramsize = int(vmConfig['platform'].get('videoram',4)) * 1024
712
self.is_stubdom = (self.kernel.find('stubdom') >= 0)
713
self.superpages = int(vmConfig['superpages'])
715
def buildDomain(self):
716
store_evtchn = self.vm.getStorePort()
717
console_evtchn = self.vm.getConsolePort()
719
mem_mb = self.getRequiredInitialReservation() / 1024
721
log.debug("domid = %d", self.vm.getDomid())
722
log.debug("memsize = %d", mem_mb)
723
log.debug("image = %s", self.kernel)
724
log.debug("store_evtchn = %d", store_evtchn)
725
log.debug("console_evtchn = %d", console_evtchn)
726
log.debug("cmdline = %s", self.cmdline)
727
log.debug("ramdisk = %s", self.ramdisk)
728
log.debug("vcpus = %d", self.vm.getVCpuCount())
729
log.debug("features = %s", self.vm.getFeatures())
730
log.debug("flags = %d", self.flags)
731
log.debug("superpages = %d", self.superpages)
732
if arch.type == "ia64":
733
log.debug("vhpt = %d", self.vhpt)
735
return xc.linux_build(domid = self.vm.getDomid(),
738
store_evtchn = store_evtchn,
739
console_evtchn = console_evtchn,
740
cmdline = self.cmdline,
741
ramdisk = self.ramdisk,
742
features = self.vm.getFeatures(),
745
superpages = self.superpages)
747
def getBitSize(self):
748
return xc.getBitSize(image = self.kernel,
749
cmdline = self.cmdline,
750
features = self.vm.getFeatures()
753
def getRequiredAvailableMemory(self, mem_kb):
755
mem_kb += self.vramsize
758
def getRequiredInitialReservation(self):
759
return self.vm.getMemoryTarget()
761
def getRequiredMaximumReservation(self):
762
return self.vm.getMemoryMaximum()
764
def parseDeviceModelArgs(self, vmConfig):
765
ret = ImageHandler.parseDeviceModelArgs(self, vmConfig)
766
if vmConfig['platform'].get('serial'):
767
ret = ["-serial", vmConfig['platform'].get('serial')] + ret
769
ret = ["-serial", "pty"] + ret
772
def getDeviceModelArgs(self, restore = False):
773
args = ImageHandler.getDeviceModelArgs(self, restore)
774
args = args + ([ "-M", "xenpv"])
778
class HVMImageHandler(ImageHandler):
782
def __init__(self, vm, vmConfig):
783
ImageHandler.__init__(self, vm, vmConfig)
784
self.shutdownWatch = None
785
self.rebootFeatureWatch = None
787
def getBitSize(self):
790
def configure(self, vmConfig):
791
ImageHandler.configure(self, vmConfig)
793
self.loader = vmConfig['platform'].get('loader')
796
if 'hvm' not in info['xen_caps']:
799
xen_platform_pci = int(vmConfig['platform'].get('xen_platform_pci',1))
800
rtc_timeoffset = vmConfig['platform'].get('rtc_timeoffset')
802
if not self.display :
805
store_dmargs = [ x for x in self.dmargs
806
if x not in ['-sdl', '-disable-opengl'] ]
808
midx = store_dmargs.index('-monitor')
809
store_dmargs[midx + 1] = 'pty'
812
self.vm.storeVm(("image/dmargs", " ".join(store_dmargs)),
813
("image/device-model", self.device_model),
814
("image/display", self.display))
815
self.vm.permissionsVm("image/dmargs", { 'dom': self.vm.getDomid(), 'read': True } )
817
if xen_platform_pci == 0:
819
log.info("No need to create platform device.[domid:%d]", self.vm.getDomid())
822
log.info("Need to create platform device.[domid:%d]", self.vm.getDomid())
824
xstransact.Store("/local/domain/0/device-model/%i"%self.vm.getDomid(),
825
('disable_pf', disable_pf))
826
self.vm.storeVm(("rtc/timeoffset", rtc_timeoffset))
827
self.vm.permissionsVm("rtc/timeoffset", { 'dom': self.vm.getDomid(), 'read': True } )
829
self.apic = int(vmConfig['platform'].get('apic', 0))
830
self.acpi = int(vmConfig['platform'].get('acpi', 0))
831
self.guest_os_type = vmConfig['platform'].get('guest_os_type')
832
self.memory_sharing = int(vmConfig['memory_sharing'])
833
xc.dom_set_memshr(self.vm.getDomid(), self.memory_sharing)
836
# Return a list of cmd line args to the device models based on the
838
def parseDeviceModelArgs(self, vmConfig):
839
ret = ImageHandler.parseDeviceModelArgs(self, vmConfig)
840
ret = ret + ['-vcpus', str(self.vm.getVCpuCount())]
841
ret = ret + ['-vcpu_avail', hex(self.vm.getVCpuAvail())]
844
log.debug("kernel = %s", self.kernel)
845
ret = ret + ['-kernel', self.kernel]
847
log.debug("ramdisk = %s", self.ramdisk)
848
ret = ret + ['-initrd', self.ramdisk]
850
log.debug("cmdline = %s", self.cmdline)
851
ret = ret + ['-append', self.cmdline]
854
dmargs = [ 'boot', 'fda', 'fdb', 'soundhw',
855
'localtime', 'serial', 'stdvga', 'isa',
856
'acpi', 'usb', 'usbdevice', 'gfx_passthru' ]
859
v = vmConfig['platform'].get(a)
861
# python doesn't allow '-' in variable names
862
if a == 'stdvga': a = 'std-vga'
863
if a == 'keymap': a = 'k'
865
# Handle booleans gracefully
866
if a in ['localtime', 'std-vga', 'isa', 'usb', 'acpi']:
868
if v != None: v = int(v)
869
if v: ret.append("-%s" % a)
870
except (ValueError, TypeError):
871
pass # if we can't convert it to a sane type, ignore it
878
ret.append("-serial")
882
ret.append("-%s" % a)
885
if a in ['fda', 'fdb']:
887
if not os.path.isabs(v):
888
raise VmError("Floppy file %s does not exist." % v)
889
log.debug("args: %s, val: %s" % (a,v))
891
# Handle disk/network related options
895
for devuuid in vmConfig['vbd_refs']:
896
devinfo = vmConfig['devices'][devuuid][1]
897
uname = devinfo.get('uname')
898
if uname is not None and 'file:' in uname:
899
(_, vbdparam) = string.split(uname, ':', 1)
900
if not os.path.isfile(vbdparam):
901
raise VmError('Disk image does not exist: %s' %
904
for devuuid in vmConfig['vif_refs']:
905
devinfo = vmConfig['devices'][devuuid][1]
906
dtype = devinfo.get('type', 'ioemu')
910
mac = devinfo.get('mac')
912
raise VmError("MAC address not specified or generated.")
913
bridge = devinfo.get('bridge', 'xenbr0')
914
model = devinfo.get('model', 'rtl8139')
916
ret.append("nic,vlan=%d,macaddr=%s,model=%s" %
918
vifname = devinfo.get('vifname')
920
vifname = "tap-" + vifname
922
vifname = "tap%d.%d" % (self.vm.getDomid(), nics-1)
924
ret.append("tap,vlan=%d,ifname=%s,bridge=%s" %
925
(nics, vifname, bridge))
933
def getDeviceModelArgs(self, restore = False):
934
args = ImageHandler.getDeviceModelArgs(self, restore)
935
args = args + ([ "-M", "xenfv"])
937
args = args + ([ "-loadvm", "/var/lib/xen/qemu-save.%d" %
938
self.vm.getDomid() ])
941
def buildDomain(self):
942
store_evtchn = self.vm.getStorePort()
944
memmax_mb = self.getRequiredMaximumReservation() / 1024
945
mem_mb = self.getRequiredInitialReservation() / 1024
947
log.debug("domid = %d", self.vm.getDomid())
948
log.debug("image = %s", self.loader)
949
log.debug("store_evtchn = %d", store_evtchn)
950
log.debug("memsize = %d", memmax_mb)
951
log.debug("target = %d", mem_mb)
952
log.debug("vcpus = %d", self.vm.getVCpuCount())
953
log.debug("vcpu_avail = %li", self.vm.getVCpuAvail())
954
log.debug("acpi = %d", self.acpi)
955
log.debug("apic = %d", self.apic)
957
rc = xc.hvm_build(domid = self.vm.getDomid(),
961
vcpus = self.vm.getVCpuCount(),
962
vcpu_avail = self.vm.getVCpuAvail(),
965
rc['notes'] = { 'SUSPEND_CANCEL': 1 }
967
rc['store_mfn'] = xc.hvm_get_param(self.vm.getDomid(),
969
xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_STORE_EVTCHN,
975
class IA64_HVM_ImageHandler(HVMImageHandler):
977
def configure(self, vmConfig):
978
HVMImageHandler.configure(self, vmConfig)
979
self.vhpt = int(vmConfig['platform'].get('vhpt', 0))
980
self.vramsize = int(vmConfig['platform'].get('videoram',4)) * 1024
982
def buildDomain(self):
983
xc.nvram_init(self.vm.getName(), self.vm.getDomid())
984
xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_VHPT_SIZE, self.vhpt)
985
if self.guest_os_type is not None:
986
xc.set_os_type(self.guest_os_type.lower(), self.vm.getDomid())
987
return HVMImageHandler.buildDomain(self)
989
def getRequiredAvailableMemory(self, mem_kb):
991
# ROM size for guest firmware, io page, xenstore page
992
# buffer io page, buffer pio page and memmap info page
993
extra_pages = 1024 + 5
994
mem_kb += extra_pages * page_kb
995
mem_kb += self.vramsize
998
def getRequiredInitialReservation(self):
999
return self.vm.getMemoryTarget()
1001
def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
1002
# Explicit shadow memory is not a concept
1005
def getDeviceModelArgs(self, restore = False):
1006
args = HVMImageHandler.getDeviceModelArgs(self, restore)
1007
args = args + ([ "-m", "%s" %
1008
(self.getRequiredInitialReservation() / 1024) ])
1012
# Guest CPUID configuration is not implemented yet.
1015
class IA64_Linux_ImageHandler(LinuxImageHandler):
1017
def configure(self, vmConfig):
1018
LinuxImageHandler.configure(self, vmConfig)
1019
self.vhpt = int(vmConfig['platform'].get('vhpt', 0))
1022
# Guest CPUID configuration is not implemented yet.
1025
class X86_HVM_ImageHandler(HVMImageHandler):
1027
def configure(self, vmConfig):
1028
HVMImageHandler.configure(self, vmConfig)
1029
self.pae = int(vmConfig['platform'].get('pae', 0))
1030
self.vramsize = int(vmConfig['platform'].get('videoram',4)) * 1024
1032
def buildDomain(self):
1033
xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_PAE_ENABLED, self.pae)
1034
rc = HVMImageHandler.buildDomain(self)
1038
def getBitSize(self):
1041
def getRequiredAvailableMemory(self, mem_kb):
1042
return mem_kb + self.vramsize
1044
def getRequiredInitialReservation(self):
1045
return self.vm.getMemoryTarget()
1047
def getRequiredMaximumReservation(self):
1048
return self.vm.getMemoryMaximum()
1050
def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
1051
# 256 pages (1MB) per vcpu,
1052
# plus 1 page per MiB of RAM for the P2M map,
1053
# plus 1 page per MiB of RAM to shadow the resident processes.
1054
# This is higher than the minimum that Xen would allocate if no value
1055
# were given (but the Xen minimum is for safety, not performance).
1056
return max(4 * (256 * self.vm.getVCpuCount() + 2 * (maxmem_kb / 1024)),
1060
class X86_Linux_ImageHandler(LinuxImageHandler):
1062
def buildDomain(self):
1063
# set physical mapping limit
1064
# add an 8MB slack to balance backend allocations.
1065
mem_kb = self.getRequiredMaximumReservation() + (8 * 1024)
1066
xc.domain_set_memmap_limit(self.vm.getDomid(), mem_kb)
1067
rc = LinuxImageHandler.buildDomain(self)
1073
"linux": IA64_Linux_ImageHandler,
1074
"hvm": IA64_HVM_ImageHandler,
1077
"linux": X86_Linux_ImageHandler,
1078
"hvm": X86_HVM_ImageHandler,
1082
def findImageHandlerClass(image):
1083
"""Find the image handler class for an image config.
1086
@return ImageHandler subclass or None
1088
image_type = image.image_type()
1090
return _handlers[arch.type][image_type]
1092
raise VmError('unknown image type: ' + image_type)