diff --git a/doc/swss-schema.md b/doc/swss-schema.md index aa58e06d2c..f6af65b815 100644 --- a/doc/swss-schema.md +++ b/doc/swss-schema.md @@ -714,6 +714,13 @@ Stores information for physical switch ports managed by the switch chip. Ports t ; the elected routing-stack. ; Supported range: 1-3600. + teamsyncd_timer = 1*4DIGIT ; teamsyncd_timer holds the time interval utilized by teamsyncd during warm-restart episodes. + ; The timer is started when teamsyncd starts. During the timer interval teamsyncd + ; will preserver all LAG interface changes, but it will not apply them. The changes + ; will only be applied when the timer expired. During the changes application the stale + ; LAG entries will be removed, the new LAG entries will be created. + ; Supported range: 1-9999. 0 is invalid + ### VXLAN\_TUNNEL Stores vxlan tunnels configuration diff --git a/teamsyncd/teamsync.cpp b/teamsyncd/teamsync.cpp index 5db7d3c455..0ada643275 100644 --- a/teamsyncd/teamsync.cpp +++ b/teamsyncd/teamsync.cpp @@ -4,13 +4,16 @@ #include #include #include +#include #include "logger.h" #include "netmsg.h" #include "dbconnector.h" #include "producerstatetable.h" +#include "warm_restart.h" #include "teamsync.h" using namespace std; +using namespace std::chrono; using namespace swss; /* Taken from drivers/net/team/team.c */ @@ -22,6 +25,34 @@ TeamSync::TeamSync(DBConnector *db, DBConnector *stateDb, Select *select) : m_lagMemberTable(db, APP_LAG_MEMBER_TABLE_NAME), m_stateLagTable(stateDb, STATE_LAG_TABLE_NAME) { + WarmStart::initialize("teamsyncd", "teamd"); + WarmStart::checkWarmStart("teamsyncd", "teamd"); + m_warmstart = WarmStart::isWarmStart(); + + if (m_warmstart) + { + m_start_time = steady_clock::now(); + auto warmRestartIval = WarmStart::getWarmStartTimer("teamsyncd", "teamd"); + m_pending_timeout = warmRestartIval ? warmRestartIval : DEFAULT_WR_PENDING_TIMEOUT; + m_lagTable.create_temp_view(); + m_lagMemberTable.create_temp_view(); + SWSS_LOG_NOTICE("Starting in warmstart mode"); + } +} + +void TeamSync::periodic() +{ + if (m_warmstart) + { + auto diff = duration_cast(steady_clock::now() - m_start_time); + if(diff.count() > m_pending_timeout) + { + applyState(); + m_warmstart = false; // apply state just once + } + } + + doSelectableTask(); } void TeamSync::doSelectableTask() @@ -44,6 +75,23 @@ void TeamSync::doSelectableTask() m_selectablesToRemove.clear(); } +void TeamSync::applyState() +{ + SWSS_LOG_NOTICE("Applying state"); + + m_lagTable.apply_temp_view(); + m_lagMemberTable.apply_temp_view(); + + for(auto &it: m_stateLagTablePreserved) + { + const auto &lagName = it.first; + const auto &fvVector = it.second; + m_stateLagTable.set(lagName, fvVector); + } + + m_stateLagTablePreserved.clear(); +} + void TeamSync::onMsg(int nlmsg_type, struct nl_object *obj) { struct rtnl_link *link = (struct rtnl_link *)obj; @@ -90,7 +138,14 @@ void TeamSync::addLag(const string &lagName, int ifindex, bool admin_state, fvVector.clear(); FieldValueTuple s("state", "ok"); fvVector.push_back(s); - m_stateLagTable.set(lagName, fvVector); + if (m_warmstart) + { + m_stateLagTablePreserved[lagName] = fvVector; + } + else + { + m_stateLagTable.set(lagName, fvVector); + } /* Create the team instance */ auto sync = make_shared(lagName, ifindex, &m_lagMemberTable); @@ -116,7 +171,15 @@ void TeamSync::removeLag(const string &lagName) if (m_teamSelectables.find(lagName) == m_teamSelectables.end()) return; - m_stateLagTable.del(lagName); + if (m_warmstart) + { + m_stateLagTablePreserved.erase(lagName); + } + else + { + m_stateLagTable.del(lagName); + } + m_selectablesToRemove.insert(lagName); } diff --git a/teamsyncd/teamsync.h b/teamsyncd/teamsync.h index 83b42a8364..0f771a7796 100644 --- a/teamsyncd/teamsync.h +++ b/teamsyncd/teamsync.h @@ -11,6 +11,11 @@ #include "netmsg.h" #include +// seconds +const uint32_t DEFAULT_WR_PENDING_TIMEOUT = 70; + +using namespace std::chrono; + namespace swss { class TeamSync : public NetMsg @@ -18,12 +23,11 @@ class TeamSync : public NetMsg public: TeamSync(DBConnector *db, DBConnector *stateDb, Select *select); + void periodic(); + /* Listen to RTM_NEWLINK, RTM_DELLINK to track team devices */ virtual void onMsg(int nlmsg_type, struct nl_object *obj); - /* Handle all selectables add/removal events */ - void doSelectableTask(); - class TeamPortSync : public Selectable { public: @@ -54,12 +58,23 @@ class TeamSync : public NetMsg bool oper_state); void removeLag(const std::string &lagName); + /* valid only in WR mode */ + void applyState(); + + /* Handle all selectables add/removal events */ + void doSelectableTask(); + private: Select *m_select; ProducerStateTable m_lagTable; ProducerStateTable m_lagMemberTable; Table m_stateLagTable; + bool m_warmstart; + std::unordered_map> m_stateLagTablePreserved; + steady_clock::time_point m_start_time; + uint32_t m_pending_timeout; + /* Store selectables needed to be updated in doSelectableTask function */ std::set m_selectablesToAdd; std::set m_selectablesToRemove; diff --git a/teamsyncd/teamsyncd.cpp b/teamsyncd/teamsyncd.cpp index 7e61c3efa4..9876d88d6e 100644 --- a/teamsyncd/teamsyncd.cpp +++ b/teamsyncd/teamsyncd.cpp @@ -34,9 +34,8 @@ int main(int argc, char **argv) while (true) { Selectable *temps; - s.select(&temps); - - sync.doSelectableTask(); + s.select(&temps, 1000); // block for a second + sync.periodic(); } } catch (const std::exception& e)