]> git.proxmox.com Git - mirror_frr.git/blobdiff - babeld/message.c
*: use rb-trees to store interfaces instead of sorted linked-lists
[mirror_frr.git] / babeld / message.c
index bfb17625b7f4c8bcef1e2d58fc1109ea4afc8195..ea378240be4f813d4215cf3e2de22125e110ec99 100644 (file)
@@ -1,21 +1,4 @@
-/*  
- *  This file is free software: you may copy, redistribute and/or modify it  
- *  under the terms of the GNU General Public License as published by the  
- *  Free Software Foundation, either version 2 of the License, or (at your  
- *  option) any later version.  
- *  
- *  This file is distributed in the hope that it will be useful, but  
- *  WITHOUT ANY WARRANTY; without even the implied warranty of  
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
- *  General Public License for more details.  
- *  
- *  You should have received a copy of the GNU General Public License  
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  
- *  
- * This file incorporates work covered by the following copyright and  
- * permission notice:  
- *  
-
+/*
 Copyright (c) 2007, 2008 by Juliusz Chroboczek
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -37,14 +20,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */
 
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
 #include <zebra.h>
 #include "if.h"
 
@@ -59,24 +34,38 @@ THE SOFTWARE.
 #include "resend.h"
 #include "message.h"
 #include "kernel.h"
+#include "babel_main.h"
 
-unsigned char packet_header[4] = {42, 2};
+static unsigned char packet_header[4] = {42, 2};
 
-int parasitic = 0;
 int split_horizon = 1;
 
 unsigned short myseqno = 0;
-struct timeval seqno_time = {0, 0};
 
 #define UNICAST_BUFSIZE 1024
-int unicast_buffered = 0;
-unsigned char *unicast_buffer = NULL;
+static int unicast_buffered = 0;
+static unsigned char *unicast_buffer = NULL;
 struct neighbour *unicast_neighbour = NULL;
 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 };
-
+/* Minimum TLV _body_ length for TLVs of particular types (0 = no limit). */
+static const unsigned char tlv_min_length[MESSAGE_MAX + 1] =
+{
+    [ MESSAGE_PAD1       ] =  0,
+    [ MESSAGE_PADN       ] =  0,
+    [ MESSAGE_ACK_REQ    ] =  6,
+    [ MESSAGE_ACK        ] =  2,
+    [ MESSAGE_HELLO      ] =  6,
+    [ MESSAGE_IHU        ] =  6,
+    [ MESSAGE_ROUTER_ID  ] = 10,
+    [ MESSAGE_NH         ] =  2,
+    [ MESSAGE_UPDATE     ] = 10,
+    [ MESSAGE_REQUEST    ] =  2,
+    [ MESSAGE_MH_REQUEST ] = 14,
+};
+
+/* 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,
@@ -84,6 +73,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;
@@ -98,7 +88,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;
@@ -108,6 +100,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;
@@ -116,19 +109,155 @@ 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_update_subtlv(const unsigned char *a, int alen,
+                    unsigned char *channels)
+{
+    int type, len, i = 0;
+
+    while(i < alen) {
+        type = a[i];
+        if(type == SUBTLV_PAD1) {
+            i++;
+            continue;
+        }
+
+        if(i + 1 > alen) {
+            zlog_err("Received truncated attributes.");
+            return;
+        }
+        len = a[i + 1];
+        if(i + len > alen) {
+            zlog_err("Received truncated attributes.");
+            return;
+        }
+
+        if(type == SUBTLV_PADN) {
+            /* Nothing. */
+        } else if(type == SUBTLV_DIVERSITY) {
+            if(len > DIVERSITY_HOPS) {
+                zlog_err("Received overlong channel information (%d > %d).n",
+                         len, DIVERSITY_HOPS);
+                len = DIVERSITY_HOPS;
+            }
+            if(memchr(a + i + 2, 0, len) != NULL) {
+                /* 0 is reserved. */
+                zlog_err("Channel information contains 0!");
+                return;
+            }
+            memset(channels, 0, DIVERSITY_HOPS);
+            memcpy(channels, a + i + 2, len);
+        } else {
+            debugf(BABEL_DEBUG_COMMON,
+                   "Received unknown route attribute %d.", type);
+        }
+
+        i += len + 2;
+    }
+}
+
+static int
+parse_hello_subtlv(const unsigned char *a, int alen,
+                   unsigned int *hello_send_us)
+{
+    int type, len, i = 0, ret = 0;
+
+    while(i < alen) {
+        type = a[0];
+        if(type == SUBTLV_PAD1) {
+            i++;
+            continue;
+        }
+
+        if(i + 1 > alen) {
+            zlog_err("Received truncated sub-TLV on Hello message.");
+            return -1;
+        }
+        len = a[i + 1];
+        if(i + len > alen) {
+            zlog_err("Received truncated sub-TLV on Hello message.");
+            return -1;
+        }
+
+        if(type == SUBTLV_PADN) {
+            /* Nothing to do. */
+        } else if(type == SUBTLV_TIMESTAMP) {
+            if(len >= 4) {
+                DO_NTOHL(*hello_send_us, a + i + 2);
+                ret = 1;
+            } else {
+                zlog_err("Received incorrect RTT sub-TLV on Hello message.");
+            }
+        } else {
+            debugf(BABEL_DEBUG_COMMON,
+                   "Received unknown Hello sub-TLV type %d.", type);
+        }
+
+        i += len + 2;
+    }
+    return ret;
+}
+
+static int
+parse_ihu_subtlv(const unsigned char *a, int alen,
+                 unsigned int *hello_send_us,
+                 unsigned int *hello_rtt_receive_time)
+{
+    int type, len, i = 0, ret = 0;
+
+    while(i < alen) {
+        type = a[0];
+        if(type == SUBTLV_PAD1) {
+            i++;
+            continue;
+        }
+
+        if(i + 1 > alen) {
+            zlog_err("Received truncated sub-TLV on IHU message.");
+            return -1;
+        }
+        len = a[i + 1];
+        if(i + len > alen) {
+            zlog_err("Received truncated sub-TLV on IHU message.");
+            return -1;
+        }
+
+        if(type == SUBTLV_PADN) {
+            /* Nothing to do. */
+        } else if(type == SUBTLV_TIMESTAMP) {
+            if(len >= 8) {
+                DO_NTOHL(*hello_send_us, a + i + 2);
+                DO_NTOHL(*hello_rtt_receive_time, a + i + 6);
+                ret = 1;
+            }
+            else {
+                zlog_err("Received incorrect RTT sub-TLV on IHU message.");
+            }
+        } else {
+            debugf(BABEL_DEBUG_COMMON,
+                   "Received unknown IHU sub-TLV type %d.", type);
+        }
+
+        i += len + 2;
+    }
+    return ret;
 }
 
 static int
