mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-27 17:59:37 -04:00
vfio: selftests: Add tests to validate SR-IOV UAPI
Add a selftest, vfio_pci_sriov_uapi_test.c, to validate the SR-IOV UAPI, including the following cases, iterating over all the IOMMU modes currently supported: - Setting correct/incorrect/NULL tokens during device init. - Close the PF device immediately after setting the token. - Change/override the PF's token after device init. Signed-off-by: Raghavendra Rao Ananta <rananta@google.com> Reviewed-by: Vipin Sharma <vipinsh@google.com> Reviewed-by: David Matlack <dmatlack@google.com> Tested-by: David Matlack <dmatlack@google.com> Link: https://lore.kernel.org/r/20260505212838.1698034-9-rananta@google.com Signed-off-by: Alex Williamson <alex@shazbot.org>
This commit is contained in:
committed by
Alex Williamson
parent
3152e7f457
commit
a6e4e72660
@@ -12,6 +12,7 @@ TEST_GEN_PROGS += vfio_iommufd_setup_test
|
||||
TEST_GEN_PROGS += vfio_pci_device_test
|
||||
TEST_GEN_PROGS += vfio_pci_device_init_perf_test
|
||||
TEST_GEN_PROGS += vfio_pci_driver_test
|
||||
TEST_GEN_PROGS += vfio_pci_sriov_uapi_test
|
||||
|
||||
TEST_FILES += scripts/cleanup.sh
|
||||
TEST_FILES += scripts/lib.sh
|
||||
|
||||
217
tools/testing/selftests/vfio/vfio_pci_sriov_uapi_test.c
Normal file
217
tools/testing/selftests/vfio/vfio_pci_sriov_uapi_test.c
Normal file
@@ -0,0 +1,217 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include "lib/include/libvfio/assert.h"
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
#include <libvfio.h>
|
||||
|
||||
#include "../kselftest_harness.h"
|
||||
|
||||
#define UUID_1 "52ac9bff-3a88-4fbd-901a-0d767c3b6c97"
|
||||
#define UUID_2 "88594674-90a0-47a9-aea8-9d9b352ac08a"
|
||||
|
||||
static const char *pf_bdf;
|
||||
static char *vf_bdf;
|
||||
|
||||
static pid_t main_pid;
|
||||
|
||||
static int container_setup(struct vfio_pci_device *device, const char *bdf,
|
||||
const char *vf_token)
|
||||
{
|
||||
vfio_pci_group_setup(device, bdf);
|
||||
vfio_container_set_iommu(device);
|
||||
__vfio_pci_group_get_device_fd(device, bdf, vf_token);
|
||||
|
||||
/* The device fd will be -1 in case of mismatched tokens */
|
||||
return (device->fd < 0);
|
||||
}
|
||||
|
||||
static int iommufd_setup(struct vfio_pci_device *device, const char *bdf,
|
||||
const char *vf_token)
|
||||
{
|
||||
vfio_pci_cdev_open(device, bdf);
|
||||
return __vfio_device_bind_iommufd(device->fd,
|
||||
device->iommu->iommufd, vf_token);
|
||||
}
|
||||
|
||||
static int device_init(const char *bdf, struct iommu *iommu,
|
||||
const char *vf_token, struct vfio_pci_device **out_dev)
|
||||
{
|
||||
struct vfio_pci_device *device = vfio_pci_device_alloc(bdf, iommu);
|
||||
int ret;
|
||||
|
||||
if (iommu->mode->container_path)
|
||||
ret = container_setup(device, bdf, vf_token);
|
||||
else
|
||||
ret = iommufd_setup(device, bdf, vf_token);
|
||||
|
||||
*out_dev = device;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void device_cleanup(struct vfio_pci_device *device)
|
||||
{
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
if (device->fd > 0)
|
||||
VFIO_ASSERT_EQ(close(device->fd), 0);
|
||||
|
||||
if (device->group_fd)
|
||||
VFIO_ASSERT_EQ(close(device->group_fd), 0);
|
||||
|
||||
vfio_pci_device_free(device);
|
||||
}
|
||||
|
||||
FIXTURE(vfio_pci_sriov_uapi_test) {
|
||||
struct vfio_pci_device *pf;
|
||||
struct vfio_pci_device *vf;
|
||||
struct iommu *iommu;
|
||||
char *pf_token;
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT(vfio_pci_sriov_uapi_test) {
|
||||
const char *iommu_mode;
|
||||
char *vf_token;
|
||||
};
|
||||
|
||||
#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode, _name, _vf_token) \
|
||||
FIXTURE_VARIANT_ADD(vfio_pci_sriov_uapi_test, _iommu_mode ## _ ## _name) { \
|
||||
.iommu_mode = #_iommu_mode, \
|
||||
.vf_token = (_vf_token), \
|
||||
}
|
||||
|
||||
FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(same_uuid, UUID_1);
|
||||
FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(diff_uuid, UUID_2);
|
||||
FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(null_uuid, NULL);
|
||||
|
||||
FIXTURE_SETUP(vfio_pci_sriov_uapi_test)
|
||||
{
|
||||
self->iommu = iommu_init(variant->iommu_mode);
|
||||
|
||||
self->pf_token = UUID_1;
|
||||
ASSERT_EQ(device_init(pf_bdf, self->iommu, self->pf_token, &self->pf), 0);
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(vfio_pci_sriov_uapi_test)
|
||||
{
|
||||
device_cleanup(self->vf);
|
||||
device_cleanup(self->pf);
|
||||
iommu_cleanup(self->iommu);
|
||||
}
|
||||
|
||||
/*
|
||||
* This asserts if the VF device is successfully created if its token matches
|
||||
* with the token used to create/override the PF or fails during a mismatch.
|
||||
*/
|
||||
#define ASSERT_COND_VF_CREATION(_ret) do { \
|
||||
if (!variant->vf_token || strcmp(self->pf_token, variant->vf_token)) { \
|
||||
ASSERT_NE((_ret), 0); \
|
||||
} else { \
|
||||
ASSERT_EQ((_ret), 0); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Validate if the UAPI handles correctly and incorrectly set token on the VF.
|
||||
*/
|
||||
TEST_F(vfio_pci_sriov_uapi_test, init_token_match)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = device_init(vf_bdf, self->iommu, variant->vf_token, &self->vf);
|
||||
ASSERT_COND_VF_CREATION(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* After closing the PF, validate if the VF access still needs the right token.
|
||||
*/
|
||||
TEST_F(vfio_pci_sriov_uapi_test, pf_early_close)
|
||||
{
|
||||
int ret;
|
||||
|
||||
device_cleanup(self->pf);
|
||||
|
||||
/* Clean the 'pf' to avoid calling device_cleanup() again. */
|
||||
self->pf = NULL;
|
||||
|
||||
ret = device_init(vf_bdf, self->iommu, variant->vf_token, &self->vf);
|
||||
ASSERT_COND_VF_CREATION(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* After PF device init, override the existing token and validate if the newly
|
||||
* set token is the one that's active.
|
||||
*/
|
||||
TEST_F(vfio_pci_sriov_uapi_test, override_token)
|
||||
{
|
||||
int ret;
|
||||
|
||||
self->pf_token = UUID_2;
|
||||
vfio_device_set_vf_token(self->pf->fd, self->pf_token);
|
||||
|
||||
ret = device_init(vf_bdf, self->iommu, variant->vf_token, &self->vf);
|
||||
ASSERT_COND_VF_CREATION(ret);
|
||||
}
|
||||
|
||||
static void vf_teardown(void)
|
||||
{
|
||||
/*
|
||||
* The child processes, created by TEST_F()s, inherits this atexit()
|
||||
* handler. Hence, check and destroy the VF only when the main/parent
|
||||
* process exits.
|
||||
*/
|
||||
if (getpid() != main_pid)
|
||||
return;
|
||||
|
||||
free(vf_bdf);
|
||||
sysfs_sriov_numvfs_set(pf_bdf, 0);
|
||||
}
|
||||
|
||||
static void vf_setup(void)
|
||||
{
|
||||
char *vf_driver;
|
||||
int nr_vfs;
|
||||
|
||||
nr_vfs = sysfs_sriov_totalvfs_get(pf_bdf);
|
||||
if (nr_vfs <= 0)
|
||||
ksft_exit_skip("SR-IOV may not be supported by the PF: %s\n", pf_bdf);
|
||||
|
||||
nr_vfs = sysfs_sriov_numvfs_get(pf_bdf);
|
||||
if (nr_vfs != 0)
|
||||
ksft_exit_skip("SR-IOV already configured for the PF: %s\n", pf_bdf);
|
||||
|
||||
/* Create only one VF for testing */
|
||||
sysfs_sriov_numvfs_set(pf_bdf, 1);
|
||||
|
||||
/*
|
||||
* Setup an exit handler to destroy the VF in case of failures
|
||||
* during further setup at the end of the test run.
|
||||
*/
|
||||
main_pid = getpid();
|
||||
VFIO_ASSERT_EQ(atexit(vf_teardown), 0);
|
||||
|
||||
vf_bdf = sysfs_sriov_vf_bdf_get(pf_bdf, 0);
|
||||
|
||||
/*
|
||||
* The VF inherits the driver from the PF.
|
||||
* Ensure this is 'vfio-pci' before proceeding.
|
||||
*/
|
||||
vf_driver = sysfs_driver_get(vf_bdf);
|
||||
VFIO_ASSERT_NE(vf_driver, NULL);
|
||||
VFIO_ASSERT_EQ(strcmp(vf_driver, "vfio-pci"), 0);
|
||||
free(vf_driver);
|
||||
|
||||
printf("Created 1 VF (%s) under the PF: %s\n", vf_bdf, pf_bdf);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pf_bdf = vfio_selftests_get_bdf(&argc, argv);
|
||||
vf_setup();
|
||||
|
||||
return test_harness_run(argc, argv);
|
||||
}
|
||||
Reference in New Issue
Block a user