summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--data/configd-include.json3
-rw-r--r--data/templates/frr/bgpd.frr.j28
-rw-r--r--data/templates/frr/policy.frr.j24
-rw-r--r--data/templates/frr/static_routes_macro.j27
-rw-r--r--data/templates/frr/staticd.frr.j22
-rw-r--r--data/templates/frr/zebra.vrf.route-map.frr.j28
-rw-r--r--data/templates/load-balancing/wlb.conf.j2130
-rw-r--r--data/templates/openvpn/server.conf.j22
-rw-r--r--debian/control4
-rw-r--r--interface-definitions/dns-forwarding.xml.in64
-rw-r--r--interface-definitions/include/bgp/protocol-common-config.xml.i6
-rw-r--r--interface-definitions/include/constraint/login-username.xml.i3
-rw-r--r--interface-definitions/include/static/static-route-bfd.xml.i37
-rw-r--r--interface-definitions/include/static/static-route.xml.i1
-rw-r--r--interface-definitions/include/static/static-route6.xml.i1
-rw-r--r--interface-definitions/include/syslog-facility.xml.i156
-rw-r--r--interface-definitions/lldp.xml.in2
-rw-r--r--interface-definitions/load-balancing-wan.xml.in11
-rw-r--r--interface-definitions/policy.xml.in59
-rw-r--r--interface-definitions/protocols-bgp.xml.in14
-rw-r--r--interface-definitions/protocols-failover.xml.in20
-rw-r--r--interface-definitions/system-login.xml.in2
-rw-r--r--interface-definitions/system-syslog.xml.in818
-rw-r--r--interface-definitions/vrf.xml.in15
-rw-r--r--op-mode-definitions/conntrack-sync.xml.in24
-rw-r--r--op-mode-definitions/counters.xml.in80
-rwxr-xr-xop-mode-definitions/generate-system-login-user.xml.in12
-rw-r--r--op-mode-definitions/include/ospf-common.xml.i15
-rw-r--r--op-mode-definitions/openvpn.xml.in8
-rw-r--r--op-mode-definitions/reboot.xml.in2
-rw-r--r--op-mode-definitions/show-acceleration.xml.in2
-rw-r--r--op-mode-definitions/show-bfd.xml.in13
-rw-r--r--op-mode-definitions/show-interfaces-bonding.xml.in12
-rw-r--r--op-mode-definitions/show-interfaces-bridge.xml.in8
-rw-r--r--op-mode-definitions/show-interfaces-dummy.xml.in8
-rw-r--r--op-mode-definitions/show-interfaces-ethernet.xml.in12
-rw-r--r--op-mode-definitions/show-interfaces-geneve.xml.in8
-rw-r--r--op-mode-definitions/show-interfaces-input.xml.in8
-rw-r--r--op-mode-definitions/show-interfaces-l2tpv3.xml.in8
-rw-r--r--op-mode-definitions/show-interfaces-loopback.xml.in8
-rw-r--r--op-mode-definitions/show-interfaces-pppoe.xml.in6
-rw-r--r--op-mode-definitions/show-interfaces-pseudo-ethernet.xml.in8
-rw-r--r--op-mode-definitions/show-interfaces-sstpc.xml.in6
-rw-r--r--op-mode-definitions/show-interfaces-tunnel.xml.in8
-rw-r--r--op-mode-definitions/show-interfaces-virtual-ethernet.xml.in8
-rw-r--r--op-mode-definitions/show-interfaces-vti.xml.in8
-rw-r--r--op-mode-definitions/show-interfaces-vxlan.xml.in8
-rw-r--r--op-mode-definitions/show-interfaces-wireguard.xml.in6
-rw-r--r--op-mode-definitions/show-interfaces-wireless.xml.in12
-rw-r--r--op-mode-definitions/show-interfaces-wwan.xml.in8
-rw-r--r--op-mode-definitions/vpn-ipsec.xml.in43
-rw-r--r--python/vyos/base.py3
-rw-r--r--python/vyos/ethtool.py15
-rw-r--r--python/vyos/ifconfig/ethernet.py14
-rw-r--r--python/vyos/opmode.py5
-rw-r--r--python/vyos/template.py1
-rw-r--r--python/vyos/utils/__init__.py0
-rw-r--r--python/vyos/utils/dict.py235
-rw-r--r--python/vyos/xml/load.py18
-rw-r--r--smoketest/configs/vrf-bgp-pppoe-underlay473
-rwxr-xr-xsmoketest/scripts/cli/test_policy.py23
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_static.py16
-rwxr-xr-xsmoketest/scripts/cli/test_vrf.py104
-rwxr-xr-xsrc/conf_mode/dns_forwarding.py22
-rwxr-xr-xsrc/conf_mode/load-balancing-wan.py132
-rwxr-xr-xsrc/conf_mode/protocols_bgp.py38
-rwxr-xr-xsrc/conf_mode/protocols_isis.py2
-rwxr-xr-xsrc/conf_mode/protocols_ospf.py2
-rwxr-xr-xsrc/conf_mode/protocols_ospfv3.py2
-rwxr-xr-xsrc/conf_mode/vrf.py14
-rw-r--r--src/conf_mode/vrf_vni.py104
-rwxr-xr-xsrc/helpers/vyos-failover.py41
-rwxr-xr-xsrc/op_mode/bgp.py170
-rwxr-xr-xsrc/op_mode/conntrack_sync.py219
-rwxr-xr-xsrc/op_mode/dynamic_dns.py16
-rwxr-xr-xsrc/op_mode/ipsec.py216
-rwxr-xr-xsrc/op_mode/show_vpn_ra.py56
-rwxr-xr-xsrc/op_mode/show_wwan.py8
-rwxr-xr-xsrc/services/vyos-http-api-server2
-rw-r--r--src/systemd/vyos-wan-load-balance.service15
81 files changed, 2387 insertions, 1308 deletions
diff --git a/Makefile b/Makefile
index e130bec70..4400cbfdc 100644
--- a/Makefile
+++ b/Makefile
@@ -38,9 +38,6 @@ interface_definitions: $(config_xml_obj)
# T2773 - EIGRP support for VRF
rm -rf $(TMPL_DIR)/vrf/name/node.tag/protocols/eigrp
- # T4518, T4470 Load-balancing wan
- rm -rf $(TMPL_DIR)/load-balancing
-
# XXX: test if there are empty node.def files - this is not allowed as these
# could mask help strings or mandatory priority statements
find $(TMPL_DIR) -name node.def -type f -empty -exec false {} + || sh -c 'echo "There are empty node.def files! Check your interface definitions." && exit 1'
diff --git a/data/configd-include.json b/data/configd-include.json
index 2f1d39006..456211caa 100644
--- a/data/configd-include.json
+++ b/data/configd-include.json
@@ -85,5 +85,6 @@
"vpn_l2tp.py",
"vpn_pptp.py",
"vpn_sstp.py",
-"vrf.py"
+"vrf.py",
+"vrf_vni.py"
]
diff --git a/data/templates/frr/bgpd.frr.j2 b/data/templates/frr/bgpd.frr.j2
index b749be93f..7bd9efdce 100644
--- a/data/templates/frr/bgpd.frr.j2
+++ b/data/templates/frr/bgpd.frr.j2
@@ -419,16 +419,18 @@ router bgp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
rd {{ vni_config.rd }}
{% endif %}
{% if vni_config.route_target.both is vyos_defined %}
- route-target both {{ vni_config.route_target.both }}
+{% for route_target in vni_config.route_target.both %}
+ route-target both {{ route_target }}
+{% endfor %}
{% endif %}
{% if vni_config.route_target.export is vyos_defined %}
{% for route_target in vni_config.route_target.export %}
- route-target export {{ route_target }}
+ route-target export {{ route_target }}
{% endfor %}
{% endif %}
{% if vni_config.route_target.import is vyos_defined %}
{% for route_target in vni_config.route_target.import %}
- route-target import {{ route_target }}
+ route-target import {{ route_target }}
{% endfor %}
{% endif %}
exit-vni
diff --git a/data/templates/frr/policy.frr.j2 b/data/templates/frr/policy.frr.j2
index 9b5e80aed..ed5876ae9 100644
--- a/data/templates/frr/policy.frr.j2
+++ b/data/templates/frr/policy.frr.j2
@@ -245,6 +245,10 @@ route-map {{ route_map }} {{ rule_config.action }} {{ rule }}
{% if rule_config.match.peer is vyos_defined %}
match peer {{ rule_config.match.peer }}
{% endif %}
+{% if rule_config.match.protocol is vyos_defined %}
+{% set source_protocol = 'ospf6' if rule_config.match.protocol == 'ospfv3' else rule_config.match.protocol %}
+ match source-protocol {{ source_protocol }}
+{% endif %}
{% if rule_config.match.rpki is vyos_defined %}
match rpki {{ rule_config.match.rpki }}
{% endif %}
diff --git a/data/templates/frr/static_routes_macro.j2 b/data/templates/frr/static_routes_macro.j2
index 1c64ac58b..8afd4a68a 100644
--- a/data/templates/frr/static_routes_macro.j2
+++ b/data/templates/frr/static_routes_macro.j2
@@ -18,7 +18,12 @@
{% endif %}
{% if prefix_config.next_hop is vyos_defined and prefix_config.next_hop is not none %}
{% for next_hop, next_hop_config in prefix_config.next_hop.items() if next_hop_config.disable is not defined %}
-{{ ip_ipv6 }} route {{ prefix }} {{ next_hop }} {{ next_hop_config.interface if next_hop_config.interface is vyos_defined }} {{ next_hop_config.distance if next_hop_config.distance is vyos_defined }} {{ 'nexthop-vrf ' ~ next_hop_config.vrf if next_hop_config.vrf is vyos_defined }} {{ 'table ' ~ table if table is vyos_defined }}
+{{ ip_ipv6 }} route {{ prefix }} {{ next_hop }} {{ next_hop_config.interface if next_hop_config.interface is vyos_defined }} {{ next_hop_config.distance if next_hop_config.distance is vyos_defined }} {{ 'nexthop-vrf ' ~ next_hop_config.vrf if next_hop_config.vrf is vyos_defined }} {{ 'bfd profile ' ~ next_hop_config.bfd.profile if next_hop_config.bfd.profile is vyos_defined }} {{ 'table ' ~ table if table is vyos_defined }}
+{% if next_hop_config.bfd.multi_hop.source is vyos_defined %}
+{% for source, source_config in next_hop_config.bfd.multi_hop.source.items() %}
+{{ ip_ipv6 }} route {{ prefix }} {{ next_hop }} bfd multi-hop source {{ source }} profile {{ source_config.profile }}
+{% endfor %}
+{% endif %}
{% endfor %}
{% endif %}
{% endmacro %}
diff --git a/data/templates/frr/staticd.frr.j2 b/data/templates/frr/staticd.frr.j2
index 55c05ceb7..992a0435c 100644
--- a/data/templates/frr/staticd.frr.j2
+++ b/data/templates/frr/staticd.frr.j2
@@ -37,7 +37,7 @@ vrf {{ vrf }}
{% endfor %}
{% endif %}
{% if vrf is vyos_defined %}
- exit-vrf
+exit-vrf
{% endif %}
!
{# Policy route tables #}
diff --git a/data/templates/frr/zebra.vrf.route-map.frr.j2 b/data/templates/frr/zebra.vrf.route-map.frr.j2
index eb6abd8e7..4e1206374 100644
--- a/data/templates/frr/zebra.vrf.route-map.frr.j2
+++ b/data/templates/frr/zebra.vrf.route-map.frr.j2
@@ -1,6 +1,10 @@
!
{% if name is vyos_defined %}
{% for vrf, vrf_config in name.items() %}
+{# code path required for vrf_vni.py as we will only render the required VR configuration and not all of them #}
+{% if only_vrf is vyos_defined and vrf is not vyos_defined(only_vrf) %}
+{% continue %}
+{% endif %}
vrf {{ vrf }}
{% if vrf_config.ip.protocol is vyos_defined %}
{% for protocol_name, protocol_config in vrf_config.ip.protocol.items() %}
@@ -15,10 +19,10 @@ vrf {{ vrf }}
ipv6 protocol {{ protocol_name }} route-map {{ protocol_config.route_map }}
{% endfor %}
{% endif %}
-{% if vrf_config.vni is vyos_defined %}
+{% if vrf_config.vni is vyos_defined and no_vni is not vyos_defined %}
vni {{ vrf_config.vni }}
{% endif %}
+exit-vrf
{% endfor %}
- exit-vrf
!
{% endif %}
diff --git a/data/templates/load-balancing/wlb.conf.j2 b/data/templates/load-balancing/wlb.conf.j2
new file mode 100644
index 000000000..d3326b6b8
--- /dev/null
+++ b/data/templates/load-balancing/wlb.conf.j2
@@ -0,0 +1,130 @@
+# Generated by /usr/libexec/vyos/conf_mode/load-balancing-wan.py
+
+{% if disable_source_nat is vyos_defined %}
+disable-source-nat
+{% endif %}
+{% if enable_local_traffic is vyos_defined %}
+enable-local-traffic
+{% endif %}
+{% if sticky_connections is vyos_defined %}
+sticky-connections inbound
+{% endif %}
+{% if flush_connections is vyos_defined %}
+flush-conntrack
+{% endif %}
+{% if hook is vyos_defined %}
+hook "{{ hook }}"
+{% endif %}
+{% if interface_health is vyos_defined %}
+health {
+{% for interface, interface_config in interface_health.items() %}
+ interface {{ interface }} {
+{% if interface_config.failure_count is vyos_defined %}
+ failure-ct {{ interface_config.failure_count }}
+{% endif %}
+{% if interface_config.success_count is vyos_defined %}
+ success-ct {{ interface_config.success_count }}
+{% endif %}
+{% if interface_config.nexthop is vyos_defined %}
+ nexthop {{ interface_config.nexthop }}
+{% endif %}
+{% if interface_config.test is vyos_defined %}
+{% for test_rule, test_config in interface_config.test.items() %}
+ rule {{ test_rule }} {
+{% if test_config.type is vyos_defined %}
+{% set type_translate = {'ping': 'ping', 'ttl': 'udp', 'user-defined': 'user-defined'} %}
+ type {{ type_translate[test_config.type] }} {
+{% if test_config.ttl_limit is vyos_defined and test_config.type == 'ttl' %}
+ ttl {{ test_config.ttl_limit }}
+{% endif %}
+{% if test_config.test_script is vyos_defined and test_config.type == 'user-defined' %}
+ test-script {{ test_config.test_script }}
+{% endif %}
+{% if test_config.target is vyos_defined %}
+ target {{ test_config.target }}
+{% endif %}
+ resp-time {{ test_config.resp_time | int * 1000 }}
+ }
+{% endif %}
+ }
+{% endfor %}
+{% endif %}
+ }
+{% endfor %}
+}
+{% endif %}
+
+{% if rule is vyos_defined %}
+{% for rule, rule_config in rule.items() %}
+rule {{ rule }} {
+{% if rule_config.exclude is vyos_defined %}
+ exclude
+{% endif %}
+{% if rule_config.failover is vyos_defined %}
+ failover
+{% endif %}
+{% if rule_config.limit is vyos_defined %}
+ limit {
+{% if rule_config.limit.burst is vyos_defined %}
+ burst {{ rule_config.limit.burst }}
+{% endif %}
+{% if rule_config.limit.rate is vyos_defined %}
+ rate {{ rule_config.limit.rate }}
+{% endif %}
+{% if rule_config.limit.period is vyos_defined %}
+ period {{ rule_config.limit.period }}
+{% endif %}
+{% if rule_config.limit.threshold is vyos_defined %}
+ thresh {{ rule_config.limit.threshold }}
+{% endif %}
+ }
+{% endif %}
+{% if rule_config.per_packet_balancing is vyos_defined %}
+ per-packet-balancing
+{% endif %}
+{% if rule_config.protocol is vyos_defined %}
+ protocol {{ rule_config.protocol }}
+{% endif %}
+{% if rule_config.destination is vyos_defined %}
+ destination {
+{% if rule_config.destination.address is vyos_defined %}
+ address "{{ rule_config.destination.address }}"
+{% endif %}
+{% if rule_config.destination.port is vyos_defined %}
+{% if '-' in rule_config.destination.port %}
+ port-ipt "-m multiport --dports {{ rule_config.destination.port | replace('-', ':') }}"
+{% else %}
+ port-ipt " --dport {{ rule_config.destination.port }}"
+{% endif %}
+{% endif %}
+ }
+{% endif %}
+{% if rule_config.source is vyos_defined %}
+ source {
+{% if rule_config.source.address is vyos_defined %}
+ address "{{ rule_config.source.address }}"
+{% endif %}
+{% if rule_config.source.port is vyos_defined %}
+{% if '-' in rule_config.source.port %}
+ port-ipt "-m multiport --sports {{ rule_config.source.port | replace('-', ':') }}"
+{% else %}
+ port.ipt " --sport {{ rule_config.source.port }}"
+{% endif %}
+{% endif %}
+ }
+{% endif %}
+{% if rule_config.inbound_interface is vyos_defined %}
+ inbound-interface {{ rule_config.inbound_interface }}
+{% endif %}
+{% if rule_config.interface is vyos_defined %}
+{% for interface, interface_config in rule_config.interface.items() %}
+ interface {{ interface }} {
+{% if interface_config.weight is vyos_defined %}
+ weight {{ interface_config.weight }}
+{% endif %}
+ }
+{% endfor %}
+{% endif %}
+}
+{% endfor %}
+{% endif %}
diff --git a/data/templates/openvpn/server.conf.j2 b/data/templates/openvpn/server.conf.j2
index af866f2a6..6332ed9c2 100644
--- a/data/templates/openvpn/server.conf.j2
+++ b/data/templates/openvpn/server.conf.j2
@@ -98,7 +98,7 @@ server-ipv6 {{ subnet }}
{% endif %}
{% if server.client_ip_pool is vyos_defined and server.client_ip_pool.disable is not vyos_defined %}
-ifconfig-pool {{ server.client_ip_pool.start }} {{ server.client_ip_pool.stop }}{{ server.client_ip_pool.subnet_mask if server.client_ip_pool.subnet_mask is vyos_defined }}
+ifconfig-pool {{ server.client_ip_pool.start }} {{ server.client_ip_pool.stop }} {{ server.client_ip_pool.subnet_mask if server.client_ip_pool.subnet_mask is vyos_defined }}
{% endif %}
{% if server.max_connections is vyos_defined %}
max-clients {{ server.max_connections }}
diff --git a/debian/control b/debian/control
index 3126e6ad9..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,7 @@ Standards-Version: 3.9.6
Package: vyos-1x
Architecture: amd64 arm64
Depends:
- ${python3:Depends},
+ ${python3:Depends} (>= 3.10),
aardvark-dns,
accel-ppp,
auditd,
diff --git a/interface-definitions/dns-forwarding.xml.in b/interface-definitions/dns-forwarding.xml.in
index 6b7344b1d..de6991e06 100644
--- a/interface-definitions/dns-forwarding.xml.in
+++ b/interface-definitions/dns-forwarding.xml.in
@@ -126,7 +126,7 @@
<children>
<tagNode name="a">
<properties>
- <help>"A" record</help>
+ <help>A record</help>
<valueHelp>
<format>txt</format>
<description>A DNS name relative to the root record</description>
@@ -163,7 +163,7 @@
</tagNode>
<tagNode name="aaaa">
<properties>
- <help>"AAAA" record</help>
+ <help>AAAA record</help>
<valueHelp>
<format>txt</format>
<description>A DNS name relative to the root record</description>
@@ -200,7 +200,7 @@
</tagNode>
<tagNode name="cname">
<properties>
- <help>"CNAME" record</help>
+ <help>CNAME record</help>
<valueHelp>
<format>txt</format>
<description>A DNS name relative to the root record</description>
@@ -219,7 +219,7 @@
<help>Target DNS name</help>
<valueHelp>
<format>name.example.com</format>
- <description>An absolute DNS name</description>
+ <description>Absolute DNS name</description>
</valueHelp>
<constraint>
<regex>[-_a-zA-Z0-9.]{1,63}(?&lt;!\.)</regex>
@@ -232,7 +232,7 @@
</tagNode>
<tagNode name="mx">
<properties>
- <help>"MX" record</help>
+ <help>MX record</help>
<valueHelp>
<format>txt</format>
<description>A DNS name relative to the root record</description>
@@ -251,7 +251,7 @@
<help>Mail server</help>
<valueHelp>
<format>name.example.com</format>
- <description>An absolute DNS name</description>
+ <description>Absolute DNS name</description>
</valueHelp>
<constraint>
<regex>[-_a-zA-Z0-9.]{1,63}(?&lt;!\.)</regex>
@@ -277,9 +277,37 @@
#include <include/generic-disable-node.xml.i>
</children>
</tagNode>
+ <tagNode name="ns">
+ <properties>
+ <help>NS record</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>A DNS name relative to the root record</description>
+ </valueHelp>
+ <constraint>
+ <regex>([-_a-zA-Z0-9.]{1,63}|@)(?&lt;!\.)</regex>
+ </constraint>
+ </properties>
+ <children>
+ <leafNode name="target">
+ <properties>
+ <help>Target DNS server authoritative for subdomain</help>
+ <valueHelp>
+ <format>nsXX.example.com</format>
+ <description>Absolute DNS name</description>
+ </valueHelp>
+ <constraint>
+ <regex>[-_a-zA-Z0-9.]{1,63}(?&lt;!\.)</regex>
+ </constraint>
+ </properties>
+ </leafNode>
+ #include <include/dns/time-to-live.xml.i>
+ #include <include/generic-disable-node.xml.i>
+ </children>
+ </tagNode>
<tagNode name="ptr">
<properties>
- <help>"PTR" record</help>
+ <help>PTR record</help>
<valueHelp>
<format>txt</format>
<description>A DNS name relative to the root record</description>
@@ -298,7 +326,7 @@
<help>Target DNS name</help>
<valueHelp>
<format>name.example.com</format>
- <description>An absolute DNS name</description>
+ <description>Absolute DNS name</description>
</valueHelp>
<constraint>
<regex>[-_a-zA-Z0-9.]{1,63}(?&lt;!\.)</regex>
@@ -311,7 +339,7 @@
</tagNode>
<tagNode name="txt">
<properties>
- <help>"TXT" record</help>
+ <help>TXT record</help>
<valueHelp>
<format>txt</format>
<description>A DNS name relative to the root record</description>
@@ -341,7 +369,7 @@
</tagNode>
<tagNode name="spf">
<properties>
- <help>"SPF" record (type=SPF)</help>
+ <help>SPF record</help>
<valueHelp>
<format>txt</format>
<description>A DNS name relative to the root record</description>
@@ -370,7 +398,7 @@
</tagNode>
<tagNode name="srv">
<properties>
- <help>"SRV" record</help>
+ <help>SRV record</help>
<valueHelp>
<format>txt</format>
<description>A DNS name relative to the root record</description>
@@ -401,7 +429,7 @@
<help>Server hostname</help>
<valueHelp>
<format>name.example.com</format>
- <description>An absolute DNS name</description>
+ <description>Absolute DNS name</description>
</valueHelp>
<constraint>
<regex>[-_a-zA-Z0-9.]{1,63}(?&lt;!\.)</regex>
@@ -454,7 +482,7 @@
</tagNode>
<tagNode name="naptr">
<properties>
- <help>"NAPTR" record</help>
+ <help>NAPTR record</help>
<valueHelp>
<format>txt</format>
<description>A DNS name relative to the root record</description>
@@ -507,25 +535,25 @@
</leafNode>
<leafNode name="lookup-srv">
<properties>
- <help>"S" flag</help>
+ <help>S flag</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="lookup-a">
<properties>
- <help>"A" flag</help>
+ <help>A flag</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="resolve-uri">
<properties>
- <help>"U" flag</help>
+ <help>U flag</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="protocol-specific">
<properties>
- <help>"P" flag</help>
+ <help>P flag</help>
<valueless/>
</properties>
</leafNode>
@@ -547,7 +575,7 @@
<help>Replacement DNS name</help>
<valueHelp>
<format>name.example.com</format>
- <description>An absolute DNS name</description>
+ <description>Absolute DNS name</description>
</valueHelp>
<constraint>
<regex>[-_a-zA-Z0-9.]{1,63}(?&lt;!\.)</regex>
diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i
index bcc131f83..527eaf991 100644
--- a/interface-definitions/include/bgp/protocol-common-config.xml.i
+++ b/interface-definitions/include/bgp/protocol-common-config.xml.i
@@ -810,6 +810,12 @@
</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>
diff --git a/interface-definitions/include/constraint/login-username.xml.i b/interface-definitions/include/constraint/login-username.xml.i
new file mode 100644
index 000000000..09a68b796
--- /dev/null
+++ b/interface-definitions/include/constraint/login-username.xml.i
@@ -0,0 +1,3 @@
+<!-- include start from constraint/login-username.xml.i -->
+<regex>[-_a-zA-Z0-9.]{1,100}</regex>
+<!-- include end -->
diff --git a/interface-definitions/include/static/static-route-bfd.xml.i b/interface-definitions/include/static/static-route-bfd.xml.i
new file mode 100644
index 000000000..a05a08d12
--- /dev/null
+++ b/interface-definitions/include/static/static-route-bfd.xml.i
@@ -0,0 +1,37 @@
+<!-- include start from static/static-route-bfd.xml.i -->
+<node name="bfd">
+ <properties>
+ <help>BFD monitoring</help>
+ </properties>
+ <children>
+ #include <include/bfd/profile.xml.i>
+ <node name="multi-hop">
+ <properties>
+ <help>Use BFD multi hop session</help>
+ </properties>
+ <children>
+ <tagNode name="source">
+ <properties>
+ <help>Use source for BFD session</help>
+ <valueHelp>
+ <format>ipv4</format>
+ <description>IPv4 source address</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 source address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv4-address"/>
+ <validator name="ipv6-address"/>
+ </constraint>
+ </properties>
+ <children>
+ #include <include/bfd/profile.xml.i>
+ </children>
+ </tagNode>
+ </children>
+ </node>
+ </children>
+</node>
+<!-- include end --> \ No newline at end of file
diff --git a/interface-definitions/include/static/static-route.xml.i b/interface-definitions/include/static/static-route.xml.i
index 268cfa005..29921a731 100644
--- a/interface-definitions/include/static/static-route.xml.i
+++ b/interface-definitions/include/static/static-route.xml.i
@@ -51,6 +51,7 @@
#include <include/static/static-route-distance.xml.i>
#include <include/static/static-route-interface.xml.i>
#include <include/static/static-route-vrf.xml.i>
+ #include <include/static/static-route-bfd.xml.i>
</children>
</tagNode>
</children>
diff --git a/interface-definitions/include/static/static-route6.xml.i b/interface-definitions/include/static/static-route6.xml.i
index 1f8d54108..a83cc230b 100644
--- a/interface-definitions/include/static/static-route6.xml.i
+++ b/interface-definitions/include/static/static-route6.xml.i
@@ -50,6 +50,7 @@
#include <include/static/static-route-distance.xml.i>
#include <include/static/static-route-interface.xml.i>
#include <include/static/static-route-vrf.xml.i>
+ #include <include/static/static-route-bfd.xml.i>
</children>
</tagNode>
</children>
diff --git a/interface-definitions/include/syslog-facility.xml.i b/interface-definitions/include/syslog-facility.xml.i
new file mode 100644
index 000000000..57067ece2
--- /dev/null
+++ b/interface-definitions/include/syslog-facility.xml.i
@@ -0,0 +1,156 @@
+<!-- include start from syslog-facility.xml.i -->
+<tagNode name="facility">
+ <properties>
+ <help>Facility for logging</help>
+ <completionHelp>
+ <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
+ </completionHelp>
+ <constraint>
+ <regex>(auth|authpriv|cron|daemon|kern|lpr|mail|mark|news|protocols|security|syslog|user|uucp|local0|local1|local2|local3|local4|local5|local6|local7|all)</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid facility type</constraintErrorMessage>
+ <valueHelp>
+ <format>all</format>
+ <description>All facilities excluding "mark"</description>
+ </valueHelp>
+ <valueHelp>
+ <format>auth</format>
+ <description>Authentication and authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>authpriv</format>
+ <description>Non-system authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>cron</format>
+ <description>Cron daemon</description>
+ </valueHelp>
+ <valueHelp>
+ <format>daemon</format>
+ <description>System daemons</description>
+ </valueHelp>
+ <valueHelp>
+ <format>kern</format>
+ <description>Kernel</description>
+ </valueHelp>
+ <valueHelp>
+ <format>lpr</format>
+ <description>Line printer spooler</description>
+ </valueHelp>
+ <valueHelp>
+ <format>mail</format>
+ <description>Mail subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>mark</format>
+ <description>Timestamp</description>
+ </valueHelp>
+ <valueHelp>
+ <format>news</format>
+ <description>USENET subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>protocols</format>
+ <description>depricated will be set to local7</description>
+ </valueHelp>
+ <valueHelp>
+ <format>security</format>
+ <description>depricated will be set to auth</description>
+ </valueHelp>
+ <valueHelp>
+ <format>syslog</format>
+ <description>Authentication and authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>user</format>
+ <description>Application processes</description>
+ </valueHelp>
+ <valueHelp>
+ <format>uucp</format>
+ <description>UUCP subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local0</format>
+ <description>Local facility 0</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local1</format>
+ <description>Local facility 1</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local2</format>
+ <description>Local facility 2</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local3</format>
+ <description>Local facility 3</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local4</format>
+ <description>Local facility 4</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local5</format>
+ <description>Local facility 5</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local6</format>
+ <description>Local facility 6</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local7</format>
+ <description>Local facility 7</description>
+ </valueHelp>
+ </properties>
+ <children>
+ <leafNode name="level">
+ <properties>
+ <help>Logging level</help>
+ <completionHelp>
+ <list>emerg alert crit err warning notice info debug all</list>
+ </completionHelp>
+ <constraint>
+ <regex>(emerg|alert|crit|err|warning|notice|info|debug|all)</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid loglevel</constraintErrorMessage>
+ <valueHelp>
+ <format>emerg</format>
+ <description>Emergency messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>alert</format>
+ <description>Urgent messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>crit</format>
+ <description>Critical messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>err</format>
+ <description>Error messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>warning</format>
+ <description>Warning messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>notice</format>
+ <description>Messages for further investigation</description>
+ </valueHelp>
+ <valueHelp>
+ <format>info</format>
+ <description>Informational messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>debug</format>
+ <description>Debug messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>all</format>
+ <description>Log everything</description>
+ </valueHelp>
+ </properties>
+ </leafNode>
+ </children>
+</tagNode>
+<!-- include end -->
diff --git a/interface-definitions/lldp.xml.in b/interface-definitions/lldp.xml.in
index b9ffe234c..738bb11c1 100644
--- a/interface-definitions/lldp.xml.in
+++ b/interface-definitions/lldp.xml.in
@@ -20,7 +20,7 @@
<description>Location data for a specific interface</description>
</valueHelp>
<completionHelp>
- <script>${vyatta_sbindir}/vyatta-interfaces.pl --show all</script>
+ <script>${vyos_completion_dir}/list_interfaces</script>
<list>all</list>
</completionHelp>
</properties>
diff --git a/interface-definitions/load-balancing-wan.xml.in b/interface-definitions/load-balancing-wan.xml.in
index c1d7e2c67..3a2c111ac 100644
--- a/interface-definitions/load-balancing-wan.xml.in
+++ b/interface-definitions/load-balancing-wan.xml.in
@@ -3,6 +3,7 @@
<node name="load-balancing">
<properties>
<help>Configure load-balancing</help>
+ <priority>900</priority>
</properties>
<children>
<node name="wan" owner="${vyos_conf_scripts_dir}/load-balancing-wan.py">
@@ -59,6 +60,7 @@
<validator name="numeric" argument="--range 1-10"/>
</constraint>
</properties>
+ <defaultValue>1</defaultValue>
</leafNode>
<leafNode name="nexthop">
<properties>
@@ -91,6 +93,7 @@
<validator name="numeric" argument="--range 1-10"/>
</constraint>
</properties>
+ <defaultValue>1</defaultValue>
</leafNode>
<tagNode name="test">
<properties>
@@ -115,6 +118,7 @@
<validator name="numeric" argument="--range 1-30"/>
</constraint>
</properties>
+ <defaultValue>5</defaultValue>
</leafNode>
<leafNode name="target">
<properties>
@@ -151,6 +155,7 @@
<validator name="numeric" argument="--range 1-254"/>
</constraint>
</properties>
+ <defaultValue>1</defaultValue>
</leafNode>
<leafNode name="type">
<properties>
@@ -242,6 +247,7 @@
</constraint>
<constraintErrorMessage>Weight must be between 1 and 255</constraintErrorMessage>
</properties>
+ <defaultValue>1</defaultValue>
</leafNode>
</children>
</tagNode>
@@ -261,6 +267,7 @@
<validator name="numeric" argument="--range 0-4294967295"/>
</constraint>
</properties>
+ <defaultValue>5</defaultValue>
</leafNode>
<leafNode name="period">
<properties>
@@ -284,6 +291,7 @@
<regex>(hour|minute|second)</regex>
</constraint>
</properties>
+ <defaultValue>second</defaultValue>
</leafNode>
<leafNode name="rate">
<properties>
@@ -296,6 +304,7 @@
<validator name="numeric" argument="--range 0-4294967295"/>
</constraint>
</properties>
+ <defaultValue>5</defaultValue>
</leafNode>
<leafNode name="threshold">
<properties>
@@ -315,6 +324,7 @@
<regex>(above|below)</regex>
</constraint>
</properties>
+ <defaultValue>below</defaultValue>
</leafNode>
</children>
</node>
@@ -355,6 +365,7 @@
<validator name="ip-protocol"/>
</constraint>
</properties>
+ <defaultValue>all</defaultValue>
</leafNode>
<node name="source">
<properties>
diff --git a/interface-definitions/policy.xml.in b/interface-definitions/policy.xml.in
index 7d5fe79ef..02828c4f6 100644
--- a/interface-definitions/policy.xml.in
+++ b/interface-definitions/policy.xml.in
@@ -971,6 +971,65 @@
</constraint>
</properties>
</leafNode>
+ <leafNode name="protocol">
+ <properties>
+ <help>Match protocol via which the route was learnt</help>
+ <completionHelp>
+ <list>babel bgp connected isis kernel ospf ospfv3 rip ripng static table vnc</list>
+ </completionHelp>
+ <valueHelp>
+ <format>babel</format>
+ <description>Babel routing protocol (Babel)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>bgp</format>
+ <description>Border Gateway Protocol (BGP)</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 (IS-IS)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>kernel</format>
+ <description>Kernel routes</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ospf</format>
+ <description>Open Shortest Path First (OSPFv2)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ospfv3</format>
+ <description>Open Shortest Path First (IPv6) (OSPFv3)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>rip</format>
+ <description>Routing Information Protocol (RIP)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ripng</format>
+ <description>Routing Information Protocol next-generation (IPv6) (RIPng)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>static</format>
+ <description>Statically configured routes</description>
+ </valueHelp>
+ <valueHelp>
+ <format>table</format>
+ <description>Non-main Kernel Routing Table</description>
+ </valueHelp>
+ <valueHelp>
+ <format>vnc</format>
+ <description>Virtual Network Control (VNC)</description>
+ </valueHelp>
+ <constraint>
+ <regex>(babel|bgp|connected|isis|kernel|ospf|ospfv3|rip|ripng|static|table|vnc)</regex>
+ </constraint>
+ </properties>
+ </leafNode>
<leafNode name="rpki">
<properties>
<help>Match RPKI validation result</help>
diff --git a/interface-definitions/protocols-bgp.xml.in b/interface-definitions/protocols-bgp.xml.in
index 78b461f9d..e1a822999 100644
--- a/interface-definitions/protocols-bgp.xml.in
+++ b/interface-definitions/protocols-bgp.xml.in
@@ -9,20 +9,6 @@
</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 a8c5c717f..c0caec68e 100644
--- a/interface-definitions/protocols-failover.xml.in
+++ b/interface-definitions/protocols-failover.xml.in
@@ -37,6 +37,26 @@
<help>Check target options</help>
</properties>
<children>
+ <leafNode name="policy">
+ <properties>
+ <help>Policy for check targets</help>
+ <completionHelp>
+ <list>any-available all-available</list>
+ </completionHelp>
+ <valueHelp>
+ <format>all-available</format>
+ <description>All targets must be alive</description>
+ </valueHelp>
+ <valueHelp>
+ <format>any-available</format>
+ <description>Any target must be alive</description>
+ </valueHelp>
+ <constraint>
+ <regex>(all-available|any-available)</regex>
+ </constraint>
+ </properties>
+ <defaultValue>any-available</defaultValue>
+ </leafNode>
#include <include/port-number.xml.i>
<leafNode name="target">
<properties>
diff --git a/interface-definitions/system-login.xml.in b/interface-definitions/system-login.xml.in
index 258913929..be4f53c3b 100644
--- a/interface-definitions/system-login.xml.in
+++ b/interface-definitions/system-login.xml.in
@@ -12,7 +12,7 @@
<properties>
<help>Local user account information</help>
<constraint>
- <regex>[-_a-zA-Z0-9.]{1,100}</regex>
+ #include <include/constraint/login-username.xml.i>
</constraint>
<constraintErrorMessage>Username contains illegal characters or\nexceeds 100 character limitation.</constraintErrorMessage>
</properties>
diff --git a/interface-definitions/system-syslog.xml.in b/interface-definitions/system-syslog.xml.in
index 90c3de5c1..4a2adfd5f 100644
--- a/interface-definitions/system-syslog.xml.in
+++ b/interface-definitions/system-syslog.xml.in
@@ -11,175 +11,25 @@
<tagNode name="user">
<properties>
<help>Logging to specific terminal of given user</help>
+ <completionHelp>
+ <path>system login user</path>
+ </completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Local user account</description>
+ </valueHelp>
<constraint>
- <regex>[a-z_][a-z0-9_-]{1,31}[$]?</regex>
+ #include <include/constraint/login-username.xml.i>
</constraint>
<constraintErrorMessage>illegal characters in user</constraintErrorMessage>
- <valueHelp>
- <format>username</format>
- <description>user login name</description>
- </valueHelp>
</properties>
<children>
- <tagNode name="facility">
- <properties>
- <help>Facility for logging</help>
- <completionHelp>
- <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
- </completionHelp>
- <constraint>
- <regex>(auth|authpriv|cron|daemon|kern|lpr|mail|mark|news|protocols|security|syslog|user|uucp|local0|local1|local2|local3|local4|local5|local6|local7|all)</regex>
- </constraint>
- <constraintErrorMessage>Invalid facility type</constraintErrorMessage>
- <valueHelp>
- <format>all</format>
- <description>All facilities excluding "mark"</description>
- </valueHelp>
- <valueHelp>
- <format>auth</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>authpriv</format>
- <description>Non-system authorization</description>
- </valueHelp>
- <valueHelp>
- <format>cron</format>
- <description>Cron daemon</description>
- </valueHelp>
- <valueHelp>
- <format>daemon</format>
- <description>System daemons</description>
- </valueHelp>
- <valueHelp>
- <format>kern</format>
- <description>Kernel</description>
- </valueHelp>
- <valueHelp>
- <format>lpr</format>
- <description>Line printer spooler</description>
- </valueHelp>
- <valueHelp>
- <format>mail</format>
- <description>Mail subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>mark</format>
- <description>Timestamp</description>
- </valueHelp>
- <valueHelp>
- <format>news</format>
- <description>USENET subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>protocols</format>
- <description>depricated will be set to local7</description>
- </valueHelp>
- <valueHelp>
- <format>security</format>
- <description>depricated will be set to auth</description>
- </valueHelp>
- <valueHelp>
- <format>syslog</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>user</format>
- <description>Application processes</description>
- </valueHelp>
- <valueHelp>
- <format>uucp</format>
- <description>UUCP subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>local0</format>
- <description>Local facility 0</description>
- </valueHelp>
- <valueHelp>
- <format>local1</format>
- <description>Local facility 1</description>
- </valueHelp>
- <valueHelp>
- <format>local2</format>
- <description>Local facility 2</description>
- </valueHelp>
- <valueHelp>
- <format>local3</format>
- <description>Local facility 3</description>
- </valueHelp>
- <valueHelp>
- <format>local4</format>
- <description>Local facility 4</description>
- </valueHelp>
- <valueHelp>
- <format>local5</format>
- <description>Local facility 5</description>
- </valueHelp>
- <valueHelp>
- <format>local6</format>
- <description>Local facility 6</description>
- </valueHelp>
- <valueHelp>
- <format>local7</format>
- <description>Local facility 7</description>
- </valueHelp>
- </properties>
- <children>
- <leafNode name="level">
- <properties>
- <help>Logging level</help>
- <completionHelp>
- <list>emerg alert crit err warning notice info debug all</list>
- </completionHelp>
- <constraint>
- <regex>(emerg|alert|crit|err|warning|notice|info|debug|all)</regex>
- </constraint>
- <constraintErrorMessage>Invalid loglevel</constraintErrorMessage>
- <valueHelp>
- <format>emerg</format>
- <description>Emergency messages</description>
- </valueHelp>
- <valueHelp>
- <format>alert</format>
- <description>Urgent messages</description>
- </valueHelp>
- <valueHelp>
- <format>crit</format>
- <description>Critical messages</description>
- </valueHelp>
- <valueHelp>
- <format>err</format>
- <description>Error messages</description>
- </valueHelp>
- <valueHelp>
- <format>warning</format>
- <description>Warning messages</description>
- </valueHelp>
- <valueHelp>
- <format>notice</format>
- <description>Messages for further investigation</description>
- </valueHelp>
- <valueHelp>
- <format>info</format>
- <description>Informational messages</description>
- </valueHelp>
- <valueHelp>
- <format>debug</format>
- <description>Debug messages</description>
- </valueHelp>
- <valueHelp>
- <format>all</format>
- <description>Log everything</description>
- </valueHelp>
- </properties>
- </leafNode>
- </children>
- </tagNode>
+ #include <include/syslog-facility.xml.i>
</children>
</tagNode>
<tagNode name="host">
<properties>
- <help>Logging to a remote host</help>
+ <help>Logging to remote host</help>
<constraint>
<validator name="ip-address"/>
<validator name="fqdn"/>
@@ -190,186 +40,17 @@
<description>Remote syslog server IPv4 address</description>
</valueHelp>
<valueHelp>
+ <format>ipv6</format>
+ <description>Remote syslog server IPv6 address</description>
+ </valueHelp>
+ <valueHelp>
<format>hostname</format>
<description>Remote syslog server FQDN</description>
</valueHelp>
</properties>
<children>
#include <include/port-number.xml.i>
- <tagNode name="facility">
- <properties>
- <help>Facility for logging</help>
- <completionHelp>
- <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
- </completionHelp>
- <constraint>
- <regex>(auth|authpriv|cron|daemon|kern|lpr|mail|mark|news|protocols|security|syslog|user|uucp|local0|local1|local2|local3|local4|local5|local6|local7|all)</regex>
- </constraint>
- <constraintErrorMessage>Invalid facility type</constraintErrorMessage>
- <valueHelp>
- <format>all</format>
- <description>All facilities excluding "mark"</description>
- </valueHelp>
- <valueHelp>
- <format>auth</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>authpriv</format>
- <description>Non-system authorization</description>
- </valueHelp>
- <valueHelp>
- <format>cron</format>
- <description>Cron daemon</description>
- </valueHelp>
- <valueHelp>
- <format>daemon</format>
- <description>System daemons</description>
- </valueHelp>
- <valueHelp>
- <format>kern</format>
- <description>Kernel</description>
- </valueHelp>
- <valueHelp>
- <format>lpr</format>
- <description>Line printer spooler</description>
- </valueHelp>
- <valueHelp>
- <format>mail</format>
- <description>Mail subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>mark</format>
- <description>Timestamp</description>
- </valueHelp>
- <valueHelp>
- <format>news</format>
- <description>USENET subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>protocols</format>
- <description>depricated will be set to local7</description>
- </valueHelp>
- <valueHelp>
- <format>security</format>
- <description>depricated will be set to auth</description>
- </valueHelp>
- <valueHelp>
- <format>syslog</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>user</format>
- <description>Application processes</description>
- </valueHelp>
- <valueHelp>
- <format>uucp</format>
- <description>UUCP subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>local0</format>
- <description>Local facility 0</description>
- </valueHelp>
- <valueHelp>
- <format>local1</format>
- <description>Local facility 1</description>
- </valueHelp>
- <valueHelp>
- <format>local2</format>
- <description>Local facility 2</description>
- </valueHelp>
- <valueHelp>
- <format>local3</format>
- <description>Local facility 3</description>
- </valueHelp>
- <valueHelp>
- <format>local4</format>
- <description>Local facility 4</description>
- </valueHelp>
- <valueHelp>
- <format>local5</format>
- <description>Local facility 5</description>
- </valueHelp>
- <valueHelp>
- <format>local6</format>
- <description>Local facility 6</description>
- </valueHelp>
- <valueHelp>
- <format>local7</format>
- <description>Local facility 7</description>
- </valueHelp>
- </properties>
- <children>
- <leafNode name="protocol">
- <properties>
- <help>syslog communication protocol</help>
- <valueHelp>
- <format>udp</format>
- <description>send log messages to remote syslog server over udp</description>
- </valueHelp>
- <valueHelp>
- <format>tcp</format>
- <description>send log messages to remote syslog server over tcp</description>
- </valueHelp>
- <completionHelp>
- <list>udp tcp</list>
- </completionHelp>
- <constraint>
- <regex>(udp|tcp)</regex>
- </constraint>
- <constraintErrorMessage>invalid protocol name</constraintErrorMessage>
- </properties>
- </leafNode>
- <leafNode name="level">
- <properties>
- <help>Logging level</help>
- <completionHelp>
- <list>emerg alert crit err warning notice info debug all</list>
- </completionHelp>
- <constraint>
- <regex>(emerg|alert|crit|err|warning|notice|info|debug|all)</regex>
- </constraint>
- <constraintErrorMessage>Invalid loglevel</constraintErrorMessage>
- <valueHelp>
- <format>emerg</format>
- <description>Emergency messages</description>
- </valueHelp>
- <valueHelp>
- <format>alert</format>
- <description>Urgent messages</description>
- </valueHelp>
- <valueHelp>
- <format>crit</format>
- <description>Critical messages</description>
- </valueHelp>
- <valueHelp>
- <format>err</format>
- <description>Error messages</description>
- </valueHelp>
- <valueHelp>
- <format>warning</format>
- <description>Warning messages</description>
- </valueHelp>
- <valueHelp>
- <format>notice</format>
- <description>Messages for further investigation</description>
- </valueHelp>
- <valueHelp>
- <format>info</format>
- <description>Informational messages</description>
- </valueHelp>
- <valueHelp>
- <format>debug</format>
- <description>Debug messages</description>
- </valueHelp>
- <valueHelp>
- <format>all</format>
- <description>Log everything</description>
- </valueHelp>
- </properties>
- </leafNode>
- </children>
- </tagNode>
+ #include <include/syslog-facility.xml.i>
<node name="format">
<properties>
<help>Logging format</help>
@@ -390,160 +71,7 @@
<help>Logging to system standard location</help>
</properties>
<children>
- <tagNode name="facility">
- <properties>
- <help>Facility for logging</help>
- <completionHelp>
- <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
- </completionHelp>
- <constraint>
- <regex>(auth|authpriv|cron|daemon|kern|lpr|mail|mark|news|protocols|security|syslog|user|uucp|local0|local1|local2|local3|local4|local5|local6|local7|all)</regex>
- </constraint>
- <constraintErrorMessage>Invalid facility type</constraintErrorMessage>
- <valueHelp>
- <format>all</format>
- <description>All facilities excluding "mark"</description>
- </valueHelp>
- <valueHelp>
- <format>auth</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>authpriv</format>
- <description>Non-system authorization</description>
- </valueHelp>
- <valueHelp>
- <format>cron</format>
- <description>Cron daemon</description>
- </valueHelp>
- <valueHelp>
- <format>daemon</format>
- <description>System daemons</description>
- </valueHelp>
- <valueHelp>
- <format>kern</format>
- <description>Kernel</description>
- </valueHelp>
- <valueHelp>
- <format>lpr</format>
- <description>Line printer spooler</description>
- </valueHelp>
- <valueHelp>
- <format>mail</format>
- <description>Mail subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>mark</format>
- <description>Timestamp</description>
- </valueHelp>
- <valueHelp>
- <format>news</format>
- <description>USENET subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>protocols</format>
- <description>depricated will be set to local7</description>
- </valueHelp>
- <valueHelp>
- <format>security</format>
- <description>depricated will be set to auth</description>
- </valueHelp>
- <valueHelp>
- <format>syslog</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>user</format>
- <description>Application processes</description>
- </valueHelp>
- <valueHelp>
- <format>uucp</format>
- <description>UUCP subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>local0</format>
- <description>Local facility 0</description>
- </valueHelp>
- <valueHelp>
- <format>local1</format>
- <description>Local facility 1</description>
- </valueHelp>
- <valueHelp>
- <format>local2</format>
- <description>Local facility 2</description>
- </valueHelp>
- <valueHelp>
- <format>local3</format>
- <description>Local facility 3</description>
- </valueHelp>
- <valueHelp>
- <format>local4</format>
- <description>Local facility 4</description>
- </valueHelp>
- <valueHelp>
- <format>local5</format>
- <description>Local facility 5</description>
- </valueHelp>
- <valueHelp>
- <format>local6</format>
- <description>Local facility 6</description>
- </valueHelp>
- <valueHelp>
- <format>local7</format>
- <description>Local facility 7</description>
- </valueHelp>
- </properties>
- <children>
- <leafNode name="level">
- <properties>
- <help>Logging level</help>
- <completionHelp>
- <list>emerg alert crit err warning notice info debug all</list>
- </completionHelp>
- <constraint>
- <regex>(emerg|alert|crit|err|warning|notice|info|debug|all)</regex>
- </constraint>
- <constraintErrorMessage>Invalid loglevel</constraintErrorMessage>
- <valueHelp>
- <format>emerg</format>
- <description>Emergency messages</description>
- </valueHelp>
- <valueHelp>
- <format>alert</format>
- <description>Urgent messages</description>
- </valueHelp>
- <valueHelp>
- <format>crit</format>
- <description>Critical messages</description>
- </valueHelp>
- <valueHelp>
- <format>err</format>
- <description>Error messages</description>
- </valueHelp>
- <valueHelp>
- <format>warning</format>
- <description>Warning messages</description>
- </valueHelp>
- <valueHelp>
- <format>notice</format>
- <description>Messages for further investigation</description>
- </valueHelp>
- <valueHelp>
- <format>info</format>
- <description>Informational messages</description>
- </valueHelp>
- <valueHelp>
- <format>debug</format>
- <description>Debug messages</description>
- </valueHelp>
- <valueHelp>
- <format>all</format>
- <description>Log everything</description>
- </valueHelp>
- </properties>
- </leafNode>
- </children>
- </tagNode>
+ #include <include/syslog-facility.xml.i>
<node name="marker">
<properties>
<help>mark messages sent to syslog</help>
@@ -559,10 +87,10 @@
</leafNode>
</children>
</node>
- <leafNode name ="preserve-fqdn">
+ <leafNode name="preserve-fqdn">
<properties>
<help>uses FQDN for logging</help>
- <valueless />
+ <valueless/>
</properties>
</leafNode>
</children>
@@ -601,160 +129,7 @@
</leafNode>
</children>
</node>
- <tagNode name="facility">
- <properties>
- <help>Facility for logging</help>
- <completionHelp>
- <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
- </completionHelp>
- <constraint>
- <regex>(auth|authpriv|cron|daemon|kern|lpr|mail|mark|news|protocols|security|syslog|user|uucp|local0|local1|local2|local3|local4|local5|local6|local7|all)</regex>
- </constraint>
- <constraintErrorMessage>Invalid facility type</constraintErrorMessage>
- <valueHelp>
- <format>all</format>
- <description>All facilities excluding "mark"</description>
- </valueHelp>
- <valueHelp>
- <format>auth</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>authpriv</format>
- <description>Non-system authorization</description>
- </valueHelp>
- <valueHelp>
- <format>cron</format>
- <description>Cron daemon</description>
- </valueHelp>
- <valueHelp>
- <format>daemon</format>
- <description>System daemons</description>
- </valueHelp>
- <valueHelp>
- <format>kern</format>
- <description>Kernel</description>
- </valueHelp>
- <valueHelp>
- <format>lpr</format>
- <description>Line printer spooler</description>
- </valueHelp>
- <valueHelp>
- <format>mail</format>
- <description>Mail subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>mark</format>
- <description>Timestamp</description>
- </valueHelp>
- <valueHelp>
- <format>news</format>
- <description>USENET subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>protocols</format>
- <description>depricated will be set to local7</description>
- </valueHelp>
- <valueHelp>
- <format>security</format>
- <description>depricated will be set to auth</description>
- </valueHelp>
- <valueHelp>
- <format>syslog</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>user</format>
- <description>Application processes</description>
- </valueHelp>
- <valueHelp>
- <format>uucp</format>
- <description>UUCP subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>local0</format>
- <description>Local facility 0</description>
- </valueHelp>
- <valueHelp>
- <format>local1</format>
- <description>Local facility 1</description>
- </valueHelp>
- <valueHelp>
- <format>local2</format>
- <description>Local facility 2</description>
- </valueHelp>
- <valueHelp>
- <format>local3</format>
- <description>Local facility 3</description>
- </valueHelp>
- <valueHelp>
- <format>local4</format>
- <description>Local facility 4</description>
- </valueHelp>
- <valueHelp>
- <format>local5</format>
- <description>Local facility 5</description>
- </valueHelp>
- <valueHelp>
- <format>local6</format>
- <description>Local facility 6</description>
- </valueHelp>
- <valueHelp>
- <format>local7</format>
- <description>Local facility 7</description>
- </valueHelp>
- </properties>
- <children>
- <leafNode name="level">
- <properties>
- <help>Logging level</help>
- <completionHelp>
- <list>emerg alert crit err warning notice info debug all</list>
- </completionHelp>
- <constraint>
- <regex>(emerg|alert|crit|err|warning|notice|info|debug|all)</regex>
- </constraint>
- <constraintErrorMessage>Invalid loglevel</constraintErrorMessage>
- <valueHelp>
- <format>emerg</format>
- <description>Emergency messages</description>
- </valueHelp>
- <valueHelp>
- <format>alert</format>
- <description>Urgent messages</description>
- </valueHelp>
- <valueHelp>
- <format>crit</format>
- <description>Critical messages</description>
- </valueHelp>
- <valueHelp>
- <format>err</format>
- <description>Error messages</description>
- </valueHelp>
- <valueHelp>
- <format>warning</format>
- <description>Warning messages</description>
- </valueHelp>
- <valueHelp>
- <format>notice</format>
- <description>Messages for further investigation</description>
- </valueHelp>
- <valueHelp>
- <format>info</format>
- <description>Informational messages</description>
- </valueHelp>
- <valueHelp>
- <format>debug</format>
- <description>Debug messages</description>
- </valueHelp>
- <valueHelp>
- <format>all</format>
- <description>Log everything</description>
- </valueHelp>
- </properties>
- </leafNode>
- </children>
- </tagNode>
+ #include <include/syslog-facility.xml.i>
</children>
</tagNode>
<node name="console">
@@ -762,160 +137,7 @@
<help>logging to serial console</help>
</properties>
<children>
- <tagNode name="facility">
- <properties>
- <help>Facility for logging</help>
- <completionHelp>
- <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
- </completionHelp>
- <constraint>
- <regex>(auth|authpriv|cron|daemon|kern|lpr|mail|mark|news|protocols|security|syslog|user|uucp|local0|local1|local2|local3|local4|local5|local6|local7|all)</regex>
- </constraint>
- <constraintErrorMessage>Invalid facility type</constraintErrorMessage>
- <valueHelp>
- <format>all</format>
- <description>All facilities excluding "mark"</description>
- </valueHelp>
- <valueHelp>
- <format>auth</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>authpriv</format>
- <description>Non-system authorization</description>
- </valueHelp>
- <valueHelp>
- <format>cron</format>
- <description>Cron daemon</description>
- </valueHelp>
- <valueHelp>
- <format>daemon</format>
- <description>System daemons</description>
- </valueHelp>
- <valueHelp>
- <format>kern</format>
- <description>Kernel</description>
- </valueHelp>
- <valueHelp>
- <format>lpr</format>
- <description>Line printer spooler</description>
- </valueHelp>
- <valueHelp>
- <format>mail</format>
- <description>Mail subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>mark</format>
- <description>Timestamp</description>
- </valueHelp>
- <valueHelp>
- <format>news</format>
- <description>USENET subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>protocols</format>
- <description>depricated will be set to local7</description>
- </valueHelp>
- <valueHelp>
- <format>security</format>
- <description>depricated will be set to auth</description>
- </valueHelp>
- <valueHelp>
- <format>syslog</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>user</format>
- <description>Application processes</description>
- </valueHelp>
- <valueHelp>
- <format>uucp</format>
- <description>UUCP subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>local0</format>
- <description>Local facility 0</description>
- </valueHelp>
- <valueHelp>
- <format>local1</format>
- <description>Local facility 1</description>
- </valueHelp>
- <valueHelp>
- <format>local2</format>
- <description>Local facility 2</description>
- </valueHelp>
- <valueHelp>
- <format>local3</format>
- <description>Local facility 3</description>
- </valueHelp>
- <valueHelp>
- <format>local4</format>
- <description>Local facility 4</description>
- </valueHelp>
- <valueHelp>
- <format>local5</format>
- <description>Local facility 5</description>
- </valueHelp>
- <valueHelp>
- <format>local6</format>
- <description>Local facility 6</description>
- </valueHelp>
- <valueHelp>
- <format>local7</format>
- <description>Local facility 7</description>
- </valueHelp>
- </properties>
- <children>
- <leafNode name="level">
- <properties>
- <help>Logging level</help>
- <completionHelp>
- <list>emerg alert crit err warning notice info debug all</list>
- </completionHelp>
- <constraint>
- <regex>(emerg|alert|crit|err|warning|notice|info|debug|all)</regex>
- </constraint>
- <constraintErrorMessage>Invalid loglevel</constraintErrorMessage>
- <valueHelp>
- <format>emerg</format>
- <description>Emergency messages</description>
- </valueHelp>
- <valueHelp>
- <format>alert</format>
- <description>Urgent messages</description>
- </valueHelp>
- <valueHelp>
- <format>crit</format>
- <description>Critical messages</description>
- </valueHelp>
- <valueHelp>
- <format>err</format>
- <description>Error messages</description>
- </valueHelp>
- <valueHelp>
- <format>warning</format>
- <description>Warning messages</description>
- </valueHelp>
- <valueHelp>
- <format>notice</format>
- <description>Messages for further investigation</description>
- </valueHelp>
- <valueHelp>
- <format>info</format>
- <description>Informational messages</description>
- </valueHelp>
- <valueHelp>
- <format>debug</format>
- <description>Debug messages</description>
- </valueHelp>
- <valueHelp>
- <format>all</format>
- <description>Log everything</description>
- </valueHelp>
- </properties>
- </leafNode>
- </children>
- </tagNode>
+ #include <include/syslog-facility.xml.i>
</children>
</node>
</children>
diff --git a/interface-definitions/vrf.xml.in b/interface-definitions/vrf.xml.in
index a7efe146a..3783785ce 100644
--- a/interface-definitions/vrf.xml.in
+++ b/interface-definitions/vrf.xml.in
@@ -121,7 +121,20 @@
<constraintErrorMessage>VRF routing table must be in range from 100 to 65535</constraintErrorMessage>
</properties>
</leafNode>
- #include <include/vni.xml.i>
+ <leafNode name="vni" owner="${vyos_conf_scripts_dir}/vrf_vni.py $VAR(../@)">
+ <properties>
+ <help>Virtual Network Identifier</help>
+ <!-- must be after BGP to keep correct order when removing L3VNIs in FRR -->
+ <priority>822</priority>
+ <valueHelp>
+ <format>u32:0-16777214</format>
+ <description>VXLAN virtual network identifier</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 0-16777214"/>
+ </constraint>
+ </properties>
+ </leafNode>
</children>
</tagNode>
</children>
diff --git a/op-mode-definitions/conntrack-sync.xml.in b/op-mode-definitions/conntrack-sync.xml.in
index 3e29ecd39..a66331f27 100644
--- a/op-mode-definitions/conntrack-sync.xml.in
+++ b/op-mode-definitions/conntrack-sync.xml.in
@@ -11,13 +11,13 @@
<properties>
<help>Reset external cache and request resync with other systems</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py --reset-cache-external</command>
+ <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py reset_external_cache</command>
</leafNode>
<leafNode name="internal-cache">
<properties>
<help>Reset internal cache and request resync with other systems</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py --reset-cache-internal</command>
+ <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py reset_internal_cache</command>
</leafNode>
</children>
</node>
@@ -27,9 +27,9 @@
<children>
<leafNode name="conntrack-sync">
<properties>
- <help>Restart connection tracking synchronization service</help>
+ <help>Restart the connection tracking synchronization service</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py --restart</command>
+ <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py restart</command>
</leafNode>
</children>
</node>
@@ -49,19 +49,19 @@
<properties>
<help>Show external connection tracking cache entries</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py --show-external; ${vyos_op_scripts_dir}/conntrack_sync.py --show-external-expect</command>
+ <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py show_external_cache</command>
<children>
<leafNode name="main">
<properties>
<help>Show external main connection tracking cache entries</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py --show-external</command>
+ <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py show_external_cache</command>
</leafNode>
<leafNode name="expect">
<properties>
<help>Show external expect connection tracking cache entries</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py --show-external-expect</command>
+ <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py show_external_expect</command>
</leafNode>
</children>
</node>
@@ -69,19 +69,19 @@
<properties>
<help>Show internal connection tracking cache entries</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py --show-internal; ${vyos_op_scripts_dir}/conntrack_sync.py --show-internal-expect</command>
+ <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py show_internal_cache</command>
<children>
<leafNode name="main">
<properties>
<help>Show internal main connection tracking cache entries</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py --show-internal</command>
+ <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py show_internal_cache</command>
</leafNode>
<leafNode name="expect">
<properties>
<help>Show internal expect connection tracking cache entries</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py --show-internal-expect</command>
+ <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py show_internal_expect</command>
</leafNode>
</children>
</node>
@@ -91,13 +91,13 @@
<properties>
<help>Show connection syncing statistics</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py --show-statistics</command>
+ <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py show_statistics</command>
</leafNode>
<leafNode name="status">
<properties>
<help>Show conntrack-sync status</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py --show-status</command>
+ <command>sudo ${vyos_op_scripts_dir}/conntrack_sync.py show_status</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/counters.xml.in b/op-mode-definitions/counters.xml.in
index 4bf08d201..f563cb9a0 100644
--- a/op-mode-definitions/counters.xml.in
+++ b/op-mode-definitions/counters.xml.in
@@ -19,7 +19,7 @@
<properties>
<help>Clear all bonding interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -35,7 +35,7 @@
<properties>
<help>Clear interface counters for a given bonding interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -48,7 +48,7 @@
<properties>
<help>Clear all bridge interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -64,7 +64,7 @@
<properties>
<help>Clear interface counters for a given bridge interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -77,7 +77,7 @@
<properties>
<help>Clear all dummy interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -93,7 +93,7 @@
<properties>
<help>Clear interface counters for a given dummy interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -106,7 +106,7 @@
<properties>
<help>Clear all ethernet interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -122,7 +122,7 @@
<properties>
<help>Clear interface counters for a given ethernet interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -135,7 +135,7 @@
<properties>
<help>Clear all GENEVE interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -151,7 +151,7 @@
<properties>
<help>Clear interface counters for a given GENEVE interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -164,7 +164,7 @@
<properties>
<help>Clear all Input interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -180,7 +180,7 @@
<properties>
<help>Clear interface counters for a given Input interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -193,7 +193,7 @@
<properties>
<help>Clear all L2TPv3 interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -209,7 +209,7 @@
<properties>
<help>Clear interface counters for a given L2TPv3 interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -222,7 +222,7 @@
<properties>
<help>Clear all loopback interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -238,7 +238,7 @@
<properties>
<help>Clear interface counters for a given loopback interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -251,7 +251,7 @@
<properties>
<help>Clear all MACsec interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -267,7 +267,7 @@
<properties>
<help>Clear interface counters for a given MACsec interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -280,7 +280,7 @@
<properties>
<help>Clear all OpenVPN interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -296,7 +296,7 @@
<properties>
<help>Clear interface counters for a given OpenVPN interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -309,7 +309,7 @@
<properties>
<help>Clear all PPPoE interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -325,7 +325,7 @@
<properties>
<help>Clear interface counters for a given PPPoE interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -338,7 +338,7 @@
<properties>
<help>Clear all Pseudo-Ethernet interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -354,7 +354,7 @@
<properties>
<help>Clear interface counters for a given Pseudo-Ethernet interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -367,7 +367,7 @@
<properties>
<help>Clear all SSTP interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -383,7 +383,7 @@
<properties>
<help>Clear interface counters for a given SSTP interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -396,7 +396,7 @@
<properties>
<help>Clear all tunnel interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -412,7 +412,7 @@
<properties>
<help>Clear interface counters for a given tunnel interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -425,7 +425,7 @@
<properties>
<help>Clear all virtual-ethernet interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -441,7 +441,7 @@
<properties>
<help>Clear interface counters for a given virtual-ethernet interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -454,7 +454,7 @@
<properties>
<help>Clear all VTI interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -470,7 +470,7 @@
<properties>
<help>Clear interface counters for a given VTI interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -483,7 +483,7 @@
<properties>
<help>Clear all VXLAN interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -499,7 +499,7 @@
<properties>
<help>Clear interface counters for a given VXLAN interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -512,7 +512,7 @@
<properties>
<help>Clear all Wireguard interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</node>
</children>
</node>
@@ -528,7 +528,7 @@
<properties>
<help>Clear interface counters for a given Wireguard interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -541,7 +541,7 @@
<properties>
<help>Clear all wireless interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</leafNode>
</children>
</node>
@@ -557,7 +557,7 @@
<properties>
<help>Clear counters for a given wireless interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
@@ -570,7 +570,7 @@
<properties>
<help>Clear all WWAN interface counters</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_type "$3"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-type "$3"</command>
</leafNode>
</children>
</node>
@@ -586,7 +586,7 @@
<properties>
<help>Clear counters for a given WWAN interface</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf_name "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/interfaces.py clear_counters --intf-name "$4"</command>
</leafNode>
</children>
</tagNode>
diff --git a/op-mode-definitions/generate-system-login-user.xml.in b/op-mode-definitions/generate-system-login-user.xml.in
index d0519b6bd..237a13610 100755
--- a/op-mode-definitions/generate-system-login-user.xml.in
+++ b/op-mode-definitions/generate-system-login-user.xml.in
@@ -35,19 +35,19 @@
<properties>
<help>Duration of single time interval</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/generate_system_login_user.py --username "$5" --rate_limit "$9"</command>
+ <command>sudo ${vyos_op_scripts_dir}/generate_system_login_user.py --username "$5" --rate-limit "$9"</command>
<children>
<tagNode name="rate-time">
<properties>
<help>The number of digits in the one-time password</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/generate_system_login_user.py --username "$5" --rate_limit "$9" --rate_time "${11}" </command>
+ <command>sudo ${vyos_op_scripts_dir}/generate_system_login_user.py --username "$5" --rate-limit "$9" --rate-time "${11}" </command>
<children>
<tagNode name="window-size">
<properties>
<help>The number of digits in the one-time password</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/generate_system_login_user.py --username "$5" --rate_limit "$9" --rate_time "${11}" --window_size "${13}"</command>
+ <command>sudo ${vyos_op_scripts_dir}/generate_system_login_user.py --username "$5" --rate-limit "$9" --rate-time "${11}" --window-size "${13}"</command>
</tagNode>
</children>
</tagNode>
@@ -57,19 +57,19 @@
<properties>
<help>The number of digits in the one-time password</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/generate_system_login_user.py --username "$5" --window_size "${9}"</command>
+ <command>sudo ${vyos_op_scripts_dir}/generate_system_login_user.py --username "$5" --window-size "${9}"</command>
<children>
<tagNode name="rate-limit">
<properties>
<help>Duration of single time interval</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/generate_system_login_user.py --username "$5" --rate_limit "${11}" --window_size "${9}"</command>
+ <command>sudo ${vyos_op_scripts_dir}/generate_system_login_user.py --username "$5" --rate-limit "${11}" --window-size "${9}"</command>
<children>
<tagNode name="rate-time">
<properties>
<help>Duration of single time interval</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/generate_system_login_user.py --username "$5" --rate_limit "${11}" --rate_time "${13}" --window_size "${9}"</command>
+ <command>sudo ${vyos_op_scripts_dir}/generate_system_login_user.py --username "$5" --rate-limit "${11}" --rate-time "${13}" --window-size "${9}"</command>
</tagNode>
</children>
</tagNode>
diff --git a/op-mode-definitions/include/ospf-common.xml.i b/op-mode-definitions/include/ospf-common.xml.i
index aebbae5ff..979ffb07e 100644
--- a/op-mode-definitions/include/ospf-common.xml.i
+++ b/op-mode-definitions/include/ospf-common.xml.i
@@ -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>
-<!-- included end --> \ No newline at end of file
+ <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/openvpn.xml.in b/op-mode-definitions/openvpn.xml.in
index 94647af02..f205b0026 100644
--- a/op-mode-definitions/openvpn.xml.in
+++ b/op-mode-definitions/openvpn.xml.in
@@ -37,13 +37,13 @@
<properties>
<help>Show OpenVPN interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=openvpn</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=openvpn</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed OpenVPN interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=openvpn</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=openvpn</command>
</leafNode>
</children>
</node>
@@ -54,7 +54,7 @@
<script>sudo ${vyos_completion_dir}/list_interfaces --type openvpn</script>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name=$4</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name=$4</command>
<children>
<tagNode name="user">
<properties>
@@ -95,7 +95,7 @@
<properties>
<help>Show summary of specified OpenVPN interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4"</command>
</leafNode>
</children>
</tagNode>
diff --git a/op-mode-definitions/reboot.xml.in b/op-mode-definitions/reboot.xml.in
index 6414742d9..d5a71f561 100644
--- a/op-mode-definitions/reboot.xml.in
+++ b/op-mode-definitions/reboot.xml.in
@@ -25,7 +25,7 @@
<list>&lt;Minutes&gt;</list>
</completionHelp>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/powerctrl.py --yes --reboot_in $3 $4</command>
+ <command>sudo ${vyos_op_scripts_dir}/powerctrl.py --yes --reboot-in $3 $4</command>
</tagNode>
<tagNode name="at">
<properties>
diff --git a/op-mode-definitions/show-acceleration.xml.in b/op-mode-definitions/show-acceleration.xml.in
index 6fd3babf5..fccfba5e3 100644
--- a/op-mode-definitions/show-acceleration.xml.in
+++ b/op-mode-definitions/show-acceleration.xml.in
@@ -21,7 +21,7 @@
<properties>
<help>Show QAT information for a given acceleration device</help>
<completionHelp>
- <script>${vyos_op_scripts_dir}/show_acceleration.py --dev_list</script>
+ <script>${vyos_op_scripts_dir}/show_acceleration.py --dev-list</script>
</completionHelp>
</properties>
<children>
diff --git a/op-mode-definitions/show-bfd.xml.in b/op-mode-definitions/show-bfd.xml.in
index 39e42e6ec..87d672e04 100644
--- a/op-mode-definitions/show-bfd.xml.in
+++ b/op-mode-definitions/show-bfd.xml.in
@@ -49,6 +49,19 @@
</leafNode>
</children>
</node>
+ <node name="static">
+ <properties>
+ <help>Show route Routing Table</help>
+ </properties>
+ <children>
+ <leafNode name="routes">
+ <properties>
+ <help>Showing BFD monitored static routes</help>
+ </properties>
+ <command>vtysh -c "show bfd static route"</command>
+ </leafNode>
+ </children>
+ </node>
</children>
</node>
</children>
diff --git a/op-mode-definitions/show-interfaces-bonding.xml.in b/op-mode-definitions/show-interfaces-bonding.xml.in
index c41e7bd5f..aa224e6cf 100644
--- a/op-mode-definitions/show-interfaces-bonding.xml.in
+++ b/op-mode-definitions/show-interfaces-bonding.xml.in
@@ -11,13 +11,13 @@
<path>interfaces bonding</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=bonding</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=bonding</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified bonding interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=bonding</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=bonding</command>
</leafNode>
<leafNode name="detail">
<properties>
@@ -38,13 +38,13 @@
<path>interfaces bonding ${COMP_WORDS[3]} vif</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4.$6" --intf_type=bonding</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4.$6" --intf-type=bonding</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of specified virtual network interface (vif) information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4.$6" --intf_type=bonding</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4.$6" --intf-type=bonding</command>
</leafNode>
</children>
</tagNode>
@@ -60,13 +60,13 @@
<properties>
<help>Show Bonding interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=bonding</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=bonding</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed bonding interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=bonding</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=bonding</command>
</leafNode>
<leafNode name="slaves">
<properties>
diff --git a/op-mode-definitions/show-interfaces-bridge.xml.in b/op-mode-definitions/show-interfaces-bridge.xml.in
index 22cd3ee67..dc813682d 100644
--- a/op-mode-definitions/show-interfaces-bridge.xml.in
+++ b/op-mode-definitions/show-interfaces-bridge.xml.in
@@ -11,13 +11,13 @@
<path>interfaces bridge</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=bridge</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=bridge</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified bridge interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=bridge</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=bridge</command>
</leafNode>
</children>
</tagNode>
@@ -25,13 +25,13 @@
<properties>
<help>Show Bridge interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=bridge</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=bridge</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed bridge interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=bridge</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=bridge</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-dummy.xml.in b/op-mode-definitions/show-interfaces-dummy.xml.in
index 958d3483d..b8ec7da91 100644
--- a/op-mode-definitions/show-interfaces-dummy.xml.in
+++ b/op-mode-definitions/show-interfaces-dummy.xml.in
@@ -11,13 +11,13 @@
<path>interfaces dummy</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=dummy</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=dummy</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified dummy interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=dummy</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=dummy</command>
</leafNode>
</children>
</tagNode>
@@ -25,13 +25,13 @@
<properties>
<help>Show Dummy interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=dummy</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=dummy</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed dummy interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=dummy</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=dummy</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-ethernet.xml.in b/op-mode-definitions/show-interfaces-ethernet.xml.in
index 81759c2b6..7c12d6084 100644
--- a/op-mode-definitions/show-interfaces-ethernet.xml.in
+++ b/op-mode-definitions/show-interfaces-ethernet.xml.in
@@ -11,13 +11,13 @@
<path>interfaces ethernet</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=ethernet</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified ethernet interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=ethernet</command>
</leafNode>
<leafNode name="identify">
<properties>
@@ -58,13 +58,13 @@
<path>interfaces ethernet ${COMP_WORDS[3]} vif</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4.$6" --intf_type=ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4.$6" --intf-type=ethernet</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of specified virtual network interface (vif) information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4.$6" --intf_type=ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4.$6" --intf-type=ethernet</command>
</leafNode>
</children>
</tagNode>
@@ -80,13 +80,13 @@
<properties>
<help>Show Ethernet interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=ethernet</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed ethernet interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=ethernet</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-geneve.xml.in b/op-mode-definitions/show-interfaces-geneve.xml.in
index 3cf45878d..d3d188031 100644
--- a/op-mode-definitions/show-interfaces-geneve.xml.in
+++ b/op-mode-definitions/show-interfaces-geneve.xml.in
@@ -11,13 +11,13 @@
<path>interfaces geneve</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=geneve</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=geneve</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified GENEVE interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=geneve</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=geneve</command>
</leafNode>
</children>
</tagNode>
@@ -25,13 +25,13 @@
<properties>
<help>Show GENEVE interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=geneve</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=geneve</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed GENEVE interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=geneve</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=geneve</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-input.xml.in b/op-mode-definitions/show-interfaces-input.xml.in
index 5d93dcee6..e5d420056 100644
--- a/op-mode-definitions/show-interfaces-input.xml.in
+++ b/op-mode-definitions/show-interfaces-input.xml.in
@@ -11,13 +11,13 @@
<path>interfaces input</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=input</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=input</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified input interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=input</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=input</command>
</leafNode>
</children>
</tagNode>
@@ -25,13 +25,13 @@
<properties>
<help>Show Input (ifb) interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=input</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=input</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed input interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=input</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=input</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-l2tpv3.xml.in b/op-mode-definitions/show-interfaces-l2tpv3.xml.in
index 713e36dac..2d165171c 100644
--- a/op-mode-definitions/show-interfaces-l2tpv3.xml.in
+++ b/op-mode-definitions/show-interfaces-l2tpv3.xml.in
@@ -11,13 +11,13 @@
<path>interfaces l2tpv3</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=l2tpv3</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=l2tpv3</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified L2TPv3 interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=l2tpv3</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=l2tpv3</command>
</leafNode>
</children>
</tagNode>
@@ -25,13 +25,13 @@
<properties>
<help>Show L2TPv3 interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=l2tpv3</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=l2tpv3</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed L2TPv3 interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=l2tpv3</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=l2tpv3</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-loopback.xml.in b/op-mode-definitions/show-interfaces-loopback.xml.in
index a24151cc3..d341a6359 100644
--- a/op-mode-definitions/show-interfaces-loopback.xml.in
+++ b/op-mode-definitions/show-interfaces-loopback.xml.in
@@ -11,13 +11,13 @@
<path>interfaces loopback</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=loopback</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=loopback</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified Loopback interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=loopback</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=loopback</command>
</leafNode>
</children>
</tagNode>
@@ -25,13 +25,13 @@
<properties>
<help>Show Loopback interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=loopback</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=loopback</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed Loopback interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=loopback</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=loopback</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-pppoe.xml.in b/op-mode-definitions/show-interfaces-pppoe.xml.in
index a34473148..1c6e0b83e 100644
--- a/op-mode-definitions/show-interfaces-pppoe.xml.in
+++ b/op-mode-definitions/show-interfaces-pppoe.xml.in
@@ -11,7 +11,7 @@
<path>interfaces pppoe</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=pppoe</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=pppoe</command>
<children>
<leafNode name="log">
<properties>
@@ -34,13 +34,13 @@
<properties>
<help>Show PPPoE interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=pppoe</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=pppoe</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed PPPoE interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=pppoe</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=pppoe</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-pseudo-ethernet.xml.in b/op-mode-definitions/show-interfaces-pseudo-ethernet.xml.in
index cb62639ee..4ab2a5fbb 100644
--- a/op-mode-definitions/show-interfaces-pseudo-ethernet.xml.in
+++ b/op-mode-definitions/show-interfaces-pseudo-ethernet.xml.in
@@ -11,13 +11,13 @@
<path>interfaces pseudo-ethernet</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=pseudo-ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=pseudo-ethernet</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified pseudo-ethernet/MACvlan interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=pseudo-ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=pseudo-ethernet</command>
</leafNode>
</children>
</tagNode>
@@ -25,13 +25,13 @@
<properties>
<help>Show Pseudo-Ethernet/MACvlan interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=pseudo-ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=pseudo-ethernet</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed pseudo-ethernet/MACvlan interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=pseudo-ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=pseudo-ethernet</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-sstpc.xml.in b/op-mode-definitions/show-interfaces-sstpc.xml.in
index a619a9fd2..307276f72 100644
--- a/op-mode-definitions/show-interfaces-sstpc.xml.in
+++ b/op-mode-definitions/show-interfaces-sstpc.xml.in
@@ -11,7 +11,7 @@
<path>interfaces sstpc</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=sstpc</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=sstpc</command>
<children>
<leafNode name="log">
<properties>
@@ -34,13 +34,13 @@
<properties>
<help>Show SSTP client interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=sstpc</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=sstpc</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed SSTP client interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=sstpc</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=sstpc</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-tunnel.xml.in b/op-mode-definitions/show-interfaces-tunnel.xml.in
index 10e10e655..b99b0cbb2 100644
--- a/op-mode-definitions/show-interfaces-tunnel.xml.in
+++ b/op-mode-definitions/show-interfaces-tunnel.xml.in
@@ -11,13 +11,13 @@
<path>interfaces tunnel</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=tunnel</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=tunnel</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified tunnel interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=tunnel</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=tunnel</command>
</leafNode>
</children>
</tagNode>
@@ -25,13 +25,13 @@
<properties>
<help>Show Tunnel interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=tunnel</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=tunnel</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed tunnel interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=tunnel</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=tunnel</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-virtual-ethernet.xml.in b/op-mode-definitions/show-interfaces-virtual-ethernet.xml.in
index c743492fb..18ae806b7 100644
--- a/op-mode-definitions/show-interfaces-virtual-ethernet.xml.in
+++ b/op-mode-definitions/show-interfaces-virtual-ethernet.xml.in
@@ -11,13 +11,13 @@
<path>interfaces virtual-ethernet</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=virtual-ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=virtual-ethernet</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified virtual-ethernet interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=virtual-ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=virtual-ethernet</command>
</leafNode>
</children>
</tagNode>
@@ -25,13 +25,13 @@
<properties>
<help>Show virtual-ethernet interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=virtual-ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=virtual-ethernet</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed virtual-ethernet interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=virtual-ethernet</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=virtual-ethernet</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-vti.xml.in b/op-mode-definitions/show-interfaces-vti.xml.in
index d532894b7..ae5cfeb9c 100644
--- a/op-mode-definitions/show-interfaces-vti.xml.in
+++ b/op-mode-definitions/show-interfaces-vti.xml.in
@@ -11,13 +11,13 @@
<path>interfaces vti</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=vti</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=vti</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified vti interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=vti</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=vti</command>
</leafNode>
</children>
</tagNode>
@@ -25,13 +25,13 @@
<properties>
<help>Show VTI interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=vti</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=vti</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed vti interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=vti</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=vti</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-vxlan.xml.in b/op-mode-definitions/show-interfaces-vxlan.xml.in
index fde832551..fd729b986 100644
--- a/op-mode-definitions/show-interfaces-vxlan.xml.in
+++ b/op-mode-definitions/show-interfaces-vxlan.xml.in
@@ -11,13 +11,13 @@
<path>interfaces vxlan</path>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=vxlan</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=vxlan</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified VXLAN interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=vxlan</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=vxlan</command>
</leafNode>
</children>
</tagNode>
@@ -25,13 +25,13 @@
<properties>
<help>Show VXLAN interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=vxlan</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=vxlan</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed VXLAN interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=vxlan</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=vxlan</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-wireguard.xml.in b/op-mode-definitions/show-interfaces-wireguard.xml.in
index d045beafc..bab7f19c8 100644
--- a/op-mode-definitions/show-interfaces-wireguard.xml.in
+++ b/op-mode-definitions/show-interfaces-wireguard.xml.in
@@ -11,7 +11,7 @@
<script>${vyos_completion_dir}/list_interfaces --type wireguard</script>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=wireguard</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=wireguard</command>
<children>
<leafNode name="allowed-ips">
<properties>
@@ -49,13 +49,13 @@
<properties>
<help>Show WireGuard interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=wireguard</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=wireguard</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed Wireguard interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=wireguard</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=wireguard</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/show-interfaces-wireless.xml.in b/op-mode-definitions/show-interfaces-wireless.xml.in
index f39d402f1..27c0f43db 100644
--- a/op-mode-definitions/show-interfaces-wireless.xml.in
+++ b/op-mode-definitions/show-interfaces-wireless.xml.in
@@ -8,13 +8,13 @@
<properties>
<help>Show Wireless (WLAN) interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=wireless</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=wireless</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed wireless interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=wireless</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=wireless</command>
</leafNode>
<leafNode name="info">
<properties>
@@ -31,13 +31,13 @@
<script>${vyos_completion_dir}/list_interfaces --type wireless</script>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=wireless</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=wireless</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified wireless interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=wireless</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4" --intf-type=wireless</command>
</leafNode>
<node name="scan">
<properties>
@@ -63,13 +63,13 @@
<properties>
<help>Show specified virtual network interface (vif) information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4.$6" --intf_type=wireless</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4.$6" --intf-type=wireless</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of specified virtual network interface (vif) information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4.$6" --intf_type=wireless</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-name="$4.$6" --intf-type=wireless</command>
</leafNode>
</children>
</tagNode>
diff --git a/op-mode-definitions/show-interfaces-wwan.xml.in b/op-mode-definitions/show-interfaces-wwan.xml.in
index 17d4111a9..45558115b 100644
--- a/op-mode-definitions/show-interfaces-wwan.xml.in
+++ b/op-mode-definitions/show-interfaces-wwan.xml.in
@@ -12,7 +12,7 @@
<script>cd /sys/class/net; ls -d wwan*</script>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=wirelessmodem</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-name="$4" --intf-type=wirelessmodem</command>
<children>
<leafNode name="capabilities">
<properties>
@@ -72,7 +72,7 @@
<properties>
<help>Show WWAN module detailed information summary</help>
</properties>
- <command>mmcli --modem ${4#wwan}</command>
+ <command>if cli-shell-api existsActive interfaces wwan $4; then mmcli --modem ${4#wwan}; else echo "Interface \"$4\" unconfigured!"; fi</command>
</leafNode>
<leafNode name="log">
<properties>
@@ -86,13 +86,13 @@
<properties>
<help>Show Wireless Modem (WWAN) interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_type=wirelessmodem</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf-type=wirelessmodem</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed Wireless Modem (WWAN( interface information</help>
</properties>
- <command>${vyos_op_scripts_dir}/interfaces.py show --intf_type=wirelessmodem</command>
+ <command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=wirelessmodem</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/vpn-ipsec.xml.in b/op-mode-definitions/vpn-ipsec.xml.in
index 5a7e6dd63..c7ba780a3 100644
--- a/op-mode-definitions/vpn-ipsec.xml.in
+++ b/op-mode-definitions/vpn-ipsec.xml.in
@@ -35,7 +35,7 @@
<list>&lt;x.x.x.x&gt; &lt;h:h:h:h:h:h:h:h&gt;</list>
</completionHelp>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/ipsec.py reset_profile_dst --profile="$5" --tunnel="$7" --nbma_dst="$9"</command>
+ <command>sudo ${vyos_op_scripts_dir}/ipsec.py reset_profile_dst --profile="$5" --tunnel="$7" --nbma-dst="$9"</command>
</tagNode>
</children>
<command>sudo ${vyos_op_scripts_dir}/ipsec.py reset_profile_all --profile="$5" --tunnel="$7"</command>
@@ -204,12 +204,37 @@
</properties>
<command>sudo ip xfrm policy list</command>
</node>
- <leafNode name="remote-access">
- <properties>
- <help>Show active VPN server sessions</help>
- </properties>
- <command>${vyos_op_scripts_dir}/show_vpn_ra.py</command>
- </leafNode>
+ <node name="remote-access">
+ <properties>
+ <help>Show active VPN server sessions</help>
+ </properties>
+ <children>
+ <node name="detail">
+ <properties>
+ <help>Show detail active IKEv2 RA sessions</help>
+ </properties>
+ <command>if systemctl is-active --quiet strongswan ; then sudo ${vyos_op_scripts_dir}/ipsec.py show_ra_detail; else echo "IPsec process not running" ; fi</command>
+ </node>
+ <tagNode name="connection-id">
+ <properties>
+ <help>Show detail active IKEv2 RA sessions by connection-id</help>
+ </properties>
+ <command>if systemctl is-active --quiet strongswan ; then sudo ${vyos_op_scripts_dir}/ipsec.py show_ra_detail --conn-id="$6"; else echo "IPsec process not running" ; fi</command>
+ </tagNode>
+ <node name="summary">
+ <properties>
+ <help>Show active IKEv2 RA sessions summary</help>
+ </properties>
+ <command>if systemctl is-active --quiet strongswan ; then sudo ${vyos_op_scripts_dir}/ipsec.py show_ra_summary; else echo "IPsec process not running" ; fi</command>
+ </node>
+ <tagNode name="username">
+ <properties>
+ <help>Show detail active IKEv2 RA sessions by username</help>
+ </properties>
+ <command>if systemctl is-active --quiet strongswan ; then sudo ${vyos_op_scripts_dir}/ipsec.py show_ra_detail --username="$6"; else echo "IPsec process not running" ; fi</command>
+ </tagNode>
+ </children>
+ </node>
<node name="sa">
<properties>
<help>Show all active IPsec Security Associations (SA)</help>
@@ -241,11 +266,11 @@
<command></command>
</tagNode>
-->
- <node name="verbose">
+ <node name="detail">
<properties>
<help>Show Verbose Detail on all active IPsec Security Associations (SA)</help>
</properties>
- <command>if systemctl is-active --quiet strongswan ; then sudo /usr/sbin/ipsec statusall ; else echo "IPsec process not running" ; fi</command>
+ <command>if systemctl is-active --quiet strongswan ; then sudo ${vyos_op_scripts_dir}/ipsec.py show_sa_detail ; else echo "IPsec process not running" ; fi</command>
</node>
</children>
<command>if systemctl is-active --quiet strongswan ; then sudo ${vyos_op_scripts_dir}/ipsec.py show_sa ; else echo "IPsec process not running" ; fi</command>
diff --git a/python/vyos/base.py b/python/vyos/base.py
index 9b93cb2f2..c1acfd060 100644
--- a/python/vyos/base.py
+++ b/python/vyos/base.py
@@ -1,4 +1,4 @@
-# Copyright 2018-2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2018-2023 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -41,7 +41,6 @@ class BaseWarning:
isfirstmessage = False
initial_indent = self.standardindent
print(f'{mes}')
- print('')
class Warning():
diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py
index bc3402059..1b1e54dfb 100644
--- a/python/vyos/ethtool.py
+++ b/python/vyos/ethtool.py
@@ -51,6 +51,7 @@ class Ethtool:
_ring_buffers_max = { }
_driver_name = None
_auto_negotiation = False
+ _auto_negotiation_supported = None
_flow_control = False
_flow_control_enabled = None
@@ -80,7 +81,13 @@ class Ethtool:
self._speed_duplex.update({ speed : {}})
if duplex not in self._speed_duplex[speed]:
self._speed_duplex[speed].update({ duplex : ''})
- if 'Auto-negotiation:' in line:
+ if 'Supports auto-negotiation:' in line:
+ # Split the following string: Auto-negotiation: off
+ # we are only interested in off or on
+ tmp = line.split()[-1]
+ self._auto_negotiation_supported = bool(tmp == 'Yes')
+ # Only read in if Auto-negotiation is supported
+ if self._auto_negotiation_supported and 'Auto-negotiation:' in line:
# Split the following string: Auto-negotiation: off
# we are only interested in off or on
tmp = line.split()[-1]
@@ -132,8 +139,12 @@ class Ethtool:
# ['Autonegotiate:', 'on']
self._flow_control_enabled = out.splitlines()[1].split()[-1]
+ def check_auto_negotiation_supported(self):
+ """ Check if the NIC supports changing auto-negotiation """
+ return self._auto_negotiation_supported
+
def get_auto_negotiation(self):
- return self._auto_negotiation
+ return self._auto_negotiation_supported and self._auto_negotiation
def get_driver_name(self):
return self._driver_name
diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py
index 5080144ff..6a49c022a 100644
--- a/python/vyos/ifconfig/ethernet.py
+++ b/python/vyos/ifconfig/ethernet.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2021 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2023 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -14,9 +14,10 @@
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
import os
-import re
from glob import glob
+
+from vyos.base import Warning
from vyos.ethtool import Ethtool
from vyos.ifconfig.interface import Interface
from vyos.util import run
@@ -118,7 +119,7 @@ class EthernetIf(Interface):
cmd = f'ethtool --pause {ifname} autoneg {enable} tx {enable} rx {enable}'
output, code = self._popen(cmd)
if code:
- print(f'Could not set flowcontrol for {ifname}')
+ Warning(f'could not change "{ifname}" flow control setting!')
return output
return None
@@ -134,6 +135,7 @@ class EthernetIf(Interface):
>>> i = EthernetIf('eth0')
>>> i.set_speed_duplex('auto', 'auto')
"""
+ ifname = self.config['ifname']
if speed not in ['auto', '10', '100', '1000', '2500', '5000', '10000',
'25000', '40000', '50000', '100000', '400000']:
@@ -143,7 +145,11 @@ class EthernetIf(Interface):
raise ValueError("Value out of range (duplex)")
if not self.ethtool.check_speed_duplex(speed, duplex):
- self._debug_msg(f'NIC driver does not support changing speed/duplex settings!')
+ Warning(f'changing speed/duplex setting on "{ifname}" is unsupported!')
+ return
+
+ if not self.ethtool.check_auto_negotiation_supported():
+ Warning(f'changing auto-negotiation setting on "{ifname}" is unsupported!')
return
# Get current speed and duplex settings:
diff --git a/python/vyos/opmode.py b/python/vyos/opmode.py
index d7172a0b5..230a85541 100644
--- a/python/vyos/opmode.py
+++ b/python/vyos/opmode.py
@@ -209,6 +209,11 @@ def run(module):
for opt in type_hints:
th = type_hints[opt]
+ # Function argument names use underscores as separators
+ # but command-line options should use hyphens
+ # Without this, we'd get options like "--foo_bar"
+ opt = re.sub(r'_', '-', opt)
+
if _get_arg_type(th) == bool:
subparser.add_argument(f"--{opt}", action='store_true')
else:
diff --git a/python/vyos/template.py b/python/vyos/template.py
index 06a292706..254a15e3a 100644
--- a/python/vyos/template.py
+++ b/python/vyos/template.py
@@ -44,6 +44,7 @@ def _get_environment(location=None):
loader=loc_loader,
trim_blocks=True,
undefined=ChainableUndefined,
+ extensions=['jinja2.ext.loopcontrols']
)
env.filters.update(_FILTERS)
env.tests.update(_TESTS)
diff --git a/python/vyos/utils/__init__.py b/python/vyos/utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python/vyos/utils/__init__.py
diff --git a/python/vyos/utils/dict.py b/python/vyos/utils/dict.py
new file mode 100644
index 000000000..66b40d92b
--- /dev/null
+++ b/python/vyos/utils/dict.py
@@ -0,0 +1,235 @@
+# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+
+def colon_separated_to_dict(data_string, uniquekeys=False):
+ """ Converts a string containing newline-separated entries
+ of colon-separated key-value pairs into a dict.
+
+ Such files are common in Linux /proc filesystem
+
+ Args:
+ data_string (str): data string
+ uniquekeys (bool): whether to insist that keys are unique or not
+
+ Returns: dict
+
+ Raises:
+ ValueError: if uniquekeys=True and the data string has
+ duplicate keys.
+
+ Note:
+ If uniquekeys=True, then dict entries are always strings,
+ otherwise they are always lists of strings.
+ """
+ import re
+ key_value_re = re.compile('([^:]+)\s*\:\s*(.*)')
+
+ data_raw = re.split('\n', data_string)
+
+ data = {}
+
+ for l in data_raw:
+ l = l.strip()
+ if l:
+ match = re.match(key_value_re, l)
+ if match and (len(match.groups()) == 2):
+ key = match.groups()[0].strip()
+ value = match.groups()[1].strip()
+ else:
+ raise ValueError(f"""Line "{l}" could not be parsed a colon-separated pair """, l)
+ if key in data.keys():
+ if uniquekeys:
+ raise ValueError("Data string has duplicate keys: {0}".format(key))
+ else:
+ data[key].append(value)
+ else:
+ if uniquekeys:
+ data[key] = value
+ else:
+ data[key] = [value]
+ else:
+ pass
+
+ return data
+
+def _mangle_dict_keys(data, regex, replacement, abs_path=[], no_tag_node_value_mangle=False, mod=0):
+ """ Mangles dict keys according to a regex and replacement character.
+ Some libraries like Jinja2 do not like certain characters in dict keys.
+ This function can be used for replacing all offending characters
+ with something acceptable.
+
+ Args:
+ data (dict): Original dict to mangle
+
+ Returns: dict
+ """
+ from vyos.xml import is_tag
+
+ new_dict = {}
+
+ for key in data.keys():
+ save_mod = mod
+ save_path = abs_path[:]
+
+ abs_path.append(key)
+
+ if not is_tag(abs_path):
+ new_key = re.sub(regex, replacement, key)
+ else:
+ if mod%2:
+ new_key = key
+ else:
+ new_key = re.sub(regex, replacement, key)
+ if no_tag_node_value_mangle:
+ mod += 1
+
+ value = data[key]
+
+ if isinstance(value, dict):
+ new_dict[new_key] = _mangle_dict_keys(value, regex, replacement, abs_path=abs_path, mod=mod, no_tag_node_value_mangle=no_tag_node_value_mangle)
+ else:
+ new_dict[new_key] = value
+
+ mod = save_mod
+ abs_path = save_path[:]
+
+ return new_dict
+
+def mangle_dict_keys(data, regex, replacement, abs_path=[], no_tag_node_value_mangle=False):
+ return _mangle_dict_keys(data, regex, replacement, abs_path=abs_path, no_tag_node_value_mangle=no_tag_node_value_mangle, mod=0)
+
+def _get_sub_dict(d, lpath):
+ k = lpath[0]
+ if k not in d.keys():
+ return {}
+ c = {k: d[k]}
+ lpath = lpath[1:]
+ if not lpath:
+ return c
+ elif not isinstance(c[k], dict):
+ return {}
+ return _get_sub_dict(c[k], lpath)
+
+def get_sub_dict(source, lpath, get_first_key=False):
+ """ Returns the sub-dict of a nested dict, defined by path of keys.
+
+ Args:
+ source (dict): Source dict to extract from
+ lpath (list[str]): sequence of keys
+
+ Returns: source, if lpath is empty, else
+ {key : source[..]..[key]} for key the last element of lpath, if exists
+ {} otherwise
+ """
+ if not isinstance(source, dict):
+ raise TypeError("source must be of type dict")
+ if not isinstance(lpath, list):
+ raise TypeError("path must be of type list")
+ if not lpath:
+ return source
+
+ ret = _get_sub_dict(source, lpath)
+
+ if get_first_key and lpath and ret:
+ tmp = next(iter(ret.values()))
+ if not isinstance(tmp, dict):
+ raise TypeError("Data under node is not of type dict")
+ ret = tmp
+
+ return ret
+
+def dict_search(path, dict_object):
+ """ Traverse Python dictionary (dict_object) delimited by dot (.).
+ Return value of key if found, None otherwise.
+
+ This is faster implementation then jmespath.search('foo.bar', dict_object)"""
+ if not isinstance(dict_object, dict) or not path:
+ return None
+
+ parts = path.split('.')
+ inside = parts[:-1]
+ if not inside:
+ if path not in dict_object:
+ return None
+ return dict_object[path]
+ c = dict_object
+ for p in parts[:-1]:
+ c = c.get(p, {})
+ return c.get(parts[-1], None)
+
+def dict_search_args(dict_object, *path):
+ # Traverse dictionary using variable arguments
+ # Added due to above function not allowing for '.' in the key names
+ # Example: dict_search_args(some_dict, 'key', 'subkey', 'subsubkey', ...)
+ if not isinstance(dict_object, dict) or not path:
+ return None
+
+ for item in path:
+ if item not in dict_object:
+ return None
+ dict_object = dict_object[item]
+ return dict_object
+
+def dict_search_recursive(dict_object, key, path=[]):
+ """ Traverse a dictionary recurisvely and return the value of the key
+ we are looking for.
+
+ Thankfully copied from https://stackoverflow.com/a/19871956
+
+ Modified to yield optional path to found keys
+ """
+ if isinstance(dict_object, list):
+ for i in dict_object:
+ new_path = path + [i]
+ for x in dict_search_recursive(i, key, new_path):
+ yield x
+ elif isinstance(dict_object, dict):
+ if key in dict_object:
+ new_path = path + [key]
+ yield dict_object[key], new_path
+ for k, j in dict_object.items():
+ new_path = path + [k]
+ for x in dict_search_recursive(j, key, new_path):
+ yield x
+
+def dict_to_list(d, save_key_to=None):
+ """ Convert a dict to a list of dicts.
+
+ Optionally, save the original key of the dict inside
+ dicts stores in that list.
+ """
+ def save_key(i, k):
+ if isinstance(i, dict):
+ i[save_key_to] = k
+ return
+ elif isinstance(i, list):
+ for _i in i:
+ save_key(_i, k)
+ else:
+ raise ValueError(f"Cannot save the key: the item is {type(i)}, not a dict")
+
+ collect = []
+
+ for k,_ in d.items():
+ item = d[k]
+ if save_key_to is not None:
+ save_key(item, k)
+ if isinstance(item, list):
+ collect += item
+ else:
+ collect.append(item)
+
+ return collect
diff --git a/python/vyos/xml/load.py b/python/vyos/xml/load.py
index c3022f3d6..f842ff9ce 100644
--- a/python/vyos/xml/load.py
+++ b/python/vyos/xml/load.py
@@ -71,16 +71,12 @@ def _merge(dict1, dict2):
continue
if isinstance(dict1[k], dict) and isinstance(dict2[k], dict):
dict1[k] = _merge(dict1[k], dict2[k])
- elif isinstance(dict1[k], dict) and isinstance(dict2[k], dict):
+ elif isinstance(dict1[k], list) and isinstance(dict2[k], list):
dict1[k].extend(dict2[k])
elif dict1[k] == dict2[k]:
- # A definition shared between multiple files
- if k in (kw.valueless, kw.multi, kw.hidden, kw.node, kw.summary, kw.owner, kw.priority):
- continue
- _fatal()
- raise RuntimeError('parsing issue - undefined leaf?')
+ continue
else:
- raise RuntimeError('parsing issue - we messed up?')
+ dict1[k] = dict2[k]
return dict1
@@ -131,7 +127,7 @@ def _format_nodes(inside, conf, xml):
name = node.pop('@name')
into = inside + [name]
if name in r:
- r[name].update(_format_node(into, node, xml))
+ _merge(r[name], _format_node(into, node, xml))
else:
r[name] = _format_node(into, node, xml)
r[name][kw.node] = nodename
@@ -141,7 +137,7 @@ def _format_nodes(inside, conf, xml):
name = node.pop('@name')
into = inside + [name]
if name in r:
- r[name].update(_format_node(inside + [name], node, xml))
+ _merge(r[name], _format_node(inside + [name], node, xml))
else:
r[name] = _format_node(inside + [name], node, xml)
r[name][kw.node] = nodename
@@ -180,10 +176,10 @@ def _format_node(inside, conf, xml):
if isinstance(conf, list):
for child in children:
- r = _safe_update(r, _format_nodes(inside, child, xml))
+ _merge(r, _format_nodes(inside, child, xml))
else:
child = children
- r = _safe_update(r, _format_nodes(inside, child, xml))
+ _merge(r, _format_nodes(inside, child, xml))
elif 'properties' in keys:
properties = conf.pop('properties')
diff --git a/smoketest/configs/vrf-bgp-pppoe-underlay b/smoketest/configs/vrf-bgp-pppoe-underlay
new file mode 100644
index 000000000..cba35eab1
--- /dev/null
+++ b/smoketest/configs/vrf-bgp-pppoe-underlay
@@ -0,0 +1,473 @@
+interfaces {
+ bridge br50 {
+ address 192.168.0.1/24
+ member {
+ interface eth0.50 {
+ }
+ interface eth2 {
+ }
+ interface eth3 {
+ }
+ }
+ }
+ dummy dum0 {
+ address 100.64.51.252/32
+ address 2001:db8:200:ffff::1/128
+ vrf vyos-test-01
+ }
+ ethernet eth0 {
+ offload {
+ gro
+ gso
+ rps
+ sg
+ tso
+ }
+ ring-buffer {
+ rx 256
+ tx 256
+ }
+ vif 5 {
+ address 2001:db8:200:f0::114/64
+ address 100.64.50.121/28
+ vrf vyos-test-01
+ }
+ vif 10 {
+ address 2001:db8:200:10::ffff/64
+ address 2001:db8:200::ffff/64
+ address 100.64.50.62/26
+ vrf vyos-test-01
+ }
+ vif 15 {
+ address 100.64.50.78/28
+ address 2001:db8:200:15::ffff/64
+ vrf vyos-test-01
+ }
+ vif 50 {
+ description "Member of bridge br50"
+ }
+ vif 110 {
+ address 100.64.51.190/27
+ address 100.64.51.158/28
+ address 2001:db8:200:101::ffff/64
+ vrf vyos-test-01
+ }
+ vif 410 {
+ address 100.64.51.206/28
+ address 2001:db8:200:104::ffff/64
+ vrf vyos-test-01
+ }
+ vif 500 {
+ address 100.64.51.238/28
+ address 2001:db8:200:50::ffff/64
+ vrf vyos-test-01
+ }
+ vif 520 {
+ address 100.64.50.190/28
+ address 2001:db8:200:520::ffff/64
+ vrf vyos-test-01
+ }
+ vif 666 {
+ address 2001:db8:200:ff::101:1/112
+ address 100.64.51.223/31
+ vrf vyos-test-01
+ }
+ vif 800 {
+ address 2001:db8:200:ff::104:1/112
+ address 100.64.51.212/31
+ vrf vyos-test-01
+ }
+ vif 810 {
+ address 100.64.51.30/27
+ address 2001:db8:200:102::ffff/64
+ vrf vyos-test-01
+ }
+ }
+ ethernet eth1 {
+ offload {
+ gro
+ gso
+ rps
+ sg
+ tso
+ }
+ ring-buffer {
+ rx 256
+ tx 256
+ }
+ }
+ ethernet eth2 {
+ offload {
+ gro
+ gso
+ sg
+ tso
+ }
+ }
+ ethernet eth3 {
+ offload {
+ gro
+ gso
+ sg
+ tso
+ }
+ }
+ loopback lo {
+ }
+ pppoe pppoe7 {
+ authentication {
+ password vyos
+ username vyos
+ }
+ dhcpv6-options {
+ pd 0 {
+ interface br50 {
+ address 1
+ }
+ length 56
+ }
+ }
+ ip {
+ adjust-mss 1452
+ }
+ ipv6 {
+ address {
+ autoconf
+ }
+ adjust-mss 1432
+ }
+ mtu 1492
+ no-peer-dns
+ source-interface eth1
+ }
+ virtual-ethernet veth0 {
+ address 100.64.51.220/31
+ address 2001:db8:200:ff::105:1/112
+ description "Core: connect vyos-test-01 and default VRF"
+ peer-name veth1
+ }
+ virtual-ethernet veth1 {
+ address 100.64.51.221/31
+ address 2001:db8:200:ff::105:2/112
+ description "Core: connect vyos-test-01 and default VRF"
+ peer-name veth0
+ vrf vyos-test-01
+ }
+ wireguard wg500 {
+ address 100.64.51.209/31
+ mtu 1500
+ peer A {
+ address 192.0.2.1
+ allowed-ips 0.0.0.0/0
+ port 5500
+ public-key KGSXF4QckzGe7f7CT+r6VZ5brOD/pVYk8yvrxOQ+X0Y=
+ }
+ port 5500
+ private-key iLJh6Me6AdPJtNv3dgGhUbtyFxExxmNU4v0Fs6YE2Xc=
+ vrf vyos-test-01
+ }
+ wireguard wg501 {
+ address 2001:db8:200:ff::102:2/112
+ mtu 1500
+ peer A {
+ address 2001:db8:300::1
+ allowed-ips ::/0
+ port 5501
+ public-key OF+1OJ+VfQ0Yw1mgVtQ2ion4CnAdy8Bvx7yEiO4+Pn8=
+ }
+ port 5501
+ private-key 0MP5X0PW58O4q2LDpuIXgZ0ySyAoWH8/kdpvQccCbUU=
+ vrf vyos-test-01
+ }
+ wireguard wg666 {
+ address 172.29.0.0/31
+ mtu 1500
+ peer B {
+ allowed-ips 0.0.0.0/0
+ public-key 2HT+RfwcqJMYNYzdmtmpem8Ht0dL37o31APHVwmh024=
+ }
+ port 50666
+ private-key zvPnp2MLAoX7SotuHLFLDyy4sdlD7ttbD1xNEqA3mkU=
+ }
+}
+nat {
+ source {
+ rule 100 {
+ outbound-interface pppoe7
+ source {
+ address 192.168.0.0/24
+ }
+ translation {
+ address masquerade
+ }
+ }
+ }
+}
+policy {
+ prefix-list AS100-origin-v4 {
+ rule 10 {
+ action permit
+ prefix 100.64.0.0/12
+ }
+ rule 100 {
+ action permit
+ prefix 0.0.0.0/0
+ }
+ }
+ prefix-list AS200-origin-v4 {
+ rule 10 {
+ action permit
+ prefix 10.0.0.0/8
+ }
+ rule 20 {
+ action permit
+ prefix 172.16.0.0/12
+ }
+
+ }
+ prefix-list6 AS100-origin-v6 {
+ rule 10 {
+ action permit
+ prefix 2001:db8:200::/40
+ }
+ }
+ prefix-list6 AS200-origin-v6 {
+ rule 10 {
+ action permit
+ prefix 2001:db8:100::/40
+ }
+ }
+}
+protocols {
+ static {
+ route 192.0.2.255/32 {
+ interface pppoe7 {
+ }
+ }
+ route 100.64.50.0/23 {
+ next-hop 100.64.51.221 {
+ }
+ }
+ route6 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff/128 {
+ interface pppoe7 {
+ }
+ }
+ }
+}
+qos {
+ interface pppoe7 {
+ egress isp-out
+ }
+ policy {
+ shaper isp-out {
+ bandwidth 38mbit
+ default {
+ bandwidth 100%
+ burst 15k
+ queue-limit 1000
+ queue-type fq-codel
+ }
+ }
+ }
+}
+service {
+ router-advert {
+ interface br50 {
+ prefix ::/64 {
+ preferred-lifetime 2700
+ valid-lifetime 5400
+ }
+ }
+ interface eth0.500 {
+ default-preference high
+ name-server 2001:db8:200::1
+ name-server 2001:db8:200::2
+ prefix 2001:db8:200:50::/64 {
+ valid-lifetime infinity
+ }
+ }
+ interface eth0.520 {
+ default-preference high
+ name-server 2001:db8:200::1
+ name-server 2001:db8:200::2
+ prefix 2001:db8:200:520::/64 {
+ valid-lifetime infinity
+ }
+ }
+ }
+ ssh {
+ disable-host-validation
+ dynamic-protection {
+ allow-from 100.64.0.0/10
+ allow-from 2001:db8:200::/40
+ }
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ conntrack {
+ modules {
+ ftp
+ h323
+ nfs
+ pptp
+ sip
+ sqlnet
+ tftp
+ }
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ domain-name vyos.net
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ name-server 192.168.0.1
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+vrf {
+ bind-to-all
+ name vyos-test-01 {
+ protocols {
+ bgp {
+ address-family {
+ ipv4-unicast {
+ network 100.64.50.0/23 {
+ }
+ }
+ ipv6-unicast {
+ network 2001:db8:200:ffff::1/128 {
+ }
+ }
+ }
+ neighbor 100.64.51.208 {
+ peer-group AS100v4
+ }
+ neighbor 100.64.51.222 {
+ address-family {
+ ipv4-unicast {
+ default-originate {
+ }
+ maximum-prefix 10
+ prefix-list {
+ export AS100-origin-v4
+ import AS200-origin-v4
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as 200
+ }
+ neighbor 100.64.51.251 {
+ peer-group AS100v4
+ shutdown
+ }
+ neighbor 100.64.51.254 {
+ peer-group AS100v4
+ shutdown
+ }
+ neighbor 2001:db8:200:ffff::2 {
+ peer-group AS100v6
+ shutdown
+ }
+ neighbor 2001:db8:200:ffff::a {
+ peer-group AS100v6
+ }
+ neighbor 2001:db8:200:ff::101:2 {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 10
+ prefix-list {
+ export AS100-origin-v6
+ import AS200-origin-v6
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as 200
+ }
+ peer-group AS100v4 {
+ address-family {
+ ipv4-unicast {
+ nexthop-self {
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as internal
+ update-source dum0
+ }
+ peer-group AS100v6 {
+ address-family {
+ ipv6-unicast {
+ nexthop-self {
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as internal
+ update-source dum0
+ }
+ system-as 100
+ }
+ static {
+ route 192.168.0.0/24 {
+ next-hop 100.64.51.220 {
+ }
+ }
+ route 100.64.50.0/23 {
+ blackhole {
+ }
+ }
+ route 100.64.51.32/27 {
+ next-hop 100.64.51.5 {
+ }
+ }
+ route6 2001:db8:2fe:ffff::/64 {
+ next-hop 2001:db8:200:102::5 {
+ }
+ }
+ }
+ }
+ table 1000
+ }
+}
+
+// Warning: Do not remove the following line.
+// vyos-config-version: "bgp@3:broadcast-relay@1:cluster@1:config-management@1:conntrack@3:conntrack-sync@2:container@1:dhcp-relay@2:dhcp-server@6:dhcpv6-server@1:dns-forwarding@3:firewall@9:flow-accounting@1:https@4:ids@1:interfaces@28:ipoe-server@1:ipsec@12:isis@2:l2tp@4:lldp@1:mdns@1:monitoring@1:nat@5:nat66@1:ntp@2:openconnect@2:ospf@1:policy@5:pppoe-server@6:pptp@2:qos@2:quagga@10:rpki@1:salt@1:snmp@3:ssh@2:sstp@4:system@25:vrf@3:vrrp@3:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2"
+// Release version: 1.4-rolling-202303160317
diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py
index 3a4ef666a..f35cdaa4c 100755
--- a/smoketest/scripts/cli/test_policy.py
+++ b/smoketest/scripts/cli/test_policy.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
@@ -1071,6 +1071,22 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
},
},
},
+ 'match-protocol' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'match' : {
+ 'protocol' : 'static',
+ },
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'match' : {
+ 'protocol' : 'bgp',
+ },
+ },
+ },
+ },
'relative-metric' : {
'rule' : {
'10' : {
@@ -1202,6 +1218,8 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
self.cli_set(path + ['rule', rule, 'match', 'rpki', 'notfound'])
if 'rpki-valid' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'rpki', 'valid'])
+ if 'protocol' in rule_config['match']:
+ self.cli_set(path + ['rule', rule, 'match', 'protocol', rule_config['match']['protocol']])
if 'tag' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'tag', rule_config['match']['tag']])
@@ -1368,6 +1386,9 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
if 'peer' in rule_config['match']:
tmp = f'match peer {rule_config["match"]["peer"]}'
self.assertIn(tmp, config)
+ if 'protocol' in rule_config['match']:
+ tmp = f'match source-protocol {rule_config["match"]["protocol"]}'
+ self.assertIn(tmp, config)
if 'rpki-invalid' in rule_config['match']:
tmp = f'match rpki invalid'
self.assertIn(tmp, config)
diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py
index bc023f3f2..275f1a1df 100755
--- a/smoketest/scripts/cli/test_protocols_static.py
+++ b/smoketest/scripts/cli/test_protocols_static.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
@@ -31,6 +31,8 @@ routes = {
'192.0.2.100' : { 'distance' : '100' },
'192.0.2.110' : { 'distance' : '110', 'interface' : 'eth0' },
'192.0.2.120' : { 'distance' : '120', 'disable' : '' },
+ '192.0.2.130' : { 'bfd' : '' },
+ '192.0.2.140' : { 'bfd_source' : '192.0.2.10' },
},
'interface' : {
'eth0' : { 'distance' : '130' },
@@ -67,6 +69,8 @@ routes = {
'2001:db8::1' : { 'distance' : '10' },
'2001:db8::2' : { 'distance' : '20', 'interface' : 'eth0' },
'2001:db8::3' : { 'distance' : '30', 'disable' : '' },
+ '2001:db8::4' : { 'bfd' : '' },
+ '2001:db8::5' : { 'bfd_source' : '2001:db8::ffff' },
},
'interface' : {
'eth0' : { 'distance' : '40', 'vrf' : 'black' },
@@ -95,6 +99,7 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestProtocolsStatic, cls).setUpClass()
+ cls.cli_delete(cls, ['vrf'])
cls.cli_set(cls, ['vrf', 'name', 'black', 'table', '43210'])
@classmethod
@@ -116,6 +121,7 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
def test_01_static(self):
+ bfd_profile = 'vyos-test'
for route, route_config in routes.items():
route_type = 'route'
if is_ipv6(route):
@@ -132,6 +138,10 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
self.cli_set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']])
if 'vrf' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']])
+ if 'bfd' in next_hop_config:
+ self.cli_set(base + ['next-hop', next_hop, 'bfd', 'profile', bfd_profile ])
+ if 'bfd_source' in next_hop_config:
+ self.cli_set(base + ['next-hop', next_hop, 'bfd', 'multi-hop', 'source', next_hop_config['bfd_source'], 'profile', bfd_profile])
if 'interface' in route_config:
@@ -186,6 +196,10 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
tmp += ' ' + next_hop_config['distance']
if 'vrf' in next_hop_config:
tmp += ' nexthop-vrf ' + next_hop_config['vrf']
+ if 'bfd' in next_hop_config:
+ tmp += ' bfd profile ' + bfd_profile
+ if 'bfd_source' in next_hop_config:
+ tmp += ' bfd multi-hop source ' + next_hop_config['bfd_source'] + ' profile ' + bfd_profile
if 'disable' in next_hop_config:
self.assertNotIn(tmp, frrconfig)
diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py
index 8016c0105..926616727 100755
--- a/smoketest/scripts/cli/test_vrf.py
+++ b/smoketest/scripts/cli/test_vrf.py
@@ -61,7 +61,8 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
self.assertNotIn(vrf, interfaces())
def test_vrf_vni_and_table_id(self):
- table = '1000'
+ base_table = '1000'
+ table = base_table
for vrf in vrfs:
base = base_path + ['name', vrf]
description = f'VyOS-VRF-{vrf}'
@@ -82,7 +83,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify VRF configuration
- table = '1000'
+ table = base_table
iproute2_config = read_file('/etc/iproute2/rt_tables.d/vyos-vrf.conf')
for vrf in vrfs:
description = f'VyOS-VRF-{vrf}'
@@ -196,7 +197,8 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
self.cli_delete(['interfaces', section, interface, 'vrf'])
def test_vrf_static_route(self):
- table = '100'
+ base_table = '100'
+ table = base_table
for vrf in vrfs:
next_hop = f'192.0.{table}.1'
prefix = f'10.0.{table}.0/24'
@@ -217,13 +219,12 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify VRF configuration
- table = '100'
+ table = base_table
for vrf in vrfs:
next_hop = f'192.0.{table}.1'
prefix = f'10.0.{table}.0/24'
self.assertTrue(vrf in interfaces())
- vrf_if = Interface(vrf)
frrconfig = self.getFRRconfig(f'vrf {vrf}')
self.assertIn(f' vni {table}', frrconfig)
@@ -369,5 +370,98 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
route_map = f'route-map-{vrf}-{protocol}'
self.assertIn(f' ipv6 protocol {protocol} route-map {route_map}', frrconfig)
+ def test_vrf_vni_duplicates(self):
+ base_table = '6300'
+ table = base_table
+ for vrf in vrfs:
+ base = base_path + ['name', vrf]
+ self.cli_set(base + ['table', str(table)])
+ self.cli_set(base + ['vni', '100'])
+ table = str(int(table) + 1)
+
+ # L3VNIs can only be used once
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ table = base_table
+ for vrf in vrfs:
+ base = base_path + ['name', vrf]
+ self.cli_set(base + ['vni', str(table)])
+ table = str(int(table) + 1)
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify VRF configuration
+ table = base_table
+ for vrf in vrfs:
+ self.assertTrue(vrf in interfaces())
+
+ frrconfig = self.getFRRconfig(f'vrf {vrf}')
+ self.assertIn(f' vni {table}', frrconfig)
+ # Increment table ID for the next run
+ table = str(int(table) + 1)
+
+ def test_vrf_vni_add_change_remove(self):
+ base_table = '6300'
+ table = base_table
+ for vrf in vrfs:
+ base = base_path + ['name', vrf]
+ self.cli_set(base + ['table', str(table)])
+ self.cli_set(base + ['vni', str(table)])
+ table = str(int(table) + 1)
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify VRF configuration
+ table = base_table
+ for vrf in vrfs:
+ self.assertTrue(vrf in interfaces())
+
+ frrconfig = self.getFRRconfig(f'vrf {vrf}')
+ self.assertIn(f' vni {table}', frrconfig)
+ # Increment table ID for the next run
+ table = str(int(table) + 1)
+
+ # Now change all L3VNIs (increment 2)
+ # We must also change the base_table number as we probably could get
+ # duplicate VNI's during the test as VNIs are applied 1:1 to FRR
+ base_table = '5000'
+ table = base_table
+ for vrf in vrfs:
+ base = base_path + ['name', vrf]
+ self.cli_set(base + ['vni', str(table)])
+ table = str(int(table) + 2)
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify VRF configuration
+ table = base_table
+ for vrf in vrfs:
+ self.assertTrue(vrf in interfaces())
+
+ frrconfig = self.getFRRconfig(f'vrf {vrf}')
+ self.assertIn(f' vni {table}', frrconfig)
+ # Increment table ID for the next run
+ table = str(int(table) + 2)
+
+ # Now delete all the VNIs
+ for vrf in vrfs:
+ base = base_path + ['name', vrf]
+ self.cli_delete(base + ['vni'])
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify no VNI is defined
+ for vrf in vrfs:
+ self.assertTrue(vrf in interfaces())
+
+ frrconfig = self.getFRRconfig(f'vrf {vrf}')
+ self.assertNotIn('vni', frrconfig)
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/dns_forwarding.py b/src/conf_mode/dns_forwarding.py
index 36c1098fe..0d86c6a52 100755
--- a/src/conf_mode/dns_forwarding.py
+++ b/src/conf_mode/dns_forwarding.py
@@ -99,7 +99,7 @@ def get_config(config=None):
recorddata = zonedata['records']
- for rtype in [ 'a', 'aaaa', 'cname', 'mx', 'ptr', 'txt', 'spf', 'srv', 'naptr' ]:
+ for rtype in [ 'a', 'aaaa', 'cname', 'mx', 'ns', 'ptr', 'txt', 'spf', 'srv', 'naptr' ]:
if rtype not in recorddata:
continue
for subnode in recorddata[rtype]:
@@ -113,7 +113,7 @@ def get_config(config=None):
rdata = dict_merge(rdefaults, rdata)
if not 'address' in rdata:
- dns['authoritative_zone_errors'].append('{}.{}: at least one address is required'.format(subnode, node))
+ dns['authoritative_zone_errors'].append(f'{subnode}.{node}: at least one address is required')
continue
if subnode == 'any':
@@ -126,12 +126,12 @@ def get_config(config=None):
'ttl': rdata['ttl'],
'value': address
})
- elif rtype in ['cname', 'ptr']:
+ elif rtype in ['cname', 'ptr', 'ns']:
rdefaults = defaults(base + ['authoritative-domain', 'records', rtype]) # T2665
rdata = dict_merge(rdefaults, rdata)
if not 'target' in rdata:
- dns['authoritative_zone_errors'].append('{}.{}: target is required'.format(subnode, node))
+ dns['authoritative_zone_errors'].append(f'{subnode}.{node}: target is required')
continue
zone['records'].append({
@@ -146,7 +146,7 @@ def get_config(config=None):
rdata = dict_merge(rdefaults, rdata)
if not 'server' in rdata:
- dns['authoritative_zone_errors'].append('{}.{}: at least one server is required'.format(subnode, node))
+ dns['authoritative_zone_errors'].append(f'{subnode}.{node}: at least one server is required')
continue
for servername in rdata['server']:
@@ -164,7 +164,7 @@ def get_config(config=None):
rdata = dict_merge(rdefaults, rdata)
if not 'value' in rdata:
- dns['authoritative_zone_errors'].append('{}.{}: at least one value is required'.format(subnode, node))
+ dns['authoritative_zone_errors'].append(f'{subnode}.{node}: at least one value is required')
continue
for value in rdata['value']:
@@ -179,7 +179,7 @@ def get_config(config=None):
rdata = dict_merge(rdefaults, rdata)
if not 'value' in rdata:
- dns['authoritative_zone_errors'].append('{}.{}: value is required'.format(subnode, node))
+ dns['authoritative_zone_errors'].append(f'{subnode}.{node}: value is required')
continue
zone['records'].append({
@@ -194,7 +194,7 @@ def get_config(config=None):
rdata = dict_merge(rdefaults, rdata)
if not 'entry' in rdata:
- dns['authoritative_zone_errors'].append('{}.{}: at least one entry is required'.format(subnode, node))
+ dns['authoritative_zone_errors'].append(f'{subnode}.{node}: at least one entry is required')
continue
for entryno in rdata['entry']:
@@ -203,11 +203,11 @@ def get_config(config=None):
entrydata = dict_merge(entrydefaults, entrydata)
if not 'hostname' in entrydata:
- dns['authoritative_zone_errors'].append('{}.{}: hostname is required for entry {}'.format(subnode, node, entryno))
+ dns['authoritative_zone_errors'].append(f'{subnode}.{node}: hostname is required for entry {entryno}')
continue
if not 'port' in entrydata:
- dns['authoritative_zone_errors'].append('{}.{}: port is required for entry {}'.format(subnode, node, entryno))
+ dns['authoritative_zone_errors'].append(f'{subnode}.{node}: port is required for entry {entryno}')
continue
zone['records'].append({
@@ -223,7 +223,7 @@ def get_config(config=None):
if not 'rule' in rdata:
- dns['authoritative_zone_errors'].append('{}.{}: at least one rule is required'.format(subnode, node))
+ dns['authoritative_zone_errors'].append(f'{subnode}.{node}: at least one rule is required')
continue
for ruleno in rdata['rule']:
diff --git a/src/conf_mode/load-balancing-wan.py b/src/conf_mode/load-balancing-wan.py
index 11840249f..7086aaf8b 100755
--- a/src/conf_mode/load-balancing-wan.py
+++ b/src/conf_mode/load-balancing-wan.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 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
@@ -14,17 +14,25 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import os
from sys import exit
+from shutil import rmtree
+from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import node_changed
-from vyos.util import call
+from vyos.configdict import dict_merge
+from vyos.util import cmd
+from vyos.template import render
+from vyos.xml import defaults
from vyos import ConfigError
-from pprint import pprint
from vyos import airbag
airbag.enable()
+load_balancing_dir = '/run/load-balance'
+load_balancing_conf_file = f'{load_balancing_dir}/wlb.conf'
+systemd_service = 'vyos-wan-load-balance.service'
+
def get_config(config=None):
if config:
@@ -33,27 +41,135 @@ def get_config(config=None):
conf = Config()
base = ['load-balancing', 'wan']
- lb = conf.get_config_dict(base, get_first_key=True,
- no_tag_node_value_mangle=True)
+ lb = conf.get_config_dict(base,
+ get_first_key=True,
+ key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True)
+
+ # We have gathered the dict representation of the CLI, but there are default
+ # options which we need to update into the dictionary retrived.
+ default_values = defaults(base)
+ # lb base default values can not be merged here - remove and add them later
+ if 'interface_health' in default_values:
+ del default_values['interface_health']
+ if 'rule' in default_values:
+ del default_values['rule']
+ lb = dict_merge(default_values, lb)
+
+ if 'interface_health' in lb:
+ for iface in lb.get('interface_health'):
+ default_values_iface = defaults(base + ['interface-health'])
+ if 'test' in default_values_iface:
+ del default_values_iface['test']
+ lb['interface_health'][iface] = dict_merge(
+ default_values_iface, lb['interface_health'][iface])
+ if 'test' in lb['interface_health'][iface]:
+ for node_test in lb['interface_health'][iface]['test']:
+ default_values_test = defaults(base +
+ ['interface-health', 'test'])
+ lb['interface_health'][iface]['test'][node_test] = dict_merge(
+ default_values_test,
+ lb['interface_health'][iface]['test'][node_test])
+
+ if 'rule' in lb:
+ for rule in lb.get('rule'):
+ default_values_rule = defaults(base + ['rule'])
+ if 'interface' in default_values_rule:
+ del default_values_rule['interface']
+ lb['rule'][rule] = dict_merge(default_values_rule, lb['rule'][rule])
+ if not conf.exists(base + ['rule', rule, 'limit']):
+ del lb['rule'][rule]['limit']
+ if 'interface' in lb['rule'][rule]:
+ for iface in lb['rule'][rule]['interface']:
+ default_values_rule_iface = defaults(base + ['rule', 'interface'])
+ lb['rule'][rule]['interface'][iface] = dict_merge(default_values_rule_iface, lb['rule'][rule]['interface'][iface])
- pprint(lb)
return lb
+
def verify(lb):
- return None
+ if not lb:
+ return None
+
+ if 'interface_health' not in lb:
+ raise ConfigError(
+ 'A valid WAN load-balance configuration requires an interface with a nexthop!'
+ )
+
+ for interface, interface_config in lb['interface_health'].items():
+ if 'nexthop' not in interface_config:
+ raise ConfigError(
+ f'interface-health {interface} nexthop must be specified!')
+
+ if 'test' in interface_config:
+ for test_rule, test_config in interface_config['test'].items():
+ if 'type' in test_config:
+ if test_config['type'] == 'user-defined' and 'test_script' not in test_config:
+ raise ConfigError(
+ f'test {test_rule} script must be defined for test-script!'
+ )
+
+ if 'rule' not in lb:
+ Warning(
+ 'At least one rule with an (outbound) interface must be defined for WAN load balancing to be active!'
+ )
+ else:
+ for rule, rule_config in lb['rule'].items():
+ if 'inbound_interface' not in rule_config:
+ raise ConfigError(f'rule {rule} inbound-interface must be specified!')
+ if {'failover', 'exclude'} <= set(rule_config):
+ raise ConfigError(f'rule {rule} failover cannot be configured with exclude!')
+ if {'limit', 'exclude'} <= set(rule_config):
+ raise ConfigError(f'rule {rule} limit cannot be used with exclude!')
+ if 'interface' not in rule_config:
+ if 'exclude' not in rule_config:
+ Warning(
+ f'rule {rule} will be inactive because no (outbound) interfaces have been defined for this rule'
+ )
+ for direction in {'source', 'destination'}:
+ if direction in rule_config:
+ if 'protocol' in rule_config and 'port' in rule_config[
+ direction]:
+ if rule_config['protocol'] not in {'tcp', 'udp'}:
+ raise ConfigError('ports can only be specified when protocol is "tcp" or "udp"')
def generate(lb):
if not lb:
+ # Delete /run/load-balance/wlb.conf
+ if os.path.isfile(load_balancing_conf_file):
+ os.unlink(load_balancing_conf_file)
+ # Delete old directories
+ if os.path.isdir(load_balancing_dir):
+ rmtree(load_balancing_dir, ignore_errors=True)
+ if os.path.exists('/var/run/load-balance/wlb.out'):
+ os.unlink('/var/run/load-balance/wlb.out')
+
return None
+ # Create load-balance dir
+ if not os.path.isdir(load_balancing_dir):
+ os.mkdir(load_balancing_dir)
+
+ render(load_balancing_conf_file, 'load-balancing/wlb.conf.j2', lb)
+
return None
def apply(lb):
+ if not lb:
+ try:
+ cmd(f'systemctl stop {systemd_service}')
+ except Exception as e:
+ print(f"Error message: {e}")
+
+ else:
+ cmd('sudo sysctl -w net.netfilter.nf_conntrack_acct=1')
+ cmd(f'systemctl restart {systemd_service}')
return None
+
if __name__ == '__main__':
try:
c = get_config()
diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py
index 66505e58d..b23584bdb 100755
--- a/src/conf_mode/protocols_bgp.py
+++ b/src/conf_mode/protocols_bgp.py
@@ -50,16 +50,24 @@ def get_config(config=None):
bgp = conf.get_config_dict(base, key_mangling=('-', '_'),
get_first_key=True, no_tag_node_value_mangle=True)
- # Assign the name of our VRF context. This MUST be done before the return
- # statement below, else on deletion we will delete the default instance
- # instead of the VRF instance.
- if vrf: bgp.update({'vrf' : vrf})
-
bgp['dependent_vrfs'] = conf.get_config_dict(['vrf', 'name'],
key_mangling=('-', '_'),
get_first_key=True,
no_tag_node_value_mangle=True)
+ # Assign the name of our VRF context. This MUST be done before the return
+ # statement below, else on deletion we will delete the default instance
+ # instead of the VRF instance.
+ if vrf:
+ bgp.update({'vrf' : vrf})
+ # We can not delete the BGP VRF instance if there is a L3VNI configured
+ tmp = ['vrf', 'name', vrf, 'vni']
+ if conf.exists(tmp):
+ bgp.update({'vni' : conf.return_value(tmp)})
+ # We can safely delete ourself from the dependent vrf list
+ if vrf in bgp['dependent_vrfs']:
+ del bgp['dependent_vrfs'][vrf]
+
bgp['dependent_vrfs'].update({'default': {'protocols': {
'bgp': conf.get_config_dict(base_path, key_mangling=('-', '_'),
get_first_key=True,
@@ -202,9 +210,13 @@ def verify(bgp):
if 'vrf' in bgp:
# Cannot delete vrf if it exists in import vrf list in other vrfs
for tmp_afi in ['ipv4_unicast', 'ipv6_unicast']:
- if verify_vrf_as_import(bgp['vrf'],tmp_afi,bgp['dependent_vrfs']):
- raise ConfigError(f'Cannot delete vrf {bgp["vrf"]} instance, ' \
- 'Please unconfigure import vrf commands!')
+ if verify_vrf_as_import(bgp['vrf'], tmp_afi, bgp['dependent_vrfs']):
+ raise ConfigError(f'Cannot delete VRF instance "{bgp["vrf"]}", ' \
+ 'unconfigure "import vrf" commands!')
+ # We can not delete the BGP instance if a L3VNI instance exists
+ if 'vni' in bgp:
+ raise ConfigError(f'Cannot delete VRF instance "{bgp["vrf"]}", ' \
+ f'unconfigure VNI "{bgp["vni"]}" first!')
else:
# We are running in the default VRF context, thus we can not delete
# our main BGP instance if there are dependent BGP VRF instances.
@@ -429,7 +441,6 @@ def verify(bgp):
f'{afi} administrative distance {key}!')
if afi in ['ipv4_unicast', 'ipv6_unicast']:
-
vrf_name = bgp['vrf'] if dict_search('vrf', bgp) else 'default'
# Verify if currant VRF contains rd and route-target options
# and does not exist in import list in other VRFs
@@ -478,6 +489,15 @@ def verify(bgp):
tmp = dict_search(f'route_map.vpn.{export_import}', afi_config)
if tmp: verify_route_map(tmp, bgp)
+ # Checks only required for L2VPN EVPN
+ if afi in ['l2vpn_evpn']:
+ if 'vni' in afi_config:
+ for vni, vni_config in afi_config['vni'].items():
+ if 'rd' in vni_config and 'advertise_all_vni' not in afi_config:
+ raise ConfigError('BGP EVPN "rd" requires "advertise-all-vni" to be set!')
+ if 'route_target' in vni_config and 'advertise_all_vni' not in afi_config:
+ raise ConfigError('BGP EVPN "route-target" requires "advertise-all-vni" to be set!')
+
return None
def generate(bgp):
diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py
index af2937db8..ecca87db0 100755
--- a/src/conf_mode/protocols_isis.py
+++ b/src/conf_mode/protocols_isis.py
@@ -129,7 +129,7 @@ def verify(isis):
vrf = isis['vrf']
tmp = get_interface_config(interface)
if 'master' not in tmp or tmp['master'] != vrf:
- raise ConfigError(f'Interface {interface} is not a member of VRF {vrf}!')
+ raise ConfigError(f'Interface "{interface}" is not a member of VRF "{vrf}"!')
# If md5 and plaintext-password set at the same time
for password in ['area_password', 'domain_password']:
diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py
index fbb876123..b73483470 100755
--- a/src/conf_mode/protocols_ospf.py
+++ b/src/conf_mode/protocols_ospf.py
@@ -196,7 +196,7 @@ def verify(ospf):
vrf = ospf['vrf']
tmp = get_interface_config(interface)
if 'master' not in tmp or tmp['master'] != vrf:
- raise ConfigError(f'Interface {interface} is not a member of VRF {vrf}!')
+ raise ConfigError(f'Interface "{interface}" is not a member of VRF "{vrf}"!')
# Segment routing checks
if dict_search('segment_routing.global_block', ospf):
diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py
index ee1fdd399..cb21bd83c 100755
--- a/src/conf_mode/protocols_ospfv3.py
+++ b/src/conf_mode/protocols_ospfv3.py
@@ -138,7 +138,7 @@ def verify(ospfv3):
vrf = ospfv3['vrf']
tmp = get_interface_config(interface)
if 'master' not in tmp or tmp['master'] != vrf:
- raise ConfigError(f'Interface {interface} is not a member of VRF {vrf}!')
+ raise ConfigError(f'Interface "{interface}" is not a member of VRF "{vrf}"!')
return None
diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py
index a7ef4cb5c..0b983293e 100755
--- a/src/conf_mode/vrf.py
+++ b/src/conf_mode/vrf.py
@@ -108,6 +108,12 @@ def get_config(config=None):
# vyos.configverify.verify_common_route_maps() for more information.
tmp = {'policy' : {'route-map' : conf.get_config_dict(['policy', 'route-map'],
get_first_key=True)}}
+
+ # L3VNI setup is done via vrf_vni.py as it must be de-configured (on node
+ # deletetion prior to the BGP process. Tell the Jinja2 template no VNI
+ # setup is needed
+ vrf.update({'no_vni' : ''})
+
# Merge policy dict into "regular" config dict
vrf = dict_merge(tmp, vrf)
return vrf
@@ -124,8 +130,8 @@ def verify(vrf):
f'static routes installed!')
if 'name' in vrf:
- reserved_names = ["add", "all", "broadcast", "default", "delete", "dev", "get", "inet", "mtu", "link", "type",
- "vrf"]
+ reserved_names = ["add", "all", "broadcast", "default", "delete", "dev",
+ "get", "inet", "mtu", "link", "type", "vrf"]
table_ids = []
for name, vrf_config in vrf['name'].items():
# Reserved VRF names
@@ -142,8 +148,8 @@ def verify(vrf):
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 vrf_config['table'] in table_ids:
+ # VRF routing table ID must be unique on the system
+ if 'table' in vrf_config and vrf_config['table'] in table_ids:
raise ConfigError(f'VRF "{name}" table id is not unique!')
table_ids.append(vrf_config['table'])
diff --git a/src/conf_mode/vrf_vni.py b/src/conf_mode/vrf_vni.py
new file mode 100644
index 000000000..9f33536e5
--- /dev/null
+++ b/src/conf_mode/vrf_vni.py
@@ -0,0 +1,104 @@
+#!/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/>.
+
+from sys import argv
+from sys import exit
+
+from vyos.config import Config
+from vyos.template import render_to_string
+from vyos.util import dict_search
+from vyos import ConfigError
+from vyos import frr
+from vyos import airbag
+airbag.enable()
+
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
+
+ vrf_name = None
+ if len(argv) > 1:
+ vrf_name = argv[1]
+ else:
+ return None
+
+ # Using duplicate L3VNIs makes no sense - it's also forbidden in FRR,
+ # thus VyOS CLI must deny this, too. Instead of getting only the dict for
+ # the requested VRF and den comparing it with depenent VRfs to not have any
+ # duplicate we will just grad ALL VRFs by default but only render/apply
+ # the configuration for the requested VRF - that makes the code easier and
+ # hopefully less error prone
+ vrf = conf.get_config_dict(['vrf'], key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
+ get_first_key=True)
+
+ # Store name of VRF we are interested in for FRR config rendering
+ vrf.update({'only_vrf' : vrf_name})
+
+ return vrf
+
+def verify(vrf):
+ if not vrf:
+ return
+
+ if len(argv) < 2:
+ raise ConfigError('VRF parameter not specified when valling vrf_vni.py')
+
+ if 'name' in vrf:
+ vni_ids = []
+ for name, vrf_config in vrf['name'].items():
+ # VRF VNI (Virtual Network Identifier) must be unique on the system
+ if 'vni' in vrf_config:
+ if vrf_config['vni'] in vni_ids:
+ raise ConfigError(f'VRF "{name}" VNI is not unique!')
+ vni_ids.append(vrf_config['vni'])
+
+ return None
+
+def generate(vrf):
+ if not vrf:
+ return
+
+ 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)
+ # There is only one VRF inside the dict as we read only one in get_config()
+ if vrf and 'only_vrf' in vrf:
+ vrf_name = vrf['only_vrf']
+ frr_cfg.modify_section(f'^vrf {vrf_name}', stop_pattern='^exit-vrf', remove_stop_mark=True)
+ if vrf and 'new_frr_config' in vrf:
+ frr_cfg.add_before(frr.default_add_before, vrf['new_frr_config'])
+ frr_cfg.commit_configuration(frr_daemon)
+
+ return None
+
+if __name__ == '__main__':
+ try:
+ c = get_config()
+ verify(c)
+ generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ exit(1)
diff --git a/src/helpers/vyos-failover.py b/src/helpers/vyos-failover.py
index 03fb42f57..ce4cf8fa4 100755
--- a/src/helpers/vyos-failover.py
+++ b/src/helpers/vyos-failover.py
@@ -93,7 +93,12 @@ def is_port_open(ip, port):
s.close()
-def is_target_alive(target_list=None, iface='', proto='icmp', port=None, debug=False):
+def is_target_alive(target_list=None,
+ iface='',
+ proto='icmp',
+ port=None,
+ debug=False,
+ policy='any-available') -> bool:
"""Check the availability of each target in the target_list using
the specified protocol ICMP, ARP, TCP
@@ -103,17 +108,19 @@ def is_target_alive(target_list=None, iface='', proto='icmp', port=None, debug=F
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.
+ policy (str): The policy to use for the check. Options are 'any-available' or 'all-available'.
Returns:
- bool: True if all targets are reachable, False otherwise.
+ bool: True if all targets are reachable according to the policy, False otherwise.
Example:
- % is_target_alive(['192.0.2.1', '192.0.2.5'], 'eth1', proto='arp')
+ % is_target_alive(['192.0.2.1', '192.0.2.5'], 'eth1', proto='arp', policy='all-available')
True
"""
if iface != '':
iface = f'-I {iface}'
+ num_reachable_targets = 0
for target in target_list:
match proto:
case 'icmp':
@@ -121,25 +128,34 @@ def is_target_alive(target_list=None, iface='', proto='icmp', port=None, debug=F
rc, response = rc_cmd(command)
if debug:
print(f' [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]')
- if rc != 0:
- return False
+ if rc == 0:
+ num_reachable_targets += 1
+ if policy == 'any-available':
+ return True
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
+ if rc == 0:
+ num_reachable_targets += 1
+ if policy == 'any-available':
+ return True
case _ if proto == 'tcp' and port is not None:
- if not is_port_open(target, port):
- return False
+ if is_port_open(target, port):
+ num_reachable_targets += 1
+ if policy == 'any-available':
+ return True
case _:
return False
- return True
+ if policy == 'all-available' and num_reachable_targets == len(target_list):
+ return True
+
+ return False
if __name__ == '__main__':
@@ -178,6 +194,7 @@ if __name__ == '__main__':
conf_metric = int(nexthop_config.get('metric'))
port = nexthop_config.get('check').get('port')
port_opt = f'port {port}' if port else ''
+ policy = nexthop_config.get('check').get('policy')
proto = nexthop_config.get('check').get('type')
target = nexthop_config.get('check').get('target')
timeout = nexthop_config.get('check').get('timeout')
@@ -186,7 +203,7 @@ if __name__ == '__main__':
if not is_route_exists(route, next_hop, conf_iface, conf_metric):
if debug: print(f" [NEW_ROUTE_DETECTED] route: [{route}]")
# Add route if check-target alive
- if is_target_alive(target, conf_iface, proto, port, debug=debug):
+ if is_target_alive(target, conf_iface, proto, port, debug=debug, policy=policy):
if debug: print(f' [ ADD ] -- ip route add {route} via {next_hop} dev {conf_iface} '
f'metric {conf_metric} proto failover\n###')
rc, command = rc_cmd(f'ip route add {route} via {next_hop} dev {conf_iface} '
@@ -205,7 +222,7 @@ if __name__ == '__main__':
# Route was added, check if the target is alive
# We should delete route if check fails only if route exists in the routing table
- if not is_target_alive(target, conf_iface, proto, port, debug=debug) and \
+ if not is_target_alive(target, conf_iface, proto, port, debug=debug, policy=policy) and \
is_route_exists(route, next_hop, conf_iface, conf_metric):
if debug:
print(f'Nexh_hop {next_hop} fail, target not response')
diff --git a/src/op_mode/bgp.py b/src/op_mode/bgp.py
index 3f6d45dd7..af9ea788b 100755
--- a/src/op_mode/bgp.py
+++ b/src/op_mode/bgp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 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
@@ -15,101 +15,133 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Purpose:
-# Displays bgp neighbors information.
-# Used by the "show bgp (vrf <tag>) ipv4|ipv6 neighbors" commands.
+# Displays BGP neighbors and tables information.
import re
import sys
import typing
-import jmespath
from jinja2 import Template
-from humps import decamelize
-
-from vyos.configquery import ConfigTreeQuery
import vyos.opmode
-ArgFamily = typing.Literal['inet', 'inet6']
-
frr_command_template = Template("""
-{% if family %}
- show bgp
- {{ 'vrf ' ~ vrf if vrf else '' }}
- {{ 'ipv6' if family == 'inet6' else 'ipv4'}}
- {{ 'neighbor ' ~ peer if peer else 'summary' }}
+show bgp
+
+{## VRF and family modifiers that may precede any options ##}
+
+{% if vrf %}
+ vrf {{vrf}}
+{% endif %}
+
+{% if family == "inet" %}
+ ipv4
+{% elif family == "inet6" %}
+ ipv6
+{% elif family == "l2vpn" %}
+ l2vpn evpn
+{% endif %}
+
+{% if family_modifier == "unicast" %}
+ unicast
+{% elif family_modifier == "multicast" %}
+ multicast
+{% elif family_modifier == "flowspec" %}
+ flowspec
+{% elif family_modifier == "vpn" %}
+ vpn
+{% endif %}
+
+{## Mutually exclusive query parameters ##}
+
+{# Network prefix #}
+{% if prefix %}
+ {{prefix}}
+
+ {% if longer_prefixes %}
+ longer-prefixes
+ {% elif best_path %}
+ bestpath
+ {% endif %}
{% endif %}
+{# Regex #}
+{% if regex %}
+ regex {{regex}}
+{% endif %}
+
+{## Raw modifier ##}
+
{% if raw %}
json
{% endif %}
""")
+ArgFamily = typing.Literal['inet', 'inet6', 'l2vpn']
+ArgFamilyModifier = typing.Literal['unicast', 'labeled_unicast', 'multicast', 'vpn', 'flowspec']
+
+def show_summary(raw: bool):
+ from vyos.util import cmd
+
+ if raw:
+ from json import loads
+
+ output = cmd(f"vtysh -c 'show bgp summary json'").strip()
-def _verify(func):
- """Decorator checks if BGP config exists
- BGP configuration can be present under vrf <tag>
- If we do npt get arg 'peer' then it can be 'bgp summary'
- """
- from functools import wraps
-
- @wraps(func)
- def _wrapper(*args, **kwargs):
- config = ConfigTreeQuery()
- afi = 'ipv6' if kwargs.get('family') == 'inet6' else 'ipv4'
- global_vrfs = ['all', 'default']
- peer = kwargs.get('peer')
- vrf = kwargs.get('vrf')
- unconf_message = f'BGP or neighbor is not configured'
- # Add option to check the specific neighbor if we have arg 'peer'
- peer_opt = f'neighbor {peer} address-family {afi}-unicast' if peer else ''
- vrf_opt = ''
- if vrf and vrf not in global_vrfs:
- vrf_opt = f'vrf name {vrf}'
- # Check if config does not exist
- if not config.exists(f'{vrf_opt} protocols bgp {peer_opt}'):
- raise vyos.opmode.UnconfiguredSubsystem(unconf_message)
- return func(*args, **kwargs)
-
- return _wrapper
-
-
-@_verify
-def show_neighbors(raw: bool,
- family: ArgFamily,
- peer: typing.Optional[str],
- vrf: typing.Optional[str]):
- kwargs = dict(locals())
- frr_command = frr_command_template.render(kwargs)
- frr_command = re.sub(r'\s+', ' ', frr_command)
+ # FRR 8.5 correctly returns an empty object when BGP is not running,
+ # we don't need to do anything special here
+ return loads(output)
+ else:
+ output = cmd(f"vtysh -c 'show bgp summary'")
+ return output
+def show_neighbors(raw: bool):
from vyos.util import cmd
- output = cmd(f"vtysh -c '{frr_command}'")
+ from vyos.utils.dict import dict_to_list
if raw:
from json import loads
- data = loads(output)
- # Get list of the peers
- peers = jmespath.search('*.peers | [0]', data)
- if peers:
- # Create new dict, delete old key 'peers'
- # add key 'peers' neighbors to the list
- list_peers = []
- new_dict = jmespath.search('* | [0]', data)
- if 'peers' in new_dict:
- new_dict.pop('peers')
-
- for neighbor, neighbor_options in peers.items():
- neighbor_options['neighbor'] = neighbor
- list_peers.append(neighbor_options)
- new_dict['peers'] = list_peers
- return decamelize(new_dict)
- data = jmespath.search('* | [0]', data)
- return decamelize(data)
+ output = cmd(f"vtysh -c 'show bgp neighbors json'").strip()
+ d = loads(output)
+ return dict_to_list(d, save_key_to="neighbor")
else:
+ output = cmd(f"vtysh -c 'show bgp neighbors'")
return output
+def show(raw: bool,
+ family: ArgFamily,
+ family_modifier: ArgFamilyModifier,
+ prefix: typing.Optional[str],
+ longer_prefixes: typing.Optional[bool],
+ best_path: typing.Optional[bool],
+ regex: typing.Optional[str],
+ vrf: typing.Optional[str]):
+ from vyos.utils.dict import dict_to_list
+
+ if (longer_prefixes or best_path) and (prefix is None):
+ raise ValueError("longer_prefixes and best_path can only be used when prefix is given")
+ elif (family == "l2vpn") and (family_modifier is not None):
+ raise ValueError("l2vpn family does not accept any modifiers")
+ else:
+ kwargs = dict(locals())
+
+ frr_command = frr_command_template.render(kwargs)
+ frr_command = re.sub(r'\s+', ' ', frr_command)
+
+ from vyos.util import cmd
+ output = cmd(f"vtysh -c '{frr_command}'")
+
+ if raw:
+ from json import loads
+ d = loads(output)
+ if not ("routes" in d):
+ raise vyos.opmode.InternalError("FRR returned a BGP table with no routes field")
+ d = d["routes"]
+ routes = dict_to_list(d, save_key_to="route_key")
+ return routes
+ else:
+ return output
if __name__ == '__main__':
try:
diff --git a/src/op_mode/conntrack_sync.py b/src/op_mode/conntrack_sync.py
index 54ecd6d0e..c3345a936 100755
--- a/src/op_mode/conntrack_sync.py
+++ b/src/op_mode/conntrack_sync.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2022 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,9 +15,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
+import sys
import syslog
import xmltodict
+import vyos.opmode
+
from argparse import ArgumentParser
from vyos.configquery import CliShellApiConfigQuery
from vyos.configquery import ConfigTreeQuery
@@ -31,36 +34,23 @@ conntrackd_bin = '/usr/sbin/conntrackd'
conntrackd_config = '/run/conntrackd/conntrackd.conf'
failover_state_file = '/var/run/vyatta-conntrackd-failover-state'
-parser = ArgumentParser(description='Conntrack Sync')
-group = parser.add_mutually_exclusive_group()
-group.add_argument('--restart', help='Restart connection tracking synchronization service', action='store_true')
-group.add_argument('--reset-cache-internal', help='Reset internal cache', action='store_true')
-group.add_argument('--reset-cache-external', help='Reset external cache', action='store_true')
-group.add_argument('--show-internal', help='Show internal (main) tracking cache', action='store_true')
-group.add_argument('--show-external', help='Show external (main) tracking cache', action='store_true')
-group.add_argument('--show-internal-expect', help='Show internal (expect) tracking cache', action='store_true')
-group.add_argument('--show-external-expect', help='Show external (expect) tracking cache', action='store_true')
-group.add_argument('--show-statistics', help='Show connection syncing statistics', action='store_true')
-group.add_argument('--show-status', help='Show conntrack-sync status', action='store_true')
-
def is_configured():
""" Check if conntrack-sync service is configured """
config = CliShellApiConfigQuery()
if not config.exists(['service', 'conntrack-sync']):
- print('Service conntrackd-sync not configured!')
- exit(1)
+ raise vyos.opmode.UnconfiguredSubsystem("conntrack-sync is not configured!")
def send_bulk_update():
""" send bulk update of internal-cache to other systems """
tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -B')
if tmp > 0:
- print('ERROR: failed to send bulk update to other conntrack-sync systems')
+ raise vyos.opmode.Error('Failed to send bulk update to other conntrack-sync systems')
def request_sync():
""" request resynchronization with other systems """
tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -n')
if tmp > 0:
- print('ERROR: failed to request resynchronization of external cache')
+ raise vyos.opmode.Error('Failed to request resynchronization of external cache')
def flush_cache(direction):
""" flush conntrackd cache (internal or external) """
@@ -68,9 +58,9 @@ def flush_cache(direction):
raise ValueError()
tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -f {direction}')
if tmp > 0:
- print('ERROR: failed to clear {direction} cache')
+ raise vyos.opmode.Error('Failed to clear {direction} cache')
-def xml_to_stdout(xml):
+def from_xml(raw, xml):
out = []
for line in xml.splitlines():
if line == '\n':
@@ -78,108 +68,131 @@ def xml_to_stdout(xml):
parsed = xmltodict.parse(line)
out.append(parsed)
- print(render_to_string('conntrackd/conntrackd.op-mode.j2', {'data' : out}))
-
-if __name__ == '__main__':
- args = parser.parse_args()
- syslog.openlog(ident='conntrack-tools', logoption=syslog.LOG_PID,
- facility=syslog.LOG_INFO)
+ if raw:
+ return out
+ else:
+ return render_to_string('conntrackd/conntrackd.op-mode.j2', {'data' : out})
+
+def restart():
+ is_configured()
+ if commit_in_progress():
+ raise vyos.opmode.CommitInProgress('Cannot restart conntrackd while a commit is in progress')
+
+ syslog.syslog('Restarting conntrack sync service...')
+ cmd('systemctl restart conntrackd.service')
+ # request resynchronization with other systems
+ request_sync()
+ # send bulk update of internal-cache to other systems
+ send_bulk_update()
+
+def reset_external_cache():
+ is_configured()
+ syslog.syslog('Resetting external cache of conntrack sync service...')
+
+ # flush the external cache
+ flush_cache('external')
+ # request resynchronization with other systems
+ request_sync()
+
+def reset_internal_cache():
+ is_configured()
+ syslog.syslog('Resetting internal cache of conntrack sync service...')
+ # flush the internal cache
+ flush_cache('internal')
+
+ # request resynchronization of internal cache with kernel conntrack table
+ tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -R')
+ if tmp > 0:
+ print('ERROR: failed to resynchronize internal cache with kernel conntrack table')
- if args.restart:
- is_configured()
- if commit_in_progress():
- print('Cannot restart conntrackd while a commit is in progress')
- exit(1)
-
- syslog.syslog('Restarting conntrack sync service...')
- cmd('systemctl restart conntrackd.service')
- # request resynchronization with other systems
- request_sync()
- # send bulk update of internal-cache to other systems
- send_bulk_update()
-
- elif args.reset_cache_external:
- is_configured()
- syslog.syslog('Resetting external cache of conntrack sync service...')
+ # send bulk update of internal-cache to other systems
+ send_bulk_update()
- # flush the external cache
- flush_cache('external')
- # request resynchronization with other systems
- request_sync()
+def _show_cache(raw, opts):
+ is_configured()
+ out = cmd(f'{conntrackd_bin} -C {conntrackd_config} {opts} -x')
+ return from_xml(raw, out)
- elif args.reset_cache_internal:
- is_configured()
- syslog.syslog('Resetting internal cache of conntrack sync service...')
- # flush the internal cache
- flush_cache('internal')
+def show_external_cache(raw: bool):
+ opts = '-e ct'
+ return _show_cache(raw, opts)
- # request resynchronization of internal cache with kernel conntrack table
- tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -R')
- if tmp > 0:
- print('ERROR: failed to resynchronize internal cache with kernel conntrack table')
+def show_external_expect(raw: bool):
+ opts = '-e expect'
+ return _show_cache(raw, opts)
- # send bulk update of internal-cache to other systems
- send_bulk_update()
+def show_internal_cache(raw: bool):
+ opts = '-i ct'
+ return _show_cache(raw, opts)
- elif args.show_external or args.show_internal or args.show_external_expect or args.show_internal_expect:
- is_configured()
- opt = ''
- if args.show_external:
- opt = '-e ct'
- elif args.show_external_expect:
- opt = '-e expect'
- elif args.show_internal:
- opt = '-i ct'
- elif args.show_internal_expect:
- opt = '-i expect'
-
- if args.show_external or args.show_internal:
- print('Main Table Entries:')
- else:
- print('Expect Table Entries:')
- out = cmd(f'sudo {conntrackd_bin} -C {conntrackd_config} {opt} -x')
- xml_to_stdout(out)
+def show_internal_expect(raw: bool):
+ opts = '-i expect'
+ return _show_cache(raw, opts)
- elif args.show_statistics:
+def show_statistics(raw: bool):
+ if raw:
+ raise vyos.opmode.UnsupportedOperation("Machine-readable conntrack-sync statistics are not available yet")
+ else:
is_configured()
config = ConfigTreeQuery()
print('\nMain Table Statistics:\n')
- call(f'sudo {conntrackd_bin} -C {conntrackd_config} -s')
+ call(f'{conntrackd_bin} -C {conntrackd_config} -s')
print()
if config.exists(['service', 'conntrack-sync', 'expect-sync']):
print('\nExpect Table Statistics:\n')
- call(f'sudo {conntrackd_bin} -C {conntrackd_config} -s exp')
+ call(f'{conntrackd_bin} -C {conntrackd_config} -s exp')
print()
- elif args.show_status:
- is_configured()
- config = ConfigTreeQuery()
- ct_sync_intf = config.list_nodes(['service', 'conntrack-sync', 'interface'])
- ct_sync_intf = ', '.join(ct_sync_intf)
- failover_state = "no transition yet!"
- expect_sync_protocols = "disabled"
-
- if config.exists(['service', 'conntrack-sync', 'failover-mechanism', 'vrrp']):
- failover_mechanism = "vrrp"
- vrrp_sync_grp = config.value(['service', 'conntrack-sync', 'failover-mechanism', 'vrrp', 'sync-group'])
-
- if os.path.isfile(failover_state_file):
- with open(failover_state_file, "r") as f:
- failover_state = f.readline()
-
- if config.exists(['service', 'conntrack-sync', 'expect-sync']):
- expect_sync_protocols = config.values(['service', 'conntrack-sync', 'expect-sync'])
- if 'all' in expect_sync_protocols:
- expect_sync_protocols = ["ftp", "sip", "h323", "nfs", "sqlnet"]
+def show_status(raw: bool):
+ is_configured()
+ config = ConfigTreeQuery()
+ ct_sync_intf = config.list_nodes(['service', 'conntrack-sync', 'interface'])
+ ct_sync_intf = ', '.join(ct_sync_intf)
+ failover_state = "no transition yet!"
+ expect_sync_protocols = []
+
+ if config.exists(['service', 'conntrack-sync', 'failover-mechanism', 'vrrp']):
+ failover_mechanism = "vrrp"
+ vrrp_sync_grp = config.value(['service', 'conntrack-sync', 'failover-mechanism', 'vrrp', 'sync-group'])
+
+ if os.path.isfile(failover_state_file):
+ with open(failover_state_file, "r") as f:
+ failover_state = f.readline()
+
+ if config.exists(['service', 'conntrack-sync', 'expect-sync']):
+ expect_sync_protocols = config.values(['service', 'conntrack-sync', 'expect-sync'])
+ if 'all' in expect_sync_protocols:
+ expect_sync_protocols = ["ftp", "sip", "h323", "nfs", "sqlnet"]
+
+ if raw:
+ status_data = {
+ "sync_interface": ct_sync_intf,
+ "failover_mechanism": failover_mechanism,
+ "sync_group": vrrp_sync_grp,
+ "last_transition": failover_state,
+ "sync_protocols": expect_sync_protocols
+ }
+
+ return status_data
+ else:
+ if expect_sync_protocols:
expect_sync_protocols = ', '.join(expect_sync_protocols)
-
+ else:
+ expect_sync_protocols = "disabled"
show_status = (f'\nsync-interface : {ct_sync_intf}\n'
f'failover-mechanism : {failover_mechanism} [sync-group {vrrp_sync_grp}]\n'
- f'last state transition : {failover_state}'
+ f'last state transition : {failover_state}\n'
f'ExpectationSync : {expect_sync_protocols}')
- print(show_status)
+ return show_status
- else:
- parser.print_help()
- exit(1)
+if __name__ == '__main__':
+ syslog.openlog(ident='conntrack-tools', logoption=syslog.LOG_PID, facility=syslog.LOG_INFO)
+
+ try:
+ res = vyos.opmode.run(sys.modules[__name__])
+ if res:
+ print(res)
+ except (ValueError, vyos.opmode.Error) as e:
+ print(e)
+ sys.exit(1)
diff --git a/src/op_mode/dynamic_dns.py b/src/op_mode/dynamic_dns.py
index 2cba33cc8..d41a74db3 100755
--- a/src/op_mode/dynamic_dns.py
+++ b/src/op_mode/dynamic_dns.py
@@ -21,6 +21,7 @@ import time
from tabulate import tabulate
from vyos.config import Config
+from vyos.template import is_ipv4, is_ipv6
from vyos.util import call
cache_file = r'/run/ddclient/ddclient.cache'
@@ -46,7 +47,7 @@ def _get_formatted_host_records(host_data):
def show_status():
- # A ddclient status file must not always exist
+ # A ddclient status file might not always exist
if not os.path.exists(cache_file):
sys.exit(0)
@@ -62,9 +63,20 @@ def show_status():
# 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():
+ if k in list(columns.keys()) + ['ip', 'status']: # ip and status are legacy keys
props[k] = v
+ # Extract IPv4 and IPv6 address and status from legacy keys
+ # Dual-stack isn't supported in legacy format, 'ip' and 'status' are for one of IPv4 or IPv6
+ if 'ip' in props:
+ if is_ipv4(props['ip']):
+ props['ipv4'] = props['ip']
+ props['status-ipv4'] = props['status']
+ elif is_ipv6(props['ip']):
+ props['ipv6'] = props['ip']
+ props['status-ipv6'] = props['status']
+ del props['ip']
+
# Convert mtime to human readable format
if 'mtime' in props:
props['mtime'] = time.strftime(
diff --git a/src/op_mode/ipsec.py b/src/op_mode/ipsec.py
index 7f4fb72e5..db4948d7a 100755
--- a/src/op_mode/ipsec.py
+++ b/src/op_mode/ipsec.py
@@ -13,7 +13,6 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
import re
import sys
import typing
@@ -24,6 +23,7 @@ from tabulate import tabulate
from vyos.util import convert_data
from vyos.util import seconds_to_human
+from vyos.util import cmd
from vyos.configquery import ConfigTreeQuery
import vyos.opmode
@@ -46,6 +46,25 @@ def _get_raw_data_sas():
except (vyos.ipsec.ViciInitiateError) as err:
raise vyos.opmode.UnconfiguredSubsystem(err)
+
+def _get_output_swanctl_sas_from_list(ra_output_list: list) -> str:
+ """
+ Template for output for VICI
+ Inserts \n after each IKE SA
+ :param ra_output_list: IKE SAs list
+ :type ra_output_list: list
+ :return: formatted string
+ :rtype: str
+ """
+ output = '';
+ for sa_val in ra_output_list:
+ for sa in sa_val.values():
+ swanctl_output: str = cmd(
+ f'sudo swanctl -l --ike-id {sa["uniqueid"]}')
+ output = f'{output}{swanctl_output}\n\n'
+ return output
+
+
def _get_formatted_output_sas(sas):
sa_data = []
for sa in sas:
@@ -444,6 +463,7 @@ def reset_peer(peer: str, tunnel: typing.Optional[str] = None):
except (vyos.ipsec.ViciCommandError) as err:
raise vyos.opmode.IncorrectValue(err)
+
def reset_all_peers():
sitetosite_list = _get_all_sitetosite_peers_name_list()
if sitetosite_list:
@@ -457,6 +477,7 @@ def reset_all_peers():
raise vyos.opmode.UnconfiguredSubsystem(
'VPN IPSec site-to-site is not configured, aborting')
+
def _get_ra_session_list_by_username(username: typing.Optional[str] = None):
"""
Return list of remote-access IKE_SAs uniqueids
@@ -466,15 +487,15 @@ def _get_ra_session_list_by_username(username: typing.Optional[str] = None):
:rtype:
"""
list_sa_id = []
- sa_list = vyos.ipsec.get_vici_sas()
+ sa_list = _get_raw_data_sas()
for sa_val in sa_list:
for sa in sa_val.values():
if 'remote-eap-id' in sa:
if username:
- if username == sa['remote-eap-id'].decode():
- list_sa_id.append(sa['uniqueid'].decode())
+ if username == sa['remote-eap-id']:
+ list_sa_id.append(sa['uniqueid'])
else:
- list_sa_id.append(sa['uniqueid'].decode())
+ list_sa_id.append(sa['uniqueid'])
return list_sa_id
@@ -556,6 +577,24 @@ def show_sa(raw: bool):
return _get_formatted_output_sas(sa_data)
+def _get_output_sas_detail(ra_output_list: list) -> str:
+ """
+ Formate all IKE SAs detail output
+ :param ra_output_list: IKE SAs list
+ :type ra_output_list: list
+ :return: formatted RA IKE SAs detail output
+ :rtype: str
+ """
+ return _get_output_swanctl_sas_from_list(ra_output_list)
+
+
+def show_sa_detail(raw: bool):
+ sa_data = _get_raw_data_sas()
+ if raw:
+ return sa_data
+ return _get_output_sas_detail(sa_data)
+
+
def show_connections(raw: bool):
list_conns = _get_convert_data_connections()
list_sas = _get_raw_data_sas()
@@ -573,6 +612,173 @@ def show_connections_summary(raw: bool):
return _get_raw_connections_summary(list_conns, list_sas)
+def _get_ra_sessions(username: typing.Optional[str] = None) -> list:
+ """
+ Return list of remote-access IKE_SAs from VICI by username.
+ If username unspecified, return all remote-access IKE_SAs
+ :param username: Username of RA connection
+ :type username: str
+ :return: list of ra remote-access IKE_SAs
+ :rtype: list
+ """
+ list_sa = []
+ sa_list = _get_raw_data_sas()
+ for conn in sa_list:
+ for sa in conn.values():
+ if 'remote-eap-id' in sa:
+ if username:
+ if username == sa['remote-eap-id']:
+ list_sa.append(conn)
+ else:
+ list_sa.append(conn)
+ return list_sa
+
+
+def _filter_ikesas(list_sa: list, filter_key: str, filter_value: str) -> list:
+ """
+ Filter IKE SAs by specifice key
+ :param list_sa: list of IKE SAs
+ :type list_sa: list
+ :param filter_key: Filter Key
+ :type filter_key: str
+ :param filter_value: Filter Value
+ :type filter_value: str
+ :return: Filtered list of IKE SAs
+ :rtype: list
+ """
+ filtered_sa_list = []
+ for conn in list_sa:
+ for sa in conn.values():
+ if sa[filter_key] and sa[filter_key] == filter_value:
+ filtered_sa_list.append(conn)
+ return filtered_sa_list
+
+
+def _get_last_installed_childsa(sa: dict) -> str:
+ """
+ Return name of last installed active Child SA
+ :param sa: Dictionary with Child SAs
+ :type sa: dict
+ :return: Name of the Last installed active Child SA
+ :rtype: str
+ """
+ child_sa_name = None
+ child_sa_id = 0
+ for sa_name, child_sa in sa['child-sas'].items():
+ if child_sa['state'] == 'INSTALLED':
+ if child_sa_id == 0 or int(child_sa['uniqueid']) > child_sa_id:
+ child_sa_id = int(child_sa['uniqueid'])
+ child_sa_name = sa_name
+ return child_sa_name
+
+
+def _get_formatted_ike_proposal(sa: dict) -> str:
+ """
+ Return IKE proposal string in format
+ EncrALG-EncrKeySize/PFR/HASH/DH-GROUP
+ :param sa: IKE SA
+ :type sa: dict
+ :return: IKE proposal string
+ :rtype: str
+ """
+ proposal = ''
+ proposal = f'{proposal}{sa["encr-alg"]}' if 'encr-alg' in sa else proposal
+ proposal = f'{proposal}-{sa["encr-keysize"]}' if 'encr-keysize' in sa else proposal
+ proposal = f'{proposal}/{sa["prf-alg"]}' if 'prf-alg' in sa else proposal
+ proposal = f'{proposal}/{sa["integ-alg"]}' if 'integ-alg' in sa else proposal
+ proposal = f'{proposal}/{sa["dh-group"]}' if 'dh-group' in sa else proposal
+ return proposal
+
+
+def _get_formatted_ipsec_proposal(sa: dict) -> str:
+ """
+ Return IPSec proposal string in format
+ Protocol: EncrALG-EncrKeySize/HASH/PFS
+ :param sa: Child SA
+ :type sa: dict
+ :return: IPSec proposal string
+ :rtype: str
+ """
+ proposal = ''
+ proposal = f'{proposal}{sa["protocol"]}' if 'protocol' in sa else proposal
+ proposal = f'{proposal}:{sa["encr-alg"]}' if 'encr-alg' in sa else proposal
+ proposal = f'{proposal}-{sa["encr-keysize"]}' if 'encr-keysize' in sa else proposal
+ proposal = f'{proposal}/{sa["integ-alg"]}' if 'integ-alg' in sa else proposal
+ proposal = f'{proposal}/{sa["dh-group"]}' if 'dh-group' in sa else proposal
+ return proposal
+
+
+def _get_output_ra_sas_detail(ra_output_list: list) -> str:
+ """
+ Formate RA IKE SAs detail output
+ :param ra_output_list: IKE SAs list
+ :type ra_output_list: list
+ :return: formatted RA IKE SAs detail output
+ :rtype: str
+ """
+ return _get_output_swanctl_sas_from_list(ra_output_list)
+
+
+def _get_formatted_output_ra_summary(ra_output_list: list):
+ sa_data = []
+ for conn in ra_output_list:
+ for sa in conn.values():
+ sa_id = sa['uniqueid'] if 'uniqueid' in sa else ''
+ sa_username = sa['remote-eap-id'] if 'remote-eap-id' in sa else ''
+ sa_protocol = f'IKEv{sa["version"]}' if 'version' in sa else ''
+ sa_remotehost = sa['remote-host'] if 'remote-host' in sa else ''
+ sa_remoteid = sa['remote-id'] if 'remote-id' in sa else ''
+ sa_ike_proposal = _get_formatted_ike_proposal(sa)
+ sa_tunnel_ip = sa['remote-vips']
+ child_sa_key = _get_last_installed_childsa(sa)
+ if child_sa_key:
+ child_sa = sa['child-sas'][child_sa_key]
+ sa_ipsec_proposal = _get_formatted_ipsec_proposal(child_sa)
+ sa_state = "UP"
+ sa_uptime = seconds_to_human(sa['established'])
+ else:
+ sa_ipsec_proposal = ''
+ sa_state = "DOWN"
+ sa_uptime = ''
+ sa_data.append(
+ [sa_id, sa_username, sa_protocol, sa_state, sa_uptime,
+ sa_tunnel_ip,
+ sa_remotehost, sa_remoteid, sa_ike_proposal,
+ sa_ipsec_proposal])
+
+ headers = ["Connection ID", "Username", "Protocol", "State", "Uptime",
+ "Tunnel IP", "Remote Host", "Remote ID", "IKE Proposal",
+ "IPSec Proposal"]
+ sa_data = sorted(sa_data, key=_alphanum_key)
+ output = tabulate(sa_data, headers)
+ return output
+
+
+def show_ra_detail(raw: bool, username: typing.Optional[str] = None,
+ conn_id: typing.Optional[str] = None):
+ list_sa: list = _get_ra_sessions()
+ if username:
+ list_sa = _filter_ikesas(list_sa, 'remote-eap-id', username)
+ elif conn_id:
+ list_sa = _filter_ikesas(list_sa, 'uniqueid', conn_id)
+ if not list_sa:
+ raise vyos.opmode.IncorrectValue(
+ f'No active connections found, aborting')
+ if raw:
+ return list_sa
+ return _get_output_ra_sas_detail(list_sa)
+
+
+def show_ra_summary(raw: bool):
+ list_sa: list = _get_ra_sessions()
+ if not list_sa:
+ raise vyos.opmode.IncorrectValue(
+ f'No active connections found, aborting')
+ if raw:
+ return list_sa
+ return _get_formatted_output_ra_summary(list_sa)
+
+
if __name__ == '__main__':
try:
res = vyos.opmode.run(sys.modules[__name__])
diff --git a/src/op_mode/show_vpn_ra.py b/src/op_mode/show_vpn_ra.py
deleted file mode 100755
index 73688c4ea..000000000
--- a/src/op_mode/show_vpn_ra.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2019 VyOS maintainers and contributors
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import os
-import sys
-import re
-
-from vyos.util import popen
-
-# chech connection to pptp and l2tp daemon
-def get_sessions():
- absent_pptp = False
- absent_l2tp = False
- pptp_cmd = "accel-cmd -p 2003 show sessions"
- l2tp_cmd = "accel-cmd -p 2004 show sessions"
- err_pattern = "^Connection.+failed$"
- # This value for chack only output header without sessions.
- len_def_header = 170
-
- # Check pptp
- output, err = popen(pptp_cmd, decode='utf-8')
- if not err and len(output) > len_def_header and not re.search(err_pattern, output):
- print(output)
- else:
- absent_pptp = True
-
- # Check l2tp
- output, err = popen(l2tp_cmd, decode='utf-8')
- if not err and len(output) > len_def_header and not re.search(err_pattern, output):
- print(output)
- else:
- absent_l2tp = True
-
- if absent_l2tp and absent_pptp:
- print("No active remote access VPN sessions")
-
-
-def main():
- get_sessions()
-
-
-if __name__ == '__main__':
- main()
diff --git a/src/op_mode/show_wwan.py b/src/op_mode/show_wwan.py
index 529b5bd0f..eb601a456 100755
--- a/src/op_mode/show_wwan.py
+++ b/src/op_mode/show_wwan.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 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
@@ -17,6 +17,7 @@
import argparse
from sys import exit
+from vyos.configquery import ConfigTreeQuery
from vyos.util import cmd
parser = argparse.ArgumentParser()
@@ -49,6 +50,11 @@ def qmi_cmd(device, command, silent=False):
if __name__ == '__main__':
args = parser.parse_args()
+ tmp = ConfigTreeQuery()
+ if not tmp.exists(['interfaces', 'wwan', args.interface]):
+ print(f'Interface "{args.interface}" unconfigured!')
+ exit(1)
+
# remove the WWAN prefix from the interface, required for the CDC interface
if_num = args.interface.replace('wwan','')
cdc = f'/dev/cdc-wdm{if_num}'
diff --git a/src/services/vyos-http-api-server b/src/services/vyos-http-api-server
index cd73f38ec..acaa383b4 100755
--- a/src/services/vyos-http-api-server
+++ b/src/services/vyos-http-api-server
@@ -283,7 +283,7 @@ class MultipartRequest(Request):
return self._headers
async def form(self) -> FormData:
- if not hasattr(self, "_form"):
+ if self._form is None:
assert (
parse_options_header is not None
), "The `python-multipart` library must be installed to use form parsing."
diff --git a/src/systemd/vyos-wan-load-balance.service b/src/systemd/vyos-wan-load-balance.service
new file mode 100644
index 000000000..7d62a2ff6
--- /dev/null
+++ b/src/systemd/vyos-wan-load-balance.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=VyOS WAN load-balancing service
+After=vyos-router.service
+
+[Service]
+ExecStart=/opt/vyatta/sbin/wan_lb -f /run/load-balance/wlb.conf -d -i /var/run/vyatta/wlb.pid
+ExecReload=/bin/kill -s SIGTERM $MAINPID && sleep 5 && /opt/vyatta/sbin/wan_lb -f /run/load-balance/wlb.conf -d -i /var/run/vyatta/wlb.pid
+ExecStop=/bin/kill -s SIGTERM $MAINPID
+PIDFile=/var/run/vyatta/wlb.pid
+KillMode=process
+Restart=on-failure
+RestartSec=5s
+
+[Install]
+WantedBy=multi-user.target