]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
OFAgent: Share codes of l2-population in OVS agent
authorfumihiko kakuma <kakuma@valinux.co.jp>
Tue, 15 Apr 2014 02:54:50 +0000 (11:54 +0900)
committerfumihiko kakuma <kakuma@valinux.co.jp>
Wed, 23 Jul 2014 00:00:13 +0000 (09:00 +0900)
This is step 1 implementation of OFAgent l2-population.
OFAgent partially uses codes in OVS agent on implementation of l2-population.
We share these codes adding mixin class for OVS to l2-population rpc.
We use a ryu library instead of executing a ovs-vsctl command
and on OFAgent l2-population is no longer optional.
Also a function of local arp responder will be implemented on step 2.

related commit: b6133c35dd587f6b01e8ec12757347b2767713a6

Partially implements: blueprint ofagent-l2pop

Change-Id: I99a2adfd380a9fefe34c53e0dabc21d8cf5936cc

neutron/agent/l2population_rpc.py
neutron/plugins/ml2/drivers/l2pop/constants.py
neutron/plugins/ofagent/agent/ofa_neutron_agent.py
neutron/plugins/openvswitch/agent/ovs_neutron_agent.py
neutron/tests/unit/agent/l2population_rpc_base.py [new file with mode: 0644]
neutron/tests/unit/agent/test_l2population_rpc.py [new file with mode: 0644]
neutron/tests/unit/ofagent/test_ofa_neutron_agent.py
neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py

index 80c5a97de00629e8ee3bf7fe772bed1cd06a72e8..3a8ad309fe90e24517ad29b9fb655346abe9b434 100644 (file)
@@ -22,11 +22,22 @@ import abc
 from oslo.config import cfg
 import six
 
+from neutron.common import constants as n_const
 from neutron.common import log
+from neutron.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
 
 
 @six.add_metaclass(abc.ABCMeta)
 class L2populationRpcCallBackMixin(object):
+    '''General mixin class of L2-population RPC call back.
+
+    The following methods are called through RPC.
+        add_fdb_entries(), remove_fdb_entries(), update_fdb_entries()
+    The following methods are used in a agent as an internal method.
+        fdb_add(), fdb_remove(), fdb_update()
+    '''
 
     @log.log
     def add_fdb_entries(self, context, fdb_entries, host=None):
@@ -54,3 +65,118 @@ class L2populationRpcCallBackMixin(object):
     @abc.abstractmethod
     def fdb_update(self, context, fdb_entries):
         pass
+
+
+class L2populationRpcCallBackTunnelMixin(L2populationRpcCallBackMixin):
+    '''Mixin class of L2-population call back for Tunnel.
+
+    The following all methods are used in a agent as an internal method.
+    '''
+
+    @abc.abstractmethod
+    def add_fdb_flow(self, port_info, remote_ip, lvm, ofport):
+        '''Add flow for fdb
+
+        This method assumes to be used by method fdb_add_tun.
+        We expect to add a flow entry to send a packet to specified port
+        on bridge.
+        And you may edit some information for local arp respond.
+
+        :param port_info: list to include mac and ip.
+            [mac, ip]
+        :remote_ip: remote ip address.
+        :param lvm: a local VLAN map of network.
+        :param ofport: a port to add.
+        '''
+        pass
+
+    @abc.abstractmethod
+    def del_fdb_flow(self, port_info, remote_ip, lvm, ofport):
+        '''Delete flow for fdb
+
+        This method assumes to be used by method fdb_remove_tun.
+        We expect to delete a flow entry to send a packet to specified port
+        from bridge.
+        And you may delete some information for local arp respond.
+
+        :param port_info: a list to contain mac and ip.
+            [mac, ip]
+        :remote_ip: remote ip address.
+        :param lvm: local VLAN map of network.
+        :param ofport: a port to delete.
+        '''
+        pass
+
+    @abc.abstractmethod
+    def setup_tunnel_port(self, remote_ip, network_type):
+        '''Setup an added tunnel port.
+
+        This method assumes to be used by method fdb_add_tun.
+        We expect to prepare to call add_fdb_flow. It will be mainly adding
+        a port to a bridge.
+        If you need, you may do some preparation for a bridge.
+
+        :param remote_ip: an ip for port to setup.
+        :param network_type: a type of network.
+        :returns: a ofport value. the value 0 means to be unavailable port.
+        '''
+        pass
+
+    @abc.abstractmethod
+    def cleanup_tunnel_port(self, tun_ofport, tunnel_type):
+        '''Clean up a deleted tunnel port.
+
+        This method assumes to be used by method fdb_remove_tun.
+        We expect to clean up after calling del_fdb_flow. It will be mainly
+        deleting a port from a bridge.
+        If you need, you may do some cleanup for a bridge.
+
+        :param tun_ofport: a port value to cleanup.
+        :param tunnel_type: a type of tunnel.
+        '''
+        pass
+
+    def get_agent_ports(self, fdb_entries, local_vlan_map):
+        for network_id, values in fdb_entries.items():
+            lvm = local_vlan_map.get(network_id)
+            agent_ports = values.get('ports') if lvm else {}
+            yield (lvm, agent_ports)
+
+    @log.log
+    def fdb_add_tun(self, context, lvm, agent_ports, ofports):
+        for remote_ip, ports in agent_ports.items():
+            # Ensure we have a tunnel port with this remote agent
+            ofport = ofports[lvm.network_type].get(remote_ip)
+            if not ofport:
+                ofport = self.setup_tunnel_port(remote_ip, lvm.network_type)
+                if ofport == 0:
+                    continue
+            for port in ports:
+                self.add_fdb_flow(port, remote_ip, lvm, ofport)
+
+    @log.log
+    def fdb_remove_tun(self, context, lvm, agent_ports, ofports):
+        for remote_ip, ports in agent_ports.items():
+            ofport = ofports[lvm.network_type].get(remote_ip)
+            if not ofport:
+                continue
+            for port in ports:
+                self.del_fdb_flow(port, remote_ip, lvm, ofport)
+                if port == n_const.FLOODING_ENTRY:
+                    # Check if this tunnel port is still used
+                    self.cleanup_tunnel_port(ofport, lvm.network_type)
+
+    @log.log
+    def fdb_update(self, context, fdb_entries):
+        '''Call methods named '_fdb_<action>'.
+
+        This method assumes that methods '_fdb_<action>' are defined in class.
+        Currently the following actions are available.
+            chg_ip
+        '''
+        for action, values in fdb_entries.items():
+            method = '_fdb_' + action
+            if not hasattr(self, method):
+                raise NotImplementedError()
+
+            getattr(self, method)(context, values)
index 2c9b7f96fe9468d847f33df2073eb68b48e72a2b..9ea7b387a29fe83db76d31b4935765e6ee700b11 100644 (file)
@@ -20,4 +20,5 @@
 from neutron.common import constants
 
 SUPPORTED_AGENT_TYPES = [constants.AGENT_TYPE_OVS,
-                         constants.AGENT_TYPE_LINUXBRIDGE]
+                         constants.AGENT_TYPE_LINUXBRIDGE,
+                         constants.AGENT_TYPE_OFA]
index f5b497a755cf58aa9bd835ab652b6bb18d250d70..a8bc29d69322dd1a55d612803f3a23910f193cae 100644 (file)
@@ -26,6 +26,7 @@ from ryu.base import app_manager
 from ryu.lib import hub
 from ryu.ofproto import ofproto_v1_3 as ryu_ofp13
 
+from neutron.agent import l2population_rpc
 from neutron.agent.linux import ip_lib
 from neutron.agent.linux import ovs_lib
 from neutron.agent.linux import polling
@@ -161,13 +162,16 @@ class OFANeutronAgentRyuApp(app_manager.RyuApp):
 
 
 class OFANeutronAgent(n_rpc.RpcCallback,
-                      sg_rpc.SecurityGroupAgentRpcCallbackMixin):
+                      sg_rpc.SecurityGroupAgentRpcCallbackMixin,
+                      l2population_rpc.L2populationRpcCallBackTunnelMixin):
     """A agent for OpenFlow Agent ML2 mechanism driver.
 
     OFANeutronAgent is a OpenFlow Agent agent for a ML2 plugin.
     This is as a ryu application thread.
+    This has the following features.
     - An agent acts as an OpenFlow controller on each compute nodes.
     - OpenFlow 1.3 (vendor agnostic unlike OVS extensions).
+    - l2-population is mandatory.
     """
 
     # history
