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

Extend eoiu support to speed up route reconciliation of EVPN/fdbsyncd #1700

Open
wants to merge 3 commits 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
79 changes: 77 additions & 2 deletions fdbsyncd/fdbsyncd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,36 @@
using namespace std;
using namespace swss;

// Wait 3 seconds after detecting EOIU reached state
const uint32_t DEFAULT_EOIU_HOLD_INTERVAL = 3;

// Check if eoiu state reached by ipv4 ipv6 and evpn
static bool eoiuFlagsSet(Table &bgpStateTable)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It conveys as Flag set. Can you rename to isEoiuFlagsSet instead?

{
string value;

bgpStateTable.hget("IPv4|eoiu", "state", value);
if (value != "reached")
{
SWSS_LOG_DEBUG("IPv4|eoiu state: %s", value.c_str());
return false;
}
bgpStateTable.hget("IPv6|eoiu", "state", value);
if (value != "reached")
{
SWSS_LOG_DEBUG("IPv6|eoiu state: %s", value.c_str());
return false;
}
bgpStateTable.hget("Evpn|eoiu", "state", value);
if (value != "reached")
{
SWSS_LOG_DEBUG("Evpn|eoiu state: %s", value.c_str());
return false;
}
SWSS_LOG_NOTICE("Warm-Restart bgp eoiu reached for ipv4 Evpn and ipv6");
return true;
}

int main(int argc, char **argv)
{
Logger::linkToDbNative("fdbsyncd");
Expand All @@ -21,6 +51,8 @@ int main(int argc, char **argv)
DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
DBConnector log_db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
Table bgpStateTable(&stateDb, STATE_BGP_TABLE_NAME);


FdbSync sync(&pipelineAppDB, &stateDb, &config_db);

Expand All @@ -37,6 +69,10 @@ int main(int argc, char **argv)
int ret;
Select s;
SelectableTimer replayCheckTimer(timespec{0, 0});
// Before eoiu flags detected, check them periodically. It also stop upon detection of reconciliation done.
SelectableTimer eoiuCheckTimer(timespec{0, 0});
// After eoiu flags are detected, start a hold timer before starting reconciliation.
SelectableTimer eoiuHoldTimer(timespec{0, 0});

using namespace std::chrono;

Expand Down Expand Up @@ -115,9 +151,14 @@ int main(int argc, char **argv)
}
//Else the interval is already set to default value

//TODO: Optimise the reconcillation time using eoiu - issue#1657
SWSS_LOG_NOTICE("Starting ReconcileTimer");
sync.getRestartAssist()->startReconcileTimer(s);

