From 5734509c0545ebd95a5b8e3f22a911c1a39ffa1b Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 25 Dec 2011 17:52:09 +0100 Subject: babeld: Initial import, for Babel routing protocol. * Initial import of the Babel routing protocol, ported to Quagga. * LICENCE: Update the original LICENCE file to include all known potentially applicable copyright claims. Ask that any future contributors to babeld/ grant MIT/X11 licence to their work. * *.{c,h}: Add GPL headers, in according with the SFLC guidance on dealing with potentially mixed GPL/other licensed work, at: https://www.softwarefreedom.org/resources/2007/gpl-non-gpl-collaboration.html --- babeld/message.c | 1456 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1456 insertions(+) create mode 100644 babeld/message.c (limited to 'babeld/message.c') diff --git a/babeld/message.c b/babeld/message.c new file mode 100644 index 00000000..bfb17625 --- /dev/null +++ b/babeld/message.c @@ -0,0 +1,1456 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + +Copyright (c) 2007, 2008 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "if.h" + +#include "babeld.h" +#include "util.h" +#include "net.h" +#include "babel_interface.h" +#include "source.h" +#include "neighbour.h" +#include "route.h" +#include "xroute.h" +#include "resend.h" +#include "message.h" +#include "kernel.h" + +unsigned char packet_header[4] = {42, 2}; + +int parasitic = 0; +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}; + +static const unsigned char v4prefix[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; + +static int +network_prefix(int ae, int plen, unsigned int omitted, + const unsigned char *p, const unsigned char *dp, + unsigned int len, unsigned char *p_r) +{ + unsigned pb; + unsigned char prefix[16]; + + if(plen >= 0) + pb = (plen + 7) / 8; + else if(ae == 1) + pb = 4; + else + pb = 16; + + if(pb > 16) + return -1; + + memset(prefix, 0, 16); + + switch(ae) { + case 0: break; + case 1: + if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted)) + return -1; + memcpy(prefix, v4prefix, 12); + if(omitted) { + if (dp == NULL || !v4mapped(dp)) return -1; + memcpy(prefix, dp, 12 + omitted); + } + if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted); + break; + case 2: + if(omitted > 16 || (pb > omitted && len < pb - omitted)) return -1; + if(omitted) { + if (dp == NULL || v4mapped(dp)) return -1; + memcpy(prefix, dp, omitted); + } + if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted); + break; + case 3: + if(pb > 8 && len < pb - 8) return -1; + prefix[0] = 0xfe; + prefix[1] = 0x80; + if(pb > 8) memcpy(prefix + 8, p, pb - 8); + break; + default: + return -1; + } + + mask_prefix(p_r, prefix, plen < 0 ? 128 : ae == 1 ? plen + 96 : plen); + return 1; +} + +static int +network_address(int ae, const unsigned char *a, unsigned int len, + unsigned char *a_r) +{ + return network_prefix(ae, -1, 0, a, NULL, len, a_r); +} + +void +parse_packet(const unsigned char *from, struct interface *ifp, + const unsigned char *packet, int packetlen) +{ + int i; + const unsigned char *message; + unsigned char type, len; + int bodylen; + struct neighbour *neigh; + int have_router_id = 0, have_v4_prefix = 0, have_v6_prefix = 0, + have_v4_nh = 0, have_v6_nh = 0; + unsigned char router_id[8], v4_prefix[16], v6_prefix[16], + v4_nh[16], v6_nh[16]; + + if(!linklocal(from)) { + fprintf(stderr, "Received packet from non-local address %s.\n", + format_address(from)); + return; + } + + if(packet[0] != 42) { + fprintf(stderr, "Received malformed packet on %s from %s.\n", + ifp->name, format_address(from)); + return; + } + + if(packet[1] != 2) { + fprintf(stderr, + "Received packet with unknown version %d on %s from %s.\n", + packet[1], ifp->name, format_address(from)); + return; + } + + neigh = find_neighbour(from, ifp); + if(neigh == NULL) { + fprintf(stderr, "Couldn't allocate neighbour.\n"); + return; + } + + DO_NTOHS(bodylen, packet + 2); + + if(bodylen + 4 > packetlen) { + fprintf(stderr, "Received truncated packet (%d + 4 > %d).\n", + bodylen, packetlen); + bodylen = packetlen - 4; + } + + i = 0; + while(i < bodylen) { + message = packet + 4 + i; + type = message[0]; + if(type == MESSAGE_PAD1) { + debugf(BABEL_DEBUG_COMMON,"Received pad1 from %s on %s.", + format_address(from), ifp->name); + i++; + continue; + } + if(i + 1 > bodylen) { + fprintf(stderr, "Received truncated message.\n"); + break; + } + len = message[1]; + if(i + len > bodylen) { + fprintf(stderr, "Received truncated message.\n"); + break; + } + + if(type == MESSAGE_PADN) { + debugf(BABEL_DEBUG_COMMON,"Received pad%d from %s on %s.", + len, format_address(from), ifp->name); + } else if(type == MESSAGE_ACK_REQ) { + unsigned short nonce, interval; + if(len < 6) goto fail; + DO_NTOHS(nonce, message + 4); + DO_NTOHS(interval, message + 6); + debugf(BABEL_DEBUG_COMMON,"Received ack-req (%04X %d) from %s on %s.", + nonce, interval, format_address(from), ifp->name); + send_ack(neigh, nonce, interval); + } else if(type == MESSAGE_ACK) { + debugf(BABEL_DEBUG_COMMON,"Received ack from %s on %s.", + format_address(from), ifp->name); + /* Nothing right now */ + } else if(type == MESSAGE_HELLO) { + unsigned short seqno, interval; + int changed; + if(len < 6) goto fail; + DO_NTOHS(seqno, message + 4); + DO_NTOHS(interval, message + 6); + debugf(BABEL_DEBUG_COMMON,"Received hello %d (%d) from %s on %s.", + seqno, interval, + format_address(from), ifp->name); + babel_get_if_nfo(ifp)->activity_time = babel_now.tv_sec; + changed = update_neighbour(neigh, seqno, interval); + update_neighbour_metric(neigh, changed); + if(interval > 0) + schedule_neighbours_check(interval * 10, 0); + } else if(type == MESSAGE_IHU) { + unsigned short txcost, interval; + unsigned char address[16]; + int rc; + if(len < 6) goto fail; + DO_NTOHS(txcost, message + 4); + DO_NTOHS(interval, message + 6); + rc = network_address(message[2], message + 8, len - 6, address); + if(rc < 0) goto fail; + debugf(BABEL_DEBUG_COMMON,"Received ihu %d (%d) from %s on %s for %s.", + txcost, interval, + format_address(from), ifp->name, + format_address(address)); + if(message[2] == 0 || is_interface_ll_address(ifp, address)) { + int changed = txcost != neigh->txcost; + neigh->txcost = txcost; + neigh->ihu_time = babel_now; + neigh->ihu_interval = interval; + update_neighbour_metric(neigh, changed); + if(interval > 0) + schedule_neighbours_check(interval * 10 * 3, 0); + } + } else if(type == MESSAGE_ROUTER_ID) { + if(len < 10) { + have_router_id = 0; + goto fail; + } + memcpy(router_id, message + 4, 8); + have_router_id = 1; + debugf(BABEL_DEBUG_COMMON,"Received router-id %s from %s on %s.", + format_eui64(router_id), format_address(from), ifp->name); + } else if(type == MESSAGE_NH) { + unsigned char nh[16]; + int rc; + if(len < 2) { + have_v4_nh = 0; + have_v6_nh = 0; + goto fail; + } + rc = network_address(message[2], message + 4, len - 2, + nh); + if(rc < 0) { + have_v4_nh = 0; + have_v6_nh = 0; + goto fail; + } + debugf(BABEL_DEBUG_COMMON,"Received nh %s (%d) from %s on %s.", + format_address(nh), message[2], + format_address(from), ifp->name); + if(message[2] == 1) { + memcpy(v4_nh, nh, 16); + have_v4_nh = 1; + } else { + memcpy(v6_nh, nh, 16); + have_v6_nh = 1; + } + } else if(type == MESSAGE_UPDATE) { + unsigned char prefix[16], *nh; + unsigned char plen; + unsigned short interval, seqno, metric; + int rc; + if(len < 10) { + if(len < 2 || message[3] & 0x80) + have_v4_prefix = have_v6_prefix = 0; + goto fail; + } + DO_NTOHS(interval, message + 6); + DO_NTOHS(seqno, message + 8); + DO_NTOHS(metric, message + 10); + if(message[5] == 0 || + (message[3] == 1 ? have_v4_prefix : have_v6_prefix)) + rc = network_prefix(message[2], message[4], message[5], + message + 12, + message[2] == 1 ? v4_prefix : v6_prefix, + len - 10, prefix); + else + rc = -1; + if(rc < 0) { + if(message[3] & 0x80) + have_v4_prefix = have_v6_prefix = 0; + goto fail; + } + + plen = message[4] + (message[2] == 1 ? 96 : 0); + + if(message[3] & 0x80) { + if(message[2] == 1) { + memcpy(v4_prefix, prefix, 16); + have_v4_prefix = 1; + } else { + memcpy(v6_prefix, prefix, 16); + have_v6_prefix = 1; + } + } + if(message[3] & 0x40) { + if(message[2] == 1) { + memset(router_id, 0, 4); + memcpy(router_id + 4, prefix + 12, 4); + } else { + memcpy(router_id, prefix + 8, 8); + } + have_router_id = 1; + } + if(!have_router_id && message[2] != 0) { + fprintf(stderr, "Received prefix with no router id.\n"); + goto fail; + } + debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.", + (message[3] & 0x80) ? "/prefix" : "", + (message[3] & 0x40) ? "/id" : "", + format_prefix(prefix, plen), + format_address(from), ifp->name); + + if(message[2] == 0) { + if(metric < 0xFFFF) { + fprintf(stderr, + "Received wildcard update with finite metric.\n"); + goto done; + } + retract_neighbour_routes(neigh); + goto done; + } else if(message[2] == 1) { + if(!have_v4_nh) + goto fail; + nh = v4_nh; + } else if(have_v6_nh) { + nh = v6_nh; + } else { + nh = neigh->address; + } + + if(message[2] == 1) { + if(!babel_get_if_nfo(ifp)->ipv4) + goto done; + } + + update_route(router_id, prefix, plen, seqno, metric, interval, + neigh, nh); + } else if(type == MESSAGE_REQUEST) { + unsigned char prefix[16], plen; + int rc; + 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(BABEL_DEBUG_COMMON,"Received request for %s from %s on %s.", + message[2] == 0 ? "any" : format_prefix(prefix, plen), + format_address(from), ifp->name); + if(message[2] == 0) { + /* If a neighbour is requesting a full route dump from us, + we might as well send it an IHU. */ + send_ihu(neigh, NULL); + send_update(neigh->ifp, 0, NULL, 0); + } else { + send_update(neigh->ifp, 0, prefix, plen); + } + } else if(type == MESSAGE_MH_REQUEST) { + unsigned char prefix[16], plen; + unsigned short seqno; + int rc; + 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; + plen = message[3] + (message[2] == 1 ? 96 : 0); + debugf(BABEL_DEBUG_COMMON,"Received request (%d) for %s from %s on %s (%s, %d).", + message[6], + format_prefix(prefix, plen), + format_address(from), ifp->name, + format_eui64(message + 8), seqno); + handle_request(neigh, prefix, plen, message[6], + seqno, message + 8); + } else { + debugf(BABEL_DEBUG_COMMON,"Received unknown packet type %d from %s on %s.", + type, format_address(from), ifp->name); + } + done: + i += len + 2; + continue; + + fail: + fprintf(stderr, "Couldn't parse packet (%d, %d) from %s on %s.\n", + message[0], message[1], format_address(from), ifp->name); + goto done; + } + 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) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + if(babel_ifp->bucket <= 0) { + int seconds = babel_now.tv_sec - babel_ifp->bucket_time; + if(seconds > 0) { + babel_ifp->bucket = MIN(BUCKET_TOKENS_MAX, + seconds * BUCKET_TOKENS_PER_SEC); + } + /* Reset bucket time unconditionally, in case clock is stepped. */ + babel_ifp->bucket_time = babel_now.tv_sec; + } + + if(babel_ifp->bucket > 0) { + babel_ifp->bucket--; + return 1; + } else { + return 0; + } +} + +void +flushbuf(struct interface *ifp) +{ + int rc; + struct sockaddr_in6 sin6; + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + + assert(babel_ifp->buffered <= babel_ifp->bufsize); + + flushupdates(ifp); + + if(babel_ifp->buffered > 0) { + debugf(BABEL_DEBUG_COMMON," (flushing %d buffered bytes on %s)", + babel_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, babel_ifp->buffered); + rc = babel_send(protocol_socket, + packet_header, sizeof(packet_header), + babel_ifp->sendbuf, babel_ifp->buffered, + (struct sockaddr*)&sin6, sizeof(sin6)); + if(rc < 0) + zlog_err("send: %s", safe_strerror(errno)); + } else { + fprintf(stderr, "Warning: bucket full, dropping packet to %s.\n", + ifp->name); + } + } + VALGRIND_MAKE_MEM_UNDEFINED(babel_ifp->sendbuf, babel_ifp->bufsize); + babel_ifp->buffered = 0; + babel_ifp->have_buffered_hello = 0; + babel_ifp->have_buffered_id = 0; + babel_ifp->have_buffered_nh = 0; + babel_ifp->have_buffered_prefix = 0; + babel_ifp->flush_timeout.tv_sec = 0; + babel_ifp->flush_timeout.tv_usec = 0; +} + +static void +schedule_flush(struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + unsigned msecs = jitter(babel_ifp, 0); + if(babel_ifp->flush_timeout.tv_sec != 0 && + timeval_minus_msec(&babel_ifp->flush_timeout, &babel_now) < msecs) + return; + set_timeout(&babel_ifp->flush_timeout, msecs); +} + +static void +schedule_flush_now(struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + /* Almost now */ + unsigned msecs = roughly(10); + if(babel_ifp->flush_timeout.tv_sec != 0 && + timeval_minus_msec(&babel_ifp->flush_timeout, &babel_now) < msecs) + return; + set_timeout(&babel_ifp->flush_timeout, msecs); +} + +static void +schedule_unicast_flush(unsigned msecs) +{ + if(!unicast_neighbour) + return; + if(unicast_flush_timeout.tv_sec != 0 && + timeval_minus_msec(&unicast_flush_timeout, &babel_now) < msecs) + return; + unicast_flush_timeout.tv_usec = (babel_now.tv_usec + msecs * 1000) %1000000; + unicast_flush_timeout.tv_sec = + babel_now.tv_sec + (babel_now.tv_usec / 1000 + msecs) / 1000; +} + +static void +ensure_space(struct interface *ifp, int space) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + if(babel_ifp->bufsize - babel_ifp->buffered < space) + flushbuf(ifp); +} + +static void +start_message(struct interface *ifp, int type, int len) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + if(babel_ifp->bufsize - babel_ifp->buffered < len + 2) + flushbuf(ifp); + babel_ifp->sendbuf[babel_ifp->buffered++] = type; + babel_ifp->sendbuf[babel_ifp->buffered++] = len; +} + +static void +end_message(struct interface *ifp, int type, int bytes) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + assert(babel_ifp->buffered >= bytes + 2 && + babel_ifp->sendbuf[babel_ifp->buffered - bytes - 2] == type && + babel_ifp->sendbuf[babel_ifp->buffered - bytes - 1] == bytes); + schedule_flush(ifp); +} + +static void +accumulate_byte(struct interface *ifp, unsigned char value) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + babel_ifp->sendbuf[babel_ifp->buffered++] = value; +} + +static void +accumulate_short(struct interface *ifp, unsigned short value) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + DO_HTONS(babel_ifp->sendbuf + babel_ifp->buffered, value); + babel_ifp->buffered += 2; +} + +static void +accumulate_bytes(struct interface *ifp, + const unsigned char *value, unsigned len) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + memcpy(babel_ifp->sendbuf + babel_ifp->buffered, value, len); + babel_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, babel_get_if_nfo(neigh->ifp)->bufsize)) + flush_unicast(0); + } + if(!unicast_buffer) + unicast_buffer = malloc(UNICAST_BUFSIZE); + if(!unicast_buffer) { + zlog_err("malloc(unicast_buffer): %s", safe_strerror(errno)); + 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(babel_get_if_nfo(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_bytes(struct neighbour *neigh, + const unsigned char *value, unsigned len) +{ + memcpy(unicast_buffer + unicast_buffered, value, len); + unicast_buffered += len; +} + +void +send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval) +{ + int rc; + debugf(BABEL_DEBUG_COMMON,"Sending ack (%04x) to %s on %s.", + 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); + /* Roughly yields a value no larger than 3/2, so this meets the deadline */ + schedule_unicast_flush(roughly(interval * 6)); +} + +void +send_hello_noupdate(struct interface *ifp, unsigned interval) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + /* This avoids sending multiple hellos in a single packet, which breaks + link quality estimation. */ + if(babel_ifp->have_buffered_hello) + flushbuf(ifp); + + babel_ifp->hello_seqno = seqno_plus(babel_ifp->hello_seqno, 1); + set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval); + + if(!if_up(ifp)) + return; + + debugf(BABEL_DEBUG_COMMON,"Sending hello %d (%d) to %s.", + babel_ifp->hello_seqno, interval, ifp->name); + + start_message(ifp, MESSAGE_HELLO, 6); + accumulate_short(ifp, 0); + accumulate_short(ifp, babel_ifp->hello_seqno); + accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval); + end_message(ifp, MESSAGE_HELLO, 6); + babel_ifp->have_buffered_hello = 1; +} + +void +send_hello(struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10); + /* Send full IHU every 3 hellos, and marginal IHU each time */ + if(babel_ifp->hello_seqno % 3 == 0) + send_ihu(NULL, ifp); + else + 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); + rc = babel_send(protocol_socket, + packet_header, sizeof(packet_header), + unicast_buffer, unicast_buffered, + (struct sockaddr*)&sin6, sizeof(sin6)); + if(rc < 0) + zlog_err("send(unicast): %s", safe_strerror(errno)); + } 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, + unsigned short seqno, unsigned short metric) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + int add_metric, v4, real_plen, omit = 0; + const unsigned char *real_prefix; + unsigned short flags = 0; + + if(!if_up(ifp)) + return; + + add_metric = output_filter(id, prefix, plen, ifp->ifindex); + if(add_metric >= INFINITY) + return; + + metric = MIN(metric + add_metric, INFINITY); + /* Worst case */ + ensure_space(ifp, 20 + 12 + 28); + + v4 = plen >= 96 && v4mapped(prefix); + + if(v4) { + if(!babel_ifp->ipv4) + return; + if(!babel_ifp->have_buffered_nh || + memcmp(babel_ifp->buffered_nh, babel_ifp->ipv4, 4) != 0) { + start_message(ifp, MESSAGE_NH, 6); + accumulate_byte(ifp, 1); + accumulate_byte(ifp, 0); + accumulate_bytes(ifp, babel_ifp->ipv4, 4); + end_message(ifp, MESSAGE_NH, 6); + memcpy(babel_ifp->buffered_nh, babel_ifp->ipv4, 4); + babel_ifp->have_buffered_nh = 1; + } + + real_prefix = prefix + 12; + real_plen = plen - 96; + } else { + if(babel_ifp->have_buffered_prefix) { + while(omit < plen / 8 && + babel_ifp->buffered_prefix[omit] == prefix[omit]) + omit++; + } + if(!babel_ifp->have_buffered_prefix || plen >= 48) + flags |= 0x80; + real_prefix = prefix; + real_plen = plen; + } + + if(!babel_ifp->have_buffered_id + || memcmp(id, babel_ifp->buffered_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); + } + memcpy(babel_ifp->buffered_id, id, 16); + babel_ifp->have_buffered_id = 1; + } + + start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit); + accumulate_byte(ifp, v4 ? 1 : 2); + accumulate_byte(ifp, flags); + accumulate_byte(ifp, real_plen); + accumulate_byte(ifp, omit); + accumulate_short(ifp, (babel_ifp->update_interval + 5) / 10); + accumulate_short(ifp, seqno); + accumulate_short(ifp, metric); + accumulate_bytes(ifp, real_prefix + omit, (real_plen + 7) / 8 - omit); + end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit); + + if(flags & 0x80) { + memcpy(babel_ifp->buffered_prefix, prefix, 16); + babel_ifp->have_buffered_prefix = 1; + } +} + +static int +compare_buffered_updates(const void *av, const void *bv) +{ + const struct buffered_update *a = av, *b = bv; + int rc, v4a, v4b, ma, mb; + + rc = memcmp(a->id, b->id, 8); + if(rc != 0) + return rc; + + v4a = (a->plen >= 96 && v4mapped(a->prefix)); + v4b = (b->plen >= 96 && v4mapped(b->prefix)); + + if(v4a > v4b) + return 1; + else if(v4a < v4b) + return -1; + + ma = (!v4a && a->plen == 128 && memcmp(a->prefix + 8, a->id, 8) == 0); + mb = (!v4b && b->plen == 128 && memcmp(b->prefix + 8, b->id, 8) == 0); + + if(ma > mb) + return -1; + else if(mb > ma) + return 1; + + if(a->plen < b->plen) + return 1; + else if(a->plen > b->plen) + return -1; + + return memcmp(a->prefix, b->prefix, 16); +} + +void +flushupdates(struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = NULL; + struct xroute *xroute; + struct route *route; + const unsigned char *last_prefix = NULL; + unsigned char last_plen = 0xFF; + int i; + + if(ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) + flushupdates(ifp_aux); + return; + } + + babel_ifp = babel_get_if_nfo(ifp); + if(babel_ifp->num_buffered_updates > 0) { + struct buffered_update *b = babel_ifp->buffered_updates; + int n = babel_ifp->num_buffered_updates; + + babel_ifp->buffered_updates = NULL; + babel_ifp->update_bufsize = 0; + babel_ifp->num_buffered_updates = 0; + + if(!if_up(ifp)) + goto done; + + debugf(BABEL_DEBUG_COMMON," (flushing %d buffered updates on %s (%d))", + n, ifp->name, ifp->ifindex); + + /* In order to send fewer update messages, we want to send updates + with the same router-id together, with IPv6 going out before IPv4. */ + + for(i = 0; i < n; i++) { + route = find_installed_route(b[i].prefix, b[i].plen); + if(route) + memcpy(b[i].id, route->src->id, 8); + else + memcpy(b[i].id, myid, 8); + } + + qsort(b, n, sizeof(struct buffered_update), compare_buffered_updates); + + for(i = 0; i < n; i++) { + unsigned short seqno; + unsigned short metric; + + /* The same update may be scheduled multiple times before it is + sent out. Since our buffer is now sorted, it is enough to + compare with the previous update. */ + + if(last_prefix) { + if(b[i].plen == last_plen && + memcmp(b[i].prefix, last_prefix, 16) == 0) + continue; + } + + xroute = find_xroute(b[i].prefix, b[i].plen); + route = find_installed_route(b[i].prefix, b[i].plen); + + if(xroute && (!route || xroute->metric <= kernel_metric)) { + really_send_update(ifp, myid, + xroute->prefix, xroute->plen, + myseqno, xroute->metric); + last_prefix = xroute->prefix; + last_plen = xroute->plen; + } else if(route) { + seqno = route->seqno; + metric = route_metric(route); + if(metric < INFINITY) + satisfy_request(route->src->prefix, route->src->plen, + seqno, route->src->id, ifp); + if((babel_ifp->flags & BABEL_IF_SPLIT_HORIZON) && + route->neigh->ifp == ifp) + continue; + really_send_update(ifp, route->src->id, + route->src->prefix, + route->src->plen, + seqno, metric); + update_source(route->src, seqno, metric); + last_prefix = route->src->prefix; + last_plen = route->src->plen; + } 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, + myseqno, INFINITY); + } + } + schedule_flush_now(ifp); + done: + free(b); + } + babel_ifp->update_flush_timeout.tv_sec = 0; + babel_ifp->update_flush_timeout.tv_usec = 0; +} + +static void +schedule_update_flush(struct interface *ifp, int urgent) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + unsigned msecs; + msecs = update_jitter(babel_ifp, urgent); + if(babel_ifp->update_flush_timeout.tv_sec != 0 && + timeval_minus_msec(&babel_ifp->update_flush_timeout, &babel_now) < msecs) + return; + set_timeout(&babel_ifp->update_flush_timeout, msecs); +} + +static void +buffer_update(struct interface *ifp, + const unsigned char *prefix, unsigned char plen) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + if(babel_ifp->num_buffered_updates > 0 && + babel_ifp->num_buffered_updates >= babel_ifp->update_bufsize) + flushupdates(ifp); + + if(babel_ifp->update_bufsize == 0) { + int n; + assert(babel_ifp->buffered_updates == NULL); + n = MAX(babel_ifp->bufsize / 16, 4); + again: + babel_ifp->buffered_updates = malloc(n *sizeof(struct buffered_update)); + if(babel_ifp->buffered_updates == NULL) { + zlog_err("malloc(buffered_updates): %s", safe_strerror(errno)); + if(n > 4) { + n = 4; + goto again; + } + return; + } + babel_ifp->update_bufsize = n; + babel_ifp->num_buffered_updates = 0; + } + + memcpy(babel_ifp->buffered_updates[babel_ifp->num_buffered_updates].prefix, + prefix, 16); + babel_ifp->buffered_updates[babel_ifp->num_buffered_updates].plen = plen; + babel_ifp->num_buffered_updates++; +} + +void +send_update(struct interface *ifp, int urgent, + const unsigned char *prefix, unsigned char plen) +{ + babel_interface_nfo *babel_ifp = NULL; + int i; + + if(ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + struct route *route; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) + send_update(ifp_aux, urgent, prefix, plen); + if(prefix) { + /* Since flushupdates only deals with non-wildcard interfaces, we + need to do this now. */ + route = find_installed_route(prefix, plen); + if(route && route_metric(route) < INFINITY) + satisfy_request(prefix, plen, route->src->seqno, route->src->id, + NULL); + } + return; + } + + if(!if_up(ifp)) + return; + + babel_ifp = babel_get_if_nfo(ifp); + if(prefix) { + if(!parasitic || find_xroute(prefix, plen)) { + debugf(BABEL_DEBUG_COMMON,"Sending update to %s for %s.", + ifp->name, format_prefix(prefix, plen)); + buffer_update(ifp, prefix, plen); + } + } else { + if(!interface_idle(babel_ifp)) { + send_self_update(ifp); + if(!parasitic) { + debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", ifp->name); + for(i = 0; i < numroutes; i++) + if(routes[i].installed) + buffer_update(ifp, + routes[i].src->prefix, + routes[i].src->plen); + } + } + set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); + } + schedule_update_flush(ifp, urgent); +} + +void +send_update_resend(struct interface *ifp, + const unsigned char *prefix, unsigned char plen) +{ + int delay; + + assert(prefix != NULL); + + send_update(ifp, 1, prefix, plen); + + delay = 2000; + delay = MIN(delay, wireless_hello_interval / 2); + delay = MIN(delay, wired_hello_interval / 2); + delay = MAX(delay, 10); + record_resend(RESEND_UPDATE, prefix, plen, 0, 0, NULL, delay); +} + +void +send_wildcard_retraction(struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = NULL; + if(ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) + send_wildcard_retraction(ifp_aux); + return; + } + + if(!if_up(ifp)) + return; + + babel_ifp = babel_get_if_nfo(ifp); + start_message(ifp, MESSAGE_UPDATE, 10); + accumulate_byte(ifp, 0); + accumulate_byte(ifp, 0x40); + 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); + + babel_ifp->have_buffered_id = 0; +} + +void +update_myseqno() +{ + myseqno = seqno_plus(myseqno, 1); + seqno_time = babel_now; +} + +void +send_self_update(struct interface *ifp) +{ + int i; + + if(ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) { + if(!if_up(ifp_aux)) + continue; + send_self_update(ifp_aux); + } + return; + } + + if(!interface_idle(babel_get_if_nfo(ifp))) { + debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name); + for(i = 0; i < numxroutes; i++) + send_update(ifp, 0, xroutes[i].prefix, xroutes[i].plen); + } +} + +void +send_ihu(struct neighbour *neigh, struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = NULL; + int rxcost, interval; + int ll; + + if(neigh == NULL && ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) { + if(if_up(ifp_aux)) + continue; + send_ihu(NULL, ifp_aux); + } + return; + } + + if(neigh == NULL) { + struct neighbour *ngh; + FOR_ALL_NEIGHBOURS(ngh) { + if(ngh->ifp == ifp) + send_ihu(ngh, ifp); + } + return; + } + + + if(ifp && neigh->ifp != ifp) + return; + + ifp = neigh->ifp; + babel_ifp = babel_get_if_nfo(ifp); + if(!if_up(ifp)) + return; + + rxcost = neighbour_rxcost(neigh); + interval = (babel_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(BABEL_DEBUG_COMMON,"Sending %sihu %d on %s to %s.", + unicast_neighbour == neigh ? "unicast " : "", + rxcost, + neigh->ifp->name, + format_address(neigh->address)); + + ll = linklocal(neigh->address); + + if(unicast_neighbour != neigh) { + start_message(ifp, MESSAGE_IHU, ll ? 14 : 22); + 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); + end_message(ifp, MESSAGE_IHU, ll ? 14 : 22); + } else { + int rc; + rc = start_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22); + 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); + end_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22); + } +} + +/* Send IHUs to all marginal neighbours */ +void +send_marginal_ihu(struct interface *ifp) +{ + struct neighbour *neigh; + FOR_ALL_NEIGHBOURS(neigh) { + if(ifp && neigh->ifp != ifp) + continue; + if(neigh->txcost >= 384 || (neigh->reach & 0xF000) != 0xF000) + send_ihu(neigh, ifp); + } +} + +void +send_request(struct interface *ifp, + const unsigned char *prefix, unsigned char plen) +{ + babel_interface_nfo *babel_ifp = NULL; + int v4, len; + + if(ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) { + if(if_up(ifp_aux)) + continue; + send_request(ifp_aux, prefix, plen); + } + return; + } + + /* make sure any buffered updates go out before this request. */ + flushupdates(ifp); + + if(!if_up(ifp)) + return; + + babel_ifp = babel_get_if_nfo(ifp); + debugf(BABEL_DEBUG_COMMON,"sending request to %s for %s.", + ifp->name, prefix ? format_prefix(prefix, plen) : "any"); + v4 = plen >= 96 && v4mapped(prefix); + len = !prefix ? 2 : v4 ? 6 : 18; + + start_message(ifp, MESSAGE_REQUEST, len); + accumulate_byte(ifp, !prefix ? 0 : v4 ? 1 : 2); + accumulate_byte(ifp, !prefix ? 0 : v4 ? plen - 96 : plen); + if(prefix) { + if(v4) + accumulate_bytes(ifp, prefix + 12, 4); + else + accumulate_bytes(ifp, prefix, 16); + } + end_message(ifp, MESSAGE_REQUEST, len); +} + +void +send_unicast_request(struct neighbour *neigh, + const unsigned char *prefix, unsigned char plen) +{ + int rc, v4, len; + + /* make sure any buffered updates go out before this request. */ + flushupdates(neigh->ifp); + + debugf(BABEL_DEBUG_COMMON,"sending unicast request to %s for %s.", + format_address(neigh->address), + prefix ? format_prefix(prefix, plen) : "any"); + v4 = plen >= 96 && v4mapped(prefix); + len = !prefix ? 2 : v4 ? 6 : 18; + + rc = start_unicast_message(neigh, MESSAGE_REQUEST, len); + if(rc < 0) return; + accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? 1 : 2); + accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? plen - 96 : plen); + if(prefix) { + if(v4) + accumulate_unicast_bytes(neigh, prefix + 12, 4); + else + accumulate_unicast_bytes(neigh, prefix, 16); + } + end_unicast_message(neigh, MESSAGE_REQUEST, len); +} + +void +send_multihop_request(struct interface *ifp, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id, + unsigned short hop_count) +{ + babel_interface_nfo *babel_ifp = NULL; + int v4, pb, len; + + /* Make sure any buffered updates go out before this request. */ + flushupdates(ifp); + + if(ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) { + if(!if_up(ifp_aux)) + continue; + send_multihop_request(ifp_aux, prefix, plen, seqno, id, hop_count); + } + return; + } + + if(!if_up(ifp)) + return; + + babel_ifp = babel_get_if_nfo(ifp); + debugf(BABEL_DEBUG_COMMON,"Sending request (%d) on %s for %s.", + hop_count, ifp->name, format_prefix(prefix, plen)); + v4 = plen >= 96 && v4mapped(prefix); + pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; + len = 6 + 8 + pb; + + 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, 0); + accumulate_bytes(ifp, id, 8); + if(prefix) { + if(v4) + accumulate_bytes(ifp, prefix + 12, pb); + else + accumulate_bytes(ifp, prefix, pb); + } + end_message(ifp, MESSAGE_MH_REQUEST, len); +} + +void +send_unicast_multihop_request(struct neighbour *neigh, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id, + unsigned short hop_count) +{ + int rc, v4, pb, len; + + /* Make sure any buffered updates go out before this request. */ + flushupdates(neigh->ifp); + + debugf(BABEL_DEBUG_COMMON,"Sending multi-hop request to %s for %s (%d hops).", + format_address(neigh->address), + format_prefix(prefix, plen), hop_count); + v4 = plen >= 96 && v4mapped(prefix); + pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; + len = 6 + 8 + pb; + + 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, 0); + accumulate_unicast_bytes(neigh, id, 8); + if(prefix) { + if(v4) + accumulate_unicast_bytes(neigh, prefix + 12, pb); + else + accumulate_unicast_bytes(neigh, prefix, pb); + } + end_unicast_message(neigh, MESSAGE_MH_REQUEST, len); +} + +void +send_request_resend(struct neighbour *neigh, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, unsigned char *id) +{ + int delay; + + if(neigh) + send_unicast_multihop_request(neigh, prefix, plen, seqno, id, 127); + else + send_multihop_request(NULL, prefix, plen, seqno, id, 127); + + delay = 2000; + delay = MIN(delay, wireless_hello_interval / 2); + delay = MIN(delay, wired_hello_interval / 2); + delay = MAX(delay, 10); + record_resend(RESEND_REQUEST, prefix, plen, seqno, id, + neigh ? neigh->ifp : NULL, delay); +} + +void +handle_request(struct neighbour *neigh, const unsigned char *prefix, + unsigned char plen, unsigned char hop_count, + unsigned short seqno, const unsigned char *id) +{ + struct xroute *xroute; + struct route *route; + struct neighbour *successor = NULL; + + xroute = find_xroute(prefix, plen); + route = find_installed_route(prefix, plen); + + if(xroute && (!route || xroute->metric <= kernel_metric)) { + if(hop_count > 0 && memcmp(id, myid, 8) == 0) { + if(seqno_compare(seqno, myseqno) > 0) { + if(seqno_minus(seqno, myseqno) > 100) { + /* Hopelessly out-of-date request */ + return; + } + update_myseqno(); + } + } + send_update(neigh->ifp, 1, prefix, plen); + return; + } + + if(route && + (memcmp(id, route->src->id, 8) != 0 || + seqno_compare(seqno, route->seqno) <= 0)) { + send_update(neigh->ifp, 1, prefix, plen); + return; + } + + if(hop_count <= 1) + return; + + if(route && memcmp(id, route->src->id, 8) == 0 && + seqno_minus(seqno, route->seqno) > 100) { + /* Hopelessly out-of-date */ + return; + } + + if(request_redundant(neigh->ifp, prefix, plen, seqno, id)) + return; + + /* Let's try to forward this request. */ + if(route && route_metric(route) < INFINITY) + successor = route->neigh; + + if(!successor || successor == neigh) { + /* We were about to forward a request to its requestor. Try to + find a different neighbour to forward the request to. */ + struct route *other_route; + + other_route = find_best_route(prefix, plen, 0, neigh); + if(other_route && route_metric(other_route) < INFINITY) + successor = other_route->neigh; + } + + if(!successor || successor == neigh) + /* Give up */ + return; + + send_unicast_multihop_request(successor, prefix, plen, seqno, id, + hop_count - 1); + record_resend(RESEND_REQUEST, prefix, plen, seqno, id, + neigh->ifp, 0); +} -- cgit v1.2.1 From ef4de4d36c2dc10a68d41e518057d04b262ec867 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sun, 8 Jan 2012 15:29:19 +0400 Subject: babeld: address FreeBSD "struct route" issue FreeBSD system headers have their own "struct route", which made it impossible to compile babeld. Switching babeld to "struct babel_route". --- babeld/message.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'babeld/message.c') diff --git a/babeld/message.c b/babeld/message.c index bfb17625..57d875fb 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -854,7 +854,7 @@ flushupdates(struct interface *ifp) { babel_interface_nfo *babel_ifp = NULL; struct xroute *xroute; - struct route *route; + struct babel_route *route; const unsigned char *last_prefix = NULL; unsigned char last_plen = 0xFF; int i; @@ -1004,7 +1004,7 @@ send_update(struct interface *ifp, int urgent, if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; - struct route *route; + struct babel_route *route; FOR_ALL_INTERFACES(ifp_aux, linklist_node) send_update(ifp_aux, urgent, prefix, plen); if(prefix) { @@ -1392,7 +1392,7 @@ handle_request(struct neighbour *neigh, const unsigned char *prefix, unsigned short seqno, const unsigned char *id) { struct xroute *xroute; - struct route *route; + struct babel_route *route; struct neighbour *successor = NULL; xroute = find_xroute(prefix, plen); @@ -1438,7 +1438,7 @@ handle_request(struct neighbour *neigh, const unsigned char *prefix, if(!successor || successor == neigh) { /* We were about to forward a request to its requestor. Try to find a different neighbour to forward the request to. */ - struct route *other_route; + struct babel_route *other_route; other_route = find_best_route(prefix, plen, 0, neigh); if(other_route && route_metric(other_route) < INFINITY) -- cgit v1.2.1 From 3dbda0ceebe369a1071600fe7d8d8ecf45f1027c Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sun, 8 Jan 2012 16:52:36 +0400 Subject: babeld: address some compilation warnings Including system headers is not necessary with zebra.h included and sometimes results in "__ASSERT_FUNCTION redefined" compilation warning. * babeld.c * babel_distribute_update_interface(): make static * babel_interface.c * interface_config_write(): unused 'babel_ifp' * don't include system headers * message.c * send_request(): unused 'babel_ifp' * send_multihop_request(): idem * don't include system headers * route.c: don't include system headers * xroute.c: idem * source.h: newline at EOF * message.h: idem --- babeld/message.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'babeld/message.c') diff --git a/babeld/message.c b/babeld/message.c index 57d875fb..7930a1b1 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -37,14 +37,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include - #include #include "if.h" @@ -1216,7 +1208,6 @@ void send_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { - babel_interface_nfo *babel_ifp = NULL; int v4, len; if(ifp == NULL) { @@ -1236,7 +1227,6 @@ send_request(struct interface *ifp, if(!if_up(ifp)) return; - babel_ifp = babel_get_if_nfo(ifp); debugf(BABEL_DEBUG_COMMON,"sending request to %s for %s.", ifp->name, prefix ? format_prefix(prefix, plen) : "any"); v4 = plen >= 96 && v4mapped(prefix); @@ -1288,7 +1278,6 @@ send_multihop_request(struct interface *ifp, unsigned short seqno, const unsigned char *id, unsigned short hop_count) { - babel_interface_nfo *babel_ifp = NULL; int v4, pb, len; /* Make sure any buffered updates go out before this request. */ @@ -1308,7 +1297,6 @@ send_multihop_request(struct interface *ifp, if(!if_up(ifp)) return; - babel_ifp = babel_get_if_nfo(ifp); debugf(BABEL_DEBUG_COMMON,"Sending request (%d) on %s for %s.", hop_count, ifp->name, format_prefix(prefix, plen)); v4 = plen >= 96 && v4mapped(prefix); -- cgit v1.2.1 From 4eedea551290906fc76f3a0c908ae759e78bb68a Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Tue, 17 Jan 2012 22:46:21 +0100 Subject: babeld: change fprintf(stderr) in term of zlog_err. --- babeld/message.c | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) (limited to 'babeld/message.c') diff --git a/babeld/message.c b/babeld/message.c index 7930a1b1..92c416b9 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -145,35 +145,34 @@ parse_packet(const unsigned char *from, struct interface *ifp, v4_nh[16], v6_nh[16]; if(!linklocal(from)) { - fprintf(stderr, "Received packet from non-local address %s.\n", - format_address(from)); + zlog_err("Received packet from non-local address %s.", + format_address(from)); return; } if(packet[0] != 42) { - fprintf(stderr, "Received malformed packet on %s from %s.\n", - ifp->name, format_address(from)); + zlog_err("Received malformed packet on %s from %s.", + ifp->name, format_address(from)); return; } if(packet[1] != 2) { - fprintf(stderr, - "Received packet with unknown version %d on %s from %s.\n", - packet[1], ifp->name, format_address(from)); + zlog_err("Received packet with unknown version %d on %s from %s.", + packet[1], ifp->name, format_address(from)); return; } neigh = find_neighbour(from, ifp); if(neigh == NULL) { - fprintf(stderr, "Couldn't allocate neighbour.\n"); + zlog_err("Couldn't allocate neighbour."); return; } DO_NTOHS(bodylen, packet + 2); if(bodylen + 4 > packetlen) { - fprintf(stderr, "Received truncated packet (%d + 4 > %d).\n", - bodylen, packetlen); + zlog_err("Received truncated packet (%d + 4 > %d).", + bodylen, packetlen); bodylen = packetlen - 4; } @@ -188,12 +187,12 @@ parse_packet(const unsigned char *from, struct interface *ifp, continue; } if(i + 1 > bodylen) { - fprintf(stderr, "Received truncated message.\n"); + zlog_err("Received truncated message."); break; } len = message[1]; if(i + len > bodylen) { - fprintf(stderr, "Received truncated message.\n"); + zlog_err("Received truncated message."); break; } @@ -330,7 +329,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, have_router_id = 1; } if(!have_router_id && message[2] != 0) { - fprintf(stderr, "Received prefix with no router id.\n"); + zlog_err("Received prefix with no router id."); goto fail; } debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.", @@ -341,8 +340,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, if(message[2] == 0) { if(metric < 0xFFFF) { - fprintf(stderr, - "Received wildcard update with finite metric.\n"); + zlog_err("Received wildcard update with finite metric."); goto done; } retract_neighbour_routes(neigh); @@ -409,8 +407,8 @@ parse_packet(const unsigned char *from, struct interface *ifp, continue; fail: - fprintf(stderr, "Couldn't parse packet (%d, %d) from %s on %s.\n", - message[0], message[1], format_address(from), ifp->name); + zlog_err("Couldn't parse packet (%d, %d) from %s on %s.", + message[0], message[1], format_address(from), ifp->name); goto done; } return; @@ -470,8 +468,8 @@ flushbuf(struct interface *ifp) if(rc < 0) zlog_err("send: %s", safe_strerror(errno)); } else { - fprintf(stderr, "Warning: bucket full, dropping packet to %s.\n", - ifp->name); + zlog_err("Warning: bucket full, dropping packet to %s.", + ifp->name); } } VALGRIND_MAKE_MEM_UNDEFINED(babel_ifp->sendbuf, babel_ifp->bufsize); @@ -705,11 +703,9 @@ flush_unicast(int dofree) if(rc < 0) zlog_err("send(unicast): %s", safe_strerror(errno)); } else { - fprintf(stderr, - "Warning: bucket full, dropping unicast packet" - "to %s if %s.\n", - format_address(unicast_neighbour->address), - unicast_neighbour->ifp->name); + zlog_err("Warning: bucket full, dropping unicast packet to %s if %s.", + format_address(unicast_neighbour->address), + unicast_neighbour->ifp->name); } done: -- cgit v1.2.1 From c35fafdf887aa32c5be6ad738d3a3b0140cea6e8 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Mon, 23 Jan 2012 23:46:32 +0100 Subject: babeld: babelz merge. Babelz is the last version of the stand-alone babel daemon. In particular, it use multiple channels to diminuate interferences. Please refer to this one for more details. --- babeld/message.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 174 insertions(+), 28 deletions(-) (limited to 'babeld/message.c') diff --git a/babeld/message.c b/babeld/message.c index 92c416b9..8cd1db63 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -69,6 +69,8 @@ struct timeval unicast_flush_timeout = {0, 0}; static const unsigned char v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; +/* Parse a network prefix, encoded in the somewhat baroque compressed + representation used by Babel. Return the number of bytes parsed. */ static int network_prefix(int ae, int plen, unsigned int omitted, const unsigned char *p, const unsigned char *dp, @@ -76,6 +78,7 @@ network_prefix(int ae, int plen, unsigned int omitted, { unsigned pb; unsigned char prefix[16]; + int ret = -1; if(plen >= 0) pb = (plen + 7) / 8; @@ -90,7 +93,9 @@ network_prefix(int ae, int plen, unsigned int omitted, memset(prefix, 0, 16); switch(ae) { - case 0: break; + case 0: + ret = 0; + break; case 1: if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted)) return -1; @@ -100,6 +105,7 @@ network_prefix(int ae, int plen, unsigned int omitted, memcpy(prefix, dp, 12 + omitted); } if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted); + ret = pb - omitted; break; case 2: if(omitted > 16 || (pb > omitted && len < pb - omitted)) return -1; @@ -108,19 +114,68 @@ network_prefix(int ae, int plen, unsigned int omitted, memcpy(prefix, dp, omitted); } if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted); + ret = pb - omitted; break; case 3: if(pb > 8 && len < pb - 8) return -1; prefix[0] = 0xfe; prefix[1] = 0x80; if(pb > 8) memcpy(prefix + 8, p, pb - 8); + ret = pb - 8; break; default: return -1; } mask_prefix(p_r, prefix, plen < 0 ? 128 : ae == 1 ? plen + 96 : plen); - return 1; + return ret; +} + +static void +parse_route_attributes(const unsigned char *a, int alen, + unsigned char *channels) +{ + int type, len, i = 0; + + while(i < alen) { + type = a[i]; + if(type == 0) { + i++; + continue; + } + + if(i + 1 > alen) { + fprintf(stderr, "Received truncated attributes.\n"); + return; + } + len = a[i + 1]; + if(i + len > alen) { + fprintf(stderr, "Received truncated attributes.\n"); + return; + } + + if(type == 1) { + /* Nothing. */ + } else if(type == 2) { + if(len > DIVERSITY_HOPS) { + fprintf(stderr, + "Received overlong channel information (%d > %d).\n", + len, DIVERSITY_HOPS); + len = DIVERSITY_HOPS; + } + if(memchr(a + i + 2, 0, len) != NULL) { + /* 0 is reserved. */ + fprintf(stderr, "Channel information contains 0!"); + return; + } + memset(channels, 0, DIVERSITY_HOPS); + memcpy(channels, a + i + 2, len); + } else { + fprintf(stderr, "Received unknown route attribute %d.\n", type); + } + + i += len + 2; + } } static int @@ -130,6 +185,13 @@ network_address(int ae, const unsigned char *a, unsigned int len, return network_prefix(ae, -1, 0, a, NULL, len, a_r); } +static int +channels_len(unsigned char *channels) +{ + unsigned char *p = memchr(channels, 0, DIVERSITY_HOPS); + return p ? (p - channels) : DIVERSITY_HOPS; +} + void parse_packet(const unsigned char *from, struct interface *ifp, const unsigned char *packet, int packetlen) @@ -284,8 +346,9 @@ parse_packet(const unsigned char *from, struct interface *ifp, } else if(type == MESSAGE_UPDATE) { unsigned char prefix[16], *nh; unsigned char plen; + unsigned char channels[DIVERSITY_HOPS]; unsigned short interval, seqno, metric; - int rc; + int rc, parsed_len; if(len < 10) { if(len < 2 || message[3] & 0x80) have_v4_prefix = have_v6_prefix = 0; @@ -307,6 +370,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, have_v4_prefix = have_v6_prefix = 0; goto fail; } + parsed_len = 10 + rc; plen = message[4] + (message[2] == 1 ? 96 : 0); @@ -360,8 +424,27 @@ parse_packet(const unsigned char *from, struct interface *ifp, goto done; } + if((ifp->flags & BABEL_IF_FARAWAY)) { + channels[0] = 0; + } else { + /* This will be overwritten by parse_route_attributes below. */ + if(metric < 256) { + /* Assume non-interfering (wired) link. */ + channels[0] = 0; + } else { + /* Assume interfering. */ + channels[0] = BABEL_IF_CHANNEL_INTERFERING; + channels[1] = 0; + } + + if(parsed_len < len) + parse_route_attributes(message + 2 + parsed_len, + len - parsed_len, channels); + } + update_route(router_id, prefix, plen, seqno, metric, interval, - neigh, nh); + neigh, nh, + channels, channels_len(channels)); } else if(type == MESSAGE_REQUEST) { unsigned char prefix[16], plen; int rc; @@ -374,10 +457,17 @@ parse_packet(const unsigned char *from, struct interface *ifp, message[2] == 0 ? "any" : format_prefix(prefix, plen), format_address(from), ifp->name); if(message[2] == 0) { + struct babel_interface *babel_ifp =babel_get_if_nfo(neigh->ifp); /* If a neighbour is requesting a full route dump from us, we might as well send it an IHU. */ send_ihu(neigh, NULL); - send_update(neigh->ifp, 0, NULL, 0); + /* Since nodes send wildcard requests on boot, booting + a large number of nodes at the same time may cause an + update storm. Ignore a wildcard request that happens + shortly after we sent a full update. */ + if(babel_ifp->last_update_time < + babel_now.tv_sec - MAX(babel_ifp->hello_interval / 100, 1)) + send_update(neigh->ifp, 0, NULL, 0); } else { send_update(neigh->ifp, 0, prefix, plen); } @@ -665,10 +755,12 @@ send_hello_noupdate(struct interface *ifp, unsigned interval) void send_hello(struct interface *ifp) { + int changed; + changed = update_hello_interval(ifp); babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10); /* Send full IHU every 3 hellos, and marginal IHU each time */ - if(babel_ifp->hello_seqno % 3 == 0) + if(changed || babel_ifp->hello_seqno % 3 == 0) send_ihu(NULL, ifp); else send_marginal_ihu(ifp); @@ -724,12 +816,19 @@ static void really_send_update(struct interface *ifp, const unsigned char *id, const unsigned char *prefix, unsigned char plen, - unsigned short seqno, unsigned short metric) + unsigned short seqno, unsigned short metric, + unsigned char *channels, int channels_len) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); int add_metric, v4, real_plen, omit = 0; const unsigned char *real_prefix; unsigned short flags = 0; + int channels_size; + + if(diversity_kind != DIVERSITY_CHANNEL) + channels_len = -1; + + channels_size = channels_len >= 0 ? channels_len + 2 : 0; if(!if_up(ifp)) return; @@ -786,7 +885,8 @@ really_send_update(struct interface *ifp, babel_ifp->have_buffered_id = 1; } - start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit); + start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + + channels_size); accumulate_byte(ifp, v4 ? 1 : 2); accumulate_byte(ifp, flags); accumulate_byte(ifp, real_plen); @@ -795,7 +895,14 @@ really_send_update(struct interface *ifp, accumulate_short(ifp, seqno); accumulate_short(ifp, metric); accumulate_bytes(ifp, real_prefix + omit, (real_plen + 7) / 8 - omit); - end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit); + /* 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); + } + end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + + channels_size); if(flags & 0x80) { memcpy(babel_ifp->buffered_prefix, prefix, 16); @@ -884,9 +991,6 @@ flushupdates(struct interface *ifp) qsort(b, n, sizeof(struct buffered_update), compare_buffered_updates); for(i = 0; i < n; i++) { - unsigned short seqno; - unsigned short metric; - /* The same update may be scheduled multiple times before it is sent out. Since our buffer is now sorted, it is enough to compare with the previous update. */ @@ -903,22 +1007,51 @@ flushupdates(struct interface *ifp) if(xroute && (!route || xroute->metric <= kernel_metric)) { really_send_update(ifp, myid, xroute->prefix, xroute->plen, - myseqno, xroute->metric); + myseqno, xroute->metric, + NULL, 0); last_prefix = xroute->prefix; last_plen = xroute->plen; } else if(route) { + unsigned char channels[DIVERSITY_HOPS]; + int chlen; + struct interface *route_ifp = route->neigh->ifp; + struct babel_interface *babel_route_ifp = NULL; + unsigned short metric; + unsigned short seqno; + seqno = route->seqno; - metric = route_metric(route); + metric = + route_interferes(route, ifp) ? + route_metric(route) : + route_metric_noninterfering(route); + if(metric < INFINITY) satisfy_request(route->src->prefix, route->src->plen, seqno, route->src->id, ifp); if((babel_ifp->flags & BABEL_IF_SPLIT_HORIZON) && route->neigh->ifp == ifp) continue; + + babel_route_ifp = babel_get_if_nfo(route_ifp); + if(babel_route_ifp->channel ==BABEL_IF_CHANNEL_NONINTERFERING) { + memcpy(channels, route->channels, DIVERSITY_HOPS); + } else { + if(babel_route_ifp->channel == BABEL_IF_CHANNEL_UNKNOWN) + channels[0] = BABEL_IF_CHANNEL_INTERFERING; + else { + assert(babel_route_ifp->channel > 0 && + babel_route_ifp->channel <= 255); + channels[0] = babel_route_ifp->channel; + } + memcpy(channels + 1, route->channels, DIVERSITY_HOPS - 1); + } + + chlen = channels_len(channels); really_send_update(ifp, route->src->id, route->src->prefix, route->src->plen, - seqno, metric); + seqno, metric, + channels, chlen); update_source(route->src, seqno, metric); last_prefix = route->src->prefix; last_plen = route->src->plen; @@ -926,7 +1059,7 @@ flushupdates(struct interface *ifp) /* 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, - myseqno, INFINITY); + myseqno, INFINITY, NULL, -1); } } schedule_flush_now(ifp); @@ -961,12 +1094,17 @@ buffer_update(struct interface *ifp, if(babel_ifp->update_bufsize == 0) { int n; assert(babel_ifp->buffered_updates == NULL); - n = MAX(babel_ifp->bufsize / 16, 4); + /* Allocate enough space to hold a full update. Since the + 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, babel_ifp->bufsize / 16); again: babel_ifp->buffered_updates = malloc(n *sizeof(struct buffered_update)); if(babel_ifp->buffered_updates == NULL) { zlog_err("malloc(buffered_updates): %s", safe_strerror(errno)); if(n > 4) { + /* Try again with a tiny buffer. */ n = 4; goto again; } @@ -982,12 +1120,18 @@ buffer_update(struct interface *ifp, babel_ifp->num_buffered_updates++; } +static void +buffer_update_callback(struct babel_route *route, void *closure) +{ + buffer_update((struct interface*)closure, + route->src->prefix, route->src->plen); +} + void send_update(struct interface *ifp, int urgent, const unsigned char *prefix, unsigned char plen) { babel_interface_nfo *babel_ifp = NULL; - int i; if(ifp == NULL) { struct interface *ifp_aux; @@ -1020,15 +1164,13 @@ send_update(struct interface *ifp, int urgent, if(!interface_idle(babel_ifp)) { send_self_update(ifp); if(!parasitic) { - debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", ifp->name); - for(i = 0; i < numroutes; i++) - if(routes[i].installed) - buffer_update(ifp, - routes[i].src->prefix, - routes[i].src->plen); + debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", + ifp->name); + for_all_installed_routes(buffer_update_callback, ifp); } } set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); + babel_ifp->last_update_time = babel_now.tv_sec; } schedule_update_flush(ifp, urgent); } @@ -1086,11 +1228,16 @@ update_myseqno() seqno_time = babel_now; } +static void +send_xroute_update_callback(struct xroute *xroute, void *closure) +{ + struct interface *ifp = (struct interface*)closure; + send_update(ifp, 0, xroute->prefix, xroute->plen); +} + void send_self_update(struct interface *ifp) { - int i; - if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; @@ -1104,8 +1251,7 @@ send_self_update(struct interface *ifp) if(!interface_idle(babel_get_if_nfo(ifp))) { debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name); - for(i = 0; i < numxroutes; i++) - send_update(ifp, 0, xroutes[i].prefix, xroutes[i].plen); + for_all_xroutes(send_xroute_update_callback, ifp); } } -- cgit v1.2.1 From 52d54422bdc0b70356d84a38a0ce15ba5dea03e0 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Sat, 11 Feb 2012 13:08:00 +0100 Subject: Resynchronise with babeld-1.3.1. --- babeld/message.c | 43 ++++++++++++------------------------------- 1 file changed, 12 insertions(+), 31 deletions(-) (limited to 'babeld/message.c') diff --git a/babeld/message.c b/babeld/message.c index 8cd1db63..e86b4325 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -282,7 +282,6 @@ parse_packet(const unsigned char *from, struct interface *ifp, debugf(BABEL_DEBUG_COMMON,"Received hello %d (%d) from %s on %s.", seqno, interval, format_address(from), ifp->name); - babel_get_if_nfo(ifp)->activity_time = babel_now.tv_sec; changed = update_neighbour(neigh, seqno, interval); update_neighbour_metric(neigh, changed); if(interval > 0) @@ -466,7 +465,8 @@ 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(babel_ifp->last_update_time < - babel_now.tv_sec - MAX(babel_ifp->hello_interval / 100, 1)) + (time_t)(babel_now.tv_sec - + MAX(babel_ifp->hello_interval / 100, 1))) send_update(neigh->ifp, 0, NULL, 0); } else { send_update(neigh->ifp, 0, prefix, plen); @@ -755,12 +755,10 @@ send_hello_noupdate(struct interface *ifp, unsigned interval) void send_hello(struct interface *ifp) { - int changed; - changed = update_hello_interval(ifp); babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10); /* Send full IHU every 3 hellos, and marginal IHU each time */ - if(changed || babel_ifp->hello_seqno % 3 == 0) + if(babel_ifp->hello_seqno % 3 == 0) send_ihu(NULL, ifp); else send_marginal_ihu(ifp); @@ -1161,13 +1159,11 @@ send_update(struct interface *ifp, int urgent, buffer_update(ifp, prefix, plen); } } else { - if(!interface_idle(babel_ifp)) { - send_self_update(ifp); - if(!parasitic) { - debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", - ifp->name); - for_all_installed_routes(buffer_update_callback, ifp); - } + send_self_update(ifp); + if(!parasitic) { + debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", + ifp->name); + for_all_installed_routes(buffer_update_callback, ifp); } set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); babel_ifp->last_update_time = babel_now.tv_sec; @@ -1179,17 +1175,10 @@ void send_update_resend(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { - int delay; - assert(prefix != NULL); send_update(ifp, 1, prefix, plen); - - delay = 2000; - delay = MIN(delay, wireless_hello_interval / 2); - delay = MIN(delay, wired_hello_interval / 2); - delay = MAX(delay, 10); - record_resend(RESEND_UPDATE, prefix, plen, 0, 0, NULL, delay); + record_resend(RESEND_UPDATE, prefix, plen, 0, 0, NULL, resend_delay); } void @@ -1249,10 +1238,8 @@ send_self_update(struct interface *ifp) return; } - if(!interface_idle(babel_get_if_nfo(ifp))) { - debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name); - for_all_xroutes(send_xroute_update_callback, ifp); - } + debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name); + for_all_xroutes(send_xroute_update_callback, ifp); } void @@ -1501,19 +1488,13 @@ send_request_resend(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned char *id) { - int delay; - if(neigh) send_unicast_multihop_request(neigh, prefix, plen, seqno, id, 127); else send_multihop_request(NULL, prefix, plen, seqno, id, 127); - delay = 2000; - delay = MIN(delay, wireless_hello_interval / 2); - delay = MIN(delay, wired_hello_interval / 2); - delay = MAX(delay, 10); record_resend(RESEND_REQUEST, prefix, plen, seqno, id, - neigh ? neigh->ifp : NULL, delay); + neigh ? neigh->ifp : NULL, resend_delay); } void -- cgit v1.2.1 From 6881f2698279f3c47a55e8969860eeac59e8c3d7 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 14 Feb 2012 15:43:34 +0100 Subject: babeld: remove "parasitic" mode. This is the functionality described in Appendix C of RFC 6126. Its main purpose is to avoid keeping a full source table, which makes it possible to implement a subset of Babel in just a few hundred lines of code. However, in Quagga the code for maintaining the source table is already there, and a parasitic implementation can be simulated using filtering -- so it makes little sense to keep the functionality. --- babeld/message.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'babeld/message.c') diff --git a/babeld/message.c b/babeld/message.c index e86b4325..9dcfc677 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -54,7 +54,6 @@ THE SOFTWARE. unsigned char packet_header[4] = {42, 2}; -int parasitic = 0; int split_horizon = 1; unsigned short myseqno = 0; @@ -1153,18 +1152,13 @@ send_update(struct interface *ifp, int urgent, babel_ifp = babel_get_if_nfo(ifp); if(prefix) { - if(!parasitic || find_xroute(prefix, plen)) { - debugf(BABEL_DEBUG_COMMON,"Sending update to %s for %s.", - ifp->name, format_prefix(prefix, plen)); - buffer_update(ifp, prefix, plen); - } + debugf(BABEL_DEBUG_COMMON,"Sending update to %s for %s.", + ifp->name, format_prefix(prefix, plen)); + buffer_update(ifp, prefix, plen); } else { send_self_update(ifp); - if(!parasitic) { - debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", - ifp->name); - for_all_installed_routes(buffer_update_callback, ifp); - } + debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", ifp->name); + for_all_installed_routes(buffer_update_callback, ifp); set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); babel_ifp->last_update_time = babel_now.tv_sec; } -- cgit v1.2.1