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 support sequential IDF isolation #19136

Merged
merged 1 commit into from
May 31, 2024
Merged
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
87 changes: 87 additions & 0 deletions dockers/docker-fpm-frr/base_image_files/idf_isolation
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/bin/bash

# Restrict command to sudo users
if [ "$EUID" -ne 0 ] ; then
echo "Root priveleges are needed for this operation"
exit 1
fi

# Command is only supported on spine routers
if [[ "$(sonic-cfggen -d -v DEVICE_METADATA.localhost.type)" != *"SpineRouter"* ]] ; then
echo "Operation is not supported on this platform"
exit 1
fi

# Skip operation on chassis supervisor
if [ -f /etc/sonic/chassisdb.conf ]; then
echo "Skipping Operation on chassis supervisor"
exit 0
fi

idf_isolation_states=("isolated_no_export" "isolated_withdraw_all" "unisolated" "status")
valid=false
for state in "${idf_isolation_states[@]}"; do
if [[ "$1" == "$state" ]]; then
valid=true
break
fi
done
if [ $valid == false ]; then
echo "Invalid parameter $1, Operation not supported"
echo ""
echo "Usage: sudo idf_isolation <isolated_no_export|isolated_withdraw_all|unisolated|status>"
exit 0
fi

IDF_ISOLATION_STATE="{\"BGP_DEVICE_GLOBAL\":{\"STATE\":{\"idf_isolation_state\": \"$1\"}}}"

# read SONiC immutable variables
[ -f /etc/sonic/sonic-environment ] && . /etc/sonic/sonic-environment

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

# Parse the device specific asic conf file, if it exists
ASIC_CONF=/usr/share/sonic/device/$PLATFORM/asic.conf
[ -f $ASIC_CONF ] && . $ASIC_CONF

if [[ ($NUM_ASIC -gt 1) ]]; then
asic=0
NAMESPACE_PREFIX='asic'

while [ $asic -lt $NUM_ASIC ]
do
sub_role=`sonic-cfggen -d -v "DEVICE_METADATA['localhost']['sub_role']" -n $NAMESPACE_PREFIX$asic`
if [ $sub_role == 'FrontEnd' ] ; then
cur_idf_isolation_state="$(sonic-cfggen -d -v BGP_DEVICE_GLOBAL.STATE.idf_isolation_state -n $NAMESPACE_PREFIX$asic)"
if [ $1 == 'status' ] ; then
echo "BGP$asic: IDF isolation state: $cur_idf_isolation_state"
else
if [ $1 == $cur_idf_isolation_state ]; then
echo "BGP$asic: IDF is already in $1 state"
else
sonic-cfggen -a "$IDF_ISOLATION_STATE" -w -n $NAMESPACE_PREFIX$asic
logger -t $1 -p user.info "IDF isolation state: $1"
echo "BGP$asic: IDF isolation state: $1"
fi
fi
fi
asic=$[$asic+1]
done
else
cur_idf_isolation_state="$(sonic-cfggen -d -v BGP_DEVICE_GLOBAL.STATE.idf_isolation_state)"
if [ $1 == 'status' ] ; then
echo "IDF isolation state: $cur_idf_isolation_state"
else
if [ $1 == $cur_idf_isolation_state ]; then
echo "IDF is already in $1 state"
else
sonic-cfggen -a "$IDF_ISOLATION_STATE" -w
logger -t $1 -p user.info "IDF isolation state: $1"
echo "IDF isolation state: $1"
fi
fi
fi

if [ $1 != 'status' ]; then
echo "Please execute 'sudo config save' to preserve IDF isolation state after reboot or config reload"
fi
20 changes: 20 additions & 0 deletions dockers/docker-fpm-frr/frr/bgpd/idf_isolate/idf_isolate.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
route-map CHECK_IDF_ISOLATION permit 1
match ip address prefix-list PL_LoopbackV4
set community {{ constants.bgp.traffic_shift_community }}
route-map CHECK_IDF_ISOLATION permit 2
match ipv6 address prefix-list PL_LoopbackV6
set community {{ constants.bgp.traffic_shift_community }}
route-map CHECK_IDF_ISOLATION permit 3
match tag {{ constants.bgp.internal_community_match_tag }}
set community {{ constants.bgp.traffic_shift_community }}
{# #}
{%- if isolation_status == "isolated_withdraw_all" -%}
route-map CHECK_IDF_ISOLATION deny 4
route-map CHECK_IDF_ISOLATION permit 10
no set community no-export additive{# Added to clean up state, in case of transition from isolated_no_export (not expected) #}
{%- elif isolation_status == "isolated_no_export" -%}
route-map CHECK_IDF_ISOLATION permit 10
set community no-export additive
no route-map CHECK_IDF_ISOLATION deny 4{# Added to clean up state, in case of transition from isolated_withdraw_all (not expected) #}
{# #}
{%- endif -%}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
no route-map CHECK_IDF_ISOLATION permit 1
no route-map CHECK_IDF_ISOLATION permit 2
no route-map CHECK_IDF_ISOLATION permit 3
no route-map CHECK_IDF_ISOLATION deny 4
route-map CHECK_IDF_ISOLATION permit 10
no set community no-export additive
1 change: 1 addition & 0 deletions rules/docker-fpm-frr.mk
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ $(DOCKER_FPM_FRR)_BASE_IMAGE_FILES += TSA:/usr/bin/TSA
$(DOCKER_FPM_FRR)_BASE_IMAGE_FILES += TSB:/usr/bin/TSB
$(DOCKER_FPM_FRR)_BASE_IMAGE_FILES += TSC:/usr/bin/TSC
$(DOCKER_FPM_FRR)_BASE_IMAGE_FILES += TS:/usr/bin/TS
$(DOCKER_FPM_FRR)_BASE_IMAGE_FILES += idf_isolation:/usr/bin/idf_isolation

SONIC_BULLSEYE_DOCKERS += $(DOCKER_FPM_FRR)
SONIC_BULLSEYE_DBG_DOCKERS += $(DOCKER_FPM_FRR_DBG)
6 changes: 4 additions & 2 deletions src/sonic-bgpcfgd/bgpcfgd/managers_bgp.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,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)
idf_isolation_rm = self.device_global_cfgmgr.check_state_and_get_idf_isolation_routemaps()
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 + tsa_rm
cmd = ('router bgp %s\n' % kwargs['bgp_asn']) + pg + tsa_rm + idf_isolation_rm
else:
cmd = ('router bgp %s vrf %s\n' % (kwargs['bgp_asn'], kwargs['vrf'])) + pg + tsa_rm
cmd = ('router bgp %s vrf %s\n' % (kwargs['bgp_asn'], kwargs['vrf'])) + pg + tsa_rm + idf_isolation_rm
self.update_entity(cmd, "Peer-group for peer '%s'" % name)
return True

Expand Down Expand Up @@ -108,6 +109,7 @@ def __init__(self, common_objs, db_name, table_name, peer_type, check_neig_meta)
("CONFIG_DB", swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, "localhost/bgp_asn"),
("CONFIG_DB", swsscommon.CFG_LOOPBACK_INTERFACE_TABLE_NAME, "Loopback0"),
("CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME, "tsa_enabled"),
("CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME, "idf_isolation_state"),
("LOCAL", "local_addresses", ""),
("LOCAL", "interfaces", ""),
]
Expand Down
51 changes: 46 additions & 5 deletions src/sonic-bgpcfgd/bgpcfgd/managers_device_global.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ def __init__(self, common_objs, db, table):
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")
self.idf_isolate_template = common_objs['tf'].from_file("bgpd/idf_isolate/idf_isolate.conf.j2")
self.idf_unisolate_template = common_objs['tf'].from_file("bgpd/idf_isolate/idf_unisolate.conf.j2")
self.directory.subscribe([("CONFIG_DB", swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, "localhost/switch_type"),], self.on_switch_type_change)
super(DeviceGlobalCfgMgr, self).__init__(
common_objs,
Expand All @@ -42,13 +44,31 @@ def set_handler(self, key, data):
log_err("DeviceGlobalCfgMgr:: data is None")
return False

tsa_status = "false"
idf_isolation_state = "unisolated"

if self.directory.path_exist("CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME, "tsa_enabled"):
tsa_status = self.directory.get_slot("CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME)["tsa_enabled"]
if self.directory.path_exist("CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME, "idf_isolation_state"):
idf_isolation_state = self.directory.get_slot("CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME)["idf_isolation_state"]

if "tsa_enabled" in data:
self.cfg_mgr.commit()
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
if tsa_status != data["tsa_enabled"]:
self.cfg_mgr.commit()
self.cfg_mgr.update()
self.isolate_unisolate_device(data["tsa_enabled"])


if "idf_isolation_state" in data:
self.directory.put(self.db_name, self.table_name, "idf_isolation_state", data["idf_isolation_state"])
if idf_isolation_state != data["idf_isolation_state"]:
if self.switch_type and self.switch_type != "SpineRouter":
log_debug("DeviceGlobalCfgMgr:: Skipping IDF isolation configuration on Switch type: %s" % self.switch_type)
return True
self.downstream_isolate_unisolate(data["idf_isolation_state"])

return True

def del_handler(self, key):
log_debug("DeviceGlobalCfgMgr:: del handler")
Expand Down Expand Up @@ -113,3 +133,24 @@ def __extract_out_route_map_names(self, cmds):
route_map_names.add(result.group(1))
return route_map_names

def downstream_isolate_unisolate(self, idf_isolation_state):
cmd = "\n"
if idf_isolation_state == "unisolated":
cmd += self.idf_unisolate_template.render(constants=self.constants)
log_notice("DeviceGlobalCfgMgr:: IDF un-isolated")
else:
cmd += self.idf_isolate_template.render(isolation_status=idf_isolation_state, constants=self.constants)
log_notice("DeviceGlobalCfgMgr:: IDF isolated, {} policy applied".format(idf_isolation_state))

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

def check_state_and_get_idf_isolation_routemaps(self):
""" API to get TSA route-maps if device is isolated"""
cmd = ""
if self.directory.path_exist("CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME, "idf_isolation_state"):
idf_isolation_state = self.directory.get_slot("CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME)["idf_isolation_state"]
if idf_isolation_state != "unisolated":
log_notice("DeviceGlobalCfgMgr:: IDF is isolated. Applying required route-maps")
cmd = self.idf_isolate_template.render(isolation_status=idf_isolation_state, constants=self.constants)
return cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
!
! 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 CHECK_IDF_ISOLATION permit 1
match ip address prefix-list PL_LoopbackV4
set community 12345:12345
route-map CHECK_IDF_ISOLATION permit 2
match ipv6 address prefix-list PL_LoopbackV6
set community 12345:12345
route-map CHECK_IDF_ISOLATION permit 3
match tag 1001
set community 12345:12345
route-map CHECK_IDF_ISOLATION permit 10
set community no-export additive
no route-map CHECK_IDF_ISOLATION deny 4

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 CHECK_IDF_ISOLATION permit 1
match ip address prefix-list PL_LoopbackV4
set community 12345:12345
route-map CHECK_IDF_ISOLATION permit 2
match ipv6 address prefix-list PL_LoopbackV6
set community 12345:12345
route-map CHECK_IDF_ISOLATION permit 3
match tag 1001
set community 12345:12345
route-map CHECK_IDF_ISOLATION deny 4
route-map CHECK_IDF_ISOLATION permit 10
no set community no-export additive
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
!
! 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 CHECK_IDF_ISOLATION permit 1
no route-map CHECK_IDF_ISOLATION permit 2
no route-map CHECK_IDF_ISOLATION permit 3
no route-map CHECK_IDF_ISOLATION deny 4
route-map CHECK_IDF_ISOLATION permit 10
no set community no-export additive
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
route-map CHECK_IDF_ISOLATION permit 1
match ip address prefix-list PL_LoopbackV4
set community 12345:12345
route-map CHECK_IDF_ISOLATION permit 2
match ipv6 address prefix-list PL_LoopbackV6
set community 12345:12345
route-map CHECK_IDF_ISOLATION permit 3
match tag 1001
set community 12345:12345
route-map CHECK_IDF_ISOLATION permit 10
set community no-export additive
no route-map CHECK_IDF_ISOLATION deny 4
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
route-map CHECK_IDF_ISOLATION permit 1
match ip address prefix-list PL_LoopbackV4
set community 12345:555
route-map CHECK_IDF_ISOLATION permit 2
match ipv6 address prefix-list PL_LoopbackV6
set community 12345:555
route-map CHECK_IDF_ISOLATION permit 3
match tag 1002
set community 12345:555
route-map CHECK_IDF_ISOLATION permit 10
set community no-export additive
no route-map CHECK_IDF_ISOLATION deny 4
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"constants": {
"bgp": {
"traffic_shift_community": "12345:555",
"internal_community_match_tag": "1002"
}
},
"isolation_status": "isolated_no_export"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
route-map CHECK_IDF_ISOLATION permit 1
match ip address prefix-list PL_LoopbackV4
set community 12345:555
route-map CHECK_IDF_ISOLATION permit 2
match ipv6 address prefix-list PL_LoopbackV6
set community 12345:555
route-map CHECK_IDF_ISOLATION permit 3
match tag 1002
set community 12345:555
route-map CHECK_IDF_ISOLATION deny 4
route-map CHECK_IDF_ISOLATION permit 10
no set community no-export additive
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"constants": {
"bgp": {
"traffic_shift_community": "12345:555",
"internal_community_match_tag": "1002"
}
},
"isolation_status": "isolated_withdraw_all"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
no route-map CHECK_IDF_ISOLATION permit 1
no route-map CHECK_IDF_ISOLATION permit 2
no route-map CHECK_IDF_ISOLATION permit 3
no route-map CHECK_IDF_ISOLATION deny 4
route-map CHECK_IDF_ISOLATION permit 10
no set community no-export additive
Loading
Loading