]> git.proxmox.com Git - mirror_frr.git/commitdiff
babeld: babelz merge.
authorMatthieu Boutier <boutier@pps.jussieu.fr>
Mon, 23 Jan 2012 22:46:32 +0000 (23:46 +0100)
committerPaul Jakma <paul@quagga.net>
Sun, 25 Mar 2012 16:06:53 +0000 (17:06 +0100)
Babelz is the last version of the stand-alone babel daemon. In
particular, it use multiple channels to diminuate
interferences. Please refer to this one for more details.

15 files changed:
babeld/babel_interface.c
babeld/babel_interface.h
babeld/babel_main.c
babeld/babeld.c
babeld/message.c
babeld/neighbour.c
babeld/net.c
babeld/route.c
babeld/route.h
babeld/source.c
babeld/source.h
babeld/util.c
babeld/util.h
babeld/xroute.c
babeld/xroute.h

index e403cce08573712ff4d08f12aee447c057dd2340..1c8c88687d3e06fa499d7030106410aa28a726f2 100644 (file)
@@ -456,6 +456,30 @@ interface_idle(babel_interface_nfo *babel_ifp)
             babel_ifp->activity_time < babel_now.tv_sec - idle_time);
 }
 
+int
+update_hello_interval(struct interface *ifp)
+{
+    int rc = 0;
+    unsigned short interval;
+    struct babel_interface *babel_ifp = babel_get_if_nfo(ifp);
+
+    if(interface_idle(babel_ifp))
+        interval = idle_hello_interval;
+    else if(IF_CONF(ifp, hello_interval) > 0)
+        interval = IF_CONF(ifp, hello_interval);
+    else if((ifp->flags & BABEL_IF_WIRED))
+        interval = wired_hello_interval;
+    else
+        interval = wireless_hello_interval;
+
+    if(babel_ifp->hello_interval != interval) {
+        babel_ifp->hello_interval = interval;
+        rc = 1;
+    }
+
+    return rc;
+}
+
 /* This should be no more than half the hello interval, so that hellos
    aren't sent late.  The result is in milliseconds. */
 unsigned
