Move from fixed cookie array to dynamic tree
[olsrd.git] / src / link_set.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 /*
43  * Link sensing database for the OLSR routing daemon
44  */
45
46 #include "defs.h"
47 #include "link_set.h"
48 #include "mid_set.h"
49 #include "neighbor_table.h"
50 #include "olsr.h"
51 #include "scheduler.h"
52 #include "olsr_spf.h"
53 #include "net_olsr.h"
54 #include "ipcalc.h"
55 #include "lq_plugin.h"
56 #include "common/string.h"
57 #include "olsr_logging.h"
58
59 /* head node for all link sets */
60 struct list_node link_entry_head;
61
62 static struct olsr_cookie_info *link_dead_timer_cookie = NULL;
63 static struct olsr_cookie_info *link_loss_timer_cookie = NULL;
64 static struct olsr_cookie_info *link_sym_timer_cookie = NULL;
65
66 bool link_changes;                     /* is set if changes occur in MPRS set */
67
68 void
69 signal_link_changes(bool val)
70 {                               /* XXX ugly */
71   link_changes = val;
72 }
73
74 /* Prototypes. */
75 static int check_link_status(const struct lq_hello_message *message, const struct interface *in_if);
76 static struct link_entry *add_link_entry(const union olsr_ip_addr *,
77                                          const union olsr_ip_addr *,
78                                          union olsr_ip_addr *, olsr_reltime, olsr_reltime, struct interface *);
79 static bool get_neighbor_status(const union olsr_ip_addr *);
80
81 void
82 olsr_init_link_set(void)
83 {
84   OLSR_INFO(LOG_LINKS, "Initialize linkset...\n");
85
86   /* Init list head */
87   list_head_init(&link_entry_head);
88
89   link_dead_timer_cookie = olsr_alloc_cookie("Link dead", OLSR_COOKIE_TYPE_TIMER);
90   link_loss_timer_cookie = olsr_alloc_cookie("Link loss", OLSR_COOKIE_TYPE_TIMER);
91   link_sym_timer_cookie = olsr_alloc_cookie("Link SYM", OLSR_COOKIE_TYPE_TIMER);
92
93 }
94
95
96 /**
97  * Get the status of a link. The status is based upon different
98  * timeouts in the link entry.
99  *
100  * @param remote address of the remote interface
101  * @return the link status of the link
102  */
103 int
104 lookup_link_status(const struct link_entry *entry)
105 {
106
107   if (entry == NULL || list_is_empty(&link_entry_head)) {
108     return UNSPEC_LINK;
109   }
110
111   /*
112    * Hysteresis
113    */
114   if (entry->link_sym_timer) {
115     return SYM_LINK;
116   }
117
118   if (!TIMED_OUT(entry->ASYM_time)) {
119     return ASYM_LINK;
120   }
121
122   return LOST_LINK;
123 }
124
125
126 /**
127  * Find the "best" link status to a neighbor
128  *
129  * @param address the address to check for
130  * @return true if a symmetric link exists false if not
131  */
132 static bool
133 get_neighbor_status(const union olsr_ip_addr *address)
134 {
135   const union olsr_ip_addr *main_addr;
136   struct interface *ifs;
137   struct tc_entry *tc;
138
139   /* Find main address */
140   if (!(main_addr = olsr_lookup_main_addr_by_alias(address)))
141     main_addr = address;
142
143   /*
144    * Locate the hookup point.
145    */
146   tc = olsr_locate_tc_entry(main_addr);
147
148   /* Loop trough local interfaces to check all possebilities */
149   OLSR_FOR_ALL_INTERFACES(ifs) {
150
151     struct mid_entry *aliases;
152     struct link_entry *lnk = lookup_link_entry(main_addr, NULL, ifs);
153
154     if (lnk != NULL) {
155       if (lookup_link_status(lnk) == SYM_LINK)
156         return true;
157     }
158
159     /* Walk the aliases */
160     OLSR_FOR_ALL_TC_MID_ENTRIES(tc, aliases) {
161
162       lnk = lookup_link_entry(&aliases->mid_alias_addr, NULL, ifs);
163       if (lnk && (lookup_link_status(lnk) == SYM_LINK)) {
164         return true;
165       }
166     }
167     OLSR_FOR_ALL_TC_MID_ENTRIES_END(tc, aliases);
168   }
169   OLSR_FOR_ALL_INTERFACES_END(ifs);
170
171   return false;
172 }
173
174 /**
175  * Find best link to a neighbor
176  */
177 struct link_entry *
178 get_best_link_to_neighbor(const union olsr_ip_addr *remote)
179 {
180   const union olsr_ip_addr *main_addr;
181   struct link_entry *walker, *good_link, *backup_link;
182   olsr_linkcost curr_lcost = LINK_COST_BROKEN;
183   olsr_linkcost tmp_lc;
184
185   /* main address lookup */
186   main_addr = olsr_lookup_main_addr_by_alias(remote);
187
188   /* "remote" *already is* the main address */
189   if (!main_addr) {
190     main_addr = remote;
191   }
192
193   /* we haven't selected any links, yet */
194   good_link = NULL;
195   backup_link = NULL;
196
197   /* loop through all links that we have */
198   OLSR_FOR_ALL_LINK_ENTRIES(walker) {
199
200     /* if this is not a link to the neighour in question, skip */
201     if (olsr_ipcmp(&walker->neighbor->nbr_addr, main_addr) != 0)
202       continue;
203
204     /* get the link cost */
205     tmp_lc = walker->linkcost;
206
207     /*
208      * is this link better than anything we had before ?
209      * use the requested remote interface address as a tie-breaker.
210      */
211     if ((tmp_lc < curr_lcost) || ((tmp_lc == curr_lcost) && olsr_ipcmp(&walker->local_iface_addr, remote) == 0)) {
212
213       /* memorize the link quality */
214       curr_lcost = tmp_lc;
215
216       /* prefer symmetric links over asymmetric links */
217       if (lookup_link_status(walker) == SYM_LINK) {
218         good_link = walker;
219       } else {
220         backup_link = walker;
221       }
222     }
223   }
224   OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
225
226   /*
227    * if we haven't found any symmetric links, try to return an asymmetric link.
228    */
229   return good_link ? good_link : backup_link;
230 }
231
232 static void
233 set_loss_link_multiplier(struct link_entry *entry)
234 {
235   struct interface *inter;
236   struct olsr_if_config *cfg_inter;
237   struct olsr_lq_mult *mult;
238   uint32_t val = 0;
239
240   /* find the interface for the link */
241   inter = if_ifwithaddr(&entry->local_iface_addr);
242
243   /* find the interface configuration for the interface */
244   for (cfg_inter = olsr_cnf->if_configs; cfg_inter; cfg_inter = cfg_inter->next) {
245     if (cfg_inter->interf == inter) {
246       break;
247     }
248   }
249
250   /* loop through the multiplier entries */
251   for (mult = cfg_inter->cnf->lq_mult; mult != NULL; mult = mult->next) {
252     /*
253      * use the default multiplier only if there isn't any entry that
254      * has a matching IP address.
255      */
256     if ((val == 0 && olsr_ipcmp(&mult->addr, &all_zero) == 0) || olsr_ipcmp(&mult->addr, &entry->neighbor_iface_addr) == 0) {
257       val = mult->value;
258     }
259   }
260
261   /* if we have not found an entry, then use the default multiplier */
262   if (val == 0) {
263     val = LINK_LOSS_MULTIPLIER;
264   }
265
266   /* store the multiplier */
267   entry->loss_link_multiplier = val;
268 }
269
270 /*
271  * Delete, unlink and free a link entry.
272  */
273 static void
274 olsr_delete_link_entry(struct link_entry *link)
275 {
276
277   /*
278    * Delete the corresponding tc-edge for that link.
279    */
280   if (link->link_tc_edge) {
281     olsr_delete_tc_edge_entry(link->link_tc_edge);
282     link->link_tc_edge = NULL;
283
284     changes_topology = true;
285   }
286
287   /*
288    * Delete the rt_path for the link-end.
289    */
290   olsr_delete_routing_table(&link->neighbor_iface_addr, 8 * olsr_cnf->ipsize,
291                             &link->neighbor->nbr_addr, OLSR_RT_ORIGIN_LINK);
292
293   /* Delete neighbor entry */
294   if (link->neighbor->linkcount == 1) {
295     olsr_delete_nbr_entry(link->neighbor);
296   } else {
297     link->neighbor->linkcount--;
298   }
299
300   /* Kill running timers */
301   olsr_stop_timer(link->link_timer);
302   link->link_timer = NULL;
303   olsr_stop_timer(link->link_sym_timer);
304   link->link_sym_timer = NULL;
305   olsr_stop_timer(link->link_loss_timer);
306   link->link_loss_timer = NULL;
307
308   list_remove(&link->link_list);
309
310   /* Unlink Interfaces */
311   unlock_interface(link->inter);
312   link->inter = NULL;
313
314   free(link->if_name);
315   olsr_free_link_entry(link);
316
317   changes_neighborhood = true;
318 }
319
320 /**
321  * Delete all link entries matching a given interface id
322  */
323 void
324 olsr_delete_link_entry_by_if(const struct interface *ifp)
325 {
326   struct link_entry *link;
327
328   if (list_is_empty(&link_entry_head)) {
329     return;
330   }
331
332   OLSR_FOR_ALL_LINK_ENTRIES(link) {
333     if (ifp == link->inter) {
334       olsr_delete_link_entry(link);
335     }
336   }
337   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
338 }
339
340 /**
341  * Callback for the link loss timer.
342  */
343 static void
344 olsr_expire_link_loss_timer(void *context)
345 {
346   struct link_entry *link;
347
348   link = (struct link_entry *)context;
349
350   /* count the lost packet */
351   olsr_update_packet_loss_worker(link, true);
352
353   /* next timeout in 1.0 x htime */
354   olsr_change_timer(link->link_loss_timer, link->loss_helloint, OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC);
355 }
356
357 /**
358  * Callback for the link SYM timer.
359  */
360 static void
361 olsr_expire_link_sym_timer(void *context)
362 {
363   struct link_entry *link;
364
365   link = (struct link_entry *)context;
366   link->link_sym_timer = NULL;  /* be pedandic */
367
368   if (link->prev_status != SYM_LINK) {
369     return;
370   }
371
372   link->prev_status = lookup_link_status(link);
373   olsr_update_nbr_status(link->neighbor, get_neighbor_status(&link->neighbor_iface_addr));
374   changes_neighborhood = true;
375 }
376
377 /**
378  * Callback for the link_hello timer.
379  */
380 void
381 olsr_expire_link_hello_timer(void *context)
382 {
383   struct link_entry *link;
384
385   link = (struct link_entry *)context;
386
387   /* update neighbor status */
388   olsr_update_nbr_status(link->neighbor, get_neighbor_status(&link->neighbor_iface_addr));
389 }
390
391 /**
392  * Callback for the link timer.
393  */
394 static void
395 olsr_expire_link_entry(void *context)
396 {
397   struct link_entry *link;
398
399   link = (struct link_entry *)context;
400   link->link_timer = NULL;      /* be pedandic */
401
402   olsr_delete_link_entry(link);
403 }
404
405 /**
406  * Set the link expiration timer.
407  */
408 static void
409 olsr_set_link_timer(struct link_entry *link, unsigned int rel_timer)
410 {
411   olsr_set_timer(&link->link_timer, rel_timer, OLSR_LINK_JITTER,
412                  OLSR_TIMER_ONESHOT, &olsr_expire_link_entry, link, link_dead_timer_cookie);
413 }
414
415 /**
416  * Nothing mysterious here.
417  * Adding a new link entry to the link set.
418  *
419  * @param local the local IP address
420  * @param remote the remote IP address
421  * @param remote_main the remote nodes main address
422  * @param vtime the validity time of the entry
423  * @param htime the HELLO interval of the remote node
424  * @param local_if the local interface
425  * @return the new (or already existing) link_entry
426  */
427 static struct link_entry *
428 add_link_entry(const union olsr_ip_addr *local,
429                const union olsr_ip_addr *remote,
430                union olsr_ip_addr *remote_main, olsr_reltime vtime, olsr_reltime htime, struct interface *local_if)
431 {
432   struct link_entry *link;
433   struct nbr_entry *neighbor;
434 #if !defined  REMOVE_LOG_DEBUG
435   struct ipaddr_str localbuf, rembuf;
436 #endif
437
438   link = lookup_link_entry(remote, remote_main, local_if);
439   if (link) {
440     /*
441      * Link exists. Update tc_edge LQ and exit.
442      */
443     olsr_copylq_link_entry_2_tc_edge_entry(link->link_tc_edge, link);
444     changes_neighborhood = olsr_calc_tc_edge_entry_etx(link->link_tc_edge);
445     return link;
446   }
447
448   /*
449    * if there exists no link tuple with
450    * L_neighbor_iface_addr == Source Address
451    */
452
453   OLSR_DEBUG(LOG_LINKS, "Adding %s=>%s to link set\n", olsr_ip_to_string(&localbuf, local), olsr_ip_to_string(&rembuf, remote));
454
455   /* a new tuple is created with... */
456   link = olsr_malloc_link_entry();
457
458   /* copy if_name, if it is defined */
459   if (local_if->int_name) {
460     size_t name_size = strlen(local_if->int_name) + 1;
461     link->if_name = olsr_malloc(name_size, "target of if_name in new link entry");
462     strscpy(link->if_name, local_if->int_name, name_size);
463   } else
464     link->if_name = NULL;
465
466   /* shortcut to interface. */
467   link->inter = local_if;
468   lock_interface(local_if);
469
470   /*
471    * L_local_iface_addr = Address of the interface
472    * which received the HELLO message
473    */
474   link->local_iface_addr = *local;
475
476   /* L_neighbor_iface_addr = Source Address */
477   link->neighbor_iface_addr = *remote;
478
479   /* L_time = current time + validity time */
480   olsr_set_link_timer(link, vtime);
481
482   link->prev_status = ASYM_LINK;
483
484   link->loss_helloint = htime;
485
486   olsr_set_timer(&link->link_loss_timer, htime + htime / 2,
487                  OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC, &olsr_expire_link_loss_timer, link, link_loss_timer_cookie);
488
489   set_loss_link_multiplier(link);
490
491   link->linkcost = LINK_COST_BROKEN;
492
493   /* Add to queue */
494   list_add_before(&link_entry_head, &link->link_list);
495
496   /*
497    * Create the neighbor entry
498    */
499
500   /* Neighbor MUST exist! */
501   neighbor = olsr_lookup_nbr_entry(remote_main, true);
502   if (!neighbor) {
503     OLSR_DEBUG(LOG_LINKS, "ADDING NEW NEIGHBOR ENTRY %s FROM LINK SET\n", olsr_ip_to_string(&rembuf, remote_main));
504     neighbor = olsr_add_nbr_entry(remote_main);
505   }
506
507   neighbor->linkcount++;
508   link->neighbor = neighbor;
509
510   /*
511    * Now create a tc-edge for that link.
512    */
513   olsr_change_myself_tc();
514   if (link->link_tc_edge == NULL) {
515     link->link_tc_edge = olsr_add_tc_edge_entry(tc_myself, remote_main, 0);
516   }
517
518   /*
519    * Mark the edge local such that it does not get deleted
520    * during cleanup functions.
521    */
522   link->link_tc_edge->flags |= TC_EDGE_FLAG_LOCAL;
523
524   /*
525    * Add the rt_path for the link-end. This is an optimization
526    * that lets us install > 1 hop routes prior to receiving
527    * the MID entry for the 1 hop neighbor.
528    */
529   olsr_insert_routing_table(remote, 8 * olsr_cnf->ipsize, remote_main, OLSR_RT_ORIGIN_LINK);
530
531   changes_neighborhood = true;
532   return link;
533 }
534
535
536 /**
537  * Lookup the status of a link.
538  *
539  * @param int_addr address of the remote interface
540  * @return 1 of the link is symmertic 0 if not
541  */
542 int
543 check_neighbor_link(const union olsr_ip_addr *int_addr)
544 {
545   struct link_entry *link;
546
547   OLSR_FOR_ALL_LINK_ENTRIES(link) {
548     if (olsr_ipcmp(int_addr, &link->neighbor_iface_addr) == 0) {
549       return lookup_link_status(link);
550     }
551   }
552   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
553
554   return UNSPEC_LINK;
555 }
556
557 /**
558  * Lookup a link entry
559  *
560  * @param remote the remote interface address
561  * @param remote_main the remote nodes main address
562  * @param local the local interface address
563  * @return the link entry if found, NULL if not
564  */
565 struct link_entry *
566 lookup_link_entry(const union olsr_ip_addr *remote, const union olsr_ip_addr *remote_main, const struct interface *local)
567 {
568   struct link_entry *link;
569
570   OLSR_FOR_ALL_LINK_ENTRIES(link) {
571     if (olsr_ipcmp(remote, &link->neighbor_iface_addr) == 0 && (link->if_name ? !strcmp(link->if_name, local->int_name)
572                                                                 : olsr_ipcmp(&local->ip_addr, &link->local_iface_addr) == 0)) {
573       /* check the remote-main address only if there is one given */
574       if (NULL != remote_main && olsr_ipcmp(remote_main, &link->neighbor->nbr_addr) != 0) {
575         /* Neighbor has changed it's main_addr, update */
576 #if !defined REMOVE_LOG_DEBUG
577         struct ipaddr_str oldbuf, newbuf;
578 #endif
579         OLSR_DEBUG(LOG_LINKS, "Neighbor changed main_ip, updating %s -> %s\n",
580                    olsr_ip_to_string(&oldbuf, &link->neighbor->nbr_addr), olsr_ip_to_string(&newbuf, remote_main));
581         link->neighbor->nbr_addr = *remote_main;
582       }
583       return link;
584     }
585   }
586   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
587
588   return NULL;
589 }
590
591 /**
592  * Update a link entry. This is the "main entrypoint" in
593  * the link-sensing. This function is called from the HELLO
594  * parser function. It makes sure a entry is updated or created.
595  *
596  * @param local the local IP address
597  * @param remote the remote IP address
598  * @param message the HELLO message
599  * @param in_if the interface on which this HELLO was received
600  * @return the link_entry struct describing this link entry
601  */
602 struct link_entry *
603 update_link_entry(const union olsr_ip_addr *local,
604                   const union olsr_ip_addr *remote, struct lq_hello_message *message, struct interface *in_if)
605 {
606   struct link_entry *entry;
607
608   /* Add if not registered */
609   entry = add_link_entry(local, remote, &message->comm.orig, message->comm.vtime, message->htime, in_if);
610
611   /* Update ASYM_time */
612   entry->vtime = message->comm.vtime;
613   entry->ASYM_time = GET_TIMESTAMP(message->comm.vtime);
614
615   entry->prev_status = check_link_status(message, in_if);
616
617   switch (entry->prev_status) {
618   case (LOST_LINK):
619     olsr_stop_timer(entry->link_sym_timer);
620     entry->link_sym_timer = NULL;
621     break;
622   case (SYM_LINK):
623   case (ASYM_LINK):
624
625     /* L_SYM_time = current time + validity time */
626     olsr_set_timer(&entry->link_sym_timer, message->comm.vtime,
627                    OLSR_LINK_SYM_JITTER, OLSR_TIMER_ONESHOT, &olsr_expire_link_sym_timer, entry, link_sym_timer_cookie);
628
629     /* L_time = L_SYM_time + NEIGHB_HOLD_TIME */
630     olsr_set_link_timer(entry, message->comm.vtime + NEIGHB_HOLD_TIME * MSEC_PER_SEC);
631     break;
632   default:;
633   }
634
635   /* L_time = max(L_time, L_ASYM_time) */
636   if (entry->link_timer && (entry->link_timer->timer_clock < entry->ASYM_time)) {
637     olsr_set_link_timer(entry, TIME_DUE(entry->ASYM_time));
638   }
639
640   /* Update neighbor */
641   olsr_update_nbr_status(entry->neighbor, get_neighbor_status(remote));
642
643   return entry;
644 }
645
646
647 /**
648  * Function that updates all registered pointers to
649  * one neighbor entry with another pointer
650  * Used by MID updates.
651  *
652  * @old the pointer to replace
653  * @new the pointer to use instead of "old"
654  * @return the number of entries updated
655  */
656 int
657 replace_neighbor_link_set(const struct nbr_entry *old, struct nbr_entry *new)
658 {
659   struct link_entry *link;
660   int retval = 0;
661
662   if (list_is_empty(&link_entry_head)) {
663     return retval;
664   }
665
666   OLSR_FOR_ALL_LINK_ENTRIES(link) {
667
668     if (link->neighbor == old) {
669       link->neighbor = new;
670       retval++;
671     }
672   }
673   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
674
675   return retval;
676 }
677
678
679 /**
680  *Checks the link status to a neighbor by
681  *looking in a received HELLO message.
682  *
683  *@param message the HELLO message to check
684  *
685  *@return the link status
686  */
687 static int
688 check_link_status(const struct lq_hello_message *message, const struct interface *in_if)
689 {
690   int ret = UNSPEC_LINK;
691   struct lq_hello_neighbor *neighbors;
692
693   neighbors = message->neigh;
694   while (neighbors) {
695
696     /*
697      * Note: If a neigh has 2 cards we can reach, the neigh
698      * will send a Hello with the same IP mentined twice
699      */
700     if (olsr_ipcmp(&neighbors->addr, &in_if->ip_addr) == 0
701         && neighbors->link_type != UNSPEC_LINK) {
702       ret = neighbors->link_type;
703       if (SYM_LINK == ret) {
704         break;
705       }
706     }
707     neighbors = neighbors->next;
708   }
709
710   return ret;
711 }
712
713 void
714 olsr_print_link_set(void)
715 {
716 #if !defined REMOVE_LOG_INFO
717   /* The whole function makes no sense without it. */
718   struct link_entry *walker;
719   const int addrsize = olsr_cnf->ip_version == AF_INET ? 15 : 39;
720
721   OLSR_INFO(LOG_LINKS, "\n--- %s ---------------------------------------------------- LINKS\n\n", olsr_wallclock_string());
722   OLSR_INFO_NH(LOG_LINKS, "%-*s  %-6s %-14s %s\n", addrsize, "IP address", "hyst", "      LQ      ", "ETX");
723
724   OLSR_FOR_ALL_LINK_ENTRIES(walker) {
725     struct ipaddr_str buf;
726     struct lqtextbuffer lqbuffer1, lqbuffer2;
727
728     OLSR_INFO_NH(LOG_LINKS, "%-*s %-14s %s\n",
729                  addrsize, olsr_ip_to_string(&buf, &walker->neighbor_iface_addr),
730                  get_link_entry_text(walker, '/', &lqbuffer1), get_linkcost_text(walker->linkcost, false, &lqbuffer2));
731   } OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
732 #endif
733 }
734
735 /*
736  * called for every LQ HELLO message.
737  * update the timeout with the htime value from the message
738  */
739 void
740 olsr_update_packet_loss_hello_int(struct link_entry *entry, olsr_reltime loss_hello_int)
741 {
742   entry->loss_helloint = loss_hello_int;
743 }
744
745 void
746 olsr_update_packet_loss(struct link_entry *entry)
747 {
748   olsr_update_packet_loss_worker(entry, false);
749
750   /* timeout for the first lost packet is 1.5 x htime */
751   olsr_set_timer(&entry->link_loss_timer, entry->loss_helloint + entry->loss_helloint / 2,
752                  OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC, &olsr_expire_link_loss_timer, entry, link_loss_timer_cookie);
753 }
754
755 /*
756  * Local Variables:
757  * c-basic-offset: 2
758  * indent-tabs-mode: nil
759  * End:
760  */