Skip to content

Commit 572c2b1

Browse files
SeanMooneyricolin
authored andcommitted
Add locked_memory extra spec and image property
This change adds a new hw:locked_memory extra spec and hw_locked_memory image property to contol preventing guest memory from swapping. This change adds docs and extend the flavor validators for the new extra spec. Also add new image property. Blueprint: libvirt-viommu-device Change-Id: Id3779594f0078a5045031aded2ed68ee4301abbd
1 parent 85c9544 commit 572c2b1

File tree

15 files changed

+237
-7
lines changed

15 files changed

+237
-7
lines changed

doc/notification_samples/common_payloads/ImageMetaPropsPayload.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
"hw_architecture": "x86_64"
55
},
66
"nova_object.name": "ImageMetaPropsPayload",
7-
"nova_object.version": "1.10"
7+
"nova_object.version": "1.11"
88
}

doc/source/admin/libvirt-misc.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,33 @@ For example, to hide your signature from the guest OS, run:
138138
.. code:: console
139139
140140
$ openstack flavor set $FLAVOR --property hw:hide_hypervisor_id=true
141+
142+
143+
.. _extra-spec-locked_memory:
144+
145+
Locked memory allocation
146+
------------------------
147+
148+
.. versionadded:: 26.0.0 (Zed)
149+
150+
Locking memory marks the guest memory allocations as unmovable and
151+
unswappable. It is implicitly enabled in a number of cases such as SEV or
152+
realtime guests but can also be enabled explictly using the
153+
``hw:locked_memory`` extra spec (or use ``hw_locked_memory`` image property).
154+
``hw:locked_memory`` (also ``hw_locked_memory`` image property) accept
155+
boolean values in string format like 'true' or 'false' value.
156+
It will raise `FlavorImageLockedMemoryConflict` exception if both flavor and
157+
image property are specified but with different boolean values.
158+
This will only be allowed if you have also set ``hw:mem_page_size``,
159+
so we can ensure that the scheduler can actually account for this correctly
160+
and prevent out of memory events. Otherwise, will raise `LockMemoryForbidden`
161+
exception.
162+
163+
.. code:: console
164+
165+
$ openstack flavor set FLAVOR-NAME \
166+
--property hw:locked_memory=BOOLEAN_VALUE
167+
168+
.. note::
169+
170+
This is currently only supported by the libvirt driver.

nova/api/validation/extra_specs/hw.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,18 @@
163163
'pattern': r'(large|small|any|\d+([kKMGT]i?)?(b|bit|B)?)',
164164
},
165165
),
166+
base.ExtraSpecValidator(
167+
name='hw:locked_memory',
168+
description=(
169+
'Determine if **guest** (instance) memory should be locked '
170+
'preventing swaping. This is required in rare cases for device '
171+
'DMA transfers. Only supported by the libvirt virt driver.'
172+
),
173+
value={
174+
'type': bool,
175+
'description': 'Whether to lock **guest** (instance) memory.',
176+
},
177+
),
166178
]
167179

168180
numa_validators = [

nova/exception.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,17 @@ class MemoryPageSizeNotSupported(Invalid):
18611861
msg_fmt = _("Page size %(pagesize)s is not supported by the host.")
18621862

18631863

1864+
class LockMemoryForbidden(Forbidden):
1865+
msg_fmt = _("locked_memory value in image or flavor is forbidden when "
1866+
"mem_page_size is not set.")
1867+
1868+
1869+
class FlavorImageLockedMemoryConflict(NovaException):
1870+
msg_fmt = _("locked_memory value in image (%(image)s) and flavor "
1871+
"(%(flavor)s) conflict. A consistent value is expected if "
1872+
"both specified.")
1873+
1874+
18641875
class CPUPinningInvalid(Invalid):
18651876
msg_fmt = _("CPU set to pin %(requested)s must be a subset of "
18661877
"free CPU set %(available)s")

nova/notifications/objects/image.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ class ImageMetaPropsPayload(base.NotificationPayloadBase):
128128
# Version 1.9: Added 'hw_emulation_architecture' field
129129
# Version 1.10: Added 'hw_ephemeral_encryption' and
130130
# 'hw_ephemeral_encryption_format' fields
131-
VERSION = '1.10'
131+
# Version 1.11: Added 'hw_locked_memory' field
132+
VERSION = '1.11'
132133

133134
SCHEMA = {
134135
k: ('image_meta_props', k) for k in image_meta.ImageMetaProps.fields}

nova/objects/image_meta.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,17 @@ class ImageMetaProps(base.NovaObject):
190190
# Version 1.31: Added 'hw_emulation_architecture' field
191191
# Version 1.32: Added 'hw_ephemeral_encryption' and
192192
# 'hw_ephemeral_encryption_format' fields
193+
# Version 1.33: Added 'hw_locked_memory' field
193194
# NOTE(efried): When bumping this version, the version of
194195
# ImageMetaPropsPayload must also be bumped. See its docstring for details.
195-
VERSION = '1.32'
196+
VERSION = '1.33'
196197

197198
def obj_make_compatible(self, primitive, target_version):
198199
super(ImageMetaProps, self).obj_make_compatible(primitive,
199200
target_version)
200201
target_version = versionutils.convert_version_to_tuple(target_version)
202+
if target_version < (1, 33):
203+
primitive.pop('hw_locked_memory', None)
201204
if target_version < (1, 32):
202205
primitive.pop('hw_ephemeral_encryption', None)
203206
primitive.pop('hw_ephemeral_encryption_format', None)
@@ -368,6 +371,10 @@ def obj_make_compatible(self, primitive, target_version):
368371
# image with a network boot image
369372
'hw_ipxe_boot': fields.FlexibleBooleanField(),
370373

374+
# string - make sure ``locked`` element is present in the
375+
# ``memoryBacking``.
376+
'hw_locked_memory': fields.FlexibleBooleanField(),
377+
371378
# There are sooooooooooo many possible machine types in
372379
# QEMU - several new ones with each new release - that it
373380
# is not practical to enumerate them all. So we use a free

nova/tests/functional/notification_sample_tests/test_instance.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,7 +1231,7 @@ def test_rebuild_server(self):
12311231
'nova_object.data': {},
12321232
'nova_object.name': 'ImageMetaPropsPayload',
12331233
'nova_object.namespace': 'nova',
1234-
'nova_object.version': '1.10',
1234+
'nova_object.version': '1.11',
12351235
},
12361236
'image.size': 58145823,
12371237
'image.tags': [],
@@ -1327,7 +1327,7 @@ def test_rebuild_server_with_trusted_cert(self):
13271327
'nova_object.data': {},
13281328
'nova_object.name': 'ImageMetaPropsPayload',
13291329
'nova_object.namespace': 'nova',
1330-
'nova_object.version': '1.10',
1330+
'nova_object.version': '1.11',
13311331
},
13321332
'image.size': 58145823,
13331333
'image.tags': [],

