📄 lq_route.c
字号:
/* * 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 * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of olsr.org, olsrd nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Visit http://www.olsr.org for more information. * * If you find this software useful feel free to make a donation * to the project. For more information see the website or contact * the copyright holders. * * $Id: lq_route.c,v 1.53 2007/10/16 09:54:43 bernd67 Exp $ */#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 "lq_route.h"/* * 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 intavl_comp_etx (void *etx1, void *etx2){ if (*(float *)etx1 < *(float *)etx2) { return -1; } if (*(float *)etx1 > *(float *)etx2) { return +1; } return 0;}/* * olsr_spf_add_cand_tree * * Key an existing vertex to a candidate tree. */static voidolsr_spf_add_cand_tree (struct avl_tree *tree, struct tc_entry *vert){ vert->cand_tree_node.key = &vert->path_etx; vert->cand_tree_node.data = vert;#ifdef DEBUG OLSR_PRINTF(1, "SPF: insert candidate %s, cost %f\n", olsr_ip_to_string(&(vert->addr)), vert->path_etx);#endif avl_insert(tree, &vert->cand_tree_node, AVL_DUP);}/* * olsr_spf_del_cand_tree * * Unkey an existing vertex from a candidate tree. */static voidolsr_spf_del_cand_tree (struct avl_tree *tree, struct tc_entry *vert){#ifdef DEBUG OLSR_PRINTF(1, "SPF: delete candidate %s, cost %f\n", olsr_ip_to_string(&(vert->addr)), vert->path_etx);#endif avl_delete(tree, &vert->cand_tree_node);}/* * olsr_spf_add_path_list * * Insert an SPF result at the end of the path list. */static voidolsr_spf_add_path_list (struct list_node *head, int *path_count, struct tc_entry *vert){ vert->path_list_node.data = vert;#ifdef DEBUG OLSR_PRINTF(1, "SPF: append path %s, cost %f, via %s\n", olsr_ip_to_string(&(vert->addr)), vert->path_etx, olsr_ip_to_string(vert->next_hop ? &vert->next_hop->neighbor_iface_addr : NULL));#endif list_add_before(head, &vert->path_list_node); *path_count = *path_count + 1;}/* * olsr_spf_extract_best * * return the node with the minimum pathcost. */static struct tc_entry *olsr_spf_extract_best (struct avl_tree *tree){ struct avl_node *node; node = avl_walk_first(tree); return (node ? node->data : NULL);}char *olsr_etx_to_string(float etx){ static char buff[20]; if (etx == INFINITE_ETX) return "INF"; snprintf(buff, 20, "%.6f", etx); return buff;}/* * 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 voidolsr_spf_relax (struct avl_tree *cand_tree, struct tc_entry *vert){ struct tc_entry *new_vert; struct tc_edge_entry *tc_edge; struct avl_node *edge_node; float new_etx;#ifdef DEBUG OLSR_PRINTF(1, "SPF: exploring node %s, cost %f\n", olsr_ip_to_string(&(vert->addr)), vert->path_etx);#endif /* * loop through all edges of this vertex. */ for (edge_node = avl_walk_first(&vert->edge_tree); edge_node; edge_node = avl_walk_next(edge_node)) { tc_edge = edge_node->data; /* * We are not interested in dead-end or dying edges. */ if (!tc_edge->edge_inv || (tc_edge->flags & OLSR_TC_EDGE_DOWN)) {#ifdef DEBUG OLSR_PRINTF(1, "SPF: ignoring edge %s\n", olsr_ip_to_string(&tc_edge->T_dest_addr)); if (tc_edge->flags & OLSR_TC_EDGE_DOWN) { OLSR_PRINTF(1, "SPF: edge down\n"); } if (!tc_edge->edge_inv) { OLSR_PRINTF(1, "SPF: no inverse edge\n"); }#endif continue; } /* * total quality of the path through this vertex * to the destination of this edge */ new_etx = vert->path_etx + tc_edge->etx;#ifdef DEBUG OLSR_PRINTF(1, "SPF: exploring edge %s, cost %s\n", olsr_ip_to_string(&(tc_edge->T_dest_addr)), olsr_etx_to_string(new_vert->path_etx));#endif /* * 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_vert = tc_edge->edge_inv->tc; if (new_etx < new_vert->path_etx) { /* if this node has been on the candidate tree delete it */ if (new_vert->path_etx != INFINITE_ETX) { olsr_spf_del_cand_tree(cand_tree, new_vert); } /* re-insert on candidate tree with the better metric */ new_vert->path_etx = new_etx; olsr_spf_add_cand_tree(cand_tree, new_vert); /* pull-up the next-hop and bump the hop count */ if (vert->next_hop) { new_vert->next_hop = vert->next_hop; } new_vert->hops = vert->hops + 1;#ifdef DEBUG OLSR_PRINTF(1, "SPF: better path to %s, cost %s -> %s, via %s, hops %u\n", olsr_ip_to_string(&new_vert->addr), olsr_etx_to_string(new_vert->path_etx), olsr_etx_to_string(new_etx), olsr_ip_to_string(vert->next_hop ? &vert->next_hop->neighbor_iface_addr : NULL), new_vert->->hops);#endif } }}/* * 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 voidolsr_spf_run_full (struct avl_tree *cand_tree, struct list_node *path_list, int *path_count){ struct tc_entry *vert; *path_count = 0; while ((vert = olsr_spf_extract_best(cand_tree))) { olsr_spf_relax(cand_tree, vert); /* * move the best path from the candidate tree * to the path list. */ olsr_spf_del_cand_tree(cand_tree, vert); olsr_spf_add_path_list(path_list, path_count, vert); }}voidolsr_calculate_routing_table (void){ struct avl_tree cand_tree; struct list_node path_list; int i, plen, path_count = 0; struct tc_entry *tc; struct tc_edge_entry *tc_edge; struct tc_entry *vert; struct neighbor_entry *neigh; struct mid_address *mid_walker; struct hna_entry *hna_gw; struct hna_net *hna; struct interface *inter; struct link_entry *link;#ifdef SPF_PROFILING struct timeval t1, t2, t3, t4, t5, spf_init, spf_run, route, kernel, total; gettimeofday(&t1, NULL);#endif /* * 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_etx = INFINITE_ETX; 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_etx = ZERO_ETX; olsr_spf_add_cand_tree(&cand_tree, tc_myself); /* * 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) { 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; } /* * 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->last_htime, link->loss_link_quality2, link->neigh_link_quality2); } else { tc_edge->link_quality = link->loss_link_quality2; tc_edge->inverse_link_quality = link->neigh_link_quality2; olsr_calc_tc_edge_entry_etx(tc_edge); } if (tc_edge->edge_inv) { tc_edge->edge_inv->tc->next_hop = link; } } }#ifdef SPF_PROFILING gettimeofday(&t2, NULL);#endif /* * Run the SPF calculation. */ olsr_spf_run_full(&cand_tree, &path_list, &path_count); OLSR_PRINTF(2, "\n--- %02d:%02d:%02d.%02d ------------------------------------------------- DIJKSTRA\n\n", nowtm->tm_hour, nowtm->tm_min, nowtm->tm_sec, (int)now.tv_usec/10000);#ifdef SPF_PROFILING gettimeofday(&t3, NULL);#endif /* * In the path tree we have all the reachable nodes in our topology. */ for (; !list_is_empty(&path_list); list_remove(path_list.next)) { vert = path_list.next->data; link = vert->next_hop; if (!link) { OLSR_PRINTF(2, "%s no next-hop\n", olsr_ip_to_string(&vert->addr)); continue; } /* find the interface for the found link */ inter = link->if_name ? if_ifwithname(link->if_name) : if_ifwithaddr(&link->local_iface_addr); /* interface is up ? */ if (inter) { /* add a route to the main address of the destination node */ olsr_insert_routing_table(&vert->addr, olsr_cnf->maxplen, &vert->addr, &link->neighbor_iface_addr, inter->if_index, vert->hops, vert->path_etx); /* 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, olsr_cnf->maxplen, &vert->addr, &link->neighbor_iface_addr, inter->if_index, vert->hops, vert->path_etx); } /* find the node's HNAs */ hna_gw = olsr_lookup_hna_gw(&vert->addr); /* node doesn't announce any HNAs */ if (!hna_gw) { continue; } /* loop through the node's HNAs */ for (hna = hna_gw->networks.next; hna != &hna_gw->networks; hna = hna->next) { plen = olsr_get_hna_prefix_len(hna); if (vert->path_etx != INFINITE_ETX) olsr_insert_routing_table(&hna->A_network_addr, plen, &vert->addr, &link->neighbor_iface_addr, inter->if_index, vert->hops, vert->path_etx); } } }#ifdef SPF_PROFILING gettimeofday(&t4, NULL);#endif /* move the route changes into the kernel */ olsr_update_kernel_routes();#ifdef SPF_PROFILING gettimeofday(&t5, NULL);#endif#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: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -