diff options
author | Thanos Makatos <thanos.makatos@nutanix.com> | 2021-02-10 09:08:10 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-10 09:08:10 +0000 |
commit | 365ca96a97740332d3633090d850222d10bc9d70 (patch) | |
tree | bd9885cd57351c05ac12d63ef51a4e4e5b3eef7d /test | |
parent | c5d11659c95c995acb77a71fe03c38b240ca43d9 (diff) | |
download | libvfio-user-365ca96a97740332d3633090d850222d10bc9d70.zip libvfio-user-365ca96a97740332d3633090d850222d10bc9d70.tar.gz libvfio-user-365ca96a97740332d3633090d850222d10bc9d70.tar.bz2 |
expose migration region (#305)
This patch exposes the fact that live migration is implemented as a
special device region. Hiding this from the user doesn't offer much
benefit since it only takes just a little bit of extra code for the user
to handle it as a region. We do keep the migration callback
functionality since this feature substantially simplifies supporting
live migration from the device implementation's perspective.
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Co-authored-by: John Levon <john.levon@nutanix.com>
Diffstat (limited to 'test')
-rw-r--r-- | test/CMakeLists.txt | 2 | ||||
-rw-r--r-- | test/mocks.c | 23 | ||||
-rw-r--r-- | test/unit-tests.c | 176 |
3 files changed, 198 insertions, 3 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2a339f0..a4f49ad 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -53,6 +53,8 @@ target_link_libraries(unit-tests PUBLIC "-Wl,--wrap=close") target_link_libraries(unit-tests PUBLIC "-Wl,--wrap=tran_sock_send_iovec") target_link_libraries(unit-tests PUBLIC "-Wl,--wrap=free") target_link_libraries(unit-tests PUBLIC "-Wl,--wrap=process_request") +target_link_libraries(unit-tests PUBLIC "-Wl,--wrap=bind") +target_link_libraries(unit-tests PUBLIC "-Wl,--wrap=listen") enable_testing() add_test(NAME unit-tests COMMAND unit-tests) diff --git a/test/mocks.c b/test/mocks.c index c38ec7b..303a6c2 100644 --- a/test/mocks.c +++ b/test/mocks.c @@ -33,6 +33,8 @@ #include <setjmp.h> #include <cmocka.h> #include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> #include "mocks.h" #include "dma.h" @@ -124,6 +126,10 @@ __wrap_exec_command(vfu_ctx_t *vfu_ctx, struct vfio_user_header *hdr, int __wrap_close(int fd) { + if (!is_patched(close)) { + return __real_close(fd); + } + check_expected(fd); return mock(); } @@ -168,6 +174,19 @@ __wrap_process_request(vfu_ctx_t *vfu_ctx) return mock(); } +int __wrap_bind(int sockfd __attribute__((unused)), + const struct sockaddr *addr __attribute__((unused)), + socklen_t addrlen __attribute__((unused))) +{ + return 0; +} + +int __wrap_listen(int sockfd __attribute__((unused)), + int backlog __attribute__((unused))) +{ + return 0; +} + /* FIXME should be something faster than unsorted array, look at tsearch(3). */ static struct function funcs[] = { {.addr = &__wrap_dma_controller_add_region}, @@ -179,7 +198,9 @@ static struct function funcs[] = { {.addr = &__wrap_close}, {.addr = &__wrap_tran_sock_send_iovec}, {.addr = &__wrap_free}, - {.addr = &__wrap_process_request} + {.addr = &__wrap_process_request}, + {.addr = &__wrap_bind}, + {.addr = &__wrap_listen} }; static struct function* diff --git a/test/unit-tests.c b/test/unit-tests.c index c989d91..e3ad86e 100644 --- a/test/unit-tests.c +++ b/test/unit-tests.c @@ -39,6 +39,7 @@ #include <alloca.h> #include <string.h> #include <linux/pci_regs.h> +#include <sys/param.h> #include "dma.h" #include "libvfio-user.h" @@ -1202,11 +1203,158 @@ test_migration_state_transitions(void **state __attribute__ ((unused))) * and provide a function to execute before and after each unit test. */ static int -setup(void **state __attribute__((unused))) { +setup(void **state __attribute__((unused))) +{ unpatch_all(); return 0; } +static struct test_setup_migr_reg_dat { + vfu_ctx_t *v; + size_t rs; /* migration registers size */ + size_t ds; /* migration data size */ + size_t s; /* migration region size*/ + const vfu_migration_callbacks_t c; +} migr_reg_data = { + .c = { + .version = VFU_MIGR_CALLBACKS_VERS, + .transition = (void *)0x1, + .get_pending_bytes = (void *)0x2, + .prepare_data = (void *)0x3, + .read_data = (void *)0x4, + .write_data = (void *)0x5, + .data_written = (void *)0x6 + } +}; + +static int +setup_test_setup_migration_region(void **state) +{ + struct test_setup_migr_reg_dat *p = &migr_reg_data; + p->v = vfu_create_ctx(VFU_TRANS_SOCK, "test", 0, NULL, + VFU_DEV_TYPE_PCI); + if (p->v == NULL) { + return -1; + } + p->rs = ROUND_UP(sizeof(struct vfio_device_migration_info), sysconf(_SC_PAGE_SIZE)); + p->ds = sysconf(_SC_PAGE_SIZE); + p->s = p->rs + p->ds; + *state = p; + return setup(state); +} + +static vfu_ctx_t * +get_vfu_ctx(void **state) +{ + return (*((struct test_setup_migr_reg_dat **)(state)))->v; +} + +static int +teardown_test_setup_migration_region(void **state) +{ + struct test_setup_migr_reg_dat *p = *state; + vfu_destroy_ctx(p->v); + return 0; +} + +static void +test_setup_migration_region_too_small(void **state) +{ + vfu_ctx_t *v = get_vfu_ctx(state); + int r = vfu_setup_region(v, VFU_PCI_DEV_MIGR_REGION_IDX, + vfu_get_migr_register_area_size() - 1, NULL, + VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, NULL, 0, -1); + assert_int_equal(-1, r); + assert_int_equal(EINVAL, errno); +} + +static void +test_setup_migration_region_size_ok(void **state) +{ + vfu_ctx_t *v = get_vfu_ctx(state); + int r = vfu_setup_region(v, VFU_PCI_DEV_MIGR_REGION_IDX, + vfu_get_migr_register_area_size(), NULL, + VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, NULL, 0, -1); + assert_int_equal(0, r); +} + +static void +test_setup_migration_region_fully_mappable(void **state) +{ + struct test_setup_migr_reg_dat *p = *state; + int r = vfu_setup_region(p->v, VFU_PCI_DEV_MIGR_REGION_IDX, p->s, + NULL, VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, NULL, 0, + 0xdeadbeef); + assert_int_equal(-1, r); + assert_int_equal(EINVAL, errno); +} + +static void +test_setup_migration_region_sparsely_mappable_over_migration_registers(void **state) +{ + struct test_setup_migr_reg_dat *p = *state; + struct iovec mmap_areas[] = { + [0] = { + .iov_base = 0, + .iov_len = p->rs + } + }; + int r = vfu_setup_region(p->v, VFU_PCI_DEV_MIGR_REGION_IDX, p->s, NULL, + VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, mmap_areas, 1, 0xdeadbeef); + assert_int_equal(-1, r); + assert_int_equal(EINVAL, errno); +} + +static void +test_setup_migration_region_sparsely_mappable_valid(void **state) +{ + struct test_setup_migr_reg_dat *p = *state; + struct iovec mmap_areas[] = { + [0] = { + .iov_base = (void *)p->rs, + .iov_len = p->ds + } + }; + int r = vfu_setup_region(p->v, VFU_PCI_DEV_MIGR_REGION_IDX, p->s, NULL, + VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, mmap_areas, 1, + 0xdeadbeef); + assert_int_equal(0, r); +} + +static void +test_setup_migration_callbacks_without_migration_region(void **state) +{ + struct test_setup_migr_reg_dat *p = *state; + assert_int_equal(-1, vfu_setup_device_migration_callbacks(p->v, &p->c, 0)); + assert_int_equal(EINVAL, errno); +} + +static void +test_setup_migration_callbacks_bad_data_offset(void **state) +{ + struct test_setup_migr_reg_dat *p = *state; + int r = vfu_setup_region(p->v, VFU_PCI_DEV_MIGR_REGION_IDX, p->s, NULL, + VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, NULL, 0, -1); + assert_int_equal(0, r); + r = vfu_setup_device_migration_callbacks(p->v, &p->c, + vfu_get_migr_register_area_size() - 1); + assert_int_equal(-1, r); +} + +static void +test_setup_migration_callbacks(void **state) +{ + struct test_setup_migr_reg_dat *p = *state; + int r = vfu_setup_region(p->v, VFU_PCI_DEV_MIGR_REGION_IDX, p->s, NULL, + VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, NULL, 0, -1); + assert_int_equal(0, r); + r = vfu_setup_device_migration_callbacks(p->v, &p->c, + vfu_get_migr_register_area_size()); + assert_int_equal(0, r); + assert_non_null(p->v->migration); + /* FIXME can't validate p->v->migration because it's a private strcut, need to move it out of lib/migration.c */ +} + int main(void) { const struct CMUnitTest tests[] = { @@ -1232,7 +1380,31 @@ int main(void) cmocka_unit_test_setup(test_dma_map_sg, setup), cmocka_unit_test_setup(test_dma_addr_to_sg, setup), cmocka_unit_test_setup(test_vfu_setup_device_dma_cb, setup), - cmocka_unit_test_setup(test_migration_state_transitions, setup) + cmocka_unit_test_setup(test_migration_state_transitions, setup), + cmocka_unit_test_setup_teardown(test_setup_migration_region_too_small, + setup_test_setup_migration_region, + teardown_test_setup_migration_region), + cmocka_unit_test_setup_teardown(test_setup_migration_region_size_ok, + setup_test_setup_migration_region, + teardown_test_setup_migration_region), + cmocka_unit_test_setup_teardown(test_setup_migration_region_fully_mappable, + setup_test_setup_migration_region, + teardown_test_setup_migration_region), + cmocka_unit_test_setup_teardown(test_setup_migration_region_sparsely_mappable_over_migration_registers, + setup_test_setup_migration_region, + teardown_test_setup_migration_region), + cmocka_unit_test_setup_teardown(test_setup_migration_region_sparsely_mappable_valid, + setup_test_setup_migration_region, + teardown_test_setup_migration_region), + cmocka_unit_test_setup_teardown(test_setup_migration_callbacks_without_migration_region, + setup_test_setup_migration_region, + teardown_test_setup_migration_region), + cmocka_unit_test_setup_teardown(test_setup_migration_callbacks_bad_data_offset, + setup_test_setup_migration_region, + teardown_test_setup_migration_region), + cmocka_unit_test_setup_teardown(test_setup_migration_callbacks, + setup_test_setup_migration_region, + teardown_test_setup_migration_region), }; return cmocka_run_group_tests(tests, NULL, NULL); |