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);
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)
{
}
-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;
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;
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);
- }
- }
+ best = rte_cow_rta(best, pool);
+ nexthop_link(best->attrs, nhs);
if (best != best0)
*rt_free = best;