summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/proto.c8
-rw-r--r--nest/protocol.h1
-rw-r--r--nest/rt-table.c48
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)