diff -Nru babeld-1.2.1/babeld.c babeld-1.3.0/babeld.c --- babeld-1.2.1/babeld.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/babeld.c 2011-12-08 18:46:00.000000000 +0000 @@ -43,7 +43,7 @@ #include "util.h" #include "net.h" #include "kernel.h" -#include "network.h" +#include "interface.h" #include "source.h" #include "neighbour.h" #include "route.h" @@ -108,7 +108,7 @@ char *config_file = NULL; void *vrc; unsigned int seed; - struct network *net; + struct interface *ifp; gettime(&now); @@ -362,22 +362,22 @@ } for(i = optind; i < argc; i++) { - vrc = add_network(argv[i], NULL); + vrc = add_interface(argv[i], NULL); if(vrc == NULL) goto fail; } - if(networks == NULL) { + if(interfaces == NULL) { fprintf(stderr, "Eek... asked to run on no interfaces!\n"); goto fail; } - FOR_ALL_NETS(net) { - /* net->ifindex is not necessarily valid at this point */ - int ifindex = if_nametoindex(net->ifname); + FOR_ALL_INTERFACES(ifp) { + /* ifp->ifindex is not necessarily valid at this point */ + int ifindex = if_nametoindex(ifp->name); if(ifindex > 0) { unsigned char eui[8]; - rc = if_eui64(net->ifname, ifindex, eui); + rc = if_eui64(ifp->name, ifindex, eui); if(rc < 0) continue; memcpy(myid, eui, 8); @@ -482,7 +482,7 @@ rc = resize_receive_buffer(1500); if(rc < 0) goto fail; - check_networks(); + check_interfaces(); if(receive_buffer == NULL) goto fail; @@ -499,27 +499,27 @@ /* Make some noise so that others notice us, and send retractions in case we were restarted recently */ - FOR_ALL_NETS(net) { - if(!net_up(net)) + FOR_ALL_INTERFACES(ifp) { + if(!if_up(ifp)) continue; /* Apply jitter before we send the first message. */ usleep(roughly(10000)); gettime(&now); - send_hello(net); - send_wildcard_retraction(net); + send_hello(ifp); + send_wildcard_retraction(ifp); } - FOR_ALL_NETS(net) { - if(!net_up(net)) + FOR_ALL_INTERFACES(ifp) { + if(!if_up(ifp)) continue; usleep(roughly(10000)); gettime(&now); - send_hello(net); - send_wildcard_retraction(net); - send_self_update(net); - send_request(net, NULL, 0); - flushupdates(net); - flushbuf(net); + send_hello(ifp); + send_wildcard_retraction(ifp); + send_self_update(ifp); + send_request(ifp, NULL, 0); + flushupdates(ifp); + flushbuf(ifp); } debugf("Entering main loop.\n"); @@ -535,13 +535,13 @@ timeval_min_sec(&tv, source_expiry_time); timeval_min_sec(&tv, kernel_dump_time); timeval_min(&tv, &resend_time); - FOR_ALL_NETS(net) { - if(!net_up(net)) + FOR_ALL_INTERFACES(ifp) { + if(!if_up(ifp)) continue; - timeval_min(&tv, &net->flush_timeout); - timeval_min(&tv, &net->hello_timeout); - timeval_min(&tv, &net->update_timeout); - timeval_min(&tv, &net->update_flush_timeout); + timeval_min(&tv, &ifp->flush_timeout); + timeval_min(&tv, &ifp->hello_timeout); + timeval_min(&tv, &ifp->update_timeout); + timeval_min(&tv, &ifp->update_flush_timeout); } timeval_min(&tv, &unicast_flush_timeout); FD_ZERO(&readfds); @@ -593,11 +593,11 @@ sleep(1); } } else { - FOR_ALL_NETS(net) { - if(!net_up(net)) + FOR_ALL_INTERFACES(ifp) { + if(!if_up(ifp)) continue; - if(net->ifindex == sin6.sin6_scope_id) { - parse_packet((unsigned char*)&sin6.sin6_addr, net, + if(ifp->ifindex == sin6.sin6_scope_id) { + parse_packet((unsigned char*)&sin6.sin6_addr, ifp, receive_buffer, rc); VALGRIND_MAKE_MEM_UNDEFINED(receive_buffer, receive_buffer_size); @@ -619,7 +619,7 @@ if(errno != EINTR && errno != EAGAIN) perror("accept(local_server_socket)"); } else { - local_dump(); + local_notify_all(); } } @@ -647,7 +647,7 @@ } if(kernel_link_changed || kernel_addr_changed) { - check_networks(); + check_interfaces(); kernel_link_changed = 0; } @@ -671,7 +671,7 @@ } if(now.tv_sec >= expiry_time) { - check_networks(); + check_interfaces(); expire_routes(); expire_resend(); expiry_time = now.tv_sec + roughly(30); @@ -682,15 +682,15 @@ source_expiry_time = now.tv_sec + roughly(300); } - FOR_ALL_NETS(net) { - if(!net_up(net)) + FOR_ALL_INTERFACES(ifp) { + if(!if_up(ifp)) continue; - if(timeval_compare(&now, &net->hello_timeout) >= 0) - send_hello(net); - if(timeval_compare(&now, &net->update_timeout) >= 0) - send_update(net, 0, NULL, 0); - if(timeval_compare(&now, &net->update_flush_timeout) >= 0) - flushupdates(net); + if(timeval_compare(&now, &ifp->hello_timeout) >= 0) + send_hello(ifp); + if(timeval_compare(&now, &ifp->update_timeout) >= 0) + send_update(ifp, 0, NULL, 0); + if(timeval_compare(&now, &ifp->update_flush_timeout) >= 0) + flushupdates(ifp); } if(resend_time.tv_sec != 0) { @@ -703,12 +703,12 @@ flush_unicast(1); } - FOR_ALL_NETS(net) { - if(!net_up(net)) + FOR_ALL_INTERFACES(ifp) { + if(!if_up(ifp)) continue; - if(net->flush_timeout.tv_sec != 0) { - if(timeval_compare(&now, &net->flush_timeout) >= 0) - flushbuf(net); + if(ifp->flush_timeout.tv_sec != 0) { + if(timeval_compare(&now, &ifp->flush_timeout) >= 0) + flushbuf(ifp); } } @@ -722,35 +722,30 @@ usleep(roughly(10000)); gettime(&now); - /* Uninstall and flush all routes. */ - while(numroutes > 0) { - if(routes[0].installed) - uninstall_route(&routes[0]); - /* We need to flush the route so network_up won't reinstall it */ - flush_route(&routes[0]); - } + /* We need to flush so interface_up won't try to reinstall. */ + flush_all_routes(); - FOR_ALL_NETS(net) { - if(!net_up(net)) + FOR_ALL_INTERFACES(ifp) { + if(!if_up(ifp)) continue; - send_wildcard_retraction(net); + send_wildcard_retraction(ifp); /* Make sure that we expire quickly from our neighbours' association caches. */ - send_hello_noupdate(net, 10); - flushbuf(net); + send_hello_noupdate(ifp, 10); + flushbuf(ifp); usleep(roughly(1000)); gettime(&now); } - FOR_ALL_NETS(net) { - if(!net_up(net)) + FOR_ALL_INTERFACES(ifp) { + if(!if_up(ifp)) continue; /* Make sure they got it. */ - send_wildcard_retraction(net); - send_hello_noupdate(net, 1); - flushbuf(net); + send_wildcard_retraction(ifp); + send_hello_noupdate(ifp, 1); + flushbuf(ifp); usleep(roughly(10000)); gettime(&now); - network_up(net, 0); + interface_up(ifp, 0); } kernel_setup_socket(0); kernel_setup(0); @@ -802,10 +797,10 @@ exit(1); fail: - FOR_ALL_NETS(net) { - if(!net_up(net)) + FOR_ALL_INTERFACES(ifp) { + if(!if_up(ifp)) continue; - network_up(net, 0); + interface_up(ifp, 0); } kernel_setup_socket(0); kernel_setup(0); @@ -924,10 +919,62 @@ } static void +dump_route_callback(struct route *route, void *closure) +{ + FILE *out = (FILE*)closure; + const unsigned char *nexthop = + memcmp(route->nexthop, route->neigh->address, 16) == 0 ? + NULL : route->nexthop; + char channels[100]; + + if(route->channels[0] == 0) + channels[0] = '\0'; + else { + int k, j = 0; + snprintf(channels, 100, " chan ("); + j = strlen(channels); + for(k = 0; k < DIVERSITY_HOPS; k++) { + if(route->channels[k] == 0) + break; + if(k > 0) + channels[j++] = ','; + snprintf(channels + j, 100 - j, "%d", route->channels[k]); + j = strlen(channels); + } + snprintf(channels + j, 100 - j, ")"); + if(k == 0) + channels[0] = '\0'; + } + + fprintf(out, "%s metric %d refmetric %d id %s seqno %d%s age %d " + "via %s neigh %s%s%s%s\n", + format_prefix(route->src->prefix, route->src->plen), + route_metric(route), route->refmetric, + format_eui64(route->src->id), + (int)route->seqno, + channels, + (int)(now.tv_sec - route->time), + route->neigh->ifp->name, + format_address(route->neigh->address), + nexthop ? " nexthop " : "", + nexthop ? format_address(nexthop) : "", + route->installed ? " (installed)" : + route_feasible(route) ? " (feasible)" : ""); +} + +static void +dump_xroute_callback(struct xroute *xroute, void *closure) +{ + FILE *out = (FILE*)closure; + fprintf(out, "%s metric %d (exported)\n", + format_prefix(xroute->prefix, xroute->plen), + xroute->metric); +} + +static void dump_tables(FILE *out) { struct neighbour *neigh; - int i; fprintf(out, "\n"); @@ -936,57 +983,15 @@ FOR_ALL_NEIGHBOURS(neigh) { fprintf(out, "Neighbour %s dev %s reach %04x rxcost %d txcost %d chan %d%s.\n", format_address(neigh->address), - neigh->network->ifname, + neigh->ifp->name, neigh->reach, neighbour_rxcost(neigh), neigh->txcost, - neigh->network->channel, - net_up(neigh->network) ? "" : " (down)"); - } - for(i = 0; i < numxroutes; i++) { - fprintf(out, "%s metric %d (exported)\n", - format_prefix(xroutes[i].prefix, xroutes[i].plen), - xroutes[i].metric); - } - for(i = 0; i < numroutes; i++) { - const unsigned char *nexthop = - memcmp(routes[i].nexthop, routes[i].neigh->address, 16) == 0 ? - NULL : routes[i].nexthop; - char channels[100]; - if(routes[i].channels[0] == 0) - channels[0] = '\0'; - else { - int k, j = 0; - snprintf(channels, 100, " chan ("); - j = strlen(channels); - for(k = 0; k < DIVERSITY_HOPS; k++) { - if(routes[i].channels[k] == 0) - break; - if(k > 0) - channels[j++] = ','; - snprintf(channels + j, 100 - j, "%d", routes[i].channels[k]); - j = strlen(channels); - } - snprintf(channels + j, 100 - j, ")"); - if(k == 0) - channels[0] = '\0'; - } - - fprintf(out, "%s metric %d refmetric %d id %s seqno %d%s age %d " - "via %s neigh %s%s%s%s\n", - format_prefix(routes[i].src->prefix, routes[i].src->plen), - route_metric(&routes[i]), routes[i].refmetric, - format_eui64(routes[i].src->id), - (int)routes[i].seqno, - channels, - (int)(now.tv_sec - routes[i].time), - routes[i].neigh->network->ifname, - format_address(routes[i].neigh->address), - nexthop ? " nexthop " : "", - nexthop ? format_address(nexthop) : "", - routes[i].installed ? " (installed)" : - route_feasible(&routes[i]) ? " (feasible)" : ""); + neigh->ifp->channel, + if_up(neigh->ifp) ? "" : " (down)"); } + for_all_xroutes(dump_xroute_callback, out); + for_all_routes(dump_route_callback, out); fflush(out); } diff -Nru babeld-1.2.1/CHANGES babeld-1.3.0/CHANGES --- babeld-1.2.1/CHANGES 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/CHANGES 2011-12-08 18:46:00.000000000 +0000 @@ -1,3 +1,16 @@ +8 December 2011: babeld-1.3.0 + + * Made the route table into a sorted array, and use binary sort for + searching for routes. This makes most route operations O(log n), at + a slight cost in memory usage. + * Changed the update sending strategy to use buffers large enough for + a full update. This makes the duplicate suppression mechanism + effective in large networks, at a small cost in memory usage. + * Rate-limit the reaction to wildcard requests. This avoids an update + storm at boot in large networks. + * Fixed a bug that prevented usage of the "default" keyword in + configuration files. + 16 October 2011: babeld-1.2.1 * Fixed an incorrect assertion that would cause a crash when -w was diff -Nru babeld-1.2.1/configuration.c babeld-1.3.0/configuration.c --- babeld-1.2.1/configuration.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/configuration.c 2011-12-08 18:46:00.000000000 +0000 @@ -34,13 +34,13 @@ #include "babeld.h" #include "util.h" -#include "network.h" +#include "interface.h" #include "configuration.h" struct filter *input_filters = NULL; struct filter *output_filters = NULL; struct filter *redistribute_filters = NULL; -struct network_conf *network_confs = NULL; +struct interface_conf *interface_confs = NULL; /* get_next_char callback */ typedef int (*gnc_t)(void*); @@ -370,15 +370,15 @@ return NULL; } -static struct network_conf * -parse_nconf(gnc_t gnc, void *closure) +static struct interface_conf * +parse_ifconf(gnc_t gnc, void *closure) { int c; char *token; - struct network_conf *nconf; + struct interface_conf *if_conf; - nconf = calloc(1, sizeof(struct network_conf)); - if(nconf == NULL) + if_conf = calloc(1, sizeof(struct interface_conf)); + if(if_conf == NULL) goto error; c = gnc(closure); @@ -393,7 +393,7 @@ if(c < -1 || token == NULL) goto error; - nconf->ifname = token; + if_conf->ifname = token; while(c >= 0 && c != '\n') { c = skip_whitespace(c, gnc, closure); @@ -410,43 +410,43 @@ c = getint(c, &cost, gnc, closure); if(c < -1 || cost <= 0 || cost > 0xFFFF) goto error; - nconf->cost = cost; + if_conf->cost = cost; } else if(strcmp(token, "hello-interval") == 0) { int interval; c = getmsec(c, &interval, gnc, closure); if(c < -1 || interval <= 0 || interval > 10 * 0xFFFF) goto error; - nconf->hello_interval = interval; + if_conf->hello_interval = interval; } else if(strcmp(token, "update-interval") == 0) { int interval; c = getmsec(c, &interval, gnc, closure); if(c < -1 || interval <= 0 || interval > 10 * 0xFFFF) goto error; - nconf->update_interval = interval; + if_conf->update_interval = interval; } else if(strcmp(token, "wired") == 0) { int v; c = getbool(c, &v, gnc, closure); if(c < -1) goto error; - nconf->wired = v; + if_conf->wired = v; } else if(strcmp(token, "faraway") == 0) { int v; c = getbool(c, &v, gnc, closure); if(c < -1) goto error; - nconf->faraway = v; + if_conf->faraway = v; } else if(strcmp(token, "link-quality") == 0) { int v; c = getbool(c, &v, gnc, closure); if(c < -1) goto error; - nconf->lq = v; + if_conf->lq = v; } else if(strcmp(token, "split-horizon") == 0) { int v; c = getbool(c, &v, gnc, closure); if(c < -1) goto error; - nconf->split_horizon = v; + if_conf->split_horizon = v; } else if(strcmp(token, "channel") == 0) { char *t, *end; @@ -455,19 +455,19 @@ goto error; if(strcmp(t, "noninterfering") == 0) - nconf->channel = NET_CHANNEL_NONINTERFERING; + if_conf->channel = IF_CHANNEL_NONINTERFERING; else if(strcmp(t, "interfering") == 0) - nconf->channel = NET_CHANNEL_INTERFERING; + if_conf->channel = IF_CHANNEL_INTERFERING; else { - nconf->channel = strtol(t, &end, 0); + if_conf->channel = strtol(t, &end, 0); if(*end != '\0') goto error; } free(t); - if((nconf->channel < 1 || nconf->channel > 254) && - nconf->channel != NET_CHANNEL_NONINTERFERING) + if((if_conf->channel < 1 || if_conf->channel > 254) && + if_conf->channel != IF_CHANNEL_NONINTERFERING) goto error; } else { goto error; @@ -475,10 +475,10 @@ free(token); } - return nconf; + return if_conf; error: - free(nconf); + free(if_conf); return NULL; } @@ -499,7 +499,7 @@ } static void -merge_nconf(struct network_conf *dest, struct network_conf *src) +merge_ifconf(struct interface_conf *dest, struct interface_conf *src) { assert(strcmp(dest->ifname, src->ifname) == 0); @@ -520,24 +520,24 @@ } static void -add_nconf(struct network_conf *nconf, struct network_conf **nconfs) +add_ifconf(struct interface_conf *if_conf, struct interface_conf **if_confs) { - if(*nconfs == NULL) { - nconf->next = NULL; - *nconfs = nconf; + if(*if_confs == NULL) { + if_conf->next = NULL; + *if_confs = if_conf; } else { - struct network_conf *n; - n = *nconfs; - while(n->next) { - if(strcmp(n->ifname, nconf->ifname) == 0) { - merge_nconf(n, nconf); - free(nconf); + struct interface_conf *if_c; + if_c = *if_confs; + while(if_c->next) { + if(strcmp(if_c->ifname, if_conf->ifname) == 0) { + merge_ifconf(if_c, if_conf); + free(if_conf); return; } - n = n->next; + if_c = if_c->next; } - nconf->next = NULL; - n->next = nconf; + if_conf->next = NULL; + if_c->next = if_conf; } } @@ -582,11 +582,11 @@ return -1; add_filter(filter, &redistribute_filters); } else if(strcmp(token, "interface") == 0) { - struct network_conf *nconf; - nconf = parse_nconf(gnc, closure); - if(nconf == NULL) + struct interface_conf *if_conf; + if_conf = parse_ifconf(gnc, closure); + if(if_conf == NULL) return -1; - add_nconf(nconf, &network_confs); + add_ifconf(if_conf, &interface_confs); } else { return -1; } @@ -759,15 +759,15 @@ filter->plen_le = 128; add_filter(filter, &redistribute_filters); - while(network_confs) { - struct network_conf *n; + while(interface_confs) { + struct interface_conf *if_conf; void *vrc; - n = network_confs; - network_confs = network_confs->next; - n->next = NULL; - vrc = add_network(n->ifname, n); + if_conf = interface_confs; + interface_confs = interface_confs->next; + if_conf->next = NULL; + vrc = add_interface(if_conf->ifname, if_conf); if(vrc == NULL) { - fprintf(stderr, "Couldn't add interface %s.\n", n->ifname); + fprintf(stderr, "Couldn't add interface %s.\n", if_conf->ifname); return -1; } } diff -Nru babeld-1.2.1/debian/changelog babeld-1.3.0/debian/changelog --- babeld-1.2.1/debian/changelog 2011-11-23 06:49:31.000000000 +0000 +++ babeld-1.3.0/debian/changelog 2011-12-08 19:49:12.000000000 +0000 @@ -1,3 +1,9 @@ +babeld (1.3.0-1) unstable; urgency=low + + * New upstream release + + -- Stéphane Glondu Thu, 08 Dec 2011 20:49:12 +0100 + babeld (1.2.1-1) unstable; urgency=low * New upstream release diff -Nru babeld-1.2.1/interface.c babeld-1.3.0/interface.c --- babeld-1.2.1/interface.c 1970-01-01 00:00:00.000000000 +0000 +++ babeld-1.3.0/interface.c 2011-12-08 18:46:00.000000000 +0000 @@ -0,0 +1,465 @@ +/* +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 +#include +#include + +#include "babeld.h" +#include "util.h" +#include "kernel.h" +#include "interface.h" +#include "neighbour.h" +#include "message.h" +#include "route.h" +#include "configuration.h" + +struct interface *interfaces = NULL; + +static struct interface * +last_interface(void) +{ + struct interface *ifp = interfaces; + + if(!ifp) + return NULL; + + while(ifp->next) + ifp = ifp->next; + + return ifp; +} + +struct interface * +add_interface(char *ifname, struct interface_conf *if_conf) +{ + struct interface *ifp; + + assert(!if_conf || strcmp(ifname, if_conf->ifname) == 0); + + FOR_ALL_INTERFACES(ifp) { + if(strcmp(ifp->name, ifname) == 0) { + assert(if_conf == NULL); + return ifp; + } + } + + ifp = malloc(sizeof(struct interface)); + if(ifp == NULL) + return NULL; + + memset(ifp, 0, sizeof(struct interface)); + strncpy(ifp->name, ifname, IF_NAMESIZE); + ifp->conf = if_conf; + ifp->activity_time = now.tv_sec; + ifp->bucket_time = now.tv_sec; + ifp->bucket = BUCKET_TOKENS_MAX; + ifp->hello_seqno = (random() & 0xFFFF); + + if(interfaces == NULL) + interfaces = ifp; + else + last_interface()->next = ifp; + + return ifp; +} + +int +interface_idle(struct interface *ifp) +{ + return (idle_hello_interval > 0 && + ifp->activity_time < now.tv_sec - idle_time); +} + +int +update_hello_interval(struct interface *ifp) +{ + int rc = 0; + unsigned short interval; + + if(interface_idle(ifp)) + interval = idle_hello_interval; + else if(IF_CONF(ifp, hello_interval) > 0) + interval = IF_CONF(ifp, hello_interval); + else if((ifp->flags & IF_WIRED)) + interval = wired_hello_interval; + else + interval = wireless_hello_interval; + + if(ifp->hello_interval != interval) { + ifp->hello_interval = interval; + rc = 1; + } + + return rc; +} + +/* This should be no more than half the hello interval, so that hellos + aren't sent late. The result is in milliseconds. */ +unsigned +jitter(struct interface *ifp, int urgent) +{ + unsigned interval = ifp->hello_interval; + if(urgent) + interval = MIN(interval, 100); + else + interval = MIN(interval, 4000); + return roughly(interval) / 4; +} + +unsigned +update_jitter(struct interface *ifp, int urgent) +{ + unsigned interval = ifp->hello_interval; + if(urgent) + interval = MIN(interval, 100); + else + interval = MIN(interval, 4000); + return roughly(interval); +} + +void +set_timeout(struct timeval *timeout, int msecs) +{ + timeval_add_msec(timeout, &now, roughly(msecs)); +} + +static int +check_interface_ipv4(struct interface *ifp) +{ + unsigned char ipv4[4]; + int rc; + + if(ifp->ifindex > 0) + rc = kernel_interface_ipv4(ifp->name, ifp->ifindex, ipv4); + else + rc = 0; + + if(rc > 0) { + if(!ifp->ipv4 || memcmp(ipv4, ifp->ipv4, 4) != 0) { + debugf("Noticed IPv4 change for %s.\n", ifp->name); + flush_interface_routes(ifp, 0); + if(!ifp->ipv4) + ifp->ipv4 = malloc(4); + if(ifp->ipv4) + memcpy(ifp->ipv4, ipv4, 4); + return 1; + } + } else { + if(ifp->ipv4) { + debugf("Noticed IPv4 change for %s.\n", ifp->name); + flush_interface_routes(ifp, 0); + free(ifp->ipv4); + ifp->ipv4 = NULL; + return 1; + } + } + return 0; +} + +int +check_interface_channel(struct interface *ifp) +{ + int channel = IF_CONF(ifp, channel); + + if(channel == IF_CHANNEL_UNKNOWN) { + if((ifp->flags & IF_WIRED)) { + channel = IF_CHANNEL_NONINTERFERING; + } else { + channel = kernel_interface_channel(ifp->name, ifp->ifindex); + if(channel < 0) + fprintf(stderr, + "Couldn't determine channel of interface %s: %s.\n", + ifp->name, strerror(errno)); + if(channel <= 0) + channel = IF_CHANNEL_INTERFERING; + } + } + + if(ifp->channel != channel) { + ifp->channel = channel; + return 1; + } + return 0; +} + +int +interface_up(struct interface *ifp, int up) +{ + int mtu, rc, wired; + struct ipv6_mreq mreq; + + if((!!up) == if_up(ifp)) + return 0; + + if(up) + ifp->flags |= IF_UP; + else + ifp->flags &= ~IF_UP; + + if(up) { + struct kernel_route ll[32]; + if(ifp->ifindex <= 0) { + fprintf(stderr, + "Upping unknown interface %s.\n", ifp->name); + return interface_up(ifp, 0); + } + + rc = kernel_setup_interface(1, ifp->name, ifp->ifindex); + if(rc < 0) { + fprintf(stderr, "kernel_setup_interface(%s, %d) failed.\n", + ifp->name, ifp->ifindex); + return interface_up(ifp, 0); + } + + mtu = kernel_interface_mtu(ifp->name, ifp->ifindex); + if(mtu < 0) { + fprintf(stderr, "Warning: couldn't get MTU of interface %s (%d).\n", + ifp->name, ifp->ifindex); + mtu = 1280; + } + + /* We need to be able to fit at least two messages into a packet, + so MTUs below 116 require lower layer fragmentation. */ + /* In IPv6, the minimum MTU is 1280, and every host must be able + to reassemble up to 1500 bytes, but I'd rather not rely on this. */ + if(mtu < 128) { + fprintf(stderr, "Suspiciously low MTU %d on interface %s (%d).\n", + mtu, ifp->name, ifp->ifindex); + mtu = 128; + } + + if(ifp->sendbuf) + free(ifp->sendbuf); + + /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */ + ifp->bufsize = mtu - sizeof(packet_header) - 60; + ifp->sendbuf = malloc(ifp->bufsize); + if(ifp->sendbuf == NULL) { + fprintf(stderr, "Couldn't allocate sendbuf.\n"); + ifp->bufsize = 0; + return interface_up(ifp, 0); + } + + resize_receive_buffer(mtu); + + if(IF_CONF(ifp, wired) == CONFIG_NO) { + wired = 0; + } else if(IF_CONF(ifp, wired) == CONFIG_YES) { + wired = 1; + } else if(all_wireless) { + wired = 0; + } else { + rc = kernel_interface_wireless(ifp->name, ifp->ifindex); + if(rc < 0) { + fprintf(stderr, + "Warning: couldn't determine whether %s (%d) " + "is a wireless interface.\n", + ifp->name, ifp->ifindex); + wired = 0; + } else { + wired = !rc; + } + } + + if(wired) { + ifp->flags |= IF_WIRED; + ifp->cost = IF_CONF(ifp, cost); + if(ifp->cost <= 0) ifp->cost = 96; + if(IF_CONF(ifp, split_horizon) == CONFIG_NO) + ifp->flags &= ~IF_SPLIT_HORIZON; + else if(IF_CONF(ifp, split_horizon) == CONFIG_YES) + ifp->flags |= IF_SPLIT_HORIZON; + else if(split_horizon) + ifp->flags |= IF_SPLIT_HORIZON; + else + ifp->flags &= ~IF_SPLIT_HORIZON; + if(IF_CONF(ifp, lq) == CONFIG_YES) + ifp->flags |= IF_LQ; + else + ifp->flags &= ~IF_LQ; + } else { + ifp->flags &= ~IF_WIRED; + ifp->cost = IF_CONF(ifp, cost); + if(ifp->cost <= 0) ifp->cost = 256; + if(IF_CONF(ifp, split_horizon) == CONFIG_YES) + ifp->flags |= IF_SPLIT_HORIZON; + else + ifp->flags &= ~IF_SPLIT_HORIZON; + if(IF_CONF(ifp, lq) == CONFIG_NO) + ifp->flags &= ~IF_LQ; + else + ifp->flags |= IF_LQ; + } + + if(IF_CONF(ifp, faraway) == CONFIG_YES) + ifp->flags |= IF_FARAWAY; + + ifp->activity_time = now.tv_sec; + update_hello_interval(ifp); + /* Since the interface was marked as active above, the + idle_hello_interval cannot be the one being used here. */ + ifp->update_interval = + IF_CONF(ifp, update_interval) > 0 ? + IF_CONF(ifp, update_interval) : + ifp->hello_interval * 4; + + memset(&mreq, 0, sizeof(mreq)); + memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); + mreq.ipv6mr_interface = ifp->ifindex; + + rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, + (char*)&mreq, sizeof(mreq)); + if(rc < 0) { + perror("setsockopt(IPV6_JOIN_GROUP)"); + /* This is probably due to a missing link-local address, + so down this interface, and wait until the main loop + tries to up it again. */ + return interface_up(ifp, 0); + } + + if(ifp->ll) + free(ifp->ll); + ifp->numll = 0; + ifp->ll = NULL; + rc = kernel_addresses(ifp->name, ifp->ifindex, 1, ll, 32); + if(rc < 0) { + perror("kernel_ll_addresses"); + } else if(rc > 0) { + ifp->ll = malloc(16 * rc); + if(ifp->ll == NULL) { + perror("malloc(ll)"); + } else { + int i; + for(i = 0; i < rc; i++) + memcpy(ifp->ll[i], ll[i].prefix, 16); + ifp->numll = rc; + } + } + check_interface_channel(ifp); + update_interface_metric(ifp); + rc = check_interface_ipv4(ifp); + + debugf("Upped interface %s (%s, cost=%d, channel=%d%s).\n", + ifp->name, + (ifp->flags & IF_WIRED) ? "wired" : "wireless", + ifp->cost, + ifp->channel, + ifp->ipv4 ? ", IPv4" : ""); + + set_timeout(&ifp->hello_timeout, ifp->hello_interval); + set_timeout(&ifp->update_timeout, ifp->update_interval); + send_hello(ifp); + if(rc > 0) + send_update(ifp, 0, NULL, 0); + send_request(ifp, NULL, 0); + } else { + flush_interface_routes(ifp, 0); + ifp->buffered = 0; + ifp->bufsize = 0; + free(ifp->sendbuf); + ifp->num_buffered_updates = 0; + ifp->update_bufsize = 0; + if(ifp->buffered_updates) + free(ifp->buffered_updates); + ifp->buffered_updates = NULL; + ifp->sendbuf = NULL; + if(ifp->ifindex > 0) { + memset(&mreq, 0, sizeof(mreq)); + memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); + mreq.ipv6mr_interface = ifp->ifindex; + rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + (char*)&mreq, sizeof(mreq)); + if(rc < 0) + perror("setsockopt(IPV6_LEAVE_GROUP)"); + kernel_setup_interface(0, ifp->name, ifp->ifindex); + } + if(ifp->ll) + free(ifp->ll); + ifp->ll = NULL; + ifp->numll = 0; + } + + return 1; +} + +int +interface_ll_address(struct interface *ifp, const unsigned char *address) +{ + int i; + + if(!if_up(ifp)) + return 0; + + for(i = 0; i < ifp->numll; i++) + if(memcmp(ifp->ll[i], address, 16) == 0) + return 1; + + return 0; +} + +void +check_interfaces(void) +{ + struct interface *ifp; + int rc, ifindex, ifindex_changed = 0; + + FOR_ALL_INTERFACES(ifp) { + ifindex = if_nametoindex(ifp->name); + if(ifindex != ifp->ifindex) { + debugf("Noticed ifindex change for %s.\n", ifp->name); + ifp->ifindex = 0; + interface_up(ifp, 0); + ifp->ifindex = ifindex; + ifindex_changed = 1; + } + + if(ifp->ifindex > 0) + rc = kernel_interface_operational(ifp->name, ifp->ifindex); + else + rc = 0; + if((rc > 0) != if_up(ifp)) { + debugf("Noticed status change for %s.\n", ifp->name); + interface_up(ifp, rc > 0); + } + + if(if_up(ifp)) { + check_interface_channel(ifp); + rc = check_interface_ipv4(ifp); + if(rc > 0) { + send_request(ifp, NULL, 0); + send_update(ifp, 0, NULL, 0); + } + } + } + + if(ifindex_changed) + renumber_filters(); +} diff -Nru babeld-1.2.1/interface.h babeld-1.3.0/interface.h --- babeld-1.2.1/interface.h 1970-01-01 00:00:00.000000000 +0000 +++ babeld-1.3.0/interface.h 2011-12-08 18:46:00.000000000 +0000 @@ -0,0 +1,116 @@ +/* +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. +*/ + +struct buffered_update { + unsigned char id[8]; + unsigned char prefix[16]; + unsigned char plen; + unsigned char pad[3]; +}; + +struct interface_conf { + char *ifname; + unsigned hello_interval; + unsigned update_interval; + unsigned short cost; + char wired; + char split_horizon; + char lq; + char faraway; + int channel; + struct interface_conf *next; +}; + +#define CONFIG_DEFAULT 0 +#define CONFIG_NO 1 +#define CONFIG_YES 2 + +#define IF_UP (1 << 0) +#define IF_WIRED (1<<1) +#define IF_SPLIT_HORIZON (1 << 2) +#define IF_LQ (1 << 3) +#define IF_FARAWAY (1 << 4) + +/* Only INTERFERING can appear on the wire. */ +#define IF_CHANNEL_UNKNOWN 0 +#define IF_CHANNEL_INTERFERING 255 +#define IF_CHANNEL_NONINTERFERING -2 + +struct interface { + struct interface *next; + struct interface_conf *conf; + unsigned int ifindex; + unsigned short flags; + unsigned short cost; + int channel; + struct timeval hello_timeout; + struct timeval update_timeout; + struct timeval flush_timeout; + struct timeval update_flush_timeout; + char name[IF_NAMESIZE]; + unsigned char *ipv4; + int numll; + unsigned char (*ll)[16]; + int buffered; + int bufsize; + char have_buffered_hello; + char have_buffered_id; + char have_buffered_nh; + char have_buffered_prefix; + unsigned char buffered_id[16]; + unsigned char buffered_nh[4]; + unsigned char buffered_prefix[16]; + unsigned char *sendbuf; + struct buffered_update *buffered_updates; + int num_buffered_updates; + int update_bufsize; + time_t bucket_time; + unsigned int bucket; + time_t activity_time; + time_t last_update_time; + unsigned short hello_seqno; + unsigned hello_interval; + unsigned update_interval; +}; + +#define IF_CONF(_ifp, _field) \ + ((_ifp)->conf ? (_ifp)->conf->_field : 0) + +extern struct interface *interfaces; + +#define FOR_ALL_INTERFACES(_ifp) for(_ifp = interfaces; _ifp; _ifp = _ifp->next) + +static inline int +if_up(struct interface *ifp) +{ + return !!(ifp->flags & IF_UP); +} + +struct interface *add_interface(char *ifname, struct interface_conf *if_conf); +int interface_idle(struct interface *ifp); +int update_hello_interval(struct interface *ifp); +unsigned jitter(struct interface *ifp, int urgent); +unsigned update_jitter(struct interface *ifp, int urgent); +void set_timeout(struct timeval *timeout, int msecs); +int interface_up(struct interface *ifp, int up); +int interface_ll_address(struct interface *ifp, const unsigned char *address); +void check_interfaces(void); diff -Nru babeld-1.2.1/kernel_netlink.c babeld-1.3.0/kernel_netlink.c --- babeld-1.2.1/kernel_netlink.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/kernel_netlink.c 2011-12-08 18:46:00.000000000 +0000 @@ -49,7 +49,7 @@ #include "babeld.h" #include "kernel.h" #include "util.h" -#include "network.h" +#include "interface.h" int export_table = -1, import_table = -1; @@ -1239,7 +1239,7 @@ int ifindex; char *ifname; unsigned int ifflags; - struct network *net; + struct interface *ifp; len = nh->nlmsg_len; @@ -1257,8 +1257,8 @@ return 0; kdebugf("filter_interfaces: link change on if %s(%d): 0x%x\n", ifname, ifindex, (unsigned)ifflags); - FOR_ALL_NETS(net) { - if (strcmp(net->ifname, ifname) == 0) + FOR_ALL_INTERFACES(ifp) { + if (strcmp(ifp->name, ifname) == 0) return 1; } return 0; diff -Nru babeld-1.2.1/local.c babeld-1.3.0/local.c --- babeld-1.2.1/local.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/local.c 2011-12-08 18:46:00.000000000 +0000 @@ -27,7 +27,7 @@ #include #include "babeld.h" -#include "network.h" +#include "interface.h" #include "source.h" #include "neighbour.h" #include "xroute.h" @@ -140,7 +140,7 @@ address as a unique identifier. */ (unsigned long int)neigh, format_address(neigh->address), - neigh->network->ifname, + neigh->ifp->name, neigh->reach, neighbour_rxcost(neigh), neighbour_txcost(neigh), @@ -207,7 +207,7 @@ format_eui64(route->src->id), route_metric(route), route->refmetric, format_address(route->neigh->address), - route->neigh->network->ifname); + route->neigh->ifp->name); if(rc < 0 || rc >= 512) goto fail; @@ -222,10 +222,22 @@ return; } +static void +local_notify_xroute_callback(struct xroute *xroute, void *closure) +{ + local_notify_xroute(xroute, LOCAL_ADD); +} + +static void +local_notify_route_callback(struct route *route, void *closure) +{ + local_notify_route(route, LOCAL_ADD); +} + void -local_dump() +local_notify_all() { - int i, rc; + int rc; struct neighbour *neigh; const char *header = "BABEL 0.0\n"; @@ -240,10 +252,8 @@ FOR_ALL_NEIGHBOURS(neigh) { local_notify_neighbour(neigh, LOCAL_ADD); } - for(i = 0; i < numxroutes; i++) - local_notify_xroute(&xroutes[i], LOCAL_ADD); - for(i = 0; i < numroutes; i++) - local_notify_route(&routes[i], LOCAL_ADD); + for_all_xroutes(local_notify_xroute_callback, NULL); + for_all_routes(local_notify_route_callback, NULL); return; fail: diff -Nru babeld-1.2.1/local.h babeld-1.3.0/local.h --- babeld-1.2.1/local.h 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/local.h 2011-12-08 18:46:00.000000000 +0000 @@ -35,7 +35,7 @@ void local_notify_neighbour(struct neighbour *neigh, int kind); void local_notify_xroute(struct xroute *xroute, int kind); void local_notify_route(struct route *route, int kind); -void local_dump(void); +void local_notify_all(void); #else diff -Nru babeld-1.2.1/Makefile babeld-1.3.0/Makefile --- babeld-1.2.1/Makefile 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/Makefile 2011-12-08 18:46:00.000000000 +0000 @@ -8,10 +8,10 @@ LDLIBS = -lrt -SRCS = babeld.c net.c kernel.c util.c network.c source.c neighbour.c \ +SRCS = babeld.c net.c kernel.c util.c interface.c source.c neighbour.c \ route.c xroute.c message.c resend.c configuration.c local.c -OBJS = babeld.o net.o kernel.o util.o network.o source.o neighbour.o \ +OBJS = babeld.o net.o kernel.o util.o interface.o source.o neighbour.o \ route.o xroute.o message.o resend.o configuration.o local.o babeld: $(OBJS) diff -Nru babeld-1.2.1/message.c babeld-1.3.0/message.c --- babeld-1.2.1/message.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/message.c 2011-12-08 18:46:00.000000000 +0000 @@ -31,7 +31,7 @@ #include "babeld.h" #include "util.h" #include "net.h" -#include "network.h" +#include "interface.h" #include "source.h" #include "neighbour.h" #include "route.h" @@ -182,7 +182,7 @@ } void -parse_packet(const unsigned char *from, struct network *net, +parse_packet(const unsigned char *from, struct interface *ifp, const unsigned char *packet, int packetlen) { int i; @@ -203,18 +203,18 @@ if(packet[0] != 42) { fprintf(stderr, "Received malformed packet on %s from %s.\n", - net->ifname, format_address(from)); + 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], net->ifname, format_address(from)); + packet[1], ifp->name, format_address(from)); return; } - neigh = find_neighbour(from, net); + neigh = find_neighbour(from, ifp); if(neigh == NULL) { fprintf(stderr, "Couldn't allocate neighbour.\n"); return; @@ -234,7 +234,7 @@ type = message[0]; if(type == MESSAGE_PAD1) { debugf("Received pad1 from %s on %s.\n", - format_address(from), net->ifname); + format_address(from), ifp->name); i++; continue; } @@ -250,18 +250,18 @@ if(type == MESSAGE_PADN) { debugf("Received pad%d from %s on %s.\n", - len, format_address(from), net->ifname); + 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("Received ack-req (%04X %d) from %s on %s.\n", - nonce, interval, format_address(from), net->ifname); + nonce, interval, format_address(from), ifp->name); send_ack(neigh, nonce, interval); } else if(type == MESSAGE_ACK) { debugf("Received ack from %s on %s.\n", - format_address(from), net->ifname); + format_address(from), ifp->name); /* Nothing right now */ } else if(type == MESSAGE_HELLO) { unsigned short seqno, interval; @@ -271,9 +271,9 @@ DO_NTOHS(interval, message + 6); debugf("Received hello %d (%d) from %s on %s.\n", seqno, interval, - format_address(from), net->ifname); - net->activity_time = now.tv_sec; - update_hello_interval(net); + format_address(from), ifp->name); + ifp->activity_time = now.tv_sec; + update_hello_interval(ifp); changed = update_neighbour(neigh, seqno, interval); update_neighbour_metric(neigh, changed); if(interval > 0) @@ -289,9 +289,9 @@ if(rc < 0) goto fail; debugf("Received ihu %d (%d) from %s on %s for %s.\n", txcost, interval, - format_address(from), net->ifname, + format_address(from), ifp->name, format_address(address)); - if(message[2] == 0 || network_ll_address(net, address)) { + if(message[2] == 0 || interface_ll_address(ifp, address)) { int changed = txcost != neigh->txcost; neigh->txcost = txcost; neigh->ihu_time = now; @@ -308,7 +308,7 @@ memcpy(router_id, message + 4, 8); have_router_id = 1; debugf("Received router-id %s from %s on %s.\n", - format_eui64(router_id), format_address(from), net->ifname); + format_eui64(router_id), format_address(from), ifp->name); } else if(type == MESSAGE_NH) { unsigned char nh[16]; int rc; @@ -326,7 +326,7 @@ } debugf("Received nh %s (%d) from %s on %s.\n", format_address(nh), message[2], - format_address(from), net->ifname); + format_address(from), ifp->name); if(message[2] == 1) { memcpy(v4_nh, nh, 16); have_v4_nh = 1; @@ -391,7 +391,7 @@ (message[3] & 0x80) ? "/prefix" : "", (message[3] & 0x40) ? "/id" : "", format_prefix(prefix, plen), - format_address(from), net->ifname); + format_address(from), ifp->name); if(message[2] == 0) { if(metric < 0xFFFF) { @@ -412,11 +412,11 @@ } if(message[2] == 1) { - if(!net->ipv4) + if(!ifp->ipv4) goto done; } - if((net->flags & NET_FARAWAY)) { + if((ifp->flags & IF_FARAWAY)) { channels[0] = 0; } else { /* This will be overwritten by parse_route_attributes below. */ @@ -425,7 +425,7 @@ channels[0] = 0; } else { /* Assume interfering. */ - channels[0] = NET_CHANNEL_INTERFERING; + channels[0] = IF_CHANNEL_INTERFERING; channels[1] = 0; } @@ -447,14 +447,20 @@ plen = message[3] + (message[2] == 1 ? 96 : 0); debugf("Received request for %s from %s on %s.\n", message[2] == 0 ? "any" : format_prefix(prefix, plen), - format_address(from), net->ifname); + 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->network, 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(neigh->ifp->last_update_time < + now.tv_sec - MAX(neigh->ifp->hello_interval / 100, 1)) + send_update(neigh->ifp, 0, NULL, 0); } else { - send_update(neigh->network, 0, prefix, plen); + send_update(neigh->ifp, 0, prefix, plen); } } else if(type == MESSAGE_MH_REQUEST) { unsigned char prefix[16], plen; @@ -469,13 +475,13 @@ debugf("Received request (%d) for %s from %s on %s (%s, %d).\n", message[6], format_prefix(prefix, plen), - format_address(from), net->ifname, + format_address(from), ifp->name, format_eui64(message + 8), seqno); handle_request(neigh, prefix, plen, message[6], seqno, message + 8); } else { debugf("Received unknown packet type %d from %s on %s.\n", - type, format_address(from), net->ifname); + type, format_address(from), ifp->name); } done: i += len + 2; @@ -483,7 +489,7 @@ fail: fprintf(stderr, "Couldn't parse packet (%d, %d) from %s on %s.\n", - message[0], message[1], format_address(from), net->ifname); + message[0], message[1], format_address(from), ifp->name); goto done; } return; @@ -494,20 +500,20 @@ should never trigger. But I'm superstitious. */ static int -check_bucket(struct network *net) +check_bucket(struct interface *ifp) { - if(net->bucket <= 0) { - int seconds = now.tv_sec - net->bucket_time; + if(ifp->bucket <= 0) { + int seconds = now.tv_sec - ifp->bucket_time; if(seconds > 0) { - net->bucket = MIN(BUCKET_TOKENS_MAX, + ifp->bucket = MIN(BUCKET_TOKENS_MAX, seconds * BUCKET_TOKENS_PER_SEC); } /* Reset bucket time unconditionally, in case clock is stepped. */ - net->bucket_time = now.tv_sec; + ifp->bucket_time = now.tv_sec; } - if(net->bucket > 0) { - net->bucket--; + if(ifp->bucket > 0) { + ifp->bucket--; return 1; } else { return 0; @@ -515,65 +521,65 @@ } void -flushbuf(struct network *net) +flushbuf(struct interface *ifp) { int rc; struct sockaddr_in6 sin6; - assert(net->buffered <= net->bufsize); + assert(ifp->buffered <= ifp->bufsize); - flushupdates(net); + flushupdates(ifp); - if(net->buffered > 0) { + if(ifp->buffered > 0) { debugf(" (flushing %d buffered bytes on %s)\n", - net->buffered, net->ifname); - if(check_bucket(net)) { + 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 = net->ifindex; - DO_HTONS(packet_header + 2, net->buffered); + sin6.sin6_scope_id = ifp->ifindex; + DO_HTONS(packet_header + 2, ifp->buffered); rc = babel_send(protocol_socket, packet_header, sizeof(packet_header), - net->sendbuf, net->buffered, + ifp->sendbuf, ifp->buffered, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) perror("send"); } else { fprintf(stderr, "Warning: bucket full, dropping packet to %s.\n", - net->ifname); + ifp->name); } } - VALGRIND_MAKE_MEM_UNDEFINED(net->sendbuf, net->bufsize); - net->buffered = 0; - net->have_buffered_hello = 0; - net->have_buffered_id = 0; - net->have_buffered_nh = 0; - net->have_buffered_prefix = 0; - net->flush_timeout.tv_sec = 0; - net->flush_timeout.tv_usec = 0; + VALGRIND_MAKE_MEM_UNDEFINED(ifp->sendbuf, ifp->bufsize); + ifp->buffered = 0; + ifp->have_buffered_hello = 0; + ifp->have_buffered_id = 0; + ifp->have_buffered_nh = 0; + ifp->have_buffered_prefix = 0; + ifp->flush_timeout.tv_sec = 0; + ifp->flush_timeout.tv_usec = 0; } static void -schedule_flush(struct network *net) +schedule_flush(struct interface *ifp) { - unsigned msecs = jitter(net, 0); - if(net->flush_timeout.tv_sec != 0 && - timeval_minus_msec(&net->flush_timeout, &now) < msecs) + unsigned msecs = jitter(ifp, 0); + if(ifp->flush_timeout.tv_sec != 0 && + timeval_minus_msec(&ifp->flush_timeout, &now) < msecs) return; - set_timeout(&net->flush_timeout, msecs); + set_timeout(&ifp->flush_timeout, msecs); } static void -schedule_flush_now(struct network *net) +schedule_flush_now(struct interface *ifp) { /* Almost now */ unsigned msecs = roughly(10); - if(net->flush_timeout.tv_sec != 0 && - timeval_minus_msec(&net->flush_timeout, &now) < msecs) + if(ifp->flush_timeout.tv_sec != 0 && + timeval_minus_msec(&ifp->flush_timeout, &now) < msecs) return; - set_timeout(&net->flush_timeout, msecs); + set_timeout(&ifp->flush_timeout, msecs); } static void @@ -590,49 +596,49 @@ } static void -ensure_space(struct network *net, int space) +ensure_space(struct interface *ifp, int space) { - if(net->bufsize - net->buffered < space) - flushbuf(net); + if(ifp->bufsize - ifp->buffered < space) + flushbuf(ifp); } static void -start_message(struct network *net, int type, int len) +start_message(struct interface *ifp, int type, int len) { - if(net->bufsize - net->buffered < len + 2) - flushbuf(net); - net->sendbuf[net->buffered++] = type; - net->sendbuf[net->buffered++] = len; + if(ifp->bufsize - ifp->buffered < len + 2) + flushbuf(ifp); + ifp->sendbuf[ifp->buffered++] = type; + ifp->sendbuf[ifp->buffered++] = len; } static void -end_message(struct network *net, int type, int bytes) +end_message(struct interface *ifp, int type, int bytes) { - assert(net->buffered >= bytes + 2 && - net->sendbuf[net->buffered - bytes - 2] == type && - net->sendbuf[net->buffered - bytes - 1] == bytes); - schedule_flush(net); + assert(ifp->buffered >= bytes + 2 && + ifp->sendbuf[ifp->buffered - bytes - 2] == type && + ifp->sendbuf[ifp->buffered - bytes - 1] == bytes); + schedule_flush(ifp); } static void -accumulate_byte(struct network *net, unsigned char value) +accumulate_byte(struct interface *ifp, unsigned char value) { - net->sendbuf[net->buffered++] = value; + ifp->sendbuf[ifp->buffered++] = value; } static void -accumulate_short(struct network *net, unsigned short value) +accumulate_short(struct interface *ifp, unsigned short value) { - DO_HTONS(net->sendbuf + net->buffered, value); - net->buffered += 2; + DO_HTONS(ifp->sendbuf + ifp->buffered, value); + ifp->buffered += 2; } static void -accumulate_bytes(struct network *net, +accumulate_bytes(struct interface *ifp, const unsigned char *value, unsigned len) { - memcpy(net->sendbuf + net->buffered, value, len); - net->buffered += len; + memcpy(ifp->sendbuf + ifp->buffered, value, len); + ifp->buffered += len; } static int @@ -641,7 +647,7 @@ if(unicast_neighbour) { if(neigh != unicast_neighbour || unicast_buffered + len + 2 >= - MIN(UNICAST_BUFSIZE, neigh->network->bufsize)) + MIN(UNICAST_BUFSIZE, neigh->ifp->bufsize)) flush_unicast(0); } if(!unicast_buffer) @@ -664,7 +670,7 @@ 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->network, 0)); + schedule_unicast_flush(jitter(neigh->ifp, 0)); } static void @@ -693,7 +699,7 @@ { int rc; debugf("Sending ack (%04x) to %s on %s.\n", - nonce, format_address(neigh->address), neigh->network->ifname); + 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); @@ -702,41 +708,41 @@ } void -send_hello_noupdate(struct network *net, unsigned interval) +send_hello_noupdate(struct interface *ifp, unsigned interval) { /* This avoids sending multiple hellos in a single packet, which breaks link quality estimation. */ - if(net->have_buffered_hello) - flushbuf(net); + if(ifp->have_buffered_hello) + flushbuf(ifp); - net->hello_seqno = seqno_plus(net->hello_seqno, 1); - set_timeout(&net->hello_timeout, net->hello_interval); + ifp->hello_seqno = seqno_plus(ifp->hello_seqno, 1); + set_timeout(&ifp->hello_timeout, ifp->hello_interval); - if(!net_up(net)) + if(!if_up(ifp)) return; debugf("Sending hello %d (%d) to %s.\n", - net->hello_seqno, interval, net->ifname); + ifp->hello_seqno, interval, ifp->name); - start_message(net, MESSAGE_HELLO, 6); - accumulate_short(net, 0); - accumulate_short(net, net->hello_seqno); - accumulate_short(net, interval > 0xFFFF ? 0xFFFF : interval); - end_message(net, MESSAGE_HELLO, 6); - net->have_buffered_hello = 1; + start_message(ifp, MESSAGE_HELLO, 6); + accumulate_short(ifp, 0); + accumulate_short(ifp, ifp->hello_seqno); + accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval); + end_message(ifp, MESSAGE_HELLO, 6); + ifp->have_buffered_hello = 1; } void -send_hello(struct network *net) +send_hello(struct interface *ifp) { int changed; - changed = update_hello_interval(net); - send_hello_noupdate(net, (net->hello_interval + 9) / 10); + changed = update_hello_interval(ifp); + send_hello_noupdate(ifp, (ifp->hello_interval + 9) / 10); /* Send full IHU every 3 hellos, and marginal IHU each time */ - if(changed || net->hello_seqno % 3 == 0) - send_ihu(NULL, net); + if(changed || ifp->hello_seqno % 3 == 0) + send_ihu(NULL, ifp); else - send_marginal_ihu(net); + send_marginal_ihu(ifp); } void @@ -748,18 +754,18 @@ if(unicast_buffered == 0) goto done; - if(!net_up(unicast_neighbour->network)) + if(!if_up(unicast_neighbour->ifp)) goto done; /* Preserve ordering of messages */ - flushbuf(unicast_neighbour->network); + flushbuf(unicast_neighbour->ifp); - if(check_bucket(unicast_neighbour->network)) { + 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->network->ifindex; + 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), @@ -772,7 +778,7 @@ "Warning: bucket full, dropping unicast packet" "to %s if %s.\n", format_address(unicast_neighbour->address), - unicast_neighbour->network->ifname); + unicast_neighbour->ifp->name); } done: @@ -788,7 +794,7 @@ } static void -really_send_update(struct network *net, +really_send_update(struct interface *ifp, const unsigned char *id, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned short metric, @@ -804,82 +810,82 @@ channels_size = channels_len >= 0 ? channels_len + 2 : 0; - if(!net_up(net)) + if(!if_up(ifp)) return; - add_metric = output_filter(id, prefix, plen, net->ifindex); + add_metric = output_filter(id, prefix, plen, ifp->ifindex); if(add_metric >= INFINITY) return; metric = MIN(metric + add_metric, INFINITY); /* Worst case */ - ensure_space(net, 20 + 12 + 28); + ensure_space(ifp, 20 + 12 + 28); v4 = plen >= 96 && v4mapped(prefix); if(v4) { - if(!net->ipv4) + if(!ifp->ipv4) return; - if(!net->have_buffered_nh || - memcmp(net->buffered_nh, net->ipv4, 4) != 0) { - start_message(net, MESSAGE_NH, 6); - accumulate_byte(net, 1); - accumulate_byte(net, 0); - accumulate_bytes(net, net->ipv4, 4); - end_message(net, MESSAGE_NH, 6); - memcpy(net->buffered_nh, net->ipv4, 4); - net->have_buffered_nh = 1; + if(!ifp->have_buffered_nh || + memcmp(ifp->buffered_nh, ifp->ipv4, 4) != 0) { + start_message(ifp, MESSAGE_NH, 6); + accumulate_byte(ifp, 1); + accumulate_byte(ifp, 0); + accumulate_bytes(ifp, ifp->ipv4, 4); + end_message(ifp, MESSAGE_NH, 6); + memcpy(ifp->buffered_nh, ifp->ipv4, 4); + ifp->have_buffered_nh = 1; } real_prefix = prefix + 12; real_plen = plen - 96; } else { - if(net->have_buffered_prefix) { + if(ifp->have_buffered_prefix) { while(omit < plen / 8 && - net->buffered_prefix[omit] == prefix[omit]) + ifp->buffered_prefix[omit] == prefix[omit]) omit++; } - if(!net->have_buffered_prefix || plen >= 48) + if(!ifp->have_buffered_prefix || plen >= 48) flags |= 0x80; real_prefix = prefix; real_plen = plen; } - if(!net->have_buffered_id || memcmp(id, net->buffered_id, 8) != 0) { + if(!ifp->have_buffered_id || memcmp(id, ifp->buffered_id, 8) != 0) { if(real_plen == 128 && memcmp(real_prefix + 8, id, 8) == 0) { flags |= 0x40; } else { - start_message(net, MESSAGE_ROUTER_ID, 10); - accumulate_short(net, 0); - accumulate_bytes(net, id, 8); - end_message(net, MESSAGE_ROUTER_ID, 10); + start_message(ifp, MESSAGE_ROUTER_ID, 10); + accumulate_short(ifp, 0); + accumulate_bytes(ifp, id, 8); + end_message(ifp, MESSAGE_ROUTER_ID, 10); } - memcpy(net->buffered_id, id, 16); - net->have_buffered_id = 1; + memcpy(ifp->buffered_id, id, 16); + ifp->have_buffered_id = 1; } - start_message(net, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + + start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + channels_size); - accumulate_byte(net, v4 ? 1 : 2); - accumulate_byte(net, flags); - accumulate_byte(net, real_plen); - accumulate_byte(net, omit); - accumulate_short(net, (net->update_interval + 5) / 10); - accumulate_short(net, seqno); - accumulate_short(net, metric); - accumulate_bytes(net, real_prefix + omit, (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, (ifp->update_interval + 5) / 10); + accumulate_short(ifp, seqno); + accumulate_short(ifp, metric); + accumulate_bytes(ifp, real_prefix + omit, (real_plen + 7) / 8 - omit); /* Note that an empty channels TLV is different from no such TLV. */ if(channels_len >= 0) { - accumulate_byte(net, 2); - accumulate_byte(net, channels_len); - accumulate_bytes(net, channels, channels_len); + accumulate_byte(ifp, 2); + accumulate_byte(ifp, channels_len); + accumulate_bytes(ifp, channels, channels_len); } - end_message(net, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + + end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + channels_size); if(flags & 0x80) { - memcpy(net->buffered_prefix, prefix, 16); - net->have_buffered_prefix = 1; + memcpy(ifp->buffered_prefix, prefix, 16); + ifp->have_buffered_prefix = 1; } } @@ -918,7 +924,7 @@ } void -flushupdates(struct network *net) +flushupdates(struct interface *ifp) { struct xroute *xroute; struct route *route; @@ -926,26 +932,26 @@ unsigned char last_plen = 0xFF; int i; - if(net == NULL) { - struct network *n; - FOR_ALL_NETS(n) - flushupdates(n); + if(ifp == NULL) { + struct interface *ifp_aux; + FOR_ALL_INTERFACES(ifp_aux) + flushupdates(ifp_aux); return; } - if(net->num_buffered_updates > 0) { - struct buffered_update *b = net->buffered_updates; - int n = net->num_buffered_updates; + if(ifp->num_buffered_updates > 0) { + struct buffered_update *b = ifp->buffered_updates; + int n = ifp->num_buffered_updates; - net->buffered_updates = NULL; - net->update_bufsize = 0; - net->num_buffered_updates = 0; + ifp->buffered_updates = NULL; + ifp->update_bufsize = 0; + ifp->num_buffered_updates = 0; - if(!net_up(net)) + if(!if_up(ifp)) goto done; debugf(" (flushing %d buffered updates on %s (%d))\n", - n, net->ifname, net->ifindex); + 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. */ @@ -975,7 +981,7 @@ route = find_installed_route(b[i].prefix, b[i].plen); if(xroute && (!route || xroute->metric <= kernel_metric)) { - really_send_update(net, myid, + really_send_update(ifp, myid, xroute->prefix, xroute->plen, myseqno, xroute->metric, NULL, 0); @@ -984,39 +990,39 @@ } else if(route) { unsigned char channels[DIVERSITY_HOPS]; int chlen; - struct network *route_net = route->neigh->network; + struct interface *route_ifp = route->neigh->ifp; unsigned short metric; unsigned short seqno; seqno = route->seqno; metric = - route_interferes(route, net) ? + 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, net); + seqno, route->src->id, ifp); - if((net->flags & NET_SPLIT_HORIZON) && - route->neigh->network == net) + if((ifp->flags & IF_SPLIT_HORIZON) && + route->neigh->ifp == ifp) continue; - if(route_net->channel == NET_CHANNEL_NONINTERFERING) { + if(route_ifp->channel == IF_CHANNEL_NONINTERFERING) { memcpy(channels, route->channels, DIVERSITY_HOPS); } else { - if(route_net->channel == NET_CHANNEL_UNKNOWN) - channels[0] = NET_CHANNEL_INTERFERING; + if(route_ifp->channel == IF_CHANNEL_UNKNOWN) + channels[0] = IF_CHANNEL_INTERFERING; else { - assert(route_net->channel > 0 && - route_net->channel <= 255); - channels[0] = route_net->channel; + assert(route_ifp->channel > 0 && + route_ifp->channel <= 255); + channels[0] = route_ifp->channel; } memcpy(channels + 1, route->channels, DIVERSITY_HOPS - 1); } chlen = channels_len(channels); - really_send_update(net, route->src->id, + really_send_update(ifp, route->src->id, route->src->prefix, route->src->plen, seqno, metric, @@ -1027,72 +1033,82 @@ } 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(net, myid, b[i].prefix, b[i].plen, + really_send_update(ifp, myid, b[i].prefix, b[i].plen, myseqno, INFINITY, NULL, -1); } } - schedule_flush_now(net); + schedule_flush_now(ifp); done: free(b); } - net->update_flush_timeout.tv_sec = 0; - net->update_flush_timeout.tv_usec = 0; + ifp->update_flush_timeout.tv_sec = 0; + ifp->update_flush_timeout.tv_usec = 0; } static void -schedule_update_flush(struct network *net, int urgent) +schedule_update_flush(struct interface *ifp, int urgent) { unsigned msecs; - msecs = update_jitter(net, urgent); - if(net->update_flush_timeout.tv_sec != 0 && - timeval_minus_msec(&net->update_flush_timeout, &now) < msecs) + msecs = update_jitter(ifp, urgent); + if(ifp->update_flush_timeout.tv_sec != 0 && + timeval_minus_msec(&ifp->update_flush_timeout, &now) < msecs) return; - set_timeout(&net->update_flush_timeout, msecs); + set_timeout(&ifp->update_flush_timeout, msecs); } static void -buffer_update(struct network *net, +buffer_update(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { - if(net->num_buffered_updates > 0 && - net->num_buffered_updates >= net->update_bufsize) - flushupdates(net); + if(ifp->num_buffered_updates > 0 && + ifp->num_buffered_updates >= ifp->update_bufsize) + flushupdates(ifp); - if(net->update_bufsize == 0) { + if(ifp->update_bufsize == 0) { int n; - assert(net->buffered_updates == NULL); - n = MAX(net->bufsize / 16, 4); + assert(ifp->buffered_updates == NULL); + /* 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, ifp->bufsize / 16); again: - net->buffered_updates = malloc(n * sizeof(struct buffered_update)); - if(net->buffered_updates == NULL) { + ifp->buffered_updates = malloc(n * sizeof(struct buffered_update)); + if(ifp->buffered_updates == NULL) { perror("malloc(buffered_updates)"); if(n > 4) { + /* Try again with a tiny buffer. */ n = 4; goto again; } return; } - net->update_bufsize = n; - net->num_buffered_updates = 0; + ifp->update_bufsize = n; + ifp->num_buffered_updates = 0; } - memcpy(net->buffered_updates[net->num_buffered_updates].prefix, + memcpy(ifp->buffered_updates[ifp->num_buffered_updates].prefix, prefix, 16); - net->buffered_updates[net->num_buffered_updates].plen = plen; - net->num_buffered_updates++; + ifp->buffered_updates[ifp->num_buffered_updates].plen = plen; + ifp->num_buffered_updates++; } void -send_update(struct network *net, int urgent, - const unsigned char *prefix, unsigned char plen) +buffer_update_callback(struct route *route, void *closure) { - int i; + buffer_update((struct interface*)closure, + route->src->prefix, route->src->plen); +} - if(net == NULL) { - struct network *n; +void +send_update(struct interface *ifp, int urgent, + const unsigned char *prefix, unsigned char plen) +{ + if(ifp == NULL) { + struct interface *ifp_aux; struct route *route; - FOR_ALL_NETS(n) - send_update(n, urgent, prefix, plen); + FOR_ALL_INTERFACES(ifp_aux) + send_update(ifp_aux, urgent, prefix, plen); if(prefix) { /* Since flushupdates only deals with non-wildcard interfaces, we need to do this now. */ @@ -1104,41 +1120,38 @@ return; } - if(!net_up(net)) + if(!if_up(ifp)) return; if(prefix) { if(!parasitic || find_xroute(prefix, plen)) { debugf("Sending update to %s for %s.\n", - net->ifname, format_prefix(prefix, plen)); - buffer_update(net, prefix, plen); + ifp->name, format_prefix(prefix, plen)); + buffer_update(ifp, prefix, plen); } } else { - if(!network_idle(net)) { - send_self_update(net); + if(!interface_idle(ifp)) { + send_self_update(ifp); if(!parasitic) { - debugf("Sending update to %s for any.\n", net->ifname); - for(i = 0; i < numroutes; i++) - if(routes[i].installed) - buffer_update(net, - routes[i].src->prefix, - routes[i].src->plen); + debugf("Sending update to %s for any.\n", ifp->name); + for_all_installed_routes(buffer_update_callback, ifp); } } - set_timeout(&net->update_timeout, net->update_interval); + set_timeout(&ifp->update_timeout, ifp->update_interval); + ifp->last_update_time = now.tv_sec; } - schedule_update_flush(net, urgent); + schedule_update_flush(ifp, urgent); } void -send_update_resend(struct network *net, +send_update_resend(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { int delay; assert(prefix != NULL); - send_update(net, 1, prefix, plen); + send_update(ifp, 1, prefix, plen); delay = 2000; delay = MIN(delay, wireless_hello_interval / 2); @@ -1148,29 +1161,29 @@ } void -send_wildcard_retraction(struct network *net) +send_wildcard_retraction(struct interface *ifp) { - if(net == NULL) { - struct network *n; - FOR_ALL_NETS(n) - send_wildcard_retraction(n); + if(ifp == NULL) { + struct interface *ifp_aux; + FOR_ALL_INTERFACES(ifp_aux) + send_wildcard_retraction(ifp_aux); return; } - if(!net_up(net)) + if(!if_up(ifp)) return; - start_message(net, MESSAGE_UPDATE, 10); - accumulate_byte(net, 0); - accumulate_byte(net, 0x40); - accumulate_byte(net, 0); - accumulate_byte(net, 0); - accumulate_short(net, 0xFFFF); - accumulate_short(net, myseqno); - accumulate_short(net, 0xFFFF); - end_message(net, MESSAGE_UPDATE, 10); + 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); - net->have_buffered_id = 0; + ifp->have_buffered_id = 0; } void @@ -1180,40 +1193,44 @@ seqno_time = now; } -void -send_self_update(struct network *net) +static void +send_xroute_update_callback(struct xroute *xroute, void *closure) { - int i; + struct interface *ifp = (struct interface*)closure; + send_update(ifp, 0, xroute->prefix, xroute->plen); +} - if(net == NULL) { - struct network *n; - FOR_ALL_NETS(n) { - if(!net_up(n)) +void +send_self_update(struct interface *ifp) +{ + if(ifp == NULL) { + struct interface *ifp_aux; + FOR_ALL_INTERFACES(ifp_aux) { + if(!if_up(ifp_aux)) continue; - send_self_update(n); + send_self_update(ifp_aux); } return; } - if(!network_idle(net)) { - debugf("Sending self update to %s.\n", net->ifname); - for(i = 0; i < numxroutes; i++) - send_update(net, 0, xroutes[i].prefix, xroutes[i].plen); + if(!interface_idle(ifp)) { + debugf("Sending self update to %s.\n", ifp->name); + for_all_xroutes(send_xroute_update_callback, ifp); } } void -send_ihu(struct neighbour *neigh, struct network *net) +send_ihu(struct neighbour *neigh, struct interface *ifp) { int rxcost, interval; int ll; - if(neigh == NULL && net == NULL) { - struct network *n; - FOR_ALL_NETS(n) { - if(net_up(n)) + if(neigh == NULL && ifp == NULL) { + struct interface *ifp_aux; + FOR_ALL_INTERFACES(ifp_aux) { + if(if_up(ifp_aux)) continue; - send_ihu(NULL, n); + send_ihu(NULL, ifp_aux); } return; } @@ -1221,22 +1238,22 @@ if(neigh == NULL) { struct neighbour *ngh; FOR_ALL_NEIGHBOURS(ngh) { - if(ngh->network == net) - send_ihu(ngh, net); + if(ngh->ifp == ifp) + send_ihu(ngh, ifp); } return; } - if(net && neigh->network != net) + if(ifp && neigh->ifp != ifp) return; - net = neigh->network; - if(!net_up(net)) + ifp = neigh->ifp; + if(!if_up(ifp)) return; rxcost = neighbour_rxcost(neigh); - interval = (net->hello_interval * 3 + 9) / 10; + interval = (ifp->hello_interval * 3 + 9) / 10; /* Conceptually, an IHU is a unicast message. We usually send them as multicast, since this allows aggregation into a single packet and @@ -1245,22 +1262,22 @@ debugf("Sending %sihu %d on %s to %s.\n", unicast_neighbour == neigh ? "unicast " : "", rxcost, - neigh->network->ifname, + neigh->ifp->name, format_address(neigh->address)); ll = linklocal(neigh->address); if(unicast_neighbour != neigh) { - start_message(net, MESSAGE_IHU, ll ? 14 : 22); - accumulate_byte(net, ll ? 3 : 2); - accumulate_byte(net, 0); - accumulate_short(net, rxcost); - accumulate_short(net, interval); + 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(net, neigh->address + 8, 8); + accumulate_bytes(ifp, neigh->address + 8, 8); else - accumulate_bytes(net, neigh->address, 16); - end_message(net, MESSAGE_IHU, ll ? 14 : 22); + 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); @@ -1279,54 +1296,54 @@ /* Send IHUs to all marginal neighbours */ void -send_marginal_ihu(struct network *net) +send_marginal_ihu(struct interface *ifp) { struct neighbour *neigh; FOR_ALL_NEIGHBOURS(neigh) { - if(net && neigh->network != net) + if(ifp && neigh->ifp != ifp) continue; if(neigh->txcost >= 384 || (neigh->reach & 0xF000) != 0xF000) - send_ihu(neigh, net); + send_ihu(neigh, ifp); } } void -send_request(struct network *net, +send_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { int v4, len; - if(net == NULL) { - struct network *n; - FOR_ALL_NETS(n) { - if(net_up(n)) + if(ifp == NULL) { + struct interface *ifp_auxn; + FOR_ALL_INTERFACES(ifp_auxn) { + if(if_up(ifp_auxn)) continue; - send_request(n, prefix, plen); + send_request(ifp_auxn, prefix, plen); } return; } /* make sure any buffered updates go out before this request. */ - flushupdates(net); + flushupdates(ifp); - if(!net_up(net)) + if(!if_up(ifp)) return; debugf("sending request to %s for %s.\n", - net->ifname, prefix ? format_prefix(prefix, plen) : "any"); + ifp->name, prefix ? format_prefix(prefix, plen) : "any"); v4 = plen >= 96 && v4mapped(prefix); len = !prefix ? 2 : v4 ? 6 : 18; - start_message(net, MESSAGE_REQUEST, len); - accumulate_byte(net, !prefix ? 0 : v4 ? 1 : 2); - accumulate_byte(net, !prefix ? 0 : v4 ? plen - 96 : plen); + 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(net, prefix + 12, 4); + accumulate_bytes(ifp, prefix + 12, 4); else - accumulate_bytes(net, prefix, 16); + accumulate_bytes(ifp, prefix, 16); } - end_message(net, MESSAGE_REQUEST, len); + end_message(ifp, MESSAGE_REQUEST, len); } void @@ -1336,7 +1353,7 @@ int rc, v4, len; /* make sure any buffered updates go out before this request. */ - flushupdates(neigh->network); + flushupdates(neigh->ifp); debugf("sending unicast request to %s for %s.\n", format_address(neigh->address), @@ -1358,7 +1375,7 @@ } void -send_multihop_request(struct network *net, +send_multihop_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, unsigned short hop_count) @@ -1366,41 +1383,41 @@ int v4, pb, len; /* Make sure any buffered updates go out before this request. */ - flushupdates(net); + flushupdates(ifp); - if(net == NULL) { - struct network *n; - FOR_ALL_NETS(n) { - if(!net_up(n)) + if(ifp == NULL) { + struct interface *ifp_aux; + FOR_ALL_INTERFACES(ifp_aux) { + if(!if_up(ifp_aux)) continue; - send_multihop_request(n, prefix, plen, seqno, id, hop_count); + send_multihop_request(ifp_aux, prefix, plen, seqno, id, hop_count); } return; } - if(!net_up(net)) + if(!if_up(ifp)) return; debugf("Sending request (%d) on %s for %s.\n", - hop_count, net->ifname, format_prefix(prefix, plen)); + 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(net, MESSAGE_MH_REQUEST, len); - accumulate_byte(net, v4 ? 1 : 2); - accumulate_byte(net, v4 ? plen - 96 : plen); - accumulate_short(net, seqno); - accumulate_byte(net, hop_count); - accumulate_byte(net, 0); - accumulate_bytes(net, id, 8); + 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(net, prefix + 12, pb); + accumulate_bytes(ifp, prefix + 12, pb); else - accumulate_bytes(net, prefix, pb); + accumulate_bytes(ifp, prefix, pb); } - end_message(net, MESSAGE_MH_REQUEST, len); + end_message(ifp, MESSAGE_MH_REQUEST, len); } void @@ -1412,7 +1429,7 @@ int rc, v4, pb, len; /* Make sure any buffered updates go out before this request. */ - flushupdates(neigh->network); + flushupdates(neigh->ifp); debugf("Sending multi-hop request to %s for %s (%d hops).\n", format_address(neigh->address), @@ -1455,7 +1472,7 @@ delay = MIN(delay, wired_hello_interval / 2); delay = MAX(delay, 10); record_resend(RESEND_REQUEST, prefix, plen, seqno, id, - neigh ? neigh->network : NULL, delay); + neigh ? neigh->ifp : NULL, delay); } void @@ -1480,14 +1497,14 @@ update_myseqno(); } } - send_update(neigh->network, 1, prefix, plen); + 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->network, 1, prefix, plen); + send_update(neigh->ifp, 1, prefix, plen); return; } @@ -1500,7 +1517,7 @@ return; } - if(request_redundant(neigh->network, prefix, plen, seqno, id)) + if(request_redundant(neigh->ifp, prefix, plen, seqno, id)) return; /* Let's try to forward this request. */ @@ -1524,5 +1541,5 @@ send_unicast_multihop_request(successor, prefix, plen, seqno, id, hop_count - 1); record_resend(RESEND_REQUEST, prefix, plen, seqno, id, - neigh->network, 0); + neigh->ifp, 0); } diff -Nru babeld-1.2.1/message.h babeld-1.3.0/message.h --- babeld-1.2.1/message.h 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/message.h 2011-12-08 18:46:00.000000000 +0000 @@ -50,29 +50,29 @@ extern struct neighbour *unicast_neighbour; extern struct timeval unicast_flush_timeout; -void parse_packet(const unsigned char *from, struct network *net, +void parse_packet(const unsigned char *from, struct interface *ifp, const unsigned char *packet, int packetlen); -void flushbuf(struct network *net); -void flushupdates(struct network *net); +void flushbuf(struct interface *ifp); +void flushupdates(struct interface *ifp); void send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval); -void send_hello_noupdate(struct network *net, unsigned interval); -void send_hello(struct network *net); +void send_hello_noupdate(struct interface *ifp, unsigned interval); +void send_hello(struct interface *ifp); void flush_unicast(int dofree); -void send_update(struct network *net, int urgent, +void send_update(struct interface *ifp, int urgent, const unsigned char *prefix, unsigned char plen); -void send_update_resend(struct network *net, +void send_update_resend(struct interface *ifp, const unsigned char *prefix, unsigned char plen); -void send_wildcard_retraction(struct network *net); +void send_wildcard_retraction(struct interface *ifp); void update_myseqno(void); -void send_self_update(struct network *net); -void send_ihu(struct neighbour *neigh, struct network *net); -void send_marginal_ihu(struct network *net); -void send_request(struct network *net, +void send_self_update(struct interface *ifp); +void send_ihu(struct neighbour *neigh, struct interface *ifp); +void send_marginal_ihu(struct interface *ifp); +void send_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen); void send_unicast_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen); -void send_multihop_request(struct network *net, +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); diff -Nru babeld-1.2.1/neighbour.c babeld-1.3.0/neighbour.c --- babeld-1.2.1/neighbour.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/neighbour.c 2011-12-08 18:46:00.000000000 +0000 @@ -28,7 +28,7 @@ #include "babeld.h" #include "util.h" -#include "network.h" +#include "interface.h" #include "neighbour.h" #include "source.h" #include "route.h" @@ -39,12 +39,12 @@ struct neighbour *neighs = NULL; static struct neighbour * -find_neighbour_nocreate(const unsigned char *address, struct network *net) +find_neighbour_nocreate(const unsigned char *address, struct interface *ifp) { struct neighbour *neigh; FOR_ALL_NEIGHBOURS(neigh) { if(memcmp(address, neigh->address, 16) == 0 && - neigh->network == net) + neigh->ifp == ifp) return neigh; } return NULL; @@ -71,17 +71,17 @@ } struct neighbour * -find_neighbour(const unsigned char *address, struct network *net) +find_neighbour(const unsigned char *address, struct interface *ifp) { struct neighbour *neigh; const struct timeval zero = {0, 0}; - neigh = find_neighbour_nocreate(address, net); + neigh = find_neighbour_nocreate(address, ifp); if(neigh) return neigh; debugf("Creating neighbour %s on %s.\n", - format_address(address), net->ifname); + format_address(address), ifp->name); neigh = malloc(sizeof(struct neighbour)); if(neigh == NULL) { @@ -97,11 +97,11 @@ neigh->hello_time = zero; neigh->hello_interval = 0; neigh->ihu_interval = 0; - neigh->network = net; + neigh->ifp = ifp; neigh->next = neighs; neighs = neigh; local_notify_neighbour(neigh, LOCAL_ADD); - send_hello(net); + send_hello(ifp); return neigh; } @@ -174,14 +174,14 @@ /* Make sure to give neighbours some feedback early after association */ if((neigh->reach & 0xBF00) == 0x8000) { /* A new neighbour */ - send_hello(neigh->network); + send_hello(neigh->ifp); } else { /* Don't send hellos, in order to avoid a positive feedback loop. */ int a = (neigh->reach & 0xC000); int b = (neigh->reach & 0x3000); if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) { /* Reachability is either 1100 or 0011 */ - send_self_update(neigh->network); + send_self_update(neigh->ifp); } } @@ -269,25 +269,25 @@ if((reach & 0xFFF0) == 0 || delay >= 180000) { return INFINITY; - } else if((neigh->network->flags & NET_LQ)) { + } else if((neigh->ifp->flags & IF_LQ)) { int sreach = ((reach & 0x8000) >> 2) + ((reach & 0x4000) >> 1) + (reach & 0x3FFF); /* 0 <= sreach <= 0x7FFF */ - int cost = (0x8000 * neigh->network->cost) / (sreach + 1); - /* cost >= network->cost */ + int cost = (0x8000 * neigh->ifp->cost) / (sreach + 1); + /* cost >= interface->cost */ if(delay >= 40000) cost = (cost * (delay - 20000) + 10000) / 20000; return MIN(cost, INFINITY); } else { /* To lose one hello is a misfortune, to lose two is carelessness. */ if((reach & 0xC000) == 0xC000) - return neigh->network->cost; + return neigh->ifp->cost; else if((reach & 0xC000) == 0) return INFINITY; else if((reach & 0x2000)) - return neigh->network->cost; + return neigh->ifp->cost; else return INFINITY; } @@ -298,7 +298,7 @@ { unsigned a, b; - if(!net_up(neigh->network)) + if(!if_up(neigh->ifp)) return INFINITY; a = neighbour_txcost(neigh); @@ -310,7 +310,7 @@ if(b >= INFINITY) return INFINITY; - if(!(neigh->network->flags & NET_LQ) || (a <= 256 && b <= 256)) { + if(!(neigh->ifp->flags & IF_LQ) || (a < 256 && b < 256)) { return a; } else { /* a = 256/alpha, b = 256/beta, where alpha and beta are the expected diff -Nru babeld-1.2.1/neighbour.h babeld-1.3.0/neighbour.h --- babeld-1.2.1/neighbour.h 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/neighbour.h 2011-12-08 18:46:00.000000000 +0000 @@ -31,7 +31,7 @@ struct timeval ihu_time; unsigned short hello_interval; /* in centiseconds */ unsigned short ihu_interval; /* in centiseconds */ - struct network *network; + struct interface *ifp; }; extern struct neighbour *neighs; @@ -42,7 +42,7 @@ int neighbour_valid(struct neighbour *neigh); void flush_neighbour(struct neighbour *neigh); struct neighbour *find_neighbour(const unsigned char *address, - struct network *net); + struct interface *ifp); int update_neighbour(struct neighbour *neigh, int hello, int hello_interval); unsigned check_neighbours(void); unsigned neighbour_txcost(struct neighbour *neigh); diff -Nru babeld-1.2.1/net.c babeld-1.3.0/net.c --- babeld-1.2.1/net.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/net.c 2011-12-08 18:46:00.000000000 +0000 @@ -21,12 +21,14 @@ */ #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -42,6 +44,7 @@ int s, rc; int saved_errno; int one = 1, zero = 0; + const int ds = 0xc0; /* CS6 - Network Control */ s = socket(PF_INET6, SOCK_DGRAM, 0); if(s < 0) @@ -70,6 +73,15 @@ if(rc < 0) goto fail; +#ifdef IPV6_TCLASS + rc = setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds)); +#else + rc = -1; + errno = ENOSYS; +#endif + if(rc < 0) + perror("Couldn't set traffic class"); + rc = fcntl(s, F_GETFL, 0); if(rc < 0) goto fail; diff -Nru babeld-1.2.1/network.c babeld-1.3.0/network.c --- babeld-1.2.1/network.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/network.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,464 +0,0 @@ -/* -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 -#include -#include - -#include "babeld.h" -#include "util.h" -#include "kernel.h" -#include "network.h" -#include "neighbour.h" -#include "message.h" -#include "route.h" -#include "configuration.h" - -struct network *networks = NULL; - -static struct network * -last_network(void) -{ - struct network *net = networks; - - if(!net) - return NULL; - - while(net->next) - net = net->next; - - return net; -} - -struct network * -add_network(char *ifname, struct network_conf *conf) -{ - struct network *net; - - assert(!conf || strcmp(ifname, conf->ifname) == 0); - - FOR_ALL_NETS(net) { - if(strcmp(net->ifname, ifname) == 0) { - assert(conf == NULL); - return net; - } - } - - net = malloc(sizeof(struct network)); - if(net == NULL) - return NULL; - - memset(net, 0, sizeof(struct network)); - strncpy(net->ifname, ifname, IF_NAMESIZE); - net->conf = conf; - net->activity_time = now.tv_sec; - net->bucket_time = now.tv_sec; - net->bucket = BUCKET_TOKENS_MAX; - net->hello_seqno = (random() & 0xFFFF); - - if(networks == NULL) - networks = net; - else - last_network()->next = net; - - return net; -} - -int -network_idle(struct network *net) -{ - return (idle_hello_interval > 0 && - net->activity_time < now.tv_sec - idle_time); -} - -int -update_hello_interval(struct network *net) -{ - int rc = 0; - unsigned short interval; - - if(network_idle(net)) - interval = idle_hello_interval; - else if(NET_CONF(net, hello_interval) > 0) - interval = NET_CONF(net, hello_interval); - else if((net->flags & NET_WIRED)) - interval = wired_hello_interval; - else - interval = wireless_hello_interval; - - if(net->hello_interval != interval) { - net->hello_interval = interval; - rc = 1; - } - - return rc; -} - -/* This should be no more than half the hello interval, so that hellos - aren't sent late. The result is in milliseconds. */ -unsigned -jitter(struct network *net, int urgent) -{ - unsigned interval = net->hello_interval; - if(urgent) - interval = MIN(interval, 100); - else - interval = MIN(interval, 4000); - return roughly(interval) / 4; -} - -unsigned -update_jitter(struct network *net, int urgent) -{ - unsigned interval = net->hello_interval; - if(urgent) - interval = MIN(interval, 100); - else - interval = MIN(interval, 4000); - return roughly(interval); -} - -void -set_timeout(struct timeval *timeout, int msecs) -{ - timeval_add_msec(timeout, &now, roughly(msecs)); -} - -static int -check_network_ipv4(struct network *net) -{ - unsigned char ipv4[4]; - int rc; - - if(net->ifindex > 0) - rc = kernel_interface_ipv4(net->ifname, net->ifindex, ipv4); - else - rc = 0; - - if(rc > 0) { - if(!net->ipv4 || memcmp(ipv4, net->ipv4, 4) != 0) { - debugf("Noticed IPv4 change for %s.\n", net->ifname); - flush_network_routes(net, 0); - if(!net->ipv4) - net->ipv4 = malloc(4); - if(net->ipv4) - memcpy(net->ipv4, ipv4, 4); - return 1; - } - } else { - if(net->ipv4) { - debugf("Noticed IPv4 change for %s.\n", net->ifname); - flush_network_routes(net, 0); - free(net->ipv4); - net->ipv4 = NULL; - return 1; - } - } - return 0; -} - -int -check_network_channel(struct network *net) -{ - int channel = NET_CONF(net, channel); - - if(channel == NET_CHANNEL_UNKNOWN) { - if((net->flags & NET_WIRED)) { - channel = NET_CHANNEL_NONINTERFERING; - } else { - channel = kernel_interface_channel(net->ifname, net->ifindex); - if(channel < 0) - fprintf(stderr, - "Couldn't determine channel of interface %s: %s.\n", - net->ifname, strerror(errno)); - if(channel <= 0) - channel = NET_CHANNEL_INTERFERING; - } - } - - if(net->channel != channel) { - net->channel = channel; - return 1; - } - return 0; -} - -int -network_up(struct network *net, int up) -{ - int mtu, rc, wired; - struct ipv6_mreq mreq; - - if((!!up) == net_up(net)) - return 0; - - if(up) - net->flags |= NET_UP; - else - net->flags &= ~NET_UP; - - if(up) { - struct kernel_route ll[32]; - if(net->ifindex <= 0) { - fprintf(stderr, - "Upping unknown interface %s.\n", net->ifname); - return network_up(net, 0); - } - - rc = kernel_setup_interface(1, net->ifname, net->ifindex); - if(rc < 0) { - fprintf(stderr, "kernel_setup_interface(%s, %d) failed.\n", - net->ifname, net->ifindex); - return network_up(net, 0); - } - - mtu = kernel_interface_mtu(net->ifname, net->ifindex); - if(mtu < 0) { - fprintf(stderr, "Warning: couldn't get MTU of interface %s (%d).\n", - net->ifname, net->ifindex); - mtu = 1280; - } - - /* We need to be able to fit at least two messages into a packet, - so MTUs below 116 require lower layer fragmentation. */ - /* In IPv6, the minimum MTU is 1280, and every host must be able - to reassemble up to 1500 bytes, but I'd rather not rely on this. */ - if(mtu < 128) { - fprintf(stderr, "Suspiciously low MTU %d on interface %s (%d).\n", - mtu, net->ifname, net->ifindex); - mtu = 128; - } - - if(net->sendbuf) - free(net->sendbuf); - - /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */ - net->bufsize = mtu - sizeof(packet_header) - 60; - net->sendbuf = malloc(net->bufsize); - if(net->sendbuf == NULL) { - fprintf(stderr, "Couldn't allocate sendbuf.\n"); - net->bufsize = 0; - return network_up(net, 0); - } - - resize_receive_buffer(mtu); - - if(NET_CONF(net, wired) == CONFIG_NO) { - wired = 0; - } else if(NET_CONF(net, wired) == CONFIG_YES) { - wired = 1; - } else if(all_wireless) { - wired = 0; - } else { - rc = kernel_interface_wireless(net->ifname, net->ifindex); - if(rc < 0) { - fprintf(stderr, - "Warning: couldn't determine whether %s (%d) " - "is a wireless interface.\n", - net->ifname, net->ifindex); - wired = 0; - } else { - wired = !rc; - } - } - - if(wired) { - net->flags |= NET_WIRED; - net->cost = NET_CONF(net, cost); - if(net->cost <= 0) net->cost = 96; - if(NET_CONF(net, split_horizon) == CONFIG_NO) - net->flags &= ~NET_SPLIT_HORIZON; - else if(NET_CONF(net, split_horizon) == CONFIG_YES) - net->flags |= NET_SPLIT_HORIZON; - else if(split_horizon) - net->flags |= NET_SPLIT_HORIZON; - else - net->flags &= ~NET_SPLIT_HORIZON; - if(NET_CONF(net, lq) == CONFIG_YES) - net->flags |= NET_LQ; - else - net->flags &= ~NET_LQ; - } else { - net->flags &= ~NET_WIRED; - net->cost = NET_CONF(net, cost); - if(net->cost <= 0) net->cost = 256; - if(NET_CONF(net, split_horizon) == CONFIG_YES) - net->flags |= NET_SPLIT_HORIZON; - else - net->flags &= ~NET_SPLIT_HORIZON; - if(NET_CONF(net, lq) == CONFIG_NO) - net->flags &= ~NET_LQ; - else - net->flags |= NET_LQ; - } - - if(NET_CONF(net, faraway) == CONFIG_YES) - net->flags |= NET_FARAWAY; - - net->activity_time = now.tv_sec; - update_hello_interval(net); - /* Since the interface was marked as active above, the - idle_hello_interval cannot be the one being used here. */ - net->update_interval = - NET_CONF(net, update_interval) > 0 ? - NET_CONF(net, update_interval) : - net->hello_interval * 4; - - memset(&mreq, 0, sizeof(mreq)); - memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); - mreq.ipv6mr_interface = net->ifindex; - - rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, - (char*)&mreq, sizeof(mreq)); - if(rc < 0) { - perror("setsockopt(IPV6_JOIN_GROUP)"); - /* This is probably due to a missing link-local address, - so down this network, and wait until the main loop - tries to up it again. */ - return network_up(net, 0); - } - - if(net->ll) - free(net->ll); - net->numll = 0; - net->ll = NULL; - rc = kernel_addresses(net->ifname, net->ifindex, 1, ll, 32); - if(rc < 0) { - perror("kernel_ll_addresses"); - } else if(rc > 0) { - net->ll = malloc(16 * rc); - if(net->ll == NULL) { - perror("malloc(ll)"); - } else { - int i; - for(i = 0; i < rc; i++) - memcpy(net->ll[i], ll[i].prefix, 16); - net->numll = rc; - } - } - set_timeout(&net->hello_timeout, net->hello_interval); - set_timeout(&net->update_timeout, net->update_interval); - send_hello(net); - send_request(net, NULL, 0); - } else { - flush_network_routes(net, 0); - net->buffered = 0; - net->bufsize = 0; - free(net->sendbuf); - net->num_buffered_updates = 0; - net->update_bufsize = 0; - if(net->buffered_updates) - free(net->buffered_updates); - net->buffered_updates = NULL; - net->sendbuf = NULL; - if(net->ifindex > 0) { - memset(&mreq, 0, sizeof(mreq)); - memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); - mreq.ipv6mr_interface = net->ifindex; - rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, - (char*)&mreq, sizeof(mreq)); - if(rc < 0) - perror("setsockopt(IPV6_LEAVE_GROUP)"); - kernel_setup_interface(0, net->ifname, net->ifindex); - } - if(net->ll) - free(net->ll); - net->ll = NULL; - net->numll = 0; - } - - check_network_channel(net); - update_network_metric(net); - rc = check_network_ipv4(net); - - debugf("Upped network %s (%s, cost=%d, channel=%d%s).\n", - net->ifname, - (net->flags & NET_WIRED) ? "wired" : "wireless", - net->cost, - net->channel, - net->ipv4 ? ", IPv4" : ""); - - if(up && rc > 0) - send_update(net, 0, NULL, 0); - - return 1; -} - -int -network_ll_address(struct network *net, const unsigned char *address) -{ - int i; - - if(!net_up(net)) - return 0; - - for(i = 0; i < net->numll; i++) - if(memcmp(net->ll[i], address, 16) == 0) - return 1; - - return 0; -} - -void -check_networks(void) -{ - struct network *net; - int rc, ifindex, ifindex_changed = 0; - - FOR_ALL_NETS(net) { - ifindex = if_nametoindex(net->ifname); - if(ifindex != net->ifindex) { - debugf("Noticed ifindex change for %s.\n", net->ifname); - net->ifindex = 0; - network_up(net, 0); - net->ifindex = ifindex; - ifindex_changed = 1; - } - - if(net->ifindex > 0) - rc = kernel_interface_operational(net->ifname, net->ifindex); - else - rc = 0; - if((rc > 0) != net_up(net)) { - debugf("Noticed status change for %s.\n", net->ifname); - network_up(net, rc > 0); - } - - check_network_channel(net); - rc = check_network_ipv4(net); - if(rc > 0) { - send_request(net, NULL, 0); - send_update(net, 0, NULL, 0); - } - } - - if(ifindex_changed) - renumber_filters(); -} diff -Nru babeld-1.2.1/network.h babeld-1.3.0/network.h --- babeld-1.2.1/network.h 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/network.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -/* -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. -*/ - -struct buffered_update { - unsigned char id[8]; - unsigned char prefix[16]; - unsigned char plen; - unsigned char pad[3]; -}; - -struct network_conf { - char *ifname; - unsigned hello_interval; - unsigned update_interval; - unsigned short cost; - char wired; - char split_horizon; - char lq; - char faraway; - int channel; - struct network_conf *next; -}; - -#define CONFIG_DEFAULT 0 -#define CONFIG_NO 1 -#define CONFIG_YES 2 - -#define NET_UP (1 << 0) -#define NET_WIRED (1<<1) -#define NET_SPLIT_HORIZON (1 << 2) -#define NET_LQ (1 << 3) -#define NET_FARAWAY (1 << 4) - -/* Only INTERFERING can appear on the wire. */ -#define NET_CHANNEL_UNKNOWN 0 -#define NET_CHANNEL_INTERFERING 255 -#define NET_CHANNEL_NONINTERFERING -2 - -struct network { - struct network *next; - struct network_conf *conf; - unsigned int ifindex; - unsigned short flags; - unsigned short cost; - int channel; - struct timeval hello_timeout; - struct timeval update_timeout; - struct timeval flush_timeout; - struct timeval update_flush_timeout; - char ifname[IF_NAMESIZE]; - unsigned char *ipv4; - int numll; - unsigned char (*ll)[16]; - int buffered; - int bufsize; - char have_buffered_hello; - char have_buffered_id; - char have_buffered_nh; - char have_buffered_prefix; - unsigned char buffered_id[16]; - unsigned char buffered_nh[4]; - unsigned char buffered_prefix[16]; - unsigned char *sendbuf; - struct buffered_update *buffered_updates; - int num_buffered_updates; - int update_bufsize; - time_t bucket_time; - unsigned int bucket; - time_t activity_time; - unsigned short hello_seqno; - unsigned hello_interval; - unsigned update_interval; -}; - -#define NET_CONF(_net, _field) \ - ((_net)->conf ? (_net)->conf->_field : 0) - -extern struct network *networks; -extern int numnets; - -#define FOR_ALL_NETS(_net) for(_net = networks; _net; _net = _net->next) - -static inline int -net_up(struct network *net) -{ - return !!(net->flags & NET_UP); -} - -struct network *add_network(char *ifname, struct network_conf *conf); -int network_idle(struct network *net); -int update_hello_interval(struct network *net); -unsigned jitter(struct network *net, int urgent); -unsigned update_jitter(struct network *net, int urgent); -void set_timeout(struct timeval *timeout, int msecs); -int network_up(struct network *net, int up); -int network_ll_address(struct network *net, const unsigned char *address); -void check_networks(void); diff -Nru babeld-1.2.1/resend.c babeld-1.3.0/resend.c --- babeld-1.2.1/resend.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/resend.c 2011-12-08 18:46:00.000000000 +0000 @@ -30,7 +30,7 @@ #include "neighbour.h" #include "resend.h" #include "message.h" -#include "network.h" +#include "interface.h" #include "configuration.h" struct timeval resend_time = {0, 0}; @@ -83,10 +83,10 @@ int record_resend(int kind, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, - struct network *network, int delay) + struct interface *ifp, int delay) { struct resend *resend; - unsigned int ifindex = network ? network->ifindex : 0; + unsigned int ifindex = ifp ? ifp->ifindex : 0; if((kind == RESEND_REQUEST && input_filter(NULL, prefix, plen, NULL, ifindex) >= INFINITY) || @@ -114,8 +114,8 @@ else memset(resend->id, 0, 8); resend->seqno = seqno; - if(resend->network != network) - resend->network = NULL; + if(resend->ifp != ifp) + resend->ifp = NULL; } else { resend = malloc(sizeof(struct resend)); if(resend == NULL) @@ -130,7 +130,7 @@ memcpy(resend->id, id, 8); else memset(resend->id, 0, 8); - resend->network = network; + resend->ifp = ifp; resend->time = now; resend->next = to_resend; to_resend = resend; @@ -174,7 +174,7 @@ /* Determine whether a given request should be forwarded. */ int -request_redundant(struct network *net, +request_redundant(struct interface *ifp, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id) { @@ -188,7 +188,7 @@ seqno_compare(request->seqno, seqno) > 0) return 0; - if(request->network != NULL && request->network != net) + if(request->ifp != NULL && request->ifp != ifp) return 0; if(request->max > 0) @@ -196,7 +196,7 @@ return 1; if(timeval_minus_msec(&now, &request->time) < - (net ? MIN(net->hello_interval, 1000) : 1000)) + (ifp ? MIN(ifp->hello_interval, 1000) : 1000)) /* Fairly recent. */ return 1; @@ -206,7 +206,7 @@ int satisfy_request(const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, - struct network *network) + struct interface *ifp) { struct resend *request, *previous; @@ -214,7 +214,7 @@ if(request == NULL) return 0; - if(network != NULL && request->network != network) + if(ifp != NULL && request->ifp != ifp) return 0; if(memcmp(request->id, id, 8) != 0 || @@ -291,12 +291,12 @@ if(timeval_compare(&now, &timeout) >= 0) { switch(resend->kind) { case RESEND_REQUEST: - send_multihop_request(resend->network, + send_multihop_request(resend->ifp, resend->prefix, resend->plen, resend->seqno, resend->id, 127); break; case RESEND_UPDATE: - send_update(resend->network, 1, + send_update(resend->ifp, 1, resend->prefix, resend->plen); break; default: abort(); diff -Nru babeld-1.2.1/resend.h babeld-1.3.0/resend.h --- babeld-1.2.1/resend.h 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/resend.h 2011-12-08 18:46:00.000000000 +0000 @@ -35,7 +35,7 @@ unsigned char plen; unsigned short seqno; unsigned char id[8]; - struct network *network; + struct interface *ifp; struct resend *next; }; @@ -46,15 +46,15 @@ void flush_resends(struct neighbour *neigh); int record_resend(int kind, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, - struct network *net, int delay); + struct interface *ifp, int delay); int unsatisfied_request(const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id); -int request_redundant(struct network *net, +int request_redundant(struct interface *ifp, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id); int satisfy_request(const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, - struct network *net); + struct interface *ifp); void expire_resend(void); void recompute_resend_time(void); diff -Nru babeld-1.2.1/route.c babeld-1.3.0/route.c --- babeld-1.2.1/route.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/route.c 2011-12-08 18:46:00.000000000 +0000 @@ -1,5 +1,5 @@ /* -Copyright (c) 2007, 2008 by Juliusz Chroboczek +Copyright (c) 2007-2011 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 @@ -30,7 +30,7 @@ #include "babeld.h" #include "util.h" #include "kernel.h" -#include "network.h" +#include "interface.h" #include "source.h" #include "neighbour.h" #include "route.h" @@ -40,39 +40,161 @@ #include "configuration.h" #include "local.h" -struct route *routes = NULL; -int numroutes = 0, maxroutes = 0; +struct route **routes = NULL; +static int route_slots = 0, max_route_slots = 0; int kernel_metric = 0; int allow_duplicates = -1; int diversity_kind = DIVERSITY_NONE; int diversity_factor = 256; /* in units of 1/256 */ int keep_unfeasible = 0; +/* We maintain a list of "slots", ordered by prefix. Every slot + contains a linked list of the routes to this prefix, with the + installed route, if any, at the head of the list. */ + +static int +route_compare(const unsigned char *prefix, unsigned char plen, + struct route *route) +{ + int i = memcmp(prefix, route->src->prefix, 16); + if(i != 0) + return i; + + if(plen < route->src->plen) + return -1; + else if(plen > route->src->plen) + return 1; + else + return 0; +} + +/* Performs binary search, returns -1 in case of failure. In the latter + case, new_return is the place where to insert the new element. */ + +static int +find_route_slot(const unsigned char *prefix, unsigned char plen, + int *new_return) +{ + int p, m, g, c; + + if(route_slots < 1) { + if(new_return) + *new_return = 0; + return -1; + } + + p = 0; g = route_slots - 1; + + do { + m = (p + g) / 2; + c = route_compare(prefix, plen, routes[m]); + if(c == 0) + return m; + else if(c < 0) + g = m - 1; + else + p = m + 1; + } while(p <= g); + + if(new_return) + *new_return = p; + + return -1; +} + struct route * find_route(const unsigned char *prefix, unsigned char plen, struct neighbour *neigh, const unsigned char *nexthop) { - int i; - for(i = 0; i < numroutes; i++) { - if(routes[i].neigh == neigh && - memcmp(routes[i].nexthop, nexthop, 16) == 0 && - source_match(routes[i].src, prefix, plen)) - return &routes[i]; + struct route *route; + int i = find_route_slot(prefix, plen, NULL); + + if(i < 0) + return NULL; + + route = routes[i]; + + while(route) { + if(route->neigh == neigh && memcmp(route->nexthop, nexthop, 16) == 0) + return route; + route = route->next; } + return NULL; } struct route * find_installed_route(const unsigned char *prefix, unsigned char plen) { - int i; - for(i = 0; i < numroutes; i++) { - if(routes[i].installed && source_match(routes[i].src, prefix, plen)) - return &routes[i]; - } + int i = find_route_slot(prefix, plen, NULL); + + if(i >= 0 && routes[i]->installed) + return routes[i]; + return NULL; } +/* Returns an overestimate of the number of installed routes. */ +int +installed_routes_estimate(void) +{ + return route_slots; +} + +static int +resize_route_table(int new_slots) +{ + struct route **new_routes; + assert(new_slots >= route_slots); + + if(new_slots == 0) { + new_routes = NULL; + free(routes); + } else { + new_routes = realloc(routes, new_slots * sizeof(struct route*)); + if(new_routes == NULL) + return -1; + } + + max_route_slots = new_slots; + routes = new_routes; + return 1; +} + +/* Insert a route into the table. If successful, retains the route. + On failure, caller must free the route. */ +static struct route * +insert_route(struct route *route) +{ + int i, n; + + assert(!route->installed); + + i = find_route_slot(route->src->prefix, route->src->plen, &n); + + if(i < 0) { + if(route_slots >= max_route_slots) + resize_route_table(max_route_slots < 1 ? 8 : 2 * max_route_slots); + if(route_slots >= max_route_slots) + return NULL; + route->next = NULL; + if(n < route_slots) + memmove(routes + n + 1, routes + n, + (route_slots - n) * sizeof(struct route*)); + route_slots++; + routes[n] = route; + } else { + struct route *r; + r = routes[i]; + while(r->next) + r = r->next; + r->next = route; + route->next = NULL; + } + + return route; +} + void flush_route(struct route *route) { @@ -81,41 +203,69 @@ unsigned oldmetric; int lost = 0; - i = route - routes; - assert(i >= 0 && i < numroutes); - oldmetric = route_metric(route); + src = route->src; if(route->installed) { uninstall_route(route); lost = 1; } + i = find_route_slot(route->src->prefix, route->src->plen, NULL); + assert(i >= 0 && i < route_slots); + local_notify_route(route, LOCAL_FLUSH); - src = route->src; + if(route == routes[i]) { + routes[i] = route->next; + route->next = NULL; + free(route); + + if(routes[i] == NULL) { + if(i < route_slots - 1) + memmove(routes + i, routes + i + 1, + (route_slots - i - 1) * sizeof(struct route*)); + routes[route_slots - 1] = NULL; + route_slots--; + } + + if(route_slots == 0) + resize_route_table(0); + else if(max_route_slots > 8 && route_slots < max_route_slots / 4) + resize_route_table(max_route_slots / 2); + } else { + struct route *r = routes[i]; + while(r->next != route) + r = r->next; + r->next = route->next; + route->next = NULL; + free(route); + } - if(i != numroutes - 1) - memcpy(routes + i, routes + numroutes - 1, sizeof(struct route)); - numroutes--; - VALGRIND_MAKE_MEM_UNDEFINED(routes + numroutes, sizeof(struct route)); + if(lost) + route_lost(src, oldmetric); - if(numroutes == 0) { - free(routes); - routes = NULL; - maxroutes = 0; - } else if(maxroutes > 8 && numroutes < maxroutes / 4) { - struct route *new_routes; - int n = maxroutes / 2; - new_routes = realloc(routes, n * sizeof(struct route)); - if(new_routes != NULL) { - routes = new_routes; - maxroutes = n; + release_source(src); +} + +void +flush_all_routes() +{ + int i; + + /* Start from the end, to avoid shifting the table. */ + i = route_slots - 1; + while(i >= 0) { + while(i < route_slots) { + /* Uninstall first, to avoid calling route_lost. */ + if(routes[i]->installed) + uninstall_route(routes[0]); + flush_route(routes[i]); } + i--; } - if(lost) - route_lost(src, oldmetric); + check_sources_released(); } void @@ -124,28 +274,68 @@ int i; i = 0; - while(i < numroutes) { - if(routes[i].neigh == neigh) { - flush_route(&routes[i]); - continue; + while(i < route_slots) { + struct route *r; + r = routes[i]; + while(r) { + if(r->neigh == neigh) { + flush_route(r); + goto again; + } + r = r->next; } i++; + again: + ; } } void -flush_network_routes(struct network *net, int v4only) +flush_interface_routes(struct interface *ifp, int v4only) { int i; i = 0; - while(i < numroutes) { - if(routes[i].neigh->network == net && - (!v4only || v4mapped(routes[i].nexthop))) { - flush_route(&routes[i]); - continue; + while(i < route_slots) { + struct route *r; + r = routes[i]; + while(r) { + if(r->neigh->ifp == ifp && + (!v4only || v4mapped(r->nexthop))) { + flush_route(r); + goto again; + } + r = r->next; } i++; + again: + ; + } +} + +/* Iterate a function over all routes. */ +void +for_all_routes(void (*f)(struct route*, void*), void *closure) +{ + int i; + + for(i = 0; i < route_slots; i++) { + struct route *r = routes[i]; + while(r) { + (*f)(r, closure); + r = r->next; + } + } +} + +void +for_all_installed_routes(void (*f)(struct route*, void*), void *closure) +{ + int i; + + for(i = 0; i < route_slots; i++) { + if(routes[i]->installed) + (*f)(routes[i], closure); } } @@ -155,10 +345,28 @@ return metric < INFINITY ? kernel_metric : KERNEL_INFINITY; } +/* This is used to maintain the invariant that the installed route is at + the head of the list. */ +static void +move_installed_route(struct route *route, int i) +{ + assert(i >= 0 && i < route_slots); + assert(route->installed); + + if(route != routes[i]) { + struct route *r = routes[i]; + while(r->next != route) + r = r->next; + r->next = route->next; + route->next = routes[i]; + routes[i] = route; + } +} + void install_route(struct route *route) { - int rc; + int i, rc; if(route->installed) return; @@ -167,9 +375,18 @@ fprintf(stderr, "WARNING: installing unfeasible route " "(this shouldn't happen)."); + i = find_route_slot(route->src->prefix, route->src->plen, NULL); + assert(i >= 0 && i < route_slots); + + if(routes[i] != route && routes[i]->installed) { + fprintf(stderr, "WARNING: attempting to install duplicate route " + "(this shouldn't happen)."); + return; + } + rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen, route->nexthop, - route->neigh->network->ifindex, + route->neigh->ifp->ifindex, metric_to_kernel(route_metric(route)), NULL, 0, 0); if(rc < 0) { int save = errno; @@ -178,6 +395,8 @@ return; } route->installed = 1; + move_installed_route(route, i); + local_notify_route(route, LOCAL_CHANGE); } @@ -191,7 +410,7 @@ rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen, route->nexthop, - route->neigh->network->ifindex, + route->neigh->ifp->ifindex, metric_to_kernel(route_metric(route)), NULL, 0, 0); if(rc < 0) perror("kernel_route(FLUSH)"); @@ -222,9 +441,9 @@ "(this shouldn't happen)."); rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen, - old->nexthop, old->neigh->network->ifindex, + old->nexthop, old->neigh->ifp->ifindex, metric_to_kernel(route_metric(old)), - new->nexthop, new->neigh->network->ifindex, + new->nexthop, new->neigh->ifp->ifindex, metric_to_kernel(route_metric(new))); if(rc < 0) { perror("kernel_route(MODIFY)"); @@ -233,7 +452,8 @@ old->installed = 0; new->installed = 1; - + move_installed_route(new, find_route_slot(new->src->prefix, new->src->plen, + NULL)); local_notify_route(old, LOCAL_CHANGE); local_notify_route(new, LOCAL_CHANGE); } @@ -251,9 +471,9 @@ if(route->installed && old != new) { int rc; rc = kernel_route(ROUTE_MODIFY, route->src->prefix, route->src->plen, - route->nexthop, route->neigh->network->ifindex, + route->nexthop, route->neigh->ifp->ifindex, old, - route->nexthop, route->neigh->network->ifindex, + route->nexthop, route->neigh->ifp->ifindex, new); if(rc < 0) { perror("kernel_route(MODIFY metric)"); @@ -294,33 +514,33 @@ static int channels_interfere(int ch1, int ch2) { - if(ch1 == NET_CHANNEL_NONINTERFERING || ch2 == NET_CHANNEL_NONINTERFERING) + if(ch1 == IF_CHANNEL_NONINTERFERING || ch2 == IF_CHANNEL_NONINTERFERING) return 0; - if(ch1 == NET_CHANNEL_INTERFERING || ch2 == NET_CHANNEL_INTERFERING) + if(ch1 == IF_CHANNEL_INTERFERING || ch2 == IF_CHANNEL_INTERFERING) return 1; return ch1 == ch2; } int -route_interferes(struct route *route, struct network *net) +route_interferes(struct route *route, struct interface *ifp) { switch(diversity_kind) { case DIVERSITY_NONE: return 1; case DIVERSITY_INTERFACE_1: - return route->neigh->network == net; + return route->neigh->ifp == ifp; case DIVERSITY_CHANNEL_1: case DIVERSITY_CHANNEL: - if(route->neigh->network == net) + if(route->neigh->ifp == ifp) return 1; - if(channels_interfere(net->channel, route->neigh->network->channel)) + if(channels_interfere(ifp->channel, route->neigh->ifp->channel)) return 1; if(diversity_kind == DIVERSITY_CHANNEL) { int i; for(i = 0; i < DIVERSITY_HOPS; i++) { if(route->channels[i] == 0) break; - if(channels_interfere(net->channel, route->channels[i])) + if(channels_interfere(ifp->channel, route->channels[i])) return 1; } } @@ -355,21 +575,22 @@ find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, struct neighbour *exclude) { - struct route *route = NULL; - int i; + struct route *route, *r; + int i = find_route_slot(prefix, plen, NULL); + + if(i < 0) + return NULL; + + route = routes[i]; - for(i = 0; i < numroutes; i++) { - if(!source_match(routes[i].src, prefix, plen)) - continue; - if(route_expired(&routes[i])) - continue; - if(feasible && !route_feasible(&routes[i])) - continue; - if(exclude && routes[i].neigh == exclude) - continue; - if(route && route_metric(route) <= route_metric(&routes[i])) - continue; - route = &routes[i]; + r = route->next; + while(r) { + if(!route_expired(r) && + (!feasible || route_feasible(r)) && + (!exclude || r->neigh != exclude) && + (route_metric(r) < route_metric(route))) + route = r; + r = r->next; } return route; } @@ -391,7 +612,7 @@ int add_metric = input_filter(route->src->id, route->src->prefix, route->src->plen, neigh->address, - neigh->network->ifindex); + neigh->ifp->ifindex); change_route_metric(route, route->refmetric, neighbour_cost(route->neigh), add_metric); if(route_metric(route) != oldmetric) @@ -408,11 +629,13 @@ if(changed) { int i; - i = 0; - while(i < numroutes) { - if(routes[i].neigh == neigh) - update_route_metric(&routes[i]); - i++; + for(i = 0; i < route_slots; i++) { + struct route *r = routes[i]; + while(r) { + if(r->neigh == neigh) + update_route_metric(r); + r = r->next; + } } } @@ -420,21 +643,24 @@ } void -update_network_metric(struct network *net) +update_interface_metric(struct interface *ifp) { int i; - i = 0; - while(i < numroutes) { - if(routes[i].neigh->network == net) - update_route_metric(&routes[i]); - i++; + for(i = 0; i < route_slots; i++) { + struct route *r = routes[i]; + while(r) { + if(r->neigh->ifp == ifp) + update_route_metric(r); + r = r->next; + } } } /* This is called whenever we receive an update. */ struct route * -update_route(const unsigned char *a, const unsigned char *p, unsigned char plen, +update_route(const unsigned char *id, + const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned short refmetric, unsigned short interval, struct neighbour *neigh, const unsigned char *nexthop, @@ -446,27 +672,34 @@ int add_metric; int hold_time = MAX((4 * interval) / 100 + interval / 50, 15); - if(memcmp(a, myid, 8) == 0) + if(memcmp(id, myid, 8) == 0) return NULL; - if(martian_prefix(p, plen)) { + if(martian_prefix(prefix, plen)) { fprintf(stderr, "Rejecting martian route to %s through %s.\n", - format_prefix(p, plen), format_address(a)); + format_prefix(prefix, plen), format_address(id)); return NULL; } - add_metric = input_filter(a, p, plen, - neigh->address, neigh->network->ifindex); + add_metric = input_filter(id, prefix, plen, + neigh->address, neigh->ifp->ifindex); if(add_metric >= INFINITY) return NULL; - src = find_source(a, p, plen, 1, seqno); + route = find_route(prefix, plen, neigh, nexthop); + + if(route && memcmp(route->src->id, id, 8) == 0) + /* Avoid scanning the source table. */ + src = route->src; + else + src = find_source(id, prefix, plen, 1, seqno); + if(src == NULL) return NULL; feasible = update_feasible(src, seqno, refmetric); - route = find_route(p, plen, neigh, nexthop); metric = MIN((int)refmetric + neighbour_cost(neigh) + add_metric, INFINITY); + if(route) { struct source *oldsrc; unsigned short oldmetric; @@ -492,7 +725,7 @@ } } - route->src = src; + route->src = retain_source(src); if((feasible || keep_unfeasible) && refmetric < INFINITY) route->time = now.tv_sec; route->seqno = seqno; @@ -507,7 +740,10 @@ if(!feasible) send_unfeasible_request(neigh, route->installed && route_old(route), seqno, metric, src); + release_source(oldsrc); } else { + struct route *new_route; + if(refmetric >= INFINITY) /* Somebody's retracting a route we never saw. */ return NULL; @@ -517,19 +753,13 @@ return NULL; } - if(numroutes >= maxroutes) { - struct route *new_routes; - int n = maxroutes < 1 ? 8 : 2 * maxroutes; - new_routes = routes == NULL ? - malloc(n * sizeof(struct route)) : - realloc(routes, n * sizeof(struct route)); - if(new_routes == NULL) - return NULL; - maxroutes = n; - routes = new_routes; + route = malloc(sizeof(struct route)); + if(route == NULL) { + perror("malloc(route)"); + return NULL; } - route = &routes[numroutes]; - route->src = src; + + route->src = retain_source(src); route->refmetric = refmetric; route->cost = neighbour_cost(neigh); route->add_metric = add_metric; @@ -543,7 +773,13 @@ if(channels_len > 0) memcpy(&route->channels, channels, MIN(channels_len, DIVERSITY_HOPS)); - numroutes++; + route->next = NULL; + new_route = insert_route(route); + if(new_route == NULL) { + fprintf(stderr, "Couldn't insert route.\n"); + free(route); + return NULL; + } local_notify_route(route, LOCAL_ADD); consider_route(route); } @@ -602,13 +838,6 @@ if(route_metric(installed) >= INFINITY) goto install; - if(route_metric(installed) >= route_metric(route) + 192) - goto install; - - /* Avoid switching sources */ - if(installed->src != route->src) - return; - if(route_metric(installed) >= route_metric(route) + 64) goto install; @@ -628,15 +857,18 @@ { int i; - i = 0; - while(i < numroutes) { - if(routes[i].neigh == neigh) { - if(routes[i].refmetric != INFINITY) { - unsigned short oldmetric = route_metric(&routes[i]); - retract_route(&routes[i]); + for(i = 0; i < route_slots; i++) { + struct route *r = routes[i]; + while(r) { + if(r->neigh == neigh) { + if(r->refmetric != INFINITY) { + unsigned short oldmetric = route_metric(r); + retract_route(r); if(oldmetric != INFINITY) - route_changed(&routes[i], routes[i].src, oldmetric); + route_changed(r, r->src, oldmetric); + } } + r = r->next; } i++; } @@ -743,30 +975,38 @@ } } +/* This is called periodically to flush old routes. It will also send + requests for routes that are about to expire. */ void expire_routes(void) { + struct route *r; int i; debugf("Expiring old routes.\n"); i = 0; - while(i < numroutes) { - struct route *route = &routes[i]; - - if(route->time > now.tv_sec || /* clock stepped */ - route_old(route)) { - flush_route(route); - continue; - } + while(i < route_slots) { + r = routes[i]; + while(r) { + /* Protect against clock being stepped. */ + if(r->time > now.tv_sec || route_old(r)) { + flush_route(r); + goto again; + } - update_route_metric(route); + update_route_metric(r); - if(route->installed && route->refmetric < INFINITY) { - if(route_old(route)) - send_unicast_request(route->neigh, - route->src->prefix, route->src->plen); + if(r->installed && r->refmetric < INFINITY) { + if(route_old(r)) + /* Route about to expire, send a request. */ + send_unicast_request(r->neigh, + r->src->prefix, r->src->plen); + } + r = r->next; } i++; + again: + ; } } diff -Nru babeld-1.2.1/route.h babeld-1.3.0/route.h --- babeld-1.2.1/route.h 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/route.h 2011-12-08 18:46:00.000000000 +0000 @@ -1,5 +1,5 @@ /* -Copyright (c) 2007, 2008 by Juliusz Chroboczek +Copyright (c) 2007-2011 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 @@ -39,10 +39,10 @@ unsigned short hold_time; /* in seconds */ short installed; unsigned char channels[DIVERSITY_HOPS]; + struct route *next; }; -extern struct route *routes; -extern int numroutes, maxroutes; +extern struct route **routes; extern int kernel_metric, allow_duplicates; extern int diversity_kind, diversity_factor; extern int keep_unfeasible; @@ -69,16 +69,20 @@ struct neighbour *neigh, const unsigned char *nexthop); struct route *find_installed_route(const unsigned char *prefix, unsigned char plen); +int installed_routes_estimate(void); void flush_route(struct route *route); +void flush_all_routes(void); void flush_neighbour_routes(struct neighbour *neigh); -void flush_network_routes(struct network *net, int v4only); +void flush_interface_routes(struct interface *ifp, int v4only); +void for_all_routes(void (*f)(struct route*, void*), void *closure); +void for_all_installed_routes(void (*f)(struct route*, void*), void *closure); void install_route(struct route *route); void uninstall_route(struct route *route); void switch_route(struct route *old, struct route *new); int route_feasible(struct route *route); int route_old(struct route *route); int route_expired(struct route *route); -int route_interferes(struct route *route, struct network *net); +int route_interferes(struct route *route, struct interface *ifp); int update_feasible(struct source *src, unsigned short seqno, unsigned short refmetric); struct route *find_best_route(const unsigned char *prefix, unsigned char plen, @@ -86,10 +90,10 @@ struct route *install_best_route(const unsigned char prefix[16], unsigned char plen); void update_neighbour_metric(struct neighbour *neigh, int changed); -void update_network_metric(struct network *net); +void update_interface_metric(struct interface *ifp); void update_route_metric(struct route *route); -struct route *update_route(const unsigned char *a, - const unsigned char *p, unsigned char plen, +struct route *update_route(const unsigned char *id, + const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned short refmetric, unsigned short interval, struct neighbour *neigh, const unsigned char *nexthop, diff -Nru babeld-1.2.1/source.c babeld-1.3.0/source.c --- babeld-1.2.1/source.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/source.c 2011-12-08 18:46:00.000000000 +0000 @@ -24,11 +24,12 @@ #include #include #include +#include #include "babeld.h" #include "util.h" #include "source.h" -#include "network.h" +#include "interface.h" #include "route.h" struct source *srcs = NULL; @@ -46,8 +47,10 @@ continue; if(memcmp(src->id, id, 8) != 0) continue; - if(source_match(src, p, plen)) - return src; + if(src->plen != plen) + continue; + if(memcmp(src->prefix, p, 16) == 0) + return src; } if(!create) @@ -65,23 +68,33 @@ src->seqno = seqno; src->metric = INFINITY; src->time = now.tv_sec; + src->route_count = 0; src->next = srcs; srcs = src; return src; } -int -flush_source(struct source *src) +struct source * +retain_source(struct source *src) { - int i; + assert(src->route_count < 0xffff); + src->route_count++; + return src; +} - /* This is absolutely horrible -- it makes expire_sources quadratic. - But it's not called very often. */ +void +release_source(struct source *src) +{ + assert(src->route_count > 0); + src->route_count--; +} - for(i = 0; i < numroutes; i++) { - if(routes[i].src == src) - return 0; - } +int +flush_source(struct source *src) +{ + if(src->route_count > 0) + /* The source is in use by a route. */ + return 0; if(srcs == src) { srcs = src->next; @@ -96,19 +109,6 @@ return 1; } -int -source_match(struct source *src, - const unsigned char *p, unsigned char plen) -{ - if(src->plen != plen) - return 0; - if(src->prefix[15] != p[15]) - return 0; - if(memcmp(src->prefix, p, 16) != 0) - return 0; - return 1; -} - void update_source(struct source *src, unsigned short seqno, unsigned short metric) @@ -116,6 +116,10 @@ if(metric >= INFINITY) return; + /* If a source is expired, pretend that it doesn't exist and update + it unconditionally. This makes ensures that old data will + eventually be overridden, and prevents us from getting stuck if + a router loses its sequence number. */ if(src->time < now.tv_sec - SOURCE_GC_TIME || seqno_compare(src->seqno, seqno) < 0 || (src->seqno == seqno && src->metric > metric)) { @@ -144,3 +148,17 @@ src = src->next; } } + +void +check_sources_released(void) +{ + struct source *src; + + for(src = srcs; src; src = src->next) { + if(src->route_count != 0) + fprintf(stderr, "Warning: source %s %s has refcount %d.\n", + format_eui64(src->id), + format_prefix(src->prefix, src->plen), + (int)src->route_count); + } +} diff -Nru babeld-1.2.1/source.h babeld-1.3.0/source.h --- babeld-1.2.1/source.h 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/source.h 2011-12-08 18:46:00.000000000 +0000 @@ -29,16 +29,18 @@ unsigned char plen; unsigned short seqno; unsigned short metric; + unsigned short route_count; time_t time; }; -int source_match(struct source *src, - const unsigned char *p, unsigned char plen); struct source *find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, int create, unsigned short seqno); +struct source *retain_source(struct source *src); +void release_source(struct source *src); int flush_source(struct source *src); void update_source(struct source *src, unsigned short seqno, unsigned short metric); void expire_sources(void); +void check_sources_released(void); diff -Nru babeld-1.2.1/util.c babeld-1.3.0/util.c --- babeld-1.2.1/util.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/util.c 2011-12-08 18:46:00.000000000 +0000 @@ -308,6 +308,7 @@ if(strcmp(net, "default") == 0) { memset(prefix, 0, 16); plen = 0; + af = AF_INET6; } else { slash = strchr(net, '/'); if(slash == NULL) { diff -Nru babeld-1.2.1/xroute.c babeld-1.3.0/xroute.c --- babeld-1.2.1/xroute.c 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/xroute.c 2011-12-08 18:46:00.000000000 +0000 @@ -36,12 +36,11 @@ #include "xroute.h" #include "util.h" #include "configuration.h" -#include "network.h" +#include "interface.h" #include "local.h" -struct xroute *xroutes; -int numxroutes = 0; -int maxxroutes = 0; +static struct xroute *xroutes; +static int numxroutes = 0, maxxroutes = 0; struct xroute * find_xroute(const unsigned char *prefix, unsigned char plen) @@ -120,6 +119,22 @@ return 1; } +/* Returns an overestimate of the number of xroutes. */ +int +xroutes_estimate() +{ + return numxroutes; +} + +void +for_all_xroutes(void (*f)(struct xroute*, void*), void *closure) +{ + int i; + + for(i = 0; i < numxroutes; i++) + (*f)(&xroutes[i], closure); +} + int check_xroutes(int send_updates) { diff -Nru babeld-1.2.1/xroute.h babeld-1.3.0/xroute.h --- babeld-1.2.1/xroute.h 2011-10-16 11:09:19.000000000 +0000 +++ babeld-1.3.0/xroute.h 2011-12-08 18:46:00.000000000 +0000 @@ -28,11 +28,10 @@ int proto; }; -extern struct xroute *xroutes; -extern int numxroutes; - struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen); void flush_xroute(struct xroute *xroute); int add_xroute(unsigned char prefix[16], unsigned char plen, unsigned short metric, unsigned int ifindex, int proto); +int xroutes_estimate(void); +void for_all_xroutes(void (*f)(struct xroute*, void*), void *closure); int check_xroutes(int send_updates);