Extract l2pop/DVR controller logic to common method
Regular ports and DVR ports are treated almost the same, extract the l2pop logic to treat them to a unified method that gets an argument if the FDB entries are needed or not, in order to reduce code duplication. Change-Id: I1f2a1de4cb7c29724e2354577f915a48173a1966
This commit is contained in:
parent
51fcac0389
commit
86a6639294
|
@ -173,6 +173,43 @@ class L2populationMechanismDriver(api.MechanismDriver,
|
||||||
|
|
||||||
return agent, agent_host, agent_ip, segment, fdb_entries
|
return agent, agent_host, agent_ip, segment, fdb_entries
|
||||||
|
|
||||||
|
def _create_agent_fdb(self, session, agent, segment, network_id):
|
||||||
|
agent_fdb_entries = {network_id:
|
||||||
|
{'segment_id': segment['segmentation_id'],
|
||||||
|
'network_type': segment['network_type'],
|
||||||
|
'ports': {}}}
|
||||||
|
tunnel_network_ports = (
|
||||||
|
self.get_dvr_network_ports(session, network_id).all())
|
||||||
|
fdb_network_ports = (
|
||||||
|
self.get_nondvr_network_ports(session, network_id).all())
|
||||||
|
ports = agent_fdb_entries[network_id]['ports']
|
||||||
|
ports.update(self._get_tunnels(
|
||||||
|
fdb_network_ports + tunnel_network_ports,
|
||||||
|
agent.host))
|
||||||
|
for agent_ip, fdbs in ports.items():
|
||||||
|
for binding, agent in fdb_network_ports:
|
||||||
|
if self.get_agent_ip(agent) == agent_ip:
|
||||||
|
fdbs.extend(self._get_port_fdb_entries(binding.port))
|
||||||
|
|
||||||
|
return agent_fdb_entries
|
||||||
|
|
||||||
|
def _get_tunnels(self, tunnel_network_ports, exclude_host):
|
||||||
|
agents = {}
|
||||||
|
for _, agent in tunnel_network_ports:
|
||||||
|
if agent.host == exclude_host:
|
||||||
|
continue
|
||||||
|
|
||||||
|
ip = self.get_agent_ip(agent)
|
||||||
|
if not ip:
|
||||||
|
LOG.debug("Unable to retrieve the agent ip, check "
|
||||||
|
"the agent %s configuration.", agent.host)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ip not in agents:
|
||||||
|
agents[ip] = [const.FLOODING_ENTRY]
|
||||||
|
|
||||||
|
return agents
|
||||||
|
|
||||||
def _update_port_up(self, context):
|
def _update_port_up(self, context):
|
||||||
port = context.current
|
port = context.current
|
||||||
agent_host = context.host
|
agent_host = context.host
|
||||||
|
@ -191,63 +228,27 @@ class L2populationMechanismDriver(api.MechanismDriver,
|
||||||
{'segment_id': segment['segmentation_id'],
|
{'segment_id': segment['segmentation_id'],
|
||||||
'network_type': segment['network_type'],
|
'network_type': segment['network_type'],
|
||||||
'ports': {agent_ip: []}}}
|
'ports': {agent_ip: []}}}
|
||||||
|
other_fdb_ports = other_fdb_entries[network_id]['ports']
|
||||||
|
|
||||||
if agent_active_ports == 1 or (
|
if agent_active_ports == 1 or (
|
||||||
self.get_agent_uptime(agent) < cfg.CONF.l2pop.agent_boot_time):
|
self.get_agent_uptime(agent) < cfg.CONF.l2pop.agent_boot_time):
|
||||||
# First port activated on current agent in this network,
|
# First port activated on current agent in this network,
|
||||||
# we have to provide it with the whole list of fdb entries
|
# we have to provide it with the whole list of fdb entries
|
||||||
agent_fdb_entries = {network_id:
|
agent_fdb_entries = self._create_agent_fdb(session,
|
||||||
{'segment_id': segment['segmentation_id'],
|
agent,
|
||||||
'network_type': segment['network_type'],
|
segment,
|
||||||
'ports': {}}}
|
network_id)
|
||||||
ports = agent_fdb_entries[network_id]['ports']
|
|
||||||
|
|
||||||
nondvr_network_ports = self.get_nondvr_network_ports(session,
|
|
||||||
network_id)
|
|
||||||
for network_port in nondvr_network_ports:
|
|
||||||
binding, agent = network_port
|
|
||||||
if agent.host == agent_host:
|
|
||||||
continue
|
|
||||||
|
|
||||||
ip = self.get_agent_ip(agent)
|
|
||||||
if not ip:
|
|
||||||
LOG.debug("Unable to retrieve the agent ip, check "
|
|
||||||
"the agent %(agent_host)s configuration.",
|
|
||||||
{'agent_host': agent.host})
|
|
||||||
continue
|
|
||||||
|
|
||||||
agent_ports = ports.get(ip, [const.FLOODING_ENTRY])
|
|
||||||
agent_ports += self._get_port_fdb_entries(binding.port)
|
|
||||||
ports[ip] = agent_ports
|
|
||||||
|
|
||||||
dvr_network_ports = self.get_dvr_network_ports(session, network_id)
|
|
||||||
for network_port in dvr_network_ports:
|
|
||||||
binding, agent = network_port
|
|
||||||
if agent.host == agent_host:
|
|
||||||
continue
|
|
||||||
|
|
||||||
ip = self.get_agent_ip(agent)
|
|
||||||
if not ip:
|
|
||||||
LOG.debug("Unable to retrieve the agent ip, check "
|
|
||||||
"the agent %(agent_host)s configuration.",
|
|
||||||
{'agent_host': agent.host})
|
|
||||||
continue
|
|
||||||
|
|
||||||
agent_ports = ports.get(ip, [const.FLOODING_ENTRY])
|
|
||||||
ports[ip] = agent_ports
|
|
||||||
|
|
||||||
# And notify other agents to add flooding entry
|
# And notify other agents to add flooding entry
|
||||||
other_fdb_entries[network_id]['ports'][agent_ip].append(
|
other_fdb_ports[agent_ip].append(const.FLOODING_ENTRY)
|
||||||
const.FLOODING_ENTRY)
|
|
||||||
|
|
||||||
if ports.keys():
|
if agent_fdb_entries[network_id]['ports'].keys():
|
||||||
self.L2populationAgentNotify.add_fdb_entries(
|
self.L2populationAgentNotify.add_fdb_entries(
|
||||||
self.rpc_ctx, agent_fdb_entries, agent_host)
|
self.rpc_ctx, agent_fdb_entries, agent_host)
|
||||||
|
|
||||||
# Notify other agents to add fdb rule for current port
|
# Notify other agents to add fdb rule for current port
|
||||||
if port['device_owner'] != const.DEVICE_OWNER_DVR_INTERFACE:
|
if port['device_owner'] != const.DEVICE_OWNER_DVR_INTERFACE:
|
||||||
other_fdb_entries[network_id]['ports'][agent_ip] += (
|
other_fdb_ports[agent_ip] += port_fdb_entries
|
||||||
port_fdb_entries)
|
|
||||||
|
|
||||||
self.L2populationAgentNotify.add_fdb_entries(self.rpc_ctx,
|
self.L2populationAgentNotify.add_fdb_entries(self.rpc_ctx,
|
||||||
other_fdb_entries)
|
other_fdb_entries)
|
||||||
|
|
|
@ -26,10 +26,12 @@ from neutron.db import agents_db
|
||||||
from neutron.extensions import portbindings
|
from neutron.extensions import portbindings
|
||||||
from neutron.extensions import providernet as pnet
|
from neutron.extensions import providernet as pnet
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
|
from neutron.plugins.ml2.drivers.l2pop import db as l2pop_db
|
||||||
from neutron.plugins.ml2.drivers.l2pop import mech_driver as l2pop_mech_driver
|
from neutron.plugins.ml2.drivers.l2pop import mech_driver as l2pop_mech_driver
|
||||||
from neutron.plugins.ml2.drivers.l2pop import rpc as l2pop_rpc
|
from neutron.plugins.ml2.drivers.l2pop import rpc as l2pop_rpc
|
||||||
from neutron.plugins.ml2 import managers
|
from neutron.plugins.ml2 import managers
|
||||||
from neutron.plugins.ml2 import rpc
|
from neutron.plugins.ml2 import rpc
|
||||||
|
from neutron.tests import base
|
||||||
from neutron.tests.unit.ml2 import test_ml2_plugin as test_plugin
|
from neutron.tests.unit.ml2 import test_ml2_plugin as test_plugin
|
||||||
|
|
||||||
HOST = 'my_l2_host'
|
HOST = 'my_l2_host'
|
||||||
|
@ -788,3 +790,104 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase):
|
||||||
rem_fdb_entries):
|
rem_fdb_entries):
|
||||||
l2pop_mech.delete_port_postcommit(mock.Mock())
|
l2pop_mech.delete_port_postcommit(mock.Mock())
|
||||||
self.assertTrue(upd_port_down.called)
|
self.assertTrue(upd_port_down.called)
|
||||||
|
|
||||||
|
|
||||||
|
class TestL2PopulationMechDriver(base.BaseTestCase):
|
||||||
|
|
||||||
|
def _test_get_tunnels(self, agent_ip, exclude_host=True):
|
||||||
|
mech_driver = l2pop_mech_driver.L2populationMechanismDriver()
|
||||||
|
agent = mock.Mock()
|
||||||
|
agent.host = HOST
|
||||||
|
network_ports = ((None, agent),)
|
||||||
|
with mock.patch.object(l2pop_db.L2populationDbMixin,
|
||||||
|
'get_agent_ip',
|
||||||
|
return_value=agent_ip):
|
||||||
|
excluded_host = HOST + '-EXCLUDE' if exclude_host else HOST
|
||||||
|
return mech_driver._get_tunnels(network_ports, excluded_host)
|
||||||
|
|
||||||
|
def test_get_tunnels(self):
|
||||||
|
tunnels = self._test_get_tunnels('20.0.0.1')
|
||||||
|
self.assertTrue('20.0.0.1' in tunnels)
|
||||||
|
|
||||||
|
def test_get_tunnels_no_ip(self):
|
||||||
|
tunnels = self._test_get_tunnels(None)
|
||||||
|
self.assertEqual(0, len(tunnels))
|
||||||
|
|
||||||
|
def test_get_tunnels_dont_exclude_host(self):
|
||||||
|
tunnels = self._test_get_tunnels(None, exclude_host=False)
|
||||||
|
self.assertEqual(0, len(tunnels))
|
||||||
|
|
||||||
|
def _test_create_agent_fdb(self, fdb_network_ports_query, agent_ips):
|
||||||
|
mech_driver = l2pop_mech_driver.L2populationMechanismDriver()
|
||||||
|
tunnel_network_ports_query, tunnel_agent = (
|
||||||
|
self._mock_network_ports_query(HOST + '1', None))
|
||||||
|
agent_ips[tunnel_agent] = '10.0.0.1'
|
||||||
|
|
||||||
|
def agent_ip_side_effect(agent):
|
||||||
|
return agent_ips[agent]
|
||||||
|
|
||||||
|
with contextlib.nested(
|
||||||
|
mock.patch.object(l2pop_db.L2populationDbMixin,
|
||||||
|
'get_agent_ip',
|
||||||
|
side_effect=agent_ip_side_effect),
|
||||||
|
mock.patch.object(l2pop_db.L2populationDbMixin,
|
||||||
|
'get_nondvr_network_ports',
|
||||||
|
new=fdb_network_ports_query),
|
||||||
|
mock.patch.object(l2pop_db.L2populationDbMixin,
|
||||||
|
'get_dvr_network_ports',
|
||||||
|
new=tunnel_network_ports_query)):
|
||||||
|
session = mock.Mock()
|
||||||
|
agent = mock.Mock()
|
||||||
|
agent.host = HOST
|
||||||
|
segment = {'segmentation_id': 1, 'network_type': 'vxlan'}
|
||||||
|
return mech_driver._create_agent_fdb(session,
|
||||||
|
agent,
|
||||||
|
segment,
|
||||||
|
'network_id')
|
||||||
|
|
||||||
|
def _mock_network_ports_query(self, host_name, binding):
|
||||||
|
agent = mock.Mock()
|
||||||
|
agent.host = host_name
|
||||||
|
result = [(binding, agent)]
|
||||||
|
all_mock = mock.Mock()
|
||||||
|
all_mock.all = mock.Mock(return_value=result)
|
||||||
|
mock_query = mock.Mock(return_value=all_mock)
|
||||||
|
return mock_query, agent
|
||||||
|
|
||||||
|
def test_create_agent_fdb(self):
|
||||||
|
binding = mock.Mock()
|
||||||
|
binding.port = {'mac_address': '00:00:DE:AD:BE:EF',
|
||||||
|
'fixed_ips': [{'ip_address': '1.1.1.1'}]}
|
||||||
|
fdb_network_ports_query, fdb_agent = (
|
||||||
|
self._mock_network_ports_query(HOST + '2', binding))
|
||||||
|
agent_ips = {fdb_agent: '20.0.0.1'}
|
||||||
|
|
||||||
|
agent_fdb = self._test_create_agent_fdb(fdb_network_ports_query,
|
||||||
|
agent_ips)
|
||||||
|
result = agent_fdb['network_id']
|
||||||
|
|
||||||
|
expected_result = {'segment_id': 1,
|
||||||
|
'network_type': 'vxlan',
|
||||||
|
'ports':
|
||||||
|
{'10.0.0.1':
|
||||||
|
[constants.FLOODING_ENTRY],
|
||||||
|
'20.0.0.1':
|
||||||
|
[constants.FLOODING_ENTRY,
|
||||||
|
l2pop_rpc.PortInfo(
|
||||||
|
mac_address='00:00:DE:AD:BE:EF',
|
||||||
|
ip_address='1.1.1.1')]}}
|
||||||
|
self.assertEqual(expected_result, result)
|
||||||
|
|
||||||
|
def test_create_agent_fdb_only_tunnels(self):
|
||||||
|
all_mock = mock.Mock()
|
||||||
|
all_mock.all = mock.Mock(return_value=[])
|
||||||
|
fdb_network_ports_query = mock.Mock(return_value=all_mock)
|
||||||
|
agent_fdb = self._test_create_agent_fdb(fdb_network_ports_query, {})
|
||||||
|
result = agent_fdb['network_id']
|
||||||
|
|
||||||
|
expected_result = {'segment_id': 1,
|
||||||
|
'network_type': 'vxlan',
|
||||||
|
'ports':
|
||||||
|
{'10.0.0.1':
|
||||||
|
[constants.FLOODING_ENTRY]}}
|
||||||
|
self.assertEqual(expected_result, result)
|
||||||
|
|
Loading…
Reference in New Issue