summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniil Baturin <daniil@vyos.io>2026-10-14 18:16:45 +0100
committerGitHub <noreply@github.com>2026-10-14 18:16:45 +0100
commite96e646f030f4ee6835b1ebbdca0640f0440f0d0 (patch)
treecc2e505b83991ec6e2652e46d60adc200650d2b4
parentb75c60f0602723122f0f45a7da8d6b45c4765edf (diff)
parent0b43a668ac1fdbc5149616f5065279bbce9a02c8 (diff)
downloadvyos-1x-e96e646f030f4ee6835b1ebbdca0640f0440f0d0.tar.gz
vyos-1x-e96e646f030f4ee6835b1ebbdca0640f0440f0d0.zip
Merge pull request #5478 from jestabro/rdep-interface
T7886: add a general method for verifying interface reverse dependencies
-rw-r--r--interface-definitions/firewall.xml.in2
-rw-r--r--interface-definitions/include/constraint/dependent-error-interface-name.xml.i7
-rw-r--r--interface-definitions/include/constraint/dependent-warning-interface-name.xml.i7
-rw-r--r--interface-definitions/include/dependent-error-generic-interface-multi.xml.i19
-rw-r--r--interface-definitions/include/dependent-error-generic-interface.xml.i18
-rw-r--r--interface-definitions/include/dependent-error-source-interface.xml.i18
-rw-r--r--interface-definitions/include/dependent-warning-generic-interface-multi-broadcast.xml.i19
-rw-r--r--interface-definitions/include/dependent-warning-generic-interface-multi.xml.i19
-rw-r--r--interface-definitions/include/dependent-warning-source-interface.xml.i18
-rw-r--r--interface-definitions/include/interface/dependent-error-inbound-interface.xml.i11
-rw-r--r--interface-definitions/include/interface/vif-s.xml.i2
-rw-r--r--interface-definitions/include/interface/vif.xml.i1
-rw-r--r--interface-definitions/include/isis/protocol-common-config.xml.i1
-rw-r--r--interface-definitions/include/ospf/protocol-common-config.xml.i4
-rw-r--r--interface-definitions/include/ospfv3/protocol-common-config.xml.i4
-rw-r--r--interface-definitions/interfaces_bonding.xml.in1
-rw-r--r--interface-definitions/interfaces_bridge.xml.in1
-rw-r--r--interface-definitions/interfaces_dummy.xml.in1
-rw-r--r--interface-definitions/interfaces_ethernet.xml.in1
-rw-r--r--interface-definitions/interfaces_geneve.xml.in1
-rw-r--r--interface-definitions/interfaces_input.xml.in1
-rw-r--r--interface-definitions/interfaces_l2tpv3.xml.in1
-rw-r--r--interface-definitions/interfaces_macsec.xml.in1
-rw-r--r--interface-definitions/interfaces_openvpn.xml.in1
-rw-r--r--interface-definitions/interfaces_pppoe.xml.in1
-rw-r--r--interface-definitions/interfaces_pseudo-ethernet.xml.in1
-rw-r--r--interface-definitions/interfaces_sstpc.xml.in1
-rw-r--r--interface-definitions/interfaces_tunnel.xml.in1
-rw-r--r--interface-definitions/interfaces_virtual-ethernet.xml.in1
-rw-r--r--interface-definitions/interfaces_vti.xml.in1
-rw-r--r--interface-definitions/interfaces_vxlan.xml.in1
-rw-r--r--interface-definitions/interfaces_wireguard.xml.in1
-rw-r--r--interface-definitions/interfaces_wireless.xml.in1
-rw-r--r--interface-definitions/interfaces_wwan.xml.in1
-rw-r--r--interface-definitions/policy_local-route.xml.in4
-rw-r--r--interface-definitions/protocols_igmp-proxy.xml.in1
-rw-r--r--interface-definitions/protocols_mpls.xml.in2
-rw-r--r--interface-definitions/protocols_pim.xml.in4
-rw-r--r--interface-definitions/protocols_pim6.xml.in4
-rw-r--r--interface-definitions/qos.xml.in4
-rw-r--r--interface-definitions/service_conntrack-sync.xml.in1
-rw-r--r--interface-definitions/service_dhcp-relay.xml.in10
-rw-r--r--interface-definitions/service_ipoe-server.xml.in1
-rw-r--r--interface-definitions/service_mdns_repeater.xml.in2
-rw-r--r--interface-definitions/service_ndp-proxy.xml.in4
-rw-r--r--interface-definitions/service_ntp.xml.in5
-rw-r--r--interface-definitions/service_pppoe-server.xml.in1
-rw-r--r--interface-definitions/system_flow-accounting.xml.in4
-rw-r--r--interface-definitions/system_option.xml.in2
-rw-r--r--python/vyos/configmanager.py128
-rw-r--r--python/vyos/dependentverify.py115
-rw-r--r--python/vyos/referencetree.py9
-rw-r--r--schema/interface_definition.rnc18
-rw-r--r--schema/interface_definition.rng27
54 files changed, 477 insertions, 38 deletions
diff --git a/interface-definitions/firewall.xml.in b/interface-definitions/firewall.xml.in
index 53be2edfa..0ebe6cf69 100644
--- a/interface-definitions/firewall.xml.in
+++ b/interface-definitions/firewall.xml.in
@@ -16,7 +16,7 @@
</properties>
<children>
#include <include/generic-description.xml.i>
- #include <include/generic-interface-multi.xml.i>
+ #include <include/dependent-error-generic-interface-multi.xml.i>
<leafNode name="offload">
<properties>
<help>Offloading method</help>
diff --git a/interface-definitions/include/constraint/dependent-error-interface-name.xml.i b/interface-definitions/include/constraint/dependent-error-interface-name.xml.i
new file mode 100644
index 000000000..ec4d524f4
--- /dev/null
+++ b/interface-definitions/include/constraint/dependent-error-interface-name.xml.i
@@ -0,0 +1,7 @@
+<!-- include start from constraint/dependent-error-interface-name.xml.i -->
+<constraint>
+ <regex>(bond|br|dum|en|ersp|eth|gnv|ifb|ipoe|lan|l2tp|l2tpeth|macsec|peth|ppp|pppoe|pptp|sstp|sstpc|tun|veth|vpptap|vpptun|vti|vtun|vxlan|wg|wlan|wwan)[0-9]+(.\d+)?|pod-[-_a-zA-Z0-9]{1,11}|lo</regex>
+ <validator name="interface-exists"/>
+</constraint>
+<dependency kind="interface" alert="error"/>
+<!-- include end -->
diff --git a/interface-definitions/include/constraint/dependent-warning-interface-name.xml.i b/interface-definitions/include/constraint/dependent-warning-interface-name.xml.i
new file mode 100644
index 000000000..bc646c3c9
--- /dev/null
+++ b/interface-definitions/include/constraint/dependent-warning-interface-name.xml.i
@@ -0,0 +1,7 @@
+<!-- include start from constraint/dependent-warning-interface-name.xml.i -->
+<constraint>
+ <regex>(bond|br|dum|en|ersp|eth|gnv|ifb|ipoe|lan|l2tp|l2tpeth|macsec|peth|ppp|pppoe|pptp|sstp|sstpc|tun|veth|vpptap|vpptun|vti|vtun|vxlan|wg|wlan|wwan)[0-9]+(.\d+)?|pod-[-_a-zA-Z0-9]{1,11}|lo</regex>
+ <validator name="interface-exists"/>
+</constraint>
+<dependency kind="interface" alert="warning"/>
+<!-- include end -->
diff --git a/interface-definitions/include/dependent-error-generic-interface-multi.xml.i b/interface-definitions/include/dependent-error-generic-interface-multi.xml.i
new file mode 100644
index 000000000..c5dd26267
--- /dev/null
+++ b/interface-definitions/include/dependent-error-generic-interface-multi.xml.i
@@ -0,0 +1,19 @@
+<!-- include start from dependent-error-generic-interface-multi.xml.i -->
+<leafNode name="interface">
+ <properties>
+ <help>Interface</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces</script>
+ </completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Interface name</description>
+ </valueHelp>
+ <constraint>
+ #include <include/constraint/interface-name.xml.i>
+ </constraint>
+ <multi/>
+ <dependency kind="interface" alert="error"/>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/dependent-error-generic-interface.xml.i b/interface-definitions/include/dependent-error-generic-interface.xml.i
new file mode 100644
index 000000000..c48e728c8
--- /dev/null
+++ b/interface-definitions/include/dependent-error-generic-interface.xml.i
@@ -0,0 +1,18 @@
+<!-- include start from dependent-error-generic-interface.xml.i -->
+<leafNode name="interface">
+ <properties>
+ <help>Interface</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces</script>
+ </completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Interface name</description>
+ </valueHelp>
+ <constraint>
+ #include <include/constraint/interface-name.xml.i>
+ </constraint>
+ <dependency kind="interface" alert="error"/>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/dependent-error-source-interface.xml.i b/interface-definitions/include/dependent-error-source-interface.xml.i
new file mode 100644
index 000000000..b3c23f64e
--- /dev/null
+++ b/interface-definitions/include/dependent-error-source-interface.xml.i
@@ -0,0 +1,18 @@
+<!-- include start from dependent-error-source-interface.xml.i -->
+<leafNode name="source-interface">
+ <properties>
+ <help>Interface used to establish connection</help>
+ <valueHelp>
+ <format>interface</format>
+ <description>Interface name</description>
+ </valueHelp>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces</script>
+ </completionHelp>
+ <constraint>
+ #include <include/constraint/interface-name.xml.i>
+ </constraint>
+ <dependency kind="interface" alert="error"/>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/dependent-warning-generic-interface-multi-broadcast.xml.i b/interface-definitions/include/dependent-warning-generic-interface-multi-broadcast.xml.i
new file mode 100644
index 000000000..22f6b6552
--- /dev/null
+++ b/interface-definitions/include/dependent-warning-generic-interface-multi-broadcast.xml.i
@@ -0,0 +1,19 @@
+<!-- include start from dependent-warning-generic-interface-multi-broadcast.xml.i -->
+<leafNode name="interface">
+ <properties>
+ <help>Interface</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces --broadcast</script>
+ </completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Interface name</description>
+ </valueHelp>
+ <constraint>
+ #include <include/constraint/interface-name.xml.i>
+ </constraint>
+ <multi/>
+ <dependency kind="interface" alert="warning"/>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/dependent-warning-generic-interface-multi.xml.i b/interface-definitions/include/dependent-warning-generic-interface-multi.xml.i
new file mode 100644
index 000000000..bd4b9ea93
--- /dev/null
+++ b/interface-definitions/include/dependent-warning-generic-interface-multi.xml.i
@@ -0,0 +1,19 @@
+<!-- include start from dependent-warning-generic-interface-multi.xml.i -->
+<leafNode name="interface">
+ <properties>
+ <help>Interface</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces</script>
+ </completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Interface name</description>
+ </valueHelp>
+ <constraint>
+ #include <include/constraint/interface-name.xml.i>
+ </constraint>
+ <multi/>
+ <dependency kind="interface" alert="warning"/>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/dependent-warning-source-interface.xml.i b/interface-definitions/include/dependent-warning-source-interface.xml.i
new file mode 100644
index 000000000..164135f2f
--- /dev/null
+++ b/interface-definitions/include/dependent-warning-source-interface.xml.i
@@ -0,0 +1,18 @@
+<!-- include start from dependent-warning-source-interface.xml.i -->
+<leafNode name="source-interface">
+ <properties>
+ <help>Interface used to establish connection</help>
+ <valueHelp>
+ <format>interface</format>
+ <description>Interface name</description>
+ </valueHelp>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces</script>
+ </completionHelp>
+ <constraint>
+ #include <include/constraint/interface-name.xml.i>
+ </constraint>
+ <dependency kind="interface" alert="warning"/>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/interface/dependent-error-inbound-interface.xml.i b/interface-definitions/include/interface/dependent-error-inbound-interface.xml.i
new file mode 100644
index 000000000..e1c79feb0
--- /dev/null
+++ b/interface-definitions/include/interface/dependent-error-inbound-interface.xml.i
@@ -0,0 +1,11 @@
+<!-- include start from interface/dependent-error-inbound-interface.xml.i -->
+<leafNode name="inbound-interface">
+ <properties>
+ <help>Inbound Interface</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces</script>
+ </completionHelp>
+ <dependency kind="interface" alert="error"/>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/interface/vif-s.xml.i b/interface-definitions/include/interface/vif-s.xml.i
index 65ca10207..e07a9bf8a 100644
--- a/interface-definitions/include/interface/vif-s.xml.i
+++ b/interface-definitions/include/interface/vif-s.xml.i
@@ -10,6 +10,7 @@
<validator name="numeric" argument="--range 0-4094"/>
</constraint>
<constraintErrorMessage>VLAN ID must be between 0 and 4094</constraintErrorMessage>
+ <kind>interface</kind>
</properties>
<children>
#include <include/generic-description.xml.i>
@@ -32,6 +33,7 @@
<validator name="numeric" argument="--range 0-4094"/>
</constraint>
<constraintErrorMessage>VLAN ID must be between 0 and 4094</constraintErrorMessage>
+ <kind>interface</kind>
</properties>
<children>
#include <include/generic-description.xml.i>
diff --git a/interface-definitions/include/interface/vif.xml.i b/interface-definitions/include/interface/vif.xml.i
index 87f91c5ce..e9b9385f1 100644
--- a/interface-definitions/include/interface/vif.xml.i
+++ b/interface-definitions/include/interface/vif.xml.i
@@ -10,6 +10,7 @@
<validator name="numeric" argument="--range 0-4094"/>
</constraint>
<constraintErrorMessage>VLAN ID must be between 0 and 4094</constraintErrorMessage>
+ <kind>interface</kind>
</properties>
<children>
#include <include/generic-description.xml.i>
diff --git a/interface-definitions/include/isis/protocol-common-config.xml.i b/interface-definitions/include/isis/protocol-common-config.xml.i
index 6a7388c99..d0424ea4f 100644
--- a/interface-definitions/include/isis/protocol-common-config.xml.i
+++ b/interface-definitions/include/isis/protocol-common-config.xml.i
@@ -719,6 +719,7 @@
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
+ <dependency kind="interface" alert="error"/>
</properties>
<children>
#include <include/bfd/bfd.xml.i>
diff --git a/interface-definitions/include/ospf/protocol-common-config.xml.i b/interface-definitions/include/ospf/protocol-common-config.xml.i
index 93d718ed4..caef8abb4 100644
--- a/interface-definitions/include/ospf/protocol-common-config.xml.i
+++ b/interface-definitions/include/ospf/protocol-common-config.xml.i
@@ -406,9 +406,7 @@
<format>txt</format>
<description>Interface name</description>
</valueHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
+ #include <include/constraint/dependent-error-interface-name.xml.i>
</properties>
<children>
<leafNode name="area">
diff --git a/interface-definitions/include/ospfv3/protocol-common-config.xml.i b/interface-definitions/include/ospfv3/protocol-common-config.xml.i
index 72fb86d3d..e6d3b23b8 100644
--- a/interface-definitions/include/ospfv3/protocol-common-config.xml.i
+++ b/interface-definitions/include/ospfv3/protocol-common-config.xml.i
@@ -132,9 +132,7 @@
<format>txt</format>
<description>Interface used for routing information exchange</description>
</valueHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
+ #include <include/constraint/dependent-error-interface-name.xml.i>
</properties>
<children>
<leafNode name="area">
diff --git a/interface-definitions/interfaces_bonding.xml.in b/interface-definitions/interfaces_bonding.xml.in
index 9945fc15d..6eca96fb1 100644
--- a/interface-definitions/interfaces_bonding.xml.in
+++ b/interface-definitions/interfaces_bonding.xml.in
@@ -14,6 +14,7 @@
<format>bondN</format>
<description>Bonding interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6-dhcp.xml.i>
diff --git a/interface-definitions/interfaces_bridge.xml.in b/interface-definitions/interfaces_bridge.xml.in
index d4ee2a652..b2b08659a 100644
--- a/interface-definitions/interfaces_bridge.xml.in
+++ b/interface-definitions/interfaces_bridge.xml.in
@@ -14,6 +14,7 @@
<format>brN</format>
<description>Bridge interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6-dhcp.xml.i>
diff --git a/interface-definitions/interfaces_dummy.xml.in b/interface-definitions/interfaces_dummy.xml.in
index 993380ab8..9f4856845 100644
--- a/interface-definitions/interfaces_dummy.xml.in
+++ b/interface-definitions/interfaces_dummy.xml.in
@@ -14,6 +14,7 @@
<format>dumN</format>
<description>Dummy interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6.xml.i>
diff --git a/interface-definitions/interfaces_ethernet.xml.in b/interface-definitions/interfaces_ethernet.xml.in
index e110bd48f..466c0c8e4 100644
--- a/interface-definitions/interfaces_ethernet.xml.in
+++ b/interface-definitions/interfaces_ethernet.xml.in
@@ -17,6 +17,7 @@
<regex>((eth|lan)[0-9]+|(eno|ens|enp|enx).+)</regex>
</constraint>
<constraintErrorMessage>Invalid Ethernet interface name</constraintErrorMessage>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6-dhcp.xml.i>
diff --git a/interface-definitions/interfaces_geneve.xml.in b/interface-definitions/interfaces_geneve.xml.in
index b85bd3b9e..385d15250 100644
--- a/interface-definitions/interfaces_geneve.xml.in
+++ b/interface-definitions/interfaces_geneve.xml.in
@@ -14,6 +14,7 @@
<format>gnvN</format>
<description>GENEVE interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6.xml.i>
diff --git a/interface-definitions/interfaces_input.xml.in b/interface-definitions/interfaces_input.xml.in
index 771c47e42..8ca45053a 100644
--- a/interface-definitions/interfaces_input.xml.in
+++ b/interface-definitions/interfaces_input.xml.in
@@ -15,6 +15,7 @@
<format>ifbN</format>
<description>Input interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/generic-description.xml.i>
diff --git a/interface-definitions/interfaces_l2tpv3.xml.in b/interface-definitions/interfaces_l2tpv3.xml.in
index 381e86bd0..3f6d77ad8 100644
--- a/interface-definitions/interfaces_l2tpv3.xml.in
+++ b/interface-definitions/interfaces_l2tpv3.xml.in
@@ -14,6 +14,7 @@
<format>l2tpethN</format>
<description>L2TPv3 interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6.xml.i>
diff --git a/interface-definitions/interfaces_macsec.xml.in b/interface-definitions/interfaces_macsec.xml.in
index 5279a9495..3ece4d777 100644
--- a/interface-definitions/interfaces_macsec.xml.in
+++ b/interface-definitions/interfaces_macsec.xml.in
@@ -14,6 +14,7 @@
<format>macsecN</format>
<description>MACsec interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6-dhcp.xml.i>
diff --git a/interface-definitions/interfaces_openvpn.xml.in b/interface-definitions/interfaces_openvpn.xml.in
index ff16a5610..f0bf1db9c 100644
--- a/interface-definitions/interfaces_openvpn.xml.in
+++ b/interface-definitions/interfaces_openvpn.xml.in
@@ -14,6 +14,7 @@
<format>vtunN</format>
<description>OpenVPN interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/authentication.xml.i>
diff --git a/interface-definitions/interfaces_pppoe.xml.in b/interface-definitions/interfaces_pppoe.xml.in
index d38074b41..37067aefc 100644
--- a/interface-definitions/interfaces_pppoe.xml.in
+++ b/interface-definitions/interfaces_pppoe.xml.in
@@ -14,6 +14,7 @@
<format>pppoeN</format>
<description>PPPoE dialer interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
<leafNode name="address">
diff --git a/interface-definitions/interfaces_pseudo-ethernet.xml.in b/interface-definitions/interfaces_pseudo-ethernet.xml.in
index 5687e3556..72e0fcf80 100644
--- a/interface-definitions/interfaces_pseudo-ethernet.xml.in
+++ b/interface-definitions/interfaces_pseudo-ethernet.xml.in
@@ -14,6 +14,7 @@
<format>pethN</format>
<description>Pseudo Ethernet interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6-dhcp.xml.i>
diff --git a/interface-definitions/interfaces_sstpc.xml.in b/interface-definitions/interfaces_sstpc.xml.in
index b7c49446f..418901a66 100644
--- a/interface-definitions/interfaces_sstpc.xml.in
+++ b/interface-definitions/interfaces_sstpc.xml.in
@@ -14,6 +14,7 @@
<format>sstpcN</format>
<description>Secure Socket Tunneling Protocol interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/generic-description.xml.i>
diff --git a/interface-definitions/interfaces_tunnel.xml.in b/interface-definitions/interfaces_tunnel.xml.in
index 74849be5d..eb97e2b4c 100644
--- a/interface-definitions/interfaces_tunnel.xml.in
+++ b/interface-definitions/interfaces_tunnel.xml.in
@@ -14,6 +14,7 @@
<format>tunN</format>
<description>Tunnel interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/generic-description.xml.i>
diff --git a/interface-definitions/interfaces_virtual-ethernet.xml.in b/interface-definitions/interfaces_virtual-ethernet.xml.in
index 1559a6038..37631e312 100644
--- a/interface-definitions/interfaces_virtual-ethernet.xml.in
+++ b/interface-definitions/interfaces_virtual-ethernet.xml.in
@@ -14,6 +14,7 @@
<format>vethN</format>
<description>Virtual Ethernet interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6-dhcp.xml.i>
diff --git a/interface-definitions/interfaces_vti.xml.in b/interface-definitions/interfaces_vti.xml.in
index 39fb3131e..b472ac9b1 100644
--- a/interface-definitions/interfaces_vti.xml.in
+++ b/interface-definitions/interfaces_vti.xml.in
@@ -14,6 +14,7 @@
<format>vtiN</format>
<description>VTI interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6.xml.i>
diff --git a/interface-definitions/interfaces_vxlan.xml.in b/interface-definitions/interfaces_vxlan.xml.in
index 7f71dca34..55924edc0 100644
--- a/interface-definitions/interfaces_vxlan.xml.in
+++ b/interface-definitions/interfaces_vxlan.xml.in
@@ -14,6 +14,7 @@
<format>vxlanN</format>
<description>VXLAN interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6.xml.i>
diff --git a/interface-definitions/interfaces_wireguard.xml.in b/interface-definitions/interfaces_wireguard.xml.in
index 33cb5864a..d22230de4 100644
--- a/interface-definitions/interfaces_wireguard.xml.in
+++ b/interface-definitions/interfaces_wireguard.xml.in
@@ -14,6 +14,7 @@
<format>wgN</format>
<description>WireGuard interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6.xml.i>
diff --git a/interface-definitions/interfaces_wireless.xml.in b/interface-definitions/interfaces_wireless.xml.in
index 1b5356caa..ec1817585 100644
--- a/interface-definitions/interfaces_wireless.xml.in
+++ b/interface-definitions/interfaces_wireless.xml.in
@@ -17,6 +17,7 @@
<format>wlanN</format>
<description>Wireless (WiFi/WLAN) interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6-dhcp.xml.i>
diff --git a/interface-definitions/interfaces_wwan.xml.in b/interface-definitions/interfaces_wwan.xml.in
index 552806d4e..7763cc704 100644
--- a/interface-definitions/interfaces_wwan.xml.in
+++ b/interface-definitions/interfaces_wwan.xml.in
@@ -17,6 +17,7 @@
<format>wwanN</format>
<description>Wireless Wide Area Network interface name</description>
</valueHelp>
+ <kind>interface</kind>
</properties>
<children>
#include <include/interface/address-ipv4-ipv6-dhcp.xml.i>
diff --git a/interface-definitions/policy_local-route.xml.in b/interface-definitions/policy_local-route.xml.in
index 9f6588db8..fed3a8edc 100644
--- a/interface-definitions/policy_local-route.xml.in
+++ b/interface-definitions/policy_local-route.xml.in
@@ -73,7 +73,7 @@
#include <include/port-number.xml.i>
</children>
</node>
- #include <include/interface/inbound-interface.xml.i>
+ #include <include/interface/dependent-error-inbound-interface.xml.i>
</children>
</tagNode>
</children>
@@ -148,7 +148,7 @@
#include <include/port-number.xml.i>
</children>
</node>
- #include <include/interface/inbound-interface.xml.i>
+ #include <include/interface/dependent-error-inbound-interface.xml.i>
</children>
</tagNode>
</children>
diff --git a/interface-definitions/protocols_igmp-proxy.xml.in b/interface-definitions/protocols_igmp-proxy.xml.in
index a1deeb3fc..65a5cf3c7 100644
--- a/interface-definitions/protocols_igmp-proxy.xml.in
+++ b/interface-definitions/protocols_igmp-proxy.xml.in
@@ -22,6 +22,7 @@
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
+ <dependency kind="interface" alert="error"/>
</properties>
<children>
<leafNode name="alt-subnet">
diff --git a/interface-definitions/protocols_mpls.xml.in b/interface-definitions/protocols_mpls.xml.in
index fc1864f38..b904a0740 100644
--- a/interface-definitions/protocols_mpls.xml.in
+++ b/interface-definitions/protocols_mpls.xml.in
@@ -574,7 +574,7 @@
</leafNode>
</children>
</node>
- #include <include/generic-interface-multi.xml.i>
+ #include <include/dependent-error-generic-interface-multi.xml.i>
</children>
</node>
</children>
diff --git a/interface-definitions/protocols_pim.xml.in b/interface-definitions/protocols_pim.xml.in
index 4a20c0d9b..3de986545 100644
--- a/interface-definitions/protocols_pim.xml.in
+++ b/interface-definitions/protocols_pim.xml.in
@@ -15,9 +15,7 @@
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
+ #include <include/constraint/dependent-error-interface-name.xml.i>
</properties>
<children>
#include <include/bfd/bfd.xml.i>
diff --git a/interface-definitions/protocols_pim6.xml.in b/interface-definitions/protocols_pim6.xml.in
index 8bd3f3fee..0d6d4d1b6 100644
--- a/interface-definitions/protocols_pim6.xml.in
+++ b/interface-definitions/protocols_pim6.xml.in
@@ -15,9 +15,7 @@
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
+ #include <include/constraint/dependent-error-interface-name.xml.i>
</properties>
<children>
#include <include/pim/bsm.xml.i>
diff --git a/interface-definitions/qos.xml.in b/interface-definitions/qos.xml.in
index aad1de629..5f3e76c2c 100644
--- a/interface-definitions/qos.xml.in
+++ b/interface-definitions/qos.xml.in
@@ -16,9 +16,7 @@
<format>txt</format>
<description>Interface name</description>
</valueHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
+ #include <include/constraint/dependent-warning-interface-name.xml.i>
</properties>
<children>
<leafNode name="ingress">
diff --git a/interface-definitions/service_conntrack-sync.xml.in b/interface-definitions/service_conntrack-sync.xml.in
index 9483c809b..56faa4a59 100644
--- a/interface-definitions/service_conntrack-sync.xml.in
+++ b/interface-definitions/service_conntrack-sync.xml.in
@@ -141,6 +141,7 @@
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces --bridgeable</script>
</completionHelp>
+ <dependency kind="interface" alert="error"/>
</properties>
<children>
<leafNode name="peer">
diff --git a/interface-definitions/service_dhcp-relay.xml.in b/interface-definitions/service_dhcp-relay.xml.in
index 9fdd9581d..0fbb75598 100644
--- a/interface-definitions/service_dhcp-relay.xml.in
+++ b/interface-definitions/service_dhcp-relay.xml.in
@@ -10,7 +10,7 @@
</properties>
<children>
#include <include/generic-disable-node.xml.i>
- #include <include/generic-interface-multi-broadcast.xml.i>
+ #include <include/dependent-warning-generic-interface-multi-broadcast.xml.i>
<leafNode name="listen-interface">
<properties>
<help>Interface for DHCP Relay Agent to listen for requests</help>
@@ -21,9 +21,7 @@
<format>txt</format>
<description>Interface name</description>
</valueHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
+ #include <include/constraint/dependent-warning-interface-name.xml.i>
<multi/>
</properties>
</leafNode>
@@ -37,9 +35,7 @@
<format>txt</format>
<description>Interface name</description>
</valueHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
+ #include <include/constraint/dependent-warning-interface-name.xml.i>
<multi/>
</properties>
</leafNode>
diff --git a/interface-definitions/service_ipoe-server.xml.in b/interface-definitions/service_ipoe-server.xml.in
index 27b163001..f3a7e1e3c 100644
--- a/interface-definitions/service_ipoe-server.xml.in
+++ b/interface-definitions/service_ipoe-server.xml.in
@@ -90,6 +90,7 @@
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
+ <dependency kind="interface" alert="warning"/>
</properties>
<children>
<leafNode name="mode">
diff --git a/interface-definitions/service_mdns_repeater.xml.in b/interface-definitions/service_mdns_repeater.xml.in
index 9d626bf6a..0cdb45db3 100644
--- a/interface-definitions/service_mdns_repeater.xml.in
+++ b/interface-definitions/service_mdns_repeater.xml.in
@@ -14,7 +14,7 @@
</properties>
<children>
#include <include/generic-disable-node.xml.i>
- #include <include/generic-interface-multi.xml.i>
+ #include <include/dependent-error-generic-interface-multi.xml.i>
<leafNode name="ip-version">
<properties>
<help>IP address version to use</help>
diff --git a/interface-definitions/service_ndp-proxy.xml.in b/interface-definitions/service_ndp-proxy.xml.in
index 327ce89d5..a35457991 100644
--- a/interface-definitions/service_ndp-proxy.xml.in
+++ b/interface-definitions/service_ndp-proxy.xml.in
@@ -28,9 +28,7 @@
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
- <constraint>
- #include <include/constraint/interface-name.xml.i>
- </constraint>
+ #include <include/constraint/dependent-error-interface-name.xml.i>
</properties>
<children>
#include <include/generic-disable-node.xml.i>
diff --git a/interface-definitions/service_ntp.xml.in b/interface-definitions/service_ntp.xml.in
index 216722715..f85b5715b 100644
--- a/interface-definitions/service_ntp.xml.in
+++ b/interface-definitions/service_ntp.xml.in
@@ -10,10 +10,10 @@
</properties>
<children>
#include <include/allow-client.xml.i>
- #include <include/generic-interface.xml.i>
+ #include <include/dependent-error-generic-interface.xml.i>
#include <include/listen-address.xml.i>
#include <include/source-address-ipv4-ipv6-multi.xml.i>
- #include <include/source-interface.xml.i>
+ #include <include/dependent-error-source-interface.xml.i>
#include <include/interface/vrf.xml.i>
<node name="timestamp">
<properties>
@@ -39,6 +39,7 @@
#include <include/constraint/interface-name.xml.i>
<regex>all</regex>
</constraint>
+ <dependency kind="interface" alert="error"/>
</properties>
<children>
<leafNode name="receive-filter">
diff --git a/interface-definitions/service_pppoe-server.xml.in b/interface-definitions/service_pppoe-server.xml.in
index 81a4a95e3..06f4225a6 100644
--- a/interface-definitions/service_pppoe-server.xml.in
+++ b/interface-definitions/service_pppoe-server.xml.in
@@ -61,6 +61,7 @@
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
+ <dependency kind="interface" alert="warning"/>
</properties>
<children>
<leafNode name="combined">
diff --git a/interface-definitions/system_flow-accounting.xml.in b/interface-definitions/system_flow-accounting.xml.in
index 53436036e..c340fccd6 100644
--- a/interface-definitions/system_flow-accounting.xml.in
+++ b/interface-definitions/system_flow-accounting.xml.in
@@ -20,7 +20,7 @@
<help>NetFlow settings</help>
</properties>
<children>
- #include <include/generic-interface-multi.xml.i>
+ #include <include/dependent-warning-generic-interface-multi.xml.i>
<leafNode name="engine-id">
<properties>
<help>NetFlow engine-id</help>
@@ -112,7 +112,7 @@
<defaultValue>2055</defaultValue>
</leafNode>
#include <include/source-address-ipv4-ipv6.xml.i>
- #include <include/source-interface.xml.i>
+ #include <include/dependent-warning-source-interface.xml.i>
</children>
</tagNode>
<leafNode name="inactive-timeout">
diff --git a/interface-definitions/system_option.xml.in b/interface-definitions/system_option.xml.in
index c295b2ebe..3bc58155c 100644
--- a/interface-definitions/system_option.xml.in
+++ b/interface-definitions/system_option.xml.in
@@ -381,7 +381,7 @@
<help>Global options used for HTTP client</help>
</properties>
<children>
- #include <include/source-interface.xml.i>
+ #include <include/dependent-error-source-interface.xml.i>
#include <include/source-address-ipv4-ipv6.xml.i>
</children>
</node>
diff --git a/python/vyos/configmanager.py b/python/vyos/configmanager.py
index 46bff08b0..69d40e5ef 100644
--- a/python/vyos/configmanager.py
+++ b/python/vyos/configmanager.py
@@ -13,7 +13,9 @@
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
-import json
+
+import json # noqa: I001
+import logging
from types import ModuleType
from dataclasses import dataclass
@@ -23,9 +25,26 @@ from pathlib import Path
from vyos.config import Config
from vyos.config import ConfigDict
from vyos.configtree import ConfigTree
+from vyos.configtree import DiffTree
from vyos.referencetree import ReferenceTree
+from vyos.dependentverify import removed_dependency_value_paths_of_kind
+from vyos.dependentverify import dependent_value_paths_of_kind
+from vyos.dependentverify import concatenate_vif
+
from vyos.utils.system import load_as_module
from vyos.defaults import directories
+from vyos.base import Warning as Warn
+from vyos import ConfigError
+
+LOG = logging.getLogger(Path(__file__).stem)
+handler = logging.StreamHandler()
+formatter = logging.Formatter('(%(name)s): %(message)s')
+handler.setFormatter(formatter)
+LOG.addHandler(handler)
+
+debug = False
+
+_ = LOG.setLevel(logging.DEBUG) if debug else LOG.setLevel(logging.INFO)
@dataclass
@@ -38,6 +57,8 @@ class ConfigDictCache:
class Component:
module: ModuleType
name: str
+ rdep_error: list = field(default_factory=list)
+ rdep_warning: list = field(default_factory=list)
cache: ConfigDictCache = None
@@ -54,6 +75,7 @@ class ConfigManager:
self.config: Config = None
self.running_config: ConfigTree = None
self.session_config: ConfigTree = None
+ self.diff_tree: DiffTree = None
self.components = self.init_components()
@@ -92,14 +114,111 @@ class ConfigManager:
if config is None:
self.running_config = None
self.session_config = None
+ self.diff_tree = None
else:
self.running_config = config.get_config_tree(effective=True)
self.session_config = config.get_config_tree()
- setattr(config, 'manager', self)
+ self.diff_tree = DiffTree(self.running_config, self.session_config)
if self.cache_config:
self.clear_cache()
+ self.clear_rdep()
+
+ if config is None:
+ return
+
+ self.init_rdep()
+
+ def init_rdep(self):
+ # pylint: disable=too-many-locals,too-many-branches
+ """
+ Schema definition for reverse dependency alert:
+ alertAttr = attribute alert
+ {
+ "error" | "warning"
+ }
+
+ We are currently only considering reverse dependencies for type
+ (kind) 'interface'. Extension for other kinds may be added here.
+
+ The reference tree utils return data of the form outlined below. In
+ all cases, the input path is a reference tree path, and consequently
+ may define a subtree of the config (due to intermediary tag node);
+ thus the return values are lists of (tuples including) actual config
+ paths.
+
+ removed_dependency_value_paths: list[tuple[list(values), path]]
+ are the values for each path defined by the XML paths of kind
+ 'interface', which are to be removed in the current commit session.
+
+ dependent_value_paths: dict[alert: list[tuple[list(values), path]]]
+ are the (values, path) defined by all XML dependency annotations
+ existing in the session tree, indexed by alert type.
+
+ The dependent_value_paths are cross-referenced with the interface
+ values scheduled for deletion in removed_dependency_value_paths, and
+ the corresponding alert raised in the configmanager verify stage.
+ """
+ removed_dependency_value_paths = removed_dependency_value_paths_of_kind(
+ 'interface', self.reference_tree, self.session_config, self.diff_tree
+ )
+
+ removed_dependency_value_paths, orig_value = concatenate_vif(
+ self.reference_tree, removed_dependency_value_paths
+ )
+
+ LOG.debug(f'removed_dependency_value_paths: {removed_dependency_value_paths}')
+
+ if not removed_dependency_value_paths:
+ return
+
+ dependent_value_paths = dependent_value_paths_of_kind(
+ 'interface', self.reference_tree, self.session_config
+ )
+
+ LOG.debug(f'dependent_value_paths: {dependent_value_paths}')
+
+ if not dependent_value_paths:
+ return
+
+ for vals, path in removed_dependency_value_paths:
+ rpath = self.reference_tree.reference_path_from_config_path(path)
+ owner = self.reference_tree.get_owner(rpath)
+ if owner is None:
+ LOG.error(f'Path {path} has no owner')
+ continue
+ component_name = Path(owner).stem
+ component = self.components.get(component_name)
+ LOG.debug(f'owner: {component_name}')
+
+ errors = dependent_value_paths.get('error', [])
+ rdep_err = component.rdep_error
+ for dependent_vals, dependent_path in errors:
+ for v in set(vals) & set(dependent_vals):
+ ov = orig_value.get(v, v)
+ path_str = ' '.join(path + [ov])
+ dpath_str = ' '.join(dependent_path)
+ rdep_err.append(
+ f'\nNode:\n "{path_str}"\nis required by:\n "{dpath_str}"\n'
+ )
+
+ warnings = dependent_value_paths.get('warning', [])
+ rdep_warn = component.rdep_warning
+ for dependent_vals, dependent_path in warnings:
+ for v in set(vals) & set(dependent_vals):
+ ov = orig_value.get(v, v)
+ path_str = ' '.join(path + [ov])
+ dpath_str = ' '.join(dependent_path)
+ rdep_warn.append(
+ f'removed node:\n "{path_str}"\nis referenced by:\n "{dpath_str}"\n'
+ )
+
+ def clear_rdep(self):
+ for component in self.components.values():
+ component.rdep_error = []
+ component.rdep_warning = []
+
def clear_cache(self):
for component in self.components.values():
component.cache = None
@@ -121,6 +240,11 @@ class ConfigManager:
component = self.components[script_name]
mod = component.module
+ if errors := component.rdep_error:
+ raise ConfigError('\n'.join(errors))
+ if warnings := component.rdep_warning:
+ Warn('\n'.join(warnings))
+
mod.verify(config_dict)
def generate(self, script_name: str, config_dict: ConfigDict) -> None:
diff --git a/python/vyos/dependentverify.py b/python/vyos/dependentverify.py
new file mode 100644
index 000000000..1e22b65a0
--- /dev/null
+++ b/python/vyos/dependentverify.py
@@ -0,0 +1,115 @@
+# Copyright (C) VyOS Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+
+from vyos.configtree import ConfigTree # noqa: I001
+from vyos.configtree import DiffTree
+from vyos.configtree import subtree_values_of_path
+from vyos.referencetree import ReferenceTree
+from vyos.base import Warning as Warn
+
+
+def removed_dependency_value_paths_of_kind(
+ kind: str,
+ reference_tree: ReferenceTree,
+ session_tree: ConfigTree,
+ diff_tree: DiffTree,
+):
+ paths = reference_tree.get_nodes_of_kind(kind)
+ value_paths = []
+ for path in paths:
+ path_vals = subtree_values_of_path(diff_tree.sub, path, reference_tree)
+ path_vals = [t for t in path_vals if t != ([], [])]
+ for vlst, p in path_vals:
+ vals = list(
+ filter(
+ lambda v, cur_p=p: not session_tree.exists(cur_p + [v]),
+ vlst,
+ )
+ )
+ if vals:
+ value_paths.append((vals, p))
+
+ return value_paths
+
+
+def dependent_value_paths_of_kind(
+ kind: str,
+ reference_tree: ReferenceTree,
+ session_tree: ConfigTree,
+):
+ dependent_data = reference_tree.get_rdeps_of_kind_data(kind)
+
+ dependent_value_paths = {}
+ for p, a in dependent_data:
+ path_vals = subtree_values_of_path(session_tree, p, reference_tree)
+ path_vals = [t for t in path_vals if t != ([], [])]
+ if path_vals:
+ lst = dependent_value_paths.setdefault(a, [])
+ lst.extend(path_vals)
+
+ return dependent_value_paths
+
+
+vif_refpath = [
+ ['interfaces', 'ethernet', 'vif'],
+ ['interfaces', 'ethernet', 'vif-s'],
+ ['interfaces', 'ethernet', 'vif-s', 'vif-c'],
+ ['interfaces', 'bonding', 'vif'],
+ ['interfaces', 'bonding', 'vif-s'],
+ ['interfaces', 'bonding', 'vif-s', 'vif-c'],
+ ['interfaces', 'bridge', 'vif'],
+ ['interfaces', 'pseudo-ethernet', 'vif'],
+ ['interfaces', 'pseudo-ethernet', 'vif-s'],
+ ['interfaces', 'pseudo-ethernet', 'vif-s', 'vif-c'],
+ ['interfaces', 'virtual-ethernet', 'vif'],
+ ['interfaces', 'virtual-ethernet', 'vif-s'],
+ ['interfaces', 'virtual-ethernet', 'vif-s', 'vif-c'],
+ ['interfaces', 'wireless', 'vif'],
+ ['interfaces', 'wireless', 'vif-s'],
+ ['interfaces', 'wireless', 'vif-s', 'vif-c'],
+]
+
+
+def check_vif_path(reference_tree: ReferenceTree):
+ for p in vif_refpath:
+ if not reference_tree.exists(p):
+ Warn(f'Out of date reference path: {p}')
+
+
+def concatenate_vif(reference_tree: ReferenceTree, value_paths):
+ check_vif_path(reference_tree)
+ revised = []
+ orig_value = {}
+ for vp in value_paths:
+ refpath = reference_tree.reference_path_from_config_path(vp[1])
+ if refpath not in vif_refpath:
+ revised.append(vp)
+ else:
+ p = vp[1]
+ match p[-1]:
+ case 'vif':
+ rev_vals = [p[2] + '.' + v for v in vp[0]]
+ orig_value |= dict(zip(rev_vals, vp[0]))
+ revised.append((rev_vals, vp[1]))
+ case 'vif-s':
+ rev_vals = [p[2] + '.' + v for v in vp[0]]
+ orig_value |= dict(zip(rev_vals, vp[0]))
+ revised.append((rev_vals, vp[1]))
+ case 'vif-c':
+ rev_vals = [p[2] + '.' + p[4] + '.' + v for v in vp[0]]
+ orig_value |= dict(zip(rev_vals, vp[0]))
+ revised.append((rev_vals, vp[1]))
+ return revised, orig_value
diff --git a/python/vyos/referencetree.py b/python/vyos/referencetree.py
index 0cd969762..24e8da1ec 100644
--- a/python/vyos/referencetree.py
+++ b/python/vyos/referencetree.py
@@ -71,7 +71,14 @@ class ReferenceTree:
return bool(res)
def get_owner(self, path):
- return self.__lib.get_owner(self.__pointer, path.encode()).decode()
+ check_path(path)
+ path_str = ' '.join(map(str, path)).encode()
+
+ owner = self.__lib.get_owner(self.__pointer, path_str)
+ if not owner:
+ return None
+
+ return owner.decode()
def get_multi_nodes(self, tag_value_placeholder='', as_tuple=False):
import json
diff --git a/schema/interface_definition.rnc b/schema/interface_definition.rnc
index 0c929ad2c..faa0c4f03 100644
--- a/schema/interface_definition.rnc
+++ b/schema/interface_definition.rnc
@@ -99,6 +99,9 @@ properties = element properties
(element constraintSilenceOutput { empty })? &
completionHelp* &
+ (element kind { text })* &
+ dependency? &
+
# "docs" is used to store documentation for a node in a structured format
# It is used to generate documentation for the CLI and Web docs
(element docs {
@@ -197,3 +200,18 @@ completionHelp = element completionHelp
(element path { text })* &
(element script { text })*
}
+
+dependency = element dependency
+{
+ kindAttr & alertAttr
+}
+
+kindAttr = attribute kind
+{
+ text
+}
+
+alertAttr = attribute alert
+{
+ "error" | "warning"
+}
diff --git a/schema/interface_definition.rng b/schema/interface_definition.rng
index 2c46266d3..0398d749b 100644
--- a/schema/interface_definition.rng
+++ b/schema/interface_definition.rng
@@ -182,6 +182,14 @@
<zeroOrMore>
<ref name="completionHelp"/>
</zeroOrMore>
+ <zeroOrMore>
+ <element name="kind">
+ <text/>
+ </element>
+ </zeroOrMore>
+ <optional>
+ <ref name="dependency"/>
+ </optional>
<optional>
<!--
"docs" is used to store documentation for a node in a structured format
@@ -366,4 +374,23 @@
</interleave>
</element>
</define>
+ <define name="dependency">
+ <element name="dependency">
+ <interleave>
+ <ref name="kindAttr"/>
+ <ref name="alertAttr"/>
+ </interleave>
+ </element>
+ </define>
+ <define name="kindAttr">
+ <attribute name="kind"/>
+ </define>
+ <define name="alertAttr">
+ <attribute name="alert">
+ <choice>
+ <value>error</value>
+ <value>warning</value>
+ </choice>
+ </attribute>
+ </define>
</grammar>