@@ -138,6 +267,52 @@ 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;
+}
+
+/* Check, that the provided frame consists of a valid Babel packet header
+   followed by a sequence of TLVs. TLVs of known types are also checked to meet
+   minimum length constraints defined for each. Return 0 for no errors. */
+static int
+babel_packet_examin(const unsigned char *packet, int packetlen)
+{
+    unsigned i = 0, bodylen;
+    const unsigned char *message;
+    unsigned char type, len;
+
+    if(packetlen < 4 || packet[0] != 42 || packet[1] != 2)
+        return 1;
+    DO_NTOHS(bodylen, packet + 2);
+    while (i < bodylen){
+        message = packet + 4 + i;
+        type = message[0];
+        if(type == MESSAGE_PAD1) {
+            i++;
+            continue;
+        }
+        if(i + 1 > bodylen) {
+            debugf(BABEL_DEBUG_COMMON,"Received truncated message.");
+            return 1;
+        }
+        len = message[1];
+        if(i + len > bodylen) {
+            debugf(BABEL_DEBUG_COMMON,"Received truncated message.");
+            return 1;
+        }
+        /* not Pad1 */
+        if(type <= MESSAGE_MAX && tlv_min_length[type] && len < tlv_min_length[type]) {
+            debugf(BABEL_DEBUG_COMMON,"Undersized %u TLV", type);
+            return 1;
+        }
+        i += len + 2;
+    }
+    return 0;
+}
+
 void
 parse_packet(const unsigned char *from, struct interface *ifp,
              const unsigned char *packet, int packetlen)
