summaryrefslogtreecommitdiff
path: root/data/templates
diff options
context:
space:
mode:
Diffstat (limited to 'data/templates')
-rw-r--r--data/templates/accel-ppp/config_chap_secrets_radius.j266
-rw-r--r--data/templates/accel-ppp/config_ip_pool.j22
-rw-r--r--data/templates/accel-ppp/config_modules_auth_mode.j210
-rw-r--r--data/templates/accel-ppp/config_modules_auth_protocols.j220
-rw-r--r--data/templates/accel-ppp/config_modules_ipv6.j210
-rw-r--r--data/templates/accel-ppp/config_shaper_radius.j220
-rw-r--r--data/templates/accel-ppp/pppoe.config.tmpl22
-rw-r--r--data/templates/conserver/dropbear@.service.tmpl4
-rw-r--r--data/templates/dhcp-client/daemon-options.tmpl2
-rw-r--r--data/templates/dhcp-client/ipv6.tmpl3
-rw-r--r--data/templates/dhcp-server/dhcpd.conf.tmpl18
-rw-r--r--data/templates/dhcp-server/dhcpdv6.conf.tmpl6
-rw-r--r--data/templates/firewall/nftables-nat.tmpl119
-rw-r--r--data/templates/firewall/nftables-nat66.tmpl102
-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
-rw-r--r--data/templates/https/nginx.default.tmpl5
-rw-r--r--data/templates/login/authorized_keys.tmpl9
-rw-r--r--data/templates/login/pam_radius_auth.conf.tmpl36
-rw-r--r--data/templates/ntp/ntpd.conf.tmpl (renamed from data/templates/ntp/ntp.conf.tmpl)6
-rw-r--r--data/templates/ntp/override.conf.tmpl9
-rw-r--r--data/templates/openvpn/client.conf.tmpl2
-rw-r--r--data/templates/openvpn/server.conf.tmpl6
-rw-r--r--data/templates/pppoe/ip-down.script.tmpl6
-rw-r--r--data/templates/pppoe/peer.tmpl4
-rw-r--r--data/templates/proxy-ndp/ndppd.conf.tmpl44
-rw-r--r--data/templates/salt-minion/minion.tmpl4
-rw-r--r--data/templates/snmp/etc.snmpd.conf.tmpl4
-rw-r--r--data/templates/snmp/override.conf.tmpl4
-rw-r--r--data/templates/squid/sg_acl.conf.tmpl36
-rw-r--r--data/templates/squid/squidGuard.conf.tmpl182
-rw-r--r--data/templates/ssh/override.conf.tmpl6
-rw-r--r--data/templates/ssh/sshd_config.tmpl32
-rw-r--r--data/templates/syslog/rsyslog.conf.tmpl58
-rw-r--r--data/templates/system-login/pam_radius_auth.conf.tmpl16
-rw-r--r--data/templates/system/ssh_config.tmpl6
-rw-r--r--data/templates/vrf/vrf.conf.tmpl9
46 files changed, 1351 insertions, 573 deletions
diff --git a/data/templates/accel-ppp/config_chap_secrets_radius.j2 b/data/templates/accel-ppp/config_chap_secrets_radius.j2
index 4e2254b21..49af3a228 100644
--- a/data/templates/accel-ppp/config_chap_secrets_radius.j2
+++ b/data/templates/accel-ppp/config_chap_secrets_radius.j2
@@ -1,33 +1,33 @@
-{% if authentication.mode is defined and authentication.mode == 'local' %}
-[chap-secrets]
-chap-secrets={{ chap_secrets_file }}
-{% elif authentication.mode is defined and authentication.mode == 'radius' %}
-[radius]
-verbose=1
-{% for server, options in authentication.radius.server.items() if not options.disable is defined %}
-server={{ server }},{{ options.key }},auth-port={{ options.port }},acct-port={{ options.acct_port }},req-limit=0,fail-time={{ options.fail_time }}
-{% endfor %}
-{% if authentication.radius.acct_interim_jitter is defined and authentication.radius.acct_interim_jitter is not none %}
-acct-interim-jitter={{ authentication.radius.acct_interim_jitter }}
-{% endif %}
-acct-timeout={{ authentication.radius.acct_timeout }}
-timeout={{ authentication.radius.timeout }}
-max-try={{ authentication.radius.max_try }}
-{% if authentication.radius.nas_identifier is defined and authentication.radius.nas_identifier is not none %}
-nas-identifier={{ authentication.radius.nas_identifier }}
-{% endif %}
-{% if authentication.radius.nas_ip_address is defined and authentication.radius.nas_ip_address is not none %}
-nas-ip-address={{ authentication.radius.nas_ip_address }}
-{% endif %}
-{% if authentication.radius.source_address is defined and authentication.radius.source_address is not none %}
-bind={{ authentication.radius.source_address }}
-{% endif %}
-{% if authentication.radius.dynamic_author.server is defined and authentication.radius.dynamic_author.server is not none %}
-dae-server={{ authentication.radius.dynamic_author.server }}:{{ authentication.radius.dynamic_author.port }},{{ authentication.radius.dynamic_author.key }}
-{% endif %}
-{% endif %}
-{# Both chap-secrets and radius block required the gw-ip-address #}
-{% if gateway_address is defined and gateway_address is not none %}
-gw-ip-address={{ gateway_address }}
-{% endif %}
-
+{% if authentication.mode is defined and authentication.mode == 'local' %}
+[chap-secrets]
+chap-secrets={{ chap_secrets_file }}
+{% elif authentication.mode is defined and authentication.mode == 'radius' %}
+[radius]
+verbose=1
+{% for server, options in authentication.radius.server.items() if not options.disable is defined %}
+server={{ server }},{{ options.key }},auth-port={{ options.port }},acct-port={{ options.acct_port }},req-limit=0,fail-time={{ options.fail_time }}
+{% endfor %}
+{% if authentication.radius.acct_interim_jitter is defined and authentication.radius.acct_interim_jitter is not none %}
+acct-interim-jitter={{ authentication.radius.acct_interim_jitter }}
+{% endif %}
+acct-timeout={{ authentication.radius.acct_timeout }}
+timeout={{ authentication.radius.timeout }}
+max-try={{ authentication.radius.max_try }}
+{% if authentication.radius.nas_identifier is defined and authentication.radius.nas_identifier is not none %}
+nas-identifier={{ authentication.radius.nas_identifier }}
+{% endif %}
+{% if authentication.radius.nas_ip_address is defined and authentication.radius.nas_ip_address is not none %}
+nas-ip-address={{ authentication.radius.nas_ip_address }}
+{% endif %}
+{% if authentication.radius.source_address is defined and authentication.radius.source_address is not none %}
+bind={{ authentication.radius.source_address }}
+{% endif %}
+{% if authentication.radius.dynamic_author.server is defined and authentication.radius.dynamic_author.server is not none %}
+dae-server={{ authentication.radius.dynamic_author.server }}:{{ authentication.radius.dynamic_author.port }},{{ authentication.radius.dynamic_author.key }}
+{% endif %}
+{% endif %}
+{# Both chap-secrets and radius block required the gw-ip-address #}
+{% if gateway_address is defined and gateway_address is not none %}
+gw-ip-address={{ gateway_address }}
+{% endif %}
+
diff --git a/data/templates/accel-ppp/config_ip_pool.j2 b/data/templates/accel-ppp/config_ip_pool.j2
index 973bc0071..3b0f68084 100644
--- a/data/templates/accel-ppp/config_ip_pool.j2
+++ b/data/templates/accel-ppp/config_ip_pool.j2
@@ -4,7 +4,7 @@
gw-ip-address={{ gateway_address }}
{% endif %}
{% if client_ip_pool.start is defined and client_ip_pool.stop is defined and client_ip_pool.start is not none and client_ip_pool.stop is not none %}
-{{ client_ip_pool.start }}-{{ client_ip_pool.stop }}
+{{ client_ip_pool.start }}-{{ client_ip_pool.stop.split('.')[3] }}
{% endif %}
{% if client_ip_pool.subnet is defined and client_ip_pool.subnet is not none %}
{% for subnet in client_ip_pool.subnet %}
diff --git a/data/templates/accel-ppp/config_modules_auth_mode.j2 b/data/templates/accel-ppp/config_modules_auth_mode.j2
index 5eca76f91..e3d578b38 100644
--- a/data/templates/accel-ppp/config_modules_auth_mode.j2
+++ b/data/templates/accel-ppp/config_modules_auth_mode.j2
@@ -1,5 +1,5 @@
-{% if authentication is defined and authentication.mode is defined and authentication.mode == 'local' %}
-chap-secrets
-{% elif authentication is defined and authentication.mode is defined and authentication.mode == 'radius' %}
-radius
-{% endif %}
+{% if authentication is defined and authentication.mode is defined and authentication.mode == 'local' %}
+chap-secrets
+{% elif authentication is defined and authentication.mode is defined and authentication.mode == 'radius' %}
+radius
+{% endif %}
diff --git a/data/templates/accel-ppp/config_modules_auth_protocols.j2 b/data/templates/accel-ppp/config_modules_auth_protocols.j2
index e122d6c48..454d37792 100644
--- a/data/templates/accel-ppp/config_modules_auth_protocols.j2
+++ b/data/templates/accel-ppp/config_modules_auth_protocols.j2
@@ -1,10 +1,10 @@
-{% for protocol in authentication.protocols %}
-{# this should be fixed in the CLI by a migrator #}
-{% if protocol == 'chap' %}
-auth_chap_md5
-{% elif protocol == 'mschap' %}
-auth_mschap_v1
-{% else %}
-auth_{{ protocol.replace('-', '_') }}
-{% endif %}
-{% endfor %}
+{% for protocol in authentication.protocols %}
+{# this should be fixed in the CLI by a migrator #}
+{% if protocol == 'chap' %}
+auth_chap_md5
+{% elif protocol == 'mschap' %}
+auth_mschap_v1
+{% else %}
+auth_{{ protocol.replace('-', '_') }}
+{% endif %}
+{% endfor %}
diff --git a/data/templates/accel-ppp/config_modules_ipv6.j2 b/data/templates/accel-ppp/config_modules_ipv6.j2
index e9ea4924b..02740ce7c 100644
--- a/data/templates/accel-ppp/config_modules_ipv6.j2
+++ b/data/templates/accel-ppp/config_modules_ipv6.j2
@@ -1,5 +1,5 @@
-{% if ppp_options.ipv6 is defined and ppp_options.ipv6 != 'deny' %}
-ipv6pool
-ipv6_nd
-ipv6_dhcp
-{% endif %}
+{% if ppp_options.ipv6 is defined and ppp_options.ipv6 != 'deny' %}
+ipv6pool
+ipv6_nd
+ipv6_dhcp
+{% endif %}
diff --git a/data/templates/accel-ppp/config_shaper_radius.j2 b/data/templates/accel-ppp/config_shaper_radius.j2
index 2a6641245..8de5f5df3 100644
--- a/data/templates/accel-ppp/config_shaper_radius.j2
+++ b/data/templates/accel-ppp/config_shaper_radius.j2
@@ -1,10 +1,10 @@
-{% if authentication is defined and authentication.mode is defined and authentication.mode == 'radius' %}
-{% if authentication is defined and authentication.radius is defined and authentication.radius.rate_limit is defined and authentication.radius.rate_limit.enable is defined %}
-[shaper]
-verbose=1
-attr={{ authentication.radius.rate_limit.attribute }}
-{% if authentication.radius.rate_limit.vendor is defined and authentication.radius.rate_limit.vendor is not none %}
-vendor={{ authentication.radius.rate_limit.vendor }}
-{% endif %}
-{% endif %}
-{% endif %}
+{% if authentication is defined and authentication.mode is defined and authentication.mode == 'radius' %}
+{% if authentication is defined and authentication.radius is defined and authentication.radius.rate_limit is defined and authentication.radius.rate_limit.enable is defined %}
+[shaper]
+verbose=1
+attr={{ authentication.radius.rate_limit.attribute }}
+{% if authentication.radius.rate_limit.vendor is defined and authentication.radius.rate_limit.vendor is not none %}
+vendor={{ authentication.radius.rate_limit.vendor }}
+{% endif %}
+{% endif %}
+{% endif %}
diff --git a/data/templates/accel-ppp/pppoe.config.tmpl b/data/templates/accel-ppp/pppoe.config.tmpl
index 3dfb615da..f444af85c 100644
--- a/data/templates/accel-ppp/pppoe.config.tmpl
+++ b/data/templates/accel-ppp/pppoe.config.tmpl
@@ -96,12 +96,24 @@ mtu={{ mtu }}
verbose=1
ac-name={{ access_concentrator }}
-{% if interface %}
-{% for iface in interface %}
+{% if interface is defined and interface is not none %}
+{% for iface, iface_config in interface.items() %}
+{% if iface_config.vlan_id is not defined and iface_config.vlan_range is not defined %}
interface={{ iface }}
-{% if interface[iface].vlan_id is defined or interface[iface].vlan_range is defined %}
-vlan-mon={{ iface }},{{ interface[iface].vlan_id | join(',') }},{{ interface[iface].vlan_range | join(',') }}
-interface=re:{{ interface.name }}\.\d+
+{% endif %}
+{% if iface_config.vlan_id is defined and iface_config.vlan_range is not defined %}
+{% for vlan in iface_config.vlan_id %}
+interface={{ iface }}.{{ vlan }}
+vlan-mon={{ iface }},{{ vlan }}
+{% endfor %}
+{% endif %}
+{% if iface_config.vlan_range is defined and iface_config.vlan_id is not defined %}
+vlan-mon={{ iface }},{{ iface_config.vlan_range | join(',') }}
+interface=re:{{ iface | replace('.', '\\.') }}\.\d+
+{% endif %}
+{% if iface_config.vlan_id is defined and iface_config.vlan_range is defined %}
+vlan-mon={{ iface }},{{ iface_config.vlan_id | join(',') }},{{ iface_config.vlan_range | join(',') }}
+interface=re:{{ iface | replace('.', '\\.') }}\.\d+
{% endif %}
{% endfor %}
{% endif %}
diff --git a/data/templates/conserver/dropbear@.service.tmpl b/data/templates/conserver/dropbear@.service.tmpl
new file mode 100644
index 000000000..4bb73f751
--- /dev/null
+++ b/data/templates/conserver/dropbear@.service.tmpl
@@ -0,0 +1,4 @@
+[Service]
+ExecStart=
+ExecStart=/usr/sbin/dropbear -w -j -k -r /etc/dropbear/dropbear_rsa_host_key -c "/usr/bin/console {{ device }}" -P /run/conserver/dropbear.%I.pid -p %I
+PIDFile=/run/conserver/dropbear.%I.pid
diff --git a/data/templates/dhcp-client/daemon-options.tmpl b/data/templates/dhcp-client/daemon-options.tmpl
index 290aefa49..40629dca1 100644
--- a/data/templates/dhcp-client/daemon-options.tmpl
+++ b/data/templates/dhcp-client/daemon-options.tmpl
@@ -1,4 +1,4 @@
### Autogenerated by interface.py ###
-DHCLIENT_OPTS="-nw -cf /var/lib/dhcp/dhclient_{{ifname}}.conf -pf /var/lib/dhcp/dhclient_{{ifname}}.pid -lf /var/lib/dhcp/dhclient_{{ifname}}.leases {{ifname}}"
+DHCLIENT_OPTS="-nw -cf /var/lib/dhcp/dhclient_{{ifname}}.conf -pf /var/lib/dhcp/dhclient_{{ifname}}.pid -lf /var/lib/dhcp/dhclient_{{ifname}}.leases{{" -e IF_METRIC=" ~ dhcp_options.default_route_distance if dhcp_options.default_route_distance is defined and dhcp_options.default_route_distance is not none}} {{ifname}}"
diff --git a/data/templates/dhcp-client/ipv6.tmpl b/data/templates/dhcp-client/ipv6.tmpl
index 68f668117..c292664e9 100644
--- a/data/templates/dhcp-client/ipv6.tmpl
+++ b/data/templates/dhcp-client/ipv6.tmpl
@@ -2,6 +2,9 @@
# man https://www.unix.com/man-page/debian/5/dhcp6c.conf/
interface {{ ifname }} {
+{% if dhcpv6_options is defined and dhcpv6_options.duid is defined and dhcpv6_options.duid is not none %}
+ send client-id {{ dhcpv6_options.duid }};
+{% endif %}
{% if address is defined and 'dhcpv6' in address %}
request domain-name-servers;
request domain-name;
diff --git a/data/templates/dhcp-server/dhcpd.conf.tmpl b/data/templates/dhcp-server/dhcpd.conf.tmpl
index ff2e31998..f0bfa468c 100644
--- a/data/templates/dhcp-server/dhcpd.conf.tmpl
+++ b/data/templates/dhcp-server/dhcpd.conf.tmpl
@@ -8,16 +8,12 @@
on release {
set ClientName = pick-first-value(host-decl-name, option fqdn.hostname, option host-name);
set ClientIp = binary-to-ascii(10, 8, ".",leased-address);
- set ClientMac = binary-to-ascii(16, 8, ":",substring(hardware, 1, 6));
- set ClientDomain = pick-first-value(config-option domain-name, "..YYZ!");
- execute("/usr/libexec/vyos/system/on-dhcp-event.sh", "release", ClientName, ClientIp, ClientMac, ClientDomain);
+ execute("/usr/libexec/vyos/system/on-dhcp-event.sh", "release", "", ClientIp, "", "");
}
on expiry {
set ClientName = pick-first-value(host-decl-name, option fqdn.hostname, option host-name);
set ClientIp = binary-to-ascii(10, 8, ".",leased-address);
- set ClientMac = binary-to-ascii(16, 8, ":",substring(hardware, 1, 6));
- set ClientDomain = pick-first-value(config-option domain-name, "..YYZ!");
- execute("/usr/libexec/vyos/system/on-dhcp-event.sh", "release", ClientName, ClientIp, ClientMac, ClientDomain);
+ execute("/usr/libexec/vyos/system/on-dhcp-event.sh", "release", "", ClientIp, "", "");
}
{% endif %}
@@ -201,11 +197,15 @@ shared-network {{ network | replace('_','-') }} {
on commit {
set shared-networkname = "{{ network | replace('_','-') }}";
{% if hostfile_update is defined %}
- set ClientName = pick-first-value(host-decl-name, option fqdn.hostname, option host-name);
set ClientIp = binary-to-ascii(10, 8, ".", leased-address);
set ClientMac = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6));
- set ClientDomain = pick-first-value(config-option domain-name, "..YYZ!");
- execute("/usr/libexec/vyos/system/on-dhcp-event.sh", "commit", ClientName, ClientIp, ClientMac, ClientDomain);
+ set ClientName = pick-first-value(host-decl-name, option fqdn.hostname, option host-name, "empty_hostname");
+ if not (ClientName = "empty_hostname") {
+ set ClientDomain = pick-first-value(config-option domain-name, "..YYZ!");
+ execute("/usr/libexec/vyos/system/on-dhcp-event.sh", "commit", ClientName, ClientIp, ClientMac, ClientDomain);
+ } else {
+ log(concat("Hostname is not defined for client with IP: ", ClientIP, " MAC: ", ClientMac));
+ }
{% endif %}
}
}
diff --git a/data/templates/dhcp-server/dhcpdv6.conf.tmpl b/data/templates/dhcp-server/dhcpdv6.conf.tmpl
index de7c9b29c..25e5fa592 100644
--- a/data/templates/dhcp-server/dhcpdv6.conf.tmpl
+++ b/data/templates/dhcp-server/dhcpdv6.conf.tmpl
@@ -8,6 +8,12 @@ log-facility local7;
option dhcp6.preference {{ preference }};
{% endif %}
+{% if global_parameters is defined and global_parameters.name_server is defined and global_parameters.name_server is not none %}
+{% for nameserver in global_parameters.name_server %}
+option dhcp6.name-servers {{ nameserver }};
+{% endfor %}
+{% endif %}
+
# Shared network configration(s)
{% if shared_network_name is defined and shared_network_name is not none %}
{% for network, network_config in shared_network_name.items() if network_config.disable is not defined %}
diff --git a/data/templates/firewall/nftables-nat.tmpl b/data/templates/firewall/nftables-nat.tmpl
index 8769c2384..b80fc1968 100644
--- a/data/templates/firewall/nftables-nat.tmpl
+++ b/data/templates/firewall/nftables-nat.tmpl
@@ -1,87 +1,103 @@
#!/usr/sbin/nft -f
{% macro nat_rule(rule, config, chain) %}
-{% set comment = "" %}
-{% set base_log = "" %}
-{% set src_addr = "ip saddr " + config.source.address if config.source is defined and config.source.address is defined and config.source.address is not none %}
-{% set dst_addr = "ip daddr " + config.destination.address if config.destination is defined and config.destination.address is defined and config.destination.address is not none %}
+{% set comment = '' %}
+{% set base_log = '' %}
+{% set src_addr = 'ip saddr ' + config.source.address.replace('!','!= ') if config.source is defined and config.source.address is defined and config.source.address is not none %}
+{% set dst_addr = 'ip daddr ' + config.destination.address.replace('!','!= ') if config.destination is defined and config.destination.address is defined and config.destination.address is not none %}
{# negated port groups need special treatment, move != in front of { } group #}
{% if config.source is defined and config.source.port is defined and config.source.port is not none and config.source.port.startswith('!=') %}
-{% set src_port = "sport != { " + config.source.port.replace('!=','') +" }" %}
+{% set src_port = 'sport != { ' + config.source.port.replace('!=','') + ' }' %}
{% else %}
-{% set src_port = "sport { " + config.source.port +" }" if config.source is defined and config.source.port is defined and config.source.port is not none %}
+{% set src_port = 'sport { ' + config.source.port + ' }' if config.source is defined and config.source.port is defined and config.source.port is not none %}
{% endif %}
{# negated port groups need special treatment, move != in front of { } group #}
{% if config.destination is defined and config.destination.port is defined and config.destination.port is not none and config.destination.port.startswith('!=') %}
-{% set dst_port = "dport != { " + config.destination.port.replace('!=','') +" }" %}
+{% set dst_port = 'dport != { ' + config.destination.port.replace('!=','') + ' }' %}
{% else %}
-{% set dst_port = "dport { " + config.destination.port +" }" if config.destination is defined and config.destination.port is defined and config.destination.port is not none %}
-{% endif %}
-{% if chain == "PREROUTING" %}
-{% set comment = "DST-NAT-" + rule %}
-{% set base_log = "[NAT-DST-" + rule %}
-{% set interface = " iifname \"" + config.inbound_interface + "\"" if config.inbound_interface is defined and config.inbound_interface != 'any' else '' %}
-{% set trns_addr = "dnat to " + config.translation.address if config.translation is defined and config.translation.address is defined and config.translation.address is not none %}
-{% elif chain == "POSTROUTING" %}
-{% set comment = "SRC-NAT-" + rule %}
-{% set base_log = "[NAT-SRC-" + rule %}
-{% set interface = " oifname \"" + config.outbound_interface + "\"" if config.outbound_interface is defined and config.outbound_interface != 'any' else '' %}
-{% if config.translation is defined and config.translation.address is defined and config.translation.address == 'masquerade' %}
-{% set trns_addr = config.translation.address %}
-{% if config.translation.port is defined and config.translation.port is not none %}
-{% set trns_addr = trns_addr + " to " %}
+{% set dst_port = 'dport { ' + config.destination.port + ' }' if config.destination is defined and config.destination.port is defined and config.destination.port is not none %}
+{% endif %}
+{% if chain == 'PREROUTING' %}
+{% set comment = 'DST-NAT-' + rule %}
+{% set base_log = '[NAT-DST-' + rule %}
+{% set interface = ' iifname "' + config.inbound_interface + '"' if config.inbound_interface is defined and config.inbound_interface != 'any' else '' %}
+{% if config.translation is defined and config.translation.address is defined and config.translation.address is not none %}
+{# support 1:1 network translation #}
+{% if config.translation.address | is_ip_network %}
+{% set trns_addr = 'dnat ip prefix to ip daddr map { ' + config.destination.address + ' : ' + config.translation.address + ' }' %}
+{# we can now clear out the dst_addr part as it's already covered in aboves map #}
+{% set dst_addr = '' %}
+{% else %}
+{% set trns_addr = 'dnat to ' + config.translation.address %}
+{% endif %}
+{% endif %}
+{% elif chain == 'POSTROUTING' %}
+{% set comment = 'SRC-NAT-' + rule %}
+{% set base_log = '[NAT-SRC-' + rule %}
+{% set interface = ' oifname "' + config.outbound_interface + '"' if config.outbound_interface is defined and config.outbound_interface != 'any' else '' %}
+{% if config.translation is defined and config.translation.address is defined and config.translation.address is not none %}
+{% if config.translation.address == 'masquerade' %}
+{% set trns_addr = config.translation.address %}
+{% if config.translation.port is defined and config.translation.port is not none %}
+{% set trns_addr = trns_addr + ' to ' %}
+{% endif %}
+{# support 1:1 network translation #}
+{% elif config.translation.address | is_ip_network %}
+{% set trns_addr = 'snat ip prefix to ip saddr map { ' + config.source.address + ' : ' + config.translation.address + ' }' %}
+{# we can now clear out the src_addr part as it's already covered in aboves map #}
+{% set src_addr = '' %}
+{% else %}
+{% set trns_addr = 'snat to ' + config.translation.address %}
{% endif %}
-{% else %}
-{% set trns_addr = "snat to " + config.translation.address if config.translation is defined and config.translation.address is defined and config.translation.address is not none %}
{% endif %}
{% endif %}
-{% set trns_port = ":" + config.translation.port if config.translation is defined and config.translation.port is defined and config.translation.port is not none %}
+{% set trns_port = ':' + config.translation.port if config.translation is defined and config.translation.port is defined and config.translation.port is not none %}
{# protocol has a default value thus it is always present #}
-{% if config.protocol == "tcp_udp" %}
-{% set protocol = "tcp" %}
-{% set comment = comment + " tcp_udp" %}
+{% if config.protocol == 'tcp_udp' %}
+{% set protocol = 'tcp' %}
+{% set comment = comment + ' tcp_udp' %}
{% else %}
{% set protocol = config.protocol %}
{% endif %}
{% if config.log is defined %}
{% if config.exclude is defined %}
-{% set log = base_log + "-EXCL]" %}
+{% set log = base_log + '-EXCL]' %}
{% elif config.translation is defined and config.translation.address is defined and config.translation.address == 'masquerade' %}
-{% set log = base_log + "-MASQ]" %}
+{% set log = base_log +'-MASQ]' %}
{% else %}
-{% set log = base_log + "]" %}
+{% set log = base_log + ']' %}
{% endif %}
{% endif %}
{% if config.exclude is defined %}
-{# rule has been marked as "exclude" thus we simply return here #}
-{% set trns_addr = "return" %}
-{% set trns_port = "" %}
+{# rule has been marked as 'exclude' thus we simply return here #}
+{% set trns_addr = 'return' %}
+{% set trns_port = '' %}
{% endif %}
-{% set output = "add rule ip nat " + chain + interface %}
-{% if protocol != "all" %}
-{% set output = output + " ip protocol " + protocol %}
+{% set output = 'add rule ip nat ' + chain + interface %}
+{% if protocol != 'all' %}
+{% set output = output + ' ip protocol ' + protocol %}
{% endif %}
{% if src_addr %}
-{% set output = output + " " + src_addr %}
+{% set output = output + ' ' + src_addr %}
{% endif %}
{% if src_port %}
-{% set output = output + " " + protocol + " " + src_port %}
+{% set output = output + ' ' + protocol + ' ' + src_port %}
{% endif %}
{% if dst_addr %}
-{% set output = output + " " + dst_addr %}
+{% set output = output + ' ' + dst_addr %}
{% endif %}
{% if dst_port %}
-{% set output = output + " " + protocol + " " + dst_port %}
+{% set output = output + ' ' + protocol + ' ' + dst_port %}
{% endif %}
{# Count packets #}
-{% set output = output + " counter" %}
+{% set output = output + ' counter' %}
{# Special handling of log option, we must repeat the entire rule before the #}
{# NAT translation options are added, this is essential #}
{% if log %}
-{% set log_output = output + " log prefix \"" + log + "\" comment \"" + comment + "\"" %}
+{% set log_output = output + ' log prefix "' + log + '" comment "' + comment + '"' %}
{% endif %}
{% if trns_addr %}
-{% set output = output + " " + trns_addr %}
+{% set output = output + ' ' + trns_addr %}
{% endif %}
{% if trns_port %}
{# Do not add a whitespace here, translation port must be directly added after IP address #}
@@ -89,23 +105,23 @@
{% set output = output + trns_port %}
{% endif %}
{% if comment %}
-{% set output = output + " comment \"" + comment + "\"" %}
+{% set output = output + ' comment "' + comment + '"' %}
{% endif %}
{{ log_output if log_output }}
{{ output }}
{# Special handling if protocol is tcp_udp, we must repeat the entire rule with udp as protocol #}
-{% if config.protocol == "tcp_udp" %}
+{% if config.protocol == 'tcp_udp' %}
{# Beware of trailing whitespace, without it the comment tcp_udp will be changed to udp_udp #}
-{{ log_output | replace("tcp ", "udp ") if log_output }}
-{{ output | replace("tcp ", "udp ") }}
+{{ log_output | replace('tcp ', 'udp ') if log_output }}
+{{ output | replace('tcp ', 'udp ') }}
{% endif %}
{% endmacro %}
# Start with clean NAT table
-flush table nat
+flush table ip nat
{% if helper_functions == 'remove' %}
{# NAT if going to be disabled - remove rules and targets from nftables #}
-{% set base_command = "delete rule ip raw" %}
+{% set base_command = 'delete rule ip raw' %}
{{ base_command }} PREROUTING handle {{ pre_ct_ignore }}
{{ base_command }} OUTPUT handle {{ out_ct_ignore }}
{{ base_command }} PREROUTING handle {{ pre_ct_conntrack }}
@@ -117,7 +133,7 @@ delete chain ip raw NAT_CONNTRACK
{# NAT if enabled - add targets to nftables #}
add chain ip raw NAT_CONNTRACK
add rule ip raw NAT_CONNTRACK counter accept
-{% set base_command = "add rule ip raw" %}
+{% set base_command = 'add rule ip raw' %}
{{ base_command }} PREROUTING position {{ pre_ct_ignore }} counter jump VYATTA_CT_HELPER
{{ base_command }} OUTPUT position {{ out_ct_ignore }} counter jump VYATTA_CT_HELPER
{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK
@@ -132,7 +148,6 @@ add rule ip raw NAT_CONNTRACK counter accept
{{ nat_rule(rule, config, 'PREROUTING') }}
{% endfor %}
{% endif %}
-
#
# Source NAT rules build up here
#
diff --git a/data/templates/firewall/nftables-nat66.tmpl b/data/templates/firewall/nftables-nat66.tmpl
new file mode 100644
index 000000000..e5c1b1b8d
--- /dev/null
+++ b/data/templates/firewall/nftables-nat66.tmpl
@@ -0,0 +1,102 @@
+#!/usr/sbin/nft -f
+
+{% macro nptv6_rule(rule,config, chain) %}
+{% set comment = '' %}
+{% set base_log = '' %}
+{% set src_prefix = "ip6 saddr " + config.source.prefix if config.source is defined and config.source.prefix is defined and config.source.prefix is not none %}
+{% set dest_address = "ip6 daddr " + config.destination.address if config.destination is defined and config.destination.address is defined and config.destination.address is not none %}
+{% if chain == "PREROUTING" %}
+{% set comment = "DST-NAT66-" + rule %}
+{% set base_log = '[NAT66-DST-' + rule %}
+{% set interface = " iifname \"" + config.inbound_interface + "\"" if config.inbound_interface is defined and config.inbound_interface != 'any' else '' %}
+{% if config.translation.address | is_ip_network %}
+{# support 1:1 network translation #}
+{% set dnat_type = "dnat prefix to " %}
+{% else %}
+{% set dnat_type = "dnat to " %}
+{% endif %}
+{% set trns_address = dnat_type + config.translation.address if config.translation is defined and config.translation.address is defined and config.translation.address is not none %}
+{% elif chain == "POSTROUTING" %}
+{% set comment = 'SRC-NAT66-' + rule %}
+{% set base_log = '[NAT66-SRC-' + rule %}
+{% if config.translation is defined and config.translation.address is defined and config.translation.address is not none %}
+{% if config.translation.address == 'masquerade' %}
+{% set trns_address = config.translation.address %}
+{% else %}
+{% if config.translation.address | is_ip_network %}
+{# support 1:1 network translation #}
+{% set snat_type = "snat prefix to " %}
+{% else %}
+{% set snat_type = "snat to " %}
+{% endif %}
+{% set trns_address = snat_type + config.translation.address %}
+{% endif %}
+{% endif %}
+{% set interface = " oifname \"" + config.outbound_interface + "\"" if config.outbound_interface is defined else '' %}
+{% endif %}
+{% if config.log is defined %}
+{% if config.translation is defined and config.translation.address is defined and config.translation.address == 'masquerade' %}
+{% set log = base_log +'-MASQ]' %}
+{% else %}
+{% set log = base_log + "]" %}
+{% endif %}
+{% endif %}
+{% set output = "add rule ip6 nat " + chain + interface %}
+{# Count packets #}
+{% set output = output + " counter" %}
+{# Special handling of log option, we must repeat the entire rule before the #}
+{# NAT translation options are added, this is essential #}
+{% if log %}
+{% set log_output = output + " log prefix \"" + log + "\" comment \"" + comment + "\"" %}
+{% endif %}
+{% if src_prefix %}
+{% set output = output + " " + src_prefix %}
+{% endif %}
+{% if dest_address %}
+{% set output = output + " " + dest_address %}
+{% endif %}
+{% if trns_address %}
+{% set output = output + " " + trns_address %}
+{% endif %}
+{% if comment %}
+{% set output = output + " comment \"" + comment + "\"" %}
+{% endif %}
+{{ log_output if log_output }}
+{{ output }}
+{% endmacro %}
+
+# Start with clean NAT table
+flush table ip6 nat
+{% if helper_functions == 'remove' %}
+{# NAT if going to be disabled - remove rules and targets from nftables #}
+{% set base_command = "delete rule ip6 raw" %}
+{{base_command}} PREROUTING handle {{ pre_ct_conntrack }}
+{{base_command}} OUTPUT handle {{ out_ct_conntrack }}
+
+delete chain ip6 raw NAT_CONNTRACK
+
+{% elif helper_functions == 'add' %}
+{# NAT if enabled - add targets to nftables #}
+add chain ip6 raw NAT_CONNTRACK
+add rule ip6 raw NAT_CONNTRACK counter accept
+{% set base_command = "add rule ip6 raw" %}
+{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK
+{{ base_command }} OUTPUT position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK
+{% endif %}
+
+#
+# Destination NAT66 rules build up here
+#
+{% if destination is defined and destination.rule is defined and destination.rule is not none %}
+{% for rule, config in destination.rule.items() if config.disable is not defined %}
+{{ nptv6_rule(rule, config, 'PREROUTING') }}
+{% endfor %}
+{% endif %}
+#
+# Source NAT66 rules build up here
+#
+{% if source is defined and source.rule is defined and source.rule is not none %}
+{% for rule, config in source.rule.items() if config.disable is not defined %}
+{{ nptv6_rule(rule, config, 'POSTROUTING') }}
+{% endfor %}
+{% endif %}
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 %}
diff --git a/data/templates/https/nginx.default.tmpl b/data/templates/https/nginx.default.tmpl
index 855ebff4f..916764410 100644
--- a/data/templates/https/nginx.default.tmpl
+++ b/data/templates/https/nginx.default.tmpl
@@ -40,9 +40,11 @@ server {
{% endif %}
# proxy settings for HTTP API, if enabled; 503, if not
- location ~ /(retrieve|configure|config-file|image|generate|show) {
+ location ~ /(retrieve|configure|config-file|image|generate|show|docs|openapi.json|redoc) {
{% if server.api %}
proxy_pass http://localhost:{{ server.api.port }};
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 600;
proxy_buffering off;
{% else %}
@@ -50,6 +52,7 @@ server {
{% endif %}
}
+ error_page 497 =301 https://$host:{{ server.port }}$request_uri;
error_page 501 502 503 =200 @50*_json;
{% if api_set %}
diff --git a/data/templates/login/authorized_keys.tmpl b/data/templates/login/authorized_keys.tmpl
new file mode 100644
index 000000000..639a80e1d
--- /dev/null
+++ b/data/templates/login/authorized_keys.tmpl
@@ -0,0 +1,9 @@
+### Automatically generated by system-login.py ###
+
+{% if authentication is defined and authentication.public_keys is defined and authentication.public_keys is not none %}
+{% for key, key_options in authentication.public_keys.items() %}
+{# The whitespace after options is wisely chosen #}
+{{ key_options.options + ' ' if key_options.options is defined }}{{ key_options.type }} {{ key_options.key }} {{ key }}
+{% endfor %}
+{% endif %}
+
diff --git a/data/templates/login/pam_radius_auth.conf.tmpl b/data/templates/login/pam_radius_auth.conf.tmpl
new file mode 100644
index 000000000..fad8e7dcb
--- /dev/null
+++ b/data/templates/login/pam_radius_auth.conf.tmpl
@@ -0,0 +1,36 @@
+# Automatically generated by system-login.py
+# RADIUS configuration file
+
+{% if radius is defined and radius is not none %}
+{# RADIUS IPv6 source address must be specified in [] notation #}
+{% set source_address = namespace() %}
+{% if radius.source_address is defined and radius.source_address is not none %}
+{% for address in radius.source_address %}
+{% if address | is_ipv4 %}
+{% set source_address.ipv4 = address %}
+{% elif address | is_ipv6 %}
+{% set source_address.ipv6 = "[" + address + "]" %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if radius.server is defined and radius.server is not none %}
+# server[:port] shared_secret timeout source_ip
+{# .items() returns a tuple of two elements: key and value. 1 relates to the 2nd element i.e. the value and .priority relates to the key from the internal dict #}
+{% for server, options in radius.server.items() | sort(attribute='1.priority') if not options.disabled %}
+{# RADIUS IPv6 servers must be specified in [] notation #}
+{% if server | is_ipv4 %}
+{{ server }}:{{ options.port }} {{ "%-25s" | format(options.key) }} {{ "%-10s" | format(options.timeout) }} {{ source_address.ipv4 if source_address.ipv4 is defined }}
+{% else %}
+[{{ server }}]:{{ options.port }} {{ "%-25s" | format(options.key) }} {{ "%-10s" | format(options.timeout) }} {{ source_address.ipv6 if source_address.ipv6 is defined }}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+priv-lvl 15
+mapped_priv_user radius_priv_user
+
+{% if radius.vrf is defined and radius.vrf is not none %}
+vrf-name {{ radius.vrf }}
+{% endif %}
+{% endif %}
+
diff --git a/data/templates/ntp/ntp.conf.tmpl b/data/templates/ntp/ntpd.conf.tmpl
index 3f319c89b..2b56b53c3 100644
--- a/data/templates/ntp/ntp.conf.tmpl
+++ b/data/templates/ntp/ntpd.conf.tmpl
@@ -36,10 +36,4 @@ interface ignore wildcard
{% for address in listen_address %}
interface listen {{ address }}
{% endfor %}
-interface listen 127.0.0.1
-interface listen ::1
-{% else %}
-interface ignore wildcard
-interface listen 127.0.0.1
-interface listen ::1
{% endif %}
diff --git a/data/templates/ntp/override.conf.tmpl b/data/templates/ntp/override.conf.tmpl
index 466638e5a..28eb61b21 100644
--- a/data/templates/ntp/override.conf.tmpl
+++ b/data/templates/ntp/override.conf.tmpl
@@ -1,11 +1,14 @@
-{% set vrf_command = '/sbin/ip vrf exec ' + vrf + ' ' if vrf is defined else '' %}
+{% set vrf_command = 'ip vrf exec ' + vrf + ' ' if vrf is defined else '' %}
[Unit]
StartLimitIntervalSec=0
+ConditionPathExists={{config_file}}
After=vyos-router.service
[Service]
ExecStart=
-ExecStart={{vrf_command}}/usr/lib/ntp/ntp-systemd-wrapper
-Restart=on-failure
+ExecStart={{vrf_command}}/usr/sbin/ntpd -g -p {{config_file | replace('.conf', '.pid') }} -c {{config_file}} -u ntp:ntp
+PIDFile=
+PIDFile={{config_file | replace('.conf', '.pid') }}
+Restart=always
RestartSec=10
diff --git a/data/templates/openvpn/client.conf.tmpl b/data/templates/openvpn/client.conf.tmpl
index 62387ef7c..e6e15b6ad 100644
--- a/data/templates/openvpn/client.conf.tmpl
+++ b/data/templates/openvpn/client.conf.tmpl
@@ -23,7 +23,7 @@ ifconfig-ipv6-push {{ ipv6_ip[0] }} {{ ipv6_remote }}
push "route-ipv6 {{ route6 }}"
{% endfor %}
{% for net6 in ipv6_subnet %}
-iroute {{ net6 }}
+iroute-ipv6 {{ net6 }}
{% endfor %}
{% endif %}
{% if disable is defined %}
diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl
index b3b0c936a..79288e40f 100644
--- a/data/templates/openvpn/server.conf.tmpl
+++ b/data/templates/openvpn/server.conf.tmpl
@@ -281,6 +281,10 @@ compat-names
# Custom options added by user (not validated)
#
{% for option in openvpn_option %}
-{{ option }}
+{% for argument in option.split('--') %}
+{% if argument is defined and argument != '' %}
+--{{ argument }}
+{% endif %}
+{% endfor %}
{% endfor %}
{% endif %}
diff --git a/data/templates/pppoe/ip-down.script.tmpl b/data/templates/pppoe/ip-down.script.tmpl
index 5e119f796..bac4155d6 100644
--- a/data/templates/pppoe/ip-down.script.tmpl
+++ b/data/templates/pppoe/ip-down.script.tmpl
@@ -23,10 +23,12 @@ if [ -d /sys/class/net/{{ ifname }}/upper_* ]; then
VRF_NAME="vrf ${VRF_NAME}"
fi
-# Always delete default route when interface goes down
+{% if default_route != 'none' %}
+# Always delete default route when interface goes down if we installed it
vtysh -c "conf t" ${VRF_NAME} -c "no ip route 0.0.0.0/0 {{ ifname }} ${VRF_NAME}"
-{% if ipv6 is defined and ipv6.address is defined and ipv6.address.autoconf is defined %}
+{% if ipv6 is defined and ipv6.address is defined and ipv6.address.autoconf is defined %}
vtysh -c "conf t" ${VRF_NAME} -c "no ipv6 route ::/0 {{ ifname }} ${VRF_NAME}"
+{% endif %}
{% endif %}
{% endif %}
diff --git a/data/templates/pppoe/peer.tmpl b/data/templates/pppoe/peer.tmpl
index db2cc6188..0f78f9384 100644
--- a/data/templates/pppoe/peer.tmpl
+++ b/data/templates/pppoe/peer.tmpl
@@ -47,8 +47,8 @@ mtu {{ mtu }}
mru {{ mtu }}
{% if authentication is defined %}
-{{ "user " + authentication.user if authentication.user is defined }}
-{{ "password " + authentication.password if authentication.password is defined }}
+{{ 'user "' + authentication.user + '"' if authentication.user is defined }}
+{{ 'password "' + authentication.password + '"' if authentication.password is defined }}
{% endif %}
{{ "usepeerdns" if no_peer_dns is not defined }}
diff --git a/data/templates/proxy-ndp/ndppd.conf.tmpl b/data/templates/proxy-ndp/ndppd.conf.tmpl
new file mode 100644
index 000000000..0137d8135
--- /dev/null
+++ b/data/templates/proxy-ndp/ndppd.conf.tmpl
@@ -0,0 +1,44 @@
+########################################################
+#
+# autogenerated by nat66.py
+#
+# The configuration file must define one upstream
+# interface.
+#
+# For some services, such as nat66, because it runs
+# stateless, it needs to rely on NDP Proxy to respond
+# to NDP requests.
+#
+# When using nat66 source rules, NDP Proxy needs
+# to be enabled
+#
+########################################################
+
+{% set global = namespace(ndppd_interfaces = [],ndppd_prefixs = []) %}
+{% if source is defined and source.rule is defined and source.rule is not none %}
+{% for rule, config in source.rule.items() if config.disable is not defined %}
+{% if config.outbound_interface is defined %}
+{% if config.outbound_interface not in global.ndppd_interfaces %}
+{% set global.ndppd_interfaces = global.ndppd_interfaces + [config.outbound_interface] %}
+{% endif %}
+{% if config.translation.prefix is defined %}
+{% set global.ndppd_prefixs = global.ndppd_prefixs + [{'interface':config.outbound_interface,'rule':config.translation.prefix}] %}
+{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+{% for interface in global.ndppd_interfaces %}
+proxy {{ interface }} {
+ router yes
+ timeout 500
+ ttl 30000
+{% for map in global.ndppd_prefixs %}
+{% if map.interface == interface %}
+ rule {{ map.rule }} {
+ static
+ }
+{% endif %}
+{% endfor %}
+}
+{% endfor %}
diff --git a/data/templates/salt-minion/minion.tmpl b/data/templates/salt-minion/minion.tmpl
index 405fb9131..99749b57a 100644
--- a/data/templates/salt-minion/minion.tmpl
+++ b/data/templates/salt-minion/minion.tmpl
@@ -21,7 +21,9 @@ hash_type: {{ hash }}
# location. Remote logging works best when configured to use rsyslogd(8) (e.g.:
# ``file:///dev/log``), with rsyslogd(8) configured for network logging. The URI
# format is: <file|udp|tcp>://<host|socketpath>:<port-if-required>/<log-facility>
-log_file: file:///dev/log
+# log_file: file:///dev/log
+#
+log_file: /var/log/salt/minion
# The level of messages to send to the console.
# One of 'garbage', 'trace', 'debug', info', 'warning', 'error', 'critical'.
diff --git a/data/templates/snmp/etc.snmpd.conf.tmpl b/data/templates/snmp/etc.snmpd.conf.tmpl
index 278506350..db2114fa1 100644
--- a/data/templates/snmp/etc.snmpd.conf.tmpl
+++ b/data/templates/snmp/etc.snmpd.conf.tmpl
@@ -22,6 +22,10 @@ notificationEvent linkDownTrap linkDown ifIndex ifDescr ifType ifAdminStatus i
monitor -r 10 -e linkUpTrap "Generate linkUp" ifOperStatus != 2
monitor -r 10 -e linkDownTrap "Generate linkDown" ifOperStatus == 2
+# Remove all old ifTable entries with the same ifName as newly appeared
+# interface (with different ifIndex) - this is the case on e.g. ppp interfaces
+interface_replace_old yes
+
########################
# configurable section #
########################
diff --git a/data/templates/snmp/override.conf.tmpl b/data/templates/snmp/override.conf.tmpl
index e6302a9e1..68f5fd931 100644
--- a/data/templates/snmp/override.conf.tmpl
+++ b/data/templates/snmp/override.conf.tmpl
@@ -1,4 +1,4 @@
-{% set vrf_command = '/sbin/ip vrf exec ' + vrf + ' ' if vrf is defined else '' %}
+{% set vrf_command = 'ip vrf exec ' + vrf + ' ' if vrf is defined else '' %}
[Unit]
StartLimitIntervalSec=0
After=vyos-router.service
@@ -8,6 +8,6 @@ Environment=
Environment="MIBSDIR=/usr/share/snmp/mibs:/usr/share/snmp/mibs/iana:/usr/share/snmp/mibs/ietf:/usr/share/mibs/site:/usr/share/snmp/mibs:/usr/share/mibs/iana:/usr/share/mibs/ietf:/usr/share/mibs/netsnmp"
ExecStart=
ExecStart={{vrf_command}}/usr/sbin/snmpd -LS0-5d -Lf /dev/null -u Debian-snmp -g Debian-snmp -I -ipCidrRouteTable,inetCidrRouteTable -f -p /run/snmpd.pid
-Restart=on-failure
+Restart=always
RestartSec=10
diff --git a/data/templates/squid/sg_acl.conf.tmpl b/data/templates/squid/sg_acl.conf.tmpl
index cb1c3ccb0..ce72b173a 100644
--- a/data/templates/squid/sg_acl.conf.tmpl
+++ b/data/templates/squid/sg_acl.conf.tmpl
@@ -1,18 +1,18 @@
-### generated by service_webproxy.py ###
-dbhome {{ squidguard_db_dir }}
-
-dest {{ category }}-{{ rule }} {
-{% if list_type == 'domains' %}
- domainlist {{ category }}/domains
-{% elif list_type == 'urls' %}
- urllist {{ category }}/urls
-{% elif list_type == 'expressions' %}
- expressionlist {{ category }}/expressions
-{% endif %}
-}
-
-acl {
- default {
- pass all
- }
-}
+### generated by service_webproxy.py ###
+dbhome {{ squidguard_db_dir }}
+
+dest {{ category }}-{{ rule }} {
+{% if list_type == 'domains' %}
+ domainlist {{ category }}/domains
+{% elif list_type == 'urls' %}
+ urllist {{ category }}/urls
+{% elif list_type == 'expressions' %}
+ expressionlist {{ category }}/expressions
+{% endif %}
+}
+
+acl {
+ default {
+ pass all
+ }
+}
diff --git a/data/templates/squid/squidGuard.conf.tmpl b/data/templates/squid/squidGuard.conf.tmpl
index 74de3a651..f530d1072 100644
--- a/data/templates/squid/squidGuard.conf.tmpl
+++ b/data/templates/squid/squidGuard.conf.tmpl
@@ -1,91 +1,91 @@
-### generated by service_webproxy.py ###
-
-{% macro sg_rule(category, log, db_dir) %}
-{% set expressions = db_dir + '/' + category + '/expressions' %}
-dest {{ category }}-default {
- domainlist {{ category }}/domains
- urllist {{ category }}/urls
-{% if expressions | is_file %}
- expressionlist {{ category }}/expressions
-{% endif %}
-{% if log is defined %}
- log blacklist.log
-{% endif %}
-}
-{% endmacro %}
-
-{% if url_filtering is defined and url_filtering.disable is not defined %}
-{% if url_filtering.squidguard is defined and url_filtering.squidguard is not none %}
-{% set sg_config = url_filtering.squidguard %}
-{% set acl = namespace(value='local-ok-default') %}
-{% set acl.value = acl.value + ' !in-addr' if sg_config.allow_ipaddr_url is not defined else acl.value %}
-dbhome {{ squidguard_db_dir }}
-logdir /var/log/squid
-
-rewrite safesearch {
- s@(.*\.google\..*/(custom|search|images|groups|news)?.*q=.*)@\1\&safe=active@i
- s@(.*\..*/yandsearch?.*text=.*)@\1\&fyandex=1@i
- s@(.*\.yahoo\..*/search.*p=.*)@\1\&vm=r@i
- s@(.*\.live\..*/.*q=.*)@\1\&adlt=strict@i
- s@(.*\.msn\..*/.*q=.*)@\1\&adlt=strict@i
- s@(.*\.bing\..*/search.*q=.*)@\1\&adlt=strict@i
- log rewrite.log
-}
-
-{% if sg_config.local_ok is defined and sg_config.local_ok is not none %}
-{% set acl.value = acl.value + ' local-ok-default' %}
-dest local-ok-default {
- domainlist local-ok-default/domains
-}
-{% endif %}
-{% if sg_config.local_ok_url is defined and sg_config.local_ok_url is not none %}
-{% set acl.value = acl.value + ' local-ok-url-default' %}
-dest local-ok-url-default {
- urllist local-ok-url-default/urls
-}
-{% endif %}
-{% if sg_config.local_block is defined and sg_config.local_block is not none %}
-{% set acl.value = acl.value + ' !local-block-default' %}
-dest local-block-default {
- domainlist local-block-default/domains
-}
-{% endif %}
-{% if sg_config.local_block_url is defined and sg_config.local_block_url is not none %}
-{% set acl.value = acl.value + ' !local-block-url-default' %}
-dest local-block-url-default {
- urllist local-block-url-default/urls
-}
-{% endif %}
-{% if sg_config.local_block_keyword is defined and sg_config.local_block_keyword is not none %}
-{% set acl.value = acl.value + ' !local-block-keyword-default' %}
-dest local-block-keyword-default {
- expressionlist local-block-keyword-default/expressions
-}
-{% endif %}
-
-{% if sg_config.block_category is defined and sg_config.block_category is not none %}
-{% for category in sg_config.block_category %}
-{{ sg_rule(category, sg_config.log, squidguard_db_dir) }}
-{% set acl.value = acl.value + ' !' + category + '-default' %}
-{% endfor %}
-{% endif %}
-{% if sg_config.allow_category is defined and sg_config.allow_category is not none %}
-{% for category in sg_config.allow_category %}
-{{ sg_rule(category, False, squidguard_db_dir) }}
-{% set acl.value = acl.value + ' ' + category + '-default' %}
-{% endfor %}
-{% endif %}
-acl {
- default {
-{% if sg_config.enable_safe_search is defined %}
- rewrite safesearch
-{% endif %}
- pass {{ acl.value }} {{ 'none' if sg_config.default_action is defined and sg_config.default_action == 'block' else 'allow' }}
- redirect 302:http://{{ sg_config.redirect_url }}
-{% if sg_config.log is defined and sg_config.log is not none %}
- log blacklist.log
-{% endif %}
- }
-}
-{% endif %}
-{% endif %}
+### generated by service_webproxy.py ###
+
+{% macro sg_rule(category, log, db_dir) %}
+{% set expressions = db_dir + '/' + category + '/expressions' %}
+dest {{ category }}-default {
+ domainlist {{ category }}/domains
+ urllist {{ category }}/urls
+{% if expressions | is_file %}
+ expressionlist {{ category }}/expressions
+{% endif %}
+{% if log is defined %}
+ log blacklist.log
+{% endif %}
+}
+{% endmacro %}
+
+{% if url_filtering is defined and url_filtering.disable is not defined %}
+{% if url_filtering.squidguard is defined and url_filtering.squidguard is not none %}
+{% set sg_config = url_filtering.squidguard %}
+{% set acl = namespace(value='local-ok-default') %}
+{% set acl.value = acl.value + ' !in-addr' if sg_config.allow_ipaddr_url is not defined else acl.value %}
+dbhome {{ squidguard_db_dir }}
+logdir /var/log/squid
+
+rewrite safesearch {
+ s@(.*\.google\..*/(custom|search|images|groups|news)?.*q=.*)@\1\&safe=active@i
+ s@(.*\..*/yandsearch?.*text=.*)@\1\&fyandex=1@i
+ s@(.*\.yahoo\..*/search.*p=.*)@\1\&vm=r@i
+ s@(.*\.live\..*/.*q=.*)@\1\&adlt=strict@i
+ s@(.*\.msn\..*/.*q=.*)@\1\&adlt=strict@i
+ s@(.*\.bing\..*/search.*q=.*)@\1\&adlt=strict@i
+ log rewrite.log
+}
+
+{% if sg_config.local_ok is defined and sg_config.local_ok is not none %}
+{% set acl.value = acl.value + ' local-ok-default' %}
+dest local-ok-default {
+ domainlist local-ok-default/domains
+}
+{% endif %}
+{% if sg_config.local_ok_url is defined and sg_config.local_ok_url is not none %}
+{% set acl.value = acl.value + ' local-ok-url-default' %}
+dest local-ok-url-default {
+ urllist local-ok-url-default/urls
+}
+{% endif %}
+{% if sg_config.local_block is defined and sg_config.local_block is not none %}
+{% set acl.value = acl.value + ' !local-block-default' %}
+dest local-block-default {
+ domainlist local-block-default/domains
+}
+{% endif %}
+{% if sg_config.local_block_url is defined and sg_config.local_block_url is not none %}
+{% set acl.value = acl.value + ' !local-block-url-default' %}
+dest local-block-url-default {
+ urllist local-block-url-default/urls
+}
+{% endif %}
+{% if sg_config.local_block_keyword is defined and sg_config.local_block_keyword is not none %}
+{% set acl.value = acl.value + ' !local-block-keyword-default' %}
+dest local-block-keyword-default {
+ expressionlist local-block-keyword-default/expressions
+}
+{% endif %}
+
+{% if sg_config.block_category is defined and sg_config.block_category is not none %}
+{% for category in sg_config.block_category %}
+{{ sg_rule(category, sg_config.log, squidguard_db_dir) }}
+{% set acl.value = acl.value + ' !' + category + '-default' %}
+{% endfor %}
+{% endif %}
+{% if sg_config.allow_category is defined and sg_config.allow_category is not none %}
+{% for category in sg_config.allow_category %}
+{{ sg_rule(category, False, squidguard_db_dir) }}
+{% set acl.value = acl.value + ' ' + category + '-default' %}
+{% endfor %}
+{% endif %}
+acl {
+ default {
+{% if sg_config.enable_safe_search is defined %}
+ rewrite safesearch
+{% endif %}
+ pass {{ acl.value }} {{ 'none' if sg_config.default_action is defined and sg_config.default_action == 'block' else 'allow' }}
+ redirect 302:http://{{ sg_config.redirect_url }}
+{% if sg_config.log is defined and sg_config.log is not none %}
+ log blacklist.log
+{% endif %}
+ }
+}
+{% endif %}
+{% endif %}
diff --git a/data/templates/ssh/override.conf.tmpl b/data/templates/ssh/override.conf.tmpl
index 843aa927b..5f8f35e89 100644
--- a/data/templates/ssh/override.conf.tmpl
+++ b/data/templates/ssh/override.conf.tmpl
@@ -1,4 +1,4 @@
-{% set vrf_command = '/sbin/ip vrf exec ' + vrf + ' ' if vrf is defined else '' %}
+{% set vrf_command = 'ip vrf exec ' + vrf + ' ' if vrf is defined else '' %}
[Unit]
StartLimitIntervalSec=0
After=vyos-router.service
@@ -7,5 +7,7 @@ ConditionPathExists={{config_file}}
[Service]
ExecStart=
ExecStart={{vrf_command}}/usr/sbin/sshd -f {{config_file}} -D $SSHD_OPTS
+Restart=always
+RestartPreventExitStatus=
RestartSec=10
-
+RuntimeDirectoryPreserve=yes
diff --git a/data/templates/ssh/sshd_config.tmpl b/data/templates/ssh/sshd_config.tmpl
index 52d537aca..2f2b78a66 100644
--- a/data/templates/ssh/sshd_config.tmpl
+++ b/data/templates/ssh/sshd_config.tmpl
@@ -27,6 +27,8 @@ Banner /etc/issue.net
Subsystem sftp /usr/lib/openssh/sftp-server
UsePAM yes
PermitRootLogin no
+PidFile /run/sshd/sshd.pid
+AddressFamily any
#
# User configurable section
@@ -47,59 +49,59 @@ LogLevel {{ loglevel | upper }}
# Specifies whether password authentication is allowed
PasswordAuthentication {{ "no" if disable_password_authentication is defined else "yes" }}
-{% if listen_address %}
+{% if listen_address is defined and listen_address is not none %}
# Specifies the local addresses sshd should listen on
{% for address in listen_address %}
ListenAddress {{ address }}
{% endfor %}
{% endif %}
-{% if ciphers %}
+{% if ciphers is defined and ciphers is not none %}
# Specifies the ciphers allowed for protocol version 2
-{% set value = ciphers if ciphers is string else ciphers | join(',') %}
+{% set value = ciphers if ciphers is string else ciphers | join(',') %}
Ciphers {{ value }}
{% endif %}
-{% if mac %}
+{% if mac is defined and mac is not none %}
# Specifies the available MAC (message authentication code) algorithms
-{% set value = mac if mac is string else mac | join(',') %}
+{% set value = mac if mac is string else mac | join(',') %}
MACs {{ value }}
{% endif %}
-{% if key_exchange %}
+{% if key_exchange is defined and key_exchange is not none %}
# Specifies the available Key Exchange algorithms
-{% set value = key_exchange if key_exchange is string else key_exchange | join(',') %}
+{% set value = key_exchange if key_exchange is string else key_exchange | join(',') %}
KexAlgorithms {{ value }}
{% endif %}
-{% if access_control is defined %}
-{% if access_control.allow is defined %}
+{% if access_control is defined and access_control is not none %}
+{% if access_control.allow is defined and access_control.allow is not none %}
{% if access_control.allow.user is defined %}
# If specified, login is allowed only for user names that match
-{% set value = access_control.allow.user if access_control.allow.user is string else access_control.allow.user | join(' ') %}
+{% set value = access_control.allow.user if access_control.allow.user is string else access_control.allow.user | join(' ') %}
AllowUsers {{ value }}
{% endif %}
{% if access_control.allow.group is defined %}
# If specified, login is allowed only for users whose primary group or supplementary group list matches
-{% set value = access_control.allow.group if access_control.allow.group is string else access_control.allow.group | join(' ') %}
+{% set value = access_control.allow.group if access_control.allow.group is string else access_control.allow.group | join(' ') %}
AllowGroups {{ value }}
{% endif %}
{% endif %}
-{% if access_control.deny is defined %}
+{% if access_control.deny is defined and access_control.deny is not none %}
{% if access_control.deny.user is defined %}
# Login is disallowed for user names that match
-{% set value = access_control.deny.user if access_control.deny.user is string else access_control.deny.user | join(' ') %}
+{% set value = access_control.deny.user if access_control.deny.user is string else access_control.deny.user | join(' ') %}
DenyUsers {{ value }}
{% endif %}
{% if access_control.deny.group is defined %}
# Login is disallowed for users whose primary group or supplementary group list matches
-{% set value = access_control.deny.group if access_control.deny.group is string else access_control.deny.group | join(' ') %}
+{% set value = access_control.deny.group if access_control.deny.group is string else access_control.deny.group | join(' ') %}
DenyGroups {{ value }}
{% endif %}
{% endif %}
{% endif %}
-{% if client_keepalive_interval %}
+{% if client_keepalive_interval is defined and client_keepalive_interval is not none %}
# Sets a timeout interval in seconds after which if no data has been received from the client,
# sshd(8) will send a message through the encrypted channel to request a response from the client
ClientAliveInterval {{ client_keepalive_interval }}
diff --git a/data/templates/syslog/rsyslog.conf.tmpl b/data/templates/syslog/rsyslog.conf.tmpl
index 10fbb9d3c..e25ef48d4 100644
--- a/data/templates/syslog/rsyslog.conf.tmpl
+++ b/data/templates/syslog/rsyslog.conf.tmpl
@@ -2,47 +2,47 @@
## file based logging
{% if files['global']['marker'] %}
$ModLoad immark
-{% if files['global']['marker-interval'] %}
+{% if files['global']['marker-interval'] %}
$MarkMessagePeriod {{files['global']['marker-interval']}}
-{% endif %}
+{% endif %}
{% endif %}
{% if files['global']['preserver_fqdn'] %}
$PreserveFQDN on
{% endif %}
-{% for file in files %}
-$outchannel {{file}},{{files[file]['log-file']}},{{files[file]['max-size']}},{{files[file]['action-on-max-size']}}
-{{files[file]['selectors']}} :omfile:${{file}}
+{% for file, file_options in files.items() %}
+$outchannel {{ file }},{{ file_options['log-file'] }},{{ file_options['max-size'] }},{{ file_options['action-on-max-size'] }}
+{{ file_options['selectors'] }} :omfile:${{ file }}
{% endfor %}
-{% if console %}
+{% if console is defined and console is not none %}
## console logging
-{% for con in console %}
-{{console[con]['selectors']}} /dev/console
-{% endfor %}
+{% for con, con_options in console.items() %}
+{{ con_options['selectors'] }} /dev/console
+{% endfor %}
{% endif %}
-{% if hosts %}
+{% if hosts is defined and hosts is not none %}
## remote logging
-{% for host in hosts %}
-{% if hosts[host]['proto'] == 'tcp' %}
-{% if hosts[host]['port'] %}
-{% if hosts[host]['oct_count'] %}
-{{hosts[host]['selectors']}} @@(o){{host}}:{{hosts[host]['port']}};RSYSLOG_SyslogProtocol23Format
+{% for host, host_options in hosts.items() %}
+{% if host_options.proto == 'tcp' %}
+{% if host_options.port is defined %}
+{% if host_options.oct_count is defined %}
+{{ host_options.selectors }} @@(o){{ host }}:{{ host_options.port }};RSYSLOG_SyslogProtocol23Format
+{% else %}
+{{ host_options.selectors }} @@{{ host }}:{{ host_options.port }}
+{% endif %}
{% else %}
-{{hosts[host]['selectors']}} @@{{host}}:{{hosts[host]['port']}}
+{{ host_options.selectors }} @@{{ host }}
{% endif %}
{% else %}
-{{hosts[host]['selectors']}} @@{{host}}
-{% endif %}
-{% else %}
-{% if hosts[host]['port'] %}
-{{hosts[host]['selectors']}} @{{host}}:{{hosts[host]['port']}}
-{% else %}
-{{hosts[host]['selectors']}} @{{host}}
+{% if host_options['port'] %}
+{{ host_options.selectors }} @{{ host | bracketize_ipv6 }}:{{ host_options.port }}
+{% else %}
+{{ host_options.selectors }} @{{ host | bracketize_ipv6 }}
+{% endif %}
{% endif %}
-{% endif %}
-{% endfor %}
+{% endfor %}
{% endif %}
-{% if user %}
-{% for u in user %}
-{{user[u]['selectors']}} :omusrmsg:{{u}}
-{% endfor %}
+{% if user is defined and user is not none %}
+{% for username, user_options in user.items() %}
+{{ user_options.selectors }} :omusrmsg:{{ username }}
+{% endfor %}
{% endif %}
diff --git a/data/templates/system-login/pam_radius_auth.conf.tmpl b/data/templates/system-login/pam_radius_auth.conf.tmpl
deleted file mode 100644
index ec2d6df95..000000000
--- a/data/templates/system-login/pam_radius_auth.conf.tmpl
+++ /dev/null
@@ -1,16 +0,0 @@
-# Automatically generated by system-login.py
-# RADIUS configuration file
-{% if radius_server %}
-# server[:port] shared_secret timeout source_ip
-{% for s in radius_server|sort(attribute='priority') if not s.disabled %}
-{% set addr_port = s.address + ":" + s.port %}
-{{ "%-22s" | format(addr_port) }} {{ "%-25s" | format(s.key) }} {{ "%-10s" | format(s.timeout) }} {{ radius_source_address if radius_source_address }}
-{% endfor %}
-
-priv-lvl 15
-mapped_priv_user radius_priv_user
-
-{% if radius_vrf %}
-vrf-name {{ radius_vrf }}
-{% endif %}
-{% endif %}
diff --git a/data/templates/system/ssh_config.tmpl b/data/templates/system/ssh_config.tmpl
index 509bd5479..abc03f069 100644
--- a/data/templates/system/ssh_config.tmpl
+++ b/data/templates/system/ssh_config.tmpl
@@ -1,3 +1,3 @@
-{% if ssh_client is defined and ssh_client.source_address is defined and ssh_client.source_address is not none %}
-BindAddress {{ ssh_client.source_address }}
-{% endif %}
+{% if ssh_client is defined and ssh_client.source_address is defined and ssh_client.source_address is not none %}
+BindAddress {{ ssh_client.source_address }}
+{% endif %}
diff --git a/data/templates/vrf/vrf.conf.tmpl b/data/templates/vrf/vrf.conf.tmpl
index 6d01d2b89..29c0ba08d 100644
--- a/data/templates/vrf/vrf.conf.tmpl
+++ b/data/templates/vrf/vrf.conf.tmpl
@@ -1,8 +1,9 @@
### Autogenerated by vrf.py ###
#
# Routing table ID to name mapping reference
-
# id vrf name comment
-{% for vrf in vrf_add %}
-{{ "%-10s" | format(vrf.table) }} {{ "%-16s" | format(vrf.name) }} # {{ vrf.description }}
-{% endfor %}
+{% if name is defined and name is not none %}
+{% for vrf, vrf_config in name.items() %}
+{{ "%-10s" | format(vrf_config.table) }} {{ "%-16s" | format(vrf) }} {{ '# ' + vrf_config.description if vrf_config.description is defined and vrf_config.description is not none }}
+{% endfor %}
+{% endif %}