Refactor l2_pop code to pass mac/ip info more readably

Previous code used a 2 element array to represent a mac/ip address
pair.  Code assumed that element 0 was mac and 1 was ip.  This made
the code difficult to read and difficult to maintain.  An attempt was
made to insert a third value that failed miserably because of the
position dependence and other code that assumed not only positions but
also the number of elements.

Using a namedtuple seems to be the best way to get better
maintainability.  Named tuples can be compared with regular tuples.
The json serializer still uses an array to represent it so the on-wire
representation of the object has not changed.  A short snip of code
was required to restore the namedtuple from the RPC message.

Change-Id: I7f8c93b0e12ee0179bb23dfbb3a3d814615b1c2e
Closes-Bug: #1352801
This commit is contained in:
Carl Baldwin 2014-08-06 01:02:09 +00:00
parent 7cb6ca011e
commit 8f50bc29ed
11 changed files with 275 additions and 123 deletions

View File

@ -21,6 +21,7 @@ import six
from neutron.common import constants as n_const
from neutron.common import log
from neutron.openstack.common import log as logging
from neutron.plugins.ml2.drivers.l2pop import rpc as l2pop_rpc
LOG = logging.getLogger(__name__)
@ -38,17 +39,43 @@ class L2populationRpcCallBackMixin(object):
@log.log
def add_fdb_entries(self, context, fdb_entries, host=None):
if not host or host == cfg.CONF.host:
self.fdb_add(context, fdb_entries)
self.fdb_add(context, self._unmarshall_fdb_entries(fdb_entries))
@log.log
def remove_fdb_entries(self, context, fdb_entries, host=None):
if not host or host == cfg.CONF.host:
self.fdb_remove(context, fdb_entries)
self.fdb_remove(context, self._unmarshall_fdb_entries(fdb_entries))
@log.log
def update_fdb_entries(self, context, fdb_entries, host=None):
if not host or host == cfg.CONF.host:
self.fdb_update(context, fdb_entries)
self.fdb_update(context, self._unmarshall_fdb_entries(fdb_entries))
@staticmethod
def _unmarshall_fdb_entries(fdb_entries):
"""Prepares fdb_entries from JSON.
All methods in this class that receive messages should call this to
unmarshall fdb_entries from the wire.
:param fdb_entries: Original fdb_entries data-structure. Looks like:
{
<uuid>: {
...,
'ports': {
<ip address>: [ [<mac>, <ip>], ... ],
...
:returns: Deep copy with [<mac>, <ip>] converted to PortInfo
"""
unmarshalled = dict(fdb_entries)
for value in unmarshalled.values():
if 'ports' in value:
value['ports'] = dict(
(address, [l2pop_rpc.PortInfo(*pi) for pi in port_infos])
for address, port_infos in value['ports'].items()
)
return unmarshalled
@abc.abstractmethod
def fdb_add(self, context, fdb_entries):
@ -80,9 +107,10 @@ class L2populationRpcCallBackTunnelMixin(L2populationRpcCallBackMixin):
:param br: represent the bridge on which add_fdb_flow should be
applied.
:param port_info: list to include mac and ip.
:param port_info: PortInfo instance to include mac and ip.
.mac_address
.ip_address
[mac, ip]
:remote_ip: remote ip address.
:param lvm: a local VLAN map of network.
:param ofport: a port to add.
@ -100,8 +128,10 @@ class L2populationRpcCallBackTunnelMixin(L2populationRpcCallBackMixin):
:param br: represent the bridge on which del_fdb_flow should be
applied.
:param port_info: a list to contain mac and ip.
[mac, ip]
:param port_info: PortInfo instance to include mac and ip.
.mac_address
.ip_address
:remote_ip: remote ip address.
:param lvm: local VLAN map of network.
:param ofport: a port to delete.
@ -222,13 +252,16 @@ class L2populationRpcCallBackTunnelMixin(L2populationRpcCallBackMixin):
agent and network.
{'net1':
{'agent_ip':
{'before': [[mac, ip]],
'after': [[mac, ip]]
{'before': PortInfo,
'after': PortInfo
}
}
'net2':
...
}
PortInfo has .mac_address and .ip_address attrs.
:param local_ip: local IP address of this agent.
:local_vlan_map: local VLAN map of network.
'''
@ -243,11 +276,13 @@ class L2populationRpcCallBackTunnelMixin(L2populationRpcCallBackMixin):
continue
after = state.get('after', [])
for mac, ip in after:
self.setup_entry_for_arp_reply(br, 'add', lvm.vlan, mac,
ip)
for mac_ip in after:
self.setup_entry_for_arp_reply(br, 'add', lvm.vlan,
mac_ip.mac_address,
mac_ip.ip_address)
before = state.get('before', [])
for mac, ip in before:
self.setup_entry_for_arp_reply(br, 'remove', lvm.vlan, mac,
ip)
for mac_ip in before:
self.setup_entry_for_arp_reply(br, 'remove', lvm.vlan,
mac_ip.mac_address,
mac_ip.ip_address)

View File

@ -70,7 +70,7 @@ MAX_GRE_ID = 2 ** 32 - 1
MIN_VXLAN_VNI = 1
MAX_VXLAN_VNI = 2 ** 24 - 1
FLOODING_ENTRY = ['00:00:00:00:00:00', '0.0.0.0']
FLOODING_ENTRY = ('00:00:00:00:00:00', '0.0.0.0')
EXT_NS_COMP = '_backward_comp_e_ns'
EXT_NS = '_extension_ns'

View File

@ -40,8 +40,9 @@ class L2populationMechanismDriver(api.MechanismDriver,
self.migrated_ports = {}
def _get_port_fdb_entries(self, port):
return [[port['mac_address'],
ip['ip_address']] for ip in port['fixed_ips']]
return [l2pop_rpc.PortInfo(mac_address=port['mac_address'],
ip_address=ip['ip_address'])
for ip in port['fixed_ips']]
def delete_port_postcommit(self, context):
port = context.current
@ -75,8 +76,12 @@ class L2populationMechanismDriver(api.MechanismDriver,
return
agent, agent_host, agent_ip, segment, port_fdb_entries = port_infos
orig_mac_ip = [[port['mac_address'], ip] for ip in orig_ips]
port_mac_ip = [[port['mac_address'], ip] for ip in port_ips]
orig_mac_ip = [l2pop_rpc.PortInfo(mac_address=port['mac_address'],
ip_address=ip)
for ip in orig_ips]
port_mac_ip = [l2pop_rpc.PortInfo(mac_address=port['mac_address'],
ip_address=ip)
for ip in port_ips]
upd_fdb_entries = {port['network_id']: {agent_ip: {}}}

View File

@ -13,6 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
import copy
from neutron.common import rpc as n_rpc
from neutron.common import topics
from neutron.openstack.common import log as logging
@ -21,6 +24,9 @@ from neutron.openstack.common import log as logging
LOG = logging.getLogger(__name__)
PortInfo = collections.namedtuple("PortInfo", "mac_address ip_address")
class L2populationAgentNotifyAPI(n_rpc.RpcProxy):
BASE_RPC_API_VERSION = '1.0'
@ -39,8 +45,10 @@ class L2populationAgentNotifyAPI(n_rpc.RpcProxy):
'method': method,
'fdb_entries': fdb_entries})
marshalled_fdb_entries = self._marshall_fdb_entries(fdb_entries)
self.fanout_cast(context,
self.make_msg(method, fdb_entries=fdb_entries),
self.make_msg(method,
fdb_entries=marshalled_fdb_entries),
topic=self.topic_l2pop_update)
def _notification_host(self, context, method, fdb_entries, host):
@ -50,8 +58,10 @@ class L2populationAgentNotifyAPI(n_rpc.RpcProxy):
'topic': self.topic,
'method': method,
'fdb_entries': fdb_entries})
marshalled_fdb_entries = self._marshall_fdb_entries(fdb_entries)
self.cast(context,
self.make_msg(method, fdb_entries=fdb_entries),
self.make_msg(method,
fdb_entries=marshalled_fdb_entries),
topic='%s.%s' % (self.topic_l2pop_update, host))
def add_fdb_entries(self, context, fdb_entries, host=None):
@ -80,3 +90,28 @@ class L2populationAgentNotifyAPI(n_rpc.RpcProxy):
else:
self._notification_fanout(context, 'update_fdb_entries',
fdb_entries)
@staticmethod
def _marshall_fdb_entries(fdb_entries):
"""Prepares fdb_entries for serialization to JSON for RPC.
All methods in this class that send messages should call this to
marshall fdb_entries for the wire.
:param fdb_entries: Original fdb_entries data-structure. Looks like:
{
<uuid>: {
...,
'ports': {
<ip address>: [ PortInfo, ... ],
...
:returns: Deep copy with PortInfo converted to [mac, ip]
"""
marshalled = copy.deepcopy(fdb_entries)
for value in marshalled.values():
if 'ports' in value:
for address, port_infos in value['ports'].items():
value['ports'][address] = [[mac, ip]
for mac, ip in port_infos]
return marshalled

View File

@ -379,8 +379,9 @@ class OFANeutronAgent(n_rpc.RpcCallback,
for port_info in port_infos:
if port_info == n_const.FLOODING_ENTRY:
continue
self.ryuapp.add_arp_table_entry(
lvm.vlan, port_info[1], port_info[0])
self.ryuapp.add_arp_table_entry(lvm.vlan,
port_info.ip_address,
port_info.mac_address)
@log.log
def _fdb_remove_arp(self, lvm, agent_ports):
@ -388,7 +389,7 @@ class OFANeutronAgent(n_rpc.RpcCallback,
for port_info in port_infos:
if port_info == n_const.FLOODING_ENTRY:
continue
self.ryuapp.del_arp_table_entry(lvm.vlan, port_info[1])
self.ryuapp.del_arp_table_entry(lvm.vlan, port_info.ip_address)
def add_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
if port_info == n_const.FLOODING_ENTRY:
@ -399,11 +400,13 @@ class OFANeutronAgent(n_rpc.RpcCallback,
lvm.tun_ofports, goto_next=True)
else:
self.ryuapp.add_arp_table_entry(
lvm.vlan, port_info[1], port_info[0])
lvm.vlan,
port_info.ip_address,
port_info.mac_address)
br.install_tunnel_output(
tables.TUNNEL_OUT,
lvm.vlan, lvm.segmentation_id,
set([ofport]), goto_next=False, eth_dst=port_info[0])
set([ofport]), goto_next=False, eth_dst=port_info.mac_address)
def del_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
if port_info == n_const.FLOODING_ENTRY:
@ -418,9 +421,9 @@ class OFANeutronAgent(n_rpc.RpcCallback,
tables.TUNNEL_FLOOD[lvm.network_type],
lvm.vlan)
else:
self.ryuapp.del_arp_table_entry(lvm.vlan, port_info[1])
self.ryuapp.del_arp_table_entry(lvm.vlan, port_info.ip_address)
br.delete_tunnel_output(tables.TUNNEL_OUT,
lvm.vlan, eth_dst=port_info[0])
lvm.vlan, eth_dst=port_info.mac_address)
def setup_entry_for_arp_reply(self, br, action, local_vid, mac_address,
ip_address):

View File

@ -375,12 +375,13 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
actions="strip_vlan,set_tunnel:%s,output:%s" %
(lvm.segmentation_id, ofports))
else:
self.setup_entry_for_arp_reply(br, 'add', lvm.vlan, port_info[0],
port_info[1])
self.setup_entry_for_arp_reply(br, 'add', lvm.vlan,
port_info.mac_address,
port_info.ip_address)
br.add_flow(table=constants.UCAST_TO_TUN,
priority=2,
dl_vlan=lvm.vlan,
dl_dst=port_info[0],
dl_dst=port_info.mac_address,
actions="strip_vlan,set_tunnel:%s,output:%s" %
(lvm.segmentation_id, ofport))
@ -398,10 +399,11 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
br.delete_flows(table=constants.FLOOD_TO_TUN, dl_vlan=lvm.vlan)
else:
self.setup_entry_for_arp_reply(br, 'remove', lvm.vlan,
port_info[0], port_info[1])
port_info.mac_address,
port_info.ip_address)
br.delete_flows(table=constants.UCAST_TO_TUN,
dl_vlan=lvm.vlan,
dl_dst=port_info[0])
dl_dst=port_info.mac_address)
def _fdb_chg_ip(self, context, fdb_entries):
LOG.debug("update chg_ip received")

View File

@ -18,6 +18,7 @@ import collections
import mock
from neutron.agent import l2population_rpc
from neutron.plugins.ml2.drivers.l2pop import rpc as l2pop_rpc
from neutron.plugins.openvswitch.agent import ovs_neutron_agent
from neutron.tests import base
@ -81,9 +82,9 @@ class TestL2populationRpcCallBackTunnelMixinBase(base.BaseTestCase):
port='port3')]
self.agent_ports = {
self.ports[0].ip: [[self.lvms[0].mac, self.lvms[0].ip]],
self.ports[1].ip: [[self.lvms[1].mac, self.lvms[1].ip]],
self.ports[2].ip: [[self.lvms[2].mac, self.lvms[2].ip]],
self.ports[0].ip: [(self.lvms[0].mac, self.lvms[0].ip)],
self.ports[1].ip: [(self.lvms[1].mac, self.lvms[1].ip)],
self.ports[2].ip: [(self.lvms[2].mac, self.lvms[2].ip)],
}
self.fdb_entries1 = {
@ -92,21 +93,21 @@ class TestL2populationRpcCallBackTunnelMixinBase(base.BaseTestCase):
'segment_id': self.lvms[0].segid,
'ports': {
self.local_ip: [],
self.ports[0].ip: [[self.lvms[0].mac, self.lvms[0].ip]]},
self.ports[0].ip: [(self.lvms[0].mac, self.lvms[0].ip)]},
},
self.lvms[1].net: {
'network_type': self.type_gre,
'segment_id': self.lvms[1].segid,
'ports': {
self.local_ip: [],
self.ports[1].ip: [[self.lvms[1].mac, self.lvms[1].ip]]},
self.ports[1].ip: [(self.lvms[1].mac, self.lvms[1].ip)]},
},
self.lvms[2].net: {
'network_type': self.type_gre,
'segment_id': self.lvms[2].segid,
'ports': {
self.local_ip: [],
self.ports[2].ip: [[self.lvms[2].mac, self.lvms[2].ip]]},
self.ports[2].ip: [(self.lvms[2].mac, self.lvms[2].ip)]},
},
}
@ -129,18 +130,24 @@ class TestL2populationRpcCallBackTunnelMixinBase(base.BaseTestCase):
self.upd_fdb_entry1_val = {
self.lvms[0].net: {
self.ports[0].ip: {
'before': [[self.lvms[0].mac, self.lvms[0].ip]],
'after': [[self.lvms[1].mac, self.lvms[1].ip]],
'before': [l2pop_rpc.PortInfo(self.lvms[0].mac,
self.lvms[0].ip)],
'after': [l2pop_rpc.PortInfo(self.lvms[1].mac,
self.lvms[1].ip)],
},
self.ports[1].ip: {
'before': [[self.lvms[0].mac, self.lvms[0].ip]],
'after': [[self.lvms[1].mac, self.lvms[1].ip]],
'before': [l2pop_rpc.PortInfo(self.lvms[0].mac,
self.lvms[0].ip)],
'after': [l2pop_rpc.PortInfo(self.lvms[1].mac,
self.lvms[1].ip)],
},
},
self.lvms[1].net: {
self.ports[2].ip: {
'before': [[self.lvms[0].mac, self.lvms[0].ip]],
'after': [[self.lvms[2].mac, self.lvms[2].ip]],
'before': [l2pop_rpc.PortInfo(self.lvms[0].mac,
self.lvms[0].ip)],
'after': [l2pop_rpc.PortInfo(self.lvms[2].mac,
self.lvms[2].ip)],
},
},
}

View File

@ -39,10 +39,10 @@ class TestL2populationRpcCallBackTunnelMixin(
results[lvm] = agent_ports
expected = {
self.lvm1: {
self.ports[0].ip: [[self.lvms[0].mac, self.lvms[0].ip]],
self.ports[0].ip: [(self.lvms[0].mac, self.lvms[0].ip)],
self.local_ip: []},
self.lvm3: {
self.ports[2].ip: [[self.lvms[2].mac, self.lvms[2].ip]],
self.ports[2].ip: [(self.lvms[2].mac, self.lvms[2].ip)],
self.local_ip: []},
}
self.assertEqual(expected, results)
@ -55,11 +55,11 @@ class TestL2populationRpcCallBackTunnelMixin(
results[lvm] = agent_ports
expected = {
self.lvm1: {
self.ports[0].ip: [[self.lvms[0].mac, self.lvms[0].ip]],
self.ports[0].ip: [(self.lvms[0].mac, self.lvms[0].ip)],
self.local_ip: []},
self.lvm2: {},
self.lvm3: {
self.ports[2].ip: [[self.lvms[2].mac, self.lvms[2].ip]],
self.ports[2].ip: [(self.lvms[2].mac, self.lvms[2].ip)],
self.local_ip: []},
}
self.assertEqual(expected, results)
@ -72,11 +72,11 @@ class TestL2populationRpcCallBackTunnelMixin(
self.fakeagent.fdb_add_tun('context', self.fakebr, self.lvm1,
self.agent_ports, self.ofports)
expected = [
mock.call(self.fakebr, [self.lvms[0].mac, self.lvms[0].ip],
mock.call(self.fakebr, (self.lvms[0].mac, self.lvms[0].ip),
self.ports[0].ip, self.lvm1, self.ports[0].ofport),
mock.call(self.fakebr, [self.lvms[1].mac, self.lvms[1].ip],
mock.call(self.fakebr, (self.lvms[1].mac, self.lvms[1].ip),
self.ports[1].ip, self.lvm1, self.ports[1].ofport),
mock.call(self.fakebr, [self.lvms[2].mac, self.lvms[2].ip],
mock.call(self.fakebr, (self.lvms[2].mac, self.lvms[2].ip),
self.ports[2].ip, self.lvm1, self.ports[2].ofport),
]
self.assertEqual(sorted(expected),
@ -95,11 +95,11 @@ class TestL2populationRpcCallBackTunnelMixin(
mock_setup_tunnel_port.assert_called_once_with(
self.fakebr, self.ports[1].ip, self.lvm1.network_type)
expected = [
mock.call(self.fakebr, [self.lvms[0].mac, self.lvms[0].ip],
mock.call(self.fakebr, (self.lvms[0].mac, self.lvms[0].ip),
self.ports[0].ip, self.lvm1, self.ports[0].ofport),
mock.call(self.fakebr, [self.lvms[1].mac, self.lvms[1].ip],
mock.call(self.fakebr, (self.lvms[1].mac, self.lvms[1].ip),
self.ports[1].ip, self.lvm1, ofport),
mock.call(self.fakebr, [self.lvms[2].mac, self.lvms[2].ip],
mock.call(self.fakebr, (self.lvms[2].mac, self.lvms[2].ip),
self.ports[2].ip, self.lvm1, self.ports[2].ofport),
]
self.assertEqual(sorted(expected),
@ -117,9 +117,9 @@ class TestL2populationRpcCallBackTunnelMixin(
mock_setup_tunnel_port.assert_called_once_with(
self.fakebr, self.ports[1].ip, self.lvm1.network_type)
expected = [
mock.call(self.fakebr, [self.lvms[0].mac, self.lvms[0].ip],
mock.call(self.fakebr, (self.lvms[0].mac, self.lvms[0].ip),
self.ports[0].ip, self.lvm1, self.ports[0].ofport),
mock.call(self.fakebr, [self.lvms[2].mac, self.lvms[2].ip],
mock.call(self.fakebr, (self.lvms[2].mac, self.lvms[2].ip),
self.ports[2].ip, self.lvm1, self.ports[2].ofport),
]
self.assertEqual(sorted(expected),
@ -131,11 +131,11 @@ class TestL2populationRpcCallBackTunnelMixin(
self.fakeagent.fdb_remove_tun('context', self.fakebr, self.lvm1,
self.agent_ports, self.ofports)
expected = [
mock.call(self.fakebr, [self.lvms[0].mac, self.lvms[0].ip],
mock.call(self.fakebr, (self.lvms[0].mac, self.lvms[0].ip),
self.ports[0].ip, self.lvm1, self.ports[0].ofport),
mock.call(self.fakebr, [self.lvms[1].mac, self.lvms[1].ip],
mock.call(self.fakebr, (self.lvms[1].mac, self.lvms[1].ip),
self.ports[1].ip, self.lvm1, self.ports[1].ofport),
mock.call(self.fakebr, [self.lvms[2].mac, self.lvms[2].ip],
mock.call(self.fakebr, (self.lvms[2].mac, self.lvms[2].ip),
self.ports[2].ip, self.lvm1, self.ports[2].ofport),
]
self.assertEqual(sorted(expected),
@ -150,12 +150,12 @@ class TestL2populationRpcCallBackTunnelMixin(
self.fakeagent.fdb_remove_tun('context', self.fakebr, self.lvm1,
self.agent_ports, self.ofports)
expected = [
mock.call(self.fakebr, [self.lvms[0].mac, self.lvms[0].ip],
mock.call(self.fakebr, (self.lvms[0].mac, self.lvms[0].ip),
self.ports[0].ip, self.lvm1, self.ports[0].ofport),
mock.call(self.fakebr,
[n_const.FLOODING_ENTRY[0], n_const.FLOODING_ENTRY[1]],
(n_const.FLOODING_ENTRY[0], n_const.FLOODING_ENTRY[1]),
self.ports[1].ip, self.lvm1, self.ports[1].ofport),
mock.call(self.fakebr, [self.lvms[2].mac, self.lvms[2].ip],
mock.call(self.fakebr, (self.lvms[2].mac, self.lvms[2].ip),
self.ports[2].ip, self.lvm1, self.ports[2].ofport),
]
self.assertEqual(sorted(expected),
@ -170,9 +170,9 @@ class TestL2populationRpcCallBackTunnelMixin(
self.fakeagent.fdb_remove_tun('context', self.fakebr, self.lvm1,
self.agent_ports, self.ofports)
expected = [
mock.call(self.fakebr, [self.lvms[0].mac, self.lvms[0].ip],
mock.call(self.fakebr, (self.lvms[0].mac, self.lvms[0].ip),
self.ports[0].ip, self.lvm1, self.ports[0].ofport),
mock.call(self.fakebr, [self.lvms[2].mac, self.lvms[2].ip],
mock.call(self.fakebr, (self.lvms[2].mac, self.lvms[2].ip),
self.ports[2].ip, self.lvm1, self.ports[2].ofport),
]
self.assertEqual(sorted(expected),
@ -223,8 +223,8 @@ class TestL2populationRpcCallBackTunnelMixin(
upd_fdb_entry_val = {
self.lvms[0].net: {
self.local_ip: {
'before': [[self.lvms[0].mac, self.lvms[0].ip]],
'after': [[self.lvms[1].mac, self.lvms[1].ip]],
'before': [(self.lvms[0].mac, self.lvms[0].ip)],
'after': [(self.lvms[1].mac, self.lvms[1].ip)],
},
},
}

View File

@ -16,6 +16,7 @@
import contextlib
import mock
from neutron.agent import l2population_rpc
from neutron.common import constants
from neutron.common import topics
from neutron import context
@ -26,6 +27,7 @@ from neutron import manager
from neutron.openstack.common import timeutils
from neutron.plugins.ml2 import config as config
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 import managers
from neutron.plugins.ml2 import rpc
from neutron.tests.unit import test_db_plugin as test_plugin
@ -92,6 +94,8 @@ PLUGIN_NAME = 'neutron.plugins.ml2.plugin.Ml2Plugin'
NOTIFIER = 'neutron.plugins.ml2.rpc.AgentNotifierApi'
DEVICE_OWNER_COMPUTE = 'compute:None'
FLOODING_ENTRY_AS_LIST = list(constants.FLOODING_ENTRY)
class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
@ -167,6 +171,48 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
agent_state={'agent_state': L2_AGENT_5},
time=timeutils.strtime())
def test_port_info_compare(self):
# An assumption the code makes is that PortInfo compares equal to
# equivalent regular tuples.
self.assertEqual(("mac", "ip"), l2pop_rpc.PortInfo("mac", "ip"))
flooding_entry = l2pop_rpc.PortInfo(*constants.FLOODING_ENTRY)
self.assertEqual(constants.FLOODING_ENTRY, flooding_entry)
def test__unmarshall_fdb_entries(self):
entries = {'foouuid': {
'segment_id': 1001,
'ports': {'192.168.0.10': [['00:00:00:00:00:00', '0.0.0.0'],
['fa:16:3e:ff:8c:0f', '10.0.0.6']]},
'network_type': 'vxlan'}}
mixin = l2population_rpc.L2populationRpcCallBackMixin
entries = mixin._unmarshall_fdb_entries(entries)
port_info_list = entries['foouuid']['ports']['192.168.0.10']
# Check that the lists have been properly converted to PortInfo
self.assertIsInstance(port_info_list[0], l2pop_rpc.PortInfo)
self.assertIsInstance(port_info_list[1], l2pop_rpc.PortInfo)
self.assertEqual(('00:00:00:00:00:00', '0.0.0.0'), port_info_list[0])
self.assertEqual(('fa:16:3e:ff:8c:0f', '10.0.0.6'), port_info_list[1])
def test__marshall_fdb_entries(self):
entries = {'foouuid': {
'segment_id': 1001,
'ports': {'192.168.0.10': [('00:00:00:00:00:00', '0.0.0.0'),
('fa:16:3e:ff:8c:0f', '10.0.0.6')]},
'network_type': 'vxlan'}}
entries = l2pop_rpc.L2populationAgentNotifyAPI._marshall_fdb_entries(
entries)
port_info_list = entries['foouuid']['ports']['192.168.0.10']
# Check that the PortInfo tuples have been converted to list
self.assertIsInstance(port_info_list[0], list)
self.assertIsInstance(port_info_list[1], list)
self.assertEqual(['00:00:00:00:00:00', '0.0.0.0'], port_info_list[0])
self.assertEqual(['fa:16:3e:ff:8c:0f', '10.0.0.6'], port_info_list[1])
def test_fdb_add_called(self):
self._register_ml2_agents()
@ -193,7 +239,7 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{'fdb_entries':
{p1['network_id']:
{'ports':
{'20.0.0.1': [constants.FLOODING_ENTRY,
{'20.0.0.1': [FLOODING_ENTRY_AS_LIST,
[p1['mac_address'],
p1_ips[0]]]},
'network_type': 'vxlan',
@ -253,7 +299,7 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{'fdb_entries':
{p1['network_id']:
{'ports':
{'20.0.0.5': [constants.FLOODING_ENTRY,
{'20.0.0.5': [FLOODING_ENTRY_AS_LIST,
[p1['mac_address'],
p1_ips[0]]]},
'network_type': 'vlan',
@ -299,7 +345,7 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{'fdb_entries':
{p1['network_id']:
{'ports':
{'20.0.0.2': [constants.FLOODING_ENTRY,
{'20.0.0.2': [FLOODING_ENTRY_AS_LIST,
[p2['mac_address'],
p2_ips[0]]]},
'network_type': 'vxlan',
@ -320,7 +366,7 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{'fdb_entries':
{p1['network_id']:
{'ports':
{'20.0.0.1': [constants.FLOODING_ENTRY,
{'20.0.0.1': [FLOODING_ENTRY_AS_LIST,
[p1['mac_address'],
p1_ips[0]]]},
'network_type': 'vxlan',
@ -368,7 +414,7 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{p1['network_id']:
{'ports':
{'20.0.0.2':
[constants.FLOODING_ENTRY,
[FLOODING_ENTRY_AS_LIST,
[p1['mac_address'],
p1_ips[0]]]},
'network_type': 'vxlan',
@ -392,7 +438,7 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{p1['network_id']:
{'ports':
{'20.0.0.1':
[constants.FLOODING_ENTRY,
[FLOODING_ENTRY_AS_LIST,
[p3['mac_address'],
p3_ips[0]]]},
'network_type': 'vxlan',
@ -481,7 +527,7 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{'fdb_entries':
{p2['network_id']:
{'ports':
{'20.0.0.1': [constants.FLOODING_ENTRY,
{'20.0.0.1': [FLOODING_ENTRY_AS_LIST,
[p2['mac_address'],
p2_ips[0]]]},
'network_type': 'vxlan',
@ -562,7 +608,7 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{'fdb_entries':
{p1['network_id']:
{'ports':
{'20.0.0.1': [constants.FLOODING_ENTRY,
{'20.0.0.1': [FLOODING_ENTRY_AS_LIST,
[p1['mac_address'],
p1_ips[0]]]},
'network_type': 'vxlan',
@ -604,8 +650,8 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{'chg_ip':
{p1['network_id']:
{'20.0.0.1':
{'after': [[p1['mac_address'],
'10.0.0.10']]}}}}},
{'after': [(p1['mac_address'],
'10.0.0.10')]}}}}},
'namespace': None,
'method': 'update_fdb_entries'}
@ -626,10 +672,10 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{'chg_ip':
{p1['network_id']:
{'20.0.0.1':
{'before': [[p1['mac_address'],
'10.0.0.10']],
'after': [[p1['mac_address'],
'10.0.0.16']]}}}}},
{'before': [(p1['mac_address'],
'10.0.0.10')],
'after': [(p1['mac_address'],
'10.0.0.16')]}}}}},
'namespace': None,
'method': 'update_fdb_entries'}
@ -649,8 +695,8 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{'chg_ip':
{p1['network_id']:
{'20.0.0.1':
{'before': [[p1['mac_address'],
'10.0.0.2']]}}}}},
{'before': [(p1['mac_address'],
'10.0.0.2')]}}}}},
'namespace': None,
'method': 'update_fdb_entries'}
@ -728,7 +774,7 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{'fdb_entries':
{p1['network_id']:
{'ports':
{'20.0.0.1': [constants.FLOODING_ENTRY,
{'20.0.0.1': [FLOODING_ENTRY_AS_LIST,
[p1['mac_address'],
p1_ips[0]]]},
'network_type': 'vxlan',
@ -786,7 +832,7 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
{'fdb_entries':
{p1['network_id']:
{'ports':
{'20.0.0.1': [constants.FLOODING_ENTRY,
{'20.0.0.1': [FLOODING_ENTRY_AS_LIST,
[p1['mac_address'],
p1_ips[0]]]},
'network_type': 'vxlan',
@ -809,4 +855,4 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
'remove_fdb_entries')) as (upd_port_down,
rem_fdb_entries):
l2pop_mech.delete_port_postcommit(mock.Mock())
self.assertTrue(upd_port_down.called)
self.assertTrue(upd_port_down.called)

View File

@ -33,10 +33,12 @@ from neutron.agent.linux import utils
from neutron.common import constants as n_const
from neutron.openstack.common import importutils
from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2.drivers.l2pop import rpc as l2pop_rpc
from neutron.tests.unit.ofagent import ofa_test_base
NOTIFIER = ('neutron.plugins.ml2.rpc.AgentNotifierApi')
FLOODING_ENTRY = l2pop_rpc.PortInfo(*n_const.FLOODING_ENTRY)
def _mock_port(is_neutron=True, normalized_name=None):
@ -560,8 +562,8 @@ class TestOFANeutronAgent(ofa_test_base.OFAAgentTestBase):
'segment_id': 'tun2',
'ports':
{'agent_ip':
[['mac', 'ip'],
n_const.FLOODING_ENTRY]}}}
[l2pop_rpc.PortInfo('mac', 'ip'),
FLOODING_ENTRY]}}}
with contextlib.nested(
mock.patch.object(self.agent.ryuapp, "add_arp_table_entry"),
mock.patch.object(self.agent.ryuapp, "del_arp_table_entry"),
@ -580,8 +582,8 @@ class TestOFANeutronAgent(ofa_test_base.OFAAgentTestBase):
'segment_id': 'tun1',
'ports':
{self.lvms[1].ip:
[['mac', 'ip'],
n_const.FLOODING_ENTRY]}}}
[l2pop_rpc.PortInfo('mac', 'ip'),
FLOODING_ENTRY]}}}
with contextlib.nested(
mock.patch.object(self.agent, '_setup_tunnel_port'),
mock.patch.object(self.agent.int_br, 'install_tunnel_output'),
@ -604,8 +606,8 @@ class TestOFANeutronAgent(ofa_test_base.OFAAgentTestBase):
'segment_id': 'tun2',
'ports':
{self.lvms[1].ip:
[['mac', 'ip'],
n_const.FLOODING_ENTRY]}}}
[l2pop_rpc.PortInfo('mac', 'ip'),
FLOODING_ENTRY]}}}
with contextlib.nested(
mock.patch.object(self.agent.int_br, 'install_tunnel_output'),
mock.patch.object(self.agent.int_br, 'delete_tunnel_output'),
@ -623,11 +625,13 @@ class TestOFANeutronAgent(ofa_test_base.OFAAgentTestBase):
fdb_entry = {self.lvms[0].net:
{'network_type': self.tunnel_type,
'segment_id': 'tun1',
'ports': {self.lvms[0].ip: [['mac', 'ip']]}}}
'ports': {self.lvms[0].ip: [l2pop_rpc.PortInfo('mac',
'ip')]}}}
with mock.patch.object(self.agent, '_setup_tunnel_port') as add_tun_fn:
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(add_tun_fn.called)
fdb_entry[self.lvms[0].net]['ports'][tunnel_ip] = [['mac', 'ip']]
fdb_entry[self.lvms[0].net]['ports'][tunnel_ip] = [
l2pop_rpc.PortInfo('mac', 'ip')]
self.agent.fdb_add(None, fdb_entry)
add_tun_fn.assert_called_with(
self.agent.int_br, tun_name, tunnel_ip, self.tunnel_type)
@ -637,7 +641,7 @@ class TestOFANeutronAgent(ofa_test_base.OFAAgentTestBase):
fdb_entry = {self.lvms[1].net:
{'network_type': self.tunnel_type,
'segment_id': 'tun2',
'ports': {self.lvms[1].ip: [n_const.FLOODING_ENTRY]}}}
'ports': {self.lvms[1].ip: [FLOODING_ENTRY]}}}
with mock.patch.object(self.agent.int_br,
'delete_port') as del_port_fn:
self.agent.fdb_remove(None, fdb_entry)
@ -648,11 +652,14 @@ class TestOFANeutronAgent(ofa_test_base.OFAAgentTestBase):
fdb_entry = {self.lvms[0].net:
{'network_type': self.tunnel_type,
'segment_id': 'tun1',
'ports': {self.lvms[0].ip: [n_const.FLOODING_ENTRY,
['mac1', 'ip1']],
self.lvms[1].ip: [['mac2', 'ip2']],
'192.0.2.1': [n_const.FLOODING_ENTRY,
['mac3', 'ip3']]}}}
'ports': {self.lvms[0].ip: [
FLOODING_ENTRY,
l2pop_rpc.PortInfo('mac1', 'ip1')],
self.lvms[1].ip: [
l2pop_rpc.PortInfo('mac2', 'ip2')],
'192.0.2.1': [
FLOODING_ENTRY,
l2pop_rpc.PortInfo('mac3', 'ip3')]}}}
with mock.patch.object(self.agent,
'setup_tunnel_port') as setup_tun_fn:
self.agent.fdb_add(None, fdb_entry)
@ -671,11 +678,14 @@ class TestOFANeutronAgent(ofa_test_base.OFAAgentTestBase):
fdb_entry = {self.lvms[0].net:
{'network_type': network_type,
'segment_id': 'tun1',
'ports': {self.lvms[0].ip: [n_const.FLOODING_ENTRY,
['mac1', 'ip1']],
self.lvms[1].ip: [['mac2', 'ip2']],
'192.0.2.1': [n_const.FLOODING_ENTRY,
['mac3', 'ip3']]}}}
'ports': {self.lvms[0].ip: [
FLOODING_ENTRY,
l2pop_rpc.PortInfo('mac1', 'ip1')],
self.lvms[1].ip: [
l2pop_rpc.PortInfo('mac2', 'ip2')],
'192.0.2.1': [
FLOODING_ENTRY,
l2pop_rpc.PortInfo('mac3', 'ip3')]}}}
with mock.patch.object(self.agent,
'setup_tunnel_port') as setup_tun_fn:
self.agent.fdb_add(None, fdb_entry)
@ -702,11 +712,14 @@ class TestOFANeutronAgent(ofa_test_base.OFAAgentTestBase):
fdb_entry = {self.lvms[0].net:
{'network_type': self.tunnel_type,
'segment_id': 'tun1',
'ports': {self.lvms[0].ip: [n_const.FLOODING_ENTRY,
['mac1', 'ip1']],
self.lvms[1].ip: [['mac2', 'ip2']],
'192.0.2.1': [n_const.FLOODING_ENTRY,
['mac3', 'ip3']]}}}
'ports': {self.lvms[0].ip: [
FLOODING_ENTRY,
l2pop_rpc.PortInfo('mac1', 'ip1')],
self.lvms[1].ip: [
l2pop_rpc.PortInfo('mac2', 'ip2')],
'192.0.2.1': [
FLOODING_ENTRY,
l2pop_rpc.PortInfo('mac3', 'ip3')]}}}
with mock.patch.object(self.agent,
'cleanup_tunnel_port') as cleanup_tun_fn:
self.agent.fdb_remove(None, fdb_entry)
@ -724,11 +737,14 @@ class TestOFANeutronAgent(ofa_test_base.OFAAgentTestBase):
fdb_entry = {self.lvms[0].net:
{'network_type': network_type,
'segment_id': 'tun1',
'ports': {self.lvms[0].ip: [n_const.FLOODING_ENTRY,
['mac1', 'ip1']],
self.lvms[1].ip: [['mac2', 'ip2']],
'192.0.2.1': [n_const.FLOODING_ENTRY,
['mac3', 'ip3']]}}}
'ports': {self.lvms[0].ip: [
FLOODING_ENTRY,
l2pop_rpc.PortInfo('mac1', 'ip1')],
self.lvms[1].ip: [
l2pop_rpc.PortInfo('mac2', 'ip2')],
'192.0.2.1': [
FLOODING_ENTRY,
l2pop_rpc.PortInfo('mac3', 'ip3')]}}}
with mock.patch.object(self.agent,
'cleanup_tunnel_port') as cleanup_tun_fn:
self.agent.fdb_remove(None, fdb_entry)

View File

@ -27,6 +27,7 @@ from neutron.agent.linux import utils
from neutron.common import constants as n_const
from neutron.openstack.common import log
from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2.drivers.l2pop import rpc as l2pop_rpc
from neutron.plugins.openvswitch.agent import ovs_neutron_agent
from neutron.plugins.openvswitch.common import constants
from neutron.tests import base
@ -1030,7 +1031,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
'segment_id': 'tun2',
'ports':
{'agent_ip':
[[FAKE_MAC, FAKE_IP1],
[l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1),
n_const.FLOODING_ENTRY]}}}
with mock.patch.object(self.agent.tun_br,
"deferred") as defer_fn:
@ -1047,7 +1048,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
'segment_id': 'tun1',
'ports':
{'2.2.2.2':
[[FAKE_MAC, FAKE_IP1],
[l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1),
n_const.FLOODING_ENTRY]}}}
class ActionMatcher(object):
@ -1102,7 +1103,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
'segment_id': 'tun2',
'ports':
{'2.2.2.2':
[[FAKE_MAC, FAKE_IP1],
[l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1),
n_const.FLOODING_ENTRY]}}}
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'deferred'),
@ -1132,7 +1133,8 @@ class TestOvsNeutronAgent(base.BaseTestCase):
fdb_entry = {'net1':
{'network_type': 'gre',
'segment_id': 'tun1',
'ports': {'1.1.1.1': [[FAKE_MAC, FAKE_IP1]]}}}
'ports': {'1.1.1.1': [l2pop_rpc.PortInfo(FAKE_MAC,
FAKE_IP1)]}}}
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'deferred'),
mock.patch.object(self.agent.tun_br, 'do_action_flows'),
@ -1142,7 +1144,8 @@ class TestOvsNeutronAgent(base.BaseTestCase):
deferred_fn.return_value = deferred_br
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(add_tun_fn.called)
fdb_entry['net1']['ports']['10.10.10.10'] = [[FAKE_MAC, FAKE_IP1]]
fdb_entry['net1']['ports']['10.10.10.10'] = [
l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1)]
self.agent.fdb_add(None, fdb_entry)
add_tun_fn.assert_called_with(
deferred_br, 'gre-0a0a0a0a', '10.10.10.10', 'gre')
@ -1168,8 +1171,8 @@ class TestOvsNeutronAgent(base.BaseTestCase):
fdb_entries = {'chg_ip':
{'net1':
{'agent_ip':
{'before': [[FAKE_MAC, FAKE_IP1]],
'after': [[FAKE_MAC, FAKE_IP2]]}}}}
{'before': [l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1)],
'after': [l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP2)]}}}}
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'deferred'),
mock.patch.object(self.agent.tun_br, 'do_action_flows'),