From 9611f0472280dfb19558812f4f74be6af55fd42f Mon Sep 17 00:00:00 2001 From: Hamdy Khader Date: Sun, 10 Feb 2019 16:31:23 +0200 Subject: [PATCH] Add create_port field in VIFPortProfileOpenVSwitch profile In case of Smart NIC, os-vif is used to plug the representor port to the integration bridge, so the Neutron agent that runs on the Smart NIC must behave like libvirt and do plug/unplug for the representor port. Change-Id: Ic2c3c88ad0c3865dae96c717b5d137f1ea18326f --- os_vif/objects/vif.py | 20 +++++++++++++++++--- os_vif/tests/unit/test_objects.py | 6 +++--- os_vif/tests/unit/test_vif.py | 11 +++++++++++ vif_plug_ovs/ovs.py | 7 +++++++ vif_plug_ovs/tests/unit/test_plugin.py | 25 +++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/os_vif/objects/vif.py b/os_vif/objects/vif.py index 26f435e8..ef84f560 100644 --- a/os_vif/objects/vif.py +++ b/os_vif/objects/vif.py @@ -226,7 +226,8 @@ class VIFPortProfileOpenVSwitch(VIFPortProfileBase): # Version 1.0: Initial release # Version 1.1: Added 'datapath_type' # Version 1.2: VIFPortProfileBase updated to 1.1 - VERSION = '1.2' + # Version 1.3: Added 'create_port' + VERSION = '1.3' fields = { 'interface_id': fields.UUIDField(), @@ -234,6 +235,9 @@ class VIFPortProfileOpenVSwitch(VIFPortProfileBase): # Datapath type of the bridge 'datapath_type': fields.StringField(nullable=True), + + # If set, the os-vif plugin should add the port to the bridge + 'create_port': fields.BooleanField(default=False), } def obj_make_compatible(self, primitive, target_version): @@ -245,6 +249,8 @@ class VIFPortProfileOpenVSwitch(VIFPortProfileBase): if target_version < (1, 2): super(VIFPortProfileOpenVSwitch, self).obj_make_compatible( primitive, "1.0") + if target_version < (1, 3) and 'create_port' in primitive: + del primitive['create_port'] @base.VersionedObjectRegistry.register @@ -253,7 +259,8 @@ class VIFPortProfileFPOpenVSwitch(VIFPortProfileOpenVSwitch): # Version 1.0: Initial release # Version 1.1: VIFPortProfileOpenVSwitch updated to 1.1 # Version 1.2: VIFPortProfileOpenVSwitch updated to 1.2 - VERSION = '1.2' + # Version 1.3: VIFPortProfileOpenVSwitch updated to 1.3 + VERSION = '1.3' fields = { # Name of the bridge (managed by fast path) to connect to @@ -271,6 +278,9 @@ class VIFPortProfileFPOpenVSwitch(VIFPortProfileOpenVSwitch): if target_version < (1, 2): super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible( primitive, "1.1") + if target_version < (1, 3): + super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible( + primitive, "1.2") @removals.removed_class("VIFPortProfileOVSRepresentor", @@ -284,7 +294,8 @@ class VIFPortProfileOVSRepresentor(VIFPortProfileOpenVSwitch): # Version 1.0: Initial release # Version 1.1: VIFPortProfileOpenVSwitch updated to 1.1 # Version 1.2: VIFPortProfileOpenVSwitch updated to 1.2 - VERSION = '1.2' + # Version 1.3: VIFPortProfileOpenVSwitch updated to 1.3 + VERSION = '1.3' fields = { # Name to set on the representor (if set) @@ -302,6 +313,9 @@ class VIFPortProfileOVSRepresentor(VIFPortProfileOpenVSwitch): if target_version < (1, 2): super(VIFPortProfileOVSRepresentor, self).obj_make_compatible( primitive, "1.1") + if target_version < (1, 3): + super(VIFPortProfileOVSRepresentor, self).obj_make_compatible( + primitive, "1.2") @base.VersionedObjectRegistry.register diff --git a/os_vif/tests/unit/test_objects.py b/os_vif/tests/unit/test_objects.py index b9248ebc..b6942543 100644 --- a/os_vif/tests/unit/test_objects.py +++ b/os_vif/tests/unit/test_objects.py @@ -40,12 +40,12 @@ object_data = { 'VIFPortProfile8021Qbg': '1.1-b3011621809dca9216b50579ce9d6b19', 'VIFPortProfile8021Qbh': '1.1-226b61b2e76ba452f7b31530cff80ac9', 'VIFPortProfileBase': '1.1-4982d1621df12ebd1f3b07948f3d0e5f', - 'VIFPortProfileOpenVSwitch': '1.2-25aec86b7ec9fcb3434f896f694818de', - 'VIFPortProfileFPOpenVSwitch': '1.2-4a4f230d89a5ea0e43011f678b626dd9', + 'VIFPortProfileOpenVSwitch': '1.3-1ad9a350a9cae19c977d21fcce7c8c7f', + 'VIFPortProfileFPOpenVSwitch': '1.3-06c425743430e7702ef112e09b987346', 'VIFPortProfileFPBridge': '1.1-49f1952bf50bab7a95112c908534751f', 'VIFPortProfileFPTap': '1.1-fd178229477604dfb65de5ce929488e5', 'VIFVHostUser': '1.1-1f95b43be1f884f090ca1f4d79adfd35', - 'VIFPortProfileOVSRepresentor': '1.2-d0609e93ea884ef7b4949177e9fcdc39', + 'VIFPortProfileOVSRepresentor': '1.3-f625e17143473b93d6c7f97ded9f785a', 'VIFNestedDPDK': '1.0-fdbaf6b20afd116529929b21aa7158dc', 'VIFPortProfileK8sDPDK': '1.1-e2a2abd112b14e0239e76b99d9b252ae', 'DatapathOffloadBase': '1.0-77509ea1ea0dd750d5864b9bd87d3f9d', diff --git a/os_vif/tests/unit/test_vif.py b/os_vif/tests/unit/test_vif.py index 88cf23cb..b88e7fb7 100644 --- a/os_vif/tests/unit/test_vif.py +++ b/os_vif/tests/unit/test_vif.py @@ -106,6 +106,17 @@ class TestVIFS(base.TestCase): self.assertEqual('netdev', data['datapath_type']) self.assertNotIn('datapath_offload', data) + def test_port_profile_ovs_backport_1_2(self): + obj = objects.vif.VIFPortProfileOpenVSwitch( + interface_id="07bd6cea-fb37-4594-b769-90fc51854ee9", + create_port=True) + primitive = obj.obj_to_primitive(target_version='1.2') + self.assertEqual('1.2', primitive['versioned_object.version']) + data = primitive['versioned_object.data'] + self.assertEqual('07bd6cea-fb37-4594-b769-90fc51854ee9', + data['interface_id']) + self.assertNotIn('create_port', data) + def test_vif_direct_plain(self): self._test_vif(objects.vif.VIFDirect, vif_name="vif123", diff --git a/vif_plug_ovs/ovs.py b/vif_plug_ovs/ovs.py index 83fefcdb..c605309c 100644 --- a/vif_plug_ovs/ovs.py +++ b/vif_plug_ovs/ovs.py @@ -247,6 +247,13 @@ class OvsPlugin(plugin.PluginBase): # this comment will be removed when we actully fix #1734320 in # all cases. + # NOTE(hamdyk): As a WA to the above note, one can use + # VIFPortProfileOpenVSwitch.create_port flag to explicitly + # plug the port to the switch. + if ("create_port" in vif.port_profile and + vif.port_profile.create_port): + self._create_vif_port(vif, vif.vif_name, instance_info) + def _plug_vf_passthrough(self, vif, instance_info): self.ovsdb.ensure_ovs_bridge( vif.network.bridge, constants.OVS_DATAPATH_SYSTEM) diff --git a/vif_plug_ovs/tests/unit/test_plugin.py b/vif_plug_ovs/tests/unit/test_plugin.py index 4b7377a0..2da53355 100644 --- a/vif_plug_ovs/tests/unit/test_plugin.py +++ b/vif_plug_ovs/tests/unit/test_plugin.py @@ -61,6 +61,10 @@ class PluginTest(testtools.TestCase): interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa', datapath_type='netdev') + self.profile_ovs_smart_nic = objects.vif.VIFPortProfileOpenVSwitch( + interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa', + create_port=True) + self.profile_ovs_no_datatype = objects.vif.VIFPortProfileOpenVSwitch( interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa', datapath_type='') @@ -80,6 +84,13 @@ class PluginTest(testtools.TestCase): vif_name='tap-xxx-yyy-zzz', port_profile=self.profile_ovs) + self.vif_ovs_smart_nic = objects.vif.VIFOpenVSwitch( + id='b679325f-ca89-4ee0-a8be-6db1409b69ea', + address='ca:fe:de:ad:be:ef', + network=self.network_ovs, + vif_name='rep0-0', + port_profile=self.profile_ovs_smart_nic) + self.vif_vhostuser = objects.vif.VIFVHostUser( id='b679325f-ca89-4ee0-a8be-6db1409b69ea', address='ca:fe:de:ad:be:ef', @@ -445,3 +456,17 @@ class PluginTest(testtools.TestCase): 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']) + + @mock.patch.object(ovsdb_lib.BaseOVS, 'ensure_ovs_bridge') + @mock.patch.object(ovs.OvsPlugin, "_create_vif_port") + def test_plug_vif_ovs_smart_nic(self, create_port, ensure_bridge): + plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME) + plugin.plug(self.vif_ovs_smart_nic, self.instance) + ensure_bridge.assert_called_once() + create_port.assert_called_once() + + @mock.patch.object(ovs.OvsPlugin, '_unplug_vif_generic') + def test_unplug_vif_ovs_smart_nic(self, delete_port): + plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME) + plugin.unplug(self.vif_ovs_smart_nic, self.instance) + delete_port.assert_called_once()