text: # 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.
  #
  
  
  """Implentation of Brocade SVI service Plugin."""
  
  from oslo.config import cfg
  
  from neutron.common import constants as l3_constants
  from neutron.openstack.common import excutils
  from neutron.openstack.common import log as logging
  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')),
                 cfg.StrOpt('username', default='admin',
                            help=_('The SSH username to use')),
                 cfg.StrOpt('password', default='password', secret=True,
                            help=_('The SSH password to use')),
                 cfg.StrOpt('rbridge_id', default=1,
                            help=_('Rbridge id of provider edge router(s)')),
                 ]
  
  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(_("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)
          try:
              switch = self._switch
              self._driver.delete_router(switch['address'],
                                         switch['username'],
                                         switch['password'],
                                         switch['rbridge_id'],
                                         str(router['id']))
          except Exception:
              excutils.save_and_reraise_exception()
  
      def add_router_interface(self, context, router_id, interface_info):
          """creates svi on NOS device and assigns ip addres 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(_("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)
                  LOG.error(_("BrocadeSVIPlugin: adding redundant router "
                              "interface is not supported"))
                  raise Exception(_("BrocadeSVIPlugin:adding redundant router "
                                    "interface is not supported"))
  
          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(_("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(_("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
  