From add9f4a99cc358749b276157d9957c527fef4fe7 Mon Sep 17 00:00:00 2001 From: Dimitri Staessens Date: Wed, 29 Jul 2026 18:47:41 +0200 Subject: ipcpd: Flush fd from pff after disconnect The flow descriptors were not immediately removed from the routing tables when they were disconnected, so forwarding paths could still use the fd after the IPCP has deallocated the flow. Refactors the tests and adds some for the del_fd function. Signed-off-by: Dimitri Staessens Signed-off-by: Sander Vrijders --- src/ipcpd/unicast/pff/tests/pft_test.c | 300 ++++++++++++++++++++++++++++----- 1 file changed, 262 insertions(+), 38 deletions(-) (limited to 'src/ipcpd/unicast/pff/tests') diff --git a/src/ipcpd/unicast/pff/tests/pft_test.c b/src/ipcpd/unicast/pff/tests/pft_test.c index 20e73a94..0b4a165b 100644 --- a/src/ipcpd/unicast/pff/tests/pft_test.c +++ b/src/ipcpd/unicast/pff/tests/pft_test.c @@ -22,97 +22,321 @@ #include "pft.c" +#include + #include #define TBL_SIZE 256 #define INT_TEST 4 -int pft_test(int argc, - char ** argv) +/* Next hops used by the del_fd tests. */ +#define FD_GONE 7 +#define FD_KEEP 8 +#define FD_OTHER 9 + +static int pft_add(struct pft * pft, + uint64_t dst, + const int * fds, + size_t len) +{ + int * blk; + size_t i; + + blk = malloc(sizeof(*blk) * len); + if (blk == NULL) + return -1; + + for (i = 0; i < len; i++) + blk[i] = fds[i]; + + if (pft_insert(pft, dst, blk, len)) { + free(blk); + return -1; + } + + return 0; +} + +static int test_pft_create_destroy(void) +{ + struct pft * pft; + + TEST_START(); + + pft = pft_create(TBL_SIZE); + if (pft == NULL) { + printf("Failed to create.\n"); + goto fail; + } + + pft_destroy(pft); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_pft_insert_lookup(void) { struct pft * pft; - int i; int * j; size_t len; + int i; - (void) argc; - (void) argv; + TEST_START(); pft = pft_create(TBL_SIZE); if (pft == NULL) { printf("Failed to create.\n"); - return -1; + goto fail; } for (i = 0; i < TBL_SIZE + INT_TEST + 2; i++) { - j = malloc(sizeof(*j)); - if (j == NULL) { - printf("Failed to malloc.\n"); - pft_destroy(pft); - return -1; - } - *j = i; - - if (pft_insert(pft, i, j, 1)) { + if (pft_add(pft, i, &i, 1)) { printf("Failed to insert.\n"); - pft_destroy(pft); - free(j); - return -1; + goto fail_pft; } } if (pft_lookup(pft, INT_TEST, &j, &len)) { printf("Failed to lookup.\n"); - pft_destroy(pft); - return -1; + goto fail_pft; } if (*j != INT_TEST) { printf("Lookup returned wrong value (%d != %d).\n", INT_TEST, *j); - pft_destroy(pft); - return -1; + goto fail_pft; } if (pft_lookup(pft, TBL_SIZE + INT_TEST, &j, &len)) { - printf("Failed to lookup.\n"); - pft_destroy(pft); - return -1; + printf("Failed to lookup on a shared bucket.\n"); + goto fail_pft; } if (*j != TBL_SIZE + INT_TEST) { printf("Lookup returned wrong value (%d != %d).\n", - INT_TEST, *j); - pft_destroy(pft); - return -1; + TBL_SIZE + INT_TEST, *j); + goto fail_pft; + } + + pft_destroy(pft); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_pft: + pft_destroy(pft); + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_pft_delete(void) +{ + struct pft * pft; + int * j; + size_t len; + int i; + + TEST_START(); + + pft = pft_create(TBL_SIZE); + if (pft == NULL) { + printf("Failed to create.\n"); + goto fail; + } + + for (i = 0; i < TBL_SIZE + INT_TEST + 2; i++) { + if (pft_add(pft, i, &i, 1)) { + printf("Failed to insert.\n"); + goto fail_pft; + } } if (pft_delete(pft, INT_TEST)) { printf("Failed to delete.\n"); - pft_destroy(pft); - return -1; + goto fail_pft; } if (pft_lookup(pft, INT_TEST, &j, &len) == 0) { printf("Failed to delete properly.\n"); - pft_destroy(pft); - return -1; + goto fail_pft; } if (pft_lookup(pft, TBL_SIZE + INT_TEST, &j, &len)) { printf("Failed to lookup after deletion.\n"); - pft_destroy(pft); - return -1; + goto fail_pft; } if (*j != TBL_SIZE + INT_TEST) { printf("Lookup returned wrong value (%d != %d).\n", - INT_TEST, *j); - pft_destroy(pft); - return -1; + TBL_SIZE + INT_TEST, *j); + goto fail_pft; } pft_destroy(pft); - return 0; + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_pft: + pft_destroy(pft); + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_pft_del_fd_sole(void) +{ + struct pft * pft; + int * j; + size_t len; + int fds[] = {FD_GONE}; + + TEST_START(); + + pft = pft_create(TBL_SIZE); + if (pft == NULL) { + printf("Failed to create.\n"); + goto fail; + } + + if (pft_add(pft, INT_TEST, fds, 1)) { + printf("Failed to insert.\n"); + goto fail_pft; + } + + pft_del_fd(pft, FD_GONE); + + if (pft_lookup(pft, INT_TEST, &j, &len) == 0) { + printf("Route without a next hop survived.\n"); + goto fail_pft; + } + + pft_destroy(pft); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_pft: + pft_destroy(pft); + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_pft_del_fd_shared(void) +{ + struct pft * pft; + int * j; + size_t len; + int fds[] = {FD_KEEP, FD_GONE, FD_OTHER}; + + TEST_START(); + + pft = pft_create(TBL_SIZE); + if (pft == NULL) { + printf("Failed to create.\n"); + goto fail; + } + + if (pft_add(pft, INT_TEST, fds, 3)) { + printf("Failed to insert.\n"); + goto fail_pft; + } + + pft_del_fd(pft, FD_GONE); + + if (pft_lookup(pft, INT_TEST, &j, &len)) { + printf("Route with next hops left was dropped.\n"); + goto fail_pft; + } + + if (len != 2) { + printf("Expected 2 next hops, got %zu.\n", len); + goto fail_pft; + } + + if (j[0] != FD_KEEP || j[1] != FD_OTHER) { + printf("Next hops not preserved in order (%d, %d).\n", + j[0], j[1]); + goto fail_pft; + } + + pft_destroy(pft); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_pft: + pft_destroy(pft); + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_pft_del_fd_untouched(void) +{ + struct pft * pft; + int * j; + size_t len; + int fds[] = {FD_KEEP}; + + TEST_START(); + + pft = pft_create(TBL_SIZE); + if (pft == NULL) { + printf("Failed to create.\n"); + goto fail; + } + + if (pft_add(pft, INT_TEST, fds, 1)) { + printf("Failed to insert.\n"); + goto fail_pft; + } + + pft_del_fd(pft, FD_GONE); + + if (pft_lookup(pft, INT_TEST, &j, &len)) { + printf("Unrelated route was dropped.\n"); + goto fail_pft; + } + + if (len != 1 || *j != FD_KEEP) { + printf("Unrelated route was modified.\n"); + goto fail_pft; + } + + pft_destroy(pft); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_pft: + pft_destroy(pft); + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int pft_test(int argc, + char ** argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + + ret |= test_pft_create_destroy(); + ret |= test_pft_insert_lookup(); + ret |= test_pft_delete(); + ret |= test_pft_del_fd_sole(); + ret |= test_pft_del_fd_shared(); + ret |= test_pft_del_fd_untouched(); + + return ret; } -- cgit v1.2.3