diff --git a/faucet/port.py b/faucet/port.py index 706a230b46..d79bb1be15 100644 --- a/faucet/port.py +++ b/faucet/port.py @@ -518,18 +518,18 @@ def lacp_port_update(self, selected, cold_start=False): # Cold starting, so revert to unconfigured state self.deconfigure_port() elif self.lacp_selected: - # Can configure LACP port to be forced SELECTED + # Configured LACP port option to be forced into SELECTED state self.select_port() - elif self.lacp_standby: - # Can configure LACP port to be forced STANDBY - self.standby_port() elif self.lacp_unselected: - # Can configure LACP port to be force UNSELECTED + # Configured LACP port option to be forced into UNSELECTED state self.deselect_port() else: if selected: - # Belongs on chosen DP for LAG, so SELECT port + # Port SELECTED so change state to SELECTED self.select_port() + elif self.lacp_standby: + # Send port to STANDBY if not SELECTED + self.standby_port() else: # Doesn't belong on chosen DP for LAG, DESELECT port self.deselect_port() diff --git a/tests/unit/faucet/test_port.py b/tests/unit/faucet/test_port.py index ccbaf0702e..1fc5b989a8 100755 --- a/tests/unit/faucet/test_port.py +++ b/tests/unit/faucet/test_port.py @@ -106,9 +106,10 @@ def test_lacp_port_update(self): port.lacp_port_update(True) self.assertEqual(port.dyn_lacp_port_selected, LACP_PORT_SELECTED) # Test option to force standby mode + # Option forces the statemachine to revert to STANDBY mode when not selected port.lacp_standby = True port.lacp_port_update(True) - self.assertEqual(port.dyn_lacp_port_selected, LACP_PORT_STANDBY) + self.assertEqual(port.dyn_lacp_port_selected, LACP_PORT_SELECTED) port.lacp_port_update(False) self.assertEqual(port.dyn_lacp_port_selected, LACP_PORT_STANDBY) # Test forcing selected port diff --git a/tests/unit/faucet/test_valve_stack.py b/tests/unit/faucet/test_valve_stack.py index b68c0a86e7..08b1f0c80b 100755 --- a/tests/unit/faucet/test_valve_stack.py +++ b/tests/unit/faucet/test_valve_stack.py @@ -309,6 +309,83 @@ def test_MCLAG_cold_start(self): self.assertTrue(port.is_actor_up(), 'Actor not UP') +class ValveStackMCLAGStandbyTestCase(ValveTestBases.ValveTestSmall): + """Test MCLAG with standby port option overrules unselected states""" + + CONFIG = """ +dps: + s1: +%s + stack: + priority: 1 + interfaces: + 1: + description: p1 + stack: + dp: s2 + port: 1 + 2: + description: p3 + native_vlan: 100 + lacp_standby: True + lacp: 1 + 3: + description: p4 + native_vlan: 100 + lacp_standby: True + lacp: 1 + s2: + hardware: 'GenericTFM' + dp_id: 0x2 + interfaces: + 1: + description: p1 + stack: + dp: s1 + port: 1 + 2: + description: p3 + native_vlan: 100 + lacp_standby: True + lacp: 1 + 3: + description: p4 + native_vlan: 100 + lacp_standby: True + lacp: 1 +""" % BASE_DP1_CONFIG + + def setUp(self): + """Setup basic loop config""" + self.setup_valve(self.CONFIG) + + def get_other_valves(self, valve): + """Return other running valves""" + return self.valves_manager._other_running_valves(valve) # pylint: disable=protected-access + + def test_MCLAG_standby_option(self): + """Test MCLAG standby option forces standby state instead of unselected""" + self.activate_all_ports() + valve = self.valves_manager.valves[0x1] + other_valve = self.valves_manager.valves[0x2] + for port in valve.dp.ports.values(): + if port.lacp: + valve.lacp_update(port, True, 1, 1, self.get_other_valves(valve)) + self.assertTrue(port.is_port_selected()) + for port in other_valve.dp.ports.values(): + if port.lacp: + other_valve.lacp_update(port, True, 1, 1, self.get_other_valves(other_valve)) + self.assertTrue(port.is_port_standby()) + for port in valve.dp.ports.values(): + if port.lacp: + valve.lacp_update(port, False, 1, 1, self.get_other_valves(valve)) + self.assertTrue(port.is_port_standby()) + for port in other_valve.dp.ports.values(): + if port.lacp: + other_valve.lacp_update(port, True, 1, 1, self.get_other_valves(other_valve)) + self.assertTrue(port.is_port_selected()) + + class ValveStackRootExtLoopProtectTestCase(ValveTestBases.ValveTestSmall): """External loop protect test cases"""