@@ -178,8 +182,7 @@ class OFANeutronAgent(n_rpc.RpcCallback,
     def __init__(self, ryuapp, integ_br, tun_br, local_ip,
                  bridge_mappings, root_helper,
                  polling_interval, tunnel_types=None,
-                 veth_mtu=None, l2_population=False,
-                 minimize_polling=False,
+                 veth_mtu=None, minimize_polling=False,
                  ovsdb_monitor_respawn_interval=(
                      constants.DEFAULT_OVSDBMON_RESPAWN)):
         """Constructor.
@@ -208,7 +211,6 @@ class OFANeutronAgent(n_rpc.RpcCallback,
         self.available_local_vlans = set(xrange(n_const.MIN_VLAN_TAG,
                                                 n_const.MAX_VLAN_TAG))
         self.tunnel_types = tunnel_types or []
-        self.l2_pop = l2_population
         self.agent_state = {
             'binary': 'neutron-ofa-agent',
             'host': cfg.CONF.host,
@@ -216,7 +218,7 @@ class OFANeutronAgent(n_rpc.RpcCallback,
             'configurations': {'bridge_mappings': bridge_mappings,
                                'tunnel_types': self.tunnel_types,
                                'tunneling_ip': local_ip,
-                               'l2_population': self.l2_pop},
+                               'l2_population': True},
             'agent_type': n_const.AGENT_TYPE_OFA,
             'start_flag': True}
 
@@ -291,8 +293,8 @@ class OFANeutronAgent(n_rpc.RpcCallback,
         # Define the listening consumers for the agent
         consumers = [[topics.PORT, topics.UPDATE],
                      [topics.NETWORK, topics.DELETE],
-                     [constants.TUNNEL, topics.UPDATE],
-                     [topics.SECURITY_GROUP, topics.UPDATE]]
+                     [topics.SECURITY_GROUP, topics.UPDATE],
+                     [topics.L2POPULATION, topics.UPDATE, cfg.CONF.host]]
         self.connection = agent_rpc.create_consumers(self.endpoints,
                                                      self.topic,
                                                      consumers)
@@ -341,45 +343,100 @@ class OFANeutronAgent(n_rpc.RpcCallback,
         # they are not used since there is no guarantee the notifications
         # are processed in the same order as the relevant API requests
         self.updated_ports.add(ports.get_normalized_port_name(port['id']))
-        LOG.debug(_("port_update received port %s"), port['id'])
+        LOG.debug("port_update received port %s", port['id'])
+
+    def fdb_add(self, context, fdb_entries):
+        LOG.debug("fdb_add received")
+        for lvm, agent_ports in self.get_agent_ports(fdb_entries,
+                                                     self.local_vlan_map):
+            agent_ports.pop(self.local_ip, None)
+            if len(agent_ports):
+                self.fdb_add_tun(context, lvm, agent_ports,
+                                 self.tun_br_ofports)
+
+    def fdb_remove(self, context, fdb_entries):
+        LOG.debug("fdb_remove received")
+        for lvm, agent_ports in self.get_agent_ports(fdb_entries,
+                                                     self.local_vlan_map):
+            agent_ports.pop(self.local_ip, None)
+            if len(agent_ports):
+                self.fdb_remove_tun(context, lvm, agent_ports,
+                                    self.tun_br_ofports)
+
+    def _add_fdb_flooding_flow(self, lvm):
+        datapath = self.tun_br.datapath
+        ofp = datapath.ofproto
+        ofpp = datapath.ofproto_parser
+        match = ofpp.OFPMatch(
+            vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT)
+        actions = [ofpp.OFPActionPopVlan(),
+                   ofpp.OFPActionSetField(
+                       tunnel_id=int(lvm.segmentation_id))]
+        for tun_ofport in lvm.tun_ofports:
+            actions.append(ofpp.OFPActionOutput(int(tun_ofport), 0))
+        instructions = [ofpp.OFPInstructionActions(
+                        ofp.OFPIT_APPLY_ACTIONS, actions)]
+        msg = ofpp.OFPFlowMod(datapath,
+                              table_id=constants.FLOOD_TO_TUN,
+                              command=ofp.OFPFC_ADD,
+                              priority=1,
+                              match=match, instructions=instructions)
+        self.ryu_send_msg(msg)
 
-    def tunnel_update(self, context, **kwargs):
-        LOG.debug(_("tunnel_update received"))
-        if not self.enable_tunneling:
-            return
-        tunnel_ip = kwargs.get('tunnel_ip')
-        tunnel_type = kwargs.get('tunnel_type')
-        if not tunnel_type:
-            LOG.error(_("No tunnel_type specified, cannot create tunnels"))
-            return
-        if tunnel_type not in self.tunnel_types:
-            LOG.error(_("tunnel_type %s not supported by agent"), tunnel_type)
-            return
-        if tunnel_ip == self.local_ip:
-            return
-        tun_name = self._create_tunnel_port_name(tunnel_type, tunnel_ip)
-        if not tun_name:
-            return
-        self.setup_tunnel_port(tun_name, tunnel_ip, tunnel_type)
+    def add_fdb_flow(self, port_info, remote_ip, lvm, ofport):
+        datapath = self.tun_br.datapath
+        ofp = datapath.ofproto
+        ofpp = datapath.ofproto_parser
+        if port_info == n_const.FLOODING_ENTRY:
+            lvm.tun_ofports.add(ofport)
+            self._add_fdb_flooding_flow(lvm)
+        else:
+            match = ofpp.OFPMatch(
+                vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT,
+                eth_dst=port_info[0])
+            actions = [ofpp.OFPActionPopVlan(),
+                       ofpp.OFPActionSetField(
+                           tunnel_id=int(lvm.segmentation_id)),
+                       ofpp.OFPActionOutput(int(ofport), 0)]
+            instructions = [ofpp.OFPInstructionActions(
+                            ofp.OFPIT_APPLY_ACTIONS, actions)]
+            msg = ofpp.OFPFlowMod(datapath,
+                                  table_id=constants.UCAST_TO_TUN,
+                                  command=ofp.OFPFC_ADD,
+                                  priority=2,
+                                  match=match, instructions=instructions)
+            self.ryu_send_msg(msg)
 
-    def _provision_local_vlan_outbound_for_tunnel(self, lvid,
-                                                  segmentation_id, ofports):
-        br = self.tun_br
-        match = br.ofparser.OFPMatch(
-            vlan_vid=int(lvid) | ryu_ofp13.OFPVID_PRESENT)
-        actions = [br.ofparser.OFPActionPopVlan(),
-                   br.ofparser.OFPActionSetField(
-                       tunnel_id=int(segmentation_id))]
-        for ofport in ofports:
-            actions.append(br.ofparser.OFPActionOutput(ofport, 0))
-        instructions = [br.ofparser.OFPInstructionActions(
-                        ryu_ofp13.OFPIT_APPLY_ACTIONS, actions)]
-        msg = br.ofparser.OFPFlowMod(
-            br.datapath,
-            table_id=constants.FLOOD_TO_TUN,
-            priority=1,
-            match=match, instructions=instructions)
-        self.ryu_send_msg(msg)
+    def del_fdb_flow(self, port_info, remote_ip, lvm, ofport):
+        datapath = self.tun_br.datapath
+        ofp = datapath.ofproto
+        ofpp = datapath.ofproto_parser
+        if port_info == n_const.FLOODING_ENTRY:
+            lvm.tun_ofports.remove(ofport)
+            if len(lvm.tun_ofports) > 0:
+                self._add_fdb_flooding_flow(lvm)
+            else:
+                # This local vlan doesn't require any more tunelling
+                match = ofpp.OFPMatch(
+                    vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT)
+                msg = ofpp.OFPFlowMod(datapath,
+                                      table_id=constants.FLOOD_TO_TUN,
+                                      command=ofp.OFPFC_DELETE,
+                                      out_group=ofp.OFPG_ANY,
+                                      out_port=ofp.OFPP_ANY,
+                                      match=match)
+                self.ryu_send_msg(msg)
+        else:
+            match = ofpp.OFPMatch(
+                vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT,
+                eth_dst=port_info[0])
+            msg = ofpp.OFPFlowMod(datapath,
+                                  table_id=constants.UCAST_TO_TUN,
+                                  command=ofp.OFPFC_DELETE,
+                                  out_group=ofp.OFPG_ANY,
+                                  out_port=ofp.OFPP_ANY,
+                                  match=match)
+            self.ryu_send_msg(msg)
 
     def _provision_local_vlan_inbound_for_tunnel(self, lvid, network_type,
                                                  segmentation_id):
@@ -404,11 +461,6 @@ class OFANeutronAgent(n_rpc.RpcCallback,
         self.ryu_send_msg(msg)
 
     def _local_vlan_for_tunnel(self, lvid, network_type, segmentation_id):
-        ofports = [int(ofport) for ofport in
-                   self.tun_br_ofports[network_type].values()]
-        if ofports:
-            self._provision_local_vlan_outbound_for_tunnel(
-                lvid, segmentation_id, ofports)
         self._provision_local_vlan_inbound_for_tunnel(lvid, network_type,
                                                       segmentation_id)
 
@@ -588,6 +640,9 @@ class OFANeutronAgent(n_rpc.RpcCallback,
                     out_port=ryu_ofp13.OFPP_ANY,
                     match=match)
                 self.ryu_send_msg(msg)
+                # Try to remove tunnel ports if not used by other networks
+                for ofport in lvm.tun_ofports:
+                    self.cleanup_tunnel_port(ofport, lvm.network_type)
         elif lvm.network_type in (p_const.TYPE_FLAT, p_const.TYPE_VLAN):
             if lvm.physical_network in self.phys_brs:
                 self._reclaim_local_vlan_outbound(lvm)
@@ -1015,7 +1070,7 @@ class OFANeutronAgent(n_rpc.RpcCallback,
         else:
             LOG.debug(_("No VIF port for port %s defined on agent."), port_id)
 
-    def setup_tunnel_port(self, port_name, remote_ip, tunnel_type):
+    def _setup_tunnel_port(self, port_name, remote_ip, tunnel_type):
         ofport = self.tun_br.add_tunnel_port(port_name,
                                              remote_ip,
                                              self.local_ip,
@@ -1044,36 +1099,45 @@ class OFANeutronAgent(n_rpc.RpcCallback,
                                               match=match,
                                               instructions=instructions)
         self.ryu_send_msg(msg)
+        return ofport
 
-        ofports = [int(p) for p in self.tun_br_ofports[tunnel_type].values()]
-        if ofports:
-            # Update flooding flows to include the new tunnel
-            for network_id, vlan_mapping in self.local_vlan_map.iteritems():
-                if vlan_mapping.network_type == tunnel_type:
-                    match = self.tun_br.ofparser.OFPMatch(
-                        vlan_vid=int(vlan_mapping.vlan) |
-                        ryu_ofp13.OFPVID_PRESENT)
-                    actions = [
-                        self.tun_br.ofparser.OFPActionPopVlan(),
-                        self.tun_br.ofparser.OFPActionSetField(
-                            tunnel_id=int(vlan_mapping.segmentation_id))]
-                    actions.extend(
-                        self.tun_br.ofparser.OFPActionOutput(p, 0)
-                        for p in ofports
-                    )
-                    instructions = [
-                        self.tun_br.ofparser.OFPInstructionActions(
-                            ryu_ofp13.OFPIT_APPLY_ACTIONS,
-                            actions)]
-                    msg = self.tun_br.ofparser.OFPFlowMod(
-                        self.tun_br.datapath,
-                        table_id=constants.FLOOD_TO_TUN,
-                        priority=1,
-                        match=match,
-                        instructions=instructions)
-                    self.ryu_send_msg(msg)
+    def setup_tunnel_port(self, remote_ip, network_type):
+        port_name = self._create_tunnel_port_name(network_type, remote_ip)
+        if not port_name:
+            return 0
+        ofport = self._setup_tunnel_port(port_name,
+                                         remote_ip,
+                                         network_type)
         return ofport
 
+    def _remove_tunnel_port(self, tun_ofport, tunnel_type):
+        datapath = self.tun_br.datapath
+        ofp = datapath.ofproto
+        ofpp = datapath.ofproto_parser
+        for remote_ip, ofport in self.tun_br_ofports[tunnel_type].items():
+            if ofport == tun_ofport:
+                port_name = self._create_tunnel_port_name(tunnel_type,
+                                                          remote_ip)
+                if port_name:
+                    self.tun_br.delete_port(port_name)
+                match = ofpp.OFPMatch(in_port=int(ofport))
+                msg = ofpp.OFPFlowMod(datapath,
+                                      command=ofp.OFPFC_DELETE,
+                                      out_group=ofp.OFPG_ANY,
+                                      out_port=ofp.OFPP_ANY,
+                                      match=match)
+                self.ryu_send_msg(msg)
+                self.tun_br_ofports[tunnel_type].pop(remote_ip, None)
+
+    def cleanup_tunnel_port(self, tun_ofport, tunnel_type):
+        # Check if this tunnel port is still used
+        for lvm in self.local_vlan_map.values():
+            if tun_ofport in lvm.tun_ofports:
+                break
+        # If not, remove it
+        else:
+            self._remove_tunnel_port(tun_ofport, tunnel_type)
+
     def treat_devices_added_or_updated(self, devices):
         resync = False
         all_ports = dict((p.normalized_port_name(), p) for p in
@@ -1245,19 +1309,9 @@ class OFANeutronAgent(n_rpc.RpcCallback,
         resync = False
         try:
             for tunnel_type in self.tunnel_types:
-                details = self.plugin_rpc.tunnel_sync(self.context,
-                                                      self.local_ip,
-                                                      tunnel_type)
-                tunnels = details['tunnels']
-                for tunnel in tunnels:
-                    if self.local_ip != tunnel['ip_address']:
-                        tun_name = self._create_tunnel_port_name(
-                            tunnel_type, tunnel['ip_address'])
-                        if not tun_name:
-                            continue
-                        self.setup_tunnel_port(tun_name,
-                                               tunnel['ip_address'],
-                                               tunnel_type)
+                self.plugin_rpc.tunnel_sync(self.context,
+                                            self.local_ip,
+                                            tunnel_type)
         except Exception as e:
             LOG.debug(_("Unable to sync tunnel IP %(local_ip)s: %(e)s"),
                       {'local_ip': self.local_ip, 'e': e})
@@ -1428,7 +1482,6 @@ def create_agent_config_map(config):
         minimize_polling=config.AGENT.minimize_polling,
         tunnel_types=config.AGENT.tunnel_types,
         veth_mtu=config.AGENT.veth_mtu,
-        l2_population=False,
         ovsdb_monitor_respawn_interval=constants.DEFAULT_OVSDBMON_RESPAWN,
     )
 
index 4f8c2b60be3137807769336ed7bf58c7b99480c2..956ef7082381e47866e9ca83f2b0a8f435398dd4 100644 (file)
@@ -97,7 +97,7 @@ class OVSSecurityGroupAgent(sg_rpc.SecurityGroupAgentRpcMixin):
 
 class OVSNeutronAgent(n_rpc.RpcCallback,
                       sg_rpc.SecurityGroupAgentRpcCallbackMixin,
-                      l2population_rpc.L2populationRpcCallBackMixin,
+                      l2population_rpc.L2populationRpcCallBackTunnelMixin,
                       dvr_rpc.DVRAgentRpcCallbackMixin):
     '''Implements OVS-based tunneling, VLANs and flat networks.
 
@@ -348,61 +348,35 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
             return
         tun_name = '%s-%s' % (tunnel_type, tunnel_id)
         if not self.l2_pop:
-            self.setup_tunnel_port(tun_name, tunnel_ip, tunnel_type)
+            self._setup_tunnel_port(tun_name, tunnel_ip, tunnel_type)
 
     def fdb_add(self, context, fdb_entries):
-        LOG.debug(_("fdb_add received"))
-        for network_id, values in fdb_entries.items():
-            lvm = self.local_vlan_map.get(network_id)
-            if not lvm:
-                # Agent doesn't manage any port in this network
-                continue
-            agent_ports = values.get('ports')
+        LOG.debug("fdb_add received")
+        for lvm, agent_ports in self.get_agent_ports(fdb_entries,
+                                                     self.local_vlan_map):
             agent_ports.pop(self.local_ip, None)
             if len(agent_ports):
                 if not self.enable_distributed_routing:
                     self.tun_br.defer_apply_on()
-                for agent_ip, ports in agent_ports.items():
-                    # Ensure we have a tunnel port with this remote agent
-                    ofport = self.tun_br_ofports[
-                        lvm.network_type].get(agent_ip)
-                    if not ofport:
-                        remote_ip_hex = self.get_ip_in_hex(agent_ip)
-                        if not remote_ip_hex:
-                            continue
-                        port_name = '%s-%s' % (lvm.network_type, remote_ip_hex)
-                        ofport = self.setup_tunnel_port(port_name, agent_ip,
-                                                        lvm.network_type)
-                        if ofport == 0:
-                            continue
-                    for port in ports:
-                        self._add_fdb_flow(port, agent_ip, lvm, ofport)
+                self.fdb_add_tun(context, lvm, agent_ports,
+                                 self.tun_br_ofports)
                 if not self.enable_distributed_routing:
                     self.tun_br.defer_apply_off()
 
     def fdb_remove(self, context, fdb_entries):
-        LOG.debug(_("fdb_remove received"))
-        for network_id, values in fdb_entries.items():
-            lvm = self.local_vlan_map.get(network_id)
-            if not lvm:
-                # Agent doesn't manage any more ports in this network
-                continue
-            agent_ports = values.get('ports')
+        LOG.debug("fdb_remove received")
+        for lvm, agent_ports in self.get_agent_ports(fdb_entries,
+                                                     self.local_vlan_map):
             agent_ports.pop(self.local_ip, None)
             if len(agent_ports):
                 if not self.enable_distributed_routing:
                     self.tun_br.defer_apply_on()
-                for agent_ip, ports in agent_ports.items():
-                    ofport = self.tun_br_ofports[
-                        lvm.network_type].get(agent_ip)
-                    if not ofport:
-                        continue
-                    for port in ports:
-                        self._del_fdb_flow(port, agent_ip, lvm, ofport)
+                self.fdb_remove_tun(context, lvm, agent_ports,
+                                    self.tun_br_ofports)
                 if not self.enable_distributed_routing:
                     self.tun_br.defer_apply_off()
 
-    def _add_fdb_flow(self, port_info, agent_ip, lvm, ofport):
+    def add_fdb_flow(self, port_info, remote_ip, lvm, ofport):
         if port_info == q_const.FLOODING_ENTRY:
             lvm.tun_ofports.add(ofport)
             ofports = ','.join(lvm.tun_ofports)
@@ -422,7 +396,7 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
                                      "output:%s" %
                                      (lvm.segmentation_id, ofport))
 
-    def _del_fdb_flow(self, port_info, agent_ip, lvm, ofport):
+    def del_fdb_flow(self, port_info, remote_ip, lvm, ofport):
         if port_info == q_const.FLOODING_ENTRY:
             lvm.tun_ofports.remove(ofport)
             if len(lvm.tun_ofports) > 0:
@@ -436,8 +410,6 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
                 # This local vlan doesn't require any more tunnelling
                 self.tun_br.delete_flows(table=constants.FLOOD_TO_TUN,
                                          dl_vlan=lvm.vlan)
-            # Check if this tunnel port is still used
-            self.cleanup_tunnel_port(ofport, lvm.network_type)
         else:
             self._set_arp_responder('remove', lvm.vlan, port_info[0],
                                     port_info[1])
@@ -486,15 +458,6 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
                 for mac, ip in before:
                     self._set_arp_responder('remove', lvm.vlan, mac, ip)
 
-    def fdb_update(self, context, fdb_entries):
-        LOG.debug(_("fdb_update received"))
-        for action, values in fdb_entries.items():
-            method = '_fdb_' + action
-            if not hasattr(self, method):
-                raise NotImplementedError()
-
-            getattr(self, method)(context, values)
-
     def _set_arp_responder(self, action, lvid, mac_str, ip_str):
         '''Set the ARP respond entry.
 
@@ -1111,7 +1074,7 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
         else:
             LOG.debug(_("No VIF port for port %s defined on agent."), port_id)
 
-    def setup_tunnel_port(self, port_name, remote_ip, tunnel_type):
+    def _setup_tunnel_port(self, port_name, remote_ip, tunnel_type):
         ofport = self.tun_br.add_tunnel_port(port_name,
                                              remote_ip,
                                              self.local_ip,
@@ -1150,6 +1113,16 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
                                           ofports))
         return ofport
 
+    def setup_tunnel_port(self, remote_ip, network_type):
+        remote_ip_hex = self.get_ip_in_hex(remote_ip)
+        if not remote_ip_hex:
+            return 0
+        port_name = '%s-%s' % (network_type, remote_ip_hex)
+        ofport = self._setup_tunnel_port(port_name,
+                                         remote_ip,
+                                         network_type)
+        return ofport
+
     def cleanup_tunnel_port(self, tun_ofport, tunnel_type):
         # Check if this tunnel port is still used
         for lvm in self.local_vlan_map.values():
@@ -1393,9 +1366,8 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
                                 continue
                             tun_name = '%s-%s' % (tunnel_type,
                                                   tunnel_id or remote_ip_hex)
-                            self.setup_tunnel_port(tun_name,
-                                                   tunnel['ip_address'],
-                                                   tunnel_type)
+                            self._setup_tunnel_port(
+                                tun_name, tunnel['ip_address'], tunnel_type)
         except Exception as e:
             LOG.debug(_("Unable to sync tunnel IP %(local_ip)s: %(e)s"),
                       {'local_ip': self.local_ip, 'e': e})
diff --git a/neutron/tests/unit/agent/l2population_rpc_base.py b/neutron/tests/unit/agent/l2population_rpc_base.py
new file mode 100644 (file)
index 0000000..563e057
--- /dev/null
@@ -0,0 +1,140 @@
+# Copyright (C) 2014 VA Linux Systems Japan K.K.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+# @author: Fumihiko Kakuma, VA Linux Systems Japan K.K.
+
+import collections
+
+from neutron.agent import l2population_rpc
+from neutron.plugins.openvswitch.agent import ovs_neutron_agent
+from neutron.tests import base
+
+
+class FakeNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin):
+
+    def fdb_add(self, context, fdb_entries):
+        pass
+
+    def fdb_remove(self, context, fdb_entries):
+        pass
+
+    def add_fdb_flow(self, port_info, remote_ip, lvm, ofport):
+        pass
+
+    def del_fdb_flow(self, port_info, remote_ip, lvm, ofport):
+        pass
+
+    def setup_tunnel_port(self, remote_ip, network_type):
+        pass
+
+    def cleanup_tunnel_port(self, tun_ofport, tunnel_type):
+        pass
+
+
+class TestL2populationRpcCallBackTunnelMixinBase(base.BaseTestCase):
+
+    def setUp(self):
+        super(TestL2populationRpcCallBackTunnelMixinBase, self).setUp()
+        self.fakeagent = FakeNeutronAgent()
+        Port = collections.namedtuple('Port', 'ip, ofport')
+        LVM = collections.namedtuple(
+            'LVM', 'net, vlan, phys, segid, mac, ip, vif, port')
+
+        self.local_ip = '127.0.0.1'
+        self.type_gre = 'gre'
+        self.ports = [Port(ip='10.1.0.1', ofport='ofport1'),
+                      Port(ip='10.1.0.2', ofport='ofport2'),
+                      Port(ip='10.1.0.3', ofport='ofport3')]
+        self.ofports = {
+            self.type_gre: {
+                self.ports[0].ip: self.ports[0].ofport,
+                self.ports[1].ip: self.ports[1].ofport,
+                self.ports[2].ip: self.ports[2].ofport,
+            }
+        }
+
+        self.lvms = [LVM(net='net1', vlan=1, phys='phys1', segid='tun1',
+                         mac='mac1', ip='1.1.1.1', vif='vifid1',
+                         port='port1'),
+                     LVM(net='net2', vlan=2, phys='phys2', segid='tun2',
+                         mac='mac2', ip='2.2.2.2', vif='vifid2',
+                         port='port2'),
+                     LVM(net='net3', vlan=3, phys='phys3', segid='tun3',
+                         mac='mac3', ip='3.3.3.3', vif='vifid3',
+                         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.fdb_entries1 = {
+            self.lvms[0].net: {
+                'network_type': self.type_gre,
+                'segment_id': self.lvms[0].segid,
+                'ports': {
+                    self.local_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.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.lvm1 = ovs_neutron_agent.LocalVLANMapping(
+            self.lvms[0].vlan, self.type_gre, self.lvms[0].phys,
+            self.lvms[0].segid, {self.lvms[0].vif: self.lvms[0].port})
+        self.lvm2 = ovs_neutron_agent.LocalVLANMapping(
+            self.lvms[1].vlan, self.type_gre, self.lvms[1].phys,
+            self.lvms[1].segid, {self.lvms[1].vif: self.lvms[1].port})
+        self.lvm3 = ovs_neutron_agent.LocalVLANMapping(
+            self.lvms[2].vlan, self.type_gre, self.lvms[2].phys,
+            self.lvms[2].segid, {self.lvms[2].vif: self.lvms[2].port})
+
+        self.local_vlan_map1 = {
+            self.lvms[0].net: self.lvm1,
+            self.lvms[1].net: self.lvm2,
+            self.lvms[2].net: self.lvm3,
+        }
+
+        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]],
+                },
+                self.ports[1].ip: {
+                    'before': [[self.lvms[0].mac, self.lvms[0].ip]],
+                    'after': [[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]],
+                },
+            },
+        }
+        self.upd_fdb_entry1 = {'chg_ip': self.upd_fdb_entry1_val}
diff --git a/neutron/tests/unit/agent/test_l2population_rpc.py b/neutron/tests/unit/agent/test_l2population_rpc.py
new file mode 100644 (file)
index 0000000..3f54219
--- /dev/null
@@ -0,0 +1,190 @@
+# Copyright (C) 2014 VA Linux Systems Japan K.K.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+# @author: Fumihiko Kakuma, VA Linux Systems Japan K.K.
+
+import contextlib
+
+import mock
+
+from neutron.common import constants as n_const
+from neutron.tests.unit.agent import l2population_rpc_base
+
+
+class TestL2populationRpcCallBackTunnelMixin(
+    l2population_rpc_base.TestL2populationRpcCallBackTunnelMixinBase):
+
+    def test_get_agent_ports_no_data(self):
+        for lvm, agent_ports in self.fakeagent.get_agent_ports(
+            self.fdb_entries1, {}):
+            self.assertIsNone(lvm)
+            self.assertEqual({}, agent_ports)
+
+    def test_get_agent_ports_non_existence_key_in_lvm(self):
+        results = {}
+        del self.local_vlan_map1[self.lvms[1].net]
+        for lvm, agent_ports in self.fakeagent.get_agent_ports(
+            self.fdb_entries1, self.local_vlan_map1):
+            results[lvm] = agent_ports
+        expected = {
+            self.lvm1: {
+                self.ports[0].ip: [[self.lvms[0].mac, self.lvms[0].ip]],
+                self.local_ip: []},
+            None: {},
+            self.lvm3: {
+                self.ports[2].ip: [[self.lvms[2].mac, self.lvms[2].ip]],
+                self.local_ip: []},
+        }
+        self.assertEqual(expected, results)
+
+    def test_get_agent_ports_no_agent_ports(self):
+        results = {}
+        self.fdb_entries1[self.lvms[1].net]['ports'] = {}
+        for lvm, agent_ports in self.fakeagent.get_agent_ports(
+            self.fdb_entries1, self.local_vlan_map1):
+            results[lvm] = agent_ports
+        expected = {
+            self.lvm1: {
+                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.local_ip: []},
+        }
+        self.assertEqual(expected, results)
+
+    def test_fdb_add_tun(self):
+        with contextlib.nested(
+            mock.patch.object(self.fakeagent, 'setup_tunnel_port'),
+            mock.patch.object(self.fakeagent, 'add_fdb_flow'),
+        ) as (mock_setup_tunnel_port, mock_add_fdb_flow):
+            self.fakeagent.fdb_add_tun('context', self.lvm1,
+                                       self.agent_ports, self.ofports)
+        expected = [
+            mock.call([self.lvms[0].mac, self.lvms[0].ip], self.ports[0].ip,
+                      self.lvm1, self.ports[0].ofport),
+            mock.call([self.lvms[1].mac, self.lvms[1].ip], self.ports[1].ip,
+                      self.lvm1, self.ports[1].ofport),
+            mock.call([self.lvms[2].mac, self.lvms[2].ip], self.ports[2].ip,
+                      self.lvm1, self.ports[2].ofport),
+        ]
+        self.assertEqual(sorted(expected),
+                         sorted(mock_add_fdb_flow.call_args_list))
+
+    def test_fdb_add_tun_non_existence_key_in_ofports(self):
+        ofport = self.lvm1.network_type + '0a0a0a0a'
+        del self.ofports[self.type_gre][self.ports[1].ip]
+        with contextlib.nested(
+            mock.patch.object(self.fakeagent, 'setup_tunnel_port',
+                              return_value=ofport),
+            mock.patch.object(self.fakeagent, 'add_fdb_flow'),
+        ) as (mock_setup_tunnel_port, mock_add_fdb_flow):
+            self.fakeagent.fdb_add_tun('context', self.lvm1,
+                                       self.agent_ports, self.ofports)
+        mock_setup_tunnel_port.assert_called_once_with(
+            self.ports[1].ip, self.lvm1.network_type)
+        expected = [
+            mock.call([self.lvms[0].mac, self.lvms[0].ip], self.ports[0].ip,
+                      self.lvm1, self.ports[0].ofport),
+            mock.call([self.lvms[1].mac, self.lvms[1].ip], self.ports[1].ip,
+                      self.lvm1, ofport),
+            mock.call([self.lvms[2].mac, self.lvms[2].ip], self.ports[2].ip,
+                      self.lvm1, self.ports[2].ofport),
+        ]
+        self.assertEqual(sorted(expected),
+                         sorted(mock_add_fdb_flow.call_args_list))
+
+    def test_fdb_add_tun_unavailable_ofport(self):
+        del self.ofports[self.type_gre][self.ports[1].ip]
+        with contextlib.nested(
+            mock.patch.object(self.fakeagent, 'setup_tunnel_port',
+                              return_value=0),
+            mock.patch.object(self.fakeagent, 'add_fdb_flow'),
+        ) as (mock_setup_tunnel_port, mock_add_fdb_flow):
+            self.fakeagent.fdb_add_tun('context', self.lvm1,
+                                       self.agent_ports, self.ofports)
+        mock_setup_tunnel_port.assert_called_once_with(
+            self.ports[1].ip, self.lvm1.network_type)
+        expected = [
+            mock.call([self.lvms[0].mac, self.lvms[0].ip], self.ports[0].ip,
+                      self.lvm1, self.ports[0].ofport),
+            mock.call([self.lvms[2].mac, self.lvms[2].ip], self.ports[2].ip,
+                      self.lvm1, self.ports[2].ofport),
+        ]
+        self.assertEqual(sorted(expected),
+                         sorted(mock_add_fdb_flow.call_args_list))
+
+    def test_fdb_remove_tun(self):
+        with mock.patch.object(
+            self.fakeagent, 'del_fdb_flow') as mock_del_fdb_flow:
+            self.fakeagent.fdb_remove_tun('context', self.lvm1,
+                                          self.agent_ports, self.ofports)
+        expected = [
+            mock.call([self.lvms[0].mac, self.lvms[0].ip], self.ports[0].ip,
+                      self.lvm1, self.ports[0].ofport),
+            mock.call([self.lvms[1].mac, self.lvms[1].ip], self.ports[1].ip,
+                      self.lvm1, self.ports[1].ofport),
+            mock.call([self.lvms[2].mac, self.lvms[2].ip], self.ports[2].ip,
+                      self.lvm1, self.ports[2].ofport),
+        ]
+        self.assertEqual(sorted(expected),
+                         sorted(mock_del_fdb_flow.call_args_list))
+
+    def test_fdb_remove_tun_flooding_entry(self):
+        self.agent_ports[self.ports[1].ip] = [n_const.FLOODING_ENTRY]
+        with contextlib.nested(
+            mock.patch.object(self.fakeagent, 'del_fdb_flow'),
+            mock.patch.object(self.fakeagent, 'cleanup_tunnel_port'),
+        ) as (mock_del_fdb_flow, mock_cleanup_tunnel_port):
+            self.fakeagent.fdb_remove_tun('context', self.lvm1,
+                                          self.agent_ports, self.ofports)
+        expected = [
+            mock.call([self.lvms[0].mac, self.lvms[0].ip], self.ports[0].ip,
+                      self.lvm1, self.ports[0].ofport),
+            mock.call([n_const.FLOODING_ENTRY[0], n_const.FLOODING_ENTRY[1]],
+                      self.ports[1].ip, self.lvm1, self.ports[1].ofport),
+            mock.call([self.lvms[2].mac, self.lvms[2].ip], self.ports[2].ip,
+                      self.lvm1, self.ports[2].ofport),
+        ]
+        self.assertEqual(sorted(expected),
+                         sorted(mock_del_fdb_flow.call_args_list))
+        mock_cleanup_tunnel_port.assert_called_once_with(
+            self.ports[1].ofport, self.lvm1.network_type)
+
+    def test_fdb_remove_tun_non_existence_key_in_ofports(self):
+        del self.ofports[self.type_gre][self.ports[1].ip]
+        with mock.patch.object(
+            self.fakeagent, 'del_fdb_flow') as mock_del_fdb_flow:
+            self.fakeagent.fdb_remove_tun('context', self.lvm1,
+                                          self.agent_ports, self.ofports)
+        expected = [
+            mock.call([self.lvms[0].mac, self.lvms[0].ip], self.ports[0].ip,
+                      self.lvm1, self.ports[0].ofport),
+            mock.call([self.lvms[2].mac, self.lvms[2].ip], self.ports[2].ip,
+                      self.lvm1, self.ports[2].ofport),
+        ]
+        self.assertEqual(sorted(expected),
+                         sorted(mock_del_fdb_flow.call_args_list))
+
+    def test_fdb_update(self):
+        fake__fdb_chg_ip = mock.Mock()
+        self.fakeagent._fdb_chg_ip = fake__fdb_chg_ip
+        self.fakeagent.fdb_update('context', self.upd_fdb_entry1)
+        fake__fdb_chg_ip.assert_called_once_with(
+            'context', self.upd_fdb_entry1_val)
+
+    def test_fdb_update_non_existence_method(self):
+        self.assertRaises(NotImplementedError,
+                          self.fakeagent.fdb_update,
+                          'context', self.upd_fdb_entry1)
index 406480d801d08f9849df058e6c3953be5f0b2902..aaec36c9d62b614ac686478c3874d4d87a6d6f8c 100644 (file)
@@ -18,6 +18,7 @@
 # @author: Fumihiko Kakuma, VA Linux Systems Japan K.K.
 # @author: YAMAMOTO Takashi, VA Linux Systems Japan K.K.
 
+import collections
 import contextlib
 
 import mock
@@ -27,6 +28,7 @@ import testtools
 
 from neutron.agent.linux import ip_lib
 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.openvswitch.common import constants
@@ -258,27 +260,36 @@ class TestOFANeutronAgent(OFAAgentTestCase):
                        'FixedIntervalLoopingCall',
                        new=MockFixedIntervalLoopingCall)):
             self.agent = self.mod_agent.OFANeutronAgent(self.ryuapp, **kwargs)
-            self.agent.tun_br = _mk_test_br('tun_br')
-            self.datapath = mock.Mock()
-            self.ofparser = mock.Mock()
-            self.agent.phys_brs['phys-net1'] = _mk_test_br('phys_br1')
-            self.agent.phys_ofports['phys-net1'] = 777
-            self.agent.int_ofports['phys-net1'] = 666
-            self.datapath.ofparser = self.ofparser
-            self.ofparser.OFPMatch = mock.Mock()
-            self.ofparser.OFPMatch.return_value = mock.Mock()
-            self.ofparser.OFPFlowMod = mock.Mock()
-            self.ofparser.OFPFlowMod.return_value = mock.Mock()
-            self.agent.int_br.ofparser = self.ofparser
-            self.agent.int_br.datapath = _mk_test_dp('int_br')
 
         self.agent.sg_agent = mock.Mock()
+        self.int_dp = _mk_test_dp('int_br')
+        self.agent.int_br.ofparser = self.int_dp.ofproto_parser
+        self.agent.int_br.datapath = self.int_dp
+        self.agent.tun_br = _mk_test_br('tun_br')
+        self.agent.phys_brs['phys-net1'] = _mk_test_br('phys_br1')
+        self.agent.phys_ofports['phys-net1'] = 777
+        self.agent.int_ofports['phys-net1'] = 666
+        self.datapath = _mk_test_dp('phys_br')
+
+    def _create_tunnel_port_name(self, tunnel_ip, tunnel_type):
+        tunnel_ip_hex = '%08x' % netaddr.IPAddress(tunnel_ip, version=4)
+        return '%s-%s' % (tunnel_type, tunnel_ip_hex)
 
     def _mock_port_bound(self, ofport=None, new_local_vlan=None,
                          old_local_vlan=None):
         port = mock.Mock()
         port.ofport = ofport
         net_uuid = 'my-net-uuid'
+        ofp = self.agent.int_br.datapath.ofproto
+        ofpp = self.agent.int_br.datapath.ofproto_parser
+        expected_msg = ofpp.OFPFlowMod(
+            self.agent.int_br.datapath,
+            match=ofpp.OFPMatch(in_port=port.ofport),
+            table_id=ofp.OFPTT_ALL,
+            command=ofp.OFPFC_DELETE,
+            out_group=ofp.OFPG_ANY,
+            out_port=ofp.OFPP_ANY
+        )
         if old_local_vlan is not None:
             self.agent.local_vlan_map[net_uuid] = (
                 self.mod_agent.LocalVLANMapping(
@@ -296,8 +307,7 @@ class TestOFANeutronAgent(OFAAgentTestCase):
             set_ovs_db_func.assert_called_once_with(
                 "Port", mock.ANY, "tag", str(new_local_vlan))
             if ofport != -1:
-                ryu_send_msg_func.assert_called_once_with(
-                    self.ofparser.OFPFlowMod.return_value)
+                ryu_send_msg_func.assert_called_once_with(expected_msg)
             else:
                 self.assertFalse(ryu_send_msg_func.called)
         else:
@@ -316,6 +326,12 @@ class TestOFANeutronAgent(OFAAgentTestCase):
     def _test_port_dead(self, cur_tag=None):
         port = mock.Mock()
         port.ofport = 1
+        ofpp = self.agent.int_br.datapath.ofproto_parser
+        expected_msg = ofpp.OFPFlowMod(
+            self.agent.int_br.datapath,
+            priority=2,
+            match=ofpp.OFPMatch(in_port=port.ofport)
+        )
         with contextlib.nested(
             mock.patch.object(self.mod_agent.OVSBridge,
                               'set_db_attribute', return_value=True),
@@ -331,8 +347,7 @@ class TestOFANeutronAgent(OFAAgentTestCase):
         else:
             set_ovs_db_func.assert_called_once_with(
                 "Port", mock.ANY, "tag", str(self.mod_agent.DEAD_VLAN_TAG))
-            ryu_send_msg_func.assert_called_once_with(
-                self.ofparser.OFPFlowMod.return_value)
+            ryu_send_msg_func.assert_called_once_with(expected_msg)
 
     def test_port_dead(self):
         self._test_port_dead()
@@ -570,14 +585,17 @@ class TestOFANeutronAgent(OFAAgentTestCase):
             )
 
     def test_network_delete(self):
-        with mock.patch.object(self.agent,
-                               "reclaim_local_vlan") as recl_fn:
+        with contextlib.nested(
+            mock.patch.object(self.agent, "reclaim_local_vlan"),
+            mock.patch.object(self.agent.tun_br, "cleanup_tunnel_port")
+        ) as (recl_fn, clean_tun_fn):
             self.agent.network_delete("unused_context",
                                       network_id="123")
             self.assertFalse(recl_fn.called)
             self.agent.local_vlan_map["123"] = "LVM object"
             self.agent.network_delete("unused_context",
                                       network_id="123")
+            self.assertFalse(clean_tun_fn.called)
             recl_fn.assert_called_with("123")
 
     def test_port_update(self):
@@ -655,6 +673,146 @@ class TestOFANeutronAgent(OFAAgentTestCase):
             self.agent.port_unbound("vif3", "netuid12345")
             self.assertEqual(reclvl_fn.call_count, 2)
 
+    def _prepare_l2_pop_ofports(self):
+        LVM = collections.namedtuple('LVM', 'net, vlan, segid, ip')
+        self.lvms = [LVM(net='net1', vlan=11, segid='21', ip='1.1.1.1'),
+                     LVM(net='net2', vlan=12, segid='22', ip='2.2.2.2')]
+        self.tunnel_type = 'gre'
+        self.tun_name1 = self._create_tunnel_port_name(self.lvms[0].ip,
+                                                       self.tunnel_type)
+        self.tun_name2 = self._create_tunnel_port_name(self.lvms[1].ip,
+                                                       self.tunnel_type)
+        lvm1 = mock.Mock()
+        lvm1.network_type = self.tunnel_type
+        lvm1.vlan = self.lvms[0].vlan
+        lvm1.segmentation_id = self.lvms[0].segid
+        lvm1.tun_ofports = set(['1'])
+        lvm2 = mock.Mock()
+        lvm2.network_type = self.tunnel_type
+        lvm2.vlan = self.lvms[1].vlan
+        lvm2.segmentation_id = self.lvms[1].segid
+        lvm2.tun_ofports = set(['1', '2'])
+        self.agent.local_vlan_map = {self.lvms[0].net: lvm1,
+                                     self.lvms[1].net: lvm2}
+        self.agent.tun_br_ofports = {self.tunnel_type:
+                                     {self.lvms[0].ip: '1',
+                                      self.lvms[1].ip: '2'}}
+
+    def test_fdb_ignore_network(self):
+        self._prepare_l2_pop_ofports()
+        fdb_entry = {'net3': {}}
+        with contextlib.nested(
+            mock.patch.object(self.agent, 'ryu_send_msg'),
+            mock.patch.object(self.agent, '_setup_tunnel_port'),
+            mock.patch.object(self.agent, 'cleanup_tunnel_port')
+        ) as (ryu_send_msg_fn, add_tun_fn, clean_tun_fn):
+            self.agent.fdb_add(None, fdb_entry)
+            self.assertFalse(add_tun_fn.called)
+            self.agent.fdb_remove(None, fdb_entry)
+            self.assertFalse(clean_tun_fn.called)
+            self.assertFalse(ryu_send_msg_fn.called)
+
+    def test_fdb_ignore_self(self):
+        self._prepare_l2_pop_ofports()
+        self.agent.local_ip = 'agent_ip'
+        fdb_entry = {self.lvms[1].net:
+                     {'network_type': self.tunnel_type,
+                      'segment_id': 'tun2',
+                      'ports':
+                      {'agent_ip':
+                       [['mac', 'ip'],
+                        n_const.FLOODING_ENTRY]}}}
+        with mock.patch.object(self.agent.tun_br,
+                               "defer_apply_on") as defer_fn:
+            self.agent.fdb_add(None, fdb_entry)
+            self.assertFalse(defer_fn.called)
+
+            self.agent.fdb_remove(None, fdb_entry)
+            self.assertFalse(defer_fn.called)
+
+    def test_fdb_add_flows(self):
+        self._prepare_l2_pop_ofports()
+        fdb_entry = {self.lvms[0].net:
+                     {'network_type': self.tunnel_type,
+                      'segment_id': 'tun1',
+                      'ports':
+                      {self.lvms[1].ip:
+                       [['mac', 'ip'],
+                        n_const.FLOODING_ENTRY]}}}
+        with contextlib.nested(
+            mock.patch.object(self.agent, 'ryu_send_msg'),
+            mock.patch.object(self.agent.tun_br, '_setup_tunnel_port'),
+        ) as (ryu_send_msg_fn, add_tun_fn):
+            add_tun_fn.return_value = '2'
+            self.agent.fdb_add(None, fdb_entry)
+            self.assertEqual(ryu_send_msg_fn.call_count, 2)
+
+    def test_fdb_del_flows(self):
+        self._prepare_l2_pop_ofports()
+        fdb_entry = {self.lvms[1].net:
+                     {'network_type': self.tunnel_type,
+                      'segment_id': 'tun2',
+                      'ports':
+                      {self.lvms[1].ip:
+                       [['mac', 'ip'],
+                        n_const.FLOODING_ENTRY]}}}
+        with mock.patch.object(self.agent,
+                               'ryu_send_msg') as ryu_send_msg_fn:
+            self.agent.fdb_remove(None, fdb_entry)
+            self.assertEqual(ryu_send_msg_fn.call_count, 3)
+
+    def test_fdb_add_port(self):
+        self._prepare_l2_pop_ofports()
+        tunnel_ip = '10.10.10.10'
+        tun_name = self._create_tunnel_port_name(tunnel_ip,
+                                                 self.tunnel_type)
+        fdb_entry = {self.lvms[0].net:
+                     {'network_type': self.tunnel_type,
+                      'segment_id': 'tun1',
+                      'ports': {self.lvms[0].ip: [['mac', 'ip']]}}}
+        with contextlib.nested(
+            mock.patch.object(self.agent, 'ryu_send_msg'),
+            mock.patch.object(self.agent, '_setup_tunnel_port')
+        ) as (ryu_send_msg_fn, 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']]
+            self.agent.fdb_add(None, fdb_entry)
+            add_tun_fn.assert_called_with(
+                tun_name, tunnel_ip, self.tunnel_type)
+
+    def test_fdb_del_port(self):
+        self._prepare_l2_pop_ofports()
+        fdb_entry = {self.lvms[1].net:
+                     {'network_type': self.tunnel_type,
+                      'segment_id': 'tun2',
+                      'ports': {self.lvms[1].ip: [n_const.FLOODING_ENTRY]}}}
+        with contextlib.nested(
+            mock.patch.object(self.agent, 'ryu_send_msg'),
+            mock.patch.object(self.agent.tun_br, 'delete_port')
+        ) as (ryu_send_msg_fn, del_port_fn):
+            self.agent.fdb_remove(None, fdb_entry)
+            del_port_fn.assert_called_once_with(self.tun_name2)
+
+    def test_recl_lv_port_to_preserve(self):
+        self._prepare_l2_pop_ofports()
+        self.agent.enable_tunneling = True
+        with mock.patch.object(
+            self.agent.tun_br, 'cleanup_tunnel_port'
+        ) as clean_tun_fn:
+            self.agent.reclaim_local_vlan(self.lvms[0].net)
+            self.assertFalse(clean_tun_fn.called)
+
+    def test_recl_lv_port_to_remove(self):
+        self._prepare_l2_pop_ofports()
+        self.agent.enable_tunneling = True
+        with contextlib.nested(
+            mock.patch.object(self.agent.tun_br, 'delete_port'),
+            mock.patch.object(self.agent, 'ryu_send_msg')
+        ) as (del_port_fn, ryu_send_msg_fn):
+            self.agent.reclaim_local_vlan(self.lvms[1].net)
+            del_port_fn.assert_called_once_with(self.tun_name2)
+
     def test_daemon_loop_uses_polling_manager(self):
         with mock.patch(
             'neutron.agent.linux.polling.get_polling_manager'
@@ -671,13 +829,13 @@ class TestOFANeutronAgent(OFAAgentTestCase):
                                             constants.DEFAULT_OVSDBMON_RESPAWN)
         mock_loop.assert_called_once_with(polling_manager=fake_pm.__enter__())
 
-    def test_setup_tunnel_port_error_negative(self):
+    def test__setup_tunnel_port_error_negative(self):
         with contextlib.nested(
             mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
                               return_value='-1'),
             mock.patch.object(self.mod_agent.LOG, 'error')
         ) as (add_tunnel_port_fn, log_error_fn):
-            ofport = self.agent.setup_tunnel_port(
+            ofport = self.agent._setup_tunnel_port(
                 'gre-1', 'remote_ip', p_const.TYPE_GRE)
             add_tunnel_port_fn.assert_called_once_with(
                 'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
@@ -687,14 +845,14 @@ class TestOFANeutronAgent(OFAAgentTestCase):
                 {'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
             self.assertEqual(ofport, 0)
 
-    def test_setup_tunnel_port_error_not_int(self):
+    def test__setup_tunnel_port_error_not_int(self):
         with contextlib.nested(
             mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
                               return_value=None),
             mock.patch.object(self.mod_agent.LOG, 'exception'),
             mock.patch.object(self.mod_agent.LOG, 'error')
         ) as (add_tunnel_port_fn, log_exc_fn, log_error_fn):
-            ofport = self.agent.setup_tunnel_port(
+            ofport = self.agent._setup_tunnel_port(
                 'gre-1', 'remote_ip', p_const.TYPE_GRE)
             add_tunnel_port_fn.assert_called_once_with(
                 'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
@@ -707,72 +865,18 @@ class TestOFANeutronAgent(OFAAgentTestCase):
                 {'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
             self.assertEqual(ofport, 0)
 
-    def _create_tunnel_port_name(self, tunnel_ip, tunnel_type):
-        tunnel_ip_hex = '%08x' % netaddr.IPAddress(tunnel_ip, version=4)
-        return '%s-%s' % (tunnel_type, tunnel_ip_hex)
-
-    def test_tunnel_sync_with_valid_ip_address_and_gre_type(self):
-        tunnel_ip = '100.101.102.103'
-        self.agent.tunnel_types = ['gre']
-        tun_name = self._create_tunnel_port_name(tunnel_ip,
-                                                 self.agent.tunnel_types[0])
-        fake_tunnel_details = {'tunnels': [{'ip_address': tunnel_ip}]}
-        with contextlib.nested(
-            mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
-                              return_value=fake_tunnel_details),
-            mock.patch.object(self.agent, 'setup_tunnel_port')
-        ) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
-            self.agent.tunnel_sync()
-            expected_calls = [mock.call(tun_name, tunnel_ip,
-                                        self.agent.tunnel_types[0])]
-            setup_tunnel_port_fn.assert_has_calls(expected_calls)
-
-    def test_tunnel_sync_with_valid_ip_address_and_vxlan_type(self):
-        tunnel_ip = '100.101.31.15'
+    def test_tunnel_sync(self):
+        self.agent.local_ip = 'agent_ip'
+        self.agent.context = 'fake_context'
         self.agent.tunnel_types = ['vxlan']
-        tun_name = self._create_tunnel_port_name(tunnel_ip,
-                                                 self.agent.tunnel_types[0])
-        fake_tunnel_details = {'tunnels': [{'ip_address': tunnel_ip}]}
-        with contextlib.nested(
-            mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
-                              return_value=fake_tunnel_details),
-            mock.patch.object(self.agent, 'setup_tunnel_port')
-        ) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
+        with mock.patch.object(
+            self.agent.plugin_rpc, 'tunnel_sync'
+        ) as tunnel_sync_rpc_fn:
             self.agent.tunnel_sync()
-            expected_calls = [mock.call(tun_name, tunnel_ip,
-                                        self.agent.tunnel_types[0])]
-            setup_tunnel_port_fn.assert_has_calls(expected_calls)
-
-    def test_tunnel_sync_invalid_ip_address(self):
-        tunnel_ip = '100.100.100.100'
-        self.agent.tunnel_types = ['vxlan']
-        tun_name = self._create_tunnel_port_name(tunnel_ip,
-                                                 self.agent.tunnel_types[0])
-        fake_tunnel_details = {'tunnels': [{'ip_address': '300.300.300.300'},
-                                           {'ip_address': tunnel_ip}]}
-        with contextlib.nested(
-            mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
-                              return_value=fake_tunnel_details),
-            mock.patch.object(self.agent, 'setup_tunnel_port')
-        ) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
-            self.agent.tunnel_sync()
-            setup_tunnel_port_fn.assert_called_once_with(
-                tun_name, tunnel_ip, self.agent.tunnel_types[0])
-
-    def test_tunnel_update(self):
-        tunnel_ip = '10.10.10.10'
-        self.agent.tunnel_types = ['gre']
-        tun_name = self._create_tunnel_port_name(tunnel_ip,
-                                                 self.agent.tunnel_types[0])
-        kwargs = {'tunnel_ip': tunnel_ip,
-                  'tunnel_type': self.agent.tunnel_types[0]}
-        self.agent.setup_tunnel_port = mock.Mock()
-        self.agent.enable_tunneling = True
-        self.agent.l2_pop = False
-        self.agent.tunnel_update(context=None, **kwargs)
-        expected_calls = [mock.call(tun_name, tunnel_ip,
-                                    self.agent.tunnel_types[0])]
-        self.agent.setup_tunnel_port.assert_has_calls(expected_calls)
+            tunnel_sync_rpc_fn.assert_called_once_with(
+                self.agent.context,
+                self.agent.local_ip,
+                self.agent.tunnel_types[0])
 
     def test__provision_local_vlan_inbound_for_tunnel(self):
         with mock.patch.object(self.agent, 'ryu_send_msg') as sendmsg:
index 771a09ddff4d467e01a1f01fcd97a6e83afd0472..5aa43f0e2566403f5f84e555a01ceac92385c1a7 100644 (file)
@@ -934,7 +934,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
                               return_value='6'),
             mock.patch.object(self.agent.tun_br, "add_flow")
         ) as (add_tun_port_fn, add_flow_fn):
-            self.agent.setup_tunnel_port('portname', '1.2.3.4', 'vxlan')
+            self.agent._setup_tunnel_port('portname', '1.2.3.4', 'vxlan')
             self.assertTrue(add_tun_port_fn.called)
 
     def test_port_unbound(self):
@@ -978,7 +978,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
         with contextlib.nested(
             mock.patch.object(self.agent.tun_br, 'add_flow'),
             mock.patch.object(self.agent.tun_br, 'delete_flows'),
-            mock.patch.object(self.agent, 'setup_tunnel_port'),
+            mock.patch.object(self.agent, '_setup_tunnel_port'),
             mock.patch.object(self.agent, 'cleanup_tunnel_port')
         ) as (add_flow_fn, del_flow_fn, add_tun_fn, clean_tun_fn):
             self.agent.fdb_add(None, fdb_entry)
@@ -1018,7 +1018,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
         with contextlib.nested(
             mock.patch.object(self.agent.tun_br, 'add_flow'),
             mock.patch.object(self.agent.tun_br, 'mod_flow'),
-            mock.patch.object(self.agent, 'setup_tunnel_port'),
+            mock.patch.object(self.agent, '_setup_tunnel_port'),
         ) as (add_flow_fn, mod_flow_fn, add_tun_fn):
             self.agent.fdb_add(None, fdb_entry)
             self.assertFalse(add_tun_fn.called)
@@ -1088,7 +1088,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
         with contextlib.nested(
             mock.patch.object(self.agent.tun_br, 'add_flow'),
             mock.patch.object(self.agent.tun_br, 'mod_flow'),
-            mock.patch.object(self.agent, 'setup_tunnel_port')
+            mock.patch.object(self.agent, '_setup_tunnel_port')
         ) as (add_flow_fn, mod_flow_fn, add_tun_fn):
             self.agent.fdb_add(None, fdb_entry)
             self.assertFalse(add_tun_fn.called)
@@ -1201,13 +1201,13 @@ class TestOvsNeutronAgent(base.BaseTestCase):
                                        constants.DEFAULT_OVSDBMON_RESPAWN)
         mock_loop.assert_called_once_with(polling_manager=mock.ANY)
 
-    def test_setup_tunnel_port_error_negative(self):
+    def test__setup_tunnel_port_error_negative(self):
         with contextlib.nested(
             mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
                               return_value='-1'),
             mock.patch.object(ovs_neutron_agent.LOG, 'error')
         ) as (add_tunnel_port_fn, log_error_fn):
-            ofport = self.agent.setup_tunnel_port(
+            ofport = self.agent._setup_tunnel_port(
                 'gre-1', 'remote_ip', p_const.TYPE_GRE)
             add_tunnel_port_fn.assert_called_once_with(
                 'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
@@ -1217,14 +1217,14 @@ class TestOvsNeutronAgent(base.BaseTestCase):
                 {'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
             self.assertEqual(ofport, 0)
 
-    def test_setup_tunnel_port_error_not_int(self):
+    def test__setup_tunnel_port_error_not_int(self):
         with contextlib.nested(
             mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
                               return_value=None),
             mock.patch.object(ovs_neutron_agent.LOG, 'exception'),
             mock.patch.object(ovs_neutron_agent.LOG, 'error')
         ) as (add_tunnel_port_fn, log_exc_fn, log_error_fn):
-            ofport = self.agent.setup_tunnel_port(
+            ofport = self.agent._setup_tunnel_port(
                 'gre-1', 'remote_ip', p_const.TYPE_GRE)
             add_tunnel_port_fn.assert_called_once_with(
                 'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
@@ -1237,14 +1237,14 @@ class TestOvsNeutronAgent(base.BaseTestCase):
                 {'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
             self.assertEqual(ofport, 0)
 
-    def test_setup_tunnel_port_error_negative_df_disabled(self):
+    def test__setup_tunnel_port_error_negative_df_disabled(self):
         with contextlib.nested(
             mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
                               return_value='-1'),
             mock.patch.object(ovs_neutron_agent.LOG, 'error')
         ) as (add_tunnel_port_fn, log_error_fn):
             self.agent.dont_fragment = False
-            ofport = self.agent.setup_tunnel_port(
+            ofport = self.agent._setup_tunnel_port(
                 'gre-1', 'remote_ip', p_const.TYPE_GRE)
             add_tunnel_port_fn.assert_called_once_with(
                 'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
@@ -1260,25 +1260,25 @@ class TestOvsNeutronAgent(base.BaseTestCase):
         with contextlib.nested(
             mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
                               return_value=fake_tunnel_details),
-            mock.patch.object(self.agent, 'setup_tunnel_port')
-        ) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
+            mock.patch.object(self.agent, '_setup_tunnel_port')
+        ) as (tunnel_sync_rpc_fn, _setup_tunnel_port_fn):
             self.agent.tunnel_types = ['gre']
             self.agent.tunnel_sync()
             expected_calls = [mock.call('gre-42', '100.101.102.103', 'gre')]
-            setup_tunnel_port_fn.assert_has_calls(expected_calls)
+            _setup_tunnel_port_fn.assert_has_calls(expected_calls)
 
     def test_tunnel_sync_with_ml2_plugin(self):
         fake_tunnel_details = {'tunnels': [{'ip_address': '100.101.31.15'}]}
         with contextlib.nested(
             mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
                               return_value=fake_tunnel_details),
-            mock.patch.object(self.agent, 'setup_tunnel_port')
-        ) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
+            mock.patch.object(self.agent, '_setup_tunnel_port')
+        ) as (tunnel_sync_rpc_fn, _setup_tunnel_port_fn):
             self.agent.tunnel_types = ['vxlan']
             self.agent.tunnel_sync()
             expected_calls = [mock.call('vxlan-64651f0f',
                                         '100.101.31.15', 'vxlan')]
-            setup_tunnel_port_fn.assert_has_calls(expected_calls)
+            _setup_tunnel_port_fn.assert_has_calls(expected_calls)
 
     def test_tunnel_sync_invalid_ip_address(self):
         fake_tunnel_details = {'tunnels': [{'ip_address': '300.300.300.300'},
@@ -1286,24 +1286,24 @@ class TestOvsNeutronAgent(base.BaseTestCase):
         with contextlib.nested(
             mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
                               return_value=fake_tunnel_details),
-            mock.patch.object(self.agent, 'setup_tunnel_port')
-        ) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
+            mock.patch.object(self.agent, '_setup_tunnel_port')
+        ) as (tunnel_sync_rpc_fn, _setup_tunnel_port_fn):
             self.agent.tunnel_types = ['vxlan']
             self.agent.tunnel_sync()
-            setup_tunnel_port_fn.assert_called_once_with('vxlan-64646464',
-                                                         '100.100.100.100',
-                                                         'vxlan')
+            _setup_tunnel_port_fn.assert_called_once_with('vxlan-64646464',
+                                                          '100.100.100.100',
+                                                          'vxlan')
 
     def test_tunnel_update(self):
         kwargs = {'tunnel_ip': '10.10.10.10',
                   'tunnel_type': 'gre'}
-        self.agent.setup_tunnel_port = mock.Mock()
+        self.agent._setup_tunnel_port = mock.Mock()
         self.agent.enable_tunneling = True
         self.agent.tunnel_types = ['gre']
         self.agent.l2_pop = False
         self.agent.tunnel_update(context=None, **kwargs)
         expected_calls = [mock.call('gre-0a0a0a0a', '10.10.10.10', 'gre')]
-        self.agent.setup_tunnel_port.assert_has_calls(expected_calls)
+        self.agent._setup_tunnel_port.assert_has_calls(expected_calls)
 
     def test_ovs_restart(self):
         reply2 = {'current': set(['tap0']),