Skip to content

Commit fc93871

Browse files
tjchadagayxieca
authored andcommitted
Changes to persist TSA/B state across reloads (#11257)
1 parent 4abfd37 commit fc93871

File tree

12 files changed

+354
-18
lines changed

12 files changed

+354
-18
lines changed

dockers/docker-fpm-frr/base_image_files/TS

+23-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55

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

8+
if [[ $1 == "TSA" ]]; then
9+
TSA_STATE_UPDATE='{"BGP_DEVICE_GLOBAL":{"STATE":{"tsa_enabled": "true"}}}'
10+
elif [[ $1 == "TSB" ]]; then
11+
TSA_STATE_UPDATE='{"BGP_DEVICE_GLOBAL":{"STATE":{"tsa_enabled": "false"}}}'
12+
fi
13+
814
# Parse the device specific asic conf file, if it exists
915
ASIC_CONF=/usr/share/sonic/device/$PLATFORM/asic.conf
1016
[ -f $ASIC_CONF ] && . $ASIC_CONF
@@ -20,10 +26,25 @@ if [[ ($NUM_ASIC -gt 1) ]]; then
2026
if [ $sub_role == 'FrontEnd' ]
2127
then
2228
echo -e "BGP"$asic" : \c"
23-
docker exec -i bgp$asic /usr/bin/$1
29+
if [[ -n "$TSA_STATE_UPDATE" ]]; then
30+
sonic-cfggen -a "$TSA_STATE_UPDATE" -w -n $NAMESPACE_PREFIX$asic
31+
logger -t $1 -p user.info "BGP$asic: System Mode: Normal -> Maintenance"
32+
echo "BGP$asic: System Mode: Normal -> Maintenance"
33+
else
34+
# If TSC is executed, invoke FRR script to check installed route-maps
35+
docker exec -i bgp$asic /usr/bin/$1
36+
fi
2437
fi
2538
asic=$[$asic+1]
2639
done
2740
else
28-
docker exec -i bgp /usr/bin/$1
41+
if [[ -n "$TSA_STATE_UPDATE" ]]; then
42+
sonic-cfggen -a "$TSA_STATE_UPDATE" -w
43+
logger -t $1 -p user.info "System Mode: Normal -> Maintenance"
44+
echo "System Mode: Normal -> Maintenance"
45+
else
46+
# If TSC is executed, invoke FRR script to check installed route-maps
47+
docker exec -i bgp /usr/bin/$1
48+
fi
2949
fi
50+

dockers/docker-fpm-frr/base_image_files/TSA

+16-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
#!/bin/bash
22

3-
# toggle the mux to standby if dualtor and any mux active
4-
if
5-
[[ "$(sonic-cfggen -d -v DEVICE_METADATA.localhost.subtype | tr [:upper:] [:lower:])" == *"dualtor"* ]] &&
6-
[[ $(show mux status | grep active | wc -l) > 0 ]];
7-
then
8-
logger -t TSA -p user.info "Toggle all mux mode to standby"
9-
sudo config mux mode standby all
3+
4+
if [[ "$(sonic-cfggen -d -v BGP_DEVICE_GLOBAL.STATE.tsa_enabled)" == "true" ]]; then
5+
echo "System is already in Maintenance"
6+
logger -t TSA -p user.info "System is already in Maintenance"
7+
else
8+
# toggle the mux to standby if dualtor and any mux active
9+
if
10+
[[ "$(sonic-cfggen -d -v DEVICE_METADATA.localhost.subtype | tr [:upper:] [:lower:])" == *"dualtor"* ]] &&
11+
[[ $(show mux status | grep active | wc -l) > 0 ]];
12+
then
13+
logger -t TSA -p user.info "Toggle all mux mode to standby"
14+
sudo config mux mode standby all
15+
fi
16+
17+
/usr/bin/TS TSA
18+
echo "Please execute 'config save' to preserve System mode in Maintenance after reboot or config reload"
1019
fi
1120

12-
/usr/bin/TS TSA

dockers/docker-fpm-frr/base_image_files/TSB

+13-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
#!/bin/bash
22

3-
# toggle the mux to auto if dualtor
4-
if [[ "$(sonic-cfggen -d -v DEVICE_METADATA.localhost.subtype | tr [:upper:] [:lower:])" == *"dualtor"* ]];
5-
then
6-
logger -t TSB -p user.info "Toggle all mux mode to auto"
7-
sudo config mux mode auto all
3+
if [[ "$(sonic-cfggen -d -v BGP_DEVICE_GLOBAL.STATE.tsa_enabled)" == "false" ]]; then
4+
echo "System is already in Normal mode"
5+
logger -t TSB -p user.info "System is already in Normal mode"
6+
else
7+
# toggle the mux to auto if dualtor
8+
if [[ "$(sonic-cfggen -d -v DEVICE_METADATA.localhost.subtype | tr [:upper:] [:lower:])" == *"dualtor"* ]];
9+
then
10+
logger -t TSB -p user.info "Toggle all mux mode to auto"
11+
sudo config mux mode auto all
12+
fi
13+
14+
/usr/bin/TS TSB
15+
echo "Please execute 'config save' to preserve System mode in Normal state after reboot or config reload"
816
fi
917

10-
/usr/bin/TS TSB

files/build_templates/init_cfg.json.j2

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
"POLL_INTERVAL": "10000"
2828
}
2929
},
30+
"BGP_DEVICE_GLOBAL": {
31+
"STATE": {
32+
"tsa_enabled": "false"
33+
}
34+
},
3035
{%- set features = [("bgp", "enabled", false, "enabled"),
3136
("database", "always_enabled", false, "always_enabled"),
3237
("lldp", "enabled", true, "enabled"),

src/sonic-bgpcfgd/bgpcfgd/main.py

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from .managers_setsrc import ZebraSetSrc
1919
from .managers_static_rt import StaticRouteMgr
2020
from .managers_rm import RouteMapMgr
21+
from .managers_device_global import DeviceGlobalCfgMgr
2122
from .runner import Runner, signal_handler
2223
from .template import TemplateFabric
2324
from .utils import read_constants
@@ -64,6 +65,8 @@ def do_work():
6465
# Route Advertisement Managers
6566
AdvertiseRouteMgr(common_objs, "STATE_DB", swsscommon.STATE_ADVERTISE_NETWORK_TABLE_NAME),
6667
RouteMapMgr(common_objs, "APPL_DB", swsscommon.APP_BGP_PROFILE_TABLE_NAME),
68+
# Device Global Manager
69+
DeviceGlobalCfgMgr(common_objs, "CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME),
6770
]
6871
runner = Runner(common_objs['cfg_mgr'])
6972
for mgr in managers:
@@ -96,3 +99,4 @@ def main():
9699
sys.exit(rc)
97100
except SystemExit:
98101
os._exit(rc)
102+

src/sonic-bgpcfgd/bgpcfgd/managers_bgp.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from .manager import Manager
99
from .template import TemplateFabric
1010
from .utils import run_command
11+
from .managers_device_global import DeviceGlobalCfgMgr
1112

1213

1314
class BGPPeerGroupMgr(object):
@@ -23,6 +24,7 @@ def __init__(self, common_objs, base_template):
2324
tf = common_objs['tf']
2425
self.policy_template = tf.from_file(base_template + "policies.conf.j2")
2526
self.peergroup_template = tf.from_file(base_template + "peer-group.conf.j2")
27+
self.device_global_cfgmgr = DeviceGlobalCfgMgr(common_objs, "CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME)
2628

2729
def update(self, name, **kwargs):
2830
"""
@@ -56,14 +58,15 @@ def update_pg(self, name, **kwargs):
5658
"""
5759
try:
5860
pg = self.peergroup_template.render(**kwargs)
61+
tsa_rm = self.device_global_cfgmgr.check_state_and_get_tsa_routemaps(pg)
5962
except jinja2.TemplateError as e:
6063
log_err("Can't render peer-group template: '%s': %s" % (name, str(e)))
6164
return False
6265

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

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
from .manager import Manager
2+
from .log import log_err, log_debug, log_notice
3+
import re
4+
from swsscommon import swsscommon
5+
6+
class DeviceGlobalCfgMgr(Manager):
7+
"""This class responds to change in device-specific state"""
8+
9+
def __init__(self, common_objs, db, table):
10+
"""
11+
Initialize the object
12+
:param common_objs: common object dictionary
13+
:param db: name of the db
14+
:param table: name of the table in the db
15+
"""
16+
self.directory = common_objs['directory']
17+
self.cfg_mgr = common_objs['cfg_mgr']
18+
self.constants = common_objs['constants']
19+
self.tsa_template = common_objs['tf'].from_file("bgpd/tsa/bgpd.tsa.isolate.conf.j2")
20+
self.tsb_template = common_objs['tf'].from_file("bgpd/tsa/bgpd.tsa.unisolate.conf.j2")
21+
super(DeviceGlobalCfgMgr, self).__init__(
22+
common_objs,
23+
[],
24+
db,
25+
table,
26+
)
27+
28+
def set_handler(self, key, data):
29+
log_debug("DeviceGlobalCfgMgr:: set handler")
30+
""" Handle device tsa_enabled state change """
31+
if not data:
32+
log_err("DeviceGlobalCfgMgr:: data is None")
33+
return False
34+
35+
if "tsa_enabled" in data:
36+
self.cfg_mgr.commit()
37+
self.cfg_mgr.update()
38+
self.isolate_unisolate_device(data["tsa_enabled"])
39+
self.directory.put(self.db_name, self.table_name, "tsa_enabled", data["tsa_enabled"])
40+
return True
41+
return False
42+
43+
def del_handler(self, key):
44+
log_debug("DeviceGlobalCfgMgr:: del handler")
45+
return True
46+
47+
def check_state_and_get_tsa_routemaps(self, cfg):
48+
""" API to get TSA route-maps if device is isolated"""
49+
cmd = ""
50+
if self.directory.path_exist("CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME, "tsa_enabled"):
51+
tsa_status = self.directory.get_slot("CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME)["tsa_enabled"]
52+
if tsa_status == "true":
53+
cmds = cfg.replace("#012", "\n").split("\n")
54+
log_notice("DeviceGlobalCfgMgr:: Device is isolated. Applying TSA route-maps")
55+
cmd = self.get_ts_routemaps(cmds, self.tsa_template)
56+
return cmd
57+
58+
def isolate_unisolate_device(self, tsa_status):
59+
""" API to get TSA/TSB route-maps and apply configuration"""
60+
cmd = "\n"
61+
if tsa_status == "true":
62+
log_notice("DeviceGlobalCfgMgr:: Device isolated. Executing TSA")
63+
cmd += self.get_ts_routemaps(self.cfg_mgr.get_text(), self.tsa_template)
64+
else:
65+
log_notice("DeviceGlobalCfgMgr:: Device un-isolated. Executing TSB")
66+
cmd += self.get_ts_routemaps(self.cfg_mgr.get_text(), self.tsb_template)
67+
68+
self.cfg_mgr.push(cmd)
69+
log_debug("DeviceGlobalCfgMgr::Done")
70+
71+
def get_ts_routemaps(self, cmds, ts_template):
72+
if not cmds:
73+
return ""
74+
75+
route_map_names = self.__extract_out_route_map_names(cmds)
76+
return self.__generate_routemaps_from_template(route_map_names, ts_template)
77+
78+
def __generate_routemaps_from_template(self, route_map_names, template):
79+
cmd = "\n"
80+
for rm in sorted(route_map_names):
81+
if "_INTERNAL_" in rm:
82+
continue
83+
if "V4" in rm:
84+
ipv="V4" ; ipp="ip"
85+
elif "V6" in rm:
86+
ipv="V6" ; ipp="ipv6"
87+
else:
88+
continue
89+
cmd += template.render(route_map_name=rm,ip_version=ipv,ip_protocol=ipp, constants=self.constants)
90+
cmd += "\n"
91+
return cmd
92+
93+
def __extract_out_route_map_names(self, cmds):
94+
route_map_names = set()
95+
out_route_map = re.compile(r'^\s*neighbor \S+ route-map (\S+) out$')
96+
for line in cmds:
97+
result = out_route_map.match(line)
98+
if result:
99+
route_map_names.add(result.group(1))
100+
return route_map_names
101+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
!
2+
! template: bgpd/templates/general/peer-group.conf.j2
3+
!
4+
neighbor PEER_V4 peer-group
5+
neighbor PEER_V6 peer-group
6+
address-family ipv4
7+
neighbor PEER_V4 allowas-in 1
8+
neighbor PEER_V4 soft-reconfiguration inbound
9+
neighbor PEER_V4 route-map FROM_BGP_PEER_V4 in
10+
neighbor PEER_V4 route-map TO_BGP_PEER_V4 out
11+
exit-address-family
12+
address-family ipv6
13+
neighbor PEER_V6 allowas-in 1
14+
neighbor PEER_V6 soft-reconfiguration inbound
15+
neighbor PEER_V6 route-map FROM_BGP_PEER_V6 in
16+
neighbor PEER_V6 route-map TO_BGP_PEER_V6 out
17+
exit-address-family
18+
!
19+
! end of template: bgpd/templates/general/peer-group.conf.j2
20+
!
21+
22+
23+
route-map TO_BGP_PEER_V4 permit 20
24+
match ip address prefix-list PL_LoopbackV4
25+
set community 12345:12345
26+
route-map TO_BGP_PEER_V4 deny 30
27+
!
28+
route-map TO_BGP_PEER_V6 permit 20
29+
match ipv6 address prefix-list PL_LoopbackV6
30+
set community 12345:12345
31+
route-map TO_BGP_PEER_V6 deny 30
32+
!
33+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
!
2+
! template: bgpd/templates/general/peer-group.conf.j2
3+
!
4+
neighbor PEER_V4 peer-group
5+
neighbor PEER_V6 peer-group
6+
address-family ipv4
7+
neighbor PEER_V4 allowas-in 1
8+
neighbor PEER_V4 soft-reconfiguration inbound
9+
neighbor PEER_V4 route-map FROM_BGP_PEER_V4 in
10+
neighbor PEER_V4 route-map TO_BGP_PEER_V4 out
11+
exit-address-family
12+
address-family ipv6
13+
neighbor PEER_V6 allowas-in 1
14+
neighbor PEER_V6 soft-reconfiguration inbound
15+
neighbor PEER_V6 route-map FROM_BGP_PEER_V6 in
16+
neighbor PEER_V6 route-map TO_BGP_PEER_V6 out
17+
exit-address-family
18+
!
19+
! end of template: bgpd/templates/general/peer-group.conf.j2
20+
!
21+
22+
23+
no route-map TO_BGP_PEER_V4 permit 20
24+
no route-map TO_BGP_PEER_V4 deny 30
25+
!
26+
no route-map TO_BGP_PEER_V6 permit 20
27+
no route-map TO_BGP_PEER_V6 deny 30
28+
!
29+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
route-map TO_BGP_PEER_V4 permit 20
3+
match ip address prefix-list PL_LoopbackV4
4+
set community 12345:12345
5+
route-map TO_BGP_PEER_V4 deny 30
6+
!
7+
route-map TO_BGP_PEER_V6 permit 20
8+
match ipv6 address prefix-list PL_LoopbackV6
9+
set community 12345:12345
10+
route-map TO_BGP_PEER_V6 deny 30
11+
!
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
no route-map TO_BGP_PEER_V4 permit 20
3+
no route-map TO_BGP_PEER_V4 deny 30
4+
!
5+
no route-map TO_BGP_PEER_V6 permit 20
6+
no route-map TO_BGP_PEER_V6 deny 30
7+
!

0 commit comments

Comments
 (0)