Brocade vendor code decomposition from neutron repo.

Brocade code decomposition of VDX mechanism driver,
includes moving out the driver and unit tests. Left
behind are the DB model for migration and config

Closes bug: #1427793

Change-Id: I3b06a1800cce1ddbb87c6ebd7981e3f249df5060
This commit is contained in:
Shiv Haris 2015-02-02 17:58:53 -08:00
parent d6a12942f3
commit bad92a463e
12 changed files with 14 additions and 1716 deletions

View File

@ -402,7 +402,7 @@ The following chart captures the following aspects:
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
| networking-bigswitch_ | ml2,core,l3 | no | yes | [C] | Kilo |
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
| networking-brocade_ | | | | | |
| networking-brocade_ | ml2,l3 | yes | yes | [C] | Kilo |
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
| networking-cisco_ | core,ml2,l3,fw,vpn | yes | yes | [B] | |
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
@ -452,6 +452,11 @@ Big Switch Networks
.. _networking-brocade:
* Git: https://github.com/stackforge/networking-brocade
* Launchpad: https://launchpad.net/networking-brocade
* PyPI: https://pypi.python.org/pypi/networking-brocade
.. _networking-cisco:
Cisco

View File

@ -1,10 +1,16 @@
Brocade ML2 Mechanism driver from ML2 plugin
============================================
* The real code now resides in stackforge:
http://github.com/stackforge/networking-brocade
* up-to-date version of these instructions are located at:
http://50.56.236.34/docs/brocade-ml2-mechanism.txt
* N.B.: Please see Prerequisites section regarding ncclient (netconf client library)
* Supports VCS (Virtual Cluster of Switches)
* Issues/Questions/Bugs: sharis@brocade.com

View File

