0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-08 12:18:42 +00:00

Lockless feed of a single net

This commit is contained in:
Maria Matejka 2024-04-23 18:50:22 +02:00
parent 93c3923462
commit de3bd705f8
3 changed files with 128 additions and 6 deletions

View File

@ -32,6 +32,10 @@
SAME_TYPE(&_ptr->i, _orig); \
_ptr; })
#define BIRD_ALIGN(s, a) (((s)+a-1)&~(a-1))
#define BIRD_SET_ALIGNED_POINTER(ptr, val) do { \
size_t _alignment = _Alignof(typeof(*ptr)); \
ptr = (typeof(ptr)) BIRD_ALIGN((uintptr_t)(val), _alignment); \
} while (0)
#define CPU_STRUCT_ALIGN (MAX_(_Alignof(void*), _Alignof(u64)))
#define BIRD_CPU_ALIGN(s) BIRD_ALIGN((s), CPU_STRUCT_ALIGN)

View File

@ -298,6 +298,14 @@ struct rt_pending_export {
const rte *new, *new_best, *old, *old_best;
};
struct rt_export_feed {
uint count_routes, count_exports;
struct netindex *ni;
rte *block;
u64 *exports;
char data[0];
};
struct rt_export_request {
struct rt_export_hook *hook; /* Table part of the export */
char *name;
@ -570,6 +578,8 @@ void rt_flowspec_link(rtable *src, rtable *dst);
void rt_flowspec_unlink(rtable *src, rtable *dst);
rtable *rt_setup(pool *, struct rtable_config *);
struct rt_export_feed *rt_net_feed(rtable *t, net_addr *a);
rte rt_net_best(rtable *t, net_addr *a);
int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
rte *rt_export_merged(struct channel *c, const net_addr *n, const rte ** feed, uint count, linpool *pool, int silent);
void rt_refresh_begin(struct rt_import_request *);

View File

@ -696,6 +696,23 @@ rte_feed_obtain(struct rtable_reading *tr, net *n, const rte **feed, uint count)
RT_READ_RETRY(tr);
}
static void
rte_feed_obtain_copy(struct rtable_reading *tr, net *n, rte *feed, uint count)
{
uint i = 0;
NET_READ_WALK_ROUTES(tr, n, ep, e)
{
if (i >= count)
RT_READ_RETRY(tr);
feed[i++] = e->rte;
ea_free_later(ea_ref(e->rte.attrs));
}
if (i != count)
RT_READ_RETRY(tr);
}
static rte *
export_filter(struct channel *c, rte *rt, int silent)
{
@ -2023,9 +2040,89 @@ rte_import(struct rt_import_request *req, const net_addr *n, rte *new, struct rt
}
}
/* Check rtable for best route to given net whether it would be exported do p */
int
rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter)
struct rt_export_feed *
rt_net_feed(rtable *t, net_addr *a)
{
RT_READ(t, tr);
const struct netindex *i = net_find_index(t->netindex, a);
net *n = i ? net_find(tr, i) : NULL;
if (!n)
return 0;
/* Get the feed itself. It may change under our hands tho. */
struct rt_pending_export *first = atomic_load_explicit(&n->first, memory_order_acquire);
struct rt_pending_export *last = atomic_load_explicit(&n->last, memory_order_acquire);
/* Count the elements */
uint rcnt = rte_feed_count(tr, n);
uint ecnt = 0;
uint ocnt = 0;
for (struct rt_pending_export *rpe = first; rpe;
rpe = atomic_load_explicit(&rpe->next, memory_order_acquire))
{
ecnt++;
if (rpe->old)
ocnt++;
}
struct rt_export_feed *feed = NULL;
if (rcnt || ocnt || ecnt)
{
uint size = sizeof *feed
+ (rcnt+ocnt) * sizeof *feed->block + _Alignof(typeof(*feed->block))
+ ecnt * sizeof *feed->exports + _Alignof(typeof(*feed->exports));
feed = tmp_alloc(size);
feed->ni = i;
feed->count_routes = rcnt+ocnt;
feed->count_exports = ecnt;
BIRD_SET_ALIGNED_POINTER(feed->block, feed->data);
BIRD_SET_ALIGNED_POINTER(feed->exports, &feed->block[rcnt+ocnt]);
/* Consistency check */
ASSERT_DIE(((void *) &feed->exports[ecnt]) <= ((void *) feed) + size);
if (rcnt)
rte_feed_obtain_copy(tr, n, feed->block, rcnt);
if (ecnt)
{
uint e = 0;
uint rpos = rcnt;
for (struct rt_pending_export *rpe = first; rpe;
rpe = atomic_load_explicit(&rpe->next, memory_order_acquire))
if (e >= ecnt)
RT_READ_RETRY(tr);
else
{
feed->exports[e++] = rpe->seq;
/* Copy also obsolete routes */
if (rpe->old)
{
ASSERT_DIE(rpos < rcnt + ocnt);
feed->block[rpos++] = *rpe->old;
ea_free_later(ea_ref(rpe->old->attrs));
}
}
ASSERT_DIE(e == ecnt);
}
}
/* Check that it indeed didn't change and the last export is still the same. */
if (last != atomic_load_explicit(&n->last, memory_order_acquire) ||
first != atomic_load_explicit(&n->first, memory_order_acquire))
RT_READ_RETRY(tr);
return feed;
}
rte
rt_net_best(rtable *t, net_addr *a)
{
rte rt = {};
@ -2033,12 +2130,23 @@ rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filte
const struct netindex *i = net_find_index(t->netindex, a);
net *n = i ? net_find(tr, i) : NULL;
if (!n)
return rt;
struct rte_storage *e = NET_READ_BEST_ROUTE(tr, n);
if (!e || !rte_is_valid(&e->rte))
return 0;
return rt;
ea_free_later(ea_ref(e->rte.attrs));
return RTE_COPY(e);
}
/* Check rtable for best route to given net whether it would be exported do p */
int
rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter)
{
rte rt = rt_net_best(t, a);
rt = RTE_COPY(e);
int v = c->proto->preexport ? c->proto->preexport(c, &rt) : 0;
if (v == RIC_PROCESS)
v = (f_run(filter, &rt, FF_SILENT) <= F_ACCEPT);