summaryrefslogtreecommitdiff
path: root/data/templates/frr
diff options
context:
space:
mode:
Diffstat (limited to 'data/templates/frr')
-rw-r--r--data/templates/frr/bfd.frr.tmpl56
-rw-r--r--data/templates/frr/bgp.frr.tmpl204
-rw-r--r--data/templates/frr/ospf.frr.tmpl60
-rw-r--r--data/templates/frr/ospfv3.frr.tmpl43
-rw-r--r--data/templates/frr/rip.frr.tmpl225
-rw-r--r--data/templates/frr/rip_ripng.frr.j236
-rw-r--r--data/templates/frr/ripng.frr.tmpl60
-rw-r--r--data/templates/frr/rpki.frr.tmpl17
-rw-r--r--data/templates/frr/static.frr.tmpl38
-rw-r--r--data/templates/frr/static_routes_macro.j215
-rw-r--r--data/templates/frr/vrf.frr.tmpl25
11 files changed, 563 insertions, 216 deletions
diff --git a/data/templates/frr/bfd.frr.tmpl b/data/templates/frr/bfd.frr.tmpl
index 9e5ad3379..16f8be92c 100644
--- a/data/templates/frr/bfd.frr.tmpl
+++ b/data/templates/frr/bfd.frr.tmpl
@@ -1,22 +1,44 @@
!
bfd
-{% for peer in old_peers %}
- no peer {{ peer.remote }}{% if peer.multihop %} multihop{% endif %}{% if peer.src_addr %} local-address {{ peer.src_addr }}{% endif %}{% if peer.src_if %} interface {{ peer.src_if }}{% endif %}
-
-{% endfor %}
-!
-{% for peer in new_peers %}
- peer {{ peer.remote }}{% if peer.multihop %} multihop{% endif %}{% if peer.src_addr %} local-address {{ peer.src_addr }}{% endif %}{% if peer.src_if %} interface {{ peer.src_if }}{% endif %}
-
- detect-multiplier {{ peer.multiplier }}
- receive-interval {{ peer.rx_interval }}
- transmit-interval {{ peer.tx_interval }}
-{% if peer.echo_mode %}
- echo-mode
+{% if profile is defined and profile is not none %}
+{% for profile_name, profile_config in profile.items() %}
+ profile {{ profile_name }}
+ detect-multiplier {{ profile_config.interval.multiplier }}
+ receive-interval {{ profile_config.interval.receive }}
+ transmit-interval {{ profile_config.interval.transmit }}
+{% if profile_config.interval['echo-interval'] is defined and profile_config.interval['echo-interval'] is not none %}
+ echo-interval {{ profile_config.interval['echo-interval'] }}
+{% endif %}
+{% if profile_config['echo-mode'] is defined %}
+ echo-mode
+{% endif %}
+{% if profile_config.shutdown is defined %}
+ shutdown
+{% else %}
+ no shutdown
+{% endif %}
+ exit
+{% endfor %}
{% endif %}
-{% if peer.echo_interval != '' %}
- echo-interval {{ peer.echo_interval }}
+{% if peer is defined and peer is not none %}
+{% for peer_name, peer_config in peer.items() %}
+ peer {{ peer_name }}{{ ' multihop' if peer_config.multihop is defined }}{{ ' local-address ' + peer_config.source.address if peer_config.source is defined and peer_config.source.address is defined }}{{ ' interface ' + peer_config.source.interface if peer_config.source is defined and peer_config.source.interface is defined }}
+ detect-multiplier {{ peer_config.interval.multiplier }}
+ receive-interval {{ peer_config.interval.receive }}
+ transmit-interval {{ peer_config.interval.transmit }}
+{% if peer_config.interval['echo-interval'] is defined and peer_config.interval['echo-interval'] is not none %}
+ echo-interval {{ peer_config.interval['echo-interval'] }}
+{% endif %}
+{% if peer_config['echo-mode'] is defined %}
+ echo-mode
+{% endif %}
+{% if peer_config.shutdown is defined %}
+ shutdown
+{% else %}
+ no shutdown
+{% endif %}
+ exit
+{% endfor %}
{% endif %}
- {% if not peer.shutdown %}no {% endif %}shutdown
-{% endfor %}
+ end
!
diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl
index 523fe75e3..30741aa27 100644
--- a/data/templates/frr/bgp.frr.tmpl
+++ b/data/templates/frr/bgp.frr.tmpl
@@ -9,6 +9,9 @@
{% if config.remote_as is defined and config.remote_as is not none %}
neighbor {{ neighbor }} remote-as {{ config.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 %}
@@ -43,12 +46,26 @@
{% 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 %}
@@ -70,80 +87,96 @@
{% endif %}
!
{% if config.address_family is defined and config.address_family is not none %}
-{% for af in config.address_family %}
-{% if af == 'ipv4_unicast' %}
+{% for afi, afi_config in config.address_family.items() %}
+{% if afi == 'ipv4_unicast' %}
address-family ipv4 unicast
-{% elif af == 'ipv6_unicast' %}
+{% elif afi == 'ipv6_unicast' %}
address-family ipv6 unicast
+{% 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 config.address_family[af].allowas_in is defined and config.address_family[af].allowas_in is not none %}
- neighbor {{ neighbor }} allowas-in {{ config.address_family[af].allowas_in.number if config.address_family[af].allowas_in.number is defined }}
+{% if afi_config.addpath_tx_per_as is defined %}
+ neighbor {{ neighbor }} addpath-tx-bestpath-per-AS
{% endif %}
-{% if config.address_family[af].remove_private_as is defined %}
+{% 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.remove_private_as is defined %}
neighbor {{ neighbor }} remove-private-AS
{% endif %}
-{% if config.address_family[af].route_reflector_client is defined %}
+{% if afi_config.route_reflector_client is defined %}
neighbor {{ neighbor }} route-reflector-client
{% endif %}
-{% if config.address_family[af].weight is defined and config.address_family[af].weight is not none %}
- neighbor {{ neighbor }} weight {{ config.address_family[af].weight }}
+{% 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 config.address_family[af].attribute_unchanged is defined and config.address_family[af].attribute_unchanged is not none %}
- neighbor {{ neighbor }} attribute-unchanged {{ 'as-path ' if config.address_family[af].attribute_unchanged.as_path is defined }}{{ 'med ' if config.address_family[af].attribute_unchanged.med is defined }}{{ 'next-hop ' if config.address_family[af].attribute_unchanged.next_hop is defined }}
+{% 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 config.address_family[af].capability is defined and config.address_family[af].capability.orf is defined and config.address_family[af].capability.orf.prefix_list is defined and config.address_family[af].capability.orf.prefix_list is not none %}
- neighbor {{ neighbor }} capability orf prefix-list {{ config.address_family[af].capability.orf.prefix_list }}
+{% 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 config.address_family[af].default_originate is defined %}
- neighbor {{ neighbor }} default-originate {{ 'route-map ' + config.address_family[af].default_originate.route_map if config.address_family[af].default_originate.route_map is defined }}
+{% 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 config.address_family[af].distribute_list is defined and config.address_family[af].distribute_list is not none %}
-{% if config.address_family[af].distribute_list.export is defined and config.address_family[af].distribute_list.export is not none %}
- neighbor {{ neighbor }} distribute-list {{ config.address_family[af].distribute_list.export }} out
+{% 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 config.address_family[af].distribute_list.import is defined and config.address_family[af].distribute_list.import is not none %}
- neighbor {{ neighbor }} distribute-list {{ config.address_family[af].distribute_list.import }} in
+{% 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 config.address_family[af].filter_list is defined and config.address_family[af].filter_list is not none %}
-{% if config.address_family[af].filter_list.export is defined and config.address_family[af].filter_list.export is not none %}
- neighbor {{ neighbor }} filter-list {{ config.address_family[af].filter_list.export }} out
+{% 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 config.address_family[af].filter_list.import is defined and config.address_family[af].filter_list.import is not none %}
- neighbor {{ neighbor }} filter-list {{ config.address_family[af].filter_list.import }} in
+{% 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 config.address_family[af].maximum_prefix is defined and config.address_family[af].maximum_prefix is not none %}
- neighbor {{ neighbor }} maximum-prefix {{ config.address_family[af].maximum_prefix }}
+{% 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 config.address_family[af].nexthop_self is defined %}
-{# https://phabricator.vyos.net/T1817 #}
- neighbor {{ neighbor }} next-hop-self {{ 'force' if config.address_family[af].nexthop_self.force is defined }}
+{% if afi_config.nexthop_self is defined %}
+ neighbor {{ neighbor }} next-hop-self {{ 'force' if afi_config.nexthop_self.force is defined }}
{% endif %}
-{% if config.address_family[af].route_server_client is defined %}
+{% if afi_config.route_server_client is defined %}
neighbor {{ neighbor }} route-server-client
{% endif %}
-{% if config.address_family[af].route_map is defined and config.address_family[af].route_map is not none %}
-{% if config.address_family[af].route_map.export is defined and config.address_family[af].route_map.export is not none %}
- neighbor {{ neighbor }} route-map {{ config.address_family[af].route_map.export }} out
+{% 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 config.address_family[af].route_map.import is defined and config.address_family[af].route_map.import is not none %}
- neighbor {{ neighbor }} route-map {{ config.address_family[af].route_map.import }} in
+{% 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 config.address_family[af].prefix_list is defined and config.address_family[af].prefix_list is not none %}
-{% if config.address_family[af].prefix_list.export is defined and config.address_family[af].prefix_list.export is not none %}
- neighbor {{ neighbor }} prefix-list {{ config.address_family[af].prefix_list.export }} out
+{% 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 config.address_family[af].prefix_list.import is defined and config.address_family[af].prefix_list.import is not none %}
- neighbor {{ neighbor }} prefix-list {{ config.address_family[af].prefix_list.import }} in
+{% 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 config.address_family[af].soft_reconfiguration is defined and config.address_family[af].soft_reconfiguration.inbound is defined %}
+{% if afi_config.soft_reconfiguration is defined and afi_config.soft_reconfiguration.inbound is defined %}
neighbor {{ neighbor }} soft-reconfiguration inbound
{% endif %}
-{% if config.address_family[af].unsuppress_map is defined and config.address_family[af].unsuppress_map is not none %}
- neighbor {{ neighbor }} unsuppress-map {{ config.address_family[af].unsuppress_map }}
+{% 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
@@ -153,41 +186,95 @@
{% endmacro %}
!
router bgp {{ asn }}
+{# Disable eBGP policy by default until there is a CLI option #}
+{# Workaround for T3183 until we have decided about a migration script #}
+ no bgp ebgp-requires-policy
+{# 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 af in address_family %}
+{% for afi, afi_config in address_family.items() %}
!
-{% if af == 'ipv4_unicast' %}
+{% if afi == 'ipv4_unicast' %}
address-family ipv4 unicast
-{% elif af == 'ipv6_unicast' %}
+{% elif afi == 'ipv6_unicast' %}
address-family ipv6 unicast
+{% elif afi == 'l2vpn_evpn' %}
+ address-family l2vpn evpn
{% endif %}
-{% if address_family[af].aggregate_address is defined and address_family[af].aggregate_address is not none %}
-{% for ip in address_family[af].aggregate_address %}
- aggregate-address {{ ip }}{{ ' as-set' if address_family[af].aggregate_address[ip].as_set is defined }}{{ ' summary-only' if address_family[af].aggregate_address[ip].summary_only is defined }}
+{% 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 address_family[af].redistribute is defined and address_family[af].redistribute is not none %}
-{% for protocol in address_family[af].redistribute %}
+{% if afi_config.redistribute is defined and afi_config.redistribute is not none %}
+{% for protocol in afi_config.redistribute %}
{% if protocol == 'table' %}
- redistribute table {{ address_family[af].redistribute[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 address_family[af].redistribute[protocol].metric is defined %} metric {{ address_family[af].redistribute[protocol].metric }}{% endif %}{% if address_family[af].redistribute[protocol].route_map is defined %} route-map {{ address_family[af].redistribute[protocol].route_map }}{% 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 address_family[af].network is defined and address_family[af].network is not none %}
-{% for network in address_family[af].network %}
- network {{ network }}{% if address_family[af].network[network].route_map is defined %} route-map {{ address_family[af].network[network].route_map }}{% endif %}{% if address_family[af].network[network].backdoor is defined %} backdoor{% 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 %}
{####### we need this blank line!! #######}
{% 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 %}
+ exit-vni
+{% endfor %}
+{% endif %}
exit-address-family
{% endfor %}
{% endif %}
@@ -293,6 +380,9 @@ router bgp {{ asn }}
{% 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 %}
diff --git a/data/templates/frr/ospf.frr.tmpl b/data/templates/frr/ospf.frr.tmpl
index 07699290c..140b6b406 100644
--- a/data/templates/frr/ospf.frr.tmpl
+++ b/data/templates/frr/ospf.frr.tmpl
@@ -1,4 +1,55 @@
!
+{% if interface is defined and interface is not none %}
+{% for iface, iface_config in interface.items() %}
+interface {{ iface }}
+{% if iface_config.authentication is defined and iface_config.authentication is not none %}
+{% if iface_config.authentication.plaintext_password is defined and iface_config.authentication.plaintext_password is not none %}
+ ip ospf authentication-key {{ iface_config.authentication.plaintext_password }}
+{% elif iface_config.authentication.md5 is defined %}
+ ip ospf authentication message-digest
+{% if iface_config.authentication.md5.key_id is defined and iface_config.authentication.md5.key_id is not none %}
+{% for key, key_config in iface_config.authentication.md5.key_id.items() %}
+ ip ospf message-digest-key {{ key }} md5 {{ key_config.md5_key }}
+{% endfor %}
+{% endif %}
+{% endif %}
+{% endif %}
+{% if iface_config.cost is defined and iface_config.cost is not none %}
+ ip ospf cost {{ iface_config.cost }}
+{% endif %}
+{% if iface_config.priority is defined and iface_config.priority is not none %}
+ ip ospf priority {{ iface_config.priority }}
+{% endif %}
+{% if iface_config.hello_interval is defined and iface_config.hello_interval is not none %}
+ ip ospf hello-interval {{ iface_config.hello_interval }}
+{% endif %}
+{% if iface_config.retransmit_interval is defined and iface_config.retransmit_interval is not none %}
+ ip ospf retransmit-interval {{ iface_config.retransmit_interval }}
+{% endif %}
+{% if iface_config.transmit_delay is defined and iface_config.transmit_delay is not none %}
+ ip ospf transmit-delay {{ iface_config.transmit_delay }}
+{% endif %}
+{% if iface_config.dead_interval is defined and iface_config.dead_interval is not none %}
+ ip ospf dead-interval {{ iface_config.dead_interval }}
+{% elif iface_config.hello_multiplier is defined and iface_config.hello_multiplier is not none %}
+ ip ospf dead-interval minimal hello-multiplier {{ iface_config.hello_multiplier }}
+{% endif %}
+{% if iface_config.bfd is defined %}
+ ip ospf bfd
+{% endif %}
+{% if iface_config.mtu_ignore is defined %}
+ ip ospf mtu-ignore
+{% endif %}
+{% if iface_config.network is defined and iface_config.network is not none %}
+ ip ospf network {{ iface_config.network }}
+{% endif %}
+{% if iface_config.bandwidth is defined and iface_config.bandwidth is not none %}
+ bandwidth {{ iface_config.bandwidth }}
+{% endif %}
+!
+{% endfor %}
+{% endif %}
+!
router ospf
{% if access_list is defined and access_list is not none %}
{% for acl, acl_config in access_list.items() %}
@@ -50,10 +101,8 @@ router ospf
{% endfor %}
{% endif %}
{% endif %}
-{% if link_config.dead_interval is defined and link_config.dead_interval is not none %}
-{# The following values are default values #}
- area {{ area_id }} virtual-link {{ link }} hello-interval {{ link_config.hello_interval }} retransmit-interval {{ link_config.retransmit_interval }} transmit-delay {{ link_config.retransmit_interval }} dead-interval {{ link_config.dead_interval }}
-{% endif %}
+{# The following values are default values #}
+ area {{ area_id }} virtual-link {{ link }} hello-interval {{ link_config.hello_interval }} retransmit-interval {{ link_config.retransmit_interval }} transmit-delay {{ link_config.transmit_delay }} dead-interval {{ link_config.dead_interval }}
{% endfor %}
{% endif %}
{% endfor %}
@@ -110,6 +159,9 @@ router ospf
passive-interface {{ interface }}
{% endfor %}
{% for interface in passive_interface_exclude if passive_interface_exclude is defined %}
+{% if interface.startswith('vlink') %}
+{% set interface = interface.upper() %}
+{% endif %}
no passive-interface {{ interface }}
{% endfor %}
{% if redistribute is defined and redistribute is not none %}
diff --git a/data/templates/frr/ospfv3.frr.tmpl b/data/templates/frr/ospfv3.frr.tmpl
index c63ef80dc..d08972a80 100644
--- a/data/templates/frr/ospfv3.frr.tmpl
+++ b/data/templates/frr/ospfv3.frr.tmpl
@@ -1,4 +1,47 @@
!
+{% if interface is defined and interface is not none %}
+{% for iface, iface_config in interface.items() %}
+interface {{ iface }}
+{% if iface_config.cost is defined and iface_config.cost is not none %}
+ ipv6 ospf6 cost {{ iface_config.cost }}
+{% endif %}
+{% if iface_config.priority is defined and iface_config.priority is not none %}
+ ipv6 ospf6 priority {{ iface_config.priority }}
+{% endif %}
+{% if iface_config.hello_interval is defined and iface_config.hello_interval is not none %}
+ ipv6 ospf6 hello-interval {{ iface_config.hello_interval }}
+{% endif %}
+{% if iface_config.retransmit_interval is defined and iface_config.retransmit_interval is not none %}
+ ipv6 ospf6 retransmit-interval {{ iface_config.retransmit_interval }}
+{% endif %}
+{% if iface_config.transmit_delay is defined and iface_config.transmit_delay is not none %}
+ ipv6 ospf6 transmit-delay {{ iface_config.transmit_delay }}
+{% endif %}
+{% if iface_config.dead_interval is defined and iface_config.dead_interval is not none %}
+ ipv6 ospf6 dead-interval {{ iface_config.dead_interval }}
+{% endif %}
+{% if iface_config.bfd is defined %}
+ ipv6 ospf6 bfd
+{% endif %}
+{% if iface_config.mtu_ignore is defined %}
+ ipv6 ospf6 mtu-ignore
+{% endif %}
+{% if iface_config.ifmtu is defined and iface_config.ifmtu is not none %}
+ ipv6 ospf6 ifmtu {{ iface_config.ifmtu }}
+{% endif %}
+{% if iface_config.network is defined and iface_config.network is not none %}
+ ipv6 ospf6 network {{ iface_config.network }}
+{% endif %}
+{% if iface_config.instance_id is defined and iface_config.instance_id is not none %}
+ ipv6 ospf6 instance-id {{ iface_config.instance_id }}
+{% endif %}
+{% if iface_config.passive is defined %}
+ ipv6 ospf6 passive
+{% endif %}
+!
+{% endfor %}
+{% endif %}
+!
router ospf6
{% if area is defined and area is not none %}
{% for area_id, area_config in area.items() %}
diff --git a/data/templates/frr/rip.frr.tmpl b/data/templates/frr/rip.frr.tmpl
index 83df4e203..bc92bddf9 100644
--- a/data/templates/frr/rip.frr.tmpl
+++ b/data/templates/frr/rip.frr.tmpl
@@ -1,143 +1,92 @@
!
-{% if rip_conf %}
-router rip
-{% if old_default_distance %}
-no distance {{old_default_distance}}
-{% endif %}
-{% if default_distance %}
-distance {{default_distance}}
-{% endif %}
-{% if old_default_originate %}
-no default-information originate
-{% endif %}
-{% if default_originate %}
-default-information originate
-{% endif %}
-{% if old_rip.default_metric %}
-no default-metric {{old_rip.default_metric}}
-{% endif %}
-{% if rip.default_metric %}
-default-metric {{rip.default_metric}}
-{% endif %}
-{% for protocol in old_rip.redist %}
-{% if old_rip.redist[protocol]['metric'] and old_rip.redist[protocol]['route_map'] %}
-no redistribute {{protocol}} metric {{rip.redist[protocol]['metric']}} route-map {{rip.redist[protocol]['route_map']}}
-{% elif old_rip.redist[protocol]['metric'] %}
-no redistribute {{protocol}} metric {{old_rip.redist[protocol]['metric']}}
-{% elif old_rip.redist[protocol]['route_map'] %}
-no redistribute {{protocol}} route-map {{old_rip.redist[protocol]['route_map']}}
-{% else %}
-no redistribute {{protocol}}
-{% endif %}
-{% endfor %}
-{% for protocol in rip.redist %}
-{% if rip.redist[protocol]['metric'] and rip.redist[protocol]['route_map'] %}
-redistribute {{protocol}} metric {{rip.redist[protocol]['metric']}} route-map {{rip.redist[protocol]['route_map']}}
-{% elif rip.redist[protocol]['metric'] %}
-redistribute {{protocol}} metric {{rip.redist[protocol]['metric']}}
-{% elif rip.redist[protocol]['route_map'] %}
-redistribute {{protocol}} route-map {{rip.redist[protocol]['route_map']}}
-{% else %}
-redistribute {{protocol}}
-{% endif %}
-{% endfor %}
-{% for iface in old_rip.distribute %}
-{% if old_rip.distribute[iface].iface_access_list_in %}
-no distribute-list {{old_rip.distribute[iface].iface_access_list_in}} in {{iface}}
-{% endif %}
-{% if old_rip.distribute[iface].iface_access_list_out %}
-no distribute-list {{old_rip.distribute[iface].iface_access_list_out}} out {{iface}}
-{% endif %}
-{% if old_rip.distribute[iface].iface_prefix_list_in %}
-no distribute-list prefix {{old_rip.distribute[iface].iface_prefix_list_in}} in {{iface}}
-{% endif %}
-{% if old_rip.distribute[iface].iface_prefix_list_out %}
-no distribute-list prefix {{old_rip.distribute[iface].iface_prefix_list_out}} out {{iface}}
-{% endif %}
-{% endfor %}
-{% for iface in rip.distribute %}
-{% if rip.distribute[iface].iface_access_list_in %}
-distribute-list {{rip.distribute[iface].iface_access_list_in}} in {{iface}}
-{% endif %}
-{% if rip.distribute[iface].iface_access_list_out %}
-distribute-list {{rip.distribute[iface].iface_access_list_out}} out {{iface}}
-{% endif %}
-{% if rip.distribute[iface].iface_prefix_list_in %}
-distribute-list prefix {{rip.distribute[iface].iface_prefix_list_in}} in {{iface}}
+{# RIP key-chain definition #}
+{% if interface is defined and interface is not none %}
+{% for iface, iface_config in interface.items() %}
+{% if iface_config.authentication is defined and iface_config.authentication.md5 is defined and iface_config.authentication.md5 is not none %}
+key chain {{ iface }}-rip
+{% for key_id, key_options in iface_config.authentication.md5.items() %}
+ key {{ key_id }}
+{% if key_options.password is defined and key_options.password is not none %}
+ key-string {{ key_options.password }}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% endfor %}
{% endif %}
-{% if rip.distribute[iface].iface_prefix_list_out %}
-distribute-list prefix {{rip.distribute[iface].iface_prefix_list_out}} out {{iface}}
-{% endif %}
-{% endfor %}
-{% if old_rip.dist_acl_in %}
-no distribute-list {{old_rip.dist_acl_in}} in
-{% endif %}
-{% if rip.dist_acl_in %}
-distribute-list {{rip.dist_acl_in}} in
-{% endif %}
-{% if old_rip.dist_acl_out %}
-no distribute-list {{old_rip.dist_acl_out}} out
-{% endif %}
-{% if rip.dist_acl_out %}
-distribute-list {{rip.dist_acl_out}} out
-{% endif %}
-{% if old_rip.dist_prfx_in %}
-no distribute-list prefix {{old_rip.dist_prfx_in}} in
-{% endif %}
-{% if rip.dist_prfx_in %}
-distribute-list prefix {{rip.dist_prfx_in}} in
-{% endif %}
-{% if old_rip.dist_prfx_out %}
-no distribute-list prefix {{old_rip.dist_prfx_out}} out
-{% endif %}
-{% if rip.dist_prfx_out %}
-distribute-list prefix {{rip.dist_prfx_out}} out
-{% endif %}
-{% for network in old_rip.networks %}
-no network {{network}}
-{% endfor %}
-{% for network in rip.networks %}
-network {{network}}
-{% endfor %}
-{% for iface in old_rip.ifaces %}
-no network {{iface}}
-{% endfor %}
-{% for iface in rip.ifaces %}
-network {{iface}}
-{% endfor %}
-{% for neighbor in old_rip.neighbors %}
-no neighbor {{neighbor}}
-{% endfor %}
-{% for neighbor in rip.neighbors %}
-neighbor {{neighbor}}
-{% endfor %}
-{% for net in rip.net_distance %}
-{% if rip.net_distance[net].access_list and rip.net_distance[net].distance %}
-distance {{rip.net_distance[net].distance}} {{net}} {{rip.net_distance[net].access_list}}
-{% else %}
-distance {{rip.net_distance[net].distance}} {{net}}
-{% endif %}
-{% endfor %}
-{% for passive_iface in old_rip.passive_iface %}
-no passive-interface {{passive_iface}}
-{% endfor %}
-{% for passive_iface in rip.passive_iface %}
-passive-interface {{passive_iface}}
-{% endfor %}
-{% for route in old_rip.route %}
-no route {{route}}
-{% endfor %}
-{% for route in rip.route %}
-route {{route}}
-{% endfor %}
-{% if old_rip.timer_update or old_rip.timer_timeout or old_rip.timer_garbage %}
-no timers basic
-{% endif %}
-{% if rip.timer_update or rip.timer_timeout or rip.timer_garbage %}
-timers basic {{rip.timer_update}} {{rip.timer_timeout}} {{rip.timer_garbage}}
+!
+{# Interface specific configuration #}
+{% if interface is defined and interface is not none %}
+{% for iface, iface_config in interface.items() %}
+interface {{ iface }}
+{% if iface_config.authentication is defined and iface_config.authentication.plaintext_password is defined and iface_config.authentication.plaintext_password is not none %}
+ ip rip authentication mode text
+ ip rip authentication string {{ iface_config.authentication.plaintext_password }}
+{% elif iface_config.authentication is defined and iface_config.authentication.md5 is defined and iface_config.authentication.md5 is not none %}
+ ip rip authentication key-chain {{ iface }}-rip
+ ip rip authentication mode md5
+{% endif %}
+{% if iface_config.split_horizon is defined and iface_config.split_horizon.disable is defined %}
+ no ip rip split-horizon
+{% endif %}
+{% if iface_config.split_horizon is defined and iface_config.split_horizon.poison_reverse is defined %}
+ ip rip split-horizon poisoned-reverse
+{% endif %}
+{% endfor %}
{% endif %}
!
-{% else %}
-no router rip
+router rip
+{% if default_distance is defined and default_distance is not none %}
+ distance {{ default_distance }}
+{% endif %}
+{% if network_distance is defined and network_distance is not none %}
+{% for network, network_config in network_distance.items() %}
+{% if network_config.distance is defined and network_config.distance is not none %}
+ distance {{ network_config.distance }} {{ network }}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if neighbor is defined and neighbor is not none %}
+{% for address in neighbor %}
+ neighbor {{ address }}
+{% endfor %}
+{% endif %}
+{% if distribute_list is defined and distribute_list is not none %}
+{% if distribute_list.access_list is defined and distribute_list.access_list is not none %}
+{% if distribute_list.access_list.in is defined and distribute_list.access_list.in is not none %}
+ distribute-list {{ distribute_list.access_list.in }} in
+{% endif %}
+{% if distribute_list.access_list.out is defined and distribute_list.access_list.out is not none %}
+ distribute-list {{ distribute_list.access_list.out }} out
+{% endif %}
+{% endif %}
+{% if distribute_list.interface is defined and distribute_list.interface is not none %}
+{% for interface, interface_config in distribute_list.interface.items() %}
+{% if interface_config.access_list is defined and interface_config.access_list is not none %}
+{% if interface_config.access_list.in is defined and interface_config.access_list.in is not none %}
+ distribute-list {{ interface_config.access_list.in }} in {{ interface }}
+{% endif %}
+{% if interface_config.access_list.out is defined and interface_config.access_list.out is not none %}
+ distribute-list {{ interface_config.access_list.out }} out {{ interface }}
+{% endif %}
+{% endif %}
+{% if interface_config.prefix_list is defined and interface_config.prefix_list is not none %}
+{% if interface_config.prefix_list.in is defined and interface_config.prefix_list.in is not none %}
+ distribute-list prefix {{ interface_config.prefix_list.in }} in {{ interface }}
+{% endif %}
+{% if interface_config.prefix_list.out is defined and interface_config.prefix_list.out is not none %}
+ distribute-list prefix {{ interface_config.prefix_list.out }} out {{ interface }}
+{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if distribute_list.prefix_list is defined and distribute_list.prefix_list is not none %}
+{% if distribute_list.prefix_list.in is defined and distribute_list.prefix_list.in is not none %}
+ distribute-list prefix {{ distribute_list.prefix_list.in }} in
+{% endif %}
+{% if distribute_list.prefix_list.out is defined and distribute_list.prefix_list.out is not none %}
+ distribute-list prefix {{ distribute_list.prefix_list.out }} out
+{% endif %}
+{% endif %}
+{% endif %}
+{% include 'frr/rip_ripng.frr.j2' %}
!
-{% endif %}
diff --git a/data/templates/frr/rip_ripng.frr.j2 b/data/templates/frr/rip_ripng.frr.j2
new file mode 100644
index 000000000..de180ee6b
--- /dev/null
+++ b/data/templates/frr/rip_ripng.frr.j2
@@ -0,0 +1,36 @@
+{% if default_information is defined and default_information.originate is defined %}
+ default-information originate
+{% endif %}
+{% if default_metric is defined and default_metric is not none %}
+ default-metric {{ default_metric }}
+{% endif %}
+{% if passive_interface is defined and passive_interface is not none %}
+{% for interface in passive_interface %}
+ passive-interface {{ interface }}
+{% endfor %}
+{% endif %}
+{% if network is defined and network is not none %}
+{% for prefix in network %}
+ network {{ prefix }}
+{% endfor %}
+{% endif %}
+{% if interface is defined and interface is not none %}
+{% for ifname in interface %}
+ network {{ ifname }}
+{% endfor %}
+{% endif %}
+{% if route is defined and route is not none %}
+{% for prefix in route %}
+ route {{ prefix }}
+{% endfor %}
+{% endif %}
+{# timers have default values #}
+ timers basic {{ timers['update'] }} {{ timers.timeout }} {{ timers.garbage_collection }}
+{% if redistribute is defined and redistribute is not none %}
+{% for protocol, protocol_config in redistribute.items() %}
+{% if protocol == 'ospfv3' %}
+{% set protocol = 'ospf6' %}
+{% endif %}
+ redistribute {{ protocol }} {{ 'metric ' + protocol_config.metric if protocol_config.metric is defined }} {{ 'route-map ' + protocol_config.route_map if protocol_config.route_map is defined }}
+{% endfor %}
+{% endif %}
diff --git a/data/templates/frr/ripng.frr.tmpl b/data/templates/frr/ripng.frr.tmpl
new file mode 100644
index 000000000..25df15121
--- /dev/null
+++ b/data/templates/frr/ripng.frr.tmpl
@@ -0,0 +1,60 @@
+!
+{# Interface specific configuration #}
+{% if interface is defined and interface is not none %}
+{% for iface, iface_config in interface.items() %}
+interface {{ iface }}
+{% if iface_config.split_horizon is defined and iface_config.split_horizon.disable is defined %}
+ no ipv6 rip split-horizon
+{% endif %}
+{% if iface_config.split_horizon is defined and iface_config.split_horizon.poison_reverse is defined %}
+ ipv6 rip split-horizon poisoned-reverse
+{% endif %}
+{% endfor %}
+{% endif %}
+!
+router ripng
+{% if aggregate_address is defined and aggregate_address is not none %}
+{% for prefix in aggregate_address %}
+ aggregate-address {{ prefix }}
+{% endfor %}
+{% endif %}
+{% if distribute_list is defined and distribute_list is not none %}
+{% if distribute_list.access_list is defined and distribute_list.access_list is not none %}
+{% if distribute_list.access_list.in is defined and distribute_list.access_list.in is not none %}
+ ipv6 distribute-list {{ distribute_list.access_list.in }} in
+{% endif %}
+{% if distribute_list.access_list.out is defined and distribute_list.access_list.out is not none %}
+ ipv6 distribute-list {{ distribute_list.access_list.out }} out
+{% endif %}
+{% endif %}
+{% if distribute_list.interface is defined and distribute_list.interface is not none %}
+{% for interface, interface_config in distribute_list.interface.items() %}
+{% if interface_config.access_list is defined and interface_config.access_list is not none %}
+{% if interface_config.access_list.in is defined and interface_config.access_list.in is not none %}
+ ipv6 distribute-list {{ interface_config.access_list.in }} in {{ interface }}
+{% endif %}
+{% if interface_config.access_list.out is defined and interface_config.access_list.out is not none %}
+ ipv6 distribute-list {{ interface_config.access_list.out }} out {{ interface }}
+{% endif %}
+{% endif %}
+{% if interface_config.prefix_list is defined and interface_config.prefix_list is not none %}
+{% if interface_config.prefix_list.in is defined and interface_config.prefix_list.in is not none %}
+ ipv6 distribute-list prefix {{ interface_config.prefix_list.in }} in {{ interface }}
+{% endif %}
+{% if interface_config.prefix_list.out is defined and interface_config.prefix_list.out is not none %}
+ ipv6 distribute-list prefix {{ interface_config.prefix_list.out }} out {{ interface }}
+{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if distribute_list.prefix_list is defined and distribute_list.prefix_list is not none %}
+{% if distribute_list.prefix_list.in is defined and distribute_list.prefix_list.in is not none %}
+ ipv6 distribute-list prefix {{ distribute_list.prefix_list.in }} in
+{% endif %}
+{% if distribute_list.prefix_list.out is defined and distribute_list.prefix_list.out is not none %}
+ ipv6 distribute-list prefix {{ distribute_list.prefix_list.out }} out
+{% endif %}
+{% endif %}
+{% endif %}
+{% include 'frr/rip_ripng.frr.j2' %}
+!
diff --git a/data/templates/frr/rpki.frr.tmpl b/data/templates/frr/rpki.frr.tmpl
new file mode 100644
index 000000000..346a0caa9
--- /dev/null
+++ b/data/templates/frr/rpki.frr.tmpl
@@ -0,0 +1,17 @@
+!
+{# as FRR does not support deleting the entire rpki section we leave it in place even when it's empty #}
+rpki
+{% if cache is defined and cache is not none %}
+{% for peer, peer_config in cache.items() %}
+{# port is mandatory and preference uses a default value #}
+{% if peer_config.ssh is defined and peer_config.ssh.username is defined and peer_config.ssh.username is not none %}
+ rpki cache {{ peer }} {{ peer_config.port }} {{ peer_config.ssh.username }} {{ peer_config.ssh.private_key_file }} {{ peer_config.ssh.public_key_file }} {{ peer_config.ssh.known_hosts_file }} preference {{ peer_config.preference }}
+{% else %}
+ rpki cache {{ peer }} {{ peer_config.port }} preference {{ peer_config.preference }}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if polling_period is defined and polling_period is not none %}
+ rpki polling_period {{ polling_period }}
+{% endif %}
+!
diff --git a/data/templates/frr/static.frr.tmpl b/data/templates/frr/static.frr.tmpl
new file mode 100644
index 000000000..bb0ec80a5
--- /dev/null
+++ b/data/templates/frr/static.frr.tmpl
@@ -0,0 +1,38 @@
+{% from 'frr/static_routes_macro.j2' import static_routes %}
+!
+{# IPv4 routing #}
+{% if route is defined and route is not none %}
+{% for prefix, prefix_config in route.items() %}
+{{ static_routes('ip', prefix, prefix_config) }}
+{%- endfor -%}
+{% endif %}
+!
+{# IPv6 routing #}
+{% if route6 is defined and route6 is not none %}
+{% for prefix, prefix_config in route6.items() %}
+{{ static_routes('ipv6', prefix, prefix_config) }}
+{%- endfor -%}
+{% endif %}
+!
+{# Policy route tables #}
+{% if table is defined and table is not none %}
+{% for table_id, table_config in table.items() %}
+{% if table_config.route is defined and table_config.route is not none %}
+{% for prefix, prefix_config in table_config.route.items() %}
+{{ static_routes('ip', prefix, prefix_config, table_id) }}
+{%- endfor -%}
+{% endif %}
+!
+{% if table_config.route6 is defined and table_config.route6 is not none %}
+{% for prefix, prefix_config in table_config.route6.items() %}
+{{ static_routes('ipv6', prefix, prefix_config, table_id) }}
+{%- endfor -%}
+{% endif %}
+!
+{% endfor %}
+{% endif %}
+!
+{% if route_map is defined and route_map is not none %}
+ip protocol static route-map {{ route_map }}
+!
+{% endif %}
diff --git a/data/templates/frr/static_routes_macro.j2 b/data/templates/frr/static_routes_macro.j2
new file mode 100644
index 000000000..b24232ef3
--- /dev/null
+++ b/data/templates/frr/static_routes_macro.j2
@@ -0,0 +1,15 @@
+{% macro static_routes(ip_ipv6, prefix, prefix_config, table=None) %}
+{% if prefix_config.blackhole is defined %}
+{{ ip_ipv6 }} route {{ prefix }} blackhole {{ prefix_config.blackhole.distance if prefix_config.blackhole.distance is defined }} {{ 'tag ' + prefix_config.blackhole.tag if prefix_config.blackhole.tag is defined }} {{ 'table ' + table if table is defined and table is not none }}
+{% endif %}
+{% if prefix_config.interface is defined and prefix_config.interface is not none %}
+{% for interface, interface_config in prefix_config.interface.items() if interface_config.disable is not defined %}
+{{ ip_ipv6 }} route {{ prefix }} {{ interface }} {{ interface_config.distance if interface_config.distance is defined }} {{ 'nexthop-vrf ' + interface_config.vrf if interface_config.vrf is defined }} {{ 'table ' + table if table is defined and table is not none }}
+{% endfor %}
+{% endif %}
+{% if prefix_config.next_hop is defined and prefix_config.next_hop is not none %}
+{% for next_hop, next_hop_config in prefix_config.next_hop.items() if next_hop_config.disable is not defined %}
+{{ ip_ipv6 }} route {{ prefix }} {{ next_hop }} {{ next_hop_config.interface if next_hop_config.interface is defined }} {{ next_hop_config.distance if next_hop_config.distance is defined }} {{ 'nexthop-vrf ' + next_hop_config.vrf if next_hop_config.vrf is defined }} {{ 'table ' + table if table is defined and table is not none }}
+{% endfor %}
+{% endif %}
+{% endmacro %}
diff --git a/data/templates/frr/vrf.frr.tmpl b/data/templates/frr/vrf.frr.tmpl
new file mode 100644
index 000000000..8d3d8e9dd
--- /dev/null
+++ b/data/templates/frr/vrf.frr.tmpl
@@ -0,0 +1,25 @@
+{% from 'frr/static_routes_macro.j2' import static_routes %}
+!
+{% if vrf is defined and vrf is not none %}
+{% for vrf_name, vrf_config in vrf.items() %}
+vrf {{ vrf_name }}
+{% if vrf_config.vni is defined and vrf_config.vni is not none %}
+ vni {{ vrf_config.vni }}
+{% endif %}
+{% if vrf_config.static is defined and vrf_config.static is not none %}
+{# IPv4 routes #}
+{% if vrf_config.static.route is defined and vrf_config.static.route is not none %}
+{% for prefix, prefix_config in vrf_config.static.route.items() %}
+ {{ static_routes('ip', prefix, prefix_config) }}
+{%- endfor -%}
+{% endif %}
+{# IPv6 routes #}
+{% if vrf_config.static.route6 is defined and vrf_config.static.route6 is not none %}
+{% for prefix, prefix_config in vrf_config.static.route6.items() %}
+ {{ static_routes('ipv6', prefix, prefix_config) }}
+{%- endfor -%}
+{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+!