diff options
21 files changed, 650 insertions, 369 deletions
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) diff --git a/data/templates/frr/rip.frr.tmpl b/data/templates/frr/rip.frr.tmpl index eeaee7199..c0d062fc6 100644 --- a/data/templates/frr/rip.frr.tmpl +++ b/data/templates/frr/rip.frr.tmpl @@ -1,4 +1,39 @@ ! +{# 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 %} +! +{# 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 %} +! router rip {% if default_information is defined and default_information.originate is defined %} default-information originate diff --git a/interface-definitions/include/ospf-authentication.xml.i b/interface-definitions/include/ospf-authentication.xml.i index 0963e5cc0..efb29c1f0 100644 --- a/interface-definitions/include/ospf-authentication.xml.i +++ b/interface-definitions/include/ospf-authentication.xml.i @@ -16,6 +16,9 @@ <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"> @@ -25,6 +28,10 @@ <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> @@ -38,6 +45,10 @@ <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> 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/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..1d5e6f949 --- /dev/null +++ b/interface-definitions/include/rip-interface.xml.i @@ -0,0 +1,85 @@ +<!-- 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="authentication"> + <properties> + <help>Authentication</help> + </properties> + <children> + <tagNode name="md5"> + <properties> + <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="password"> + <properties> + <help>Authentication password</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> + <leafNode name="plaintext-password"> + <properties> + <help>Plain text password</help> + <valueHelp> + <format>txt</format> + <description>Plain text password (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> + </node> + <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-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/protocols-ospf.xml.in b/interface-definitions/protocols-ospf.xml.in index ee350fb17..a616c0e60 100644 --- a/interface-definitions/protocols-ospf.xml.in +++ b/interface-definitions/protocols-ospf.xml.in @@ -404,6 +404,13 @@ <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> diff --git a/interface-definitions/protocols-rip.xml.in b/interface-definitions/protocols-rip.xml.in index 2587e94c3..4ced26d8a 100644 --- a/interface-definitions/protocols-rip.xml.in +++ b/interface-definitions/protocols-rip.xml.in @@ -19,31 +19,8 @@ </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> @@ -60,6 +37,9 @@ <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> @@ -69,19 +49,7 @@ #include <include/rip-prefix-list.xml.i> </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> + #include <include/rip-interface.xml.i> <leafNode name="neighbor"> <properties> <help>Neighbor router</help> @@ -196,52 +164,7 @@ <multi/> </properties> </leafNode> - <node name="timers"> - <properties> - <help>RIP timer values</help> - </properties> - <children> - <leafNode name="garbage-collection"> - <properties> - <help>Garbage collection timer (default: 120)</help> - <valueHelp> - <format>u32:5-2147483647</format> - <description>Garbage colletion time</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 (default: 180)</help> - <valueHelp> - <format>u32:5-2147483647</format> - <description>Routing information timeout timer</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 (default: 30)</help> - <valueHelp> - <format>u32:5-2147483647</format> - <description>Routing table update timer in seconds</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 5-2147483647"/> - </constraint> - </properties> - <defaultValue>30</defaultValue> - </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 index 2fca0f5dd..74f720e89 100644 --- a/interface-definitions/protocols-ripng.xml.in +++ b/interface-definitions/protocols-ripng.xml.in @@ -20,67 +20,14 @@ <multi/> </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>Default 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:1-4294967295</format> - <description>Access list to apply to input packets</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-4294967295"/> - </constraint> - </properties> - </leafNode> - <leafNode name="out"> - <properties> - <help>Access list to apply to output packets</help> - <valueHelp> - <format>u32:1-4294967295</format> - <description>Access list to apply to output packets</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-4294967295"/> - </constraint> - </properties> - </leafNode> - </children> - </node> + #include <include/rip-access-list6.xml.i> <tagNode name="interface"> <properties> <help>Apply filtering to an interface</help> @@ -91,118 +38,19 @@ <completionHelp> <script>${vyos_completion_dir}/list_interfaces.py</script> </completionHelp> + <constraint> + <validator name="interface-name"/> + </constraint> </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:1-4294967295</format> - <description>Access list to apply to input packets</description> - </valueHelp> - <completionHelp> - <path>policy access-list6</path> - </completionHelp> - </properties> - </leafNode> - <leafNode name="out"> - <properties> - <help>Access list to apply to output packets</help> - <valueHelp> - <format>u32:1-4294967295</format> - <description>Access list to apply to output packets</description> - </valueHelp> - <completionHelp> - <path>policy access-list</path> - </completionHelp> - </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-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> + #include <include/rip-access-list6.xml.i> + #include <include/rip-prefix-list6.xml.i> </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"> - <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> + #include <include/rip-prefix-list6.xml.i> </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> + #include <include/rip-interface.xml.i> <leafNode name="network"> <properties> <help>RIPng network</help> @@ -289,60 +137,8 @@ <multi/> </properties> </leafNode> - <leafNode name="route-map"> - <properties> - <help>Filter routes installed in local route map</help> - <completionHelp> - <path>policy route-map</path> - </completionHelp> - </properties> - </leafNode> - <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> + #include <include/ospf-route-map.xml.i> + #include <include/rip-timers.xml.i> </children> </node> </children> diff --git a/smoketest/configs/rip-router b/smoketest/configs/rip-router new file mode 100644 index 000000000..0a3a41103 --- /dev/null +++ b/smoketest/configs/rip-router @@ -0,0 +1,138 @@ +interfaces { + dummy dum0 { + address 192.0.2.0/32 + } + ethernet eth0 { + duplex auto + ip { + rip { + authentication { + md5 1 { + password VyOSsecure + } + } + 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 + } + } + } + } + vif-s 200 { + ip { + rip { + authentication { + md5 1 { + password VyOSsecure + } + } + split-horizon { + disable + } + } + } + vif-c 2000 { + ip { + rip { + authentication { + md5 1 { + password VyOSsecure + } + } + } + } + } + vif-c 3000 { + ip { + rip { + split-horizon { + disable + } + } + } + } + } + } +} +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 { + } + } + } +} +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/scripts/cli/test_protocols_rip.py b/smoketest/scripts/cli/test_protocols_rip.py index 1bd069638..2c5c9030a 100755 --- a/smoketest/scripts/cli/test_protocols_rip.py +++ b/smoketest/scripts/cli/test_protocols_rip.py @@ -64,7 +64,7 @@ class TestProtocolsRIP(unittest.TestCase): # Check for running process self.assertTrue(process_named_running(PROCESS_NAME)) - def test_rip_simple(self): + def test_rip(self): distance = '40' network_distance = '66' metric = '8' diff --git a/smoketest/scripts/cli/test_protocols_ripng.py b/smoketest/scripts/cli/test_protocols_ripng.py new file mode 100755 index 000000000..90cbaccd8 --- /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' 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 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/src/conf_mode/protocols_rip.py b/src/conf_mode/protocols_rip.py index bb3790fb2..06d7c6d49 100755 --- a/src/conf_mode/protocols_rip.py +++ b/src/conf_mode/protocols_rip.py @@ -89,6 +89,16 @@ def verify(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!') + 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}"!') + verify_route_maps(rip) def generate(rip): @@ -106,6 +116,7 @@ def apply(rip): # 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']) diff --git a/src/migration-scripts/interfaces/18-to-19 b/src/migration-scripts/interfaces/18-to-19 index 965b76a04..31e253098 100755 --- a/src/migration-scripts/interfaces/18-to-19 +++ b/src/migration-scripts/interfaces/18-to-19 @@ -18,6 +18,34 @@ 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_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]) + if __name__ == '__main__': if (len(argv) < 1): print("Must specify file name!") @@ -34,64 +62,33 @@ if __name__ == '__main__': # for type in config.list_nodes(['interfaces']): for interface in config.list_nodes(['interfaces', type]): - - ip_ospf = ['interfaces', type, interface, 'ip', 'ospf'] - if config.exists(ip_ospf): - config.set(['protocols', 'ospf', 'interface']) - config.set_tag(['protocols', 'ospf', 'interface']) - config.copy(ip_ospf, ['protocols', 'ospf', 'interface', interface]) - config.delete(ip_ospf) - - # if "ip ospf" was the only setting, we can clean out the empty - # ip node afterwards - if len(config.list_nodes(ip_ospf[:-1])) == 0: - config.delete(ip_ospf[:-1]) + if_base = ['interfaces', type, interface, 'ip'] + migrate_rip(config, if_base, interface) + migrate_ospf(config, if_base, interface) vif_path = ['interfaces', type, interface, 'vif'] if config.exists(vif_path): for vif in config.list_nodes(vif_path): - vif_ospf_path = vif_path + [vif, 'ip', 'ospf'] - if config.exists(vif_ospf_path): - config.set(['protocols', 'ospf', 'interface']) - config.set_tag(['protocols', 'ospf', 'interface']) - config.copy(vif_ospf_path, ['protocols', 'ospf', 'interface', f'{interface}.{vif}']) - config.delete(vif_ospf_path) - - # if "ip ospf" was the only setting, we can clean out the empty - # ip node afterwards - if len(config.list_nodes(vif_ospf_path[:-1])) == 0: - config.delete(vif_ospf_path[:-1]) + vif_if_base = vif_path + [vif, 'ip'] + migrate_rip(config, vif_if_base, f'{interface}.{vif}') + migrate_ospf(config, vif_if_base, f'{interface}.{vif}') 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_ospf_path = vif_s_path + [vif_s, 'ip', 'ospf'] - if config.exists(vif_s_ospf_path): - config.set(['protocols', 'ospf', 'interface']) - config.set_tag(['protocols', 'ospf', 'interface']) - config.copy(vif_s_ospf_path, ['protocols', 'ospf', 'interface', f'{interface}.{vif_s}']) + vif_s_if_base = vif_s_path + [vif_s, 'ip'] - 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_ospf_path = vif_c_path + [vif_c, 'ip', 'ospf'] - if config.exists(vif_c_ospf_path): - config.set(['protocols', 'ospf', 'interface']) - config.set_tag(['protocols', 'ospf', 'interface']) - config.copy(vif_c_ospf_path, ['protocols', 'ospf', 'interface', f'{interface}.{vif_s}.{vif_c}']) - config.delete(vif_c_ospf_path) + # 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_if_base = vif_c_path + [vif_c, 'ip'] + migrate_rip(config, vif_c_if_base, f'{interface}.{vif_s}.{vif_c}') + migrate_ospf(config, vif_c_if_base, f'{interface}.{vif_s}.{vif_c}') - # if "ip ospf" was the only setting, we can clean out the empty - # ip node afterwards - if len(config.list_nodes(vif_c_ospf_path[:-1])) == 0: - config.delete(vif_c_ospf_path[:-1]) - - config.delete(vif_s_ospf_path) - - # if "ip ospf" was the only setting, we can clean out the empty - # ip node afterwards - if len(config.list_nodes(vif_s_ospf_path[:-1])) == 0: - config.delete(vif_s_ospf_path[:-1]) + migrate_rip(config, vif_s_if_base, f'{interface}.{vif_s}') + migrate_ospf(config, vif_s_if_base, f'{interface}.{vif_s}') try: with open(file_name, 'w') as f: @@ -99,4 +96,3 @@ if __name__ == '__main__': 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 index 9058af016..5b4893205 100755 --- a/src/migration-scripts/rpki/0-to-1 +++ b/src/migration-scripts/rpki/0-to-1 @@ -48,7 +48,12 @@ if config.exists(base + ['cache']): # Increase preference for the next caching peer - actually VyOS 1.2 # supported only one but better save then sorry (T3253) preference += 1 - config.rename(base + ['cache', cache], address) + + # 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: 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']): |