From ce9ee556ac661c0cee358cadef4bc2d54df8104d Mon Sep 17 00:00:00 2001 From: mamtap Date: Wed, 11 Mar 2015 05:43:44 -0700 Subject: [PATCH] IBM SDN-VE Plugin decomposition This addresses the changes in ml2 mech-driver and l3 service plugin to comply with the core-vendor-decomposition spec The monolithic sdnve plugin will not be removed with this change as it is still being used. Once the ml2 plugin is merged and the older plugin becomes obsolete, it will be removed from the neutron tree. Partially-implements: blueprint core-vendor-decomposition Closes-bug: #1430216 Change-Id: I5bc85a5f0a62b690004d8352b3bc43b9612c213d --- doc/source/devref/contribute.rst | 13 ++ .../ml2/drivers/ibm/mechanism_sdnve.py | 106 +++++++++ .../plugins/ml2/drivers/ibm/requirements.txt | 1 + neutron/services/l3_router/l3_sdnve.py | 203 ++++++++++++++++++ setup.cfg | 2 + 5 files changed, 325 insertions(+) create mode 100644 neutron/plugins/ml2/drivers/ibm/mechanism_sdnve.py create mode 100644 neutron/plugins/ml2/drivers/ibm/requirements.txt create mode 100644 neutron/services/l3_router/l3_sdnve.py diff --git a/doc/source/devref/contribute.rst b/doc/source/devref/contribute.rst index ed18bb2979f..a3183f39ba6 100644 --- a/doc/source/devref/contribute.rst +++ b/doc/source/devref/contribute.rst @@ -406,6 +406,8 @@ The following chart captures the following aspects: +-------------------------------+-----------------------+-----------+------------------+---------+--------------+ | networking-hyperv_ | | | | | | +-------------------------------+-----------------------+-----------+------------------+---------+--------------+ +| networking-ibm_ | ml2,l3 | yes | no | [B] | Kilo | ++-------------------------------+-----------------------+-----------+------------------+---------+--------------+ | networking-metaplugin_ | core | no | no | [C] | Kilo | +-------------------------------+-----------------------+-----------+------------------+---------+--------------+ | networking-midonet_ | core,lb | yes | yes | [C] | Kilo | @@ -431,6 +433,7 @@ The following chart captures the following aspects: | vmware-nsx_ | core | yes | yes | [C] | Kilo | +-------------------------------+-----------------------+-----------+------------------+---------+--------------+ + .. _networking-arista: Arista @@ -452,6 +455,15 @@ Cisco .. _networking-hyperv: + +.. _networking-ibm: + +IBM SDNVE +--------- + +* Git: https://github.com/stackforge/networking-ibm +* Launchpad: https://launchpad.net/networking-ibm + .. _networking-metaplugin: Metaplugin @@ -525,3 +537,4 @@ VMware * Git: https://github.com/stackforge/vmware-nsx * Launchpad: https://launchpad.net/vmware-nsx * PyPI: https://pypi.python.org/pypi/vmware-nsx + diff --git a/neutron/plugins/ml2/drivers/ibm/mechanism_sdnve.py b/neutron/plugins/ml2/drivers/ibm/mechanism_sdnve.py new file mode 100644 index 00000000000..5b322e67ed8 --- /dev/null +++ b/neutron/plugins/ml2/drivers/ibm/mechanism_sdnve.py @@ -0,0 +1,106 @@ +# Copyright 2015 IBM Corp. +# +# 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. + +from networking_ibm.sdnve.ml2 import sdnve_driver +from oslo_log import log as logging + +from neutron.common import constants as n_const +from neutron.extensions import portbindings +from neutron.plugins.ml2 import driver_api as api + +LOG = logging.getLogger(__name__) + + +class SdnveMechanismDriver(api.MechanismDriver): + """Ml2 Mechanism driver for IBM SDNVE Controller""" + def initialize(self): + self.vif_type = portbindings.VIF_TYPE_BRIDGE + self.vif_details = {portbindings.CAP_PORT_FILTER: False} + self.restrict_update_subnet = ['enable_dhcp', + 'gateway_ip', + 'allocation-pool'] + self.restrict_update_network = ['router:external'] + self.sdnve_drv = sdnve_driver.SdnveDriver() + + # NETWORK + def create_network_precommit(self, context): + self.sdnve_drv._pre_create_network(context) + + def create_network_postcommit(self, context): + self.sdnve_drv._create_network(context) + + def update_network_precommit(self, context): + self.sdnve_drv._pre_update_network(context) + + def update_network_postcommit(self, context): + self.sdnve_drv._update_network(context) + + def delete_network_postcommit(self, context): + self.sdnve_drv._delete_network(context) + + # SUBNET + def create_subnet_precommit(self, context): + self.sdnve_drv._pre_create_subnet(context) + + def create_subnet_postcommit(self, context): + self.sdnve_drv._create_subnet(context) + + def update_subnet_postcommit(self, context): + self.sdnve_drv._update_subnet(context) + + def update_subnet_precommit(self, context): + self.sdnve_drv._pre_update_subnet(context) + + def delete_subnet_postcommit(self, context): + self.sdnve_drv._delete_subnet(context) + + # PORT + def create_port_postcommit(self, context): + self.sdnve_drv._create_port(context) + + def create_port_precommit(self, context): + self.sdnve_drv._pre_create_port(context) + + def delete_port_precommit(self, context): + self.sdnve_drv._pre_delete_port(context) + + def update_port_postcommit(self, context): + self.sdnve_drv._update_port(context) + + def delete_port_postcommit(self, context): + self.sdnve_drv._delete_port(context) + + def bind_port(self, context): + LOG.debug("Attempting to bind port %(port)s on " + "network %(network)s", + {'port': context.current['id'], + 'network': context.network.current['id']}) + for segment in context.network.network_segments: + if self.sdnve_drv._check_segment(segment): + context.set_binding(segment[api.ID], + self.vif_type, + self.vif_details, + status=n_const.PORT_STATUS_ACTIVE) + LOG.debug("Bound using segment: %s", segment) + return + else: + LOG.debug("Refusing to bind port for segment ID %(id)s, " + "segment %(seg)s, phys net %(physnet)s, and " + "network type %(nettype)s", + {'id': segment[api.ID], + 'seg': segment[api.SEGMENTATION_ID], + 'physnet': segment[api.PHYSICAL_NETWORK], + 'nettype': segment[api.NETWORK_TYPE]}) diff --git a/neutron/plugins/ml2/drivers/ibm/requirements.txt b/neutron/plugins/ml2/drivers/ibm/requirements.txt new file mode 100644 index 00000000000..4d5b188aa39 --- /dev/null +++ b/neutron/plugins/ml2/drivers/ibm/requirements.txt @@ -0,0 +1 @@ +networking-ibm diff --git a/neutron/services/l3_router/l3_sdnve.py b/neutron/services/l3_router/l3_sdnve.py new file mode 100644 index 00000000000..912644bf8c4 --- /dev/null +++ b/neutron/services/l3_router/l3_sdnve.py @@ -0,0 +1,203 @@ +# Copyright 2015 IBM Corp. +# +# 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. + +from networking_ibm.sdnve.common import exceptions as sdnve_exc +from networking_ibm.sdnve.l3plugin import sdnve_l3driver +from oslo_log import log as logging +from oslo_utils import excutils + +from neutron.common import constants as q_const +from neutron.common import exceptions as n_exc +from neutron.db import db_base_plugin_v2 +from neutron.db import extraroute_db +from neutron.db import l3_gwmode_db +from neutron.i18n import _LE +from neutron.plugins.common import constants as l3_constants + + +LOG = logging.getLogger(__name__) + + +class SdnveL3ServicePlugin(db_base_plugin_v2.NeutronDbPluginV2, + extraroute_db.ExtraRoute_db_mixin, + l3_gwmode_db.L3_NAT_db_mixin): + + supported_extension_aliases = ["router", "ext-gw-mode", + "extraroute"] + + def __init__(self): + self.driver = sdnve_l3driver.SdnveL3Driver() + + def get_plugin_type(self): + return l3_constants.L3_ROUTER_NAT + + def get_plugin_description(self): + """Returns string description of the plugin.""" + return ("SDNVE Service plugin") + + def create_router(self, context, router): + if router['router']['admin_state_up'] is False: + router['router']['admin_state_up'] = True + with context.session.begin(subtransactions=True): + new_router = super(SdnveL3ServicePlugin, self).create_router( + context, router) + try: + self.driver.create_router(context, new_router) + return new_router + except Exception as e: + with excutils.save_and_reraise_exception(): + LOG.error(_LE("Create router failed in SDN-VE with error %s"), + e) + super(SdnveL3ServicePlugin, self).delete_router( + context, new_router['id']) + + def update_router(self, context, id, router): + if not router['router'].get('admin_state_up', True): + raise n_exc.NotImplementedError(_('admin_state_up=False ' + 'routers are not ' + 'supported.')) + original_router = {} + updated_router = {} + with context.session.begin(subtransactions=True): + original_router = super(SdnveL3ServicePlugin, self).get_router( + context, id) + updated_router = super(SdnveL3ServicePlugin, self).update_router( + context, id, router) + try: + self.driver.update_router(context, id, original_router, router) + return updated_router + except Exception as e: + LOG.error(_LE("Update router failed in SDN-VE with error %s"), + e) + + def delete_router(self, context, id): + with context.session.begin(subtransactions=True): + super(SdnveL3ServicePlugin, self).delete_router(context, id) + try: + self.driver.delete_router(context, id) + except Exception as e: + LOG.error(_LE("Delete router operation failed in SDN-VE after " + "deleting the router in DB: %s"), e) + + def add_router_interface(self, context, router_id, interface_info): + new_interface = super(SdnveL3ServicePlugin, self).add_router_interface( + context, router_id, interface_info) + request_info = interface_info.copy() + request_info['port_id'] = new_interface['port_id'] + if 'subnet_id' not in interface_info: + request_info['subnet_id'] = new_interface['subnet_id'] + try: + self.driver.add_router_interface(context, router_id, request_info) + return new_interface + except Exception as e: + with excutils.save_and_reraise_exception(): + LOG.error(_LE("Update router-add-interface failed in SDN-VE " + "with error %s"), e) + super(SdnveL3ServicePlugin, self).remove_router_interface( + context, router_id, interface_info) + + def _add_router_interface_only(self, context, router_id, interface_info): + if interface_info.get('port_id'): + try: + self.driver._add_router_interface_only(context, + router_id, + interface_info) + except Exception as e: + LOG.error(_LE("Add interface in the rollback of a " + "remove_router_interface operation failed %s"), + e) + + def remove_router_interface(self, context, router_id, interface_info): + subnet_id = interface_info.get('subnet_id') + if not subnet_id: + portid = interface_info.get('port_id') + if not portid: + raise sdnve_exc.BadInputException(msg=_('No port ID')) + + myport = super(SdnveL3ServicePlugin, self).\ + get_port(context, portid) + myfixed_ips = myport.get('fixed_ips') + if not myfixed_ips: + raise sdnve_exc.BadInputException(msg=_('No fixed IP')) + subnet_id = myfixed_ips[0].get('subnet_id') + if subnet_id: + interface_info['subnet_id'] = subnet_id + else: + portid = interface_info.get('port_id') + if not portid: + subnet = super(SdnveL3ServicePlugin, self).\ + get_subnet(context, subnet_id) + device_filter = {'device_id': [router_id], + 'device_owner': [q_const.DEVICE_OWNER_ROUTER_INTF], + 'network_id': [subnet['network_id']]} + ports = super(SdnveL3ServicePlugin, self).get_ports(context, + filters=device_filter) + if ports: + portid = ports[0]['id'] + interface_info['port_id'] = portid + with context.session.begin(subtransactions=True): + info = super(SdnveL3ServicePlugin, self).remove_router_interface( + context, router_id, interface_info) + try: + self.driver.remove_router_interface(context, + router_id, + interface_info) + return info + except Exception as e: + with excutils.save_and_reraise_exception(): + LOG.error(_LE("Update router-remove-interface" + " failed : %s"), e) + self._add_router_interface_only(context, + router_id, interface_info) + + def create_floatingip(self, context, floatingip): + with context.session.begin(subtransactions=True): + new_floatingip = super(SdnveL3ServicePlugin, + self).create_floatingip(context, floatingip) + try: + self.driver.create_floatingip(context, new_floatingip) + return new_floatingip + except Exception as e: + with excutils.save_and_reraise_exception(): + LOG.error(_LE("Create floating ip failed with error %s"), e) + super(SdnveL3ServicePlugin, self).delete_floatingip( + context, new_floatingip['id']) + + def update_floatingip(self, context, id, floatingip): + with context.session.begin(subtransactions=True): + original_floatingip = super( + SdnveL3ServicePlugin, self).get_floatingip(context, id) + updated_floatingip = super( + SdnveL3ServicePlugin, self).update_floatingip( + context, id, floatingip) + try: + self.driver.update_floatingip(context, + id, + original_floatingip, + floatingip) + return updated_floatingip + except Exception as e: + with excutils.save_and_reraise_exception(): + LOG.error(_LE("Update floating ip failed with error %s"), e) + super(SdnveL3ServicePlugin, self).update_floatingip( + context, id, {'floatingip': original_floatingip}) + + def delete_floatingip(self, context, id): + super(SdnveL3ServicePlugin, self).delete_floatingip(context, id) + try: + self.driver.delete_floatingip(context, id) + except Exception as e: + LOG.error(_LE("Delete floatingip failed in SDN-VE: %s"), e) diff --git a/setup.cfg b/setup.cfg index 44d7b4c1797..c9e15c28c64 100644 --- a/setup.cfg +++ b/setup.cfg @@ -137,6 +137,7 @@ neutron.service_plugins = neutron.services.firewall.fwaas_plugin.FirewallPlugin = neutron_fwaas.services.firewall.fwaas_plugin:FirewallPlugin neutron.services.loadbalancer.plugin.LoadBalancerPlugin = neutron_lbaas.services.loadbalancer.plugin:LoadBalancerPlugin neutron.services.vpn.plugin.VPNDriverPlugin = neutron_vpnaas.services.vpn.plugin:VPNDriverPlugin + ibm_l3 = neutron.services.l3_router.l3_sdnve:SdnveL3ServicePlugin neutron.service_providers = # These are for backwards compat with Juno firewall service provider configuration values neutron.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver = neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas:IptablesFwaasDriver @@ -179,6 +180,7 @@ neutron.ml2.mechanism_drivers = sriovnicswitch = neutron.plugins.ml2.drivers.mech_sriov.mech_driver:SriovNicSwitchMechanismDriver nuage = neutron.plugins.ml2.drivers.mech_nuage.driver:NuageMechanismDriver fake_agent = neutron.tests.unit.ml2.drivers.mech_fake_agent:FakeAgentMechanismDriver + sdnve = neutron.plugins.ml2.drivers.ibm.mechanism_sdnve:SdnveMechanismDriver neutron.ml2.extension_drivers = test = neutron.tests.unit.ml2.drivers.ext_test:TestExtensionDriver testdb = neutron.tests.unit.ml2.drivers.ext_test:TestDBExtensionDriver