Performance optimization.
[olsrd.git] / src / lq_route.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Thomas Lopatic (thomas@lopatic.de)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright 
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright 
13  *   notice, this list of conditions and the following disclaimer in 
14  *   the documentation and/or other materials provided with the 
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its 
17  *   contributors may be used to endorse or promote products derived 
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  * $Id: lq_route.c,v 1.23 2005/01/24 10:35:58 tlopatic Exp $
40  */
41
42 #include "defs.h"
43 #include "tc_set.h"
44 #include "neighbor_table.h"
45 #include "link_set.h"
46 #include "routing_table.h"
47 #include "mid_set.h"
48 #include "hna_set.h"
49 #include "lq_list.h"
50 #include "lq_avl.h"
51 #include "lq_route.h"
52
53 struct dijk_edge
54 {
55   struct avl_node tree_node;
56   struct list_node node;
57   struct dijk_vertex *dest;
58   float etx;
59 };
60
61 struct dijk_vertex
62 {
63   struct avl_node tree_node;
64   struct list_node node;
65   union olsr_ip_addr addr;
66   struct avl_tree edge_tree;
67   struct list edge_list;
68   float path_etx;
69   struct dijk_vertex *prev;
70   olsr_bool done;
71 };
72
73 static int avl_comp_ipv6(void *ip1, void *ip2)
74 {
75   return memcmp(ip1, ip2, ipsize);
76 }
77
78 static int avl_comp_ipv4(void *ip1, void *ip2)
79 {
80   if (*(unsigned int *)ip1 < *(unsigned int *)ip2)
81     return -1;
82
83   if (*(unsigned int *)ip1 == *(unsigned int *)ip2)
84     return 0;
85
86   return 1;
87 }
88
89 static int (*avl_comp)(void *, void *);
90
91 static void add_vertex(struct avl_tree *vertex_tree, struct list *vertex_list,
92                        union olsr_ip_addr *addr, float path_etx)
93 {
94   struct avl_node *node;
95   struct dijk_vertex *vert;
96
97   // see whether this destination is already in our list
98
99   node = avl_find(vertex_tree, addr);
100
101   // if it's not in our list, add it
102
103   if (node == NULL)
104   {
105     vert = olsr_malloc(sizeof (struct dijk_vertex), "Dijkstra vertex");
106
107     vert->tree_node.data = vert;
108     vert->tree_node.key = &vert->addr;
109
110     vert->node.data = vert;
111
112     COPY_IP(&vert->addr, addr);
113     
114     vert->path_etx = path_etx;
115     vert->prev = NULL;
116     vert->done = OLSR_FALSE;
117
118     avl_init(&vert->edge_tree, avl_comp);
119     list_init(&vert->edge_list);
120
121     avl_insert(vertex_tree, &vert->tree_node);
122     list_add_tail(vertex_list, &vert->node);
123   }
124 }
125
126 static void add_edge(struct avl_tree *vertex_tree, struct list *vertex_list,
127                      union olsr_ip_addr *src, union olsr_ip_addr *dst,
128                      float etx)
129 {
130   struct avl_node *node;
131   struct dijk_vertex *svert;
132   struct dijk_vertex *dvert;
133   struct dijk_edge *edge;
134
135   // source lookup
136
137   node = avl_find(vertex_tree, src);
138
139   // source vertex does not exist
140
141   if (node == NULL)
142     return;
143
144   svert = node->data;
145
146   // destination lookup
147
148   node = avl_find(vertex_tree, dst);
149
150   // destination vertex does not exist
151
152   if (node == NULL)
153     return;
154
155   dvert = node->data;
156
157   // check for existing forward edge
158
159   if (avl_find(&svert->edge_tree, dst) == NULL)
160   {
161     // add forward edge
162
163     edge = olsr_malloc(sizeof (struct dijk_vertex), "Dijkstra edge 1");
164
165     edge->tree_node.data = edge;
166     edge->tree_node.key = &dvert->addr;
167
168     edge->node.data = edge;
169
170     edge->dest = dvert;
171     edge->etx = etx;
172
173     avl_insert(&svert->edge_tree, &edge->tree_node);
174     list_add_tail(&svert->edge_list, &edge->node);
175   }
176
177   // check for existing inverse edge
178
179   if (avl_find(&dvert->edge_tree, src) == NULL)
180   {
181     // add inverse edge
182
183     edge = olsr_malloc(sizeof (struct dijk_vertex), "Dijkstra edge 2");
184
185     edge->tree_node.data = edge;
186     edge->tree_node.key = &svert->addr;
187
188     edge->node.data = edge;
189
190     edge->dest = svert;
191     edge->etx = etx;
192
193     avl_insert(&dvert->edge_tree, &edge->tree_node);
194     list_add_tail(&dvert->edge_list, &edge->node);
195   }
196 }
197
198 static void free_everything(struct list *vertex_list)
199 {
200   struct list_node *vnode, *enode;
201   struct dijk_vertex *vert;
202   struct dijk_edge *edge;
203
204   vnode = list_get_head(vertex_list);
205
206   // loop through all vertices
207
208   while (vnode != NULL)
209   {
210     vert = vnode->data;
211
212     enode = list_get_head(&vert->edge_list);
213
214     // loop through all edges of the current vertex
215
216     while (enode != NULL)
217     {
218       edge = enode->data;
219
220       enode = list_get_next(enode);
221       free(edge);
222     }
223
224     vnode = list_get_next(vnode);
225     free(vert);
226   }
227 }
228
229 // XXX - bad complexity
230
231 static struct dijk_vertex *extract_best(struct list *vertex_list)
232 {
233   float best_etx = INFINITE_ETX + 1.0;
234   struct list_node *node;
235   struct dijk_vertex *vert;
236   struct dijk_vertex *res = NULL;
237
238   node = list_get_head(vertex_list);
239
240   // loop through all vertices
241   
242   while (node != NULL)
243   {
244     vert = node->data;
245
246     // see whether the current vertex is better than what we have
247
248     if (!vert->done && vert->path_etx < best_etx)
249     {
250       best_etx = vert->path_etx;
251       res = vert;
252     }
253
254     node = list_get_next(node);
255   }
256
257   // if we've found a vertex, remove it from the set
258
259   if (res != NULL)
260     res->done = OLSR_TRUE;
261
262   return res;
263 }
264
265 static void relax(struct dijk_vertex *vert)
266 {
267   struct dijk_edge *edge;
268   float new_etx;
269   struct list_node *node;
270
271   node = list_get_head(&vert->edge_list);
272
273   // loop through all edges of this vertex
274
275   while (node != NULL)
276   {
277     edge = node->data;
278
279     // total quality of the path through this vertex to the
280     // destination of this edge
281
282     new_etx = vert->path_etx + edge->etx;
283
284     // if it's better than the current path quality of this
285     // edge's destination, then we've found a better path to
286     // this destination
287
288     if (new_etx < edge->dest->path_etx)
289     {
290       edge->dest->path_etx = new_etx;
291       edge->dest->prev = vert;
292     }
293
294     node = list_get_next(node);
295   }
296 }
297
298 static char *etx_to_string(float etx)
299 {
300   static char buff[20];
301
302   if (etx == INFINITE_ETX)
303     return "INF";
304
305   sprintf(buff, "%.2f", etx);
306   return buff;
307 }
308
309 void olsr_calculate_lq_routing_table(void)
310 {
311   struct avl_tree vertex_tree;
312   struct list vertex_list;
313   int i;
314   struct tc_entry *tcsrc;
315   struct topo_dst *tcdst;
316   struct dijk_vertex *vert;
317   struct link_entry *link;
318   struct neighbor_entry *neigh;
319   struct list_node *node;
320   struct dijk_vertex *myself;
321   struct dijk_vertex *walker;
322   int hops;
323   struct mid_address *mid_walker;
324   float etx;
325   struct hna_entry *hna_gw;
326   struct hna_net *hna;
327   struct rt_entry *gw_rt, *hna_rt, *head_rt;
328
329   if (ipsize == 4)
330     avl_comp = avl_comp_ipv4;
331
332   else
333     avl_comp = avl_comp_ipv6;
334
335   // initialize the graph
336
337   avl_init(&vertex_tree, avl_comp);
338   list_init(&vertex_list);
339
340   // add ourselves to the vertex list
341
342   add_vertex(&vertex_tree, &vertex_list, &main_addr, 0.0);
343
344   // add our neighbours
345
346   for (i = 0; i < HASHSIZE; i++)
347     for (neigh = neighbortable[i].next; neigh != &neighbortable[i];
348          neigh = neigh->next)
349       if (neigh->status == SYM)
350         add_vertex(&vertex_tree, &vertex_list, &neigh->neighbor_main_addr,
351                    INFINITE_ETX);
352
353   // add remaining vertices
354
355   for (i = 0; i < HASHSIZE; i++)
356     for (tcsrc = tc_table[i].next; tcsrc != &tc_table[i]; tcsrc = tcsrc->next)
357     {
358       // add source
359
360       add_vertex(&vertex_tree, &vertex_list, &tcsrc->T_last_addr,
361                  INFINITE_ETX);
362
363       // add destinations of this source
364
365       for (tcdst = tcsrc->destinations.next; tcdst != &tcsrc->destinations;
366            tcdst = tcdst->next)
367         add_vertex(&vertex_tree, &vertex_list, &tcdst->T_dest_addr,
368                    INFINITE_ETX);
369     }
370
371   // add edges to and from our neighbours
372
373   for (i = 0; i < HASHSIZE; i++)
374     for (neigh = neighbortable[i].next; neigh != &neighbortable[i];
375          neigh = neigh->next)
376       if (neigh->status == SYM)
377       {
378         link = olsr_neighbor_best_link(&neigh->neighbor_main_addr);
379
380         if (link->loss_link_quality >= MIN_LINK_QUALITY &&
381             link->neigh_link_quality >= MIN_LINK_QUALITY)
382           {
383             etx = 1.0 / (link->loss_link_quality * link->neigh_link_quality);
384
385             add_edge(&vertex_tree, &vertex_list, &neigh->neighbor_main_addr,
386                      &main_addr, etx);
387           }
388       }
389
390   // add remaining edges
391
392   for (i = 0; i < HASHSIZE; i++)
393     for (tcsrc = tc_table[i].next; tcsrc != &tc_table[i]; tcsrc = tcsrc->next)
394       for (tcdst = tcsrc->destinations.next; tcdst != &tcsrc->destinations;
395            tcdst = tcdst->next)
396       {
397         if (tcdst->link_quality >= MIN_LINK_QUALITY &&
398             tcdst->inverse_link_quality >= MIN_LINK_QUALITY)
399           {
400             etx = 1.0 / (tcdst->link_quality * tcdst->inverse_link_quality);
401
402             add_edge(&vertex_tree, &vertex_list, &tcdst->T_dest_addr,
403                      &tcsrc->T_last_addr, etx);
404           }
405       }
406
407   // run Dijkstra's algorithm
408
409   for (;;)
410   {
411     vert = extract_best(&vertex_list);
412
413     if (vert == NULL)
414       break;
415
416     relax(vert);
417   }
418
419   // save the old routing table
420
421   olsr_move_route_table(routingtable, old_routes);
422
423   node = list_get_head(&vertex_list);
424
425   // we're the first vertex in the list
426   
427   myself = node->data;
428
429   olsr_printf(2, "\n--- %02d:%02d:%02d.%02d ------------------------------------------------- DIJKSTRA\n\n",
430               nowtm->tm_hour,
431               nowtm->tm_min,
432               nowtm->tm_sec,
433               now.tv_usec/10000);
434
435   for (node = list_get_next(node); node != NULL; node = list_get_next(node))
436   {
437     vert = node->data;
438
439     hops = 1;
440
441     // count hops to until the path ends or until we have reached a
442     // one-hop neighbour
443
444     for (walker = vert; walker != NULL && walker->prev != myself;
445          walker = walker->prev)
446     {
447       olsr_printf(2, "%s:%s <- ", olsr_ip_to_string(&walker->addr),
448                   etx_to_string(walker->path_etx));
449       hops++;
450     }
451
452     // if no path to a one-hop neighbour was found, ignore this node
453
454     if (walker != NULL)
455     {
456       olsr_printf(2, "%s:%s (one-hop)\n", olsr_ip_to_string(&walker->addr),
457                   etx_to_string(walker->path_etx));
458
459       // node reachable => add to the set of unprocessed nodes
460       // for HNA processing
461
462       vert->done = OLSR_FALSE;
463     }
464
465     else
466     {
467       olsr_printf(2, "FAILED\n", olsr_ip_to_string(&vert->addr));
468       continue;
469     }
470
471 #if defined linux && 0
472     /*
473      * on Linux we can add a new route for a destination before removing
474      * the old route, so frequent route updates are not a problem, as
475      * we never have a time window in which there isn't any route; hence
476      * we can use the more volatile ETX value instead of the hop count
477      */
478
479     hops = (int)vert->path_etx;
480
481     if (hops > 100)
482       hops = 100;
483 #endif
484
485     // add a route to the main address of the destination node
486
487     olsr_insert_routing_table(&vert->addr,
488                               get_neighbor_nexthop(&walker->addr), hops);
489
490     // add routes to the remaining interfaces of the destination node
491
492     for (mid_walker = mid_lookup_aliases(&vert->addr); mid_walker != NULL;
493          mid_walker = mid_walker->next_alias)
494       olsr_insert_routing_table(&mid_walker->alias,
495                                 get_neighbor_nexthop(&walker->addr), hops);
496   }
497
498   // add HNA routes - the set of unprocessed network nodes contains
499   // all reachable network nodes
500
501   for (;;)
502   {
503     // extract the network node with the best ETX and remove it
504     // from the set of unprocessed network nodes
505
506     vert = extract_best(&vertex_list);
507
508     // no more nodes left
509
510     if (vert == NULL)
511       break;
512
513     // find the node's HNAs
514
515     hna_gw = olsr_lookup_hna_gw(&vert->addr);
516
517     // node doesn't announce any HNAs
518
519     if (hna_gw == NULL)
520       continue;
521
522     // loop through the node's HNAs
523
524     for (hna = hna_gw->networks.next; hna != &hna_gw->networks;
525          hna = hna->next)
526     {
527       // we already have a route via a previous (better) node
528
529       if (olsr_lookup_routing_table(&hna->A_network_addr) != NULL)
530         continue;
531
532       // find route to the node
533
534       gw_rt = olsr_lookup_routing_table(&hna_gw->A_gateway_addr);
535
536       // should never happen as we only process reachable nodes
537
538       if (gw_rt == NULL)
539       {
540         fprintf(stderr, "LQ HNA processing: Gateway without a route.");
541         continue;
542       }
543
544       // create route for the HNA
545
546       hna_rt = olsr_malloc(sizeof(struct rt_entry), "LQ HNA route entry");
547
548       // set HNA IP address and netmask
549
550       COPY_IP(&hna_rt->rt_dst, &hna->A_network_addr);
551       hna_rt->rt_mask = hna->A_netmask;
552
553       // copy remaining fields from the node's route
554
555       COPY_IP(&hna_rt->rt_router, &gw_rt->rt_router);
556       hna_rt->rt_metric = gw_rt->rt_metric;
557       hna_rt->rt_if = gw_rt->rt_if;
558
559       // we're not a host route
560
561       hna_rt->rt_flags = RTF_UP | RTF_GATEWAY;
562
563       // find the correct list
564
565       head_rt = &routingtable[olsr_hashing(&hna->A_network_addr)];
566
567       // enqueue
568
569       head_rt->next->prev = hna_rt;
570       hna_rt->next = head_rt->next;
571
572       head_rt->next = hna_rt;
573       hna_rt->prev = head_rt;
574     }
575   }
576
577   // free the graph
578
579   free_everything(&vertex_list);
580
581   // move the route changes into the kernel
582
583   olsr_update_kernel_routes();
584
585   // free the saved routing table
586
587   olsr_free_routing_table(old_routes);
588 }