]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Nest: Dropping global rte_update_pool
authorJan Maria Matejka <mq@ucw.cz>
Wed, 24 Jan 2018 15:00:42 +0000 (16:00 +0100)
committerJan Maria Matejka <mq@ucw.cz>
Wed, 26 Sep 2018 14:20:09 +0000 (16:20 +0200)
nest/route.h
nest/rt-table.c
proto/bgp/packets.c
proto/radv/radv.c
proto/static/static.c

index 2ec1dc7fa3158465930058bc134fb7ac49e20ac6..c0590f6e69c7607ad43acbafd83434df8dcfaf81 100644 (file)
@@ -295,7 +295,7 @@ rte *rte_find(net *net, struct rte_src *src);
 rte *rte_get_temp(struct rta *);
 void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
 /* rte_update() moved to protocol.h to avoid dependency conflicts */
-int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter);
+int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter, struct linpool *pool);
 rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent);
 void rt_refresh_begin(rtable *t, struct channel *c);
 void rt_refresh_end(rtable *t, struct channel *c);
@@ -626,12 +626,12 @@ void rta_dump_all(void);
 void rta_show(struct cli *, rta *);
 
 struct hostentry * rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep);
-void rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls);
+void rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls, struct linpool *lp);
 
 static inline void
-rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll, mpls_label_stack *mls)
+rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll, mpls_label_stack *mls, struct linpool *lp)
 {
-  rta_apply_hostentry(a, rt_get_hostentry(tab, gw, ll, dep), mls);
+  rta_apply_hostentry(a, rt_get_hostentry(tab, gw, ll, dep), mls, lp);
 }
 
 /*
index 036b34c4794765126708e20d3948003106d49b11..5f6f5720d09cd6542c8651d9f1bd9f90468d7b0c 100644 (file)
@@ -46,7 +46,6 @@
 pool *rt_table_pool;
 
 static slab *rte_slab;
-static linpool *rte_update_pool;
 
 static list routing_tables;
 
@@ -393,8 +392,8 @@ rte_trace_out(uint flag, struct proto *p, rte *e, char *msg)
     rte_trace(p, e, '<', msg);
 }
 
-static rte *
-export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int silent)
+rte *
+export_filter(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int silent)
 {
   struct proto *p = c->proto;
   struct filter *filter = c->out_filter;
@@ -450,12 +449,6 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
   return NULL;
 }
 
-static inline rte *
-export_filter(struct channel *c, rte *rt0, rte **rt_free, int silent)
-{
-  return export_filter_(c, rt0, rt_free, rte_update_pool, silent);
-}
-
 static void
 do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
 {
@@ -534,7 +527,7 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
 }
 
 static void
-rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, int refeed)
+rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, struct linpool *lp, int refeed)
 {
   struct proto *p = c->proto;
 
@@ -569,10 +562,10 @@ rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, int refeed)
    */
 
   if (new)
-    new = export_filter(c, new, &new_free, 0);
+    new = export_filter(c, new, &new_free, lp, 0);
 
   if (old && !(refeed || (old->lastmod <= c->last_tx_filter_change)))
-    old = export_filter(c, old, &old_free, 1);
+    old = export_filter(c, old, &old_free, lp, 1);
 
   if (!new && !old)
   {
@@ -605,7 +598,7 @@ rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, int refeed)
 }
 
 static void
-rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_changed, rte *before_old, int feed)
+rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_changed, rte *before_old, struct linpool *lp, int feed)
 {
   // struct proto *p = c->proto;
 
@@ -631,7 +624,7 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
   /* First, find the new_best route - first accepted by filters */
   for (r=net->routes; rte_is_valid(r); r=r->next)
     {
-      if (new_best = export_filter(c, r, &new_free, 0))
+      if (new_best = export_filter(c, r, &new_free, lp, 0))
        break;
 
       /* Note if we walked around the position of old_changed route */
@@ -692,7 +685,7 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
 
   /* First case */
   if (old_meet)
-    if (old_best = export_filter(c, old_changed, &old_free, 1))
+    if (old_best = export_filter(c, old_changed, &old_free, lp, 1))
       goto found;
 
   /* Second case */
@@ -710,11 +703,11 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
   /* Fourth case */
   for (r=r->next; rte_is_valid(r); r=r->next)
     {
-      if (old_best = export_filter(c, r, &old_free, 1))
+      if (old_best = export_filter(c, r, &old_free, lp, 1))
        goto found;
 
       if (r == before_old)
-       if (old_best = export_filter(c, old_changed, &old_free, 1))
+       if (old_best = export_filter(c, old_changed, &old_free, lp, 1))
          goto found;
     }
 
@@ -750,7 +743,7 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int
   if (!rte_is_valid(best0))
     return NULL;
 
-  best = export_filter_(c, best0, rt_free, pool, silent);
+  best = export_filter(c, best0, rt_free, pool, silent);
 
   if (!best || !rte_is_reachable(best))
     return best;
@@ -760,7 +753,7 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int
     if (!rte_mergable(best0, rt0))
       continue;
 
-    rt = export_filter_(c, rt0, &tmp, pool, 1);
+    rt = export_filter(c, rt0, &tmp, pool, 1);
 
     if (!rt)
       continue;
@@ -792,7 +785,7 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int
 
 static void
 rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed,
-                rte *new_best, rte*old_best, int refeed)
+                rte *new_best, rte *old_best, struct linpool *lp, int refeed)
 {
   // struct proto *p = c->proto;
 
@@ -811,10 +804,10 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
   if ((new_best == old_best) && !refeed)
   {
     new_changed = rte_mergable(new_best, new_changed) ?
-      export_filter(c, new_changed, &new_changed_free, 1) : NULL;
+      export_filter(c, new_changed, &new_changed_free, lp, 1) : NULL;
 
     old_changed = rte_mergable(old_best, old_changed) ?
-      export_filter(c, old_changed, &old_changed_free, 1) : NULL;
+      export_filter(c, old_changed, &old_changed_free, lp, 1) : NULL;
 
     if (!new_changed && !old_changed)
       return;
@@ -827,12 +820,12 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
 
   /* Prepare new merged route */
   if (new_best)
-    new_best = rt_export_merged(c, net, &new_best_free, rte_update_pool, 0);
+    new_best = rt_export_merged(c, net, &new_best_free, lp, 0);
 
   /* Prepare old merged route (without proper merged next hops) */
   /* There are some issues with running filter on old route - see rt_notify_basic() */
   if (old_best && !refeed)
-    old_best = export_filter(c, old_best, &old_best_free, 1);
+    old_best = export_filter(c, old_best, &old_best_free, lp, 1);
 
   if (new_best || old_best)
     do_rt_notify(c, net, new_best, old_best, refeed);
@@ -883,7 +876,7 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
  */
 static void
 rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old,
-            rte *new_best, rte *old_best, rte *before_old)
+            rte *new_best, rte *old_best, rte *before_old, struct linpool *lp)
 {
   if (!rte_is_valid(new))
     new = NULL;
@@ -911,11 +904,11 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old,
 
       if (c->ra_mode == type)
        if (type == RA_ACCEPTED)
-         rt_notify_accepted(c, net, new, old, before_old, 0);
+         rt_notify_accepted(c, net, new, old, before_old, lp, 0);
        else if (type == RA_MERGED)
-         rt_notify_merged(c, net, new, old, new_best, old_best, 0);
+         rt_notify_merged(c, net, new, old, new_best, old_best, lp, 0);
        else
-         rt_notify_basic(c, net, new, old, 0);
+         rt_notify_basic(c, net, new, old, lp, 0);
     }
 }
 
@@ -994,7 +987,7 @@ rte_same(rte *x, rte *y)
 static inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); }
 
 static void
-rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
+rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src, struct linpool *lp)
 {
   struct proto *p = c->proto;
   struct rtable *table = c->table;
@@ -1229,12 +1222,12 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
     }
 
   /* Propagate the route change */
-  rte_announce(table, RA_ANY, net, new, old, NULL, NULL, NULL);
+  rte_announce(table, RA_ANY, net, new, old, NULL, NULL, NULL, lp);
   if (net->routes != old_best)
-    rte_announce(table, RA_OPTIMAL, net, net->routes, old_best, NULL, NULL, NULL);
+    rte_announce(table, RA_OPTIMAL, net, net->routes, old_best, NULL, NULL, NULL, lp);
   if (table->config->sorted)
