Example #1
0
/**
 * Splice a label and a label fragment together.
 *
 */
uint64_t LabelSplicer_splice(uint64_t goHere_be, uint64_t viaHere_be)
{
    uint64_t goHere = Endian_bigEndianToHost64(goHere_be);
    uint64_t viaHere = Endian_bigEndianToHost64(viaHere_be);
    uint64_t log2ViaHere = Bits_log2x64(viaHere);

    if (Bits_log2x64(goHere) + log2ViaHere > 61) {
        // Too big, can't splice.
        return UINT64_MAX;
    }

    return Endian_hostToBigEndian64(((goHere ^ 1) << log2ViaHere) ^ viaHere);
}
Example #2
0
uint64_t EncodingScheme_convertLabel(struct EncodingScheme* scheme,
                                     uint64_t routeLabel,
                                     int convertTo)
{
    int formNum = EncodingScheme_getFormNum(scheme, routeLabel);
    if (formNum == EncodingScheme_getFormNum_INVALID) {
        return EncodingScheme_convertLabel_INVALID;
    }

    struct EncodingScheme_Form* currentForm = &scheme->forms[formNum];

    if (scheme->count == 1
        || (routeLabel & Bits_maxBits64(currentForm->prefixLen + currentForm->bitCount)) == 1)
    {
        // fixed width encoding or it's a self label, this is easy
        switch (convertTo) {
            case 0:
            case EncodingScheme_convertLabel_convertTo_CANNONICAL: return routeLabel;
            default: return EncodingScheme_convertLabel_INVALID;
        }
    }

    routeLabel >>= currentForm->prefixLen;
    uint64_t director = routeLabel & Bits_maxBits64(currentForm->bitCount);
    routeLabel >>= currentForm->bitCount;

    // ACKTUNG: Magic afoot!
    // Conversions are necessary for two reasons.
    // #1 ensure 0001 always references interface 1, the self interface.
    // #2 reuse interface the binary encoding for interface 1 in other EncodingForms
    //    because interface 1 cannot be expressed as anything other than 0001
    if ((currentForm->prefix & Bits_maxBits64(currentForm->prefixLen)) == 1) {
        // Swap 0 and 1 if the prefix is 1, this makes 0001 alias to 1
        // because 0 can never show up in the wild, we reuse it for 1.
        Assert_true(director != 0);
        if (director == 1) { director--; }
    } else if (director) {
        // Reuse the number 1 for 2 and 2 for 3 etc. to gain an extra slot in all other encodings.
        director++;
    }

    if (convertTo == EncodingScheme_convertLabel_convertTo_CANNONICAL) {
        // Take into account the fact that if the destination form does not have a 1 prefix,
        // an extra number will be available.
        int minBitsA = Bits_log2x64(director) + 1;
        int minBitsB = Bits_log2x64(director-1) + 1;
        for (int i = 0; i < scheme->count; i++) {
            struct EncodingScheme_Form* form = &scheme->forms[i];
            int minBits = ((form->prefix & Bits_maxBits64(form->prefixLen)) == 1)
                ? minBitsA : minBitsB;
            if (form->bitCount >= minBits) {
                convertTo = i;
                break;
            }
        }
    }

    if (convertTo < 0 || convertTo >= scheme->count) {
        // convertTo value is insane
        return EncodingScheme_convertLabel_INVALID;
    }

    struct EncodingScheme_Form* nextForm = &scheme->forms[convertTo];

    if ((nextForm->prefix & Bits_maxBits64(nextForm->prefixLen)) == 1) {
        // Swap 1 and 0 back if necessary.
        if (director == 0) { director++; }
    } else if (director) {
        // Or move the numbers down by one.
        director--;
    }

    if ((Bits_log2x64(director) + 1) > nextForm->bitCount) {
        // won't fit in requested form
        return EncodingScheme_convertLabel_INVALID;
    }
    if (Bits_log2x64(routeLabel) + EncodingScheme_formSize(nextForm) > 59) {
        return EncodingScheme_convertLabel_INVALID;
    }

    routeLabel <<= nextForm->bitCount;
    routeLabel |= director;
    routeLabel <<= nextForm->prefixLen;
    routeLabel |= nextForm->prefix;

    if ((routeLabel & Bits_maxBits64(nextForm->prefixLen + nextForm->bitCount)) == 1) {
        // looks like a self-route
        return EncodingScheme_convertLabel_INVALID;
    }

    return routeLabel;
}
Example #3
0
static int getBadness(struct Address* badAddr, struct Address* selfAddr)
{
    uint64_t xor = Endian_bigEndianToHost64(badAddr->ip6.longs.one_be ^ selfAddr->ip6.longs.one_be);
    return Bits_log2x64(xor) + Bits_log2x64(badAddr->path);
}
Example #4
0
static void dumpTable_addEntries(struct Context* ctx,
                                 int i,
                                 int j,
                                 struct List_Item* last,
                                 String* txid)
{
    uint8_t path[20];
    uint8_t ip[40];
    String* pathStr = &(String) { .len = 19, .bytes = (char*)path };
    String* ipStr = &(String) { .len = 39, .bytes = (char*)ip };
    Object* link = Int_OBJ(0xFFFFFFFF);
    Object* version = Int_OBJ(Version_DEFAULT_ASSUMPTION);
    Dict entry = Dict_CONST(
        String_CONST("ip"), String_OBJ(ipStr), Dict_CONST(
        String_CONST("link"), link, Dict_CONST(
        String_CONST("path"), String_OBJ(pathStr), Dict_CONST(
        String_CONST("version"), version, NULL
    ))));

    struct List_Item next = { .next = last, .elem = Dict_OBJ(&entry) };

    if (i >= ctx->store->size || j >= ENTRIES_PER_PAGE) {
        if (i > j) {
            dumpTable_send(ctx, last, (j >= ENTRIES_PER_PAGE), txid);
            return;
        }

        Address_printIp(ip, ctx->store->selfAddress);
        strcpy((char*)path, "0000.0000.0000.0001");
        version->as.number = Version_CURRENT_PROTOCOL;
        dumpTable_send(ctx, &next, (j >= ENTRIES_PER_PAGE), txid);
        return;
    }

    struct Node* n = NodeStore_dumpTable(ctx->store, i);
    link->as.number = n->reach;
    version->as.number = n->version;
    Address_printIp(ip, &n->address);
    AddrTools_printPath(path, n->address.path);

    dumpTable_addEntries(ctx, i + 1, j + 1, &next, txid);
}

