0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-17 16:48:43 +00:00

Table import and export are now explicit hooks.

Channels have now included rt_import_req and rt_export_req to hook into
the table instead of just one list node. This will (in future) allow for:

* channel import and export bound to different tables
* more efficient pipe code (dropping most of the channel code)
* conversion of 'show route' to a special kind of export
* temporary static routes from CLI

The import / export states are also updated to the new algorithms.
This commit is contained in:
Maria Matejka 2021-06-21 17:07:31 +02:00
parent 3a8197a9dc
commit f81702b7e4
12 changed files with 1122 additions and 663 deletions

View File

@ -425,6 +425,23 @@ filter_commit(struct config *new, struct config *old)
} }
} }
void channel_filter_dump(const struct filter *f)
{
if (f == FILTER_ACCEPT)
debug(" ALL");
else if (f == FILTER_REJECT)
debug(" NONE");
else if (f == FILTER_UNDEF)
debug(" UNDEF");
else if (f->sym) {
ASSERT(f->sym->filter == f);
debug(" named filter %s", f->sym->name);
} else {
debug("\n");
f_dump_line(f->root, 2);
}
}
void filters_dump_all(void) void filters_dump_all(void)
{ {
struct symbol *sym; struct symbol *sym;
@ -444,19 +461,10 @@ void filters_dump_all(void)
struct channel *c; struct channel *c;
WALK_LIST(c, sym->proto->proto->channels) { WALK_LIST(c, sym->proto->proto->channels) {
debug(" Channel %s (%s) IMPORT", c->name, net_label[c->net_type]); debug(" Channel %s (%s) IMPORT", c->name, net_label[c->net_type]);
if (c->in_filter == FILTER_ACCEPT) channel_filter_dump(c->in_filter);
debug(" ALL\n"); debug(" EXPORT", c->name, net_label[c->net_type]);
else if (c->in_filter == FILTER_REJECT) channel_filter_dump(c->out_filter);
debug(" NONE\n");
else if (c->in_filter == FILTER_UNDEF)
debug(" UNDEF\n");
else if (c->in_filter->sym) {
ASSERT(c->in_filter->sym->filter == c->in_filter);
debug(" named filter %s\n", c->in_filter->sym->name);
} else {
debug("\n"); debug("\n");
f_dump_line(c->in_filter->root, 2);
}
} }
} }
} }

View File

@ -820,8 +820,10 @@ CF_CLI(DUMP NEIGHBORS,,, [[Dump neighbor cache]])
{ neigh_dump_all(); cli_msg(0, ""); } ; { neigh_dump_all(); cli_msg(0, ""); } ;
CF_CLI(DUMP ATTRIBUTES,,, [[Dump attribute cache]]) CF_CLI(DUMP ATTRIBUTES,,, [[Dump attribute cache]])
{ rta_dump_all(); cli_msg(0, ""); } ; { rta_dump_all(); cli_msg(0, ""); } ;
CF_CLI(DUMP ROUTES,,, [[Dump routing table]]) CF_CLI(DUMP ROUTES,,, [[Dump routes]])
{ rt_dump_all(); cli_msg(0, ""); } ; { rt_dump_all(); cli_msg(0, ""); } ;
CF_CLI(DUMP TABLES,,, [[Dump table connections]])
{ rt_dump_hooks_all(); cli_msg(0, ""); } ;
CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]]) CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]])
{ protos_dump_all(); cli_msg(0, ""); } ; { protos_dump_all(); cli_msg(0, ""); } ;
CF_CLI(DUMP FILTER ALL,,, [[Dump all filters in linearized form]]) CF_CLI(DUMP FILTER ALL,,, [[Dump all filters in linearized form]])

View File