@ -17,17 +17,6 @@
"""Implentation of Brocade ML2 Mechanism driver for ML2 Plugin."""
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
from oslo_utils import importutils
from neutron.i18n import _LE, _LI
from neutron.plugins.ml2 import driver_api
from neutron.plugins.ml2.drivers.brocade.db import models as brocade_db
LOG = logging.getLogger(__name__)
MECHANISM_VERSION = 0.9
NOS_DRIVER = 'neutron.plugins.ml2.drivers.brocade.nos.nosdriver.NOSdriver'
ML2_BROCADE = [cfg.StrOpt('address', default='',
help=_('The address of the host to SSH to')),
@ -44,410 +33,3 @@ ML2_BROCADE = [cfg.StrOpt('address', default='',
]
cfg.CONF.register_opts(ML2_BROCADE, "ml2_brocade")
class BrocadeMechanism(driver_api.MechanismDriver):
"""ML2 Mechanism driver for Brocade VDX switches. This is the upper
layer driver class that interfaces to lower layer (NETCONF) below.
"""
def __init__(self):
self._driver = None
self._physical_networks = None
self._switch = None
self.initialize()
def initialize(self):
"""Initilize of variables needed by this class."""
self._physical_networks = cfg.CONF.ml2_brocade.physical_networks
self.brocade_init()
def brocade_init(self):
"""Brocade specific initialization for this class."""
osversion = None
self._switch = {
'address': cfg.CONF.ml2_brocade.address,
'username': cfg.CONF.ml2_brocade.username,
'password': cfg.CONF.ml2_brocade.password,
'ostype': cfg.CONF.ml2_brocade.ostype,
'osversion': cfg.CONF.ml2_brocade.osversion}
self._driver = importutils.import_object(NOS_DRIVER)
# Detect version of NOS on the switch
osversion = self._switch['osversion']
if osversion == "autodetect":
osversion = self._driver.get_nos_version(
self._switch['address'],
self._switch['username'],
self._switch['password'])
virtual_fabric_enabled = self._driver.is_virtual_fabric_enabled(
self._switch['address'],
self._switch['username'],
self._switch['password'])
if virtual_fabric_enabled:
LOG.debug("Virtual Fabric: enabled")
else:
LOG.debug("Virtual Fabric: not enabled")
self.set_features_enabled(osversion, virtual_fabric_enabled)
def set_features_enabled(self, nos_version, virtual_fabric_enabled):
self._virtual_fabric_enabled = virtual_fabric_enabled
version = nos_version.split(".", 2)
# Starting 4.1.0 port profile domains are supported
if int(version[0]) >= 5 or (int(version[0]) >= 4
and int(version[1]) >= 1):
self._pp_domains_supported = True
else:
self._pp_domains_supported = False
self._driver.set_features_enabled(self._pp_domains_supported,
self._virtual_fabric_enabled)
def get_features_enabled(self):
return self._pp_domains_supported, self._virtual_fabric_enabled
def create_network_precommit(self, mech_context):
"""Create Network in the mechanism specific database table."""
network = mech_context.current
context = mech_context._plugin_context
tenant_id = network['tenant_id']
network_id = network['id']
segments = mech_context.network_segments
# currently supports only one segment per network
segment = segments[0]
network_type = segment['network_type']
vlan_id = segment['segmentation_id']
segment_id = segment['id']
if segment['physical_network'] not in self._physical_networks:
raise Exception(
_("Brocade Mechanism: failed to create network, "
"network cannot be created in the configured "
"physical network"))
if network_type != 'vlan':
raise Exception(
_("Brocade Mechanism: failed to create network, "
"only network type vlan is supported"))
try:
brocade_db.create_network(context, network_id, vlan_id,
segment_id, network_type, tenant_id)
except Exception:
LOG.exception(
_LE("Brocade Mechanism: failed to create network in db"))
raise Exception(
_("Brocade Mechanism: create_network_precommit failed"))
LOG.info(_LI("create network (precommit): %(network_id)s "
"of network type = %(network_type)s "
"with vlan = %(vlan_id)s "
"for tenant %(tenant_id)s"),
{'network_id': network_id,
'network_type': network_type,
'vlan_id': vlan_id,
'tenant_id': tenant_id})
def create_network_postcommit(self, mech_context):
"""Create Network as a portprofile on the switch."""
LOG.debug("create_network_postcommit: called")
network = mech_context.current
# use network_id to get the network attributes
# ONLY depend on our db for getting back network attributes
# this is so we can replay postcommit from db
context = mech_context._plugin_context
network_id = network['id']
network = brocade_db.get_network(context, network_id)
network_type = network['network_type']
tenant_id = network['tenant_id']
vlan_id = network['vlan']
try:
self._driver.create_network(self._switch['address'],
self._switch['username'],
self._switch['password'],
vlan_id)
except Exception:
LOG.exception(_LE("Brocade NOS driver: failed in create network"))
brocade_db.delete_network(context, network_id)
raise Exception(
_("Brocade Mechanism: create_network_postcommmit failed"))
LOG.info(_LI("created network (postcommit): %(network_id)s"
" of network type = %(network_type)s"
" with vlan = %(vlan_id)s"
" for tenant %(tenant_id)s"),
{'network_id': network_id,
'network_type': network_type,
'vlan_id': vlan_id,
'tenant_id': tenant_id})
def delete_network_precommit(self, mech_context):
"""Delete Network from the plugin specific database table."""
LOG.debug("delete_network_precommit: called")
network = mech_context.current
network_id = network['id']
vlan_id = network['provider:segmentation_id']
tenant_id = network['tenant_id']
context = mech_context._plugin_context
try:
brocade_db.delete_network(context, network_id)
except Exception:
LOG.exception(
_LE("Brocade Mechanism: failed to delete network in db"))
raise Exception(
_("Brocade Mechanism: delete_network_precommit failed"))
LOG.info(_LI("delete network (precommit): %(network_id)s"
" with vlan = %(vlan_id)s"
" for tenant %(tenant_id)s"),
{'network_id': network_id,
'vlan_id': vlan_id,
'tenant_id': tenant_id})
def delete_network_postcommit(self, mech_context):
"""Delete network which translates to removng portprofile
from the switch.
"""
LOG.debug("delete_network_postcommit: called")
network = mech_context.current
network_id = network['id']
vlan_id = network['provider:segmentation_id']
tenant_id = network['tenant_id']
try:
self._driver.delete_network(self._switch['address'],
self._switch['username'],
self._switch['password'],
vlan_id)
except Exception:
LOG.exception(_LE("Brocade NOS driver: failed to delete network"))
raise Exception(
_("Brocade switch exception, "
"delete_network_postcommit failed"))
LOG.info(_LI("delete network (postcommit): %(network_id)s"
" with vlan = %(vlan_id)s"
" for tenant %(tenant_id)s"),
{'network_id': network_id,
'vlan_id': vlan_id,
'tenant_id': tenant_id})
def update_network_precommit(self, mech_context):
"""Noop now, it is left here for future."""
pass
def update_network_postcommit(self, mech_context):
"""Noop now, it is left here for future."""
pass
def create_port_precommit(self, mech_context):
"""Create logical port on the switch (db update)."""
LOG.debug("create_port_precommit: called")
port = mech_context.current
port_id = port['id']
network_id = port['network_id']
tenant_id = port['tenant_id']
admin_state_up = port['admin_state_up']
context = mech_context._plugin_context
network = brocade_db.get_network(context, network_id)
vlan_id = network['vlan']
try:
brocade_db.create_port(context, port_id, network_id,
None,
vlan_id, tenant_id, admin_state_up)
except Exception:
LOG.exception(_LE("Brocade Mechanism: failed to create port"
" in db"))
raise Exception(
_("Brocade Mechanism: create_port_precommit failed"))
def create_port_postcommit(self, mech_context):
"""Associate the assigned MAC address to the portprofile."""
LOG.debug("create_port_postcommit: called")
port = mech_context.current
port_id = port['id']
network_id = port['network_id']
tenant_id = port['tenant_id']
context = mech_context._plugin_context
self._associate_mac_to_net(context, network_id, port['mac_address'],
"create_port_postcommit")
LOG.info(
_LI("created port (postcommit): port_id=%(port_id)s"
" network_id=%(network_id)s tenant_id=%(tenant_id)s"),
{'port_id': port_id,
'network_id': network_id, 'tenant_id': tenant_id})
def delete_port_precommit(self, mech_context):
"""Delete logical port on the switch (db update)."""
LOG.debug("delete_port_precommit: called")
port = mech_context.current
port_id = port['id']
context = mech_context._plugin_context
try:
brocade_db.delete_port(context, port_id)
except Exception:
LOG.exception(_LE("Brocade Mechanism: failed to delete port"
" in db"))
raise Exception(
_("Brocade Mechanism: delete_port_precommit failed"))
def delete_port_postcommit(self, mech_context):
"""Dissociate MAC address from the portprofile."""
LOG.debug("delete_port_postcommit: called")
port = mech_context.current
port_id = port['id']
network_id = port['network_id']
tenant_id = port['tenant_id']
context = mech_context._plugin_context
self._dissociate_mac_from_net(context, network_id, port['mac_address'],
"delete_port_postcommit")
LOG.info(
_LI("delete port (postcommit): port_id=%(port_id)s"
" network_id=%(network_id)s tenant_id=%(tenant_id)s"),
{'port_id': port_id,
'network_id': network_id, 'tenant_id': tenant_id})
def update_port_precommit(self, mech_context):
"""Noop now, it is left here for future."""
LOG.debug("update_port_precommit(self: called")
def update_port_postcommit(self, mech_context):
"""If mac changes, update association to network."""
LOG.debug("update_port_postcommit: called")
port = mech_context.current
old_port = mech_context.original
if port['mac_address'] == old_port['mac_address']:
return
port_id = port['id']
network_id = port['network_id']
tenant_id = port['tenant_id']
context = mech_context._plugin_context
self._dissociate_mac_from_net(context, network_id,
old_port['mac_address'],
"update_port_postcommit")
self._associate_mac_to_net(context, network_id, port['mac_address'],
"update_port_postcommit")
LOG.info(
_LI("update port (postcommit): port_id=%(port_id)s"
" network_id=%(network_id)s tenant_id=%(tenant_id)s."),
{'port_id': port_id,
'network_id': network_id, 'tenant_id': tenant_id})
def create_subnet_precommit(self, mech_context):
"""Noop now, it is left here for future."""
LOG.debug("create_subnetwork_precommit: called")
def create_subnet_postcommit(self, mech_context):
"""Noop now, it is left here for future."""
LOG.debug("create_subnetwork_postcommit: called")
def delete_subnet_precommit(self, mech_context):
"""Noop now, it is left here for future."""
LOG.debug("delete_subnetwork_precommit: called")
def delete_subnet_postcommit(self, mech_context):
"""Noop now, it is left here for future."""
LOG.debug("delete_subnetwork_postcommit: called")
def update_subnet_precommit(self, mech_context):
"""Noop now, it is left here for future."""
LOG.debug("update_subnet_precommit(self: called")
def update_subnet_postcommit(self, mech_context):
"""Noop now, it is left here for future."""
LOG.debug("update_subnet_postcommit: called")
def _associate_mac_to_net(self, context, network_id, interface_mac, op):
network = brocade_db.get_network(context, network_id)
vlan_id = network['vlan']
# convert mac format: xx:xx:xx:xx:xx:xx -> xxxx.xxxx.xxxx
mac = self.mac_reformat_62to34(interface_mac)
try:
self._driver.associate_mac_to_network(self._switch['address'],
self._switch['username'],
self._switch['password'],
vlan_id,
mac)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(
_LE("Brocade NOS driver: failed to associate mac %s"),
interface_mac)
def _dissociate_mac_from_net(self, context, network_id, interface_mac, op):
network = brocade_db.get_network(context, network_id)
vlan_id = network['vlan']
# convert mac format: xx:xx:xx:xx:xx:xx -> xxxx.xxxx.xxxx
mac = self.mac_reformat_62to34(interface_mac)
try:
self._driver.dissociate_mac_from_network(
self._switch['address'],
self._switch['username'],
self._switch['password'],
vlan_id,
mac)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(
_LE("Brocade NOS driver: failed to dissociate MAC %s"),
interface_mac)
@staticmethod
def mac_reformat_62to34(interface_mac):
"""Transform MAC address format.
Transforms from 6 groups of 2 hexadecimal numbers delimited by ":"
to 3 groups of 4 hexadecimals numbers delimited by ".".
:param interface_mac: MAC address in the format xx:xx:xx:xx:xx:xx
:type interface_mac: string
:returns: MAC address in the format xxxx.xxxx.xxxx
:rtype: string
"""
mac = interface_mac.replace(":", "")
mac = mac[0:4] + "." + mac[4:8] + "." + mac[8:12]
return mac

View File

@ -1,433 +0,0 @@
# Copyright (c) 2014 Brocade Communications Systems, Inc.
# 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.
"""NOS NETCONF XML Configuration Command Templates.
Interface Configuration Commands
"""
# Get NOS Version
SHOW_FIRMWARE_VERSION = (
"show-firmware-version xmlns:nc="
"'urn:brocade.com:mgmt:brocade-firmware-ext'"
)
GET_VCS_DETAILS = (
'get-vcs-details xmlns:nc="urn:brocade.com:mgmt:brocade-vcs"'
)
SHOW_VIRTUAL_FABRIC = (
'show-virtual-fabric xmlns:nc="urn:brocade.com:mgmt:brocade-vcs"'
)
GET_VIRTUAL_FABRIC_INFO = (
'interface xmlns:nc="urn:brocade.com:mgmt:brocade-firmware-ext"'
)
NOS_VERSION = "./*/{urn:brocade.com:mgmt:brocade-firmware-ext}os-version"
VFAB_ENABLE = "./*/*/*/{urn:brocade.com:mgmt:brocade-vcs}vfab-enable"
# Create VLAN (vlan_id)
CREATE_VLAN_INTERFACE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<interface-vlan xmlns="urn:brocade.com:mgmt:brocade-interface">
<interface>
<vlan>
<name>{vlan_id}</name>
</vlan>
</interface>
</interface-vlan>
</config>
"""
# Delete VLAN (vlan_id)
DELETE_VLAN_INTERFACE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<interface-vlan xmlns="urn:brocade.com:mgmt:brocade-interface">
<interface>
<vlan operation="delete">
<name>{vlan_id}</name>
</vlan>
</interface>
</interface-vlan>
</config>
"""
#
# AMPP Life-cycle Management Configuration Commands
#
# Create AMPP port-profile (port_profile_name)
CREATE_PORT_PROFILE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<name>{name}</name>
</port-profile>
</config>
"""
# Create VLAN sub-profile for port-profile (port_profile_name)
CREATE_VLAN_PROFILE_FOR_PORT_PROFILE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<name>{name}</name>
<vlan-profile/>
</port-profile>
</config>
"""
# Configure L2 mode for VLAN sub-profile (port_profile_name)
CONFIGURE_L2_MODE_FOR_VLAN_PROFILE_IN_DOMAIN = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<name>{name}</name>
<vlan-profile>
<switchport-basic>
<basic/>
</switchport-basic>
</vlan-profile>
</port-profile>
</config>
"""
# Configure L2 mode for VLAN sub-profile (port_profile_name)
CONFIGURE_L2_MODE_FOR_VLAN_PROFILE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<name>{name}</name>
<vlan-profile>
<switchport/>
</vlan-profile>
</port-profile>
</config>
"""
# Configure trunk mode for VLAN sub-profile (port_profile_name)
CONFIGURE_TRUNK_MODE_FOR_VLAN_PROFILE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<name>{name}</name>
<vlan-profile>
<switchport>
<mode>
<vlan-mode>trunk</vlan-mode>
</mode>
</switchport>
</vlan-profile>
</port-profile>
</config>
"""
# Configure allowed VLANs for VLAN sub-profile
# (port_profile_name, allowed_vlan, native_vlan)
CONFIGURE_ALLOWED_VLANS_FOR_VLAN_PROFILE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<name>{name}</name>
<vlan-profile>
<switchport>
<trunk>
<allowed>
<vlan>
<add>{vlan_id}</add>
</vlan>
</allowed>
</trunk>
</switchport>
</vlan-profile>
</port-profile>
</config>
"""
# Delete port-profile (port_profile_name)
DELETE_PORT_PROFILE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile
xmlns="urn:brocade.com:mgmt:brocade-port-profile" operation="delete">
<name>{name}</name>
</port-profile>
</config>
"""
# Activate port-profile (port_profile_name)
ACTIVATE_PORT_PROFILE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile-global xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<port-profile>
<name>{name}</name>
<activate/>
</port-profile>
</port-profile-global>
</config>
"""
# Deactivate port-profile (port_profile_name)
DEACTIVATE_PORT_PROFILE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile-global xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<port-profile>
<name>{name}</name>
<activate
xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete" />
</port-profile>
</port-profile-global>
</config>
"""
# Associate MAC address to port-profile (port_profile_name, mac_address)
ASSOCIATE_MAC_TO_PORT_PROFILE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile-global xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<port-profile>
<name>{name}</name>
<static>
<mac-address>{mac_address}</mac-address>
</static>
</port-profile>
</port-profile-global>
</config>
"""
# Dissociate MAC address from port-profile (port_profile_name, mac_address)
DISSOCIATE_MAC_FROM_PORT_PROFILE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile-global xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<port-profile>
<name>{name}</name>
<static
xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete">
<mac-address>{mac_address}</mac-address>
</static>
</port-profile>
</port-profile-global>
</config>
"""
# port-profile domain management commands
REMOVE_PORTPROFILE_FROM_DOMAIN = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile-domain xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<port-profile-domain-name>{domain_name}</port-profile-domain-name>
<profile operation="delete">
<profile-name>{name}</profile-name>
</profile>
</port-profile-domain>
</config>
"""
# put port profile in default domain
CONFIGURE_PORTPROFILE_IN_DOMAIN = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile-domain xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<port-profile-domain-name>{domain_name}</port-profile-domain-name>
<profile>
<profile-name>{name}</profile-name>
</profile>
</port-profile-domain>
</config>
"""
#
# L3 Life-cycle Management Configuration Commands
#
# Create SVI and assign ippaddres (rbridge_id,vlan_id,ip_address)
CONFIGURE_SVI_WITH_IP_ADDRESS = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
<rbridge-id>{rbridge_id}</rbridge-id>
<interface xmlns="urn:brocade.com:mgmt:brocade-interface">
<ve>
<name>{vlan_id}</name>
<ip xmlns="urn:brocade.com:mgmt:brocade-ip-config">
<ip-config>
<address>
<address>{ip_address}</address>
</address>
</ip-config>
</ip>
</ve>
</interface>
</rbridge-id>
</config>
"""
# delete SVI (rbridge_id,vlan_id)
DELETE_SVI = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
<rbridge-id>{rbridge_id}</rbridge-id>
<interface xmlns="urn:brocade.com:mgmt:brocade-interface">
<ve operation="delete">
<name>{vlan_id}</name>
</ve>
</interface>
</rbridge-id>
</config>
"""
# Activate SVI (rbridge_id,vlan_id)
ACTIVATE_SVI = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
<rbridge-id>{rbridge_id}</rbridge-id>
<interface xmlns="urn:brocade.com:mgmt:brocade-interface">
<ve>
<name>{vlan_id}</name>
<shutdown xmlns="urn:brocade.com:mgmt:brocade-ip-config"
xc:operation="delete"></shutdown>
</ve>
</interface>
</rbridge-id>
</config>
"""
# Remove ipaddress from SVI (rbridge_id,vlan_id)
DECONFIGURE_IP_FROM_SVI = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
<rbridge-id>{rbridge_id}</rbridge-id>
<interface xmlns="urn:brocade.com:mgmt:brocade-interface">
<ve>
<name>{vlan_id}</name>
<ip xmlns="urn:brocade.com:mgmt:brocade-ip-config">
<ip-config>
<address xc:operation="delete">
<address>{gw_ip}</address>
</address>
</ip-config>
</ip>
</ve>
</interface>
</rbridge-id>
</config>
"""
# create vrf (rbridge_id,vrf_name)
CREATE_VRF = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
<rbridge-id>{rbridge_id}</rbridge-id>
<vrf xmlns="urn:brocade.com:mgmt:brocade-vrf">
<vrf-name>{vrf_name}</vrf-name>
</vrf>
</rbridge-id>
</config>
"""
# delete vrf (rbridge_id,vrf_name)
DELETE_VRF = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
<rbridge-id>{rbridge_id}</rbridge-id>
<vrf xmlns="urn:brocade.com:mgmt:brocade-vrf"
xc:operation="delete">
<vrf-name>{vrf_name}</vrf-name>
</vrf>
</rbridge-id>
</config>
"""
# configure route distinguisher for vrf (rbridge_id,vrf_name, rd)
CONFIGURE_RD_FOR_VRF = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
<rbridge-id>{rbridge_id}</rbridge-id>
<vrf xmlns="urn:brocade.com:mgmt:brocade-vrf">
<vrf-name>{vrf_name}</vrf-name>
<route-distiniguisher>{rd}</route-distiniguisher>
</vrf>
</rbridge-id>
</config>
"""
# configure address-family for vrf (rbridge_id,vrf_name)
ADD_ADDRESS_FAMILY_FOR_VRF_V1 = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
<rbridge-id>{rbridge_id}</rbridge-id>
<vrf xmlns="urn:brocade.com:mgmt:brocade-vrf">
<vrf-name>{vrf_name}</vrf-name>
<address-family xmlns="urn:brocade.com:mgmt:brocade-vrf">
<ipv4>
<max-route>1200</max-route>
</ipv4>
</address-family>
</vrf>
</rbridge-id>
</config>
"""
# configure address-family for vrf (rbridge_id,vrf_name)
ADD_ADDRESS_FAMILY_FOR_VRF = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
<rbridge-id>{rbridge_id}</rbridge-id>
<vrf xmlns="urn:brocade.com:mgmt:brocade-vrf">
<vrf-name>{vrf_name}</vrf-name>
<address-family xmlns="urn:brocade.com:mgmt:brocade-vrf">
<ip>
<unicast/>
</ip>
</address-family>
</vrf>
</rbridge-id>
</config>
"""
# Bind vrf to SVI (rbridge_id,vlan_idi, vrf)
ADD_VRF_TO_SVI = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
<rbridge-id>{rbridge_id}</rbridge-id>
<interface xmlns="urn:brocade.com:mgmt:brocade-interface">
<ve>
<name>{vlan_id}</name>
<vrf xmlns="urn:brocade.com:mgmt:brocade-ip-config">
<forwarding>{vrf_name}</forwarding>
</vrf>
</ve>
</interface>
</rbridge-id>
</config>
"""
# unbind vrf from SVI (rbridge_id,vlan_idi, vrf)
DELETE_VRF_FROM_SVI = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
<rbridge-id>{rbridge_id}</rbridge-id>
<interface xmlns="urn:brocade.com:mgmt:brocade-interface">
<ve>
<name>{vlan_id}</name>
<vrf xmlns="urn:brocade.com:mgmt:brocade-ip-config"
operation="delete">
<forwarding>{vrf_name}</forwarding>
</vrf>
</ve>
</interface>
</rbridge-id>
</config>
"""
#
# Constants
#
# Port profile naming convention for Neutron networks
OS_PORT_PROFILE_NAME = "openstack-profile-{id}"
OS_VRF_NAME = "osv-{id}"
# Port profile filter expressions
PORT_PROFILE_XPATH_FILTER = "/port-profile"
PORT_PROFILE_NAME_XPATH_FILTER = "/port-profile[name='{name}']"

View File

@ -1,485 +0,0 @@
# Copyright 2014 Brocade Communications System, Inc.
# 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.
"""Brocade NOS Driver implements NETCONF over SSHv2 for
Neutron network life-cycle management.
"""
from ncclient import manager
from oslo_log import log as logging
from oslo_utils import excutils
from xml.etree import ElementTree
from neutron.i18n import _LE
from neutron.plugins.ml2.drivers.brocade.nos import nctemplates as template
LOG = logging.getLogger(__name__)
SSH_PORT = 22
def nos_unknown_host_cb(host, fingerprint):
"""An unknown host callback.
Returns `True` if it finds the key acceptable,
and `False` if not. This default callback for NOS always returns 'True'
(i.e. trusts all hosts for now).
"""
return True
class NOSdriver(object):
"""NOS NETCONF interface driver for Neutron network.
Handles life-cycle management of Neutron network (leverages AMPP on NOS)
"""
def __init__(self):
self.mgr = None
self._virtual_fabric_enabled = False
self._pp_domains_supported = False
def set_features_enabled(self, pp_domains_supported,
virtual_fabric_enabled):
"""Set features in the driver based on what was detected by the MD."""
self._pp_domains_supported = pp_domains_supported
self._virtual_fabric_enabled = virtual_fabric_enabled
def get_features_enabled(self):
"""Respond to status of features enabled."""
return self._pp_domains_supported, self._virtual_fabric_enabled
def connect(self, host, username, password):
"""Connect via SSH and initialize the NETCONF session."""
# Use the persisted NETCONF connection
if self.mgr and self.mgr.connected:
return self.mgr
# check if someone forgot to edit the conf file with real values
if host == '':
raise Exception(_("Brocade Switch IP address is not set, "
"check config ml2_conf_brocade.ini file"))
# Open new NETCONF connection
try:
self.mgr = manager.connect(host=host, port=SSH_PORT,
username=username, password=password,
unknown_host_cb=nos_unknown_host_cb)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("Connect failed to switch"))
LOG.debug("Connect success to host %(host)s:%(ssh_port)d",
dict(host=host, ssh_port=SSH_PORT))
return self.mgr
def close_session(self):
"""Close NETCONF session."""
if self.mgr:
self.mgr.close_session()
self.mgr = None
def get_nos_version(self, host, username, password):
"""Show version of NOS."""
try:
mgr = self.connect(host, username, password)
return self.nos_version_request(mgr)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error"))
self.close_session()
def is_virtual_fabric_enabled(self, host, username, password):
"""Show version of NOS."""
try:
mgr = self.connect(host, username, password)
return (self.virtual_fabric_info(mgr) == "enabled")
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error"))
self.close_session()
def create_network(self, host, username, password, net_id):
"""Creates a new virtual network."""
domain_name = "default"
name = template.OS_PORT_PROFILE_NAME.format(id=net_id)
try:
mgr = self.connect(host, username, password)
self.create_vlan_interface(mgr, net_id)
self.create_port_profile(mgr, name)
if self._pp_domains_supported and self._virtual_fabric_enabled:
self.configure_port_profile_in_domain(mgr, domain_name, name)
self.create_vlan_profile_for_port_profile(mgr, name)
if self._pp_domains_supported:
self.configure_l2_mode_for_vlan_profile_with_domains(mgr, name)
else:
self.configure_l2_mode_for_vlan_profile(mgr, name)
self.configure_trunk_mode_for_vlan_profile(mgr, name)
self.configure_allowed_vlans_for_vlan_profile(mgr, name, net_id)
self.activate_port_profile(mgr, name)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error"))
self.close_session()
def delete_network(self, host, username, password, net_id):
"""Deletes a virtual network."""
domain_name = "default"
name = template.OS_PORT_PROFILE_NAME.format(id=net_id)
try:
mgr = self.connect(host, username, password)
if self._pp_domains_supported and self._virtual_fabric_enabled:
self.remove_port_profile_from_domain(mgr, domain_name, name)
self.deactivate_port_profile(mgr, name)
self.delete_port_profile(mgr, name)
self.delete_vlan_interface(mgr, net_id)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error"))
self.close_session()
def associate_mac_to_network(self, host, username, password,
net_id, mac):
"""Associates a MAC address to virtual network."""
name = template.OS_PORT_PROFILE_NAME.format(id=net_id)
try:
mgr = self.connect(host, username, password)
self.associate_mac_to_port_profile(mgr, name, mac)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error"))
self.close_session()
def dissociate_mac_from_network(self, host, username, password,
net_id, mac):
"""Dissociates a MAC address from virtual network."""
name = template.OS_PORT_PROFILE_NAME.format(id=net_id)
try:
mgr = self.connect(host, username, password)
self.dissociate_mac_from_port_profile(mgr, name, mac)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error"))
self.close_session()
def create_vlan_interface(self, mgr, vlan_id):
"""Configures a VLAN interface."""
confstr = template.CREATE_VLAN_INTERFACE.format(vlan_id=vlan_id)
mgr.edit_config(target='running', config=confstr)
def delete_vlan_interface(self, mgr, vlan_id):
"""Deletes a VLAN interface."""
confstr = template.DELETE_VLAN_INTERFACE.format(vlan_id=vlan_id)
mgr.edit_config(target='running', config=confstr)
def get_port_profiles(self, mgr):
"""Retrieves all port profiles."""
filterstr = template.PORT_PROFILE_XPATH_FILTER
response = mgr.get_config(source='running',
filter=('xpath', filterstr)).data_xml
return response
def get_port_profile(self, mgr, name):
"""Retrieves a port profile."""
filterstr = template.PORT_PROFILE_NAME_XPATH_FILTER.format(name=name)
response = mgr.get_config(source='running',
filter=('xpath', filterstr)).data_xml
return response
def create_port_profile(self, mgr, name):
"""Creates a port profile."""
confstr = template.CREATE_PORT_PROFILE.format(name=name)
mgr.edit_config(target='running', config=confstr)
def delete_port_profile(self, mgr, name):
"""Deletes a port profile."""
confstr = template.DELETE_PORT_PROFILE.format(name=name)
mgr.edit_config(target='running', config=confstr)
def activate_port_profile(self, mgr, name):
"""Activates a port profile."""
confstr = template.ACTIVATE_PORT_PROFILE.format(name=name)
mgr.edit_config(target='running', config=confstr)
def deactivate_port_profile(self, mgr, name):
"""Deactivates a port profile."""
confstr = template.DEACTIVATE_PORT_PROFILE.format(name=name)
mgr.edit_config(target='running', config=confstr)
def associate_mac_to_port_profile(self, mgr, name, mac_address):
"""Associates a MAC address to a port profile."""
confstr = template.ASSOCIATE_MAC_TO_PORT_PROFILE.format(
name=name, mac_address=mac_address)
mgr.edit_config(target='running', config=confstr)
def dissociate_mac_from_port_profile(self, mgr, name, mac_address):
"""Dissociates a MAC address from a port profile."""
confstr = template.DISSOCIATE_MAC_FROM_PORT_PROFILE.format(
name=name, mac_address=mac_address)
mgr.edit_config(target='running', config=confstr)
def create_vlan_profile_for_port_profile(self, mgr, name):
"""Creates VLAN sub-profile for port profile."""
confstr = template.CREATE_VLAN_PROFILE_FOR_PORT_PROFILE.format(
name=name)
mgr.edit_config(target='running', config=confstr)
def configure_l2_mode_for_vlan_profile(self, mgr, name):
"""Configures L2 mode for VLAN sub-profile."""
confstr = template.CONFIGURE_L2_MODE_FOR_VLAN_PROFILE.format(
name=name)
mgr.edit_config(target='running', config=confstr)
def configure_trunk_mode_for_vlan_profile(self, mgr, name):
"""Configures trunk mode for VLAN sub-profile."""
confstr = template.CONFIGURE_TRUNK_MODE_FOR_VLAN_PROFILE.format(
name=name)
mgr.edit_config(target='running', config=confstr)
def configure_allowed_vlans_for_vlan_profile(self, mgr, name, vlan_id):
"""Configures allowed VLANs for VLAN sub-profile."""
confstr = template.CONFIGURE_ALLOWED_VLANS_FOR_VLAN_PROFILE.format(
name=name, vlan_id=vlan_id)
mgr.edit_config(target='running', config=confstr)
def remove_port_profile_from_domain(self, mgr, domain_name, name):
"""Remove port-profile from default domain."""
confstr = template.REMOVE_PORTPROFILE_FROM_DOMAIN.format(
domain_name=domain_name, name=name)
mgr.edit_config(target='running', config=confstr)
def configure_port_profile_in_domain(self, mgr, domain_name, name):
"""put port-profile in default domain."""
confstr = template.CONFIGURE_PORTPROFILE_IN_DOMAIN.format(
domain_name=domain_name, name=name)
mgr.edit_config(target='running', config=confstr)
def configure_l2_mode_for_vlan_profile_with_domains(self, mgr, name):
"""Configures L2 mode for VLAN sub-profile."""
confstr = template.CONFIGURE_L2_MODE_FOR_VLAN_PROFILE_IN_DOMAIN.format(
name=name)
mgr.edit_config(target='running', config=confstr)
def nos_version_request(self, mgr):
"""Get firmware information using NETCONF rpc."""
reply = mgr.dispatch(template.SHOW_FIRMWARE_VERSION, None, None)
et = ElementTree.fromstring(str(reply))
return et.find(template.NOS_VERSION).text
def virtual_fabric_info(self, mgr):
"""Get virtual fabric info using NETCONF get-config."""
response = mgr.get_config('running',
filter=("xpath", "/vcs/virtual-fabric"))
et = ElementTree.fromstring(str(response))
vfab_enable = et.find(template.VFAB_ENABLE)
if vfab_enable is not None:
return "enabled"
return "disabled"
def create_svi(self, host, username, password,
rbridge_id, vlan_id, ip_address, router_id):
"""create svi on configured rbridge-id."""
try:
mgr = self.connect(host, username, password)
self.bind_vrf_to_svi(host, username, password,
rbridge_id, vlan_id, router_id)
self.configure_svi_with_ip_address(mgr,
rbridge_id, vlan_id, ip_address)
self.activate_svi(mgr, rbridge_id, vlan_id)
except Exception as ex:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error: %s"), ex)
self.close_session()
def delete_svi(self, host, username, password,
rbridge_id, vlan_id, gw_ip, router_id):
"""delete svi from configured rbridge-id."""
try:
mgr = self.connect(host, username, password)
self.remove_svi(mgr, rbridge_id, vlan_id)
except Exception as ex:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error: %s"), ex)
self.close_session()
def create_router(self, host, username, password, rbridge_id, router_id):
"""create vrf and associate vrf."""
router_id = router_id[0:11]
vrf_name = template.OS_VRF_NAME.format(id=router_id)
rd = router_id + ":" + router_id
try:
mgr = self.connect(host, username, password)
self.create_vrf(mgr, rbridge_id, vrf_name)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error"))
self.close_session()
try:
# For Nos5.0.0
self.configure_rd_for_vrf(mgr, rbridge_id, vrf_name, rd)
self.configure_address_family_for_vrf(mgr, rbridge_id, vrf_name)
except Exception:
with excutils.save_and_reraise_exception() as ctxt:
try:
# This is done because on 4.0.0 rd doesnt accept alpha
# character nor hyphen
rd = "".join(i for i in router_id if i in "0123456789")
rd = rd[:4] + ":" + rd[:4]
self.configure_rd_for_vrf(mgr, rbridge_id, vrf_name, rd)
self.configure_address_family_for_vrf_v1(mgr,
rbridge_id,
vrf_name)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error"))
self.close_session()
ctxt.reraise = False
def delete_router(self, host, username, password, rbridge_id, router_id):
"""delete router and associated vrf."""
router_id = router_id[0:11]
vrf_name = template.OS_VRF_NAME.format(id=router_id)
try:
mgr = self.connect(host, username, password)
self.delete_vrf(mgr, rbridge_id, vrf_name)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error"))
self.close_session()
def bind_vrf_to_svi(self, host, username, password, rbridge_id,
vlan_id, router_id):
"""binds vrf to a svi."""
router_id = router_id[0:11]
vrf_name = template.OS_VRF_NAME.format(id=router_id)
try:
mgr = self.connect(host, username, password)
self.add_vrf_to_svi(mgr, rbridge_id, vlan_id, vrf_name)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error"))
self.close_session()
def unbind_vrf_to_svi(self, host, username, password, rbridge_id,
vlan_id, router_id):
"""unbind vrf from the svi."""
router_id = router_id[0:11]
vrf_name = template.OS_VRF_NAME.format(id=router_id)
try:
mgr = self.connect(host, username, password)
self.delete_vrf_from_svi(mgr, rbridge_id, vlan_id, vrf_name)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("NETCONF error"))
self.close_session()
def create_vrf(self, mgr, rbridge_id, vrf_name):
"""create vrf on rbridge."""
confstr = template.CREATE_VRF.format(rbridge_id=rbridge_id,
vrf_name=vrf_name)
mgr.edit_config(target='running', config=confstr)
def delete_vrf(self, mgr, rbridge_id, vrf_name):
"""delete vrf on rbridge."""
confstr = template.DELETE_VRF.format(rbridge_id=rbridge_id,
vrf_name=vrf_name)
mgr.edit_config(target='running', config=confstr)
def configure_rd_for_vrf(self, mgr, rbridge_id, vrf_name, rd):
"""configure rd on vrf on rbridge."""
confstr = template.CONFIGURE_RD_FOR_VRF.format(rbridge_id=rbridge_id,
vrf_name=vrf_name,
rd=rd)
mgr.edit_config(target='running', config=confstr)
def configure_address_family_for_vrf_v1(self, mgr, rbridge_id, vrf_name):
"""configure ipv4 address family to vrf on rbridge."""
confstr = template.ADD_ADDRESS_FAMILY_FOR_VRF_V1.format(
rbridge_id=rbridge_id,
vrf_name=vrf_name)
mgr.edit_config(target='running', config=confstr)
def configure_address_family_for_vrf(self, mgr, rbridge_id, vrf_name):
"""configure ipv4 address family to vrf on rbridge."""
confstr = template.ADD_ADDRESS_FAMILY_FOR_VRF.format(
rbridge_id=rbridge_id, vrf_name=vrf_name)
mgr.edit_config(target='running', config=confstr)
def configure_svi_with_ip_address(self, mgr, rbridge_id,
vlan_id, ip_address):
"""configure SVI with ip address on rbridge."""
confstr = template.CONFIGURE_SVI_WITH_IP_ADDRESS.format(
rbridge_id=rbridge_id,
vlan_id=vlan_id,
ip_address=ip_address)
mgr.edit_config(target='running', config=confstr)
def activate_svi(self, mgr, rbridge_id, vlan_id):
"""activate the svi on the rbridge."""
confstr = template.ACTIVATE_SVI.format(rbridge_id=rbridge_id,
vlan_id=vlan_id)
mgr.edit_config(target='running', config=confstr)
def add_vrf_to_svi(self, mgr, rbridge_id, vlan_id, vrf_name):
"""add vrf to svi on rbridge."""
confstr = template.ADD_VRF_TO_SVI.format(rbridge_id=rbridge_id,
vlan_id=vlan_id,
vrf_name=vrf_name)
mgr.edit_config(target='running', config=confstr)
def delete_vrf_from_svi(self, mgr, rbridge_id, vlan_id, vrf_name):
"""delete vrf from svi on rbridge."""
confstr = template.DELETE_VRF_FROM_SVI.format(rbridge_id=rbridge_id,
vlan_id=vlan_id,
vrf_name=vrf_name)
mgr.edit_config(target='running', config=confstr)
def remove_svi(self, mgr, rbridge_id, vlan_id):
"""delete vrf from svi on rbridge."""
confstr = template.DELETE_SVI.format(rbridge_id=rbridge_id,
vlan_id=vlan_id)
mgr.edit_config(target='running', config=confstr)

