Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[active-standby] support reset heartbeat suspend timer #286

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/DbInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <boost/bind/bind.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>

#include "swss/netdispatcher.h"
#include "swss/netlink.h"
Expand Down Expand Up @@ -1050,6 +1051,10 @@ void DbInterface::processMuxLinkmgrConfigNotifiction(std::deque<swss::KeyOpField
mMuxManagerPtr->processSrcMac(v == "ToRMac");
} else if (f == "interval_pck_loss_count_update") {
mMuxManagerPtr->setLinkProberStatUpdateIntervalCount(boost::lexical_cast<uint32_t> (v));
} else if (f == "reset_suspend_timer") {
boost::tokenizer<> tok(v);
std::vector<std::string> ports(tok.begin(), tok.end());
mMuxManagerPtr->processResetSuspendTimer(ports);
}

MUXLOGINFO(boost::format("key: %s, Operation: %s, f: %s, v: %s") %
Expand Down
17 changes: 17 additions & 0 deletions src/MuxManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,4 +598,21 @@ void MuxManager::handleTsaEnableNotification(bool enable)
}
}

//
// ---> processResetSuspendTimer
//
// process suspend timer reset requests
//
void MuxManager::processResetSuspendTimer(const std::vector<std::string> &portNames)
{
for (const std::string &portName : portNames)
{
MUXLOGINFO(boost::format("%s: reset heartbeat suspend timer") % portName);
PortMapIterator portMapIterator = mPortMap.find(portName);
if (portMapIterator != mPortMap.end()) {
portMapIterator->second->handleResetSuspendTimer();
}
}
}

} /* namespace mux */
11 changes: 11 additions & 0 deletions src/MuxManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,17 @@ class MuxManager
*/
void handleTsaEnableNotification(bool enable);

/**
*@method processResetSuspendTimer
*
*@brief process suspend timer reset requests
*
*@param portNames (in) mux ports to reset the suspend timer
*
*@return none
*/
void processResetSuspendTimer(const std::vector<std::string> &portNames);

private:
/**
*@method getMuxPortCableType
Expand Down
15 changes: 15 additions & 0 deletions src/MuxPort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,4 +437,19 @@ void MuxPort::handleTsaEnable(bool enable)
));
}

//
// ---> handleResetSuspendTimer();
//
// handle suspend timer reset
//
void MuxPort::handleResetSuspendTimer()
{
MUXLOGWARNING(boost::format("%s: reset heartbeat suspend timer") % mMuxPortConfig.getPortName());

boost::asio::post(mStrand, boost::bind(
&link_manager::LinkManagerStateMachineBase::handleResetSuspendTimer,
mLinkManagerStateMachinePtr.get()
));
}

} /* namespace mux */
9 changes: 9 additions & 0 deletions src/MuxPort.h
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,15 @@ class MuxPort: public std::enable_shared_from_this<MuxPort>
*/
void handleTsaEnable(bool enable);

/**
*@method handleResetSuspendTimer
*
*@brief handle reset suspend timer request
*
* @return none
*/
void handleResetSuspendTimer();

protected:
friend class test::MuxManagerTest;
friend class test::FakeMuxPort;
Expand Down
16 changes: 16 additions & 0 deletions src/link_manager/LinkManagerStateMachineActiveStandby.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,22 @@ void ActiveStandbyStateMachine::handleResetLinkProberPckLossCount()
mResetIcmpPacketCountsFnPtr();
}

// ---> handleResetSuspendTimer();
//
// reset the heartbeat suspend timer
//
void ActiveStandbyStateMachine::handleResetSuspendTimer()
{
MUXLOGDEBUG(boost::format("%s: reset heartbeat suspend timer") % mMuxPortConfig.getPortName());

if (ps(mCompositeState) == link_prober::LinkProberState::Label::Unknown &&
ms(mCompositeState) == mux_state::MuxState::Label::Active &&
ls(mCompositeState) == link_state::LinkState::Label::Up) {
mUnknownActiveUpBackoffFactor = 1;
mResumeTxFnPtr();
}
}

//
// ---> updateMuxLinkmgrState();
//
Expand Down
9 changes: 9 additions & 0 deletions src/link_manager/LinkManagerStateMachineActiveStandby.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,15 @@ class ActiveStandbyStateMachine: public LinkManagerStateMachineBase,
*/
void handleResetLinkProberPckLossCount();

/**
* @method handleResetSuspendTimer
*
* @brief reset the heartbeat suspend timer
*
* @return none
*/
void handleResetSuspendTimer();

private:
/**
*@method updateMuxLinkmgrState
Expand Down
9 changes: 9 additions & 0 deletions src/link_manager/LinkManagerStateMachineBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,15 @@ void LinkManagerStateMachineBase::handleResetLinkProberPckLossCount()
MUXLOGINFO(mMuxPortConfig.getPortName());
}

// ---> handleResetSuspendTimer();
//
// reset the heartbeat suspend timer
//
void LinkManagerStateMachineBase::handleResetSuspendTimer()
{
MUXLOGINFO(mMuxPortConfig.getPortName());
}

//
// ---> postMuxStateEvent(mux_state::MuxState::Label label)
//
Expand Down
9 changes: 9 additions & 0 deletions src/link_manager/LinkManagerStateMachineBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,15 @@ class LinkManagerStateMachineBase : public common::StateMachine {
*/
virtual void handleResetLinkProberPckLossCount();

/**
* @method handleResetSuspendTimer
*
* @brief reset the heartbeat suspend timer
*
* @return none
*/
virtual void handleResetSuspendTimer();

public:
/**
*@method getLinkProberStateMachinePtr
Expand Down
11 changes: 8 additions & 3 deletions src/link_prober/LinkProber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,9 @@ void LinkProber::startProbing()
//
void LinkProber::suspendTxProbes(uint32_t suspendTime_msec)
{
MUXLOGWARNING(boost::format("%s: suspend ICMP heartbeat probing") % mMuxPortConfig.getPortName());
MUXLOGWARNING(boost::format("%s: suspend ICMP heartbeat probing %dms") % mMuxPortConfig.getPortName() % suspendTime_msec);

// NOTE: the timer reset also cancels any pending async ops with ec as boost::asio::error::operation_aborted
mSuspendTimer.expires_from_now(boost::posix_time::milliseconds(suspendTime_msec));
mSuspendTimer.async_wait(mStrand.wrap(boost::bind(
&LinkProber::handleSuspendTimeout,
Expand All @@ -198,6 +199,7 @@ void LinkProber::suspendTxProbes(uint32_t suspendTime_msec)
)));

mSuspendTx = true;
mCancelSuspend = false;
}

//
Expand All @@ -210,6 +212,7 @@ void LinkProber::resumeTxProbes()
MUXLOGWARNING(boost::format("%s: resume ICMP heartbeat probing") % mMuxPortConfig.getPortName());

mSuspendTimer.cancel();
mCancelSuspend = true;
}

//
Expand Down Expand Up @@ -538,8 +541,8 @@ void LinkProber::handleSuspendTimeout(boost::system::error_code errorCode)

mSuspendTx = false;

if (errorCode == boost::system::errc::success) {
// inform the composite state machine about Suspend timer expiry
if (errorCode == boost::system::errc::success || mCancelSuspend) {
// inform the composite state machine about Suspend timer expiry or cancel
boost::asio::io_service::strand &strand = mLinkProberStateMachinePtr->getStrand();
boost::asio::io_service &ioService = strand.context();
ioService.post(strand.wrap(boost::bind(
Expand All @@ -549,6 +552,8 @@ void LinkProber::handleSuspendTimeout(boost::system::error_code errorCode)
LinkProberStateMachineBase::getSuspendTimerExpiredEvent()
)));
}

mCancelSuspend = false;
}

//
Expand Down
1 change: 1 addition & 0 deletions src/link_prober/LinkProber.h
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,7 @@ class LinkProber
std::array<uint8_t, MUX_MAX_ICMP_BUFFER_SIZE> mTxBuffer;
std::array<uint8_t, MUX_MAX_ICMP_BUFFER_SIZE> mRxBuffer;

bool mCancelSuspend = false;
bool mSuspendTx = false;
bool mShutdownTx = false;
bool mDecreaseProbingInterval = false;
Expand Down
1 change: 1 addition & 0 deletions test/FakeMuxPort.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class FakeMuxPort : public ::mux::MuxPort {

link_prober::LinkProberState::Label getPeerLinkProberState() { return getActiveActiveStateMachinePtr()->mPeerLinkProberState; };
mux_state::MuxState::Label getPeerMuxState() { return getActiveActiveStateMachinePtr()->mPeerMuxState; };
uint32_t getActiveStandbyStateMachineSuspendBackoffFactor() { return getActiveStandbyStateMachinePtr()->mUnknownActiveUpBackoffFactor; }

inline void initLinkProberActiveActive();
inline void initLinkProberActiveStandby();
Expand Down
19 changes: 19 additions & 0 deletions test/LinkManagerStateMachineActiveActiveTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ void LinkManagerStateMachineActiveActiveTest::handleMuxConfig(std::string config
}
}

void LinkManagerStateMachineActiveActiveTest::handleResetSuspendTimer(uint32_t count)
{
mFakeMuxPort.handleResetSuspendTimer();
runIoService(count);
}

void LinkManagerStateMachineActiveActiveTest::activateStateMachine(bool enable_feature_default_route)
{
mMuxConfig.enableDefaultRouteFeature(enable_feature_default_route);
Expand Down Expand Up @@ -1210,4 +1216,17 @@ TEST_F(LinkManagerStateMachineActiveActiveTest, StateMachineInitEventWithMultipl
EXPECT_EQ(mDbInterfacePtr->mSetMuxStateInvokeCount, 2);
}

TEST_F(LinkManagerStateMachineActiveActiveTest, ResetSuspendTimer)
{
setMuxActive();

EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mSuspendTxProbeCallCount, 0);
EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mResumeTxProbeCallCount, 2);
// reset suspend timer is NOOP for active-active composite state machine
handleResetSuspendTimer();
VALIDATE_STATE(Active, Active, Up);
EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mSuspendTxProbeCallCount, 0);
EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mResumeTxProbeCallCount, 2);
}

} /* namespace test */
1 change: 1 addition & 0 deletions test/LinkManagerStateMachineActiveActiveTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class LinkManagerStateMachineActiveActiveTest : public ::testing::Test
void handleProbeMuxState(std::string, uint32_t count = 0);
void handleLinkState(std::string linkState, uint32_t count = 0);
void handleMuxConfig(std::string config, uint32_t count = 0, bool poll = false);
void handleResetSuspendTimer(uint32_t count = 0);
void activateStateMachine(bool enable_feature_default_route=false);
void setMuxActive();
void setMuxStandby();
Expand Down
45 changes: 45 additions & 0 deletions test/LinkManagerStateMachineTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,12 @@ void LinkManagerStateMachineTest::handleMuxConfig(std::string config, uint32_t c
runIoService(count);
}

