]> git.proxmox.com Git - mirror_frr.git/blob - babeld/route.c
Merge branch 'babeld-merge' into master-copy
[mirror_frr.git] / babeld / route.c
1 /*
2 * This file is free software: you may copy, redistribute and/or modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation, either version 2 of the License, or (at your
5 * option) any later version.
6 *
7 * This file is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 * This file incorporates work covered by the following copyright and
16 * permission notice:
17 *
18 Copyright (c) 2007, 2008 by Juliusz Chroboczek
19 Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
20
21 Permission is hereby granted, free of charge, to any person obtaining a copy
22 of this software and associated documentation files (the "Software"), to deal
23 in the Software without restriction, including without limitation the rights
24 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25 copies of the Software, and to permit persons to whom the Software is
26 furnished to do so, subject to the following conditions:
27
28 The above copyright notice and this permission notice shall be included in
29 all copies or substantial portions of the Software.
30
31 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37 THE SOFTWARE.
38 */
39
40 #include <zebra.h>
41 #include "if.h"
42
43 #include "babeld.h"
44 #include "util.h"
45 #include "kernel.h"
46 #include "babel_interface.h"
47 #include "source.h"
48 #include "neighbour.h"
49 #include "route.h"
50 #include "xroute.h"
51 #include "message.h"
52 #include "resend.h"
53
54 static void consider_route(struct babel_route *route);
55
56 struct babel_route **routes = NULL;
57 static int route_slots = 0, max_route_slots = 0;
58 int kernel_metric = 0;
59 int allow_duplicates = -1;
60 int diversity_kind = DIVERSITY_NONE;
61 int diversity_factor = 256; /* in units of 1/256 */
62 int keep_unfeasible = 0;
63
64 /* We maintain a list of "slots", ordered by prefix. Every slot
65 contains a linked list of the routes to this prefix, with the
66 installed route, if any, at the head of the list. */
67
68 static int
69 route_compare(const unsigned char *prefix, unsigned char plen,
70 struct babel_route *route)
71 {
72 int i = memcmp(prefix, route->src->prefix, 16);
73 if(i != 0)
74 return i;
75
76 if(plen < route->src->plen)
77 return -1;
78 else if(plen > route->src->plen)
79 return 1;
80 else
81 return 0;
82 }
83
84 /* Performs binary search, returns -1 in case of failure. In the latter
85 case, new_return is the place where to insert the new element. */
86
87 static int
88 find_route_slot(const unsigned char *prefix, unsigned char plen,
89 int *new_return)
90 {
91 int p, m, g, c;
92
93 if(route_slots < 1) {
94 if(new_return)
95 *new_return = 0;
96 return -1;
97 }
98
99 p = 0; g = route_slots - 1;
100
101 do {
102 m = (p + g) / 2;
103 c = route_compare(prefix, plen, routes[m]);
104 if(c == 0)
105 return m;
106 else if(c < 0)
107 g = m - 1;
108 else
109 p = m + 1;
110 } while(p <= g);
111
112 if(new_return)
113 *new_return = p;
114
115 return -1;
116 }
117
118 struct babel_route *
119 find_route(const unsigned char *prefix, unsigned char plen,
120 struct neighbour *neigh, const unsigned char *nexthop)
121 {
122 struct babel_route *route;
123 int i = find_route_slot(prefix, plen, NULL);
124
125 if(i < 0)
126 return NULL;
127
128 route = routes[i];
129
130 while(route) {
131 if(route->neigh == neigh && memcmp(route->nexthop, nexthop, 16) == 0)
132 return route;
133 route = route->next;
134 }
135
136 return NULL;
137 }
138
139 struct babel_route *
140 find_installed_route(const unsigned char *prefix, unsigned char plen)
141 {
142 int i = find_route_slot(prefix, plen, NULL);
143
144 if(i >= 0 && routes[i]->installed)
145 return routes[i];
146
147 return NULL;
148 }
149
150 /* Returns an overestimate of the number of installed routes. */
151 int
152 installed_routes_estimate(void)
153 {
154 return route_slots;
155 }
156
157 static int
158 resize_route_table(int new_slots)
159 {
160 struct babel_route **new_routes;
161 assert(new_slots >= route_slots);
162
163 if(new_slots == 0) {
164 new_routes = NULL;
165 free(routes);
166 } else {
167 new_routes = realloc(routes, new_slots * sizeof(struct babel_route*));
168 if(new_routes == NULL)
169 return -1;
170 }
171
172 max_route_slots = new_slots;
173 routes = new_routes;
174 return 1;
175 }
176
177 /* Insert a route into the table. If successful, retains the route.
178 On failure, caller must free the route. */
179 static struct babel_route *
180 insert_route(struct babel_route *route)
181 {
182 int i, n;
183
184 assert(!route->installed);
185
186 i = find_route_slot(route->src->prefix, route->src->plen, &n);
187
188 if(i < 0) {
189 if(route_slots >= max_route_slots)
190 resize_route_table(max_route_slots < 1 ? 8 : 2 * max_route_slots);
191 if(route_slots >= max_route_slots)
192 return NULL;
193 route->next = NULL;
194 if(n < route_slots)
195 memmove(routes + n + 1, routes + n,
196 (route_slots - n) * sizeof(struct babel_route*));
197 route_slots++;
198 routes[n] = route;
199 } else {
200 struct babel_route *r;
201 r = routes[i];
202 while(r->next)
203 r = r->next;
204 r->next = route;
205 route->next = NULL;
206 }
207
208 return route;
209 }
210
211 void
212 flush_route(struct babel_route *route)
213 {
214 int i;
215 struct source *src;
216 unsigned oldmetric;
217 int lost = 0;
218
219 oldmetric = route_metric(route);
220 src = route->src;
221
222 if(route->installed) {
223 uninstall_route(route);
224 lost = 1;
225 }
226
227 i = find_route_slot(route->src->prefix, route->src->plen, NULL);
228 assert(i >= 0 && i < route_slots);
229
230 if(route == routes[i]) {
231 routes[i] = route->next;
232 route->next = NULL;
233 free(route);
234
235 if(routes[i] == NULL) {
236 if(i < route_slots - 1)
237 memmove(routes + i, routes + i + 1,
238 (route_slots - i - 1) * sizeof(struct babel_route*));
239 routes[route_slots - 1] = NULL;
240 route_slots--;
241 }
242
243 if(route_slots == 0)
244 resize_route_table(0);
245 else if(max_route_slots > 8 && route_slots < max_route_slots / 4)
246 resize_route_table(max_route_slots / 2);
247 } else {
248 struct babel_route *r = routes[i];
249 while(r->next != route)
250 r = r->next;
251 r->next = route->next;
252 route->next = NULL;
253 free(route);
254 }
255
256 if(lost)
257 route_lost(src, oldmetric);
258
259 release_source(src);
260 }
261
262 void
263 flush_all_routes()
264 {
265 int i;
266
267 /* Start from the end, to avoid shifting the table. */
268 i = route_slots - 1;
269 while(i >= 0) {
270 while(i < route_slots) {
271 /* Uninstall first, to avoid calling route_lost. */
272 if(routes[i]->installed)
273 uninstall_route(routes[0]);
274 flush_route(routes[i]);
275 }
276 i--;
277 }
278
279 check_sources_released();
280 }
281
282 void
283 flush_neighbour_routes(struct neighbour *neigh)
284 {
285 int i;
286
287 i = 0;
288 while(i < route_slots) {
289 struct babel_route *r;
290 r = routes[i];
291 while(r) {
292 if(r->neigh == neigh) {
293 flush_route(r);
294 goto again;
295 }
296 r = r->next;
297 }
298 i++;
299 again:
300 ;
301 }
302 }
303
304 void
305 flush_interface_routes(struct interface *ifp, int v4only)
306 {
307 int i;
308
309 i = 0;
310 while(i < route_slots) {
311 struct babel_route *r;
312 r = routes[i];
313 while(r) {
314 if(r->neigh->ifp == ifp &&
315 (!v4only || v4mapped(r->nexthop))) {
316 flush_route(r);
317 goto again;
318 }
319 r = r->next;
320 }
321 i++;
322 again:
323 ;
324 }
325 }
326
327 /* Iterate a function over all routes. */
328 void
329 for_all_routes(void (*f)(struct babel_route*, void*), void *closure)
330 {
331 int i;
332
333 for(i = 0; i < route_slots; i++) {
334 struct babel_route *r = routes[i];
335 while(r) {
336 (*f)(r, closure);
337 r = r->next;
338 }
339 }
340 }
341
342 void
343 for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure)
344 {
345 int i;
346
347 for(i = 0; i < route_slots; i++) {
348 if(routes[i]->installed)
349 (*f)(routes[i], closure);
350 }
351 }
352
353 static int
354 metric_to_kernel(int metric)
355 {
356 return metric < INFINITY ? kernel_metric : KERNEL_INFINITY;
357 }
358
359 /* This is used to maintain the invariant that the installed route is at
360 the head of the list. */
361 static void
362 move_installed_route(struct babel_route *route, int i)
363 {
364 assert(i >= 0 && i < route_slots);
365 assert(route->installed);
366
367 if(route != routes[i]) {
368 struct babel_route *r = routes[i];
369 while(r->next != route)
370 r = r->next;
371 r->next = route->next;
372 route->next = routes[i];
373 routes[i] = route;
374 }
375 }
376
377 void
378 install_route(struct babel_route *route)
379 {
380 int i, rc;
381
382 if(route->installed)
383 return;
384
385 if(!route_feasible(route))
386 zlog_err("WARNING: installing unfeasible route "
387 "(this shouldn't happen).");
388
389 i = find_route_slot(route->src->prefix, route->src->plen, NULL);
390 assert(i >= 0 && i < route_slots);
391
392 if(routes[i] != route && routes[i]->installed) {
393 fprintf(stderr, "WARNING: attempting to install duplicate route "
394 "(this shouldn't happen).");
395 return;
396 }
397
398 rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen,
399 route->nexthop,
400 route->neigh->ifp->ifindex,
401 metric_to_kernel(route_metric(route)), NULL, 0, 0);
402 if(rc < 0) {
403 int save = errno;
404 zlog_err("kernel_route(ADD): %s", safe_strerror(errno));
405 if(save != EEXIST)
406 return;
407 }
408 route->installed = 1;
409 move_installed_route(route, i);
410
411 }
412
413 void
414 uninstall_route(struct babel_route *route)
415 {
416 int rc;
417
418 if(!route->installed)
419 return;
420
421 rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen,
422 route->nexthop,
423 route->neigh->ifp->ifindex,
424 metric_to_kernel(route_metric(route)), NULL, 0, 0);
425 if(rc < 0)
426 zlog_err("kernel_route(FLUSH): %s", safe_strerror(errno));
427
428 route->installed = 0;
429 }
430
431 /* This is equivalent to uninstall_route followed with install_route,
432 but without the race condition. The destination of both routes
433 must be the same. */
434
435 static void
436 switch_routes(struct babel_route *old, struct babel_route *new)
437 {
438 int rc;
439
440 if(!old) {
441 install_route(new);
442 return;
443 }
444
445 if(!old->installed)
446 return;
447
448 if(!route_feasible(new))
449 zlog_err("WARNING: switching to unfeasible route "
450 "(this shouldn't happen).");
451
452 rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen,
453 old->nexthop, old->neigh->ifp->ifindex,
454 metric_to_kernel(route_metric(old)),
455 new->nexthop, new->neigh->ifp->ifindex,
456 metric_to_kernel(route_metric(new)));
457 if(rc < 0) {
458 zlog_err("kernel_route(MODIFY): %s", safe_strerror(errno));
459 return;
460 }
461
462 old->installed = 0;
463 new->installed = 1;
464 move_installed_route(new, find_route_slot(new->src->prefix, new->src->plen,
465 NULL));
466 }
467
468 static void
469 change_route_metric(struct babel_route *route,
470 unsigned refmetric, unsigned cost, unsigned add)
471 {
472 int old, new;
473 int newmetric = MIN(refmetric + cost + add, INFINITY);
474
475 old = metric_to_kernel(route_metric(route));
476 new = metric_to_kernel(newmetric);
477
478 if(route->installed && old != new) {
479 int rc;
480 rc = kernel_route(ROUTE_MODIFY, route->src->prefix, route->src->plen,
481 route->nexthop, route->neigh->ifp->ifindex,
482 old,
483 route->nexthop, route->neigh->ifp->ifindex,
484 new);
485 if(rc < 0) {
486 zlog_err("kernel_route(MODIFY metric): %s", safe_strerror(errno));
487 return;
488 }
489 }
490
491 route->refmetric = refmetric;
492 route->cost = cost;
493 route->add_metric = add;
494 }
495
496 static void
497 retract_route(struct babel_route *route)
498 {
499 change_route_metric(route, INFINITY, INFINITY, 0);
500 }
501
502 int
503 route_feasible(struct babel_route *route)
504 {
505 return update_feasible(route->src, route->seqno, route->refmetric);
506 }
507
508 int
509 route_old(struct babel_route *route)
510 {
511 return route->time < babel_now.tv_sec - route->hold_time * 7 / 8;
512 }
513
514 int
515 route_expired(struct babel_route *route)
516 {
517 return route->time < babel_now.tv_sec - route->hold_time;
518 }
519
520 static int
521 channels_interfere(int ch1, int ch2)
522 {
523 if(ch1 == BABEL_IF_CHANNEL_NONINTERFERING
524 || ch2 == BABEL_IF_CHANNEL_NONINTERFERING)
525 return 0;
526 if(ch1 == BABEL_IF_CHANNEL_INTERFERING
527 || ch2 == BABEL_IF_CHANNEL_INTERFERING)
528 return 1;
529 return ch1 == ch2;
530 }
531
532 int
533 route_interferes(struct babel_route *route, struct interface *ifp)
534 {
535 struct babel_interface *babel_ifp = NULL;
536 switch(diversity_kind) {
537 case DIVERSITY_NONE:
538 return 1;
539 case DIVERSITY_INTERFACE_1:
540 return route->neigh->ifp == ifp;
541 case DIVERSITY_CHANNEL_1:
542 case DIVERSITY_CHANNEL:
543 if(route->neigh->ifp == ifp)
544 return 1;
545 babel_ifp = babel_get_if_nfo(ifp);
546 if(channels_interfere(babel_ifp->channel,
547 babel_get_if_nfo(route->neigh->ifp)->channel))
548 return 1;
549 if(diversity_kind == DIVERSITY_CHANNEL) {
550 int i;
551 for(i = 0; i < DIVERSITY_HOPS; i++) {
552 if(route->channels[i] == 0)
553 break;
554 if(channels_interfere(babel_ifp->channel, route->channels[i]))
555 return 1;
556 }
557 }
558 return 0;
559 default:
560 fprintf(stderr, "Unknown kind of diversity.\n");
561 return 1;
562 }
563 }
564
565 int
566 update_feasible(struct source *src,
567 unsigned short seqno, unsigned short refmetric)
568 {
569 if(src == NULL)
570 return 1;
571
572 if(src->time < babel_now.tv_sec - SOURCE_GC_TIME)
573 /* Never mind what is probably stale data */
574 return 1;
575
576 if(refmetric >= INFINITY)
577 /* Retractions are always feasible */
578 return 1;
579
580 return (seqno_compare(seqno, src->seqno) > 0 ||
581 (src->seqno == seqno && refmetric < src->metric));
582 }
583
584 /* This returns the feasible route with the smallest metric. */
585 struct babel_route *
586 find_best_route(const unsigned char *prefix, unsigned char plen, int feasible,
587 struct neighbour *exclude)
588 {
589 struct babel_route *route = NULL, *r = NULL;
590 int i = find_route_slot(prefix, plen, NULL);
591
592 if(i < 0)
593 return NULL;
594
595 route = routes[i];
596
597 r = route->next;
598 while(r) {
599 if(!route_expired(r) &&
600 (!feasible || route_feasible(r)) &&
601 (!exclude || r->neigh != exclude) &&
602 (route_metric(r) < route_metric(route)))
603 route = r;
604 r = r->next;
605 }
606 return route;
607 }
608
609 void
610 update_route_metric(struct babel_route *route)
611 {
612 int oldmetric = route_metric(route);
613
614 if(route_expired(route)) {
615 if(route->refmetric < INFINITY) {
616 route->seqno = seqno_plus(route->src->seqno, 1);
617 retract_route(route);
618 if(oldmetric < INFINITY)
619 route_changed(route, route->src, oldmetric);
620 }
621 } else {
622 struct neighbour *neigh = route->neigh;
623 int add_metric = input_filter(route->src->id,
624 route->src->prefix, route->src->plen,
625 neigh->address,
626 neigh->ifp->ifindex);
627 change_route_metric(route, route->refmetric,
628 neighbour_cost(route->neigh), add_metric);
629 if(route_metric(route) != oldmetric)
630 route_changed(route, route->src, oldmetric);
631 }
632 }
633
634 /* Called whenever a neighbour's cost changes, to update the metric of
635 all routes through that neighbour. Calls local_notify_neighbour. */
636 void
637 update_neighbour_metric(struct neighbour *neigh, int changed)
638 {
639
640 if(changed) {
641 int i;
642
643 for(i = 0; i < route_slots; i++) {
644 struct babel_route *r = routes[i];
645 while(r) {
646 if(r->neigh == neigh)
647 update_route_metric(r);
648 r = r->next;
649 }
650 }
651 }
652 }
653
654 void
655 update_interface_metric(struct interface *ifp)
656 {
657 int i;
658
659 for(i = 0; i < route_slots; i++) {
660 struct babel_route *r = routes[i];
661 while(r) {
662 if(r->neigh->ifp == ifp)
663 update_route_metric(r);
664 r = r->next;
665 }
666 }
667 }
668
669 /* This is called whenever we receive an update. */
670 struct babel_route *
671 update_route(const unsigned char *router_id,
672 const unsigned char *prefix, unsigned char plen,
673 unsigned short seqno, unsigned short refmetric,
674 unsigned short interval,
675 struct neighbour *neigh, const unsigned char *nexthop,
676 const unsigned char *channels, int channels_len)
677 {
678 struct babel_route *route;
679 struct source *src;
680 int metric, feasible;
681 int add_metric;
682 int hold_time = MAX((4 * interval) / 100 + interval / 50, 15);
683
684 if(memcmp(router_id, myid, 8) == 0)
685 return NULL;
686
687 if(martian_prefix(prefix, plen)) {
688 zlog_err("Rejecting martian route to %s through %s.",
689 format_prefix(prefix, plen), format_address(router_id));
690 return NULL;
691 }
692
693 add_metric = input_filter(router_id, prefix, plen,
694 neigh->address, neigh->ifp->ifindex);
695 if(add_metric >= INFINITY)
696 return NULL;
697
698 route = find_route(prefix, plen, neigh, nexthop);
699
700 if(route && memcmp(route->src->id, router_id, 8) == 0)
701 /* Avoid scanning the source table. */
702 src = route->src;
703 else
704 src = find_source(router_id, prefix, plen, 1, seqno);
705
706 if(src == NULL)
707 return NULL;
708
709 feasible = update_feasible(src, seqno, refmetric);
710 metric = MIN((int)refmetric + neighbour_cost(neigh) + add_metric, INFINITY);
711
712 if(route) {
713 struct source *oldsrc;
714 unsigned short oldmetric;
715 int lost = 0;
716
717 oldsrc = route->src;
718 oldmetric = route_metric(route);
719
720 /* If a successor switches sources, we must accept his update even
721 if it makes a route unfeasible in order to break any routing loops
722 in a timely manner. If the source remains the same, we ignore
723 the update. */
724 if(!feasible && route->installed) {
725 debugf(BABEL_DEBUG_COMMON,"Unfeasible update for installed route to %s "
726 "(%s %d %d -> %s %d %d).",
727 format_prefix(src->prefix, src->plen),
728 format_address(route->src->id),
729 route->seqno, route->refmetric,
730 format_address(src->id), seqno, refmetric);
731 if(src != route->src) {
732 uninstall_route(route);
733 lost = 1;
734 }
735 }
736
737 route->src = retain_source(src);
738 if((feasible || keep_unfeasible) && refmetric < INFINITY)
739 route->time = babel_now.tv_sec;
740 route->seqno = seqno;
741 change_route_metric(route,
742 refmetric, neighbour_cost(neigh), add_metric);
743 route->hold_time = hold_time;
744
745 route_changed(route, oldsrc, oldmetric);
746 if(lost)
747 route_lost(oldsrc, oldmetric);
748
749 if(!feasible)
750 send_unfeasible_request(neigh, route->installed && route_old(route),
751 seqno, metric, src);
752 release_source(oldsrc);
753 } else {
754 struct babel_route *new_route;
755
756 if(refmetric >= INFINITY)
757 /* Somebody's retracting a route we never saw. */
758 return NULL;
759 if(!feasible) {
760 send_unfeasible_request(neigh, 0, seqno, metric, src);
761 if(!keep_unfeasible)
762 return NULL;
763 }
764
765 route = malloc(sizeof(struct babel_route));
766 if(route == NULL) {
767 perror("malloc(route)");
768 return NULL;
769 }
770
771 route->src = retain_source(src);
772 route->refmetric = refmetric;
773 route->cost = neighbour_cost(neigh);
774 route->add_metric = add_metric;
775 route->seqno = seqno;
776 route->neigh = neigh;
777 memcpy(route->nexthop, nexthop, 16);
778 route->time = babel_now.tv_sec;
779 route->hold_time = hold_time;
780 route->installed = 0;
781 memset(&route->channels, 0, sizeof(route->channels));
782 if(channels_len > 0)
783 memcpy(&route->channels, channels,
784 MIN(channels_len, DIVERSITY_HOPS));
785 route->next = NULL;
786 new_route = insert_route(route);
787 if(new_route == NULL) {
788 fprintf(stderr, "Couldn't insert route.\n");
789 free(route);
790 return NULL;
791 }
792 consider_route(route);
793 }
794 return route;
795 }
796
797 /* We just received an unfeasible update. If it's any good, send
798 a request for a new seqno. */
799 void
800 send_unfeasible_request(struct neighbour *neigh, int force,
801 unsigned short seqno, unsigned short metric,
802 struct source *src)
803 {
804 struct babel_route *route = find_installed_route(src->prefix, src->plen);
805
806 if(seqno_minus(src->seqno, seqno) > 100) {
807 /* Probably a source that lost its seqno. Let it time-out. */
808 return;
809 }
810
811 if(force || !route || route_metric(route) >= metric + 512) {
812 send_unicast_multihop_request(neigh, src->prefix, src->plen,
813 src->metric >= INFINITY ?
814 src->seqno :
815 seqno_plus(src->seqno, 1),
816 src->id, 127);
817 }
818 }
819
820 /* This takes a feasible route and decides whether to install it. */
821 static void
822 consider_route(struct babel_route *route)
823 {
824 struct babel_route *installed;
825 struct xroute *xroute;
826
827 if(route->installed)
828 return;
829
830 if(!route_feasible(route))
831 return;
832
833 xroute = find_xroute(route->src->prefix, route->src->plen);
834 if(xroute && (allow_duplicates < 0 || xroute->metric >= allow_duplicates))
835 return;
836
837 installed = find_installed_route(route->src->prefix, route->src->plen);
838
839 if(installed == NULL)
840 goto install;
841
842 if(route_metric(route) >= INFINITY)
843 return;
844
845 if(route_metric(installed) >= INFINITY)
846 goto install;
847
848 if(route_metric(installed) >= route_metric(route) + 64)
849 goto install;
850
851 return;
852
853 install:
854 switch_routes(installed, route);
855 if(installed && route->installed)
856 send_triggered_update(route, installed->src, route_metric(installed));
857 else
858 send_update(NULL, 1, route->src->prefix, route->src->plen);
859 return;
860 }
861
862 void
863 retract_neighbour_routes(struct neighbour *neigh)
864 {
865 int i;
866
867 for(i = 0; i < route_slots; i++) {
868 struct babel_route *r = routes[i];
869 while(r) {
870 if(r->neigh == neigh) {
871 if(r->refmetric != INFINITY) {
872 unsigned short oldmetric = route_metric(r);
873 retract_route(r);
874 if(oldmetric != INFINITY)
875 route_changed(r, r->src, oldmetric);
876 }
877 }
878 r = r->next;
879 }
880 i++;
881 }
882 }
883
884 void
885 send_triggered_update(struct babel_route *route, struct source *oldsrc,
886 unsigned oldmetric)
887 {
888 unsigned newmetric, diff;
889 /* 1 means send speedily, 2 means resend */
890 int urgent;
891
892 if(!route->installed)
893 return;
894
895 newmetric = route_metric(route);
896 diff =
897 newmetric >= oldmetric ? newmetric - oldmetric : oldmetric - newmetric;
898
899 if(route->src != oldsrc || (oldmetric < INFINITY && newmetric >= INFINITY))
900 /* Switching sources can cause transient routing loops.
901 Retractions can cause blackholes. */
902 urgent = 2;
903 else if(newmetric > oldmetric && oldmetric < 6 * 256 && diff >= 512)
904 /* Route getting significantly worse */
905 urgent = 1;
906 else if(unsatisfied_request(route->src->prefix, route->src->plen,
907 route->seqno, route->src->id))
908 /* Make sure that requests are satisfied speedily */
909 urgent = 1;
910 else if(oldmetric >= INFINITY && newmetric < INFINITY)
911 /* New route */
912 urgent = 0;
913 else if(newmetric < oldmetric && diff < 1024)
914 /* Route getting better. This may be a transient fluctuation, so
915 don't advertise it to avoid making routes unfeasible later on. */
916 return;
917 else if(diff < 384)
918 /* Don't fret about trivialities */
919 return;
920 else
921 urgent = 0;
922
923 if(urgent >= 2)
924 send_update_resend(NULL, route->src->prefix, route->src->plen);
925 else
926 send_update(NULL, urgent, route->src->prefix, route->src->plen);
927
928 if(oldmetric < INFINITY) {
929 if(newmetric >= oldmetric + 512) {
930 send_request_resend(NULL, route->src->prefix, route->src->plen,
931 route->src->metric >= INFINITY ?
932 route->src->seqno :
933 seqno_plus(route->src->seqno, 1),
934 route->src->id);
935 } else if(newmetric >= oldmetric + 288) {
936 send_request(NULL, route->src->prefix, route->src->plen);
937 }
938 }
939 }
940
941 /* A route has just changed. Decide whether to switch to a different route or
942 send an update. */
943 void
944 route_changed(struct babel_route *route,
945 struct source *oldsrc, unsigned short oldmetric)
946 {
947 if(route->installed) {
948 if(route_metric(route) > oldmetric) {
949 struct babel_route *better_route;
950 better_route =
951 find_best_route(route->src->prefix, route->src->plen, 1, NULL);
952 if(better_route &&
953 route_metric(better_route) <= route_metric(route) - 96)
954 consider_route(better_route);
955 }
956
957 if(route->installed)
958 /* We didn't change routes after all. */
959 send_triggered_update(route, oldsrc, oldmetric);
960 } else {
961 /* Reconsider routes even when their metric didn't decrease,
962 they may not have been feasible before. */
963 consider_route(route);
964 }
965 }
966
967 /* We just lost the installed route to a given destination. */
968 void
969 route_lost(struct source *src, unsigned oldmetric)
970 {
971 struct babel_route *new_route;
972 new_route = find_best_route(src->prefix, src->plen, 1, NULL);
973 if(new_route) {
974 consider_route(new_route);
975 } else if(oldmetric < INFINITY) {
976 /* Complain loudly. */
977 send_update_resend(NULL, src->prefix, src->plen);
978 send_request_resend(NULL, src->prefix, src->plen,
979 src->metric >= INFINITY ?
980 src->seqno : seqno_plus(src->seqno, 1),
981 src->id);
982 }
983 }
984
985 /* This is called periodically to flush old routes. It will also send
986 requests for routes that are about to expire. */
987 void
988 expire_routes(void)
989 {
990 struct babel_route *r;
991 int i;
992
993 debugf(BABEL_DEBUG_COMMON,"Expiring old routes.");
994
995 i = 0;
996 while(i < route_slots) {
997 r = routes[i];
998 while(r) {
999 /* Protect against clock being stepped. */
1000 if(r->time > babel_now.tv_sec || route_old(r)) {
1001 flush_route(r);
1002 goto again;
1003 }
1004
1005 update_route_metric(r);
1006
1007 if(r->installed && r->refmetric < INFINITY) {
1008 if(route_old(r))
1009 /* Route about to expire, send a request. */
1010 send_unicast_request(r->neigh,
1011 r->src->prefix, r->src->plen);
1012 }
1013 r = r->next;
1014 }
1015 i++;
1016 again:
1017 ;
1018 }
1019 }