nova/tests/unit/notifications/objects/test_notification.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ def test_payload_is_not_generated_if_notification_format_is_unversioned(
386386
# ImageMetaProps, so when you see a fail here for that reason, you must
387387
# *also* bump the version of ImageMetaPropsPayload. See its docstring for
388388
# more information.
389-
'ImageMetaPropsPayload': '1.10-44cf0030dc94a1a60ba7a0e222e854d6',
389+
'ImageMetaPropsPayload': '1.11-938809cd33367c52cbc814fb9b6783dc',
390390
'InstanceActionNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
391391
'InstanceActionPayload': '1.8-4fa3da9cbf0761f1f700ae578f36dc2f',
392392
'InstanceActionRebuildNotification':

nova/tests/unit/objects/test_image_meta.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ def test_normal_props(self):
108108
'hw_video_model': 'vga',
109109
'hw_video_ram': '512',
110110
'hw_qemu_guest_agent': 'yes',
111+
'hw_locked_memory': 'true',
111112
'trait:CUSTOM_TRUSTED': 'required',
112113
# Fill sane values for the rest here
113114
}
@@ -116,6 +117,7 @@ def test_normal_props(self):
116117
self.assertEqual('vga', virtprops.hw_video_model)
117118
self.assertEqual(512, virtprops.hw_video_ram)
118119
self.assertTrue(virtprops.hw_qemu_guest_agent)
120+
self.assertTrue(virtprops.hw_locked_memory)
119121
self.assertIsNotNone(virtprops.traits_required)
120122
self.assertIn('CUSTOM_TRUSTED', virtprops.traits_required)
121123

@@ -285,6 +287,28 @@ def test_set_numa_cpus_no_count(self):
285287
self.assertEqual([set([0, 1, 2, 3])],
286288
virtprops.hw_numa_cpus)
287289

290+
def test_locked_memory_prop(self):
291+
props = {'hw_locked_memory': 'true'}
292+
virtprops = objects.ImageMetaProps.from_dict(props)
293+
self.assertTrue(virtprops.hw_locked_memory)
294+
295+
def test_obj_make_compatible_hw_locked_memory(self):
296+
"""Check 'hw_locked_memory' compatibility."""
297+
# assert that 'hw_locked_memory' is supported
298+
# on a suitably new version
299+
obj = objects.ImageMetaProps(
300+
hw_locked_memory='true',
301+
)
302+
primitive = obj.obj_to_primitive('1.33')
303+
self.assertIn('hw_locked_memory',
304+
primitive['nova_object.data'])
305+
self.assertTrue(primitive['nova_object.data']['hw_locked_memory'])
306+
307+
# and is absent on older versions
308+
primitive = obj.obj_to_primitive('1.32')
309+
self.assertNotIn('hw_locked_memory',
310+
primitive['nova_object.data'])
311+
288312
def test_get_unnumbered_trait_fields(self):
289313
"""Tests that only valid un-numbered required traits are parsed from
290314
the properties.

nova/tests/unit/objects/test_objects.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1072,7 +1072,7 @@ def obj_name(cls):
10721072
'HyperVLiveMigrateData': '1.4-e265780e6acfa631476c8170e8d6fce0',
10731073
'IDEDeviceBus': '1.0-29d4c9f27ac44197f01b6ac1b7e16502',
10741074
'ImageMeta': '1.8-642d1b2eb3e880a367f37d72dd76162d',
1075-
'ImageMetaProps': '1.32-4967d35948af08b710b8b861f3fff0f9',
1075+
'ImageMetaProps': '1.33-6b7a29f769e6b8eee3f05832d78c85a2',
10761076
'Instance': '2.7-d187aec68cad2e4d8b8a03a68e4739ce',
10771077
'InstanceAction': '1.2-9a5abc87fdd3af46f45731960651efb5',
10781078
'InstanceActionEvent': '1.4-5b1f361bd81989f8bb2c20bb7e8a4cb4',

0 commit comments

Comments
 (0)