Skip to content

Commit 1bbf53e

Browse files
committed
xen: Add test-ring0 tests
Signed-off-by: Tu Dinh <[email protected]>
1 parent 82c0a8b commit 1bbf53e

File tree

3 files changed

+159
-1
lines changed

3 files changed

+159
-1
lines changed

jobs.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,9 +385,13 @@
385385
"description": "Testing of the Xen hypervisor itself",
386386
"requirements": [
387387
"A host with HVM FEP enabled (`hvm_fep` Xen command line parameter).",
388+
"A small VM that can be imported on the SRs.",
389+
"The host will be rebooted by the tests.",
388390
],
389391
"nb_pools": 1,
390-
"params": {},
392+
"params": {
393+
"--vm": "single/small_vm",
394+
},
391395
"paths": ["tests/xen"],
392396
},
393397
"vtpm": {

tests/xen/conftest.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from packaging import version
55

6+
from lib.host import Host
67
# Explicitly import package-scoped fixtures (see explanation in pkgfixtures.py)
78
from pkgfixtures import host_with_saved_yum_state
89

@@ -65,3 +66,11 @@ def host_with_dom0_tests(host_with_saved_yum_state):
6566
host = host_with_saved_yum_state
6667
host.yum_install(['xen-dom0-tests'])
6768
yield host
69+
70+
@pytest.fixture(scope="package")
71+
def host_with_ring0_tests(host_with_saved_yum_state: Host):
72+
host = host_with_saved_yum_state
73+
host.yum_install(['test-ring0'])
74+
yield host
75+
# clean up the loaded test modules and test states at the end
76+
host.reboot(verify=True)

tests/xen/test_ring0.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import logging
2+
import pytest
3+
import secrets
4+
import time
5+
from typing import Optional
6+
7+
from lib.host import Host
8+
from lib.vm import VM
9+
10+
# Requirements:
11+
# From --hosts parameter:
12+
# - host: XCP-ng host >= 8.2, reboots after test
13+
# From --vm parameter:
14+
# - A VM to import
15+
# Only XST tests with pass/fail results, and that don't crash the host were included.
16+
17+
18+
def do_execute_xst(host: Host, modname: str, testname: Optional[str] = None):
19+
if testname is None:
20+
testname = modname
21+
host.ssh(f"modprobe xst_{modname}")
22+
try:
23+
host.ssh(f"echo 1 > /sys/kernel/debug/xst/{testname}/run")
24+
host.ssh(f"grep -q 'status: pass' /sys/kernel/debug/xst/{testname}/results")
25+
finally:
26+
host.ssh(f"modprobe -r xst_{modname}", check=False)
27+
28+
29+
@pytest.fixture
30+
def host_without_livepatch_loaded(host: Host):
31+
if host.ssh_with_result("lsmod | grep -wq livepatch_tester").returncode == 0:
32+
pytest.fail("livepatch_tester already loaded, host needs reboot")
33+
return host
34+
35+
36+
@pytest.mark.reboot # host_with_ring0_tests
37+
@pytest.mark.usefixtures("host_with_ring0_tests")
38+
class TestRing0Tests:
39+
def test_privcmd_restrict(self, host: Host):
40+
host.ssh("/usr/bin/privcmd-restrict_test")
41+
42+
def test_xst_alloc_balloon(self, host: Host):
43+
do_execute_xst(host, "alloc_balloon")
44+
45+
def test_xst_big_module(self, host: Host):
46+
do_execute_xst(host, "big_module")
47+
48+
def test_xst_evtchn_latency(self, host: Host):
49+
do_execute_xst(host, "evtchn_latency", "evtchn_lat")
50+
51+
@pytest.mark.skip("only makes sense for 2l evtchn")
52+
def test_xst_evtchn_limit(self, host: Host):
53+
do_execute_xst(host, "evtchn_limit")
54+
55+
def test_xst_evtchn_stress(self, host: Host):
56+
do_execute_xst(host, "evtchn_stress")
57+
58+
@pytest.mark.skip("leaks event channels infinitely")
59+
def test_xst_evtchn_unbind(self, host: Host):
60+
do_execute_xst(host, "evtchn_unbind")
61+
62+
def test_xst_get_user_pages(self, host: Host):
63+
host.ssh("modprobe xst_get_user_pages")
64+
try:
65+
host.ssh("/usr/bin/gup_test")
66+
finally:
67+
host.ssh("modprobe -r xst_get_user_pages", check=False)
68+
69+
def test_xst_grant_copy_perf(self, host: Host):
70+
do_execute_xst(host, "grant_copy_perf", "gntcpy_perf")
71+
72+
@pytest.mark.small_vm
73+
def test_xst_ioemu_msi(self, host: Host, running_unix_vm: VM):
74+
# TODO: validate MSI reception in guest
75+
vm = running_unix_vm
76+
domid = vm.param_get("dom-id")
77+
host.ssh("modprobe xst_ioemu_msi")
78+
try:
79+
host.ssh(f"echo {domid} > /sys/kernel/debug/xst/ioemu_msi/domid")
80+
host.ssh("echo 1 > /sys/kernel/debug/xst/ioemu_msi/data")
81+
host.ssh("echo 1 > /sys/kernel/debug/xst/ioemu_msi/run")
82+
host.ssh("grep -q 'status: pass' /sys/kernel/debug/xst/ioemu_msi/results")
83+
finally:
84+
host.ssh("modprobe -r xst_ioemu_msi", check=False)
85+
86+
def test_xst_livepatch(self, host_without_livepatch_loaded: Host):
87+
"""
88+
This test loads a `livepatch_testee` module, whose test functions are
89+
updated by loading `livepatch_tester`. Distinguish between unpatched
90+
and patch functions using printk output, delimited by a random marker.
91+
92+
`livepatch_tester` also, strangely enough, causes the patched
93+
`test_function_crash` to crash the host (instead of the other way
94+
around). So don't test that.
95+
"""
96+
host = host_without_livepatch_loaded
97+
try:
98+
host.ssh("modprobe livepatch_testee")
99+
100+
marker = secrets.token_hex()
101+
logging.debug(f"using pre-patch marker {marker}")
102+
host.ssh(f"echo {marker} > /dev/kmsg")
103+
host.ssh("echo 1 > /proc/livepatch_testee/cmd")
104+
host.ssh(f"dmesg | grep -A 9999 {marker} | grep -q test_function_default_old")
105+
106+
host.ssh("modprobe livepatch_tester")
107+
108+
marker = secrets.token_hex()
109+
logging.debug(f"using post-patch marker {marker}")
110+
host.ssh(f"echo {marker} > /dev/kmsg")
111+
host.ssh("echo 1 > /proc/livepatch_testee/cmd")
112+
host.ssh(f"dmesg | grep -A 9999 {marker} | grep -q test_function_default_new")
113+
finally:
114+
host.ssh("modprobe -r livepatch_testee", check=False)
115+
116+
def test_xst_memory_leak(self, host: Host):
117+
if not host.file_exists("/sys/kernel/debug/kmemleak"):
118+
pytest.skip("CONFIG_DEBUG_KMEMLEAK is not set")
119+
120+
host.ssh("modprobe xst_memory_leak")
121+
122+
try:
123+
host.ssh("echo clear > /sys/kernel/debug/kmemleak")
124+
host.ssh("echo 1 > /sys/kernel/debug/xst/memleak/run")
125+
host.ssh("modprobe -r xst_memory_leak")
126+
host.ssh("echo scan > /sys/kernel/debug/kmemleak")
127+
# scan twice with a delay inbetween, otherwise the leak may not show up
128+
time.sleep(5)
129+
host.ssh("echo scan > /sys/kernel/debug/kmemleak")
130+
host.ssh("grep -q unreferenced /sys/kernel/debug/kmemleak")
131+
finally:
132+
host.ssh("modprobe -r xst_memory_leak", check=False)
133+
134+
def test_xst_pte_set_clear_flags(self, host: Host):
135+
do_execute_xst(host, "pte_set_clear_flags")
136+
137+
def test_xst_ptwr_xchg(self, host: Host):
138+
do_execute_xst(host, "ptwr_xchg")
139+
140+
def test_xst_set_memory_uc(self, host: Host):
141+
do_execute_xst(host, "set_memory_uc")
142+
143+
@pytest.mark.skip("crashes the host, disabled by default")
144+
def test_xst_soft_lockup(self, host: Host):
145+
do_execute_xst(host, "soft_lockup")

0 commit comments

Comments
 (0)