From: Guus Sliepen Date: Fri, 11 Dec 2009 21:31:27 +0000 (+0100) Subject: Merge branch 'master' into 1.1 X-Git-Tag: import-tinc-1.1~574 X-Git-Url: http://git.meshlink.io/?p=meshlink;a=commitdiff_plain;h=d6c50eb73ad49bd2eac67214995dff76b7a20661;hp=-c Merge branch 'master' into 1.1 Conflicts: src/subnet.c --- d6c50eb73ad49bd2eac67214995dff76b7a20661 diff --combined src/graph.c index 06bf36d7,f5aff5bf..d54e5cd6 --- a/src/graph.c +++ b/src/graph.c @@@ -44,7 -44,7 +44,7 @@@ #include "system.h" -#include "avl_tree.h" +#include "splay_tree.h" #include "config.h" #include "connection.h" #include "device.h" @@@ -57,16 -57,21 +57,16 @@@ #include "utils.h" #include "xalloc.h" -static bool graph_changed = true; - /* Implementation of Kruskal's algorithm. - Running time: O(EN) + Running time: O(E) Please note that sorting on weight is already done by add_edge(). */ void mst_kruskal(void) { - avl_node_t *node, *next; + splay_node_t *node, *next; edge_t *e; node_t *n; connection_t *c; - int nodes = 0; - int safe_edges = 0; - bool skipped; /* Clear MST status on connections */ @@@ -75,6 -80,11 +75,6 @@@ c->status.mst = false; } - /* Do we have something to do at all? */ - - if(!edge_weight_tree->head) - return; - ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Kruskal's algorithm:"); /* Clear visited status on nodes */ @@@ -82,16 -92,29 +82,16 @@@ for(node = node_tree->head; node; node = node->next) { n = node->data; n->status.visited = false; - nodes++; - } - - /* Starting point */ - - for(node = edge_weight_tree->head; node; node = node->next) { - e = node->data; - if(e->from->status.reachable) { - e->from->status.visited = true; - break; - } } /* Add safe edges */ - for(skipped = false, node = edge_weight_tree->head; node; node = next) { + for(node = edge_weight_tree->head; node; node = next) { next = node->next; e = node->data; - if(!e->reverse || e->from->status.visited == e->to->status.visited) { - skipped = true; + if(!e->reverse || (e->from->status.visited && e->to->status.visited)) continue; - } e->from->status.visited = true; e->to->status.visited = true; @@@ -102,133 -125,20 +102,133 @@@ if(e->reverse->connection) e->reverse->connection->status.mst = true; - safe_edges++; - ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name, e->to->name, e->weight); + } +} - if(skipped) { - skipped = false; - next = edge_weight_tree->head; - continue; +/* Implementation of Dijkstra's algorithm. + Running time: O(N^2) +*/ + +void sssp_dijkstra(void) { + splay_node_t *node, *to; + edge_t *e; + node_t *n, *m; + list_t *todo_list; + list_node_t *lnode, *nnode; + bool indirect; + + todo_list = list_alloc(NULL); + + ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Dijkstra's algorithm:"); + + /* Clear visited status on nodes */ + + for(node = node_tree->head; node; node = node->next) { + n = node->data; + n->status.visited = false; + n->status.indirect = true; + n->distance = -1; + } + + /* Begin with myself */ + + myself->status.indirect = false; + myself->nexthop = myself; + myself->via = myself; + myself->distance = 0; + list_insert_head(todo_list, myself); + + /* Loop while todo_list is filled */ + + while(todo_list->head) { + n = NULL; + nnode = NULL; + + /* Select node from todo_list with smallest distance */ + + for(lnode = todo_list->head; lnode; lnode = lnode->next) { + m = lnode->data; + if(!n || m->status.indirect < n->status.indirect || m->distance < n->distance) { + n = m; + nnode = lnode; + } + } + + /* Mark this node as visited and remove it from the todo_list */ + + n->status.visited = true; + list_unlink_node(todo_list, nnode); + + /* Update distance of neighbours and add them to the todo_list */ + + for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */ + e = to->data; + + if(e->to->status.visited || !e->reverse) + continue; + + /* Situation: + + / + / + ----->(n)---e-->(e->to) + \ + \ + + Where e is an edge, (n) and (e->to) are nodes. + n->address is set to the e->address of the edge left of n to n. + We are currently examining the edge e right of n from n: + + - If e->reverse->address != n->address, then e->to is probably + not reachable for the nodes left of n. We do as if the indirectdata + flag is set on edge e. + - If edge e provides for better reachability of e->to, update e->to. + */ + + if(e->to->distance < 0) + list_insert_tail(todo_list, e->to); + + indirect = n->status.indirect || e->options & OPTION_INDIRECT || ((n != myself) && sockaddrcmp(&n->address, &e->reverse->address)); + + if(e->to->distance >= 0 && (!e->to->status.indirect || indirect) && e->to->distance <= n->distance + e->weight) + continue; + + e->to->distance = n->distance + e->weight; + e->to->status.indirect = indirect; + e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop; + e->to->via = indirect ? n->via : e->to; + e->to->options = e->options; + + if(sockaddrcmp(&e->to->address, &e->address)) { + node = splay_unlink(node_udp_tree, e->to); + sockaddrfree(&e->to->address); + sockaddrcpy(&e->to->address, &e->address); + + if(e->to->hostname) + free(e->to->hostname); + + e->to->hostname = sockaddr2hostname(&e->to->address); + + if(node) + splay_insert_node(node_udp_tree, node); + + if(e->to->options & OPTION_PMTU_DISCOVERY) { + e->to->mtuprobes = 0; + e->to->minmtu = 0; + e->to->maxmtu = MTU; + if(e->to->status.validkey) + send_mtu_probe(e->to); + } + } + + ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Updating edge %s - %s weight %d distance %d", e->from->name, + e->to->name, e->weight, e->to->distance); } } - ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Done, counted %d nodes and %d safe edges.", nodes, - safe_edges); + list_free(todo_list); } /* Implementation of a simple breadth-first search algorithm. @@@ -236,12 -146,16 +236,12 @@@ */ void sssp_bfs(void) { - avl_node_t *node, *next, *to; + splay_node_t *node, *to; edge_t *e; node_t *n; list_t *todo_list; list_node_t *from, *todonext; bool indirect; - char *name; - char *address, *port; - char *envp[7]; - int i; todo_list = list_alloc(NULL); @@@ -316,15 -230,6 +316,15 @@@ } list_free(todo_list); +} + +void check_reachability() { + splay_node_t *node, *next; + node_t *n; + char *name; + char *address, *port; + char *envp[7]; + int i; /* Check reachability status. */ @@@ -352,7 -257,10 +352,7 @@@ n->minmtu = 0; n->mtuprobes = 0; - if(n->mtuevent) { - event_del(n->mtuevent); - n->mtuevent = NULL; - } + event_del(&n->mtuevent); xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : ""); @@@ -378,13 -286,79 +378,16 @@@ free(envp[i]); subnet_update(n, NULL, n->status.reachable); + + if(!n->status.reachable) + update_node_udp(n, NULL); } } } void graph(void) { subnet_cache_flush(); - sssp_bfs(); + sssp_dijkstra(); + check_reachability(); mst_kruskal(); - graph_changed = true; -} - - - -/* Dump nodes and edges to a graphviz file. - - The file can be converted to an image with - dot -Tpng graph_filename -o image_filename.png -Gconcentrate=true -*/ - -void dump_graph(void) { - avl_node_t *node; - node_t *n; - edge_t *e; - char *filename = NULL, *tmpname = NULL; - FILE *file; - - if(!graph_changed || !get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename)) - return; - - graph_changed = false; - - ifdebug(PROTOCOL) logger(LOG_NOTICE, "Dumping graph"); - - if(filename[0] == '|') { - file = popen(filename + 1, "w"); - } else { - xasprintf(&tmpname, "%s.new", filename); - file = fopen(tmpname, "w"); - } - - if(!file) { - logger(LOG_ERR, "Unable to open graph dump file %s: %s", filename, strerror(errno)); - free(tmpname); - return; - } - - fprintf(file, "digraph {\n"); - - /* dump all nodes first */ - for(node = node_tree->head; node; node = node->next) { - n = node->data; - fprintf(file, " %s [label = \"%s\"];\n", n->name, n->name); - } - - /* now dump all edges */ - for(node = edge_weight_tree->head; node; node = node->next) { - e = node->data; - fprintf(file, " %s -> %s;\n", e->from->name, e->to->name); - } - - fprintf(file, "}\n"); - - if(filename[0] == '|') { - pclose(file); - } else { - fclose(file); -#ifdef HAVE_MINGW - unlink(filename); -#endif - rename(tmpname, filename); - free(tmpname); - } } diff --combined src/route.c index 758801be,16423892..3c0cf5b5 --- a/src/route.c +++ b/src/route.c @@@ -20,7 -20,7 +20,7 @@@ #include "system.h" -#include "avl_tree.h" +#include "splay_tree.h" #include "connection.h" #include "ethernet.h" #include "ipv4.h" @@@ -49,8 -49,6 +49,8 @@@ static const size_t icmp6_size = sizeof static const size_t ns_size = sizeof(struct nd_neighbor_solicit); static const size_t opt_size = sizeof(struct nd_opt_hdr); +static struct event age_subnets_event; + /* RFC 1071 */ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) { @@@ -74,7 -72,6 +74,7 @@@ static bool ratelimit(int frequency) { static time_t lasttime = 0; static int count = 0; + time_t now = time(NULL); if(lasttime == now) { if(++count > frequency) @@@ -102,46 -99,12 +102,46 @@@ static void swap_mac_addresses(vpn_pack memcpy(&packet->data[6], &tmp, sizeof tmp); } +static void age_subnets(int fd, short events, void *data) { + subnet_t *s; + connection_t *c; + splay_node_t *node, *next, *node2; + bool left = false; + time_t now = time(NULL); + + for(node = myself->subnet_tree->head; node; node = next) { + next = node->next; + s = node->data; + if(s->expires && s->expires < now) { + ifdebug(TRAFFIC) { + char netstr[MAXNETSTR]; + if(net2str(netstr, sizeof netstr, s)) + logger(LOG_INFO, "Subnet %s expired", netstr); + } + + for(node2 = connection_tree->head; node2; node2 = node2->next) { + c = node2->data; + if(c->status.active) + send_del_subnet(c, s); + } + + subnet_del(myself, s); + } else { + if(s->expires) + left = true; + } + } + + if(left) + event_add(&age_subnets_event, &(struct timeval){10, 0}); +} + static void learn_mac(mac_t *address) { subnet_t *subnet; - avl_node_t *node; + splay_node_t *node; connection_t *c; - subnet = lookup_subnet_mac(address); + subnet = lookup_subnet_mac(myself, address); /* If we don't know this MAC address yet, store it */ @@@ -152,7 -115,7 +152,7 @@@ subnet = new_subnet(); subnet->type = SUBNET_MAC; - subnet->expires = now + macexpire; + subnet->expires = time(NULL) + macexpire; subnet->net.mac.address = *address; subnet->weight = 10; subnet_add(myself, subnet); @@@ -164,13 -127,35 +164,13 @@@ if(c->status.active) send_add_subnet(c, subnet); } - } - - if(subnet->expires) - subnet->expires = now + macexpire; -} - -void age_subnets(void) { - subnet_t *s; - connection_t *c; - avl_node_t *node, *next, *node2; - - for(node = myself->subnet_tree->head; node; node = next) { - next = node->next; - s = node->data; - if(s->expires && s->expires < now) { - ifdebug(TRAFFIC) { - char netstr[MAXNETSTR]; - if(net2str(netstr, sizeof netstr, s)) - logger(LOG_INFO, "Subnet %s expired", netstr); - } - for(node2 = connection_tree->head; node2; node2 = node2->next) { - c = node2->data; - if(c->status.active) - send_del_subnet(c, s); - } - - subnet_del(myself, s); - } + if(!timeout_initialized(&age_subnets_event)) + timeout_set(&age_subnets_event, age_subnets, NULL); + event_add(&age_subnets_event, &(struct timeval){10, 0}); + } else { + if(subnet->expires) + subnet->expires = time(NULL) + macexpire; } } @@@ -423,7 -408,7 +423,7 @@@ static void route_ipv6_unreachable(node /* Generate checksum */ - checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0); + checksum = inet_checksum(&pseudo, sizeof pseudo, ~0); checksum = inet_checksum(&icmp6, icmp6_size, checksum); checksum = inet_checksum(packet->data + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum); @@@ -542,7 -527,7 +542,7 @@@ static void route_neighborsol(node_t *s /* Generate checksum */ - checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0); + checksum = inet_checksum(&pseudo, sizeof pseudo, ~0); checksum = inet_checksum(&ns, ns_size, checksum); if(has_opt) { checksum = inet_checksum(&opt, opt_size, checksum); @@@ -605,7 -590,7 +605,7 @@@ /* Generate checksum */ - checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0); + checksum = inet_checksum(&pseudo, sizeof pseudo, ~0); checksum = inet_checksum(&ns, ns_size, checksum); if(has_opt) { checksum = inet_checksum(&opt, opt_size, checksum); @@@ -666,7 -651,7 +666,7 @@@ static void route_arp(node_t *source, v /* Check if this is a valid ARP request */ if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP || - arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) { + arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof addr || ntohs(arp.arp_op) != ARPOP_REQUEST) { ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type ARP request"); return; } @@@ -690,9 -675,9 +690,9 @@@ memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ - memcpy(&addr, arp.arp_tpa, sizeof(addr)); /* save protocol addr */ - memcpy(arp.arp_tpa, arp.arp_spa, sizeof(addr)); /* swap destination and source protocol address */ - memcpy(arp.arp_spa, &addr, sizeof(addr)); /* ... */ + memcpy(&addr, arp.arp_tpa, sizeof addr); /* save protocol addr */ + memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr); /* swap destination and source protocol address */ + memcpy(arp.arp_spa, &addr, sizeof addr); /* ... */ memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN); /* set target hard/proto addr */ memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ @@@ -720,7 -705,7 +720,7 @@@ static void route_mac(node_t *source, v /* Lookup destination address */ memcpy(&dest, &packet->data[0], sizeof dest); - subnet = lookup_subnet_mac(&dest); + subnet = lookup_subnet_mac(NULL, &dest); if(!subnet) { broadcast_packet(source, packet); diff --combined src/subnet.c index 0669b8a0,bc66fecc..8bc8fce8 --- a/src/subnet.c +++ b/src/subnet.c @@@ -20,8 -20,7 +20,8 @@@ #include "system.h" -#include "avl_tree.h" +#include "splay_tree.h" +#include "control_common.h" #include "device.h" #include "logger.h" #include "net.h" @@@ -34,7 -33,7 +34,7 @@@ /* lists type of subnet */ -avl_tree_t *subnet_tree; +splay_tree_t *subnet_tree; /* Subnet lookup cache */ @@@ -64,7 -63,7 +64,7 @@@ void subnet_cache_flush() static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) { int result; - result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t)); + result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof a->net.mac.address); if(result) return result; @@@ -146,21 -145,21 +146,21 @@@ int subnet_compare(const subnet_t *a, c /* Initialising trees */ void init_subnets(void) { - subnet_tree = avl_alloc_tree((avl_compare_t) subnet_compare, (avl_action_t) free_subnet); + subnet_tree = splay_alloc_tree((splay_compare_t) subnet_compare, (splay_action_t) free_subnet); subnet_cache_flush(); } void exit_subnets(void) { - avl_delete_tree(subnet_tree); + splay_delete_tree(subnet_tree); } -avl_tree_t *new_subnet_tree(void) { - return avl_alloc_tree((avl_compare_t) subnet_compare, NULL); +splay_tree_t *new_subnet_tree(void) { + return splay_alloc_tree((splay_compare_t) subnet_compare, NULL); } -void free_subnet_tree(avl_tree_t *subnet_tree) { - avl_delete_tree(subnet_tree); +void free_subnet_tree(splay_tree_t *subnet_tree) { + splay_delete_tree(subnet_tree); } /* Allocating and freeing space for subnets */ @@@ -178,15 -177,15 +178,15 @@@ void free_subnet(subnet_t *subnet) void subnet_add(node_t *n, subnet_t *subnet) { subnet->owner = n; - avl_insert(subnet_tree, subnet); - avl_insert(n->subnet_tree, subnet); + splay_insert(subnet_tree, subnet); + splay_insert(n->subnet_tree, subnet); subnet_cache_flush(); } void subnet_del(node_t *n, subnet_t *subnet) { - avl_delete(n->subnet_tree, subnet); - avl_delete(subnet_tree, subnet); + splay_delete(n->subnet_tree, subnet); + splay_delete(subnet_tree, subnet); subnet_cache_flush(); } @@@ -274,7 -273,7 +274,7 @@@ bool str2net(subnet_t *subnet, const ch bool net2str(char *netstr, int len, const subnet_t *subnet) { if(!netstr || !subnet) { - logger(LOG_ERR, "net2str() was called with netstr=%p, subnet=%p!\n", netstr, subnet); + logger(LOG_ERR, "net2str() was called with netstr=%p, subnet=%p!", netstr, subnet); return false; } @@@ -327,12 -326,12 +327,12 @@@ /* Subnet lookup routines */ subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet) { - return avl_search(owner->subnet_tree, subnet); + return splay_search(owner->subnet_tree, subnet); } - subnet_t *lookup_subnet_mac(const mac_t *address) { - subnet_t *p, *r = NULL, subnet = {0}; + subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) { + subnet_t *p, *r = NULL; - avl_node_t *n; + splay_node_t *n; int i; // Check if this address is cached @@@ -340,20 -339,18 +340,18 @@@ for(i = 0; i < 2; i++) { if(!cache_mac_valid[i]) continue; + if(owner && cache_mac_subnet[i] && cache_mac_subnet[i]->owner != owner) + continue; if(!memcmp(address, &cache_mac_address[i], sizeof *address)) return cache_mac_subnet[i]; } // Search all subnets for a matching one - subnet.type = SUBNET_MAC; - subnet.net.mac.address = *address; - subnet.owner = NULL; - - for(n = subnet_tree->head; n; n = n->next) { + for(n = owner ? owner->subnet_tree->head : subnet_tree->head; n; n = n->next) { p = n->data; - if(!p || p->type != subnet.type) + if(!p || p->type != SUBNET_MAC) continue; if(!memcmp(address, &p->net.mac.address, sizeof *address)) { @@@ -374,8 -371,8 +372,8 @@@ } subnet_t *lookup_subnet_ipv4(const ipv4_t *address) { - subnet_t *p, *r = NULL, subnet = {0}; + subnet_t *p, *r = NULL; - avl_node_t *n; + splay_node_t *n; int i; // Check if this address is cached @@@ -389,15 -386,10 +387,10 @@@ // Search all subnets for a matching one - subnet.type = SUBNET_IPV4; - subnet.net.ipv4.address = *address; - subnet.net.ipv4.prefixlength = 32; - subnet.owner = NULL; - for(n = subnet_tree->head; n; n = n->next) { p = n->data; - if(!p || p->type != subnet.type) + if(!p || p->type != SUBNET_IPV4) continue; if(!maskcmp(address, &p->net.ipv4.address, p->net.ipv4.prefixlength)) { @@@ -418,8 -410,8 +411,8 @@@ } subnet_t *lookup_subnet_ipv6(const ipv6_t *address) { - subnet_t *p, *r = NULL, subnet = {0}; + subnet_t *p, *r = NULL; - avl_node_t *n; + splay_node_t *n; int i; // Check if this address is cached @@@ -433,15 -425,10 +426,10 @@@ // Search all subnets for a matching one - subnet.type = SUBNET_IPV6; - subnet.net.ipv6.address = *address; - subnet.net.ipv6.prefixlength = 128; - subnet.owner = NULL; - for(n = subnet_tree->head; n; n = n->next) { p = n->data; - if(!p || p->type != subnet.type) + if(!p || p->type != SUBNET_IPV6) continue; if(!maskcmp(address, &p->net.ipv6.address, p->net.ipv6.prefixlength)) { @@@ -462,7 -449,7 +450,7 @@@ } void subnet_update(node_t *owner, subnet_t *subnet, bool up) { - avl_node_t *node; + splay_node_t *node; int i; char *envp[9] = {0}; char netstr[MAXNETSTR]; @@@ -528,19 -515,19 +516,19 @@@ free(envp[i]); } -void dump_subnets(void) { +bool dump_subnets(connection_t *c) { char netstr[MAXNETSTR]; subnet_t *subnet; - avl_node_t *node; - - logger(LOG_DEBUG, "Subnet list:"); + splay_node_t *node; for(node = subnet_tree->head; node; node = node->next) { subnet = node->data; if(!net2str(netstr, sizeof netstr, subnet)) continue; - logger(LOG_DEBUG, " %s owner %s", netstr, subnet->owner->name); + send_request(c, "%d %d %s owner %s", + CONTROL, REQ_DUMP_SUBNETS, + netstr, subnet->owner->name); } - logger(LOG_DEBUG, "End of subnet list."); + return send_request(c, "%d %d", CONTROL, REQ_DUMP_SUBNETS); } diff --combined src/subnet.h index 466eb20c,b2124a0e..df48f60e --- a/src/subnet.h +++ b/src/subnet.h @@@ -69,18 -69,18 +69,18 @@@ extern subnet_t *new_subnet(void) __att extern void free_subnet(subnet_t *); extern void init_subnets(void); extern void exit_subnets(void); -extern avl_tree_t *new_subnet_tree(void) __attribute__ ((__malloc__)); -extern void free_subnet_tree(avl_tree_t *); +extern splay_tree_t *new_subnet_tree(void) __attribute__ ((__malloc__)); +extern void free_subnet_tree(splay_tree_t *); extern void subnet_add(struct node_t *, subnet_t *); extern void subnet_del(struct node_t *, subnet_t *); extern void subnet_update(struct node_t *, subnet_t *, bool); extern bool net2str(char *, int, const subnet_t *); extern bool str2net(subnet_t *, const char *); extern subnet_t *lookup_subnet(const struct node_t *, const subnet_t *); - extern subnet_t *lookup_subnet_mac(const mac_t *); + extern subnet_t *lookup_subnet_mac(const struct node_t *, const mac_t *); extern subnet_t *lookup_subnet_ipv4(const ipv4_t *); extern subnet_t *lookup_subnet_ipv6(const ipv6_t *); -extern void dump_subnets(void); +extern bool dump_subnets(struct connection_t *); extern void subnet_cache_flush(void); #endif /* __TINC_SUBNET_H__ */