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 <zhangxiaohan@szzt.com.cn>
Co-Authored-By: tangzhuo <ztang@hnu.edu.cn>
This commit is contained in:
zhangxiaohan 2018-09-18 17:05:59 +08:00
parent c3e4a072bb
commit 56c118a638
3 changed files with 92 additions and 12 deletions

View File

@ -43,6 +43,7 @@ from neutron.db import l3_hamode_db # noqa
from neutron.db import models_v2 from neutron.db import models_v2
from neutron.db import portbindings_db from neutron.db import portbindings_db
from neutron.extensions import providernet as provider from neutron.extensions import providernet as provider
from neutron.objects import ports as q_ports
from neutron.objects.qos import policy as policy_object from neutron.objects.qos import policy as policy_object
import neutron.objects.router as router_object import neutron.objects.router as router_object
from neutron.plugins.ml2 import managers as n_managers 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 external_net
from neutron_lib.api.definitions import l3 as l3_apidef from neutron_lib.api.definitions import l3 as l3_apidef
from neutron_lib.api.definitions import portbindings 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.definitions import provider_net
from neutron_lib.api import validators from neutron_lib.api import validators
from neutron_lib.api.validators import availability_zone as az_validator 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 # do not reserve snat port for bridge and external subnet
snat_port_id = self.helper.prepare_top_snat_port( snat_port_id = self.helper.prepare_top_snat_port(
t_ctx, context, res['tenant_id'], network['id'], res['id']) t_ctx, context, res['tenant_id'], network['id'], res['id'])
self._create_port_binding(context, snat_port_id)
if res['enable_dhcp']: 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']) t_ctx, context, res['tenant_id'], network['id'], res['id'])
self._create_port_binding(context, dhcp_port_id)
except Exception: except Exception:
if snat_port_id: if snat_port_id:
super(TricirclePlugin, self).delete_port(context, 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']) self.delete_subnet(context, res['id'])
raise raise
return res return res
@ -573,6 +579,7 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
q_ctx, {'name': [port_name]}) q_ctx, {'name': [port_name]})
if ports: if ports:
super(TricirclePlugin, self).delete_port(q_ctx, ports[0]['id']) 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) db_api.delete_pre_created_resource_mapping(t_ctx, port_name)
def delete_subnet(self, context, subnet_id): def delete_subnet(self, context, subnet_id):
@ -642,6 +649,18 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
t_constants.POD_NOT_SPECIFIED) t_constants.POD_NOT_SPECIFIED)
return result 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): def create_port(self, context, port):
port_body = port['port'] port_body = port['port']
if port_body['device_id'] == t_constants.interface_port_device_id: 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, t_ctx, context, port_body['tenant_id'], pod,
{'id': port_body['name']}, t_constants.RT_PORT, {'id': port_body['name']}, t_constants.RT_PORT,
gateway_port_body) gateway_port_body)
self._create_port_binding(context, t_gateway_id)
return super(TricirclePlugin, self).get_port(context, t_gateway_id) return super(TricirclePlugin, self).get_port(context, t_gateway_id)
db_port = super(TricirclePlugin, self).create_port_db(context, port) db_port = super(TricirclePlugin, self).create_port_db(context, port)
self._ensure_default_security_group_on_port(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) result = self._make_port_dict(db_port)
self.extension_manager.process_create_port(context, port_body, result) self.extension_manager.process_create_port(context, port_body, result)
self._process_port_create_security_group(context, result, sgids) self._process_port_create_security_group(context, result, sgids)
self._create_port_binding(context, db_port.id)
return result return result
def _check_mac_update_allowed(self, orig_port, port): def _check_mac_update_allowed(self, orig_port, port):
@ -795,10 +816,28 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
'name': bottom_port['name'] '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): def update_port(self, context, port_id, port):
t_ctx = t_context.get_context_from_neutron_context(context) t_ctx = t_context.get_context_from_neutron_context(context)
top_port = super(TricirclePlugin, self).get_port(context, port_id) top_port = super(TricirclePlugin, self).get_port(context, port_id)
updated_port = None 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 # 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, # router interface, we cannot directly update bottom port in this case,
# otherwise we will fail when attaching bottom port to bottom router # otherwise we will fail when attaching bottom port to bottom router
@ -993,6 +1032,7 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
'comparator': 'eq', 'comparator': 'eq',
'value': port_id}]) 'value': port_id}])
super(TricirclePlugin, self).delete_port(context, 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): def _get_port_qos_info(self, context, port_id):
policy = policy_object.QosPolicy.get_port_policy(context, port_id) policy = policy_object.QosPolicy.get_port_policy(context, port_id)

