Skip to content

Commit aee889f

Browse files
authored
Merge pull request vyos#1253 from c-po/boot-ifname-race
Testsuite: T3871: change testcase to use multiple NIC drivers
2 parents c82f5af + 90149ea commit aee889f

2 files changed

Lines changed: 91 additions & 10 deletions

File tree

Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ ISO_PATH := $(build_dir)/live-image-$(ARCH).hybrid.iso
88
# to their scripts via $(MAKECMDGOALS). Those extra words are also goals as
99
# far as make is concerned, so without this they'd fall through to the `%:`
1010
# flavor rule below and run build-vyos-image with garbage arguments.
11-
TEST_TARGETS := test test-no-interfaces test-no-interfaces-no-vpp test-interfaces test-vpp testc testcvpp testraid testsb testtpm test-ci-qcow2 test-image-update qemu-live
11+
TEST_TARGETS := test test-no-interfaces test-no-interfaces-no-vpp test-interfaces test-vpp testc testcvpp testraid testsb testtpm testifname test-ci-qcow2 test-image-update qemu-live
1212
ifneq ($(filter $(TEST_TARGETS),$(firstword $(MAKECMDGOALS))),)
1313
$(eval $(filter-out $(firstword $(MAKECMDGOALS)),$(MAKECMDGOALS)):;@:)
1414
endif
@@ -71,6 +71,11 @@ testsb:
7171
testtpm:
7272
scripts/check-qemu-install --debug --tpmtest --iso $(ISO_PATH) $(filter-out $@,$(MAKECMDGOALS))
7373

74+
.PHONY: testifname
75+
.ONESHELL:
76+
testifname:
77+
scripts/check-qemu-install --debug --ifnametest --iso $(ISO_PATH) $(filter-out $@,$(MAKECMDGOALS))
78+
7479
.PHONY: test-ci-qcow2
7580
.ONESHELL:
7681
test-ci-qcow2:

scripts/check-qemu-install

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ tpm_folder = '/tmp/vyos_tpm_test'
8282
tpm_sock = f'{tpm_folder}/swtpm-sock'
8383
qemu_name = 'VyOS-QEMU'
8484

85+
# RFC7042 section 2.1.2 MAC addresses used for documentation
86+
macbase = '00:00:5E:00:53'
87+
8588
test_timeout = 5 *3600 # 5 hours (in seconds) to complete individual testcases
8689

8790
op_mode_prompt = r'vyos@vyos:~\$'
@@ -137,6 +140,8 @@ parser.add_argument('--configtest', help='Execute load/commit config tests',
137140
action='store_true', default=False)
138141
parser.add_argument('--tpmtest', help='Execute TPM encrypted config tests',
139142
action='store_true', default=False)
143+
parser.add_argument('--ifnametest', help='Execute interface naming/hw-id persistence tests',
144+
action='store_true', default=False)
140145
parser.add_argument('--sbtest', help='Execute Secure Boot tests',
141146
action='store_true', default=False)
142147
parser.add_argument('--cloud-init', help='Execute cloud-init tests',
@@ -268,9 +273,6 @@ def get_qemu_cmd(name, enable_uefi, disk_img, raid=None, iso_img=None, tpm=False
268273
else:
269274
nested_cdrom = f'{nested_cdrom} -device ide-cd,bus=achi0.1,{drive_settings}'
270275

271-
# RFC7042 section 2.1.2 MAC addresses used for documentation
272-
macbase = '00:00:5E:00:53'
273-
274276
# Set QEmu disk image format - this differs if VyOS was installed via smoketest
275277
# or we use an already ewxisting image
276278
disk_format = 'qcow2' if args.disk.endswith('.qcow2') else 'raw'
@@ -290,10 +292,10 @@ def get_qemu_cmd(name, enable_uefi, disk_img, raid=None, iso_img=None, tpm=False
290292
-netdev user,id=n1 -device virtio-net-pci,netdev=n1,mac={macbase}:01,romfile="",host_mtu=1500 \
291293
-netdev user,id=n2 -device virtio-net-pci,netdev=n2,mac={macbase}:02,romfile="",host_mtu=1500 \
292294
-netdev user,id=n3 -device virtio-net-pci,netdev=n3,mac={macbase}:03,romfile="",host_mtu=1500 \
293-
-netdev user,id=n4 -device virtio-net-pci,netdev=n4,mac={macbase}:04,romfile="" \
294-
-netdev user,id=n5 -device virtio-net-pci,netdev=n5,mac={macbase}:05,romfile="" \
295-
-netdev user,id=n6 -device virtio-net-pci,netdev=n6,mac={macbase}:06,romfile="" \
296-
-netdev user,id=n7 -device virtio-net-pci,netdev=n7,mac={macbase}:07,romfile="" \
295+
-netdev user,id=n4 -device e1000e,netdev=n4,mac={macbase}:04,romfile="" \
296+
-netdev user,id=n5 -device e1000e,netdev=n5,mac={macbase}:05,romfile="" \
297+
-netdev user,id=n6 -device vmxnet3,netdev=n6,mac={macbase}:06,romfile="" \
298+
-netdev user,id=n7 -device vmxnet3,netdev=n7,mac={macbase}:07,romfile="" \
297299
-device virtio-scsi-pci,id=scsi0 \
298300
{cdrom}{nested_cdrom} \
299301
-drive format={disk_format},file={disk_img},if=none,media=disk,id=drive-hd1,readonly=off \
@@ -387,6 +389,8 @@ if args.test_image_update:
387389
_primary_modes.append('--test-image-update')
388390
if args.tpmtest:
389391
_primary_modes.append('--tpmtest')
392+
if args.ifnametest:
393+
_primary_modes.append('--ifnametest')
390394
if args.raid:
391395
_primary_modes.append('--raid')
392396
if args.smoketest:
@@ -397,8 +401,8 @@ if args.sbtest:
397401
_primary_modes.append('--sbtest')
398402
if len(_primary_modes) > 1:
399403
log.error('Incompatible combination of testcase flags (%s): only one of '
400-
'--cloud-init, --test-image-update, --tpmtest, --raid, --smoketest, '
401-
'--configtest, --sbtest may be set.', ', '.join(_primary_modes))
404+
'--cloud-init, --test-image-update, --tpmtest, --ifnametest, --raid, '
405+
'--smoketest, --configtest, --sbtest may be set.', ', '.join(_primary_modes))
402406
sys.exit(1)
403407

404408
if args.no_interfaces and not args.smoketest:
@@ -687,6 +691,31 @@ def basic_cli_tests(c):
687691
c.expect(f'set console_type="{console_type}"')
688692
c.expect(op_mode_prompt)
689693

694+
def verify_eth_mac_mapping(c, log):
695+
""" NICs are attached with a mix of drivers (virtio/e1000e/vmxnet3, see
696+
get_qemu_cmd()) to cover different naming schemes. Regardless of
697+
driver, udev must always enumerate them in ascending order: eth0
698+
carries mac0, eth1 mac1, ... up to eth7 mac7 - never scrambled. """
699+
log.info('Verify eth0..eth7 are enumerated in ascending MAC order')
700+
c.sendline('ip -json link show | jq -r \'.[] | select(.ifname|test("^eth[0-9]+$")) | "\(.ifname) \(.address)"\'')
701+
c.expect(op_mode_prompt)
702+
lines = [l.strip() for l in c.before.decode(errors='replace').splitlines() if l.strip()]
703+
704+
macs = {}
705+
for line in lines:
706+
parts = line.split()
707+
if len(parts) == 2 and re.fullmatch(r'eth\d+', parts[0]):
708+
macs[parts[0]] = parts[1].lower()
709+
710+
for i in range(8):
711+
ifname = f'eth{i}'
712+
expected_mac = f'{macbase}:{i:02x}'.lower()
713+
if ifname not in macs:
714+
raise Exception(f'Interface {ifname} not found on installed system')
715+
if macs[ifname] != expected_mac:
716+
raise Exception(f'Interface {ifname} has MAC {macs[ifname]}, expected {expected_mac} - naming race?')
717+
log.info('eth0..eth7 MAC mapping verified')
718+
690719
def _image_update_cli_sequence(c, log, new_image_name, server_bind_host='127.0.0.1', use_vrf=False):
691720
"""One add-system-image/delete cycle for nested ISO over HTTP (optional Linux VRF + VyOS vrf arg)."""
692721
url = f'http://{server_bind_host}:{NESTED_HTTP_SERV_PORT}/{NESTED_INNER_ISO_NAME}'
@@ -1067,6 +1096,11 @@ try:
10671096
log.info('Basic CLI configuration mode test')
10681097
basic_cli_tests(c)
10691098

1099+
#################################################
1100+
# Verify NIC driver mix did not scramble interface naming
1101+
#################################################
1102+
verify_eth_mac_mapping(c, log)
1103+
10701104
#################################################
10711105
# Verify /etc/os-release via lsb_release
10721106
#################################################
@@ -1274,6 +1308,48 @@ try:
12741308
c.sendline('exit')
12751309
c.expect(op_mode_prompt)
12761310

1311+
elif args.ifnametest:
1312+
# A missing/deleted hw-id binding, or a fully deleted interface
1313+
# config, must not change the eth0..eth7 <-> MAC mapping after
1314+
# the next reboot (regression check for the boot-time naming race).
1315+
log.info('Running interface naming/hw-id persistence tests')
1316+
del_idx, hwid_idx = random.sample(range(8), 2)
1317+
log.info(f'Deleting eth{del_idx} entirely, removing hw-id only on eth{hwid_idx}')
1318+
1319+
c.sendline('configure')
1320+
c.expect(cfg_mode_prompt)
1321+
c.sendline(f'delete interfaces ethernet eth{del_idx}')
1322+
c.expect(cfg_mode_prompt)
1323+
c.sendline(f'delete interfaces ethernet eth{hwid_idx} hw-id')
1324+
c.expect(cfg_mode_prompt)
1325+
c.sendline('commit')
1326+
c.expect(cfg_mode_prompt)
1327+
c.sendline('save')
1328+
c.expect(cfg_mode_prompt)
1329+
c.sendline('exit')
1330+
c.expect(op_mode_prompt)
1331+
1332+
log.info('Rebooting to verify interface naming survives across reboot')
1333+
c.sendline('reboot now')
1334+
waitForLogin(c, log)
1335+
loginVM(c, log)
1336+
1337+
log.info('Collecting interface naming diagnostics')
1338+
c.sendline('show configuration commands | match "hw-id"')
1339+
c.expect(op_mode_prompt)
1340+
c.sendline('show interfaces ethernet')
1341+
c.expect(op_mode_prompt)
1342+
c.sendline('ip link show')
1343+
c.expect(op_mode_prompt)
1344+
c.sendline('show log | match "hw-id"')
1345+
c.expect(op_mode_prompt)
1346+
c.sendline('cat /run/vyos-net-name-resolve.json 2>/dev/null || true')
1347+
c.expect(op_mode_prompt)
1348+
c.sendline('show log kernel | match "eth"')
1349+
c.expect(op_mode_prompt)
1350+
1351+
verify_eth_mac_mapping(c, log)
1352+
12771353
elif args.raid:
12781354
# Verify RAID subsystem - by deleting a disk and re-create the array
12791355
# from scratch

0 commit comments

Comments
 (0)