diff --git a/README.md b/README.md index fa7929d..f753fa9 100644 --- a/README.md +++ b/README.md @@ -357,57 +357,57 @@ kernel and device, changing some features might not be supported. ```yaml ethtool: features: - esp-hw-offload: yes|no # optional - esp-tx-csum-hw-offload: yes|no # optional - fcoe-mtu: yes|no # optional + esp_hw_offload: yes|no # optional + esp_tx_csum_hw_offload: yes|no # optional + fcoe_mtu: yes|no # optional gro: yes|no # optional gso: yes|no # optional highdma: yes|no # optional - hw-tc-offload: yes|no # optional - l2-fwd-offload: yes|no # optional + hw_tc_offload: yes|no # optional + l2_fwd_offload: yes|no # optional loopback: yes|no # optional lro: yes|no # optional ntuple: yes|no # optional rx: yes|no # optional - rx-all: yes|no # optional - rx-fcs: yes|no # optional - rx-gro-hw: yes|no # optional - rx-udp_tunnel-port-offload: yes|no # optional - rx-vlan-filter: yes|no # optional - rx-vlan-stag-filter: yes|no # optional - rx-vlan-stag-hw-parse: yes|no # optional + rx_all: yes|no # optional + rx_fcs: yes|no # optional + rx_gro_hw: yes|no # optional + rx_udp_tunnel_port_offload: yes|no # optional + rx_vlan_filter: yes|no # optional + rx_vlan_stag_filter: yes|no # optional + rx_vlan_stag_hw_parse: yes|no # optional rxhash: yes|no # optional rxvlan: yes|no # optional sg: yes|no # optional - tls-hw-record: yes|no # optional - tls-hw-tx-offload: yes|no # optional + tls_hw_record: yes|no # optional + tls_hw_tx_offload: yes|no # optional tso: yes|no # optional tx: yes|no # optional - tx-checksum-fcoe-crc: yes|no # optional - tx-checksum-ip-generic: yes|no # optional - tx-checksum-ipv4: yes|no # optional - tx-checksum-ipv6: yes|no # optional - tx-checksum-sctp: yes|no # optional - tx-esp-segmentation: yes|no # optional - tx-fcoe-segmentation: yes|no # optional - tx-gre-csum-segmentation: yes|no # optional - tx-gre-segmentation: yes|no # optional - tx-gso-partial: yes|no # optional - tx-gso-robust: yes|no # optional - tx-ipxip4-segmentation: yes|no # optional - tx-ipxip6-segmentation: yes|no # optional - tx-nocache-copy: yes|no # optional - tx-scatter-gather: yes|no # optional - tx-scatter-gather-fraglist: yes|no # optional - tx-sctp-segmentation: yes|no # optional - tx-tcp-ecn-segmentation: yes|no # optional - tx-tcp-mangleid-segmentation: yes|no # optional - tx-tcp-segmentation: yes|no # optional - tx-tcp6-segmentation: yes|no # optional - tx-udp-segmentation: yes|no # optional - tx-udp_tnl-csum-segmentation: yes|no # optional - tx-udp_tnl-segmentation: yes|no # optional - tx-vlan-stag-hw-insert: yes|no # optional + tx_checksum_fcoe_crc: yes|no # optional + tx_checksum_ip_generic: yes|no # optional + tx_checksum_ipv4: yes|no # optional + tx_checksum_ipv6: yes|no # optional + tx_checksum_sctp: yes|no # optional + tx_esp_segmentation: yes|no # optional + tx_fcoe_segmentation: yes|no # optional + tx_gre_csum_segmentation: yes|no # optional + tx_gre_segmentation: yes|no # optional + tx_gso_partial: yes|no # optional + tx_gso_robust: yes|no # optional + tx_ipxip4_segmentation: yes|no # optional + tx_ipxip6_segmentation: yes|no # optional + tx_nocache_copy: yes|no # optional + tx_scatter_gather: yes|no # optional + tx_scatter_gather_fraglist: yes|no # optional + tx_sctp_segmentation: yes|no # optional + tx_tcp_ecn_segmentation: yes|no # optional + tx_tcp_mangleid_segmentation: yes|no # optional + tx_tcp_segmentation: yes|no # optional + tx_tcp6_segmentation: yes|no # optional + tx_udp_segmentation: yes|no # optional + tx_udp_tnl_csum_segmentation: yes|no # optional + tx_udp_tnl_segmentation: yes|no # optional + tx_vlan_stag_hw_insert: yes|no # optional txvlan: yes|no # optional ``` diff --git a/examples/ethtool_features.yml b/examples/ethtool_features.yml index d8842c2..c580f89 100644 --- a/examples/ethtool_features.yml +++ b/examples/ethtool_features.yml @@ -16,4 +16,4 @@ features: gro: "no" gso: "yes" - tx-sctp-segmentation: "no" + tx_sctp_segmentation: "no" diff --git a/library/network_connections.py b/library/network_connections.py index 217a178..1935f70 100644 --- a/library/network_connections.py +++ b/library/network_connections.py @@ -369,6 +369,7 @@ class IfcfgUtil: ethtool_features = connection["ethtool"]["features"] configured_features = [] for feature, setting in ethtool_features.items(): + feature = feature.replace("_", "-") value = "" if setting: value = "on" diff --git a/module_utils/network_lsr/argument_validator.py b/module_utils/network_lsr/argument_validator.py index 06dc58d..f82e740 100644 --- a/module_utils/network_lsr/argument_validator.py +++ b/module_utils/network_lsr/argument_validator.py @@ -199,6 +199,12 @@ class ArgValidatorBool(ArgValidator): raise ValidationError(name, "must be an boolean but is '%s'" % (value)) +class ArgValidatorDeprecated: + def __init__(self, name, deprecated_by): + self.name = name + self.deprecated_by = deprecated_by + + class ArgValidatorDict(ArgValidator): def __init__( self, @@ -222,26 +228,33 @@ class ArgValidatorDict(ArgValidator): items = list(value.items()) except AttributeError: raise ValidationError(name, "invalid content is not a dictionary") - for (k, v) in items: - if k in seen_keys: - raise ValidationError(name, "duplicate key '%s'" % (k)) - seen_keys.add(k) - validator = self.nested.get(k, None) - if validator is None: - raise ValidationError(name, "invalid key '%s'" % (k)) + for (setting, value) in items: try: - vv = validator._validate(v, name + "." + k) + validator = self.nested[setting] + except KeyError: + raise ValidationError(name, "invalid key '%s'" % (setting)) + if isinstance(validator, ArgValidatorDeprecated): + setting = validator.deprecated_by + validator = self.nested.get(setting, None) + if setting in seen_keys: + raise ValidationError(name, "duplicate key '%s'" % (setting)) + seen_keys.add(setting) + try: + validated_value = validator._validate(value, name + "." + setting) except ValidationError as e: raise ValidationError(e.name, e.error_message) - result[k] = vv - for (k, v) in self.nested.items(): - if k in seen_keys: + result[setting] = validated_value + for (setting, validator) in self.nested.items(): + if setting in seen_keys or isinstance(validator, ArgValidatorDeprecated): continue - if v.required: - raise ValidationError(name, "missing required key '%s'" % (k)) - vv = v.get_default_value() - if not self.all_missing_during_validate and vv is not ArgValidator.MISSING: - result[k] = vv + if validator.required: + raise ValidationError(name, "missing required key '%s'" % (setting)) + default_value = validator.get_default_value() + if ( + not self.all_missing_during_validate + and default_value is not ArgValidator.MISSING + ): + result[setting] = default_value return result @@ -549,62 +562,174 @@ class ArgValidator_DictEthtoolFeatures(ArgValidatorDict): self, name="features", nested=[ - ArgValidatorBool("esp-hw-offload", default_value=None), - ArgValidatorBool("esp-tx-csum-hw-offload", default_value=None), - ArgValidatorBool("fcoe-mtu", default_value=None), + ArgValidatorBool("esp_hw_offload", default_value=None), + ArgValidatorDeprecated( + "esp-hw-offload", deprecated_by="esp_hw_offload" + ), + ArgValidatorBool("esp_tx_csum_hw_offload", default_value=None), + ArgValidatorDeprecated( + "esp-tx-csum-hw-offload", deprecated_by="esp_tx_csum_hw_offload", + ), + ArgValidatorBool("fcoe_mtu", default_value=None), + ArgValidatorDeprecated("fcoe-mtu", deprecated_by="fcoe_mtu"), ArgValidatorBool("gro", default_value=None), ArgValidatorBool("gso", default_value=None), ArgValidatorBool("highdma", default_value=None), - ArgValidatorBool("hw-tc-offload", default_value=None), - ArgValidatorBool("l2-fwd-offload", default_value=None), + ArgValidatorBool("hw_tc_offload", default_value=None), + ArgValidatorDeprecated("hw-tc-offload", deprecated_by="hw_tc_offload"), + ArgValidatorBool("l2_fwd_offload", default_value=None), + ArgValidatorDeprecated( + "l2-fwd-offload", deprecated_by="l2_fwd_offload" + ), ArgValidatorBool("loopback", default_value=None), ArgValidatorBool("lro", default_value=None), ArgValidatorBool("ntuple", default_value=None), ArgValidatorBool("rx", default_value=None), ArgValidatorBool("rxhash", default_value=None), ArgValidatorBool("rxvlan", default_value=None), - ArgValidatorBool("rx-all", default_value=None), - ArgValidatorBool("rx-fcs", default_value=None), - ArgValidatorBool("rx-gro-hw", default_value=None), - ArgValidatorBool("rx-udp_tunnel-port-offload", default_value=None), - ArgValidatorBool("rx-vlan-filter", default_value=None), - ArgValidatorBool("rx-vlan-stag-filter", default_value=None), - ArgValidatorBool("rx-vlan-stag-hw-parse", default_value=None), + ArgValidatorBool("rx_all", default_value=None), + ArgValidatorDeprecated("rx-all", deprecated_by="rx_all"), + ArgValidatorBool("rx_fcs", default_value=None), + ArgValidatorDeprecated("rx-fcs", deprecated_by="rx_fcs"), + ArgValidatorBool("rx_gro_hw", default_value=None), + ArgValidatorDeprecated("rx-gro-hw", deprecated_by="rx_gro_hw"), + ArgValidatorBool("rx_udp_tunnel_port_offload", default_value=None), + ArgValidatorDeprecated( + "rx-udp_tunnel-port-offload", + deprecated_by="rx_udp_tunnel_port_offload", + ), + ArgValidatorBool("rx_vlan_filter", default_value=None), + ArgValidatorDeprecated( + "rx-vlan-filter", deprecated_by="rx_vlan_filter" + ), + ArgValidatorBool("rx_vlan_stag_filter", default_value=None), + ArgValidatorDeprecated( + "rx-vlan-stag-filter", deprecated_by="rx_vlan_stag_filter", + ), + ArgValidatorBool("rx_vlan_stag_hw_parse", default_value=None), + ArgValidatorDeprecated( + "rx-vlan-stag-hw-parse", deprecated_by="rx_vlan_stag_hw_parse", + ), ArgValidatorBool("sg", default_value=None), - ArgValidatorBool("tls-hw-record", default_value=None), - ArgValidatorBool("tls-hw-tx-offload", default_value=None), + ArgValidatorBool("tls_hw_record", default_value=None), + ArgValidatorDeprecated("tls-hw-record", deprecated_by="tls_hw_record"), + ArgValidatorBool("tls_hw_tx_offload", default_value=None), + ArgValidatorDeprecated( + "tls-hw-tx-offload", deprecated_by="tls_hw_tx_offload", + ), ArgValidatorBool("tso", default_value=None), ArgValidatorBool("tx", default_value=None), ArgValidatorBool("txvlan", default_value=None), - ArgValidatorBool("tx-checksum-fcoe-crc", default_value=None), - ArgValidatorBool("tx-checksum-ipv4", default_value=None), - ArgValidatorBool("tx-checksum-ipv6", default_value=None), - ArgValidatorBool("tx-checksum-ip-generic", default_value=None), - ArgValidatorBool("tx-checksum-sctp", default_value=None), - ArgValidatorBool("tx-esp-segmentation", default_value=None), - ArgValidatorBool("tx-fcoe-segmentation", default_value=None), - ArgValidatorBool("tx-gre-csum-segmentation", default_value=None), - ArgValidatorBool("tx-gre-segmentation", default_value=None), - ArgValidatorBool("tx-gso-partial", default_value=None), - ArgValidatorBool("tx-gso-robust", default_value=None), - ArgValidatorBool("tx-ipxip4-segmentation", default_value=None), - ArgValidatorBool("tx-ipxip6-segmentation", default_value=None), - ArgValidatorBool("tx-nocache-copy", default_value=None), - ArgValidatorBool("tx-scatter-gather", default_value=None), - ArgValidatorBool("tx-scatter-gather-fraglist", default_value=None), - ArgValidatorBool("tx-sctp-segmentation", default_value=None), - ArgValidatorBool("tx-tcp6-segmentation", default_value=None), - ArgValidatorBool("tx-tcp-ecn-segmentation", default_value=None), - ArgValidatorBool("tx-tcp-mangleid-segmentation", default_value=None), - ArgValidatorBool("tx-tcp-segmentation", default_value=None), - ArgValidatorBool("tx-udp-segmentation", default_value=None), - ArgValidatorBool("tx-udp_tnl-csum-segmentation", default_value=None), - ArgValidatorBool("tx-udp_tnl-segmentation", default_value=None), - ArgValidatorBool("tx-vlan-stag-hw-insert", default_value=None), + ArgValidatorBool("tx_checksum_fcoe_crc", default_value=None), + ArgValidatorDeprecated( + "tx-checksum-fcoe-crc", deprecated_by="tx_checksum_fcoe_crc", + ), + ArgValidatorBool("tx_checksum_ipv4", default_value=None), + ArgValidatorDeprecated( + "tx-checksum-ipv4", deprecated_by="tx_checksum_ipv4", + ), + ArgValidatorBool("tx_checksum_ipv6", default_value=None), + ArgValidatorDeprecated( + "tx-checksum-ipv6", deprecated_by="tx_checksum_ipv6", + ), + ArgValidatorBool("tx_checksum_ip_generic", default_value=None), + ArgValidatorDeprecated( + "tx-checksum-ip-generic", deprecated_by="tx_checksum_ip_generic", + ), + ArgValidatorBool("tx_checksum_sctp", default_value=None), + ArgValidatorDeprecated( + "tx-checksum-sctp", deprecated_by="tx_checksum_sctp", + ), + ArgValidatorBool("tx_esp_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-esp-segmentation", deprecated_by="tx_esp_segmentation", + ), + ArgValidatorBool("tx_fcoe_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-fcoe-segmentation", deprecated_by="tx_fcoe_segmentation", + ), + ArgValidatorBool("tx_gre_csum_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-gre-csum-segmentation", + deprecated_by="tx_gre_csum_segmentation", + ), + ArgValidatorBool("tx_gre_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-gre-segmentation", deprecated_by="tx_gre_segmentation", + ), + ArgValidatorBool("tx_gso_partial", default_value=None), + ArgValidatorDeprecated( + "tx-gso-partial", deprecated_by="tx_gso_partial" + ), + ArgValidatorBool("tx_gso_robust", default_value=None), + ArgValidatorDeprecated("tx-gso-robust", deprecated_by="tx_gso_robust"), + ArgValidatorBool("tx_ipxip4_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-ipxip4-segmentation", deprecated_by="tx_ipxip4_segmentation", + ), + ArgValidatorBool("tx_ipxip6_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-ipxip6-segmentation", deprecated_by="tx_ipxip6_segmentation", + ), + ArgValidatorBool("tx_nocache_copy", default_value=None), + ArgValidatorDeprecated( + "tx-nocache-copy", deprecated_by="tx_nocache_copy", + ), + ArgValidatorBool("tx_scatter_gather", default_value=None), + ArgValidatorDeprecated( + "tx-scatter-gather", deprecated_by="tx_scatter_gather", + ), + ArgValidatorBool("tx_scatter_gather_fraglist", default_value=None), + ArgValidatorDeprecated( + "tx-scatter-gather-fraglist", + deprecated_by="tx_scatter_gather_fraglist", + ), + ArgValidatorBool("tx_sctp_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-sctp-segmentation", deprecated_by="tx_sctp_segmentation", + ), + ArgValidatorBool("tx_tcp6_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-tcp6-segmentation", deprecated_by="tx_tcp6_segmentation", + ), + ArgValidatorBool("tx_tcp_ecn_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-tcp-ecn-segmentation", deprecated_by="tx_tcp_ecn_segmentation", + ), + ArgValidatorBool("tx_tcp_mangleid_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-tcp-mangleid-segmentation", + deprecated_by="tx_tcp_mangleid_segmentation", + ), + ArgValidatorBool("tx_tcp_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-tcp-segmentation", deprecated_by="tx_tcp_segmentation", + ), + ArgValidatorBool("tx_udp_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-udp-segmentation", deprecated_by="tx_udp_segmentation", + ), + ArgValidatorBool("tx_udp_tnl_csum_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-udp_tnl-csum-segmentation", + deprecated_by="tx_udp_tnl_csum_segmentation", + ), + ArgValidatorBool("tx_udp_tnl_segmentation", default_value=None), + ArgValidatorDeprecated( + "tx-udp_tnl-segmentation", deprecated_by="tx_udp_tnl_segmentation", + ), + ArgValidatorBool("tx_vlan_stag_hw_insert", default_value=None), + ArgValidatorDeprecated( + "tx-vlan-stag-hw-insert", deprecated_by="tx_vlan_stag_hw_insert", + ), ], ) self.default_value = dict( - [(k, v.default_value) for k, v in self.nested.items()] + [ + (name, validator.default_value) + for name, validator in self.nested.items() + if not isinstance(validator, ArgValidatorDeprecated) + ] ) diff --git a/module_utils/network_lsr/nm_provider.py b/module_utils/network_lsr/nm_provider.py index 9f9b028..c59330e 100644 --- a/module_utils/network_lsr/nm_provider.py +++ b/module_utils/network_lsr/nm_provider.py @@ -17,7 +17,7 @@ def get_nm_ethtool_feature(name): :rtype: str """ - name = ETHTOOL_FEATURE_PREFIX + name.upper().replace("-", "_") + name = ETHTOOL_FEATURE_PREFIX + name.upper() feature = getattr(Util.NM(), name, None) return feature diff --git a/tests/playbooks/tests_ethtool_features.yml b/tests/playbooks/tests_ethtool_features.yml index bdaddb0..76b0f8a 100644 --- a/tests/playbooks/tests_ethtool_features.yml +++ b/tests/playbooks/tests_ethtool_features.yml @@ -79,6 +79,72 @@ - >- 'tx-tcp-segmentation: off' in ethtool_features.stdout_lines | map('trim') + - name: >- + TEST: I can enable tx_tcp_segmentation (using underscores). + debug: + msg: "##################################################" + - import_role: + name: linux-system-roles.network + vars: + network_connections: + - name: "{{ interface }}" + state: up + type: ethernet + ip: + dhcp4: "no" + auto6: "no" + ethtool: + features: + tx_tcp_segmentation: "yes" + - name: Get current device features + command: "ethtool --show-features {{ interface }}" + register: ethtool_features + - name: + debug: + var: ethtool_features.stdout_lines + - name: Assert device features + assert: + that: + - >- + 'tx-tcp-segmentation: on' in + ethtool_features.stdout_lines | map('trim') + - name: I cannot change tx_tcp_segmentation and tx-tcp-segmentation at + the same time. + block: + - name: >- + TEST: Change feature with both underscores and dashes. + debug: + msg: "##################################################" + - network_connections: + provider: "{{ network_provider | mandatory }}" + connections: + - name: "{{ interface }}" + state: up + type: ethernet + ip: + dhcp4: "no" + auto6: "no" + ethtool: + features: + tx_tcp_segmentation: "no" + tx-tcp-segmentation: "no" + register: __network_connections_result + rescue: + - name: Show network_connections result + debug: + var: __network_connections_result + - assert: + that: + - '{{ "fatal error: configuration error: + connections[0].ethtool.features: duplicate key + ''tx_tcp_segmentation''" in + __network_connections_result.msg }}' + always: + - name: Check failure + debug: + var: __network_connections_result + - assert: + that: "{{ __network_connections_result.failed == true }}" - name: "TEST: I can reset features to their original value." debug: msg: "##################################################" diff --git a/tests/unit/test_network_connections.py b/tests/unit/test_network_connections.py index 939f4f2..3ec9520 100755 --- a/tests/unit/test_network_connections.py +++ b/tests/unit/test_network_connections.py @@ -8,6 +8,7 @@ import pprint as pprint_ import socket import sys import unittest +import copy TESTS_BASEDIR = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(1, os.path.join(TESTS_BASEDIR, "../..", "library")) @@ -69,57 +70,57 @@ VALIDATE_ONE_MODE_INITSCRIPTS = ARGS_CONNECTIONS.VALIDATE_ONE_MODE_INITSCRIPTS VALIDATE_ONE_MODE_NM = ARGS_CONNECTIONS.VALIDATE_ONE_MODE_NM ETHTOOL_FEATURES_DEFAULTS = { - "esp-hw-offload": None, - "esp-tx-csum-hw-offload": None, - "fcoe-mtu": None, + "esp_hw_offload": None, + "esp_tx_csum_hw_offload": None, + "fcoe_mtu": None, "gro": None, "gso": None, "highdma": None, - "hw-tc-offload": None, - "l2-fwd-offload": None, + "hw_tc_offload": None, + "l2_fwd_offload": None, "loopback": None, "lro": None, "ntuple": None, "rx": None, - "rx-all": None, - "rx-fcs": None, - "rx-gro-hw": None, - "rx-udp_tunnel-port-offload": None, - "rx-vlan-filter": None, - "rx-vlan-stag-filter": None, - "rx-vlan-stag-hw-parse": None, + "rx_all": None, + "rx_fcs": None, + "rx_gro_hw": None, + "rx_udp_tunnel_port_offload": None, + "rx_vlan_filter": None, + "rx_vlan_stag_filter": None, + "rx_vlan_stag_hw_parse": None, "rxhash": None, "rxvlan": None, "sg": None, - "tls-hw-record": None, - "tls-hw-tx-offload": None, + "tls_hw_record": None, + "tls_hw_tx_offload": None, "tso": None, "tx": None, - "tx-checksum-fcoe-crc": None, - "tx-checksum-ip-generic": None, - "tx-checksum-ipv4": None, - "tx-checksum-ipv6": None, - "tx-checksum-sctp": None, - "tx-esp-segmentation": None, - "tx-fcoe-segmentation": None, - "tx-gre-csum-segmentation": None, - "tx-gre-segmentation": None, - "tx-gso-partial": None, - "tx-gso-robust": None, - "tx-ipxip4-segmentation": None, - "tx-ipxip6-segmentation": None, - "tx-nocache-copy": None, - "tx-scatter-gather": None, - "tx-scatter-gather-fraglist": None, - "tx-sctp-segmentation": None, - "tx-tcp-ecn-segmentation": None, - "tx-tcp-mangleid-segmentation": None, - "tx-tcp-segmentation": None, - "tx-tcp6-segmentation": None, - "tx-udp-segmentation": None, - "tx-udp_tnl-csum-segmentation": None, - "tx-udp_tnl-segmentation": None, - "tx-vlan-stag-hw-insert": None, + "tx_checksum_fcoe_crc": None, + "tx_checksum_ip_generic": None, + "tx_checksum_ipv4": None, + "tx_checksum_ipv6": None, + "tx_checksum_sctp": None, + "tx_esp_segmentation": None, + "tx_fcoe_segmentation": None, + "tx_gre_csum_segmentation": None, + "tx_gre_segmentation": None, + "tx_gso_partial": None, + "tx_gso_robust": None, + "tx_ipxip4_segmentation": None, + "tx_ipxip6_segmentation": None, + "tx_nocache_copy": None, + "tx_scatter_gather": None, + "tx_scatter_gather_fraglist": None, + "tx_sctp_segmentation": None, + "tx_tcp_ecn_segmentation": None, + "tx_tcp_mangleid_segmentation": None, + "tx_tcp_segmentation": None, + "tx_tcp6_segmentation": None, + "tx_udp_segmentation": None, + "tx_udp_tnl_csum_segmentation": None, + "tx_udp_tnl_segmentation": None, + "tx_vlan_stag_hw_insert": None, "txvlan": None, } @@ -2475,6 +2476,76 @@ class TestValidator(unittest.TestCase): }, ) + def _test_ethtool_changes(self, input_features, expected_features): + """ + When passing a dictionary 'input_features' with each feature and their + value to change, and a dictionary 'expected_features' with the expected + result in the configuration, the expected and resulting connection are + created and validated. + """ + custom_ethtool_features = copy.deepcopy(ETHTOOL_FEATURES_DEFAULTS) + custom_ethtool_features.update(expected_features) + expected_ethtool = {"features": custom_ethtool_features} + input_connection = { + "ethtool": {"features": input_features}, + "name": "5", + "persistent_state": "present", + "type": "ethernet", + } + + expected_connection = { + "actions": ["present"], + "ethtool": expected_ethtool, + "interface_name": "5", + "persistent_state": "present", + "state": None, + "type": "ethernet", + } + self.check_one_connection_with_defaults(input_connection, expected_connection) + + def test_set_ethtool_feature(self): + """ + When passing the name of an non-deprecated ethtool feature, their + current version is updated. + """ + input_features = {"tx_tcp_segmentation": "yes"} + expected_feature_changes = {"tx_tcp_segmentation": True} + self._test_ethtool_changes(input_features, expected_feature_changes) + + def test_set_deprecated_ethtool_feature(self): + """ + When passing a deprecated name, their current version is updated. + """ + input_features = {"tx-tcp-segmentation": "yes"} + expected_feature_changes = {"tx_tcp_segmentation": True} + self._test_ethtool_changes(input_features, expected_feature_changes) + + def test_invalid_ethtool_settings(self): + """ + When both the deprecated and current version of a feature are stated, + a Validation Error is raised. + """ + input_features = {"tx-tcp-segmentation": "yes", "tx_tcp_segmentation": "yes"} + features_validator = ( + network_lsr.argument_validator.ArgValidator_DictEthtoolFeatures() + ) + self.assertValidationError(features_validator, input_features) + + def test_deprecated_ethtool_names(self): + """ + Test that for each validator in + ArgValidator_DictEthtoolFeatures.nested there is another non-deprecated + validator that has the name from the deprecated_by attribute" + """ + validators = ( + network_lsr.argument_validator.ArgValidator_DictEthtoolFeatures().nested + ) + for name, validator in validators.items(): + if isinstance( + validator, network_lsr.argument_validator.ArgValidatorDeprecated + ): + assert validator.deprecated_by in validators.keys() + @my_test_skipIf(nmutil is None, "no support for NM (libnm via pygobject)") class TestNM(unittest.TestCase): diff --git a/tests/unit/test_nm_provider.py b/tests/unit/test_nm_provider.py index 0a2679a..c8fd4eb 100644 --- a/tests/unit/test_nm_provider.py +++ b/tests/unit/test_nm_provider.py @@ -27,5 +27,5 @@ with mock.patch.dict("sys.modules", {"gi": mock.Mock(), "gi.repository": mock.Mo def test_get_nm_ethtool_feature(): """ Test get_nm_ethtool_feature() """ with mock.patch.object(nm_provider.Util, "NM") as nm_mock: - nm_feature = nm_provider.get_nm_ethtool_feature("esp-hw-offload") + nm_feature = nm_provider.get_nm_ethtool_feature("esp_hw_offload") assert nm_feature == nm_mock.return_value.ETHTOOL_OPTNAME_FEATURE_ESP_HW_OFFLOAD