@ -43,8 +43,7 @@ static int graceful_restart_state;
static u32 graceful_restart_locks; static u32 graceful_restart_locks;
static char *p_states[] = { "DOWN", "START", "UP", "STOP" }; static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
static char *c_states[] = { "DOWN", "START", "UP", "FLUSHING" }; static char *c_states[] = { "DOWN", "START", "UP", "STOP", "RESTART" };
static char *e_states[] = { "DOWN", "FEEDING", "READY" };
extern struct protocol proto_unix_iface; extern struct protocol proto_unix_iface;
@ -55,12 +54,14 @@ 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_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_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_reset_limit(struct channel *c, struct limit *l, int dir);
static void channel_feed_end(struct channel *c);
static void channel_export_stopped(struct rt_export_request *req);
static inline int proto_is_done(struct proto *p) static inline int proto_is_done(struct proto *p)
{ return (p->proto_state == PS_DOWN) && (p->active_channels == 0); } { return (p->proto_state == PS_DOWN) && (p->active_channels == 0); }
static inline int channel_is_active(struct channel *c) static inline int channel_is_active(struct channel *c)
{ return (c->channel_state == CS_START) || (c->channel_state == CS_UP); } { return (c->channel_state != CS_DOWN); }
static inline int channel_reloadable(struct channel *c) static inline int channel_reloadable(struct channel *c)
{ return c->proto->reload_routes && c->reloadable; } { return c->proto->reload_routes && c->reloadable; }
@ -68,12 +69,48 @@ static inline int channel_reloadable(struct channel *c)
static inline void static inline void
channel_log_state_change(struct channel *c) channel_log_state_change(struct channel *c)
{ {
if (c->export_state)
CD(c, "State changed to %s/%s", c_states[c->channel_state], e_states[c->export_state]);
else
CD(c, "State changed to %s", c_states[c->channel_state]); CD(c, "State changed to %s", c_states[c->channel_state]);
} }
void
channel_import_log_state_change(struct rt_import_request *req, u8 state)
{
struct channel *c = SKIP_BACK(struct channel, in_req, req);
CD(c, "Channel import state changed to %s", rt_import_state_name(state));
}
void
channel_export_log_state_change(struct rt_export_request *req, u8 state)
{
struct channel *c = SKIP_BACK(struct channel, out_req, req);
CD(c, "Channel export state changed to %s", rt_export_state_name(state));
switch (state)
{
case TES_FEEDING:
if (c->proto->feed_begin)
c->proto->feed_begin(c, !c->refeeding);
break;
case TES_READY:
channel_feed_end(c);
break;
}
}
static void
channel_dump_import_req(struct rt_import_request *req)
{
struct channel *c = SKIP_BACK(struct channel, in_req, req);
debug(" Channel %s.%s import request %p\n", c->proto->name, c->name, req);
}
static void
channel_dump_export_req(struct rt_export_request *req)
{
struct channel *c = SKIP_BACK(struct channel, out_req, req);
debug(" Channel %s.%s export request %p\n", c->proto->name, c->name, req);
}
static void static void
proto_log_state_change(struct proto *p) proto_log_state_change(struct proto *p)
{ {
@ -141,6 +178,15 @@ proto_find_channel_by_name(struct proto *p, const char *n)
return NULL; return NULL;
} }
rte * channel_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 * proto_add_channel - connect protocol to a routing table
* @p: protocol instance * @p: protocol instance
@ -165,6 +211,7 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
c->channel = cf->channel; c->channel = cf->channel;
c->proto = p; c->proto = p;
c->table = cf->table->table; c->table = cf->table->table;
rt_lock_table(c->table);
c->in_filter = cf->in_filter; c->in_filter = cf->in_filter;
c->out_filter = cf->out_filter; c->out_filter = cf->out_filter;
@ -182,7 +229,6 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
c->rpki_reload = cf->rpki_reload; c->rpki_reload = cf->rpki_reload;
c->channel_state = CS_DOWN; c->channel_state = CS_DOWN;
c->export_state = ES_DOWN;
c->last_state_change = current_time(); c->last_state_change = current_time();
c->reloadable = 1; c->reloadable = 1;
@ -204,6 +250,7 @@ proto_remove_channel(struct proto *p UNUSED, struct channel *c)
CD(c, "Removed", c->name); CD(c, "Removed", c->name);
rt_unlock_table(c->table);
rem_node(&c->n); rem_node(&c->n);
mb_free(c); mb_free(c);
} }
@ -224,7 +271,7 @@ proto_pause_channels(struct proto *p)
struct channel *c; struct channel *c;
WALK_LIST(c, p->channels) WALK_LIST(c, p->channels)
if (!c->disabled && channel_is_active(c)) if (!c->disabled && channel_is_active(c))
channel_set_state(c, CS_START); channel_set_state(c, CS_PAUSE);
} }
static void static void
@ -233,7 +280,7 @@ proto_stop_channels(struct proto *p)
struct channel *c; struct channel *c;
WALK_LIST(c, p->channels) WALK_LIST(c, p->channels)
if (!c->disabled && channel_is_active(c)) if (!c->disabled && channel_is_active(c))
channel_set_state(c, CS_FLUSHING); channel_set_state(c, CS_STOP);
} }
static void static void
@ -244,69 +291,6 @@ proto_remove_channels(struct proto *p)
proto_remove_channel(p, c); proto_remove_channel(p, c);
} }
static void
channel_schedule_feed(struct channel *c, int initial)
{
// DBG("%s: Scheduling meal\n", p->name);
ASSERT(c->channel_state == CS_UP);
c->export_state = ES_FEEDING;
c->refeeding = !initial;
ev_schedule_work(c->feed_event);
}
static void
channel_feed_loop(void *ptr)
{
struct channel *c = ptr;
if (c->export_state != ES_FEEDING)
return;
/* Start feeding */
if (!c->feed_active)
{
if (c->proto->feed_begin)
c->proto->feed_begin(c, !c->refeeding);
c->refeed_pending = 0;
}
// DBG("Feeding protocol %s continued\n", p->name);
if (!rt_feed_channel(c))
{
ev_schedule_work(c->feed_event);
return;
}
/* Reset export limit if the feed ended with acceptable number of exported routes */
if (c->refeeding &&
(c->limit_active & (1 << PLD_OUT)) &&
(c->refeed_count <= c->out_limit.max))
{
log(L_INFO "Protocol %s resets route export limit (%u)", c->proto->name, c->out_limit.max);
channel_reset_limit(c, &c->out_limit, PLD_OUT);
/* Continue in feed - it will process routing table again from beginning */
c->refeed_count = 0;
ev_schedule_work(c->feed_event);
return;
}
// DBG("Feeding protocol %s finished\n", p->name);
c->export_state = ES_READY;
channel_log_state_change(c);
if (c->proto->feed_end)
c->proto->feed_end(c);
/* Restart feeding */
if (c->refeed_pending)
channel_request_feeding(c);
}
static void static void
channel_roa_in_changed(struct rt_subscription *s) channel_roa_in_changed(struct rt_subscription *s)
{ {
@ -325,14 +309,12 @@ static void
channel_roa_out_changed(struct rt_subscription *s) channel_roa_out_changed(struct rt_subscription *s)
{ {
struct channel *c = s->data; struct channel *c = s->data;
int active = (c->export_state == ES_FEEDING); CD(c, "Feeding triggered by RPKI change");
CD(c, "Feeding triggered by RPKI change%s", active ? " - already active" : "");
if (!active)
channel_request_feeding(c);
else
c->refeed_pending = 1; c->refeed_pending = 1;
if (c->out_req.hook)
rt_stop_export(&c->out_req, channel_export_stopped);
} }
/* Temporary code, subscriptions should be changed to resources */ /* Temporary code, subscriptions should be changed to resources */
@ -444,34 +426,189 @@ channel_roa_unsubscribe_all(struct channel *c)
} }
static void static void
channel_start_export(struct channel *c) channel_start_import(struct channel *c)
{ {
ASSERT(c->channel_state == CS_UP); if (c->in_req.hook)
ASSERT(c->export_state == ES_DOWN); {
log(L_WARN "%s.%s: Attempted to start channel's already started import", c->proto->name, c->name);
return;
}
channel_schedule_feed(c, 1); /* Sets ES_FEEDING */ 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,
.trace_routes = c->debug | c->proto->debug,
.dump_req = channel_dump_import_req,
.log_state_change = channel_import_log_state_change,
.preimport = channel_preimport,
.rte_modify = c->proto->rte_modify,
};
ASSERT(c->channel_state == CS_UP);
channel_reset_limit(c, &c->rx_limit, PLD_RX);
channel_reset_limit(c, &c->in_limit, PLD_IN);
memset(&c->import_stats, 0, sizeof(struct channel_import_stats));
DBG("%s.%s: Channel start import req=%p\n", c->proto->name, c->name, &c->in_req);
rt_request_import(c->table, &c->in_req);
} }
static void static void
channel_stop_export(struct channel *c) channel_start_export(struct channel *c)
{ {
/* Need to abort feeding */ if (c->out_req.hook)
if (c->export_state == ES_FEEDING) {
rt_feed_channel_abort(c); log(L_WARN "%s.%s: Attempted to start channel's already started export", c->proto->name, c->name);
return;
}
c->export_state = ES_DOWN; 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,
.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);
channel_reset_limit(c, &c->out_limit, PLD_OUT); channel_reset_limit(c, &c->out_limit, PLD_OUT);
bmap_reset(&c->export_map, 1024);
bmap_reset(&c->export_reject_map, 1024); memset(&c->export_stats, 0, sizeof(struct channel_export_stats));
switch (c->ra_mode) {
case RA_OPTIMAL:
c->out_req.export_one = rt_notify_optimal;
break;
case RA_ANY:
c->out_req.export_one = rt_notify_any;
c->out_req.export_bulk = rt_feed_any;
break;
case RA_ACCEPTED:
c->out_req.export_bulk = rt_notify_accepted;
break;
case RA_MERGED:
c->out_req.export_bulk = rt_notify_merged;
break;
default:
bug("Unknown route announcement mode");
}
DBG("%s.%s: Channel start export req=%p\n", c->proto->name, c->name, &c->out_req);
rt_request_export(c->table, &c->out_req);
} }
static void
channel_check_stopped(struct channel *c)
{
switch (c->channel_state)
{
case CS_STOP:
if (c->out_req.hook || c->in_req.hook)
return;
channel_set_state(c, CS_DOWN);
ev_schedule(c->proto->event);
break;
case CS_PAUSE:
if (c->out_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(struct rt_import_request *req)
{
struct channel *c = SKIP_BACK(struct channel, in_req, req);
req->hook = NULL;
if (c->in_table)
rt_prune_sync(c->in_table, 1);
mb_free(c->in_req.name);
c->in_req.name = NULL;
channel_check_stopped(c);
}
static void
channel_export_stopped(struct rt_export_request *req)
{
struct channel *c = SKIP_BACK(struct channel, out_req, req);
/* The hook has already stopped */
req->hook = NULL;
if (c->refeed_pending)
{
c->refeeding = 1;
c->refeed_pending = 0;
rt_request_export(c->table, req);
return;
}
/* Free the routes from out_table */
if (c->out_table)
rt_prune_sync(c->out_table, 1);
mb_free(c->out_req.name);
c->out_req.name = NULL;
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 &&
(c->limit_active & (1 << PLD_OUT)) &&
(c->refeed_count <= l->max) &&
(l->count <= l->max))
{
log(L_INFO "Protocol %s resets route export limit (%u)", c->proto->name, l->max);
c->refeed_pending = 1;
rt_stop_export(req, channel_export_stopped);
return;
}
if (c->proto->feed_end)
c->proto->feed_end(c);
if (c->refeed_pending)
rt_stop_export(req, channel_export_stopped);
else
c->refeeding = 0;
}
/* Called by protocol for reload from in_table */ /* Called by protocol for reload from in_table */
void void
channel_schedule_reload(struct channel *c) channel_schedule_reload(struct channel *c)
{ {
ASSERT(c->channel_state == CS_UP); ASSERT(c->in_req.hook);
rt_reload_channel_abort(c); rt_reload_channel_abort(c);
ev_schedule_work(c->reload_event); ev_schedule_work(c->reload_event);
@ -497,23 +634,6 @@ channel_reload_loop(void *ptr)
channel_request_reload(c); channel_request_reload(c);
} }
static void
channel_reset_import(struct channel *c)
{
/* Need to abort feeding */
ev_postpone(c->reload_event);
rt_reload_channel_abort(c);
rt_prune_sync(c->in_table, 1);
}
static void
channel_reset_export(struct channel *c)
{
/* Just free the routes */
rt_prune_sync(c->out_table, 1);
}
/* Called by protocol to activate in_table */ /* Called by protocol to activate in_table */
void void
channel_setup_in_table(struct channel *c) channel_setup_in_table(struct channel *c)
@ -545,22 +665,11 @@ channel_setup_out_table(struct channel *c)
static void static void
channel_do_start(struct channel *c) channel_do_start(struct channel *c)
{ {
rt_lock_table(c->table);
add_tail(&c->table->channels, &c->table_node);
c->proto->active_channels++; c->proto->active_channels++;
c->feed_event = ev_new_init(c->proto->pool, channel_feed_loop, c);
bmap_init(&c->export_map, c->proto->pool, 1024);
bmap_init(&c->export_reject_map, c->proto->pool, 1024);
memset(&c->export_stats, 0, sizeof(struct export_stats));
memset(&c->import_stats, 0, sizeof(struct import_stats));
channel_reset_limit(c, &c->rx_limit, PLD_RX);
channel_reset_limit(c, &c->in_limit, PLD_IN);
channel_reset_limit(c, &c->out_limit, PLD_OUT);
CALL(c->channel->start, c); CALL(c->channel->start, c);
channel_start_import(c);
} }
static void static void
@ -575,9 +684,31 @@ channel_do_up(struct channel *c)
} }
static void static void
channel_do_flush(struct channel *c) channel_do_pause(struct channel *c)
{ {
rt_schedule_prune(c->table); /* Need to abort feeding */
if (c->reload_event)
{
ev_postpone(c->reload_event);
rt_reload_channel_abort(c);
}
/* Stop export */
if (c->out_req.hook)
rt_stop_export(&c->out_req, channel_export_stopped);
channel_roa_unsubscribe_all(c);
bmap_free(&c->export_map);
bmap_free(&c->export_reject_map);
}
static void
channel_do_stop(struct channel *c)
{
/* Stop import */
if (c->in_req.hook)
rt_stop_import(&c->in_req, channel_import_stopped);
c->gr_wait = 0; c->gr_wait = 0;
if (c->gr_lock) if (c->gr_lock)
@ -586,30 +717,21 @@ channel_do_flush(struct channel *c)
CALL(c->channel->shutdown, c); CALL(c->channel->shutdown, c);
/* This have to be done in here, as channel pool is freed before channel_do_down() */ /* This have to be done in here, as channel pool is freed before channel_do_down() */
bmap_free(&c->export_map);
bmap_free(&c->export_reject_map);
c->in_table = NULL; c->in_table = NULL;
c->reload_event = NULL; c->reload_event = NULL;
c->out_table = NULL; c->out_table = NULL;
channel_roa_unsubscribe_all(c);
} }
static void static void
channel_do_down(struct channel *c) channel_do_down(struct channel *c)
{ {
ASSERT(!c->feed_active && !c->reload_active); ASSERT(!c->reload_active);
rem_node(&c->table_node);
rt_unlock_table(c->table);
c->proto->active_channels--; c->proto->active_channels--;
if (c->in_limit.count || c->rx_limit.count)
bug("%s: Channel %s is down but still has some routes", c->proto->name, c->name);
// bmap_free(&c->export_map); // bmap_free(&c->export_map);
memset(&c->import_stats, 0, sizeof(struct import_stats)); memset(&c->import_stats, 0, sizeof(struct channel_import_stats));
memset(&c->export_stats, 0, sizeof(struct export_stats)); memset(&c->export_stats, 0, sizeof(struct channel_export_stats));
c->in_table = NULL; c->in_table = NULL;
c->reload_event = NULL; c->reload_event = NULL;
@ -628,7 +750,6 @@ void
channel_set_state(struct channel *c, uint state) channel_set_state(struct channel *c, uint state)
{ {
uint cs = c->channel_state; uint cs = c->channel_state;
uint es = c->export_state;
DBG("%s reporting channel %s state transition %s -> %s\n", c->proto->name, c->name, c_states[cs], c_states[state]); DBG("%s reporting channel %s state transition %s -> %s\n", c->proto->name, c->name, c_states[cs], c_states[state]);
if (state == cs) if (state == cs)
@ -640,20 +761,11 @@ channel_set_state(struct channel *c, uint state)
switch (state) switch (state)
{ {
case CS_START: case CS_START:
ASSERT(cs == CS_DOWN || cs == CS_UP); ASSERT(cs == CS_DOWN || cs == CS_PAUSE);
if (cs == CS_DOWN) if (cs == CS_DOWN)
channel_do_start(c); channel_do_start(c);
if (es != ES_DOWN)
channel_stop_export(c);
if (c->in_table && (cs == CS_UP))
channel_reset_import(c);
if (c->out_table && (cs == CS_UP))
channel_reset_export(c);
break; break;
case CS_UP: case CS_UP:
@ -668,23 +780,24 @@ channel_set_state(struct channel *c, uint state)
channel_do_up(c); channel_do_up(c);
break; break;
case CS_FLUSHING: case CS_PAUSE:
ASSERT(cs == CS_START || cs == CS_UP); ASSERT(cs == CS_UP);
if (es != ES_DOWN) if (cs == CS_UP)
channel_stop_export(c); channel_do_pause(c);
break;
if (c->in_table && (cs == CS_UP)) case CS_STOP:
channel_reset_import(c); ASSERT(cs == CS_UP || cs == CS_START || cs == CS_PAUSE);
if (c->out_table && (cs == CS_UP)) if (cs == CS_UP)
channel_reset_export(c); channel_do_pause(c);
channel_do_flush(c); channel_do_stop(c);
break; break;
case CS_DOWN: case CS_DOWN:
ASSERT(cs == CS_FLUSHING); ASSERT(cs == CS_STOP);
channel_do_down(c); channel_do_down(c);
break; break;
@ -709,35 +822,16 @@ channel_set_state(struct channel *c, uint state)
void void
channel_request_feeding(struct channel *c) channel_request_feeding(struct channel *c)
{ {
ASSERT(c->channel_state == CS_UP); ASSERT(c->out_req.hook);
CD(c, "Feeding requested"); c->refeed_pending = 1;
rt_stop_export(&c->out_req, channel_export_stopped);
/* Do nothing if we are still waiting for feeding */
if (c->export_state == ES_DOWN)
return;
/* If we are already feeding, we want to restart it */
if (c->export_state == ES_FEEDING)
{
/* Unless feeding is in initial state */
if (!c->feed_active)
return;
rt_feed_channel_abort(c);
}
/* Track number of exported routes during refeed */
c->refeed_count = 0;
channel_schedule_feed(c, 0); /* Sets ES_FEEDING */
channel_log_state_change(c);
} }
static void static void
channel_request_reload(struct channel *c) channel_request_reload(struct channel *c)
{ {
ASSERT(c->channel_state == CS_UP); ASSERT(c->in_req.hook);
ASSERT(channel_reloadable(c)); ASSERT(channel_reloadable(c));
CD(c, "Reload requested"); CD(c, "Reload requested");
@ -861,6 +955,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
c->merge_limit = cf->merge_limit; c->merge_limit = cf->merge_limit;
c->preference = cf->preference; c->preference = cf->preference;
c->debug = cf->debug; 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->in_keep_filtered = cf->in_keep_filtered;
c->rpki_reload = cf->rpki_reload; c->rpki_reload = cf->rpki_reload;
@ -975,8 +1070,8 @@ proto_event(void *ptr)
if (proto_is_done(p)) if (proto_is_done(p))
{ {
if (p->proto->cleanup) rfree(p->pool);
p->proto->cleanup(p); p->pool = NULL;
p->active = 0; p->active = 0;
proto_log_state_change(p); proto_log_state_change(p);
@ -1528,7 +1623,7 @@ graceful_restart_done(timer *t UNUSED)
WALK_LIST(c, p->channels) WALK_LIST(c, p->channels)
{ {
/* Resume postponed export of routes */ /* Resume postponed export of routes */
if ((c->channel_state == CS_UP) && c->gr_wait && c->proto->rt_notify) if ((c->channel_state == CS_UP) && c->gr_wait && p->rt_notify)
channel_start_export(c); channel_start_export(c);
/* Cleanup */ /* Cleanup */
@ -1618,7 +1713,11 @@ protos_dump_all(void)
struct proto *p; struct proto *p;
WALK_LIST(p, proto_list) WALK_LIST(p, proto_list)
{ {
debug(" protocol %s state %s\n", p->name, p_states[p->proto_state]); #define DPF(x) (p->x ? " " #x : "")
debug(" protocol %s (%p) state %s with %d active channels flags: %s%s%s%s%s\n",
p->name, p, p_states[p->proto_state], p->active_channels,
DPF(disabled), DPF(active), DPF(do_start), DPF(do_stop), DPF(reconfiguring));
#undef DPF
struct channel *c; struct channel *c;
WALK_LIST(c, p->channels) WALK_LIST(c, p->channels)
@ -1628,6 +1727,9 @@ protos_dump_all(void)
debug("\tInput filter: %s\n", filter_name(c->in_filter)); debug("\tInput filter: %s\n", filter_name(c->in_filter));
if (c->out_filter) if (c->out_filter)
debug("\tOutput filter: %s\n", filter_name(c->out_filter)); debug("\tOutput filter: %s\n", filter_name(c->out_filter));
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 (p->proto->dump && (p->proto_state != PS_DOWN)) if (p->proto->dump && (p->proto_state != PS_DOWN))
@ -1933,8 +2035,6 @@ proto_do_down(struct proto *p)
{ {
p->down_code = 0; p->down_code = 0;
neigh_prune(); neigh_prune();
rfree(p->pool);
p->pool = NULL;
/* Shutdown is finished in the protocol event */ /* Shutdown is finished in the protocol event */
if (proto_is_done(p)) if (proto_is_done(p))
@ -2029,8 +2129,16 @@ proto_state_name(struct proto *p)
static void static void
channel_show_stats(struct channel *c) channel_show_stats(struct channel *c)
{ {
struct import_stats *is = &c->import_stats; struct channel_import_stats *ch_is = &c->import_stats;
struct export_stats *es = &c->export_stats; struct channel_export_stats *ch_es = &c->export_stats;
struct rt_import_stats *rt_is = c->in_req.hook ? &c->in_req.hook->stats : NULL;
struct rt_export_stats *rt_es = c->out_req.hook ? &c->out_req.hook->stats : NULL;
#define SON(ie, item) ((ie) ? (ie)->item : 0)
#define SCI(item) SON(ch_is, item)
#define SCE(item) SON(ch_es, item)
#define SRI(item) SON(rt_is, item)
#define SRE(item) SON(rt_es, item)
u32 rx_routes = c->rx_limit.count; u32 rx_routes = c->rx_limit.count;
u32 in_routes = c->in_limit.count; u32 in_routes = c->in_limit.count;
@ -2038,24 +2146,31 @@ channel_show_stats(struct channel *c)
if (c->in_keep_filtered) if (c->in_keep_filtered)
cli_msg(-1006, " Routes: %u imported, %u filtered, %u exported, %u preferred", cli_msg(-1006, " Routes: %u imported, %u filtered, %u exported, %u preferred",
in_routes, (rx_routes - in_routes), out_routes, is->pref); in_routes, (rx_routes - in_routes), out_routes, SRI(pref));
else else
cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred", cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred",
in_routes, out_routes, is->pref); in_routes, out_routes, SRI(pref));
cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); 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", cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u %10u %10u",
is->updates_received, is->updates_invalid, SCI(updates_received), SCI(updates_invalid),
is->updates_filtered, is->updates_ignored, SCI(updates_filtered), SRI(updates_ignored),
is->updates_accepted); SCI(updates_limited_rx), SCI(updates_limited_in),
cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u", SRI(updates_accepted));
is->withdraws_received, is->withdraws_invalid, cli_msg(-1006, " Import withdraws: %10u %10u --- %10u --- %10u",
is->withdraws_ignored, is->withdraws_accepted); SCI(withdraws_received), SCI(withdraws_invalid),
cli_msg(-1006, " Export updates: %10u %10u %10u --- %10u", SRI(withdraws_ignored), SRI(withdraws_accepted));
es->updates_received, es->updates_rejected, cli_msg(-1006, " Export updates: %10u %10u %10u --- %10u %10u",
es->updates_filtered, es->updates_accepted); SRE(updates_received), SCE(updates_rejected),
cli_msg(-1006, " Export withdraws: %10u --- --- --- %10u", SCE(updates_filtered), SCE(updates_limited), SCE(updates_accepted));
es->withdraws_received, es->withdraws_accepted); cli_msg(-1006, " Export withdraws: %10u --- --- --- ---%10u",
SRE(withdraws_received), SCE(withdraws_accepted));
#undef SRI
#undef SRE
#undef SCI
#undef SCE
#undef SON
} }
void void
@ -2073,6 +2188,8 @@ channel_show_info(struct channel *c)
{ {
cli_msg(-1006, " Channel %s", c->name); cli_msg(-1006, " Channel %s", c->name);
cli_msg(-1006, " State: %s", c_states[c->channel_state]); cli_msg(-1006, " State: %s", c_states[c->channel_state]);
cli_msg(-1006, " Import state: %s", rt_import_state_name(rt_import_get_state(c->in_req.hook)));
cli_msg(-1006, " Export state: %s", rt_export_state_name(rt_export_get_state(c->out_req.hook)));
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));

View File

@ -77,7 +77,6 @@ struct protocol {
void (*dump)(struct proto *); /* Debugging dump */ void (*dump)(struct proto *); /* Debugging dump */
int (*start)(struct proto *); /* Start the instance */ int (*start)(struct proto *); /* Start the instance */
int (*shutdown)(struct proto *); /* Stop the instance */ int (*shutdown)(struct proto *); /* Stop the instance */
void (*cleanup)(struct proto *); /* Called after shutdown when protocol became hungry/down */
void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */ void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */
void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */ void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */
int (*get_attr)(const struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */ int (*get_attr)(const struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
@ -133,30 +132,6 @@ struct proto_config {
}; };
/* Protocol statistics */ /* Protocol statistics */
struct import_stats {
/* Import - from protocol to core */
u32 pref; /* Number of routes selected as best in the (adjacent) routing table */
u32 updates_received; /* Number of route updates received */
u32 updates_invalid; /* Number of route updates rejected as invalid */
u32 updates_filtered; /* Number of route updates rejected by filters */
u32 updates_ignored; /* Number of route updates rejected as already in route table */
u32 updates_accepted; /* Number of route updates accepted and imported */
u32 withdraws_received; /* Number of route withdraws received */
u32 withdraws_invalid; /* Number of route withdraws rejected as invalid */
u32 withdraws_ignored; /* Number of route withdraws rejected as already not in route table */
u32 withdraws_accepted; /* Number of route withdraws accepted and processed */
};
struct export_stats {
/* Export - from core to protocol */
u32 updates_received; /* Number of route updates received */
u32 updates_rejected; /* Number of route updates rejected by protocol */
u32 updates_filtered; /* Number of route updates rejected by filters */
u32 updates_accepted; /* Number of route updates accepted and exported */
u32 withdraws_received; /* Number of route withdraws received */
u32 withdraws_accepted; /* Number of route withdraws accepted and processed */
};
struct proto { struct proto {
node n; /* Node in global proto_list */ node n; /* Node in global proto_list */
struct protocol *proto; /* Protocol */ struct protocol *proto; /* Protocol */
@ -512,7 +487,6 @@ struct channel_config {
struct channel { struct channel {
node n; /* Node in proto->channels */ node n; /* Node in proto->channels */
node table_node; /* Node in table->channels */
const char *name; /* Channel name (may be NULL) */ const char *name; /* Channel name (may be NULL) */
const struct channel_class *channel; const struct channel_class *channel;
@ -531,10 +505,28 @@ struct channel {
u8 limit_actions[PLD_MAX]; /* Limit actions enum */ u8 limit_actions[PLD_MAX]; /* Limit actions enum */
u8 limit_active; /* Flags for active limits */ u8 limit_active; /* Flags for active limits */
struct event *feed_event; /* Event responsible for feeding */ struct channel_import_stats {
struct fib_iterator feed_fit; /* Routing table iterator used during feeding */ /* Import - from protocol to core */
struct import_stats import_stats; /* Import statistics */ u32 updates_received; /* Number of route updates received */
struct export_stats export_stats; /* Export statistics */ u32 updates_invalid; /* Number of route updates rejected as invalid */
u32 updates_filtered; /* Number of route updates rejected by filters */
u32 updates_limited_rx; /* Number of route updates exceeding the rx_limit */
u32 updates_limited_in; /* Number of route updates exceeding the in_limit */
u32 withdraws_received; /* Number of route withdraws received */
u32 withdraws_invalid; /* Number of route withdraws rejected as invalid */
} import_stats;
struct channel_export_stats {
/* Export - from core to protocol */
u32 updates_rejected; /* Number of route updates rejected by protocol */
u32 updates_filtered; /* Number of route updates rejected by filters */
u32 updates_accepted; /* Number of route updates accepted and exported */
u32 updates_limited; /* Number of route updates exceeding the out_limit */
u32 withdraws_accepted; /* Number of route withdraws accepted and processed */
} export_stats;
struct rt_import_request in_req; /* Table import connection */
struct rt_export_request out_req; /* Table export connection */
u32 refeed_count; /* Number of routes exported during refeed regardless of out_limit */ u32 refeed_count; /* Number of routes exported during refeed regardless of out_limit */
@ -548,10 +540,7 @@ struct channel {
u8 stale; /* Used in reconfiguration */ u8 stale; /* Used in reconfiguration */
u8 channel_state; u8 channel_state;
u8 export_state; /* Route export state (ES_*, see below) */ u8 refeeding; /* Refeeding the channel. */
u8 feed_active;
u8 flush_active;
u8 refeeding; /* We are refeeding (valid only if export_state == ES_FEEDING) */
u8 reloadable; /* Hook reload_routes() is allowed on the channel */ u8 reloadable; /* Hook reload_routes() is allowed on the channel */
u8 gr_lock; /* Graceful restart mechanism should wait for this channel */ u8 gr_lock; /* Graceful restart mechanism should wait for this channel */
u8 gr_wait; /* Route export to channel is postponed until graceful restart */ u8 gr_wait; /* Route export to channel is postponed until graceful restart */
@ -599,34 +588,34 @@ struct channel {
* restricted by that and is on volition of the protocol. Generally, channels * restricted by that and is on volition of the protocol. Generally, channels
* are opened in protocols' start() hooks when going to PS_UP. * are opened in protocols' start() hooks when going to PS_UP.
* *
* CS_FLUSHING - The transitional state between initialized channel and closed * CS_STOP - The transitional state between initialized channel and closed
* channel. The channel is still initialized, but no route exchange is allowed. * channel. The channel is still initialized, but no route exchange is allowed.
* Instead, the associated table is running flush loop to remove routes imported * Instead, the associated table is running flush loop to remove routes imported
* through the channel. After that, the channel changes state to CS_DOWN and * through the channel. After that, the channel changes state to CS_DOWN and
* is detached from the table (the table is unlocked and the channel is unlinked * is detached from the table (the table is unlocked and the channel is unlinked
* from it). Unlike other states, the CS_FLUSHING state is not explicitly * from it). Unlike other states, the CS_STOP state is not explicitly
* entered or left by the protocol. A protocol may request to close a channel * entered or left by the protocol. A protocol may request to close a channel
* (by calling channel_close()), which causes the channel to change state to * (by calling channel_close()), which causes the channel to change state to
* CS_FLUSHING and later to CS_DOWN. Also note that channels are closed * CS_STOP and later to CS_DOWN. Also note that channels are closed
* automatically by the core when the protocol is going down. * automatically by the core when the protocol is going down.
* *
* CS_PAUSE - Almost the same as CS_STOP, just the table import is kept and
* the table export is stopped before transitioning to CS_START.
*
* Allowed transitions: * Allowed transitions:
* *
* CS_DOWN -> CS_START / CS_UP * CS_DOWN -> CS_START / CS_UP
* CS_START -> CS_UP / CS_FLUSHING * CS_START -> CS_UP / CS_STOP
* CS_UP -> CS_START / CS_FLUSHING * CS_UP -> CS_PAUSE / CS_STOP
* CS_FLUSHING -> CS_DOWN (automatic) * CS_PAUSE -> CS_START (automatic)
* CS_STOP -> CS_DOWN (automatic)
*/ */
#define CS_DOWN 0 #define CS_DOWN 0
#define CS_START 1 #define CS_START 1
#define CS_UP 2 #define CS_UP 2
#define CS_FLUSHING 3 #define CS_STOP 3
#define CS_PAUSE 4
#define ES_DOWN 0
#define ES_FEEDING 1
#define ES_READY 2
struct channel_config *proto_cf_find_channel(struct proto_config *p, uint net_type); struct channel_config *proto_cf_find_channel(struct proto_config *p, uint net_type);
static inline struct channel_config *proto_cf_main_channel(struct proto_config *pc) static inline struct channel_config *proto_cf_main_channel(struct proto_config *pc)
@ -644,7 +633,7 @@ void channel_schedule_reload(struct channel *c);
static inline void channel_init(struct channel *c) { channel_set_state(c, CS_START); } static inline void channel_init(struct channel *c) { channel_set_state(c, CS_START); }
static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP); } 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_STOP); }
void channel_request_feeding(struct channel *c); void channel_request_feeding(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);

View File

@ -2,6 +2,7 @@
* BIRD Internet Routing Daemon -- Routing Table * BIRD Internet Routing Daemon -- Routing Table
* *
* (c) 1998--2000 Martin Mares <mj@ucw.cz> * (c) 1998--2000 Martin Mares <mj@ucw.cz>
* (c) 2019--2021 Maria Matejka <mq@jmq.cz>
* *
* Can be freely distributed and used under the terms of the GNU GPL. * Can be freely distributed and used under the terms of the GNU GPL.
*/ */
@ -17,6 +18,7 @@
struct ea_list; struct ea_list;
struct protocol; struct protocol;
struct proto; struct proto;
struct channel;
struct rte_src; struct rte_src;
struct symbol; struct symbol;
struct timer; struct timer;
@ -160,12 +162,12 @@ typedef struct rtable {
struct slab *rte_slab; /* Slab to allocate route objects */ struct slab *rte_slab; /* Slab to allocate route objects */
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) */
uint addr_type; /* Type of address data stored in table (NET_*) */ uint addr_type; /* Type of address data stored in table (NET_*) */
int use_count; /* Number of protocols using this table */ int use_count; /* Number of protocols using this table */
u32 rt_count; /* Number of routes in the table */ u32 rt_count; /* Number of routes in the table */
byte internal; /* Internal table of a protocol */ list imports; /* Registered route importers */
list exports; /* Registered route exporters */
struct hmap id_map; struct hmap id_map;
struct hostcache *hostcache; struct hostcache *hostcache;
@ -182,6 +184,7 @@ typedef struct rtable {
byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */ byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
byte hcu_scheduled; /* Hostcache update is scheduled */ byte hcu_scheduled; /* Hostcache update is scheduled */
byte nhu_state; /* Next Hop Update state */ byte nhu_state; /* Next Hop Update state */
byte internal; /* This table is internal for some other object */
struct fib_iterator prune_fit; /* Rtable prune FIB iterator */ struct fib_iterator prune_fit; /* Rtable prune FIB iterator */
struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */ struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */
struct tbf rl_pipe; /* Rate limiting token buffer for pipe collisions */ struct tbf rl_pipe; /* Rate limiting token buffer for pipe collisions */
@ -238,7 +241,7 @@ typedef struct rte {
struct rta *attrs; /* Attributes of this route */ struct rta *attrs; /* Attributes of this route */
const net_addr *net; /* Network this RTE belongs to */ const net_addr *net; /* Network this RTE belongs to */
struct rte_src *src; /* Route source that created the route */ struct rte_src *src; /* Route source that created the route */
struct channel *sender; /* Channel used to send the route to the routing table */ struct rt_import_hook *sender; /* Import hook used to send the route to the routing table */
btime lastmod; /* Last modified (set by table) */ btime lastmod; /* Last modified (set by table) */
u32 id; /* Table specific route id */ u32 id; /* Table specific route id */
byte flags; /* Table-specific flags */ byte flags; /* Table-specific flags */
@ -262,12 +265,127 @@ struct rte_storage {
#define REF_MODIFY 16 /* Route is scheduled for modify */ #define REF_MODIFY 16 /* Route is scheduled for modify */
/* Route is valid for propagation (may depend on other flags in the future), accepts NULL */ /* Route is valid for propagation (may depend on other flags in the future), accepts NULL */
static inline int rte_is_valid(rte *r) { return r && !(r->flags & REF_FILTERED); } static inline int rte_is_valid(const rte *r) { return r && !(r->flags & REF_FILTERED); }
/* Route just has REF_FILTERED flag */ /* Route just has REF_FILTERED flag */
static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED); } static inline int rte_is_filtered(const rte *r) { return !!(r->flags & REF_FILTERED); }
/* Table-channel connections */
struct rt_import_request {
struct rt_import_hook *hook; /* The table part of importer */
char *name;
u8 trace_routes;
void (*dump_req)(struct rt_import_request *req);
void (*log_state_change)(struct rt_import_request *req, u8 state);
/* Preimport is called when the @new route is just-to-be inserted, replacing @old.
* Return a route (may be different or modified in-place) to continue or NULL to withdraw. */
struct rte *(*preimport)(struct rt_import_request *req, struct rte *new, struct rte *old);
struct rte *(*rte_modify)(struct rte *, struct linpool *);
};
struct rt_import_hook {
node n;
rtable *table; /* The connected table */
struct rt_import_request *req; /* The requestor */
struct rt_import_stats {
/* Import - from protocol to core */
u32 pref; /* Number of routes selected as best in the (adjacent) routing table */
u32 updates_ignored; /* Number of route updates rejected as already in route table */
u32 updates_accepted; /* Number of route updates accepted and imported */
u32 withdraws_ignored; /* Number of route withdraws rejected as already not in route table */
u32 withdraws_accepted; /* Number of route withdraws accepted and processed */
} stats;
btime last_state_change; /* Time of last state transition */
u8 import_state; /* IS_* */
void (*stopped)(struct rt_import_request *); /* Stored callback when import is stopped */
};
struct rt_pending_export {
struct rte_storage *new, *new_best, *old, *old_best;
};
struct rt_export_request {
struct rt_export_hook *hook; /* Table part of the export */
char *name;
u8 trace_routes;
/* There are two methods of export. You can either request feeding every single change
* or feeding the whole route feed. In case of regular export, &export_one is preferred.
* Anyway, when feeding, &export_bulk is preferred, falling back to &export_one.
* Thus, for RA_OPTIMAL, &export_one is only set,
* for RA_MERGED and RA_ACCEPTED, &export_bulk is only set
* and for RA_ANY, both are set to accomodate for feeding all routes but receiving single changes
*/
void (*export_one)(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe);
void (*export_bulk)(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe, rte **feed, uint count);
void (*dump_req)(struct rt_export_request *req);
void (*log_state_change)(struct rt_export_request *req, u8);
};
struct rt_export_hook {
node n;
rtable *table; /* The connected table */
pool *pool;
linpool *lp;
struct rt_export_request *req; /* The requestor */
struct rt_export_stats {
/* Export - from core to protocol */
u32 updates_received; /* Number of route updates received */
u32 withdraws_received; /* Number of route withdraws received */
} stats;
struct fib_iterator feed_fit; /* Routing table iterator used during feeding */
btime last_state_change; /* Time of last state transition */
u8 refeed_pending; /* Refeeding and another refeed is scheduled */
u8 export_state; /* Route export state (TES_*, see below) */
struct event *event; /* Event running all the export operations */
void (*stopped)(struct rt_export_request *); /* Stored callback when export is stopped */
};
#define TIS_DOWN 0
#define TIS_UP 1
#define TIS_STOP 2
#define TIS_FLUSHING 3
#define TIS_WAITING 4
#define TIS_CLEARED 5
#define TIS_MAX 6
#define TES_DOWN 0
#define TES_HUNGRY 1
#define TES_FEEDING 2
#define TES_READY 3
#define TES_STOP 4
#define TES_MAX 5
void rt_request_import(rtable *tab, struct rt_import_request *req);
void rt_request_export(rtable *tab, struct rt_export_request *req);
void rt_stop_import(struct rt_import_request *, void (*stopped)(struct rt_import_request *));
void rt_stop_export(struct rt_export_request *, void (*stopped)(struct rt_export_request *));
const char *rt_import_state_name(u8 state);
const char *rt_export_state_name(u8 state);
static inline u8 rt_import_get_state(struct rt_import_hook *ih) { return ih ? ih->import_state : TIS_DOWN; }
static inline u8 rt_export_get_state(struct rt_export_hook *eh) { return eh ? eh->export_state : TES_DOWN; }
void rte_import(struct rt_import_request *req, const net_addr *net, rte *new, struct rte_src *src);
/* Types of route announcement, also used as flags */ /* Types of route announcement, also used as flags */
#define RA_UNDEF 0 /* Undefined RA type */ #define RA_UNDEF 0 /* Undefined RA type */
#define RA_OPTIMAL 1 /* Announcement of optimal route change */ #define RA_OPTIMAL 1 /* Announcement of optimal route change */
@ -281,6 +399,7 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED);
#define RIC_REJECT -1 /* Rejected by protocol */ #define RIC_REJECT -1 /* Rejected by protocol */
#define RIC_DROP -2 /* Silently dropped by protocol */ #define RIC_DROP -2 /* Silently dropped by protocol */
#define rte_update channel_rte_import
/** /**
* rte_update - enter a new update to a routing table * rte_update - enter a new update to a routing table
* @c: channel doing the update * @c: channel doing the update
@ -335,23 +454,24 @@ static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) f
void *net_route(rtable *tab, const net_addr *n); void *net_route(rtable *tab, const net_addr *n);
int net_roa_check(rtable *tab, const net_addr *n, u32 asn); int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter); int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
rte *rt_export_merged_show(struct channel *c, net *n, linpool *pool); rte *rt_export_merged(struct channel *c, rte ** feed, uint count, linpool *pool, int silent);
void rt_refresh_begin(rtable *t, struct channel *c); void rt_refresh_begin(rtable *t, struct rt_import_request *);
void rt_refresh_end(rtable *t, struct channel *c); void rt_refresh_end(rtable *t, struct rt_import_request *);
void rt_modify_stale(rtable *t, struct channel *c); void rt_modify_stale(rtable *t, struct rt_import_request *);
void rt_schedule_prune(rtable *t); void rt_schedule_prune(rtable *t);
void rte_dump(struct rte_storage *); void rte_dump(struct rte_storage *);
void rte_free(struct rte_storage *, rtable *); void rte_free(struct rte_storage *, rtable *);
struct rte_storage *rte_store(const rte *, net *net, rtable *); struct rte_storage *rte_store(const rte *, net *net, rtable *);
void rt_dump(rtable *); void rt_dump(rtable *);
void rt_dump_all(void); void rt_dump_all(void);
int rt_feed_channel(struct channel *c); void rt_dump_hooks(rtable *);
void rt_feed_channel_abort(struct channel *c); void rt_dump_hooks_all(void);
int rt_reload_channel(struct channel *c); int rt_reload_channel(struct channel *c);
void rt_reload_channel_abort(struct channel *c); void rt_reload_channel_abort(struct channel *c);
void rt_refeed_channel(struct channel *c); void rt_refeed_channel(struct channel *c);
void rt_prune_sync(rtable *t, int all); void rt_prune_sync(rtable *t, int all);
int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old, struct rte_storage **old_exported); int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
int rte_update_out(struct channel *c, const net_addr *n, rte *new, const rte *old, struct rte_storage **old_exported);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type); struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
@ -377,6 +497,7 @@ struct rt_show_data {
struct channel *export_channel; struct channel *export_channel;
struct config *running_on_config; struct config *running_on_config;
struct krt_proto *kernel; struct krt_proto *kernel;
struct rt_export_hook *kernel_export_hook;
int export_mode, primary_only, filtered, stats, show_for; int export_mode, primary_only, filtered, stats, show_for;
int table_open; /* Iteration (fit) is open */ int table_open; /* Iteration (fit) is open */

View File

@ -98,6 +98,29 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
rta_show(c, a); rta_show(c, a);
} }
static uint
rte_feed_count(net *n)
{
uint count = 0;
for (struct rte_storage *e = n->routes; e; e = e->next)
if (rte_is_valid(RTE_OR_NULL(e)))
count++;
return count;
}
static void
rte_feed_obtain(net *n, rte **feed, uint count)
{
uint i = 0;
for (struct rte_storage *e = n->routes; e; e = e->next)
if (rte_is_valid(RTE_OR_NULL(e)))
{
ASSERT_DIE(i < count);
feed[i++] = &e->rte;
}
ASSERT_DIE(i == count);
}
static void static void
rt_show_net(struct cli *c, net *n, struct rt_show_data *d) rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
{ {
@ -128,7 +151,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
struct rte e = er->rte; struct rte e = er->rte;
/* Export channel is down, do not try to export routes to it */ /* Export channel is down, do not try to export routes to it */
if (ec && (ec->export_state == ES_DOWN)) if (ec && !ec->out_req.hook)
goto skip; goto skip;
if (d->export_mode == RSEM_EXPORTED) if (d->export_mode == RSEM_EXPORTED)
@ -143,7 +166,14 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
{ {
/* Special case for merged export */ /* Special case for merged export */
pass = 1; pass = 1;
rte *em = rt_export_merged_show(ec, n, c->show_pool); uint count = rte_feed_count(n);
if (!count)
goto skip;
rte **feed = alloca(count * sizeof(rte *));
rte_feed_obtain(n, feed, count);
rte *em = rt_export_merged(ec, feed, count, c->show_pool, 1);
if (em) if (em)
e = *em; e = *em;
else else
@ -315,7 +345,7 @@ rt_show_get_default_tables(struct rt_show_data *d)
{ {
WALK_LIST(c, d->export_protocol->channels) WALK_LIST(c, d->export_protocol->channels)
{ {
if (c->export_state == ES_DOWN) if (!c->out_req.hook)
continue; continue;
tab = rt_show_add_table(d, c->table); tab = rt_show_add_table(d, c->table);

File diff suppressed because it is too large Load Diff

View File

@ -775,25 +775,25 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
{ {
case BGP_GRS_NONE: case BGP_GRS_NONE:
c->gr_active = BGP_GRS_ACTIVE; c->gr_active = BGP_GRS_ACTIVE;
rt_refresh_begin(c->c.table, &c->c); rt_refresh_begin(c->c.table, &c->c.in_req);
break; break;
case BGP_GRS_ACTIVE: case BGP_GRS_ACTIVE:
rt_refresh_end(c->c.table, &c->c); rt_refresh_end(c->c.table, &c->c.in_req);
rt_refresh_begin(c->c.table, &c->c); rt_refresh_begin(c->c.table, &c->c.in_req);
break; break;
case BGP_GRS_LLGR: case BGP_GRS_LLGR:
rt_refresh_begin(c->c.table, &c->c); rt_refresh_begin(c->c.table, &c->c.in_req);
rt_modify_stale(c->c.table, &c->c); rt_modify_stale(c->c.table, &c->c.in_req);
break; break;
} }
} }
else else
{ {
/* Just flush the routes */ /* Just flush the routes */
rt_refresh_begin(c->c.table, &c->c); rt_refresh_begin(c->c.table, &c->c.in_req);
rt_refresh_end(c->c.table, &c->c); rt_refresh_end(c->c.table, &c->c.in_req);
} }
/* Reset bucket and prefix tables */ /* Reset bucket and prefix tables */
@ -834,7 +834,7 @@ bgp_graceful_restart_done(struct bgp_channel *c)
BGP_TRACE(D_EVENTS, "Neighbor graceful restart done"); BGP_TRACE(D_EVENTS, "Neighbor graceful restart done");
tm_stop(c->stale_timer); tm_stop(c->stale_timer);
rt_refresh_end(c->c.table, &c->c); rt_refresh_end(c->c.table, &c->c.in_req);
} }
/** /**
@ -876,7 +876,7 @@ bgp_graceful_restart_timeout(timer *t)
/* Channel is in GR, and supports LLGR -> start LLGR */ /* Channel is in GR, and supports LLGR -> start LLGR */
c->gr_active = BGP_GRS_LLGR; c->gr_active = BGP_GRS_LLGR;
tm_start(c->stale_timer, c->stale_time S); tm_start(c->stale_timer, c->stale_time S);
rt_modify_stale(c->c.table, &c->c); rt_modify_stale(c->c.table, &c->c.in_req);
} }
} }
else else
@ -914,10 +914,10 @@ bgp_refresh_begin(struct bgp_channel *c)
{ log(L_WARN "%s: BEGIN-OF-RR received before END-OF-RIB, ignoring", p->p.name); return; } { log(L_WARN "%s: BEGIN-OF-RR received before END-OF-RIB, ignoring", p->p.name); return; }
c->load_state = BFS_REFRESHING; c->load_state = BFS_REFRESHING;
rt_refresh_begin(c->c.table, &c->c); rt_refresh_begin(c->c.table, &c->c.in_req);
if (c->c.in_table) if (c->c.in_table)
rt_refresh_begin(c->c.in_table, &c->c); rt_refresh_begin(c->c.in_table, &c->c.in_req);
} }
/** /**
@ -938,7 +938,7 @@ bgp_refresh_end(struct bgp_channel *c)
{ log(L_WARN "%s: END-OF-RR received without prior BEGIN-OF-RR, ignoring", p->p.name); return; } { log(L_WARN "%s: END-OF-RR received without prior BEGIN-OF-RR, ignoring", p->p.name); return; }
c->load_state = BFS_NONE; c->load_state = BFS_NONE;
rt_refresh_end(c->c.table, &c->c); rt_refresh_end(c->c.table, &c->c.in_req);
if (c->c.in_table) if (c->c.in_table)
rt_prune_sync(c->c.in_table, 0); rt_prune_sync(c->c.in_table, 0);

View File

@ -82,7 +82,7 @@ pipe_preexport(struct channel *c, rte *e)
struct pipe_proto *p = (void *) c->proto; struct pipe_proto *p = (void *) c->proto;
/* Avoid direct loopbacks */ /* Avoid direct loopbacks */
if (e->sender == c) if (e->sender == c->in_req.hook)
return -1; return -1;
/* Indirection check */ /* Indirection check */
@ -212,10 +212,15 @@ pipe_get_status(struct proto *P, byte *buf)
static void static void
pipe_show_stats(struct pipe_proto *p) pipe_show_stats(struct pipe_proto *p)
{ {
struct import_stats *s1i = &p->pri->import_stats; struct channel_import_stats *s1i = &p->pri->import_stats;
struct export_stats *s1e = &p->pri->export_stats; struct channel_export_stats *s1e = &p->pri->export_stats;
struct import_stats *s2i = &p->sec->import_stats; struct channel_import_stats *s2i = &p->sec->import_stats;
struct export_stats *s2e = &p->sec->export_stats; struct channel_export_stats *s2e = &p->sec->export_stats;
struct rt_import_stats *rs1i = p->pri->in_req.hook ? &p->pri->in_req.hook->stats : NULL;
struct rt_export_stats *rs1e = p->pri->out_req.hook ? &p->pri->out_req.hook->stats : NULL;
struct rt_import_stats *rs2i = p->sec->in_req.hook ? &p->sec->in_req.hook->stats : NULL;
struct rt_export_stats *rs2e = p->sec->out_req.hook ? &p->sec->out_req.hook->stats : NULL;
u32 pri_routes = p->pri->in_limit.count; u32 pri_routes = p->pri->in_limit.count;
u32 sec_routes = p->sec->in_limit.count; u32 sec_routes = p->sec->in_limit.count;
@ -245,21 +250,19 @@ pipe_show_stats(struct pipe_proto *p)
pri_routes, sec_routes); pri_routes, sec_routes);
cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted");
cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u",
s2e->updates_received, s2e->updates_rejected + s1i->updates_invalid, rs2e->updates_received, s2e->updates_rejected + s1i->updates_invalid,
s2e->updates_filtered, s1i->updates_ignored, s1i->updates_accepted); s2e->updates_filtered, rs1i->updates_ignored, rs1i->updates_accepted);
cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u", cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u",
s2e->withdraws_received, s1i->withdraws_invalid, rs2e->withdraws_received, s1i->withdraws_invalid,
s1i->withdraws_ignored, s1i->withdraws_accepted); rs1i->withdraws_ignored, rs1i->withdraws_accepted);
cli_msg(-1006, " Export updates: %10u %10u %10u %10u %10u", cli_msg(-1006, " Export updates: %10u %10u %10u %10u %10u",
s1e->updates_received, s1e->updates_rejected + s2i->updates_invalid, rs1e->updates_received, s1e->updates_rejected + s2i->updates_invalid,
s1e->updates_filtered, s2i->updates_ignored, s2i->updates_accepted); s1e->updates_filtered, rs2i->updates_ignored, rs2i->updates_accepted);
cli_msg(-1006, " Export withdraws: %10u %10u --- %10u %10u", cli_msg(-1006, " Export withdraws: %10u %10u --- %10u %10u",
s1e->withdraws_received, s2i->withdraws_invalid, rs1e->withdraws_received, s2i->withdraws_invalid,
s2i->withdraws_ignored, s2i->withdraws_accepted); rs2i->withdraws_ignored, rs2i->withdraws_accepted);
} }
static const char *pipe_feed_state[] = { [ES_DOWN] = "down", [ES_FEEDING] = "feed", [ES_READY] = "up" };
static void static void
pipe_show_proto_info(struct proto *P) pipe_show_proto_info(struct proto *P)
{ {
@ -268,8 +271,8 @@ pipe_show_proto_info(struct proto *P)
cli_msg(-1006, " Channel %s", "main"); cli_msg(-1006, " Channel %s", "main");
cli_msg(-1006, " Table: %s", p->pri->table->name); cli_msg(-1006, " Table: %s", p->pri->table->name);
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", rt_export_state_name(rt_export_get_state(p->sec->out_req.hook)));
cli_msg(-1006, " Export state: %s", pipe_feed_state[p->pri->export_state]); cli_msg(-1006, " Export state: %s", rt_export_state_name(rt_export_get_state(p->pri->out_req.hook)));
cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter)); cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_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));

View File

@ -661,9 +661,9 @@ rpki_handle_cache_response_pdu(struct rpki_cache *cache, const struct pdu_cache_
* a refresh cycle. * a refresh cycle.
*/ */
if (cache->p->roa4_channel) if (cache->p->roa4_channel)
rt_refresh_begin(cache->p->roa4_channel->table, cache->p->roa4_channel); rt_refresh_begin(cache->p->roa4_channel->table, &cache->p->roa4_channel->in_req);
if (cache->p->roa6_channel) if (cache->p->roa6_channel)
rt_refresh_begin(cache->p->roa6_channel->table, cache->p->roa6_channel); rt_refresh_begin(cache->p->roa6_channel->table, &cache->p->roa6_channel->in_req);
cache->p->refresh_channels = 1; cache->p->refresh_channels = 1;
} }
@ -819,9 +819,9 @@ rpki_handle_end_of_data_pdu(struct rpki_cache *cache, const struct pdu_end_of_da
{ {
cache->p->refresh_channels = 0; cache->p->refresh_channels = 0;
if (cache->p->roa4_channel) if (cache->p->roa4_channel)
rt_refresh_end(cache->p->roa4_channel->table, cache->p->roa4_channel); rt_refresh_end(cache->p->roa4_channel->table, &cache->p->roa4_channel->in_req);
if (cache->p->roa6_channel) if (cache->p->roa6_channel)
rt_refresh_end(cache->p->roa6_channel->table, cache->p->roa6_channel); rt_refresh_end(cache->p->roa6_channel->table, &cache->p->roa6_channel->in_req);
} }
cache->last_update = current_time(); cache->last_update = current_time();

View File

@ -507,19 +507,13 @@ static_shutdown(struct proto *P)
WALK_LIST(r, cf->routes) WALK_LIST(r, cf->routes)
static_reset_rte(p, r); static_reset_rte(p, r);
return PS_DOWN;
}
static void
static_cleanup(struct proto *P)
{
struct static_proto *p = (void *) P;
if (p->igp_table_ip4) if (p->igp_table_ip4)
rt_unlock_table(p->igp_table_ip4); rt_unlock_table(p->igp_table_ip4);
if (p->igp_table_ip6) if (p->igp_table_ip6)
rt_unlock_table(p->igp_table_ip6); rt_unlock_table(p->igp_table_ip6);
return PS_DOWN;
} }
static void static void
@ -777,7 +771,6 @@ struct protocol proto_static = {
.dump = static_dump, .dump = static_dump,
.start = static_start, .start = static_start,
.shutdown = static_shutdown, .shutdown = static_shutdown,
.cleanup = static_cleanup,
.reconfigure = static_reconfigure, .reconfigure = static_reconfigure,
.copy_config = static_copy_config, .copy_config = static_copy_config,
.get_route_info = static_get_route_info, .get_route_info = static_get_route_info,

View File

@ -542,6 +542,29 @@ krt_is_installed(struct krt_proto *p, net *n)
return n->routes && bmap_test(&p->p.main_channel->export_map, n->routes->rte.id); return n->routes && bmap_test(&p->p.main_channel->export_map, n->routes->rte.id);
} }
static uint
rte_feed_count(net *n)
{
uint count = 0;
for (struct rte_storage *e = n->routes; e; e = e->next)
if (rte_is_valid(RTE_OR_NULL(e)))
count++;
return count;
}
static void
rte_feed_obtain(net *n, rte **feed, uint count)
{
uint i = 0;
for (struct rte_storage *e = n->routes; e; e = e->next)
if (rte_is_valid(RTE_OR_NULL(e)))
{
ASSERT_DIE(i < count);
feed[i++] = &e->rte;
}
ASSERT_DIE(i == count);
}
static struct rte * static struct rte *
krt_export_net(struct krt_proto *p, net *net) krt_export_net(struct krt_proto *p, net *net)
{ {
@ -549,7 +572,15 @@ krt_export_net(struct krt_proto *p, net *net)
const struct filter *filter = c->out_filter; const struct filter *filter = c->out_filter;
if (c->ra_mode == RA_MERGED) if (c->ra_mode == RA_MERGED)
return rt_export_merged_show(c, net, krt_filter_lp); {
uint count = rte_feed_count(net);
if (!count)
return NULL;
rte **feed = alloca(count * sizeof(rte *));
rte_feed_obtain(net, feed, count);
return rt_export_merged(c, feed, count, krt_filter_lp, 1);
}
static _Thread_local rte rt; static _Thread_local rte rt;
rt = net->routes->rte; rt = net->routes->rte;