Commit 21045b56 authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Implement protocol version 1.

This is not compatible with version 0.  Uses 24-byte messages and
doesn't distinguish routes from xroutes.
parent b9f132d5
...@@ -42,7 +42,7 @@ THE SOFTWARE. ...@@ -42,7 +42,7 @@ THE SOFTWARE.
#include "util.h" #include "util.h"
#include "net.h" #include "net.h"
#include "kernel.h" #include "kernel.h"
#include "destination.h" #include "source.h"
#include "neighbour.h" #include "neighbour.h"
#include "route.h" #include "route.h"
#include "xroute.h" #include "xroute.h"
...@@ -64,12 +64,13 @@ int wired_hello_interval = -1; ...@@ -64,12 +64,13 @@ int wired_hello_interval = -1;
int idle_hello_interval = -1; int idle_hello_interval = -1;
int update_interval = -1; int update_interval = -1;
int max_request_hopcount = 65;
struct network nets[MAXNETS]; struct network nets[MAXNETS];
int numnets = 0; int numnets = 0;
const unsigned char zeroes[16] = {0}; const unsigned char zeroes[16] = {0};
const unsigned char ones[16] =
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
char *state_file = "/var/lib/babel-state"; char *state_file = "/var/lib/babel-state";
...@@ -83,8 +84,6 @@ static volatile sig_atomic_t exiting = 0, dumping = 0; ...@@ -83,8 +84,6 @@ static volatile sig_atomic_t exiting = 0, dumping = 0;
struct network *add_network(char *ifname, int ifindex, int bufsize, struct network *add_network(char *ifname, int ifindex, int bufsize,
int wired, unsigned int cost); int wired, unsigned int cost);
void expire_routes(void);
static int kernel_routes_callback(void *closure); static int kernel_routes_callback(void *closure);
static void init_signals(void); static void init_signals(void);
static void dump_tables(FILE *out); static void dump_tables(FILE *out);
...@@ -96,6 +95,7 @@ main(int argc, char **argv) ...@@ -96,6 +95,7 @@ main(int argc, char **argv)
struct ipv6_mreq mreq; struct ipv6_mreq mreq;
int i, rc, fd; int i, rc, fd;
static unsigned char *buf; static unsigned char *buf;
struct timeval check_neighbours_time;
int expiry_time, kernel_dump_time; int expiry_time, kernel_dump_time;
void *vrc; void *vrc;
unsigned int seed; unsigned int seed;
...@@ -135,26 +135,27 @@ main(int argc, char **argv) ...@@ -135,26 +135,27 @@ main(int argc, char **argv)
protocol_port = atoi(*arg); protocol_port = atoi(*arg);
} else if(strcmp(*arg, "-x") == 0 || strcmp(*arg, "-X") == 0) { } else if(strcmp(*arg, "-x") == 0 || strcmp(*arg, "-X") == 0) {
int force = (strcmp(*arg, "-X") == 0); int force = (strcmp(*arg, "-X") == 0);
if(nummyxroutes >= MAXMYXROUTES) { if(numxroutes >= MAXXROUTES) {
fprintf(stderr, "Too many network routes.\n"); fprintf(stderr, "Too many exported routes.\n");
exit(1); exit(1);
} }
SHIFTE(); SHIFTE();
rc = parse_net(*arg, rc = parse_net(*arg,
myxroutes[nummyxroutes].prefix, xroutes[numxroutes].prefix,
&myxroutes[nummyxroutes].plen); &xroutes[numxroutes].plen);
if(rc < 0) if(rc < 0)
goto syntax; goto syntax;
SHIFTE(); SHIFTE();
if(strcmp(*arg, "infinity") == 0) if(strcmp(*arg, "infinity") == 0)
myxroutes[nummyxroutes].cost = INFINITY; xroutes[numxroutes].metric = INFINITY;
else else {
myxroutes[nummyxroutes].cost = atoi(*arg); int metric = atoi(*arg);
if(myxroutes[nummyxroutes].cost < 0 || if(metric < 0 || metric > INFINITY)
myxroutes[nummyxroutes].cost > INFINITY) goto syntax;
goto syntax; xroutes[numxroutes].metric = metric;
myxroutes[nummyxroutes].installed = force ? 2 : 0; }
nummyxroutes++; xroutes[numxroutes].exported = force ? 2 : 0;
numxroutes++;
} else if(strcmp(*arg, "-h") == 0) { } else if(strcmp(*arg, "-h") == 0) {
SHIFTE(); SHIFTE();
wireless_hello_interval = atoi(*arg); wireless_hello_interval = atoi(*arg);
...@@ -182,7 +183,7 @@ main(int argc, char **argv) ...@@ -182,7 +183,7 @@ main(int argc, char **argv)
} else if(strcmp(*arg, "-s") == 0) { } else if(strcmp(*arg, "-s") == 0) {
split_horizon = 0; split_horizon = 0;
} else if(strcmp(*arg, "-b") == 0) { } else if(strcmp(*arg, "-b") == 0) {
broadcast_txcost = 1; broadcast_ihu = 1;
} else if(strcmp(*arg, "-S") == 0) { } else if(strcmp(*arg, "-S") == 0) {
SHIFTE(); SHIFTE();
state_file = *arg; state_file = *arg;
...@@ -196,7 +197,7 @@ main(int argc, char **argv) ...@@ -196,7 +197,7 @@ main(int argc, char **argv)
} }
if(wireless_hello_interval <= 0) if(wireless_hello_interval <= 0)
wireless_hello_interval = 8; wireless_hello_interval = 6;
if(wired_hello_interval <= 0) if(wired_hello_interval <= 0)
wired_hello_interval = 30; wired_hello_interval = 30;
...@@ -207,7 +208,7 @@ main(int argc, char **argv) ...@@ -207,7 +208,7 @@ main(int argc, char **argv)
70); 70);
if(seqno_interval <= 0) if(seqno_interval <= 0)
seqno_interval = MAX(2 * wireless_hello_interval - 1, 2); seqno_interval = MAX(wireless_hello_interval - 1, 2);
jitter = MIN(wireless_hello_interval * 1000 / 4, 2000); jitter = MIN(wireless_hello_interval * 1000 / 4, 2000);
update_jitter = 2 * jitter; update_jitter = 2 * jitter;
...@@ -235,7 +236,7 @@ main(int argc, char **argv) ...@@ -235,7 +236,7 @@ main(int argc, char **argv)
srandom(seed); srandom(seed);
reboot_time = now.tv_sec; reboot_time = now.tv_sec;
seqno = (random() & 0xFF); myseqno = (random() & 0xFFFF);
fd = open(state_file, O_RDONLY); fd = open(state_file, O_RDONLY);
if(fd < 0 && errno != ENOENT) if(fd < 0 && errno != ENOENT)
...@@ -243,24 +244,35 @@ main(int argc, char **argv) ...@@ -243,24 +244,35 @@ main(int argc, char **argv)
rc = unlink(state_file); rc = unlink(state_file);
if(fd >= 0 && rc < 0) { if(fd >= 0 && rc < 0) {
perror("unlink(babel-state)"); perror("unlink(babel-state)");
/* If we couldn't unlink it, it might be stale. */ /* If we couldn't unlink it, it's probably stale. */
close(fd); close(fd);
fd = -1; fd = -1;
} }
if(fd >= 0) { if(fd >= 0) {
char buf[100]; char buf[100];
int s, t; char buf2[100];
int s;
long t;
rc = read(fd, buf, 99); rc = read(fd, buf, 99);
if(rc < 0) { if(rc < 0) {
perror("read(babel-state)"); perror("read(babel-state)");
} else { } else {
buf[rc] = '\0'; buf[rc] = '\0';
rc = sscanf(buf, "%d %d\n", &s, &t); rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t);
if(rc == 2 && s >= 0 && s < 256) { if(rc == 3 && s >= 0 && s <= 0xFFFF) {
debugf("Got %d %d from babel-state.\n", s, t); unsigned char sid[16];
seqno = ((s + 1) & 0xFF); rc = parse_address(buf2, sid);
if(t >= 1176800000 && t <= now.tv_sec) if(rc < 0) {
reboot_time = t; fprintf(stderr, "Couldn't parse babel-state.\n");
} else if(memcmp(sid, myid, 16) != 0) {
fprintf(stderr, "ID mismatch in babel-state.\n");
} else {
debugf("Got %s %d %ld from babel-state.\n",
format_address(sid), s, t);
myseqno = ((s + 1) & 0xFFFF);
if(t >= 1176800000L && t <= now.tv_sec)
reboot_time = t;
}
} else { } else {
fprintf(stderr, "Couldn't parse babel-state.\n"); fprintf(stderr, "Couldn't parse babel-state.\n");
} }
...@@ -315,14 +327,14 @@ main(int argc, char **argv) ...@@ -315,14 +327,14 @@ main(int argc, char **argv)
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 (%d).\n",
*arg, ifindex); *arg, ifindex);
mtu = 1204; mtu = 1280;
maxmtu = MAX(maxmtu, 16384); maxmtu = MAX(maxmtu, 0x10000);
} else if(mtu < 1280) { } else if(mtu < 1280) {
fprintf(stderr, fprintf(stderr,
"Warning: suspiciously low MTU %d on interface %s (%d).\n", "Warning: suspiciously low MTU %d on interface %s (%d).\n",
mtu, *arg, ifindex); mtu, *arg, ifindex);
mtu = 1204; mtu = 1280;
maxmtu = MAX(maxmtu, 16384); maxmtu = MAX(maxmtu, 0x10000);
} else { } else {
if(mtu >= 0x10000) { if(mtu >= 0x10000) {
fprintf(stderr, fprintf(stderr,
...@@ -332,10 +344,10 @@ main(int argc, char **argv) ...@@ -332,10 +344,10 @@ main(int argc, char **argv)
maxmtu = MAX(maxmtu, mtu); maxmtu = MAX(maxmtu, mtu);
mtu = 32768; mtu = 32768;
} }
maxmtu = MAX(maxmtu, mtu);
/* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
mtu -= 60;
} }
maxmtu = MAX(maxmtu, mtu);
/* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
mtu -= 60;
rc = kernel_interface_wireless(*arg, ifindex); rc = kernel_interface_wireless(*arg, ifindex);
if(rc < 0) { if(rc < 0) {
...@@ -347,7 +359,7 @@ main(int argc, char **argv) ...@@ -347,7 +359,7 @@ main(int argc, char **argv)
} }
debugf("Adding %s network %s (%d).\n", debugf("Adding %s network %s (%d).\n",
rc ? "wireless" : "wired", *arg, ifindex); rc ? "wireless" : "wired", *arg, ifindex);
vrc = add_network(*arg, ifindex, mtu, !rc, rc ? 0 : 128); vrc = add_network(*arg, ifindex, mtu, !rc, rc ? 256 : 128);
if(vrc == NULL) if(vrc == NULL)
goto fail; goto fail;
SHIFT(); SHIFT();
...@@ -360,24 +372,28 @@ main(int argc, char **argv) ...@@ -360,24 +372,28 @@ main(int argc, char **argv)
} }
init_signals(); init_signals();
check_myxroutes(); check_xroutes();
kernel_routes_changed = 0; kernel_routes_changed = 0;
kernel_dump_time = now.tv_sec + 20 + random() % 20; kernel_dump_time = now.tv_sec + 20 + random() % 20;
timeval_plus_msec(&check_neighbours_time, &now, 5000 + random() % 5000);
expiry_time = now.tv_sec + 20 + random() % 20; expiry_time = now.tv_sec + 20 + random() % 20;
/* Make some noise so others notice us */ /* Make some noise so that others notice us */
for(i = 0; i < numnets; i++) { for(i = 0; i < numnets; i++) {
gettimeofday(&now, NULL);
send_hello(&nets[i]); send_hello(&nets[i]);
send_request(&nets[i], NULL, 0, -1); send_request(&nets[i], NULL, 0);
flushbuf(&nets[i]);
usleep(50000 + random() % 100000);
} }
for(i = 0; i < numnets; i++) { for(i = 0; i < numnets; i++) {
usleep(50000 + random() % 100000);
flushbuf(&nets[i]);
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
send_hello(&nets[i]); send_hello(&nets[i]);
send_self_update(&nets[i], 0); send_self_update(&nets[i], 0);
send_request(&nets[i], NULL, 0, -1); send_request(&nets[i], NULL, 0);
flushbuf(&nets[i]);
usleep(50000 + random() % 100000);
} }
debugf("Entering main loop.\n"); debugf("Entering main loop.\n");
...@@ -387,19 +403,9 @@ main(int argc, char **argv) ...@@ -387,19 +403,9 @@ main(int argc, char **argv)
fd_set readfds; fd_set readfds;
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
if(update_flush_time.tv_sec != 0) {
if(now.tv_sec >= update_flush_time.tv_sec)
flushupdates();
}
for(i = 0; i < numnets; i++) {
if(nets[i].flush_time.tv_sec != 0) {
if(timeval_compare(&now, &nets[i].flush_time) >= 0)
flushbuf(&nets[i]);
}
}
tv.tv_sec = expiry_time; tv = check_neighbours_time;
tv.tv_usec = random() % 1000000; timeval_min_sec(&tv, expiry_time);
for(i = 0; i < numnets; i++) { for(i = 0; i < numnets; i++) {
timeval_min(&tv, &nets[i].flush_time); timeval_min(&tv, &nets[i].flush_time);
timeval_min_sec(&tv, timeval_min_sec(&tv,
...@@ -420,12 +426,13 @@ main(int argc, char **argv) ...@@ -420,12 +426,13 @@ main(int argc, char **argv)
rc = select(MAX(protocol_socket, kernel_socket) + 1, rc = select(MAX(protocol_socket, kernel_socket) + 1,
&readfds, NULL, NULL, &tv); &readfds, NULL, NULL, &tv);
if(rc < 0) { if(rc < 0) {
if(errno != EINTR) { if(errno == EINTR) {
rc = 0;
FD_ZERO(&readfds);
} else {
perror("select"); perror("select");
sleep(1); sleep(1);
continue; continue;
} else {
FD_ZERO(&readfds);
} }
} }
} }
...@@ -458,32 +465,40 @@ main(int argc, char **argv) ...@@ -458,32 +465,40 @@ main(int argc, char **argv)
} }
} }
if(now.tv_sec >= expiry_time) {
expire_routes();
expiry_time = now.tv_sec + 20 + random() % 20;
}
if(kernel_routes_changed || now.tv_sec >= kernel_dump_time) { if(kernel_routes_changed || now.tv_sec >= kernel_dump_time) {
rc = check_myxroutes(); rc = check_xroutes();
if(rc > 0) if(rc > 0)
send_self_update(NULL, 1); send_self_update(NULL, 1);
else if(rc < 0) else if(rc < 0)
fprintf(stderr, "Warning: couldn't check installed routes.\n"); fprintf(stderr, "Warning: couldn't check exported routes.\n");
kernel_routes_changed = 0; kernel_routes_changed = 0;
if(kernel_socket >= 0) if(kernel_socket >= 0)
kernel_dump_time = now.tv_sec + 200 + random() % 100; kernel_dump_time = now.tv_sec + 200 + random() % 200;
else else
kernel_dump_time = now.tv_sec + 20 + random() % 20; kernel_dump_time = now.tv_sec + 20 + random() % 20;
} }
if(timeval_compare(&check_neighbours_time, &now) < 0) {
int msecs;
msecs = check_neighbours();
msecs = MAX(msecs, 500);
timeval_plus_msec(&check_neighbours_time, &now,
msecs / 2 + random() % msecs);
}
if(now.tv_sec >= expiry_time) {
expire_routes();
expiry_time = now.tv_sec + 20 + random() % 20;
}
for(i = 0; i < numnets; i++) { for(i = 0; i < numnets; i++) {
if(now.tv_sec >= nets[i].hello_time + nets[i].hello_interval) if(now.tv_sec >= nets[i].hello_time + nets[i].hello_interval)
send_hello(&nets[i]); send_hello(&nets[i]);
if(now.tv_sec >= nets[i].txcost_time + nets[i].txcost_interval) if(now.tv_sec >= nets[i].ihu_time + nets[i].ihu_interval)
send_txcost(NULL, &nets[i]); send_ihu(NULL, &nets[i]);
if(!network_idle(&nets[i])) { if(!network_idle(&nets[i])) {
if(now.tv_sec >= nets[i].update_time + update_interval) if(now.tv_sec >= nets[i].update_time + update_interval)
send_update(NULL, &nets[i]); send_update(&nets[i], NULL, 0);
if(now.tv_sec >= if(now.tv_sec >=
nets[i].self_update_time + nets[i].self_update_interval) { nets[i].self_update_time + nets[i].self_update_interval) {
send_self_update(&nets[i], 0); send_self_update(&nets[i], 0);
...@@ -491,6 +506,18 @@ main(int argc, char **argv) ...@@ -491,6 +506,18 @@ main(int argc, char **argv)
} }
} }
if(update_flush_time.tv_sec != 0) {
if(now.tv_sec >= update_flush_time.tv_sec)
flushupdates();
}
for(i = 0; i < numnets; i++) {
if(nets[i].flush_time.tv_sec != 0) {
if(timeval_compare(&now, &nets[i].flush_time) >= 0)
flushbuf(&nets[i]);
}
}
if(debug || dumping) { if(debug || dumping) {
dump_tables(stdout); dump_tables(stdout);
dumping = 0; dumping = 0;
...@@ -502,25 +529,25 @@ main(int argc, char **argv) ...@@ -502,25 +529,25 @@ main(int argc, char **argv)
/* Uninstall and retract all routes. */ /* Uninstall and retract all routes. */
if(routes[i].installed) { if(routes[i].installed) {
uninstall_route(&routes[i]); uninstall_route(&routes[i]);
send_update(routes[i].dest, NULL); send_update(NULL, routes[i].src->prefix, routes[i].src->plen);
} }
} }
flushupdates();
usleep(50000 + random() % 100000);
for(i = 0; i < numnets; i++) { for(i = 0; i < numnets; i++) {
/* Retract self routes. */ /* Retract exported routes. */
send_self_retract(&nets[i]); send_self_retract(&nets[i]);
/* Make sure that we expire quickly from our neighbours' /* Make sure that we expire quickly from our neighbours'
association caches. */ association caches. */
nets[i].hello_interval = 1; nets[i].hello_interval = 1;
send_hello(&nets[i]); send_hello(&nets[i]);
flushbuf(&nets[i]); flushbuf(&nets[i]);
usleep(50000 + random() % 100000);
} }
usleep(50000 + random() % 100000);
for(i = 0; i < numnets; i++) { for(i = 0; i < numnets; i++) {
/* Make sure they got it. */ /* Make sure they got it. */
send_self_retract(&nets[i]);
send_hello(&nets[i]); send_hello(&nets[i]);
flushbuf(&nets[i]); flushbuf(&nets[i]);
usleep(50000 + random() % 100000);
kernel_setup_interface(0, nets[i].ifname, nets[i].ifindex); kernel_setup_interface(0, nets[i].ifname, nets[i].ifindex);
} }
kernel_setup(0); kernel_setup(0);
...@@ -531,7 +558,8 @@ main(int argc, char **argv) ...@@ -531,7 +558,8 @@ main(int argc, char **argv)
unlink(state_file); unlink(state_file);
} else { } else {
char buf[100]; char buf[100];
rc = snprintf(buf, 100, "%d %d\n", seqno, (int)now.tv_sec); rc = snprintf(buf, 100, "%s %d %ld\n",
format_address(myid), (int)myseqno, (long)now.tv_sec);
rc = write(fd, buf, rc); rc = write(fd, buf, rc);
if(rc < 0) { if(rc < 0) {
perror("write(babel-state)"); perror("write(babel-state)");
...@@ -539,7 +567,7 @@ main(int argc, char **argv) ...@@ -539,7 +567,7 @@ main(int argc, char **argv)
} }
close(fd); close(fd);
} }
debugf("Done."); debugf("Done.\n");
return 0; return 0;
syntax: syntax:
...@@ -551,7 +579,7 @@ main(int argc, char **argv) ...@@ -551,7 +579,7 @@ main(int argc, char **argv)
" " " "
"[-u update] [-k metric] [-s] [-P] [-c cost]\n" "[-u update] [-k metric] [-s] [-P] [-c cost]\n"
" " " "
"[-d level] [-x net cost] [-X net cost]... address interface...\n", "[-d level] [-x net cost] [-X net cost]... id interface...\n",
argv[0]); argv[0]);
exit(1); exit(1);
...@@ -622,16 +650,6 @@ dump_tables(FILE *out) ...@@ -622,16 +650,6 @@ dump_tables(FILE *out)
fprintf(out, "My id %s\n", format_address(myid)); fprintf(out, "My id %s\n", format_address(myid));
for(i = 0; i < nummyxroutes; i++) {
fprintf(out, "External %s/%d cost %d%s\n",
format_address(myxroutes[i].prefix),
myxroutes[i].plen,
myxroutes[i].cost,
myxroutes[i].installed ?
(myxroutes[i].installed >= 2 ? " (forced)" : " (installed)") :
"");
}
for(i = 0; i < numneighs; i++) { for(i = 0; i < numneighs; i++) {
if(neighs[i].id[0] == 0xFF) if(neighs[i].id[0] == 0xFF)
continue; continue;
...@@ -643,27 +661,25 @@ dump_tables(FILE *out) ...@@ -643,27 +661,25 @@ dump_tables(FILE *out)
neighbour_rxcost(&neighs[i]), neighbour_rxcost(&neighs[i]),
neighs[i].txcost); neighs[i].txcost);
} }
for(i = 0; i < numroutes; i++) {
fprintf(out, "%s metric %d refmetric %d seqno %d age %d ",
format_address(routes[i].dest->address),
routes[i].metric, routes[i].refmetric, routes[i].seqno,
(int)(now.tv_sec - routes[i].time));
fprintf(out, "via %s nexthop %s%s\n",
routes[i].nexthop->network->ifname,
format_address(routes[i].nexthop->address),
routes[i].installed ? " (installed)" :
route_feasible(&routes[i]) ? " (feasible)" : "");
}
for(i = 0; i < numxroutes; i++) { for(i = 0; i < numxroutes; i++) {
fprintf(out, "%s/%d gw %s nexthop %s cost %d metric %d age %d%s\n", fprintf(out, "%s metric %d (%s)\n",
format_address(xroutes[i].prefix), format_prefix(xroutes[i].prefix, xroutes[i].plen),
xroutes[i].plen,
format_address(xroutes[i].gateway->address),
format_address(xroutes[i].nexthop->address),
xroutes[i].cost,
xroutes[i].metric, xroutes[i].metric,
(int)(now.tv_sec - xroutes[i].time), xroutes[i].exported ?
xroutes[i].installed ? " (installed)" : ""); xroutes[i].exported > 1 ? "forced" : "exported" :
"not exported");
}
for(i = 0; i < numroutes; i++) {
fprintf(out, "%s via %s metric %d refmetric %d seqno %d age %d "
"via %s nexthop %s%s\n",
format_prefix(routes[i].src->prefix, routes[i].src->plen),
format_address(routes[i].src->address),
routes[i].metric, routes[i].refmetric, (int)routes[i].seqno,
(int)(now.tv_sec - routes[i].time),
routes[i].nexthop->network->ifname,
format_address(routes[i].nexthop->address),
routes[i].installed ? " (installed)" :
route_feasible(&routes[i]) ? " (feasible)" : "");
} }
fflush(out); fflush(out);
} }
...@@ -702,7 +718,7 @@ add_network(char *ifname, int ifindex, int mtu, int wired, unsigned int cost) ...@@ -702,7 +718,7 @@ add_network(char *ifname, int ifindex, int mtu, int wired, unsigned int cost)
nets[numnets].buffered = 0; nets[numnets].buffered = 0;
nets[numnets].bucket_time = now.tv_sec; nets[numnets].bucket_time = now.tv_sec;
nets[numnets].bucket = 0; nets[numnets].bucket = 0;
nets[numnets].hello_seqno = (random() & 0xFF); nets[numnets].hello_seqno = (random() & 0xFFFF);
numnets++; numnets++;
return &nets[numnets - 1]; return &nets[numnets - 1];
} }
...@@ -725,55 +741,7 @@ update_hello_interval(struct network *net) ...@@ -725,55 +741,7 @@ update_hello_interval(struct network *net)
net->hello_interval = wireless_hello_interval; net->hello_interval = wireless_hello_interval;
net->self_update_interval = net->self_update_interval =
MAX(15 + nets[numnets].hello_interval / 2, MAX(15 + net->hello_interval / 2, net->hello_interval);
nets[numnets].hello_interval);
net->txcost_interval = 7 * net->hello_interval / 4;
}
void net->ihu_interval = 10 * net->hello_interval / 4;
expire_routes(void)
{
int i;
debugf("Expiring old routes.\n");
for(i = 0; i < numneighs; i++) {
if(neighs[i].id[0] == 0xFF)
continue;
check_neighbour(&neighs[i]);
/* No need to update_neighbour_metric -- update_route_metric below. */
}
i = 0;
while(i < numroutes) {
struct route *route = &routes[i];
if(route->time < now.tv_sec - route_gc_delay) {
flush_route(route);
continue;
}
update_route_metric(route);
if(route->installed && route->refmetric < INFINITY) {
if(route->time < now.tv_sec - MAX(10, route_timeout_delay - 25))
send_unicast_request(route->nexthop, route->dest,
max_request_hopcount, -1);
}
i++;
}
i = 0;
while(i < numxroutes) {
struct xroute *xroute = &xroutes[i];
if(xroute->time < now.tv_sec - xroute_gc_delay ||
(xroute->cost >= INFINITY &&
xroute->time < now.tv_sec - xroute_hold_delay)) {
flush_xroute(xroute);
continue;
}
update_xroute_metric(xroute, xroute->cost);
i++;
}
} }
...@@ -21,12 +21,10 @@ THE SOFTWARE. ...@@ -21,12 +21,10 @@ THE SOFTWARE.
*/ */
#define MAXROUTES 512 #define MAXROUTES 512
#define MAXDESTS 1024 #define MAXSRCS 1024
#define MAXNEIGHBOURS 128 #define MAXNEIGHBOURS 128
#define MAXNETS 8 #define MAXNETS 8
#define MAXXROUTES 128 #define MAXXROUTES 64
#define MAXMYXROUTES 64
#define MAX_BUFFERED_UPDATES 100
#define INFINITY ((unsigned short)(~0)) #define INFINITY ((unsigned short)(~0))
...@@ -68,7 +66,7 @@ struct network { ...@@ -68,7 +66,7 @@ struct network {
int hello_time; int hello_time;
int self_update_time; int self_update_time;
int update_time; int update_time;
int txcost_time; int ihu_time;
char ifname[IF_NAMESIZE]; char ifname[IF_NAMESIZE];
int buffered; int buffered;
struct timeval flush_time; struct timeval flush_time;
...@@ -77,10 +75,10 @@ struct network { ...@@ -77,10 +75,10 @@ struct network {
int bucket_time; int bucket_time;
unsigned int bucket; unsigned int bucket;
int activity_time; int activity_time;
unsigned char hello_seqno; unsigned short hello_seqno;
unsigned int hello_interval; unsigned int hello_interval;
unsigned int self_update_interval; unsigned int self_update_interval;
unsigned int txcost_interval; unsigned int ihu_interval;
}; };
extern struct timeval now; extern struct timeval now;
...@@ -92,7 +90,7 @@ extern unsigned char myid[16]; ...@@ -92,7 +90,7 @@ extern unsigned char myid[16];
extern struct network nets[MAXNETS]; extern struct network nets[MAXNETS];
extern int numnets; extern int numnets;
extern const unsigned char zeroes[16]; extern const unsigned char zeroes[16], ones[16];
extern int protocol_port; extern int protocol_port;
extern unsigned char protocol_group[16]; extern unsigned char protocol_group[16];
......
...@@ -96,7 +96,7 @@ write_proc(char *filename, int value) ...@@ -96,7 +96,7 @@ write_proc(char *filename, int value)
} }
struct netlink { struct netlink {
unsigned int seqno; unsigned short seqno;
int sock; int sock;
struct sockaddr_nl sockaddr; struct sockaddr_nl sockaddr;
socklen_t socklen; socklen_t socklen;
......
...@@ -30,7 +30,7 @@ THE SOFTWARE. ...@@ -30,7 +30,7 @@ THE SOFTWARE.
#include "babel.h" #include "babel.h"
#include "util.h" #include "util.h"
#include "net.h" #include "net.h"
#include "destination.h" #include "source.h"
#include "neighbour.h" #include "neighbour.h"
#include "route.h" #include "route.h"
#include "xroute.h" #include "xroute.h"
...@@ -38,21 +38,25 @@ THE SOFTWARE. ...@@ -38,21 +38,25 @@ THE SOFTWARE.
struct timeval update_flush_time = {0, 0}; struct timeval update_flush_time = {0, 0};
const unsigned char packet_header[4] = {42, 0, 0, 0}; const unsigned char packet_header[8] = {42, 1};
unsigned int jitter; unsigned int jitter;
unsigned int update_jitter; unsigned int update_jitter;
int add_cost = 0; int add_cost = 0;
int parasitic = 0; int parasitic = 0;
int silent_time = 30; int silent_time = 30;
int broadcast_txcost = 0; int broadcast_ihu = 0;
int split_horizon = 1; int split_horizon = 1;
unsigned char seqno = 0; unsigned short myseqno = 0;
int seqno_time = 0; int seqno_time = 0;
int seqno_interval = -1; int seqno_interval = -1;
struct destination *buffered_updates[MAX_BUFFERED_UPDATES]; struct buffered_update {
unsigned char prefix[16];
unsigned char plen;
};
struct buffered_update buffered_updates[MAX_BUFFERED_UPDATES];
struct network *update_net = NULL; struct network *update_net = NULL;
int updates = 0; int updates = 0;
...@@ -62,9 +66,13 @@ parse_packet(const unsigned char *from, struct network *net, ...@@ -62,9 +66,13 @@ parse_packet(const unsigned char *from, struct network *net,
{ {
int i, j; int i, j;
const unsigned char *message; const unsigned char *message;
unsigned char type, plen;
unsigned short seqno;
unsigned short metric;
const unsigned char *address;
struct neighbour *neigh; struct neighbour *neigh;
struct xroute pxroutes[40]; int have_current_source = 0;
int numpxroutes = 0; unsigned char current_source[16];
if(from[0] != 0xFE || (from[1] & 0xC0) != 0x80) { if(from[0] != 0xFE || (from[1] & 0xC0) != 0x80) {
fprintf(stderr, "Received packet from non-local address %s.\n", fprintf(stderr, "Received packet from non-local address %s.\n",
...@@ -72,148 +80,122 @@ parse_packet(const unsigned char *from, struct network *net, ...@@ -72,148 +80,122 @@ parse_packet(const unsigned char *from, struct network *net,
return; return;
} }
if(len % 20 != 4 || packet[0] != 42) { if(packet[0] != 42) {
fprintf(stderr, "Received malformed packet on %s from %s.\n", fprintf(stderr, "Received malformed packet on %s from %s.\n",
net->ifname, format_address(from)); net->ifname, format_address(from));
return; return;
} }
if(packet[1] != 0) { if(packet[1] != 1) {
fprintf(stderr, fprintf(stderr,
"Received packet with unknown version %d on %s from %s.\n", "Received packet with unknown version %d on %s from %s.\n",
packet[1], net->ifname, format_address(from)); packet[1], net->ifname, format_address(from));
return; return;
} }
if(len % 24 != 8) {
fprintf(stderr, "Received malformed packet on %s from %s.\n",
net->ifname, format_address(from));
return;
}
j = 0; j = 0;
for(i = 0; i < (len - 4) / 20; i++) { for(i = 0; i < (len - 8) / 24; i++) {
message = packet + 4 + 20 * i; message = packet + 8 + 24 * i;
if(message[0] != 4 && message[0] != 2) { type = message[0];
if(numpxroutes > 0) { plen = message[1];
fprintf(stderr, "Received unexpected xroute on %s from %s.\n", seqno = ntohs(*(uint16_t*)(message + 4));
net->ifname, format_address(from)); metric = ntohs(*(uint16_t*)(message + 6));
} address = message + 8;
numpxroutes = 0; if(type == 0) {
VALGRIND_MAKE_MEM_UNDEFINED(&pxroutes, sizeof(pxroutes)); int changed;
} if(memcmp(address, myid, 16) == 0)
if(message[0] == 0) {
if(memcmp(message + 4, myid, 16) == 0)
continue; continue;
debugf("Received hello on %s from %s (%s).\n", debugf("Received hello on %s from %s (%s).\n",
net->ifname, net->ifname,
format_address(message + 4), format_address(address),
format_address(from)); format_address(from));
net->activity_time = now.tv_sec; net->activity_time = now.tv_sec;
neigh = add_neighbour(message + 4, from, net); neigh = add_neighbour(address, from, net);
if(neigh == NULL) if(neigh == NULL)
continue; continue;
update_neighbour(neigh, message[1], changed = update_neighbour(neigh, seqno, metric);
((message[2] & 0x3) << 8) | message[3]); if(changed)
update_neighbour_metric(neigh); update_neighbour_metric(neigh);
} else { } else {
neigh = find_neighbour(from, net); neigh = find_neighbour(from, net);
if(neigh == NULL) if(neigh == NULL)
continue; continue;
net->activity_time = now.tv_sec; net->activity_time = now.tv_sec;
if(message[0] == 1) { if(type == 1) {
int hopcount = message[2]; debugf("Received ihu for %s from %s (%s).\n",
int theirseqno = message[1]; format_address(address),
format_address(neigh->id),
format_address(from));
if(plen == 0xFF || memcmp(myid, address, 16) == 0) {
neigh->txcost = metric;
neigh->ihu_time = now.tv_sec;
update_neighbour_metric(neigh);
}
} else if(type == 2) {
debugf("Received request on %s from %s (%s) for %s " debugf("Received request on %s from %s (%s) for %s "
"(%d hops for seqno %d).\n", "(%d hops).\n",
net->ifname, net->ifname,
format_address(neigh->id), format_address(neigh->id),
format_address(from), format_address(from),
format_address(message + 4), plen == 0xFF ?
hopcount, theirseqno); "any" :
if(memcmp(message + 4, zeroes, 16) == 0) { format_prefix(address, plen),
metric);
if(plen == 0xFF) {
/* 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 its txcost. */ we might as well send it an ihu. */
send_txcost(neigh, NULL); send_ihu(neigh, NULL);
send_update(NULL, neigh->network); send_update(neigh->network, NULL, 0);
} else if(memcmp(message + 4, myid, 16) == 0) { } else {
int new_seqno; send_update(neigh->network, address, plen);
send_txcost(neigh, NULL);
if(hopcount > 0 && seqno_compare(theirseqno, seqno) <= 0)
/* Somebody's requesting an old seqno. */
new_seqno = 0;
else
new_seqno = 1;
send_self_update(neigh->network, new_seqno);
} else if(!parasitic) {
struct destination *dest;
dest = find_destination(message + 4, 0, 0);
if(dest) {
if(hopcount == 0) {
send_update(dest, neigh->network);
} else {
/* Request for a new seqno */
struct route *installed;
installed = find_installed_route(dest);
if(installed && installed->nexthop != neigh) {
if(seqno_compare(installed->seqno,
theirseqno) >= 0)
send_update(dest, neigh->network);
else if(!request_requested(dest,
theirseqno,
neigh->network)) {
if(hopcount >= 2)
send_unicast_request(installed->nexthop,
dest,
hopcount - 1,
theirseqno);
notice_request(dest, theirseqno,
neigh->network);
}
}
}
}
} }
} else if(message[0] == 2) { } else if(type == 3) {
debugf("Received update on %s from %s (%s) for %s.\n", if(plen == 0xFF)
debugf("Received update for %s/none on %s from %s (%s).\n",
format_address(message + 8),
net->ifname,
format_address(neigh->id),
format_address(from));
else
debugf("Received update for %s on %s from %s (%s).\n",
format_prefix(message + 8, plen),
net->ifname,
format_address(neigh->id),
format_address(from));
memcpy(current_source, address, 16);
have_current_source = 1;
if(memcmp(address, myid, 16) == 0)
continue;
if(plen <= 128)
update_route(address, mask_prefix(address, plen), plen,
seqno, metric, neigh);
} else if(type == 4) {
debugf("Received prefix %s on %s from %s (%s).\n",
format_prefix(address, plen),
net->ifname, net->ifname,
format_address(neigh->id), format_address(neigh->id),
format_address(from),
format_address(message + 4));
if(memcmp(message + 4, myid, 16) == 0) {
int metric = ((message[2] << 8) | (message[3] & 0xFF));
int theirseqno = message[1];
if(metric >= INFINITY) {
/* Oh my, someone is retracting a route to me. */
send_txcost(neigh, NULL);
send_self_update(neigh->network,
seqno_compare(theirseqno, seqno) > 0);
}
continue;
}
update_route(message + 4,
message[1], (message[2] << 8 | message[3]),
neigh, pxroutes, numpxroutes);
numpxroutes = 0;
VALGRIND_MAKE_MEM_UNDEFINED(&pxroutes, sizeof(pxroutes));
} else if(message[0] == 3) {
debugf("Received txcost from %s.\n", format_address(from));
if(memcmp(myid, message + 4, 16) == 0 ||
memcmp(zeroes, message + 4, 16) == 0) {
neigh->txcost = (message[2] << 8 | message[3]);
neigh->txcost_time = now.tv_sec;
}
update_neighbour_metric(neigh);
} else if(message[0] == 4) {
debugf("Received xroute from %s.\n",
format_address(from)); format_address(from));
if(numpxroutes >= 40) { if(!have_current_source) {
fprintf(stderr, "Too many xroutes in update.\n"); fprintf(stderr, "Received prefix with no source "
"on %s from %s (%s).\n",
net->ifname,
format_address(neigh->id),
format_address(from));
continue; continue;
} }
memcpy(pxroutes[numpxroutes].prefix, message + 4, 16); if(memcmp(current_source, myid, 16) == 0)
pxroutes[numpxroutes].plen = message[1]; continue;
pxroutes[numpxroutes].cost = update_route(current_source, mask_prefix(address, plen), plen,
((message[2] << 8) | (message[3] & 0xFF)); seqno, metric, neigh);
numpxroutes++;
} else { } else {
debugf("Received unknown packet type %d from %s.\n", debugf("Received unknown packet type %d from %s (%s).\n",
message[0], format_address(from)); type, format_address(neigh->id), format_address(from));
} }
} }
} }
...@@ -248,10 +230,10 @@ flushbuf(struct network *net) ...@@ -248,10 +230,10 @@ flushbuf(struct network *net)
int rc; int rc;
struct sockaddr_in6 sin6; struct sockaddr_in6 sin6;
if(update_net == net) { assert(net->buffered <= net->bufsize);
if(update_net == net)
flushupdates(); flushupdates();
return;
}
if(net->buffered > 0) { if(net->buffered > 0) {
debugf(" (flushing %d buffered bytes on %s)\n", debugf(" (flushing %d buffered bytes on %s)\n",
...@@ -304,6 +286,7 @@ schedule_flush_now(struct network *net) ...@@ -304,6 +286,7 @@ schedule_flush_now(struct network *net)
static void static void
start_message(struct network *net, int bytes) start_message(struct network *net, int bytes)
{ {
assert(net->buffered % 8 == 0);
if(net->bufsize - net->buffered < bytes) if(net->bufsize - net->buffered < bytes)
flushbuf(net); flushbuf(net);
} }
...@@ -311,7 +294,6 @@ start_message(struct network *net, int bytes) ...@@ -311,7 +294,6 @@ start_message(struct network *net, int bytes)
static void static void
accumulate_byte(struct network *net, unsigned char byte) accumulate_byte(struct network *net, unsigned char byte)
{ {
assert(net->bufsize - net->buffered >= 1);
net->sendbuf[net->buffered] = byte; net->sendbuf[net->buffered] = byte;
net->buffered++; net->buffered++;
} }
...@@ -319,9 +301,7 @@ accumulate_byte(struct network *net, unsigned char byte) ...@@ -319,9 +301,7 @@ accumulate_byte(struct network *net, unsigned char byte)
static void static void
accumulate_short(struct network *net, unsigned short s) accumulate_short(struct network *net, unsigned short s)
{ {
assert(net->bufsize - net->buffered >= 2); *(uint16_t *)(net->sendbuf + net->buffered) = htons(s);
net->sendbuf[net->buffered] = s >> 8;
net->sendbuf[net->buffered + 1] = (s & 0xFF);
net->buffered += 2; net->buffered += 2;
} }
...@@ -329,61 +309,78 @@ static void ...@@ -329,61 +309,78 @@ static void
accumulate_data(struct network *net, accumulate_data(struct network *net,
const unsigned char *data, unsigned int len) const unsigned char *data, unsigned int len)
{ {
assert(net->bufsize - net->buffered >= len);
memcpy(net->sendbuf + net->buffered, data, len); memcpy(net->sendbuf + net->buffered, data, len);
net->buffered += len; net->buffered += len;
} }
static void
send_message(struct network *net,
unsigned char type, unsigned char plen,
unsigned short seqno, unsigned short metric,
const unsigned char *address)
{
start_message(net, 24);
accumulate_byte(net, type);
accumulate_byte(net, plen);
accumulate_short(net, 0);
accumulate_short(net, seqno);
accumulate_short(net, metric);
accumulate_data(net, address, 16);
schedule_flush(net);
}
static const unsigned char *
message_source_id(struct network *net)
{
int i;
assert(net->buffered % 24 == 0);
i = net->buffered / 24 - 1;
while(i >= 0) {
const unsigned char *message;
message = (const unsigned char*)(net->sendbuf + i * 24);
if(message[0] == 3)
return message + 8;
else if(message[0] == 4)
i--;
else
break;
}
return NULL;
}
void void
send_hello(struct network *net) send_hello(struct network *net)
{ {
debugf("Sending hello to %s.\n", net->ifname); debugf("Sending hello to %s.\n", net->ifname);
update_hello_interval(net); update_hello_interval(net);
start_message(net, 20); net->hello_seqno = ((net->hello_seqno + 1) & 0xFFFF);
accumulate_byte(net, 0);
net->hello_seqno = ((net->hello_seqno + 1) & 0xFF);
accumulate_byte(net, net->hello_seqno);
if(net->hello_interval >= 1 << 10)
accumulate_short(net, 0);
else
accumulate_short(net, net->hello_interval);
accumulate_data(net, myid, 16);
schedule_flush(net);
net->hello_time = now.tv_sec; net->hello_time = now.tv_sec;
send_message(net, 0, 0, net->hello_seqno,
100 * net->hello_interval > 0xFFFF ?
0 : 100 * net->hello_interval,
myid);
} }
void void
send_request(struct network *net, struct destination *dest, send_request(struct network *net,
int hopcount, int seqno) const unsigned char *prefix, unsigned char plen)
{ {
int i; int i;
if(net == NULL) { if(net == NULL) {
for(i = 0; i < numnets; i++) for(i = 0; i < numnets; i++)
send_request(&nets[i], dest, hopcount, seqno); send_request(&nets[i], prefix, plen);
return; return;
} }
debugf("Sending request to %s for %s (%d hops for seqno %d).\n", debugf("Sending request to %s for %s.\n",
net->ifname, dest ? format_address(dest->address) : "::/0", net->ifname, prefix ? format_prefix(prefix, plen) : "any");
hopcount, seqno); if(prefix)
start_message(net, 20); send_message(net, 2, plen, 0, 0, prefix);
accumulate_byte(net, 1); else
if(hopcount > 0 && dest) { send_message(net, 2, 0xFF, 0, 0, ones);
if(seqno >= 0)
accumulate_byte(net, seqno);
else
accumulate_byte(net,
dest->metric >= INFINITY ?
dest->seqno : ((dest->seqno + 1) & 0xFF));
accumulate_byte(net, hopcount);
} else {
accumulate_byte(net, 0);
accumulate_byte(net, 0);
}
accumulate_byte(net, 0);
accumulate_data(net, dest ? dest->address : zeroes, 16);
schedule_flush(net);
} }
static void static void
...@@ -411,44 +408,50 @@ send_unicast_packet(struct neighbour *neigh, unsigned char *buf, int buflen) ...@@ -411,44 +408,50 @@ send_unicast_packet(struct neighbour *neigh, unsigned char *buf, int buflen)
} }
void void
send_unicast_request(struct neighbour *neigh, struct destination *dest, send_unicast_request(struct neighbour *neigh,
int hopcount, int seqno) const unsigned char *prefix, unsigned char plen)
{ {
unsigned char buf[20]; unsigned char buf[24];
debugf("Sending unicast request to %s (%s) for %s " debugf("Sending unicast request to %s (%s) for %s.\n",
"(%d hops for seqno %d).\n",
format_address(neigh->id), format_address(neigh->id),
format_address(neigh->address), format_address(neigh->address),
dest ? format_address(dest->address) : "::/0", prefix ? format_prefix(prefix, plen) : "any");
hopcount, seqno);
memset(buf, 0, 24);
buf[0] = 1; buf[0] = 1;
if(hopcount > 0 && dest) { if(prefix) {
if(seqno >= 0) memcpy(buf + 8, prefix, 16);
buf[1] = seqno; buf[7] = plen;
else
buf[1] =
dest->metric >= INFINITY ?
dest->seqno : ((dest->seqno + 1) & 0xFF);
buf[2] = hopcount;
} else { } else {
buf[1] = 0; memcpy(buf + 8, ones, 16);
buf[2] = 0; buf[7] = 0xFF;
} }
buf[3] = 0; send_unicast_packet(neigh, buf, 24);
if(dest == NULL) }
memset(buf + 4, 0, 16);
else
memcpy(buf + 4, dest->address, 16);
send_unicast_packet(neigh, buf, 20); static void
really_send_update(struct network *net,
const unsigned char *address,
const unsigned char *prefix, unsigned char plen,
unsigned short seqno, unsigned short metric)
{
if(in_prefix(address, prefix, plen)) {
send_message(net, 3, plen, seqno, metric, address);
} else {
unsigned const char *sid;
start_message(net, 48);
sid = message_source_id(net);
if(sid == NULL || memcmp(address, sid, 16) != 0)
send_message(net, 3, 0xFF, 0, 0xFFFF, address);
send_message(net, 4, plen, seqno, metric, prefix);
}
} }
void void
flushupdates(void) flushupdates(void)
{ {
int i, j; int i;
if(updates > 0) { if(updates > 0) {
/* Ensure that we won't be recursively called by flushbuf. */ /* Ensure that we won't be recursively called by flushbuf. */
...@@ -458,96 +461,44 @@ flushupdates(void) ...@@ -458,96 +461,44 @@ flushupdates(void)
update_net = NULL; update_net = NULL;
debugf(" (flushing %d buffered updates)\n", n); debugf(" (flushing %d buffered updates)\n", n);
for(i = 0; i < n; i++) {
if(buffered_updates[i] == NULL) {
int numpxroutes;
numpxroutes = 0;
for(j = 0; j < nummyxroutes; j++) {
if(myxroutes[j].installed)
numpxroutes++;
}
start_message(net, 20 + 20 * numpxroutes);
for(j = 0; j < nummyxroutes; j++) {
if(!myxroutes[j].installed)
continue;
if(net->bufsize - net->buffered < 40) {
/* We cannot just call start_message, as this would
split the xroutes from the update. */
start_message(net, 20);
accumulate_byte(net, 2);
accumulate_byte(net, seqno);
accumulate_short(net, 0);
accumulate_data(net, myid, 16);
flushbuf(net);
}
start_message(net, 20);
accumulate_byte(net, 4);
accumulate_byte(net, myxroutes[j].plen);
accumulate_short(net, myxroutes[j].cost);
accumulate_data(net, myxroutes[j].prefix, 16);
}
start_message(net, 20);
accumulate_byte(net, 2);
accumulate_byte(net, seqno);
accumulate_short(net, 0);
accumulate_data(net, myid, 16);
} else {
struct route *route;
int seqno;
int metric;
route = find_installed_route(buffered_updates[i]);
if(route) {
if(split_horizon && net->wired &&
route->nexthop->network == net)
continue;
seqno = route->seqno;
metric = MIN(route->metric + add_cost, INFINITY);
} else {
seqno = buffered_updates[i]->seqno;
metric = INFINITY;
}
update_destination(buffered_updates[i], seqno, metric); for(i = 0; i < n; i++) {
satisfy_request(buffered_updates[i], seqno, net); struct xroute *xroute;
struct route *route;
/* Don't send xroutes if the metric is infinite as the seqno struct source *src;
might be originated by us. */ unsigned short seqno;
if(metric < INFINITY) { unsigned short metric;
int numpxroutes; xroute = find_exported_xroute(buffered_updates[i].prefix,
numpxroutes = 0; buffered_updates[i].plen);
for(j = 0; j < numxroutes; j++) { if(xroute) {
if(xroutes[j].installed && really_send_update(net, myid,
xroutes[j].gateway == buffered_updates[i]) xroute->prefix, xroute->plen,
numpxroutes++; myseqno, xroute->metric);
} continue;
start_message(net, 20 + 20 * numpxroutes); }
for(j = 0; j < numxroutes; j++) { route = find_installed_route(buffered_updates[i].prefix,
if(!xroutes[j].installed) buffered_updates[i].plen);
continue; if(route) {
if(xroutes[j].gateway != buffered_updates[i]) if(split_horizon &&
continue; net->wired && route->nexthop->network == net)
/* See comment above */ continue;
if(net->bufsize - net->buffered < 40) { seqno = route->seqno;
start_message(net, 20); metric = MIN((int)route->metric + add_cost, INFINITY);
accumulate_byte(net, 2); really_send_update(net, route->src->address,
accumulate_byte(net, seqno); route->src->prefix,
accumulate_short(net, metric); route->src->plen,
accumulate_data(net, seqno, metric);
buffered_updates[i]->address, 16); update_source(route->src, seqno, metric);
flushbuf(net); continue;
} }
start_message(net, 20); src = find_recent_source(buffered_updates[i].prefix,
accumulate_byte(net, 4); buffered_updates[i].plen);
accumulate_byte(net, xroutes[j].plen); if(src) {
accumulate_short(net, xroutes[j].cost); really_send_update(net, src->address, src->prefix, src->plen,
accumulate_data(net, xroutes[j].prefix, 16); src->metric >= INFINITY ?
} src->seqno : (src->seqno + 1) & 0xFFFF,
} INFINITY);
start_message(net, 20); continue;
accumulate_byte(net, 2);
accumulate_byte(net, seqno);
accumulate_short(net, metric);
accumulate_data(net, buffered_updates[i]->address, 16);
} }
} }
schedule_flush_now(net); schedule_flush_now(net);
...@@ -570,7 +521,8 @@ schedule_update_flush(void) ...@@ -570,7 +521,8 @@ schedule_update_flush(void)
} }
static void static void
buffer_update(struct network *net, struct destination *dest) buffer_update(struct network *net,
const unsigned char *prefix, unsigned char plen)
{ {
int i; int i;
...@@ -579,64 +531,61 @@ buffer_update(struct network *net, struct destination *dest) ...@@ -579,64 +531,61 @@ buffer_update(struct network *net, struct destination *dest)
update_net = net; update_net = net;
for(i = 0; i < updates; i++) for(i = 0; i < updates; i++) {
if(buffered_updates[i] == dest) if(buffered_updates[i].plen == plen &&
memcmp(buffered_updates[i].prefix, prefix, 16) == 0)
return; return;
}
if(updates >= MAX_BUFFERED_UPDATES) if(updates >= MAX_BUFFERED_UPDATES)
flushupdates(); flushupdates();
buffered_updates[updates++] = dest; memcpy(buffered_updates[updates].prefix, prefix, 16);
buffered_updates[updates].plen = plen;
updates++;
} }
void void
send_update(struct destination *dest, struct network *net) send_update(struct network *net,
const unsigned char *prefix, unsigned char plen)
{ {
int i; int i;
if(dest != NULL) {
/* The case of net == NULL is not handled by flushupdates.
The other case is, but it won't do any harm to record it early. */
struct route *installed = find_installed_route(dest);
satisfy_request(dest, installed ? installed->seqno : dest->seqno,
net);
}
if(net == NULL) { if(net == NULL) {
for(i = 0; i < numnets; i++) for(i = 0; i < numnets; i++)
send_update(dest, &nets[i]); send_update(&nets[i], prefix, plen);
return; return;
} }
if(parasitic || if(parasitic || (silent_time && now.tv_sec < reboot_time + silent_time)) {
(silent_time && now.tv_sec < reboot_time + silent_time)) { if(prefix == NULL) {
net->update_time = now.tv_sec;
if(dest == NULL)
send_self_update(net, 0); send_self_update(net, 0);
net->update_time = now.tv_sec;
} else if(find_exported_xroute(prefix, plen)) {
buffer_update(net, prefix, plen);
}
return; return;
} }
silent_time = 0; silent_time = 0;
if(dest) { if(prefix) {
if(updates >= net->bufsize / 20) { if(updates > net->bufsize / 24 - 2) {
/* Update won't fit in a single packet -- send a full dump. */ /* Update won't fit in a single packet -- send a full dump. */
send_update(NULL, net); send_update(net, NULL, 0);
return; return;
} }
debugf("Sending update to %s for %s.\n", debugf("Sending update to %s for %s.\n",
net->ifname, format_address(dest->address)); net->ifname, format_prefix(prefix, plen));
buffer_update(net, dest); buffer_update(net, prefix, plen);
} else { } else {
if(now.tv_sec - net->update_time < 2) { send_self_update(net, 0);
send_self_update(net, 0); if(now.tv_sec - net->update_time < 1)
return; return;
} debugf("Sending update to %s for any.\n", net->ifname);
debugf("Sending update to %s for ::/0.\n", net->ifname);
for(i = 0; i < numroutes; i++) for(i = 0; i < numroutes; i++)
if(routes[i].installed) if(routes[i].installed)
buffer_update(net, routes[i].dest); buffer_update(net, routes[i].src->prefix, routes[i].src->plen);
net->update_time = now.tv_sec; net->update_time = now.tv_sec;
send_self_update(net, 0);
} }
schedule_update_flush(); schedule_update_flush();
} }
...@@ -644,14 +593,13 @@ send_update(struct destination *dest, struct network *net) ...@@ -644,14 +593,13 @@ send_update(struct destination *dest, struct network *net)
void void
send_self_update(struct network *net, int force_seqno) send_self_update(struct network *net, int force_seqno)
{ {
if((force_seqno && seqno_time < now.tv_sec) || int i;
seqno_time + seqno_interval < now.tv_sec) { if(force_seqno || seqno_time + seqno_interval < now.tv_sec) {
seqno = ((seqno + 1) & 0xFF); myseqno = ((myseqno + 1) & 0xFFFF);
seqno_time = now.tv_sec; seqno_time = now.tv_sec;
} }
if(net == NULL) { if(net == NULL) {
int i;
for(i = 0; i < numnets; i++) for(i = 0; i < numnets; i++)
send_self_update(&nets[i], 0); send_self_update(&nets[i], 0);
return; return;
...@@ -659,14 +607,20 @@ send_self_update(struct network *net, int force_seqno) ...@@ -659,14 +607,20 @@ send_self_update(struct network *net, int force_seqno)
debugf("Sending self update to %s.\n", net->ifname); debugf("Sending self update to %s.\n", net->ifname);
buffer_update(net, NULL);
net->self_update_time = now.tv_sec; net->self_update_time = now.tv_sec;
for(i = 0; i < numxroutes; i++) {
if(xroutes[i].exported)
send_update(net, xroutes[i].prefix, xroutes[i].plen);
}
schedule_update_flush(); schedule_update_flush();
} }
void void
send_self_retract(struct network *net) send_self_retract(struct network *net)
{ {
int i;
if(net == NULL) { if(net == NULL) {
int i; int i;
for(i = 0; i < numnets; i++) for(i = 0; i < numnets; i++)
...@@ -674,18 +628,18 @@ send_self_retract(struct network *net) ...@@ -674,18 +628,18 @@ send_self_retract(struct network *net)
return; return;
} }
flushupdates();
debugf("Retracting self on %s.\n", net->ifname); debugf("Retracting self on %s.\n", net->ifname);
seqno = ((seqno + 1) & 0xFF); myseqno = ((myseqno + 1) & 0xFFFF);
seqno_time = now.tv_sec; seqno_time = now.tv_sec;
start_message(net, 20);
accumulate_byte(net, 2);
accumulate_byte(net, seqno);
accumulate_short(net, 0xFFFF);
accumulate_data(net, myid, 16);
schedule_flush(net);
net->self_update_time = now.tv_sec; net->self_update_time = now.tv_sec;
for(i = 0; i < numxroutes; i++) {
if(xroutes[i].exported)
really_send_update(net, myid, xroutes[i].prefix, xroutes[i].plen,
myseqno, 0xFFFF);
}
} }
void void
...@@ -694,40 +648,34 @@ send_neighbour_update(struct neighbour *neigh, struct network *net) ...@@ -694,40 +648,34 @@ send_neighbour_update(struct neighbour *neigh, struct network *net)
int i; int i;
for(i = 0; i < numroutes; i++) { for(i = 0; i < numroutes; i++) {
if(routes[i].installed && routes[i].nexthop == neigh) if(routes[i].installed && routes[i].nexthop == neigh)
send_update(routes[i].dest, net); send_update(net, routes[i].src->prefix, routes[i].src->plen);
} }
schedule_update_flush();
} }
void void
send_txcost(struct neighbour *neigh, struct network *net) send_ihu(struct neighbour *neigh, struct network *net)
{ {
int i; int i;
if(neigh == NULL && net == NULL) { if(neigh == NULL && net == NULL) {
for(i = 0; i < numnets; i++) for(i = 0; i < numnets; i++)
send_txcost(NULL, &nets[i]); send_ihu(NULL, &nets[i]);
return; return;
} }
if(neigh == NULL) { if(neigh == NULL) {
if(broadcast_txcost && net->wired) { if(broadcast_ihu && net->wired) {
debugf("Sending broadcast txcost to %s.\n", net->ifname); debugf("Sending broadcast ihu to %s.\n", net->ifname);
start_message(net, 20); send_message(net, 1, 0xFF, 0, net->cost, ones);
accumulate_byte(net, 3);
accumulate_byte(net, 0);
accumulate_short(net, net->cost);
accumulate_data(net, zeroes, 16);
schedule_flush(net);
} else { } else {
for(i = 0; i < numneighs; i++) { for(i = 0; i < numneighs; i++) {
if(neighs[i].id[0] != 0xFF) { if(neighs[i].id[0] != 0xFF) {
if(neighs[i].network == net) if(neighs[i].network == net)
send_txcost(&neighs[i], net); send_ihu(&neighs[i], net);
} }
} }
} }
net->txcost_time = now.tv_sec; net->ihu_time = now.tv_sec;
} else { } else {
int rxcost; int rxcost;
...@@ -736,17 +684,12 @@ send_txcost(struct neighbour *neigh, struct network *net) ...@@ -736,17 +684,12 @@ send_txcost(struct neighbour *neigh, struct network *net)
net = neigh->network; net = neigh->network;
debugf("Sending txcost on %s to %s (%s).\n", debugf("Sending ihu on %s to %s (%s).\n",
neigh->network->ifname, neigh->network->ifname,
format_address(neigh->id), format_address(neigh->id),
format_address(neigh->address)); format_address(neigh->address));
rxcost = neighbour_rxcost(neigh); rxcost = neighbour_rxcost(neigh);
start_message(net, 20); send_message(net, 1, 128, 0, rxcost, neigh->id);
accumulate_byte(net, 3);
accumulate_byte(net, 0);
accumulate_short(net, rxcost);
accumulate_data(net, neigh->id, 16);
schedule_flush(net);
} }
} }
...@@ -20,7 +20,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ...@@ -20,7 +20,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
extern unsigned char seqno; #define MAX_BUFFERED_UPDATES 200
extern unsigned short myseqno;
extern int seqno_time; extern int seqno_time;
extern int seqno_interval; extern int seqno_interval;
...@@ -29,25 +31,26 @@ extern unsigned int update_jitter; ...@@ -29,25 +31,26 @@ extern unsigned int update_jitter;
extern int add_cost; extern int add_cost;
extern int parasitic; extern int parasitic;
extern int silent_time; extern int silent_time;
extern int broadcast_txcost; extern int broadcast_ihu;
extern int split_horizon; extern int split_horizon;
extern struct timeval update_flush_time; extern struct timeval update_flush_time;
extern const unsigned char packet_header[4]; extern const unsigned char packet_header[8];
void parse_packet(const unsigned char *from, struct network *net, void parse_packet(const unsigned char *from, struct network *net,
const unsigned char *packet, int len); const unsigned char *packet, int len);
void flushbuf(struct network *net); void flushbuf(struct network *net);
void send_hello(struct network *net); void send_hello(struct network *net);
void send_request(struct network *net, struct destination *dest, void send_request(struct network *net,
int hopcount, int seqno); const unsigned char *prefix, unsigned char plen);
void send_unicast_request(struct neighbour *neigh, struct destination *dest, void send_unicast_request(struct neighbour *neigh,
int hopcount, int seqno); const unsigned char *prefix, unsigned char plen);
void send_update(struct destination *dest, struct network *net); void send_update(struct network *net,
const unsigned char *prefix, unsigned char plen);
void send_self_update(struct network *net, int force_seqno); void send_self_update(struct network *net, int force_seqno);
void send_self_retract(struct network *net); void send_self_retract(struct network *net);
void send_neighbour_update(struct neighbour *neigh, struct network *net); void send_neighbour_update(struct neighbour *neigh, struct network *net);
void send_txcost(struct neighbour *neigh, struct network *net); void send_ihu(struct neighbour *neigh, struct network *net);
void schedule_flush_now(struct network *net); void schedule_flush_now(struct network *net);
void flushupdates(void); void flushupdates(void);
......
...@@ -29,9 +29,8 @@ THE SOFTWARE. ...@@ -29,9 +29,8 @@ THE SOFTWARE.
#include "babel.h" #include "babel.h"
#include "util.h" #include "util.h"
#include "neighbour.h" #include "neighbour.h"
#include "destination.h" #include "source.h"
#include "route.h" #include "route.h"
#include "xroute.h"
#include "message.h" #include "message.h"
struct neighbour neighs[MAXNEIGHBOURS]; struct neighbour neighs[MAXNEIGHBOURS];
...@@ -40,15 +39,14 @@ int numneighs = 0; ...@@ -40,15 +39,14 @@ int numneighs = 0;
void void
flush_neighbour(struct neighbour *neigh) flush_neighbour(struct neighbour *neigh)
{ {
flush_neighbour_xroutes(neigh);
flush_neighbour_routes(neigh); flush_neighbour_routes(neigh);
memset(neigh, 0, sizeof(*neigh)); memset(neigh, 0, sizeof(*neigh));
if(neigh == &neighs[numneighs - 1]) { VALGRIND_MAKE_MEM_UNDEFINED(neigh, sizeof(*neigh));
neigh->id[0] = 0xFF;
while(numneighs > 0 && neighs[numneighs - 1].id[0] == 0xFF) {
numneighs--; numneighs--;
VALGRIND_MAKE_MEM_UNDEFINED(neigh, sizeof(*neigh)); VALGRIND_MAKE_MEM_UNDEFINED(&neighs[numneighs],
} else { sizeof(neighs[numneighs]));
VALGRIND_MAKE_MEM_UNDEFINED(neigh, sizeof(*neigh));
neigh->id[0] = 0xFF;
} }
} }
...@@ -71,6 +69,7 @@ add_neighbour(const unsigned char *id, const unsigned char *address, ...@@ -71,6 +69,7 @@ add_neighbour(const unsigned char *id, const unsigned char *address,
struct network *net) struct network *net)
{ {
struct neighbour *neigh; struct neighbour *neigh;
const struct timeval zero = {0, 0};
int i; int i;
if(id[0] == 0xFF) { if(id[0] == 0xFF) {
...@@ -104,11 +103,10 @@ add_neighbour(const unsigned char *id, const unsigned char *address, ...@@ -104,11 +103,10 @@ add_neighbour(const unsigned char *id, const unsigned char *address,
} }
memcpy(neigh->id, id, 16); memcpy(neigh->id, id, 16);
memcpy(neigh->address, address, 16); memcpy(neigh->address, address, 16);
neigh->hello_interval = 0;
neigh->reach = 0; neigh->reach = 0;
neigh->txcost = INFINITY; neigh->txcost = INFINITY;
neigh->txcost_time = now.tv_sec; neigh->ihu_time = now.tv_sec;
neigh->hello_time = 0; neigh->hello_time = zero;
neigh->hello_interval = 0; neigh->hello_interval = 0;
neigh->hello_seqno = -1; neigh->hello_seqno = -1;
neigh->network = net; neigh->network = net;
...@@ -116,19 +114,23 @@ add_neighbour(const unsigned char *id, const unsigned char *address, ...@@ -116,19 +114,23 @@ add_neighbour(const unsigned char *id, const unsigned char *address,
return neigh; return neigh;
} }
void /* Recompute a neighbour's rxcost. Return true if anything changed. */
int
update_neighbour(struct neighbour *neigh, int hello, int hello_interval) update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
{ {
int missed_hellos; int missed_hellos;
int rc = 0;
if(hello < 0) { if(hello < 0) {
if(neigh->hello_interval <= 0) if(neigh->hello_interval <= 0)
return; return rc;
missed_hellos = missed_hellos = (timeval_minus_msec(&now, &neigh->hello_time) -
(now.tv_sec - 3 - neigh->hello_time) / neigh->hello_interval; neigh->hello_interval * 6) /
(neigh->hello_interval * 10);
if(missed_hellos <= 0) if(missed_hellos <= 0)
return; return rc;
neigh->hello_time += missed_hellos * neigh->hello_interval; timeval_plus_msec(&neigh->hello_time, &neigh->hello_time,
missed_hellos * neigh->hello_interval * 10);
} else { } else {
if(neigh->hello_seqno >= 0 && neigh->reach > 0) { if(neigh->hello_seqno >= 0 && neigh->reach > 0) {
missed_hellos = seqno_minus(hello, neigh->hello_seqno) - 1; missed_hellos = seqno_minus(hello, neigh->hello_seqno) - 1;
...@@ -137,97 +139,120 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval) ...@@ -137,97 +139,120 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
didn't notice. */ didn't notice. */
neigh->reach <<= -missed_hellos; neigh->reach <<= -missed_hellos;
missed_hellos = 0; missed_hellos = 0;
rc = 1;
} }
} else { } else {
missed_hellos = 0; missed_hellos = 0;
} }
neigh->hello_time = now.tv_sec; neigh->hello_time = now;
neigh->hello_interval = hello_interval; neigh->hello_interval = hello_interval;
} }
neigh->reach >>= missed_hellos; if(missed_hellos > 0) {
missed_hellos = 0; neigh->reach >>= missed_hellos;
missed_hellos = 0;
rc = 1;
}
if(hello >= 0) { if(hello >= 0) {
neigh->hello_seqno = hello; neigh->hello_seqno = hello;
neigh->reach >>= 1; neigh->reach >>= 1;
neigh->reach |= 0x8000; neigh->reach |= 0x8000;
if((neigh->reach & 0xFC00) == 0xFC00)
return rc;
else
rc = 1;
} }
/* Make sure to give neighbours some feedback early after association */ /* Make sure to give neighbours some feedback early after association */
if((neigh->reach & 0xFC00) == 0x8000) { if((neigh->reach & 0xFC00) == 0x8000) {
/* A new neighbour */ /* A new neighbour */
send_hello(neigh->network); send_hello(neigh->network);
send_txcost(neigh, NULL); send_ihu(neigh, NULL);
} else { } else {
/* Don't send hellos, in order to avoid a positive feedback loop. */ /* Don't send hellos, in order to avoid a positive feedback loop. */
int a = (neigh->reach & 0xC000); int a = (neigh->reach & 0xC000);
int b = (neigh->reach & 0x3000); int b = (neigh->reach & 0x3000);
if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) { if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) {
/* Reachability is either 1100 or 0011 */ /* Reachability is either 1100 or 0011 */
send_txcost(neigh, NULL); send_ihu(neigh, NULL);
send_self_update(neigh->network, 0); send_self_update(neigh->network, 0);
send_neighbour_update(neigh, NULL); send_neighbour_update(neigh, NULL);
} }
} }
if((neigh->reach & 0xFF00) == 0xC000) { if((neigh->reach & 0xFC00) == 0xC000) {
/* This is a newish neighbour. If we don't have another route to it, /* This is a newish neighbour. If we don't have another route to it,
request a full route dump. This assumes that the neighbour's ID request a full route dump. This assumes that the neighbour's id
is also its IP address. */ is also its IP address and that it is exporting a route to itself. */
struct destination *dest;
struct route *route = NULL; struct route *route = NULL;
dest = find_destination(neigh->id, 0, 0); if(!martian_prefix(neigh->id, 128))
if(dest) route = find_installed_route(neigh->id, 128);
route = find_installed_route(dest);
if(!route || route->metric >= INFINITY || route->nexthop == neigh) if(!route || route->metric >= INFINITY || route->nexthop == neigh)
send_unicast_request(neigh, NULL, 0, -1); send_unicast_request(neigh, NULL, 0);
} }
return rc;
} }
void int
check_neighbour(struct neighbour *neigh) check_neighbours()
{ {
update_neighbour(neigh, -1, 0); int i, changed;
if(neigh->reach == 0) { int msecs = 50000;
flush_neighbour(neigh);
return; debugf("Checking neighbours.\n");
}
for(i = 0; i < numneighs; i++) {
if(neighs[i].id[0] == 0xFF)
continue;
if(!neigh->network->wired) { changed = update_neighbour(&neighs[i], -1, 0);
while(neigh->txcost < INFINITY &&
neigh->txcost_time <= now.tv_sec - 40) { if(neighs[i].reach == 0 ||
neigh->txcost = MIN((int)neigh->txcost * 3 / 2, INFINITY); timeval_minus_msec(&now, &neighs[i].hello_time) > 300000) {
neigh->txcost_time += 10; flush_neighbour(&neighs[i]);
continue;
} }
if(changed)
update_neighbour_metric(&neighs[i]);
if(neighs[i].hello_interval > 0)
msecs = MIN(msecs, neighs[i].hello_interval * 10);
} }
return msecs;
} }
int int
neighbour_rxcost(struct neighbour *neigh) neighbour_rxcost(struct neighbour *neigh)
{ {
update_neighbour(neigh, -1, 0); int delay;
if((neigh->reach & 0xF800) == 0) unsigned short reach = neigh->reach;
delay = timeval_minus_msec(&now, &neigh->hello_time);
if((reach & 0xF800) == 0 || delay >= 180000) {
return INFINITY; return INFINITY;
else if(neigh->network->wired) { } else if(neigh->network->wired) {
if((neigh->reach & 0xE000) != 0) { /* To lose one hello is a misfortune, to lose two is carelessness. */
int c = neigh->network->cost; if((reach & 0xC000) == 0xC000)
int d = now.tv_sec - neigh->hello_time; return neigh->network->cost;
if(d >= 60) else if((reach & 0xC000) == 0)
c = (c * (d - 40) + 19) / 20; return INFINITY;
return MIN(c, INFINITY); else if((reach & 0x2000))
} else { return neigh->network->cost;
else
return INFINITY; return INFINITY;
}
} else { } else {
int r = (neigh->reach & 0x7FFF) + ((neigh->reach & 0x8000) >> 1); int sreach = (reach & 0x7FFF) + ((reach & 0x8000) >> 1);
/* 0 <= r <= 0xBFFF */ /* 0 <= sreach <= 0xBFFF */
int c = (0xC000 * 0x100) / r; int cost = (0xC000 * neigh->network->cost) / (sreach + 1);
int d = now.tv_sec - neigh->hello_time; /* cost >= network->cost */
if(d >= 40) if(delay >= 40000)
c = (c * (d - 20) + 10) / 20; cost = (cost * (delay - 20000) + 10000) / 20000;
return MIN(c + neigh->network->cost, INFINITY); return MIN(cost, INFINITY);
} }
} }
...@@ -236,6 +261,9 @@ neighbour_cost(struct neighbour *neigh) ...@@ -236,6 +261,9 @@ neighbour_cost(struct neighbour *neigh)
{ {
int a, b; int a, b;
if(now.tv_sec - neigh->ihu_time >= 180)
return INFINITY;
a = neigh->txcost; a = neigh->txcost;
if(a >= INFINITY) if(a >= INFINITY)
......
...@@ -26,10 +26,10 @@ struct neighbour { ...@@ -26,10 +26,10 @@ struct neighbour {
unsigned short reach; unsigned short reach;
unsigned short txcost; unsigned short txcost;
/* This is -1 when unknown, so don't make it unsigned */ /* This is -1 when unknown, so don't make it unsigned */
short int hello_seqno; int hello_seqno;
int txcost_time; int ihu_time;
int hello_time; struct timeval hello_time;
int hello_interval; unsigned short hello_interval; /* in centiseconds */
struct network *network; struct network *network;
}; };
...@@ -42,7 +42,7 @@ struct neighbour *find_neighbour(const unsigned char *address, ...@@ -42,7 +42,7 @@ struct neighbour *find_neighbour(const unsigned char *address,
struct neighbour * struct neighbour *
add_neighbour(const unsigned char *id, const unsigned char *address, add_neighbour(const unsigned char *id, const unsigned char *address,
struct network *net); struct network *net);
void update_neighbour(struct neighbour *neigh, int hello, int hello_interval); int update_neighbour(struct neighbour *neigh, int hello, int hello_interval);
void check_neighbour(struct neighbour *neigh); int check_neighbours(void);
int neighbour_rxcost(struct neighbour *neigh); int neighbour_rxcost(struct neighbour *neigh);
int neighbour_cost(struct neighbour *neigh); int neighbour_cost(struct neighbour *neigh);
...@@ -29,7 +29,7 @@ THE SOFTWARE. ...@@ -29,7 +29,7 @@ THE SOFTWARE.
#include "babel.h" #include "babel.h"
#include "util.h" #include "util.h"
#include "kernel.h" #include "kernel.h"
#include "destination.h" #include "source.h"
#include "neighbour.h" #include "neighbour.h"
#include "route.h" #include "route.h"
#include "xroute.h" #include "xroute.h"
...@@ -42,22 +42,24 @@ int route_timeout_delay = 50; ...@@ -42,22 +42,24 @@ int route_timeout_delay = 50;
int route_gc_delay = 95; int route_gc_delay = 95;
struct route * struct route *
find_route(struct destination *dest, struct neighbour *nexthop) find_route(const unsigned char *prefix, unsigned char plen,
struct neighbour *nexthop)
{ {
int i; int i;
for(i = 0; i < numroutes; i++) { for(i = 0; i < numroutes; i++) {
if(routes[i].nexthop == nexthop && routes[i].dest == dest) if(routes[i].nexthop == nexthop &&
source_match(routes[i].src, prefix, plen))
return &routes[i]; return &routes[i];
} }
return NULL; return NULL;
} }
struct route * struct route *
find_installed_route(struct destination *dest) find_installed_route(const unsigned char *prefix, unsigned char plen)
{ {
int i; int i;
for(i = 0; i < numroutes; i++) { for(i = 0; i < numroutes; i++) {
if(routes[i].installed && routes[i].dest == dest) if(routes[i].installed && source_match(routes[i].src, prefix, plen))
return &routes[i]; return &routes[i];
} }
return NULL; return NULL;
...@@ -67,8 +69,8 @@ void ...@@ -67,8 +69,8 @@ void
flush_route(struct route *route) flush_route(struct route *route)
{ {
int n; int n;
struct destination *dest; struct source *src;
int install = 0, oldmetric; int oldmetric, lost = 0;
n = route - routes; n = route - routes;
assert(n >= 0 && n < numroutes); assert(n >= 0 && n < numroutes);
...@@ -77,33 +79,18 @@ flush_route(struct route *route) ...@@ -77,33 +79,18 @@ flush_route(struct route *route)
if(route->installed) { if(route->installed) {
uninstall_route(route); uninstall_route(route);
install = 1; lost = 1;
} }
dest = route->dest; src = route->src;
if(n != numroutes - 1) if(n != numroutes - 1)
memcpy(routes + n, routes + numroutes - 1, sizeof(struct route)); memcpy(routes + n, routes + numroutes - 1, sizeof(struct route));
numroutes--; numroutes--;
VALGRIND_MAKE_MEM_UNDEFINED(routes + numroutes, sizeof(struct route)); VALGRIND_MAKE_MEM_UNDEFINED(routes + numroutes, sizeof(struct route));
if(install) { if(lost)
struct route *new_route; route_lost(src, oldmetric);
new_route = find_best_route(dest);
if(new_route) {
install_route(new_route);
send_triggered_update(new_route, oldmetric);
} else {
if(dest->metric < INFINITY) {
dest->metric = INFINITY;
dest->seqno = (dest->seqno + 1) & 0xFF;
}
send_update(dest, NULL);
}
if(oldmetric < INFINITY &&
(!new_route || new_route->metric >= INFINITY))
send_request(NULL, route->dest, max_request_hopcount, -1);
}
} }
void void
...@@ -135,17 +122,12 @@ metric_to_kernel(int metric) ...@@ -135,17 +122,12 @@ metric_to_kernel(int metric)
void void
install_route(struct route *route) install_route(struct route *route)
{ {
struct route *installed;
int rc; int rc;
if(route->installed) if(route->installed)
return; return;
installed = find_installed_route(route->dest); rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen,
if(installed)
uninstall_route(installed);
rc = kernel_route(ROUTE_ADD, route->dest->address, 128,
route->nexthop->address, route->nexthop->address,
route->nexthop->network->ifindex, route->nexthop->network->ifindex,
metric_to_kernel(route->metric), 0); metric_to_kernel(route->metric), 0);
...@@ -155,60 +137,85 @@ install_route(struct route *route) ...@@ -155,60 +137,85 @@ install_route(struct route *route)
return; return;
} }
route->installed = 1; route->installed = 1;
consider_all_xroutes(route);
} }
void void
uninstall_route(struct route *route) uninstall_route(struct route *route)
{ {
int i, rc; int rc;
if(!route->installed) if(!route->installed)
return; return;
for(i = 0; i < numxroutes; i++) { rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen,
if(xroutes[i].installed &&
xroutes[i].gateway == route->dest &&
xroutes[i].nexthop == route->nexthop)
uninstall_xroute(&xroutes[i]);
}
rc = kernel_route(ROUTE_FLUSH, route->dest->address, 128,
route->nexthop->address, route->nexthop->address,
route->nexthop->network->ifindex, route->nexthop->network->ifindex,
metric_to_kernel(route->metric), 0); metric_to_kernel(route->metric), 0);
if(rc < 0) if(rc < 0)
perror("kernel_route(FLUSH)"); perror("kernel_route(FLUSH)");
route->installed = 0; route->installed = 0;
} }
void
change_route_metric(struct route *route, int newmetric)
{
int rc;
if(route->installed) {
rc = kernel_route(ROUTE_MODIFY,
route->src->prefix, route->src->plen,
route->nexthop->address,
route->nexthop->network->ifindex,
metric_to_kernel(route->metric),
metric_to_kernel(newmetric));
if(rc < 0) {
perror("kernel_route(MODIFY)");
return;
}
}
route->metric = newmetric;
}
int int
route_feasible(struct route *route) route_feasible(struct route *route)
{ {
return update_feasible(route->seqno, route->refmetric, route->dest); return update_feasible(route->src->address,
route->src->prefix, route->src->plen,
route->seqno, route->refmetric);
} }
int int
update_feasible(unsigned char seqno, unsigned short refmetric, update_feasible(const unsigned char *a,
struct destination *dest) const unsigned char *p, unsigned char plen,
unsigned short seqno, unsigned short refmetric)
{ {
if(dest->time < now.tv_sec - 200) { struct source *src = find_source(a, p, plen, 0, 0);
if(src == NULL)
return 1;
if(src->time < now.tv_sec - 200)
/* Never mind what is probably stale data */ /* Never mind what is probably stale data */
return 1; return 1;
}
return (seqno_compare(dest->seqno, seqno) < 0 || if(refmetric >= INFINITY)
(dest->seqno == seqno && refmetric < dest->metric)); /* Retractions are always feasible */
return 1;
return (seqno_compare(seqno, src->seqno) > 0 ||
(src->seqno == seqno && refmetric < src->metric));
} }
/* This returns a feasible route. The only condition it must satisfy if that
if there is a feasible route, then one will be found. */
struct route * struct route *
find_best_route(struct destination *dest) find_best_route(const unsigned char *prefix, unsigned char plen)
{ {
struct route *route = NULL; struct route *route = NULL;
int i; int i;
for(i = 0; i < numroutes; i++) { for(i = 0; i < numroutes; i++) {
if(routes[i].dest != dest) if(!source_match(routes[i].src, prefix, plen))
continue; continue;
if(routes[i].time < now.tv_sec - route_timeout_delay) if(routes[i].time < now.tv_sec - route_timeout_delay)
continue; continue;
...@@ -229,19 +236,6 @@ find_best_route(struct destination *dest) ...@@ -229,19 +236,6 @@ find_best_route(struct destination *dest)
return route; return route;
} }
void
update_neighbour_metric(struct neighbour *neigh)
{
int i;
i = 0;
while(i < numroutes) {
if(routes[i].nexthop == neigh)
update_route_metric(&routes[i]);
i++;
}
}
void void
update_route_metric(struct route *route) update_route_metric(struct route *route)
{ {
...@@ -251,7 +245,7 @@ update_route_metric(struct route *route) ...@@ -251,7 +245,7 @@ update_route_metric(struct route *route)
oldmetric = route->metric; oldmetric = route->metric;
if(route->time < now.tv_sec - route_timeout_delay) { if(route->time < now.tv_sec - route_timeout_delay) {
if(route->refmetric < INFINITY) { if(route->refmetric < INFINITY) {
route->seqno = (route->dest->seqno + 1) & 0xFF; route->seqno = (route->src->seqno + 1) & 0xFFFF;
route->refmetric = INFINITY; route->refmetric = INFINITY;
} }
newmetric = INFINITY; newmetric = INFINITY;
...@@ -261,59 +255,73 @@ update_route_metric(struct route *route) ...@@ -261,59 +255,73 @@ update_route_metric(struct route *route)
} }
change_route_metric(route, newmetric); change_route_metric(route, newmetric);
trigger_route_change(route, route->src, oldmetric);
}
if(route->installed) { void
if(newmetric > oldmetric) { update_neighbour_metric(struct neighbour *neigh)
struct route *better_route; {
better_route = find_best_route(route->dest); int i;
if(better_route && better_route->metric <= route->metric - 96)
consider_route(better_route); i = 0;
} while(i < numroutes) {
if(route->installed) if(routes[i].nexthop == neigh)
send_triggered_update(route, oldmetric); update_route_metric(&routes[i]);
} else if(newmetric < oldmetric) { i++;
consider_route(route);
} }
} }
/* This is called whenever we receive an update. */
struct route * struct route *
update_route(const unsigned char *d, int seqno, int refmetric, update_route(const unsigned char *a, const unsigned char *p, unsigned char plen,
struct neighbour *nexthop, unsigned short seqno, unsigned short refmetric,
struct xroute *pxroutes, int numpxroutes) struct neighbour *nexthop)
{ {
struct route *route; struct route *route;
struct destination *dest; struct source *src;
int i, metric; int metric, feasible;
if(martian_prefix(d, 128)) { if(martian_prefix(p, plen)) {
fprintf(stderr, "Rejecting martian route to %s.\n", fprintf(stderr, "Rejecting martian route to %s through %s.\n",
format_address(d)); format_prefix(p, plen), format_address(a));
return NULL; return NULL;
} }
dest = find_destination(d, 1, seqno); src = find_source(a, p, plen, 1, seqno);
if(dest == NULL) if(src == NULL)
return NULL; return NULL;
if(!update_feasible(seqno, refmetric, dest)) { feasible = update_feasible(a, p, plen, seqno, refmetric);
debugf("Rejecting unfeasible update from %s.\n", route = find_route(p, plen, nexthop);
format_address(nexthop->address)); metric = MIN((int)refmetric + neighbour_cost(nexthop), INFINITY);
/* It would be really nice to send a request at this point,
but that might get us into a positive feedback loop. */
return NULL;
}
metric = MIN(refmetric + neighbour_cost(nexthop), INFINITY);
route = find_route(dest, nexthop);
if(route) { if(route) {
int oldseqno; struct source *oldsrc;
int oldmetric; unsigned short oldseqno;
unsigned short oldmetric;
int lost = 0;
oldsrc = route->src;
oldseqno = route->seqno; oldseqno = route->seqno;
oldmetric = route->metric; oldmetric = route->metric;
if(refmetric < INFINITY) {
/* If a successor switches sources, we must accept his update even
if it makes a route unfeasible in order to break any routing loops.
It's not clear to me (jch) what is the best approach if the
successor sticks to the same source but increases its metric. */
if(!feasible && route->installed) {
debugf("Unfeasible update for installed route to %s "
"(%s %d %d -> %s %d %d).\n",
format_prefix(src->prefix, src->plen),
format_address(route->src->address),
route->seqno, route->refmetric,
format_address(src->address), seqno, refmetric);
uninstall_route(route);
lost = 1;
}
route->src = src;
if(feasible && refmetric < INFINITY) {
route->time = now.tv_sec; route->time = now.tv_sec;
if(route->refmetric >= INFINITY) if(route->refmetric >= INFINITY)
route->origtime = now.tv_sec; route->origtime = now.tv_sec;
...@@ -321,20 +329,14 @@ update_route(const unsigned char *d, int seqno, int refmetric, ...@@ -321,20 +329,14 @@ update_route(const unsigned char *d, int seqno, int refmetric,
route->seqno = seqno; route->seqno = seqno;
route->refmetric = refmetric; route->refmetric = refmetric;
change_route_metric(route, metric); change_route_metric(route, metric);
if(seqno_compare(oldseqno, seqno) <= 0) {
if(seqno_compare(oldseqno, seqno) < 0) if(feasible)
retract_xroutes(dest, nexthop, pxroutes, numpxroutes); trigger_route_change(route, oldsrc, oldmetric);
for(i = 0; i < numpxroutes; i++) else if(lost)
update_xroute(pxroutes[i].prefix, route_lost(oldsrc, oldmetric);
pxroutes[i].plen,
dest, nexthop,
pxroutes[i].cost);
}
if(route->installed)
send_triggered_update(route, oldmetric);
else
consider_route(route);
} else { } else {
if(!feasible)
return NULL;
if(refmetric >= INFINITY) if(refmetric >= INFINITY)
/* Somebody's retracting a route we never saw. */ /* Somebody's retracting a route we never saw. */
return NULL; return NULL;
...@@ -343,7 +345,7 @@ update_route(const unsigned char *d, int seqno, int refmetric, ...@@ -343,7 +345,7 @@ update_route(const unsigned char *d, int seqno, int refmetric,
return NULL; return NULL;
} }
route = &routes[numroutes]; route = &routes[numroutes];
route->dest = dest; route->src = src;
route->refmetric = refmetric; route->refmetric = refmetric;
route->seqno = seqno; route->seqno = seqno;
route->metric = metric; route->metric = metric;
...@@ -352,16 +354,14 @@ update_route(const unsigned char *d, int seqno, int refmetric, ...@@ -352,16 +354,14 @@ update_route(const unsigned char *d, int seqno, int refmetric,
route->origtime = now.tv_sec; route->origtime = now.tv_sec;
route->installed = 0; route->installed = 0;
numroutes++; numroutes++;
for(i = 0; i < numpxroutes; i++)
update_xroute(pxroutes[i].prefix,
pxroutes[i].plen,
dest, nexthop,
pxroutes[i].cost);
consider_route(route); consider_route(route);
} }
return route; return route;
} }
/* This takes a feasible route and decides whether to install it. The only
condition that it must satisfy is that if there is no currently installed
route, then one will be installed. */
void void
consider_route(struct route *route) consider_route(struct route *route)
{ {
...@@ -373,7 +373,10 @@ consider_route(struct route *route) ...@@ -373,7 +373,10 @@ consider_route(struct route *route)
if(!route_feasible(route)) if(!route_feasible(route))
return; return;
installed = find_installed_route(route->dest); if(find_exported_xroute(route->src->prefix, route->src->plen))
return;
installed = find_installed_route(route->src->prefix, route->src->plen);
if(installed == NULL) if(installed == NULL)
goto install; goto install;
...@@ -381,62 +384,112 @@ consider_route(struct route *route) ...@@ -381,62 +384,112 @@ consider_route(struct route *route)
if(installed->metric >= route->metric + 384) if(installed->metric >= route->metric + 384)
goto install; goto install;
/* Avoid routes that haven't been around for some time */
if(route->origtime >= now.tv_sec - 30) if(route->origtime >= now.tv_sec - 30)
return; return;
if(installed->metric >= route->metric + 192)
goto install;
/* Avoid switching sources */
if(installed->src != route->src)
return;
if(installed->metric >= route->metric + 96) if(installed->metric >= route->metric + 96)
goto install; goto install;
return; return;
install: install:
install_route(route);
if(installed) if(installed)
send_triggered_update(route, installed->metric); uninstall_route(installed);
install_route(route);
if(installed && route->installed)
send_triggered_update(route, installed->src, installed->metric);
else else
send_update(route->dest, NULL); send_update(NULL, route->src->prefix, route->src->plen);
return; return;
} }
void void
change_route_metric(struct route *route, int newmetric) send_triggered_update(struct route *route, struct source *oldsrc, int oldmetric)
{
if(!route->installed)
return;
/* Switching sources can cause transient routing loops, so always send
updates in that case */
if(route->src != oldsrc ||
((route->metric >= INFINITY) != (oldmetric >= INFINITY)) ||
(route->metric >= oldmetric + 256 || oldmetric >= route->metric + 256))
send_update(NULL, route->src->prefix, route->src->plen);
if(oldmetric < INFINITY) {
if(route->metric >= INFINITY || route->metric - oldmetric >= 384)
send_request(NULL, route->src->prefix, route->src->plen);
}
}
/* A route has just changed. Decide whether to switch to a different route or
send an update. */
void
trigger_route_change(struct route *route,
struct source *oldsrc, unsigned short oldmetric)
{ {
int rc;
if(route->installed) { if(route->installed) {
rc = kernel_route(ROUTE_MODIFY, if(route->metric > oldmetric) {
route->dest->address, 128, struct route *better_route;
route->nexthop->address, better_route =
route->nexthop->network->ifindex, find_best_route(route->src->prefix, route->src->plen);
metric_to_kernel(route->metric), if(better_route && better_route->metric <= route->metric - 96)
metric_to_kernel(newmetric)); consider_route(better_route);
if(rc < 0) {
perror("kernel_route(MODIFY)");
return;
} }
if(route->installed)
send_triggered_update(route, oldsrc, oldmetric);
} else if(route->metric < oldmetric) {
consider_route(route);
} }
route->metric = newmetric;
} }
/* We just lost the installed route to a given destination. */
void void
send_triggered_update(struct route *route, int oldmetric) route_lost(struct source *src, int oldmetric)
{ {
if(!route->installed) struct route *new_route;
return; new_route = find_best_route(src->prefix, src->plen);
if(new_route) {
consider_route(new_route);
} else {
/* Complain loudly. */
send_update(NULL, src->prefix, src->plen);
if(oldmetric < INFINITY)
send_request(NULL, src->prefix, src->plen);
}
}
void
expire_routes(void)
{
int i;
if((route->metric >= INFINITY && oldmetric < INFINITY) || debugf("Expiring old routes.\n");
(route->metric - oldmetric >= 256 || oldmetric - route->metric >= 256))
send_update(route->dest, NULL);
else if(request_requested(route->dest, route->seqno, NULL))
send_update(route->dest, route->dest->requested_net);
if(oldmetric < INFINITY) { i = 0;
if(route->metric >= INFINITY) { while(i < numroutes) {
/* We just lost a route, request a new seqno from the source */ struct route *route = &routes[i];
send_request(NULL, route->dest, max_request_hopcount, -1);
} else if(route->metric - oldmetric >= 384) { if(route->time < now.tv_sec - route_gc_delay) {
/* This route's metric has increased a lot -- let's hope we find flush_route(route);
something better */ continue;
send_request(NULL, route->dest, 1, route->seqno);
} }
update_route_metric(route);
if(route->installed && route->refmetric < INFINITY) {
if(route->time < now.tv_sec - MAX(10, route_timeout_delay - 25))
send_unicast_request(route->nexthop,
route->src->prefix, route->src->plen);
}
i++;
} }
} }
...@@ -20,13 +20,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ...@@ -20,13 +20,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
struct xroute;
struct route { struct route {
struct destination *dest; struct source *src;
unsigned short metric; unsigned short metric;
unsigned short refmetric; unsigned short refmetric;
unsigned char seqno; unsigned short seqno;
struct neighbour *nexthop; struct neighbour *nexthop;
int time; int time;
int origtime; int origtime;
...@@ -39,22 +37,33 @@ extern int kernel_metric; ...@@ -39,22 +37,33 @@ extern int kernel_metric;
extern int route_timeout_delay; extern int route_timeout_delay;
extern int route_gc_delay; extern int route_gc_delay;
struct route *find_route(struct destination *dest, struct neighbour *nexthop); struct route *find_route(const unsigned char *prefix, unsigned char plen,
struct route *find_installed_route(struct destination *dest); struct neighbour *nexthop);
struct route *find_installed_route(const unsigned char *prefix,
unsigned char plen);
void flush_route(struct route *route); void flush_route(struct route *route);
void flush_neighbour_routes(struct neighbour *neigh); void flush_neighbour_routes(struct neighbour *neigh);
unsigned int metric_to_kernel(int metric); unsigned int metric_to_kernel(int metric);
void install_route(struct route *route); void install_route(struct route *route);
void uninstall_route(struct route *route); void uninstall_route(struct route *route);
void change_route_metric(struct route *route, int newmetric);
int route_feasible(struct route *route); int route_feasible(struct route *route);
int update_feasible(unsigned char seqno, unsigned short refmetric, int update_feasible(const unsigned char *a,
struct destination *dest); const unsigned char *p, unsigned char plen,
struct route *find_best_route(struct destination *dest); unsigned short seqno, unsigned short refmetric);
struct route *find_best_route(const unsigned char *prefix, unsigned char plen);
struct route *install_best_route(const unsigned char prefix[16],
unsigned char plen);
void update_neighbour_metric(struct neighbour *neigh); void update_neighbour_metric(struct neighbour *neigh);
void update_route_metric(struct route *route); void update_route_metric(struct route *route);
struct route *update_route(const unsigned char *d, int seqno, int refmetric, struct route *update_route(const unsigned char *a,
struct neighbour *nexthop, const unsigned char *p, unsigned char plen,
struct xroute *pxroutes, int numpxroutes); unsigned short seqno, unsigned short refmetric,
struct neighbour *nexthop);
void consider_route(struct route *route); void consider_route(struct route *route);
void change_route_metric(struct route *route, int newmetric); void send_triggered_update(struct route *route,
void send_triggered_update(struct route *route, int oldmetric); struct source *oldsrc, int oldmetric);
void trigger_route_change(struct route *route,
struct source *oldsrc, unsigned short oldmetric);
void route_lost(struct source *src, int oldmetric);
void expire_routes(void);
...@@ -23,107 +23,86 @@ THE SOFTWARE. ...@@ -23,107 +23,86 @@ THE SOFTWARE.
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include "babel.h" #include "babel.h"
#include "util.h" #include "util.h"
#include "destination.h" #include "source.h"
struct destination dests[MAXDESTS]; struct source srcs[MAXSRCS];
int numdests = 0; int numsrcs = 0;
struct destination * struct source *
find_destination(const unsigned char *d, int create, unsigned char seqno) find_source(const unsigned char *a, const unsigned char *p, unsigned char plen,
int create, unsigned short seqno)
{ {
int i; int i;
for(i = 0; i < numdests; i++) { for(i = 0; i < numsrcs; i++) {
/* This should really be a hash table. For now, check the /* This should really be a hash table. For now, check the
last byte first. */ last byte first. */
if(dests[i].address[15] != d[15]) if(srcs[i].address[15] != a[15])
continue; continue;
if(memcmp(dests[i].address, d, 16) == 0) if(memcmp(srcs[i].address, a, 16) != 0)
return &dests[i]; continue;
if(source_match(&srcs[i], p, plen))
return &srcs[i];
} }
if(!create) if(!create)
return NULL; return NULL;
if(numdests >= MAXDESTS) { if(numsrcs >= MAXSRCS) {
fprintf(stderr, "Too many destinations.\n"); fprintf(stderr, "Too many sources.\n");
return NULL; return NULL;
} }
memcpy(dests[numdests].address, d, 16); memcpy(srcs[numsrcs].address, a, 16);
dests[numdests].seqno = seqno; memcpy(srcs[numsrcs].prefix, p, 16);
dests[numdests].metric = INFINITY; srcs[numsrcs].plen = plen;
dests[numdests].time = now.tv_sec; srcs[numsrcs].seqno = seqno;
dests[numdests].requested_seqno = -1; srcs[numsrcs].metric = INFINITY;
dests[numdests].requested_net = NULL; srcs[numsrcs].time = now.tv_sec;
return &dests[numdests++]; return &srcs[numsrcs++];
} }
void struct source *
update_destination(struct destination *dest, find_recent_source(const unsigned char *p, unsigned char plen)
unsigned char seqno, unsigned short metric)
{ {
if(seqno_compare(dest->seqno, seqno) < 0 || int i;
(dest->seqno == seqno && dest->metric > metric)) { struct source *src = NULL;
dest->seqno = seqno;
dest->metric = metric;
}
dest->time = now.tv_sec;
if(dest->requested_seqno >= 0) {
if(seqno_minus(dest->requested_seqno, seqno) >= 16) {
/* Stale data? */
dest->requested_seqno = -1;
dest->requested_net = NULL;
}
}
}
void for(i = 0; i < numsrcs; i++) {
notice_request(struct destination *dest, unsigned char seqno, if(!source_match(&srcs[i], p, plen))
struct network *net) continue;
{ if(!src || src->time < srcs[i].time)
if(dest->requested_seqno < 0) { src = &srcs[i];
dest->requested_seqno = seqno;
dest->requested_net = net;
} else {
if(seqno_compare(dest->requested_seqno, seqno) < 0)
dest->requested_seqno = seqno;
if(net == NULL || net != dest->requested_net)
dest->requested_net = NULL;
} }
return src;
} }
int int
request_requested(struct destination *dest, unsigned char seqno, source_match(struct source *src,
struct network *net) const unsigned char *p, unsigned char plen)
{ {
if(dest->requested_seqno < 0) if(src->plen != plen)
return 0; return 0;
if(src->prefix[15] != p[15])
if(seqno_compare(dest->requested_seqno, seqno) < 0)
return 0; return 0;
if(memcmp(src->prefix, p, 16) != 0)
if(dest->requested_net == NULL)
return 1;
if(net == NULL || net != dest->requested_net)
return 0; return 0;
return 1; return 1;
} }
void void
satisfy_request(struct destination *dest, unsigned char seqno, update_source(struct source *src,
struct network *net) unsigned short seqno, unsigned short metric)
{ {
if(dest->requested_seqno >= 0) { if(metric >= INFINITY)
if(net == NULL || net == dest->requested_net) { return;
if(seqno_compare(seqno, dest->requested_seqno) >= 0) {
dest->requested_seqno = -1; if(seqno_compare(src->seqno, seqno) < 0 ||
dest->requested_net = NULL; (src->seqno == seqno && src->metric > metric)) {
} src->seqno = seqno;
} src->metric = metric;
} }
src->time = now.tv_sec;
} }
...@@ -20,22 +20,22 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ...@@ -20,22 +20,22 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
struct destination { struct source {
unsigned char address[16]; unsigned char address[16];
unsigned char seqno; unsigned char prefix[16];
unsigned char plen;
unsigned short seqno;
unsigned short metric; unsigned short metric;
int time; int time;
int requested_seqno;
struct network *requested_net;
}; };
struct destination *find_destination(const unsigned char *d, int source_match(struct source *src,
int create, unsigned char seqno); const unsigned char *p, unsigned char plen);
void update_destination(struct destination *dest, struct source *find_source(const unsigned char *a,
unsigned char seqno, unsigned short metric); const unsigned char *p,
void notice_request(struct destination *dest, unsigned char seqno, unsigned char plen,
struct network *net); int create, unsigned short seqno);
int request_requested(struct destination *dest, unsigned char seqno, struct source *find_recent_source(const unsigned char *p,
struct network *net); unsigned char plen);
void satisfy_request(struct destination *dest, unsigned char seqno, void update_source(struct source *src,
struct network *net); unsigned short seqno, unsigned short metric);
...@@ -38,7 +38,7 @@ seqno_compare(unsigned char s1, unsigned char s2) ...@@ -38,7 +38,7 @@ seqno_compare(unsigned char s1, unsigned char s2)
{ {
if(s1 == s2) if(s1 == s2)
return 0; return 0;
else if(((s2 - s1) & 0xFF) < 128) else if(((s2 - s1) & 0xFFFF) < 0x8000)
return -1; return -1;
else else
return 1; return 1;
...@@ -49,10 +49,10 @@ seqno_minus(unsigned char s1, unsigned char s2) ...@@ -49,10 +49,10 @@ seqno_minus(unsigned char s1, unsigned char s2)
{ {
if(s1 == s2) if(s1 == s2)
return 0; return 0;
else if(((s2 - s1) & 0xFF) < 128) else if(((s2 - s1) & 0xFFFF) < 0x8000)
return -(int)((s2 - s1) & 0xFF); return -(int)((s2 - s1) & 0xFFFF);
else else
return ((s1 - s2) & 0xFF); return ((s1 - s2) & 0xFFFF);
} }
void void
...@@ -75,6 +75,20 @@ timeval_minus_msec(const struct timeval *s1, const struct timeval *s2) ...@@ -75,6 +75,20 @@ timeval_minus_msec(const struct timeval *s1, const struct timeval *s2)
(s1->tv_usec - s2->tv_usec) / 1000; (s1->tv_usec - s2->tv_usec) / 1000;
} }
void
timeval_plus_msec(struct timeval *d, const struct timeval *s, int msecs)
{
int usecs;
d->tv_sec = s->tv_sec + msecs / 1000;
usecs = s->tv_usec + (msecs % 1000) * 1000;
if(usecs < 1000000) {
d->tv_usec = usecs;
} else {
d->tv_usec = usecs - 1000000;
d->tv_sec++;
}
}
int int
timeval_compare(const struct timeval *s1, const struct timeval *s2) timeval_compare(const struct timeval *s1, const struct timeval *s2)
{ {
...@@ -122,6 +136,38 @@ do_debugf(const char *format, ...) ...@@ -122,6 +136,38 @@ do_debugf(const char *format, ...)
fflush(stderr); fflush(stderr);
} }
int
in_prefix(const unsigned char *address,
const unsigned char *prefix, unsigned char plen)
{
unsigned char m;
if(plen > 128)
plen = 128;
if(memcmp(address, prefix, plen / 8) != 0)
return 0;
m = 0xFF << (8 - (plen % 8));
return ((address[plen / 8] & m) == (prefix[plen / 8] & m));
}
const unsigned char *
mask_prefix(const unsigned char *prefix, unsigned char plen)
{
static unsigned char ret[16];
if(plen > 128)
plen = 128;
memset(ret, 0, 16);
memcpy(ret, prefix, plen / 8);
if(plen % 8 != 0)
ret[plen / 8] = 0xFF << (8 - (plen % 8));
return (const unsigned char *)ret;
}
const char * const char *
format_address(const unsigned char *address) format_address(const unsigned char *address)
{ {
...@@ -131,6 +177,19 @@ format_address(const unsigned char *address) ...@@ -131,6 +177,19 @@ format_address(const unsigned char *address)
return inet_ntop(AF_INET6, address, buf[i], INET6_ADDRSTRLEN); return inet_ntop(AF_INET6, address, buf[i], INET6_ADDRSTRLEN);
} }
const char *
format_prefix(const unsigned char *prefix, unsigned char plen)
{
static char buf[4][INET6_ADDRSTRLEN + 4];
static int i = 0;
int n;
i = (i + 1) % 4;
inet_ntop(AF_INET6, prefix, buf[i], INET6_ADDRSTRLEN);
n = strlen(buf[i]);
snprintf(buf[i] + n, INET6_ADDRSTRLEN + 4 - n, "/%d", plen);
return buf[i];
}
int int
parse_address(const char *address, unsigned char *addr_r) parse_address(const char *address, unsigned char *addr_r)
{ {
...@@ -146,12 +205,12 @@ parse_address(const char *address, unsigned char *addr_r) ...@@ -146,12 +205,12 @@ parse_address(const char *address, unsigned char *addr_r)
} }
int int
parse_net(const char *net, unsigned char *prefix_r, unsigned short *plen_r) parse_net(const char *net, unsigned char *prefix_r, unsigned char *plen_r)
{ {
char buf[INET6_ADDRSTRLEN]; char buf[INET6_ADDRSTRLEN];
char *slash, *end; char *slash, *end;
unsigned char prefix[16]; unsigned char prefix[16];
unsigned short plen; long plen;
int rc; int rc;
if(strcmp(net, "default") == 0) { if(strcmp(net, "default") == 0) {
...@@ -173,11 +232,11 @@ parse_net(const char *net, unsigned char *prefix_r, unsigned short *plen_r) ...@@ -173,11 +232,11 @@ parse_net(const char *net, unsigned char *prefix_r, unsigned short *plen_r)
if(rc < 0) if(rc < 0)
return rc; return rc;
plen = strtol(slash + 1, &end, 0); plen = strtol(slash + 1, &end, 0);
if(*end != '\0') if(*end != '\0' || plen < 0 || plen > 128)
return -1; return -1;
} }
} }
memcpy(prefix_r, prefix, 16); memcpy(prefix_r, mask_prefix(prefix, plen), 16);
*plen_r = plen; *plen_r = plen;
return 0; return 0;
} }
......
...@@ -20,28 +20,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ...@@ -20,28 +20,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
int seqno_compare(unsigned char s1, unsigned char s2) int seqno_compare(unsigned short s1, unsigned short s2)
ATTRIBUTE ((const)); ATTRIBUTE ((const));
int seqno_minus(unsigned char s1, unsigned char s2) int seqno_minus(unsigned short s1, unsigned short s2)
ATTRIBUTE ((const)); ATTRIBUTE ((const));
void timeval_minus(struct timeval *d, void timeval_minus(struct timeval *d,
const struct timeval *s1, const struct timeval *s2); const struct timeval *s1, const struct timeval *s2);
int timeval_minus_msec(const struct timeval *s1, const struct timeval *s2) int timeval_minus_msec(const struct timeval *s1, const struct timeval *s2)
ATTRIBUTE ((pure)); ATTRIBUTE ((pure));
void timeval_plus_msec(struct timeval *d,
const struct timeval *s, int msecs);
int timeval_compare(const struct timeval *s1, const struct timeval *s2) int timeval_compare(const struct timeval *s1, const struct timeval *s2)
ATTRIBUTE ((pure)); ATTRIBUTE ((pure));
void timeval_min(struct timeval *d, const struct timeval *s); void timeval_min(struct timeval *d, const struct timeval *s);
void timeval_min_sec(struct timeval *d, int secs); void timeval_min_sec(struct timeval *d, int secs);
void do_debugf(const char *format, ...) ATTRIBUTE ((format (printf, 1, 2))); void do_debugf(const char *format, ...) ATTRIBUTE ((format (printf, 1, 2)));
int in_prefix(const unsigned char *address,
const unsigned char *prefix, unsigned char plen)
ATTRIBUTE ((pure));
const unsigned char *mask_prefix(const unsigned char *prefix,
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);
int parse_address(const char *address, unsigned char *addr_r); int parse_address(const char *address, unsigned char *addr_r);
int parse_net(const char *net, unsigned char *prefix_r, unsigned short *plen_r); int parse_net(const char *net, unsigned char *prefix_r, unsigned char *plen_r);
int wait_for_fd(int direction, int fd, int msecs); int wait_for_fd(int direction, int fd, int msecs);
int martian_prefix(const unsigned char *prefix, int plen); int martian_prefix(const unsigned char *prefix, int plen);
/* If debugging is disabled, we want to avoid calling format_address /* If debugging is disabled, we want to avoid calling format_address
for every omitted debugging message. So debug is a macro. But for every omitted debugging message. So debug is a macro. But
vararg macros are not portable... */ vararg macros are not portable. */
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
#define debugf(...) \ #define debugf(...) \
do { \ do { \
......
...@@ -36,322 +36,22 @@ THE SOFTWARE. ...@@ -36,322 +36,22 @@ THE SOFTWARE.
struct xroute xroutes[MAXXROUTES]; struct xroute xroutes[MAXXROUTES];
int numxroutes = 0; int numxroutes = 0;
struct xroute myxroutes[MAXMYXROUTES];
int nummyxroutes = 0;
int xroute_gc_delay = 180;
int xroute_hold_delay = 45;
static int
xroute_prefix(struct xroute *xroute, const unsigned char *prefix, int plen)
{
return (xroute->plen == plen &&
memcmp(xroute->prefix, prefix, 16) == 0);
}
static struct xroute *
find_installed_xroute(unsigned char *prefix, unsigned short plen)
{
int i;
for(i = 0; i < numxroutes; i++) {
if(xroutes[i].installed && xroute_prefix(&xroutes[i], prefix, plen))
return &xroutes[i];
}
return NULL;
}
static struct xroute *
find_installed_myxroute(unsigned char *prefix, unsigned short plen)
{
int i;
for(i = 0; i < nummyxroutes; i++) {
if(myxroutes[i].installed && xroute_prefix(&myxroutes[i], prefix, plen))
return &myxroutes[i];
}
return NULL;
}
static struct xroute *
find_best_xroute(unsigned char *prefix, unsigned short plen)
{
struct xroute *xroute = NULL;
struct route *route;
int i;
for(i = 0; i < numxroutes; i++) {
if(!xroute_prefix(&xroutes[i], prefix, plen))
continue;
if(xroutes[i].metric >= INFINITY && xroutes[i].cost < INFINITY)
continue;
route = find_installed_route(xroutes[i].gateway);
if(!route || route->nexthop != xroutes[i].nexthop)
continue;
if(!xroute || xroutes[i].metric < xroute->metric)
xroute = &xroutes[i];
}
return xroute;
}
void
install_xroute(struct xroute *xroute)
{
struct route *gwroute;
struct xroute *installed;
int rc;
if(xroute->installed)
return;
if(xroute->metric >= INFINITY && xroute->cost < INFINITY)
return;
gwroute = find_installed_route(xroute->gateway);
if(!gwroute || gwroute->nexthop != xroute->nexthop) {
fprintf(stderr,
"Attempted to install a blackhole xroute "
"(this shouldn't happen).\n");
return;
}
installed = find_installed_xroute(xroute->prefix, xroute->plen);
if(installed)
uninstall_xroute(installed);
rc = kernel_route(ROUTE_ADD, xroute->prefix, xroute->plen,
gwroute->nexthop->address,
gwroute->nexthop->network->ifindex,
metric_to_kernel(xroute->metric), 0);
if(rc < 0) {
perror("kernel_route(ADD)");
if(errno != EEXIST)
return;
}
xroute->installed = 1;
}
void
uninstall_xroute(struct xroute *xroute)
{
struct route *gwroute;
int rc;
if(!xroute->installed)
return;
gwroute = find_installed_route(xroute->gateway);
if(!gwroute) {
fprintf(stderr,
"Attempted to uninstall a blackhole xroute "
"(this shouldn't happen).\n");
return;
}
rc = kernel_route(ROUTE_FLUSH, xroute->prefix, xroute->plen,
gwroute->nexthop->address,
gwroute->nexthop->network->ifindex,
metric_to_kernel(xroute->metric), 0);
if(rc < 0)
perror("kernel_route(FLUSH)");
xroute->installed = 0;
}
void
consider_xroute(struct xroute *xroute)
{
struct xroute *installed;
struct route *route;
if(xroute->installed)
return;
route = find_installed_route(xroute->gateway);
if(xroute->nexthop != route->nexthop)
return;
update_xroute_metric(xroute, xroute->cost);
installed = find_installed_myxroute(xroute->prefix, xroute->plen);
if(!installed) {
installed = find_installed_xroute(xroute->prefix, xroute->plen);
if(!installed || installed->metric > xroute->metric + 64)
install_xroute(xroute);
}
}
void
consider_all_xroutes(struct route *route)
{
int i;
for(i = 0; i < numxroutes; i++) {
if(xroutes[i].gateway == route->dest &&
xroutes[i].nexthop == route->nexthop)
consider_xroute(&xroutes[i]);
}
}
void
flush_xroute(struct xroute *xroute)
{
int n;
int install = 0;
unsigned char prefix[16];
unsigned short plen = 0;
n = xroute - xroutes;
assert(n >= 0 && n < numxroutes);
if(xroute->installed) {
uninstall_xroute(xroute);
memcpy(prefix, xroute->prefix, 16);
plen = xroute->plen;
install = 1;
}
if(n != numxroutes - 1)
memcpy(xroutes + n, xroutes + numxroutes - 1,
sizeof(struct xroute));
numxroutes--;
VALGRIND_MAKE_MEM_UNDEFINED(xroutes + numxroutes, sizeof(struct xroute));
if(install) {
struct xroute *xroute;
xroute = find_best_xroute(prefix, plen);
if(xroute)
install_xroute(xroute);
}
}
void
flush_neighbour_xroutes(struct neighbour *neigh)
{
int i;
i = 0;
while(i < numxroutes) {
if(xroutes[i].nexthop == neigh) {
flush_xroute(xroutes + i);
continue;
}
i++;
}
}
void
retract_xroutes(struct destination *gateway, struct neighbour *nexthop,
const struct xroute *except, int numexcept)
{
int i, j;
for(i = 0; i < numxroutes; i++) {
if(xroutes[i].cost < INFINITY && xroutes[i].gateway == gateway &&
xroutes[i].nexthop == nexthop) {
for(j = 0; j < numexcept; j++) {
if(xroute_prefix(&xroutes[i], except[j].prefix, except[j].plen))
goto skip;
}
update_xroute_metric(&xroutes[i], INFINITY);
}
skip: ;
}
}
struct xroute * struct xroute *
update_xroute(const unsigned char *prefix, unsigned short plen, find_exported_xroute(const unsigned char *prefix, unsigned char plen)
struct destination *gateway, struct neighbour *nexthop, int cost)
{ {
int i; int i;
struct xroute *xroute = NULL;
struct route *gwroute;
if(martian_prefix(prefix, plen)) {
fprintf(stderr, "Ignoring martian xroute.\n");
return NULL;
}
if(gateway == NULL) {
fprintf(stderr, "Ignoring xroute through unknown destination.\n");
return NULL;
}
for(i = 0; i < numxroutes; i++) { for(i = 0; i < numxroutes; i++) {
xroute = &xroutes[i]; if(xroutes[i].exported) {
if(xroute->gateway == gateway && xroute->nexthop == nexthop && if(xroutes[i].plen == plen &&
xroute_prefix(xroute, prefix, plen)) { memcmp(xroutes[i].prefix, prefix, 16) == 0)
update_xroute_metric(xroute, cost); return &xroutes[i];
xroute->time = now.tv_sec;
return xroute;
} }
} }
return NULL;
if(numxroutes >= MAXXROUTES) {
fprintf(stderr, "Too many xroutes.\n");
return NULL;
}
gwroute = find_installed_route(gateway);
xroute = &xroutes[numxroutes];
memcpy(&xroute->prefix, prefix, 16);
xroute->plen = plen;
xroute->gateway = gateway;
xroute->nexthop = nexthop;
xroute->cost = cost;
xroute->metric =
gwroute && gwroute->nexthop == xroute->nexthop ?
MIN(gwroute->metric + cost, INFINITY) :
INFINITY;
xroute->time = now.tv_sec;
xroute->installed = 0;
numxroutes++;
if(gwroute)
consider_xroute(xroute);
return xroute;
} }
void
update_xroute_metric(struct xroute *xroute, int cost)
{
struct route *gwroute;
int oldmetric, newmetric;
int rc;
gwroute = find_installed_route(xroute->gateway);
oldmetric = xroute->metric;
newmetric = gwroute && gwroute->nexthop == xroute->nexthop ?
MIN(gwroute->metric + cost, INFINITY) :
INFINITY;
if(xroute->cost != cost || oldmetric != newmetric) {
xroute->cost = cost;
if(xroute->installed) {
if(gwroute == NULL) {
fprintf(stderr, "Found installed blackhole xroute!.\n");
return;
}
rc = kernel_route(ROUTE_MODIFY, xroute->prefix, xroute->plen,
gwroute->nexthop->address,
gwroute->nexthop->network->ifindex,
metric_to_kernel(oldmetric),
metric_to_kernel(newmetric));
if(rc < 0) {
perror("kernel_route(MODIFY)");
return;
}
}
xroute->metric = newmetric;
if(newmetric > oldmetric) {
struct xroute *best;
best = find_best_xroute(xroute->prefix, xroute->plen);
if(best)
consider_xroute(best);
}
}
}
int int
check_myxroutes() check_xroutes()
{ {
int i, j, n, change; int i, j, n, change;
struct kernel_route routes[120]; struct kernel_route routes[120];
...@@ -359,9 +59,9 @@ check_myxroutes() ...@@ -359,9 +59,9 @@ check_myxroutes()
debugf("Checking kernel routes.\n"); debugf("Checking kernel routes.\n");
n = -1; n = -1;
for(i = 0; i < nummyxroutes; i++) for(i = 0; i < numxroutes; i++)
if(myxroutes[i].installed < 2) if(xroutes[i].exported < 2)
n = MAX(n, myxroutes[i].plen); n = MAX(n, xroutes[i].plen);
if(n < 0) if(n < 0)
return 0; return 0;
...@@ -371,20 +71,32 @@ check_myxroutes() ...@@ -371,20 +71,32 @@ check_myxroutes()
return -1; return -1;
change = 0; change = 0;
for(i = 0; i < nummyxroutes; i++) { for(i = 0; i < numxroutes; i++) {
int installed; int export;
if(myxroutes[i].installed == 2) if(xroutes[i].exported == 2)
continue; continue;
installed = 0; export = 0;
for(j = 0; j < n; j++) { for(j = 0; j < n; j++) {
if(xroute_prefix(&myxroutes[i], if(xroutes[i].plen == routes[j].plen &&
routes[j].prefix, routes[j].plen)) { memcmp(xroutes[i].prefix, routes[j].prefix, 16) == 0) {
installed = 1; export = 1;
break; break;
} }
} }
if(myxroutes[i].installed != installed) { if(xroutes[i].exported != export) {
myxroutes[i].installed = installed; xroutes[i].exported = export;
if(export) {
struct route *route;
route = find_installed_route(xroutes[i].prefix,
xroutes[i].plen);
if(route)
uninstall_route(route);
} else {
struct route *route;
route = find_best_route(xroutes[i].prefix, xroutes[i].plen);
if(route)
consider_route(route);
}
change = 1; change = 1;
} }
} }
......
...@@ -20,38 +20,17 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ...@@ -20,38 +20,17 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
struct route; int check_xroutes(void);
struct xroute { struct xroute {
unsigned char prefix[16]; unsigned char prefix[16];
unsigned short plen; unsigned char plen;
struct destination *gateway; char exported;
struct neighbour *nexthop; unsigned short metric;
int cost;
int metric;
int time;
int installed;
}; };
extern struct xroute xroutes[MAXXROUTES]; extern struct xroute xroutes[MAXXROUTES];
extern int numxroutes; extern int numxroutes;
extern struct xroute myxroutes[MAXMYXROUTES]; struct xroute *find_exported_xroute(const unsigned char *prefix,
extern int nummyxroutes; unsigned char plen);
extern int xroute_gc_delay;
extern int xroute_hold_delay;
void install_xroute(struct xroute *xroute);
void uninstall_xroute(struct xroute *xroute);
void consider_xroute(struct xroute *xroute);
void consider_all_xroutes(struct route *route);
void flush_xroute(struct xroute *xroute);
void flush_neighbour_xroutes(struct neighbour *neigh);
void retract_xroutes(struct destination *gateway, struct neighbour *nexthop,
const struct xroute *except, int numexcept);
struct xroute * update_xroute(const unsigned char *prefix, unsigned short plen,
struct destination *gateway,
struct neighbour *nexthop, int cost);
void update_xroute_metric(struct xroute *xroute, int cost);
int check_myxroutes(void);
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