]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Move internal port processing to router classes
authorCarl Baldwin <carl.baldwin@hp.com>
Tue, 10 Feb 2015 05:17:51 +0000 (05:17 +0000)
committerCarl Baldwin <carl.baldwin@hp.com>
Fri, 13 Mar 2015 14:39:53 +0000 (14:39 +0000)
Change-Id: I38b18f6d24c788c96b2d13ccca5d2e9a7a4fcdeb
Partially-Implements: bp/restructure-l3-agent

neutron/agent/l3/agent.py
neutron/agent/l3/dvr.py
neutron/agent/l3/dvr_router.py
neutron/agent/l3/ha.py
neutron/agent/l3/ha_router.py
neutron/agent/l3/router_info.py
neutron/tests/unit/agent/l3/test_dvr_router.py
neutron/tests/unit/test_l3_agent.py

index 0e4a6ce3ba09cbae5544c04c9baa163ec874c310..99998d66756cc40584c2713387116c8bca0da388 100644 (file)
@@ -24,7 +24,6 @@ from oslo_utils import timeutils
 
 from neutron.agent.l3 import dvr
 from neutron.agent.l3 import dvr_router
-from neutron.agent.l3 import dvr_snat_ns
 from neutron.agent.l3 import event_observers
 from neutron.agent.l3 import ha
 from neutron.agent.l3 import ha_router
@@ -323,68 +322,6 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
         self.event_observers.notify(
             adv_svc.AdvancedService.after_router_removed, ri)
 
-    def _set_subnet_info(self, port):
-        ips = port['fixed_ips']
-        if not ips:
-            raise Exception(_("Router port %s has no IP address") % port['id'])
-        if len(ips) > 1:
-            LOG.error(_LE("Ignoring multiple IPs on router port %s"),
-                      port['id'])
-        prefixlen = netaddr.IPNetwork(port['subnet']['cidr']).prefixlen
-        port['ip_cidr'] = "%s/%s" % (ips[0]['ip_address'], prefixlen)
-
-    def _get_existing_devices(self, ri):
-        ip_wrapper = ip_lib.IPWrapper(namespace=ri.ns_name)
-        ip_devs = ip_wrapper.get_devices(exclude_loopback=True)
-        return [ip_dev.name for ip_dev in ip_devs]
-
-    def _process_internal_ports(self, ri):
-        internal_ports = ri.router.get(l3_constants.INTERFACE_KEY, [])
-        existing_port_ids = set([p['id'] for p in ri.internal_ports])
-        current_port_ids = set([p['id'] for p in internal_ports
-                                if p['admin_state_up']])
-        new_ports = [p for p in internal_ports if
-                     p['id'] in current_port_ids and
-                     p['id'] not in existing_port_ids]
-        old_ports = [p for p in ri.internal_ports if
-                     p['id'] not in current_port_ids]
-
-        new_ipv6_port = False
-        old_ipv6_port = False
-        for p in new_ports:
-            self._set_subnet_info(p)
-            self.internal_network_added(ri, p)
-            ri.internal_ports.append(p)
-            if ri.router['distributed']:
-                ri._set_subnet_arp_info(p)
-            if (not new_ipv6_port and
-                    netaddr.IPNetwork(p['subnet']['cidr']).version == 6):
-                new_ipv6_port = True
-
-        for p in old_ports:
-            self.internal_network_removed(ri, p)
-            ri.internal_ports.remove(p)
-            if (not old_ipv6_port and
-                    netaddr.IPNetwork(p['subnet']['cidr']).version == 6):
-                old_ipv6_port = True
-
-        # Enable RA
-        if new_ipv6_port or old_ipv6_port:
-            ri.radvd.enable(internal_ports)
-
-        existing_devices = self._get_existing_devices(ri)
-        current_internal_devs = set([n for n in existing_devices
-                                     if n.startswith(INTERNAL_DEV_PREFIX)])
-        current_port_devs = set([ri.get_internal_device_name(id) for
-                                 id in current_port_ids])
-        stale_devs = current_internal_devs - current_port_devs
-        for stale_dev in stale_devs:
-            LOG.debug('Deleting stale internal router device: %s',
-                      stale_dev)
-            self.driver.unplug(stale_dev,
-                               namespace=ri.ns_name,
-                               prefix=INTERNAL_DEV_PREFIX)
-
     def _process_external_gateway(self, ri):
         ex_gw_port = ri.get_ex_gw_port()
         ex_gw_port_id = (ex_gw_port and ex_gw_port['id'] or
@@ -404,7 +341,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
                 port2_filtered = _get_filtered_dict(port2, keys_to_ignore)
                 return port1_filtered == port2_filtered
 
-            self._set_subnet_info(ex_gw_port)
+            ri._set_subnet_info(ex_gw_port)
             if not ri.ex_gw_port:
                 self.external_gateway_added(ri, ex_gw_port, interface_name)
             elif not _gateway_ports_equal(ex_gw_port, ri.ex_gw_port):
@@ -412,7 +349,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
         elif not ex_gw_port and ri.ex_gw_port:
             self.external_gateway_removed(ri, ri.ex_gw_port, interface_name)
 
-        existing_devices = self._get_existing_devices(ri)
+        existing_devices = ri._get_existing_devices()
         stale_devs = [dev for dev in existing_devices
                       if dev.startswith(EXTERNAL_DEV_PREFIX)
                       and dev != interface_name]
@@ -426,7 +363,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
 
         # Process SNAT rules for external gateway
         if (not ri.router['distributed'] or
-            ex_gw_port and self.get_gw_port_host(ri.router) == self.host):
+            ex_gw_port and ri.get_gw_port_host() == self.host):
             ri.perform_snat_action(self._handle_router_snat_rules,
                                    interface_name)
 
@@ -486,7 +423,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
         if ri.router.get('distributed') and ex_gw_port:
             ri.fip_ns = self.get_fip_ns(ex_gw_port['network_id'])
             ri.fip_ns.scan_fip_ports(ri)
-        self._process_internal_ports(ri)
+        ri._process_internal_ports()
         self._process_external(ri)
         # Process static routes for router
         ri.routes_updated()
@@ -536,8 +473,8 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
 
     def create_dvr_fip_interfaces(self, ri, ex_gw_port):
         floating_ips = ri.get_floating_ips()
