Add support for ethtool features

This commit is contained in:
Till Maas 2019-06-06 21:48:05 +02:00
parent e37e9d7560
commit 70aa9875aa
12 changed files with 547 additions and 4 deletions

View file

@ -339,6 +339,68 @@ The IP configuration supports the following options:
**Note:** Slaves to the bridge, bond or team devices cannot specify `ip` settings.
### `ethtool`
The ethtool settings allow to enable or disable varios features. The names
correspond to the names used by the `ethtool` utility. Depending on the actual
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
gro: yes|no # optional
gso: yes|no # optional
highdma: 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
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
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
txvlan: yes|no # optional
```
Examples of Options
-------------------

View file

@ -0,0 +1,14 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- hosts: all
tasks:
- include_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ network_interface_name1 }}"
state: up
type: ethernet
ip:
dhcp4: "no"
auto6: "no"

View file

@ -0,0 +1,19 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- hosts: all
tasks:
- include_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ network_interface_name1 }}"
state: up
type: ethernet
ip:
dhcp4: "no"
auto6: "no"
ethtool:
features:
gro: "no"
gso: "yes"
tx-sctp-segmentation: "no"

View file

@ -20,6 +20,7 @@ from ansible.module_utils.network_lsr.argument_validator import (
# pylint: disable=import-error
from ansible.module_utils.network_lsr.utils import Util
from ansible.module_utils.network_lsr import nm_provider
DOCUMENTATION = """
---
@ -361,16 +362,39 @@ class IfcfgUtil:
if connection["mtu"]:
ifcfg["MTU"] = str(connection["mtu"])
ethtool_options = ""
if "ethernet" in connection:
if connection["ethernet"]["autoneg"] is not None:
if connection["ethernet"]["autoneg"]:
s = "autoneg on"
ethtool_options = "autoneg on"
else:
s = "autoneg off speed %s duplex %s" % (
ethtool_options = "autoneg off speed %s duplex %s" % (
connection["ethernet"]["speed"],
connection["ethernet"]["duplex"],
)
ifcfg["ETHTOOL_OPTS"] = s
ethtool_features = connection["ethtool"]["features"]
configured_features = []
for feature, setting in ethtool_features.items():
value = ""
if setting:
value = "on"
elif setting is not None:
value = "off"
if value:
configured_features.append("%s %s" % (feature, value))
if configured_features:
if ethtool_options:
ethtool_options += " ; "
ethtool_options += "-K %s %s" % (
connection["interface_name"],
" ".join(configured_features),
)
if ethtool_options:
ifcfg["ETHTOOL_OPTS"] = ethtool_options
if connection["master"] is not None:
m = ArgUtil.connection_find_master(connection["master"], connections, idx)
@ -839,6 +863,20 @@ class NMUtil:
NM.SETTING_WIRED_SPEED, connection["ethernet"]["speed"]
)
if hasattr(NM, "SettingEthtool"):
s_ethtool = self.connection_ensure_setting(con, NM.SettingEthtool)
for feature, setting in connection["ethtool"]["features"].items():
nm_feature = nm_provider.get_nm_ethtool_feature(feature)
if setting is None:
if nm_feature:
s_ethtool.set_feature(nm_feature, NM.Ternary.DEFAULT)
elif setting:
s_ethtool.set_feature(nm_feature, NM.Ternary.TRUE)
else:
s_ethtool.set_feature(nm_feature, NM.Ternary.FALSE)
if connection["mtu"]:
if connection["type"] == "infiniband":
s_infiniband = self.connection_ensure_setting(con, NM.SettingInfiniband)
@ -1830,7 +1868,9 @@ class Cmd_nm(Cmd):
Cmd.run_prepare(self)
names = {}
for connection in self.connections:
for idx, connection in enumerate(self.connections):
self._check_ethtool_setting_support(idx, connection)
name = connection["name"]
if not name:
assert connection["persistent_state"] == "absent"
@ -1872,6 +1912,37 @@ class Cmd_nm(Cmd):
finally:
self._checkpoint = None
def _check_ethtool_setting_support(self, idx, connection):
""" Check if SettingEthtool support is needed and available
If any feature is specified, the SettingEthtool setting needs to be
available. Also NM needs to know about each specified setting. Do not
check if NM knows about any defaults.
"""
NM = Util.NM()
# If the profile is not completely specified, for example if only the
# runtime change is specified, the ethtool subtree might be missing.
# Then no checks are required.
if "ethtool" not in connection:
return
ethtool_features = connection["ethtool"]["features"]
specified_features = dict(
[(k, v) for k, v in ethtool_features.items() if v is not None]
)
if specified_features and not hasattr(NM, "SettingEthtool"):
self.log_fatal(idx, "ethtool.features specified but not supported by NM")
for feature, setting in specified_features.items():
nm_feature = nm_provider.get_nm_ethtool_feature(feature)
if not nm_feature:
self.log_fatal(
idx, "ethtool feature %s specified but not support by NM" % feature
)
def run_action_absent(self, idx):
seen = set()
name = self.connections[idx]["name"]

View file

@ -521,6 +521,92 @@ class ArgValidator_DictEthernet(ArgValidatorDict):
return result
class ArgValidator_DictEthtool(ArgValidatorDict):
def __init__(self):
ArgValidatorDict.__init__(
self,
name="ethtool",
nested=[ArgValidator_DictEthtoolFeatures()],
default_value=ArgValidator.MISSING,
)
self.default_value = dict(
[(k, v.default_value) for k, v in self.nested.items()]
)
class ArgValidator_DictEthtoolFeatures(ArgValidatorDict):
# List of features created with:
# nmcli connection modify "virbr0" ethtool.feature- on |& \
# sed -e 's_[,:]_\n_g' | \ # split output in newlines
# grep ^\ f | \ # select only lines starting with " f"
# tr -d " ." | \ # remove spaces and fullstops
# sed -e 's,feature-,ArgValidatorBool(",' \ # add Python code
# -e 's/$/", default_value=None)],/'
def __init__(self):
ArgValidatorDict.__init__(
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("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("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("sg", default_value=None),
ArgValidatorBool("tls-hw-record", default_value=None),
ArgValidatorBool("tls-hw-tx-offload", default_value=None),
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),
],
)
self.default_value = dict(
[(k, v.default_value) for k, v in self.nested.items()]
)
class ArgValidator_DictBond(ArgValidatorDict):
VALID_MODES = [
@ -668,6 +754,7 @@ class ArgValidator_DictConnection(ArgValidatorDict):
ArgValidatorBool("ignore_errors", default_value=None),
ArgValidator_DictIP(),
ArgValidator_DictEthernet(),
ArgValidator_DictEthtool(),
ArgValidator_DictBond(),
ArgValidator_DictInfiniband(),
ArgValidator_DictVlan(),

View file

@ -0,0 +1,23 @@
# SPDX-License-Identifier: BSD-3-Clause
""" Support for NetworkManager aka the NM provider """
# pylint: disable=import-error, no-name-in-module
from ansible.module_utils.network_lsr.utils import Util
ETHTOOL_FEATURE_PREFIX = "ETHTOOL_OPTNAME_FEATURE_"
def get_nm_ethtool_feature(name):
"""
Translate ethtool feature into Network Manager name
:param name: Name of the feature
:type name: str
:returns: Name of the feature to be used by `NM.SettingEthtool.set_feature()`
:rtype: str
"""
name = ETHTOOL_FEATURE_PREFIX + name.upper().replace("-", "_")
feature = getattr(Util.NM(), name, None)
return feature

View file

@ -19,6 +19,8 @@ IGNORE = [
"tests_unit.yml",
"tests_vlan_mtu_initscripts.yml",
"tests_vlan_mtu_nm.yml",
"tests_ethtool_features_initscripts.yml",
"tests_ethtool_features_nm.yml",
]
OTHER_PLAYBOOK = """

View file

@ -0,0 +1,111 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- hosts: all
vars:
interface: lsrfeat1
type: veth
tasks:
- name: "INIT: Ethtool feeatures tests"
debug:
msg: "##################################################"
- include_tasks: tasks/show-interfaces.yml
- include_tasks: tasks/manage-test-interface.yml
vars:
state: present
- include_tasks: tasks/assert-device_present.yml
- name: Install ethtool (test dependency)
package:
name: ethtool
state: present
- block:
- name: "TEST: I can create a profile without changing the ethtool features."
debug:
msg: "##################################################"
- name: Get current device features
command: "ethtool --show-features {{ interface }}"
register: original_ethtool_features
- import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
state: up
type: ethernet
ip:
dhcp4: "no"
auto6: "no"
- name: Get current device features
command: "ethtool --show-features {{ interface }}"
register: ethtool_features
- name: "ASSERT: The profile does not change the ethtool features"
assert:
that:
- original_ethtool_features.stdout == ethtool_features.stdout
- name: "TEST: I can disable gro and tx-tcp-segmentation and enable gso."
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:
gro: "no"
gso: "yes"
tx-tcp-segmentation: "no"
- 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:
- "'generic-receive-offload: off' in ethtool_features.stdout_lines"
- "'generic-segmentation-offload: on' in ethtool_features.stdout_lines"
- "'tx-tcp-segmentation: off' in ethtool_features.stdout_lines | map('trim')"
- name: "TEST: I can reset features to their original value."
debug:
msg: "##################################################"
- import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
state: up
type: ethernet
ip:
dhcp4: "no"
auto6: "no"
- name: Get current device features
command: "ethtool --show-features {{ interface }}"
register: ethtool_features
# Resetting the ethtools only works with NetworkManager
- name: "ASSERT: The profile does not change the ethtool features"
assert:
that:
- original_ethtool_features.stdout == ethtool_features.stdout
when:
network_provider == 'nm'
always:
- block:
- import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
persistent_state: absent
state: down
ignore_errors: true
- include_tasks: tasks/manage-test-interface.yml
vars:
state: absent
tags:
- "tests::cleanup"

View file

@ -0,0 +1,13 @@
---
# set network provider and gather facts
- hosts: all
tasks:
- name: Set network provider to 'initscripts'
set_fact:
network_provider: initscripts
# workaround for: https://github.com/ansible/ansible/issues/27973
# There is no way in Ansible to abort a playbook hosts with specific OS
# releases Therefore we include the playbook with the tests only if the hosts
# would support it.
- import_playbook: playbooks/tests_ethtool_features.yml

View file

@ -0,0 +1,28 @@
---
# set network provider and gather facts
- hosts: all
tasks:
- name: Set network provider to 'nm'
set_fact:
network_provider: nm
- name: Install NetworkManager
package:
name: NetworkManager
state: present
- name: Get NetworkManager version
command: rpm -q --qf "%{version}" NetworkManager
args:
warn: "no"
when: true
register: NetworkManager_version
# workaround for: https://github.com/ansible/ansible/issues/27973
# There is no way in Ansible to abort a playbook hosts with specific OS
# releases Therefore we include the playbook with the tests only if the hosts
# would support it.
# The test should run with NetworkManager, therefore it cannot run on RHEL 6 or CentOS 6.
- import_playbook: playbooks/tests_ethtool_features.yml
when:
- ansible_distribution_major_version != '6'
# NetworkManager 1.20.0 introduced ethtool settings support
- NetworkManager_version.stdout is version('1.20.0', '>=')

View file

@ -67,6 +67,63 @@ def pprint(msg, obj):
ARGS_CONNECTIONS = network_lsr.argument_validator.ArgValidator_ListConnections()
VALIDATE_ONE_MODE_INITSCRIPTS = ARGS_CONNECTIONS.VALIDATE_ONE_MODE_INITSCRIPTS
ETHTOOL_FEATURES_DEFAULTS = {
"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,
"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,
"rxhash": None,
"rxvlan": None,
"sg": 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,
"txvlan": None,
}
ETHTOOL_DEFAULTS = {"features": ETHTOOL_FEATURES_DEFAULTS}
ETHERNET_DEFAULTS = {"autoneg": None, "duplex": None, "speed": 0}
@ -77,6 +134,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"ignore_errors": None,
"ip": {
"gateway6": None,
@ -316,6 +374,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"ignore_errors": None,
"interface_name": "5",
"ip": {
@ -364,6 +423,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "5",
@ -407,6 +467,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": False,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "5",
@ -487,6 +548,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": None,
@ -547,6 +609,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "prod1",
@ -604,6 +667,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": None,
@ -650,6 +714,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "prod.100",
@ -739,6 +804,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": None,
@ -785,6 +851,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "prod.100",
@ -874,6 +941,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "eth0",
@ -914,6 +982,7 @@ class TestValidator(unittest.TestCase):
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "veth0",
@ -963,6 +1032,7 @@ class TestValidator(unittest.TestCase):
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "veth1",
@ -1062,6 +1132,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "bridge2",
@ -1097,6 +1168,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "eth1",
@ -1156,6 +1228,7 @@ class TestValidator(unittest.TestCase):
"bond": {"mode": "balance-rr", "miimon": None},
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "bond1",
@ -1200,6 +1273,7 @@ class TestValidator(unittest.TestCase):
"bond": {"mode": "active-backup", "miimon": None},
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "bond1",
@ -1255,6 +1329,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"ignore_errors": None,
"interface_name": None,
"ip": {
@ -1296,6 +1371,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": {"autoneg": False, "duplex": "half", "speed": 400},
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "5",
@ -1366,6 +1442,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "6643-master",
@ -1401,6 +1478,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "6643",
@ -1451,6 +1529,7 @@ class TestValidator(unittest.TestCase):
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"infiniband": {"p_key": -1, "transport_mode": "datagram"},
@ -1519,6 +1598,7 @@ class TestValidator(unittest.TestCase):
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"infiniband": {"p_key": 5, "transport_mode": "datagram"},
@ -1595,6 +1675,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "555",
@ -1685,6 +1766,7 @@ class TestValidator(unittest.TestCase):
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "e556",

View file

@ -0,0 +1,31 @@
#!/usr/bin/env python
""" Tests for network_connections Ansible module """
# SPDX-License-Identifier: BSD-3-Clause
import os
import sys
TESTS_BASEDIR = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(1, os.path.join(TESTS_BASEDIR, "../..", "library"))
sys.path.insert(1, os.path.join(TESTS_BASEDIR, "../..", "module_utils"))
try:
from unittest import mock
except ImportError: # py2
import mock
sys.modules["ansible"] = mock.Mock()
sys.modules["ansible.module_utils.basic"] = mock.Mock()
sys.modules["ansible.module_utils"] = mock.Mock()
sys.modules["ansible.module_utils.network_lsr"] = __import__("network_lsr")
with mock.patch.dict("sys.modules", {"gi": mock.Mock(), "gi.repository": mock.Mock()}):
# pylint: disable=import-error, wrong-import-position
from network_lsr import nm_provider
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")
assert nm_feature == nm_mock.return_value.ETHTOOL_OPTNAME_FEATURE_ESP_HW_OFFLOAD