Henry Gessau 0e3766ced4 Prepare for multiple cisco ML2 mech drivers
Code tree reorganization in preparation for ML2 mechanism drivers for
other cisco products. The cisco nexus ML2 mechanism driver and its
test cases need to move down into their own subdirectory.

Closes-bug: #1277222

Change-Id: I2ba366332276069545b3deb0bbd39016a893327b
2014-02-07 11:37:01 -05:00

198 lines
7.9 KiB
Python

# Copyright 2013 OpenStack Foundation
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
ML2 Mechanism Driver for Cisco Nexus platforms.
"""
from oslo.config import cfg
from neutron.common import constants as n_const
from neutron.extensions import portbindings
from neutron.openstack.common import log as logging
from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2 import driver_api as api
from neutron.plugins.ml2.drivers.cisco.nexus import config as conf
from neutron.plugins.ml2.drivers.cisco.nexus import credentials_v2 as cred
from neutron.plugins.ml2.drivers.cisco.nexus import exceptions as excep
from neutron.plugins.ml2.drivers.cisco.nexus import nexus_db_v2 as nxos_db
from neutron.plugins.ml2.drivers.cisco.nexus import nexus_network_driver
LOG = logging.getLogger(__name__)
class CiscoNexusMechanismDriver(api.MechanismDriver):
"""Cisco Nexus ML2 Mechanism Driver."""
def initialize(self):
# Create ML2 device dictionary from ml2_conf.ini entries.
conf.ML2MechCiscoConfig()
# Extract configuration parameters from the configuration file.
self._nexus_switches = conf.ML2MechCiscoConfig.nexus_dict
LOG.debug(_("nexus_switches found = %s"), self._nexus_switches)
self.credentials = {}
self.driver = nexus_network_driver.CiscoNexusDriver()
# Initialize credential store after database initialization.
cred.Store.initialize()
def _valid_network_segment(self, segment):
return (cfg.CONF.ml2_cisco.managed_physical_network is None or
cfg.CONF.ml2_cisco.managed_physical_network ==
segment[api.PHYSICAL_NETWORK])
def _get_vlanid(self, context):
segment = context.bound_segment
if (segment and segment[api.NETWORK_TYPE] == p_const.TYPE_VLAN and
self._valid_network_segment(segment)):
return context.bound_segment.get(api.SEGMENTATION_ID)
def _is_deviceowner_compute(self, port):
return port['device_owner'].startswith('compute')
def _is_status_active(self, port):
return port['status'] == n_const.PORT_STATUS_ACTIVE
def _get_switch_info(self, host_id):
for switch_ip, attr in self._nexus_switches:
if str(attr) == str(host_id):
port_id = self._nexus_switches[switch_ip, attr]
return port_id, switch_ip
else:
raise excep.NexusComputeHostNotConfigured(host=host_id)
def _configure_nxos_db(self, context, vlan_id, device_id, host_id):
"""Create the nexus database entry.
Called during update precommit port event.
"""
port_id, switch_ip = self._get_switch_info(host_id)
nxos_db.add_nexusport_binding(port_id, str(vlan_id), switch_ip,
device_id)
def _configure_switch_entry(self, context, vlan_id, device_id, host_id):
"""Create a nexus switch entry.
if needed, create a VLAN in the appropriate switch/port and
configure the appropriate interfaces for this VLAN.
Called during update postcommit port event.
"""
port_id, switch_ip = self._get_switch_info(host_id)
vlan_name = cfg.CONF.ml2_cisco.vlan_name_prefix + str(vlan_id)
# Check to see if this is the first binding to use this vlan on the
# switch/port. Configure switch accordingly.
bindings = nxos_db.get_nexusvlan_binding(vlan_id, switch_ip)
if len(bindings) == 1:
LOG.debug(_("Nexus: create & trunk vlan %s"), vlan_name)
self.driver.create_and_trunk_vlan(switch_ip, vlan_id, vlan_name,
port_id)
else:
LOG.debug(_("Nexus: trunk vlan %s"), vlan_name)
self.driver.enable_vlan_on_trunk_int(switch_ip, vlan_id, port_id)
def _delete_nxos_db(self, context, vlan_id, device_id, host_id):
"""Delete the nexus database entry.
Called during delete precommit port event.
"""
try:
row = nxos_db.get_nexusvm_binding(vlan_id, device_id)
nxos_db.remove_nexusport_binding(row.port_id, row.vlan_id,
row.switch_ip, row.instance_id)
except excep.NexusPortBindingNotFound:
return
def _delete_switch_entry(self, context, vlan_id, device_id, host_id):
"""Delete the nexus switch entry.
By accessing the current db entries determine if switch
configuration can be removed.
Called during update postcommit port event.
"""
port_id, switch_ip = self._get_switch_info(host_id)
# if there are no remaining db entries using this vlan on this nexus
# switch port then remove vlan from the switchport trunk.
try:
nxos_db.get_port_vlan_switch_binding(port_id, vlan_id, switch_ip)
except excep.NexusPortBindingNotFound:
self.driver.disable_vlan_on_trunk_int(switch_ip, vlan_id, port_id)
# if there are no remaining db entries using this vlan on this
# nexus switch then remove the vlan.
try:
nxos_db.get_nexusvlan_binding(vlan_id, switch_ip)
except excep.NexusPortBindingNotFound:
self.driver.delete_vlan(switch_ip, vlan_id)
def _port_action(self, context, func):
"""Verify configuration and then process event."""
device_id = context.current.get('device_id')
host_id = context.current.get(portbindings.HOST_ID)
# Workaround until vlan can be retrieved during delete_port_postcommit
# (or prehaps unbind_port) event.
if func == self._delete_switch_entry:
vlan_id = self._delete_port_postcommit_vlan
else:
vlan_id = self._get_vlanid(context)
if vlan_id and device_id and host_id:
func(context, vlan_id, device_id, host_id)
else:
fields = "vlan_id " if not vlan_id else ""
fields += "device_id " if not device_id else ""
fields += "host_id" if not host_id else ""
raise excep.NexusMissingRequiredFields(fields=fields)
# Workaround until vlan can be retrieved during delete_port_postcommit
# (or prehaps unbind_port) event.
if func == self._delete_nxos_db:
self._delete_port_postcommit_vlan = vlan_id
else:
self._delete_port_postcommit_vlan = 0
def update_port_precommit(self, context):
"""Update port pre-database transaction commit event."""
port = context.current
if self._is_deviceowner_compute(port) and self._is_status_active(port):
self._port_action(context, self._configure_nxos_db)
def update_port_postcommit(self, context):
"""Update port non-database commit event."""
port = context.current
if self._is_deviceowner_compute(port) and self._is_status_active(port):
self._port_action(context, self._configure_switch_entry)
def delete_port_precommit(self, context):
"""Delete port pre-database commit event."""
if self._is_deviceowner_compute(context.current):
self._port_action(context, self._delete_nxos_db)
def delete_port_postcommit(self, context):
"""Delete port non-database commit event."""
if self._is_deviceowner_compute(context.current):
self._port_action(context, self._delete_switch_entry)