From a7499c34038141221e393eb891134b2d3dfb1ca7 Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Tue, 29 Nov 2022 13:57:16 +0000 Subject: [PATCH] static route expiry feature support --- src/sonic-bgpcfgd/bgpcfgd/main.py | 7 +++ .../bgpcfgd/managers_static_rt.py | 24 +++++++- src/sonic-bgpcfgd/bgpcfgd/static_rt_timer.py | 58 +++++++++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 src/sonic-bgpcfgd/bgpcfgd/static_rt_timer.py diff --git a/src/sonic-bgpcfgd/bgpcfgd/main.py b/src/sonic-bgpcfgd/bgpcfgd/main.py index 698e1756e654..e94597eb29f5 100644 --- a/src/sonic-bgpcfgd/bgpcfgd/main.py +++ b/src/sonic-bgpcfgd/bgpcfgd/main.py @@ -2,6 +2,7 @@ import signal import sys import syslog +import threading import traceback from swsscommon import swsscommon @@ -17,6 +18,7 @@ from .managers_intf import InterfaceMgr from .managers_setsrc import ZebraSetSrc from .managers_static_rt import StaticRouteMgr +from .static_rt_timer import StaticRouteTimer from .managers_rm import RouteMapMgr from .runner import Runner, signal_handler from .template import TemplateFabric @@ -27,6 +29,9 @@ def do_work(): """ Main function """ + st_rt_timer = StaticRouteTimer() + thr = threading.Thread(target = st_rt_timer.run) + thr.start() frr = FRR(["bgpd", "zebra", "staticd"]) frr.wait_for_daemons(seconds=20) # @@ -59,6 +64,7 @@ def do_work(): BBRMgr(common_objs, "CONFIG_DB", "BGP_BBR"), # Static Route Managers StaticRouteMgr(common_objs, "CONFIG_DB", "STATIC_ROUTE"), + StaticRouteMgr(common_objs, "APPL_DB", "STATIC_ROUTE"), # Route Advertisement Managers AdvertiseRouteMgr(common_objs, "STATE_DB", swsscommon.STATE_ADVERTISE_NETWORK_TABLE_NAME), RouteMapMgr(common_objs, "APPL_DB", swsscommon.APP_BGP_PROFILE_TABLE_NAME), @@ -67,6 +73,7 @@ def do_work(): for mgr in managers: runner.add_manager(mgr) runner.run() + thr.join() def main(): diff --git a/src/sonic-bgpcfgd/bgpcfgd/managers_static_rt.py b/src/sonic-bgpcfgd/bgpcfgd/managers_static_rt.py index 6fafeda8142d..e479b8edf9de 100644 --- a/src/sonic-bgpcfgd/bgpcfgd/managers_static_rt.py +++ b/src/sonic-bgpcfgd/bgpcfgd/managers_static_rt.py @@ -4,6 +4,7 @@ from .template import TemplateFabric import socket from swsscommon import swsscommon +from ipaddress import ip_network, IPv4Network class StaticRouteMgr(Manager): """ This class updates static routes when STATIC_ROUTE table is updated """ @@ -93,11 +94,28 @@ def split_key(key): Split key into vrf name and prefix. :param key: key to split :return: vrf name extracted from the key, ip prefix extracted from the key + key example: APPL_DB vrf:5.5.5.0/24, 5.5.5.0/24, vrf:2001::0/64, 2001::0/64 + CONFIG_DB vrf|5.5.5.0/24, 5.5.5.0/24, vrf|2001::0/64, 2001::0/64 """ - if '|' not in key: - return 'default', key - else: + vrf = "" + prefix = "" + + if '|' in key: return tuple(key.split('|', 1)) + else: + try: + _ = ip_network(key) + vrf, prefix = 'default', key + except ValueError: + # key in APPL_DB + log_debug("static route key {} is not prefix only formart, split with ':'".format(key)) + output = key.split(':', 1) + if len(output) < 2: + log_debug("invalid input in APPL_DB {}".format(key)) + raise ValueError + vrf = output[0] + prefix = key[len(vrf)+1:] + return vrf, prefix def static_route_commands(self, ip_nh_set, cur_nh_set, ip_prefix, vrf): diff_set = ip_nh_set.symmetric_difference(cur_nh_set) diff --git a/src/sonic-bgpcfgd/bgpcfgd/static_rt_timer.py b/src/sonic-bgpcfgd/bgpcfgd/static_rt_timer.py new file mode 100644 index 000000000000..7042849ef426 --- /dev/null +++ b/src/sonic-bgpcfgd/bgpcfgd/static_rt_timer.py @@ -0,0 +1,58 @@ +from .log import log_err, log_info, log_debug +from swsscommon import swsscommon +import time + +class StaticRouteTimer(object): + """ This class checks the static routes and deletes those entries that have not been refreshed """ + def __init__(self): + self.db = swsscommon.SonicV2Connector() + self.db.connect(self.db.APPL_DB) + self.timer = None + self.start = None + + DEFAULT_TIMER = 180 + DEFAULT_SLEEP = 60 + MAX_TIMER = 1800 + + def set_timer(self): + """ Check for custom route expiry time in STATIC_ROUTE_EXPIRY_TIME """ + timer = self.db.get(self.db.APPL_DB, "STATIC_ROUTE_EXPIRY_TIME", "time") + if timer is not None: + if timer.isdigit(): + timer = int(timer) + if timer > 0 and timer <= self.MAX_TIMER: + self.timer = timer + return + log_err("Custom static route expiry time of {}s is invalid!".format(timer)) + return + + def alarm(self): + """ Clear unrefreshed static routes """ + static_routes = self.db.keys(self.db.APPL_DB, "STATIC_ROUTE:*") + if static_routes is not None: + for sr in static_routes: + expiry = self.db.get(self.db.APPL_DB, sr, "expiry") + if expiry == "false": + continue + refresh = self.db.get(self.db.APPL_DB, sr, "refresh") + if refresh == "true": + self.db.set(self.db.APPL_DB, sr, "refresh", "false") + log_debug("Refresh status of static route {} is set to false".format(sr)) + else: + self.db.delete(self.db.APPL_DB, sr) + log_debug("Static route {} deleted".format(sr)) + self.start = time.time() + return + + def run(self): + self.start = time.time() + while True: + self.set_timer() + if self.timer: + log_info("Static route expiry set to {}s".format(self.timer)) + time.sleep(self.timer) + self.alarm() + else: + time.sleep(self.DEFAULT_SLEEP) + if time.time() - self.start >= self.DEFAULT_TIMER: + self.alarm()