diff options
Diffstat (limited to 'nest/rt-table.c')
-rw-r--r-- | nest/rt-table.c | 73 |
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) |