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
This diff is collapsed.
......@@ -21,12 +21,10 @@ THE SOFTWARE.
*/
#define MAXROUTES 512
#define MAXDESTS 1024
#define MAXSRCS 1024
#define MAXNEIGHBOURS 128
#define MAXNETS 8
#define MAXXROUTES 128
#define MAXMYXROUTES 64
#define MAX_BUFFERED_UPDATES 100
#define MAXXROUTES 64
#define INFINITY ((unsigned short)(~0))
......@@ -68,7 +66,7 @@ struct network {
int hello_time;
int self_update_time;
int update_time;
int txcost_time;
int ihu_time;
char ifname[IF_NAMESIZE];
int buffered;
struct timeval flush_time;
......@@ -77,10 +75,10 @@ struct network {
int bucket_time;
unsigned int bucket;
int activity_time;
unsigned char hello_seqno;
unsigned short hello_seqno;
unsigned int hello_interval;
unsigned int self_update_interval;
unsigned int txcost_interval;
unsigned int ihu_interval;
};
extern struct timeval now;
......@@ -92,7 +90,7 @@ extern unsigned char myid[16];
extern struct network nets[MAXNETS];
extern int numnets;
extern const unsigned char zeroes[16];
extern const unsigned char zeroes[16], ones[16];
extern int protocol_port;
extern unsigned char protocol_group[16];
......
......@@ -96,7 +96,7 @@ write_proc(char *filename, int value)
}
struct netlink {
unsigned int seqno;
unsigned short seqno;
int sock;
struct sockaddr_nl sockaddr;
socklen_t socklen;
......
This diff is collapsed.
......@@ -20,7 +20,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
extern unsigned char seqno;
#define MAX_BUFFERED_UPDATES 200
extern unsigned short myseqno;
extern int seqno_time;
extern int seqno_interval;
......@@ -29,25 +31,26 @@ extern unsigned int update_jitter;
extern int add_cost;
extern int parasitic;
extern int silent_time;
extern int broadcast_txcost;
extern int broadcast_ihu;
extern int split_horizon;
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,
const unsigned char *packet, int len);
void flushbuf(struct network *net);
void send_hello(struct network *net);
void send_request(struct network *net, struct destination *dest,
int hopcount, int seqno);
void send_unicast_request(struct neighbour *neigh, struct destination *dest,
int hopcount, int seqno);
void send_update(struct destination *dest, struct network *net);
void send_request(struct network *net,
const unsigned char *prefix, unsigned char plen);
void send_unicast_request(struct neighbour *neigh,
const unsigned char *prefix, unsigned char plen);
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_retract(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 flushupdates(void);
......
......@@ -29,9 +29,8 @@ THE SOFTWARE.
#include "babel.h"
#include "util.h"
#include "neighbour.h"
#include "destination.h"
#include "source.h"
#include "route.h"
#include "xroute.h"
#include "message.h"
struct neighbour neighs[MAXNEIGHBOURS];
......@@ -40,15 +39,14 @@ int numneighs = 0;
void
flush_neighbour(struct neighbour *neigh)
{
flush_neighbour_xroutes(neigh);
flush_neighbour_routes(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--;
VALGRIND_MAKE_MEM_UNDEFINED(neigh, sizeof(*neigh));
} else {
VALGRIND_MAKE_MEM_UNDEFINED(neigh, sizeof(*neigh));
neigh->id[0] = 0xFF;
VALGRIND_MAKE_MEM_UNDEFINED(&neighs[numneighs],
sizeof(neighs[numneighs]));
}
}
......@@ -71,6 +69,7 @@ add_neighbour(const unsigned char *id, const unsigned char *address,
struct network *net)
{
struct neighbour *neigh;
const struct timeval zero = {0, 0};
int i;
if(id[0] == 0xFF) {
......@@ -104,11 +103,10 @@ add_neighbour(const unsigned char *id, const unsigned char *address,
}
memcpy(neigh->id, id, 16);
memcpy(neigh->address, address, 16);
neigh->hello_interval = 0;
neigh->reach = 0;
neigh->txcost = INFINITY;
neigh->txcost_time = now.tv_sec;
neigh->hello_time = 0;
neigh->ihu_time = now.tv_sec;
neigh->hello_time = zero;
neigh->hello_interval = 0;
neigh->hello_seqno = -1;
neigh->network = net;
......@@ -116,19 +114,23 @@ add_neighbour(const unsigned char *id, const unsigned char *address,
return neigh;
}
void
/* Recompute a neighbour's rxcost. Return true if anything changed. */
int
update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
{
int missed_hellos;
int rc = 0;
if(hello < 0) {
if(neigh->hello_interval <= 0)
return;
missed_hellos =
(now.tv_sec - 3 - neigh->hello_time) / neigh->hello_interval;
return rc;
missed_hellos = (timeval_minus_msec(&now, &neigh->hello_time) -
neigh->hello_interval * 6) /
(neigh->hello_interval * 10);
if(missed_hellos <= 0)
return;
neigh->hello_time += missed_hellos * neigh->hello_interval;
return rc;
timeval_plus_msec(&neigh->hello_time, &neigh->hello_time,
missed_hellos * neigh->hello_interval * 10);
} else {
if(neigh->hello_seqno >= 0 && neigh->reach > 0) {
missed_hellos = seqno_minus(hello, neigh->hello_seqno) - 1;
......@@ -137,97 +139,120 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
didn't notice. */
neigh->reach <<= -missed_hellos;
missed_hellos = 0;
rc = 1;
}
} else {
missed_hellos = 0;
}
neigh->hello_time = now.tv_sec;
neigh->hello_time = now;
neigh->hello_interval = hello_interval;
}
neigh->reach >>= missed_hellos;
missed_hellos = 0;
if(missed_hellos > 0) {
neigh->reach >>= missed_hellos;
missed_hellos = 0;
rc = 1;
}
if(hello >= 0) {
neigh->hello_seqno = hello;
neigh->reach >>= 1;
neigh->reach |= 0x8000;
if((neigh->reach & 0xFC00) == 0xFC00)
return rc;
else
rc = 1;
}
/* Make sure to give neighbours some feedback early after association */
if((neigh->reach & 0xFC00) == 0x8000) {
/* A new neighbour */
send_hello(neigh->network);
send_txcost(neigh, NULL);
send_ihu(neigh, NULL);
} else {
/* Don't send hellos, in order to avoid a positive feedback loop. */
int a = (neigh->reach & 0xC000);
int b = (neigh->reach & 0x3000);
if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) {
/* Reachability is either 1100 or 0011 */
send_txcost(neigh, NULL);
send_ihu(neigh, NULL);
send_self_update(neigh->network, 0);
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,
request a full route dump. This assumes that the neighbour's ID
is also its IP address. */
struct destination *dest;
request a full route dump. This assumes that the neighbour's id
is also its IP address and that it is exporting a route to itself. */
struct route *route = NULL;
dest = find_destination(neigh->id, 0, 0);
if(dest)
route = find_installed_route(dest);
if(!martian_prefix(neigh->id, 128))
route = find_installed_route(neigh->id, 128);
if(!route || route->metric >= INFINITY || route->nexthop == neigh)
send_unicast_request(neigh, NULL, 0, -1);
send_unicast_request(neigh, NULL, 0);
}
return rc;
}
void
check_neighbour(struct neighbour *neigh)
int
check_neighbours()
{
update_neighbour(neigh, -1, 0);
if(neigh->reach == 0) {
flush_neighbour(neigh);
return;
}
int i, changed;
int msecs = 50000;
debugf("Checking neighbours.\n");
for(i = 0; i < numneighs; i++) {
if(neighs[i].id[0] == 0xFF)
continue;
if(!neigh->network->wired) {
while(neigh->txcost < INFINITY &&
neigh->txcost_time <= now.tv_sec - 40) {
neigh->txcost = MIN((int)neigh->txcost * 3 / 2, INFINITY);
neigh->txcost_time += 10;
changed = update_neighbour(&neighs[i], -1, 0);
if(neighs[i].reach == 0 ||
timeval_minus_msec(&now, &neighs[i].hello_time) > 300000) {
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
neighbour_rxcost(struct neighbour *neigh)
{
update_neighbour(neigh, -1, 0);
if((neigh->reach & 0xF800) == 0)
int delay;
unsigned short reach = neigh->reach;
delay = timeval_minus_msec(&now, &neigh->hello_time);
if((reach & 0xF800) == 0 || delay >= 180000) {
return INFINITY;
else if(neigh->network->wired) {
if((neigh->reach & 0xE000) != 0) {
int c = neigh->network->cost;
int d = now.tv_sec - neigh->hello_time;
if(d >= 60)
c = (c * (d - 40) + 19) / 20;
return MIN(c, INFINITY);
} else {
} else if(neigh->network->wired) {
/* To lose one hello is a misfortune, to lose two is carelessness. */
if((reach & 0xC000) == 0xC000)
return neigh->network->cost;
else if((reach & 0xC000) == 0)
return INFINITY;
else if((reach & 0x2000))
return neigh->network->cost;
else
return INFINITY;
}
} else {
int r = (neigh->reach & 0x7FFF) + ((neigh->reach & 0x8000) >> 1);
/* 0 <= r <= 0xBFFF */
int c = (0xC000 * 0x100) / r;
int d = now.tv_sec - neigh->hello_time;
if(d >= 40)
c = (c * (d - 20) + 10) / 20;
return MIN(c + neigh->network->cost, INFINITY);
int sreach = (reach & 0x7FFF) + ((reach & 0x8000) >> 1);
/* 0 <= sreach <= 0xBFFF */
int cost = (0xC000 * neigh->network->cost) / (sreach + 1);
/* cost >= network->cost */
if(delay >= 40000)
cost = (cost * (delay - 20000) + 10000) / 20000;
return MIN(cost, INFINITY);
}
}
......@@ -236,6 +261,9 @@ neighbour_cost(struct neighbour *neigh)
{
int a, b;
if(now.tv_sec - neigh->ihu_time >= 180)
return INFINITY;
a = neigh->txcost;
if(a >= INFINITY)
......
......@@ -26,10 +26,10 @@ struct neighbour {
unsigned short reach;
unsigned short txcost;
/* This is -1 when unknown, so don't make it unsigned */
short int hello_seqno;
int txcost_time;
int hello_time;
int hello_interval;
int hello_seqno;
int ihu_time;
struct timeval hello_time;
unsigned short hello_interval; /* in centiseconds */
struct network *network;
};
......@@ -42,7 +42,7 @@ struct neighbour *find_neighbour(const unsigned char *address,
struct neighbour *
add_neighbour(const unsigned char *id, const unsigned char *address,
struct network *net);
void update_neighbour(struct neighbour *neigh, int hello, int hello_interval);
void check_neighbour(struct neighbour *neigh);
int update_neighbour(struct neighbour *neigh, int hello, int hello_interval);
int check_neighbours(void);
int neighbour_rxcost(struct neighbour *neigh);
int neighbour_cost(struct neighbour *neigh);
This diff is collapsed.
......@@ -20,13 +20,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
struct xroute;
struct route {
struct destination *dest;
struct source *src;
unsigned short metric;
unsigned short refmetric;
unsigned char seqno;
unsigned short seqno;
struct neighbour *nexthop;
int time;
int origtime;
......@@ -39,22 +37,33 @@ extern int kernel_metric;
extern int route_timeout_delay;
extern int route_gc_delay;
struct route *find_route(struct destination *dest, struct neighbour *nexthop);
struct route *find_installed_route(struct destination *dest);
struct route *find_route(const unsigned char *prefix, unsigned char plen,
struct neighbour *nexthop);
struct route *find_installed_route(const unsigned char *prefix,
unsigned char plen);
void flush_route(struct route *route);
void flush_neighbour_routes(struct neighbour *neigh);
unsigned int metric_to_kernel(int metric);
void install_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 update_feasible(unsigned char seqno, unsigned short refmetric,
struct destination *dest);
struct route *find_best_route(struct destination *dest);
int update_feasible(const unsigned char *a,
const unsigned char *p, unsigned char plen,
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_route_metric(struct route *route);
struct route *update_route(const unsigned char *d, int seqno, int refmetric,
struct neighbour *nexthop,
struct xroute *pxroutes, int numpxroutes);
struct route *update_route(const unsigned char *a,
const unsigned char *p, unsigned char plen,
unsigned short seqno, unsigned short refmetric,
struct neighbour *nexthop);
void consider_route(struct route *route);
void change_route_metric(struct route *route, int newmetric);
void send_triggered_update(struct route *route, int oldmetric);
void send_triggered_update(struct route *route,
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.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "babel.h"
#include "util.h"
#include "destination.h"
#include "source.h"
struct destination dests[MAXDESTS];
int numdests = 0;
struct source srcs[MAXSRCS];
int numsrcs = 0;
struct destination *
find_destination(const unsigned char *d, int create, unsigned char seqno)
struct source *
find_source(const unsigned char *a, const unsigned char *p, unsigned char plen,
int create, unsigned short seqno)
{
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
last byte first. */
if(dests[i].address[15] != d[15])
if(srcs[i].address[15] != a[15])
continue;
if(memcmp(dests[i].address, d, 16) == 0)
return &dests[i];
if(memcmp(srcs[i].address, a, 16) != 0)
continue;
if(source_match(&srcs[i], p, plen))
return &srcs[i];
}
if(!create)
return NULL;
if(numdests >= MAXDESTS) {
fprintf(stderr, "Too many destinations.\n");
if(numsrcs >= MAXSRCS) {
fprintf(stderr, "Too many sources.\n");
return NULL;
}
memcpy(dests[numdests].address, d, 16);
dests[numdests].seqno = seqno;
dests[numdests].metric = INFINITY;
dests[numdests].time = now.tv_sec;
dests[numdests].requested_seqno = -1;
dests[numdests].requested_net = NULL;
return &dests[numdests++];
memcpy(srcs[numsrcs].address, a, 16);
memcpy(srcs[numsrcs].prefix, p, 16);
srcs[numsrcs].plen = plen;
srcs[numsrcs].seqno = seqno;
srcs[numsrcs].metric = INFINITY;
srcs[numsrcs].time = now.tv_sec;
return &srcs[numsrcs++];
}
void
update_destination(struct destination *dest,
unsigned char seqno, unsigned short metric)
struct source *
find_recent_source(const unsigned char *p, unsigned char plen)
{
if(seqno_compare(dest->seqno, seqno) < 0 ||
(dest->seqno == seqno && dest->metric > metric)) {
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;
}
}
}
int i;
struct source *src = NULL;
void
notice_request(struct destination *dest, unsigned char seqno,
struct network *net)
{
if(dest->requested_seqno < 0) {
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;
for(i = 0; i < numsrcs; i++) {
if(!source_match(&srcs[i], p, plen))
continue;
if(!src || src->time < srcs[i].time)
src = &srcs[i];
}
return src;
}
int
request_requested(struct destination *dest, unsigned char seqno,
struct network *net)
source_match(struct source *src,
const unsigned char *p, unsigned char plen)
{
if(dest->requested_seqno < 0)
if(src->plen != plen)
return 0;
if(seqno_compare(dest->requested_seqno, seqno) < 0)
if(src->prefix[15] != p[15])
return 0;
if(dest->requested_net == NULL)
return 1;
if(net == NULL || net != dest->requested_net)
if(memcmp(src->prefix, p, 16) != 0)
return 0;
return 1;
}
void
satisfy_request(struct destination *dest, unsigned char seqno,
struct network *net)
update_source(struct source *src,
unsigned short seqno, unsigned short metric)
{
if(dest->requested_seqno >= 0) {
if(net == NULL || net == dest->requested_net) {
if(seqno_compare(seqno, dest->requested_seqno) >= 0) {
dest->requested_seqno = -1;
dest->requested_net = NULL;
}
}
if(metric >= INFINITY)
return;
if(seqno_compare(src->seqno, seqno) < 0 ||
(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
THE SOFTWARE.
*/
struct destination {
struct source {
unsigned char address[16];
unsigned char seqno;
unsigned char prefix[16];
unsigned char plen;
unsigned short seqno;
unsigned short metric;
int time;
int requested_seqno;
struct network *requested_net;
};
struct destination *find_destination(const unsigned char *d,
int create, unsigned char seqno);
void update_destination(struct destination *dest,
unsigned char seqno, unsigned short metric);
void notice_request(struct destination *dest, unsigned char seqno,
struct network *net);
int request_requested(struct destination *dest, unsigned char seqno,
struct network *net);
void satisfy_request(struct destination *dest, unsigned char seqno,
struct network *net);
int source_match(struct source *src,
const unsigned char *p, unsigned char plen);
struct source *find_source(const unsigned char *a,
const unsigned char *p,
unsigned char plen,
int create, unsigned short seqno);
struct source *find_recent_source(const unsigned char *p,
unsigned char plen);
void update_source(struct source *src,
unsigned short seqno, unsigned short metric);
......@@ -38,7 +38,7 @@ seqno_compare(unsigned char s1, unsigned char s2)
{
if(s1 == s2)
return 0;
else if(((s2 - s1) & 0xFF) < 128)
else if(((s2 - s1) & 0xFFFF) < 0x8000)
return -1;
else
return 1;
......@@ -49,10 +49,10 @@ seqno_minus(unsigned char s1, unsigned char s2)
{
if(s1 == s2)
return 0;
else if(((s2 - s1) & 0xFF) < 128)
return -(int)((s2 - s1) & 0xFF);
else if(((s2 - s1) & 0xFFFF) < 0x8000)
return -(int)((s2 - s1) & 0xFFFF);
else
return ((s1 - s2) & 0xFF);
return ((s1 - s2) & 0xFFFF);
}
void
......@@ -75,6 +75,20 @@ timeval_minus_msec(const struct timeval *s1, const struct timeval *s2)
(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
timeval_compare(const struct timeval *s1, const struct timeval *s2)
{
......@@ -122,6 +136,38 @@ do_debugf(const char *format, ...)
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 *
format_address(const unsigned char *address)
{
......@@ -131,6 +177,19 @@ format_address(const unsigned char *address)