Browse Source

Don't crash ovs agent during reconfigure of phys bridges

In case when physical bridge was recreated on host, ovs agent
is trying to reconfigure it.
If there will be e.g. timeout while getting bridge's datapath_id,
RuntimeError will be raised and that caused crash of whole agent.

This patch changes that to not crash agent in such case but try to
reconfigure everything in next rpc_loop iteration once again.

Conflicts:
    neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py
    neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py

Change-Id: Ic9b17a420068c0c76748e2c24d97be1ed7c460c7
Closes-Bug: #1837380
(cherry picked from commit b63809715a)
changes/71/673171/1
Slawek Kaplonski 1 month ago
parent
commit
fa2863be86

+ 20
- 1
neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py View File

@@ -179,6 +179,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
179 179
         # keeps association between ports and ofports to detect ofport change
180 180
         self.vifname_to_ofport_map = {}
181 181
         self.setup_rpc()
182
+        # Stores newly created bridges
183
+        self.added_bridges = list()
182 184
         self.bridge_mappings = self._parse_bridge_mappings(
183 185
             ovs_conf.bridge_mappings)
184 186
         self.setup_physical_bridges(self.bridge_mappings)
@@ -1078,6 +1080,21 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
1078 1080
                                         self.arp_responder_enabled)
1079 1081
 
1080 1082
     def _reconfigure_physical_bridges(self, bridges):
1083
+        try:
1084
+            sync = self._do_reconfigure_physical_bridges(bridges)
1085
+            self.added_bridges = []
1086
+        except RuntimeError:
1087
+            # If there was error and bridges aren't properly reconfigured,
1088
+            # there is no need to do full sync once again. It will be done when
1089
+            # reconfiguration of physical bridges will be finished without
1090
+            # errors
1091
+            sync = False
1092
+            self.added_bridges = bridges
1093
+            LOG.warning("RuntimeError during setup of physical bridges: %s",
1094
+                        bridges)
1095
+        return sync
1096
+
1097
+    def _do_reconfigure_physical_bridges(self, bridges):
1081 1098
         sync = False
1082 1099
         bridge_mappings = {}
1083 1100
         for bridge in bridges:
@@ -2083,8 +2100,10 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
2083 2100
                 continue
2084 2101
             # Check if any physical bridge wasn't recreated recently
2085 2102
             if bridges_monitor:
2103
+                added_bridges = (
2104
+                    bridges_monitor.bridges_added + self.added_bridges)
2086 2105
                 bridges_recreated = self._reconfigure_physical_bridges(
2087
-                    bridges_monitor.bridges_added)
2106
+                    added_bridges)
2088 2107
                 sync |= bridges_recreated
2089 2108
             # Notify the plugin of tunnel IP
2090 2109
             if self.enable_tunneling and tunnel_sync:

+ 17
- 4
neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py View File

@@ -1680,7 +1680,7 @@ class TestOvsNeutronAgent(object):
1680 1680
             self.agent.reclaim_local_vlan('net2')
1681 1681
             tun_br.delete_port.assert_called_once_with('gre-02020202')
1682 1682
 
1683
-    def test_ext_br_recreated(self):
1683
+    def _test_ext_br_recreated(self, setup_bridges_side_effect):
1684 1684
         bridge_mappings = {'physnet0': 'br-ex0',
1685 1685
                            'physnet1': 'br-ex1'}
1686 1686
         ex_br_mocks = [mock.Mock(br_name='br-ex0'),
@@ -1688,6 +1688,9 @@ class TestOvsNeutronAgent(object):
1688 1688
         phys_bridges = {'physnet0': ex_br_mocks[0],
1689 1689
                         'physnet1': ex_br_mocks[1]},
1690 1690
         bm_mock = mock.Mock()
1691
+        bridges_added = ['br-ex0']
1692
+        expected_added_bridges = (
1693
+            bridges_added if setup_bridges_side_effect else [])
1691 1694
         with mock.patch(
1692 1695
             'neutron.agent.linux.ovsdb_monitor.get_bridges_monitor',
1693 1696
             return_value=bm_mock),\
@@ -1706,14 +1709,24 @@ class TestOvsNeutronAgent(object):
1706 1709
                 mock.patch.object(
1707 1710
                     self.agent,
1708 1711
                     'setup_physical_bridges') as setup_physical_bridges:
1709
-            bm_mock.bridges_added = ['br-ex0']
1712
+            bm_mock.bridges_added = bridges_added
1713
+            setup_physical_bridges.side_effect = setup_bridges_side_effect
1710 1714
             try:
1711 1715
                 self.agent.rpc_loop(polling_manager=mock.Mock(),
1712 1716
                                     bridges_monitor=bm_mock)
1713 1717
             except TypeError:
1714 1718
                 pass
1715
-        setup_physical_bridges.assert_called_once_with(
1716
-            {'physnet0': 'br-ex0'})
1719
+        # Setup bridges should be called once even if it will raise Runtime
1720
+        # Error because there is raised TypeError in _agent_has_updates to stop
1721
+        # agent after first loop iteration
1722
+        setup_physical_bridges.assert_called_once_with({'physnet0': 'br-ex0'})
1723
+        self.assertEqual(expected_added_bridges, self.agent.added_bridges)
1724
+
1725
+    def test_ext_br_recreated(self):
1726
+        self._test_ext_br_recreated(setup_bridges_side_effect=None)
1727
+
1728
+    def test_ext_br_recreated_fail_setup_physical_bridge(self):
1729
+        self._test_ext_br_recreated(setup_bridges_side_effect=RuntimeError)
1717 1730
 
1718 1731
     def test_daemon_loop_uses_polling_manager(self):
1719 1732
         ex_br_mock = mock.Mock(br_name="br-ex0")

Loading…
Cancel
Save