diff options
Diffstat (limited to 'hicn-light/src/hicn/processor/fib.c')
-rw-r--r-- | hicn-light/src/hicn/processor/fib.c | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/hicn-light/src/hicn/processor/fib.c b/hicn-light/src/hicn/processor/fib.c new file mode 100644 index 000000000..e7a680f9c --- /dev/null +++ b/hicn-light/src/hicn/processor/fib.c @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <src/hicn/config.h> +#include <stdio.h> + +#include <hicn/processor/fib.h> + +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_Network.h> + +#include <parc/assert/parc_Assert.h> + +#define NULL_POS 128 +#define MSB_POS 127 + +struct node; +typedef struct node FibNode; + +struct node { + FibNode *left; + FibNode *right; + FibEntry *entry; + unsigned pos; +}; + +struct fib { + FibNode *root; + unsigned size; +}; + +// ===================================================== +// Public API + +FibNode *_createNode(FibNode *left, FibNode *right, FibEntry *entry, + unsigned pos) { + FibNode *n = parcMemory_AllocateAndClear(sizeof(FibNode)); + parcAssertNotNull(n, "parcMemory_AllocateAndClear(%zu) returned NULL", + sizeof(FibNode)); + + n->left = left; + n->right = right; + n->entry = entry; + n->pos = pos; + + return n; +} + +FIB *fib_Create() { + FIB *hicnFib = parcMemory_AllocateAndClear(sizeof(FIB)); + parcAssertNotNull(hicnFib, "parcMemory_AllocateAndClear(%zu) returned NULL", + sizeof(FIB)); + + hicnFib->root = + _createNode(NULL, NULL, NULL, + NULL_POS); // the pos will decrease going down in the trie + hicnFib->root->left = hicnFib->root; + hicnFib->root->right = hicnFib->root; + + hicnFib->size = 0; + + return hicnFib; +} + +void _destroyNode(FibNode *n) { + fibEntry_Release(&n->entry); + parcMemory_Deallocate((void **)&n); + n = NULL; +} + +void _destroyFib(FIB *fib) { + // XXX + // to be done + return; +} + +void fib_Destroy(FIB **fibPtr) { + parcAssertNotNull(fibPtr, "Parameter must be non-null double pointer"); + parcAssertNotNull(*fibPtr, "Parameter must dereference to non-null pointer"); + + FIB *fib = *fibPtr; + + _destroyFib(fib); + parcMemory_Deallocate((void **)&fib); + *fibPtr = NULL; +} + +void fib_Add(FIB *fib, FibEntry *entry) { + parcAssertNotNull(fib, "Parameter must be non-null"); + parcAssertNotNull(entry, "Parameter must be non-null"); + + NameBitvector *name = name_GetContentName(fibEntry_GetPrefix(entry)); + + // search the name + FibNode *prev = fib->root; + FibNode *curr; + + if (nameBitvector_testBit(name, MSB_POS)) { + curr = fib->root->right; + } else { + curr = fib->root->left; + } + + while (prev->pos > curr->pos) { + prev = curr; + if (nameBitvector_testBit(name, curr->pos)) { + curr = curr->right; + } else { + curr = curr->left; + } + } + + if (curr->entry != NULL && + nameBitvector_Equals( + name, name_GetContentName(fibEntry_GetPrefix(curr->entry)))) { + // there is already an entry with this name + // do nothing. Before call ADD we should check + // if the node exists, and, in that case update it + return; + } + + // if the name is not in the FIB search for the first different bit between + // the new name to add and the node found in the trie + uint8_t pos = MSB_POS; + if (curr->entry != NULL) + pos = nameBitvector_firstDiff( + name, name_GetContentName(fibEntry_GetPrefix(curr->entry))); + + // reset pointer and search the insertion point + prev = fib->root; + if (nameBitvector_testBit(name, MSB_POS)) + curr = fib->root->right; + else + curr = fib->root->left; + + while (prev->pos > curr->pos && curr->pos > pos) { + prev = curr; + if (nameBitvector_testBit(name, curr->pos)) { + curr = curr->right; + } else { + curr = curr->left; + } + } + + // insert the node + fib->size++; + FibNode *n = _createNode(NULL, NULL, entry, pos); + + if (nameBitvector_testBit(name, pos)) { + n->left = curr; + n->right = n; + } else { + n->left = n; + n->right = curr; + } + + uint8_t new_pos = prev->pos; + if (new_pos == NULL_POS) new_pos = MSB_POS; + + if (nameBitvector_testBit(name, new_pos)) { + prev->right = n; + } else { + prev->left = n; + } +} + +FibEntry *fib_Contains(const FIB *fib, const Name *prefix) { + parcAssertNotNull(fib, "Parameter must be non-null"); + parcAssertNotNull(prefix, "Parameter must be non-null"); + + NameBitvector *name = name_GetContentName(prefix); + + // this is the same as the first part of the add function + // we cannnot call this function inside the add because + // we need the pointer prev and curr for the insertion + + FibNode *prev = fib->root; + FibNode *curr; + + if (nameBitvector_testBit(name, MSB_POS)) + curr = fib->root->right; + else + curr = fib->root->left; + + while (prev->pos > curr->pos) { + prev = curr; + + if (nameBitvector_testBit(name, curr->pos)) { + curr = curr->right; + } else { + curr = curr->left; + } + } + + if (curr->entry != NULL && + nameBitvector_Equals( + name, name_GetContentName(fibEntry_GetPrefix(curr->entry)))) { + return curr->entry; + } else { + return NULL; + } +} + +void _removeNode(FIB *fib, const Name *prefix) { + parcAssertNotNull(fib, "Parameter must be non-null"); + parcAssertNotNull(prefix, "Parameter must be non-null"); + + FibNode *grand = NULL; // grandparent + FibNode *prev = + fib->root; // parent: it will points to curr of the next hop in the trie + FibNode *curr; // current node: the node to remove + + NameBitvector *name = name_GetContentName(prefix); + + if (nameBitvector_testBit(name, MSB_POS)) { + curr = fib->root->right; + } else { + curr = fib->root->left; + } + + // in the first loop we always search the node to remove + while (prev->pos > curr->pos) { + grand = prev; + prev = curr; + + if (nameBitvector_testBit(name, curr->pos)) { + curr = curr->right; + } else { + curr = curr->left; + } + } + + if (!nameBitvector_Equals( + name, name_GetContentName(fibEntry_GetPrefix(curr->entry)))) { + // the node does not exists + return; + } + + // search for the real parent of curr (*tmpPrev) + // prev points to curr or next node in the trie + // this is because of the loopback links + + FibNode *tmpPrev = fib->root; + FibNode *tmpCurr; + + if (nameBitvector_testBit(name, MSB_POS)) { + tmpCurr = fib->root->right; + } else { + tmpCurr = fib->root->left; + } + + // here we compare pointer so we are sure to stop at the right potion + while (tmpCurr != curr) { + tmpPrev = tmpCurr; + + if (nameBitvector_testBit(name, tmpCurr->pos)) { + tmpCurr = tmpCurr->right; + } else { + tmpCurr = tmpCurr->left; + } + } + + // now curr is the node to remove and tmpPrev is the real parent of curr + + if (curr == prev) { + // this is the case where curr is a leaf node + FibNode *next; // child of curr (the loopback) + + if (nameBitvector_testBit(name, curr->pos)) { + next = curr->left; + } else { + next = curr->right; + } + + if (nameBitvector_testBit(name, tmpPrev->pos)) { + tmpPrev->right = next; + } else { + tmpPrev->left = next; + } + + } else { + // curr is an internal node + FibNode *next; // child of prev (loopback) + + if (nameBitvector_testBit(name, prev->pos)) { + next = prev->left; + } else { + next = prev->right; + } + + if (nameBitvector_testBit(name, grand->pos)) { + grand->right = next; + } else { + grand->left = next; + } + + if (nameBitvector_testBit(name, tmpPrev->pos)) { + tmpPrev->right = prev; + } else { + tmpPrev->left = prev; + } + + prev->left = curr->left; + prev->right = curr->right; + prev->pos = curr->pos; + } + + fib->size--; + _destroyNode(curr); +} + +void fib_Remove(FIB *fib, const Name *name, unsigned connId) { + parcAssertNotNull(fib, "Parameter must be non-null"); + parcAssertNotNull(name, "Parameter must be non-null"); + + FibEntry *entry = fib_Contains(fib, name); + + if (entry == NULL) { + return; + } + + fibEntry_RemoveNexthopByConnectionId(entry, connId); + if (fibEntry_NexthopCount(entry) == 0) { + _removeNode(fib, name); + } +} + +void _removeConnectionId(FibNode *n, unsigned pos, unsigned connectionId, + FibEntryList *list) { + if (n->pos < pos) { + fibEntry_RemoveNexthopByConnectionId(n->entry, connectionId); + if (fibEntry_NexthopCount(n->entry) == 0) { + fibEntryList_Append(list, n->entry); + } + _removeConnectionId(n->left, n->pos, connectionId, list); + _removeConnectionId(n->right, n->pos, connectionId, list); + } +} + +void fib_RemoveConnectionId(FIB *fib, unsigned connectionId) { + parcAssertNotNull(fib, "Parameter must be non-null"); + + // 1 - we vist the tree to remove the connection id + // 2 - during the visit we collect the fib entry with 0 nexthop + // 3 - after the visit we remove this entries + + FibEntryList *list = fibEntryList_Create(); + + _removeConnectionId(fib->root->left, fib->root->pos, connectionId, list); + _removeConnectionId(fib->root->right, fib->root->pos, connectionId, list); + + for (int i = 0; i < fibEntryList_Length(list); i++) { + _removeNode(fib, fibEntry_GetPrefix(fibEntryList_Get(list, i))); + } + + fibEntryList_Destroy(&list); +} + +size_t fib_Length(const FIB *fib) { + parcAssertNotNull(fib, "Parameter must be non-null"); + return fib->size; +} + +FibEntry *fib_Match(const FIB *fib, const Message *interestMessage) { + parcAssertNotNull(fib, "Parameter must be non-null"); + parcAssertNotNull(interestMessage, "Parameter must be non-null"); + + NameBitvector *name = name_GetContentName(message_GetName(interestMessage)); + + FibNode *prev = fib->root; + FibNode *curr; + + FibNode *match = NULL; + unsigned len = 0; + + if (nameBitvector_testBit(name, MSB_POS)) + curr = fib->root->right; + else + curr = fib->root->left; + + while (prev->pos > curr->pos) { + prev = curr; + + if (curr->entry != NULL) { + if (nameBitvector_StartsWith( + name, name_GetContentName(fibEntry_GetPrefix(curr->entry))) && + nameBitvector_GetLength( + name_GetContentName(fibEntry_GetPrefix(curr->entry))) > len) { + match = curr; + len = nameBitvector_GetLength( + name_GetContentName(fibEntry_GetPrefix(curr->entry))); + } + } + + if (nameBitvector_testBit(name, curr->pos)) + curr = curr->right; + else + curr = curr->left; + } + + if (curr->entry != NULL) { + if (nameBitvector_StartsWith( + name, name_GetContentName(fibEntry_GetPrefix(curr->entry))) && + nameBitvector_GetLength( + name_GetContentName(fibEntry_GetPrefix(curr->entry))) > len) { + match = curr; + len = nameBitvector_GetLength( + name_GetContentName(fibEntry_GetPrefix(curr->entry))); + } + } + + if (match != NULL && match->entry != NULL) { + return match->entry; + } else { + return NULL; + } +} + +void _collectFibEntries(FibNode *n, int pos, FibEntryList *list) { + if (n->pos < (unsigned)pos) { + fibEntryList_Append(list, n->entry); + _collectFibEntries(n->left, n->pos, list); + _collectFibEntries(n->right, n->pos, list); + } +} + +FibEntryList *fib_GetEntries(const FIB *fib) { + parcAssertNotNull(fib, "Parameter must be non-null"); + + FibEntryList *list = fibEntryList_Create(); + + _collectFibEntries(fib->root->left, fib->root->pos, list); + _collectFibEntries(fib->root->right, fib->root->pos, list); + + return list; +} |