Skip to content

Commit deef074

Browse files
committed
Linkmgrd subscribing State DB route event (sonic-net#13)
Summary: Fixes # (issue) This PR is to make linkmgrd subscribe events from ROUTE_TABLE in State DB, and react accordingly: - If any of the two default route state appears to be 'na', linkmgrd should switch to standby. - If both are 'ok', there will be a mux state probing and what happens next depends on linkmgrd state machine and the probing response. Type of change: New feature Motivation for this PR: To make linkmgrd subscribe state DB route event, and handle the switchovers. Documentation: Related PR: sonic-net/sonic-swss#2009
1 parent aa03765 commit deef074

10 files changed

Lines changed: 225 additions & 0 deletions

src/DbInterface.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,59 @@ void DbInterface::handleMuxStateNotifiction(swss::SubscriberStateTable &statedbP
730730
processMuxStateNotifiction(entries);
731731
}
732732

733+
//
734+
// ---> processDefaultRouteStateNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries)
735+
//
736+
// process default route state notification from orchagent
737+
//
738+
void DbInterface::processDefaultRouteStateNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries)
739+
{
740+
for (auto &entry: entries) {
741+
std::string key = kfvKey(entry);
742+
std::string op = kfvOp(entry);
743+
std::vector<swss::FieldValueTuple> fieldValues = kfvFieldsValues(entry);
744+
745+
std::vector<swss::FieldValueTuple>::const_iterator cit = std::find_if(
746+
fieldValues.cbegin(),
747+
fieldValues.cend(),
748+
[] (const swss::FieldValueTuple &fv) {return fvField(fv) == "state";}
749+
);
750+
751+
if (cit != fieldValues.cend()) {
752+
const std::string field = cit->first;
753+
const std::string value = cit->second;
754+
755+
MUXLOGDEBUG(boost::format("key: %s, operation: %s, field: %s, value: %s") %
756+
key %
757+
op %
758+
field %
759+
value
760+
);
761+
762+
if (key == "0.0.0.0/0") {
763+
mMuxManagerPtr->addOrUpdateDefaultRouteState(true, value);
764+
} else if (key == "::/0") {
765+
mMuxManagerPtr->addOrUpdateDefaultRouteState(false, value);
766+
} else {
767+
MUXLOGFATAL(boost::format("Received Invalid IP: %s") % key );
768+
}
769+
}
770+
}
771+
}
772+
773+
//
774+
// ---> handleDefaultRouteStateNotification(swss::SubscriberStateTable &statedbRouteTable);
775+
//
776+
// handle Default Route State notification from orchagent
777+
//
778+
void DbInterface::handleDefaultRouteStateNotification(swss::SubscriberStateTable &statedbRouteTable)
779+
{
780+
std::deque<swss::KeyOpFieldsValuesTuple> entries;
781+
782+
statedbRouteTable.pops(entries);
783+
processDefaultRouteStateNotification(entries);
784+
}
785+
733786
//
734787
// ---> handleSwssNotification();
735788
//
@@ -752,6 +805,8 @@ void DbInterface::handleSwssNotification()
752805
swss::SubscriberStateTable appDbMuxResponseTable(appDbPtr.get(), APP_MUX_CABLE_RESPONSE_TABLE_NAME);
753806
// for getting state db MUX state when orchagent updates it
754807
swss::SubscriberStateTable stateDbPortTable(stateDbPtr.get(), STATE_MUX_CABLE_TABLE_NAME);
808+
// for getting state db default route state
809+
swss::SubscriberStateTable stateDbRouteTable(stateDbPtr.get(), STATE_ROUTE_TABLE_NAME);
755810

756811
getTorMacAddress(configDbPtr);
757812
getLoopback2InterfaceInfo(configDbPtr);
@@ -771,6 +826,7 @@ void DbInterface::handleSwssNotification()
771826
swssSelect.addSelectable(&appDbPortTable);
772827
swssSelect.addSelectable(&appDbMuxResponseTable);
773828
swssSelect.addSelectable(&stateDbPortTable);
829+
swssSelect.addSelectable(&stateDbRouteTable);
774830
swssSelect.addSelectable(&netlinkNeighbor);
775831

776832
while (mPollSwssNotifcation) {
@@ -797,6 +853,8 @@ void DbInterface::handleSwssNotification()
797853
handleMuxResponseNotifiction(appDbMuxResponseTable);
798854
} else if (selectable == static_cast<swss::Selectable *> (&stateDbPortTable)) {
799855
handleMuxStateNotifiction(stateDbPortTable);
856+
} else if (selectable == static_cast<swss::Selectable *> (&stateDbRouteTable)) {
857+
handleDefaultRouteStateNotification(stateDbRouteTable);
800858
} else if (selectable == static_cast<swss::Selectable *> (&netlinkNeighbor)) {
801859
continue;
802860
} else {

src/DbInterface.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,28 @@ class DbInterface
462462
*/
463463
void handleSwssNotification();
464464

465+
/**
466+
* @method processDefaultRouteStateNotification
467+
*
468+
* @brief process default route state notification from orchagent
469+
*
470+
* @param entries reference to state db default route state entries
471+
*
472+
* @return none
473+
*/
474+
void processDefaultRouteStateNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries);
475+
476+
/**
477+
* @method handleDefaultRouteStateNotification
478+
*
479+
* @brief handle Default Route State notification from orchagent
480+
*
481+
* @param statedbRouteTable reference to state db route table
482+
*
483+
* @return none
484+
*/
485+
void handleDefaultRouteStateNotification(swss::SubscriberStateTable &statedbRouteTable);
486+
465487
private:
466488
static std::vector<std::string> mMuxState;
467489
static std::vector<std::string> mMuxLinkmgrState;

src/MuxManager.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,34 @@ void MuxManager::processProbeMuxState(const std::string &portName, const std::st
234234
}
235235
}
236236

237+
//
238+
// ---> addOrUpdateDefaultRouteState(boost::asio::ip::address& address, const std::string &routeState);
239+
//
240+
// update default route state based on state db notification
241+
//
242+
void MuxManager::addOrUpdateDefaultRouteState(bool is_v4, const std::string &routeState)
243+
{
244+
if (is_v4) {
245+
mIpv4DefaultRouteState = routeState;
246+
} else {
247+
mIpv6DefaultRouteState = routeState;
248+
}
249+
250+
std::string nextState = "na";
251+
// For now we only need IPv4 default route state to be "ok". If we switch to IPv6 in the furture, this will cause an issue.
252+
if (mIpv4DefaultRouteState == "ok") {
253+
nextState = "ok";
254+
}
255+
256+
MUXLOGINFO(boost::format("Default route state: %s") % nextState);
257+
258+
PortMapIterator portMapIterator = mPortMap.begin();
259+
while (portMapIterator != mPortMap.end()) {
260+
portMapIterator->second->handleDefaultRouteState(nextState);
261+
portMapIterator ++;
262+
}
263+
}
264+
237265
//
238266
// ---> getMuxPortPtrOrThrow(const std::string &portName);
239267
//

src/MuxManager.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,19 @@ class MuxManager
305305
*/
306306
void processProbeMuxState(const std::string &portName, const std::string &muxState);
307307

308+
/**
309+
* @method addOrUpdateDefaultRouteState
310+
*
311+
* @brief update default route state based on state db notification
312+
*
313+
* @param ipAddress
314+
* @param routeState
315+
*
316+
* @return none
317+
*
318+
*/
319+
void addOrUpdateDefaultRouteState(bool is_v4, const std::string &routeState);
320+
308321
private:
309322
/**
310323
*@method getMuxPortPtrOrThrow
@@ -360,6 +373,9 @@ class MuxManager
360373
std::shared_ptr<mux::DbInterface> mDbInterfacePtr;
361374

362375
PortMap mPortMap;
376+
377+
std::string mIpv4DefaultRouteState = "na";
378+
std::string mIpv6DefaultRouteState = "na";
363379
};
364380

365381
} /* namespace mux */

src/MuxPort.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,20 @@ void MuxPort::handleMuxConfig(const std::string &config)
228228
)));
229229
}
230230

231+
//
232+
// ---> handleDefaultRouteState(const std::string &routeState);
233+
//
234+
// handles default route state notification
235+
//
236+
void MuxPort::handleDefaultRouteState(const std::string &routeState)
237+
{
238+
MUXLOGDEBUG(boost::format("port: %s, state db default route state: %s") % mMuxPortConfig.getPortName() % routeState);
239+
240+
boost::asio::io_service &ioService = mStrand.context();
241+
ioService.post(mStrand.wrap(boost::bind(
242+
&link_manager::LinkManagerStateMachine::handleDefaultRouteStateNotification,
243+
&mLinkManagerStateMachine,
244+
routeState
245+
)));
246+
}
231247
} /* namespace mux */

src/MuxPort.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,17 @@ class MuxPort: public std::enable_shared_from_this<MuxPort>
252252
*/
253253
void handleMuxConfig(const std::string &config);
254254

255+
/**
256+
* @method handleDefaultRouteState(const std::string &routeState)
257+
*
258+
* @brief handles default route state notification
259+
*
260+
* @param routeState
261+
*
262+
* @return none
263+
*/
264+
void handleDefaultRouteState(const std::string &routeState);
265+
255266
protected:
256267
friend class test::MuxManagerTest;
257268
friend class test::FakeMuxPort;

