From 3508feea888bfc0d95eb8928d98afd50bc335eb9 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 1 Oct 2020 19:43:12 +0200 Subject: configdict: T2372: use config.exists() when probing for interface removal We must use exists() as get_config_dict() will always return {} - even when an empty interface node like +macsec macsec1 { +} exists. --- python/vyos/configdict.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'python') diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py index 58ecd3f17..660d779d4 100644 --- a/python/vyos/configdict.py +++ b/python/vyos/configdict.py @@ -290,8 +290,12 @@ def get_interface_dict(config, base, ifname=''): config.set_level(base + [ifname]) dict = config.get_config_dict([], key_mangling=('-', '_'), get_first_key=True) - # Check if interface has been removed - if dict == {}: + # Check if interface has been removed. We must use exists() as get_config_dict() + # will always return {} - even when an empty interface node like + # +macsec macsec1 { + # +} + # exists. + if not config.exists([]): dict.update({'deleted' : ''}) # Add interface instance name into dictionary -- cgit v1.2.3 From 4cfb3515475d95313ad1840978ee09704bd6351a Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 1 Oct 2020 21:30:23 +0200 Subject: vlan: configdict: T2945: determine if vlan is part of bridge Every interface knows if it is part of a bridge or not - except a VLAN (VIF) interface. Also VLANs should be aware of its master bridge. Add a testcase to ensure when VIFs on an interface change the bridge does not loos one of it's members. --- python/vyos/configdict.py | 13 +++++++++ smoketest/scripts/cli/test_interfaces_bridge.py | 37 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) (limited to 'python') diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py index 660d779d4..ce6d58693 100644 --- a/python/vyos/configdict.py +++ b/python/vyos/configdict.py @@ -360,6 +360,10 @@ def get_interface_dict(config, base, ifname=''): # XXX: T2665: blend in proper DHCPv6-PD default values dict['vif'][vif] = T2665_set_dhcpv6pd_defaults(dict['vif'][vif]) + # Check if we are a member of a bridge device + bridge = is_member(config, f'{ifname}.{vif}', 'bridge') + if bridge: dict['vif'][vif].update({'is_bridge_member' : bridge}) + for vif_s, vif_s_config in dict.get('vif_s', {}).items(): default_vif_s_values = defaults(base + ['vif-s']) # XXX: T2665: we only wan't the vif-s defaults - do not care about vif-c @@ -375,6 +379,10 @@ def get_interface_dict(config, base, ifname=''): dict['vif_s'][vif_s] = T2665_set_dhcpv6pd_defaults( dict['vif_s'][vif_s]) + # Check if we are a member of a bridge device + bridge = is_member(config, f'{ifname}.{vif_s}', 'bridge') + if bridge: dict['vif_s'][vif_s].update({'is_bridge_member' : bridge}) + for vif_c, vif_c_config in vif_s_config.get('vif_c', {}).items(): default_vif_c_values = defaults(base + ['vif-s', 'vif-c']) @@ -389,6 +397,11 @@ def get_interface_dict(config, base, ifname=''): dict['vif_s'][vif_s]['vif_c'][vif_c] = T2665_set_dhcpv6pd_defaults( dict['vif_s'][vif_s]['vif_c'][vif_c]) + # Check if we are a member of a bridge device + bridge = is_member(config, f'{ifname}.{vif_s}.{vif_c}', 'bridge') + if bridge: dict['vif_s'][vif_s]['vif_c'][vif_c].update( + {'is_bridge_member' : bridge}) + # Check vif, vif-s/vif-c VLAN interfaces for removal dict = get_removed_vlans(config, dict) return dict diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py index bc0bb69c6..a1359680b 100755 --- a/smoketest/scripts/cli/test_interfaces_bridge.py +++ b/smoketest/scripts/cli/test_interfaces_bridge.py @@ -18,6 +18,8 @@ import os import unittest from base_interfaces_test import BasicInterfaceTest +from glob import glob +from netifaces import interfaces from vyos.ifconfig import Section class BridgeInterfaceTest(BasicInterfaceTest.BaseTest): @@ -44,6 +46,7 @@ class BridgeInterfaceTest(BasicInterfaceTest.BaseTest): self._options['br0'].append(f'member interface {member}') def test_add_remove_member(self): + """ Add member interfaces to bridge and set STP cost/priority """ for interface in self._interfaces: base = self._base_path + [interface] self.session.set(base + ['stp']) @@ -59,12 +62,46 @@ class BridgeInterfaceTest(BasicInterfaceTest.BaseTest): cost += 1 priority += 1 + # commit config self.session.commit() + # check member interfaces are added on the bridge + bridge_members = [] + for tmp in glob(f'/sys/class/net/{interface}/lower_*'): + bridge_members.append(os.path.basename(tmp).replace('lower_', '')) + + for member in self._members: + self.assertIn(member, bridge_members) + + # delete all members for interface in self._interfaces: self.session.delete(self._base_path + [interface, 'member']) self.session.commit() + def test_vlan_members(self): + """ T2945: ensure that VIFs are not dropped from bridge """ + + self.session.set(['interfaces', 'ethernet', 'eth0', 'vif', '300']) + self.session.set(['interfaces', 'bridge', 'br0', 'member', 'interface', 'eth0.300']) + self.session.commit() + + # member interface must be assigned to the bridge + self.assertTrue(os.path.exists('/sys/class/net/br0/lower_eth0.300')) + + # add second bridge member + self.session.set(['interfaces', 'ethernet', 'eth0', 'vif', '400']) + self.session.commit() + + # member interface must still be assigned to the bridge + self.assertTrue(os.path.exists('/sys/class/net/br0/lower_eth0.300')) + + # remove VLAN interfaces + self.session.delete(['interfaces', 'ethernet', 'eth0', 'vif', '300']) + self.session.delete(['interfaces', 'ethernet', 'eth0', 'vif', '400']) + self.session.commit() + + if __name__ == '__main__': unittest.main() + -- cgit v1.2.3 From 2123eef951467ea2e69ec2ad3f68e0282f84414e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 3 Oct 2020 11:47:14 +0200 Subject: vyos.xml: T2956: add support for list of defaultValues Sometimes (PPPoE server is one of them) a simple defaultValue in the XML is not enough - several values should be set. In order to support a list of defaultValues you can now simply list them as a whitespace separated string. Example: pap chap mschap mschap-v2 will generate a Python list ['pap', 'chap', 'mschap', 'mschap-v2'] when retrieved by vyos.xml.defaults() --- python/vyos/xml/definition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python') diff --git a/python/vyos/xml/definition.py b/python/vyos/xml/definition.py index a25fc50c5..7831af4d2 100644 --- a/python/vyos/xml/definition.py +++ b/python/vyos/xml/definition.py @@ -297,7 +297,7 @@ class XML(dict): continue value = conf[k] if self.is_multi(fpath) and not isinstance(value, list): - value = [value] + value = value.split(' ') r[under] = value return r -- cgit v1.2.3