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