]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Brocade vendor code decomposition from neutron repo.
authorShiv Haris <sharis@brocade.com>
Tue, 3 Feb 2015 01:58:53 +0000 (17:58 -0800)
committerShiv Haris <sharis@brocade.com>
Fri, 13 Mar 2015 14:32:42 +0000 (07:32 -0700)
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

12 files changed:
doc/source/devref/contribute.rst
neutron/plugins/ml2/drivers/brocade/README.md
neutron/plugins/ml2/drivers/brocade/mechanism_brocade.py
neutron/plugins/ml2/drivers/brocade/nos/__init__.py [deleted file]
neutron/plugins/ml2/drivers/brocade/nos/nctemplates.py [deleted file]
neutron/plugins/ml2/drivers/brocade/nos/nosdriver.py [deleted file]
neutron/plugins/ml2/drivers/brocade/requirements.txt [new file with mode: 0644]
neutron/services/l3_router/brocade/l3_router_plugin.py
neutron/tests/unit/ml2/drivers/brocade/__init__.py [deleted file]
neutron/tests/unit/ml2/drivers/brocade/test_brocade_l3_plugin.py [deleted file]
neutron/tests/unit/ml2/drivers/brocade/test_brocade_mechanism_driver.py [deleted file]
setup.cfg

index 73c9e8794a739d9788cce704a0873adaf94270a5..dd6c220f1c824be35a6033d2606a04714b70c2f2 100644 (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
index 9ee4e0b97b6a0286e6d04f8390b766ec11e2f21c..6a2cb2a5c49d2e680debc6edf92770e9f4f952b6 100644 (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
 
 
index dd98bf7d4d97b79d7b81d93972fba968a931fbc4..a9953dedcad736119e42f3f29a47ed9a94d77c87 100644 (file)
 """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
diff --git a/neutron/plugins/ml2/drivers/brocade/nos/__init__.py b/neutron/plugins/ml2/drivers/brocade/nos/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/neutron/plugins/ml2/drivers/brocade/nos/nctemplates.py b/neutron/plugins/ml2/drivers/brocade/nos/nctemplates.py
deleted file mode 100644 (file)
index f52c8c9..0000000
+++ /dev/null
@@ -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}']"
diff --git a/neutron/plugins/ml2/drivers/brocade/nos/nosdriver.py b/neutron/plugins/ml2/drivers/brocade/nos/nosdriver.py
deleted file mode 100644 (file)
index 1ae52d3..0000000
+++ /dev/null
@@ -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)
diff --git a/neutron/plugins/ml2/drivers/brocade/requirements.txt b/neutron/plugins/ml2/drivers/brocade/requirements.txt
new file mode 100644 (file)
index 0000000..15f03ff
--- /dev/null
@@ -0,0 +1 @@
+networking-brocade
index 1be98dc5edc3d412c2c2580d668c4490ff715f88..c4b3a678097503456321f6f3d6a0bc63a3221b1c 100644 (file)
 """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
diff --git a/neutron/tests/unit/ml2/drivers/brocade/__init__.py b/neutron/tests/unit/ml2/drivers/brocade/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/neutron/tests/unit/ml2/drivers/brocade/test_brocade_l3_plugin.py b/neutron/tests/unit/ml2/drivers/brocade/test_brocade_l3_plugin.py
deleted file mode 100644 (file)
index 8511900..0000000
+++ /dev/null
@@ -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
diff --git a/neutron/tests/unit/ml2/drivers/brocade/test_brocade_mechanism_driver.py b/neutron/tests/unit/ml2/drivers/brocade/test_brocade_mechanism_driver.py
deleted file mode 100644 (file)
index cbb1df6..0000000
+++ /dev/null
@@ -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)
index 44d7b4c179735a86dd74a9520063a1f06877e7e4..7c55d3f55272077542cf59f3c10db55bd7474a3e 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -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