From 84cac51a51fc29349077e8cecadf1aed11f9b824 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 30 Aug 2016 17:17:27 +0200 Subject: [PATCH] Nest: Keep multipath next hops sorted --- nest/route.h | 2 ++ nest/rt-attr.c | 28 ++++++++++++++++++++++++++++ nest/rt-table.c | 7 +++++++ proto/rip/rip.c | 5 +---- proto/static/static.c | 5 +---- 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/nest/route.h b/nest/route.h index 3969db6b..bb4674b9 100644 --- a/nest/route.h +++ b/nest/route.h @@ -506,6 +506,8 @@ int mpnh__same(struct mpnh *x, struct mpnh *y); /* Compare multipath nexthops */ static inline int mpnh_same(struct mpnh *x, struct mpnh *y) { return (x == y) || mpnh__same(x, y); } struct mpnh *mpnh_merge(struct mpnh *x, struct mpnh *y, int rx, int ry, int max, linpool *lp); +void mpnh_insert(struct mpnh **n, struct mpnh *y); +int mpnh_is_sorted(struct mpnh *x); void rta_init(void); rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */ diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 42b74f34..ab0069b5 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -302,6 +302,34 @@ mpnh_merge(struct mpnh *x, struct mpnh *y, int rx, int ry, int max, linpool *lp) return root; } +void +mpnh_insert(struct mpnh **n, struct mpnh *x) +{ + for (; *n; n = &((*n)->next)) + { + int cmp = mpnh_compare_node(*n, x); + + if (cmp < 0) + continue; + else if (cmp > 0) + break; + else + return; + } + + x->next = *n; + *n = x; +} + +int +mpnh_is_sorted(struct mpnh *x) +{ + for (; x && x->next; x = x->next) + if (mpnh_compare_node(x, x->next) >= 0) + return 0; + + return 1; +} static struct mpnh * mpnh_copy(struct mpnh *o) diff --git a/nest/rt-table.c b/nest/rt-table.c index 9baf2849..f4df22aa 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -804,6 +804,13 @@ rte_validate(rte *e) return 0; } + if ((e->attrs->dest == RTD_MULTIPATH) && !mpnh_is_sorted(e->attrs->nexthops)) + { + log(L_WARN "Ignoring unsorted multipath route %I/%d received via %s", + n->n.prefix, n->n.pxlen, e->sender->proto->name); + return 0; + } + return 1; } diff --git a/proto/rip/rip.c b/proto/rip/rip.c index c85fd69b..36527253 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -173,7 +173,6 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) { /* ECMP route */ struct mpnh *nhs = NULL; - struct mpnh **nhp = &nhs; int num = 0; for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next) @@ -185,9 +184,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) nh->gw = rt->next_hop; nh->iface = rt->from->nbr->iface; nh->weight = rt->from->ifa->cf->ecmp_weight; - nh->next = NULL; - *nhp = nh; - nhp = &(nh->next); + mpnh_insert(&nhs, nh); num++; if (rt->tag != rt_tag) diff --git a/proto/static/static.c b/proto/static/static.c index be808593..d54302a8 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -81,7 +81,6 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa) { struct static_route *r2; struct mpnh *nhs = NULL; - struct mpnh **nhp = &nhs; for (r2 = r->mp_next; r2; r2 = r2->mp_next) if (r2->installed) @@ -90,9 +89,7 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa) nh->gw = r2->via; nh->iface = r2->neigh->iface; nh->weight = r2->masklen; /* really */ - nh->next = NULL; - *nhp = nh; - nhp = &(nh->next); + mpnh_insert(&nhs, nh); } /* There is at least one nexthop */