summaryrefslogtreecommitdiff
path: root/nest/proto.c
diff options
context:
space:
mode:
Diffstat (limited to 'nest/proto.c')
-rw-r--r--nest/proto.c894
1 files changed, 284 insertions, 610 deletions
diff --git a/nest/proto.c b/nest/proto.c
index 2546e812..cd6a3faa 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -15,19 +15,17 @@
#include "lib/event.h"
#include "lib/timer.h"
#include "lib/string.h"
-#include "lib/coro.h"
#include "conf/conf.h"
-#include "nest/route.h"
+#include "nest/rt.h"
#include "nest/iface.h"
#include "nest/cli.h"
#include "filter/filter.h"
#include "filter/f-inst.h"
pool *proto_pool;
-list proto_list;
+list STATIC_LIST_INIT(proto_list);
-static list protocol_list;
-struct protocol *class_to_protocol[PROTOCOL__MAX];
+static list STATIC_LIST_INIT(protocol_list);
#define CD(c, msg, args...) ({ if (c->debug & D_STATES) log(L_TRACE "%s.%s: " msg, c->proto->name, c->name ?: "?", ## args); })
#define PD(p, msg, args...) ({ if (p->debug & D_STATES) log(L_TRACE "%s: " msg, p->name, ## args); })
@@ -47,28 +45,20 @@ static char *c_states[] = { "DOWN", "START", "UP", "STOP", "RESTART" };
extern struct protocol proto_unix_iface;
-static void channel_aux_request_refeed(struct channel_aux_table *cat);
+static void channel_request_reload(struct channel *c);
static void proto_rethink_goal(struct proto *p);
static char *proto_state_name(struct proto *p);
static void channel_init_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf);
static void channel_update_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf);
static void channel_reset_limit(struct channel *c, struct limit *l, int dir);
static void channel_feed_end(struct channel *c);
+static void channel_stop_export(struct channel *c);
static void channel_export_stopped(struct rt_export_request *req);
+static void channel_check_stopped(struct channel *c);
static inline int proto_is_done(struct proto *p)
{ return (p->proto_state == PS_DOWN) && proto_is_inactive(p); }
-static inline event_list *proto_event_list(struct proto *p)
-{ return p->loop == &main_birdloop ? &global_event_list : birdloop_event_list(p->loop); }
-
-static inline event_list *proto_work_list(struct proto *p)
-{ return p->loop == &main_birdloop ? &global_work_list : birdloop_event_list(p->loop); }
-
-static inline void proto_send_event(struct proto *p)
-{ ev_send(proto_event_list(p), p->event); }
-
-
static inline int channel_is_active(struct channel *c)
{ return (c->channel_state != CS_DOWN); }
@@ -97,9 +87,7 @@ channel_export_log_state_change(struct rt_export_request *req, u8 state)
switch (state)
{
case TES_FEEDING:
- if (c->out_table)
- rt_refresh_begin(&c->out_table->push);
- else if (c->proto->feed_begin)
+ if (c->proto->feed_begin)
c->proto->feed_begin(c, !c->refeeding);
break;
case TES_READY:
@@ -189,16 +177,6 @@ proto_find_channel_by_name(struct proto *p, const char *n)
return NULL;
}
-rte * channel_preimport(struct rt_import_request *req, rte *new, rte *old);
-rte * channel_in_preimport(struct rt_import_request *req, rte *new, rte *old);
-
-void rt_notify_optimal(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe);
-void rt_notify_any(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe);
-void rt_feed_any(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe, rte **feed, uint count);
-void rt_notify_accepted(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe, rte **feed, uint count);
-void rt_notify_merged(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe, rte **feed, uint count);
-
-
/**
* proto_add_channel - connect protocol to a routing table
* @p: protocol instance
@@ -223,25 +201,22 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
c->channel = cf->channel;
c->proto = p;
c->table = cf->table->table;
-
- RT_LOCKED(c->table, t)
- rt_lock_table(t);
+ rt_lock_table(c->table);
c->in_filter = cf->in_filter;
c->out_filter = cf->out_filter;
+ c->out_subprefix = cf->out_subprefix;
channel_init_limit(c, &c->rx_limit, PLD_RX, &cf->rx_limit);
channel_init_limit(c, &c->in_limit, PLD_IN, &cf->in_limit);
channel_init_limit(c, &c->out_limit, PLD_OUT, &cf->out_limit);
- c->rte_update_pool = lp_new_default(proto_pool);
-
c->net_type = cf->net_type;
c->ra_mode = cf->ra_mode;
c->preference = cf->preference;
c->debug = cf->debug;
c->merge_limit = cf->merge_limit;
- c->in_keep_filtered = cf->in_keep_filtered;
+ c->in_keep = cf->in_keep;
c->rpki_reload = cf->rpki_reload;
c->channel_state = CS_DOWN;
@@ -266,9 +241,7 @@ proto_remove_channel(struct proto *p UNUSED, struct channel *c)
CD(c, "Removed", c->name);
- RT_LOCKED(c->table, t)
- rt_unlock_table(t);
-
+ rt_unlock_table(c->table);
rem_node(&c->n);
mb_free(c);
}
@@ -309,51 +282,76 @@ proto_remove_channels(struct proto *p)
proto_remove_channel(p, c);
}
+struct roa_subscription {
+ node roa_node;
+ struct settle settle;
+ struct channel *c;
+ struct rt_export_request req;
+};
+
static void
-channel_roa_in_changed(void *_data)
+channel_roa_in_changed(struct settle *se)
{
- struct channel *c = _data;
+ struct roa_subscription *s = SKIP_BACK(struct roa_subscription, settle, se);
+ struct channel *c = s->c;
CD(c, "Reload triggered by RPKI change");
-
channel_request_reload(c);
}
static void
-channel_roa_out_changed(void *_data)
+channel_roa_out_changed(struct settle *se)
{
- struct channel *c = _data;
+ struct roa_subscription *s = SKIP_BACK(struct roa_subscription, settle, se);
+ struct channel *c = s->c;
+
CD(c, "Feeding triggered by RPKI change");
c->refeed_pending = 1;
+ channel_stop_export(c);
+}
- if (c->out_req.hook)
- rt_stop_export(&c->out_req, channel_export_stopped);
+static void
+channel_export_one_roa(struct rt_export_request *req, const net_addr *net UNUSED, struct rt_pending_export *first)
+{
+ struct roa_subscription *s = SKIP_BACK(struct roa_subscription, req, req);
+
+ /* TODO: use the information about what roa has changed */
+ settle_kick(&s->settle, s->c->proto->loop);
+
+ rpe_mark_seen_all(req->hook, first, NULL, NULL);
}
-/* Temporary code, subscriptions should be changed to resources */
-struct roa_subscription {
- struct rt_subscription s;
- node roa_node;
-};
+static void
+channel_dump_roa_req(struct rt_export_request *req)
+{
+ struct roa_subscription *s = SKIP_BACK(struct roa_subscription, req, req);
+ struct channel *c = s->c;
+ struct rtable_private *tab = SKIP_BACK(struct rtable_private, exporter.e, req->hook->table);
+
+ debug(" Channel %s.%s ROA %s change notifier from table %s request %p\n",
+ c->proto->name, c->name,
+ (s->settle.hook == channel_roa_in_changed) ? "import" : "export",
+ tab->name, req);
+}
static int
channel_roa_is_subscribed(struct channel *c, rtable *tab, int dir)
{
- void (*hook)(void *) =
+ void (*hook)(struct settle *) =
dir ? channel_roa_in_changed : channel_roa_out_changed;
struct roa_subscription *s;
node *n;
WALK_LIST2(s, n, c->roa_subscriptions, roa_node)
- if ((s->s.tab == tab) && (s->s.event->hook == hook))
+ if ((tab == SKIP_BACK(rtable, priv.exporter.e, s->req.hook->table))
+ && (s->settle.hook == hook))
return 1;
return 0;
}
-
static void
channel_roa_subscribe(struct channel *c, rtable *tab, int dir)
{
@@ -361,21 +359,41 @@ channel_roa_subscribe(struct channel *c, rtable *tab, int dir)
return;
struct roa_subscription *s = mb_allocz(c->proto->pool, sizeof(struct roa_subscription));
- s->s.event = ev_new_init(c->proto->pool, dir ? channel_roa_in_changed : channel_roa_out_changed, c);
- s->s.event->list = proto_work_list(c->proto);
- rt_subscribe(tab, &s->s);
+ *s = (struct roa_subscription) {
+ .settle = SETTLE_INIT(&c->roa_settle, dir ? channel_roa_in_changed : channel_roa_out_changed, NULL),
+ .c = c,
+ .req = {
+ .name = mb_sprintf(c->proto->pool, "%s.%s.roa-%s.%s",
+ c->proto->name, c->name, dir ? "in" : "out", tab->name),
+ .list = proto_work_list(c->proto),
+ .trace_routes = c->debug | c->proto->debug,
+ .dump_req = channel_dump_roa_req,
+ .export_one = channel_export_one_roa,
+ },
+ };
add_tail(&c->roa_subscriptions, &s->roa_node);
+ rt_request_export(tab, &s->req);
}
static void
-channel_roa_unsubscribe(struct roa_subscription *s)
+channel_roa_unsubscribed(struct rt_export_request *req)
{
- rt_unsubscribe(&s->s);
+ struct roa_subscription *s = SKIP_BACK(struct roa_subscription, req, req);
+ struct channel *c = s->c;
+
rem_node(&s->roa_node);
- rfree(s->s.event);
mb_free(s);
+
+ channel_check_stopped(c);
+}
+
+static void
+channel_roa_unsubscribe(struct roa_subscription *s)
+{
+ rt_stop_export(&s->req, channel_roa_unsubscribed);
+ settle_cancel(&s->settle);
}
static void
@@ -395,7 +413,7 @@ channel_roa_subscribe_filter(struct channel *c, int dir)
#ifdef CONFIG_BGP
/* No automatic reload for BGP channels without in_table / out_table */
if (c->channel == &channel_bgp)
- valid = dir ? !!c->in_table : !!c->out_table;
+ valid = dir ? ((c->in_keep & RIK_PREFILTER) == RIK_PREFILTER) : !!c->out_table;
#endif
struct filter_iterator fit;
@@ -405,14 +423,8 @@ channel_roa_subscribe_filter(struct channel *c, int dir)
{
switch (fi->fi_code)
{
- case FI_ROA_CHECK_IMPLICIT:
- tab = fi->i_FI_ROA_CHECK_IMPLICIT.rtc->table;
- if (valid) channel_roa_subscribe(c, tab, dir);
- found = 1;
- break;
-
- case FI_ROA_CHECK_EXPLICIT:
- tab = fi->i_FI_ROA_CHECK_EXPLICIT.rtc->table;
+ case FI_ROA_CHECK:
+ tab = fi->i_FI_ROA_CHECK.rtc->table;
if (valid) channel_roa_subscribe(c, tab, dir);
found = 1;
break;
@@ -449,14 +461,10 @@ channel_start_import(struct channel *c)
return;
}
- int nlen = strlen(c->name) + strlen(c->proto->name) + 2;
- char *rn = mb_allocz(c->proto->pool, nlen);
- bsprintf(rn, "%s.%s", c->proto->name, c->name);
-
c->in_req = (struct rt_import_request) {
- .name = rn,
- .list = proto_work_list(c->proto),
+ .name = mb_sprintf(c->proto->pool, "%s.%s", c->proto->name, c->name),
.trace_routes = c->debug | c->proto->debug,
+ .list = proto_work_list(c->proto),
.dump_req = channel_dump_import_req,
.log_state_change = channel_import_log_state_change,
.preimport = channel_preimport,
@@ -478,26 +486,24 @@ channel_start_export(struct channel *c)
{
if (c->out_req.hook)
{
- c->restart_export = 1;
- log(L_WARN "%s.%s: Fast channel export restart", c->proto->name, c->name);
+ log(L_WARN "%s.%s: Attempted to start channel's already started export", c->proto->name, c->name);
return;
}
ASSERT(c->channel_state == CS_UP);
- int nlen = strlen(c->name) + strlen(c->proto->name) + 2;
- char *rn = mb_allocz(c->proto->pool, nlen);
- bsprintf(rn, "%s.%s", c->proto->name, c->name);
c->out_req = (struct rt_export_request) {
- .name = rn,
+ .name = mb_sprintf(c->proto->pool, "%s.%s", c->proto->name, c->name),
.list = proto_work_list(c->proto),
+ .addr = c->out_subprefix,
+ .addr_mode = c->out_subprefix ? TE_ADDR_IN : TE_ADDR_NONE,
.trace_routes = c->debug | c->proto->debug,
.dump_req = channel_dump_export_req,
.log_state_change = channel_export_log_state_change,
};
- bmap_init(&c->export_map, c->proto->pool, 1024);
- bmap_init(&c->export_reject_map, c->proto->pool, 1024);
+ bmap_init(&c->export_map, c->proto->pool, 16);
+ bmap_init(&c->export_reject_map, c->proto->pool, 16);
channel_reset_limit(c, &c->out_limit, PLD_OUT);
@@ -531,32 +537,28 @@ channel_check_stopped(struct channel *c)
switch (c->channel_state)
{
case CS_STOP:
- if (c->out_req.hook || c->in_req.hook || c->out_table || c->in_table)
+ if (!EMPTY_LIST(c->roa_subscriptions) || c->out_req.hook || c->in_req.hook || c->reload_req.hook)
return;
channel_set_state(c, CS_DOWN);
- proto_send_event(c->proto);
+ proto_send_event(c->proto, c->proto->event);
break;
case CS_PAUSE:
- if (c->out_req.hook)
+ if (!EMPTY_LIST(c->roa_subscriptions) || c->out_req.hook || c->reload_req.hook)
return;
channel_set_state(c, CS_START);
break;
- default:
- bug("Stopped channel in a bad state: %d", c->channel_state);
}
DBG("%s.%s: Channel requests/hooks stopped (in state %s)\n", c->proto->name, c->name, c_states[c->channel_state]);
}
void
-channel_import_stopped(void *_c)
+channel_import_stopped(struct rt_import_request *req)
{
- struct channel *c = _c;
-
- c->in_req.hook = NULL;
+ struct channel *c = SKIP_BACK(struct channel, in_req, req);
mb_free(c->in_req.name);
c->in_req.name = NULL;
@@ -577,8 +579,10 @@ channel_export_stopped(struct rt_export_request *req)
c->refeeding = 1;
c->refeed_pending = 0;
- bmap_reset(&c->export_map, 1024);
- bmap_reset(&c->export_reject_map, 1024);
+ channel_reset_limit(c, &c->out_limit, PLD_OUT);
+
+ bmap_reset(&c->export_map, 16);
+ bmap_reset(&c->export_reject_map, 16);
rt_request_export(c->table, req);
return;
@@ -590,20 +594,12 @@ channel_export_stopped(struct rt_export_request *req)
bmap_free(&c->export_map);
bmap_free(&c->export_reject_map);
- if (c->restart_export)
- {
- c->restart_export = 0;
- channel_start_export(c);
- }
- else
- channel_check_stopped(c);
+ channel_check_stopped(c);
}
static void
channel_feed_end(struct channel *c)
{
- struct rt_export_request *req = &c->out_req;
-
/* Reset export limit if the feed ended with acceptable number of exported routes */
struct limit *l = &c->out_limit;
if (c->refeeding &&
@@ -615,377 +611,96 @@ channel_feed_end(struct channel *c)
channel_reset_limit(c, &c->out_limit, PLD_OUT);
c->refeed_pending = 1;
- rt_stop_export(req, channel_export_stopped);
+ channel_stop_export(c);
return;
}
- if (c->out_table)
- rt_refresh_end(&c->out_table->push);
- else if (c->proto->feed_end)
+ if (c->proto->feed_end)
c->proto->feed_end(c);
if (c->refeed_pending)
- rt_stop_export(req, channel_export_stopped);
-}
-
-#define CHANNEL_AUX_TABLE_DUMP_REQ(inout, imex, pgimex, pushget) static void \
- channel_##inout##_##pushget##_dump_req(struct rt_##pgimex##_request *req) { \
- struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, pushget, req); \
- debug(" Channel %s.%s " #imex " table " #pushget " request %p\n", cat->c->proto->name, cat->c->name, req); }
-
-CHANNEL_AUX_TABLE_DUMP_REQ(in, import, import, push)
-CHANNEL_AUX_TABLE_DUMP_REQ(in, import, export, get)
-CHANNEL_AUX_TABLE_DUMP_REQ(out, export, import, push)
-CHANNEL_AUX_TABLE_DUMP_REQ(out, export, export, get)
-
-#undef CHANNEL_AUX_TABLE_DUMP_REQ
-
-static uint channel_aux_imex(struct channel_aux_table *cat)
-{
- if (cat->c->in_table == cat)
- return 0;
- else if (cat->c->out_table == cat)
- return 1;
+ channel_stop_export(c);
else
- bug("Channel aux table must be in_table or out_table");
-}
-
-static void
-channel_aux_stopped(void *data)
-{
- struct channel_aux_table *cat;
-
- RT_LOCKED((rtable *) data, t)
- cat = t->config->owner;
-
- ASSERT_DIE(cat->push.hook == NULL);
- ASSERT_DIE(cat->get.hook == NULL);
- ASSERT_DIE(cat->stop_pending);
-
- struct channel *c = cat->c;
-
- if (channel_aux_imex(cat))
- c->out_table = NULL;
- else
- c->in_table = NULL;
-
- mb_free(cat);
- channel_check_stopped(c);
-}
-
-static void
-channel_aux_import_stopped(void *_cat)
-{
- struct channel_aux_table *cat = _cat;
-
- cat->push.hook = NULL;
-
- if (!cat->get.hook)
- RT_LOCKED(cat->tab, t)
- {
- t->delete = channel_aux_stopped;
- rt_unlock_table(t);
- }
+ c->refeeding = 0;
}
-static void
-channel_aux_export_stopped(struct rt_export_request *req)
+/* Called by protocol for reload from in_table */
+void
+channel_schedule_reload(struct channel *c)
{
- struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
- req->hook = NULL;
+ ASSERT(c->in_req.hook);
- if (cat->refeed_pending && !cat->stop_pending)
+ if (c->reload_req.hook)
{
- cat->refeed_pending = 0;
- rt_request_export(cat->tab, req);
-
+ CD(c, "Reload triggered before the previous one has finished");
+ c->reload_pending = 1;
return;
}
- if (!cat->push.hook)
- RT_LOCKED(cat->tab, t)
- {
- t->delete = channel_aux_stopped;
- rt_unlock_table(t);
- }
+ rt_refresh_begin(&c->in_req);
+ rt_request_export(c->table, &c->reload_req);
}
static void
-channel_aux_stop(struct channel_aux_table *cat)
+channel_reload_stopped(struct rt_export_request *req)
{
- ASSERT_DIE(!cat->stop_pending);
-
- cat->stop_pending = 1;
-
- RT_LOCKED(cat->tab, t)
- rt_lock_table(t);
-
- cat->push_stopped = (event) {
- .hook = channel_aux_import_stopped,
- .data = cat,
- .list = proto_event_list(cat->c->proto),
- };
-
- rt_stop_import(&cat->push, &cat->push_stopped);
- rt_stop_export(&cat->get, channel_aux_export_stopped);
-}
+ struct channel *c = SKIP_BACK(struct channel, reload_req, req);
-static void
-channel_push_log_state_change(struct rt_import_request *req, u8 state)
-{
- struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, push, req);
- const char *imex = channel_aux_imex(cat) ? "export" : "import";
- CD(cat->c, "Channel %s table import state changed to %s", imex, rt_import_state_name(state));
-}
-
-static void
-channel_get_log_state_change(struct rt_export_request *req, u8 state)
-{
- struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
- const char *imex = channel_aux_imex(cat) ? "export" : "import";
- CD(cat->c, "Channel %s table export state changed to %s", imex, rt_export_state_name(state));
-
- switch (state)
+ /* Restart reload */
+ if (c->reload_pending)
{
- case TES_FEEDING:
- if (imex && cat->c->proto->feed_begin)
- cat->c->proto->feed_begin(cat->c, !cat->c->refeeding);
- else if (!imex)
- rt_refresh_begin(&cat->c->in_req);
- break;
-
- case TES_READY:
- if (imex && cat->c->proto->feed_end)
- cat->c->proto->feed_end(cat->c);
- else if (!imex)
- rt_refresh_end(&cat->c->in_req);
-
- if (cat->refeed_pending)
- rt_stop_export(&cat->get, channel_aux_export_stopped);
-
- break;
- }
-}
-
-void rte_update_direct(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
-
-static int
-channel_aux_export_one_any(struct rt_export_request *req, struct rt_pending_export *rpe, rte **new, rte **old)
-{
- struct rte_src *src = rpe->new ? rpe->new->rte.src : rpe->old->rte.src;
- *old = RTES_OR_NULL(rpe->old);
- struct rte_storage *new_stored;
-
- while (rpe)
- {
- new_stored = rpe->new;
- rpe_mark_seen(req->hook, rpe);
- rpe = rpe_next(rpe, src);
- }
-
- *new = RTES_CLONE(new_stored, *new);
-
- return (*new || *old) && (&new_stored->rte != *old);
-}
-
-static int
-channel_aux_export_one_best(struct rt_export_request *req, struct rt_pending_export *rpe, rte **new, rte **old)
-{
- *old = RTES_OR_NULL(rpe->old_best);
- struct rte_storage *new_stored;
-
- while (rpe)
- {
- new_stored = rpe->new_best;
- rpe_mark_seen(req->hook, rpe);
- rpe = rpe_next(rpe, NULL);
+ c->reload_pending = 0;
+ channel_request_reload(c);
}
- *new = RTES_CLONE(new_stored, *new);
-
- return (*new || *old) && (&new_stored->rte != *old);
-}
-
-static void
-channel_in_export_one_any(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe)
-{
- struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
-
- rte n0, *new = &n0, *old;
- if (channel_aux_export_one_any(req, rpe, &new, &old))
- rte_update_direct(cat->c, net, new, old ? old->src : new->src);
+ if (c->channel_state != CS_UP)
+ channel_check_stopped(c);
}
static void
-channel_in_export_one_best(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe)
+channel_reload_log_state_change(struct rt_export_request *req, u8 state)
{
- struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
-
- rte n0, *new = &n0, *old;
- if (channel_aux_export_one_best(req, rpe, &new, &old))
- rte_update_direct(cat->c, net, new, old ? old->src : new->src);
-}
+ struct channel *c = SKIP_BACK(struct channel, reload_req, req);
-static void
-channel_in_export_bulk_any(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe UNUSED, rte **feed, uint count)
-{
- struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
- for (uint i=0; i<count; i++)
+ if (state == TES_READY)
{
- rte n0 = *feed[i];
- rte_update_direct(cat->c, net, &n0, n0.src);
- }
-}
+ if (c->channel_state == CS_UP)
+ rt_refresh_end(&c->in_req);
-static void
-channel_in_export_bulk_best(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe UNUSED, rte **feed, uint count)
-{
- struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
- if (!count)
- return;
-
- rte n0 = *feed[0];
- rte_update_direct(cat->c, net, &n0, n0.src);
-}
-
-void do_rt_notify_direct(struct channel *c, const net_addr *net, rte *new, const rte *old);
-
-static void
-channel_out_export_one_any(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe)
-{
- struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
- rte n0, *new = &n0, *old;
- if (channel_aux_export_one_any(req, rpe, &new, &old))
- do_rt_notify_direct(cat->c, net, new, old);
-}
-
-static void
-channel_out_export_one_best(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe)
-{
- struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
- rte n0, *new = &n0, *old;
- if (channel_aux_export_one_best(req, rpe, &new, &old))
- do_rt_notify_direct(cat->c, net, new, old);
+ rt_stop_export(req, channel_reload_stopped);
+ }
}
static void
-channel_out_export_bulk(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe UNUSED, rte **feed, uint count)
+channel_reload_dump_req(struct rt_export_request *req)
{
- struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
- if (cat->c->ra_mode != RA_ANY)
- ASSERT_DIE(count <= 1);
-
- for (uint i=0; i<count; i++)
- {
- rte n0 = *feed[i];
- do_rt_notify_direct(cat->c, net, &n0, NULL);
- }
+ struct channel *c = SKIP_BACK(struct channel, reload_req, req);
+ debug(" Channel %s.%s import reload request %p\n", c->proto->name, c->name, req);
}
/* Called by protocol to activate in_table */
-void
-channel_setup_in_table(struct channel *c, int best)
-{
- int nlen = sizeof("import") + strlen(c->name) + strlen(c->proto->name) + 3;
-
- struct {
- struct channel_aux_table cat;
- struct rtable_config tab_cf;
- char name[0];
- } *cat = mb_allocz(c->proto->pool, sizeof(*cat) + nlen);
-
- bsprintf(cat->name, "%s.%s.import", c->proto->name, c->name);
-
- cat->tab_cf.owner = cat;
- cat->tab_cf.name = cat->name;
- cat->tab_cf.addr_type = c->net_type;
- cat->tab_cf.cork_limit = 4 * page_size / sizeof(struct rt_pending_export);
-
- c->in_table = &cat->cat;
- c->in_table->push = (struct rt_import_request) {
- .name = cat->name,
- .list = proto_work_list(c->proto),
- .trace_routes = c->debug | c->proto->debug,
- .dump_req = channel_in_push_dump_req,
- .log_state_change = channel_push_log_state_change,
- .preimport = channel_in_preimport,
- };
- c->in_table->get = (struct rt_export_request) {
- .name = cat->name,
- .list = proto_work_list(c->proto),
- .trace_routes = c->debug | c->proto->debug,
- .dump_req = channel_in_get_dump_req,
- .log_state_change = channel_get_log_state_change,
- .export_one = best ? channel_in_export_one_best : channel_in_export_one_any,
- .export_bulk = best ? channel_in_export_bulk_best : channel_in_export_bulk_any,
- };
-
- c->in_table->c = c;
- c->in_table->tab = rt_setup(c->proto->pool, &cat->tab_cf);
-
- rt_request_import(c->in_table->tab, &c->in_table->push);
- rt_request_export(c->in_table->tab, &c->in_table->get);
-}
-
-/* Called by protocol to activate out_table */
-void
-channel_setup_out_table(struct channel *c)
+static void
+channel_setup_in_table(struct channel *c)
{
- int nlen = sizeof("export") + strlen(c->name) + strlen(c->proto->name) + 3;
-
- struct {
- struct channel_aux_table cat;
- struct rtable_config tab_cf;
- char name[0];
- } *cat = mb_allocz(c->proto->pool, sizeof(*cat) + nlen);
-
- bsprintf(cat->name, "%s.%s.export", c->proto->name, c->name);
-
- cat->tab_cf.owner = cat;
- cat->tab_cf.name = cat->name;
- cat->tab_cf.addr_type = c->net_type;
- cat->tab_cf.cork_limit = 4 * page_size / sizeof(struct rt_pending_export);
-
- c->out_table = &cat->cat;
- c->out_table->push = (struct rt_import_request) {
- .name = cat->name,
+ c->reload_req = (struct rt_export_request) {
+ .name = mb_sprintf(c->proto->pool, "%s.%s.import", c->proto->name, c->name),
.list = proto_work_list(c->proto),
.trace_routes = c->debug | c->proto->debug,
- .dump_req = channel_out_push_dump_req,
- .log_state_change = channel_push_log_state_change,
+ .export_bulk = channel_reload_export_bulk,
+ .dump_req = channel_reload_dump_req,
+ .log_state_change = channel_reload_log_state_change,
};
- c->out_table->get = (struct rt_export_request) {
- .name = cat->name,
- .list = proto_work_list(c->proto),
- .trace_routes = c->debug | c->proto->debug,
- .dump_req = channel_out_get_dump_req,
- .log_state_change = channel_get_log_state_change,
- .export_one = (c->ra_mode == RA_ANY) ? channel_out_export_one_any : channel_out_export_one_best,
- .export_bulk = channel_out_export_bulk,
- };
-
- c->out_table->c = c;
- c->out_table->tab = rt_setup(c->proto->pool, &cat->tab_cf);
-
- rt_request_import(c->out_table->tab, &c->out_table->push);
- rt_request_export(c->out_table->tab, &c->out_table->get);
}
-static void
-channel_aux_request_refeed(struct channel_aux_table *cat)
-{
- if (cat->stop_pending)
- return;
-
- cat->refeed_pending = 1;
- rt_stop_export(&cat->get, channel_aux_export_stopped);
-}
static void
channel_do_start(struct channel *c)
{
c->proto->active_channels++;
+ if ((c->in_keep & RIK_PREFILTER) == RIK_PREFILTER)
+ channel_setup_in_table(c);
+
CALL(c->channel->start, c);
channel_start_import(c);
@@ -1005,36 +720,26 @@ channel_do_up(struct channel *c)
static void
channel_do_pause(struct channel *c)
{
- /* Stop export */
- if (c->out_req.hook)
- {
- rt_stop_export(&c->out_req, channel_export_stopped);
- c->refeeding = 0;
- }
-
+ /* Drop ROA subscriptions */
channel_roa_unsubscribe_all(c);
+
+ /* Need to abort feeding */
+ c->reload_pending = 0;
+
+ if (c->reload_req.hook && c->reload_req.hook->export_state != TES_STOP)
+ rt_stop_export(&c->reload_req, channel_reload_stopped);
+
+ /* Stop export */
+ c->refeed_pending = 0;
+ channel_stop_export(c);
}
static void
channel_do_stop(struct channel *c)
{
- /* Drop auxiliary tables */
- if (c->in_table)
- channel_aux_stop(c->in_table);
-
- if (c->out_table)
- channel_aux_stop(c->out_table);
-
/* Stop import */
if (c->in_req.hook)
- {
- c->in_stopped = (event) {
- .hook = channel_import_stopped,
- .data = c,
- .list = proto_event_list(c->proto),
- };
- rt_stop_import(&c->in_req, &c->in_stopped);
- }
+ rt_stop_import(&c->in_req, channel_import_stopped);
c->gr_wait = 0;
if (c->gr_lock)
@@ -1042,24 +747,27 @@ channel_do_stop(struct channel *c)
CALL(c->channel->shutdown, c);
- channel_roa_unsubscribe_all(c);
}
static void
channel_do_down(struct channel *c)
{
- ASSERT(!c->out_req.hook && !c->in_req.hook && !c->out_table && !c->in_table);
+ ASSERT(!c->reload_req.hook);
c->proto->active_channels--;
memset(&c->import_stats, 0, sizeof(struct channel_import_stats));
memset(&c->export_stats, 0, sizeof(struct channel_export_stats));
+ c->out_table = NULL;
+
+ /* The in_table and out_table are going to be freed by freeing their resource pools. */
+
CALL(c->channel->cleanup, c);
/* Schedule protocol shutddown */
if (proto_is_done(c->proto))
- proto_send_event(c->proto);
+ proto_send_event(c->proto, c->proto->event);
}
void
@@ -1085,7 +793,7 @@ channel_set_state(struct channel *c, uint state)
break;
case CS_UP:
- ASSERT(cs == CS_DOWN || cs == CS_START || cs == CS_PAUSE);
+ ASSERT(cs == CS_DOWN || cs == CS_START);
if (cs == CS_DOWN)
channel_do_start(c);
@@ -1135,32 +843,28 @@ channel_set_state(struct channel *c, uint state)
* completed, it will switch back to ES_READY. This function can be called
* even when feeding is already running, in that case it is restarted.
*/
-static void
-channel_request_table_feeding(struct channel *c)
+void
+channel_request_feeding(struct channel *c)
{
ASSERT(c->out_req.hook);
+ if (c->refeed_pending)
+ return;
+
c->refeed_pending = 1;
- rt_stop_export(&c->out_req, channel_export_stopped);
+ channel_stop_export(c);
}
-void
-channel_request_feeding(struct channel *c)
+static void
+channel_stop_export(struct channel *c)
{
- if (c->gr_wait || !c->proto->rt_notify)
+ if (!c->out_req.hook || (c->out_req.hook->export_state == TES_STOP))
return;
- CD(c, "Refeed requested");
-
- ASSERT_DIE(c->out_req.hook);
-
- if (c->out_table)
- channel_aux_request_refeed(c->out_table);
- else
- channel_request_table_feeding(c);
+ rt_stop_export(&c->out_req, channel_export_stopped);
}
-void
+static void
channel_request_reload(struct channel *c)
{
ASSERT(c->in_req.hook);
@@ -1168,31 +872,12 @@ channel_request_reload(struct channel *c)
CD(c, "Reload requested");
- if (c->in_table)
- channel_aux_request_refeed(c->in_table);
+ if ((c->in_keep & RIK_PREFILTER) == RIK_PREFILTER)
+ channel_schedule_reload(c);
else
c->proto->reload_routes(c);
}
-void
-channel_refresh_begin(struct channel *c)
-{
- CD(c, "Channel route refresh begin");
- if (c->in_table)
- rt_refresh_begin(&c->in_table->push);
- else
- rt_refresh_begin(&c->in_req);
-}
-
-void
-channel_refresh_end(struct channel *c)
-{
- if (c->in_table)
- rt_refresh_end(&c->in_table->push);
- else
- rt_refresh_end(&c->in_req);
-}
-
const struct channel_class channel_basic = {
.channel_size = sizeof(struct channel),
.config_size = sizeof(struct channel_config)
@@ -1212,7 +897,7 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty
if (proto->net_type && (net_type != proto->net_type))
cf_error("Different channel type");
- tab = new_config->def_tables[net_type];
+ tab = rt_get_default_table(new_config, net_type);
}
if (!cc)
@@ -1231,6 +916,11 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty
cf->debug = new_config->channel_default_debug;
cf->rpki_reload = 1;
+ cf->roa_settle = (struct settle_config) {
+ .min = 1 S,
+ .max = 20 S,
+ };
+
add_tail(&proto->channels, &cf->n);
return cf;
@@ -1250,6 +940,7 @@ channel_config_get(const struct channel_class *cc, const char *name, uint net_ty
cf_error("Multiple %s channels", name);
cf->parent = proto;
+ cf->copy = 1;
return cf;
}
@@ -1275,8 +966,16 @@ static int reconfigure_type; /* Hack to propagate type info to channel_reconfig
int
channel_reconfigure(struct channel *c, struct channel_config *cf)
{
+ /* Touched by reconfiguration */
+ c->stale = 0;
+
/* FIXME: better handle these changes, also handle in_keep_filtered */
- if ((c->table != cf->table->table) || (cf->ra_mode && (c->ra_mode != cf->ra_mode)))
+ if ((c->table != cf->table->table) ||
+ (cf->ra_mode && (c->ra_mode != cf->ra_mode)) ||
+ (cf->in_keep != c->in_keep) ||
+ cf->out_subprefix && c->out_subprefix &&
+ !net_equal(cf->out_subprefix, c->out_subprefix) ||
+ (!cf->out_subprefix != !c->out_subprefix))
return 0;
/* Note that filter_same() requires arguments in (new, old) order */
@@ -1301,11 +1000,27 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
// c->ra_mode = cf->ra_mode;
c->merge_limit = cf->merge_limit;
c->preference = cf->preference;
+ c->out_req.addr = c->out_subprefix = cf->out_subprefix;
c->debug = cf->debug;
c->in_req.trace_routes = c->out_req.trace_routes = c->debug | c->proto->debug;
- c->in_keep_filtered = cf->in_keep_filtered;
c->rpki_reload = cf->rpki_reload;
+ if ( (c->roa_settle.min != cf->roa_settle.min)
+ || (c->roa_settle.max != cf->roa_settle.max))
+ {
+ c->roa_settle = cf->roa_settle;
+
+ struct roa_subscription *s;
+ node *n;
+
+ WALK_LIST2(s, n, c->roa_subscriptions, roa_node)
+ {
+ s->settle.cf = cf->roa_settle;
+ if (settle_active(&s->settle))
+ settle_kick(&s->settle, &main_birdloop);
+ }
+ }
+
/* Execute channel-specific reconfigure hook */
if (c->channel->reconfigure && !c->channel->reconfigure(c, cf, &import_changed, &export_changed))
return 0;
@@ -1348,7 +1063,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
channel_request_reload(c);
if (export_changed)
- channel_request_table_feeding(c);
+ channel_request_feeding(c);
done:
CD(c, "Reconfigured");
@@ -1399,6 +1114,11 @@ proto_configure_channel(struct proto *p, struct channel **pc, struct channel_con
static void
proto_cleanup(struct proto *p)
{
+ CALL(p->proto->cleanup, p);
+
+ rfree(p->pool);
+ p->pool = NULL;
+
p->active = 0;
proto_log_state_change(p);
proto_rethink_goal(p);
@@ -1409,13 +1129,13 @@ proto_loop_stopped(void *ptr)
{
struct proto *p = ptr;
- ASSERT_DIE(birdloop_inside(&main_birdloop));
+ birdloop_enter(&main_birdloop);
+ birdloop_free(p->loop);
p->loop = &main_birdloop;
- p->pool = NULL;
- p->event->list = NULL;
-
proto_cleanup(p);
+
+ birdloop_leave(&main_birdloop);
}
static void
@@ -1425,8 +1145,7 @@ proto_event(void *ptr)
if (p->do_stop)
{
- if (p->proto == &proto_unix_iface)
- if_flush_ifaces(p);
+ iface_unsubscribe(&p->iface_sub);
p->do_stop = 0;
}
@@ -1435,11 +1154,7 @@ proto_event(void *ptr)
if (p->loop != &main_birdloop)
birdloop_stop_self(p->loop, proto_loop_stopped, p);
else
- {
- rp_free(p->pool, proto_pool);
- p->pool = NULL;
proto_cleanup(p);
- }
}
@@ -1499,24 +1214,15 @@ proto_start(struct proto *p)
DBG("Kicking %s up\n", p->name);
PD(p, "Starting");
- int ns = strlen("Protocol ") + strlen(p->cf->name) + 1;
- void *nb = mb_alloc(proto_pool, ns);
- ASSERT_DIE(ns - 1 == bsnprintf(nb, ns, "Protocol %s", p->cf->name));
+ p->pool = rp_newf(proto_pool, "Protocol %s", p->cf->name);
if (graceful_restart_state == GRS_INIT)
p->gr_recovery = 1;
- if (p->cf->loop_order == DOMAIN_ORDER(the_bird))
- p->pool = rp_new(proto_pool, &main_birdloop, nb);
- else
- {
- p->loop = birdloop_new(proto_pool, p->cf->loop_order, nb);
- p->pool = birdloop_pool(p->loop);
- }
-
- p->event->list = proto_event_list(p);
+ if (p->cf->loop_order != DOMAIN_ORDER(the_bird))
+ p->loop = birdloop_new(p->pool, p->cf->loop_order, p->pool->name, p->cf->loop_max_latency);
- mb_move(nb, p->pool);
+ p->iface_sub.target = proto_event_list(p);
PROTO_LOCKED_FROM_MAIN(p)
proto_notify_state(p, (p->proto->start ? p->proto->start(p) : PS_UP));
@@ -1674,7 +1380,7 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
(nc->vrf != oc->vrf))
return 0;
- p->name = nc->name;
+ p->sources.name = p->name = nc->name;
p->debug = nc->debug;
p->mrtdump = nc->mrtdump;
reconfigure_type = type;
@@ -1735,6 +1441,8 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
p = oc->proto;
sym = cf_find_symbol(new, oc->name);
+ struct birdloop *proto_loop = PROTO_ENTER_FROM_MAIN(p);
+
/* Handle dynamic protocols */
if (!sym && oc->parent && !new->shutdown)
{
@@ -1760,13 +1468,10 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
nc->proto = p;
/* We will try to reconfigure protocol p */
- if (!force_reconfig)
+ if (!force_reconfig && proto_reconfigure(p, oc, nc, type))
{
- int ok;
- PROTO_LOCKED_FROM_MAIN(p)
- ok = proto_reconfigure(p, oc, nc, type);
- if (ok)
- continue;
+ PROTO_LEAVE_FROM_MAIN(proto_loop);
+ continue;
}
if (nc->parent)
@@ -1805,6 +1510,8 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
}
p->reconfiguring = 1;
+ PROTO_LEAVE_FROM_MAIN(proto_loop);
+
config_add_obstacle(old);
proto_rethink_goal(p);
}
@@ -2088,7 +1795,7 @@ protos_dump_all(void)
debug("Protocols:\n");
struct proto *p;
- WALK_LIST(p, proto_list)
+ WALK_LIST(p, proto_list) PROTO_LOCKED_FROM_MAIN(p)
{
#define DPF(x) (p->x ? " " #x : "")
debug(" protocol %s (%p) state %s with %d active channels flags: %s%s%s%s\n",
@@ -2107,20 +1814,6 @@ protos_dump_all(void)
debug("\tChannel state: %s/%s/%s\n", c_states[c->channel_state],
c->in_req.hook ? rt_import_state_name(rt_import_get_state(c->in_req.hook)) : "-",
c->out_req.hook ? rt_export_state_name(rt_export_get_state(c->out_req.hook)) : "-");
- if (c->in_table)
- {
- debug("\tInput aux table:\n");
- rt_dump_hooks(c->in_table->tab);
- rt_dump(c->in_table->tab);
- debug("\tEnd of input aux table.\n");
- }
- if (c->out_table)
- {
- debug("\tOutput aux table:\n");
- rt_dump_hooks(c->in_table->tab);
- rt_dump(c->in_table->tab);
- debug("\tEnd of output aux table.\n");
- }
}
if (p->proto->dump && (p->proto_state != PS_DOWN))
@@ -2140,14 +1833,13 @@ void
proto_build(struct protocol *p)
{
add_tail(&protocol_list, &p->n);
- ASSERT(p->class);
- ASSERT(!class_to_protocol[p->class]);
- class_to_protocol[p->class] = p;
}
/* FIXME: convert this call to some protocol hook */
extern void bfd_init_all(void);
+void protos_build_gen(void);
+
/**
* protos_build - build a protocol list
*
@@ -2160,46 +1852,9 @@ extern void bfd_init_all(void);
void
protos_build(void)
{
- init_list(&proto_list);
- init_list(&protocol_list);
+ protos_build_gen();
- proto_build(&proto_device);
-#ifdef CONFIG_RADV
- proto_build(&proto_radv);
-#endif
-#ifdef CONFIG_RIP
- proto_build(&proto_rip);
-#endif
-#ifdef CONFIG_STATIC
- proto_build(&proto_static);
-#endif
-#ifdef CONFIG_MRT
- proto_build(&proto_mrt);
-#endif
-#ifdef CONFIG_OSPF
- proto_build(&proto_ospf);
-#endif
-#ifdef CONFIG_PIPE
- proto_build(&proto_pipe);
-#endif
-#ifdef CONFIG_BGP
- proto_build(&proto_bgp);
-#endif
-#ifdef CONFIG_BFD
- proto_build(&proto_bfd);
- bfd_init_all();
-#endif
-#ifdef CONFIG_BABEL
- proto_build(&proto_babel);
-#endif
-#ifdef CONFIG_RPKI
- proto_build(&proto_rpki);
-#endif
-#ifdef CONFIG_PERF
- proto_build(&proto_perf);
-#endif
-
- proto_pool = rp_new(&root_pool, &main_birdloop, "Protocols");
+ proto_pool = rp_new(&root_pool, "Protocols");
}
@@ -2207,29 +1862,40 @@ protos_build(void)
int proto_restart;
static void
-proto_shutdown_loop(void *data UNUSED)
+proto_restart_event_hook(void *_p)
{
- struct proto *p, *p_next;
+ struct proto *p = _p;
+ if (!p->down_sched)
+ return;
- WALK_LIST_DELSAFE(p, p_next, proto_list)
- if (p->down_sched)
- {
- proto_restart = (p->down_sched == PDS_RESTART);
+ proto_restart = (p->down_sched == PDS_RESTART);
+ p->disabled = 1;
+ proto_rethink_goal(p);
- p->disabled = 1;
- proto_rethink_goal(p);
- if (proto_restart)
- {
- p->disabled = 0;
- proto_rethink_goal(p);
- }
- }
+ p->restart_event = NULL;
+ p->restart_timer = NULL;
+
+ if (proto_restart)
+ /* No need to call proto_rethink_goal() here again as the proto_cleanup() routine will
+ * call it after the protocol stops ... and both these routines are fixed to main_birdloop.
+ */
+ p->disabled = 0;
}
-static event proto_schedule_down_event = {
- .hook = proto_shutdown_loop,
- .list = &global_event_list,
-};
+static void
+proto_send_restart_event(struct proto *p)
+{
+ if (!p->restart_event)
+ p->restart_event = ev_new_init(p->pool, proto_restart_event_hook, p);
+
+ ev_send(&global_event_list, p->restart_event);
+}
+
+static void
+proto_send_restart_event_from_timer(struct timer *t)
+{
+ proto_send_restart_event((struct proto *) t->data);
+}
static inline void
proto_schedule_down(struct proto *p, byte restart, byte code)
@@ -2244,7 +1910,20 @@ proto_schedule_down(struct proto *p, byte restart, byte code)
p->down_sched = restart ? PDS_RESTART : PDS_DISABLE;
p->down_code = code;
- ev_send_self(&proto_schedule_down_event);
+ if (!restart)
+ {
+ if (p->restart_timer && tm_active(p->restart_timer))
+ tm_stop(p->restart_timer);
+
+ proto_send_restart_event(p);
+ }
+ else
+ {
+ if (!p->restart_timer)
+ p->restart_timer = tm_new_init(p->pool, proto_send_restart_event_from_timer, p, 0, 0);
+
+ tm_start_max_in(p->restart_timer, 250 MS, p->loop);
+ }
}
/**
@@ -2386,23 +2065,19 @@ static struct rte_owner_class default_rte_owner_class;
static inline void
proto_do_start(struct proto *p)
{
- ASSERT_DIE(birdloop_inside(p->loop));
-
p->active = 1;
- rt_init_sources(&p->sources, p->name, proto_work_list(p));
+ rt_init_sources(&p->sources, p->name, proto_event_list(p));
if (!p->sources.class)
p->sources.class = &default_rte_owner_class;
if (!p->cf->late_if_feed)
- if_feed_baby(p);
+ iface_subscribe(&p->iface_sub);
}
static void
proto_do_up(struct proto *p)
{
- ASSERT_DIE(birdloop_inside(p->loop));
-
if (!p->main_source)
p->main_source = rt_get_source(p, 0);
// Locked automaticaly
@@ -2410,7 +2085,7 @@ proto_do_up(struct proto *p)
proto_start_channels(p);
if (p->cf->late_if_feed)
- if_feed_baby(p);
+ iface_subscribe(&p->iface_sub);
}
static inline void
@@ -2435,18 +2110,17 @@ proto_do_stop(struct proto *p)
rt_destroy_sources(&p->sources, p->event);
p->do_stop = 1;
- proto_send_event(p);
+ proto_send_event(p, p->event);
}
static void
proto_do_down(struct proto *p)
{
p->down_code = 0;
- neigh_prune(p);
/* Shutdown is finished in the protocol event */
if (proto_is_done(p))
- proto_send_event(p);
+ proto_send_event(p, p->event);
}
@@ -2552,18 +2226,18 @@ channel_show_stats(struct channel *c)
u32 in_routes = c->in_limit.count;
u32 out_routes = c->out_limit.count;
- if (c->in_keep_filtered)
+ if (c->in_keep)
cli_msg(-1006, " Routes: %u imported, %u filtered, %u exported, %u preferred",
in_routes, (rx_routes - in_routes), out_routes, SRI(pref));
else
cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred",
in_routes, out_routes, SRI(pref));
- cli_msg(-1006, " Route change stats: received rejected filtered ignored limited accepted");
- cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u %10u",
+ cli_msg(-1006, " Route change stats: received rejected filtered ignored RX limit IN limit accepted");
+ cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u %10u %10u",
SCI(updates_received), SCI(updates_invalid),
SCI(updates_filtered), SRI(updates_ignored),
- SCI(updates_limited_rx) + SCI(updates_limited_in),
+ SCI(updates_limited_rx), SCI(updates_limited_in),
SRI(updates_accepted));
cli_msg(-1006, " Import withdraws: %10u %10u --- %10u --- %10u",
SCI(withdraws_received), SCI(withdraws_invalid),