-        fip_agent_port = self.get_floating_agent_gw_interface(
-            ri, ex_gw_port['network_id'])
+        fip_agent_port = ri.get_floating_agent_gw_interface(
+            ex_gw_port['network_id'])
         LOG.debug("FloatingIP agent gateway port received from the plugin: "
                   "%s", fip_agent_port)
         if floating_ips:
@@ -546,7 +483,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
                 if 'subnet' not in fip_agent_port:
                     LOG.error(_LE('Missing subnet/agent_gateway_port'))
                 else:
-                    self._set_subnet_info(fip_agent_port)
+                    ri._set_subnet_info(fip_agent_port)
                     ri.fip_ns.create_gateway_port(fip_agent_port)
 
         if ri.fip_ns.agent_gateway_port and floating_ips:
@@ -568,27 +505,21 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
     def get_external_device_name(self, port_id):
         return (EXTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
 
-    def get_floating_agent_gw_interface(self, ri, ext_net_id):
-        """Filter Floating Agent GW port for the external network."""
-        fip_ports = ri.router.get(l3_constants.FLOATINGIP_AGENT_INTF_KEY, [])
-        return next(
-            (p for p in fip_ports if p['network_id'] == ext_net_id), None)
-
     def external_gateway_added(self, ri, ex_gw_port, interface_name):
         if ri.router['distributed']:
             ip_wrapr = ip_lib.IPWrapper(namespace=ri.ns_name)
             ip_wrapr.netns.execute(['sysctl', '-w',
                                    'net.ipv4.conf.all.send_redirects=0'])
-            snat_ports = self.get_snat_interfaces(ri)
+            snat_ports = ri.get_snat_interfaces()
             for p in ri.internal_ports:
-                gateway = self._map_internal_interfaces(ri, p, snat_ports)
+                gateway = ri._map_internal_interfaces(p, snat_ports)
                 id_name = ri.get_internal_device_name(p['id'])
                 if gateway:
-                    self._snat_redirect_add(ri, gateway['fixed_ips'][0]
-                                            ['ip_address'], p, id_name)
+                    ri._snat_redirect_add(
+                        gateway['fixed_ips'][0]['ip_address'], p, id_name)
 
             if (self.conf.agent_mode == l3_constants.L3_AGENT_MODE_DVR_SNAT and
-                self.get_gw_port_host(ri.router) == self.host):
+                ri.get_gw_port_host() == self.host):
                 self._create_dvr_gateway(ri, ex_gw_port, interface_name,
                                          snat_ports)
             for port in snat_ports:
@@ -617,7 +548,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
         preserve_ips = []
         if ri.router['distributed']:
             if (self.conf.agent_mode == l3_constants.L3_AGENT_MODE_DVR_SNAT and
-                self.get_gw_port_host(ri.router) == self.host):
+                ri.get_gw_port_host() == self.host):
                 ns_name = ri.snat_namespace.name
             else:
                 # no centralized SNAT gateway for this node/agent
@@ -665,16 +596,16 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
                 to_fip_interface_name = (
                     self._get_external_device_interface_name(ri, ex_gw_port))
                 ri.process_floating_ip_addresses(to_fip_interface_name)
-            snat_ports = self.get_snat_interfaces(ri)
+            snat_ports = ri.get_snat_interfaces()
             for p in ri.internal_ports:
                 gateway = self._map_internal_interfaces(ri, p, snat_ports)
                 internal_interface = ri.get_internal_device_name(p['id'])
-                self._snat_redirect_remove(ri, gateway['fixed_ips'][0]
-                                           ['ip_address'],
-                                           p, internal_interface)
+                ri._snat_redirect_remove(gateway['fixed_ips'][0]['ip_address'],
+                                         p,
+                                         internal_interface)
 
             if (self.conf.agent_mode == l3_constants.L3_AGENT_MODE_DVR_SNAT
-                and self.get_gw_port_host(ri.router) == self.host):
+                and ri.get_gw_port_host() == self.host):
                 ns_name = ri.snat_namespace.name
             else:
                 # not hosting agent - no work to do
@@ -702,89 +633,6 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
                   (interface_name, ex_gw_ip))]
         return rules
 
-    def _internal_network_added(self, ns_name, network_id, port_id,
-                                internal_cidr, mac_address,
-                                interface_name, prefix, is_ha=False):
-        if not ip_lib.device_exists(interface_name, namespace=ns_name):
-            self.driver.plug(network_id, port_id, interface_name, mac_address,
-                             namespace=ns_name,
-                             prefix=prefix)
-
-        if not is_ha:
-            self.driver.init_l3(interface_name, [internal_cidr],
-                                namespace=ns_name)
-            ip_address = internal_cidr.split('/')[0]
-            ip_lib.send_gratuitous_arp(ns_name,
-                                       interface_name,
-                                       ip_address,
-                                       self.conf.send_arp_for_ha)
-
-    def internal_network_added(self, ri, port):
-        network_id = port['network_id']
-        port_id = port['id']
-        internal_cidr = port['ip_cidr']
-        mac_address = port['mac_address']
-
-        interface_name = ri.get_internal_device_name(port_id)
-
-        self._internal_network_added(ri.ns_name, network_id, port_id,
-                                     internal_cidr, mac_address,
-                                     interface_name, INTERNAL_DEV_PREFIX,
-                                     ri.is_ha)
-
-        if ri.is_ha:
-            ri._ha_disable_addressing_on_interface(interface_name)
-            ri._add_vip(internal_cidr, interface_name)
-
-        ex_gw_port = ri.get_ex_gw_port()
-        if ri.router['distributed'] and ex_gw_port:
-            snat_ports = self.get_snat_interfaces(ri)
-            sn_port = self._map_internal_interfaces(ri, port, snat_ports)
-            if sn_port:
-                self._snat_redirect_add(ri, sn_port['fixed_ips'][0]
-                                        ['ip_address'], port, interface_name)
-                if (self.conf.agent_mode == l3_constants.L3_AGENT_MODE_DVR_SNAT
-                    and self.get_gw_port_host(ri.router) == self.host):
-                    ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
-                        ri.router['id'])
-                    self._set_subnet_info(sn_port)
-                    interface_name = (
-                          self.get_snat_int_device_name(sn_port['id']))
-                    self._internal_network_added(ns_name,
-                                                 sn_port['network_id'],
-                                                 sn_port['id'],
-                                                 sn_port['ip_cidr'],
-                                                 sn_port['mac_address'],
-                                                 interface_name,
-                                                 dvr.SNAT_INT_DEV_PREFIX)
-
-    def internal_network_removed(self, ri, port):
-        port_id = port['id']
-        interface_name = ri.get_internal_device_name(port_id)
-        if ri.router['distributed'] and ri.ex_gw_port:
-            sn_port = self._map_internal_interfaces(ri, port, ri.snat_ports)
-            if sn_port:
-                self._snat_redirect_remove(ri, sn_port['fixed_ips'][0]
-                                           ['ip_address'], port,
-                                           interface_name)
-                if (self.conf.agent_mode == l3_constants.L3_AGENT_MODE_DVR_SNAT
-                    and ri.ex_gw_port['binding:host_id'] == self.host):
-                    snat_interface = (
-                        self.get_snat_int_device_name(sn_port['id'])
-                    )
-                    ns_name = ri.snat_namespace.name
-                    prefix = dvr.SNAT_INT_DEV_PREFIX
-                    if ip_lib.device_exists(snat_interface,
-                                            namespace=ns_name):
-                        self.driver.unplug(snat_interface, namespace=ns_name,
-                                           prefix=prefix)
-
-        if ip_lib.device_exists(interface_name, namespace=ri.ns_name):
-            if ri.is_ha:
-                ri._clear_vips(interface_name)
-            self.driver.unplug(interface_name, namespace=ri.ns_name,
-                               prefix=INTERNAL_DEV_PREFIX)
-
     def router_deleted(self, context, router_id):
         """Deal with router deletion RPC message."""
         LOG.debug('Got router deleted notification for %s', router_id)
