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

Changes to persist TSA/B state across reloads #11257

Merged
merged 13 commits into from
Jul 12, 2022
23 changes: 21 additions & 2 deletions dockers/docker-fpm-frr/base_image_files/TS
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@

PLATFORM=${PLATFORM:-`sonic-cfggen -H -v DEVICE_METADATA.localhost.platform`}

if [[ $1 == "TSA" ]]; then
TSA_STATE_UPDATE='{"BGP_DEVICE_GLOBAL":{"STATE":{"tsa_enabled": "true"}}}'
elif [[ $1 == "TSB" ]]; then
TSA_STATE_UPDATE='{"BGP_DEVICE_GLOBAL":{"STATE":{"tsa_enabled": "false"}}}'
fi

# Parse the device specific asic conf file, if it exists
ASIC_CONF=/usr/share/sonic/device/$PLATFORM/asic.conf
[ -f $ASIC_CONF ] && . $ASIC_CONF
Expand All @@ -20,10 +26,23 @@ if [[ ($NUM_ASIC -gt 1) ]]; then
if [ $sub_role == 'FrontEnd' ]
then
echo -e "BGP"$asic" : \c"
docker exec -i bgp$asic /usr/bin/$1
if [[ -n "$TSA_STATE_UPDATE" ]]; then
sonic-cfggen -a "$TSA_STATE_UPDATE" -w -n $NAMESPACE_PREFIX$asic
logger -t $1 -p user.info "ConfigDB updated"
else
# If TSC is executed, invoke FRR script to check installed route-maps
docker exec -i bgp$asic /usr/bin/$1
tjchadaga marked this conversation as resolved.
Show resolved Hide resolved
fi
fi
asic=$[$asic+1]
done
else
docker exec -i bgp /usr/bin/$1
if [[ -n "$TSA_STATE_UPDATE" ]]; then
sonic-cfggen -a "$TSA_STATE_UPDATE" -w
logger -t $1 -p user.info "ConfigDB updated"
else
# If TSC is executed, invoke FRR script to check installed route-maps
docker exec -i bgp /usr/bin/$1
fi
fi

27 changes: 19 additions & 8 deletions dockers/docker-fpm-frr/base_image_files/TSA
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
#!/bin/bash

# toggle the mux to standby if dualtor and any mux active
if
[[ "$(sonic-cfggen -d -v DEVICE_METADATA.localhost.subtype | tr [:upper:] [:lower:])" == *"dualtor"* ]] &&
[[ $(show mux status | grep active | wc -l) > 0 ]];
then
logger -t TSA -p user.info "Toggle all mux mode to standby"
sudo config mux mode standby all

if [[ "$(sonic-cfggen -d -v BGP_DEVICE_GLOBAL.STATE.tsa_enabled)" == "true" ]]; then
echo "System is already in Maintenance"
logger -t TSA -p user.info "System is already in Maintenance"
else
# toggle the mux to standby if dualtor and any mux active
if
[[ "$(sonic-cfggen -d -v DEVICE_METADATA.localhost.subtype | tr [:upper:] [:lower:])" == *"dualtor"* ]] &&
[[ $(show mux status | grep active | wc -l) > 0 ]];
then
logger -t TSA -p user.info "Toggle all mux mode to standby"
sudo config mux mode standby all
fi

/usr/bin/TS TSA
tjchadaga marked this conversation as resolved.
Show resolved Hide resolved
logger -t TSA -p user.info "System Mode: Normal -> Maintenance"
echo "System Mode: Normal -> Maintenance"
echo ""
echo "Please execute 'config save' to preserve System mode in Maintenance after reboot or config reload"
fi

/usr/bin/TS TSA
23 changes: 16 additions & 7 deletions dockers/docker-fpm-frr/base_image_files/TSB
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
#!/bin/bash

# toggle the mux to auto if dualtor
if [[ "$(sonic-cfggen -d -v DEVICE_METADATA.localhost.subtype | tr [:upper:] [:lower:])" == *"dualtor"* ]];
then
logger -t TSB -p user.info "Toggle all mux mode to auto"
sudo config mux mode auto all
fi
if [[ "$(sonic-cfggen -d -v BGP_DEVICE_GLOBAL.STATE.tsa_enabled)" == "false" ]]; then
echo "System is already in Normal mode"
logger -t TSB -p user.info "System is already in Normal mode"
else
# toggle the mux to auto if dualtor
if [[ "$(sonic-cfggen -d -v DEVICE_METADATA.localhost.subtype | tr [:upper:] [:lower:])" == *"dualtor"* ]];
then
logger -t TSB -p user.info "Toggle all mux mode to auto"
sudo config mux mode auto all
fi

/usr/bin/TS TSB
/usr/bin/TS TSB
tjchadaga marked this conversation as resolved.
Show resolved Hide resolved
logger -t TSB -p user.info "System Mode: Maintenance -> Normal"
echo "System Mode: Maintenance -> Normal"
echo ""
echo "Please execute 'config save' to preserve System mode in Normal state after reboot or config reload"
fi
5 changes: 5 additions & 0 deletions files/build_templates/init_cfg.json.j2
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@
"POLL_INTERVAL": "10000"
}
},
"BGP_DEVICE_GLOBAL": {
"STATE": {
"tsa_enabled": "false"
}
},
{%- set features = [("bgp", "enabled", false, "enabled"),
("database", "always_enabled", false, "always_enabled"),
("lldp", "enabled", true, "enabled"),
Expand Down
3 changes: 3 additions & 0 deletions src/sonic-bgpcfgd/bgpcfgd/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .managers_setsrc import ZebraSetSrc
from .managers_static_rt import StaticRouteMgr
from .managers_rm import RouteMapMgr
from .managers_device_global import DeviceGlobalCfgMgr
from .runner import Runner, signal_handler
from .template import TemplateFabric
from .utils import read_constants
Expand Down Expand Up @@ -64,6 +65,8 @@ def do_work():
# 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),
# Device Global Manager
DeviceGlobalCfgMgr(common_objs, "CONFIG_DB", "BGP_DEVICE_GLOBAL"),
tjchadaga marked this conversation as resolved.
Show resolved Hide resolved
]
runner = Runner(common_objs['cfg_mgr'])
for mgr in managers:
Expand Down
7 changes: 5 additions & 2 deletions src/sonic-bgpcfgd/bgpcfgd/managers_bgp.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .manager import Manager
from .template import TemplateFabric
from .utils import run_command
from .managers_device_global import DeviceGlobalCfgMgr


class BGPPeerGroupMgr(object):
Expand All @@ -23,6 +24,7 @@ def __init__(self, common_objs, base_template):
tf = common_objs['tf']
self.policy_template = tf.from_file(base_template + "policies.conf.j2")
self.peergroup_template = tf.from_file(base_template + "peer-group.conf.j2")
self.device_global_cfgmgr = DeviceGlobalCfgMgr(common_objs, "CONFIG_DB", "BGP_DEVICE_GLOBAL")
tjchadaga marked this conversation as resolved.
Show resolved Hide resolved

def update(self, name, **kwargs):
"""
Expand Down Expand Up @@ -56,14 +58,15 @@ def update_pg(self, name, **kwargs):
"""
try:
pg = self.peergroup_template.render(**kwargs)
tsa_rm = self.device_global_cfgmgr.check_state_and_get_tsa_routemaps(pg)
tjchadaga marked this conversation as resolved.
Show resolved Hide resolved
except jinja2.TemplateError as e:
log_err("Can't render peer-group template: '%s': %s" % (name, str(e)))
return False

if kwargs['vrf'] == 'default':
cmd = ('router bgp %s\n' % kwargs['bgp_asn']) + pg
cmd = ('router bgp %s\n' % kwargs['bgp_asn']) + pg + tsa_rm
else:
cmd = ('router bgp %s vrf %s\n' % (kwargs['bgp_asn'], kwargs['vrf'])) + pg
cmd = ('router bgp %s vrf %s\n' % (kwargs['bgp_asn'], kwargs['vrf'])) + pg + tsa_rm
self.update_entity(cmd, "Peer-group for peer '%s'" % name)
return True

Expand Down
106 changes: 106 additions & 0 deletions src/sonic-bgpcfgd/bgpcfgd/managers_device_global.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from .manager import Manager
from .log import log_err, log_debug, log_notice
import re

class DeviceGlobalCfgMgr(Manager):
"""This class responds to change in device-specific state"""

def __init__(self, common_objs, db, table):
"""
Initialize the object
:param common_objs: common object dictionary
:param db: name of the db
:param table: name of the table in the db
"""
self.directory = common_objs['directory']
self.cfg_mgr = common_objs['cfg_mgr']
self.constants = common_objs['constants']
self.tsa_template = common_objs['tf'].from_file("bgpd/tsa/bgpd.tsa.isolate.conf.j2")
self.tsb_template = common_objs['tf'].from_file("bgpd/tsa/bgpd.tsa.unisolate.conf.j2")
super(DeviceGlobalCfgMgr, self).__init__(
common_objs,
[],
db,
table,
)

def set_handler(self, key, data):
log_debug("DeviceGlobalCfgMgr:: set handler")
""" Handle device tsa_enabled state change """
if not data:
log_err("DeviceGlobalCfgMgr:: data is None")
return False

if "tsa_enabled" in data:
self.cfg_mgr.commit()
tjchadaga marked this conversation as resolved.
Show resolved Hide resolved
self.cfg_mgr.update()
self.isolate_unisolate_device(data["tsa_enabled"])
self.directory.put(self.db_name, self.table_name, "tsa_enabled", data["tsa_enabled"])
return True
return False

def del_handler(self, key):
log_debug("DeviceGlobalCfgMgr:: del handler")
return True

def check_state_and_get_tsa_routemaps(self, cfg):
""" API to get TSA route-maps if device is isolated"""
cmd = ""
if self.directory.path_exist("CONFIG_DB", "BGP_DEVICE_GLOBAL", "tsa_enabled"):
tsa_status = self.directory.get_slot("CONFIG_DB", "BGP_DEVICE_GLOBAL")["tsa_enabled"]
if tsa_status == "true":
cmds = cfg.replace("#012", "\n").split("\n")
log_notice("DeviceGlobalCfgMgr:: Device is isolated. Applying TSA route-maps")
cmd = self.get_tsa_routemaps(cmds)
return cmd

def isolate_unisolate_device(self, tsa_status):
""" API to get TSA/TSB route-maps and apply configuration"""
cmd = "\n"
if tsa_status == "true":
log_notice("DeviceGlobalCfgMgr:: Device isolated. Executing TSA")
cmd += self.get_tsa_routemaps(self.cfg_mgr.get_text())
else:
log_notice("DeviceGlobalCfgMgr:: Device un-isolated. Executing TSB")
cmd += self.get_tsb_routemaps(self.cfg_mgr.get_text())

self.cfg_mgr.push(cmd)
log_debug("DeviceGlobalCfgMgr::Done")

def get_tsa_routemaps(self, cmds):
tjchadaga marked this conversation as resolved.
Show resolved Hide resolved
if not cmds:
return ""

route_map_names = self.__extract_out_route_map_names(cmds)
return self.__generate_routemaps_from_template(route_map_names, self.tsa_template)

def get_tsb_routemaps(self, cmds):
if not cmds:
return ""

route_map_names = self.__extract_out_route_map_names(cmds)
return self.__generate_routemaps_from_template(route_map_names, self.tsb_template)

def __generate_routemaps_from_template(self, route_map_names, template):
tjchadaga marked this conversation as resolved.
Show resolved Hide resolved
cmd = "\n"
for rm in sorted(route_map_names):
if "_INTERNAL_" in rm:
continue
if "V4" in rm:
ipv="V4" ; ipp="ip"
elif "V6" in rm:
ipv="V6" ; ipp="ipv6"
else:
continue
cmd += template.render(route_map_name=rm,ip_version=ipv,ip_protocol=ipp, constants=self.constants)
cmd += "\n"
return cmd

def __extract_out_route_map_names(self, cmds):
route_map_names = set()
out_route_map = re.compile(r'^\s*neighbor \S+ route-map (\S+) out$')
for line in cmds:
result = out_route_map.match(line)
if result:
route_map_names.add(result.group(1))
return route_map_names
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
!
! template: bgpd/templates/general/peer-group.conf.j2
!
neighbor PEER_V4 peer-group
neighbor PEER_V6 peer-group
address-family ipv4
neighbor PEER_V4 allowas-in 1
neighbor PEER_V4 soft-reconfiguration inbound
neighbor PEER_V4 route-map FROM_BGP_PEER_V4 in
neighbor PEER_V4 route-map TO_BGP_PEER_V4 out
exit-address-family
address-family ipv6
neighbor PEER_V6 allowas-in 1
neighbor PEER_V6 soft-reconfiguration inbound
neighbor PEER_V6 route-map FROM_BGP_PEER_V6 in
neighbor PEER_V6 route-map TO_BGP_PEER_V6 out
exit-address-family
!
! end of template: bgpd/templates/general/peer-group.conf.j2
!


route-map TO_BGP_PEER_V4 permit 20
match ip address prefix-list PL_LoopbackV4
set community 12345:12345
route-map TO_BGP_PEER_V4 deny 30
!
route-map TO_BGP_PEER_V6 permit 20
match ipv6 address prefix-list PL_LoopbackV6
set community 12345:12345
route-map TO_BGP_PEER_V6 deny 30
!

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
!
! template: bgpd/templates/general/peer-group.conf.j2
!
neighbor PEER_V4 peer-group
neighbor PEER_V6 peer-group
address-family ipv4
neighbor PEER_V4 allowas-in 1
neighbor PEER_V4 soft-reconfiguration inbound
neighbor PEER_V4 route-map FROM_BGP_PEER_V4 in
neighbor PEER_V4 route-map TO_BGP_PEER_V4 out
exit-address-family
address-family ipv6
neighbor PEER_V6 allowas-in 1
neighbor PEER_V6 soft-reconfiguration inbound
neighbor PEER_V6 route-map FROM_BGP_PEER_V6 in
neighbor PEER_V6 route-map TO_BGP_PEER_V6 out
exit-address-family
!
! end of template: bgpd/templates/general/peer-group.conf.j2
!


no route-map TO_BGP_PEER_V4 permit 20
no route-map TO_BGP_PEER_V4 deny 30
!
no route-map TO_BGP_PEER_V6 permit 20
no route-map TO_BGP_PEER_V6 deny 30
!

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

route-map TO_BGP_PEER_V4 permit 20
match ip address prefix-list PL_LoopbackV4
set community 12345:12345
route-map TO_BGP_PEER_V4 deny 30
!
route-map TO_BGP_PEER_V6 permit 20
match ipv6 address prefix-list PL_LoopbackV6
set community 12345:12345
route-map TO_BGP_PEER_V6 deny 30
!
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

no route-map TO_BGP_PEER_V4 permit 20
no route-map TO_BGP_PEER_V4 deny 30
!
no route-map TO_BGP_PEER_V6 permit 20
no route-map TO_BGP_PEER_V6 deny 30
!
Loading