@@ -560,10 +584,11 @@ interface_recalculate(struct interface *ifp)
     update_interface_metric(ifp);
 
     debugf(BABEL_DEBUG_COMMON,
-           "Upped network %s (%s, cost=%d%s).",
+           "Upped interface %s (%s, cost=%d, channel=%d%s).",
            ifp->name,
            (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
            babel_ifp->cost,
+           babel_ifp->channel,
            babel_ifp->ipv4 ? ", IPv4" : "");
 
     if(rc > 0)
@@ -777,19 +802,41 @@ DEFUN (show_babel_neighbour,
 }
 
 static void
-show_babel_routes_sub (struct vty *vty, struct babel_route *route)
+show_babel_routes_sub (struct babel_route *route, void *closure)
 {
+    struct vty *vty = (struct vty*) closure;
     const unsigned char *nexthop =
         memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
         NULL : route->nexthop;
+    char channels[100];
+
+    if(route->channels[0] == 0)
+        channels[0] = '\0';
+    else {
+        int k, j = 0;
+        snprintf(channels, 100, " chan (");
+        j = strlen(channels);
+        for(k = 0; k < DIVERSITY_HOPS; k++) {
+            if(route->channels[k] == 0)
+                break;
+            if(k > 0)
+                channels[j++] = ',';
+            snprintf(channels + j, 100 - j, "%d", route->channels[k]);
+            j = strlen(channels);
+        }
+        snprintf(channels + j, 100 - j, ")");
+        if(k == 0)
+            channels[0] = '\0';
+    }
 
     vty_out(vty,
-            "%s metric %d refmetric %d id %s seqno %d age %d "
+            "%s metric %d refmetric %d id %s seqno %d%s age %d "
             "via %s neigh %s%s%s%s%s",
             format_prefix(route->src->prefix, route->src->plen),
             route_metric(route), route->refmetric,
             format_eui64(route->src->id),
             (int)route->seqno,
+            channels,
             (int)(babel_now.tv_sec - route->time),
             route->neigh->ifp->name,
             format_address(route->neigh->address),
@@ -801,11 +848,12 @@ show_babel_routes_sub (struct vty *vty, struct babel_route *route)
 }
 
 static void
-show_babel_xroutes_sub (struct vty *vty, struct xroute *xroute)
+show_babel_xroutes_sub (struct xroute *xroute, void *closure)
 {
+    struct vty *vty = (struct vty *) closure;
     vty_out(vty, "%s metric %d (exported)%s",
-            format_prefix(xroutes->prefix, xroute->plen),
-            xroutes->metric,
+            format_prefix(xroute->prefix, xroute->plen),
+            xroute->metric,
             VTY_NEWLINE);
 }
 
@@ -818,15 +866,8 @@ DEFUN (show_babel_database,
        "Database information\n"
        "No attributes\n")
 {
-    int i;
-
-    for(i = 0; i < numroutes; i++) {
-        show_babel_routes_sub(vty, &routes[i]);
-    }
-    for(i = 0; i < numxroutes; i++) {
-        show_babel_xroutes_sub(vty, &xroutes[i]);
-    }
-
+    for_all_routes(show_babel_routes_sub, vty);
+    for_all_xroutes(show_babel_xroutes_sub, vty);
     return CMD_SUCCESS;
 }
 
@@ -950,6 +991,7 @@ babel_interface_allocate (void)
     babel_ifp->bucket = BUCKET_TOKENS_MAX;
     babel_ifp->hello_seqno = (random() & 0xFFFF);
     babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL;
+    babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
 
     return babel_ifp;
 }
index d9fb9a4a2025d1156552b18d40ea98666779bc7e..5b551fbe2d189734164d02ca88893a23d6425cb5 100644 (file)
@@ -42,10 +42,15 @@ THE SOFTWARE.
 #include <zebra.h>
 #include "zclient.h"
 
+#define CONFIG_DEFAULT 0
+#define CONFIG_NO 1
+#define CONFIG_YES 2
+
 /* babeld interface informations */
 struct babel_interface {
     unsigned short flags;                     /* see below */
     unsigned short cost;
+    int channel;
     struct timeval hello_timeout;
     struct timeval update_timeout;
     struct timeval flush_timeout;
@@ -67,6 +72,7 @@ struct babel_interface {
     time_t bucket_time;
     unsigned int bucket;
     time_t activity_time;
+    time_t last_update_time;
     unsigned short hello_seqno;
     unsigned hello_interval;
     unsigned update_interval;
@@ -85,12 +91,20 @@ static inline babel_interface_nfo* babel_get_if_nfo(struct interface *ifp)
     return ((babel_interface_nfo*) ifp->info);
 }
 
+#define IF_CONF(_ifp, _field) babel_get_if_nfo(_ifp)->_field
+
 /* babel_interface_nfo flags */
+#define BABEL_IF_IS_UP         (1 << 0)
 #define BABEL_IF_WIRED         (1 << 1)
 #define BABEL_IF_SPLIT_HORIZON (1 << 2)
 #define BABEL_IF_LQ            (1 << 3)
-#define BABEL_IF_IS_ENABLE     (1 << 4)
-#define BABEL_IF_IS_UP         (1 << 5)
+#define BABEL_IF_FARAWAY       (1 << 4)
+#define BABEL_IF_IS_ENABLE     (1 << 7)
+
+/* Only INTERFERING can appear on the wire. */
+#define BABEL_IF_CHANNEL_UNKNOWN 0
+#define BABEL_IF_CHANNEL_INTERFERING 255
+#define BABEL_IF_CHANNEL_NONINTERFERING -2
 
 static inline int
 if_up(struct interface *ifp)
@@ -133,6 +147,7 @@ int babel_interface_address_delete (int, struct zclient *, zebra_size_t);
 
 /* others functions */
 int interface_idle(babel_interface_nfo *);
+int update_hello_interval(struct interface *ifp);
 unsigned jitter(babel_interface_nfo *, int);
 unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent);
 /* return "true" if "address" is one of our ipv6 addresses */
index 159ba656592c651d069b2c1bafda9381747d418c..4d6f60eb756c78532aee0fb596845b6569aa587f 100644 (file)
@@ -482,7 +482,7 @@ babel_exit_properly(void)
 
     /* Uninstall and flush all routes. */
     debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
-    babel_uninstall_all_routes();
+    flush_all_routes();
     babel_interface_close_all();
     babel_zebra_close_connexion();
     babel_save_state_file();
index 0cf8c8a1fb4a21528a47cfcc3ff6f765c78639bc..d69662c00d4a23ad5bff3a317a6cc482fa03b490 100644 (file)
@@ -269,7 +269,7 @@ babel_initial_noise(void)
 static void
 babel_clean_routing_process()
 {
-    babel_uninstall_all_routes();
+    flush_all_routes();
     babel_interface_close_all();
 
     /* cancel threads */
index 92c416b9feb1e0c5e2d08a7ac16cfa6464df2fd1..8cd1db6393f127b1480babadf35a19c33268878d 100644 (file)
@@ -69,6 +69,8 @@ struct timeval unicast_flush_timeout = {0, 0};
 static const unsigned char v4prefix[16] =
     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
 
+/* Parse a network prefix, encoded in the somewhat baroque compressed
+   representation used by Babel.  Return the number of bytes parsed. */
 static int
 network_prefix(int ae, int plen, unsigned int omitted,
                const unsigned char *p, const unsigned char *dp,
@@ -76,6 +78,7 @@ network_prefix(int ae, int plen, unsigned int omitted,
 {
     unsigned pb;
     unsigned char prefix[16];
+    int ret = -1;
 
     if(plen >= 0)
         pb = (plen + 7) / 8;
@@ -90,7 +93,9 @@ network_prefix(int ae, int plen, unsigned int omitted,
     memset(prefix, 0, 16);
 
     switch(ae) {
-    case 0: break;
+    case 0:
+        ret = 0;
+        break;
     case 1:
         if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
             return -1;
@@ -100,6 +105,7 @@ network_prefix(int ae, int plen, unsigned int omitted,
             memcpy(prefix, dp, 12 + omitted);
         }
         if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted);
+        ret = pb - omitted;
         break;
     case 2:
         if(omitted > 16 || (pb > omitted && len < pb - omitted)) return -1;
@@ -108,19 +114,68 @@ network_prefix(int ae, int plen, unsigned int omitted,
             memcpy(prefix, dp, omitted);
         }
         if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted);
+        ret = pb - omitted;
         break;
     case 3:
         if(pb > 8 && len < pb - 8) return -1;
         prefix[0] = 0xfe;
         prefix[1] = 0x80;
         if(pb > 8) memcpy(prefix + 8, p, pb - 8);
+        ret = pb - 8;
         break;
     default:
         return -1;
     }
 
     mask_prefix(p_r, prefix, plen < 0 ? 128 : ae == 1 ? plen + 96 : plen);
-    return 1;
+    return ret;
+}
+
+static void
+parse_route_attributes(const unsigned char *a, int alen,
+                       unsigned char *channels)
+{
+    int type, len, i = 0;
+
+    while(i < alen) {
+        type = a[i];
+        if(type == 0) {
+            i++;
+            continue;
+        }
+
+        if(i + 1 > alen) {
+            fprintf(stderr, "Received truncated attributes.\n");
+            return;
+        }
+        len = a[i + 1];
+        if(i + len > alen) {
+            fprintf(stderr, "Received truncated attributes.\n");
+            return;
+        }
+
+        if(type == 1) {
+            /* Nothing. */
+        } else if(type == 2) {
+            if(len > DIVERSITY_HOPS) {
+                fprintf(stderr,
+                        "Received overlong channel information (%d > %d).\n",
+                        len, DIVERSITY_HOPS);
+                len = DIVERSITY_HOPS;
+            }
+            if(memchr(a + i + 2, 0, len) != NULL) {
+                /* 0 is reserved. */
+                fprintf(stderr, "Channel information contains 0!");
+                return;
+            }
+            memset(channels, 0, DIVERSITY_HOPS);
+            memcpy(channels, a + i + 2, len);
+        } else {
+            fprintf(stderr, "Received unknown route attribute %d.\n", type);
+        }
+
+        i += len + 2;
+    }
 }
 
 static int
@@ -130,6 +185,13 @@ network_address(int ae, const unsigned char *a, unsigned int len,
     return network_prefix(ae, -1, 0, a, NULL, len, a_r);
 }
 
+static int
+channels_len(unsigned char *channels)
+{
+    unsigned char *p = memchr(channels, 0, DIVERSITY_HOPS);
+    return p ? (p - channels) : DIVERSITY_HOPS;
+}
+
 void
 parse_packet(const unsigned char *from, struct interface *ifp,
              const unsigned char *packet, int packetlen)
@@ -284,8 +346,9 @@ parse_packet(const unsigned char *from, struct interface *ifp,
         } else if(type == MESSAGE_UPDATE) {
             unsigned char prefix[16], *nh;
             unsigned char plen;
+            unsigned char channels[DIVERSITY_HOPS];
             unsigned short interval, seqno, metric;
-            int rc;
+            int rc, parsed_len;
             if(len < 10) {
                 if(len < 2 || message[3] & 0x80)
                     have_v4_prefix = have_v6_prefix = 0;
@@ -307,6 +370,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
                     have_v4_prefix = have_v6_prefix = 0;
                 goto fail;
             }
+            parsed_len = 10 + rc;
 
             plen = message[4] + (message[2] == 1 ? 96 : 0);
 
@@ -360,8 +424,27 @@ parse_packet(const unsigned char *from, struct interface *ifp,
                     goto done;
             }
 
+            if((ifp->flags & BABEL_IF_FARAWAY)) {
+                channels[0] = 0;
+            } else {
+                /* This will be overwritten by parse_route_attributes below. */
+                if(metric < 256) {
+                    /* Assume non-interfering (wired) link. */
+                    channels[0] = 0;
+                } else {
+                    /* Assume interfering. */
+                    channels[0] = BABEL_IF_CHANNEL_INTERFERING;
+                    channels[1] = 0;
+                }
+
+                if(parsed_len < len)
+                    parse_route_attributes(message + 2 + parsed_len,
+                                           len - parsed_len, channels);
+            }
+
             update_route(router_id, prefix, plen, seqno, metric, interval,
-                         neigh, nh);
+                         neigh, nh,
+                         channels, channels_len(channels));
         } else if(type == MESSAGE_REQUEST) {
             unsigned char prefix[16], plen;
             int rc;
@@ -374,10 +457,17 @@ parse_packet(const unsigned char *from, struct interface *ifp,
                    message[2] == 0 ? "any" : format_prefix(prefix, plen),
                    format_address(from), ifp->name);
             if(message[2] == 0) {
+                struct babel_interface *babel_ifp =babel_get_if_nfo(neigh->ifp);
                 /* If a neighbour is requesting a full route dump from us,
                    we might as well send it an IHU. */
                 send_ihu(neigh, NULL);
-                send_update(neigh->ifp, 0, NULL, 0);
+                /* Since nodes send wildcard requests on boot, booting
+                   a large number of nodes at the same time may cause an
+                   update storm.  Ignore a wildcard request that happens
+                   shortly after we sent a full update. */
+                if(babel_ifp->last_update_time <
+                   babel_now.tv_sec - MAX(babel_ifp->hello_interval / 100, 1))
+                    send_update(neigh->ifp, 0, NULL, 0);
             } else {
                 send_update(neigh->ifp, 0, prefix, plen);
             }
@@ -665,10 +755,12 @@ send_hello_noupdate(struct interface *ifp, unsigned interval)
 void
 send_hello(struct interface *ifp)
 {
+    int changed;
+    changed = update_hello_interval(ifp);
     babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
     send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10);
     /* Send full IHU every 3 hellos, and marginal IHU each time */
-    if(babel_ifp->hello_seqno % 3 == 0)
+    if(changed || babel_ifp->hello_seqno % 3 == 0)
         send_ihu(NULL, ifp);
     else
         send_marginal_ihu(ifp);
@@ -724,12 +816,19 @@ static void
 really_send_update(struct interface *ifp,
                    const unsigned char *id,
                    const unsigned char *prefix, unsigned char plen,
-                   unsigned short seqno, unsigned short metric)
+                   unsigned short seqno, unsigned short metric,
+                   unsigned char *channels, int channels_len)
 {
     babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
     int add_metric, v4, real_plen, omit = 0;
     const unsigned char *real_prefix;
     unsigned short flags = 0;
+    int channels_size;
+
+    if(diversity_kind != DIVERSITY_CHANNEL)
+        channels_len = -1;
+
+    channels_size = channels_len >= 0 ? channels_len + 2 : 0;
 
     if(!if_up(ifp))
         return;
@@ -786,7 +885,8 @@ really_send_update(struct interface *ifp,
         babel_ifp->have_buffered_id = 1;
     }
 
-    start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit);
+    start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit +
+                  channels_size);
     accumulate_byte(ifp, v4 ? 1 : 2);
     accumulate_byte(ifp, flags);
     accumulate_byte(ifp, real_plen);
@@ -795,7 +895,14 @@ really_send_update(struct interface *ifp,
     accumulate_short(ifp, seqno);
     accumulate_short(ifp, metric);
     accumulate_bytes(ifp, real_prefix + omit, (real_plen + 7) / 8 - omit);
-    end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit);
+    /* Note that an empty channels TLV is different from no such TLV. */
+    if(channels_len >= 0) {
+        accumulate_byte(ifp, 2);
+        accumulate_byte(ifp, channels_len);
+        accumulate_bytes(ifp, channels, channels_len);
+    }
+    end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit +
+                channels_size);
 
     if(flags & 0x80) {
         memcpy(babel_ifp->buffered_prefix, prefix, 16);
@@ -884,9 +991,6 @@ flushupdates(struct interface *ifp)
         qsort(b, n, sizeof(struct buffered_update), compare_buffered_updates);
 
         for(i = 0; i < n; i++) {
-            unsigned short seqno;
-            unsigned short metric;
-
             /* The same update may be scheduled multiple times before it is
                sent out.  Since our buffer is now sorted, it is enough to
                compare with the previous update. */
@@ -903,22 +1007,51 @@ flushupdates(struct interface *ifp)
             if(xroute && (!route || xroute->metric <= kernel_metric)) {
                 really_send_update(ifp, myid,
                                    xroute->prefix, xroute->plen,
-                                   myseqno, xroute->metric);
+                                   myseqno, xroute->metric,
+                                   NULL, 0);
                 last_prefix = xroute->prefix;
                 last_plen = xroute->plen;
             } else if(route) {
+                unsigned char channels[DIVERSITY_HOPS];
+                int chlen;
+                struct interface *route_ifp = route->neigh->ifp;
+                struct babel_interface *babel_route_ifp = NULL;
+                unsigned short metric;
+                unsigned short seqno;
+
                 seqno = route->seqno;
-                metric = route_metric(route);
+                metric =
+                    route_interferes(route, ifp) ?
+                    route_metric(route) :
+                    route_metric_noninterfering(route);
+
                 if(metric < INFINITY)
                     satisfy_request(route->src->prefix, route->src->plen,
                                     seqno, route->src->id, ifp);
                 if((babel_ifp->flags & BABEL_IF_SPLIT_HORIZON) &&
                    route->neigh->ifp == ifp)
                     continue;
+
+                babel_route_ifp = babel_get_if_nfo(route_ifp);
+                if(babel_route_ifp->channel ==BABEL_IF_CHANNEL_NONINTERFERING) {
+                    memcpy(channels, route->channels, DIVERSITY_HOPS);
+                } else {
+                    if(babel_route_ifp->channel == BABEL_IF_CHANNEL_UNKNOWN)
+                        channels[0] = BABEL_IF_CHANNEL_INTERFERING;
+                    else {
+                        assert(babel_route_ifp->channel > 0 &&
+                               babel_route_ifp->channel <= 255);
+                        channels[0] = babel_route_ifp->channel;
+                    }
+                    memcpy(channels + 1, route->channels, DIVERSITY_HOPS - 1);
+                }
+
+                chlen = channels_len(channels);
                 really_send_update(ifp, route->src->id,
                                    route->src->prefix,
                                    route->src->plen,
-                                   seqno, metric);
+                                   seqno, metric,
+                                   channels, chlen);
                 update_source(route->src, seqno, metric);
                 last_prefix = route->src->prefix;
                 last_plen = route->src->plen;
@@ -926,7 +1059,7 @@ flushupdates(struct interface *ifp)
             /* There's no route for this prefix.  This can happen shortly
                after an xroute has been retracted, so send a retraction. */
                 really_send_update(ifp, myid, b[i].prefix, b[i].plen,
-                                   myseqno, INFINITY);
+                                   myseqno, INFINITY, NULL, -1);
             }
         }
         schedule_flush_now(ifp);
