diff --git a/src/link_manager/LinkManagerStateMachine.cpp b/src/link_manager/LinkManagerStateMachine.cpp index 1fee86b7..31bfc4f3 100644 --- a/src/link_manager/LinkManagerStateMachine.cpp +++ b/src/link_manager/LinkManagerStateMachine.cpp @@ -505,6 +505,17 @@ void LinkManagerStateMachine::handleStateChange(MuxStateEvent &event, mux_state: if (ms(mCompositeState) != mux_state::MuxState::Wait) { // Verify if state db MUX state matches the driver/current MUX state mMuxPortPtr->getMuxState(); + + // Handle pending mux mode config change + if (mPendingMuxModeChange) { + MUXLOGINFO(boost::format("%s: Mux state: %s . Execute pending MUX mode config change.") % + mMuxPortConfig.getPortName() % + mMuxStateName[ms(mCompositeState)] + ); + + handleMuxConfigNotification(mTargetMuxMode); + mPendingMuxModeChange = false; + } } if (ms(mCompositeState) != mux_state::MuxState::Unknown) { @@ -706,18 +717,32 @@ void LinkManagerStateMachine::handleSwssLinkStateNotification(const link_state:: // void LinkManagerStateMachine::handleMuxConfigNotification(const common::MuxPortConfig::Mode mode) { + if (mComponentInitState.test(MuxStateComponent) && + mode != common::MuxPortConfig::Mode::Auto && + mode != common::MuxPortConfig::Mode::Manual && + ms(mCompositeState) == mux_state::MuxState::Wait) { + + MUXLOGINFO(boost::format("%s: Mux state: %s , mux mode config change is pending. ") % + mMuxPortConfig.getPortName() % + mMuxStateName[ms(mCompositeState)] + ); + + mPendingMuxModeChange = true; + mTargetMuxMode = mode; + + return; + } + if (mComponentInitState.all()) { if (mode == common::MuxPortConfig::Mode::Active && - ms(mCompositeState) != mux_state::MuxState::Label::Active && - ms(mCompositeState) != mux_state::MuxState::Label::Wait) { + ms(mCompositeState) != mux_state::MuxState::Label::Active) { CompositeState nextState = mCompositeState; enterLinkProberState(nextState, link_prober::LinkProberState::Wait); switchMuxState(nextState, mux_state::MuxState::Label::Active); LOGWARNING_MUX_STATE_TRANSITION(mMuxPortConfig.getPortName(), mCompositeState, nextState); mCompositeState = nextState; } else if(mode == common::MuxPortConfig::Mode::Standby && - ms(mCompositeState) != mux_state::MuxState::Label::Standby && - ms(mCompositeState) != mux_state::MuxState::Label::Wait) { + ms(mCompositeState) != mux_state::MuxState::Label::Standby) { mSendPeerSwitchCommandFnPtr(); } else { mMuxStateMachine.setWaitStateCause(mux_state::WaitState::WaitStateCause::DriverUpdate); @@ -728,6 +753,7 @@ void LinkManagerStateMachine::handleMuxConfigNotification(const common::MuxPortC } mMuxPortConfig.setMode(mode); + } // diff --git a/src/link_manager/LinkManagerStateMachine.h b/src/link_manager/LinkManagerStateMachine.h index 735e856d..0cac9284 100644 --- a/src/link_manager/LinkManagerStateMachine.h +++ b/src/link_manager/LinkManagerStateMachine.h @@ -919,6 +919,9 @@ class LinkManagerStateMachine: public common::StateMachine, uint32_t mWaitActiveUpCount = 0; uint32_t mMuxUnknownBackoffFactor = 1; + bool mPendingMuxModeChange = false; + common::MuxPortConfig::Mode mTargetMuxMode = common::MuxPortConfig::Mode::Auto; + std::bitset mComponentInitState = {0}; Label mLabel = Label::Uninitialized; }; diff --git a/test/FakeMuxPort.h b/test/FakeMuxPort.h index f8a587bb..ac0c5df3 100644 --- a/test/FakeMuxPort.h +++ b/test/FakeMuxPort.h @@ -53,6 +53,9 @@ class FakeMuxPort: public ::mux::MuxPort mux_state::MuxStateMachine& getMuxStateMachine() {return getLinkManagerStateMachine()->getMuxStateMachine();}; link_state::LinkStateMachine& getLinkStateMachine() {return getLinkManagerStateMachine()->getLinkStateMachine();}; + bool getPendingMuxModeChange() {return getLinkManagerStateMachine()->mPendingMuxModeChange;}; + common::MuxPortConfig::Mode getTargetMuxMode() {return getLinkManagerStateMachine()->mTargetMuxMode;}; + std::shared_ptr mFakeLinkProber; }; diff --git a/test/LinkManagerStateMachineTest.cpp b/test/LinkManagerStateMachineTest.cpp index d55797df..9c4253a7 100644 --- a/test/LinkManagerStateMachineTest.cpp +++ b/test/LinkManagerStateMachineTest.cpp @@ -568,6 +568,44 @@ TEST_F(LinkManagerStateMachineTest, MuxStandbyLinkProberUnknown) VALIDATE_STATE(Active, Active, Up); } +TEST_F(LinkManagerStateMachineTest, MuxStandbyLinkProberUnknownCliSwitchover) +{ + setMuxStandby(); + + // verify MUX enters wait state + EXPECT_EQ(mDbInterfacePtr->mProbeMuxStateInvokeCount, 0); + EXPECT_EQ(mDbInterfacePtr->mGetMuxStateInvokeCount, 1); + EXPECT_EQ(mDbInterfacePtr->mSetMuxStateInvokeCount, 0); + postLinkProberEvent(link_prober::LinkProberState::Unknown, 2); + VALIDATE_STATE(Wait, Wait, Up); + EXPECT_EQ(mDbInterfacePtr->mSetMuxStateInvokeCount, 1); + + // mux mode config change is cached due to MuxState:Wait + handleMuxConfig("active", 1); + EXPECT_TRUE(mFakeMuxPort.getPendingMuxModeChange()); + EXPECT_EQ(mFakeMuxPort.getTargetMuxMode(), common::MuxPortConfig::Mode::Active); + + // swss notification, exiting MuxState:wait + handleMuxState("standby", 4); + EXPECT_EQ(mDbInterfacePtr->mGetMuxStateInvokeCount, 2); + // execute pending mux mode config change, switch to MuxState:Active + EXPECT_EQ(mDbInterfacePtr->mSetMuxStateInvokeCount, 2); + VALIDATE_STATE(Wait, Wait, Up); + EXPECT_FALSE(mFakeMuxPort.getPendingMuxModeChange()); + + // swss notification + handleMuxState("active", 3); + VALIDATE_STATE(Wait, Active, Up); + + // change state to active + postLinkProberEvent(link_prober::LinkProberState::Active, 2); + VALIDATE_STATE(Active, Wait, Up); + + // xcvrd notification + handleProbeMuxState("active", 4); + VALIDATE_STATE(Active, Active, Up); +} + TEST_F(LinkManagerStateMachineTest, MuxStandbyLinkProberUnknownReturnStandby) { setMuxStandby();