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,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