Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 3243e0a9 authored by JONGLEZ Baptiste's avatar JONGLEZ Baptiste
Browse files

Don't make actual device changes in bind_port()

According to the bind_port specification (as summed up in its docstring),
we should not make any change when bind_port() is called, because binding
results might end up not getting committed.

To satisfy this specification, this patch moves actual device
reconfiguration to update_port_postcommit().

In addition, this will likely make it easier to improve performance of
bulk port creation in the future, see https://bugs.launchpad.net/neutron/+bug/1976270

Note that this change introduces a different retry behaviour when we fail
to configure a device.  Since bind_port() is retried several times by
Neutron, we indirectly benefited from these retries, but this is no longer
the case.  However, NGS already has an internal retry mechanism for SSH
connection errors, which should cover most network-related issues.

To sum up, errors that are no longer covered by a retry are the ones that
happen after we successfully connect to the device.  For instance, the
switch port may not exist on the device, or the device could be in an
unexpected state such as a port being currently part of an unexpected
VLAN.  This kind of errors are unlikely to be solved by retrying, so the
new behaviour should be fine and will even allow to return the error much
faster to the end-user.

Change-Id: If4ca9c58d7f30b40992d0f1aee7e915c6978e0ca
parent d0d72a88
Branches g5k
No related tags found
No related merge requests found
...@@ -17,6 +17,7 @@ import sys ...@@ -17,6 +17,7 @@ import sys
from neutron.db import provisioning_blocks from neutron.db import provisioning_blocks
from neutron_lib.api.definitions import portbindings from neutron_lib.api.definitions import portbindings
from neutron_lib.callbacks import resources from neutron_lib.callbacks import resources
from neutron_lib import constants as const
from neutron_lib.plugins.ml2 import api from neutron_lib.plugins.ml2 import api
from oslo_log import log as logging from oslo_log import log as logging
...@@ -340,20 +341,50 @@ class GenericSwitchDriver(api.MechanismDriver): ...@@ -340,20 +341,50 @@ class GenericSwitchDriver(api.MechanismDriver):
state changes that it does not know or care about. state changes that it does not know or care about.
""" """
port = context.current port = context.current
network = context.network.current
if self._is_port_bound(port): if self._is_port_bound(port):
binding_profile = port['binding:profile'] binding_profile = port['binding:profile']
local_link_information = binding_profile.get( local_link_information = binding_profile.get(
'local_link_information') 'local_link_information')
if not local_link_information: if not local_link_information:
return return
# Necessary because the "provisioning_complete" event triggers
# an additional call to update_port_postcommit(). We don't
# want to configure the port a second time.
if port['status'] == const.PORT_STATUS_ACTIVE:
LOG.debug("Port %(port_id)s is already active, "
"not doing anything",
{'port_id': port['id']})
return
# If binding has already succeeded, we should have valid links
# at this point, but check just in case.
if not self._is_link_valid(port, network):
return
is_802_3ad = self._is_802_3ad(port)
for link in local_link_information: for link in local_link_information:
port_id = link.get('port_id')
switch_info = link.get('switch_info') switch_info = link.get('switch_info')
switch_id = link.get('switch_id') switch_id = link.get('switch_id')
switch = device_utils.get_switch_device( switch = device_utils.get_switch_device(
self.switches, switch_info=switch_info, self.switches, switch_info=switch_info,
ngs_mac_address=switch_id) ngs_mac_address=switch_id)
if not switch:
return # If segmentation ID is None, set vlan 1
segmentation_id = network.get('provider:segmentation_id') or 1
LOG.debug("Putting switch port %(switch_port)s on "
"%(switch_info)s in vlan %(segmentation_id)s",
{'switch_port': port_id, 'switch_info': switch_info,
'segmentation_id': segmentation_id})
# Move port to network
if is_802_3ad and hasattr(switch, 'plug_bond_to_network'):
switch.plug_bond_to_network(port_id, segmentation_id)
else:
switch.plug_port_to_network(port_id, segmentation_id)
LOG.info("Successfully plugged port %(port_id)s in segment "
"%(segment_id)s on device %(device)s",
{'port_id': port['id'], 'device': switch_info,
'segment_id': segmentation_id})
provisioning_blocks.provisioning_complete( provisioning_blocks.provisioning_complete(
context._plugin_context, port['id'], resources.PORT, context._plugin_context, port['id'], resources.PORT,
GENERIC_SWITCH_ENTITY) GENERIC_SWITCH_ENTITY)
...@@ -446,32 +477,7 @@ class GenericSwitchDriver(api.MechanismDriver): ...@@ -446,32 +477,7 @@ class GenericSwitchDriver(api.MechanismDriver):
if not self._is_link_valid(port, network): if not self._is_link_valid(port, network):
return return
is_802_3ad = self._is_802_3ad(port) segments = context.segments_to_bind
for link in local_link_information:
port_id = link.get('port_id')
switch_info = link.get('switch_info')
switch_id = link.get('switch_id')
switch = device_utils.get_switch_device(
self.switches, switch_info=switch_info,
ngs_mac_address=switch_id)
segments = context.segments_to_bind
# If segmentation ID is None, set vlan 1
segmentation_id = segments[0].get('segmentation_id') or 1
LOG.debug("Putting port %(port_id)s on %(switch_info)s "
"to vlan: %(segmentation_id)s",
{'port_id': port_id, 'switch_info': switch_info,
'segmentation_id': segmentation_id})
# Move port to network
if is_802_3ad and hasattr(switch, 'plug_bond_to_network'):
switch.plug_bond_to_network(port_id, segmentation_id)
else:
switch.plug_port_to_network(port_id, segmentation_id)
LOG.info("Successfully bound port %(port_id)s in segment "
"%(segment_id)s on device %(device)s",
{'port_id': port['id'], 'device': switch_info,
'segment_id': segmentation_id})
context.set_binding(segments[0][api.ID], context.set_binding(segments[0][api.ID],
portbindings.VIF_TYPE_OTHER, {}) portbindings.VIF_TYPE_OTHER, {})
provisioning_blocks.add_provisioning_component( provisioning_blocks.add_provisioning_component(
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment