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

Sonic t2 support for radian #21732

Merged
merged 10 commits into from
Feb 22, 2025
Merged
Show file tree
Hide file tree
Changes from 5 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
178 changes: 178 additions & 0 deletions dockers/docker-fpm-frr/base_image_files/prefix_list
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#!/bin/bash

# Function to display help message
display_help() {
echo "Usage: sudo prefix-list <command> <PREFIX_TYPE> <NETWORK>"
echo ""
echo "Commands:"
echo " add Add a prefix with prefix type and network."
echo " Requires: <PREFIX_TYPE>, <NETWORK>."
echo ""
echo " remove Remove a prefix with prefix type and network."
echo " Requires: <PREFIX_TYPE>, <NETWORK>."
echo ""
echo " status Display current prefix lists."
echo " No additional parameters required."
echo ""
echo "Arguments:"
echo " <PREFIX_TYPE> Type of prefix list. Allowed values: {$(IFS='|'; echo "${supported_prefix_types[*]}")}."
echo " <NETWORK> Network in CIDR format."
echo ""
echo "Options:"
echo " -h, --help Display this help message."
exit 0
}


# Function to check if the user has root privileges
check_root_privileges() {
if [ "$EUID" -ne 0 ] ; then
echo "Root privileges are needed for this operation." >&2
exit 1
fi
}

# Function to check if the device is supported device with type spine routers and subtype UpstreamLC
check_spine_router() {
type=$(sonic-cfggen -d -v DEVICE_METADATA.localhost.type)
sub_type=$(sonic-cfggen -d -v DEVICE_METADATA.localhost.sub_type)

# only supported on spine routers and UpstreamLC
if [[ "$type" != "SpineRouter" || "$sub_type" != "UpstreamLC" ]]; then
echo "Operation is only supported on UpstreamLC of SpineRouter." >&2
exit 1
fi
}

# Function to skip operation on chassis supervisor
skip_chassis_supervisor() {
if [ -f /etc/sonic/chassisdb.conf ]; then
echo "Skipping Operation on chassis supervisor"
exit 0
fi
}

# Function to validate the operation and prefix type parameters
validate_operation() {
local valid_operation=false
local valid_prefix_type=false

for operation in "${prefix_list_operations[@]}"; do
if [[ "$1" == "$operation" ]]; then
valid_operation=true
break
fi
done

if [ $valid_operation == false ]; then
echo "Invalid parameter $1, Operation not supported" >&2
echo ""
display_help
exit 1
fi

# Check if the prefix type is supported or not if the operation is not status
if [ $1 != "status" ]; then
for prefix_type in "${supported_prefix_types[@]}"; do
if [[ "$2" == "$prefix_type" ]]; then
valid_prefix_type=true
break
fi
done

if [ $valid_prefix_type == false ]; then
echo "Invalid parameter $2, Prefix type not supported" >&2
echo ""
display_help
exit 1
fi
fi
}

# Function to handle prefix list operations for a specific ASIC
handle_prefix_list_asic() {
local asic=$1
local operation=$2
local PREFIX_TYPE=$3
local network=$4
local namespace_prefix='asic'

if [ $operation == 'status' ] ; then
echo "BGP$asic: Current prefix lists:"
sonic-cfggen -d -v PREFIX_LIST -n $namespace_prefix$asic
else
if [ $operation == 'add' ]; then
local prefix_list_entry="{\"PREFIX_LIST\":{\"$PREFIX_TYPE|$network\":{}}}"
sonic-cfggen -a "$prefix_list_entry" -w -n $namespace_prefix$asic
logger -t $operation -p user.info "Added prefix list: $PREFIX_TYPE with network: $network"
echo "BGP$asic: Added prefix list: $PREFIX_TYPE with network: $network"
elif [ $operation == 'remove' ]; then
sonic-db-cli -n $namespace_prefix$asic CONFIG_DB DEL "PREFIX_LIST|$PREFIX_TYPE|$network"
logger -t $operation -p user.info "Removed prefix list: $PREFIX_TYPE with network: $network"
echo "BGP$asic: Removed prefix list: $PREFIX_TYPE with network: $network"
fi
fi
}

