neutron/neutron/services/l3_router/brocade/l3_router_plugin.py

237 lines
11 KiB
Python

# 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.gettextutils import _LE, _LI
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(_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 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(_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