From 56c118a638609c57aae40df2f3b13f7feacb3c28 Mon Sep 17 00:00:00 2001 From: zhangxiaohan Date: Tue, 18 Sep 2018 17:05:59 +0800 Subject: [PATCH] Qos rule not update after vm bound qos 1. What is the problem? Qos rule cannot be updated after virtual machine creation and qos policy binding. 2. What is the solution to the problem? In central_plugin.py, add maintenance to the neutron0 database table ml2_port_bindings to provide add and delete record. Change-Id: I23462862bbdb33e96a58b67ed4cd6f3abf95076f Signed-off-by: zhang xiaohan Co-Authored-By: tangzhuo --- tricircle/network/central_plugin.py | 42 +++++++++++++- tricircle/network/local_plugin.py | 7 ++- .../tests/unit/network/test_local_plugin.py | 55 ++++++++++++++++--- 3 files changed, 92 insertions(+), 12 deletions(-) diff --git a/tricircle/network/central_plugin.py b/tricircle/network/central_plugin.py index ede1ee19..8f059a8b 100644 --- a/tricircle/network/central_plugin.py +++ b/tricircle/network/central_plugin.py @@ -43,6 +43,7 @@ from neutron.db import l3_hamode_db # noqa from neutron.db import models_v2 from neutron.db import portbindings_db from neutron.extensions import providernet as provider +from neutron.objects import ports as q_ports from neutron.objects.qos import policy as policy_object import neutron.objects.router as router_object from neutron.plugins.ml2 import managers as n_managers @@ -50,6 +51,7 @@ from neutron_lib.api.definitions import availability_zone as az_def from neutron_lib.api.definitions import external_net from neutron_lib.api.definitions import l3 as l3_apidef from neutron_lib.api.definitions import portbindings +from neutron_lib.api.definitions import portbindings_extended as pb_ext from neutron_lib.api.definitions import provider_net from neutron_lib.api import validators from neutron_lib.api.validators import availability_zone as az_validator @@ -558,12 +560,16 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2, # do not reserve snat port for bridge and external subnet snat_port_id = self.helper.prepare_top_snat_port( t_ctx, context, res['tenant_id'], network['id'], res['id']) + self._create_port_binding(context, snat_port_id) if res['enable_dhcp']: - self.helper.prepare_top_dhcp_port( + dhcp_port_id = self.helper.prepare_top_dhcp_port( t_ctx, context, res['tenant_id'], network['id'], res['id']) + self._create_port_binding(context, dhcp_port_id) except Exception: if snat_port_id: super(TricirclePlugin, self).delete_port(context, snat_port_id) + q_ports.PortBinding.delete_objects(context, + port_id=snat_port_id) self.delete_subnet(context, res['id']) raise return res @@ -573,6 +579,7 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2, q_ctx, {'name': [port_name]}) if ports: super(TricirclePlugin, self).delete_port(q_ctx, ports[0]['id']) + q_ports.PortBinding.delete_objects(q_ctx, port_id=ports[0]['id']) db_api.delete_pre_created_resource_mapping(t_ctx, port_name) def delete_subnet(self, context, subnet_id): @@ -642,6 +649,18 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2, t_constants.POD_NOT_SPECIFIED) return result + def _create_port_binding(self, context, port_id): + port_binding = q_ports.PortBinding(context) + port_binding.unique_keys.append(['port_id']) + port_binding.port_id = port_id + port_binding.host = '' + port_binding.profile = {} + port_binding.vif_type = portbindings.VIF_TYPE_UNBOUND + port_binding.vif_details = {} + port_binding.vnic_type = portbindings.VNIC_NORMAL + port_binding.status = 'ACTIVE' + port_binding.create() + def create_port(self, context, port): port_body = port['port'] if port_body['device_id'] == t_constants.interface_port_device_id: @@ -655,6 +674,7 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2, t_ctx, context, port_body['tenant_id'], pod, {'id': port_body['name']}, t_constants.RT_PORT, gateway_port_body) + self._create_port_binding(context, t_gateway_id) return super(TricirclePlugin, self).get_port(context, t_gateway_id) db_port = super(TricirclePlugin, self).create_port_db(context, port) self._ensure_default_security_group_on_port(context, port) @@ -662,6 +682,7 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2, result = self._make_port_dict(db_port) self.extension_manager.process_create_port(context, port_body, result) self._process_port_create_security_group(context, result, sgids) + self._create_port_binding(context, db_port.id) return result def _check_mac_update_allowed(self, orig_port, port): @@ -795,10 +816,28 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2, 'name': bottom_port['name'] }}) + def _process_port_binding(self, context, port_id, port): + profile = port['port'].get('binding:profile') + if profile is not None and \ + set([portbindings.VIF_TYPE, portbindings.HOST_ID, + portbindings.VIF_DETAILS, portbindings.VNIC_TYPE] + ).issubset(profile.keys()): + q_ports.PortBinding.update_object( + context, + { + pb_ext.VIF_TYPE: profile[portbindings.VIF_TYPE], + pb_ext.HOST: profile[portbindings.HOST_ID], + pb_ext.VIF_DETAILS: profile[portbindings.VIF_DETAILS], + pb_ext.VNIC_TYPE: profile[portbindings.VNIC_TYPE] + }, + port_id=port_id + ) + def update_port(self, context, port_id, port): t_ctx = t_context.get_context_from_neutron_context(context) top_port = super(TricirclePlugin, self).get_port(context, port_id) updated_port = None + self._process_port_binding(context, port_id, port) # be careful that l3_db will call update_port to update device_id of # router interface, we cannot directly update bottom port in this case, # otherwise we will fail when attaching bottom port to bottom router @@ -993,6 +1032,7 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2, 'comparator': 'eq', 'value': port_id}]) super(TricirclePlugin, self).delete_port(context, port_id) + q_ports.PortBinding.delete_objects(context, port_id=port_id) def _get_port_qos_info(self, context, port_id): policy = policy_object.QosPolicy.get_port_policy(context, port_id) diff --git a/tricircle/network/local_plugin.py b/tricircle/network/local_plugin.py index 381fc9ea..a162bac3 100644 --- a/tricircle/network/local_plugin.py +++ b/tricircle/network/local_plugin.py @@ -738,8 +738,11 @@ class TricirclePlugin(plugin.Ml2Plugin): region_name = self._get_neutron_region() update_dict = {portbindings.PROFILE: { t_constants.PROFILE_REGION: region_name, - t_constants.PROFILE_DEVICE: b_port['device_owner'] - }} + t_constants.PROFILE_DEVICE: b_port['device_owner'], + portbindings.VIF_DETAILS: b_port[portbindings.VIF_DETAILS], + portbindings.VNIC_TYPE: b_port[portbindings.VNIC_TYPE], + portbindings.VIF_TYPE: b_port[portbindings.VIF_TYPE], + portbindings.HOST_ID: b_port[portbindings.HOST_ID]}} if b_port.get(t_constants.PROFILE_STATUS): update_dict[portbindings.PROFILE].update({ t_constants.PROFILE_STATUS: b_port['status'] diff --git a/tricircle/tests/unit/network/test_local_plugin.py b/tricircle/tests/unit/network/test_local_plugin.py index 3695c8b7..e6daeabc 100644 --- a/tricircle/tests/unit/network/test_local_plugin.py +++ b/tricircle/tests/unit/network/test_local_plugin.py @@ -646,7 +646,11 @@ class PluginTest(unittest.TestCase): fake_port = { 'id': port_id, 'network_id': b_net['id'], - 'binding:vif_type': 'fake_vif_type'} + 'binding:vif_type': 'fake_vif_type', + 'binding:host_id': host_id, + portbindings.VIF_DETAILS: {}, + portbindings.VNIC_TYPE: 'normal' + } fake_agent = { 'agent_type': 'Open vSwitch agent', 'host': host_id, @@ -662,7 +666,11 @@ class PluginTest(unittest.TestCase): mock_update.assert_called_with( self.context, 'port', port_id, {'port': {'binding:profile': {'region': 'Pod1', - 'device': 'compute:None'}}}) + 'device': 'compute:None', + 'binding:vif_type': 'fake_vif_type', + 'binding:host_id': host_id, + portbindings.VIF_DETAILS: {}, + portbindings.VNIC_TYPE: 'normal'}}}) # update network type from vlan to vxlan update_resource('network', False, b_net['id'], @@ -673,7 +681,11 @@ class PluginTest(unittest.TestCase): mock_update.assert_called_with( self.context, 'port', port_id, {'port': {'binding:profile': {'region': 'Pod1', - 'device': 'compute:None'}}}) + 'device': 'compute:None', + 'binding:vif_type': 'fake_vif_type', + 'binding:host_id': host_id, + portbindings.VIF_DETAILS: {}, + portbindings.VNIC_TYPE: 'normal'}}}) # update network type from fake_vif_type to ovs update_resource('port', False, port_id, @@ -686,7 +698,12 @@ class PluginTest(unittest.TestCase): mock_update.assert_called_with( self.context, 'port', port_id, {'port': {'binding:profile': {'region': 'Pod1', - 'device': 'compute:None'}}}) + 'device': 'compute:None', + 'binding:vif_type': 'ovs', + 'binding:host_id': + 'fake_another_host', + portbindings.VIF_DETAILS: {}, + portbindings.VNIC_TYPE: 'normal'}}}) self.plugin.update_port(self.context, port_id, update_body) # default p2p mode, update with agent host tunnel ip @@ -696,7 +713,11 @@ class PluginTest(unittest.TestCase): 'tunnel_ip': '192.168.1.101', 'type': 'Open vSwitch agent', 'host': host_id, - 'device': 'compute:None'}}}) + 'device': 'compute:None', + 'binding:vif_type': 'ovs', + 'binding:host_id': host_id, + portbindings.VIF_DETAILS: {}, + portbindings.VNIC_TYPE: 'normal'}}}) cfg.CONF.set_override('cross_pod_vxlan_mode', 'l2gw', 'client') cfg.CONF.set_override('l2gw_tunnel_ip', '192.168.1.105', 'tricircle') @@ -710,7 +731,11 @@ class PluginTest(unittest.TestCase): 'tunnel_ip': '192.168.1.105', 'type': 'Open vSwitch agent', 'host': 'fake_host', - 'device': 'compute:None'}}}) + 'device': 'compute:None', + 'binding:vif_type': 'ovs', + 'binding:host_id': host_id, + portbindings.VIF_DETAILS: {}, + portbindings.VNIC_TYPE: 'normal'}}}) cfg.CONF.set_override('l2gw_tunnel_ip', None, 'tricircle') cfg.CONF.set_override('cross_pod_vxlan_mode', 'l2gw', 'client') @@ -719,7 +744,11 @@ class PluginTest(unittest.TestCase): mock_update.assert_called_with( self.context, 'port', port_id, {'port': {'binding:profile': {'region': 'Pod1', - 'device': 'compute:None'}}}) + 'device': 'compute:None', + 'binding:vif_type': 'ovs', + 'binding:host_id': host_id, + portbindings.VIF_DETAILS: {}, + portbindings.VNIC_TYPE: 'normal'}}}) cfg.CONF.set_override('cross_pod_vxlan_mode', 'noop', 'client') self.plugin.update_port(self.context, port_id, update_body) @@ -727,7 +756,11 @@ class PluginTest(unittest.TestCase): mock_update.assert_called_with( self.context, 'port', port_id, {'port': {'binding:profile': {'region': 'Pod1', - 'device': 'compute:None'}}}) + 'device': 'compute:None', + 'binding:vif_type': 'ovs', + 'binding:host_id': host_id, + portbindings.VIF_DETAILS: {}, + portbindings.VNIC_TYPE: 'normal'}}}) FakeCorePlugin.supported_extension_aliases = [] self.plugin.update_port(self.context, port_id, update_body) @@ -735,7 +768,11 @@ class PluginTest(unittest.TestCase): mock_update.assert_called_with( self.context, 'port', port_id, {'port': {'binding:profile': {'region': 'Pod1', - 'device': 'compute:None'}}}) + 'device': 'compute:None', + 'binding:vif_type': 'ovs', + 'binding:host_id': host_id, + portbindings.VIF_DETAILS: {}, + portbindings.VNIC_TYPE: 'normal'}}}) FakeCorePlugin.supported_extension_aliases = ['agent'] self.plugin.update_port(self.context, port_id,