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.80 2007/12/02 19:00:27 bernd67 Exp $
44 * Link sensing database for the OLSR routing daemon
49 #include "hysteresis.h"
52 #include "neighbor_table.h"
54 #include "scheduler.h"
60 static clock_t hold_time_neighbor;
62 struct link_entry *link_set;
66 check_link_status(const struct hello_message *message, const struct interface *in_if);
69 olsr_time_out_hysteresis(void);
71 static void olsr_time_out_packet_loss(void);
73 static struct link_entry *
74 add_link_entry(const union olsr_ip_addr *, const union olsr_ip_addr *, const union olsr_ip_addr *, double, double, const struct interface *);
77 olsr_time_out_link_set(void);
80 get_neighbor_status(const union olsr_ip_addr *);
84 get_hold_time_neighbor(void)
86 return hold_time_neighbor;
96 olsr_init_link_set(void)
100 hold_time_neighbor = (NEIGHB_HOLD_TIME*1000) / olsr_cnf->system_tick_divider;
102 olsr_register_timeout_function(&olsr_time_out_link_set, OLSR_TRUE);
103 if(olsr_cnf->use_hysteresis)
105 olsr_register_timeout_function(&olsr_time_out_hysteresis, OLSR_TRUE);
108 if (olsr_cnf->lq_level > 0)
110 olsr_register_timeout_function(&olsr_time_out_packet_loss, OLSR_TRUE);
117 * Get the status of a link. The status is based upon different
118 * timeouts in the link entry.
120 *@param remote address of the remote interface
122 *@return the link status of the link
125 lookup_link_status(const struct link_entry *entry)
128 if(entry == NULL || link_set == NULL)
134 if(olsr_cnf->use_hysteresis)
137 if L_LOST_LINK_time is not expired, the link is advertised
138 with a link type of LOST_LINK.
141 if(!TIMED_OUT(entry->L_LOST_LINK_time))
144 otherwise, if L_LOST_LINK_time is expired and L_link_pending
145 is set to "true", the link SHOULD NOT be advertised at all;
147 if(entry->L_link_pending == 1)
150 struct ipaddr_str buf;
151 OLSR_PRINTF(3, "HYST[%s]: Setting to HIDE\n", olsr_ip_to_string(&buf, &entry->neighbor_iface_addr));
156 otherwise, if L_LOST_LINK_time is expired and L_link_pending
157 is set to "false", the link is advertised as described
158 previously in section 6.
162 if(!TIMED_OUT(entry->SYM_time))
165 if(!TIMED_OUT(entry->ASYM_time))
179 *Find the "best" link status to a
182 *@param address the address to check for
184 *@return SYM_LINK if a symmetric link exists 0 if not
187 get_neighbor_status(const union olsr_ip_addr *address)
189 const union olsr_ip_addr *main_addr;
190 struct interface *ifs;
192 //printf("GET_NEIGHBOR_STATUS\n");
194 /* Find main address */
195 if(!(main_addr = mid_lookup_main_addr(address)))
198 //printf("\tmain: %s\n", olsr_ip_to_string(main_addr));
200 /* Loop trough local interfaces to check all possebilities */
201 for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next)
203 struct mid_address *aliases;
204 struct link_entry *lnk = lookup_link_entry(main_addr, NULL, ifs);
206 //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
207 //printf("%s : ", olsr_ip_to_string(main_addr));
210 //printf("%d\n", lookup_link_status(link));
211 if(lookup_link_status(lnk) == SYM_LINK)
215 for(aliases = mid_lookup_aliases(main_addr);
217 aliases = aliases->next_alias)
219 //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
220 //printf("%s : ", olsr_ip_to_string(&aliases->address));
221 lnk = lookup_link_entry(&aliases->alias, NULL, ifs);
224 //printf("%d\n", lookup_link_status(link));
226 if(lookup_link_status(lnk) == SYM_LINK)
236 * Find best link to a neighbor
240 get_best_link_to_neighbor(const union olsr_ip_addr *remote)
242 const union olsr_ip_addr *main_addr;
243 struct link_entry *walker, *good_link, *backup_link;
244 int curr_metric = MAX_IF_METRIC;
245 float curr_lq = -1.0;
247 // main address lookup
249 main_addr = mid_lookup_main_addr(remote);
251 // "remote" *already is* the main address
253 if (main_addr == NULL)
256 // we haven't selected any links, yet
261 // loop through all links that we have
263 for (walker = link_set; walker != NULL; walker = walker->next)
265 // if this is not a link to the neighour in question, skip
267 if (!ipequal(&walker->neighbor->neighbor_main_addr, main_addr))
270 // handle the non-LQ, RFC-compliant case
272 if (olsr_cnf->lq_level == 0)
274 struct interface *tmp_if;
276 // find the interface for the link - we select the link with the
277 // best local interface metric
278 tmp_if = walker->if_name ? if_ifwithname(walker->if_name) :
279 if_ifwithaddr(&walker->local_iface_addr);
284 // is this interface better than anything we had before?
286 if ((tmp_if->int_metric < curr_metric) ||
287 // use the requested remote interface address as a tie-breaker
288 ((tmp_if->int_metric == curr_metric) &&
289 ipequal(&walker->local_iface_addr, remote)))
291 // memorize the interface's metric
293 curr_metric = tmp_if->int_metric;
295 // prefer symmetric links over asymmetric links
297 if (lookup_link_status(walker) == SYM_LINK)
301 backup_link = walker;
305 // handle the LQ, non-RFC compliant case
311 // calculate the bi-directional link quality - we select the link
312 // with the best link quality
314 tmp_lq = walker->loss_link_quality * walker->neigh_link_quality;
316 // is this link better than anything we had before?
318 if((tmp_lq > curr_lq) ||
319 // use the requested remote interface address as a tie-breaker
320 ((tmp_lq == curr_lq) && ipequal(&walker->local_iface_addr, remote)))
322 // memorize the link quality
326 // prefer symmetric links over asymmetric links
328 if(lookup_link_status(walker) == SYM_LINK)
332 backup_link = walker;
337 // if we haven't found any symmetric links, try to return an
340 return good_link ? good_link : backup_link;
343 static void set_loss_link_multiplier(struct link_entry *entry)
345 struct interface *inter;
346 struct olsr_if *cfg_inter;
347 struct olsr_lq_mult *mult;
349 union olsr_ip_addr null_addr;
351 // find the interface for the link
353 inter = if_ifwithaddr(&entry->local_iface_addr);
355 // find the interface configuration for the interface
357 for (cfg_inter = olsr_cnf->interfaces; cfg_inter != NULL;
358 cfg_inter = cfg_inter->next)
359 if (cfg_inter->interf == inter)
362 // create a null address for comparison
364 memset(&null_addr, 0, sizeof (union olsr_ip_addr));
366 // loop through the multiplier entries
368 for (mult = cfg_inter->cnf->lq_mult; mult != NULL; mult = mult->next)
370 // use the default multiplier only if there isn't any entry that
371 // has a matching IP address
373 if ((ipequal(&mult->addr, &null_addr) && val < 0.0) ||
374 ipequal(&mult->addr, &entry->neighbor_iface_addr))
378 // if we have not found an entry, then use the default multiplier
383 // store the multiplier
385 entry->loss_link_multiplier = val;
389 *Delete all interface link entries
391 *@param interface ip address
395 del_if_link_entries(const union olsr_ip_addr *int_addr)
397 struct link_entry *tmp_link_set, *last_link_entry;
402 tmp_link_set = link_set;
403 last_link_entry = NULL;
408 if(ipequal(int_addr, &tmp_link_set->local_iface_addr))
410 if(last_link_entry != NULL)
412 last_link_entry->next = tmp_link_set->next;
414 /* Delete neighbor entry */
415 if(tmp_link_set->neighbor->linkcount == 1)
416 olsr_delete_neighbor_table(&tmp_link_set->neighbor->neighbor_main_addr);
418 tmp_link_set->neighbor->linkcount--;
420 //olsr_delete_neighbor_if_no_link(&tmp_link_set->neighbor->neighbor_main_addr);
421 changes_neighborhood = OLSR_TRUE;
424 tmp_link_set = last_link_entry;
428 link_set = tmp_link_set->next; /* CHANGED */
430 /* Delete neighbor entry */
431 if(tmp_link_set->neighbor->linkcount == 1)
432 olsr_delete_neighbor_table(&tmp_link_set->neighbor->neighbor_main_addr);
434 tmp_link_set->neighbor->linkcount--;
436 changes_neighborhood = OLSR_TRUE;
439 tmp_link_set = link_set;
444 last_link_entry = tmp_link_set;
445 tmp_link_set = tmp_link_set->next;
452 *Nothing mysterious here.
453 *Adding a new link entry to the link set.
455 *@param local the local IP address
456 *@param remote the remote IP address
457 *@param remote_main the remote nodes main address
458 *@param vtime the validity time of the entry
459 *@param htime the HELLO interval of the remote node
460 *@param local_if the local interface
463 static struct link_entry *
464 add_link_entry(const union olsr_ip_addr *local,
465 const union olsr_ip_addr *remote,
466 const union olsr_ip_addr *remote_main,
469 const struct interface *local_if)
471 struct link_entry *new_link;
472 struct neighbor_entry *neighbor;
473 struct link_entry *tmp_link_set = lookup_link_entry(remote, remote_main, local_if);
478 * if there exists no link tuple with
479 * L_neighbor_iface_addr == Source Address
485 struct ipaddr_str localbuf, rembuf;
487 OLSR_PRINTF(1, "Adding %s=>%s to link set\n", olsr_ip_to_string(&localbuf, local), olsr_ip_to_string(&rembuf, remote));
491 /* a new tuple is created with... */
493 new_link = olsr_malloc(sizeof(struct link_entry), "new link entry");
495 memset(new_link, 0 , sizeof(struct link_entry));
497 /* copy if_name, if it is defined */
498 if (local_if->int_name)
500 new_link->if_name = olsr_malloc(strlen(local_if->int_name)+1, "target of if_name in new link entry");
501 strcpy(new_link->if_name, local_if->int_name);
503 new_link->if_name = NULL;
506 * L_local_iface_addr = Address of the interface
507 * which received the HELLO message
509 //printf("\tLocal IF: %s\n", olsr_ip_to_string(local));
510 new_link->local_iface_addr = *local;
511 /* L_neighbor_iface_addr = Source Address */
512 new_link->neighbor_iface_addr = *remote;
514 /* L_SYM_time = current time - 1 (expired) */
515 new_link->SYM_time = now_times - 1;
517 /* L_time = current time + validity time */
518 new_link->time = GET_TIMESTAMP(vtime*1000);
520 new_link->prev_status = ASYM_LINK;
523 if(olsr_cnf->use_hysteresis)
525 new_link->L_link_pending = 1;
526 new_link->L_LOST_LINK_time = GET_TIMESTAMP(vtime*1000);
527 new_link->hello_timeout = GET_TIMESTAMP(htime*1500);
528 new_link->last_htime = htime;
529 new_link->olsr_seqno = 0;
530 new_link->olsr_seqno_valid = OLSR_FALSE;
533 new_link->L_link_quality = 0.0;
535 if (olsr_cnf->lq_level > 0)
537 new_link->loss_hello_int = htime;
539 new_link->loss_timeout = GET_TIMESTAMP(htime * 1500.0);
541 new_link->loss_seqno = 0;
542 new_link->loss_seqno_valid = 0;
543 new_link->loss_missed_hellos = 0;
545 new_link->lost_packets = 0;
546 new_link->total_packets = 0;
548 new_link->loss_index = 0;
550 memset(new_link->loss_bitmap, 0, sizeof (new_link->loss_bitmap));
552 set_loss_link_multiplier(new_link);
555 new_link->loss_link_quality = 0.0;
556 new_link->neigh_link_quality = 0.0;
558 new_link->loss_link_quality2 = 0.0;
559 new_link->neigh_link_quality2 = 0.0;
561 new_link->saved_loss_link_quality = 0.0;
562 new_link->saved_neigh_link_quality = 0.0;
565 new_link->next = link_set;
570 * Create the neighbor entry
573 /* Neighbor MUST exist! */
574 neighbor = olsr_lookup_neighbor_table(remote_main);
579 struct ipaddr_str buf;
581 OLSR_PRINTF(3, "ADDING NEW NEIGHBOR ENTRY %s FROM LINK SET\n", olsr_ip_to_string(&buf, remote_main));
583 neighbor = olsr_insert_neighbor_table(remote_main);
586 neighbor->linkcount++;
587 new_link->neighbor = neighbor;
588 if(!ipequal(remote, remote_main))
590 /* Add MID alias if not already registered */
591 /* This is kind of sketchy... and not specified
592 * in the RFC. We can only guess a vtime.
593 * We'll go for one that is hopefully long
594 * enough in most cases. 10 seconds
597 /* Erik Tromp - commented out. It is not RFC-compliant. Also, MID aliases
598 * that are not explicitly declared by a node will be removed as soon as
599 * the olsr_prune_aliases(...) function is called.
601 * OLSR_PRINTF(1, "Adding MID alias main %s ", olsr_ip_to_string(remote_main));
602 * OLSR_PRINTF(1, "-> %s based on HELLO\n\n", olsr_ip_to_string(remote));
603 * insert_mid_alias(remote_main, remote, MID_ALIAS_HACK_VTIME);
612 *Lookup the status of a link.
614 *@param int_addr address of the remote interface
616 *@return 1 of the link is symmertic 0 if not
620 check_neighbor_link(const union olsr_ip_addr *int_addr)
622 struct link_entry *tmp_link_set;
624 tmp_link_set = link_set;
628 if(ipequal(int_addr, &tmp_link_set->neighbor_iface_addr))
629 return lookup_link_status(tmp_link_set);
630 tmp_link_set = tmp_link_set->next;
639 *@param remote the remote interface address
640 *@param remote_main the remote nodes main address
641 *@param local the local interface address
643 *@return the link entry if found, NULL if not
646 lookup_link_entry(const union olsr_ip_addr *remote, const union olsr_ip_addr *remote_main, const struct interface *local)
648 struct link_entry *tmp_link_set;
650 tmp_link_set = link_set;
654 if(ipequal(remote, &tmp_link_set->neighbor_iface_addr) &&
655 (tmp_link_set->if_name
656 ? !strcmp(tmp_link_set->if_name, local->int_name)
657 : ipequal(&local->ip_addr, &tmp_link_set->local_iface_addr)
659 /* check the remote-main address only if there is one given */
660 (remote_main == NULL || ipequal(remote_main, &tmp_link_set->neighbor->neighbor_main_addr))
663 tmp_link_set = tmp_link_set->next;
676 *Update a link entry. This is the "main entrypoint" in
677 *the link-sensing. This function is called from the HELLO
679 *It makes sure a entry is updated or created.
681 *@param local the local IP address
682 *@param remote the remote IP address
683 *@param message the HELLO message
684 *@param in_if the interface on which this HELLO was received
686 *@return the link_entry struct describing this link entry
689 update_link_entry(const union olsr_ip_addr *local,
690 const union olsr_ip_addr *remote,
691 const struct hello_message *message,
692 const struct interface *in_if)
694 struct link_entry *entry;
696 /* Add if not registered */
697 entry = add_link_entry(local, remote, &message->source_addr, message->vtime, message->htime, in_if);
699 /* Update ASYM_time */
700 //printf("Vtime is %f\n", message->vtime);
701 /* L_ASYM_time = current time + validity time */
702 entry->ASYM_time = GET_TIMESTAMP(message->vtime*1000);
704 entry->prev_status = check_link_status(message, in_if);
706 //printf("Status %d\n", status);
708 switch(entry->prev_status)
711 /* L_SYM_time = current time - 1 (i.e., expired) */
712 entry->SYM_time = now_times - 1;
717 /* L_SYM_time = current time + validity time */
718 //printf("updating SYM time for %s\n", olsr_ip_to_string(remote));
719 entry->SYM_time = GET_TIMESTAMP(message->vtime*1000);
721 /* L_time = L_SYM_time + NEIGHB_HOLD_TIME */
722 entry->time = entry->SYM_time + hold_time_neighbor;
728 /* L_time = max(L_time, L_ASYM_time) */
729 if(entry->time < entry->ASYM_time)
730 entry->time = entry->ASYM_time;
734 printf("Updating link LOCAL: %s ", olsr_ip_to_string(local));
735 printf("REMOTE: %s\n", olsr_ip_to_string(remote));
736 printf("VTIME: %f ", message->vtime);
737 printf("STATUS: %d\n", status);
740 /* Update hysteresis values */
741 if(olsr_cnf->use_hysteresis)
742 olsr_process_hysteresis(entry);
744 /* Update neighbor */
745 update_neighbor_status(entry->neighbor, get_neighbor_status(remote));
752 * Fuction that updates all registered pointers to
753 * one neighbor entry with another pointer
754 * Used by MID updates.
756 *@old the pointer to replace
757 *@new the pointer to use instead of "old"
759 *@return the number of entries updated
762 replace_neighbor_link_set(const struct neighbor_entry *old,
763 struct neighbor_entry *new)
765 struct link_entry *tmp_link_set;
773 tmp_link_set = link_set;
778 if(tmp_link_set->neighbor == old)
780 tmp_link_set->neighbor = new;
783 tmp_link_set = tmp_link_set->next;
792 *Checks the link status to a neighbor by
793 *looking in a received HELLO message.
795 *@param message the HELLO message to check
797 *@return the link status
800 check_link_status(const struct hello_message *message, const struct interface *in_if)
802 int ret = UNSPEC_LINK;
803 struct hello_neighbor *neighbors;
805 neighbors = message->neighbors;
807 while(neighbors!=NULL)
810 * Note: If a neigh has 2 cards we can reach, the neigh
811 * will send a Hello with the same IP mentined twice
813 if(ipequal(&neighbors->address, &in_if->ip_addr))
816 ret = neighbors->link;
817 if (SYM_LINK == ret) break;
820 neighbors = neighbors->next;
829 *Time out the link set. In other words, the link
830 *set is traversed and all non-valid entries are
835 olsr_time_out_link_set(void)
838 struct link_entry *tmp_link_set, *last_link_entry;
843 tmp_link_set = link_set;
844 last_link_entry = NULL;
849 if(TIMED_OUT(tmp_link_set->time))
851 if(last_link_entry != NULL)
853 last_link_entry->next = tmp_link_set->next;
855 /* Delete neighbor entry */
856 if(tmp_link_set->neighbor->linkcount == 1)
857 olsr_delete_neighbor_table(&tmp_link_set->neighbor->neighbor_main_addr);
859 tmp_link_set->neighbor->linkcount--;
861 //olsr_delete_neighbor_if_no_link(&tmp_link_set->neighbor->neighbor_main_addr);
862 changes_neighborhood = OLSR_TRUE;
863 free(tmp_link_set->if_name);
865 tmp_link_set = last_link_entry;
869 link_set = tmp_link_set->next; /* CHANGED */
871 /* Delete neighbor entry */
872 if(tmp_link_set->neighbor->linkcount == 1)
873 olsr_delete_neighbor_table(&tmp_link_set->neighbor->neighbor_main_addr);
875 tmp_link_set->neighbor->linkcount--;
877 changes_neighborhood = OLSR_TRUE;
879 free(tmp_link_set->if_name);
881 tmp_link_set = link_set;
885 else if((tmp_link_set->prev_status == SYM_LINK) &&
886 TIMED_OUT(tmp_link_set->SYM_time))
888 tmp_link_set->prev_status = lookup_link_status(tmp_link_set);
889 update_neighbor_status(tmp_link_set->neighbor,
890 get_neighbor_status(&tmp_link_set->neighbor_iface_addr));
891 changes_neighborhood = OLSR_TRUE;
894 last_link_entry = tmp_link_set;
895 tmp_link_set = tmp_link_set->next;
905 *Updates links that we have not received
906 *HELLO from in expected time according to
912 olsr_time_out_hysteresis(void)
914 struct link_entry *tmp_link_set;
919 tmp_link_set = link_set;
923 if(TIMED_OUT(tmp_link_set->hello_timeout))
926 struct ipaddr_str buf;
928 tmp_link_set->L_link_quality = olsr_hyst_calc_instability(tmp_link_set->L_link_quality);
929 OLSR_PRINTF(1, "HYST[%s] HELLO timeout %0.3f\n", olsr_ip_to_string(&buf, &tmp_link_set->neighbor_iface_addr), tmp_link_set->L_link_quality);
930 /* Update hello_timeout - NO SLACK THIS TIME */
931 tmp_link_set->hello_timeout = GET_TIMESTAMP(tmp_link_set->last_htime*1000);
932 /* Recalculate status */
933 /* Update hysteresis values */
934 olsr_process_hysteresis(tmp_link_set);
936 /* update neighbor status */
939 /* Update neighbor */
940 update_neighbor_status(tmp_link_set->neighbor,
941 get_neighbor_status(&tmp_link_set->neighbor_iface_addr));
943 /* Update seqno - not mentioned in the RFC... kind of a hack.. */
944 tmp_link_set->olsr_seqno++;
946 tmp_link_set = tmp_link_set->next;
952 void olsr_print_link_set(void)
955 /* The whole function makes no sense without it. */
956 struct link_entry *walker;
957 const int addrsize = olsr_cnf->ip_version == AF_INET ? 15 : 39;
959 OLSR_PRINTF(0, "\n--- %02d:%02d:%02d.%02d ---------------------------------------------------- LINKS\n\n",
963 (int)now.tv_usec/10000U);
964 OLSR_PRINTF(1, "%-*s %-6s %-6s %-6s %-6s %-6s %s\n", addrsize, "IP address", "hyst", "LQ", "lost", "total","NLQ", "ETX");
966 for (walker = link_set; walker != NULL; walker = walker->next)
968 struct ipaddr_str buf;
971 if (walker->loss_link_quality < MIN_LINK_QUALITY || walker->neigh_link_quality < MIN_LINK_QUALITY)
974 etx = 1.0 / (walker->loss_link_quality * walker->neigh_link_quality);
976 OLSR_PRINTF(1, "%-*s %5.3f %5.3f %-3d %-3d %5.3f %.2f\n",
977 addrsize, olsr_ip_to_string(&buf, &walker->neighbor_iface_addr),
978 walker->L_link_quality,
979 walker->loss_link_quality,
980 walker->lost_packets,
981 walker->total_packets,
982 walker->neigh_link_quality,
988 static void update_packet_loss_worker(struct link_entry *entry, int lost)
990 unsigned char mask = 1 << (entry->loss_index & 7);
991 const int idx = entry->loss_index >> 3;
992 double rel_lq, saved_lq;
998 if ((entry->loss_bitmap[idx] & mask) != 0)
1000 // but the packet that we replace was lost
1001 // => decrement packet loss
1003 entry->loss_bitmap[idx] &= ~mask;
1004 entry->lost_packets--;
1012 if ((entry->loss_bitmap[idx] & mask) == 0)
1014 // but the packet that we replace was not lost
1015 // => increment packet loss
1017 entry->loss_bitmap[idx] |= mask;
1018 entry->lost_packets++;
1022 // move to the next packet
1024 entry->loss_index++;
1026 // wrap around at the end of the packet loss window
1028 if (entry->loss_index >= olsr_cnf->lq_wsize)
1029 entry->loss_index = 0;
1031 // count the total number of handled packets up to the window size
1033 if (entry->total_packets < olsr_cnf->lq_wsize)
1034 entry->total_packets++;
1036 // the current reference link quality
1038 saved_lq = entry->saved_loss_link_quality;
1040 if (saved_lq == 0.0)
1043 // calculate the new link quality
1045 // start slowly: receive the first packet => link quality = 1 / n
1046 // (n = window size)
1047 entry->loss_link_quality =
1048 (float)(entry->total_packets - entry->lost_packets) /
1049 (float)(olsr_cnf->lq_wsize < (2 * 4) ? olsr_cnf->lq_wsize:
1050 4 * (((float)olsr_cnf->lq_wsize / 4 - 1) * entry->total_packets + olsr_cnf->lq_wsize) / olsr_cnf->lq_wsize);
1052 // multiply the calculated link quality with the user-specified multiplier
1054 entry->loss_link_quality *= entry->loss_link_multiplier;
1056 // if the link quality has changed by more than 10 percent,
1057 // print the new link quality table
1059 rel_lq = entry->loss_link_quality / saved_lq;
1061 if (rel_lq > 1.1 || rel_lq < 0.9)
1063 entry->saved_loss_link_quality = entry->loss_link_quality;
1065 if (olsr_cnf->lq_dlimit > 0)
1067 changes_neighborhood = OLSR_TRUE;
1068 changes_topology = OLSR_TRUE;
1072 OLSR_PRINTF(3, "Skipping Dijkstra (1)\n");
1074 // create a new ANSN
1076 // XXX - we should check whether we actually
1077 // announce this neighbour
1079 signal_link_changes(OLSR_TRUE);
1083 void olsr_update_packet_loss_hello_int(struct link_entry *entry,
1084 double loss_hello_int)
1086 // called for every LQ HELLO message - update the timeout
1087 // with the htime value from the message
1089 entry->loss_hello_int = loss_hello_int;
1092 void olsr_update_packet_loss(const union olsr_ip_addr *rem, const struct interface *loc,
1095 struct link_entry *entry;
1097 // called for every OLSR packet
1099 entry = lookup_link_entry(rem, NULL, loc);
1101 // it's the very first LQ HELLO message - we do not yet have a link
1106 // a) have we seen a packet before, i.e. is the sequence number valid?
1108 // b) heuristically detect a restart (= sequence number reset)
1111 if (entry->loss_seqno_valid != 0 &&
1112 (unsigned short)(seqno - entry->loss_seqno) < 100)
1114 // loop through all lost packets
1116 while (entry->loss_seqno != seqno)
1118 // have we already considered all lost LQ HELLO messages?
1120 if (entry->loss_missed_hellos == 0)
1121 update_packet_loss_worker(entry, 1);
1123 // if not, then decrement the number of lost LQ HELLOs
1126 entry->loss_missed_hellos--;
1128 entry->loss_seqno++;
1132 // we have received a packet, otherwise this function would not
1135 update_packet_loss_worker(entry, 0);
1139 entry->loss_missed_hellos = 0;
1140 entry->loss_seqno = seqno + 1;
1142 // we now have a valid serial number for sure
1144 entry->loss_seqno_valid = 1;
1146 // timeout for the first lost packet is 1.5 x htime
1148 entry->loss_timeout = GET_TIMESTAMP(entry->loss_hello_int * 1500.0);
1151 static void olsr_time_out_packet_loss(void)
1153 struct link_entry *walker;
1155 // loop through all links
1157 for (walker = link_set; walker != NULL; walker = walker->next)
1159 // find a link that has not seen any packets for a very long
1160 // time (first time: 1.5 x htime, subsequently: 1.0 x htime)
1162 if (!TIMED_OUT(walker->loss_timeout))
1165 // count the lost packet
1167 update_packet_loss_worker(walker, 1);
1169 // memorize that we've counted the packet, so that we do not
1170 // count it a second time later
1172 walker->loss_missed_hellos++;
1174 // next timeout in 1.0 x htime
1176 walker->loss_timeout = GET_TIMESTAMP(walker->loss_hello_int * 1000.0);
1180 void olsr_update_dijkstra_link_qualities(void)
1182 struct link_entry *walker;
1184 for (walker = link_set; walker != NULL; walker = walker->next)
1186 walker->loss_link_quality2 = walker->loss_link_quality;
1187 walker->neigh_link_quality2 = walker->neigh_link_quality;
1191 float olsr_calc_link_etx(const struct link_entry *link)
1193 return link->loss_link_quality < MIN_LINK_QUALITY ||
1194 link->neigh_link_quality < MIN_LINK_QUALITY
1196 : 1.0 / (link->loss_link_quality * link->neigh_link_quality);