@@ -961,12 +1094,17 @@ buffer_update(struct interface *ifp,
     if(babel_ifp->update_bufsize == 0) {
         int n;
         assert(babel_ifp->buffered_updates == NULL);
-        n = MAX(babel_ifp->bufsize / 16, 4);
+        /* Allocate enough space to hold a full update.  Since the
+           number of installed routes will grow over time, make sure we
+           have enough space to send a full-ish frame. */
+        n = installed_routes_estimate() + xroutes_estimate() + 4;
+        n = MAX(n, babel_ifp->bufsize / 16);
     again:
         babel_ifp->buffered_updates = malloc(n *sizeof(struct buffered_update));
         if(babel_ifp->buffered_updates == NULL) {
             zlog_err("malloc(buffered_updates): %s", safe_strerror(errno));
             if(n > 4) {
+                /* Try again with a tiny buffer. */
                 n = 4;
                 goto again;
             }
@@ -982,12 +1120,18 @@ buffer_update(struct interface *ifp,
     babel_ifp->num_buffered_updates++;
 }
 
+static void
+buffer_update_callback(struct babel_route *route, void *closure)
+{
+    buffer_update((struct interface*)closure,
+                  route->src->prefix, route->src->plen);
+}
+
 void
 send_update(struct interface *ifp, int urgent,
             const unsigned char *prefix, unsigned char plen)
 {
     babel_interface_nfo *babel_ifp = NULL;
-    int i;
 
     if(ifp == NULL) {
       struct interface *ifp_aux;
@@ -1020,15 +1164,13 @@ send_update(struct interface *ifp, int urgent,
         if(!interface_idle(babel_ifp)) {
             send_self_update(ifp);
             if(!parasitic) {
-                debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", ifp->name);
-                for(i = 0; i < numroutes; i++)
-                    if(routes[i].installed)
-                        buffer_update(ifp,
-                                      routes[i].src->prefix,
-                                      routes[i].src->plen);
+                debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.",
+                       ifp->name);
+                for_all_installed_routes(buffer_update_callback, ifp);
             }
         }
         set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
+        babel_ifp->last_update_time = babel_now.tv_sec;
     }
     schedule_update_flush(ifp, urgent);
 }
@@ -1086,11 +1228,16 @@ update_myseqno()
     seqno_time = babel_now;
 }
 
+static void
+send_xroute_update_callback(struct xroute *xroute, void *closure)
+{
+    struct interface *ifp = (struct interface*)closure;
+    send_update(ifp, 0, xroute->prefix, xroute->plen);
+}
+
 void
 send_self_update(struct interface *ifp)
 {
-    int i;
-
     if(ifp == NULL) {
       struct interface *ifp_aux;
       struct listnode *linklist_node = NULL;
@@ -1104,8 +1251,7 @@ send_self_update(struct interface *ifp)
 
     if(!interface_idle(babel_get_if_nfo(ifp))) {
         debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name);
-        for(i = 0; i < numxroutes; i++)
-            send_update(ifp, 0, xroutes[i].prefix, xroutes[i].plen);
+        for_all_xroutes(send_xroute_update_callback, ifp);
     }
 }
 
index f360b8915848f100ca7ecc33f94af84b5983e719..5a327dfe9107710fe9554e751e667eaee5d8799e 100644 (file)
@@ -122,7 +122,8 @@ find_neighbour(const unsigned char *address, struct interface *ifp)
     return neigh;
 }
 
-/* Recompute a neighbour's rxcost.  Return true if anything changed. */
+/* Recompute a neighbour's rxcost.  Return true if anything changed.
+   This does not call local_notify_neighbour, see update_neighbour_metric. */
 int
 update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
 {
@@ -327,7 +328,7 @@ neighbour_cost(struct neighbour *neigh)
         return INFINITY;
 
     if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ)
-       || (a <= 256 && b <= 256)) {
+       || (a < 256 && b < 256)) {
         return a;
     } else {
         /* a = 256/alpha, b = 256/beta, where alpha and beta are the expected
index eaed51d20a6e47e6e1a195d4ab7783ec980ee1c2..5e0200b0ab591528e9fc48b6c67e464a46814c2e 100644 (file)
@@ -58,6 +58,7 @@ babel_socket(int port)
     int s, rc;
     int saved_errno;
     int one = 1, zero = 0;
+    const int ds = 0xc0;        /* CS6 - Network Control */
 
     s = socket(PF_INET6, SOCK_DGRAM, 0);
     if(s < 0)
@@ -86,6 +87,15 @@ babel_socket(int port)
     if(rc < 0)
         goto fail;
 
+#ifdef IPV6_TCLASS
+    rc = setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds));
+#else
+    rc = -1;
+    errno = ENOSYS;
+#endif
+    if(rc < 0)
+        perror("Couldn't set traffic class");
+
     rc = fcntl(s, F_GETFL, 0);
     if(rc < 0)
         goto fail;
