diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/proto.c | 8 | ||||
-rw-r--r-- | nest/protocol.h | 1 | ||||
-rw-r--r-- | nest/rt-table.c | 48 |
3 files changed, 40 insertions, 17 deletions
diff --git a/nest/proto.c b/nest/proto.c index fadce6c7..d4a333d0 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -1693,11 +1693,11 @@ channel_show_stats(struct channel *c) struct proto_stats *s = &c->stats; if (c->in_keep_filtered) - cli_msg(-1006, " Routes: %u imported, %u filtered, %u exported", - s->imp_routes, s->filt_routes, s->exp_routes); + cli_msg(-1006, " Routes: %u imported, %u filtered, %u exported, %u preferred", + s->imp_routes, s->filt_routes, s->exp_routes, s->pref_routes); else - cli_msg(-1006, " Routes: %u imported, %u exported", - s->imp_routes, s->exp_routes); + cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred", + s->imp_routes, s->exp_routes, s->pref_routes); cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", diff --git a/nest/protocol.h b/nest/protocol.h index 7f539aef..6c04071b 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -134,6 +134,7 @@ struct proto_stats { /* Import - from protocol to core */ u32 imp_routes; /* Number of routes successfully imported to the (adjacent) routing table */ u32 filt_routes; /* Number of routes rejected in import filter but kept in the routing table */ + u32 pref_routes; /* Number of routes selected as best in the (adjacent) routing table */ u32 imp_updates_received; /* Number of route updates received */ u32 imp_updates_invalid; /* Number of route updates rejected as invalid */ u32 imp_updates_filtered; /* Number of route updates rejected by filters */ diff --git a/nest/rt-table.c b/nest/rt-table.c index 61ddb8c0..a1900532 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -564,33 +564,47 @@ rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, int refeed) * and the end of refeed - if a newly filtered route disappears during this * period, proper withdraw is not sent (because old would be also filtered) * and the route is not refeeded (because it disappeared before that). - * Therefore, we also do not try to run the filter on old routes that are - * older than the last filter change. + * This is handled below as a special case. */ if (new) new = export_filter(c, new, &new_free, 0); - if (old && !(refeed || (old->lastmod <= c->last_tx_filter_change))) + if (old && !refeed) old = export_filter(c, old, &old_free, 1); if (!new && !old) { /* * As mentioned above, 'old' value may be incorrect in some race conditions. - * We generally ignore it with the exception of withdraw to pipe protocol. - * In that case we rather propagate unfiltered withdraws regardless of - * export filters to ensure that when a protocol is flushed, its routes are - * removed from all tables. Possible spurious unfiltered withdraws are not - * problem here as they are ignored if there is no corresponding route at - * the other end of the pipe. We directly call rt_notify() hook instead of + * We generally ignore it with two exceptions: + * + * First, withdraw to pipe protocol. In that case we rather propagate + * unfiltered withdraws regardless of export filters to ensure that when a + * protocol is flushed, its routes are removed from all tables. Possible + * spurious unfiltered withdraws are not problem here as they are ignored if + * there is no corresponding route at the other end of the pipe. + * + * Second, recent filter change. If old route is older than filter change, + * then it was previously evaluated by a different filter and we do not know + * whether it was really propagated. In that case we rather send spurious + * withdraw than do nothing and possibly cause phantom routes. + * + * In both cases wqe directly call rt_notify() hook instead of * do_rt_notify() to avoid logging and stat counters. */ + int pipe_withdraw = 0, filter_change = 0; #ifdef CONFIG_PIPE - if ((p->proto == &proto_pipe) && !new0 && (p != old0->sender->proto)) - p->rt_notify(p, c, net, NULL, old0); + pipe_withdraw = (p->proto == &proto_pipe) && !new0; #endif + filter_change = old0 && (old0->lastmod <= c->last_tx_filter_change); + + if ((pipe_withdraw || filter_change) && (p != old0->sender->proto)) + { + c->stats.exp_withdraws_accepted++; + p->rt_notify(p, c, net, NULL, old0); + } return; } @@ -900,8 +914,16 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, if (!old && !new) return; - if ((type == RA_OPTIMAL) && tab->hostcache) - rt_notify_hostcache(tab, net); + if (type == RA_OPTIMAL) + { + if (new) + new->sender->stats.pref_routes++; + if (old) + old->sender->stats.pref_routes--; + + if (tab->hostcache) + rt_notify_hostcache(tab, net); + } struct channel *c; node *n; WALK_LIST2(c, n, tab->channels, table_node) |