summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2016-08-30 17:17:27 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2016-09-14 11:53:54 +0200
commit84cac51a51fc29349077e8cecadf1aed11f9b824 (patch)
tree68186ea208019211d06ad98df82df84ab255f5e6
parenta1839f3c61af66814a8c52b9ad28e59aab4ede0e (diff)
Nest: Keep multipath next hops sorted
-rw-r--r--nest/route.h2
-rw-r--r--nest/rt-attr.c28
-rw-r--r--nest/rt-table.c7
-rw-r--r--proto/rip/rip.c5
-rw-r--r--proto/static/static.c5
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 */