/* runTest_ReplaceLeastRecentlyUsed * * Tests that the address mapper replaces the last recently used item * when adding a new item to a full address map. * * 1. Fill the address map * 2. Add another entry * 3. Check that only the least recent entry was removed */ static int runTest_replaceLeastRecentlyUsed(struct AppState* state, struct AddressMapper* map, struct TestInfo* info) { info->name = "Replace least recently used"; /* fill the address map */ for (unsigned int label = 1; label <= AddressMapper_MAX_ENTRIES; label++) { AddressMapper_put(label, getDummyAddress(), map); } /* santity check that the address mapper was filled */ for (unsigned int label = 1; label <= AddressMapper_MAX_ENTRIES; label++) { int index; index = AddressMapper_indexOf(label, map); if (index == -1) { info->failMessage = "Address mapper could not be filled"; return 0; } } /* add one more entry */ AddressMapper_put(AddressMapper_MAX_ENTRIES + 1, getDummyAddress(), map); /* now check that only the first item was evicted from the address map */ for (unsigned int label = 1; label <= AddressMapper_MAX_ENTRIES + 1; label++) { int index; index = AddressMapper_indexOf(label, map); if ((label != 1) && (index == -1)) { info->failMessage = "An item other than the least recently used was removed"; return 0; } else if ((label == 1) && (index != -1)) { info->failMessage = "Least recently used item was not removed"; return 0; } } info->pass = true; return 0; }
/* runTest_dontReplaceMostRecentlyUsed * * Tests that the address mapper does not replace the most recently used item * when adding a new item to a full address map * * 1. Fill address map with labels 1 .. N * 2. Query the index of the least recently used item (label=1) in order to promote it to * being the most recently used item * 3. Add a new entry to the address map * 4. Ensure it is entry with label==2 which has been removed */ static int runTest_dontReplaceMostRecentlyUsed(struct AppState* state, struct AddressMapper* map, struct TestInfo* info) { info->name = "Don't replace most recently used"; /* fill the address map such that the item with label==1 is the least recently used */ for (unsigned int label = 1; label <= AddressMapper_MAX_ENTRIES; label++) { AddressMapper_put(label, getDummyAddress(), map); } /* touch item #1. #2 is now the least recently used */ int index; index = AddressMapper_indexOf(1, map); if (index == -1) { info->failMessage = "Failed to fill address map - first item was dropped"; } /* add a new entry and check that #1 was not replaced. * check that #2 was replaced. */ AddressMapper_put(AddressMapper_MAX_ENTRIES + 1, getDummyAddress(), map); index = AddressMapper_indexOf(1, map); if (index == -1) { info->failMessage = "Address mapper wrongly removed #1 when it was not the " "least recently used"; return 0; } index = AddressMapper_indexOf(2, map); if (index != -1) { info->failMessage = "Address mapper replaced an item other than the " "least recently used"; return 0; } info->pass = true; return 0; }
/** * This is called as sendMessage() by the switch. * There is only one switch interface which sends all traffic. * message is aligned on the beginning of the switch header. */ static uint8_t incomingFromSwitch(struct Message* message, struct Interface* switchIf) { struct Ducttape* context = switchIf->senderContext; struct Headers_SwitchHeader* switchHeader = (struct Headers_SwitchHeader*) message->bytes; Message_shift(message, -Headers_SwitchHeader_SIZE); // The label comes in reversed from the switch because the switch doesn't know that we aren't // another switch ready to parse more bits, bit reversing the label yields the source address. switchHeader->label_be = Bits_bitReverse64(switchHeader->label_be); if (Headers_getMessageType(switchHeader) == Headers_SwitchHeader_TYPE_CONTROL) { uint8_t labelStr[20]; uint64_t label = Endian_bigEndianToHost64(switchHeader->label_be); AddrTools_printPath(labelStr, label); if (message->length < Control_HEADER_SIZE) { Log_info1(context->logger, "dropped runt ctrl packet from [%s]", labelStr); return Error_NONE; } else { Log_debug1(context->logger, "ctrl packet from [%s]", labelStr); } struct Control* ctrl = (struct Control*) message->bytes; bool pong = false; if (ctrl->type_be == Control_ERROR_be) { if (message->length < Control_Error_MIN_SIZE) { Log_info1(context->logger, "dropped runt error packet from [%s]", labelStr); return Error_NONE; } Log_info2(context->logger, "error packet from [%s], error type [%d]", labelStr, Endian_bigEndianToHost32(ctrl->content.error.errorType_be)); RouterModule_brokenPath(Endian_bigEndianToHost64(switchHeader->label_be), context->routerModule); uint8_t causeType = Headers_getMessageType(&ctrl->content.error.cause); if (causeType == Headers_SwitchHeader_TYPE_CONTROL) { if (message->length < Control_Error_MIN_SIZE + Control_HEADER_SIZE) { Log_info1(context->logger, "error packet from [%s] containing runt cause packet", labelStr); return Error_NONE; } struct Control* causeCtrl = (struct Control*) &(&ctrl->content.error.cause)[1]; if (causeCtrl->type_be != Control_PING_be) { Log_info3(context->logger, "error packet from [%s] caused by [%s] packet ([%d])", labelStr, Control_typeString(causeCtrl->type_be), Endian_bigEndianToHost16(causeCtrl->type_be)); } else { Log_debug2(context->logger, "error packet from [%s] in response to ping, length: [%d].", labelStr, message->length); // errors resulting from pings are forwarded back to the pinger. pong = true; } } else if (causeType != Headers_SwitchHeader_TYPE_DATA) { Log_info1(context->logger, "error packet from [%s] containing cause of unknown type [%d]", labelStr); } } else if (ctrl->type_be == Control_PONG_be) { pong = true; } else if (ctrl->type_be == Control_PING_be) { ctrl->type_be = Control_PONG_be; Message_shift(message, Headers_SwitchHeader_SIZE); switchIf->receiveMessage(message, switchIf); } else { Log_info2(context->logger, "control packet of unknown type from [%s], type [%d]", labelStr, Endian_bigEndianToHost16(ctrl->type_be)); } if (pong) { // Shift back over the header Message_shift(message, Headers_SwitchHeader_SIZE); context->switchPingerIf->receiveMessage(message, context->switchPingerIf); } return Error_NONE; } uint8_t* herKey = extractPublicKey(message, switchHeader->label_be, context->logger); int herAddrIndex; if (herKey) { uint8_t herAddrStore[16]; AddressCalc_addressForPublicKey(herAddrStore, herKey); if (herAddrStore[0] != 0xFC) { Log_debug(context->logger, "Got message from peer whose address is not in fc00::/8 range.\n"); return 0; } herAddrIndex = AddressMapper_put(switchHeader->label_be, herAddrStore, &context->addrMap); } else { herAddrIndex = AddressMapper_indexOf(switchHeader->label_be, &context->addrMap); if (herAddrIndex == -1) { uint64_t label = Endian_bigEndianToHost64(switchHeader->label_be); struct Node* n = RouterModule_getNode(label, context->routerModule); if (n) { herAddrIndex = AddressMapper_put(switchHeader->label_be, n->address.ip6.bytes, &context->addrMap); } else { #ifdef Log_DEBUG uint8_t switchAddr[20]; AddrTools_printPath(switchAddr, Endian_bigEndianToHost64(switchHeader->label_be)); Log_debug1(context->logger, "Dropped traffic packet from unknown node. (%s)\n", &switchAddr); #endif return 0; } } } // If the source address is the same as the router address, no third layer of crypto. context->routerAddress = context->addrMap.entries[herAddrIndex].address; // This is needed so that the priority and other information // from the switch header can be passed on properly. context->switchHeader = switchHeader; context->session = SessionManager_getSession(context->routerAddress, herKey, context->sm); // This goes to incomingFromCryptoAuth() // then incomingFromRouter() then core() context->layer = OUTER_LAYER; context->session->receiveMessage(message, context->session); return 0; }
/* runTest_orderCheck * * Tests that the address mapper properly maintains its entries in order of most * recently used and replaces entries in order of least recently used. * * 1. Fill address mapper * 2. Shuffle the contents of the address map * 2. Queries the address mapper in a random order * 3. Add new entries to the map such that only the most recently used * of the previously entries should still be presnt. * 4. Query the address map to see if only the most recently used item remains. */ static int runTest_orderCheck(struct AppState* state, struct AddressMapper* map, struct TestInfo* info) { info->name = "Order check"; /* the labels used for this test, stored in a random order */ uint64_t* labels; const uint64_t labelMin = 0xF000000000000000; const uint64_t labelMax = 0xFFFFFFFFFFFFFFFF; labels = state->allocator->calloc(AddressMapper_MAX_ENTRIES, sizeof(uint64_t), state->allocator); if (labels == NULL) { fprintf(stderr, "Failed to allocate memory\n"); return -1; } /* now generate random unique labels and add each one to the map */ for (int i = 0; i < AddressMapper_MAX_ENTRIES; i++) { generateLabel: labels[i] = (rand64() % (labelMax - labelMin + 1)) + labelMin; /* check the label is unique */ for (int j = 0; j < i; j++) { if (labels[i] == labels[j]) { goto generateLabel; } } AddressMapper_put(labels[i], getDummyAddress(), map); } /* shuffle the map */ for (int i = 0; i < AddressMapper_MAX_ENTRIES; i++) { int index; uint64_t randomLabel; randomLabel = labels[rand() % AddressMapper_MAX_ENTRIES]; index = AddressMapper_indexOf(randomLabel, map); if (index == -1) { info->failMessage = "Map has lost an element"; goto out; } } /* query the items in a random order. * after this, labels[0] will be the least recently used * item and labels[AddressMapper_MAX_ENTRIES - 1] will be the * most recently used */ for (int i = 0; i < AddressMapper_MAX_ENTRIES; i++) { uint64_t tmp; size_t r; /* swap labels[i] with a random element */ r = rand() % AddressMapper_MAX_ENTRIES; tmp = labels[i]; labels[i] = labels[r]; labels[r] = tmp; int index; index = AddressMapper_indexOf(labels[i], map); if (index == -1) { info->failMessage = "Map has lost an element"; goto out; } } /* now check the items are replaced in the correct order. * The new labels are guaranteed to be unique from the labels already * in the map. * After this action there should be just one item left, * the most recently used item from above - this is the * last item in the shuffled array. */ for (int i = 0; i < AddressMapper_MAX_ENTRIES - 1; i++) { /* add a new entry */ uint64_t newLabel = labels[i] - labelMin; AddressMapper_put(newLabel, getDummyAddress(), map); } /* verify that only most recently used item remains, as expected */ for (int i = 0; i < AddressMapper_MAX_ENTRIES; i++) { int index; index = AddressMapper_indexOf(labels[i], map); /* items < (AddressMapper_MAX_ENTRIES - 1) should have been replaced as least used */ if ((i < (AddressMapper_MAX_ENTRIES - 1)) && (index != -1)) { info->failMessage = "Element was not removed as expected"; goto out; } /* item == (AddressMapper_MAX_ENTRIES - 1) should not have been replaced */ if ((i == (AddressMapper_MAX_ENTRIES - 1)) && (index == -1)) { info->failMessage = "Unexpected item was lost"; goto out; } } info->pass = true; out: return 0; }
/* runTest_removeAndPut * * Tets the "remove" functionality of the address mapper is optimal by checking * that the address mapper replaces "removed" entries when new entries are added, * rather than entries that are still valid. * * 1. Fill the address map * 2. Remove a random selection of entries * 3. Add new entries to replace the previously removed entries * 4. Check that only the removed entries were replaced */ static int runTest_removeAndPut(struct AppState* state, struct AddressMapper* map, struct TestInfo* info) { /* the labels to remove - a maximum of 8 */ uint64_t removeLabels[8]; info->name = "Remove and put"; /* fill the address map */ for (unsigned int label = 1; label <= AddressMapper_MAX_ENTRIES; label++) { AddressMapper_put(label, getDummyAddress(), map); } /* remove a random number (between 1 and 8) of labels, at random */ unsigned int numToRemove = (rand() % 8) + 1; for (unsigned int i = 0; i < numToRemove; i++) { generateRandomLabel: removeLabels[i] = (rand() % AddressMapper_MAX_ENTRIES) + 1; /* check the label is unique */ for (unsigned int j = 0; j < i; j++) { if (removeLabels[j] == removeLabels[i]) { goto generateRandomLabel; } } int index; index = AddressMapper_indexOf(removeLabels[i], map); if (index == -1) { info->failMessage = "Could not find item which should have been " "present in map"; return 0; } int result; result = AddressMapper_remove(index, map); if (result != 0) { info->failMessage = "Could not remove item which should have been " "present in map"; return 0; } } /* put some new items in the map to replace the removed ones */ for (unsigned int i = 1; i <= numToRemove; i++) { AddressMapper_put(AddressMapper_MAX_ENTRIES + i, getDummyAddress(), map); } /* check that the map contents is as expected. * check that all of the original items are present apart from the ones * that were removed */ for (unsigned int label = 1; label <= AddressMapper_MAX_ENTRIES; label++) { /* find out if this item should have been removed */ bool wasRemoved = false; for (unsigned int i = 0; i < numToRemove; i++) { if (label == removeLabels[i]) { wasRemoved = true; } } int index; index = AddressMapper_indexOf(label, map); if ((wasRemoved == true) && (index != -1)) { info->failMessage = "Removed item still exists in the map"; return 0; } else if ((wasRemoved == false) && (index == -1)) { info->failMessage = "Non-removed item is missing from the map"; return 0; } } info->pass = true; return 0; }
/** * This is called as sendMessage() by the switch. * There is only one switch interface which sends all traffic. * message is aligned on the beginning of the switch header. */ static uint8_t incomingFromSwitch(struct Message* message, struct Interface* switchIf) { struct Context* context = switchIf->senderContext; struct Headers_SwitchHeader* switchHeader = (struct Headers_SwitchHeader*) message->bytes; Message_shift(message, -Headers_SwitchHeader_SIZE); // The label comes in reversed from the switch because the switch doesn't know that we aren't // another switch ready to parse more bits, bit reversing the label yields the source address. switchHeader->label_be = Bits_bitReverse64(switchHeader->label_be); if (Headers_getMessageType(switchHeader) == MessageType_CONTROL) { struct Control* ctrl = (struct Control*) (switchHeader + 1); if (ctrl->type_be == Control_ERROR_be) { if (memcmp(&ctrl->content.error.cause.label_be, &switchHeader->label_be, 8)) { Log_warn(context->logger, "Different label for cause than return packet, this shouldn't happen. " "Perhaps a packet was corrupted.\n"); return 0; } uint32_t errType_be = ctrl->content.error.errorType_be; if (errType_be == Endian_bigEndianToHost32(Error_MALFORMED_ADDRESS)) { Log_info(context->logger, "Got malformed-address error, removing route.\n"); RouterModule_brokenPath(switchHeader->label_be, context->routerModule); return 0; } Log_info1(context->logger, "Got error packet, error type: %d", Endian_bigEndianToHost32(errType_be)); } return 0; } uint8_t* herKey = extractPublicKey(message, switchHeader->label_be, context->logger); int herAddrIndex; if (herKey) { uint8_t herAddrStore[16]; AddressCalc_addressForPublicKey(herAddrStore, herKey); if (herAddrStore[0] != 0xFC) { Log_debug(context->logger, "Got message from peer whose address is not in fc00::/8 range.\n"); return 0; } herAddrIndex = AddressMapper_put(switchHeader->label_be, herAddrStore, &context->addrMap); } else { herAddrIndex = AddressMapper_indexOf(switchHeader->label_be, &context->addrMap); if (herAddrIndex == -1) { struct Node* n = RouterModule_getNode(switchHeader->label_be, context->routerModule); if (n) { herAddrIndex = AddressMapper_put(switchHeader->label_be, n->address.ip6.bytes, &context->addrMap); } else { #ifdef Log_DEBUG uint8_t switchAddr[20]; struct Address addr; addr.networkAddress_be = switchHeader->label_be; Address_printNetworkAddress(switchAddr, &addr); Log_debug1(context->logger, "Dropped traffic packet from unknown node. (%s)\n", &switchAddr); #endif return 0; } } } uint8_t* herAddr = context->addrMap.addresses[herAddrIndex]; // This is needed so that the priority and other information // from the switch header can be passed on properly. context->switchHeader = switchHeader; context->session = SessionManager_getSession(herAddr, herKey, context->sm); // This goes to incomingFromCryptoAuth() // then incomingFromRouter() then core() context->layer = OUTER_LAYER; context->session->receiveMessage(message, context->session); return 0; }