Skip to content

Commit b793dab

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 b793dab

File tree

2 files changed

+127
-0
lines changed

2 files changed

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

0 commit comments

Comments
 (0)