diff options
-rw-r--r-- | data/templates/vrrp/keepalived.conf.tmpl | 14 | ||||
-rw-r--r-- | interface-definitions/include/generic-interface-broadcast.xml.i | 17 | ||||
-rw-r--r-- | interface-definitions/vrrp.xml.in | 37 | ||||
-rw-r--r-- | python/vyos/ifconfig/bridge.py | 12 | ||||
-rw-r--r-- | python/vyos/ifconfig/wireless.py | 6 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_ha_vrrp.py | 34 | ||||
-rwxr-xr-x | src/op_mode/show_dhcpv6.py | 2 |
7 files changed, 107 insertions, 15 deletions
diff --git a/data/templates/vrrp/keepalived.conf.tmpl b/data/templates/vrrp/keepalived.conf.tmpl index afbdc978e..10d5c6d24 100644 --- a/data/templates/vrrp/keepalived.conf.tmpl +++ b/data/templates/vrrp/keepalived.conf.tmpl @@ -28,6 +28,9 @@ vrrp_instance {{ name }} { virtual_router_id {{ group_config.vrid }} priority {{ group_config.priority }} advert_int {{ group_config.advertise_interval }} +{% if group_config.track is defined and group_config.track.exclude_vrrp_interface is defined %} + dont_track_primary +{% endif %} {% if group_config.no_preempt is not defined and group_config.preempt_delay is defined and group_config.preempt_delay is not none %} preempt_delay {{ group_config.preempt_delay }} {% elif group_config.no_preempt is defined %} @@ -61,8 +64,8 @@ vrrp_instance {{ name }} { {% endif %} {% if group_config.virtual_address is defined and group_config.virtual_address is not none %} virtual_ipaddress { -{% for addr in group_config.virtual_address %} - {{ addr }} +{% for addr, addr_config in group_config.virtual_address.items() %} + {{ addr }}{{ ' dev ' + addr_config.interface if addr_config.interface is defined }} {% endfor %} } {% endif %} @@ -73,6 +76,13 @@ vrrp_instance {{ name }} { {% endfor %} } {% endif %} +{% if group_config.track is defined and group_config.track.interface is defined and group_config.track.interface is not none %} + track_interface { +{% for interface in group_config.track.interface %} + {{ interface }} +{% endfor %} + } +{% endif %} {% if group_config.health_check is defined and group_config.health_check.script is defined and group_config.health_check.script is not none %} track_script { healthcheck_{{ name }} diff --git a/interface-definitions/include/generic-interface-broadcast.xml.i b/interface-definitions/include/generic-interface-broadcast.xml.i new file mode 100644 index 000000000..6f76dde1a --- /dev/null +++ b/interface-definitions/include/generic-interface-broadcast.xml.i @@ -0,0 +1,17 @@ +<!-- include start from generic-interface-broadcast.xml.i --> +<leafNode name="interface"> + <properties> + <help>Interface Name to use</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Interface name</description> + </valueHelp> + <constraint> + <validator name="interface-name"/> + </constraint> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/vrrp.xml.in b/interface-definitions/vrrp.xml.in index b58cf735c..337a0bbc9 100644 --- a/interface-definitions/vrrp.xml.in +++ b/interface-definitions/vrrp.xml.in @@ -188,6 +188,35 @@ <help>Use VRRP virtual MAC address as per RFC3768</help> </properties> </leafNode> + <node name="track"> + <properties> + <help>Track settings</help> + </properties> + <children> + <leafNode name="exclude-vrrp-interface"> + <properties> + <valueless/> + <help>Disable track state of main interface</help> + </properties> + </leafNode> + <leafNode name="interface"> + <properties> + <help>Interface name state check</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Interface name</description> + </valueHelp> + <constraint> + <validator name="interface-name"/> + </constraint> + <multi/> + </properties> + </leafNode> + </children> + </node> <node name="transition-script"> <properties> <help>VRRP transition scripts</help> @@ -233,7 +262,7 @@ </leafNode> </children> </node> - <leafNode name="virtual-address"> + <tagNode name="virtual-address"> <properties> <help>Virtual address (IPv4 or IPv6, but they must not be mixed in one group)</help> <valueHelp> @@ -249,9 +278,11 @@ <validator name="ipv6-host"/> </constraint> <constraintErrorMessage>Virtual address must be a valid IPv4 or IPv6 address with prefix length (e.g. 192.0.2.3/24 or 2001:db8:ff::10/64)</constraintErrorMessage> - <multi/> </properties> - </leafNode> + <children> + #include <include/generic-interface-broadcast.xml.i> + </children> + </tagNode> <leafNode name="virtual-address-excluded"> <properties> <help>Virtual address (If you need additional IPv4 and IPv6 in same group)</help> diff --git a/python/vyos/ifconfig/bridge.py b/python/vyos/ifconfig/bridge.py index 27073b266..ffd9c590f 100644 --- a/python/vyos/ifconfig/bridge.py +++ b/python/vyos/ifconfig/bridge.py @@ -298,7 +298,6 @@ class BridgeIf(Interface): tmp = dict_search('member.interface', config) if tmp: - for interface, interface_config in tmp.items(): # if interface does yet not exist bail out early and # add it later @@ -316,10 +315,13 @@ class BridgeIf(Interface): # enslave interface port to bridge self.add_port(interface) - # always set private-vlan/port isolation - tmp = dict_search('isolated', interface_config) - value = 'on' if (tmp != None) else 'off' - lower.set_port_isolation(value) + if not interface.startswith('wlan'): + # always set private-vlan/port isolation - this can not be + # done when lower link is a wifi link, as it will trigger: + # RTNETLINK answers: Operation not supported + tmp = dict_search('isolated', interface_config) + value = 'on' if (tmp != None) else 'off' + lower.set_port_isolation(value) # set bridge port path cost if 'cost' in interface_config: diff --git a/python/vyos/ifconfig/wireless.py b/python/vyos/ifconfig/wireless.py index d897715db..11120a3d3 100644 --- a/python/vyos/ifconfig/wireless.py +++ b/python/vyos/ifconfig/wireless.py @@ -54,10 +54,10 @@ class WiFiIf(Interface): on any interface. """ # We can not call add_to_bridge() until wpa_supplicant is running, thus - # we will remove the key from the config dict and react to this specal - # case in thie derived class. + # we will remove the key from the config dict and react to this special + # case in this derived class. # re-add ourselves to any bridge we might have fallen out of - bridge_member = '' + bridge_member = None if 'is_bridge_member' in config: bridge_member = config['is_bridge_member'] del config['is_bridge_member'] diff --git a/smoketest/scripts/cli/test_ha_vrrp.py b/smoketest/scripts/cli/test_ha_vrrp.py index 27ea39870..8abc70ccd 100755 --- a/smoketest/scripts/cli/test_ha_vrrp.py +++ b/smoketest/scripts/cli/test_ha_vrrp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-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 @@ -166,5 +166,37 @@ class TestVRRP(VyOSUnitTestSHIM.TestCase): for group in groups: self.assertIn(f'{group}', config) + + def test_04_exclude_vrrp_interface(self): + group = 'VyOS-WAN' + none_vrrp_interface = 'eth2' + vlan_id = '24' + vip = '100.64.24.1/24' + vip_dev = '192.0.2.2/24' + vrid = '150' + group_base = base_path + ['group', group] + + self.cli_set(['interfaces', 'ethernet', vrrp_interface, 'vif', vlan_id, 'address', '100.64.24.11/24']) + self.cli_set(group_base + ['interface', f'{vrrp_interface}.{vlan_id}']) + self.cli_set(group_base + ['virtual-address', vip]) + self.cli_set(group_base + ['virtual-address', vip_dev, 'interface', none_vrrp_interface]) + self.cli_set(group_base + ['track', 'exclude-vrrp-interface']) + self.cli_set(group_base + ['track', 'interface', none_vrrp_interface]) + self.cli_set(group_base + ['vrid', vrid]) + + # commit changes + self.cli_commit() + + config = getConfig(f'vrrp_instance {group}') + + self.assertIn(f'interface {vrrp_interface}.{vlan_id}', config) + self.assertIn(f'virtual_router_id {vrid}', config) + self.assertIn(f'dont_track_primary', config) + self.assertIn(f' {vip}', config) + self.assertIn(f' {vip_dev} dev {none_vrrp_interface}', config) + self.assertIn(f'track_interface', config) + self.assertIn(f' {none_vrrp_interface}', config) + + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/op_mode/show_dhcpv6.py b/src/op_mode/show_dhcpv6.py index ac211fb0a..f70f04298 100755 --- a/src/op_mode/show_dhcpv6.py +++ b/src/op_mode/show_dhcpv6.py @@ -139,7 +139,7 @@ def get_leases(config, leases, state, pool=None, sort='ip'): # apply output/display sort if sort == 'ip': - leases = sorted(leases, key = lambda k: int(ip_address(k['ip']))) + leases = sorted(leases, key = lambda k: int(ip_address(k['ip'].split('/')[0]))) else: leases = sorted(leases, key = lambda k: k[sort]) |