Skip to content

Commit 3d83499

Browse files
committed
CPI: Add test case to check hypervisor bit of cpi info
Check hypervisor bit of cpi info when there's nested guest boot up and it will be changed as expected Signed-off-by: bfu <[email protected]>
1 parent 61fff3f commit 3d83499

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

libvirt/tests/cfg/guest_kernel_debugging/cpi_info.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@
1616
- long_system_name:
1717
test_case_name = long_system_name
1818
test_system_name = "VERYLONGSYSTEMNAME123456789"
19+
- nested_kvm_cpi:
20+
test_case_name = nested_kvm_cpi
1921

libvirt/tests/src/guest_kernel_debugging/cpi_info.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import logging as log
22
import re
3+
import time
34

45
from virttest import utils_misc, virsh
6+
from avocado.utils import process
57
from virttest.utils_cpi import (
68
CPIChecker,
79
get_cpi_config,
@@ -298,6 +300,128 @@ def test_long_system_name(long_system_name):
298300

299301
logging.info("Long system name validation test passed")
300302

303+
def test_nested_kvm_cpi():
304+
"""
305+
Test case 4: Test CPI system_level behavior in nested KVM environment
306+
307+
Steps:
308+
1. L1 host: enable nested
309+
2. L2 guest: Check /sys/firmware/cpi/system_level and verify hypervisor_bit is '0'
310+
3. L2 guest: enable nested and Boot L3 guest
311+
4. L2 guest: Check /sys/firmware/cpi/system_level and verify hypervisor_bit is '1'
312+
"""
313+
logging.info("=== Test Case 4: Nested KVM CPI ===")
314+
315+
session = None
316+
try:
317+
# Login L2 guest
318+
session = vm.wait_for_login(timeout=60)
319+
320+
def check_and_enable_nested(is_guest=False):
321+
current_nested = None
322+
try:
323+
if is_guest:
324+
# Check on L2 guest
325+
current_nested = (session.cmd_output(
326+
"cat /sys/module/kvm/parameters/nested",
327+
timeout=30).strip())
328+
logging.info(f"Current nested status: {current_nested}")
329+
else:
330+
# Check on L1 host
331+
current_nested = process.run(
332+
"cat /sys/module/kvm/parameters/nested",
333+
timeout=30).stdout_text.strip()
334+
logging.info(f"Current nested status: {current_nested}")
335+
except Exception as e:
336+
logging.warning(
337+
f"Failed to check current nested status: {e}")
338+
339+
# Reload kvm module with nested=1 if not already enabled
340+
if current_nested != "1":
341+
logging.info("Reloading kvm module with nested=1")
342+
try:
343+
# Reload kvm modules with nested enabled
344+
if is_guest:
345+
# Reload on L2 guest
346+
session.cmd_output(
347+
"modprobe -r kvm ; modprobe kvm nested=1",
348+
timeout=30)
349+
# Verify nested is enabled
350+
new_status = session.cmd_output(
351+
"cat /sys/module/kvm/parameters/nested",
352+
timeout=30).strip()
353+
else:
354+
process.run(
355+
"modprobe -r kvm ; modprobe kvm nested=1",
356+
timeout=30).stdout_text.strip()
357+
# Verify nested is enabled
358+
new_status = process.run(
359+
"cat /sys/module/kvm/parameters/nested",
360+
timeout=30).stdout_text.strip()
361+
if new_status != "1":
362+
test.fail("Failed to enable nested virtualization")
363+
logging.info(
364+
"Nested virtualization enabled successfully")
365+
except Exception as e:
366+
test.fail(f"Failed to reload kvm module: {e}")
367+
else:
368+
logging.info("Nested virtualization already enabled")
369+
370+
logging.info("Step 1: Enabling nested virtualization on L1 host")
371+
check_and_enable_nested(is_guest=False)
372+
373+
logging.info("Step 2: Checking CPI system_level on L2 guest")
374+
checker = CPIChecker(vm, serial=serial)
375+
system_level = checker.get_cpi_field("system_level")
376+
parsed = checker._parse_system_level(system_level)
377+
if parsed['hypervisor_bit'] != 0:
378+
test.fail(f"L2 hypervisor_bit should be 0, but actual is "
379+
f"{parsed['hypervisor_bit']}")
380+
381+
logging.info("Step 3: Enable nested on L2 guest and Boot L3 guest")
382+
check_and_enable_nested(is_guest=True)
383+
384+
# install qemu-kvm on L2
385+
logging.info("Installing qemu-kvm")
386+
install_status = session.cmd_status('dnf install -y qemu-kvm*',
387+
timeout=180)
388+
if install_status != 0:
389+
check_status = session.cmd_status("which /usr/libexec/qemu-kvm")
390+
if check_status != 0:
391+
test.fail("Failed to install qemu-kvm and not found in PATH")
392+
else:
393+
logging.info("qemu-kvm already installed")
394+
395+
logging.info("Starting L3 guest")
396+
start_cmd = \
397+
"/usr/libexec/qemu-kvm -machine s390-ccw-virtio -no-shutdown &"
398+
try:
399+
session.sendline(start_cmd)
400+
except Exception as e:
401+
logging.error(f"Failed to start L3 guest: {e}")
402+
test.fail(f"Failed to start L3 guest: {e}")
403+
404+
# wait L3 guest to boot up
405+
logging.info("waiting for L3 guest to boot")
406+
time.sleep(5)
407+
# Verify qemu-kvm process is running
408+
qemu_status = session.cmd_status("pgrep -f qemu-kvm")
409+
if qemu_status != 0:
410+
test.fail("L3 guest (qemu-kvm) process not found")
411+
412+
logging.info("Step 4: Checking CPI system_level on L2 guest")
413+
system_level = checker.get_cpi_field("system_level")
414+
parsed = checker._parse_system_level(system_level)
415+
if parsed['hypervisor_bit'] != 1:
416+
test.fail(f"L2 hypervisor_bit should be 1, but actual is "
417+
f"{parsed['hypervisor_bit']}")
418+
finally:
419+
if session is not None:
420+
try:
421+
session.close()
422+
except Exception as e:
423+
logging.warning(f"Failed to close session: {e}")
424+
301425
def cleanup_cpi_config():
302426
"""
303427
Clean up CPI configuration by restoring from backup
@@ -315,6 +439,8 @@ def cleanup_cpi_config():
315439
test_managedsave()
316440
elif test_case_name == "long_system_name":
317441
test_long_system_name(test_system_name)
442+
elif test_case_name == "nested_kvm_cpi":
443+
test_nested_kvm_cpi()
318444
else:
319445
test.error(f"Unknown test case: {test_case_name}")
320446

0 commit comments

Comments
 (0)