mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-08 12:18:42 +00:00
Index of different net_addr values for hashing and bit-marking
For many reasons, it's handy to assign a contiguous range of integers to known net_addr values. This is a data structure keeping this mapping.
This commit is contained in:
parent
6c4be8d1d3
commit
54d5e36ec0
@ -1,4 +1,4 @@
|
||||
src := a-path.c a-set.c bitmap.c bitops.c blake2s.c blake2b.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c rcu.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
|
||||
src := a-path.c a-set.c bitmap.c bitops.c blake2s.c blake2b.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
|
||||
|
@ -31,10 +31,15 @@
|
||||
(v) = (typeof(v)){ }; \
|
||||
})
|
||||
|
||||
#define HASH_FIND(v,id,key...) \
|
||||
#define HASH_FIND_CHAIN(v,id,key...) \
|
||||
({ \
|
||||
u32 _h = HASH_FN(v, id, key); \
|
||||
HASH_TYPE(v) *_n = (v).data[_h]; \
|
||||
(v).data[_h]; \
|
||||
})
|
||||
|
||||
#define HASH_FIND(v,id,key...) \
|
||||
({ \
|
||||
HASH_TYPE(v) *_n = HASH_FIND_CHAIN(v, id, key); \
|
||||
while (_n && !HASH_EQ(v, id, id##_KEY(_n), key)) \
|
||||
_n = id##_NEXT(_n); \
|
||||
_n; \
|
||||
|
222
lib/netindex.c
Normal file
222
lib/netindex.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Handle for persistent or semipersistent usage
|
||||
*/
|
||||
struct netindex_handle {
|
||||
resource r;
|
||||
struct netindex *index;
|
||||
netindex_hash *h;
|
||||
};
|
||||
|
||||
static void
|
||||
net_unlock_index_persistent(resource *r)
|
||||
{
|
||||
struct netindex_handle *nh = SKIP_BACK(struct netindex_handle, r, r);
|
||||
net_unlock_index(nh->h, nh->index);
|
||||
}
|
||||
|
||||
static void
|
||||
netindex_handle_dump(resource *r, unsigned indent UNUSED)
|
||||
{
|
||||
struct netindex_handle *nh = SKIP_BACK(struct netindex_handle, r, r);
|
||||
debug("index=%u, net=%N", nh->index->index, nh->index->addr);
|
||||
}
|
||||
|
||||
static struct resclass netindex_handle_class = {
|
||||
.name = "Netindex handle",
|
||||
.size = sizeof(struct netindex_handle),
|
||||
.free = net_unlock_index_persistent,
|
||||
.dump = netindex_handle_dump,
|
||||
};
|
||||
|
||||
static struct netindex *
|
||||
net_lock_index_persistent(struct netindex_hash_private *hp, struct netindex *ni, pool *p)
|
||||
{
|
||||
if (!ni)
|
||||
return NULL;
|
||||
|
||||
struct netindex_handle *nh = ralloc(p, &netindex_handle_class);
|
||||
// log(L_TRACE "Revive index %p", ni);
|
||||
lfuc_lock_revive(&ni->uc);
|
||||
nh->index = ni;
|
||||
nh->h = SKIP_BACK(netindex_hash, priv, hp);
|
||||
return ni;
|
||||
}
|
||||
|
||||
/*
|
||||
* Index initialization
|
||||
*/
|
||||
netindex_hash *
|
||||
netindex_hash_new(pool *sp)
|
||||
{
|
||||
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;
|
||||
|
||||
nh->cleanup_list = &global_event_list;
|
||||
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)
|
||||
{
|
||||
NH_LOCK((netindex_hash *) _nh, nh);
|
||||
|
||||
for (uint t = 0; t < NET_MAX; t++)
|
||||
{
|
||||
if (!nh->net[t].hash.data)
|
||||
continue;
|
||||
|
||||
HASH_WALK_FILTER(nh->net[t].hash, next, i, ii)
|
||||
if (lfuc_finished(&i->uc))
|
||||
{
|
||||
HASH_DO_REMOVE(nh->net[t].hash, NETINDEX, ii);
|
||||
hmap_clear(&nh->net[t].id_map, i->index);
|
||||
if (nh->net[t].slab)
|
||||
sl_free(i);
|
||||
else
|
||||
mb_free(i);
|
||||
}
|
||||
HASH_WALK_DELSAFE_END;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
netindex_hash_init(struct netindex_hash_private *hp, u8 type)
|
||||
{
|
||||
ASSERT_DIE(hp->net[type].block == NULL);
|
||||
|
||||
hp->net[type].slab = net_addr_length[type] ? sl_new(hp->pool, sizeof (struct netindex) + net_addr_length[type]) : NULL;
|
||||
HASH_INIT(hp->net[type].hash, hp->pool, NETINDEX_ORDER);
|
||||
hp->net[type].block_size = 128;
|
||||
hp->net[type].block = mb_allocz(hp->pool, hp->net[type].block_size * sizeof (struct netindex *));
|
||||
hmap_init(&hp->net[type].id_map, hp->pool, 128);
|
||||
};
|
||||
|
||||
/*
|
||||
* Private index manipulation
|
||||
*/
|
||||
struct netindex *
|
||||
net_find_index_fragile_chain(struct netindex_hash_private *hp, const net_addr *n)
|
||||
{
|
||||
ASSERT_DIE(n->type < NET_MAX);
|
||||
if (!hp->net[n->type].block)
|
||||
return NULL;
|
||||
|
||||
u32 h = net_hash(n);
|
||||
return HASH_FIND_CHAIN(hp->net[n->type].hash, NETINDEX, h, n);
|
||||
}
|
||||
|
||||
struct netindex *
|
||||
net_find_index_fragile(struct netindex_hash_private *hp, const net_addr *n)
|
||||
{
|
||||
ASSERT_DIE(n->type < NET_MAX);
|
||||
if (!hp->net[n->type].block)
|
||||
return NULL;
|
||||
|
||||
u32 h = net_hash(n);
|
||||
return HASH_FIND(hp->net[n->type].hash, NETINDEX, h, n);
|
||||
}
|
||||
|
||||
static struct netindex *
|
||||
net_find_index_locked(struct netindex_hash_private *hp, const net_addr *n, pool *p)
|
||||
{
|
||||
struct netindex *ni = net_find_index_fragile(hp, n);
|
||||
return ni ? net_lock_index_persistent(hp, ni, p) : NULL;
|
||||
}
|
||||
|
||||
static struct netindex *
|
||||
net_new_index_locked(struct netindex_hash_private *hp, const net_addr *n, pool *p)
|
||||
{
|
||||
if (!hp->net[n->type].block)
|
||||
netindex_hash_init(hp, n->type);
|
||||
|
||||
u32 i = hmap_first_zero(&hp->net[n->type].id_map);
|
||||
hmap_set(&hp->net[n->type].id_map, i);
|
||||
|
||||
struct netindex *ni = hp->net[n->type].slab ?
|
||||
sl_alloc(hp->net[n->type].slab) :
|
||||
mb_alloc(hp->pool, n->length + sizeof *ni);
|
||||
|
||||
*ni = (struct netindex) {
|
||||
.hash = net_hash(n),
|
||||
.index = i,
|
||||
};
|
||||
net_copy(ni->addr, n);
|
||||
|
||||
HASH_INSERT2(hp->net[n->type].hash, NETINDEX, hp->pool, ni);
|
||||
|
||||
return net_lock_index_persistent(hp, ni, p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Public entry points
|
||||
*/
|
||||
|
||||
void net_lock_index(netindex_hash *h UNUSED, struct netindex *i)
|
||||
{
|
||||
// log(L_TRACE "Lock index %p", i);
|
||||
return lfuc_lock(&i->uc);
|
||||
}
|
||||
|
||||
void net_unlock_index(netindex_hash *h, struct netindex *i)
|
||||
{
|
||||
// log(L_TRACE "Unlock index %p", i);
|
||||
return lfuc_unlock(&i->uc, h->cleanup_list, &h->cleanup_event);
|
||||
}
|
||||
|
||||
struct netindex *
|
||||
net_find_index_persistent(netindex_hash *h, const net_addr *n, pool *p)
|
||||
{
|
||||
NH_LOCK(h, hp);
|
||||
return net_find_index_locked(hp, n, p);
|
||||
}
|
||||
|
||||
struct netindex *
|
||||
net_get_index_persistent(netindex_hash *h, const net_addr *n, pool *p)
|
||||
{
|
||||
NH_LOCK(h, hp);
|
||||
return
|
||||
net_find_index_locked(hp, n, p) ?:
|
||||
net_new_index_locked(hp, n, p);
|
||||
}
|
||||
|
||||
struct netindex *
|
||||
net_resolve_index_persistent(netindex_hash *h, u8 net_type, u32 i, pool *p)
|
||||
{
|
||||
NH_LOCK(h, hp);
|
||||
return net_lock_index_persistent(hp, hp->net[net_type].block_size > i ? hp->net[net_type].block[i] : NULL, p);
|
||||
}
|
55
lib/netindex.h
Normal file
55
lib/netindex.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_LIB_NETINDEX_H_
|
||||
#define _BIRD_LIB_NETINDEX_H_
|
||||
|
||||
#include "lib/bitmap.h"
|
||||
#include "lib/hash.h"
|
||||
#include "lib/lockfree.h"
|
||||
#include "lib/net.h"
|
||||
#include "lib/resource.h"
|
||||
|
||||
/* Index object */
|
||||
struct netindex {
|
||||
struct netindex *next; /* Next in hash chain */
|
||||
u32 hash; /* Cached hash value */
|
||||
u32 index; /* Assigned index */
|
||||
struct lfuc uc; /* Atomic usecount */
|
||||
net_addr addr[0]; /* The net itself (one) */
|
||||
};
|
||||
|
||||
/* Index hash: data structure completely opaque, use handlers */
|
||||
typedef union netindex_hash netindex_hash;
|
||||
|
||||
/* Initialization */
|
||||
netindex_hash *netindex_hash_new(pool *);
|
||||
|
||||
/* Find/get/resolve index and allocate its usecount to the given pool */
|
||||
struct netindex *net_find_index_persistent(netindex_hash *, const net_addr *, pool *);
|
||||
struct netindex *net_get_index_persistent(netindex_hash *, const net_addr *, pool *);
|
||||
struct netindex *net_resolve_index_persistent(netindex_hash *, u8, u32, pool *);
|
||||
|
||||
/* Find/get/resolve index; pointer valid until end of task */
|
||||
static inline struct netindex *net_find_index(netindex_hash *h, const net_addr *n)
|
||||
{ return net_find_index_persistent(h, n, tmp_res.pool); }
|
||||
static inline struct netindex *net_get_index(netindex_hash *h, const net_addr *n)
|
||||
{ return net_get_index_persistent(h, n, tmp_res.pool); }
|
||||
static inline struct netindex *net_resolve_index(netindex_hash *h, u8 net_type, u32 index)
|
||||
{ return net_resolve_index_persistent(h, net_type, index, tmp_res.pool); }
|
||||
|
||||
/* Update use-count without allocating a handle. Take same care
|
||||
* to ensure that your locks and unlocks are always balanced. */
|
||||
void net_lock_index(netindex_hash *h, struct netindex *i);
|
||||
void net_unlock_index(netindex_hash *h, struct netindex *i);
|
||||
|
||||
/* Retrieve the index from its addr pointer */
|
||||
#define NET_TO_INDEX(a) \
|
||||
SKIP_BACK(struct netindex, addr, TYPE_CAST(net_addr *, net_addr (*)[0], a))
|
||||
|
||||
#endif //_BIRD_LIB_NETINDEX_H_
|
47
lib/netindex_private.h
Normal file
47
lib/netindex_private.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_LIB_NETINDEX_PRIVATE_H_
|
||||
#define _BIRD_LIB_NETINDEX_PRIVATE_H_
|
||||
|
||||
#include "lib/netindex.h"
|
||||
|
||||
#define NETINDEX_HASH_PUBLIC \
|
||||
DOMAIN(attrs) lock; /* Assigned lock */ \
|
||||
event_list *cleanup_list; /* Cleanup event list */ \
|
||||
event cleanup_event; /* Cleanup event */ \
|
||||
|
||||
struct netindex_hash_private {
|
||||
struct { NETINDEX_HASH_PUBLIC; };
|
||||
struct netindex_hash_private **locked_at;
|
||||
pool *pool;
|
||||
struct {
|
||||
slab *slab;
|
||||
HASH(struct netindex) hash;
|
||||
uint block_size;
|
||||
struct netindex **block;
|
||||
struct hmap id_map;
|
||||
} net[NET_MAX];
|
||||
};
|
||||
|
||||
typedef union netindex_hash {
|
||||
struct { NETINDEX_HASH_PUBLIC; };
|
||||
struct netindex_hash_private priv;
|
||||
} netindex_hash;
|
||||
|
||||
LOBJ_UNLOCK_CLEANUP(netindex_hash, attrs);
|
||||
#define NH_LOCK(h, hp) LOBJ_LOCK(h, hp, netindex_hash, attrs)
|
||||
|
||||
/* Find indices in a locked context with no usecounting */
|
||||
struct netindex *net_find_index_fragile(struct netindex_hash_private *hp, const net_addr *n);
|
||||
|
||||
/* The same but instead of returning the exact match,
|
||||
* return the first item in hash chain */
|
||||
struct netindex *net_find_index_fragile_chain(struct netindex_hash_private *hp, const net_addr *n);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user