src/link_manager/LinkManagerStateMachine.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,28 @@ void LinkManagerStateMachine::handleSwitchActiveRequestEvent()
815815
}
816816
}
817817

818+
//
819+
// ---> handleDefaultRouteStateNotification(const std::string &routeState);
820+
//
821+
// handle default route state notification from routeorch
822+
//
823+
void LinkManagerStateMachine::handleDefaultRouteStateNotification(const std::string &routeState)
824+
{
825+
MUXLOGWARNING(boost::format("%s: state db default route state: %s") % mMuxPortConfig.getPortName() % routeState);
826+
827+
if (mComponentInitState.test(MuxStateComponent)) {
828+
if (ms(mCompositeState) != mux_state::MuxState::Label::Standby && routeState == "na") {
829+
CompositeState nextState = mCompositeState;
830+
enterLinkProberState(nextState, link_prober::LinkProberState::Wait);
831+
switchMuxState(nextState, mux_state::MuxState::Label::Standby, true);
832+
LOGWARNING_MUX_STATE_TRANSITION(mMuxPortConfig.getPortName(), mCompositeState, nextState);
833+
mCompositeState = nextState;
834+
} else {
835+
enterMuxWaitState(mCompositeState);
836+
}
837+
}
838+
}
839+
818840
//
819841
// ---> updateMuxLinkmgrState();
820842
//

src/link_manager/LinkManagerStateMachine.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,17 @@ class LinkManagerStateMachine: public common::StateMachine,
476476
*/
477477
void handleSwitchActiveRequestEvent();
478478

479+
/**
480+
* @method handleDefaultRouteStateNotification(const std::string &routeState)
481+
*
482+
* @brief handle default route state notification from routeorch
483+
*
484+
* @param routeState
485+
*
486+
* @return none
487+
*/
488+
void handleDefaultRouteStateNotification(const std::string &routeState);
489+
479490
private:
480491
/**
481492
*@method updateMuxLinkmgrState

test/LinkManagerStateMachineTest.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,12 @@ void LinkManagerStateMachineTest::setMuxStandby()
230230
VALIDATE_STATE(Standby, Standby, Up);
231231
}
232232

233+
void LinkManagerStateMachineTest::postDefaultRouteEvent(std::string routeState, uint32_t count)
234+
{
235+
mFakeMuxPort.handleDefaultRouteState(routeState);
236+
runIoService(count);
237+
}
238+
233239
TEST_F(LinkManagerStateMachineTest, MuxActiveSwitchOver)
234240
{
235241
setMuxActive();
@@ -1013,4 +1019,38 @@ TEST_F(LinkManagerStateMachineTest, MuxStandby2Unknown2Error)
10131019
VALIDATE_STATE(Standby, Error, Down);
10141020
}
10151021

1022+
TEST_F(LinkManagerStateMachineTest, MuxActivDefaultRouteStateNA)
1023+
{
1024+
setMuxActive();
1025+
1026+
EXPECT_EQ(mDbInterfacePtr->mSetMuxStateInvokeCount, 0);
1027+
postDefaultRouteEvent("na", 3);
1028+
1029+
VALIDATE_STATE(Wait, Wait, Up);
1030+
EXPECT_EQ(mDbInterfacePtr->mSetMuxStateInvokeCount, 1);
1031+
1032+
postLinkProberEvent(link_prober::LinkProberState::Standby, 3);
1033+
VALIDATE_STATE(Standby, Wait, Up);
1034+
1035+
handleMuxState("standby", 3);
1036+
VALIDATE_STATE(Standby, Standby, Up);
1037+
}
1038+
1039+
TEST_F(LinkManagerStateMachineTest, MuxStandbyDefaultRouteStateOK)
1040+
{
1041+
setMuxStandby();
1042+
1043+
EXPECT_EQ(mDbInterfacePtr->mProbeMuxStateInvokeCount, 0);
1044+
postDefaultRouteEvent("ok", 2);
1045+
1046+
VALIDATE_STATE(Standby, Wait, Up);
1047+
EXPECT_EQ(mDbInterfacePtr->mProbeMuxStateInvokeCount, 1);
1048+
1049+
postLinkProberEvent(link_prober::LinkProberState::Standby, 3);
1050+
VALIDATE_STATE(Standby, Wait, Up);
1051+
1052+
handleMuxState("standby", 3);
1053+
VALIDATE_STATE(Standby, Standby, Up);
1054+
}
1055+
10161056
} /* namespace test */

test/LinkManagerStateMachineTest.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class LinkManagerStateMachineTest: public ::testing::Test
5151
void activateStateMachine();
5252
void setMuxActive();
5353
void setMuxStandby();
54+
void postDefaultRouteEvent(std::string routeState, uint32_t count = 0);
5455

5556
public:
5657
boost::asio::io_service mIoService;

0 commit comments

Comments
 (0)