index 2496d1917532ea107000277e467f70d1a4f98fe1..d6829b63e87f3ab5a2e657d860e8992f8c4b53c3 100644 (file)
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import binascii
 import weakref
 
-import netaddr
 from oslo_log import log as logging
 
 from neutron.agent.l3 import dvr_fip_ns
 from neutron.agent.l3 import dvr_snat_ns
-from neutron.agent.linux import ip_lib
 from neutron.agent.linux import iptables_manager
-from neutron.common import constants as l3_constants
-from neutron.i18n import _LE
 
 LOG = logging.getLogger(__name__)
 
 # TODO(Carl) Following constants retained to increase SNR during refactoring
 SNAT_INT_DEV_PREFIX = dvr_snat_ns.SNAT_INT_DEV_PREFIX
 SNAT_NS_PREFIX = dvr_snat_ns.SNAT_NS_PREFIX
-# xor-folding mask used for IPv6 rule index
-MASK_30 = 0x3fffffff
 
 
 class AgentMixin(object):
@@ -65,52 +58,6 @@ class AgentMixin(object):
     def get_ports_by_subnet(self, subnet_id):
         return self.plugin_rpc.get_ports_by_subnet(self.context, subnet_id)
 
-    def get_snat_int_device_name(self, port_id):
-        return (SNAT_INT_DEV_PREFIX +
-                port_id)[:self.driver.DEV_NAME_LEN]
-
-    def get_snat_interfaces(self, ri):
-        return ri.router.get(l3_constants.SNAT_ROUTER_INTF_KEY, [])
-
-    def get_gw_port_host(self, router):
-        host = router.get('gw_port_host')
-        if not host:
-            LOG.debug("gw_port_host missing from router: %s",
-                      router['id'])
-        return host
-
-    def _get_snat_idx(self, ip_cidr):
-        """Generate index for DVR snat rules and route tables.
-
-        The index value has to be 32 bits or less but more than the system
-        generated entries i.e. 32768. For IPv4 use the numeric value of the
-        cidr. For IPv6 generate a crc32 bit hash and xor-fold to 30 bits.
-        Use the freed range to extend smaller values so that they become
-        greater than system generated entries.
-        """
-        net = netaddr.IPNetwork(ip_cidr)
-        if net.version == 6:
-            # the crc32 & 0xffffffff is for Python 2.6 and 3.0 compatibility
-            snat_idx = binascii.crc32(ip_cidr) & 0xffffffff
-            # xor-fold the hash to reserve upper range to extend smaller values
-            snat_idx = (snat_idx >> 30) ^ (snat_idx & MASK_30)
-            if snat_idx < 32768:
-                snat_idx = snat_idx + MASK_30
-        else:
-            snat_idx = net.value
-        return snat_idx
-
-    def _map_internal_interfaces(self, ri, int_port, snat_ports):
-        """Return the SNAT port for the given internal interface port."""
-        fixed_ip = int_port['fixed_ips'][0]
-        subnet_id = fixed_ip['subnet_id']
-        match_port = [p for p in snat_ports if
-                      p['fixed_ips'][0]['subnet_id'] == subnet_id]
-        if match_port:
-            return match_port[0]
-        else:
-            LOG.error(_LE('DVR: no map match_port found!'))
-
     def _create_dvr_gateway(self, ri, ex_gw_port, gw_interface_name,
                             snat_ports):
         """Create SNAT namespace."""
@@ -118,12 +65,13 @@ class AgentMixin(object):
         # connect snat_ports to br_int from SNAT namespace
         for port in snat_ports:
             # create interface_name
-            self._set_subnet_info(port)
-            interface_name = self.get_snat_int_device_name(port['id'])
-            self._internal_network_added(snat_ns.name, port['network_id'],
-                                         port['id'], port['ip_cidr'],
-                                         port['mac_address'], interface_name,
-                                         SNAT_INT_DEV_PREFIX)
+            ri._set_subnet_info(port)
+            interface_name = ri.get_snat_int_device_name(port['id'])
+            # TODO(Carl) calling private method on router.  Will fix soon.
+            ri._internal_network_added(snat_ns.name, port['network_id'],
+                                       port['id'], port['ip_cidr'],
+                                       port['mac_address'], interface_name,
+                                       SNAT_INT_DEV_PREFIX)
         self._external_gateway_added(ri, ex_gw_port, gw_interface_name,
                                      snat_ns.name, preserve_ips=[])
         ri.snat_iptables_manager = iptables_manager.IptablesManager(
@@ -132,33 +80,6 @@ class AgentMixin(object):
         # kicks the FW Agent to add rules for the snat namespace
         self.process_router_add(ri)
 
-    def _snat_redirect_add(self, ri, gateway, sn_port, sn_int):
-        """Adds rules and routes for SNAT redirection."""
-        try:
-            ip_cidr = sn_port['ip_cidr']
-            snat_idx = self._get_snat_idx(ip_cidr)
-            ns_ipr = ip_lib.IPRule(namespace=ri.ns_name)
-            ns_ipd = ip_lib.IPDevice(sn_int, namespace=ri.ns_name)
-            ns_ipwrapr = ip_lib.IPWrapper(namespace=ri.ns_name)
-            ns_ipd.route.add_gateway(gateway, table=snat_idx)
-            ns_ipr.rule.add(ip_cidr, snat_idx, snat_idx)
-            ns_ipwrapr.netns.execute(['sysctl', '-w', 'net.ipv4.conf.%s.'
-                                     'send_redirects=0' % sn_int])
-        except Exception:
-            LOG.exception(_LE('DVR: error adding redirection logic'))
-
-    def _snat_redirect_remove(self, ri, gateway, sn_port, sn_int):
-        """Removes rules and routes for SNAT redirection."""
-        try:
-            ip_cidr = sn_port['ip_cidr']
-            snat_idx = self._get_snat_idx(ip_cidr)
-            ns_ipr = ip_lib.IPRule(namespace=ri.ns_name)
-            ns_ipd = ip_lib.IPDevice(sn_int, namespace=ri.ns_name)
-            ns_ipd.route.delete_gateway(gateway, table=snat_idx)
-            ns_ipr.rule.delete(ip_cidr, snat_idx, snat_idx)
-        except Exception:
-            LOG.exception(_LE('DVR: removed snat failed'))
-
     def add_arp_entry(self, context, payload):
         """Add arp entry into router namespace.  Called from RPC."""
         router_id = payload['router_id']
index 0e1de86db0464a633cb9e8c1017084f77252517c..6af1e67adc2134fb57f91c04b0e1763048fc52e2 100644 (file)
@@ -12,6 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import binascii
+import netaddr
+
 from oslo_log import log as logging
 from oslo_utils import excutils
 
@@ -24,6 +27,8 @@ from neutron.common import utils as common_utils
 from neutron.i18n import _LE
 
 LOG = logging.getLogger(__name__)
+# xor-folding mask used for IPv6 rule index
+MASK_30 = 0x3fffffff
 
 
 class DvrRouter(router.RouterInfo):
@@ -45,6 +50,13 @@ class DvrRouter(router.RouterInfo):
         floating_ips = super(DvrRouter, self).get_floating_ips()
         return [i for i in floating_ips if i['host'] == self.host]
 
+    def get_snat_interfaces(self):
+        return self.router.get(l3_constants.SNAT_ROUTER_INTF_KEY, [])
+
+    def get_snat_int_device_name(self, port_id):
+        long_name = dvr_snat_ns.SNAT_INT_DEV_PREFIX + port_id
+        return long_name[:self.driver.DEV_NAME_LEN]
+
     def _handle_fip_nat_rules(self, interface_name, action):
         """Configures NAT rules for Floating IPs for DVR.
 
@@ -139,7 +151,6 @@ class DvrRouter(router.RouterInfo):
             return l3_constants.FLOATINGIP_STATUS_ERROR
 
         # Special Handling for DVR - update FIP namespace
-        # and ri.namespace to handle DVR based FIP
         ip_cidr = common_utils.ip_to_cidr(fip['floating_ip_address'])
         self.floating_ip_added_dist(fip, ip_cidr)
         return l3_constants.FLOATINGIP_STATUS_ACTIVE
@@ -212,3 +223,144 @@ class DvrRouter(router.RouterInfo):
                                            p['mac_address'],
                                            subnet_id,
                                            'add')
+
+    def _map_internal_interfaces(self, int_port, snat_ports):
+        """Return the SNAT port for the given internal interface port."""
+        fixed_ip = int_port['fixed_ips'][0]
+        subnet_id = fixed_ip['subnet_id']
+        match_port = [p for p in snat_ports if
+                      p['fixed_ips'][0]['subnet_id'] == subnet_id]
+        if match_port:
+            return match_port[0]
+        else:
+            LOG.error(_LE('DVR: no map match_port found!'))
+
+    @staticmethod
+    def _get_snat_idx(ip_cidr):
+        """Generate index for DVR snat rules and route tables.
+
+        The index value has to be 32 bits or less but more than the system
+        generated entries i.e. 32768. For IPv4 use the numeric value of the
+        cidr. For IPv6 generate a crc32 bit hash and xor-fold to 30 bits.
+        Use the freed range to extend smaller values so that they become
+        greater than system generated entries.
+        """
+        net = netaddr.IPNetwork(ip_cidr)
+        if net.version == 6:
+            # the crc32 & 0xffffffff is for Python 2.6 and 3.0 compatibility
+            snat_idx = binascii.crc32(ip_cidr) & 0xffffffff
+            # xor-fold the hash to reserve upper range to extend smaller values
+            snat_idx = (snat_idx >> 30) ^ (snat_idx & MASK_30)
+            if snat_idx < 32768:
+                snat_idx = snat_idx + MASK_30
+        else:
+            snat_idx = net.value
+        return snat_idx
+
+    def _snat_redirect_add(self, gateway, sn_port, sn_int):
+        """Adds rules and routes for SNAT redirection."""
+        try:
+            ip_cidr = sn_port['ip_cidr']
+            snat_idx = self._get_snat_idx(ip_cidr)
+            ns_ipr = ip_lib.IPRule(namespace=self.ns_name)
+            ns_ipd = ip_lib.IPDevice(sn_int, namespace=self.ns_name)
+            ns_ipwrapr = ip_lib.IPWrapper(namespace=self.ns_name)
+            ns_ipd.route.add_gateway(gateway, table=snat_idx)
+            ns_ipr.rule.add(ip_cidr, snat_idx, snat_idx)
+            ns_ipwrapr.netns.execute(['sysctl', '-w', 'net.ipv4.conf.%s.'
+                                     'send_redirects=0' % sn_int])
+        except Exception:
+            LOG.exception(_LE('DVR: error adding redirection logic'))
+
+    def _snat_redirect_remove(self, gateway, sn_port, sn_int):
+        """Removes rules and routes for SNAT redirection."""
+        try:
+            ip_cidr = sn_port['ip_cidr']
+            snat_idx = self._get_snat_idx(ip_cidr)
+            ns_ipr = ip_lib.IPRule(namespace=self.ns_name)
+            ns_ipd = ip_lib.IPDevice(sn_int, namespace=self.ns_name)
+            ns_ipd.route.delete_gateway(gateway, table=snat_idx)
+            ns_ipr.rule.delete(ip_cidr, snat_idx, snat_idx)
+        except Exception:
+            LOG.exception(_LE('DVR: removed snat failed'))
+
+    def get_gw_port_host(self):
+        host = self.router.get('gw_port_host')
+        if not host:
+            LOG.debug("gw_port_host missing from router: %s",
+                      self.router['id'])
+        return host
+
+    def internal_network_added(self, port):
+        super(DvrRouter, self).internal_network_added(port)
+
+        ex_gw_port = self.get_ex_gw_port()
+        if not ex_gw_port:
+            return
+
+        snat_ports = self.get_snat_interfaces()
+        sn_port = self._map_internal_interfaces(port, snat_ports)
+        if not sn_port:
+            return
+
+        interface_name = self.get_internal_device_name(port['id'])
+        self._snat_redirect_add(sn_port['fixed_ips'][0]['ip_address'],
+                                port,
+                                interface_name)
+
+        # TODO(Carl) This is a sign that dvr needs two router classes.
+        is_this_snat_host = (self.agent_conf.agent_mode == 'dvr_snat' and
+            self.get_gw_port_host() == self.host)
+        if not is_this_snat_host:
+            return
+
+        ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(self.router['id'])
+        self._set_subnet_info(sn_port)
+        interface_name = self.get_snat_int_device_name(sn_port['id'])
+        self._internal_network_added(
+            ns_name,
+            sn_port['network_id'],
+            sn_port['id'],
+            sn_port['ip_cidr'],
+            sn_port['mac_address'],
+            interface_name,
+            dvr_snat_ns.SNAT_INT_DEV_PREFIX)
+
+        self._set_subnet_arp_info(port)
+
+    def _dvr_internal_network_removed(self, port):
+        if not self.ex_gw_port:
+            return
+
+        sn_port = self._map_internal_interfaces(port, self.snat_ports)
+        if not sn_port:
+            return
+
+        # DVR handling code for SNAT
+        interface_name = self.get_internal_device_name(port['id'])
+        self._snat_redirect_remove(sn_port['fixed_ips'][0]['ip_address'],
+                                   port,
+                                   interface_name)
+
+        is_this_snat_host = (self.agent_conf.agent_mode == 'dvr_snat' and
+            self.ex_gw_port['binding:host_id'] == self.host)
+        if not is_this_snat_host:
+            return
+
+        snat_interface = (
+            self.get_snat_int_device_name(sn_port['id']))
+        ns_name = self.snat_namespace.name
+        prefix = dvr_snat_ns.SNAT_INT_DEV_PREFIX
+        if ip_lib.device_exists(snat_interface, namespace=ns_name):
+            self.driver.unplug(snat_interface, namespace=ns_name,
+                               prefix=prefix)
+
+    def internal_network_removed(self, port):
+        self._dvr_internal_network_removed(port)
+        super(DvrRouter, self).internal_network_removed(port)
+
+    def get_floating_agent_gw_interface(self, ext_net_id):
+        """Filter Floating Agent GW port for the external network."""
+        fip_ports = self.router.get(l3_constants.FLOATINGIP_AGENT_INTF_KEY, [])
+        return next(
+            (p for p in fip_ports if p['network_id'] == ext_net_id), None)
index cf693e39694bc42cd3b544d80cd377329de6d6b7..0b4e87127b681f28a58d6d13a3f5f41adf3d8b60 100644 (file)
@@ -61,7 +61,7 @@ class AgentMixin(object):
                       ri.router_id)
             return
 
-        self._set_subnet_info(ha_port)
+        ri._set_subnet_info(ha_port)
         ri.ha_network_added(ha_port['network_id'],
                             ha_port['id'],
                             ha_port['ip_cidr'],
index 83a25ee671a87468b2a676b7fcd5ce0376fc6f51..36bf0431e3a65bf8d244168ef334cf7127388f4d 100644 (file)
@@ -251,3 +251,24 @@ class HaRouter(router.RouterInfo):
 
     def remove_floating_ip(self, device, ip_cidr):
         self._remove_vip(ip_cidr)
+
+    def internal_network_added(self, port):
+        port_id = port['id']
+        interface_name = self.get_internal_device_name(port_id)
+
+        if not ip_lib.device_exists(interface_name, namespace=self.ns_name):
+            self.driver.plug(port['network_id'],
+                             port_id,
+                             interface_name,
+                             port['mac_address'],
+                             namespace=self.ns_name,
+                             prefix=router.INTERNAL_DEV_PREFIX)
+
+        self._ha_disable_addressing_on_interface(interface_name)
+        self._add_vip(port['ip_cidr'], interface_name)
+
+    def internal_network_removed(self, port):
+        super(HaRouter, self).internal_network_removed(port)
+
+        interface_name = self.get_internal_device_name(port['id'])
+        self._clear_vips(interface_name)
index ab44bf44933361bf466f4b485f73efe88e9faf2d..43cd6ef83ac52e8e9ced373edd5ca1b946a6e419 100644 (file)
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import netaddr
+
 from oslo_log import log as logging
 
 from neutron.agent.l3 import namespaces
@@ -20,10 +22,10 @@ from neutron.agent.linux import iptables_manager
 from neutron.common import constants as l3_constants
 from neutron.common import exceptions as n_exc
 from neutron.common import utils as common_utils
-from neutron.i18n import _LW
+from neutron.i18n import _LE, _LW
 
 LOG = logging.getLogger(__name__)
-INTERNAL_DEV_PREFIX = 'qr-'
+INTERNAL_DEV_PREFIX = namespaces.INTERNAL_DEV_PREFIX
 
 
 class RouterInfo(object):
@@ -86,6 +88,16 @@ class RouterInfo(object):
     def get_internal_device_name(self, port_id):
         return (INTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
 
+    def _set_subnet_info(self, port):
+        ips = port['fixed_ips']
+        if not ips:
+            raise Exception(_("Router port %s has no IP address") % port['id'])
+        if len(ips) > 1:
+            LOG.error(_LE("Ignoring multiple IPs on router port %s"),
+                      port['id'])
+        prefixlen = netaddr.IPNetwork(port['subnet']['cidr']).prefixlen
+        port['ip_cidr'] = "%s/%s" % (ips[0]['ip_address'], prefixlen)
+
     def perform_snat_action(self, snat_callback, *args):
         # Process SNAT rules for attached subnets
         if self._snat_action:
@@ -245,3 +257,95 @@ class RouterInfo(object):
         self.radvd.disable()
         if self.router_namespace:
             self.router_namespace.delete()
+
+    def _internal_network_added(self, ns_name, network_id, port_id,
+                                internal_cidr, mac_address,
+                                interface_name, prefix):
+        if not ip_lib.device_exists(interface_name,
+                                    namespace=ns_name):
+            self.driver.plug(network_id, port_id, interface_name, mac_address,
+                             namespace=ns_name,
+                             prefix=prefix)
+
+        self.driver.init_l3(interface_name, [internal_cidr],
+                            namespace=ns_name)
+        ip_address = internal_cidr.split('/')[0]
+        ip_lib.send_gratuitous_arp(ns_name,
+                                   interface_name,
+                                   ip_address,
+                                   self.agent_conf.send_arp_for_ha)
+
+    def internal_network_added(self, port):
+        network_id = port['network_id']
+        port_id = port['id']
+        internal_cidr = port['ip_cidr']
+        mac_address = port['mac_address']
+
+        interface_name = self.get_internal_device_name(port_id)
+
+        self._internal_network_added(self.ns_name,
+                                     network_id,
+                                     port_id,
+                                     internal_cidr,
+                                     mac_address,
+                                     interface_name,
+                                     INTERNAL_DEV_PREFIX)
+
+    def internal_network_removed(self, port):
+        interface_name = self.get_internal_device_name(port['id'])
+
+        if ip_lib.device_exists(interface_name, namespace=self.ns_name):
+            self.driver.unplug(interface_name, namespace=self.ns_name,
+                               prefix=INTERNAL_DEV_PREFIX)
+
+    def _get_existing_devices(self):
+        ip_wrapper = ip_lib.IPWrapper(namespace=self.ns_name)
+        ip_devs = ip_wrapper.get_devices(exclude_loopback=True)
+        return [ip_dev.name for ip_dev in ip_devs]
+
+    def _process_internal_ports(self):
+        existing_port_ids = set(p['id'] for p in self.internal_ports)
+
+        internal_ports = self.router.get(l3_constants.INTERFACE_KEY, [])
+        current_port_ids = set(p['id'] for p in internal_ports
+                               if p['admin_state_up'])
+
+        new_port_ids = current_port_ids - existing_port_ids
+        new_ports = [p for p in internal_ports if p['id'] in new_port_ids]
+        old_ports = [p for p in self.internal_ports
+                     if p['id'] not in current_port_ids]
+
+        new_ipv6_port = False
+        old_ipv6_port = False
+        for p in new_ports:
+            self._set_subnet_info(p)
+            self.internal_network_added(p)
+            self.internal_ports.append(p)
+            if (not new_ipv6_port and
+                    netaddr.IPNetwork(p['subnet']['cidr']).version == 6):
+                new_ipv6_port = True
+
+        for p in old_ports:
+            self.internal_network_removed(p)
+            self.internal_ports.remove(p)
+            if (not old_ipv6_port and
+                    netaddr.IPNetwork(p['subnet']['cidr']).version == 6):
+                old_ipv6_port = True
+
+        # Enable RA
+        if new_ipv6_port or old_ipv6_port:
+            self.radvd.enable(internal_ports)
+
+        existing_devices = self._get_existing_devices()
+        current_internal_devs = set(n for n in existing_devices
+                                    if n.startswith(
+                                        INTERNAL_DEV_PREFIX))
+        current_port_devs = set(self.get_internal_device_name(port_id)
+                                for port_id in current_port_ids)
+        stale_devs = current_internal_devs - current_port_devs
+        for stale_dev in stale_devs:
+            LOG.debug('Deleting stale internal router device: %s',
+                      stale_dev)
+            self.driver.unplug(stale_dev,
+                               namespace=self.ns_name,
+                               prefix=INTERNAL_DEV_PREFIX)
index 974852f3f0b19952a8620fc72d6324348dbb93b5..ef3dd5f71dda2ac3405a0a5d1e741d5386f9d05a 100644 (file)
@@ -184,3 +184,25 @@ class TestDvrRouterOperations(base.BaseTestCase):
         router_ports = [port]
         ri.router.get.return_value = router_ports
         self.assertEqual(None, ri._get_internal_port(mock.sentinel.subnet_id2))
+
+    def test__get_snat_idx_ipv4(self):
+        ip_cidr = '101.12.13.00/24'
+        ri = self._create_router(mock.MagicMock())
+        snat_idx = ri._get_snat_idx(ip_cidr)
+        # 0x650C0D00 is numerical value of 101.12.13.00
+        self.assertEqual(0x650C0D00, snat_idx)
+
+    def test__get_snat_idx_ipv6(self):
+        ip_cidr = '2620:0:a03:e100::/64'
+        ri = self._create_router(mock.MagicMock())
+        snat_idx = ri._get_snat_idx(ip_cidr)
+        # 0x3D345705 is 30 bit xor folded crc32 of the ip_cidr
+        self.assertEqual(0x3D345705, snat_idx)
+
+    def test__get_snat_idx_ipv6_below_32768(self):
+        ip_cidr = 'd488::/30'
+        # crc32 of this ip_cidr is 0x1BD7
+        ri = self._create_router(mock.MagicMock())
+        snat_idx = ri._get_snat_idx(ip_cidr)
+        # 0x1BD7 + 0x3FFFFFFF = 0x40001BD6
+        self.assertEqual(0x40001BD6, snat_idx)
index 8a9415a234eb30b6b09a0e3b78ffa7fbe120ade9..fe41f77360f9096497d6d2e949a775873989197b 100644 (file)
@@ -279,23 +279,6 @@ class BasicRouterOperationsFramework(base.BaseTestCase):
         self.ri_kwargs = {'agent_conf': self.conf,
                           'interface_driver': self.mock_driver}
 
-    def _prepare_internal_network_data(self):
-        port_id = _uuid()
-        router_id = _uuid()
-        network_id = _uuid()
-        router = prepare_router_data(num_internal_ports=2)
-        router_id = router['id']
-        agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
-        ri = l3router.RouterInfo(router_id, router,
-                                 **self.ri_kwargs)
-        cidr = '99.0.1.9/24'
-        mac = 'ca:fe:de:ad:be:ef'
-        port = {'network_id': network_id,
-                'id': port_id, 'ip_cidr': cidr,
-                'mac_address': mac}
-
-        return agent, ri, port
-
     def _process_router_instance_for_agent(self, agent, ri, router):
         ri.router = router
         if not ri.radvd:
@@ -361,26 +344,41 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
         l3_agent.L3NATAgent(HOSTNAME, self.conf)
 
     def _test_internal_network_action(self, action):
-        agent, ri, port = self._prepare_internal_network_data()
+        router = prepare_router_data(num_internal_ports=2)
+        router_id = router['id']
+        ri = l3router.RouterInfo(router_id, router, **self.ri_kwargs)
+        port = {'network_id': _uuid(),
+                'id': _uuid(),
+                'ip_cidr': '99.0.1.9/24',
+                'mac_address': 'ca:fe:de:ad:be:ef'}
+
         interface_name = ri.get_internal_device_name(port['id'])
 
         if action == 'add':
             self.device_exists.return_value = False
-            agent.internal_network_added(ri, port)
+            ri.internal_network_added(port)
             self.assertEqual(self.mock_driver.plug.call_count, 1)
             self.assertEqual(self.mock_driver.init_l3.call_count, 1)
             self.send_arp.assert_called_once_with(ri.ns_name, interface_name,
                                                   '99.0.1.9', mock.ANY)
         elif action == 'remove':
             self.device_exists.return_value = True
-            agent.internal_network_removed(ri, port)
+            ri.internal_network_removed(port)
             self.assertEqual(self.mock_driver.unplug.call_count, 1)
         else:
             raise Exception("Invalid action %s" % action)
 
     def _test_internal_network_action_dist(self, action):
-        agent, ri, port = self._prepare_internal_network_data()
-        ri.router['distributed'] = True
+        router = prepare_router_data(num_internal_ports=2)
+        router_id = router['id']
+        agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
+        ri = dvr_router.DvrRouter(
+            agent, HOSTNAME, router_id, router, **self.ri_kwargs)
+        port = {'network_id': _uuid(),
+                'id': _uuid(),
+                'ip_cidr': '99.0.1.9/24',
+                'mac_address': 'ca:fe:de:ad:be:ef'}
+
         ri.router['gw_port_host'] = HOSTNAME
         agent.host = HOSTNAME
         agent.conf.agent_mode = 'dvr_snat'
@@ -408,29 +406,30 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
         if action == 'add':
             self.device_exists.return_value = False
 
-            agent._map_internal_interfaces = mock.Mock(return_value=sn_port)
-            agent._snat_redirect_add = mock.Mock()
-            agent._set_subnet_info = mock.Mock()
-            agent._internal_network_added = mock.Mock()
-            agent.internal_network_added(ri, port)
-            self.assertEqual(agent._snat_redirect_add.call_count, 1)
-            self.assertEqual(agent._set_subnet_info.call_count, 1)
-            self.assertEqual(agent._internal_network_added.call_count, 2)
-            agent._internal_network_added.assert_called_with(
+            ri._map_internal_interfaces = mock.Mock(return_value=sn_port)
+            ri._snat_redirect_add = mock.Mock()
+            ri._set_subnet_info = mock.Mock()
+            ri._set_subnet_arp_info = mock.Mock()
+            ri._internal_network_added = mock.Mock()
+            ri.internal_network_added(port)
+            self.assertEqual(ri._snat_redirect_add.call_count, 1)
+            self.assertEqual(ri._set_subnet_info.call_count, 1)
+            self.assertEqual(ri._internal_network_added.call_count, 2)
+            ri._set_subnet_arp_info.assert_called_once_with(port)
+            ri._internal_network_added.assert_called_with(
                 dvr_snat_ns.SnatNamespace.get_snat_ns_name(ri.router['id']),
                 sn_port['network_id'],
                 sn_port['id'],
                 sn_port['ip_cidr'],
                 sn_port['mac_address'],
-                agent.get_snat_int_device_name(sn_port['id']),
+                ri.get_snat_int_device_name(sn_port['id']),
                 dvr_snat_ns.SNAT_INT_DEV_PREFIX)
         elif action == 'remove':
             self.device_exists.return_value = False
-            agent._map_internal_interfaces = mock.Mock(return_value=sn_port)
-            agent._snat_redirect_remove = mock.Mock()
-            agent.internal_network_removed(ri, port)
-            agent._snat_redirect_remove.assert_called_with(
-                ri,
+            ri._map_internal_interfaces = mock.Mock(return_value=sn_port)
+            ri._snat_redirect_remove = mock.Mock()
+            ri.internal_network_removed(port)
+            ri._snat_redirect_remove.assert_called_with(
                 sn_port['fixed_ips'][0]['ip_address'],
                 port,
                 ri.get_internal_device_name(port['id']))
@@ -456,12 +455,12 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
             agent.conf.agent_mode = 'dvr_snat'
             agent.host = HOSTNAME
             agent._create_dvr_gateway = mock.Mock()
-            agent.get_snat_interfaces = mock.Mock(return_value=self.snat_ports)
             ri = dvr_router.DvrRouter(agent,
                                       HOSTNAME,
                                       router['id'],
                                       router,
                                       **self.ri_kwargs)
+            ri.get_snat_interfaces = mock.Mock(return_value=self.snat_ports)
             ri.create_snat_namespace()
             ri.fip_ns = agent.get_fip_ns(ex_net_id)
             ri.internal_ports = self.snat_ports
@@ -509,7 +508,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
         elif action == 'remove':
             self.device_exists.return_value = True
             agent._map_internal_interfaces = mock.Mock(return_value=sn_port)
-            agent._snat_redirect_remove = mock.Mock()
+            ri._snat_redirect_remove = mock.Mock()
             agent.external_gateway_removed(ri, ex_gw_port, interface_name)
             if not router.get('distributed'):
                 self.mock_driver.unplug.assert_called_once_with(
@@ -518,8 +517,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
                     namespace=mock.ANY,
                     prefix=mock.ANY)
             else:
-                agent._snat_redirect_remove.assert_called_with(
-                    ri,
+                ri._snat_redirect_remove.assert_called_with(
                     sn_port['fixed_ips'][0]['ip_address'],
                     sn_port,
                     ri.get_internal_device_name(sn_port['id']))
@@ -643,32 +641,13 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
             else:
                 self.assertIn(r.rule, expected_rules)
 
-    def test__get_snat_idx_ipv4(self):
-        ip_cidr = '101.12.13.00/24'
-        agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
-        snat_idx = agent._get_snat_idx(ip_cidr)
-        # 0x650C0D00 is numerical value of 101.12.13.00
-        self.assertEqual(0x650C0D00, snat_idx)
-
-    def test__get_snat_idx_ipv6(self):
-        ip_cidr = '2620:0:a03:e100::/64'
-        agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
-        snat_idx = agent._get_snat_idx(ip_cidr)
-        # 0x3D345705 is 30 bit xor folded crc32 of the ip_cidr
-        self.assertEqual(0x3D345705, snat_idx)
-
-    def test__get_snat_idx_ipv6_below_32768(self):
-        ip_cidr = 'd488::/30'
-        # crc32 of this ip_cidr is 0x1BD7
-        agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
-        snat_idx = agent._get_snat_idx(ip_cidr)
-        # 0x1BD7 + 0x3FFFFFFF = 0x40001BD6
-        self.assertEqual(0x40001BD6, snat_idx)
-
     def test__map_internal_interfaces(self):
-        agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
         router = prepare_router_data(num_internal_ports=4)
-        ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
+        ri = dvr_router.DvrRouter(mock.sentinel.agent,
+                                  HOSTNAME,
+                                  router['id'],
+                                  router,
+                                  **self.ri_kwargs)
         test_port = {
             'mac_address': '00:12:23:34:45:56',
             'fixed_ips': [{'subnet_id': _get_subnet_id(
@@ -676,15 +655,11 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
                 'ip_address': '101.12.13.14'}]}
         internal_ports = ri.router.get(l3_constants.INTERFACE_KEY, [])
         # test valid case
-        res_port = agent._map_internal_interfaces(ri,
-                                                  internal_ports[0],
-                                                  [test_port])
+        res_port = ri._map_internal_interfaces(internal_ports[0], [test_port])
         self.assertEqual(test_port, res_port)
         # test invalid case
         test_port['fixed_ips'][0]['subnet_id'] = 1234
-        res_ip = agent._map_internal_interfaces(ri,
-                                                internal_ports[0],
-                                                [test_port])
+        res_ip = ri._map_internal_interfaces(internal_ports[0], [test_port])
         self.assertNotEqual(test_port, res_ip)
         self.assertIsNone(res_ip)
 
@@ -907,7 +882,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
             agent, HOSTNAME, router['id'], router, **self.ri_kwargs)
         self.assertEqual(
             agent_gateway_port[0],
-            agent.get_floating_agent_gw_interface(ri, fake_network_id))
+            ri.get_floating_agent_gw_interface(fake_network_id))
 
     @mock.patch.object(lla.LinkLocalAllocator, '_write')
     def test_create_dvr_fip_interfaces(self, lla_write):
@@ -945,9 +920,9 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
         with contextlib.nested(mock.patch.object(ri,
                                                  'get_floating_ips'),
                                mock.patch.object(
-                                   agent, 'get_floating_agent_gw_interface'),
+                                   ri, 'get_floating_agent_gw_interface'),
                                mock.patch.object(
-                                   agent, '_set_subnet_info')
+                                   ri, '_set_subnet_info')
                                ) as (fips,
                                      fip_gw_port,
                                      sub_info):
@@ -1205,7 +1180,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
         ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
         agent.external_gateway_added = mock.Mock()
         with mock.patch.object(
-                l3_agent.L3NATAgent,
+                ri,
                 'internal_network_added') as internal_network_added:
             # raise RuntimeError to simulate that an unexpected exception
             # occurs
@@ -1233,7 +1208,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
         agent.process_router(ri)
 
         with mock.patch.object(
-                l3_agent.L3NATAgent,
+                ri,
                 'internal_network_removed') as internal_net_removed:
             # raise RuntimeError to simulate that an unexpected exception
             # occurs
@@ -1384,9 +1359,9 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
         self.assertEqual(len(internal_ports), 1)
         internal_port = internal_ports[0]
 
-        with contextlib.nested(mock.patch.object(l3_agent.L3NATAgent,
+        with contextlib.nested(mock.patch.object(ri,
                                                  'internal_network_removed'),
-                               mock.patch.object(l3_agent.L3NATAgent,
+                               mock.patch.object(ri,
                                                  'internal_network_added'),
                                mock.patch.object(l3_agent.L3NATAgent,
                                                  'external_gateway_removed'),
@@ -1402,8 +1377,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
             self.assertEqual(external_gateway_added.call_count, 1)
             self.assertFalse(external_gateway_removed.called)
             self.assertFalse(internal_network_removed.called)
-            internal_network_added.assert_called_once_with(
-                ri, internal_port)
+            internal_network_added.assert_called_once_with(internal_port)
             self.assertEqual(self.mock_driver.unplug.call_count,
                              len(stale_devnames))
             calls = [mock.call(stale_devname,
@@ -1767,7 +1741,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
                        'mac_address': 'ca:fe:de:ad:be:ef',
                        'ip_cidr': '20.0.0.30/24'}
 
-        interface_name = agent.get_snat_int_device_name(port_id)
+        interface_name = ri.get_snat_int_device_name(port_id)
         self.device_exists.return_value = False
 
         agent._create_dvr_gateway(ri, dvr_gw_port, interface_name,