static void dumpTable(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
{
    struct Context* ctx = Identity_cast((struct Context*) vcontext);
    int64_t* page = Dict_getInt(args, String_CONST("page"));
    int i = (page) ? *page * ENTRIES_PER_PAGE : 0;
    dumpTable_addEntries(ctx, i, 0, NULL, txid);
}

static bool isOneHop(struct Node_Link* link)
{
    struct EncodingScheme* ps = link->parent->encodingScheme;
    int num = EncodingScheme_getFormNum(ps, link->cannonicalLabel);
    Assert_always(num > -1 && num < ps->count);
    return EncodingScheme_formSize(&ps->forms[num]) == Bits_log2x64(link->cannonicalLabel);
}

static void getLink(Dict* args, void* vcontext, String* txid, struct Allocator* alloc)
{
    struct Context* ctx = Identity_cast((struct Context*) vcontext);

    Dict* ret = Dict_new(alloc);
    Dict* result = Dict_new(alloc);
    Dict_putDict(ret, String_new("result", alloc), result, alloc);
    Dict_putString(ret, String_new("error", alloc), String_new("none", alloc), alloc);

    struct Node_Link* link;

    String* ipStr = Dict_getString(args, String_new("parent", alloc));
    int64_t* linkNum = Dict_getInt(args, String_new("linkNum", alloc));
    uint8_t ip[16];
    if (ipStr->len != 39 || AddrTools_parseIp(ip, ipStr->bytes)) {
        Dict_remove(ret, String_CONST("result"));
        Dict_putString(ret,
                       String_new("error", alloc),
                       String_new("Could not parse ip", alloc),
                       alloc);

    } else if ((link = NodeStore_getLink(ctx->store, ip, *linkNum))) {
        Dict_putInt(result,
                    String_new("inverseLinkEncodingFormNumber", alloc),
                    link->inverseLinkEncodingFormNumber,
                    alloc);
        Dict_putInt(result, String_new("linkState", alloc), link->linkState, alloc);

        Dict_putInt(result, String_new("isOneHop", alloc), isOneHop(link), alloc);

        String* cannonicalLabel = String_newBinary(NULL, 19, alloc);
        AddrTools_printPath(cannonicalLabel->bytes, link->cannonicalLabel);
        Dict_putString(result, String_new("cannonicalLabel", alloc), cannonicalLabel, alloc);

        String* parent = String_newBinary(NULL, 39, alloc);
        AddrTools_printIp(parent->bytes, link->parent->address.ip6.bytes);
        Dict_putString(result, String_new("parent", alloc), parent, alloc);

        String* child = String_newBinary(NULL, 39, alloc);
        AddrTools_printIp(child->bytes, link->child->address.ip6.bytes);
        Dict_putString(result, String_new("child", alloc), child, alloc);
    }

    Admin_sendMessage(ret, txid, ctx->admin);
}
static void getNode(Dict* args, void* vcontext, String* txid, struct Allocator* alloc)
{
    struct Context* ctx = Identity_cast((struct Context*) vcontext);

    Dict* ret = Dict_new(alloc);
    Dict* result = Dict_new(alloc);
    Dict_putDict(ret, String_new("result", alloc), result, alloc);
    Dict_putString(ret, String_new("error", alloc), String_new("none", alloc), alloc);

    // no ipStr specified --> return self-node
    struct Node_Two* node = ctx->store->selfNode;

    String* ipStr = Dict_getString(args, String_new("ip", alloc));
    uint8_t ip[16];
    while (ipStr) {
        if (ipStr->len != 39 || AddrTools_parseIp(ip, ipStr->bytes)) {
            Dict_remove(ret, String_CONST("result"));
            Dict_putString(ret,
                           String_new("error", alloc),
                           String_new("Could not parse ip", alloc),
                           alloc);

        } else if (!(node = NodeStore_getNode2(ctx->store, ip))) {
            // not found
        } else {
            break;
        }

        Admin_sendMessage(ret, txid, ctx->admin);
        return;
    }

    Dict_putInt(result, String_new("protocolVersion", alloc), node->version, alloc);

    String* key = Key_stringify(node->address.key, alloc);
    Dict_putString(result, String_new("key", alloc), key, alloc);

    uint32_t linkCount = NodeStore_linkCount(node);
    Dict_putInt(result, String_new("linkCount", alloc), linkCount, alloc);

    List* encScheme = EncodingScheme_asList(node->encodingScheme, alloc);
    Dict_putList(result, String_new("encodingScheme", alloc), encScheme, alloc);

    Admin_sendMessage(ret, txid, ctx->admin);
}

static void getRouteLabel(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
{
    struct Context* ctx = Identity_cast((struct Context*) vcontext);

    char* err = NULL;

    String* pathToParentS = Dict_getString(args, String_CONST("pathToParent"));
    uint64_t pathToParent;
    if (pathToParentS->len != 19) {
        err = "pathToParent incorrect length";
    } else if (AddrTools_parsePath(&pathToParent, pathToParentS->bytes)) {
        err = "Failed to parse pathToParent";
    }

    String* childAddressS = Dict_getString(args, String_CONST("childAddress"));
    uint8_t childAddress[16];
    if (childAddressS->len != 39) {
        err = "childAddress of incorrect length, must be a 39 character full ipv6 address";
    } else if (AddrTools_parseIp(childAddress, childAddressS->bytes)) {
        err = "Failed to parse childAddress";
    }

    uint64_t label = UINT64_MAX;
    if (!err) {
        label = NodeStore_getRouteLabel(ctx->store, pathToParent, childAddress);
        err = NodeStore_getRouteLabel_strerror(label);
    }
    Dict* response = Dict_new(requestAlloc);
    if (!err) {
        String* printedPath = String_newBinary(NULL, 19, requestAlloc);
        AddrTools_printPath(printedPath->bytes, label);
        Dict_putString(response, String_new("result", requestAlloc), printedPath, requestAlloc);
        Dict_putString(response,
                       String_new("error", requestAlloc),
                       String_new("none", requestAlloc),
                       requestAlloc);
        Admin_sendMessage(response, txid, ctx->admin);
    } else {
        Dict_putString(response,
                       String_new("error", requestAlloc),
                       String_new(err, requestAlloc),
                       requestAlloc);
        Admin_sendMessage(response, txid, ctx->admin);
    }
}

void NodeStore_admin_register(struct NodeStore* nodeStore,
                              struct Admin* admin,
                              struct Allocator* alloc)
{
    struct Context* ctx = Allocator_clone(alloc, (&(struct Context) {
        .admin = admin,
        .alloc = alloc,
        .store = nodeStore
    }));
    Identity_set(ctx);

    Admin_registerFunction("NodeStore_dumpTable", dumpTable, ctx, false,
        ((struct Admin_FunctionArg[]) {
            { .name = "page", .required = 1, .type = "Int" },
        }), admin);

    Admin_registerFunction("NodeStore_getLink", getLink, ctx, true,
        ((struct Admin_FunctionArg[]) {
            { .name = "parent", .required = 1, .type = "String" },
            { .name = "linkNum", .required = 1, .type = "Int" },
        }), admin);
Example #5
0
/**
 * Determine if the node at the end of the given label is one hop away.
 *
 * @param label_be the label to test.
 * @return true if the node is 1 hop away, false otherwise.
 */
bool LabelSplicer_isOneHop(uint64_t label_be)
{
    uint64_t label = Endian_bigEndianToHost64(label_be);
    return (int)NumberCompress_bitsUsedForLabel(label) == Bits_log2x64(label);
}