void LinkManagerStateMachineTest::handleResetSuspendTimer(uint32_t count)
{
mFakeMuxPort.handleResetSuspendTimer();
runIoService(count);
}

void LinkManagerStateMachineTest::activateStateMachine()
{
mFakeMuxPort.activateStateMachine();
Expand Down Expand Up @@ -1607,4 +1613,43 @@ TEST_F(LinkManagerStateMachineTest, DefaultRouteStateRaceCondition)
stopIoServiceThreaded();
}

TEST_F(LinkManagerStateMachineTest, ResetSuspendTimer)
{
setMuxActive();

// swss notification
handleMuxState("active", 3);
VALIDATE_STATE(Active, Active, Up);

EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mSuspendTxProbeCallCount, 0);
EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mResumeTxProbeCallCount, 1);

handleResetSuspendTimer();

EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mSuspendTxProbeCallCount, 0);
EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mResumeTxProbeCallCount, 1);

EXPECT_EQ(mDbInterfacePtr->mProbeMuxStateInvokeCount, 0);
EXPECT_EQ(mDbInterfacePtr->mGetMuxStateInvokeCount, 1);
postLinkProberEvent(link_prober::LinkProberState::Unknown, 2);
VALIDATE_STATE(Unknown, Active, Up);
EXPECT_EQ(mDbInterfacePtr->mProbeMuxStateInvokeCount, 0);
EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mSuspendTxProbeCallCount, 1);
EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mResumeTxProbeCallCount, 1);
EXPECT_EQ(mFakeMuxPort.getActiveStandbyStateMachineSuspendBackoffFactor(), 2);

handleResetSuspendTimer();

// once suspend timer is reset, the tx probe is resumed
EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mSuspendTxProbeCallCount, 1);
EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mResumeTxProbeCallCount, 2);
// the backoff factor is restored to 1
EXPECT_EQ(mFakeMuxPort.getActiveStandbyStateMachineSuspendBackoffFactor(), 1);

postSuspendTimerExpiredEvent(2);
VALIDATE_STATE(Unknown, Wait, Up);
EXPECT_EQ(mFakeMuxPort.mFakeLinkProber->mDetectLinkCallCount, 1);
EXPECT_EQ(mDbInterfacePtr->mProbeMuxStateInvokeCount, 1);
}

} /* namespace test */
1 change: 1 addition & 0 deletions test/LinkManagerStateMachineTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class LinkManagerStateMachineTest: public ::testing::Test
void handleProbeMuxState(std::string, uint32_t count = 0);
void handleLinkState(std::string linkState, uint32_t count = 0);
void handleMuxConfig(std::string config, uint32_t count = 0);
void handleResetSuspendTimer(uint32_t count = 0);
void activateStateMachine();
void setMuxActive();
void setMuxStandby();
Expand Down
2 changes: 2 additions & 0 deletions test/MuxManagerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -903,9 +903,11 @@ TEST_F(MuxManagerTest, LinkmgrdConfig)
{"LINK_PROBER", "SET", {{"interval_v4", "abc"}}},
{"LINK_PROBER", "SET", {{"src_mac", "ToRMac"}}},
{"LINK_PROBER", "SET", {{"interval_pck_loss_count_update", "900"}}},
{"LINK_PROBER", "SET", {{"reset_suspend_timer", "Ethernet0"}}},
{"MUXLOGGER", "SET", {{"log_verbosity", "warning"}}},
};
processMuxLinkmgrConfigNotifiction(entries);
runIoService(2);

EXPECT_TRUE(getTimeoutIpv4_msec(port) == v4PorbeInterval);
EXPECT_TRUE(getTimeoutIpv6_msec(port) == v6ProveInterval);
Expand Down
Loading