@@ -151,37 +326,39 @@ parse_packet(const unsigned char *from, struct interface *ifp,
         have_v4_nh = 0, have_v6_nh = 0;
     unsigned char router_id[8], v4_prefix[16], v6_prefix[16],
         v4_nh[16], v6_nh[16];
+    int have_hello_rtt = 0;
+    /* Content of the RTT sub-TLV on IHU messages. */
+    unsigned int hello_send_us = 0, hello_rtt_receive_time = 0;
+    babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
 
-    if(!linklocal(from)) {
-        fprintf(stderr, "Received packet from non-local address %s.\n",
-                format_address(from));
-        return;
+    if(babel_ifp->flags & BABEL_IF_TIMESTAMPS) {
+        /* We want to track exactly when we received this packet. */
+        gettime(&babel_now);
     }
 
-    if(packet[0] != 42) {
-        fprintf(stderr, "Received malformed packet on %s from %s.\n",
-                ifp->name, format_address(from));
+    if(!linklocal(from)) {
+        zlog_err("Received packet from non-local address %s.",
+                 format_address(from));
         return;
     }
 
-    if(packet[1] != 2) {
-        fprintf(stderr,
-                "Received packet with unknown version %d on %s from %s.\n",
-                packet[1], ifp->name, format_address(from));
+    if (babel_packet_examin (packet, packetlen)) {
+        zlog_err("Received malformed packet on %s from %s.",
+                 ifp->name, format_address(from));
         return;
     }
 
     neigh = find_neighbour(from, ifp);
     if(neigh == NULL) {
-        fprintf(stderr, "Couldn't allocate neighbour.\n");
+        zlog_err("Couldn't allocate neighbour.");
         return;
     }
 
     DO_NTOHS(bodylen, packet + 2);
 
     if(bodylen + 4 > packetlen) {
-        fprintf(stderr, "Received truncated packet (%d + 4 > %d).\n",
-                bodylen, packetlen);
+        zlog_err("Received truncated packet (%d + 4 > %d).",
+                 bodylen, packetlen);
         bodylen = packetlen - 4;
     }
 
@@ -195,22 +372,13 @@ parse_packet(const unsigned char *from, struct interface *ifp,
             i++;
             continue;
         }
-        if(i + 1 > bodylen) {
-            fprintf(stderr, "Received truncated message.\n");
-            break;
-        }
         len = message[1];
-        if(i + len > bodylen) {
-            fprintf(stderr, "Received truncated message.\n");
-            break;
-        }
 
         if(type == MESSAGE_PADN) {
             debugf(BABEL_DEBUG_COMMON,"Received pad%d from %s on %s.",
                    len, format_address(from), ifp->name);
         } else if(type == MESSAGE_ACK_REQ) {
             unsigned short nonce, interval;
-            if(len < 6) goto fail;
             DO_NTOHS(nonce, message + 4);
             DO_NTOHS(interval, message + 6);
             debugf(BABEL_DEBUG_COMMON,"Received ack-req (%04X %d) from %s on %s.",
@@ -223,22 +391,29 @@ parse_packet(const unsigned char *from, struct interface *ifp,
         } else if(type == MESSAGE_HELLO) {
             unsigned short seqno, interval;
             int changed;
-            if(len < 6) goto fail;
+            unsigned int timestamp = 0;
             DO_NTOHS(seqno, message + 4);
             DO_NTOHS(interval, message + 6);
             debugf(BABEL_DEBUG_COMMON,"Received hello %d (%d) from %s on %s.",
                    seqno, interval,
                    format_address(from), ifp->name);
-            babel_get_if_nfo(ifp)->activity_time = babel_now.tv_sec;
             changed = update_neighbour(neigh, seqno, interval);
             update_neighbour_metric(neigh, changed);
             if(interval > 0)
-                schedule_neighbours_check(interval * 10, 0);
+                /* Multiply by 3/2 to allow hellos to expire. */
+                schedule_neighbours_check(interval * 15, 0);
+            /* Sub-TLV handling. */
+            if(len > 8) {
+                if(parse_hello_subtlv(message + 8, len - 6, &timestamp) > 0) {
+                    neigh->hello_send_us = timestamp;
+                    neigh->hello_rtt_receive_time = babel_now;
+                    have_hello_rtt = 1;
+                }
+            }
         } else if(type == MESSAGE_IHU) {
             unsigned short txcost, interval;
             unsigned char address[16];
             int rc;
-            if(len < 6) goto fail;
             DO_NTOHS(txcost, message + 4);
             DO_NTOHS(interval, message + 6);
             rc = network_address(message[2], message + 8, len - 6, address);
@@ -254,13 +429,14 @@ parse_packet(const unsigned char *from, struct interface *ifp,
                 neigh->ihu_interval = interval;
                 update_neighbour_metric(neigh, changed);
                 if(interval > 0)
-                    schedule_neighbours_check(interval * 10 * 3, 0);
+                    /* Multiply by 3/2 to allow neighbours to expire. */
+                    schedule_neighbours_check(interval * 45, 0);
+                /* RTT sub-TLV. */
+                if(len > 10 + rc)
+                    parse_ihu_subtlv(message + 8 + rc, len - 6 - rc,
+                                     &hello_send_us, &hello_rtt_receive_time);
             }
         } else if(type == MESSAGE_ROUTER_ID) {
-            if(len < 10) {
-                have_router_id = 0;
-                goto fail;
-            }
             memcpy(router_id, message + 4, 8);
             have_router_id = 1;
             debugf(BABEL_DEBUG_COMMON,"Received router-id %s from %s on %s.",
@@ -268,11 +444,6 @@ parse_packet(const unsigned char *from, struct interface *ifp,
         } else if(type == MESSAGE_NH) {
             unsigned char nh[16];
             int rc;
-            if(len < 2) {
-                have_v4_nh = 0;
-                have_v6_nh = 0;
-                goto fail;
-            }
             rc = network_address(message[2], message + 4, len - 2,
                                  nh);
             if(rc < 0) {
@@ -293,18 +464,14 @@ 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;
-            if(len < 10) {
-                if(len < 2 || message[3] & 0x80)
-                    have_v4_prefix = have_v6_prefix = 0;
-                goto fail;
-            }
+            int rc, parsed_len;
             DO_NTOHS(interval, message + 6);
             DO_NTOHS(seqno, message + 8);
             DO_NTOHS(metric, message + 10);
             if(message[5] == 0 ||
-               (message[3] == 1 ? have_v4_prefix : have_v6_prefix))
+               (message[2] == 1 ? have_v4_prefix : have_v6_prefix))
                 rc = network_prefix(message[2], message[4], message[5],
                                     message + 12,
                                     message[2] == 1 ? v4_prefix : v6_prefix,
@@ -316,6 +483,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);
 
@@ -338,7 +506,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
                 have_router_id = 1;
             }
             if(!have_router_id && message[2] != 0) {
-                fprintf(stderr, "Received prefix with no router id.\n");
+                zlog_err("Received prefix with no router id.");
                 goto fail;
             }
             debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.",
@@ -349,8 +517,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
 
             if(message[2] == 0) {
                 if(metric < 0xFFFF) {
-                    fprintf(stderr,
-                            "Received wildcard update with finite metric.\n");
+                    zlog_err("Received wildcard update with finite metric.");
                     goto done;
                 }
                 retract_neighbour_routes(neigh);
@@ -370,12 +537,30 @@ parse_packet(const unsigned char *from, struct interface *ifp,
                     goto done;
             }
 
+            if((babel_get_if_nfo(ifp)->flags & BABEL_IF_FARAWAY)) {
+                channels[0] = 0;
+            } else {
+                /* This will be overwritten by parse_update_subtlv 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_update_subtlv(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;
-            if(len < 2) goto fail;
             rc = network_prefix(message[2], message[3], 0,
                                 message + 4, NULL, len - 2, prefix);
             if(rc < 0) goto fail;
@@ -384,10 +569,18 @@ 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 *neigh_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(neigh_ifp->last_update_time <
+                   (time_t)(babel_now.tv_sec -
+                            MAX(neigh_ifp->hello_interval / 100, 1)))
+                    send_update(neigh->ifp, 0, NULL, 0);
             } else {
                 send_update(neigh->ifp, 0, prefix, plen);
             }
@@ -395,7 +588,6 @@ parse_packet(const unsigned char *from, struct interface *ifp,
             unsigned char prefix[16], plen;
             unsigned short seqno;
             int rc;
-            if(len < 14) goto fail;
             DO_NTOHS(seqno, message + 4);
             rc = network_prefix(message[2], message[3], 0,
                                 message + 16, NULL, len - 14, prefix);
@@ -417,10 +609,48 @@ parse_packet(const unsigned char *from, struct interface *ifp,
         continue;
 
     fail:
-        fprintf(stderr, "Couldn't parse packet (%d, %d) from %s on %s.\n",
-                message[0], message[1], format_address(from), ifp->name);
+        zlog_err("Couldn't parse packet (%d, %d) from %s on %s.",
+                 message[0], message[1], format_address(from), ifp->name);
         goto done;
     }
+
+    /* We can calculate the RTT to this neighbour. */
+    if(have_hello_rtt && hello_send_us && hello_rtt_receive_time) {
+        int remote_waiting_us, local_waiting_us;
+        unsigned int rtt, smoothed_rtt;
+        unsigned int old_rttcost;
+        int changed = 0;
+        remote_waiting_us = neigh->hello_send_us - hello_rtt_receive_time;
+        local_waiting_us = time_us(neigh->hello_rtt_receive_time) -
+            hello_send_us;
+
+        /* Sanity checks (validity window of 10 minutes). */
+        if(remote_waiting_us < 0 || local_waiting_us < 0 ||
+           remote_waiting_us > 600000000 || local_waiting_us > 600000000)
+            return;
+
+        rtt = MAX(0, local_waiting_us - remote_waiting_us);
+        debugf(BABEL_DEBUG_COMMON, "RTT to %s on %s sample result: %d us.\n",
+               format_address(from), ifp->name, rtt);
+
+        old_rttcost = neighbour_rttcost(neigh);
+        if (valid_rtt(neigh)) {
+            /* Running exponential average. */
+            smoothed_rtt = (babel_ifp->rtt_decay * rtt +
+                           (256 - babel_ifp->rtt_decay) * neigh->rtt);
+            /* Rounding (up or down) to get closer to the sample. */
+            neigh->rtt = (neigh->rtt >= rtt) ? smoothed_rtt / 256 :
+                (smoothed_rtt + 255) / 256;
+        } else {
+            /* We prefer to be conservative with new neighbours
+               (higher RTT) */
+            assert(rtt <= 0x7FFFFFFF);
+            neigh->rtt = 2*rtt;
+        }
+        changed = (neighbour_rttcost(neigh) == old_rttcost ? 0 : 1);
+        update_neighbour_metric(neigh, changed);
+        neigh->rtt_time = babel_now;
+    }
     return;
 }
 
@@ -450,6 +680,31 @@ check_bucket(struct interface *ifp)
     }
 }
 
+static int
+fill_rtt_message(struct interface *ifp)
+{
+    babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
+    if((babel_ifp->flags & BABEL_IF_TIMESTAMPS) &&
+       (babel_ifp->buffered_hello >= 0)) {
+        if(babel_ifp->sendbuf[babel_ifp->buffered_hello + 8] == SUBTLV_PADN &&
+           babel_ifp->sendbuf[babel_ifp->buffered_hello + 9] == 4) {
+            unsigned int time;
+            /* Change the type of sub-TLV. */
+            babel_ifp->sendbuf[babel_ifp->buffered_hello + 8] =
+                SUBTLV_TIMESTAMP;
+            gettime(&babel_now);
+            time = time_us(babel_now);
+            DO_HTONL(babel_ifp->sendbuf + babel_ifp->buffered_hello + 10, time);
+            return 1;
+        } else {
+            zlog_err("No space left for timestamp sub-TLV "
+                     "(this shouldn't happen)");
+            return -1;
+        }
+    }
+    return 0;
+}
+
 void
 flushbuf(struct interface *ifp)
 {
@@ -471,6 +726,7 @@ flushbuf(struct interface *ifp)
             sin6.sin6_port = htons(protocol_port);
             sin6.sin6_scope_id = ifp->ifindex;
             DO_HTONS(packet_header + 2, babel_ifp->buffered);
+            fill_rtt_message(ifp);
             rc = babel_send(protocol_socket,
                             packet_header, sizeof(packet_header),
                             babel_ifp->sendbuf, babel_ifp->buffered,
@@ -478,13 +734,13 @@ flushbuf(struct interface *ifp)
             if(rc < 0)
                 zlog_err("send: %s", safe_strerror(errno));
         } else {
-            fprintf(stderr, "Warning: bucket full, dropping packet to %s.\n",
-                    ifp->name);
+            zlog_err("Warning: bucket full, dropping packet to %s.",
+                     ifp->name);
         }
     }
     VALGRIND_MAKE_MEM_UNDEFINED(babel_ifp->sendbuf, babel_ifp->bufsize);
     babel_ifp->buffered = 0;
-    babel_ifp->have_buffered_hello = 0;
+    babel_ifp->buffered_hello = -1;
     babel_ifp->have_buffered_id = 0;
     babel_ifp->have_buffered_nh = 0;
     babel_ifp->have_buffered_prefix = 0;
@@ -571,6 +827,14 @@ accumulate_short(struct interface *ifp, unsigned short value)
     babel_ifp->buffered += 2;
 }
 
+static void
+accumulate_int(struct interface *ifp, unsigned int value)
+{
+    babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
+    DO_HTONL(babel_ifp->sendbuf + babel_ifp->buffered, value);
+    babel_ifp->buffered += 4;
+}
+
 static void
 accumulate_bytes(struct interface *ifp,
                  const unsigned char *value, unsigned len)
@@ -625,6 +889,13 @@ accumulate_unicast_short(struct neighbour *neigh, unsigned short value)
     unicast_buffered += 2;
 }
 
+static void
+accumulate_unicast_int(struct neighbour *neigh, unsigned int value)
+{
+    DO_HTONL(unicast_buffer + unicast_buffered, value);
+    unicast_buffered += 4;
+}
+
 static void
 accumulate_unicast_bytes(struct neighbour *neigh,
                          const unsigned char *value, unsigned len)
@@ -652,7 +923,7 @@ send_hello_noupdate(struct interface *ifp, unsigned interval)
     babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
     /* This avoids sending multiple hellos in a single packet, which breaks
        link quality estimation. */
-    if(babel_ifp->have_buffered_hello)
+    if(babel_ifp->buffered_hello >= 0)
         flushbuf(ifp);
 
     babel_ifp->hello_seqno = seqno_plus(babel_ifp->hello_seqno, 1);
@@ -664,12 +935,21 @@ send_hello_noupdate(struct interface *ifp, unsigned interval)
     debugf(BABEL_DEBUG_COMMON,"Sending hello %d (%d) to %s.",
            babel_ifp->hello_seqno, interval, ifp->name);
 
-    start_message(ifp, MESSAGE_HELLO, 6);
+    start_message(ifp, MESSAGE_HELLO,
+                  (babel_ifp->flags & BABEL_IF_TIMESTAMPS) ? 12 : 6);
+    babel_ifp->buffered_hello = babel_ifp->buffered - 2;
     accumulate_short(ifp, 0);
     accumulate_short(ifp, babel_ifp->hello_seqno);
     accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval);
-    end_message(ifp, MESSAGE_HELLO, 6);
-    babel_ifp->have_buffered_hello = 1;
+    if(babel_ifp->flags & BABEL_IF_TIMESTAMPS) {
+        /* Sub-TLV containing the local time of emission. We use a
+           Pad4 sub-TLV, which we'll fill just before sending. */
+        accumulate_byte(ifp, SUBTLV_PADN);
+        accumulate_byte(ifp, 4);
+        accumulate_int(ifp, 0);
+    }
+    end_message(ifp, MESSAGE_HELLO,
+                (babel_ifp->flags & BABEL_IF_TIMESTAMPS) ? 12 : 6);
 }
 
 void
@@ -706,6 +986,7 @@ flush_unicast(int dofree)
         sin6.sin6_port = htons(protocol_port);
         sin6.sin6_scope_id = unicast_neighbour->ifp->ifindex;
         DO_HTONS(packet_header + 2, unicast_buffered);
+        fill_rtt_message(unicast_neighbour->ifp);
         rc = babel_send(protocol_socket,
                         packet_header, sizeof(packet_header),
                         unicast_buffer, unicast_buffered,
@@ -713,11 +994,9 @@ flush_unicast(int dofree)
         if(rc < 0)
             zlog_err("send(unicast): %s", safe_strerror(errno));
     } else {
-        fprintf(stderr,
-                "Warning: bucket full, dropping unicast packet"
-                "to %s if %s.\n",
-                format_address(unicast_neighbour->address),
-                unicast_neighbour->ifp->name);
+        zlog_err("Warning: bucket full, dropping unicast packet to %s if %s.",
+                 format_address(unicast_neighbour->address),
+                 unicast_neighbour->ifp->name);
     }
 
  done:
@@ -736,12 +1015,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;
@@ -798,7 +1084,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);
@@ -807,7 +1094,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);
@@ -854,15 +1148,15 @@ flushupdates(struct interface *ifp)
 {
     babel_interface_nfo *babel_ifp = NULL;
     struct xroute *xroute;
-    struct route *route;
+    struct babel_route *route;
     const unsigned char *last_prefix = NULL;
     unsigned char last_plen = 0xFF;
     int i;
 
     if(ifp == NULL) {
-      struct interface *ifp_aux;
-      struct listnode *linklist_node = NULL;
-        FOR_ALL_INTERFACES(ifp_aux, linklist_node)
+       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+        struct interface *ifp_aux;
+        FOR_ALL_INTERFACES(vrf, ifp_aux)
             flushupdates(ifp_aux);
         return;
     }
@@ -896,9 +1190,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. */
@@ -915,22 +1206,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;
@@ -938,7 +1258,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);
@@ -973,12 +1293,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;
             }