index aadf80f2734cee8ed83723c8192cbc654c245472..a9ffc5d9ab9c5b817319aa05dba17375238ab969 100644 (file)
@@ -53,36 +53,161 @@ THE SOFTWARE.
 
 static void consider_route(struct babel_route *route);
 
-struct babel_route *routes = NULL;
-int numroutes = 0, maxroutes = 0;
+struct babel_route **routes = NULL;
+static int route_slots = 0, max_route_slots = 0;
 int kernel_metric = 0;
 int allow_duplicates = -1;
+int diversity_kind = DIVERSITY_NONE;
+int diversity_factor = 256;     /* in units of 1/256 */
+int keep_unfeasible = 0;
+
+/* 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. */
+
+static int
+route_compare(const unsigned char *prefix, unsigned char plen,
+               struct babel_route *route)
+{
+    int i = memcmp(prefix, route->src->prefix, 16);
+    if(i != 0)
+        return i;
+
+    if(plen < route->src->plen)
+        return -1;
+    else if(plen > route->src->plen)
+        return 1;
+    else
+        return 0;
+}
+
+/* Performs binary search, returns -1 in case of failure.  In the latter
+   case, new_return is the place where to insert the new element. */
+
+static int
+find_route_slot(const unsigned char *prefix, unsigned char plen,
+                int *new_return)
+{
+    int p, m, g, c;
+
+    if(route_slots < 1) {
+        if(new_return)
+            *new_return = 0;
+        return -1;
+    }
+
+    p = 0; g = route_slots - 1;
+
+    do {
+        m = (p + g) / 2;
+        c = route_compare(prefix, plen, routes[m]);
+        if(c == 0)
+            return m;
+        else if(c < 0)
+            g = m - 1;
+        else
+            p = m + 1;
+    } while(p <= g);
+
+    if(new_return)
+        *new_return = p;
+
+    return -1;
+}
 
 struct babel_route *
 find_route(const unsigned char *prefix, unsigned char plen,
            struct neighbour *neigh, const unsigned char *nexthop)
 {
-    int i;
-    for(i = 0; i < numroutes; i++) {
-        if(routes[i].neigh == neigh &&
-           memcmp(routes[i].nexthop, nexthop, 16) == 0 &&
-           source_match(routes[i].src, prefix, plen))
-            return &routes[i];
+    struct babel_route *route;
+    int i = find_route_slot(prefix, plen, NULL);
+
+    if(i < 0)
+        return NULL;
+
+    route = routes[i];
+
+    while(route) {
+        if(route->neigh == neigh && memcmp(route->nexthop, nexthop, 16) == 0)
+            return route;
+        route = route->next;
     }
+
     return NULL;
 }
 
 struct babel_route *
 find_installed_route(const unsigned char *prefix, unsigned char plen)
 {
-    int i;
-    for(i = 0; i < numroutes; i++) {
-        if(routes[i].installed && source_match(routes[i].src, prefix, plen))
-            return &routes[i];
-    }
+    int i = find_route_slot(prefix, plen, NULL);
+
+    if(i >= 0 && routes[i]->installed)
+        return routes[i];
+
     return NULL;
 }
 
+/* Returns an overestimate of the number of installed routes. */
+int
+installed_routes_estimate(void)
+{
+    return route_slots;
+}
+
+static int
+resize_route_table(int new_slots)
+{
+    struct babel_route **new_routes;
+    assert(new_slots >= route_slots);
+
+    if(new_slots == 0) {
+        new_routes = NULL;
+        free(routes);
+    } else {
+        new_routes = realloc(routes, new_slots * sizeof(struct babel_route*));
+        if(new_routes == NULL)
+            return -1;
+    }
+
+    max_route_slots = new_slots;
+    routes = new_routes;
+    return 1;
+}
+
+/* Insert a route into the table.  If successful, retains the route.
+   On failure, caller must free the route. */
+static struct babel_route *
+insert_route(struct babel_route *route)
+{
+    int i, n;
+
+    assert(!route->installed);
+
+    i = find_route_slot(route->src->prefix, route->src->plen, &n);
+
+    if(i < 0) {
+        if(route_slots >= max_route_slots)
+            resize_route_table(max_route_slots < 1 ? 8 : 2 * max_route_slots);
+        if(route_slots >= max_route_slots)
+            return NULL;
+        route->next = NULL;
+        if(n < route_slots)
+            memmove(routes + n + 1, routes + n,
+                    (route_slots - n) * sizeof(struct babel_route*));
+        route_slots++;
+        routes[n] = route;
+    } else {
+        struct babel_route *r;
+        r = routes[i];
+        while(r->next)
+            r = r->next;
+        r->next = route;
+        route->next = NULL;
+    }
+
+    return route;
+}
+
 void
 flush_route(struct babel_route *route)
 {
@@ -91,39 +216,67 @@ flush_route(struct babel_route *route)
     unsigned oldmetric;
     int lost = 0;
 
-    i = route - routes;
-    assert(i >= 0 && i < numroutes);
-
     oldmetric = route_metric(route);
+    src = route->src;
 
     if(route->installed) {
         uninstall_route(route);
         lost = 1;
     }
 
-    src = route->src;
+    i = find_route_slot(route->src->prefix, route->src->plen, NULL);
+    assert(i >= 0 && i < route_slots);
 
-    if(i != numroutes - 1)
-        memcpy(routes + i, routes + numroutes - 1, sizeof(struct babel_route));
-    numroutes--;
-    VALGRIND_MAKE_MEM_UNDEFINED(routes + numroutes, sizeof(struct babel_route));
+    if(route == routes[i]) {
+        routes[i] = route->next;
+        route->next = NULL;
+        free(route);
 
-    if(numroutes == 0) {
-        free(routes);
-        routes = NULL;
-        maxroutes = 0;
-    } else if(maxroutes > 8 && numroutes < maxroutes / 4) {
-        struct babel_route *new_routes;
-        int n = maxroutes / 2;
-        new_routes = realloc(routes, n * sizeof(struct babel_route));
-        if(new_routes != NULL) {
-            routes = new_routes;
-            maxroutes = n;
+        if(routes[i] == NULL) {
+            if(i < route_slots - 1)
+                memmove(routes + i, routes + i + 1,
+                        (route_slots - i - 1) * sizeof(struct babel_route*));
+            routes[route_slots - 1] = NULL;
+            route_slots--;
         }
+
+        if(route_slots == 0)
+            resize_route_table(0);
+        else if(max_route_slots > 8 && route_slots < max_route_slots / 4)
+            resize_route_table(max_route_slots / 2);
+    } else {
+        struct babel_route *r = routes[i];
+        while(r->next != route)
+            r = r->next;
+        r->next = route->next;
+        route->next = NULL;
+        free(route);
     }
 
     if(lost)
         route_lost(src, oldmetric);
+
+    release_source(src);
+}
+
+void
+flush_all_routes()
+{
+    int i;
+
+    /* Start from the end, to avoid shifting the table. */
+    i = route_slots - 1;
+    while(i >= 0) {
+        while(i < route_slots) {
+        /* Uninstall first, to avoid calling route_lost. */
+            if(routes[i]->installed)
+                uninstall_route(routes[0]);
+            flush_route(routes[i]);
+        }
+        i--;
+    }
+
+    check_sources_released();
 }
 
 void
@@ -132,12 +285,19 @@ flush_neighbour_routes(struct neighbour *neigh)
     int i;
 
     i = 0;
-    while(i < numroutes) {
-        if(routes[i].neigh == neigh) {
-            flush_route(&routes[i]);
-            continue;
+    while(i < route_slots) {
+        struct babel_route *r;
+        r = routes[i];
+        while(r) {
+            if(r->neigh == neigh) {
+                flush_route(r);
+                goto again;
+            }
+            r = r->next;
         }
         i++;
+    again:
+        ;
     }
 }
 
@@ -147,13 +307,46 @@ flush_interface_routes(struct interface *ifp, int v4only)
     int i;
 
     i = 0;
-    while(i < numroutes) {
-        if(routes[i].neigh->ifp == ifp &&
-           (!v4only || v4mapped(routes[i].nexthop))) {
-           flush_route(&routes[i]);
-           continue;
+    while(i < route_slots) {
+        struct babel_route *r;
+        r = routes[i];
+        while(r) {
+            if(r->neigh->ifp == ifp &&
+               (!v4only || v4mapped(r->nexthop))) {
+                flush_route(r);
+                goto again;
+            }
+            r = r->next;
         }
         i++;
+    again:
+        ;
+    }
+}
+
+/* Iterate a function over all routes. */
+void
+for_all_routes(void (*f)(struct babel_route*, void*), void *closure)
+{
+    int i;
+
+    for(i = 0; i < route_slots; i++) {
+        struct babel_route *r = routes[i];
+        while(r) {
+            (*f)(r, closure);
+            r = r->next;
+        }
+    }
+}
+
+void
+for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure)
+{
+    int i;
+
+    for(i = 0; i < route_slots; i++) {
+        if(routes[i]->installed)
+            (*f)(routes[i], closure);
     }
 }
 
@@ -163,10 +356,28 @@ metric_to_kernel(int metric)
     return metric < INFINITY ? kernel_metric : KERNEL_INFINITY;
 }
 
+/* This is used to maintain the invariant that the installed route is at
+   the head of the list. */
+static void
+move_installed_route(struct babel_route *route, int i)
+{
+    assert(i >= 0 && i < route_slots);
+    assert(route->installed);
+
+    if(route != routes[i]) {
+        struct babel_route *r = routes[i];
+        while(r->next != route)
+            r = r->next;
+        r->next = route->next;
+        route->next = routes[i];
+        routes[i] = route;
+    }
+}
+
 void
 install_route(struct babel_route *route)
 {
-    int rc;
+    int i, rc;
 
     if(route->installed)
         return;
@@ -175,6 +386,15 @@ install_route(struct babel_route *route)
         zlog_err("WARNING: installing unfeasible route "
                  "(this shouldn't happen).");
 
+    i = find_route_slot(route->src->prefix, route->src->plen, NULL);
+    assert(i >= 0 && i < route_slots);
+
+    if(routes[i] != route && routes[i]->installed) {
+        fprintf(stderr, "WARNING: attempting to install duplicate route "
+                "(this shouldn't happen).");
+        return;
+    }
+
     rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen,
                       route->nexthop,
                       route->neigh->ifp->ifindex,
@@ -186,6 +406,8 @@ install_route(struct babel_route *route)
             return;
     }
     route->installed = 1;
+    move_installed_route(route, i);
+
 }
 
 void
@@ -239,15 +461,16 @@ switch_routes(struct babel_route *old, struct babel_route *new)
 
     old->installed = 0;
     new->installed = 1;
+    move_installed_route(new, find_route_slot(new->src->prefix, new->src->plen,
+                                              NULL));
 }
 
 static void
-change_route_metric(struct babel_route *route, unsigned newmetric)
+change_route_metric(struct babel_route *route,
+                    unsigned refmetric, unsigned cost, unsigned add)
 {
     int old, new;
-
-    if(route_metric(route) == newmetric)
-        return;
+    int newmetric = MIN(refmetric + cost + add, INFINITY);
 
     old = metric_to_kernel(route_metric(route));
     new = metric_to_kernel(newmetric);
@@ -265,14 +488,15 @@ change_route_metric(struct babel_route *route, unsigned newmetric)
         }
     }
 
