Convert lq_etx_float to new plugin system
[olsrd.git] / lib / lq_etx_ff / src / lq_plugin_etx_ff.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include "tc_set.h"
43 #include "link_set.h"
44 #include "lq_plugin.h"
45 #include "olsr_spf.h"
46 #include "lq_packet.h"
47 #include "olsr.h"
48 #include "lq_plugin_etx_ff.h"
49 #include "parser.h"
50 #include "mid_set.h"
51 #include "scheduler.h"
52 #include "olsr_logging.h"
53
54 #define LQ_PLUGIN_RELEVANT_COSTCHANGE_FF 16
55
56 static int lq_etxff_post_init(void);
57
58 static void lq_etxff_initialize(void);
59 static void lq_etxff_deinitialize(void);
60
61 static olsr_linkcost lq_etxff_calc_link_entry_cost(struct link_entry *);
62 static olsr_linkcost lq_etxff_calc_lq_hello_neighbor_cost(struct lq_hello_neighbor *);
63 static olsr_linkcost lq_etxff_calc_tc_mpr_addr_cost(struct tc_mpr_addr *);
64 static olsr_linkcost lq_etxff_calc_tc_edge_entry_cost(struct tc_edge_entry *);
65
66 static bool lq_etxff_is_relevant_costchange(olsr_linkcost c1, olsr_linkcost c2);
67
68 static olsr_linkcost lq_etxff_packet_loss_handler(struct link_entry *, bool);
69
70 static void lq_etxff_memorize_foreign_hello(struct link_entry *, struct lq_hello_neighbor *);
71 static void lq_etxff_copy_link_entry_lq_into_tc_mpr_addr(struct tc_mpr_addr *target, struct link_entry *source);
72 static void lq_etxff_copy_link_entry_lq_into_tc_edge_entry(struct tc_edge_entry *target, struct link_entry *source);
73 static void lq_etxff_copy_link_lq_into_neighbor(struct lq_hello_neighbor *target, struct link_entry *source);
74
75 static void lq_etxff_clear_link_entry(struct link_entry *);
76
77 static int lq_etxff_serialize_hello_lq(unsigned char *buff, struct lq_hello_neighbor *lq);
78 static int lq_etxff_serialize_tc_lq(unsigned char *buff, struct tc_mpr_addr *lq);
79 static void lq_etxff_deserialize_hello_lq(uint8_t const **curr, struct lq_hello_neighbor *lq);
80 static void lq_etxff_deserialize_tc_lq(uint8_t const **curr, struct tc_edge_entry *lq);
81
82 static char *lq_etxff_print_link_entry_lq(struct link_entry *entry, char separator, struct lqtextbuffer *buffer);
83 static char *lq_etxff_print_tc_edge_entry_lq(struct tc_edge_entry *ptr, char separator, struct lqtextbuffer *buffer);
84 static char *lq_etxff_print_cost(olsr_linkcost cost, struct lqtextbuffer *buffer);
85
86 static struct olsr_cookie_info *default_lq_ff_timer_cookie = NULL;
87
88 DEFINE_PLUGIN6_NP(PLUGIN_DESCR, PLUGIN_AUTHOR, NULL, lq_etxff_post_init, NULL, NULL, true)
89
90 /* etx lq plugin (freifunk fpm version) settings */
91 struct lq_handler lq_etxff_handler = {
92   "etx (freifunk)",
93
94   &lq_etxff_initialize,
95   &lq_etxff_deinitialize,
96
97   &lq_etxff_calc_link_entry_cost,
98   &lq_etxff_calc_lq_hello_neighbor_cost,
99   &lq_etxff_calc_tc_mpr_addr_cost,
100   &lq_etxff_calc_tc_edge_entry_cost,
101
102   &lq_etxff_is_relevant_costchange,
103
104   &lq_etxff_packet_loss_handler,
105
106   &lq_etxff_memorize_foreign_hello,
107   &lq_etxff_copy_link_entry_lq_into_tc_mpr_addr,
108   &lq_etxff_copy_link_entry_lq_into_tc_edge_entry,
109   &lq_etxff_copy_link_lq_into_neighbor,
110
111   &lq_etxff_clear_link_entry,
112   NULL,
113   NULL,
114   NULL,
115
116   &lq_etxff_serialize_hello_lq,
117   &lq_etxff_serialize_tc_lq,
118   &lq_etxff_deserialize_hello_lq,
119   &lq_etxff_deserialize_tc_lq,
120
121   &lq_etxff_print_link_entry_lq,
122   &lq_etxff_print_tc_edge_entry_lq,
123   &lq_etxff_print_cost,
124
125   sizeof(struct lq_etxff_tc_edge),
126   sizeof(struct lq_etxff_tc_mpr_addr),
127   sizeof(struct lq_etxff_lq_hello_neighbor),
128   sizeof(struct lq_etxff_link_entry),
129
130   LQ_HELLO_MESSAGE,
131   LQ_TC_MESSAGE
132 };
133
134 static int lq_etxff_post_init(void) {
135   active_lq_handler = &lq_etxff_handler;
136   return 0;
137 }
138
139 static void
140 lq_etxff_packet_parser(struct olsr *olsr, struct interface *in_if, union olsr_ip_addr *from_addr)
141 {
142   const union olsr_ip_addr *main_addr;
143   struct lq_etxff_link_entry *lnk;
144   uint32_t seq_diff;
145
146   /* Find main address */
147   main_addr = olsr_lookup_main_addr_by_alias(from_addr);
148
149   /* Loopup link entry */
150   lnk = (struct lq_etxff_link_entry *)lookup_link_entry(from_addr, main_addr, in_if);
151   if (lnk == NULL) {
152     return;
153   }
154
155   if (lnk->last_seq_nr == olsr->olsr_seqno) {
156 #ifndef REMOVE_LOG_WARN
157     struct ipaddr_str buf;
158 #endif
159     OLSR_WARN(LOG_LQ_PLUGINS, "Got package with same sequence number from %s\n", olsr_ip_to_string(&buf, from_addr));
160     return;
161   }
162   if (lnk->last_seq_nr > olsr->olsr_seqno) {
163     seq_diff = (uint32_t) olsr->olsr_seqno + 65536 - lnk->last_seq_nr;
164   } else {
165     seq_diff = olsr->olsr_seqno - lnk->last_seq_nr;
166   }
167
168   /* Jump in sequence numbers ? */
169   if (seq_diff > 256) {
170     seq_diff = 1;
171   }
172
173   lnk->received[lnk->activePtr]++;
174   lnk->lost[lnk->activePtr] += (seq_diff - 1);
175
176   lnk->last_seq_nr = olsr->olsr_seqno;
177   lnk->missed_seconds = 0;
178 }
179
180 static void
181 lq_etxff_timer(void __attribute__ ((unused)) * context)
182 {
183   struct link_entry *link;
184   OLSR_FOR_ALL_LINK_ENTRIES(link) {
185     struct lq_etxff_link_entry *lq_link;
186     uint32_t ratio;
187     uint16_t i, received, lost;
188
189 #ifndef REMOVE_LOG_DEBUG
190     struct ipaddr_str buf;
191     // struct lqtextbuffer lqbuffer;
192 #endif
193     lq_link = (struct lq_etxff_link_entry *)link;
194
195     OLSR_DEBUG(LOG_LQ_PLUGINS, "LQ-FF new entry for %s: rec: %d lost: %d",
196                olsr_ip_to_string(&buf, &link->neighbor_iface_addr),
197                lq_link->received[lq_link->activePtr], lq_link->lost[lq_link->activePtr]);
198
199     received = 0;
200     lost = 0;
201
202     /* enlarge window if still in quickstart phase */
203     if (lq_link->windowSize < LQ_FF_WINDOW) {
204       lq_link->windowSize++;
205     }
206     for (i = 0; i < lq_link->windowSize; i++) {
207       received += lq_link->received[i];
208       lost += lq_link->lost[i];
209     }
210
211     OLSR_DEBUG(LOG_LQ_PLUGINS, " total-rec: %d total-lost: %d", received, lost);
212
213     /* calculate link quality */
214     if (received + lost == 0) {
215       lq_link->lq.valueLq = 0;
216     } else {
217
218       /* keep missed hello periods in mind (round up hello interval to seconds) */
219       uint32_t missed_hello_cost = lq_link->missed_seconds / ((lq_link->core.link_loss_timer->timer_period + 999) / 1000);
220       lost += missed_hello_cost * missed_hello_cost;
221
222       // start with link-loss-factor
223       ratio = link->loss_link_multiplier;
224
225       // calculate received/(received + loss) factor
226       ratio = ratio * received;
227       ratio = ratio / (received + lost);
228       ratio = (ratio * 255) >> 16;
229
230       lq_link->lq.valueLq = (uint8_t) (ratio);
231     }
232
233     // shift buffer
234     lq_link->activePtr = (lq_link->activePtr + 1) % LQ_FF_WINDOW;
235     lq_link->lost[lq_link->activePtr] = 0;
236     lq_link->received[lq_link->activePtr] = 0;
237     lq_link->missed_seconds++;
238   }
239   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
240 }
241
242 static struct timer_entry *lq_etxff_timer_struct = NULL;
243
244 static void
245 lq_etxff_initialize(void)
246 {
247   /* Some cookies for stats keeping */
248   olsr_packetparser_add_function(&lq_etxff_packet_parser);
249   default_lq_ff_timer_cookie = olsr_alloc_cookie("Default Freifunk LQ", OLSR_COOKIE_TYPE_TIMER);
250   lq_etxff_timer_struct = olsr_start_timer(1000, 0, OLSR_TIMER_PERIODIC, &lq_etxff_timer, NULL, default_lq_ff_timer_cookie);
251 }
252
253 static void
254 lq_etxff_deinitialize(void)
255 {
256   olsr_stop_timer(lq_etxff_timer_struct);
257   olsr_packetparser_remove_function(&lq_etxff_packet_parser);
258 }
259
260 static olsr_linkcost
261 lq_etxff_calc_linkcost(struct lq_etxff_linkquality *lq)
262 {
263   olsr_linkcost cost;
264
265   if (lq->valueLq < (unsigned int)(255 * MINIMAL_USEFUL_LQ) || lq->valueNlq < (unsigned int)(255 * MINIMAL_USEFUL_LQ)) {
266     return LINK_COST_BROKEN;
267   }
268
269   cost = 65536 * 255 / (int)lq->valueLq * 255 / (int)lq->valueNlq;
270
271   if (cost > LINK_COST_BROKEN)
272     return LINK_COST_BROKEN;
273   if (cost == 0)
274     return 1;
275   return cost;
276 }
277
278 static olsr_linkcost
279 lq_etxff_calc_link_entry_cost(struct link_entry *link)
280 {
281   struct lq_etxff_link_entry *lq_link = (struct lq_etxff_link_entry *)link;
282
283   return lq_etxff_calc_linkcost(&lq_link->lq);
284 }
285
286 static olsr_linkcost
287 lq_etxff_calc_lq_hello_neighbor_cost(struct lq_hello_neighbor *neigh)
288 {
289   struct lq_etxff_lq_hello_neighbor *lq_neigh = (struct lq_etxff_lq_hello_neighbor *)neigh;
290
291   return lq_etxff_calc_linkcost(&lq_neigh->lq);
292 }
293
294 static olsr_linkcost
295 lq_etxff_calc_tc_mpr_addr_cost(struct tc_mpr_addr *mpr)
296 {
297   struct lq_etxff_tc_mpr_addr *lq_mpr = (struct lq_etxff_tc_mpr_addr *)mpr;
298
299   return lq_etxff_calc_linkcost(&lq_mpr->lq);
300 }
301
302 static olsr_linkcost
303 lq_etxff_calc_tc_edge_entry_cost(struct tc_edge_entry *edge)
304 {
305   struct lq_etxff_tc_edge *lq_edge = (struct lq_etxff_tc_edge *)edge;
306
307   return lq_etxff_calc_linkcost(&lq_edge->lq);
308 }
309
310 static bool
311 lq_etxff_is_relevant_costchange(olsr_linkcost c1, olsr_linkcost c2)
312 {
313   if (c1 > c2) {
314     return c2 - c1 > LQ_PLUGIN_RELEVANT_COSTCHANGE_FF;
315   }
316   return c1 - c2 > LQ_PLUGIN_RELEVANT_COSTCHANGE_FF;
317 }
318
319 static olsr_linkcost
320 lq_etxff_packet_loss_handler(struct link_entry *link, bool loss __attribute__ ((unused)))
321 {
322   return lq_etxff_calc_link_entry_cost(link);
323 }
324
325 static void
326 lq_etxff_memorize_foreign_hello(struct link_entry *target, struct lq_hello_neighbor *source)
327 {
328   struct lq_etxff_link_entry *lq_target = (struct lq_etxff_link_entry *)target;
329   struct lq_etxff_lq_hello_neighbor *lq_source = (struct lq_etxff_lq_hello_neighbor *)source;
330
331   if (source) {
332     lq_target->lq.valueNlq = lq_source->lq.valueLq;
333   } else {
334     lq_target->lq.valueNlq = 0;
335   }
336
337 }
338
339 static void
340 lq_etxff_copy_link_entry_lq_into_tc_mpr_addr(struct tc_mpr_addr *target, struct link_entry *source)
341 {
342   struct lq_etxff_tc_mpr_addr *lq_target = (struct lq_etxff_tc_mpr_addr *)target;
343   struct lq_etxff_link_entry *lq_source = (struct lq_etxff_link_entry *)source;
344
345   lq_target->lq = lq_source->lq;
346 }
347
348 static void
349 lq_etxff_copy_link_entry_lq_into_tc_edge_entry(struct tc_edge_entry *target, struct link_entry *source)
350 {
351   struct lq_etxff_tc_edge *lq_target = (struct lq_etxff_tc_edge *)target;
352   struct lq_etxff_link_entry *lq_source = (struct lq_etxff_link_entry *)source;
353
354   lq_target->lq = lq_source->lq;
355 }
356
357 static void
358 lq_etxff_copy_link_lq_into_neighbor(struct lq_hello_neighbor *target, struct link_entry *source)
359 {
360   struct lq_etxff_lq_hello_neighbor *lq_target = (struct lq_etxff_lq_hello_neighbor *)target;
361   struct lq_etxff_link_entry *lq_source = (struct lq_etxff_link_entry *)source;
362
363   lq_target->lq = lq_source->lq;
364 }
365
366 static void
367 lq_etxff_clear_link_entry(struct link_entry *link)
368 {
369   struct lq_etxff_link_entry *lq_link = (struct lq_etxff_link_entry *)link;
370   int i;
371
372   lq_link->windowSize = LQ_FF_QUICKSTART_INIT;
373   for (i = 0; i < LQ_FF_WINDOW; i++) {
374     lq_link->lost[i] = 3;
375   }
376 }
377
378 static int
379 lq_etxff_serialize_hello_lq(unsigned char *buff, struct lq_hello_neighbor *neigh)
380 {
381   struct lq_etxff_lq_hello_neighbor *lq_neigh = (struct lq_etxff_lq_hello_neighbor *)neigh;
382
383   buff[0] = (unsigned char)lq_neigh->lq.valueLq;
384   buff[1] = (unsigned char)lq_neigh->lq.valueNlq;
385   buff[2] = (unsigned char)(0);
386   buff[3] = (unsigned char)(0);
387
388   return 4;
389 }
390 static int
391 lq_etxff_serialize_tc_lq(unsigned char *buff, struct tc_mpr_addr *mpr)
392 {
393   struct lq_etxff_tc_mpr_addr *lq_mpr = (struct lq_etxff_tc_mpr_addr *)mpr;
394
395   buff[0] = (unsigned char)lq_mpr->lq.valueLq;
396   buff[1] = (unsigned char)lq_mpr->lq.valueNlq;
397   buff[2] = (unsigned char)(0);
398   buff[3] = (unsigned char)(0);
399
400   return 4;
401 }
402
403 static void
404 lq_etxff_deserialize_hello_lq(uint8_t const **curr, struct lq_hello_neighbor *neigh)
405 {
406   struct lq_etxff_lq_hello_neighbor *lq_neigh = (struct lq_etxff_lq_hello_neighbor *)neigh;
407
408   pkt_get_u8(curr, &lq_neigh->lq.valueLq);
409   pkt_get_u8(curr, &lq_neigh->lq.valueNlq);
410   pkt_ignore_u16(curr);
411
412 }
413 static void
414 lq_etxff_deserialize_tc_lq(uint8_t const **curr, struct tc_edge_entry *edge)
415 {
416   struct lq_etxff_tc_edge *lq_edge = (struct lq_etxff_tc_edge *)edge;
417
418   pkt_get_u8(curr, &lq_edge->lq.valueLq);
419   pkt_get_u8(curr, &lq_edge->lq.valueNlq);
420   pkt_ignore_u16(curr);
421 }
422
423 static char *
424 lq_etxff_print_lq(struct lq_etxff_linkquality *lq, char separator, struct lqtextbuffer *buffer)
425 {
426   int i = 0;
427
428   if (lq->valueLq == 255) {
429     strcpy(buffer->buf, "1.000");
430     i += 5;
431   } else {
432     i = sprintf(buffer->buf, "0.%03d", (lq->valueLq * 1000) / 255);
433   }
434   buffer->buf[i++] = separator;
435
436   if (lq->valueNlq == 255) {
437     strcpy(&buffer->buf[i], "1.000");
438   } else {
439     sprintf(&buffer->buf[i], "0.%03d", (lq->valueNlq * 1000) / 255);
440   }
441   return buffer->buf;
442 }
443
444 static char *
445 lq_etxff_print_link_entry_lq(struct link_entry *link, char separator, struct lqtextbuffer *buffer)
446 {
447   struct lq_etxff_link_entry *lq_link = (struct lq_etxff_link_entry *)link;
448
449   return lq_etxff_print_lq(&lq_link->lq, separator, buffer);
450 }
451
452 static char *
453 lq_etxff_print_tc_edge_entry_lq(struct tc_edge_entry *edge, char separator, struct lqtextbuffer *buffer)
454 {
455   struct lq_etxff_tc_edge *lq_edge = (struct lq_etxff_tc_edge *)edge;
456
457   return lq_etxff_print_lq(&lq_edge->lq, separator, buffer);
458 }
459
460 static char *
461 lq_etxff_print_cost(olsr_linkcost cost, struct lqtextbuffer *buffer)
462 {
463   // must calculate
464   uint32_t roundDown = cost >> 16;
465   uint32_t fraction = ((cost & 0xffff) * 1000) >> 16;
466
467   sprintf(buffer->buf, "%u.%03u", roundDown, fraction);
468   return buffer->buf;
469 }
470
471 /*
472  * Local Variables:
473  * c-basic-offset: 2
474  * indent-tabs-mode: nil
475  * End:
476  */