void (*bt_assert_hook)(int result, struct f_inst *assert);
-struct filter_roa_notifier {
- resource r;
- struct listener L;
+struct filter_roa_reloader {
+ node n;
+ struct listener *L;
struct rtable *roa_table;
struct filter_slot *slot;
};
-static void filter_roa_notifier_hook(struct listener *L, void *data UNUSED) {
- struct filter_roa_notifier *frn = SKIP_BACK(struct filter_roa_notifier, L, L);
- frn->slot->reloader(frn->slot);
+static void filter_roa_reloader_notify(void *self, const void *data UNUSED) {
+ struct filter_roa_reloader *frr = self;
+ frr->slot->reloader(frr->slot);
}
-static void filter_roa_notifier_unsubscribe(struct listener *L) {
- struct filter_roa_notifier *frn = SKIP_BACK(struct filter_roa_notifier, L, L);
- rfree(frn);
+static void filter_roa_reloader_unsubscribe(void *self) {
+ struct filter_roa_reloader *frr = self;
+ rem_node(&(frr->n));
+ mb_free(self);
}
-static void filter_roa_notifier_free(resource *r) {
- struct filter_roa_notifier *frn = (void *) r;
- 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;
+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_reloader *oldfrr;
node *x;
- WALK_LIST2(oldL, x, slot->notifiers, receiver_node)
- if (oldL->hook == filter_roa_notifier_hook)
- {
- 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. */
- }
-
- struct filter_roa_notifier *frn = ralloc(slot->p, &filter_roa_notifier_class);
- frn->L = (struct listener) {
- .hook = filter_roa_notifier_hook,
- .unsub = filter_roa_notifier_unsubscribe,
- };
- frn->roa_table = roa_table;
- frn->slot = slot;
-
- subscribe(&(frn->L), &(roa_table->listeners), &(slot->notifiers));
+ WALK_LIST2(oldfrr, x, slot->notifiers, n)
+ if (oldfrr->roa_table == roa_table)
+ return; /* Old notifier found for the same event. */
+
+ struct filter_roa_reloader *frr = mb_allocz(slot->p, sizeof(struct filter_roa_reloader));
+ frr->roa_table = roa_table;
+ frr->slot = slot;
+ add_tail(&(slot->notifiers), &(frr->n));
+ frr->L = subscribe(slot->p, &(roa_table->listeners), filter_roa_reloader_notify, filter_roa_reloader_unsubscribe, frr);
}
static struct adata undef_adata; /* adata of length 0 used for undefined */
else
{
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);
}
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_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);
-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)
$(all-daemon)
$(cf-local)
--- /dev/null
+/*
+ * 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);
+}
#ifndef _BIRD_NOTIFY_H_
#define _BIRD_NOTIFY_H_
+#include "lib/resource.h"
#include "lib/lists.h"
-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;
+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
c->proto = p;
c->table = cf->table->table;
- c->in_filter.filter = cf->in_filter;
- c->in_filter.reloader = channel_filter_slot_reimport;
- 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);
+ filter_slot_init(&(c->in_filter), p->pool, cf->in_filter, channel_filter_slot_reimport);
+ filter_slot_init(&(c->out_filter), p->pool, cf->out_filter, channel_filter_slot_reexport);
c->rx_limit = cf->rx_limit;
c->in_limit = cf->in_limit;
/* No filter notifier shall remain after transitioning from CS_UP state. */
if (cs == CS_UP)
{
- unsubscribe_all(&(c->in_filter.notifiers));
- unsubscribe_all(&(c->out_filter.notifiers));
+ filter_slot_deactivate(&(c->in_filter));
+ filter_slot_deactivate(&(c->out_filter));
}
switch (state)
if (c->merge_limit != cf->merge_limit)
export_changed = 1;
- /* Reconfigure channel fields */
- c->in_filter.filter = cf->in_filter;
- c->out_filter.filter = cf->out_filter;
-
- if (import_changed)
- unsubscribe_all(&(c->in_filter.notifiers));
+ /* 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;
- if (export_changed)
- unsubscribe_all(&(c->out_filter.notifiers));
+ 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;
+ /* Reconfigure other channel fields */
c->rx_limit = cf->rx_limit;
c->in_limit = cf->in_limit;
c->out_limit = cf->out_limit;
debug("\tTABLE %s\n", c->table->name);
if (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)
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))