@@ -999,13 +1324,12 @@ 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;
-      struct listnode *linklist_node = NULL;
-        struct route *route;
-        FOR_ALL_INTERFACES(ifp_aux, linklist_node)
+       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+        struct interface *ifp_aux;
+        struct babel_route *route;
+        FOR_ALL_INTERFACES(vrf, ifp_aux)
             send_update(ifp_aux, urgent, prefix, plen);
         if(prefix) {
             /* Since flushupdates only deals with non-wildcard interfaces, we
@@ -1023,24 +1347,27 @@ send_update(struct interface *ifp, int urgent,
 
     babel_ifp = babel_get_if_nfo(ifp);
     if(prefix) {
-        if(!parasitic || find_xroute(prefix, plen)) {
-            debugf(BABEL_DEBUG_COMMON,"Sending update to %s for %s.",
-                   ifp->name, format_prefix(prefix, plen));
-            buffer_update(ifp, prefix, plen);
-        }
+        debugf(BABEL_DEBUG_COMMON,"Sending update to %s for %s.",
+               ifp->name, format_prefix(prefix, plen));
+        buffer_update(ifp, prefix, plen);
     } else {
-        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);
+        struct route_stream *routes = NULL;
+        send_self_update(ifp);
+        debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", ifp->name);
+        routes = route_stream(1);
+        if(routes) {
+            while(1) {
+                struct babel_route *route = route_stream_next(routes);
+                if(route == NULL)
+                    break;
+                buffer_update(ifp, route->src->prefix, route->src->plen);
             }
+            route_stream_done(routes);
+        } else {
+            zlog_err("Couldn't allocate route stream.");
         }
         set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
+        babel_ifp->last_update_time = babel_now.tv_sec;
     }
     schedule_update_flush(ifp, urgent);
 }
@@ -1049,17 +1376,10 @@ void
 send_update_resend(struct interface *ifp,
                    const unsigned char *prefix, unsigned char plen)
 {
-    int delay;
-
     assert(prefix != NULL);
 
     send_update(ifp, 1, prefix, plen);
-
-    delay = 2000;
-    delay = MIN(delay, wireless_hello_interval / 2);
-    delay = MIN(delay, wired_hello_interval / 2);
-    delay = MAX(delay, 10);
-    record_resend(RESEND_UPDATE, prefix, plen, 0, 0, NULL, delay);
+    record_resend(RESEND_UPDATE, prefix, plen, 0, NULL, NULL, resend_delay);
 }
 
 void
@@ -1067,9 +1387,9 @@ send_wildcard_retraction(struct interface *ifp)
 {
     babel_interface_nfo *babel_ifp = NULL;
     if(ifp == NULL) {
-      struct interface *ifp_aux;
-      struct listnode *linklist_node = NULL;
-        FOR_ALL_INTERFACES(ifp_aux, linklist_node)
+       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+        struct interface *ifp_aux;
+        FOR_ALL_INTERFACES(vrf, ifp_aux)
             send_wildcard_retraction(ifp_aux);
         return;
     }
@@ -1095,18 +1415,16 @@ void
 update_myseqno()
 {
     myseqno = seqno_plus(myseqno, 1);
-    seqno_time = babel_now;
 }
 
 void
 send_self_update(struct interface *ifp)
 {
-    int i;
-
+    struct xroute_stream *xroutes;
     if(ifp == NULL) {
-      struct interface *ifp_aux;
-      struct listnode *linklist_node = NULL;
-        FOR_ALL_INTERFACES(ifp_aux, linklist_node) {
+       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+        struct interface *ifp_aux;
+        FOR_ALL_INTERFACES(vrf, ifp_aux) {
             if(!if_up(ifp_aux))
                 continue;
             send_self_update(ifp_aux);
@@ -1114,10 +1432,17 @@ send_self_update(struct interface *ifp)
         return;
     }
 
-    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);
+    debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name);
+    xroutes = xroute_stream();
+    if(xroutes) {
+        while(1) {
+            struct xroute *xroute = xroute_stream_next(xroutes);
+            if(xroute == NULL) break;
+            send_update(ifp, 0, xroute->prefix, xroute->plen);
+        }
+        xroute_stream_done(xroutes);
+    } else {
+        zlog_err("Couldn't allocate xroute stream.");
     }
 }
 
@@ -1127,11 +1452,13 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
     babel_interface_nfo *babel_ifp = NULL;
     int rxcost, interval;
     int ll;
+    int send_rtt_data;
+    int msglen;
 
     if(neigh == NULL && ifp == NULL) {
-      struct interface *ifp_aux;
-      struct listnode *linklist_node = NULL;
-        FOR_ALL_INTERFACES(ifp_aux, linklist_node) {
+       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+        struct interface *ifp_aux;
+        FOR_ALL_INTERFACES(vrf, ifp_aux) {
             if(if_up(ifp_aux))
                 continue;
             send_ihu(NULL, ifp_aux);
@@ -1172,8 +1499,22 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
 
     ll = linklocal(neigh->address);
 
+    if((babel_ifp->flags & BABEL_IF_TIMESTAMPS) && neigh->hello_send_us
+       /* Checks whether the RTT data is not too old to be sent. */
+       && timeval_minus_msec(&babel_now,
+                             &neigh->hello_rtt_receive_time) < 1000000) {
+        send_rtt_data = 1;
+    } else {
+        neigh->hello_send_us = 0;
+        send_rtt_data = 0;
+    }
+
+    /* The length depends on the format of the address, and then an
+       optional 10-bytes sub-TLV for timestamps (used to compute a RTT). */
+    msglen = (ll ? 14 : 22) + (send_rtt_data ? 10 : 0);
+
     if(unicast_neighbour != neigh) {
-        start_message(ifp, MESSAGE_IHU, ll ? 14 : 22);
+        start_message(ifp, MESSAGE_IHU, msglen);
         accumulate_byte(ifp, ll ? 3 : 2);
         accumulate_byte(ifp, 0);
         accumulate_short(ifp, rxcost);
@@ -1182,10 +1523,16 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
             accumulate_bytes(ifp, neigh->address + 8, 8);
         else
             accumulate_bytes(ifp, neigh->address, 16);
-        end_message(ifp, MESSAGE_IHU, ll ? 14 : 22);
+        if (send_rtt_data) {
+            accumulate_byte(ifp, SUBTLV_TIMESTAMP);
+            accumulate_byte(ifp, 8);
+            accumulate_int(ifp, neigh->hello_send_us);
+            accumulate_int(ifp, time_us(neigh->hello_rtt_receive_time));
+        }
+        end_message(ifp, MESSAGE_IHU, msglen);
     } else {
         int rc;
-        rc = start_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22);
+        rc = start_unicast_message(neigh, MESSAGE_IHU, msglen);
         if(rc < 0) return;
         accumulate_unicast_byte(neigh, ll ? 3 : 2);
         accumulate_unicast_byte(neigh, 0);
