From 78d12361479b0d01b9b11cac410cb9c6ce48c7fe Mon Sep 17 00:00:00 2001
From: Matthieu Boutier <boutier@pps.univ-paris-diderot.fr>
Date: Mon, 14 Dec 2015 19:32:16 +0100
Subject: [PATCH] Optimization, by allowing traversing (installed) specific
 routes only.

Two main modifications:
  - source-specific routes are putted in front of the RIB,
  - route_stream now allows traversing all routes, all installed routes,
    or source-specific installed routes.
---
 babeld.c         |  2 +-
 disambiguation.c | 15 ++++++++-------
 local.c          |  2 +-
 message.c        |  2 +-
 route.c          | 46 ++++++++++++++++++++++++++++++++++++++++------
 route.h          |  5 ++++-
 6 files changed, 55 insertions(+), 17 deletions(-)

diff --git a/babeld.c b/babeld.c
index 649c283..1bb6ae6 100644
--- a/babeld.c
+++ b/babeld.c
@@ -1123,7 +1123,7 @@ dump_tables(FILE *out)
         xroute_stream_done(xroutes);
     }
 
-    routes = route_stream(0);
+    routes = route_stream(ROUTE_ALL);
     if(routes) {
         while(1) {
             struct babel_route *route = route_stream_next(routes);
diff --git a/disambiguation.c b/disambiguation.c
index 1774833..37bb9bf 100644
--- a/disambiguation.c
+++ b/disambiguation.c
@@ -145,7 +145,7 @@ min_conflict(const struct zone *zone, const struct babel_route *rt)
     const struct babel_route *min = NULL;
     struct route_stream *stream = NULL;
     struct zone curr_zone;
-    stream = route_stream(1);
+    stream = route_stream(ROUTE_INSTALLED);
     if(!stream) {
         fprintf(stderr, "Couldn't allocate route stream.\n");
         return NULL;
@@ -171,7 +171,8 @@ conflict_solution(const struct babel_route *rt)
     const struct babel_route *min = NULL; /* == solution */
     struct zone zone;
     struct zone tmp;
-    stream1 = route_stream(1);
+    /* Having a conflict requires at least one specific route. */
+    stream1 = route_stream(ROUTE_SS_INSTALLED);
     if(!stream1) {
         return NULL;
     }
@@ -179,7 +180,7 @@ conflict_solution(const struct babel_route *rt)
         rt1 = route_stream_next(stream1);
         if(rt1 == NULL) break;
 
-        stream2 = route_stream(1);
+        stream2 = route_stream(ROUTE_INSTALLED);
         if(!stream2) {
             route_stream_done(stream1);
             fprintf(stderr, "Couldn't allocate route stream.\n");
@@ -281,7 +282,7 @@ kinstall_route(const struct babel_route *route)
         goto end;
     }
 
-    stream = route_stream(1);
+    stream = route_stream(ROUTE_INSTALLED);
     if(!stream) {
         fprintf(stderr, "Couldn't allocate route stream.\n");
         return -1;
@@ -350,7 +351,7 @@ kuninstall_route(const struct babel_route *route)
         perror("kernel_route(FLUSH)");
 
     /* Remove source-specific conflicting routes */
-    stream = route_stream(1);
+    stream = route_stream(ROUTE_INSTALLED);
     if(!stream) {
         fprintf(stderr, "Couldn't allocate route stream.\n");
         return -1;
@@ -395,7 +396,7 @@ kswitch_routes(const struct babel_route *old, const struct babel_route *new)
 
     /* Remove source-specific conflicting routes */
     if(!kernel_disambiguate(v4mapped(old->nexthop))) {
-        stream = route_stream(1);
+        stream = route_stream(ROUTE_INSTALLED);
         if(!stream) {
             fprintf(stderr, "Couldn't allocate route stream.\n");
             return -1;
@@ -442,7 +443,7 @@ kchange_route_metric(const struct babel_route *route,
     }
 
     if(!kernel_disambiguate(v4mapped(route->nexthop))) {
-        stream = route_stream(1);
+        stream = route_stream(ROUTE_INSTALLED);
         if(!stream) {
             fprintf(stderr, "Couldn't allocate route stream.\n");
             return -1;
diff --git a/local.c b/local.c
index 8a6b758..1cd4b21 100644
--- a/local.c
+++ b/local.c
@@ -289,7 +289,7 @@ local_notify_all_1(int s)
         xroute_stream_done(xroutes);
     }
 
-    routes = route_stream(0);
+    routes = route_stream(ROUTE_ALL);
     if(routes) {
         while(1) {
             struct babel_route *route = route_stream_next(routes);
diff --git a/message.c b/message.c
index 2342202..3d490d4 100644
--- a/message.c
+++ b/message.c
@@ -1525,7 +1525,7 @@ send_update(struct interface *ifp, int urgent,
         struct route_stream *routes;
         send_self_update(ifp);
         debugf("Sending update to %s for any.\n", ifp->name);
-        routes = route_stream(1);
+        routes = route_stream(ROUTE_INSTALLED);
         if(routes) {
             while(1) {
                 struct babel_route *route = route_stream_next(routes);
diff --git a/route.c b/route.c
index 842f71a..b06a944 100644
--- a/route.c
+++ b/route.c
@@ -52,6 +52,22 @@ int keep_unfeasible = 0;
 static int smoothing_half_life = 0;
 static int two_to_the_one_over_hl = 0; /* 2^(1/hl) * 0x10000 */
 
+static int
+check_specific_first(void)
+{
+    /* All source-specific routes are in front of the list */
+    int specific = 1;
+    int i;
+    for(i = 0; i < route_slots; i++) {
+        if(routes[i]->src->src_plen == 0) {
+            specific = 0;
+        } else if(!specific) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
 /* We maintain a list of "slots", ordered by prefix.  Every slot
    contains a linked list of the routes to this prefix, with the
    installed route, if any, at the head of the list. */
@@ -61,7 +77,16 @@ route_compare(const unsigned char *prefix, unsigned char plen,
               const unsigned char *src_prefix, unsigned char src_plen,
               struct babel_route *route)
 {
-    int i = memcmp(prefix, route->src->prefix, 16);
+    int i;
+
+    /* Put all source-specific routes in the front of the list. */
+    if(src_plen == 0 && route->src->src_plen > 0) {
+        return 1;
+    } else if(src_plen > 0 && route->src->src_plen == 0) {
+        return -1;
+    }
+
+    i = memcmp(prefix, route->src->prefix, 16);
     if(i != 0)
         return i;
 
@@ -344,16 +369,19 @@ struct route_stream {
 
 
 struct route_stream *
-route_stream(int installed)
+route_stream(int which)
 {
     struct route_stream *stream;
 
+    if(!check_specific_first())
+        fprintf(stderr, "Invariant failed: specific routes first in RIB.\n");
+
     stream = malloc(sizeof(struct route_stream));
     if(stream == NULL)
         return NULL;
 
-    stream->installed = installed;
-    stream->index = installed ? 0 : -1;
+    stream->installed = which;
+    stream->index = which == ROUTE_ALL ? -1 : 0;
     stream->next = NULL;
 
     return stream;
@@ -363,8 +391,14 @@ struct babel_route *
 route_stream_next(struct route_stream *stream)
 {
     if(stream->installed) {
-        while(stream->index < route_slots && !routes[stream->index]->installed)
-            stream->index++;
+        while(stream->index < route_slots)
+            if(stream->installed == ROUTE_SS_INSTALLED &&
+               routes[stream->index]->src->src_plen == 0)
+                return NULL;
+            else if(routes[stream->index]->installed)
+                break;
+            else
+                stream->index++;
 
         if(stream->index < route_slots)
             return routes[stream->index++];
diff --git a/route.h b/route.h
index fd68810..f2231e8 100644
--- a/route.h
+++ b/route.h
@@ -44,6 +44,9 @@ struct babel_route {
     struct babel_route *next;
 };
 
+#define ROUTE_ALL 0
+#define ROUTE_INSTALLED 1
+#define ROUTE_SS_INSTALLED 2
 struct route_stream;
 
 extern struct babel_route **routes;
@@ -80,7 +83,7 @@ void flush_route(struct babel_route *route);
 void flush_all_routes(void);
 void flush_neighbour_routes(struct neighbour *neigh);
 void flush_interface_routes(struct interface *ifp, int v4only);
-struct route_stream *route_stream(int installed);
+struct route_stream *route_stream(int which);
 struct babel_route *route_stream_next(struct route_stream *stream);
 void route_stream_done(struct route_stream *stream);
 int metric_to_kernel(int metric);
-- 
2.5.4 (Apple Git-61)

