From 483109a9f3d68f47dc4f1a7701e82c9971e3e57c Mon Sep 17 00:00:00 2001 From: Ofer Ben-Yacov Date: Wed, 4 May 2016 18:01:45 +0300 Subject: [PATCH] enabling L2GW to work with DVR In DVR mode no host IP is associated with the L3 Agent because the router is configured on all the Compute Nodes and on the Network Node. To overcome this problem we look for L3 Agent that is running on the Network Node, resolve the hostname of the Network Node to get its IP address and use it to configure the destination IP needed for neutron port location information. Closes-Bug: 1463784 Change-Id: I2595c714ede896baa7726ceec793de9a7a29e6b2 --- .../services/l2gateway/exceptions.py | 8 ++++ .../services/l2gateway/ovsdb/data.py | 6 ++- .../l2gateway/service_drivers/rpc_l2gw.py | 41 +++++++++++++++++++ .../service_drivers/test_rpc_l2gw.py | 4 +- 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/networking_l2gw/services/l2gateway/exceptions.py b/networking_l2gw/services/l2gateway/exceptions.py index 4671a2e4..19a994cd 100644 --- a/networking_l2gw/services/l2gateway/exceptions.py +++ b/networking_l2gw/services/l2gateway/exceptions.py @@ -135,3 +135,11 @@ base.FAULT_MAP.update({L2GatewayInUse: web_exc.HTTPConflict, L2GatewayDuplicateSegmentationID: web_exc.HTTPConflict, L2AgentNotFoundByHost: web_exc.HTTPNotFound, OVSDBError: web_exc.HTTPConflict}) + + +class L3DvrAgentNotFound(exceptions.NotFound): + message = _("L3 agent could not be found") + + +class DvrAgentHostnameNotFound(exceptions.NeutronException): + message = _("Hostname '%(host)' has 127.0.0.1 address") diff --git a/networking_l2gw/services/l2gateway/ovsdb/data.py b/networking_l2gw/services/l2gateway/ovsdb/data.py index 0016e2a4..9de4b660 100644 --- a/networking_l2gw/services/l2gateway/ovsdb/data.py +++ b/networking_l2gw/services/l2gateway/ovsdb/data.py @@ -325,7 +325,11 @@ class OVSDBData(object): call add_fdb_entries. otherwise, call tunnel_sync. """ for mac in new_remote_macs: - agent_l2_pop_enabled = self._get_agent_by_mac(context, mac) + try: + agent_l2_pop_enabled = self._get_agent_by_mac(context, mac) + except l2gw_exc.L2AgentNotFoundByHost as e: + LOG.debug(e.message) + continue physical_switches = self._get_physical_switch_ips(context, mac) for physical_switch in physical_switches: other_fdb_entries = self._get_fdb_entries( diff --git a/networking_l2gw/services/l2gateway/service_drivers/rpc_l2gw.py b/networking_l2gw/services/l2gateway/service_drivers/rpc_l2gw.py index 61d444a4..f84575c5 100644 --- a/networking_l2gw/services/l2gateway/service_drivers/rpc_l2gw.py +++ b/networking_l2gw/services/l2gateway/service_drivers/rpc_l2gw.py @@ -14,6 +14,7 @@ # under the License. import abc +from neutron.common import constants as nc_const from neutron.common import rpc as n_rpc from neutron.db import agents_db from neutron.extensions import portbindings @@ -30,6 +31,9 @@ from networking_l2gw.services.l2gateway import exceptions as l2gw_exc from networking_l2gw.services.l2gateway import service_drivers from networking_l2gw.services.l2gateway.service_drivers import agent_api +from neutron.plugins.ml2 import managers + +from neutron_lib import constants as n_const from neutron_lib import exceptions from oslo_config import cfg from oslo_log import log as logging @@ -64,6 +68,7 @@ class L2gwRpcDriver(service_drivers.L2gwDriver): self.start_l2gateway_agent_scheduler() self.gateway_resource = constants.GATEWAY_RESOURCE_NAME self.l2gateway_db = l2_gw_db.L2GatewayMixin() + self.type_manager = managers.TypeManager() @property def service_type(self): @@ -459,6 +464,9 @@ class L2gwRpcDriver(service_drivers.L2gwDriver): def _get_ip_details(self, context, port): host = port[portbindings.HOST_ID] + if (not host and + (port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE)): + return self._get_l3_dvr_agent_details(context, port) agent = self._get_agent_details(context, host) conf_dict = agent.get("configurations") dst_ip = conf_dict.get("tunneling_ip") @@ -490,6 +498,39 @@ class L2gwRpcDriver(service_drivers.L2gwDriver): host=host) return l2_agent + def _get_l3_dvr_agent_details(self, context, port): + """Getting host IP for router port in DVR mode + + in case of DVR, the router port will not have host information as + there is router in each Compute Node and in the Network Node. + Here we look for the L3 Agent in the Network Node, get its hostname and + resolve its hostname to IP address to be used as destination IP. + """ + endpoints = self.type_manager.drivers.get('vxlan').obj.get_endpoints() + agents = self.service_plugin._core_plugin.get_agents( + context, + filters={ + 'agent_type': [n_const.AGENT_TYPE_L3], + 'alive': ['true'] + }) + for agent in agents: + conf_dict = agent.get("configurations") + if conf_dict.get("agent_mode") == nc_const.L3_AGENT_MODE_DVR_SNAT: + hostname = agent.get('host') + for endpoint in endpoints: + if endpoint.get('host') == hostname: + dst_ip = endpoint.get('ip_address') + fixed_ip_list = port.get('fixed_ips') + fixed_ip = fixed_ip_list[0].get('ip_address') + LOG.debug( + 'Adding DVR dst_ip: %s, fixed_ip: %s', + dst_ip, + fixed_ip + ) + return dst_ip, fixed_ip + raise l2gw_exc.DvrAgentHostnameNotFound(host=hostname) + raise l2gw_exc.L3DvrAgentNotFound() + def _get_logical_switch_dict(self, context, logical_switch, gw_connection): if logical_switch: uuid = logical_switch.get('uuid') diff --git a/networking_l2gw/tests/unit/services/l2gateway/service_drivers/test_rpc_l2gw.py b/networking_l2gw/tests/unit/services/l2gateway/service_drivers/test_rpc_l2gw.py index 97e431fd..f6e69e21 100755 --- a/networking_l2gw/tests/unit/services/l2gateway/service_drivers/test_rpc_l2gw.py +++ b/networking_l2gw/tests/unit/services/l2gateway/service_drivers/test_rpc_l2gw.py @@ -18,7 +18,7 @@ import contextlib from neutron.common import rpc as n_rpc from neutron import context as ctx from neutron.db import agents_db -from neutron.tests import base +from neutron.tests.unit.plugins.ml2 import test_plugin from networking_l2gw.db.l2gateway.ovsdb import lib as db from networking_l2gw.services.l2gateway.common import l2gw_validators @@ -31,7 +31,7 @@ from networking_l2gw.services.l2gateway.service_drivers import rpc_l2gw from oslo_utils import importutils -class TestL2gwRpcDriver(base.BaseTestCase): +class TestL2gwRpcDriver(test_plugin.Ml2PluginV2TestCase): def setUp(self): super(TestL2gwRpcDriver, self).setUp()