Skip to content

Commit d12d05f

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

File tree

2 files changed

+164
-1
lines changed

2 files changed

+164
-1
lines changed

jobs.py

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

tests/xen/test_ring0.py

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

0 commit comments

Comments
 (0)