View File

@ -0,0 +1 @@
networking-brocade

View File

@ -18,20 +18,6 @@
"""Implentation of Brocade SVI service Plugin."""
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
from neutron.common import constants as l3_constants
from neutron.i18n import _LE, _LI
from neutron.plugins.ml2 import db
from neutron.plugins.ml2.drivers.brocade.db import models as brocade_db
from neutron.plugins.ml2.drivers.brocade.nos import nosdriver as driver
from neutron.services.l3_router import l3_router_plugin as router
DEVICE_OWNER_ROUTER_INTF = l3_constants.DEVICE_OWNER_ROUTER_INTF
DEVICE_OWNER_ROUTER_GW = l3_constants.DEVICE_OWNER_ROUTER_GW
DEVICE_OWNER_FLOATINGIP = l3_constants.DEVICE_OWNER_FLOATINGIP
ML2_BROCADE = [cfg.StrOpt('address', default='',
help=_('The address of the host to SSH to')),
@ -44,194 +30,3 @@ ML2_BROCADE = [cfg.StrOpt('address', default='',
]
cfg.CONF.register_opts(ML2_BROCADE, "ml2_brocade")
LOG = logging.getLogger(__name__)
class BrocadeSVIPlugin(router.L3RouterPlugin):
"""Brocade SVI service Plugin."""
def __init__(self):
"""Initialize Brocade Plugin
Specify switch address and db configuration.
"""
super(BrocadeSVIPlugin, self).__init__()
self._switch = None
self._driver = None
self.brocade_init()
def brocade_init(self):
"""Brocade specific initialization."""
LOG.debug("brocadeSVIPlugin::brocade_init()")
self._switch = {'address': cfg.CONF.ml2_brocade.address,
'username': cfg.CONF.ml2_brocade.username,
'password': cfg.CONF.ml2_brocade.password,
'rbridge_id': cfg.CONF.ml2_brocade.rbridge_id
}
self._driver = driver.NOSdriver()
LOG.info(_LI("rbridge id %s"), self._switch['rbridge_id'])
def create_router(self, context, router):
"""Creates a vrf on NOS device."""
LOG.debug("BrocadeSVIPlugin.create_router called: ")
with context.session.begin(subtransactions=True):
new_router = super(BrocadeSVIPlugin, self).create_router(context,
router)
# Router on VDX
try:
switch = self._switch
self._driver.create_router(switch['address'],
switch['username'],
switch['password'],
switch['rbridge_id'],
str(new_router['id']))
except Exception:
with excutils.save_and_reraise_exception():
with context.session.begin(subtransactions=True):
super(BrocadeSVIPlugin, self).delete_router(
context,
new_router['id'])
LOG.debug("BrocadeSVIPlugin.create_router: "
"router created on VDX switch")
return new_router
def delete_router(self, context, router_id):
"""Delete a vrf on NOS device."""
router = super(BrocadeSVIPlugin, self).get_router(context, router_id)
super(BrocadeSVIPlugin, self).delete_router(context, router_id)
switch = self._switch
self._driver.delete_router(switch['address'],
switch['username'],
switch['password'],
switch['rbridge_id'],
str(router['id']))
def add_router_interface(self, context, router_id, interface_info):
"""creates svi on NOS device and assigns ip address to SVI."""
LOG.debug("BrocadeSVIPlugin.add_router_interface on VDX: "
"router_id=%(router_id)s "
"interface_info=%(interface_info)r",
{'router_id': router_id, 'interface_info': interface_info})
with context.session.begin(subtransactions=True):
info = super(BrocadeSVIPlugin, self).add_router_interface(
context, router_id, interface_info)
port = db.get_port(context.session, info["port_id"])
# shutting down neutron port to allow NOS to do Arp/Routing
port['admin_state_up'] = False
port['port'] = port
self._core_plugin.update_port(context, info["port_id"], port)
interface_info = info
subnet = self._core_plugin._get_subnet(context,
interface_info["subnet_id"])
cidr = subnet["cidr"]
net_addr, net_len = self.net_addr(cidr)
gateway_ip = subnet["gateway_ip"]
network_id = subnet['network_id']
bnet = brocade_db.get_network(context, network_id)
vlan_id = bnet['vlan']
gateway_ip_cidr = gateway_ip + '/' + str(net_len)
LOG.debug("Allocated cidr %(cidr)s from the pool, "
"network_id %(net_id)s "
"bnet %(bnet)s "
"vlan %(vlan_id)d ", {'cidr': gateway_ip_cidr,
'net_id': network_id,
'bnet': bnet,
'vlan_id': int(vlan_id)})
port_filters = {'network_id': [network_id],
'device_owner': [DEVICE_OWNER_ROUTER_INTF]}
port_count = self._core_plugin.get_ports_count(context,
port_filters)
LOG.info(_LI("BrocadeSVIPlugin.add_router_interface ports_count "
"%d"),
port_count)
# port count is checked against 2 since the current port is already
# added to db
if port_count == 2:
# This subnet is already part of some router
# (this is not supported in this version of brocade svi plugin)
msg = _("BrocadeSVIPlugin: adding redundant router interface "
"is not supported")
LOG.error(msg)
raise Exception(msg)
try:
switch = self._switch
self._driver.create_svi(switch['address'],
switch['username'],
switch['password'],
switch['rbridge_id'],
vlan_id,
gateway_ip_cidr,
str(router_id))
except Exception:
LOG.error(_LE("Failed to create Brocade resources to add router "
"interface. info=%(info)s, router_id=%(router_id)s"),
{"info": info, "router_id": router_id})
with excutils.save_and_reraise_exception():
with context.session.begin(subtransactions=True):
self.remove_router_interface(context, router_id,
interface_info)
return info
def remove_router_interface(self, context, router_id, interface_info):
"""Deletes svi from NOS device."""
LOG.debug("BrocadeSVIPlugin.remove_router_interface called: "
"router_id=%(router_id)s "
"interface_info=%(interface_info)r",
{'router_id': router_id, 'interface_info': interface_info})
with context.session.begin(subtransactions=True):
info = super(BrocadeSVIPlugin, self).remove_router_interface(
context, router_id, interface_info)
try:
subnet = self._core_plugin._get_subnet(context,
info['subnet_id'])
cidr = subnet['cidr']
net_addr, net_len = self.net_addr(cidr)
gateway_ip = subnet['gateway_ip']
network_id = subnet['network_id']
bnet = brocade_db.get_network(context, network_id)
vlan_id = bnet['vlan']
gateway_ip_cidr = gateway_ip + '/' + str(net_len)
LOG.debug("remove_router_interface removed cidr %(cidr)s"
" from the pool,"
" network_id %(net_id)s bnet %(bnet)s"
" vlan %(vlan_id)d",
{'cidr': gateway_ip_cidr,
'net_id': network_id,
'bnet': bnet,
'vlan_id': int(vlan_id)})
switch = self._switch
self._driver.delete_svi(switch['address'],
switch['username'],
switch['password'],
switch['rbridge_id'],
vlan_id,
gateway_ip_cidr,
str(router_id))
except Exception:
with excutils.save_and_reraise_exception():
LOG.error(_LE("Fail remove of interface from brocade "
"router interface. info=%(info)s, "
"router_id=%(router_id)s"),
{"info": info, "router_id": router_id})
return True
@staticmethod
def net_addr(addr):
"""Get network address prefix and length from a given address."""
if addr is None:
return None, None
nw_addr, nw_len = addr.split('/')
nw_len = int(nw_len)
return nw_addr, nw_len

View File

@ -1,57 +0,0 @@
# Copyright (c) 2014 OpenStack Foundation
#
# 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.
#
#
import mock
from oslo_config import cfg
from oslo_context import context as oslo_context
from oslo_log import log as logging
from oslo_utils import importutils
from neutron.db import api as db
from neutron.tests.unit import test_l3_plugin
LOG = logging.getLogger(__name__)
L3_SVC_PLUGIN = ('neutron.services.l3_router.'
'brocade.l3_router_plugin.BrocadeSVIPlugin')
class BrocadeSVIPlugin_TestCases(test_l3_plugin.TestL3NatBasePlugin):
def setUp(self):
def mocked_brocade_init(self):
LOG.debug("brocadeSVIPlugin::mocked_brocade_init()")
self._switch = {'address': cfg.CONF.ml2_brocade.address,
'username': cfg.CONF.ml2_brocade.username,
'password': cfg.CONF.ml2_brocade.password,
'rbridge_id': cfg.CONF.ml2_brocade.rbridge_id
}
LOG.info(_("rbridge id %s"), self._switch['rbridge_id'])
self._driver = mock.MagicMock()
self.l3_plugin = importutils.import_object(L3_SVC_PLUGIN)
with mock.patch.object(self.l3_plugin,
'brocade_init', new=mocked_brocade_init):
super(BrocadeSVIPlugin_TestCases, self).setUp()
self.context = oslo_context.get_admin_context()
self.context.session = db.get_session()
class TestBrocadeSVINatBase(test_l3_plugin.L3NatExtensionTestCase,
BrocadeSVIPlugin_TestCases):
pass

View File

@ -1,116 +0,0 @@
# Copyright (c) 2013 OpenStack Foundation
#
# 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.
import mock
from oslo_log import log as logging
from oslo_utils import importutils
from neutron.plugins.ml2 import config as ml2_config
from neutron.plugins.ml2.drivers.brocade import (mechanism_brocade
as brocademechanism)
from neutron.tests.unit.ml2 import test_ml2_plugin
LOG = logging.getLogger(__name__)
MECHANISM_NAME = ('neutron.plugins.ml2.'
'drivers.brocade.mechanism_brocade.BrocadeMechanism')
class TestBrocadeMechDriverV2(test_ml2_plugin.Ml2PluginV2TestCase):
"""Test Brocade VCS/VDX mechanism driver.
"""
_mechanism_name = MECHANISM_NAME
def setUp(self):
_mechanism_name = MECHANISM_NAME
ml2_opts = {
'mechanism_drivers': ['brocade'],
'tenant_network_types': ['vlan']}
for opt, val in ml2_opts.items():
ml2_config.cfg.CONF.set_override(opt, val, 'ml2')
def mocked_brocade_init(self):
self._driver = mock.MagicMock()
with mock.patch.object(brocademechanism.BrocadeMechanism,
'brocade_init', new=mocked_brocade_init):
super(TestBrocadeMechDriverV2, self).setUp()
self.mechanism_driver = importutils.import_object(_mechanism_name)
class TestBrocadeMechDriverNetworksV2(test_ml2_plugin.TestMl2NetworksV2,
TestBrocadeMechDriverV2):
pass
class TestBrocadeMechDriverPortsV2(test_ml2_plugin.TestMl2PortsV2,
TestBrocadeMechDriverV2):
pass
class TestBrocadeMechDriverSubnetsV2(test_ml2_plugin.TestMl2SubnetsV2,
TestBrocadeMechDriverV2):
pass
class TestBrocadeMechDriverFeaturesEnabledTestCase(TestBrocadeMechDriverV2):
def setUp(self):
super(TestBrocadeMechDriverFeaturesEnabledTestCase, self).setUp()
def test_version_features(self):
vf = True
# Test for NOS version 4.0.3
self.mechanism_driver.set_features_enabled("4.0.3", vf)
# Verify
pp_domain_support, virtual_fabric_enabled = (
self.mechanism_driver.get_features_enabled()
)
self.assertFalse(pp_domain_support)
self.assertTrue(virtual_fabric_enabled)
# Test for NOS version 4.1.0
vf = True
self.mechanism_driver.set_features_enabled("4.1.0", vf)
# Verify
pp_domain_support, virtual_fabric_enabled = (
self.mechanism_driver.get_features_enabled()
)
self.assertTrue(pp_domain_support)
self.assertTrue(virtual_fabric_enabled)
# Test for NOS version 4.1.3
vf = False
self.mechanism_driver.set_features_enabled("4.1.3", vf)
# Verify
pp_domain_support, virtual_fabric_enabled = (
self.mechanism_driver.get_features_enabled()
)
self.assertTrue(pp_domain_support)
self.assertFalse(virtual_fabric_enabled)
# Test for NOS version 5.0.0
vf = True
self.mechanism_driver.set_features_enabled("5.0.0", vf)
# Verify
pp_domain_support, virtual_fabric_enabled = (
self.mechanism_driver.get_features_enabled()
)
self.assertTrue(pp_domain_support)
self.assertTrue(virtual_fabric_enabled)

View File

@ -174,7 +174,7 @@ neutron.ml2.mechanism_drivers =
bigswitch = neutron.plugins.ml2.drivers.mech_bigswitch.driver:BigSwitchMechanismDriver
ofagent = neutron.plugins.ml2.drivers.ofagent.driver:OfagentMechanismDriver
mlnx = neutron.plugins.ml2.drivers.mlnx.mech_mlnx:MlnxMechanismDriver
brocade = neutron.plugins.ml2.drivers.brocade.mechanism_brocade:BrocadeMechanism
brocade = networking_brocade.vdx.ml2driver.mechanism_brocade:BrocadeMechanism
fslsdn = neutron.plugins.ml2.drivers.freescale.mechanism_fslsdn:FslsdnMechanismDriver
sriovnicswitch = neutron.plugins.ml2.drivers.mech_sriov.mech_driver:SriovNicSwitchMechanismDriver
nuage = neutron.plugins.ml2.drivers.mech_nuage.driver:NuageMechanismDriver