-    rte_announce(table, RA_ACCEPTED, net, new, old, NULL, NULL, before_old);
-  rte_announce(table, RA_MERGED, net, new, old, net->routes, old_best, NULL);
+    rte_announce(table, RA_ACCEPTED, net, new, old, NULL, NULL, before_old, lp);
+  rte_announce(table, RA_MERGED, net, new, old, net->routes, old_best, NULL, lp);
 
   if (!net->routes &&
       (table->gc_counter++ >= table->config->gc_max_ops) &&
@@ -1250,21 +1243,6 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
     rte_free_quick(old);
 }
 
-static int rte_update_nest_cnt;                /* Nesting counter to allow recursive updates */
-
-static inline void
-rte_update_lock(void)
-{
-  rte_update_nest_cnt++;
-}
-
-static inline void
-rte_update_unlock(void)
-{
-  if (!--rte_update_nest_cnt)
-    lp_flush(rte_update_pool);
-}
-
 static inline void
 rte_hide_dummy_routes(net *net, rte **dummy)
 {
@@ -1333,12 +1311,12 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
   struct proto *p = c->proto;
   struct proto_stats *stats = &c->stats;
   struct filter *filter = c->in_filter;
+  struct linpool *lp = lp_new(c->proto->pool, 1024);
   rte *dummy = NULL;
   net *nn;
 
   ASSERT(c->channel_state == CS_UP);
 
-  rte_update_lock();
   if (new)
     {
       nn = net_get(c->table, n);
@@ -1370,11 +1348,11 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
        }
       else
        {
-         rte_make_tmp_attrs(&new, rte_update_pool);
+         rte_make_tmp_attrs(&new, lp);
          if (filter && (filter != FILTER_REJECT))
            {
              ea_list *oldea = new->attrs->eattrs;
-             int fr = f_run(filter, &new, rte_update_pool, 0);
+             int fr = f_run(filter, &new, lp, 0);
              if (fr > F_ACCEPT)
                {
                  stats->imp_updates_filtered++;
@@ -1400,16 +1378,16 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
       if (!(nn = net_find(c->table, n)) || !src)
        {
          stats->imp_withdraws_ignored++;
-         rte_update_unlock();
-         return;
+         goto done;
        }
     }
 
  recalc:
   rte_hide_dummy_routes(nn, &dummy);
-  rte_recalculate(c, nn, new, src);
+  rte_recalculate(c, nn, new, src, lp);
   rte_unhide_dummy_routes(nn, &dummy);
-  rte_update_unlock();
+ done:
+  rfree(lp);
   return;
 
  drop:
@@ -1418,32 +1396,11 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
   goto recalc;
 }
 
-/* Independent call to rte_announce(), used from next hop
-   recalculation, outside of rte_update(). new must be non-NULL */
-static inline void
-rte_announce_i(rtable *tab, unsigned type, net *net, rte *new, rte *old,
-              rte *new_best, rte *old_best)
-{
-  rte_update_lock();
-  rte_announce(tab, type, net, new, old, new_best, old_best, NULL);
-  rte_update_unlock();
-}
-
-static inline void
-rte_discard(rte *old)  /* Non-filtered route deletion, used during garbage collection */
-{
-  rte_update_lock();
-  rte_recalculate(old->sender, old->net, NULL, old->attrs->src);
-  rte_update_unlock();
-}
-
 /* Modify existing route by protocol hook, used for long-lived graceful restart */
 static inline void
-rte_modify(rte *old)
+rte_modify(rte *old, struct linpool *lp)
 {
-  rte_update_lock();
-
-  rte *new = old->sender->proto->rte_modify(old, rte_update_pool);
+  rte *new = old->sender->proto->rte_modify(old, lp);
   if (new != old)
   {
     if (new)
@@ -1453,15 +1410,13 @@ rte_modify(rte *old)
       new->flags = (old->flags & ~REF_MODIFY) | REF_COW;
     }
 
-    rte_recalculate(old->sender, old->net, new, old->attrs->src);
+    rte_recalculate(old->sender, old->net, new, old->attrs->src, lp);
   }
-
-  rte_update_unlock();
 }
 
 /* Check rtable for best route to given net whether it would be exported do p */
 int
-rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
+rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter, struct linpool *lp)
 {
   net *n = net_find(t, a);
   rte *rt = n ? n->routes : NULL;
@@ -1469,20 +1424,16 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
   if (!rte_is_valid(rt))
     return 0;
 
-  rte_update_lock();
-
   /* Rest is stripped down export_filter() */
-  rte_make_tmp_attrs(&rt, rte_update_pool);
-  int v = p->import_control ? p->import_control(p, &rt, rte_update_pool) : 0;
+  rte_make_tmp_attrs(&rt, lp);
+  int v = p->import_control ? p->import_control(p, &rt, lp) : 0;
   if (v == RIC_PROCESS)
-    v = (f_run(filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT);
+    v = (f_run(filter, &rt, lp, FF_SILENT) <= F_ACCEPT);
 
    /* Discard temporary rte */
   if (rt != n->routes)
     rte_free(rt);
 
-  rte_update_unlock();
-
   return v > 0;
 }
 
@@ -1699,7 +1650,6 @@ rt_init(void)
 {
   rta_init();
   rt_table_pool = rp_new(&root_pool, "Routing tables");
-  rte_update_pool = lp_new_default(rt_table_pool);
   rte_slab = sl_new(rt_table_pool, sizeof(rte));
   init_list(&routing_tables);
 }
@@ -1764,7 +1714,10 @@ again:
                return;
              }
 
