mirror of
https://github.com/linux-system-roles/network.git
synced 2026-01-23 10:25:28 +00:00
Merge pull request #115 from tyll/ethtool
Support ethtool -K|--features|--offload
This commit is contained in:
commit
d5891d43a2
12 changed files with 547 additions and 4 deletions
62
README.md
62
README.md
|
|
@ -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
|
||||
-------------------
|
||||
|
|
|
|||
14
examples/ethtool-features-default.yml
Normal file
14
examples/ethtool-features-default.yml
Normal 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"
|
||||
19
examples/ethtool-features.yml
Normal file
19
examples/ethtool-features.yml
Normal 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"
|
||||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
23
module_utils/network_lsr/nm_provider.py
Normal file
23
module_utils/network_lsr/nm_provider.py
Normal 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
|
||||
|
|
@ -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 = """
|
||||
|
|
|
|||
111
tests/playbooks/tests_ethtool_features.yml
Normal file
111
tests/playbooks/tests_ethtool_features.yml
Normal 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"
|
||||
13
tests/tests_ethtool_features_initscripts.yml
Normal file
13
tests/tests_ethtool_features_initscripts.yml
Normal 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
|
||||
28
tests/tests_ethtool_features_nm.yml
Normal file
28
tests/tests_ethtool_features_nm.yml
Normal 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', '>=')
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
31
tests/unit/test_nm_provider.py
Normal file
31
tests/unit/test_nm_provider.py
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue