diff options
-rw-r--r-- | nest/route.h | 1 | ||||
-rw-r--r-- | nest/rt-attr.c | 20 | ||||
-rw-r--r-- | sysdep/linux/netlink.c | 4 |
3 files changed, 24 insertions, 1 deletions
diff --git a/nest/route.h b/nest/route.h index 15aac8f6..e356f686 100644 --- a/nest/route.h +++ b/nest/route.h @@ -628,6 +628,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_sort(struct nexthop *x); 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); diff --git a/nest/rt-attr.c b/nest/rt-attr.c index cc362cab..1803db92 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -200,7 +200,7 @@ nexthop__same(struct nexthop *x, struct nexthop *y) } static int -nexthop_compare_node(struct nexthop *x, struct nexthop *y) +nexthop_compare_node(const struct nexthop *x, const struct nexthop *y) { int r; @@ -318,6 +318,24 @@ nexthop_insert(struct nexthop **n, struct nexthop *x) *n = x; } +struct nexthop * +nexthop_sort(struct nexthop *x) +{ + struct nexthop *s = NULL; + + /* Simple insert-sort */ + while (x) + { + struct nexthop *n = x; + x = n->next; + n->next = NULL; + + nexthop_insert(&s, n); + } + + return s; +} + int nexthop_is_sorted(struct nexthop *x) { diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 5a0b4d0c..6e3fe488 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -725,6 +725,10 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr nh = RTNH_NEXT(nh); } + /* Ensure nexthops are sorted to satisfy nest invariant */ + if (!nexthop_is_sorted(first)) + first = nexthop_sort(first); + return first; } |