diff options
Diffstat (limited to 'data/templates')
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 %} |