-    route->metric = newmetric;
+    route->refmetric = refmetric;
+    route->cost = cost;
+    route->add_metric = add;
 }
 
 static void
 retract_route(struct babel_route *route)
 {
-    route->refmetric = INFINITY;
-    change_route_metric(route, INFINITY);
+    change_route_metric(route, INFINITY, INFINITY, 0);
 }
 
 int
@@ -293,6 +517,51 @@ route_expired(struct babel_route *route)
     return route->time < babel_now.tv_sec - route->hold_time;
 }
 
+static int
+channels_interfere(int ch1, int ch2)
+{
+    if(ch1 == BABEL_IF_CHANNEL_NONINTERFERING
+       || ch2 == BABEL_IF_CHANNEL_NONINTERFERING)
+        return 0;
+    if(ch1 == BABEL_IF_CHANNEL_INTERFERING
+       || ch2 == BABEL_IF_CHANNEL_INTERFERING)
+        return 1;
+    return ch1 == ch2;
+}
+
+int
+route_interferes(struct babel_route *route, struct interface *ifp)
+{
+    struct babel_interface *babel_ifp = NULL;
+    switch(diversity_kind) {
+    case DIVERSITY_NONE:
+        return 1;
+    case DIVERSITY_INTERFACE_1:
+        return route->neigh->ifp == ifp;
+    case DIVERSITY_CHANNEL_1:
+    case DIVERSITY_CHANNEL:
+        if(route->neigh->ifp == ifp)
+            return 1;
+        babel_ifp = babel_get_if_nfo(ifp);
+        if(channels_interfere(babel_ifp->channel,
+                              babel_get_if_nfo(route->neigh->ifp)->channel))
+            return 1;
+        if(diversity_kind == DIVERSITY_CHANNEL) {
+            int i;
+            for(i = 0; i < DIVERSITY_HOPS; i++) {
+                if(route->channels[i] == 0)
+                    break;
+                if(channels_interfere(babel_ifp->channel, route->channels[i]))
+                    return 1;
+            }
+        }
+        return 0;
+    default:
+        fprintf(stderr, "Unknown kind of diversity.\n");
+        return 1;
+    }
+}
+
 int
 update_feasible(struct source *src,
                 unsigned short seqno, unsigned short refmetric)
