summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniil Baturin <daniil@vyos.io>2023-04-13 15:07:50 +0100
committerGitHub <noreply@github.com>2023-04-13 15:07:50 +0100
commit0439599a8e31ee1a4252a2c38bb512f414388870 (patch)
tree74fdaf45958ca6cd209a4aa3c45bc5b5bc307127
parent78d846824df05682f63c2dc7d894aa501ed9f63f (diff)
parent7d642a2862dcd0c7c2f80ac42ea9427970804d06 (diff)
downloadvyos-1x-0439599a8e31ee1a4252a2c38bb512f414388870.tar.gz
vyos-1x-0439599a8e31ee1a4252a2c38bb512f414388870.zip
Merge pull request #1943 from c-po/t5150-frr
T5150: implementation of new Kernel/Zebra route-map support
-rw-r--r--data/configd-include.json1
-rw-r--r--data/templates/frr/vrf-vni.frr.j29
-rw-r--r--data/templates/frr/vrf.route-map.frr.j210
-rw-r--r--data/templates/frr/vrf.route-map.v6.frr.j210
-rw-r--r--data/templates/frr/zebra.route-map.frr.j29
-rw-r--r--data/templates/frr/zebra.vrf.route-map.frr.j224
-rw-r--r--interface-definitions/include/bgp/protocol-common-config.xml.i1
-rw-r--r--interface-definitions/include/eigrp/protocol-common-config.xml.i1
-rw-r--r--interface-definitions/include/isis/protocol-common-config.xml.i1
-rw-r--r--interface-definitions/include/ospf/protocol-common-config.xml.i1
-rw-r--r--interface-definitions/include/ospfv3/protocol-common-config.xml.i1
-rw-r--r--interface-definitions/include/system-ip-protocol.xml.i56
-rw-r--r--interface-definitions/include/system-ipv6-protocol.xml.i52
-rw-r--r--interface-definitions/include/version/bgp-version.xml.i2
-rw-r--r--interface-definitions/include/version/isis-version.xml.i2
-rw-r--r--interface-definitions/include/version/ospf-version.xml.i2
-rw-r--r--interface-definitions/include/version/quagga-version.xml.i2
-rw-r--r--interface-definitions/include/version/rip-version.xml.i3
-rw-r--r--interface-definitions/system-ip.xml.in1
-rw-r--r--interface-definitions/system-ipv6.xml.in1
-rw-r--r--interface-definitions/vrf.xml.in17
-rw-r--r--interface-definitions/xml-component-version.xml.in1
-rw-r--r--smoketest/configs/egb-igp-route-maps127
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bgp.py32
-rwxr-xr-xsmoketest/scripts/cli/test_system_ip.py29
-rwxr-xr-xsmoketest/scripts/cli/test_system_ipv6.py34
-rwxr-xr-xsmoketest/scripts/cli/test_vrf.py80
-rwxr-xr-xsrc/conf_mode/protocols_bgp.py11
-rwxr-xr-xsrc/conf_mode/protocols_eigrp.py10
-rwxr-xr-xsrc/conf_mode/protocols_isis.py14
-rwxr-xr-xsrc/conf_mode/protocols_ospf.py11
-rwxr-xr-xsrc/conf_mode/protocols_ospfv3.py10
-rwxr-xr-xsrc/conf_mode/protocols_static.py8
-rwxr-xr-xsrc/conf_mode/system-ip.py38
-rwxr-xr-xsrc/conf_mode/system-ipv6.py38
-rwxr-xr-xsrc/conf_mode/vrf.py49
-rwxr-xr-xsrc/conf_mode/vrf_vni.py65
-rwxr-xr-xsrc/migration-scripts/bgp/3-to-464
-rwxr-xr-xsrc/migration-scripts/isis/2-to-363
-rwxr-xr-xsrc/migration-scripts/ospf/1-to-280
-rwxr-xr-xsrc/migration-scripts/quagga/10-to-1151
-rwxr-xr-xsrc/migration-scripts/rip/0-to-151
42 files changed, 847 insertions, 225 deletions
diff --git a/data/configd-include.json b/data/configd-include.json
index 456211caa..1c843e9fa 100644
--- a/data/configd-include.json
+++ b/data/configd-include.json
@@ -86,5 +86,4 @@
"vpn_pptp.py",
"vpn_sstp.py",
"vrf.py",
-"vrf_vni.py"
]
diff --git a/data/templates/frr/vrf-vni.frr.j2 b/data/templates/frr/vrf-vni.frr.j2
deleted file mode 100644
index e5f4810a1..000000000
--- a/data/templates/frr/vrf-vni.frr.j2
+++ /dev/null
@@ -1,9 +0,0 @@
-{% if name is vyos_defined %}
-{% for vrf, vrf_config in name.items() %}
-vrf {{ vrf }}
-{% if vrf_config.vni is vyos_defined %}
- vni {{ vrf_config.vni }}
-{% endif %}
- exit-vrf
-{% endfor %}
-{% endif %}
diff --git a/data/templates/frr/vrf.route-map.frr.j2 b/data/templates/frr/vrf.route-map.frr.j2
deleted file mode 100644
index 5e0c56a7b..000000000
--- a/data/templates/frr/vrf.route-map.frr.j2
+++ /dev/null
@@ -1,10 +0,0 @@
-!
-{% if vrf is vyos_defined and route_map is vyos_defined %}
-vrf {{ vrf }}
- ip protocol {{ protocol }} route-map {{ route_map }}
- exit-vrf
-!
-{% elif route_map is vyos_defined %}
-ip protocol {{ protocol }} route-map {{ route_map }}
-{% endif %}
-!
diff --git a/data/templates/frr/vrf.route-map.v6.frr.j2 b/data/templates/frr/vrf.route-map.v6.frr.j2
deleted file mode 100644
index 7dc59a046..000000000
--- a/data/templates/frr/vrf.route-map.v6.frr.j2
+++ /dev/null
@@ -1,10 +0,0 @@
-!
-{% if vrf is vyos_defined and route_map is vyos_defined %}
-vrf {{ vrf }}
- ipv6 protocol {{ protocol }} route-map {{ route_map }}
- exit-vrf
-!
-{% elif route_map is vyos_defined %}
-ipv6 protocol {{ protocol }} route-map {{ route_map }}
-{% endif %}
-!
diff --git a/data/templates/frr/zebra.route-map.frr.j2 b/data/templates/frr/zebra.route-map.frr.j2
new file mode 100644
index 000000000..8e18abbde
--- /dev/null
+++ b/data/templates/frr/zebra.route-map.frr.j2
@@ -0,0 +1,9 @@
+!
+{% if protocol is vyos_defined %}
+{% for protocol_name, protocol_config in protocol.items() %}
+{% if protocol_name is vyos_defined('ospfv3') %}
+{% set protocol_name = 'ospf6' %}
+{% endif %}
+{{ afi }} protocol {{ protocol_name }} route-map {{ protocol_config.route_map }}
+{% endfor %}
+{% endif %}
diff --git a/data/templates/frr/zebra.vrf.route-map.frr.j2 b/data/templates/frr/zebra.vrf.route-map.frr.j2
new file mode 100644
index 000000000..eb6abd8e7
--- /dev/null
+++ b/data/templates/frr/zebra.vrf.route-map.frr.j2
@@ -0,0 +1,24 @@
+!
+{% if name is vyos_defined %}
+{% for vrf, vrf_config in name.items() %}
+vrf {{ vrf }}
+{% if vrf_config.ip.protocol is vyos_defined %}
+{% for protocol_name, protocol_config in vrf_config.ip.protocol.items() %}
+ ip protocol {{ protocol_name }} route-map {{ protocol_config.route_map }}
+{% endfor %}
+{% endif %}
+{% if vrf_config.ipv6.protocol is vyos_defined %}
+{% for protocol_name, protocol_config in vrf_config.ipv6.protocol.items() %}
+{% if protocol_name is vyos_defined('ospfv3') %}
+{% set protocol_name = 'ospf6' %}
+{% endif %}
+ ipv6 protocol {{ protocol_name }} route-map {{ protocol_config.route_map }}
+{% endfor %}
+{% endif %}
+{% if vrf_config.vni is vyos_defined %}
+ vni {{ vrf_config.vni }}
+{% endif %}
+{% endfor %}
+ exit-vrf
+!
+{% endif %}
diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i
index a9122db57..527eaf991 100644
--- a/interface-definitions/include/bgp/protocol-common-config.xml.i
+++ b/interface-definitions/include/bgp/protocol-common-config.xml.i
@@ -1565,7 +1565,6 @@
#include <include/port-number.xml.i>
</children>
</tagNode>
-#include <include/route-map.xml.i>
<node name="timers">
<properties>
<help>BGP protocol timers</help>
diff --git a/interface-definitions/include/eigrp/protocol-common-config.xml.i b/interface-definitions/include/eigrp/protocol-common-config.xml.i
index 88365187a..a21d18424 100644
--- a/interface-definitions/include/eigrp/protocol-common-config.xml.i
+++ b/interface-definitions/include/eigrp/protocol-common-config.xml.i
@@ -107,7 +107,6 @@
<multi/>
</properties>
</leafNode>
-#include <include/route-map.xml.i>
#include <include/router-id.xml.i>
<!-- FRR timers not implemented yet -->
<leafNode name="variance">
diff --git a/interface-definitions/include/isis/protocol-common-config.xml.i b/interface-definitions/include/isis/protocol-common-config.xml.i
index 8103b5c5d..4ca7061db 100644
--- a/interface-definitions/include/isis/protocol-common-config.xml.i
+++ b/interface-definitions/include/isis/protocol-common-config.xml.i
@@ -687,5 +687,4 @@
</leafNode>
</children>
</tagNode>
-#include <include/route-map.xml.i>
<!-- include end -->
diff --git a/interface-definitions/include/ospf/protocol-common-config.xml.i b/interface-definitions/include/ospf/protocol-common-config.xml.i
index e400119dd..b7f22cb88 100644
--- a/interface-definitions/include/ospf/protocol-common-config.xml.i
+++ b/interface-definitions/include/ospf/protocol-common-config.xml.i
@@ -816,7 +816,6 @@
</leafNode>
</children>
</node>
-#include <include/route-map.xml.i>
<node name="timers">
<properties>
<help>Adjust routing timers</help>
diff --git a/interface-definitions/include/ospfv3/protocol-common-config.xml.i b/interface-definitions/include/ospfv3/protocol-common-config.xml.i
index 1c33ca920..a7de50638 100644
--- a/interface-definitions/include/ospfv3/protocol-common-config.xml.i
+++ b/interface-definitions/include/ospfv3/protocol-common-config.xml.i
@@ -256,5 +256,4 @@
</node>
</children>
</node>
-#include <include/route-map.xml.i>
<!-- include end -->
diff --git a/interface-definitions/include/system-ip-protocol.xml.i b/interface-definitions/include/system-ip-protocol.xml.i
new file mode 100644
index 000000000..c630eb3f7
--- /dev/null
+++ b/interface-definitions/include/system-ip-protocol.xml.i
@@ -0,0 +1,56 @@
+<!-- include start from system-ip-protocol.xml.i -->
+<tagNode name="protocol">
+ <properties>
+ <help>Filter routing info exchanged between routing protocol and zebra</help>
+ <completionHelp>
+ <list>any babel bgp connected eigrp isis kernel ospf rip static table</list>
+ </completionHelp>
+ <valueHelp>
+ <format>any</format>
+ <description>Any of the above protocols</description>
+ </valueHelp>
+ <valueHelp>
+ <format>babel</format>
+ <description>Babel routing protocol</description>
+ </valueHelp>
+ <valueHelp>
+ <format>bgp</format>
+ <description>Border Gateway Protocol</description>
+ </valueHelp>
+ <valueHelp>
+ <format>connected</format>
+ <description>Connected routes (directly attached subnet or host)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>eigrp</format>
+ <description>Enhanced Interior Gateway Routing Protocol</description>
+ </valueHelp>
+ <valueHelp>
+ <format>isis</format>
+ <description>Intermediate System to Intermediate System</description>
+ </valueHelp>
+ <valueHelp>
+ <format>kernel</format>
+ <description>Kernel routes (not installed via the zebra RIB)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ospf</format>
+ <description>Open Shortest Path First (OSPFv2)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>rip</format>
+ <description>Routing Information Protocol</description>
+ </valueHelp>
+ <valueHelp>
+ <format>static</format>
+ <description>Statically configured routes</description>
+ </valueHelp>
+ <constraint>
+ <regex>(any|babel|bgp|connected|eigrp|isis|kernel|ospf|rip|static|table)</regex>
+ </constraint>
+ </properties>
+ <children>
+ #include <include/route-map.xml.i>
+ </children>
+</tagNode>
+<!-- include end --> \ No newline at end of file
diff --git a/interface-definitions/include/system-ipv6-protocol.xml.i b/interface-definitions/include/system-ipv6-protocol.xml.i
new file mode 100644
index 000000000..485776a71
--- /dev/null
+++ b/interface-definitions/include/system-ipv6-protocol.xml.i
@@ -0,0 +1,52 @@
+<!-- include start from system-ipv6-protocol.xml.i -->
+<tagNode name="protocol">
+ <properties>
+ <help>Filter routing info exchanged between routing protocol and zebra</help>
+ <completionHelp>
+ <list>any babel bgp connected isis kernel ospfv3 ripng static table</list>
+ </completionHelp>
+ <valueHelp>
+ <format>any</format>
+ <description>Any of the above protocols</description>
+ </valueHelp>
+ <valueHelp>
+ <format>babel</format>
+ <description>Babel routing protocol</description>
+ </valueHelp>
+ <valueHelp>
+ <format>bgp</format>
+ <description>Border Gateway Protocol</description>
+ </valueHelp>
+ <valueHelp>
+ <format>connected</format>
+ <description>Connected routes (directly attached subnet or host)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>isis</format>
+ <description>Intermediate System to Intermediate System</description>
+ </valueHelp>
+ <valueHelp>
+ <format>kernel</format>
+ <description>Kernel routes (not installed via the zebra RIB)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ospfv3</format>
+ <description>Open Shortest Path First (OSPFv3)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ripng</format>
+ <description>Routing Information Protocol next-generation</description>
+ </valueHelp>
+ <valueHelp>
+ <format>static</format>
+ <description>Statically configured routes</description>
+ </valueHelp>
+ <constraint>
+ <regex>(any|babel|bgp|connected|isis|kernel|ospfv3|ripng|static|table)</regex>
+ </constraint>
+ </properties>
+ <children>
+ #include <include/route-map.xml.i>
+ </children>
+</tagNode>
+<!-- include end -->
diff --git a/interface-definitions/include/version/bgp-version.xml.i b/interface-definitions/include/version/bgp-version.xml.i
index ced49e729..1386ea9bc 100644
--- a/interface-definitions/include/version/bgp-version.xml.i
+++ b/interface-definitions/include/version/bgp-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/bgp-version.xml.i -->
-<syntaxVersion component='bgp' version='3'></syntaxVersion>
+<syntaxVersion component='bgp' version='4'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/include/version/isis-version.xml.i b/interface-definitions/include/version/isis-version.xml.i
index 7bf12e81a..f50329b09 100644
--- a/interface-definitions/include/version/isis-version.xml.i
+++ b/interface-definitions/include/version/isis-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/isis-version.xml.i -->
-<syntaxVersion component='isis' version='2'></syntaxVersion>
+<syntaxVersion component='isis' version='3'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/include/version/ospf-version.xml.i b/interface-definitions/include/version/ospf-version.xml.i
index 755965daa..df108837b 100644
--- a/interface-definitions/include/version/ospf-version.xml.i
+++ b/interface-definitions/include/version/ospf-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/ospf-version.xml.i -->
-<syntaxVersion component='ospf' version='1'></syntaxVersion>
+<syntaxVersion component='ospf' version='2'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/include/version/quagga-version.xml.i b/interface-definitions/include/version/quagga-version.xml.i
index f9944acce..23d884cd4 100644
--- a/interface-definitions/include/version/quagga-version.xml.i
+++ b/interface-definitions/include/version/quagga-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/quagga-version.xml.i -->
-<syntaxVersion component='quagga' version='10'></syntaxVersion>
+<syntaxVersion component='quagga' version='11'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/include/version/rip-version.xml.i b/interface-definitions/include/version/rip-version.xml.i
new file mode 100644
index 000000000..30ace486a
--- /dev/null
+++ b/interface-definitions/include/version/rip-version.xml.i
@@ -0,0 +1,3 @@
+<!-- include start from include/version/rip-version.xml.i -->
+<syntaxVersion component='rip' version='1'></syntaxVersion>
+<!-- include end -->
diff --git a/interface-definitions/system-ip.xml.in b/interface-definitions/system-ip.xml.in
index e00dbf252..abdede979 100644
--- a/interface-definitions/system-ip.xml.in
+++ b/interface-definitions/system-ip.xml.in
@@ -48,6 +48,7 @@
</leafNode>
</children>
</node>
+ #include <include/system-ip-protocol.xml.i>
</children>
</node>
</children>
diff --git a/interface-definitions/system-ipv6.xml.in b/interface-definitions/system-ipv6.xml.in
index 63260d00c..e17e1c01c 100644
--- a/interface-definitions/system-ipv6.xml.in
+++ b/interface-definitions/system-ipv6.xml.in
@@ -36,6 +36,7 @@
#include <include/arp-ndp-table-size.xml.i>
</children>
</node>
+ #include <include/system-ipv6-protocol.xml.i>
<leafNode name="strict-dad">
<properties>
<help>Disable IPv6 operation on interface when DAD fails on LL addr</help>
diff --git a/interface-definitions/vrf.xml.in b/interface-definitions/vrf.xml.in
index 96c6d8be2..a7efe146a 100644
--- a/interface-definitions/vrf.xml.in
+++ b/interface-definitions/vrf.xml.in
@@ -34,6 +34,7 @@
</properties>
<children>
#include <include/interface/disable-forwarding.xml.i>
+ #include <include/system-ip-protocol.xml.i>
</children>
</node>
<node name="ipv6">
@@ -42,6 +43,7 @@
</properties>
<children>
#include <include/interface/disable-forwarding.xml.i>
+ #include <include/system-ipv6-protocol.xml.i>
</children>
</node>
<node name="protocols">
@@ -119,20 +121,7 @@
<constraintErrorMessage>VRF routing table must be in range from 100 to 65535</constraintErrorMessage>
</properties>
</leafNode>
- <leafNode name="vni" owner="${vyos_conf_scripts_dir}/vrf_vni.py">
- <properties>
- <help>Virtual Network Identifier</help>
- <!-- priority must be after BGP -->
- <priority>822</priority>
- <valueHelp>
- <format>u32: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/xml-component-version.xml.in b/interface-definitions/xml-component-version.xml.in
index 2e6506efc..e05f64643 100644
--- a/interface-definitions/xml-component-version.xml.in
+++ b/interface-definitions/xml-component-version.xml.in
@@ -33,6 +33,7 @@
#include <include/version/pptp-version.xml.i>
#include <include/version/qos-version.xml.i>
#include <include/version/quagga-version.xml.i>
+ #include <include/version/rip-version.xml.i>
#include <include/version/rpki-version.xml.i>
#include <include/version/salt-version.xml.i>
#include <include/version/snmp-version.xml.i>
diff --git a/smoketest/configs/egb-igp-route-maps b/smoketest/configs/egb-igp-route-maps
new file mode 100644
index 000000000..ca36691d4
--- /dev/null
+++ b/smoketest/configs/egb-igp-route-maps
@@ -0,0 +1,127 @@
+interfaces {
+ ethernet eth0 {
+ address 192.0.2.1/25
+ duplex auto
+ smp-affinity auto
+ speed auto
+ }
+ ethernet eth1 {
+ address 192.0.2.129/25
+ address 2001:db8::1234/64
+ duplex auto
+ smp-affinity auto
+ speed auto
+ }
+ loopback lo {
+ }
+}
+policy {
+ route-map zebra-bgp {
+ rule 10 {
+ action permit
+ }
+ }
+ route-map zebra-isis {
+ rule 10 {
+ action permit
+ }
+ }
+ route-map zebra-ospf {
+ rule 10 {
+ action permit
+ }
+ }
+ route-map zebra-ospfv3 {
+ rule 10 {
+ action permit
+ }
+ }
+ route-map zebra-ripng {
+ rule 10 {
+ action permit
+ }
+ }
+ route-map zebra-static {
+ rule 10 {
+ action permit
+ }
+ }
+}
+protocols {
+ bgp 100 {
+ route-map zebra-bgp
+ }
+ isis {
+ interface eth0 {
+ }
+ net 49.0001.1921.6800.1002.00
+ route-map zebra-isis
+ }
+ ospf {
+ area 0 {
+ network 192.0.2.0/25
+ network 192.0.2.128/25
+ }
+ log-adjacency-changes {
+ }
+ parameters {
+ abr-type cisco
+ router-id 1.1.1.1
+ }
+ passive-interface default
+ passive-interface-exclude eth0
+ passive-interface-exclude eth1
+ route-map zebra-ospf
+ }
+ ospfv3 {
+ area 0 {
+ interface eth1
+ }
+ parameters {
+ router-id 1.1.1.1
+ }
+ route-map zebra-ospfv3
+ }
+ ripng {
+ interface eth1
+ route-map zebra-ripng
+ }
+ static {
+ route-map zebra-static
+ }
+}
+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 ""
+ }
+ }
+ }
+ name-server 192.168.0.1
+ syslog {
+ global {
+ archive {
+ file 5
+ size 512
+ }
+ facility all {
+ level info
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+// Warning: Do not remove the following line.
+// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@3:conntrack-sync@2:dhcp-relay@2:dhcp-server@6:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@22:ipoe-server@1:ipsec@5:isis@1:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@8:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@21:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1"
+// Release version: 1.3.2
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index f6eede87a..2fd5d0c9b 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -713,7 +713,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
for prefix in listen_ranges:
self.assertIn(f' bgp listen range {prefix} peer-group {peer_group}', frrconfig)
-
def test_bgp_07_l2vpn_evpn(self):
vnis = ['10010', '10020', '10030']
neighbors = ['192.0.2.10', '192.0.2.20', '192.0.2.30']
@@ -743,26 +742,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' advertise-default-gw', vniconfig)
self.assertIn(f' advertise-svi-ip', vniconfig)
- def test_bgp_08_zebra_route_map(self):
- # Implemented because of T3328
- self.cli_set(base_path + ['route-map', route_map_in])
- # commit changes
- self.cli_commit()
-
- # Verify FRR configuration
- zebra_route_map = f'ip protocol bgp route-map {route_map_in}'
- frrconfig = self.getFRRconfig(zebra_route_map)
- self.assertIn(zebra_route_map, frrconfig)
-
- # Remove the route-map again
- self.cli_delete(base_path + ['route-map'])
- # commit changes
- self.cli_commit()
-
- # Verify FRR configuration
- frrconfig = self.getFRRconfig(zebra_route_map)
- self.assertNotIn(zebra_route_map, frrconfig)
-
def test_bgp_09_distance_and_flowspec(self):
distance_external = '25'
distance_internal = '30'
@@ -830,7 +809,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_set(vrf_base + ['table', table])
self.cli_set(vrf_base + ['protocols', 'bgp', 'system-as', ASN])
self.cli_set(vrf_base + ['protocols', 'bgp', 'parameters', 'router-id', router_id])
- self.cli_set(vrf_base + ['protocols', 'bgp', 'route-map', route_map_in])
table = str(int(table) + 1000)
# import VRF routes do main RIB
@@ -843,7 +821,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' address-family ipv6 unicast', frrconfig)
-
for vrf in vrfs:
self.assertIn(f' import vrf {vrf}', frrconfig)
@@ -852,15 +829,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'router bgp {ASN} vrf {vrf}', frr_vrf_config)
self.assertIn(f' bgp router-id {router_id}', frr_vrf_config)
- # XXX: Currently this is not working as FRR() class does not support
- # route-maps for multiple vrfs because the modify_section() only works
- # on lines and not text blocks.
- #
- # vrfconfig = self.getFRRconfig(f'vrf {vrf}')
- # zebra_route_map = f' ip protocol bgp route-map {route_map_in}'
- # self.assertIn(zebra_route_map, vrfconfig)
-
-
def test_bgp_11_confederation(self):
router_id = '127.10.10.2'
confed_id = str(int(ASN) + 1)
diff --git a/smoketest/scripts/cli/test_system_ip.py b/smoketest/scripts/cli/test_system_ip.py
index f71ef5b3f..e7f7e3345 100755
--- a/smoketest/scripts/cli/test_system_ip.py
+++ b/smoketest/scripts/cli/test_system_ip.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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,6 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.configsession import ConfigSessionError
from vyos.util import read_file
base_path = ['system', 'ip']
@@ -82,5 +83,31 @@ class TestSystemIP(VyOSUnitTestSHIM.TestCase):
self.assertEqual(read_file(gc_thresh2), str(size // 2))
self.assertEqual(read_file(gc_thresh1), str(size // 8))
+ def test_system_ip_protocol_route_map(self):
+ protocols = ['any', 'babel', 'bgp', 'connected', 'eigrp', 'isis',
+ 'kernel', 'ospf', 'rip', 'static', 'table']
+
+ for protocol in protocols:
+ self.cli_set(['policy', 'route-map', f'route-map-{protocol}', 'rule', '10', 'action', 'permit'])
+ self.cli_set(base_path + ['protocol', protocol, 'route-map', f'route-map-{protocol}'])
+
+ self.cli_commit()
+
+ # Verify route-map properly applied to FRR
+ frrconfig = self.getFRRconfig('ip protocol', end='', daemon='zebra')
+ for protocol in protocols:
+ self.assertIn(f'ip protocol {protocol} route-map route-map-{protocol}', frrconfig)
+
+ def test_system_ip_protocol_non_existing_route_map(self):
+ non_existing = 'non-existing'
+ self.cli_set(base_path + ['protocol', 'static', 'route-map', non_existing])
+
+ # VRF does yet not exist - an error must be thrown
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(['policy', 'route-map', non_existing, 'rule', '10', 'action', 'deny'])
+ # Commit again
+ self.cli_commit()
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_ipv6.py b/smoketest/scripts/cli/test_system_ipv6.py
index c8aea9100..e91b924fc 100755
--- a/smoketest/scripts/cli/test_system_ipv6.py
+++ b/smoketest/scripts/cli/test_system_ipv6.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2022 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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,6 +18,7 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.configsession import ConfigSessionError
from vyos.template import is_ipv4
from vyos.util import read_file
from vyos.util import get_interface_config
@@ -88,5 +89,36 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase):
self.assertEqual(read_file(gc_thresh2), str(size // 2))
self.assertEqual(read_file(gc_thresh1), str(size // 8))
+ def test_system_ipv6_protocol_route_map(self):
+ protocols = ['any', 'babel', 'bgp', 'connected', 'isis',
+ 'kernel', 'ospfv3', 'ripng', 'static', 'table']
+
+ for protocol in protocols:
+ route_map = 'route-map-' + protocol.replace('ospfv3', 'ospf6')
+
+ self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
+ self.cli_set(base_path + ['protocol', protocol, 'route-map', route_map])
+
+ self.cli_commit()
+
+ # Verify route-map properly applied to FRR
+ frrconfig = self.getFRRconfig('ipv6 protocol', end='', daemon='zebra')
+ for protocol in protocols:
+ # VyOS and FRR use a different name for OSPFv3 (IPv6)
+ if protocol == 'ospfv3':
+ protocol = 'ospf6'
+ self.assertIn(f'ipv6 protocol {protocol} route-map route-map-{protocol}', frrconfig)
+
+ def test_system_ipv6_protocol_non_existing_route_map(self):
+ non_existing = 'non-existing6'
+ self.cli_set(base_path + ['protocol', 'static', 'route-map', non_existing])
+
+ # VRF does yet not exist - an error must be thrown
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(['policy', 'route-map', non_existing, 'rule', '10', 'action', 'deny'])
+ # Commit again
+ self.cli_commit()
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py
index 176c095fb..8016c0105 100755
--- a/smoketest/scripts/cli/test_vrf.py
+++ b/smoketest/scripts/cli/test_vrf.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2022 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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
@@ -33,6 +33,8 @@ from vyos.validate import is_intf_addr_assigned
base_path = ['vrf']
vrfs = ['red', 'green', 'blue', 'foo-bar', 'baz_foo']
+v4_protocols = ['any', 'babel', 'bgp', 'connected', 'eigrp', 'isis', 'kernel', 'ospf', 'rip', 'static', 'table']
+v6_protocols = ['any', 'babel', 'bgp', 'connected', 'isis', 'kernel', 'ospfv3', 'ripng', 'static', 'table']
class VRFTest(VyOSUnitTestSHIM.TestCase):
_interfaces = []
@@ -291,5 +293,81 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
self.assertEqual(read_file(f'/proc/sys/net/ipv4/conf/{vrf}/forwarding'), '0')
self.assertEqual(read_file(f'/proc/sys/net/ipv6/conf/{vrf}/forwarding'), '0')
+ def test_vrf_ip_protocol_route_map(self):
+ table = '6000'
+
+ for vrf in vrfs:
+ base = base_path + ['name', vrf]
+ self.cli_set(base + ['table', table])
+
+ for protocol in v4_protocols:
+ self.cli_set(['policy', 'route-map', f'route-map-{vrf}-{protocol}', 'rule', '10', 'action', 'permit'])
+ self.cli_set(base + ['ip', 'protocol', protocol, 'route-map', f'route-map-{vrf}-{protocol}'])
+
+ table = str(int(table) + 1)
+
+ self.cli_commit()
+
+ # Verify route-map properly applied to FRR
+ for vrf in vrfs:
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon='zebra')
+ self.assertIn(f'vrf {vrf}', frrconfig)
+ for protocol in v4_protocols:
+ self.assertIn(f' ip protocol {protocol} route-map route-map-{vrf}-{protocol}', frrconfig)
+
+ def test_vrf_ip_ipv6_protocol_non_existing_route_map(self):
+ table = '6100'
+ non_existing = 'non-existing'
+
+ for vrf in vrfs:
+ base = base_path + ['name', vrf]
+ self.cli_set(base + ['table', table])
+ for protocol in v4_protocols:
+ self.cli_set(base + ['ip', 'protocol', protocol, 'route-map', f'v4-{non_existing}'])
+ for protocol in v6_protocols:
+ self.cli_set(base + ['ipv6', 'protocol', protocol, 'route-map', f'v6-{non_existing}'])
+
+ table = str(int(table) + 1)
+
+ # Both v4 and v6 route-maps do not exist yet
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(['policy', 'route-map', f'v4-{non_existing}', 'rule', '10', 'action', 'deny'])
+
+ # v6 route-map does not exist yet
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(['policy', 'route-map', f'v6-{non_existing}', 'rule', '10', 'action', 'deny'])
+
+ # Commit again
+ self.cli_commit()
+
+ def test_vrf_ipv6_protocol_route_map(self):
+ table = '6200'
+
+ for vrf in vrfs:
+ base = base_path + ['name', vrf]
+ self.cli_set(base + ['table', table])
+
+ for protocol in v6_protocols:
+ route_map = f'route-map-{vrf}-{protocol.replace("ospfv3", "ospf6")}'
+ self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
+ self.cli_set(base + ['ipv6', 'protocol', protocol, 'route-map', route_map])
+
+ table = str(int(table) + 1)
+
+ self.cli_commit()
+
+ # Verify route-map properly applied to FRR
+ for vrf in vrfs:
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon='zebra')
+ self.assertIn(f'vrf {vrf}', frrconfig)
+ for protocol in v6_protocols:
+ # VyOS and FRR use a different name for OSPFv3 (IPv6)
+ if protocol == 'ospfv3':
+ protocol = 'ospf6'
+ route_map = f'route-map-{vrf}-{protocol}'
+ self.assertIn(f' ipv6 protocol {protocol} route-map {route_map}', frrconfig)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py
index cf553f0e8..66505e58d 100755
--- a/src/conf_mode/protocols_bgp.py
+++ b/src/conf_mode/protocols_bgp.py
@@ -484,26 +484,15 @@ def generate(bgp):
if not bgp or 'deleted' in bgp:
return None
- bgp['protocol'] = 'bgp' # required for frr/vrf.route-map.frr.j2
- bgp['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.j2', bgp)
bgp['frr_bgpd_config'] = render_to_string('frr/bgpd.frr.j2', bgp)
-
return None
def apply(bgp):
bgp_daemon = 'bgpd'
- zebra_daemon = 'zebra'
# Save original configuration prior to starting any commit actions
frr_cfg = frr.FRRConfig()
- # The route-map used for the FIB (zebra) is part of the zebra daemon
- frr_cfg.load_configuration(zebra_daemon)
- frr_cfg.modify_section(r'(\s+)?ip protocol bgp route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
- if 'frr_zebra_config' in bgp:
- frr_cfg.add_before(frr.default_add_before, bgp['frr_zebra_config'])
- frr_cfg.commit_configuration(zebra_daemon)
-
# Generate empty helper string which can be ammended to FRR commands, it
# will be either empty (default VRF) or contain the "vrf <name" statement
vrf = ''
diff --git a/src/conf_mode/protocols_eigrp.py b/src/conf_mode/protocols_eigrp.py
index 6e75e34ff..609b39065 100755
--- a/src/conf_mode/protocols_eigrp.py
+++ b/src/conf_mode/protocols_eigrp.py
@@ -78,24 +78,14 @@ def generate(eigrp):
if not eigrp or 'deleted' in eigrp:
return None
- eigrp['protocol'] = 'eigrp' # required for frr/vrf.route-map.frr.j2
- eigrp['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.j2', eigrp)
eigrp['frr_eigrpd_config'] = render_to_string('frr/eigrpd.frr.j2', eigrp)
def apply(eigrp):
eigrp_daemon = 'eigrpd'
- zebra_daemon = 'zebra'
# Save original configuration prior to starting any commit actions
frr_cfg = frr.FRRConfig()
- # The route-map used for the FIB (zebra) is part of the zebra daemon
- frr_cfg.load_configuration(zebra_daemon)
- frr_cfg.modify_section(r'(\s+)?ip protocol eigrp route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
- if 'frr_zebra_config' in eigrp:
- frr_cfg.add_before(frr.default_add_before, eigrp['frr_zebra_config'])
- frr_cfg.commit_configuration(zebra_daemon)
-
# Generate empty helper string which can be ammended to FRR commands, it
# will be either empty (default VRF) or contain the "vrf <name" statement
vrf = ''
diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py
index cb8ea3be4..af2937db8 100755
--- a/src/conf_mode/protocols_isis.py
+++ b/src/conf_mode/protocols_isis.py
@@ -203,7 +203,7 @@ def verify(isis):
if list(set(global_range) & set(local_range)):
raise ConfigError(f'Segment-Routing Global Block ({g_low_label_value}/{g_high_label_value}) '\
f'conflicts with Local Block ({l_low_label_value}/{l_high_label_value})!')
-
+
# Check for a blank or invalid value per prefix
if dict_search('segment_routing.prefix', isis):
for prefix, prefix_config in isis['segment_routing']['prefix'].items():
@@ -218,7 +218,7 @@ def verify(isis):
if dict_search('segment_routing.prefix', isis):
for prefix, prefix_config in isis['segment_routing']['prefix'].items():
if 'absolute' in prefix_config:
- if ("explicit_null" in prefix_config['absolute']) and ("no_php_flag" in prefix_config['absolute']):
+ if ("explicit_null" in prefix_config['absolute']) and ("no_php_flag" in prefix_config['absolute']):
raise ConfigError(f'Segment routing prefix {prefix} cannot have both explicit-null '\
f'and no-php-flag configured at the same time.')
elif 'index' in prefix_config:
@@ -232,25 +232,15 @@ def generate(isis):
if not isis or 'deleted' in isis:
return None
- isis['protocol'] = 'isis' # required for frr/vrf.route-map.frr.j2
- isis['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.j2', isis)
isis['frr_isisd_config'] = render_to_string('frr/isisd.frr.j2', isis)
return None
def apply(isis):
isis_daemon = 'isisd'
- zebra_daemon = 'zebra'
# Save original configuration prior to starting any commit actions
frr_cfg = frr.FRRConfig()
- # The route-map used for the FIB (zebra) is part of the zebra daemon
- frr_cfg.load_configuration(zebra_daemon)
- frr_cfg.modify_section('(\s+)?ip protocol isis route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
- if 'frr_zebra_config' in isis:
- frr_cfg.add_before(frr.default_add_before, isis['frr_zebra_config'])
- frr_cfg.commit_configuration(zebra_daemon)
-
# Generate empty helper string which can be ammended to FRR commands, it
# will be either empty (default VRF) or contain the "vrf <name" statement
vrf = ''
diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py
index eb64afa0c..fbb876123 100755
--- a/src/conf_mode/protocols_ospf.py
+++ b/src/conf_mode/protocols_ospf.py
@@ -256,25 +256,15 @@ def generate(ospf):
if not ospf or 'deleted' in ospf:
return None
- ospf['protocol'] = 'ospf' # required for frr/vrf.route-map.frr.j2
- ospf['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.j2', ospf)
ospf['frr_ospfd_config'] = render_to_string('frr/ospfd.frr.j2', ospf)
return None
def apply(ospf):
ospf_daemon = 'ospfd'
- zebra_daemon = 'zebra'
# Save original configuration prior to starting any commit actions
frr_cfg = frr.FRRConfig()
- # The route-map used for the FIB (zebra) is part of the zebra daemon
- frr_cfg.load_configuration(zebra_daemon)
- frr_cfg.modify_section('(\s+)?ip protocol ospf route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
- if 'frr_zebra_config' in ospf:
- frr_cfg.add_before(frr.default_add_before, ospf['frr_zebra_config'])
- frr_cfg.commit_configuration(zebra_daemon)
-
# Generate empty helper string which can be ammended to FRR commands, it
# will be either empty (default VRF) or contain the "vrf <name" statement
vrf = ''
@@ -292,6 +282,7 @@ def apply(ospf):
if 'frr_ospfd_config' in ospf:
frr_cfg.add_before(frr.default_add_before, ospf['frr_ospfd_config'])
+
frr_cfg.commit_configuration(ospf_daemon)
return None
diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py
index 1e2c02d03..ee1fdd399 100755
--- a/src/conf_mode/protocols_ospfv3.py
+++ b/src/conf_mode/protocols_ospfv3.py
@@ -146,25 +146,15 @@ def generate(ospfv3):
if not ospfv3 or 'deleted' in ospfv3:
return None
- ospfv3['protocol'] = 'ospf6' # required for frr/vrf.route-map.v6.frr.j2
- ospfv3['frr_zebra_config'] = render_to_string('frr/vrf.route-map.v6.frr.j2', ospfv3)
ospfv3['new_frr_config'] = render_to_string('frr/ospf6d.frr.j2', ospfv3)
return None
def apply(ospfv3):
ospf6_daemon = 'ospf6d'
- zebra_daemon = 'zebra'
# Save original configuration prior to starting any commit actions
frr_cfg = frr.FRRConfig()
- # The route-map used for the FIB (zebra) is part of the zebra daemon
- frr_cfg.load_configuration(zebra_daemon)
- frr_cfg.modify_section('(\s+)?ipv6 protocol ospf6 route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
- if 'frr_zebra_config' in ospfv3:
- frr_cfg.add_before(frr.default_add_before, ospfv3['frr_zebra_config'])
- frr_cfg.commit_configuration(zebra_daemon)
-
# Generate empty helper string which can be ammended to FRR commands, it
# will be either empty (default VRF) or contain the "vrf <name" statement
vrf = ''
diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py
index 3e5ebb805..7b6150696 100755
--- a/src/conf_mode/protocols_static.py
+++ b/src/conf_mode/protocols_static.py
@@ -105,20 +105,14 @@ def generate(static):
def apply(static):
static_daemon = 'staticd'
- zebra_daemon = 'zebra'
# Save original configuration prior to starting any commit actions
frr_cfg = frr.FRRConfig()
-
- # The route-map used for the FIB (zebra) is part of the zebra daemon
- frr_cfg.load_configuration(zebra_daemon)
- frr_cfg.modify_section(r'^ip protocol static route-map [-a-zA-Z0-9.]+', '')
- frr_cfg.commit_configuration(zebra_daemon)
frr_cfg.load_configuration(static_daemon)
if 'vrf' in static:
vrf = static['vrf']
- frr_cfg.modify_section(f'^vrf {vrf}', stop_pattern='^exit', remove_stop_mark=True)
+ frr_cfg.modify_section(f'^vrf {vrf}', stop_pattern='^exit-vrf', remove_stop_mark=True)
else:
frr_cfg.modify_section(r'^ip route .*')
frr_cfg.modify_section(r'^ipv6 route .*')
diff --git a/src/conf_mode/system-ip.py b/src/conf_mode/system-ip.py
index 0c5063ed3..95865c690 100755
--- a/src/conf_mode/system-ip.py
+++ b/src/conf_mode/system-ip.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2022 VyOS maintainers and contributors
+# Copyright (C) 2019-2023 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,12 +18,15 @@ from sys import exit
from vyos.config import Config
from vyos.configdict import dict_merge
+from vyos.configverify import verify_route_map
+from vyos.template import render_to_string
from vyos.util import call
from vyos.util import dict_search
from vyos.util import sysctl_write
from vyos.util import write_file
from vyos.xml import defaults
from vyos import ConfigError
+from vyos import frr
from vyos import airbag
airbag.enable()
@@ -40,13 +43,30 @@ def get_config(config=None):
default_values = defaults(base)
opt = dict_merge(default_values, opt)
+ # When working with FRR we need to know the corresponding address-family
+ opt['afi'] = 'ip'
+
+ # We also need the route-map information from the config
+ #
+ # XXX: one MUST always call this without the key_mangling() option! See
+ # vyos.configverify.verify_common_route_maps() for more information.
+ tmp = {'policy' : {'route-map' : conf.get_config_dict(['policy', 'route-map'],
+ get_first_key=True)}}
+ # Merge policy dict into "regular" config dict
+ opt = dict_merge(tmp, opt)
return opt
def verify(opt):
- pass
+ if 'protocol' in opt:
+ for protocol, protocol_options in opt['protocol'].items():
+ if 'route_map' in protocol_options:
+ verify_route_map(protocol_options['route_map'], opt)
+ return
def generate(opt):
- pass
+ if 'protocol' in opt:
+ opt['frr_zebra_config'] = render_to_string('frr/zebra.route-map.frr.j2', opt)
+ return
def apply(opt):
# Apply ARP threshold values
@@ -78,6 +98,18 @@ def apply(opt):
value = '1' if (tmp != None) else '0'
sysctl_write('net.ipv4.fib_multipath_hash_policy', value)
+ if 'protocol' in opt:
+ zebra_daemon = 'zebra'
+ # Save original configuration prior to starting any commit actions
+ frr_cfg = frr.FRRConfig()
+
+ # The route-map used for the FIB (zebra) is part of the zebra daemon
+ frr_cfg.load_configuration(zebra_daemon)
+ frr_cfg.modify_section(r'ip protocol \w+ route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
+ if 'frr_zebra_config' in opt:
+ frr_cfg.add_before(frr.default_add_before, opt['frr_zebra_config'])
+ frr_cfg.commit_configuration(zebra_daemon)
+
if __name__ == '__main__':
try:
c = get_config()
diff --git a/src/conf_mode/system-ipv6.py b/src/conf_mode/system-ipv6.py
index 26aacf46b..b6d3a79c3 100755
--- a/src/conf_mode/system-ipv6.py
+++ b/src/conf_mode/system-ipv6.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2022 VyOS maintainers and contributors
+# Copyright (C) 2019-2023 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,11 +19,14 @@ import os
from sys import exit
from vyos.config import Config
from vyos.configdict import dict_merge
+from vyos.configverify import verify_route_map
+from vyos.template import render_to_string
from vyos.util import dict_search
from vyos.util import sysctl_write
from vyos.util import write_file
from vyos.xml import defaults
from vyos import ConfigError
+from vyos import frr
from vyos import airbag
airbag.enable()
@@ -41,13 +44,30 @@ def get_config(config=None):
default_values = defaults(base)
opt = dict_merge(default_values, opt)
+ # When working with FRR we need to know the corresponding address-family
+ opt['afi'] = 'ipv6'
+
+ # We also need the route-map information from the config
+ #
+ # XXX: one MUST always call this without the key_mangling() option! See
+ # vyos.configverify.verify_common_route_maps() for more information.
+ tmp = {'policy' : {'route-map' : conf.get_config_dict(['policy', 'route-map'],
+ get_first_key=True)}}
+ # Merge policy dict into "regular" config dict
+ opt = dict_merge(tmp, opt)
return opt
def verify(opt):
- pass
+ if 'protocol' in opt:
+ for protocol, protocol_options in opt['protocol'].items():
+ if 'route_map' in protocol_options:
+ verify_route_map(protocol_options['route_map'], opt)
+ return
def generate(opt):
- pass
+ if 'protocol' in opt:
+ opt['frr_zebra_config'] = render_to_string('frr/zebra.route-map.frr.j2', opt)
+ return
def apply(opt):
# configure multipath
@@ -78,6 +98,18 @@ def apply(opt):
if name == 'accept_dad':
write_file(os.path.join(root, name), value)
+ if 'protocol' in opt:
+ zebra_daemon = 'zebra'
+ # Save original configuration prior to starting any commit actions
+ frr_cfg = frr.FRRConfig()
+
+ # The route-map used for the FIB (zebra) is part of the zebra daemon
+ frr_cfg.load_configuration(zebra_daemon)
+ frr_cfg.modify_section(r'ipv6 protocol \w+ route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
+ if 'frr_zebra_config' in opt:
+ frr_cfg.add_before(frr.default_add_before, opt['frr_zebra_config'])
+ frr_cfg.commit_configuration(zebra_daemon)
+
if __name__ == '__main__':
try:
c = get_config()
diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py
index c17cca3bd..a7ef4cb5c 100755
--- a/src/conf_mode/vrf.py
+++ b/src/conf_mode/vrf.py
@@ -20,9 +20,12 @@ from sys import exit
from json import loads
from vyos.config import Config
+from vyos.configdict import dict_merge
from vyos.configdict import node_changed
+from vyos.configverify import verify_route_map
from vyos.ifconfig import Interface
from vyos.template import render
+from vyos.template import render_to_string
from vyos.util import call
from vyos.util import cmd
from vyos.util import dict_search
@@ -99,6 +102,14 @@ def get_config(config=None):
routes = vrf_routing(conf, name)
if routes: vrf['vrf_remove'][name]['route'] = routes
+ # We also need the route-map information from the config
+ #
+ # XXX: one MUST always call this without the key_mangling() option! See
+ # vyos.configverify.verify_common_route_maps() for more information.
+ tmp = {'policy' : {'route-map' : conf.get_config_dict(['policy', 'route-map'],
+ get_first_key=True)}}
+ # Merge policy dict into "regular" config dict
+ vrf = dict_merge(tmp, vrf)
return vrf
def verify(vrf):
@@ -116,35 +127,50 @@ def verify(vrf):
reserved_names = ["add", "all", "broadcast", "default", "delete", "dev", "get", "inet", "mtu", "link", "type",
"vrf"]
table_ids = []
- for name, config in vrf['name'].items():
+ for name, vrf_config in vrf['name'].items():
# Reserved VRF names
if name in reserved_names:
raise ConfigError(f'VRF name "{name}" is reserved and connot be used!')
# table id is mandatory
- if 'table' not in config:
+ if 'table' not in vrf_config:
raise ConfigError(f'VRF "{name}" table id is mandatory!')
# routing table id can't be changed - OS restriction
if os.path.isdir(f'/sys/class/net/{name}'):
tmp = str(dict_search('linkinfo.info_data.table', get_interface_config(name)))
- if tmp and tmp != config['table']:
+ if tmp and tmp != vrf_config['table']:
raise ConfigError(f'VRF "{name}" table id modification not possible!')
# VRf routing table ID must be unique on the system
- if config['table'] in table_ids:
+ if vrf_config['table'] in table_ids:
raise ConfigError(f'VRF "{name}" table id is not unique!')
- table_ids.append(config['table'])
+ table_ids.append(vrf_config['table'])
+
+ tmp = dict_search('ip.protocol', vrf_config)
+ if tmp != None:
+ for protocol, protocol_options in tmp.items():
+ if 'route_map' in protocol_options:
+ verify_route_map(protocol_options['route_map'], vrf)
+
+ tmp = dict_search('ipv6.protocol', vrf_config)
+ if tmp != None:
+ for protocol, protocol_options in tmp.items():
+ if 'route_map' in protocol_options:
+ verify_route_map(protocol_options['route_map'], vrf)
return None
def generate(vrf):
+ # Render iproute2 VR helper names
render(config_file, 'iproute2/vrf.conf.j2', vrf)
# Render nftables zones config
render(nft_vrf_config, 'firewall/nftables-vrf-zones.j2', vrf)
- return None
+ # Render VRF Kernel/Zebra route-map filters
+ vrf['frr_zebra_config'] = render_to_string('frr/zebra.vrf.route-map.frr.j2', vrf)
+ return None
def apply(vrf):
# Documentation
@@ -249,6 +275,17 @@ def apply(vrf):
nft_add_element = f'add element inet vrf_zones ct_iface_map {{ "{name}" : {table} }}'
cmd(f'nft {nft_add_element}')
+ # Apply FRR filters
+ zebra_daemon = 'zebra'
+ # Save original configuration prior to starting any commit actions
+ frr_cfg = frr.FRRConfig()
+
+ # The route-map used for the FIB (zebra) is part of the zebra daemon
+ frr_cfg.load_configuration(zebra_daemon)
+ frr_cfg.modify_section(f'^vrf .+', stop_pattern='^exit-vrf', remove_stop_mark=True)
+ if 'frr_zebra_config' in vrf:
+ frr_cfg.add_before(frr.default_add_before, vrf['frr_zebra_config'])
+ frr_cfg.commit_configuration(zebra_daemon)
# return to default lookup preference when no VRF is configured
if 'name' not in vrf:
diff --git a/src/conf_mode/vrf_vni.py b/src/conf_mode/vrf_vni.py
deleted file mode 100755
index 585fdbebf..000000000
--- a/src/conf_mode/vrf_vni.py
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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
-# 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.config import Config
-from vyos.template import render_to_string
-from vyos import ConfigError
-from vyos import frr
-from vyos import airbag
-airbag.enable()
-
-frr_daemon = 'zebra'
-
-def get_config(config=None):
- if config:
- conf = config
- else:
- conf = Config()
-
- base = ['vrf']
- vrf = conf.get_config_dict(base, get_first_key=True)
- return vrf
-
-def verify(vrf):
- return None
-
-def generate(vrf):
- vrf['new_frr_config'] = render_to_string('frr/vrf-vni.frr.j2', vrf)
- return None
-
-def apply(vrf):
- # add configuration to FRR
- frr_cfg = frr.FRRConfig()
- frr_cfg.load_configuration(frr_daemon)
- frr_cfg.modify_section(f'^vrf .+', stop_pattern='^exit-vrf', remove_stop_mark=True)
- if 'new_frr_config' in vrf:
- frr_cfg.add_before(frr.default_add_before, vrf['new_frr_config'])
- 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/migration-scripts/bgp/3-to-4 b/src/migration-scripts/bgp/3-to-4
new file mode 100755
index 000000000..0df2fbec4
--- /dev/null
+++ b/src/migration-scripts/bgp/3-to-4
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 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/>.
+
+# T5150: Rework CLI definitions to apply route-maps between routing daemons
+# and zebra/kernel
+
+from sys import argv
+from sys import exit
+
+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()
+
+config = ConfigTree(config_file)
+
+bgp_base = ['protocols', 'bgp']
+# Check if BGP is configured - if so, migrate the CLI node
+if config.exists(bgp_base):
+ if config.exists(bgp_base + ['route-map']):
+ tmp = config.return_value(bgp_base + ['route-map'])
+
+ config.set(['system', 'ip', 'protocol', 'bgp', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ip', 'protocol'])
+ config.delete(bgp_base + ['route-map'])
+
+
+# Check if vrf names are configured. Check if BGP is configured - if so, migrate
+# the CLI node(s)
+if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ vrf_base = ['vrf', 'name', vrf]
+ if config.exists(vrf_base + ['protocols', 'bgp', 'route-map']):
+ tmp = config.return_value(vrf_base + ['protocols', 'bgp', 'route-map'])
+
+ config.set(vrf_base + ['ip', 'protocol', 'bgp', 'route-map'], value=tmp)
+ config.set_tag(vrf_base + ['ip', 'protocol', 'bgp'])
+ config.delete(vrf_base + ['protocols', 'bgp', 'route-map'])
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print(f'Failed to save the modified config: {e}')
+ exit(1)
diff --git a/src/migration-scripts/isis/2-to-3 b/src/migration-scripts/isis/2-to-3
new file mode 100755
index 000000000..4490feb0a
--- /dev/null
+++ b/src/migration-scripts/isis/2-to-3
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 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/>.
+
+# T5150: Rework CLI definitions to apply route-maps between routing daemons
+# and zebra/kernel
+
+from sys import argv
+from sys import exit
+
+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()
+
+config = ConfigTree(config_file)
+
+isis_base = ['protocols', 'isis']
+# Check if IS-IS is configured - if so, migrate the CLI node
+if config.exists(isis_base):
+ if config.exists(isis_base + ['route-map']):
+ tmp = config.return_value(isis_base + ['route-map'])
+
+ config.set(['system', 'ip', 'protocol', 'isis', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ip', 'protocol'])
+ config.delete(isis_base + ['route-map'])
+
+# Check if vrf names are configured. Check if IS-IS is configured - if so,
+# migrate the CLI node(s)
+if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ vrf_base = ['vrf', 'name', vrf]
+ if config.exists(vrf_base + ['protocols', 'isis', 'route-map']):
+ tmp = config.return_value(vrf_base + ['protocols', 'isis', 'route-map'])
+
+ config.set(vrf_base + ['ip', 'protocol', 'isis', 'route-map'], value=tmp)
+ config.set_tag(vrf_base + ['ip', 'protocol', 'isis'])
+ config.delete(vrf_base + ['protocols', 'isis', 'route-map'])
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print(f'Failed to save the modified config: {e}')
+ exit(1)
diff --git a/src/migration-scripts/ospf/1-to-2 b/src/migration-scripts/ospf/1-to-2
new file mode 100755
index 000000000..a6beaf04e
--- /dev/null
+++ b/src/migration-scripts/ospf/1-to-2
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 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/>.
+
+# T5150: Rework CLI definitions to apply route-maps between routing daemons
+# and zebra/kernel
+
+from sys import argv
+from sys import exit
+
+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()
+
+config = ConfigTree(config_file)
+
+ospf_base = ['protocols', 'ospf']
+# Check if OSPF is configured - if so, migrate the CLI node
+if config.exists(ospf_base):
+ if config.exists(ospf_base + ['route-map']):
+ tmp = config.return_value(ospf_base + ['route-map'])
+
+ config.set(['system', 'ip', 'protocol', 'ospf', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ip', 'protocol'])
+ config.delete(ospf_base + ['route-map'])
+
+ospfv3_base = ['protocols', 'ospfv3']
+# Check if OSPFv3 is configured - if so, migrate the CLI node
+if config.exists(ospfv3_base):
+ if config.exists(ospfv3_base + ['route-map']):
+ tmp = config.return_value(ospfv3_base + ['route-map'])
+
+ config.set(['system', 'ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ipv6', 'protocol'])
+ config.delete(ospfv3_base + ['route-map'])
+
+# Check if vrf names are configured. Check if OSPF/OSPFv3 is configured - if so,
+# migrate the CLI node(s)
+if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ vrf_base = ['vrf', 'name', vrf]
+ if config.exists(vrf_base + ['protocols', 'ospf', 'route-map']):
+ tmp = config.return_value(vrf_base + ['protocols', 'ospf', 'route-map'])
+
+ config.set(vrf_base + ['ip', 'protocol', 'ospf', 'route-map'], value=tmp)
+ config.set_tag(vrf_base + ['ip', 'protocol', 'ospf'])
+ config.delete(vrf_base + ['protocols', 'ospf', 'route-map'])
+
+ if config.exists(vrf_base + ['protocols', 'ospfv3', 'route-map']):
+ tmp = config.return_value(vrf_base + ['protocols', 'ospfv3', 'route-map'])
+
+ config.set(vrf_base + ['ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp)
+ config.set_tag(vrf_base + ['ipv6', 'protocol', 'ospfv6'])
+ config.delete(vrf_base + ['protocols', 'ospfv3', 'route-map'])
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print(f'Failed to save the modified config: {e}')
+ exit(1)
diff --git a/src/migration-scripts/quagga/10-to-11 b/src/migration-scripts/quagga/10-to-11
new file mode 100755
index 000000000..04fc16f79
--- /dev/null
+++ b/src/migration-scripts/quagga/10-to-11
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 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/>.
+
+# T5150: Rework CLI definitions to apply route-maps between routing daemons
+# and zebra/kernel
+
+from sys import argv
+from sys import exit
+
+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()
+
+config = ConfigTree(config_file)
+
+static_base = ['protocols', 'static']
+# Check if static routes are configured - if so, migrate the CLI node
+if config.exists(static_base):
+ if config.exists(static_base + ['route-map']):
+ tmp = config.return_value(static_base + ['route-map'])
+
+ config.set(['system', 'ip', 'protocol', 'static', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ip', 'protocol'])
+ config.delete(static_base + ['route-map'])
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print(f'Failed to save the modified config: {e}')
+ exit(1)
diff --git a/src/migration-scripts/rip/0-to-1 b/src/migration-scripts/rip/0-to-1
new file mode 100755
index 000000000..60d510001
--- /dev/null
+++ b/src/migration-scripts/rip/0-to-1
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 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/>.
+
+# T5150: Rework CLI definitions to apply route-maps between routing daemons
+# and zebra/kernel
+
+from sys import argv
+from sys import exit
+
+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()
+
+config = ConfigTree(config_file)
+
+ripng_base = ['protocols', 'ripng']
+# Check if RIPng is configured - if so, migrate the CLI node
+if config.exists(ripng_base):
+ if config.exists(ripng_base + ['route-map']):
+ tmp = config.return_value(ripng_base + ['route-map'])
+
+ config.set(['system', 'ipv6', 'protocol', 'ripng', 'route-map'], value=tmp)
+ config.set_tag(['system', 'ipv6', 'protocol'])
+ config.delete(ripng_base + ['route-map'])
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print(f'Failed to save the modified config: {e}')
+ exit(1)