From f154ef9cc8f9a14273b7c48ac29cb828cd25109a Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 26 Apr 2017 14:00:53 +0000 Subject: [PATCH] Revert "hardware offload support for openvswitch" This reverts commit 157bf4c5cc18941a9a382be8310119d1b66105cb. The feature hasn't merged into upstream OVS yet. We should wait until it does so in the event that there are changes (or it fails to merge at all). Change-Id: I564cae602bd88d71ce0796202db764502b2108f1 --- doc/source/plugins/ovs.rst | 18 ---- os_vif/tests/test_os_vif.py | 3 +- vif_plug_ovs/exception.py | 9 -- vif_plug_ovs/linux_net.py | 94 +-------------------- vif_plug_ovs/ovs.py | 31 +------ vif_plug_ovs/tests/test_linux_net.py | 122 +-------------------------- vif_plug_ovs/tests/test_plugin.py | 92 +------------------- 7 files changed, 7 insertions(+), 362 deletions(-) diff --git a/doc/source/plugins/ovs.rst b/doc/source/plugins/ovs.rst index a39d9e93..dc360526 100644 --- a/doc/source/plugins/ovs.rst +++ b/doc/source/plugins/ovs.rst @@ -32,24 +32,6 @@ The Open vSwitch plugin provides support for the following VIF types: Refer to :ref:`vif-vhostuser` for more information. -`VIFHostDevice` - - Configuration where an SR-IOV PCI device virtual function (VF) is passed - through to a guest. The ``hw-tc-offload`` feature should be enabled on the - SR-IOV Physical Function (PF) using ``ethtool``: - - .. code-block:: shell - - ethtool -K hw-tc-offload - - This will create *VF representor* per VF. The VF representor plays the same - role as TAP devices in Para-Virtual (PV) setup. In this case the ``plug()`` - method connects the VF representor to the OpenVSwitch bridge. - - Refer to :ref:`vif-hostdevice` for more information. - - .. versionadded:: 1.5.0 - For information on the VIF type objects, refer to :doc:`../vif_types`. Note that only the above VIF types are supported by this plugin. diff --git a/os_vif/tests/test_os_vif.py b/os_vif/tests/test_os_vif.py index 90c9016e..0d3fb0a9 100644 --- a/os_vif/tests/test_os_vif.py +++ b/os_vif/tests/test_os_vif.py @@ -146,11 +146,10 @@ class TestOSVIF(base.TestCase): self.assertEqual(info.plugin_info[1].plugin_name, "ovs") vif_info = info.plugin_info[1].vif_info - self.assertEqual(len(vif_info), 4) + self.assertEqual(len(vif_info), 3) self.assertEqual(vif_info[0].vif_object_name, "VIFBridge") self.assertEqual(vif_info[1].vif_object_name, "VIFOpenVSwitch") self.assertEqual(vif_info[2].vif_object_name, "VIFVHostUser") - self.assertEqual(vif_info[3].vif_object_name, "VIFHostDevice") def test_host_info_filtered(self): os_vif.initialize() diff --git a/vif_plug_ovs/exception.py b/vif_plug_ovs/exception.py index 011ca46c..66dc4937 100644 --- a/vif_plug_ovs/exception.py +++ b/vif_plug_ovs/exception.py @@ -26,12 +26,3 @@ class MissingPortProfile(osv_exception.ExceptionBase): class WrongPortProfile(osv_exception.ExceptionBase): msg_fmt = _('Port profile %(profile)s is not a subclass ' 'of VIFPortProfileOpenVSwitch') - - -class RepresentorNotFound(osv_exception.ExceptionBase): - msg_fmt = _('Failed getting representor port for PF %(ifname)s with ' - '%(vf_num)s') - - -class PciDeviceNotFoundById(osv_exception.ExceptionBase): - msg_fmt = _("PCI device %(id)s not found") diff --git a/vif_plug_ovs/linux_net.py b/vif_plug_ovs/linux_net.py index e50e0a38..1459682b 100644 --- a/vif_plug_ovs/linux_net.py +++ b/vif_plug_ovs/linux_net.py @@ -19,10 +19,7 @@ """Implements vlans, bridges using linux utilities.""" -import errno -import glob import os -import re import sys from oslo_concurrency import processutils @@ -35,8 +32,6 @@ from vif_plug_ovs import privsep LOG = logging.getLogger(__name__) -VIRTFN_RE = re.compile("virtfn(\d+)") - def _ovs_vsctl(args, timeout=None): full_args = ['ovs-vsctl'] @@ -158,7 +153,7 @@ def ensure_bridge(bridge): process_input='1', check_exit_code=[0, 1]) # we bring up the bridge to allow it to switch packets - set_interface_state(bridge, 'up') + processutils.execute('ip', 'link', 'set', bridge, 'up') @privsep.vif_plug.entrypoint @@ -202,12 +197,6 @@ def _set_device_mtu(dev, mtu): check_exit_code=[0, 2, 254]) -@privsep.vif_plug.entrypoint -def set_interface_state(interface_name, port_state): - processutils.execute('ip', 'link', 'set', interface_name, port_state, - check_exit_code=[0, 2, 254]) - - @privsep.vif_plug.entrypoint def _set_mtu_request(dev, mtu, timeout=None): args = ['--', 'set', 'interface', dev, @@ -223,84 +212,3 @@ def _ovs_supports_mtu_requests(timeout=None): ' a column whose name matches "mtu_request"'): return False return True - - -def get_representor_port(pf_ifname, vf_num): - """Get the representor netdevice which is corresponding to the VF. - - This method gets PF interface name and number of VF. It iterates over all - the interfaces under the PF location and looks for interface that has the - VF number in the phys_port_name. That interface is the representor for - the requested VF. - """ - path = "/sys/class/net/%s/subsystem/" % pf_ifname - try: - for device in os.listdir(path): - if device == pf_ifname: - continue - file_name = os.path.join(path, device, 'phys_port_name') - if not os.path.isfile(file_name): - continue - try: - representor_num = open("%s/%s/phys_port_name" % - (path, device)).readline().rstrip() - if int(representor_num) == int(vf_num): - return device - except IOError as e: - # We want to ignore interfaces which we can't read their - # phys_port_name file. - with excutils.save_and_reraise_exception() as ctxt: - if e.errno == errno.EOPNOTSUPP: - ctxt.reraise = False - except ValueError: - # skip representor_num which we can't convert to integer - continue - - except IOError: - pass - raise exception.RepresentorNotFound(ifname=pf_ifname, vf_num=vf_num) - - -def _get_sysfs_netdev_path(pci_addr, pf_interface): - """Get the sysfs path based on the PCI address of the device. - - Assumes a networking device - will not check for the existence of the path. - """ - if pf_interface: - return "/sys/bus/pci/devices/%s/physfn/net" % (pci_addr) - return "/sys/bus/pci/devices/%s/net" % (pci_addr) - - -def get_ifname_by_pci_address(pci_addr, pf_interface=False): - """Get the interface name based on a VF's pci address - - The returned interface name is either the parent PF's or that of the VF - itself based on the argument of pf_interface. - """ - dev_path = _get_sysfs_netdev_path(pci_addr, pf_interface) - try: - dev_info = os.listdir(dev_path) - return dev_info.pop() - except Exception: - raise exception.PciDeviceNotFoundById(id=pci_addr) - - -def get_vf_num_by_pci_address(pci_addr): - """Get the VF number based on a VF's pci address - - A VF is associated with an VF number, which ip link command uses to - configure it. This number can be obtained from the PCI device filesystem. - """ - virtfns_path = "/sys/bus/pci/devices/%s/physfn/virtfn*" % (pci_addr) - vf_num = None - try: - for vf_path in glob.iglob(virtfns_path): - if re.search(pci_addr, os.readlink(vf_path)): - t = VIRTFN_RE.search(vf_path) - vf_num = t.group(1) - break - except Exception: - pass - if vf_num is None: - raise exception.PciDeviceNotFoundById(id=pci_addr) - return vf_num diff --git a/vif_plug_ovs/ovs.py b/vif_plug_ovs/ovs.py index 62e52611..aede60f9 100644 --- a/vif_plug_ovs/ovs.py +++ b/vif_plug_ovs/ovs.py @@ -79,11 +79,7 @@ class OvsPlugin(plugin.PluginBase): objects.host_info.HostVIFInfo( vif_object_name=objects.vif.VIFVHostUser.__name__, min_version="1.0", - max_version="1.0"), - objects.host_info.HostVIFInfo( - vif_object_name=objects.vif.VIFHostDevice.__name__, - min_version="1.0", - max_version="1.0"), + max_version="1.0") ]) def _get_mtu(self, vif): @@ -155,17 +151,6 @@ class OvsPlugin(plugin.PluginBase): constants.OVS_DATAPATH_SYSTEM) self._create_vif_port(vif, vif.id, instance_info) - def _plug_vf_passthrough(self, vif, instance_info): - linux_net.ensure_ovs_bridge( - vif.network.bridge, constants.OVS_DATAPATH_SYSTEM) - pci_slot = vif.dev_address - pf_ifname = linux_net.get_ifname_by_pci_address( - pci_slot, pf_interface=True) - vf_num = linux_net.get_vf_num_by_pci_address(pci_slot) - representor = linux_net.get_representor_port(pf_ifname, vf_num) - linux_net.set_interface_state(representor, 'up') - self._create_vif_port(vif, representor, instance_info) - def plug(self, vif, instance_info): if not hasattr(vif, "port_profile"): raise exception.MissingPortProfile() @@ -187,8 +172,6 @@ class OvsPlugin(plugin.PluginBase): self._plug_vif_windows(vif, instance_info) elif isinstance(vif, objects.vif.VIFVHostUser): self._plug_vhostuser(vif, instance_info) - elif isinstance(vif, objects.vif.VIFHostDevice): - self._plug_vf_passthrough(vif, instance_info) def _unplug_vhostuser(self, vif, instance_info): linux_net.delete_ovs_vif_port(vif.network.bridge, @@ -217,16 +200,6 @@ class OvsPlugin(plugin.PluginBase): linux_net.delete_ovs_vif_port(vif.network.bridge, vif.id, timeout=self.config.ovs_vsctl_timeout) - def _unplug_vf_passthrough(self, vif, instance_info): - """Remove port from OVS.""" - pci_slot = vif.dev_address - pf_ifname = linux_net.get_ifname_by_pci_address(pci_slot, - pf_interface=True) - vf_num = linux_net.get_vf_num_by_pci_address(pci_slot) - representor = linux_net.get_representor_port(pf_ifname, vf_num) - linux_net.delete_ovs_vif_port(vif.network.bridge, representor) - linux_net.set_interface_state(representor, 'down') - def unplug(self, vif, instance_info): if not hasattr(vif, "port_profile"): raise exception.MissingPortProfile() @@ -245,5 +218,3 @@ class OvsPlugin(plugin.PluginBase): self._unplug_vif_windows(vif, instance_info) elif isinstance(vif, objects.vif.VIFVHostUser): self._unplug_vhostuser(vif, instance_info) - elif isinstance(vif, objects.vif.VIFHostDevice): - self._unplug_vf_passthrough(vif, instance_info) diff --git a/vif_plug_ovs/tests/test_linux_net.py b/vif_plug_ovs/tests/test_linux_net.py index a347bb50..9be794a4 100644 --- a/vif_plug_ovs/tests/test_linux_net.py +++ b/vif_plug_ovs/tests/test_linux_net.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -import glob import mock import os.path import testtools @@ -18,7 +17,6 @@ import testtools from oslo_concurrency import processutils from vif_plug_ovs import constants -from vif_plug_ovs import exception from vif_plug_ovs import linux_net from vif_plug_ovs import privsep @@ -36,8 +34,7 @@ class LinuxNetTest(testtools.TestCase): linux_net.ensure_bridge("br0") self.assertEqual(mock_execute.mock_calls, [ - mock.call('ip', 'link', 'set', 'br0', 'up', - check_exit_code=[0, 2, 254]), + mock.call('ip', 'link', 'set', 'br0', 'up'), ]) self.assertEqual(mock_dev_exists.mock_calls, [ mock.call("br0"), @@ -56,8 +53,7 @@ class LinuxNetTest(testtools.TestCase): mock.call('brctl', 'stp', 'br0', "off"), mock.call('tee', '/sys/class/net/br0/bridge/multicast_snooping', check_exit_code=[0, 1], process_input='0'), - mock.call('ip', 'link', 'set', 'br0', 'up', - check_exit_code=[0, 2, 254]), + mock.call('ip', 'link', 'set', 'br0', 'up'), ]) self.assertEqual(mock_dev_exists.mock_calls, [ mock.call("br0") @@ -78,8 +74,7 @@ class LinuxNetTest(testtools.TestCase): check_exit_code=[0, 1], process_input='0'), mock.call('tee', '/proc/sys/net/ipv6/conf/br0/disable_ipv6', check_exit_code=[0, 1], process_input='1'), - mock.call('ip', 'link', 'set', 'br0', 'up', - check_exit_code=[0, 2, 254]), + mock.call('ip', 'link', 'set', 'br0', 'up'), ]) self.assertEqual(mock_dev_exists.mock_calls, [ mock.call("br0") @@ -301,114 +296,3 @@ class LinuxNetTest(testtools.TestCase): result = linux_net._ovs_supports_mtu_requests(timeout=timeout) mock_vsctl.assert_called_with(args, timeout=timeout) self.assertTrue(result) - - @mock.patch('six.moves.builtins.open') - @mock.patch.object(os.path, 'isfile') - @mock.patch.object(os, 'listdir') - def test_get_representor_port(self, mock_listdir, mock_isfile, mock_open): - mock_listdir.return_value = [ - 'pf_ifname', 'vf1_ifname', 'vf2_ifname', 'rep_vf_1', 'rep_vf_2' - ] - mock_isfile.side_effect = [True, True, True, True, True] - mock_open.return_value.__enter__ = lambda s: s - mock_open.return_value.__exit__ = mock.Mock() - readline_mock = mock_open.return_value.readline - readline_mock.side_effect = ['', '', '1', '2'] - ifname = linux_net.get_representor_port('pf_ifname', '2') - self.assertEqual('rep_vf_2', ifname) - - @mock.patch('six.moves.builtins.open') - @mock.patch.object(os.path, 'isfile') - @mock.patch.object(os, 'listdir') - def test_get_representor_port_not_found( - self, mock_listdir, mock_isfile, mock_open): - mock_listdir.return_value = [ - 'pf_ifname', 'vf1_ifname', 'vf2_ifname', 'rep_vf_1', 'rep_vf_2' - ] - mock_isfile.side_effect = [True, True, True, True, True] - mock_open.return_value.__enter__ = lambda s: s - mock_open.return_value.__exit__ = mock.Mock() - readline_mock = mock_open.return_value.readline - readline_mock.side_effect = ['', '', '1', '2'] - self.assertRaises( - exception.RepresentorNotFound, - linux_net.get_representor_port, - 'pf_ifname', '3'), - - @mock.patch('six.moves.builtins.open') - @mock.patch.object(os.path, 'isfile') - @mock.patch.object(os, 'listdir') - def test_get_representor_port_exception( - self, mock_listdir, mock_isfile, mock_open): - mock_listdir.return_value = [ - 'pf_ifname', 'vf1_ifname', 'vf2_ifname', 'rep_vf_1', 'rep_vf_2' - ] - mock_isfile.side_effect = [True, True, True, True, True] - mock_open.return_value.__enter__ = lambda s: s - mock_open.return_value.__exit__ = mock.Mock() - readline_mock = mock_open.return_value.readline - readline_mock.side_effect = ['', IOError(), '1', '2'] - self.assertRaises( - exception.RepresentorNotFound, - linux_net.get_representor_port, - 'pf_ifname', '3'), - - @mock.patch.object(os, 'listdir') - def test_physical_function_inferface_name(self, mock_listdir): - mock_listdir.return_value = ['foo', 'bar'] - ifname = linux_net.get_ifname_by_pci_address( - '0000:00:00.1', pf_interface=True) - self.assertEqual(ifname, 'bar') - - @mock.patch.object(os, 'listdir') - def test_virtual_function_inferface_name(self, mock_listdir): - mock_listdir.return_value = ['foo', 'bar'] - ifname = linux_net.get_ifname_by_pci_address( - '0000:00:00.1', pf_interface=False) - self.assertEqual(ifname, 'bar') - - @mock.patch.object(os, 'listdir') - def test_get_ifname_by_pci_address_exception(self, mock_listdir): - mock_listdir.side_effect = OSError('No such file or directory') - self.assertRaises( - exception.PciDeviceNotFoundById, - linux_net.get_ifname_by_pci_address, - '0000:00:00.1' - ) - - @mock.patch.object(os, 'readlink') - @mock.patch.object(glob, 'iglob') - def test_vf_number_found(self, mock_iglob, mock_readlink): - mock_iglob.return_value = [ - '/sys/bus/pci/devices/0000:00:00.1/physfn/virtfn3', - ] - mock_readlink.return_value = '../../0000:00:00.1' - vf_num = linux_net.get_vf_num_by_pci_address('0000:00:00.1') - self.assertEqual(vf_num, '3') - - @mock.patch.object(os, 'readlink') - @mock.patch.object(glob, 'iglob') - def test_vf_number_not_found(self, mock_iglob, mock_readlink): - mock_iglob.return_value = [ - '/sys/bus/pci/devices/0000:00:00.1/physfn/virtfn3', - ] - mock_readlink.return_value = '../../0000:00:00.2' - self.assertRaises( - exception.PciDeviceNotFoundById, - linux_net.get_vf_num_by_pci_address, - '0000:00:00.1' - ) - - @mock.patch.object(os, 'readlink') - @mock.patch.object(glob, 'iglob') - def test_get_vf_num_by_pci_address_exception( - self, mock_iglob, mock_readlink): - mock_iglob.return_value = [ - '/sys/bus/pci/devices/0000:00:00.1/physfn/virtfn3', - ] - mock_readlink.side_effect = OSError('No such file or directory') - self.assertRaises( - exception.PciDeviceNotFoundById, - linux_net.get_vf_num_by_pci_address, - '0000:00:00.1' - ) diff --git a/vif_plug_ovs/tests/test_plugin.py b/vif_plug_ovs/tests/test_plugin.py index 4f5baf1e..590b8319 100644 --- a/vif_plug_ovs/tests/test_plugin.py +++ b/vif_plug_ovs/tests/test_plugin.py @@ -14,7 +14,6 @@ import mock import testtools from os_vif import objects -from os_vif.objects import fields from vif_plug_ovs import constants from vif_plug_ovs import linux_net @@ -89,15 +88,6 @@ class PluginTest(testtools.TestCase): mode='server', # qemu server mode <=> ovs client mode port_profile=self.profile_ovs) - self.vif_ovs_vf_passthrough = objects.vif.VIFHostDevice( - id='b679325f-ca89-4ee0-a8be-6db1409b69ea', - address='ca:fe:de:ad:be:ef', - network=self.network_ovs, - dev_type=fields.VIFVIFHostDeviceDevType.ETHERNET, - dev_address='0002:24:12.3', - bridge_name='br-int', - port_profile=self.profile_ovs) - self.instance = objects.instance_info.InstanceInfo( name='demo', uuid='f0000000-0000-0000-0000-000000000001') @@ -143,7 +133,6 @@ class PluginTest(testtools.TestCase): ensure_ovs_bridge.assert_called_once_with( self.vif_ovs.network.bridge, constants.OVS_DATAPATH_SYSTEM) - @mock.patch.object(linux_net, 'set_interface_state') @mock.patch.object(linux_net, 'ensure_ovs_bridge') @mock.patch.object(ovs.OvsPlugin, '_update_vif_port') @mock.patch.object(ovs.OvsPlugin, '_create_vif_port') @@ -156,8 +145,7 @@ class PluginTest(testtools.TestCase): def test_plug_ovs_bridge(self, mock_sys, ensure_bridge, device_exists, create_veth_pair, update_veth_pair, add_bridge_port, _create_vif_port, - _update_vif_port, ensure_ovs_bridge, - set_interface_state): + _update_vif_port, ensure_ovs_bridge): calls = { 'device_exists': [mock.call('qvob679325f-ca')], 'create_veth_pair': [mock.call('qvbb679325f-ca', @@ -167,8 +155,6 @@ class PluginTest(testtools.TestCase): 'qvob679325f-ca', 1500)], 'ensure_bridge': [mock.call('qbrvif-xxx-yyy')], - 'set_interface_state': [mock.call('qbrvif-xxx-yyy', - 'up')], 'add_bridge_port': [mock.call('qbrvif-xxx-yyy', 'qvbb679325f-ca')], '_update_vif_port': [mock.call(self.vif_ovs_hybrid, @@ -323,79 +309,3 @@ class PluginTest(testtools.TestCase): plugin = ovs.OvsPlugin.load("ovs") plugin.unplug(self.vif_vhostuser, self.instance) delete_ovs_vif_port.assert_has_calls(calls['delete_ovs_vif_port']) - - @mock.patch.object(linux_net, 'ensure_ovs_bridge') - @mock.patch.object(linux_net, 'get_ifname_by_pci_address') - @mock.patch.object(linux_net, 'get_vf_num_by_pci_address') - @mock.patch.object(linux_net, 'get_representor_port') - @mock.patch.object(linux_net, 'set_interface_state') - @mock.patch.object(ovs.OvsPlugin, '_create_vif_port') - def test_plug_ovs_vf_passthrough(self, _create_vif_port, - set_interface_state, - get_representor_port, - get_vf_num_by_pci_address, - get_ifname_by_pci_address, - ensure_ovs_bridge): - - get_ifname_by_pci_address.return_value = 'eth0' - get_vf_num_by_pci_address.return_value = '2' - get_representor_port.return_value = 'eth0_2' - calls = { - - 'ensure_ovs_bridge': [mock.call('br0', - constants.OVS_DATAPATH_SYSTEM)], - 'get_ifname_by_pci_address': [mock.call('0002:24:12.3', - pf_interface=True)], - 'get_vf_num_by_pci_address': [mock.call('0002:24:12.3')], - 'get_representor_port': [mock.call('eth0', '2')], - 'set_interface_state': [mock.call('eth0_2', 'up')], - '_create_vif_port': [mock.call( - self.vif_ovs_vf_passthrough, 'eth0_2', - self.instance)] - } - - plugin = ovs.OvsPlugin.load("ovs") - plugin.plug(self.vif_ovs_vf_passthrough, self.instance) - ensure_ovs_bridge.assert_has_calls(calls['ensure_ovs_bridge']) - get_ifname_by_pci_address.assert_has_calls( - calls['get_ifname_by_pci_address']) - get_vf_num_by_pci_address.assert_has_calls( - calls['get_vf_num_by_pci_address']) - get_representor_port.assert_has_calls( - calls['get_representor_port']) - set_interface_state.assert_has_calls(calls['set_interface_state']) - _create_vif_port.assert_has_calls(calls['_create_vif_port']) - - @mock.patch.object(linux_net, 'get_ifname_by_pci_address') - @mock.patch.object(linux_net, 'get_vf_num_by_pci_address') - @mock.patch.object(linux_net, 'get_representor_port') - @mock.patch.object(linux_net, 'set_interface_state') - @mock.patch.object(linux_net, 'delete_ovs_vif_port') - def test_unplug_ovs_vf_passthrough(self, delete_ovs_vif_port, - set_interface_state, - get_representor_port, - get_vf_num_by_pci_address, - get_ifname_by_pci_address): - calls = { - - 'get_ifname_by_pci_address': [mock.call('0002:24:12.3', - pf_interface=True)], - 'get_vf_num_by_pci_address': [mock.call('0002:24:12.3')], - 'get_representor_port': [mock.call('eth0', '2')], - 'set_interface_state': [mock.call('eth0_2', 'down')], - 'delete_ovs_vif_port': [mock.call('br0', 'eth0_2')] - } - - get_ifname_by_pci_address.return_value = 'eth0' - get_vf_num_by_pci_address.return_value = '2' - get_representor_port.return_value = 'eth0_2' - plugin = ovs.OvsPlugin.load("ovs") - plugin.unplug(self.vif_ovs_vf_passthrough, self.instance) - get_ifname_by_pci_address.assert_has_calls( - calls['get_ifname_by_pci_address']) - get_vf_num_by_pci_address.assert_has_calls( - calls['get_vf_num_by_pci_address']) - get_representor_port.assert_has_calls( - calls['get_representor_port']) - delete_ovs_vif_port.assert_has_calls(calls['delete_ovs_vif_port']) - set_interface_state.assert_has_calls(calls['set_interface_state'])