]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Nest: Keep multipath next hops sorted
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 30 Aug 2016 15:17:27 +0000 (17:17 +0200)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 14 Sep 2016 09:53:54 +0000 (11:53 +0200)
nest/route.h
nest/rt-attr.c
nest/rt-table.c
proto/rip/rip.c
proto/static/static.c

index 3969db6b77de4b6c270005e3ca9076cf4837d436..bb4674b93e6242ecbc515d68397a5aa270db9358 100644 (file)
@@ -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++ */
index 42b74f3467d753a2ca1c0d1b7bcce75454b7ca9f..ab0069b58f1c4ce8578bf17cda056b413bb22646 100644 (file)
@@ -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)
index 9baf2849ea6c70cc88b7f5ad7688200c93e3ae1a..f4df22aa9526d70e9ac598cded4d94c74fa0112b 100644 (file)
@@ -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;
 }
 
index c85fd69b92f421e3f813eec04cb1ad09c0ac09c1..365272538c8169329e75364132a91137c5fcc770 100644 (file)
@@ -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)
index be808593c622a5581527cb48c54bdd58096b3102..d54302a8908165362e6048d55c009d325ae305ea 100644 (file)
@@ -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 */