From 38e835dede88158d97c3039ed22faabed79c7181 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 13 May 2015 13:19:26 +0200 Subject: [PATCH 1/3] Fix in the last commit --- sysdep/linux/netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 72837ce0..71f58554 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -316,7 +316,7 @@ nl_add_multipath(struct nlmsghdr *h, unsigned bufsize, struct mpnh *nh) rtnh->rtnh_hops = nh->weight; rtnh->rtnh_ifindex = nh->iface->index; - nl_add_attr_u32(h, bufsize, RTA_GATEWAY, nh->gw); + nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw); nl_close_nexthop(h, rtnh); } From 86f567e13c2202fc3c3a1ce49f9a35220a50f117 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 16 May 2015 20:17:59 +0200 Subject: [PATCH 2/3] Fix minor issue in pipe route propagation In some circumstances during reconfiguration, routes propagated by pipes to other tables may hang there even after the primary routes are removed. There is already a workaround for this issue in the code which removes these stale routes by flush process when source protocols are shut down. This patch is a cleaner fix and allows to simplify the flush process --- nest/rt-table.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/nest/rt-table.c b/nest/rt-table.c index dbe0c50d..a8fe137c 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -347,11 +347,13 @@ do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tm } static void -rt_notify_basic(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tmpa, int refeed) +rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, ea_list *tmpa, int refeed) { - // struct proto *p = ah->proto; + struct proto *p = ah->proto; struct proto_stats *stats = ah->stats; + rte *new = new0; + rte *old = old0; rte *new_free = NULL; rte *old_free = NULL; @@ -369,7 +371,7 @@ rt_notify_basic(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list * FIXME - this is broken because 'configure soft' may change * filters but keep routes. Refeed is expected to be called after * change of the filters and with old == new, therefore we do not - * even try to run the filter on an old route, This may lead to + * even try to run the filter on an old route, This may lead to * 'spurious withdraws' but ensure that there are no 'missing * withdraws'. * @@ -386,9 +388,26 @@ rt_notify_basic(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list if (old && !refeed) old = export_filter(ah, old, &old_free, NULL, 1); - /* FIXME - This is broken because of incorrect 'old' value (see above) */ 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 + * do_rt_notify() to avoid logging and stat counters. + */ + +#ifdef CONFIG_PIPE + if ((p->proto == &proto_pipe) && !new0 && (p != old0->sender->proto)) + p->rt_notify(p, ah->table, net, NULL, old0, NULL); +#endif + return; + } do_rt_notify(ah, net, new, old, tmpa, refeed); From d0e23d42de133de706151411d8d4091d07904d29 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sun, 17 May 2015 00:54:33 +0200 Subject: [PATCH 3/3] Simplify flushing process Related to changes from previous patch. --- nest/rt-table.c | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/nest/rt-table.c b/nest/rt-table.c index a8fe137c..24517e2c 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1384,9 +1384,8 @@ rt_init(void) static int -rt_prune_step(rtable *tab, int step, int *limit) +rt_prune_step(rtable *tab, int *limit) { - static struct tbf rl_flush = TBF_DEFAULT_LOG_LIMITS; struct fib_iterator *fit = &tab->prune_fit; DBG("Pruning route table %s\n", tab->name); @@ -1411,9 +1410,7 @@ again: rescan: for (e=n->routes; e; e=e->next) - if (e->sender->proto->flushing || - (e->flags & REF_DISCARD) || - (step && e->attrs->src->proto->flushing)) + if (e->sender->proto->flushing || (e->flags & REF_DISCARD)) { if (*limit <= 0) { @@ -1421,10 +1418,6 @@ again: return 0; } - if (step) - log_rl(&rl_flush, L_WARN "Route %I/%d from %s still in %s after flush", - n->n.prefix, n->n.pxlen, e->attrs->src->proto->name, tab->name); - rte_discard(tab, e); (*limit)--; @@ -1464,7 +1457,7 @@ static inline int rt_prune_table(rtable *tab) { int limit = 512; - return rt_prune_step(tab, 0, &limit); + return rt_prune_step(tab, &limit); } /** @@ -1473,37 +1466,17 @@ rt_prune_table(rtable *tab) * The prune loop scans routing tables and removes routes belonging to flushing * protocols, discarded routes and also stale network entries. Returns 1 when * all such routes are pruned. It is a part of the protocol flushing loop. - * - * The prune loop runs in two steps. In the first step it prunes just the routes - * with flushing senders (in explicitly marked tables) so the route removal is - * propagated as usual. In the second step, all remaining relevant routes are - * removed. Ideally, there shouldn't be any, but it happens when pipe filters - * are changed. */ int rt_prune_loop(void) { - static int step = 0; int limit = 512; rtable *t; - again: WALK_LIST(t, routing_tables) - if (! rt_prune_step(t, step, &limit)) + if (! rt_prune_step(t, &limit)) return 0; - if (step == 0) - { - /* Prepare for the second step */ - WALK_LIST(t, routing_tables) - t->prune_state = RPS_SCHEDULED; - - step = 1; - goto again; - } - - /* Done */ - step = 0; return 1; }