/*
* The olsr.org Optimized Link-State Routing daemon(olsrd)
* Copyright (c) 2004, Thomas Lopatic (thomas@lopatic.de)
+ * IPv4 performance optimization (c) 2006, sven-ola(gmx.de)
+ * SPF implementation (c) 2007, Hannes Gredler (hannes@gredler.at)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* to the project. For more information see the website or contact
* the copyright holders.
*
- * $Id: lq_route.c,v 1.23 2005/01/24 10:35:58 tlopatic Exp $
+ * Implementation of Dijkstras algorithm. Initially all nodes
+ * are initialized to infinite cost. First we put ourselves
+ * on the heap of reachable nodes. Our heap implementation
+ * is based on an AVL tree which gives interesting performance
+ * characteristics for the frequent operations of minimum key
+ * extraction and re-keying. Next all neighbors of a node are
+ * explored and put on the heap if the cost of reaching them is
+ * better than reaching the current candidate node.
+ * The SPF calculation is terminated if there are no more nodes
+ * on the heap.
*/
+#include "ipcalc.h"
#include "defs.h"
+#include "olsr.h"
#include "tc_set.h"
#include "neighbor_table.h"
+#include "two_hop_neighbor_table.h"
#include "link_set.h"
#include "routing_table.h"
#include "mid_set.h"
#include "hna_set.h"
-#include "lq_list.h"
-#include "lq_avl.h"
+#include "common/list.h"
+#include "common/avl.h"
#include "lq_route.h"
+#include "net_olsr.h"
+#include "lq_plugin.h"
-struct dijk_edge
-{
- struct avl_node tree_node;
- struct list_node node;
- struct dijk_vertex *dest;
- float etx;
-};
-
-struct dijk_vertex
-{
- struct avl_node tree_node;
- struct list_node node;
- union olsr_ip_addr addr;
- struct avl_tree edge_tree;
- struct list edge_list;
- float path_etx;
- struct dijk_vertex *prev;
- olsr_bool done;
-};
-
-static int avl_comp_ipv6(void *ip1, void *ip2)
-{
- return memcmp(ip1, ip2, ipsize);
-}
+struct timer_entry *spf_backoff_timer = NULL;
-static int avl_comp_ipv4(void *ip1, void *ip2)
-{
- if (*(unsigned int *)ip1 < *(unsigned int *)ip2)
+/*
+ * avl_comp_etx
+ *
+ * compare two etx metrics.
+ * return 0 if there is an exact match and
+ * -1 / +1 depending on being smaller or bigger.
+ * note that this results in the most optimal code
+ * after compiler optimization.
+ */
+static int
+avl_comp_etx (const void *etx1, const void *etx2)
+{
+ if (*(const olsr_linkcost *)etx1 < *(const olsr_linkcost *)etx2) {
return -1;
+ }
- if (*(unsigned int *)ip1 == *(unsigned int *)ip2)
- return 0;
+ if (*(const olsr_linkcost *)etx1 > *(const olsr_linkcost *)etx2) {
+ return +1;
+ }
- return 1;
+ return 0;
}
-static int (*avl_comp)(void *, void *);
-
-static void add_vertex(struct avl_tree *vertex_tree, struct list *vertex_list,
- union olsr_ip_addr *addr, float path_etx)
+/*
+ * olsr_spf_add_cand_tree
+ *
+ * Key an existing vertex to a candidate tree.
+ */
+static void
+olsr_spf_add_cand_tree (struct avl_tree *tree,
+ struct tc_entry *tc)
{
- struct avl_node *node;
- struct dijk_vertex *vert;
-
- // see whether this destination is already in our list
-
- node = avl_find(vertex_tree, addr);
-
- // if it's not in our list, add it
-
- if (node == NULL)
- {
- vert = olsr_malloc(sizeof (struct dijk_vertex), "Dijkstra vertex");
-
- vert->tree_node.data = vert;
- vert->tree_node.key = &vert->addr;
-
- vert->node.data = vert;
-
- COPY_IP(&vert->addr, addr);
-
- vert->path_etx = path_etx;
- vert->prev = NULL;
- vert->done = OLSR_FALSE;
+#if !defined(NODEBUG) && defined(DEBUG)
+ struct ipaddr_str buf;
+ struct lqtextbuffer lqbuffer;
+#endif
+ tc->cand_tree_node.key = &tc->path_cost;
- avl_init(&vert->edge_tree, avl_comp);
- list_init(&vert->edge_list);
+#ifdef DEBUG
+ OLSR_PRINTF(2, "SPF: insert candidate %s, cost %s\n",
+ olsr_ip_to_string(&buf, &tc->addr),
+ get_linkcost_text(tc->path_cost, OLSR_FALSE, &lqbuffer));
+#endif
- avl_insert(vertex_tree, &vert->tree_node);
- list_add_tail(vertex_list, &vert->node);
- }
+ avl_insert(tree, &tc->cand_tree_node, AVL_DUP);
}
-static void add_edge(struct avl_tree *vertex_tree, struct list *vertex_list,
- union olsr_ip_addr *src, union olsr_ip_addr *dst,
- float etx)
+/*
+ * olsr_spf_del_cand_tree
+ *
+ * Unkey an existing vertex from a candidate tree.
+ */
+static void
+olsr_spf_del_cand_tree (struct avl_tree *tree,
+ struct tc_entry *tc)
{
- struct avl_node *node;
- struct dijk_vertex *svert;
- struct dijk_vertex *dvert;
- struct dijk_edge *edge;
-
- // source lookup
-
- node = avl_find(vertex_tree, src);
-
- // source vertex does not exist
-
- if (node == NULL)
- return;
-
- svert = node->data;
-
- // destination lookup
-
- node = avl_find(vertex_tree, dst);
-
- // destination vertex does not exist
-
- if (node == NULL)
- return;
-
- dvert = node->data;
-
- // check for existing forward edge
-
- if (avl_find(&svert->edge_tree, dst) == NULL)
- {
- // add forward edge
-
- edge = olsr_malloc(sizeof (struct dijk_vertex), "Dijkstra edge 1");
-
- edge->tree_node.data = edge;
- edge->tree_node.key = &dvert->addr;
-
- edge->node.data = edge;
-
- edge->dest = dvert;
- edge->etx = etx;
-
- avl_insert(&svert->edge_tree, &edge->tree_node);
- list_add_tail(&svert->edge_list, &edge->node);
- }
- // check for existing inverse edge
-
- if (avl_find(&dvert->edge_tree, src) == NULL)
- {
- // add inverse edge
-
- edge = olsr_malloc(sizeof (struct dijk_vertex), "Dijkstra edge 2");
+#ifdef DEBUG
+#ifndef NODEBUG
+ struct ipaddr_str buf;
+ struct lqtextbuffer lqbuffer;
+#endif
+ OLSR_PRINTF(2, "SPF: delete candidate %s, cost %s\n",
+ olsr_ip_to_string(&buf, &tc->addr),
+ get_linkcost_text(tc->path_cost, OLSR_FALSE, &lqbuffer));
+#endif
- edge->tree_node.data = edge;
- edge->tree_node.key = &svert->addr;
+ avl_delete(tree, &tc->cand_tree_node);
+}
- edge->node.data = edge;
+/*
+ * olsr_spf_add_path_list
+ *
+ * Insert an SPF result at the end of the path list.
+ */
+static void
+olsr_spf_add_path_list (struct list_node *head, int *path_count,
+ struct tc_entry *tc)
+{
+#if !defined(NODEBUG) && defined(DEBUG)
+ struct ipaddr_str pathbuf, nbuf;
+ struct lqtextbuffer lqbuffer;
+#endif
- edge->dest = svert;
- edge->etx = etx;
+#ifdef DEBUG
+ OLSR_PRINTF(2, "SPF: append path %s, cost %s, via %s\n",
+ olsr_ip_to_string(&pathbuf, &tc->addr),
+ get_linkcost_text(tc->path_cost, OLSR_FALSE, &lqbuffer),
+ tc->next_hop ? olsr_ip_to_string(
+ &nbuf, &tc->next_hop->neighbor_iface_addr) : "-");
+#endif
- avl_insert(&dvert->edge_tree, &edge->tree_node);
- list_add_tail(&dvert->edge_list, &edge->node);
- }
+ list_add_before(head, &tc->path_list_node);
+ *path_count = *path_count + 1;
}
-static void free_everything(struct list *vertex_list)
+/*
+ * olsr_spf_extract_best
+ *
+ * return the node with the minimum pathcost.
+ */
+static struct tc_entry *
+olsr_spf_extract_best (struct avl_tree *tree)
{
- struct list_node *vnode, *enode;
- struct dijk_vertex *vert;
- struct dijk_edge *edge;
+ struct avl_node *node = avl_walk_first(tree);
- vnode = list_get_head(vertex_list);
+ return (node ? cand_tree2tc(node) : NULL);
+}
- // loop through all vertices
- while (vnode != NULL)
- {
- vert = vnode->data;
+/*
+ * olsr_spf_relax
+ *
+ * Explore all edges of a node and add the node
+ * to the candidate tree if the if the aggregate
+ * path cost is better.
+ */
+static void
+olsr_spf_relax (struct avl_tree *cand_tree, struct tc_entry *tc)
+{
+ struct avl_node *edge_node;
+ olsr_linkcost new_cost;
- enode = list_get_head(&vert->edge_list);
+#ifdef DEBUG
+#ifndef NODEBUG
+ struct ipaddr_str buf, nbuf;
+ struct lqtextbuffer lqbuffer;
+#endif
+ OLSR_PRINTF(2, "SPF: exploring node %s, cost %s\n",
+ olsr_ip_to_string(&buf, &tc->addr),
+ get_linkcost_text(tc->path_cost, OLSR_FALSE, &lqbuffer));
+#endif
- // loop through all edges of the current vertex
+ /*
+ * loop through all edges of this vertex.
+ */
+ for (edge_node = avl_walk_first(&tc->edge_tree);
+ edge_node;
+ edge_node = avl_walk_next(edge_node)) {
- while (enode != NULL)
- {
- edge = enode->data;
+ struct tc_entry *new_tc;
+ struct tc_edge_entry *tc_edge = edge_tree2tc_edge(edge_node);
- enode = list_get_next(enode);
- free(edge);
+ /*
+ * We are not interested in dead-end or dying edges.
+ */
+ if (!tc_edge->edge_inv ||
+ ((tc_edge->flags | tc_edge->edge_inv->flags) & OLSR_TC_EDGE_DOWN)) {
+#ifdef DEBUG
+ OLSR_PRINTF(2, "SPF: ignoring edge %s\n",
+ olsr_ip_to_string(&buf, &tc_edge->T_dest_addr));
+ if (!tc_edge->edge_inv) {
+ OLSR_PRINTF(2, "SPF: no inverse edge\n");
+ }
+
+ if (tc_edge->flags & OLSR_TC_EDGE_DOWN) {
+ OLSR_PRINTF(2, "SPF: edge down\n");
+ }
+ if (!tc_edge->edge_inv) {
+ OLSR_PRINTF(2, "SPF: no inverse edge\n");
+ } else if (tc_edge->edge_inv->flags & OLSR_TC_EDGE_DOWN){
+ OLSR_PRINTF(2, "SPF: inverse edge down\n");
+ }
+#endif
+ continue;
}
- vnode = list_get_next(vnode);
- free(vert);
- }
-}
+ /*
+ * total quality of the path through this vertex
+ * to the destination of this edge
+ */
+ new_cost = tc->path_cost + tc_edge->cost;
-// XXX - bad complexity
+#ifdef DEBUG
+ OLSR_PRINTF(2, "SPF: exploring edge %s, cost %s\n",
+ olsr_ip_to_string(&buf, &tc_edge->T_dest_addr),
+ get_linkcost_text(new_cost, OLSR_TRUE, &lqbuffer));
+#endif
-static struct dijk_vertex *extract_best(struct list *vertex_list)
-{
- float best_etx = INFINITE_ETX + 1.0;
- struct list_node *node;
- struct dijk_vertex *vert;
- struct dijk_vertex *res = NULL;
+ /*
+ * if it's better than the current path quality of this edge's
+ * destination node, then we've found a better path to this node.
+ */
+ new_tc = tc_edge->edge_inv->tc;
- node = list_get_head(vertex_list);
+ if (new_cost < new_tc->path_cost) {
- // loop through all vertices
-
- while (node != NULL)
- {
- vert = node->data;
+ /* if this node has been on the candidate tree delete it */
+ if (new_tc->path_cost < ROUTE_COST_BROKEN) {
+ olsr_spf_del_cand_tree(cand_tree, new_tc);
+ }
- // see whether the current vertex is better than what we have
+ /* re-insert on candidate tree with the better metric */
+ new_tc->path_cost = new_cost;
+ olsr_spf_add_cand_tree(cand_tree, new_tc);
- if (!vert->done && vert->path_etx < best_etx)
- {
- best_etx = vert->path_etx;
- res = vert;
- }
+ /* pull-up the next-hop and bump the hop count */
+ if (tc->next_hop) {
+ new_tc->next_hop = tc->next_hop;
+ }
+ new_tc->hops = tc->hops + 1;
+
+#ifdef DEBUG
+ OLSR_PRINTF(2, "SPF: better path to %s, cost %s, via %s, hops %u\n",
+ olsr_ip_to_string(&buf, &new_tc->addr),
+ get_linkcost_text(new_cost, OLSR_TRUE, &lqbuffer),
+ tc->next_hop ? olsr_ip_to_string(
+ &nbuf, &tc->next_hop->neighbor_iface_addr) : "<none>",
+ new_tc->hops);
+#endif
- node = list_get_next(node);
+ }
}
-
- // if we've found a vertex, remove it from the set
-
- if (res != NULL)
- res->done = OLSR_TRUE;
-
- return res;
}
-static void relax(struct dijk_vertex *vert)
+/*
+ * olsr_spf_run_full
+ *
+ * Run the Dijkstra algorithm.
+ *
+ * A node gets added to the candidate tree when one of its edges has
+ * an overall better root path cost than the node itself.
+ * The node with the shortest metric gets moved from the candidate to
+ * the path list every pass.
+ * The SPF computation is completed when there are no more nodes
+ * on the candidate tree.
+ */
+static void
+olsr_spf_run_full (struct avl_tree *cand_tree, struct list_node *path_list,
+ int *path_count)
{
- struct dijk_edge *edge;
- float new_etx;
- struct list_node *node;
-
- node = list_get_head(&vert->edge_list);
-
- // loop through all edges of this vertex
+ struct tc_entry *tc;
- while (node != NULL)
- {
- edge = node->data;
+ *path_count = 0;
- // total quality of the path through this vertex to the
- // destination of this edge
+ while ((tc = olsr_spf_extract_best(cand_tree))) {
- new_etx = vert->path_etx + edge->etx;
+ olsr_spf_relax(cand_tree, tc);
- // if it's better than the current path quality of this
- // edge's destination, then we've found a better path to
- // this destination
-
- if (new_etx < edge->dest->path_etx)
- {
- edge->dest->path_etx = new_etx;
- edge->dest->prev = vert;
- }
-
- node = list_get_next(node);
+ /*
+ * move the best path from the candidate tree
+ * to the path list.
+ */
+ olsr_spf_del_cand_tree(cand_tree, tc);
+ olsr_spf_add_path_list(path_list, path_count, tc);
}
}
-static char *etx_to_string(float etx)
+/**
+ * Callback for the SPF backoff timer.
+ */
+static void
+olsr_expire_spf_backoff(void *context __attribute__((unused)))
{
- static char buff[20];
-
- if (etx == INFINITE_ETX)
- return "INF";
-
- sprintf(buff, "%.2f", etx);
- return buff;
+ spf_backoff_timer = NULL;
}
-void olsr_calculate_lq_routing_table(void)
+void
+olsr_calculate_routing_table (void *context __attribute__((unused)))
{
- struct avl_tree vertex_tree;
- struct list vertex_list;
- int i;
- struct tc_entry *tcsrc;
- struct topo_dst *tcdst;
- struct dijk_vertex *vert;
- struct link_entry *link;
+#ifdef SPF_PROFILING
+ struct timeval t1, t2, t3, t4, t5, spf_init, spf_run, route, kernel, total;
+#endif
+ struct avl_tree cand_tree;
+ struct avl_node *rtp_tree_node;
+ struct list_node path_list; /* head of the path_list */
+ struct tc_entry *tc;
+ struct rt_path *rtp;
+ struct tc_edge_entry *tc_edge;
struct neighbor_entry *neigh;
- struct list_node *node;
- struct dijk_vertex *myself;
- struct dijk_vertex *walker;
- int hops;
- struct mid_address *mid_walker;
- float etx;
- struct hna_entry *hna_gw;
- struct hna_net *hna;
- struct rt_entry *gw_rt, *hna_rt, *head_rt;
-
- if (ipsize == 4)
- avl_comp = avl_comp_ipv4;
-
- else
- avl_comp = avl_comp_ipv6;
-
- // initialize the graph
-
- avl_init(&vertex_tree, avl_comp);
- list_init(&vertex_list);
-
- // add ourselves to the vertex list
-
- add_vertex(&vertex_tree, &vertex_list, &main_addr, 0.0);
-
- // add our neighbours
-
- for (i = 0; i < HASHSIZE; i++)
- for (neigh = neighbortable[i].next; neigh != &neighbortable[i];
- neigh = neigh->next)
- if (neigh->status == SYM)
- add_vertex(&vertex_tree, &vertex_list, &neigh->neighbor_main_addr,
- INFINITE_ETX);
-
- // add remaining vertices
-
- for (i = 0; i < HASHSIZE; i++)
- for (tcsrc = tc_table[i].next; tcsrc != &tc_table[i]; tcsrc = tcsrc->next)
- {
- // add source
-
- add_vertex(&vertex_tree, &vertex_list, &tcsrc->T_last_addr,
- INFINITE_ETX);
-
- // add destinations of this source
-
- for (tcdst = tcsrc->destinations.next; tcdst != &tcsrc->destinations;
- tcdst = tcdst->next)
- add_vertex(&vertex_tree, &vertex_list, &tcdst->T_dest_addr,
- INFINITE_ETX);
- }
-
- // add edges to and from our neighbours
-
- for (i = 0; i < HASHSIZE; i++)
- for (neigh = neighbortable[i].next; neigh != &neighbortable[i];
- neigh = neigh->next)
- if (neigh->status == SYM)
- {
- link = olsr_neighbor_best_link(&neigh->neighbor_main_addr);
+ struct link_entry *link;
+ int path_count = 0;
+
+ /* We are done if our backoff timer is running */
+ if (!spf_backoff_timer) {
+ spf_backoff_timer =
+ olsr_start_timer(1000, 5, OLSR_TIMER_ONESHOT, &olsr_expire_spf_backoff,
+ NULL, 0);
+ } else {
+ return;
+ }
- if (link->loss_link_quality >= MIN_LINK_QUALITY &&
- link->neigh_link_quality >= MIN_LINK_QUALITY)
- {
- etx = 1.0 / (link->loss_link_quality * link->neigh_link_quality);
+#ifdef SPF_PROFILING
+ gettimeofday(&t1, NULL);
+#endif
- add_edge(&vertex_tree, &vertex_list, &neigh->neighbor_main_addr,
- &main_addr, etx);
- }
+ /*
+ * Prepare the candidate tree and result list.
+ */
+ avl_init(&cand_tree, avl_comp_etx);
+ list_head_init(&path_list);
+ olsr_bump_routingtree_version();
+
+ /*
+ * Initialize vertices in the lsdb.
+ */
+ OLSR_FOR_ALL_TC_ENTRIES(tc) {
+ tc->next_hop = NULL;
+ tc->path_cost = ROUTE_COST_BROKEN;
+ tc->hops = 0;
+ } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
+
+ /*
+ * zero ourselves and add us to the candidate tree.
+ */
+ olsr_change_myself_tc();
+ tc_myself->path_cost = ZERO_ROUTE_COST;
+ olsr_spf_add_cand_tree(&cand_tree, tc_myself);
+
+ /*
+ * add edges to and from our neighbours.
+ */
+ OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
+
+ if (neigh->status == SYM) {
+
+ tc_edge = olsr_lookup_tc_edge(tc_myself, &neigh->neighbor_main_addr);
+ link = get_best_link_to_neighbor(&neigh->neighbor_main_addr);
+ if (!link) {
+
+ /*
+ * If there is no best link to this neighbor
+ * and we had an edge before then flush the edge.
+ */
+ if (tc_edge) {
+ olsr_delete_tc_edge_entry(tc_edge);
+ }
+ continue;
}
- // add remaining edges
-
- for (i = 0; i < HASHSIZE; i++)
- for (tcsrc = tc_table[i].next; tcsrc != &tc_table[i]; tcsrc = tcsrc->next)
- for (tcdst = tcsrc->destinations.next; tcdst != &tcsrc->destinations;
- tcdst = tcdst->next)
- {
- if (tcdst->link_quality >= MIN_LINK_QUALITY &&
- tcdst->inverse_link_quality >= MIN_LINK_QUALITY)
- {
- etx = 1.0 / (tcdst->link_quality * tcdst->inverse_link_quality);
-
- add_edge(&vertex_tree, &vertex_list, &tcdst->T_dest_addr,
- &tcsrc->T_last_addr, etx);
- }
+ /* find the interface for the link */
+ if (link->if_name) {
+ link->inter = if_ifwithname(link->if_name);
+ } else {
+ link->inter = if_ifwithaddr(&link->local_iface_addr);
}
- // run Dijkstra's algorithm
-
- for (;;)
- {
- vert = extract_best(&vertex_list);
-
- if (vert == NULL)
- break;
-
- relax(vert);
- }
-
- // save the old routing table
-
- olsr_move_route_table(routingtable, old_routes);
-
- node = list_get_head(&vertex_list);
-
- // we're the first vertex in the list
-
- myself = node->data;
-
- olsr_printf(2, "\n--- %02d:%02d:%02d.%02d ------------------------------------------------- DIJKSTRA\n\n",
- nowtm->tm_hour,
- nowtm->tm_min,
- nowtm->tm_sec,
- now.tv_usec/10000);
-
- for (node = list_get_next(node); node != NULL; node = list_get_next(node))
- {
- vert = node->data;
-
- hops = 1;
-
- // count hops to until the path ends or until we have reached a
- // one-hop neighbour
-
- for (walker = vert; walker != NULL && walker->prev != myself;
- walker = walker->prev)
- {
- olsr_printf(2, "%s:%s <- ", olsr_ip_to_string(&walker->addr),
- etx_to_string(walker->path_etx));
- hops++;
+ /*
+ * Set the next-hops of our neighbors.
+ */
+ if (!tc_edge) {
+ tc_edge = olsr_add_tc_edge_entry(tc_myself, &neigh->neighbor_main_addr,
+ 0, link->vtime);
+ } else {
+ /*
+ * Update LQ and timers, such that the edge does not get deleted.
+ */
+ olsr_copylq_link_entry_2_tc_edge_entry(tc_edge, link);
+ olsr_set_tc_edge_timer(tc_edge, link->vtime*1000);
+ olsr_calc_tc_edge_entry_etx(tc_edge);
+ }
+ if (tc_edge->edge_inv) {
+ tc_edge->edge_inv->tc->next_hop = link;
+ }
}
+ } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
- // if no path to a one-hop neighbour was found, ignore this node
+#ifdef SPF_PROFILING
+ gettimeofday(&t2, NULL);
+#endif
- if (walker != NULL)
- {
- olsr_printf(2, "%s:%s (one-hop)\n", olsr_ip_to_string(&walker->addr),
- etx_to_string(walker->path_etx));
+ /*
+ * Run the SPF calculation.
+ */
+ olsr_spf_run_full(&cand_tree, &path_list, &path_count);
- // node reachable => add to the set of unprocessed nodes
- // for HNA processing
+ OLSR_PRINTF(2, "\n--- %s ------------------------------------------------- DIJKSTRA\n\n",
+ olsr_wallclock_string());
- vert->done = OLSR_FALSE;
- }
+#ifdef SPF_PROFILING
+ gettimeofday(&t3, NULL);
+#endif
- else
- {
- olsr_printf(2, "FAILED\n", olsr_ip_to_string(&vert->addr));
+ /*
+ * In the path list we have all the reachable nodes in our topology.
+ */
+ for (; !list_is_empty(&path_list); list_remove(path_list.next)) {
+
+ tc = pathlist2tc(path_list.next);
+ link = tc->next_hop;
+
+ if (!link) {
+#ifdef DEBUG
+ /*
+ * Supress the error msg when our own tc_entry
+ * does not contain a next-hop.
+ */
+ if (tc != tc_myself) {
+#ifndef NODEBUG
+ struct ipaddr_str buf;
+#endif
+ OLSR_PRINTF(2, "SPF: %s no next-hop\n", olsr_ip_to_string(&buf, &tc->addr));
+ }
+#endif
continue;
}
-#if defined linux && 0
/*
- * on Linux we can add a new route for a destination before removing
- * the old route, so frequent route updates are not a problem, as
- * we never have a time window in which there isn't any route; hence
- * we can use the more volatile ETX value instead of the hop count
+ * Now walk all prefixes advertised by that node.
+ * Since the node is reachable, insert the prefix into the global RIB.
+ * If the prefix is already in the RIB, refresh the entry such
+ * that olsr_delete_outdated_routes() does not purge it off.
*/
+ for (rtp_tree_node = avl_walk_first(&tc->prefix_tree);
+ rtp_tree_node;
+ rtp_tree_node = avl_walk_next(rtp_tree_node)) {
- hops = (int)vert->path_etx;
-
- if (hops > 100)
- hops = 100;
-#endif
-
- // add a route to the main address of the destination node
-
- olsr_insert_routing_table(&vert->addr,
- get_neighbor_nexthop(&walker->addr), hops);
-
- // add routes to the remaining interfaces of the destination node
-
- for (mid_walker = mid_lookup_aliases(&vert->addr); mid_walker != NULL;
- mid_walker = mid_walker->next_alias)
- olsr_insert_routing_table(&mid_walker->alias,
- get_neighbor_nexthop(&walker->addr), hops);
- }
-
- // add HNA routes - the set of unprocessed network nodes contains
- // all reachable network nodes
-
- for (;;)
- {
- // extract the network node with the best ETX and remove it
- // from the set of unprocessed network nodes
-
- vert = extract_best(&vertex_list);
-
- // no more nodes left
-
- if (vert == NULL)
- break;
-
- // find the node's HNAs
+ rtp = rtp_prefix_tree2rtp(rtp_tree_node);
- hna_gw = olsr_lookup_hna_gw(&vert->addr);
+ if (rtp->rtp_rt) {
- // node doesn't announce any HNAs
-
- if (hna_gw == NULL)
- continue;
-
- // loop through the node's HNAs
-
- for (hna = hna_gw->networks.next; hna != &hna_gw->networks;
- hna = hna->next)
- {
- // we already have a route via a previous (better) node
-
- if (olsr_lookup_routing_table(&hna->A_network_addr) != NULL)
- continue;
+ /*
+ * If there is a route entry, the prefix is already in the global RIB.
+ */
+ olsr_update_rt_path(rtp, tc, link);
- // find route to the node
+ } else {
- gw_rt = olsr_lookup_routing_table(&hna_gw->A_gateway_addr);
-
- // should never happen as we only process reachable nodes
-
- if (gw_rt == NULL)
- {
- fprintf(stderr, "LQ HNA processing: Gateway without a route.");
- continue;
+ /*
+ * The prefix is reachable and not yet in the global RIB.
+ * Build a rt_entry for it.
+ */
+ olsr_insert_rt_path(rtp, tc, link);
}
-
- // create route for the HNA
-
- hna_rt = olsr_malloc(sizeof(struct rt_entry), "LQ HNA route entry");
-
- // set HNA IP address and netmask
-
- COPY_IP(&hna_rt->rt_dst, &hna->A_network_addr);
- hna_rt->rt_mask = hna->A_netmask;
-
- // copy remaining fields from the node's route
-
- COPY_IP(&hna_rt->rt_router, &gw_rt->rt_router);
- hna_rt->rt_metric = gw_rt->rt_metric;
- hna_rt->rt_if = gw_rt->rt_if;
-
- // we're not a host route
-
- hna_rt->rt_flags = RTF_UP | RTF_GATEWAY;
-
- // find the correct list
-
- head_rt = &routingtable[olsr_hashing(&hna->A_network_addr)];
-
- // enqueue
-
- head_rt->next->prev = hna_rt;
- hna_rt->next = head_rt->next;
-
- head_rt->next = hna_rt;
- hna_rt->prev = head_rt;
}
}
- // free the graph
+ /* Update the RIB based on the new SPF results */
+
+ olsr_update_rib_routes();
- free_everything(&vertex_list);
+#ifdef SPF_PROFILING
+ gettimeofday(&t4, NULL);
+#endif
- // move the route changes into the kernel
+ /* move the route changes into the kernel */
olsr_update_kernel_routes();
- // free the saved routing table
+#ifdef SPF_PROFILING
+ gettimeofday(&t5, NULL);
+#endif
- olsr_free_routing_table(old_routes);
+#ifdef SPF_PROFILING
+ timersub(&t2, &t1, &spf_init);
+ timersub(&t3, &t2, &spf_run);
+ timersub(&t4, &t3, &route);
+ timersub(&t5, &t4, &kernel);
+ timersub(&t5, &t1, &total);
+ OLSR_PRINTF(1, "\n--- SPF-stats for %d nodes, %d routes (total/init/run/route/kern): "
+ "%d, %d, %d, %d, %d\n",
+ path_count, routingtree.count,
+ (int)total.tv_usec, (int)spf_init.tv_usec, (int)spf_run.tv_usec,
+ (int)route.tv_usec, (int)kernel.tv_usec);
+#endif
}
+
+/*
+ * Local Variables:
+ * c-basic-offset: 2
+ * End:
+ */