diff --git a/nest/proto.c b/nest/proto.c index 418a7a61..cf81573f 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -785,7 +785,9 @@ proto_schedule_feed(struct proto *p, int initial) 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; + proto_reset_limit(p->main_ahook->in_limit); // p->main_ahook->out_limit = p->cf->out_limit; + // proto_reset_limit(p->main_ahook->out_limit); } proto_relink(p); @@ -953,43 +955,42 @@ proto_limit_name(struct proto_limit *l) * proto_notify_limit: notify about limit hit and take appropriate action * @ah: announce hook * @l: limit being hit + * @rt_count: the number of routes * * 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. + * according to @l->action. */ -int -proto_notify_limit(struct announce_hook *ah, struct proto_limit *l) +void +proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count) { struct proto *p = ah->proto; int dir = (ah->in_limit == l); - if (l->active) - return (l->action != PLA_WARN); + if (l->state == PLS_BLOCKED) + return; - 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)); + if (rt_count == l->limit) + 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; + l->state = PLS_ACTIVE; + break; case PLA_BLOCK: - return 1; + l->state = PLS_BLOCKED; + break; case PLA_RESTART: case PLA_DISABLE: + l->state = PLS_BLOCKED; proto_schedule_down(p, l->action == PLA_RESTART, dir ? PDC_IN_LIMIT_HIT : PDC_OUT_LIMIT_HIT); - return 1; + break; } - - return 0; } /** @@ -1101,9 +1102,11 @@ proto_show_stats(struct proto_stats *s) 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]" : ""); + if (!l) + return; + + cli_msg(-1006, " %-16s%d%s", dsc, l->limit, l->state ? " [HIT]" : ""); + cli_msg(-1006, " Action: %s", proto_limit_name(l)); } void @@ -1233,8 +1236,8 @@ proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED) * 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; + if (!p->proto->multitable) + proto_reset_limit(p->main_ahook->in_limit); } /* re-exporting routes */ diff --git a/nest/protocol.h b/nest/protocol.h index 3dd7cf2f..d8442acb 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -375,13 +375,24 @@ extern struct proto_config *cf_dev_proto; #define PLA_RESTART 4 /* Force protocol restart */ #define PLA_DISABLE 5 /* Shutdown and disable protocol */ +#define PLS_INITIAL 0 /* Initial limit state after protocol start */ +#define PLS_ACTIVE 1 /* Limit was hit */ +#define PLS_BLOCKED 2 /* Limit is active and blocking new routes */ + struct proto_limit { u32 limit; /* Maximum number of prefixes */ byte action; /* Action to take (PLA_*) */ - byte active; /* Limit is active */ + byte state; /* State of limit (PLS_*) */ }; -int proto_notify_limit(struct announce_hook *ah, struct proto_limit *l); +void proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count); + +static inline void proto_reset_limit(struct proto_limit *l) +{ + if (l) + l->state = PLS_INITIAL; +} + /* * Route Announcement Hook diff --git a/nest/rt-table.c b/nest/rt-table.c index 6a28fd43..6d82e1d3 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -485,12 +485,18 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str } struct proto_limit *l = ah->in_limit; - if (l && !old && new && (stats->imp_routes >= l->limit) && proto_notify_limit(ah, l)) + if (l && !old && new) { - stats->imp_updates_ignored++; - rte_trace_in(D_FILTERS, p, new, "ignored [limit]"); - rte_free_quick(new); - return; + if (stats->imp_routes >= l->limit) + proto_notify_limit(ah, l, stats->imp_routes); + + if (l->state == PLS_BLOCKED) + { + stats->imp_updates_ignored++; + rte_trace_in(D_FILTERS, p, new, "ignored [limit]"); + rte_free_quick(new); + return; + } } if (new) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index cf743dff..95dbe477 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1165,9 +1165,9 @@ bgp_show_proto_info(struct proto *P) p->rs_client ? " route-server" : "", p->as4_session ? " AS4" : ""); cli_msg(-1006, " Source address: %I", p->source_addr); - if (p->cf->route_limit) + if (P->cf->in_limit) cli_msg(-1006, " Route limit: %d/%d", - p->p.stats.imp_routes, p->cf->route_limit); + p->p.stats.imp_routes, P->cf->in_limit->limit); cli_msg(-1006, " Hold timer: %d/%d", tm_remains(c->hold_timer), c->hold_time); cli_msg(-1006, " Keepalive timer: %d/%d", diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index aa2db4b0..1c16f485 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -40,7 +40,6 @@ struct bgp_config { int rr_client; /* Whether neighbor is RR client of me */ int rs_client; /* Whether neighbor is RS client of me */ int advertise_ipv4; /* Whether we should add IPv4 capability advertisement to OPEN message */ - u32 route_limit; /* Number of routes that may be imported, 0 means disable limit */ int passive; /* Do not initiate outgoing connection */ int interpret_communities; /* Hardwired handling of well-known communities */ unsigned connect_retry_time; diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index a5fcc6f6..41bac474 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -127,10 +127,8 @@ pipe_reload_routes(struct proto *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; + proto_reset_limit(P->main_ahook->in_limit); + proto_reset_limit(p->peer_ahook->in_limit); return 1; } @@ -168,10 +166,12 @@ pipe_start(struct proto *P) 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; + proto_reset_limit(P->main_ahook->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; + proto_reset_limit(p->peer_ahook->in_limit); return PS_UP; }