Set primary interface of active backup bond interface

The standby controller would potentially fail to boot while
attempting to PXE-boot when configured with a management LAG.

This commit determines the interface with the lowest slave MAC
address in an active_standby LAG configuration and assigns it
as the primary interface.

Story: 2002865
Task: 22814

Change-Id: I73f03cb9cb2fd632a1e64b4e7744e3be067318a4
Signed-off-by: Jack Ding <jack.ding@windriver.com>
This commit is contained in:
Patrick Bonnell 2018-06-22 15:33:45 -04:00 committed by Jack Ding
parent d646fa044a
commit 3347cd311a
5 changed files with 43 additions and 23 deletions

View File

@ -376,9 +376,7 @@ class ConfigValidator(object):
(mgmt_prefix, str(self.mgmt_network.cidr)))
if self.mgmt_network.logical_interface.lag_interface:
supported_lag_mode = [4]
if self.system_mode != SYSTEM_MODE_DUPLEX_DIRECT:
supported_lag_mode.append(1)
supported_lag_mode = [1, 4]
if (self.mgmt_network.logical_interface.lag_mode not in
supported_lag_mode):
raise ConfigFail("Unsupported LAG mode (%d) for %s interface"

View File

@ -976,8 +976,7 @@ class ConfigAssistant():
print
print "Specify one of the bonding policies. Possible values are:"
print " 1) 802.3ad (LACP) policy"
if self.system_mode != sysinv_constants.SYSTEM_MODE_DUPLEX_DIRECT:
print " 2) Active-backup policy"
print " 2) Active-backup policy"
user_input = raw_input(
"\nManagement interface bonding policy [" +
@ -989,17 +988,9 @@ class ConfigAssistant():
constants.LAG_MODE_8023AD
break
elif user_input == '2':
if (self.system_mode ==
sysinv_constants.SYSTEM_MODE_DUPLEX_DIRECT):
print textwrap.fill(
"Active-backup bonding policy is not supported "
"for AIO duplex-direct configuration."
)
continue
else:
self.lag_management_interface_policy = \
constants.LAG_MODE_ACTIVE_BACKUP
self.lag_management_interface_txhash = None
self.lag_management_interface_policy = \
constants.LAG_MODE_ACTIVE_BACKUP
self.lag_management_interface_txhash = None
break
elif user_input == "":
break

View File

@ -1250,9 +1250,7 @@ def _check_interface_data(op, interface, ihost, existing_interface):
# Make sure network type 'mgmt', with if type 'ae',
# can only be in ae mode 'active_standby' or '802.3ad'
valid_mgmt_aemode = ['802.3ad']
if utils.get_system_mode() != constants.SYSTEM_MODE_DUPLEX_DIRECT:
valid_mgmt_aemode.append('active_standby')
valid_mgmt_aemode = ['802.3ad', 'active_standby']
if (constants.NETWORK_TYPE_MGMT in networktypelist and iftype == 'ae' and
aemode not in valid_mgmt_aemode):
msg = _("Device interface with network type {}, and interface "

View File

@ -809,7 +809,7 @@ def get_vlan_network_config(context, iface, config):
return config
def get_bond_interface_options(iface):
def get_bond_interface_options(iface, primary_iface):
"""
Get the interface config attribute for bonding options
"""
@ -817,7 +817,9 @@ def get_bond_interface_options(iface):
tx_hash_policy = iface['txhashpolicy']
options = None
if ae_mode in ACTIVE_STANDBY_AE_MODES:
options = 'mode=active-backup miimon=100'
# Requires the active device in an active_standby LAG
# configuration to be determined based on the lowest MAC address
options = 'mode=active-backup miimon=100 primary={}'.format(primary_iface['ifname'])
else:
options = 'xmit_hash_policy=%s miimon=100' % tx_hash_policy
if ae_mode in BALANCED_AE_MODES:
@ -833,7 +835,8 @@ def get_bond_network_config(context, iface, config):
interface.
"""
options = {'MACADDR': iface['imac'].rstrip()}
bonding_options = get_bond_interface_options(iface)
primary_iface = get_primary_bond_interface(context, iface)
bonding_options = get_bond_interface_options(iface, primary_iface)
if bonding_options:
options['BONDING_OPTS'] = bonding_options
options['up'] = 'sleep 10'
@ -841,6 +844,36 @@ def get_bond_network_config(context, iface, config):
return config
def get_primary_bond_interface(context, iface):
"""
Return the slave interface with the lowest MAC address
"""
slaves = get_bond_interface_slaves(context, iface)
sorted_slaves = sorted(slaves, key=slave_sort_key)
primary_iface = sorted_slaves[0]
return primary_iface
def get_bond_interface_slaves(context, iface):
"""
Return the slave interface objects for the corresponding
bond interface
"""
slaves = iface['uses']
ifaces = []
for ifname, iface in six.iteritems(context['interfaces']):
if ifname in slaves:
ifaces.append(iface)
return ifaces
def slave_sort_key(iface):
"""
Sort interfaces by lowest MAC address
"""
return int(iface['imac'].replace(':', ''), 16)
def get_ethernet_network_config(context, iface, config):
"""
Augments a basic config dictionary with the attributes specific to an

View File

@ -1081,7 +1081,7 @@ class InterfaceTestCase(BaseTestCase):
config = interface.get_interface_network_config(self.context, bond)
options = {'up': 'sleep 10',
'MACADDR': bond['imac'],
'BONDING_OPTS': 'mode=active-backup miimon=100'}
'BONDING_OPTS': 'mode=active-backup miimon=100 primary=eth1'}
expected = self._get_network_config(
ifname=bond['ifname'], mtu=1500, method='manual', options=options)
print(expected)