libvirt: Add guest generation for vDPA

Add the ability to generate the libvirt interface XML for a neutron port
with a vnic_type of vdpa.

Blueprint: libvirt-vdpa-support
Change-Id: I2c7b183fcb01f3cb67cb1c8b8bea7aaf5ce424f3
This commit is contained in:
Stephen Finucane 2021-03-10 18:32:38 +00:00 committed by Sean Mooney
parent 9a673a8faa
commit e9c80da2db
7 changed files with 99 additions and 3 deletions

View File

@ -332,7 +332,7 @@ def _nova_to_osvif_vif_ovs(vif):
interface_id=vif.get('ovs_interfaceid') or vif['id'],
datapath_type=vif['details'].get(
model.VIF_DETAILS_OVS_DATAPATH_TYPE))
if vnic_type == model.VNIC_TYPE_DIRECT:
if vnic_type in (model.VNIC_TYPE_DIRECT, model.VNIC_TYPE_VDPA):
obj = _get_vnic_direct_vif_instance(
vif,
port_profile=_get_ovs_representor_port_profile(vif),

View File

@ -692,6 +692,46 @@ class OSVIFUtilTestCase(test.NoDBTestCase):
self.assertObjEqual(expect, actual)
def test_nova_to_osvif_ovs_with_vnic_vdpa(self):
vif = model.VIF(
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
type=model.VIF_TYPE_OVS,
address="22:52:25:62:e2:aa",
vnic_type=model.VNIC_TYPE_VDPA,
network=model.Network(
id="b82c1929-051e-481d-8110-4669916c7915",
label="Demo Net",
subnets=[]),
profile={'pci_slot': '0000:0a:00.1'}
)
actual = os_vif_util.nova_to_osvif_vif(vif)
expect = osv_objects.vif.VIFHostDevice(
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
active=False,
address="22:52:25:62:e2:aa",
dev_address='0000:0a:00.1',
dev_type=os_vif_fields.VIFHostDeviceDevType.ETHERNET,
plugin="ovs",
port_profile=osv_objects.vif.VIFPortProfileOVSRepresentor(
interface_id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
representor_name="nicdc065497-3c",
representor_address="0000:0a:00.1",
datapath_offload=osv_objects.vif.DatapathOffloadRepresentor(
representor_name="nicdc065497-3c",
representor_address="0000:0a:00.1")),
has_traffic_filtering=False,
preserve_on_delete=False,
network=osv_objects.network.Network(
id="b82c1929-051e-481d-8110-4669916c7915",
bridge_interface=None,
label="Demo Net",
subnets=osv_objects.subnet.SubnetList(
objects=[])))
self.assertObjEqual(expect, actual)
def test_nova_to_osvif_vhostuser_ovs(self):
vif = model.VIF(
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",

View File

@ -174,6 +174,25 @@ class DesignerTestCase(test.NoDBTestCase):
self.assertIsNone(conf.vhost_rx_queue_size)
self.assertIsNone(conf.vhost_tx_queue_size)
def test_set_vif_host_backend_vdpa_config(self):
conf = config.LibvirtConfigGuestInterface()
designer.set_vif_host_backend_vdpa_config(
conf, '/dev/vdpa_vdpa0')
self.assertEqual('vdpa', conf.net_type)
self.assertEqual('/dev/vdpa_vdpa0', conf.source_dev)
self.assertIsNone(conf.vhost_rx_queue_size)
self.assertIsNone(conf.vhost_tx_queue_size)
def test_set_vif_host_backend_vdpa_config_queue_size(self):
conf = config.LibvirtConfigGuestInterface()
designer.set_vif_host_backend_vdpa_config(
conf, '/dev/vdpa_vdpa0', rx_queue_size=512,
tx_queue_size=1024)
self.assertEqual('vdpa', conf.net_type)
self.assertEqual('/dev/vdpa_vdpa0', conf.source_dev)
self.assertEqual(512, conf.vhost_rx_queue_size)
self.assertEqual(1024, conf.vhost_tx_queue_size)
def test_set_vif_host_backend_vhostuser_config_queue_size(self):
conf = config.LibvirtConfigGuestInterface()
designer.set_vif_host_backend_vhostuser_config(conf, 'fake-mode',

View File

@ -1814,6 +1814,8 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
elif self.net_type == "direct":
dev.append(etree.Element("source", dev=self.source_dev,
mode=self.source_mode))
elif self.net_type == "vdpa":
dev.append(etree.Element("source", dev=self.source_dev))
elif self.net_type == "hostdev":
source_elem = etree.Element("source")
domain, bus, slot, func = \

View File

@ -151,6 +151,22 @@ def set_vif_host_backend_vhostuser_config(conf, mode, path, rx_queue_size,
conf.target_dev = tapname
def set_vif_host_backend_vdpa_config(
conf, dev_path, rx_queue_size=None, tx_queue_size=None,
):
"""Populate a LibvirtConfigGuestInterface instance
with host backend details for a vdpa device.
NOTE: @rx_queue_size and @tx_queue_size can be None
"""
conf.net_type = "vdpa"
conf.source_dev = dev_path
if rx_queue_size:
conf.vhost_rx_queue_size = rx_queue_size
if tx_queue_size:
conf.vhost_tx_queue_size = tx_queue_size
def set_vif_mtu_config(conf, mtu):
"""Populate a LibvirtConfigGuestInterface instance
with network mtu.

View File

@ -442,7 +442,7 @@ class LibvirtDriver(driver.ComputeDriver):
conn_event_handler=self._handle_conn_event)
self._supported_perf_events = []
self.vif_driver = libvirt_vif.LibvirtGenericVIFDriver()
self.vif_driver = libvirt_vif.LibvirtGenericVIFDriver(self._host)
# NOTE(lyarwood): Volume drivers are loaded on-demand
self.volume_drivers: ty.Dict[str, volume.LibvirtBaseVolumeDriver] = {}

View File

@ -19,6 +19,7 @@
"""VIF drivers for libvirt."""
import os
import typing as ty
import os_vif
from os_vif import exception as osv_exception
@ -40,6 +41,7 @@ from nova import profiler
from nova import utils
from nova.virt.libvirt import config as vconfig
from nova.virt.libvirt import designer
from nova.virt.libvirt import host as libvirt_host
from nova.virt import osinfo
@ -148,6 +150,10 @@ def ensure_vlan(vlan_num, bridge_interface, mac_address=None, mtu=None,
class LibvirtGenericVIFDriver(object):
"""Generic VIF driver for libvirt networking."""
def __init__(self, host: libvirt_host.Host = None):
super().__init__()
self.host = host
def get_vif_devname(self, vif):
if 'devname' in vif:
return vif['devname']
@ -490,6 +496,13 @@ class LibvirtGenericVIFDriver(object):
raise exception.InternalError(
_('Unsupported VIF port profile type %s') % profile_name)
def _get_vdpa_dev_path(self, pci_address: ty.Text) -> ty.Text:
if self.host is not None:
return self.host.get_vdpa_device_path(pci_address)
# TODO(sean-k-mooney) this should never be raised remove when host
# is not optional in __init__.
raise TypeError("self.host must set to use this function.")
def _get_config_os_vif(self, instance, vif, image_meta, inst_type,
virt_type, vnic_type):
"""Get the domain config for a VIF
@ -518,7 +531,13 @@ class LibvirtGenericVIFDriver(object):
elif isinstance(vif, osv_vifs.VIFVHostUser):
self._set_config_VIFVHostUser(instance, vif, conf)
elif isinstance(vif, osv_vifs.VIFHostDevice):
self._set_config_VIFHostDevice(instance, vif, conf)
if vnic_type != network_model.VNIC_TYPE_VDPA:
self._set_config_VIFHostDevice(instance, vif, conf)
else:
dev_path = self._get_vdpa_dev_path(vif.dev_address)
designer.set_vif_host_backend_vdpa_config(
conf, dev_path, CONF.libvirt.rx_queue_size,
CONF.libvirt.tx_queue_size)
else:
raise exception.InternalError(
_("Unsupported VIF type %s") % vif.obj_name())