Commit 5ae13e15 authored by Ondrej Zajicek (work)'s avatar Ondrej Zajicek (work)
Browse files

Nest: Change nexthop merging order to prefer earlier nexthops

When nexthop merge limit was applied, the old code used first N nexthops
in the canonical ordering. Now the code prefers nexthops based on the
order or routes in the network.
parent 00cf501a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -638,6 +638,7 @@ int nexthop__same(struct nexthop *x, struct nexthop *y); /* Compare multipath ne
static inline int nexthop_same(struct nexthop *x, struct nexthop *y)
{ return (x == y) || nexthop__same(x, y); }
struct nexthop *nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, linpool *lp);
struct nexthop *nexthop_merge2(struct nexthop *x, struct nexthop *y, int ry, int *max, linpool *lp);
static inline void nexthop_link(struct rta *a, struct nexthop *from)
{ memcpy(&a->nh, from, nexthop_size(from)); }
void nexthop_insert(struct nexthop **n, struct nexthop *y);
+51 −0
Original line number Diff line number Diff line
@@ -285,6 +285,57 @@ nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, lin
  return root;
}

/**
 * nexthop_merge2 - merge nexthop lists
 * @x: list 1
 * @y: list 2
 * @ry: reusability of list @y
 * @max: max number of added nexthops
 * @lp: linpool for allocating nexthops
 *
 * The nexthop_merge2() function takes two nexthop lists @x and @y and merges
 * them, eliminating possible duplicates. It is a variant of nexthop_merge()
 * function differing in how @max limit is handled, here it limits just number
 * of nexthops added from the second list @y. The @max value is decreased with
 * each such nexthop, this return remaining 'unused' limit, which can be used in
 * subsequent calls. The list @x is expected to be an accumulator and its
 * reusability is implied.  New nodes are allocated from linpool @lp.
 */
struct nexthop *
nexthop_merge2(struct nexthop *x, struct nexthop *y, int ry, int *max, linpool *lp)
{
  struct nexthop *root = NULL;
  struct nexthop **n = &root;

  if (*max <= 0)
    return x;

  while (x || y)
  {
    int cmp = nexthop_compare_node(x, y);
    if (cmp < 0)
    {
      *n = x;
      x = x->next;
    }
    else if (cmp > 0)
    {
      *n = ry ? y : nexthop_copy_node(y, lp);
      y = (--*max) ? y->next : NULL;
    }
    else
    {
      *n = x;
      x = x->next;
      y = y->next;
    }
    n = &((*n)->next);
  }
  *n = NULL;

  return root;
}

void
nexthop_insert(struct nexthop **n, struct nexthop *x)
{
+8 −19
Original line number Diff line number Diff line
@@ -849,18 +849,13 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
}


static struct nexthop *
nexthop_merge_rta(struct nexthop *nhs, rta *a, linpool *pool, int max)
{
  return nexthop_merge(nhs, &(a->nh), 1, 0, max, pool);
}

rte *
rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, linpool *pool, int silent)
{
  // struct proto *p = c->proto;
  struct nexthop *nhs = NULL;
  rte *best0, *best, *rt0, *rt, *tmp;
  int max = c->merge_limit;

  best0 = net->routes;
  *rt_free = NULL;
@@ -870,10 +865,12 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, lin

  best = export_filter_(c, best0, rt_free, tmpa, pool, silent);

  if (!best || !rte_is_reachable(best))
  if (!best || !rte_is_reachable(best) || !best0->next)
    return best;

  for (rt0 = best0->next; rt0; rt0 = rt0->next)
  nhs = nexthop_merge2(NULL, &(best->attrs->nh), 0, &max, pool);

  for (rt0 = best0->next; rt0 && max; rt0 = rt0->next)
  {
    if (!rte_mergable(best0, rt0))
      continue;
@@ -884,22 +881,14 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, lin
      continue;

    if (rte_is_reachable(rt))
      nhs = nexthop_merge_rta(nhs, rt->attrs, pool, c->merge_limit);
      nhs = nexthop_merge2(nhs, &(rt->attrs->nh), 0, &max, pool);

    if (tmp)
      rte_free(tmp);
  }

  if (nhs)
  {
    nhs = nexthop_merge_rta(nhs, best->attrs, pool, c->merge_limit);

    if (nhs->next)
    {
  best = rte_cow_rta(best, pool);
  nexthop_link(best->attrs, nhs);
    }
  }

  if (best != best0)
    *rt_free = best;