summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/config.Y14
-rw-r--r--nest/proto.c71
-rw-r--r--nest/protocol.h19
-rw-r--r--nest/rt-table.c35
4 files changed, 96 insertions, 43 deletions
diff --git a/nest/config.Y b/nest/config.Y
index 60b03278..c59319cb 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -179,6 +179,7 @@ proto_item:
| IMPORT imexport { this_proto->in_filter = $2; }
| EXPORT imexport { this_proto->out_filter = $2; }
| IMPORT LIMIT limit_spec { this_proto->in_limit = $3; }
+ | EXPORT LIMIT limit_spec { this_proto->out_limit = $3; }
| TABLE rtable { this_proto->table = $2; }
| ROUTER ID idval { this_proto->router_id = $3; }
| DESCRIPTION TEXT { this_proto->dsc = $2; }
@@ -192,17 +193,18 @@ imexport:
;
limit_action:
- WARN { $$ = PLA_WARN; }
- | BLOCK { $$ = PLA_BLOCK; }
- | RESTART { $$ = PLA_RESTART; }
- | DISABLE { $$ = PLA_DISABLE; }
+ /* default */ { $$ = PLA_DISABLE; }
+ | EXCEED WARN { $$ = PLA_WARN; }
+ | EXCEED BLOCK { $$ = PLA_BLOCK; }
+ | EXCEED RESTART { $$ = PLA_RESTART; }
+ | EXCEED DISABLE { $$ = PLA_DISABLE; }
;
limit_spec:
- expr EXCEED limit_action {
+ expr limit_action {
struct proto_limit *l = cfg_allocz(sizeof(struct proto_limit));
l->limit = $1;
- l->action = $3;
+ l->action = $2;
$$ = l;
}
;
diff --git a/nest/proto.c b/nest/proto.c
index 418a7a61..887d3e5e 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -406,13 +406,14 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
if (p->proto->multitable)
return 1;
- /* Update filters in the main announce hook */
+ /* Update filters and limits in the main announce hook
+ Note that this also resets limit state */
if (p->main_ahook)
{
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;
+ p->main_ahook->out_limit = nc->out_limit;
}
/* Update routes when filters changed. If the protocol in not UP,
@@ -774,9 +775,16 @@ proto_schedule_feed(struct proto *p, int initial)
p->core_state = FS_FEEDING;
p->refeeding = !initial;
- /* Hack: reset exp_routes during refeed, and do not decrease it later */
+ /* FIXME: This should be changed for better support of multitable protos */
if (!initial)
- p->stats.exp_routes = 0;
+ {
+ struct announce_hook *ah;
+ for (ah = p->ahooks; ah; ah = ah->next)
+ proto_reset_limit(ah->out_limit);
+
+ /* Hack: reset exp_routes during refeed, and do not decrease it later */
+ p->stats.exp_routes = 0;
+ }
/* Connect protocol to routing table */
if (initial && !p->proto->multitable)
@@ -785,7 +793,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;
- // p->main_ahook->out_limit = p->cf->out_limit;
+ p->main_ahook->out_limit = p->cf->out_limit;
+ proto_reset_limit(p->main_ahook->in_limit);
+ proto_reset_limit(p->main_ahook->out_limit);
}
proto_relink(p);
@@ -870,6 +880,8 @@ proto_schedule_flush(struct proto *p)
proto_schedule_flush_loop();
}
+/* Temporary hack to propagate restart to BGP */
+int proto_restart;
static void
proto_shutdown_loop(struct timer *t UNUSED)
@@ -879,11 +891,11 @@ proto_shutdown_loop(struct timer *t UNUSED)
WALK_LIST_DELSAFE(p, p_next, active_proto_list)
if (p->down_sched)
{
- int restart = (p->down_sched == PDS_RESTART);
+ proto_restart = (p->down_sched == PDS_RESTART);
p->disabled = 1;
proto_rethink_goal(p);
- if (restart)
+ if (proto_restart)
{
p->disabled = 0;
proto_rethink_goal(p);
@@ -953,43 +965,43 @@ 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));
+ /* For warning action, we want the log message every time we hit the limit */
+ if (!l->state || ((l->action == PLA_WARN) && (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 +1113,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
@@ -1115,6 +1129,7 @@ proto_show_basic_info(struct proto *p)
cli_msg(-1006, " Output filter: %s", filter_name(p->cf->out_filter));
proto_show_limit(p->cf->in_limit, "Import limit:");
+ proto_show_limit(p->cf->out_limit, "Export limit:");
if (p->proto_state != PS_DOWN)
proto_show_stats(&p->stats);
@@ -1233,8 +1248,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..3f9ed96e 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -95,7 +95,7 @@ struct proto_config {
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 */
+ struct proto_limit *out_limit; /* Limit for exporting routes to protocol */
/* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
@@ -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
@@ -394,7 +405,7 @@ struct announce_hook {
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_limit *out_limit; /* Output limit */
struct proto_stats *stats; /* Per-table protocol statistics */
struct announce_hook *next; /* Next hook for the same protocol */
};
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 6a28fd43..06121ea3 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -273,6 +273,23 @@ do_rte_announce(struct announce_hook *ah, int type UNUSED, net *net, rte *new, r
if (!new && !old)
return;
+ struct proto_limit *l = ah->out_limit;
+ if (l && new && (!old || refeed))
+ {
+ if (stats->exp_routes >= l->limit)
+ proto_notify_limit(ah, l, stats->exp_routes);
+
+ if (l->state == PLS_BLOCKED)
+ {
+ /* Exported route counter ignores whether the route was
+ blocked by limit, to be consistent when limits change */
+ stats->exp_routes++;
+ stats->exp_updates_rejected++;
+ rte_trace_out(D_FILTERS, p, new, "rejected [limit]");
+ goto done;
+ }
+ }
+
if (new)
stats->exp_updates_accepted++;
else
@@ -307,6 +324,8 @@ do_rte_announce(struct announce_hook *ah, int type UNUSED, net *net, rte *new, r
}
else
p->rt_notify(p, ah->table, net, new, old, new->attrs->eattrs);
+
+ done:
if (new && new != new0) /* Discard temporary rte's */
rte_free(new);
if (old && old != old0)
@@ -485,12 +504,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)