// Also start periodic eoiu check timer, first wait 5 seconds, then check every 1 second
eoiuCheckTimer.setInterval(timespec{5, 0});
eoiuCheckTimer.start();
s.addSelectable(&eoiuCheckTimer);
SWSS_LOG_NOTICE("Warm-Restart eoiuCheckTimer timer started.");
}
else
{
Expand All @@ -126,6 +167,39 @@ int main(int argc, char **argv)
replayCheckTimer.start();
}
}
else if (temps == &eoiuCheckTimer)
{
if (sync.getRestartAssist()->isWarmStartInProgress())
{
if (eoiuFlagsSet(bgpStateTable))
{
/* Obtain eoiu hold timer defined for bgp docker */
uint32_t eoiuHoldIval = WarmStart::getWarmStartTimer("eoiu_hold", "bgp");
if (!eoiuHoldIval)
{
eoiuHoldTimer.setInterval(timespec{DEFAULT_EOIU_HOLD_INTERVAL, 0});
eoiuHoldIval = DEFAULT_EOIU_HOLD_INTERVAL;
}
else
{
eoiuHoldTimer.setInterval(timespec{(time_t)eoiuHoldIval, 0});
}
eoiuHoldTimer.start();
s.addSelectable(&eoiuHoldTimer);
SWSS_LOG_NOTICE("Warm-Restart started EOIU hold timer which is to expire in %d seconds.", eoiuHoldIval);
s.removeSelectable(&eoiuCheckTimer);
continue;
}
eoiuCheckTimer.setInterval(timespec{1, 0});
// re-start eoiu check timer
eoiuCheckTimer.start();
SWSS_LOG_DEBUG("Warm-Restart eoiuCheckTimer restarted");
}
else
{
s.removeSelectable(&eoiuCheckTimer);
}
}
else
{
/*
Expand All @@ -134,11 +208,12 @@ int main(int argc, char **argv)
*/
if (sync.getRestartAssist()->isWarmStartInProgress())
{
if (sync.getRestartAssist()->checkReconcileTimer(temps))
if (sync.getRestartAssist()->checkReconcileTimer(temps) || temps == &eoiuHoldTimer)
{
sync.m_reconcileDone = true;
sync.getRestartAssist()->stopReconcileTimer(s);
sync.getRestartAssist()->reconcile();
s.removeSelectable(&eoiuHoldTimer);
SWSS_LOG_NOTICE("VXLAN FDB VNI Reconcillation Complete");
}
}
Expand Down
43 changes: 35 additions & 8 deletions fpmsyncd/bgp_eoiu_marker.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@ def __init__(self):
self.ipv4_neigh_eor_status = {}
self.ipv6_neighbors = []
self.ipv6_neigh_eor_status = {}
self.evpn_neighbors = []
self.evpn_neigh_eor_status = {}
self.keepalivesRecvCnt = {}
self.bgp_ipv4_eoiu = False
self.bgp_ipv6_eoiu = False
self.bgp_evpn_eoiu = False
self.get_peers_wt = self.DEF_TIME_OUT

def get_all_peers(self):
Expand All @@ -57,8 +60,12 @@ def get_all_peers(self):
if "ipv6Unicast" in peer_info and "peers" in peer_info["ipv6Unicast"]:
self.ipv6_neighbors = peer_info["ipv6Unicast"]["peers"].keys()

if "l2VpnEvpn" in peer_info and "peers" in peer_info["l2VpnEvpn"]:
self.evpn_neighbors = peer_info["l2VpnEvpn"]["peers"].keys()

syslog.syslog('BGP ipv4 neighbors: {}'.format(self.ipv4_neighbors))
syslog.syslog('BGP ipv4 neighbors: {}'.format(self.ipv6_neighbors))
syslog.syslog('BGP ipv6 neighbors: {}'.format(self.ipv6_neighbors))
syslog.syslog('BGP evpn neighbors: {}'.format(self.evpn_neighbors))
return

except Exception:
Expand All @@ -75,6 +82,8 @@ def init_peers_eor_status(self):
self.ipv4_neigh_eor_status[neigh] = "unknown"
for neigh in self.ipv6_neighbors:
self.ipv6_neigh_eor_status[neigh] = "unknown"
for neigh in self.evpn_neighbors:
self.evpn_neigh_eor_status[neigh] = "unknown"

# Set the statedb "BGP_STATE_TABLE|eoiu", so fpmsyncd can get the bgp eoiu signal
# Only two families: 'ipv4' and 'ipv6'
Expand All @@ -94,13 +103,15 @@ def clean_bgp_eoiu_marker(self):
db.connect(db.STATE_DB, False)
db.delete(db.STATE_DB, "BGP_STATE_TABLE|IPv4|eoiu")
db.delete(db.STATE_DB, "BGP_STATE_TABLE|IPv6|eoiu")
db.delete(db.STATE_DB, "BGP_STATE_TABLE|Evpn|eoiu")
db.close(db.STATE_DB)
syslog.syslog('Cleaned ipv4 and ipv6 eoiu marker flags')
syslog.syslog('Cleaned ipv4 evpn and ipv6 eoiu marker flags')
return

def bgp_eor_received(self, neigh, is_ipv4):
def bgp_eor_received(self, neigh, af):
try:
neighstr = "%s" % neigh
af_str = "%s" % af
eor_received = False
cmd = "vtysh -c 'show bgp neighbors %s json'" % neighstr
output = commands.getoutput(cmd)
Expand All @@ -109,9 +120,11 @@ def bgp_eor_received(self, neigh, is_ipv4):
if "gracefulRestartInfo" in neig_status[neighstr]:
if "endOfRibRecv" in neig_status[neighstr]["gracefulRestartInfo"]:
eor_info = neig_status[neighstr]["gracefulRestartInfo"]["endOfRibRecv"]
if is_ipv4 and "IPv4 Unicast" in eor_info and eor_info["IPv4 Unicast"] == True:
if af_str == "Ipv4" and "ipv4Unicast" in eor_info and eor_info["ipv4Unicast"] == True:
eor_received = True
elif af_str == "Ipv6" and "ipv6Unicast" in eor_info and eor_info["ipv6Unicast"] == True:
eor_received = True
elif not is_ipv4 and "IPv6 Unicast" in eor_info and eor_info["IPv6 Unicast"] == True:
elif af_str == "Evpn" and "l2VpnEvpn" in eor_info and eor_info["l2VpnEvpn"] == True:
eor_received = True
if eor_received:
syslog.syslog('BGP eor received for neighbors: {}'.format(neigh))
Expand Down Expand Up @@ -150,21 +163,29 @@ def wait_for_bgp_eoiu(self):
while wait_time >= 0:
if not self.bgp_ipv4_eoiu:
for neigh, eor_status in self.ipv4_neigh_eor_status.items():
if eor_status == "unknown" and self.bgp_eor_received(neigh, True):
if eor_status == "unknown" and self.bgp_eor_received(neigh, "Ipv4"):
self.ipv4_neigh_eor_status[neigh] = "rcvd"
if "unknown" not in self.ipv4_neigh_eor_status.values():
self.bgp_ipv4_eoiu = True
syslog.syslog("BGP ipv4 eoiu reached")

if not self.bgp_ipv6_eoiu:
for neigh, eor_status in self.ipv6_neigh_eor_status.items():
if eor_status == "unknown" and self.bgp_eor_received(neigh, False):
if eor_status == "unknown" and self.bgp_eor_received(neigh, "Ipv6"):
self.ipv6_neigh_eor_status[neigh] = "rcvd"
if "unknown" not in self.ipv6_neigh_eor_status.values():
self.bgp_ipv6_eoiu = True
syslog.syslog('BGP ipv6 eoiu reached')

if self.bgp_ipv6_eoiu and self.bgp_ipv4_eoiu:
if not self.bgp_evpn_eoiu:
for neigh, eor_status in self.evpn_neigh_eor_status.items():
if eor_status == "unknown" and self.bgp_eor_received(neigh, "Evpn"):
self.evpn_neigh_eor_status[neigh] = "rcvd"
if "unknown" not in self.evpn_neigh_eor_status.values():
self.bgp_evpn_eoiu = True
syslog.syslog("BGP evpn eoiu reached")

if self.bgp_ipv6_eoiu and self.bgp_ipv4_eoiu and self.bgp_evpn_eoiu:
break;
time.sleep(self.CHECK_INTERVAL)
wait_time -= self.CHECK_INTERVAL
Expand All @@ -175,6 +196,9 @@ def wait_for_bgp_eoiu(self):
if not self.bgp_ipv4_eoiu:
syslog.syslog(syslog.LOG_ERR, "BGP ipv4 eoiu not reached: {}".format(self.ipv4_neigh_eor_status));

if not self.bgp_evpn_eoiu:
syslog.syslog(syslog.LOG_ERR, "BGP evpn eoiu not reached: {}".format(self.evpn_neigh_eor_status));

def main():

print "bgp_eoiu_marker service is started"
Expand All @@ -200,6 +224,7 @@ def main():

bgp_state_check.set_bgp_eoiu_marker("IPv4", "unknown")
bgp_state_check.set_bgp_eoiu_marker("IPv6", "unknown")
bgp_state_check.set_bgp_eoiu_marker("Evpn", "unknown")
bgp_state_check.get_all_peers()
bgp_state_check.init_peers_eor_status()
try:
Expand All @@ -213,6 +238,8 @@ def main():
bgp_state_check.set_bgp_eoiu_marker("IPv4", "reached")
if bgp_state_check.bgp_ipv6_eoiu:
bgp_state_check.set_bgp_eoiu_marker("IPv6", "reached")
if bgp_state_check.bgp_evpn_eoiu:
bgp_state_check.set_bgp_eoiu_marker("Evpn", "reached")

print "bgp_eoiu_marker service is done"
return
Expand Down