summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/config.Y10
-rw-r--r--nest/protocol.h3
-rw-r--r--nest/rt-table.c48
3 files changed, 43 insertions, 18 deletions
diff --git a/nest/config.Y b/nest/config.Y
index c59319cb..14cff10a 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -44,7 +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(LIMIT, ACTION, 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)
@@ -194,10 +194,10 @@ imexport:
limit_action:
/* default */ { $$ = PLA_DISABLE; }
- | EXCEED WARN { $$ = PLA_WARN; }
- | EXCEED BLOCK { $$ = PLA_BLOCK; }
- | EXCEED RESTART { $$ = PLA_RESTART; }
- | EXCEED DISABLE { $$ = PLA_DISABLE; }
+ | ACTION WARN { $$ = PLA_WARN; }
+ | ACTION BLOCK { $$ = PLA_BLOCK; }
+ | ACTION RESTART { $$ = PLA_RESTART; }
+ | ACTION DISABLE { $$ = PLA_DISABLE; }
;
limit_spec:
diff --git a/nest/protocol.h b/nest/protocol.h
index 3f9ed96e..8a632715 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -387,7 +387,8 @@ struct proto_limit {
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)
+static inline void
+proto_reset_limit(struct proto_limit *l)
{
if (l)
l->state = PLS_INITIAL;
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 06121ea3..bb0ee4c8 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -269,27 +269,52 @@ do_rte_announce(struct announce_hook *ah, int type UNUSED, net *net, rte *new, r
}
}
- /* FIXME - This is broken because of incorrect 'old' value (see above) */
- if (!new && !old)
- return;
+ /*
+ * Export route limits has several problems. Because exp_routes
+ * counter is reset before refeed, we don't really know whether
+ * limit is breached and whether the update is new or not Therefore
+ * the number of really exported routes may exceed the limit
+ * temporarily (routes exported before and new routes in refeed).
+ *
+ * Minor advantage is that if the limit is decreased and refeed is
+ * requested, the number of exported routes really decrease.
+ *
+ * Second problem is that with export limits, we don't know whether
+ * old was really exported (it might be blocked by limit). When a
+ * withdraw is exported, we announce it even when the previous
+ * update was blocked. This is not a big issue, but the same problem
+ * is in updating exp_routes counter. Therefore, to be consistent in
+ * increases and decreases of exp_routes, we count exported routes
+ * regardless of blocking by limits.
+ *
+ * Similar problem is in handling updates - when a new route is
+ * received and blocking is active, the route would be blocked, but
+ * when an update for the route will be received later, the update
+ * would be propagated (as old != NULL). Therefore, we have to block
+ * also non-new updates (contrary to import blocking).
+ */
struct proto_limit *l = ah->out_limit;
- if (l && new && (!old || refeed))
+ if (l && new)
{
- if (stats->exp_routes >= l->limit)
+ if ((!old || refeed) && (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_routes++; /* see note above */
stats->exp_updates_rejected++;
rte_trace_out(D_FILTERS, p, new, "rejected [limit]");
- goto done;
+ if (new != new0)
+ rte_free(new);
+ new = NULL;
}
}
+ /* FIXME - This is broken because of incorrect 'old' value (see above) */
+ if (!new && !old)
+ return;
+
if (new)
stats->exp_updates_accepted++;
else
@@ -325,7 +350,6 @@ 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)
@@ -1781,14 +1805,14 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
d->net_counter++;
for(e=n->routes; e; e=e->next)
{
- struct ea_list *tmpa, *old_tmpa;
+ struct ea_list *tmpa;
struct proto *p0 = e->attrs->proto;
struct proto *p1 = d->export_protocol;
struct proto *p2 = d->show_protocol;
d->rt_counter++;
ee = e;
rte_update_lock(); /* We use the update buffer for filtering */
- old_tmpa = tmpa = p0->make_tmp_attrs ? p0->make_tmp_attrs(e, rte_update_pool) : NULL;
+ tmpa = p0->make_tmp_attrs ? p0->make_tmp_attrs(e, rte_update_pool) : NULL;
ok = (d->filter == FILTER_ACCEPT || f_run(d->filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
if (p2 && p2 != p0) ok = 0;
if (ok && d->export_mode)