View File

@ -738,8 +738,11 @@ class TricirclePlugin(plugin.Ml2Plugin):
region_name = self._get_neutron_region() region_name = self._get_neutron_region()
update_dict = {portbindings.PROFILE: { update_dict = {portbindings.PROFILE: {
t_constants.PROFILE_REGION: region_name, 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): if b_port.get(t_constants.PROFILE_STATUS):
update_dict[portbindings.PROFILE].update({ update_dict[portbindings.PROFILE].update({
t_constants.PROFILE_STATUS: b_port['status'] t_constants.PROFILE_STATUS: b_port['status']

View File

@ -646,7 +646,11 @@ class PluginTest(unittest.TestCase):
fake_port = { fake_port = {
'id': port_id, 'id': port_id,
'network_id': b_net['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 = { fake_agent = {
'agent_type': 'Open vSwitch agent', 'agent_type': 'Open vSwitch agent',
'host': host_id, 'host': host_id,
@ -662,7 +666,11 @@ class PluginTest(unittest.TestCase):
mock_update.assert_called_with( mock_update.assert_called_with(
self.context, 'port', port_id, self.context, 'port', port_id,
{'port': {'binding:profile': {'region': 'Pod1', {'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 network type from vlan to vxlan
update_resource('network', False, b_net['id'], update_resource('network', False, b_net['id'],
@ -673,7 +681,11 @@ class PluginTest(unittest.TestCase):
mock_update.assert_called_with( mock_update.assert_called_with(
self.context, 'port', port_id, self.context, 'port', port_id,
{'port': {'binding:profile': {'region': 'Pod1', {'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 network type from fake_vif_type to ovs
update_resource('port', False, port_id, update_resource('port', False, port_id,
@ -686,7 +698,12 @@ class PluginTest(unittest.TestCase):
mock_update.assert_called_with( mock_update.assert_called_with(
self.context, 'port', port_id, self.context, 'port', port_id,
{'port': {'binding:profile': {'region': 'Pod1', {'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) self.plugin.update_port(self.context, port_id, update_body)
# default p2p mode, update with agent host tunnel ip # default p2p mode, update with agent host tunnel ip
@ -696,7 +713,11 @@ class PluginTest(unittest.TestCase):
'tunnel_ip': '192.168.1.101', 'tunnel_ip': '192.168.1.101',
'type': 'Open vSwitch agent', 'type': 'Open vSwitch agent',
'host': host_id, '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('cross_pod_vxlan_mode', 'l2gw', 'client')
cfg.CONF.set_override('l2gw_tunnel_ip', '192.168.1.105', 'tricircle') 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', 'tunnel_ip': '192.168.1.105',
'type': 'Open vSwitch agent', 'type': 'Open vSwitch agent',
'host': 'fake_host', '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('l2gw_tunnel_ip', None, 'tricircle')
cfg.CONF.set_override('cross_pod_vxlan_mode', 'l2gw', 'client') cfg.CONF.set_override('cross_pod_vxlan_mode', 'l2gw', 'client')
@ -719,7 +744,11 @@ class PluginTest(unittest.TestCase):
mock_update.assert_called_with( mock_update.assert_called_with(
self.context, 'port', port_id, self.context, 'port', port_id,
{'port': {'binding:profile': {'region': 'Pod1', {'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') cfg.CONF.set_override('cross_pod_vxlan_mode', 'noop', 'client')
self.plugin.update_port(self.context, port_id, update_body) self.plugin.update_port(self.context, port_id, update_body)
@ -727,7 +756,11 @@ class PluginTest(unittest.TestCase):
mock_update.assert_called_with( mock_update.assert_called_with(
self.context, 'port', port_id, self.context, 'port', port_id,
{'port': {'binding:profile': {'region': 'Pod1', {'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 = [] FakeCorePlugin.supported_extension_aliases = []
self.plugin.update_port(self.context, port_id, update_body) self.plugin.update_port(self.context, port_id, update_body)
@ -735,7 +768,11 @@ class PluginTest(unittest.TestCase):
mock_update.assert_called_with( mock_update.assert_called_with(
self.context, 'port', port_id, self.context, 'port', port_id,
{'port': {'binding:profile': {'region': 'Pod1', {'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'] FakeCorePlugin.supported_extension_aliases = ['agent']
self.plugin.update_port(self.context, port_id, self.plugin.update_port(self.context, port_id,