summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ipcpd/unicast/pff/multipath.c20
-rw-r--r--src/ipcpd/unicast/pff/multipath.h4
-rw-r--r--src/ipcpd/unicast/pff/pft.c37
-rw-r--r--src/ipcpd/unicast/pff/pft.h3
-rw-r--r--src/ipcpd/unicast/pff/simple.c20
-rw-r--r--src/ipcpd/unicast/pff/simple.h4
-rw-r--r--src/ipcpd/unicast/pff/tests/pft_test.c300
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;
}