summaryrefslogtreecommitdiffstats
path: root/networking-odl/networking_odl/l3
diff options
context:
space:
mode:
Diffstat (limited to 'networking-odl/networking_odl/l3')
-rw-r--r--networking-odl/networking_odl/l3/__init__.py0
-rw-r--r--networking-odl/networking_odl/l3/l3_odl.py189
-rw-r--r--networking-odl/networking_odl/l3/l3_odl_v2.py206
3 files changed, 395 insertions, 0 deletions
diff --git a/networking-odl/networking_odl/l3/__init__.py b/networking-odl/networking_odl/l3/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking-odl/networking_odl/l3/__init__.py
diff --git a/networking-odl/networking_odl/l3/l3_odl.py b/networking-odl/networking_odl/l3/l3_odl.py
new file mode 100644
index 0000000..e06e335
--- /dev/null
+++ b/networking-odl/networking_odl/l3/l3_odl.py
@@ -0,0 +1,189 @@
+#
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# 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 as logging
+
+from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
+from neutron.api.rpc.handlers import l3_rpc
+from neutron.common import rpc as n_rpc
+from neutron.common import topics
+from neutron.db import extraroute_db
+from neutron.db import l3_agentschedulers_db
+from neutron.db import l3_dvr_db
+from neutron.db import l3_gwmode_db
+from neutron.plugins.common import constants
+from neutron_lib import constants as q_const
+
+from networking_odl.common import client as odl_client
+from networking_odl.common import utils as odl_utils
+
+try:
+ from neutron.db.db_base_plugin_v2 import common_db_mixin
+except ImportError as e:
+ # the change set ofece8cc2e9aae1610a325d0c206e38da3da9a0a1a
+ # the Change-Id of I1eac61c258541bca80e14be4b7c75519a014ffae
+ # db_base_plugin_v2.common_db_mixin was removed
+ from neutron.db import common_db_mixin
+
+
+cfg.CONF.import_group('ml2_odl', 'networking_odl.common.config')
+LOG = logging.getLogger(__name__)
+ROUTERS = 'routers'
+FLOATINGIPS = 'floatingips'
+
+
+class OpenDaylightL3RouterPlugin(
+ common_db_mixin.CommonDbMixin,
+ extraroute_db.ExtraRoute_db_mixin,
+ l3_dvr_db.L3_NAT_with_dvr_db_mixin,
+ l3_gwmode_db.L3_NAT_db_mixin,
+ l3_agentschedulers_db.L3AgentSchedulerDbMixin):
+
+ """Implementation of the OpenDaylight L3 Router Service Plugin.
+
+ This class implements a L3 service plugin that provides
+ router and floatingip resources and manages associated
+ request/response.
+ """
+ supported_extension_aliases = ["dvr", "router", "ext-gw-mode",
+ "extraroute"]
+
+ def __init__(self):
+ self.setup_rpc()
+ self.client = odl_client.OpenDaylightRestClient.create_client()
+
+ def setup_rpc(self):
+ self.topic = topics.L3PLUGIN
+ self.conn = n_rpc.create_connection()
+ self.agent_notifiers.update(
+ {q_const.AGENT_TYPE_L3: l3_rpc_agent_api.L3AgentNotifyAPI()})
+ self.endpoints = [l3_rpc.L3RpcCallback()]
+ self.conn.create_consumer(self.topic, self.endpoints,
+ fanout=False)
+ self.conn.consume_in_threads()
+
+ def get_plugin_type(self):
+ return constants.L3_ROUTER_NAT
+
+ def get_plugin_description(self):
+ """returns string description of the plugin."""
+ return ("L3 Router Service Plugin for basic L3 forwarding"
+ " using OpenDaylight")
+
+ def filter_update_router_attributes(self, router):
+ """Filter out router attributes for an update operation."""
+ odl_utils.try_del(router, ['id', 'tenant_id', 'status'])
+
+ def create_router(self, context, router):
+ router_dict = super(OpenDaylightL3RouterPlugin, self).create_router(
+ context, router)
+ url = ROUTERS
+ self.client.sendjson('post', url, {ROUTERS[:-1]: router_dict})
+ return router_dict
+
+ def update_router(self, context, id, router):
+ router_dict = super(OpenDaylightL3RouterPlugin, self).update_router(
+ context, id, router)
+ url = ROUTERS + "/" + id
+ resource = router_dict.copy()
+ self.filter_update_router_attributes(resource)
+ self.client.sendjson('put', url, {ROUTERS[:-1]: resource})
+ return router_dict
+
+ def delete_router(self, context, id):
+ super(OpenDaylightL3RouterPlugin, self).delete_router(context, id)
+ url = ROUTERS + "/" + id
+ self.client.sendjson('delete', url, None)
+
+ def create_floatingip(self, context, floatingip,
+ initial_status=q_const.FLOATINGIP_STATUS_ACTIVE):
+ fip_dict = super(OpenDaylightL3RouterPlugin, self).create_floatingip(
+ context, floatingip, initial_status)
+ url = FLOATINGIPS
+ self.client.sendjson('post', url, {FLOATINGIPS[:-1]: fip_dict})
+ return fip_dict
+
+ def update_floatingip(self, context, id, floatingip):
+ with context.session.begin(subtransactions=True):
+ fip_dict = super(OpenDaylightL3RouterPlugin,
+ self).update_floatingip(context, id, floatingip)
+ # Update status based on association
+ if fip_dict.get('port_id') is None:
+ fip_dict['status'] = q_const.FLOATINGIP_STATUS_DOWN
+ else:
+ fip_dict['status'] = q_const.FLOATINGIP_STATUS_ACTIVE
+ self.update_floatingip_status(context, id, fip_dict['status'])
+
+ url = FLOATINGIPS + "/" + id
+ self.client.sendjson('put', url, {FLOATINGIPS[:-1]: fip_dict})
+ return fip_dict
+
+ def delete_floatingip(self, context, id):
+ super(OpenDaylightL3RouterPlugin, self).delete_floatingip(context, id)
+ url = FLOATINGIPS + "/" + id
+ self.client.sendjson('delete', url, None)
+
+ def add_router_interface(self, context, router_id, interface_info):
+ new_router = super(
+ OpenDaylightL3RouterPlugin, self).add_router_interface(
+ context, router_id, interface_info)
+ url = ROUTERS + "/" + router_id + "/add_router_interface"
+ router_dict = self._generate_router_dict(router_id, interface_info,
+ new_router)
+ self.client.sendjson('put', url, router_dict)
+ return new_router
+
+ def remove_router_interface(self, context, router_id, interface_info):
+ new_router = super(
+ OpenDaylightL3RouterPlugin, self).remove_router_interface(
+ context, router_id, interface_info)
+ url = ROUTERS + "/" + router_id + "/remove_router_interface"
+ router_dict = self._generate_router_dict(router_id, interface_info,
+ new_router)
+ self.client.sendjson('put', url, router_dict)
+ return new_router
+
+ def _generate_router_dict(self, router_id, interface_info, new_router):
+ # Get network info for the subnet that is being added to the router.
+ # Check if the interface information is by port-id or subnet-id
+ add_by_port, add_by_sub = self._validate_interface_info(interface_info)
+ if add_by_sub:
+ _port_id = new_router['port_id']
+ _subnet_id = interface_info['subnet_id']
+ elif add_by_port:
+ _port_id = interface_info['port_id']
+ _subnet_id = new_router['subnet_id']
+
+ router_dict = {'subnet_id': _subnet_id,
+ 'port_id': _port_id,
+ 'id': router_id,
+ 'tenant_id': new_router['tenant_id']}
+
+ return router_dict
+
+ dvr_deletens_if_no_port_warned = False
+
+ def dvr_deletens_if_no_port(self, context, port_id):
+ # TODO(yamahata): implement this method or delete this logging
+ # For now, this is defined to avoid attribute exception
+ # Since ODL L3 does not create namespaces, this is always going to
+ # be a noop. When it is confirmed, delete this comment and logging
+ if not self.dvr_deletens_if_no_port_warned:
+ LOG.debug('dvr is not suported yet. '
+ 'this method needs to be implemented')
+ self.dvr_deletens_if_no_port_warned = True
+ return []
diff --git a/networking-odl/networking_odl/l3/l3_odl_v2.py b/networking-odl/networking_odl/l3/l3_odl_v2.py
new file mode 100644
index 0000000..2732ea6
--- /dev/null
+++ b/networking-odl/networking_odl/l3/l3_odl_v2.py
@@ -0,0 +1,206 @@
+# Copyright (c) 2016 OpenStack Foundation
+# 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 log as logging
+
+from neutron.db import api as db_api
+from neutron.db import common_db_mixin
+from neutron.db import extraroute_db
+from neutron.db import l3_agentschedulers_db
+from neutron.db import l3_dvr_db
+from neutron.db import l3_gwmode_db
+from neutron.plugins.common import constants
+from neutron_lib import constants as q_const
+
+from networking_odl.common import config # noqa
+from networking_odl.common import constants as odl_const
+from networking_odl.db import db
+from networking_odl.journal import journal
+
+LOG = logging.getLogger(__name__)
+
+
+class OpenDaylightL3RouterPlugin(
+ common_db_mixin.CommonDbMixin,
+ extraroute_db.ExtraRoute_db_mixin,
+ l3_dvr_db.L3_NAT_with_dvr_db_mixin,
+ l3_gwmode_db.L3_NAT_db_mixin,
+ l3_agentschedulers_db.L3AgentSchedulerDbMixin):
+
+ """Implementation of the OpenDaylight L3 Router Service Plugin.
+
+ This class implements a L3 service plugin that provides
+ router and floatingip resources and manages associated
+ request/response.
+ """
+ supported_extension_aliases = ["dvr", "router", "ext-gw-mode",
+ "extraroute"]
+
+ def __init__(self):
+ super(OpenDaylightL3RouterPlugin, self).__init__()
+
+ # TODO(rcurran): Continue investigation into how many journal threads
+ # to run per neutron controller deployment.
+ self.journal = journal.OpendaylightJournalThread()
+
+ def get_plugin_type(self):
+ return constants.L3_ROUTER_NAT
+
+ def get_plugin_description(self):
+ """Returns string description of the plugin."""
+ return ("L3 Router Service Plugin for basic L3 forwarding "
+ "using OpenDaylight.")
+
+ @journal.call_thread_on_end
+ def create_router(self, context, router):
+ session = db_api.get_session()
+ with session.begin(subtransactions=True):
+ router_dict = super(
+ OpenDaylightL3RouterPlugin, self).create_router(context,
+ router)
+ db.create_pending_row(context.session, odl_const.ODL_ROUTER,
+ router_dict['id'], odl_const.ODL_CREATE,
+ router_dict)
+ return router_dict
+
+ @journal.call_thread_on_end
+ def update_router(self, context, router_id, router):
+ session = db_api.get_session()
+ with session.begin(subtransactions=True):
+ router_dict = super(
+ OpenDaylightL3RouterPlugin, self).update_router(
+ context, router_id, router)
+ db.create_pending_row(context.session, odl_const.ODL_ROUTER,
+ router_id, odl_const.ODL_UPDATE, router_dict)
+ return router_dict
+
+ @journal.call_thread_on_end
+ def delete_router(self, context, router_id):
+ session = db_api.get_session()
+ router_dict = self.get_router(context, router_id)
+ dependency_list = [router_dict['gw_port_id']]
+ with session.begin(subtransactions=True):
+ super(OpenDaylightL3RouterPlugin, self).delete_router(context,
+ router_id)
+ db.create_pending_row(context.session, odl_const.ODL_ROUTER,
+ router_id, odl_const.ODL_DELETE,
+ dependency_list)
+
+ @journal.call_thread_on_end
+ def create_floatingip(self, context, floatingip,
+ initial_status=q_const.FLOATINGIP_STATUS_ACTIVE):
+ session = db_api.get_session()
+ with session.begin(subtransactions=True):
+ fip_dict = super(
+ OpenDaylightL3RouterPlugin, self).create_floatingip(
+ context, floatingip, initial_status)
+ db.create_pending_row(context.session, odl_const.ODL_FLOATINGIP,
+ fip_dict['id'], odl_const.ODL_CREATE,
+ fip_dict)
+ return fip_dict
+
+ @journal.call_thread_on_end
+ def update_floatingip(self, context, floatingip_id, floatingip):
+ session = db_api.get_session()
+ with session.begin(subtransactions=True):
+ fip_dict = super(
+ OpenDaylightL3RouterPlugin, self).update_floatingip(
+ context, floatingip_id, floatingip)
+
+ # Update status based on association
+ if fip_dict.get('port_id') is None:
+ fip_dict['status'] = q_const.FLOATINGIP_STATUS_DOWN
+ else:
+ fip_dict['status'] = q_const.FLOATINGIP_STATUS_ACTIVE
+ self.update_floatingip_status(context, floatingip_id,
+ fip_dict['status'])
+
+ db.create_pending_row(context.session, odl_const.ODL_FLOATINGIP,
+ floatingip_id, odl_const.ODL_UPDATE,
+ fip_dict)
+ return fip_dict
+
+ @journal.call_thread_on_end
+ def delete_floatingip(self, context, floatingip_id):
+ session = db_api.get_session()
+ floatingip_dict = self.get_floatingip(context, floatingip_id)
+ dependency_list = [floatingip_dict['router_id']]
+ dependency_list.append(floatingip_dict['floating_network_id'])
+ with session.begin(subtransactions=True):
+ super(OpenDaylightL3RouterPlugin, self).delete_floatingip(
+ context, floatingip_id)
+ db.create_pending_row(context.session, odl_const.ODL_FLOATINGIP,
+ floatingip_id, odl_const.ODL_DELETE,
+ dependency_list)
+
+ @journal.call_thread_on_end
+ def add_router_interface(self, context, router_id, interface_info):
+ session = db_api.get_session()
+ with session.begin(subtransactions=True):
+ new_router = super(
+ OpenDaylightL3RouterPlugin, self).add_router_interface(
+ context, router_id, interface_info)
+ router_dict = self._generate_router_dict(router_id, interface_info,
+ new_router)
+ db.create_pending_row(context.session, odl_const.ODL_ROUTER_INTF,
+ odl_const.ODL_UUID_NOT_USED,
+ odl_const.ODL_ADD, router_dict)
+ return new_router
+
+ @journal.call_thread_on_end
+ def remove_router_interface(self, context, router_id, interface_info):
+ session = db_api.get_session()
+ with session.begin(subtransactions=True):
+ new_router = super(
+ OpenDaylightL3RouterPlugin, self).remove_router_interface(
+ context, router_id, interface_info)
+ router_dict = self._generate_router_dict(router_id, interface_info,
+ new_router)
+ db.create_pending_row(context.session, odl_const.ODL_ROUTER_INTF,
+ odl_const.ODL_UUID_NOT_USED,
+ odl_const.ODL_REMOVE, router_dict)
+ return new_router
+
+ def _generate_router_dict(self, router_id, interface_info, new_router):
+ # Get network info for the subnet that is being added to the router.
+ # Check if the interface information is by port-id or subnet-id.
+ add_by_port, add_by_sub = self._validate_interface_info(interface_info)
+ if add_by_sub:
+ _port_id = new_router['port_id']
+ _subnet_id = interface_info['subnet_id']
+ elif add_by_port:
+ _port_id = interface_info['port_id']
+ _subnet_id = new_router['subnet_id']
+
+ router_dict = {'subnet_id': _subnet_id,
+ 'port_id': _port_id,
+ 'id': router_id,
+ 'tenant_id': new_router['tenant_id']}
+
+ return router_dict
+
+ dvr_deletens_if_no_port_warned = False
+
+ def dvr_deletens_if_no_port(self, context, port_id):
+ # TODO(yamahata): implement this method or delete this logging
+ # For now, this is defined to avoid attribute exception
+ # Since ODL L3 does not create namespaces, this is always going to
+ # be a noop. When it is confirmed, delete this comment and logging
+ if not self.dvr_deletens_if_no_port_warned:
+ LOG.debug('dvr is not suported yet. '
+ 'this method needs to be implemented')
+ self.dvr_deletens_if_no_port_warned = True
+ return []