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.38 2004/12/19 13:53:18 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 olsr_init_timer((olsr_u32_t) (NEIGHB_HOLD_TIME*1000), &hold_time_neighbor);
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)
118 if(olsr_cnf->use_hysteresis)
121 if L_LOST_LINK_time is not expired, the link is advertised
122 with a link type of LOST_LINK.
124 if(!TIMED_OUT(&entry->L_LOST_LINK_time))
127 otherwise, if L_LOST_LINK_time is expired and L_link_pending
128 is set to "true", the link SHOULD NOT be advertised at all;
130 if(entry->L_link_pending == 1)
133 olsr_printf(3, "HYST[%s]: Setting to HIDE\n", olsr_ip_to_string(&entry->neighbor_iface_addr));
138 otherwise, if L_LOST_LINK_time is expired and L_link_pending
139 is set to "false", the link is advertised as described
140 previously in section 6.
144 if(!TIMED_OUT(&entry->SYM_time))
147 if(!TIMED_OUT(&entry->ASYM_time))
161 *Find the "best" link status to a
164 *@param address the address to check for
166 *@return SYM_LINK if a symmetric link exists 0 if not
169 get_neighbor_status(union olsr_ip_addr *address)
171 union olsr_ip_addr *main_addr;
172 struct addresses *aliases;
173 struct link_entry *link;
174 struct interface *ifs;
176 //printf("GET_NEIGHBOR_STATUS\n");
178 /* Find main address */
179 if(!(main_addr = mid_lookup_main_addr(address)))
182 //printf("\tmain: %s\n", olsr_ip_to_string(main_addr));
184 /* Loop trough local interfaces to check all possebilities */
185 for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next)
187 //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
188 //printf("%s : ", olsr_ip_to_string(main_addr));
189 if((link = lookup_link_entry(main_addr, &ifs->ip_addr)) != NULL)
191 //printf("%d\n", lookup_link_status(link));
192 if(lookup_link_status(link) == SYM_LINK)
196 for(aliases = mid_lookup_aliases(main_addr);
198 aliases = aliases->next)
200 //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
201 //printf("%s : ", olsr_ip_to_string(&aliases->address));
202 if((link = lookup_link_entry(&aliases->address, &ifs->ip_addr)) != NULL)
204 //printf("%d\n", lookup_link_status(link));
206 if(lookup_link_status(link) == SYM_LINK)
219 *Get the remote interface address to use as nexthop
220 *to reach the remote host.
222 *@param address the address of the remote host
223 *@return the nexthop address to use. Returns the pointer
224 *passed as arg 1 if nothing is found(if no MID is registered).
227 get_neighbor_nexthop(union olsr_ip_addr *address)
229 union olsr_ip_addr *main_addr;
230 struct addresses *aliases;
231 struct link_entry *link;
232 struct interface *ifs;
234 //printf("GET_NEIGHBOR_NEXTHOP\n");
236 /* Find main address */
237 if(!(main_addr = mid_lookup_main_addr(address)))
240 //printf("\tmain: %s\n", olsr_ip_to_string(main_addr));
242 /* Loop trough local interfaces to check all possebilities */
243 for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next)
245 //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
246 //printf("%s : ", olsr_ip_to_string(main_addr));
247 if((link = lookup_link_entry(main_addr, &ifs->ip_addr)) != NULL)
249 //printf("%d\n", lookup_link_status(link));
250 if(lookup_link_status(link) == SYM_LINK)
254 for(aliases = mid_lookup_aliases(main_addr);
256 aliases = aliases->next)
258 //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
259 //printf("%s : ", olsr_ip_to_string(&aliases->address));
260 if((link = lookup_link_entry(&aliases->address, &ifs->ip_addr)) != NULL)
262 //printf("%d\n", lookup_link_status(link));
264 if(lookup_link_status(link) == SYM_LINK)
265 return &aliases->address;
270 /* This shoud only happen if not MID addresses for the
271 * multi-homed remote host are registered yet
280 *Get the interface to use when setting up
281 *a route to a neighbor. The interface with
282 *the lowest metric is used.
284 *As this function is only called by the route calculation
285 *functions it is considered that the caller is responsible
286 *for making sure the neighbor is symmetric.
287 *Due to experiences of route calculaition queryig for interfaces
288 *when no links with a valid SYM time is avalibe, the function
289 *will return a possible interface with an expired SYM time
290 *if no SYM links were discovered.
292 *@param address of the neighbor - does not have to
295 *@return a interface struct representing the interface to use
298 get_interface_link_set(union olsr_ip_addr *remote)
300 struct link_entry *tmp_link_set;
301 union olsr_ip_addr *remote_addr;
302 struct interface *if_to_use, *tmp_if, *backup_if;
303 float link_quality, backup_link_quality, curr;
309 backup_link_quality = -1.0;
311 if(remote == NULL || link_set == NULL)
313 olsr_printf(1, "Get interface: not sane request or empty link set!\n");
317 /* Check for main address of address */
318 if((remote_addr = mid_lookup_main_addr(remote)) == NULL)
319 remote_addr = remote;
321 tmp_link_set = link_set;
325 //printf("Checking %s vs ", olsr_ip_to_string(&tmp_link_set->neighbor_iface_addr));
326 //printf("%s\n", olsr_ip_to_string(addr));
328 if(COMP_IP(remote_addr, &tmp_link_set->neighbor->neighbor_main_addr) ||
329 COMP_IP(remote_addr, &tmp_link_set->neighbor_iface_addr))
332 tmp_if = if_ifwithaddr(&tmp_link_set->local_iface_addr);
334 /* Must be symmetric link! */
335 if(!TIMED_OUT(&tmp_link_set->SYM_time))
337 if (olsr_cnf->lq_level == 0)
339 if (if_to_use == NULL ||
340 if_to_use->int_metric > tmp_if->int_metric)
346 curr = tmp_link_set->loss_link_quality *
347 tmp_link_set->neigh_link_quality;
349 if (curr > link_quality)
356 /* Backup solution in case the links have timed out */
359 if (olsr_cnf->lq_level == 0)
361 if (if_to_use == NULL &&
362 (backup_if == NULL ||
363 backup_if->int_metric > tmp_if->int_metric))
369 curr = tmp_link_set->loss_link_quality *
370 tmp_link_set->neigh_link_quality;
372 if (if_to_use == NULL && curr > backup_link_quality)
375 backup_link_quality = curr;
381 tmp_link_set = tmp_link_set->next;
385 if(if_to_use == NULL)
394 *Nothing mysterious here.
395 *Adding a new link entry to the link set.
397 *@param local the local IP address
398 *@param remote the remote IP address
399 *@param remote_main teh remote nodes main address
400 *@param vtime the validity time of the entry
401 *@param htime the HELLO interval of the remote node
404 static struct link_entry *
405 add_new_entry(union olsr_ip_addr *local, union olsr_ip_addr *remote, union olsr_ip_addr *remote_main, double vtime, double htime)
407 struct link_entry *tmp_link_set, *new_link;
408 struct neighbor_entry *neighbor;
410 struct interface *local_if;
413 tmp_link_set = link_set;
417 if(COMP_IP(remote, &tmp_link_set->neighbor_iface_addr))
419 tmp_link_set = tmp_link_set->next;
423 * if there exists no link tuple with
424 * L_neighbor_iface_addr == Source Address
428 olsr_printf(3, "Adding %s to link set\n", olsr_ip_to_string(remote));
431 /* a new tuple is created with... */
433 new_link = olsr_malloc(sizeof(struct link_entry), "new link entry");
435 memset(new_link, 0 , sizeof(struct link_entry));
437 * L_local_iface_addr = Address of the interface
438 * which received the HELLO message
440 //printf("\tLocal IF: %s\n", olsr_ip_to_string(local));
441 COPY_IP(&new_link->local_iface_addr, local);
442 /* L_neighbor_iface_addr = Source Address */
443 COPY_IP(&new_link->neighbor_iface_addr, remote);
445 /* L_SYM_time = current time - 1 (expired) */
446 new_link->SYM_time = now;
448 new_link->SYM_time.tv_sec -= 1;
450 /* L_time = current time + validity time */
451 olsr_get_timestamp((olsr_u32_t) vtime*1000, &new_link->time);
455 if(olsr_cnf->use_hysteresis)
457 new_link->L_link_pending = 1;
458 olsr_get_timestamp((olsr_u32_t) vtime*1000, &new_link->L_LOST_LINK_time);
459 olsr_get_timestamp((olsr_u32_t) htime*1500, &new_link->hello_timeout);
460 new_link->last_htime = htime;
461 new_link->olsr_seqno = 0;
462 new_link->olsr_seqno_valid = OLSR_FALSE;
465 new_link->L_link_quality = 0.0;
467 if (olsr_cnf->lq_level > 0)
469 new_link->loss_hello_int = htime;
471 olsr_get_timestamp((olsr_u32_t)(htime * 1500.0),
472 &new_link->loss_timeout);
474 new_link->loss_seqno = 0;
475 new_link->loss_seqno_valid = 0;
476 new_link->loss_missed_hellos = 0;
478 new_link->lost_packets = 0;
479 new_link->total_packets = 0;
481 new_link->loss_window_size = olsr_cnf->lq_wsize;
482 new_link->loss_index = 0;
484 memset(new_link->loss_bitmap, 0, sizeof (new_link->loss_bitmap));
487 new_link->loss_link_quality = 0.0;
488 new_link->neigh_link_quality = 0.0;
490 new_link->saved_loss_link_quality = 0.0;
491 new_link->saved_neigh_link_quality = 0.0;
494 new_link->next = link_set;
499 * Create the neighbor entry
502 /* Neighbor MUST exist! */
503 if(NULL == (neighbor = olsr_lookup_neighbor_table(remote_main)))
505 neighbor = olsr_insert_neighbor_table(remote_main);
506 /* Copy the main address */
507 COPY_IP(&neighbor->neighbor_main_addr, remote_main);
509 olsr_printf(3, "ADDING NEW NEIGHBOR ENTRY %s FROM LINK SET\n", olsr_ip_to_string(remote_main));
513 neighbor->linkcount++;
516 new_link->neighbor = neighbor;
518 if(!COMP_IP(remote, remote_main))
520 /* Add MID alias if not already registered */
521 /* This is kind of sketchy... and not specified
522 * in the RFC. We can only guess a vtime.
523 * We'll go for one that is hopefully long
524 * enough in most cases. 20 seconds
526 olsr_printf(1, "Adding MID alias main %s ", olsr_ip_to_string(remote_main));
527 olsr_printf(1, "-> %s based on HELLO\n\n", olsr_ip_to_string(remote));
528 insert_mid_alias(remote_main, remote, 20.0);
531 /* Add to link-layer spy list */
535 local_if = if_ifwithaddr(local);
537 olsr_printf(1, "Adding %s to spylist of interface %s\n", olsr_ip_to_string(remote), local_if->int_name);
539 if((local_if != NULL) && (add_spy_node(remote, local_if->int_name)))
540 new_link->spy_activated = 1;
549 *Lookup the status of a link.
551 *@param int_addr address of the remote interface
553 *@return 1 of the link is symmertic 0 if not
557 check_neighbor_link(union olsr_ip_addr *int_addr)
559 struct link_entry *tmp_link_set;
561 tmp_link_set = link_set;
565 if(COMP_IP(int_addr, &tmp_link_set->neighbor_iface_addr))
566 return lookup_link_status(tmp_link_set);
567 tmp_link_set = tmp_link_set->next;
576 *@param remote the remote interface address
577 *@param local the local interface address
579 *@return the link entry if found, NULL if not
582 lookup_link_entry(union olsr_ip_addr *remote, union olsr_ip_addr *local)
584 struct link_entry *tmp_link_set;
586 tmp_link_set = link_set;
590 if(COMP_IP(remote, &tmp_link_set->neighbor_iface_addr) &&
591 COMP_IP(local, &tmp_link_set->local_iface_addr))
593 tmp_link_set = tmp_link_set->next;
606 *Update a link entry. This is the "main entrypoint" in
607 *the link-sensing. This function is calles from the HELLO
609 *It makes sure a entry is updated or created.
611 *@param local the local IP address
612 *@param remote the remote IP address
613 *@param message the HELLO message
614 *@param in_if the interface on which this HELLO was received
616 *@return the link_entry struct describing this link entry
619 update_link_entry(union olsr_ip_addr *local, union olsr_ip_addr *remote, struct hello_message *message, struct interface *in_if)
622 struct link_entry *entry;
624 struct interface *local_if;
627 /* Add if not registered */
628 entry = add_new_entry(local, remote, &message->source_addr, message->vtime, message->htime);
630 /* Update link layer info */
631 /* Add to link-layer spy list */
633 if(llinfo && !entry->spy_activated)
635 local_if = if_ifwithaddr(local);
637 olsr_printf(1, "Adding %s to spylist of interface %s\n", olsr_ip_to_string(remote), local_if->int_name);
639 if((local_if != NULL) && (add_spy_node(remote, local_if->int_name)))
640 entry->spy_activated = 1;
644 /* Update ASYM_time */
645 //printf("Vtime is %f\n", message->vtime);
646 /* L_ASYM_time = current time + validity time */
647 olsr_get_timestamp((olsr_u32_t) (message->vtime*1000), &entry->ASYM_time);
650 status = check_link_status(message);
652 //printf("Status %d\n", status);
657 /* L_SYM_time = current time - 1 (i.e., expired) */
658 entry->SYM_time = now;
659 entry->SYM_time.tv_sec -= 1;
664 /* L_SYM_time = current time + validity time */
665 //printf("updating SYM time for %s\n", olsr_ip_to_string(remote));
666 olsr_get_timestamp((olsr_u32_t) (message->vtime*1000), &entry->SYM_time);
668 /* L_time = L_SYM_time + NEIGHB_HOLD_TIME */
669 timeradd(&entry->SYM_time, &hold_time_neighbor, &entry->time);
675 /* L_time = max(L_time, L_ASYM_time) */
676 if(timercmp(&entry->time, &entry->ASYM_time, <))
677 entry->time = entry->ASYM_time;
681 printf("Updating link LOCAL: %s ", olsr_ip_to_string(local));
682 printf("REMOTE: %s\n", olsr_ip_to_string(remote));
683 printf("VTIME: %f ", message->vtime);
684 printf("STATUS: %d\n", status);
687 /* Update hysteresis values */
688 if(olsr_cnf->use_hysteresis)
689 olsr_process_hysteresis(entry);
691 /* update neighbor status */
692 status = get_neighbor_status(remote);
694 /* Update neighbor */
695 update_neighbor_status(entry->neighbor, status);
702 * Fuction that updates all registered pointers to
703 * one neighbor entry with another pointer
704 * Used by MID updates.
706 *@old the pointer to replace
707 *@new the pointer to use instead of "old"
709 *@return the number of entries updated
712 replace_neighbor_link_set(struct neighbor_entry *old,
713 struct neighbor_entry *new)
715 struct link_entry *tmp_link_set, *last_link_entry;
723 tmp_link_set = link_set;
724 last_link_entry = NULL;
729 if(tmp_link_set->neighbor == old)
731 tmp_link_set->neighbor = new;
734 tmp_link_set = tmp_link_set->next;
743 *Checks the link status to a neighbor by
744 *looking in a received HELLO message.
746 *@param message the HELLO message to check
748 *@return the link status
751 check_link_status(struct hello_message *message)
754 struct hello_neighbor *neighbors;
755 struct interface *ifd;
757 neighbors = message->neighbors;
759 while(neighbors!=NULL)
761 //printf("(linkstatus)Checking %s ",olsr_ip_to_string(&neighbors->address));
762 //printf("against %s\n",olsr_ip_to_string(&main_addr));
764 /* Check all interfaces */
765 for (ifd = ifnet; ifd ; ifd = ifd->int_next)
767 if(COMP_IP(&neighbors->address, &ifd->ip_addr))
770 return neighbors->link;
774 neighbors = neighbors->next;
783 *Time out the link set. In other words, the link
784 *set is traversed and all non-valid entries are
789 olsr_time_out_link_set()
792 struct link_entry *tmp_link_set, *last_link_entry;
797 tmp_link_set = link_set;
798 last_link_entry = NULL;
803 if(TIMED_OUT(&tmp_link_set->time))
805 if(last_link_entry != NULL)
807 last_link_entry->next = tmp_link_set->next;
809 /* Delete neighbor entry */
810 if(tmp_link_set->neighbor->linkcount == 1)
811 olsr_delete_neighbor_table(&tmp_link_set->neighbor->neighbor_main_addr);
813 tmp_link_set->neighbor->linkcount--;
815 //olsr_delete_neighbor_if_no_link(&tmp_link_set->neighbor->neighbor_main_addr);
816 changes_neighborhood = OLSR_TRUE;
819 tmp_link_set = last_link_entry;
823 link_set = tmp_link_set->next; /* CHANGED */
825 /* Delete neighbor entry */
826 if(tmp_link_set->neighbor->linkcount == 1)
827 olsr_delete_neighbor_table(&tmp_link_set->neighbor->neighbor_main_addr);
829 tmp_link_set->neighbor->linkcount--;
831 changes_neighborhood = OLSR_TRUE;
834 tmp_link_set = link_set;
839 last_link_entry = tmp_link_set;
840 tmp_link_set = tmp_link_set->next;
850 *Updates links that we have not received
851 *HELLO from in expected time according to
857 olsr_time_out_hysteresis()
860 struct link_entry *tmp_link_set;
866 tmp_link_set = link_set;
870 if(TIMED_OUT(&tmp_link_set->hello_timeout))
872 tmp_link_set->L_link_quality = olsr_hyst_calc_instability(tmp_link_set->L_link_quality);
873 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);
874 /* Update hello_timeout - NO SLACK THIS TIME */
875 olsr_get_timestamp((olsr_u32_t) tmp_link_set->last_htime*1000, &tmp_link_set->hello_timeout);
877 /* Recalculate status */
878 /* Update hysteresis values */
879 olsr_process_hysteresis(tmp_link_set);
881 /* update neighbor status */
882 status = get_neighbor_status(&tmp_link_set->neighbor_iface_addr);
885 /* Update neighbor */
886 update_neighbor_status(tmp_link_set->neighbor, status);
888 /* Update seqno - not mentioned in the RFC... kind of a hack.. */
889 tmp_link_set->olsr_seqno++;
891 tmp_link_set = tmp_link_set->next;
897 void olsr_print_link_set(void)
899 struct link_entry *walker;
903 olsr_printf(1, "\n--- %02d:%02d:%02d.%02d ---------------------------------------------------- LINKS\n\n",
909 if (olsr_cnf->ip_version == AF_INET)
911 olsr_printf(1, "IP address hyst LQ lost total NLQ ETX\n");
912 fstr = "%-15s %5.3f %5.3f %-3d %-3d %5.3f %.2f\n";
917 olsr_printf(1, "IP address hyst LQ lost total NLQ ETX\n");
918 fstr = "%-39s %5.3f %5.3f %-3d %-3d %5.3f %.2f\n";
921 for (walker = link_set; walker != NULL; walker = walker->next)
923 if (walker->loss_link_quality < MIN_LINK_QUALITY ||
924 walker->neigh_link_quality < MIN_LINK_QUALITY)
928 etx = 1.0 / (walker->loss_link_quality * walker->neigh_link_quality);
930 olsr_printf(1, fstr, olsr_ip_to_string(&walker->neighbor_iface_addr),
931 walker->L_link_quality, walker->loss_link_quality,
932 walker->lost_packets, walker->total_packets,
933 walker->neigh_link_quality, etx);
937 static void update_packet_loss_worker(struct link_entry *entry, int lost)
939 unsigned char mask = 1 << (entry->loss_index & 7);
940 int index = entry->loss_index >> 3;
941 double rel_lq, saved_lq;
947 if ((entry->loss_bitmap[index] & mask) != 0)
949 // but the packet that we replace was lost
950 // => decrement packet loss
952 entry->loss_bitmap[index] &= ~mask;
953 entry->lost_packets--;
961 if ((entry->loss_bitmap[index] & mask) == 0)
963 // but the packet that we replace was not lost
964 // => increment packet loss
966 entry->loss_bitmap[index] |= mask;
967 entry->lost_packets++;
971 // move to the next packet
975 // wrap around at the end of the packet loss window
977 if (entry->loss_index >= entry->loss_window_size)
978 entry->loss_index = 0;
980 // count the total number of handled packets up to the window size
982 if (entry->total_packets < entry->loss_window_size)
983 entry->total_packets++;
985 // the current reference link quality
987 saved_lq = entry->saved_loss_link_quality;
992 // calculate the new link quality
994 // start slowly: receive the first packet => link quality = 1 / n
997 entry->loss_link_quality =
998 (float)(entry->total_packets - entry->lost_packets) /
999 (float)(entry->loss_window_size);
1001 // if the link quality has changed by more than 10 percent,
1002 // print the new link quality table
1004 rel_lq = entry->loss_link_quality / saved_lq;
1006 if (rel_lq > 1.1 || rel_lq < 0.9)
1008 entry->saved_loss_link_quality = entry->loss_link_quality;
1010 changes_neighborhood = OLSR_TRUE;
1011 changes_topology = OLSR_TRUE;
1013 // create a new ANSN
1015 // XXX - we should check whether we actually
1016 // announce this neighbour
1018 changes = OLSR_TRUE;
1022 void olsr_update_packet_loss_hello_int(struct link_entry *entry,
1023 double loss_hello_int)
1025 // called for every LQ HELLO message - update the timeout
1026 // with the htime value from the message
1028 entry->loss_hello_int = loss_hello_int;
1031 void olsr_update_packet_loss(union olsr_ip_addr *rem, union olsr_ip_addr *loc,
1034 struct link_entry *entry;
1036 // called for every OLSR packet
1038 entry = lookup_link_entry(rem, loc);
1040 // it's the very first LQ HELLO message - we do not yet have a link
1045 // a) have we seen a packet before, i.e. is the sequence number valid?
1047 // b) heuristically detect a restart (= sequence number reset)
1050 if (entry->loss_seqno_valid != 0 &&
1051 (unsigned short)(seqno - entry->loss_seqno) < 100)
1053 // loop through all lost packets
1055 while (entry->loss_seqno != seqno)
1057 // have we already considered all lost LQ HELLO messages?
1059 if (entry->loss_missed_hellos == 0)
1060 update_packet_loss_worker(entry, 1);
1062 // if not, then decrement the number of lost LQ HELLOs
1065 entry->loss_missed_hellos--;
1067 entry->loss_seqno++;
1071 // we have received a packet, otherwise this function would not
1074 update_packet_loss_worker(entry, 0);
1078 entry->loss_missed_hellos = 0;
1079 entry->loss_seqno = seqno + 1;
1081 // we now have a valid serial number for sure
1083 entry->loss_seqno_valid = 1;
1085 // timeout for the first lost packet is 1.5 x htime
1087 olsr_get_timestamp((olsr_u32_t)(entry->loss_hello_int * 1500.0),
1088 &entry->loss_timeout);
1091 static void olsr_time_out_packet_loss()
1093 struct link_entry *walker;
1095 // loop through all links
1097 for (walker = link_set; walker != NULL; walker = walker->next)
1099 // find a link that has not seen any packets for a very long
1100 // time (first time: 1.5 x htime, subsequently: 1.0 x htime)
1102 if (!TIMED_OUT(&walker->loss_timeout))
1105 // count the lost packet
1107 update_packet_loss_worker(walker, 1);
1109 // memorize that we've counted the packet, so that we do not
1110 // count it a second time later
1112 walker->loss_missed_hellos++;
1114 // next timeout in 1.0 x htime
1116 olsr_get_timestamp((olsr_u32_t)(walker->loss_hello_int * 1000.0),
1117 &walker->loss_timeout);
1121 struct link_entry *olsr_neighbor_best_link(union olsr_ip_addr *main)
1123 struct link_entry *walker;
1126 struct link_entry *res = NULL;
1128 // loop through all links
1130 for (walker = link_set; walker != NULL; walker = walker->next)
1132 // check whether it's a link to the requested neighbor and
1133 // whether the link's quality is better than what we have
1135 if(COMP_IP(main, &walker->neighbor->neighbor_main_addr))
1137 curr = walker->loss_link_quality * walker->neigh_link_quality;