]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Improve DVR scale performance
authorErik Colnick <erik.colnick@hp.com>
Fri, 23 Jan 2015 19:16:28 +0000 (12:16 -0700)
committerErik Colnick <erik.colnick@hp.com>
Thu, 19 Mar 2015 13:21:53 +0000 (07:21 -0600)
Only process floating ips on a router that are relevant to the agent
hosting the router (don't process floating ips assigned to a router
if the associated vm is not hosted on the compute node requesting the
router sync). In this way, the number of database calls made during
the DVR router updates is optimized to eliminate unnecessary
duplication of calls which return the same data or are made to get
data for routers which are not relevant to the sync_routers request
from the agent.

Change-Id: I4e8477bb61ffff164d2f3bbebb94e95a25838ce0
Partial-Bug: #1413314

neutron/db/l3_dvr_db.py
neutron/db/l3_dvrscheduler_db.py
neutron/db/l3_hamode_db.py
neutron/tests/unit/db/test_l3_dvr_db.py

index d98c574adcd72783d33b4b24337983b3c131b91d..2912744bd06955bf6f4a33cd4b5c802aed54b586 100644 (file)
@@ -414,30 +414,26 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
                 router[SNAT_ROUTER_INTF_KEY] = snat_router_intfs
         return routers_dict
 
-    def _process_floating_ips(self, context, routers_dict, floating_ips):
+    def _process_floating_ips_dvr(self, context, routers_dict,
+                                  floating_ips, host, agent):
+        fip_sync_interfaces = None
+        LOG.debug("FIP Agent : %s ", agent.id)
         for floating_ip in floating_ips:
             router = routers_dict.get(floating_ip['router_id'])
             if router:
                 router_floatingips = router.get(l3_const.FLOATINGIP_KEY, [])
-                floatingip_agent_intfs = []
                 if router['distributed']:
-                    floating_ip['host'] = self.get_vm_port_hostid(
-                        context, floating_ip['port_id'])
-                    LOG.debug("Floating IP host: %s", floating_ip['host'])
-                    # if no VM there won't be an agent assigned
-                    if not floating_ip['host']:
+                    if floating_ip.get('host', None) != host:
                         continue
-                    fip_agent = self._get_agent_by_type_and_host(
-                        context, l3_const.AGENT_TYPE_L3,
-                        floating_ip['host'])
-                    LOG.debug("FIP Agent : %s ", fip_agent['id'])
-                    floatingip_agent_intfs = self.get_fip_sync_interfaces(
-                        context, fip_agent['id'])
-                    LOG.debug("FIP Agent ports: %s", floatingip_agent_intfs)
+                    LOG.debug("Floating IP host: %s", floating_ip['host'])
                 router_floatingips.append(floating_ip)
                 router[l3_const.FLOATINGIP_KEY] = router_floatingips
+                if not fip_sync_interfaces:
+                    fip_sync_interfaces = self.get_fip_sync_interfaces(
+                        context, agent.id)
+                    LOG.debug("FIP Agent ports: %s", fip_sync_interfaces)
                 router[l3_const.FLOATINGIP_AGENT_INTF_KEY] = (
-                    floatingip_agent_intfs)
+                    fip_sync_interfaces)
 
     def get_fip_sync_interfaces(self, context, fip_agent_id):
         """Query router interfaces that relate to list of router_ids."""
@@ -451,15 +447,23 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
             self._populate_subnet_for_ports(context, interfaces)
         return interfaces
 
-    def get_sync_data(self, context, router_ids=None, active=None):
+    def get_dvr_sync_data(self, context, host, agent, router_ids=None,
+                          active=None):
         routers, interfaces, floating_ips = self._get_router_info_list(
             context, router_ids=router_ids, active=active,
             device_owners=l3_const.ROUTER_INTERFACE_OWNERS)
+        port_filter = {portbindings.HOST_ID: [host]}
+        ports = self._core_plugin.get_ports(context, port_filter)
+        port_dict = dict((port['id'], port) for port in ports)
         # Add the port binding host to the floatingip dictionary
         for fip in floating_ips:
-            fip['host'] = self.get_vm_port_hostid(context, fip['port_id'])
+            vm_port = port_dict.get(fip['port_id'], None)
+            if vm_port:
+                fip['host'] = self.get_vm_port_hostid(context, fip['port_id'],
+                                                      port=vm_port)
         routers_dict = self._process_routers(context, routers)
