diff --git a/dockers/docker-fpm-frr/frr/bgpd/templates/general/instance.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/templates/general/instance.conf.j2 index 836561e426..123be329a5 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/templates/general/instance.conf.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/templates/general/instance.conf.j2 @@ -1,46 +1,5 @@ -! -! template: bgpd/templates/general/instance.conf.j2 -! - neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} - neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} -{# set the bgp neighbor timers if they have not default values #} -{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60) - or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %} - neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] | default("60") }} {{ bgp_session['holdtime'] | default("180") }} -{% endif %} - neighbor {{ neighbor_addr }} timers connect 10 -! -{% if 'admin_status' in bgp_session and bgp_session['admin_status'] == 'down' or 'admin_status' not in bgp_session and 'default_bgp_status' in CONFIG_DB__DEVICE_METADATA['localhost'] and CONFIG_DB__DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %} - neighbor {{ neighbor_addr }} shutdown -{% endif %} -! -{% if neighbor_addr | ipv4 %} - address-family ipv4 - neighbor {{ neighbor_addr }} peer-group PEER_V4 -! -{% elif neighbor_addr | ipv6 %} - address-family ipv6 - neighbor {{ neighbor_addr }} peer-group PEER_V6 -! -{% endif %} -! -{% if 'rrclient' in bgp_session and bgp_session['rrclient'] | int != 0 %} - neighbor {{ neighbor_addr }} route-reflector-client -{% endif %} -! -{% if 'nhopself' in bgp_session and bgp_session['nhopself'] | int != 0 %} - neighbor {{ neighbor_addr }} next-hop-self -{% endif %} -! - neighbor {{ neighbor_addr }} activate - exit-address-family -! -{% if bgp_session["asn"] == bgp_asn and CONFIG_DB__DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" %} - address-family l2vpn evpn - neighbor {{ neighbor_addr }} activate - advertise-all-vni - exit-address-family -{% endif %} +{% from "bgpd/templates/general/router.j2" import general_routing with context %} +{{ general_routing("instance") }} ! ! end of template: bgpd/templates/general/instance.conf.j2 ! diff --git a/dockers/docker-fpm-frr/frr/bgpd/templates/general/numbered/instance.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/templates/general/numbered/instance.conf.j2 new file mode 100644 index 0000000000..836561e426 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/templates/general/numbered/instance.conf.j2 @@ -0,0 +1,46 @@ +! +! template: bgpd/templates/general/instance.conf.j2 +! + neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} + neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} +{# set the bgp neighbor timers if they have not default values #} +{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60) + or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %} + neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] | default("60") }} {{ bgp_session['holdtime'] | default("180") }} +{% endif %} + neighbor {{ neighbor_addr }} timers connect 10 +! +{% if 'admin_status' in bgp_session and bgp_session['admin_status'] == 'down' or 'admin_status' not in bgp_session and 'default_bgp_status' in CONFIG_DB__DEVICE_METADATA['localhost'] and CONFIG_DB__DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %} + neighbor {{ neighbor_addr }} shutdown +{% endif %} +! +{% if neighbor_addr | ipv4 %} + address-family ipv4 + neighbor {{ neighbor_addr }} peer-group PEER_V4 +! +{% elif neighbor_addr | ipv6 %} + address-family ipv6 + neighbor {{ neighbor_addr }} peer-group PEER_V6 +! +{% endif %} +! +{% if 'rrclient' in bgp_session and bgp_session['rrclient'] | int != 0 %} + neighbor {{ neighbor_addr }} route-reflector-client +{% endif %} +! +{% if 'nhopself' in bgp_session and bgp_session['nhopself'] | int != 0 %} + neighbor {{ neighbor_addr }} next-hop-self +{% endif %} +! + neighbor {{ neighbor_addr }} activate + exit-address-family +! +{% if bgp_session["asn"] == bgp_asn and CONFIG_DB__DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" %} + address-family l2vpn evpn + neighbor {{ neighbor_addr }} activate + advertise-all-vni + exit-address-family +{% endif %} +! +! end of template: bgpd/templates/general/instance.conf.j2 +! diff --git a/dockers/docker-fpm-frr/frr/bgpd/templates/general/numbered/peer-group.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/templates/general/numbered/peer-group.conf.j2 new file mode 100644 index 0000000000..7c7758000a --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/templates/general/numbered/peer-group.conf.j2 @@ -0,0 +1,38 @@ +! +! template: bgpd/templates/general/peer-group.conf.j2 +! + neighbor PEER_V4 peer-group + neighbor PEER_V6 peer-group + address-family ipv4 +{% if CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} + neighbor PEER_V4 allowas-in 1 +{% elif CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'LeafRouter' %} +{% if CONFIG_DB__BGP_BBR['status'] == 'enabled' %} + neighbor PEER_V4 allowas-in 1 +{% endif %} +{% endif %} + 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 +{% if (CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'SpineRouter' and CONFIG_DB__DEVICE_METADATA['localhost']['subtype'] == 'UpstreamLC') or CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'UpperSpineRouter' %} + table-map SELECTIVE_ROUTE_DOWNLOAD_V4 +{% endif %} + exit-address-family + address-family ipv6 +{% if CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} + neighbor PEER_V6 allowas-in 1 +{% elif CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'LeafRouter' %} +{% if CONFIG_DB__BGP_BBR['status'] == 'enabled' %} + neighbor PEER_V6 allowas-in 1 +{% endif %} +{% endif %} + 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 +{% if (CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'SpineRouter' and CONFIG_DB__DEVICE_METADATA['localhost']['subtype'] == 'UpstreamLC') or CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'UpperSpineRouter' %} + table-map SELECTIVE_ROUTE_DOWNLOAD_V6 +{% endif %} + exit-address-family +! +! end of template: bgpd/templates/general/peer-group.conf.j2 +! diff --git a/dockers/docker-fpm-frr/frr/bgpd/templates/general/numbered/policies.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/templates/general/numbered/policies.conf.j2 new file mode 100644 index 0000000000..5305ccd813 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/templates/general/numbered/policies.conf.j2 @@ -0,0 +1,144 @@ +! +! template: bgpd/templates/general/policies.conf.j2 +! +! +ip prefix-list DEFAULT_IPV4 permit 0.0.0.0/0 +ipv6 prefix-list DEFAULT_IPV6 permit ::/0 +! +{% if constants.bgp.allow_list is defined and constants.bgp.allow_list.enabled is defined and constants.bgp.allow_list.enabled and constants.bgp.allow_list.drop_community is defined %} +! +! +! please don't remove. 65535 entries are default rules +! which works when allow_list is enabled, but new configuration +! is not applied +! +{% if allow_list_default_action == 'deny' %} +! +route-map ALLOW_LIST_DEPLOYMENT_ID_0_V4 permit 65535 + set community no-export additive +! +route-map ALLOW_LIST_DEPLOYMENT_ID_0_V6 permit 65535 + set community no-export additive +{% else %} +! +route-map ALLOW_LIST_DEPLOYMENT_ID_0_V4 permit 65535 + set community {{ constants.bgp.allow_list.drop_community }} additive +! +route-map ALLOW_LIST_DEPLOYMENT_ID_0_V6 permit 65535 + set community {{ constants.bgp.allow_list.drop_community }} additive +{% endif %} +! +bgp community-list standard allow_list_default_community permit no-export +bgp community-list standard allow_list_default_community permit {{ constants.bgp.allow_list.drop_community }} +! +route-map FROM_BGP_PEER_V4 permit 10 + call ALLOW_LIST_DEPLOYMENT_ID_0_V4 + on-match next +! +route-map FROM_BGP_PEER_V4 permit 11 + match community allow_list_default_community +{% if CONFIG_DB__DEVICE_METADATA and 'localhost' in CONFIG_DB__DEVICE_METADATA and 'type' in CONFIG_DB__DEVICE_METADATA['localhost'] and 'subtype' in CONFIG_DB__DEVICE_METADATA['localhost'] %} +{% if CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'SpineRouter' and CONFIG_DB__DEVICE_METADATA['localhost']['subtype'] == 'UpstreamLC' %} + on-match next +! +route-map FROM_BGP_PEER_V4 permit 12 + match ip address prefix-list DEFAULT_IPV4 +! +route-map FROM_BGP_PEER_V4 permit 13 +{% if CONFIG_DB__DEVICE_METADATA['localhost']['switch_type'] != 'chassis-packet' %} + set tag {{ constants.bgp.route_do_not_send_appdb_tag }} +{% else %} + set tag {{ constants.bgp.route_eligible_for_fallback_to_default_tag }} +{% endif %} + set community {{ constants.bgp.internal_fallback_community }} additive +{% endif %} +{% endif %} +! +route-map FROM_BGP_PEER_V6 permit 10 + call ALLOW_LIST_DEPLOYMENT_ID_0_V6 + on-match next +! +route-map FROM_BGP_PEER_V6 permit 11 + match community allow_list_default_community +{% if CONFIG_DB__DEVICE_METADATA and 'localhost' in CONFIG_DB__DEVICE_METADATA and 'type' in CONFIG_DB__DEVICE_METADATA['localhost'] and 'subtype' in CONFIG_DB__DEVICE_METADATA['localhost'] %} +{% if CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'SpineRouter' and CONFIG_DB__DEVICE_METADATA['localhost']['subtype'] == 'UpstreamLC' %} + on-match next +! +route-map FROM_BGP_PEER_V6 permit 12 + match ipv6 address prefix-list DEFAULT_IPV6 +! +route-map FROM_BGP_PEER_V6 permit 13 +{% if CONFIG_DB__DEVICE_METADATA['localhost']['switch_type'] != 'chassis-packet' %} + set tag {{ constants.bgp.route_do_not_send_appdb_tag }} +{% else %} + set tag {{ constants.bgp.route_eligible_for_fallback_to_default_tag }} +{% endif %} + set community {{ constants.bgp.internal_fallback_community }} additive +{% endif %} +{% endif %} +! +{% endif %} +! +! +! +route-map FROM_BGP_PEER_V4 permit 100 +! +route-map TO_BGP_PEER_V4 permit 100 + call CHECK_IDF_ISOLATION +! +! +route-map FROM_BGP_PEER_V6 permit 1 + on-match next + set ipv6 next-hop prefer-global +! +route-map FROM_BGP_PEER_V6 permit 100 +! +route-map TO_BGP_PEER_V6 permit 100 + call CHECK_IDF_ISOLATION +! +route-map CHECK_IDF_ISOLATION permit 10 +! +! +! +{% if CONFIG_DB__DEVICE_METADATA and 'localhost' in CONFIG_DB__DEVICE_METADATA and 'type' in CONFIG_DB__DEVICE_METADATA['localhost'] %} +{% if (CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'SpineRouter' and 'subtype' in CONFIG_DB__DEVICE_METADATA['localhost'] and CONFIG_DB__DEVICE_METADATA['localhost']['subtype'] == 'UpstreamLC') or +CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'UpperSpineRouter' %} +bgp community-list standard ANCHOR_ROUTE_COMMUNITY permit {{ constants.bgp.anchor_route_community }} +bgp community-list standard LOCAL_ANCHOR_ROUTE_COMMUNITY permit {{ constants.bgp.local_anchor_route_community }} +bgp community-list standard ANCHOR_CONTRIBUTING_ROUTE_COMMUNITY permit {{ constants.bgp.anchor_contributing_route_community }} +! +route-map SELECTIVE_ROUTE_DOWNLOAD_V4 deny 10 + match community LOCAL_ANCHOR_ROUTE_COMMUNITY +! +route-map SELECTIVE_ROUTE_DOWNLOAD_V4 permit 1000 +! +route-map SELECTIVE_ROUTE_DOWNLOAD_V6 deny 10 + match community LOCAL_ANCHOR_ROUTE_COMMUNITY +! +route-map SELECTIVE_ROUTE_DOWNLOAD_V6 permit 1000 +! +route-map TAG_ANCHOR_COMMUNITY permit 10 + set community {{ constants.bgp.local_anchor_route_community }} {{ constants.bgp.anchor_route_community }} additive +! +route-map TO_BGP_PEER_V6 permit 50 + match ipv6 address prefix-list ANCHOR_CONTRIBUTING_ROUTES + set community {{ constants.bgp.anchor_contributing_route_community }} additive + on-match next +! +route-map TO_BGP_PEER_V6 permit 60 + set comm-list LOCAL_ANCHOR_ROUTE_COMMUNITY delete + on-match next +! +route-map TO_BGP_PEER_V4 permit 50 + match ip address prefix-list ANCHOR_CONTRIBUTING_ROUTES + set community {{ constants.bgp.anchor_contributing_route_community }} additive + on-match next +! +route-map TO_BGP_PEER_V4 permit 60 + set comm-list LOCAL_ANCHOR_ROUTE_COMMUNITY delete + on-match next +! +{% endif %} +{% endif %} +! end of template: bgpd/templates/general/policies.conf.j2 +! diff --git a/dockers/docker-fpm-frr/frr/bgpd/templates/general/peer-group.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/templates/general/peer-group.conf.j2 index 7c7758000a..3f922c2c78 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/templates/general/peer-group.conf.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/templates/general/peer-group.conf.j2 @@ -1,38 +1,5 @@ -! -! template: bgpd/templates/general/peer-group.conf.j2 -! - neighbor PEER_V4 peer-group - neighbor PEER_V6 peer-group - address-family ipv4 -{% if CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} - neighbor PEER_V4 allowas-in 1 -{% elif CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'LeafRouter' %} -{% if CONFIG_DB__BGP_BBR['status'] == 'enabled' %} - neighbor PEER_V4 allowas-in 1 -{% endif %} -{% endif %} - 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 -{% if (CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'SpineRouter' and CONFIG_DB__DEVICE_METADATA['localhost']['subtype'] == 'UpstreamLC') or CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'UpperSpineRouter' %} - table-map SELECTIVE_ROUTE_DOWNLOAD_V4 -{% endif %} - exit-address-family - address-family ipv6 -{% if CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} - neighbor PEER_V6 allowas-in 1 -{% elif CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'LeafRouter' %} -{% if CONFIG_DB__BGP_BBR['status'] == 'enabled' %} - neighbor PEER_V6 allowas-in 1 -{% endif %} -{% endif %} - 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 -{% if (CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'SpineRouter' and CONFIG_DB__DEVICE_METADATA['localhost']['subtype'] == 'UpstreamLC') or CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'UpperSpineRouter' %} - table-map SELECTIVE_ROUTE_DOWNLOAD_V6 -{% endif %} - exit-address-family +{% from "bgpd/templates/general/router.j2" import general_routing with context %} +{{ general_routing("peer-group") }} ! ! end of template: bgpd/templates/general/peer-group.conf.j2 ! diff --git a/dockers/docker-fpm-frr/frr/bgpd/templates/general/policies.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/templates/general/policies.conf.j2 index 5305ccd813..94b5249256 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/templates/general/policies.conf.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/templates/general/policies.conf.j2 @@ -1,144 +1,5 @@ +{% from "bgpd/templates/general/router.j2" import general_routing with context %} +{{ general_routing("policies") }} ! -! template: bgpd/templates/general/policies.conf.j2 -! -! -ip prefix-list DEFAULT_IPV4 permit 0.0.0.0/0 -ipv6 prefix-list DEFAULT_IPV6 permit ::/0 -! -{% if constants.bgp.allow_list is defined and constants.bgp.allow_list.enabled is defined and constants.bgp.allow_list.enabled and constants.bgp.allow_list.drop_community is defined %} -! -! -! please don't remove. 65535 entries are default rules -! which works when allow_list is enabled, but new configuration -! is not applied -! -{% if allow_list_default_action == 'deny' %} -! -route-map ALLOW_LIST_DEPLOYMENT_ID_0_V4 permit 65535 - set community no-export additive -! -route-map ALLOW_LIST_DEPLOYMENT_ID_0_V6 permit 65535 - set community no-export additive -{% else %} -! -route-map ALLOW_LIST_DEPLOYMENT_ID_0_V4 permit 65535 - set community {{ constants.bgp.allow_list.drop_community }} additive -! -route-map ALLOW_LIST_DEPLOYMENT_ID_0_V6 permit 65535 - set community {{ constants.bgp.allow_list.drop_community }} additive -{% endif %} -! -bgp community-list standard allow_list_default_community permit no-export -bgp community-list standard allow_list_default_community permit {{ constants.bgp.allow_list.drop_community }} -! -route-map FROM_BGP_PEER_V4 permit 10 - call ALLOW_LIST_DEPLOYMENT_ID_0_V4 - on-match next -! -route-map FROM_BGP_PEER_V4 permit 11 - match community allow_list_default_community -{% if CONFIG_DB__DEVICE_METADATA and 'localhost' in CONFIG_DB__DEVICE_METADATA and 'type' in CONFIG_DB__DEVICE_METADATA['localhost'] and 'subtype' in CONFIG_DB__DEVICE_METADATA['localhost'] %} -{% if CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'SpineRouter' and CONFIG_DB__DEVICE_METADATA['localhost']['subtype'] == 'UpstreamLC' %} - on-match next -! -route-map FROM_BGP_PEER_V4 permit 12 - match ip address prefix-list DEFAULT_IPV4 -! -route-map FROM_BGP_PEER_V4 permit 13 -{% if CONFIG_DB__DEVICE_METADATA['localhost']['switch_type'] != 'chassis-packet' %} - set tag {{ constants.bgp.route_do_not_send_appdb_tag }} -{% else %} - set tag {{ constants.bgp.route_eligible_for_fallback_to_default_tag }} -{% endif %} - set community {{ constants.bgp.internal_fallback_community }} additive -{% endif %} -{% endif %} -! -route-map FROM_BGP_PEER_V6 permit 10 - call ALLOW_LIST_DEPLOYMENT_ID_0_V6 - on-match next -! -route-map FROM_BGP_PEER_V6 permit 11 - match community allow_list_default_community -{% if CONFIG_DB__DEVICE_METADATA and 'localhost' in CONFIG_DB__DEVICE_METADATA and 'type' in CONFIG_DB__DEVICE_METADATA['localhost'] and 'subtype' in CONFIG_DB__DEVICE_METADATA['localhost'] %} -{% if CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'SpineRouter' and CONFIG_DB__DEVICE_METADATA['localhost']['subtype'] == 'UpstreamLC' %} - on-match next -! -route-map FROM_BGP_PEER_V6 permit 12 - match ipv6 address prefix-list DEFAULT_IPV6 -! -route-map FROM_BGP_PEER_V6 permit 13 -{% if CONFIG_DB__DEVICE_METADATA['localhost']['switch_type'] != 'chassis-packet' %} - set tag {{ constants.bgp.route_do_not_send_appdb_tag }} -{% else %} - set tag {{ constants.bgp.route_eligible_for_fallback_to_default_tag }} -{% endif %} - set community {{ constants.bgp.internal_fallback_community }} additive -{% endif %} -{% endif %} -! -{% endif %} -! -! -! -route-map FROM_BGP_PEER_V4 permit 100 -! -route-map TO_BGP_PEER_V4 permit 100 - call CHECK_IDF_ISOLATION -! -! -route-map FROM_BGP_PEER_V6 permit 1 - on-match next - set ipv6 next-hop prefer-global -! -route-map FROM_BGP_PEER_V6 permit 100 -! -route-map TO_BGP_PEER_V6 permit 100 - call CHECK_IDF_ISOLATION -! -route-map CHECK_IDF_ISOLATION permit 10 -! -! -! -{% if CONFIG_DB__DEVICE_METADATA and 'localhost' in CONFIG_DB__DEVICE_METADATA and 'type' in CONFIG_DB__DEVICE_METADATA['localhost'] %} -{% if (CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'SpineRouter' and 'subtype' in CONFIG_DB__DEVICE_METADATA['localhost'] and CONFIG_DB__DEVICE_METADATA['localhost']['subtype'] == 'UpstreamLC') or -CONFIG_DB__DEVICE_METADATA['localhost']['type'] == 'UpperSpineRouter' %} -bgp community-list standard ANCHOR_ROUTE_COMMUNITY permit {{ constants.bgp.anchor_route_community }} -bgp community-list standard LOCAL_ANCHOR_ROUTE_COMMUNITY permit {{ constants.bgp.local_anchor_route_community }} -bgp community-list standard ANCHOR_CONTRIBUTING_ROUTE_COMMUNITY permit {{ constants.bgp.anchor_contributing_route_community }} -! -route-map SELECTIVE_ROUTE_DOWNLOAD_V4 deny 10 - match community LOCAL_ANCHOR_ROUTE_COMMUNITY -! -route-map SELECTIVE_ROUTE_DOWNLOAD_V4 permit 1000 -! -route-map SELECTIVE_ROUTE_DOWNLOAD_V6 deny 10 - match community LOCAL_ANCHOR_ROUTE_COMMUNITY -! -route-map SELECTIVE_ROUTE_DOWNLOAD_V6 permit 1000 -! -route-map TAG_ANCHOR_COMMUNITY permit 10 - set community {{ constants.bgp.local_anchor_route_community }} {{ constants.bgp.anchor_route_community }} additive -! -route-map TO_BGP_PEER_V6 permit 50 - match ipv6 address prefix-list ANCHOR_CONTRIBUTING_ROUTES - set community {{ constants.bgp.anchor_contributing_route_community }} additive - on-match next -! -route-map TO_BGP_PEER_V6 permit 60 - set comm-list LOCAL_ANCHOR_ROUTE_COMMUNITY delete - on-match next -! -route-map TO_BGP_PEER_V4 permit 50 - match ip address prefix-list ANCHOR_CONTRIBUTING_ROUTES - set community {{ constants.bgp.anchor_contributing_route_community }} additive - on-match next -! -route-map TO_BGP_PEER_V4 permit 60 - set comm-list LOCAL_ANCHOR_ROUTE_COMMUNITY delete - on-match next -! -{% endif %} -{% endif %} ! end of template: bgpd/templates/general/policies.conf.j2 ! diff --git a/dockers/docker-fpm-frr/frr/bgpd/templates/general/router.j2 b/dockers/docker-fpm-frr/frr/bgpd/templates/general/router.j2 new file mode 100644 index 0000000000..b31c7e2468 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/templates/general/router.j2 @@ -0,0 +1,17 @@ +{# router.j2 - dispatch peer-template rendering between numbered (IPv4/IPv6 keyed) + and unnumbered (interface-name keyed) BGP neighbors. + Caller imports `general_routing` and invokes it with the logical template + name (one of: instance, peer-group, policies). The macro selects the + unnumbered sub-template only when `neighbor_addr` is provided AND is not a + valid IPv4/IPv6 address (i.e. it is an interface name). When `neighbor_addr` + is absent the template is rendered in numbered mode, preserving existing + behaviour for legacy code paths and golden tests that render the template + in a per-peer-loop without passing a single neighbor_addr kwarg. #} +{% macro general_routing(template_name) %} +{%- set is_unnumbered = neighbor_addr is defined and not ((neighbor_addr | ipv4) or (neighbor_addr | ipv6)) -%} +{%- if is_unnumbered -%} +{%- include "bgpd/templates/general/unnumbered/" + template_name + ".conf.j2" -%} +{%- else -%} +{%- include "bgpd/templates/general/numbered/" + template_name + ".conf.j2" -%} +{%- endif -%} +{% endmacro %} diff --git a/dockers/docker-fpm-frr/frr/bgpd/templates/general/unnumbered/instance.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/templates/general/unnumbered/instance.conf.j2 new file mode 100644 index 0000000000..e9f51db6aa --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/templates/general/unnumbered/instance.conf.j2 @@ -0,0 +1,39 @@ +! +! template: bgpd/templates/unnumbered/instance.conf.j2 +! +! Renders an unnumbered (IPv6 link-local) BGP neighbor over an interface. +! `neighbor_addr` is an interface name (e.g. PortChannel101), NOT an IP. +! + neighbor {{ neighbor_addr }} interface peer-group PEER_UNNUMBERED + neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} +{% if bgp_session.get('name') %} + neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} +{% endif %} +{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60) + or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %} + neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] | default("60") }} {{ bgp_session['holdtime'] | default("180") }} +{% endif %} + neighbor {{ neighbor_addr }} timers connect 10 +{% if bgp_session.get('admin_status') == 'down' %} + neighbor {{ neighbor_addr }} shutdown +{% endif %} +! + address-family ipv4 unicast + neighbor {{ neighbor_addr }} activate +{% if bgp_session.get('rrclient', '0') | int != 0 %} + neighbor {{ neighbor_addr }} route-reflector-client +{% endif %} +{% if bgp_session.get('nhopself', '0') | int != 0 %} + neighbor {{ neighbor_addr }} next-hop-self +{% endif %} + exit-address-family +! + address-family ipv6 unicast + neighbor {{ neighbor_addr }} activate +{% if bgp_session.get('rrclient', '0') | int != 0 %} + neighbor {{ neighbor_addr }} route-reflector-client +{% endif %} + exit-address-family +! +! end of template: bgpd/templates/unnumbered/instance.conf.j2 +! diff --git a/dockers/docker-fpm-frr/frr/bgpd/templates/general/unnumbered/peer-group.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/templates/general/unnumbered/peer-group.conf.j2 new file mode 100644 index 0000000000..e946682142 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/templates/general/unnumbered/peer-group.conf.j2 @@ -0,0 +1,18 @@ +! +! template: bgpd/templates/general/unnumbered/peer-group.conf.j2 +! Renders the PEER_UNNUMBERED peer-group inside `router bgp `. +! + neighbor PEER_UNNUMBERED peer-group + address-family ipv4 unicast + neighbor PEER_UNNUMBERED soft-reconfiguration inbound + neighbor PEER_UNNUMBERED route-map FROM_BGP_PEER_UNNUMBERED in + neighbor PEER_UNNUMBERED route-map TO_BGP_PEER_UNNUMBERED out + exit-address-family + address-family ipv6 unicast + neighbor PEER_UNNUMBERED soft-reconfiguration inbound + neighbor PEER_UNNUMBERED route-map FROM_BGP_PEER_UNNUMBERED in + neighbor PEER_UNNUMBERED route-map TO_BGP_PEER_UNNUMBERED out + exit-address-family +! +! end of template: bgpd/templates/general/unnumbered/peer-group.conf.j2 +! diff --git a/dockers/docker-fpm-frr/frr/bgpd/templates/general/unnumbered/policies.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/templates/general/unnumbered/policies.conf.j2 new file mode 100644 index 0000000000..69b154c2fd --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/templates/general/unnumbered/policies.conf.j2 @@ -0,0 +1,11 @@ +! +! template: bgpd/templates/general/unnumbered/policies.conf.j2 +! Renders top-level route-maps for the unnumbered peer-group +! Default permit-all; +! +route-map FROM_BGP_PEER_UNNUMBERED permit 100 +! +route-map TO_BGP_PEER_UNNUMBERED permit 100 +! +! end of template: bgpd/templates/general/unnumbered/policies.conf.j2 +! diff --git a/src/sonic-bgpcfgd/tests/conftest.py b/src/sonic-bgpcfgd/tests/conftest.py new file mode 100644 index 0000000000..e1bd4afccc --- /dev/null +++ b/src/sonic-bgpcfgd/tests/conftest.py @@ -0,0 +1,42 @@ +"""Local conftest: shim sonic_py_common and swsscommon for hosts that +don't have them installed.""" +import sys +import types +from unittest.mock import MagicMock + + +def _install_sonic_py_common_shim(): + if "sonic_py_common" in sys.modules and getattr( + sys.modules["sonic_py_common"], "__path__", None) is not None: + return + spc = types.ModuleType("sonic_py_common") + spc.__path__ = [] # mark as package so submodule imports work + sys.modules["sonic_py_common"] = spc + + di = types.ModuleType("sonic_py_common.device_info") + di.is_chassis = MagicMock(return_value=False) + di.is_supervisor = MagicMock(return_value=False) + di.get_platform = MagicMock(return_value="x86_64-kvm_x86_64-r0") + di.get_hwsku = MagicMock(return_value="Force10-S6000") + sys.modules["sonic_py_common.device_info"] = di + spc.device_info = di + + ma = types.ModuleType("sonic_py_common.multi_asic") + ma.is_multi_asic = MagicMock(return_value=False) + sys.modules["sonic_py_common.multi_asic"] = ma + spc.multi_asic = ma + + gm = types.ModuleType("sonic_py_common.general") + gm.getstatusoutput_noshell = MagicMock(return_value=(0, "")) + sys.modules["sonic_py_common.general"] = gm + spc.general = gm + + +_install_sonic_py_common_shim() + +try: + import swsscommon # noqa: F401 +except ImportError: + from tests import swsscommon_test + sys.modules["swsscommon"] = swsscommon_test + sys.modules["swsscommon.swsscommon"] = swsscommon_test diff --git a/src/sonic-bgpcfgd/tests/test_bgp_router_dispatch.py b/src/sonic-bgpcfgd/tests/test_bgp_router_dispatch.py new file mode 100644 index 0000000000..7617f6429b --- /dev/null +++ b/src/sonic-bgpcfgd/tests/test_bgp_router_dispatch.py @@ -0,0 +1,143 @@ +""" +Tests for the general/router.j2 dispatcher: verifies that the thin wrappers +in dockers/docker-fpm-frr/frr/bgpd/templates/general/{instance,peer-group, +policies}.conf.j2 route to numbered/* sub-templates when neighbor_addr is an +IP address, and to unnumbered/* sub-templates when neighbor_addr is an +interface name (non-IP string). + +These tests exercise the templates directly via TemplateFabric, decoupled +from any bgpcfgd Manager state, so they cleanly validate the routing logic. +""" +import os + +import pytest + +from bgpcfgd.template import TemplateFabric + +TEMPLATE_PATH = os.path.abspath( + os.path.join(os.path.dirname(__file__), "..", "..", "..", + "dockers", "docker-fpm-frr", "frr") +) + + +@pytest.fixture(scope="module") +def tf(): + return TemplateFabric(TEMPLATE_PATH) + + +def _common_kwargs(neighbor_addr): + """Minimal kwargs that satisfy both numbered and unnumbered templates.""" + return { + "neighbor_addr": neighbor_addr, + "bgp_asn": 65100, + "vrf": "default", + "bgp_session": { + "asn": 64600, + "name": "ARISTA01T1", + "admin_status": "up", + "local_addr": "10.0.0.0", + "holdtime": "180", + "keepalive": "60", + }, + "constants": {"bgp": {}}, + "CONFIG_DB__DEVICE_METADATA": { + "localhost": { + "type": "ToRRouter", + "subtype": "", + "default_bgp_status": "up", + "bgp_asn": "65100", + } + }, + "CONFIG_DB__BGP_BBR": {"status": "disabled"}, + "CONFIG_DB__LOOPBACK_INTERFACE": {}, + "CONFIG_DB__DEVICE_NEIGHBOR_METADATA": {}, + "loopback0_ipv4": "10.1.0.32", + } + + +# --------------------------------------------------------------------------- +# IP neighbor -> dispatcher must route to general/numbered/*.conf.j2 +# --------------------------------------------------------------------------- + +@pytest.mark.parametrize("ip", ["10.0.0.1", "fc00::1"]) +def test_dispatcher_instance_ip_routes_to_numbered(tf, ip): + tmpl = tf.from_file("bgpd/templates/general/instance.conf.j2") + out = tmpl.render(**_common_kwargs(ip)) + # Numbered template renders `peer-group PEER_V4`/`PEER_V6` and uses the + # numbered marker comment. + assert "bgpd/templates/general/numbered/instance.conf.j2" not in out, \ + "Marker comment is in the sub-template; not expected to leak" + assert ("PEER_V4" in out) or ("PEER_V6" in out), \ + "Numbered instance template should set peer-group PEER_V4/PEER_V6" + # And must not have the unnumbered-only artifact + assert "PEER_UNNUMBERED" not in out + assert "interface peer-group" not in out + + +@pytest.mark.parametrize("ip", ["10.0.0.1", "fc00::1"]) +def test_dispatcher_peer_group_ip_routes_to_numbered(tf, ip): + tmpl = tf.from_file("bgpd/templates/general/peer-group.conf.j2") + out = tmpl.render(**_common_kwargs(ip)) + assert "neighbor PEER_V4 peer-group" in out + assert "neighbor PEER_V6 peer-group" in out + assert "PEER_UNNUMBERED" not in out + + +@pytest.mark.parametrize("ip", ["10.0.0.1", "fc00::1"]) +def test_dispatcher_policies_ip_routes_to_numbered(tf, ip): + tmpl = tf.from_file("bgpd/templates/general/policies.conf.j2") + out = tmpl.render(**_common_kwargs(ip)) + # Numbered policies sets the default IPv4/IPv6 prefix-lists. + assert "ip prefix-list DEFAULT_IPV4 permit 0.0.0.0/0" in out + + +# --------------------------------------------------------------------------- +# Interface-name neighbor -> dispatcher must route to general/unnumbered/*.conf.j2 +# --------------------------------------------------------------------------- + +@pytest.mark.parametrize("iface", ["PortChannel101", "Ethernet0", "Po1031.101"]) +def test_dispatcher_instance_iface_routes_to_unnumbered(tf, iface): + tmpl = tf.from_file("bgpd/templates/general/instance.conf.j2") + out = tmpl.render(**_common_kwargs(iface)) + # Unnumbered template uses `neighbor interface peer-group PEER_UNNUMBERED` + assert ("neighbor %s interface peer-group PEER_UNNUMBERED" % iface) in out, \ + "Unnumbered instance template should bind iface to PEER_UNNUMBERED" + # Numbered-only artifact must not appear + assert "peer-group PEER_V4" not in out + assert "peer-group PEER_V6" not in out + + +@pytest.mark.parametrize("iface", ["PortChannel101", "Po1031.101"]) +def test_dispatcher_peer_group_iface_routes_to_unnumbered(tf, iface): + tmpl = tf.from_file("bgpd/templates/general/peer-group.conf.j2") + out = tmpl.render(**_common_kwargs(iface)) + assert "neighbor PEER_UNNUMBERED peer-group" in out + assert "PEER_V4 peer-group" not in out + + +@pytest.mark.parametrize("iface", ["PortChannel101", "Po1031.101"]) +def test_dispatcher_policies_iface_routes_to_unnumbered(tf, iface): + tmpl = tf.from_file("bgpd/templates/general/policies.conf.j2") + out = tmpl.render(**_common_kwargs(iface)) + # Numbered DEFAULT_IPV4/V6 prefix-list should NOT appear in unnumbered policies. + assert "ip prefix-list DEFAULT_IPV4 permit 0.0.0.0/0" not in out + + +# --------------------------------------------------------------------------- +# router.j2 macro itself: import and call directly +# --------------------------------------------------------------------------- + +def test_router_macro_directly_dispatches(tf): + """Render an inline template that imports the macro and calls it - + proves the macro contract works regardless of the wrapper *.conf.j2.""" + src = ( + '{% from "bgpd/templates/general/router.j2" import general_routing ' + 'with context %}{{ general_routing("instance") }}' + ) + t = tf.env.from_string(src) + # IP neighbor -> numbered branch + out_ip = t.render(**_common_kwargs("10.0.0.1")) + assert "PEER_V4" in out_ip or "PEER_V6" in out_ip + # Interface neighbor -> unnumbered branch + out_if = t.render(**_common_kwargs("PortChannel101")) + assert "PEER_UNNUMBERED" in out_if diff --git a/src/sonic-swss b/src/sonic-swss index cdd979a808..c763882117 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit cdd979a8087e41142b2eb8817e2f2c4c335ff62d +Subproject commit c7638821170f070dc3968ba74d20ff7163f0d3cd diff --git a/src/sonic-utilities b/src/sonic-utilities index 3136803b39..6270b27b66 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit 3136803b39a6e05a36e8aa3741a4b59d4dfc75f0 +Subproject commit 6270b27b66146edca0e8ab2a3744e476825684eb