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
Ofer Ben-Yacov 7 years ago
parent 14c50d7d1f
commit 483109a9f3

@ -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 address")

@ -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)
agent_l2_pop_enabled = self._get_agent_by_mac(context, mac)
except l2gw_exc.L2AgentNotFoundByHost as e:
physical_switches = self._get_physical_switch_ips(context, mac)
for physical_switch in physical_switches:
other_fdb_entries = self._get_fdb_entries(

@ -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.gateway_resource = constants.GATEWAY_RESOURCE_NAME
self.l2gateway_db = l2_gw_db.L2GatewayMixin()
self.type_manager = managers.TypeManager()
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):
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(
'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')
'Adding DVR dst_ip: %s, fixed_ip: %s',
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')

@ -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()