mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2025-01-11 03:21:53 +00:00
Filter slots a bit more encapsulated.
This commit is contained in:
parent
368e0ef15b
commit
370958afc2
@ -53,57 +53,36 @@
|
|||||||
|
|
||||||
void (*bt_assert_hook)(int result, struct f_inst *assert);
|
void (*bt_assert_hook)(int result, struct f_inst *assert);
|
||||||
|
|
||||||
struct filter_roa_notifier {
|
struct filter_roa_reloader {
|
||||||
resource r;
|
node n;
|
||||||
struct listener L;
|
struct listener *L;
|
||||||
struct rtable *roa_table;
|
struct rtable *roa_table;
|
||||||
struct filter_slot *slot;
|
struct filter_slot *slot;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void filter_roa_notifier_hook(struct listener *L, void *data UNUSED) {
|
static void filter_roa_reloader_notify(void *self, const void *data UNUSED) {
|
||||||
struct filter_roa_notifier *frn = SKIP_BACK(struct filter_roa_notifier, L, L);
|
struct filter_roa_reloader *frr = self;
|
||||||
frn->slot->reloader(frn->slot);
|
frr->slot->reloader(frr->slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void filter_roa_notifier_unsubscribe(struct listener *L) {
|
static void filter_roa_reloader_unsubscribe(void *self) {
|
||||||
struct filter_roa_notifier *frn = SKIP_BACK(struct filter_roa_notifier, L, L);
|
struct filter_roa_reloader *frr = self;
|
||||||
rfree(frn);
|
rem_node(&(frr->n));
|
||||||
|
mb_free(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void filter_roa_notifier_free(resource *r) {
|
static void filter_roa_reloader_subscribe(struct rtable *roa_table, struct filter_slot *slot, const net_addr *n UNUSED, u32 as UNUSED) {
|
||||||
struct filter_roa_notifier *frn = (void *) r;
|
struct filter_roa_reloader *oldfrr;
|
||||||
unsubscribe(&(frn->L));
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct resclass filter_roa_notifier_class = {
|
|
||||||
.name = "Filter ROA Notifier",
|
|
||||||
.size = sizeof(struct filter_roa_notifier),
|
|
||||||
.free = filter_roa_notifier_free,
|
|
||||||
.dump = NULL,
|
|
||||||
.lookup = NULL,
|
|
||||||
.memsize = NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void filter_roa_notifier_subscribe(struct rtable *roa_table, struct filter_slot *slot, const net_addr *n UNUSED, u32 as UNUSED) {
|
|
||||||
struct listener *oldL;
|
|
||||||
node *x;
|
node *x;
|
||||||
WALK_LIST2(oldL, x, slot->notifiers, receiver_node)
|
WALK_LIST2(oldfrr, x, slot->notifiers, n)
|
||||||
if (oldL->hook == filter_roa_notifier_hook)
|
if (oldfrr->roa_table == roa_table)
|
||||||
{
|
|
||||||
struct filter_roa_notifier *old = SKIP_BACK(struct filter_roa_notifier, L, oldL);
|
|
||||||
if ((old->roa_table == roa_table) && (old->slot == slot))
|
|
||||||
return; /* Old notifier found for the same event. */
|
return; /* Old notifier found for the same event. */
|
||||||
}
|
|
||||||
|
|
||||||
struct filter_roa_notifier *frn = ralloc(slot->p, &filter_roa_notifier_class);
|
struct filter_roa_reloader *frr = mb_allocz(slot->p, sizeof(struct filter_roa_reloader));
|
||||||
frn->L = (struct listener) {
|
frr->roa_table = roa_table;
|
||||||
.hook = filter_roa_notifier_hook,
|
frr->slot = slot;
|
||||||
.unsub = filter_roa_notifier_unsubscribe,
|
add_tail(&(slot->notifiers), &(frr->n));
|
||||||
};
|
frr->L = subscribe(slot->p, &(roa_table->listeners), filter_roa_reloader_notify, filter_roa_reloader_unsubscribe, frr);
|
||||||
frn->roa_table = roa_table;
|
|
||||||
frn->slot = slot;
|
|
||||||
|
|
||||||
subscribe(&(frn->L), &(roa_table->listeners), &(slot->notifiers));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct adata undef_adata; /* adata of length 0 used for undefined */
|
static struct adata undef_adata; /* adata of length 0 used for undefined */
|
||||||
@ -1612,7 +1591,7 @@ interpret(struct f_inst *what)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (f_slot)
|
if (f_slot)
|
||||||
filter_roa_notifier_subscribe(table, f_slot, v1.val.net, as);
|
filter_roa_reloader_subscribe(table, f_slot, v1.val.net, as);
|
||||||
|
|
||||||
res.val.i = net_roa_check(table, v1.val.net, as);
|
res.val.i = net_roa_check(table, v1.val.net, as);
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,21 @@ struct filter_slot {
|
|||||||
list notifiers;
|
list notifiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline void filter_slot_init(struct filter_slot *fs, pool *pp, struct filter *filter, void (*reloader)(struct filter_slot *))
|
||||||
|
{
|
||||||
|
fs->filter = filter;
|
||||||
|
fs->reloader = reloader;
|
||||||
|
fs->p = rp_new(pp, "filter slot pool");
|
||||||
|
init_list(&(fs->notifiers));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void filter_slot_deactivate(struct filter_slot *fs)
|
||||||
|
{
|
||||||
|
rfree(fs->p);
|
||||||
|
ASSERT(EMPTY_LIST(fs->notifiers));
|
||||||
|
fs->p = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct f_inst *f_new_inst(enum f_instruction_code fi_code);
|
struct f_inst *f_new_inst(enum f_instruction_code fi_code);
|
||||||
struct f_inst *f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da);
|
struct f_inst *f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da);
|
||||||
struct f_inst *f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa);
|
struct f_inst *f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
src := a-path.c a-set.c cli.c cmds.c iface.c locks.c neighbor.c password.c proto.c rt-attr.c rt-dev.c rt-fib.c rt-show.c rt-table.c
|
src := a-path.c a-set.c cli.c cmds.c iface.c locks.c neighbor.c notify.c password.c proto.c rt-attr.c rt-dev.c rt-fib.c rt-show.c rt-table.c
|
||||||
obj := $(src-o-files)
|
obj := $(src-o-files)
|
||||||
$(all-daemon)
|
$(all-daemon)
|
||||||
$(cf-local)
|
$(cf-local)
|
||||||
|
72
nest/notify.c
Normal file
72
nest/notify.c
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* BIRD Internet Routing Daemon -- Notificators and Listeners
|
||||||
|
*
|
||||||
|
* (c) 2019 Maria Matejka <mq@jmq.cz>
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nest/bird.h"
|
||||||
|
#include "lib/resource.h"
|
||||||
|
#include "nest/notify.h"
|
||||||
|
|
||||||
|
struct listener {
|
||||||
|
resource r;
|
||||||
|
node n;
|
||||||
|
|
||||||
|
void (*notify)(void *self, const void *data);
|
||||||
|
void (*unsubscribe)(void *self);
|
||||||
|
|
||||||
|
void *self;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
listener_unsubscribe(resource *r)
|
||||||
|
{
|
||||||
|
struct listener *L = (struct listener *) r;
|
||||||
|
rem_node(&(L->n));
|
||||||
|
CALL(L->unsubscribe, L->self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct resclass listener_class = {
|
||||||
|
.name = "Listener",
|
||||||
|
.size = sizeof(struct listener),
|
||||||
|
.free = listener_unsubscribe,
|
||||||
|
.dump = NULL,
|
||||||
|
.lookup = NULL,
|
||||||
|
.memsize = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct listener *
|
||||||
|
subscribe(pool *p, list *sender, void (*notify)(void *, const void *), void (*unsubscribe)(void *), void *self)
|
||||||
|
{
|
||||||
|
struct listener *L = ralloc(p, &listener_class);
|
||||||
|
L->notify = notify;
|
||||||
|
L->unsubscribe = unsubscribe;
|
||||||
|
L->self = self;
|
||||||
|
|
||||||
|
add_tail(sender, &(L->n));
|
||||||
|
return L;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unsubscribe(struct listener *L)
|
||||||
|
{
|
||||||
|
L->unsubscribe = NULL;
|
||||||
|
rfree(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unsubscribe_all(list *sender)
|
||||||
|
{
|
||||||
|
struct listener *L;
|
||||||
|
node *x, *y;
|
||||||
|
WALK_LIST2_DELSAFE(L, x, y, *sender, n)
|
||||||
|
rfree(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
void notify(list *sender, const void *data)
|
||||||
|
{
|
||||||
|
struct listener *L;
|
||||||
|
node *x, *y;
|
||||||
|
WALK_LIST2_DELSAFE(L, x, y, *sender, n)
|
||||||
|
L->notify(L->self, data);
|
||||||
|
}
|
@ -9,80 +9,14 @@
|
|||||||
#ifndef _BIRD_NOTIFY_H_
|
#ifndef _BIRD_NOTIFY_H_
|
||||||
#define _BIRD_NOTIFY_H_
|
#define _BIRD_NOTIFY_H_
|
||||||
|
|
||||||
|
#include "lib/resource.h"
|
||||||
#include "lib/lists.h"
|
#include "lib/lists.h"
|
||||||
|
|
||||||
struct listener {
|
struct listener;
|
||||||
node sender_node;
|
|
||||||
node receiver_node;
|
|
||||||
|
|
||||||
void (*hook)(struct listener *who, void *data);
|
|
||||||
void (*dump)(struct listener *who);
|
|
||||||
void (*unsub)(struct listener *who);
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline void subscribe(struct listener *who, list *sender, list *receiver)
|
|
||||||
{
|
|
||||||
ASSERT(!NODE_VALID(&(who->sender_node)));
|
|
||||||
ASSERT(!NODE_VALID(&(who->receiver_node)));
|
|
||||||
|
|
||||||
add_tail(sender, &(who->sender_node));
|
|
||||||
add_tail(receiver, &(who->receiver_node));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void unsubscribe(struct listener *who)
|
|
||||||
{
|
|
||||||
/* Allow multiple unsubscribe */
|
|
||||||
if (!NODE_VALID(&(who->sender_node))
|
|
||||||
&& !NODE_VALID(&(who->receiver_node)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
ASSERT(NODE_VALID(&(who->sender_node))
|
|
||||||
&& NODE_VALID(&(who->receiver_node)));
|
|
||||||
|
|
||||||
rem_node(&(who->sender_node));
|
|
||||||
rem_node(&(who->receiver_node));
|
|
||||||
|
|
||||||
who->sender_node = who->receiver_node = (node) {};
|
|
||||||
CALL(who->unsub, who);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void unsubscribe_all(list *receiver)
|
|
||||||
{
|
|
||||||
struct listener *n;
|
|
||||||
node *x, *y;
|
|
||||||
WALK_LIST2_DELSAFE(n, x, y, *receiver, receiver_node)
|
|
||||||
unsubscribe(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void notify(list *sender, void *data)
|
|
||||||
{
|
|
||||||
struct listener *n;
|
|
||||||
node *x, *y;
|
|
||||||
WALK_LIST2_DELSAFE(n, x, y, *sender, sender_node)
|
|
||||||
n->hook(n, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void listeners_dump(list *sender, list *receiver)
|
|
||||||
{
|
|
||||||
ASSERT((!sender) || (!receiver));
|
|
||||||
ASSERT(sender || receiver);
|
|
||||||
|
|
||||||
struct listener *n;
|
|
||||||
node *x;
|
|
||||||
if (sender)
|
|
||||||
WALK_LIST2(n, x, *sender, sender_node) {
|
|
||||||
debug("\t\tNotifier: hook %p", n->hook);
|
|
||||||
CALL(n->dump, n);
|
|
||||||
debug("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (receiver)
|
|
||||||
WALK_LIST2(n, x, *receiver, receiver_node) {
|
|
||||||
debug("\t\tNotifier: hook %p", n->hook);
|
|
||||||
CALL(n->dump, n);
|
|
||||||
debug("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
struct listener *subscribe(pool *p, list *sender, void (*notify)(void *self, const void *data), void (*unsubscribe)(void *self), void *self);
|
||||||
|
void unsubscribe(struct listener *L);
|
||||||
|
void unsubscribe_all(list *sender);
|
||||||
|
void notify(list *sender, const void *data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
43
nest/proto.c
43
nest/proto.c
@ -160,15 +160,8 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
|
|||||||
c->proto = p;
|
c->proto = p;
|
||||||
c->table = cf->table->table;
|
c->table = cf->table->table;
|
||||||
|
|
||||||
c->in_filter.filter = cf->in_filter;
|
filter_slot_init(&(c->in_filter), p->pool, cf->in_filter, channel_filter_slot_reimport);
|
||||||
c->in_filter.reloader = channel_filter_slot_reimport;
|
filter_slot_init(&(c->out_filter), p->pool, cf->out_filter, channel_filter_slot_reexport);
|
||||||
c->in_filter.p = p->pool;
|
|
||||||
init_list(&c->in_filter.notifiers);
|
|
||||||
|
|
||||||
c->out_filter.filter = cf->out_filter;
|
|
||||||
c->out_filter.reloader = channel_filter_slot_reexport;
|
|
||||||
c->out_filter.p = p->pool;
|
|
||||||
init_list(&c->out_filter.notifiers);
|
|
||||||
|
|
||||||
c->rx_limit = cf->rx_limit;
|
c->rx_limit = cf->rx_limit;
|
||||||
c->in_limit = cf->in_limit;
|
c->in_limit = cf->in_limit;
|
||||||
@ -418,8 +411,8 @@ channel_set_state(struct channel *c, uint state)
|
|||||||
/* No filter notifier shall remain after transitioning from CS_UP state. */
|
/* No filter notifier shall remain after transitioning from CS_UP state. */
|
||||||
if (cs == CS_UP)
|
if (cs == CS_UP)
|
||||||
{
|
{
|
||||||
unsubscribe_all(&(c->in_filter.notifiers));
|
filter_slot_deactivate(&(c->in_filter));
|
||||||
unsubscribe_all(&(c->out_filter.notifiers));
|
filter_slot_deactivate(&(c->out_filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
@ -626,16 +619,20 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
|
|||||||
if (c->merge_limit != cf->merge_limit)
|
if (c->merge_limit != cf->merge_limit)
|
||||||
export_changed = 1;
|
export_changed = 1;
|
||||||
|
|
||||||
/* Reconfigure channel fields */
|
/* Reconfigure filter slots */
|
||||||
|
if (import_changed) {
|
||||||
|
filter_slot_deactivate(&(c->in_filter));
|
||||||
|
filter_slot_init(&(c->in_filter), c->proto->pool, cf->in_filter, channel_filter_slot_reimport);
|
||||||
|
} else
|
||||||
c->in_filter.filter = cf->in_filter;
|
c->in_filter.filter = cf->in_filter;
|
||||||
|
|
||||||
|
if (export_changed) {
|
||||||
|
filter_slot_deactivate(&(c->out_filter));
|
||||||
|
filter_slot_init(&(c->out_filter), c->proto->pool, cf->out_filter, channel_filter_slot_reexport);
|
||||||
|
} else
|
||||||
c->out_filter.filter = cf->out_filter;
|
c->out_filter.filter = cf->out_filter;
|
||||||
|
|
||||||
if (import_changed)
|
/* Reconfigure other channel fields */
|
||||||
unsubscribe_all(&(c->in_filter.notifiers));
|
|
||||||
|
|
||||||
if (export_changed)
|
|
||||||
unsubscribe_all(&(c->out_filter.notifiers));
|
|
||||||
|
|
||||||
c->rx_limit = cf->rx_limit;
|
c->rx_limit = cf->rx_limit;
|
||||||
c->in_limit = cf->in_limit;
|
c->in_limit = cf->in_limit;
|
||||||
c->out_limit = cf->out_limit;
|
c->out_limit = cf->out_limit;
|
||||||
@ -1335,18 +1332,8 @@ protos_dump_all(void)
|
|||||||
debug("\tTABLE %s\n", c->table->name);
|
debug("\tTABLE %s\n", c->table->name);
|
||||||
if (c->in_filter.filter)
|
if (c->in_filter.filter)
|
||||||
debug("\tInput filter: %s\n", filter_name(c->in_filter.filter));
|
debug("\tInput filter: %s\n", filter_name(c->in_filter.filter));
|
||||||
if (!EMPTY_LIST(c->in_filter.notifiers))
|
|
||||||
{
|
|
||||||
debug("\tInput filter notifiers:\n");
|
|
||||||
listeners_dump(NULL, &(c->in_filter.notifiers));
|
|
||||||
}
|
|
||||||
if (c->out_filter.filter)
|
if (c->out_filter.filter)
|
||||||
debug("\tOutput filter: %s\n", filter_name(c->out_filter.filter));
|
debug("\tOutput filter: %s\n", filter_name(c->out_filter.filter));
|
||||||
if (!EMPTY_LIST(c->out_filter.notifiers))
|
|
||||||
{
|
|
||||||
debug("\tOutput filter notifiers:\n");
|
|
||||||
listeners_dump(NULL, &(c->out_filter.notifiers));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->proto->dump && (p->proto_state != PS_DOWN))
|
if (p->proto->dump && (p->proto_state != PS_DOWN))
|
||||||
|
Loading…
Reference in New Issue
Block a user