File 0001-l2-pop-check-for-more-than-1-first-active-port-on-a-.patch of Package openstack-neutron

From 1ba5e6964b5eadd660f2f333e774ce174c4e6f06 Mon Sep 17 00:00:00 2001
From: Oleg Bondarev <obondarev@mirantis.com>
Date: Thu, 30 Aug 2018 12:25:07 +0400
Subject: [PATCH] l2 pop: check for more than 1 first active port on a node

With high concurrency more than 1 port may be activated on an
OVS agent at the same time (like VM port + a DVR port),
so the patch mitigates the condition by checking for 1 or 2
first active ports.

Given that the condition also contains "or self.agent_restarted(context)"
which makes it True first 180 sec (by default) after agent restart,
I believe the downside of changing 1 to 2 should be negligible.

Please see bug for more details on the issue.

Closes-Bug: #1789846
Change-Id: Ieab0186cbe05185d47bbf5a31141563cf923f66f
(cherry picked from commit b32db30874a7729c4e9209cfc18e106a7e9fc697)
---
 .../plugins/ml2/drivers/l2pop/mech_driver.py  |  9 ++--
 .../ml2/drivers/l2pop/test_mech_driver.py     | 54 +++++++++++++++++++
 2 files changed, 60 insertions(+), 3 deletions(-)

Index: neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/l2pop/mech_driver.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/plugins/ml2/drivers/l2pop/mech_driver.py
+++ neutron-9.4.2.dev21/neutron/plugins/ml2/drivers/l2pop/mech_driver.py
@@ -273,9 +273,12 @@ class L2populationMechanismDriver(api.Me
             segment, agent_ip, network_id)
         other_fdb_ports = other_fdb_entries[network_id]['ports']
 
-        if agent_active_ports == 1 or (l2pop_db.get_agent_uptime(agent) <
-                                       cfg.CONF.l2pop.agent_boot_time):
-            # First port activated on current agent in this network,
+        # with high concurrency more than 1 port may be activated on an agent
+        # at the same time (like VM port + a DVR port) so checking for 1 or 2
+        is_first_port = agent_active_ports in (1, 2)
+        if is_first_port or (l2pop_db.get_agent_uptime(agent) <
+                             cfg.CONF.l2pop.agent_boot_time):
+            # First port(s) activated on current agent in this network,
             # we have to provide it with the whole list of fdb entries
             agent_fdb_entries = self._create_agent_fdb(session,
                                                        agent,
Index: neutron-9.4.2.dev21/neutron/tests/unit/plugins/ml2/drivers/l2pop/test_mech_driver.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/tests/unit/plugins/ml2/drivers/l2pop/test_mech_driver.py
+++ neutron-9.4.2.dev21/neutron/tests/unit/plugins/ml2/drivers/l2pop/test_mech_driver.py
@@ -707,6 +707,60 @@ class TestL2PopulationRpcTestCase(test_p
                 self.mock_fanout.assert_called_with(
                     mock.ANY, 'add_fdb_entries', expected)
 
+    def test_update_port_up_two_active_ports(self):
+        '''The test will check that even with 2 active ports on the host,
+        agent will be provided with the whole list of fdb entries. Bug 1789846
+        '''
+        self._register_ml2_agents()
+
+        with self.subnet(network=self._network) as subnet:
+            host_arg = {portbindings.HOST_ID: HOST}
+            # 2 ports on host 1
+            with self.port(subnet=subnet,
+                           device_owner=DEVICE_OWNER_COMPUTE,
+                           arg_list=(portbindings.HOST_ID,),
+                           **host_arg) as port1:
+                with self.port(subnet=subnet,
+                               device_owner=DEVICE_OWNER_COMPUTE,
+                               arg_list=(portbindings.HOST_ID,),
+                               **host_arg) as port2:
+                    # 1 port on another host to have fdb entree to update
+                    # agent on host 1
+                    host_arg = {portbindings.HOST_ID: HOST + '_2'}
+                    with self.port(subnet=subnet,
+                                   device_owner=DEVICE_OWNER_COMPUTE,
+                                   arg_list=(portbindings.HOST_ID,),
+                                   **host_arg) as port3:
+                        p1 = port1['port']
+                        p2 = port2['port']
+                        p3 = port3['port']
+
+                        # only ACTIVE ports count
+                        plugin = directory.get_plugin()
+                        p2['status'] = 'ACTIVE'
+                        plugin.update_port(self.adminContext, p2['id'], port2)
+                        p3['status'] = 'ACTIVE'
+                        plugin.update_port(self.adminContext, p3['id'], port3)
+
+                        self.mock_cast.reset_mock()
+                        p1['status'] = 'ACTIVE'
+                        plugin.update_port(self.adminContext, p1['id'], port1)
+
+                        # agent on host 1 should be updated with entry from
+                        # another host
+                        expected = {p3['network_id']:
+                            {'ports':
+                             {'20.0.0.2': [
+                                 constants.FLOODING_ENTRY,
+                                 l2pop_rpc.PortInfo(
+                                     p3['mac_address'],
+                                     p3['fixed_ips'][0]['ip_address'])]},
+                             'network_type': 'vxlan',
+                             'segment_id': 1}}
+
+                        self.mock_cast.assert_called_once_with(
+                            mock.ANY, 'add_fdb_entries', expected, HOST)
+
     def test_update_port_down(self):
         self._register_ml2_agents()
 
openSUSE Build Service is sponsored by