mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-23 18:21:54 +00:00
ROA change notifications: simple variant
This implementation will just automatically request channel reload/refeed when ROA change is detected. It may be sufficient for many uses; performance impact for big IXPs is unclear.
This commit is contained in:
parent
b9deced219
commit
f827cf11be
@ -45,6 +45,7 @@
|
|||||||
#include "nest/protocol.h"
|
#include "nest/protocol.h"
|
||||||
#include "nest/iface.h"
|
#include "nest/iface.h"
|
||||||
#include "nest/attrs.h"
|
#include "nest/attrs.h"
|
||||||
|
#include "nest/notify.h"
|
||||||
#include "conf/conf.h"
|
#include "conf/conf.h"
|
||||||
#include "filter/filter.h"
|
#include "filter/filter.h"
|
||||||
|
|
||||||
@ -52,6 +53,59 @@
|
|||||||
|
|
||||||
void (*bt_assert_hook)(int result, struct f_inst *assert);
|
void (*bt_assert_hook)(int result, struct f_inst *assert);
|
||||||
|
|
||||||
|
struct filter_roa_notifier {
|
||||||
|
resource r;
|
||||||
|
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_notifier_unsubscribe(struct listener *L) {
|
||||||
|
struct filter_roa_notifier *frn = SKIP_BACK(struct filter_roa_notifier, L, L);
|
||||||
|
rfree(frn);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
static struct adata undef_adata; /* adata of length 0 used for undefined */
|
static struct adata undef_adata; /* adata of length 0 used for undefined */
|
||||||
|
|
||||||
/* Special undef value for paths and clists */
|
/* Special undef value for paths and clists */
|
||||||
@ -542,6 +596,7 @@ static struct ea_list **f_eattrs;
|
|||||||
static struct linpool *f_pool;
|
static struct linpool *f_pool;
|
||||||
static struct buffer f_buf;
|
static struct buffer f_buf;
|
||||||
static int f_flags;
|
static int f_flags;
|
||||||
|
static struct filter_slot *f_slot;
|
||||||
|
|
||||||
static inline void f_cache_eattrs(void)
|
static inline void f_cache_eattrs(void)
|
||||||
{
|
{
|
||||||
@ -1555,7 +1610,12 @@ interpret(struct f_inst *what)
|
|||||||
if (table->addr_type != (v1.val.net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
|
if (table->addr_type != (v1.val.net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
|
||||||
res.val.i = ROA_UNKNOWN; /* Prefix and table type mismatch */
|
res.val.i = ROA_UNKNOWN; /* Prefix and table type mismatch */
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (f_slot)
|
||||||
|
filter_roa_notifier_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);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1754,12 +1814,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
|||||||
* modified in place, old cached rta is possibly freed.
|
* modified in place, old cached rta is possibly freed.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags)
|
f_run(struct filter_slot *filter_slot, struct rte **rte, struct linpool *tmp_pool, int flags)
|
||||||
{
|
{
|
||||||
if (filter == FILTER_ACCEPT)
|
if (filter_slot->filter == FILTER_ACCEPT)
|
||||||
return F_ACCEPT;
|
return F_ACCEPT;
|
||||||
|
|
||||||
if (filter == FILTER_REJECT)
|
if (filter_slot->filter == FILTER_REJECT)
|
||||||
return F_REJECT;
|
return F_REJECT;
|
||||||
|
|
||||||
int rte_cow = ((*rte)->flags & REF_COW);
|
int rte_cow = ((*rte)->flags & REF_COW);
|
||||||
@ -1770,10 +1830,11 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla
|
|||||||
f_old_rta = NULL;
|
f_old_rta = NULL;
|
||||||
f_pool = tmp_pool;
|
f_pool = tmp_pool;
|
||||||
f_flags = flags;
|
f_flags = flags;
|
||||||
|
f_slot = filter_slot;
|
||||||
|
|
||||||
LOG_BUFFER_INIT(f_buf);
|
LOG_BUFFER_INIT(f_buf);
|
||||||
|
|
||||||
struct f_val res = interpret(filter->root);
|
struct f_val res = interpret(filter_slot->filter->root);
|
||||||
|
|
||||||
if (f_old_rta) {
|
if (f_old_rta) {
|
||||||
/*
|
/*
|
||||||
@ -1797,7 +1858,7 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla
|
|||||||
|
|
||||||
if (res.type != T_RETURN) {
|
if (res.type != T_RETURN) {
|
||||||
if (!(f_flags & FF_SILENT))
|
if (!(f_flags & FF_SILENT))
|
||||||
log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name);
|
log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter_slot->filter->name);
|
||||||
return F_ERROR;
|
return F_ERROR;
|
||||||
}
|
}
|
||||||
DBG( "done (%u)\n", res.val.i );
|
DBG( "done (%u)\n", res.val.i );
|
||||||
@ -1815,6 +1876,7 @@ f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool)
|
|||||||
f_old_rta = NULL;
|
f_old_rta = NULL;
|
||||||
f_pool = tmp_pool;
|
f_pool = tmp_pool;
|
||||||
f_flags = 0;
|
f_flags = 0;
|
||||||
|
f_slot = NULL;
|
||||||
|
|
||||||
LOG_BUFFER_INIT(f_buf);
|
LOG_BUFFER_INIT(f_buf);
|
||||||
|
|
||||||
@ -1831,6 +1893,7 @@ f_eval(struct f_inst *expr, struct linpool *tmp_pool)
|
|||||||
f_eattrs = NULL;
|
f_eattrs = NULL;
|
||||||
f_rte = NULL;
|
f_rte = NULL;
|
||||||
f_pool = tmp_pool;
|
f_pool = tmp_pool;
|
||||||
|
f_slot = NULL;
|
||||||
|
|
||||||
LOG_BUFFER_INIT(f_buf);
|
LOG_BUFFER_INIT(f_buf);
|
||||||
|
|
||||||
|
@ -149,6 +149,13 @@ struct filter {
|
|||||||
struct f_inst *root;
|
struct f_inst *root;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct filter_slot {
|
||||||
|
struct filter *filter;
|
||||||
|
void (*reloader)(struct filter_slot *);
|
||||||
|
pool *p;
|
||||||
|
list notifiers;
|
||||||
|
};
|
||||||
|
|
||||||
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);
|
||||||
@ -175,7 +182,7 @@ void trie_format(struct f_trie *t, buffer *buf);
|
|||||||
struct ea_list;
|
struct ea_list;
|
||||||
struct rte;
|
struct rte;
|
||||||
|
|
||||||
int f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
|
int f_run(struct filter_slot *filter_slot, struct rte **rte, struct linpool *tmp_pool, int flags);
|
||||||
struct f_val f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool);
|
struct f_val f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool);
|
||||||
struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool);
|
struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool);
|
||||||
uint f_eval_int(struct f_inst *expr);
|
uint f_eval_int(struct f_inst *expr);
|
||||||
@ -286,6 +293,7 @@ struct f_trie
|
|||||||
#define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val));
|
#define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val));
|
||||||
|
|
||||||
#define FF_SILENT 2 /* Silent filter execution */
|
#define FF_SILENT 2 /* Silent filter execution */
|
||||||
|
#define FF_TEMP 4 /* Result of this filter is dropped */
|
||||||
|
|
||||||
/* Custom route attributes */
|
/* Custom route attributes */
|
||||||
struct custom_attribute {
|
struct custom_attribute {
|
||||||
|
88
nest/notify.h
Normal file
88
nest/notify.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BIRD_NOTIFY_H_
|
||||||
|
#define _BIRD_NOTIFY_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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
68
nest/proto.c
68
nest/proto.c
@ -125,6 +125,16 @@ proto_find_channel_by_name(struct proto *p, const char *n)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void channel_filter_slot_reimport(struct filter_slot *fs)
|
||||||
|
{
|
||||||
|
return channel_request_reload(SKIP_BACK(struct channel, in_filter, fs));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void channel_filter_slot_reexport(struct filter_slot *fs)
|
||||||
|
{
|
||||||
|
return channel_request_feeding(SKIP_BACK(struct channel, out_filter, fs));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* proto_add_channel - connect protocol to a routing table
|
* proto_add_channel - connect protocol to a routing table
|
||||||
* @p: protocol instance
|
* @p: protocol instance
|
||||||
@ -150,8 +160,16 @@ 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 = cf->in_filter;
|
c->in_filter.filter = cf->in_filter;
|
||||||
c->out_filter = cf->out_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);
|
||||||
|
|
||||||
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;
|
||||||
@ -397,6 +415,13 @@ channel_set_state(struct channel *c, uint state)
|
|||||||
c->channel_state = state;
|
c->channel_state = state;
|
||||||
c->last_state_change = current_time();
|
c->last_state_change = current_time();
|
||||||
|
|
||||||
|
/* 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));
|
||||||
|
}
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case CS_START:
|
case CS_START:
|
||||||
@ -492,7 +517,7 @@ channel_reloadable(struct channel *c)
|
|||||||
return c->proto->reload_routes && c->reloadable;
|
return c->proto->reload_routes && c->reloadable;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
channel_request_reload(struct channel *c)
|
channel_request_reload(struct channel *c)
|
||||||
{
|
{
|
||||||
ASSERT(c->channel_state == CS_UP);
|
ASSERT(c->channel_state == CS_UP);
|
||||||
@ -592,8 +617,8 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Note that filter_same() requires arguments in (new, old) order */
|
/* Note that filter_same() requires arguments in (new, old) order */
|
||||||
int import_changed = !filter_same(cf->in_filter, c->in_filter);
|
int import_changed = !filter_same(cf->in_filter, c->in_filter.filter);
|
||||||
int export_changed = !filter_same(cf->out_filter, c->out_filter);
|
int export_changed = !filter_same(cf->out_filter, c->out_filter.filter);
|
||||||
|
|
||||||
if (c->preference != cf->preference)
|
if (c->preference != cf->preference)
|
||||||
import_changed = 1;
|
import_changed = 1;
|
||||||
@ -602,8 +627,15 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
|
|||||||
export_changed = 1;
|
export_changed = 1;
|
||||||
|
|
||||||
/* Reconfigure channel fields */
|
/* Reconfigure channel fields */
|
||||||
c->in_filter = cf->in_filter;
|
c->in_filter.filter = cf->in_filter;
|
||||||
c->out_filter = cf->out_filter;
|
c->out_filter.filter = cf->out_filter;
|
||||||
|
|
||||||
|
if (import_changed)
|
||||||
|
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;
|
||||||
@ -1301,10 +1333,20 @@ protos_dump_all(void)
|
|||||||
WALK_LIST(c, p->channels)
|
WALK_LIST(c, p->channels)
|
||||||
{
|
{
|
||||||
debug("\tTABLE %s\n", c->table->name);
|
debug("\tTABLE %s\n", c->table->name);
|
||||||
if (c->in_filter)
|
if (c->in_filter.filter)
|
||||||
debug("\tInput filter: %s\n", filter_name(c->in_filter));
|
debug("\tInput filter: %s\n", filter_name(c->in_filter.filter));
|
||||||
if (c->out_filter)
|
if (!EMPTY_LIST(c->in_filter.notifiers))
|
||||||
debug("\tOutput filter: %s\n", filter_name(c->out_filter));
|
{
|
||||||
|
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))
|
if (p->proto->dump && (p->proto_state != PS_DOWN))
|
||||||
@ -1731,8 +1773,8 @@ channel_show_info(struct channel *c)
|
|||||||
cli_msg(-1006, " State: %s", c_states[c->channel_state]);
|
cli_msg(-1006, " State: %s", c_states[c->channel_state]);
|
||||||
cli_msg(-1006, " Table: %s", c->table->name);
|
cli_msg(-1006, " Table: %s", c->table->name);
|
||||||
cli_msg(-1006, " Preference: %d", c->preference);
|
cli_msg(-1006, " Preference: %d", c->preference);
|
||||||
cli_msg(-1006, " Input filter: %s", filter_name(c->in_filter));
|
cli_msg(-1006, " Input filter: %s", filter_name(c->in_filter.filter));
|
||||||
cli_msg(-1006, " Output filter: %s", filter_name(c->out_filter));
|
cli_msg(-1006, " Output filter: %s", filter_name(c->out_filter.filter));
|
||||||
|
|
||||||
if (graceful_restart_state == GRS_ACTIVE)
|
if (graceful_restart_state == GRS_ACTIVE)
|
||||||
cli_msg(-1006, " GR recovery: %s%s",
|
cli_msg(-1006, " GR recovery: %s%s",
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
#include "lib/lists.h"
|
#include "lib/lists.h"
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/event.h"
|
#include "lib/event.h"
|
||||||
|
#include "filter/filter.h"
|
||||||
|
#include "nest/notify.h"
|
||||||
#include "nest/route.h"
|
#include "nest/route.h"
|
||||||
#include "conf/conf.h"
|
#include "conf/conf.h"
|
||||||
|
|
||||||
@ -511,8 +513,8 @@ struct channel {
|
|||||||
struct proto *proto;
|
struct proto *proto;
|
||||||
|
|
||||||
struct rtable *table;
|
struct rtable *table;
|
||||||
struct filter *in_filter; /* Input filter */
|
struct filter_slot in_filter; /* Input filter */
|
||||||
struct filter *out_filter; /* Output filter */
|
struct filter_slot out_filter; /* Output filter */
|
||||||
struct channel_limit rx_limit; /* Receive limit (for in_keep_filtered) */
|
struct channel_limit rx_limit; /* Receive limit (for in_keep_filtered) */
|
||||||
struct channel_limit in_limit; /* Input limit */
|
struct channel_limit in_limit; /* Input limit */
|
||||||
struct channel_limit out_limit; /* Output limit */
|
struct channel_limit out_limit; /* Output limit */
|
||||||
@ -620,6 +622,7 @@ static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP)
|
|||||||
static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); }
|
static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); }
|
||||||
|
|
||||||
void channel_request_feeding(struct channel *c);
|
void channel_request_feeding(struct channel *c);
|
||||||
|
void channel_request_reload(struct channel *c);
|
||||||
void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
|
void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
|
||||||
void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
|
void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
|
||||||
int channel_reconfigure(struct channel *c, struct channel_config *cf);
|
int channel_reconfigure(struct channel *c, struct channel_config *cf);
|
||||||
|
@ -19,6 +19,7 @@ struct proto;
|
|||||||
struct rte_src;
|
struct rte_src;
|
||||||
struct symbol;
|
struct symbol;
|
||||||
struct filter;
|
struct filter;
|
||||||
|
struct filter_slot;
|
||||||
struct cli;
|
struct cli;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -148,6 +149,7 @@ typedef struct rtable {
|
|||||||
struct fib fib;
|
struct fib fib;
|
||||||
char *name; /* Name of this table */
|
char *name; /* Name of this table */
|
||||||
list channels; /* List of attached channels (struct channel) */
|
list channels; /* List of attached channels (struct channel) */
|
||||||
|
list listeners; /* List of attached listeners (struct listener) */
|
||||||
uint addr_type; /* Type of address data stored in table (NET_*) */
|
uint addr_type; /* Type of address data stored in table (NET_*) */
|
||||||
int pipe_busy; /* Pipe loop detection */
|
int pipe_busy; /* Pipe loop detection */
|
||||||
int use_count; /* Number of protocols using this table */
|
int use_count; /* Number of protocols using this table */
|
||||||
@ -297,7 +299,7 @@ rte *rte_find(net *net, struct rte_src *src);
|
|||||||
rte *rte_get_temp(struct rta *);
|
rte *rte_get_temp(struct rta *);
|
||||||
void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
|
void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
|
||||||
/* rte_update() moved to protocol.h to avoid dependency conflicts */
|
/* rte_update() moved to protocol.h to avoid dependency conflicts */
|
||||||
int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter);
|
int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter_slot *filter_slot);
|
||||||
rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent);
|
rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent);
|
||||||
void rt_refresh_begin(rtable *t, struct channel *c);
|
void rt_refresh_begin(rtable *t, struct channel *c);
|
||||||
void rt_refresh_end(rtable *t, struct channel *c);
|
void rt_refresh_end(rtable *t, struct channel *c);
|
||||||
@ -318,6 +320,10 @@ void rt_reload_channel_abort(struct channel *c);
|
|||||||
void rt_prune_sync(rtable *t, int all);
|
void rt_prune_sync(rtable *t, int all);
|
||||||
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
|
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
|
||||||
|
|
||||||
|
struct rt_notify {
|
||||||
|
struct network *net;
|
||||||
|
rte *new, *old, *new_best, *old_best, *before_old;
|
||||||
|
};
|
||||||
|
|
||||||
/* Default limit for ECMP next hops, defined in sysdep code */
|
/* Default limit for ECMP next hops, defined in sysdep code */
|
||||||
extern const int rt_default_ecmp;
|
extern const int rt_default_ecmp;
|
||||||
|
@ -149,7 +149,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
|||||||
* command may change the export filter and do not update routes.
|
* command may change the export filter and do not update routes.
|
||||||
*/
|
*/
|
||||||
int do_export = (ic > 0) ||
|
int do_export = (ic > 0) ||
|
||||||
(f_run(ec->out_filter, &e, c->show_pool, FF_SILENT) <= F_ACCEPT);
|
(f_run(&(ec->out_filter), &e, c->show_pool, FF_SILENT | FF_TEMP) <= F_ACCEPT);
|
||||||
|
|
||||||
|
|
||||||
if (do_export != (d->export_mode == RSEM_EXPORT))
|
if (do_export != (d->export_mode == RSEM_EXPORT))
|
||||||
goto skip;
|
goto skip;
|
||||||
@ -162,7 +163,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
|||||||
if (d->show_protocol && (d->show_protocol != e->attrs->src->proto))
|
if (d->show_protocol && (d->show_protocol != e->attrs->src->proto))
|
||||||
goto skip;
|
goto skip;
|
||||||
|
|
||||||
if (f_run(d->filter, &e, c->show_pool, 0) > F_ACCEPT)
|
struct filter_slot fs = { .filter = d->filter };
|
||||||
|
if (f_run(&fs, &e, c->show_pool, FF_TEMP) > F_ACCEPT)
|
||||||
goto skip;
|
goto skip;
|
||||||
|
|
||||||
if (d->stats < 2)
|
if (d->stats < 2)
|
||||||
|
@ -397,7 +397,7 @@ static rte *
|
|||||||
export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int silent)
|
export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int silent)
|
||||||
{
|
{
|
||||||
struct proto *p = c->proto;
|
struct proto *p = c->proto;
|
||||||
struct filter *filter = c->out_filter;
|
struct filter *filter = c->out_filter.filter;
|
||||||
struct proto_stats *stats = &c->stats;
|
struct proto_stats *stats = &c->stats;
|
||||||
rte *rt;
|
rte *rt;
|
||||||
int v;
|
int v;
|
||||||
@ -426,7 +426,7 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
|
|||||||
rte_make_tmp_attrs(&rt, pool);
|
rte_make_tmp_attrs(&rt, pool);
|
||||||
|
|
||||||
v = filter && ((filter == FILTER_REJECT) ||
|
v = filter && ((filter == FILTER_REJECT) ||
|
||||||
(f_run(filter, &rt, pool,
|
(f_run(&(c->out_filter), &rt, pool,
|
||||||
(silent ? FF_SILENT : 0)) > F_ACCEPT));
|
(silent ? FF_SILENT : 0)) > F_ACCEPT));
|
||||||
if (v)
|
if (v)
|
||||||
{
|
{
|
||||||
@ -941,6 +941,17 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old,
|
|||||||
else
|
else
|
||||||
rt_notify_basic(c, net, new, old, 0);
|
rt_notify_basic(c, net, new, old, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct rt_notify rtn = {
|
||||||
|
.net = net,
|
||||||
|
.new = new,
|
||||||
|
.old = old,
|
||||||
|
.new_best = new_best,
|
||||||
|
.old_best = old_best,
|
||||||
|
.before_old = before_old,
|
||||||
|
};
|
||||||
|
|
||||||
|
notify(&(tab->listeners), &rtn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
@ -1364,7 +1375,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
|
|||||||
{
|
{
|
||||||
struct proto *p = c->proto;
|
struct proto *p = c->proto;
|
||||||
struct proto_stats *stats = &c->stats;
|
struct proto_stats *stats = &c->stats;
|
||||||
struct filter *filter = c->in_filter;
|
struct filter *filter = c->in_filter.filter;
|
||||||
rte *dummy = NULL;
|
rte *dummy = NULL;
|
||||||
net *nn;
|
net *nn;
|
||||||
|
|
||||||
@ -1409,7 +1420,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
|
|||||||
if (filter && (filter != FILTER_REJECT))
|
if (filter && (filter != FILTER_REJECT))
|
||||||
{
|
{
|
||||||
ea_list *oldea = new->attrs->eattrs;
|
ea_list *oldea = new->attrs->eattrs;
|
||||||
int fr = f_run(filter, &new, rte_update_pool, 0);
|
int fr = f_run(&(c->in_filter), &new, rte_update_pool, 0);
|
||||||
if (fr > F_ACCEPT)
|
if (fr > F_ACCEPT)
|
||||||
{
|
{
|
||||||
stats->imp_updates_filtered++;
|
stats->imp_updates_filtered++;
|
||||||
@ -1503,9 +1514,9 @@ rte_modify(rte *old)
|
|||||||
rte_update_unlock();
|
rte_update_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check rtable for best route to given net whether it would be exported do p */
|
/* One time check rtable for best route to given net whether it would be exported do p */
|
||||||
int
|
int
|
||||||
rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
|
rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter_slot *filter_slot)
|
||||||
{
|
{
|
||||||
net *n = net_find(t, a);
|
net *n = net_find(t, a);
|
||||||
rte *rt = n ? n->routes : NULL;
|
rte *rt = n ? n->routes : NULL;
|
||||||
@ -1520,7 +1531,7 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
|
|||||||
if (v == RIC_PROCESS)
|
if (v == RIC_PROCESS)
|
||||||
{
|
{
|
||||||
rte_make_tmp_attrs(&rt, rte_update_pool);
|
rte_make_tmp_attrs(&rt, rte_update_pool);
|
||||||
v = (f_run(filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT);
|
v = (f_run(filter_slot, &rt, rte_update_pool, FF_SILENT | FF_TEMP) <= F_ACCEPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Discard temporary rte */
|
/* Discard temporary rte */
|
||||||
@ -1727,6 +1738,7 @@ rt_setup(pool *p, rtable *t, struct rtable_config *cf)
|
|||||||
t->addr_type = cf->addr_type;
|
t->addr_type = cf->addr_type;
|
||||||
fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
|
fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
|
||||||
init_list(&t->channels);
|
init_list(&t->channels);
|
||||||
|
init_list(&t->listeners);
|
||||||
|
|
||||||
t->rt_event = ev_new_init(p, rt_event, t);
|
t->rt_event = ev_new_init(p, rt_event, t);
|
||||||
t->gc_time = current_time();
|
t->gc_time = current_time();
|
||||||
|
@ -498,7 +498,8 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
|
|||||||
|
|
||||||
rte_make_tmp_attrs(&rt, s->linpool);
|
rte_make_tmp_attrs(&rt, s->linpool);
|
||||||
|
|
||||||
if (f_run(s->filter, &rt, s->linpool, 0) <= F_ACCEPT)
|
struct filter_slot fs = { .filter = s->filter };
|
||||||
|
if (f_run(&(fs), &rt, s->linpool, FF_TEMP) <= F_ACCEPT)
|
||||||
mrt_rib_table_entry(s, rt);
|
mrt_rib_table_entry(s, rt);
|
||||||
|
|
||||||
if (rt != rt0)
|
if (rt != rt0)
|
||||||
|
@ -266,8 +266,8 @@ pipe_show_proto_info(struct proto *P)
|
|||||||
cli_msg(-1006, " Peer table: %s", p->sec->table->name);
|
cli_msg(-1006, " Peer table: %s", p->sec->table->name);
|
||||||
cli_msg(-1006, " Import state: %s", pipe_feed_state[p->sec->export_state]);
|
cli_msg(-1006, " Import state: %s", pipe_feed_state[p->sec->export_state]);
|
||||||
cli_msg(-1006, " Export state: %s", pipe_feed_state[p->pri->export_state]);
|
cli_msg(-1006, " Export state: %s", pipe_feed_state[p->pri->export_state]);
|
||||||
cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter));
|
cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter.filter));
|
||||||
cli_msg(-1006, " Export filter: %s", filter_name(p->pri->out_filter));
|
cli_msg(-1006, " Export filter: %s", filter_name(p->pri->out_filter.filter));
|
||||||
|
|
||||||
channel_show_limit(&p->pri->in_limit, "Import limit:");
|
channel_show_limit(&p->pri->in_limit, "Import limit:");
|
||||||
channel_show_limit(&p->sec->in_limit, "Export limit:");
|
channel_show_limit(&p->sec->in_limit, "Export limit:");
|
||||||
|
@ -560,7 +560,7 @@ radv_check_active(struct radv_proto *p)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
struct channel *c = p->p.main_channel;
|
struct channel *c = p->p.main_channel;
|
||||||
return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter);
|
return rt_examine(c->table, &cf->trigger, &p->p, &(c->out_filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -562,7 +562,7 @@ static struct rte *
|
|||||||
krt_export_net(struct krt_proto *p, net *net, rte **rt_free)
|
krt_export_net(struct krt_proto *p, net *net, rte **rt_free)
|
||||||
{
|
{
|
||||||
struct channel *c = p->p.main_channel;
|
struct channel *c = p->p.main_channel;
|
||||||
struct filter *filter = c->out_filter;
|
struct filter *filter = c->out_filter.filter;
|
||||||
rte *rt;
|
rte *rt;
|
||||||
|
|
||||||
if (c->ra_mode == RA_MERGED)
|
if (c->ra_mode == RA_MERGED)
|
||||||
@ -584,7 +584,7 @@ krt_export_net(struct krt_proto *p, net *net, rte **rt_free)
|
|||||||
if (filter == FILTER_ACCEPT)
|
if (filter == FILTER_ACCEPT)
|
||||||
goto accept;
|
goto accept;
|
||||||
|
|
||||||
if (f_run(filter, &rt, krt_filter_lp, FF_SILENT) > F_ACCEPT)
|
if (f_run(&(c->out_filter), &rt, krt_filter_lp, FF_SILENT | FF_TEMP) > F_ACCEPT)
|
||||||
goto reject;
|
goto reject;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user