@@ -317,21 +586,22 @@ struct babel_route *
 find_best_route(const unsigned char *prefix, unsigned char plen, int feasible,
                 struct neighbour *exclude)
 {
-    struct babel_route *route = NULL;
-    int i;
+    struct babel_route *route = NULL, *r = NULL;
+    int i = find_route_slot(prefix, plen, NULL);
+
+    if(i < 0)
+        return NULL;
+
+    route = routes[i];
 
-    for(i = 0; i < numroutes; i++) {
-        if(!source_match(routes[i].src, prefix, plen))
-            continue;
-        if(route_expired(&routes[i]))
-            continue;
-        if(feasible && !route_feasible(&routes[i]))
-            continue;
-        if(exclude && routes[i].neigh == exclude)
-            continue;
-        if(route && route_metric(route) <= route_metric(&routes[i]))
-            continue;
-        route = &routes[i];
+    r = route->next;
+    while(r) {
+        if(!route_expired(r) &&
+           (!feasible || route_feasible(r)) &&
+           (!exclude || r->neigh != exclude) &&
+           (route_metric(r) < route_metric(route)))
+            route = r;
+        r = r->next;
     }
     return route;
 }
@@ -354,31 +624,29 @@ update_route_metric(struct babel_route *route)
                                       route->src->prefix, route->src->plen,
                                       neigh->address,
                                       neigh->ifp->ifindex);
