Add HPET timer support for x86 guests
This commit adds support for the High Precision Event Timer (HPET) for x86 guests in the libvirt driver. The timer can be set by image property 'hw_time_hpet'. By default it remains turned off. When it is turned on the HPET timer is activated in libvirt. If the image property 'hw_time_hpet' is incorrectly set to a non-boolean, the HPET timer remains turned off. blueprint: support-hpet-on-guest Change-Id: I3debf725544cae245fd31a8d97650392965d480a Signed-off-by: Jack Ding <jack.ding@windriver.com>
This commit is contained in:
parent
47bcc39cd6
commit
9e884de68a
@ -170,12 +170,15 @@ class ImageMetaProps(base.NovaObject):
|
||||
# Version 1.18: Pull signature properties from cursive library
|
||||
# Version 1.19: Added 'img_hide_hypervisor_id' type field
|
||||
# Version 1.20: Added 'traits_required' list field
|
||||
VERSION = '1.20'
|
||||
# Version 1.21: Added 'hw_time_hpet' field
|
||||
VERSION = '1.21'
|
||||
|
||||
def obj_make_compatible(self, primitive, target_version):
|
||||
super(ImageMetaProps, self).obj_make_compatible(primitive,
|
||||
target_version)
|
||||
target_version = versionutils.convert_version_to_tuple(target_version)
|
||||
if target_version < (1, 21):
|
||||
primitive.pop('hw_time_hpet', None)
|
||||
if target_version < (1, 20):
|
||||
primitive.pop('traits_required', None)
|
||||
if target_version < (1, 19):
|
||||
@ -326,6 +329,9 @@ class ImageMetaProps(base.NovaObject):
|
||||
# name of the RNG device type eg virtio
|
||||
'hw_rng_model': fields.RNGModelField(),
|
||||
|
||||
# boolean 'true' or 'false' to enable HPET
|
||||
'hw_time_hpet': fields.FlexibleBooleanField(),
|
||||
|
||||
# number of serial ports to create
|
||||
'hw_serial_port_count': fields.IntegerField(),
|
||||
|
||||
|
@ -1093,7 +1093,7 @@ object_data = {
|
||||
'HVSpec': '1.2-de06bcec472a2f04966b855a49c46b41',
|
||||
'IDEDeviceBus': '1.0-29d4c9f27ac44197f01b6ac1b7e16502',
|
||||
'ImageMeta': '1.8-642d1b2eb3e880a367f37d72dd76162d',
|
||||
'ImageMetaProps': '1.20-ffd686cde289814695d5f89522aa5aef',
|
||||
'ImageMetaProps': '1.21-f3721d8f744a9507a1966c81c386b532',
|
||||
'Instance': '2.4-4437eb8b2737c3054ea579b8efe31dc5',
|
||||
'InstanceAction': '1.1-f9f293e526b66fca0d05c3b3a2d13914',
|
||||
'InstanceActionEvent': '1.2-b2f368b8a29d8d872b1f6ea841e820a0',
|
||||
|
@ -3633,6 +3633,153 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
||||
else:
|
||||
self.assertEqual(2, len(cfg.clock.timers))
|
||||
|
||||
def test_get_guest_config_clock_hpet_false(self):
|
||||
self.flags(virt_type='kvm', group='libvirt')
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
image_meta = objects.ImageMeta.from_dict({
|
||||
"disk_format": "raw",
|
||||
"properties": {"hw_time_hpet": "false"}})
|
||||
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
|
||||
instance_ref,
|
||||
image_meta)
|
||||
hpet_map = {
|
||||
fields.Architecture.X86_64: True,
|
||||
fields.Architecture.I686: True,
|
||||
fields.Architecture.PPC: False,
|
||||
fields.Architecture.PPC64: False,
|
||||
fields.Architecture.ARMV7: False,
|
||||
fields.Architecture.AARCH64: False,
|
||||
}
|
||||
|
||||
for guestarch, expect_hpet in hpet_map.items():
|
||||
with mock.patch.object(libvirt_driver.libvirt_utils,
|
||||
'get_arch',
|
||||
return_value=guestarch):
|
||||
cfg = drvr._get_guest_config(instance_ref, [],
|
||||
image_meta,
|
||||
disk_info)
|
||||
self.assertIsInstance(cfg.clock,
|
||||
vconfig.LibvirtConfigGuestClock)
|
||||
self.assertEqual(cfg.clock.offset, "utc")
|
||||
self.assertIsInstance(cfg.clock.timers[0],
|
||||
vconfig.LibvirtConfigGuestTimer)
|
||||
self.assertIsInstance(cfg.clock.timers[1],
|
||||
vconfig.LibvirtConfigGuestTimer)
|
||||
self.assertEqual(cfg.clock.timers[0].name, "pit")
|
||||
self.assertEqual(cfg.clock.timers[0].tickpolicy,
|
||||
"delay")
|
||||
self.assertEqual(cfg.clock.timers[1].name, "rtc")
|
||||
self.assertEqual(cfg.clock.timers[1].tickpolicy,
|
||||
"catchup")
|
||||
if expect_hpet:
|
||||
self.assertEqual(3, len(cfg.clock.timers))
|
||||
self.assertIsInstance(cfg.clock.timers[2],
|
||||
vconfig.LibvirtConfigGuestTimer)
|
||||
self.assertEqual('hpet', cfg.clock.timers[2].name)
|
||||
self.assertFalse(cfg.clock.timers[2].present)
|
||||
else:
|
||||
self.assertEqual(2, len(cfg.clock.timers))
|
||||
|
||||
def test_get_guest_config_clock_hpet_true(self):
|
||||
self.flags(virt_type='kvm', group='libvirt')
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
image_meta = objects.ImageMeta.from_dict({
|
||||
"id": uuids.image_id,
|
||||
"disk_format": "raw",
|
||||
"properties": {"hw_time_hpet": "true"}})
|
||||
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
|
||||
instance_ref,
|
||||
image_meta)
|
||||
hpet_map = {
|
||||
fields.Architecture.X86_64: True,
|
||||
fields.Architecture.I686: True,
|
||||
fields.Architecture.PPC: False,
|
||||
fields.Architecture.PPC64: False,
|
||||
fields.Architecture.ARMV7: False,
|
||||
fields.Architecture.AARCH64: False,
|
||||
}
|
||||
|
||||
for guestarch, expect_hpet in hpet_map.items():
|
||||
with mock.patch.object(libvirt_driver.libvirt_utils,
|
||||
'get_arch',
|
||||
return_value=guestarch):
|
||||
cfg = drvr._get_guest_config(instance_ref, [],
|
||||
image_meta,
|
||||
disk_info)
|
||||
self.assertIsInstance(cfg.clock,
|
||||
vconfig.LibvirtConfigGuestClock)
|
||||
self.assertEqual(cfg.clock.offset, "utc")
|
||||
self.assertIsInstance(cfg.clock.timers[0],
|
||||
vconfig.LibvirtConfigGuestTimer)
|
||||
self.assertIsInstance(cfg.clock.timers[1],
|
||||
vconfig.LibvirtConfigGuestTimer)
|
||||
self.assertEqual(cfg.clock.timers[0].name, "pit")
|
||||
self.assertEqual(cfg.clock.timers[0].tickpolicy,
|
||||
"delay")
|
||||
self.assertEqual(cfg.clock.timers[1].name, "rtc")
|
||||
self.assertEqual(cfg.clock.timers[1].tickpolicy,
|
||||
"catchup")
|
||||
if expect_hpet:
|
||||
self.assertEqual(3, len(cfg.clock.timers))
|
||||
self.assertIsInstance(cfg.clock.timers[2],
|
||||
vconfig.LibvirtConfigGuestTimer)
|
||||
self.assertEqual('hpet', cfg.clock.timers[2].name)
|
||||
self.assertTrue(cfg.clock.timers[2].present)
|
||||
else:
|
||||
self.assertEqual(2, len(cfg.clock.timers))
|
||||
|
||||
def test_get_guest_config_clock_hpet_invalid(self):
|
||||
self.flags(virt_type='kvm', group='libvirt')
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
image_meta = objects.ImageMeta.from_dict({
|
||||
"disk_format": "raw",
|
||||
"properties": {"hw_time_hpet": "blah"}})
|
||||
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
|
||||
instance_ref,
|
||||
image_meta)
|
||||
hpet_map = {
|
||||
fields.Architecture.X86_64: True,
|
||||
fields.Architecture.I686: True,
|
||||
fields.Architecture.PPC: False,
|
||||
fields.Architecture.PPC64: False,
|
||||
fields.Architecture.ARMV7: False,
|
||||
fields.Architecture.AARCH64: False,
|
||||
}
|
||||
|
||||
for guestarch, expect_hpet in hpet_map.items():
|
||||
with mock.patch.object(libvirt_driver.libvirt_utils,
|
||||
'get_arch',
|
||||
return_value=guestarch):
|
||||
cfg = drvr._get_guest_config(instance_ref, [],
|
||||
image_meta,
|
||||
disk_info)
|
||||
self.assertIsInstance(cfg.clock,
|
||||
vconfig.LibvirtConfigGuestClock)
|
||||
self.assertEqual(cfg.clock.offset, "utc")
|
||||
self.assertIsInstance(cfg.clock.timers[0],
|
||||
vconfig.LibvirtConfigGuestTimer)
|
||||
self.assertIsInstance(cfg.clock.timers[1],
|
||||
vconfig.LibvirtConfigGuestTimer)
|
||||
self.assertEqual(cfg.clock.timers[0].name, "pit")
|
||||
self.assertEqual(cfg.clock.timers[0].tickpolicy,
|
||||
"delay")
|
||||
self.assertEqual(cfg.clock.timers[1].name, "rtc")
|
||||
self.assertEqual(cfg.clock.timers[1].tickpolicy,
|
||||
"catchup")
|
||||
if expect_hpet:
|
||||
self.assertEqual(3, len(cfg.clock.timers))
|
||||
self.assertIsInstance(cfg.clock.timers[2],
|
||||
vconfig.LibvirtConfigGuestTimer)
|
||||
self.assertEqual('hpet', cfg.clock.timers[2].name)
|
||||
# a non-boolean value of hw_time_hpet should be treated as
|
||||
# False
|
||||
self.assertFalse(cfg.clock.timers[2].present)
|
||||
else:
|
||||
self.assertEqual(2, len(cfg.clock.timers))
|
||||
|
||||
@mock.patch.object(libvirt_utils, 'get_arch')
|
||||
def test_get_guest_config_windows_timer(self, mock_get_arch):
|
||||
mock_get_arch.return_value = fields.Architecture.I686
|
||||
|
@ -4569,6 +4569,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
clk.add_timer(tmpit)
|
||||
clk.add_timer(tmrtc)
|
||||
|
||||
hpet = image_meta.properties.get('hw_time_hpet', False)
|
||||
guestarch = libvirt_utils.get_arch(image_meta)
|
||||
if guestarch in (fields.Architecture.I686,
|
||||
fields.Architecture.X86_64):
|
||||
@ -4576,8 +4577,12 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
# qemu -no-hpet is not supported on non-x86 targets.
|
||||
tmhpet = vconfig.LibvirtConfigGuestTimer()
|
||||
tmhpet.name = "hpet"
|
||||
tmhpet.present = False
|
||||
tmhpet.present = hpet
|
||||
clk.add_timer(tmhpet)
|
||||
else:
|
||||
if hpet:
|
||||
LOG.warning('HPET is not turned on for non-x86 guests in image'
|
||||
' %s.', image_meta.id)
|
||||
|
||||
# Provide Windows guests with the paravirtualized hyperv timer source.
|
||||
# This is the windows equiv of kvm-clock, allowing Windows
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added support for the High Precision Event Timer (HPET) for x86 guests
|
||||
in the libvirt driver when image property ``hypervisor_type=qemu`` is set.
|
||||
The timer can be set by setting a ``hw_time_hpet=True`` image property
|
||||
key/value pair. By default HPET remains turned off. When it is turned on
|
||||
the HPET is activated in libvirt.
|
Loading…
Reference in New Issue
Block a user