summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/frr/staticd.frr.j22
-rw-r--r--interface-definitions/protocols-failover.xml.in20
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_static.py3
-rw-r--r--src/conf_mode/vrf_vni.py7
-rwxr-xr-xsrc/helpers/vyos-failover.py41
-rwxr-xr-xsrc/services/vyos-http-api-server2
6 files changed, 56 insertions, 19 deletions
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/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/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py
index bc023f3f2..706663ce5 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
@@ -95,6 +95,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
diff --git a/src/conf_mode/vrf_vni.py b/src/conf_mode/vrf_vni.py
index 0cf52a2ef..47b2200eb 100644
--- a/src/conf_mode/vrf_vni.py
+++ b/src/conf_mode/vrf_vni.py
@@ -35,12 +35,11 @@ def get_config(config=None):
vrf_name = argv[1]
base = ['vrf', 'name', vrf_name]
- tmp = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=False)
+ tmp = conf.get_config_dict(base, key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True, get_first_key=True)
if not tmp:
return None
- vrf = { 'name' : conf.get_config_dict(base, key_mangling=('-', '_'),
- get_first_key=False) }
-
+ vrf = { 'name' : tmp }
return vrf
def verify(vrf):
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/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."