Commit f107b49e authored by Juliusz Chroboczek's avatar Juliusz Chroboczek Committed by Juliusz Chroboczek

Use a per-neighbour unicast buffer.

This removes duplication between unicast and multicast variants of message
formatting.
parent 09a59d51
...@@ -582,6 +582,7 @@ main(int argc, char **argv) ...@@ -582,6 +582,7 @@ main(int argc, char **argv)
send_hello(ifp); send_hello(ifp);
send_wildcard_retraction(ifp); send_wildcard_retraction(ifp);
send_self_update(ifp); send_self_update(ifp);
send_multicast_request(ifp, NULL, 0, NULL, 0);
flushupdates(ifp); flushupdates(ifp);
flushbuf(&ifp->buf); flushbuf(&ifp->buf);
} }
...@@ -591,6 +592,7 @@ main(int argc, char **argv) ...@@ -591,6 +592,7 @@ main(int argc, char **argv)
while(1) { while(1) {
struct timeval tv; struct timeval tv;
fd_set readfds; fd_set readfds;
struct neighbour *neigh;
gettime(&now); gettime(&now);
...@@ -608,7 +610,9 @@ main(int argc, char **argv) ...@@ -608,7 +610,9 @@ main(int argc, char **argv)
timeval_min(&tv, &ifp->update_timeout); timeval_min(&tv, &ifp->update_timeout);
timeval_min(&tv, &ifp->update_flush_timeout); timeval_min(&tv, &ifp->update_flush_timeout);
} }
timeval_min(&tv, &unicast_flush_timeout); FOR_ALL_NEIGHBOURS(neigh) {
timeval_min(&tv, &neigh->buf.timeout);
}
FD_ZERO(&readfds); FD_ZERO(&readfds);
if(timeval_compare(&tv, &now) > 0) { if(timeval_compare(&tv, &now) > 0) {
int maxfd = 0; int maxfd = 0;
...@@ -770,11 +774,6 @@ main(int argc, char **argv) ...@@ -770,11 +774,6 @@ main(int argc, char **argv)
do_resend(); do_resend();
} }
if(unicast_flush_timeout.tv_sec != 0) {
if(timeval_compare(&now, &unicast_flush_timeout) >= 0)
flush_unicast(1);
}
FOR_ALL_INTERFACES(ifp) { FOR_ALL_INTERFACES(ifp) {
if(!if_up(ifp)) if(!if_up(ifp))
continue; continue;
...@@ -786,6 +785,14 @@ main(int argc, char **argv) ...@@ -786,6 +785,14 @@ main(int argc, char **argv)
} }
} }
FOR_ALL_NEIGHBOURS(neigh) {
if(neigh->buf.timeout.tv_sec != 0) {
if(timeval_compare(&now, &neigh->buf.timeout) >= 0) {
flushbuf(&neigh->buf);
}
}
}
if(UNLIKELY(debug || dumping)) { if(UNLIKELY(debug || dumping)) {
dump_tables(stdout); dump_tables(stdout);
dumping = 0; dumping = 0;
......
...@@ -480,6 +480,7 @@ interface_up(struct interface *ifp, int up) ...@@ -480,6 +480,7 @@ interface_up(struct interface *ifp, int up)
send_hello(ifp); send_hello(ifp);
if(rc > 0) if(rc > 0)
send_update(ifp, 0, NULL, 0, NULL, 0); send_update(ifp, 0, NULL, 0, NULL, 0);
send_multicast_request(ifp, NULL, 0, NULL, 0);
} else { } else {
flush_interface_routes(ifp, 0); flush_interface_routes(ifp, 0);
ifp->buf.len = 0; ifp->buf.len = 0;
...@@ -566,6 +567,7 @@ check_interfaces(void) ...@@ -566,6 +567,7 @@ check_interfaces(void)
check_interface_channel(ifp); check_interface_channel(ifp);
rc = check_interface_ipv4(ifp); rc = check_interface_ipv4(ifp);
if(rc > 0) { if(rc > 0) {
send_multicast_request(ifp, NULL, 0, NULL, 0);
send_update(ifp, 0, NULL, 0, NULL, 0); send_update(ifp, 0, NULL, 0, NULL, 0);
} }
} }
......
...@@ -48,12 +48,6 @@ int split_horizon = 1; ...@@ -48,12 +48,6 @@ int split_horizon = 1;
unsigned short myseqno = 0; unsigned short myseqno = 0;
struct timeval seqno_time = {0, 0}; struct timeval seqno_time = {0, 0};
#define UNICAST_BUFSIZE 1024
int unicast_buffered = 0;
unsigned char *unicast_buffer = NULL;
struct neighbour *unicast_neighbour = NULL;
struct timeval unicast_flush_timeout = {0, 0};
extern const unsigned char v4prefix[16]; extern const unsigned char v4prefix[16];
#define MAX_CHANNEL_HOPS 20 #define MAX_CHANNEL_HOPS 20
...@@ -944,9 +938,8 @@ flushbuf(struct buffered *buf) ...@@ -944,9 +938,8 @@ flushbuf(struct buffered *buf)
} }
static void static void
schedule_flush(struct buffered *buf) schedule_flush_ms(struct buffered *buf, int msecs)
{ {
unsigned msecs = jitter(buf, 0);
if(buf->timeout.tv_sec != 0 && if(buf->timeout.tv_sec != 0 &&
timeval_minus_msec(&buf->timeout, &now) < msecs) timeval_minus_msec(&buf->timeout, &now) < msecs)
return; return;
...@@ -954,27 +947,15 @@ schedule_flush(struct buffered *buf) ...@@ -954,27 +947,15 @@ schedule_flush(struct buffered *buf)
} }
static void static void
schedule_flush_now(struct buffered *buf) schedule_flush(struct buffered *buf)
{ {
/* Almost now */ schedule_flush_ms(buf, jitter(buf, 0));
unsigned msecs = roughly(10);
if(buf->timeout.tv_sec != 0 &&
timeval_minus_msec(&buf->timeout, &now) < msecs)
return;
set_timeout(&buf->timeout, msecs);
} }
static void static void
schedule_unicast_flush(unsigned msecs) schedule_flush_now(struct buffered *buf)
{ {
if(!unicast_neighbour) schedule_flush_ms(buf, roughly(10));
return;
if(unicast_flush_timeout.tv_sec != 0 &&
timeval_minus_msec(&unicast_flush_timeout, &now) < msecs)
return;
unicast_flush_timeout.tv_usec = (now.tv_usec + msecs * 1000) % 1000000;
unicast_flush_timeout.tv_sec =
now.tv_sec + (now.tv_usec / 1000 + msecs) / 1000;
} }
static void static void
...@@ -1030,77 +1011,16 @@ accumulate_bytes(struct buffered *buf, ...@@ -1030,77 +1011,16 @@ accumulate_bytes(struct buffered *buf,
buf->len += len; buf->len += len;
} }
static int
start_unicast_message(struct neighbour *neigh, int type, int len)
{
if(unicast_neighbour) {
if(neigh != unicast_neighbour ||
unicast_buffered + len + 2 >=
MIN(UNICAST_BUFSIZE, neigh->ifp->buf.size))
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->buf, 0));
}
static void
accumulate_unicast_byte(struct neighbour *neigh, unsigned char value)
{
unicast_buffer[unicast_buffered++] = value;
}
static void
accumulate_unicast_short(struct neighbour *neigh, unsigned short value)
{
DO_HTONS(unicast_buffer + unicast_buffered, value);
unicast_buffered += 2;
}
static void
accumulate_unicast_int(struct neighbour *neigh, unsigned int value)
{
DO_HTONL(unicast_buffer + unicast_buffered, value);
unicast_buffered += 4;
}
static void
accumulate_unicast_bytes(struct neighbour *neigh,
const unsigned char *value, unsigned len)
{
memcpy(unicast_buffer + unicast_buffered, value, len);
unicast_buffered += len;
}
void void
send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval) send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval)
{ {
int rc;
debugf("Sending ack (%04x) to %s on %s.\n", debugf("Sending ack (%04x) to %s on %s.\n",
nonce, format_address(neigh->address), neigh->ifp->name); nonce, format_address(neigh->address), neigh->ifp->name);
rc = start_unicast_message(neigh, MESSAGE_ACK, 2); if(rc < 0) return; start_message(&neigh->buf, MESSAGE_ACK, 2);
accumulate_unicast_short(neigh, nonce); accumulate_short(&neigh->buf, nonce);
end_unicast_message(neigh, MESSAGE_ACK, 2); end_message(&neigh->buf, MESSAGE_ACK, 2);
/* Roughly yields a value no larger than 3/2, so this meets the deadline */ /* Roughly yields a value no larger than 3/2, so this meets the deadline */
schedule_unicast_flush(roughly(interval * 6)); schedule_flush_ms(&neigh->buf, roughly(interval * 6));
} }
void void
...@@ -1148,47 +1068,6 @@ send_hello(struct interface *ifp) ...@@ -1148,47 +1068,6 @@ send_hello(struct interface *ifp)
send_marginal_ihu(ifp); send_marginal_ihu(ifp);
} }
void
flush_unicast(int dofree)
{
struct sockaddr_in6 sin6;
int rc;
if(unicast_buffered == 0)
goto done;
if(!if_up(unicast_neighbour->ifp))
goto done;
/* Preserve ordering of messages */
flushbuf(&unicast_neighbour->ifp->buf);
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->buf);
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)");
done:
VALGRIND_MAKE_MEM_UNDEFINED(unicast_buffer, UNICAST_BUFSIZE);
unicast_buffered = 0;
if(dofree && unicast_buffer) {
free(unicast_buffer);
unicast_buffer = NULL;
}
unicast_neighbour = NULL;
unicast_flush_timeout.tv_sec = 0;
unicast_flush_timeout.tv_usec = 0;
}
static void static void
really_send_update(struct interface *ifp, really_send_update(struct interface *ifp,
const unsigned char *id, const unsigned char *id,
...@@ -1722,12 +1601,7 @@ send_ihu(struct neighbour *neigh, struct interface *ifp) ...@@ -1722,12 +1601,7 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
rxcost = neighbour_rxcost(neigh); rxcost = neighbour_rxcost(neigh);
interval = (ifp->hello_interval * 3 + 9) / 10; interval = (ifp->hello_interval * 3 + 9) / 10;
/* Conceptually, an IHU is a unicast message. We usually send them as debugf("Sending ihu %d on %s to %s.\n",
multicast, since this allows aggregation into a single packet and
avoids an ARP exchange. If we already have a unicast message queued
for this neighbour, however, we might as well piggyback the IHU. */
debugf("Sending %sihu %d on %s to %s.\n",
unicast_neighbour == neigh ? "unicast " : "",
rxcost, rxcost,
neigh->ifp->name, neigh->ifp->name,
format_address(neigh->address)); format_address(neigh->address));
...@@ -1747,44 +1621,22 @@ send_ihu(struct neighbour *neigh, struct interface *ifp) ...@@ -1747,44 +1621,22 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
optional 10-bytes sub-TLV for timestamps (used to compute a RTT). */ optional 10-bytes sub-TLV for timestamps (used to compute a RTT). */
msglen = (ll ? 14 : 22) + (send_rtt_data ? 10 : 0); msglen = (ll ? 14 : 22) + (send_rtt_data ? 10 : 0);
if(unicast_neighbour != neigh) { start_message(&ifp->buf, MESSAGE_IHU, msglen);
start_message(&ifp->buf, MESSAGE_IHU, msglen); accumulate_byte(&ifp->buf, ll ? 3 : 2);
accumulate_byte(&ifp->buf, ll ? 3 : 2); accumulate_byte(&ifp->buf, 0);
accumulate_byte(&ifp->buf, 0); accumulate_short(&ifp->buf, rxcost);
accumulate_short(&ifp->buf, rxcost); accumulate_short(&ifp->buf, interval);
accumulate_short(&ifp->buf, interval); if(ll)
if(ll) accumulate_bytes(&ifp->buf, neigh->address + 8, 8);
accumulate_bytes(&ifp->buf, neigh->address + 8, 8); else
else accumulate_bytes(&ifp->buf, neigh->address, 16);
accumulate_bytes(&ifp->buf, neigh->address, 16); if(send_rtt_data) {
if(send_rtt_data) { accumulate_byte(&ifp->buf, SUBTLV_TIMESTAMP);
accumulate_byte(&ifp->buf, SUBTLV_TIMESTAMP); accumulate_byte(&ifp->buf, 8);
accumulate_byte(&ifp->buf, 8); accumulate_int(&ifp->buf, neigh->hello_send_us);
accumulate_int(&ifp->buf, neigh->hello_send_us); accumulate_int(&ifp->buf, time_us(neigh->hello_rtt_receive_time));
accumulate_int(&ifp->buf, time_us(neigh->hello_rtt_receive_time));
}
end_message(&ifp->buf, 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);
} }
end_message(&ifp->buf, MESSAGE_IHU, msglen);
} }
/* Send IHUs to all marginal neighbours */ /* Send IHUs to all marginal neighbours */
...@@ -1802,51 +1654,35 @@ send_marginal_ihu(struct interface *ifp) ...@@ -1802,51 +1654,35 @@ send_marginal_ihu(struct interface *ifp)
/* Standard wildcard request with prefix == NULL && src_prefix == zeroes, /* Standard wildcard request with prefix == NULL && src_prefix == zeroes,
Specific wildcard request with prefix == zeroes && src_prefix == NULL. */ Specific wildcard request with prefix == zeroes && src_prefix == NULL. */
void static void
send_request(struct interface *ifp, send_request(struct buffered *buf,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen) const unsigned char *src_prefix, unsigned char src_plen)
{ {
int v4, pb, spb, len, is_ss; int v4, pb, spb, len, 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);
if(!if_up(ifp))
return;
if(prefix && src_prefix) { if(prefix && src_prefix) {
debugf("sending request to %s for %s from %s.\n", ifp->name, debugf("sending request for %s from %s.\n",
format_prefix(prefix, plen), format_prefix(prefix, plen),
format_prefix(src_prefix, src_plen)); format_prefix(src_prefix, src_plen));
} else if(prefix) { } else if(prefix) {
debugf("sending request to %s for any specific.\n", ifp->name); debugf("sending request for any specific.\n");
start_message(&ifp->buf, MESSAGE_REQUEST_SRC_SPECIFIC, 3); start_message(buf, MESSAGE_REQUEST_SRC_SPECIFIC, 3);
accumulate_byte(&ifp->buf, 0); accumulate_byte(buf, 0);
accumulate_byte(&ifp->buf, 0); accumulate_byte(buf, 0);
accumulate_byte(&ifp->buf, 0); accumulate_byte(buf, 0);
end_message(&ifp->buf, MESSAGE_REQUEST_SRC_SPECIFIC, 3); end_message(buf, MESSAGE_REQUEST_SRC_SPECIFIC, 3);
return; return;
} else if(src_prefix) { } else if(src_prefix) {
debugf("sending request to %s for any.\n", ifp->name); debugf("sending request for any.\n");
start_message(&ifp->buf, MESSAGE_REQUEST, 2); start_message(buf, MESSAGE_REQUEST, 2);
accumulate_byte(&ifp->buf, 0); accumulate_byte(buf, 0);
accumulate_byte(&ifp->buf, 0); accumulate_byte(buf, 0);
end_message(&ifp->buf, MESSAGE_REQUEST, 2); end_message(buf, MESSAGE_REQUEST, 2);
return; return;
} else { } else {
send_request(ifp, NULL, 0, zeroes, 0); send_request(buf, NULL, 0, zeroes, 0);
send_request(ifp, zeroes, 0, NULL, 0); send_request(buf, zeroes, 0, NULL, 0);
return; return;
} }
...@@ -1858,166 +1694,142 @@ send_request(struct interface *ifp, ...@@ -1858,166 +1694,142 @@ send_request(struct interface *ifp,
if(is_ss) { if(is_ss) {
spb = v4 ? ((src_plen - 96) + 7) / 8 : (src_plen + 7) / 8; spb = v4 ? ((src_plen - 96) + 7) / 8 : (src_plen + 7) / 8;
len += spb + 1; len += spb + 1;
start_message(&ifp->buf, MESSAGE_REQUEST_SRC_SPECIFIC, len); start_message(buf, MESSAGE_REQUEST_SRC_SPECIFIC, len);
} else { } else {
spb = 0; spb = 0;
start_message(&ifp->buf, MESSAGE_REQUEST, len); start_message(buf, MESSAGE_REQUEST, len);
} }
accumulate_byte(&ifp->buf, v4 ? 1 : 2); accumulate_byte(buf, v4 ? 1 : 2);
accumulate_byte(&ifp->buf, v4 ? plen - 96 : plen); accumulate_byte(buf, v4 ? plen - 96 : plen);
if(is_ss) if(is_ss)
accumulate_byte(&ifp->buf, v4 ? src_plen - 96 : src_plen); accumulate_byte(buf, v4 ? src_plen - 96 : src_plen);
if(v4) if(v4)
accumulate_bytes(&ifp->buf, prefix + 12, pb); accumulate_bytes(buf, prefix + 12, pb);
else else
accumulate_bytes(&ifp->buf, prefix, pb); accumulate_bytes(buf, prefix, pb);
if(is_ss) { if(is_ss) {
if(v4) if(v4)
accumulate_bytes(&ifp->buf, src_prefix + 12, spb); accumulate_bytes(buf, src_prefix + 12, spb);
else else
accumulate_bytes(&ifp->buf, src_prefix, spb); accumulate_bytes(buf, src_prefix, spb);
end_message(&ifp->buf, MESSAGE_REQUEST_SRC_SPECIFIC, len); end_message(buf, MESSAGE_REQUEST_SRC_SPECIFIC, len);
} else { } else {
end_message(&ifp->buf, MESSAGE_REQUEST, len); 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);
send_request(&ifp->buf, prefix, plen, src_prefix, src_plen);
}
void void
send_unicast_request(struct neighbour *neigh, send_unicast_request(struct neighbour *neigh,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen) const unsigned char *src_prefix, unsigned char src_plen)
{ {
int rc, v4, pb, spb, len, is_ss; if(!if_up(neigh->ifp))
return;
/* make sure any buffered updates go out before this request. */
flushupdates(neigh->ifp); flushupdates(neigh->ifp);
if(prefix && src_prefix) { send_request(&neigh->buf, prefix, plen, src_prefix, src_plen);
debugf("sending unicast request to %s for %s from %s.\n", }
format_address(neigh->address),
format_prefix(prefix, plen),
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);
return;
}
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, is_ss;
debugf("Sending request (%d) for %s from %s.\n",
hop_count, format_prefix(prefix, plen),
format_prefix(src_prefix, src_plen));
v4 = plen >= 96 && v4mapped(prefix); v4 = plen >= 96 && v4mapped(prefix);
pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8;
len = 2 + pb; len = 6 + 8 + pb;
is_ss = !is_default(src_prefix, src_plen); is_ss = !is_default(src_prefix, src_plen);
if(is_ss) { if(is_ss) {
spb = v4 ? ((src_plen - 96) + 7) / 8 : (src_plen + 7) / 8; spb = v4 ? ((src_plen - 96) + 7) / 8 : (src_plen + 7) / 8;
len += spb + 1; len += spb;
rc = start_unicast_message(neigh, MESSAGE_REQUEST_SRC_SPECIFIC, len); start_message(buf, MESSAGE_MH_REQUEST_SRC_SPECIFIC, len);
} else { } else {
spb = 0; spb = 0;
rc = start_unicast_message(neigh, MESSAGE_REQUEST, len); 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) { if(is_ss) {
if(v4) if(v4)
accumulate_unicast_bytes(neigh, src_prefix + 12, spb); accumulate_bytes(buf, src_prefix + 12, spb);
else else
accumulate_unicast_bytes(neigh, src_prefix, spb); accumulate_bytes(buf, src_prefix, spb);
end_unicast_message(neigh, MESSAGE_REQUEST_SRC_SPECIFIC, len); end_message(buf, MESSAGE_MH_REQUEST_SRC_SPECIFIC, len);
} else { } else {
end_unicast_message(neigh, MESSAGE_REQUEST, len); end_message(buf, MESSAGE_MH_REQUEST, len);
} }
} }
void void
send_multihop_request(struct interface *ifp, send_multicast_multihop_request(struct interface *ifp,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen, const unsigned char *src_prefix, unsigned char src_plen,
unsigned short seqno, const unsigned char *id, unsigned short seqno, const unsigned char *id,
unsigned short hop_count) unsigned short hop_count)
{ {
int v4, pb, spb, len, is_ss;
/* Make sure any buffered updates go out before this request. */
flushupdates(ifp);
if(ifp == NULL) { if(ifp == NULL) {
struct interface *ifp_aux; struct interface *ifp_aux;
FOR_ALL_INTERFACES(ifp_aux) { FOR_ALL_INTERFACES(ifp_aux) {
if(!if_up(ifp_aux)) if(!if_up(ifp_aux))
continue; continue;
send_multihop_request(ifp_aux, prefix, plen, src_prefix, src_plen, send_multicast_multihop_request(ifp_aux,
seqno, id, hop_count); prefix, plen, src_prefix, src_plen,
seqno, id, hop_count);
} }
return; return;
} }
flushupdates(ifp);
if(!if_up(ifp)) if(!if_up(ifp))
return; return;
debugf("Sending request (%d) on %s for %s from %s.\n", send_multihop_request(&ifp->buf, prefix, plen, src_prefix, src_plen,
hop_count, ifp->name, format_prefix(prefix, plen), seqno, id, hop_count);
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->buf, MESSAGE_MH_REQUEST_SRC_SPECIFIC, len);
} else {
spb = 0;
start_message(&ifp->buf, MESSAGE_MH_REQUEST, len);
}
accumulate_byte(&ifp->buf, v4 ? 1 : 2);
accumulate_byte(&ifp->buf, v4 ? plen - 96 : plen);
accumulate_short(&ifp->buf, seqno);
accumulate_byte(&ifp->buf, hop_count);
accumulate_byte(&ifp->buf, v4 ? src_plen - 96 : src_plen);
accumulate_bytes(&ifp->buf, id, 8);
if(prefix) {
if(v4)
accumulate_bytes(&ifp->buf, prefix + 12, pb);
else
accumulate_bytes(&ifp->buf, prefix, pb);
}
if(is_ss) {
if(v4)
accumulate_bytes(&ifp->buf, src_prefix + 12, spb);
else
accumulate_bytes(&ifp->buf, src_prefix, spb);
end_message(&ifp->buf, MESSAGE_MH_REQUEST_SRC_SPECIFIC, len);
} else {
end_message(&ifp->buf, MESSAGE_MH_REQUEST, len);
}
} }
void void
...@@ -2028,50 +1840,10 @@ send_unicast_multihop_request(struct neighbour *neigh, ...@@ -2028,50 +1840,10 @@ send_unicast_multihop_request(struct neighbour *neigh,
unsigned short seqno, const unsigned char *id, unsigned short seqno, const unsigned char *id,
unsigned short hop_count) unsigned short hop_count)
{ {
int rc, v4, pb, spb, len, is_ss;
/* Make sure any buffered updates go out before this request. */
flushupdates(neigh->ifp); flushupdates(neigh->ifp);
debugf("Sending multi-hop request to %s for %s from %s (%d hops).\n", send_multihop_request(&neigh->buf, prefix, plen, src_prefix, src_plen,
format_address(neigh->address), seqno, id, hop_count);
format_prefix(prefix, plen),
format_prefix(src_prefix, src_plen), hop_count);
v4 = plen >= 96 && v4mapped(prefix);
pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8;
len = 6 + 8 + pb;
is_ss = !is_default(src_prefix, src_plen);
if(is_ss) {
spb = v4 ? ((src_plen - 96) + 7) / 8 : (src_plen + 7) / 8;
len += spb;
rc = start_unicast_message(neigh, MESSAGE_MH_REQUEST_SRC_SPECIFIC, len);
} else {
spb = 0;
rc = start_unicast_message(neigh, MESSAGE_MH_REQUEST, len);
}
if(rc < 0) return;
accumulate_unicast_byte(neigh, v4 ? 1 : 2);
accumulate_unicast_byte(neigh, v4 ? plen - 96 : plen);
accumulate_unicast_short(neigh, seqno);
accumulate_unicast_byte(neigh, hop_count);
accumulate_unicast_byte(neigh, v4 ? src_plen - 96 : src_plen);
accumulate_unicast_bytes(neigh, id, 8);
if(prefix) {
if(v4)
accumulate_unicast_bytes(neigh, prefix + 12, pb);
else
accumulate_unicast_bytes(neigh, prefix, pb);
}
if(is_ss) {
if(v4)
accumulate_unicast_bytes(neigh, src_prefix + 12, spb);
else
accumulate_unicast_bytes(neigh, src_prefix, spb);
end_unicast_message(neigh, MESSAGE_MH_REQUEST_SRC_SPECIFIC, len);
} else {
end_unicast_message(neigh, MESSAGE_MH_REQUEST, len);
}
} }
/* Send a request to a well-chosen neighbour and resend. If there is no /* Send a request to a well-chosen neighbour and resend. If there is no
......
...@@ -52,9 +52,6 @@ extern int split_horizon; ...@@ -52,9 +52,6 @@ extern int split_horizon;
extern unsigned char packet_header[4]; extern unsigned char packet_header[4];
extern struct neighbour *unicast_neighbour;
extern struct timeval unicast_flush_timeout;
void parse_packet(const unsigned char *from, struct interface *ifp, void parse_packet(const unsigned char *from, struct interface *ifp,
const unsigned char *packet, int packetlen); const unsigned char *packet, int packetlen);
void flushbuf(struct buffered *buf); void flushbuf(struct buffered *buf);
...@@ -76,19 +73,20 @@ void update_myseqno(void); ...@@ -76,19 +73,20 @@ void update_myseqno(void);
void send_self_update(struct interface *ifp); void send_self_update(struct interface *ifp);
void send_ihu(struct neighbour *neigh, struct interface *ifp); void send_ihu(struct neighbour *neigh, struct interface *ifp);
void send_marginal_ihu(struct interface *ifp); void send_marginal_ihu(struct interface *ifp);
void send_request(struct interface *ifp, void send_multicast_request(struct interface *ifp,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, unsigned char src_plen); const unsigned char *src_prefix, unsigned char src_plen);
void send_unicast_request(struct neighbour *neigh, void send_unicast_request(struct neighbour *neigh,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
const unsigned char *src_prefix, const unsigned char *src_prefix,
unsigned char src_plen); unsigned char src_plen);
void send_multihop_request(struct interface *ifp, void
const unsigned char *prefix, unsigned char plen, send_multicast_multihop_request(struct interface *ifp,
const unsigned char *src_prefix, const unsigned char *prefix, unsigned char plen,
unsigned char src_plen, const unsigned char *src_prefix,
unsigned short seqno, const unsigned char *id, unsigned char src_plen,
unsigned short hop_count); unsigned short seqno, const unsigned char *id,
unsigned short hop_count);
void void
send_unicast_multihop_request(struct neighbour *neigh, send_unicast_multihop_request(struct neighbour *neigh,
const unsigned char *prefix, unsigned char plen, const unsigned char *prefix, unsigned char plen,
......
...@@ -57,8 +57,6 @@ void ...@@ -57,8 +57,6 @@ void
flush_neighbour(struct neighbour *neigh) flush_neighbour(struct neighbour *neigh)
{ {
flush_neighbour_routes(neigh); flush_neighbour_routes(neigh);
if(unicast_neighbour == neigh)
flush_unicast(1);
flush_resends(neigh); flush_resends(neigh);
if(neighs == neigh) { if(neighs == neigh) {
...@@ -70,6 +68,7 @@ flush_neighbour(struct neighbour *neigh) ...@@ -70,6 +68,7 @@ flush_neighbour(struct neighbour *neigh)
previous->next = neigh->next; previous->next = neigh->next;
} }
local_notify_neighbour(neigh, LOCAL_FLUSH); local_notify_neighbour(neigh, LOCAL_FLUSH);
free(neigh->buf.buf);
free(neigh); free(neigh);
} }
...@@ -78,6 +77,7 @@ find_neighbour(const unsigned char *address, struct interface *ifp) ...@@ -78,6 +77,7 @@ find_neighbour(const unsigned char *address, struct interface *ifp)
{ {
struct neighbour *neigh; struct neighbour *neigh;
const struct timeval zero = {0, 0}; const struct timeval zero = {0, 0};
char *buf;
neigh = find_neighbour_nocreate(address, ifp); neigh = find_neighbour_nocreate(address, ifp);
if(neigh) if(neigh)
...@@ -86,6 +86,12 @@ find_neighbour(const unsigned char *address, struct interface *ifp) ...@@ -86,6 +86,12 @@ find_neighbour(const unsigned char *address, struct interface *ifp)
debugf("Creating neighbour %s on %s.\n", debugf("Creating neighbour %s on %s.\n",
format_address(address), ifp->name); format_address(address), ifp->name);
buf = malloc(ifp->buf.size);
if(buf == NULL) {
perror("malloc(neighbour->buf)");
return NULL;
}
neigh = calloc(1, sizeof(struct neighbour)); neigh = calloc(1, sizeof(struct neighbour));
if(neigh == NULL) { if(neigh == NULL) {
perror("malloc(neighbour)"); perror("malloc(neighbour)");
...@@ -100,6 +106,13 @@ find_neighbour(const unsigned char *address, struct interface *ifp) ...@@ -100,6 +106,13 @@ find_neighbour(const unsigned char *address, struct interface *ifp)
neigh->hello_rtt_receive_time = zero; neigh->hello_rtt_receive_time = zero;
neigh->rtt_time = zero; neigh->rtt_time = zero;
neigh->ifp = ifp; neigh->ifp = ifp;
neigh->buf.buf = buf;
neigh->buf.size = ifp->buf.size;
neigh->buf.flush_interval = ifp->buf.flush_interval;
neigh->buf.sin6.sin6_family = AF_INET6;
memcpy(&neigh->buf.sin6.sin6_addr, address, 16);
neigh->buf.sin6.sin6_port = htons(protocol_port);
neigh->buf.sin6.sin6_scope_id = ifp->ifindex;
neigh->next = neighs; neigh->next = neighs;
neighs = neigh; neighs = neigh;
local_notify_neighbour(neigh, LOCAL_ADD); local_notify_neighbour(neigh, LOCAL_ADD);
......
...@@ -44,6 +44,7 @@ struct neighbour { ...@@ -44,6 +44,7 @@ struct neighbour {
unsigned int rtt; unsigned int rtt;
struct timeval rtt_time; struct timeval rtt_time;
struct interface *ifp; struct interface *ifp;
struct buffered buf;
}; };
extern struct neighbour *neighs; extern struct neighbour *neighs;
......
...@@ -306,10 +306,12 @@ do_resend() ...@@ -306,10 +306,12 @@ do_resend()
if(timeval_compare(&now, &timeout) >= 0) { if(timeval_compare(&now, &timeout) >= 0) {
switch(resend->kind) { switch(resend->kind) {
case RESEND_REQUEST: case RESEND_REQUEST:
send_multihop_request(resend->ifp, send_multicast_multihop_request(resend->ifp,
resend->prefix, resend->plen, resend->prefix, resend->plen,
resend->src_prefix, resend->src_plen, resend->src_prefix,
resend->seqno, resend->id, 127); resend->src_plen,
resend->seqno, resend->id,
127);
break; break;
case RESEND_UPDATE: case RESEND_UPDATE:
send_update(resend->ifp, 1, send_update(resend->ifp, 1,
......
...@@ -1139,8 +1139,8 @@ send_triggered_update(struct babel_route *route, struct source *oldsrc, ...@@ -1139,8 +1139,8 @@ send_triggered_update(struct babel_route *route, struct source *oldsrc,
if(oldmetric < INFINITY) { if(oldmetric < INFINITY) {
if(newmetric >= oldmetric + 288) { if(newmetric >= oldmetric + 288) {
send_request(NULL, route->src->prefix, route->src->plen, send_multicast_request(NULL, route->src->prefix, route->src->plen,
route->src->src_prefix, route->src->src_plen); route->src->src_prefix, route->src->src_plen);
} }
} }
} }
......
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