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

Merge branch 'rfc6126bis'

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