Implements generalized import hooks.
Thanks to Alexander V. Chernikov for the original patch.
This commit is contained in:
parent
ae8b300164
commit
ebecb6f6a1
13 changed files with 328 additions and 72 deletions
|
@ -431,6 +431,14 @@ to zero to disable it. An empty <cf><m/switch/</cf> is equivalent to <cf/on/
|
||||||
<tag>export <m/filter/</tag> This is similar to the <cf>import</cf> keyword, except that it
|
<tag>export <m/filter/</tag> This is similar to the <cf>import</cf> keyword, except that it
|
||||||
works in the direction from the routing table to the protocol. Default: <cf/none/.
|
works in the direction from the routing table to the protocol. Default: <cf/none/.
|
||||||
|
|
||||||
|
<tag>import limit <m/number/ exceed warn | block | restart | disable</tag>
|
||||||
|
Specify an import route limit and the action to be taken when
|
||||||
|
the limit is hit. Warn action just prints warning log
|
||||||
|
message. Block action ignores new routes (and converts route
|
||||||
|
updates to withdraws) coming from the protocol. Restart and
|
||||||
|
disable actions shut the protocol down like appropriate
|
||||||
|
commands. Default: <cf/none/.
|
||||||
|
|
||||||
<tag>description "<m/text/"</tag> This is an optional
|
<tag>description "<m/text/"</tag> This is an optional
|
||||||
description of the protocol. It is displayed as a part of the
|
description of the protocol. It is displayed as a part of the
|
||||||
output of 'show route all' command.
|
output of 'show route all' command.
|
||||||
|
@ -1327,7 +1335,8 @@ for each neighbor using the following configuration parameters:
|
||||||
|
|
||||||
<tag>route limit <m/number/</tag> The maximal number of routes
|
<tag>route limit <m/number/</tag> The maximal number of routes
|
||||||
that may be imported from the protocol. If the route limit is
|
that may be imported from the protocol. If the route limit is
|
||||||
exceeded, the connection is closed with error. Default: no limit.
|
exceeded, the connection is closed with error. Limit is currently implemented as
|
||||||
|
<cf/import limit number exceed restart/. Default: no limit.
|
||||||
|
|
||||||
<tag>disable after error <m/switch/</tag> When an error is encountered (either
|
<tag>disable after error <m/switch/</tag> When an error is encountered (either
|
||||||
locally or by the other side), disable the instance automatically
|
locally or by the other side), disable the instance automatically
|
||||||
|
|
|
@ -44,6 +44,7 @@ CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
|
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
|
||||||
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
|
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
|
||||||
|
CF_KEYWORDS(EXCEED, LIMIT, WARN, BLOCK, RESTART, DISABLE)
|
||||||
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
|
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
|
||||||
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE, ROA, MAX, FLUSH)
|
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE, ROA, MAX, FLUSH)
|
||||||
CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION)
|
CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION)
|
||||||
|
@ -64,8 +65,9 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
|
||||||
%type <ro> roa_args
|
%type <ro> roa_args
|
||||||
%type <rot> roa_table_arg
|
%type <rot> roa_table_arg
|
||||||
%type <sd> sym_args
|
%type <sd> sym_args
|
||||||
%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport roa_mode
|
%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport roa_mode limit_action
|
||||||
%type <ps> proto_patt proto_patt2
|
%type <ps> proto_patt proto_patt2
|
||||||
|
%type <g> limit_spec
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
|
@ -176,6 +178,7 @@ proto_item:
|
||||||
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
|
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
|
||||||
| IMPORT imexport { this_proto->in_filter = $2; }
|
| IMPORT imexport { this_proto->in_filter = $2; }
|
||||||
| EXPORT imexport { this_proto->out_filter = $2; }
|
| EXPORT imexport { this_proto->out_filter = $2; }
|
||||||
|
| IMPORT LIMIT limit_spec { this_proto->in_limit = $3; }
|
||||||
| TABLE rtable { this_proto->table = $2; }
|
| TABLE rtable { this_proto->table = $2; }
|
||||||
| ROUTER ID idval { this_proto->router_id = $3; }
|
| ROUTER ID idval { this_proto->router_id = $3; }
|
||||||
| DESCRIPTION TEXT { this_proto->dsc = $2; }
|
| DESCRIPTION TEXT { this_proto->dsc = $2; }
|
||||||
|
@ -188,6 +191,22 @@ imexport:
|
||||||
| NONE { $$ = FILTER_REJECT; }
|
| NONE { $$ = FILTER_REJECT; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
limit_action:
|
||||||
|
WARN { $$ = PLA_WARN; }
|
||||||
|
| BLOCK { $$ = PLA_BLOCK; }
|
||||||
|
| RESTART { $$ = PLA_RESTART; }
|
||||||
|
| DISABLE { $$ = PLA_DISABLE; }
|
||||||
|
;
|
||||||
|
|
||||||
|
limit_spec:
|
||||||
|
expr EXCEED limit_action {
|
||||||
|
struct proto_limit *l = cfg_allocz(sizeof(struct proto_limit));
|
||||||
|
l->limit = $1;
|
||||||
|
l->action = $3;
|
||||||
|
$$ = l;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
rtable:
|
rtable:
|
||||||
SYM {
|
SYM {
|
||||||
if ($1->class != SYM_TABLE) cf_error("Table name expected");
|
if ($1->class != SYM_TABLE) cf_error("Table name expected");
|
||||||
|
|
154
nest/proto.c
154
nest/proto.c
|
@ -34,11 +34,13 @@ static list flush_proto_list;
|
||||||
static struct proto *initial_device_proto;
|
static struct proto *initial_device_proto;
|
||||||
|
|
||||||
static event *proto_flush_event;
|
static event *proto_flush_event;
|
||||||
|
static timer *proto_shutdown_timer;
|
||||||
|
|
||||||
static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
|
static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
|
||||||
static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
|
static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
|
||||||
|
|
||||||
static void proto_flush_loop(void *);
|
static void proto_flush_loop(void *);
|
||||||
|
static void proto_shutdown_loop(struct timer *);
|
||||||
static void proto_rethink_goal(struct proto *p);
|
static void proto_rethink_goal(struct proto *p);
|
||||||
static char *proto_state_name(struct proto *p);
|
static char *proto_state_name(struct proto *p);
|
||||||
|
|
||||||
|
@ -134,8 +136,6 @@ extern pool *rt_table_pool;
|
||||||
* proto_add_announce_hook - connect protocol to a routing table
|
* proto_add_announce_hook - connect protocol to a routing table
|
||||||
* @p: protocol instance
|
* @p: protocol instance
|
||||||
* @t: routing table to connect to
|
* @t: routing table to connect to
|
||||||
* @in: input filter
|
|
||||||
* @out: output filter
|
|
||||||
* @stats: per-table protocol statistics
|
* @stats: per-table protocol statistics
|
||||||
*
|
*
|
||||||
* This function creates a connection between the protocol instance @p
|
* This function creates a connection between the protocol instance @p
|
||||||
|
@ -155,8 +155,7 @@ extern pool *rt_table_pool;
|
||||||
* automatically by the core code.
|
* automatically by the core code.
|
||||||
*/
|
*/
|
||||||
struct announce_hook *
|
struct announce_hook *
|
||||||
proto_add_announce_hook(struct proto *p, struct rtable *t, struct filter *in,
|
proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats)
|
||||||
struct filter *out, struct proto_stats *stats)
|
|
||||||
{
|
{
|
||||||
struct announce_hook *h;
|
struct announce_hook *h;
|
||||||
|
|
||||||
|
@ -166,8 +165,6 @@ proto_add_announce_hook(struct proto *p, struct rtable *t, struct filter *in,
|
||||||
h = mb_allocz(rt_table_pool, sizeof(struct announce_hook));
|
h = mb_allocz(rt_table_pool, sizeof(struct announce_hook));
|
||||||
h->table = t;
|
h->table = t;
|
||||||
h->proto = p;
|
h->proto = p;
|
||||||
h->in_filter = in;
|
|
||||||
h->out_filter = out;
|
|
||||||
h->stats = stats;
|
h->stats = stats;
|
||||||
|
|
||||||
h->next = p->ahooks;
|
h->next = p->ahooks;
|
||||||
|
@ -414,6 +411,8 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
|
||||||
{
|
{
|
||||||
p->main_ahook->in_filter = nc->in_filter;
|
p->main_ahook->in_filter = nc->in_filter;
|
||||||
p->main_ahook->out_filter = nc->out_filter;
|
p->main_ahook->out_filter = nc->out_filter;
|
||||||
|
p->main_ahook->in_limit = nc->in_limit;
|
||||||
|
// p->main_ahook->out_limit = nc->out_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update routes when filters changed. If the protocol in not UP,
|
/* Update routes when filters changed. If the protocol in not UP,
|
||||||
|
@ -438,6 +437,7 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
|
||||||
and we have to do regular protocol restart. */
|
and we have to do regular protocol restart. */
|
||||||
log(L_INFO "Restarting protocol %s", p->name);
|
log(L_INFO "Restarting protocol %s", p->name);
|
||||||
p->disabled = 1;
|
p->disabled = 1;
|
||||||
|
p->down_code = PDC_CF_RESTART;
|
||||||
proto_rethink_goal(p);
|
proto_rethink_goal(p);
|
||||||
p->disabled = 0;
|
p->disabled = 0;
|
||||||
proto_rethink_goal(p);
|
proto_rethink_goal(p);
|
||||||
|
@ -512,6 +512,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
|
||||||
log(L_INFO "Disabling protocol %s", p->name);
|
log(L_INFO "Disabling protocol %s", p->name);
|
||||||
|
|
||||||
PD(p, "Restarting");
|
PD(p, "Restarting");
|
||||||
|
p->down_code = nc->disabled ? PDC_CF_DISABLE : PDC_CF_RESTART;
|
||||||
p->cf_new = nc;
|
p->cf_new = nc;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -519,9 +520,11 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
|
||||||
if (!shutting_down)
|
if (!shutting_down)
|
||||||
log(L_INFO "Removing protocol %s", p->name);
|
log(L_INFO "Removing protocol %s", p->name);
|
||||||
PD(p, "Unconfigured");
|
PD(p, "Unconfigured");
|
||||||
|
p->down_code = PDC_CF_REMOVE;
|
||||||
p->cf_new = NULL;
|
p->cf_new = NULL;
|
||||||
}
|
}
|
||||||
p->reconfiguring = 1;
|
p->reconfiguring = 1;
|
||||||
|
|
||||||
config_add_obstacle(old);
|
config_add_obstacle(old);
|
||||||
proto_rethink_goal(p);
|
proto_rethink_goal(p);
|
||||||
}
|
}
|
||||||
|
@ -704,6 +707,8 @@ protos_build(void)
|
||||||
proto_pool = rp_new(&root_pool, "Protocols");
|
proto_pool = rp_new(&root_pool, "Protocols");
|
||||||
proto_flush_event = ev_new(proto_pool);
|
proto_flush_event = ev_new(proto_pool);
|
||||||
proto_flush_event->hook = proto_flush_loop;
|
proto_flush_event->hook = proto_flush_loop;
|
||||||
|
proto_shutdown_timer = tm_new(proto_pool);
|
||||||
|
proto_shutdown_timer->hook = proto_shutdown_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -775,8 +780,13 @@ proto_schedule_feed(struct proto *p, int initial)
|
||||||
|
|
||||||
/* Connect protocol to routing table */
|
/* Connect protocol to routing table */
|
||||||
if (initial && !p->proto->multitable)
|
if (initial && !p->proto->multitable)
|
||||||
p->main_ahook = proto_add_announce_hook(p, p->table,
|
{
|
||||||
p->cf->in_filter, p->cf->out_filter, &p->stats);
|
p->main_ahook = proto_add_announce_hook(p, p->table, &p->stats);
|
||||||
|
p->main_ahook->in_filter = p->cf->in_filter;
|
||||||
|
p->main_ahook->out_filter = p->cf->out_filter;
|
||||||
|
p->main_ahook->in_limit = p->cf->in_limit;
|
||||||
|
// p->main_ahook->out_limit = p->cf->out_limit;
|
||||||
|
}
|
||||||
|
|
||||||
proto_relink(p);
|
proto_relink(p);
|
||||||
p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
|
p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
|
||||||
|
@ -861,6 +871,42 @@ proto_schedule_flush(struct proto *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
proto_shutdown_loop(struct timer *t UNUSED)
|
||||||
|
{
|
||||||
|
struct proto *p, *p_next;
|
||||||
|
|
||||||
|
WALK_LIST_DELSAFE(p, p_next, active_proto_list)
|
||||||
|
if (p->down_sched)
|
||||||
|
{
|
||||||
|
int restart = (p->down_sched == PDS_RESTART);
|
||||||
|
|
||||||
|
p->disabled = 1;
|
||||||
|
proto_rethink_goal(p);
|
||||||
|
if (restart)
|
||||||
|
{
|
||||||
|
p->disabled = 0;
|
||||||
|
proto_rethink_goal(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
proto_schedule_down(struct proto *p, byte restart, byte code)
|
||||||
|
{
|
||||||
|
/* Does not work for other states (even PS_START) */
|
||||||
|
ASSERT(p->proto_state == PS_UP);
|
||||||
|
|
||||||
|
/* Scheduled restart may change to shutdown, but not otherwise */
|
||||||
|
if (p->down_sched == PDS_DISABLE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p->down_sched = restart ? PDS_RESTART : PDS_DISABLE;
|
||||||
|
p->down_code = code;
|
||||||
|
tm_start_max(proto_shutdown_timer, restart ? 2 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* proto_request_feeding - request feeding routes to the protocol
|
* proto_request_feeding - request feeding routes to the protocol
|
||||||
* @p: given protocol
|
* @p: given protocol
|
||||||
|
@ -890,6 +936,62 @@ proto_request_feeding(struct proto *p)
|
||||||
proto_schedule_feed(p, 0);
|
proto_schedule_feed(p, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
proto_limit_name(struct proto_limit *l)
|
||||||
|
{
|
||||||
|
const char *actions[] = {
|
||||||
|
[PLA_WARN] = "warn",
|
||||||
|
[PLA_BLOCK] = "block",
|
||||||
|
[PLA_RESTART] = "restart",
|
||||||
|
[PLA_DISABLE] = "disable",
|
||||||
|
};
|
||||||
|
|
||||||
|
return actions[l->action];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* proto_notify_limit: notify about limit hit and take appropriate action
|
||||||
|
* @ah: announce hook
|
||||||
|
* @l: limit being hit
|
||||||
|
*
|
||||||
|
* The function is called by the route processing core when limit @l
|
||||||
|
* is breached. It activates the limit and tooks appropriate action
|
||||||
|
* according to @l->action. It also says what should be done with the
|
||||||
|
* route that breached the limit.
|
||||||
|
*
|
||||||
|
* Returns 1 if the route should be freed, 0 otherwise.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
proto_notify_limit(struct announce_hook *ah, struct proto_limit *l)
|
||||||
|
{
|
||||||
|
struct proto *p = ah->proto;
|
||||||
|
int dir = (ah->in_limit == l);
|
||||||
|
|
||||||
|
if (l->active)
|
||||||
|
return (l->action != PLA_WARN);
|
||||||
|
|
||||||
|
l->active = 1;
|
||||||
|
log(L_WARN "Protocol %s hits route %s limit (%d), action: %s",
|
||||||
|
p->name, dir ? "import" : "export", l->limit, proto_limit_name(l));
|
||||||
|
|
||||||
|
switch (l->action)
|
||||||
|
{
|
||||||
|
case PLA_WARN:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case PLA_BLOCK:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case PLA_RESTART:
|
||||||
|
case PLA_DISABLE:
|
||||||
|
proto_schedule_down(p, l->action == PLA_RESTART,
|
||||||
|
dir ? PDC_IN_LIMIT_HIT : PDC_OUT_LIMIT_HIT);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* proto_notify_state - notify core about protocol state change
|
* proto_notify_state - notify core about protocol state change
|
||||||
* @p: protocol the state of which has changed
|
* @p: protocol the state of which has changed
|
||||||
|
@ -919,6 +1021,8 @@ proto_notify_state(struct proto *p, unsigned ps)
|
||||||
switch (ps)
|
switch (ps)
|
||||||
{
|
{
|
||||||
case PS_DOWN:
|
case PS_DOWN:
|
||||||
|
p->down_code = 0;
|
||||||
|
p->down_sched = 0;
|
||||||
if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
|
if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
|
||||||
proto_schedule_flush(p);
|
proto_schedule_flush(p);
|
||||||
|
|
||||||
|
@ -942,6 +1046,7 @@ proto_notify_state(struct proto *p, unsigned ps)
|
||||||
proto_schedule_feed(p, 1);
|
proto_schedule_feed(p, 1);
|
||||||
break;
|
break;
|
||||||
case PS_STOP:
|
case PS_STOP:
|
||||||
|
p->down_sched = 0;
|
||||||
if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
|
if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
|
||||||
proto_schedule_flush(p);
|
proto_schedule_flush(p);
|
||||||
break;
|
break;
|
||||||
|
@ -993,6 +1098,14 @@ proto_show_stats(struct proto_stats *s)
|
||||||
s->exp_withdraws_received, s->exp_withdraws_accepted);
|
s->exp_withdraws_received, s->exp_withdraws_accepted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
proto_show_limit(struct proto_limit *l, const char *dsc)
|
||||||
|
{
|
||||||
|
if (l)
|
||||||
|
cli_msg(-1006, " %16s%d, action: %s%s", dsc, l->limit,
|
||||||
|
proto_limit_name(l), l->active ? " [HIT]" : "");
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
proto_show_basic_info(struct proto *p)
|
proto_show_basic_info(struct proto *p)
|
||||||
{
|
{
|
||||||
|
@ -1001,6 +1114,8 @@ proto_show_basic_info(struct proto *p)
|
||||||
cli_msg(-1006, " Input filter: %s", filter_name(p->cf->in_filter));
|
cli_msg(-1006, " Input filter: %s", filter_name(p->cf->in_filter));
|
||||||
cli_msg(-1006, " Output filter: %s", filter_name(p->cf->out_filter));
|
cli_msg(-1006, " Output filter: %s", filter_name(p->cf->out_filter));
|
||||||
|
|
||||||
|
proto_show_limit(p->cf->in_limit, "Import limit:");
|
||||||
|
|
||||||
if (p->proto_state != PS_DOWN)
|
if (p->proto_state != PS_DOWN)
|
||||||
proto_show_stats(&p->stats);
|
proto_show_stats(&p->stats);
|
||||||
}
|
}
|
||||||
|
@ -1052,6 +1167,7 @@ proto_cmd_disable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
|
||||||
|
|
||||||
log(L_INFO "Disabling protocol %s", p->name);
|
log(L_INFO "Disabling protocol %s", p->name);
|
||||||
p->disabled = 1;
|
p->disabled = 1;
|
||||||
|
p->down_code = PDC_CMD_DISABLE;
|
||||||
proto_rethink_goal(p);
|
proto_rethink_goal(p);
|
||||||
cli_msg(-9, "%s: disabled", p->name);
|
cli_msg(-9, "%s: disabled", p->name);
|
||||||
}
|
}
|
||||||
|
@ -1082,6 +1198,7 @@ proto_cmd_restart(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
|
||||||
|
|
||||||
log(L_INFO "Restarting protocol %s", p->name);
|
log(L_INFO "Restarting protocol %s", p->name);
|
||||||
p->disabled = 1;
|
p->disabled = 1;
|
||||||
|
p->down_code = PDC_CMD_RESTART;
|
||||||
proto_rethink_goal(p);
|
proto_rethink_goal(p);
|
||||||
p->disabled = 0;
|
p->disabled = 0;
|
||||||
proto_rethink_goal(p);
|
proto_rethink_goal(p);
|
||||||
|
@ -1105,12 +1222,21 @@ proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED)
|
||||||
|
|
||||||
/* re-importing routes */
|
/* re-importing routes */
|
||||||
if (dir != CMD_RELOAD_OUT)
|
if (dir != CMD_RELOAD_OUT)
|
||||||
if (! (p->reload_routes && p->reload_routes(p)))
|
{
|
||||||
{
|
if (! (p->reload_routes && p->reload_routes(p)))
|
||||||
cli_msg(-8006, "%s: reload failed", p->name);
|
{
|
||||||
return;
|
cli_msg(-8006, "%s: reload failed", p->name);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should be done before reload_routes() hook?
|
||||||
|
* Perhaps, but these hooks work asynchronously.
|
||||||
|
*/
|
||||||
|
if (!p->proto->multitable && p->main_ahook->in_limit)
|
||||||
|
p->main_ahook->in_limit->active = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* re-exporting routes */
|
/* re-exporting routes */
|
||||||
if (dir != CMD_RELOAD_IN)
|
if (dir != CMD_RELOAD_IN)
|
||||||
proto_request_feeding(p);
|
proto_request_feeding(p);
|
||||||
|
|
|
@ -94,13 +94,15 @@ struct proto_config {
|
||||||
u32 router_id; /* Protocol specific router ID */
|
u32 router_id; /* Protocol specific router ID */
|
||||||
struct rtable_config *table; /* Table we're attached to */
|
struct rtable_config *table; /* Table we're attached to */
|
||||||
struct filter *in_filter, *out_filter; /* Attached filters */
|
struct filter *in_filter, *out_filter; /* Attached filters */
|
||||||
|
struct proto_limit *in_limit; /* Limit for importing routes from protocol */
|
||||||
|
// struct proto_limit *out_limit; /* Limit for exporting routes to protocol */
|
||||||
|
|
||||||
/* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
|
/* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
|
||||||
|
|
||||||
/* Protocol-specific data follow... */
|
/* Protocol-specific data follow... */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Protocol statistics */
|
/* Protocol statistics */
|
||||||
struct proto_stats {
|
struct proto_stats {
|
||||||
/* Import - from protocol to core */
|
/* Import - from protocol to core */
|
||||||
u32 imp_routes; /* Number of routes successfully imported to the (adjacent) routing table */
|
u32 imp_routes; /* Number of routes successfully imported to the (adjacent) routing table */
|
||||||
|
@ -138,14 +140,16 @@ struct proto {
|
||||||
u32 debug; /* Debugging flags */
|
u32 debug; /* Debugging flags */
|
||||||
u32 mrtdump; /* MRTDump flags */
|
u32 mrtdump; /* MRTDump flags */
|
||||||
unsigned preference; /* Default route preference */
|
unsigned preference; /* Default route preference */
|
||||||
unsigned accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */
|
byte accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */
|
||||||
unsigned disabled; /* Manually disabled */
|
byte disabled; /* Manually disabled */
|
||||||
unsigned proto_state; /* Protocol state machine (see below) */
|
byte proto_state; /* Protocol state machine (PS_*, see below) */
|
||||||
unsigned core_state; /* Core state machine (see below) */
|
byte core_state; /* Core state machine (FS_*, see below) */
|
||||||
unsigned core_goal; /* State we want to reach (see below) */
|
byte core_goal; /* State we want to reach (FS_*, see below) */
|
||||||
unsigned reconfiguring; /* We're shutting down due to reconfiguration */
|
byte reconfiguring; /* We're shutting down due to reconfiguration */
|
||||||
unsigned refeeding; /* We are refeeding (valid only if core_state == FS_FEEDING) */
|
byte refeeding; /* We are refeeding (valid only if core_state == FS_FEEDING) */
|
||||||
unsigned flushing; /* Protocol is flushed in current flush loop round */
|
byte flushing; /* Protocol is flushed in current flush loop round */
|
||||||
|
byte down_sched; /* Shutdown is scheduled for later (PDS_*) */
|
||||||
|
byte down_code; /* Reason for shutdown (PDC_* codes) */
|
||||||
u32 hash_key; /* Random key used for hashing of neighbors */
|
u32 hash_key; /* Random key used for hashing of neighbors */
|
||||||
bird_clock_t last_state_change; /* Time of last state transition */
|
bird_clock_t last_state_change; /* Time of last state transition */
|
||||||
char *last_state_name_announced; /* Last state name we've announced to the user */
|
char *last_state_name_announced; /* Last state name we've announced to the user */
|
||||||
|
@ -210,6 +214,18 @@ struct proto_spec {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define PDS_DISABLE 1 /* Proto disable scheduled */
|
||||||
|
#define PDS_RESTART 2 /* Proto restart scheduled */
|
||||||
|
|
||||||
|
#define PDC_CF_REMOVE 0x01 /* Removed in new config */
|
||||||
|
#define PDC_CF_DISABLE 0x02 /* Disabled in new config */
|
||||||
|
#define PDC_CF_RESTART 0x03 /* Restart due to reconfiguration */
|
||||||
|
#define PDC_CMD_DISABLE 0x11 /* Result of disable command */
|
||||||
|
#define PDC_CMD_RESTART 0x12 /* Result of restart command */
|
||||||
|
#define PDC_IN_LIMIT_HIT 0x21 /* Route import limit reached */
|
||||||
|
#define PDC_OUT_LIMIT_HIT 0x22 /* Route export limit reached - not implemented */
|
||||||
|
|
||||||
|
|
||||||
void *proto_new(struct proto_config *, unsigned size);
|
void *proto_new(struct proto_config *, unsigned size);
|
||||||
void *proto_config_new(struct protocol *, unsigned size, int class);
|
void *proto_config_new(struct protocol *, unsigned size, int class);
|
||||||
void proto_copy_config(struct proto_config *dest, struct proto_config *src);
|
void proto_copy_config(struct proto_config *dest, struct proto_config *src);
|
||||||
|
@ -220,6 +236,7 @@ proto_copy_rest(struct proto_config *dest, struct proto_config *src, unsigned si
|
||||||
{ memcpy(dest + 1, src + 1, size - sizeof(struct proto_config)); }
|
{ memcpy(dest + 1, src + 1, size - sizeof(struct proto_config)); }
|
||||||
|
|
||||||
|
|
||||||
|
void proto_show_limit(struct proto_limit *l, const char *dsc);
|
||||||
void proto_show_basic_info(struct proto *p);
|
void proto_show_basic_info(struct proto *p);
|
||||||
|
|
||||||
void proto_cmd_show(struct proto *, unsigned int, int);
|
void proto_cmd_show(struct proto *, unsigned int, int);
|
||||||
|
@ -348,6 +365,24 @@ void proto_notify_state(struct proto *p, unsigned state);
|
||||||
|
|
||||||
extern struct proto_config *cf_dev_proto;
|
extern struct proto_config *cf_dev_proto;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Protocol limits
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PLA_WARN 1 /* Issue log warning */
|
||||||
|
#define PLA_BLOCK 2 /* Block new routes */
|
||||||
|
#define PLA_RESTART 4 /* Force protocol restart */
|
||||||
|
#define PLA_DISABLE 5 /* Shutdown and disable protocol */
|
||||||
|
|
||||||
|
struct proto_limit {
|
||||||
|
u32 limit; /* Maximum number of prefixes */
|
||||||
|
byte action; /* Action to take (PLA_*) */
|
||||||
|
byte active; /* Limit is active */
|
||||||
|
};
|
||||||
|
|
||||||
|
int proto_notify_limit(struct announce_hook *ah, struct proto_limit *l);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Route Announcement Hook
|
* Route Announcement Hook
|
||||||
*/
|
*/
|
||||||
|
@ -358,11 +393,13 @@ struct announce_hook {
|
||||||
struct proto *proto;
|
struct proto *proto;
|
||||||
struct filter *in_filter; /* Input filter */
|
struct filter *in_filter; /* Input filter */
|
||||||
struct filter *out_filter; /* Output filter */
|
struct filter *out_filter; /* Output filter */
|
||||||
|
struct proto_limit *in_limit; /* Input limit */
|
||||||
|
// struct proto_limit *out_limit; /* Output limit */
|
||||||
struct proto_stats *stats; /* Per-table protocol statistics */
|
struct proto_stats *stats; /* Per-table protocol statistics */
|
||||||
struct announce_hook *next; /* Next hook for the same protocol */
|
struct announce_hook *next; /* Next hook for the same protocol */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *, struct filter *, struct filter *, struct proto_stats *);
|
struct announce_hook *proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats);
|
||||||
struct announce_hook *proto_find_announce_hook(struct proto *p, struct rtable *t);
|
struct announce_hook *proto_find_announce_hook(struct proto *p, struct rtable *t);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -182,6 +182,16 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg)
|
||||||
rte_trace(p, e, '<', msg);
|
rte_trace(p, e, '<', msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do_rte_announce - announce new rte to protocol
|
||||||
|
* @ah: pointer to announce hook
|
||||||
|
* @type: announce type (RA_ANY or RA_OPTIMAL)
|
||||||
|
* @net: pointer to announced network
|
||||||
|
* @new: new rte or NULL
|
||||||
|
* @old: previous rte or NULL
|
||||||
|
* @tmpa: new rte attributes (possibly modified by filter)
|
||||||
|
* @refeed: whether we are refeeding protocol
|
||||||
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
do_rte_announce(struct announce_hook *ah, int type UNUSED, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
|
do_rte_announce(struct announce_hook *ah, int type UNUSED, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
|
||||||
{
|
{
|
||||||
|
@ -474,6 +484,15 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct proto_limit *l = ah->in_limit;
|
||||||
|
if (l && !old && new && (stats->imp_routes >= l->limit) && proto_notify_limit(ah, l))
|
||||||
|
{
|
||||||
|
stats->imp_updates_ignored++;
|
||||||
|
rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
|
||||||
|
rte_free_quick(new);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (new)
|
if (new)
|
||||||
stats->imp_updates_accepted++;
|
stats->imp_updates_accepted++;
|
||||||
else
|
else
|
||||||
|
|
|
@ -542,22 +542,6 @@ bgp_active(struct bgp_proto *p)
|
||||||
bgp_start_timer(conn->connect_retry_timer, delay);
|
bgp_start_timer(conn->connect_retry_timer, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
bgp_apply_limits(struct bgp_proto *p)
|
|
||||||
{
|
|
||||||
if (p->cf->route_limit && (p->p.stats.imp_routes > p->cf->route_limit))
|
|
||||||
{
|
|
||||||
log(L_WARN "%s: Route limit exceeded, shutting down", p->p.name);
|
|
||||||
bgp_store_error(p, NULL, BE_AUTO_DOWN, BEA_ROUTE_LIMIT_EXCEEDED);
|
|
||||||
bgp_update_startup_delay(p);
|
|
||||||
bgp_stop(p, 1); // Errcode 6, 1 - max number of prefixes reached
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bgp_connect - initiate an outgoing connection
|
* bgp_connect - initiate an outgoing connection
|
||||||
* @p: BGP instance
|
* @p: BGP instance
|
||||||
|
@ -868,24 +852,46 @@ static int
|
||||||
bgp_shutdown(struct proto *P)
|
bgp_shutdown(struct proto *P)
|
||||||
{
|
{
|
||||||
struct bgp_proto *p = (struct bgp_proto *) P;
|
struct bgp_proto *p = (struct bgp_proto *) P;
|
||||||
unsigned subcode;
|
unsigned subcode = 0;
|
||||||
|
|
||||||
BGP_TRACE(D_EVENTS, "Shutdown requested");
|
BGP_TRACE(D_EVENTS, "Shutdown requested");
|
||||||
bgp_store_error(p, NULL, BE_MAN_DOWN, 0);
|
|
||||||
|
|
||||||
if (P->reconfiguring)
|
switch (P->down_code)
|
||||||
{
|
{
|
||||||
if (P->cf_new)
|
case PDC_CF_REMOVE:
|
||||||
subcode = 6; // Errcode 6, 6 - other configuration change
|
case PDC_CF_DISABLE:
|
||||||
|
subcode = 3; // Errcode 6, 3 - peer de-configured
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDC_CF_RESTART:
|
||||||
|
subcode = 6; // Errcode 6, 6 - other configuration change
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDC_CMD_DISABLE:
|
||||||
|
subcode = 2; // Errcode 6, 2 - administrative shutdown
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDC_CMD_RESTART:
|
||||||
|
subcode = 4; // Errcode 6, 4 - administrative reset
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDC_IN_LIMIT_HIT:
|
||||||
|
subcode = 1; // Errcode 6, 1 - max number of prefixes reached
|
||||||
|
log(L_WARN "%s: Route limit exceeded, shutting down", p->p.name);
|
||||||
|
|
||||||
|
bgp_store_error(p, NULL, BE_AUTO_DOWN, BEA_ROUTE_LIMIT_EXCEEDED);
|
||||||
|
if (P->cf->in_limit->action == PLA_RESTART)
|
||||||
|
bgp_update_startup_delay(p);
|
||||||
else
|
else
|
||||||
subcode = 3; // Errcode 6, 3 - peer de-configured
|
p->startup_delay = 0;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
subcode = 2; // Errcode 6, 2 - administrative shutdown
|
|
||||||
|
|
||||||
|
bgp_store_error(p, NULL, BE_MAN_DOWN, 0);
|
||||||
p->startup_delay = 0;
|
p->startup_delay = 0;
|
||||||
bgp_stop(p, subcode);
|
|
||||||
|
|
||||||
|
done:
|
||||||
|
bgp_stop(p, subcode);
|
||||||
return p->p.proto_state;
|
return p->p.proto_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -969,6 +975,10 @@ bgp_check_config(struct bgp_config *c)
|
||||||
/* Different default for gw_mode */
|
/* Different default for gw_mode */
|
||||||
if (!c->gw_mode)
|
if (!c->gw_mode)
|
||||||
c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT;
|
c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT;
|
||||||
|
|
||||||
|
/* Disable after error incompatible with restart limit action */
|
||||||
|
if (c->c.in_limit && (c->c.in_limit->action == PLA_RESTART) && c->disable_after_error)
|
||||||
|
c->c.in_limit->action = PLA_DISABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1116,9 +1126,6 @@ bgp_get_status(struct proto *P, byte *buf)
|
||||||
bsprintf(buf, "%-14s%s%s", bgp_state_dsc(p), err1, err2);
|
bsprintf(buf, "%-14s%s%s", bgp_state_dsc(p), err1, err2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bird_clock_t tm_remains(timer *t)
|
|
||||||
{ return t->expires ? t->expires - now : 0; }
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bgp_show_proto_info(struct proto *P)
|
bgp_show_proto_info(struct proto *P)
|
||||||
{
|
{
|
||||||
|
|
|
@ -152,7 +152,6 @@ void bgp_conn_enter_established_state(struct bgp_conn *conn);
|
||||||
void bgp_conn_enter_close_state(struct bgp_conn *conn);
|
void bgp_conn_enter_close_state(struct bgp_conn *conn);
|
||||||
void bgp_conn_enter_idle_state(struct bgp_conn *conn);
|
void bgp_conn_enter_idle_state(struct bgp_conn *conn);
|
||||||
void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code);
|
void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code);
|
||||||
int bgp_apply_limits(struct bgp_proto *p);
|
|
||||||
void bgp_stop(struct bgp_proto *p, unsigned subcode);
|
void bgp_stop(struct bgp_proto *p, unsigned subcode);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,11 @@ bgp_proto:
|
||||||
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
|
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
|
||||||
| bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
|
| bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
|
||||||
| bgp_proto PASSWORD TEXT ';' { BGP_CFG->password = $3; }
|
| bgp_proto PASSWORD TEXT ';' { BGP_CFG->password = $3; }
|
||||||
| bgp_proto ROUTE LIMIT expr ';' { BGP_CFG->route_limit = $4; }
|
| bgp_proto ROUTE LIMIT expr ';' {
|
||||||
|
this_proto->in_limit = cfg_allocz(sizeof(struct proto_limit));
|
||||||
|
this_proto->in_limit->limit = $4;
|
||||||
|
this_proto->in_limit->action = PLA_RESTART;
|
||||||
|
}
|
||||||
| bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
|
| bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
|
||||||
| bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; }
|
| bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; }
|
||||||
| bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; }
|
| bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; }
|
||||||
|
|
|
@ -915,9 +915,6 @@ bgp_do_rx_update(struct bgp_conn *conn,
|
||||||
if (n = net_find(p->p.table, prefix, pxlen))
|
if (n = net_find(p->p.table, prefix, pxlen))
|
||||||
rte_update(p->p.table, n, &p->p, &p->p, NULL);
|
rte_update(p->p.table, n, &p->p, &p->p, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bgp_apply_limits(p) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
|
@ -36,6 +36,7 @@ pipe_proto:
|
||||||
cf_error("Routing table name expected");
|
cf_error("Routing table name expected");
|
||||||
PIPE_CFG->peer = $4->def;
|
PIPE_CFG->peer = $4->def;
|
||||||
}
|
}
|
||||||
|
| pipe_proto EXPORT LIMIT limit_spec ';' { PIPE_CFG->out_limit = $4; }
|
||||||
| pipe_proto MODE OPAQUE ';' { PIPE_CFG->mode = PIPE_OPAQUE; }
|
| pipe_proto MODE OPAQUE ';' { PIPE_CFG->mode = PIPE_OPAQUE; }
|
||||||
| pipe_proto MODE TRANSPARENT ';' { PIPE_CFG->mode = PIPE_TRANSPARENT; }
|
| pipe_proto MODE TRANSPARENT ';' { PIPE_CFG->mode = PIPE_TRANSPARENT; }
|
||||||
;
|
;
|
||||||
|
|
|
@ -24,9 +24,10 @@
|
||||||
* rte_update(), an import filter in ahook 2 is called. When a new
|
* rte_update(), an import filter in ahook 2 is called. When a new
|
||||||
* route is announced in the peer table, an export filter in ahook2
|
* route is announced in the peer table, an export filter in ahook2
|
||||||
* and an import filter in ahook 1 are used. Oviously, there is no
|
* and an import filter in ahook 1 are used. Oviously, there is no
|
||||||
* need in filtering the same route twice, so both import filters
|
* need in filtering the same route twice, so both import filters are
|
||||||
* are set to accept, while user configured 'import' and 'export'
|
* set to accept, while user configured 'import' and 'export' filters
|
||||||
* filters are used as export filters in ahooks 2 and 1.
|
* are used as export filters in ahooks 2 and 1. Route limits are
|
||||||
|
* handled similarly, but on the import side of ahooks.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#undef LOCAL_DEBUG
|
#undef LOCAL_DEBUG
|
||||||
|
@ -116,6 +117,8 @@ pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpo
|
||||||
static int
|
static int
|
||||||
pipe_reload_routes(struct proto *P)
|
pipe_reload_routes(struct proto *P)
|
||||||
{
|
{
|
||||||
|
struct pipe_proto *p = (struct pipe_proto *) P;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Because the pipe protocol feeds routes from both routing tables
|
* Because the pipe protocol feeds routes from both routing tables
|
||||||
* together, both directions are reloaded during refeed and 'reload
|
* together, both directions are reloaded during refeed and 'reload
|
||||||
|
@ -123,6 +126,12 @@ pipe_reload_routes(struct proto *P)
|
||||||
* request refeed when 'reload in' command is used.
|
* request refeed when 'reload in' command is used.
|
||||||
*/
|
*/
|
||||||
proto_request_feeding(P);
|
proto_request_feeding(P);
|
||||||
|
|
||||||
|
if (P->main_ahook->in_limit)
|
||||||
|
P->main_ahook->in_limit->active = 0;
|
||||||
|
if (p->peer_ahook->in_limit)
|
||||||
|
p->peer_ahook->in_limit->active = 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +155,7 @@ pipe_init(struct proto_config *C)
|
||||||
static int
|
static int
|
||||||
pipe_start(struct proto *P)
|
pipe_start(struct proto *P)
|
||||||
{
|
{
|
||||||
|
struct pipe_config *cf = (struct pipe_config *) P->cf;
|
||||||
struct pipe_proto *p = (struct pipe_proto *) P;
|
struct pipe_proto *p = (struct pipe_proto *) P;
|
||||||
|
|
||||||
/* Lock both tables, unlock is handled in pipe_cleanup() */
|
/* Lock both tables, unlock is handled in pipe_cleanup() */
|
||||||
|
@ -155,10 +165,13 @@ pipe_start(struct proto *P)
|
||||||
/* Going directly to PS_UP - prepare for feeding,
|
/* Going directly to PS_UP - prepare for feeding,
|
||||||
connect the protocol to both routing tables */
|
connect the protocol to both routing tables */
|
||||||
|
|
||||||
P->main_ahook = proto_add_announce_hook(P, P->table,
|
P->main_ahook = proto_add_announce_hook(P, P->table, &P->stats);
|
||||||
FILTER_ACCEPT, P->cf->out_filter, &P->stats);
|
P->main_ahook->out_filter = cf->c.out_filter;
|
||||||
p->peer_ahook = proto_add_announce_hook(P, p->peer_table,
|
P->main_ahook->in_limit = cf->c.in_limit;
|
||||||
FILTER_ACCEPT, P->cf->in_filter, &p->peer_stats);
|
|
||||||
|
p->peer_ahook = proto_add_announce_hook(P, p->peer_table, &p->peer_stats);
|
||||||
|
p->peer_ahook->out_filter = cf->c.in_filter;
|
||||||
|
p->peer_ahook->in_limit = cf->out_limit;
|
||||||
|
|
||||||
return PS_UP;
|
return PS_UP;
|
||||||
}
|
}
|
||||||
|
@ -204,10 +217,16 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
|
||||||
|
|
||||||
/* Update output filters in ahooks */
|
/* Update output filters in ahooks */
|
||||||
if (P->main_ahook)
|
if (P->main_ahook)
|
||||||
P->main_ahook->out_filter = new->out_filter;
|
{
|
||||||
|
P->main_ahook->out_filter = new->out_filter;
|
||||||
|
P->main_ahook->in_limit = new->in_limit;
|
||||||
|
}
|
||||||
|
|
||||||
if (p->peer_ahook)
|
if (p->peer_ahook)
|
||||||
p->peer_ahook->out_filter = new->in_filter;
|
{
|
||||||
|
p->peer_ahook->out_filter = new->in_filter;
|
||||||
|
p->peer_ahook->in_limit = nc->out_limit;
|
||||||
|
}
|
||||||
|
|
||||||
if ((P->proto_state != PS_UP) || (proto_reconfig_type == RECONFIG_SOFT))
|
if ((P->proto_state != PS_UP) || (proto_reconfig_type == RECONFIG_SOFT))
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -283,12 +302,16 @@ static void
|
||||||
pipe_show_proto_info(struct proto *P)
|
pipe_show_proto_info(struct proto *P)
|
||||||
{
|
{
|
||||||
struct pipe_proto *p = (struct pipe_proto *) P;
|
struct pipe_proto *p = (struct pipe_proto *) P;
|
||||||
|
struct pipe_config *cf = (struct pipe_config *) P->cf;
|
||||||
|
|
||||||
// cli_msg(-1006, " Table: %s", P->table->name);
|
// cli_msg(-1006, " Table: %s", P->table->name);
|
||||||
// cli_msg(-1006, " Peer table: %s", p->peer_table->name);
|
// cli_msg(-1006, " Peer table: %s", p->peer_table->name);
|
||||||
cli_msg(-1006, " Preference: %d", P->preference);
|
cli_msg(-1006, " Preference: %d", P->preference);
|
||||||
cli_msg(-1006, " Input filter: %s", filter_name(P->cf->in_filter));
|
cli_msg(-1006, " Input filter: %s", filter_name(cf->c.in_filter));
|
||||||
cli_msg(-1006, " Output filter: %s", filter_name(P->cf->out_filter));
|
cli_msg(-1006, " Output filter: %s", filter_name(cf->c.out_filter));
|
||||||
|
|
||||||
|
proto_show_limit(cf->c.in_limit, "Import limit:");
|
||||||
|
proto_show_limit(cf->out_limit, "Export limit:");
|
||||||
|
|
||||||
if (P->proto_state != PS_DOWN)
|
if (P->proto_state != PS_DOWN)
|
||||||
pipe_show_stats(p);
|
pipe_show_stats(p);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
struct pipe_config {
|
struct pipe_config {
|
||||||
struct proto_config c;
|
struct proto_config c;
|
||||||
struct rtable_config *peer; /* Table we're connected to */
|
struct rtable_config *peer; /* Table we're connected to */
|
||||||
|
struct proto_limit *out_limit; /* Export route limit */
|
||||||
int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */
|
int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,22 @@ void tm_start(timer *, unsigned after);
|
||||||
void tm_stop(timer *);
|
void tm_stop(timer *);
|
||||||
void tm_dump_all(void);
|
void tm_dump_all(void);
|
||||||
|
|
||||||
|
extern bird_clock_t now; /* Relative, monotonic time in seconds */
|
||||||
|
extern bird_clock_t now_real; /* Time in seconds since fixed known epoch */
|
||||||
|
|
||||||
|
static inline bird_clock_t
|
||||||
|
tm_remains(timer *t)
|
||||||
|
{
|
||||||
|
return t->expires ? t->expires - now : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
tm_start_max(timer *t, unsigned after)
|
||||||
|
{
|
||||||
|
bird_clock_t rem = tm_remains(t);
|
||||||
|
tm_start(t, (rem > after) ? rem : after);
|
||||||
|
}
|
||||||
|
|
||||||
static inline timer *
|
static inline timer *
|
||||||
tm_new_set(pool *p, void (*hook)(struct timer *), void *data, unsigned rand, unsigned rec)
|
tm_new_set(pool *p, void (*hook)(struct timer *), void *data, unsigned rand, unsigned rec)
|
||||||
{
|
{
|
||||||
|
@ -41,8 +57,6 @@ tm_new_set(pool *p, void (*hook)(struct timer *), void *data, unsigned rand, uns
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern bird_clock_t now; /* Relative, monotonic time in seconds */
|
|
||||||
extern bird_clock_t now_real; /* Time in seconds since fixed known epoch */
|
|
||||||
|
|
||||||
struct timeformat {
|
struct timeformat {
|
||||||
char *fmt1, *fmt2;
|
char *fmt1, *fmt2;
|
||||||
|
|
Loading…
Reference in a new issue