From 3347cd311ae3da1e8305818d66031d43143902c2 Mon Sep 17 00:00:00 2001 From: Patrick Bonnell Date: Fri, 22 Jun 2018 15:33:45 -0400 Subject: [PATCH] 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 --- .../configutilities/common/validator.py | 4 +- .../controllerconfig/configassistant.py | 17 ++------ .../sysinv/api/controllers/v1/interface.py | 4 +- .../sysinv/sysinv/sysinv/puppet/interface.py | 39 +++++++++++++++++-- .../sysinv/tests/puppet/test_interface.py | 2 +- 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/configutilities/configutilities/configutilities/common/validator.py b/configutilities/configutilities/configutilities/common/validator.py index bda6bea42e..f831311b97 100755 --- a/configutilities/configutilities/configutilities/common/validator.py +++ b/configutilities/configutilities/configutilities/common/validator.py @@ -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" diff --git a/controllerconfig/controllerconfig/controllerconfig/configassistant.py b/controllerconfig/controllerconfig/controllerconfig/configassistant.py index e527590494..1a5456c57b 100644 --- a/controllerconfig/controllerconfig/controllerconfig/configassistant.py +++ b/controllerconfig/controllerconfig/controllerconfig/configassistant.py @@ -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 diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py index 23d3962438..823c283da3 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py @@ -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 " diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/interface.py b/sysinv/sysinv/sysinv/sysinv/puppet/interface.py index a97c317bba..44fdb6021e 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/interface.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/interface.py @@ -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 diff --git a/sysinv/sysinv/sysinv/sysinv/tests/puppet/test_interface.py b/sysinv/sysinv/sysinv/sysinv/tests/puppet/test_interface.py index 5e84646b8f..f9dd61325d 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/puppet/test_interface.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/puppet/test_interface.py @@ -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)