/* 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;
}
Beispiel #3
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;
}
Beispiel #6
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;
}