From 3cc286037b35c36b56bd7b5f940e2462cd04c013 Mon Sep 17 00:00:00 2001 From: Dan Sneddon Date: Fri, 3 Apr 2020 23:35:06 -0700 Subject: [PATCH] Run ifup on a bond when a slave interface is restarted This change adds the bond to the list of interfaces to be restarted when a slave interface is restarted. On Fedora/CentOS like systems restart all interface slaves in a bond, the bond will be left in a downed state. This change runs ifup on the bond if any slave interfaces are restarted, which insures that the bond should be up in all cases when os-net-config exits. Tests were added to ensure that in all cases each interface or bond will only be restarted once, and that bonds will only be restarted if the interface modifications require restart. Change-Id: Ibbe8021afdc4772c6e2017d11d012b8f5c46d907 Closes-bug: 1870608 (cherry picked from commit fe13c4944be3221092f9147385700e4914a30cde) --- os_net_config/impl_ifcfg.py | 13 +++++++++- os_net_config/tests/test_impl_ifcfg.py | 34 +++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/os_net_config/impl_ifcfg.py b/os_net_config/impl_ifcfg.py index 6ec11884..3157d0c7 100644 --- a/os_net_config/impl_ifcfg.py +++ b/os_net_config/impl_ifcfg.py @@ -1155,6 +1155,7 @@ class IfcfgNetConfig(os_net_config.NetConfig): restart_vlans = [] restart_bridges = [] restart_linux_bonds = [] + start_linux_bonds = [] restart_linux_teams = [] restart_vpp = False apply_interfaces = [] @@ -1162,6 +1163,7 @@ class IfcfgNetConfig(os_net_config.NetConfig): apply_routes = [] update_files = {} all_file_names = [] + linux_bond_children = {} ivs_uplinks = [] # ivs physical uplinks ivs_interfaces = [] # ivs internal ports nfvswitch_interfaces = [] # nfvswitch physical interfaces @@ -1407,11 +1409,12 @@ class IfcfgNetConfig(os_net_config.NetConfig): all_file_names.append(bond_route_path) all_file_names.append(bond_route6_path) all_file_names.append(bond_rule_path) + children = self.child_members(bond_name) + linux_bond_children[bond_name] = children if utils.diff(bond_path, bond_data): if self.ifcfg_requires_restart(bond_path, bond_data): restart_linux_bonds.append(bond_name) # Avoid duplicate interface being added to the restart list - children = self.child_members(bond_name) for child in children: if child not in restart_interfaces: restart_interfaces.append(child) @@ -1594,6 +1597,10 @@ class IfcfgNetConfig(os_net_config.NetConfig): for interface in restart_interfaces: self.ifdown(interface) + for bond in linux_bond_children: + if interface in linux_bond_children[bond]: + if bond not in restart_linux_bonds: + start_linux_bonds.append(bond) for linux_bond in restart_linux_bonds: self.ifdown(linux_bond) @@ -1664,6 +1671,10 @@ class IfcfgNetConfig(os_net_config.NetConfig): for interface in restart_interfaces: self.ifup(interface) + for linux_bond in start_linux_bonds: + if linux_bond not in restart_linux_bonds: + restart_linux_bonds.append(linux_bond) + for linux_bond in restart_linux_bonds: self.ifup(linux_bond) diff --git a/os_net_config/tests/test_impl_ifcfg.py b/os_net_config/tests/test_impl_ifcfg.py index fcdfa4f4..66d7d722 100644 --- a/os_net_config/tests/test_impl_ifcfg.py +++ b/os_net_config/tests/test_impl_ifcfg.py @@ -2284,14 +2284,46 @@ class TestIfcfgNetConfigApply(base.TestCase): self.assertIn('em2', self.ifup_interface_names) self.assertIn('vlan10', self.ifup_interface_names) + def test_linux_bond_ifup_on_child_restart(self): + # if a bond slave is restarted then ifup should be called on the bond + self.ifup_interface_names = [] + interface1 = objects.Interface('em1') + bond = objects.LinuxBond('bond0', members=[interface1]) + self.provider.add_linux_bond(bond) + self.provider.add_interface(interface1) + self.provider.apply() + self.assertIn('em1', self.ifup_interface_names) + self.assertIn('bond0', self.ifup_interface_names) + + self.ifup_interface_names = [] + # changing mtu should not require a restart of em1 (or the bond) + interface1.mtu = 9000 + self.provider.linuxbond_data = {} + self.provider.interface_data = {} + self.provider.add_linux_bond(bond) + self.provider.add_interface(interface1) + self.provider.apply() + self.assertNotIn('em1', self.ifup_interface_names) + self.assertNotIn('bond0', self.ifup_interface_names) + + # changing nm_controlled should require a restart of em1 (and the bond) + interface1.nm_controlled = True + self.provider.add_interface(interface1) + self.provider.apply() + self.assertIn('em1', self.ifup_interface_names) + self.assertIn('bond0', self.ifup_interface_names) + def test_restart_interface_counts(self): interface = objects.Interface('em1') - self.provider.add_interface(interface) interface2 = objects.Interface('em2') + bond = objects.LinuxBond('bond0', members=[interface, interface2]) + self.provider.add_bond(bond) + self.provider.add_interface(interface) self.provider.add_interface(interface2) self.provider.apply() self.assertEqual(1, self.ifup_interface_names.count("em1")) self.assertEqual(1, self.ifup_interface_names.count("em2")) + self.assertEqual(1, self.ifup_interface_names.count("bond0")) def test_vlan_apply(self): vlan = objects.Vlan('em1', 5)