Merge "Packed virtqueue support was added."
This commit is contained in:
commit
8ac050c253
@ -4,5 +4,5 @@
|
|||||||
"hw_architecture": "x86_64"
|
"hw_architecture": "x86_64"
|
||||||
},
|
},
|
||||||
"nova_object.name": "ImageMetaPropsPayload",
|
"nova_object.name": "ImageMetaPropsPayload",
|
||||||
"nova_object.version": "1.12"
|
"nova_object.version": "1.13"
|
||||||
}
|
}
|
||||||
|
@ -527,6 +527,18 @@ feature_flag_validators = [
|
|||||||
'description': 'model for vIOMMU',
|
'description': 'model for vIOMMU',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
base.ExtraSpecValidator(
|
||||||
|
name='hw:virtio_packed_ring',
|
||||||
|
description=(
|
||||||
|
'Permit guests to negotiate the virtio packed ring format. '
|
||||||
|
'This requires guest support and is only supported by '
|
||||||
|
'the libvirt driver.'
|
||||||
|
),
|
||||||
|
value={
|
||||||
|
'type': bool,
|
||||||
|
'description': 'Whether to enable packed virtqueue',
|
||||||
|
},
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
ephemeral_encryption_validators = [
|
ephemeral_encryption_validators = [
|
||||||
|
@ -751,6 +751,9 @@ class API:
|
|||||||
if flavor['memory_mb'] < int(image.get('min_ram') or 0):
|
if flavor['memory_mb'] < int(image.get('min_ram') or 0):
|
||||||
raise exception.FlavorMemoryTooSmall()
|
raise exception.FlavorMemoryTooSmall()
|
||||||
|
|
||||||
|
# Verify flavor/image Virtio Packed Ring configuration conflict.
|
||||||
|
hardware.get_packed_virtqueue_constraint(flavor, image)
|
||||||
|
|
||||||
# Image min_disk is in gb, size is in bytes. For sanity, have them both
|
# Image min_disk is in gb, size is in bytes. For sanity, have them both
|
||||||
# in bytes.
|
# in bytes.
|
||||||
image_min_disk = int(image.get('min_disk') or 0) * units.Gi
|
image_min_disk = int(image.get('min_disk') or 0) * units.Gi
|
||||||
|
@ -130,7 +130,8 @@ class ImageMetaPropsPayload(base.NotificationPayloadBase):
|
|||||||
# 'hw_ephemeral_encryption_format' fields
|
# 'hw_ephemeral_encryption_format' fields
|
||||||
# Version 1.11: Added 'hw_locked_memory' field
|
# Version 1.11: Added 'hw_locked_memory' field
|
||||||
# Version 1.12: Added 'hw_viommu_model' field
|
# Version 1.12: Added 'hw_viommu_model' field
|
||||||
VERSION = '1.12'
|
# Version 1.13: Added 'hw_virtio_packed_ring' field
|
||||||
|
VERSION = '1.13'
|
||||||
|
|
||||||
SCHEMA = {
|
SCHEMA = {
|
||||||
k: ('image_meta_props', k) for k in image_meta.ImageMetaProps.fields}
|
k: ('image_meta_props', k) for k in image_meta.ImageMetaProps.fields}
|
||||||
|
@ -192,14 +192,17 @@ class ImageMetaProps(base.NovaObject):
|
|||||||
# 'hw_ephemeral_encryption_format' fields
|
# 'hw_ephemeral_encryption_format' fields
|
||||||
# Version 1.33: Added 'hw_locked_memory' field
|
# Version 1.33: Added 'hw_locked_memory' field
|
||||||
# Version 1.34: Added 'hw_viommu_model' field
|
# Version 1.34: Added 'hw_viommu_model' field
|
||||||
|
# Version 1.35: Added 'hw_virtio_packed_ring' field
|
||||||
# NOTE(efried): When bumping this version, the version of
|
# NOTE(efried): When bumping this version, the version of
|
||||||
# ImageMetaPropsPayload must also be bumped. See its docstring for details.
|
# ImageMetaPropsPayload must also be bumped. See its docstring for details.
|
||||||
VERSION = '1.34'
|
VERSION = '1.35'
|
||||||
|
|
||||||
def obj_make_compatible(self, primitive, target_version):
|
def obj_make_compatible(self, primitive, target_version):
|
||||||
super(ImageMetaProps, self).obj_make_compatible(primitive,
|
super(ImageMetaProps, self).obj_make_compatible(primitive,
|
||||||
target_version)
|
target_version)
|
||||||
target_version = versionutils.convert_version_to_tuple(target_version)
|
target_version = versionutils.convert_version_to_tuple(target_version)
|
||||||
|
if target_version < (1, 35):
|
||||||
|
primitive.pop('hw_virtio_packed_ring', None)
|
||||||
if target_version < (1, 34):
|
if target_version < (1, 34):
|
||||||
primitive.pop('hw_viommu_model', None)
|
primitive.pop('hw_viommu_model', None)
|
||||||
if target_version < (1, 33):
|
if target_version < (1, 33):
|
||||||
@ -473,6 +476,9 @@ class ImageMetaProps(base.NovaObject):
|
|||||||
'hw_ephemeral_encryption_format':
|
'hw_ephemeral_encryption_format':
|
||||||
fields.BlockDeviceEncryptionFormatTypeField(),
|
fields.BlockDeviceEncryptionFormatTypeField(),
|
||||||
|
|
||||||
|
# boolean - If true, this will enable the virtio packed ring feature
|
||||||
|
'hw_virtio_packed_ring': fields.FlexibleBooleanField(),
|
||||||
|
|
||||||
# if true download using bittorrent
|
# if true download using bittorrent
|
||||||
'img_bittorrent': fields.FlexibleBooleanField(),
|
'img_bittorrent': fields.FlexibleBooleanField(),
|
||||||
|
|
||||||
|
@ -271,6 +271,22 @@ def accelerators_filter(ctxt, request_spec):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@trace_request_filter
|
||||||
|
def packed_virtqueue_filter(ctxt, request_spec):
|
||||||
|
"""Allow only compute nodes with Packed virtqueue.
|
||||||
|
|
||||||
|
This filter retains only nodes whose compute manager published the
|
||||||
|
COMPUTE_NET_VIRTIO_PACKED trait, thus indicates virtqueue packed feature.
|
||||||
|
"""
|
||||||
|
trait_name = os_traits.COMPUTE_NET_VIRTIO_PACKED
|
||||||
|
if (hardware.get_packed_virtqueue_constraint(request_spec.flavor,
|
||||||
|
request_spec.image)):
|
||||||
|
request_spec.root_required.add(trait_name)
|
||||||
|
LOG.debug('virtqueue_filter request filter added required '
|
||||||
|
'trait %s', trait_name)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
@trace_request_filter
|
@trace_request_filter
|
||||||
def routed_networks_filter(
|
def routed_networks_filter(
|
||||||
ctxt: nova_context.RequestContext,
|
ctxt: nova_context.RequestContext,
|
||||||
@ -436,6 +452,7 @@ ALL_REQUEST_FILTERS = [
|
|||||||
isolate_aggregates,
|
isolate_aggregates,
|
||||||
transform_image_metadata,
|
transform_image_metadata,
|
||||||
accelerators_filter,
|
accelerators_filter,
|
||||||
|
packed_virtqueue_filter,
|
||||||
routed_networks_filter,
|
routed_networks_filter,
|
||||||
remote_managed_ports_filter,
|
remote_managed_ports_filter,
|
||||||
ephemeral_encryption_filter,
|
ephemeral_encryption_filter,
|
||||||
|
@ -18,6 +18,7 @@ Provides common functionality for integrated unit tests
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import datetime
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
@ -394,6 +395,32 @@ class InstanceHelperMixin:
|
|||||||
|
|
||||||
return flavor['id']
|
return flavor['id']
|
||||||
|
|
||||||
|
def _create_image(self, metadata):
|
||||||
|
image = {
|
||||||
|
'id': 'c456eb30-91d7-4f43-8f46-2efd9eccd744',
|
||||||
|
'name': 'fake-image-custom-property',
|
||||||
|
'created_at': datetime.datetime(2011, 1, 1, 1, 2, 3),
|
||||||
|
'updated_at': datetime.datetime(2011, 1, 1, 1, 2, 3),
|
||||||
|
'deleted_at': None,
|
||||||
|
'deleted': False,
|
||||||
|
'status': 'active',
|
||||||
|
'is_public': False,
|
||||||
|
'container_format': 'raw',
|
||||||
|
'disk_format': 'raw',
|
||||||
|
'size': '25165824',
|
||||||
|
'min_ram': 0,
|
||||||
|
'min_disk': 0,
|
||||||
|
'protected': False,
|
||||||
|
'visibility': 'public',
|
||||||
|
'tags': ['tag1', 'tag2'],
|
||||||
|
'properties': {
|
||||||
|
'kernel_id': 'nokernel',
|
||||||
|
'ramdisk_id': 'nokernel',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
image['properties'].update(metadata)
|
||||||
|
return self.glance.create(None, image)
|
||||||
|
|
||||||
def _build_server(self, name=None, image_uuid=None, flavor_id=None,
|
def _build_server(self, name=None, image_uuid=None, flavor_id=None,
|
||||||
networks=None, az=None, host=None):
|
networks=None, az=None, host=None):
|
||||||
"""Build a request for the server create API.
|
"""Build a request for the server create API.
|
||||||
|
@ -1238,7 +1238,7 @@ class TestInstanceNotificationSample(
|
|||||||
'nova_object.data': {},
|
'nova_object.data': {},
|
||||||
'nova_object.name': 'ImageMetaPropsPayload',
|
'nova_object.name': 'ImageMetaPropsPayload',
|
||||||
'nova_object.namespace': 'nova',
|
'nova_object.namespace': 'nova',
|
||||||
'nova_object.version': '1.12',
|
'nova_object.version': '1.13',
|
||||||
},
|
},
|
||||||
'image.size': 58145823,
|
'image.size': 58145823,
|
||||||
'image.tags': [],
|
'image.tags': [],
|
||||||
@ -1334,7 +1334,7 @@ class TestInstanceNotificationSample(
|
|||||||
'nova_object.data': {},
|
'nova_object.data': {},
|
||||||
'nova_object.name': 'ImageMetaPropsPayload',
|
'nova_object.name': 'ImageMetaPropsPayload',
|
||||||
'nova_object.namespace': 'nova',
|
'nova_object.namespace': 'nova',
|
||||||
'nova_object.version': '1.12',
|
'nova_object.version': '1.13',
|
||||||
},
|
},
|
||||||
'image.size': 58145823,
|
'image.size': 58145823,
|
||||||
'image.tags': [],
|
'image.tags': [],
|
||||||
|
@ -2188,6 +2188,77 @@ class ServerMovingTests(integrated_helpers.ProviderUsageBaseTestCase):
|
|||||||
self.assert_hypervisor_usage(
|
self.assert_hypervisor_usage(
|
||||||
dest_rp_uuid, self.flavor2, volume_backed=False)
|
dest_rp_uuid, self.flavor2, volume_backed=False)
|
||||||
|
|
||||||
|
def test_resize_server_conflict(self):
|
||||||
|
|
||||||
|
# Set appropriate traits for Resource Provider
|
||||||
|
rp_uuid1 = self._get_provider_uuid_by_host(self.compute1.host)
|
||||||
|
self._set_provider_traits(rp_uuid1, ['COMPUTE_NET_VIRTIO_PACKED'])
|
||||||
|
|
||||||
|
# Create image
|
||||||
|
image = self._create_image(metadata={'hw_virtio_packed_ring': 'true'})
|
||||||
|
|
||||||
|
# Create server
|
||||||
|
server = self._build_server(image_uuid=image['id'], networks='none')
|
||||||
|
created_server = self.api.post_server({"server": server})
|
||||||
|
created_server_id = created_server['id']
|
||||||
|
found_server = self._wait_for_state_change(created_server, 'ACTIVE')
|
||||||
|
|
||||||
|
# Create a flavor with conflict in relation to the image configuration
|
||||||
|
flavor_id = self._create_flavor(
|
||||||
|
extra_spec={'hw:virtio_packed_ring': 'false'})
|
||||||
|
|
||||||
|
# Resize server(flavorRef: 1 -> 2)
|
||||||
|
post = {'resize': {"flavorRef": flavor_id}}
|
||||||
|
|
||||||
|
ex = self.assertRaises(client.OpenStackApiException,
|
||||||
|
self.api.post_server_action,
|
||||||
|
created_server_id, post)
|
||||||
|
|
||||||
|
# By returning 400, We want to confirm that the RESIZE server
|
||||||
|
# does not cause unexpected behavior.
|
||||||
|
self.assertEqual(400, ex.response.status_code)
|
||||||
|
|
||||||
|
# Verify that the instance is still in the Active state
|
||||||
|
self.assertEqual('ACTIVE', found_server['status'])
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
self._delete_server(found_server)
|
||||||
|
|
||||||
|
def test_rebuild_server_conflict(self):
|
||||||
|
|
||||||
|
# Set appropriate traits for Resource Provider
|
||||||
|
rp_uuid1 = self._get_provider_uuid_by_host(self.compute1.host)
|
||||||
|
self._set_provider_traits(rp_uuid1, ['COMPUTE_NET_VIRTIO_PACKED'])
|
||||||
|
|
||||||
|
# Create flavor
|
||||||
|
flavor_id = self._create_flavor(
|
||||||
|
extra_spec={'hw:virtio_packed_ring': 'true'})
|
||||||
|
|
||||||
|
# Create server
|
||||||
|
server = self._build_server(flavor_id=flavor_id, networks='none')
|
||||||
|
created_server = self.api.post_server({"server": server})
|
||||||
|
created_server_id = created_server['id']
|
||||||
|
found_server = self._wait_for_state_change(created_server, 'ACTIVE')
|
||||||
|
|
||||||
|
# Create an image with conflict in relation to the flavor configuration
|
||||||
|
image = self._create_image(metadata={'hw_virtio_packed_ring': 'false'})
|
||||||
|
|
||||||
|
# Now rebuild the server with a different image
|
||||||
|
post = {'rebuild': {'imageRef': image['id']}}
|
||||||
|
ex = self.assertRaises(client.OpenStackApiException,
|
||||||
|
self.api.post_server_action,
|
||||||
|
created_server_id, post)
|
||||||
|
|
||||||
|
# By returning 400, We want to confirm that the RESIZE server
|
||||||
|
# does not cause unexpected behavior.
|
||||||
|
self.assertEqual(400, ex.response.status_code)
|
||||||
|
|
||||||
|
# Verify that the instance is still in the Active state
|
||||||
|
self.assertEqual('ACTIVE', found_server['status'])
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
self._delete_server(found_server)
|
||||||
|
|
||||||
def test_evacuate_with_no_compute(self):
|
def test_evacuate_with_no_compute(self):
|
||||||
source_hostname = self.compute1.host
|
source_hostname = self.compute1.host
|
||||||
dest_hostname = self.compute2.host
|
dest_hostname = self.compute2.host
|
||||||
|
@ -386,7 +386,7 @@ notification_object_data = {
|
|||||||
# ImageMetaProps, so when you see a fail here for that reason, you must
|
# ImageMetaProps, so when you see a fail here for that reason, you must
|
||||||
# *also* bump the version of ImageMetaPropsPayload. See its docstring for
|
# *also* bump the version of ImageMetaPropsPayload. See its docstring for
|
||||||
# more information.
|
# more information.
|
||||||
'ImageMetaPropsPayload': '1.12-b9c64832d7772c1973e913bacbe0e8f9',
|
'ImageMetaPropsPayload': '1.13-24345c28a6463e85e12902d43af0ecf2',
|
||||||
'InstanceActionNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
'InstanceActionNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||||
'InstanceActionPayload': '1.8-4fa3da9cbf0761f1f700ae578f36dc2f',
|
'InstanceActionPayload': '1.8-4fa3da9cbf0761f1f700ae578f36dc2f',
|
||||||
'InstanceActionRebuildNotification':
|
'InstanceActionRebuildNotification':
|
||||||
|
@ -1105,7 +1105,7 @@ object_data = {
|
|||||||
'HyperVLiveMigrateData': '1.4-e265780e6acfa631476c8170e8d6fce0',
|
'HyperVLiveMigrateData': '1.4-e265780e6acfa631476c8170e8d6fce0',
|
||||||
'IDEDeviceBus': '1.0-29d4c9f27ac44197f01b6ac1b7e16502',
|
'IDEDeviceBus': '1.0-29d4c9f27ac44197f01b6ac1b7e16502',
|
||||||
'ImageMeta': '1.8-642d1b2eb3e880a367f37d72dd76162d',
|
'ImageMeta': '1.8-642d1b2eb3e880a367f37d72dd76162d',
|
||||||
'ImageMetaProps': '1.34-29b3a6b7fe703f36bfd240d914f16c21',
|
'ImageMetaProps': '1.35-66ec4135a4c08d6e67e39cb0400b059e',
|
||||||
'Instance': '2.8-2727dba5e4a078e6cc848c1f94f7eb24',
|
'Instance': '2.8-2727dba5e4a078e6cc848c1f94f7eb24',
|
||||||
'InstanceAction': '1.2-9a5abc87fdd3af46f45731960651efb5',
|
'InstanceAction': '1.2-9a5abc87fdd3af46f45731960651efb5',
|
||||||
'InstanceActionEvent': '1.4-5b1f361bd81989f8bb2c20bb7e8a4cb4',
|
'InstanceActionEvent': '1.4-5b1f361bd81989f8bb2c20bb7e8a4cb4',
|
||||||
|
@ -499,6 +499,41 @@ class TestRequestFilter(test.NoDBTestCase):
|
|||||||
# Assert about logging
|
# Assert about logging
|
||||||
mock_log.assert_not_called()
|
mock_log.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch.object(request_filter, 'LOG')
|
||||||
|
def test_virtio_filter_with_packed_ring_in_flavor(self, mock_log):
|
||||||
|
# First ensure that packed_virtqueue_filter is included
|
||||||
|
self.assertIn(request_filter.packed_virtqueue_filter,
|
||||||
|
request_filter.ALL_REQUEST_FILTERS)
|
||||||
|
|
||||||
|
es = {'hw:virtio_packed_ring': 'true'}
|
||||||
|
reqspec = objects.RequestSpec(
|
||||||
|
flavor=objects.Flavor(extra_specs=es),
|
||||||
|
image=objects.ImageMeta(properties=objects.ImageMetaProps()))
|
||||||
|
self.assertEqual(set(), reqspec.root_required)
|
||||||
|
self.assertEqual(set(), reqspec.root_forbidden)
|
||||||
|
|
||||||
|
# Request filter puts the trait into the request spec
|
||||||
|
request_filter.packed_virtqueue_filter(self.context, reqspec)
|
||||||
|
self.assertEqual({ot.COMPUTE_NET_VIRTIO_PACKED}, reqspec.root_required)
|
||||||
|
self.assertEqual(set(), reqspec.root_forbidden)
|
||||||
|
|
||||||
|
@mock.patch.object(request_filter, 'LOG')
|
||||||
|
def test_virtio_filter_with_packed_ring_in_image(self, mock_log):
|
||||||
|
# First ensure that packed_virtqueue_filter is included
|
||||||
|
self.assertIn(request_filter.packed_virtqueue_filter,
|
||||||
|
request_filter.ALL_REQUEST_FILTERS)
|
||||||
|
|
||||||
|
reqspec = objects.RequestSpec(flavor=objects.Flavor(extra_specs={}),
|
||||||
|
image=objects.ImageMeta(
|
||||||
|
properties=objects.ImageMetaProps(hw_virtio_packed_ring=True)))
|
||||||
|
self.assertEqual(set(), reqspec.root_required)
|
||||||
|
self.assertEqual(set(), reqspec.root_forbidden)
|
||||||
|
|
||||||
|
# Request filter puts the trait into the request spec
|
||||||
|
request_filter.packed_virtqueue_filter(self.context, reqspec)
|
||||||
|
self.assertEqual({ot.COMPUTE_NET_VIRTIO_PACKED}, reqspec.root_required)
|
||||||
|
self.assertEqual(set(), reqspec.root_forbidden)
|
||||||
|
|
||||||
def test_routed_networks_filter_not_enabled(self):
|
def test_routed_networks_filter_not_enabled(self):
|
||||||
self.assertIn(request_filter.routed_networks_filter,
|
self.assertIn(request_filter.routed_networks_filter,
|
||||||
request_filter.ALL_REQUEST_FILTERS)
|
request_filter.ALL_REQUEST_FILTERS)
|
||||||
|
@ -1923,6 +1923,26 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
|
|||||||
self.assertTrue(obj.uses_virtio)
|
self.assertTrue(obj.uses_virtio)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
def test_config_driver_packed_options(self):
|
||||||
|
obj = self._get_virtio_interface()
|
||||||
|
obj.driver_name = "vhost"
|
||||||
|
obj.driver_packed = True
|
||||||
|
|
||||||
|
xml = obj.to_xml()
|
||||||
|
self.assertXmlEqual(xml, """
|
||||||
|
<interface type="ethernet">
|
||||||
|
<mac address="DE:AD:BE:EF:CA:FE"/>
|
||||||
|
<model type="virtio"/>
|
||||||
|
<driver name="vhost" packed="on"/>
|
||||||
|
<target dev="vnet0"/>
|
||||||
|
</interface>""")
|
||||||
|
|
||||||
|
# parse the xml from the first object into a new object and make sure
|
||||||
|
# they are the same
|
||||||
|
obj2 = config.LibvirtConfigGuestInterface()
|
||||||
|
obj2.parse_str(xml)
|
||||||
|
self.assertXmlEqual(xml, obj2.to_xml())
|
||||||
|
|
||||||
def test_config_driver_options(self):
|
def test_config_driver_options(self):
|
||||||
obj = self._get_virtio_interface()
|
obj = self._get_virtio_interface()
|
||||||
obj.driver_name = "vhost"
|
obj.driver_name = "vhost"
|
||||||
|
@ -40,7 +40,7 @@ class DesignerTestCase(test.NoDBTestCase):
|
|||||||
conf = config.LibvirtConfigGuestInterface()
|
conf = config.LibvirtConfigGuestInterface()
|
||||||
designer.set_vif_guest_frontend_config(conf, 'fake-mac',
|
designer.set_vif_guest_frontend_config(conf, 'fake-mac',
|
||||||
'fake-model', 'fake-driver',
|
'fake-model', 'fake-driver',
|
||||||
'fake-queues', None)
|
'fake-queues', None, None)
|
||||||
self.assertEqual('fake-mac', conf.mac_addr)
|
self.assertEqual('fake-mac', conf.mac_addr)
|
||||||
self.assertEqual('fake-model', conf.model)
|
self.assertEqual('fake-model', conf.model)
|
||||||
self.assertEqual('fake-driver', conf.driver_name)
|
self.assertEqual('fake-driver', conf.driver_name)
|
||||||
@ -51,7 +51,7 @@ class DesignerTestCase(test.NoDBTestCase):
|
|||||||
conf = config.LibvirtConfigGuestInterface()
|
conf = config.LibvirtConfigGuestInterface()
|
||||||
designer.set_vif_guest_frontend_config(conf, 'fake-mac',
|
designer.set_vif_guest_frontend_config(conf, 'fake-mac',
|
||||||
'fake-model', 'fake-driver',
|
'fake-model', 'fake-driver',
|
||||||
'fake-queues', 1024)
|
'fake-queues', 1024, None)
|
||||||
self.assertEqual('fake-mac', conf.mac_addr)
|
self.assertEqual('fake-mac', conf.mac_addr)
|
||||||
self.assertEqual('fake-model', conf.model)
|
self.assertEqual('fake-model', conf.model)
|
||||||
self.assertEqual('fake-driver', conf.driver_name)
|
self.assertEqual('fake-driver', conf.driver_name)
|
||||||
|
@ -992,6 +992,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||||||
expected = {
|
expected = {
|
||||||
'COMPUTE_GRAPHICS_MODEL_VGA': True,
|
'COMPUTE_GRAPHICS_MODEL_VGA': True,
|
||||||
'COMPUTE_NET_VIF_MODEL_VIRTIO': True,
|
'COMPUTE_NET_VIF_MODEL_VIRTIO': True,
|
||||||
|
'COMPUTE_NET_VIRTIO_PACKED': True,
|
||||||
'COMPUTE_SECURITY_TPM_1_2': False,
|
'COMPUTE_SECURITY_TPM_1_2': False,
|
||||||
'COMPUTE_SECURITY_TPM_2_0': False,
|
'COMPUTE_SECURITY_TPM_2_0': False,
|
||||||
'COMPUTE_STORAGE_BUS_VIRTIO': True,
|
'COMPUTE_STORAGE_BUS_VIRTIO': True,
|
||||||
@ -1030,7 +1031,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_storage_bus_traits')
|
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_storage_bus_traits')
|
||||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_video_model_traits')
|
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_video_model_traits')
|
||||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_vif_model_traits')
|
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_vif_model_traits')
|
||||||
def test_static_traits__invalid_trait(
|
def test_static_traits_invalid_trait(
|
||||||
self, mock_vif_traits, mock_video_traits, mock_storage_traits,
|
self, mock_vif_traits, mock_video_traits, mock_storage_traits,
|
||||||
mock_cpu_traits, mock_log,
|
mock_cpu_traits, mock_log,
|
||||||
):
|
):
|
||||||
@ -1043,6 +1044,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||||
expected = {
|
expected = {
|
||||||
'COMPUTE_NET_VIF_MODEL_VIRTIO': True,
|
'COMPUTE_NET_VIF_MODEL_VIRTIO': True,
|
||||||
|
'COMPUTE_NET_VIRTIO_PACKED': True,
|
||||||
'COMPUTE_SECURITY_TPM_1_2': False,
|
'COMPUTE_SECURITY_TPM_1_2': False,
|
||||||
'COMPUTE_SECURITY_TPM_2_0': False,
|
'COMPUTE_SECURITY_TPM_2_0': False,
|
||||||
'COMPUTE_VIOMMU_MODEL_AUTO': True,
|
'COMPUTE_VIOMMU_MODEL_AUTO': True,
|
||||||
|
@ -725,6 +725,38 @@ class LibvirtVifTestCase(test.NoDBTestCase):
|
|||||||
self.assertEqual(4, conf.vhost_queues)
|
self.assertEqual(4, conf.vhost_queues)
|
||||||
self.assertIsNone(conf.driver_name)
|
self.assertIsNone(conf.driver_name)
|
||||||
|
|
||||||
|
def _test_virtio_packed_config(self, image_meta, flavor):
|
||||||
|
d = vif.LibvirtGenericVIFDriver()
|
||||||
|
|
||||||
|
xml = self._get_instance_xml(d, self.vif_bridge,
|
||||||
|
image_meta, flavor)
|
||||||
|
|
||||||
|
node = self._get_node(xml)
|
||||||
|
packed = node.find("driver").get("packed")
|
||||||
|
self.assertEqual(packed, 'on')
|
||||||
|
|
||||||
|
def test_image_packed_config(self):
|
||||||
|
extra_specs = {}
|
||||||
|
extra_specs['hw:virtio_packed_ring'] = True
|
||||||
|
|
||||||
|
flavor = objects.Flavor(
|
||||||
|
name='foo', vcpus=2, memory_mb=1024, extra_specs=extra_specs)
|
||||||
|
image_meta = objects.ImageMeta.from_dict(
|
||||||
|
{'name': 'bar', 'properties': {}})
|
||||||
|
|
||||||
|
self._test_virtio_packed_config(image_meta, flavor)
|
||||||
|
|
||||||
|
def test_flavor_packed_config(self):
|
||||||
|
image_meta_props = {}
|
||||||
|
image_meta_props['hw_virtio_packed_ring'] = True
|
||||||
|
|
||||||
|
flavor = objects.Flavor(
|
||||||
|
name='foo', vcpus=2, memory_mb=1024, extra_specs={})
|
||||||
|
image_meta = objects.ImageMeta.from_dict(
|
||||||
|
{'name': 'bar', 'properties': image_meta_props})
|
||||||
|
|
||||||
|
self._test_virtio_packed_config(image_meta, flavor)
|
||||||
|
|
||||||
def _test_virtio_config_queue_sizes(
|
def _test_virtio_config_queue_sizes(
|
||||||
self, vnic_type=network_model.VNIC_TYPE_NORMAL):
|
self, vnic_type=network_model.VNIC_TYPE_NORMAL):
|
||||||
self.flags(rx_queue_size=512, group='libvirt')
|
self.flags(rx_queue_size=512, group='libvirt')
|
||||||
@ -895,7 +927,7 @@ class LibvirtVifTestCase(test.NoDBTestCase):
|
|||||||
d.get_base_config(None, 'ca:fe:de:ad:be:ef', image_meta,
|
d.get_base_config(None, 'ca:fe:de:ad:be:ef', image_meta,
|
||||||
flavor, 'kvm', 'normal')
|
flavor, 'kvm', 'normal')
|
||||||
mock_set.assert_called_once_with(mock.ANY, 'ca:fe:de:ad:be:ef',
|
mock_set.assert_called_once_with(mock.ANY, 'ca:fe:de:ad:be:ef',
|
||||||
'virtio', None, None, None)
|
'virtio', None, None, None, False)
|
||||||
|
|
||||||
@mock.patch.object(vif.designer, 'set_vif_guest_frontend_config',
|
@mock.patch.object(vif.designer, 'set_vif_guest_frontend_config',
|
||||||
wraps=vif.designer.set_vif_guest_frontend_config)
|
wraps=vif.designer.set_vif_guest_frontend_config)
|
||||||
@ -911,9 +943,9 @@ class LibvirtVifTestCase(test.NoDBTestCase):
|
|||||||
image_meta = objects.ImageMeta.from_dict(
|
image_meta = objects.ImageMeta.from_dict(
|
||||||
{'properties': {'hw_vif_model': 'virtio'}})
|
{'properties': {'hw_vif_model': 'virtio'}})
|
||||||
conf = d.get_base_config(None, 'ca:fe:de:ad:be:ef', image_meta,
|
conf = d.get_base_config(None, 'ca:fe:de:ad:be:ef', image_meta,
|
||||||
None, 'kvm', vnic_type)
|
objects.Flavor(vcpus=2), 'kvm', vnic_type)
|
||||||
mock_set.assert_called_once_with(mock.ANY, 'ca:fe:de:ad:be:ef',
|
mock_set.assert_called_once_with(mock.ANY, 'ca:fe:de:ad:be:ef',
|
||||||
None, None, None, None)
|
None, None, None, None, False)
|
||||||
self.assertIsNone(conf.vhost_queues)
|
self.assertIsNone(conf.vhost_queues)
|
||||||
self.assertIsNone(conf.driver_name)
|
self.assertIsNone(conf.driver_name)
|
||||||
self.assertIsNone(conf.model)
|
self.assertIsNone(conf.model)
|
||||||
|
@ -5701,11 +5701,57 @@ class VIFMultiqueueEnabledTest(test.NoDBTestCase):
|
|||||||
|
|
||||||
if isinstance(expected, type) and issubclass(expected, Exception):
|
if isinstance(expected, type) and issubclass(expected, Exception):
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
expected, hw.get_vif_multiqueue_constraint, flavor, image_meta,
|
expected, hw.get_vif_multiqueue_constraint, flavor, image_meta
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected, hw.get_vif_multiqueue_constraint(flavor, image_meta),
|
expected, hw.get_vif_multiqueue_constraint(flavor, image_meta)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class VIFVirtioEnabledTest(test.NoDBTestCase):
|
||||||
|
|
||||||
|
@ddt.unpack
|
||||||
|
@ddt.data(
|
||||||
|
# pass: no configuration
|
||||||
|
(None, None, False),
|
||||||
|
# pass: flavor-only configuration
|
||||||
|
('yes', None, True),
|
||||||
|
# pass: image-only configuration
|
||||||
|
(None, True, True),
|
||||||
|
# pass: identical image and flavor configuration
|
||||||
|
('yes', True, True),
|
||||||
|
# fail: mismatched image and flavor configuration
|
||||||
|
('no', True, exception.FlavorImageConflict),
|
||||||
|
)
|
||||||
|
def test_get_vif_virtio_constraint(
|
||||||
|
self, flavor_policy, image_policy, expected,
|
||||||
|
):
|
||||||
|
extra_specs = {}
|
||||||
|
|
||||||
|
if flavor_policy:
|
||||||
|
extra_specs['hw:virtio_packed_ring'] = flavor_policy
|
||||||
|
|
||||||
|
image_meta_props = {}
|
||||||
|
|
||||||
|
if image_policy:
|
||||||
|
image_meta_props['hw_virtio_packed_ring'] = image_policy
|
||||||
|
|
||||||
|
flavor = objects.Flavor(
|
||||||
|
name='foo', vcpus=2, memory_mb=1024, extra_specs=extra_specs)
|
||||||
|
image_meta = objects.ImageMeta.from_dict(
|
||||||
|
{'name': 'bar', 'properties': image_meta_props})
|
||||||
|
|
||||||
|
if isinstance(expected, type) and issubclass(expected, Exception):
|
||||||
|
self.assertRaises(
|
||||||
|
expected, hw.get_packed_virtqueue_constraint,
|
||||||
|
flavor, image_meta,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.assertEqual(
|
||||||
|
expected, hw.get_packed_virtqueue_constraint(
|
||||||
|
flavor, image_meta),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1941,6 +1941,56 @@ def get_vif_multiqueue_constraint(
|
|||||||
return flavor_value or image_value or False
|
return flavor_value or image_value or False
|
||||||
|
|
||||||
|
|
||||||
|
def get_packed_virtqueue_constraint(
|
||||||
|
flavor,
|
||||||
|
image_meta,
|
||||||
|
) -> bool:
|
||||||
|
"""Validate and return the requested Packed virtqueue configuration.
|
||||||
|
|
||||||
|
:param flavor: ``nova.objects.Flavor`` or dict instance
|
||||||
|
:param image_meta: ``nova.objects.ImageMeta`` or dict instance
|
||||||
|
:raises: nova.exception.FlavorImageConflict if a value is specified in both
|
||||||
|
the flavor and the image, but the values do not match
|
||||||
|
:returns: True if the Packed virtqueue must be enabled, else False.
|
||||||
|
"""
|
||||||
|
key_value = 'virtio_packed_ring'
|
||||||
|
|
||||||
|
if type(image_meta) is dict:
|
||||||
|
flavor_key = ':'.join(['hw', key_value])
|
||||||
|
image_key = '_'.join(['hw', key_value])
|
||||||
|
flavor_value_str = flavor.get('extra_specs', {}).get(flavor_key, None)
|
||||||
|
image_value = image_meta.get('properties', {}).get(image_key, None)
|
||||||
|
else:
|
||||||
|
flavor_value_str, image_value = _get_flavor_image_meta(
|
||||||
|
key_value, flavor, image_meta)
|
||||||
|
|
||||||
|
flavor_value = None
|
||||||
|
if flavor_value_str is not None:
|
||||||
|
flavor_value = strutils.bool_from_string(flavor_value_str)
|
||||||
|
|
||||||
|
if (
|
||||||
|
image_value is not None and
|
||||||
|
flavor_value is not None and
|
||||||
|
image_value != flavor_value
|
||||||
|
):
|
||||||
|
msg = _(
|
||||||
|
"Flavor has %(prefix)s:%(key)s extra spec "
|
||||||
|
"explicitly set to %(flavor_val)s, conflicting with image "
|
||||||
|
"which has %(prefix)s_%(key)s explicitly set to "
|
||||||
|
"%(image_val)s."
|
||||||
|
)
|
||||||
|
raise exception.FlavorImageConflict(
|
||||||
|
msg % {
|
||||||
|
'prefix': 'hw',
|
||||||
|
'key': key_value,
|
||||||
|
'flavor_val': flavor_value,
|
||||||
|
'image_val': image_value,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return flavor_value or image_value or False
|
||||||
|
|
||||||
|
|
||||||
def get_vtpm_constraint(
|
def get_vtpm_constraint(
|
||||||
flavor: 'objects.Flavor',
|
flavor: 'objects.Flavor',
|
||||||
image_meta: 'objects.ImageMeta',
|
image_meta: 'objects.ImageMeta',
|
||||||
|
@ -1765,6 +1765,7 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
|
|||||||
self.filterparams = []
|
self.filterparams = []
|
||||||
self.driver_name = None
|
self.driver_name = None
|
||||||
self.driver_iommu = False
|
self.driver_iommu = False
|
||||||
|
self.driver_packed = False
|
||||||
self.vhostuser_mode = None
|
self.vhostuser_mode = None
|
||||||
self.vhostuser_path = None
|
self.vhostuser_path = None
|
||||||
self.vhostuser_type = None
|
self.vhostuser_type = None
|
||||||
@ -1817,6 +1818,7 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
|
|||||||
drv_elem = None
|
drv_elem = None
|
||||||
if (self.driver_name or
|
if (self.driver_name or
|
||||||
self.driver_iommu or
|
self.driver_iommu or
|
||||||
|
self.driver_packed or
|
||||||
self.net_type == "vhostuser"):
|
self.net_type == "vhostuser"):
|
||||||
|
|
||||||
drv_elem = etree.Element("driver")
|
drv_elem = etree.Element("driver")
|
||||||
@ -1825,6 +1827,8 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
|
|||||||
drv_elem.set("name", self.driver_name)
|
drv_elem.set("name", self.driver_name)
|
||||||
if self.driver_iommu:
|
if self.driver_iommu:
|
||||||
drv_elem.set("iommu", "on")
|
drv_elem.set("iommu", "on")
|
||||||
|
if self.driver_packed:
|
||||||
|
drv_elem.set("packed", "on")
|
||||||
|
|
||||||
if drv_elem is not None:
|
if drv_elem is not None:
|
||||||
if self.vhost_queues is not None:
|
if self.vhost_queues is not None:
|
||||||
@ -1837,7 +1841,8 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
|
|||||||
if (drv_elem.get('name') or drv_elem.get('queues') or
|
if (drv_elem.get('name') or drv_elem.get('queues') or
|
||||||
drv_elem.get('rx_queue_size') or
|
drv_elem.get('rx_queue_size') or
|
||||||
drv_elem.get('tx_queue_size') or
|
drv_elem.get('tx_queue_size') or
|
||||||
drv_elem.get('iommu')):
|
drv_elem.get('iommu') or
|
||||||
|
drv_elem.get('packed')):
|
||||||
# Append the driver element into the dom only if name
|
# Append the driver element into the dom only if name
|
||||||
# or queues or tx/rx or iommu attributes are set.
|
# or queues or tx/rx or iommu attributes are set.
|
||||||
dev.append(drv_elem)
|
dev.append(drv_elem)
|
||||||
@ -1937,6 +1942,7 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
|
|||||||
elif c.tag == 'driver':
|
elif c.tag == 'driver':
|
||||||
self.driver_name = c.get('name')
|
self.driver_name = c.get('name')
|
||||||
self.driver_iommu = (c.get('iommu', '') == 'on')
|
self.driver_iommu = (c.get('iommu', '') == 'on')
|
||||||
|
self.driver_packed = (c.get('packed', '') == 'on')
|
||||||
self.vhost_queues = c.get('queues')
|
self.vhost_queues = c.get('queues')
|
||||||
self.vhost_rx_queue_size = c.get('rx_queue_size')
|
self.vhost_rx_queue_size = c.get('rx_queue_size')
|
||||||
self.vhost_tx_queue_size = c.get('tx_queue_size')
|
self.vhost_tx_queue_size = c.get('tx_queue_size')
|
||||||
|
@ -24,7 +24,7 @@ from nova.pci import utils as pci_utils
|
|||||||
|
|
||||||
|
|
||||||
def set_vif_guest_frontend_config(conf, mac, model, driver, queues,
|
def set_vif_guest_frontend_config(conf, mac, model, driver, queues,
|
||||||
rx_queue_size):
|
rx_queue_size, packed):
|
||||||
"""Populate a LibvirtConfigGuestInterface instance
|
"""Populate a LibvirtConfigGuestInterface instance
|
||||||
with guest frontend details.
|
with guest frontend details.
|
||||||
|
|
||||||
@ -39,6 +39,8 @@ def set_vif_guest_frontend_config(conf, mac, model, driver, queues,
|
|||||||
conf.vhost_queues = queues
|
conf.vhost_queues = queues
|
||||||
if rx_queue_size:
|
if rx_queue_size:
|
||||||
conf.vhost_rx_queue_size = rx_queue_size
|
conf.vhost_rx_queue_size = rx_queue_size
|
||||||
|
if packed is not None:
|
||||||
|
conf.driver_packed = packed
|
||||||
|
|
||||||
|
|
||||||
def set_vif_host_backend_ethernet_config(conf, tapname):
|
def set_vif_host_backend_ethernet_config(conf, tapname):
|
||||||
|
@ -224,17 +224,14 @@ NEXT_MIN_QEMU_VERSION = (6, 2, 0)
|
|||||||
# vIOMMU model value `virtio` minimal support version
|
# vIOMMU model value `virtio` minimal support version
|
||||||
MIN_LIBVIRT_VIOMMU_VIRTIO_MODEL = (8, 3, 0)
|
MIN_LIBVIRT_VIOMMU_VIRTIO_MODEL = (8, 3, 0)
|
||||||
|
|
||||||
|
|
||||||
MIN_LIBVIRT_TB_CACHE_SIZE = (8, 0, 0)
|
MIN_LIBVIRT_TB_CACHE_SIZE = (8, 0, 0)
|
||||||
|
|
||||||
# Virtuozzo driver support
|
# Virtuozzo driver support
|
||||||
MIN_VIRTUOZZO_VERSION = (7, 0, 0)
|
MIN_VIRTUOZZO_VERSION = (7, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
# Names of the types that do not get compressed during migration
|
# Names of the types that do not get compressed during migration
|
||||||
NO_COMPRESSION_TYPES = ('qcow2',)
|
NO_COMPRESSION_TYPES = ('qcow2',)
|
||||||
|
|
||||||
|
|
||||||
# number of serial console limit
|
# number of serial console limit
|
||||||
QEMU_MAX_SERIAL_PORTS = 4
|
QEMU_MAX_SERIAL_PORTS = 4
|
||||||
# Qemu supports 4 serial consoles, we remove 1 because of the PTY one defined
|
# Qemu supports 4 serial consoles, we remove 1 because of the PTY one defined
|
||||||
@ -244,7 +241,6 @@ VGPU_RESOURCE_SEMAPHORE = 'vgpu_resources'
|
|||||||
|
|
||||||
LIBVIRT_PERF_EVENT_PREFIX = 'VIR_PERF_PARAM_'
|
LIBVIRT_PERF_EVENT_PREFIX = 'VIR_PERF_PARAM_'
|
||||||
|
|
||||||
|
|
||||||
# Maxphysaddr minimal support version.
|
# Maxphysaddr minimal support version.
|
||||||
MIN_LIBVIRT_MAXPHYSADDR = (8, 7, 0)
|
MIN_LIBVIRT_MAXPHYSADDR = (8, 7, 0)
|
||||||
MIN_QEMU_MAXPHYSADDR = (2, 7, 0)
|
MIN_QEMU_MAXPHYSADDR = (2, 7, 0)
|
||||||
@ -9041,6 +9037,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
|
|
||||||
traits: ty.Dict[str, bool] = {}
|
traits: ty.Dict[str, bool] = {}
|
||||||
traits.update(self._get_cpu_traits())
|
traits.update(self._get_cpu_traits())
|
||||||
|
traits.update(self._get_packed_virtqueue_traits())
|
||||||
traits.update(self._get_storage_bus_traits())
|
traits.update(self._get_storage_bus_traits())
|
||||||
traits.update(self._get_video_model_traits())
|
traits.update(self._get_video_model_traits())
|
||||||
traits.update(self._get_vif_model_traits())
|
traits.update(self._get_vif_model_traits())
|
||||||
@ -12423,6 +12420,14 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
in supported_models for model in all_models
|
in supported_models for model in all_models
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _get_packed_virtqueue_traits(self) -> ty.Dict[str, bool]:
|
||||||
|
"""Get Virtio Packed Ring traits to be set on the host's
|
||||||
|
resource provider.
|
||||||
|
|
||||||
|
:return: A dict of trait names mapped to boolean values.
|
||||||
|
"""
|
||||||
|
return {ot.COMPUTE_NET_VIRTIO_PACKED: True}
|
||||||
|
|
||||||
def _get_cpu_traits(self) -> ty.Dict[str, bool]:
|
def _get_cpu_traits(self) -> ty.Dict[str, bool]:
|
||||||
"""Get CPU-related traits to be set and unset on the host's resource
|
"""Get CPU-related traits to be set and unset on the host's resource
|
||||||
provider.
|
provider.
|
||||||
|
@ -192,11 +192,13 @@ class LibvirtGenericVIFDriver(object):
|
|||||||
vhost_queues = None
|
vhost_queues = None
|
||||||
rx_queue_size = None
|
rx_queue_size = None
|
||||||
|
|
||||||
|
packed = self._get_packed_virtqueue_settings(
|
||||||
|
image_meta, flavor)
|
||||||
# NOTE(stephenfin): Skip most things here as only apply to virtio
|
# NOTE(stephenfin): Skip most things here as only apply to virtio
|
||||||
# devices
|
# devices
|
||||||
if vnic_type in network_model.VNIC_TYPES_DIRECT_PASSTHROUGH:
|
if vnic_type in network_model.VNIC_TYPES_DIRECT_PASSTHROUGH:
|
||||||
designer.set_vif_guest_frontend_config(
|
designer.set_vif_guest_frontend_config(
|
||||||
conf, mac, model, driver, vhost_queues, rx_queue_size)
|
conf, mac, model, driver, vhost_queues, rx_queue_size, packed)
|
||||||
return conf
|
return conf
|
||||||
|
|
||||||
rx_queue_size = CONF.libvirt.rx_queue_size
|
rx_queue_size = CONF.libvirt.rx_queue_size
|
||||||
@ -211,7 +213,7 @@ class LibvirtGenericVIFDriver(object):
|
|||||||
# The rest of this only applies to virtio
|
# The rest of this only applies to virtio
|
||||||
if model != network_model.VIF_MODEL_VIRTIO:
|
if model != network_model.VIF_MODEL_VIRTIO:
|
||||||
designer.set_vif_guest_frontend_config(
|
designer.set_vif_guest_frontend_config(
|
||||||
conf, mac, model, driver, vhost_queues, rx_queue_size)
|
conf, mac, model, driver, vhost_queues, rx_queue_size, packed)
|
||||||
return conf
|
return conf
|
||||||
|
|
||||||
# Workaround libvirt bug, where it mistakenly enables vhost mode, even
|
# Workaround libvirt bug, where it mistakenly enables vhost mode, even
|
||||||
@ -243,7 +245,7 @@ class LibvirtGenericVIFDriver(object):
|
|||||||
driver = 'vhost'
|
driver = 'vhost'
|
||||||
|
|
||||||
designer.set_vif_guest_frontend_config(
|
designer.set_vif_guest_frontend_config(
|
||||||
conf, mac, model, driver, vhost_queues, rx_queue_size)
|
conf, mac, model, driver, vhost_queues, rx_queue_size, packed)
|
||||||
|
|
||||||
return conf
|
return conf
|
||||||
|
|
||||||
@ -296,6 +298,13 @@ class LibvirtGenericVIFDriver(object):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _get_packed_virtqueue_settings(self, image_meta, flavor):
|
||||||
|
"""A method to check if Virtio Packed Ring was requested."""
|
||||||
|
if not isinstance(image_meta, objects.ImageMeta):
|
||||||
|
image_meta = objects.ImageMeta.from_dict(image_meta)
|
||||||
|
|
||||||
|
return hardware.get_packed_virtqueue_constraint(flavor, image_meta)
|
||||||
|
|
||||||
def get_bridge_name(self, vif):
|
def get_bridge_name(self, vif):
|
||||||
return vif['network']['bridge']
|
return vif['network']['bridge']
|
||||||
|
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Handling packed virtqueue requests for an instance is now supported on
|
||||||
|
the nodes with Qemu v4.2 and Libvirt v6.3.
|
||||||
|
|
||||||
|
VMs using virtio-net will see an increase in performance. The increase
|
||||||
|
can be anywhere between 10/20% (see DPDK Intel Vhost/virtio perf. reports)
|
||||||
|
and 75% (using Napatech SmartNICs).
|
||||||
|
|
||||||
|
Packed Ring can be requested via image property or flavor extra spec.
|
||||||
|
hw_virtio_packed_ring=true|false (default false)
|
||||||
|
hw:virtio_packed_ring=true|false (default false)
|
||||||
|
|
||||||
|
Useful references:
|
||||||
|
https://libvirt.org/formatdomain.html#virtio-related-options
|
||||||
|
https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html
|
||||||
|
https://specs.openstack.org/openstack/nova-specs/specs/2023.2/approved/virtio_packedring_configuration_support.html
|
||||||
|
|
@ -52,7 +52,7 @@ psutil>=3.2.2 # BSD
|
|||||||
oslo.versionedobjects>=1.35.0 # Apache-2.0
|
oslo.versionedobjects>=1.35.0 # Apache-2.0
|
||||||
os-brick>=5.2 # Apache-2.0
|
os-brick>=5.2 # Apache-2.0
|
||||||
os-resource-classes>=1.1.0 # Apache-2.0
|
os-resource-classes>=1.1.0 # Apache-2.0
|
||||||
os-traits>=2.10.0 # Apache-2.0
|
os-traits>=3.0.0 # Apache-2.0
|
||||||
os-vif>=3.1.0 # Apache-2.0
|
os-vif>=3.1.0 # Apache-2.0
|
||||||
castellan>=0.16.0 # Apache-2.0
|
castellan>=0.16.0 # Apache-2.0
|
||||||
microversion-parse>=0.2.1 # Apache-2.0
|
microversion-parse>=0.2.1 # Apache-2.0
|
||||||
|
Loading…
Reference in New Issue
Block a user