serialized LQ data is not always 4 bytes long, so we need a function to precalculate...
[olsrd.git] / lib / lq_etx_float / src / lq_plugin_etx_float.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 "olsr_spf.h"
45 #include "lq_packet.h"
46 #include "olsr.h"
47 #include "olsr_logging.h"
48 #include "lq_plugin_etx_float.h"
49
50 #define PLUGIN_DESCR    "Floating point based ETX metric with exponential aging"
51 #define PLUGIN_AUTHOR   "Henning Rogge and others"
52
53 #define LQ_PLUGIN_LC_MULTIPLIER 1024
54
55 #define LQ_FLOAT_DEFAULT_AGING       0.05        /* 65536 * 0.05 */
56 #define LQ_FLOAT_QUICKSTART_AGING    0.25       /* 65536 * 0.25 */
57 #define LQ_QUICKSTART_STEPS        12
58
59 static int set_plugin_float(const char *, void *, set_plugin_parameter_addon);
60 static int lq_etxfloat_post_init(void);
61
62 static olsr_linkcost lq_etxfloat_calc_link_entry_cost(struct link_entry *);
63 static olsr_linkcost lq_etxfloat_calc_lq_hello_neighbor_cost(struct lq_hello_neighbor *);
64 static olsr_linkcost lq_etxfloat_calc_tc_mpr_addr_cost(struct tc_mpr_addr *);
65 static olsr_linkcost lq_etxfloat_calc_tc_edge_entry_cost(struct tc_edge_entry *);
66
67 static bool lq_etxfloat_is_relevant_costchange(olsr_linkcost c1, olsr_linkcost c2);
68
69 static olsr_linkcost lq_etxfloat_packet_loss_handler(struct link_entry *, bool);
70
71 static void lq_etxfloat_memorize_foreign_hello(struct link_entry *, struct lq_hello_neighbor *);
72 static void lq_etxfloat_copy_link_entry_lq_into_tc_mpr_addr(struct tc_mpr_addr *target, struct link_entry *source);
73 static void lq_etxfloat_copy_link_entry_lq_into_tc_edge_entry(struct tc_edge_entry *target, struct link_entry *source);
74 static void lq_etxfloat_copy_link_lq_into_neighbor(struct lq_hello_neighbor *target, struct link_entry *source);
75
76 static int lq_etxfloat_serialize_hello_lq(unsigned char *buff, struct lq_hello_neighbor *lq);
77 static int lq_etxfloat_serialize_tc_lq(unsigned char *buff, struct tc_mpr_addr *lq);
78 static void lq_etxfloat_deserialize_hello_lq(uint8_t const **curr, struct lq_hello_neighbor *lq);
79 static void lq_etxfloat_deserialize_tc_lq(uint8_t const **curr, struct tc_edge_entry *lq);
80
81 static char *lq_etxfloat_print_link_entry_lq(struct link_entry *entry, char separator, struct lqtextbuffer *buffer);
82 static char *lq_etxfloat_print_tc_edge_entry_lq(struct tc_edge_entry *ptr, char separator, struct lqtextbuffer *buffer);
83 static char *lq_etxfloat_print_cost(olsr_linkcost cost, struct lqtextbuffer *buffer);
84
85 /* etx lq plugin (freifunk fpm version) settings */
86 struct lq_handler lq_etxfloat_handler = {
87   "etx (float)",
88
89   NULL,
90   NULL,
91
92   &lq_etxfloat_calc_link_entry_cost,
93   &lq_etxfloat_calc_lq_hello_neighbor_cost,
94   &lq_etxfloat_calc_tc_mpr_addr_cost,
95   &lq_etxfloat_calc_tc_edge_entry_cost,
96
97   &lq_etxfloat_is_relevant_costchange,
98
99   &lq_etxfloat_packet_loss_handler,
100
101   &lq_etxfloat_memorize_foreign_hello,
102   &lq_etxfloat_copy_link_entry_lq_into_tc_mpr_addr,
103   &lq_etxfloat_copy_link_entry_lq_into_tc_edge_entry,
104   &lq_etxfloat_copy_link_lq_into_neighbor,
105
106   NULL,
107   NULL,
108   NULL,
109   NULL,
110
111   &lq_etxfloat_serialize_hello_lq,
112   &lq_etxfloat_serialize_tc_lq,
113   &lq_etxfloat_deserialize_hello_lq,
114   &lq_etxfloat_deserialize_tc_lq,
115
116   &lq_etxfloat_print_link_entry_lq,
117   &lq_etxfloat_print_tc_edge_entry_lq,
118   &lq_etxfloat_print_cost,
119
120   sizeof(struct lq_etxfloat_tc_edge),
121   sizeof(struct lq_etxfloat_tc_mpr_addr),
122   sizeof(struct lq_etxfloat_lq_hello_neighbor),
123   sizeof(struct lq_etxfloat_link_entry),
124
125   LQ_HELLO_MESSAGE,
126   LQ_TC_MESSAGE,
127
128   4,4
129 };
130
131 static float lq_aging = LQ_FLOAT_DEFAULT_AGING;
132
133 static const struct olsrd_plugin_parameters plugin_parameters[] = {
134   {.name = "LinkQualityAging",.set_plugin_parameter = &set_plugin_float,.data = &lq_aging},
135 };
136
137 DEFINE_PLUGIN6(PLUGIN_DESCR, PLUGIN_AUTHOR, NULL, lq_etxfloat_post_init, NULL, NULL, false, plugin_parameters)
138
139 static int
140 set_plugin_float(const char *value, void *data, set_plugin_parameter_addon addon __attribute__ ((unused)))
141 {
142   if (data != NULL) {
143     sscanf(value, "%f", (float *)data);
144     OLSR_INFO(LOG_LQ_PLUGINS, "%s float %f\n", "Got", *(float *)data);
145   } else {
146     OLSR_INFO(LOG_LQ_PLUGINS, "%s float %s\n", "Ignored", value);
147   }
148   return 0;
149 }
150
151 static int lq_etxfloat_post_init(void) {
152   active_lq_handler = &lq_etxfloat_handler;
153   return 0;
154 }
155
156 static olsr_linkcost
157 lq_etxfloat_calc_linkcost(struct lq_etxfloat_linkquality *lq)
158 {
159   olsr_linkcost cost;
160
161   if (lq->valueLq < MINIMAL_USEFUL_LQ || lq->valueNlq < MINIMAL_USEFUL_LQ) {
162     return LINK_COST_BROKEN;
163   }
164
165   cost = (olsr_linkcost) (1.0 / (lq->valueLq * lq->valueNlq) * LQ_PLUGIN_LC_MULTIPLIER);
166
167   if (cost > LINK_COST_BROKEN)
168     return LINK_COST_BROKEN;
169   if (cost == 0) {
170     return 1;
171   }
172   return cost;
173 }
174
175 static olsr_linkcost
176 lq_etxfloat_calc_link_entry_cost(struct link_entry *link)
177 {
178   struct lq_etxfloat_link_entry *lq_link = (struct lq_etxfloat_link_entry *)link;
179
180   return lq_etxfloat_calc_linkcost(&lq_link->lq);
181 }
182
183 static olsr_linkcost
184 lq_etxfloat_calc_lq_hello_neighbor_cost(struct lq_hello_neighbor *neigh)
185 {
186   struct lq_etxfloat_lq_hello_neighbor *lq_neigh = (struct lq_etxfloat_lq_hello_neighbor *)neigh;
187
188   return lq_etxfloat_calc_linkcost(&lq_neigh->lq);
189 }
190
191 static olsr_linkcost
192 lq_etxfloat_calc_tc_mpr_addr_cost(struct tc_mpr_addr *mpr)
193 {
194   struct lq_etxfloat_tc_mpr_addr *lq_mpr = (struct lq_etxfloat_tc_mpr_addr *)mpr;
195
196   return lq_etxfloat_calc_linkcost(&lq_mpr->lq);
197 }
198
199 static olsr_linkcost
200 lq_etxfloat_calc_tc_edge_entry_cost(struct tc_edge_entry *edge)
201 {
202   struct lq_etxfloat_tc_edge *lq_edge = (struct lq_etxfloat_tc_edge *)edge;
203
204   return lq_etxfloat_calc_linkcost(&lq_edge->lq);
205 }
206
207 static bool
208 lq_etxfloat_is_relevant_costchange(olsr_linkcost c1, olsr_linkcost c2)
209 {
210   if (c1 > c2) {
211     return c2 - c1 > LQ_PLUGIN_RELEVANT_COSTCHANGE;
212   }
213   return c1 - c2 > LQ_PLUGIN_RELEVANT_COSTCHANGE;
214 }
215
216 static olsr_linkcost
217 lq_etxfloat_packet_loss_handler(struct link_entry *link, bool loss)
218 {
219   struct lq_etxfloat_link_entry *lq_link = (struct lq_etxfloat_link_entry *)link;
220
221   float alpha = lq_aging;
222
223   if (lq_link->quickstart < LQ_QUICKSTART_STEPS) {
224     /* fast enough to get the LQ value within 6 Hellos up to 0.9 */
225     alpha = LQ_FLOAT_QUICKSTART_AGING;
226     lq_link->quickstart++;
227   }
228   // exponential moving average
229   lq_link->lq.valueLq *= (1 - alpha);
230   if (!loss) {
231     lq_link->lq.valueLq += (alpha * link->loss_link_multiplier / 65536);
232   }
233   return lq_etxfloat_calc_linkcost(&lq_link->lq);
234 }
235
236 static void
237 lq_etxfloat_memorize_foreign_hello(struct link_entry *target, struct lq_hello_neighbor *source)
238 {
239   struct lq_etxfloat_link_entry *lq_target = (struct lq_etxfloat_link_entry *)target;
240   struct lq_etxfloat_lq_hello_neighbor *lq_source = (struct lq_etxfloat_lq_hello_neighbor *)source;
241
242   if (source) {
243     lq_target->lq.valueNlq = lq_source->lq.valueLq;
244   } else {
245     lq_target->lq.valueNlq = 0;
246   }
247
248 }
249
250 static void
251 lq_etxfloat_copy_link_entry_lq_into_tc_mpr_addr(struct tc_mpr_addr *target, struct link_entry *source)
252 {
253   struct lq_etxfloat_tc_mpr_addr *lq_target = (struct lq_etxfloat_tc_mpr_addr *)target;
254   struct lq_etxfloat_link_entry *lq_source = (struct lq_etxfloat_link_entry *)source;
255
256   lq_target->lq = lq_source->lq;
257 }
258
259 static void
260 lq_etxfloat_copy_link_entry_lq_into_tc_edge_entry(struct tc_edge_entry *target, struct link_entry *source)
261 {
262   struct lq_etxfloat_tc_edge *lq_target = (struct lq_etxfloat_tc_edge *)target;
263   struct lq_etxfloat_link_entry *lq_source = (struct lq_etxfloat_link_entry *)source;
264
265   lq_target->lq = lq_source->lq;
266 }
267
268 static void
269 lq_etxfloat_copy_link_lq_into_neighbor(struct lq_hello_neighbor *target, struct link_entry *source)
270 {
271   struct lq_etxfloat_lq_hello_neighbor *lq_target = (struct lq_etxfloat_lq_hello_neighbor *)target;
272   struct lq_etxfloat_link_entry *lq_source = (struct lq_etxfloat_link_entry *)source;
273
274   lq_target->lq = lq_source->lq;
275 }
276
277 static int
278 lq_etxfloat_serialize_hello_lq(unsigned char *buff, struct lq_hello_neighbor *neigh)
279 {
280   struct lq_etxfloat_lq_hello_neighbor *lq_neigh = (struct lq_etxfloat_lq_hello_neighbor *)neigh;
281
282   buff[0] = (unsigned char)(lq_neigh->lq.valueLq * 255);
283   buff[1] = (unsigned char)(lq_neigh->lq.valueNlq * 255);
284   buff[2] = (unsigned char)(0);
285   buff[3] = (unsigned char)(0);
286
287   return 4;
288 }
289 static int
290 lq_etxfloat_serialize_tc_lq(unsigned char *buff, struct tc_mpr_addr *mpr)
291 {
292   struct lq_etxfloat_tc_mpr_addr *lq_mpr = (struct lq_etxfloat_tc_mpr_addr *)mpr;
293
294   buff[0] = (unsigned char)(lq_mpr->lq.valueLq * 255);
295   buff[1] = (unsigned char)(lq_mpr->lq.valueNlq * 255);
296   buff[2] = (unsigned char)(0);
297   buff[3] = (unsigned char)(0);
298
299   return 4;
300 }
301
302 static void
303 lq_etxfloat_deserialize_hello_lq(uint8_t const **curr, struct lq_hello_neighbor *neigh)
304 {
305   struct lq_etxfloat_lq_hello_neighbor *lq_neigh = (struct lq_etxfloat_lq_hello_neighbor *)neigh;
306
307   uint8_t lq_value, nlq_value;
308
309   pkt_get_u8(curr, &lq_value);
310   pkt_get_u8(curr, &nlq_value);
311   pkt_ignore_u16(curr);
312
313   lq_neigh->lq.valueLq = (float)lq_value / 255.0;
314   lq_neigh->lq.valueNlq = (float)nlq_value / 255.0;
315 }
316
317 static void
318 lq_etxfloat_deserialize_tc_lq(uint8_t const **curr, struct tc_edge_entry *edge)
319 {
320   struct lq_etxfloat_tc_edge *lq_edge = (struct lq_etxfloat_tc_edge *)edge;
321
322   uint8_t lq_value, nlq_value;
323
324   pkt_get_u8(curr, &lq_value);
325   pkt_get_u8(curr, &nlq_value);
326   pkt_ignore_u16(curr);
327
328   lq_edge->lq.valueLq = (float)lq_value / 255.0;
329   lq_edge->lq.valueNlq = (float)nlq_value / 255.0;
330 }
331
332 static char *
333 lq_etxfloat_print_lq(struct lq_etxfloat_linkquality *lq, char separator, struct lqtextbuffer *buffer)
334 {
335   snprintf(buffer->buf, sizeof(struct lqtextbuffer), "%2.3f%c%2.3f", lq->valueLq, separator, lq->valueNlq);
336   return buffer->buf;
337 }
338
339 static char *
340 lq_etxfloat_print_link_entry_lq(struct link_entry *link, char separator, struct lqtextbuffer *buffer)
341 {
342   struct lq_etxfloat_link_entry *lq_link = (struct lq_etxfloat_link_entry *)link;
343
344   return lq_etxfloat_print_lq(&lq_link->lq, separator, buffer);
345 }
346
347 static char *
348 lq_etxfloat_print_tc_edge_entry_lq(struct tc_edge_entry *edge, char separator, struct lqtextbuffer *buffer)
349 {
350   struct lq_etxfloat_tc_edge *lq_edge = (struct lq_etxfloat_tc_edge *)edge;
351
352   return lq_etxfloat_print_lq(&lq_edge->lq, separator, buffer);
353 }
354
355 static char *
356 lq_etxfloat_print_cost(olsr_linkcost cost, struct lqtextbuffer *buffer)
357 {
358   // must calculate
359   snprintf(buffer->buf, sizeof(struct lqtextbuffer), "%2.3f", ((float)cost) / LQ_PLUGIN_LC_MULTIPLIER);
360   return buffer->buf;
361 }
362
363 /*
364  * Local Variables:
365  * c-basic-offset: 2
366  * indent-tabs-mode: nil
367  * End:
368  */