2 * The olsr.org Optimized Link-State Routing daemon(olsrd)
3 * Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
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.
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.
33 * Visit http://www.olsr.org for more information.
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.
39 * $Id: link_set.c,v 1.39 2005/01/16 19:49:28 kattemat Exp $
44 * Link sensing database for the OLSR routing daemon
48 #include "hysteresis.h"
52 #include "scheduler.h"
53 #include "link_layer.h"
58 check_link_status(struct hello_message *);
61 olsr_time_out_hysteresis(void);
63 static void olsr_time_out_packet_loss(void);
65 static struct link_entry *
66 add_new_entry(union olsr_ip_addr *, union olsr_ip_addr *, union olsr_ip_addr *, double, double);
69 olsr_time_out_link_set(void);
72 get_neighbor_status(union olsr_ip_addr *);
82 hold_time_neighbor = (NEIGHB_HOLD_TIME*1000) / system_tick_divider;
84 olsr_register_timeout_function(&olsr_time_out_link_set);
85 if(olsr_cnf->use_hysteresis)
87 olsr_register_timeout_function(&olsr_time_out_hysteresis);
90 if (olsr_cnf->lq_level > 0)
92 olsr_register_timeout_function(&olsr_time_out_packet_loss);
99 * Get the status of a link. The status is based upon different
100 * timeouts in the link entry.
102 *@param remote address of the remote interface
104 *@return the link status of the link
107 lookup_link_status(struct link_entry *entry)
110 if(entry == NULL || link_set == NULL)
116 if(olsr_cnf->use_hysteresis)
119 if L_LOST_LINK_time is not expired, the link is advertised
120 with a link type of LOST_LINK.
123 if(!TIMED_OUT(entry->L_LOST_LINK_time))
126 otherwise, if L_LOST_LINK_time is expired and L_link_pending
127 is set to "true", the link SHOULD NOT be advertised at all;
129 if(entry->L_link_pending == 1)
132 olsr_printf(3, "HYST[%s]: Setting to HIDE\n", olsr_ip_to_string(&entry->neighbor_iface_addr));
137 otherwise, if L_LOST_LINK_time is expired and L_link_pending
138 is set to "false", the link is advertised as described
139 previously in section 6.
143 if(!TIMED_OUT(entry->SYM_time))
146 if(!TIMED_OUT(entry->ASYM_time))
160 *Find the "best" link status to a
163 *@param address the address to check for
165 *@return SYM_LINK if a symmetric link exists 0 if not
168 get_neighbor_status(union olsr_ip_addr *address)
170 union olsr_ip_addr *main_addr;
171 struct addresses *aliases;
172 struct link_entry *link;
173 struct interface *ifs;
175 //printf("GET_NEIGHBOR_STATUS\n");
177 /* Find main address */
178 if(!(main_addr = mid_lookup_main_addr(address)))
181 //printf("\tmain: %s\n", olsr_ip_to_string(main_addr));
183 /* Loop trough local interfaces to check all possebilities */
184 for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next)
186 //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
187 //printf("%s : ", olsr_ip_to_string(main_addr));
188 if((link = lookup_link_entry(main_addr, &ifs->ip_addr)) != NULL)
190 //printf("%d\n", lookup_link_status(link));
191 if(lookup_link_status(link) == SYM_LINK)
195 for(aliases = mid_lookup_aliases(main_addr);
197 aliases = aliases->next)
199 //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
200 //printf("%s : ", olsr_ip_to_string(&aliases->address));
201 if((link = lookup_link_entry(&aliases->address, &ifs->ip_addr)) != NULL)
203 //printf("%d\n", lookup_link_status(link));
205 if(lookup_link_status(link) == SYM_LINK)
218 *Get the remote interface address to use as nexthop
219 *to reach the remote host.
221 *@param address the address of the remote host
222 *@return the nexthop address to use. Returns the pointer
223 *passed as arg 1 if nothing is found(if no MID is registered).
226 get_neighbor_nexthop(union olsr_ip_addr *address)
228 union olsr_ip_addr *main_addr;
229 struct addresses *aliases;
230 struct link_entry *link;
231 struct interface *ifs;
233 //printf("GET_NEIGHBOR_NEXTHOP\n");
235 /* Find main address */
236 if(!(main_addr = mid_lookup_main_addr(address)))
239 //printf("\tmain: %s\n", olsr_ip_to_string(main_addr));
241 /* Loop trough local interfaces to check all possebilities */
242 for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next)
244 //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
245 //printf("%s : ", olsr_ip_to_string(main_addr));
246 if((link = lookup_link_entry(main_addr, &ifs->ip_addr)) != NULL)
248 //printf("%d\n", lookup_link_status(link));
249 if(lookup_link_status(link) == SYM_LINK)
253 for(aliases = mid_lookup_aliases(main_addr);
255 aliases = aliases->next)
257 //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
258 //printf("%s : ", olsr_ip_to_string(&aliases->address));
259 if((link = lookup_link_entry(&aliases->address, &ifs->ip_addr)) != NULL)
261 //printf("%d\n", lookup_link_status(link));
263 if(lookup_link_status(link) == SYM_LINK)
264 return &aliases->address;
269 /* This shoud only happen if not MID addresses for the
270 * multi-homed remote host are registered yet
279 *Get the interface to use when setting up
280 *a route to a neighbor. The interface with
281 *the lowest metric is used.
283 *As this function is only called by the route calculation
284 *functions it is considered that the caller is responsible
285 *for making sure the neighbor is symmetric.
286 *Due to experiences of route calculaition queryig for interfaces
287 *when no links with a valid SYM time is avalibe, the function
288 *will return a possible interface with an expired SYM time
289 *if no SYM links were discovered.
291 *@param address of the neighbor - does not have to
294 *@return a interface struct representing the interface to use
297 get_interface_link_set(union olsr_ip_addr *remote)
299 struct link_entry *tmp_link_set;
300 union olsr_ip_addr *remote_addr;
301 struct interface *if_to_use, *tmp_if, *backup_if;
302 float link_quality, backup_link_quality, curr;
308 backup_link_quality = -1.0;
310 if(remote == NULL || link_set == NULL)
312 olsr_printf(1, "Get interface: not sane request or empty link set!\n");
316 /* Check for main address of address */
317 if((remote_addr = mid_lookup_main_addr(remote)) == NULL)
318 remote_addr = remote;
320 tmp_link_set = link_set;
324 //printf("Checking %s vs ", olsr_ip_to_string(&tmp_link_set->neighbor_iface_addr));
325 //printf("%s\n", olsr_ip_to_string(addr));
327 if(COMP_IP(remote_addr, &tmp_link_set->neighbor->neighbor_main_addr) ||
328 COMP_IP(remote_addr, &tmp_link_set->neighbor_iface_addr))
331 tmp_if = if_ifwithaddr(&tmp_link_set->local_iface_addr);
333 /* Must be symmetric link! */
334 if(!TIMED_OUT(tmp_link_set->SYM_time))
336 if (olsr_cnf->lq_level == 0)
338 if (if_to_use == NULL ||
339 if_to_use->int_metric > tmp_if->int_metric)
345 curr = tmp_link_set->loss_link_quality *
346 tmp_link_set->neigh_link_quality;
348 if (curr > link_quality)
355 /* Backup solution in case the links have timed out */
358 if (olsr_cnf->lq_level == 0)
360 if (if_to_use == NULL &&
361 (backup_if == NULL ||
362 backup_if->int_metric > tmp_if->int_metric))
368 curr = tmp_link_set->loss_link_quality *
369 tmp_link_set->neigh_link_quality;
371 if (if_to_use == NULL && curr > backup_link_quality)
374 backup_link_quality = curr;
380 tmp_link_set = tmp_link_set->next;
384 if(if_to_use == NULL)
393 *Nothing mysterious here.
394 *Adding a new link entry to the link set.
396 *@param local the local IP address
397 *@param remote the remote IP address
398 *@param remote_main teh remote nodes main address
399 *@param vtime the validity time of the entry
400 *@param htime the HELLO interval of the remote node
403 static struct link_entry *
404 add_new_entry(union olsr_ip_addr *local, union olsr_ip_addr *remote, union olsr_ip_addr *remote_main, double vtime, double htime)
406 struct link_entry *tmp_link_set, *new_link;
407 struct neighbor_entry *neighbor;
409 struct interface *local_if;
412 tmp_link_set = link_set;
416 if(COMP_IP(remote, &tmp_link_set->neighbor_iface_addr))
418 tmp_link_set = tmp_link_set->next;
422 * if there exists no link tuple with
423 * L_neighbor_iface_addr == Source Address
427 olsr_printf(3, "Adding %s to link set\n", olsr_ip_to_string(remote));
430 /* a new tuple is created with... */
432 new_link = olsr_malloc(sizeof(struct link_entry), "new link entry");
434 memset(new_link, 0 , sizeof(struct link_entry));
436 * L_local_iface_addr = Address of the interface
437 * which received the HELLO message
439 //printf("\tLocal IF: %s\n", olsr_ip_to_string(local));
440 COPY_IP(&new_link->local_iface_addr, local);
441 /* L_neighbor_iface_addr = Source Address */
442 COPY_IP(&new_link->neighbor_iface_addr, remote);
444 /* L_SYM_time = current time - 1 (expired) */
445 new_link->SYM_time = now_times - 1;
447 /* L_time = current time + validity time */
448 new_link->time = GET_TIMESTAMP(vtime*1000);
452 if(olsr_cnf->use_hysteresis)
454 new_link->L_link_pending = 1;
455 new_link->L_LOST_LINK_time = GET_TIMESTAMP(vtime*1000);
456 new_link->hello_timeout = GET_TIMESTAMP(htime*1500);
457 new_link->last_htime = htime;
458 new_link->olsr_seqno = 0;
459 new_link->olsr_seqno_valid = OLSR_FALSE;
462 new_link->L_link_quality = 0.0;
464 if (olsr_cnf->lq_level > 0)
466 new_link->loss_hello_int = htime;
468 new_link->loss_timeout = GET_TIMESTAMP(htime * 1500.0);
470 new_link->loss_seqno = 0;
471 new_link->loss_seqno_valid = 0;
472 new_link->loss_missed_hellos = 0;
474 new_link->lost_packets = 0;
475 new_link->total_packets = 0;
477 new_link->loss_window_size = olsr_cnf->lq_wsize;
478 new_link->loss_index = 0;
480 memset(new_link->loss_bitmap, 0, sizeof (new_link->loss_bitmap));
483 new_link->loss_link_quality = 0.0;
484 new_link->neigh_link_quality = 0.0;
486 new_link->saved_loss_link_quality = 0.0;
487 new_link->saved_neigh_link_quality = 0.0;
490 new_link->next = link_set;
495 * Create the neighbor entry
498 /* Neighbor MUST exist! */
499 if(NULL == (neighbor = olsr_lookup_neighbor_table(remote_main)))
501 neighbor = olsr_insert_neighbor_table(remote_main);
502 /* Copy the main address */
503 COPY_IP(&neighbor->neighbor_main_addr, remote_main);
505 olsr_printf(3, "ADDING NEW NEIGHBOR ENTRY %s FROM LINK SET\n", olsr_ip_to_string(remote_main));
509 neighbor->linkcount++;
512 new_link->neighbor = neighbor;
514 if(!COMP_IP(remote, remote_main))
516 /* Add MID alias if not already registered */
517 /* This is kind of sketchy... and not specified
518 * in the RFC. We can only guess a vtime.
519 * We'll go for one that is hopefully long
520 * enough in most cases. 20 seconds
522 olsr_printf(1, "Adding MID alias main %s ", olsr_ip_to_string(remote_main));
523 olsr_printf(1, "-> %s based on HELLO\n\n", olsr_ip_to_string(remote));
524 insert_mid_alias(remote_main, remote, 20.0);
527 /* Add to link-layer spy list */
531 local_if = if_ifwithaddr(local);
533 olsr_printf(1, "Adding %s to spylist of interface %s\n", olsr_ip_to_string(remote), local_if->int_name);
535 if((local_if != NULL) && (add_spy_node(remote, local_if->int_name)))
536 new_link->spy_activated = 1;
545 *Lookup the status of a link.
547 *@param int_addr address of the remote interface
549 *@return 1 of the link is symmertic 0 if not
553 check_neighbor_link(union olsr_ip_addr *int_addr)
555 struct link_entry *tmp_link_set;
557 tmp_link_set = link_set;
561 if(COMP_IP(int_addr, &tmp_link_set->neighbor_iface_addr))
562 return lookup_link_status(tmp_link_set);
563 tmp_link_set = tmp_link_set->next;
572 *@param remote the remote interface address
573 *@param local the local interface address
575 *@return the link entry if found, NULL if not
578 lookup_link_entry(union olsr_ip_addr *remote, union olsr_ip_addr *local)
580 struct link_entry *tmp_link_set;
582 tmp_link_set = link_set;
586 if(COMP_IP(remote, &tmp_link_set->neighbor_iface_addr) &&
587 COMP_IP(local, &tmp_link_set->local_iface_addr))
589 tmp_link_set = tmp_link_set->next;
602 *Update a link entry. This is the "main entrypoint" in
603 *the link-sensing. This function is calles from the HELLO
605 *It makes sure a entry is updated or created.
607 *@param local the local IP address
608 *@param remote the remote IP address
609 *@param message the HELLO message
610 *@param in_if the interface on which this HELLO was received
612 *@return the link_entry struct describing this link entry
615 update_link_entry(union olsr_ip_addr *local, union olsr_ip_addr *remote, struct hello_message *message, struct interface *in_if)
618 struct link_entry *entry;
620 struct interface *local_if;
623 /* Add if not registered */
624 entry = add_new_entry(local, remote, &message->source_addr, message->vtime, message->htime);
626 /* Update link layer info */
627 /* Add to link-layer spy list */
629 if(llinfo && !entry->spy_activated)
631 local_if = if_ifwithaddr(local);
633 olsr_printf(1, "Adding %s to spylist of interface %s\n", olsr_ip_to_string(remote), local_if->int_name);
635 if((local_if != NULL) && (add_spy_node(remote, local_if->int_name)))
636 entry->spy_activated = 1;
640 /* Update ASYM_time */
641 //printf("Vtime is %f\n", message->vtime);
642 /* L_ASYM_time = current time + validity time */
643 entry->ASYM_time = GET_TIMESTAMP(message->vtime*1000);
645 status = check_link_status(message);
647 //printf("Status %d\n", status);
652 /* L_SYM_time = current time - 1 (i.e., expired) */
653 entry->SYM_time = now_times - 1;
658 /* L_SYM_time = current time + validity time */
659 //printf("updating SYM time for %s\n", olsr_ip_to_string(remote));
660 entry->SYM_time = GET_TIMESTAMP(message->vtime*1000);
662 /* L_time = L_SYM_time + NEIGHB_HOLD_TIME */
663 entry->time = entry->SYM_time + hold_time_neighbor;
669 /* L_time = max(L_time, L_ASYM_time) */
670 if(entry->time < entry->ASYM_time)
671 entry->time = entry->ASYM_time;
675 printf("Updating link LOCAL: %s ", olsr_ip_to_string(local));
676 printf("REMOTE: %s\n", olsr_ip_to_string(remote));
677 printf("VTIME: %f ", message->vtime);
678 printf("STATUS: %d\n", status);
681 /* Update hysteresis values */
682 if(olsr_cnf->use_hysteresis)
683 olsr_process_hysteresis(entry);
685 /* update neighbor status */
686 status = get_neighbor_status(remote);
688 /* Update neighbor */
689 update_neighbor_status(entry->neighbor, status);
696 * Fuction that updates all registered pointers to
697 * one neighbor entry with another pointer
698 * Used by MID updates.
700 *@old the pointer to replace
701 *@new the pointer to use instead of "old"
703 *@return the number of entries updated
706 replace_neighbor_link_set(struct neighbor_entry *old,
707 struct neighbor_entry *new)
709 struct link_entry *tmp_link_set, *last_link_entry;
717 tmp_link_set = link_set;
718 last_link_entry = NULL;
723 if(tmp_link_set->neighbor == old)
725 tmp_link_set->neighbor = new;
728 tmp_link_set = tmp_link_set->next;
737 *Checks the link status to a neighbor by
738 *looking in a received HELLO message.
740 *@param message the HELLO message to check
742 *@return the link status
745 check_link_status(struct hello_message *message)
748 struct hello_neighbor *neighbors;
749 struct interface *ifd;
751 neighbors = message->neighbors;
753 while(neighbors!=NULL)
755 //printf("(linkstatus)Checking %s ",olsr_ip_to_string(&neighbors->address));
756 //printf("against %s\n",olsr_ip_to_string(&main_addr));
758 /* Check all interfaces */
759 for (ifd = ifnet; ifd ; ifd = ifd->int_next)
761 if(COMP_IP(&neighbors->address, &ifd->ip_addr))
764 return neighbors->link;
768 neighbors = neighbors->next;
777 *Time out the link set. In other words, the link
778 *set is traversed and all non-valid entries are
783 olsr_time_out_link_set()
786 struct link_entry *tmp_link_set, *last_link_entry;
791 tmp_link_set = link_set;
792 last_link_entry = NULL;
797 if(TIMED_OUT(tmp_link_set->time))
799 if(last_link_entry != NULL)
801 last_link_entry->next = tmp_link_set->next;
803 /* Delete neighbor entry */
804 if(tmp_link_set->neighbor->linkcount == 1)
805 olsr_delete_neighbor_table(&tmp_link_set->neighbor->neighbor_main_addr);
807 tmp_link_set->neighbor->linkcount--;
809 //olsr_delete_neighbor_if_no_link(&tmp_link_set->neighbor->neighbor_main_addr);
810 changes_neighborhood = OLSR_TRUE;
813 tmp_link_set = last_link_entry;
817 link_set = tmp_link_set->next; /* CHANGED */
819 /* Delete neighbor entry */
820 if(tmp_link_set->neighbor->linkcount == 1)
821 olsr_delete_neighbor_table(&tmp_link_set->neighbor->neighbor_main_addr);
823 tmp_link_set->neighbor->linkcount--;
825 changes_neighborhood = OLSR_TRUE;
828 tmp_link_set = link_set;
833 last_link_entry = tmp_link_set;
834 tmp_link_set = tmp_link_set->next;
844 *Updates links that we have not received
845 *HELLO from in expected time according to
851 olsr_time_out_hysteresis()
854 struct link_entry *tmp_link_set;
860 tmp_link_set = link_set;
864 if(TIMED_OUT(tmp_link_set->hello_timeout))
866 tmp_link_set->L_link_quality = olsr_hyst_calc_instability(tmp_link_set->L_link_quality);
867 olsr_printf(1, "HYST[%s] HELLO timeout %0.3f\n", olsr_ip_to_string(&tmp_link_set->neighbor_iface_addr), tmp_link_set->L_link_quality);
868 /* Update hello_timeout - NO SLACK THIS TIME */
869 tmp_link_set->hello_timeout = GET_TIMESTAMP(tmp_link_set->last_htime*1000);
870 /* Recalculate status */
871 /* Update hysteresis values */
872 olsr_process_hysteresis(tmp_link_set);
874 /* update neighbor status */
875 status = get_neighbor_status(&tmp_link_set->neighbor_iface_addr);
878 /* Update neighbor */
879 update_neighbor_status(tmp_link_set->neighbor, status);
881 /* Update seqno - not mentioned in the RFC... kind of a hack.. */
882 tmp_link_set->olsr_seqno++;
884 tmp_link_set = tmp_link_set->next;
890 void olsr_print_link_set(void)
892 struct link_entry *walker;
896 olsr_printf(1, "\n--- %02d:%02d:%02d.%02d ---------------------------------------------------- LINKS\n\n",
902 if (olsr_cnf->ip_version == AF_INET)
904 olsr_printf(1, "IP address hyst LQ lost total NLQ ETX\n");
905 fstr = "%-15s %5.3f %5.3f %-3d %-3d %5.3f %.2f\n";
910 olsr_printf(1, "IP address hyst LQ lost total NLQ ETX\n");
911 fstr = "%-39s %5.3f %5.3f %-3d %-3d %5.3f %.2f\n";
914 for (walker = link_set; walker != NULL; walker = walker->next)
916 if (walker->loss_link_quality < MIN_LINK_QUALITY ||
917 walker->neigh_link_quality < MIN_LINK_QUALITY)
921 etx = 1.0 / (walker->loss_link_quality * walker->neigh_link_quality);
923 olsr_printf(1, fstr, olsr_ip_to_string(&walker->neighbor_iface_addr),
924 walker->L_link_quality, walker->loss_link_quality,
925 walker->lost_packets, walker->total_packets,
926 walker->neigh_link_quality, etx);
930 static void update_packet_loss_worker(struct link_entry *entry, int lost)
932 unsigned char mask = 1 << (entry->loss_index & 7);
933 int index = entry->loss_index >> 3;
934 double rel_lq, saved_lq;
940 if ((entry->loss_bitmap[index] & mask) != 0)
942 // but the packet that we replace was lost
943 // => decrement packet loss
945 entry->loss_bitmap[index] &= ~mask;
946 entry->lost_packets--;
954 if ((entry->loss_bitmap[index] & mask) == 0)
956 // but the packet that we replace was not lost
957 // => increment packet loss
959 entry->loss_bitmap[index] |= mask;
960 entry->lost_packets++;
964 // move to the next packet
968 // wrap around at the end of the packet loss window
970 if (entry->loss_index >= entry->loss_window_size)
971 entry->loss_index = 0;
973 // count the total number of handled packets up to the window size
975 if (entry->total_packets < entry->loss_window_size)
976 entry->total_packets++;
978 // the current reference link quality
980 saved_lq = entry->saved_loss_link_quality;
985 // calculate the new link quality
987 // start slowly: receive the first packet => link quality = 1 / n
990 entry->loss_link_quality =
991 (float)(entry->total_packets - entry->lost_packets) /
992 (float)(entry->loss_window_size);
994 // if the link quality has changed by more than 10 percent,
995 // print the new link quality table
997 rel_lq = entry->loss_link_quality / saved_lq;
999 if (rel_lq > 1.1 || rel_lq < 0.9)
1001 entry->saved_loss_link_quality = entry->loss_link_quality;
1003 changes_neighborhood = OLSR_TRUE;
1004 changes_topology = OLSR_TRUE;
1006 // create a new ANSN
1008 // XXX - we should check whether we actually
1009 // announce this neighbour
1011 changes = OLSR_TRUE;
1015 void olsr_update_packet_loss_hello_int(struct link_entry *entry,
1016 double loss_hello_int)
1018 // called for every LQ HELLO message - update the timeout
1019 // with the htime value from the message
1021 entry->loss_hello_int = loss_hello_int;
1024 void olsr_update_packet_loss(union olsr_ip_addr *rem, union olsr_ip_addr *loc,
1027 struct link_entry *entry;
1029 // called for every OLSR packet
1031 entry = lookup_link_entry(rem, loc);
1033 // it's the very first LQ HELLO message - we do not yet have a link
1038 // a) have we seen a packet before, i.e. is the sequence number valid?
1040 // b) heuristically detect a restart (= sequence number reset)
1043 if (entry->loss_seqno_valid != 0 &&
1044 (unsigned short)(seqno - entry->loss_seqno) < 100)
1046 // loop through all lost packets
1048 while (entry->loss_seqno != seqno)
1050 // have we already considered all lost LQ HELLO messages?
1052 if (entry->loss_missed_hellos == 0)
1053 update_packet_loss_worker(entry, 1);
1055 // if not, then decrement the number of lost LQ HELLOs
1058 entry->loss_missed_hellos--;
1060 entry->loss_seqno++;
1064 // we have received a packet, otherwise this function would not
1067 update_packet_loss_worker(entry, 0);
1071 entry->loss_missed_hellos = 0;
1072 entry->loss_seqno = seqno + 1;
1074 // we now have a valid serial number for sure
1076 entry->loss_seqno_valid = 1;
1078 // timeout for the first lost packet is 1.5 x htime
1080 entry->loss_timeout = GET_TIMESTAMP(entry->loss_hello_int * 1500.0);
1083 static void olsr_time_out_packet_loss()
1085 struct link_entry *walker;
1087 // loop through all links
1089 for (walker = link_set; walker != NULL; walker = walker->next)
1091 // find a link that has not seen any packets for a very long
1092 // time (first time: 1.5 x htime, subsequently: 1.0 x htime)
1094 if (!TIMED_OUT(walker->loss_timeout))
1097 // count the lost packet
1099 update_packet_loss_worker(walker, 1);
1101 // memorize that we've counted the packet, so that we do not
1102 // count it a second time later
1104 walker->loss_missed_hellos++;
1106 // next timeout in 1.0 x htime
1108 walker->loss_timeout = GET_TIMESTAMP(walker->loss_hello_int * 1000.0);
1112 struct link_entry *olsr_neighbor_best_link(union olsr_ip_addr *main)
1114 struct link_entry *walker;
1117 struct link_entry *res = NULL;
1119 // loop through all links
1121 for (walker = link_set; walker != NULL; walker = walker->next)
1123 // check whether it's a link to the requested neighbor and
1124 // whether the link's quality is better than what we have
1126 if(COMP_IP(main, &walker->neighbor->neighbor_main_addr))
1128 curr = walker->loss_link_quality * walker->neigh_link_quality;