# Function to handle prefix list operations for a single ASIC
handle_prefix_list_single() {
local operation=$1
local PREFIX_TYPE=$2
local network=$3

if [ $operation == 'status' ] ; then
echo "Current prefix lists:"
sonic-cfggen -d -v PREFIX_LIST
else
if [ $operation == 'add' ]; then
local prefix_list_entry="{\"PREFIX_LIST\":{\"$PREFIX_TYPE|$network\":{}}}"
sonic-cfggen -a "$prefix_list_entry" -w
logger -t $operation -p user.info "Added prefix list: $PREFIX_TYPE with network: $network"
echo "Added prefix list: $PREFIX_TYPE with network: $network"
elif [ $operation == 'remove' ]; then
sonic-db-cli CONFIG_DB DEL "PREFIX_LIST|$PREFIX_TYPE|$network"
logger -t $operation -p user.info "Removed prefix list: $PREFIX_TYPE with network: $network"
echo "Removed prefix list: $PREFIX_TYPE with network: $network"
fi
fi
}

prefix_list_operations=("add" "remove" "status")
supported_prefix_types=("ANCHOR_PREFIX")
# Main script execution
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
display_help
fi

check_root_privileges
check_spine_router
skip_chassis_supervisor

validate_operation $1 $2

# 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
while [ $asic -lt $NUM_ASIC ]
do
sub_role=`sonic-cfggen -d -v "DEVICE_METADATA['localhost']['sub_role']" -n asic$asic`
if [ $sub_role == 'FrontEnd' ]; then
handle_prefix_list_asic $asic $1 $2 $3
fi
asic=$((asic+1))
done
else
handle_prefix_list_single $1 $2 $3
fi

