diff options
Diffstat (limited to 'networking_sfc/services/flowclassifier')
11 files changed, 380 insertions, 0 deletions
diff --git a/networking_sfc/services/flowclassifier/__init__.py b/networking_sfc/services/flowclassifier/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/networking_sfc/services/flowclassifier/__init__.py diff --git a/networking_sfc/services/flowclassifier/common/__init__.py b/networking_sfc/services/flowclassifier/common/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/networking_sfc/services/flowclassifier/common/__init__.py diff --git a/networking_sfc/services/flowclassifier/common/config.py b/networking_sfc/services/flowclassifier/common/config.py new file mode 100644 index 0000000..ed2496f --- /dev/null +++ b/networking_sfc/services/flowclassifier/common/config.py @@ -0,0 +1,27 @@ +# Copyright 2015 Futurewei. 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 oslo_config import cfg + + +FLOWCLASSIFIER_DRIVER_OPTS = [ + cfg.ListOpt('drivers', + default=['dummy'], + help=_("An ordered list of flow classifier drivers " + "entrypoints to be loaded from the " + "networking_sfc.flowclassifier.drivers namespace.")), +] + + +cfg.CONF.register_opts(FLOWCLASSIFIER_DRIVER_OPTS, "flowclassifier") diff --git a/networking_sfc/services/flowclassifier/common/context.py b/networking_sfc/services/flowclassifier/common/context.py new file mode 100644 index 0000000..d873077 --- /dev/null +++ b/networking_sfc/services/flowclassifier/common/context.py @@ -0,0 +1,37 @@ +# Copyright 2015 Futurewei. 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. + + +class FlowClassifierPluginContext(object): + """Flow Classifier context base class.""" + def __init__(self, plugin, plugin_context): + self._plugin = plugin + self._plugin_context = plugin_context + + +class FlowClassifierContext(FlowClassifierPluginContext): + + def __init__(self, plugin, plugin_context, flowclassifier, + original_flowclassifier=None): + super(FlowClassifierContext, self).__init__(plugin, plugin_context) + self._flowclassifier = flowclassifier + self._original_flowclassifier = original_flowclassifier + + @property + def current(self): + return self._flowclassifier + + @property + def original(self): + return self._original_flowclassifier diff --git a/networking_sfc/services/flowclassifier/common/exceptions.py b/networking_sfc/services/flowclassifier/common/exceptions.py new file mode 100644 index 0000000..9f186c0 --- /dev/null +++ b/networking_sfc/services/flowclassifier/common/exceptions.py @@ -0,0 +1,31 @@ +# Copyright 2015 Futurewei. 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. +"""Exceptions used by FlowClassifier plugin and drivers.""" + +from neutron.common import exceptions + + +class FlowClassifierDriverError(exceptions.NeutronException): + """flow classifier driver call failed.""" + message = _("%(method)s failed.") + + +class FlowClassifierException(exceptions.NeutronException): + """Base for flow classifier driver exceptions returned to user.""" + pass + + +class FlowClassifierBadRequest(exceptions.BadRequest, FlowClassifierException): + """Base for flow classifier driver bad request exceptions.""" + pass diff --git a/networking_sfc/services/flowclassifier/driver_manager.py b/networking_sfc/services/flowclassifier/driver_manager.py new file mode 100644 index 0000000..1af4470 --- /dev/null +++ b/networking_sfc/services/flowclassifier/driver_manager.py @@ -0,0 +1,104 @@ +# Copyright 2015 Futurewei. 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 oslo_config import cfg +from oslo_log import log +import stevedore + +from neutron.i18n import _LE +from neutron.i18n import _LI + +from networking_sfc.services.flowclassifier.common import exceptions as fc_exc + + +LOG = log.getLogger(__name__) +cfg.CONF.import_opt('drivers', + 'networking_sfc.services.flowclassifier.common.config', + group='flowclassifier') + + +class FlowClassifierDriverManager(stevedore.named.NamedExtensionManager): + """Implementation of Flow Classifier drivers.""" + + def __init__(self): + # Registered flow classifier drivers, keyed by name. + self.drivers = {} + # Ordered list of flow classifier drivers, defining + # the order in which the drivers are called. + self.ordered_drivers = [] + LOG.info(_LI("Configured Flow Classifier drivers: %s"), + cfg.CONF.flowclassifier.drivers) + super(FlowClassifierDriverManager, self).__init__( + 'networking_sfc.flowclassifier.drivers', + cfg.CONF.flowclassifier.drivers, + invoke_on_load=True, + name_order=True) + LOG.info(_LI("Loaded Flow Classifier drivers: %s"), + self.names()) + self._register_drivers() + + def _register_drivers(self): + """Register all Flow Classifier drivers. + + This method should only be called once in the + FlowClassifierDriverManager constructor. + """ + for ext in self: + self.drivers[ext.name] = ext + self.ordered_drivers.append(ext) + LOG.info(_LI("Registered Flow Classifier drivers: %s"), + [driver.name for driver in self.ordered_drivers]) + + def initialize(self): + # ServiceChain bulk operations requires each driver to support them + self.native_bulk_support = True + for driver in self.ordered_drivers: + LOG.info(_LI("Initializing Flow Classifier driver '%s'"), + driver.name) + driver.obj.initialize() + self.native_bulk_support &= getattr(driver.obj, + 'native_bulk_support', True) + + def _call_drivers(self, method_name, context): + """Helper method for calling a method across all drivers. + + :param method_name: name of the method to call + :param context: context parameter to pass to each method call + :param continue_on_failure: whether or not to continue to call + all SFC drivers once one has raised an exception + if any Flow Classifier driver call fails. + """ + for driver in self.ordered_drivers: + try: + getattr(driver.obj, method_name)(context) + except Exception as e: + # This is an internal failure. + LOG.exception(e) + LOG.error( + _LE("Flow Classifier driver '%(name)s'" + "failed in %(method)s"), + {'name': driver.name, 'method': method_name} + ) + raise fc_exc.FlowClassifierDriverError( + method=method_name + ) + + def create_flow_classifier(self, context): + self._call_drivers("create_flow_classifier", context) + + def update_flow_classifier(self, context): + self._call_drivers("update_flow_classifier", context) + + def delete_flow_classifier(self, context): + self._call_drivers("delete_flow_classifier", context) diff --git a/networking_sfc/services/flowclassifier/drivers/__init__.py b/networking_sfc/services/flowclassifier/drivers/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/networking_sfc/services/flowclassifier/drivers/__init__.py diff --git a/networking_sfc/services/flowclassifier/drivers/base.py b/networking_sfc/services/flowclassifier/drivers/base.py new file mode 100644 index 0000000..eeaa60a --- /dev/null +++ b/networking_sfc/services/flowclassifier/drivers/base.py @@ -0,0 +1,33 @@ +# Copyright 2015 Futurewei. 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. + +import abc +import six + + +@six.add_metaclass(abc.ABCMeta) +class FlowClassifierDriverBase(object): + """Flow Classifier Driver Base Class.""" + + @abc.abstractmethod + def create_flow_classifier(self, context): + pass + + @abc.abstractmethod + def delete_flow_classifier(self, context): + pass + + @abc.abstractmethod + def update_flow_classifier(self, context): + pass diff --git a/networking_sfc/services/flowclassifier/drivers/dummy/__init__.py b/networking_sfc/services/flowclassifier/drivers/dummy/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/networking_sfc/services/flowclassifier/drivers/dummy/__init__.py diff --git a/networking_sfc/services/flowclassifier/drivers/dummy/dummy.py b/networking_sfc/services/flowclassifier/drivers/dummy/dummy.py new file mode 100644 index 0000000..d032cc9 --- /dev/null +++ b/networking_sfc/services/flowclassifier/drivers/dummy/dummy.py @@ -0,0 +1,35 @@ +# Copyright 2015 Futurewei. 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 oslo_log import helpers as log_helpers + +from networking_sfc.services.flowclassifier.drivers import base as fc_driver + + +class DummyDriver(fc_driver.FlowClassifierDriverBase): + """Flow Classifier Driver Dummy Class.""" + def initialize(self): + pass + + @log_helpers.log_method_call + def create_flow_classifier(self, context): + pass + + @log_helpers.log_method_call + def update_flow_classifier(self, context): + pass + + @log_helpers.log_method_call + def delete_flow_classifier(self, context): + pass diff --git a/networking_sfc/services/flowclassifier/plugin.py b/networking_sfc/services/flowclassifier/plugin.py new file mode 100644 index 0000000..692e1d8 --- /dev/null +++ b/networking_sfc/services/flowclassifier/plugin.py @@ -0,0 +1,113 @@ +# Copyright 2015 Futurewei. 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 oslo_log import helpers as log_helpers +from oslo_log import log as logging +from oslo_utils import excutils + +from neutron.i18n import _LE +from neutron import manager + +from networking_sfc.db import flowclassifier_db as fc_db +from networking_sfc.extensions import flowclassifier as fc_ext +from networking_sfc.services.flowclassifier.common import context as fc_ctx +from networking_sfc.services.flowclassifier.common import exceptions as fc_exc +from networking_sfc.services.flowclassifier import driver_manager as fc_driver + + +LOG = logging.getLogger(__name__) + + +class FlowClassifierPlugin(fc_db.FlowClassifierDbPlugin): + + """Implementation of the Plugin.""" + supported_extension_aliases = [fc_ext.FLOW_CLASSIFIER_EXT] + path_prefix = fc_ext.FLOW_CLASSIFIER_PREFIX + + def __init__(self): + self.driver_manager = fc_driver.FlowClassifierDriverManager() + super(FlowClassifierPlugin, self).__init__() + self.driver_manager.initialize() + + def _get_port(self, context, id): + port = super(FlowClassifierPlugin, self)._get_port(context, id) + core_plugin = manager.NeutronManager.get_plugin() + return core_plugin.get_port(context, port['id']) + + def _get_fixed_ip_from_port(self, context, logical_port, ip_prefix): + if logical_port is not None: + port = self._get_port(context, logical_port) + if ( + ip_prefix is None and + 'fixed_ips' in port and + port['fixed_ips'] + ): + for fixed_ip in port['fixed_ips']: + ip_prefix = ( + '%s/32' % fixed_ip['ip_address'] + ) + break + return ip_prefix + + @log_helpers.log_method_call + def create_flow_classifier(self, context, flow_classifier): + fc_db = super(FlowClassifierPlugin, self).create_flow_classifier( + context, flow_classifier) + fc_db_context = fc_ctx.FlowClassifierContext(self, context, fc_db) + try: + self.driver_manager.create_flow_classifier(fc_db_context) + except fc_exc.FlowClassifierDriverError as e: + LOG.exception(e) + with excutils.save_and_reraise_exception(): + LOG.error(_LE("Create flow classifier failed, " + "deleting flow_classifier '%s'"), + fc_db['id']) + self.delete_flow_classifier(context, fc_db['id']) + return fc_db + + @log_helpers.log_method_call + def update_flow_classifier(self, context, id, flow_classifier): + original_flowclassifier = self.get_flow_classifier(context, id) + updated_fc = super(FlowClassifierPlugin, self).update_flow_classifier( + context, id, flow_classifier) + fc_db_context = fc_ctx.FlowClassifierContext( + self, context, updated_fc, + original_flowclassifier=original_flowclassifier) + + try: + self.driver_manager.update_flow_classifier(fc_db_context) + except fc_exc.FlowClassifierDriverError as e: + LOG.exception(e) + with excutils.save_and_reraise_exception(): + LOG.error(_LE("Update flow classifier failed, " + "flow_classifier '%s'"), + updated_fc['id']) + + return updated_fc + + @log_helpers.log_method_call + def delete_flow_classifier(self, context, fc_id): + fc = self.get_flow_classifier(context, fc_id) + fc_context = fc_ctx.FlowClassifierContext(self, context, fc) + try: + self.driver_manager.delete_flow_classifier(fc_context) + except fc_exc.FlowClassfierDriverError as e: + LOG.exception(e) + with excutils.save_and_reraise_exception(): + LOG.error(_LE("Delete port pair group failed, " + "flow_classifier '%s'"), + fc_id) + + super(FlowClassifierPlugin, self).delete_flow_classifier( + context, fc_id) |