Use ETX for HNA routes, too.
[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.21 2005/01/22 12:25:25 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_route.h"
51
52 struct dijk_edge
53 {
54   struct list_node node;
55   struct dijk_vertex *dest;
56   float etx;
57 };
58
59 struct dijk_vertex
60 {
61   struct list_node node;
62   union olsr_ip_addr addr;
63   struct list edge_list;
64   float path_etx;
65   struct dijk_vertex *prev;
66   olsr_bool done;
67 };
68
69 // XXX - bad complexity
70
71 static void add_vertex(struct list *vertex_list, union olsr_ip_addr *addr,
72                        float path_etx)
73 {
74   struct list_node *node;
75   struct dijk_vertex *vert;
76
77   // see whether this destination is already in our list
78
79   node = list_get_head(vertex_list);
80
81   while (node != NULL)
82   {
83     vert = node->data;
84
85     if (COMP_IP(&vert->addr, addr))
86       break;
87
88     node = list_get_next(node);
89   }
90
91   // if it's not in our list, add it
92
93   if (node == NULL)
94   {
95     vert = olsr_malloc(sizeof (struct dijk_vertex), "Dijkstra vertex");
96
97     vert->node.data = vert;
98
99     COPY_IP(&vert->addr, addr);
100     
101     vert->path_etx = path_etx;
102     vert->prev = NULL;
103     vert->done = OLSR_FALSE;
104
105     list_init(&vert->edge_list);
106
107     list_add_tail(vertex_list, &vert->node);
108   }
109 }
110
111 // XXX - bad complexity
112
113 static void add_edge(struct list *vertex_list, union olsr_ip_addr *src,
114                      union olsr_ip_addr *dst, float etx)
115 {
116   struct list_node *node;
117   struct dijk_vertex *vert;
118   struct dijk_vertex *svert;
119   struct dijk_vertex *dvert;
120   struct dijk_edge *edge;
121
122   // source and destination lookup
123
124   node = list_get_head(vertex_list);
125
126   svert = NULL;
127   dvert = NULL;
128
129   while (node != NULL)
130   {
131     vert = node->data;
132
133     if (COMP_IP(&vert->addr, src))
134     {
135       svert = vert;
136
137       if (dvert != NULL)
138         break;
139     }
140
141     else if (COMP_IP(&vert->addr, dst))
142     {
143       dvert = vert;
144
145       if (svert != NULL)
146         break;
147     }
148
149     node = list_get_next(node);
150   }
151
152   // source or destination vertex does not exist
153
154   if (svert == NULL || dvert == NULL)
155     return;
156
157   node = list_get_head(&svert->edge_list);
158
159   while (node != NULL)
160   {
161     edge = node->data;
162
163     if (edge->dest == dvert)
164       break;
165
166     node = list_get_next(node);
167   }
168
169   // edge already exists
170
171   if (node != NULL)
172     return;
173
174   edge = olsr_malloc(sizeof (struct dijk_vertex), "Dijkstra edge");
175
176   edge->node.data = edge;
177
178   edge->dest = dvert;
179   edge->etx = etx;
180
181   list_add_tail(&svert->edge_list, &edge->node);
182 }
183
184 static void free_everything(struct list *vertex_list)
185 {
186   struct list_node *vnode, *enode;
187   struct dijk_vertex *vert;
188   struct dijk_edge *edge;
189
190   vnode = list_get_head(vertex_list);
191
192   // loop through all vertices
193
194   while (vnode != NULL)
195   {
196     vert = vnode->data;
197
198     enode = list_get_head(&vert->edge_list);
199
200     // loop through all edges of the current vertex
201
202     while (enode != NULL)
203     {
204       edge = enode->data;
205
206       enode = list_get_next(enode);
207       free(edge);
208     }
209
210     vnode = list_get_next(vnode);
211     free(vert);
212   }
213 }
214
215 // XXX - bad complexity
216
217 static struct dijk_vertex *extract_best(struct list *vertex_list)
218 {
219   float best_etx = INFINITE_ETX + 1.0;
220   struct list_node *node;
221   struct dijk_vertex *vert;
222   struct dijk_vertex *res = NULL;
223
224   node = list_get_head(vertex_list);
225
226   // loop through all vertices
227   
228   while (node != NULL)
229   {
230     vert = node->data;
231
232     // see whether the current vertex is better than what we have
233
234     if (!vert->done && vert->path_etx < best_etx)
235     {
236       best_etx = vert->path_etx;
237       res = vert;
238     }
239
240     node = list_get_next(node);
241   }
242
243   // if we've found a vertex, remove it from the set
244
245   if (res != NULL)
246     res->done = OLSR_TRUE;
247
248   return res;
249 }
250
251 static void relax(struct dijk_vertex *vert)
252 {
253   struct dijk_edge *edge;
254   float new_etx;
255   struct list_node *node;
256
257   node = list_get_head(&vert->edge_list);
258
259   // loop through all edges of this vertex
260
261   while (node != NULL)
262   {
263     edge = node->data;
264
265     // total quality of the path through this vertex to the
266     // destination of this edge
267
268     new_etx = vert->path_etx + edge->etx;
269
270     // if it's better than the current path quality of this
271     // edge's destination, then we've found a better path to
272     // this destination
273
274     if (new_etx < edge->dest->path_etx)
275     {
276       edge->dest->path_etx = new_etx;
277       edge->dest->prev = vert;
278     }
279
280     node = list_get_next(node);
281   }
282 }
283
284 static char *etx_to_string(float etx)
285 {
286   static char buff[20];
287
288   if (etx == INFINITE_ETX)
289     return "INF";
290
291   sprintf(buff, "%.2f", etx);
292   return buff;
293 }
294
295 void olsr_calculate_lq_routing_table(void)
296 {
297   struct list vertex_list;
298   int i;
299   struct tc_entry *tcsrc;
300   struct topo_dst *tcdst;
301   struct dijk_vertex *vert;
302   struct link_entry *link;
303   struct neighbor_entry *neigh;
304   struct list_node *node;
305   struct dijk_vertex *myself;
306   struct dijk_vertex *walker;
307   int hops;
308   struct mid_address *mid_walker;
309   float etx;
310   struct hna_entry *hna_gw;
311   struct hna_net *hna;
312   struct rt_entry *gw_rt, *hna_rt, *head_rt;
313
314   // initialize the graph
315
316   list_init(&vertex_list);
317
318   // add ourselves to the vertex list
319
320   add_vertex(&vertex_list, &main_addr, 0.0);
321
322   // add our neighbours
323
324   for (i = 0; i < HASHSIZE; i++)
325     for (neigh = neighbortable[i].next; neigh != &neighbortable[i];
326          neigh = neigh->next)
327       if (neigh->status == SYM)
328         add_vertex(&vertex_list, &neigh->neighbor_main_addr, INFINITE_ETX);
329
330   // add remaining vertices
331
332   for (i = 0; i < HASHSIZE; i++)
333     for (tcsrc = tc_table[i].next; tcsrc != &tc_table[i]; tcsrc = tcsrc->next)
334     {
335       // add source
336
337       add_vertex(&vertex_list, &tcsrc->T_last_addr, INFINITE_ETX);
338
339       // add destinations of this source
340
341       for (tcdst = tcsrc->destinations.next; tcdst != &tcsrc->destinations;
342            tcdst = tcdst->next)
343         add_vertex(&vertex_list, &tcdst->T_dest_addr, INFINITE_ETX);
344     }
345
346   // add edges to and from our neighbours
347
348   for (i = 0; i < HASHSIZE; i++)
349     for (neigh = neighbortable[i].next; neigh != &neighbortable[i];
350          neigh = neigh->next)
351       if (neigh->status == SYM)
352       {
353         link = olsr_neighbor_best_link(&neigh->neighbor_main_addr);
354
355         if (link->loss_link_quality >= MIN_LINK_QUALITY &&
356             link->neigh_link_quality >= MIN_LINK_QUALITY)
357           {
358             etx = 1.0 / (link->loss_link_quality * link->neigh_link_quality);
359
360             add_edge(&vertex_list, &main_addr, &neigh->neighbor_main_addr,
361                      etx);
362
363             add_edge(&vertex_list, &neigh->neighbor_main_addr, &main_addr,
364                      etx);
365           }
366       }
367
368   // add remaining edges
369
370   for (i = 0; i < HASHSIZE; i++)
371     for (tcsrc = tc_table[i].next; tcsrc != &tc_table[i]; tcsrc = tcsrc->next)
372       for (tcdst = tcsrc->destinations.next; tcdst != &tcsrc->destinations;
373            tcdst = tcdst->next)
374       {
375         if (tcdst->link_quality >= MIN_LINK_QUALITY &&
376             tcdst->inverse_link_quality >= MIN_LINK_QUALITY)
377           {
378             etx = 1.0 / (tcdst->link_quality * tcdst->inverse_link_quality);
379
380             add_edge(&vertex_list, &tcsrc->T_last_addr, &tcdst->T_dest_addr,
381                      etx);
382
383             add_edge(&vertex_list, &tcdst->T_dest_addr, &tcsrc->T_last_addr,
384                      etx);
385           }
386       }
387
388   // run Dijkstra's algorithm
389
390   for (;;)
391   {
392     vert = extract_best(&vertex_list);
393
394     if (vert == NULL)
395       break;
396
397     relax(vert);
398   }
399
400   // save the old routing table
401
402   olsr_move_route_table(routingtable, old_routes);
403
404   node = list_get_head(&vertex_list);
405
406   // we're the first vertex in the list
407   
408   myself = node->data;
409
410   olsr_printf(2, "\n--- %02d:%02d:%02d.%02d ------------------------------------------------- DIJKSTRA\n\n",
411               nowtm->tm_hour,
412               nowtm->tm_min,
413               nowtm->tm_sec,
414               now.tv_usec/10000);
415
416   for (node = list_get_next(node); node != NULL; node = list_get_next(node))
417   {
418     vert = node->data;
419
420     hops = 1;
421
422     // count hops to until the path ends or until we have reached a
423     // one-hop neighbour
424
425     for (walker = vert; walker != NULL && walker->prev != myself;
426          walker = walker->prev)
427     {
428       olsr_printf(2, "%s:%s <- ", olsr_ip_to_string(&walker->addr),
429                   etx_to_string(walker->path_etx));
430       hops++;
431     }
432
433     // if no path to a one-hop neighbour was found, ignore this node
434
435     if (walker != NULL)
436     {
437       olsr_printf(2, "%s:%s (one-hop)\n", olsr_ip_to_string(&walker->addr),
438                   etx_to_string(walker->path_etx));
439
440       // node reachable => add to the set of unprocessed nodes
441       // for HNA processing
442
443       vert->done = OLSR_FALSE;
444     }
445
446     else
447     {
448       olsr_printf(2, "FAILED\n", olsr_ip_to_string(&vert->addr));
449       continue;
450     }
451
452 #if defined linux && 0
453     /*
454      * on Linux we can add a new route for a destination before removing
455      * the old route, so frequent route updates are not a problem, as
456      * we never have a time window in which there isn't any route; hence
457      * we can use the more volatile ETX value instead of the hop count
458      */
459
460     hops = (int)vert->path_etx;
461
462     if (hops > 100)
463       hops = 100;
464 #endif
465
466     // add a route to the main address of the destination node
467
468     olsr_insert_routing_table(&vert->addr,
469                               get_neighbor_nexthop(&walker->addr), hops);
470
471     // add routes to the remaining interfaces of the destination node
472
473     for (mid_walker = mid_lookup_aliases(&vert->addr); mid_walker != NULL;
474          mid_walker = mid_walker->next_alias)
475       olsr_insert_routing_table(&mid_walker->alias,
476                                 get_neighbor_nexthop(&walker->addr), hops);
477   }
478
479   // add HNA routes - the set of unprocessed network nodes contains
480   // all reachable network nodes
481
482   for (;;)
483   {
484     // extract the network node with the best ETX and remove it
485     // from the set of unprocessed network nodes
486
487     vert = extract_best(&vertex_list);
488
489     // no more nodes left
490
491     if (vert == NULL)
492       break;
493
494     // find the node's HNAs
495
496     hna_gw = olsr_lookup_hna_gw(&vert->addr);
497
498     // node doesn't announce any HNAs
499
500     if (hna_gw == NULL)
501       continue;
502
503     // loop through the node's HNAs
504
505     for (hna = hna_gw->networks.next; hna != &hna_gw->networks;
506          hna = hna->next)
507     {
508       // we already have a route via a previous (better) node
509
510       if (olsr_lookup_routing_table(&hna->A_network_addr) != NULL)
511         continue;
512
513       // find route to the node
514
515       gw_rt = olsr_lookup_routing_table(&hna_gw->A_gateway_addr);
516
517       // should never happen as we only process reachable nodes
518
519       if (gw_rt == NULL)
520       {
521         fprintf(stderr, "LQ HNA processing: Gateway without a route.");
522         continue;
523       }
524
525       // create route for the HNA
526
527       hna_rt = olsr_malloc(sizeof(struct rt_entry), "LQ HNA route entry");
528
529       // set HNA IP address and netmask
530
531       COPY_IP(&hna_rt->rt_dst, &hna->A_network_addr);
532       hna_rt->rt_mask = hna->A_netmask;
533
534       // copy remaining fields from the node's route
535
536       COPY_IP(&hna_rt->rt_router, &gw_rt->rt_router);
537       hna_rt->rt_metric = gw_rt->rt_metric;
538       hna_rt->rt_if = gw_rt->rt_if;
539
540       // we're not a host route
541
542       hna_rt->rt_flags = RTF_UP | RTF_GATEWAY;
543
544       // find the correct list
545
546       head_rt = &routingtable[olsr_hashing(&hna->A_network_addr)];
547
548       // enqueue
549
550       head_rt->next->prev = hna_rt;
551       hna_rt->next = head_rt->next;
552
553       head_rt->next = hna_rt;
554       hna_rt->prev = head_rt;
555     }
556   }
557
558   // free the graph
559
560   free_everything(&vertex_list);
561
562   // move the route changes into the kernel
563
564   olsr_update_kernel_routes();
565
566   // free the saved routing table
567
568   olsr_free_routing_table(old_routes);
569 }