11import logging as log
22import re
3+ import time
34
45from virttest import utils_misc , virsh
6+ from avocado .utils import process
57from 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