Fix - restart VLAN interface on underlying device change

When a change is needed on bond, os-net-config write the
configuration and restart nic and bond. But it does not
restart vlan on top of the bond. The results is that  all
routes for vlan interfaces are lost.

This moves the processing of VLAN's so that it run's
after any interfaces, bridges, bonds etc. Then
concatenates the restart lists from other interfaces and
do a check if 'PHYSDEV' of a VLAN interface is being
restarted.

Closes-Bug: #1806027
Related: RHBZ#1654987
Change-Id: I246da54cf02d06466f52d210f89d82ca9e2a6ef2
(cherry picked from commit 19067b4e77)
This commit is contained in:
Harald Jensås 2018-11-30 10:54:06 +01:00
parent 6429384f23
commit 0743c2c803
2 changed files with 73 additions and 20 deletions

View File

@ -15,6 +15,7 @@
# under the License.
import glob
import itertools
import logging
import os
import re
@ -121,6 +122,18 @@ class IfcfgNetConfig(os_net_config.NetConfig):
self.bond_primary_ifaces = {}
logger.info('Ifcfg net config provider created.')
def parse_ifcfg(self, ifcfg_data):
"""Break out the key/value pairs from ifcfg_data
Return the keys and values without quotes.
"""
ifcfg_values = {}
for line in ifcfg_data.split("\n"):
if not line.startswith("#") and line.find("=") > 0:
k, v = line.split("=", 1)
ifcfg_values[k] = v.strip("\"'")
return ifcfg_values
def child_members(self, name):
children = set()
try:
@ -792,26 +805,6 @@ class IfcfgNetConfig(os_net_config.NetConfig):
logger.info('No changes required for nfvswitch interface: %s' %
iface_name)
for vlan_name, vlan_data in self.vlan_data.items():
route_data = self.route_data.get(vlan_name, '')
route6_data = self.route6_data.get(vlan_name, '')
vlan_path = self.root_dir + ifcfg_config_path(vlan_name)
vlan_route_path = self.root_dir + route_config_path(vlan_name)
vlan_route6_path = self.root_dir + route6_config_path(vlan_name)
all_file_names.append(vlan_path)
all_file_names.append(vlan_route_path)
all_file_names.append(vlan_route6_path)
if (utils.diff(vlan_path, vlan_data) or
utils.diff(vlan_route_path, route_data)):
restart_vlans.append(vlan_name)
restart_vlans.extend(self.child_members(vlan_name))
update_files[vlan_path] = vlan_data
update_files[vlan_route_path] = route_data
update_files[vlan_route6_path] = route6_data
else:
logger.info('No changes required for vlan interface: %s' %
vlan_name)
for bridge_name, bridge_data in self.bridge_data.items():
route_data = self.route_data.get(bridge_name, '')
route6_data = self.route6_data.get(bridge_name, '')
@ -924,6 +917,40 @@ class IfcfgNetConfig(os_net_config.NetConfig):
logger.info('No changes required for InfiniBand iface: %s' %
interface_name)
# NOTE(hjensas): Process the VLAN's last so that we know if the vlan's
# parent interface is being restarted.
for vlan_name, vlan_data in self.vlan_data.items():
route_data = self.route_data.get(vlan_name, '')
route6_data = self.route6_data.get(vlan_name, '')
vlan_path = self.root_dir + ifcfg_config_path(vlan_name)
vlan_route_path = self.root_dir + route_config_path(vlan_name)
vlan_route6_path = self.root_dir + route6_config_path(vlan_name)
all_file_names.append(vlan_path)
all_file_names.append(vlan_route_path)
all_file_names.append(vlan_route6_path)
restarts_concatenated = itertools.chain(restart_interfaces,
restart_bridges,
restart_linux_bonds,
restart_linux_teams)
if (self.parse_ifcfg(vlan_data).get('PHYSDEV') in
restarts_concatenated):
if vlan_name not in restart_vlans:
restart_vlans.append(vlan_name)
update_files[vlan_path] = vlan_data
update_files[vlan_path] = vlan_data
update_files[vlan_route_path] = route_data
update_files[vlan_route6_path] = route6_data
elif (utils.diff(vlan_path, vlan_data) or
utils.diff(vlan_route_path, route_data)):
restart_vlans.append(vlan_name)
restart_vlans.extend(self.child_members(vlan_name))
update_files[vlan_path] = vlan_data
update_files[vlan_route_path] = route_data
update_files[vlan_route6_path] = route6_data
else:
logger.info('No changes required for vlan interface: %s' %
vlan_name)
if cleanup:
for ifcfg_file in glob.iglob(cleanup_pattern()):
if ifcfg_file not in all_file_names:

View File

@ -1184,6 +1184,32 @@ class TestIfcfgNetConfigApply(base.TestCase):
self.assertIn('em1', self.ifup_interface_names)
self.assertIn('em2', self.ifup_interface_names)
def test_restart_vlans_on_bond_change(self):
self.ifup_interface_names = []
interface1 = objects.Interface('em1')
interface2 = objects.Interface('em2')
bond = objects.LinuxBond('bond0', members=[interface1, interface2])
vlan = objects.Vlan('bond0', 10)
self.provider.add_interface(interface1)
self.provider.add_interface(interface2)
self.provider.add_linux_bond(bond)
self.provider.add_vlan(vlan)
self.provider.apply()
self.assertIn('bond0', self.ifup_interface_names)
self.assertIn('em1', self.ifup_interface_names)
self.assertIn('em2', self.ifup_interface_names)
self.assertIn('vlan10', self.ifup_interface_names)
# Change the bond configuration
self.ifup_interface_names = []
bond.bonding_options = 'mode=1 miimon=100'
self.provider.add_linux_bond(bond)
self.provider.apply()
self.assertIn('bond0', self.ifup_interface_names)
self.assertIn('em1', self.ifup_interface_names)
self.assertIn('em2', self.ifup_interface_names)
self.assertIn('vlan10', self.ifup_interface_names)
def test_restart_interface_counts(self):
interface = objects.Interface('em1')
self.provider.add_interface(interface)