Commit 5afde873 authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Merge branch 'rfc6126bis'

parents 8627b6fc 3a4fbbf0
...@@ -582,8 +582,9 @@ main(int argc, char **argv) ...@@ -582,8 +582,9 @@ main(int argc, char **argv)
send_hello(ifp); send_hello(ifp);
send_wildcard_retraction(ifp); send_wildcard_retraction(ifp);
send_self_update(ifp); send_self_update(ifp);
send_multicast_request(ifp, NULL, 0, NULL, 0);
flushupdates(ifp); flushupdates(ifp);
flushbuf(ifp); flushbuf(&ifp->buf);
} }
debugf("Entering main loop.\n"); debugf("Entering main loop.\n");
...@@ -591,6 +592,7 @@ main(int argc, char **argv) ...@@ -591,6 +592,7 @@ main(int argc, char **argv)
while(1) { while(1) {
struct timeval tv; struct timeval tv;
fd_set readfds; fd_set readfds;
struct neighbour *neigh;
gettime(&now); gettime(&now);
...@@ -603,12 +605,14 @@ main(int argc, char **argv) ...@@ -603,12 +605,14 @@ main(int argc, char **argv)
FOR_ALL_INTERFACES(ifp) { FOR_ALL_INTERFACES(ifp) {
if(!if_up(ifp)) if(!if_up(ifp))
continue; continue;
timeval_min(&tv, &ifp->flush_timeout); timeval_min(&tv, &ifp->buf.timeout);
timeval_min(&tv, &ifp->hello_timeout); timeval_min(&tv, &ifp->hello_timeout);
timeval_min(&tv, &ifp->update_timeout); timeval_min(&tv, &ifp->update_timeout);
timeval_min(&tv, &ifp->update_flush_timeout); timeval_min(&tv, &ifp->update_flush_timeout);
} }
timeval_min(&tv, &unicast_flush_timeout); FOR_ALL_NEIGHBOURS(neigh) {
timeval_min(&tv, &neigh->buf.timeout);
}
FD_ZERO(&readfds); FD_ZERO(&readfds);
if(timeval_compare(&tv, &now) > 0) { if(timeval_compare(&tv, &now) > 0) {
int maxfd = 0; int maxfd = 0;
...@@ -770,17 +774,22 @@ main(int argc, char **argv) ...@@ -770,17 +774,22 @@ main(int argc, char **argv)
do_resend(); do_resend();
} }
if(unicast_flush_timeout.tv_sec != 0) {
if(timeval_compare(&now, &unicast_flush_timeout) >= 0)
flush_unicast(1);
}
FOR_ALL_INTERFACES(ifp) { FOR_ALL_INTERFACES(ifp) {
if(!if_up(ifp)) if(!if_up(ifp))
continue; continue;
if(ifp->flush_timeout.tv_sec != 0) { if(ifp->buf.timeout.tv_sec != 0) {
if(timeval_compare(&now, &ifp->flush_timeout) >= 0) if(timeval_compare(&now, &ifp->buf.timeout) >= 0) {
flushbuf(ifp); flushupdates(ifp);
flushbuf(&ifp->buf);
}
}
}
FOR_ALL_NEIGHBOURS(neigh) {
if(neigh->buf.timeout.tv_sec != 0) {
if(timeval_compare(&now, &neigh->buf.timeout) >= 0) {
flushbuf(&neigh->buf);
}
} }
} }
...@@ -803,8 +812,8 @@ main(int argc, char **argv) ...@@ -803,8 +812,8 @@ main(int argc, char **argv)
send_wildcard_retraction(ifp); send_wildcard_retraction(ifp);
/* Make sure that we expire quickly from our neighbours' /* Make sure that we expire quickly from our neighbours'
association caches. */ association caches. */
send_hello_noupdate(ifp, 10); send_hello_noihu(ifp, 10);
flushbuf(ifp); flushbuf(&ifp->buf);
usleep(roughly(1000)); usleep(roughly(1000));
gettime(&now); gettime(&now);
} }
...@@ -813,8 +822,8 @@ main(int argc, char **argv) ...@@ -813,8 +822,8 @@ main(int argc, char **argv)
continue; continue;
/* Make sure they got it. */ /* Make sure they got it. */
send_wildcard_retraction(ifp); send_wildcard_retraction(ifp);
send_hello_noupdate(ifp, 1); send_hello_noihu(ifp, 1);
flushbuf(ifp); flushbuf(&ifp->buf);
usleep(roughly(10000)); usleep(roughly(10000));
gettime(&now); gettime(&now);
interface_up(ifp, 0); interface_up(ifp, 0);
...@@ -1113,7 +1122,7 @@ dump_tables(FILE *out) ...@@ -1113,7 +1122,7 @@ dump_tables(FILE *out)
FOR_ALL_NEIGHBOURS(neigh) { FOR_ALL_NEIGHBOURS(neigh) {
fprintf(out, "Neighbour %s dev %s reach %04x ureach %04x " fprintf(out, "Neighbour %s dev %s reach %04x ureach %04x "
"rxcost %d txcost %d rtt %s rttcost %d chan %d%s.\n", "rxcost %u txcost %d rtt %s rttcost %u chan %d%s.\n",
format_address(neigh->address), format_address(neigh->address),
neigh->ifp->name, neigh->ifp->name,
neigh->hello.reach, neigh->hello.reach,
......
...@@ -24,6 +24,8 @@ THE SOFTWARE. ...@@ -24,6 +24,8 @@ THE SOFTWARE.
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <assert.h> #include <assert.h>
#ifdef __linux #ifdef __linux
...@@ -560,6 +562,12 @@ parse_anonymous_ifconf(int c, gnc_t gnc, void *closure, ...@@ -560,6 +562,12 @@ parse_anonymous_ifconf(int c, gnc_t gnc, void *closure,
if(c < -1) if(c < -1)
goto error; goto error;
if_conf->faraway = v; if_conf->faraway = v;
} else if(strcmp(token, "unicast") == 0) {
int v;
c = getbool(c, &v, gnc, closure);
if(c < -1)
goto error;
if_conf->unicast = v;
} else if(strcmp(token, "link-quality") == 0) { } else if(strcmp(token, "link-quality") == 0) {
int v; int v;
c = getbool(c, &v, gnc, closure); c = getbool(c, &v, gnc, closure);
...@@ -711,6 +719,7 @@ merge_ifconf(struct interface_conf *dest, ...@@ -711,6 +719,7 @@ merge_ifconf(struct interface_conf *dest,
MERGE(split_horizon); MERGE(split_horizon);
MERGE(lq); MERGE(lq);
MERGE(faraway); MERGE(faraway);
MERGE(unicast);
MERGE(channel); MERGE(channel);
MERGE(enable_timestamps); MERGE(enable_timestamps);
MERGE(rfc6126); MERGE(rfc6126);
......
...@@ -25,6 +25,8 @@ THE SOFTWARE. ...@@ -25,6 +25,8 @@ THE SOFTWARE.
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> #include <sys/time.h>
#include "babeld.h" #include "babeld.h"
......
...@@ -80,8 +80,6 @@ add_interface(char *ifname, struct interface_conf *if_conf) ...@@ -80,8 +80,6 @@ add_interface(char *ifname, struct interface_conf *if_conf)
strncpy(ifp->name, ifname, IF_NAMESIZE); strncpy(ifp->name, ifname, IF_NAMESIZE);
ifp->conf = if_conf ? if_conf : default_interface_conf; ifp->conf = if_conf ? if_conf : default_interface_conf;
ifp->bucket_time = now.tv_sec;
ifp->bucket = BUCKET_TOKENS_MAX;
ifp->hello_seqno = (random() & 0xFFFF); ifp->hello_seqno = (random() & 0xFFFF);
if(interfaces == NULL) if(interfaces == NULL)
...@@ -132,14 +130,14 @@ flush_interface(char *ifname) ...@@ -132,14 +130,14 @@ flush_interface(char *ifname)
/* This should be no more than half the hello interval, so that hellos /* This should be no more than half the hello interval, so that hellos
aren't sent late. The result is in milliseconds. */ aren't sent late. The result is in milliseconds. */
unsigned unsigned
jitter(struct interface *ifp, int urgent) jitter(struct buffered *buf, int urgent)
{ {
unsigned interval = ifp->hello_interval; unsigned interval = buf->flush_interval;
if(urgent) if(urgent)
interval = MIN(interval, 100); interval = MIN(interval, 20);
else else
interval = MIN(interval, 4000); interval = MIN(interval, 2000);
return roughly(interval) / 4; return roughly(interval / 2);
} }
unsigned unsigned
...@@ -297,14 +295,20 @@ interface_up(struct interface *ifp, int up) ...@@ -297,14 +295,20 @@ interface_up(struct interface *ifp, int up)
rc = kernel_setup_interface(1, ifp->name, ifp->ifindex); rc = kernel_setup_interface(1, ifp->name, ifp->ifindex);
if(rc < 0) { if(rc < 0) {
fprintf(stderr, "kernel_setup_interface(%s, %d) failed.\n", fprintf(stderr, "kernel_setup_interface(%s, %u) failed.\n",
ifp->name, ifp->ifindex); ifp->name, ifp->ifindex);
goto fail; goto fail;
} }
memset(&ifp->buf.sin6, 0, sizeof(ifp->buf.sin6));
ifp->buf.sin6.sin6_family = AF_INET6;
memcpy(&ifp->buf.sin6.sin6_addr, protocol_group, 16);
ifp->buf.sin6.sin6_port = htons(protocol_port);
ifp->buf.sin6.sin6_scope_id = ifp->ifindex;
mtu = kernel_interface_mtu(ifp->name, ifp->ifindex); mtu = kernel_interface_mtu(ifp->name, ifp->ifindex);
if(mtu < 0) { if(mtu < 0) {
fprintf(stderr, "Warning: couldn't get MTU of interface %s (%d).\n", fprintf(stderr, "Warning: couldn't get MTU of interface %s (%u).\n",
ifp->name, ifp->ifindex); ifp->name, ifp->ifindex);
mtu = 1280; mtu = 1280;
} }
...@@ -314,27 +318,27 @@ interface_up(struct interface *ifp, int up) ...@@ -314,27 +318,27 @@ interface_up(struct interface *ifp, int up)
/* In IPv6, the minimum MTU is 1280, and every host must be able /* In IPv6, the minimum MTU is 1280, and every host must be able
to reassemble up to 1500 bytes, but I'd rather not rely on this. */ to reassemble up to 1500 bytes, but I'd rather not rely on this. */
if(mtu < 128) { if(mtu < 128) {
fprintf(stderr, "Suspiciously low MTU %d on interface %s (%d).\n", fprintf(stderr, "Suspiciously low MTU %d on interface %s (%u).\n",
mtu, ifp->name, ifp->ifindex); mtu, ifp->name, ifp->ifindex);
mtu = 128; mtu = 128;
} }
if(ifp->sendbuf) if(ifp->buf.buf)
free(ifp->sendbuf); free(ifp->buf.buf);
/* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */ /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
ifp->bufsize = mtu - sizeof(packet_header) - 60; ifp->buf.size = mtu - sizeof(packet_header) - 60;
ifp->sendbuf = malloc(ifp->bufsize); ifp->buf.buf = malloc(ifp->buf.size);
if(ifp->sendbuf == NULL) { if(ifp->buf.buf == NULL) {
fprintf(stderr, "Couldn't allocate sendbuf.\n"); fprintf(stderr, "Couldn't allocate sendbuf.\n");
ifp->bufsize = 0; ifp->buf.size = 0;
goto fail; goto fail;
} }
rc = resize_receive_buffer(mtu); rc = resize_receive_buffer(mtu);
if(rc < 0) if(rc < 0)
fprintf(stderr, "Warning: couldn't resize " fprintf(stderr, "Warning: couldn't resize "
"receive buffer for interface %s (%d) (%d bytes).\n", "receive buffer for interface %s (%u) (%d bytes).\n",
ifp->name, ifp->ifindex, mtu); ifp->name, ifp->ifindex, mtu);
type = IF_CONF(ifp, type); type = IF_CONF(ifp, type);
...@@ -345,7 +349,7 @@ interface_up(struct interface *ifp, int up) ...@@ -345,7 +349,7 @@ interface_up(struct interface *ifp, int up)
rc = kernel_interface_wireless(ifp->name, ifp->ifindex); rc = kernel_interface_wireless(ifp->name, ifp->ifindex);
if(rc < 0) { if(rc < 0) {
fprintf(stderr, fprintf(stderr,
"Warning: couldn't determine whether %s (%d) " "Warning: couldn't determine whether %s (%u) "
"is a wireless interface.\n", "is a wireless interface.\n",
ifp->name, ifp->ifindex); ifp->name, ifp->ifindex);
} else if(rc) { } else if(rc) {
...@@ -387,6 +391,9 @@ interface_up(struct interface *ifp, int up) ...@@ -387,6 +391,9 @@ interface_up(struct interface *ifp, int up)
if(IF_CONF(ifp, faraway) == CONFIG_YES) if(IF_CONF(ifp, faraway) == CONFIG_YES)
ifp->flags |= IF_FARAWAY; ifp->flags |= IF_FARAWAY;
if(IF_CONF(ifp, unicast) == CONFIG_YES)
ifp->flags |= IF_UNICAST;
if(IF_CONF(ifp, hello_interval) > 0) if(IF_CONF(ifp, hello_interval) > 0)
ifp->hello_interval = IF_CONF(ifp, hello_interval); ifp->hello_interval = IF_CONF(ifp, hello_interval);
else if(type == IF_TYPE_WIRELESS) else if(type == IF_TYPE_WIRELESS)
...@@ -399,6 +406,10 @@ interface_up(struct interface *ifp, int up) ...@@ -399,6 +406,10 @@ interface_up(struct interface *ifp, int up)
IF_CONF(ifp, update_interval) : IF_CONF(ifp, update_interval) :
ifp->hello_interval * 4; ifp->hello_interval * 4;
/* This must be no more than half the Hello interval, or else
Hellos will arrive late. */
ifp->buf.flush_interval = ifp->hello_interval / 2;
ifp->rtt_decay = ifp->rtt_decay =
IF_CONF(ifp, rtt_decay) > 0 ? IF_CONF(ifp, rtt_decay) > 0 ?
IF_CONF(ifp, rtt_decay) : 42; IF_CONF(ifp, rtt_decay) : 42;
...@@ -411,8 +422,8 @@ interface_up(struct interface *ifp, int up) ...@@ -411,8 +422,8 @@ interface_up(struct interface *ifp, int up)
IF_CONF(ifp, rtt_max) : 120000; IF_CONF(ifp, rtt_max) : 120000;
if(ifp->rtt_max <= ifp->rtt_min) { if(ifp->rtt_max <= ifp->rtt_min) {
fprintf(stderr, fprintf(stderr,
"Uh, rtt-max is less than or equal to rtt-min (%d <= %d). " "Uh, rtt-max is less than or equal to rtt-min (%u <= %u). "
"Setting it to %d.\n", ifp->rtt_max, ifp->rtt_min, "Setting it to %u.\n", ifp->rtt_max, ifp->rtt_min,
ifp->rtt_min + 10000); ifp->rtt_min + 10000);
ifp->rtt_max = ifp->rtt_min + 10000; ifp->rtt_max = ifp->rtt_min + 10000;
} }
...@@ -421,23 +432,20 @@ interface_up(struct interface *ifp, int up) ...@@ -421,23 +432,20 @@ interface_up(struct interface *ifp, int up)
ifp->max_rtt_penalty = 96; ifp->max_rtt_penalty = 96;
if(IF_CONF(ifp, enable_timestamps) == CONFIG_YES) if(IF_CONF(ifp, enable_timestamps) == CONFIG_YES)
ifp->flags |= IF_TIMESTAMPS; ifp->buf.enable_timestamps = 1;
else if(IF_CONF(ifp, enable_timestamps) == CONFIG_NO) else if(IF_CONF(ifp, enable_timestamps) == CONFIG_NO)
ifp->flags &= ~IF_TIMESTAMPS; ifp->buf.enable_timestamps = 0;
else if(type == IF_TYPE_TUNNEL) else if(type == IF_TYPE_TUNNEL)
ifp->flags |= IF_TIMESTAMPS; ifp->buf.enable_timestamps = 1;
else else
ifp->flags &= ~IF_TIMESTAMPS; ifp->buf.enable_timestamps = 0;
if(ifp->max_rtt_penalty > 0 && !(ifp->flags & IF_TIMESTAMPS)) if(ifp->max_rtt_penalty > 0 && !ifp->buf.enable_timestamps)
fprintf(stderr, fprintf(stderr,
"Warning: max_rtt_penalty is set " "Warning: max_rtt_penalty is set "
"but timestamps are disabled on interface %s.\n", "but timestamps are disabled on interface %s.\n",
ifp->name); ifp->name);
if(IF_CONF(ifp, rfc6126) == CONFIG_YES) ifp->buf.rfc6126_compatible = (IF_CONF(ifp, rfc6126) == CONFIG_YES);
ifp->flags |= IF_RFC6126;
else
ifp->flags &= ~IF_RFC6126;
rc = check_link_local_addresses(ifp); rc = check_link_local_addresses(ifp);
if(rc < 0) { if(rc < 0) {
...@@ -472,17 +480,18 @@ interface_up(struct interface *ifp, int up) ...@@ -472,17 +480,18 @@ interface_up(struct interface *ifp, int up)
send_hello(ifp); send_hello(ifp);
if(rc > 0) if(rc > 0)
send_update(ifp, 0, NULL, 0, NULL, 0); send_update(ifp, 0, NULL, 0, NULL, 0);
send_multicast_request(ifp, NULL, 0, NULL, 0);
} else { } else {
flush_interface_routes(ifp, 0); flush_interface_routes(ifp, 0);
ifp->buffered = 0; ifp->buf.len = 0;
ifp->bufsize = 0; ifp->buf.size = 0;
free(ifp->sendbuf); free(ifp->buf.buf);
ifp->num_buffered_updates = 0; ifp->num_buffered_updates = 0;
ifp->update_bufsize = 0; ifp->update_bufsize = 0;
if(ifp->buffered_updates) if(ifp->buffered_updates)
free(ifp->buffered_updates); free(ifp->buffered_updates);
ifp->buffered_updates = NULL; ifp->buffered_updates = NULL;
ifp->sendbuf = NULL; ifp->buf.buf = NULL;
if(ifp->ifindex > 0) { if(ifp->ifindex > 0) {
memset(&mreq, 0, sizeof(mreq)); memset(&mreq, 0, sizeof(mreq));
memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
...@@ -558,6 +567,7 @@ check_interfaces(void) ...@@ -558,6 +567,7 @@ check_interfaces(void)
check_interface_channel(ifp); check_interface_channel(ifp);
rc = check_interface_ipv4(ifp); rc = check_interface_ipv4(ifp);
if(rc > 0) { if(rc > 0) {
send_multicast_request(ifp, NULL, 0, NULL, 0);
send_update(ifp, 0, NULL, 0, NULL, 0); send_update(ifp, 0, NULL, 0, NULL, 0);
} }
} }
......
...@@ -45,6 +45,7 @@ struct interface_conf { ...@@ -45,6 +45,7 @@ struct interface_conf {
char split_horizon; char split_horizon;
char lq; char lq;
char faraway; char faraway;
char unicast;
int channel; int channel;
int enable_timestamps; int enable_timestamps;
int rfc6126; int rfc6126;
...@@ -69,16 +70,34 @@ struct interface_conf { ...@@ -69,16 +70,34 @@ struct interface_conf {
#define IF_LQ (1 << 3) #define IF_LQ (1 << 3)
/* Nodes on the far end don't interfere with nodes on the near end. */ /* Nodes on the far end don't interfere with nodes on the near end. */
#define IF_FARAWAY (1 << 4) #define IF_FARAWAY (1 << 4)
/* Send timestamps in Hello and IHU. */ /* Send most TLVs over unicast. */
#define IF_TIMESTAMPS (1 << 5) #define IF_UNICAST (1 << 5)
/* Remain compatible with RFC 6126. */
#define IF_RFC6126 (1 << 6)
/* Only INTERFERING can appear on the wire. */ /* Only INTERFERING can appear on the wire. */
#define IF_CHANNEL_UNKNOWN 0 #define IF_CHANNEL_UNKNOWN 0
#define IF_CHANNEL_INTERFERING 255 #define IF_CHANNEL_INTERFERING 255
#define IF_CHANNEL_NONINTERFERING -2 #define IF_CHANNEL_NONINTERFERING -2
struct buffered {
struct sockaddr_in6 sin6;
char *buf;
int len;
int size;
int flush_interval;
struct timeval timeout;
char enable_timestamps;
char rfc6126_compatible;
char have_id;
char have_nh;
char have_prefix;
unsigned char id[8];
unsigned char nh[4];
unsigned char prefix[16];
/* Relative position of the Hello message in the send buffer, or
(-1) if there is none. */
int hello;
};
struct interface { struct interface {
struct interface *next; struct interface *next;
struct interface_conf *conf; struct interface_conf *conf;
...@@ -88,31 +107,16 @@ struct interface { ...@@ -88,31 +107,16 @@ struct interface {
int channel; int channel;
struct timeval hello_timeout; struct timeval hello_timeout;
struct timeval update_timeout; struct timeval update_timeout;
struct timeval flush_timeout;
struct timeval update_flush_timeout; struct timeval update_flush_timeout;
char name[IF_NAMESIZE]; char name[IF_NAMESIZE];
unsigned char *ipv4; unsigned char *ipv4;
int numll; int numll;
unsigned char (*ll)[16]; unsigned char (*ll)[16];
int buffered; struct buffered buf;
int bufsize;
/* Relative position of the Hello message in the send buffer, or
(-1) if there is none. */
int buffered_hello;
char have_buffered_id;
char have_buffered_nh;
char have_buffered_prefix;
unsigned char buffered_id[8];
unsigned char buffered_nh[4];
unsigned char buffered_prefix[16];
unsigned char *sendbuf;
struct buffered_update *buffered_updates; struct buffered_update *buffered_updates;
int num_buffered_updates; int num_buffered_updates;
int update_bufsize; int update_bufsize;
time_t bucket_time;
unsigned int bucket;
time_t last_update_time; time_t last_update_time;
time_t last_specific_update_time;
unsigned short hello_seqno; unsigned short hello_seqno;
unsigned hello_interval; unsigned hello_interval;
unsigned update_interval; unsigned update_interval;
...@@ -140,7 +144,7 @@ if_up(struct interface *ifp) ...@@ -140,7 +144,7 @@ if_up(struct interface *ifp)
struct interface *add_interface(char *ifname, struct interface_conf *if_conf); struct interface *add_interface(char *ifname, struct interface_conf *if_conf);
int flush_interface(char *ifname); int flush_interface(char *ifname);
unsigned jitter(struct interface *ifp, int urgent); unsigned jitter(struct buffered *buf, int urgent);
unsigned update_jitter(struct interface *ifp, int urgent); unsigned update_jitter(struct interface *ifp, int urgent);
void set_timeout(struct timeval *timeout, int msecs); void set_timeout(struct timeval *timeout, int msecs);
int interface_up(struct interface *ifp, int up); int interface_up(struct interface *ifp, int up);
......
...@@ -446,7 +446,7 @@ netlink_talk(struct nlmsghdr *nh) ...@@ -446,7 +446,7 @@ netlink_talk(struct nlmsghdr *nh)
nh->nlmsg_seq = ++nl_command.seqno; nh->nlmsg_seq = ++nl_command.seqno;
kdebugf("Sending seqno %d from address %p (talk)\n", kdebugf("Sending seqno %d from address %p (talk)\n",
nl_command.seqno, &nl_command.seqno); nl_command.seqno, (void*)&nl_command.seqno);
rc = sendmsg(nl_command.sock, &msg, 0); rc = sendmsg(nl_command.sock, &msg, 0);
if(rc < 0 && (errno == EAGAIN || errno == EINTR)) { if(rc < 0 && (errno == EAGAIN || errno == EINTR)) {
...@@ -514,7 +514,7 @@ netlink_send_dump(int type, void *data, int len) { ...@@ -514,7 +514,7 @@ netlink_send_dump(int type, void *data, int len) {
buf.nh.nlmsg_len = NLMSG_LENGTH(len); buf.nh.nlmsg_len = NLMSG_LENGTH(len);
kdebugf("Sending seqno %d from address %p (dump)\n", kdebugf("Sending seqno %d from address %p (dump)\n",
nl_command.seqno, &nl_command.seqno); nl_command.seqno, (void*)&nl_command.seqno);
rc = sendmsg(nl_command.sock, &msg, 0); rc = sendmsg(nl_command.sock, &msg, 0);
if(rc < buf.nh.nlmsg_len) { if(rc < buf.nh.nlmsg_len) {
...@@ -677,14 +677,18 @@ kernel_setup_interface(int setup, const char *ifname, int ifindex) ...@@ -677,14 +677,18 @@ kernel_setup_interface(int setup, const char *ifname, int ifindex)
fprintf(stderr, fprintf(stderr,
"Warning: cannot save old configuration for %s.\n", "Warning: cannot save old configuration for %s.\n",
ifname); ifname);
rc = write_proc(buf, 0); if(old_if[i].rp_filter) {
if(rc < 0) rc = write_proc(buf, 0);
return -1; if(rc < 0)
return -1;
}
} else { } else {
if(i >= 0 && old_if[i].rp_filter >= 0) if(i >= 0 && old_if[i].rp_filter > 0)
rc = write_proc(buf, old_if[i].rp_filter); rc = write_proc(buf, old_if[i].rp_filter);
else else if(i < 0)
rc = -1; rc = -1;
else
rc = 1;
if(rc < 0) if(rc < 0)
fprintf(stderr, fprintf(stderr,
...@@ -1590,7 +1594,7 @@ add_rule(int prio, const unsigned char *src_prefix, int src_plen, int table) ...@@ -1590,7 +1594,7 @@ add_rule(int prio, const unsigned char *src_prefix, int src_plen, int table)
message_header->nlmsg_len += current_attribute->rta_len; message_header->nlmsg_len += current_attribute->rta_len;
current_attribute = (void*) current_attribute = (void*)
((char*)current_attribute) + current_attribute->rta_len; ((char*)current_attribute + current_attribute->rta_len);
/* src */ /* src */
current_attribute->rta_len = RTA_LENGTH(addr_size); current_attribute->rta_len = RTA_LENGTH(addr_size);
...@@ -1599,7 +1603,7 @@ add_rule(int prio, const unsigned char *src_prefix, int src_plen, int table) ...@@ -1599,7 +1603,7 @@ add_rule(int prio, const unsigned char *src_prefix, int src_plen, int table)
message_header->nlmsg_len += current_attribute->rta_len; message_header->nlmsg_len += current_attribute->rta_len;
current_attribute = (void*) current_attribute = (void*)
((char*)current_attribute) + current_attribute->rta_len; ((char*)current_attribute + current_attribute->rta_len);
/* send message */ /* send message */
if(message_header->nlmsg_len > 64) { if(message_header->nlmsg_len > 64) {
...@@ -1652,7 +1656,7 @@ flush_rule(int prio, int family) ...@@ -1652,7 +1656,7 @@ flush_rule(int prio, int family)
message_header->nlmsg_len += current_attribute->rta_len; message_header->nlmsg_len += current_attribute->rta_len;
current_attribute = (void*) current_attribute = (void*)
((char*)current_attribute) + current_attribute->rta_len; ((char*)current_attribute + current_attribute->rta_len);
/* send message */ /* send message */
if(message_header->nlmsg_len > 64) { if(message_header->nlmsg_len > 64) {
......
...@@ -44,11 +44,13 @@ THE SOFTWARE. ...@@ -44,11 +44,13 @@ THE SOFTWARE.
#include <net/route.h> #include <net/route.h>
#include "babeld.h" #include "babeld.h"
#include "interface.h"
#include "neighbour.h" #include "neighbour.h"
#include "kernel.h" #include "kernel.h"
#include "util.h" #include "util.h"
static int get_sdl(struct sockaddr_dl *sdl, char *ifname); static int get_sdl(struct sockaddr_dl *sdl, char *ifname);
static const unsigned char v4prefix[16] = static const unsigned char v4prefix[16] =
...@@ -586,7 +588,7 @@ print_kernel_route(int add, struct kernel_route *route) ...@@ -586,7 +588,7 @@ print_kernel_route(int add, struct kernel_route *route)
memcpy(ifname,"unk",4); memcpy(ifname,"unk",4);
fprintf(stderr, fprintf(stderr,
"%s kernel route: dest: %s gw: %s metric: %d if: %s(%d) \n", "%s kernel route: dest: %s gw: %s metric: %d if: %s(%u) \n",
add == RTM_ADD ? "Add" : add == RTM_ADD ? "Add" :
add == RTM_DELETE ? "Delete" : "Change", add == RTM_DELETE ? "Delete" : "Change",
format_prefix(route->prefix, route->plen), format_prefix(route->prefix, route->plen),
......
...@@ -145,7 +145,7 @@ local_notify_neighbour_1(struct local_socket *s, ...@@ -145,7 +145,7 @@ local_notify_neighbour_1(struct local_socket *s,
rttbuf[0] = '\0'; rttbuf[0] = '\0';
if(valid_rtt(neigh)) { if(valid_rtt(neigh)) {
rc = snprintf(rttbuf, 64, " rtt %s rttcost %d", rc = snprintf(rttbuf, 64, " rtt %s rttcost %u",
format_thousands(neigh->rtt), neighbour_rttcost(neigh)); format_thousands(neigh->rtt), neighbour_rttcost(neigh));
if(rc < 0 || rc >= 64) if(rc < 0 || rc >= 64)
rttbuf[0] = '\0'; rttbuf[0] = '\0';
...@@ -154,7 +154,7 @@ local_notify_neighbour_1(struct local_socket *s, ...@@ -154,7 +154,7 @@ local_notify_neighbour_1(struct local_socket *s,
rc = snprintf(buf, 512, rc = snprintf(buf, 512,
"%s neighbour %lx address %s " "%s neighbour %lx address %s "
"if %s reach %04x ureach %04x " "if %s reach %04x ureach %04x "
"rxcost %d txcost %d%s cost %d\n", "rxcost %u txcost %u%s cost %u\n",
local_kind(kind), local_kind(kind),
/* Neighbours never move around in memory , so we can use the /* Neighbours never move around in memory , so we can use the
address as a unique identifier. */ address as a unique identifier. */
......
...@@ -48,12 +48,6 @@ int split_horizon = 1; ...@@ -48,12 +48,6 @@ int split_horizon = 1;
unsigned short myseqno = 0; unsigned short myseqno = 0;
struct timeval seqno_time = {0, 0}; struct timeval seqno_time = {0, 0};
#define UNICAST_BUFSIZE 1024
int unicast_buffered = 0;
unsigned char *unicast_buffer = NULL;
struct neighbour *unicast_neighbour = NULL;
struct timeval unicast_flush_timeout = {0, 0};
extern const unsigned char v4prefix[16]; extern const unsigned char v4prefix[16];
#define MAX_CHANNEL_HOPS 20 #define MAX_CHANNEL_HOPS 20
...@@ -121,9 +115,10 @@ network_prefix(int ae, int plen, unsigned int omitted, ...@@ -121,9 +115,10 @@ network_prefix(int ae, int plen, unsigned int omitted,
} }
static int static int
parse_update_subtlv(struct interface *ifp, int metric, parse_update_subtlv(struct interface *ifp, int metric, int ae,
const unsigned char *a, int alen, const unsigned char *a, int alen,
unsigned char *channels, int *channels_len_return) unsigned char *channels, int *channels_len_return,
unsigned char *src_prefix, unsigned char *src_plen)
{ {
int type, len, i = 0; int type, len, i = 0;
int channels_len; int channels_len;
...@@ -149,21 +144,28 @@ parse_update_subtlv(struct interface *ifp, int metric, ...@@ -149,21 +144,28 @@ parse_update_subtlv(struct interface *ifp, int metric,
continue; continue;
} }
if(i + 1 > alen) { if(i + 1 > alen)
fprintf(stderr, "Received truncated sub-TLV on Update.\n"); goto fail;
return -1;
}
len = a[i + 1]; len = a[i + 1];
if(i + len + 2 > alen) { if(i + len + 2 > alen)
fprintf(stderr, "Received truncated sub-TLV on Update.\n"); goto fail;
return -1;
}
if(type == SUBTLV_PADN) { if(type == SUBTLV_PADN) {
/* Nothing. */ /* Nothing. */
} else if(type == SUBTLV_DIVERSITY) { } else if(type == SUBTLV_DIVERSITY) {
memcpy(channels, a + i + 2, MIN(len, *channels_len_return)); memcpy(channels, a + i + 2, MIN(len, *channels_len_return));
channels_len = MIN(len, *channels_len_return); channels_len = MIN(len, *channels_len_return);
} else if(type == SUBTLV_SOURCE_PREFIX) {
int rc;
if(len < 1)
goto fail;
*src_plen = a[i + 2];
rc = network_prefix(ae, *src_plen, 0, a + i + 3, NULL,
len - 1, src_prefix);
if(rc < 0)
goto fail;
if(ae == 1)
(*src_plen) += 96;
} else { } else {
debugf("Received unknown%s Update sub-TLV %d.\n", debugf("Received unknown%s Update sub-TLV %d.\n",
(type & 0x80) != 0 ? " mandatory" : "", type); (type & 0x80) != 0 ? " mandatory" : "", type);
...@@ -175,6 +177,10 @@ parse_update_subtlv(struct interface *ifp, int metric, ...@@ -175,6 +177,10 @@ parse_update_subtlv(struct interface *ifp, int metric,
} }
*channels_len_return = channels_len; *channels_len_return = channels_len;
return 1; return 1;
fail:
fprintf(stderr, "Received truncated sub-TLV on Update.\n");
return -1;
} }
static int static int
...@@ -249,6 +255,7 @@ parse_ihu_subtlv(const unsigned char *a, int alen, ...@@ -249,6 +255,7 @@ parse_ihu_subtlv(const unsigned char *a, int alen,
fprintf(stderr, "Received truncated sub-TLV on IHU.\n"); fprintf(stderr, "Received truncated sub-TLV on IHU.\n");
return -1; return -1;
} }
len = a[i + 1]; len = a[i + 1];
if(i + len + 2 > alen) { if(i + len + 2 > alen) {
fprintf(stderr, "Received truncated sub-TLV on IHU.\n"); fprintf(stderr, "Received truncated sub-TLV on IHU.\n");
...@@ -287,7 +294,8 @@ parse_ihu_subtlv(const unsigned char *a, int alen, ...@@ -287,7 +294,8 @@ parse_ihu_subtlv(const unsigned char *a, int alen,
} }
static int static int
parse_other_subtlv(const unsigned char *a, int alen) parse_request_subtlv(int ae, const unsigned char *a, int alen,
unsigned char *src_prefix, unsigned char *src_plen)
{ {
int type, len, i = 0; int type, len, i = 0;
...@@ -298,16 +306,107 @@ parse_other_subtlv(const unsigned char *a, int alen) ...@@ -298,16 +306,107 @@ parse_other_subtlv(const unsigned char *a, int alen)
continue; continue;
} }
if(i + 1 > alen) { if(i + 1 > alen)
fprintf(stderr, "Received truncated sub-TLV.\n"); goto fail;
return -1;
len = a[i + 1];
if(i + len > alen)
goto fail;
if(type == SUBTLV_PADN) {
/* Nothing to do. */
} else if(type == SUBTLV_SOURCE_PREFIX) {
int rc;
if(len < 1)
goto fail;
*src_plen = a[i + 2];
rc = network_prefix(ae, *src_plen, 0, a + i + 3, NULL,
len - 1, src_prefix);
if(rc < 0)
goto fail;
if(ae == 1)
(*src_plen) += 96;
} else {
debugf("Received unknown%s Route Request sub-TLV %d.\n",
((type & 0x80) != 0) ? " mandatory" : "", type);
if((type & 0x80) != 0)
return -1;
} }
i += len + 2;
}
return 1;
fail:
fprintf(stderr, "Received truncated sub-TLV on Route Request.\n");
return -1;
}
static int
parse_seqno_request_subtlv(int ae, const unsigned char *a, int alen,
unsigned char *src_prefix, unsigned char *src_plen)
{
int type, len, i = 0;
while(i < alen) {
type = a[0];
if(type == SUBTLV_PAD1) {
i++;
continue;
}
if(i + 1 > alen)
goto fail;
len = a[i + 1]; len = a[i + 1];
if(i + len + 2 > alen) { if(i + len + 2 > alen)
fprintf(stderr, "Received truncated sub-TLV.\n"); goto fail;
return -1;
if(type == SUBTLV_PADN) {
/* Nothing to do. */
} else if(type == SUBTLV_SOURCE_PREFIX) {
int rc;
if(len < 1)
goto fail;
*src_plen = a[i + 2];
rc = network_prefix(ae, *src_plen, 0, a + i + 3, NULL,
len - 1, src_prefix);
if(rc < 0)
goto fail;
if(ae == 1)
(*src_plen) += 96;
} else {
debugf("Received unknown%s Route Request sub-TLV %d.\n",
((type & 0x80) != 0) ? " mandatory" : "", type);
if((type & 0x80) != 0)
return -1;
}
i += len + 2;
}
return 1;
fail:
fprintf(stderr, "Received truncated sub-TLV on Route Request.\n");
return -1;
}
static int
parse_other_subtlv(const unsigned char *a, int alen)
{
int type, len, i = 0;
while(i < alen) {
type = a[0];
if(type == SUBTLV_PAD1) {
i++;
continue;
} }
if(i + 1 > alen)
goto fail;
len = a[i + 1];
if(i + len > alen)
goto fail;
if((type & 0x80) != 0) { if((type & 0x80) != 0) {
debugf("Received unknown mandatory sub-TLV %d.\n", type); debugf("Received unknown mandatory sub-TLV %d.\n", type);
return -1; return -1;
...@@ -316,6 +415,9 @@ parse_other_subtlv(const unsigned char *a, int alen) ...@@ -316,6 +415,9 @@ parse_other_subtlv(const unsigned char *a, int alen)
i += len + 2; i += len + 2;
} }
return 1; return 1;
fail:
fprintf(stderr, "Received truncated sub-TLV.\n");
return -1;
} }
static int static int
...@@ -342,7 +444,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -342,7 +444,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
/* Content of the RTT sub-TLV on IHU messages. */ /* Content of the RTT sub-TLV on IHU messages. */
unsigned int hello_send_us = 0, hello_rtt_receive_time = 0; unsigned int hello_send_us = 0, hello_rtt_receive_time = 0;
if(ifp->flags & IF_TIMESTAMPS) { if(ifp->buf.enable_timestamps) {
/* We want to track exactly when we received this packet. */ /* We want to track exactly when we received this packet. */
gettime(&now); gettime(&now);
} }
...@@ -528,7 +630,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -528,7 +630,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
unsigned char channels[MAX_CHANNEL_HOPS]; unsigned char channels[MAX_CHANNEL_HOPS];
int channels_len = MAX_CHANNEL_HOPS; int channels_len = MAX_CHANNEL_HOPS;
unsigned short interval, seqno, metric; unsigned short interval, seqno, metric;
int rc, parsed_len; int rc, parsed_len, is_ss;
if(len < 10) { if(len < 10) {
if(len < 2 || message[3] & 0x80) if(len < 2 || message[3] & 0x80)
have_v4_prefix = have_v6_prefix = 0; have_v4_prefix = have_v6_prefix = 0;
...@@ -588,7 +690,6 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -588,7 +690,6 @@ parse_packet(const unsigned char *from, struct interface *ifp,
(message[3] & 0x40) ? "/id" : "", (message[3] & 0x40) ? "/id" : "",
format_prefix(prefix, plen), format_prefix(prefix, plen),
format_address(from), ifp->name); format_address(from), ifp->name);
if(message[2] == 0) { if(message[2] == 0) {
rc = parse_other_subtlv(message + 12, len - 10); rc = parse_other_subtlv(message + 12, len - 10);
if(rc < 0) if(rc < 0)
...@@ -610,10 +711,20 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -610,10 +711,20 @@ parse_packet(const unsigned char *from, struct interface *ifp,
nh = neigh->address; nh = neigh->address;
} }
rc = parse_update_subtlv(ifp, metric, message + 2 + parsed_len, rc = parse_update_subtlv(ifp, metric, message[2],
len - parsed_len, channels, &channels_len); message + 2 + parsed_len,
if (rc < 0) len - parsed_len, channels, &channels_len,
src_prefix, &src_plen);
if(rc < 0)
goto done; goto done;
is_ss = !is_default(src_prefix, src_plen);
debugf("Received update%s%s for dst %s%s%s from %s on %s.\n",
(message[3] & 0x80) ? "/prefix" : "",
(message[3] & 0x40) ? "/id" : "",
format_prefix(prefix, plen),
is_ss ? " src " : "",
is_ss ? format_prefix(src_prefix, src_plen) : "",
format_address(from), ifp->name);
if(message[2] == 1) { if(message[2] == 1) {
if(!ifp->ipv4) if(!ifp->ipv4)
...@@ -625,19 +736,33 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -625,19 +736,33 @@ parse_packet(const unsigned char *from, struct interface *ifp,
channels, channels_len); channels, channels_len);
} else if(type == MESSAGE_REQUEST) { } else if(type == MESSAGE_REQUEST) {
unsigned char prefix[16], src_prefix[16], plen, src_plen; unsigned char prefix[16], src_prefix[16], plen, src_plen;
int rc; int rc, is_ss;
if(len < 2) goto fail; if(len < 2) goto fail;
rc = network_prefix(message[2], message[3], 0, rc = network_prefix(message[2], message[3], 0,
message + 4, NULL, len - 2, prefix); message + 4, NULL, len - 2, prefix);
if(rc < 0) goto fail; if(rc < 0) goto fail;
plen = message[3] + (message[2] == 1 ? 96 : 0); plen = message[3] + (message[2] == 1 ? 96 : 0);
debugf("Received request for %s from %s on %s.\n", if(message[2] == 1) {
message[2] == 0 ? "any" : format_prefix(prefix, plen), v4tov6(src_prefix, zeroes);
format_address(from), ifp->name); src_plen = 96;
rc = parse_other_subtlv(message + 4 + rc, len - 2 - rc); } else {
memcpy(src_prefix, zeroes, 16);
src_plen = 0;
}
rc = parse_request_subtlv(message[2], message + 4 + rc,
len - 2 - rc, src_prefix, &src_plen);
if(rc < 0) if(rc < 0)
goto done; goto done;
is_ss = !is_default(src_prefix, src_plen);
if(message[2] == 0) { if(message[2] == 0) {
if(is_ss) {
/* Wildcard requests don't carry a source prefix. */
fprintf(stderr,
"Received source-specific wildcard request.\n");
goto done;
}
debugf("Received request for any from %s on %s.\n",
format_address(from), ifp->name);
/* If a neighbour is requesting a full route dump from us, /* If a neighbour is requesting a full route dump from us,
we might as well send it an IHU. */ we might as well send it an IHU. */
send_ihu(neigh, NULL); send_ihu(neigh, NULL);
...@@ -646,31 +771,26 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -646,31 +771,26 @@ parse_packet(const unsigned char *from, struct interface *ifp,
update storm. Ignore a wildcard request that happens update storm. Ignore a wildcard request that happens
shortly after we sent a full update. */ shortly after we sent a full update. */
if(neigh->ifp->last_update_time < if(neigh->ifp->last_update_time <
now.tv_sec - MAX(neigh->ifp->hello_interval / 100, 1)) now.tv_sec - MAX(neigh->ifp->hello_interval / 100, 1)) {
send_update(neigh->ifp, 0, NULL, 0, zeroes, 0); send_update(neigh->ifp, 0, NULL, 0, NULL, 0);
} else {
if(message[2] == 1) {
v4tov6(src_prefix, zeroes);
src_plen = 96;
} else {
memcpy(src_prefix, zeroes, 16);
src_plen = 0;
} }
} else {
debugf("Received request for dst %s%s%s from %s on %s.\n",
message[2] == 0 ? "" : format_prefix(prefix, plen),
is_ss ? " src " : "",
is_ss ? format_prefix(src_prefix, src_plen) : "",
format_address(from), ifp->name);
send_update(neigh->ifp, 0, prefix, plen, src_prefix, src_plen); send_update(neigh->ifp, 0, prefix, plen, src_prefix, src_plen);
} }
} else if(type == MESSAGE_MH_REQUEST) { } else if(type == MESSAGE_MH_REQUEST) {
unsigned char prefix[16], src_prefix[16], plen, src_plen; unsigned char prefix[16], src_prefix[16], plen, src_plen;
unsigned short seqno; unsigned short seqno;
int rc; int rc, is_ss;
if(len < 14) goto fail; if(len < 14) goto fail;
DO_NTOHS(seqno, message + 4); DO_NTOHS(seqno, message + 4);
rc = network_prefix(message[2], message[3], 0, rc = network_prefix(message[2], message[3], 0,
message + 16, NULL, len - 14, prefix); message + 16, NULL, len - 14, prefix);
if(rc < 0) goto fail; if(rc < 0) goto fail;
rc = parse_other_subtlv(message + 16 + rc, len - 14 - rc);
if(rc < 0)
goto done;
plen = message[3] + (message[2] == 1 ? 96 : 0);
if(message[2] == 1) { if(message[2] == 1) {
v4tov6(src_prefix, zeroes); v4tov6(src_prefix, zeroes);
src_plen = 96; src_plen = 96;
...@@ -678,165 +798,23 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -678,165 +798,23 @@ parse_packet(const unsigned char *from, struct interface *ifp,
memcpy(src_prefix, zeroes, 16); memcpy(src_prefix, zeroes, 16);
src_plen = 0; src_plen = 0;
} }
debugf("Received request (%d) for %s from %s on %s (%s, %d).\n", rc = parse_seqno_request_subtlv(message[2], message + 16 + rc,
message[6], len - 14 - rc, src_prefix,
format_prefix(prefix, plen), &src_plen);
format_address(from), ifp->name,
format_eui64(message + 8), seqno);
handle_request(neigh, prefix, plen, src_prefix, src_plen,
message[6], seqno, message + 8);
} else if(type == MESSAGE_UPDATE_SRC_SPECIFIC) {
unsigned char prefix[16], src_prefix[16], *nh;
unsigned char ae, plen, src_plen, omitted;
unsigned char channels[MAX_CHANNEL_HOPS];
int channels_len = MAX_CHANNEL_HOPS;
unsigned short interval, seqno, metric;
const unsigned char *src_prefix_beginning = NULL;
int rc, parsed_len = 0;
if(len < 10)
goto fail;
ae = message[2];
src_plen = message[3];
plen = message[4];
omitted = message[5];
DO_NTOHS(interval, message + 6);
DO_NTOHS(seqno, message + 8);
DO_NTOHS(metric, message + 10);
if(omitted == 0 || (ae == 1 ? have_v4_prefix : have_v6_prefix))
rc = network_prefix(ae, plen, omitted, message + 12,
ae == 1 ? v4_prefix : v6_prefix,
len - 10, prefix);
else
rc = -1;
if(rc < 0)
goto fail;
parsed_len = 10 + rc;
src_prefix_beginning = message + 2 + parsed_len;
rc = network_prefix(ae, src_plen, 0, src_prefix_beginning, NULL,
len - parsed_len, src_prefix);
if(rc < 0)
goto fail;
parsed_len += rc;
if(ae == 1) {
plen += 96;
src_plen += 96;
}
if(!have_router_id) {
fprintf(stderr, "Received prefix with no router id.\n");
goto fail;
}
debugf("Received ss-update for (%s from %s) from %s on %s.\n",
format_prefix(prefix, plen),
format_prefix(src_prefix, src_plen),
format_address(from), ifp->name);
if(ae == 0) {
debugf("Received invalid Source-Specific wildcard update.\n");
rc = parse_other_subtlv(message + 12, len - 10);
if(rc < 0)
goto done;
retract_neighbour_routes(neigh);
goto done;
} else if(ae == 1) {
if(!have_v4_nh)
goto fail;
nh = v4_nh;
} else if(have_v6_nh) {
nh = v6_nh;
} else {
nh = neigh->address;
}
rc = parse_update_subtlv(ifp, metric, message + 2 + parsed_len,
len - parsed_len, channels, &channels_len);
if(rc < 0)
goto done;
if(ae == 1) {
if(!ifp->ipv4)
goto done;
}
update_route(router_id, prefix, plen, src_prefix, src_plen,
seqno, metric, interval, neigh, nh,
channels, channels_len);
} else if(type == MESSAGE_REQUEST_SRC_SPECIFIC) {
unsigned char prefix[16], plen, ae, src_prefix[16], src_plen;
int rc, parsed = 5;
if(len < 3) goto fail;
ae = message[2];
plen = message[3];
src_plen = message[4];
rc = network_prefix(ae, plen, 0, message + parsed,
NULL, len + 2 - parsed, prefix);
if(rc < 0) goto fail;
if(ae == 1)
plen += 96;
parsed += rc;
rc = network_prefix(ae, src_plen, 0, message + parsed,
NULL, len + 2 - parsed, src_prefix);
if(rc < 0) goto fail;
if(ae == 1)
src_plen += 96;
parsed += rc;
rc = parse_other_subtlv(message + parsed, len - parsed + 2);
if(rc < 0)
goto done;
if(ae == 0) {
debugf("Received request for any source-specific "
"from %s on %s.\n",
format_address(from), ifp->name);
/* See comments for std requests. */
send_ihu(neigh, NULL);
if(neigh->ifp->last_specific_update_time <
now.tv_sec - MAX(neigh->ifp->hello_interval / 100, 1))
send_update(neigh->ifp, 0, zeroes, 0, NULL, 0);
} else {
debugf("Received request for (%s from %s) from %s on %s.\n",
format_prefix(prefix, plen),
format_prefix(src_prefix, src_plen),
format_address(from), ifp->name);
send_update(neigh->ifp, 0, prefix, plen, src_prefix, src_plen);
}
} else if(type == MESSAGE_MH_REQUEST_SRC_SPECIFIC) {
unsigned char prefix[16], plen, ae, src_prefix[16], src_plen, hopc;
const unsigned char *router_id;
unsigned short seqno;
int rc, parsed = 16;
if(len < 14) goto fail;
ae = message[2];
plen = message[3];
DO_NTOHS(seqno, message + 4);
hopc = message[6];
src_plen = message[7];
router_id = message + 8;
rc = network_prefix(ae, plen, 0, message + parsed,
NULL, len + 2 - parsed, prefix);
if(rc < 0) goto fail;
if(ae == 1)
plen += 96;
parsed += rc;
rc = network_prefix(ae, src_plen, 0, message + parsed,
NULL, len + 2 - parsed, src_prefix);
if(rc < 0) goto fail;
parsed += rc;
rc = parse_other_subtlv(message + parsed, len - parsed + 2);
if(rc < 0) if(rc < 0)
goto done; goto done;
if(ae == 1) is_ss = !is_default(src_prefix, src_plen);
src_plen += 96; plen = message[3] + (message[2] == 1 ? 96 : 0);
debugf("Received request (%d) for (%s, %s)" debugf("Received request (%d) for dst %s%s%s from %s on "
" from %s on %s (%s, %d).\n", "%s (%s, %d).\n",
message[6], message[6],
format_prefix(prefix, plen), format_prefix(prefix, plen),
format_prefix(src_prefix, src_plen), is_ss ? " src " : "",
is_ss ? format_prefix(src_prefix, src_plen) : "",
format_address(from), ifp->name, format_address(from), ifp->name,
format_eui64(router_id), seqno); format_eui64(message + 8), seqno);
handle_request(neigh, prefix, plen, src_prefix, src_plen, handle_request(neigh, prefix, plen, src_prefix, src_plen,
hopc, seqno, router_id); message[6], seqno, message + 8);
} else { } else {
debugf("Received unknown packet type %d from %s on %s.\n", debugf("Received unknown packet type %d from %s on %s.\n",
type, format_address(from), ifp->name); type, format_address(from), ifp->name);
...@@ -891,43 +869,18 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -891,43 +869,18 @@ parse_packet(const unsigned char *from, struct interface *ifp,
return; return;
} }
/* Under normal circumstances, there are enough moderation mechanisms
elsewhere in the protocol to make sure that this last-ditch check
should never trigger. But I'm superstitious. */
static int static int
check_bucket(struct interface *ifp) fill_rtt_message(struct buffered *buf)
{ {
if(ifp->bucket <= 0) { if(buf->enable_timestamps && (buf->hello >= 0)) {
int seconds = now.tv_sec - ifp->bucket_time; if(buf->buf[buf->hello + 8] == SUBTLV_PADN &&
if(seconds > 0) { buf->buf[buf->hello + 9] == 4) {
ifp->bucket = MIN(BUCKET_TOKENS_MAX,
seconds * BUCKET_TOKENS_PER_SEC);
}
/* Reset bucket time unconditionally, in case clock is stepped. */
ifp->bucket_time = now.tv_sec;
}
if(ifp->bucket > 0) {
ifp->bucket--;
return 1;
} else {
return 0;
}
}
static int
fill_rtt_message(struct interface *ifp)
{
if((ifp->flags & IF_TIMESTAMPS) && (ifp->buffered_hello >= 0)) {
if(ifp->sendbuf[ifp->buffered_hello + 8] == SUBTLV_PADN &&
ifp->sendbuf[ifp->buffered_hello + 9] == 4) {
unsigned int time; unsigned int time;
/* Change the type of sub-TLV. */ /* Change the type of sub-TLV. */
ifp->sendbuf[ifp->buffered_hello + 8] = SUBTLV_TIMESTAMP; buf->buf[buf->hello + 8] = SUBTLV_TIMESTAMP;
gettime(&now); gettime(&now);
time = time_us(now); time = time_us(now);
DO_HTONL(ifp->sendbuf + ifp->buffered_hello + 10, time); DO_HTONL(buf->buf + buf->hello + 10, time);
return 1; return 1;
} else { } else {
fprintf(stderr, fprintf(stderr,
...@@ -940,214 +893,129 @@ fill_rtt_message(struct interface *ifp) ...@@ -940,214 +893,129 @@ fill_rtt_message(struct interface *ifp)
} }
void void
flushbuf(struct interface *ifp) flushbuf(struct buffered *buf)
{ {
int rc; int rc;
struct sockaddr_in6 sin6;
assert(ifp->buffered <= ifp->bufsize); assert(buf->len <= buf->size);
flushupdates(ifp); if(buf->len > 0) {
debugf(" (flushing %d buffered bytes)\n", buf->len);
if(ifp->buffered > 0) { DO_HTONS(packet_header + 2, buf->len);
debugf(" (flushing %d buffered bytes on %s)\n", fill_rtt_message(buf);
ifp->buffered, ifp->name); rc = babel_send(protocol_socket,
if(check_bucket(ifp)) { packet_header, sizeof(packet_header),
memset(&sin6, 0, sizeof(sin6)); buf->buf, buf->len,
sin6.sin6_family = AF_INET6; (struct sockaddr*)&buf->sin6,
memcpy(&sin6.sin6_addr, protocol_group, 16); sizeof(buf->sin6));
sin6.sin6_port = htons(protocol_port); if(rc < 0)
sin6.sin6_scope_id = ifp->ifindex; perror("send");
DO_HTONS(packet_header + 2, ifp->buffered);
fill_rtt_message(ifp);
rc = babel_send(protocol_socket,
packet_header, sizeof(packet_header),
ifp->sendbuf, ifp->buffered,
(struct sockaddr*)&sin6, sizeof(sin6));
if(rc < 0)
perror("send");
} else {
fprintf(stderr, "Warning: bucket full, dropping packet to %s.\n",
ifp->name);
}
} }
VALGRIND_MAKE_MEM_UNDEFINED(ifp->sendbuf, ifp->bufsize); VALGRIND_MAKE_MEM_UNDEFINED(buf->buf, buf->size);
ifp->buffered = 0; buf->len = 0;
ifp->buffered_hello = -1; buf->hello = -1;
ifp->have_buffered_id = 0; buf->have_id = 0;
ifp->have_buffered_nh = 0; buf->have_nh = 0;
ifp->have_buffered_prefix = 0; buf->have_prefix = 0;
ifp->flush_timeout.tv_sec = 0; buf->timeout.tv_sec = 0;
ifp->flush_timeout.tv_usec = 0; buf->timeout.tv_usec = 0;
} }
static void static void
schedule_flush(struct interface *ifp) schedule_flush_ms(struct buffered *buf, int msecs)
{ {
unsigned msecs = jitter(ifp, 0); if(buf->timeout.tv_sec != 0 &&
if(ifp->flush_timeout.tv_sec != 0 && timeval_minus_msec(&buf->timeout, &now) < msecs)
timeval_minus_msec(&ifp->flush_timeout, &now) < msecs)
return; return;
set_timeout(&ifp->flush_timeout, msecs); set_timeout(&buf->timeout, msecs);
} }
static void static void
schedule_flush_now(struct interface *ifp) schedule_flush(struct buffered *buf)
{ {
/* Almost now */ schedule_flush_ms(buf, jitter(buf, 0));
unsigned msecs = roughly(10);
if(ifp->flush_timeout.tv_sec != 0 &&
timeval_minus_msec(&ifp->flush_timeout, &now) < msecs)
return;
set_timeout(&ifp->flush_timeout, msecs);
} }
static void static void
schedule_unicast_flush(unsigned msecs) schedule_flush_now(struct buffered *buf)
{ {
if(!unicast_neighbour) schedule_flush_ms(buf, roughly(10));
return;
if(unicast_flush_timeout.tv_sec != 0 &&
timeval_minus_msec(&unicast_flush_timeout, &now) < msecs)
return;
unicast_flush_timeout.tv_usec = (now.tv_usec + msecs * 1000) % 1000000;
unicast_flush_timeout.tv_sec =
now.tv_sec + (now.tv_usec / 1000 + msecs) / 1000;
} }
static void static void
ensure_space(struct interface *ifp, int space) ensure_space(struct buffered *buf, int space)
{ {
if(ifp->bufsize - ifp->buffered < space) if(buf->size - buf->len < space)
flushbuf(ifp); flushbuf(buf);
} }
static void static void
start_message(struct interface *ifp, int type, int len) start_message(struct buffered *buf, int type, int len)
{ {
if(ifp->bufsize - ifp->buffered < len + 2) if(buf->size - buf->len < len + 2)
flushbuf(ifp); flushbuf(buf);
ifp->sendbuf[ifp->buffered++] = type; buf->buf[buf->len++] = type;
ifp->sendbuf[ifp->buffered++] = len; buf->buf[buf->len++] = len;
} }
static void static void
end_message(struct interface *ifp, int type, int bytes) end_message(struct buffered *buf, int type, int bytes)
{ {
assert(ifp->buffered >= bytes + 2 && assert(buf->len >= bytes + 2 &&
ifp->sendbuf[ifp->buffered - bytes - 2] == type && buf->buf[buf->len - bytes - 2] == type &&
ifp->sendbuf[ifp->buffered - bytes - 1] == bytes); buf->buf[buf->len - bytes - 1] == bytes);
schedule_flush(ifp); schedule_flush(buf);
} }
static void static void
accumulate_byte(struct interface *ifp, unsigned char value) accumulate_byte(struct buffered *buf, unsigned char value)
{ {
ifp->sendbuf[ifp->buffered++] = value; buf->buf[buf->len++] = value;
} }
static void static void
accumulate_short(struct interface *ifp, unsigned short value) accumulate_short(struct buffered *buf, unsigned short value)
{ {
DO_HTONS(ifp->sendbuf + ifp->buffered, value); DO_HTONS(buf->buf + buf->len, value);
ifp->buffered += 2; buf->len += 2;
} }
static void static void
accumulate_int(struct interface *ifp, unsigned int value) accumulate_int(struct buffered *buf, unsigned int value)
{ {
DO_HTONL(ifp->sendbuf + ifp->buffered, value); DO_HTONL(buf->buf + buf->len, value);
ifp->buffered += 4; buf->len += 4;
} }
static void static void
accumulate_bytes(struct interface *ifp, accumulate_bytes(struct buffered *buf,
const unsigned char *value, unsigned len) const unsigned char *value, unsigned len)
{ {
memcpy(ifp->sendbuf + ifp->buffered, value, len); memcpy(buf->buf + buf->len, value, len);
ifp->buffered += len; buf->len += len;
}
static int
start_unicast_message(struct neighbour *neigh, int type, int len)
{
if(unicast_neighbour) {
if(neigh != unicast_neighbour ||
unicast_buffered + len + 2 >=
MIN(UNICAST_BUFSIZE, neigh->ifp->bufsize))
flush_unicast(0);
}
if(!unicast_buffer)
unicast_buffer = malloc(UNICAST_BUFSIZE);
if(!unicast_buffer) {
perror("malloc(unicast_buffer)");
return -1;
}
unicast_neighbour = neigh;
unicast_buffer[unicast_buffered++] = type;
unicast_buffer[unicast_buffered++] = len;
return 1;
}
static void
end_unicast_message(struct neighbour *neigh, int type, int bytes)
{
assert(unicast_neighbour == neigh && unicast_buffered >= bytes + 2 &&
unicast_buffer[unicast_buffered - bytes - 2] == type &&
unicast_buffer[unicast_buffered - bytes - 1] == bytes);
schedule_unicast_flush(jitter(neigh->ifp, 0));
}
static void
accumulate_unicast_byte(struct neighbour *neigh, unsigned char value)
{
unicast_buffer[unicast_buffered++] = value;
}
static void
accumulate_unicast_short(struct neighbour *neigh, unsigned short value)
{
DO_HTONS(unicast_buffer + unicast_buffered, 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)
{
memcpy(unicast_buffer + unicast_buffered, value, len);
unicast_buffered += len;
} }
void void
send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval) send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval)
{ {
int rc;
debugf("Sending ack (%04x) to %s on %s.\n", debugf("Sending ack (%04x) to %s on %s.\n",
nonce, format_address(neigh->address), neigh->ifp->name); nonce, format_address(neigh->address), neigh->ifp->name);
rc = start_unicast_message(neigh, MESSAGE_ACK, 2); if(rc < 0) return; start_message(&neigh->buf, MESSAGE_ACK, 2);
accumulate_unicast_short(neigh, nonce); accumulate_short(&neigh->buf, nonce);
end_unicast_message(neigh, MESSAGE_ACK, 2); end_message(&neigh->buf, MESSAGE_ACK, 2);
/* Roughly yields a value no larger than 3/2, so this meets the deadline */ /* Roughly yields a value no larger than 3/2, so this meets the deadline */
schedule_unicast_flush(roughly(interval * 6)); schedule_flush_ms(&neigh->buf, roughly(interval * 6));
} }
void void
send_hello_noupdate(struct interface *ifp, unsigned interval) send_hello_noihu(struct interface *ifp, unsigned interval)
{ {
/* This avoids sending multiple hellos in a single packet, which breaks /* This avoids sending multiple hellos in a single packet, which breaks
link quality estimation. */ link quality estimation. */
if(ifp->buffered_hello >= 0) if(ifp->buf.hello >= 0) {
flushbuf(ifp); flushupdates(ifp);
flushbuf(&ifp->buf);
}
ifp->hello_seqno = seqno_plus(ifp->hello_seqno, 1); ifp->hello_seqno = seqno_plus(ifp->hello_seqno, 1);
set_timeout(&ifp->hello_timeout, ifp->hello_interval); set_timeout(&ifp->hello_timeout, ifp->hello_interval);
...@@ -1158,25 +1026,25 @@ send_hello_noupdate(struct interface *ifp, unsigned interval) ...@@ -1158,25 +1026,25 @@ send_hello_noupdate(struct interface *ifp, unsigned interval)
debugf("Sending hello %d (%d) to %s.\n", debugf("Sending hello %d (%d) to %s.\n",
ifp->hello_seqno, interval, ifp->name); ifp->hello_seqno, interval, ifp->name);
start_message(ifp, MESSAGE_HELLO, (ifp->flags & IF_TIMESTAMPS) ? 12 : 6); start_message(&ifp->buf, MESSAGE_HELLO, ifp->buf.enable_timestamps ? 12 : 6);
ifp->buffered_hello = ifp->buffered - 2; ifp->buf.hello = ifp->buf.len - 2;
accumulate_short(ifp, 0); accumulate_short(&ifp->buf, 0);
accumulate_short(ifp, ifp->hello_seqno); accumulate_short(&ifp->buf, ifp->hello_seqno);
accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval); accumulate_short(&ifp->buf, interval > 0xFFFF ? 0xFFFF : interval);
if(ifp->flags & IF_TIMESTAMPS) { if(ifp->buf.enable_timestamps) {
/* Sub-TLV containing the local time of emission. We use a /* Sub-TLV containing the local time of emission. We use a
Pad4 sub-TLV, which we'll fill just before sending. */ Pad4 sub-TLV, which we'll fill just before sending. */
accumulate_byte(ifp, SUBTLV_PADN); accumulate_byte(&ifp->buf, SUBTLV_PADN);
accumulate_byte(ifp, 4); accumulate_byte(&ifp->buf, 4);
accumulate_int(ifp, 0); accumulate_int(&ifp->buf, 0);
} }
end_message(ifp, MESSAGE_HELLO, (ifp->flags & IF_TIMESTAMPS) ? 12 : 6); end_message(&ifp->buf, MESSAGE_HELLO, ifp->buf.enable_timestamps ? 12 : 6);
} }
void void
send_hello(struct interface *ifp) send_hello(struct interface *ifp)
{ {
send_hello_noupdate(ifp, (ifp->hello_interval + 9) / 10); send_hello_noihu(ifp, (ifp->hello_interval + 9) / 10);
/* Send full IHU every 3 hellos, and marginal IHU each time */ /* Send full IHU every 3 hellos, and marginal IHU each time */
if(ifp->hello_seqno % 3 == 0) if(ifp->hello_seqno % 3 == 0)
send_ihu(NULL, ifp); send_ihu(NULL, ifp);
...@@ -1184,115 +1052,64 @@ send_hello(struct interface *ifp) ...@@ -1184,115 +1052,64 @@ send_hello(struct interface *ifp)
send_marginal_ihu(ifp); send_marginal_ihu(ifp);
} }
void
flush_unicast(int dofree)
{
struct sockaddr_in6 sin6;
int rc;
if(unicast_buffered == 0)
goto done;
if(!if_up(unicast_neighbour->ifp))
goto done;
/* Preserve ordering of messages */
flushbuf(unicast_neighbour->ifp);
if(check_bucket(unicast_neighbour->ifp)) {
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
memcpy(&sin6.sin6_addr, unicast_neighbour->address, 16);
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,
(struct sockaddr*)&sin6, sizeof(sin6));
if(rc < 0)
perror("send(unicast)");
} else {
fprintf(stderr,
"Warning: bucket full, dropping unicast packet "
"to %s if %s.\n",
format_address(unicast_neighbour->address),
unicast_neighbour->ifp->name);
}
done:
VALGRIND_MAKE_MEM_UNDEFINED(unicast_buffer, UNICAST_BUFSIZE);
unicast_buffered = 0;
if(dofree && unicast_buffer) {
free(unicast_buffer);
unicast_buffer = NULL;
}
unicast_neighbour = NULL;
unicast_flush_timeout.tv_sec = 0;
unicast_flush_timeout.tv_usec = 0;
}
static void static void
really_send_update(struct interface *ifp, really_buffer_update(struct buffered *buf, struct interface *ifp,
const unsigned char *id, const unsigned char *id,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen, const unsigned char *src_prefix, unsigned char src_plen,
unsigned short seqno, unsigned short metric, unsigned short seqno, unsigned short metric,
unsigned char *channels, int channels_len) unsigned char *channels, int channels_len)
{ {
int add_metric, v4, real_plen, omit = 0; int add_metric, v4, real_plen, real_src_plen;
const unsigned char *real_prefix; int omit, spb, channels_size, len;
const unsigned char *real_src_prefix = NULL; const unsigned char *real_prefix, *real_src_prefix;
int real_src_plen = 0;
unsigned short flags = 0; unsigned short flags = 0;
int channels_size;
int is_ss = !is_default(src_prefix, src_plen); int is_ss = !is_default(src_prefix, src_plen);
if(diversity_kind != DIVERSITY_CHANNEL)
channels_len = -1;
channels_size = channels_len >= 0 ? channels_len + 2 : 0;
if(!if_up(ifp)) if(!if_up(ifp))
return; return;
if(is_ss && buf->rfc6126_compatible)
return;
add_metric = output_filter(id, prefix, plen, src_prefix, add_metric = output_filter(id, prefix, plen, src_prefix,
src_plen, ifp->ifindex); src_plen, ifp->ifindex);
if(add_metric >= INFINITY) if(add_metric >= INFINITY)
return; return;
metric = MIN(metric + add_metric, INFINITY); metric = MIN(metric + add_metric, INFINITY);
/* Worst case */ /* Worst case */
ensure_space(ifp, 20 + 12 + 28 + 18); ensure_space(buf, 20 + 12 + 28 + 18);
v4 = plen >= 96 && v4mapped(prefix); v4 = plen >= 96 && v4mapped(prefix);
if(v4) { if(v4) {
if(!ifp->ipv4) if(!ifp->ipv4)
return; return;
if(!ifp->have_buffered_nh || omit = 0;
memcmp(ifp->buffered_nh, ifp->ipv4, 4) != 0) { if(!buf->have_nh ||
start_message(ifp, MESSAGE_NH, 6); memcmp(buf->nh, ifp->ipv4, 4) != 0) {
accumulate_byte(ifp, 1); start_message(buf, MESSAGE_NH, 6);
accumulate_byte(ifp, 0); accumulate_byte(buf, 1);
accumulate_bytes(ifp, ifp->ipv4, 4); accumulate_byte(buf, 0);
end_message(ifp, MESSAGE_NH, 6); accumulate_bytes(buf, ifp->ipv4, 4);
memcpy(ifp->buffered_nh, ifp->ipv4, 4); end_message(buf, MESSAGE_NH, 6);
ifp->have_buffered_nh = 1; memcpy(&buf->nh, ifp->ipv4, 4);
buf->have_nh = 1;
} }
real_prefix = prefix + 12; real_prefix = prefix + 12;
real_plen = plen - 96; real_plen = plen - 96;
real_src_prefix = src_prefix + 12; real_src_prefix = src_prefix + 12;
real_src_plen = src_plen - 96; real_src_plen = src_plen - 96;
} else { } else {
if(ifp->have_buffered_prefix) { omit = 0;
if(buf->have_prefix) {
while(omit < plen / 8 && while(omit < plen / 8 &&
ifp->buffered_prefix[omit] == prefix[omit]) buf->prefix[omit] == prefix[omit])
omit++; omit++;
} }
if(!is_ss && (!ifp->have_buffered_prefix || plen >= 48)) if(!buf->have_prefix || plen >= 48)
flags |= 0x80; flags |= 0x80;
real_prefix = prefix; real_prefix = prefix;
real_plen = plen; real_plen = plen;
...@@ -1300,57 +1117,77 @@ really_send_update(struct interface *ifp, ...@@ -1300,57 +1117,77 @@ really_send_update(struct interface *ifp,
real_src_plen = src_plen; real_src_plen = src_plen;
} }
if(!ifp->have_buffered_id || memcmp(id, ifp->buffered_id, 8) != 0) { if(!buf->have_id || memcmp(id, buf->id, 8) != 0) {
if(!is_ss && real_plen == 128 && if(real_plen == 128 && memcmp(real_prefix + 8, id, 8) == 0) {
memcmp(real_prefix + 8, id, 8) == 0) {
flags |= 0x40; flags |= 0x40;
} else { } else {
start_message(ifp, MESSAGE_ROUTER_ID, 10); start_message(buf, MESSAGE_ROUTER_ID, 10);
accumulate_short(ifp, 0); accumulate_short(buf, 0);
accumulate_bytes(ifp, id, 8); accumulate_bytes(buf, id, 8);
end_message(ifp, MESSAGE_ROUTER_ID, 10); end_message(buf, MESSAGE_ROUTER_ID, 10);
} }
memcpy(ifp->buffered_id, id, 8); memcpy(buf->id, id, 8);
ifp->have_buffered_id = 1; buf->have_id = 1;
} }
if(!is_ss) channels_size = diversity_kind == DIVERSITY_CHANNEL && channels_len >= 0 ?
start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + channels_len + 2 : 0;
channels_size); len = 10 + (real_plen + 7) / 8 - omit + channels_size;
else spb = (real_src_plen + 7) / 8;
start_message(ifp, MESSAGE_UPDATE_SRC_SPECIFIC,
10 + (real_plen + 7) / 8 - omit +
(real_src_plen + 7) / 8 + channels_size);
accumulate_byte(ifp, v4 ? 1 : 2);
if(is_ss)
accumulate_byte(ifp, real_src_plen);
else
accumulate_byte(ifp, flags);
accumulate_byte(ifp, real_plen);
accumulate_byte(ifp, omit);
accumulate_short(ifp, (ifp->update_interval + 5) / 10);
accumulate_short(ifp, seqno);
accumulate_short(ifp, metric);
accumulate_bytes(ifp, real_prefix + omit, (real_plen + 7) / 8 - omit);
if(is_ss) if(is_ss)
accumulate_bytes(ifp, real_src_prefix, (real_src_plen + 7) / 8); len += 3 + spb;
start_message(buf, MESSAGE_UPDATE, len);
accumulate_byte(buf, v4 ? 1 : 2);
accumulate_byte(buf, flags);
accumulate_byte(buf, real_plen);
accumulate_byte(buf, omit);
accumulate_short(buf, (ifp->update_interval + 5) / 10);
accumulate_short(buf, seqno);
accumulate_short(buf, metric);
accumulate_bytes(buf, real_prefix + omit, (real_plen + 7) / 8 - omit);
if(is_ss) {
accumulate_byte(buf, SUBTLV_SOURCE_PREFIX);
accumulate_byte(buf, 1 + spb);
accumulate_byte(buf, real_src_plen);
accumulate_bytes(buf, real_src_prefix, spb);
}
/* Note that an empty channels TLV is different from no such TLV. */ /* Note that an empty channels TLV is different from no such TLV. */
if(channels_len >= 0) { if(channels_size > 0) {
accumulate_byte(ifp, 2); accumulate_byte(buf, 2);
accumulate_byte(ifp, channels_len); accumulate_byte(buf, channels_len);
accumulate_bytes(ifp, channels, channels_len); accumulate_bytes(buf, channels, channels_len);
} }
if(!is_ss) end_message(buf, MESSAGE_UPDATE, len);
end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit +
channels_size);
else
end_message(ifp, MESSAGE_UPDATE_SRC_SPECIFIC,
10 + (real_plen + 7) / 8 - omit +
(real_src_plen + 7) / 8 + channels_size);
if(flags & 0x80) { if(flags & 0x80) {
memcpy(ifp->buffered_prefix, prefix, 16); memcpy(buf->prefix, prefix, 16);
ifp->have_buffered_prefix = 1; buf->have_prefix = 1;
}
}
static void
really_send_update(struct interface *ifp, const unsigned char *id,
const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen,
unsigned short seqno, unsigned short metric,
unsigned char *channels, int channels_len)
{
if(!if_up(ifp))
return;
if((ifp->flags & IF_UNICAST) != 0) {
struct neighbour *neigh;
FOR_ALL_NEIGHBOURS(neigh) {
if(neigh->ifp == ifp) {
really_buffer_update(&neigh->buf, ifp, id,
prefix, plen, src_prefix, src_plen,
seqno, metric, channels, channels_len);
}
}
} else {
really_buffer_update(&ifp->buf, ifp, id,
prefix, plen, src_prefix, src_plen,
seqno, metric, channels, channels_len);
} }
} }
...@@ -1512,7 +1349,8 @@ flushupdates(struct interface *ifp) ...@@ -1512,7 +1349,8 @@ flushupdates(struct interface *ifp)
really_send_update(ifp, route->src->id, really_send_update(ifp, route->src->id,
route->src->prefix, route->src->plen, route->src->prefix, route->src->plen,
route->src->src_prefix, route->src->src_plen, route->src->src_prefix,
route->src->src_plen,
seqno, metric, seqno, metric,
channels, chlen); channels, chlen);
update_source(route->src, seqno, metric); update_source(route->src, seqno, metric);
...@@ -1523,12 +1361,23 @@ flushupdates(struct interface *ifp) ...@@ -1523,12 +1361,23 @@ flushupdates(struct interface *ifp)
} else { } else {
/* There's no route for this prefix. This can happen shortly /* There's no route for this prefix. This can happen shortly
after an xroute has been retracted, so send a retraction. */ after an xroute has been retracted, so send a retraction. */
really_send_update(ifp, myid, b[i].prefix, b[i].plen, really_send_update(ifp, myid,
b[i].prefix, b[i].plen,
b[i].src_prefix, b[i].src_plen, b[i].src_prefix, b[i].src_plen,
myseqno, INFINITY, NULL, -1); myseqno, INFINITY, NULL, -1);
} }
} }
schedule_flush_now(ifp);
if((ifp->flags & IF_UNICAST) != 0) {
struct neighbour *neigh;
FOR_ALL_NEIGHBOURS(neigh) {
if(neigh->ifp == ifp) {
schedule_flush_now(&neigh->buf);
}
}
} else {
schedule_flush_now(&ifp->buf);
}
done: done:
free(b); free(b);
} }
...@@ -1563,7 +1412,7 @@ buffer_update(struct interface *ifp, ...@@ -1563,7 +1412,7 @@ buffer_update(struct interface *ifp,
number of installed routes will grow over time, make sure we number of installed routes will grow over time, make sure we
have enough space to send a full-ish frame. */ have enough space to send a full-ish frame. */
n = installed_routes_estimate() + xroutes_estimate() + 4; n = installed_routes_estimate() + xroutes_estimate() + 4;
n = MAX(n, ifp->bufsize / 16); n = MAX(n, ifp->buf.size / 16);
again: again:
ifp->buffered_updates = malloc(n * sizeof(struct buffered_update)); ifp->buffered_updates = malloc(n * sizeof(struct buffered_update));
if(ifp->buffered_updates == NULL) { if(ifp->buffered_updates == NULL) {
...@@ -1643,10 +1492,7 @@ send_update(struct interface *ifp, int urgent, ...@@ -1643,10 +1492,7 @@ send_update(struct interface *ifp, int urgent,
fprintf(stderr, "Couldn't allocate route stream.\n"); fprintf(stderr, "Couldn't allocate route stream.\n");
} }
set_timeout(&ifp->update_timeout, ifp->update_interval); set_timeout(&ifp->update_timeout, ifp->update_interval);
if(!prefix) ifp->last_update_time = now.tv_sec;
ifp->last_update_time = now.tv_sec;
else
ifp->last_specific_update_time = now.tv_sec;
} else { } else {
send_update(ifp, urgent, NULL, 0, zeroes, 0); send_update(ifp, urgent, NULL, 0, zeroes, 0);
send_update(ifp, urgent, zeroes, 0, NULL, 0); send_update(ifp, urgent, zeroes, 0, NULL, 0);
...@@ -1666,6 +1512,23 @@ send_update_resend(struct interface *ifp, ...@@ -1666,6 +1512,23 @@ send_update_resend(struct interface *ifp,
0, NULL, NULL, resend_delay); 0, NULL, NULL, resend_delay);
} }
void
buffer_wildcard_retraction(struct buffered *buf)
{
start_message(buf, MESSAGE_UPDATE, 10);
accumulate_byte(buf, 0);
accumulate_byte(buf, 0);
accumulate_byte(buf, 0);
accumulate_byte(buf, 0);
accumulate_short(buf, 0xFFFF);
accumulate_short(buf, myseqno);
accumulate_short(buf, 0xFFFF);
end_message(buf, MESSAGE_UPDATE, 10);
buf->have_id = 0;
}
void void
send_wildcard_retraction(struct interface *ifp) send_wildcard_retraction(struct interface *ifp)
{ {
...@@ -1679,17 +1542,16 @@ send_wildcard_retraction(struct interface *ifp) ...@@ -1679,17 +1542,16 @@ send_wildcard_retraction(struct interface *ifp)
if(!if_up(ifp)) if(!if_up(ifp))
return; return;
start_message(ifp, MESSAGE_UPDATE, 10); if((ifp->flags & IF_UNICAST) != 0) {
accumulate_byte(ifp, 0); struct neighbour *neigh;
accumulate_byte(ifp, 0); FOR_ALL_NEIGHBOURS(neigh) {
accumulate_byte(ifp, 0); if(neigh->ifp == ifp) {
accumulate_byte(ifp, 0); buffer_wildcard_retraction(&neigh->buf);
accumulate_short(ifp, 0xFFFF); }
accumulate_short(ifp, myseqno); }
accumulate_short(ifp, 0xFFFF); } else {
end_message(ifp, MESSAGE_UPDATE, 10); buffer_wildcard_retraction(&ifp->buf);
}
ifp->have_buffered_id = 0;
} }
void void
...@@ -1728,13 +1590,40 @@ send_self_update(struct interface *ifp) ...@@ -1728,13 +1590,40 @@ send_self_update(struct interface *ifp)
} }
} }
void
buffer_ihu(struct buffered *buf, unsigned short rxcost,
unsigned short interval, const unsigned char *address,
int rtt_data, unsigned int t1, unsigned int t2)
{
int msglen, ll;
ll = linklocal(address);
msglen = (ll ? 14 : 200) + (rtt_data ? 10 : 0);
start_message(buf, MESSAGE_IHU, msglen);
accumulate_byte(buf, ll ? 3 : 2);
accumulate_byte(buf, 0);
accumulate_short(buf, rxcost);
accumulate_short(buf, interval);
if(ll)
accumulate_bytes(buf, address + 8, 8);
else
accumulate_bytes(buf, address, 16);
if(rtt_data) {
accumulate_byte(buf, SUBTLV_TIMESTAMP);
accumulate_byte(buf, 8);
accumulate_int(buf, t1);
accumulate_int(buf, t2);
}
end_message(buf, MESSAGE_IHU, msglen);
}
void void
send_ihu(struct neighbour *neigh, struct interface *ifp) send_ihu(struct neighbour *neigh, struct interface *ifp)
{ {
int rxcost, interval; int rxcost, interval;
int ll;
int send_rtt_data; int send_rtt_data;
int msglen;
if(neigh == NULL && ifp == NULL) { if(neigh == NULL && ifp == NULL) {
struct interface *ifp_aux; struct interface *ifp_aux;
...@@ -1765,19 +1654,12 @@ send_ihu(struct neighbour *neigh, struct interface *ifp) ...@@ -1765,19 +1654,12 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
rxcost = neighbour_rxcost(neigh); rxcost = neighbour_rxcost(neigh);
interval = (ifp->hello_interval * 3 + 9) / 10; interval = (ifp->hello_interval * 3 + 9) / 10;
/* Conceptually, an IHU is a unicast message. We usually send them as debugf("Sending ihu %d on %s to %s.\n",
multicast, since this allows aggregation into a single packet and
avoids an ARP exchange. If we already have a unicast message queued
for this neighbour, however, we might as well piggyback the IHU. */
debugf("Sending %sihu %d on %s to %s.\n",
unicast_neighbour == neigh ? "unicast " : "",
rxcost, rxcost,
neigh->ifp->name, neigh->ifp->name,
format_address(neigh->address)); format_address(neigh->address));
ll = linklocal(neigh->address); if(ifp->buf.enable_timestamps && neigh->hello_send_us &&
if((ifp->flags & IF_TIMESTAMPS) && neigh->hello_send_us &&
/* Checks whether the RTT data is not too old to be sent. */ /* Checks whether the RTT data is not too old to be sent. */
timeval_minus_msec(&now, &neigh->hello_rtt_receive_time) < 1000000) { timeval_minus_msec(&now, &neigh->hello_rtt_receive_time) < 1000000) {
send_rtt_data = 1; send_rtt_data = 1;
...@@ -1786,48 +1668,10 @@ send_ihu(struct neighbour *neigh, struct interface *ifp) ...@@ -1786,48 +1668,10 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
send_rtt_data = 0; send_rtt_data = 0;
} }
/* The length depends on the format of the address, and then an buffer_ihu(&ifp->buf, rxcost, interval, neigh->address,
optional 10-bytes sub-TLV for timestamps (used to compute a RTT). */ send_rtt_data, neigh->hello_send_us,
msglen = (ll ? 14 : 22) + (send_rtt_data ? 10 : 0); time_us(neigh->hello_rtt_receive_time));
if(unicast_neighbour != neigh) {
start_message(ifp, MESSAGE_IHU, msglen);
accumulate_byte(ifp, ll ? 3 : 2);
accumulate_byte(ifp, 0);
accumulate_short(ifp, rxcost);
accumulate_short(ifp, interval);
if(ll)
accumulate_bytes(ifp, neigh->address + 8, 8);
else
accumulate_bytes(ifp, neigh->address, 16);
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, msglen);
if(rc < 0) return;
accumulate_unicast_byte(neigh, ll ? 3 : 2);
accumulate_unicast_byte(neigh, 0);
accumulate_unicast_short(neigh, rxcost);
accumulate_unicast_short(neigh, interval);
if(ll)
accumulate_unicast_bytes(neigh, neigh->address + 8, 8);
else
accumulate_unicast_bytes(neigh, neigh->address, 16);
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);
}
} }
/* Send IHUs to all marginal neighbours */ /* Send IHUs to all marginal neighbours */
...@@ -1845,83 +1689,86 @@ send_marginal_ihu(struct interface *ifp) ...@@ -1845,83 +1689,86 @@ send_marginal_ihu(struct interface *ifp)
/* Standard wildcard request with prefix == NULL && src_prefix == zeroes, /* Standard wildcard request with prefix == NULL && src_prefix == zeroes,
Specific wildcard request with prefix == zeroes && src_prefix == NULL. */ Specific wildcard request with prefix == zeroes && src_prefix == NULL. */
void static void
send_request(struct interface *ifp, send_request(struct buffered *buf,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen) const unsigned char *src_prefix, unsigned char src_plen)
{ {
int v4, pb, spb, len, is_ss; int v4, pb, spb, len;
int is_ss = !is_default(src_prefix, src_plen);
if(ifp == NULL) {
struct interface *ifp_aux;
FOR_ALL_INTERFACES(ifp_aux) {
if(!if_up(ifp_aux))
continue;
send_request(ifp_aux, prefix, plen, src_prefix, src_plen);
}
return;
}
/* make sure any buffered updates go out before this request. */
flushupdates(ifp);
if(!if_up(ifp)) if(is_ss && buf->rfc6126_compatible)
return; return;
if(prefix && src_prefix) { if(!prefix) {
debugf("sending request to %s for %s from %s.\n", ifp->name, assert(!src_prefix);
format_prefix(prefix, plen), debugf("sending request for any.\n");
format_prefix(src_prefix, src_plen)); start_message(buf, MESSAGE_REQUEST, 2);
} else if(prefix) { accumulate_byte(buf, 0);
debugf("sending request to %s for any specific.\n", ifp->name); accumulate_byte(buf, 0);
start_message(ifp, MESSAGE_REQUEST_SRC_SPECIFIC, 3); end_message(buf, MESSAGE_REQUEST, 2);
accumulate_byte(ifp, 0);
accumulate_byte(ifp, 0);
accumulate_byte(ifp, 0);
end_message(ifp, MESSAGE_REQUEST_SRC_SPECIFIC, 3);
return;
} else if(src_prefix) {
debugf("sending request to %s for any.\n", ifp->name);
start_message(ifp, MESSAGE_REQUEST, 2);
accumulate_byte(ifp, 0);
accumulate_byte(ifp, 0);
end_message(ifp, MESSAGE_REQUEST, 2);
return;
} else {
send_request(ifp, NULL, 0, zeroes, 0);
send_request(ifp, zeroes, 0, NULL, 0);
return; return;
} }
debugf("sending request for %s from %s.\n",
format_prefix(prefix, plen),
format_prefix(src_prefix, src_plen));
v4 = plen >= 96 && v4mapped(prefix); v4 = plen >= 96 && v4mapped(prefix);
pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8;
len = 2 + pb; spb = v4 ? ((src_plen - 96) + 7) / 8 : (src_plen + 7) / 8;
len = 2 + pb + (is_ss ? 3 + spb : 0);
is_ss = !is_default(src_prefix, src_plen); start_message(buf, MESSAGE_REQUEST, len);
if(is_ss) { accumulate_byte(buf, v4 ? 1 : 2);
spb = v4 ? ((src_plen - 96) + 7) / 8 : (src_plen + 7) / 8; accumulate_byte(buf, v4 ? plen - 96 : plen);
len += spb + 1;
start_message(ifp, MESSAGE_REQUEST_SRC_SPECIFIC, len);
} else {
spb = 0;
start_message(ifp, MESSAGE_REQUEST, len);
}
accumulate_byte(ifp, v4 ? 1 : 2);
accumulate_byte(ifp, v4 ? plen - 96 : plen);
if(is_ss)
accumulate_byte(ifp, v4 ? src_plen - 96 : src_plen);
if(v4) if(v4)
accumulate_bytes(ifp, prefix + 12, pb); accumulate_bytes(buf, prefix + 12, pb);
else else
accumulate_bytes(ifp, prefix, pb); accumulate_bytes(buf, prefix, pb);
if(is_ss) { if(is_ss) {
accumulate_byte(buf, SUBTLV_SOURCE_PREFIX);
accumulate_byte(buf, 1 + spb);
accumulate_byte(buf, v4 ? src_plen - 96 : src_plen);
if(v4) if(v4)
accumulate_bytes(ifp, src_prefix + 12, spb); accumulate_bytes(buf, src_prefix + 12, spb);
else else
accumulate_bytes(ifp, src_prefix, spb); accumulate_bytes(buf, src_prefix, spb);
end_message(ifp, MESSAGE_REQUEST_SRC_SPECIFIC, len); }
} else { end_message(buf, MESSAGE_REQUEST, len);
end_message(ifp, MESSAGE_REQUEST, len); }
void
send_multicast_request(struct interface *ifp,
const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen)
{
if(ifp == NULL) {
struct interface *ifp_auxn;
FOR_ALL_INTERFACES(ifp_auxn) {
if(if_up(ifp_auxn))
continue;
send_multicast_request(ifp_auxn, prefix, plen, src_prefix, src_plen);
}
return;
}
if(!if_up(ifp))
return;
/* make sure any buffered updates go out before this request. */
flushupdates(ifp);
if((ifp->flags & IF_UNICAST) != 0) {
struct neighbour *neigh;
FOR_ALL_NEIGHBOURS(neigh) {
if(neigh->ifp == ifp) {
send_request(&neigh->buf, prefix, plen,
src_prefix, src_plen);
} else {
send_request(&ifp->buf, prefix, plen, src_prefix, src_plen);
}
}
} }
} }
...@@ -1930,136 +1777,97 @@ send_unicast_request(struct neighbour *neigh, ...@@ -1930,136 +1777,97 @@ send_unicast_request(struct neighbour *neigh,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen) const unsigned char *src_prefix, unsigned char src_plen)
{ {
int rc, v4, pb, spb, len, is_ss; if(!if_up(neigh->ifp))
return;
/* make sure any buffered updates go out before this request. */
flushupdates(neigh->ifp); flushupdates(neigh->ifp);
if(prefix && src_prefix) { send_request(&neigh->buf, prefix, plen, src_prefix, src_plen);
debugf("sending unicast request to %s for %s from %s.\n", }
format_address(neigh->address),
format_prefix(prefix, plen), static void
format_prefix(src_prefix, src_plen)); send_multihop_request(struct buffered *buf,
} else if(prefix) { const unsigned char *prefix, unsigned char plen,
debugf("sending unicast request to %s for any specific.\n", const unsigned char *src_prefix, unsigned char src_plen,
format_address(neigh->address)); unsigned short seqno, const unsigned char *id,
rc = start_unicast_message(neigh, MESSAGE_REQUEST_SRC_SPECIFIC, 3); unsigned short hop_count)
if(rc < 0) return; {
accumulate_unicast_byte(neigh, 0); int v4, pb, spb, len;
accumulate_unicast_byte(neigh, 0); int is_ss = !is_default(src_prefix, src_plen);
accumulate_unicast_byte(neigh, 0);
end_unicast_message(neigh, MESSAGE_REQUEST_SRC_SPECIFIC, 3); if(is_ss && buf->rfc6126_compatible)
return;
} else if(src_prefix) {
debugf("sending unicast request to %s for any.\n",
format_address(neigh->address));
rc = start_unicast_message(neigh, MESSAGE_REQUEST, 2);
if(rc < 0) return;
accumulate_unicast_byte(neigh, 0);
accumulate_unicast_byte(neigh, 0);
end_unicast_message(neigh, MESSAGE_REQUEST, 2);
return;
} else {
send_unicast_request(neigh, NULL, 0, zeroes, 0);
send_unicast_request(neigh, zeroes, 0, NULL, 0);
return; return;
}
debugf("Sending request (%d) for %s.\n",
hop_count, format_prefix(prefix, plen));
v4 = plen >= 96 && v4mapped(prefix); v4 = plen >= 96 && v4mapped(prefix);
pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8;
len = 2 + pb; spb = v4 ? ((src_plen - 96) + 7) / 8 : (src_plen + 7) / 8;
len = 6 + 8 + pb + (is_ss ? 3 + spb : 0);
is_ss = !is_default(src_prefix, src_plen);
if(is_ss) { start_message(buf, MESSAGE_MH_REQUEST, len);
spb = v4 ? ((src_plen - 96) + 7) / 8 : (src_plen + 7) / 8; accumulate_byte(buf, v4 ? 1 : 2);
len += spb + 1; accumulate_byte(buf, v4 ? plen - 96 : plen);
rc = start_unicast_message(neigh, MESSAGE_REQUEST_SRC_SPECIFIC, len); accumulate_short(buf, seqno);
} else { accumulate_byte(buf, hop_count);
spb = 0; accumulate_byte(buf, v4 ? src_plen - 96 : src_plen);
rc = start_unicast_message(neigh, MESSAGE_REQUEST, len); accumulate_bytes(buf, id, 8);
if(prefix) {
if(v4)
accumulate_bytes(buf, prefix + 12, pb);
else
accumulate_bytes(buf, prefix, pb);
} }
if(rc < 0) return;
accumulate_unicast_byte(neigh, v4 ? 1 : 2);
accumulate_unicast_byte(neigh, v4 ? plen - 96 : plen);
if(is_ss)
accumulate_unicast_byte(neigh, v4 ? src_plen - 96 : src_plen);
if(v4)
accumulate_unicast_bytes(neigh, prefix + 12, pb);
else
accumulate_unicast_bytes(neigh, prefix, pb);
if(is_ss) { if(is_ss) {
accumulate_byte(buf, SUBTLV_SOURCE_PREFIX);
accumulate_byte(buf, 1 + spb);
accumulate_byte(buf, v4 ? src_plen - 96 : src_plen);
if(v4) if(v4)
accumulate_unicast_bytes(neigh, src_prefix + 12, spb); accumulate_bytes(buf, src_prefix + 12, spb);
else else
accumulate_unicast_bytes(neigh, src_prefix, spb); accumulate_bytes(buf, src_prefix, spb);
end_unicast_message(neigh, MESSAGE_REQUEST_SRC_SPECIFIC, len);
} else {
end_unicast_message(neigh, MESSAGE_REQUEST, len);
} }
end_message(buf, MESSAGE_MH_REQUEST, len);
} }
void void
send_multihop_request(struct interface *ifp, send_multicast_multihop_request(struct interface *ifp,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen, const unsigned char *src_prefix, unsigned char src_plen,
unsigned short seqno, const unsigned char *id, unsigned short seqno, const unsigned char *id,
unsigned short hop_count) unsigned short hop_count)
{ {
int v4, pb, spb, len, is_ss;
/* Make sure any buffered updates go out before this request. */
flushupdates(ifp);
if(ifp == NULL) { if(ifp == NULL) {
struct interface *ifp_aux; struct interface *ifp_aux;
FOR_ALL_INTERFACES(ifp_aux) { FOR_ALL_INTERFACES(ifp_aux) {
if(!if_up(ifp_aux)) if(!if_up(ifp_aux))
continue; continue;
send_multihop_request(ifp_aux, prefix, plen, src_prefix, src_plen, send_multicast_multihop_request(ifp_aux,
seqno, id, hop_count); prefix, plen, src_prefix, src_plen,
seqno, id, hop_count);
} }
return; return;
} }
flushupdates(ifp);
if(!if_up(ifp)) if(!if_up(ifp))
return; return;
debugf("Sending request (%d) on %s for %s from %s.\n", if((ifp->flags & IF_UNICAST) != 0) {
hop_count, ifp->name, format_prefix(prefix, plen), struct neighbour *neigh;
format_prefix(src_prefix, src_plen)); FOR_ALL_NEIGHBOURS(neigh) {
v4 = plen >= 96 && v4mapped(prefix); if(neigh->ifp == ifp) {
pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; send_multihop_request(&neigh->buf, prefix, plen,
len = 6 + 8 + pb; src_prefix, src_plen,
seqno, id, hop_count);
is_ss = !is_default(src_prefix, src_plen); }
if(is_ss) { }
spb = v4 ? ((src_plen - 96) + 7) / 8 : (src_plen + 7) / 8;
len += spb;
start_message(ifp, MESSAGE_MH_REQUEST_SRC_SPECIFIC, len);
} else {
spb = 0;
start_message(ifp, MESSAGE_MH_REQUEST, len);
}
accumulate_byte(ifp, v4 ? 1 : 2);
accumulate_byte(ifp, v4 ? plen - 96 : plen);
accumulate_short(ifp, seqno);
accumulate_byte(ifp, hop_count);
accumulate_byte(ifp, v4 ? src_plen - 96 : src_plen);
accumulate_bytes(ifp, id, 8);
if(prefix) {
if(v4)
accumulate_bytes(ifp, prefix + 12, pb);
else
accumulate_bytes(ifp, prefix, pb);
}
if(is_ss) {
if(v4)
accumulate_bytes(ifp, src_prefix + 12, spb);
else
accumulate_bytes(ifp, src_prefix, spb);
end_message(ifp, MESSAGE_MH_REQUEST_SRC_SPECIFIC, len);
} else { } else {
end_message(ifp, MESSAGE_MH_REQUEST, len); send_multihop_request(&ifp->buf, prefix, plen,
src_prefix, src_plen,
seqno, id, hop_count);
} }
} }
...@@ -2071,50 +1879,9 @@ send_unicast_multihop_request(struct neighbour *neigh, ...@@ -2071,50 +1879,9 @@ send_unicast_multihop_request(struct neighbour *neigh,
unsigned short seqno, const unsigned char *id, unsigned short seqno, const unsigned char *id,
unsigned short hop_count) unsigned short hop_count)
{ {
int rc, v4, pb, spb, len, is_ss;
/* Make sure any buffered updates go out before this request. */
flushupdates(neigh->ifp); flushupdates(neigh->ifp);
send_multihop_request(&neigh->buf, prefix, plen, src_prefix, src_plen,
debugf("Sending multi-hop request to %s for %s from %s (%d hops).\n", seqno, id, hop_count);
format_address(neigh->address),
format_prefix(prefix, plen),
format_prefix(src_prefix, src_plen), hop_count);
v4 = plen >= 96 && v4mapped(prefix);
pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8;
len = 6 + 8 + pb;
is_ss = !is_default(src_prefix, src_plen);
if(is_ss) {
spb = v4 ? ((src_plen - 96) + 7) / 8 : (src_plen + 7) / 8;
len += spb;
rc = start_unicast_message(neigh, MESSAGE_MH_REQUEST_SRC_SPECIFIC, len);
} else {
spb = 0;
rc = start_unicast_message(neigh, MESSAGE_MH_REQUEST, len);
}
if(rc < 0) return;
accumulate_unicast_byte(neigh, v4 ? 1 : 2);
accumulate_unicast_byte(neigh, v4 ? plen - 96 : plen);
accumulate_unicast_short(neigh, seqno);
accumulate_unicast_byte(neigh, hop_count);
accumulate_unicast_byte(neigh, v4 ? src_plen - 96 : src_plen);
accumulate_unicast_bytes(neigh, id, 8);
if(prefix) {
if(v4)
accumulate_unicast_bytes(neigh, prefix + 12, pb);
else
accumulate_unicast_bytes(neigh, prefix, pb);
}
if(is_ss) {
if(v4)
accumulate_unicast_bytes(neigh, src_prefix + 12, spb);
else
accumulate_unicast_bytes(neigh, src_prefix, spb);
end_unicast_message(neigh, MESSAGE_MH_REQUEST_SRC_SPECIFIC, len);
} else {
end_unicast_message(neigh, MESSAGE_MH_REQUEST, len);
}
} }
/* Send a request to a well-chosen neighbour and resend. If there is no /* Send a request to a well-chosen neighbour and resend. If there is no
...@@ -2135,8 +1902,12 @@ send_request_resend(const unsigned char *prefix, unsigned char plen, ...@@ -2135,8 +1902,12 @@ send_request_resend(const unsigned char *prefix, unsigned char plen,
record_resend(RESEND_REQUEST, prefix, plen, src_prefix, src_plen, seqno, record_resend(RESEND_REQUEST, prefix, plen, src_prefix, src_plen, seqno,
id, neigh->ifp, resend_delay); id, neigh->ifp, resend_delay);
} else { } else {
send_multihop_request(NULL, prefix, plen, src_prefix, src_plen, struct interface *ifp;
seqno, id, 127); FOR_ALL_INTERFACES(ifp) {
if(!if_up(ifp)) continue;
send_multihop_request(&ifp->buf, prefix, plen, src_prefix, src_plen,
seqno, id, 127);
}
} }
} }
......
...@@ -22,9 +22,6 @@ THE SOFTWARE. ...@@ -22,9 +22,6 @@ THE SOFTWARE.
#define MAX_BUFFERED_UPDATES 200 #define MAX_BUFFERED_UPDATES 200
#define BUCKET_TOKENS_MAX 4000
#define BUCKET_TOKENS_PER_SEC 1000
#define MESSAGE_PAD1 0 #define MESSAGE_PAD1 0
#define MESSAGE_PADN 1 #define MESSAGE_PADN 1
#define MESSAGE_ACK_REQ 2 #define MESSAGE_ACK_REQ 2
...@@ -37,15 +34,13 @@ THE SOFTWARE. ...@@ -37,15 +34,13 @@ THE SOFTWARE.
#define MESSAGE_REQUEST 9 #define MESSAGE_REQUEST 9
#define MESSAGE_MH_REQUEST 10 #define MESSAGE_MH_REQUEST 10
/* 11 and 12 are for authentication */ /* 11 and 12 are for authentication */
#define MESSAGE_UPDATE_SRC_SPECIFIC 13
#define MESSAGE_REQUEST_SRC_SPECIFIC 14
#define MESSAGE_MH_REQUEST_SRC_SPECIFIC 15
/* Protocol extension through sub-TLVs. */ /* Protocol extension through sub-TLVs. */
#define SUBTLV_PAD1 0 #define SUBTLV_PAD1 0
#define SUBTLV_PADN 1 #define SUBTLV_PADN 1
#define SUBTLV_DIVERSITY 2 /* Also known as babelz. */ #define SUBTLV_DIVERSITY 2 /* Also known as babelz. */
#define SUBTLV_TIMESTAMP 3 /* Used to compute RTT. */ #define SUBTLV_TIMESTAMP 3 /* Used to compute RTT. */
#define SUBTLV_SOURCE_PREFIX 128 /* Source-specific routing. */
extern unsigned short myseqno; extern unsigned short myseqno;
extern struct timeval seqno_time; extern struct timeval seqno_time;
...@@ -55,16 +50,13 @@ extern int split_horizon; ...@@ -55,16 +50,13 @@ extern int split_horizon;
extern unsigned char packet_header[4]; extern unsigned char packet_header[4];
extern struct neighbour *unicast_neighbour;
extern struct timeval unicast_flush_timeout;
void parse_packet(const unsigned char *from, struct interface *ifp, void parse_packet(const unsigned char *from, struct interface *ifp,
const unsigned char *packet, int packetlen); const unsigned char *packet, int packetlen);
void flushbuf(struct interface *ifp); void flushbuf(struct buffered *buf);
void flushupdates(struct interface *ifp); void flushupdates(struct interface *ifp);
void send_ack(struct neighbour *neigh, unsigned short nonce, void send_ack(struct neighbour *neigh, unsigned short nonce,
unsigned short interval); unsigned short interval);
void send_hello_noupdate(struct interface *ifp, unsigned interval); void send_hello_noihu(struct interface *ifp, unsigned interval);
void send_hello(struct interface *ifp); void send_hello(struct interface *ifp);
void flush_unicast(int dofree); void flush_unicast(int dofree);
void send_update(struct interface *ifp, int urgent, void send_update(struct interface *ifp, int urgent,
...@@ -79,19 +71,20 @@ void update_myseqno(void); ...@@ -79,19 +71,20 @@ void update_myseqno(void);
void send_self_update(struct interface *ifp); void send_self_update(struct interface *ifp);
void send_ihu(struct neighbour *neigh, struct interface *ifp); void send_ihu(struct neighbour *neigh, struct interface *ifp);
void send_marginal_ihu(struct interface *ifp); void send_marginal_ihu(struct interface *ifp);
void send_request(struct interface *ifp, void send_multicast_request(struct interface *ifp,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen); const unsigned char *src_prefix, unsigned char src_plen);
void send_unicast_request(struct neighbour *neigh, void send_unicast_request(struct neighbour *neigh,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, const unsigned char *src_prefix,
unsigned char src_plen); unsigned char src_plen);
void send_multihop_request(struct interface *ifp, void
const unsigned char *prefix, unsigned char plen, send_multicast_multihop_request(struct interface *ifp,
const unsigned char *src_prefix, const unsigned char *prefix, unsigned char plen,
unsigned char src_plen, const unsigned char *src_prefix,
unsigned short seqno, const unsigned char *id, unsigned char src_plen,
unsigned short hop_count); unsigned short seqno, const unsigned char *id,
unsigned short hop_count);
void void
send_unicast_multihop_request(struct neighbour *neigh, send_unicast_multihop_request(struct neighbour *neigh,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
......
...@@ -24,6 +24,8 @@ THE SOFTWARE. ...@@ -24,6 +24,8 @@ THE SOFTWARE.
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h> #include <time.h>
#include <assert.h> #include <assert.h>
...@@ -55,8 +57,6 @@ void ...@@ -55,8 +57,6 @@ void
flush_neighbour(struct neighbour *neigh) flush_neighbour(struct neighbour *neigh)
{ {
flush_neighbour_routes(neigh); flush_neighbour_routes(neigh);
if(unicast_neighbour == neigh)
flush_unicast(1);
flush_resends(neigh); flush_resends(neigh);
if(neighs == neigh) { if(neighs == neigh) {
...@@ -68,6 +68,7 @@ flush_neighbour(struct neighbour *neigh) ...@@ -68,6 +68,7 @@ flush_neighbour(struct neighbour *neigh)
previous->next = neigh->next; previous->next = neigh->next;
} }
local_notify_neighbour(neigh, LOCAL_FLUSH); local_notify_neighbour(neigh, LOCAL_FLUSH);
free(neigh->buf.buf);
free(neigh); free(neigh);
} }
...@@ -76,6 +77,7 @@ find_neighbour(const unsigned char *address, struct interface *ifp) ...@@ -76,6 +77,7 @@ find_neighbour(const unsigned char *address, struct interface *ifp)
{ {
struct neighbour *neigh; struct neighbour *neigh;
const struct timeval zero = {0, 0}; const struct timeval zero = {0, 0};
char *buf;
neigh = find_neighbour_nocreate(address, ifp); neigh = find_neighbour_nocreate(address, ifp);
if(neigh) if(neigh)
...@@ -84,8 +86,15 @@ find_neighbour(const unsigned char *address, struct interface *ifp) ...@@ -84,8 +86,15 @@ find_neighbour(const unsigned char *address, struct interface *ifp)
debugf("Creating neighbour %s on %s.\n", debugf("Creating neighbour %s on %s.\n",
format_address(address), ifp->name); format_address(address), ifp->name);
buf = malloc(ifp->buf.size);
if(buf == NULL) {
perror("malloc(neighbour->buf)");
return NULL;
}
neigh = calloc(1, sizeof(struct neighbour)); neigh = calloc(1, sizeof(struct neighbour));
if(neigh == NULL) { if(neigh == NULL) {
free(buf);
perror("malloc(neighbour)"); perror("malloc(neighbour)");
return NULL; return NULL;
} }
...@@ -98,6 +107,13 @@ find_neighbour(const unsigned char *address, struct interface *ifp) ...@@ -98,6 +107,13 @@ find_neighbour(const unsigned char *address, struct interface *ifp)
neigh->hello_rtt_receive_time = zero; neigh->hello_rtt_receive_time = zero;
neigh->rtt_time = zero; neigh->rtt_time = zero;
neigh->ifp = ifp; neigh->ifp = ifp;
neigh->buf.buf = buf;
neigh->buf.size = ifp->buf.size;
neigh->buf.flush_interval = ifp->buf.flush_interval;
neigh->buf.sin6.sin6_family = AF_INET6;
memcpy(&neigh->buf.sin6.sin6_addr, address, 16);
neigh->buf.sin6.sin6_port = htons(protocol_port);
neigh->buf.sin6.sin6_scope_id = ifp->ifindex;
neigh->next = neighs; neigh->next = neighs;
neighs = neigh; neighs = neigh;
local_notify_neighbour(neigh, LOCAL_ADD); local_notify_neighbour(neigh, LOCAL_ADD);
...@@ -135,6 +151,11 @@ update_neighbour(struct neighbour *neigh, struct hello_history *hist, ...@@ -135,6 +151,11 @@ update_neighbour(struct neighbour *neigh, struct hello_history *hist,
missed_hellos = 0; missed_hellos = 0;
rc = 1; rc = 1;
} else if(missed_hellos < 0) { } else if(missed_hellos < 0) {
/* Late hello. Probably due to the link layer buffering
packets during a link outage or a cpu overload. */
fprintf(stderr,
"Late hello: bufferbloated neighbor %s\n",
format_address(neigh->address));
hist->reach <<= -missed_hellos; hist->reach <<= -missed_hellos;
missed_hellos = 0; missed_hellos = 0;
rc = 1; rc = 1;
......
...@@ -44,6 +44,7 @@ struct neighbour { ...@@ -44,6 +44,7 @@ struct neighbour {
unsigned int rtt; unsigned int rtt;
struct timeval rtt_time; struct timeval rtt_time;
struct interface *ifp; struct interface *ifp;
struct buffered buf;
}; };
extern struct neighbour *neighs; extern struct neighbour *neighs;
......
...@@ -24,13 +24,15 @@ THE SOFTWARE. ...@@ -24,13 +24,15 @@ THE SOFTWARE.
#include <time.h> #include <time.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "babeld.h" #include "babeld.h"
#include "util.h" #include "util.h"
#include "interface.h"
#include "neighbour.h" #include "neighbour.h"
#include "resend.h" #include "resend.h"
#include "message.h" #include "message.h"
#include "interface.h"
#include "configuration.h" #include "configuration.h"
struct timeval resend_time = {0, 0}; struct timeval resend_time = {0, 0};
...@@ -304,10 +306,12 @@ do_resend() ...@@ -304,10 +306,12 @@ do_resend()
if(timeval_compare(&now, &timeout) >= 0) { if(timeval_compare(&now, &timeout) >= 0) {
switch(resend->kind) { switch(resend->kind) {
case RESEND_REQUEST: case RESEND_REQUEST:
send_multihop_request(resend->ifp, send_multicast_multihop_request(resend->ifp,
resend->prefix, resend->plen, resend->prefix, resend->plen,
resend->src_prefix, resend->src_plen, resend->src_prefix,
resend->seqno, resend->id, 127); resend->src_plen,
resend->seqno, resend->id,
127);
break; break;
case RESEND_UPDATE: case RESEND_UPDATE:
send_update(resend->ifp, 1, send_update(resend->ifp, 1,
......
...@@ -1139,8 +1139,8 @@ send_triggered_update(struct babel_route *route, struct source *oldsrc, ...@@ -1139,8 +1139,8 @@ send_triggered_update(struct babel_route *route, struct source *oldsrc,
if(oldmetric < INFINITY) { if(oldmetric < INFINITY) {
if(newmetric >= oldmetric + 288) { if(newmetric >= oldmetric + 288) {
send_request(NULL, route->src->prefix, route->src->plen, send_multicast_request(NULL, route->src->prefix, route->src->plen,
route->src->src_prefix, route->src->src_plen); route->src->src_prefix, route->src->src_plen);
} }
} }
} }
......
...@@ -24,6 +24,8 @@ THE SOFTWARE. ...@@ -24,6 +24,8 @@ THE SOFTWARE.
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <assert.h> #include <assert.h>
#include "babeld.h" #include "babeld.h"
......
...@@ -302,7 +302,7 @@ format_thousands(unsigned int value) ...@@ -302,7 +302,7 @@ format_thousands(unsigned int value)
static char buf[4][15]; static char buf[4][15];
static int i = 0; static int i = 0;
i = (i + 1) % 4; i = (i + 1) % 4;
snprintf(buf[i], 15, "%d.%.3d", value / 1000, value % 1000); snprintf(buf[i], 15, "%u.%.3u", value / 1000, value % 1000);
return buf[i]; return buf[i];
} }
......
...@@ -88,7 +88,7 @@ unsigned char *normalize_prefix(unsigned char *restrict ret, ...@@ -88,7 +88,7 @@ unsigned char *normalize_prefix(unsigned char *restrict ret,
const unsigned char *restrict prefix, const unsigned char *restrict prefix,
unsigned char plen); unsigned char plen);
const char *format_address(const unsigned char *address); const char *format_address(const unsigned char *address);
const char *format_prefix(const unsigned char *address, unsigned char prefix); const char *format_prefix(const unsigned char *prefix, unsigned char plen);
const char *format_eui64(const unsigned char *eui); const char *format_eui64(const unsigned char *eui);
const char *format_thousands(unsigned int value); const char *format_thousands(unsigned int value);
int parse_address(const char *address, unsigned char *addr_r, int *af_r); int parse_address(const char *address, unsigned char *addr_r, int *af_r);
...@@ -161,4 +161,3 @@ static inline void kdebugf(const char *format, ...) { return; } ...@@ -161,4 +161,3 @@ static inline void kdebugf(const char *format, ...) { return; }
#endif #endif
#endif #endif
...@@ -30,33 +30,128 @@ THE SOFTWARE. ...@@ -30,33 +30,128 @@ THE SOFTWARE.
#include "babeld.h" #include "babeld.h"
#include "kernel.h" #include "kernel.h"
#include "interface.h"
#include "neighbour.h" #include "neighbour.h"
#include "message.h" #include "message.h"
#include "source.h"
#include "route.h" #include "route.h"
#include "xroute.h" #include "xroute.h"
#include "util.h" #include "util.h"
#include "configuration.h" #include "configuration.h"
#include "interface.h"
#include "local.h" #include "local.h"
static struct xroute *xroutes; static struct xroute *xroutes;
static int numxroutes = 0, maxxroutes = 0; static int numxroutes = 0, maxxroutes = 0;
static int
xroute_compare(const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen,
const struct xroute *xroute)
{
int rc;
if(plen < xroute->plen)
return -1;
if(plen > xroute->plen)
return 1;
rc = memcmp(prefix, xroute->prefix, 16);
if(rc != 0)
return rc;
if(src_plen < xroute->src_plen)
return -1;
if(src_plen > xroute->src_plen)
return 1;
rc = memcmp(src_prefix, xroute->src_prefix, 16);
if(rc != 0)
return rc;
return 0;
}
static int
find_xroute_slot(const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen,
int *new_return)
{
int p, m, g, c;
if(numxroutes < 1) {
if(new_return)
*new_return = 0;
return -1;
}
p = 0; g = numxroutes - 1;
do {
m = (p + g) / 2;
c = xroute_compare(prefix, plen, src_prefix, src_plen, &xroutes[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 xroute * struct xroute *
find_xroute(const unsigned char *prefix, unsigned char plen, find_xroute(const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen) const unsigned char *src_prefix, unsigned char src_plen)
{ {
int i; int i = find_xroute_slot(prefix, plen, src_prefix, src_plen, NULL);
for(i = 0; i < numxroutes; i++) { if(i >= 0)
if(xroutes[i].plen == plen && return &xroutes[i];
memcmp(xroutes[i].prefix, prefix, 16) == 0 &&
xroutes[i].src_plen == src_plen &&
memcmp(xroutes[i].src_prefix, src_prefix, 16) == 0)
return &xroutes[i];
}
return NULL; return NULL;
} }
int
add_xroute(unsigned char prefix[16], unsigned char plen,
unsigned char src_prefix[16], unsigned char src_plen,
unsigned short metric, unsigned int ifindex, int proto)
{
int n = -1;
int i = find_xroute_slot(prefix, plen, src_prefix, src_plen, &n);
if(i >= 0)
return -1;
if(numxroutes >= maxxroutes) {
struct xroute *new_xroutes;
int num = maxxroutes < 1 ? 8 : 2 * maxxroutes;
new_xroutes = realloc(xroutes, num * sizeof(struct xroute));
if(new_xroutes == NULL)
return -1;
maxxroutes = num;
xroutes = new_xroutes;
}
if(n < numxroutes)
memmove(xroutes + n + 1, xroutes + n,
(numxroutes - n) * sizeof(struct xroute));
numxroutes++;
memcpy(xroutes[n].prefix, prefix, 16);
xroutes[n].plen = plen;
memcpy(xroutes[n].src_prefix, src_prefix, 16);
xroutes[n].src_plen = src_plen;
xroutes[n].metric = metric;
xroutes[n].ifindex = ifindex;
xroutes[n].proto = proto;
local_notify_xroute(&xroutes[n], LOCAL_ADD);
return 1;
}
void void
flush_xroute(struct xroute *xroute) flush_xroute(struct xroute *xroute)
{ {
...@@ -68,7 +163,8 @@ flush_xroute(struct xroute *xroute) ...@@ -68,7 +163,8 @@ flush_xroute(struct xroute *xroute)
local_notify_xroute(xroute, LOCAL_FLUSH); local_notify_xroute(xroute, LOCAL_FLUSH);
if(i != numxroutes - 1) if(i != numxroutes - 1)
memcpy(xroutes + i, xroutes + numxroutes - 1, sizeof(struct xroute)); memmove(xroutes + i, xroutes + i + 1,
(numxroutes - i - 1) * sizeof(struct xroute));
numxroutes--; numxroutes--;
VALGRIND_MAKE_MEM_UNDEFINED(xroutes + numxroutes, sizeof(struct xroute)); VALGRIND_MAKE_MEM_UNDEFINED(xroutes + numxroutes, sizeof(struct xroute));
...@@ -87,42 +183,6 @@ flush_xroute(struct xroute *xroute) ...@@ -87,42 +183,6 @@ flush_xroute(struct xroute *xroute)
} }
} }
int
add_xroute(unsigned char prefix[16], unsigned char plen,
unsigned char src_prefix[16], unsigned char src_plen,
unsigned short metric, unsigned int ifindex, int proto)
{
struct xroute *xroute = find_xroute(prefix, plen, src_prefix, src_plen);
if(xroute) {
if(xroute->metric <= metric)
return 0;
xroute->metric = metric;
local_notify_xroute(xroute, LOCAL_CHANGE);
return 1;
}
if(numxroutes >= maxxroutes) {
struct xroute *new_xroutes;
int n = maxxroutes < 1 ? 8 : 2 * maxxroutes;
new_xroutes = realloc(xroutes, n * sizeof(struct xroute));
if(new_xroutes == NULL)
return -1;
maxxroutes = n;
xroutes = new_xroutes;
}
memcpy(xroutes[numxroutes].prefix, prefix, 16);
xroutes[numxroutes].plen = plen;
memcpy(xroutes[numxroutes].src_prefix, src_prefix, 16);
xroutes[numxroutes].src_plen = src_plen;
xroutes[numxroutes].metric = metric;
xroutes[numxroutes].ifindex = ifindex;
xroutes[numxroutes].proto = proto;
numxroutes++;
local_notify_xroute(&xroutes[numxroutes - 1], LOCAL_ADD);
return 1;
}
/* Returns an overestimate of the number of xroutes. */ /* Returns an overestimate of the number of xroutes. */
int int
xroutes_estimate() xroutes_estimate()
...@@ -244,15 +304,44 @@ kernel_addresses(int ifindex, int ll, struct kernel_route *routes, ...@@ -244,15 +304,44 @@ kernel_addresses(int ifindex, int ll, struct kernel_route *routes,
return found; return found;
} }
/* This must coincide with the ordering defined by xroute_compare above. */
static int
kernel_route_compare(const void *v1, const void *v2)
{
const struct kernel_route *route1 = (struct kernel_route*)v1;
const struct kernel_route *route2 = (struct kernel_route*)v2;
int rc;
if(route1->plen < route2->plen)
return -1;
if(route1->plen > route2->plen)
return 1;
rc = memcmp(route1->prefix, route2->prefix, 16);
if(rc != 0)
return rc;
if(route1->src_plen < route2->src_plen)
return -1;
if(route1->src_plen > route2->src_plen)
return 1;
rc = memcmp(route1->src_prefix, route2->src_prefix, 16);
if(rc != 0)
return rc;
return 0;
}
int int
check_xroutes(int send_updates) check_xroutes(int send_updates)
{ {
int i, j, metric, export, change = 0, rc; int i, j, change = 0, rc;
struct kernel_route *routes; struct kernel_route *routes;
struct filter_result filter_result; struct filter_result filter_result;
int numroutes, numaddresses; int numroutes;
static int maxroutes = 8; static int maxroutes = 8;
const int maxmaxroutes = 16 * 1024; const int maxmaxroutes = 256 * 1024;
debugf("\nChecking kernel routes.\n"); debugf("\nChecking kernel routes.\n");
...@@ -272,8 +361,6 @@ check_xroutes(int send_updates) ...@@ -272,8 +361,6 @@ check_xroutes(int send_updates)
if(numroutes >= maxroutes) if(numroutes >= maxroutes)
goto resize; goto resize;
numaddresses = numroutes;
rc = kernel_routes(routes + numroutes, maxroutes - numroutes); rc = kernel_routes(routes + numroutes, maxroutes - numroutes);
if(rc < 0) if(rc < 0)
fprintf(stderr, "Couldn't get kernel routes.\n"); fprintf(stderr, "Couldn't get kernel routes.\n");
...@@ -283,42 +370,65 @@ check_xroutes(int send_updates) ...@@ -283,42 +370,65 @@ check_xroutes(int send_updates)
if(numroutes >= maxroutes) if(numroutes >= maxroutes)
goto resize; goto resize;
/* Apply filter to kernel routes (e.g. change the source prefix). */ for(i = 0; i < numroutes; i++) {
routes[i].metric = redistribute_filter(routes[i].prefix, routes[i].plen,
for(i = numaddresses; i < numroutes; i++) { routes[i].src_prefix,
redistribute_filter(routes[i].prefix, routes[i].plen, routes[i].src_plen,
routes[i].src_prefix, routes[i].src_plen, routes[i].ifindex,
routes[i].ifindex, routes[i].proto, routes[i].proto,
&filter_result); &filter_result);
if(filter_result.src_prefix) { if(filter_result.src_prefix != NULL) {
memcpy(routes[i].src_prefix, filter_result.src_prefix, 16); memcpy(routes[i].src_prefix, filter_result.src_prefix, 16);
routes[i].src_plen = filter_result.src_plen; routes[i].src_plen = filter_result.src_plen;
} }
} }
/* Check for any routes that need to be flushed */ qsort(routes, numroutes, sizeof(struct kernel_route), kernel_route_compare);
i = 0; i = 0;
while(i < numxroutes) { j = 0;
export = 0; while(i < numroutes || j < numxroutes) {
metric = redistribute_filter(xroutes[i].prefix, xroutes[i].plen, /* Ignore routes filtered out. */
xroutes[i].src_prefix, xroutes[i].src_plen, if(i < numroutes && routes[i].metric >= INFINITY) {
xroutes[i].ifindex, xroutes[i].proto, i++;
NULL); continue;
if(metric < INFINITY && metric == xroutes[i].metric) {
for(j = 0; j < numroutes; j++) {
if(xroutes[i].plen == routes[j].plen &&
memcmp(xroutes[i].prefix, routes[j].prefix, 16) == 0 &&
xroutes[i].ifindex == routes[j].ifindex &&
xroutes[i].proto == routes[j].proto) {
export = 1;
break;
}
}
} }
if(!export) { if(i >= numroutes)
rc = +1;
else if(j >= numxroutes)
rc = -1;
else
rc = xroute_compare(routes[i].prefix, routes[i].plen,
routes[i].src_prefix, routes[i].src_plen,
&xroutes[j]);
if(rc < 0) {
/* Add route i. */
if(!martian_prefix(routes[i].prefix, routes[i].plen) &&
routes[i].metric < INFINITY) {
rc = add_xroute(routes[i].prefix, routes[i].plen,
routes[i].src_prefix, routes[i].src_plen,
routes[i].metric, routes[i].ifindex,
routes[i].proto);
if(rc > 0) {
struct babel_route *route;
route = find_installed_route(routes[i].prefix,
routes[i].plen,
routes[i].src_prefix,
routes[i].src_plen);
if(route) {
if(allow_duplicates < 0 ||
routes[i].metric < allow_duplicates)
uninstall_route(route);
}
if(send_updates)
send_update(NULL, 0, routes[i].prefix, routes[i].plen,
routes[i].src_prefix, routes[i].src_plen);
j++;
}
}
i++;
} else if(rc > 0) {
/* Flush xroute j. */
unsigned char prefix[16], plen; unsigned char prefix[16], plen;
unsigned char src_prefix[16], src_plen; unsigned char src_prefix[16], src_plen;
struct babel_route *route; struct babel_route *route;
...@@ -326,47 +436,27 @@ check_xroutes(int send_updates) ...@@ -326,47 +436,27 @@ check_xroutes(int send_updates)
plen = xroutes[i].plen; plen = xroutes[i].plen;
memcpy(src_prefix, xroutes[i].src_prefix, 16); memcpy(src_prefix, xroutes[i].src_prefix, 16);
src_plen = xroutes[i].src_plen; src_plen = xroutes[i].src_plen;
flush_xroute(&xroutes[i]); flush_xroute(&xroutes[j]);
route = find_best_route(prefix, plen, src_prefix, src_plen, 1,NULL); route = find_best_route(prefix, plen, src_prefix, src_plen,
if(route) 1, NULL);
if(route != NULL) {
install_route(route); install_route(route);
/* send_update_resend only records the prefix, so the update send_update(NULL, 0, prefix, plen, src_prefix, src_plen);
will only be sent after we perform all of the changes. */ } else {
if(send_updates)
send_update_resend(NULL, prefix, plen, src_prefix, src_plen); send_update_resend(NULL, prefix, plen, src_prefix, src_plen);
change = 1; }
} else { } else {
i++; if(routes[i].metric != xroutes[j].metric ||
} routes[i].proto != xroutes[j].proto) {
} xroutes[j].metric = routes[i].metric;
xroutes[j].proto = routes[i].proto;
/* Add any new routes */ local_notify_xroute(&xroutes[j], LOCAL_CHANGE);
for(i = 0; i < numroutes; i++) {
if(martian_prefix(routes[i].prefix, routes[i].plen))
continue;
metric = redistribute_filter(routes[i].prefix, routes[i].plen,
routes[i].src_prefix, routes[i].src_plen,
routes[i].ifindex, routes[i].proto, NULL);
if(metric < INFINITY) {
rc = add_xroute(routes[i].prefix, routes[i].plen,
routes[i].src_prefix, routes[i].src_plen,
metric, routes[i].ifindex, routes[i].proto);
if(rc > 0) {
struct babel_route *route;
route = find_installed_route(routes[i].prefix, routes[i].plen,
routes[i].src_prefix,
routes[i].src_plen);
if(route) {
if(allow_duplicates < 0 ||
routes[i].metric < allow_duplicates)
uninstall_route(route);
}
change = 1;
if(send_updates) if(send_updates)
send_update(NULL, 0, routes[i].prefix, routes[i].plen, send_update(NULL, 0, xroutes[j].prefix, xroutes[j].plen,
routes[i].src_prefix, routes[i].src_plen); xroutes[j].src_prefix, xroutes[j].src_plen);
} }
i++;
j++;
} }
} }
......
...@@ -34,10 +34,10 @@ struct xroute_stream; ...@@ -34,10 +34,10 @@ struct xroute_stream;
struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen, struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen); const unsigned char *src_prefix, unsigned char src_plen);
void flush_xroute(struct xroute *xroute);
int add_xroute(unsigned char prefix[16], unsigned char plen, int add_xroute(unsigned char prefix[16], unsigned char plen,
unsigned char src_prefix[16], unsigned char src_plen, unsigned char src_prefix[16], unsigned char src_plen,
unsigned short metric, unsigned int ifindex, int proto); unsigned short metric, unsigned int ifindex, int proto);
void flush_xroute(struct xroute *xroute);
int xroutes_estimate(void); int xroutes_estimate(void);
struct xroute_stream *xroute_stream(); struct xroute_stream *xroute_stream();
struct xroute *xroute_stream_next(struct xroute_stream *stream); struct xroute *xroute_stream_next(struct xroute_stream *stream);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment