2023-12-04 09:33:30 +00:00
|
|
|
/*
|
|
|
|
* BIRD Internet Routing Daemon -- Semi-global index of nets
|
|
|
|
*
|
|
|
|
* (c) 2023 Maria Matejka <mq@jmq.cz>
|
|
|
|
*
|
|
|
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "lib/birdlib.h"
|
|
|
|
#include "lib/netindex_private.h"
|
|
|
|
|
|
|
|
#define NETINDEX_KEY(n) (n)->hash, (n)->addr
|
|
|
|
#define NETINDEX_NEXT(n) (n)->next
|
|
|
|
#define NETINDEX_EQ(h,n,i,o) ((h == i) && net_equal(n,o))
|
|
|
|
#define NETINDEX_FN(h,n) (h)
|
|
|
|
#define NETINDEX_ORDER 4 /* Initial */
|
|
|
|
|
|
|
|
#define NETINDEX_REHASH netindex_rehash
|
|
|
|
#define NETINDEX_PARAMS /8, *1, 2, 2, 4, 28
|
|
|
|
|
|
|
|
HASH_DEFINE_REHASH_FN(NETINDEX, struct netindex);
|
|
|
|
|
|
|
|
static void netindex_hash_cleanup(void *netindex_hash);
|
|
|
|
|
|
|
|
static struct netindex *
|
2024-04-01 18:04:14 +00:00
|
|
|
net_lock_revive_unlock(struct netindex_hash_private *hp, struct netindex *i)
|
2023-12-04 09:33:30 +00:00
|
|
|
{
|
2024-04-01 18:04:14 +00:00
|
|
|
if (!i)
|
2023-12-04 09:33:30 +00:00
|
|
|
return NULL;
|
|
|
|
|
2024-04-01 18:04:14 +00:00
|
|
|
lfuc_lock_revive(&i->uc);
|
|
|
|
lfuc_unlock(&i->uc, hp->cleanup_list, &hp->cleanup_event);
|
|
|
|
return i;
|
2023-12-04 09:33:30 +00:00
|
|
|
}
|
|
|
|
|
2024-05-30 20:59:08 +00:00
|
|
|
void
|
|
|
|
netindex_hash_consistency_check(struct netindex_hash_private *nh)
|
|
|
|
{
|
2024-06-05 15:47:32 +00:00
|
|
|
uint count = 0;
|
|
|
|
HASH_WALK(nh->hash, next, i)
|
2024-05-30 20:59:08 +00:00
|
|
|
{
|
2024-06-05 15:47:32 +00:00
|
|
|
ASSERT_DIE(count < nh->hash.count);
|
|
|
|
ASSERT_DIE(nh->block[i->index] == i);
|
|
|
|
count++;
|
2024-05-30 20:59:08 +00:00
|
|
|
}
|
2024-06-05 15:47:32 +00:00
|
|
|
HASH_WALK_END;
|
|
|
|
|
|
|
|
ASSERT_DIE(count == nh->hash.count);
|
2024-05-30 20:59:08 +00:00
|
|
|
}
|
|
|
|
|
2023-12-04 09:33:30 +00:00
|
|
|
/*
|
|
|
|
* Index initialization
|
|
|
|
*/
|
|
|
|
netindex_hash *
|
2024-06-05 15:47:32 +00:00
|
|
|
netindex_hash_new(pool *sp, event_list *cleanup_target, u8 type)
|
2023-12-04 09:33:30 +00:00
|
|
|
{
|
|
|
|
DOMAIN(attrs) dom = DOMAIN_NEW(attrs);
|
|
|
|
LOCK_DOMAIN(attrs, dom);
|
|
|
|
|
|
|
|
pool *p = rp_new(sp, dom.attrs, "Network index");
|
|
|
|
|
|
|
|
struct netindex_hash_private *nh = mb_allocz(p, sizeof *nh);
|
|
|
|
nh->lock = dom;
|
|
|
|
nh->pool = p;
|
2024-06-05 15:47:32 +00:00
|
|
|
nh->net_type = type;
|
|
|
|
|
|
|
|
nh->slab = net_addr_length[type] ? sl_new(nh->pool, sizeof (struct netindex) + net_addr_length[type]) : NULL;
|
|
|
|
|
|
|
|
HASH_INIT(nh->hash, nh->pool, NETINDEX_ORDER);
|
|
|
|
nh->block_size = 128;
|
|
|
|
nh->block = mb_allocz(nh->pool, nh->block_size * sizeof (struct netindex *));
|
|
|
|
|
|
|
|
hmap_init(&nh->id_map, nh->pool, 128);
|
2023-12-04 09:33:30 +00:00
|
|
|
|
2024-05-30 20:59:08 +00:00
|
|
|
nh->cleanup_list = cleanup_target;
|
2023-12-04 09:33:30 +00:00
|
|
|
nh->cleanup_event = (event) { .hook = netindex_hash_cleanup, nh };
|
|
|
|
|
|
|
|
UNLOCK_DOMAIN(attrs, dom);
|
|
|
|
return SKIP_BACK(netindex_hash, priv, nh);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
netindex_hash_cleanup(void *_nh)
|
|
|
|
{
|
2024-05-30 20:59:08 +00:00
|
|
|
struct netindex_hash_private *nh = _nh;
|
|
|
|
|
|
|
|
DOMAIN(attrs) dom = nh->lock;
|
|
|
|
LOCK_DOMAIN(attrs, dom);
|
|
|
|
|
|
|
|
EXPENSIVE_CHECK(netindex_hash_consistency_check(nh));
|
|
|
|
|
|
|
|
uint kept = 0;
|
2023-12-04 09:33:30 +00:00
|
|
|
|
2024-06-05 15:47:32 +00:00
|
|
|
for (uint i = 0; i < nh->block_size; i++)
|
|
|
|
{
|
|
|
|
struct netindex *ni = nh->block[i];
|
|
|
|
if (!ni)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ASSERT_DIE(i == ni->index);
|
|
|
|
|
|
|
|
if (lfuc_finished(&ni->uc))
|
2024-05-30 20:59:08 +00:00
|
|
|
{
|
2024-06-05 15:47:32 +00:00
|
|
|
HASH_REMOVE2(nh->hash, NETINDEX, nh->pool, ni);
|
|
|
|
hmap_clear(&nh->id_map, ni->index);
|
|
|
|
nh->block[i] = NULL;
|
|
|
|
|
|
|
|
if (nh->slab)
|
|
|
|
sl_free(ni);
|
2024-05-30 20:59:08 +00:00
|
|
|
else
|
2024-06-05 15:47:32 +00:00
|
|
|
mb_free(ni);
|
2024-05-30 20:59:08 +00:00
|
|
|
}
|
2024-06-05 15:47:32 +00:00
|
|
|
else
|
|
|
|
kept++;
|
|
|
|
}
|
2024-05-30 20:59:08 +00:00
|
|
|
|
|
|
|
EXPENSIVE_CHECK(netindex_hash_consistency_check(nh));
|
|
|
|
|
|
|
|
if (kept || !nh->deleted_event)
|
|
|
|
{
|
|
|
|
UNLOCK_DOMAIN(attrs, dom);
|
|
|
|
return;
|
2023-12-04 09:33:30 +00:00
|
|
|
}
|
|
|
|
|
2024-05-30 20:59:08 +00:00
|
|
|
ev_postpone(&nh->cleanup_event);
|
|
|
|
|
|
|
|
event *e = nh->deleted_event;
|
|
|
|
event_list *t = nh->deleted_target;
|
|
|
|
|
|
|
|
/* Check cleanliness */
|
2024-06-05 15:47:32 +00:00
|
|
|
HASH_WALK(nh->hash, next, i)
|
|
|
|
bug("Stray netindex in deleted hash");
|
|
|
|
HASH_WALK_END;
|
2024-05-30 20:59:08 +00:00
|
|
|
|
|
|
|
/* Pool free is enough to drop everything */
|
|
|
|
rp_free(nh->pool);
|
|
|
|
|
|
|
|
/* And only the lock remains */
|
|
|
|
UNLOCK_DOMAIN(attrs, dom);
|
|
|
|
DOMAIN_FREE(attrs, dom);
|
|
|
|
|
|
|
|
/* Notify the requestor */
|
|
|
|
ev_send(t, e);
|
|
|
|
}
|
2023-12-04 09:33:30 +00:00
|
|
|
|
2024-05-30 20:59:08 +00:00
|
|
|
void
|
|
|
|
netindex_hash_delete(netindex_hash *h, event *e, event_list *t)
|
|
|
|
{
|
|
|
|
NH_LOCK(h, hp);
|
|
|
|
|
|
|
|
EXPENSIVE_CHECK(netindex_hash_consistency_check(nh));
|
|
|
|
|
|
|
|
hp->deleted_event = e;
|
|
|
|
hp->deleted_target = t;
|
|
|
|
|
|
|
|
ev_send(hp->cleanup_list, &hp->cleanup_event);
|
|
|
|
}
|
|
|
|
|
2023-12-04 09:33:30 +00:00
|
|
|
/*
|
|
|
|
* Private index manipulation
|
|
|
|
*/
|
|
|
|
struct netindex *
|
|
|
|
net_find_index_fragile_chain(struct netindex_hash_private *hp, const net_addr *n)
|
|
|
|
{
|
2024-06-05 15:47:32 +00:00
|
|
|
ASSERT_DIE(n->type == hp->net_type);
|
2023-12-04 09:33:30 +00:00
|
|
|
u32 h = net_hash(n);
|
2024-06-05 15:47:32 +00:00
|
|
|
return HASH_FIND_CHAIN(hp->hash, NETINDEX, h, n);
|
2023-12-04 09:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct netindex *
|
|
|
|
net_find_index_fragile(struct netindex_hash_private *hp, const net_addr *n)
|
|
|
|
{
|
2024-06-05 15:47:32 +00:00
|
|
|
ASSERT_DIE(n->type == hp->net_type);
|
2023-12-04 09:33:30 +00:00
|
|
|
|
2024-06-05 15:47:32 +00:00
|
|
|
EXPENSIVE_CHECK(netindex_hash_consistency_check(hp));
|
2024-05-30 20:59:08 +00:00
|
|
|
|
2023-12-04 09:33:30 +00:00
|
|
|
u32 h = net_hash(n);
|
2024-06-05 15:47:32 +00:00
|
|
|
return HASH_FIND(hp->hash, NETINDEX, h, n);
|
2023-12-04 09:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct netindex *
|
2024-04-01 18:04:14 +00:00
|
|
|
net_find_index_locked(struct netindex_hash_private *hp, const net_addr *n)
|
2023-12-04 09:33:30 +00:00
|
|
|
{
|
2024-04-01 18:04:14 +00:00
|
|
|
return net_lock_revive_unlock(hp, net_find_index_fragile(hp, n));
|
2023-12-04 09:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct netindex *
|
2024-04-01 18:04:14 +00:00
|
|
|
net_new_index_locked(struct netindex_hash_private *hp, const net_addr *n)
|
2023-12-04 09:33:30 +00:00
|
|
|
{
|
2024-05-30 20:59:08 +00:00
|
|
|
ASSERT_DIE(!hp->deleted_event);
|
|
|
|
|
2024-06-05 15:47:32 +00:00
|
|
|
u32 i = hmap_first_zero(&hp->id_map);
|
|
|
|
hmap_set(&hp->id_map, i);
|
2023-12-04 09:33:30 +00:00
|
|
|
|
2024-06-05 15:47:32 +00:00
|
|
|
struct netindex *ni = hp->slab ?
|
|
|
|
sl_alloc(hp->slab) :
|
2023-12-04 09:33:30 +00:00
|
|
|
mb_alloc(hp->pool, n->length + sizeof *ni);
|
|
|
|
|
|
|
|
*ni = (struct netindex) {
|
|
|
|
.hash = net_hash(n),
|
|
|
|
.index = i,
|
|
|
|
};
|
|
|
|
net_copy(ni->addr, n);
|
|
|
|
|
2024-06-05 15:47:32 +00:00
|
|
|
HASH_INSERT2(hp->hash, NETINDEX, hp->pool, ni);
|
|
|
|
while (hp->block_size <= i)
|
2024-05-20 13:57:13 +00:00
|
|
|
{
|
2024-06-05 15:47:32 +00:00
|
|
|
u32 bs = hp->block_size;
|
2024-05-20 13:57:13 +00:00
|
|
|
struct netindex **nb = mb_alloc(hp->pool, bs * 2 * sizeof *nb);
|
2024-06-05 15:47:32 +00:00
|
|
|
memcpy(nb, hp->block, bs * sizeof *nb);
|
2024-05-20 13:57:13 +00:00
|
|
|
memset(&nb[bs], 0, bs * sizeof *nb);
|
2024-05-30 20:59:08 +00:00
|
|
|
|
2024-06-05 15:47:32 +00:00
|
|
|
mb_free(hp->block);
|
|
|
|
hp->block = nb;
|
2024-05-30 20:59:08 +00:00
|
|
|
|
2024-06-05 15:47:32 +00:00
|
|
|
hp->block_size *= 2;
|
2024-05-20 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2024-06-05 15:47:32 +00:00
|
|
|
hp->block[i] = ni;
|
2023-12-04 09:33:30 +00:00
|
|
|
|
2024-04-01 18:04:14 +00:00
|
|
|
return net_lock_revive_unlock(hp, ni);
|
2023-12-04 09:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Public entry points
|
|
|
|
*/
|
|
|
|
|
|
|
|
void net_lock_index(netindex_hash *h UNUSED, struct netindex *i)
|
|
|
|
{
|
|
|
|
// log(L_TRACE "Lock index %p", i);
|
2024-01-10 08:10:03 +00:00
|
|
|
lfuc_lock(&i->uc);
|
2023-12-04 09:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void net_unlock_index(netindex_hash *h, struct netindex *i)
|
|
|
|
{
|
|
|
|
// log(L_TRACE "Unlock index %p", i);
|
2024-01-10 08:10:03 +00:00
|
|
|
lfuc_unlock(&i->uc, h->cleanup_list, &h->cleanup_event);
|
2023-12-04 09:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct netindex *
|
2024-04-01 18:04:14 +00:00
|
|
|
net_find_index(netindex_hash *h, const net_addr *n)
|
2023-12-04 09:33:30 +00:00
|
|
|
{
|
|
|
|
NH_LOCK(h, hp);
|
2024-04-01 18:04:14 +00:00
|
|
|
return net_find_index_locked(hp, n);
|
2023-12-04 09:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct netindex *
|
2024-04-01 18:04:14 +00:00
|
|
|
net_get_index(netindex_hash *h, const net_addr *n)
|
2023-12-04 09:33:30 +00:00
|
|
|
{
|
|
|
|
NH_LOCK(h, hp);
|
|
|
|
return
|
2024-04-01 18:04:14 +00:00
|
|
|
net_find_index_locked(hp, n) ?:
|
|
|
|
net_new_index_locked(hp, n);
|
2023-12-04 09:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct netindex *
|
2024-06-05 15:47:32 +00:00
|
|
|
net_resolve_index(netindex_hash *h, u32 i)
|
2023-12-04 09:33:30 +00:00
|
|
|
{
|
|
|
|
NH_LOCK(h, hp);
|
2024-05-20 13:57:13 +00:00
|
|
|
|
2024-06-05 15:47:32 +00:00
|
|
|
struct netindex *ni = hp->block[i];
|
2024-05-20 13:57:13 +00:00
|
|
|
return net_lock_revive_unlock(hp, ni);
|
2023-12-04 09:33:30 +00:00
|
|
|
}
|