if [ $1 != 'status' ]; then
echo "Please execute 'sudo config save' to preserve prefix list after reboot or config reload"
fi
11 changes: 11 additions & 0 deletions dockers/docker-fpm-frr/frr/bgpd/radian/add_radian.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{{ data.ipv }} prefix-list ANCHOR_CONTRIBUTING_ROUTES permit {{ data.prefix }} ge 48
{# #}
router bgp {{ data.bgp_asn }}
{% if data.ipv == 'ip' -%}
address-family ipv4 unicast
{% else -%}
address-family ipv6 unicast
{% endif %}
aggregate-address {{ data.prefix }} route-map TAG_ANCHOR_COMMUNITY
exit
exit
10 changes: 10 additions & 0 deletions dockers/docker-fpm-frr/frr/bgpd/radian/del_radian.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
no {{ data.ipv }} prefix-list ANCHOR_CONTRIBUTING_ROUTES permit {{ data.prefix }} ge 48
router bgp {{ data.bgp_asn }}
{% if data.ipv == 'ip' -%}
address-family ipv4 unicast
{% else %}
address-family ipv6 unicast
{% endif -%}
no aggregate-address {{ data.prefix }} route-map TAG_ANCHOR_COMMUNITY
exit
exit
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
!
! template: bgpd/templates/voq_chassis/policies.conf.j2
!
bgp community-list standard LOCAL_ANCHOR_ROUTE_COMMUNITY permit {{ constants.bgp.local_anchor_route_community }}
bgp community-list standard DEVICE_INTERNAL_COMMUNITY permit {{ constants.bgp.internal_community }}
bgp community-list standard DEVICE_INTERNAL_FALLBACK_COMMUNITY permit {{ constants.bgp.internal_fallback_community }}
bgp community-list standard NO_EXPORT permit no-export
Expand Down Expand Up @@ -31,6 +32,9 @@ route-map TO_VOQ_CHASSIS_V4_PEER permit 1
match ip address prefix-list PL_LoopbackV4
set community {{ constants.bgp.internal_community }}
!
route-map TO_VOQ_CHASSIS_V4_PEER deny 15
match community LOCAL_ANCHOR_ROUTE_COMMUNITY
!
route-map TO_VOQ_CHASSIS_V4_PEER permit 100
!
route-map FROM_VOQ_CHASSIS_V6_PEER permit 1
Expand Down Expand Up @@ -63,6 +67,9 @@ route-map TO_VOQ_CHASSIS_V6_PEER permit 1
match ipv6 address prefix-list PL_LoopbackV6
set community {{ constants.bgp.internal_community }}
!
route-map TO_VOQ_CHASSIS_V6_PEER deny 15
match community LOCAL_ANCHOR_ROUTE_COMMUNITY
!
route-map TO_VOQ_CHASSIS_V6_PEER permit 100
!
! end of template: bgpd/templates/voq_chassis/policies.conf.j2
Expand Down
1 change: 1 addition & 0 deletions files/image_config/constants/constants.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ constants:
internal_fallback_community: 22222:22222
sentinel_community: 12345:12346
internal_community_match_tag: 201
local_anchor_route_community: 12345:555
route_do_not_send_appdb_tag: 202
route_eligible_for_fallback_to_default_tag: 203
families:
Expand Down
1 change: 1 addition & 0 deletions rules/docker-fpm-frr.mk
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ $(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
$(DOCKER_FPM_FRR)_BASE_IMAGE_FILES += prefix_list:/usr/bin/prefix_list

SONIC_BOOKWORM_DOCKERS += $(DOCKER_FPM_FRR)
SONIC_BOOKWORM_DBG_DOCKERS += $(DOCKER_FPM_FRR_DBG)
5 changes: 4 additions & 1 deletion src/sonic-bgpcfgd/bgpcfgd/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from .managers_chassis_app_db import ChassisAppDbMgr
from .managers_bfd import BfdMgr
from .managers_srv6 import SRv6Mgr
from .managers_prefix_list import PrefixListMgr
from .static_rt_timer import StaticRouteTimer
from .runner import Runner, signal_handler
from .template import TemplateFabric
Expand Down Expand Up @@ -79,7 +80,9 @@ def do_work():
DeviceGlobalCfgMgr(common_objs, "CONFIG_DB", swsscommon.CFG_BGP_DEVICE_GLOBAL_TABLE_NAME),
# SRv6 Manager
SRv6Mgr(common_objs, "CONFIG_DB", "SRV6_MY_SIDS"),
SRv6Mgr(common_objs, "CONFIG_DB", "SRV6_MY_LOCATORS")
SRv6Mgr(common_objs, "CONFIG_DB", "SRV6_MY_LOCATORS"),
# Prefix List Manager
PrefixListMgr(common_objs, "CONFIG_DB", "PREFIX_LIST")
]

if device_info.is_chassis():
Expand Down
113 changes: 113 additions & 0 deletions src/sonic-bgpcfgd/bgpcfgd/managers_prefix_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
from .manager import Manager
from .log import log_debug, log_warn, log_info
from swsscommon import swsscommon
import netaddr

class PrefixListMgr(Manager):
"""This class responds to changes in the PREFIX_LIST table"""

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.templates = {
"add_radian": common_objs['tf'].from_file("bgpd/radian/add_radian.conf.j2"),
"del_radian": common_objs['tf'].from_file("bgpd/radian/del_radian.conf.j2"),
}
super(PrefixListMgr, self).__init__(
common_objs,
[],
db,
table,
)

def generate_prefix_list_config(self, data, add):
"""
Generate the prefix list configuration from the template
:param data: data from the PREFIX_LIST table
:return: rendered configuration
"""
cmd = "\n"
metadata = self.directory.get_slot("CONFIG_DB", swsscommon.CFG_DEVICE_METADATA_TABLE_NAME)["localhost"]
bgp_asn = metadata["bgp_asn"]
localhost_type = metadata["type"]
subtype = metadata["subtype"]

if data["prefix_list_name"] != "ANCHOR_PREFIX":
log_warn("PrefixListMgr:: Prefix list %s is not supported" % data["prefix_list_name"])
return
if localhost_type != "SpineRouter" or subtype != "UpstreamLC":
log_warn("PrefixListMgr:: Prefix list %s is only supported on UpstreamLC of SpineRouter" % data["prefix_list_name"])
return

# Add the anchor prefix to the radian configuration
data["bgp_asn"] = bgp_asn
if add:
# add some way of getting this asn list from the database in the future
cmd += self.templates["add_radian"].render(data=data)
log_debug("PrefixListMgr:: Anchor prefix %s added to radian configuration" % data["prefix"])
else:
cmd += self.templates["del_radian"].render(data=data)
log_debug("PrefixListMgr:: Anchor prefix %s removed from radian configuration" % data["prefix"])
self.cfg_mgr.push(cmd)



def set_handler(self, key, data):
log_debug("PrefixListMgr:: set handler")
if '|' in key:
prefix_list_name, prefix_str = key.split('|', 1)
try:
prefix = netaddr.IPNetwork(str(prefix_str))
except (netaddr.NotRegisteredError, netaddr.AddrFormatError, netaddr.AddrConversionError):
log_warn("PrefixListMgr:: Prefix '%s' format is wrong for prefix list '%s'" % (prefix_str, prefix_list_name))
return True
data["prefix_list_name"] = prefix_list_name
data["prefix"] = str(prefix.cidr)
data["ipv"] = self.get_ip_type(prefix)
# Generate the prefix list configuration
self.generate_prefix_list_config(data, add=True)
log_info("PrefixListMgr:: %s %s configuration generated" % (prefix_list_name, data["prefix"]))

self.directory.put(self.db_name, self.table_name, key, data)
log_info("PrefixListMgr:: set %s" % key)
return True

def del_handler(self, key):
log_debug("PrefixListMgr:: del handler")
if '|' in key:
prefix_list_name, prefix_str = key.split('|', 1)
try:
prefix = netaddr.IPNetwork(str(prefix_str))
except (netaddr.NotRegisteredError, netaddr.AddrFormatError, netaddr.AddrConversionError):
log_warn("PrefixListMgr:: Prefix '%s' format is wrong for prefix list '%s'" % (prefix_str, prefix_list_name))
return True
data = {}
data["prefix_list_name"] = prefix_list_name
data["prefix"] = str(prefix.cidr)
data["ipv"] = self.get_ip_type(prefix)
self.generate_prefix_list_config(data, add=False)
log_info("PrefixListMgr:: %s %s configuration deleted" % (prefix_list_name, data["prefix"]))
self.directory.remove(self.db_name, self.table_name, key)
log_info("PrefixListMgr:: deleted %s" % key)
# Implement deletion logic if necessary
return True

def get_ip_type(self, prefix: netaddr.IPNetwork):
"""
Determine the IP type (IPv4 or IPv6) of a prefix.
:param prefix: The prefix to check (e.g., "192.168.1.0/24" or "2001:db8::/32")
:return: "ip" if the prefix is an IPv4 address, "ipv6" if it is an IPv6 address, None if invalid
"""
if prefix.version == 4:
return "ip"
elif prefix.version == 6:
return "ipv6"
else:
return None
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ipv6 prefix-list ANCHOR_CONTRIBUTING_ROUTES permit ffff::/64 ge 48
router bgp 1234
address-family ipv6 unicast
aggregate-address ffff::/64 route-map TAG_ANCHOR_COMMUNITY
exit
exit
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"data": {
"ipv": "ipv6",
"prefix": "ffff::/64",
"bgp_asn": 1234
}
}
Loading
Loading