Skip to content

Commit e7d6845

Browse files
tests: Prefer permanent MAC for finding link info, fallback to current MAC
When a network connection specifies both an interface name and MAC address, and the physical interface has identical permanent and current MACs, applying the configuration multiple times can cause an error: "no such interface exists." The issue occurs because `SysUtil.link_info_find()` may return a link info entry where the user-specified MAC matches only the current ("address") but not the permanent MAC ("perm-address"). In such cases, the returned link info may have a different interface name than the one specified in the network connection, leading to the error. We already implemented a fix (c341683) that ensures link lookup prioritizes the permanent MAC, only falling back to the current MAC when necessary. The integration test `tests_mac_address_match.yml` verifies this fix by requiring an Ethernet interface where the permanent and current MACs match. Resolves: https://issues.redhat.com/browse/RHEL-74211 Signed-off-by: Wen Liang <[email protected]>
1 parent 818a560 commit e7d6845

File tree

6 files changed

+185
-0
lines changed

6 files changed

+185
-0
lines changed

tests/ensure_provider_tests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"playbooks/tests_infiniband.yml": {},
8080
"playbooks/tests_ipv6_disabled.yml": {},
8181
"playbooks/tests_ipv6_dns_search.yml": {},
82+
"playbooks/tests_mac_address_match.yml": {},
8283
"playbooks/tests_provider.yml": {
8384
MINIMUM_VERSION: "'1.20.0'",
8485
"comment": "# NetworKmanager 1.20.0 added support for forgetting profiles",
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
---
3+
- name: Play for testing MAC address match on device
4+
hosts: all
5+
vars:
6+
# This test requires an Ethernet interface whose permanent
7+
# MAC address matches its current MAC address. Ensure that the
8+
# specified interface meets this condition.
9+
#
10+
# Two VLAN profiles are defined to test deterministic behavior when fetching
11+
# link information from sysfs. The issue being tested arises when `os.listdir(path)`
12+
# returns interfaces in an arbitrary order, potentially listing a VLAN device
13+
# before its parent interface. This can cause intermittent "no such interface
14+
# exists" errors when applying configurations repeatedly.
15+
#
16+
# - `vlan_profile1` (e.g., `eth1.3732`) is named with the VLAN ID appended
17+
# after the parent interface, following the standard `<parent>.<vlan_id>` format.
18+
# - `vlan_profile2` (e.g., `120-vlan`) has a fixed name, designed to test a scenario
19+
# where lexicographic sorting causes the VLAN to appear before its parent interface.
20+
interface: "{{ lookup('env', 'MAC_ADDR_MATCH_INTERFACE') | default('eth1', true) }}"
21+
profile: "{{ interface }}"
22+
vlan_profile1: "{{ interface }}.3732"
23+
vlan_profile2: "120-vlan"
24+
lsr_fail_debug:
25+
- __network_connections_result
26+
tags:
27+
- "tests::match"
28+
tasks:
29+
- name: Show playbook name
30+
debug:
31+
msg: "this is: playbooks/tests_mac_address_match.yml"
32+
tags:
33+
- always
34+
35+
- name: Install ethtool (test dependency)
36+
package:
37+
name: ethtool
38+
state: present
39+
use: "{{ (__network_is_ostree | d(false)) |
40+
ternary('ansible.posix.rhel_rpm_ostree', omit) }}"
41+
42+
- name: Retrieve MAC address using ethtool
43+
command: ethtool -P {{ interface }}
44+
register: mac_address_result
45+
changed_when: false
46+
failed_when: mac_address_result.rc != 0
47+
48+
- name: Set the MAC address variable
49+
set_fact:
50+
mac: "{{ mac_address_result.stdout_lines[-1].split(' ')[-1] }}"
51+
52+
- name: Display the retrieved MAC address
53+
debug:
54+
msg: "Retrieved MAC address for {{ interface }}: {{ mac }}"
55+
56+
- name: Test the MAC address match
57+
tags:
58+
- tests::match:match
59+
block:
60+
- name: Include the task 'run_test.yml'
61+
include_tasks: tasks/run_test.yml
62+
vars:
63+
lsr_description: Test MAC address match on device
64+
lsr_setup:
65+
- tasks/assert_profile_absent.yml
66+
lsr_test:
67+
- tasks/create_mac_address_match.yml
68+
- tasks/create_mac_address_match.yml
69+
lsr_assert:
70+
- tasks/assert_profile_present.yml
71+
- tasks/assert_network_connections_succeeded.yml
72+
lsr_cleanup:
73+
- tasks/cleanup_vlan_and_parent_profile+device.yml
74+
- tasks/check_network_dns.yml
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
---
3+
- name: Assert that configuring network connections is succeeded
4+
assert:
5+
that:
6+
- __network_connections_result.failed == false
7+
msg: Configuring network connections is failed with the error
8+
"{{ __network_connections_result.stderr }}"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
---
3+
- name: Clean up the test devices and the connection profiles
4+
tags:
5+
- "tests::cleanup"
6+
block:
7+
- name: Import network role
8+
import_role:
9+
name: linux-system-roles.network
10+
vars:
11+
network_connections:
12+
- name: "{{ profile }}"
13+
persistent_state: absent
14+
state: down
15+
- name: "{{ vlan_profile1 }}"
16+
persistent_state: absent
17+
state: down
18+
- name: "{{ vlan_profile2 }}"
19+
persistent_state: absent
20+
state: down
21+
failed_when: false
22+
- name: Delete the device '{{ interface }}'
23+
command: ip link del {{ interface }}
24+
failed_when: false
25+
changed_when: false
26+
...
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
---
3+
- name: Include network role
4+
include_role:
5+
name: linux-system-roles.network
6+
vars:
7+
network_connections:
8+
- name: "{{ interface }}"
9+
state: up
10+
persistent_state: present
11+
autoconnect: true
12+
type: ethernet
13+
interface_name: "{{ interface }}"
14+
mac: "{{ mac }}"
15+
ip:
16+
dhcp4: false
17+
auto6: false
18+
19+
- name: "{{ vlan_profile1 }}"
20+
state: up
21+
persistent_state: present
22+
type: vlan
23+
parent: "{{ interface }}"
24+
vlan:
25+
id: 3732
26+
autoconnect: true
27+
ip:
28+
auto_gateway: false
29+
ipv6_disabled: true
30+
gateway4: 10.10.0.1
31+
address: 10.10.0.6/24
32+
dhcp4: false
33+
auto6: false
34+
35+
- name: "{{ vlan_profile2 }}"
36+
state: up
37+
persistent_state: present
38+
type: vlan
39+
parent: "{{ interface }}"
40+
vlan:
41+
id: 120
42+
autoconnect: true
43+
ip:
44+
auto_gateway: false
45+
ipv6_disabled: true
46+
gateway4: 10.10.120.1
47+
address: 10.10.120.120/24
48+
dhcp4: false
49+
auto6: false
50+
- name: Show result
51+
debug:
52+
var: __network_connections_result
53+
...
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
# This file was generated by ensure_provider_tests.py
3+
---
4+
# set network provider and gather facts
5+
# yamllint disable rule:line-length
6+
- name: Run playbook 'playbooks/tests_mac_address_match.yml' with nm as provider
7+
hosts: all
8+
tasks:
9+
- name: Include the task 'el_repo_setup.yml'
10+
include_tasks: tasks/el_repo_setup.yml
11+
- name: Set network provider to 'nm'
12+
set_fact:
13+
network_provider: nm
14+
tags:
15+
- always
16+
17+
18+
# The test requires or should run with NetworkManager, therefore it cannot run
19+
# on RHEL/CentOS 6
20+
- name: Import the playbook 'playbooks/tests_mac_address_match.yml'
21+
import_playbook: playbooks/tests_mac_address_match.yml
22+
when:
23+
- ansible_distribution_major_version != '6'

0 commit comments

Comments
 (0)