-           rte_discard(e);
+           /* Non-filtered route deletion */
+           struct linpool *lp = lp_new(e->sender->proto->pool, 1024);
+           rte_recalculate(e->sender, e->net, NULL, e->attrs->src, lp);
+           rfree(lp);
            limit--;
 
            goto rescan;
@@ -1779,7 +1732,9 @@ again:
                return;
              }
 
-           rte_modify(e);
+           struct linpool *lp = lp_new(e->sender->proto->pool, 1024);
+           rte_modify(e, lp);
+           rfree(lp);
            limit--;
 
            goto rescan;
@@ -1853,7 +1808,7 @@ rta_next_hop_outdated(rta *a)
 }
 
 void
-rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls)
+rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls, struct linpool *lp)
 {
   a->hostentry = he;
   a->dest = he->dest;
@@ -1888,7 +1843,7 @@ no_nexthop:
     else
     {
       nhr = nhp;
-      nhp = (nhp ? (nhp->next = lp_allocz(rte_update_pool, NEXTHOP_MAX_SIZE)) : &(a->nh));
+      nhp = (nhp ? (nhp->next = lp_allocz(lp, NEXTHOP_MAX_SIZE)) : &(a->nh));
     }
 
     nhp->iface = nh->iface;
@@ -1933,7 +1888,7 @@ no_nexthop:
 }
 
 static inline rte *
-rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
+rt_next_hop_update_rte(rtable *tab UNUSED, rte *old, struct linpool *lp)
 {
   rta *a = alloca(RTA_MAX_SIZE);
   memcpy(a, old->attrs, rta_size(old->attrs));
@@ -1941,7 +1896,7 @@ rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
   mpls_label_stack mls = { .len = a->nh.labels_orig };
   memcpy(mls.stack, &a->nh.label[a->nh.labels - mls.len], mls.len * sizeof(u32));
 
-  rta_apply_hostentry(a, old->attrs->hostentry, &mls);
+  rta_apply_hostentry(a, old->attrs->hostentry, &mls, lp);
   a->aflags = 0;
 
   rte *e = sl_alloc(rte_slab);
@@ -1962,13 +1917,15 @@ rt_next_hop_update_net(rtable *tab, net *n)
   if (!old_best)
     return 0;
 
+  struct linpool *lp = lp_new(rt_table_pool, 1024); /* TODO: screw it */
+
   for (k = &n->routes; e = *k; k = &e->next)
     if (rta_next_hop_outdated(e->attrs))
       {
-       new = rt_next_hop_update_rte(tab, e);
+       new = rt_next_hop_update_rte(tab, e, lp);
        *k = new;
 
-       rte_announce_i(tab, RA_ANY, n, new, e, NULL, NULL);
+       rte_announce(tab, RA_ANY, n, new, e, NULL, NULL, NULL, lp);
        rte_trace_in(D_ROUTES, new->sender->proto, new, "updated");
 
        /* Call a pre-comparison hook */
@@ -1986,7 +1943,10 @@ rt_next_hop_update_net(rtable *tab, net *n)
       }
 
   if (!count)
-    return 0;
+    {
+      rfree(lp);
+      return 0;
+    }
 
   /* Find the new best route */
   new_best = NULL;
@@ -2008,12 +1968,14 @@ rt_next_hop_update_net(rtable *tab, net *n)
   /* Announce the new best route */
   if (new != old_best)
     {
-      rte_announce_i(tab, RA_OPTIMAL, n, new, old_best, NULL, NULL);
+      rte_announce(tab, RA_OPTIMAL, n, new, old_best, NULL, NULL, NULL, lp);
       rte_trace_in(D_ROUTES, new->sender->proto, new, "updated [best]");
     }
 
   /* FIXME: Better announcement of merged routes */
-  rte_announce_i(tab, RA_MERGED, n, new, old_best, new, old_best);
+  rte_announce(tab, RA_MERGED, n, new, old_best, new, old_best, NULL, lp);
+
+  rfree(lp);
 
   if (free_old_best)
     rte_free_quick(old_best);
@@ -2194,14 +2156,14 @@ rt_commit(struct config *new, struct config *old)
 static inline void
 do_feed_channel(struct channel *c, net *n, rte *e)
 {
-  rte_update_lock();
+  struct linpool *lp = lp_new(c->proto->pool, 1024);
   if (c->ra_mode == RA_ACCEPTED)
-    rt_notify_accepted(c, n, e, NULL, NULL, c->refeeding ? 2 : 1);
+    rt_notify_accepted(c, n, e, NULL, NULL, lp, c->refeeding ? 2 : 1);
   else if (c->ra_mode == RA_MERGED)
-    rt_notify_merged(c, n, NULL, NULL, e, c->refeeding ? e : NULL, c->refeeding);
+    rt_notify_merged(c, n, NULL, NULL, e, c->refeeding ? e : NULL, lp, c->refeeding);
   else /* RA_BASIC */
-    rt_notify_basic(c, n, e, c->refeeding ? e : NULL, c->refeeding);
-  rte_update_unlock();
+    rt_notify_basic(c, n, e, c->refeeding ? e : NULL, lp, c->refeeding);
+  rfree(lp);
 }
 
 /**
index ed1db04b229013549e4ad510e58f6502b95517e2..dc65ec9e9ad345588c8afa32047c772182faabe0 100644 (file)
@@ -832,7 +832,7 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
     s->hostentry = rt_get_hostentry(tab, gw, ll, c->c.table);
 
     if (!s->mpls)
-      rta_apply_hostentry(a, s->hostentry, NULL);
+      rta_apply_hostentry(a, s->hostentry, NULL, s->pool);
 
     /* With MPLS, hostentry is applied later in bgp_apply_mpls_labels() */
   }
@@ -866,7 +866,7 @@ bgp_apply_mpls_labels(struct bgp_parse_state *s, rta *a, u32 *labels, uint lnum)
 
     ms.len = lnum;
     memcpy(ms.stack, labels, 4*lnum);
-    rta_apply_hostentry(a, s->hostentry, &ms);
+    rta_apply_hostentry(a, s->hostentry, &ms, s->pool);
   }
 }
 
index a381f7372a491509a2dd310e6c1a52c98e80b727..d719ad781b2664ce05a04ede1271851e70085114 100644 (file)
@@ -560,7 +560,9 @@ radv_check_active(struct radv_proto *p)
     return 1;
 
   struct channel *c = p->p.main_channel;
-  return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter);
+  struct linpool *lp = lp_new(p->p.pool, 1024);
+  return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter, lp);
+  rfree(lp);
 }
 
 static void
index 40096c16227645ae5efea98fa6275be7644a9438..6984db64fdf3d080898758d1dfa0df336493bf69 100644 (file)
@@ -91,7 +91,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
   if (r->dest == RTDX_RECURSIVE)
   {
     rtable *tab = ipa_is_ip4(r->via) ? p->igp_table_ip4 : p->igp_table_ip6;
-    rta_set_recursive_next_hop(p->p.main_channel->table, a, tab, r->via, IPA_NONE, r->mls);
+    rta_set_recursive_next_hop(p->p.main_channel->table, a, tab, r->via, IPA_NONE, r->mls, static_lp);
   }
 
   /* Already announced */