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.tmpl295
-rw-r--r--data/templates/frr/isis.frr.tmpl10
-rw-r--r--data/templates/frr/ospf.frr.tmpl183
-rw-r--r--data/templates/frr/ospfv3.frr.tmpl84
-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.tmpl49
-rw-r--r--data/templates/frr/static_routes_macro.j221
11 files changed, 791 insertions, 245 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 16355a1e5..53e62928b 100644
--- a/data/templates/frr/bgp.frr.tmpl
+++ b/data/templates/frr/bgp.frr.tmpl
@@ -9,6 +9,12 @@
{% 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 %}
@@ -24,7 +30,7 @@
neighbor {{ neighbor }} description {{ config.description }}
{% endif %}
{% if config.disable_capability_negotiation is defined %}
- neighbor {{ neighbor }} disable-capability-negotiation
+ 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 }}
@@ -43,87 +49,134 @@
{% 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 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
-{% elif 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.export }} in
+{% 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 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
-{% elif 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 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 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
-{% elif 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 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 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
-{% elif 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 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 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
@@ -132,62 +185,122 @@
{% endif %}
{% endmacro %}
!
-router bgp {{ asn }}
- no bgp default ipv4-unicast
+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 %}
+{# 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.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 {{ address_family[af].redistribute[protocol].table }}
+ redistribute table {{ afi_config.redistribute[protocol].table }}
{% else %}
- redistribute {{ 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 %}
+{% 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 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 %}
+{% 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 %}
!
-{# set protocols bgp xxxx maximum-paths ibgp x, Generated by default for afi_4 #}
-{# We don't have this parameter in afi_6. But this is supported in FRR #}
-{% if maximum_paths is defined and maximum_paths is not none %}
-{% if maximum_paths.ebgp is defined and maximum_paths.ebgp is not none %}
- !
- address-family ipv4 unicast
- maximum-paths {{ maximum_paths.ebgp }}
- exit-address-family
- !
-{% endif %}
-{% if maximum_paths.ibgp is defined and maximum_paths.ibgp is not none %}
- !
- address-family ipv4 unicast
- maximum-paths ibgp {{ maximum_paths.ibgp }}
- exit-address-family
- !
-{% endif %}
-{% endif %}
- !
{% if peer_group is defined and peer_group is not none %}
{% for peer, config in peer_group.items() %}
{{ bgp_neighbor(peer, config, true) }}
@@ -195,11 +308,21 @@ router bgp {{ asn }}
{% endif %}
!
{% if neighbor is defined and neighbor is not none %}
-{% for n, config in neighbor.items() %}
-{{ bgp_neighbor(n, config) }}
+{% 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
@@ -237,7 +360,6 @@ router bgp {{ asn }}
bgp default local-preference {{ parameters.default.local_pref }}
{% endif %}
{% if parameters.default.no_ipv4_unicast is defined %}
-{# We use this is parameter as default in template (5-th string) #}
no bgp default ipv4-unicast
{% endif %}
{% endif %}
@@ -261,6 +383,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 %}
@@ -280,8 +405,8 @@ router bgp {{ asn }}
{% if timers is defined and timers.keepalive is defined and timers.holdtime is defined %}
timers bgp {{ timers.keepalive }} {{ timers.holdtime }}
{% endif %}
- !
+!
{% if route_map is defined and route_map is not none %}
- ip protocol bgp route-map {{ route_map }}
+ip protocol bgp route-map {{ route_map }}
{% endif %}
- !
+!
diff --git a/data/templates/frr/isis.frr.tmpl b/data/templates/frr/isis.frr.tmpl
index 0477f2599..7f996b134 100644
--- a/data/templates/frr/isis.frr.tmpl
+++ b/data/templates/frr/isis.frr.tmpl
@@ -1,5 +1,5 @@
!
-router isis {{ process }}
+router isis VyOS {{ 'vrf ' + vrf if vrf is defined and vrf is not none }}
net {{ net }}
{% if dynamic_hostname is defined %}
hostname dynamic
@@ -133,8 +133,8 @@ router isis {{ process }}
!
{% if interface is defined and interface is not none %}
{% for iface, iface_config in interface.items() %}
-interface {{ iface }}
- ip router isis {{ process }}
+interface {{ iface }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }}
+ ip router isis VyOS
{% if iface_config.bfd is defined %}
isis bfd
{% endif %}
@@ -168,8 +168,8 @@ interface {{ iface }}
{% if iface_config.psnp_interval is defined and iface_config.psnp_interval is not none %}
isis psnp-interval {{ iface_config.psnp_interval }}
{% endif %}
-{% if iface_config.three_way_handshake is defined %}
- isis three-way-handshake
+{% if iface_config.no_three_way_handshake is defined %}
+ no isis three-way-handshake
{% endif %}
{% endfor %}
{% endif %}
diff --git a/data/templates/frr/ospf.frr.tmpl b/data/templates/frr/ospf.frr.tmpl
new file mode 100644
index 000000000..a47c64c89
--- /dev/null
+++ b/data/templates/frr/ospf.frr.tmpl
@@ -0,0 +1,183 @@
+!
+{% if interface is defined and interface is not none %}
+{% for iface, iface_config in interface.items() %}
+interface {{ iface }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }}
+{% 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 {{ '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() %}
+{% for protocol in acl_config.export if acl_config.export is defined %}
+ distribute-list {{ acl }} out {{ protocol }}
+{% endfor %}
+{% endfor %}
+{% endif %}
+{% if area is defined and area is not none %}
+{% for area_id, area_config in area.items() %}
+{% if area_config.area_type is defined and area_config.area_type is not none %}
+{% for type, type_config in area_config.area_type.items() if type != 'normal' %}
+ area {{ area_id }} {{ type }} {{ 'no-summary' if type_config.no_summary is defined }}
+{% if type_config.default_cost is defined and type_config.default_cost is not none %}
+ area {{ area_id }} default-cost {{ type_config.default_cost }}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if area_config.authentication is defined and area_config.authentication is not none %}
+ area {{ area_id }} authentication {{ 'message-digest' if area_config.authentication == 'md5' }}
+{% endif %}
+{% for network in area_config.network if area_config.network is defined %}
+ network {{ network }} area {{ area_id }}
+{% endfor %}
+{% if area_config.range is defined and area_config.range is not none %}
+{% for range, range_config in area_config.range.items() %}
+{% if range_config.cost is defined and range_config.cost is not none %}
+ area {{ area_id }} range {{ range }} cost {{ range_config.cost }}
+{% endif %}
+{% if range_config.not_advertise is defined %}
+ area {{ area_id }} range {{ range }} not-advertise
+{% endif %}
+{% if range_config.substitute is defined and range_config.substitute is not none %}
+ area {{ area_id }} range {{ range }} substitute {{ range_config.substitute }}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if area_config.shortcut is defined and area_config.shortcut is not none %}
+ area {{ area_id }} shortcut {{ area_config.shortcut }}
+{% endif %}
+{% if area_config.virtual_link is defined and area_config.virtual_link is not none %}
+{% for link, link_config in area_config.virtual_link.items() %}
+{% if link_config.authentication is defined and link_config.authentication is not none %}
+{% if link_config.authentication.plaintext_password is defined and link_config.authentication.plaintext_password is not none %}
+ area {{ area_id }} virtual-link {{ link }} authentication-key {{ link_config.authentication.plaintext_password }}
+{% elif link_config.authentication.md5 is defined and link_config.authentication.md5.key_id is defined and link_config.authentication.md5.key_id is not none %}
+{% for key, key_config in link_config.authentication.md5.key_id.items() %}
+ area {{ area_id }} virtual-link {{ link }} message-digest-key {{ key }} md5 {{ key_config.md5_key }}
+{% endfor %}
+{% endif %}
+{% 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 %}
+{% endif %}
+{% if auto_cost is defined and auto_cost.reference_bandwidth is defined and auto_cost.reference_bandwidth is not none %}
+ auto-cost reference-bandwidth {{ auto_cost.reference_bandwidth }}
+{% endif %}
+{% if default_information is defined and default_information.originate is defined and default_information.originate is not none %}
+ default-information originate {{ 'always' if default_information.originate.always is defined }} {{ 'metric ' + default_information.originate.metric if default_information.originate.metric is defined }} {{ 'metric-type ' + default_information.originate.metric_type if default_information.originate.metric_type is defined }} {{ 'route-map ' + default_information.originate.route_map if default_information.originate.route_map is defined }}
+{% endif %}
+{% if default_metric is defined and default_metric is not none %}
+ default-metric {{ default_metric }}
+{% endif %}
+{% if distance is defined and distance is not none %}
+{% if distance.global is defined and distance.global is not none %}
+ distance {{ distance.global }}
+{% endif %}
+{% if distance.ospf is defined and distance.ospf is not none %}
+ distance ospf {{ 'intra-area ' + distance.ospf.intra_area if distance.ospf.intra_area is defined }} {{ 'inter-area ' + distance.ospf.inter_area if distance.ospf.inter_area is defined }} {{ 'external ' + distance.ospf.external if distance.ospf.external is defined }}
+{% endif %}
+{% endif %}
+{% if log_adjacency_changes is defined %}
+ log-adjacency-changes {{ "detail" if log_adjacency_changes.detail is defined }}
+{% endif %}
+{% if max_metric is defined and max_metric.router_lsa is defined and max_metric.router_lsa is not none %}
+{% if max_metric.router_lsa.administrative is defined %}
+ max-metric router-lsa administrative
+{% endif %}
+{% if max_metric.router_lsa.on_shutdown is defined and max_metric.router_lsa.on_shutdown is not none %}
+ max-metric router-lsa on-shutdown {{ max_metric.router_lsa.on_shutdown }}
+{% endif %}
+{% if max_metric.router_lsa.on_startup is defined and max_metric.router_lsa.on_startup is not none %}
+ max-metric router-lsa on-startup {{ max_metric.router_lsa.on_startup }}
+{% endif %}
+{% endif %}
+{% if mpls_te is defined and mpls_te.enable is defined %}
+ mpls-te on
+ mpls-te router-address {{ mpls_te.router_address }}
+{% endif %}
+{% if neighbor is defined and neighbor is not none%}
+{% for address, address_config in neighbor.items() %}
+ neighbor {{ address }} {{ 'priority ' + address_config.priority if address_config.priority is defined }} {{ 'poll-interval ' + address_config.poll_interval if address_config.poll_interval is defined }}
+{% endfor %}
+{% endif %}
+{% if parameters is defined and parameters is not none %}
+{% if parameters.abr_type is defined and parameters.abr_type is not none %}
+ ospf abr-type {{ parameters.abr_type }}
+{% endif %}
+{% if parameters.router_id is defined and parameters.router_id is not none %}
+ ospf router-id {{ parameters.router_id }}
+{% endif %}
+{% endif %}
+{% for interface in passive_interface if passive_interface is defined %}
+ 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 %}
+{% for protocol, options in redistribute.items() %}
+ redistribute {{ protocol }} {{ 'metric ' + options.metric if options.metric is defined }} {{ 'metric-type ' + options.metric_type if options.metric_type is defined }} {{ 'route-map ' + options.route_map if options.route_map is defined }}
+{% endfor %}
+{% endif %}
+{% if refresh is defined and refresh.timers is defined and refresh.timers is not none %}
+ refresh timer {{ refresh.timers }}
+{% endif %}
+{% if timers is defined and timers.throttle is defined and timers.throttle.spf is defined and timers.throttle.spf is not none %}
+{# Timer values have default values #}
+ timers throttle spf {{ timers.throttle.spf.delay }} {{ timers.throttle.spf.initial_holdtime }} {{ timers.throttle.spf.max_holdtime }}
+{% endif %}
+!
+{% if route_map is defined and route_map is not none %}
+ip protocol ospf route-map {{ route_map }}
+{% endif %}
+!
diff --git a/data/templates/frr/ospfv3.frr.tmpl b/data/templates/frr/ospfv3.frr.tmpl
new file mode 100644
index 000000000..d08972a80
--- /dev/null
+++ b/data/templates/frr/ospfv3.frr.tmpl
@@ -0,0 +1,84 @@
+!
+{% 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() %}
+{% if area_config.interface is defined and area_config.interface is not none %}
+{% for interface in area_config.interface %}
+ interface {{ interface }} area {{ area_id }}
+{% endfor %}
+{% endif %}
+{% if area_config.range is defined and area_config.range is not none %}
+{% for prefix, prefix_config in area_config.range.items() %}
+ area {{ area_id }} range {{ prefix }} {{ 'advertise' if prefix_config.advertise is defined }} {{ 'not-advertise' if prefix_config.not_advertise is defined }}
+{% endfor %}
+{% endif %}
+{% if area_config.export_list is defined and area_config.export_list is not none %}
+ area {{ area_id }} export-list {{ area_config.export_list }}
+{% endif %}
+{% if area_config.import_list is defined and area_config.import_list is not none %}
+ area {{ area_id }} import-list {{ area_config.import_list }}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if distance is defined and distance is not none %}
+{% if distance.global is defined and distance.global is not none %}
+ distance {{ distance.global }}
+{% endif %}
+{% if distance.ospfv3 is defined and distance.ospfv3 is not none %}
+ distance ospf6 {{ 'intra-area ' + distance.ospfv3.intra_area if distance.ospfv3.intra_area is defined }} {{ 'inter-area ' + distance.ospfv3.inter_area if distance.ospfv3.inter_area is defined }} {{ 'external ' + distance.ospfv3.external if distance.ospfv3.external is defined }}
+{% endif %}
+{% endif %}
+{% if parameters is defined and parameters is not none %}
+{% if parameters.router_id is defined and parameters.router_id is not none %}
+ ospf6 router-id {{ parameters.router_id }}
+{% endif %}
+{% endif %}
+{% if redistribute is defined and redistribute is not none %}
+{% for protocol, options in redistribute.items() %}
+ redistribute {{ protocol }} {{ 'route-map ' + options.route_map if options.route_map is defined }}
+{% endfor %}
+{% endif %}
+!
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..fbdfa27c3
--- /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 | replace('_', '-') }} {{ 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 | replace('_', '-') }} {{ 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..db59a44c2
--- /dev/null
+++ b/data/templates/frr/static.frr.tmpl
@@ -0,0 +1,49 @@
+{% from 'frr/static_routes_macro.j2' import static_routes %}
+!
+{% set ip_prefix = 'ip' %}
+{% set ipv6_prefix = 'ipv6' %}
+{% if vrf is defined and vrf is not none %}
+{# We need to add an additional whitespace in front of the prefix #}
+{# when VRFs are in use, thus we use a variable for prefix handling #}
+{% set ip_prefix = ' ip' %}
+{% set ipv6_prefix = ' ipv6' %}
+vrf {{ vrf }}
+{% endif %}
+{# IPv4 routing #}
+{% if route is defined and route is not none %}
+{% for prefix, prefix_config in route.items() %}
+{{ static_routes(ip_prefix, 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, prefix_config) }}
+{%- endfor -%}
+{% endif %}
+{% if vrf is defined and vrf is not none %}
+ exit-vrf
+{% 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..f10b58047
--- /dev/null
+++ b/data/templates/frr/static_routes_macro.j2
@@ -0,0 +1,21 @@
+{% 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.dhcp_interface is defined and prefix_config.dhcp_interface is not none %}
+{% set next_hop = prefix_config.dhcp_interface | get_dhcp_router %}
+{% if next_hop is defined and next_hop is not none %}
+{{ ip_ipv6 }} route {{ prefix }} {{ next_hop }}
+{% endif %}
+{% 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 %}