diff options
-rw-r--r-- | interface-definitions/include/interface/vif.xml.i | 14 | ||||
-rw-r--r-- | python/vyos/ifconfig/interface.py | 47 | ||||
-rw-r--r-- | smoketest/scripts/cli/base_interfaces_test.py | 101 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_bridge.py | 8 |
4 files changed, 161 insertions, 9 deletions
diff --git a/interface-definitions/include/interface/vif.xml.i b/interface-definitions/include/interface/vif.xml.i index 0355054a4..9e89cbbf6 100644 --- a/interface-definitions/include/interface/vif.xml.i +++ b/interface-definitions/include/interface/vif.xml.i @@ -22,9 +22,10 @@ <leafNode name="egress-qos"> <properties> <help>VLAN egress QoS</help> - <completionHelp> - <script>echo Format for qos mapping, e.g.: '0:1 1:6 7:6'</script> - </completionHelp> + <valueHelp> + <format>txt</format> + <description>Format for qos mapping, e.g.: '0:1 1:6 7:6'</description> + </valueHelp> <constraint> <regex>[:0-7 ]+$</regex> </constraint> @@ -34,9 +35,10 @@ <leafNode name="ingress-qos"> <properties> <help>VLAN ingress QoS</help> - <completionHelp> - <script>echo Format for qos mapping '0:1 1:6 7:6'</script> - </completionHelp> + <valueHelp> + <format>txt</format> + <description>Format for qos mapping, e.g.: '0:1 1:6 7:6'</description> + </valueHelp> <constraint> <regex>[:0-7 ]+$</regex> </constraint> diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 048a2cd19..6a66d958f 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1345,12 +1345,55 @@ class Interface(Control): # create/update 802.1q VLAN interfaces for vif_id, vif_config in config.get('vif', {}).items(): + + vif_ifname = f'{ifname}.{vif_id}' + vif_config['ifname'] = vif_ifname + tmp = deepcopy(VLANIf.get_config()) tmp['source_interface'] = ifname tmp['vlan_id'] = vif_id + + # We need to ensure that the string format is consistent, and we need to exclude redundant spaces. + sep = ' ' + if 'egress_qos' in vif_config: + # Unwrap strings into arrays + egress_qos_array = vif_config['egress_qos'].split() + # The split array is spliced according to the fixed format + tmp['egress_qos'] = sep.join(egress_qos_array) + + if 'ingress_qos' in vif_config: + # Unwrap strings into arrays + ingress_qos_array = vif_config['ingress_qos'].split() + # The split array is spliced according to the fixed format + tmp['ingress_qos'] = sep.join(ingress_qos_array) + + # Since setting the QoS control parameters in the later stage will + # not completely delete the old settings, + # we still need to delete the VLAN encapsulation interface in order to + # ensure that the changed settings are effective. + cur_cfg = get_interface_config(vif_ifname) + qos_str = '' + tmp2 = dict_search('linkinfo.info_data.ingress_qos', cur_cfg) + if 'ingress_qos' in tmp and tmp2: + for item in tmp2: + from_key = item['from'] + to_key = item['to'] + qos_str += f'{from_key}:{to_key} ' + if qos_str != tmp['ingress_qos']: + if self.exists(vif_ifname): + VLANIf(vif_ifname).remove() + + qos_str = '' + tmp2 = dict_search('linkinfo.info_data.egress_qos', cur_cfg) + if 'egress_qos' in tmp and tmp2: + for item in tmp2: + from_key = item['from'] + to_key = item['to'] + qos_str += f'{from_key}:{to_key} ' + if qos_str != tmp['egress_qos']: + if self.exists(vif_ifname): + VLANIf(vif_ifname).remove() - vif_ifname = f'{ifname}.{vif_id}' - vif_config['ifname'] = vif_ifname vlan = VLANIf(vif_ifname, **tmp) vlan.update(vif_config) diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py index 56e436afc..b83091ea6 100644 --- a/smoketest/scripts/cli/base_interfaces_test.py +++ b/smoketest/scripts/cli/base_interfaces_test.py @@ -278,18 +278,119 @@ class BasicInterfaceTest: self.cli_set(base + ['mtu', self._mtu]) for address in self._test_addr: self.cli_set(base + ['address', address]) + self.cli_set(base + ['ingress-qos', '0:1']) + self.cli_set(base + ['egress-qos', '1:6']) self.cli_commit() for intf in self._interfaces: for vlan in self._vlan_range: vif = f'{intf}.{vlan}' + tmp = get_interface_config(f'{vif}') + + tmp2 = dict_search('linkinfo.info_data.ingress_qos', tmp) + for item in tmp2 if tmp2 else []: + from_key = item['from'] + to_key = item['to'] + self.assertEqual(from_key, 0) + self.assertEqual(to_key, 1) + + tmp2 = dict_search('linkinfo.info_data.egress_qos', tmp) + for item in tmp2 if tmp2 else []: + from_key = item['from'] + to_key = item['to'] + self.assertEqual(from_key, 1) + self.assertEqual(to_key, 6) + for address in self._test_addr: self.assertTrue(is_intf_addr_assigned(vif, address)) tmp = read_file(f'/sys/class/net/{vif}/mtu') self.assertEqual(tmp, self._mtu) self.assertEqual(Interface(vif).get_admin_state(), 'up') + + def test_vif_qos_change(self): + # XXX: This testcase is not allowed to run as first testcase, reason + # is the Wireless test will first load the wifi kernel hwsim module + # which creates a wlan0 and wlan1 interface which will fail the + # tearDown() test in the end that no interface is allowed to survive! + if not self._test_vlan: + self.skipTest('not supported') + + for interface in self._interfaces: + base = self._base_path + [interface] + for option in self._options.get(interface, []): + self.cli_set(base + option.split()) + + for vlan in self._vlan_range: + base = self._base_path + [interface, 'vif', vlan] + self.cli_set(base + ['mtu', self._mtu]) + for address in self._test_addr: + self.cli_set(base + ['address', address]) + self.cli_set(base + ['ingress-qos', '0:1']) + self.cli_set(base + ['egress-qos', '1:6']) + + self.cli_commit() + + for intf in self._interfaces: + for vlan in self._vlan_range: + vif = f'{intf}.{vlan}' + tmp = get_interface_config(f'{vif}') + + tmp2 = dict_search('linkinfo.info_data.ingress_qos', tmp) + for item in tmp2 if tmp2 else []: + from_key = item['from'] + to_key = item['to'] + self.assertEqual(from_key, 0) + self.assertEqual(to_key, 1) + + tmp2 = dict_search('linkinfo.info_data.egress_qos', tmp) + for item in tmp2 if tmp2 else []: + from_key = item['from'] + to_key = item['to'] + self.assertEqual(from_key, 1) + self.assertEqual(to_key, 6) + + for address in self._test_addr: + self.assertTrue(is_intf_addr_assigned(vif, address)) + + tmp = read_file(f'/sys/class/net/{vif}/mtu') + self.assertEqual(tmp, self._mtu) + self.assertEqual(Interface(vif).get_admin_state(), 'up') + + new_ingress_qos_from = 1 + new_ingress_qos_to = 6 + new_egress_qos_from = 2 + new_egress_qos_to = 7 + for interface in self._interfaces: + base = self._base_path + [interface] + for vlan in self._vlan_range: + base = self._base_path + [interface, 'vif', vlan] + self.cli_delete(base + ['ingress-qos', '0:1']) + self.cli_delete(base + ['egress-qos', '1:6']) + self.cli_set(base + ['ingress-qos', f'{new_ingress_qos_from}:{new_ingress_qos_to}']) + self.cli_set(base + ['egress-qos', f'{new_egress_qos_from}:{new_egress_qos_to}']) + + self.cli_commit() + + for intf in self._interfaces: + for vlan in self._vlan_range: + vif = f'{intf}.{vlan}' + tmp = get_interface_config(f'{vif}') + + tmp2 = dict_search('linkinfo.info_data.ingress_qos', tmp) + if tmp2: + from_key = tmp2[0]['from'] + to_key = tmp2[0]['to'] + self.assertEqual(from_key, new_ingress_qos_from) + self.assertEqual(to_key, new_ingress_qos_to) + + tmp2 = dict_search('linkinfo.info_data.egress_qos', tmp) + if tmp2: + from_key = tmp2[0]['from'] + to_key = tmp2[0]['to'] + self.assertEqual(from_key, new_egress_qos_from) + self.assertEqual(to_key, new_egress_qos_to) def test_vif_8021q_lower_up_down(self): # Testcase for https://phabricator.vyos.net/T3349 diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py index 21f20c781..6865d3a8a 100755 --- a/smoketest/scripts/cli/test_interfaces_bridge.py +++ b/smoketest/scripts/cli/test_interfaces_bridge.py @@ -134,7 +134,13 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase): for interface in self._interfaces: base = self._base_path + [interface] self.cli_set(base + ['enable-vlan']) - super().test_vif_8021q_interfaces() + super().test_vif_8021q_lower_up_down() + + def test_vif_qos_change(self): + for interface in self._interfaces: + base = self._base_path + [interface] + self.cli_set(base + ['enable-vlan']) + super().test_vif_qos_change() def test_bridge_vlan_filter(self): vif_vlan = 2 |