From 3b606b06e138787c1b1ffd1dd0fb43e971ee7e29 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Thu, 15 Jun 2017 16:00:33 +0100 Subject: [PATCH] Read datapath_type from VIF object When vif_plug_ovs.linux_net.ensure_ovs_bridge function is called, the datapath_type of the bridge should be read from the VIF object, instead of statically coercing a value. Closes-Bug: #1632372 Change-Id: Ia813c39e2917ff373f8e1f85c75fc22d109c94d3 --- os_vif/objects/vif.py | 37 +++++++++++++--- os_vif/tests/unit/test_vif.py | 58 ++++++++++++++++++++++++-- vif_plug_ovs/ovs.py | 18 +++++--- vif_plug_ovs/tests/unit/test_plugin.py | 42 +++++++++++++------ 4 files changed, 127 insertions(+), 28 deletions(-) diff --git a/os_vif/objects/vif.py b/os_vif/objects/vif.py index b0d9f803..086f4704 100644 --- a/os_vif/objects/vif.py +++ b/os_vif/objects/vif.py @@ -171,20 +171,32 @@ class VIFPortProfileBase(osv_base.VersionedObject, @base.VersionedObjectRegistry.register class VIFPortProfileOpenVSwitch(VIFPortProfileBase): # Port profile info for OpenVSwitch networks - - VERSION = '1.0' + # Version 1.0: Initial release + # Version 1.1: Added 'datapath_type' + VERSION = '1.1' fields = { 'interface_id': fields.UUIDField(), 'profile_id': fields.StringField(), + + # Datapath type of the bridge + 'datapath_type': fields.StringField(nullable=True), } + def obj_make_compatible(self, primitive, target_version): + super(VIFPortProfileOpenVSwitch, self).obj_make_compatible( + primitive, target_version) + target_version = versionutils.convert_version_to_tuple(target_version) + if target_version < (1, 1) and 'datapath_type' in primitive: + del primitive['datapath_type'] + @base.VersionedObjectRegistry.register class VIFPortProfileFPOpenVSwitch(VIFPortProfileOpenVSwitch): # Port profile info for OpenVSwitch networks using fastpath - - VERSION = '1.0' + # Version 1.0: Initial release + # Version 1.1: VIFPortProfileOpenVSwitch updated to 1.1 + VERSION = '1.1' fields = { # Name of the bridge (managed by fast path) to connect to @@ -194,12 +206,19 @@ class VIFPortProfileFPOpenVSwitch(VIFPortProfileOpenVSwitch): 'hybrid_plug': fields.BooleanField(default=False), } + def obj_make_compatible(self, primitive, target_version): + target_version = versionutils.convert_version_to_tuple(target_version) + if target_version < (1, 1): + super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible( + primitive, "1.0") + @base.VersionedObjectRegistry.register class VIFPortProfileOVSRepresentor(VIFPortProfileOpenVSwitch): # Port profile info for OpenVSwitch networks using a representor - - VERSION = '1.0' + # Version 1.0: Initial release + # Version 1.1: VIFPortProfileOpenVSwitch updated to 1.1 + VERSION = '1.1' fields = { # Name to set on the representor (if set) @@ -209,6 +228,12 @@ class VIFPortProfileOVSRepresentor(VIFPortProfileOpenVSwitch): 'representor_address': fields.PCIAddressField(nullable=True), } + def obj_make_compatible(self, primitive, target_version): + target_version = versionutils.convert_version_to_tuple(target_version) + if target_version < (1, 1): + super(VIFPortProfileOVSRepresentor, self).obj_make_compatible( + primitive, "1.0") + @base.VersionedObjectRegistry.register class VIFPortProfileFPBridge(VIFPortProfileBase): diff --git a/os_vif/tests/unit/test_vif.py b/os_vif/tests/unit/test_vif.py index 6f5e8c57..c40dc597 100644 --- a/os_vif/tests/unit/test_vif.py +++ b/os_vif/tests/unit/test_vif.py @@ -58,12 +58,26 @@ class TestVIFS(base.TestCase): def test_vif_bridge_ovs(self): prof = objects.vif.VIFPortProfileOpenVSwitch( interface_id="07bd6cea-fb37-4594-b769-90fc51854ee9", - profile_id="fishfood") + profile_id="fishfood", + datapath_type='netdev') self._test_vif(objects.vif.VIFOpenVSwitch, vif_name="vif123", bridge_name="br0", port_profile=prof) + def test_vif_bridge_ovs_backport_1_0(self): + obj = objects.vif.VIFPortProfileOpenVSwitch( + interface_id="07bd6cea-fb37-4594-b769-90fc51854ee9", + profile_id="fishfood", + datapath_type='netdev') + primitive = obj.obj_to_primitive(target_version='1.0') + self.assertEqual('1.0', primitive['versioned_object.version']) + data = primitive['versioned_object.data'] + self.assertEqual('07bd6cea-fb37-4594-b769-90fc51854ee9', + data['interface_id']) + self.assertEqual('fishfood', data['profile_id']) + self.assertNotIn('datapath_type', data) + def test_vif_direct_plain(self): self._test_vif(objects.vif.VIFDirect, vif_name="vif123", @@ -98,6 +112,7 @@ class TestVIFS(base.TestCase): prof = objects.vif.VIFPortProfileFPOpenVSwitch( interface_id="07bd6cea-fb37-4594-b769-90fc51854ee8", profile_id="fishfood", + datapath_type='netdev', bridge_name="br-int", hybrid_plug=False) self._test_vif(objects.vif.VIFVHostUser, @@ -106,10 +121,28 @@ class TestVIFS(base.TestCase): vif_name="tap123", port_profile=prof) + def test_vif_vhost_user_fp_ovs_backport_1_0(self): + obj = objects.vif.VIFPortProfileFPOpenVSwitch( + interface_id="07bd6cea-fb37-4594-b769-90fc51854ee9", + profile_id="fishfood", + datapath_type='netdev', + bridge_name="br-int", + hybrid_plug=False) + primitive = obj.obj_to_primitive(target_version='1.0') + self.assertEqual('1.0', primitive['versioned_object.version']) + data = primitive['versioned_object.data'] + self.assertEqual('07bd6cea-fb37-4594-b769-90fc51854ee9', + data['interface_id']) + self.assertEqual('fishfood', data['profile_id']) + self.assertEqual('br-int', data['bridge_name']) + self.assertEqual(False, data['hybrid_plug']) + self.assertNotIn('datapath_type', data) + def test_vif_vhost_user_ovs_representor(self): prof = objects.vif.VIFPortProfileOVSRepresentor( interface_id="07bd6cea-fb37-4594-b769-90fc51854ee8", profile_id="fishfood", + datapath_type='netdev', representor_name="tap123", representor_address="0002:24:12.3") self._test_vif(objects.vif.VIFVHostUser, @@ -118,6 +151,23 @@ class TestVIFS(base.TestCase): vif_name="tap123", port_profile=prof) + def test_vif_vhost_user_ovs_representor_backport_1_0(self): + obj = objects.vif.VIFPortProfileOVSRepresentor( + interface_id="07bd6cea-fb37-4594-b769-90fc51854ee9", + profile_id="fishfood", + datapath_type='netdev', + representor_name="tap123", + representor_address="0002:24:12.3") + primitive = obj.obj_to_primitive(target_version='1.0') + self.assertEqual('1.0', primitive['versioned_object.version']) + data = primitive['versioned_object.data'] + self.assertEqual('07bd6cea-fb37-4594-b769-90fc51854ee9', + data['interface_id']) + self.assertEqual('fishfood', data['profile_id']) + self.assertEqual('tap123', data['representor_name']) + self.assertEqual("0002:24:12.3", data['representor_address']) + self.assertNotIn('datapath_type', data) + def test_vif_vhost_user_fp_lb(self): prof = objects.vif.VIFPortProfileFPBridge(bridge_name="brq456") self._test_vif(objects.vif.VIFVHostUser, @@ -168,12 +218,12 @@ object_data = { 'VIFPortProfile8021Qbg': '1.0-167f305f6e982b9368cc38763815d429', 'VIFPortProfile8021Qbh': '1.0-4b945f07d2666ab00a48d1dc225669b1', 'VIFPortProfileBase': '1.0-77509ea1ea0dd750d5864b9bd87d3f9d', - 'VIFPortProfileOpenVSwitch': '1.0-533126c2a16b1a40ddf38c33e7b1f1c5', - 'VIFPortProfileFPOpenVSwitch': '1.0-9fc1799cb0adcd469481653b0420dc5e', + 'VIFPortProfileOpenVSwitch': '1.1-70d36e09c8d800345ce71177265212df', + 'VIFPortProfileFPOpenVSwitch': '1.1-74e77f46aa5806930df6f37a0b76ff8b', 'VIFPortProfileFPBridge': '1.0-d50872b3cddd245ffebef6053dfbe27a', 'VIFPortProfileFPTap': '1.0-11670d8dbabd772ff0da26961adadc5a', 'VIFVHostUser': '1.1-1f95b43be1f884f090ca1f4d79adfd35', - 'VIFPortProfileOVSRepresentor': '1.0-d1b67d954bcab8378c8064771d62ecd5', + 'VIFPortProfileOVSRepresentor': '1.1-30e555981003a109b133da5b43ded5df', } diff --git a/vif_plug_ovs/ovs.py b/vif_plug_ovs/ovs.py index 771c6553..48febd2f 100644 --- a/vif_plug_ovs/ovs.py +++ b/vif_plug_ovs/ovs.py @@ -106,9 +106,17 @@ class OvsPlugin(plugin.PluginBase): mtu = self._get_mtu(vif) linux_net.update_ovs_vif_port(vif_name, mtu) + @staticmethod + def _get_vif_datapath_type(vif, datapath=constants.OVS_DATAPATH_SYSTEM): + profile = vif.port_profile + if 'datapath_type' not in profile or not profile.datapath_type: + return datapath + return profile.datapath_type + def _plug_vhostuser(self, vif, instance_info): - linux_net.ensure_ovs_bridge(vif.network.bridge, - constants.OVS_DATAPATH_NETDEV) + linux_net.ensure_ovs_bridge( + vif.network.bridge, self._get_vif_datapath_type( + vif, datapath=constants.OVS_DATAPATH_NETDEV)) vif_name = OvsPlugin.gen_port_name( constants.OVS_VHOSTUSER_PREFIX, vif.id) args = {} @@ -141,7 +149,7 @@ class OvsPlugin(plugin.PluginBase): linux_net.create_veth_pair(v1_name, v2_name, mtu) linux_net.add_bridge_port(vif.bridge_name, v1_name) linux_net.ensure_ovs_bridge(vif.network.bridge, - constants.OVS_DATAPATH_SYSTEM) + self._get_vif_datapath_type(vif)) self._create_vif_port(vif, v2_name, instance_info) else: linux_net.update_veth_pair(v1_name, v2_name, mtu) @@ -152,7 +160,7 @@ class OvsPlugin(plugin.PluginBase): if not linux_net.device_exists(vif.id): linux_net.ensure_ovs_bridge(vif.network.bridge, - constants.OVS_DATAPATH_SYSTEM) + self._get_vif_datapath_type(vif)) self._create_vif_port(vif, vif.id, instance_info) def _plug_vf_passthrough(self, vif, instance_info): @@ -177,7 +185,7 @@ class OvsPlugin(plugin.PluginBase): if isinstance(vif, objects.vif.VIFOpenVSwitch): if sys.platform != constants.PLATFORM_WIN32: linux_net.ensure_ovs_bridge(vif.network.bridge, - constants.OVS_DATAPATH_SYSTEM) + self._get_vif_datapath_type(vif)) else: self._plug_vif_windows(vif, instance_info) elif isinstance(vif, objects.vif.VIFBridge): diff --git a/vif_plug_ovs/tests/unit/test_plugin.py b/vif_plug_ovs/tests/unit/test_plugin.py index b028d806..f48f46d4 100644 --- a/vif_plug_ovs/tests/unit/test_plugin.py +++ b/vif_plug_ovs/tests/unit/test_plugin.py @@ -56,7 +56,12 @@ class PluginTest(testtools.TestCase): mtu=1234) self.profile_ovs = objects.vif.VIFPortProfileOpenVSwitch( - interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa') + interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa', + datapath_type='netdev') + + self.profile_ovs_no_datatype = objects.vif.VIFPortProfileOpenVSwitch( + interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa', + datapath_type='') self.vif_ovs_hybrid = objects.vif.VIFBridge( id='b679325f-ca89-4ee0-a8be-6db1409b69ea', @@ -64,7 +69,7 @@ class PluginTest(testtools.TestCase): network=self.network_ovs, dev_name='tap-xxx-yyy-zzz', bridge_name="qbrvif-xxx-yyy", - port_profile=self.profile_ovs) + port_profile=self.profile_ovs_no_datatype) self.vif_ovs = objects.vif.VIFOpenVSwitch( id='b679325f-ca89-4ee0-a8be-6db1409b69ea', @@ -102,6 +107,16 @@ class PluginTest(testtools.TestCase): name='demo', uuid='f0000000-0000-0000-0000-000000000001') + def test__get_vif_datapath_type(self): + plugin = ovs.OvsPlugin.load('ovs') + dp_type = plugin._get_vif_datapath_type( + self.vif_ovs, datapath=constants.OVS_DATAPATH_SYSTEM) + self.assertEqual(self.profile_ovs.datapath_type, dp_type) + + dp_type = plugin._get_vif_datapath_type( + self.vif_ovs_hybrid, datapath=constants.OVS_DATAPATH_SYSTEM) + self.assertEqual(constants.OVS_DATAPATH_SYSTEM, dp_type) + @mock.patch.object(linux_net, 'create_ovs_vif_port') def test_create_vif_port(self, mock_create_ovs_vif_port): plugin = ovs.OvsPlugin.load('ovs') @@ -139,9 +154,9 @@ class PluginTest(testtools.TestCase): plugin = ovs.OvsPlugin.load("ovs") plugin._plug_bridge = plug_bridge_mock plugin.plug(self.vif_ovs, self.instance) - plug_bridge_mock.assert_not_called() - ensure_ovs_bridge.assert_called_once_with( - self.vif_ovs.network.bridge, constants.OVS_DATAPATH_SYSTEM) + dp_type = ovs.OvsPlugin._get_vif_datapath_type(self.vif_ovs) + ensure_ovs_bridge.assert_called_once_with(self.vif_ovs.network.bridge, + dp_type) @mock.patch.object(linux_net, 'set_interface_state') @mock.patch.object(linux_net, 'ensure_ovs_bridge') @@ -158,6 +173,7 @@ class PluginTest(testtools.TestCase): add_bridge_port, _create_vif_port, _update_vif_port, ensure_ovs_bridge, set_interface_state): + dp_type = ovs.OvsPlugin._get_vif_datapath_type(self.vif_ovs_hybrid) calls = { 'device_exists': [mock.call('qvob679325f-ca')], 'create_veth_pair': [mock.call('qvbb679325f-ca', @@ -176,8 +192,7 @@ class PluginTest(testtools.TestCase): '_create_vif_port': [mock.call(self.vif_ovs_hybrid, 'qvob679325f-ca', self.instance)], - 'ensure_ovs_bridge': [mock.call('br0', - constants.OVS_DATAPATH_SYSTEM)] + 'ensure_ovs_bridge': [mock.call('br0', dp_type)] } # plugging new devices should result in devices being created @@ -216,11 +231,11 @@ class PluginTest(testtools.TestCase): @mock.patch.object(ovs, 'sys') def _check_plug_ovs_windows(self, vif, mock_sys, device_exists, _create_vif_port, ensure_ovs_bridge): + dp_type = ovs.OvsPlugin._get_vif_datapath_type(vif) calls = { 'device_exists': [mock.call(vif.id)], '_create_vif_port': [mock.call(vif, vif.id, self.instance)], - 'ensure_ovs_bridge': [mock.call('br0', - constants.OVS_DATAPATH_SYSTEM)] + 'ensure_ovs_bridge': [mock.call('br0', dp_type)] } mock_sys.platform = constants.PLATFORM_WIN32 @@ -276,14 +291,14 @@ class PluginTest(testtools.TestCase): @mock.patch.object(linux_net, 'ensure_ovs_bridge') @mock.patch.object(ovs.OvsPlugin, '_create_vif_port') def test_plug_ovs_vhostuser(self, _create_vif_port, ensure_ovs_bridge): + dp_type = ovs.OvsPlugin._get_vif_datapath_type(self.vif_vhostuser) calls = { '_create_vif_port': [mock.call( self.vif_vhostuser, 'vhub679325f-ca', self.instance, interface_type='dpdkvhostuser')], - 'ensure_ovs_bridge': [mock.call('br0', - constants.OVS_DATAPATH_NETDEV)] + 'ensure_ovs_bridge': [mock.call('br0', dp_type)] } plugin = ovs.OvsPlugin.load("ovs") @@ -295,6 +310,8 @@ class PluginTest(testtools.TestCase): @mock.patch.object(linux_net, 'create_ovs_vif_port') def test_plug_ovs_vhostuser_client(self, create_ovs_vif_port, ensure_ovs_bridge): + dp_type = ovs.OvsPlugin._get_vif_datapath_type( + self.vif_vhostuser_client) calls = { 'create_ovs_vif_port': [ mock.call( @@ -305,8 +322,7 @@ class PluginTest(testtools.TestCase): 1500, interface_type='dpdkvhostuserclient', vhost_server_path='/var/run/openvswitch/vhub679325f-ca', timeout=120)], - 'ensure_ovs_bridge': [mock.call('br0', - constants.OVS_DATAPATH_NETDEV)] + 'ensure_ovs_bridge': [mock.call('br0', dp_type)] } plugin = ovs.OvsPlugin.load("ovs")