2 * The olsr.org Optimized Link-State Routing daemon(olsrd)
3 * Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org)
4 * LSDB rewrite (c) 2007, Hannes Gredler (hannes@gredler.at)
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 * Visit http://www.olsr.org for more information.
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.
47 #include "scheduler.h"
49 #include "common/avl.h"
50 #include "lq_packet.h"
52 #include "lq_plugin.h"
53 #include "olsr_cookie.h"
57 /* Root of the link state database */
58 struct avl_tree tc_tree;
59 struct tc_entry *tc_myself; /* Shortcut to ourselves */
61 /* Some cookies for stats keeping */
62 struct olsr_cookie_info *tc_edge_gc_timer_cookie = NULL;
63 struct olsr_cookie_info *tc_validity_timer_cookie = NULL;
64 struct olsr_cookie_info *tc_edge_mem_cookie = NULL;
65 struct olsr_cookie_info *tc_mem_cookie = NULL;
68 * Sven-Ola 2007-Dec: These four constants include an assumption
69 * on how long a typical olsrd mesh memorizes (TC) messages in the
70 * RAM of all nodes and how many neighbour changes between TC msgs.
71 * In Berlin, we encounter hop values up to 70 which means that
72 * messages may live up to ~15 minutes cycling between nodes and
73 * obviously breaking out of the timeout_dup() jail. It may be more
74 * correct to dynamically adapt those constants, e.g. by using the
75 * max hop number (denotes size-of-mesh) in some form or maybe
76 * a factor indicating how many (old) versions of olsrd are on.
79 /* Value window for ansn, identifies old messages to be ignored */
80 #define TC_ANSN_WINDOW 256
81 /* Value window for seqno, identifies old messages to be ignored */
82 #define TC_SEQNO_WINDOW 1024
84 /* Enlarges the value window for upcoming ansn/seqno to be accepted */
85 #define TC_ANSN_WINDOW_MULT 4
86 /* Enlarges the value window for upcoming ansn/seqno to be accepted */
87 #define TC_SEQNO_WINDOW_MULT 8
90 olsr_seq_inrange_low(int beg, int end, olsr_u16_t seq)
93 if (seq >= (olsr_u16_t)beg || seq < end) {
96 } else if (end >= 0x10000) {
97 if (seq >= beg || seq < (olsr_u16_t)end) {
100 } else if (seq >= beg && seq < end) {
107 olsr_seq_inrange_high(int beg, int end, olsr_u16_t seq)
110 if (seq > (olsr_u16_t)beg || seq <= end) {
113 } else if (end >= 0x10000) {
114 if (seq > beg || seq <= (olsr_u16_t)end) {
117 } else if (seq > beg && seq <= end) {
124 * Add a new tc_entry to the tc tree
126 * @param (last)adr address of the entry
127 * @return a pointer to the created entry
129 static struct tc_entry *
130 olsr_add_tc_entry(union olsr_ip_addr *adr)
132 #if !defined(NODEBUG) && defined(DEBUG)
133 struct ipaddr_str buf;
138 OLSR_PRINTF(1, "TC: add entry %s\n", olsr_ip_to_string(&buf, adr));
141 tc = olsr_cookie_malloc(tc_mem_cookie);
148 tc->vertex_node.key = &tc->addr;
151 * Insert into the global tc tree.
153 avl_insert(&tc_tree, &tc->vertex_node, AVL_DUP_NO);
154 olsr_lock_tc_entry(tc);
157 * Initialize subtrees for edges and prefixes.
159 avl_init(&tc->edge_tree, avl_comp_default);
160 avl_init(&tc->prefix_tree, avl_comp_prefix_default);
163 * Add a rt_path for ourselves.
165 olsr_insert_routing_table(adr, olsr_cnf->maxplen, adr,
172 * Initialize the topology set
178 OLSR_PRINTF(5, "TC: init topo\n");
180 avl_init(&tc_tree, avl_comp_default);
183 * Get some cookies for getting stats to ease troubleshooting.
185 tc_edge_gc_timer_cookie = olsr_alloc_cookie("TC edge GC", OLSR_COOKIE_TYPE_TIMER);
186 tc_validity_timer_cookie = olsr_alloc_cookie("TC validity", OLSR_COOKIE_TYPE_TIMER);
188 tc_edge_mem_cookie = olsr_alloc_cookie("TC edge", OLSR_COOKIE_TYPE_MEMORY);
189 olsr_cookie_set_memory_size(tc_edge_mem_cookie, sizeof(struct tc_edge_entry));
191 tc_mem_cookie = olsr_alloc_cookie("TC", OLSR_COOKIE_TYPE_MEMORY);
192 olsr_cookie_set_memory_size(tc_mem_cookie, sizeof(struct tc_entry));
195 * Add a TC entry for ourselves.
197 tc_myself = olsr_add_tc_entry(&olsr_cnf->main_addr);
201 * The main ip address has changed.
205 olsr_change_myself_tc(void)
210 * Check if there was a change.
212 if (ipequal(&tc_myself->addr, &olsr_cnf->main_addr)) {
217 * Flush our own tc_entry.
219 olsr_delete_tc_entry(tc_myself);
223 * The old entry for ourselves is gone, generate a new one and trigger SPF.
225 tc_myself = olsr_add_tc_entry(&olsr_cnf->main_addr);
226 changes_topology = OLSR_TRUE;
230 * Increment the reference counter.
233 olsr_lock_tc_entry(struct tc_entry *tc)
239 * Unlock and free a tc_entry once all references are gone.
242 olsr_unlock_tc_entry(struct tc_entry *tc)
244 if (--tc->refcount) {
249 * All references are gone.
251 olsr_cookie_free(tc_mem_cookie, tc);
257 * @param entry the TC entry to delete
261 olsr_delete_tc_entry(struct tc_entry *tc)
263 struct tc_edge_entry *tc_edge;
266 struct ipaddr_str buf;
267 OLSR_PRINTF(1, "TC: del entry %s\n", olsr_ip_to_string(&buf, &tc->addr));
271 * Delete the rt_path for ourselves.
273 olsr_delete_routing_table(&tc->addr, olsr_cnf->maxplen, &tc->addr);
275 /* The edgetree and prefix tree must be empty before */
276 OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
277 olsr_delete_tc_edge_entry(tc_edge);
278 } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
280 OLSR_FOR_ALL_PREFIX_ENTRIES(tc, rtp) {
281 olsr_delete_rt_path(rtp);
282 } OLSR_FOR_ALL_PREFIX_ENTRIES_END(tc, rtp);
284 /* Stop running timers */
285 olsr_stop_timer(tc->edge_gc_timer);
286 tc->edge_gc_timer = NULL;
287 olsr_stop_timer(tc->validity_timer);
288 tc->validity_timer = NULL;
290 avl_delete(&tc_tree, &tc->vertex_node);
291 olsr_unlock_tc_entry(tc);
295 * Look up a entry from the TC tree based on address
297 * @param adr the address to look for
298 * @return the entry found or NULL
301 olsr_lookup_tc_entry(union olsr_ip_addr *adr)
303 struct avl_node *node;
306 OLSR_PRINTF(1, "TC: lookup entry\n");
309 node = avl_find(&tc_tree, adr);
311 return (node ? vertex_tree2tc(node) : NULL);
315 * Lookup a tc entry. Creates one if it does not exist yet.
318 olsr_locate_tc_entry(union olsr_ip_addr *adr)
322 if (!(tc = olsr_lookup_tc_entry(adr))) {
323 return olsr_add_tc_entry(adr);
329 * Format tc_edge contents into a buffer.
332 olsr_tc_edge_to_string(struct tc_edge_entry *tc_edge)
334 static char buf[128];
335 struct ipaddr_str addrbuf, dstbuf;
336 struct tc_entry *tc = tc_edge->tc;
337 struct lqtextbuffer lqbuffer1, lqbuffer2;
339 snprintf(buf, sizeof(buf),
340 "%s > %s, cost (%6s) %s",
341 olsr_ip_to_string(&addrbuf, &tc->addr),
342 olsr_ip_to_string(&dstbuf, &tc_edge->T_dest_addr),
343 get_tc_edge_entry_text(tc_edge, &lqbuffer1),
344 get_linkcost_text(tc_edge->cost, OLSR_FALSE, &lqbuffer2));
350 * Wrapper for the timer callback.
351 * A TC entry has not been refreshed in time.
352 * Remove it from the link-state database.
355 olsr_expire_tc_entry(void *context)
359 tc = (struct tc_entry *)context;
360 tc->validity_timer = NULL;
362 olsr_delete_tc_entry(tc);
363 changes_topology = OLSR_TRUE;
367 * Wrapper for the timer callback.
368 * Does the garbage collection of older ansn entries after no edge addition to
369 * the TC entry has happened for OLSR_TC_EDGE_GC_TIME.
372 olsr_expire_tc_edge_gc(void *context)
376 tc = (struct tc_entry *)context;
377 tc->edge_gc_timer = NULL;
379 if (olsr_delete_outdated_tc_edges(tc)) {
380 changes_topology = OLSR_TRUE;
385 * If the edge does not have a minimum acceptable link quality
386 * set the etx cost to infinity such that it gets ignored during
389 * @return 1 if the change of the etx value was relevant
392 olsr_calc_tc_edge_entry_etx(struct tc_edge_entry *tc_edge)
397 * Some sanity check before recalculating the etx.
399 if (olsr_cnf->lq_level < 1) {
404 tc_edge->cost = olsr_calc_tc_cost(tc_edge);
406 return olsr_is_relevant_costchange(old, tc_edge->cost);
410 * Add a new tc_edge_entry to the tc_edge_tree
412 * @param (last)adr address of the entry
413 * @return a pointer to the created entry
415 struct tc_edge_entry *
416 olsr_add_tc_edge_entry(struct tc_entry *tc, union olsr_ip_addr *addr,
419 #if !defined(NODEBUG) && defined(DEBUG)
420 struct ipaddr_str buf;
422 struct tc_entry *tc_neighbor;
423 struct tc_edge_entry *tc_edge, *tc_edge_inv;
425 tc_edge = olsr_malloc_tc_edge_entry("add TC edge");
431 tc_edge->T_dest_addr = *addr;
432 tc_edge->ansn = ansn;
433 tc_edge->edge_node.key = &tc_edge->T_dest_addr;
436 * Insert into the edge tree.
438 avl_insert(&tc->edge_tree, &tc_edge->edge_node, AVL_DUP_NO);
439 olsr_lock_tc_entry(tc);
442 * Connect backpointer.
447 * Check if the neighboring router and the inverse edge is in the lsdb.
448 * Create short cuts to the inverse edge for faster SPF execution.
450 tc_neighbor = olsr_lookup_tc_entry(&tc_edge->T_dest_addr);
453 OLSR_PRINTF(1, "TC: found neighbor tc_entry %s\n",
454 olsr_ip_to_string(&buf, &tc_neighbor->addr));
457 tc_edge_inv = olsr_lookup_tc_edge(tc_neighbor, &tc->addr);
460 OLSR_PRINTF(1, "TC: found inverse edge for %s\n",
461 olsr_ip_to_string(&buf, &tc_edge_inv->T_dest_addr));
465 * Connect the edges mutually.
467 tc_edge_inv->edge_inv = tc_edge;
468 tc_edge->edge_inv = tc_edge_inv;
476 olsr_calc_tc_edge_entry_etx(tc_edge);
479 OLSR_PRINTF(1, "TC: add edge entry %s\n", olsr_tc_edge_to_string(tc_edge));
487 * Delete a TC edge entry.
489 * @param tc the TC entry
490 * @param tc_edge the TC edge entry
493 olsr_delete_tc_edge_entry(struct tc_edge_entry *tc_edge)
496 struct tc_edge_entry *tc_edge_inv;
499 OLSR_PRINTF(1, "TC: del edge entry %s\n", olsr_tc_edge_to_string(tc_edge));
503 avl_delete(&tc->edge_tree, &tc_edge->edge_node);
504 olsr_unlock_tc_entry(tc);
507 * Clear the backpointer of our inverse edge.
509 tc_edge_inv = tc_edge->edge_inv;
511 tc_edge_inv->edge_inv = NULL;
519 * Delete all destinations that have a lower ANSN.
521 * @param tc the entry to delete edges from
522 * @param ansn the advertised neighbor set sequence number
523 * @return 1 if any destinations were deleted 0 if not
526 olsr_delete_outdated_tc_edges(struct tc_entry *tc)
528 struct tc_edge_entry *tc_edge;
529 olsr_bool retval = OLSR_FALSE;
532 OLSR_PRINTF(5, "TC: deleting outdated TC-edge entries\n");
535 OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
536 if (SEQNO_GREATER_THAN(tc->ansn, tc_edge->ansn)) {
537 olsr_delete_tc_edge_entry(tc_edge);
540 } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
546 * Update an edge registered on an entry.
547 * Creates new edge-entries if not registered.
548 * Bases update on a received TC message
550 * @param entry the TC entry to check
551 * @pkt the TC edge entry in the packet
552 * @return 1 if entries are added 0 if not
555 olsr_tc_update_edge(struct tc_entry *tc, olsr_u16_t ansn,
556 const unsigned char **curr)
558 struct tc_edge_entry *tc_edge;
559 union olsr_ip_addr neighbor;
565 * Fetch the per-edge data
567 pkt_get_ipaddress(curr, &neighbor);
569 /* First check if we know this edge */
570 tc_edge = olsr_lookup_tc_edge(tc, &neighbor);
575 * Yet unknown - create it.
576 * Check if the address is allowed.
578 if (!olsr_validate_address(&neighbor)) {
582 tc_edge = olsr_add_tc_edge_entry(tc, &neighbor, ansn);
584 olsr_deserialize_tc_lq_pair(curr, tc_edge);
590 * We know this edge - Update entry.
592 tc_edge->ansn = ansn;
595 * Update link quality if configured.
597 if (olsr_cnf->lq_level > 0) {
598 olsr_deserialize_tc_lq_pair(curr, tc_edge);
604 if (olsr_calc_tc_edge_entry_etx(tc_edge)) {
605 if (tc->msg_hops <= olsr_cnf->lq_dlimit) {
612 OLSR_PRINTF(1, "TC: chg edge entry %s\n",
613 olsr_tc_edge_to_string(tc_edge));
623 * Lookup an edge hanging off a TC entry.
625 * @param entry the entry to check
626 * @param dst_addr the destination address to check for
627 * @return a pointer to the tc_edge found - or NULL
629 struct tc_edge_entry *
630 olsr_lookup_tc_edge(struct tc_entry *tc, union olsr_ip_addr *edge_addr)
632 struct avl_node *edge_node;
635 OLSR_PRINTF(1, "TC: lookup dst\n");
638 edge_node = avl_find(&tc->edge_tree, edge_addr);
640 return (edge_node ? edge_tree2tc_edge(edge_node) : NULL);
644 * Print the topology table to stdout
647 olsr_print_tc_table(void)
650 /* The whole function makes no sense without it. */
652 const int ipwidth = olsr_cnf->ip_version == AF_INET ? 15 : 30;
654 OLSR_PRINTF(1, "\n--- %s ------------------------------------------------- TOPOLOGY\n\n"
655 "%-*s %-*s %-5s %-5s %s %s\n",
656 olsr_wallclock_string(),
657 ipwidth, "Source IP addr", ipwidth, "Dest IP addr", "LQ", "ILQ", "ETX", "UP");
659 OLSR_FOR_ALL_TC_ENTRIES(tc) {
660 struct tc_edge_entry *tc_edge;
661 OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
662 struct ipaddr_str addrbuf, dstaddrbuf;
663 struct lqtextbuffer lqbuffer1, lqbuffer2;
665 OLSR_PRINTF(1, "%-*s %-*s (%-10s) %s\n",
666 ipwidth, olsr_ip_to_string(&addrbuf, &tc->addr),
667 ipwidth, olsr_ip_to_string(&dstaddrbuf, &tc_edge->T_dest_addr),
668 get_tc_edge_entry_text(tc_edge, &lqbuffer1),
669 get_linkcost_text(tc_edge->cost, OLSR_FALSE, &lqbuffer2));
671 } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
672 } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
677 * Process an incoming TC or TC_LQ message.
679 * If the message is interesting enough, update our edges for it,
680 * trigger SPF and finally flood it to all our 2way neighbors.
682 * The order for extracting data off the message does matter,
683 * as every call to pkt_get increases the packet offset and
684 * hence the spot we are looking at.
687 olsr_input_tc(union olsr_message *msg,
688 struct interface *input_if __attribute__((unused)),
689 union olsr_ip_addr *from_addr)
692 struct ipaddr_str buf;
694 olsr_u16_t size, msg_seq, ansn;
695 olsr_u8_t type, ttl, msg_hops;
697 unsigned int vtime_s;
698 union olsr_ip_addr originator;
699 const unsigned char *limit, *curr;
707 /* We are only interested in TC message types. */
708 pkt_get_u8(&curr, &type);
709 if ((type != LQ_TC_MESSAGE) && (type != TC_MESSAGE)) {
713 pkt_get_double(&curr, &vtime);
714 vtime_s = (unsigned int)vtime;
715 pkt_get_u16(&curr, &size);
717 pkt_get_ipaddress(&curr, &originator);
719 /* Copy header values */
720 pkt_get_u8(&curr, &ttl);
721 pkt_get_u8(&curr, &msg_hops);
722 pkt_get_u16(&curr, &msg_seq);
723 pkt_get_u16(&curr, &ansn);
724 pkt_ignore_u16(&curr);
726 tc = olsr_lookup_tc_entry(&originator);
728 if (tc && 0 != tc->edge_tree.count) {
729 if (olsr_seq_inrange_high(
730 (int)tc->msg_seq - TC_SEQNO_WINDOW,
733 olsr_seq_inrange_high(
734 (int)tc->ansn - TC_ANSN_WINDOW,
738 * Ignore already seen seq/ansn values (small window for mesh memory)
740 if ((tc->msg_seq == msg_seq) || (tc->ignored++ < 32)) {
744 OLSR_PRINTF(1, "Ignored to much LQTC's for %s, restarting\n",
745 olsr_ip_to_string(&buf, &originator));
747 } else if (!olsr_seq_inrange_high(
749 (int)tc->msg_seq + TC_SEQNO_WINDOW * TC_SEQNO_WINDOW_MULT,
751 !olsr_seq_inrange_low(
753 (int)tc->ansn + TC_ANSN_WINDOW * TC_ANSN_WINDOW_MULT,
757 * Only accept future seq/ansn values (large window for node reconnects).
758 * Restart in all other cases. Ignore a single stray message.
760 if (!tc->err_seq_valid) {
761 tc->err_seq = msg_seq;
762 tc->err_seq_valid = OLSR_TRUE;
764 if (tc->err_seq == msg_seq) {
768 OLSR_PRINTF(2, "Detected node restart for %s\n",
769 olsr_ip_to_string(&buf, &originator));
774 * Generate a new tc_entry in the lsdb and store the sequence number.
777 tc = olsr_add_tc_entry(&originator);
781 * Update the tc entry.
783 tc->msg_hops = msg_hops;
784 tc->msg_seq = msg_seq;
787 tc->err_seq_valid = OLSR_FALSE;
790 * If the sender interface (NB: not originator) of this message
791 * is not in the symmetric 1-hop neighborhood of this node, the
792 * message MUST be discarded.
794 if (check_neighbor_link(from_addr) != SYM_LINK) {
795 OLSR_PRINTF(2, "Received TC from NON SYM neighbor %s\n",
796 olsr_ip_to_string(&buf, from_addr));
800 OLSR_PRINTF(1, "Processing TC from %s, seq 0x%04x\n",
801 olsr_ip_to_string(&buf, &originator), ansn);
804 * Now walk the edge advertisements contained in the packet.
806 limit = (unsigned char *)msg + size;
807 while (curr < limit) {
808 if (olsr_tc_update_edge(tc, ansn, &curr)) {
809 changes_topology = OLSR_TRUE;
814 * Set or change the expiration timer accordingly.
816 olsr_set_timer(&tc->validity_timer, vtime_s * MSEC_PER_SEC,
817 OLSR_TC_VTIME_JITTER, OLSR_TIMER_ONESHOT,
818 &olsr_expire_tc_entry, tc, tc_validity_timer_cookie->ci_id);
821 * Kick the the edge garbage collection timer. In the meantime hopefully
822 * all edges belonging to a multipart neighbor set will arrive.
824 olsr_set_timer(&tc->edge_gc_timer, OLSR_TC_EDGE_GC_TIME,
825 OLSR_TC_EDGE_GC_JITTER, OLSR_TIMER_ONESHOT,
826 &olsr_expire_tc_edge_gc, tc, tc_edge_gc_timer_cookie->ci_id);
829 * Last, flood the message to our other neighbors.
831 olsr_forward_message(msg, from_addr);