-        int newmetric = MIN(route->refmetric +
-                            add_metric +
-                            neighbour_cost(route->neigh),
-                            INFINITY);
-
-        if(newmetric != oldmetric) {
-            change_route_metric(route, newmetric);
+        change_route_metric(route, route->refmetric,
+                            neighbour_cost(route->neigh), add_metric);
+        if(route_metric(route) != oldmetric)
             route_changed(route, route->src, oldmetric);
-        }
     }
 }
 
 /* Called whenever a neighbour's cost changes, to update the metric of
all routes through that neighbour. */
  all routes through that neighbour.  Calls local_notify_neighbour. */
 void
 update_neighbour_metric(struct neighbour *neigh, int changed)
 {
+
     if(changed) {
         int i;
 
-        i = 0;
-        while(i < numroutes) {
-            if(routes[i].neigh == neigh)
-                update_route_metric(&routes[i]);
-            i++;
+        for(i = 0; i < route_slots; i++) {
+            struct babel_route *r = routes[i];
+            while(r) {
+                if(r->neigh == neigh)
+                    update_route_metric(r);
+                r = r->next;
+            }
         }
     }
 }
@@ -388,11 +656,13 @@ update_interface_metric(struct interface *ifp)
 {
     int i;
 
-    i = 0;
-    while(i < numroutes) {
-        if(routes[i].neigh->ifp == ifp)
-            update_route_metric(&routes[i]);
-        i++;
+    for(i = 0; i < route_slots; i++) {
+        struct babel_route *r = routes[i];
+        while(r) {
+            if(r->neigh->ifp == ifp)
+                update_route_metric(r);
+            r = r->next;
+        }
     }
 }
 
@@ -402,7 +672,8 @@ update_route(const unsigned char *router_id,
              const unsigned char *prefix, unsigned char plen,
              unsigned short seqno, unsigned short refmetric,
              unsigned short interval,
-             struct neighbour *neigh, const unsigned char *nexthop)
+             struct neighbour *neigh, const unsigned char *nexthop,
+             const unsigned char *channels, int channels_len)
 {
     struct babel_route *route;
     struct source *src;
@@ -424,12 +695,18 @@ update_route(const unsigned char *router_id,
     if(add_metric >= INFINITY)
         return NULL;
 
-    src = find_source(router_id, prefix, plen, 1, seqno);
+    route = find_route(prefix, plen, neigh, nexthop);
+
+    if(route && memcmp(route->src->id, router_id, 8) == 0)
+        /* Avoid scanning the source table. */
+        src = route->src;
+    else
+        src = find_source(router_id, prefix, plen, 1, seqno);
+
     if(src == NULL)
         return NULL;
 
     feasible = update_feasible(src, seqno, refmetric);
-    route = find_route(prefix, plen, neigh, nexthop);
     metric = MIN((int)refmetric + neighbour_cost(neigh) + add_metric, INFINITY);
 
     if(route) {
@@ -457,12 +734,12 @@ update_route(const unsigned char *router_id,
             }
         }
 
-        route->src = src;
-        if(feasible && refmetric < INFINITY)
+        route->src = retain_source(src);
+        if((feasible || keep_unfeasible) && refmetric < INFINITY)
             route->time = babel_now.tv_sec;
         route->seqno = seqno;
-        route->refmetric = refmetric;
-        change_route_metric(route, metric);
+        change_route_metric(route,
+                            refmetric, neighbour_cost(neigh), add_metric);
         route->hold_time = hold_time;
 
         route_changed(route, oldsrc, oldmetric);
@@ -472,36 +749,46 @@ update_route(const unsigned char *router_id,
         if(!feasible)
             send_unfeasible_request(neigh, route->installed && route_old(route),
                                     seqno, metric, src);
+        release_source(oldsrc);
     } else {
+        struct babel_route *new_route;
+
         if(refmetric >= INFINITY)
             /* Somebody's retracting a route we never saw. */
             return NULL;
         if(!feasible) {
             send_unfeasible_request(neigh, 0, seqno, metric, src);
-            return NULL;
-        }
-        if(numroutes >= maxroutes) {
-            struct babel_route *new_routes;
-            int n = maxroutes < 1 ? 8 : 2 * maxroutes;
-            new_routes = routes == NULL ?
-                malloc(n * sizeof(struct babel_route)) :
-                realloc(routes, n * sizeof(struct babel_route));
-            if(new_routes == NULL)
+            if(!keep_unfeasible)
                 return NULL;
-            maxroutes = n;
-            routes = new_routes;
         }
-        route = &routes[numroutes];
-        route->src = src;
+
+        route = malloc(sizeof(struct babel_route));
+        if(route == NULL) {
+            perror("malloc(route)");
+            return NULL;
+        }
+
+        route->src = retain_source(src);
         route->refmetric = refmetric;
+        route->cost = neighbour_cost(neigh);
+        route->add_metric = add_metric;
         route->seqno = seqno;
-        route->metric = metric;
         route->neigh = neigh;
         memcpy(route->nexthop, nexthop, 16);
         route->time = babel_now.tv_sec;
         route->hold_time = hold_time;
         route->installed = 0;
-        numroutes++;
+        memset(&route->channels, 0, sizeof(route->channels));
+        if(channels_len > 0)
+            memcpy(&route->channels, channels,
+                   MIN(channels_len, DIVERSITY_HOPS));
+        route->next = NULL;
+        new_route = insert_route(route);
+        if(new_route == NULL) {
+            fprintf(stderr, "Couldn't insert route.\n");
+            free(route);
+            return NULL;
+        }
         consider_route(route);
     }
     return route;
@@ -558,13 +845,6 @@ consider_route(struct babel_route *route)
     if(route_metric(installed) >= INFINITY)
         goto install;
 
-    if(route_metric(installed) >= route_metric(route) + 192)
-        goto install;
-
-    /* Avoid switching sources */
-    if(installed->src != route->src)
-        return;
-
     if(route_metric(installed) >= route_metric(route) + 64)
         goto install;
 
@@ -584,15 +864,18 @@ retract_neighbour_routes(struct neighbour *neigh)
 {
     int i;
 
-    i = 0;
-    while(i < numroutes) {
-        if(routes[i].neigh == neigh) {
-            if(routes[i].refmetric != INFINITY) {
-                unsigned short oldmetric = route_metric(&routes[i]);
-                    retract_route(&routes[i]);
+    for(i = 0; i < route_slots; i++) {
+        struct babel_route *r = routes[i];
+        while(r) {
+            if(r->neigh == neigh) {
+                if(r->refmetric != INFINITY) {
+                    unsigned short oldmetric = route_metric(r);
+                    retract_route(r);
                     if(oldmetric != INFINITY)
-                        route_changed(&routes[i], routes[i].src, oldmetric);
+                        route_changed(r, r->src, oldmetric);
+                }
             }
+            r = r->next;
         }
         i++;
     }
@@ -699,51 +982,38 @@ route_lost(struct source *src, unsigned oldmetric)
     }
 }
 
+/* This is called periodically to flush old routes.  It will also send
+   requests for routes that are about to expire. */
 void
 expire_routes(void)
 {
+    struct babel_route *r;
     int i;
 
     debugf(BABEL_DEBUG_COMMON,"Expiring old routes.");
 
     i = 0;
-    while(i < numroutes) {
-        struct babel_route *route = &routes[i];
-
-        if(route->time > babel_now.tv_sec || /* clock stepped */
-           route_old(route)) {
-            flush_route(route);
-            continue;
-        }
+    while(i < route_slots) {
+        r = routes[i];
+        while(r) {
+            /* Protect against clock being stepped. */
+            if(r->time > babel_now.tv_sec || route_old(r)) {
+                flush_route(r);
+                goto again;
+            }
 
-        update_route_metric(route);
+            update_route_metric(r);
 
-        if(route->installed && route->refmetric < INFINITY) {
-            if(route_old(route))
-                send_unicast_request(route->neigh,
-                                     route->src->prefix, route->src->plen);
+            if(r->installed && r->refmetric < INFINITY) {
+                if(route_old(r))
+                    /* Route about to expire, send a request. */
+                    send_unicast_request(r->neigh,
+                                         r->src->prefix, r->src->plen);
+            }
+            r = r->next;
         }
         i++;
+    again:
+        ;
     }
 }
-
-void
-babel_uninstall_all_routes(void)
-{
-    while(numroutes > 0) {
-        uninstall_route(&routes[0]);
-        /* We need to flush the route so network_up won't reinstall it */
-        flush_route(&routes[0]);
-    }
-}
-
-struct babel_route *
-babel_route_get_by_source(struct source *src)
-{
-    int i;
-    for(i = 0; i < numroutes; i++) {
-        if(routes[i].src == src)
-            return &routes[i];
-    }
-    return NULL;
-}
index c08332a6d99767a10fde8d40b2766b1d748a08f8..b6d2d29466d5a425da8828def3eff99283a51a0f 100644 (file)
@@ -43,41 +43,69 @@ THE SOFTWARE.
 #include "babel_interface.h"
 #include "source.h"
 
+#define DIVERSITY_NONE 0
+#define DIVERSITY_INTERFACE_1 1
+#define DIVERSITY_CHANNEL_1 2
+#define DIVERSITY_CHANNEL 3
+
+#define DIVERSITY_HOPS 8
+
 struct babel_route {
     struct source *src;
-    unsigned short metric;
     unsigned short refmetric;
+    unsigned short cost;
+    unsigned short add_metric;
     unsigned short seqno;
     struct neighbour *neigh;
     unsigned char nexthop[16];
     time_t time;
     unsigned short hold_time;    /* in seconds */
     short installed;
+    unsigned char channels[DIVERSITY_HOPS];
+    struct babel_route *next;
 };
 
-static inline unsigned short
+extern struct babel_route **routes;
+extern int kernel_metric, allow_duplicates;
+extern int diversity_kind, diversity_factor;
+extern int keep_unfeasible;
+
+static inline int
 route_metric(const struct babel_route *route)
 {
-    return route->metric;
+    int m = (int)route->refmetric + route->cost + route->add_metric;
+    return MIN(m, INFINITY);
 }
 
-extern struct babel_route *routes;
-extern int numroutes, maxroutes;
-extern int kernel_metric, allow_duplicates;
+static inline int
+route_metric_noninterfering(const struct babel_route *route)
+{
+    int m =
+        (int)route->refmetric +
+        (diversity_factor * route->cost + 128) / 256 +
+        route->add_metric;
+    m = MAX(m, route->refmetric + 1);
+    return MIN(m, INFINITY);
+}
 
 struct babel_route *find_route(const unsigned char *prefix, unsigned char plen,
                          struct neighbour *neigh, const unsigned char *nexthop);
 struct babel_route *find_installed_route(const unsigned char *prefix,
                                    unsigned char plen);
+int installed_routes_estimate(void);
 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);
+void for_all_routes(void (*f)(struct babel_route*, void*), void *closure);
+void for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure);
 void install_route(struct babel_route *route);
 void uninstall_route(struct babel_route *route);
 void switch_route(struct babel_route *old, struct babel_route *new);
 int route_feasible(struct babel_route *route);
 int route_old(struct babel_route *route);
 int route_expired(struct babel_route *route);
+int route_interferes(struct babel_route *route, struct interface *ifp);
 int update_feasible(struct source *src,
                     unsigned short seqno, unsigned short refmetric);
 struct babel_route *find_best_route(const unsigned char *prefix, unsigned char plen,
@@ -87,11 +115,12 @@ struct babel_route *install_best_route(const unsigned char prefix[16],
 void update_neighbour_metric(struct neighbour *neigh, int change);
 void update_interface_metric(struct interface *ifp);
 void update_route_metric(struct babel_route *route);
-struct babel_route *update_route(const unsigned char *a,
-                           const unsigned char *p, unsigned char plen,
+struct babel_route *update_route(const unsigned char *id,
+                           const unsigned char *prefix, unsigned char plen,
                            unsigned short seqno, unsigned short refmetric,
                            unsigned short interval, struct neighbour *neigh,
-                           const unsigned char *nexthop);
+                           const unsigned char *nexthop,
+                           const unsigned char *channels, int channels_len);
 void retract_neighbour_routes(struct neighbour *neigh);
 void send_unfeasible_request(struct neighbour *neigh, int force,
                              unsigned short seqno, unsigned short metric,
@@ -103,7 +132,4 @@ void route_changed(struct babel_route *route,
 void route_lost(struct source *src, unsigned oldmetric);
 void expire_routes(void);
 
-void babel_uninstall_all_routes(void);
-struct babel_route *babel_route_get_by_source(struct source *src);
-
 #endif
index cc4ed445be771f61791491d48e09ed162177e73c..772112d4d3779095cc42d69c34998f6a26253391 100644 (file)
@@ -63,8 +63,10 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen,
             continue;
         if(memcmp(src->id, id, 8) != 0)
             continue;
-        if(source_match(src, p, plen))
-           return src;
+        if(src->plen != plen)
+            continue;
+        if(memcmp(src->prefix, p, 16) == 0)
+            return src;
     }
 
     if(!create)
@@ -82,18 +84,32 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen,
     src->seqno = seqno;
     src->metric = INFINITY;
     src->time = babel_now.tv_sec;
+    src->route_count = 0;
     src->next = srcs;
     srcs = src;
     return src;
 }
 
+struct source *
+retain_source(struct source *src)
+{
+    assert(src->route_count < 0xffff);
+    src->route_count++;
+    return src;
+}
+
+void
+release_source(struct source *src)
+{
+    assert(src->route_count > 0);
+    src->route_count--;
+}
+
 int
 flush_source(struct source *src)
 {
-    /* This is absolutely horrible -- it makes expire_sources quadratic.
-       But it's not called very often. */
-
-    if (babel_route_get_by_source(src) != NULL)
+    if(src->route_count > 0)
+        /* The source is in use by a route. */
         return 0;
 
     if(srcs == src) {
@@ -109,19 +125,6 @@ flush_source(struct source *src)
     return 1;
 }
 
-int
-source_match(struct source *src,
-             const unsigned char *p, unsigned char plen)
-{
-    if(src->plen != plen)
-        return 0;
-    if(src->prefix[15] != p[15])
-        return 0;
-    if(memcmp(src->prefix, p, 16) != 0)
-        return 0;
-    return 1;
-}
-
 void
 update_source(struct source *src,
               unsigned short seqno, unsigned short metric)
@@ -129,6 +132,10 @@ update_source(struct source *src,
     if(metric >= INFINITY)
         return;
 
+    /* If a source is expired, pretend that it doesn't exist and update
+       it unconditionally.  This makes ensures that old data will
+       eventually be overridden, and prevents us from getting stuck if
+       a router loses its sequence number. */
     if(src->time < babel_now.tv_sec - SOURCE_GC_TIME ||
        seqno_compare(src->seqno, seqno) < 0 ||
        (src->seqno == seqno && src->metric > metric)) {
@@ -157,3 +164,17 @@ expire_sources()
         src = src->next;
     }
 }
+
+void
+check_sources_released(void)
+{
+    struct source *src;
+
+    for(src = srcs; src; src = src->next) {
+        if(src->route_count != 0)
+            fprintf(stderr, "Warning: source %s %s has refcount %d.\n",
+                    format_eui64(src->id),
+                    format_prefix(src->prefix, src->plen),
+                    (int)src->route_count);
+    }
+}
index 38d3c004ce17a8fd26f5983b1e016a58f7d37001..62a7e1eea358357a493ec35807980e82783e3a7f 100644 (file)
@@ -48,19 +48,20 @@ struct source {
     unsigned char plen;
     unsigned short seqno;
     unsigned short metric;
+    unsigned short route_count;
     time_t time;
 };
 
-int source_match(struct source *src,
-                 const unsigned char *p, unsigned char plen);
 struct source *find_source(const unsigned char *id,
                            const unsigned char *p,
                            unsigned char plen,
                            int create, unsigned short seqno);
+struct source *retain_source(struct source *src);
+void release_source(struct source *src);
 int flush_source(struct source *src);
 void update_source(struct source *src,
                    unsigned short seqno, unsigned short metric);
 void expire_sources(void);
-
+void check_sources_released(void);
 
 #endif
index 514e0ff395952979c8f4e13b45a62097e702d586..011f3824eb6a5f0bbc361badd503630baf30a68f 100644 (file)
@@ -200,17 +200,6 @@ parse_msec(const char *string)
     return -1;
 }
 
-void
-do_debugf(const char *format, ...)
-{
-    va_list args;
-    va_start(args, format);
-    vfprintf(stderr, format, args);
-    fprintf(stderr, "\n");
-    fflush(stderr);
-    va_end(args);
-}
-
 int
 in_prefix(const unsigned char *restrict address,
           const unsigned char *restrict prefix, unsigned char plen)
@@ -327,63 +316,6 @@ parse_address(const char *address, unsigned char *addr_r, int *af_r)
     return -1;
 }
 
-int
-parse_net(const char *net, unsigned char *prefix_r, unsigned char *plen_r,
-          int *af_r)
-{
-    char buf[INET6_ADDRSTRLEN];
-    char *slash, *end;
-    unsigned char prefix[16];
-    long plen;
-    int af;
-    struct in_addr ina;
-    struct in6_addr ina6;
-    int rc;
-
-    if(strcmp(net, "default") == 0) {
-        memset(prefix, 0, 16);
-        plen = 0;
-    } else {
-        slash = strchr(net, '/');
-        if(slash == NULL) {
-            rc = parse_address(net, prefix, &af);
-            if(rc < 0)
-                return rc;
-            plen = 128;
-        } else {
-            if(slash - net >= INET6_ADDRSTRLEN)
-                return -1;
-            memcpy(buf, net, slash - net);
-            buf[slash - net] = '\0';
-            rc = inet_pton(AF_INET, buf, &ina);
-            if(rc > 0) {
-                memcpy(prefix, v4prefix, 12);
-                memcpy(prefix + 12, &ina, 4);
-                plen = strtol(slash + 1, &end, 0);
-                if(*end != '\0' || plen < 0 || plen > 32)
-                    return -1;
-                plen += 96;
-                af = AF_INET;
-            } else {
-                rc = inet_pton(AF_INET6, buf, &ina6);
-                if(rc > 0) {
-                    memcpy(prefix, &ina6, 16);
-                    plen = strtol(slash + 1, &end, 0);
-                    if(*end != '\0' || plen < 0 || plen > 128)
-                        return -1;
-                    af = AF_INET6;
-                } else {
-                    return -1;
-                }
-            }
-        }
-    }
-    mask_prefix(prefix_r, prefix, plen);
-    *plen_r = plen;
-    if(af_r) *af_r = af;
-    return 0;
-}
-
 int
 parse_eui64(const char *eui, unsigned char *eui_r)
 {
index 376b967f65d0af638f4925c3cbd91ce5ae1d847c..5d9d2f5dab207525a87f869ed549ff53290e499d 100644 (file)
@@ -100,8 +100,6 @@ int timeval_compare(const struct timeval *s1, const struct timeval *s2)
 void timeval_min(struct timeval *d, const struct timeval *s);
 void timeval_min_sec(struct timeval *d, time_t secs);
 int parse_msec(const char *string) ATTRIBUTE ((pure));
-void do_debugf(const char *format, ...)
-    ATTRIBUTE ((format (printf, 1, 2))) COLD;
 int in_prefix(const unsigned char *restrict address,
               const unsigned char *restrict prefix, unsigned char plen)
     ATTRIBUTE ((pure));
@@ -113,8 +111,6 @@ const char *format_prefix(const unsigned char *address, unsigned char prefix);
 const char *format_eui64(const unsigned char *eui);
 const char *format_bool(const int b);
 int parse_address(const char *address, unsigned char *addr_r, int *af_r);
-int parse_net(const char *ifp, unsigned char *prefix_r, unsigned char *plen_r,
-              int *af_r);
 int parse_eui64(const char *eui, unsigned char *eui_r);
 int wait_for_fd(int direction, int fd, int msecs);
 int martian_prefix(const unsigned char *prefix, int plen) ATTRIBUTE ((pure));
index 8330b492f367e71242ccc967653a5a70c6325c23..806516718f685d3c2434ec83dddb3159e676b3f4 100644 (file)
@@ -50,9 +50,12 @@ THE SOFTWARE.
 #include "util.h"
 #include "babel_interface.h"
 
-struct xroute *xroutes;
-int numxroutes = 0;
-int maxxroutes = 0;
+static int xroute_add_new_route(unsigned char prefix[16], unsigned char plen,
+                                unsigned short metric, unsigned int ifindex,
+                                int proto, int send_updates);
+
+static struct xroute *xroutes;
+static int numxroutes = 0, maxxroutes = 0;
 
 /* Add redistributed route to Babel table. */
 int
@@ -189,8 +192,24 @@ add_xroute(unsigned char prefix[16], unsigned char plen,
     return 1;
 }
 
-/* add an xroute, verifying some conditions; return 0 if there is no changes */
+/* Returns an overestimate of the number of xroutes. */
 int
+xroutes_estimate()
+{
+    return numxroutes;
+}
+
+void
+for_all_xroutes(void (*f)(struct xroute*, void*), void *closure)
+{
+    int i;
+
+    for(i = 0; i < numxroutes; i++)
+        (*f)(&xroutes[i], closure);
+}
+
+/* add an xroute, verifying some conditions; return 0 if there is no changes */
+static int
 xroute_add_new_route(unsigned char prefix[16], unsigned char plen,
                      unsigned short metric, unsigned int ifindex,
                      int proto, int send_updates)
index c9a4f85fb2ac1e587e4145495378efbac4942975..4d4ab99d03590bc584e7ca98f204a1c52b373668 100644 (file)
@@ -45,14 +45,8 @@ struct xroute {
     int proto;
 };
 
-extern struct xroute *xroutes;
-extern int numxroutes;
-
 struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen);
 void flush_xroute(struct xroute *xroute);
-int xroute_add_new_route(unsigned char prefix[16], unsigned char plen,
-                         unsigned short metric, unsigned int ifindex,
-                         int proto, int send_updates);
 int babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
                           unsigned int ifindex, struct in_addr *nexthop);
 int babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
@@ -61,3 +55,5 @@ int babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
                           unsigned int ifindex, struct in6_addr *nexthop);
 int babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
                              unsigned int ifindex);
+int xroutes_estimate(void);
+void for_all_xroutes(void (*f)(struct xroute*, void*), void *closure);