olsr_ip_to_string() now only overwrites the buffer after four ivocations.
[olsrd.git] / src / lq_route.c
1 /* 
2  * OLSR ad-hoc routing table management protocol
3  * Copyright (C) 2004 Thomas Lopatic (thomas@lopatic.de)
4  *
5  * This file is part of the olsr.org OLSR daemon.
6  *
7  * olsr.org is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * olsr.org is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with olsr.org; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * $Id: lq_route.c,v 1.11 2004/11/15 14:59:38 tlopatic Exp $
22  *
23  */
24
25 #if defined USE_LINK_QUALITY
26 #include "defs.h"
27 #include "tc_set.h"
28 #include "neighbor_table.h"
29 #include "link_set.h"
30 #include "routing_table.h"
31 #include "mid_set.h"
32 #include "lq_list.h"
33 #include "lq_route.h"
34
35 #define INFINITE_ETX (1 << 30)
36 #define MIN_LINK_QUALITY 0.0001
37
38 struct dijk_edge
39 {
40   struct list_node node;
41   struct dijk_vertex *dest;
42   int etx;
43 };
44
45 struct dijk_vertex
46 {
47   struct list_node node;
48   union olsr_ip_addr addr;
49   struct list edge_list;
50   int path_etx;
51   struct dijk_vertex *prev;
52   olsr_bool done;
53 };
54
55 // XXX - bad complexity
56
57 static void add_vertex(struct list *vertex_list, union olsr_ip_addr *addr,
58                        int path_etx)
59 {
60   struct list_node *node;
61   struct dijk_vertex *vert;
62
63   // see whether this destination is already in our list
64
65   node = list_get_head(vertex_list);
66
67   while (node != NULL)
68   {
69     vert = node->data;
70
71     if (COMP_IP(&vert->addr, addr))
72       break;
73
74     node = list_get_next(node);
75   }
76
77   // if it's not in our list, add it
78
79   if (node == NULL)
80   {
81     vert = olsr_malloc(sizeof (struct dijk_vertex), "Dijkstra vertex");
82
83     vert->node.data = vert;
84
85     COPY_IP(&vert->addr, addr);
86     
87     vert->path_etx = path_etx;
88     vert->prev = NULL;
89     vert->done = OLSR_FALSE;
90
91     list_init(&vert->edge_list);
92
93     list_add_tail(vertex_list, &vert->node);
94   }
95 }
96
97 // XXX - bad complexity
98
99 static void add_edge(struct list *vertex_list, union olsr_ip_addr *src,
100                      union olsr_ip_addr *dst, int etx)
101 {
102   struct list_node *node;
103   struct dijk_vertex *vert;
104   struct dijk_vertex *svert;
105   struct dijk_vertex *dvert;
106   struct dijk_edge *edge;
107
108   // source and destination lookup
109
110   node = list_get_head(vertex_list);
111
112   svert = NULL;
113   dvert = NULL;
114
115   while (node != NULL)
116   {
117     vert = node->data;
118
119     if (COMP_IP(&vert->addr, src))
120     {
121       svert = vert;
122
123       if (dvert != NULL)
124         break;
125     }
126
127     else if (COMP_IP(&vert->addr, dst))
128     {
129       dvert = vert;
130
131       if (svert != NULL)
132         break;
133     }
134
135     node = list_get_next(node);
136   }
137
138   // source or destination vertex does not exist
139
140   if (svert == NULL || dvert == NULL)
141     return;
142
143   node = list_get_head(&svert->edge_list);
144
145   while (node != NULL)
146   {
147     edge = node->data;
148
149     if (edge->dest == dvert)
150       break;
151
152     node = list_get_next(node);
153   }
154
155   // edge already exists
156
157   if (node != NULL)
158     return;
159
160   edge = olsr_malloc(sizeof (struct dijk_vertex), "Dijkstra edge");
161
162   edge->node.data = edge;
163
164   edge->dest = dvert;
165   edge->etx = etx;
166
167   list_add_tail(&svert->edge_list, &edge->node);
168 }
169
170 static void free_everything(struct list *vertex_list)
171 {
172   struct list_node *vnode, *enode;
173   struct dijk_vertex *vert;
174   struct dijk_edge *edge;
175
176   vnode = list_get_head(vertex_list);
177
178   // loop through all vertices
179
180   while (vnode != NULL)
181   {
182     vert = vnode->data;
183
184     enode = list_get_head(&vert->edge_list);
185
186     // loop through all edges of the current vertex
187
188     while (enode != NULL)
189     {
190       edge = enode->data;
191
192       enode = list_get_next(enode);
193       free(edge);
194     }
195
196     vnode = list_get_next(vnode);
197     free(vert);
198   }
199 }
200
201 // XXX - bad complexity
202
203 static struct dijk_vertex *extract_best(struct list *vertex_list)
204 {
205   int best_etx = INFINITE_ETX + 1;
206   struct list_node *node;
207   struct dijk_vertex *vert;
208   struct dijk_vertex *res = NULL;
209
210   node = list_get_head(vertex_list);
211
212   // loop through all vertices
213   
214   while (node != NULL)
215   {
216     vert = node->data;
217
218     // see whether the current vertex is better than what we have
219
220     if (!vert->done && vert->path_etx < best_etx)
221     {
222       best_etx = vert->path_etx;
223       res = vert;
224     }
225
226     node = list_get_next(node);
227   }
228
229   // if we've found a vertex, remove it from the set
230
231   if (res != NULL)
232     res->done = OLSR_TRUE;
233
234   return res;
235 }
236
237 static void relax(struct dijk_vertex *vert)
238 {
239   struct dijk_edge *edge;
240   int new_etx;
241   struct list_node *node;
242
243   node = list_get_head(&vert->edge_list);
244
245   // loop through all edges of this vertex
246
247   while (node != NULL)
248   {
249     edge = node->data;
250
251     // total quality of the path through this vertex to the
252     // destination of this edge
253
254     new_etx = vert->path_etx + edge->etx;
255
256     // if it's better than the current path quality of this
257     // edge's destination, then we've found a better path to
258     // this destination
259
260     if (new_etx < edge->dest->path_etx)
261     {
262       edge->dest->path_etx = new_etx;
263       edge->dest->prev = vert;
264     }
265
266     node = list_get_next(node);
267   }
268 }
269
270 static char *etx_to_string(int etx)
271 {
272   static char buff[10];
273
274   if (etx == INFINITE_ETX)
275     return "INF";
276
277   sprintf(buff, "%d", etx);
278   return buff;
279 }
280
281 void olsr_calculate_lq_routing_table(void)
282 {
283   struct list vertex_list;
284   int i;
285   struct tc_entry *tcsrc;
286   struct topo_dst *tcdst;
287   struct dijk_vertex *vert;
288   struct link_entry *link;
289   struct neighbor_entry *neigh;
290   struct list_node *node;
291   struct dijk_vertex *myself;
292   struct dijk_vertex *walker;
293   int hops;
294   struct addresses *mid_walker;
295
296   // initialize the graph
297
298   list_init(&vertex_list);
299
300   // add ourselves to the vertex list
301
302   add_vertex(&vertex_list, &main_addr, 0);
303
304   // add our neighbours
305
306   for (i = 0; i < HASHSIZE; i++)
307     for (neigh = neighbortable[i].next; neigh != &neighbortable[i];
308          neigh = neigh->next)
309       if (neigh->status == SYM)
310         add_vertex(&vertex_list, &neigh->neighbor_main_addr, INFINITE_ETX);
311
312   // add remaining vertices
313
314   for (i = 0; i < HASHSIZE; i++)
315     for (tcsrc = tc_table[i].next; tcsrc != &tc_table[i]; tcsrc = tcsrc->next)
316     {
317       // add source
318
319       add_vertex(&vertex_list, &tcsrc->T_last_addr, INFINITE_ETX);
320
321       // add destinations of this source
322
323       for (tcdst = tcsrc->destinations.next; tcdst != &tcsrc->destinations;
324            tcdst = tcdst->next)
325         add_vertex(&vertex_list, &tcdst->T_dest_addr, INFINITE_ETX);
326     }
327
328   // add edges to and from our neighbours
329
330   for (i = 0; i < HASHSIZE; i++)
331     for (neigh = neighbortable[i].next; neigh != &neighbortable[i];
332          neigh = neigh->next)
333       if (neigh->status == SYM)
334       {
335         link = olsr_neighbor_best_link(&neigh->neighbor_main_addr);
336
337         if (link->neigh_link_quality >= MIN_LINK_QUALITY)
338           add_edge(&vertex_list, &main_addr, &neigh->neighbor_main_addr,
339                    (int)(1.0 / link->neigh_link_quality));
340
341         link = olsr_neighbor_best_inverse_link(&neigh->neighbor_main_addr);
342
343         if (link->loss_link_quality >= MIN_LINK_QUALITY)
344           add_edge(&vertex_list, &neigh->neighbor_main_addr, &main_addr,
345                    (int)(1.0 / link->loss_link_quality));
346       }
347
348   // add remaining edges
349
350   for (i = 0; i < HASHSIZE; i++)
351     for (tcsrc = tc_table[i].next; tcsrc != &tc_table[i]; tcsrc = tcsrc->next)
352       for (tcdst = tcsrc->destinations.next; tcdst != &tcsrc->destinations;
353            tcdst = tcdst->next)
354       {
355         if (tcdst->link_quality >= MIN_LINK_QUALITY)
356           add_edge(&vertex_list, &tcsrc->T_last_addr, &tcdst->T_dest_addr,
357                    (int)(1.0 / tcdst->link_quality));
358
359         if (tcdst->inverse_link_quality >= MIN_LINK_QUALITY)
360           add_edge(&vertex_list, &tcdst->T_dest_addr, &tcsrc->T_last_addr,
361                    (int)(1.0 / tcdst->inverse_link_quality));
362       }
363
364   // run Dijkstra's algorithm
365
366   for (;;)
367   {
368     vert = extract_best(&vertex_list);
369
370     if (vert == NULL)
371       break;
372
373     relax(vert);
374   }
375
376   // save the old routing table
377
378   olsr_move_route_table(routingtable, old_routes);
379
380   node = list_get_head(&vertex_list);
381
382   // we're the first vertex in the list
383   
384   myself = node->data;
385
386   olsr_printf(2, "\n--- %02d:%02d:%02d.%02d ------------------------------------------------- DIJKSTRA\n\n",
387               nowtm->tm_hour,
388               nowtm->tm_min,
389               nowtm->tm_sec,
390               now.tv_usec/10000);
391
392   for (node = list_get_next(node); node != NULL; node = list_get_next(node))
393   {
394     vert = node->data;
395
396     hops = 1;
397
398     // count hops to until the path ends or until we have reached a
399     // one-hop neighbour
400
401     for (walker = vert; walker != NULL && walker->prev != myself;
402          walker = walker->prev)
403     {
404       olsr_printf(2, "%s:%s <- ", olsr_ip_to_string(&walker->addr),
405                   etx_to_string(walker->path_etx));
406       hops++;
407     }
408
409     // if no path to a one-hop neighbour was found, ignore this node
410
411     if (walker != NULL)
412       olsr_printf(2, "%s:%s (one-hop)\n", olsr_ip_to_string(&walker->addr),
413                   etx_to_string(walker->path_etx));
414
415     else
416     {
417       olsr_printf(2, "FAILED\n", olsr_ip_to_string(&vert->addr));
418       continue;
419     }
420
421     // add a route to the main address of the destination node
422
423     olsr_insert_routing_table(&vert->addr, &walker->addr, hops);
424
425     // add routes to the remaining interfaces of the destination node
426
427     for (mid_walker = mid_lookup_aliases(&vert->addr); mid_walker != NULL;
428          mid_walker = mid_walker->next)
429       olsr_insert_routing_table(&mid_walker->address, &walker->addr, hops);
430   }
431
432   // free the graph
433
434   free_everything(&vertex_list);
435
436   // move the route changes into the kernel
437
438   olsr_update_kernel_routes();
439
440   // free the saved routing table
441
442   olsr_free_routing_table(old_routes);
443 }
444 #endif