From: Jan Moskyto Matejka Date: Mon, 25 Apr 2016 08:35:08 +0000 (+0200) Subject: ID Map allows max and min limits X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=160239d523e0dcb123036e280673995e295a14bb;p=thirdparty%2Fbird.git ID Map allows max and min limits --- diff --git a/lib/idm.c b/lib/idm.c index 16d0e855e..2f0fa2083 100644 --- a/lib/idm.c +++ b/lib/idm.c @@ -29,35 +29,131 @@ idm_init(struct idm *m, pool *p, uint size) static inline int u32_cto(uint x) { return ffs(~x) - 1; } +static void +idm_grow(struct idm *m, u32 size) +{ + m->data = mb_realloc(m->data, size * sizeof(u32)); + memset(m->data + m->size, 0, (size - m->size) * sizeof(u32)); + m->size = size; +} + +int +idm_alloc_given(struct idm *m, u32 val) +{ + uint i = val / 32, j = val % 32; + if (i >= m->size) + idm_grow(m, i+1); + + if (m->data[i] & (1 << j)) + return 0; + + m->data[i] |= (1 << j); + m->used--; + return 1; +} + +/** + * Allocate a new ID + * @m: the ID Map to be used + * @min: minimal value returned + * @max: maximal value returned + * + * Returns the allocated value. Returns 0 if allocation is impossible. + */ u32 -idm_alloc(struct idm *m) +idm_alloc(struct idm *m, u32 min, u32 max) { + uint mini = min / 32, maxi = max / 32; + + u32 minmask = ~((1 << (min % 32)) - 1); + u32 maxmask = ((1ULL << ((max+1) % 32)) - 1); + + u32 mask; + uint i, j; - for (i = m->pos; i < m->size; i++) - if (m->data[i] != 0xffffffff) + /* Not even allocated data array at mini. */ + if (mini >= m->size) + { + i = mini; + idm_grow(m, mini+1); + mask = minmask; + goto found; + } + + /* Only one u32 contains all possible values. */ + if (mini == maxi) + { + mask = (minmask & maxmask); + if ((m->data[mini] & mask) == (mask)) + return 0; + i = mini; + goto found; + } + + /* + * a) + * m->pos + * v + * u32's in m->data: .............................. + * ^ ^ + * mini maxi + * + * b) + * m->pos + * v + * u32's in m->data: .............................. + * ^ ^ + * mini maxi + * + * c) + * m->pos + * v + * u32's in m->data: .............................. + * ^ ^ + * mini maxi + * + */ + + /* Beginning at: mini+1 (a) or m->pos (b,c) m->pos + * End at last before: MIN(maxi, m->size) ... this skips loop at c) + */ + for (i = MAX(mini+1, m->pos); i < MIN(maxi, m->size); i++) + if (m->data[i] != (mask = 0xffffffff)) goto found; - /* If we are at least 7/8 full, expand */ - if (m->used > (m->size * 28)) + /* if maxi points to an allocated value */ + if (maxi < m->size) + if ((m->data[i = maxi] & maxmask) != (mask = maxmask)) + goto found; + + /* If we have just hit m->size and we are at least 7/8 full, expand */ + if ((i == m->size) && (m->used > (m->size * 28))) { - m->size *= 2; - m->data = mb_realloc(m->data, m->size * sizeof(u32)); - memset(m->data + i, 0, (m->size - i) * sizeof(u32)); + idm_grow(m, m->size * 2); + mask = 0xffffffff; goto found; } - for (i = 0; i < m->pos; i++) - if (m->data[i] != 0xffffffff) + /* Trying i == mini (skipped before) */ + if ((m->data[i = mini] & minmask) != (mask = minmask)) + goto found; + + /* Beginning at mini+1 in all cases + * End before m->pos (a,b) or maxi (c), whatever comes earlier. This skips loop at a) */ + + for (i = mini+1; i < MIN(maxi, m->pos); i++) + if (m->data[i] != (mask = 0xffffffff)) goto found; - ASSERT(0); + return 0; found: - ASSERT(i < 0x8000000); + if (i >= 0x8000000) // Too large value + return 0; m->pos = i; - j = u32_cto(m->data[i]); + j = u32_cto(m->data[i] | ~mask); m->data[i] |= (1 << j); m->used++; @@ -74,3 +170,100 @@ idm_free(struct idm *m, u32 id) m->data[i] &= ~(1 << j); m->used--; } + +#ifdef TEST + +#include +#include + +#include "sysdep/unix/unix.h" + +struct idm m; + +static void idm_dump(struct idm *m) +{ + int w = 0; + char b[90]; + for (int i=0; isize; i++) { + u32 val = m->data[i]; + while (val) { + u32 n = ffs(val)-1; + w += sprintf(b + w, "%u,", i*32 + n); + if (w < 72) { + b[w++] = ' '; + } + else { + b[w++] = '\n'; + b[w] = 0; + debug(b); + w = 0; + } + val &= ~(1U<proto = p; src->private_id = id; - src->global_id = idm_alloc(&src_ids); + src->global_id = idm_alloc(&src_ids, 1, 0xffffffff); src->uc = 0; + ASSERT(src->global_id); /* Couldn't allocate new ID */ + HASH_INSERT2(src_hash, RSH, rta_pool, src); return src; diff --git a/nest/rt-fib.c b/nest/rt-fib.c index 558b3ace1..f81506bc6 100644 --- a/nest/rt-fib.c +++ b/nest/rt-fib.c @@ -38,6 +38,7 @@ #include "nest/bird.h" #include "nest/route.h" +#include "lib/idm.h" #include "lib/string.h" #define HASH_DEF_ORDER 10 diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 9d0a93c7b..41d230075 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -548,7 +548,10 @@ ort_to_lsaid(struct ospf_proto *p, ort *nf) if (ospf_is_v3(p)) { if (!nf->lsa_id) - nf->lsa_id = idm_alloc(&p->idm); + nf->lsa_id = idm_alloc(&p->idm, 0, 0xffffffff); + + if (!nf->lsa_id) + log(L_FATAL "%s: LSA ID allocation failed, using 0 as fallback.", p->p.name); return nf->lsa_id; }