xref: /linux/tools/testing/selftests/vfio/vfio_pci_sriov_uapi_test.c (revision efe86f088f48f18c27b648e5724048947f3b7fb4)
1*a6e4e726SRaghavendra Rao Ananta // SPDX-License-Identifier: GPL-2.0-only
2*a6e4e726SRaghavendra Rao Ananta #include "lib/include/libvfio/assert.h"
3*a6e4e726SRaghavendra Rao Ananta #include <fcntl.h>
4*a6e4e726SRaghavendra Rao Ananta #include <unistd.h>
5*a6e4e726SRaghavendra Rao Ananta #include <stdlib.h>
6*a6e4e726SRaghavendra Rao Ananta #include <sys/ioctl.h>
7*a6e4e726SRaghavendra Rao Ananta #include <linux/limits.h>
8*a6e4e726SRaghavendra Rao Ananta 
9*a6e4e726SRaghavendra Rao Ananta #include <libvfio.h>
10*a6e4e726SRaghavendra Rao Ananta 
11*a6e4e726SRaghavendra Rao Ananta #include "../kselftest_harness.h"
12*a6e4e726SRaghavendra Rao Ananta 
13*a6e4e726SRaghavendra Rao Ananta #define UUID_1 "52ac9bff-3a88-4fbd-901a-0d767c3b6c97"
14*a6e4e726SRaghavendra Rao Ananta #define UUID_2 "88594674-90a0-47a9-aea8-9d9b352ac08a"
15*a6e4e726SRaghavendra Rao Ananta 
16*a6e4e726SRaghavendra Rao Ananta static const char *pf_bdf;
17*a6e4e726SRaghavendra Rao Ananta static char *vf_bdf;
18*a6e4e726SRaghavendra Rao Ananta 
19*a6e4e726SRaghavendra Rao Ananta static pid_t main_pid;
20*a6e4e726SRaghavendra Rao Ananta 
21*a6e4e726SRaghavendra Rao Ananta static int container_setup(struct vfio_pci_device *device, const char *bdf,
22*a6e4e726SRaghavendra Rao Ananta 			   const char *vf_token)
23*a6e4e726SRaghavendra Rao Ananta {
24*a6e4e726SRaghavendra Rao Ananta 	vfio_pci_group_setup(device, bdf);
25*a6e4e726SRaghavendra Rao Ananta 	vfio_container_set_iommu(device);
26*a6e4e726SRaghavendra Rao Ananta 	__vfio_pci_group_get_device_fd(device, bdf, vf_token);
27*a6e4e726SRaghavendra Rao Ananta 
28*a6e4e726SRaghavendra Rao Ananta 	/* The device fd will be -1 in case of mismatched tokens */
29*a6e4e726SRaghavendra Rao Ananta 	return (device->fd < 0);
30*a6e4e726SRaghavendra Rao Ananta }
31*a6e4e726SRaghavendra Rao Ananta 
32*a6e4e726SRaghavendra Rao Ananta static int iommufd_setup(struct vfio_pci_device *device, const char *bdf,
33*a6e4e726SRaghavendra Rao Ananta 			 const char *vf_token)
34*a6e4e726SRaghavendra Rao Ananta {
35*a6e4e726SRaghavendra Rao Ananta 	vfio_pci_cdev_open(device, bdf);
36*a6e4e726SRaghavendra Rao Ananta 	return __vfio_device_bind_iommufd(device->fd,
37*a6e4e726SRaghavendra Rao Ananta 					  device->iommu->iommufd, vf_token);
38*a6e4e726SRaghavendra Rao Ananta }
39*a6e4e726SRaghavendra Rao Ananta 
40*a6e4e726SRaghavendra Rao Ananta static int device_init(const char *bdf, struct iommu *iommu,
41*a6e4e726SRaghavendra Rao Ananta 		       const char *vf_token, struct vfio_pci_device **out_dev)
42*a6e4e726SRaghavendra Rao Ananta {
43*a6e4e726SRaghavendra Rao Ananta 	struct vfio_pci_device *device = vfio_pci_device_alloc(bdf, iommu);
44*a6e4e726SRaghavendra Rao Ananta 	int ret;
45*a6e4e726SRaghavendra Rao Ananta 
46*a6e4e726SRaghavendra Rao Ananta 	if (iommu->mode->container_path)
47*a6e4e726SRaghavendra Rao Ananta 		ret = container_setup(device, bdf, vf_token);
48*a6e4e726SRaghavendra Rao Ananta 	else
49*a6e4e726SRaghavendra Rao Ananta 		ret = iommufd_setup(device, bdf, vf_token);
50*a6e4e726SRaghavendra Rao Ananta 
51*a6e4e726SRaghavendra Rao Ananta 	*out_dev = device;
52*a6e4e726SRaghavendra Rao Ananta 	return ret;
53*a6e4e726SRaghavendra Rao Ananta }
54*a6e4e726SRaghavendra Rao Ananta 
55*a6e4e726SRaghavendra Rao Ananta static void device_cleanup(struct vfio_pci_device *device)
56*a6e4e726SRaghavendra Rao Ananta {
57*a6e4e726SRaghavendra Rao Ananta 	if (!device)
58*a6e4e726SRaghavendra Rao Ananta 		return;
59*a6e4e726SRaghavendra Rao Ananta 
60*a6e4e726SRaghavendra Rao Ananta 	if (device->fd > 0)
61*a6e4e726SRaghavendra Rao Ananta 		VFIO_ASSERT_EQ(close(device->fd), 0);
62*a6e4e726SRaghavendra Rao Ananta 
63*a6e4e726SRaghavendra Rao Ananta 	if (device->group_fd)
64*a6e4e726SRaghavendra Rao Ananta 		VFIO_ASSERT_EQ(close(device->group_fd), 0);
65*a6e4e726SRaghavendra Rao Ananta 
66*a6e4e726SRaghavendra Rao Ananta 	vfio_pci_device_free(device);
67*a6e4e726SRaghavendra Rao Ananta }
68*a6e4e726SRaghavendra Rao Ananta 
69*a6e4e726SRaghavendra Rao Ananta FIXTURE(vfio_pci_sriov_uapi_test) {
70*a6e4e726SRaghavendra Rao Ananta 	struct vfio_pci_device *pf;
71*a6e4e726SRaghavendra Rao Ananta 	struct vfio_pci_device *vf;
72*a6e4e726SRaghavendra Rao Ananta 	struct iommu *iommu;
73*a6e4e726SRaghavendra Rao Ananta 	char *pf_token;
74*a6e4e726SRaghavendra Rao Ananta };
75*a6e4e726SRaghavendra Rao Ananta 
76*a6e4e726SRaghavendra Rao Ananta FIXTURE_VARIANT(vfio_pci_sriov_uapi_test) {
77*a6e4e726SRaghavendra Rao Ananta 	const char *iommu_mode;
78*a6e4e726SRaghavendra Rao Ananta 	char *vf_token;
79*a6e4e726SRaghavendra Rao Ananta };
80*a6e4e726SRaghavendra Rao Ananta 
81*a6e4e726SRaghavendra Rao Ananta #define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode, _name, _vf_token)		\
82*a6e4e726SRaghavendra Rao Ananta FIXTURE_VARIANT_ADD(vfio_pci_sriov_uapi_test, _iommu_mode ## _ ## _name) {	\
83*a6e4e726SRaghavendra Rao Ananta 	.iommu_mode = #_iommu_mode,						\
84*a6e4e726SRaghavendra Rao Ananta 	.vf_token = (_vf_token),						\
85*a6e4e726SRaghavendra Rao Ananta }
86*a6e4e726SRaghavendra Rao Ananta 
87*a6e4e726SRaghavendra Rao Ananta FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(same_uuid, UUID_1);
88*a6e4e726SRaghavendra Rao Ananta FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(diff_uuid, UUID_2);
89*a6e4e726SRaghavendra Rao Ananta FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(null_uuid, NULL);
90*a6e4e726SRaghavendra Rao Ananta 
91*a6e4e726SRaghavendra Rao Ananta FIXTURE_SETUP(vfio_pci_sriov_uapi_test)
92*a6e4e726SRaghavendra Rao Ananta {
93*a6e4e726SRaghavendra Rao Ananta 	self->iommu = iommu_init(variant->iommu_mode);
94*a6e4e726SRaghavendra Rao Ananta 
95*a6e4e726SRaghavendra Rao Ananta 	self->pf_token = UUID_1;
96*a6e4e726SRaghavendra Rao Ananta 	ASSERT_EQ(device_init(pf_bdf, self->iommu, self->pf_token, &self->pf), 0);
97*a6e4e726SRaghavendra Rao Ananta }
98*a6e4e726SRaghavendra Rao Ananta 
99*a6e4e726SRaghavendra Rao Ananta FIXTURE_TEARDOWN(vfio_pci_sriov_uapi_test)
100*a6e4e726SRaghavendra Rao Ananta {
101*a6e4e726SRaghavendra Rao Ananta 	device_cleanup(self->vf);
102*a6e4e726SRaghavendra Rao Ananta 	device_cleanup(self->pf);
103*a6e4e726SRaghavendra Rao Ananta 	iommu_cleanup(self->iommu);
104*a6e4e726SRaghavendra Rao Ananta }
105*a6e4e726SRaghavendra Rao Ananta 
106*a6e4e726SRaghavendra Rao Ananta /*
107*a6e4e726SRaghavendra Rao Ananta  * This asserts if the VF device is successfully created if its token matches
108*a6e4e726SRaghavendra Rao Ananta  * with the token used to create/override the PF or fails during a mismatch.
109*a6e4e726SRaghavendra Rao Ananta  */
110*a6e4e726SRaghavendra Rao Ananta #define ASSERT_COND_VF_CREATION(_ret) do {					\
111*a6e4e726SRaghavendra Rao Ananta 	if (!variant->vf_token || strcmp(self->pf_token, variant->vf_token)) {	\
112*a6e4e726SRaghavendra Rao Ananta 		ASSERT_NE((_ret), 0);						\
113*a6e4e726SRaghavendra Rao Ananta 	} else {								\
114*a6e4e726SRaghavendra Rao Ananta 		ASSERT_EQ((_ret), 0);						\
115*a6e4e726SRaghavendra Rao Ananta 	}									\
116*a6e4e726SRaghavendra Rao Ananta } while (0)
117*a6e4e726SRaghavendra Rao Ananta 
118*a6e4e726SRaghavendra Rao Ananta /*
119*a6e4e726SRaghavendra Rao Ananta  * Validate if the UAPI handles correctly and incorrectly set token on the VF.
120*a6e4e726SRaghavendra Rao Ananta  */
121*a6e4e726SRaghavendra Rao Ananta TEST_F(vfio_pci_sriov_uapi_test, init_token_match)
122*a6e4e726SRaghavendra Rao Ananta {
123*a6e4e726SRaghavendra Rao Ananta 	int ret;
124*a6e4e726SRaghavendra Rao Ananta 
125*a6e4e726SRaghavendra Rao Ananta 	ret = device_init(vf_bdf, self->iommu, variant->vf_token, &self->vf);
126*a6e4e726SRaghavendra Rao Ananta 	ASSERT_COND_VF_CREATION(ret);
127*a6e4e726SRaghavendra Rao Ananta }
128*a6e4e726SRaghavendra Rao Ananta 
129*a6e4e726SRaghavendra Rao Ananta /*
130*a6e4e726SRaghavendra Rao Ananta  * After closing the PF, validate if the VF access still needs the right token.
131*a6e4e726SRaghavendra Rao Ananta  */
132*a6e4e726SRaghavendra Rao Ananta TEST_F(vfio_pci_sriov_uapi_test, pf_early_close)
133*a6e4e726SRaghavendra Rao Ananta {
134*a6e4e726SRaghavendra Rao Ananta 	int ret;
135*a6e4e726SRaghavendra Rao Ananta 
136*a6e4e726SRaghavendra Rao Ananta 	device_cleanup(self->pf);
137*a6e4e726SRaghavendra Rao Ananta 
138*a6e4e726SRaghavendra Rao Ananta 	/* Clean the 'pf' to avoid calling device_cleanup() again. */
139*a6e4e726SRaghavendra Rao Ananta 	self->pf = NULL;
140*a6e4e726SRaghavendra Rao Ananta 
141*a6e4e726SRaghavendra Rao Ananta 	ret = device_init(vf_bdf, self->iommu, variant->vf_token, &self->vf);
142*a6e4e726SRaghavendra Rao Ananta 	ASSERT_COND_VF_CREATION(ret);
143*a6e4e726SRaghavendra Rao Ananta }
144*a6e4e726SRaghavendra Rao Ananta 
145*a6e4e726SRaghavendra Rao Ananta /*
146*a6e4e726SRaghavendra Rao Ananta  * After PF device init, override the existing token and validate if the newly
147*a6e4e726SRaghavendra Rao Ananta  * set token is the one that's active.
148*a6e4e726SRaghavendra Rao Ananta  */
149*a6e4e726SRaghavendra Rao Ananta TEST_F(vfio_pci_sriov_uapi_test, override_token)
150*a6e4e726SRaghavendra Rao Ananta {
151*a6e4e726SRaghavendra Rao Ananta 	int ret;
152*a6e4e726SRaghavendra Rao Ananta 
153*a6e4e726SRaghavendra Rao Ananta 	self->pf_token = UUID_2;
154*a6e4e726SRaghavendra Rao Ananta 	vfio_device_set_vf_token(self->pf->fd, self->pf_token);
155*a6e4e726SRaghavendra Rao Ananta 
156*a6e4e726SRaghavendra Rao Ananta 	ret = device_init(vf_bdf, self->iommu, variant->vf_token, &self->vf);
157*a6e4e726SRaghavendra Rao Ananta 	ASSERT_COND_VF_CREATION(ret);
158*a6e4e726SRaghavendra Rao Ananta }
159*a6e4e726SRaghavendra Rao Ananta 
160*a6e4e726SRaghavendra Rao Ananta static void vf_teardown(void)
161*a6e4e726SRaghavendra Rao Ananta {
162*a6e4e726SRaghavendra Rao Ananta 	/*
163*a6e4e726SRaghavendra Rao Ananta 	 * The child processes, created by TEST_F()s, inherits this atexit()
164*a6e4e726SRaghavendra Rao Ananta 	 * handler. Hence, check and destroy the VF only when the main/parent
165*a6e4e726SRaghavendra Rao Ananta 	 * process exits.
166*a6e4e726SRaghavendra Rao Ananta 	 */
167*a6e4e726SRaghavendra Rao Ananta 	if (getpid() != main_pid)
168*a6e4e726SRaghavendra Rao Ananta 		return;
169*a6e4e726SRaghavendra Rao Ananta 
170*a6e4e726SRaghavendra Rao Ananta 	free(vf_bdf);
171*a6e4e726SRaghavendra Rao Ananta 	sysfs_sriov_numvfs_set(pf_bdf, 0);
172*a6e4e726SRaghavendra Rao Ananta }
173*a6e4e726SRaghavendra Rao Ananta 
174*a6e4e726SRaghavendra Rao Ananta static void vf_setup(void)
175*a6e4e726SRaghavendra Rao Ananta {
176*a6e4e726SRaghavendra Rao Ananta 	char *vf_driver;
177*a6e4e726SRaghavendra Rao Ananta 	int nr_vfs;
178*a6e4e726SRaghavendra Rao Ananta 
179*a6e4e726SRaghavendra Rao Ananta 	nr_vfs = sysfs_sriov_totalvfs_get(pf_bdf);
180*a6e4e726SRaghavendra Rao Ananta 	if (nr_vfs <= 0)
181*a6e4e726SRaghavendra Rao Ananta 		ksft_exit_skip("SR-IOV may not be supported by the PF: %s\n", pf_bdf);
182*a6e4e726SRaghavendra Rao Ananta 
183*a6e4e726SRaghavendra Rao Ananta 	nr_vfs = sysfs_sriov_numvfs_get(pf_bdf);
184*a6e4e726SRaghavendra Rao Ananta 	if (nr_vfs != 0)
185*a6e4e726SRaghavendra Rao Ananta 		ksft_exit_skip("SR-IOV already configured for the PF: %s\n", pf_bdf);
186*a6e4e726SRaghavendra Rao Ananta 
187*a6e4e726SRaghavendra Rao Ananta 	/* Create only one VF for testing */
188*a6e4e726SRaghavendra Rao Ananta 	sysfs_sriov_numvfs_set(pf_bdf, 1);
189*a6e4e726SRaghavendra Rao Ananta 
190*a6e4e726SRaghavendra Rao Ananta 	/*
191*a6e4e726SRaghavendra Rao Ananta 	 * Setup an exit handler to destroy the VF in case of failures
192*a6e4e726SRaghavendra Rao Ananta 	 * during further setup at the end of the test run.
193*a6e4e726SRaghavendra Rao Ananta 	 */
194*a6e4e726SRaghavendra Rao Ananta 	main_pid = getpid();
195*a6e4e726SRaghavendra Rao Ananta 	VFIO_ASSERT_EQ(atexit(vf_teardown), 0);
196*a6e4e726SRaghavendra Rao Ananta 
197*a6e4e726SRaghavendra Rao Ananta 	vf_bdf = sysfs_sriov_vf_bdf_get(pf_bdf, 0);
198*a6e4e726SRaghavendra Rao Ananta 
199*a6e4e726SRaghavendra Rao Ananta 	/*
200*a6e4e726SRaghavendra Rao Ananta 	 * The VF inherits the driver from the PF.
201*a6e4e726SRaghavendra Rao Ananta 	 * Ensure this is 'vfio-pci' before proceeding.
202*a6e4e726SRaghavendra Rao Ananta 	 */
203*a6e4e726SRaghavendra Rao Ananta 	vf_driver = sysfs_driver_get(vf_bdf);
204*a6e4e726SRaghavendra Rao Ananta 	VFIO_ASSERT_NE(vf_driver, NULL);
205*a6e4e726SRaghavendra Rao Ananta 	VFIO_ASSERT_EQ(strcmp(vf_driver, "vfio-pci"), 0);
206*a6e4e726SRaghavendra Rao Ananta 	free(vf_driver);
207*a6e4e726SRaghavendra Rao Ananta 
208*a6e4e726SRaghavendra Rao Ananta 	printf("Created 1 VF (%s) under the PF: %s\n", vf_bdf, pf_bdf);
209*a6e4e726SRaghavendra Rao Ananta }
210*a6e4e726SRaghavendra Rao Ananta 
211*a6e4e726SRaghavendra Rao Ananta int main(int argc, char *argv[])
212*a6e4e726SRaghavendra Rao Ananta {
213*a6e4e726SRaghavendra Rao Ananta 	pf_bdf = vfio_selftests_get_bdf(&argc, argv);
214*a6e4e726SRaghavendra Rao Ananta 	vf_setup();
215*a6e4e726SRaghavendra Rao Ananta 
216*a6e4e726SRaghavendra Rao Ananta 	return test_harness_run(argc, argv);
217*a6e4e726SRaghavendra Rao Ananta }
218