summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2018-07-03 19:21:42 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2018-07-03 19:21:59 +0200
commitcbfdf6ed057b993d7e107b4c39b8a5b81c081eee (patch)
tree0c6255bb81f037ceff0dfa9409a5829069ea24e1 /nest
parent822a7ee6d5cd9bf38548026e0dd52fbc4634030d (diff)
Nest: Fix race condition during reconfiguration
If export filter is changed during reconfiguration and a route disappears between reconfiguration and refeed (e.g., if the route is a static route also removed during the reconfiguration), the route is not withdrawn. The patch fixes that by adding tx reconfiguration timestamp.
Diffstat (limited to 'nest')
-rw-r--r--nest/proto.c19
-rw-r--r--nest/protocol.h1
-rw-r--r--nest/rt-table.c6
3 files changed, 16 insertions, 10 deletions
diff --git a/nest/proto.c b/nest/proto.c
index 552d53ae..565b238f 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -433,10 +433,17 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
if (p->proto->multitable)
return 1;
+ int import_changed = ! filter_same(nc->in_filter, oc->in_filter);
+ int export_changed = ! filter_same(nc->out_filter, oc->out_filter);
+
+ /* We treat a change in preferences by reimporting routes */
+ if (nc->preference != oc->preference)
+ import_changed = 1;
+
/* Update filters and limits in the main announce hook
Note that this also resets limit state */
if (p->main_ahook)
- {
+ {
struct announce_hook *ah = p->main_ahook;
ah->in_filter = nc->in_filter;
ah->out_filter = nc->out_filter;
@@ -445,6 +452,9 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
ah->out_limit = nc->out_limit;
ah->in_keep_filtered = nc->in_keep_filtered;
proto_verify_limits(ah);
+
+ if (export_changed)
+ ah->last_out_filter_change = now;
}
/* Update routes when filters changed. If the protocol in not UP,
@@ -452,13 +462,6 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
if ((p->proto_state != PS_UP) || (type == RECONFIG_SOFT))
return 1;
- int import_changed = ! filter_same(nc->in_filter, oc->in_filter);
- int export_changed = ! filter_same(nc->out_filter, oc->out_filter);
-
- /* We treat a change in preferences by reimporting routes */
- if (nc->preference != oc->preference)
- import_changed = 1;
-
if (import_changed || export_changed)
log(L_INFO "Reloading protocol %s", p->name);
diff --git a/nest/protocol.h b/nest/protocol.h
index 5aca9a4e..4fb76e2b 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -471,6 +471,7 @@ struct announce_hook {
struct proto_stats *stats; /* Per-table protocol statistics */
struct announce_hook *next; /* Next hook for the same protocol */
int in_keep_filtered; /* Routes rejected in import filter are kept */
+ bird_clock_t last_out_filter_change; /* Last time when out_filter _changed_ */
};
struct announce_hook *proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats);
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 28fe5baa..07bb0b12 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -426,13 +426,15 @@ rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int re
* reconfiguration 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).
+ * 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.
*/
if (new)
new = export_filter(ah, new, &new_free, &tmpa, 0);
- if (old && !refeed)
+ if (old && !(refeed || (old->lastmod <= ah->last_out_filter_change)))
old = export_filter(ah, old, &old_free, NULL, 1);
if (!new && !old)