summaryrefslogtreecommitdiff
path: root/nest/rt-table.c
diff options
context:
space:
mode:
Diffstat (limited to 'nest/rt-table.c')
-rw-r--r--nest/rt-table.c73
1 files changed, 65 insertions, 8 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c
index eb8304f7..165f42bb 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -250,6 +250,53 @@ do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tm
struct proto *p = ah->proto;
struct proto_stats *stats = ah->stats;
+
+ /*
+ * First, apply export limit.
+ *
+ * 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)
+ {
+ if ((!old || refeed) && (stats->exp_routes >= l->limit))
+ proto_notify_limit(ah, l, stats->exp_routes);
+
+ if (l->state == PLS_BLOCKED)
+ {
+ stats->exp_routes++; /* see note above */
+ stats->exp_updates_rejected++;
+ rte_trace_out(D_FILTERS, p, new, "rejected [limit]");
+ new = NULL;
+
+ if (!old)
+ return;
+ }
+ }
+
+
if (new)
stats->exp_updates_accepted++;
else
@@ -284,10 +331,8 @@ do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tm
}
else
p->rt_notify(p, ah->table, net, new, old, new->attrs->eattrs);
-
}
-
static void
rt_notify_basic(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
{
@@ -632,6 +677,21 @@ 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)
+ {
+ 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)
stats->imp_updates_accepted++;
else
@@ -911,10 +971,7 @@ void
rte_dump(rte *e)
{
net *n = e->net;
- if (n)
- debug("%-1I/%2d ", n->n.prefix, n->n.pxlen);
- else
- debug("??? ");
+ debug("%-1I/%2d ", n->n.prefix, n->n.pxlen);
debug("KF=%02x PF=%02x pref=%d lm=%d ", n->n.flags, e->pflags, e->pref, now-e->lastmod);
rta_dump(e->attrs);
if (e->attrs->proto->proto->dump_attrs)
@@ -1923,14 +1980,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)