mirror of
				https://gitlab.labs.nic.cz/labs/bird.git
				synced 2024-05-11 16:54:54 +00:00 
			
		
		
		
	Secondary and merged exports get a whole feed instead of traversing the table structures directly
This commit is contained in:
		@@ -335,7 +335,7 @@ static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) f
 | 
				
			|||||||
void *net_route(rtable *tab, const net_addr *n);
 | 
					void *net_route(rtable *tab, const net_addr *n);
 | 
				
			||||||
int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
 | 
					int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
 | 
				
			||||||
int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
 | 
					int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
 | 
				
			||||||
rte *rt_export_merged(struct channel *c, net *net, linpool *pool, int silent);
 | 
					rte *rt_export_merged_show(struct channel *c, net *n, linpool *pool);
 | 
				
			||||||
void rt_refresh_begin(rtable *t, struct channel *c);
 | 
					void rt_refresh_begin(rtable *t, struct channel *c);
 | 
				
			||||||
void rt_refresh_end(rtable *t, struct channel *c);
 | 
					void rt_refresh_end(rtable *t, struct channel *c);
 | 
				
			||||||
void rt_modify_stale(rtable *t, struct channel *c);
 | 
					void rt_modify_stale(rtable *t, struct channel *c);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -143,7 +143,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
	  /* Special case for merged export */
 | 
						  /* Special case for merged export */
 | 
				
			||||||
	  pass = 1;
 | 
						  pass = 1;
 | 
				
			||||||
	  rte *em = rt_export_merged(ec, n, c->show_pool, 1);
 | 
						  rte *em = rt_export_merged_show(ec, n, c->show_pool);
 | 
				
			||||||
	  if (em)
 | 
						  if (em)
 | 
				
			||||||
	    e = *em;
 | 
						    e = *em;
 | 
				
			||||||
	  else
 | 
						  else
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										279
									
								
								nest/rt-table.c
									
									
									
									
									
								
							
							
						
						
									
										279
									
								
								nest/rt-table.c
									
									
									
									
									
								
							@@ -51,6 +51,13 @@ static linpool *rte_update_pool;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
list routing_tables;
 | 
					list routing_tables;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rt_pending_export {
 | 
				
			||||||
 | 
					  struct rte_storage *new;		/* New route */
 | 
				
			||||||
 | 
					  struct rte_storage *new_best;		/* New best route */
 | 
				
			||||||
 | 
					  struct rte_storage *old;		/* Old route */
 | 
				
			||||||
 | 
					  struct rte_storage *old_best;		/* Old best route */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void rt_free_hostcache(rtable *tab);
 | 
					static void rt_free_hostcache(rtable *tab);
 | 
				
			||||||
static void rt_notify_hostcache(rtable *tab, net *net);
 | 
					static void rt_notify_hostcache(rtable *tab, net *net);
 | 
				
			||||||
static void rt_update_hostcache(rtable *tab);
 | 
					static void rt_update_hostcache(rtable *tab);
 | 
				
			||||||
@@ -370,6 +377,29 @@ rte_trace_out(uint flag, struct channel *c, rte *e, const char *msg)
 | 
				
			|||||||
    rte_trace(c, e, '<', msg);
 | 
					    rte_trace(c, e, '<', msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint
 | 
				
			||||||
 | 
					rte_feed_count(net *n)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  uint count = 0;
 | 
				
			||||||
 | 
					  for (struct rte_storage *e = n->routes; e; e = e->next)
 | 
				
			||||||
 | 
					    if (rte_is_valid(RTE_OR_NULL(e)))
 | 
				
			||||||
 | 
					      count++;
 | 
				
			||||||
 | 
					  return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					rte_feed_obtain(net *n, struct rte **feed, uint count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  uint i = 0;
 | 
				
			||||||
 | 
					  for (struct rte_storage *e = n->routes; e; e = e->next)
 | 
				
			||||||
 | 
					    if (rte_is_valid(RTE_OR_NULL(e)))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      ASSERT_DIE(i < count);
 | 
				
			||||||
 | 
					      feed[i++] = &e->rte;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ASSERT_DIE(i == count);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static rte *
 | 
					static rte *
 | 
				
			||||||
export_filter_(struct channel *c, rte *rt, linpool *pool, int silent)
 | 
					export_filter_(struct channel *c, rte *rt, linpool *pool, int silent)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -523,81 +553,71 @@ rt_notify_basic(struct channel *c, const net_addr *net, rte *new, rte *old, int
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_changed, int refeed)
 | 
					rt_notify_accepted(struct channel *c, const net_addr *n, struct rt_pending_export *rpe,
 | 
				
			||||||
 | 
					    struct rte **feed, uint count, int refeed)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  // struct proto *p = c->proto;
 | 
					  rte nb0, *new_best = NULL, *old_best = NULL;
 | 
				
			||||||
  rte nb0;
 | 
					 | 
				
			||||||
  rte *new_best = NULL;
 | 
					 | 
				
			||||||
  rte *old_best = NULL;
 | 
					 | 
				
			||||||
  int new_first = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*
 | 
					  for (uint i = 0; i < count; i++)
 | 
				
			||||||
   * We assume that there are no changes in net route order except (added)
 | 
					 | 
				
			||||||
   * new_changed and (removed) old_changed. Therefore, the function is not
 | 
					 | 
				
			||||||
   * compatible with deterministic_med (where nontrivial reordering can happen
 | 
					 | 
				
			||||||
   * as a result of a route change) and with recomputation of recursive routes
 | 
					 | 
				
			||||||
   * due to next hop update (where many routes can be changed in one step).
 | 
					 | 
				
			||||||
   *
 | 
					 | 
				
			||||||
   * Note that we need this assumption just for optimizations, we could just
 | 
					 | 
				
			||||||
   * run full new_best recomputation otherwise.
 | 
					 | 
				
			||||||
   *
 | 
					 | 
				
			||||||
   * There are three cases:
 | 
					 | 
				
			||||||
   * feed or old_best is old_changed -> we need to recompute new_best
 | 
					 | 
				
			||||||
   * old_best is before new_changed -> new_best is old_best, ignore
 | 
					 | 
				
			||||||
   * old_best is after new_changed -> try new_changed, otherwise old_best
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (net->routes)
 | 
					 | 
				
			||||||
    c->export_stats.updates_received++;
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
    c->export_stats.withdraws_received++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* Find old_best - either old_changed, or route for net->routes */
 | 
					 | 
				
			||||||
  if (old_changed && bmap_test(&c->export_map, old_changed->id))
 | 
					 | 
				
			||||||
    old_best = old_changed;
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    for (struct rte_storage *r = net->routes; r && rte_is_valid(&r->rte); r = r->next)
 | 
					    if (!rte_is_valid(feed[i]))
 | 
				
			||||||
 | 
					      continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Has been already rejected, won't bother with it */
 | 
				
			||||||
 | 
					    if (!refeed && bmap_test(&c->export_reject_map, feed[i]->id))
 | 
				
			||||||
 | 
					      continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Previously exported */
 | 
				
			||||||
 | 
					    if (!old_best && bmap_test(&c->export_map, feed[i]->id))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      if (bmap_test(&c->export_map, r->rte.id))
 | 
					      /* is still best */
 | 
				
			||||||
 | 
					      if (!new_best)
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
	old_best = &r->rte;
 | 
						DBG("rt_notify_accepted: idempotent\n");
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /* is superseded */
 | 
				
			||||||
 | 
					      old_best = feed[i];
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Have no new best route yet */
 | 
				
			||||||
 | 
					    if (!new_best)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      /* Try this route not seen before */
 | 
				
			||||||
 | 
					      nb0 = *feed[i];
 | 
				
			||||||
 | 
					      new_best = export_filter(c, &nb0, 0);
 | 
				
			||||||
 | 
					      DBG("rt_notify_accepted: checking route id %u: %s\n", feed[i]->id, new_best ? "ok" : "no");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Check obsolete routes for previously exported */
 | 
				
			||||||
 | 
					  if (!old_best)
 | 
				
			||||||
 | 
					    if (rpe && rpe->old && bmap_test(&c->export_map, rpe->old->rte.id))
 | 
				
			||||||
 | 
					      old_best = &rpe->old->rte;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*    for (; rpe; rpe = atomic_load_explicit(&rpe->next, memory_order_relaxed))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      if (rpe->old && bmap_test(&hook->accept_map, rpe->old->id))
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
						old_best = &rpe->old.rte;
 | 
				
			||||||
	break;
 | 
						break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      /* Note if new_changed found before old_best */
 | 
					      if (rpe == rpe_last)
 | 
				
			||||||
      if (&r->rte == new_changed)
 | 
					 | 
				
			||||||
	new_first = 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* Find new_best */
 | 
					 | 
				
			||||||
  if ((new_changed == old_changed) || (old_best == old_changed))
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    /* Feed or old_best changed -> find first accepted by filters */
 | 
					 | 
				
			||||||
    for (struct rte_storage *r = net->routes; r && rte_is_valid(&r->rte); r = r->next)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      /* Already rejected before */
 | 
					 | 
				
			||||||
      if (!refeed && bmap_test(&c->export_reject_map, r->rte.id))
 | 
					 | 
				
			||||||
	continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (new_best = export_filter(c, ((nb0 = r->rte), &nb0), 0))
 | 
					 | 
				
			||||||
	break;
 | 
						break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					    */
 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    /* Other cases -> either new_changed, or old_best (and nothing changed) */
 | 
					 | 
				
			||||||
    if (new_first && (new_changed = export_filter(c, new_changed, 0)))
 | 
					 | 
				
			||||||
      new_best = new_changed;
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Nothing to export */
 | 
				
			||||||
  if (!new_best && !old_best)
 | 
					  if (!new_best && !old_best)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    DBG("rt_notify_accepted: nothing to export\n");
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  do_rt_notify(c, net->n.addr, new_best, old_best, refeed);
 | 
					  do_rt_notify(c, n, new_best, old_best, refeed);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -607,36 +627,45 @@ nexthop_merge_rta(struct nexthop *nhs, rta *a, linpool *pool, int max)
 | 
				
			|||||||
  return nexthop_merge(nhs, &(a->nh), 1, 0, max, pool);
 | 
					  return nexthop_merge(nhs, &(a->nh), 1, 0, max, pool);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rte *
 | 
					static rte *
 | 
				
			||||||
rt_export_merged(struct channel *c, net *net, linpool *pool, int silent)
 | 
					rt_export_merged(struct channel *c, struct rte **feed, uint count, linpool *pool, int silent, int refeed)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  _Thread_local static rte rloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // struct proto *p = c->proto;
 | 
					  // struct proto *p = c->proto;
 | 
				
			||||||
  struct nexthop *nhs = NULL;
 | 
					  struct nexthop *nhs = NULL;
 | 
				
			||||||
  _Thread_local static rte rme;
 | 
					  rte *best0 = feed[0], *best = NULL;
 | 
				
			||||||
  struct rte_storage *best0 = net->routes;
 | 
					 | 
				
			||||||
  rte *best;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!best0 || !rte_is_valid(&best0->rte))
 | 
					  if (!rte_is_valid(best0))
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  best = export_filter_(c, ((rme = best0->rte), &rme), pool, silent);
 | 
					  /* Already rejected, no need to re-run the filter */
 | 
				
			||||||
 | 
					  if (!refeed && bmap_test(&c->export_reject_map, best0->id))
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!best || !rte_is_reachable(best))
 | 
					  rloc = *best0;
 | 
				
			||||||
 | 
					  best = export_filter_(c, &rloc, pool, silent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!best)
 | 
				
			||||||
 | 
					    /* Best route doesn't pass the filter */
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!rte_is_reachable(best))
 | 
				
			||||||
 | 
					    /* Unreachable routes can't be merged */
 | 
				
			||||||
    return best;
 | 
					    return best;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (struct rte_storage *rt0 = best0->next; rt0; rt0 = rt0->next)
 | 
					  for (uint i = 1; i < count; i++)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (!rte_mergable(best, &rt0->rte))
 | 
					    if (!rte_mergable(best0, feed[i]))
 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rte rnh = rt0->rte;
 | 
					    rte tmp0 = *feed[i];
 | 
				
			||||||
    rte *rt = export_filter_(c, &rnh, pool, 1);
 | 
					    rte *tmp = export_filter_(c, &tmp0, pool, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!rt)
 | 
					    if (!tmp || !rte_is_reachable(tmp))
 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (rte_is_reachable(rt))
 | 
					    nhs = nexthop_merge_rta(nhs, tmp->attrs, pool, c->merge_limit);
 | 
				
			||||||
      nhs = nexthop_merge_rta(nhs, rt->attrs, pool, c->merge_limit);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (nhs)
 | 
					  if (nhs)
 | 
				
			||||||
@@ -653,41 +682,77 @@ rt_export_merged(struct channel *c, net *net, linpool *pool, int silent)
 | 
				
			|||||||
  return best;
 | 
					  return best;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rte *
 | 
				
			||||||
 | 
					rt_export_merged_show(struct channel *c, net *n, linpool *pool)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  uint count = rte_feed_count(n);
 | 
				
			||||||
 | 
					  rte **feed = alloca(count * sizeof(rte *));
 | 
				
			||||||
 | 
					  rte_feed_obtain(n, feed, count);
 | 
				
			||||||
 | 
					  return rt_export_merged(c, feed, count, pool, 1, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed,
 | 
					rt_notify_merged(struct channel *c, const net_addr *n, struct rt_pending_export *rpe,
 | 
				
			||||||
		 rte *new_best, rte *old_best, int refeed)
 | 
					    struct rte **feed, uint count, int refeed)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  /* We assume that all rte arguments are either NULL or rte_is_valid() */
 | 
					  // struct proto *p = c->proto;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* This check should be done by the caller */
 | 
					 | 
				
			||||||
  if (!new_best && !old_best)
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0 /* TODO: Find whether this check is possible when processing multiple changes at once. */
 | 
				
			||||||
  /* Check whether the change is relevant to the merged route */
 | 
					  /* Check whether the change is relevant to the merged route */
 | 
				
			||||||
  if ((new_best == old_best) &&
 | 
					  if ((new_best == old_best) &&
 | 
				
			||||||
      (new_changed != old_changed) &&
 | 
					      (new_changed != old_changed) &&
 | 
				
			||||||
      !rte_mergable(new_best, new_changed) &&
 | 
					      !rte_mergable(new_best, new_changed) &&
 | 
				
			||||||
      !rte_mergable(old_best, old_changed))
 | 
					      !rte_mergable(old_best, old_changed))
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (new_best)
 | 
					  rte *old_best = NULL;
 | 
				
			||||||
    c->export_stats.updates_received++;
 | 
					  /* Find old best route */
 | 
				
			||||||
  else
 | 
					  for (uint i = 0; i < count; i++)
 | 
				
			||||||
    c->export_stats.withdraws_received++;
 | 
					    if (bmap_test(&c->export_map, feed[i]->id))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      old_best = feed[i];
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Check obsolete routes for previously exported */
 | 
				
			||||||
 | 
					  if (!old_best)
 | 
				
			||||||
 | 
					    if (rpe && rpe->old && bmap_test(&c->export_map, rpe->old->rte.id))
 | 
				
			||||||
 | 
					      old_best = &rpe->old->rte;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*    for (; rpe; rpe = atomic_load_explicit(&rpe->next, memory_order_relaxed))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      if (rpe->old && bmap_test(&hook->accept_map, rpe->old->id))
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
						old_best = &rpe->old.rte;
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (rpe == rpe_last)
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Prepare new merged route */
 | 
					  /* Prepare new merged route */
 | 
				
			||||||
  if (new_best)
 | 
					  rte *new_merged = count ? rt_export_merged(c, feed, count, rte_update_pool, 0, refeed) : NULL;
 | 
				
			||||||
    new_best = rt_export_merged(c, net, rte_update_pool, 0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Check old merged route */
 | 
					  if (!new_merged && !old_best)
 | 
				
			||||||
  if (old_best && !bmap_test(&c->export_map, old_best->id))
 | 
					 | 
				
			||||||
    old_best = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!new_best && !old_best)
 | 
					 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  do_rt_notify(c, net->n.addr, new_best, old_best, refeed);
 | 
					  do_rt_notify(c, n, new_merged, old_best, refeed);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					rt_notify_bulk(struct channel *c, const net_addr *n, struct rt_pending_export *rpe,
 | 
				
			||||||
 | 
					    struct rte **feed, uint count, int refeed)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  switch (c->ra_mode)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    case RA_ACCEPTED:
 | 
				
			||||||
 | 
					      return rt_notify_accepted(c, n, rpe, feed, count, refeed);
 | 
				
			||||||
 | 
					    case RA_MERGED:
 | 
				
			||||||
 | 
					      return rt_notify_merged(c, n, rpe, feed, count, refeed);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -774,12 +839,15 @@ rte_announce(rtable *tab, net *net, struct rte_storage *new, struct rte_storage
 | 
				
			|||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case RA_ACCEPTED:
 | 
					    case RA_ACCEPTED:
 | 
				
			||||||
      rt_notify_accepted(c, net, RTE_OR_NULL(new), RTE_OR_NULL(old), 0);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case RA_MERGED:
 | 
					    case RA_MERGED:
 | 
				
			||||||
      rt_notify_merged(c, net, RTE_OR_NULL(new), RTE_OR_NULL(old), RTE_OR_NULL(new_best), RTE_OR_NULL(old_best), 0);
 | 
					      {
 | 
				
			||||||
      break;
 | 
						struct rt_pending_export rpe = { .new = new, .old = old, .new_best = new_best, .old_best = old_best };
 | 
				
			||||||
 | 
						uint count = rte_feed_count(net);
 | 
				
			||||||
 | 
						rte **feed = alloca(count * sizeof(rte *));
 | 
				
			||||||
 | 
						rte_feed_obtain(net, feed, count);
 | 
				
			||||||
 | 
						rt_notify_bulk(c, net->n.addr, &rpe, feed, count, 0);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Drop the old stored rejection if applicable.
 | 
					    /* Drop the old stored rejection if applicable.
 | 
				
			||||||
@@ -2127,10 +2195,13 @@ static inline void
 | 
				
			|||||||
do_feed_channel(struct channel *c, net *n, rte *e)
 | 
					do_feed_channel(struct channel *c, net *n, rte *e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  rte_update_lock();
 | 
					  rte_update_lock();
 | 
				
			||||||
  if (c->ra_mode == RA_ACCEPTED)
 | 
					  if ((c->ra_mode == RA_ACCEPTED) || (c->ra_mode == RA_MERGED))
 | 
				
			||||||
    rt_notify_accepted(c, n, NULL, NULL, c->refeeding);
 | 
					  {
 | 
				
			||||||
  else if (c->ra_mode == RA_MERGED)
 | 
					    uint count = rte_feed_count(n);
 | 
				
			||||||
    rt_notify_merged(c, n, NULL, NULL, e, e, c->refeeding);
 | 
					    rte **feed = alloca(count * sizeof(rte *));
 | 
				
			||||||
 | 
					    rte_feed_obtain(n, feed, count);
 | 
				
			||||||
 | 
					    rt_notify_bulk(c, n->n.addr, NULL, feed, count, c->refeeding);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  else /* RA_BASIC */
 | 
					  else /* RA_BASIC */
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    rte e0 = *e;
 | 
					    rte e0 = *e;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -566,7 +566,7 @@ krt_export_net(struct krt_proto *p, net *net)
 | 
				
			|||||||
  const struct filter *filter = c->out_filter;
 | 
					  const struct filter *filter = c->out_filter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (c->ra_mode == RA_MERGED)
 | 
					  if (c->ra_mode == RA_MERGED)
 | 
				
			||||||
    return rt_export_merged(c, net, krt_filter_lp, 1);
 | 
					    return rt_export_merged_show(c, net, krt_filter_lp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static _Thread_local rte rt;
 | 
					  static _Thread_local rte rt;
 | 
				
			||||||
  rt = net->routes->rte;
 | 
					  rt = net->routes->rte;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user