diff --git a/nest/rt-table.c b/nest/rt-table.c index dbe0c50d..24517e2c 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); @@ -1365,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); @@ -1392,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) { @@ -1402,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)--; @@ -1445,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); } /** @@ -1454,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; } 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); }