示例#1
0
static inline int encodeForm(struct EncodingScheme_Form* in, uint64_t* data, int bits)
{
    *data |= ((uint64_t)in->prefixLen & Bits_maxBits64(5)) << bits;
    bits += 5;

    *data |= ((uint64_t)in->bitCount & Bits_maxBits64(5)) << bits;
    bits += 5;

    *data |= ((uint64_t)in->prefix & Bits_maxBits64(in->prefixLen)) << bits;

    return 5 + 5 + in->prefixLen;
}
示例#2
0
/**
 * Decode a form from it's binary representation.
 * Can only use a maximum of 41 bits.
 *
 * @param out the output which will be populated with the encoding form data.
 * @param data the binary data in host order.
 * @return the number of bits of data which were consumed by the decoding.
 *         If the content is definitely not an encoding form, 0 is returned.
 */
static inline int decodeForm(struct EncodingScheme_Form* out, uint64_t d)
{
    out->prefixLen = d & Bits_maxBits64(5);
    d >>= 5;
    int bitCount = d & Bits_maxBits64(5);
    if (bitCount < 1) {
        return 0;
    }
    out->bitCount = bitCount;
    d >>= 5;
    out->prefix = d & Bits_maxBits64(out->prefixLen);
    return 5 + 5 + out->prefixLen;
}
示例#3
0
bool EncodingScheme_isSane(struct EncodingScheme* scheme)
{
    // Check for obviously insane encoding.
    if (scheme->count == 0) {
        // No encoding schemes
        return false;
    }

    if (scheme->count > 31) {
        // impossible, each form must have a different bitCount and bitCount
        // can only be expressed in 5 bits limiting it to 31 bits max and a form
        // using zero bits is not allowed so there are only 31 max possibilities.
        return false;
    }

    if (scheme->count == 1) {
        // Fixed width encoding, prefix is not allowed and bitcount must be non-zero
        if (scheme->forms[0].prefixLen != 0 || scheme->forms[0].prefix != 0) {
            // prefixLen must be 0
            return false;
        }
        if (scheme->forms[0].bitCount == 0 || scheme->forms[0].bitCount > 31) {
            // bitcount must be non-zero and can't overflow the number
            return false;
        }
        return true;
    }

    // Variable width encoding.
    for (int i = 0; i < scheme->count; i++) {
        struct EncodingScheme_Form* form = &scheme->forms[i];

        if (form->prefixLen == 0 || form->prefixLen > 31) {
            // Prefix must exist in order to distinguish between forms
            return false;
        }
        if (form->bitCount == 0 || form->bitCount > 31) {
            // Bitcount must be non-zero
            return false;
        }
        if (EncodingScheme_formSize(form) > 59) {
            // cannot be represented in the usable space in a label
            return false;
        }
        if (i > 0 && form->bitCount <= scheme->forms[i-1].bitCount) {
            // Forms must be in ascending order.
            return false;
        }
        for (int j = 0; j < scheme->count; j++) {
            // Forms must be distinguishable by their prefixes.
            if (j != i
                && (scheme->forms[j].prefix & Bits_maxBits64(form->prefixLen)) == form->prefix)
            {
                return false;
            }
        }
    }
    return true;
}
示例#4
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;
}
示例#5
0
static void numberCompressions_generic(
    uint32_t nInterfaces,
    uint32_t (*bitsUsedForLabel)(const uint64_t label),
    uint32_t (*bitsUsedForNumber)(const uint32_t number),
    uint64_t (*getCompressed)(const uint32_t number, const uint32_t bitsUsed),
    uint32_t (*getDecompressed)(const uint64_t label, const uint32_t bitsUsed),
    struct EncodingScheme* (* defineScheme)(struct Allocator* alloc) )
{

    uint8_t bitWidths[64] = { 0 };

    for (uint32_t i = 0; i < nInterfaces; ++i) {
        bitWidths[bitsUsedForNumber(i)] = 1;
    }

    for (uint32_t bits = 0; bits < 64; ++bits) {
        if (!bitWidths[bits]) {
            continue;
        }

        for (uint32_t i = 0; i < nInterfaces; ++i) {
            /* only check for greater-or-equal bit widths */
            if (bits < bitsUsedForNumber(i)) {
                continue;
            }

            uint64_t label = getCompressed(i, bits);

            if (1 == i) {
                Assert_true(1 == label);
                continue;
            }

            Assert_true(bits == bitsUsedForLabel(label));
            Assert_true(i == getDecompressed(label, bits));
        }
    }

    for (uint64_t label = 0; label < 0x10000u; ++label) {
        uint32_t bits = bitsUsedForLabel(label);
        Assert_true(1 == bitWidths[bits]);
        if (1 == (label & Bits_maxBits64(bits))) {
            //Assert_true(4 == bits);
            Assert_true(1 == getDecompressed(label, bits));
        } else {
            uint32_t i = getDecompressed(label, bits);
            Assert_true(i < nInterfaces);
        }
    }

    struct Allocator* alloc = MallocAllocator_new(20000);
    struct EncodingScheme* scheme = defineScheme(alloc);
    for (uint32_t i = 0; i < nInterfaces; i++) {
        for (int j = 0; j < scheme->count; j++) {
            int bits = scheme->forms[j].prefixLen + scheme->forms[j].bitCount;
            if ((int)bitsUsedForNumber(i) > bits) { continue; }
            uint64_t label = getCompressed(i, bits);
            for (int k = j; k < scheme->count; k++) {
                uint64_t labelB = EncodingScheme_convertLabel(scheme, label, k);
                if (1 == i && k != 0) {
                    Assert_true(1 == label);
                    Assert_true(EncodingScheme_convertLabel_INVALID == labelB);
                    continue;
                }
                int bitsB = bitsUsedForLabel(labelB);
                Assert_true(bitsB == scheme->forms[k].prefixLen + scheme->forms[k].bitCount
                    || (i == 1 && bitsB == 4));
                Assert_true(i == getDecompressed(labelB, bitsB));

                uint64_t labelC = EncodingScheme_convertLabel(scheme, labelB, j);
                Assert_true(labelC == label);
            }
        }
    }
    Allocator_free(alloc);
}