diff options
207 files changed, 10665 insertions, 2745 deletions
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index cc5e2f536..923225ea8 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,8 +5,11 @@ <!--- Provide a general summary of your changes in the Title above --> ## Types of changes -<!--- What types of changes does your code introduce? Put an 'x' in all the boxes that apply. --> -<!--- NOTE: Markdown requires no leading or trailing whitespace inside the [ ] for checking the box, please use [x] --> +<!--- +What types of changes does your code introduce? Put an 'x' in all the boxes that apply. +NOTE: Markdown requires no leading or trailing whitespace inside the [ ] for checking +the box, please use [x] +--> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Code style update (formatting, renaming) @@ -24,8 +27,14 @@ <!--- Describe your changes in detail --> ## How to test -<!--- Please describe in detail how you tested your changes. --> -<!--- Include details of your testing environment, and the tests you ran to --> +<!--- +Please describe in detail how you tested your changes. Include details of your testing +environment, and the tests you ran. When pasting configs, logs, shell output, backtraces, +and other large chunks of text, surround this text with triple backtics +``` +like this +``` +--> ## Checklist: <!--- Go over all the following points, and put an `x` in all the boxes that apply. --> diff --git a/Jenkinsfile b/Jenkinsfile index 7a760b40b..21a6829c0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ -// Copyright (C) 2020 VyOS maintainers and contributors +// Copyright (C) 2020-2021 VyOS maintainers and contributors // // This program is free software; you can redistribute it and/or modify // in order to easy exprort images built to "external" world @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. - @NonCPS // Using a version specifier library, use 'current' branch. The underscore (_) @@ -20,5 +19,5 @@ // @Library annotation is not an import statement! @Library('vyos-build@current')_ -// Start package build using library function from https://github.com/c-po/vyos-build -buildPackage() +// Start package build using library function from https://github.com/vyos/vyos-build +buildPackage(null, null, null, true) @@ -40,26 +40,11 @@ interface_definitions: $(config_xml_obj) # XXX: delete top level node.def's that now live in other packages rm -f $(TMPL_DIR)/firewall/node.def rm -f $(TMPL_DIR)/interfaces/node.def - rm -f $(TMPL_DIR)/protocols/node.def - rm -f $(TMPL_DIR)/protocols/static/node.def rm -f $(TMPL_DIR)/policy/node.def rm -f $(TMPL_DIR)/system/node.def rm -f $(TMPL_DIR)/vpn/node.def rm -f $(TMPL_DIR)/vpn/ipsec/node.def rm -rf $(TMPL_DIR)/vpn/nipsec - rm -rf $(TMPL_DIR)/protocols/nrpki - - # XXX: required until OSPF and RIP is migrated from vyatta-cfg-quagga to vyos-1x - mkdir $(TMPL_DIR)/interfaces/loopback/node.tag/ipv6 - mkdir $(TMPL_DIR)/interfaces/dummy/node.tag/ipv6 - mkdir $(TMPL_DIR)/interfaces/openvpn/node.tag/ip - mkdir -p $(TMPL_DIR)/interfaces/vti/node.tag/ip - mkdir -p $(TMPL_DIR)/interfaces/vti/node.tag/ipv6 - cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ipv6/node.def $(TMPL_DIR)/interfaces/loopback/node.tag/ipv6 - cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ipv6/node.def $(TMPL_DIR)/interfaces/dummy/node.tag/ipv6 - cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ip/node.def $(TMPL_DIR)/interfaces/openvpn/node.tag/ip - cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ip/node.def $(TMPL_DIR)/interfaces/vti/node.tag/ip - cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ipv6/node.def $(TMPL_DIR)/interfaces/vti/node.tag/ipv6 .PHONY: op_mode_definitions .ONESHELL: @@ -100,7 +85,7 @@ vyxdp: $(MAKE) -C $(XDP_DIR) .PHONY: all -all: clean interface_definitions op_mode_definitions component_versions vyshim vyxdp +all: clean interface_definitions op_mode_definitions component_versions vyshim .PHONY: clean clean: diff --git a/data/configd-include.json b/data/configd-include.json index 751d8e012..aabd7232e 100644 --- a/data/configd-include.json +++ b/data/configd-include.json @@ -21,6 +21,7 @@ "interfaces-pppoe.py", "interfaces-pseudo-ethernet.py", "interfaces-tunnel.py", +"interfaces-erspan.py", "interfaces-vxlan.py", "interfaces-wireguard.py", "interfaces-wireless.py", @@ -31,6 +32,7 @@ "nat66.py", "ntp.py", "policy-local-route.py", +"protocols_bfd.py", "protocols_bgp.py", "protocols_igmp.py", "protocols_isis.py", @@ -39,7 +41,10 @@ "protocols_ospfv3.py", "protocols_pim.py", "protocols_rip.py", +"protocols_ripng.py", +"protocols_static.py", "protocols_static_multicast.py", +"protocols_vrf.py", "salt-minion.py", "service_console-server.py", "service_ids_fastnetmon.py", 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_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/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/ipv6.tmpl b/data/templates/dhcp-client/ipv6.tmpl index 49d0d8c88..c292664e9 100644 --- a/data/templates/dhcp-client/ipv6.tmpl +++ b/data/templates/dhcp-client/ipv6.tmpl @@ -2,10 +2,10 @@ # man https://www.unix.com/man-page/debian/5/dhcp6c.conf/ interface {{ ifname }} { -{% if address is defined and 'dhcpv6' in address %} -{% if dhcpv6_options is defined and dhcpv6_options.duid is defined and dhcpv6_options.duid is not none %} +{% 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 %} +{% endif %} +{% if address is defined and 'dhcpv6' in address %} request domain-name-servers; request domain-name; {% if dhcpv6_options is defined and dhcpv6_options.parameters_only is defined %} 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/firewall/nftables-nat.tmpl b/data/templates/firewall/nftables-nat.tmpl index 499733225..b80fc1968 100644 --- a/data/templates/firewall/nftables-nat.tmpl +++ b/data/templates/firewall/nftables-nat.tmpl @@ -24,9 +24,9 @@ {% 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.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 = '' %} +{% 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 %} diff --git a/data/templates/frr/bfd.frr.tmpl b/data/templates/frr/bfd.frr.tmpl index 9e5ad3379..16f8be92c 100644 --- a/data/templates/frr/bfd.frr.tmpl +++ b/data/templates/frr/bfd.frr.tmpl @@ -1,22 +1,44 @@ ! bfd -{% for peer in old_peers %} - no peer {{ peer.remote }}{% if peer.multihop %} multihop{% endif %}{% if peer.src_addr %} local-address {{ peer.src_addr }}{% endif %}{% if peer.src_if %} interface {{ peer.src_if }}{% endif %} - -{% endfor %} -! -{% for peer in new_peers %} - peer {{ peer.remote }}{% if peer.multihop %} multihop{% endif %}{% if peer.src_addr %} local-address {{ peer.src_addr }}{% endif %}{% if peer.src_if %} interface {{ peer.src_if }}{% endif %} - - detect-multiplier {{ peer.multiplier }} - receive-interval {{ peer.rx_interval }} - transmit-interval {{ peer.tx_interval }} -{% if peer.echo_mode %} - echo-mode +{% if profile is defined and profile is not none %} +{% for profile_name, profile_config in profile.items() %} + profile {{ profile_name }} + detect-multiplier {{ profile_config.interval.multiplier }} + receive-interval {{ profile_config.interval.receive }} + transmit-interval {{ profile_config.interval.transmit }} +{% if profile_config.interval['echo-interval'] is defined and profile_config.interval['echo-interval'] is not none %} + echo-interval {{ profile_config.interval['echo-interval'] }} +{% endif %} +{% if profile_config['echo-mode'] is defined %} + echo-mode +{% endif %} +{% if profile_config.shutdown is defined %} + shutdown +{% else %} + no shutdown +{% endif %} + exit +{% endfor %} {% endif %} -{% if peer.echo_interval != '' %} - echo-interval {{ peer.echo_interval }} +{% if peer is defined and peer is not none %} +{% for peer_name, peer_config in peer.items() %} + peer {{ peer_name }}{{ ' multihop' if peer_config.multihop is defined }}{{ ' local-address ' + peer_config.source.address if peer_config.source is defined and peer_config.source.address is defined }}{{ ' interface ' + peer_config.source.interface if peer_config.source is defined and peer_config.source.interface is defined }} + detect-multiplier {{ peer_config.interval.multiplier }} + receive-interval {{ peer_config.interval.receive }} + transmit-interval {{ peer_config.interval.transmit }} +{% if peer_config.interval['echo-interval'] is defined and peer_config.interval['echo-interval'] is not none %} + echo-interval {{ peer_config.interval['echo-interval'] }} +{% endif %} +{% if peer_config['echo-mode'] is defined %} + echo-mode +{% endif %} +{% if peer_config.shutdown is defined %} + shutdown +{% else %} + no shutdown +{% endif %} + exit +{% endfor %} {% endif %} - {% if not peer.shutdown %}no {% endif %}shutdown -{% endfor %} + end ! diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index 523fe75e3..30741aa27 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -9,6 +9,9 @@ {% if config.remote_as is defined and config.remote_as is not none %} neighbor {{ neighbor }} remote-as {{ config.remote_as }} {% endif %} +{% if config.advertisement_interval is defined and config.advertisement_interval is not none %} + neighbor {{ neighbor }} advertisement-interval {{ config.advertisement_interval }} +{% endif %} {% if config.bfd is defined %} neighbor {{ neighbor }} bfd {% endif %} @@ -43,12 +46,26 @@ {% if config.password is defined and config.password is not none %} neighbor {{ neighbor }} password {{ config.password }} {% endif %} +{% if config.port is defined and config.port is not none %} + neighbor {{ neighbor }} port {{ config.port }} +{% endif %} {% if config.shutdown is defined %} neighbor {{ neighbor }} shutdown {% endif %} +{% if config.strict_capability_match is defined %} + neighbor {{ neighbor }} strict-capability-match +{% endif %} {% if config.ttl_security is defined and config.ttl_security.hops is defined and config.ttl_security.hops is not none %} neighbor {{ neighbor }} ttl-security hops {{ config.ttl_security.hops }} {% endif %} +{% if config.timers is defined %} +{% if config.timers.connect is defined and config.timers.connect is not none %} + neighbor {{ neighbor }} timers connect {{ config.timers.connect }} +{% endif %} +{% if config.timers.holdtime is defined and config.timers.keepalive is defined and config.timers.holdtime is not none and config.timers.keepalive is not none %} + neighbor {{ neighbor }} timers {{ config.timers.keepalive }} {{ config.timers.holdtime }} +{% endif %} +{% endif %} {% if config.update_source is defined and config.update_source is not none %} neighbor {{ neighbor }} update-source {{ config.update_source }} {% endif %} @@ -70,80 +87,96 @@ {% endif %} ! {% if config.address_family is defined and config.address_family is not none %} -{% for af in config.address_family %} -{% if af == 'ipv4_unicast' %} +{% for afi, afi_config in config.address_family.items() %} +{% if afi == 'ipv4_unicast' %} address-family ipv4 unicast -{% elif af == 'ipv6_unicast' %} +{% elif afi == 'ipv6_unicast' %} address-family ipv6 unicast +{% elif afi == 'l2vpn_evpn' %} + address-family l2vpn evpn +{% endif %} +{% if afi_config.addpath_tx_all is defined %} + neighbor {{ neighbor }} addpath-tx-all-paths {% endif %} -{% if config.address_family[af].allowas_in is defined and config.address_family[af].allowas_in is not none %} - neighbor {{ neighbor }} allowas-in {{ config.address_family[af].allowas_in.number if config.address_family[af].allowas_in.number is defined }} +{% if afi_config.addpath_tx_per_as is defined %} + neighbor {{ neighbor }} addpath-tx-bestpath-per-AS {% endif %} -{% if config.address_family[af].remove_private_as is defined %} +{% if afi_config.allowas_in is defined and afi_config.allowas_in is not none %} + neighbor {{ neighbor }} allowas-in {{ afi_config.allowas_in.number if afi_config.allowas_in.number is defined }} +{% endif %} +{% if afi_config.remove_private_as is defined %} neighbor {{ neighbor }} remove-private-AS {% endif %} -{% if config.address_family[af].route_reflector_client is defined %} +{% if afi_config.route_reflector_client is defined %} neighbor {{ neighbor }} route-reflector-client {% endif %} -{% if config.address_family[af].weight is defined and config.address_family[af].weight is not none %} - neighbor {{ neighbor }} weight {{ config.address_family[af].weight }} +{% if afi_config.weight is defined and afi_config.weight is not none %} + neighbor {{ neighbor }} weight {{ afi_config.weight }} +{% endif %} +{% if afi_config.attribute_unchanged is defined and afi_config.attribute_unchanged is not none %} + neighbor {{ neighbor }} attribute-unchanged {{ 'as-path ' if afi_config.attribute_unchanged.as_path is defined }}{{ 'med ' if afi_config.attribute_unchanged.med is defined }}{{ 'next-hop ' if afi_config.attribute_unchanged.next_hop is defined }} {% endif %} -{% if config.address_family[af].attribute_unchanged is defined and config.address_family[af].attribute_unchanged is not none %} - neighbor {{ neighbor }} attribute-unchanged {{ 'as-path ' if config.address_family[af].attribute_unchanged.as_path is defined }}{{ 'med ' if config.address_family[af].attribute_unchanged.med is defined }}{{ 'next-hop ' if config.address_family[af].attribute_unchanged.next_hop is defined }} +{% if afi_config.capability is defined and afi_config.capability.orf is defined and afi_config.capability.orf.prefix_list is defined and afi_config.capability.orf.prefix_list.send is defined %} + neighbor {{ neighbor }} capability orf prefix-list send {% endif %} -{% if config.address_family[af].capability is defined and config.address_family[af].capability.orf is defined and config.address_family[af].capability.orf.prefix_list is defined and config.address_family[af].capability.orf.prefix_list is not none %} - neighbor {{ neighbor }} capability orf prefix-list {{ config.address_family[af].capability.orf.prefix_list }} +{% if afi_config.capability is defined and afi_config.capability.orf is defined and afi_config.capability.orf.prefix_list is defined and afi_config.capability.orf.prefix_list.receive is defined %} + neighbor {{ neighbor }} capability orf prefix-list receive {% endif %} -{% if config.address_family[af].default_originate is defined %} - neighbor {{ neighbor }} default-originate {{ 'route-map ' + config.address_family[af].default_originate.route_map if config.address_family[af].default_originate.route_map is defined }} +{% if afi_config.default_originate is defined %} + neighbor {{ neighbor }} default-originate {{ 'route-map ' + afi_config.default_originate.route_map if afi_config.default_originate.route_map is defined }} {% endif %} -{% if config.address_family[af].distribute_list is defined and config.address_family[af].distribute_list is not none %} -{% if config.address_family[af].distribute_list.export is defined and config.address_family[af].distribute_list.export is not none %} - neighbor {{ neighbor }} distribute-list {{ config.address_family[af].distribute_list.export }} out +{% if afi_config.distribute_list is defined and afi_config.distribute_list is not none %} +{% if afi_config.distribute_list.export is defined and afi_config.distribute_list.export is not none %} + neighbor {{ neighbor }} distribute-list {{ afi_config.distribute_list.export }} out {% endif %} -{% if config.address_family[af].distribute_list.import is defined and config.address_family[af].distribute_list.import is not none %} - neighbor {{ neighbor }} distribute-list {{ config.address_family[af].distribute_list.import }} in +{% if afi_config.distribute_list.import is defined and afi_config.distribute_list.import is not none %} + neighbor {{ neighbor }} distribute-list {{ afi_config.distribute_list.import }} in {% endif %} {% endif %} -{% if config.address_family[af].filter_list is defined and config.address_family[af].filter_list is not none %} -{% if config.address_family[af].filter_list.export is defined and config.address_family[af].filter_list.export is not none %} - neighbor {{ neighbor }} filter-list {{ config.address_family[af].filter_list.export }} out +{% if afi_config.filter_list is defined and afi_config.filter_list is not none %} +{% if afi_config.filter_list.export is defined and afi_config.filter_list.export is not none %} + neighbor {{ neighbor }} filter-list {{ afi_config.filter_list.export }} out {% endif %} -{% if config.address_family[af].filter_list.import is defined and config.address_family[af].filter_list.import is not none %} - neighbor {{ neighbor }} filter-list {{ config.address_family[af].filter_list.import }} in +{% if afi_config.filter_list.import is defined and afi_config.filter_list.import is not none %} + neighbor {{ neighbor }} filter-list {{ afi_config.filter_list.import }} in {% endif %} {% endif %} -{% if config.address_family[af].maximum_prefix is defined and config.address_family[af].maximum_prefix is not none %} - neighbor {{ neighbor }} maximum-prefix {{ config.address_family[af].maximum_prefix }} +{% if afi_config.maximum_prefix is defined and afi_config.maximum_prefix is not none %} + neighbor {{ neighbor }} maximum-prefix {{ afi_config.maximum_prefix }} {% endif %} -{% if config.address_family[af].nexthop_self is defined %} -{# https://phabricator.vyos.net/T1817 #} - neighbor {{ neighbor }} next-hop-self {{ 'force' if config.address_family[af].nexthop_self.force is defined }} +{% if afi_config.nexthop_self is defined %} + neighbor {{ neighbor }} next-hop-self {{ 'force' if afi_config.nexthop_self.force is defined }} {% endif %} -{% if config.address_family[af].route_server_client is defined %} +{% if afi_config.route_server_client is defined %} neighbor {{ neighbor }} route-server-client {% endif %} -{% if config.address_family[af].route_map is defined and config.address_family[af].route_map is not none %} -{% if config.address_family[af].route_map.export is defined and config.address_family[af].route_map.export is not none %} - neighbor {{ neighbor }} route-map {{ config.address_family[af].route_map.export }} out +{% if afi_config.route_map is defined and afi_config.route_map is not none %} +{% if afi_config.route_map.export is defined and afi_config.route_map.export is not none %} + neighbor {{ neighbor }} route-map {{ afi_config.route_map.export }} out {% endif %} -{% if config.address_family[af].route_map.import is defined and config.address_family[af].route_map.import is not none %} - neighbor {{ neighbor }} route-map {{ config.address_family[af].route_map.import }} in +{% if afi_config.route_map.import is defined and afi_config.route_map.import is not none %} + neighbor {{ neighbor }} route-map {{ afi_config.route_map.import }} in {% endif %} {% endif %} -{% if config.address_family[af].prefix_list is defined and config.address_family[af].prefix_list is not none %} -{% if config.address_family[af].prefix_list.export is defined and config.address_family[af].prefix_list.export is not none %} - neighbor {{ neighbor }} prefix-list {{ config.address_family[af].prefix_list.export }} out +{% if afi_config.prefix_list is defined and afi_config.prefix_list is not none %} +{% if afi_config.prefix_list.export is defined and afi_config.prefix_list.export is not none %} + neighbor {{ neighbor }} prefix-list {{ afi_config.prefix_list.export }} out {% endif %} -{% if config.address_family[af].prefix_list.import is defined and config.address_family[af].prefix_list.import is not none %} - neighbor {{ neighbor }} prefix-list {{ config.address_family[af].prefix_list.import }} in +{% if afi_config.prefix_list.import is defined and afi_config.prefix_list.import is not none %} + neighbor {{ neighbor }} prefix-list {{ afi_config.prefix_list.import }} in {% endif %} {% endif %} -{% if config.address_family[af].soft_reconfiguration is defined and config.address_family[af].soft_reconfiguration.inbound is defined %} +{% if afi_config.soft_reconfiguration is defined and afi_config.soft_reconfiguration.inbound is defined %} neighbor {{ neighbor }} soft-reconfiguration inbound {% endif %} -{% if config.address_family[af].unsuppress_map is defined and config.address_family[af].unsuppress_map is not none %} - neighbor {{ neighbor }} unsuppress-map {{ config.address_family[af].unsuppress_map }} +{% if afi_config.unsuppress_map is defined and afi_config.unsuppress_map is not none %} + neighbor {{ neighbor }} unsuppress-map {{ afi_config.unsuppress_map }} +{% endif %} +{% if afi_config.disable_send_community is defined and afi_config.disable_send_community.extended is defined %} + no neighbor {{ neighbor }} send-community extended +{% endif %} +{% if afi_config.disable_send_community is defined and afi_config.disable_send_community.standard is defined %} + no neighbor {{ neighbor }} send-community standard {% endif %} neighbor {{ neighbor }} activate exit-address-family @@ -153,41 +186,95 @@ {% endmacro %} ! router bgp {{ asn }} +{# Disable eBGP policy by default until there is a CLI option #} +{# Workaround for T3183 until we have decided about a migration script #} + no bgp ebgp-requires-policy +{# Workaround for T2100 until we have decided about a migration script #} + no bgp network import-check {% if address_family is defined and address_family is not none %} -{% for af in address_family %} +{% for afi, afi_config in address_family.items() %} ! -{% if af == 'ipv4_unicast' %} +{% if afi == 'ipv4_unicast' %} address-family ipv4 unicast -{% elif af == 'ipv6_unicast' %} +{% elif afi == 'ipv6_unicast' %} address-family ipv6 unicast +{% elif afi == 'l2vpn_evpn' %} + address-family l2vpn evpn {% endif %} -{% if address_family[af].aggregate_address is defined and address_family[af].aggregate_address is not none %} -{% for ip in address_family[af].aggregate_address %} - aggregate-address {{ ip }}{{ ' as-set' if address_family[af].aggregate_address[ip].as_set is defined }}{{ ' summary-only' if address_family[af].aggregate_address[ip].summary_only is defined }} +{% if afi_config.aggregate_address is defined and afi_config.aggregate_address is not none %} +{% for ip in afi_config.aggregate_address %} + aggregate-address {{ ip }}{{ ' as-set' if afi_config.aggregate_address[ip].as_set is defined }}{{ ' summary-only' if afi_config.aggregate_address[ip].summary_only is defined }} {% endfor %} {% endif %} -{% if address_family[af].redistribute is defined and address_family[af].redistribute is not none %} -{% for protocol in address_family[af].redistribute %} +{% if afi_config.redistribute is defined and afi_config.redistribute is not none %} +{% for protocol in afi_config.redistribute %} {% if protocol == 'table' %} - redistribute table {{ address_family[af].redistribute[protocol].table }} + redistribute table {{ afi_config.redistribute[protocol].table }} {% else %} {% set redistribution_protocol = protocol %} {% if protocol == 'ospfv3' %} {% set redistribution_protocol = 'ospf6' %} {% endif %} - redistribute {{ redistribution_protocol }}{% if address_family[af].redistribute[protocol].metric is defined %} metric {{ address_family[af].redistribute[protocol].metric }}{% endif %}{% if address_family[af].redistribute[protocol].route_map is defined %} route-map {{ address_family[af].redistribute[protocol].route_map }}{% endif %} + redistribute {{ redistribution_protocol }}{% if afi_config.redistribute[protocol].metric is defined %} metric {{ afi_config.redistribute[protocol].metric }}{% endif %}{% if afi_config.redistribute[protocol].route_map is defined %} route-map {{ afi_config.redistribute[protocol].route_map }}{% endif %} {####### we need this blank line!! #######} {% endif %} {% endfor %} {% endif %} -{% if address_family[af].network is defined and address_family[af].network is not none %} -{% for network in address_family[af].network %} - network {{ network }}{% if address_family[af].network[network].route_map is defined %} route-map {{ address_family[af].network[network].route_map }}{% endif %}{% if address_family[af].network[network].backdoor is defined %} backdoor{% endif %} +{% if afi_config.network is defined and afi_config.network is not none %} +{% for network in afi_config.network %} + network {{ network }}{% if afi_config.network[network].route_map is defined %} route-map {{ afi_config.network[network].route_map }}{% endif %}{% if afi_config.network[network].backdoor is defined %} backdoor{% endif %} {####### we need this blank line!! #######} {% endfor %} {% endif %} +{% if afi_config.advertise_all_vni is defined %} + advertise-all-vni +{% endif %} +{% if afi_config.advertise_default_gw is defined %} + advertise-default-gw +{% endif %} +{% if afi_config.advertise_pip is defined and afi_config.advertise_pip is not none %} + advertise-pip ip {{ afi_config.advertise_pip }} +{% endif %} +{% if afi_config.advertise_svi_ip is defined %} + advertise-svi-ip +{% endif %} +{% if afi_config.rt_auto_derive is defined %} + autort rfc8365-compatible +{% endif %} +{% if afi_config.flooding is defined and afi_config.flooding.disable is defined %} + flooding disable +{% endif %} +{% if afi_config.flooding is defined and afi_config.flooding.head_end_replication is defined %} + flooding head-end-replication +{% endif %} +{% if afi_config.rd is defined and afi_config.rd is not none %} + rd {{ afi_config.rd }} +{% endif %} +{% if afi_config.route_target is defined and afi_config.route_target is not none %} +{% if afi_config.route_target.both is defined and afi_config.route_target.both is not none %} + route-target both {{ afi_config.route_target.both }} +{% endif %} +{% if afi_config.route_target.export is defined and afi_config.route_target.export is not none %} + route-target export {{ afi_config.route_target.export }} +{% endif %} +{% if afi_config.route_target.import is defined and afi_config.route_target.import is not none %} + route-target import {{ afi_config.route_target.import }} +{% endif %} +{% endif %} +{% if afi_config.vni is defined and afi_config.vni is not none %} +{% for vni, vni_config in afi_config.vni.items() %} + vni {{ vni }} +{% if vni_config.advertise_default_gw is defined %} + advertise-default-gw +{% endif %} +{% if vni_config.advertise_svi_ip is defined %} + advertise-svi-ip +{% endif %} + exit-vni +{% endfor %} +{% endif %} exit-address-family {% endfor %} {% endif %} @@ -293,6 +380,9 @@ router bgp {{ asn }} {% if parameters.graceful_restart is defined %} bgp graceful-restart {{ 'stalepath-time ' + parameters.graceful_restart.stalepath_time if parameters.graceful_restart.stalepath_time is defined }} {% endif %} +{% if parameters.graceful_shutdown is defined %} + bgp graceful-shutdown +{% endif %} {% if parameters.log_neighbor_changes is defined %} bgp log-neighbor-changes {% endif %} diff --git a/data/templates/frr/ospf.frr.tmpl b/data/templates/frr/ospf.frr.tmpl index 07699290c..140b6b406 100644 --- a/data/templates/frr/ospf.frr.tmpl +++ b/data/templates/frr/ospf.frr.tmpl @@ -1,4 +1,55 @@ ! +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +interface {{ iface }} +{% if iface_config.authentication is defined and iface_config.authentication is not none %} +{% if iface_config.authentication.plaintext_password is defined and iface_config.authentication.plaintext_password is not none %} + ip ospf authentication-key {{ iface_config.authentication.plaintext_password }} +{% elif iface_config.authentication.md5 is defined %} + ip ospf authentication message-digest +{% if iface_config.authentication.md5.key_id is defined and iface_config.authentication.md5.key_id is not none %} +{% for key, key_config in iface_config.authentication.md5.key_id.items() %} + ip ospf message-digest-key {{ key }} md5 {{ key_config.md5_key }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} +{% if iface_config.cost is defined and iface_config.cost is not none %} + ip ospf cost {{ iface_config.cost }} +{% endif %} +{% if iface_config.priority is defined and iface_config.priority is not none %} + ip ospf priority {{ iface_config.priority }} +{% endif %} +{% if iface_config.hello_interval is defined and iface_config.hello_interval is not none %} + ip ospf hello-interval {{ iface_config.hello_interval }} +{% endif %} +{% if iface_config.retransmit_interval is defined and iface_config.retransmit_interval is not none %} + ip ospf retransmit-interval {{ iface_config.retransmit_interval }} +{% endif %} +{% if iface_config.transmit_delay is defined and iface_config.transmit_delay is not none %} + ip ospf transmit-delay {{ iface_config.transmit_delay }} +{% endif %} +{% if iface_config.dead_interval is defined and iface_config.dead_interval is not none %} + ip ospf dead-interval {{ iface_config.dead_interval }} +{% elif iface_config.hello_multiplier is defined and iface_config.hello_multiplier is not none %} + ip ospf dead-interval minimal hello-multiplier {{ iface_config.hello_multiplier }} +{% endif %} +{% if iface_config.bfd is defined %} + ip ospf bfd +{% endif %} +{% if iface_config.mtu_ignore is defined %} + ip ospf mtu-ignore +{% endif %} +{% if iface_config.network is defined and iface_config.network is not none %} + ip ospf network {{ iface_config.network }} +{% endif %} +{% if iface_config.bandwidth is defined and iface_config.bandwidth is not none %} + bandwidth {{ iface_config.bandwidth }} +{% endif %} +! +{% endfor %} +{% endif %} +! router ospf {% if access_list is defined and access_list is not none %} {% for acl, acl_config in access_list.items() %} @@ -50,10 +101,8 @@ router ospf {% endfor %} {% endif %} {% endif %} -{% if link_config.dead_interval is defined and link_config.dead_interval is not none %} -{# The following values are default values #} - area {{ area_id }} virtual-link {{ link }} hello-interval {{ link_config.hello_interval }} retransmit-interval {{ link_config.retransmit_interval }} transmit-delay {{ link_config.retransmit_interval }} dead-interval {{ link_config.dead_interval }} -{% endif %} +{# The following values are default values #} + area {{ area_id }} virtual-link {{ link }} hello-interval {{ link_config.hello_interval }} retransmit-interval {{ link_config.retransmit_interval }} transmit-delay {{ link_config.transmit_delay }} dead-interval {{ link_config.dead_interval }} {% endfor %} {% endif %} {% endfor %} @@ -110,6 +159,9 @@ router ospf passive-interface {{ interface }} {% endfor %} {% for interface in passive_interface_exclude if passive_interface_exclude is defined %} +{% if interface.startswith('vlink') %} +{% set interface = interface.upper() %} +{% endif %} no passive-interface {{ interface }} {% endfor %} {% if redistribute is defined and redistribute is not none %} diff --git a/data/templates/frr/ospfv3.frr.tmpl b/data/templates/frr/ospfv3.frr.tmpl index c63ef80dc..d08972a80 100644 --- a/data/templates/frr/ospfv3.frr.tmpl +++ b/data/templates/frr/ospfv3.frr.tmpl @@ -1,4 +1,47 @@ ! +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +interface {{ iface }} +{% if iface_config.cost is defined and iface_config.cost is not none %} + ipv6 ospf6 cost {{ iface_config.cost }} +{% endif %} +{% if iface_config.priority is defined and iface_config.priority is not none %} + ipv6 ospf6 priority {{ iface_config.priority }} +{% endif %} +{% if iface_config.hello_interval is defined and iface_config.hello_interval is not none %} + ipv6 ospf6 hello-interval {{ iface_config.hello_interval }} +{% endif %} +{% if iface_config.retransmit_interval is defined and iface_config.retransmit_interval is not none %} + ipv6 ospf6 retransmit-interval {{ iface_config.retransmit_interval }} +{% endif %} +{% if iface_config.transmit_delay is defined and iface_config.transmit_delay is not none %} + ipv6 ospf6 transmit-delay {{ iface_config.transmit_delay }} +{% endif %} +{% if iface_config.dead_interval is defined and iface_config.dead_interval is not none %} + ipv6 ospf6 dead-interval {{ iface_config.dead_interval }} +{% endif %} +{% if iface_config.bfd is defined %} + ipv6 ospf6 bfd +{% endif %} +{% if iface_config.mtu_ignore is defined %} + ipv6 ospf6 mtu-ignore +{% endif %} +{% if iface_config.ifmtu is defined and iface_config.ifmtu is not none %} + ipv6 ospf6 ifmtu {{ iface_config.ifmtu }} +{% endif %} +{% if iface_config.network is defined and iface_config.network is not none %} + ipv6 ospf6 network {{ iface_config.network }} +{% endif %} +{% if iface_config.instance_id is defined and iface_config.instance_id is not none %} + ipv6 ospf6 instance-id {{ iface_config.instance_id }} +{% endif %} +{% if iface_config.passive is defined %} + ipv6 ospf6 passive +{% endif %} +! +{% endfor %} +{% endif %} +! router ospf6 {% if area is defined and area is not none %} {% for area_id, area_config in area.items() %} diff --git a/data/templates/frr/rip.frr.tmpl b/data/templates/frr/rip.frr.tmpl index 83df4e203..bc92bddf9 100644 --- a/data/templates/frr/rip.frr.tmpl +++ b/data/templates/frr/rip.frr.tmpl @@ -1,143 +1,92 @@ ! -{% if rip_conf %} -router rip -{% if old_default_distance %} -no distance {{old_default_distance}} -{% endif %} -{% if default_distance %} -distance {{default_distance}} -{% endif %} -{% if old_default_originate %} -no default-information originate -{% endif %} -{% if default_originate %} -default-information originate -{% endif %} -{% if old_rip.default_metric %} -no default-metric {{old_rip.default_metric}} -{% endif %} -{% if rip.default_metric %} -default-metric {{rip.default_metric}} -{% endif %} -{% for protocol in old_rip.redist %} -{% if old_rip.redist[protocol]['metric'] and old_rip.redist[protocol]['route_map'] %} -no redistribute {{protocol}} metric {{rip.redist[protocol]['metric']}} route-map {{rip.redist[protocol]['route_map']}} -{% elif old_rip.redist[protocol]['metric'] %} -no redistribute {{protocol}} metric {{old_rip.redist[protocol]['metric']}} -{% elif old_rip.redist[protocol]['route_map'] %} -no redistribute {{protocol}} route-map {{old_rip.redist[protocol]['route_map']}} -{% else %} -no redistribute {{protocol}} -{% endif %} -{% endfor %} -{% for protocol in rip.redist %} -{% if rip.redist[protocol]['metric'] and rip.redist[protocol]['route_map'] %} -redistribute {{protocol}} metric {{rip.redist[protocol]['metric']}} route-map {{rip.redist[protocol]['route_map']}} -{% elif rip.redist[protocol]['metric'] %} -redistribute {{protocol}} metric {{rip.redist[protocol]['metric']}} -{% elif rip.redist[protocol]['route_map'] %} -redistribute {{protocol}} route-map {{rip.redist[protocol]['route_map']}} -{% else %} -redistribute {{protocol}} -{% endif %} -{% endfor %} -{% for iface in old_rip.distribute %} -{% if old_rip.distribute[iface].iface_access_list_in %} -no distribute-list {{old_rip.distribute[iface].iface_access_list_in}} in {{iface}} -{% endif %} -{% if old_rip.distribute[iface].iface_access_list_out %} -no distribute-list {{old_rip.distribute[iface].iface_access_list_out}} out {{iface}} -{% endif %} -{% if old_rip.distribute[iface].iface_prefix_list_in %} -no distribute-list prefix {{old_rip.distribute[iface].iface_prefix_list_in}} in {{iface}} -{% endif %} -{% if old_rip.distribute[iface].iface_prefix_list_out %} -no distribute-list prefix {{old_rip.distribute[iface].iface_prefix_list_out}} out {{iface}} -{% endif %} -{% endfor %} -{% for iface in rip.distribute %} -{% if rip.distribute[iface].iface_access_list_in %} -distribute-list {{rip.distribute[iface].iface_access_list_in}} in {{iface}} -{% endif %} -{% if rip.distribute[iface].iface_access_list_out %} -distribute-list {{rip.distribute[iface].iface_access_list_out}} out {{iface}} -{% endif %} -{% if rip.distribute[iface].iface_prefix_list_in %} -distribute-list prefix {{rip.distribute[iface].iface_prefix_list_in}} in {{iface}} +{# RIP key-chain definition #} +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +{% if iface_config.authentication is defined and iface_config.authentication.md5 is defined and iface_config.authentication.md5 is not none %} +key chain {{ iface }}-rip +{% for key_id, key_options in iface_config.authentication.md5.items() %} + key {{ key_id }} +{% if key_options.password is defined and key_options.password is not none %} + key-string {{ key_options.password }} +{% endif %} +{% endfor %} +{% endif %} +{% endfor %} {% endif %} -{% if rip.distribute[iface].iface_prefix_list_out %} -distribute-list prefix {{rip.distribute[iface].iface_prefix_list_out}} out {{iface}} -{% endif %} -{% endfor %} -{% if old_rip.dist_acl_in %} -no distribute-list {{old_rip.dist_acl_in}} in -{% endif %} -{% if rip.dist_acl_in %} -distribute-list {{rip.dist_acl_in}} in -{% endif %} -{% if old_rip.dist_acl_out %} -no distribute-list {{old_rip.dist_acl_out}} out -{% endif %} -{% if rip.dist_acl_out %} -distribute-list {{rip.dist_acl_out}} out -{% endif %} -{% if old_rip.dist_prfx_in %} -no distribute-list prefix {{old_rip.dist_prfx_in}} in -{% endif %} -{% if rip.dist_prfx_in %} -distribute-list prefix {{rip.dist_prfx_in}} in -{% endif %} -{% if old_rip.dist_prfx_out %} -no distribute-list prefix {{old_rip.dist_prfx_out}} out -{% endif %} -{% if rip.dist_prfx_out %} -distribute-list prefix {{rip.dist_prfx_out}} out -{% endif %} -{% for network in old_rip.networks %} -no network {{network}} -{% endfor %} -{% for network in rip.networks %} -network {{network}} -{% endfor %} -{% for iface in old_rip.ifaces %} -no network {{iface}} -{% endfor %} -{% for iface in rip.ifaces %} -network {{iface}} -{% endfor %} -{% for neighbor in old_rip.neighbors %} -no neighbor {{neighbor}} -{% endfor %} -{% for neighbor in rip.neighbors %} -neighbor {{neighbor}} -{% endfor %} -{% for net in rip.net_distance %} -{% if rip.net_distance[net].access_list and rip.net_distance[net].distance %} -distance {{rip.net_distance[net].distance}} {{net}} {{rip.net_distance[net].access_list}} -{% else %} -distance {{rip.net_distance[net].distance}} {{net}} -{% endif %} -{% endfor %} -{% for passive_iface in old_rip.passive_iface %} -no passive-interface {{passive_iface}} -{% endfor %} -{% for passive_iface in rip.passive_iface %} -passive-interface {{passive_iface}} -{% endfor %} -{% for route in old_rip.route %} -no route {{route}} -{% endfor %} -{% for route in rip.route %} -route {{route}} -{% endfor %} -{% if old_rip.timer_update or old_rip.timer_timeout or old_rip.timer_garbage %} -no timers basic -{% endif %} -{% if rip.timer_update or rip.timer_timeout or rip.timer_garbage %} -timers basic {{rip.timer_update}} {{rip.timer_timeout}} {{rip.timer_garbage}} +! +{# Interface specific configuration #} +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +interface {{ iface }} +{% if iface_config.authentication is defined and iface_config.authentication.plaintext_password is defined and iface_config.authentication.plaintext_password is not none %} + ip rip authentication mode text + ip rip authentication string {{ iface_config.authentication.plaintext_password }} +{% elif iface_config.authentication is defined and iface_config.authentication.md5 is defined and iface_config.authentication.md5 is not none %} + ip rip authentication key-chain {{ iface }}-rip + ip rip authentication mode md5 +{% endif %} +{% if iface_config.split_horizon is defined and iface_config.split_horizon.disable is defined %} + no ip rip split-horizon +{% endif %} +{% if iface_config.split_horizon is defined and iface_config.split_horizon.poison_reverse is defined %} + ip rip split-horizon poisoned-reverse +{% endif %} +{% endfor %} {% endif %} ! -{% else %} -no router rip +router rip +{% if default_distance is defined and default_distance is not none %} + distance {{ default_distance }} +{% endif %} +{% if network_distance is defined and network_distance is not none %} +{% for network, network_config in network_distance.items() %} +{% if network_config.distance is defined and network_config.distance is not none %} + distance {{ network_config.distance }} {{ network }} +{% endif %} +{% endfor %} +{% endif %} +{% if neighbor is defined and neighbor is not none %} +{% for address in neighbor %} + neighbor {{ address }} +{% endfor %} +{% endif %} +{% if distribute_list is defined and distribute_list is not none %} +{% if distribute_list.access_list is defined and distribute_list.access_list is not none %} +{% if distribute_list.access_list.in is defined and distribute_list.access_list.in is not none %} + distribute-list {{ distribute_list.access_list.in }} in +{% endif %} +{% if distribute_list.access_list.out is defined and distribute_list.access_list.out is not none %} + distribute-list {{ distribute_list.access_list.out }} out +{% endif %} +{% endif %} +{% if distribute_list.interface is defined and distribute_list.interface is not none %} +{% for interface, interface_config in distribute_list.interface.items() %} +{% if interface_config.access_list is defined and interface_config.access_list is not none %} +{% if interface_config.access_list.in is defined and interface_config.access_list.in is not none %} + distribute-list {{ interface_config.access_list.in }} in {{ interface }} +{% endif %} +{% if interface_config.access_list.out is defined and interface_config.access_list.out is not none %} + distribute-list {{ interface_config.access_list.out }} out {{ interface }} +{% endif %} +{% endif %} +{% if interface_config.prefix_list is defined and interface_config.prefix_list is not none %} +{% if interface_config.prefix_list.in is defined and interface_config.prefix_list.in is not none %} + distribute-list prefix {{ interface_config.prefix_list.in }} in {{ interface }} +{% endif %} +{% if interface_config.prefix_list.out is defined and interface_config.prefix_list.out is not none %} + distribute-list prefix {{ interface_config.prefix_list.out }} out {{ interface }} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{% if distribute_list.prefix_list is defined and distribute_list.prefix_list is not none %} +{% if distribute_list.prefix_list.in is defined and distribute_list.prefix_list.in is not none %} + distribute-list prefix {{ distribute_list.prefix_list.in }} in +{% endif %} +{% if distribute_list.prefix_list.out is defined and distribute_list.prefix_list.out is not none %} + distribute-list prefix {{ distribute_list.prefix_list.out }} out +{% endif %} +{% endif %} +{% endif %} +{% include 'frr/rip_ripng.frr.j2' %} ! -{% endif %} diff --git a/data/templates/frr/rip_ripng.frr.j2 b/data/templates/frr/rip_ripng.frr.j2 new file mode 100644 index 000000000..de180ee6b --- /dev/null +++ b/data/templates/frr/rip_ripng.frr.j2 @@ -0,0 +1,36 @@ +{% if default_information is defined and default_information.originate is defined %} + default-information originate +{% endif %} +{% if default_metric is defined and default_metric is not none %} + default-metric {{ default_metric }} +{% endif %} +{% if passive_interface is defined and passive_interface is not none %} +{% for interface in passive_interface %} + passive-interface {{ interface }} +{% endfor %} +{% endif %} +{% if network is defined and network is not none %} +{% for prefix in network %} + network {{ prefix }} +{% endfor %} +{% endif %} +{% if interface is defined and interface is not none %} +{% for ifname in interface %} + network {{ ifname }} +{% endfor %} +{% endif %} +{% if route is defined and route is not none %} +{% for prefix in route %} + route {{ prefix }} +{% endfor %} +{% endif %} +{# timers have default values #} + timers basic {{ timers['update'] }} {{ timers.timeout }} {{ timers.garbage_collection }} +{% if redistribute is defined and redistribute is not none %} +{% for protocol, protocol_config in redistribute.items() %} +{% if protocol == 'ospfv3' %} +{% set protocol = 'ospf6' %} +{% endif %} + redistribute {{ protocol }} {{ 'metric ' + protocol_config.metric if protocol_config.metric is defined }} {{ 'route-map ' + protocol_config.route_map if protocol_config.route_map is defined }} +{% endfor %} +{% endif %} diff --git a/data/templates/frr/ripng.frr.tmpl b/data/templates/frr/ripng.frr.tmpl new file mode 100644 index 000000000..25df15121 --- /dev/null +++ b/data/templates/frr/ripng.frr.tmpl @@ -0,0 +1,60 @@ +! +{# Interface specific configuration #} +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +interface {{ iface }} +{% if iface_config.split_horizon is defined and iface_config.split_horizon.disable is defined %} + no ipv6 rip split-horizon +{% endif %} +{% if iface_config.split_horizon is defined and iface_config.split_horizon.poison_reverse is defined %} + ipv6 rip split-horizon poisoned-reverse +{% endif %} +{% endfor %} +{% endif %} +! +router ripng +{% if aggregate_address is defined and aggregate_address is not none %} +{% for prefix in aggregate_address %} + aggregate-address {{ prefix }} +{% endfor %} +{% endif %} +{% if distribute_list is defined and distribute_list is not none %} +{% if distribute_list.access_list is defined and distribute_list.access_list is not none %} +{% if distribute_list.access_list.in is defined and distribute_list.access_list.in is not none %} + ipv6 distribute-list {{ distribute_list.access_list.in }} in +{% endif %} +{% if distribute_list.access_list.out is defined and distribute_list.access_list.out is not none %} + ipv6 distribute-list {{ distribute_list.access_list.out }} out +{% endif %} +{% endif %} +{% if distribute_list.interface is defined and distribute_list.interface is not none %} +{% for interface, interface_config in distribute_list.interface.items() %} +{% if interface_config.access_list is defined and interface_config.access_list is not none %} +{% if interface_config.access_list.in is defined and interface_config.access_list.in is not none %} + ipv6 distribute-list {{ interface_config.access_list.in }} in {{ interface }} +{% endif %} +{% if interface_config.access_list.out is defined and interface_config.access_list.out is not none %} + ipv6 distribute-list {{ interface_config.access_list.out }} out {{ interface }} +{% endif %} +{% endif %} +{% if interface_config.prefix_list is defined and interface_config.prefix_list is not none %} +{% if interface_config.prefix_list.in is defined and interface_config.prefix_list.in is not none %} + ipv6 distribute-list prefix {{ interface_config.prefix_list.in }} in {{ interface }} +{% endif %} +{% if interface_config.prefix_list.out is defined and interface_config.prefix_list.out is not none %} + ipv6 distribute-list prefix {{ interface_config.prefix_list.out }} out {{ interface }} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{% if distribute_list.prefix_list is defined and distribute_list.prefix_list is not none %} +{% if distribute_list.prefix_list.in is defined and distribute_list.prefix_list.in is not none %} + ipv6 distribute-list prefix {{ distribute_list.prefix_list.in }} in +{% endif %} +{% if distribute_list.prefix_list.out is defined and distribute_list.prefix_list.out is not none %} + ipv6 distribute-list prefix {{ distribute_list.prefix_list.out }} out +{% endif %} +{% endif %} +{% endif %} +{% include 'frr/rip_ripng.frr.j2' %} +! diff --git a/data/templates/frr/rpki.frr.tmpl b/data/templates/frr/rpki.frr.tmpl new file mode 100644 index 000000000..346a0caa9 --- /dev/null +++ b/data/templates/frr/rpki.frr.tmpl @@ -0,0 +1,17 @@ +! +{# as FRR does not support deleting the entire rpki section we leave it in place even when it's empty #} +rpki +{% if cache is defined and cache is not none %} +{% for peer, peer_config in cache.items() %} +{# port is mandatory and preference uses a default value #} +{% if peer_config.ssh is defined and peer_config.ssh.username is defined and peer_config.ssh.username is not none %} + rpki cache {{ peer }} {{ peer_config.port }} {{ peer_config.ssh.username }} {{ peer_config.ssh.private_key_file }} {{ peer_config.ssh.public_key_file }} {{ peer_config.ssh.known_hosts_file }} preference {{ peer_config.preference }} +{% else %} + rpki cache {{ peer }} {{ peer_config.port }} preference {{ peer_config.preference }} +{% endif %} +{% endfor %} +{% endif %} +{% if polling_period is defined and polling_period is not none %} + rpki polling_period {{ polling_period }} +{% endif %} +! diff --git a/data/templates/frr/static.frr.tmpl b/data/templates/frr/static.frr.tmpl new file mode 100644 index 000000000..bb0ec80a5 --- /dev/null +++ b/data/templates/frr/static.frr.tmpl @@ -0,0 +1,38 @@ +{% from 'frr/static_routes_macro.j2' import static_routes %} +! +{# IPv4 routing #} +{% if route is defined and route is not none %} +{% for prefix, prefix_config in route.items() %} +{{ static_routes('ip', prefix, prefix_config) }} +{%- endfor -%} +{% endif %} +! +{# IPv6 routing #} +{% if route6 is defined and route6 is not none %} +{% for prefix, prefix_config in route6.items() %} +{{ static_routes('ipv6', prefix, prefix_config) }} +{%- endfor -%} +{% endif %} +! +{# Policy route tables #} +{% if table is defined and table is not none %} +{% for table_id, table_config in table.items() %} +{% if table_config.route is defined and table_config.route is not none %} +{% for prefix, prefix_config in table_config.route.items() %} +{{ static_routes('ip', prefix, prefix_config, table_id) }} +{%- endfor -%} +{% endif %} +! +{% if table_config.route6 is defined and table_config.route6 is not none %} +{% for prefix, prefix_config in table_config.route6.items() %} +{{ static_routes('ipv6', prefix, prefix_config, table_id) }} +{%- endfor -%} +{% endif %} +! +{% endfor %} +{% endif %} +! +{% if route_map is defined and route_map is not none %} +ip protocol static route-map {{ route_map }} +! +{% endif %} diff --git a/data/templates/frr/static_routes_macro.j2 b/data/templates/frr/static_routes_macro.j2 new file mode 100644 index 000000000..b24232ef3 --- /dev/null +++ b/data/templates/frr/static_routes_macro.j2 @@ -0,0 +1,15 @@ +{% macro static_routes(ip_ipv6, prefix, prefix_config, table=None) %} +{% if prefix_config.blackhole is defined %} +{{ ip_ipv6 }} route {{ prefix }} blackhole {{ prefix_config.blackhole.distance if prefix_config.blackhole.distance is defined }} {{ 'tag ' + prefix_config.blackhole.tag if prefix_config.blackhole.tag is defined }} {{ 'table ' + table if table is defined and table is not none }} +{% endif %} +{% if prefix_config.interface is defined and prefix_config.interface is not none %} +{% for interface, interface_config in prefix_config.interface.items() if interface_config.disable is not defined %} +{{ ip_ipv6 }} route {{ prefix }} {{ interface }} {{ interface_config.distance if interface_config.distance is defined }} {{ 'nexthop-vrf ' + interface_config.vrf if interface_config.vrf is defined }} {{ 'table ' + table if table is defined and table is not none }} +{% endfor %} +{% endif %} +{% if prefix_config.next_hop is defined and prefix_config.next_hop is not none %} +{% for next_hop, next_hop_config in prefix_config.next_hop.items() if next_hop_config.disable is not defined %} +{{ ip_ipv6 }} route {{ prefix }} {{ next_hop }} {{ next_hop_config.interface if next_hop_config.interface is defined }} {{ next_hop_config.distance if next_hop_config.distance is defined }} {{ 'nexthop-vrf ' + next_hop_config.vrf if next_hop_config.vrf is defined }} {{ 'table ' + table if table is defined and table is not none }} +{% endfor %} +{% endif %} +{% endmacro %} diff --git a/data/templates/frr/vrf.frr.tmpl b/data/templates/frr/vrf.frr.tmpl new file mode 100644 index 000000000..8d3d8e9dd --- /dev/null +++ b/data/templates/frr/vrf.frr.tmpl @@ -0,0 +1,25 @@ +{% from 'frr/static_routes_macro.j2' import static_routes %} +! +{% if vrf is defined and vrf is not none %} +{% for vrf_name, vrf_config in vrf.items() %} +vrf {{ vrf_name }} +{% if vrf_config.vni is defined and vrf_config.vni is not none %} + vni {{ vrf_config.vni }} +{% endif %} +{% if vrf_config.static is defined and vrf_config.static is not none %} +{# IPv4 routes #} +{% if vrf_config.static.route is defined and vrf_config.static.route is not none %} +{% for prefix, prefix_config in vrf_config.static.route.items() %} + {{ static_routes('ip', prefix, prefix_config) }} +{%- endfor -%} +{% endif %} +{# IPv6 routes #} +{% if vrf_config.static.route6 is defined and vrf_config.static.route6 is not none %} +{% for prefix, prefix_config in vrf_config.static.route6.items() %} + {{ static_routes('ipv6', prefix, prefix_config) }} +{%- endfor -%} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +! 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/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/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/debian/rules b/debian/rules index ab0df7201..8e5aee3e6 100755 --- a/debian/rules +++ b/debian/rules @@ -12,6 +12,8 @@ MIGRATION_SCRIPTS_DIR := opt/vyatta/etc/config-migrate/migrate SYSTEM_SCRIPTS_DIR := usr/libexec/vyos/system SERVICES_DIR := usr/libexec/vyos/services +DEB_TARGET_ARCH := $(shell dpkg-architecture -qDEB_TARGET_ARCH) + %: dh $@ --with python3, --with quilt @@ -20,6 +22,10 @@ override_dh_gencontrol: override_dh_auto_build: make all +ifeq ($(DEB_TARGET_ARCH),amd64) + # Only build XDP on amd64 systems + make vyxdp +endif override_dh_auto_install: dh_auto_install @@ -78,11 +84,6 @@ override_dh_auto_install: mkdir -p $(DIR)/$(VYOS_DATA_DIR) cp -r data/* $(DIR)/$(VYOS_DATA_DIR) - # Install XDP plugins - mkdir -p $(DIR)/$(VYOS_DATA_DIR)/xdp - cp -r src/xdp/xdp_prog_kern.o $(DIR)/$(VYOS_DATA_DIR)/xdp - find src/xdp -perm /a+x -exec cp {} $(DIR)/$(VYOS_SBIN_DIR) \; - # Install etc configuration files mkdir -p $(DIR)/etc cp -r src/etc/* $(DIR)/etc @@ -109,3 +110,10 @@ override_dh_auto_install: # Install system programs mkdir -p $(DIR)/$(VYOS_BIN_DIR) cp -r smoketest/bin/* $(DIR)/$(VYOS_BIN_DIR) + +ifeq ($(DEB_TARGET_ARCH),amd64) + # We only install XDP on amd64 systems + mkdir -p $(DIR)/$(VYOS_DATA_DIR)/xdp + cp -r src/xdp/xdp_prog_kern.o $(DIR)/$(VYOS_DATA_DIR)/xdp + find src/xdp -perm /a+x -exec cp {} $(DIR)/$(VYOS_SBIN_DIR) \; +endif diff --git a/interface-definitions/include/accel-radius-additions-disable-accounting.xlm.in b/interface-definitions/include/accel-radius-additions-disable-accounting.xml.i index 026f67453..dc5b9dd96 100644 --- a/interface-definitions/include/accel-radius-additions-disable-accounting.xlm.in +++ b/interface-definitions/include/accel-radius-additions-disable-accounting.xml.i @@ -1,7 +1,8 @@ +<!-- included start from accel-radius-additions-disable-accounting.xml.i --> <leafNode name="disable-accounting"> <properties> <help>Disable accounting</help> <valueless/> </properties> </leafNode> - +<!-- included end --> diff --git a/interface-definitions/include/accel-radius-additions.xml.i b/interface-definitions/include/accel-radius-additions.xml.i index 3ec0d587e..0067b6d1c 100644 --- a/interface-definitions/include/accel-radius-additions.xml.i +++ b/interface-definitions/include/accel-radius-additions.xml.i @@ -29,7 +29,7 @@ </properties> <defaultValue>1813</defaultValue> </leafNode> - #include <include/accel-radius-additions-disable-accounting.xlm.in> + #include <include/accel-radius-additions-disable-accounting.xml.i> <leafNode name="fail-time"> <properties> <help>Mark server unavailable for <n> seconds on failure</help> diff --git a/interface-definitions/include/bfd-common.xml.i b/interface-definitions/include/bfd-common.xml.i new file mode 100644 index 000000000..ff73e4b20 --- /dev/null +++ b/interface-definitions/include/bfd-common.xml.i @@ -0,0 +1,72 @@ +<!-- included start from bfd-common.xml.i --> +<leafNode name="echo-mode"> + <properties> + <help>Enables the echo transmission mode</help> + <valueless/> + </properties> +</leafNode> +<node name="interval"> + <properties> + <help>Configure timer intervals</help> + </properties> + <children> + <leafNode name="receive"> + <properties> + <help>Minimum interval of receiving control packets</help> + <valueHelp> + <format>10-60000</format> + <description>Interval in milliseconds</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 10-60000"/> + </constraint> + </properties> + <defaultValue>300</defaultValue> + </leafNode> + <leafNode name="transmit"> + <properties> + <help>Minimum interval of transmitting control packets</help> + <valueHelp> + <format>10-60000</format> + <description>Interval in milliseconds</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 10-60000"/> + </constraint> + </properties> + <defaultValue>300</defaultValue> + </leafNode> + <leafNode name="multiplier"> + <properties> + <help>Multiplier to determine packet loss</help> + <valueHelp> + <format>2-255</format> + <description>Remote transmission interval will be multiplied by this value</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 2-255"/> + </constraint> + </properties> + <defaultValue>3</defaultValue> + </leafNode> + <leafNode name="echo-interval"> + <properties> + <help>Echo receive transmission interval</help> + <valueHelp> + <format>10-60000</format> + <description>The minimal echo receive transmission interval that this system is capable of handling</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 10-60000"/> + </constraint> + </properties> + </leafNode> + </children> +</node> +<leafNode name="shutdown"> + <properties> + <help>Disable this peer</help> + <valueless/> + </properties> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/bgp-afi-allowas-in.xml.i b/interface-definitions/include/bgp-afi-allowas-in.xml.i new file mode 100644 index 000000000..77de04ed7 --- /dev/null +++ b/interface-definitions/include/bgp-afi-allowas-in.xml.i @@ -0,0 +1,21 @@ +<!-- included start from bgp-afi-allowas-in.xml.i --> +<node name="allowas-in"> + <properties> + <help>Accept route that contains the local-as in the as-path</help> + </properties> + <children> + <leafNode name="number"> + <properties> + <help>Number of occurrences of AS number</help> + <valueHelp> + <format>u32:1-10</format> + <description>Number of times AS is allowed in path</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-10"/> + </constraint> + </properties> + </leafNode> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/bgp-afi-attribute-unchanged.xml.i b/interface-definitions/include/bgp-afi-attribute-unchanged.xml.i new file mode 100644 index 000000000..fef53dd9d --- /dev/null +++ b/interface-definitions/include/bgp-afi-attribute-unchanged.xml.i @@ -0,0 +1,27 @@ +<!-- included start from bgp-afi-attribute-unchanged.xml.i --> +<node name="attribute-unchanged"> + <properties> + <help>BGP attributes are sent unchanged</help> + </properties> + <children> + <leafNode name="as-path"> + <properties> + <help>Send AS path unchanged</help> + <valueless/> + </properties> + </leafNode> + <leafNode name="med"> + <properties> + <help>Send multi-exit discriminator unchanged</help> + <valueless/> + </properties> + </leafNode> + <leafNode name="next-hop"> + <properties> + <help>Send nexthop unchanged</help> + <valueless/> + </properties> + </leafNode> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/bgp-afi-common.xml.i b/interface-definitions/include/bgp-afi-common.xml.i index ea4eea591..90c2753c8 100644 --- a/interface-definitions/include/bgp-afi-common.xml.i +++ b/interface-definitions/include/bgp-afi-common.xml.i @@ -1,54 +1,24 @@ <!-- included start from bgp-afi-common.xml.i --> -<node name="allowas-in"> +<leafNode name="addpath-tx-all"> <properties> - <help>Accept route that contains the local-as in the as-path</help> + <help>Use addpath to advertise all paths to a neighbor</help> + <valueless/> </properties> - <children> - <leafNode name="number"> - <properties> - <help>Number of occurrences of AS number</help> - <valueHelp> - <format>u32:1-10</format> - <description>Number of times AS is allowed in path</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-10"/> - </constraint> - </properties> - </leafNode> - </children> -</node> -<leafNode name="as-override"> +</leafNode> +<leafNode name="addpath-tx-per-as"> <properties> - <help>AS for routes sent to this peer to be the local AS</help> + <help>Use addpath to advertise the bestpath per each neighboring AS</help> <valueless/> </properties> </leafNode> -<node name="attribute-unchanged"> +#include <include/bgp-afi-allowas-in.xml.i> +<leafNode name="as-override"> <properties> - <help>BGP attributes are sent unchanged</help> + <help>AS for routes sent to this peer to be the local AS</help> + <valueless/> </properties> - <children> - <leafNode name="as-path"> - <properties> - <help>Send AS path unchanged</help> - <valueless/> - </properties> - </leafNode> - <leafNode name="med"> - <properties> - <help>Send multi-exit discriminator unchanged</help> - <valueless/> - </properties> - </leafNode> - <leafNode name="next-hop"> - <properties> - <help>Send nexthop unchanged</help> - <valueless/> - </properties> - </leafNode> - </children> -</node> +</leafNode> +#include <include/bgp-afi-attribute-unchanged.xml.i> <node name="disable-send-community"> <properties> <help>Disable sending community attributes to this peer</help> @@ -73,14 +43,7 @@ <help>Originate default route to this peer</help> </properties> <children> - <leafNode name="route-map"> - <properties> - <help>route-map to specify criteria of the default route</help> - <completionHelp> - <path>policy route-map</path> - </completionHelp> - </properties> - </leafNode> + #include <include/bgp-route-map.xml.i> </children> </node> <node name="distribute-list"> @@ -155,77 +118,23 @@ </constraint> </properties> </leafNode> -<node name="nexthop-self"> - <properties> - <help>Disable the next hop calculation for this peer</help> - </properties> - <children> - <leafNode name="force"> - <properties> - <help>Set the next hop to self for reflected routes</help> - <valueless/> - </properties> - </leafNode> - </children> -</node> +#include <include/bgp-afi-nexthop-self.xml.i> <leafNode name="remove-private-as"> <properties> <help>Remove private AS numbers from AS path in outbound route updates</help> <valueless/> </properties> </leafNode> -<node name="route-map"> - <properties> - <help>Route-map to filter route updates to/from this peer</help> - </properties> - <children> - <leafNode name="export"> - <properties> - <help>Route-map to filter outgoing route updates</help> - <completionHelp> - <path>policy route-map</path> - </completionHelp> - </properties> - </leafNode> - <leafNode name="import"> - <properties> - <help>Route-map to filter incoming route updates</help> - <completionHelp> - <path>policy route-map</path> - </completionHelp> - </properties> - </leafNode> - </children> -</node> -<leafNode name="route-reflector-client"> - <properties> - <help>Peer is a route reflector client</help> - <valueless/> - </properties> -</leafNode> -<leafNode name="route-server-client"> - <properties> - <help>Peer is a route server client</help> - <valueless/> - </properties> -</leafNode> -<node name="soft-reconfiguration"> - <properties> - <help>Soft reconfiguration for peer</help> - </properties> - <children> - <leafNode name="inbound"> - <properties> - <help>Enable inbound soft reconfiguration</help> - <valueless/> - </properties> - </leafNode> - </children> -</node> +#include <include/bgp-afi-route-map.xml.i> +#include <include/bgp-afi-route-reflector-client.xml.i> +#include <include/bgp-afi-route-server-client.xml.i> +#include <include/bgp-afi-soft-reconfiguration.xml.i> <leafNode name="unsuppress-map"> <properties> <help>Route-map to selectively unsuppress suppressed routes</help> - <valueless/> + <completionHelp> + <path>policy route-map</path> + </completionHelp> </properties> </leafNode> <leafNode name="weight"> diff --git a/interface-definitions/include/bgp-afi-l2vpn-common.xml.i b/interface-definitions/include/bgp-afi-l2vpn-common.xml.i new file mode 100644 index 000000000..11b1cf6bf --- /dev/null +++ b/interface-definitions/include/bgp-afi-l2vpn-common.xml.i @@ -0,0 +1,14 @@ +<!-- included start from bgp-afi-l2vpn-common.xml.i --> +<leafNode name="advertise-default-gw"> + <properties> + <help>Advertise All default g/w mac-ip routes in EVPN</help> + <valueless/> + </properties> +</leafNode> +<leafNode name="advertise-svi-ip"> + <properties> + <help>Advertise svi mac-ip routes in EVPN</help> + <valueless/> + </properties> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/bgp-afi-nexthop-self.xml.i b/interface-definitions/include/bgp-afi-nexthop-self.xml.i new file mode 100644 index 000000000..0bcc4e937 --- /dev/null +++ b/interface-definitions/include/bgp-afi-nexthop-self.xml.i @@ -0,0 +1,15 @@ +<!-- included start from bgp-afi-nexthop-self.xml.i --> +<node name="nexthop-self"> + <properties> + <help>Disable the next hop calculation for this peer</help> + </properties> + <children> + <leafNode name="force"> + <properties> + <help>Set the next hop to self for reflected routes</help> + <valueless/> + </properties> + </leafNode> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/bgp-afi-peer-group.xml.i b/interface-definitions/include/bgp-afi-peer-group.xml.i deleted file mode 100644 index c98a91030..000000000 --- a/interface-definitions/include/bgp-afi-peer-group.xml.i +++ /dev/null @@ -1,7 +0,0 @@ -<!-- included start from bgp-afi-peer-group.xml.i --> -<leafNode name="peer-group"> - <properties> - <help>Peer group used for this neighbor</help> - </properties> -</leafNode> -<!-- included end --> diff --git a/interface-definitions/include/bgp-afi-redistribute-metric-route-map.xml.i b/interface-definitions/include/bgp-afi-redistribute-metric-route-map.xml.i index afd56eff3..e85bf7d11 100644 --- a/interface-definitions/include/bgp-afi-redistribute-metric-route-map.xml.i +++ b/interface-definitions/include/bgp-afi-redistribute-metric-route-map.xml.i @@ -8,12 +8,5 @@ </valueHelp> </properties> </leafNode> -<leafNode name="route-map"> - <properties> - <help>Route map to filter redistributed routes</help> - <completionHelp> - <path>policy route-map</path> - </completionHelp> - </properties> -</leafNode> +#include <include/bgp-route-map.xml.i> <!-- included end --> diff --git a/interface-definitions/include/bgp-afi-route-map.xml.i b/interface-definitions/include/bgp-afi-route-map.xml.i new file mode 100644 index 000000000..5549f56ca --- /dev/null +++ b/interface-definitions/include/bgp-afi-route-map.xml.i @@ -0,0 +1,25 @@ +<!-- included start from bgp-afi-route-map.xml.i --> +<node name="route-map"> + <properties> + <help>Route-map to filter route updates to/from this peer</help> + </properties> + <children> + <leafNode name="export"> + <properties> + <help>Route-map to filter outgoing route updates</help> + <completionHelp> + <path>policy route-map</path> + </completionHelp> + </properties> + </leafNode> + <leafNode name="import"> + <properties> + <help>Route-map to filter incoming route updates</help> + <completionHelp> + <path>policy route-map</path> + </completionHelp> + </properties> + </leafNode> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/bgp-afi-route-reflector-client.xml.i b/interface-definitions/include/bgp-afi-route-reflector-client.xml.i new file mode 100644 index 000000000..f6a9caa61 --- /dev/null +++ b/interface-definitions/include/bgp-afi-route-reflector-client.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp-afi-route-reflector-client.xml.i --> +<leafNode name="route-reflector-client"> + <properties> + <help>Peer is a route reflector client</help> + <valueless/> + </properties> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/bgp-afi-route-server-client.xml.i b/interface-definitions/include/bgp-afi-route-server-client.xml.i new file mode 100644 index 000000000..60de553fe --- /dev/null +++ b/interface-definitions/include/bgp-afi-route-server-client.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp-afi-route-server-client.xml.i --> +<leafNode name="route-server-client"> + <properties> + <help>Peer is a route server client</help> + <valueless/> + </properties> +</leafNode> +<!-- included end -->
\ No newline at end of file diff --git a/interface-definitions/include/bgp-afi-soft-reconfiguration.xml.i b/interface-definitions/include/bgp-afi-soft-reconfiguration.xml.i new file mode 100644 index 000000000..7af11f8f4 --- /dev/null +++ b/interface-definitions/include/bgp-afi-soft-reconfiguration.xml.i @@ -0,0 +1,15 @@ +<!-- included start from bgp-afi-soft-reconfiguration.xml.i --> +<node name="soft-reconfiguration"> + <properties> + <help>Soft reconfiguration for peer</help> + </properties> + <children> + <leafNode name="inbound"> + <properties> + <help>Enable inbound soft reconfiguration</help> + <valueless/> + </properties> + </leafNode> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/bgp-capability-dynamic.xml.i b/interface-definitions/include/bgp-capability-dynamic.xml.i deleted file mode 100644 index 3cf300156..000000000 --- a/interface-definitions/include/bgp-capability-dynamic.xml.i +++ /dev/null @@ -1,9 +0,0 @@ -<!-- included start from bgp-capability-dynamic.xml.i --> -<!-- Capability dynamic in the afi ipv6 does nothing T3037 --> -<leafNode name="dynamic"> - <properties> - <help>Advertise dynamic capability to this neighbor</help> - <valueless/> - </properties> -</leafNode> -<!-- included end --> diff --git a/interface-definitions/include/bgp-capability.xml.i b/interface-definitions/include/bgp-capability.xml.i index 5940e46e4..8de5bd8ab 100644 --- a/interface-definitions/include/bgp-capability.xml.i +++ b/interface-definitions/include/bgp-capability.xml.i @@ -4,7 +4,12 @@ <help>Advertise capabilities to this peer-group</help> </properties> <children> - #include <include/bgp-capability-dynamic.xml.i> + <leafNode name="dynamic"> + <properties> + <help>Advertise dynamic capability to this neighbor</help> + <valueless/> + </properties> + </leafNode> <leafNode name="extended-nexthop"> <properties> <help>Advertise extended-nexthop capability to this neighbor</help> diff --git a/interface-definitions/include/bgp-neighbor-afi-ipv4-unicast.xml.i b/interface-definitions/include/bgp-neighbor-afi-ipv4-unicast.xml.i index 03a859271..ece277fbf 100644 --- a/interface-definitions/include/bgp-neighbor-afi-ipv4-unicast.xml.i +++ b/interface-definitions/include/bgp-neighbor-afi-ipv4-unicast.xml.i @@ -10,10 +10,8 @@ </properties> <children> #include <include/bgp-afi-capability-orf.xml.i> - #include <include/bgp-capability-dynamic.xml.i> </children> </node> - #include <include/bgp-afi-peer-group.xml.i> #include <include/bgp-afi-ipv4-prefix-list.xml.i> #include <include/bgp-afi-common.xml.i> </children> diff --git a/interface-definitions/include/bgp-neighbor-afi-ipv6-unicast.xml.i b/interface-definitions/include/bgp-neighbor-afi-ipv6-unicast.xml.i index e9ba23408..e43c34113 100644 --- a/interface-definitions/include/bgp-neighbor-afi-ipv6-unicast.xml.i +++ b/interface-definitions/include/bgp-neighbor-afi-ipv6-unicast.xml.i @@ -10,10 +10,8 @@ </properties> <children> #include <include/bgp-afi-capability-orf.xml.i> - #include <include/bgp-capability-dynamic.xml.i> </children> </node> - #include <include/bgp-afi-peer-group.xml.i> #include <include/bgp-afi-ipv6-nexthop-local.xml.i> #include <include/bgp-afi-ipv6-prefix-list.xml.i> #include <include/bgp-afi-common.xml.i> diff --git a/interface-definitions/include/bgp-neighbor-afi-l2vpn-evpn.xml.i b/interface-definitions/include/bgp-neighbor-afi-l2vpn-evpn.xml.i new file mode 100644 index 000000000..df346afc1 --- /dev/null +++ b/interface-definitions/include/bgp-neighbor-afi-l2vpn-evpn.xml.i @@ -0,0 +1,16 @@ +<!-- included start from bgp-neighbor-afi-l2vpn-evpn.xml.i --> +<node name="l2vpn-evpn"> + <properties> + <help>L2VPN EVPN BGP settings</help> + </properties> + <children> + #include <include/bgp-afi-allowas-in.xml.i> + #include <include/bgp-afi-attribute-unchanged.xml.i> + #include <include/bgp-afi-nexthop-self.xml.i> + #include <include/bgp-afi-route-map.xml.i> + #include <include/bgp-afi-route-reflector-client.xml.i> + #include <include/bgp-afi-route-server-client.xml.i> + #include <include/bgp-afi-soft-reconfiguration.xml.i> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/bgp-peer-group.xml.i b/interface-definitions/include/bgp-peer-group.xml.i index 24585c1ce..73c80e0e4 100644 --- a/interface-definitions/include/bgp-peer-group.xml.i +++ b/interface-definitions/include/bgp-peer-group.xml.i @@ -2,6 +2,10 @@ <leafNode name="peer-group"> <properties> <help>Peer group for this peer</help> + <valueHelp> + <format>txt</format> + <description>Peer-group name</description> + </valueHelp> </properties> </leafNode> <!-- included end --> diff --git a/interface-definitions/include/bgp-shutdown.xml.i b/interface-definitions/include/bgp-shutdown.xml.i index 330120bba..fefbfcebb 100644 --- a/interface-definitions/include/bgp-shutdown.xml.i +++ b/interface-definitions/include/bgp-shutdown.xml.i @@ -1,7 +1,7 @@ <!-- included start from bgp-shutdown.xml.i --> <leafNode name="shutdown"> <properties> - <help>Administratively shut down peer-group</help> + <help>Administratively shut down this neighbor</help> <valueless/> </properties> </leafNode> diff --git a/interface-definitions/include/bgp-update-source.xml.i b/interface-definitions/include/bgp-update-source.xml.i index c1db2e2c1..a8b212720 100644 --- a/interface-definitions/include/bgp-update-source.xml.i +++ b/interface-definitions/include/bgp-update-source.xml.i @@ -21,7 +21,7 @@ <constraint> <validator name="ipv4-address"/> <validator name="ipv6-address"/> - <regex>^(br|bond|dum|en|eth|gnv|peth|tun|vti|vxlan|wg|wlan)[0-9]+|lo$</regex> + <validator name="interface-name"/> </constraint> </properties> </leafNode> diff --git a/interface-definitions/include/interface-parameters-flowlabel.xml.i b/interface-definitions/include/interface-parameters-flowlabel.xml.i new file mode 100644 index 000000000..ae65c27c9 --- /dev/null +++ b/interface-definitions/include/interface-parameters-flowlabel.xml.i @@ -0,0 +1,16 @@ +<!-- included start from interface-parameters-flowlabel.xml.i --> +<leafNode name="flowlabel"> + <properties> + <help>Specifies the flow label to use in outgoing packets</help> + <valueHelp> + <format>0x0-0x0FFFFF</format> + <description>Tunnel key, 'inherit' or hex value</description> + </valueHelp> + <constraint> + <regex>^((0x){0,1}(0?[0-9A-Fa-f]{1,5})|inherit)$</regex> + </constraint> + <constraintErrorMessage>Must be 'inherit' or a number</constraintErrorMessage> + </properties> + <defaultValue>inherit</defaultValue> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/interface-parameters-key.xml.i b/interface-definitions/include/interface-parameters-key.xml.i new file mode 100644 index 000000000..e918ff0e8 --- /dev/null +++ b/interface-definitions/include/interface-parameters-key.xml.i @@ -0,0 +1,15 @@ +<!-- included start from interface-parameters-key.xml.i --> +<leafNode name="key"> + <properties> + <help>Tunnel key</help> + <valueHelp> + <format>u32</format> + <description>Tunnel key</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-4294967295"/> + </constraint> + <constraintErrorMessage>key must be between 0-4294967295</constraintErrorMessage> + </properties> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/interface-parameters-tos.xml.i b/interface-definitions/include/interface-parameters-tos.xml.i new file mode 100644 index 000000000..ebb537bed --- /dev/null +++ b/interface-definitions/include/interface-parameters-tos.xml.i @@ -0,0 +1,16 @@ +<!-- included start from tunnel-parameters-tos.xml.i --> +<leafNode name="tos"> + <properties> + <help>Specifies TOS value to use in outgoing packets</help> + <valueHelp> + <format>0-99</format> + <description>Type of Service (TOS)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-99"/> + </constraint> + <constraintErrorMessage>TOS must be between 0 and 99</constraintErrorMessage> + </properties> + <defaultValue>inherit</defaultValue> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/interface-parameters-ttl.xml.i b/interface-definitions/include/interface-parameters-ttl.xml.i new file mode 100644 index 000000000..a6a6f163f --- /dev/null +++ b/interface-definitions/include/interface-parameters-ttl.xml.i @@ -0,0 +1,20 @@ +<!-- included start from interface-parameters-ttl.xml.i --> +<leafNode name="ttl"> + <properties> + <help>Specifies TTL value to use in outgoing packets (default: 0)</help> + <valueHelp> + <format>0</format> + <description>Copy value from original IP header</description> + </valueHelp> + <valueHelp> + <format>1-255</format> + <description>Time to Live</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-255"/> + </constraint> + <constraintErrorMessage>TTL must be between 0 and 255</constraintErrorMessage> + </properties> + <defaultValue>0</defaultValue> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/ospf-authentication.xml.i b/interface-definitions/include/ospf-authentication.xml.i new file mode 100644 index 000000000..efb29c1f0 --- /dev/null +++ b/interface-definitions/include/ospf-authentication.xml.i @@ -0,0 +1,56 @@ +<!-- included start from ospf-authentication.xml.i --> +<node name="authentication"> + <properties> + <help>Authentication</help> + </properties> + <children> + <node name="md5"> + <properties> + <help>MD5 key id</help> + </properties> + <children> + <tagNode name="key-id"> + <properties> + <help>MD5 key id</help> + <valueHelp> + <format>u32:1-255</format> + <description>MD5 key id</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-255"/> + </constraint> + </properties> + <children> + <leafNode name="md5-key"> + <properties> + <help>MD5 authentication type</help> + <valueHelp> + <format>txt</format> + <description>MD5 Key (16 characters or less)</description> + </valueHelp> + <constraint> + <regex>^[^[:space:]]{1,16}$</regex> + </constraint> + <constraintErrorMessage>Password must be 16 characters or less</constraintErrorMessage> + </properties> + </leafNode> + </children> + </tagNode> + </children> + </node> + <leafNode name="plaintext-password"> + <properties> + <help>Plain text password</help> + <valueHelp> + <format>txt</format> + <description>Plain text password (8 characters or less)</description> + </valueHelp> + <constraint> + <regex>^[^[:space:]]{1,8}$</regex> + </constraint> + <constraintErrorMessage>Password must be 8 characters or less</constraintErrorMessage> + </properties> + </leafNode> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/ospf-interface-common.xml.i b/interface-definitions/include/ospf-interface-common.xml.i new file mode 100644 index 000000000..c3493faa3 --- /dev/null +++ b/interface-definitions/include/ospf-interface-common.xml.i @@ -0,0 +1,39 @@ +<!-- included start from ospf-interface-common.xml.i --> +<leafNode name="bfd"> + <properties> + <help>Enable Bidirectional Forwarding Detection (BFD) support</help> + <valueless/> + </properties> +</leafNode> +<leafNode name="cost"> + <properties> + <help>Interface cost</help> + <valueHelp> + <format>u32:1-65535</format> + <description>OSPF interface cost</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-65535"/> + </constraint> + </properties> +</leafNode> +<leafNode name="mtu-ignore"> + <properties> + <help>Disable Maximum Transmission Unit (MTU) mismatch detection</help> + <valueless/> + </properties> +</leafNode> +<leafNode name="priority"> + <properties> + <help>Router priority (default: 1)</help> + <valueHelp> + <format>u32:0-255</format> + <description>OSPF router priority cost</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-255"/> + </constraint> + </properties> + <defaultValue>1</defaultValue> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/ospf-intervals.xml.i b/interface-definitions/include/ospf-intervals.xml.i new file mode 100644 index 000000000..e532bd14b --- /dev/null +++ b/interface-definitions/include/ospf-intervals.xml.i @@ -0,0 +1,54 @@ +<!-- included start from ospf-intervals.xml.i --> +<leafNode name="dead-interval"> + <properties> + <help>Interval after which a neighbor is declared dead (default: 40)</help> + <valueHelp> + <format>u32:1-65535</format> + <description>Neighbor dead interval (seconds)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-65535"/> + </constraint> + </properties> + <defaultValue>40</defaultValue> +</leafNode> +<leafNode name="hello-interval"> + <properties> + <help>Interval between hello packets (default: 10)</help> + <valueHelp> + <format>u32:1-65535</format> + <description>Hello interval (seconds)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-65535"/> + </constraint> + </properties> + <defaultValue>10</defaultValue> +</leafNode> +<leafNode name="retransmit-interval"> + <properties> + <help>Interval between retransmitting lost link state advertisements (default: 5)</help> + <valueHelp> + <format>u32:1-65535</format> + <description>Retransmit interval (seconds)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-65535"/> + </constraint> + </properties> + <defaultValue>5</defaultValue> +</leafNode> +<leafNode name="transmit-delay"> + <properties> + <help>Link state transmit delay (default: 1)</help> + <valueHelp> + <format>u32:1-65535</format> + <description>Link state transmit delay (seconds)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-65535"/> + </constraint> + </properties> + <defaultValue>1</defaultValue> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/ospf-route-map.xml.i b/interface-definitions/include/ospf-route-map.xml.i index 8dc5b37da..943a477c0 100644 --- a/interface-definitions/include/ospf-route-map.xml.i +++ b/interface-definitions/include/ospf-route-map.xml.i @@ -2,6 +2,10 @@ <leafNode name="route-map"> <properties> <help>Route map reference</help> + <valueHelp> + <format>txt</format> + <description>Route map reference</description> + </valueHelp> <completionHelp> <path>policy route-map</path> </completionHelp> diff --git a/interface-definitions/include/radius-server-ipv4-ipv6.xml.i b/interface-definitions/include/radius-server-ipv4-ipv6.xml.i index e4919d86a..ab3c6d72a 100644 --- a/interface-definitions/include/radius-server-ipv4-ipv6.xml.i +++ b/interface-definitions/include/radius-server-ipv4-ipv6.xml.i @@ -22,8 +22,8 @@ </properties> <children> #include <include/generic-disable-node.xml.i> - #include <include/radius-server-key.xml.in> - #include <include/radius-server-port.xml.in> + #include <include/radius-server-key.xml.i> + #include <include/radius-server-port.xml.i> </children> </tagNode> #include <include/source-address-ipv4-ipv6.xml.i> diff --git a/interface-definitions/include/radius-server-ipv4.xml.i b/interface-definitions/include/radius-server-ipv4.xml.i index 9c73c4c49..15a421b9a 100644 --- a/interface-definitions/include/radius-server-ipv4.xml.i +++ b/interface-definitions/include/radius-server-ipv4.xml.i @@ -18,8 +18,8 @@ </properties> <children> #include <include/generic-disable-node.xml.i> - #include <include/radius-server-key.xml.in> - #include <include/radius-server-port.xml.in> + #include <include/radius-server-key.xml.i> + #include <include/radius-server-port.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/include/radius-server-key.xml.in b/interface-definitions/include/radius-server-key.xml.i index 32a01b402..32a01b402 100644 --- a/interface-definitions/include/radius-server-key.xml.in +++ b/interface-definitions/include/radius-server-key.xml.i diff --git a/interface-definitions/include/radius-server-port.xml.in b/interface-definitions/include/radius-server-port.xml.i index 71b6bddb7..71b6bddb7 100644 --- a/interface-definitions/include/radius-server-port.xml.in +++ b/interface-definitions/include/radius-server-port.xml.i diff --git a/interface-definitions/include/rip-access-list.xml.i b/interface-definitions/include/rip-access-list.xml.i new file mode 100644 index 000000000..0db6863e5 --- /dev/null +++ b/interface-definitions/include/rip-access-list.xml.i @@ -0,0 +1,39 @@ +<!-- included start from rip-access-list.xml.i --> +<node name="access-list"> + <properties> + <help>Access-list</help> + </properties> + <children> + <leafNode name="in"> + <properties> + <help>Access list to apply to input packets</help> + <valueHelp> + <format>u32</format> + <description>Access list to apply to input packets</description> + </valueHelp> + <completionHelp> + <path>policy access-list</path> + </completionHelp> + <constraint> + <validator name="numeric" argument="--range 0-4294967295"/> + </constraint> + </properties> + </leafNode> + <leafNode name="out"> + <properties> + <help>Access list to apply to output packets</help> + <valueHelp> + <format>u32</format> + <description>Access list to apply to output packets</description> + </valueHelp> + <completionHelp> + <path>policy access-list</path> + </completionHelp> + <constraint> + <validator name="numeric" argument="--range 0-4294967295"/> + </constraint> + </properties> + </leafNode> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/rip-access-list6.xml.i b/interface-definitions/include/rip-access-list6.xml.i new file mode 100644 index 000000000..6a8a37607 --- /dev/null +++ b/interface-definitions/include/rip-access-list6.xml.i @@ -0,0 +1,39 @@ +<!-- included start from rip-access-list.xml.i --> +<node name="access-list"> + <properties> + <help>Access-list</help> + </properties> + <children> + <leafNode name="in"> + <properties> + <help>Access list to apply to input packets</help> + <valueHelp> + <format>u32</format> + <description>Access list to apply to input packets</description> + </valueHelp> + <completionHelp> + <path>policy access-list6</path> + </completionHelp> + <constraint> + <validator name="numeric" argument="--range 0-4294967295"/> + </constraint> + </properties> + </leafNode> + <leafNode name="out"> + <properties> + <help>Access list to apply to output packets</help> + <valueHelp> + <format>u32</format> + <description>Access list to apply to output packets</description> + </valueHelp> + <completionHelp> + <path>policy access-list6</path> + </completionHelp> + <constraint> + <validator name="numeric" argument="--range 0-4294967295"/> + </constraint> + </properties> + </leafNode> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/rip-default-information.xml.i b/interface-definitions/include/rip-default-information.xml.i new file mode 100644 index 000000000..22a2f6ac7 --- /dev/null +++ b/interface-definitions/include/rip-default-information.xml.i @@ -0,0 +1,15 @@ +<!-- included start from rip-default-information.xml.i --> +<node name="default-information"> + <properties> + <help>Control distribution of default route</help> + </properties> + <children> + <leafNode name="originate"> + <properties> + <help>Distribute a default route</help> + <valueless/> + </properties> + </leafNode> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/rip-default-metric.xml.i b/interface-definitions/include/rip-default-metric.xml.i new file mode 100644 index 000000000..a5e6016d6 --- /dev/null +++ b/interface-definitions/include/rip-default-metric.xml.i @@ -0,0 +1,14 @@ +<!-- included start from rip-default-metric.xml.i --> +<leafNode name="default-metric"> + <properties> + <help>Metric of redistributed routes</help> + <valueHelp> + <format>u32:1-16</format> + <description>Default metric</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-16"/> + </constraint> + </properties> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/rip-interface.xml.i b/interface-definitions/include/rip-interface.xml.i new file mode 100644 index 000000000..6279c16c8 --- /dev/null +++ b/interface-definitions/include/rip-interface.xml.i @@ -0,0 +1,38 @@ +<!-- included start from rip-interface.xml.i --> +<tagNode name="interface"> + <properties> + <help>Interface name</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py</script> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Interface name</description> + </valueHelp> + <constraint> + <validator name="interface-name"/> + </constraint> + </properties> + <children> + <node name="split-horizon"> + <properties> + <help>Split horizon parameters</help> + </properties> + <children> + <leafNode name="disable"> + <properties> + <help>Disable split horizon on specified interface</help> + <valueless/> + </properties> + </leafNode> + <leafNode name="poison-reverse"> + <properties> + <help>Disable split horizon on specified interface</help> + <valueless/> + </properties> + </leafNode> + </children> + </node> + </children> +</tagNode> +<!-- included end --> diff --git a/interface-definitions/include/rip-prefix-list.xml.i b/interface-definitions/include/rip-prefix-list.xml.i new file mode 100644 index 000000000..58969a86b --- /dev/null +++ b/interface-definitions/include/rip-prefix-list.xml.i @@ -0,0 +1,33 @@ +<!-- included start from rip-prefix-list.xml.i --> +<node name="prefix-list"> + <properties> + <help>Prefix-list</help> + </properties> + <children> + <leafNode name="in"> + <properties> + <help>Prefix-list to apply to input packets</help> + <valueHelp> + <format>txt</format> + <description>Prefix-list to apply to input packets</description> + </valueHelp> + <completionHelp> + <path>policy prefix-list</path> + </completionHelp> + </properties> + </leafNode> + <leafNode name="out"> + <properties> + <help>Prefix-list to apply to output packets</help> + <valueHelp> + <format>txt</format> + <description>Prefix-list to apply to output packets</description> + </valueHelp> + <completionHelp> + <path>policy prefix-list</path> + </completionHelp> + </properties> + </leafNode> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/rip-prefix-list6.xml.i b/interface-definitions/include/rip-prefix-list6.xml.i new file mode 100644 index 000000000..f73f77d05 --- /dev/null +++ b/interface-definitions/include/rip-prefix-list6.xml.i @@ -0,0 +1,33 @@ +<!-- included start from rip-prefix-list.xml.i --> +<node name="prefix-list"> + <properties> + <help>Prefix-list</help> + </properties> + <children> + <leafNode name="in"> + <properties> + <help>Prefix-list to apply to input packets</help> + <valueHelp> + <format>txt</format> + <description>Prefix-list to apply to input packets</description> + </valueHelp> + <completionHelp> + <path>policy prefix-list6</path> + </completionHelp> + </properties> + </leafNode> + <leafNode name="out"> + <properties> + <help>Prefix-list to apply to output packets</help> + <valueHelp> + <format>txt</format> + <description>Prefix-list to apply to output packets</description> + </valueHelp> + <completionHelp> + <path>policy prefix-list6</path> + </completionHelp> + </properties> + </leafNode> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/rip-redistribute.xml.i b/interface-definitions/include/rip-redistribute.xml.i index f9dba3ffe..c7b9d2c09 100644 --- a/interface-definitions/include/rip-redistribute.xml.i +++ b/interface-definitions/include/rip-redistribute.xml.i @@ -11,16 +11,5 @@ </constraint> </properties> </leafNode> -<leafNode name="route-map"> - <properties> - <help>Route map reference</help> - <valueHelp> - <format>txt</format> - <description>Route map reference</description> - </valueHelp> - <completionHelp> - <path>policy route-map</path> - </completionHelp> - </properties> -</leafNode> +#include <include/ospf-route-map.xml.i> <!-- included end --> diff --git a/interface-definitions/include/rip-timers.xml.i b/interface-definitions/include/rip-timers.xml.i new file mode 100644 index 000000000..5ba19bb06 --- /dev/null +++ b/interface-definitions/include/rip-timers.xml.i @@ -0,0 +1,48 @@ +<!-- included start from rip-timers.xml.i --> +<node name="timers"> + <properties> + <help>RIPng timer values</help> + </properties> + <children> + <leafNode name="garbage-collection"> + <properties> + <help>Garbage collection timer</help> + <valueHelp> + <format>u32:5-2147483647</format> + <description>Garbage colletion time (default 120)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 5-2147483647"/> + </constraint> + </properties> + <defaultValue>120</defaultValue> + </leafNode> + <leafNode name="timeout"> + <properties> + <help>Routing information timeout timer</help> + <valueHelp> + <format>u32:5-2147483647</format> + <description>Routing information timeout timer (default 180)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 5-2147483647"/> + </constraint> + </properties> + <defaultValue>180</defaultValue> + </leafNode> + <leafNode name="update"> + <properties> + <help>Routing table update timer</help> + <valueHelp> + <format>u32:5-2147483647</format> + <description>Routing table update timer in seconds (default 30)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 5-2147483647"/> + </constraint> + </properties> + <defaultValue>30</defaultValue> + </leafNode> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/routing-passive-interface-xml.i b/interface-definitions/include/routing-passive-interface-xml.i new file mode 100644 index 000000000..8478620cf --- /dev/null +++ b/interface-definitions/include/routing-passive-interface-xml.i @@ -0,0 +1,24 @@ +<!-- included start from routing-passive-interface-xml.i --> +<leafNode name="passive-interface"> + <properties> + <help>Suppress routing updates on an interface</help> + <completionHelp> + <list>default</list> + <script>${vyos_completion_dir}/list_interfaces.py</script> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Interface to be passive (i.e. suppress routing updates)</description> + </valueHelp> + <valueHelp> + <format>default</format> + <description>Default to suppress routing updates on all interfaces</description> + </valueHelp> + <constraint> + <regex>^(default)$</regex> + <validator name="interface-name"/> + </constraint> + <multi/> + </properties> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/static-route-blackhole.xml.i b/interface-definitions/include/static-route-blackhole.xml.i new file mode 100644 index 000000000..d0a0c2079 --- /dev/null +++ b/interface-definitions/include/static-route-blackhole.xml.i @@ -0,0 +1,10 @@ +<!-- included start from static-route-blackhole.xml.i --> +<node name="blackhole"> + <properties> + <help>Silently discard packets when matched</help> + </properties> + <children> + #include <include/static-route-distance.xml.i> + </children> +</node> +<!-- included end --> diff --git a/interface-definitions/include/static-route-distance.xml.i b/interface-definitions/include/static-route-distance.xml.i new file mode 100644 index 000000000..d6c0d3d82 --- /dev/null +++ b/interface-definitions/include/static-route-distance.xml.i @@ -0,0 +1,14 @@ +<!-- included start from static-route-distance.xml.i --> +<leafNode name="distance"> + <properties> + <help>Distance for this route</help> + <valueHelp> + <format>u32:1-255</format> + <description>Distance for this route</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-255"/> + </constraint> + </properties> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/static-route-interface.xml.i b/interface-definitions/include/static-route-interface.xml.i new file mode 100644 index 000000000..0f10837df --- /dev/null +++ b/interface-definitions/include/static-route-interface.xml.i @@ -0,0 +1,17 @@ +<!-- included start from static-route-interface.xml.i --> +<leafNode name="interface"> + <properties> + <help>Gateway interface name</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py</script> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Gateway interface name</description> + </valueHelp> + <constraint> + <validator name="interface-name"/> + </constraint> + </properties> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/static-route-map.xml.i b/interface-definitions/include/static-route-map.xml.i new file mode 100644 index 000000000..25542b8b1 --- /dev/null +++ b/interface-definitions/include/static-route-map.xml.i @@ -0,0 +1,10 @@ +<!-- included start from static-route-map.xml.i --> +<leafNode name="route-map"> + <properties> + <help>Filter routes installed in local route map</help> + <completionHelp> + <path>policy route-map</path> + </completionHelp> + </properties> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/static-route-vrf.xml.i b/interface-definitions/include/static-route-vrf.xml.i new file mode 100644 index 000000000..70f8b0be8 --- /dev/null +++ b/interface-definitions/include/static-route-vrf.xml.i @@ -0,0 +1,19 @@ +<!-- included start from static-route-vrf.xml.i --> +<leafNode name="vrf"> + <properties> + <help>VRF to leak route</help> + <completionHelp> + <list>default</list> + <path>vrf name</path> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Name of VRF to leak to</description> + </valueHelp> + <constraint> + <regex>^(default)$</regex> + <validator name="vrf-name"/> + </constraint> + </properties> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/include/static-route.xml.i b/interface-definitions/include/static-route.xml.i new file mode 100644 index 000000000..386582e09 --- /dev/null +++ b/interface-definitions/include/static-route.xml.i @@ -0,0 +1,75 @@ +<!-- included start from static-route.xml.i --> +<tagNode name="route"> + <properties> + <help>VRF static IPv4 route</help> + <valueHelp> + <format>ipv4net</format> + <description>IPv4 static route</description> + </valueHelp> + <constraint> + <validator name="ipv4-prefix"/> + </constraint> + </properties> + <children> + <node name="blackhole"> + <properties> + <help>Silently discard pkts when matched</help> + </properties> + <children> + #include <include/static-route-distance.xml.i> + <leafNode name="tag"> + <properties> + <help>Tag value for this route</help> + <valueHelp> + <format>u32:1-4294967295</format> + <description>Tag value for this route</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-4294967295"/> + </constraint> + </properties> + </leafNode> + </children> + </node> + <tagNode name="interface"> + <properties> + <help>Next-hop IPv4 router interface</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py</script> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Gateway interface name</description> + </valueHelp> + <constraint> + <validator name="interface-name"/> + </constraint> + </properties> + <children> + #include <include/generic-disable-node.xml.i> + #include <include/static-route-distance.xml.i> + #include <include/static-route-vrf.xml.i> + </children> + </tagNode> + <tagNode name="next-hop"> + <properties> + <help>Next-hop IPv4 router address</help> + <valueHelp> + <format>ipv4</format> + <description>Next-hop router address</description> + </valueHelp> + <constraint> + <validator name="ipv4-address"/> + </constraint> + </properties> + <children> + #include <include/generic-disable-node.xml.i> + #include <include/static-route-distance.xml.i> + #include <include/static-route-interface.xml.i> + #include <include/static-route-vrf.xml.i> + </children> + </tagNode> + </children> +</tagNode> +<!-- included end --> + diff --git a/interface-definitions/include/static-route6.xml.i b/interface-definitions/include/static-route6.xml.i new file mode 100644 index 000000000..fcf97cd03 --- /dev/null +++ b/interface-definitions/include/static-route6.xml.i @@ -0,0 +1,75 @@ +<!-- included start from static-route6.xml.i --> +<tagNode name="route6"> + <properties> + <help>VRF static IPv6 route</help> + <valueHelp> + <format>ipv6net</format> + <description>IPv6 static route</description> + </valueHelp> + <constraint> + <validator name="ipv6-prefix"/> + </constraint> + </properties> + <children> + <node name="blackhole"> + <properties> + <help>Silently discard pkts when matched</help> + </properties> + <children> + #include <include/static-route-distance.xml.i> + <leafNode name="tag"> + <properties> + <help>Tag value for this route</help> + <valueHelp> + <format>u32:1-4294967295</format> + <description>Tag value for this route</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-4294967295"/> + </constraint> + </properties> + </leafNode> + </children> + </node> + <tagNode name="interface"> + <properties> + <help>IPv6 gateway interface name</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py</script> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Gateway interface name</description> + </valueHelp> + <constraint> + <validator name="interface-name"/> + </constraint> + </properties> + <children> + #include <include/generic-disable-node.xml.i> + #include <include/static-route-distance.xml.i> + #include <include/static-route-vrf.xml.i> + </children> + </tagNode> + <tagNode name="next-hop"> + <properties> + <help>IPv6 gateway address</help> + <valueHelp> + <format>ipv6</format> + <description>Next-hop IPv6 router</description> + </valueHelp> + <constraint> + <validator name="ipv6-address"/> + </constraint> + </properties> + <children> + #include <include/generic-disable-node.xml.i> + #include <include/static-route-distance.xml.i> + #include <include/static-route-interface.xml.i> + #include <include/static-route-vrf.xml.i> + </children> + </tagNode> + </children> +</tagNode> +<!-- included end --> + diff --git a/interface-definitions/include/tunnel-local-remote-ip.xml.i b/interface-definitions/include/tunnel-local-remote-ip.xml.i new file mode 100644 index 000000000..85c20f482 --- /dev/null +++ b/interface-definitions/include/tunnel-local-remote-ip.xml.i @@ -0,0 +1,37 @@ +<!-- included start from tunnel-local-remote-ip.xml.i --> +<leafNode name="local-ip"> + <properties> + <help>Local IP address for this tunnel</help> + <valueHelp> + <format>ipv4</format> + <description>Local IPv4 address for this tunnel</description> + </valueHelp> + <valueHelp> + <format>ipv6</format> + <description>Local IPv6 address for this tunnel</description> + </valueHelp> + <completionHelp> + <script>${vyos_completion_dir}/list_local_ips.sh --both</script> + </completionHelp> + <constraint> + <validator name="ip-address"/> + </constraint> + </properties> +</leafNode> +<leafNode name="remote-ip"> + <properties> + <help>Remote IP address for this tunnel</help> + <valueHelp> + <format>ipv4</format> + <description>Remote IPv4 address for this tunnel</description> + </valueHelp> + <valueHelp> + <format>ipv6</format> + <description>Remote IPv6 address for this tunnel</description> + </valueHelp> + <constraint> + <!-- does it need fixing/changing to be more restrictive ? --> + <validator name="ip-address"/> + </constraint> + </properties> +</leafNode> diff --git a/interface-definitions/include/vif-s.xml.i b/interface-definitions/include/vif-s.xml.i index 6ba7e0b99..01cb59efc 100644 --- a/interface-definitions/include/vif-s.xml.i +++ b/interface-definitions/include/vif-s.xml.i @@ -61,6 +61,7 @@ #include <include/interface-vrf.xml.i> </children> </tagNode> + #include <include/interface-vrf.xml.i> </children> </tagNode> <!-- included end --> diff --git a/interface-definitions/include/vni.xml.i b/interface-definitions/include/vni.xml.i new file mode 100644 index 000000000..faff4c3c3 --- /dev/null +++ b/interface-definitions/include/vni.xml.i @@ -0,0 +1,12 @@ + <leafNode name="vni"> + <properties> + <help>Virtual Network Identifier</help> + <valueHelp> + <format>0-16777214</format> + <description>VXLAN virtual network identifier</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-16777214"/> + </constraint> + </properties> + </leafNode> diff --git a/interface-definitions/interfaces-erspan.xml.in b/interface-definitions/interfaces-erspan.xml.in new file mode 100644 index 000000000..e36a64d3a --- /dev/null +++ b/interface-definitions/interfaces-erspan.xml.in @@ -0,0 +1,113 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="interfaces"> + <children> + <tagNode name="erspan" owner="${vyos_conf_scripts_dir}/interfaces-erspan.py"> + <properties> + <help>Encapsulated Remote SPAN over GRE and IPv4/IPv6 Tunnel Interface</help> + <priority>310</priority> + <constraint> + <regex>^ersp[0-9]+$</regex> + </constraint> + <constraintErrorMessage>ERSPAN tunnel interface must be named erspN</constraintErrorMessage> + <valueHelp> + <format>erspN</format> + <description>ERSPAN Tunnel interface name</description> + </valueHelp> + </properties> + <children> + #include <include/interface-description.xml.i> + #include <include/interface-disable.xml.i> + #include <include/interface-disable-link-detect.xml.i> + #include <include/interface-mtu-64-8024.xml.i> + #include <include/tunnel-local-remote-ip.xml.i> + <leafNode name="encapsulation"> + <properties> + <help>Encapsulation of this tunnel interface</help> + <completionHelp> + <list>erspan ip6erspan</list> + </completionHelp> + <valueHelp> + <format>erspan</format> + <description>Generic Routing Encapsulation</description> + </valueHelp> + <valueHelp> + <format>ip6erspan</format> + <description>Generic Routing Encapsulation bridge interface</description> + </valueHelp> + <constraint> + <regex>^(erspan|ip6erspan)$</regex> + </constraint> + <constraintErrorMessage>Invalid encapsulation, must be one of: erspan, ip6erspan</constraintErrorMessage> + </properties> + </leafNode> + <node name="parameters"> + <properties> + <help>ERSPAN Tunnel parameters</help> + </properties> + <children> + <node name="ip"> + <properties> + <help>IPv4 specific tunnel parameters</help> + </properties> + <children> + #include <include/interface-parameters-key.xml.i> + #include <include/interface-parameters-tos.xml.i> + #include <include/interface-parameters-ttl.xml.i> + </children> + </node> + <leafNode name="version"> + <properties> + <help>ERSPAN version number setting(default:1)</help> + <constraint> + <validator name="numeric" argument="--range 1-2"/> + </constraint> + <constraintErrorMessage>The version number of ERSPAN must be 1 or 2</constraintErrorMessage> + </properties> + <defaultValue>1</defaultValue> + </leafNode> + <leafNode name="direction"> + <properties> + <help>Specifies mirrored traffic direction</help> + <completionHelp> + <list>ingress egress</list> + </completionHelp> + <valueHelp> + <format>ingress</format> + <description>Mirror ingress direction</description> + </valueHelp> + <valueHelp> + <format>egress</format> + <description>Mirror egress direction</description> + </valueHelp> + <constraint> + <regex>^(ingress|egress)$</regex> + </constraint> + <constraintErrorMessage>The mirror direction of ERSPAN must be ingress or egress</constraintErrorMessage> + </properties> + </leafNode> + <leafNode name="hwid"> + <properties> + <help>an unique identifier of an ERSPAN v2 engine within a system</help> + <constraint> + <validator name="numeric" argument="--range 1-1048575"/> + </constraint> + <constraintErrorMessage>ERSPAN hwid must be a number(range:0-1048575)</constraintErrorMessage> + </properties> + </leafNode> + <leafNode name="idx"> + <properties> + <help>specifies the ERSPAN v1 index field</help> + <constraint> + <validator name="numeric" argument="--range 0-63"/> + </constraint> + <constraintErrorMessage>ERSPAN idx must be a number(range:0-63)</constraintErrorMessage> + </properties> + </leafNode> + </children> + </node> + </children> + </tagNode> + </children> + </node> +</interfaceDefinition> diff --git a/interface-definitions/interfaces-geneve.xml.in b/interface-definitions/interfaces-geneve.xml.in index 0c776e3c3..1064b2c18 100644 --- a/interface-definitions/interfaces-geneve.xml.in +++ b/interface-definitions/interfaces-geneve.xml.in @@ -35,18 +35,7 @@ </constraint> </properties> </leafNode> - <leafNode name="vni"> - <properties> - <help>Virtual Network Identifier</help> - <valueHelp> - <format>0-16777214</format> - <description>GENEVE virtual network identifier</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-16777214"/> - </constraint> - </properties> - </leafNode> + #include <include/vni.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in index 7fa847ab0..7a97980a2 100644 --- a/interface-definitions/interfaces-tunnel.xml.in +++ b/interface-definitions/interfaces-tunnel.xml.in @@ -27,42 +27,7 @@ </leafNode> #include <include/interface-ipv4-options.xml.i> #include <include/interface-ipv6-options.xml.i> - <leafNode name="local-ip"> - <properties> - <help>Local IP address for this tunnel</help> - <valueHelp> - <format>ipv4</format> - <description>Local IPv4 address for this tunnel</description> - </valueHelp> - <valueHelp> - <format>ipv6</format> - <description>Local IPv6 address for this tunnel [NOTICE: unavailable for mGRE tunnels]</description> - </valueHelp> - <completionHelp> - <script>${vyos_completion_dir}/list_local_ips.sh --both</script> - </completionHelp> - <constraint> - <validator name="ip-address"/> - </constraint> - </properties> - </leafNode> - <leafNode name="remote-ip"> - <properties> - <help>Remote IP address for this tunnel</help> - <valueHelp> - <format>ipv4</format> - <description>Remote IPv4 address for this tunnel</description> - </valueHelp> - <valueHelp> - <format>ipv6</format> - <description>Remote IPv6 address for this tunnel</description> - </valueHelp> - <constraint> - <!-- does it need fixing/changing to be more restrictive ? --> - <validator name="ip-address"/> - </constraint> - </properties> - </leafNode> + #include <include/tunnel-local-remote-ip.xml.i> <leafNode name="source-interface"> <properties> <help>Physical Interface used for underlaying traffic</help> @@ -186,58 +151,9 @@ <valueless/> </properties> </leafNode> - <leafNode name="ttl"> - <properties> - <help>Time to live (default: 0)</help> - <valueHelp> - <format>0</format> - <description>Copy value from original IP header</description> - </valueHelp> - <valueHelp> - <format>1-255</format> - <description>Time to Live</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-255"/> - </constraint> - <constraintErrorMessage>TTL must be between 0 and 255</constraintErrorMessage> - </properties> - <defaultValue>0</defaultValue> - </leafNode> - <leafNode name="tos"> - <properties> - <help>Type of Service (default: 0)</help> - <completionHelp> - <list>inherit</list> - </completionHelp> - <valueHelp> - <format>0</format> - <description>Copy value from original IP header</description> - </valueHelp> - <valueHelp> - <format>1-99</format> - <description>Type of Service (TOS)</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-99"/> - </constraint> - <constraintErrorMessage>TOS must be between 0 and 99</constraintErrorMessage> - </properties> - <defaultValue>0</defaultValue> - </leafNode> - <leafNode name="key"> - <properties> - <help>Tunnel key</help> - <valueHelp> - <format>u32</format> - <description>Tunnel key</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-4294967295"/> - </constraint> - <constraintErrorMessage>Key must be in range 0-4294967295</constraintErrorMessage> - </properties> - </leafNode> + #include <include/interface-parameters-key.xml.i> + #include <include/interface-parameters-tos.xml.i> + #include <include/interface-parameters-ttl.xml.i> </children> </node> <node name="ipv6"> @@ -259,20 +175,7 @@ </properties> <defaultValue>4</defaultValue> </leafNode> - <leafNode name="flowlabel"> - <properties> - <help>Flowlabel</help> - <valueHelp> - <format>0x0-0x0FFFFF</format> - <description>Tunnel key, 'inherit' or hex value</description> - </valueHelp> - <constraint> - <regex>(0x){0,1}(0?[0-9A-Fa-f]{1,5})</regex> - </constraint> - <constraintErrorMessage>Must be 'inherit' or a number</constraintErrorMessage> - </properties> - <defaultValue>inherit</defaultValue> - </leafNode> + #include <include/interface-parameters-flowlabel.xml.i> <leafNode name="hoplimit"> <properties> <help>Hoplimit</help> diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in index f90a86274..234770971 100644 --- a/interface-definitions/interfaces-vxlan.xml.in +++ b/interface-definitions/interfaces-vxlan.xml.in @@ -73,18 +73,7 @@ </properties> <defaultValue>8472</defaultValue> </leafNode> - <leafNode name="vni"> - <properties> - <help>Virtual Network Identifier</help> - <valueHelp> - <format>0-16777214</format> - <description>VXLAN virtual network identifier</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-16777214"/> - </constraint> - </properties> - </leafNode> + #include <include/vni.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/protocols-bfd.xml.in b/interface-definitions/protocols-bfd.xml.in index 8900e7955..cc3c3bf12 100644 --- a/interface-definitions/protocols-bfd.xml.in +++ b/interface-definitions/protocols-bfd.xml.in @@ -11,7 +11,7 @@ <children> <tagNode name="peer"> <properties> - <help>Configures a new BFD peer to listen and talk to</help> + <help>Configures BFD peer to listen and talk to</help> <valueHelp> <format>ipv4</format> <description>BFD peer IPv4 address</description> @@ -26,6 +26,18 @@ </constraint> </properties> <children> + <leafNode name="profile"> + <properties> + <help>Use settings from BFD profile</help> + <completionHelp> + <path>protocols bfd profile</path> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>BFD profile name</description> + </valueHelp> + </properties> + </leafNode> <node name="source"> <properties> <help>Bind listener to specified interface/address, mandatory for IPv6</help> @@ -42,6 +54,9 @@ <leafNode name="address"> <properties> <help>Local address to bind our peer listener to</help> + <completionHelp> + <script>${vyos_completion_dir}/list_local_ips.sh --both</script> + </completionHelp> <valueHelp> <format>ipv4</format> <description>Local IPv4 address used to connect to the peer</description> @@ -58,79 +73,28 @@ </leafNode> </children> </node> - <node name="interval"> - <properties> - <help>Configure timer intervals</help> - </properties> - <children> - <leafNode name="receive"> - <properties> - <help>Minimum interval of receiving control packets</help> - <valueHelp> - <format>10-60000</format> - <description>Interval in milliseconds</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 10-60000"/> - </constraint> - </properties> - </leafNode> - <leafNode name="transmit"> - <properties> - <help>Minimum interval of transmitting control packets</help> - <valueHelp> - <format>10-60000</format> - <description>Interval in milliseconds</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 10-60000"/> - </constraint> - </properties> - </leafNode> - <leafNode name="multiplier"> - <properties> - <help>Multiplier to determine packet loss</help> - <valueHelp> - <format>2-255</format> - <description>Remote transmission interval will be multiplied by this value</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 2-255"/> - </constraint> - </properties> - </leafNode> - <leafNode name="echo-interval"> - <properties> - <help>Echo receive transmission interval</help> - <valueHelp> - <format>10-60000</format> - <description>The minimal echo receive transmission interval that this system is capable of handling</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 10-60000"/> - </constraint> - </properties> - </leafNode> - </children> - </node> - <leafNode name="shutdown"> - <properties> - <help>Disable this peer</help> - <valueless/> - </properties> - </leafNode> + #include <include/bfd-common.xml.i> <leafNode name="multihop"> <properties> <help>Allow this BFD peer to not be directly connected</help> <valueless/> </properties> </leafNode> - <leafNode name="echo-mode"> - <properties> - <help>Enables the echo transmission mode</help> - <valueless/> - </properties> - </leafNode> + </children> + </tagNode> + <tagNode name="profile"> + <properties> + <help>Configure BFD profile used by individual peer</help> + <valueHelp> + <format>txt</format> + <description>Name of BFD profile</description> + </valueHelp> + <constraint> + <regex>^[-_a-zA-Z0-9]{1,32}$</regex> + </constraint> + </properties> + <children> + #include <include/bfd-common.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/protocols-bgp.xml.in b/interface-definitions/protocols-bgp.xml.in index 3edacb0ca..69f4c2d52 100644 --- a/interface-definitions/protocols-bgp.xml.in +++ b/interface-definitions/protocols-bgp.xml.in @@ -75,6 +75,14 @@ #include <include/bgp-afi-redistribute-metric-route-map.xml.i> </children> </node> + <node name="isis"> + <properties> + <help>Redistribute IS-IS routes into BGP</help> + </properties> + <children> + #include <include/bgp-afi-redistribute-metric-route-map.xml.i> + </children> + </node> <node name="kernel"> <properties> <help>Redistribute kernel routes into BGP</help> @@ -217,6 +225,127 @@ </node> </children> </node> + <node name="l2vpn-evpn"> + <properties> + <help>L2VPN EVPN BGP settings</help> + </properties> + <children> + <leafNode name="advertise-all-vni"> + <properties> + <help>Advertise All local VNIs</help> + <valueless/> + </properties> + </leafNode> + #include <include/bgp-afi-l2vpn-common.xml.i> + <leafNode name="advertise-pip"> + <properties> + <help>EVPN system primary IP</help> + <valueHelp> + <format>ipv4</format> + <description>IP address</description> + </valueHelp> + <constraint> + <validator name="ipv4-address"/> + </constraint> + </properties> + </leafNode> + <leafNode name="rt-auto-derive"> + <properties> + <help>Auto derivation of Route Target (RFC8365)</help> + <valueless/> + </properties> + </leafNode> + <node name="flooding"> + <properties> + <help>Specify handling for BUM packets</help> + </properties> + <children> + <leafNode name="disable"> + <properties> + <help>Do not flood any BUM packets</help> + <valueless/> + </properties> + </leafNode> + <leafNode name="head-end-replication"> + <properties> + <help>Flood BUM packets using head-end replication</help> + <valueless/> + </properties> + </leafNode> + </children> + </node> + <leafNode name="rd"> + <properties> + <help>Route Distinguisher</help> + <valueHelp> + <format>txt</format> + <description>Route Distinguisher, asn:xxx</description> + </valueHelp> + <constraint> + <regex>^[0-9]{1,10}:[0-9]{1,5}$</regex> + </constraint> + </properties> + </leafNode> + <node name="route-target"> + <properties> + <help>Route Target</help> + </properties> + <children> + <leafNode name="both"> + <properties> + <help>Route Target both import and export</help> + <valueHelp> + <format>txt</format> + <description>Route target (x.x.x.x:yyy|xxxx:yyyy)</description> + </valueHelp> + <constraint> + <regex>^((25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)(\.(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)){3}|[0-9]{1,10}):[0-9]{1,5}$</regex> + </constraint> + </properties> + </leafNode> + <leafNode name="export"> + <properties> + <help>Route Target export</help> + <valueHelp> + <format>txt</format> + <description>Route target (x.x.x.x:yyy|xxxx:yyyy)</description> + </valueHelp> + <constraint> + <regex>^((25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)(\.(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)){3}|[0-9]{1,10}):[0-9]{1,5}$</regex> + </constraint> + </properties> + </leafNode> + <leafNode name="import"> + <properties> + <help>Route Target import</help> + <valueHelp> + <format>txt</format> + <description>Route target (x.x.x.x:yyy|xxxx:yyyy)</description> + </valueHelp> + <constraint> + <regex>^((25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)(\.(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)){3}|[0-9]{1,10}):[0-9]{1,5}$</regex> + </constraint> + </properties> + </leafNode> + </children> + </node> + <tagNode name="vni"> + <properties> + <help>VXLAN Network Identifier</help> + <valueHelp> + <format>u32:1-16777215</format> + <description>VNI number</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-16777215"/> + </constraint> + </properties> + <children> + #include <include/bgp-afi-l2vpn-common.xml.i> + </children> + </tagNode> + </children> + </node> </children> </node> <node name="maximum-paths"> @@ -307,7 +436,7 @@ <constraint> <validator name="ipv4-address"/> <validator name="ipv6-address"/> - <regex>^(br|bond|dum|en|eth|gnv|peth|tun|vti|vxlan|wg|wlan)[0-9]+|lo$</regex> + <validator name="interface-name"/> </constraint> </properties> <children> @@ -318,6 +447,7 @@ <children> #include <include/bgp-neighbor-afi-ipv4-unicast.xml.i> #include <include/bgp-neighbor-afi-ipv6-unicast.xml.i> + #include <include/bgp-neighbor-afi-l2vpn-evpn.xml.i> </children> </node> <leafNode name="advertisement-interval"> @@ -337,25 +467,6 @@ #include <include/bgp-description.xml.i> #include <include/bgp-disable-capability-negotiation.xml.i> #include <include/bgp-disable-connected-check.xml.i> - <node name="disable-send-community"> - <properties> - <help>Disable sending community attributes to this neighbor (IPv4)</help> - </properties> - <children> - <leafNode name="extended"> - <properties> - <help>Disable sending extended community attributes to this neighbor (IPv4)</help> - <valueless/> - </properties> - </leafNode> - <leafNode name="standard"> - <properties> - <help>Disable sending standard community attributes to this neighbor (IPv4)</help> - <valueless/> - </properties> - </leafNode> - </children> - </node> #include <include/bgp-ebgp-multihop.xml.i> <node name="interface"> <properties> @@ -721,6 +832,12 @@ </leafNode> </children> </node> + <leafNode name="graceful-shutdown"> + <properties> + <help>Graceful shutdown</help> + <valueless/> + </properties> + </leafNode> <leafNode name="log-neighbor-changes"> <properties> <help>Log neighbor up/down changes and reset reason</help> @@ -771,6 +888,7 @@ <children> #include <include/bgp-neighbor-afi-ipv4-unicast.xml.i> #include <include/bgp-neighbor-afi-ipv6-unicast.xml.i> + #include <include/bgp-neighbor-afi-l2vpn-evpn.xml.i> </children> </node> #include <include/bgp-bfd.xml.i> diff --git a/interface-definitions/protocols-multicast.xml.in b/interface-definitions/protocols-multicast.xml.in index a06f2b287..bf0ead78f 100644 --- a/interface-definitions/protocols-multicast.xml.in +++ b/interface-definitions/protocols-multicast.xml.in @@ -1,5 +1,4 @@ <?xml version="1.0"?> -<!-- Multicast static routing configuration --> <interfaceDefinition> <node name="protocols"> <children> diff --git a/interface-definitions/protocols-ospf.xml.in b/interface-definitions/protocols-ospf.xml.in index 074d0db63..b9c9fcc04 100644 --- a/interface-definitions/protocols-ospf.xml.in +++ b/interface-definitions/protocols-ospf.xml.in @@ -39,6 +39,10 @@ <description>Filter connected routes</description> </valueHelp> <valueHelp> + <format>isis</format> + <description>Filter IS-IS routes</description> + </valueHelp> + <valueHelp> <format>kernel</format> <description>Filter Kernel routes</description> </valueHelp> @@ -51,7 +55,7 @@ <description>Filter static routes</description> </valueHelp> <constraint> - <regex>^(bgp|connected|kernel|rip|static)$</regex> + <regex>^(bgp|connected|isis|kernel|rip|static)$</regex> </constraint> <constraintErrorMessage>Must be bgp, connected, kernel, rip, or static</constraintErrorMessage> <multi/> @@ -275,101 +279,8 @@ </constraint> </properties> <children> - <node name="authentication"> - <properties> - <help>Authentication</help> - </properties> - <children> - <node name="md5"> - <properties> - <help>MD5 key id</help> - </properties> - <children> - <tagNode name="key-id"> - <properties> - <help>MD5 key id</help> - <valueHelp> - <format>u32:1-255</format> - <description>MD5 key id</description> - </valueHelp> - </properties> - <children> - <leafNode name="md5-key"> - <properties> - <help>MD5 authentication type</help> - <valueHelp> - <format>txt</format> - <description>MD5 Key (16 characters or less)</description> - </valueHelp> - </properties> - </leafNode> - </children> - </tagNode> - </children> - </node> - <leafNode name="plaintext-password"> - <properties> - <help>Plain text password</help> - <valueHelp> - <format>txt</format> - <description>Plain text password (8 characters or less)</description> - </valueHelp> - </properties> - </leafNode> - </children> - </node> - <leafNode name="dead-interval"> - <properties> - <help>Interval after which a neighbor is declared dead (default: 40)</help> - <valueHelp> - <format>u32:1-65535</format> - <description>Neighbor dead interval (seconds)</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-65535"/> - </constraint> - </properties> - <defaultValue>40</defaultValue> - </leafNode> - <leafNode name="hello-interval"> - <properties> - <help>Interval between hello packets (default: 10)</help> - <valueHelp> - <format>u32:1-65535</format> - <description>Hello interval (seconds)</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-65535"/> - </constraint> - </properties> - <defaultValue>10</defaultValue> - </leafNode> - <leafNode name="retransmit-interval"> - <properties> - <help>Interval between retransmitting lost link state advertisements (default: 5)</help> - <valueHelp> - <format>u32:1-65535</format> - <description>Retransmit interval (seconds)</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-65535"/> - </constraint> - </properties> - <defaultValue>5</defaultValue> - </leafNode> - <leafNode name="transmit-delay"> - <properties> - <help>Link state transmit delay (default: 1)</help> - <valueHelp> - <format>u32:1-65535</format> - <description>Link state transmit delay (seconds)</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-65535"/> - </constraint> - </properties> - <defaultValue>1</defaultValue> - </leafNode> + #include <include/ospf-authentication.xml.i> + #include <include/ospf-intervals.xml.i> </children> </tagNode> </children> @@ -491,6 +402,78 @@ </node> </children> </node> + <tagNode name="interface"> + <properties> + <help>Interface related configuration</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py</script> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Interface name</description> + </valueHelp> + <constraint> + <validator name="interface-name"/> + </constraint> + </properties> + <children> + #include <include/ospf-authentication.xml.i> + #include <include/ospf-intervals.xml.i> + #include <include/ospf-interface-common.xml.i> + <leafNode name="bandwidth"> + <properties> + <help>Bandwidth of interface (Megabit/sec)</help> + <valueHelp> + <format>u32:1-100000</format> + <description>Bandwidth in Megabit/sec (for calculating OSPF cost)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-100000"/> + </constraint> + </properties> + </leafNode> + <leafNode name="hello-multiplier"> + <properties> + <help>Hello multiplier factor</help> + <valueHelp> + <format>u32:1-10</format> + <description>Number of Hellos to send each second</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-10"/> + </constraint> + </properties> + </leafNode> + <leafNode name="network"> + <properties> + <help>Network type</help> + <completionHelp> + <list>broadcast non-broadcast point-to-multipoint point-to-point</list> + </completionHelp> + <valueHelp> + <format>broadcast</format> + <description>Broadcast network type</description> + </valueHelp> + <valueHelp> + <format>non-broadcast</format> + <description>Non-broadcast network type</description> + </valueHelp> + <valueHelp> + <format>point-to-multipoint</format> + <description>Point-to-multipoint network type</description> + </valueHelp> + <valueHelp> + <format>point-to-point</format> + <description>Point-to-point network type</description> + </valueHelp> + <constraint> + <regex>^(broadcast|non-broadcast|point-to-multipoint|point-to-point)$</regex> + </constraint> + <constraintErrorMessage>Must be broadcast, non-broadcast, point-to-multipoint or point-to-point</constraintErrorMessage> + </properties> + </leafNode> + </children> + </tagNode> <node name="log-adjacency-changes"> <properties> <help>Log changes in adjacency state</help> @@ -673,27 +656,7 @@ </leafNode> </children> </node> - <leafNode name="passive-interface"> - <properties> - <help>Suppress routing updates on an interface</help> - <completionHelp> - <list>default</list> - <script>${vyos_completion_dir}/list_interfaces.py</script> - </completionHelp> - <valueHelp> - <format>txt</format> - <description>Interface to be passive (i.e. suppress routing updates)</description> - </valueHelp> - <valueHelp> - <format>default</format> - <description>Default to suppress routing updates on all interfaces</description> - </valueHelp> - <constraint> - <regex>^(br|bond|dum|en|eth|gnv|peth|tun|vti|vxlan|wg|wlan)[0-9]+|lo|default$</regex> - </constraint> - <multi/> - </properties> - </leafNode> + #include <include/routing-passive-interface-xml.i> <leafNode name="passive-interface-exclude"> <properties> <help>Interface to exclude when using 'passive-interface default'</help> @@ -702,10 +665,15 @@ </completionHelp> <valueHelp> <format>txt</format> - <description>Interface to be passive (i.e. suppress routing updates)</description> + <description>Interface to exclude when suppressing routing updates</description> + </valueHelp> + <valueHelp> + <format>vlinkN</format> + <description>Virtual-link interface to exclude when suppressing routing updates</description> </valueHelp> <constraint> - <regex>^(br|bond|dum|en|eth|gnv|peth|tun|vti|vxlan|wg|wlan)[0-9]+|lo$</regex> + <validator name="interface-name"/> + <regex>^(vlink[0-9]+)$</regex> </constraint> <multi/> </properties> @@ -735,6 +703,16 @@ #include <include/ospf-route-map.xml.i> </children> </node> + <node name="isis"> + <properties> + <help>Redistribute IS-IS routes</help> + </properties> + <children> + #include <include/ospf-metric.xml.i> + #include <include/ospf-metric-type.xml.i> + #include <include/ospf-route-map.xml.i> + </children> + </node> <node name="kernel"> <properties> <help>Redistribute kernel routes</help> diff --git a/interface-definitions/protocols-ospfv3.xml.in b/interface-definitions/protocols-ospfv3.xml.in index 7f80f9f9d..2559e2b03 100644 --- a/interface-definitions/protocols-ospfv3.xml.in +++ b/interface-definitions/protocols-ospfv3.xml.in @@ -52,7 +52,7 @@ <description>Interface used for routing information exchange</description> </valueHelp> <constraint> - <regex>^(br|bond|dum|en|eth|gnv|peth|tun|vti|vxlan|wg|wlan)[0-9]+|lo$</regex> + <validator name="interface-name"/> </constraint> <multi/> </properties> @@ -147,6 +147,76 @@ </node> </children> </node> + <tagNode name="interface"> + <properties> + <help>Enable routing on an IPv6 interface</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py</script> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Interface used for routing information exchange</description> + </valueHelp> + <constraint> + <validator name="interface-name"/> + </constraint> + </properties> + <children> + #include <include/ospf-intervals.xml.i> + #include <include/ospf-interface-common.xml.i> + <leafNode name="ifmtu"> + <properties> + <help>Interface MTU</help> + <valueHelp> + <format>u32:1-65535</format> + <description>Interface MTU</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-65535"/> + </constraint> + </properties> + </leafNode> + <leafNode name="instance-id"> + <properties> + <help>Instance Id (default: 0)</help> + <valueHelp> + <format>u32:0-255</format> + <description>Instance Id</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-255"/> + </constraint> + </properties> + <defaultValue>0</defaultValue> + </leafNode> + <leafNode name="network"> + <properties> + <help>Network type</help> + <completionHelp> + <list>broadcast point-to-point</list> + </completionHelp> + <valueHelp> + <format>broadcast</format> + <description>Broadcast network type</description> + </valueHelp> + <valueHelp> + <format>point-to-point</format> + <description>Point-to-point network type</description> + </valueHelp> + <constraint> + <regex>^(broadcast|point-to-point)$</regex> + </constraint> + <constraintErrorMessage>Must be broadcast or point-to-point</constraintErrorMessage> + </properties> + </leafNode> + <leafNode name="passive"> + <properties> + <help>Disable forming of adjacency</help> + <valueless/> + </properties> + </leafNode> + </children> + </tagNode> <node name="parameters"> <properties> <help>OSPFv3 specific parameters</help> diff --git a/interface-definitions/protocols-rip.xml.in b/interface-definitions/protocols-rip.xml.in index 34d0a5a10..1ae3bd8f7 100644 --- a/interface-definitions/protocols-rip.xml.in +++ b/interface-definitions/protocols-rip.xml.in @@ -1,4 +1,4 @@ -<!-- Routing Information Protocol (RIP) configuration --> +<?xml version="1.0"?> <interfaceDefinition> <node name="protocols"> <children> @@ -19,73 +19,14 @@ </constraint> </properties> </leafNode> - <node name="default-information"> - <properties> - <help>Control distribution of default route</help> - </properties> - <children> - <leafNode name="originate"> - <properties> - <help>Distribute a default route</help> - <valueless/> - </properties> - </leafNode> - </children> - </node> - <leafNode name="default-metric"> - <properties> - <help>Metric of redistributed routes</help> - <valueHelp> - <format>u32:1-16</format> - <description>Redistributed routes metric</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-16"/> - </constraint> - </properties> - </leafNode> + #include <include/rip-default-information.xml.i> + #include <include/rip-default-metric.xml.i> <node name="distribute-list"> <properties> <help>Filter networks in routing updates</help> </properties> <children> - <node name="access-list"> - <properties> - <help>Access-list</help> - </properties> - <children> - <leafNode name="in"> - <properties> - <help>Access list to apply to input packets</help> - <valueHelp> - <format>u32</format> - <description>Access list to apply to input packets</description> - </valueHelp> - <completionHelp> - <path>policy access-list</path> - </completionHelp> - <constraint> - <validator name="numeric" argument="--range 0-4294967295"/> - </constraint> - </properties> - </leafNode> - <leafNode name="out"> - <properties> - <help>Access list to apply to output packets</help> - <valueHelp> - <format>u32</format> - <description>Access list to apply to output packets</description> - </valueHelp> - <completionHelp> - <path>policy access-list</path> - </completionHelp> - <constraint> - <validator name="numeric" argument="--range 0-4294967295"/> - </constraint> - </properties> - </leafNode> - </children> - </node> + #include <include/rip-access-list.xml.i> <tagNode name="interface"> <properties> <help>Apply filtering to an interface</help> @@ -96,124 +37,70 @@ <completionHelp> <script>${vyos_completion_dir}/list_interfaces.py</script> </completionHelp> + <constraint> + <validator name="interface-name"/> + </constraint> + </properties> + <children> + #include <include/rip-access-list.xml.i> + #include <include/rip-prefix-list.xml.i> + </children> + </tagNode> + #include <include/rip-prefix-list.xml.i> + </children> + </node> + #include <include/rip-interface.xml.i> + <tagNode name="interface"> + <children> + <node name="authentication"> + <properties> + <help>Authentication</help> </properties> <children> - <node name="access-list"> + <tagNode name="md5"> <properties> - <help>Access list</help> + <help>MD5 key id</help> + <valueHelp> + <format>u32:1-255</format> + <description>OSPF key id</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-255"/> + </constraint> </properties> <children> - <leafNode name="in"> + <leafNode name="password"> <properties> - <help>Access list to apply to input packets</help> + <help>Authentication password</help> <valueHelp> - <format>u32</format> - <description>Access list to apply to input packets</description> - </valueHelp> - <completionHelp> - <path>policy access-list</path> - </completionHelp> - <constraint> - <validator name="numeric" argument="--range 0-4294967295"/> - </constraint> - </properties> - </leafNode> - <leafNode name="out"> - <properties> - <help>Access list to apply to output packets</help> - <valueHelp> - <format>u32</format> - <description>Access list to apply to output packets</description> + <format>txt</format> + <description>MD5 Key (16 characters or less)</description> </valueHelp> - <completionHelp> - <path>policy access-list</path> - </completionHelp> <constraint> - <validator name="numeric" argument="--range 0-4294967295"/> + <regex>^[^[:space:]]{1,16}$</regex> </constraint> + <constraintErrorMessage>Password must be 16 characters or less</constraintErrorMessage> </properties> </leafNode> </children> - </node> - <node name="prefix-list"> - <properties> - <help>Prefix-list</help> - </properties> - <children> - <leafNode name="in"> - <properties> - <help>Prefix-list to apply to input packets</help> - <valueHelp> - <format>txt</format> - <description>Prefix-list to apply to input packets</description> - </valueHelp> - <completionHelp> - <path>policy prefix-list</path> - </completionHelp> - </properties> - </leafNode> - <leafNode name="out"> - <properties> - <help>Prefix-list to apply to output packets</help> - <valueHelp> - <format>txt</format> - <description>Prefix-list to apply to output packets</description> - </valueHelp> - <completionHelp> - <path>policy prefix-list</path> - </completionHelp> - </properties> - </leafNode> - </children> - </node> - </children> - </tagNode> - <node name="prefix-list"> - <properties> - <help>Prefix-list</help> - </properties> - <children> - <leafNode name="in"> - <properties> - <help>Prefix-list to apply to input packets</help> - <valueHelp> - <format>txt</format> - <description>Prefix-list to apply to input packets</description> - </valueHelp> - <completionHelp> - <path>policy prefix-list</path> - </completionHelp> - </properties> - </leafNode> - <leafNode name="out"> + </tagNode> + <leafNode name="plaintext-password"> <properties> - <help>Prefix-list to apply to output packets</help> + <help>Plain text password</help> <valueHelp> <format>txt</format> - <description>Prefix-list to apply to output packets</description> + <description>Plain text password (16 characters or less)</description> </valueHelp> - <completionHelp> - <path>policy prefix-list</path> - </completionHelp> + <constraint> + <regex>^[^[:space:]]{1,16}$</regex> + </constraint> + <constraintErrorMessage>Password must be 16 characters or less</constraintErrorMessage> </properties> </leafNode> </children> </node> </children> - </node> - <leafNode name="interface"> - <properties> - <help>Interface name</help> - <valueHelp> - <format>txt</format> - <description>Apply filtering to an interface</description> - </valueHelp> - <completionHelp> - <script>${vyos_completion_dir}/list_interfaces.py</script> - </completionHelp> - <multi/> - </properties> - </leafNode> + </tagNode> <leafNode name="neighbor"> <properties> <help>Neighbor router</help> @@ -264,38 +151,10 @@ </completionHelp> </properties> </leafNode> - <leafNode name="distance"> - <properties> - <help>Administrative distance for network</help> - <valueHelp> - <format>u32:1-255</format> - <description>Administrative distance</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-255"/> - </constraint> - </properties> - </leafNode> + #include <include/static-route-distance.xml.i> </children> </tagNode> - <leafNode name="passive-interface"> - <properties> - <help>Passive interface</help> - <valueHelp> - <format>txt</format> - <description>Suppress routing updates on interface</description> - </valueHelp> - <valueHelp> - <format>default</format> - <description>Suppress routing updates on all interfaces by default</description> - </valueHelp> - <completionHelp> - <list>default</list> - <script>${vyos_completion_dir}/list_interfaces.py</script> - </completionHelp> - <multi/> - </properties> - </leafNode> + #include <include/routing-passive-interface-xml.i> <node name="redistribute"> <properties> <help>Redistribute information from another routing protocol</help> @@ -317,6 +176,14 @@ #include <include/rip-redistribute.xml.i> </children> </node> + <node name="isis"> + <properties> + <help>Redistribute IS-IS routes</help> + </properties> + <children> + #include <include/rip-redistribute.xml.i> + </children> + </node> <node name="kernel"> <properties> <help>Redistribute kernel routes</help> @@ -356,49 +223,7 @@ <multi/> </properties> </leafNode> - <node name="timers"> - <properties> - <help>RIP timer values</help> - </properties> - <children> - <leafNode name="garbage-collection"> - <properties> - <help>Garbage collection timer</help> - <valueHelp> - <format>u32:5-2147483647</format> - <description>Garbage colletion time (default 120)</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 5-2147483647"/> - </constraint> - </properties> - </leafNode> - <leafNode name="timeout"> - <properties> - <help>Routing information timeout timer</help> - <valueHelp> - <format>u32:5-2147483647</format> - <description>Routing information timeout timer (default 180)</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 5-2147483647"/> - </constraint> - </properties> - </leafNode> - <leafNode name="update"> - <properties> - <help>Routing table update timer</help> - <valueHelp> - <format>u32:5-2147483647</format> - <description>Routing table update timer in seconds (default 30)</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 5-2147483647"/> - </constraint> - </properties> - </leafNode> - </children> - </node> + #include <include/rip-timers.xml.i> </children> </node> </children> diff --git a/interface-definitions/protocols-ripng.xml.in b/interface-definitions/protocols-ripng.xml.in new file mode 100644 index 000000000..e456c3f3b --- /dev/null +++ b/interface-definitions/protocols-ripng.xml.in @@ -0,0 +1,146 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="protocols"> + <children> + <node name="ripng" owner="${vyos_conf_scripts_dir}/protocols_ripng.py"> + <properties> + <help>Routing Information Protocol (RIPng) parameters</help> + </properties> + <children> + <leafNode name="aggregate-address"> + <properties> + <help>Aggregate RIPng route announcement</help> + <valueHelp> + <format>ipv6net</format> + <description>Aggregate RIPng route announcement</description> + </valueHelp> + <constraint> + <validator name="ipv6-prefix"/> + </constraint> + <multi/> + </properties> + </leafNode> + #include <include/rip-default-information.xml.i> + #include <include/rip-default-metric.xml.i> + <node name="distribute-list"> + <properties> + <help>Filter networks in routing updates</help> + </properties> + <children> + #include <include/rip-access-list6.xml.i> + <tagNode name="interface"> + <properties> + <help>Apply filtering to an interface</help> + <valueHelp> + <format>txt</format> + <description>Apply filtering to an interface</description> + </valueHelp> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py</script> + </completionHelp> + <constraint> + <validator name="interface-name"/> + </constraint> + </properties> + <children> + #include <include/rip-access-list6.xml.i> + #include <include/rip-prefix-list6.xml.i> + </children> + </tagNode> + #include <include/rip-prefix-list6.xml.i> + </children> + </node> + #include <include/rip-interface.xml.i> + <leafNode name="network"> + <properties> + <help>RIPng network</help> + <valueHelp> + <format>ipv6net</format> + <description>RIPng network</description> + </valueHelp> + <constraint> + <validator name="ipv6-prefix"/> + </constraint> + <multi/> + </properties> + </leafNode> + <leafNode name="passive-interface"> + <properties> + <help>Passive interface</help> + <valueHelp> + <format>txt</format> + <description>Suppress routing updates on interface</description> + </valueHelp> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py</script> + </completionHelp> + <multi/> + </properties> + </leafNode> + <node name="redistribute"> + <properties> + <help>Redistribute information from another routing protocol</help> + </properties> + <children> + <node name="bgp"> + <properties> + <help>Redistribute BGP routes</help> + </properties> + <children> + #include <include/rip-redistribute.xml.i> + </children> + </node> + <node name="connected"> + <properties> + <help>Redistribute connected routes</help> + </properties> + <children> + #include <include/rip-redistribute.xml.i> + </children> + </node> + <node name="kernel"> + <properties> + <help>Redistribute kernel routes</help> + </properties> + <children> + #include <include/rip-redistribute.xml.i> + </children> + </node> + <node name="ospfv3"> + <properties> + <help>Redistribute OSPFv3 routes</help> + </properties> + <children> + #include <include/rip-redistribute.xml.i> + </children> + </node> + <node name="static"> + <properties> + <help>Redistribute static routes</help> + </properties> + <children> + #include <include/rip-redistribute.xml.i> + </children> + </node> + </children> + </node> + <leafNode name="route"> + <properties> + <help>RIPng static route</help> + <valueHelp> + <format>ipv6net</format> + <description>RIPng static route</description> + </valueHelp> + <constraint> + <validator name="ipv6-prefix"/> + </constraint> + <multi/> + </properties> + </leafNode> + #include <include/ospf-route-map.xml.i> + #include <include/rip-timers.xml.i> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/interface-definitions/protocols-rpki.xml.in b/interface-definitions/protocols-rpki.xml.in index b8db49e36..94fab54a5 100644 --- a/interface-definitions/protocols-rpki.xml.in +++ b/interface-definitions/protocols-rpki.xml.in @@ -1,32 +1,44 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Protocol RPKI configuration --> <interfaceDefinition> <node name="protocols"> <children> - <node name="nrpki" owner="${vyos_conf_scripts_dir}/protocols_rpki.py"> + <node name="rpki" owner="${vyos_conf_scripts_dir}/protocols_rpki.py"> <properties> <help>BGP prefix origin validation</help> </properties> <children> <tagNode name="cache"> <properties> - <help>RPKI cache server instance</help> + <help>RPKI cache server address</help> + <valueHelp> + <format>ipv4</format> + <description>IP address of NTP server</description> + </valueHelp> + <valueHelp> + <format>ipv6</format> + <description>IPv6 address of NTP server</description> + </valueHelp> + <valueHelp> + <format>hostname</format> + <description>Fully qualified domain name of NTP server</description> + </valueHelp> + <constraint> + <validator name="ipv4-address"/> + <validator name="ipv6-address"/> + <validator name="fqdn"/> + </constraint> </properties> <children> - <leafNode name="address"> + #include <include/port-number.xml.i> + <leafNode name="preference"> <properties> - <help>RPKI cache server address</help> - </properties> - </leafNode> - <leafNode name="port"> - <properties> - <help>TCP port number</help> + <help>Preference of the cache server</help> <valueHelp> - <format>u32:1-65535</format> - <description>TCP port number</description> + <format>u32:1-255</format> + <description>Polling period</description> </valueHelp> <constraint> - <validator name="numeric" argument="--range 1-65535"/> + <validator name="numeric" argument="--range 1-255"/> </constraint> </properties> </leafNode> @@ -68,55 +80,20 @@ </node> </children> </tagNode> - <leafNode name="initial-synchronization-timeout"> - <properties> - <help>Initial RPKI cache synchronization timeout</help> - <valueHelp> - <format>u32:0-4294967295</format> - <description>Initial RPKI cache synchronization timeout</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-4294967295"/> - </constraint> - </properties> - </leafNode> <leafNode name="polling-period"> <properties> - <help>RPKI cache polling period</help> - <valueHelp> - <format>u32:1-1300</format> - <description>Polling period</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-1300"/> - </constraint> - </properties> - </leafNode> - <leafNode name="preference"> - <properties> - <help>RPKI cache preference</help> - <valueHelp> - <format>u32:0-4294967295</format> - <description>RPKI cache preference</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-4294967295"/> - </constraint> - </properties> - </leafNode> - <leafNode name="timeout"> - <properties> - <help>RPKI cache reply timeout</help> + <help>RPKI cache polling period (default: 300)</help> <valueHelp> - <format>u32:0-4294967295</format> - <description>RPKI cache reply timeout</description> + <format>u32:1-86400</format> + <description>Polling period in seconds</description> </valueHelp> <constraint> - <validator name="numeric" argument="--range 0-4294967295"/> + <validator name="numeric" argument="--range 1-86400"/> </constraint> </properties> + <defaultValue>300</defaultValue> </leafNode> - </children> + </children> </node> </children> </node> diff --git a/interface-definitions/arp.xml.in b/interface-definitions/protocols-static-arp.xml.in index 082afe00f..e5e8a9ad9 100644 --- a/interface-definitions/arp.xml.in +++ b/interface-definitions/protocols-static-arp.xml.in @@ -18,7 +18,7 @@ <children> <leafNode name="hwaddr"> <properties> - <help>mac address to translate to</help> + <help>Translation MAC address</help> <valueHelp> <format>macaddr</format> <description>Hardware (MAC) address</description> diff --git a/interface-definitions/protocols-static.xml.in b/interface-definitions/protocols-static.xml.in new file mode 100644 index 000000000..59a7927a5 --- /dev/null +++ b/interface-definitions/protocols-static.xml.in @@ -0,0 +1,33 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="protocols"> + <children> + <node name="static" owner="${vyos_conf_scripts_dir}/protocols_static.py"> + <properties> + <help>Static route parameters</help> + </properties> + <children> + #include <include/static-route-map.xml.i> + #include <include/static-route.xml.i> + #include <include/static-route6.xml.i> + <tagNode name="table"> + <properties> + <help>Policy route table number</help> + <valueHelp> + <format>u32:1-200</format> + <description>Policy route table number</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-200"/> + </constraint> + </properties> + <children> + #include <include/static-route.xml.i> + #include <include/static-route6.xml.i> + </children> + </tagNode> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/interface-definitions/protocols-vrf.xml.in b/interface-definitions/protocols-vrf.xml.in new file mode 100644 index 000000000..77297938b --- /dev/null +++ b/interface-definitions/protocols-vrf.xml.in @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<interfaceDefinition> + <node name="protocols"> + <children> + <tagNode name="vrf" owner="${vyos_conf_scripts_dir}/protocols_vrf.py"> + <properties> + <help>Name of VRF to add route for</help> + <completionHelp> + <path>vrf name</path> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>VRF instance name</description> + </valueHelp> + <constraint> + <validator name="vrf-name"/> + </constraint> + <constraintErrorMessage>VRF instance name must be 15 characters or less and can not\nbe named as regular network interfaces.\n</constraintErrorMessage> + </properties> + <children> + <node name="static"> + <properties> + <help>Static route parameters</help> + </properties> + <children> + #include <include/static-route.xml.i> + #include <include/static-route6.xml.i> + </children> + </node> + #include <include/vni.xml.i> + </children> + </tagNode> + </children> + </node> +</interfaceDefinition> diff --git a/interface-definitions/vpn_l2tp.xml.in b/interface-definitions/vpn_l2tp.xml.in index 998a8c371..3a6c8a992 100644 --- a/interface-definitions/vpn_l2tp.xml.in +++ b/interface-definitions/vpn_l2tp.xml.in @@ -217,7 +217,7 @@ <children> <tagNode name="server"> <children> - #include <include/accel-radius-additions-disable-accounting.xlm.in> + #include <include/accel-radius-additions-disable-accounting.xml.i> <leafNode name="fail-time"> <properties> <help>Mark server unavailable for <n> seconds on failure</help> diff --git a/interface-definitions/vrf.xml.in b/interface-definitions/vrf.xml.in index 81c89d94b..eca9e75a7 100644 --- a/interface-definitions/vrf.xml.in +++ b/interface-definitions/vrf.xml.in @@ -21,7 +21,7 @@ </constraint> <constraintErrorMessage>VRF instance name must be 15 characters or less and can not\nbe named as regular network interfaces.\n</constraintErrorMessage> <valueHelp> - <format>name</format> + <format>txt</format> <description>Instance name</description> </valueHelp> </properties> diff --git a/interface-definitions/vrrp.xml.in b/interface-definitions/vrrp.xml.in index caa9f4a33..3c4c9b83c 100644 --- a/interface-definitions/vrrp.xml.in +++ b/interface-definitions/vrrp.xml.in @@ -212,6 +212,15 @@ </constraint> </properties> </leafNode> + <leafNode name="mode-force"> + <properties> + <valueless/> + <help>Disable VRRP state checking (deprecated, will be removed in VyOS 1.4)</help> + <constraint> + <validator name="script"/> + </constraint> + </properties> + </leafNode> </children> </node> <leafNode name="virtual-address"> diff --git a/op-mode-definitions/generate-ssh-server-key.xml.in b/op-mode-definitions/generate-ssh-server-key.xml.in index a6ebf1b78..86bb1b1bd 100644 --- a/op-mode-definitions/generate-ssh-server-key.xml.in +++ b/op-mode-definitions/generate-ssh-server-key.xml.in @@ -2,14 +2,30 @@ <interfaceDefinition> <node name="generate"> <properties> - <help>Generate an object</help> + <help>Generate an object/key</help> </properties> <children> - <node name="ssh-server-key"> + <node name="ssh"> <properties> - <help>Regenerate the host SSH keys and restart the SSH server</help> + <help>Generate SSH related keypairs</help> </properties> - <command>${vyos_op_scripts_dir}/generate_ssh_server_key.py</command> + <children> + <node name="server-key"> + <properties> + <help>Re-generate SSH host keys and restart SSH server</help> + </properties> + <command>${vyos_op_scripts_dir}/generate_ssh_server_key.py</command> + </node> + <tagNode name="client-key"> + <properties> + <help>Re-generate SSH client keypair</help> + <completionHelp> + <list><filename></list> + </completionHelp> + </properties> + <command>ssh-keygen -t rsa -f "$4" -N ""</command> + </tagNode> + </children> </node> </children> </node> diff --git a/op-mode-definitions/include/bgp-afi-common.xml.i b/op-mode-definitions/include/bgp-afi-common.xml.i new file mode 100644 index 000000000..06cfc42a5 --- /dev/null +++ b/op-mode-definitions/include/bgp-afi-common.xml.i @@ -0,0 +1,40 @@ +<!-- included start from bgp-afi-common.xml.i --> +<tagNode name="community"> + <properties> + <help>Community number where AA and NN are (0-65535)</help> + <completionHelp> + <list>AA:NN</list> + </completionHelp> + </properties> + <children> + <leafNode name="exact-match"> + <properties> + <help>Exact match of the communities</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + </children> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</tagNode> +<tagNode name="large-community"> + <properties> + <help>List of large-community numbers</help> + <completionHelp> + <list>AA:BB:CC</list> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</tagNode> +<leafNode name="statistics"> + <properties> + <help>RIB advertisement statistics</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<leafNode name="summary"> + <properties> + <help>Summary of BGP neighbor status</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp-afi-ipv4-ipv6-common.xml.i b/op-mode-definitions/include/bgp-afi-ipv4-ipv6-common.xml.i new file mode 100644 index 000000000..dc0926375 --- /dev/null +++ b/op-mode-definitions/include/bgp-afi-ipv4-ipv6-common.xml.i @@ -0,0 +1,243 @@ +<!-- included start from bgp-afi-ipv4-ipv6-common.xml.i --> +<node name="community"> + <properties> + <help>Display routes matching the community</help> + </properties> + <children> + <leafNode name="accept-own"> + <properties> + <help>Should accept local VPN route if exported and imported into different VRF (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="accept-own-nexthop"> + <properties> + <help>Should accept VPN route with local nexthop (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="blackhole"> + <properties> + <help>Inform EBGP peers to blackhole traffic to prefix (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="exact-match"> + <properties> + <help>Exact match of the communities</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="graceful-shutdown"> + <properties> + <help>Graceful shutdown (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="llgr-stale"> + <properties> + <help>Staled Long-lived Graceful Restart VPN route (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="local-AS"> + <properties> + <help>Do not send outside local AS (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="no-advertise"> + <properties> + <help>Do not advertise to any peer (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="no-export"> + <properties> + <help>Do not export to next AS (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="no-llgr"> + <properties> + <help>Removed because Long-lived Graceful Restart was not enabled for VPN route (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="no-peer"> + <properties> + <help>Do not export to any peer (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="route-filter-translated-v4"> + <properties> + <help>RT translated VPNv4 route filtering (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="route-filter-translated-v6"> + <properties> + <help>RT translated VPNv6 route filtering (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="route-filter-v4"> + <properties> + <help>RT VPNv4 route filtering (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="route-filter-v6"> + <properties> + <help>RT VPNv6 route filtering (well-known community)</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + </children> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</node> +<tagNode name="community-list"> + <properties> + <help>Display routes matching the community-list</help> + <completionHelp> + <list>1-500 name</list> + </completionHelp> + </properties> + <children> + <leafNode name="exact-match"> + <properties> + <help>Show BGP routes exactly matching specified community list</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + </children> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</tagNode> +<node name="dampening"> + <properties> + <help>Display detailed information about dampening</help> + </properties> + <children> + <leafNode name="dampened-paths"> + <properties> + <help>Display paths suppressed due to dampening</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="flap-statistics"> + <properties> + <help>Display flap statistics of routes</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="parameters"> + <properties> + <help>Display detail of configured dampening parameters</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + </children> +</node> +<tagNode name="filter-list"> + <properties> + <help>Display routes conforming to the filter-list</help> + <completionHelp> + <script>vtysh -c 'show bgp as-path-access-list' | grep 'AS path access list' | awk '{print $NF}'</script> + </completionHelp> + </properties> +</tagNode> +<node name="large-community"> + <properties> + <help>Show BGP routes matching the specified large-communities</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</node> +<leafNode name="neighbors"> + <properties> + <help>Detailed information on TCP and BGP neighbor connections</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<tagNode name="neighbors"> + <properties> + <help>Show detailed BGP IPv4 unicast neighbor information</help> + <completionHelp> + <script>vtysh -c 'show bgp summary' | awk '{print $1'} | grep -e '^[0-9a-f]'</script> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + <leafNode name="advertised-routes"> + <properties> + <help>Show routes advertised to a BGP neighbor</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="dampened-routes"> + <properties> + <help>Show dampened routes received from BGP neighbor</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="flap-statistics"> + <properties> + <help>Show flap statistics of the routes learned from BGP neighbor</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="prefix-counts"> + <properties> + <help>Show detailed prefix count information for BGP neighbor</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <node name="received"> + <properties> + <help>Show information received from BGP neighbor</help> + </properties> + <children> + <leafNode name="prefix-filter"> + <properties> + <help>Show prefixlist filter</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + </children> + </node> + <leafNode name="received-routes"> + <properties> + <help>Show received routes from BGP neighbor</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="routes"> + <properties> + <help>Show routes learned from BGP neighbor</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + </children> +</tagNode> +<tagNode name="prefix-list"> + <properties> + <help>Display routes conforming to the prefix-list</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</tagNode> +<tagNode name="regexp"> + <properties> + <help>Display routes matching the AS path regular expression</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</tagNode> +<tagNode name="route-map"> + <properties> + <help>Show BGP routes matching the specified route map</help> + <completionHelp> + <path>policy route-map</path> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</tagNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp-prefix-bestpath-multipath.xml.i b/op-mode-definitions/include/bgp-prefix-bestpath-multipath.xml.i new file mode 100644 index 000000000..224fa6b45 --- /dev/null +++ b/op-mode-definitions/include/bgp-prefix-bestpath-multipath.xml.i @@ -0,0 +1,20 @@ +<!-- included start from bgp-prefix-bestpath-multipath.xml.i --> +<leafNode name="bestpath"> + <properties> + <help>Display only the bestpath</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<leafNode name="multipath"> + <properties> + <help>Display only multipaths</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<leafNode name="longer-prefixes"> + <properties> + <help>Display route and more specific routes</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/vtysh-generic-detail.xml.i b/op-mode-definitions/include/vtysh-generic-detail.xml.i new file mode 100644 index 000000000..5a3097a77 --- /dev/null +++ b/op-mode-definitions/include/vtysh-generic-detail.xml.i @@ -0,0 +1,8 @@ +<!-- included start from vtysh-generic-detail.xml.i -->
+<leafNode name="detail">
+ <properties>
+ <help>Detailed information</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+</leafNode>
+<!-- included end -->
diff --git a/op-mode-definitions/ipv6-route.xml.in b/op-mode-definitions/ipv6-route.xml.in index 28f5b1aad..7f188fdb2 100644 --- a/op-mode-definitions/ipv6-route.xml.in +++ b/op-mode-definitions/ipv6-route.xml.in @@ -21,7 +21,7 @@ <properties> <help>Show IPv6 Neighbor Discovery (ND) information</help> </properties> - <command>ip -f inet6 neigh list</command> + <command>${vyos_op_scripts_dir}/show_neigh.py --family inet6</command> </leafNode> </children> diff --git a/op-mode-definitions/reset-ip-igmp.xml.in b/op-mode-definitions/reset-ip-igmp.xml.in index 143553d33..e79c33da8 100644 --- a/op-mode-definitions/reset-ip-igmp.xml.in +++ b/op-mode-definitions/reset-ip-igmp.xml.in @@ -13,7 +13,7 @@ <properties> <help>Reset IGMP interfaces</help> </properties> - <command>/usr/bin/vtysh -c "clear ip igmp interfaces"</command> + <command>vtysh -c "clear ip igmp interfaces"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/reset-ip-multicast.xml.in b/op-mode-definitions/reset-ip-multicast.xml.in index d610add16..6cca07850 100644 --- a/op-mode-definitions/reset-ip-multicast.xml.in +++ b/op-mode-definitions/reset-ip-multicast.xml.in @@ -13,7 +13,7 @@ <properties> <help>Clear multicast routing table</help> </properties> - <command>/usr/bin/vtysh -c "clear ip mroute"</command> + <command>vtysh -c "clear ip mroute"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/reset-mpls.xml.in b/op-mode-definitions/reset-mpls.xml.in index 4e5d37d5b..829ed41ab 100644 --- a/op-mode-definitions/reset-mpls.xml.in +++ b/op-mode-definitions/reset-mpls.xml.in @@ -17,10 +17,10 @@ <help>Reset MPLS LDP neighbor/session</help> <completionHelp> <list><x.x.x.x> <h:h:h:h:h:h:h:h></list> - <script>/usr/bin/vtysh -c "show mpls ldp neighbor" | awk '{print $2}' | egrep -v "ID"</script> + <script>vtysh -c "show mpls ldp neighbor" | awk '{print $2}' | egrep -v "ID"</script> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "clear mpls ldp neighbor $5"</command> + <command>vtysh -c "clear mpls ldp neighbor $5"</command> </tagNode> </children> </node> diff --git a/op-mode-definitions/show-bgp.xml.in b/op-mode-definitions/show-bgp.xml.in new file mode 100644 index 000000000..cd0c5a9e5 --- /dev/null +++ b/op-mode-definitions/show-bgp.xml.in @@ -0,0 +1,262 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="show"> + <children> + <node name="bgp"> + <properties> + <help>BGP information</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + #include <include/bgp-afi-ipv4-ipv6-common.xml.i> + <tagNode name="ipv4"> + <properties> + <help>Network in the BGP routing table to display</help> + <completionHelp> + <list><x.x.x.x> <x.x.x.x/x> <h:h:h:h:h:h:h:h> <h:h:h:h:h:h:h:h/x></list> + </completionHelp> + </properties> + <children> + #include <include/bgp-prefix-bestpath-multipath.xml.i> + </children> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </tagNode> + <node name="ipv4"> + <properties> + <help>IPv4 Address Family</help> + </properties> + <children> + #include <include/bgp-afi-common.xml.i> + #include <include/bgp-afi-ipv4-ipv6-common.xml.i> + </children> + </node> + <tagNode name="ipv6"> + <properties> + <help>Network in the BGP routing table to display</help> + <completionHelp> + <list><x.x.x.x> <x.x.x.x/x> <h:h:h:h:h:h:h:h> <h:h:h:h:h:h:h:h/x></list> + </completionHelp> + </properties> + <children> + #include <include/bgp-prefix-bestpath-multipath.xml.i> + </children> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </tagNode> + <node name="ipv6"> + <properties> + <help>IPv6 Address Family</help> + </properties> + <children> + #include <include/bgp-afi-common.xml.i> + #include <include/bgp-afi-ipv4-ipv6-common.xml.i> + </children> + </node> + <node name="l2vpn"> + <properties> + <help>Layer 2 Virtual Private Network</help> + </properties> + <children> + <tagNode name="evpn"> + <properties> + <help>Network in the BGP routing table to display</help> + <completionHelp> + <list><x.x.x.x> <x.x.x.x/x> <h:h:h:h:h:h:h:h> <h:h:h:h:h:h:h:h/x></list> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </tagNode> + <node name="evpn"> + <properties> + <help>Ethernet Virtual Private Network</help> + </properties> + <children> + #include <include/bgp-afi-common.xml.i> + <node name="all"> + <properties> + <help>Display information about all EVPN NLRIs</help> + </properties> + <children> + <leafNode name="overlay"> + <properties> + <help>Display BGP Overlay Information for prefixes</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="tags"> + <properties> + <help>Display BGP tags for prefixes</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + </children> + </node> + <node name="es"> + <properties> + <help>Ethernet Segment</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + #include <include/vtysh-generic-detail.xml.i> + </children> + </node> + <node name="es-evi"> + <properties> + <help>Ethernet Segment per EVI</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + #include <include/vtysh-generic-detail.xml.i> + <tagNode name="vni"> + <properties> + <help>VxLAN Network Identifier</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </tagNode> + </children> + </node> + <leafNode name="import-rt"> + <properties> + <help>Show import route target</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <tagNode name="neighbors"> + <properties> + <help>Show detailed BGP neighbor information</help> + <completionHelp> + <script>vtysh -c 'show bgp summary' | awk '{print $1'} | grep -e '^[0-9a-f]'</script> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + <leafNode name="advertised-routes"> + <properties> + <help>Show routes advertised to a BGP neighbor</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="routes"> + <properties> + <help>Show routes learned from BGP neighbor</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + </children> + </tagNode> + <tagNode name="rd"> + <properties> + <help>Show detailed BGP neighbor information</help> + <completionHelp> + <list>ASN:NN IPADDRESS:NN</list> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + <leafNode name="overlay"> + <properties> + <help>Display BGP Overlay Information for prefixes</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="tags"> + <properties> + <help>Display BGP tags for prefixes</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + </children> + </tagNode> + <node name="route"> + <properties> + <help>EVPN route information</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + #include <include/vtysh-generic-detail.xml.i> + <node name="type"> + <properties> + <help>Specify Route type</help> + </properties> + <children> + <leafNode name="1"> + <properties> + <help>EAD (Type-1) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="2"> + <properties> + <help>MAC-IP (Type-2) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="3"> + <properties> + <help>Multicast (Type-3) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="4"> + <properties> + <help>Ethernet Segment (Type-4) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="5"> + <properties> + <help>Prefix (Type-5) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="ead"> + <properties> + <help>EAD (Type-1) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="es"> + <properties> + <help>Ethernet Segment (Type-4) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="macip"> + <properties> + <help>MAC-IP (Type-2) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="multicast"> + <properties> + <help>Multicast (Type-3) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + <leafNode name="prefix"> + <properties> + <help>Prefix (Type-5) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + </children> + </node> + <tagNode name="vni"> + <properties> + <help>VXLAN Network Identifier</help> + <completionHelp> + <list>1-16777215 all</list> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </tagNode> + </children> + </node> + </children> + </node> + </children> + </node> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/op-mode-definitions/show-ip-access-paths-prefix-community-lists.xml.in b/op-mode-definitions/show-ip-access-paths-prefix-community-lists.xml.in index a5ec65c94..d7222516a 100644 --- a/op-mode-definitions/show-ip-access-paths-prefix-community-lists.xml.in +++ b/op-mode-definitions/show-ip-access-paths-prefix-community-lists.xml.in @@ -11,7 +11,7 @@ <properties> <help>Show all IP access-lists</help> </properties> - <command>/usr/bin/vtysh -c "show ip access-list"</command> + <command>vtysh -c "show ip access-list"</command> </leafNode> <tagNode name="access-list"> <properties> @@ -20,13 +20,13 @@ <path>policy access-list</path> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip access-list $4"</command> + <command>vtysh -c "show ip access-list $4"</command> </tagNode> <leafNode name="as-path-access-list"> <properties> <help>Show all as-path-access-lists</help> </properties> - <command>/usr/bin/vtysh -c "show ip as-path-access-list"</command> + <command>vtysh -c "show ip as-path-access-list"</command> </leafNode> <tagNode name="as-path-access-list"> <properties> @@ -35,13 +35,13 @@ <path>policy as-path-list</path> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip as-path-access-list $4"</command> + <command>vtysh -c "show ip as-path-access-list $4"</command> </tagNode> <leafNode name="community-list"> <properties> <help>Show IP community-lists</help> </properties> - <command>/usr/bin/vtysh -c "show bgp community-list"</command> + <command>vtysh -c "show bgp community-list"</command> </leafNode> <tagNode name="community-list"> <properties> @@ -50,13 +50,13 @@ <path>policy community-list</path> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show bgp community-list $4 detail"</command> + <command>vtysh -c "show bgp community-list $4 detail"</command> </tagNode> <leafNode name="extcommunity-list"> <properties> <help>Show extended IP community-lists</help> </properties> - <command>/usr/bin/vtysh -c "show bgp extcommunity-list"</command> + <command>vtysh -c "show bgp extcommunity-list"</command> </leafNode> <tagNode name="extcommunity-list"> <properties> @@ -65,19 +65,19 @@ <path>policy extcommunity-list</path> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show bgp extcommunity-list $4 detail"</command> + <command>vtysh -c "show bgp extcommunity-list $4 detail"</command> </tagNode> <leafNode name="forwarding"> <properties> <help>Show IP forwarding status</help> </properties> - <command>/usr/bin/vtysh -c "show ip forwarding"</command> + <command>vtysh -c "show ip forwarding"</command> </leafNode> <leafNode name="large-community-list"> <properties> <help>Show IP large-community-lists</help> </properties> - <command>/usr/bin/vtysh -c "show bgp large-community-list"</command> + <command>vtysh -c "show bgp large-community-list"</command> </leafNode> <tagNode name="large-community-list"> <properties> @@ -86,13 +86,13 @@ <path>policy large-community-list</path> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show bgp large-community-list $4 detail"</command> + <command>vtysh -c "show bgp large-community-list $4 detail"</command> </tagNode> <leafNode name="prefix-list"> <properties> <help>Show all IP prefix-lists</help> </properties> - <command>/usr/bin/vtysh -c "show ip prefix-list"</command> + <command>vtysh -c "show ip prefix-list"</command> </leafNode> <tagNode name="prefix-list"> <properties> @@ -101,13 +101,13 @@ <path>policy prefix-list</path> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip prefix-list $4"</command> + <command>vtysh -c "show ip prefix-list $4"</command> </tagNode> <leafNode name="protocol"> <properties> <help>Show IP route-maps per protocol</help> </properties> - <command>/usr/bin/vtysh -c "show ip protocol"</command> + <command>vtysh -c "show ip protocol"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/show-ip-bgp.xml.in b/op-mode-definitions/show-ip-bgp.xml.in index a92a78266..690de0a1d 100644 --- a/op-mode-definitions/show-ip-bgp.xml.in +++ b/op-mode-definitions/show-ip-bgp.xml.in @@ -8,73 +8,35 @@ <properties> <help>Show Border Gateway Protocol (BGP) information</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp"</command> + <command>vtysh -c "show ip bgp"</command> <children> <leafNode name="attribute-info"> <properties> <help>Show BGP attribute information</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp attribute-info"</command> + <command>vtysh -c "show ip bgp attribute-info"</command> </leafNode> <leafNode name="cidr-only"> <properties> <help>Display only routes with non-natural netmasks</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp cidr-only"</command> + <command>vtysh -c "show ip bgp cidr-only"</command> </leafNode> - <node name="community"> - <properties> - <help>Show BGP routes matching the communities</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp community"</command> - </node> - <tagNode name="community"> - <properties> - <help>Display routes matching the specified communities</help> - <completionHelp> - <list><AA:NN> local-AS no-advertise no-export</list> - </completionHelp> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp community $5"</command> - </tagNode> <leafNode name="community-info"> <properties> <help>List all bgp community information</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp community-info"</command> - </leafNode> - <tagNode name="community-list"> - <properties> - <help>Show BGP routes matching specified community list</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp community-list $5"</command> - <children> - <leafNode name="exact-match"> - <properties> - <help>Show BGP routes exactly matching specified community list</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp community-list $5 exact-match"</command> - </leafNode> - </children> - </tagNode> - <leafNode name="dampened-paths"> - <properties> - <help>Show dampened BGP paths</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp dampening dampened-paths"</command> + <command>vtysh -c "show ip bgp community-info"</command> </leafNode> - <tagNode name="filter-list"> + #include <include/bgp-afi-common.xml.i> + #include <include/bgp-afi-ipv4-ipv6-common.xml.i> + <tagNode name="prefix-list"> <properties> - <help>Show BGP information for specified word</help> + <completionHelp> + <path>policy prefix-list</path> + </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip bgp filter-list $5"</command> </tagNode> - <leafNode name="flap-statistics"> - <properties> - <help>Show flap statistics of routes</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp dampening flap-statistics"</command> - </leafNode> <node name="ipv4"> <properties> <help>Show BGP IPv4 information</help> @@ -89,13 +51,13 @@ <properties> <help>Display only routes with non-natural netmasks</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast cidr-only"</command> + <command>vtysh -c "show ip bgp ipv4 unicast cidr-only"</command> </leafNode> <node name="community"> <!-- START new code --> <properties> <help>Show BGP routes matching the communities</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast community"</command> + <command>vtysh -c "show ip bgp ipv4 unicast community"</command> </node> <tagNode name="community"> <properties> @@ -104,28 +66,22 @@ <list><AA:NN> local-AS no-advertise no-export</list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast community $7"</command> + <command>vtysh -c "show ip bgp ipv4 unicast community $7"</command> </tagNode> <tagNode name="community-list"> <properties> <help>Show BGP routes matching specified community list</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast community-list $7"</command> + <command>vtysh -c "show ip bgp ipv4 unicast community-list $7"</command> <children> <leafNode name="exact-match"> <properties> <help>Show BGP routes exactly matching specified community list</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast community-list $7 exact-match"</command> + <command>vtysh -c "show ip bgp ipv4 unicast community-list $7 exact-match"</command> </leafNode> </children> </tagNode> - <tagNode name="filter-list"> - <properties> - <help>Show BGP information for specified word</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp filter-list $5"</command> - </tagNode> <tagNode name="neighbors"> <properties> <help>Show detailed BGP IPv4 unicast neighbor information</help> @@ -133,31 +89,31 @@ <script>vtysh -c "show ip bgp ipv4 unicast summary" | awk '{print $1}' | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b"</script> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast neighbors $7"</command> + <command>vtysh -c "show ip bgp ipv4 unicast neighbors $7"</command> <children> <leafNode name="advertised-routes"> <properties> <help>Show routes advertised to a BGP neighbor</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast neighbor $7 advertised-routes"</command> + <command>vtysh -c "show ip bgp ipv4 unicast neighbor $7 advertised-routes"</command> </leafNode> <leafNode name="prefix-counts"> <properties> <help>Show detailed prefix count information</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast neighbor $7 prefix-counts"</command> + <command>vtysh -c "show ip bgp ipv4 unicast neighbor $7 prefix-counts"</command> </leafNode> <leafNode name="received-routes"> <properties> <help>Show the received routes from neighbor</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast neighbor $7 received-routes"</command> + <command>vtysh -c "show ip bgp ipv4 unicast neighbor $7 received-routes"</command> </leafNode> <leafNode name="routes"> <properties> <help>Show routes learned from neighbor</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast neighbor $7 routes"</command> + <command>vtysh -c "show ip bgp ipv4 unicast neighbor $7 routes"</command> </leafNode> </children> </tagNode> @@ -165,31 +121,31 @@ <properties> <help>Show BGP path information</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast paths"</command> + <command>vtysh -c "show ip bgp ipv4 unicast paths"</command> </leafNode> <tagNode name="prefix-list"> <properties> <help>Show BGP routes matching the specified prefix list</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast prefix-list $7"</command> + <command>vtysh -c "show ip bgp ipv4 unicast prefix-list $7"</command> </tagNode> <tagNode name="regexp"> <properties> <help>Show BGP routes matching the specified AS path regular expression</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast regexp $5"</command> + <command>vtysh -c "show ip bgp ipv4 unicast regexp $5"</command> </tagNode> <tagNode name="route-map"> <properties> <help>Show BGP routes matching the specified route map</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp route-map $5"</command> + <command>vtysh -c "show ip bgp route-map $5"</command> </tagNode> <leafNode name="summary"> <properties> <help>Show summary of BGP information</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp summary"</command> + <command>vtysh -c "show ip bgp summary"</command> </leafNode> </children> </node> @@ -200,141 +156,30 @@ <list><x.x.x.x> <x.x.x.x/x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip bgp $6"</command> + <command>vtysh -c "show ip bgp $6"</command> </tagNode> </children> </node> - <node name="large-community"> - <properties> - <help>Show BGP routes matching the specified large-communities</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp large-community"</command> - </node> <leafNode name="large-community-info"> <properties> <help>Show BGP large-community information</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp large-community-info"</command> + <command>vtysh -c "show ip bgp large-community-info"</command> </leafNode> - <tagNode name="large-community-list"> - <properties> - <help>Show BGP routes matching the specified large-community list</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp large-community-list $5"</command> - </tagNode> <leafNode name="memory"> <properties> <help>Show BGP memory usage</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp memory"</command> + <command>vtysh -c "show ip bgp memory"</command> </leafNode> - <tagNode name="neighbors"> - <properties> - <help>Show detailed BGP IPv4 unicast neighbor information</help> - <completionHelp> - <script>vtysh -c "show ip bgp summary" | awk '{print $1}' | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b"</script> - </completionHelp> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp neighbors $5"</command> - <children> - <leafNode name="advertised-routes"> - <properties> - <help>Show routes advertised to a BGP neighbor</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 advertised-routes"</command> - </leafNode> - <leafNode name="dampened-routes"> - <properties> - <help>Show dampened routes received from BGP neighbor</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 dampened-routes"</command> - </leafNode> - <leafNode name="flap-statistics"> - <properties> - <help>Show flap statistics of the routes learned from BGP neighbor</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 flap-statistics"</command> - </leafNode> - <leafNode name="prefix-counts"> - <properties> - <help>Show detailed prefix count information for BGP neighbor</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 prefix-counts"</command> - </leafNode> - <node name="received"> - <properties> - <help>Show information received from BGP neighbor</help> - </properties> - <children> - <leafNode name="prefix-filter"> - <properties> - <help>Show prefixlist filter</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 received prefix-filter"</command> - </leafNode> - </children> - </node> - <leafNode name="received-routes"> - <properties> - <help>Show received routes from BGP neighbor</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 received-routes"</command> - </leafNode> - <leafNode name="routes"> - <properties> - <help>Show routes learned from BGP neighbor</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 routes"</command> - </leafNode> - </children> - </tagNode> <leafNode name="paths"> <properties> <help>Show BGP path information</help> </properties> - <command>/usr/bin/vtysh -c "show ip bgp paths"</command> - </leafNode> - <tagNode name="prefix-list"> - <properties> - <help>Show BGP routes matching the specified prefix list</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp prefix-list $5"</command> - </tagNode> - <tagNode name="regexp"> - <properties> - <help>Show BGP routes matching the specified AS path regular expression</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp regexp $5"</command> - </tagNode> - <tagNode name="route-map"> - <properties> - <help>Show BGP routes matching the specified route map</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp route-map $5"</command> - </tagNode> - <leafNode name="statistics"> - <properties> - <help>Show summary of BGP information</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp statistics"</command> - </leafNode> - <leafNode name="summary"> - <properties> - <help>Show summary of BGP information</help> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp summary"</command> + <command>vtysh -c "show ip bgp paths"</command> </leafNode> </children> </node> - <tagNode name="bgp"> - <properties> - <help>Show BGP information for specified IP address or prefix</help> - <completionHelp> - <list><x.x.x.x> <x.x.x.x/x></list> - </completionHelp> - </properties> - <command>/usr/bin/vtysh -c "show ip bgp $4"</command> - </tagNode> </children> </node> </children> diff --git a/op-mode-definitions/show-ip-igmp.xml.in b/op-mode-definitions/show-ip-igmp.xml.in index b8f2f9107..855c5d508 100644 --- a/op-mode-definitions/show-ip-igmp.xml.in +++ b/op-mode-definitions/show-ip-igmp.xml.in @@ -13,31 +13,31 @@ <properties> <help>IGMP groups information</help> </properties> - <command>/usr/bin/vtysh -c "show ip igmp groups"</command> + <command>vtysh -c "show ip igmp groups"</command> </leafNode> <leafNode name="interfaces"> <properties> <help>IGMP interfaces information</help> </properties> - <command>/usr/bin/vtysh -c "show ip igmp interface"</command> + <command>vtysh -c "show ip igmp interface"</command> </leafNode> <leafNode name="join"> <properties> <help>IGMP static join information</help> </properties> - <command>/usr/bin/vtysh -c "show ip igmp join"</command> + <command>vtysh -c "show ip igmp join"</command> </leafNode> <leafNode name="sources"> <properties> <help>IGMP sources information</help> </properties> - <command>/usr/bin/vtysh -c "show ip igmp sources"</command> + <command>vtysh -c "show ip igmp sources"</command> </leafNode> <leafNode name="statistics"> <properties> <help>IGMP statistics</help> </properties> - <command>/usr/bin/vtysh -c "show ip igmp statistics"</command> + <command>vtysh -c "show ip igmp statistics"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/show-ip-multicast.xml.in b/op-mode-definitions/show-ip-multicast.xml.in index 5331d2e35..80d83b424 100644 --- a/op-mode-definitions/show-ip-multicast.xml.in +++ b/op-mode-definitions/show-ip-multicast.xml.in @@ -25,13 +25,13 @@ <properties> <help>IP multicast information</help> </properties> - <command>/usr/bin/vtysh -c "show ip multicast"</command> + <command>vtysh -c "show ip multicast"</command> </leafNode> <leafNode name="route"> <properties> <help>IP multicast routing table</help> </properties> - <command>/usr/bin/vtysh -c "show ip mroute"</command> + <command>vtysh -c "show ip mroute"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/show-ip-ospf.xml.in b/op-mode-definitions/show-ip-ospf.xml.in index 50628d18e..fc298123b 100644 --- a/op-mode-definitions/show-ip-ospf.xml.in +++ b/op-mode-definitions/show-ip-ospf.xml.in @@ -11,25 +11,25 @@ <properties> <help>Show IPv4 Open Shortest Path First (OSPF) routing information</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf"</command> + <command>vtysh -c "show ip ospf"</command> <children> <leafNode name="border-routers"> <properties> <help>Show IPv4 OSPF border-routers information</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf border-routers"</command> + <command>vtysh -c "show ip ospf border-routers"</command> </leafNode> <node name="database"> <properties> <help>Show IPv4 OSPF database information</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database"</command> + <command>vtysh -c "show ip ospf database"</command> <children> <node name="asbr-summary"> <properties> <help>Show IPv4 OSPF ASBR summary database</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database asbr-summary"</command> + <command>vtysh -c "show ip ospf database asbr-summary"</command> <children> <tagNode name="adv-router"> <properties> @@ -38,7 +38,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database asbr-summary adv-router $7"</command> + <command>vtysh -c "show ip ospf database asbr-summary adv-router $7"</command> </tagNode> <node name="adv-router"> <properties> @@ -54,7 +54,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database asbr-summary $6"</command> + <command>vtysh -c "show ip ospf database asbr-summary $6"</command> <children> <node name="adv-router"> <properties> @@ -68,7 +68,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database asbr-summary $6 adv-router $8"</command> + <command>vtysh -c "show ip ospf database asbr-summary $6 adv-router $8"</command> </tagNode> <leafNode name="self-originate"> <properties> @@ -82,7 +82,7 @@ <properties> <help>Show IPv4 OSPF external database</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database external"</command> + <command>vtysh -c "show ip ospf database external"</command> <children> <tagNode name="adv-router"> <properties> @@ -91,7 +91,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database external adv-router $7"</command> + <command>vtysh -c "show ip ospf database external adv-router $7"</command> </tagNode> <node name="adv-router"> <properties> @@ -107,7 +107,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database external $6"</command> + <command>vtysh -c "show ip ospf database external $6"</command> <children> <node name="adv-router"> <properties> @@ -121,7 +121,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database external $6 adv-router $8"</command> + <command>vtysh -c "show ip ospf database external $6 adv-router $8"</command> </tagNode> <leafNode name="self-originate"> <properties> @@ -135,13 +135,13 @@ <properties> <help>Show IPv4 OSPF max-age database</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database max-age"</command> + <command>vtysh -c "show ip ospf database max-age"</command> </leafNode> <node name="network"> <properties> <help>Show IPv4 OSPF network database</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database network"</command> + <command>vtysh -c "show ip ospf database network"</command> <children> <tagNode name="adv-router"> <properties> @@ -150,7 +150,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database network adv-router $7"</command> + <command>vtysh -c "show ip ospf database network adv-router $7"</command> </tagNode> <node name="adv-router"> <properties> @@ -166,7 +166,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database network $6"</command> + <command>vtysh -c "show ip ospf database network $6"</command> <children> <node name="adv-router"> <properties> @@ -180,7 +180,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database network $6 adv-router $8"</command> + <command>vtysh -c "show ip ospf database network $6 adv-router $8"</command> </tagNode> <leafNode name="self-originate"> <properties> @@ -194,7 +194,7 @@ <properties> <help>Show IPv4 OSPF NSSA external database</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database nssa-external"</command> + <command>vtysh -c "show ip ospf database nssa-external"</command> <children> <tagNode name="adv-router"> <properties> @@ -203,7 +203,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database nssa-external adv-router $7"</command> + <command>vtysh -c "show ip ospf database nssa-external adv-router $7"</command> </tagNode> <node name="adv-router"> <properties> @@ -219,7 +219,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database nssa-external $6"</command> + <command>vtysh -c "show ip ospf database nssa-external $6"</command> <children> <node name="adv-router"> <properties> @@ -233,7 +233,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database nssa-external $6 adv-router $8"</command> + <command>vtysh -c "show ip ospf database nssa-external $6 adv-router $8"</command> </tagNode> <leafNode name="self-originate"> <properties> @@ -247,7 +247,7 @@ <properties> <help>Show IPv4 OSPF opaque-area database</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database opaque-area"</command> + <command>vtysh -c "show ip ospf database opaque-area"</command> <children> <tagNode name="adv-router"> <properties> @@ -256,7 +256,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database opaque-area adv-router $7"</command> + <command>vtysh -c "show ip ospf database opaque-area adv-router $7"</command> </tagNode> <node name="adv-router"> <properties> @@ -272,7 +272,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database opaque-area $6"</command> + <command>vtysh -c "show ip ospf database opaque-area $6"</command> <children> <node name="adv-router"> <properties> @@ -286,7 +286,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database opaque-area $6 adv-router $8"</command> + <command>vtysh -c "show ip ospf database opaque-area $6 adv-router $8"</command> </tagNode> <leafNode name="self-originate"> <properties> @@ -300,7 +300,7 @@ <properties> <help>Show IPv4 OSPF opaque-as database</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database opaque-as"</command> + <command>vtysh -c "show ip ospf database opaque-as"</command> <children> <tagNode name="adv-router"> <properties> @@ -309,7 +309,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database opaque-as adv-router $7"</command> + <command>vtysh -c "show ip ospf database opaque-as adv-router $7"</command> </tagNode> <node name="adv-router"> <properties> @@ -325,7 +325,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database opaque-as $6"</command> + <command>vtysh -c "show ip ospf database opaque-as $6"</command> <children> <node name="adv-router"> <properties> @@ -339,7 +339,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database opaque-as $6 adv-router $8"</command> + <command>vtysh -c "show ip ospf database opaque-as $6 adv-router $8"</command> </tagNode> <leafNode name="self-originate"> <properties> @@ -353,7 +353,7 @@ <properties> <help>Show IPv4 OSPF opaque-link database</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database opaque-link"</command> + <command>vtysh -c "show ip ospf database opaque-link"</command> <children> <tagNode name="adv-router"> <properties> @@ -362,7 +362,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database opaque-link adv-router $7"</command> + <command>vtysh -c "show ip ospf database opaque-link adv-router $7"</command> </tagNode> <node name="adv-router"> <properties> @@ -378,7 +378,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database opaque-link $6"</command> + <command>vtysh -c "show ip ospf database opaque-link $6"</command> <children> <node name="adv-router"> <properties> @@ -392,7 +392,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database opaque-link $6 adv-router $8"</command> + <command>vtysh -c "show ip ospf database opaque-link $6 adv-router $8"</command> </tagNode> <leafNode name="self-originate"> <properties> @@ -406,7 +406,7 @@ <properties> <help>Show IPv4 OSPF router database</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database router"</command> + <command>vtysh -c "show ip ospf database router"</command> <children> <tagNode name="adv-router"> <properties> @@ -415,7 +415,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database router adv-router $7"</command> + <command>vtysh -c "show ip ospf database router adv-router $7"</command> </tagNode> <node name="adv-router"> <properties> @@ -431,7 +431,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database router $6"</command> + <command>vtysh -c "show ip ospf database router $6"</command> <children> <node name="adv-router"> <properties> @@ -445,7 +445,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database router $6 adv-router $8"</command> + <command>vtysh -c "show ip ospf database router $6 adv-router $8"</command> </tagNode> <leafNode name="self-originate"> <properties> @@ -459,13 +459,13 @@ <properties> <help>Show IPv4 OSPF self-originate database</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database self-originate"</command> + <command>vtysh -c "show ip ospf database self-originate"</command> </leafNode> <node name="summary"> <properties> <help>Show summary of IPv4 OSPF database</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database summary"</command> + <command>vtysh -c "show ip ospf database summary"</command> <children> <tagNode name="adv-router"> <properties> @@ -474,7 +474,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database summary adv-router $7"</command> + <command>vtysh -c "show ip ospf database summary adv-router $7"</command> </tagNode> <node name="adv-router"> <properties> @@ -490,7 +490,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database summary $6"</command> + <command>vtysh -c "show ip ospf database summary $6"</command> <children> <node name="adv-router"> <properties> @@ -504,7 +504,7 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf database summary $6 adv-router $8"</command> + <command>vtysh -c "show ip ospf database summary $6 adv-router $8"</command> </tagNode> <leafNode name="self-originate"> <properties> @@ -520,7 +520,7 @@ <properties> <help>Show IPv4 OSPF interface information</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf interface"</command> + <command>vtysh -c "show ip ospf interface"</command> </node> <tagNode name="interface"> <properties> @@ -529,13 +529,13 @@ <script>${vyos_completion_dir}/list_interfaces.py</script> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf interface $5"</command> + <command>vtysh -c "show ip ospf interface $5"</command> </tagNode> <node name="neighbor"> <properties> <help>Show IPv4 OSPF neighbor information</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf neighbor"</command> + <command>vtysh -c "show ip ospf neighbor"</command> <children> <tagNode name="address"> <properties> @@ -544,13 +544,13 @@ <list><x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf neighbor $6"</command> + <command>vtysh -c "show ip ospf neighbor $6"</command> </tagNode> <node name="detail"> <properties> <help>Show detailed IPv4 OSPF neighbor information</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf neighbor detail"</command> + <command>vtysh -c "show ip ospf neighbor detail"</command> </node> </children> </node> @@ -562,13 +562,13 @@ <script>${vyos_completion_dir}/list_interfaces.py</script> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip ospf neighbor $5"</command> + <command>vtysh -c "show ip ospf neighbor $5"</command> </tagNode> <leafNode name="route"> <properties> <help>Show IPv4 OSPF route information</help> </properties> - <command>/usr/bin/vtysh -c "show ip ospf route"</command> + <command>vtysh -c "show ip ospf route"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/show-ip-pim.xml.in b/op-mode-definitions/show-ip-pim.xml.in index 3f4edc779..fa317a944 100644 --- a/op-mode-definitions/show-ip-pim.xml.in +++ b/op-mode-definitions/show-ip-pim.xml.in @@ -13,55 +13,55 @@ <properties> <help>PIM interfaces information</help> </properties> - <command>/usr/bin/vtysh -c "show ip pim interface"</command> + <command>vtysh -c "show ip pim interface"</command> </leafNode> <leafNode name="join"> <properties> <help>PIM join information</help> </properties> - <command>/usr/bin/vtysh -c "show ip pim join"</command> + <command>vtysh -c "show ip pim join"</command> </leafNode> <leafNode name="neighbor"> <properties> <help>PIM neighbor information</help> </properties> - <command>/usr/bin/vtysh -c "show ip pim neighbor"</command> + <command>vtysh -c "show ip pim neighbor"</command> </leafNode> <leafNode name="nexthop"> <properties> <help>PIM cached nexthop rpf information</help> </properties> - <command>/usr/bin/vtysh -c "show ip pim nexthop"</command> + <command>vtysh -c "show ip pim nexthop"</command> </leafNode> <leafNode name="state"> <properties> <help>PIM state information</help> </properties> - <command>/usr/bin/vtysh -c "show ip pim state"</command> + <command>vtysh -c "show ip pim state"</command> </leafNode> <leafNode name="statistics"> <properties> <help>PIM statistics</help> </properties> - <command>/usr/bin/vtysh -c "show ip pim statistics"</command> + <command>vtysh -c "show ip pim statistics"</command> </leafNode> <leafNode name="rp"> <properties> <help>PIM RP (Rendevous Point) information</help> </properties> - <command>/usr/bin/vtysh -c "show ip pim rp-info"</command> + <command>vtysh -c "show ip pim rp-info"</command> </leafNode> <leafNode name="rpf"> <properties> <help>PIM cached source rpf information</help> </properties> - <command>/usr/bin/vtysh -c "show ip pim rpf"</command> + <command>vtysh -c "show ip pim rpf"</command> </leafNode> <leafNode name="upstream"> <properties> <help>PIM upstream information</help> </properties> - <command>/usr/bin/vtysh -c "show ip pim upstream"</command> + <command>vtysh -c "show ip pim upstream"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/show-ip-rip.xml.in b/op-mode-definitions/show-ip-rip.xml.in index b61ab10a7..768a86ca1 100644 --- a/op-mode-definitions/show-ip-rip.xml.in +++ b/op-mode-definitions/show-ip-rip.xml.in @@ -11,13 +11,13 @@ <properties> <help>Show Routing Information Protocol (RIP) information</help> </properties> - <command>/usr/bin/vtysh -c "show ip rip"</command> + <command>vtysh -c "show ip rip"</command> <children> <leafNode name="status"> <properties> <help>Show RIP protocol status</help> </properties> - <command>/usr/bin/vtysh -c "show ip rip status"</command> + <command>vtysh -c "show ip rip status"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/show-ip-route.xml.in b/op-mode-definitions/show-ip-route.xml.in index a98048785..729572b4a 100644 --- a/op-mode-definitions/show-ip-route.xml.in +++ b/op-mode-definitions/show-ip-route.xml.in @@ -11,13 +11,13 @@ <properties> <help>Show IP routes</help> </properties> - <command>/usr/bin/vtysh -c "show ip route"</command> + <command>vtysh -c "show ip route"</command> <children> <leafNode name="bgp"> <properties> <help>Show IP BGP routes</help> </properties> - <command>/usr/bin/vtysh -c "show ip route bgp"</command> + <command>vtysh -c "show ip route bgp"</command> </leafNode> <node name="cache"> <properties> @@ -38,7 +38,7 @@ <properties> <help>Show IP connected routes</help> </properties> - <command>/usr/bin/vtysh -c "show ip route connected"</command> + <command>vtysh -c "show ip route connected"</command> </leafNode> <node name="forward"> <properties> @@ -59,43 +59,43 @@ <properties> <help>Show IP IS-IS routes</help> </properties> - <command>/usr/bin/vtysh -c "show ip route isis"</command> + <command>vtysh -c "show ip route isis"</command> </leafNode> <leafNode name="kernel"> <properties> <help>Show IP kernel routes</help> </properties> - <command>/usr/bin/vtysh -c "show ip route kernel"</command> + <command>vtysh -c "show ip route kernel"</command> </leafNode> <leafNode name="ospf"> <properties> <help>Show IP OSPF routes</help> </properties> - <command>/usr/bin/vtysh -c "show ip route ospf"</command> + <command>vtysh -c "show ip route ospf"</command> </leafNode> <leafNode name="rip"> <properties> <help>Show IP RIP routes</help> </properties> - <command>/usr/bin/vtysh -c "show ip route rip"</command> + <command>vtysh -c "show ip route rip"</command> </leafNode> <leafNode name="static"> <properties> <help>Show IP static routes</help> </properties> - <command>/usr/bin/vtysh -c "show ip route static"</command> + <command>vtysh -c "show ip route static"</command> </leafNode> <leafNode name="summary"> <properties> <help>Show IP routes summary</help> </properties> - <command>/usr/bin/vtysh -c "show ip route summary"</command> + <command>vtysh -c "show ip route summary"</command> </leafNode> <leafNode name="supernets-only"> <properties> <help>Show IP supernet routes</help> </properties> - <command>/usr/bin/vtysh -c "show ip route supernets-only"</command> + <command>vtysh -c "show ip route supernets-only"</command> </leafNode> <node name="table"> <properties> @@ -109,7 +109,7 @@ <list><1-200></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip route table $5"</command> + <command>vtysh -c "show ip route table $5"</command> </tagNode> <node name="tag"> <properties> @@ -123,7 +123,7 @@ <list><1-4294967295></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip route tag $5"</command> + <command>vtysh -c "show ip route tag $5"</command> </tagNode> <node name="vrf"> <properties> @@ -138,7 +138,7 @@ <path>vrf name</path> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip route vrf $5"</command> + <command>vtysh -c "show ip route vrf $5"</command> </tagNode> </children> </node> @@ -149,13 +149,13 @@ <list><x.x.x.x> <x.x.x.x/x></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show ip route $4"</command> + <command>vtysh -c "show ip route $4"</command> <children> <leafNode name="longer-prefixes"> <properties> <help>Show longer prefixes of routes for specified IP address or prefix</help> </properties> - <command>/usr/bin/vtysh -c "show ip route $4 longer-prefixes"</command> + <command>vtysh -c "show ip route $4 longer-prefixes"</command> </leafNode> </children> </tagNode> diff --git a/op-mode-definitions/show-ip.xml.in b/op-mode-definitions/show-ip.xml.in new file mode 100644 index 000000000..91564440d --- /dev/null +++ b/op-mode-definitions/show-ip.xml.in @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="show"> + <children> + <node name="ip"> + <properties> + <help>Show IPv4 routing information</help> + </properties> + <children> + <node name="neighbors"> + <properties> + <help>Show IPv4 Neighbor Discovery (ND) information</help> + </properties> + <command>${vyos_op_scripts_dir}/show_neigh.py --family inet</command> + </node> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/op-mode-definitions/show-ipv6-bgp.xml.in b/op-mode-definitions/show-ipv6-bgp.xml.in deleted file mode 100644 index aad61b97a..000000000 --- a/op-mode-definitions/show-ipv6-bgp.xml.in +++ /dev/null @@ -1,203 +0,0 @@ -<?xml version="1.0"?> -<interfaceDefinition> - <node name="show"> - <children> - <node name="ipv6"> - <properties> - <help>Show IPv6 routing information</help> - </properties> - <children> - <node name="bgp"> - <properties> - <help>Show Border Gateway Protocol (BGP) information</help> - </properties> - <command>vtysh -c "show bgp ipv6"</command> - <children> - <leafNode name="summary"> - <properties> - <help>Show summary of BGP neighbor status</help> - </properties> - <command>vtysh -c "show bgp ipv6 summary"</command> - </leafNode> - <tagNode name="regexp"> - <properties> - <help>Show routes matching AS path regular expression</help> - </properties> - <command>vtysh -c "show bgp ipv6 regexp $5"</command> - </tagNode> - <tagNode name="prefix-list"> - <properties> - <help>Show routes matching the IPv6 prefix-list name</help> - <completionHelp> - <path>policy prefix-list6</path> - </completionHelp> - </properties> - <command>vtysh -c "show bgp ipv6 prefix-list $5"</command> - </tagNode> - <tagNode name="neighbors"> - <properties> - <help>Show detailed information on TCP and BGP neighbor connections for given address</help> - <completionHelp> - <script>vtysh -c "show bgp ipv6 summary" | awk '{print $1}' | grep -oE "\b([0-9a-f]{1,4}\:{0,2}){0,20}\b"</script> - </completionHelp> - </properties> - <command>vtysh -c "show bgp ipv6 neighbor $5"</command> - <children> - <leafNode name="advertised-routes"> - <properties> - <help>Show routes advertised to a BGP neighbor</help> - </properties> - <command>vtysh -c "show bgp ipv6 neighbor $5 advertised-routes"</command> - </leafNode> - <leafNode name="filtered-routes"> - <properties> - <help>Show routes filtered from a BGP neighbor</help> - </properties> - <command>vtysh -c "show bgp ipv6 neighbor $5 filtered-routes"</command> - </leafNode> - <leafNode name="dampened-routes"> - <properties> - <help>Show dampened routes received from BGP neighbor</help> - </properties> - <command>vtysh -c "show bgp ipv6 neighbor $5 dampened-routes"</command> - </leafNode> - <leafNode name="flap-statistics"> - <properties> - <help>Show flap statistics of the routes learned from BGP neighbor</help> - </properties> - <command>vtysh -c "show bgp ipv6 neighbor $5 flap-statistics"</command> - </leafNode> - <leafNode name="prefix-counts"> - <properties> - <help>Show detailed prefix count information for BGP neighbor</help> - </properties> - <command>vtysh -c "show bgp ipv6 neighbor $5 prefix-counts"</command> - </leafNode> - <node name="received"> - <properties> - <help>Show information received from BGP neighbor</help> - </properties> - <children> - <leafNode name="prefix-filter"> - <properties> - <help>Show prefixlist filter</help> - </properties> - <command>vtysh -c "show bgp ipv6 neighbor $5 received prefix-filter"</command> - </leafNode> - </children> - </node> - <leafNode name="received-routes"> - <properties> - <help>Show received routes from BGP neighbor</help> - </properties> - <command>vtysh -c "show bgp ipv6 neighbor $5 received-routes"</command> - </leafNode> - <leafNode name="routes"> - <properties> - <help>Show routes learned from BGP neighbor</help> - </properties> - <command>vtysh -c "show bgp ipv6 neighbor $5 routes"</command> - </leafNode> - </children> - </tagNode> - <tagNode name="large-community"> - <properties> - <help>Show routes matching the large-community-list number or name</help> - </properties> - <command>vtysh -c "show bgp ipv6 large-community-list $5"</command> - <children> - <node name="exact-match"> - <properties> - <help>Show routes matching the large-community-list number or name</help> - </properties> - <command>vtysh -c "show bgp ipv6 large-community-list $5 exact-match"</command> - </node> - </children> - </tagNode> - <tagNode name="large-community-list"> - <properties> - <help>Show routes matching the large-community-list number or name</help> - </properties> - <command>vtysh -c "show bgp ipv6 large-community-list $5"</command> - <children> - <node name="exact-match"> - <properties> - <help>Show routes matching the large-community-list number or name</help> - </properties> - <command>vtysh -c "show bgp ipv6 large-community-list $5 exact-match"</command> - </node> - </children> - </tagNode> - <tagNode name="filter-list"> - <properties> - <help>Show routes conforming to regular expression access list name</help> - </properties> - <command>vtysh -c "show bgp ipv6 filter-list $5"</command> - </tagNode> - <tagNode name="community"> - <properties> - <help>Show BGP information for specified community number</help> - <completionHelp> - <list><AA:NN> local-AS no-advertise no-export</list> - </completionHelp> - </properties> - <command>vtysh -c "show bgp ipv6 community $5"</command> - <children> - <node name="exact-match"> - <properties> - <help>Show routes from community that exactly matches the community number</help> - </properties> - <command>vtysh -c "show bgp ipv6 community $5 exact-match"</command> - </node> - </children> - </tagNode> - <tagNode name="community-list"> - <properties> - <help>Show routes matching the community-list number or name</help> - </properties> - <command>vtysh -c "show bgp ipv6 community-list $5"</command> - <children> - <node name="exact-match"> - <properties> - <help>Show routes exactly matching the community-list name or number</help> - </properties> - <command>vtysh -c "show bgp ipv6 community-list $5 exact-match"</command> - </node> - </children> - </tagNode> - <tagNode name="route-map"> - <properties> - <help>Show BGP routes matching the specified route map</help> - <completionHelp> - <path>policy route-map</path> - </completionHelp> - </properties> - <command>vtysh -c "show bgp ipv6 route-map $5"</command> - </tagNode> - </children> - </node> - <tagNode name="bgp"> - <properties> - <help>Show BGP information for specified IP address or prefix</help> - <completionHelp> - <list><h:h:h:h:h:h:h:h> <h:h:h:h:h:h:h:h/x></list> - </completionHelp> - </properties> - <command>vtysh -c "show bgp ipv6 $4"</command> - <children> - <node name="longer-prefixes"> - <properties> - <help>Show route and more specific routes</help> - <completionHelp> - <list><h:h:h:h:h:h:h:h> <h:h:h:h:h:h:h:h/x></list> - </completionHelp> - </properties> - <command>vtysh -c "show bgp ipv6 $4 longer-prefixes"</command> - </node> - </children> - </tagNode> - </children> - </node> - </children> - </node> -</interfaceDefinition> diff --git a/op-mode-definitions/show-isis.xml.in b/op-mode-definitions/show-isis.xml.in index 4e308730f..890d511e2 100644 --- a/op-mode-definitions/show-isis.xml.in +++ b/op-mode-definitions/show-isis.xml.in @@ -16,10 +16,10 @@ <properties> <help>Show detailed information</help> </properties> - <command>/usr/bin/vtysh -c "show isis database detail"</command> + <command>vtysh -c "show isis database detail"</command> </leafNode> </children> - <command>/usr/bin/vtysh -c "show isis database"</command> + <command>vtysh -c "show isis database"</command> </node> <tagNode name="database"> <properties> @@ -28,13 +28,13 @@ <list>lsp-id detail</list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show isis database $4"</command> + <command>vtysh -c "show isis database $4"</command> </tagNode> <leafNode name="hostname"> <properties> <help>Show IS-IS dynamic hostname mapping</help> </properties> - <command>/usr/bin/vtysh -c "show isis hostname"</command> + <command>vtysh -c "show isis hostname"</command> </leafNode> <node name="interface"> <properties> @@ -48,10 +48,10 @@ <properties> <help>Show detailed information</help> </properties> - <command>/usr/bin/vtysh -c "show isis interface detail"</command> + <command>vtysh -c "show isis interface detail"</command> </leafNode> </children> - <command>/usr/bin/vtysh -c "show isis interface"</command> + <command>vtysh -c "show isis interface"</command> </node> <tagNode name="interface"> <properties> @@ -60,7 +60,7 @@ <script>${vyos_completion_dir}/list_interfaces.py</script> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show isis interface $4"</command> + <command>vtysh -c "show isis interface $4"</command> </tagNode> <node name="traffic-engineering"> <properties> @@ -71,13 +71,13 @@ <properties> <help>Show router information</help> </properties> - <command>/usr/bin/vtysh -c "show isis mpls-te router"</command> + <command>vtysh -c "show isis mpls-te router"</command> </leafNode> <leafNode name="interface"> <properties> <help>Show interface information</help> </properties> - <command>/usr/bin/vtysh -c "show isis mpls-te interface"</command> + <command>vtysh -c "show isis mpls-te interface"</command> </leafNode> <tagNode name="interface"> <properties> @@ -86,7 +86,7 @@ <script>${vyos_completion_dir}/list_interfaces.py</script> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show isis mpls-te interface $5"</command> + <command>vtysh -c "show isis mpls-te interface $5"</command> </tagNode> </children> </node> @@ -99,10 +99,10 @@ <properties> <help>Show detailed information</help> </properties> - <command>/usr/bin/vtysh -c "show isis neighbor detail"</command> + <command>vtysh -c "show isis neighbor detail"</command> </leafNode> </children> - <command>/usr/bin/vtysh -c "show isis neighbor"</command> + <command>vtysh -c "show isis neighbor"</command> </node> <tagNode name="neighbor"> <properties> @@ -111,7 +111,7 @@ <list>system-id</list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show isis neighbor $4"</command> + <command>vtysh -c "show isis neighbor $4"</command> </tagNode> <node name="route"> <properties> @@ -122,16 +122,16 @@ <properties> <help>Show level-1 routes</help> </properties> - <command>/usr/bin/vtysh -c "show isis route level-1"</command> + <command>vtysh -c "show isis route level-1"</command> </leafNode> <leafNode name="level-2"> <properties> <help>Show level-2 routes</help> </properties> - <command>/usr/bin/vtysh -c "show isis route level-2"</command> + <command>vtysh -c "show isis route level-2"</command> </leafNode> </children> - <command>/usr/bin/vtysh -c "show isis route"</command> + <command>vtysh -c "show isis route"</command> </node> <node name="segment-routing"> <properties> @@ -142,13 +142,13 @@ <properties> <help>Show node information</help> </properties> - <command>/usr/bin/vtysh -c "show isis segment-routing node"</command> + <command>vtysh -c "show isis segment-routing node"</command> </leafNode> <leafNode name="prefix-sids"> <properties> <help>Show prefix segment IDs</help> </properties> - <command>/usr/bin/vtysh -c "show isis segment-routing prefix-sids"</command> + <command>vtysh -c "show isis segment-routing prefix-sids"</command> </leafNode> </children> </node> @@ -156,13 +156,13 @@ <properties> <help>Show IS-IS SPF delay parameters</help> </properties> - <command>/usr/bin/vtysh -c "show isis spf-delay-ietf"</command> + <command>vtysh -c "show isis spf-delay-ietf"</command> </leafNode> <leafNode name="summary"> <properties> <help>Show IS-IS information summary</help> </properties> - <command>/usr/bin/vtysh -c "show isis summary"</command> + <command>vtysh -c "show isis summary"</command> </leafNode> <node name="topology"> <properties> @@ -173,16 +173,16 @@ <properties> <help>Show level-1 routes</help> </properties> - <command>/usr/bin/vtysh -c "show isis topology level-1"</command> + <command>vtysh -c "show isis topology level-1"</command> </leafNode> <leafNode name="level-2"> <properties> <help>Show level-2 routes</help> </properties> - <command>/usr/bin/vtysh -c "show isis topology level-2"</command> + <command>vtysh -c "show isis topology level-2"</command> </leafNode> </children> - <command>/usr/bin/vtysh -c "show isis topology"</command> + <command>vtysh -c "show isis topology"</command> </node> </children> </node> diff --git a/op-mode-definitions/show-mpls.xml.in b/op-mode-definitions/show-mpls.xml.in index 833ac98eb..86f6f1bcc 100644 --- a/op-mode-definitions/show-mpls.xml.in +++ b/op-mode-definitions/show-mpls.xml.in @@ -16,41 +16,41 @@ <properties> <help>Label Information Base</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding"</command> + <command>vtysh -c "show mpls ldp binding"</command> <children> <node name="detail"> <properties> <help>Show detailed information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding detail"</command> + <command>vtysh -c "show mpls ldp binding detail"</command> </node> <tagNode name="neighbor"> <properties> <help>Display labels from LDP neighbor</help> <completionHelp> <list><x.x.x.x> <h:h:h:h:h:h:h:h></list> - <script>/usr/bin/vtysh -c "show mpls ldp neighbor" | awk '{print $2}' | egrep -v "ID"</script> + <script>vtysh -c "show mpls ldp neighbor" | awk '{print $2}' | egrep -v "ID"</script> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding neighbor $6"</command> + <command>vtysh -c "show mpls ldp binding neighbor $6"</command> <children> <leafNode name="detail"> <properties> <help>Show detailed information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding neighbor $6 detail"</command> + <command>vtysh -c "show mpls ldp binding neighbor $6 detail"</command> </leafNode> <tagNode name="local-label"> <properties> <help>Match locally assigned label value</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding neighbor $6 local-label $8"</command> + <command>vtysh -c "show mpls ldp binding neighbor $6 local-label $8"</command> </tagNode> <tagNode name="remote-label"> <properties> <help>Match remotely assigned label value</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding neighbor $6 remote-label $8"</command> + <command>vtysh -c "show mpls ldp binding neighbor $6 remote-label $8"</command> </tagNode> </children> </tagNode> @@ -58,29 +58,29 @@ <properties> <help>Match locally assigned label value</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding local-label $6"</command> + <command>vtysh -c "show mpls ldp binding local-label $6"</command> <children> <leafNode name="detail"> <properties> <help>Show detailed information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding local-label $6 detail"</command> + <command>vtysh -c "show mpls ldp binding local-label $6 detail"</command> </leafNode> <tagNode name="neighbor"> <properties> <help>Match LDP neighbor</help> <completionHelp> <list><x.x.x.x> <h:h:h:h:h:h:h:h></list> - <script>/usr/bin/vtysh -c "show mpls ldp neighbor" | awk '{print $2}' | egrep -v "ID"</script> + <script>vtysh -c "show mpls ldp neighbor" | awk '{print $2}' | egrep -v "ID"</script> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding local-label $6 neighbor $8"</command> + <command>vtysh -c "show mpls ldp binding local-label $6 neighbor $8"</command> </tagNode> <tagNode name="remote-label"> <properties> <help>Match remotely assigned label value</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding local-label $6 remote-label $8"</command> + <command>vtysh -c "show mpls ldp binding local-label $6 remote-label $8"</command> </tagNode> </children> </tagNode> @@ -88,29 +88,29 @@ <properties> <help>Match remotely assigned label value</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding remote-label $6"</command> + <command>vtysh -c "show mpls ldp binding remote-label $6"</command> <children> <leafNode name="detail"> <properties> <help>Show detailed information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding remote-label $6 detail"</command> + <command>vtysh -c "show mpls ldp binding remote-label $6 detail"</command> </leafNode> <tagNode name="neighbor"> <properties> <help>Match LDP neighbor</help> <completionHelp> <list><x.x.x.x> <h:h:h:h:h:h:h:h></list> - <script>/usr/bin/vtysh -c "show mpls ldp neighbor" | awk '{print $2}' | egrep -v "ID"</script> + <script>vtysh -c "show mpls ldp neighbor" | awk '{print $2}' | egrep -v "ID"</script> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding remote-label $6 neighbor $8"</command> + <command>vtysh -c "show mpls ldp binding remote-label $6 neighbor $8"</command> </tagNode> <tagNode name="local-label"> <properties> <help>Match locally assigned label value</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding remote-label $6 local-label $8"</command> + <command>vtysh -c "show mpls ldp binding remote-label $6 local-label $8"</command> </tagNode> </children> </tagNode> @@ -123,13 +123,13 @@ <list><x.x.x.x/x> <h:h:h:h:h:h:h:h/h></list> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding $5"</command> + <command>vtysh -c "show mpls ldp binding $5"</command> <children> <leafNode name="detail"> <properties> <help>Show detailed information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp binding $5 detail"</command> + <command>vtysh -c "show mpls ldp binding $5 detail"</command> </leafNode> </children> </tagNode> @@ -137,13 +137,13 @@ <properties> <help>Discovery hello information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp discovery"</command> + <command>vtysh -c "show mpls ldp discovery"</command> <children> <leafNode name="detail"> <properties> <help>Show detailed information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp discovery detail"</command> + <command>vtysh -c "show mpls ldp discovery detail"</command> </leafNode> </children> </node> @@ -151,25 +151,25 @@ <properties> <help>LDP interface information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp interface"</command> + <command>vtysh -c "show mpls ldp interface"</command> </node> <node name="neighbor"> <properties> <help>LDP neighbor information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp neighbor"</command> + <command>vtysh -c "show mpls ldp neighbor"</command> <children> <leafNode name="detail"> <properties> <help>Show detailed information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp neighbor detail"</command> + <command>vtysh -c "show mpls ldp neighbor detail"</command> </leafNode> <leafNode name="capabilities"> <properties> <help>Show neighbor capability information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp neighbor capabilities"</command> + <command>vtysh -c "show mpls ldp neighbor capabilities"</command> </leafNode> </children> </node> @@ -178,22 +178,22 @@ <help>LDP neighbor</help> <completionHelp> <list><x.x.x.x> <h:h:h:h:h:h:h:h></list> - <script>/usr/bin/vtysh -c "show mpls ldp neighbor" | awk '{print $2}' | egrep -v "ID"</script> + <script>vtysh -c "show mpls ldp neighbor" | awk '{print $2}' | egrep -v "ID"</script> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp neighbor $5"</command> + <command>vtysh -c "show mpls ldp neighbor $5"</command> <children> <leafNode name="detail"> <properties> <help>Show detailed information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp neighbor $5 detail"</command> + <command>vtysh -c "show mpls ldp neighbor $5 detail"</command> </leafNode> <leafNode name="capabilities"> <properties> <help>Show neighbor capability information</help> </properties> - <command>/usr/bin/vtysh -c "show mpls ldp neighbor $5 capabilities"</command> + <command>vtysh -c "show mpls ldp neighbor $5 capabilities"</command> </leafNode> </children> </tagNode> @@ -203,13 +203,13 @@ <properties> <help>Show MPLS pseudowire interfaces</help> </properties> - <command>/usr/bin/vtysh -c "show mpls pseudowires"</command> + <command>vtysh -c "show mpls pseudowires"</command> </node> <node name="table"> <properties> <help>Show MPLS table</help> </properties> - <command>/usr/bin/vtysh -c "show mpls table"</command> + <command>vtysh -c "show mpls table"</command> </node> </children> </node> diff --git a/op-mode-definitions/show-protocols-bfd.xml.in b/op-mode-definitions/show-protocols-bfd.xml.in index 3d9b67c67..886b01e51 100644 --- a/op-mode-definitions/show-protocols-bfd.xml.in +++ b/op-mode-definitions/show-protocols-bfd.xml.in @@ -13,13 +13,13 @@ <properties> <help>Show all Bidirectional Forwarding Detection (BFD) peer status</help> </properties> - <command>/usr/bin/vtysh -c "show bfd peers"</command> + <command>vtysh -c "show bfd peers"</command> <children> <leafNode name="counters"> <properties> <help>Show Bidirectional Forwarding Detection (BFD) peer counters</help> </properties> - <command>/usr/bin/vtysh -c "show bfd peers counters"</command> + <command>vtysh -c "show bfd peers counters"</command> </leafNode> </children> </node> @@ -27,16 +27,16 @@ <properties> <help>Show Bidirectional Forwarding Detection (BFD) peer status</help> <completionHelp> - <script>/usr/bin/vtysh -c "show bfd peers" | awk '/[:blank:]*peer/ { printf "%s\n", $2 }'</script> + <script>vtysh -c "show bfd peers" | awk '/[:blank:]*peer/ { printf "%s\n", $2 }'</script> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show bfd peers" | awk -v BFD_PEER=$5 'BEGIN { regex = sprintf("(peer %s.*)vrf", BFD_PEER) } { if (match($0, regex, bfd_peer_value)) peer=bfd_peer_value[1] } END { if (peer) system("/usr/bin/vtysh -c \"show bfd " peer "\"") }'</command> + <command>vtysh -c "show bfd peers" | awk -v BFD_PEER=$5 'BEGIN { regex = sprintf("(peer %s.*)vrf", BFD_PEER) } { if (match($0, regex, bfd_peer_value)) peer=bfd_peer_value[1] } END { if (peer) system("vtysh -c \"show bfd " peer "\"") }'</command> <children> <leafNode name="counters"> <properties> <help>Show Bidirectional Forwarding Detection (BFD) peer counters</help> </properties> - <command>/usr/bin/vtysh -c "show bfd peers" | awk -v BFD_PEER=$5 'BEGIN { regex = sprintf("(peer %s.*)vrf", BFD_PEER) } { if (match($0, regex, bfd_peer_value)) peer=bfd_peer_value[1] } END { if (peer) system("/usr/bin/vtysh -c \"show bfd " peer " counters\"") }'</command> + <command>vtysh -c "show bfd peers" | awk -v BFD_PEER=$5 'BEGIN { regex = sprintf("(peer %s.*)vrf", BFD_PEER) } { if (match($0, regex, bfd_peer_value)) peer=bfd_peer_value[1] } END { if (peer) system("vtysh -c \"show bfd " peer " counters\"") }'</command> </leafNode> </children> </tagNode> @@ -44,7 +44,7 @@ <properties> <help>Show Bidirectional Forwarding Detection (BFD) peers brief</help> </properties> - <command>/usr/bin/vtysh -c "show bfd peers brief"</command> + <command>vtysh -c "show bfd peers brief"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/show-route-map.xml.in b/op-mode-definitions/show-route-map.xml.in index 0e376757b..633b2a4cb 100644 --- a/op-mode-definitions/show-route-map.xml.in +++ b/op-mode-definitions/show-route-map.xml.in @@ -6,7 +6,7 @@ <properties> <help>Show route-map information</help> </properties> - <command>/usr/bin/vtysh -c "show route-map"</command> + <command>vtysh -c "show route-map"</command> </node> <tagNode name="route-map"> <properties> @@ -15,7 +15,7 @@ <path>policy route-map</path> </completionHelp> </properties> - <command>/usr/bin/vtysh -c "show route-map $3"</command> + <command>vtysh -c "show route-map $3"</command> </tagNode> </children> </node> diff --git a/op-mode-definitions/show-rpki.xml.in b/op-mode-definitions/show-rpki.xml.in index d68c3b862..f593e4803 100644 --- a/op-mode-definitions/show-rpki.xml.in +++ b/op-mode-definitions/show-rpki.xml.in @@ -11,19 +11,19 @@ <properties> <help>Show RPKI cache connections</help> </properties> - <command>/usr/bin/vtysh -c "show rpki cache-connection"</command> + <command>vtysh -c "show rpki cache-connection"</command> </leafNode> <leafNode name="cache-server"> <properties> <help>Show RPKI cache servers information</help> </properties> - <command>/usr/bin/vtysh -c "show rpki cache-server"</command> + <command>vtysh -c "show rpki cache-server"</command> </leafNode> <leafNode name="prefix-table"> <properties> <help>Show RPKI-validated prefixes</help> </properties> - <command>/usr/bin/vtysh -c "show rpki prefix-table"</command> + <command>vtysh -c "show rpki prefix-table"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/show-system.xml.in b/op-mode-definitions/show-system.xml.in index 0623e3b62..5e9bf719e 100644 --- a/op-mode-definitions/show-system.xml.in +++ b/op-mode-definitions/show-system.xml.in @@ -128,7 +128,7 @@ <properties> <help>Show memory usage of all routing protocols</help> </properties> - <command>/usr/bin/vtysh -c "show memory"</command> + <command>vtysh -c "show memory"</command> </leafNode> </children> </node> @@ -162,7 +162,7 @@ <properties> <help>Show Quagga routing daemons</help> </properties> - <command>/usr/bin/vtysh -c "show daemons"</command> + <command>vtysh -c "show daemons"</command> </leafNode> <leafNode name="storage"> <properties> diff --git a/op-mode-definitions/show-table.xml.in b/op-mode-definitions/show-table.xml.in index b093a5de7..c7998e35d 100644 --- a/op-mode-definitions/show-table.xml.in +++ b/op-mode-definitions/show-table.xml.in @@ -6,7 +6,7 @@ <properties> <help>Show routing tables</help> </properties> - <command>/usr/bin/vtysh -c "show zebra router table summary"</command> + <command>vtysh -c "show zebra router table summary"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/show-version.xml.in b/op-mode-definitions/show-version.xml.in index 2202d27b3..f1e2e2666 100644 --- a/op-mode-definitions/show-version.xml.in +++ b/op-mode-definitions/show-version.xml.in @@ -24,7 +24,7 @@ <properties> <help>Show Quagga version information</help> </properties> - <command>/usr/bin/vtysh -c "show version"</command> + <command>vtysh -c "show version"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/traffic-dump.xml.in b/op-mode-definitions/traffic-dump.xml.in index cd0d459ca..76e3ddce5 100644 --- a/op-mode-definitions/traffic-dump.xml.in +++ b/op-mode-definitions/traffic-dump.xml.in @@ -16,7 +16,7 @@ </completionHelp> </properties> <children> - <tagNode name="verbose"> + <node name="verbose"> <command>sudo tcpdump -vvv -ne -i $4</command> <properties> <help>Provide more detailed packets for each monitored traffic</help> @@ -43,7 +43,7 @@ </children> </tagNode> </children> - </tagNode> + </node> <tagNode name="filter"> <command>sudo tcpdump -n -i $4 "${@:6}"</command> <properties> diff --git a/python/vyos/configsession.py b/python/vyos/configsession.py index 82b9355a3..670e6c7fc 100644 --- a/python/vyos/configsession.py +++ b/python/vyos/configsession.py @@ -129,9 +129,9 @@ class ConfigSession(object): def __run_command(self, cmd_list): p = subprocess.Popen(cmd_list, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=self.__session_env) + (stdout_data, stderr_data) = p.communicate() + output = stdout_data.decode() result = p.wait() - output = p.stdout.read().decode() - p.communicate() if result != 0: raise ConfigSessionError(output) return output diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py index abd91583d..5a4d14c68 100644 --- a/python/vyos/configverify.py +++ b/python/vyos/configverify.py @@ -89,6 +89,49 @@ def verify_vrf(config): 'Interface "{ifname}" cannot be both a member of VRF "{vrf}" ' 'and bridge "{is_bridge_member}"!'.format(**config)) +def verify_tunnel(config): + """ + This helper is used to verify the common part of the tunnel + """ + from vyos.template import is_ipv4 + from vyos.template import is_ipv6 + + if 'encapsulation' not in config: + raise ConfigError('Must configure the tunnel encapsulation for '\ + '{ifname}!'.format(**config)) + + if 'local_ip' not in config and 'dhcp_interface' not in config: + raise ConfigError('local-ip is mandatory for tunnel') + + if 'remote_ip' not in config and config['encapsulation'] != 'gre': + raise ConfigError('remote-ip is mandatory for tunnel') + + if {'local_ip', 'dhcp_interface'} <= set(config): + raise ConfigError('Can not use both local-ip and dhcp-interface') + + if config['encapsulation'] in ['ipip6', 'ip6ip6', 'ip6gre', 'ip6erspan']: + error_ipv6 = 'Encapsulation mode requires IPv6' + if 'local_ip' in config and not is_ipv6(config['local_ip']): + raise ConfigError(f'{error_ipv6} local-ip') + + if 'remote_ip' in config and not is_ipv6(config['remote_ip']): + raise ConfigError(f'{error_ipv6} remote-ip') + else: + error_ipv4 = 'Encapsulation mode requires IPv4' + if 'local_ip' in config and not is_ipv4(config['local_ip']): + raise ConfigError(f'{error_ipv4} local-ip') + + if 'remote_ip' in config and not is_ipv4(config['remote_ip']): + raise ConfigError(f'{error_ipv4} remote-ip') + + if config['encapsulation'] in ['sit', 'gre-bridge']: + if 'source_interface' in config: + raise ConfigError('Option source-interface can not be used with ' \ + 'encapsulation "sit" or "gre-bridge"') + elif config['encapsulation'] == 'gre': + if 'local_ip' in config and is_ipv6(config['local_ip']): + raise ConfigError('Can not use local IPv6 address is for mGRE tunnels') + def verify_eapol(config): """ Common helper function used by interface implementations to perform @@ -209,6 +252,13 @@ def verify_vlan_config(config): Common helper function used by interface implementations to perform recurring validation of interface VLANs """ + + # VLAN and Q-in-Q IDs are not allowed to overlap + if 'vif' in config and 'vif_s' in config: + duplicate = list(set(config['vif']) & set(config['vif_s'])) + if duplicate: + raise ConfigError(f'Duplicate VLAN id "{duplicate[0]}" used for vif and vif-s interfaces!') + # 802.1q VLANs for vlan in config.get('vif', {}): vlan = config['vif'][vlan] @@ -217,17 +267,17 @@ def verify_vlan_config(config): verify_vrf(vlan) # 802.1ad (Q-in-Q) VLANs - for vlan in config.get('vif_s', {}): - vlan = config['vif_s'][vlan] - verify_dhcpv6(vlan) - verify_address(vlan) - verify_vrf(vlan) - - for vlan in config.get('vif_s', {}).get('vif_c', {}): - vlan = config['vif_c'][vlan] - verify_dhcpv6(vlan) - verify_address(vlan) - verify_vrf(vlan) + for s_vlan in config.get('vif_s', {}): + s_vlan = config['vif_s'][s_vlan] + verify_dhcpv6(s_vlan) + verify_address(s_vlan) + verify_vrf(s_vlan) + + for c_vlan in s_vlan.get('vif_c', {}): + c_vlan = s_vlan['vif_c'][c_vlan] + verify_dhcpv6(c_vlan) + verify_address(c_vlan) + verify_vrf(c_vlan) def verify_accel_ppp_base_service(config): """ diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py new file mode 100644 index 000000000..cef7d476f --- /dev/null +++ b/python/vyos/ethtool.py @@ -0,0 +1,101 @@ +# Copyright 2021 VyOS maintainers and contributors <maintainers@vyos.io> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see <http://www.gnu.org/licenses/>. + +from vyos.util import cmd + +class Ethtool: + """ + Class is used to retrive and cache information about an ethernet adapter + """ + + # dictionary containing driver featurs, it will be populated on demand and + # the content will look like: + # { + # 'tls-hw-tx-offload': {'fixed': True, 'on': False}, + # 'tx-checksum-fcoe-crc': {'fixed': True, 'on': False}, + # 'tx-checksum-ip-generic': {'fixed': False, 'on': True}, + # 'tx-checksum-ipv4': {'fixed': True, 'on': False}, + # 'tx-checksum-ipv6': {'fixed': True, 'on': False}, + # 'tx-checksum-sctp': {'fixed': True, 'on': False}, + # 'tx-checksumming': {'fixed': False, 'on': True}, + # 'tx-esp-segmentation': {'fixed': True, 'on': False}, + # } + features = { } + ring_buffers = { } + + def __init__(self, ifname): + # Now populate features dictionaty + tmp = cmd(f'ethtool -k {ifname}') + # skip the first line, it only says: "Features for eth0": + for line in tmp.splitlines()[1:]: + if ":" in line: + key, value = [s.strip() for s in line.strip().split(":", 1)] + fixed = "fixed" in value + if fixed: + value = value.split()[0].strip() + self.features[key.strip()] = { + "on": value == "on", + "fixed": fixed + } + + tmp = cmd(f'ethtool -g {ifname}') + # We are only interested in line 2-5 which contains the device maximum + # ringbuffers + for line in tmp.splitlines()[2:6]: + if ':' in line: + key, value = [s.strip() for s in line.strip().split(":", 1)] + key = key.lower().replace(' ', '_') + self.ring_buffers[key] = int(value) + + + def is_fixed_lro(self): + # in case of a missing configuration, rather return "fixed". In Ethtool + # terminology "fixed" means the setting can not be changed by the user. + return self.features.get('large-receive-offload', True).get('fixed', True) + + def is_fixed_gro(self): + # in case of a missing configuration, rather return "fixed". In Ethtool + # terminology "fixed" means the setting can not be changed by the user. + return self.features.get('generic-receive-offload', True).get('fixed', True) + + def is_fixed_gso(self): + # in case of a missing configuration, rather return "fixed". In Ethtool + # terminology "fixed" means the setting can not be changed by the user. + return self.features.get('generic-segmentation-offload', True).get('fixed', True) + + def is_fixed_sg(self): + # in case of a missing configuration, rather return "fixed". In Ethtool + # terminology "fixed" means the setting can not be changed by the user. + return self.features.get('scatter-gather', True).get('fixed', True) + + def is_fixed_tso(self): + # in case of a missing configuration, rather return "fixed". In Ethtool + # terminology "fixed" means the setting can not be changed by the user. + return self.features.get('tcp-segmentation-offload', True).get('fixed', True) + + def is_fixed_ufo(self): + # in case of a missing configuration, rather return "fixed". In Ethtool + # terminology "fixed" means the setting can not be changed by the user. + return self.features.get('udp-fragmentation-offload', True).get('fixed', True) + + def get_rx_buffer(self): + # in case of a missing configuration rather return a "small" + # buffer of only 512 bytes. + return self.ring_buffers.get('rx', '512') + + def get_tx_buffer(self): + # in case of a missing configuration rather return a "small" + # buffer of only 512 bytes. + return self.ring_buffers.get('tx', '512') diff --git a/python/vyos/frr.py b/python/vyos/frr.py index 76e204ab3..69c7a14ce 100644 --- a/python/vyos/frr.py +++ b/python/vyos/frr.py @@ -69,8 +69,17 @@ import tempfile import re from vyos import util import logging +from logging.handlers import SysLogHandler +import os LOG = logging.getLogger(__name__) +DEBUG = os.path.exists('/tmp/vyos.frr.debug') +if DEBUG: + LOG.setLevel(logging.DEBUG) + ch = SysLogHandler(address='/dev/log') + ch2 = logging.StreamHandler() + LOG.addHandler(ch) + LOG.addHandler(ch2) _frr_daemons = ['zebra', 'bgpd', 'fabricd', 'isisd', 'ospf6d', 'ospfd', 'pbrd', 'pimd', 'ripd', 'ripngd', 'sharpd', 'staticd', 'vrrpd', 'ldpd'] @@ -175,15 +184,23 @@ def reload_configuration(config, daemon=None): f.write(config) f.flush() + LOG.debug(f'reload_configuration: Reloading config using temporary file: {f.name}') cmd = f'{path_frr_reload} --reload' if daemon: cmd += f' --daemon {daemon}' + + if DEBUG: + cmd += f' --debug --stdout' + cmd += f' {f.name}' + LOG.debug(f'reload_configuration: Executing command against frr-reload: "{cmd}"') output, code = util.popen(cmd, stderr=util.STDOUT) f.close() + for i, e in enumerate(output.split('\n')): + LOG.debug(f'frr-reload output: {i:3} {e}') if code == 1: - raise CommitError(f'Configuration FRR failed while commiting code: {repr(output)}') + raise CommitError(f'Configuration FRR failed while commiting code, please enabling debugging to examine logs') elif code: raise OSError(code, output) @@ -382,6 +399,11 @@ class FRRConfig: raise ValueError( 'The config element needs to be a string or list type object') + if config: + LOG.debug(f'__init__: frr library initiated with initial config') + for i, e in enumerate(self.config): + LOG.debug(f'__init__: initial {i:3} {e}') + def load_configuration(self, daemon=None): '''Load the running configuration from FRR into the config object daemon: str with name of the FRR Daemon to load configuration from or @@ -390,9 +412,16 @@ class FRRConfig: Using this overwrites the current loaded config objects and replaces the original loaded config ''' self.imported_config = get_configuration(daemon=daemon) - LOG.debug(f'load_configuration: Configuration loaded from FRR: {self.imported_config}') + if daemon: + LOG.debug(f'load_configuration: Configuration loaded from FRR daemon {daemon}') + else: + LOG.debug(f'load_configuration: Configuration loaded from FRR integrated config') + self.original_config = self.imported_config.split('\n') self.config = self.original_config.copy() + + for i, e in enumerate(self.imported_config.split('\n')): + LOG.debug(f'load_configuration: loaded {i:3} {e}') return def test_configuration(self): @@ -408,6 +437,8 @@ class FRRConfig: None to use the consolidated config ''' LOG.debug('commit_configuration: Commiting configuration') + for i, e in enumerate(self.config): + LOG.debug(f'commit_configuration: new_config {i:3} {e}') reload_configuration('\n'.join(self.config), daemon=daemon) def modify_section(self, start_pattern, replacement=[], stop_pattern=r'\S+', remove_stop_mark=False, count=0): diff --git a/python/vyos/ifconfig/__init__.py b/python/vyos/ifconfig/__init__.py index 9cd8d44c1..f7b55c9dd 100644 --- a/python/vyos/ifconfig/__init__.py +++ b/python/vyos/ifconfig/__init__.py @@ -39,6 +39,8 @@ from vyos.ifconfig.tunnel import IPIP6If from vyos.ifconfig.tunnel import IP6IP6If from vyos.ifconfig.tunnel import SitIf from vyos.ifconfig.tunnel import Sit6RDIf +from vyos.ifconfig.erspan import ERSpanIf +from vyos.ifconfig.erspan import ER6SpanIf from vyos.ifconfig.wireless import WiFiIf from vyos.ifconfig.l2tpv3 import L2TPv3If from vyos.ifconfig.macsec import MACsecIf diff --git a/python/vyos/ifconfig/erspan.py b/python/vyos/ifconfig/erspan.py new file mode 100755 index 000000000..50230e14a --- /dev/null +++ b/python/vyos/ifconfig/erspan.py @@ -0,0 +1,190 @@ +# Copyright 2019-2020 VyOS maintainers and contributors <maintainers@vyos.io> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see <http://www.gnu.org/licenses/>. + +# https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels/#erspan +# http://vger.kernel.org/lpc_net2018_talks/erspan-linux-presentation.pdf + +from copy import deepcopy + +from netaddr import EUI +from netaddr import mac_unix_expanded +from random import getrandbits + +from vyos.util import dict_search +from vyos.ifconfig.interface import Interface +from vyos.validate import assert_list + +@Interface.register +class _ERSpan(Interface): + """ + _ERSpan: private base class for ERSPAN tunnels + """ + default = { + **Interface.default, + **{ + 'type': 'erspan', + } + } + definition = { + **Interface.definition, + **{ + 'section': 'erspan', + 'prefixes': ['ersp',], + }, + } + + options = ['local_ip','remote_ip','encapsulation','parameters'] + + def __init__(self,ifname,**config): + self.config = deepcopy(config) if config else {} + super().__init__(ifname, **self.config) + + def change_options(self): + pass + + def update(self, config): + + # Enable/Disable of an interface must always be done at the end of the + # derived class to make use of the ref-counting set_admin_state() + # function. We will only enable the interface if 'up' was called as + # often as 'down'. This is required by some interface implementations + # as certain parameters can only be changed when the interface is + # in admin-down state. This ensures the link does not flap during + # reconfiguration. + super().update(config) + state = 'down' if 'disable' in config else 'up' + self.set_admin_state(state) + + def _create(self): + pass + +class ERSpanIf(_ERSpan): + """ + ERSpanIf: private base class for ERSPAN Over GRE and IPv4 tunnels + """ + + def _create(self): + ifname = self.config['ifname'] + local_ip = self.config['local_ip'] + remote_ip = self.config['remote_ip'] + key = self.config['parameters']['ip']['key'] + version = self.config['parameters']['version'] + command = f'ip link add dev {ifname} type erspan local {local_ip} remote {remote_ip} seq key {key} erspan_ver {version}' + + if int(version) == 1: + idx=dict_search('parameters.erspan.idx',self.config) + if idx: + command += f' erspan {idx}' + elif int(version) == 2: + direction=dict_search('parameters.erspan.direction',self.config) + if direction: + command += f' erspan_dir {direction}' + hwid=dict_search('parameters.erspan.hwid',self.config) + if hwid: + command += f' erspan_hwid {hwid}' + + ttl = dict_search('parameters.ip.ttl',self.config) + if ttl: + command += f' ttl {ttl}' + tos = dict_search('parameters.ip.tos',self.config) + if tos: + command += f' tos {tos}' + + self._cmd(command) + + def change_options(self): + ifname = self.config['ifname'] + local_ip = self.config['local_ip'] + remote_ip = self.config['remote_ip'] + key = self.config['parameters']['ip']['key'] + version = self.config['parameters']['version'] + command = f'ip link set dev {ifname} type erspan local {local_ip} remote {remote_ip} seq key {key} erspan_ver {version}' + + if int(version) == 1: + idx=dict_search('parameters.erspan.idx',self.config) + if idx: + command += f' erspan {idx}' + elif int(version) == 2: + direction=dict_search('parameters.erspan.direction',self.config) + if direction: + command += f' erspan_dir {direction}' + hwid=dict_search('parameters.erspan.hwid',self.config) + if hwid: + command += f' erspan_hwid {hwid}' + + ttl = dict_search('parameters.ip.ttl',self.config) + if ttl: + command += f' ttl {ttl}' + tos = dict_search('parameters.ip.tos',self.config) + if tos: + command += f' tos {tos}' + + self._cmd(command) + +class ER6SpanIf(_ERSpan): + """ + ER6SpanIf: private base class for ERSPAN Over GRE and IPv6 tunnels + """ + + def _create(self): + ifname = self.config['ifname'] + local_ip = self.config['local_ip'] + remote_ip = self.config['remote_ip'] + key = self.config['parameters']['ip']['key'] + version = self.config['parameters']['version'] + command = f'ip link add dev {ifname} type ip6erspan local {local_ip} remote {remote_ip} seq key {key} erspan_ver {version}' + + if int(version) == 1: + idx=dict_search('parameters.erspan.idx',self.config) + if idx: + command += f' erspan {idx}' + elif int(version) == 2: + direction=dict_search('parameters.erspan.direction',self.config) + if direction: + command += f' erspan_dir {direction}' + hwid=dict_search('parameters.erspan.hwid',self.config) + if hwid: + command += f' erspan_hwid {hwid}' + + ttl = dict_search('parameters.ip.ttl',self.config) + if ttl: + command += f' ttl {ttl}' + tos = dict_search('parameters.ip.tos',self.config) + if tos: + command += f' tos {tos}' + + self._cmd(command) + + def change_options(self): + ifname = self.config['ifname'] + local_ip = self.config['local_ip'] + remote_ip = self.config['remote_ip'] + key = self.config['parameters']['ip']['key'] + version = self.config['parameters']['version'] + command = f'ip link set dev {ifname} type ip6erspan local {local_ip} remote {remote_ip} seq key {key} erspan_ver {version}' + + if int(version) == 1: + idx=dict_search('parameters.erspan.idx',self.config) + if idx: + command += f' erspan {idx}' + elif int(version) == 2: + direction=dict_search('parameters.erspan.direction',self.config) + if direction: + command += f' erspan_dir {direction}' + hwid=dict_search('parameters.erspan.hwid',self.config) + if hwid: + command += f' erspan_hwid {hwid}' + + self._cmd(command) diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 3b92ce463..4bdabd432 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -923,12 +923,12 @@ class Interface(Control): else: add_vlan.append(vlan) allowed_vlan_ids.append(vlan) - + # Remove redundant VLANs from the system for vlan in list_diff(cur_vlan_ids, add_vlan): cmd = f'bridge vlan del dev {ifname} vid {vlan} master' self._cmd(cmd) - + for vlan in allowed_vlan_ids: cmd = f'bridge vlan add dev {ifname} vid {vlan} master' self._cmd(cmd) @@ -1015,9 +1015,11 @@ class Interface(Control): source_if = next(iter(self._config['is_mirror_intf'])) config = self._config['is_mirror_intf'][source_if].get('mirror', None) + # Please do not clear the 'set $? = 0 '. It's meant to force a return of 0 # Remove existing mirroring rules - delete_tc_cmd = f'tc qdisc del dev {source_if} handle ffff: ingress; ' - delete_tc_cmd += f'tc qdisc del dev {source_if} handle 1: root prio' + delete_tc_cmd = f'tc qdisc del dev {source_if} handle ffff: ingress 2> /dev/null;' + delete_tc_cmd += f'tc qdisc del dev {source_if} handle 1: root prio 2> /dev/null;' + delete_tc_cmd += 'set $?=0' self._popen(delete_tc_cmd) # Bail out early if nothing needs to be configured @@ -1072,6 +1074,10 @@ class Interface(Control): interface setup code and provide a single point of entry when workin on any interface. """ + if self.debug: + import pprint + pprint.pprint(config) + # Cache the configuration - it will be reused inside e.g. DHCP handler # XXX: maybe pass the option via __init__ in the future and rename this # method to apply()? @@ -1102,9 +1108,10 @@ class Interface(Control): self.del_addr('dhcp') # always ensure DHCPv6 client is stopped (when not configured as client - # for IPv6 address or prefix delegation + # for IPv6 address or prefix delegation) dhcpv6pd = dict_search('dhcpv6_options.pd', config) - if 'dhcpv6' not in new_addr or dhcpv6pd == None: + dhcpv6pd = dhcpv6pd != None and len(dhcpv6pd) != 0 + if 'dhcpv6' not in new_addr and not dhcpv6pd: self.del_addr('dhcpv6') # determine IP addresses which are assigned to the interface and build a @@ -1124,7 +1131,7 @@ class Interface(Control): self.add_addr(addr) # start DHCPv6 client when only PD was configured - if dhcpv6pd != None: + if dhcpv6pd: self.set_dhcpv6(True) # There are some items in the configuration which can only be applied diff --git a/smoketest/configs/bgp-bfd-communities b/smoketest/configs/bgp-bfd-communities new file mode 100644 index 000000000..3b3056a51 --- /dev/null +++ b/smoketest/configs/bgp-bfd-communities @@ -0,0 +1,533 @@ +interfaces { + ethernet eth0 { + address 192.0.2.100/25 + address 2001:db8::ffff/64 + } + loopback lo { + } +} +policy { + large-community-list ANYCAST_ALL { + rule 10 { + action permit + description "Allow all anycast from anywhere" + regex "4242420696:100:.*" + } + } + large-community-list ANYCAST_INT { + rule 10 { + action permit + description "Allow all anycast from int" + regex 4242420696:100:1 + } + } + prefix-list BGP-BACKBONE-IN { + description "Inbound backbone routes from other sites" + rule 10 { + action deny + description "Block default route" + prefix 0.0.0.0/0 + } + rule 20 { + action deny + description "Block int primary" + ge 21 + prefix 192.168.0.0/20 + } + rule 30 { + action deny + description "Block loopbacks" + ge 25 + prefix 192.168.253.0/24 + } + rule 40 { + action deny + description "Block backbone peering" + ge 25 + prefix 192.168.254.0/24 + } + rule 999 { + action permit + description "Allow everything else" + ge 1 + prefix 0.0.0.0/0 + } + } + prefix-list BGP-BACKBONE-OUT { + description "Outbound backbone routes to other sites" + rule 10 { + action permit + description "Int primary" + ge 23 + prefix 192.168.0.0/20 + } + } + prefix-list GLOBAL { + description "Globally redistributed routes" + rule 10 { + action permit + prefix 192.168.100.1/32 + } + rule 20 { + action permit + prefix 192.168.7.128/25 + } + } + prefix-list6 BGP-BACKBONE-IN-V6 { + description "Inbound backbone routes from other sites" + rule 10 { + action deny + description "Block default route" + prefix ::/0 + } + rule 20 { + action deny + description "Block int primary" + ge 53 + prefix fd52:d62e:8011::/52 + } + rule 30 { + action deny + description "Block peering and stuff" + ge 53 + prefix fd52:d62e:8011:f000::/52 + } + rule 999 { + action permit + description "Allow everything else" + ge 1 + prefix ::/0 + } + } + prefix-list6 BGP-BACKBONE-OUT-V6 { + description "Outbound backbone routes to other sites" + rule 10 { + action permit + ge 64 + prefix fd52:d62e:8011::/52 + } + } + prefix-list6 GLOBAL-V6 { + description "Globally redistributed routes" + rule 10 { + action permit + ge 64 + prefix fd52:d62e:8011:2::/63 + } + } + route-map BGP-REDISTRIBUTE { + rule 10 { + action permit + description "Prepend AS and allow VPN and modem" + match { + ip { + address { + prefix-list GLOBAL + } + } + } + set { + as-path-prepend 4242420666 + } + } + rule 20 { + action permit + description "Allow VPN" + match { + ipv6 { + address { + prefix-list GLOBAL-V6 + } + } + } + } + } + route-map BGP-BACKBONE-IN { + rule 10 { + action permit + match { + ip { + address { + prefix-list BGP-BACKBONE-IN + } + } + } + } + rule 20 { + action permit + match { + ipv6 { + address { + prefix-list BGP-BACKBONE-IN-V6 + } + } + } + } + rule 30 { + action permit + match { + large-community { + large-community-list ANYCAST_ALL + } + } + } + } + route-map BGP-BACKBONE-OUT { + rule 10 { + action permit + match { + ip { + address { + prefix-list BGP-BACKBONE-OUT + } + } + } + } + rule 20 { + action permit + match { + ipv6 { + address { + prefix-list BGP-BACKBONE-OUT-V6 + } + } + } + } + rule 30 { + action permit + match { + large-community { + large-community-list ANYCAST_INT + } + } + set { + as-path-prepend 4242420666 + } + } + } +} +protocols { + bfd { + peer 192.168.253.1 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address 192.168.253.3 + } + } + peer 192.168.253.2 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address 192.168.253.3 + } + } + peer 192.168.253.6 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address 192.168.253.3 + } + } + peer 192.168.253.7 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address 192.168.253.3 + } + } + peer 192.168.253.12 { + interval { + receive 100 + transmit 100 + } + multihop + source { + address 192.168.253.3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:1 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:2 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:6 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:7 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:12 { + interval { + receive 100 + transmit 100 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + } + bgp 4242420666 { + address-family { + ipv4-unicast { + redistribute { + connected { + route-map BGP-REDISTRIBUTE + } + static { + route-map BGP-REDISTRIBUTE + } + } + } + ipv6-unicast { + redistribute { + connected { + route-map BGP-REDISTRIBUTE + } + } + } + } + neighbor 192.168.253.1 { + peer-group INT + } + neighbor 192.168.253.2 { + peer-group INT + } + neighbor 192.168.253.6 { + peer-group DAL13 + } + neighbor 192.168.253.7 { + peer-group DAL13 + } + neighbor 192.168.253.12 { + address-family { + ipv4-unicast { + route-map { + export BGP-BACKBONE-OUT + import BGP-BACKBONE-IN + } + soft-reconfiguration { + inbound + } + } + } + bfd { + } + ebgp-multihop 2 + remote-as 4242420669 + update-source dum0 + } + neighbor fd52:d62e:8011:fffe:192:168:253:1 { + address-family { + ipv6-unicast { + peer-group INTv6 + } + } + } + neighbor fd52:d62e:8011:fffe:192:168:253:2 { + address-family { + ipv6-unicast { + peer-group INTv6 + } + } + } + neighbor fd52:d62e:8011:fffe:192:168:253:6 { + address-family { + ipv6-unicast { + peer-group DAL13v6 + } + } + } + neighbor fd52:d62e:8011:fffe:192:168:253:7 { + address-family { + ipv6-unicast { + peer-group DAL13v6 + } + } + } + neighbor fd52:d62e:8011:fffe:192:168:253:12 { + address-family { + ipv6-unicast { + route-map { + export BGP-BACKBONE-OUT + import BGP-BACKBONE-IN + } + soft-reconfiguration { + inbound + } + } + } + bfd { + } + ebgp-multihop 2 + remote-as 4242420669 + update-source dum0 + } + parameters { + confederation { + identifier 4242420696 + peers 4242420668 + peers 4242420669 + } + default { + no-ipv4-unicast + } + distance { + global { + external 220 + internal 220 + local 220 + } + } + graceful-restart { + } + } + peer-group DAL13 { + address-family { + ipv4-unicast { + route-map { + export BGP-BACKBONE-OUT + import BGP-BACKBONE-IN + } + soft-reconfiguration { + inbound + } + } + } + bfd + ebgp-multihop 2 + remote-as 4242420668 + update-source dum0 + } + peer-group DAL13v6 { + address-family { + ipv6-unicast { + route-map { + export BGP-BACKBONE-OUT + import BGP-BACKBONE-IN + } + soft-reconfiguration { + inbound + } + } + } + bfd + ebgp-multihop 2 + remote-as 4242420668 + update-source dum0 + } + peer-group INT { + address-family { + ipv4-unicast { + default-originate { + } + soft-reconfiguration { + inbound + } + } + } + bfd + remote-as 4242420666 + update-source dum0 + } + peer-group INTv6 { + address-family { + ipv6-unicast { + default-originate { + } + soft-reconfiguration { + inbound + } + } + } + bfd + remote-as 4242420666 + update-source dum0 + } + } +} +system { + config-management { + commit-revisions 200 + } + console { + device ttyS0 { + speed 115200 + } + } + host-name vyos + login { + user vyos { + authentication { + encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/ + plaintext-password "" + } + level admin + } + } + ntp { + server 0.pool.ntp.org { + } + server 1.pool.ntp.org { + } + server 2.pool.ntp.org { + } + } + syslog { + global { + facility all { + level info + } + facility protocols { + level debug + } + } + } + time-zone Europe/Berlin +} + +/* Warning: Do not remove the following line. */ +/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@10:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */ +/* Release version: 1.2.6-S1 */ diff --git a/smoketest/configs/bgp-big-as-cloud b/smoketest/configs/bgp-big-as-cloud new file mode 100644 index 000000000..df3ae015c --- /dev/null +++ b/smoketest/configs/bgp-big-as-cloud @@ -0,0 +1,1952 @@ +firewall { + all-ping enable + broadcast-ping disable + config-trap disable + group { + address-group bgp-peers-4 { + address 192.0.68.3 + address 192.0.68.2 + address 192.0.176.193 + address 192.0.52.0-192.0.52.255 + address 192.0.53.0-192.0.53.255 + address 192.0.16.209 + address 192.0.192.0-192.0.192.255 + address 192.0.193.0-192.0.193.255 + address 192.0.194.0-192.0.194.255 + address 192.0.195.0-192.0.195.255 + address 192.0.196.0-192.0.196.255 + address 192.0.197.0-192.0.197.255 + address 192.0.198.0-192.0.198.255 + address 192.0.199.0-192.0.199.255 + } + address-group vrrp-peers-4 { + address 192.0.68.3 + address 192.0.160.3 + address 192.0.98.3 + address 192.0.71.131 + address 192.0.84.67 + address 192.0.71.195 + address 192.0.71.115 + address 192.0.70.195 + address 192.0.70.179 + address 192.0.70.163 + address 192.0.70.147 + address 192.0.70.131 + address 192.0.70.19 + address 192.0.70.3 + address 192.0.71.99 + address 192.0.68.67 + address 192.0.71.67 + address 192.0.71.3 + address 192.0.68.35 + address 192.0.68.131 + address 192.0.69.2 + address 192.0.70.35 + address 192.0.70.67 + } + ipv6-address-group bgp-peers-6 { + address 2001:db8:c::3 + address 2001:db8:1000::2e9 + address 2001:db8:24::fb + address 2001:db8:24::fc + address 2001:db8:24::fd + address 2001:db8:24::2e + address 2001:db8:24::3d + address 2001:db8:24::4a + address 2001:db8:24::5e + address 2001:db8:24::7 + address 2001:db8:24::11 + address 2001:db8:24::18 + address 2001:db8:24::20 + address 2001:db8:24::22 + address 2001:db8:24::31 + address 2001:db8:24::58 + address 2001:db8:24::64 + address 2001:db8:24::a5 + address 2001:db8:24::aa + address 2001:db8:24::ab + address 2001:db8:24::b0 + address 2001:db8:24::b3 + address 2001:db8:24::bd + address 2001:db8:24::c + address 2001:db8:24::d2 + address 2001:db8:24::d3 + address 2001:db8:838::1 + address 2001:db8::1a27:5051:c09d + address 2001:db8::1a27:5051:c19d + address 2001:db8::20ad:0:1 + address 2001:db8::2306:0:1 + address 2001:db8::2ca:0:1 + address 2001:db8::2ca:0:2 + address 2001:db8::2ca:0:3 + address 2001:db8::2ca:0:4 + } + ipv6-address-group vrrp-peers-6 { + address fe80::fe89:15cf + } + ipv6-network-group AS64512-6 { + network 2001::/29 + } + network-group AS64512-4 { + network 192.0.68.0/22 + network 192.0.98.0/24 + network 192.0.160.0/24 + network 192.0.84.0/22 + } + } + ipv6-name management-to-local-6 { + default-action reject + enable-default-log + } + ipv6-name management-to-peers-6 { + default-action reject + enable-default-log + } + ipv6-name management-to-servers-6 { + default-action reject + enable-default-log + } + ipv6-name peers-to-local-6 { + default-action reject + enable-default-log + rule 500 { + action accept + protocol icmpv6 + } + rule 501 { + action accept + protocol vrrp + source { + group { + address-group vrrp-peers-6 + } + } + } + rule 502 { + action accept + destination { + port bgp + } + protocol tcp + source { + group { + address-group bgp-peers-6 + } + } + } + rule 503 { + action accept + protocol tcp + source { + group { + address-group bgp-peers-6 + } + port bgp + } + } + } + ipv6-name peers-to-management-6 { + default-action reject + enable-default-log + } + ipv6-name peers-to-servers-6 { + default-action reject + enable-default-log + rule 9990 { + action reject + source { + group { + network-group AS64512-6 + } + } + } + rule 9999 { + action accept + destination { + group { + network-group AS64512-6 + } + } + } + } + ipv6-name servers-to-local-6 { + default-action reject + enable-default-log + rule 500 { + action accept + protocol icmpv6 + } + rule 501 { + action accept + protocol vrrp + source { + group { + address-group vrrp-peers-6 + } + } + } + rule 511 { + action accept + protocol tcp_udp + source { + port 53 + } + } + } + ipv6-name servers-to-management-6 { + default-action reject + enable-default-log + } + ipv6-name servers-to-peers-6 { + default-action reject + enable-default-log + rule 51 { + action accept + source { + group { + network-group AS64512-6 + } + } + } + } + ipv6-receive-redirects disable + ipv6-src-route disable + ip-src-route disable + log-martians enable + name management-to-local-4 { + default-action reject + enable-default-log + rule 500 { + action accept + protocol icmp + } + rule 501 { + action accept + destination { + port 22 + } + protocol tcp + } + rule 502 { + action accept + destination { + port snmp + } + protocol udp + } + } + name management-to-peers-4 { + default-action reject + enable-default-log + } + name management-to-servers-4 { + default-action reject + enable-default-log + } + name peers-to-local-4 { + default-action reject + enable-default-log + rule 500 { + action accept + protocol icmp + } + rule 501 { + action accept + protocol vrrp + source { + group { + address-group vrrp-peers-4 + } + } + } + rule 502 { + action accept + destination { + port bgp + } + protocol tcp + source { + group { + address-group bgp-peers-4 + } + } + } + rule 503 { + action accept + protocol tcp + source { + group { + address-group bgp-peers-4 + } + port bgp + } + } + } + name peers-to-management-4 { + default-action reject + enable-default-log + } + name peers-to-servers-4 { + default-action reject + enable-default-log + rule 9990 { + action reject + source { + group { + network-group AS64512-4 + } + } + } + rule 9999 { + action accept + destination { + group { + network-group AS64512-4 + } + } + } + } + name servers-to-local-4 { + default-action reject + enable-default-log + rule 500 { + action accept + protocol icmp + } + rule 501 { + action accept + protocol vrrp + source { + group { + address-group vrrp-peers-4 + } + } + } + rule 511 { + action accept + protocol tcp_udp + source { + port 53 + } + } + } + name servers-to-management-4 { + default-action reject + enable-default-log + } + name servers-to-peers-4 { + default-action reject + enable-default-log + rule 51 { + action accept + source { + group { + network-group AS64512-4 + } + } + } + } + receive-redirects disable + send-redirects enable + source-validation disable + syn-cookies enable + twa-hazards-protection disable +} +high-availability { + vrrp { + group 11-4 { + interface eth0.11 + priority 200 + virtual-address 192.0.68.1/27 + vrid 4 + } + group 11-6 { + interface eth0.11 + priority 200 + virtual-address 2001:db8:c::1/64 + vrid 6 + } + group 102-4 { + interface eth0.102 + priority 200 + virtual-address 192.0.98.1/24 + vrid 4 + } + group 102-6 { + interface eth0.102 + priority 200 + virtual-address 2001:db8:0:102::1/64 + vrid 6 + } + group 105-4 { + interface eth0.105 + priority 200 + virtual-address 192.0.160.1/24 + vrid 4 + } + group 105-6 { + interface eth0.105 + priority 200 + virtual-address 2001:db8:0:105::1/64 + vrid 6 + } + group 1001-4 { + interface eth0.1001 + priority 200 + virtual-address 192.0.68.33/27 + vrid 4 + } + group 1001-6 { + interface eth0.1001 + priority 200 + virtual-address 2001:db8:0:1001::1/64 + vrid 6 + } + group 1002-4 { + interface eth0.1002 + priority 200 + virtual-address 192.0.68.65/26 + vrid 4 + } + group 1002-6 { + interface eth0.1002 + priority 200 + virtual-address 2001:db8:0:1002::1/64 + vrid 6 + } + group 1003-4 { + interface eth0.1003 + priority 200 + virtual-address 192.0.68.129/25 + vrid 4 + } + group 1003-6 { + interface eth0.1003 + priority 200 + virtual-address 2001:db8:0:1003::1/64 + vrid 6 + } + group 1004-4 { + interface eth0.1004 + priority 200 + virtual-address 192.0.69.1/24 + vrid 4 + } + group 1004-6 { + interface eth0.1004 + priority 200 + virtual-address 2001:db8:0:1004::1/64 + vrid 6 + } + group 1005-4 { + interface eth0.1005 + priority 200 + virtual-address 192.0.70.1/28 + vrid 4 + } + group 1005-6 { + interface eth0.1005 + priority 200 + virtual-address 2001:db8:0:1005::1/64 + vrid 6 + } + group 1006-4 { + interface eth0.1006 + priority 200 + virtual-address 192.0.70.17/28 + vrid 4 + } + group 1006-6 { + interface eth0.1006 + priority 200 + virtual-address 2001:db8:0:1006::1/64 + vrid 6 + } + group 1007-4 { + interface eth0.1007 + priority 200 + virtual-address 192.0.70.33/27 + vrid 4 + } + group 1007-6 { + interface eth0.1007 + priority 200 + virtual-address 2001:db8:0:1007::1/64 + vrid 6 + } + group 1008-4 { + interface eth0.1008 + priority 200 + virtual-address 192.0.70.65/26 + vrid 4 + } + group 1008-6 { + interface eth0.1008 + priority 200 + virtual-address 2001:db8:0:1008::1/64 + vrid 6 + } + group 1009-4 { + interface eth0.1009 + priority 200 + virtual-address 192.0.70.129/28 + vrid 4 + } + group 1009-6 { + interface eth0.1009 + priority 200 + virtual-address 2001:db8:0:1009::1/64 + vrid 6 + } + group 1010-4 { + interface eth0.1010 + priority 200 + virtual-address 192.0.70.145/28 + vrid 4 + } + group 1010-6 { + interface eth0.1010 + priority 200 + virtual-address 2001:db8:0:1010::1/64 + vrid 6 + } + group 1011-4 { + interface eth0.1011 + priority 200 + virtual-address 192.0.70.161/28 + vrid 4 + } + group 1011-6 { + interface eth0.1011 + priority 200 + virtual-address 2001:db8:0:1011::1/64 + vrid 6 + } + group 1012-4 { + interface eth0.1012 + priority 200 + virtual-address 192.0.70.177/28 + vrid 4 + } + group 1012-6 { + interface eth0.1012 + priority 200 + virtual-address 2001:db8:0:1012::1/64 + vrid 6 + } + group 1013-4 { + interface eth0.1013 + priority 200 + virtual-address 192.0.70.193/27 + vrid 4 + } + group 1013-6 { + interface eth0.1013 + priority 200 + virtual-address 2001:db8:0:1013::1/64 + vrid 6 + } + group 1014-4 { + interface eth0.1014 + priority 200 + virtual-address 192.0.84.65/26 + vrid 4 + } + group 1014-6 { + interface eth0.1014 + priority 200 + virtual-address 2001:db8:0:1014::1/64 + vrid 6 + } + group 1015-4 { + interface eth0.1015 + priority 200 + virtual-address 192.0.71.1/26 + vrid 4 + } + group 1015-6 { + interface eth0.1015 + priority 200 + virtual-address 2001:db8:0:1015::1/64 + vrid 6 + } + group 1016-4 { + interface eth0.1016 + priority 200 + virtual-address 192.0.71.65/27 + vrid 4 + } + group 1016-6 { + interface eth0.1016 + priority 200 + virtual-address 2001:db8:0:1016::1/64 + vrid 6 + } + group 1017-4 { + interface eth0.1017 + priority 200 + virtual-address 192.0.71.97/28 + vrid 4 + } + group 1017-6 { + interface eth0.1017 + priority 200 + virtual-address 2001:db8:0:1017::1/64 + vrid 6 + } + group 1018-4 { + interface eth0.1018 + priority 200 + virtual-address 192.0.71.113/28 + vrid 4 + } + group 1018-6 { + interface eth0.1018 + priority 200 + virtual-address 2001:db8:0:1018::1/64 + vrid 6 + } + group 1019-4 { + interface eth0.1019 + priority 200 + virtual-address 192.0.71.129/26 + vrid 4 + } + group 1019-6 { + interface eth0.1019 + priority 200 + virtual-address 2001:db8:0:1019::1/64 + vrid 6 + } + group 1020-4 { + interface eth0.1020 + priority 200 + virtual-address 192.0.71.193/26 + vrid 4 + } + group 1020-6 { + interface eth0.1020 + priority 200 + virtual-address 2001:db8:0:1020::1/64 + vrid 6 + } + } +} +interfaces { + ethernet eth0 { + address 192.0.0.11/16 + duplex auto + smp-affinity auto + speed auto + vif 11 { + address 192.0.68.2/27 + address 2001:db8:c::2/64 + } + vif 102 { + address 192.0.98.2/24 + address 2001:db8:0:102::2/64 + } + vif 105 { + address 192.0.160.2/24 + address 2001:db8:0:105::2/64 + } + vif 838 { + address 192.0.16.210/30 + address 2001:db8:838::2/64 + } + vif 886 { + address 192.0.193.224/21 + address 2001:db8::3:669:0:1/64 + } + vif 1001 { + address 192.0.68.34/27 + address 2001:db8:0:1001::2/64 + } + vif 1002 { + address 192.0.68.66/26 + address 2001:db8:0:1002::2/64 + } + vif 1003 { + address 192.0.68.130/25 + address 2001:db8:0:1003::2/64 + } + vif 1004 { + address 192.0.69.2/24 + address 2001:db8:0:1004::2/64 + } + vif 1005 { + address 192.0.70.2/28 + address 2001:db8:0:1005::2/64 + } + vif 1006 { + address 192.0.70.18/28 + address 2001:db8:0:1006::2/64 + } + vif 1007 { + address 192.0.70.34/27 + address 2001:db8:0:1007::2/64 + } + vif 1008 { + address 192.0.70.66/26 + address 2001:db8:0:1008::2/64 + } + vif 1009 { + address 192.0.70.130/28 + address 2001:db8:0:1009::2/64 + } + vif 1010 { + address 192.0.70.146/28 + address 2001:db8:0:1010::2/64 + } + vif 1011 { + address 192.0.70.162/28 + address 2001:db8:0:1011::2/64 + } + vif 1012 { + address 192.0.70.178/28 + address 2001:db8:0:1012::2/64 + } + vif 1013 { + address 192.0.70.194/27 + address 2001:db8:0:1013::3/64 + } + vif 1014 { + address 192.0.84.66/26 + address 2001:db8:0:1014::2/64 + } + vif 1015 { + address 192.0.71.2/26 + address 2001:db8:0:1015::2/64 + } + vif 1016 { + address 192.0.71.66/27 + address 2001:db8:0:1016::2/64 + } + vif 1017 { + address 192.0.71.98/28 + address 2001:db8:0:1017::2/64 + } + vif 1018 { + address 192.0.71.114/28 + address 2001:db8:0:1018::2/64 + } + vif 1019 { + address 192.0.71.130/26 + address 2001:db8:0:1019::2/64 + } + vif 1020 { + address 192.0.71.194/26 + address 2001:db8:0:1020::2/64 + } + vif 4088 { + address 2001:db8:24::c7/64 + address 192.0.52.199/23 + } + vif 4089 { + address 192.0.176.194/30 + address 2001:db8:1000::2ea/126 + } + } + loopback lo { + } +} +policy { + as-path-list AS64513-AS64514 { + rule 10 { + action permit + regex "^64513 64514$" + } + } + as-path-list AS64512 { + rule 10 { + action permit + regex ^$ + } + } + prefix-list defaultV4 { + rule 10 { + action permit + prefix 0.0.0.0/0 + } + } + prefix-list hostrouteV4 { + rule 10 { + action permit + ge 32 + prefix 192.0.160.0/24 + } + rule 20 { + action permit + ge 32 + prefix 192.0.98.0/24 + } + rule 30 { + action permit + ge 32 + prefix 192.0.68.0/22 + } + rule 40 { + action permit + ge 32 + prefix 192.0.84.0/22 + } + } + prefix-list vyosV4 { + rule 10 { + action permit + prefix 192.0.160.0/24 + } + rule 20 { + action permit + prefix 192.0.98.0/24 + } + rule 30 { + action permit + prefix 192.0.68.0/22 + } + rule 40 { + action permit + prefix 192.0.84.0/22 + } + } + prefix-list privateV4 { + rule 10 { + action permit + le 32 + prefix 192.0.0.0/8 + } + rule 20 { + action permit + le 32 + prefix 192.0.0.0/12 + } + rule 30 { + action permit + le 32 + prefix 192.0.0.0/16 + } + } + prefix-list6 all6 { + rule 10 { + action permit + ge 4 + prefix 2000::/3 + } + } + prefix-list6 hostrouteV6 { + rule 20 { + action permit + ge 128 + prefix 2001:db8::/29 + } + } + prefix-list6 vyosV6 { + rule 20 { + action permit + prefix 2001:db8::/29 + } + } + prefix-list6 privateV6 { + rule 10 { + action permit + prefix fc00::/7 + } + } + route-map ExportRouteMap { + rule 5 { + action permit + match { + as-path AS64512 + ip { + address { + prefix-list hostrouteV4 + } + } + } + set { + community 65000:666 + } + } + rule 10 { + action permit + match { + as-path AS64512 + ip { + address { + prefix-list vyosV4 + } + } + } + } + rule 15 { + action permit + match { + as-path AS64512 + ipv6 { + address { + prefix-list hostrouteV6 + } + } + } + set { + community 65000:666 + } + } + rule 20 { + action permit + match { + as-path AS64512 + ipv6 { + address { + prefix-list vyosV6 + } + } + } + } + rule 100 { + action deny + } + } + route-map ExportRouteMapAS64515 { + rule 10 { + action permit + match { + ipv6 { + address { + prefix-list all6 + } + } + } + } + rule 20 { + action deny + match { + ip { + address { + prefix-list defaultV4 + } + } + } + } + rule 100 { + action deny + } + } + route-map ExportRouteMapAS64516 { + rule 5 { + action permit + match { + as-path AS64512 + ip { + address { + prefix-list hostrouteV4 + } + } + } + set { + community 65000:666 + } + } + rule 10 { + action permit + match { + as-path AS64512 + ip { + address { + prefix-list vyosV4 + } + } + } + } + rule 15 { + action permit + match { + as-path AS64512 + ipv6 { + address { + prefix-list hostrouteV6 + } + } + } + set { + community 65000:666 + } + } + rule 20 { + action permit + match { + as-path AS64512 + ipv6 { + address { + prefix-list vyosV6 + } + } + } + } + rule 100 { + action deny + } + } + route-map ExportRouteMapAS64517 { + rule 5 { + action permit + match { + as-path AS64512 + ip { + address { + prefix-list hostrouteV4 + } + } + } + set { + community 64517:666 + } + } + rule 10 { + action permit + match { + as-path AS64512 + ip { + address { + prefix-list vyosV4 + } + } + } + } + rule 15 { + action permit + match { + as-path AS64512 + ipv6 { + address { + prefix-list hostrouteV6 + } + } + } + set { + community 64517:666 + } + } + rule 20 { + action permit + match { + as-path AS64512 + ipv6 { + address { + prefix-list vyosV6 + } + } + } + } + rule 100 { + action deny + } + } + route-map ExportRouteMapAS64513 { + rule 5 { + action permit + match { + as-path AS64512 + ip { + address { + prefix-list hostrouteV4 + } + } + } + set { + community 64513:666 + } + } + rule 10 { + action permit + match { + as-path AS64512 + ip { + address { + prefix-list vyosV4 + } + } + } + } + rule 15 { + action permit + match { + as-path AS64512 + ipv6 { + address { + prefix-list hostrouteV6 + } + } + } + set { + community 64513:666 + } + } + rule 20 { + action permit + match { + as-path AS64512 + ipv6 { + address { + prefix-list vyosV6 + } + } + } + } + rule 100 { + action deny + } + } + route-map ImportRouteMap { + rule 10 { + action deny + match { + ip { + address { + prefix-list privateV4 + } + } + } + } + rule 15 { + action deny + match { + ipv6 { + address { + prefix-list privateV6 + } + } + } + } + rule 20 { + action deny + match { + ip { + address { + prefix-list vyosV4 + } + } + } + } + rule 30 { + action deny + match { + ipv6 { + address { + prefix-list vyosV6 + } + } + } + } + rule 40 { + action deny + match { + as-path AS64512 + } + } + rule 50 { + action permit + match { + as-path AS64513-AS64514 + } + set { + weight 10001 + } + } + rule 65535 { + action permit + } + } +} +protocols { + bgp 64500 { + address-family { + ipv4-unicast { + network 192.0.98.0/24 { + } + network 192.0.160.0/24 { + } + network 192.0.68.0/22 { + } + network 192.0.84.0/22 { + } + redistribute { + static { + route-map ExportRouteMap + } + } + } + ipv6-unicast { + network 2001:db8::/29 { + } + redistribute { + static { + route-map ExportRouteMap + } + } + } + } + neighbor 192.0.16.209 { + address-family { + ipv4-unicast { + route-map { + export ExportRouteMapAS64516 + import ImportRouteMap + } + } + } + remote-as 64501 + } + neighbor 192.0.192.6 { + address-family { + ipv4-unicast { + maximum-prefix 100 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64502 + } + neighbor 192.0.192.157 { + address-family { + ipv4-unicast { + maximum-prefix 350000 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64503 + } + neighbor 192.0.192.228 { + address-family { + ipv4-unicast { + maximum-prefix 10000 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64504 + } + neighbor 192.0.193.157 { + address-family { + ipv4-unicast { + maximum-prefix 350000 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64505 + } + neighbor 192.0.193.202 { + address-family { + ipv4-unicast { + maximum-prefix 10000 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64506 + } + neighbor 192.0.193.223 { + address-family { + ipv4-unicast { + maximum-prefix 10000 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64507 + } + neighbor 192.0.194.161 { + address-family { + ipv4-unicast { + maximum-prefix 10000 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64508 + } + neighbor 192.0.194.171 { + address-family { + ipv4-unicast { + maximum-prefix 10000 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64509 + } + neighbor 192.0.176.193 { + address-family { + ipv4-unicast { + route-map { + export ExportRouteMapAS64516 + import ImportRouteMap + } + } + } + remote-as 64510 + } + neighbor 192.0.52.12 { + address-family { + ipv4-unicast { + maximum-prefix 300 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64511 + } + neighbor 192.0.52.17 { + address-family { + ipv4-unicast { + maximum-prefix 75 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + password vyosvyos + remote-as 64512 + } + neighbor 192.0.52.24 { + address-family { + ipv4-unicast { + maximum-prefix 300 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64513 + } + neighbor 192.0.52.32 { + address-family { + ipv4-unicast { + maximum-prefix 50 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + password vyosfoooo + remote-as 64514 + } + neighbor 192.0.52.34 { + address-family { + ipv4-unicast { + maximum-prefix 10 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64515 + } + neighbor 192.0.52.46 { + address-family { + ipv4-unicast { + maximum-prefix 10 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64516 + } + neighbor 192.0.52.49 { + address-family { + ipv4-unicast { + maximum-prefix 75 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + password secret + remote-as 64517 + } + neighbor 192.0.52.74 { + address-family { + ipv4-unicast { + maximum-prefix 15000 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + password secretvyos + remote-as 64518 + } + neighbor 192.0.52.94 { + address-family { + ipv4-unicast { + maximum-prefix 250 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64519 + } + neighbor 192.0.52.100 { + address-family { + ipv4-unicast { + maximum-prefix 50 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64520 + } + neighbor 192.0.52.119 { + address-family { + ipv4-unicast { + maximum-prefix 30 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64521 + } + neighbor 192.0.52.165 { + address-family { + ipv4-unicast { + maximum-prefix 50 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64522 + } + neighbor 192.0.52.170 { + address-family { + ipv4-unicast { + maximum-prefix 150000 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64523 + } + neighbor 192.0.52.171 { + address-family { + ipv4-unicast { + maximum-prefix 10000 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64524 + } + neighbor 192.0.52.179 { + address-family { + ipv4-unicast { + maximum-prefix 20 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64525 + } + neighbor 192.0.52.189 { + address-family { + ipv4-unicast { + maximum-prefix 1000 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64526 + } + neighbor 192.0.52.210 { + address-family { + ipv4-unicast { + maximum-prefix 15 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64527 + } + neighbor 192.0.52.211 { + address-family { + ipv4-unicast { + maximum-prefix 15 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64528 + } + neighbor 192.0.52.251 { + address-family { + ipv4-unicast { + route-map { + export ExportRouteMap + import ImportRouteMap + } + weight 1010 + } + } + remote-as 64529 + } + neighbor 192.0.52.252 { + address-family { + ipv4-unicast { + route-map { + export ExportRouteMap + } + weight 1010 + } + } + remote-as 64530 + } + neighbor 192.0.52.253 { + address-family { + ipv4-unicast { + route-map { + export ExportRouteMapAS64515 + import ImportRouteMap + } + } + } + passive + remote-as 64531 + } + neighbor 192.0.68.3 { + address-family { + ipv4-unicast { + nexthop-self + soft-reconfiguration { + inbound + } + } + } + remote-as 64532 + update-source 192.0.68.2 + } + neighbor 2001:db8:838::1 { + address-family { + ipv6-unicast { + route-map { + export ExportRouteMapAS64516 + import ImportRouteMap + } + } + } + remote-as 64533 + } + neighbor 2001:db8:c::3 { + address-family { + ipv6-unicast { + nexthop-self + soft-reconfiguration { + inbound + } + } + } + remote-as 64534 + update-source 2001:db8:c::2 + } + neighbor 2001:db8:24::2e { + address-family { + ipv6-unicast { + maximum-prefix 5 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + password vyossecret + remote-as 64535 + } + neighbor 2001:db8:24::4a { + address-family { + ipv6-unicast { + maximum-prefix 1000 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64536 + } + neighbor 2001:db8:24::5e { + address-family { + ipv6-unicast { + maximum-prefix 200 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64537 + } + neighbor 2001:db8:24::11 { + address-family { + ipv6-unicast { + maximum-prefix 20 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64538 + } + neighbor 2001:db8:24::18 { + address-family { + ipv6-unicast { + maximum-prefix 300 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64539 + } + neighbor 2001:db8:24::20 { + address-family { + ipv6-unicast { + maximum-prefix 10 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64540 + } + neighbor 2001:db8:24::22 { + address-family { + ipv6-unicast { + maximum-prefix 5 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64541 + } + neighbor 2001:db8:24::31 { + address-family { + ipv6-unicast { + maximum-prefix 20 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64542 + } + neighbor 2001:db8:24::58 { + address-family { + ipv6-unicast { + maximum-prefix 15 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64543 + } + neighbor 2001:db8:24::64 { + address-family { + ipv6-unicast { + maximum-prefix 10 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + password geheim + remote-as 64544 + } + neighbor 2001:db8:24::a5 { + address-family { + ipv6-unicast { + maximum-prefix 10 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64545 + } + neighbor 2001:db8:24::aa { + address-family { + ipv6-unicast { + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64546 + } + neighbor 2001:db8:24::ab { + address-family { + ipv6-unicast { + maximum-prefix 1800 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + remote-as 64547 + } + neighbor 2001:db8:24::b0 { + address-family { + ipv6-unicast { + maximum-prefix 5 + route-map { + export ExportRouteMap + import ImportRouteMap + } + } + } + password secret123 + remote-as 64548 + } + parameters { + default { + no-ipv4-unicast + } + log-neighbor-changes + router-id 192.0.68.2 + } + } + static { + route 192.0.98.0/24 { + blackhole { + } + } + route 192.0.160.0/24 { + blackhole { + } + } + route 192.0.68.0/22 { + blackhole { + } + } + route 192.0.84.0/22 { + blackhole { + } + } + route6 2001:db8::/29 { + blackhole { + } + } + } +} +system { + config-management { + commit-revisions 100 + } + console { + device ttyS0 { + speed 115200 + } + } + flow-accounting { + disable-imt + interface eth0.4088 + interface eth0.4089 + netflow { + engine-id 1 + server 192.0.2.55 { + port 2055 + } + version 9 + } + syslog-facility daemon + } + host-name vyos + login { + user vyos { + authentication { + encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/ + plaintext-password "" + } + } + } + name-server 2001:db8::1 + name-server 2001:db8::2 + name-server 192.0.2.1 + name-server 192.0.2.2 + ntp { + server 0.pool.ntp.org { + } + server 1.pool.ntp.org { + } + server 2.pool.ntp.org { + } + } + syslog { + global { + facility all { + level all + } + preserve-fqdn + } + } + time-zone Europe/Zurich +} +zone-policy { + zone local { + default-action drop + from management { + firewall { + ipv6-name management-to-local-6 + name management-to-local-4 + } + } + from peers { + firewall { + ipv6-name peers-to-local-6 + name peers-to-local-4 + } + } + from servers { + firewall { + ipv6-name servers-to-local-6 + name servers-to-local-4 + } + } + local-zone + } + zone management { + default-action reject + from peers { + firewall { + ipv6-name peers-to-management-6 + name peers-to-management-4 + } + } + from servers { + firewall { + ipv6-name servers-to-management-6 + name servers-to-management-4 + } + } + interface eth0 + } + zone peers { + default-action reject + from management { + firewall { + ipv6-name management-to-peers-6 + name management-to-peers-4 + } + } + from servers { + firewall { + ipv6-name servers-to-peers-6 + name servers-to-peers-4 + } + } + interface eth0.4088 + interface eth0.4089 + interface eth0.11 + interface eth0.838 + interface eth0.886 + } + zone servers { + default-action reject + from management { + firewall { + ipv6-name management-to-servers-6 + name management-to-servers-4 + } + } + from peers { + firewall { + ipv6-name peers-to-servers-6 + name peers-to-servers-4 + } + } + interface eth0.1001 + interface eth0.105 + interface eth0.102 + interface eth0.1019 + interface eth0.1014 + interface eth0.1020 + interface eth0.1018 + interface eth0.1013 + interface eth0.1012 + interface eth0.1011 + interface eth0.1010 + interface eth0.1009 + interface eth0.1006 + interface eth0.1005 + interface eth0.1017 + interface eth0.1016 + interface eth0.1002 + interface eth0.1015 + interface eth0.1003 + interface eth0.1004 + interface eth0.1007 + interface eth0.1008 + } +} + + +/* Warning: Do not remove the following line. */ +/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@9:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */ +/* Release version: 1.2.5 */ diff --git a/smoketest/configs/small-as-bgp-vrrp b/smoketest/configs/bgp-small-as index 61286c324..6b953a3f6 100644 --- a/smoketest/configs/small-as-bgp-vrrp +++ b/smoketest/configs/bgp-small-as @@ -345,6 +345,10 @@ protocols { } } neighbor 10.0.151.222 { + disable-send-community { + extended + standard + } address-family { ipv4-unicast { default-originate { diff --git a/smoketest/configs/bgp-ixp b/smoketest/configs/bgp-small-internet-exchange index de6213b50..de6213b50 100644 --- a/smoketest/configs/bgp-ixp +++ b/smoketest/configs/bgp-small-internet-exchange diff --git a/smoketest/configs/dmz-guest-lan-nat-pppoe-router b/smoketest/configs/dialup-router-complex index e671126a6..fef79ea56 100644 --- a/smoketest/configs/dmz-guest-lan-nat-pppoe-router +++ b/smoketest/configs/dialup-router-complex @@ -1660,4 +1660,3 @@ zone-policy { // Warning: Do not remove the following line. // vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@1:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@18:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@6:salt@1:snmp@2:ssh@2:sstp@3:system@20:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1" // Release version: 1.3-beta-202101091250 - diff --git a/smoketest/configs/dialup-router-medium-vpn b/smoketest/configs/dialup-router-medium-vpn new file mode 100644 index 000000000..dfb3d9621 --- /dev/null +++ b/smoketest/configs/dialup-router-medium-vpn @@ -0,0 +1,707 @@ +firewall { + all-ping enable + broadcast-ping disable + config-trap disable + ipv6-receive-redirects disable + ipv6-src-route disable + ip-src-route disable + log-martians enable + options { + interface vtun0 { + adjust-mss 1380 + } + interface vtun1 { + adjust-mss 1380 + } + interface vtun2 { + adjust-mss 1380 + } + interface wg0 { + adjust-mss 1380 + } + interface wg1 { + adjust-mss 1380 + } + } + receive-redirects disable + send-redirects enable + source-validation disable + syn-cookies disable + twa-hazards-protection enable +} +high-availability { + vrrp { + group LAN { + hello-source-address 192.168.0.250 + interface eth1 + peer-address 192.168.0.251 + priority 200 + virtual-address 192.168.0.1/24 + vrid 1 + } + sync-group failover-group { + member LAN + } + } +} +interfaces { + ethernet eth0 { + duplex auto + mtu 9000 + offload-options { + generic-receive on + generic-segmentation on + scatter-gather on + tcp-segmentation on + } + pppoe 0 { + default-route auto + mtu 1500 + name-server auto + password password + traffic-policy { + out shape-17mbit + } + user-id vyos + password vyos + } + smp-affinity auto + speed auto + } + ethernet eth1 { + address 192.168.0.250/24 + duplex auto + ip { + source-validation strict + } + mtu 9000 + offload-options { + generic-receive on + generic-segmentation on + scatter-gather on + tcp-segmentation on + } + policy { + route LAN-POLICY-BASED-ROUTING + } + smp-affinity auto + speed auto + traffic-policy { + out shape-94mbit + } + } + loopback lo { + } + openvpn vtun0 { + encryption aes256 + hash sha512 + ip { + source-validation strict + } + keep-alive { + failure-count 3 + interval 30 + } + mode client + openvpn-option "comp-lzo adaptive" + openvpn-option fast-io + openvpn-option persist-key + openvpn-option "reneg-sec 86400" + persistent-tunnel + remote-host 192.0.2.10 + tls { + ca-cert-file /config/auth/ovpn_test_ca.pem + cert-file /config/auth/ovpn_test_server.pem + key-file /config/auth/ovpn_test_server.key + auth-file /config/auth/ovpn_test_tls_auth.key + } + } + openvpn vtun1 { + authentication { + password vyos1 + username vyos1 + } + encryption aes256 + hash sha1 + keep-alive { + failure-count 3 + interval 30 + } + mode client + openvpn-option "comp-lzo adaptive" + openvpn-option "tun-mtu 1500" + openvpn-option "tun-mtu-extra 32" + openvpn-option "mssfix 1300" + openvpn-option persist-key + openvpn-option "mute 10" + openvpn-option route-nopull + openvpn-option fast-io + openvpn-option "reneg-sec 86400" + persistent-tunnel + protocol udp + remote-host 01.foo.com + remote-port 1194 + tls { + ca-cert-file /config/auth/ovpn_test_ca.pem + auth-file /config/auth/ovpn_test_tls_auth.key + } + } + openvpn vtun2 { + authentication { + password vyos2 + username vyos2 + } + disable + encryption aes256 + hash sha512 + keep-alive { + failure-count 3 + interval 30 + } + mode client + openvpn-option "tun-mtu 1500" + openvpn-option "tun-mtu-extra 32" + openvpn-option "mssfix 1300" + openvpn-option persist-key + openvpn-option "mute 10" + openvpn-option route-nopull + openvpn-option fast-io + openvpn-option remote-random + openvpn-option "reneg-sec 86400" + persistent-tunnel + protocol udp + remote-host 01.myvpn.com + remote-host 02.myvpn.com + remote-host 03.myvpn.com + remote-port 1194 + tls { + ca-cert-file /config/auth/ovpn_test_ca.pem + auth-file /config/auth/ovpn_test_tls_auth.key + } + } + wireguard wg0 { + address 192.168.10.1/24 + peer red { + allowed-ips 192.168.10.4/32 + persistent-keepalive 20 + preshared-key CumyXX7osvUT9AwnS+m2TEfCaL0Ptc2LfuZ78Sujuk8= + pubkey ALGWvMJCKpHF2tVH3hEIHqUe9iFfAmZATUUok/WQzks= + } + peer green { + allowed-ips 192.168.10.21/32 + persistent-keepalive 25 + preshared-key LQ9qmlTh9G4nZu4UgElxRUwg7JB/qoV799aADJOijnY= + pubkey 5iQUD3VoCDBTPXAPHOwUJ0p7xzKGHEY/wQmgvBVmaFI= + } + peer blue { + allowed-ips 192.168.10.3/32 + persistent-keepalive 20 + preshared-key ztFDOY9UyaDvn8N3X97SFMDwIfv7EEfuUIPP2yab6UI= + pubkey G4pZishpMRrLmd96Kr6V7LIuNGdcUb81gWaYZ+FWkG0= + } + peer pink { + allowed-ips 192.168.10.14/32 + allowed-ips 192.168.10.16/32 + persistent-keepalive 25 + preshared-key Qi9Odyx0/5itLPN5C5bEy3uMX+tmdl15QbakxpKlWqQ= + pubkey i4qNPmxyy9EETL4tIoZOLKJF4p7IlVmpAE15gglnAk4= + } + port 7777 + } + wireguard wg1 { + address 10.89.90.2/30 + peer sam { + allowed-ips 10.1.1.0/24 + allowed-ips 10.89.90.1/32 + endpoint 192.0.2.45:1200 + persistent-keepalive 20 + preshared-key XpFtzx2Z+nR8pBv9/sSf7I94OkZkVYTz0AeU5Q/QQUE= + pubkey v5zfKGvH6W/lfDXJ0en96lvKo1gfFxMUWxe02+Fj5BU= + } + port 7778 + } +} +nat { + destination { + rule 50 { + destination { + port 49371 + } + inbound-interface pppoe0 + protocol tcp_udp + translation { + address 192.168.0.5 + } + } + rule 51 { + destination { + port 58050-58051 + } + inbound-interface pppoe0 + protocol tcp + translation { + address 192.168.0.5 + } + } + rule 52 { + destination { + port 22067-22070 + } + inbound-interface pppoe0 + protocol tcp + translation { + address 192.168.0.5 + } + } + rule 53 { + destination { + port 34342 + } + inbound-interface pppoe0 + protocol tcp_udp + translation { + address 192.168.0.121 + } + } + rule 54 { + destination { + port 45459 + } + inbound-interface pppoe0 + protocol tcp_udp + translation { + address 192.168.0.120 + } + } + rule 55 { + destination { + port 22 + } + inbound-interface pppoe0 + protocol tcp + translation { + address 192.168.0.5 + } + } + rule 56 { + destination { + port 8920 + } + inbound-interface pppoe0 + protocol tcp + translation { + address 192.168.0.5 + } + } + rule 60 { + destination { + port 80,443 + } + inbound-interface pppoe0 + protocol tcp + translation { + address 192.168.0.5 + } + } + rule 70 { + destination { + port 5001 + } + inbound-interface pppoe0 + protocol tcp + translation { + address 192.168.0.5 + } + } + rule 80 { + destination { + port 25 + } + inbound-interface pppoe0 + protocol tcp + translation { + address 192.168.0.5 + } + } + rule 90 { + destination { + port 8123 + } + inbound-interface pppoe0 + protocol tcp + translation { + address 192.168.0.7 + } + } + rule 91 { + destination { + port 1880 + } + inbound-interface pppoe0 + protocol tcp + translation { + address 192.168.0.7 + } + } + rule 500 { + destination { + address !192.168.0.0/24 + port 53 + } + inbound-interface eth1 + protocol tcp_udp + source { + address !192.168.0.1-192.168.0.5 + } + translation { + address 192.168.0.1 + } + } + } + source { + rule 1000 { + outbound-interface pppoe0 + translation { + address masquerade + } + } + rule 2000 { + outbound-interface vtun0 + source { + address 192.168.0.0/16 + } + translation { + address masquerade + } + } + rule 3000 { + outbound-interface vtun1 + translation { + address masquerade + } + } + } +} +policy { + prefix-list user2-routes { + rule 1 { + action permit + prefix 10.1.1.0/24 + } + } + prefix-list user1-routes { + rule 1 { + action permit + prefix 192.168.0.0/24 + } + } + route LAN-POLICY-BASED-ROUTING { + rule 10 { + destination { + } + disable + set { + table 10 + } + source { + address 192.168.0.119/32 + } + } + rule 20 { + destination { + } + set { + table 100 + } + source { + address 192.168.0.240 + } + } + } + route-map rm-static-to-bgp { + rule 10 { + action permit + match { + ip { + address { + prefix-list user1-routes + } + } + } + } + rule 100 { + action deny + } + } +} +protocols { + bgp 64590 { + address-family { + ipv4-unicast { + redistribute { + connected { + route-map rm-static-to-bgp + } + } + } + } + neighbor 10.89.90.1 { + address-family { + ipv4-unicast { + nexthop-self + prefix-list { + export user1-routes + import user2-routes + } + soft-reconfiguration { + inbound + } + } + } + password ericandre2020 + remote-as 64589 + } + parameters { + log-neighbor-changes + router-id 10.89.90.2 + } + } + static { + interface-route 100.64.160.23/32 { + next-hop-interface pppoe0 { + } + } + interface-route 100.64.165.25/32 { + next-hop-interface pppoe0 { + } + } + interface-route 100.64.165.26/32 { + next-hop-interface pppoe0 { + } + } + interface-route 100.64.198.0/24 { + next-hop-interface vtun0 { + } + } + table 10 { + interface-route 0.0.0.0/0 { + next-hop-interface vtun1 { + } + } + } + table 100 { + route 0.0.0.0/0 { + next-hop 192.168.10.5 { + } + } + } + } +} +service { + conntrack-sync { + accept-protocol tcp,udp,icmp + disable-external-cache + event-listen-queue-size 8 + expect-sync all + failover-mechanism { + vrrp { + sync-group failover-group + } + } + interface eth1 { + peer 192.168.0.251 + } + sync-queue-size 8 + } + dhcp-server { + shared-network-name LAN { + authoritative + subnet 192.168.0.0/24 { + default-router 192.168.0.1 + dns-server 192.168.0.1 + domain-name vyos.net + domain-search vyos.net + failover { + local-address 192.168.0.250 + name DHCP02 + peer-address 192.168.0.251 + status primary + } + lease 86400 + range LANDynamic { + start 192.168.0.200 + stop 192.168.0.240 + } + static-mapping IPTV { + ip-address 192.168.0.104 + mac-address 00:50:01:31:b5:f6 + } + static-mapping McPrintus { + ip-address 192.168.0.60 + mac-address 00:50:01:58:ac:95 + static-mapping-parameters "option domain-name-servers 192.168.0.6,192.168.0.17;" + } + static-mapping Audio { + ip-address 192.168.0.107 + mac-address 00:50:01:dc:91:14 + } + static-mapping Mobile01 { + ip-address 192.168.0.109 + mac-address 00:50:01:bc:ac:51 + static-mapping-parameters "option domain-name-servers 192.168.0.6,192.168.0.17;" + } + static-mapping sand { + ip-address 192.168.0.110 + mac-address 00:50:01:af:c5:d2 + } + static-mapping pearTV { + ip-address 192.168.0.101 + mac-address 00:50:01:ba:62:79 + } + static-mapping camera1 { + ip-address 192.168.0.11 + mac-address 00:50:01:70:b9:4d + static-mapping-parameters "option domain-name-servers 192.168.0.6,192.168.0.17;" + } + static-mapping camera2 { + ip-address 192.168.0.12 + mac-address 00:50:01:70:b7:4f + static-mapping-parameters "option domain-name-servers 192.168.0.6,192.168.0.17;" + } + } + } + } + dns { + forwarding { + allow-from 192.168.0.0/16 + cache-size 8192 + dnssec off + listen-address 192.168.0.1 + name-server 100.64.0.1 + name-server 100.64.0.2 + } + } + snmp { + community AwesomeCommunity { + authorization ro + client 127.0.0.1 + network 192.168.0.0/24 + } + } + ssh { + access-control { + allow { + user vyos + } + } + client-keepalive-interval 60 + listen-address 192.168.0.1 + listen-address 192.168.10.1 + listen-address 192.168.0.250 + } +} +system { + config-management { + commit-revisions 100 + } + console { + device ttyS0 { + speed 115200 + } + } + host-name vyos + ip { + arp { + table-size 1024 + } + } + login { + user vyos { + authentication { + encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0 + plaintext-password "" + } + } + } + name-server 192.168.0.1 + ntp { + allow-clients { + address 192.168.0.0/16 + } + listen-address 192.168.0.1 + listen-address 192.168.0.250 + server nz.pool.ntp.org { + prefer + } + } + options { + beep-if-fully-booted + ctrl-alt-del-action ignore + reboot-on-panic true + } + static-host-mapping { + host-name host104.vyos.net { + inet 192.168.0.104 + } + host-name host60.vyos.net { + inet 192.168.0.60 + } + host-name host107.vyos.net { + inet 192.168.0.107 + } + host-name host109.vyos.net { + inet 192.168.0.109 + } + } + sysctl { + custom net.core.default_qdisc { + value fq + } + custom net.ipv4.tcp_congestion_control { + value bbr + } + } + syslog { + global { + facility all { + level info + } + } + host 192.168.0.252 { + facility all { + level debug + protocol udp + } + } + } + task-scheduler { + task Update-Blacklists { + executable { + path /config/scripts/vyos-foo-update.script + } + interval 3h + } + } + time-zone Pacific/Auckland +} +traffic-policy { + shaper shape-17mbit { + bandwidth 17mbit + default { + bandwidth 100% + burst 15k + queue-type fq-codel + } + } + shaper shape-94mbit { + bandwidth 94mbit + default { + bandwidth 100% + burst 15k + queue-type fq-codel + } + } +} +/* Warning: Do not remove the following line. */ +/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@9:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */ +/* Release version: 1.2.6 */ diff --git a/smoketest/configs/ospf-config b/smoketest/configs/ospf-small index fe313e4b0..d95ba4ea4 100644 --- a/smoketest/configs/ospf-config +++ b/smoketest/configs/ospf-small @@ -24,12 +24,27 @@ interfaces { transmit-delay 1 } } + ipv6 { + ospfv3 { + bfd + cost 40 + } + } } } ethernet eth1 { duplex auto smp-affinity auto speed auto + ipv6 { + ospfv3 { + bfd + cost 60 + mtu-ignore + network broadcast + priority 20 + } + } } } protocols { @@ -47,6 +62,13 @@ protocols { passive-interface default passive-interface-exclude eth0.201 } + ospfv3 { + area 0.0.0.0 { + interface eth0 + interface eth1 + interface eth2 + } + } static { route 0.0.0.0/0 { next-hop 172.18.201.254 { diff --git a/smoketest/configs/pppoe-client b/smoketest/configs/pppoe-client deleted file mode 100644 index ef6a26423..000000000 --- a/smoketest/configs/pppoe-client +++ /dev/null @@ -1,62 +0,0 @@ -interfaces { - ethernet eth0 { - } - loopback lo { - } - pppoe pppoe0 { - authentication { - password bar - user foo - } - connect-on-demand - default-route auto - mtu 1492 - source-interface eth0 - } -} -service { - ssh { - } -} -system { - config-management { - commit-revisions 100 - } - console { - device ttyS0 { - speed 115200 - } - } - host-name vyos - login { - user vyos { - authentication { - encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/ - plaintext-password "" - } - } - } - ntp { - server 0.pool.ntp.org { - } - server 1.pool.ntp.org { - } - server 2.pool.ntp.org { - } - } - syslog { - global { - facility all { - level info - } - facility protocols { - level debug - } - } - } -} - - -// Warning: Do not remove the following line. -// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@1:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@13:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@6:salt@1:snmp@2:ssh@2:sstp@3:system@19:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webgui@1:webproxy@2:zone-policy@1" -// Release version: 1.3-rolling-202010241631 diff --git a/smoketest/configs/rip-router b/smoketest/configs/rip-router new file mode 100644 index 000000000..09cb11a45 --- /dev/null +++ b/smoketest/configs/rip-router @@ -0,0 +1,267 @@ +interfaces { + dummy dum0 { + address 192.0.2.0/32 + } + ethernet eth0 { + duplex auto + ip { + rip { + authentication { + md5 1 { + password VyOSsecure + } + } + split-horizon { + poison-reverse + } + } + } + ipv6 { + ripng { + split-horizon { + poison-reverse + } + } + } + smp-affinity auto + speed auto + address 172.18.202.10/24 + } + ethernet eth1 { + duplex auto + smp-affinity auto + speed auto + vif 20 { + ip { + rip { + authentication { + plaintext-password VyOSsecure + } + split-horizon { + poison-reverse + } + } + } + ipv6 { + ripng { + split-horizon { + disable + } + } + } + } + vif-s 200 { + ip { + rip { + authentication { + md5 1 { + password VyOSsecure + } + } + split-horizon { + disable + } + } + } + ipv6 { + ripng { + split-horizon { + poison-reverse + } + } + } + vif-c 2000 { + ip { + rip { + authentication { + md5 1 { + password VyOSsecure + } + } + } + } + } + vif-c 3000 { + ip { + rip { + split-horizon { + disable + } + } + } + ipv6 { + ripng { + split-horizon { + poison-reverse + } + } + } + } + } + } +} +policy { + access-list6 198 { + rule 10 { + action permit + source { + any + } + } + } + access-list6 199 { + rule 20 { + action deny + source { + any + } + } + } + prefix-list6 bar-prefix { + rule 200 { + action deny + prefix 2001:db8::/32 + } + } + prefix-list6 foo-prefix { + rule 100 { + action permit + prefix 2001:db8::/32 + } + } + route-map FooBar123 { + rule 10 { + action permit + } + } +} +protocols { + rip { + default-distance 20 + default-information { + originate + } + interface eth0 + interface eth1.20 + interface eth1.200 + interface eth1.200.2000 + interface eth1.200.3000 + network 192.168.0.0/24 + redistribute { + connected { + } + } + } + ripng { + aggregate-address 2001:db8:1000::/48 + default-information { + originate + } + default-metric 8 + distribute-list { + access-list { + in 198 + out 199 + } + interface eth0 { + access-list { + in 198 + out 199 + } + prefix-list { + in foo-prefix + out bar-prefix + } + } + interface eth1 { + access-list { + in 198 + out 199 + } + prefix-list { + in foo-prefix + out bar-prefix + } + } + interface eth2 { + access-list { + in 198 + out 199 + } + prefix-list { + in foo-prefix + out bar-prefix + } + } + prefix-list { + in foo-prefix + out bar-prefix + } + } + interface eth0 + interface eth1 + interface eth2 + network 2001:db8:1000::/64 + network 2001:db8:1001::/64 + network 2001:db8:2000::/64 + network 2001:db8:2001::/64 + passive-interface default + redistribute { + connected { + metric 8 + route-map FooBar123 + } + static { + metric 8 + route-map FooBar123 + } + } + route 2001:db8:1000::/64 + } +} +service { + ssh { + port 22 + } +} +system { + config-management { + commit-revisions 100 + } + console { + device ttyS0 { + speed 115200 + } + } + host-name vyos + login { + user vyos { + authentication { + encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0 + plaintext-password "" + } + } + } + ntp { + server 0.pool.ntp.org { + } + server 1.pool.ntp.org { + } + server 2.pool.ntp.org { + } + } + syslog { + global { + facility all { + level info + } + facility protocols { + level debug + } + } + } +} + +/* Warning: Do not remove the following line. */ +/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@10:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */ +/* Release version: 1.2.6-S1 */ diff --git a/smoketest/configs/vrf-basic b/smoketest/configs/vrf-basic new file mode 100644 index 000000000..ded33f683 --- /dev/null +++ b/smoketest/configs/vrf-basic @@ -0,0 +1,231 @@ +interfaces { + ethernet eth0 { + address 192.0.2.1/24 + } + ethernet eth1 { + duplex auto + speed auto + vrf green + } + ethernet eth2 { + vrf red + } +} +protocols { + static { + route 0.0.0.0/0 { + next-hop 192.0.2.254 { + distance 10 + } + } + table 10 { + interface-route 1.0.0.0/8 { + next-hop-interface eth0 { + distance 20 + } + } + interface-route 2.0.0.0/8 { + next-hop-interface eth0 { + distance 20 + } + } + interface-route 3.0.0.0/8 { + next-hop-interface eth0 { + distance 20 + } + } + } + table 20 { + interface-route 4.0.0.0/8 { + next-hop-interface eth0 { + distance 20 + } + } + interface-route 5.0.0.0/8 { + next-hop-interface eth0 { + distance 50 + } + } + interface-route 6.0.0.0/8 { + next-hop-interface eth0 { + distance 60 + } + } + interface-route6 2001:db8:100::/40 { + next-hop-interface eth1 { + distance 20 + } + } + interface-route6 2001:db8::/40 { + next-hop-interface eth1 { + distance 10 + } + } + route 11.0.0.0/8 { + next-hop 1.1.1.1 { + next-hop-interface eth0 + } + } + route 12.0.0.0/8 { + next-hop 1.1.1.1 { + next-hop-interface eth0 + } + } + route 13.0.0.0/8 { + next-hop 1.1.1.1 { + next-hop-interface eth0 + } + } + } + table 30 { + interface-route6 2001:db8:200::/40 { + next-hop-interface eth1 { + distance 20 + } + } + route 14.0.0.0/8 { + next-hop 2.2.1.1 { + next-hop-interface eth1 + } + } + route 15.0.0.0/8 { + next-hop 2.2.1.1 { + next-hop-interface eth1 + } + } + } + } + vrf green { + static { + interface-route 100.0.0.0/8 { + next-hop-interface eth0 { + distance 200 + next-hop-vrf default + } + } + interface-route 101.0.0.0/8 { + next-hop-interface eth0 { + next-hop-vrf default + } + next-hop-interface eth1 { + } + } + interface-route6 2001:db8:300::/40 { + next-hop-interface eth1 { + distance 20 + next-hop-vrf default + } + } + route 20.0.0.0/8 { + next-hop 1.1.1.1 { + next-hop-interface eth1 + next-hop-vrf default + } + } + route 21.0.0.0/8 { + next-hop 2.2.1.1 { + next-hop-interface eth1 + next-hop-vrf default + } + } + route6 2001:db8:100::/40 { + next-hop fe80::1 { + interface eth0 + next-hop-vrf default + } + } + } + } + vrf red { + static { + interface-route 103.0.0.0/8 { + next-hop-interface eth0 { + distance 201 + next-hop-vrf default + } + } + interface-route 104.0.0.0/8 { + next-hop-interface eth0 { + next-hop-vrf default + } + next-hop-interface eth1 { + next-hop-vrf default + } + } + interface-route6 2001:db8:400::/40 { + next-hop-interface eth1 { + distance 24 + next-hop-vrf default + } + } + route 30.0.0.0/8 { + next-hop 1.1.1.1 { + next-hop-interface eth1 + } + } + route 40.0.0.0/8 { + next-hop 2.2.1.1 { + next-hop-interface eth1 + next-hop-vrf default + } + } + route6 2001:db8:100::/40 { + next-hop fe80::1 { + interface eth0 + next-hop-vrf default + } + } + } + } +} +system { + config-management { + commit-revisions 100 + } + console { + device ttyS0 { + speed 115200 + } + } + host-name vyos + login { + user vyos { + authentication { + encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0 + plaintext-password "" + } + } + } + nt + ntp { + server 0.pool.ntp.org { + } + server 1.pool.ntp.org { + } + server 2.pool.ntp.org { + } + } + syslog { + global { + facility all { + level info + } + facility protocols { + level debug + } + } + } + time-zone Europe/Berlin +} +vrf { + name green { + table 1000 + } + name red { + table 2000 + } +} + +// Warning: Do not remove the following line. +// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@1:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@18:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@6:salt@1:snmp@2:ssh@2:sstp@3:system@20:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1" +// Release version: 1.3-beta-202101231023 diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py index 8f21ec70e..1426e80c2 100644 --- a/smoketest/scripts/cli/base_interfaces_test.py +++ b/smoketest/scripts/cli/base_interfaces_test.py @@ -402,12 +402,13 @@ class BasicInterfaceTest: tmp = read_file(f'/proc/sys/net/ipv6/conf/{interface}/dad_transmits') self.assertEqual(dad_transmits, tmp) - def test_dhcpv6_client_options(self): + def test_dhcpv6_clinet_options(self): if not self._test_ipv6_dhcpc6: self.skipTest('not supported') - duid = '00:01:00:01:27:71:db:f0:00:50:00:00:00:10' + duid_base = 10 for interface in self._interfaces: + duid = '00:01:00:01:27:71:db:f0:00:50:00:00:00:{}'.format(duid_base) path = self._base_path + [interface] for option in self._options.get(interface, []): self.session.set(path + option.split()) @@ -417,10 +418,13 @@ class BasicInterfaceTest: self.session.set(path + ['dhcpv6-options', 'rapid-commit']) self.session.set(path + ['dhcpv6-options', 'parameters-only']) self.session.set(path + ['dhcpv6-options', 'duid', duid]) + duid_base += 1 self.session.commit() + duid_base = 10 for interface in self._interfaces: + duid = '00:01:00:01:27:71:db:f0:00:50:00:00:00:{}'.format(duid_base) dhcpc6_config = read_file(f'/run/dhcp6c/dhcp6c.{interface}.conf') self.assertIn(f'interface {interface} ' + '{', dhcpc6_config) self.assertIn(f' request domain-name-servers;', dhcpc6_config) @@ -430,6 +434,7 @@ class BasicInterfaceTest: self.assertIn(f' send rapid-commit;', dhcpc6_config) self.assertIn(f' send client-id {duid};', dhcpc6_config) self.assertIn('};', dhcpc6_config) + duid_base += 1 # Check for running process self.assertTrue(process_named_running('dhcp6c')) diff --git a/smoketest/scripts/cli/test_interfaces_bonding.py b/smoketest/scripts/cli/test_interfaces_bonding.py index 882d38760..b65d97d30 100755 --- a/smoketest/scripts/cli/test_interfaces_bonding.py +++ b/smoketest/scripts/cli/test_interfaces_bonding.py @@ -25,34 +25,32 @@ from vyos.configsession import ConfigSessionError from vyos.util import read_file class BondingInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._test_ipv6_pd = True - self._test_ipv6_dhcpc6 = True - self._test_mtu = True - self._test_vlan = True - self._test_qinq = True - self._base_path = ['interfaces', 'bonding'] - self._interfaces = ['bond0'] - self._mirror_interfaces = ['dum21354'] - self._members = [] + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._test_ipv6_pd = True + cls._test_ipv6_dhcpc6 = True + cls._test_mtu = True + cls._test_vlan = True + cls._test_qinq = True + cls._base_path = ['interfaces', 'bonding'] + cls._interfaces = ['bond0'] + cls._mirror_interfaces = ['dum21354'] + cls._members = [] # we need to filter out VLAN interfaces identified by a dot (.) # in their name - just in case! if 'TEST_ETH' in os.environ: - self._members = os.environ['TEST_ETH'].split() + cls._members = os.environ['TEST_ETH'].split() else: - for tmp in Section.interfaces("ethernet"): + for tmp in Section.interfaces('ethernet'): if not '.' in tmp: - self._members.append(tmp) - - self._options['bond0'] = [] - for member in self._members: - self._options['bond0'].append(f'member interface {member}') - - super().setUp() + cls._members.append(tmp) + cls._options['bond0'] = [] + for member in cls._members: + cls._options['bond0'].append(f'member interface {member}') def test_add_single_ip_address(self): super().test_add_single_ip_address() diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py index 33c2e7dad..f64b527b3 100755 --- a/smoketest/scripts/cli/test_interfaces_bridge.py +++ b/smoketest/scripts/cli/test_interfaces_bridge.py @@ -28,31 +28,30 @@ from vyos.util import read_file from vyos.validate import is_intf_addr_assigned class BridgeInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._test_ipv6_pd = True - self._test_ipv6_dhcpc6 = True - self._test_vlan = True - self._base_path = ['interfaces', 'bridge'] - self._mirror_interfaces = ['dum21354'] - self._members = [] + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._test_ipv6_pd = True + cls._test_ipv6_dhcpc6 = True + cls._test_vlan = True + cls._base_path = ['interfaces', 'bridge'] + cls._mirror_interfaces = ['dum21354'] + cls._members = [] # we need to filter out VLAN interfaces identified by a dot (.) # in their name - just in case! if 'TEST_ETH' in os.environ: - self._members = os.environ['TEST_ETH'].split() + cls._members = os.environ['TEST_ETH'].split() else: - for tmp in Section.interfaces("ethernet"): + for tmp in Section.interfaces('ethernet'): if not '.' in tmp: - self._members.append(tmp) + cls._members.append(tmp) - self._options['br0'] = [] - for member in self._members: - self._options['br0'].append(f'member interface {member}') - self._interfaces = list(self._options) - - super().setUp() + cls._options['br0'] = [] + for member in cls._members: + cls._options['br0'].append(f'member interface {member}') + cls._interfaces = list(cls._options) def tearDown(self): for intf in self._interfaces: diff --git a/smoketest/scripts/cli/test_interfaces_dummy.py b/smoketest/scripts/cli/test_interfaces_dummy.py index 60465a1d5..6e462bccf 100755 --- a/smoketest/scripts/cli/test_interfaces_dummy.py +++ b/smoketest/scripts/cli/test_interfaces_dummy.py @@ -19,10 +19,10 @@ import unittest from base_interfaces_test import BasicInterfaceTest class DummyInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._base_path = ['interfaces', 'dummy'] - self._interfaces = ['dum435', 'dum8677', 'dum0931', 'dum089'] - super().setUp() + @classmethod + def setUpClass(cls): + cls._base_path = ['interfaces', 'dummy'] + cls._interfaces = ['dum435', 'dum8677', 'dum0931', 'dum089'] if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_erspan.py b/smoketest/scripts/cli/test_interfaces_erspan.py new file mode 100755 index 000000000..c180f0a34 --- /dev/null +++ b/smoketest/scripts/cli/test_interfaces_erspan.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import unittest +import json + +from vyos.configsession import ConfigSession +from vyos.configsession import ConfigSessionError +from vyos.util import cmd + +from base_interfaces_test import BasicInterfaceTest + +mtu = 1500 + +def erspan_conf(interface): + tmp = cmd(f'ip -d -j link show {interface}') + ''' + [ + { + "ifindex": 17, + "link": null, + "ifname": "ersp0", + "flags": [ + "BROADCAST", + "MULTICAST" + ], + "mtu": 1450, + "qdisc": "noop", + "operstate": "DOWN", + "linkmode": "DEFAULT", + "group": "default", + "txqlen": 1000, + "link_type": "ether", + "address": "22:27:14:7b:0d:79", + "broadcast": "ff:ff:ff:ff:ff:ff", + "promiscuity": 0, + "min_mtu": 68, + "max_mtu": 0, + "linkinfo": { + "info_kind": "erspan", + "info_data": { + "remote": "10.2.2.2", + "local": "10.1.1.1", + "ttl": 0, + "pmtudisc": true, + "ikey": "0.0.0.123", + "okey": "0.0.0.123", + "iseq": true, + "oseq": true, + "erspan_index": 0, + "erspan_ver": 1 + } + }, + "inet6_addr_gen_mode": "eui64", + "num_tx_queues": 1, + "num_rx_queues": 1, + "gso_max_size": 65536, + "gso_max_segs": 65535 + } + ] + ''' + return json.loads(tmp)[0] + +class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest): + def setUp(self): + super().setUp() + + self._base_path = ['interfaces', 'erspan'] + self._test_mtu = True + + self.local_v4 = '10.1.1.1' + self.local_v6 = '2001:db8::1' + self.remote_v4 = '10.2.2.2' + self.remote_v6 = '2001:db9::1' + + def tearDown(self): + self.session.delete(['interfaces', 'erspan']) + super().tearDown() + + def test_erspan_ipv4(self): + interface = 'ersp100' + encapsulation = 'erspan' + key = 123 + + self.session.set(self._base_path + [interface, 'encapsulation', encapsulation]) + self.session.set(self._base_path + [interface, 'local-ip', self.local_v4]) + self.session.set(self._base_path + [interface, 'remote-ip', self.remote_v4]) + self.session.set(self._base_path + [interface, 'parameters', 'ip' , 'key', str(key)]) + + self.session.commit() + + conf = erspan_conf(interface) + self.assertEqual(interface, conf['ifname']) + self.assertEqual(encapsulation, conf['linkinfo']['info_kind']) + self.assertEqual(mtu, conf['mtu']) + + self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local']) + self.assertEqual(self.remote_v4, conf['linkinfo']['info_data']['remote']) + + + def test_erspan_ipv6(self): + interface = 'ersp1000' + encapsulation = 'ip6erspan' + key = 123 + + self.session.set(self._base_path + [interface, 'encapsulation', encapsulation]) + self.session.set(self._base_path + [interface, 'local-ip', self.local_v6]) + self.session.set(self._base_path + [interface, 'remote-ip', self.remote_v6]) + self.session.set(self._base_path + [interface, 'parameters', 'ip' , 'key', str(key)]) + + self.session.commit() + + conf = erspan_conf(interface) + self.assertEqual(interface, conf['ifname']) + self.assertEqual(encapsulation, conf['linkinfo']['info_kind']) + self.assertEqual(mtu, conf['mtu']) + + self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local']) + self.assertEqual(self.remote_v6, conf['linkinfo']['info_data']['remote']) + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_ethernet.py b/smoketest/scripts/cli/test_interfaces_ethernet.py index 6c6e66008..772ff248f 100755 --- a/smoketest/scripts/cli/test_interfaces_ethernet.py +++ b/smoketest/scripts/cli/test_interfaces_ethernet.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -35,38 +35,31 @@ def get_wpa_supplicant_value(interface, key): return tmp[0] class EthernetInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._test_ipv6_pd = True - self._test_ipv6_dhcpc6 = True - self._test_mtu = True - self._test_vlan = True - self._test_qinq = True - self._base_path = ['interfaces', 'ethernet'] - self._mirror_interfaces = ['dum21354'] + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._test_ipv6_pd = True + cls._test_ipv6_dhcpc6 = True + cls._test_mtu = True + cls._test_vlan = True + cls._test_qinq = True + cls._base_path = ['interfaces', 'ethernet'] + cls._mirror_interfaces = ['dum21354'] # we need to filter out VLAN interfaces identified by a dot (.) # in their name - just in case! if 'TEST_ETH' in os.environ: tmp = os.environ['TEST_ETH'].split() - self._interfaces = tmp + cls._interfaces = tmp else: - for tmp in Section.interfaces("ethernet"): + for tmp in Section.interfaces('ethernet'): if not '.' in tmp: - self._interfaces.append(tmp) + cls._interfaces.append(tmp) - self._macs = {} - for interface in self._interfaces: - try: - mac = self.session.show_config(self._base_path + - [interface, 'hw-id']).split()[1] - except: - # during initial system startup there is no hw-id node - mac = read_file(f'/sys/class/net/{interface}/address') - self._macs[interface] = mac - - super().setUp() + cls._macs = {} + for interface in cls._interfaces: + cls._macs[interface] = read_file(f'/sys/class/net/{interface}/address') def tearDown(self): @@ -102,8 +95,7 @@ class EthernetInterfaceTest(BasicInterfaceTest.BaseTest): # Validate interface state for interface in self._interfaces: - with open(f'/sys/class/net/{interface}/flags', 'r') as f: - flags = f.read() + flags = read_file(f'/sys/class/net/{interface}/flags') self.assertEqual(int(flags, 16) & 1, 0) def test_offloading_rps(self): diff --git a/smoketest/scripts/cli/test_interfaces_geneve.py b/smoketest/scripts/cli/test_interfaces_geneve.py index 12cded400..b708b5437 100755 --- a/smoketest/scripts/cli/test_interfaces_geneve.py +++ b/smoketest/scripts/cli/test_interfaces_geneve.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -20,16 +20,16 @@ from vyos.configsession import ConfigSession from base_interfaces_test import BasicInterfaceTest class GeneveInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._base_path = ['interfaces', 'geneve'] - self._options = { + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._base_path = ['interfaces', 'geneve'] + cls._options = { 'gnv0': ['vni 10', 'remote 127.0.1.1'], 'gnv1': ['vni 20', 'remote 127.0.1.2'], } - self._interfaces = list(self._options) - super().setUp() + cls._interfaces = list(cls._options) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_l2tpv3.py b/smoketest/scripts/cli/test_interfaces_l2tpv3.py index 81af6d7f4..a89895b92 100755 --- a/smoketest/scripts/cli/test_interfaces_l2tpv3.py +++ b/smoketest/scripts/cli/test_interfaces_l2tpv3.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -21,11 +21,12 @@ from base_interfaces_test import BasicInterfaceTest from vyos.util import cmd class GeneveInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._base_path = ['interfaces', 'l2tpv3'] - self._options = { + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._base_path = ['interfaces', 'l2tpv3'] + cls._options = { 'l2tpeth10': ['local-ip 127.0.0.1', 'remote-ip 127.10.10.10', 'tunnel-id 100', 'peer-tunnel-id 10', 'session-id 100', 'peer-session-id 10', @@ -35,8 +36,7 @@ class GeneveInterfaceTest(BasicInterfaceTest.BaseTest): 'session-id 20', 'tunnel-id 200', 'source-port 2020', 'destination-port 20202'], } - self._interfaces = list(self._options) - super().setUp() + cls._interfaces = list(cls._options) def test_add_single_ip_address(self): super().test_add_single_ip_address() diff --git a/smoketest/scripts/cli/test_interfaces_loopback.py b/smoketest/scripts/cli/test_interfaces_loopback.py index 36000c3ff..77dd4c1b5 100755 --- a/smoketest/scripts/cli/test_interfaces_loopback.py +++ b/smoketest/scripts/cli/test_interfaces_loopback.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -21,13 +21,13 @@ from netifaces import interfaces from vyos.validate import is_intf_addr_assigned +loopbacks = ['127.0.0.1', '::1'] + class LoopbackInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - super().setUp() - # these addresses are never allowed to be removed from the system - self._loopback_addresses = ['127.0.0.1', '::1'] - self._base_path = ['interfaces', 'loopback'] - self._interfaces = ['lo'] + @classmethod + def setUpClass(cls): + cls._base_path = ['interfaces', 'loopback'] + cls._interfaces = ['lo'] def tearDown(self): self.session.delete(self._base_path) @@ -40,12 +40,12 @@ class LoopbackInterfaceTest(BasicInterfaceTest.BaseTest): def test_add_single_ip_address(self): super().test_add_single_ip_address() - for addr in self._loopback_addresses: + for addr in loopbacks: self.assertTrue(is_intf_addr_assigned('lo', addr)) def test_add_multiple_ip_addresses(self): super().test_add_multiple_ip_addresses() - for addr in self._loopback_addresses: + for addr in loopbacks: self.assertTrue(is_intf_addr_assigned('lo', addr)) def test_interface_disable(self): diff --git a/smoketest/scripts/cli/test_interfaces_macsec.py b/smoketest/scripts/cli/test_interfaces_macsec.py index 89743e5fd..3a3e7bff3 100755 --- a/smoketest/scripts/cli/test_interfaces_macsec.py +++ b/smoketest/scripts/cli/test_interfaces_macsec.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -31,19 +31,19 @@ def get_config_value(interface, key): return tmp[0] class MACsecInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - super().setUp() - self._test_ip = True - self._test_ipv6 = True - self._base_path = ['interfaces', 'macsec'] - self._options = { 'macsec0': ['source-interface eth0', 'security cipher gcm-aes-128'] } + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._base_path = ['interfaces', 'macsec'] + cls._options = { 'macsec0': ['source-interface eth0', 'security cipher gcm-aes-128'] } # if we have a physical eth1 interface, add a second macsec instance - if 'eth1' in Section.interfaces("ethernet"): + if 'eth1' in Section.interfaces('ethernet'): macsec = { 'macsec1': [f'source-interface eth1', 'security cipher gcm-aes-128'] } - self._options.update(macsec) + cls._options.update(macsec) - self._interfaces = list(self._options) + cls._interfaces = list(cls._options) def test_macsec_encryption(self): # MACsec can be operating in authentication and encryption mode - both diff --git a/smoketest/scripts/cli/test_interfaces_openvpn.py b/smoketest/scripts/cli/test_interfaces_openvpn.py index 00db3f667..a2a1a85ec 100755 --- a/smoketest/scripts/cli/test_interfaces_openvpn.py +++ b/smoketest/scripts/cli/test_interfaces_openvpn.py @@ -625,27 +625,27 @@ if __name__ == '__main__': # Generate mandatory SSL certificate tmp = f'openssl req -newkey rsa:4096 -new -nodes -x509 -days 3650 '\ f'-keyout {ssl_key} -out {ssl_cert} -subj {subject}' - print(cmd(tmp)) + cmd(tmp) if not os.path.isfile(ca_cert): # Generate "CA" tmp = f'openssl req -new -x509 -key {ssl_key} -out {ca_cert} -subj {subject}' - print(cmd(tmp)) + cmd(tmp) if not os.path.isfile(dh_pem): # Generate "DH" key tmp = f'openssl dhparam -out {dh_pem} 2048' - print(cmd(tmp)) + cmd(tmp) if not os.path.isfile(s2s_key): # Generate site-2-site key tmp = f'openvpn --genkey --secret {s2s_key}' - print(cmd(tmp)) + cmd(tmp) if not os.path.isfile(auth_key): # Generate TLS auth key tmp = f'openvpn --genkey --secret {auth_key}' - print(cmd(tmp)) + cmd(tmp) for file in [ca_cert, ssl_cert, ssl_key, dh_pem, s2s_key, auth_key]: cmd(f'sudo chown openvpn:openvpn {file}') diff --git a/smoketest/scripts/cli/test_interfaces_pppoe.py b/smoketest/scripts/cli/test_interfaces_pppoe.py index 6bfe35d86..285c756e2 100755 --- a/smoketest/scripts/cli/test_interfaces_pppoe.py +++ b/smoketest/scripts/cli/test_interfaces_pppoe.py @@ -97,6 +97,27 @@ class PPPoEInterfaceTest(unittest.TestCase): self.assertTrue(running) + + def test_pppoe_clent_disabled_interface(self): + # Check if PPPoE Client can be disabled + for interface in self._interfaces: + self.session.set(base_path + [interface, 'authentication', 'user', 'vyos']) + self.session.set(base_path + [interface, 'authentication', 'password', 'vyos']) + self.session.set(base_path + [interface, 'source-interface', self._source_interface]) + self.session.set(base_path + [interface, 'disable']) + + self.session.commit() + + # Validate PPPoE client process + running = False + for interface in self._interfaces: + for proc in process_iter(): + if interface in proc.cmdline(): + running = True + + self.assertFalse(running) + + def test_pppoe_dhcpv6pd(self): # Check if PPPoE dialer can be configured with DHCPv6-PD address = '1' diff --git a/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py b/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py index 1a5debb79..f4cb4cdc9 100755 --- a/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py +++ b/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -19,21 +19,21 @@ import unittest from base_interfaces_test import BasicInterfaceTest class PEthInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._test_ipv6_pd = True - self._test_ipv6_dhcpc6 = True - self._test_mtu = True - self._test_vlan = True - self._test_qinq = True - self._base_path = ['interfaces', 'pseudo-ethernet'] - self._options = { + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._test_ipv6_pd = True + cls._test_ipv6_dhcpc6 = True + cls._test_mtu = True + cls._test_vlan = True + cls._test_qinq = True + cls._base_path = ['interfaces', 'pseudo-ethernet'] + cls._options = { 'peth0': ['source-interface eth1'], 'peth1': ['source-interface eth1'], } - self._interfaces = list(self._options) - super().setUp() + cls._interfaces = list(cls._options) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py index 8405fc7d0..a9250e3e5 100755 --- a/smoketest/scripts/cli/test_interfaces_tunnel.py +++ b/smoketest/scripts/cli/test_interfaces_tunnel.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -61,22 +61,22 @@ def tunnel_conf(interface): return json.loads(tmp)[0] class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._test_mtu = True - self._base_path = ['interfaces', 'tunnel'] - self.local_v4 = '192.0.2.1' - self.local_v6 = '2001:db8::1' - - self._options = { - 'tun10': ['encapsulation ipip', 'remote-ip 192.0.2.10', 'local-ip ' + self.local_v4], - 'tun20': ['encapsulation gre', 'remote-ip 192.0.2.20', 'local-ip ' + self.local_v4], + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._test_mtu = True + cls._base_path = ['interfaces', 'tunnel'] + cls.local_v4 = '192.0.2.1' + cls.local_v6 = '2001:db8::1' + cls._options = { + 'tun10': ['encapsulation ipip', 'remote-ip 192.0.2.10', 'local-ip ' + cls.local_v4], + 'tun20': ['encapsulation gre', 'remote-ip 192.0.2.20', 'local-ip ' + cls.local_v4], } + cls._interfaces = list(cls._options) - self._interfaces = list(self._options) + def setUp(self): super().setUp() - self.session.set(['interfaces', 'dummy', source_if, 'address', self.local_v4 + '/32']) self.session.set(['interfaces', 'dummy', source_if, 'address', self.local_v6 + '/128']) diff --git a/smoketest/scripts/cli/test_interfaces_vxlan.py b/smoketest/scripts/cli/test_interfaces_vxlan.py index a726aa610..fcc1b15ce 100755 --- a/smoketest/scripts/cli/test_interfaces_vxlan.py +++ b/smoketest/scripts/cli/test_interfaces_vxlan.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -20,17 +20,17 @@ from vyos.configsession import ConfigSession, ConfigSessionError from base_interfaces_test import BasicInterfaceTest class VXLANInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._test_mtu = True - self._base_path = ['interfaces', 'vxlan'] - self._options = { + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._test_mtu = True + cls._base_path = ['interfaces', 'vxlan'] + cls._options = { 'vxlan0': ['vni 10', 'remote 127.0.0.2'], 'vxlan1': ['vni 20', 'group 239.1.1.1', 'source-interface eth0'], } - self._interfaces = list(self._options) - super().setUp() + cls._interfaces = list(cls._options) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_wireguard.py b/smoketest/scripts/cli/test_interfaces_wireguard.py index d9a51b146..e70324f96 100755 --- a/smoketest/scripts/cli/test_interfaces_wireguard.py +++ b/smoketest/scripts/cli/test_interfaces_wireguard.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/smoketest/scripts/cli/test_interfaces_wireless.py b/smoketest/scripts/cli/test_interfaces_wireless.py index 51d97f032..39e8cd5b8 100755 --- a/smoketest/scripts/cli/test_interfaces_wireless.py +++ b/smoketest/scripts/cli/test_interfaces_wireless.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -32,10 +32,11 @@ def get_config_value(interface, key): return tmp[0] class WirelessInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._base_path = ['interfaces', 'wireless'] - self._options = { + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._base_path = ['interfaces', 'wireless'] + cls._options = { 'wlan0': ['physical-device phy0', 'ssid VyOS-WIFI-0', 'type station', 'address 192.0.2.1/30'], 'wlan1': ['physical-device phy0', 'ssid VyOS-WIFI-1', 'country-code se', @@ -45,8 +46,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.BaseTest): 'wlan11': ['physical-device phy1', 'ssid VyOS-WIFI-3', 'country-code se', 'type access-point', 'address 192.0.2.13/30', 'channel 0'], } - self._interfaces = list(self._options) - super().setUp() + cls._interfaces = list(cls._options) def test_wireless_add_single_ip_address(self): # derived method to check if member interfaces are enslaved properly diff --git a/smoketest/scripts/cli/test_interfaces_wirelessmodem.py b/smoketest/scripts/cli/test_interfaces_wirelessmodem.py index 696a6946b..023f57305 100755 --- a/smoketest/scripts/cli/test_interfaces_wirelessmodem.py +++ b/smoketest/scripts/cli/test_interfaces_wirelessmodem.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py new file mode 100755 index 000000000..80e5daa7c --- /dev/null +++ b/smoketest/scripts/cli/test_protocols_bfd.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import unittest + +from vyos.configsession import ConfigSession +from vyos.configsession import ConfigSessionError +from vyos.util import cmd +from vyos.util import process_named_running + +PROCESS_NAME = 'bfdd' +base_path = ['protocols', 'bfd'] + +dum_if = 'dum1001' +peers = { + '192.0.2.10' : { + 'intv_rx' : '500', + 'intv_tx' : '600', + 'multihop' : '', + 'source_addr': '192.0.2.254', + }, + '192.0.2.20' : { + 'echo_mode' : '', + 'intv_echo' : '100', + 'intv_mult' : '100', + 'intv_rx' : '222', + 'intv_tx' : '333', + 'shutdown' : '', + 'source_intf': dum_if, + }, + '2001:db8::a' : { + 'source_addr': '2001:db8::1', + 'source_intf': dum_if, + }, + '2001:db8::b' : { + 'source_addr': '2001:db8::1', + 'multihop' : '', + }, +} + +profiles = { + 'foo' : { + 'echo_mode' : '', + 'intv_echo' : '100', + 'intv_mult' : '101', + 'intv_rx' : '222', + 'intv_tx' : '333', + 'shutdown' : '', + }, + 'bar' : { + 'intv_mult' : '102', + 'intv_rx' : '444', + }, +} + +def getFRRconfig(): + return cmd('vtysh -c "show run" | sed -n "/^bfd/,/^!/p"') + +def getBFDPeerconfig(peer): + return cmd(f'vtysh -c "show run" | sed -n "/^ {peer}/,/^!/p"') + +def getBFDProfileconfig(profile): + return cmd(f'vtysh -c "show run" | sed -n "/^ {profile}/,/^!/p"') + +class TestProtocolsBFD(unittest.TestCase): + def setUp(self): + self.session = ConfigSession(os.getpid()) + + def tearDown(self): + self.session.delete(base_path) + self.session.commit() + del self.session + + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + + def test_bfd_peer(self): + for peer, peer_config in peers.items(): + if 'echo_mode' in peer_config: + self.session.set(base_path + ['peer', peer, 'echo-mode']) + if 'intv_echo' in peer_config: + self.session.set(base_path + ['peer', peer, 'interval', 'echo-interval', peer_config["intv_echo"]]) + if 'intv_mult' in peer_config: + self.session.set(base_path + ['peer', peer, 'interval', 'multiplier', peer_config["intv_mult"]]) + if 'intv_rx' in peer_config: + self.session.set(base_path + ['peer', peer, 'interval', 'receive', peer_config["intv_rx"]]) + if 'intv_tx' in peer_config: + self.session.set(base_path + ['peer', peer, 'interval', 'transmit', peer_config["intv_tx"]]) + if 'multihop' in peer_config: + self.session.set(base_path + ['peer', peer, 'multihop']) + if 'shutdown' in peer_config: + self.session.set(base_path + ['peer', peer, 'shutdown']) + if 'source_addr' in peer_config: + self.session.set(base_path + ['peer', peer, 'source', 'address', peer_config["source_addr"]]) + if 'source_intf' in peer_config: + self.session.set(base_path + ['peer', peer, 'source', 'interface', peer_config["source_intf"]]) + + # commit changes + self.session.commit() + + # Verify FRR bgpd configuration + frrconfig = getFRRconfig() + for peer, peer_config in peers.items(): + tmp = f'peer {peer}' + if 'multihop' in peer_config: + tmp += f' multihop' + if 'source_addr' in peer_config: + tmp += f' local-address {peer_config["source_addr"]}' + if 'source_intf' in peer_config: + tmp += f' interface {peer_config["source_intf"]}' + + self.assertIn(tmp, frrconfig) + peerconfig = getBFDPeerconfig(tmp) + + if 'echo_mode' in peer_config: + self.assertIn(f' echo-mode', peerconfig) + if 'intv_echo' in peer_config: + self.assertIn(f' echo-interval {peer_config["intv_echo"]}', peerconfig) + if 'intv_mult' in peer_config: + self.assertIn(f' detect-multiplier {peer_config["intv_mult"]}', peerconfig) + if 'intv_rx' in peer_config: + self.assertIn(f' receive-interval {peer_config["intv_rx"]}', peerconfig) + if 'intv_tx' in peer_config: + self.assertIn(f' transmit-interval {peer_config["intv_tx"]}', peerconfig) + if 'shutdown' not in peer_config: + self.assertIn(f' no shutdown', peerconfig) + + def test_bfd_profile(self): + peer = '192.0.2.10' + + for profile, profile_config in profiles.items(): + if 'echo_mode' in profile_config: + self.session.set(base_path + ['profile', profile, 'echo-mode']) + if 'intv_echo' in profile_config: + self.session.set(base_path + ['profile', profile, 'interval', 'echo-interval', profile_config["intv_echo"]]) + if 'intv_mult' in profile_config: + self.session.set(base_path + ['profile', profile, 'interval', 'multiplier', profile_config["intv_mult"]]) + if 'intv_rx' in profile_config: + self.session.set(base_path + ['profile', profile, 'interval', 'receive', profile_config["intv_rx"]]) + if 'intv_tx' in profile_config: + self.session.set(base_path + ['profile', profile, 'interval', 'transmit', profile_config["intv_tx"]]) + if 'shutdown' in profile_config: + self.session.set(base_path + ['profile', profile, 'shutdown']) + + self.session.set(base_path + ['peer', peer, 'profile', list(profiles)[0]]) + + # commit changes + self.session.commit() + + # Verify FRR bgpd configuration + for profile, profile_config in profiles.items(): + config = getBFDProfileconfig(f'profile {profile}') + if 'echo_mode' in profile_config: + self.assertIn(f' echo-mode', config) + if 'intv_echo' in profile_config: + self.assertIn(f' echo-interval {profile_config["intv_echo"]}', config) + if 'intv_mult' in profile_config: + self.assertIn(f' detect-multiplier {profile_config["intv_mult"]}', config) + if 'intv_rx' in profile_config: + self.assertIn(f' receive-interval {profile_config["intv_rx"]}', config) + if 'intv_tx' in profile_config: + self.assertIn(f' transmit-interval {profile_config["intv_tx"]}', config) + if 'shutdown' not in profile_config: + self.assertIn(f' no shutdown', config) + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 87d10eb85..b6a6a493c 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -19,6 +19,7 @@ import unittest from vyos.configsession import ConfigSession from vyos.configsession import ConfigSessionError +from vyos.template import is_ipv6 from vyos.util import cmd from vyos.util import process_named_running @@ -30,6 +31,8 @@ route_map_in = 'foo-map-in' route_map_out = 'foo-map-out' prefix_list_in = 'pfx-foo-in' prefix_list_out = 'pfx-foo-out' +prefix_list_in6 = 'pfx-foo-in6' +prefix_list_out6 = 'pfx-foo-out6' neighbor_config = { '192.0.2.1' : { @@ -45,6 +48,8 @@ neighbor_config = { 'local_as' : '300', 'route_map_in' : route_map_in, 'route_map_out': route_map_out, + 'no_send_comm_ext' : '', + 'addpath_all' : '', }, '192.0.2.2' : { 'remote_as' : '200', @@ -54,6 +59,7 @@ neighbor_config = { 'cap_strict' : '', 'pfx_list_in' : prefix_list_in, 'pfx_list_out' : prefix_list_out, + 'no_send_comm_std' : '', }, '192.0.2.3' : { 'description' : 'foo bar baz', @@ -62,6 +68,32 @@ neighbor_config = { 'multi_hop' : '5', 'update_src' : 'lo', }, + '2001:db8::1' : { + 'cap_dynamic' : '', + 'cap_ext_next' : '', + 'remote_as' : '123', + 'adv_interv' : '400', + 'passive' : '', + 'password' : 'VyOS-Secure123', + 'shutdown' : '', + 'cap_over' : '', + 'ttl_security' : '5', + 'local_as' : '300', + 'route_map_in' : route_map_in, + 'route_map_out': route_map_out, + 'no_send_comm_std' : '', + 'addpath_per_as' : '', + }, + '2001:db8::2' : { + 'remote_as' : '456', + 'shutdown' : '', + 'no_cap_nego' : '', + 'port' : '667', + 'cap_strict' : '', + 'pfx_list_in' : prefix_list_in6, + 'pfx_list_out' : prefix_list_out6, + 'no_send_comm_ext' : '', + }, } peer_group_config = { @@ -82,6 +114,7 @@ peer_group_config = { 'local_as' : '300', 'pfx_list_in' : prefix_list_in, 'pfx_list_out' : prefix_list_out, + 'no_send_comm_ext' : '', }, 'baz' : { 'cap_dynamic' : '', @@ -96,10 +129,13 @@ peer_group_config = { } def getFRRBGPconfig(): - return cmd(f'vtysh -c "show run" | sed -n "/router bgp {ASN}/,/^!/p"') + return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN}/,/^!/p"') + +def getFRRBGPVNIconfig(vni): + return cmd(f'vtysh -c "show run" | sed -n "/^ vni {vni}/,/^!/p"') def getFRRRPKIconfig(): - return cmd(f'vtysh -c "show run" | sed -n "/rpki/,/^!/p"') + return cmd(f'vtysh -c "show run" | sed -n "/^rpki/,/^!/p"') class TestProtocolsBGP(unittest.TestCase): def setUp(self): @@ -112,16 +148,26 @@ class TestProtocolsBGP(unittest.TestCase): self.session.set(['policy', 'prefix-list', prefix_list_out, 'rule', '10', 'action', 'permit']) self.session.set(['policy', 'prefix-list', prefix_list_out, 'rule', '10', 'prefix', '192.0.2.128/25']) + self.session.set(['policy', 'prefix-list6', prefix_list_in6, 'rule', '10', 'action', 'permit']) + self.session.set(['policy', 'prefix-list6', prefix_list_in6, 'rule', '10', 'prefix', '2001:db8:1000::/64']) + self.session.set(['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'action', 'deny']) + self.session.set(['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'prefix', '2001:db8:2000::/64']) + def tearDown(self): self.session.delete(['policy', 'route-map', route_map_in]) self.session.delete(['policy', 'route-map', route_map_out]) self.session.delete(['policy', 'prefix-list', prefix_list_in]) self.session.delete(['policy', 'prefix-list', prefix_list_out]) + self.session.delete(['policy', 'prefix-list6', prefix_list_in6]) + self.session.delete(['policy', 'prefix-list6', prefix_list_out6]) self.session.delete(base_path) self.session.commit() del self.session + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + def verify_frr_config(self, peer, peer_config, frrconfig): # recurring patterns to verify for both a simple neighbor and a peer-group if 'cap_dynamic' in peer_config: @@ -158,11 +204,20 @@ class TestProtocolsBGP(unittest.TestCase): self.assertIn(f' neighbor {peer} prefix-list {peer_config["pfx_list_in"]} in', frrconfig) if 'pfx_list_out' in peer_config: self.assertIn(f' neighbor {peer} prefix-list {peer_config["pfx_list_out"]} out', frrconfig) + if 'no_send_comm_std' in peer_config: + self.assertIn(f' no neighbor {peer} send-community', frrconfig) + if 'no_send_comm_ext' in peer_config: + self.assertIn(f' no neighbor {peer} send-community extended', frrconfig) + if 'addpath_all' in peer_config: + self.assertIn(f' neighbor {peer} addpath-tx-all-paths', frrconfig) + if 'addpath_per_as' in peer_config: + self.assertIn(f' neighbor {peer} addpath-tx-bestpath-per-AS', frrconfig) def test_bgp_01_simple(self): router_id = '127.0.0.1' local_pref = '500' + stalepath_time = '60' self.session.set(base_path + ['parameters', 'router-id', router_id]) self.session.set(base_path + ['parameters', 'log-neighbor-changes']) @@ -170,6 +225,8 @@ class TestProtocolsBGP(unittest.TestCase): self.session.set(base_path + ['parameters', 'default', 'local-pref', local_pref]) # Deactivate IPv4 unicast for a peer by default self.session.set(base_path + ['parameters', 'default', 'no-ipv4-unicast']) + self.session.set(base_path + ['parameters', 'graceful-restart', 'stalepath-time', stalepath_time]) + self.session.set(base_path + ['parameters', 'graceful-shutdown']) # commit changes self.session.commit() @@ -181,54 +238,66 @@ class TestProtocolsBGP(unittest.TestCase): self.assertIn(f' bgp log-neighbor-changes', frrconfig) self.assertIn(f' bgp default local-preference {local_pref}', frrconfig) self.assertIn(f' no bgp default ipv4-unicast', frrconfig) + self.assertIn(f' bgp graceful-restart stalepath-time {stalepath_time}', frrconfig) + self.assertIn(f' bgp graceful-shutdown', frrconfig) - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) def test_bgp_02_neighbors(self): # Test out individual neighbor configuration items, not all of them are # also available to a peer-group! - for neighbor, config in neighbor_config.items(): - if 'adv_interv' in config: - self.session.set(base_path + ['neighbor', neighbor, 'advertisement-interval', config["adv_interv"]]) - if 'cap_dynamic' in config: - self.session.set(base_path + ['neighbor', neighbor, 'capability', 'dynamic']) - if 'cap_ext_next' in config: - self.session.set(base_path + ['neighbor', neighbor, 'capability', 'extended-nexthop']) - if 'description' in config: - self.session.set(base_path + ['neighbor', neighbor, 'description', config["description"]]) - if 'no_cap_nego' in config: - self.session.set(base_path + ['neighbor', neighbor, 'disable-capability-negotiation']) - if 'multi_hop' in config: - self.session.set(base_path + ['neighbor', neighbor, 'ebgp-multihop', config["multi_hop"]]) - if 'local_as' in config: - self.session.set(base_path + ['neighbor', neighbor, 'local-as', config["local_as"]]) - if 'cap_over' in config: - self.session.set(base_path + ['neighbor', neighbor, 'override-capability']) - if 'passive' in config: - self.session.set(base_path + ['neighbor', neighbor, 'passive']) - if 'password' in config: - self.session.set(base_path + ['neighbor', neighbor, 'password', config["password"]]) - if 'port' in config: - self.session.set(base_path + ['neighbor', neighbor, 'port', config["port"]]) - if 'remote_as' in config: - self.session.set(base_path + ['neighbor', neighbor, 'remote-as', config["remote_as"]]) - if 'cap_strict' in config: - self.session.set(base_path + ['neighbor', neighbor, 'strict-capability-match']) - if 'shutdown' in config: - self.session.set(base_path + ['neighbor', neighbor, 'shutdown']) - if 'ttl_security' in config: - self.session.set(base_path + ['neighbor', neighbor, 'ttl-security', 'hops', config["ttl_security"]]) - if 'update_src' in config: - self.session.set(base_path + ['neighbor', neighbor, 'update-source', config["update_src"]]) - if 'route_map_in' in config: - self.session.set(base_path + ['neighbor', neighbor, 'address-family', 'ipv4-unicast', 'route-map', 'import', config["route_map_in"]]) - if 'route_map_out' in config: - self.session.set(base_path + ['neighbor', neighbor, 'address-family', 'ipv4-unicast', 'route-map', 'export', config["route_map_out"]]) - if 'pfx_list_in' in config: - self.session.set(base_path + ['neighbor', neighbor, 'address-family', 'ipv4-unicast', 'prefix-list', 'import', config["pfx_list_in"]]) - if 'pfx_list_out' in config: - self.session.set(base_path + ['neighbor', neighbor, 'address-family', 'ipv4-unicast', 'prefix-list', 'export', config["pfx_list_out"]]) + for peer, peer_config in neighbor_config.items(): + afi = 'ipv4-unicast' + if is_ipv6(peer): + afi = 'ipv6-unicast' + + if 'adv_interv' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'advertisement-interval', peer_config["adv_interv"]]) + if 'cap_dynamic' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'capability', 'dynamic']) + if 'cap_ext_next' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'capability', 'extended-nexthop']) + if 'description' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'description', peer_config["description"]]) + if 'no_cap_nego' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'disable-capability-negotiation']) + if 'multi_hop' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'ebgp-multihop', peer_config["multi_hop"]]) + if 'local_as' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'local-as', peer_config["local_as"]]) + if 'cap_over' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'override-capability']) + if 'passive' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'passive']) + if 'password' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'password', peer_config["password"]]) + if 'port' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'port', peer_config["port"]]) + if 'remote_as' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'remote-as', peer_config["remote_as"]]) + if 'cap_strict' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'strict-capability-match']) + if 'shutdown' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'shutdown']) + if 'ttl_security' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'ttl-security', 'hops', peer_config["ttl_security"]]) + if 'update_src' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'update-source', peer_config["update_src"]]) + if 'route_map_in' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'route-map', 'import', peer_config["route_map_in"]]) + if 'route_map_out' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'route-map', 'export', peer_config["route_map_out"]]) + if 'pfx_list_in' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'prefix-list', 'import', peer_config["pfx_list_in"]]) + if 'pfx_list_out' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'prefix-list', 'export', peer_config["pfx_list_out"]]) + if 'no_send_comm_std' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'disable-send-community', 'standard']) + if 'no_send_comm_ext' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'disable-send-community', 'extended']) + if 'addpath_all' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'addpath-tx-all']) + if 'addpath_per_as' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'addpath-tx-per-as']) # commit changes self.session.commit() @@ -238,11 +307,11 @@ class TestProtocolsBGP(unittest.TestCase): self.assertIn(f'router bgp {ASN}', frrconfig) for peer, peer_config in neighbor_config.items(): - if 'adv_interv' in config: + if 'adv_interv' in peer_config: self.assertIn(f' neighbor {peer} advertisement-interval {peer_config["adv_interv"]}', frrconfig) - if 'port' in config: + if 'port' in peer_config: self.assertIn(f' neighbor {peer} port {peer_config["port"]}', frrconfig) - if 'cap_strict' in config: + if 'cap_strict' in peer_config: self.assertIn(f' neighbor {peer} strict-capability-match', frrconfig) self.verify_frr_config(peer, peer_config, frrconfig) @@ -284,6 +353,14 @@ class TestProtocolsBGP(unittest.TestCase): self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'prefix-list', 'import', config["pfx_list_in"]]) if 'pfx_list_out' in config: self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'prefix-list', 'export', config["pfx_list_out"]]) + if 'no_send_comm_std' in config: + self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'disable-send-community', 'standard']) + if 'no_send_comm_ext' in config: + self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'disable-send-community', 'extended']) + if 'addpath_all' in config: + self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'addpath-tx-all']) + if 'addpath_per_as' in config: + self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'addpath-tx-per-as']) # commit changes self.session.commit() @@ -311,7 +388,7 @@ class TestProtocolsBGP(unittest.TestCase): } # We want to redistribute ... - redistributes = ['connected', 'kernel', 'ospf', 'rip', 'static'] + redistributes = ['connected', 'isis', 'kernel', 'ospf', 'rip', 'static'] for redistribute in redistributes: self.session.set(base_path + ['address-family', 'ipv4-unicast', 'redistribute', redistribute]) @@ -348,12 +425,12 @@ class TestProtocolsBGP(unittest.TestCase): def test_bgp_05_afi_ipv6(self): networks = { '2001:db8:100::/48' : { - }, + }, '2001:db8:200::/48' : { - }, + }, '2001:db8:300::/48' : { 'summary_only' : '', - }, + }, } # We want to redistribute ... @@ -420,38 +497,33 @@ class TestProtocolsBGP(unittest.TestCase): self.assertIn(f' bgp listen range {prefix} peer-group {peer_group}', frrconfig) - def test_bgp_07_rpki(self): - rpki_path = ['protocols', 'rpki'] - init_tmo = '50' - polling = '400' - preference = '100' - timeout = '900' - - cache = { - 'foo' : { 'address' : '1.1.1.1', 'port' : '8080' }, -# T3253 only one peer supported -# 'bar' : { 'address' : '2.2.2.2', 'port' : '9090' }, - } - - self.session.set(rpki_path + ['polling-period', polling]) - self.session.set(rpki_path + ['preference', preference]) - - for name, config in cache.items(): - self.session.set(rpki_path + ['cache', name, 'address', config['address']]) - self.session.set(rpki_path + ['cache', name, 'port', config['port']]) + def test_bgp_07_l2vpn_evpn(self): + vnis = ['10010', '10020', '10030'] + neighbors = ['192.0.2.10', '192.0.2.20', '192.0.2.30'] + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-all-vni']) + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-default-gw']) + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-svi-ip']) + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'flooding', 'disable']) + for vni in vnis: + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni, 'advertise-default-gw']) + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni, 'advertise-svi-ip']) # commit changes self.session.commit() # Verify FRR bgpd configuration - frrconfig = getFRRRPKIconfig() - self.assertIn(f'rpki polling_period {polling}', frrconfig) - - for name, config in cache.items(): - self.assertIn('rpki cache {address} {port} preference 1'.format(**config), frrconfig) - - self.session.delete(rpki_path) - + frrconfig = getFRRBGPconfig() + self.assertIn(f'router bgp {ASN}', frrconfig) + self.assertIn(f' address-family l2vpn evpn', frrconfig) + self.assertIn(f' advertise-all-vni', frrconfig) + self.assertIn(f' advertise-default-gw', frrconfig) + self.assertIn(f' advertise-svi-ip', frrconfig) + self.assertIn(f' flooding disable', frrconfig) + for vni in vnis: + vniconfig = getFRRBGPVNIconfig(vni) + self.assertIn(f'vni {vni}', vniconfig) + self.assertIn(f' advertise-default-gw', vniconfig) + self.assertIn(f' advertise-svi-ip', vniconfig) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py index d47838d8c..0ca8bb3bd 100755 --- a/smoketest/scripts/cli/test_protocols_ospf.py +++ b/smoketest/scripts/cli/test_protocols_ospf.py @@ -30,6 +30,9 @@ route_map = 'foo-bar-baz10' def getFRROSPFconfig(): return cmd('vtysh -c "show run" | sed -n "/router ospf/,/^!/p"') +def getFRRInterfaceConfig(interface): + return cmd(f'vtysh -c "show run" | sed -n "/^interface {interface}$/,/^!/p"') + class TestProtocolsOSPF(unittest.TestCase): def setUp(self): self.session = ConfigSession(os.getpid()) @@ -85,7 +88,7 @@ class TestProtocolsOSPF(unittest.TestCase): def test_ospf_03_access_list(self): acl = '100' seq = '10' - protocols = ['bgp', 'connected', 'kernel', 'rip', 'static'] + protocols = ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static'] self.session.set(['policy', 'access-list', acl, 'rule', seq, 'action', 'permit']) self.session.set(['policy', 'access-list', acl, 'rule', seq, 'source', 'any']) @@ -212,7 +215,7 @@ class TestProtocolsOSPF(unittest.TestCase): def test_ospf_08_redistribute(self): metric = '15' metric_type = '1' - redistribute = ['bgp', 'connected', 'kernel', 'rip', 'static'] + redistribute = ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static'] for protocol in redistribute: self.session.set(base_path + ['redistribute', protocol, 'metric', metric]) @@ -232,24 +235,8 @@ class TestProtocolsOSPF(unittest.TestCase): else: self.assertIn(f' redistribute {protocol} metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig) - - def test_ospf_09_area(self): - area = '0' + def test_ospf_09_virtual_link(self): networks = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'] - for network in networks: - self.session.set(base_path + ['area', area, 'network', network]) - - # commit changes - self.session.commit() - - # Verify FRR ospfd configuration - frrconfig = getFRROSPFconfig() - self.assertIn(f'router ospf', frrconfig) - for network in networks: - self.assertIn(f' network {network} area {area}', frrconfig) - - - def test_ospf_10_virtual_link(self): area = '10' shortcut = 'enable' virtual_link = '192.0.2.1' @@ -263,6 +250,8 @@ class TestProtocolsOSPF(unittest.TestCase): self.session.set(base_path + ['area', area, 'virtual-link', virtual_link, 'retransmit-interval', retransmit]) self.session.set(base_path + ['area', area, 'virtual-link', virtual_link, 'transmit-delay', transmit]) self.session.set(base_path + ['area', area, 'virtual-link', virtual_link, 'dead-interval', dead]) + for network in networks: + self.session.set(base_path + ['area', area, 'network', network]) # commit changes self.session.commit() @@ -272,6 +261,39 @@ class TestProtocolsOSPF(unittest.TestCase): self.assertIn(f'router ospf', frrconfig) self.assertIn(f' area {area} shortcut {shortcut}', frrconfig) self.assertIn(f' area {area} virtual-link {virtual_link} hello-interval {hello} retransmit-interval {retransmit} transmit-delay {transmit} dead-interval {dead}', frrconfig) + for network in networks: + self.assertIn(f' network {network} area {area}', frrconfig) + + def test_ospf_10_interface_configureation(self): + interfaces = Section.interfaces('ethernet') + password = 'vyos1234' + bandwidth = '10000' + cost = '150' + network = 'point-to-point' + priority = '200' + + for interface in interfaces: + self.session.set(base_path + ['interface', interface, 'authentication', 'plaintext-password', password]) + self.session.set(base_path + ['interface', interface, 'bandwidth', bandwidth]) + self.session.set(base_path + ['interface', interface, 'bfd']) + self.session.set(base_path + ['interface', interface, 'cost', cost]) + self.session.set(base_path + ['interface', interface, 'mtu-ignore']) + self.session.set(base_path + ['interface', interface, 'network', network]) + self.session.set(base_path + ['interface', interface, 'priority', priority]) + + # commit changes + self.session.commit() + + for interface in interfaces: + config = getFRRInterfaceConfig(interface) + self.assertIn(f'interface {interface}', config) + self.assertIn(f' ip ospf authentication-key {password}', config) + self.assertIn(f' ip ospf bfd', config) + self.assertIn(f' ip ospf cost {cost}', config) + self.assertIn(f' ip ospf mtu-ignore', config) + self.assertIn(f' ip ospf network {network}', config) + self.assertIn(f' ip ospf priority {priority}', config) + self.assertIn(f' bandwidth {bandwidth}', config) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_ospfv3.py b/smoketest/scripts/cli/test_protocols_ospfv3.py index 297d5d996..754c4488f 100755 --- a/smoketest/scripts/cli/test_protocols_ospfv3.py +++ b/smoketest/scripts/cli/test_protocols_ospfv3.py @@ -25,10 +25,15 @@ from vyos.util import process_named_running PROCESS_NAME = 'ospf6d' base_path = ['protocols', 'ospfv3'] +router_id = '192.0.2.1' +default_area = '0' def getFRROSPFconfig(): return cmd('vtysh -c "show run" | sed -n "/router ospf6/,/^!/p"') +def getFRRIFconfig(iface): + return cmd(f'vtysh -c "show run" | sed -n "/^interface {iface}/,/^!/p"') + class TestProtocolsOSPFv3(unittest.TestCase): def setUp(self): self.session = ConfigSession(os.getpid()) @@ -43,23 +48,21 @@ class TestProtocolsOSPFv3(unittest.TestCase): def test_ospfv3_01_basic(self): - area = '0' seq = '10' prefix = '2001:db8::/32' acl_name = 'foo-acl-100' - router_id = '192.0.2.1' self.session.set(['policy', 'access-list6', acl_name, 'rule', seq, 'action', 'permit']) self.session.set(['policy', 'access-list6', acl_name, 'rule', seq, 'source', 'any']) self.session.set(base_path + ['parameters', 'router-id', router_id]) - self.session.set(base_path + ['area', area, 'range', prefix, 'advertise']) - self.session.set(base_path + ['area', area, 'export-list', acl_name]) - self.session.set(base_path + ['area', area, 'import-list', acl_name]) + self.session.set(base_path + ['area', default_area, 'range', prefix, 'advertise']) + self.session.set(base_path + ['area', default_area, 'export-list', acl_name]) + self.session.set(base_path + ['area', default_area, 'import-list', acl_name]) interfaces = Section.interfaces('ethernet') for interface in interfaces: - self.session.set(base_path + ['area', area, 'interface', interface]) + self.session.set(base_path + ['area', default_area, 'interface', interface]) # commit changes self.session.commit() @@ -67,13 +70,13 @@ class TestProtocolsOSPFv3(unittest.TestCase): # Verify FRR ospfd configuration frrconfig = getFRROSPFconfig() self.assertIn(f'router ospf6', frrconfig) - self.assertIn(f' area {area} range {prefix}', frrconfig) + self.assertIn(f' area {default_area} range {prefix}', frrconfig) self.assertIn(f' ospf6 router-id {router_id}', frrconfig) - self.assertIn(f' area {area} import-list {acl_name}', frrconfig) - self.assertIn(f' area {area} export-list {acl_name}', frrconfig) + self.assertIn(f' area {default_area} import-list {acl_name}', frrconfig) + self.assertIn(f' area {default_area} export-list {acl_name}', frrconfig) for interface in interfaces: - self.assertIn(f' interface {interface} area {area}', frrconfig) + self.assertIn(f' interface {interface} area {default_area}', frrconfig) self.session.delete(['policy', 'access-list6', acl_name]) @@ -118,6 +121,46 @@ class TestProtocolsOSPFv3(unittest.TestCase): for protocol in redistribute: self.assertIn(f' redistribute {protocol} route-map {route_map}', frrconfig) + def test_ospfv3_0104_interfaces(self): + + self.session.set(base_path + ['parameters', 'router-id', router_id]) + self.session.set(base_path + ['area', default_area]) + + cost = '100' + priority = '10' + interfaces = Section.interfaces('ethernet') + for interface in interfaces: + if_base = base_path + ['interface', interface] + self.session.set(if_base + ['bfd']) + self.session.set(if_base + ['cost', cost]) + self.session.set(if_base + ['instance-id', '0']) + self.session.set(if_base + ['mtu-ignore']) + self.session.set(if_base + ['network', 'point-to-point']) + self.session.set(if_base + ['passive']) + self.session.set(if_base + ['priority', priority]) + cost = str(int(cost) + 10) + priority = str(int(priority) + 5) + + # commit changes + self.session.commit() + + # Verify FRR ospfd configuration + frrconfig = getFRROSPFconfig() + self.assertIn(f'router ospf6', frrconfig) + + cost = '100' + priority = '10' + for interface in interfaces: + if_config = getFRRIFconfig(interface) + self.assertIn(f'interface {interface}', if_config) + self.assertIn(f' ipv6 ospf6 bfd', if_config) + self.assertIn(f' ipv6 ospf6 cost {cost}', if_config) + self.assertIn(f' ipv6 ospf6 mtu-ignore', if_config) + self.assertIn(f' ipv6 ospf6 network point-to-point', if_config) + self.assertIn(f' ipv6 ospf6 passive', if_config) + self.assertIn(f' ipv6 ospf6 priority {priority}', if_config) + cost = str(int(cost) + 10) + priority = str(int(priority) + 5) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_rip.py b/smoketest/scripts/cli/test_protocols_rip.py new file mode 100755 index 000000000..f42ea0c0a --- /dev/null +++ b/smoketest/scripts/cli/test_protocols_rip.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import unittest + +from vyos.configsession import ConfigSession +from vyos.ifconfig import Section +from vyos.util import cmd +from vyos.util import process_named_running + +PROCESS_NAME = 'ripd' +acl_in = '198' +acl_out = '199' +prefix_list_in = 'foo-prefix' +prefix_list_out = 'bar-prefix' +route_map = 'FooBar123' + +base_path = ['protocols', 'rip'] + +def getFRRconfig(): + return cmd('vtysh -c "show run" | sed -n "/router rip/,/^!/p"') + +class TestProtocolsRIP(unittest.TestCase): + def setUp(self): + self.session = ConfigSession(os.getpid()) + + self.session.set(['policy', 'access-list', acl_in, 'rule', '10', 'action', 'permit']) + self.session.set(['policy', 'access-list', acl_in, 'rule', '10', 'source', 'any']) + self.session.set(['policy', 'access-list', acl_in, 'rule', '10', 'destination', 'any']) + self.session.set(['policy', 'access-list', acl_out, 'rule', '20', 'action', 'deny']) + self.session.set(['policy', 'access-list', acl_out, 'rule', '20', 'source', 'any']) + self.session.set(['policy', 'access-list', acl_out, 'rule', '20', 'destination', 'any']) + self.session.set(['policy', 'prefix-list', prefix_list_in, 'rule', '100', 'action', 'permit']) + self.session.set(['policy', 'prefix-list', prefix_list_in, 'rule', '100', 'prefix', '192.0.2.0/24']) + self.session.set(['policy', 'prefix-list', prefix_list_out, 'rule', '200', 'action', 'deny']) + self.session.set(['policy', 'prefix-list', prefix_list_out, 'rule', '200', 'prefix', '192.0.2.0/24']) + self.session.set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) + + def tearDown(self): + self.session.delete(base_path) + self.session.delete(['policy', 'access-list', acl_in]) + self.session.delete(['policy', 'access-list', acl_out]) + self.session.delete(['policy', 'prefix-list', prefix_list_in]) + self.session.delete(['policy', 'prefix-list', prefix_list_out]) + self.session.delete(['policy', 'route-map', route_map]) + + self.session.commit() + del self.session + + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + + def test_rip(self): + distance = '40' + network_distance = '66' + metric = '8' + interfaces = Section.interfaces('ethernet') + neighbors = ['1.2.3.4', '1.2.3.5', '1.2.3.6'] + networks = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'] + redistribute = ['bgp', 'connected', 'isis', 'kernel', 'ospf', 'static'] + timer_garbage = '888' + timer_timeout = '1000' + timer_update = '90' + + self.session.set(base_path + ['default-distance', distance]) + self.session.set(base_path + ['default-information', 'originate']) + self.session.set(base_path + ['default-metric', metric]) + self.session.set(base_path + ['distribute-list', 'access-list', 'in', acl_in]) + self.session.set(base_path + ['distribute-list', 'access-list', 'out', acl_out]) + self.session.set(base_path + ['distribute-list', 'prefix-list', 'in', prefix_list_in]) + self.session.set(base_path + ['distribute-list', 'prefix-list', 'out', prefix_list_out]) + self.session.set(base_path + ['passive-interface', 'default']) + self.session.set(base_path + ['timers', 'garbage-collection', timer_garbage]) + self.session.set(base_path + ['timers', 'timeout', timer_timeout]) + self.session.set(base_path + ['timers', 'update', timer_update]) + for interface in interfaces: + self.session.set(base_path + ['interface', interface]) + self.session.set(base_path + ['distribute-list', 'interface', interface, 'access-list', 'in', acl_in]) + self.session.set(base_path + ['distribute-list', 'interface', interface, 'access-list', 'out', acl_out]) + self.session.set(base_path + ['distribute-list', 'interface', interface, 'prefix-list', 'in', prefix_list_in]) + self.session.set(base_path + ['distribute-list', 'interface', interface, 'prefix-list', 'out', prefix_list_out]) + for neighbor in neighbors: + self.session.set(base_path + ['neighbor', neighbor]) + for network in networks: + self.session.set(base_path + ['network', network]) + self.session.set(base_path + ['network-distance', network, 'distance', network_distance]) + self.session.set(base_path + ['route', network]) + for proto in redistribute: + self.session.set(base_path + ['redistribute', proto, 'metric', metric]) + self.session.set(base_path + ['redistribute', proto, 'route-map', route_map]) + + + # commit changes + self.session.commit() + + # Verify FRR ospfd configuration + frrconfig = getFRRconfig() + self.assertIn(f'router rip', frrconfig) + self.assertIn(f' distance {distance}', frrconfig) + self.assertIn(f' default-information originate', frrconfig) + self.assertIn(f' default-metric {metric}', frrconfig) + self.assertIn(f' distribute-list {acl_in} in', frrconfig) + self.assertIn(f' distribute-list {acl_out} out', frrconfig) + self.assertIn(f' distribute-list prefix {prefix_list_in} in', frrconfig) + self.assertIn(f' distribute-list prefix {prefix_list_out} out', frrconfig) + self.assertIn(f' passive-interface default', frrconfig) + self.assertIn(f' timers basic {timer_update} {timer_timeout} {timer_garbage}', frrconfig) + for interface in interfaces: + self.assertIn(f' network {interface}', frrconfig) + self.assertIn(f' distribute-list {acl_in} in {interface}', frrconfig) + self.assertIn(f' distribute-list {acl_out} out {interface}', frrconfig) + self.assertIn(f' distribute-list prefix {prefix_list_in} in {interface}', frrconfig) + self.assertIn(f' distribute-list prefix {prefix_list_out} out {interface}', frrconfig) + for neighbor in neighbors: + self.assertIn(f' neighbor {neighbor}', frrconfig) + for network in networks: + self.assertIn(f' network {network}', frrconfig) + self.assertIn(f' distance {network_distance} {network}', frrconfig) + self.assertIn(f' route {network}', frrconfig) + for proto in redistribute: + self.assertIn(f' redistribute {proto} metric {metric} route-map {route_map}', frrconfig) + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_ripng.py b/smoketest/scripts/cli/test_protocols_ripng.py new file mode 100755 index 000000000..6850b60d3 --- /dev/null +++ b/smoketest/scripts/cli/test_protocols_ripng.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import unittest + +from vyos.configsession import ConfigSession +from vyos.ifconfig import Section +from vyos.util import cmd +from vyos.util import process_named_running + +PROCESS_NAME = 'ripngd' +acl_in = '198' +acl_out = '199' +prefix_list_in = 'foo-prefix' +prefix_list_out = 'bar-prefix' +route_map = 'FooBar123' + +base_path = ['protocols', 'ripng'] + +def getFRRconfig(): + return cmd('vtysh -c "show run" | sed -n "/router ripng/,/^!/p"') + +class TestProtocolsRIPng(unittest.TestCase): + def setUp(self): + self.session = ConfigSession(os.getpid()) + + self.session.set(['policy', 'access-list6', acl_in, 'rule', '10', 'action', 'permit']) + self.session.set(['policy', 'access-list6', acl_in, 'rule', '10', 'source', 'any']) + self.session.set(['policy', 'access-list6', acl_out, 'rule', '20', 'action', 'deny']) + self.session.set(['policy', 'access-list6', acl_out, 'rule', '20', 'source', 'any']) + self.session.set(['policy', 'prefix-list6', prefix_list_in, 'rule', '100', 'action', 'permit']) + self.session.set(['policy', 'prefix-list6', prefix_list_in, 'rule', '100', 'prefix', '2001:db8::/32']) + self.session.set(['policy', 'prefix-list6', prefix_list_out, 'rule', '200', 'action', 'deny']) + self.session.set(['policy', 'prefix-list6', prefix_list_out, 'rule', '200', 'prefix', '2001:db8::/32']) + self.session.set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) + + def tearDown(self): + self.session.delete(base_path) + self.session.delete(['policy', 'access-list6', acl_in]) + self.session.delete(['policy', 'access-list6', acl_out]) + self.session.delete(['policy', 'prefix-list6', prefix_list_in]) + self.session.delete(['policy', 'prefix-list6', prefix_list_out]) + self.session.delete(['policy', 'route-map', route_map]) + + self.session.commit() + del self.session + + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + + def test_ripng(self): + metric = '8' + interfaces = Section.interfaces('ethernet') + aggregates = ['2001:db8:1000::/48', '2001:db8:2000::/48', '2001:db8:3000::/48'] + networks = ['2001:db8:1000::/64', '2001:db8:1001::/64', '2001:db8:2000::/64', '2001:db8:2001::/64'] + redistribute = ['bgp', 'connected', 'kernel', 'ospfv3', 'static'] + timer_garbage = '888' + timer_timeout = '1000' + timer_update = '90' + + self.session.set(base_path + ['default-information', 'originate']) + self.session.set(base_path + ['default-metric', metric]) + self.session.set(base_path + ['distribute-list', 'access-list', 'in', acl_in]) + self.session.set(base_path + ['distribute-list', 'access-list', 'out', acl_out]) + self.session.set(base_path + ['distribute-list', 'prefix-list', 'in', prefix_list_in]) + self.session.set(base_path + ['distribute-list', 'prefix-list', 'out', prefix_list_out]) + self.session.set(base_path + ['passive-interface', 'default']) + self.session.set(base_path + ['timers', 'garbage-collection', timer_garbage]) + self.session.set(base_path + ['timers', 'timeout', timer_timeout]) + self.session.set(base_path + ['timers', 'update', timer_update]) + for aggregate in aggregates: + self.session.set(base_path + ['aggregate-address', aggregate]) + + for interface in interfaces: + self.session.set(base_path + ['interface', interface]) + self.session.set(base_path + ['distribute-list', 'interface', interface, 'access-list', 'in', acl_in]) + self.session.set(base_path + ['distribute-list', 'interface', interface, 'access-list', 'out', acl_out]) + self.session.set(base_path + ['distribute-list', 'interface', interface, 'prefix-list', 'in', prefix_list_in]) + self.session.set(base_path + ['distribute-list', 'interface', interface, 'prefix-list', 'out', prefix_list_out]) + for network in networks: + self.session.set(base_path + ['network', network]) + self.session.set(base_path + ['route', network]) + for proto in redistribute: + self.session.set(base_path + ['redistribute', proto, 'metric', metric]) + self.session.set(base_path + ['redistribute', proto, 'route-map', route_map]) + + + # commit changes + self.session.commit() + + # Verify FRR ospfd configuration + frrconfig = getFRRconfig() + self.assertIn(f'router ripng', frrconfig) + self.assertIn(f' default-information originate', frrconfig) + self.assertIn(f' default-metric {metric}', frrconfig) + self.assertIn(f' ipv6 distribute-list {acl_in} in', frrconfig) + self.assertIn(f' ipv6 distribute-list {acl_out} out', frrconfig) + self.assertIn(f' ipv6 distribute-list prefix {prefix_list_in} in', frrconfig) + self.assertIn(f' ipv6 distribute-list prefix {prefix_list_out} out', frrconfig) + self.assertIn(f' passive-interface default', frrconfig) + self.assertIn(f' timers basic {timer_update} {timer_timeout} {timer_garbage}', frrconfig) + for aggregate in aggregates: + self.assertIn(f' aggregate-address {aggregate}', frrconfig) + for interface in interfaces: + self.assertIn(f' network {interface}', frrconfig) + self.assertIn(f' ipv6 distribute-list {acl_in} in {interface}', frrconfig) + self.assertIn(f' ipv6 distribute-list {acl_out} out {interface}', frrconfig) + self.assertIn(f' ipv6 distribute-list prefix {prefix_list_in} in {interface}', frrconfig) + self.assertIn(f' ipv6 distribute-list prefix {prefix_list_out} out {interface}', frrconfig) + for network in networks: + self.assertIn(f' network {network}', frrconfig) + self.assertIn(f' route {network}', frrconfig) + for proto in redistribute: + if proto == 'ospfv3': + proto = 'ospf6' + self.assertIn(f' redistribute {proto} metric {metric} route-map {route_map}', frrconfig) + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_rpki.py b/smoketest/scripts/cli/test_protocols_rpki.py new file mode 100755 index 000000000..bec4ef76f --- /dev/null +++ b/smoketest/scripts/cli/test_protocols_rpki.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import unittest + +from vyos.configsession import ConfigSession +from vyos.configsession import ConfigSessionError +from vyos.util import cmd +from vyos.util import process_named_running + +base_path = ['protocols', 'rpki'] +PROCESS_NAME = 'bgpd' + +rpki_known_hosts = '/config/auth/known_hosts' +rpki_ssh_key = '/config/auth/id_rsa_rpki' +rpki_ssh_pub = f'{rpki_ssh_key}.pub' + +def getFRRRPKIconfig(): + return cmd(f'vtysh -c "show run" | sed -n "/rpki/,/^!/p"') + +class TestProtocolsRPKI(unittest.TestCase): + def setUp(self): + self.session = ConfigSession(os.getpid()) + + def tearDown(self): + self.session.delete(base_path) + self.session.commit() + del self.session + + # Nothing RPKI specific should be left over in the config + # + # Disabled until T3266 is resolved + # frrconfig = getFRRRPKIconfig() + # self.assertNotIn('rpki', frrconfig) + + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + + def test_rpki(self): + polling = '7200' + cache = { + '192.0.2.1' : { + 'port' : '8080', + 'preference' : '1' + }, + '192.0.2.2' : { + 'port' : '9090', + 'preference' : '2' + }, + '2001:db8::1' : { + 'port' : '1234', + 'preference' : '3' + }, + '2001:db8::2' : { + 'port' : '5678', + 'preference' : '4' + }, + } + + self.session.set(base_path + ['polling-period', polling]) + for peer, peer_config in cache.items(): + self.session.set(base_path + ['cache', peer, 'port', peer_config['port']]) + self.session.set(base_path + ['cache', peer, 'preference', peer_config['preference']]) + + # commit changes + self.session.commit() + + # Verify FRR configuration + frrconfig = getFRRRPKIconfig() + self.assertIn(f'rpki polling_period {polling}', frrconfig) + + for peer, peer_config in cache.items(): + port = peer_config['port'] + preference = peer_config['preference'] + self.assertIn(f'rpki cache {peer} {port} preference {preference}', frrconfig) + + def test_rpki_ssh(self): + polling = '7200' + cache = { + '192.0.2.3' : { + 'port' : '1234', + 'username' : 'foo', + 'preference' : '10' + }, + '192.0.2.4' : { + 'port' : '5678', + 'username' : 'bar', + 'preference' : '20' + }, + } + + self.session.set(base_path + ['polling-period', polling]) + + for peer, peer_config in cache.items(): + self.session.set(base_path + ['cache', peer, 'port', peer_config['port']]) + self.session.set(base_path + ['cache', peer, 'preference', peer_config['preference']]) + self.session.set(base_path + ['cache', peer, 'ssh', 'username', peer_config['username']]) + self.session.set(base_path + ['cache', peer, 'ssh', 'public-key-file', rpki_ssh_pub]) + self.session.set(base_path + ['cache', peer, 'ssh', 'private-key-file', rpki_ssh_key]) + self.session.set(base_path + ['cache', peer, 'ssh', 'known-hosts-file', rpki_known_hosts]) + + # commit changes + self.session.commit() + + # Verify FRR configuration + frrconfig = getFRRRPKIconfig() + self.assertIn(f'rpki polling_period {polling}', frrconfig) + + for peer, peer_config in cache.items(): + port = peer_config['port'] + preference = peer_config['preference'] + username = peer_config['username'] + self.assertIn(f'rpki cache {peer} {port} {username} {rpki_ssh_key} {rpki_known_hosts} preference {preference}', frrconfig) + + + def test_rpki_verify_preference(self): + cache = { + '192.0.2.1' : { + 'port' : '8080', + 'preference' : '1' + }, + '192.0.2.2' : { + 'port' : '9090', + 'preference' : '1' + }, + } + + for peer, peer_config in cache.items(): + self.session.set(base_path + ['cache', peer, 'port', peer_config['port']]) + self.session.set(base_path + ['cache', peer, 'preference', peer_config['preference']]) + + # check validate() - preferences must be unique + with self.assertRaises(ConfigSessionError): + self.session.commit() + + +if __name__ == '__main__': + # Create OpenSSH keypair used in RPKI tests + if not os.path.isfile(rpki_ssh_key): + cmd(f'ssh-keygen -t rsa -f {rpki_ssh_key} -N ""') + + if not os.path.isfile(rpki_known_hosts): + cmd(f'touch {rpki_known_hosts}') + + unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py new file mode 100755 index 000000000..cf591f060 --- /dev/null +++ b/smoketest/scripts/cli/test_protocols_static.py @@ -0,0 +1,385 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import unittest + +from vyos.configsession import ConfigSession +from vyos.configsession import ConfigSessionError +from vyos.template import is_ipv6 +from vyos.util import cmd + +base_path = ['protocols', 'static'] +vrf_path = ['protocols', 'vrf'] + +def getFRRCconfig(vrf=None): + if vrf: + return cmd(f'vtysh -c "show run" | sed -n "/^vrf {vrf}/,/^!/p"') + else: + return cmd(f'vtysh -c "show run" | sed -n "/^ip route/,/^!/p"') + +routes = { + '10.0.0.0/8' : { + 'next_hop' : { + '192.0.2.100' : { 'distance' : '100' }, + '192.0.2.110' : { 'distance' : '110', 'interface' : 'eth0' }, + '192.0.2.120' : { 'distance' : '120', 'disable' : '' }, + }, + 'interface' : { + 'eth0' : { 'distance' : '130' }, + 'eth1' : { 'distance' : '140' }, + }, + 'blackhole' : { 'distance' : '250', 'tag' : '500' }, + }, + '172.16.0.0/12' : { + 'interface' : { + 'eth0' : { 'distance' : '50', 'vrf' : 'black' }, + 'eth1' : { 'distance' : '60', 'vrf' : 'black' }, + }, + 'blackhole' : { 'distance' : '90' }, + }, + '192.0.2.0/24' : { + 'interface' : { + 'eth0' : { 'distance' : '50', 'vrf' : 'black' }, + 'eth1' : { 'disable' : '' }, + }, + 'blackhole' : { 'distance' : '90' }, + }, + '100.64.0.0/10' : { + 'blackhole' : { }, + }, + '2001:db8:100::/40' : { + 'next_hop' : { + '2001:db8::1' : { 'distance' : '10' }, + '2001:db8::2' : { 'distance' : '20', 'interface' : 'eth0' }, + '2001:db8::3' : { 'distance' : '30', 'disable' : '' }, + }, + 'interface' : { + 'eth0' : { 'distance' : '40', 'vrf' : 'black' }, + 'eth1' : { 'distance' : '50', 'disable' : '' }, + }, + 'blackhole' : { 'distance' : '250', 'tag' : '500' }, + }, + '2001:db8:200::/40' : { + 'interface' : { + 'eth0' : { 'distance' : '40' }, + 'eth1' : { 'distance' : '50', 'disable' : '' }, + }, + 'blackhole' : { 'distance' : '250', 'tag' : '500' }, + }, + '2001:db8::/32' : { + 'blackhole' : { 'distance' : '200', 'tag' : '600' }, + }, +} + +vrfs = ['red', 'green', 'blue'] +tables = ['80', '81', '82'] + +class StaticRouteTest(unittest.TestCase): + def setUp(self): + self.session = ConfigSession(os.getpid()) + + def tearDown(self): + for route, route_config in routes.items(): + route_type = 'route' + if is_ipv6(route): + route_type = 'route6' + self.session.delete(base_path + [route_type, route]) + + for vrf in vrfs: + self.session.delete(vrf_path + [vrf]) + + for table in tables: + self.session.delete(base_path + ['table', table]) + + self.session.commit() + del self.session + + def test_protocols_static(self): + for route, route_config in routes.items(): + route_type = 'route' + if is_ipv6(route): + route_type = 'route6' + base = base_path + [route_type, route] + if 'next_hop' in route_config: + for next_hop, next_hop_config in route_config['next_hop'].items(): + self.session.set(base + ['next-hop', next_hop]) + if 'disable' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'disable']) + if 'distance' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']]) + if 'interface' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']]) + if 'vrf' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']]) + + + if 'interface' in route_config: + for interface, interface_config in route_config['interface'].items(): + self.session.set(base + ['interface', interface]) + if 'disable' in interface_config: + self.session.set(base + ['interface', interface, 'disable']) + if 'distance' in interface_config: + self.session.set(base + ['interface', interface, 'distance', interface_config['distance']]) + if 'vrf' in interface_config: + self.session.set(base + ['interface', interface, 'vrf', interface_config['vrf']]) + + if 'blackhole' in route_config: + self.session.set(base + ['blackhole']) + if 'distance' in route_config['blackhole']: + self.session.set(base + ['blackhole', 'distance', route_config['blackhole']['distance']]) + if 'tag' in route_config['blackhole']: + self.session.set(base + ['blackhole', 'tag', route_config['blackhole']['tag']]) + + # commit changes + self.session.commit() + + # Verify FRR bgpd configuration + frrconfig = getFRRCconfig() + + # Verify routes + for route, route_config in routes.items(): + ip_ipv6 = 'ip' + if is_ipv6(route): + ip_ipv6 = 'ipv6' + + if 'next_hop' in route_config: + for next_hop, next_hop_config in route_config['next_hop'].items(): + tmp = f'{ip_ipv6} route {route} {next_hop}' + if 'interface' in next_hop_config: + tmp += ' ' + next_hop_config['interface'] + if 'distance' in next_hop_config: + tmp += ' ' + next_hop_config['distance'] + if 'vrf' in next_hop_config: + tmp += ' nexthop-vrf ' + next_hop_config['vrf'] + + if 'disable' in next_hop_config: + self.assertNotIn(tmp, frrconfig) + else: + self.assertIn(tmp, frrconfig) + + if 'interface' in route_config: + for interface, interface_config in route_config['interface'].items(): + tmp = f'{ip_ipv6} route {route} {interface}' + if 'interface' in interface_config: + tmp += ' ' + interface_config['interface'] + if 'distance' in interface_config: + tmp += ' ' + interface_config['distance'] + if 'vrf' in interface_config: + tmp += ' nexthop-vrf ' + interface_config['vrf'] + + if 'disable' in interface_config: + self.assertNotIn(tmp, frrconfig) + else: + self.assertIn(tmp, frrconfig) + + if 'blackhole' in route_config: + tmp = f'{ip_ipv6} route {route} blackhole' + if 'tag' in route_config['blackhole']: + tmp += ' tag ' + route_config['blackhole']['tag'] + if 'distance' in route_config['blackhole']: + tmp += ' ' + route_config['blackhole']['distance'] + + self.assertIn(tmp, frrconfig) + + def test_protocols_static_table(self): + for table in tables: + for route, route_config in routes.items(): + route_type = 'route' + if is_ipv6(route): + route_type = 'route6' + base = base_path + ['table', table, route_type, route] + + if 'next_hop' in route_config: + for next_hop, next_hop_config in route_config['next_hop'].items(): + self.session.set(base + ['next-hop', next_hop]) + if 'disable' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'disable']) + if 'distance' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']]) + if 'interface' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']]) + if 'vrf' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']]) + + + if 'interface' in route_config: + for interface, interface_config in route_config['interface'].items(): + self.session.set(base + ['interface', interface]) + if 'disable' in interface_config: + self.session.set(base + ['interface', interface, 'disable']) + if 'distance' in interface_config: + self.session.set(base + ['interface', interface, 'distance', interface_config['distance']]) + if 'vrf' in interface_config: + self.session.set(base + ['interface', interface, 'vrf', interface_config['vrf']]) + + if 'blackhole' in route_config: + self.session.set(base + ['blackhole']) + if 'distance' in route_config['blackhole']: + self.session.set(base + ['blackhole', 'distance', route_config['blackhole']['distance']]) + if 'tag' in route_config['blackhole']: + self.session.set(base + ['blackhole', 'tag', route_config['blackhole']['tag']]) + + # commit changes + self.session.commit() + + # Verify FRR bgpd configuration + frrconfig = getFRRCconfig() + + for table in tables: + # Verify routes + for route, route_config in routes.items(): + ip_ipv6 = 'ip' + if is_ipv6(route): + ip_ipv6 = 'ipv6' + + if 'next_hop' in route_config: + for next_hop, next_hop_config in route_config['next_hop'].items(): + tmp = f'{ip_ipv6} route {route} {next_hop}' + if 'interface' in next_hop_config: + tmp += ' ' + next_hop_config['interface'] + if 'distance' in next_hop_config: + tmp += ' ' + next_hop_config['distance'] + if 'vrf' in next_hop_config: + tmp += ' nexthop-vrf ' + next_hop_config['vrf'] + + tmp += ' table ' + table + if 'disable' in next_hop_config: + self.assertNotIn(tmp, frrconfig) + else: + self.assertIn(tmp, frrconfig) + + if 'interface' in route_config: + for interface, interface_config in route_config['interface'].items(): + tmp = f'{ip_ipv6} route {route} {interface}' + if 'interface' in interface_config: + tmp += ' ' + interface_config['interface'] + if 'distance' in interface_config: + tmp += ' ' + interface_config['distance'] + if 'vrf' in interface_config: + tmp += ' nexthop-vrf ' + interface_config['vrf'] + + tmp += ' table ' + table + if 'disable' in interface_config: + self.assertNotIn(tmp, frrconfig) + else: + self.assertIn(tmp, frrconfig) + + if 'blackhole' in route_config: + tmp = f'{ip_ipv6} route {route} blackhole' + if 'tag' in route_config['blackhole']: + tmp += ' tag ' + route_config['blackhole']['tag'] + if 'distance' in route_config['blackhole']: + tmp += ' ' + route_config['blackhole']['distance'] + + tmp += ' table ' + table + self.assertIn(tmp, frrconfig) + + + def test_protocols_vrf_static(self): + for vrf in vrfs: + for route, route_config in routes.items(): + route_type = 'route' + if is_ipv6(route): + route_type = 'route6' + base = vrf_path + [vrf, 'static', route_type, route] + + if 'next_hop' in route_config: + for next_hop, next_hop_config in route_config['next_hop'].items(): + self.session.set(base + ['next-hop', next_hop]) + if 'disable' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'disable']) + if 'distance' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']]) + if 'interface' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']]) + if 'vrf' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']]) + + + if 'interface' in route_config: + for interface, interface_config in route_config['interface'].items(): + self.session.set(base + ['interface', interface]) + if 'disable' in interface_config: + self.session.set(base + ['interface', interface, 'disable']) + if 'distance' in interface_config: + self.session.set(base + ['interface', interface, 'distance', interface_config['distance']]) + if 'vrf' in interface_config: + self.session.set(base + ['interface', interface, 'vrf', interface_config['vrf']]) + + if 'blackhole' in route_config: + self.session.set(base + ['blackhole']) + if 'distance' in route_config['blackhole']: + self.session.set(base + ['blackhole', 'distance', route_config['blackhole']['distance']]) + if 'tag' in route_config['blackhole']: + self.session.set(base + ['blackhole', 'tag', route_config['blackhole']['tag']]) + + # commit changes + self.session.commit() + + for vrf in vrfs: + # Verify FRR bgpd configuration + frrconfig = getFRRCconfig(vrf) + self.assertIn(f'vrf {vrf}', frrconfig) + + # Verify routes + for route, route_config in routes.items(): + ip_ipv6 = 'ip' + if is_ipv6(route): + ip_ipv6 = 'ipv6' + + if 'next_hop' in route_config: + for next_hop, next_hop_config in route_config['next_hop'].items(): + tmp = f'{ip_ipv6} route {route} {next_hop}' + if 'interface' in next_hop_config: + tmp += ' ' + next_hop_config['interface'] + if 'distance' in next_hop_config: + tmp += ' ' + next_hop_config['distance'] + if 'vrf' in next_hop_config: + tmp += ' nexthop-vrf ' + next_hop_config['vrf'] + + if 'disable' in next_hop_config: + self.assertNotIn(tmp, frrconfig) + else: + self.assertIn(tmp, frrconfig) + + if 'interface' in route_config: + for interface, interface_config in route_config['interface'].items(): + tmp = f'{ip_ipv6} route {route} {interface}' + if 'interface' in interface_config: + tmp += ' ' + interface_config['interface'] + if 'distance' in interface_config: + tmp += ' ' + interface_config['distance'] + if 'vrf' in interface_config: + tmp += ' nexthop-vrf ' + interface_config['vrf'] + + if 'disable' in interface_config: + self.assertNotIn(tmp, frrconfig) + else: + self.assertIn(tmp, frrconfig) + + if 'blackhole' in route_config: + tmp = f'{ip_ipv6} route {route} blackhole' + if 'tag' in route_config['blackhole']: + tmp += ' tag ' + route_config['blackhole']['tag'] + if 'distance' in route_config['blackhole']: + tmp += ' ' + route_config['blackhole']['distance'] + + self.assertIn(tmp, frrconfig) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_service_bcast-relay.py b/smoketest/scripts/cli/test_service_bcast-relay.py index c28509714..00d7750aa 100755 --- a/smoketest/scripts/cli/test_service_bcast-relay.py +++ b/smoketest/scripts/cli/test_service_bcast-relay.py @@ -30,7 +30,6 @@ class TestServiceBroadcastRelay(unittest.TestCase): self.session = ConfigSession(os.getpid()) self.session.set(['interfaces', 'dummy', 'dum1001', 'address', self._address1]) self.session.set(['interfaces', 'dummy', 'dum1002', 'address', self._address2]) - self.session.commit() def tearDown(self): self.session.delete(['interfaces', 'dummy', 'dum1001']) diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py index 5270e758a..8e977d407 100755 --- a/smoketest/scripts/cli/test_vrf.py +++ b/smoketest/scripts/cli/test_vrf.py @@ -16,19 +16,44 @@ import re import os +import json import unittest + from netifaces import interfaces from vyos.configsession import ConfigSession from vyos.configsession import ConfigSessionError +from vyos.ifconfig import Interface +from vyos.ifconfig import Section +from vyos.template import is_ipv6 +from vyos.util import cmd from vyos.util import read_file from vyos.validate import is_intf_addr_assigned -from vyos.ifconfig import Interface base_path = ['vrf'] vrfs = ['red', 'green', 'blue', 'foo-bar', 'baz_foo'] +def get_vrf_ipv4_routes(vrf): + return json.loads(cmd(f'ip -4 -j route show vrf {vrf}')) + +def get_vrf_ipv6_routes(vrf): + return json.loads(cmd(f'ip -6 -j route show vrf {vrf}')) + class VRFTest(unittest.TestCase): + _interfaces = [] + + @classmethod + def setUpClass(cls): + # we need to filter out VLAN interfaces identified by a dot (.) + # in their name - just in case! + if 'TEST_ETH' in os.environ: + tmp = os.environ['TEST_ETH'].split() + cls._interfaces = tmp + else: + for tmp in Section.interfaces('ethernet'): + if not '.' in tmp: + cls._interfaces.append(tmp) + def setUp(self): self.session = ConfigSession(os.getpid()) @@ -120,5 +145,26 @@ class VRFTest(unittest.TestCase): with self.assertRaises(ConfigSessionError): self.session.commit() + def test_vrf_assign_interface(self): + vrf = vrfs[0] + table = '5000' + self.session.set(['vrf', 'name', vrf, 'table', table]) + + for interface in self._interfaces: + section = Section.section(interface) + self.session.set(['interfaces', section, interface, 'vrf', vrf]) + + # commit changes + self.session.commit() + + # Verify & cleanup + for interface in self._interfaces: + # os.readlink resolves to: '../../../../../virtual/net/foovrf' + tmp = os.readlink(f'/sys/class/net/{interface}/master').split('/')[-1] + self.assertEqual(tmp, vrf) + # cleanup + section = Section.section(interface) + self.session.delete(['interfaces', section, interface, 'vrf']) + if __name__ == '__main__': - unittest.main(verbosity=2, failfast=True) + unittest.main(verbosity=2) diff --git a/src/conf_mode/interfaces-erspan.py b/src/conf_mode/interfaces-erspan.py new file mode 100755 index 000000000..2d65b834c --- /dev/null +++ b/src/conf_mode/interfaces-erspan.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2018-2020 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os + +from sys import exit +from copy import deepcopy +from netifaces import interfaces + +from vyos.config import Config +from vyos.configdict import dict_merge +from vyos.configdict import get_interface_dict +from vyos.configdict import node_changed +from vyos.configdict import leaf_node_changed +from vyos.configverify import verify_mtu_ipv6 +from vyos.configverify import verify_tunnel +from vyos.ifconfig import Interface +from vyos.ifconfig import ERSpanIf +from vyos.ifconfig import ER6SpanIf +from vyos.template import is_ipv4 +from vyos.template import is_ipv6 +from vyos.util import dict_search +from vyos import ConfigError +from vyos import airbag +airbag.enable() + +def get_config(config=None): + """ + Retrive CLI config as dictionary. Dictionary can never be empty, as at least + the interface name will be added or a deleted flag + """ + if config: + conf = config + else: + conf = Config() + base = ['interfaces', 'erspan'] + erspan = get_interface_dict(conf, base) + + tmp = leaf_node_changed(conf, ['encapsulation']) + if tmp: + erspan.update({'encapsulation_changed': {}}) + + return erspan + +def verify(erspan): + if 'deleted' in erspan: + return None + + if 'encapsulation' not in erspan: + raise ConfigError('Unable to detect the following ERSPAN tunnel encapsulation'\ + '{ifname}!'.format(**erspan)) + + verify_mtu_ipv6(erspan) + verify_tunnel(erspan) + + key = dict_search('parameters.ip.key',erspan) + if key == None: + raise ConfigError('parameters.ip.key is mandatory for ERSPAN tunnel') + + +def generate(erspan): + return None + +def apply(erspan): + if 'deleted' in erspan or 'encapsulation_changed' in erspan: + if erspan['ifname'] in interfaces(): + tmp = Interface(erspan['ifname']) + tmp.remove() + if 'deleted' in erspan: + return None + + dispatch = { + 'erspan': ERSpanIf, + 'ip6erspan': ER6SpanIf + } + + # We need to re-map the tunnel encapsulation proto to a valid interface class + encap = erspan['encapsulation'] + klass = dispatch[encap] + + conf = deepcopy(erspan) + + conf.update(klass.get_config()) + + del conf['ifname'] + + erspan_tunnel = klass(erspan['ifname'],**conf) + erspan_tunnel.change_options() + erspan_tunnel.update(erspan) + + return None + +if __name__ == '__main__': + try: + c = get_config() + generate(c) + verify(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py index e7f0cd6a5..e82a3e0f1 100755 --- a/src/conf_mode/interfaces-ethernet.py +++ b/src/conf_mode/interfaces-ethernet.py @@ -30,6 +30,7 @@ from vyos.configverify import verify_mtu from vyos.configverify import verify_mtu_ipv6 from vyos.configverify import verify_vlan_config from vyos.configverify import verify_vrf +from vyos.ethtool import Ethtool from vyos.ifconfig import EthernetIf from vyos.template import render from vyos.util import call @@ -76,10 +77,32 @@ def verify(ethernet): verify_mirror(ethernet) # verify offloading capabilities - if 'offload' in ethernet and 'rps' in ethernet['offload']: + if dict_search('offload.rps', ethernet) != None: if not os.path.exists(f'/sys/class/net/{ifname}/queues/rx-0/rps_cpus'): raise ConfigError('Interface does not suport RPS!') + driver = EthernetIf(ifname).get_driver_name() + # T3342 - Xen driver requires special treatment + if driver == 'vif': + if int(ethernet['mtu']) > 1500 and dict_search('offload.sg', ethernet) == None: + raise ConfigError('Xen netback drivers requires scatter-gatter offloading '\ + 'for MTU size larger then 1500 bytes') + + ethtool = Ethtool(ifname) + if 'ring_buffer' in ethernet: + max_rx = ethtool.get_rx_buffer() + max_tx = ethtool.get_tx_buffer() + + rx = dict_search('ring_buffer.rx', ethernet) + if rx and int(rx) > int(max_rx): + raise ConfigError(f'Driver only supports a maximum RX ring-buffer '\ + f'size of "{max_rx}" bytes!') + + tx = dict_search('ring_buffer.tx', ethernet) + if tx and int(tx) > int(max_tx): + raise ConfigError(f'Driver only supports a maximum TX ring-buffer '\ + f'size of "{max_tx}" bytes!') + # XDP requires multiple TX queues if 'xdp' in ethernet: queues = glob(f'/sys/class/net/{ifname}/queues/tx-*') diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py index f49792a7a..3675db73b 100755 --- a/src/conf_mode/interfaces-pppoe.py +++ b/src/conf_mode/interfaces-pppoe.py @@ -73,7 +73,7 @@ def generate(pppoe): config_files = [config_pppoe, script_pppoe_pre_up, script_pppoe_ip_up, script_pppoe_ip_down, script_pppoe_ipv6_up, config_wide_dhcp6c] - if 'deleted' in pppoe: + if 'deleted' in pppoe or 'disable' in pppoe: # stop DHCPv6-PD client call(f'systemctl stop dhcp6c@{ifname}.service') # Hang-up PPPoE connection @@ -110,13 +110,11 @@ def generate(pppoe): return None def apply(pppoe): - if 'deleted' in pppoe: - # bail out early + if 'deleted' in pppoe or 'disable' in pppoe: + call('systemctl stop ppp@{ifname}.service'.format(**pppoe)) return None - if 'disable' not in pppoe: - # Dial PPPoE connection - call('systemctl restart ppp@{ifname}.service'.format(**pppoe)) + call('systemctl restart ppp@{ifname}.service'.format(**pppoe)) return None diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py index f03bc9d5d..87da214a8 100755 --- a/src/conf_mode/interfaces-tunnel.py +++ b/src/conf_mode/interfaces-tunnel.py @@ -29,6 +29,7 @@ from vyos.configverify import verify_bridge_delete from vyos.configverify import verify_interface_exists from vyos.configverify import verify_mtu_ipv6 from vyos.configverify import verify_vrf +from vyos.configverify import verify_tunnel from vyos.ifconfig import Interface from vyos.ifconfig import GREIf from vyos.ifconfig import GRETapIf @@ -84,38 +85,7 @@ def verify(tunnel): verify_mtu_ipv6(tunnel) verify_address(tunnel) verify_vrf(tunnel) - - if 'local_ip' not in tunnel and 'dhcp_interface' not in tunnel: - raise ConfigError('local-ip is mandatory for tunnel') - - if 'remote_ip' not in tunnel and tunnel['encapsulation'] != 'gre': - raise ConfigError('remote-ip is mandatory for tunnel') - - if {'local_ip', 'dhcp_interface'} <= set(tunnel): - raise ConfigError('Can not use both local-ip and dhcp-interface') - - if tunnel['encapsulation'] in ['ipip6', 'ip6ip6', 'ip6gre']: - error_ipv6 = 'Encapsulation mode requires IPv6' - if 'local_ip' in tunnel and not is_ipv6(tunnel['local_ip']): - raise ConfigError(f'{error_ipv6} local-ip') - - if 'remote_ip' in tunnel and not is_ipv6(tunnel['remote_ip']): - raise ConfigError(f'{error_ipv6} remote-ip') - else: - error_ipv4 = 'Encapsulation mode requires IPv4' - if 'local_ip' in tunnel and not is_ipv4(tunnel['local_ip']): - raise ConfigError(f'{error_ipv4} local-ip') - - if 'remote_ip' in tunnel and not is_ipv4(tunnel['remote_ip']): - raise ConfigError(f'{error_ipv4} remote-ip') - - if tunnel['encapsulation'] in ['sit', 'gre-bridge']: - if 'source_interface' in tunnel: - raise ConfigError('Option source-interface can not be used with ' \ - 'encapsulation "sit" or "gre-bridge"') - elif tunnel['encapsulation'] == 'gre': - if 'local_ip' in tunnel and is_ipv6(tunnel['local_ip']): - raise ConfigError('Can not use local IPv6 address is for mGRE tunnels') + verify_tunnel(tunnel) if 'source_interface' in tunnel: verify_interface_exists(tunnel['source_interface']) @@ -170,7 +140,6 @@ def apply(tunnel): 'parameters.ip.ttl' : 'ttl', 'parameters.ip.tos' : 'tos', 'parameters.ip.key' : 'key', - 'parameters.ipv6.encaplimit' : 'encaplimit' } # Add additional IPv6 options if tunnel is IPv6 aware diff --git a/src/conf_mode/lldp.py b/src/conf_mode/lldp.py index 6b645857a..082c3e128 100755 --- a/src/conf_mode/lldp.py +++ b/src/conf_mode/lldp.py @@ -21,7 +21,8 @@ from copy import deepcopy from sys import exit from vyos.config import Config -from vyos.validate import is_addr_assigned,is_loopback_addr +from vyos.validate import is_addr_assigned +from vyos.validate import is_loopback_addr from vyos.version import get_version_data from vyos import ConfigError from vyos.util import call @@ -237,8 +238,10 @@ def apply(lldp): else: # LLDP service has been terminated call('systemctl stop lldpd.service') - os.unlink(config_file) - os.unlink(vyos_config_file) + if os.path.isfile(config_file): + os.unlink(config_file) + if os.path.isfile(vyos_config_file): + os.unlink(vyos_config_file) if __name__ == '__main__': try: diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py index d1e551cad..a43eed504 100755 --- a/src/conf_mode/protocols_bfd.py +++ b/src/conf_mode/protocols_bfd.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019-2020 VyOS maintainers and contributors +# Copyright (C) 2019-2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -17,191 +17,97 @@ import os from sys import exit -from copy import deepcopy from vyos.config import Config +from vyos.configdict import dict_merge from vyos.template import is_ipv6 -from vyos.template import render +from vyos.template import render_to_string from vyos.util import call from vyos.validate import is_ipv6_link_local +from vyos.xml import defaults from vyos import ConfigError +from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/bfd.frr' - -default_config_data = { - 'new_peers': [], - 'old_peers' : [] -} - -# get configuration for BFD peer from proposed or effective configuration -def get_bfd_peer_config(peer, conf_mode="proposed"): - conf = Config() - conf.set_level('protocols bfd peer {0}'.format(peer)) - - bfd_peer = { - 'remote': peer, - 'shutdown': False, - 'src_if': '', - 'src_addr': '', - 'multiplier': '3', - 'rx_interval': '300', - 'tx_interval': '300', - 'multihop': False, - 'echo_interval': '', - 'echo_mode': False, - } - - # Check if individual peer is disabled - if conf_mode == "effective" and conf.exists_effective('shutdown'): - bfd_peer['shutdown'] = True - if conf_mode == "proposed" and conf.exists('shutdown'): - bfd_peer['shutdown'] = True - - # Check if peer has a local source interface configured - if conf_mode == "effective" and conf.exists_effective('source interface'): - bfd_peer['src_if'] = conf.return_effective_value('source interface') - if conf_mode == "proposed" and conf.exists('source interface'): - bfd_peer['src_if'] = conf.return_value('source interface') - - # Check if peer has a local source address configured - this is mandatory for IPv6 - if conf_mode == "effective" and conf.exists_effective('source address'): - bfd_peer['src_addr'] = conf.return_effective_value('source address') - if conf_mode == "proposed" and conf.exists('source address'): - bfd_peer['src_addr'] = conf.return_value('source address') - - # Tell BFD daemon that we should expect packets with TTL less than 254 - # (because it will take more than one hop) and to listen on the multihop - # port (4784) - if conf_mode == "effective" and conf.exists_effective('multihop'): - bfd_peer['multihop'] = True - if conf_mode == "proposed" and conf.exists('multihop'): - bfd_peer['multihop'] = True - - # Configures the minimum interval that this system is capable of receiving - # control packets. The default value is 300 milliseconds. - if conf_mode == "effective" and conf.exists_effective('interval receive'): - bfd_peer['rx_interval'] = conf.return_effective_value('interval receive') - if conf_mode == "proposed" and conf.exists('interval receive'): - bfd_peer['rx_interval'] = conf.return_value('interval receive') - - # The minimum transmission interval (less jitter) that this system wants - # to use to send BFD control packets. - if conf_mode == "effective" and conf.exists_effective('interval transmit'): - bfd_peer['tx_interval'] = conf.return_effective_value('interval transmit') - if conf_mode == "proposed" and conf.exists('interval transmit'): - bfd_peer['tx_interval'] = conf.return_value('interval transmit') - - # Configures the detection multiplier to determine packet loss. The remote - # transmission interval will be multiplied by this value to determine the - # connection loss detection timer. The default value is 3. - if conf_mode == "effective" and conf.exists_effective('interval multiplier'): - bfd_peer['multiplier'] = conf.return_effective_value('interval multiplier') - if conf_mode == "proposed" and conf.exists('interval multiplier'): - bfd_peer['multiplier'] = conf.return_value('interval multiplier') - - # Configures the minimal echo receive transmission interval that this system is capable of handling - if conf_mode == "effective" and conf.exists_effective('interval echo-interval'): - bfd_peer['echo_interval'] = conf.return_effective_value('interval echo-interval') - if conf_mode == "proposed" and conf.exists('interval echo-interval'): - bfd_peer['echo_interval'] = conf.return_value('interval echo-interval') - - # Enables or disables the echo transmission mode - if conf_mode == "effective" and conf.exists_effective('echo-mode'): - bfd_peer['echo_mode'] = True - if conf_mode == "proposed" and conf.exists('echo-mode'): - bfd_peer['echo_mode'] = True - - return bfd_peer - -def get_config(): - bfd = deepcopy(default_config_data) - conf = Config() - if not (conf.exists('protocols bfd') or conf.exists_effective('protocols bfd')): - return None +def get_config(config=None): + if config: + conf = config else: - conf.set_level('protocols bfd') - - # as we have to use vtysh to talk to FRR we also need to know - # which peers are gone due to a config removal - thus we read in - # all peers (active or to delete) - for peer in conf.list_effective_nodes('peer'): - bfd['old_peers'].append(get_bfd_peer_config(peer, "effective")) - - for peer in conf.list_nodes('peer'): - bfd['new_peers'].append(get_bfd_peer_config(peer)) - - # find deleted peers - set_new_peers = set(conf.list_nodes('peer')) - set_old_peers = set(conf.list_effective_nodes('peer')) - bfd['deleted_peers'] = set_old_peers - set_new_peers + conf = Config() + base = ['protocols', 'bfd'] + bfd = conf.get_config_dict(base, get_first_key=True) + + # Bail out early if configuration tree does not exist + if not conf.exists(base): + return bfd + + # We have gathered the dict representation of the CLI, but there are + # default options which we need to update into the dictionary retrived. + # XXX: T2665: we currently have no nice way for defaults under tag + # nodes, thus we load the defaults "by hand" + default_values = defaults(base + ['peer']) + if 'peer' in bfd: + for peer in bfd['peer']: + bfd['peer'][peer] = dict_merge(default_values, bfd['peer'][peer]) + + if 'profile' in bfd: + for profile in bfd['profile']: + bfd['profile'][profile] = dict_merge(default_values, bfd['profile'][profile]) return bfd def verify(bfd): - if bfd is None: + if not bfd: return None - # some variables to use later - conf = Config() - - for peer in bfd['new_peers']: - # IPv6 link local peers require an explicit local address/interface - if is_ipv6_link_local(peer['remote']): - if not (peer['src_if'] and peer['src_addr']): - raise ConfigError('BFD IPv6 link-local peers require explicit local address and interface setting') - - # IPv6 peers require an explicit local address - if is_ipv6(peer['remote']): - if not peer['src_addr']: - raise ConfigError('BFD IPv6 peers require explicit local address setting') - - # multihop require source address - if peer['multihop'] and not peer['src_addr']: - raise ConfigError('Multihop require source address') - - # multihop and echo-mode cannot be used together - if peer['multihop'] and peer['echo_mode']: - raise ConfigError('Multihop and echo-mode cannot be used together') - - # multihop doesn't accept interface names - if peer['multihop'] and peer['src_if']: - raise ConfigError('Multihop and source interface cannot be used together') - - # echo interval can be configured only with enabled echo-mode - if peer['echo_interval'] != '' and not peer['echo_mode']: - raise ConfigError('echo-interval can be configured only with enabled echo-mode') - - # check if we deleted peers are not used in configuration - if conf.exists('protocols bgp'): - bgp_as = conf.list_nodes('protocols bgp')[0] - - # check BGP neighbors - for peer in bfd['deleted_peers']: - if conf.exists('protocols bgp {0} neighbor {1} bfd'.format(bgp_as, peer)): - raise ConfigError('Cannot delete BFD peer {0}: it is used in BGP configuration'.format(peer)) - if conf.exists('protocols bgp {0} neighbor {1} peer-group'.format(bgp_as, peer)): - peer_group = conf.return_value('protocols bgp {0} neighbor {1} peer-group'.format(bgp_as, peer)) - if conf.exists('protocols bgp {0} peer-group {1} bfd'.format(bgp_as, peer_group)): - raise ConfigError('Cannot delete BFD peer {0}: it belongs to BGP peer-group {1} with enabled BFD'.format(peer, peer_group)) + if 'peer' in bfd: + for peer, peer_config in bfd['peer'].items(): + # IPv6 link local peers require an explicit local address/interface + if is_ipv6_link_local(peer): + if 'source' not in peer_config or len(peer_config['source'] < 2): + raise ConfigError('BFD IPv6 link-local peers require explicit local address and interface setting') + + # IPv6 peers require an explicit local address + if is_ipv6(peer): + if 'source' not in peer_config or 'address' not in peer_config['source']: + raise ConfigError('BFD IPv6 peers require explicit local address setting') + + if 'multihop' in peer_config: + # multihop require source address + if 'source' not in peer_config or 'address' not in peer_config['source']: + raise ConfigError('BFD multihop require source address') + + # multihop and echo-mode cannot be used together + if 'echo_mode' in peer_config: + raise ConfigError('Multihop and echo-mode cannot be used together') + + # multihop doesn't accept interface names + if 'source' in peer_config and 'interface' in peer_config['source']: + raise ConfigError('Multihop and source interface cannot be used together') return None def generate(bfd): - if bfd is None: + if not bfd: + bfd['new_frr_config'] = '' return None - render(config_file, 'frr/bfd.frr.tmpl', bfd) - return None + bfd['new_frr_config'] = render_to_string('frr/bfd.frr.tmpl', bfd) def apply(bfd): - if bfd is None: - return None - - call("vtysh -d bfdd -f " + config_file) - if os.path.exists(config_file): - os.remove(config_file) + # Save original configuration prior to starting any commit actions + frr_cfg = frr.FRRConfig() + frr_cfg.load_configuration() + frr_cfg.modify_section('^bfd', '') + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', bfd['new_frr_config']) + frr_cfg.commit_configuration() + + # If FRR config is blank, rerun the blank commit x times due to frr-reload + # behavior/bug not properly clearing out on one commit. + if bfd['new_frr_config'] == '': + for a in range(5): + frr_cfg.commit_configuration() return None diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index 41d89e03b..baf5c4159 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -20,7 +20,6 @@ from sys import exit from vyos.config import Config from vyos.configdict import dict_merge -from vyos.template import render from vyos.template import render_to_string from vyos.util import call from vyos.util import dict_search @@ -29,17 +28,8 @@ from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/bgp.frr' frr_daemon = 'bgpd' -DEBUG = os.path.exists('/tmp/bgp.debug') -if DEBUG: - import logging - lg = logging.getLogger("vyos.frr") - lg.setLevel(logging.DEBUG) - ch = logging.StreamHandler() - lg.addHandler(ch) - def get_config(config=None): if config: conf = config @@ -64,6 +54,26 @@ def get_config(config=None): return bgp +def verify_remote_as(peer_config, asn_config): + if 'remote_as' in peer_config: + return peer_config['remote_as'] + + if 'peer_group' in peer_config: + peer_group_name = peer_config['peer_group'] + tmp = dict_search(f'peer_group.{peer_group_name}.remote_as', asn_config) + if tmp: return tmp + + if 'interface' in peer_config: + if 'remote_as' in peer_config['interface']: + return peer_config['interface']['remote_as'] + + if 'peer_group' in peer_config['interface']: + peer_group_name = peer_config['interface']['peer_group'] + tmp = dict_search(f'peer_group.{peer_group_name}.remote_as', asn_config) + if tmp: return tmp + + return None + def verify(bgp): if not bgp: return None @@ -89,20 +99,15 @@ def verify(bgp): raise ConfigError(f'Specified peer-group "{peer_group}" for '\ f'neighbor "{neighbor}" does not exist!') - # Some checks can/must only be done on a neighbor and nor a peer-group + + # Some checks can/must only be done on a neighbor and not a peer-group if neighbor == 'neighbor': # remote-as must be either set explicitly for the neighbor # or for the entire peer-group - if 'interface' in peer_config: - if 'remote_as' not in peer_config['interface']: - if 'peer_group' not in peer_config['interface'] or 'remote_as' not in asn_config['peer_group'][ peer_config['interface']['peer_group'] ]: - raise ConfigError('Remote AS must be set for neighbor or peer-group!') - - elif 'remote_as' not in peer_config: - if 'peer_group' not in peer_config or 'remote_as' not in asn_config['peer_group'][ peer_config['peer_group'] ]: - raise ConfigError('Remote AS must be set for neighbor or peer-group!') + if not verify_remote_as(peer_config, asn_config): + raise ConfigError(f'Neighbor "{peer}" remote-as must be set!') - for afi in ['ipv4_unicast', 'ipv6_unicast']: + for afi in ['ipv4_unicast', 'ipv6_unicast', 'l2vpn_evpn']: # Bail out early if address family is not configured if 'address_family' not in peer_config or afi not in peer_config['address_family']: continue @@ -133,6 +138,15 @@ def verify(bgp): if dict_search(f'policy.route_map.{route_map}', asn_config) == None: raise ConfigError(f'route-map "{route_map}" used for "{tmp}" does not exist!') + if 'route_reflector_client' in afi_config: + if 'remote_as' in peer_config and asn != peer_config['remote_as']: + raise ConfigError('route-reflector-client only supported for iBGP peers') + else: + if 'peer_group' in peer_config: + peer_group_as = dict_search(f'peer_group.{peer_group}.remote_as', asn_config) + if peer_group_as != None and peer_group_as != asn: + raise ConfigError('route-reflector-client only supported for iBGP peers') + # Throw an error if a peer group is not configured for allow range for prefix in dict_search('listen.range', asn_config) or []: # we can not use dict_search() here as prefix contains dots ... @@ -156,33 +170,15 @@ def generate(bgp): asn = list(bgp.keys())[0] bgp[asn]['asn'] = asn - # render(config) not needed, its only for debug - render(config_file, 'frr/bgp.frr.tmpl', bgp[asn]) bgp['new_frr_config'] = render_to_string('frr/bgp.frr.tmpl', bgp[asn]) - return None def apply(bgp): # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() frr_cfg.load_configuration(frr_daemon) - frr_cfg.modify_section(f'router bgp \S+', '') + frr_cfg.modify_section(f'^router bgp \d+$', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', bgp['new_frr_config']) - - # Debugging - if DEBUG: - from pprint import pprint - print('') - print('--------- DEBUGGING ----------') - pprint(dir(frr_cfg)) - print('Existing config:\n') - for line in frr_cfg.original_config: - print(line) - print(f'Replacement config:\n') - print(f'{bgp["new_frr_config"]}') - print(f'Modified config:\n') - print(f'{frr_cfg}') - frr_cfg.commit_configuration(frr_daemon) # If FRR config is blank, rerun the blank commit x times due to frr-reload @@ -191,7 +187,6 @@ def apply(bgp): for a in range(5): frr_cfg.commit_configuration(frr_daemon) - return None if __name__ == '__main__': diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index 7c0ffbd27..6d9eb828b 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -21,7 +21,7 @@ from sys import exit from vyos.config import Config from vyos.configdict import dict_merge from vyos.configverify import verify_route_maps -from vyos.template import render +from vyos.configverify import verify_interface_exists from vyos.template import render_to_string from vyos.util import call from vyos.util import dict_search @@ -31,17 +31,8 @@ from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/ospf.frr' frr_daemon = 'ospfd' -DEBUG = os.path.exists('/tmp/ospf.debug') -if DEBUG: - import logging - lg = logging.getLogger("vyos.frr") - lg.setLevel(logging.DEBUG) - ch = logging.StreamHandler() - lg.addHandler(ch) - def get_config(config=None): if config: conf = config @@ -76,6 +67,7 @@ def get_config(config=None): # clean them out and add them manually :( del default_values['neighbor'] del default_values['area']['virtual_link'] + del default_values['interface'] # merge in remaining default values ospf = dict_merge(default_values, ospf) @@ -94,6 +86,19 @@ def get_config(config=None): ospf['area'][area]['virtual_link'][virtual_link] = dict_merge( default_values, ospf['area'][area]['virtual_link'][virtual_link]) + if 'interface' in ospf: + for interface in ospf['interface']: + # We need to reload the defaults on every pass b/c of + # hello-multiplier dependency on dead-interval + default_values = defaults(base + ['interface']) + # If hello-multiplier is set, we need to remove the default from + # dead-interval. + if 'hello_multiplier' in ospf['interface'][interface]: + del default_values['dead_interval'] + + ospf['interface'][interface] = dict_merge(default_values, + ospf['interface'][interface]) + # We also need some additional information from the config, prefix-lists # and route-maps for instance. They will be used in verify() base = ['policy'] @@ -108,6 +113,16 @@ def verify(ospf): return None verify_route_maps(ospf) + + if 'interface' in ospf: + for interface in ospf['interface']: + verify_interface_exists(interface) + # One can not use dead-interval and hello-multiplier at the same + # time. FRR will only activate the last option set via CLI. + if {'hello_multiplier', 'dead_interval'} <= set(ospf['interface'][interface]): + raise ConfigError(f'Can not use hello-multiplier and dead-interval ' \ + f'concurrently for "{interface}"!') + return None def generate(ospf): @@ -115,33 +130,16 @@ def generate(ospf): ospf['new_frr_config'] = '' return None - # render(config) not needed, its only for debug - render(config_file, 'frr/ospf.frr.tmpl', ospf) ospf['new_frr_config'] = render_to_string('frr/ospf.frr.tmpl', ospf) - return None def apply(ospf): # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() frr_cfg.load_configuration(frr_daemon) - frr_cfg.modify_section('router ospf', '') + frr_cfg.modify_section(r'^interface \S+', '') + frr_cfg.modify_section('^router ospf$', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', ospf['new_frr_config']) - - # Debugging - if DEBUG: - from pprint import pprint - print('') - print('--------- DEBUGGING ----------') - pprint(dir(frr_cfg)) - print('Existing config:\n') - for line in frr_cfg.original_config: - print(line) - print(f'Replacement config:\n') - print(f'{ospf["new_frr_config"]}') - print(f'Modified config:\n') - print(f'{frr_cfg}') - frr_cfg.commit_configuration(frr_daemon) # If FRR config is blank, rerun the blank commit x times due to frr-reload diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py index 2fb600056..6f068b196 100755 --- a/src/conf_mode/protocols_ospfv3.py +++ b/src/conf_mode/protocols_ospfv3.py @@ -21,27 +21,17 @@ from sys import exit from vyos.config import Config from vyos.configdict import dict_merge from vyos.configverify import verify_route_maps -from vyos.template import render from vyos.template import render_to_string from vyos.util import call -from vyos.util import dict_search +from vyos.ifconfig import Interface from vyos.xml import defaults from vyos import ConfigError from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/ospfv3.frr' frr_daemon = 'ospf6d' -DEBUG = os.path.exists('/tmp/ospfv3.debug') -if DEBUG: - import logging - lg = logging.getLogger("vyos.frr") - lg.setLevel(logging.DEBUG) - ch = logging.StreamHandler() - lg.addHandler(ch) - def get_config(config=None): if config: conf = config @@ -68,6 +58,14 @@ def verify(ospfv3): return None verify_route_maps(ospfv3) + + if 'interface' in ospfv3: + for ifname, if_config in ospfv3['interface'].items(): + if 'ifmtu' in if_config: + mtu = Interface(ifname).get_mtu() + if int(if_config['ifmtu']) > int(mtu): + raise ConfigError(f'OSPFv3 ifmtu cannot go beyond physical MTU of "{mtu}"') + return None def generate(ospfv3): @@ -75,33 +73,16 @@ def generate(ospfv3): ospfv3['new_frr_config'] = '' return None - # render(config) not needed, its only for debug - render(config_file, 'frr/ospfv3.frr.tmpl', ospfv3) ospfv3['new_frr_config'] = render_to_string('frr/ospfv3.frr.tmpl', ospfv3) - return None def apply(ospfv3): # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() frr_cfg.load_configuration(frr_daemon) - frr_cfg.modify_section('router ospf6', '') + frr_cfg.modify_section(r'^interface \S+', '') + frr_cfg.modify_section('^router ospf6$', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', ospfv3['new_frr_config']) - - # Debugging - if DEBUG: - from pprint import pprint - print('') - print('--------- DEBUGGING ----------') - pprint(dir(frr_cfg)) - print('Existing config:\n') - for line in frr_cfg.original_config: - print(line) - print(f'Replacement config:\n') - print(f'{ospfv3["new_frr_config"]}') - print(f'Modified config:\n') - print(f'{frr_cfg}') - frr_cfg.commit_configuration(frr_daemon) # If FRR config is blank, re-run the blank commit x times due to frr-reload diff --git a/src/conf_mode/protocols_rip.py b/src/conf_mode/protocols_rip.py index 8ddd705f2..6db5143c5 100755 --- a/src/conf_mode/protocols_rip.py +++ b/src/conf_mode/protocols_rip.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2021 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -18,15 +18,19 @@ import os from sys import exit -from vyos import ConfigError from vyos.config import Config +from vyos.configdict import dict_merge +from vyos.configverify import verify_route_maps from vyos.util import call -from vyos.template import render - +from vyos.util import dict_search +from vyos.xml import defaults +from vyos.template import render_to_string +from vyos import ConfigError +from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/ripd.frr' +frr_daemon = 'ripd' def get_config(config=None): if config: @@ -34,277 +38,83 @@ def get_config(config=None): else: conf = Config() base = ['protocols', 'rip'] - rip_conf = { - 'rip_conf' : False, - 'default_distance' : [], - 'default_originate' : False, - 'old_rip' : { - 'default_metric' : [], - 'distribute' : {}, - 'neighbors' : {}, - 'networks' : {}, - 'net_distance' : {}, - 'passive_iface' : {}, - 'redist' : {}, - 'route' : {}, - 'ifaces' : {}, - 'timer_garbage' : 120, - 'timer_timeout' : 180, - 'timer_update' : 30 - }, - 'rip' : { - 'default_metric' : None, - 'distribute' : {}, - 'neighbors' : {}, - 'networks' : {}, - 'net_distance' : {}, - 'passive_iface' : {}, - 'redist' : {}, - 'route' : {}, - 'ifaces' : {}, - 'timer_garbage' : 120, - 'timer_timeout' : 180, - 'timer_update' : 30 - } - } - - if not (conf.exists(base) or conf.exists_effective(base)): - return None - - if conf.exists(base): - rip_conf['rip_conf'] = True - - conf.set_level(base) - - # Get default distance - if conf.exists_effective('default-distance'): - rip_conf['old_default_distance'] = conf.return_effective_value('default-distance') - - if conf.exists('default-distance'): - rip_conf['default_distance'] = conf.return_value('default-distance') - - # Get default information originate (originate default route) - if conf.exists_effective('default-information originate'): - rip_conf['old_default_originate'] = True - - if conf.exists('default-information originate'): - rip_conf['default_originate'] = True - - # Get default-metric - if conf.exists_effective('default-metric'): - rip_conf['old_rip']['default_metric'] = conf.return_effective_value('default-metric') - - if conf.exists('default-metric'): - rip_conf['rip']['default_metric'] = conf.return_value('default-metric') - - # Get distribute list interface old_rip - for dist_iface in conf.list_effective_nodes('distribute-list interface'): - # Set level 'distribute-list interface ethX' - conf.set_level(base + ['distribute-list', 'interface', dist_iface]) - rip_conf['rip']['distribute'].update({ - dist_iface : { - 'iface_access_list_in': conf.return_effective_value('access-list in'.format(dist_iface)), - 'iface_access_list_out': conf.return_effective_value('access-list out'.format(dist_iface)), - 'iface_prefix_list_in': conf.return_effective_value('prefix-list in'.format(dist_iface)), - 'iface_prefix_list_out': conf.return_effective_value('prefix-list out'.format(dist_iface)) - } - }) - - # Access-list in old_rip - if conf.exists_effective('access-list in'.format(dist_iface)): - rip_conf['old_rip']['iface_access_list_in'] = conf.return_effective_value('access-list in'.format(dist_iface)) - # Access-list out old_rip - if conf.exists_effective('access-list out'.format(dist_iface)): - rip_conf['old_rip']['iface_access_list_out'] = conf.return_effective_value('access-list out'.format(dist_iface)) - # Prefix-list in old_rip - if conf.exists_effective('prefix-list in'.format(dist_iface)): - rip_conf['old_rip']['iface_prefix_list_in'] = conf.return_effective_value('prefix-list in'.format(dist_iface)) - # Prefix-list out old_rip - if conf.exists_effective('prefix-list out'.format(dist_iface)): - rip_conf['old_rip']['iface_prefix_list_out'] = conf.return_effective_value('prefix-list out'.format(dist_iface)) - - conf.set_level(base) - - # Get distribute list interface - for dist_iface in conf.list_nodes('distribute-list interface'): - # Set level 'distribute-list interface ethX' - conf.set_level(base + ['distribute-list', 'interface', dist_iface]) - rip_conf['rip']['distribute'].update({ - dist_iface : { - 'iface_access_list_in': conf.return_value('access-list in'.format(dist_iface)), - 'iface_access_list_out': conf.return_value('access-list out'.format(dist_iface)), - 'iface_prefix_list_in': conf.return_value('prefix-list in'.format(dist_iface)), - 'iface_prefix_list_out': conf.return_value('prefix-list out'.format(dist_iface)) - } - }) - - # Access-list in - if conf.exists('access-list in'.format(dist_iface)): - rip_conf['rip']['iface_access_list_in'] = conf.return_value('access-list in'.format(dist_iface)) - # Access-list out - if conf.exists('access-list out'.format(dist_iface)): - rip_conf['rip']['iface_access_list_out'] = conf.return_value('access-list out'.format(dist_iface)) - # Prefix-list in - if conf.exists('prefix-list in'.format(dist_iface)): - rip_conf['rip']['iface_prefix_list_in'] = conf.return_value('prefix-list in'.format(dist_iface)) - # Prefix-list out - if conf.exists('prefix-list out'.format(dist_iface)): - rip_conf['rip']['iface_prefix_list_out'] = conf.return_value('prefix-list out'.format(dist_iface)) - - conf.set_level(base + ['distribute-list']) - - # Get distribute list, access-list in - if conf.exists_effective('access-list in'): - rip_conf['old_rip']['dist_acl_in'] = conf.return_effective_value('access-list in') - - if conf.exists('access-list in'): - rip_conf['rip']['dist_acl_in'] = conf.return_value('access-list in') - - # Get distribute list, access-list out - if conf.exists_effective('access-list out'): - rip_conf['old_rip']['dist_acl_out'] = conf.return_effective_value('access-list out') - - if conf.exists('access-list out'): - rip_conf['rip']['dist_acl_out'] = conf.return_value('access-list out') - - # Get ditstribute list, prefix-list in - if conf.exists_effective('prefix-list in'): - rip_conf['old_rip']['dist_prfx_in'] = conf.return_effective_value('prefix-list in') - - if conf.exists('prefix-list in'): - rip_conf['rip']['dist_prfx_in'] = conf.return_value('prefix-list in') - - # Get distribute list, prefix-list out - if conf.exists_effective('prefix-list out'): - rip_conf['old_rip']['dist_prfx_out'] = conf.return_effective_value('prefix-list out') + rip = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) - if conf.exists('prefix-list out'): - rip_conf['rip']['dist_prfx_out'] = conf.return_value('prefix-list out') + # Bail out early if configuration tree does not exist + if not conf.exists(base): + return rip - conf.set_level(base) + # We have gathered the dict representation of the CLI, but there are default + # options which we need to update into the dictionary retrived. + default_values = defaults(base) + # merge in remaining default values + rip = dict_merge(default_values, rip) - # Get network Interfaces - if conf.exists_effective('interface'): - rip_conf['old_rip']['ifaces'] = conf.return_effective_values('interface') + # We also need some additional information from the config, prefix-lists + # and route-maps for instance. They will be used in verify() + base = ['policy'] + tmp = conf.get_config_dict(base, key_mangling=('-', '_')) + # Merge policy dict into OSPF dict + rip = dict_merge(tmp, rip) - if conf.exists('interface'): - rip_conf['rip']['ifaces'] = conf.return_values('interface') + return rip - # Get neighbors - if conf.exists_effective('neighbor'): - rip_conf['old_rip']['neighbors'] = conf.return_effective_values('neighbor') - - if conf.exists('neighbor'): - rip_conf['rip']['neighbors'] = conf.return_values('neighbor') - - # Get networks - if conf.exists_effective('network'): - rip_conf['old_rip']['networks'] = conf.return_effective_values('network') - - if conf.exists('network'): - rip_conf['rip']['networks'] = conf.return_values('network') - - # Get network-distance old_rip - for net_dist in conf.list_effective_nodes('network-distance'): - rip_conf['old_rip']['net_distance'].update({ - net_dist : { - 'access_list' : conf.return_effective_value('network-distance {0} access-list'.format(net_dist)), - 'distance' : conf.return_effective_value('network-distance {0} distance'.format(net_dist)), - } - }) - - # Get network-distance - for net_dist in conf.list_nodes('network-distance'): - rip_conf['rip']['net_distance'].update({ - net_dist : { - 'access_list' : conf.return_value('network-distance {0} access-list'.format(net_dist)), - 'distance' : conf.return_value('network-distance {0} distance'.format(net_dist)), - } - }) - - # Get passive-interface - if conf.exists_effective('passive-interface'): - rip_conf['old_rip']['passive_iface'] = conf.return_effective_values('passive-interface') - - if conf.exists('passive-interface'): - rip_conf['rip']['passive_iface'] = conf.return_values('passive-interface') - - # Get redistribute for old_rip - for protocol in conf.list_effective_nodes('redistribute'): - rip_conf['old_rip']['redist'].update({ - protocol : { - 'metric' : conf.return_effective_value('redistribute {0} metric'.format(protocol)), - 'route_map' : conf.return_effective_value('redistribute {0} route-map'.format(protocol)), - } - }) - - # Get redistribute - for protocol in conf.list_nodes('redistribute'): - rip_conf['rip']['redist'].update({ - protocol : { - 'metric' : conf.return_value('redistribute {0} metric'.format(protocol)), - 'route_map' : conf.return_value('redistribute {0} route-map'.format(protocol)), - } - }) - - conf.set_level(base) - - # Get route - if conf.exists_effective('route'): - rip_conf['old_rip']['route'] = conf.return_effective_values('route') - - if conf.exists('route'): - rip_conf['rip']['route'] = conf.return_values('route') - - # Get timers garbage - if conf.exists_effective('timers garbage-collection'): - rip_conf['old_rip']['timer_garbage'] = conf.return_effective_value('timers garbage-collection') - - if conf.exists('timers garbage-collection'): - rip_conf['rip']['timer_garbage'] = conf.return_value('timers garbage-collection') - - # Get timers timeout - if conf.exists_effective('timers timeout'): - rip_conf['old_rip']['timer_timeout'] = conf.return_effective_value('timers timeout') +def verify(rip): + if not rip: + return None - if conf.exists('timers timeout'): - rip_conf['rip']['timer_timeout'] = conf.return_value('timers timeout') + acl_in = dict_search('distribute_list.access_list.in', rip) + if acl_in and acl_in not in (dict_search('policy.access_list', rip) or []): + raise ConfigError(f'Inbound ACL "{acl_in}" does not exist!') - # Get timers update - if conf.exists_effective('timers update'): - rip_conf['old_rip']['timer_update'] = conf.return_effective_value('timers update') + acl_out = dict_search('distribute_list.access_list.out', rip) + if acl_out and acl_out not in (dict_search('policy.access_list', rip) or []): + raise ConfigError(f'Outbound ACL "{acl_out}" does not exist!') - if conf.exists('timers update'): - rip_conf['rip']['timer_update'] = conf.return_value('timers update') + prefix_list_in = dict_search('distribute_list.prefix_list.in', rip) + if prefix_list_in and prefix_list_in.replace('-','_') not in (dict_search('policy.prefix_list', rip) or []): + raise ConfigError(f'Inbound prefix-list "{prefix_list_in}" does not exist!') - return rip_conf + prefix_list_out = dict_search('distribute_list.prefix_list.out', rip) + if prefix_list_out and prefix_list_out.replace('-','_') not in (dict_search('policy.prefix_list', rip) or []): + raise ConfigError(f'Outbound prefix-list "{prefix_list_out}" does not exist!') -def verify(rip): - if rip is None: - return None + if 'interface' in rip: + for interface, interface_options in rip['interface'].items(): + if 'authentication' in interface_options: + if {'md5', 'plaintext_password'} <= set(interface_options['authentication']): + raise ConfigError('Can not use both md5 and plaintext-password at the same time!') + if 'split_horizon' in interface_options: + if {'disable', 'poison_reverse'} <= set(interface_options['split_horizon']): + raise ConfigError(f'You can not have "split-horizon poison-reverse" enabled ' \ + f'with "split-horizon disable" for "{interface}"!') - # Check for network. If network-distance acl is set and distance not set - for net in rip['rip']['net_distance']: - if not rip['rip']['net_distance'][net]['distance']: - raise ConfigError(f"Must specify distance for network {net}") + verify_route_maps(rip) def generate(rip): - if rip is None: + if not rip: + rip['new_frr_config'] = '' return None - render(config_file, 'frr/rip.frr.tmpl', rip) + rip['new_frr_config'] = render_to_string('frr/rip.frr.tmpl', rip) + return None def apply(rip): - if rip is None: - return None - - if os.path.exists(config_file): - call(f'vtysh -d ripd -f {config_file}') - os.remove(config_file) - else: - print("File {0} not found".format(config_file)) - + # Save original configuration prior to starting any commit actions + frr_cfg = frr.FRRConfig() + frr_cfg.load_configuration(frr_daemon) + frr_cfg.modify_section(r'key chain \S+', '') + frr_cfg.modify_section(r'interface \S+', '') + frr_cfg.modify_section('router rip', '') + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', rip['new_frr_config']) + frr_cfg.commit_configuration(frr_daemon) + + # If FRR config is blank, rerun the blank commit x times due to frr-reload + # behavior/bug not properly clearing out on one commit. + if rip['new_frr_config'] == '': + for a in range(5): + frr_cfg.commit_configuration(frr_daemon) return None @@ -317,4 +127,3 @@ if __name__ == '__main__': except ConfigError as e: print(e) exit(1) - diff --git a/src/conf_mode/protocols_ripng.py b/src/conf_mode/protocols_ripng.py new file mode 100755 index 000000000..8cc5de64a --- /dev/null +++ b/src/conf_mode/protocols_ripng.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os + +from sys import exit + +from vyos.config import Config +from vyos.configdict import dict_merge +from vyos.configverify import verify_route_maps +from vyos.util import call +from vyos.util import dict_search +from vyos.xml import defaults +from vyos.template import render_to_string +from vyos import ConfigError +from vyos import frr +from vyos import airbag +airbag.enable() + +frr_daemon = 'ripngd' + +def get_config(config=None): + if config: + conf = config + else: + conf = Config() + base = ['protocols', 'ripng'] + ripng = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + + # Bail out early if configuration tree does not exist + if not conf.exists(base): + return ripng + + # We have gathered the dict representation of the CLI, but there are default + # options which we need to update into the dictionary retrived. + default_values = defaults(base) + # merge in remaining default values + ripng = dict_merge(default_values, ripng) + + # We also need some additional information from the config, prefix-lists + # and route-maps for instance. They will be used in verify() + base = ['policy'] + tmp = conf.get_config_dict(base, key_mangling=('-', '_')) + # Merge policy dict into OSPF dict + ripng = dict_merge(tmp, ripng) + + import pprint + pprint.pprint(ripng) + return ripng + +def verify(ripng): + if not ripng: + return None + + acl_in = dict_search('distribute_list.access_list.in', ripng) + if acl_in and acl_in not in (dict_search('policy.access_list6', ripng) or []): + raise ConfigError(f'Inbound access-list6 "{acl_in}" does not exist!') + + acl_out = dict_search('distribute_list.access_list.out', ripng) + if acl_out and acl_out not in (dict_search('policy.access_list6', ripng) or []): + raise ConfigError(f'Outbound access-list6 "{acl_out}" does not exist!') + + prefix_list_in = dict_search('distribute_list.prefix_list.in', ripng) + if prefix_list_in and prefix_list_in.replace('-','_') not in (dict_search('policy.prefix_list6', ripng) or []): + raise ConfigError(f'Inbound prefix-list6 "{prefix_list_in}" does not exist!') + + prefix_list_out = dict_search('distribute_list.prefix_list.out', ripng) + if prefix_list_out and prefix_list_out.replace('-','_') not in (dict_search('policy.prefix_list6', ripng) or []): + raise ConfigError(f'Outbound prefix-list6 "{prefix_list_out}" does not exist!') + + if 'interface' in ripng: + for interface, interface_options in ripng['interface'].items(): + if 'authentication' in interface_options: + if {'md5', 'plaintext_password'} <= set(interface_options['authentication']): + raise ConfigError('Can not use both md5 and plaintext-password at the same time!') + if 'split_horizon' in interface_options: + if {'disable', 'poison_reverse'} <= set(interface_options['split_horizon']): + raise ConfigError(f'You can not have "split-horizon poison-reverse" enabled ' \ + f'with "split-horizon disable" for "{interface}"!') + + verify_route_maps(ripng) + +def generate(ripng): + if not ripng: + ripng['new_frr_config'] = '' + return None + + ripng['new_frr_config'] = render_to_string('frr/ripng.frr.tmpl', ripng) + import pprint + pprint.pprint(ripng['new_frr_config']) + + return None + +def apply(ripng): + # Save original configuration prior to starting any commit actions + frr_cfg = frr.FRRConfig() + frr_cfg.load_configuration(frr_daemon) + frr_cfg.modify_section(r'key chain \S+', '') + frr_cfg.modify_section(r'interface \S+', '') + frr_cfg.modify_section('router ripng', '') + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', ripng['new_frr_config']) + frr_cfg.commit_configuration(frr_daemon) + + # If FRR config is blank, rerun the blank commit x times due to frr-reload + # behavior/bug not properly clearing out on one commit. + if ripng['new_frr_config'] == '': + for a in range(5): + frr_cfg.commit_configuration(frr_daemon) + + return None + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) diff --git a/src/conf_mode/protocols_rpki.py b/src/conf_mode/protocols_rpki.py new file mode 100755 index 000000000..75b870b05 --- /dev/null +++ b/src/conf_mode/protocols_rpki.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os + +from sys import exit + +from vyos.config import Config +from vyos.configdict import dict_merge +from vyos.template import render_to_string +from vyos.util import call +from vyos.util import dict_search +from vyos.xml import defaults +from vyos import ConfigError +from vyos import frr +from vyos import airbag +airbag.enable() + +frr_daemon = 'bgpd' + +def get_config(config=None): + if config: + conf = config + else: + conf = Config() + base = ['protocols', 'rpki'] + + rpki = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + if not conf.exists(base): + return rpki + + # We have gathered the dict representation of the CLI, but there are default + # options which we need to update into the dictionary retrived. + default_values = defaults(base) + rpki = dict_merge(default_values, rpki) + + return rpki + +def verify(rpki): + if not rpki: + return None + + if 'cache' in rpki: + preferences = [] + for peer, peer_config in rpki['cache'].items(): + for mandatory in ['port', 'preference']: + if mandatory not in peer_config: + raise ConfigError(f'RPKI cache "{peer}" {mandatory} must be defined!') + + if 'preference' in peer_config: + preference = peer_config['preference'] + if preference in preferences: + raise ConfigError(f'RPKI cache with preference {preference} already configured!') + preferences.append(preference) + + if 'ssh' in peer_config: + files = ['private_key_file', 'public_key_file', 'known_hosts_file'] + for file in files: + if file not in peer_config['ssh']: + raise ConfigError('RPKI+SSH requires username, public/private ' \ + 'keys and known-hosts file to be defined!') + + filename = peer_config['ssh'][file] + if not os.path.exists(filename): + raise ConfigError(f'RPKI SSH {file.replace("-","-")} "{filename}" does not exist!') + + return None + +def generate(rpki): + rpki['new_frr_config'] = render_to_string('frr/rpki.frr.tmpl', rpki) + return None + +def apply(rpki): + # Save original configuration prior to starting any commit actions + frr_cfg = frr.FRRConfig() + frr_cfg.load_configuration(frr_daemon) + frr_cfg.modify_section('rpki', '') + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', rpki['new_frr_config']) + frr_cfg.commit_configuration(frr_daemon) + + # If FRR config is blank, re-run the blank commit x times due to frr-reload + # behavior/bug not properly clearing out on one commit. + if rpki['new_frr_config'] == '': + for a in range(5): + frr_cfg.commit_configuration(frr_daemon) + + return None + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py new file mode 100755 index 000000000..5d101b33e --- /dev/null +++ b/src/conf_mode/protocols_static.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os + +from sys import exit + +from vyos.config import Config +from vyos.template import render_to_string +from vyos.util import call +from vyos.configverify import verify_route_maps +from vyos import ConfigError +from vyos import frr +from vyos import airbag +airbag.enable() + +frr_daemon = 'staticd' + +def get_config(config=None): + if config: + conf = config + else: + conf = Config() + base = ['protocols', 'static'] + static = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + return static + +def verify(static): + verify_route_maps(static) + return None + +def generate(static): + static['new_frr_config'] = render_to_string('frr/static.frr.tmpl', static) + return None + +def apply(static): + # Save original configuration prior to starting any commit actions + frr_cfg = frr.FRRConfig() + frr_cfg.load_configuration(frr_daemon) + frr_cfg.modify_section(r'^ip route .*', '') + frr_cfg.modify_section(r'^ipv6 route .*', '') + frr_cfg.add_before(r'(interface .*|line vty)', static['new_frr_config']) + frr_cfg.commit_configuration(frr_daemon) + + # If FRR config is blank, rerun the blank commit x times due to frr-reload + # behavior/bug not properly clearing out on one commit. + if static['new_frr_config'] == '': + for a in range(5): + frr_cfg.commit_configuration(frr_daemon) + + return None + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) diff --git a/src/conf_mode/protocols_vrf.py b/src/conf_mode/protocols_vrf.py new file mode 100755 index 000000000..227e7d5e1 --- /dev/null +++ b/src/conf_mode/protocols_vrf.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os + +from sys import exit + +from vyos.config import Config +from vyos.template import render_to_string +from vyos.util import call +from vyos import ConfigError +from vyos import frr +from vyos import airbag +airbag.enable() + +frr_daemon = 'staticd' + +def get_config(config=None): + if config: + conf = config + else: + conf = Config() + base = ['protocols', 'vrf'] + vrf = conf.get_config_dict(base, key_mangling=('-', '_')) + return vrf + +def verify(vrf): + + return None + +def generate(vrf): + vrf['new_frr_config'] = render_to_string('frr/vrf.frr.tmpl', vrf) + return None + +def apply(vrf): + # Save original configuration prior to starting any commit actions + frr_cfg = frr.FRRConfig() + frr_cfg.load_configuration(frr_daemon) + frr_cfg.modify_section(r'vrf \S+', '') + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', vrf['new_frr_config']) + frr_cfg.commit_configuration(frr_daemon) + + # If FRR config is blank, rerun the blank commit x times due to frr-reload + # behavior/bug not properly clearing out on one commit. + if vrf['new_frr_config'] == '': + for a in range(5): + frr_cfg.commit_configuration(frr_daemon) + + return None + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) diff --git a/src/conf_mode/service_console-server.py b/src/conf_mode/service_console-server.py index 0e5fc75b0..6e94a19ae 100755 --- a/src/conf_mode/service_console-server.py +++ b/src/conf_mode/service_console-server.py @@ -25,7 +25,8 @@ from vyos.util import call from vyos.xml import defaults from vyos import ConfigError -config_file = r'/run/conserver/conserver.cf' +config_file = '/run/conserver/conserver.cf' +dropbear_systemd_file = '/etc/systemd/system/dropbear@{port}.service.d/override.conf' def get_config(config=None): if config: @@ -75,9 +76,22 @@ def generate(proxy): return None render(config_file, 'conserver/conserver.conf.tmpl', proxy) + if 'device' in proxy: + for device in proxy['device']: + if 'ssh' not in proxy['device'][device]: + continue + + tmp = { + 'device' : device, + 'port' : proxy['device'][device]['ssh']['port'], + } + render(dropbear_systemd_file.format(**tmp), + 'conserver/dropbear@.service.tmpl', tmp) + return None def apply(proxy): + call('systemctl daemon-reload') call('systemctl stop dropbear@*.service conserver-server.service') if not proxy: @@ -89,9 +103,10 @@ def apply(proxy): if 'device' in proxy: for device in proxy['device']: - if 'ssh' in proxy['device'][device]: - port = proxy['device'][device]['ssh']['port'] - call(f'systemctl restart dropbear@{device}.service') + if 'ssh' not in proxy['device'][device]: + continue + port = proxy['device'][device]['ssh']['port'] + call(f'systemctl restart dropbear@{port}.service') return None diff --git a/src/conf_mode/service_webproxy.py b/src/conf_mode/service_webproxy.py index 8dfae348a..cbbd2e0bc 100755 --- a/src/conf_mode/service_webproxy.py +++ b/src/conf_mode/service_webproxy.py @@ -123,9 +123,6 @@ def verify(proxy): ldap_auth = dict_search('authentication.method', proxy) == 'ldap' for address, config in proxy['listen_address'].items(): - if not is_addr_assigned(address): - raise ConfigError( - f'listen-address "{address}" not assigned on any interface!') if ldap_auth and 'disable_transparent' not in config: raise ConfigError('Authentication can not be configured when ' \ 'proxy is in transparent mode') diff --git a/src/conf_mode/vrrp.py b/src/conf_mode/vrrp.py index 4510dd3e7..680a80859 100755 --- a/src/conf_mode/vrrp.py +++ b/src/conf_mode/vrrp.py @@ -75,6 +75,7 @@ def get_config(config=None): group["backup_script"] = config.return_value("transition-script backup") group["fault_script"] = config.return_value("transition-script fault") group["stop_script"] = config.return_value("transition-script stop") + group["script_mode_force"] = config.exists("transition-script mode-force") if config.exists("no-preempt"): group["preempt"] = False @@ -183,6 +184,11 @@ def verify(data): if isinstance(pa, IPv4Address): raise ConfigError("VRRP group {0} uses IPv6 but its peer-address is IPv4".format(group["name"])) + # Warn the user about the deprecated mode-force option + if group['script_mode_force']: + print("""Warning: "transition-script mode-force" VRRP option is deprecated and will be removed in VyOS 1.4.""") + print("""It's no longer necessary, so you can safely remove it from your config now.""") + # Disallow same VRID on multiple interfaces _groups = sorted(vrrp_groups, key=(lambda x: x["interface"])) count = len(_groups) - 1 diff --git a/src/migration-scripts/conntrack/1-to-2 b/src/migration-scripts/conntrack/1-to-2 new file mode 100755 index 000000000..4fc88a1ed --- /dev/null +++ b/src/migration-scripts/conntrack/1-to-2 @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# Delete "set system conntrack modules gre" option + +import sys + +from vyos.configtree import ConfigTree + +if (len(sys.argv) < 1): + print("Must specify file name!") + sys.exit(1) + +file_name = sys.argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +config = ConfigTree(config_file) + +if not config.exists(['system', 'conntrack', 'modules', 'gre']): + # Nothing to do + sys.exit(0) +else: + # Delete abandoned node + config.delete(['system', 'conntrack', 'modules', 'gre']) + + try: + with open(file_name, 'w') as f: + f.write(config.to_string()) + except OSError as e: + print("Failed to save the modified config: {}".format(e)) + sys.exit(1) diff --git a/src/migration-scripts/interfaces/18-to-19 b/src/migration-scripts/interfaces/18-to-19 new file mode 100755 index 000000000..06e07572f --- /dev/null +++ b/src/migration-scripts/interfaces/18-to-19 @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from sys import argv +from sys import exit +from vyos.configtree import ConfigTree + +def migrate_ospf(config, path, interface): + path = path + ['ospf'] + if config.exists(path): + new_base = ['protocols', 'ospf', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ip ospf" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +def migrate_ospfv3(config, path, interface): + path = path + ['ospfv3'] + if config.exists(path): + new_base = ['protocols', 'ospfv3', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ipv6 ospfv3" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +def migrate_rip(config, path, interface): + path = path + ['rip'] + if config.exists(path): + new_base = ['protocols', 'rip', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ip rip" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +def migrate_ripng(config, path, interface): + path = path + ['ripng'] + if config.exists(path): + new_base = ['protocols', 'ripng', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ipv6 ripng" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +if __name__ == '__main__': + if (len(argv) < 1): + print("Must specify file name!") + exit(1) + + file_name = argv[1] + with open(file_name, 'r') as f: + config_file = f.read() + + config = ConfigTree(config_file) + + # + # Migrate "interface ethernet eth0 ip ospf" to "protocols ospf interface eth0" + # + for type in config.list_nodes(['interfaces']): + for interface in config.list_nodes(['interfaces', type]): + ip_base = ['interfaces', type, interface, 'ip'] + ipv6_base = ['interfaces', type, interface, 'ipv6'] + migrate_rip(config, ip_base, interface) + migrate_ripng(config, ipv6_base, interface) + migrate_ospf(config, ip_base, interface) + migrate_ospfv3(config, ipv6_base, interface) + + vif_path = ['interfaces', type, interface, 'vif'] + if config.exists(vif_path): + for vif in config.list_nodes(vif_path): + vif_ip_base = vif_path + [vif, 'ip'] + vif_ipv6_base = vif_path + [vif, 'ipv6'] + ifname = f'{interface}.{vif}' + + migrate_rip(config, vif_ip_base, ifname) + migrate_ripng(config, vif_ipv6_base, ifname) + migrate_ospf(config, vif_ip_base, ifname) + migrate_ospfv3(config, vif_ipv6_base, ifname) + + + vif_s_path = ['interfaces', type, interface, 'vif-s'] + if config.exists(vif_s_path): + for vif_s in config.list_nodes(vif_s_path): + vif_s_ip_base = vif_s_path + [vif_s, 'ip'] + vif_s_ipv6_base = vif_s_path + [vif_s, 'ipv6'] + + # vif-c interfaces MUST be migrated before their parent vif-s + # interface as the migrate_*() functions delete the path! + vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c'] + if config.exists(vif_c_path): + for vif_c in config.list_nodes(vif_c_path): + vif_c_ip_base = vif_c_path + [vif_c, 'ip'] + vif_c_ipv6_base = vif_c_path + [vif_c, 'ipv6'] + ifname = f'{interface}.{vif_s}.{vif_c}' + + migrate_rip(config, vif_c_ip_base, ifname) + migrate_ripng(config, vif_c_ipv6_base, ifname) + migrate_ospf(config, vif_c_ip_base, ifname) + migrate_ospfv3(config, vif_c_ipv6_base, ifname) + + + ifname = f'{interface}.{vif_s}' + migrate_rip(config, vif_s_ip_base, ifname) + migrate_ripng(config, vif_s_ipv6_base, ifname) + migrate_ospf(config, vif_s_ip_base, ifname) + migrate_ospfv3(config, vif_s_ipv6_base, ifname) + + try: + with open(file_name, 'w') as f: + f.write(config.to_string()) + except OSError as e: + print("Failed to save the modified config: {}".format(e)) + exit(1) diff --git a/src/migration-scripts/nat/4-to-5 b/src/migration-scripts/nat/4-to-5 index dda191719..b791996e2 100755 --- a/src/migration-scripts/nat/4-to-5 +++ b/src/migration-scripts/nat/4-to-5 @@ -36,9 +36,15 @@ if not config.exists(['nat']): exit(0) else: for direction in ['source', 'destination']: + # If a node doesn't exist, we obviously have nothing to do. if not config.exists(['nat', direction]): continue + # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist, + # but there are no rules under it. + if not config.list_nodes(['nat', direction]): + continue + for rule in config.list_nodes(['nat', direction, 'rule']): base = ['nat', direction, 'rule', rule] diff --git a/src/migration-scripts/quagga/6-to-7 b/src/migration-scripts/quagga/6-to-7 new file mode 100755 index 000000000..25cf5eebd --- /dev/null +++ b/src/migration-scripts/quagga/6-to-7 @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# - T3037, BGP address-family ipv6-unicast capability dynamic does not exist in +# FRR, there is only a base, per neighbor dynamic capability, migrate config + +from sys import argv +from sys import exit +from vyos.configtree import ConfigTree +from vyos.template import is_ipv4 +from vyos.template import is_ipv6 + +if (len(argv) < 2): + print("Must specify file name!") + exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +base = ['protocols', 'bgp'] +config = ConfigTree(config_file) + +if not config.exists(base): + # Nothing to do + exit(0) + +# Check if BGP is actually configured and obtain the ASN +asn_list = config.list_nodes(base) +if asn_list: + # There's always just one BGP node, if any + bgp_base = base + [asn_list[0]] + + for neighbor_type in ['neighbor', 'peer-group']: + if not config.exists(bgp_base + [neighbor_type]): + continue + for neighbor in config.list_nodes(bgp_base + [neighbor_type]): + # T2844 - add IPv4 AFI disable-send-community support + send_comm_path = bgp_base + [neighbor_type, neighbor, 'disable-send-community'] + if config.exists(send_comm_path): + new_base = bgp_base + [neighbor_type, neighbor, 'address-family', 'ipv4-unicast'] + config.set(new_base) + config.copy(send_comm_path, new_base + ['disable-send-community']) + config.delete(send_comm_path) + + cap_dynamic = False + peer_group = None + for afi in ['ipv4-unicast', 'ipv6-unicast']: + afi_path = bgp_base + [neighbor_type, neighbor, 'address-family', afi] + # Exit loop early if AFI does not exist + if not config.exists(afi_path): + continue + + cap_path = afi_path + ['capability', 'dynamic'] + if config.exists(cap_path): + cap_dynamic = True + config.delete(cap_path) + + # We have now successfully migrated the address-family + # specific dynamic capability to the neighbor/peer-group + # level. If this has been the only option under the + # address-family nodes, we can clean them up by checking if + # no other nodes are left under that tree and if so, delete + # the parent. + # + # We walk from the most inner node to the most outer one. + cleanup = -1 + while len(config.list_nodes(cap_path[:cleanup])) == 0: + config.delete(cap_path[:cleanup]) + cleanup -= 1 + + peer_group_path = afi_path + ['peer-group'] + if config.exists(peer_group_path): + if ((is_ipv4(neighbor) and afi == 'ipv4-unicast') or + (is_ipv6(neighbor) and afi == 'ipv6-unicast')): + peer_group = config.return_value(peer_group_path) + + config.delete(peer_group_path) + + # We have now successfully migrated the address-family + # specific peer-group to the neighbor level. If this has + # been the only option under the address-family nodes, we + # can clean them up by checking if no other nodes are left + # under that tree and if so, delete the parent. + # + # We walk from the most inner node to the most outer one. + cleanup = -1 + while len(config.list_nodes(peer_group_path[:cleanup])) == 0: + config.delete(peer_group_path[:cleanup]) + cleanup -= 1 + + if cap_dynamic: + config.set(bgp_base + [neighbor_type, neighbor, 'capability', 'dynamic']) + if peer_group: + config.set(bgp_base + [neighbor_type, neighbor, 'peer-group'], value=peer_group) + +try: + with open(file_name, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print("Failed to save the modified config: {}".format(e)) + exit(1) diff --git a/src/migration-scripts/quagga/7-to-8 b/src/migration-scripts/quagga/7-to-8 new file mode 100755 index 000000000..9c277a6f1 --- /dev/null +++ b/src/migration-scripts/quagga/7-to-8 @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# - T2450: drop interface-route and interface-route6 from "protocols static" + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree + +def migrate_interface_route(config, base, path, route_route6): + """ Generic migration function which can be called on every instance of + interface-route, beeing it ipv4, ipv6 or nested under the "static table" nodes. + + What we do? + - Drop 'interface-route' or 'interface-route6' and migrate the route unter the + 'route' or 'route6' tag node. + """ + if config.exists(base + path): + for route in config.list_nodes(base + path): + interface = config.list_nodes(base + path + [route, 'next-hop-interface']) + + tmp = base + path + [route, 'next-hop-interface'] + for interface in config.list_nodes(tmp): + new_base = base + [route_route6, route, 'interface'] + config.set(new_base) + config.set_tag(base + [route_route6]) + config.set_tag(new_base) + config.copy(tmp + [interface], new_base + [interface]) + + config.delete(base + path) + +def migrate_route(config, base, path, route_route6): + """ Generic migration function which can be called on every instance of + route, beeing it ipv4, ipv6 or even nested under the static table nodes. + + What we do? + - for consistency reasons rename next-hop-interface to interface + - for consistency reasons rename next-hop-vrf to vrf + """ + if config.exists(base + path): + for route in config.list_nodes(base + path): + next_hop = base + path + [route, 'next-hop'] + if config.exists(next_hop): + for gateway in config.list_nodes(next_hop): + # IPv4 routes calls it next-hop-interface, rename this to + # interface instead so it's consitent with IPv6 + interface_path = next_hop + [gateway, 'next-hop-interface'] + if config.exists(interface_path): + config.rename(interface_path, 'interface') + + # When VRFs got introduced, I (c-po) named it next-hop-vrf, + # we can also call it vrf which is simply shorter. + vrf_path = next_hop + [gateway, 'next-hop-vrf'] + if config.exists(vrf_path): + config.rename(vrf_path, 'vrf') + + +if (len(argv) < 2): + print("Must specify file name!") + exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +base = ['protocols', 'static'] + +config = ConfigTree(config_file) +if not config.exists(base): + # Nothing to do + exit(0) + +# Migrate interface-route into route +migrate_interface_route(config, base, ['interface-route'], 'route') + +# Migrate interface-route6 into route6 +migrate_interface_route(config, base, ['interface-route6'], 'route6') + +# Cleanup nodes inside route +migrate_route(config, base, ['route'], 'route') + +# Cleanup nodes inside route6 +migrate_route(config, base, ['route6'], 'route6') + +# +# PBR table cleanup +table_path = base + ['table'] +if config.exists(table_path): + for table in config.list_nodes(table_path): + # Migrate interface-route into route + migrate_interface_route(config, table_path + [table], ['interface-route'], 'route') + + # Migrate interface-route6 into route6 + migrate_interface_route(config, table_path + [table], ['interface-route6'], 'route6') + + # Cleanup nodes inside route + migrate_route(config, table_path + [table], ['route'], 'route') + + # Cleanup nodes inside route6 + migrate_route(config, table_path + [table], ['route6'], 'route6') + +try: + with open(file_name, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print("Failed to save the modified config: {}".format(e)) + exit(1) diff --git a/src/migration-scripts/rpki/0-to-1 b/src/migration-scripts/rpki/0-to-1 new file mode 100755 index 000000000..5b4893205 --- /dev/null +++ b/src/migration-scripts/rpki/0-to-1 @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from sys import exit +from sys import argv +from vyos.configtree import ConfigTree + +if (len(argv) < 1): + print("Must specify file name!") + exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +base = ['protocols', 'rpki'] +config = ConfigTree(config_file) + +# Nothing to do +if not config.exists(base): + exit(0) + +if config.exists(base + ['cache']): + preference = 1 + for cache in config.list_nodes(base + ['cache']): + address_node = base + ['cache', cache, 'address'] + if config.exists(address_node): + address = config.return_value(address_node) + # We do not longer support the address leafNode, RPKI cache server + # IP address is now used from the tagNode + config.delete(address_node) + # VyOS 1.2 had no per instance preference, setting new defaults + config.set(base + ['cache', cache, 'preference'], value=preference) + # Increase preference for the next caching peer - actually VyOS 1.2 + # supported only one but better save then sorry (T3253) + preference += 1 + + # T3293: If the RPKI cache name equals the configured address, + # renaming is not possible, as rename expects the new path to not + # exist. + if not config.exists(base + ['cache', address]): + config.rename(base + ['cache', cache], address) + +try: + with open(file_name, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print("Failed to save the modified config: {}".format(e)) + exit(1) diff --git a/src/migration-scripts/system/18-to-19 b/src/migration-scripts/system/18-to-19 index dd2abce00..fd0e15d42 100755 --- a/src/migration-scripts/system/18-to-19 +++ b/src/migration-scripts/system/18-to-19 @@ -80,8 +80,8 @@ else: dhcp_interfaces.append(f'{intf}.{vif_s}') # try vif-c - if config.exists(intf_base + ['vif-c', vif_c]): - for vif_c in config.list_nodes(vif_s_base + ['vif-c', vif_c]): + if config.exists(intf_base + ['vif-c']): + for vif_c in config.list_nodes(vif_s_base + ['vif-c']): vif_c_base = vif_s_base + ['vif-c', vif_c] if config.exists(vif_c_base + ['address']): for addr in config.return_values(vif_c_base + ['address']): diff --git a/src/migration-scripts/vrf/0-to-1 b/src/migration-scripts/vrf/0-to-1 new file mode 100755 index 000000000..29b2fab74 --- /dev/null +++ b/src/migration-scripts/vrf/0-to-1 @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# - T2450: drop interface-route and interface-route6 from "protocols vrf" + +from sys import argv +from sys import exit +from vyos.configtree import ConfigTree + +if (len(argv) < 2): + print("Must specify file name!") + exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +base = ['protocols', 'vrf'] +config = ConfigTree(config_file) + +if not config.exists(base): + # Nothing to do + exit(0) + +for vrf in config.list_nodes(base): + static_base = base + [vrf, 'static'] + if not config.exists(static_base): + continue + + # + # Migrate interface-route into route + # + interface_route_path = static_base + ['interface-route'] + if config.exists(interface_route_path): + for route in config.list_nodes(interface_route_path): + interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface']) + + tmp = interface_route_path + [route, 'next-hop-interface'] + for interface in config.list_nodes(tmp): + new_base = static_base + ['route', route, 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(tmp + [interface], new_base + [interface]) + + config.delete(interface_route_path) + + # + # Migrate interface-route6 into route6 + # + interface_route_path = static_base + ['interface-route6'] + if config.exists(interface_route_path): + for route in config.list_nodes(interface_route_path): + interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface']) + + tmp = interface_route_path + [route, 'next-hop-interface'] + for interface in config.list_nodes(tmp): + new_base = static_base + ['route6', route, 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(tmp + [interface], new_base + [interface]) + + config.delete(interface_route_path) + + # + # Cleanup nodes inside route + # + route_path = static_base + ['route'] + if config.exists(route_path): + for route in config.list_nodes(route_path): + next_hop = route_path + [route, 'next-hop'] + if config.exists(next_hop): + for gateway in config.list_nodes(next_hop): + interface_path = next_hop + [gateway, 'next-hop-interface'] + if config.exists(interface_path): + config.rename(interface_path, 'interface') + vrf_path = next_hop + [gateway, 'next-hop-vrf'] + if config.exists(vrf_path): + config.rename(vrf_path, 'vrf') + + # + # Cleanup nodes inside route6 + # + route_path = static_base + ['route6'] + if config.exists(route_path): + for route in config.list_nodes(route_path): + next_hop = route_path + [route, 'next-hop'] + if config.exists(next_hop): + for gateway in config.list_nodes(next_hop): + vrf_path = next_hop + [gateway, 'next-hop-vrf'] + if config.exists(vrf_path): + config.rename(vrf_path, 'vrf') + +try: + with open(file_name, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print("Failed to save the modified config: {}".format(e)) + exit(1) diff --git a/src/op_mode/show_neigh.py b/src/op_mode/show_neigh.py new file mode 100755 index 000000000..94e745493 --- /dev/null +++ b/src/op_mode/show_neigh.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +#ip -j -f inet neigh list | jq +#[ + #{ + #"dst": "192.168.101.8", + #"dev": "enp0s25", + #"lladdr": "78:d2:94:72:77:7e", + #"state": [ + #"STALE" + #] + #}, + #{ + #"dst": "192.168.101.185", + #"dev": "enp0s25", + #"lladdr": "34:46:ec:76:f8:9b", + #"state": [ + #"STALE" + #] + #}, + #{ + #"dst": "192.168.101.225", + #"dev": "enp0s25", + #"lladdr": "c2:cb:fa:bf:a0:35", + #"state": [ + #"STALE" + #] + #}, + #{ + #"dst": "192.168.101.1", + #"dev": "enp0s25", + #"lladdr": "00:98:2b:f8:3f:11", + #"state": [ + #"REACHABLE" + #] + #}, + #{ + #"dst": "192.168.101.181", + #"dev": "enp0s25", + #"lladdr": "d8:9b:3b:d5:88:22", + #"state": [ + #"STALE" + #] + #} +#] + +import sys +import argparse +import json +from vyos.util import cmd + +def main(): + #parese args + parser = argparse.ArgumentParser() + parser.add_argument('--family', help='Protocol family', required=True) + args = parser.parse_args() + + neigh_raw_json = cmd(f'ip -j -f {args.family} neigh list') + neigh_raw_json = neigh_raw_json.lower() + neigh_json = json.loads(neigh_raw_json) + + format_neigh = '%-50s %-10s %-20s %s' + print(format_neigh % ("IP Address", "Device", "State", "LLADDR")) + print(format_neigh % ("----------", "------", "-----", "------")) + + if neigh_json is not None: + for neigh_item in neigh_json: + dev = neigh_item['dev'] + dst = neigh_item['dst'] + lladdr = neigh_item['lladdr'] if 'lladdr' in neigh_item else '' + state = neigh_item['state'] + + i = 0 + for state_item in state: + if i == 0: + print(format_neigh % (dst, dev, state_item, lladdr)) + else: + print(format_neigh % ('', '', state_item, '')) + i+=1 + +if __name__ == '__main__': + main() diff --git a/src/op_mode/vtysh_wrapper.sh b/src/op_mode/vtysh_wrapper.sh new file mode 100755 index 000000000..47d88330b --- /dev/null +++ b/src/op_mode/vtysh_wrapper.sh @@ -0,0 +1,4 @@ +#!/bin/sh +declare -a tmp +tmp=$@ +vtysh -c "$tmp" diff --git a/src/services/vyos-configd b/src/services/vyos-configd index 5b1ab1f1f..7aea77f5a 100755 --- a/src/services/vyos-configd +++ b/src/services/vyos-configd @@ -25,6 +25,7 @@ import logging import signal import importlib.util import zmq +from contextlib import redirect_stdout, redirect_stderr from vyos.defaults import directories from vyos.configsource import ConfigSourceString, ConfigSourceError @@ -33,6 +34,8 @@ from vyos import ConfigError CFG_GROUP = 'vyattacfg' +script_stdout_log = '/tmp/vyos-configd-script-stdout' + debug = True logger = logging.getLogger(__name__) @@ -59,7 +62,7 @@ configd_env_unset_file = os.path.join(directories['data'], 'vyos-configd-env-uns # sourced on entering config session configd_env_file = '/etc/default/vyos-configd-env' -session_tty = None +session_out = None def key_name_from_file_name(f): return os.path.splitext(f)[0] @@ -104,33 +107,29 @@ conf_mode_scripts = dict(zip(imports, modules)) exclude_set = {key_name_from_file_name(f) for f in filenames if f not in include} include_set = {key_name_from_file_name(f) for f in filenames if f in include} -def explicit_print(t, m): - try: - with open(t, 'w') as f: - f.write(m) - f.write("\n") - f.flush() - except Exception: - pass def run_script(script, config) -> int: config.set_level([]) try: - c = script.get_config(config) - script.verify(c) - script.generate(c) - script.apply(c) + with open(session_out, 'a') as f, redirect_stdout(f): + with redirect_stderr(f): + c = script.get_config(config) + script.verify(c) + script.generate(c) + script.apply(c) except ConfigError as e: logger.critical(e) - explicit_print(session_tty, str(e)) + with open(session_out, 'a') as f, redirect_stdout(f): + print(f"{e}\n") return R_ERROR_COMMIT - except Exception: + except Exception as e: + logger.critical(e) return R_ERROR_DAEMON return R_SUCCESS def initialization(socket): - global session_tty + global session_out # Reset config strings: active_string = '' session_string = '' @@ -158,9 +157,13 @@ def initialization(socket): logger.debug(f"config session pid is {pid_string}") try: - session_tty = os.readlink(f"/proc/{pid_string}/fd/1") + session_out = os.readlink(f"/proc/{pid_string}/fd/1") except FileNotFoundError: - session_tty = None + session_out = None + + # if not a 'live' session, for example on boot, write to file + if '/dev/pts' not in session_out: + session_out = script_stdout_log try: configsource = ConfigSourceString(running_config_text=active_string, diff --git a/src/system/on-dhcp-event.sh b/src/system/on-dhcp-event.sh index a062dc810..49e53d7e1 100755 --- a/src/system/on-dhcp-event.sh +++ b/src/system/on-dhcp-event.sh @@ -21,21 +21,20 @@ client_mac=$4 domain=$5 hostsd_client="/usr/bin/vyos-hostsd-client" -if [ -z "$client_name" ]; then - logger -s -t on-dhcp-event "Client name was empty, using MAC \"$client_mac\" instead" - client_name=$(echo "client-"$client_mac | tr : -) -fi - -if [ "$domain" == "..YYZ!" ]; then - client_fqdn_name=$client_name - client_search_expr=$client_name -else - client_fqdn_name=$client_name.$domain - client_search_expr="$client_name\\.$domain" -fi - case "$action" in commit) # add mapping for new lease + if [ -z "$client_name" ]; then + logger -s -t on-dhcp-event "Client name was empty, using MAC \"$client_mac\" instead" + client_name=$(echo "client-"$client_mac | tr : -) + fi + + if [ "$domain" == "..YYZ!" ]; then + client_fqdn_name=$client_name + client_search_expr=$client_name + else + client_fqdn_name=$client_name.$domain + client_search_expr="$client_name\\.$domain" + fi $hostsd_client --add-hosts "$client_fqdn_name,$client_ip" --tag "dhcp-server-$client_ip" --apply exit 0 ;; diff --git a/src/systemd/dropbear@.service b/src/systemd/dropbear@.service index a3fde5708..acf926af9 100644 --- a/src/systemd/dropbear@.service +++ b/src/systemd/dropbear@.service @@ -8,9 +8,8 @@ StartLimitIntervalSec=0 [Service] Type=forking -ExecStartPre=/usr/bin/bash -c '/usr/bin/systemctl set-environment PORT=$(cli-shell-api returnActiveValue service console-server device "%I" ssh port)' -ExecStart=-/usr/sbin/dropbear -w -j -k -r /etc/dropbear/dropbear_rsa_host_key -c "/usr/bin/console %I" -P /run/conserver/dropbear.%I.pid -p ${PORT} -PIDFile=/run/conserver/dropbear.%I.pid +ExecStart=/usr/sbin/dropbear -w -j -k -r /etc/dropbear/dropbear_rsa_host_key -P /run/dropbear/dropbear.%I.pid -p %I +PIDFile=/run/dropbear/dropbear.%I.pid KillMode=process Restart=always RestartSec=10 diff --git a/src/validators/fqdn b/src/validators/fqdn index 347ffda42..66276c093 100755 --- a/src/validators/fqdn +++ b/src/validators/fqdn @@ -17,11 +17,9 @@ import re import sys - # pattern copied from: https://www.regextester.com/103452 pattern = "(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)" - if __name__ == '__main__': if len(sys.argv) != 2: sys.exit(1) diff --git a/src/validators/interface-name b/src/validators/interface-name new file mode 100755 index 000000000..8e337b401 --- /dev/null +++ b/src/validators/interface-name @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import re +import sys + +pattern = '^(bond|br|dum|en|ersp|eth|gnv|lan|l2tp|l2tpeth|macsec|peth|ppp|pppoe|pptp|sstp|tun|vti|vtun|vxlan|wg|wlan|wlm)[0-9]+|lo$' + +if __name__ == '__main__': + if len(sys.argv) != 2: + sys.exit(1) + if not re.match(pattern, sys.argv[1]): + sys.exit(1) + sys.exit(0) |