summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--data/templates/accel-ppp/pptp.config.j27
-rw-r--r--data/templates/frr/isisd.frr.j211
-rw-r--r--data/templates/frr/ospfd.frr.j211
-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--data/templates/telegraf/telegraf.j22
-rw-r--r--debian/control5
-rw-r--r--interface-definitions/dns-forwarding.xml.in35
-rw-r--r--interface-definitions/include/bgp/protocol-common-config.xml.i7
-rw-r--r--interface-definitions/include/eigrp/protocol-common-config.xml.i1
-rw-r--r--interface-definitions/include/isis/ldp-sync-holddown.xml.i14
-rw-r--r--interface-definitions/include/isis/ldp-sync-interface.xml.i11
-rw-r--r--interface-definitions/include/isis/ldp-sync-protocol.xml.i10
-rw-r--r--interface-definitions/include/isis/protocol-common-config.xml.i5
-rw-r--r--interface-definitions/include/ospf/protocol-common-config.xml.i5
-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/protocols-bgp.xml.in14
-rw-r--r--interface-definitions/protocols-failover.xml.in1
-rw-r--r--interface-definitions/system-ip.xml.in1
-rw-r--r--interface-definitions/system-ipv6.xml.in1
-rw-r--r--interface-definitions/vpn-pptp.xml.in6
-rw-r--r--interface-definitions/vrf.xml.in6
-rw-r--r--interface-definitions/xml-component-version.xml.in1
-rw-r--r--op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i6
-rw-r--r--op-mode-definitions/include/bgp/evpn-type-1.xml.i8
-rw-r--r--op-mode-definitions/include/bgp/evpn-type-2.xml.i8
-rw-r--r--op-mode-definitions/include/bgp/evpn-type-3.xml.i8
-rw-r--r--op-mode-definitions/include/bgp/evpn-type-4.xml.i8
-rw-r--r--op-mode-definitions/include/bgp/evpn-type-5.xml.i8
-rw-r--r--op-mode-definitions/include/bgp/evpn-type-ead.xml.i8
-rw-r--r--op-mode-definitions/include/bgp/evpn-type-es.xml.i8
-rw-r--r--op-mode-definitions/include/bgp/evpn-type-macip.xml.i8
-rw-r--r--op-mode-definitions/include/bgp/evpn-type-multicast.xml.i8
-rw-r--r--op-mode-definitions/include/bgp/evpn-type-prefix.xml.i8
-rw-r--r--op-mode-definitions/include/bgp/show-bgp-common.xml.i70
-rw-r--r--op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i6
-rw-r--r--op-mode-definitions/include/isis-common.xml.i49
-rw-r--r--op-mode-definitions/include/ldp-sync.xml.i11
-rw-r--r--op-mode-definitions/include/ospf-common.xml.i27
-rw-r--r--op-mode-definitions/include/vtysh-generic-interface-tagNode.xml.i11
-rw-r--r--op-mode-definitions/show-bgp.xml.in27
-rw-r--r--op-mode-definitions/show-techsupport_report.xml.in17
-rw-r--r--python/vyos/ifconfig/interface.py8
-rw-r--r--smoketest/configs/egb-igp-route-maps127
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_openvpn.py5
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bgp.py32
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_isis.py78
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ospf.py61
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_static.py25
-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/container.py6
-rwxr-xr-xsrc/conf_mode/firewall.py3
-rwxr-xr-xsrc/conf_mode/interfaces-openvpn.py4
-rwxr-xr-xsrc/conf_mode/protocols_bgp.py11
-rwxr-xr-xsrc/conf_mode/protocols_eigrp.py12
-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/service_monitoring_telegraf.py11
-rwxr-xr-xsrc/conf_mode/system-ip.py38
-rwxr-xr-xsrc/conf_mode/system-ipv6.py38
-rwxr-xr-xsrc/conf_mode/vpn_pptp.py23
-rwxr-xr-xsrc/conf_mode/vrf.py49
-rw-r--r--[-rwxr-xr-x]src/conf_mode/vrf_vni.py21
-rw-r--r--src/etc/systemd/system/hostapd@.service.d/override.conf2
-rwxr-xr-xsrc/helpers/vyos-failover.py69
-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
-rwxr-xr-xsrc/op_mode/dhcp.py6
-rwxr-xr-xsrc/op_mode/dynamic_dns.py72
-rwxr-xr-xsrc/op_mode/openvpn.py23
-rwxr-xr-xsrc/op_mode/pki.py3
-rw-r--r--src/op_mode/show_techsupport_report.py303
90 files changed, 1720 insertions, 446 deletions
diff --git a/Makefile b/Makefile
index 4f49f0d27..e130bec70 100644
--- a/Makefile
+++ b/Makefile
@@ -67,6 +67,7 @@ op_mode_definitions: $(op_xml_obj)
rm -f $(OP_TMPL_DIR)/set/node.def
rm -f $(OP_TMPL_DIR)/show/node.def
rm -f $(OP_TMPL_DIR)/show/system/node.def
+ rm -f $(OP_TMPL_DIR)/show/tech-support/node.def
# XXX: ping and traceroute must be able to recursivly call itself as the
# options are provided from the script itself
diff --git a/data/templates/accel-ppp/pptp.config.j2 b/data/templates/accel-ppp/pptp.config.j2
index 442830b6b..78a629d2d 100644
--- a/data/templates/accel-ppp/pptp.config.j2
+++ b/data/templates/accel-ppp/pptp.config.j2
@@ -93,10 +93,15 @@ bind={{ radius_source_address }}
gw-ip-address={{ gw_ip }}
{% endif %}
-{% if radius_shaper_attr %}
+{% if radius_shaper_enable %}
[shaper]
verbose=1
+{% if radius_shaper_attr %}
attr={{ radius_shaper_attr }}
+{% endif %}
+{% if radius_shaper_multiplier %}
+rate-multiplier={{ radius_shaper_multiplier }}
+{% endif %}
{% if radius_shaper_vendor %}
vendor={{ radius_shaper_vendor }}
{% endif %}
diff --git a/data/templates/frr/isisd.frr.j2 b/data/templates/frr/isisd.frr.j2
index 8df1e9513..3c37e28b9 100644
--- a/data/templates/frr/isisd.frr.j2
+++ b/data/templates/frr/isisd.frr.j2
@@ -25,6 +25,12 @@ interface {{ iface }}
{% if iface_config.hello_padding is vyos_defined %}
isis hello padding
{% endif %}
+{% if iface_config.ldp_sync.disable is vyos_defined %}
+ no isis mpls ldp-sync
+{% elif iface_config.ldp_sync.holddown is vyos_defined %}
+ isis mpls ldp-sync
+ isis mpls ldp-sync holddown {{ iface_config.ldp_sync.holddown }}
+{% endif %}
{% if iface_config.metric is vyos_defined %}
isis metric {{ iface_config.metric }}
{% endif %}
@@ -84,6 +90,11 @@ router isis VyOS {{ 'vrf ' + vrf if vrf is vyos_defined }}
{% if max_lsp_lifetime is vyos_defined %}
max-lsp-lifetime {{ max_lsp_lifetime }}
{% endif %}
+{% if ldp_sync.holddown is vyos_defined %}
+ mpls ldp-sync holddown {{ ldp_sync.holddown }}
+{% elif ldp_sync is vyos_defined %}
+ mpls ldp-sync
+{% endif %}
{% if spf_interval is vyos_defined %}
spf-interval {{ spf_interval }}
{% endif %}
diff --git a/data/templates/frr/ospfd.frr.j2 b/data/templates/frr/ospfd.frr.j2
index 8c4a81c57..3f97b7325 100644
--- a/data/templates/frr/ospfd.frr.j2
+++ b/data/templates/frr/ospfd.frr.j2
@@ -44,6 +44,12 @@ interface {{ iface }}
{% if iface_config.bfd.profile is vyos_defined %}
ip ospf bfd profile {{ iface_config.bfd.profile }}
{% endif %}
+{% if iface_config.ldp_sync.disable is vyos_defined %}
+ no ip ospf mpls ldp-sync
+{% elif iface_config.ldp_sync.holddown is vyos_defined %}
+ ip ospf mpls ldp-sync
+ ip ospf mpls ldp-sync holddown {{ iface_config.ldp_sync.holddown }}
+{% endif %}
{% if iface_config.mtu_ignore is vyos_defined %}
ip ospf mtu-ignore
{% endif %}
@@ -133,6 +139,11 @@ router ospf {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
{% if maximum_paths is vyos_defined %}
maximum-paths {{ maximum_paths }}
{% endif %}
+{% if ldp_sync.holddown is vyos_defined %}
+ mpls ldp-sync holddown {{ ldp_sync.holddown }}
+{% elif ldp_sync is vyos_defined %}
+ mpls ldp-sync
+{% endif %}
{% if distance.global is vyos_defined %}
distance {{ distance.global }}
{% endif %}
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..3c5791c4c
--- /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 %}
+exit-vrf
+{% endfor %}
+!
+{% endif %}
diff --git a/data/templates/telegraf/telegraf.j2 b/data/templates/telegraf/telegraf.j2
index c9f402281..5852d6232 100644
--- a/data/templates/telegraf/telegraf.j2
+++ b/data/templates/telegraf/telegraf.j2
@@ -12,7 +12,7 @@
debug = false
quiet = false
logfile = ""
- hostname = ""
+ hostname = "{{ hostname }}"
omit_hostname = false
{% if azure_data_explorer is vyos_defined %}
### Azure Data Explorer ###
diff --git a/debian/control b/debian/control
index 856f57030..4a2706fc3 100644
--- a/debian/control
+++ b/debian/control
@@ -16,7 +16,7 @@ Build-Depends:
build-essential,
libvyosconfig0 (>= 0.0.7),
libzmq3-dev,
- python3,
+ python3 (>= 3.10),
python3-coverage,
python3-lxml,
python3-netifaces,
@@ -33,7 +33,8 @@ Standards-Version: 3.9.6
Package: vyos-1x
Architecture: amd64 arm64
Depends:
- ${python3:Depends},
+ ${python3:Depends} (>= 3.10),
+ aardvark-dns,
accel-ppp,
auditd,
avahi-daemon,
diff --git a/interface-definitions/dns-forwarding.xml.in b/interface-definitions/dns-forwarding.xml.in
index 14b38b24d..6b7344b1d 100644
--- a/interface-definitions/dns-forwarding.xml.in
+++ b/interface-definitions/dns-forwarding.xml.in
@@ -83,6 +83,13 @@
<tagNode name="domain">
<properties>
<help>Domain to forward to a custom DNS server</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>An absolute DNS domain name</description>
+ </valueHelp>
+ <constraint>
+ <validator name="fqdn"/>
+ </constraint>
</properties>
<children>
#include <include/name-server-ipv4-ipv6-port.xml.i>
@@ -104,11 +111,11 @@
<properties>
<help>Domain to host authoritative records for</help>
<valueHelp>
- <format>text</format>
- <description>An absolute DNS name</description>
+ <format>txt</format>
+ <description>An absolute DNS domain name</description>
</valueHelp>
<constraint>
- <regex>[-_a-zA-Z0-9.]{1,63}</regex>
+ <validator name="fqdn"/>
</constraint>
</properties>
<children>
@@ -121,7 +128,7 @@
<properties>
<help>"A" record</help>
<valueHelp>
- <format>text</format>
+ <format>txt</format>
<description>A DNS name relative to the root record</description>
</valueHelp>
<valueHelp>
@@ -158,7 +165,7 @@
<properties>
<help>"AAAA" record</help>
<valueHelp>
- <format>text</format>
+ <format>txt</format>
<description>A DNS name relative to the root record</description>
</valueHelp>
<valueHelp>
@@ -195,7 +202,7 @@
<properties>
<help>"CNAME" record</help>
<valueHelp>
- <format>text</format>
+ <format>txt</format>
<description>A DNS name relative to the root record</description>
</valueHelp>
<valueHelp>
@@ -227,7 +234,7 @@
<properties>
<help>"MX" record</help>
<valueHelp>
- <format>text</format>
+ <format>txt</format>
<description>A DNS name relative to the root record</description>
</valueHelp>
<valueHelp>
@@ -274,7 +281,7 @@
<properties>
<help>"PTR" record</help>
<valueHelp>
- <format>text</format>
+ <format>txt</format>
<description>A DNS name relative to the root record</description>
</valueHelp>
<valueHelp>
@@ -306,7 +313,7 @@
<properties>
<help>"TXT" record</help>
<valueHelp>
- <format>text</format>
+ <format>txt</format>
<description>A DNS name relative to the root record</description>
</valueHelp>
<valueHelp>
@@ -322,7 +329,7 @@
<properties>
<help>Record contents</help>
<valueHelp>
- <format>text</format>
+ <format>txt</format>
<description>Record contents</description>
</valueHelp>
<multi/>
@@ -336,7 +343,7 @@
<properties>
<help>"SPF" record (type=SPF)</help>
<valueHelp>
- <format>text</format>
+ <format>txt</format>
<description>A DNS name relative to the root record</description>
</valueHelp>
<valueHelp>
@@ -352,7 +359,7 @@
<properties>
<help>Record contents</help>
<valueHelp>
- <format>text</format>
+ <format>txt</format>
<description>Record contents</description>
</valueHelp>
</properties>
@@ -365,7 +372,7 @@
<properties>
<help>"SRV" record</help>
<valueHelp>
- <format>text</format>
+ <format>txt</format>
<description>A DNS name relative to the root record</description>
</valueHelp>
<valueHelp>
@@ -449,7 +456,7 @@
<properties>
<help>"NAPTR" record</help>
<valueHelp>
- <format>text</format>
+ <format>txt</format>
<description>A DNS name relative to the root record</description>
</valueHelp>
<valueHelp>
diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i
index a9122db57..bcc131f83 100644
--- a/interface-definitions/include/bgp/protocol-common-config.xml.i
+++ b/interface-definitions/include/bgp/protocol-common-config.xml.i
@@ -810,12 +810,6 @@
</node>
</children>
</node>
- <leafNode name="advertise-all-vni">
- <properties>
- <help>Advertise All local VNIs</help>
- <valueless/>
- </properties>
- </leafNode>
#include <include/bgp/afi-l2vpn-common.xml.i>
<leafNode name="advertise-pip">
<properties>
@@ -1565,7 +1559,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/ldp-sync-holddown.xml.i b/interface-definitions/include/isis/ldp-sync-holddown.xml.i
new file mode 100644
index 000000000..15ac26f07
--- /dev/null
+++ b/interface-definitions/include/isis/ldp-sync-holddown.xml.i
@@ -0,0 +1,14 @@
+<!-- include start from isis/ldp-sync-holddown.xml.i -->
+<leafNode name="holddown">
+ <properties>
+ <help>Hold down timer for LDP-IGP cost restoration</help>
+ <valueHelp>
+ <format>u32:0-10000</format>
+ <description>Time to wait in seconds for LDP-IGP synchronization to occur before restoring interface cost</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 0-10000"/>
+ </constraint>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/isis/ldp-sync-interface.xml.i b/interface-definitions/include/isis/ldp-sync-interface.xml.i
new file mode 100644
index 000000000..222a35256
--- /dev/null
+++ b/interface-definitions/include/isis/ldp-sync-interface.xml.i
@@ -0,0 +1,11 @@
+<!-- include start from isis/ldp-igp-sync.xml.i -->
+<node name="ldp-sync">
+ <properties>
+ <help>LDP-IGP synchronization configuration for interface</help>
+ </properties>
+ <children>
+ #include <include/generic-disable-node.xml.i>
+ #include <include/isis/ldp-sync-holddown.xml.i>
+ </children>
+</node>
+<!-- include end -->
diff --git a/interface-definitions/include/isis/ldp-sync-protocol.xml.i b/interface-definitions/include/isis/ldp-sync-protocol.xml.i
new file mode 100644
index 000000000..b2e696a70
--- /dev/null
+++ b/interface-definitions/include/isis/ldp-sync-protocol.xml.i
@@ -0,0 +1,10 @@
+<!-- include start from isis/ldp-igp-sync.xml.i -->
+<node name="ldp-sync">
+ <properties>
+ <help>Protocol wide LDP-IGP synchronization configuration</help>
+ </properties>
+ <children>
+ #include <include/isis/ldp-sync-holddown.xml.i>
+ </children>
+</node>
+<!-- include end -->
diff --git a/interface-definitions/include/isis/protocol-common-config.xml.i b/interface-definitions/include/isis/protocol-common-config.xml.i
index 0e6f19480..4ca7061db 100644
--- a/interface-definitions/include/isis/protocol-common-config.xml.i
+++ b/interface-definitions/include/isis/protocol-common-config.xml.i
@@ -152,6 +152,7 @@
</constraint>
</properties>
</leafNode>
+#include <include/isis/ldp-sync-protocol.xml.i>
<leafNode name="net">
<properties>
<help>A Network Entity Title for this process (ISO only)</help>
@@ -172,7 +173,7 @@
</leafNode>
<node name="traffic-engineering">
<properties>
- <help>Show IS-IS neighbor adjacencies</help>
+ <help>IS-IS traffic engineering extensions</help>
</properties>
<children>
<leafNode name="enable">
@@ -631,6 +632,7 @@
</properties>
</leafNode>
#include <include/isis/metric.xml.i>
+ #include <include/isis/ldp-sync-interface.xml.i>
<node name="network">
<properties>
<help>Set network type</help>
@@ -685,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 f39b9c5e3..b7f22cb88 100644
--- a/interface-definitions/include/ospf/protocol-common-config.xml.i
+++ b/interface-definitions/include/ospf/protocol-common-config.xml.i
@@ -331,6 +331,7 @@
</constraint>
</properties>
</leafNode>
+#include <include/isis/ldp-sync-protocol.xml.i>
<node name="distance">
<properties>
<help>Administrative distance</help>
@@ -385,6 +386,7 @@
#include <include/ospf/authentication.xml.i>
#include <include/ospf/intervals.xml.i>
#include <include/ospf/interface-common.xml.i>
+ #include <include/isis/ldp-sync-interface.xml.i>
<leafNode name="bandwidth">
<properties>
<help>Interface bandwidth (Mbit/s)</help>
@@ -814,7 +816,6 @@
</leafNode>
</children>
</node>
-#include <include/route-map.xml.i>
<node name="timers">
<properties>
<help>Adjust routing timers</help>
@@ -875,4 +876,4 @@
</node>
</children>
</node>
-<!-- include end -->
+<!-- include end --> \ No newline at end of file
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/protocols-bgp.xml.in b/interface-definitions/protocols-bgp.xml.in
index e1a822999..78b461f9d 100644
--- a/interface-definitions/protocols-bgp.xml.in
+++ b/interface-definitions/protocols-bgp.xml.in
@@ -9,6 +9,20 @@
</properties>
<children>
#include <include/bgp/protocol-common-config.xml.i>
+ <node name="address-family">
+ <children>
+ <node name="l2vpn-evpn">
+ <children>
+ <leafNode name="advertise-all-vni">
+ <properties>
+ <help>Advertise all local VNIs</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ </children>
+ </node>
</children>
</node>
</children>
diff --git a/interface-definitions/protocols-failover.xml.in b/interface-definitions/protocols-failover.xml.in
index 900c76eab..a8c5c717f 100644
--- a/interface-definitions/protocols-failover.xml.in
+++ b/interface-definitions/protocols-failover.xml.in
@@ -48,6 +48,7 @@
<constraint>
<validator name="ipv4-address"/>
</constraint>
+ <multi/>
</properties>
</leafNode>
<leafNode name="timeout">
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/vpn-pptp.xml.in b/interface-definitions/vpn-pptp.xml.in
index 00ffd26f9..5a8b4a78a 100644
--- a/interface-definitions/vpn-pptp.xml.in
+++ b/interface-definitions/vpn-pptp.xml.in
@@ -108,9 +108,13 @@
</tagNode>
</children>
</node>
+ <node name="radius">
+ <children>
+ #include <include/accel-ppp/radius-additions-rate-limit.xml.i>
+ </children>
+ </node>
#include <include/radius-auth-server-ipv4.xml.i>
#include <include/accel-ppp/radius-additions.xml.i>
- #include <include/accel-ppp/radius-additions-rate-limit.xml.i>
</children>
</node>
</children>
diff --git a/interface-definitions/vrf.xml.in b/interface-definitions/vrf.xml.in
index 96c6d8be2..3783785ce 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,10 +121,10 @@
<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">
+ <leafNode name="vni" owner="${vyos_conf_scripts_dir}/vrf_vni.py $VAR(../@)">
<properties>
<help>Virtual Network Identifier</help>
- <!-- priority must be after BGP -->
+ <!-- must be after BGP to keep correct order when removing L3VNIs in FRR -->
<priority>822</priority>
<valueHelp>
<format>u32:0-16777214</format>
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/op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i b/op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i
index 7dbc4fde5..820d507fd 100644
--- a/op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i
+++ b/op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i
@@ -195,6 +195,12 @@
</leafNode>
</children>
</node>
+ <leafNode name="filtered-routes">
+ <properties>
+ <help>Show filtered routes from BGP neighbor</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ </leafNode>
<leafNode name="received-routes">
<properties>
<help>Show received routes from BGP neighbor</help>
diff --git a/op-mode-definitions/include/bgp/evpn-type-1.xml.i b/op-mode-definitions/include/bgp/evpn-type-1.xml.i
new file mode 100644
index 000000000..b5097c8b1
--- /dev/null
+++ b/op-mode-definitions/include/bgp/evpn-type-1.xml.i
@@ -0,0 +1,8 @@
+<!-- included start from bgp/evpn-type-1.xml.i -->
+<leafNode name="1">
+ <properties>
+ <help>EAD (Type-1) route</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+</leafNode>
+<!-- included end -->
diff --git a/op-mode-definitions/include/bgp/evpn-type-2.xml.i b/op-mode-definitions/include/bgp/evpn-type-2.xml.i
new file mode 100644
index 000000000..827298d62
--- /dev/null
+++ b/op-mode-definitions/include/bgp/evpn-type-2.xml.i
@@ -0,0 +1,8 @@
+<!-- included start from bgp/evpn-type-2.xml.i -->
+<leafNode name="2">
+ <properties>
+ <help>MAC-IP (Type-2) route</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+</leafNode>
+<!-- included end -->
diff --git a/op-mode-definitions/include/bgp/evpn-type-3.xml.i b/op-mode-definitions/include/bgp/evpn-type-3.xml.i
new file mode 100644
index 000000000..ae90b2e5c
--- /dev/null
+++ b/op-mode-definitions/include/bgp/evpn-type-3.xml.i
@@ -0,0 +1,8 @@
+<!-- included start from bgp/evpn-type-3.xml.i -->
+<leafNode name="3">
+ <properties>
+ <help>Multicast (Type-3) route</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+</leafNode>
+<!-- included end -->
diff --git a/op-mode-definitions/include/bgp/evpn-type-4.xml.i b/op-mode-definitions/include/bgp/evpn-type-4.xml.i
new file mode 100644
index 000000000..7248b4753
--- /dev/null
+++ b/op-mode-definitions/include/bgp/evpn-type-4.xml.i
@@ -0,0 +1,8 @@
+<!-- included start from bgp/evpn-type-4.xml.i -->
+<leafNode name="4">
+ <properties>
+ <help>Ethernet Segment (Type-4) route</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+</leafNode>
+<!-- included end -->
diff --git a/op-mode-definitions/include/bgp/evpn-type-5.xml.i b/op-mode-definitions/include/bgp/evpn-type-5.xml.i
new file mode 100644
index 000000000..e3a72168a
--- /dev/null
+++ b/op-mode-definitions/include/bgp/evpn-type-5.xml.i
@@ -0,0 +1,8 @@
+<!-- included start from bgp/evpn-type-5.xml.i -->
+<leafNode name="5">
+ <properties>
+ <help>Prefix (Type-5) route</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+</leafNode>
+<!-- included end -->
diff --git a/op-mode-definitions/include/bgp/evpn-type-ead.xml.i b/op-mode-definitions/include/bgp/evpn-type-ead.xml.i
new file mode 100644
index 000000000..452de2f9a
--- /dev/null
+++ b/op-mode-definitions/include/bgp/evpn-type-ead.xml.i
@@ -0,0 +1,8 @@
+<!-- included start from bgp/evpn-type-ead.xml.i -->
+<leafNode name="ead">
+ <properties>
+ <help>EAD (Type-1) route</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+</leafNode>
+<!-- included end -->
diff --git a/op-mode-definitions/include/bgp/evpn-type-es.xml.i b/op-mode-definitions/include/bgp/evpn-type-es.xml.i
new file mode 100644
index 000000000..50c40151a
--- /dev/null
+++ b/op-mode-definitions/include/bgp/evpn-type-es.xml.i
@@ -0,0 +1,8 @@
+<!-- included start from bgp/evpn-type-es.xml.i -->
+<leafNode name="es">
+ <properties>
+ <help>Ethernet Segment (Type-4) route</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+</leafNode>
+<!-- included end -->
diff --git a/op-mode-definitions/include/bgp/evpn-type-macip.xml.i b/op-mode-definitions/include/bgp/evpn-type-macip.xml.i
new file mode 100644
index 000000000..6f601eb3f
--- /dev/null
+++ b/op-mode-definitions/include/bgp/evpn-type-macip.xml.i
@@ -0,0 +1,8 @@
+<!-- included start from bgp/evpn-type-macip.xml.i -->
+<leafNode name="macip">
+ <properties>
+ <help>MAC-IP (Type-2) route</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+</leafNode>
+<!-- included end -->
diff --git a/op-mode-definitions/include/bgp/evpn-type-multicast.xml.i b/op-mode-definitions/include/bgp/evpn-type-multicast.xml.i
new file mode 100644
index 000000000..5194dbb56
--- /dev/null
+++ b/op-mode-definitions/include/bgp/evpn-type-multicast.xml.i
@@ -0,0 +1,8 @@
+<!-- included start from bgp/evpn-type-multicast.xml.i -->
+<leafNode name="multicast">
+ <properties>
+ <help>Multicast (Type-3) route</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+</leafNode>
+<!-- included end -->
diff --git a/op-mode-definitions/include/bgp/evpn-type-prefix.xml.i b/op-mode-definitions/include/bgp/evpn-type-prefix.xml.i
new file mode 100644
index 000000000..d5054d86b
--- /dev/null
+++ b/op-mode-definitions/include/bgp/evpn-type-prefix.xml.i
@@ -0,0 +1,8 @@
+<!-- included start from bgp/evpn-type-prefix.xml.i -->
+<leafNode name="prefix">
+ <properties>
+ <help>Prefix (Type-5) route</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+</leafNode>
+<!-- included end -->
diff --git a/op-mode-definitions/include/bgp/show-bgp-common.xml.i b/op-mode-definitions/include/bgp/show-bgp-common.xml.i
index c9a112fca..de794a879 100644
--- a/op-mode-definitions/include/bgp/show-bgp-common.xml.i
+++ b/op-mode-definitions/include/bgp/show-bgp-common.xml.i
@@ -171,66 +171,16 @@
<help>Specify Route type</help>
</properties>
<children>
- <leafNode name="1">
- <properties>
- <help>EAD (Type-1) route</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
- <leafNode name="2">
- <properties>
- <help>MAC-IP (Type-2) route</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
- <leafNode name="3">
- <properties>
- <help>Multicast (Type-3) route</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
- <leafNode name="4">
- <properties>
- <help>Ethernet Segment (Type-4) route</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
- <leafNode name="5">
- <properties>
- <help>Prefix (Type-5) route</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
- <leafNode name="ead">
- <properties>
- <help>EAD (Type-1) route</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
- <leafNode name="es">
- <properties>
- <help>Ethernet Segment (Type-4) route</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
- <leafNode name="macip">
- <properties>
- <help>MAC-IP (Type-2) route</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
- <leafNode name="multicast">
- <properties>
- <help>Multicast (Type-3) route</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
- <leafNode name="prefix">
- <properties>
- <help>Prefix (Type-5) route</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
+ #include <include/bgp/evpn-type-1.xml.i>
+ #include <include/bgp/evpn-type-2.xml.i>
+ #include <include/bgp/evpn-type-3.xml.i>
+ #include <include/bgp/evpn-type-4.xml.i>
+ #include <include/bgp/evpn-type-5.xml.i>
+ #include <include/bgp/evpn-type-ead.xml.i>
+ #include <include/bgp/evpn-type-es.xml.i>
+ #include <include/bgp/evpn-type-macip.xml.i>
+ #include <include/bgp/evpn-type-multicast.xml.i>
+ #include <include/bgp/evpn-type-prefix.xml.i>
</children>
</node>
#include <include/vni-tagnode-all.xml.i>
diff --git a/op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i b/op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i
index 36cc9a3fa..db9021f3e 100644
--- a/op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i
+++ b/op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i
@@ -93,6 +93,12 @@
</properties>
<command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
</leafNode>
+ <leafNode name="filtered-routes">
+ <properties>
+ <help>Show the filtered routes from neighbor</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ </leafNode>
<leafNode name="received-routes">
<properties>
<help>Show the received routes from neighbor</help>
diff --git a/op-mode-definitions/include/isis-common.xml.i b/op-mode-definitions/include/isis-common.xml.i
index 0e20861c7..e94d868e8 100644
--- a/op-mode-definitions/include/isis-common.xml.i
+++ b/op-mode-definitions/include/isis-common.xml.i
@@ -4,12 +4,7 @@
<help>Show IS-IS link state database</help>
</properties>
<children>
- <leafNode name="detail">
- <properties>
- <help>Show detailed information</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
+ #include <include/vtysh-generic-detail.xml.i>
</children>
<command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
</node>
@@ -36,27 +31,22 @@
</completionHelp>
</properties>
<children>
- <leafNode name="detail">
- <properties>
- <help>Show detailed information</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
+ #include <include/vtysh-generic-detail.xml.i>
</children>
<command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
</node>
-<tagNode name="interface">
+#include <include/vtysh-generic-interface-tagNode.xml.i>
+<node name="mpls">
<properties>
- <help>Show specific IS-IS interface</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
+ <help>Show MPLS information</help>
</properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
-</tagNode>
+ <children>
+ #include <include/ldp-sync.xml.i>
+ </children>
+</node>
<node name="mpls-te">
<properties>
- <help>Show IS-IS MPLS traffic engineering information</help>
+ <help>Show MPLS traffic engineering information</help>
</properties>
<children>
<leafNode name="router">
@@ -71,15 +61,7 @@
</properties>
<command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
</leafNode>
- <tagNode name="interface">
- <properties>
- <help>Show specific IS-IS interface</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </tagNode>
+ #include <include/vtysh-generic-interface-tagNode.xml.i>
</children>
</node>
<node name="neighbor">
@@ -87,12 +69,7 @@
<help>Show IS-IS neighbor adjacencies</help>
</properties>
<children>
- <leafNode name="detail">
- <properties>
- <help>Show detailed information</help>
- </properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
- </leafNode>
+ #include <include/vtysh-generic-detail.xml.i>
</children>
<command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
</node>
@@ -176,4 +153,4 @@
</children>
<command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
</node>
-<!-- included end -->
+<!-- included end --> \ No newline at end of file
diff --git a/op-mode-definitions/include/ldp-sync.xml.i b/op-mode-definitions/include/ldp-sync.xml.i
new file mode 100644
index 000000000..b7b04e7e5
--- /dev/null
+++ b/op-mode-definitions/include/ldp-sync.xml.i
@@ -0,0 +1,11 @@
+<!-- included start from ldp-sync.xml.i -->
+<node name="ldp-sync">
+ <properties>
+ <help>Show LDP-IGP synchronization information</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ <children>
+ #include <include/vtysh-generic-interface-tagNode.xml.i>
+ </children>
+</node>
+<!-- included end --> \ No newline at end of file
diff --git a/op-mode-definitions/include/ospf-common.xml.i b/op-mode-definitions/include/ospf-common.xml.i
index 098254f4e..979ffb07e 100644
--- a/op-mode-definitions/include/ospf-common.xml.i
+++ b/op-mode-definitions/include/ospf-common.xml.i
@@ -508,15 +508,15 @@
</properties>
<command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
</node>
-<tagNode name="interface">
+#include <include/vtysh-generic-interface-tagNode.xml.i>
+<node name="mpls">
<properties>
- <help>Show IPv4 OSPF information for specified interface</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
+ <help>Show MPLS information</help>
</properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
-</tagNode>
+ <children>
+ #include <include/ldp-sync.xml.i>
+ </children>
+</node>
<node name="neighbor">
<properties>
<help>Show IPv4 OSPF neighbor information</help>
@@ -541,10 +541,19 @@
</properties>
<command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
</tagNode>
-<leafNode name="route">
+<node name="route">
<properties>
<help>Show IPv4 OSPF route information</help>
</properties>
<command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
-</leafNode>
+ <children>
+ <leafNode name="detail">
+ <properties>
+ <help>Show detailed IPv4 OSPF route information</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ </leafNode>
+ </children>
+</node>
<!-- included end -->
+
diff --git a/op-mode-definitions/include/vtysh-generic-interface-tagNode.xml.i b/op-mode-definitions/include/vtysh-generic-interface-tagNode.xml.i
new file mode 100644
index 000000000..e95961177
--- /dev/null
+++ b/op-mode-definitions/include/vtysh-generic-interface-tagNode.xml.i
@@ -0,0 +1,11 @@
+<!-- included start from vtysh-generic-interface.xml.i -->
+<tagNode name="interface">
+ <properties>
+ <help>Show information about specific interface</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces</script>
+ </completionHelp>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+</tagNode>
+<!-- included end -->
diff --git a/op-mode-definitions/show-bgp.xml.in b/op-mode-definitions/show-bgp.xml.in
index 974147621..3c212614c 100644
--- a/op-mode-definitions/show-bgp.xml.in
+++ b/op-mode-definitions/show-bgp.xml.in
@@ -51,6 +51,33 @@
</properties>
<command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
</leafNode>
+ #include <include/vni-tagnode-all.xml.i>
+ <tagNode name="vni">
+ <children>
+ <tagNode name="vtep">
+ <properties>
+ <help>Remote VTEP IP address</help>
+ <completionHelp>
+ <list>&lt;x.x.x.x&gt;</list>
+ </completionHelp>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ </tagNode>
+ <node name="type">
+ <properties>
+ <help>Display number of prefixes for all afi/safi</help>
+ </properties>
+ <children>
+ #include <include/bgp/evpn-type-1.xml.i>
+ #include <include/bgp/evpn-type-2.xml.i>
+ #include <include/bgp/evpn-type-3.xml.i>
+ #include <include/bgp/evpn-type-ead.xml.i>
+ #include <include/bgp/evpn-type-macip.xml.i>
+ #include <include/bgp/evpn-type-multicast.xml.i>
+ </children>
+ </node>
+ </children>
+ </tagNode>
<leafNode name="vrf">
<properties>
<help>Show BGP VRF information</help>
diff --git a/op-mode-definitions/show-techsupport_report.xml.in b/op-mode-definitions/show-techsupport_report.xml.in
new file mode 100644
index 000000000..aa51eacd9
--- /dev/null
+++ b/op-mode-definitions/show-techsupport_report.xml.in
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name="show">
+ <children>
+ <node name="tech-support">
+ <children>
+ <node name="report">
+ <properties>
+ <help>Show consolidated tech-support report (contains private information)</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/show_techsupport_report.py</command>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index fc33430eb..f62b9f7d2 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -1709,6 +1709,14 @@ class VLANIf(Interface):
if self.exists(f'{self.ifname}'):
return
+ # If source_interface or vlan_id was not explicitly defined (e.g. when
+ # calling VLANIf('eth0.1').remove() we can define source_interface and
+ # vlan_id here, as it's quiet obvious that it would be eth0 in that case.
+ if 'source_interface' not in self.config:
+ self.config['source_interface'] = '.'.join(self.ifname.split('.')[:-1])
+ if 'vlan_id' not in self.config:
+ self.config['vlan_id'] = self.ifname.split('.')[-1]
+
cmd = 'ip link add link {source_interface} name {ifname} type vlan id {vlan_id}'
if 'protocol' in self.config:
cmd += ' protocol {protocol}'
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_interfaces_openvpn.py b/smoketest/scripts/cli/test_interfaces_openvpn.py
index b2143d16e..c80c7cf80 100755
--- a/smoketest/scripts/cli/test_interfaces_openvpn.py
+++ b/smoketest/scripts/cli/test_interfaces_openvpn.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
@@ -368,6 +368,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):
self.cli_set(path + ['hash', auth_hash])
self.cli_set(path + ['mode', 'server'])
self.cli_set(path + ['local-port', port])
+ self.cli_set(path + ['server', 'mfa', 'totp'])
self.cli_set(path + ['server', 'subnet', subnet])
self.cli_set(path + ['server', 'topology', 'subnet'])
self.cli_set(path + ['keep-alive', 'failure-count', '5'])
@@ -388,6 +389,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):
for ii in num_range:
interface = f'vtun{ii}'
+ plugin = f'plugin "/usr/lib/openvpn/openvpn-otp.so" "otp_secrets=/config/auth/openvpn/{interface}-otp-secrets otp_slop=180 totp_t0=0 totp_step=30 totp_digits=6 password_is_cr=1"'
subnet = f'192.0.{ii}.0/24'
start_addr = inc_ip(subnet, '2')
@@ -411,6 +413,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'topology subnet', config)
self.assertIn(f'lport {port}', config)
self.assertIn(f'push "redirect-gateway def1"', config)
+ self.assertIn(f'{plugin}', config)
self.assertIn(f'keepalive 5 25', config)
# TLS options
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_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py
index d11d80a1f..f1a030e77 100755
--- a/smoketest/scripts/cli/test_protocols_isis.py
+++ b/smoketest/scripts/cli/test_protocols_isis.py
@@ -119,39 +119,6 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.cli_delete(['vrf', 'name', vrf])
self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf'])
- def test_isis_03_zebra_route_map(self):
- # Implemented because of T3328
- route_map = 'foo-isis-in'
-
- self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
-
- self.isis_base_config()
- self.cli_set(base_path + ['redistribute', 'ipv4', 'connected', 'level-2', 'route-map', route_map])
- self.cli_set(base_path + ['route-map', route_map])
- self.cli_set(base_path + ['level', 'level-2'])
-
- # commit changes
- self.cli_commit()
-
- # Verify FRR configuration
- zebra_route_map = f'ip protocol isis route-map {route_map}'
- frrconfig = self.getFRRconfig(zebra_route_map, daemon='zebra')
- self.assertIn(zebra_route_map, frrconfig)
-
- tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd')
- self.assertIn(' is-type level-2-only', tmp)
-
- # 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, daemon='zebra')
- self.assertNotIn(zebra_route_map, frrconfig)
-
- self.cli_delete(['policy', 'route-map', route_map])
-
def test_isis_04_default_information(self):
metric = '50'
route_map = 'default-foo-'
@@ -293,7 +260,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['segment-routing', 'prefix', prefix_three, 'absolute', 'explicit-null'])
self.cli_set(base_path + ['segment-routing', 'prefix', prefix_four, 'absolute', 'value', prefix_four_value])
self.cli_set(base_path + ['segment-routing', 'prefix', prefix_four, 'absolute', 'no-php-flag'])
-
+
# Commit all changes
self.cli_commit()
@@ -308,5 +275,48 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' segment-routing prefix {prefix_three} absolute {prefix_three_value} explicit-null', tmp)
self.assertIn(f' segment-routing prefix {prefix_four} absolute {prefix_four_value} no-php-flag', tmp)
+ def test_isis_08_ldp_sync(self):
+ holddown = "500"
+ interface = 'lo'
+
+ self.cli_set(base_path + ['net', net])
+ self.cli_set(base_path + ['interface', interface])
+ self.cli_set(base_path + ['ldp-sync', 'holddown', holddown])
+
+ # Commit main ISIS changes
+ self.cli_commit()
+
+ # Verify main ISIS changes
+ tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd')
+ self.assertIn(f' net {net}', tmp)
+ self.assertIn(f' mpls ldp-sync', tmp)
+ self.assertIn(f' mpls ldp-sync holddown {holddown}', tmp)
+
+ for interface in self._interfaces:
+ self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'holddown', holddown])
+
+ # Commit interface changes for holddown
+ self.cli_commit()
+
+ # Verify interface changes for holddown
+ tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd')
+ self.assertIn(f'interface {interface}', tmp)
+ self.assertIn(f' ip router isis {domain}', tmp)
+ self.assertIn(f' ipv6 router isis {domain}', tmp)
+ self.assertIn(f' isis mpls ldp-sync holddown {holddown}', tmp)
+
+ for interface in self._interfaces:
+ self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'disable'])
+
+ # Commit interface changes for disable
+ self.cli_commit()
+
+ # Verify interface changes for disable
+ tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd')
+ self.assertIn(f'interface {interface}', tmp)
+ self.assertIn(f' ip router isis {domain}', tmp)
+ self.assertIn(f' ipv6 router isis {domain}', tmp)
+ self.assertIn(f' no isis mpls ldp-sync', tmp)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py
index 581959b15..6fe6dd979 100755
--- a/smoketest/scripts/cli/test_protocols_ospf.py
+++ b/smoketest/scripts/cli/test_protocols_ospf.py
@@ -300,26 +300,6 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' no ip ospf passive', config)
self.assertIn(f' bandwidth {bandwidth}', config)
- def test_ospf_10_zebra_route_map(self):
- # Implemented because of T3328
- self.cli_set(base_path + ['route-map', route_map])
- # commit changes
- self.cli_commit()
-
- # Verify FRR configuration
- zebra_route_map = f'ip protocol ospf route-map {route_map}'
- 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_ospf_11_interface_area(self):
area = '0'
interfaces = Section.interfaces('ethernet')
@@ -434,6 +414,47 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' segment-routing prefix {prefix_one} index {prefix_one_value} explicit-null', frrconfig)
self.assertIn(f' segment-routing prefix {prefix_two} index {prefix_two_value} no-php-flag', frrconfig)
+ def test_ospf_15_ldp_sync(self):
+ holddown = "500"
+ interface = 'lo'
+ interfaces = Section.interfaces('ethernet')
+
+ self.cli_set(base_path + ['interface', interface])
+ self.cli_set(base_path + ['ldp-sync', 'holddown', holddown])
+
+ # Commit main OSPF changes
+ self.cli_commit()
+
+ # Verify main OSPF changes
+ frrconfig = self.getFRRconfig('router ospf')
+ self.assertIn(f'router ospf', frrconfig)
+ self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig)
+ self.assertIn(f' mpls ldp-sync holddown {holddown}', frrconfig)
+
+ for interface in interfaces:
+ self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'holddown', holddown])
+
+ # Commit interface changes for holddown
+ self.cli_commit()
+
+ # Verify interface changes for holddown
+ config = self.getFRRconfig(f'interface {interface}')
+ self.assertIn(f'interface {interface}', config)
+ self.assertIn(f' ip ospf dead-interval 40', config)
+ self.assertIn(f' ip ospf mpls ldp-sync', config)
+ self.assertIn(f' ip ospf mpls ldp-sync holddown {holddown}', config)
+
+ for interface in interfaces:
+ self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'disable'])
+
+ # Commit interface changes for disable
+ self.cli_commit()
+
+ # Verify interface changes for disable
+ config = self.getFRRconfig(f'interface {interface}')
+ self.assertIn(f'interface {interface}', config)
+ self.assertIn(f' ip ospf dead-interval 40', config)
+ self.assertIn(f' no ip ospf mpls ldp-sync', config)
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py
index 19efe7786..bc023f3f2 100755
--- a/smoketest/scripts/cli/test_protocols_static.py
+++ b/smoketest/scripts/cli/test_protocols_static.py
@@ -433,30 +433,5 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
self.assertIn(tmp, frrconfig)
- def test_04_static_zebra_route_map(self):
- # Implemented because of T3328
- route_map = 'foo-static-in'
- self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
-
- self.cli_set(base_path + ['route-map', route_map])
- # commit changes
- self.cli_commit()
-
- # Verify FRR configuration
- zebra_route_map = f'ip protocol static route-map {route_map}'
- 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)
-
- self.cli_delete(['policy', 'route-map', route_map])
-
if __name__ == '__main__':
unittest.main(verbosity=2)
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/container.py b/src/conf_mode/container.py
index 4b7ab3444..aceb27fb0 100755
--- a/src/conf_mode/container.py
+++ b/src/conf_mode/container.py
@@ -376,11 +376,11 @@ def generate(container):
'name': network,
'id' : sha256(f'{network}'.encode()).hexdigest(),
'driver': 'bridge',
- 'network_interface': f'podman-{network}',
+ 'network_interface': f'pod-{network}',
'subnets': [],
'ipv6_enabled': False,
'internal': False,
- 'dns_enabled': False,
+ 'dns_enabled': True,
'ipam_options': {
'driver': 'host-local'
}
@@ -479,7 +479,7 @@ def apply(container):
# the network interface in advance
if 'network' in container:
for network, network_config in container['network'].items():
- network_name = f'podman-{network}'
+ network_name = f'pod-{network}'
# T5147: Networks are started only as soon as there is a consumer.
# If only a network is created in the first place, no need to assign
# it to a VRF as there's no consumer, yet.
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index c41a442df..190587980 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -282,6 +282,9 @@ def verify_rule(firewall, rule_conf, ipv6):
if rule_conf['protocol'] not in ['tcp', 'udp', 'tcp_udp']:
raise ConfigError('Protocol must be tcp, udp, or tcp_udp when specifying a port or port-group')
+ if 'port' in side_conf and dict_search_args(side_conf, 'group', 'port_group'):
+ raise ConfigError(f'{side} port-group and port cannot both be defined')
+
if 'log_options' in rule_conf:
if 'log' not in rule_conf or 'enable' not in rule_conf['log']:
raise ConfigError('log-options defined, but log is not enable')
diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py
index 13d84a6fe..6f227b0d1 100755
--- a/src/conf_mode/interfaces-openvpn.py
+++ b/src/conf_mode/interfaces-openvpn.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
@@ -597,7 +597,7 @@ def generate_pki_files(openvpn):
def generate(openvpn):
interface = openvpn['ifname']
directory = os.path.dirname(cfg_file.format(**openvpn))
- plugin_dir = '/usr/lib/openvpn'
+ openvpn['plugin_dir'] = '/usr/lib/openvpn'
# create base config directory on demand
makedir(directory, user, group)
# enforce proper permissions on /run/openvpn
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 c1a1a45e1..609b39065 100755
--- a/src/conf_mode/protocols_eigrp.py
+++ b/src/conf_mode/protocols_eigrp.py
@@ -69,8 +69,6 @@ def get_config(config=None):
# Merge policy dict into "regular" config dict
eigrp = dict_merge(tmp, eigrp)
- import pprint
- pprint.pprint(eigrp)
return eigrp
def verify(eigrp):
@@ -80,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/service_monitoring_telegraf.py b/src/conf_mode/service_monitoring_telegraf.py
index 363408679..47510ce80 100755
--- a/src/conf_mode/service_monitoring_telegraf.py
+++ b/src/conf_mode/service_monitoring_telegraf.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
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
+import socket
import json
from sys import exit
@@ -57,6 +58,13 @@ def get_nft_filter_chains():
return chain_list
+def get_hostname() -> str:
+ try:
+ hostname = socket.getfqdn()
+ except socket.gaierror:
+ hostname = socket.gethostname()
+ return hostname
+
def get_config(config=None):
if config:
conf = config
@@ -79,6 +87,7 @@ def get_config(config=None):
monitoring = dict_merge(default_values, monitoring)
monitoring['custom_scripts_dir'] = custom_scripts_dir
+ monitoring['hostname'] = get_hostname()
monitoring['interfaces_ethernet'] = Section.interfaces('ethernet', vlan=False)
monitoring['nft_chains'] = get_nft_filter_chains()
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/vpn_pptp.py b/src/conf_mode/vpn_pptp.py
index 7550c411e..986a19972 100755
--- a/src/conf_mode/vpn_pptp.py
+++ b/src/conf_mode/vpn_pptp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2020 VyOS maintainers and contributors
+# Copyright (C) 2018-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
@@ -44,6 +44,8 @@ default_pptp = {
'radius_nas_ip' : '',
'radius_source_address' : '',
'radius_shaper_attr' : '',
+ 'radius_shaper_enable': False,
+ 'radius_shaper_multiplier': '',
'radius_shaper_vendor': '',
'radius_dynamic_author' : '',
'chap_secrets_file': pptp_chap_secrets, # used in Jinja2 template
@@ -183,15 +185,18 @@ def get_config(config=None):
pptp['radius_dynamic_author'] = dae
+ # Rate limit
+ if conf.exists(['rate-limit', 'attribute']):
+ pptp['radius_shaper_attr'] = conf.return_value(['rate-limit', 'attribute'])
+
if conf.exists(['rate-limit', 'enable']):
- pptp['radius_shaper_attr'] = 'Filter-Id'
- c_attr = ['rate-limit', 'enable', 'attribute']
- if conf.exists(c_attr):
- pptp['radius_shaper_attr'] = conf.return_value(c_attr)
-
- c_vendor = ['rate-limit', 'enable', 'vendor']
- if conf.exists(c_vendor):
- pptp['radius_shaper_vendor'] = conf.return_value(c_vendor)
+ pptp['radius_shaper_enable'] = True
+
+ if conf.exists(['rate-limit', 'multiplier']):
+ pptp['radius_shaper_multiplier'] = conf.return_value(['rate-limit', 'multiplier'])
+
+ if conf.exists(['rate-limit', 'vendor']):
+ pptp['radius_shaper_vendor'] = conf.return_value(['rate-limit', 'vendor'])
conf.set_level(base_path)
if conf.exists(['client-ip-pool']):
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
index 585fdbebf..56069ecbd 100755..100644
--- a/src/conf_mode/vrf_vni.py
+++ b/src/conf_mode/vrf_vni.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2021 VyOS maintainers and contributors
+# 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
@@ -24,26 +24,35 @@ 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)
+ vrf_name = None
+ if len(argv) > 1:
+ vrf_name = argv[1]
+
+ base = ['vrf', 'name', vrf_name]
+ vrf = { 'name' : conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=False) }
+
return vrf
def verify(vrf):
+ if len(argv) < 2:
+ raise ConfigError('VRF parameter not specified when valling vrf_vni.py')
+
return None
def generate(vrf):
- vrf['new_frr_config'] = render_to_string('frr/vrf-vni.frr.j2', vrf)
+ vrf['new_frr_config'] = render_to_string('frr/zebra.vrf.route-map.frr.j2', vrf)
return None
def apply(vrf):
+ frr_daemon = 'zebra'
+
# add configuration to FRR
frr_cfg = frr.FRRConfig()
frr_cfg.load_configuration(frr_daemon)
diff --git a/src/etc/systemd/system/hostapd@.service.d/override.conf b/src/etc/systemd/system/hostapd@.service.d/override.conf
index bb8e81d7a..926c07f94 100644
--- a/src/etc/systemd/system/hostapd@.service.d/override.conf
+++ b/src/etc/systemd/system/hostapd@.service.d/override.conf
@@ -1,6 +1,8 @@
[Unit]
After=
After=vyos-router.service
+ConditionFileNotEmpty=
+ConditionFileNotEmpty=/run/hostapd/%i.conf
[Service]
WorkingDirectory=/run/hostapd
diff --git a/src/helpers/vyos-failover.py b/src/helpers/vyos-failover.py
index 0de945f20..03fb42f57 100755
--- a/src/helpers/vyos-failover.py
+++ b/src/helpers/vyos-failover.py
@@ -30,7 +30,7 @@ my_name = Path(__file__).stem
def is_route_exists(route, gateway, interface, metric):
"""Check if route with expected gateway, dev and metric exists"""
- rc, data = rc_cmd(f'sudo ip --json route show protocol failover {route} '
+ rc, data = rc_cmd(f'ip --json route show protocol failover {route} '
f'via {gateway} dev {interface} metric {metric}')
if rc == 0:
data = json.loads(data)
@@ -72,6 +72,7 @@ def get_best_route_options(route, debug=False):
f'best_metric: {best_metric}, best_iface: {best_interface}')
return best_gateway, best_interface, best_metric
+
def is_port_open(ip, port):
"""
Check connection to remote host and port
@@ -91,32 +92,54 @@ def is_port_open(ip, port):
finally:
s.close()
-def is_target_alive(target=None, iface='', proto='icmp', port=None, debug=False):
- """
- Host availability check by ICMP, ARP, TCP
- Return True if target checks is successful
- % is_target_alive('192.0.2.1', 'eth1', proto='arp')
- True
+def is_target_alive(target_list=None, iface='', proto='icmp', port=None, debug=False):
+ """Check the availability of each target in the target_list using
+ the specified protocol ICMP, ARP, TCP
+
+ Args:
+ target_list (list): A list of IP addresses or hostnames to check.
+ iface (str): The name of the network interface to use for the check.
+ proto (str): The protocol to use for the check. Options are 'icmp', 'arp', or 'tcp'.
+ port (int): The port number to use for the TCP check. Only applicable if proto is 'tcp'.
+ debug (bool): If True, print debug information during the check.
+
+ Returns:
+ bool: True if all targets are reachable, False otherwise.
+
+ Example:
+ % is_target_alive(['192.0.2.1', '192.0.2.5'], 'eth1', proto='arp')
+ True
"""
if iface != '':
iface = f'-I {iface}'
- if proto == 'icmp':
- command = f'/usr/bin/ping -q {target} {iface} -n -c 2 -W 1'
- rc, response = rc_cmd(command)
- if debug: print(f' [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]')
- if rc == 0:
- return True
- elif proto == 'arp':
- command = f'/usr/bin/arping -b -c 2 -f -w 1 -i 1 {iface} {target}'
- rc, response = rc_cmd(command)
- if debug: print(f' [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]')
- if rc == 0:
- return True
- elif proto == 'tcp' and port is not None:
- return True if is_port_open(target, port) else False
- else:
- return False
+
+ for target in target_list:
+ match proto:
+ case 'icmp':
+ command = f'/usr/bin/ping -q {target} {iface} -n -c 2 -W 1'
+ rc, response = rc_cmd(command)
+ if debug:
+ print(f' [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]')
+ if rc != 0:
+ return False
+
+ case 'arp':
+ command = f'/usr/bin/arping -b -c 2 -f -w 1 -i 1 {iface} {target}'
+ rc, response = rc_cmd(command)
+ if debug:
+ print(f' [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]')
+ if rc != 0:
+ return False
+
+ case _ if proto == 'tcp' and port is not None:
+ if not is_port_open(target, port):
+ return False
+
+ case _:
+ return False
+
+ return True
if __name__ == '__main__':
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)
diff --git a/src/op_mode/dhcp.py b/src/op_mode/dhcp.py
index 41da14065..fe7f252ba 100755
--- a/src/op_mode/dhcp.py
+++ b/src/op_mode/dhcp.py
@@ -264,8 +264,10 @@ def show_pool_statistics(raw: bool, family: ArgFamily, pool: typing.Optional[str
def show_server_leases(raw: bool, family: ArgFamily, pool: typing.Optional[str],
sorted: typing.Optional[str], state: typing.Optional[ArgState]):
# if dhcp server is down, inactive leases may still be shown as active, so warn the user.
- if not is_systemd_service_running('isc-dhcp-server.service'):
- Warning('DHCP server is configured but not started. Data may be stale.')
+ v = '6' if family == 'inet6' else ''
+ service_name = 'DHCPv6' if family == 'inet6' else 'DHCP'
+ if not is_systemd_service_running(f'isc-dhcp-server{v}.service'):
+ Warning(f'{service_name} server is configured but not started. Data may be stale.')
v = 'v6' if family == 'inet6' else ''
if pool and pool not in _get_dhcp_pools(family=family):
diff --git a/src/op_mode/dynamic_dns.py b/src/op_mode/dynamic_dns.py
index 263a3b6a5..2cba33cc8 100755
--- a/src/op_mode/dynamic_dns.py
+++ b/src/op_mode/dynamic_dns.py
@@ -16,69 +16,63 @@
import os
import argparse
-import jinja2
import sys
import time
+from tabulate import tabulate
from vyos.config import Config
from vyos.util import call
cache_file = r'/run/ddclient/ddclient.cache'
-OUT_TMPL_SRC = """
-{% for entry in hosts %}
-ip address : {{ entry.ip }}
-host-name : {{ entry.host }}
-last update : {{ entry.time }}
-update-status: {{ entry.status }}
+columns = {
+ 'host': 'Hostname',
+ 'ipv4': 'IPv4 address',
+ 'status-ipv4': 'IPv4 status',
+ 'ipv6': 'IPv6 address',
+ 'status-ipv6': 'IPv6 status',
+ 'mtime': 'Last update',
+}
+
+
+def _get_formatted_host_records(host_data):
+ data_entries = []
+ for entry in host_data:
+ data_entries.append([entry.get(key) for key in columns.keys()])
+
+ header = columns.values()
+ output = tabulate(data_entries, header, numalign='left')
+ return output
-{% endfor %}
-"""
def show_status():
# A ddclient status file must not always exist
if not os.path.exists(cache_file):
sys.exit(0)
- data = {
- 'hosts': []
- }
+ data = []
with open(cache_file, 'r') as f:
for line in f:
if line.startswith('#'):
continue
- outp = {
- 'host': '',
- 'ip': '',
- 'time': ''
- }
-
- if 'host=' in line:
- host = line.split('host=')[1]
- if host:
- outp['host'] = host.split(',')[0]
-
- if 'ip=' in line:
- ip = line.split('ip=')[1]
- if ip:
- outp['ip'] = ip.split(',')[0]
-
- if 'mtime=' in line:
- mtime = line.split('mtime=')[1]
- if mtime:
- outp['time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(mtime.split(',')[0], base=10)))
+ props = {}
+ # ddclient cache rows have properties in 'key=value' format separated by comma
+ # we pick up the ones we are interested in
+ for kvraw in line.split(' ')[0].split(','):
+ k, v = kvraw.split('=')
+ if k in columns.keys():
+ props[k] = v
- if 'status=' in line:
- status = line.split('status=')[1]
- if status:
- outp['status'] = status.split(',')[0]
+ # Convert mtime to human readable format
+ if 'mtime' in props:
+ props['mtime'] = time.strftime(
+ "%Y-%m-%d %H:%M:%S", time.localtime(int(props['mtime'], base=10)))
- data['hosts'].append(outp)
+ data.append(props)
- tmpl = jinja2.Template(OUT_TMPL_SRC)
- print(tmpl.render(data))
+ print(_get_formatted_host_records(data))
def update_ddns():
diff --git a/src/op_mode/openvpn.py b/src/op_mode/openvpn.py
index 5a1a4914d..d9ae965c5 100755
--- a/src/op_mode/openvpn.py
+++ b/src/op_mode/openvpn.py
@@ -16,6 +16,7 @@
#
#
+import json
import os
import sys
import typing
@@ -25,6 +26,7 @@ import vyos.opmode
from vyos.util import bytes_to_human
from vyos.util import commit_in_progress
from vyos.util import call
+from vyos.util import rc_cmd
from vyos.config import Config
ArgMode = typing.Literal['client', 'server', 'site_to_site']
@@ -142,6 +144,25 @@ def _get_interface_status(mode: str, interface: str) -> dict:
return data
+
+def _get_interface_state(iface):
+ rc, out = rc_cmd(f'ip --json link show dev {iface}')
+ try:
+ data = json.loads(out)
+ except:
+ return 'DOWN'
+ return data[0].get('operstate', 'DOWN')
+
+
+def _get_interface_description(iface):
+ rc, out = rc_cmd(f'ip --json link show dev {iface}')
+ try:
+ data = json.loads(out)
+ except:
+ return ''
+ return data[0].get('ifalias', '')
+
+
def _get_raw_data(mode: str) -> list:
data: list = []
conf = Config()
@@ -154,6 +175,8 @@ def _get_raw_data(mode: str) -> list:
conf_dict[x]['mode'].replace('-', '_') == mode]
for intf in interfaces:
d = _get_interface_status(mode, intf)
+ d['state'] = _get_interface_state(intf)
+ d['description'] = _get_interface_description(intf)
d['local_host'] = conf_dict[intf].get('local-host', '')
d['local_port'] = conf_dict[intf].get('local-port', '')
if conf.exists(f'interfaces openvpn {intf} server client'):
diff --git a/src/op_mode/pki.py b/src/op_mode/pki.py
index 1e78c3a03..b054690b0 100755
--- a/src/op_mode/pki.py
+++ b/src/op_mode/pki.py
@@ -87,6 +87,9 @@ def get_config_certificate(name=None):
def get_certificate_ca(cert, ca_certs):
# Find CA certificate for given certificate
+ if not ca_certs:
+ return None
+
for ca_name, ca_dict in ca_certs.items():
if 'certificate' not in ca_dict:
continue
diff --git a/src/op_mode/show_techsupport_report.py b/src/op_mode/show_techsupport_report.py
new file mode 100644
index 000000000..782004144
--- /dev/null
+++ b/src/op_mode/show_techsupport_report.py
@@ -0,0 +1,303 @@
+#!/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/>.
+
+import os
+
+from typing import List
+from vyos.util import rc_cmd
+from vyos.ifconfig import Section
+from vyos.ifconfig import Interface
+
+
+def print_header(command: str) -> None:
+ """Prints a command with headers '-'.
+
+ Example:
+
+ % print_header('Example command')
+
+ ---------------
+ Example command
+ ---------------
+ """
+ header_length = len(command) * '-'
+ print(f"\n{header_length}\n{command}\n{header_length}")
+
+
+def execute_command(command: str, header_text: str) -> None:
+ """Executes a command and prints the output with a header.
+
+ Example:
+ % execute_command('uptime', "Uptime of the system")
+
+ --------------------
+ Uptime of the system
+ --------------------
+ 20:21:57 up 9:04, 5 users, load average: 0.00, 0.00, 0.0
+
+ """
+ print_header(header_text)
+ try:
+ rc, output = rc_cmd(command)
+ print(output)
+ except Exception as e:
+ print(f"Error executing command: {command}")
+ print(f"Error message: {e}")
+
+
+def op(cmd: str) -> str:
+ """Returns a command with the VyOS operational mode wrapper."""
+ return f'/opt/vyatta/bin/vyatta-op-cmd-wrapper {cmd}'
+
+
+def get_ethernet_interfaces() -> List[Interface]:
+ """Returns a list of Ethernet interfaces."""
+ return Section.interfaces('ethernet')
+
+
+def show_version() -> None:
+ """Prints the VyOS version and package changes."""
+ execute_command(op('show version'), 'VyOS Version and Package Changes')
+
+
+def show_config_file() -> None:
+ """Prints the contents of a configuration file with a header."""
+ execute_command('cat /opt/vyatta/etc/config/config.boot', 'Configuration file')
+
+
+def show_running_config() -> None:
+ """Prints the running configuration."""
+ execute_command(op('show configuration'), 'Running configuration')
+
+
+def show_package_repository_config() -> None:
+ """Prints the package repository configuration file."""
+ execute_command('cat /etc/apt/sources.list', 'Package Repository Configuration File')
+ execute_command('ls -l /etc/apt/sources.list.d/', 'Repositories')
+
+
+def show_user_startup_scripts() -> None:
+ """Prints the user startup scripts."""
+ execute_command('cat /config/scripts/vyos-postconfig-bootup.script', 'User Startup Scripts')
+
+
+def show_frr_config() -> None:
+ """Prints the FRR configuration."""
+ execute_command('vtysh -c "show run"', 'FRR configuration')
+
+
+def show_interfaces() -> None:
+ """Prints the interfaces."""
+ execute_command(op('show interfaces'), 'Interfaces')
+
+
+def show_interface_statistics() -> None:
+ """Prints the interface statistics."""
+ execute_command('ip -s link show', 'Interface statistics')
+
+
+def show_physical_interface_statistics() -> None:
+ """Prints the physical interface statistics."""
+ execute_command('/usr/bin/true', 'Physical Interface statistics')
+ for iface in get_ethernet_interfaces():
+ # Exclude vlans
+ if '.' in iface:
+ continue
+ execute_command(f'ethtool --driver {iface}', f'ethtool --driver {iface}')
+ execute_command(f'ethtool --statistics {iface}', f'ethtool --statistics {iface}')
+ execute_command(f'ethtool --show-ring {iface}', f'ethtool --show-ring {iface}')
+ execute_command(f'ethtool --show-coalesce {iface}', f'ethtool --show-coalesce {iface}')
+ execute_command(f'ethtool --pause {iface}', f'ethtool --pause {iface}')
+ execute_command(f'ethtool --show-features {iface}', f'ethtool --show-features {iface}')
+ execute_command(f'ethtool --phy-statistics {iface}', f'ethtool --phy-statistics {iface}')
+ execute_command('netstat --interfaces', 'netstat --interfaces')
+ execute_command('netstat --listening', 'netstat --listening')
+ execute_command('cat /proc/net/dev', 'cat /proc/net/dev')
+
+
+def show_bridge() -> None:
+ """Show bridge interfaces."""
+ execute_command(op('show bridge'), 'Show bridge')
+
+
+def show_arp() -> None:
+ """Prints ARP entries."""
+ execute_command(op('show arp'), 'ARP Table (Total entries)')
+ execute_command(op('show ipv6 neighbors'), 'show ipv6 neighbors')
+
+
+def show_route() -> None:
+ """Prints routing information."""
+
+ cmd_list_route = [
+ "show ip route bgp | head -108",
+ "show ip route cache",
+ "show ip route connected",
+ "show ip route forward",
+ "show ip route isis | head -108",
+ "show ip route kernel",
+ "show ip route ospf | head -108",
+ "show ip route rip",
+ "show ip route static",
+ "show ip route summary",
+ "show ip route supernets-only",
+ "show ip route table all",
+ "show ip route vrf all",
+ "show ipv6 route bgp | head 108",
+ "show ipv6 route cache",
+ "show ipv6 route connected",
+ "show ipv6 route forward",
+ "show ipv6 route isis",
+ "show ipv6 route kernel",
+ "show ipv6 route ospf",
+ "show ipv6 route rip",
+ "show ipv6 route static",
+ "show ipv6 route summary",
+ "show ipv6 route table all",
+ "show ipv6 route vrf all",
+ ]
+ for command in cmd_list_route:
+ execute_command(op(command), command)
+
+
+def show_firewall() -> None:
+ """Prints firweall information."""
+ execute_command('sudo nft list ruleset', 'nft list ruleset')
+
+
+def show_system() -> None:
+ """Prints system parameters."""
+ execute_command(op('show system image version'), 'Show System Image Version')
+ execute_command(op('show system image storage'), 'Show System Image Storage')
+
+
+def show_date() -> None:
+ """Print the current date."""
+ execute_command('date', 'Current Time')
+
+
+def show_installed_packages() -> None:
+ """Prints installed packages."""
+ execute_command('dpkg --list', 'Installed Packages')
+
+
+def show_loaded_modules() -> None:
+ """Prints loaded modules /proc/modules"""
+ execute_command('cat /proc/modules', 'Loaded Modules')
+
+
+def show_cpu_statistics() -> None:
+ """Prints CPU statistics."""
+ execute_command('/usr/bin/true', 'CPU')
+ execute_command('lscpu', 'Installed CPU\'s')
+ execute_command('top --iterations 1 --batch-mode --accum-time-toggle', 'Cumulative CPU Time Used by Running Processes')
+ execute_command('cat /proc/loadavg', 'Load Average')
+
+
+def show_system_interrupts() -> None:
+ """Prints system interrupts."""
+ execute_command('cat /proc/interrupts', 'Hardware Interrupt Counters')
+
+
+def show_soft_irqs() -> None:
+ """Prints soft IRQ's."""
+ execute_command('cat /proc/softirqs', 'Soft IRQ\'s')
+
+
+def show_softnet_statistics() -> None:
+ """Prints softnet statistics."""
+ execute_command('cat /proc/net/softnet_stat', 'cat /proc/net/softnet_stat')
+
+
+def show_running_processes() -> None:
+ """Prints current running processes"""
+ execute_command('ps -ef', 'Running Processes')
+
+
+def show_memory_usage() -> None:
+ """Prints memory usage"""
+ execute_command('/usr/bin/true', 'Memory')
+ execute_command('cat /proc/meminfo', 'Installed Memory')
+ execute_command('free', 'Memory Usage')
+
+
+def list_disks():
+ disks = set()
+ with open('/proc/partitions') as partitions_file:
+ for line in partitions_file:
+ fields = line.strip().split()
+ if len(fields) == 4 and fields[3].isalpha() and fields[3] != 'name':
+ disks.add(fields[3])
+ return disks
+
+
+def show_storage() -> None:
+ """Prints storage information."""
+ execute_command('cat /proc/devices', 'Devices')
+ execute_command('cat /proc/partitions', 'Partitions')
+
+ for disk in list_disks():
+ execute_command(f'fdisk --list /dev/{disk}', f'Partitioning for disk {disk}')
+
+
+def main():
+ # Configuration data
+ show_version()
+ show_config_file()
+ show_running_config()
+ show_package_repository_config()
+ show_user_startup_scripts()
+ show_frr_config()
+
+ # Interfaces
+ show_interfaces()
+ show_interface_statistics()
+ show_physical_interface_statistics()
+ show_bridge()
+ show_arp()
+
+ # Routing
+ show_route()
+
+ # Firewall
+ show_firewall()
+
+ # System
+ show_system()
+ show_date()
+ show_installed_packages()
+ show_loaded_modules()
+
+ # CPU
+ show_cpu_statistics()
+ show_system_interrupts()
+ show_soft_irqs()
+ show_softnet_statistics()
+
+ # Memory
+ show_memory_usage()
+
+ # Storage
+ show_storage()
+
+ # Processes
+ show_running_processes()
+
+ # TODO: Get information from clouds
+
+
+if __name__ == "__main__":
+ main()