@@ -1195,7 +1542,14 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
             accumulate_unicast_bytes(neigh, neigh->address + 8, 8);
         else
             accumulate_unicast_bytes(neigh, neigh->address, 16);
-        end_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22);
+        if (send_rtt_data) {
+            accumulate_unicast_byte(neigh, SUBTLV_TIMESTAMP);
+            accumulate_unicast_byte(neigh, 8);
+            accumulate_unicast_int(neigh, neigh->hello_send_us);
+            accumulate_unicast_int(neigh,
+                                   time_us(neigh->hello_rtt_receive_time));
+        }
+        end_unicast_message(neigh, MESSAGE_IHU, msglen);
     }
 }
 
@@ -1216,13 +1570,12 @@ void
 send_request(struct interface *ifp,
              const unsigned char *prefix, unsigned char plen)
 {
-    babel_interface_nfo *babel_ifp = NULL;
-    int v4, len;
+    int v4, pb, len;
 
     if(ifp == NULL) {
-      struct interface *ifp_aux;
-      struct listnode *linklist_node = NULL;
-        FOR_ALL_INTERFACES(ifp_aux, linklist_node) {
+       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+        struct interface *ifp_aux;
+        FOR_ALL_INTERFACES(vrf, ifp_aux) {
             if(if_up(ifp_aux))
                 continue;
             send_request(ifp_aux, prefix, plen);
@@ -1236,20 +1589,20 @@ send_request(struct interface *ifp,
     if(!if_up(ifp))
         return;
 
-    babel_ifp = babel_get_if_nfo(ifp);
     debugf(BABEL_DEBUG_COMMON,"sending request to %s for %s.",
            ifp->name, prefix ? format_prefix(prefix, plen) : "any");
     v4 = plen >= 96 && v4mapped(prefix);
-    len = !prefix ? 2 : v4 ? 6 : 18;
+    pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8;
+    len = !prefix ? 2 : 2 + pb;
 
     start_message(ifp, MESSAGE_REQUEST, len);
     accumulate_byte(ifp, !prefix ? 0 : v4 ? 1 : 2);
     accumulate_byte(ifp, !prefix ? 0 : v4 ? plen - 96 : plen);
     if(prefix) {
         if(v4)
-            accumulate_bytes(ifp, prefix + 12, 4);
+            accumulate_bytes(ifp, prefix + 12, pb);
         else
-            accumulate_bytes(ifp, prefix, 16);
+            accumulate_bytes(ifp, prefix, pb);
     }
     end_message(ifp, MESSAGE_REQUEST, len);
 }
@@ -1258,7 +1611,7 @@ void
 send_unicast_request(struct neighbour *neigh,
                      const unsigned char *prefix, unsigned char plen)
 {
-    int rc, v4, len;
+    int rc, v4, pb, len;
 
     /* make sure any buffered updates go out before this request. */
     flushupdates(neigh->ifp);
@@ -1267,7 +1620,8 @@ send_unicast_request(struct neighbour *neigh,
            format_address(neigh->address),
            prefix ? format_prefix(prefix, plen) : "any");
     v4 = plen >= 96 && v4mapped(prefix);
-    len = !prefix ? 2 : v4 ? 6 : 18;
+    pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8;
+    len = !prefix ? 2 : 2 + pb;
 
     rc = start_unicast_message(neigh, MESSAGE_REQUEST, len);
     if(rc < 0) return;
@@ -1275,9 +1629,9 @@ send_unicast_request(struct neighbour *neigh,
     accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? plen - 96 : plen);
     if(prefix) {
         if(v4)
-            accumulate_unicast_bytes(neigh, prefix + 12, 4);
+            accumulate_unicast_bytes(neigh, prefix + 12, pb);
         else
-            accumulate_unicast_bytes(neigh, prefix, 16);
+            accumulate_unicast_bytes(neigh, prefix, pb);
     }
     end_unicast_message(neigh, MESSAGE_REQUEST, len);
 }
@@ -1288,16 +1642,15 @@ send_multihop_request(struct interface *ifp,
                       unsigned short seqno, const unsigned char *id,
                       unsigned short hop_count)
 {
-    babel_interface_nfo *babel_ifp = NULL;
     int v4, pb, len;
 
     /* Make sure any buffered updates go out before this request. */
     flushupdates(ifp);
 
     if(ifp == NULL) {
-      struct interface *ifp_aux;
-      struct listnode *linklist_node = NULL;
-        FOR_ALL_INTERFACES(ifp_aux, linklist_node) {
+       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+        struct interface *ifp_aux;
+        FOR_ALL_INTERFACES(vrf, ifp_aux) {
             if(!if_up(ifp_aux))
                 continue;
             send_multihop_request(ifp_aux, prefix, plen, seqno, id, hop_count);
@@ -1308,7 +1661,6 @@ send_multihop_request(struct interface *ifp,
     if(!if_up(ifp))
         return;
 
-    babel_ifp = babel_get_if_nfo(ifp);
     debugf(BABEL_DEBUG_COMMON,"Sending request (%d) on %s for %s.",
            hop_count, ifp->name, format_prefix(prefix, plen));
     v4 = plen >= 96 && v4mapped(prefix);
@@ -1371,19 +1723,13 @@ send_request_resend(struct neighbour *neigh,
                     const unsigned char *prefix, unsigned char plen,
                     unsigned short seqno, unsigned char *id)
 {
-    int delay;
-
     if(neigh)
         send_unicast_multihop_request(neigh, prefix, plen, seqno, id, 127);
     else
         send_multihop_request(NULL, prefix, plen, seqno, id, 127);
 
-    delay = 2000;
-    delay = MIN(delay, wireless_hello_interval / 2);
-    delay = MIN(delay, wired_hello_interval / 2);
-    delay = MAX(delay, 10);
     record_resend(RESEND_REQUEST, prefix, plen, seqno, id,
-                  neigh ? neigh->ifp : NULL, delay);
+                  neigh ? neigh->ifp : NULL, resend_delay);
 }
 
 void
@@ -1392,7 +1738,7 @@ handle_request(struct neighbour *neigh, const unsigned char *prefix,
                unsigned short seqno, const unsigned char *id)
 {
     struct xroute *xroute;
-    struct route *route;
+    struct babel_route *route;
     struct neighbour *successor = NULL;
 
     xroute = find_xroute(prefix, plen);
@@ -1438,7 +1784,7 @@ handle_request(struct neighbour *neigh, const unsigned char *prefix,
     if(!successor || successor == neigh) {
         /* We were about to forward a request to its requestor.  Try to
            find a different neighbour to forward the request to. */
-        struct route *other_route;
+        struct babel_route *other_route;
 
         other_route = find_best_route(prefix, plen, 0, neigh);
         if(other_route && route_metric(other_route) < INFINITY)