diff --git a/neutron/agent/l2population_rpc.py b/neutron/agent/l2population_rpc.py index c94d29bb1b..2ffcd2be40 100644 --- a/neutron/agent/l2population_rpc.py +++ b/neutron/agent/l2population_rpc.py @@ -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: + { + : { + ..., + 'ports': { + : [ [, ], ... ], + ... + + :returns: Deep copy with [, ] 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): @@ -97,9 +124,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. @@ -117,8 +145,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 a network. See add_fdb_flow for more explanation. @@ -249,13 +279,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. :param local_vlan_map: A dict to map network_id to the corresponding lvm entry. @@ -271,11 +304,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) diff --git a/neutron/common/constants.py b/neutron/common/constants.py index e424450d25..fc82056696 100644 --- a/neutron/common/constants.py +++ b/neutron/common/constants.py @@ -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') TYPE_BOOL = "bool" TYPE_INT = "int" diff --git a/neutron/plugins/ml2/drivers/l2pop/mech_driver.py b/neutron/plugins/ml2/drivers/l2pop/mech_driver.py index c85acb1c73..75c8f0d063 100644 --- a/neutron/plugins/ml2/drivers/l2pop/mech_driver.py +++ b/neutron/plugins/ml2/drivers/l2pop/mech_driver.py @@ -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: {}}} diff --git a/neutron/plugins/ml2/drivers/l2pop/rpc.py b/neutron/plugins/ml2/drivers/l2pop/rpc.py index 8b5efacf29..95341cca50 100644 --- a/neutron/plugins/ml2/drivers/l2pop/rpc.py +++ b/neutron/plugins/ml2/drivers/l2pop/rpc.py @@ -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: + { + : { + ..., + 'ports': { + : [ 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 diff --git a/neutron/plugins/ofagent/agent/ofa_neutron_agent.py b/neutron/plugins/ofagent/agent/ofa_neutron_agent.py index bbfe28e602..f311b05975 100644 --- a/neutron/plugins/ofagent/agent/ofa_neutron_agent.py +++ b/neutron/plugins/ofagent/agent/ofa_neutron_agent.py @@ -373,8 +373,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): @@ -382,7 +383,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: @@ -393,11 +394,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: @@ -412,9 +415,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): diff --git a/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py index fadeb9ab8d..1f6fa043e8 100644 --- a/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py @@ -382,12 +382,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)) @@ -405,10 +406,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") diff --git a/neutron/tests/unit/agent/l2population_rpc_base.py b/neutron/tests/unit/agent/l2population_rpc_base.py index c9c22de0ff..8ce6482130 100644 --- a/neutron/tests/unit/agent/l2population_rpc_base.py +++ b/neutron/tests/unit/agent/l2population_rpc_base.py @@ -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)], }, }, } diff --git a/neutron/tests/unit/agent/test_l2population_rpc.py b/neutron/tests/unit/agent/test_l2population_rpc.py index 563c53b19d..b0b8f7e490 100644 --- a/neutron/tests/unit/agent/test_l2population_rpc.py +++ b/neutron/tests/unit/agent/test_l2population_rpc.py @@ -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)], }, }, } diff --git a/neutron/tests/unit/ml2/drivers/test_l2population.py b/neutron/tests/unit/ml2/drivers/test_l2population.py index fa5a8be995..70aa4945a7 100644 --- a/neutron/tests/unit/ml2/drivers/test_l2population.py +++ b/neutron/tests/unit/ml2/drivers/test_l2population.py @@ -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 @@ -25,6 +26,7 @@ from neutron.extensions import providernet as pnet from neutron import manager from neutron.openstack.common import timeutils 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.ml2 import test_ml2_plugin as test_plugin @@ -90,6 +92,8 @@ L2_AGENT_5 = { NOTIFIER = 'neutron.plugins.ml2.rpc.AgentNotifierApi' DEVICE_OWNER_COMPUTE = 'compute:None' +FLOODING_ENTRY_AS_LIST = list(constants.FLOODING_ENTRY) + class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): _mechanism_drivers = ['openvswitch', 'linuxbridge', @@ -157,6 +161,48 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): 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() @@ -183,7 +229,7 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {'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', @@ -243,7 +289,7 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {'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', @@ -289,7 +335,7 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {'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', @@ -310,7 +356,7 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {'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', @@ -358,7 +404,7 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {p1['network_id']: {'ports': {'20.0.0.2': - [constants.FLOODING_ENTRY, + [FLOODING_ENTRY_AS_LIST, [p1['mac_address'], p1_ips[0]]]}, 'network_type': 'vxlan', @@ -382,7 +428,7 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {p1['network_id']: {'ports': {'20.0.0.1': - [constants.FLOODING_ENTRY, + [FLOODING_ENTRY_AS_LIST, [p3['mac_address'], p3_ips[0]]]}, 'network_type': 'vxlan', @@ -471,7 +517,7 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {'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', @@ -552,7 +598,7 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {'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', @@ -594,8 +640,8 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {'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'} @@ -616,10 +662,10 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {'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'} @@ -639,8 +685,8 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {'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'} @@ -718,7 +764,7 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {'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', @@ -776,7 +822,7 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): {'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', @@ -799,4 +845,4 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase): 'remove_fdb_entries')) as (upd_port_down, rem_fdb_entries): l2pop_mech.delete_port_postcommit(mock.Mock()) - self.assertTrue(upd_port_down.called) \ No newline at end of file + self.assertTrue(upd_port_down.called) diff --git a/neutron/tests/unit/ofagent/test_ofa_neutron_agent.py b/neutron/tests/unit/ofagent/test_ofa_neutron_agent.py index 8113e15184..55c105168b 100644 --- a/neutron/tests/unit/ofagent/test_ofa_neutron_agent.py +++ b/neutron/tests/unit/ofagent/test_ofa_neutron_agent.py @@ -31,10 +31,12 @@ import testtools 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): @@ -512,8 +514,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"), @@ -532,8 +534,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'), @@ -556,8 +558,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'), @@ -575,11 +577,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) @@ -589,7 +593,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) @@ -600,11 +604,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) @@ -624,11 +631,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) @@ -656,11 +666,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) @@ -679,11 +692,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) diff --git a/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py b/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py index d1a7131b05..c39f1cdc18 100644 --- a/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py +++ b/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py @@ -28,6 +28,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 @@ -1092,7 +1093,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: @@ -1109,7 +1110,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): @@ -1164,7 +1165,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'), @@ -1194,7 +1195,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'), @@ -1204,7 +1206,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') @@ -1230,8 +1233,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'),