Commit ebecb6f6 authored by Ondřej Zajíček's avatar Ondřej Zajíček

Implements generalized import hooks.

Thanks to Alexander V. Chernikov for the original patch.
parent ae8b3001
......@@ -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
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
description of the protocol. It is displayed as a part of the
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
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
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(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(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE, ROA, MAX, FLUSH)
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 <rot> roa_table_arg
%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 <g> limit_spec
CF_GRAMMAR
......@@ -176,6 +178,7 @@ proto_item:
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
| IMPORT imexport { this_proto->in_filter = $2; }
| EXPORT imexport { this_proto->out_filter = $2; }
| IMPORT LIMIT limit_spec { this_proto->in_limit = $3; }
| TABLE rtable { this_proto->table = $2; }
| ROUTER ID idval { this_proto->router_id = $3; }
| DESCRIPTION TEXT { this_proto->dsc = $2; }
......@@ -188,6 +191,22 @@ imexport:
| 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:
SYM {
if ($1->class != SYM_TABLE) cf_error("Table name expected");
......
......@@ -34,11 +34,13 @@ static list flush_proto_list;
static struct proto *initial_device_proto;
static event *proto_flush_event;
static timer *proto_shutdown_timer;
static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
static void proto_flush_loop(void *);
static void proto_shutdown_loop(struct timer *);
static void proto_rethink_goal(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
* @p: protocol instance
* @t: routing table to connect to
* @in: input filter
* @out: output filter
* @stats: per-table protocol statistics
*
* This function creates a connection between the protocol instance @p
......@@ -155,8 +155,7 @@ extern pool *rt_table_pool;
* automatically by the core code.
*/
struct announce_hook *
proto_add_announce_hook(struct proto *p, struct rtable *t, struct filter *in,
struct filter *out, struct proto_stats *stats)
proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats)
{
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->table = t;
h->proto = p;
h->in_filter = in;
h->out_filter = out;
h->stats = stats;
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->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,
......@@ -438,6 +437,7 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
and we have to do regular protocol restart. */
log(L_INFO "Restarting protocol %s", p->name);
p->disabled = 1;
p->down_code = PDC_CF_RESTART;
proto_rethink_goal(p);
p->disabled = 0;
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);
PD(p, "Restarting");
p->down_code = nc->disabled ? PDC_CF_DISABLE : PDC_CF_RESTART;
p->cf_new = nc;
}
else
......@@ -519,9 +520,11 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
if (!shutting_down)
log(L_INFO "Removing protocol %s", p->name);
PD(p, "Unconfigured");
p->down_code = PDC_CF_REMOVE;
p->cf_new = NULL;
}
p->reconfiguring = 1;
config_add_obstacle(old);
proto_rethink_goal(p);
}
......@@ -704,6 +707,8 @@ protos_build(void)
proto_pool = rp_new(&root_pool, "Protocols");
proto_flush_event = ev_new(proto_pool);
proto_flush_event->hook = proto_flush_loop;
proto_shutdown_timer = tm_new(proto_pool);
proto_shutdown_timer->hook = proto_shutdown_loop;
}
static void
......@@ -775,8 +780,13 @@ proto_schedule_feed(struct proto *p, int initial)
/* Connect protocol to routing table */
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);
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
* @p: given protocol
......@@ -890,6 +936,62 @@ proto_request_feeding(struct proto *p)
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
* @p: protocol the state of which has changed
......@@ -919,6 +1021,8 @@ proto_notify_state(struct proto *p, unsigned ps)
switch (ps)
{
case PS_DOWN:
p->down_code = 0;
p->down_sched = 0;
if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
proto_schedule_flush(p);
......@@ -942,6 +1046,7 @@ proto_notify_state(struct proto *p, unsigned ps)
proto_schedule_feed(p, 1);
break;
case PS_STOP:
p->down_sched = 0;
if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
proto_schedule_flush(p);
break;
......@@ -993,6 +1098,14 @@ proto_show_stats(struct proto_stats *s)
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
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, " Output filter: %s", filter_name(p->cf->out_filter));
proto_show_limit(p->cf->in_limit, "Import limit:");
if (p->proto_state != PS_DOWN)
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);
p->disabled = 1;
p->down_code = PDC_CMD_DISABLE;
proto_rethink_goal(p);
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);
p->disabled = 1;
p->down_code = PDC_CMD_RESTART;
proto_rethink_goal(p);
p->disabled = 0;
proto_rethink_goal(p);
......@@ -1105,12 +1222,21 @@ proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED)
/* re-importing routes */
if (dir != CMD_RELOAD_OUT)
if (! (p->reload_routes && p->reload_routes(p)))
{
cli_msg(-8006, "%s: reload failed", p->name);
return;
}
{
if (! (p->reload_routes && p->reload_routes(p)))
{
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 */
if (dir != CMD_RELOAD_IN)
proto_request_feeding(p);
......
......@@ -94,13 +94,15 @@ struct proto_config {
u32 router_id; /* Protocol specific router ID */
struct rtable_config *table; /* Table we're attached to */
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 */
/* Protocol-specific data follow... */
};
/* Protocol statistics */
/* Protocol statistics */
struct proto_stats {
/* Import - from protocol to core */
u32 imp_routes; /* Number of routes successfully imported to the (adjacent) routing table */
......@@ -138,14 +140,16 @@ struct proto {
u32 debug; /* Debugging flags */
u32 mrtdump; /* MRTDump flags */
unsigned preference; /* Default route preference */
unsigned accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */
unsigned disabled; /* Manually disabled */
unsigned proto_state; /* Protocol state machine (see below) */
unsigned core_state; /* Core state machine (see below) */
unsigned core_goal; /* State we want to reach (see below) */
unsigned reconfiguring; /* We're shutting down due to reconfiguration */
unsigned refeeding; /* We are refeeding (valid only if core_state == FS_FEEDING) */
unsigned flushing; /* Protocol is flushed in current flush loop round */
byte accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */
byte disabled; /* Manually disabled */
byte proto_state; /* Protocol state machine (PS_*, see below) */
byte core_state; /* Core state machine (FS_*, see below) */
byte core_goal; /* State we want to reach (FS_*, see below) */
byte reconfiguring; /* We're shutting down due to reconfiguration */
byte refeeding; /* We are refeeding (valid only if core_state == FS_FEEDING) */
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 */
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 */
......@@ -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_config_new(struct protocol *, unsigned size, int class);
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)); }
void proto_show_limit(struct proto_limit *l, const char *dsc);
void proto_show_basic_info(struct proto *p);
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;
/*
* 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
*/
......@@ -358,11 +393,13 @@ struct announce_hook {
struct proto *proto;
struct filter *in_filter; /* Input 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 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);
#endif
......@@ -182,6 +182,16 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *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
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;
}
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)
stats->imp_updates_accepted++;
else
......
......@@ -542,22 +542,6 @@ bgp_active(struct bgp_proto *p)
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
* @p: BGP instance
......@@ -868,24 +852,46 @@ static int
bgp_shutdown(struct proto *P)
{
struct bgp_proto *p = (struct bgp_proto *) P;
unsigned subcode;
unsigned subcode = 0;
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)
subcode = 6; // Errcode 6, 6 - other configuration change
case PDC_CF_REMOVE:
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
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;
bgp_stop(p, subcode);
done:
bgp_stop(p, subcode);
return p->p.proto_state;
}
......@@ -969,6 +975,10 @@ bgp_check_config(struct bgp_config *c)
/* Different default for gw_mode */
if (!c->gw_mode)
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
......@@ -1116,9 +1126,6 @@ bgp_get_status(struct proto *P, byte *buf)
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
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_idle_state(struct bgp_conn *conn);
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);
......
......@@ -98,7 +98,11 @@ bgp_proto:
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
| bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
| 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 INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $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))
rte_update(p->p.table, n, &p->p, &p->p, NULL);
}
if (bgp_apply_limits(p) < 0)
goto done;
}
done:
......
......@@ -36,6 +36,7 @@ pipe_proto:
cf_error("Routing table name expected");
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 TRANSPARENT ';' { PIPE_CFG->mode = PIPE_TRANSPARENT; }
;
......
......@@ -24,9 +24,10 @@
* 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
* and an import filter in ahook 1 are used. Oviously, there is no
* need in filtering the same route twice, so both import filters
* are set to accept, while user configured 'import' and 'export'
* filters are used as export filters in ahooks 2 and 1.
* need in filtering the same route twice, so both import filters are
* set to accept, while user configured 'import' and 'export' filters
* 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
......@@ -116,6 +117,8 @@ pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpo
static int
pipe_reload_routes(struct proto *P)
{
struct pipe_proto *p = (struct pipe_proto *) P;
/*
* Because the pipe protocol feeds routes from both routing tables
* 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.
*/
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;
}
......@@ -146,6 +155,7 @@ pipe_init(struct proto_config *C)
static int
pipe_start(struct proto *P)
{
struct pipe_config *cf = (struct pipe_config *) P->cf;
struct pipe_proto *p = (struct pipe_proto *) P;
/* 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,
connect the protocol to both routing tables */
P->main_ahook = proto_add_announce_hook(P, P->table,
FILTER_ACCEPT, P->cf->out_filter, &P->stats);
p->peer_ahook = proto_add_announce_hook(P, p->peer_table,
FILTER_ACCEPT, P->cf->in_filter, &p->peer_stats);
P->main_ahook = proto_add_announce_hook(P, P->table, &P->stats);
P->main_ahook->out_filter = cf->c.out_filter;
P->main_ahook->in_limit = cf->c.in_limit;
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;
}
......@@ -204,10 +217,16 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
/* Update output filters in ahooks */
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)
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))
return 1;
......@@ -283,12 +302,16 @@ static void
pipe_show_proto_info(struct 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, " Peer table: %s", p->peer_table->name);
cli_msg(-1006, " Preference: %d", P->preference);
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, " Input filter: %s", filter_name(cf->c.in_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)
pipe_show_stats(p);
......
......@@ -15,6 +15,7 @@
struct pipe_config {
struct proto_config c;
struct rtable_config *peer; /* Table we're connected to */
struct proto_limit *out_limit; /* Export route limit */
int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */
};
......
......@@ -30,6 +30,22 @@ void tm_start(timer *, unsigned after);
void tm_stop(timer *);
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)
{