Merge "Brocade vendor code decomposition from neutron repo."
This commit is contained in:
@@ -402,7 +402,7 @@ The following chart captures the following aspects:
|
|||||||
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
|
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
|
||||||
| networking-bigswitch_ | ml2,core,l3 | no | yes | [C] | Kilo |
|
| 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] | |
|
| networking-cisco_ | core,ml2,l3,fw,vpn | yes | yes | [B] | |
|
||||||
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
|
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
|
||||||
@@ -452,6 +452,11 @@ Big Switch Networks
|
|||||||
|
|
||||||
.. _networking-brocade:
|
.. _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:
|
.. _networking-cisco:
|
||||||
|
|
||||||
Cisco
|
Cisco
|
||||||
|
@@ -1,10 +1,16 @@
|
|||||||
Brocade ML2 Mechanism driver from ML2 plugin
|
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:
|
* up-to-date version of these instructions are located at:
|
||||||
http://50.56.236.34/docs/brocade-ml2-mechanism.txt
|
http://50.56.236.34/docs/brocade-ml2-mechanism.txt
|
||||||
|
|
||||||
* N.B.: Please see Prerequisites section regarding ncclient (netconf client library)
|
* N.B.: Please see Prerequisites section regarding ncclient (netconf client library)
|
||||||
|
|
||||||
* Supports VCS (Virtual Cluster of Switches)
|
* Supports VCS (Virtual Cluster of Switches)
|
||||||
|
|
||||||
* Issues/Questions/Bugs: sharis@brocade.com
|
* Issues/Questions/Bugs: sharis@brocade.com
|
||||||
|
|
||||||
|
|
||||||
|
@@ -17,17 +17,6 @@
|
|||||||
"""Implentation of Brocade ML2 Mechanism driver for ML2 Plugin."""
|
"""Implentation of Brocade ML2 Mechanism driver for ML2 Plugin."""
|
||||||
|
|
||||||
from oslo_config import cfg
|
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='',
|
ML2_BROCADE = [cfg.StrOpt('address', default='',
|
||||||
help=_('The address of the host to SSH to')),
|
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")
|
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
|
|
||||||
|
@@ -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}']"
|
|
@@ -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)
|
|
1
neutron/plugins/ml2/drivers/brocade/requirements.txt
Normal file
1
neutron/plugins/ml2/drivers/brocade/requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
networking-brocade
|
@@ -18,20 +18,6 @@
|
|||||||
"""Implentation of Brocade SVI service Plugin."""
|
"""Implentation of Brocade SVI service Plugin."""
|
||||||
|
|
||||||
from oslo_config import cfg
|
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='',
|
ML2_BROCADE = [cfg.StrOpt('address', default='',
|
||||||
help=_('The address of the host to SSH to')),
|
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")
|
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
|
|
||||||
|
@@ -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
|
|
@@ -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)
|
|
@@ -175,7 +175,7 @@ neutron.ml2.mechanism_drivers =
|
|||||||
bigswitch = neutron.plugins.ml2.drivers.mech_bigswitch.driver:BigSwitchMechanismDriver
|
bigswitch = neutron.plugins.ml2.drivers.mech_bigswitch.driver:BigSwitchMechanismDriver
|
||||||
ofagent = neutron.plugins.ml2.drivers.ofagent.driver:OfagentMechanismDriver
|
ofagent = neutron.plugins.ml2.drivers.ofagent.driver:OfagentMechanismDriver
|
||||||
mlnx = neutron.plugins.ml2.drivers.mlnx.mech_mlnx:MlnxMechanismDriver
|
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
|
fslsdn = neutron.plugins.ml2.drivers.freescale.mechanism_fslsdn:FslsdnMechanismDriver
|
||||||
sriovnicswitch = neutron.plugins.ml2.drivers.mech_sriov.mech_driver:SriovNicSwitchMechanismDriver
|
sriovnicswitch = neutron.plugins.ml2.drivers.mech_sriov.mech_driver:SriovNicSwitchMechanismDriver
|
||||||
nuage = neutron.plugins.ml2.drivers.mech_nuage.driver:NuageMechanismDriver
|
nuage = neutron.plugins.ml2.drivers.mech_nuage.driver:NuageMechanismDriver
|
||||||
|
Reference in New Issue
Block a user