diff options
Diffstat (limited to 'src/ipcpd/unicast/pff')
| -rw-r--r-- | src/ipcpd/unicast/pff/multipath.c | 20 | ||||
| -rw-r--r-- | src/ipcpd/unicast/pff/multipath.h | 4 | ||||
| -rw-r--r-- | src/ipcpd/unicast/pff/pft.c | 37 | ||||
| -rw-r--r-- | src/ipcpd/unicast/pff/pft.h | 3 | ||||
| -rw-r--r-- | src/ipcpd/unicast/pff/simple.c | 20 | ||||
| -rw-r--r-- | src/ipcpd/unicast/pff/simple.h | 4 | ||||
| -rw-r--r-- | src/ipcpd/unicast/pff/tests/pft_test.c | 300 |
7 files changed, 348 insertions, 40 deletions
diff --git a/src/ipcpd/unicast/pff/multipath.c b/src/ipcpd/unicast/pff/multipath.c index 9ba59592..c2c21078 100644 --- a/src/ipcpd/unicast/pff/multipath.c +++ b/src/ipcpd/unicast/pff/multipath.c @@ -49,7 +49,7 @@ struct pff_ops multipath_pff_ops = { .del = multipath_pff_del, .flush = multipath_pff_flush, .nhop = multipath_pff_nhop, - .flow_state_change = NULL + .flow_state_change = multipath_pff_flow_state_change }; struct pff_i * multipath_pff_create(void) @@ -170,6 +170,24 @@ void multipath_pff_flush(struct pff_i * pff_i) pft_flush(pff_i->pft); } +int multipath_pff_flow_state_change(struct pff_i * pff_i, + int fd, + bool up) +{ + assert(pff_i); + + if (up) + return 0; + + pthread_rwlock_wrlock(&pff_i->lock); + + pft_del_fd(pff_i->pft, fd); + + pthread_rwlock_unlock(&pff_i->lock); + + return 0; +} + int multipath_pff_nhop(struct pff_i * pff_i, uint64_t addr) { diff --git a/src/ipcpd/unicast/pff/multipath.h b/src/ipcpd/unicast/pff/multipath.h index 5329f7fc..123030b6 100644 --- a/src/ipcpd/unicast/pff/multipath.h +++ b/src/ipcpd/unicast/pff/multipath.h @@ -53,6 +53,10 @@ void multipath_pff_flush(struct pff_i * pff_i); int multipath_pff_nhop(struct pff_i * pff_i, uint64_t addr); +int multipath_pff_flow_state_change(struct pff_i * pff_i, + int fd, + bool up); + extern struct pff_ops multipath_pff_ops; #endif /* OUROBOROS_IPCPD_UNICAST_MULTIPATH_PFF_H */ diff --git a/src/ipcpd/unicast/pff/pft.c b/src/ipcpd/unicast/pff/pft.c index d0e562d6..2a295a40 100644 --- a/src/ipcpd/unicast/pff/pft.c +++ b/src/ipcpd/unicast/pff/pft.c @@ -91,6 +91,43 @@ void pft_destroy(struct pft * pft) free(pft); } +void pft_del_fd(struct pft * pft, + int fd) +{ + unsigned int i; + struct list_head * p; + struct list_head * h; + struct pft_entry * entry; + size_t j; + size_t n; + + assert(pft); + + for (i = 0; i < pft->buckets_size; i++) { + list_for_each_safe(p, h, &(pft->buckets[i])) { + entry = list_entry(p, struct pft_entry, next); + + n = 0; + for (j = 0; j < entry->len; j++) { + if (entry->fds[j] != fd) + entry->fds[n++] = entry->fds[j]; + } + + if (n == entry->len) + continue; + + if (n > 0) { + entry->len = n; + continue; + } + + list_del(&entry->next); + free(entry->fds); + free(entry); + } + } +} + void pft_flush(struct pft * pft) { unsigned int i; diff --git a/src/ipcpd/unicast/pff/pft.h b/src/ipcpd/unicast/pff/pft.h index 15bbe451..3517e0ef 100644 --- a/src/ipcpd/unicast/pff/pft.h +++ b/src/ipcpd/unicast/pff/pft.h @@ -35,6 +35,9 @@ void pft_destroy(struct pft * table); void pft_flush(struct pft * table); +void pft_del_fd(struct pft * table, + int fd); + /* Passes ownership of the block of memory */ int pft_insert(struct pft * pft, uint64_t dst, diff --git a/src/ipcpd/unicast/pff/simple.c b/src/ipcpd/unicast/pff/simple.c index 7befa42f..4347dcba 100644 --- a/src/ipcpd/unicast/pff/simple.c +++ b/src/ipcpd/unicast/pff/simple.c @@ -47,7 +47,7 @@ struct pff_ops simple_pff_ops = { .del = simple_pff_del, .flush = simple_pff_flush, .nhop = simple_pff_nhop, - .flow_state_change = NULL + .flow_state_change = simple_pff_flow_state_change }; struct pff_i * simple_pff_create(void) @@ -170,6 +170,24 @@ void simple_pff_flush(struct pff_i * pff_i) pft_flush(pff_i->pft); } +int simple_pff_flow_state_change(struct pff_i * pff_i, + int fd, + bool up) +{ + assert(pff_i); + + if (up) + return 0; + + pthread_rwlock_wrlock(&pff_i->lock); + + pft_del_fd(pff_i->pft, fd); + + pthread_rwlock_unlock(&pff_i->lock); + + return 0; +} + int simple_pff_nhop(struct pff_i * pff_i, uint64_t addr) { diff --git a/src/ipcpd/unicast/pff/simple.h b/src/ipcpd/unicast/pff/simple.h index 1046e4c4..b72aba21 100644 --- a/src/ipcpd/unicast/pff/simple.h +++ b/src/ipcpd/unicast/pff/simple.h @@ -52,6 +52,10 @@ void simple_pff_flush(struct pff_i * pff_i); int simple_pff_nhop(struct pff_i * pff_i, uint64_t addr); +int simple_pff_flow_state_change(struct pff_i * pff_i, + int fd, + bool up); + extern struct pff_ops simple_pff_ops; #endif /* OUROBOROS_IPCPD_UNICAST_SIMPLE_PFF_H */ 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 <test/test.h> + #include <stdio.h> #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; } |
