diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/config.Y | 10 | ||||
-rw-r--r-- | nest/protocol.h | 3 | ||||
-rw-r--r-- | nest/rt-table.c | 48 |
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) |