+
+ 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. */
+
+ for(node = node_tree->head; node; node = next) {
+ next = node->next;
+ n = node->data;
+
+ if(n->status.visited != n->status.reachable) {
+ n->status.reachable = !n->status.reachable;
+
+ if(n->status.reachable) {
+ ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became reachable",
+ n->name, n->hostname);
+ } else {
+ ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became unreachable",
+ n->name, n->hostname);
+ }
+
+ /* TODO: only clear status.validkey if node is unreachable? */
+
+ n->status.validkey = false;
+ n->status.waitingforkey = false;
+
+ n->maxmtu = MTU;
+ n->minmtu = 0;
+ n->mtuprobes = 0;
+
+ event_del(&n->mtuevent);
+
+ xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
+ xasprintf(&envp[1], "DEVICE=%s", device ? : "");
+ xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
+ xasprintf(&envp[3], "NODE=%s", n->name);
+ sockaddr2str(&n->address, &address, &port);
+ xasprintf(&envp[4], "REMOTEADDRESS=%s", address);
+ xasprintf(&envp[5], "REMOTEPORT=%s", port);
+ envp[6] = NULL;
+
+ execute_script(n->status.reachable ? "host-up" : "host-down", envp);
+
+ xasprintf(&name,
+ n->status.reachable ? "hosts/%s-up" : "hosts/%s-down",
+ n->name);
+ execute_script(name, envp);
+
+ free(name);
+ free(address);
+ free(port);
+
+ for(i = 0; i < 6; i++)
+ free(envp[i]);
+
+ subnet_update(n, NULL, n->status.reachable);
+ }
+ }
+}
+
+/* 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
+*/
+
+int dump_graph(struct evbuffer *out) {
+ splay_node_t *node;
+ node_t *n;
+ edge_t *e;
+
+ if(evbuffer_add_printf(out, "digraph {\n") == -1)
+ return errno;
+
+ /* dump all nodes first */
+ for(node = node_tree->head; node; node = node->next) {
+ n = node->data;
+ if(evbuffer_add_printf(out, " %s [label = \"%s\"];\n",
+ n->name, n->name) == -1)
+ return errno;
+ }
+
+ /* now dump all edges */
+ for(node = edge_weight_tree->head; node; node = node->next) {
+ e = node->data;
+ if(evbuffer_add_printf(out, " %s -> %s;\n",
+ e->from->name, e->to->name) == -1)
+ return errno;
+ }
+
+ if(evbuffer_add_printf(out, "}\n") == -1)
+ return errno;
+
+ return 0;