-        self._process_floating_ips(context, routers_dict, floating_ips)
+        self._process_floating_ips_dvr(context, routers_dict,
+                                       floating_ips, host, agent)
         self._process_interfaces(routers_dict, interfaces)
         return routers_dict.values()
 
index e67c97f631b43455f4274ca6a39f5e310bbb0816..5592beaf694b804612e5deb186e02dfa72da4d07 100644 (file)
@@ -315,6 +315,15 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin):
                 context, router_id, chosen_agent)
             return chosen_agent
 
+    def _get_active_l3_agent_routers_sync_data(self, context, host, agent,
+                                               router_ids):
+        if n_utils.is_extension_supported(self, q_const.L3_HA_MODE_EXT_ALIAS):
+            return self.get_ha_sync_data_for_host(context, host,
+                                                  router_ids=router_ids,
+                                                  active=True)
+        return self.get_dvr_sync_data(context, host, agent,
+                                      router_ids=router_ids, active=True)
+
 
 def _notify_l3_agent_new_port(resource, event, trigger, **kwargs):
     LOG.debug('Received %s %s' % (resource, event))
index 1c0a6e59576675f162a8a975bbd61e91db0d5d15..3f52e0a5e7192f0086fcf5634896b52e5ce1381c 100644 (file)
@@ -23,6 +23,7 @@ from sqlalchemy import orm
 
 from neutron.api.v2 import attributes
 from neutron.common import constants
+from neutron.common import utils as n_utils
 from neutron.db import agents_db
 from neutron.db import l3_dvr_db
 from neutron.db import model_base
@@ -458,7 +459,15 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin):
 
     def get_ha_sync_data_for_host(self, context, host=None, router_ids=None,
                                   active=None):
-        sync_data = super(L3_HA_NAT_db_mixin, self).get_sync_data(context,
-                                                                  router_ids,
-                                                                  active)
+        if n_utils.is_extension_supported(self,
+                                          constants.L3_DISTRIBUTED_EXT_ALIAS):
+            # DVR has to be handled differently
+            agent = self._get_agent_by_type_and_host(context,
+                                                     constants.AGENT_TYPE_L3,
+                                                     host)
+            sync_data = self.get_dvr_sync_data(context, host, agent,
+                                               router_ids, active)
+        else:
+            sync_data = super(L3_HA_NAT_db_mixin, self).get_sync_data(context,
+                                                            router_ids, active)
         return self._process_sync_ha_data(context, sync_data, host)
index 9f6dc01700a122696d2152db1ced2b9a64b047e9..d9ec10463561fc5b3bdf07672c43f8855168194f 100644 (file)
@@ -317,8 +317,11 @@ class L3DvrTestCase(testlib_api.SqlTestCase):
         floatingip = {
             'id': _uuid(),
             'port_id': _uuid(),
-            'router_id': 'foo_router_id'
+            'router_id': 'foo_router_id',
+            'host': hostid
         }
+        if not hostid:
+            hostid = 'not_my_host_id'
         routers = {
             'foo_router_id': router
         }
@@ -334,25 +337,22 @@ class L3DvrTestCase(testlib_api.SqlTestCase):
             return_value=fipagent)
         self.mixin.get_fip_sync_interfaces = mock.Mock(
             return_value='fip_interface')
+        agent = mock.Mock()
+        agent.id = fipagent['id']
 
-        self.mixin._process_floating_ips(self.ctx, routers, [floatingip])
+        self.mixin._process_floating_ips_dvr(self.ctx, routers, [floatingip],
+                                             hostid, agent)
         return (router, floatingip)
 
-    def test_floatingip_on_port_no_host(self):
+    def test_floatingip_on_port_not_host(self):
         router, fip = self._floatingip_on_port_test_setup(None)
 
-        self.assertTrue(self.mixin.get_vm_port_hostid.called)
-        self.assertFalse(self.mixin._get_agent_by_type_and_host.called)
-        self.assertFalse(self.mixin.get_fip_sync_interfaces.called)
-
         self.assertNotIn(l3_const.FLOATINGIP_KEY, router)
         self.assertNotIn(l3_const.FLOATINGIP_AGENT_INTF_KEY, router)
 
     def test_floatingip_on_port_with_host(self):
         router, fip = self._floatingip_on_port_test_setup(_uuid())
 
-        self.assertTrue(self.mixin.get_vm_port_hostid.called)
-        self.assertTrue(self.mixin._get_agent_by_type_and_host.called)
         self.assertTrue(self.mixin.get_fip_sync_interfaces.called)
 
         self.assertIn(l3_const.FLOATINGIP_KEY, router)