Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SR-IOV support to nmcli module #9168

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/9168-nmcli-add-sriov-parameter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- nmcli - add ``sriov`` parameter that enables support for SR-IOV settings (https://github.com/ansible-collections/community.general/pull/9168).
41 changes: 41 additions & 0 deletions plugins/modules/nmcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,38 @@
You can encode using this Ansible jinja2 expression: V("0s{{ '[YOUR PRE-SHARED KEY]' | ansible.builtin.b64encode }}").
- This is only used when O(vpn.ipsec-enabled=true).
type: str
sriov:
description:
- Allow to configure SR-IOV settings.
- 'An up-to-date list of supported attributes can be found here:
U(https://networkmanager.pages.freedesktop.org/NetworkManager/NetworkManager/settings-sriov.html).'
type: dict
version_added: 10.1.0
suboptions:
autoprobe-drivers:
description:
- Whether to autoprobe virtual functions by a compatible driver.
type: int
eswitch-encap-mode:
description:
- Select the eswitch encapsulation support.
type: int
eswitch-inline-mode:
description:
- Select the eswitch inline-mode of the device.
type: int
eswitch-mode:
description:
- Select the eswitch mode of the device.
type: int
total-vfs:
description: Number of virtual functions to create. Consult your NIC documentation for the maximum number of VFs supported.
type: int
vfs:
description:
- 'Virtual function descriptors in the form: V(INDEX [ATTR=VALUE[ ATTR=VALUE]...]).'
- Multiple VFs can be specified using a comma as separator, for example V(2 mac=00:11:22:33:44:55 spoof-check=true,3 vlans=100).
type: str
'''

EXAMPLES = r'''
Expand Down Expand Up @@ -1687,6 +1719,7 @@ def __init__(self, module):
self.wireguard = module.params['wireguard']
self.vpn = module.params['vpn']
self.transport_mode = module.params['transport_mode']
self.sriov = module.params['sriov']

if self.method4:
self.ipv4_method = self.method4
Expand Down Expand Up @@ -1952,6 +1985,13 @@ def connection_options(self, detect_change=False):
'infiniband.transport-mode': self.transport_mode,
})

if self.type == 'ethernet':
if self.sriov:
for name, value in self.sriov.items():
options.update({
'sriov.%s' % name: value,
})

# Convert settings values based on the situation.
for setting, value in options.items():
setting_type = self.settings_type(setting)
Expand Down Expand Up @@ -2607,6 +2647,7 @@ def main():
wireguard=dict(type='dict'),
vpn=dict(type='dict'),
transport_mode=dict(type='str', choices=['datagram', 'connected']),
sriov=dict(type='dict'),
),
mutually_exclusive=[['never_default4', 'gw4'],
['routes4_extended', 'routes4'],
Expand Down
64 changes: 64 additions & 0 deletions tests/unit/plugins/modules/test_nmcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,28 @@
ipv6.ignore-auto-routes: no
"""

TESTCASE_ETHERNET_ADD_SRIOV_VFS = [
{
'type': 'ethernet',
'conn_name': 'non_existent_nw_device',
'ifname': 'ethernet_non_existant',
'sriov': {
'total-vfs': 16,
'vfs': '0 spoof-check=true vlans=100',
},
'state': 'present',
'_ansible_check_mode': False,
}
]

TESTCASE_ETHERNET_ADD_SRIOV_VFS_SHOW_OUTPUT = """\
connection.id: non_existent_nw_device
connection.interface-name: ethernet_non_existant
connection.autoconnect: yes
sriov.total-vfs: 16
sriov.vfs: 0 spoof-check=true vlans=100
"""

TESTCASE_ETHERNET_ADD_IPV6_INT_WITH_ROUTE_AND_METRIC = [
{
'type': 'ethernet',
Expand Down Expand Up @@ -1806,6 +1828,12 @@ def mocked_ethernet_connection_with_ipv6_static_address_multiple_static_routes_c
))


@pytest.fixture
def mocked_ethernet_connection_with_sriov_vfs_create(mocker):
mocker_set(mocker,
execute_return=(0, TESTCASE_ETHERNET_ADD_SRIOV_VFS_SHOW_OUTPUT, ""))


@pytest.fixture
def mocked_ethernet_connection_with_ipv6_static_address_static_route_with_metric_create(mocker):
mocker_set(mocker,
Expand Down Expand Up @@ -3312,6 +3340,41 @@ def test_ethernet_connection_static_ipv6_address_multiple_static_routes_with_met
assert results['changed']


@pytest.mark.parametrize('patch_ansible_module', TESTCASE_ETHERNET_ADD_SRIOV_VFS, indirect=['patch_ansible_module'])
def test_ethernet_connection_sriov_vfs_create(
mocked_ethernet_connection_with_sriov_vfs_create, capfd):
"""
Test : Create ethernet connection with SR-IOV VFs
"""
with pytest.raises(SystemExit):
nmcli.main()

assert nmcli.Nmcli.execute_command.call_count == 1
arg_list = nmcli.Nmcli.execute_command.call_args_list
add_args, add_kw = arg_list[0]

assert add_args[0][0] == '/usr/bin/nmcli'
assert add_args[0][1] == 'con'
assert add_args[0][2] == 'add'
assert add_args[0][3] == 'type'
assert add_args[0][4] == 'ethernet'
assert add_args[0][5] == 'con-name'
assert add_args[0][6] == 'non_existent_nw_device'

add_args_text = list(map(to_text, add_args[0]))

for param in ['connection.interface-name', 'ethernet_non_existant',
'con-name', 'non_existent_nw_device',
'sriov.total-vfs', '16',
'sriov.vfs', '0 spoof-check=true vlans=100']:
assert param in add_args_text

out, err = capfd.readouterr()
results = json.loads(out)
assert not results.get('failed')
assert results['changed']


@pytest.mark.parametrize('patch_ansible_module', TESTCASE_ETHERNET_ADD_IPV6_INT_WITH_ROUTE_AND_METRIC, indirect=['patch_ansible_module'])
def test_ethernet_connection_static_ipv6_address_static_route_with_metric_create(
mocked_ethernet_connection_with_ipv6_static_address_static_route_with_metric_create, capfd):
Expand Down Expand Up @@ -4384,6 +4447,7 @@ def test_bond_connection_unchanged(mocked_generic_connection_diff_check, capfd):
wireguard=dict(type='dict'),
vpn=dict(type='dict'),
transport_mode=dict(type='str', choices=['datagram', 'connected']),
sriov=dict(type='dict'),
),
mutually_exclusive=[['never_default4', 'gw4'],
['routes4_extended', 'routes4'],
Expand Down