From 1d9cf31e849b862063200309734bab6620f57f1d Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 8 May 2021 21:21:21 +0200 Subject: vrf: bgp: T3523: bugfix Kernel route-map deployment Commit 4f9aa30f ("vrf: bgp: T3523: add route-map support for kernel routes") added the possibility to also filter BGP routes towards the OS kernel, but the smoketests failed. Reason was a non working CLI command applied to bgpd. Thus the VRF route-map and the BGP configuration is now split into two templates, one to be used for each daemon (zebra and bgpd). Nevertheless one more bug was found in vyos.frr which currently does not suppoort calling modify_section() inside a configuration "block". See [1] for more info. [1]: https://phabricator.vyos.net/T3529 --- data/templates/frr/bgp.frr.tmpl | 482 ---------------------------- data/templates/frr/bgpd.frr.tmpl | 473 +++++++++++++++++++++++++++ data/templates/frr/isis.frr.tmpl | 9 - data/templates/frr/ospf.frr.tmpl | 9 - data/templates/frr/vrf.route-map.frr.tmpl | 10 + smoketest/scripts/cli/test_protocols_bgp.py | 11 +- src/conf_mode/protocols_bgp.py | 20 +- src/conf_mode/protocols_isis.py | 17 +- src/conf_mode/protocols_ospf.py | 17 +- 9 files changed, 531 insertions(+), 517 deletions(-) delete mode 100644 data/templates/frr/bgp.frr.tmpl create mode 100644 data/templates/frr/bgpd.frr.tmpl create mode 100644 data/templates/frr/vrf.route-map.frr.tmpl diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl deleted file mode 100644 index 0245c875e..000000000 --- a/data/templates/frr/bgp.frr.tmpl +++ /dev/null @@ -1,482 +0,0 @@ -{### MACRO definition for recurring peer patter, this can be either fed by a ###} -{### peer-group or an individual BGP neighbor ###} -{% macro bgp_neighbor(neighbor, config, peer_group=false) %} -{% if peer_group == true %} - neighbor {{ neighbor }} peer-group -{% elif config.peer_group is defined and config.peer_group is not none %} - neighbor {{ neighbor }} peer-group {{ config.peer_group }} -{% endif %} -{% if config.remote_as is defined and config.remote_as is not none %} - neighbor {{ neighbor }} remote-as {{ config.remote_as }} -{% endif %} -{% if config.interface is defined and config.interface.remote_as is defined and config.interface.remote_as is not none %} - neighbor {{ neighbor }} interface remote-as {{ config.interface.remote_as }} -{% endif %} -{% if config.advertisement_interval is defined and config.advertisement_interval is not none %} - neighbor {{ neighbor }} advertisement-interval {{ config.advertisement_interval }} -{% endif %} -{% if config.bfd is defined %} - neighbor {{ neighbor }} bfd -{% endif %} -{% if config.capability is defined and config.capability is not none %} -{% if config.capability.dynamic is defined %} - neighbor {{ neighbor }} capability dynamic -{% endif %} -{% if config.capability.extended_nexthop is defined %} - neighbor {{ neighbor }} capability extended-nexthop -{% endif %} -{% endif %} -{% if config.description is defined and config.description is not none %} - neighbor {{ neighbor }} description {{ config.description }} -{% endif %} -{% if config.disable_capability_negotiation is defined %} - neighbor {{ neighbor }} dont-capability-negotiate -{% endif %} -{% if config.ebgp_multihop is defined and config.ebgp_multihop is not none %} - neighbor {{ neighbor }} ebgp-multihop {{ config.ebgp_multihop }} -{% endif %} -{% if config.graceful_restart is defined and config.graceful_restart is not none %} -{% if config.graceful_restart == 'enable' %} -{% set graceful_restart = 'graceful-restart' %} -{% elif config.graceful_restart == 'disable' %} -{% set graceful_restart = 'graceful-restart-disable' %} -{% elif config.graceful_restart == 'restart-helper' %} -{% set graceful_restart = 'graceful-restart-helper' %} -{% endif %} - neighbor {{ neighbor }} {{ graceful_restart }} -{% endif %} -{% if config.local_as is defined and config.local_as is not none %} -{% for local_asn in config.local_as %} - neighbor {{ neighbor }} local-as {{ local_asn }} {{ 'no-prepend' if config.local_as[local_asn].no_prepend is defined }} -{% endfor %} -{% endif %} -{% if config.override_capability is defined %} - neighbor {{ neighbor }} override-capability -{% endif %} -{% if config.passive is defined %} - neighbor {{ neighbor }} passive -{% endif %} -{% if config.password is defined and config.password is not none %} - neighbor {{ neighbor }} password {{ config.password }} -{% endif %} -{% if config.port is defined and config.port is not none %} - neighbor {{ neighbor }} port {{ config.port }} -{% endif %} -{% if config.shutdown is defined %} - neighbor {{ neighbor }} shutdown -{% endif %} -{% if config.strict_capability_match is defined %} - neighbor {{ neighbor }} strict-capability-match -{% endif %} -{% if config.ttl_security is defined and config.ttl_security.hops is defined and config.ttl_security.hops is not none %} - neighbor {{ neighbor }} ttl-security hops {{ config.ttl_security.hops }} -{% endif %} -{% if config.timers is defined %} -{% if config.timers.connect is defined and config.timers.connect is not none %} - neighbor {{ neighbor }} timers connect {{ config.timers.connect }} -{% endif %} -{% if config.timers.holdtime is defined and config.timers.keepalive is defined and config.timers.holdtime is not none and config.timers.keepalive is not none %} - neighbor {{ neighbor }} timers {{ config.timers.keepalive }} {{ config.timers.holdtime }} -{% endif %} -{% endif %} -{% if config.update_source is defined and config.update_source is not none %} - neighbor {{ neighbor }} update-source {{ config.update_source }} -{% endif %} -{% if config.interface is defined and config.interface is not none %} -{% if config.interface.peer_group is defined and config.interface.peer_group is not none %} - neighbor {{ neighbor }} interface peer-group {{ config.interface.peer_group }} -{% endif %} -{% if config.interface.v6only is defined and config.interface.v6only is not none %} -{% if config.interface.v6only.peer_group is defined and config.interface.v6only.peer_group is not none %} - neighbor {{ neighbor }} interface v6only peer-group {{ config.interface.v6only.peer_group }} -{% endif %} -{% if config.interface.v6only.remote_as is defined and config.interface.v6only.remote_as is not none %} - neighbor {{ neighbor }} interface v6only remote-as {{ config.interface.v6only.remote_as }} -{% endif %} -{% endif %} -{% endif %} - ! -{% if config.address_family is defined and config.address_family is not none %} -{% for afi, afi_config in config.address_family.items() %} -{% if afi == 'ipv4_unicast' %} - address-family ipv4 unicast -{% elif afi == 'ipv4_multicast' %} - address-family ipv4 multicast -{% elif afi == 'ipv4_labeled_unicast' %} - address-family ipv4 labeled-unicast -{% elif afi == 'ipv4_vpn' %} - address-family ipv4 vpn -{% elif afi == 'ipv4_flowspec' %} - address-family ipv4 flowspec -{% elif afi == 'ipv6_unicast' %} - address-family ipv6 unicast -{% elif afi == 'ipv6_multicast' %} - address-family ipv6 multicast -{% elif afi == 'ipv6_labeled_unicast' %} - address-family ipv6 labeled-unicast -{% elif afi == 'ipv6_vpn' %} - address-family ipv6 vpn -{% elif afi == 'ipv6_flowspec' %} - address-family ipv6 flowspec -{% elif afi == 'l2vpn_evpn' %} - address-family l2vpn evpn -{% endif %} -{% if afi_config.addpath_tx_all is defined %} - neighbor {{ neighbor }} addpath-tx-all-paths -{% endif %} -{% if afi_config.addpath_tx_per_as is defined %} - neighbor {{ neighbor }} addpath-tx-bestpath-per-AS -{% endif %} -{% if afi_config.allowas_in is defined and afi_config.allowas_in is not none %} - neighbor {{ neighbor }} allowas-in {{ afi_config.allowas_in.number if afi_config.allowas_in.number is defined }} -{% endif %} -{% if afi_config.as_override is defined %} - neighbor {{ neighbor }} as-override -{% endif %} -{% if afi_config.remove_private_as is defined %} - neighbor {{ neighbor }} remove-private-AS -{% endif %} -{% if afi_config.route_reflector_client is defined %} - neighbor {{ neighbor }} route-reflector-client -{% endif %} -{% if afi_config.weight is defined and afi_config.weight is not none %} - neighbor {{ neighbor }} weight {{ afi_config.weight }} -{% endif %} -{% if afi_config.attribute_unchanged is defined and afi_config.attribute_unchanged is not none %} - neighbor {{ neighbor }} attribute-unchanged {{ 'as-path ' if afi_config.attribute_unchanged.as_path is defined }}{{ 'med ' if afi_config.attribute_unchanged.med is defined }}{{ 'next-hop ' if afi_config.attribute_unchanged.next_hop is defined }} -{% endif %} -{% if afi_config.capability is defined and afi_config.capability.orf is defined and afi_config.capability.orf.prefix_list is defined and afi_config.capability.orf.prefix_list.send is defined %} - neighbor {{ neighbor }} capability orf prefix-list send -{% endif %} -{% if afi_config.capability is defined and afi_config.capability.orf is defined and afi_config.capability.orf.prefix_list is defined and afi_config.capability.orf.prefix_list.receive is defined %} - neighbor {{ neighbor }} capability orf prefix-list receive -{% endif %} -{% if afi_config.default_originate is defined %} - neighbor {{ neighbor }} default-originate {{ 'route-map ' ~ afi_config.default_originate.route_map if afi_config.default_originate.route_map is defined }} -{% endif %} -{% if afi_config.distribute_list is defined and afi_config.distribute_list is not none %} -{% if afi_config.distribute_list.export is defined and afi_config.distribute_list.export is not none %} - neighbor {{ neighbor }} distribute-list {{ afi_config.distribute_list.export }} out -{% endif %} -{% if afi_config.distribute_list.import is defined and afi_config.distribute_list.import is not none %} - neighbor {{ neighbor }} distribute-list {{ afi_config.distribute_list.import }} in -{% endif %} -{% endif %} -{% if afi_config.filter_list is defined and afi_config.filter_list is not none %} -{% if afi_config.filter_list.export is defined and afi_config.filter_list.export is not none %} - neighbor {{ neighbor }} filter-list {{ afi_config.filter_list.export }} out -{% endif %} -{% if afi_config.filter_list.import is defined and afi_config.filter_list.import is not none %} - neighbor {{ neighbor }} filter-list {{ afi_config.filter_list.import }} in -{% endif %} -{% endif %} -{% if afi_config.maximum_prefix is defined and afi_config.maximum_prefix is not none %} - neighbor {{ neighbor }} maximum-prefix {{ afi_config.maximum_prefix }} -{% endif %} -{% if afi_config.nexthop_self is defined %} - neighbor {{ neighbor }} next-hop-self {{ 'force' if afi_config.nexthop_self.force is defined }} -{% endif %} -{% if afi_config.route_server_client is defined %} - neighbor {{ neighbor }} route-server-client -{% endif %} -{% if afi_config.route_map is defined and afi_config.route_map is not none %} -{% if afi_config.route_map.export is defined and afi_config.route_map.export is not none %} - neighbor {{ neighbor }} route-map {{ afi_config.route_map.export }} out -{% endif %} -{% if afi_config.route_map.import is defined and afi_config.route_map.import is not none %} - neighbor {{ neighbor }} route-map {{ afi_config.route_map.import }} in -{% endif %} -{% endif %} -{% if afi_config.prefix_list is defined and afi_config.prefix_list is not none %} -{% if afi_config.prefix_list.export is defined and afi_config.prefix_list.export is not none %} - neighbor {{ neighbor }} prefix-list {{ afi_config.prefix_list.export }} out -{% endif %} -{% if afi_config.prefix_list.import is defined and afi_config.prefix_list.import is not none %} - neighbor {{ neighbor }} prefix-list {{ afi_config.prefix_list.import }} in -{% endif %} -{% endif %} -{% if afi_config.soft_reconfiguration is defined and afi_config.soft_reconfiguration.inbound is defined %} - neighbor {{ neighbor }} soft-reconfiguration inbound -{% endif %} -{% if afi_config.unsuppress_map is defined and afi_config.unsuppress_map is not none %} - neighbor {{ neighbor }} unsuppress-map {{ afi_config.unsuppress_map }} -{% endif %} -{% if afi_config.disable_send_community is defined and afi_config.disable_send_community.extended is defined %} - no neighbor {{ neighbor }} send-community extended -{% endif %} -{% if afi_config.disable_send_community is defined and afi_config.disable_send_community.standard is defined %} - no neighbor {{ neighbor }} send-community standard -{% endif %} - neighbor {{ neighbor }} activate - exit-address-family - ! -{% endfor %} -{% endif %} -{% endmacro %} -! -{% if vrf is defined and vrf is not none and route_map is defined and route_map is not none %} -vrf {{ vrf }} - ip protocol bgp route-map {{ route_map }} - exit-vrf -! -{% elif route_map is defined and route_map is not none %} -ip protocol bgp route-map {{ route_map }} -{% endif %} -! -router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none }} -{% if parameters is defined and parameters.ebgp_requires_policy is defined %} - bgp ebgp-requires-policy -{% else %} - no bgp ebgp-requires-policy -{% endif %} -{% if parameters is defined and parameters.default is defined and parameters.default.no_ipv4_unicast is defined %} -{# Option must be set before any neighbor - see https://phabricator.vyos.net/T3463 #} - no bgp default ipv4-unicast -{% endif %} -{# Workaround for T2100 until we have decided about a migration script #} - no bgp network import-check -{% if address_family is defined and address_family is not none %} -{% for afi, afi_config in address_family.items() %} - ! -{% if afi == 'ipv4_unicast' %} - address-family ipv4 unicast -{% elif afi == 'ipv4_multicast' %} - address-family ipv4 multicast -{% elif afi == 'ipv4_labeled_unicast' %} - address-family ipv4 labeled-unicast -{% elif afi == 'ipv4_vpn' %} - address-family ipv4 vpn -{% elif afi == 'ipv4_flowspec' %} - address-family ipv4 flowspec -{% elif afi == 'ipv6_unicast' %} - address-family ipv6 unicast -{% elif afi == 'ipv6_multicast' %} - address-family ipv6 multicast -{% elif afi == 'ipv6_labeled_unicast' %} - address-family ipv6 labeled-unicast -{% elif afi == 'ipv6_vpn' %} - address-family ipv6 vpn -{% elif afi == 'ipv6_flowspec' %} - address-family ipv6 flowspec -{% elif afi == 'l2vpn_evpn' %} - address-family l2vpn evpn -{% endif %} -{% if afi_config.aggregate_address is defined and afi_config.aggregate_address is not none %} -{% for ip in afi_config.aggregate_address %} - aggregate-address {{ ip }}{{ ' as-set' if afi_config.aggregate_address[ip].as_set is defined }}{{ ' summary-only' if afi_config.aggregate_address[ip].summary_only is defined }} -{% endfor %} -{% endif %} -{% if afi_config.maximum_paths is defined and afi_config.maximum_paths.ebgp is defined and afi_config.maximum_paths.ebgp is not none %} - maximum-paths {{ afi_config.maximum_paths.ebgp }} -{% endif %} -{% if afi_config.maximum_paths is defined and afi_config.maximum_paths.ibgp is defined and afi_config.maximum_paths.ibgp is not none %} - maximum-paths ibgp {{ afi_config.maximum_paths.ibgp }} -{% endif %} -{% if afi_config.redistribute is defined and afi_config.redistribute is not none %} -{% for protocol in afi_config.redistribute %} -{% if protocol == 'table' %} - redistribute table {{ afi_config.redistribute[protocol].table }} -{% else %} -{% set redistribution_protocol = protocol %} -{% if protocol == 'ospfv3' %} -{% set redistribution_protocol = 'ospf6' %} -{% endif %} - redistribute {{ redistribution_protocol }}{% if afi_config.redistribute[protocol].metric is defined %} metric {{ afi_config.redistribute[protocol].metric }}{% endif %}{% if afi_config.redistribute[protocol].route_map is defined %} route-map {{ afi_config.redistribute[protocol].route_map }}{% endif %} -{####### we need this blank line!! #######} - -{% endif %} -{% endfor %} -{% endif %} -{% if afi_config.network is defined and afi_config.network is not none %} -{% for network in afi_config.network %} - network {{ network }}{% if afi_config.network[network].route_map is defined %} route-map {{ afi_config.network[network].route_map }}{% endif %}{% if afi_config.network[network].backdoor is defined %} backdoor{% endif %}{% if afi_config.network[network].rd is defined and afi_config.network[network].label is defined%} rd {{ afi_config.network[network].rd }} label {{ afi_config.network[network].label }}{% endif %} -{####### we need this blank line!! #######} - -{% endfor %} -{% endif %} -{% if afi_config.advertise is defined and afi_config.advertise is not none %} -{% for adv_afi, adv_afi_config in afi_config.advertise.items() %} -{% if adv_afi_config.unicast is defined and adv_afi_config.unicast is not none %} - advertise {{ adv_afi }} unicast {{ 'route-map ' ~ adv_afi_config.unicast.route_map if adv_afi_config.unicast.route_map is defined }} -{% endif %} -{% endfor %} -{% endif %} -{% if afi_config.distance is defined and afi_config.distance is not none %} -{% if afi_config.distance is defined and afi_config.distance.external is defined and afi_config.distance.internal is defined and afi_config.distance.local is defined %} - distance bgp {{ afi_config.distance.external }} {{ afi_config.distance.internal }} {{ afi_config.distance.local }} -{% endif %} -{% if afi_config.distance.prefix is defined and afi_config.distance.prefix is not none %} -{% for prefix in afi_config.distance.prefix %} - distance {{ afi_config.distance.prefix[prefix].distance }} {{ prefix }} -{% endfor %} -{% endif %} -{% endif %} -{% if afi_config.local_install is defined and afi_config.local_install is not none %} -{% for interface in afi_config.local_install.interface %} - local-install {{ interface }} -{% endfor %} -{% endif %} -{% if afi_config.advertise_all_vni is defined %} - advertise-all-vni -{% endif %} -{% if afi_config.advertise_default_gw is defined %} - advertise-default-gw -{% endif %} -{% if afi_config.advertise_pip is defined and afi_config.advertise_pip is not none %} - advertise-pip ip {{ afi_config.advertise_pip }} -{% endif %} -{% if afi_config.advertise_svi_ip is defined %} - advertise-svi-ip -{% endif %} -{% if afi_config.rt_auto_derive is defined %} - autort rfc8365-compatible -{% endif %} -{% if afi_config.flooding is defined and afi_config.flooding.disable is defined %} - flooding disable -{% endif %} -{% if afi_config.flooding is defined and afi_config.flooding.head_end_replication is defined %} - flooding head-end-replication -{% endif %} -{% if afi_config.rd is defined and afi_config.rd is not none %} - rd {{ afi_config.rd }} -{% endif %} -{% if afi_config.route_target is defined and afi_config.route_target is not none %} -{% if afi_config.route_target.both is defined and afi_config.route_target.both is not none %} - route-target both {{ afi_config.route_target.both }} -{% endif %} -{% if afi_config.route_target.export is defined and afi_config.route_target.export is not none %} - route-target export {{ afi_config.route_target.export }} -{% endif %} -{% if afi_config.route_target.import is defined and afi_config.route_target.import is not none %} - route-target import {{ afi_config.route_target.import }} -{% endif %} -{% endif %} -{% if afi_config.vni is defined and afi_config.vni is not none %} -{% for vni, vni_config in afi_config.vni.items() %} - vni {{ vni }} -{% if vni_config.advertise_default_gw is defined %} - advertise-default-gw -{% endif %} -{% if vni_config.advertise_svi_ip is defined %} - advertise-svi-ip -{% endif %} -{% if vni_config.rd is defined and vni_config.rd is not none %} - rd {{ vni_config.rd }} -{% endif %} -{% if vni_config.route_target is defined and vni_config.route_target is not none %} -{% if vni_config.route_target.both is defined and vni_config.route_target.both is not none %} - route-target both {{ vni_config.route_target.both }} -{% endif %} -{% if vni_config.route_target.export is defined and vni_config.route_target.export is not none %} - route-target export {{ vni_config.route_target.export }} -{% endif %} -{% if vni_config.route_target.import is defined and vni_config.route_target.import is not none %} - route-target import {{ vni_config.route_target.import }} -{% endif %} -{% endif %} - exit-vni -{% endfor %} -{% endif %} - exit-address-family -{% endfor %} -{% endif %} - ! -{% if peer_group is defined and peer_group is not none %} -{% for peer, config in peer_group.items() %} -{{ bgp_neighbor(peer, config, true) }} -{% endfor %} -{% endif %} - ! -{% if neighbor is defined and neighbor is not none %} -{% for peer, config in neighbor.items() %} -{{ bgp_neighbor(peer, config) }} -{% endfor %} -{% endif %} - ! -{% if listen is defined %} -{% if listen.limit is defined and listen.limit is not none %} - bgp listen limit {{ listen.limit }} -{% endif %} -{% for prefix, options in listen.range.items() %} -{% if options.peer_group is defined and options.peer_group is not none %} - bgp listen range {{ prefix }} peer-group {{ options.peer_group }} -{% endif %} -{% endfor %} -{% endif %} -{% if parameters is defined %} -{% if parameters.always_compare_med is defined %} - bgp always-compare-med -{% endif %} -{% if parameters.bestpath is defined and parameters.bestpath is not none %} -{% if parameters.bestpath.compare_routerid is defined %} - bgp bestpath compare-routerid -{% endif %} -{% if parameters.bestpath.as_path is defined and parameters.bestpath.as_path is not none %} -{% for option in parameters.bestpath.as_path %} - bgp bestpath as-path {{ option|replace('_', '-') }} -{% endfor %} -{% endif %} -{% if parameters.bestpath.med is defined and parameters.bestpath.med is not none %} - bgp bestpath med {{ 'confed' if parameters.bestpath.med.confed is defined }} {{ 'missing-as-worst' if parameters.bestpath.med.missing_as_worst is defined }} -{% endif %} -{% endif %} -{% if parameters.cluster_id is defined and parameters.cluster_id is not none %} - bgp cluster-id {{ parameters.cluster_id }} -{% endif %} -{% if parameters.confederation is defined and parameters.confederation is not none %} -{% if parameters.confederation.identifier is defined and parameters.confederation.identifier is not none %} - bgp confederation identifier {{ parameters.confederation.identifier }} -{% endif %} -{% if parameters.confederation.peers is defined and parameters.confederation.peers is not none %} - bgp confederation peers {{ parameters.confederation.peers }} -{% endif %} -{% endif %} -{% if parameters.dampening is defined and parameters.dampening is defined and parameters.dampening.half_life is defined and parameters.dampening.half_life is not none %} -{# Doesn't work in current FRR configuration; vtysh (bgp dampening 16 751 2001 61) #} - bgp dampening {{ parameters.dampening.half_life }} {{ parameters.dampening.re_use if parameters.dampening.re_use is defined }} {{ parameters.dampening.start_suppress_time if parameters.dampening.start_suppress_time is defined }} {{ parameters.dampening.max_suppress_time if parameters.dampening.max_suppress_time is defined }} -{% endif %} -{% if parameters.default is defined and parameters.default is not none %} -{% if parameters.default.local_pref is defined and parameters.default.local_pref is not none %} - bgp default local-preference {{ parameters.default.local_pref }} -{% endif %} -{% endif %} -{% if parameters.deterministic_med is defined %} - bgp deterministic-med -{% endif %} -{% if parameters.distance is defined and parameters.distance is not none %} -{% if parameters.distance.global is defined and parameters.distance.global.external is defined and parameters.distance.global.internal is defined and parameters.distance.global.local is defined %} - distance bgp {{ parameters.distance.global.external }} {{ parameters.distance.global.internal }} {{ parameters.distance.global.local }} -{% endif %} -{% if parameters.distance.prefix is defined and parameters.distance.prefix is not none %} -{% for prefix in parameters.distance.prefix %} - distance {{ parameters.distance.prefix[prefix].distance }} {{ prefix }} -{% endfor %} -{% endif %} -{% endif %} -{% if parameters.graceful_restart is defined %} - bgp graceful-restart {{ 'stalepath-time ' ~ parameters.graceful_restart.stalepath_time if parameters.graceful_restart.stalepath_time is defined }} -{% endif %} -{% if parameters.graceful_shutdown is defined %} - bgp graceful-shutdown -{% endif %} -{% if parameters.log_neighbor_changes is defined %} - bgp log-neighbor-changes -{% endif %} -{% if parameters.network_import_check is defined %} - bgp network import-check -{% endif %} -{% if parameters.no_client_to_client_reflection is defined %} - no bgp client-to-client reflection -{% endif %} -{% if parameters.no_fast_external_failover is defined %} - no bgp fast-external-failover -{% endif %} -{% if parameters.router_id is defined and parameters.router_id is not none %} - bgp router-id {{ parameters.router_id }} -{% endif %} -{% endif %} -{% if timers is defined and timers.keepalive is defined and timers.holdtime is defined %} - timers bgp {{ timers.keepalive }} {{ timers.holdtime }} -{% endif %} - end -! \ No newline at end of file diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl new file mode 100644 index 000000000..57b9ba8d6 --- /dev/null +++ b/data/templates/frr/bgpd.frr.tmpl @@ -0,0 +1,473 @@ +{### MACRO definition for recurring peer patter, this can be either fed by a ###} +{### peer-group or an individual BGP neighbor ###} +{% macro bgp_neighbor(neighbor, config, peer_group=false) %} +{% if peer_group == true %} + neighbor {{ neighbor }} peer-group +{% elif config.peer_group is defined and config.peer_group is not none %} + neighbor {{ neighbor }} peer-group {{ config.peer_group }} +{% endif %} +{% if config.remote_as is defined and config.remote_as is not none %} + neighbor {{ neighbor }} remote-as {{ config.remote_as }} +{% endif %} +{% if config.interface is defined and config.interface.remote_as is defined and config.interface.remote_as is not none %} + neighbor {{ neighbor }} interface remote-as {{ config.interface.remote_as }} +{% endif %} +{% if config.advertisement_interval is defined and config.advertisement_interval is not none %} + neighbor {{ neighbor }} advertisement-interval {{ config.advertisement_interval }} +{% endif %} +{% if config.bfd is defined %} + neighbor {{ neighbor }} bfd +{% endif %} +{% if config.capability is defined and config.capability is not none %} +{% if config.capability.dynamic is defined %} + neighbor {{ neighbor }} capability dynamic +{% endif %} +{% if config.capability.extended_nexthop is defined %} + neighbor {{ neighbor }} capability extended-nexthop +{% endif %} +{% endif %} +{% if config.description is defined and config.description is not none %} + neighbor {{ neighbor }} description {{ config.description }} +{% endif %} +{% if config.disable_capability_negotiation is defined %} + neighbor {{ neighbor }} dont-capability-negotiate +{% endif %} +{% if config.ebgp_multihop is defined and config.ebgp_multihop is not none %} + neighbor {{ neighbor }} ebgp-multihop {{ config.ebgp_multihop }} +{% endif %} +{% if config.graceful_restart is defined and config.graceful_restart is not none %} +{% if config.graceful_restart == 'enable' %} +{% set graceful_restart = 'graceful-restart' %} +{% elif config.graceful_restart == 'disable' %} +{% set graceful_restart = 'graceful-restart-disable' %} +{% elif config.graceful_restart == 'restart-helper' %} +{% set graceful_restart = 'graceful-restart-helper' %} +{% endif %} + neighbor {{ neighbor }} {{ graceful_restart }} +{% endif %} +{% if config.local_as is defined and config.local_as is not none %} +{% for local_asn in config.local_as %} + neighbor {{ neighbor }} local-as {{ local_asn }} {{ 'no-prepend' if config.local_as[local_asn].no_prepend is defined }} +{% endfor %} +{% endif %} +{% if config.override_capability is defined %} + neighbor {{ neighbor }} override-capability +{% endif %} +{% if config.passive is defined %} + neighbor {{ neighbor }} passive +{% endif %} +{% if config.password is defined and config.password is not none %} + neighbor {{ neighbor }} password {{ config.password }} +{% endif %} +{% if config.port is defined and config.port is not none %} + neighbor {{ neighbor }} port {{ config.port }} +{% endif %} +{% if config.shutdown is defined %} + neighbor {{ neighbor }} shutdown +{% endif %} +{% if config.strict_capability_match is defined %} + neighbor {{ neighbor }} strict-capability-match +{% endif %} +{% if config.ttl_security is defined and config.ttl_security.hops is defined and config.ttl_security.hops is not none %} + neighbor {{ neighbor }} ttl-security hops {{ config.ttl_security.hops }} +{% endif %} +{% if config.timers is defined %} +{% if config.timers.connect is defined and config.timers.connect is not none %} + neighbor {{ neighbor }} timers connect {{ config.timers.connect }} +{% endif %} +{% if config.timers.holdtime is defined and config.timers.keepalive is defined and config.timers.holdtime is not none and config.timers.keepalive is not none %} + neighbor {{ neighbor }} timers {{ config.timers.keepalive }} {{ config.timers.holdtime }} +{% endif %} +{% endif %} +{% if config.update_source is defined and config.update_source is not none %} + neighbor {{ neighbor }} update-source {{ config.update_source }} +{% endif %} +{% if config.interface is defined and config.interface is not none %} +{% if config.interface.peer_group is defined and config.interface.peer_group is not none %} + neighbor {{ neighbor }} interface peer-group {{ config.interface.peer_group }} +{% endif %} +{% if config.interface.v6only is defined and config.interface.v6only is not none %} +{% if config.interface.v6only.peer_group is defined and config.interface.v6only.peer_group is not none %} + neighbor {{ neighbor }} interface v6only peer-group {{ config.interface.v6only.peer_group }} +{% endif %} +{% if config.interface.v6only.remote_as is defined and config.interface.v6only.remote_as is not none %} + neighbor {{ neighbor }} interface v6only remote-as {{ config.interface.v6only.remote_as }} +{% endif %} +{% endif %} +{% endif %} + ! +{% if config.address_family is defined and config.address_family is not none %} +{% for afi, afi_config in config.address_family.items() %} +{% if afi == 'ipv4_unicast' %} + address-family ipv4 unicast +{% elif afi == 'ipv4_multicast' %} + address-family ipv4 multicast +{% elif afi == 'ipv4_labeled_unicast' %} + address-family ipv4 labeled-unicast +{% elif afi == 'ipv4_vpn' %} + address-family ipv4 vpn +{% elif afi == 'ipv4_flowspec' %} + address-family ipv4 flowspec +{% elif afi == 'ipv6_unicast' %} + address-family ipv6 unicast +{% elif afi == 'ipv6_multicast' %} + address-family ipv6 multicast +{% elif afi == 'ipv6_labeled_unicast' %} + address-family ipv6 labeled-unicast +{% elif afi == 'ipv6_vpn' %} + address-family ipv6 vpn +{% elif afi == 'ipv6_flowspec' %} + address-family ipv6 flowspec +{% elif afi == 'l2vpn_evpn' %} + address-family l2vpn evpn +{% endif %} +{% if afi_config.addpath_tx_all is defined %} + neighbor {{ neighbor }} addpath-tx-all-paths +{% endif %} +{% if afi_config.addpath_tx_per_as is defined %} + neighbor {{ neighbor }} addpath-tx-bestpath-per-AS +{% endif %} +{% if afi_config.allowas_in is defined and afi_config.allowas_in is not none %} + neighbor {{ neighbor }} allowas-in {{ afi_config.allowas_in.number if afi_config.allowas_in.number is defined }} +{% endif %} +{% if afi_config.as_override is defined %} + neighbor {{ neighbor }} as-override +{% endif %} +{% if afi_config.remove_private_as is defined %} + neighbor {{ neighbor }} remove-private-AS +{% endif %} +{% if afi_config.route_reflector_client is defined %} + neighbor {{ neighbor }} route-reflector-client +{% endif %} +{% if afi_config.weight is defined and afi_config.weight is not none %} + neighbor {{ neighbor }} weight {{ afi_config.weight }} +{% endif %} +{% if afi_config.attribute_unchanged is defined and afi_config.attribute_unchanged is not none %} + neighbor {{ neighbor }} attribute-unchanged {{ 'as-path ' if afi_config.attribute_unchanged.as_path is defined }}{{ 'med ' if afi_config.attribute_unchanged.med is defined }}{{ 'next-hop ' if afi_config.attribute_unchanged.next_hop is defined }} +{% endif %} +{% if afi_config.capability is defined and afi_config.capability.orf is defined and afi_config.capability.orf.prefix_list is defined and afi_config.capability.orf.prefix_list.send is defined %} + neighbor {{ neighbor }} capability orf prefix-list send +{% endif %} +{% if afi_config.capability is defined and afi_config.capability.orf is defined and afi_config.capability.orf.prefix_list is defined and afi_config.capability.orf.prefix_list.receive is defined %} + neighbor {{ neighbor }} capability orf prefix-list receive +{% endif %} +{% if afi_config.default_originate is defined %} + neighbor {{ neighbor }} default-originate {{ 'route-map ' ~ afi_config.default_originate.route_map if afi_config.default_originate.route_map is defined }} +{% endif %} +{% if afi_config.distribute_list is defined and afi_config.distribute_list is not none %} +{% if afi_config.distribute_list.export is defined and afi_config.distribute_list.export is not none %} + neighbor {{ neighbor }} distribute-list {{ afi_config.distribute_list.export }} out +{% endif %} +{% if afi_config.distribute_list.import is defined and afi_config.distribute_list.import is not none %} + neighbor {{ neighbor }} distribute-list {{ afi_config.distribute_list.import }} in +{% endif %} +{% endif %} +{% if afi_config.filter_list is defined and afi_config.filter_list is not none %} +{% if afi_config.filter_list.export is defined and afi_config.filter_list.export is not none %} + neighbor {{ neighbor }} filter-list {{ afi_config.filter_list.export }} out +{% endif %} +{% if afi_config.filter_list.import is defined and afi_config.filter_list.import is not none %} + neighbor {{ neighbor }} filter-list {{ afi_config.filter_list.import }} in +{% endif %} +{% endif %} +{% if afi_config.maximum_prefix is defined and afi_config.maximum_prefix is not none %} + neighbor {{ neighbor }} maximum-prefix {{ afi_config.maximum_prefix }} +{% endif %} +{% if afi_config.nexthop_self is defined %} + neighbor {{ neighbor }} next-hop-self {{ 'force' if afi_config.nexthop_self.force is defined }} +{% endif %} +{% if afi_config.route_server_client is defined %} + neighbor {{ neighbor }} route-server-client +{% endif %} +{% if afi_config.route_map is defined and afi_config.route_map is not none %} +{% if afi_config.route_map.export is defined and afi_config.route_map.export is not none %} + neighbor {{ neighbor }} route-map {{ afi_config.route_map.export }} out +{% endif %} +{% if afi_config.route_map.import is defined and afi_config.route_map.import is not none %} + neighbor {{ neighbor }} route-map {{ afi_config.route_map.import }} in +{% endif %} +{% endif %} +{% if afi_config.prefix_list is defined and afi_config.prefix_list is not none %} +{% if afi_config.prefix_list.export is defined and afi_config.prefix_list.export is not none %} + neighbor {{ neighbor }} prefix-list {{ afi_config.prefix_list.export }} out +{% endif %} +{% if afi_config.prefix_list.import is defined and afi_config.prefix_list.import is not none %} + neighbor {{ neighbor }} prefix-list {{ afi_config.prefix_list.import }} in +{% endif %} +{% endif %} +{% if afi_config.soft_reconfiguration is defined and afi_config.soft_reconfiguration.inbound is defined %} + neighbor {{ neighbor }} soft-reconfiguration inbound +{% endif %} +{% if afi_config.unsuppress_map is defined and afi_config.unsuppress_map is not none %} + neighbor {{ neighbor }} unsuppress-map {{ afi_config.unsuppress_map }} +{% endif %} +{% if afi_config.disable_send_community is defined and afi_config.disable_send_community.extended is defined %} + no neighbor {{ neighbor }} send-community extended +{% endif %} +{% if afi_config.disable_send_community is defined and afi_config.disable_send_community.standard is defined %} + no neighbor {{ neighbor }} send-community standard +{% endif %} + neighbor {{ neighbor }} activate + exit-address-family + ! +{% endfor %} +{% endif %} +{% endmacro %} +! +router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none }} +{% if parameters is defined and parameters.ebgp_requires_policy is defined %} + bgp ebgp-requires-policy +{% else %} + no bgp ebgp-requires-policy +{% endif %} +{% if parameters is defined and parameters.default is defined and parameters.default.no_ipv4_unicast is defined %} +{# Option must be set before any neighbor - see https://phabricator.vyos.net/T3463 #} + no bgp default ipv4-unicast +{% endif %} +{# Workaround for T2100 until we have decided about a migration script #} + no bgp network import-check +{% if address_family is defined and address_family is not none %} +{% for afi, afi_config in address_family.items() %} + ! +{% if afi == 'ipv4_unicast' %} + address-family ipv4 unicast +{% elif afi == 'ipv4_multicast' %} + address-family ipv4 multicast +{% elif afi == 'ipv4_labeled_unicast' %} + address-family ipv4 labeled-unicast +{% elif afi == 'ipv4_vpn' %} + address-family ipv4 vpn +{% elif afi == 'ipv4_flowspec' %} + address-family ipv4 flowspec +{% elif afi == 'ipv6_unicast' %} + address-family ipv6 unicast +{% elif afi == 'ipv6_multicast' %} + address-family ipv6 multicast +{% elif afi == 'ipv6_labeled_unicast' %} + address-family ipv6 labeled-unicast +{% elif afi == 'ipv6_vpn' %} + address-family ipv6 vpn +{% elif afi == 'ipv6_flowspec' %} + address-family ipv6 flowspec +{% elif afi == 'l2vpn_evpn' %} + address-family l2vpn evpn +{% endif %} +{% if afi_config.aggregate_address is defined and afi_config.aggregate_address is not none %} +{% for ip in afi_config.aggregate_address %} + aggregate-address {{ ip }}{{ ' as-set' if afi_config.aggregate_address[ip].as_set is defined }}{{ ' summary-only' if afi_config.aggregate_address[ip].summary_only is defined }} +{% endfor %} +{% endif %} +{% if afi_config.maximum_paths is defined and afi_config.maximum_paths.ebgp is defined and afi_config.maximum_paths.ebgp is not none %} + maximum-paths {{ afi_config.maximum_paths.ebgp }} +{% endif %} +{% if afi_config.maximum_paths is defined and afi_config.maximum_paths.ibgp is defined and afi_config.maximum_paths.ibgp is not none %} + maximum-paths ibgp {{ afi_config.maximum_paths.ibgp }} +{% endif %} +{% if afi_config.redistribute is defined and afi_config.redistribute is not none %} +{% for protocol in afi_config.redistribute %} +{% if protocol == 'table' %} + redistribute table {{ afi_config.redistribute[protocol].table }} +{% else %} +{% set redistribution_protocol = protocol %} +{% if protocol == 'ospfv3' %} +{% set redistribution_protocol = 'ospf6' %} +{% endif %} + redistribute {{ redistribution_protocol }}{% if afi_config.redistribute[protocol].metric is defined %} metric {{ afi_config.redistribute[protocol].metric }}{% endif %}{% if afi_config.redistribute[protocol].route_map is defined %} route-map {{ afi_config.redistribute[protocol].route_map }}{% endif %} +{####### we need this blank line!! #######} + +{% endif %} +{% endfor %} +{% endif %} +{% if afi_config.network is defined and afi_config.network is not none %} +{% for network in afi_config.network %} + network {{ network }}{% if afi_config.network[network].route_map is defined %} route-map {{ afi_config.network[network].route_map }}{% endif %}{% if afi_config.network[network].backdoor is defined %} backdoor{% endif %}{% if afi_config.network[network].rd is defined and afi_config.network[network].label is defined%} rd {{ afi_config.network[network].rd }} label {{ afi_config.network[network].label }}{% endif %} +{####### we need this blank line!! #######} + +{% endfor %} +{% endif %} +{% if afi_config.advertise is defined and afi_config.advertise is not none %} +{% for adv_afi, adv_afi_config in afi_config.advertise.items() %} +{% if adv_afi_config.unicast is defined and adv_afi_config.unicast is not none %} + advertise {{ adv_afi }} unicast {{ 'route-map ' ~ adv_afi_config.unicast.route_map if adv_afi_config.unicast.route_map is defined }} +{% endif %} +{% endfor %} +{% endif %} +{% if afi_config.distance is defined and afi_config.distance is not none %} +{% if afi_config.distance is defined and afi_config.distance.external is defined and afi_config.distance.internal is defined and afi_config.distance.local is defined %} + distance bgp {{ afi_config.distance.external }} {{ afi_config.distance.internal }} {{ afi_config.distance.local }} +{% endif %} +{% if afi_config.distance.prefix is defined and afi_config.distance.prefix is not none %} +{% for prefix in afi_config.distance.prefix %} + distance {{ afi_config.distance.prefix[prefix].distance }} {{ prefix }} +{% endfor %} +{% endif %} +{% endif %} +{% if afi_config.local_install is defined and afi_config.local_install is not none %} +{% for interface in afi_config.local_install.interface %} + local-install {{ interface }} +{% endfor %} +{% endif %} +{% if afi_config.advertise_all_vni is defined %} + advertise-all-vni +{% endif %} +{% if afi_config.advertise_default_gw is defined %} + advertise-default-gw +{% endif %} +{% if afi_config.advertise_pip is defined and afi_config.advertise_pip is not none %} + advertise-pip ip {{ afi_config.advertise_pip }} +{% endif %} +{% if afi_config.advertise_svi_ip is defined %} + advertise-svi-ip +{% endif %} +{% if afi_config.rt_auto_derive is defined %} + autort rfc8365-compatible +{% endif %} +{% if afi_config.flooding is defined and afi_config.flooding.disable is defined %} + flooding disable +{% endif %} +{% if afi_config.flooding is defined and afi_config.flooding.head_end_replication is defined %} + flooding head-end-replication +{% endif %} +{% if afi_config.rd is defined and afi_config.rd is not none %} + rd {{ afi_config.rd }} +{% endif %} +{% if afi_config.route_target is defined and afi_config.route_target is not none %} +{% if afi_config.route_target.both is defined and afi_config.route_target.both is not none %} + route-target both {{ afi_config.route_target.both }} +{% endif %} +{% if afi_config.route_target.export is defined and afi_config.route_target.export is not none %} + route-target export {{ afi_config.route_target.export }} +{% endif %} +{% if afi_config.route_target.import is defined and afi_config.route_target.import is not none %} + route-target import {{ afi_config.route_target.import }} +{% endif %} +{% endif %} +{% if afi_config.vni is defined and afi_config.vni is not none %} +{% for vni, vni_config in afi_config.vni.items() %} + vni {{ vni }} +{% if vni_config.advertise_default_gw is defined %} + advertise-default-gw +{% endif %} +{% if vni_config.advertise_svi_ip is defined %} + advertise-svi-ip +{% endif %} +{% if vni_config.rd is defined and vni_config.rd is not none %} + rd {{ vni_config.rd }} +{% endif %} +{% if vni_config.route_target is defined and vni_config.route_target is not none %} +{% if vni_config.route_target.both is defined and vni_config.route_target.both is not none %} + route-target both {{ vni_config.route_target.both }} +{% endif %} +{% if vni_config.route_target.export is defined and vni_config.route_target.export is not none %} + route-target export {{ vni_config.route_target.export }} +{% endif %} +{% if vni_config.route_target.import is defined and vni_config.route_target.import is not none %} + route-target import {{ vni_config.route_target.import }} +{% endif %} +{% endif %} + exit-vni +{% endfor %} +{% endif %} + exit-address-family +{% endfor %} +{% endif %} + ! +{% if peer_group is defined and peer_group is not none %} +{% for peer, config in peer_group.items() %} +{{ bgp_neighbor(peer, config, true) }} +{% endfor %} +{% endif %} + ! +{% if neighbor is defined and neighbor is not none %} +{% for peer, config in neighbor.items() %} +{{ bgp_neighbor(peer, config) }} +{% endfor %} +{% endif %} + ! +{% if listen is defined %} +{% if listen.limit is defined and listen.limit is not none %} + bgp listen limit {{ listen.limit }} +{% endif %} +{% for prefix, options in listen.range.items() %} +{% if options.peer_group is defined and options.peer_group is not none %} + bgp listen range {{ prefix }} peer-group {{ options.peer_group }} +{% endif %} +{% endfor %} +{% endif %} +{% if parameters is defined %} +{% if parameters.always_compare_med is defined %} + bgp always-compare-med +{% endif %} +{% if parameters.bestpath is defined and parameters.bestpath is not none %} +{% if parameters.bestpath.compare_routerid is defined %} + bgp bestpath compare-routerid +{% endif %} +{% if parameters.bestpath.as_path is defined and parameters.bestpath.as_path is not none %} +{% for option in parameters.bestpath.as_path %} + bgp bestpath as-path {{ option|replace('_', '-') }} +{% endfor %} +{% endif %} +{% if parameters.bestpath.med is defined and parameters.bestpath.med is not none %} + bgp bestpath med {{ 'confed' if parameters.bestpath.med.confed is defined }} {{ 'missing-as-worst' if parameters.bestpath.med.missing_as_worst is defined }} +{% endif %} +{% endif %} +{% if parameters.cluster_id is defined and parameters.cluster_id is not none %} + bgp cluster-id {{ parameters.cluster_id }} +{% endif %} +{% if parameters.confederation is defined and parameters.confederation is not none %} +{% if parameters.confederation.identifier is defined and parameters.confederation.identifier is not none %} + bgp confederation identifier {{ parameters.confederation.identifier }} +{% endif %} +{% if parameters.confederation.peers is defined and parameters.confederation.peers is not none %} + bgp confederation peers {{ parameters.confederation.peers }} +{% endif %} +{% endif %} +{% if parameters.dampening is defined and parameters.dampening is defined and parameters.dampening.half_life is defined and parameters.dampening.half_life is not none %} +{# Doesn't work in current FRR configuration; vtysh (bgp dampening 16 751 2001 61) #} + bgp dampening {{ parameters.dampening.half_life }} {{ parameters.dampening.re_use if parameters.dampening.re_use is defined }} {{ parameters.dampening.start_suppress_time if parameters.dampening.start_suppress_time is defined }} {{ parameters.dampening.max_suppress_time if parameters.dampening.max_suppress_time is defined }} +{% endif %} +{% if parameters.default is defined and parameters.default is not none %} +{% if parameters.default.local_pref is defined and parameters.default.local_pref is not none %} + bgp default local-preference {{ parameters.default.local_pref }} +{% endif %} +{% endif %} +{% if parameters.deterministic_med is defined %} + bgp deterministic-med +{% endif %} +{% if parameters.distance is defined and parameters.distance is not none %} +{% if parameters.distance.global is defined and parameters.distance.global.external is defined and parameters.distance.global.internal is defined and parameters.distance.global.local is defined %} + distance bgp {{ parameters.distance.global.external }} {{ parameters.distance.global.internal }} {{ parameters.distance.global.local }} +{% endif %} +{% if parameters.distance.prefix is defined and parameters.distance.prefix is not none %} +{% for prefix in parameters.distance.prefix %} + distance {{ parameters.distance.prefix[prefix].distance }} {{ prefix }} +{% endfor %} +{% endif %} +{% endif %} +{% if parameters.graceful_restart is defined %} + bgp graceful-restart {{ 'stalepath-time ' ~ parameters.graceful_restart.stalepath_time if parameters.graceful_restart.stalepath_time is defined }} +{% endif %} +{% if parameters.graceful_shutdown is defined %} + bgp graceful-shutdown +{% endif %} +{% if parameters.log_neighbor_changes is defined %} + bgp log-neighbor-changes +{% endif %} +{% if parameters.network_import_check is defined %} + bgp network import-check +{% endif %} +{% if parameters.no_client_to_client_reflection is defined %} + no bgp client-to-client reflection +{% endif %} +{% if parameters.no_fast_external_failover is defined %} + no bgp fast-external-failover +{% endif %} +{% if parameters.router_id is defined and parameters.router_id is not none %} + bgp router-id {{ parameters.router_id }} +{% endif %} +{% endif %} +{% if timers is defined and timers.keepalive is defined and timers.holdtime is defined %} + timers bgp {{ timers.keepalive }} {{ timers.holdtime }} +{% endif %} + end +! \ No newline at end of file diff --git a/data/templates/frr/isis.frr.tmpl b/data/templates/frr/isis.frr.tmpl index c74ac3101..433f10892 100644 --- a/data/templates/frr/isis.frr.tmpl +++ b/data/templates/frr/isis.frr.tmpl @@ -1,13 +1,4 @@ ! -{% if vrf is defined and vrf is not none and route_map is defined and route_map is not none %} -vrf {{ vrf }} - ip protocol isis route-map {{ route_map }} - exit-vrf -! -{% elif route_map is defined and route_map is not none %} -ip protocol isis route-map {{ route_map }} -{% endif %} -! router isis VyOS {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} net {{ net }} {% if dynamic_hostname is defined %} diff --git a/data/templates/frr/ospf.frr.tmpl b/data/templates/frr/ospf.frr.tmpl index 6283ad4e5..36aa699a9 100644 --- a/data/templates/frr/ospf.frr.tmpl +++ b/data/templates/frr/ospf.frr.tmpl @@ -50,15 +50,6 @@ interface {{ iface }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% endfor %} {% endif %} ! -{% if vrf is defined and vrf is not none and route_map is defined and route_map is not none %} -vrf {{ vrf }} - ip protocol ospf route-map {{ route_map }} - exit-vrf -! -{% elif route_map is defined and route_map is not none %} -ip protocol ospf route-map {{ route_map }} -{% endif %} -! router ospf {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% if access_list is defined and access_list is not none %} {% for acl, acl_config in access_list.items() %} diff --git a/data/templates/frr/vrf.route-map.frr.tmpl b/data/templates/frr/vrf.route-map.frr.tmpl new file mode 100644 index 000000000..cb0e07616 --- /dev/null +++ b/data/templates/frr/vrf.route-map.frr.tmpl @@ -0,0 +1,10 @@ +! +{% if vrf is defined and vrf is not none and route_map is defined and route_map is not none %} +vrf {{ vrf }} + ip protocol {{ protocol }} route-map {{ route_map }} + exit-vrf +! +{% elif route_map is defined and route_map is not none %} +ip protocol {{ protocol }} route-map {{ route_map }} +{% endif %} +! diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 08697eebf..0ed66657c 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -144,6 +144,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): def tearDown(self): self.cli_delete(['policy']) + self.cli_delete(['vrf']) self.cli_delete(base_path) self.cli_commit() @@ -624,6 +625,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.cli_set(vrf_base + ['table', table]) self.cli_set(vrf_base + ['protocols', 'bgp', 'local-as', ASN]) self.cli_set(vrf_base + ['protocols', 'bgp', 'parameters', 'router-id', router_id]) + self.cli_set(vrf_base + ['protocols', 'bgp', 'route-map', route_map_in]) table = str(int(table) + 1000) self.cli_commit() @@ -631,9 +633,16 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): for vrf in vrfs: # Verify FRR bgpd configuration frrconfig = self.getFRRconfig(f'router bgp {ASN} vrf {vrf}') - self.assertIn(f'router bgp {ASN} vrf {vrf}', frrconfig) self.assertIn(f' bgp router-id {router_id}', frrconfig) + # CCC: Currently this is not working as FRR() class does not support + # route-maps for multiple vrfs because the modify_section() only works + # on lines and not text blocks. + # + # vrfconfig = self.getFRRconfig(f'vrf {vrf}') + # zebra_route_map = f' ip protocol bgp route-map {route_map_in}' + # self.assertIn(zebra_route_map, vrfconfig) + if __name__ == '__main__': unittest.main(verbosity=2) \ No newline at end of file diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index 2b0cb1fe2..a51fe6d72 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -233,10 +233,14 @@ def verify(bgp): def generate(bgp): if not bgp or 'deleted' in bgp: - bgp['new_frr_config'] = '' + bgp['frr_bgpd_config'] = '' + bgp['frr_zebra_config'] = '' return None - bgp['new_frr_config'] = render_to_string('frr/bgp.frr.tmpl', bgp) + bgp['protocol'] = 'bgp' # required for frr/vrf.route-map.frr.tmpl + bgp['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.tmpl', bgp) + bgp['frr_bgpd_config'] = render_to_string('frr/bgpd.frr.tmpl', bgp) + return None def apply(bgp): @@ -248,7 +252,8 @@ def apply(bgp): # The route-map used for the FIB (zebra) is part of the zebra daemon frr_cfg.load_configuration(zebra_daemon) - frr_cfg.modify_section(r'\s+ip protocol bgp route-map [-a-zA-Z0-9.]+$', '', ' ') + frr_cfg.modify_section(r'(\s+)?ip protocol bgp route-map [-a-zA-Z0-9.]+$', '', '(\s|!)') + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', bgp['frr_zebra_config']) frr_cfg.commit_configuration(zebra_daemon) # Generate empty helper string which can be ammended to FRR commands, it @@ -259,14 +264,17 @@ def apply(bgp): frr_cfg.load_configuration(bgp_daemon) frr_cfg.modify_section(f'^router bgp \d+{vrf}$', '') - frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', bgp['new_frr_config']) + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', bgp['frr_bgpd_config']) frr_cfg.commit_configuration(bgp_daemon) - # If FRR config is blank, rerun the blank commit x times due to frr-reload + # If FRR config is blank, re-run the blank commit x times due to frr-reload # behavior/bug not properly clearing out on one commit. - if bgp['new_frr_config'] == '': + if bgp['frr_bgpd_config'] == '': for a in range(5): frr_cfg.commit_configuration(bgp_daemon) + if bgp['frr_zebra_config'] == '': + for a in range(5): + frr_cfg.commit_configuration(zebra_daemon) # Save configuration to /run/frr/config/frr.conf frr.save_configuration() diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py index e3f57c6ba..ef21e0055 100755 --- a/src/conf_mode/protocols_isis.py +++ b/src/conf_mode/protocols_isis.py @@ -190,10 +190,13 @@ def verify(isis): def generate(isis): if not isis or 'deleted' in isis: - isis['new_frr_config'] = '' + isis['frr_isisd_config'] = '' + isis['frr_zebra_config'] = '' return None - isis['new_frr_config'] = render_to_string('frr/isis.frr.tmpl', isis) + isis['protocol'] = 'isis' # required for frr/vrf.route-map.frr.tmpl + isis['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.tmpl', isis) + isis['frr_isisd_config'] = render_to_string('frr/isis.frr.tmpl', isis) return None def apply(isis): @@ -205,7 +208,8 @@ def apply(isis): # The route-map used for the FIB (zebra) is part of the zebra daemon frr_cfg.load_configuration(zebra_daemon) - frr_cfg.modify_section(r'\s+ip protocol isis route-map [-a-zA-Z0-9.]+$', '', ' ') + frr_cfg.modify_section(r'(\s+)?ip protocol isis route-map [-a-zA-Z0-9.]+$', '', '(\s|!)') + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', isis['frr_zebra_config']) frr_cfg.commit_configuration(zebra_daemon) # Generate empty helper string which can be ammended to FRR commands, it @@ -223,14 +227,17 @@ def apply(isis): for interface in isis[key]: frr_cfg.modify_section(f'^interface {interface}{vrf}$', '') - frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', isis['new_frr_config']) + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', isis['frr_isisd_config']) frr_cfg.commit_configuration(isis_daemon) # If FRR config is blank, rerun the blank commit x times due to frr-reload # behavior/bug not properly clearing out on one commit. - if isis['new_frr_config'] == '': + if isis['frr_isisd_config'] == '': for a in range(5): frr_cfg.commit_configuration(isis_daemon) + if isis['frr_zebra_config'] == '': + for a in range(5): + frr_cfg.commit_configuration(zebra_daemon) # Save configuration to /run/frr/config/frr.conf frr.save_configuration() diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index b5fef0c64..21eb8e447 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -171,10 +171,13 @@ def verify(ospf): def generate(ospf): if not ospf or 'deleted' in ospf: - ospf['new_frr_config'] = '' + ospf['frr_ospfd_config'] = '' + ospf['frr_zebra_config'] = '' return None - ospf['new_frr_config'] = render_to_string('frr/ospf.frr.tmpl', ospf) + ospf['protocol'] = 'ospf' # required for frr/vrf.route-map.frr.tmpl + ospf['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.tmpl', ospf) + ospf['frr_ospfd_config'] = render_to_string('frr/ospf.frr.tmpl', ospf) return None def apply(ospf): @@ -186,7 +189,8 @@ def apply(ospf): # The route-map used for the FIB (zebra) is part of the zebra daemon frr_cfg.load_configuration(zebra_daemon) - frr_cfg.modify_section(r'\s+ip protocol ospf route-map [-a-zA-Z0-9.]+$', '', ' ') + frr_cfg.modify_section(r'(\s+)?ip protocol ospf route-map [-a-zA-Z0-9.]+$', '', '(\s|!)') + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', ospf['frr_zebra_config']) frr_cfg.commit_configuration(zebra_daemon) # Generate empty helper string which can be ammended to FRR commands, it @@ -204,14 +208,17 @@ def apply(ospf): for interface in ospf[key]: frr_cfg.modify_section(f'^interface {interface}{vrf}$', '') - frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', ospf['new_frr_config']) + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', ospf['frr_ospfd_config']) frr_cfg.commit_configuration(ospf_daemon) # If FRR config is blank, rerun the blank commit x times due to frr-reload # behavior/bug not properly clearing out on one commit. - if ospf['new_frr_config'] == '': + if ospf['frr_ospfd_config'] == '': for a in range(5): frr_cfg.commit_configuration(ospf_daemon) + if ospf['frr_zebra_config'] == '': + for a in range(5): + frr_cfg.commit_configuration(zebra_daemon) # Save configuration to /run/frr/config/frr.conf frr.save_configuration() -- cgit v1.2.3