blob: aa181be70bab3d8292abaa301b49cc79d51db365 [file] [log] [blame]
Paul Jakma57345092011-12-25 17:52:09 +01001/*
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 *
18Copyright (c) 2007, 2008 by Juliusz Chroboczek
19Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
20
21Permission is hereby granted, free of charge, to any person obtaining a copy
22of this software and associated documentation files (the "Software"), to deal
23in the Software without restriction, including without limitation the rights
24to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25copies of the Software, and to permit persons to whom the Software is
26furnished to do so, subject to the following conditions:
27
28The above copyright notice and this permission notice shall be included in
29all copies or substantial portions of the Software.
30
31THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37THE SOFTWARE.
38*/
39
Paul Jakma57345092011-12-25 17:52:09 +010040#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
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +040054static void consider_route(struct babel_route *route);
Paul Jakma57345092011-12-25 17:52:09 +010055
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +040056struct babel_route *routes = NULL;
Paul Jakma57345092011-12-25 17:52:09 +010057int numroutes = 0, maxroutes = 0;
58int kernel_metric = 0;
59int allow_duplicates = -1;
60
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +040061struct babel_route *
Paul Jakma57345092011-12-25 17:52:09 +010062find_route(const unsigned char *prefix, unsigned char plen,
63 struct neighbour *neigh, const unsigned char *nexthop)
64{
65 int i;
66 for(i = 0; i < numroutes; i++) {
67 if(routes[i].neigh == neigh &&
68 memcmp(routes[i].nexthop, nexthop, 16) == 0 &&
69 source_match(routes[i].src, prefix, plen))
70 return &routes[i];
71 }
72 return NULL;
73}
74
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +040075struct babel_route *
Paul Jakma57345092011-12-25 17:52:09 +010076find_installed_route(const unsigned char *prefix, unsigned char plen)
77{
78 int i;
79 for(i = 0; i < numroutes; i++) {
80 if(routes[i].installed && source_match(routes[i].src, prefix, plen))
81 return &routes[i];
82 }
83 return NULL;
84}
85
86void
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +040087flush_route(struct babel_route *route)
Paul Jakma57345092011-12-25 17:52:09 +010088{
89 int i;
90 struct source *src;
91 unsigned oldmetric;
92 int lost = 0;
93
94 i = route - routes;
95 assert(i >= 0 && i < numroutes);
96
97 oldmetric = route_metric(route);
98
99 if(route->installed) {
100 uninstall_route(route);
101 lost = 1;
102 }
103
104 src = route->src;
105
106 if(i != numroutes - 1)
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400107 memcpy(routes + i, routes + numroutes - 1, sizeof(struct babel_route));
Paul Jakma57345092011-12-25 17:52:09 +0100108 numroutes--;
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400109 VALGRIND_MAKE_MEM_UNDEFINED(routes + numroutes, sizeof(struct babel_route));
Paul Jakma57345092011-12-25 17:52:09 +0100110
111 if(numroutes == 0) {
112 free(routes);
113 routes = NULL;
114 maxroutes = 0;
115 } else if(maxroutes > 8 && numroutes < maxroutes / 4) {
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400116 struct babel_route *new_routes;
Paul Jakma57345092011-12-25 17:52:09 +0100117 int n = maxroutes / 2;
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400118 new_routes = realloc(routes, n * sizeof(struct babel_route));
Paul Jakma57345092011-12-25 17:52:09 +0100119 if(new_routes != NULL) {
120 routes = new_routes;
121 maxroutes = n;
122 }
123 }
124
125 if(lost)
126 route_lost(src, oldmetric);
127}
128
129void
130flush_neighbour_routes(struct neighbour *neigh)
131{
132 int i;
133
134 i = 0;
135 while(i < numroutes) {
136 if(routes[i].neigh == neigh) {
137 flush_route(&routes[i]);
138 continue;
139 }
140 i++;
141 }
142}
143
144void
145flush_interface_routes(struct interface *ifp, int v4only)
146{
147 int i;
148
149 i = 0;
150 while(i < numroutes) {
151 if(routes[i].neigh->ifp == ifp &&
152 (!v4only || v4mapped(routes[i].nexthop))) {
153 flush_route(&routes[i]);
154 continue;
155 }
156 i++;
157 }
158}
159
160static int
161metric_to_kernel(int metric)
162{
163 return metric < INFINITY ? kernel_metric : KERNEL_INFINITY;
164}
165
166void
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400167install_route(struct babel_route *route)
Paul Jakma57345092011-12-25 17:52:09 +0100168{
169 int rc;
170
171 if(route->installed)
172 return;
173
174 if(!route_feasible(route))
175 fprintf(stderr, "WARNING: installing unfeasible route "
176 "(this shouldn't happen).");
177
178 rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen,
179 route->nexthop,
180 route->neigh->ifp->ifindex,
181 metric_to_kernel(route_metric(route)), NULL, 0, 0);
182 if(rc < 0) {
183 int save = errno;
184 zlog_err("kernel_route(ADD): %s", safe_strerror(errno));
185 if(save != EEXIST)
186 return;
187 }
188 route->installed = 1;
189}
190
191void
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400192uninstall_route(struct babel_route *route)
Paul Jakma57345092011-12-25 17:52:09 +0100193{
194 int rc;
195
196 if(!route->installed)
197 return;
198
199 rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen,
200 route->nexthop,
201 route->neigh->ifp->ifindex,
202 metric_to_kernel(route_metric(route)), NULL, 0, 0);
203 if(rc < 0)
204 zlog_err("kernel_route(FLUSH): %s", safe_strerror(errno));
205
206 route->installed = 0;
207}
208
209/* This is equivalent to uninstall_route followed with install_route,
210 but without the race condition. The destination of both routes
211 must be the same. */
212
213static void
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400214switch_routes(struct babel_route *old, struct babel_route *new)
Paul Jakma57345092011-12-25 17:52:09 +0100215{
216 int rc;
217
218 if(!old) {
219 install_route(new);
220 return;
221 }
222
223 if(!old->installed)
224 return;
225
226 if(!route_feasible(new))
227 fprintf(stderr, "WARNING: switching to unfeasible route "
228 "(this shouldn't happen).");
229
230 rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen,
231 old->nexthop, old->neigh->ifp->ifindex,
232 metric_to_kernel(route_metric(old)),
233 new->nexthop, new->neigh->ifp->ifindex,
234 metric_to_kernel(route_metric(new)));
235 if(rc < 0) {
236 zlog_err("kernel_route(MODIFY): %s", safe_strerror(errno));
237 return;
238 }
239
240 old->installed = 0;
241 new->installed = 1;
242}
243
244static void
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400245change_route_metric(struct babel_route *route, unsigned newmetric)
Paul Jakma57345092011-12-25 17:52:09 +0100246{
247 int old, new;
248
249 if(route_metric(route) == newmetric)
250 return;
251
252 old = metric_to_kernel(route_metric(route));
253 new = metric_to_kernel(newmetric);
254
255 if(route->installed && old != new) {
256 int rc;
257 rc = kernel_route(ROUTE_MODIFY, route->src->prefix, route->src->plen,
258 route->nexthop, route->neigh->ifp->ifindex,
259 old,
260 route->nexthop, route->neigh->ifp->ifindex,
261 new);
262 if(rc < 0) {
263 zlog_err("kernel_route(MODIFY metric): %s", safe_strerror(errno));
264 return;
265 }
266 }
267
268 route->metric = newmetric;
269}
270
271static void
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400272retract_route(struct babel_route *route)
Paul Jakma57345092011-12-25 17:52:09 +0100273{
274 route->refmetric = INFINITY;
275 change_route_metric(route, INFINITY);
276}
277
278int
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400279route_feasible(struct babel_route *route)
Paul Jakma57345092011-12-25 17:52:09 +0100280{
281 return update_feasible(route->src, route->seqno, route->refmetric);
282}
283
284int
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400285route_old(struct babel_route *route)
Paul Jakma57345092011-12-25 17:52:09 +0100286{
287 return route->time < babel_now.tv_sec - route->hold_time * 7 / 8;
288}
289
290int
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400291route_expired(struct babel_route *route)
Paul Jakma57345092011-12-25 17:52:09 +0100292{
293 return route->time < babel_now.tv_sec - route->hold_time;
294}
295
296int
297update_feasible(struct source *src,
298 unsigned short seqno, unsigned short refmetric)
299{
300 if(src == NULL)
301 return 1;
302
303 if(src->time < babel_now.tv_sec - SOURCE_GC_TIME)
304 /* Never mind what is probably stale data */
305 return 1;
306
307 if(refmetric >= INFINITY)
308 /* Retractions are always feasible */
309 return 1;
310
311 return (seqno_compare(seqno, src->seqno) > 0 ||
312 (src->seqno == seqno && refmetric < src->metric));
313}
314
315/* This returns the feasible route with the smallest metric. */
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400316struct babel_route *
Paul Jakma57345092011-12-25 17:52:09 +0100317find_best_route(const unsigned char *prefix, unsigned char plen, int feasible,
318 struct neighbour *exclude)
319{
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400320 struct babel_route *route = NULL;
Paul Jakma57345092011-12-25 17:52:09 +0100321 int i;
322
323 for(i = 0; i < numroutes; i++) {
324 if(!source_match(routes[i].src, prefix, plen))
325 continue;
326 if(route_expired(&routes[i]))
327 continue;
328 if(feasible && !route_feasible(&routes[i]))
329 continue;
330 if(exclude && routes[i].neigh == exclude)
331 continue;
332 if(route && route_metric(route) <= route_metric(&routes[i]))
333 continue;
334 route = &routes[i];
335 }
336 return route;
337}
338
339void
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400340update_route_metric(struct babel_route *route)
Paul Jakma57345092011-12-25 17:52:09 +0100341{
342 int oldmetric = route_metric(route);
343
344 if(route_expired(route)) {
345 if(route->refmetric < INFINITY) {
346 route->seqno = seqno_plus(route->src->seqno, 1);
347 retract_route(route);
348 if(oldmetric < INFINITY)
349 route_changed(route, route->src, oldmetric);
350 }
351 } else {
352 struct neighbour *neigh = route->neigh;
353 int add_metric = input_filter(route->src->id,
354 route->src->prefix, route->src->plen,
355 neigh->address,
356 neigh->ifp->ifindex);
357 int newmetric = MIN(route->refmetric +
358 add_metric +
359 neighbour_cost(route->neigh),
360 INFINITY);
361
362 if(newmetric != oldmetric) {
363 change_route_metric(route, newmetric);
364 route_changed(route, route->src, oldmetric);
365 }
366 }
367}
368
369/* Called whenever a neighbour's cost changes, to update the metric of
370 all routes through that neighbour. */
371void
372update_neighbour_metric(struct neighbour *neigh, int changed)
373{
374 if(changed) {
375 int i;
376
377 i = 0;
378 while(i < numroutes) {
379 if(routes[i].neigh == neigh)
380 update_route_metric(&routes[i]);
381 i++;
382 }
383 }
384}
385
386void
387update_interface_metric(struct interface *ifp)
388{
389 int i;
390
391 i = 0;
392 while(i < numroutes) {
393 if(routes[i].neigh->ifp == ifp)
394 update_route_metric(&routes[i]);
395 i++;
396 }
397}
398
399/* This is called whenever we receive an update. */
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400400struct babel_route *
Paul Jakma57345092011-12-25 17:52:09 +0100401update_route(const unsigned char *router_id,
402 const unsigned char *prefix, unsigned char plen,
403 unsigned short seqno, unsigned short refmetric,
404 unsigned short interval,
405 struct neighbour *neigh, const unsigned char *nexthop)
406{
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400407 struct babel_route *route;
Paul Jakma57345092011-12-25 17:52:09 +0100408 struct source *src;
409 int metric, feasible;
410 int add_metric;
411 int hold_time = MAX((4 * interval) / 100 + interval / 50, 15);
412
413 if(memcmp(router_id, myid, 8) == 0)
414 return NULL; /* I have announced the route */
415
416 if(martian_prefix(prefix, plen)) {
417 fprintf(stderr, "Rejecting martian route to %s through %s.\n",
418 format_prefix(prefix, plen), format_address(router_id));
419 return NULL;
420 }
421
422 add_metric = input_filter(router_id, prefix, plen,
423 neigh->address, neigh->ifp->ifindex);
424 if(add_metric >= INFINITY)
425 return NULL;
426
427 src = find_source(router_id, prefix, plen, 1, seqno);
428 if(src == NULL)
429 return NULL;
430
431 feasible = update_feasible(src, seqno, refmetric);
432 route = find_route(prefix, plen, neigh, nexthop);
433 metric = MIN((int)refmetric + neighbour_cost(neigh) + add_metric, INFINITY);
434
435 if(route) {
436 struct source *oldsrc;
437 unsigned short oldmetric;
438 int lost = 0;
439
440 oldsrc = route->src;
441 oldmetric = route_metric(route);
442
443 /* If a successor switches sources, we must accept his update even
444 if it makes a route unfeasible in order to break any routing loops
445 in a timely manner. If the source remains the same, we ignore
446 the update. */
447 if(!feasible && route->installed) {
448 debugf(BABEL_DEBUG_COMMON,"Unfeasible update for installed route to %s "
449 "(%s %d %d -> %s %d %d).",
450 format_prefix(src->prefix, src->plen),
451 format_address(route->src->id),
452 route->seqno, route->refmetric,
453 format_address(src->id), seqno, refmetric);
454 if(src != route->src) {
455 uninstall_route(route);
456 lost = 1;
457 }
458 }
459
460 route->src = src;
461 if(feasible && refmetric < INFINITY)
462 route->time = babel_now.tv_sec;
463 route->seqno = seqno;
464 route->refmetric = refmetric;
465 change_route_metric(route, metric);
466 route->hold_time = hold_time;
467
468 route_changed(route, oldsrc, oldmetric);
469 if(lost)
470 route_lost(oldsrc, oldmetric);
471
472 if(!feasible)
473 send_unfeasible_request(neigh, route->installed && route_old(route),
474 seqno, metric, src);
475 } else {
476 if(refmetric >= INFINITY)
477 /* Somebody's retracting a route we never saw. */
478 return NULL;
479 if(!feasible) {
480 send_unfeasible_request(neigh, 0, seqno, metric, src);
481 return NULL;
482 }
483 if(numroutes >= maxroutes) {
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400484 struct babel_route *new_routes;
Paul Jakma57345092011-12-25 17:52:09 +0100485 int n = maxroutes < 1 ? 8 : 2 * maxroutes;
486 new_routes = routes == NULL ?
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400487 malloc(n * sizeof(struct babel_route)) :
488 realloc(routes, n * sizeof(struct babel_route));
Paul Jakma57345092011-12-25 17:52:09 +0100489 if(new_routes == NULL)
490 return NULL;
491 maxroutes = n;
492 routes = new_routes;
493 }
494 route = &routes[numroutes];
495 route->src = src;
496 route->refmetric = refmetric;
497 route->seqno = seqno;
498 route->metric = metric;
499 route->neigh = neigh;
500 memcpy(route->nexthop, nexthop, 16);
501 route->time = babel_now.tv_sec;
502 route->hold_time = hold_time;
503 route->installed = 0;
504 numroutes++;
505 consider_route(route);
506 }
507 return route;
508}
509
510/* We just received an unfeasible update. If it's any good, send
511 a request for a new seqno. */
512void
513send_unfeasible_request(struct neighbour *neigh, int force,
514 unsigned short seqno, unsigned short metric,
515 struct source *src)
516{
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400517 struct babel_route *route = find_installed_route(src->prefix, src->plen);
Paul Jakma57345092011-12-25 17:52:09 +0100518
519 if(seqno_minus(src->seqno, seqno) > 100) {
520 /* Probably a source that lost its seqno. Let it time-out. */
521 return;
522 }
523
524 if(force || !route || route_metric(route) >= metric + 512) {
525 send_unicast_multihop_request(neigh, src->prefix, src->plen,
526 src->metric >= INFINITY ?
527 src->seqno :
528 seqno_plus(src->seqno, 1),
529 src->id, 127);
530 }
531}
532
533/* This takes a feasible route and decides whether to install it. */
534static void
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400535consider_route(struct babel_route *route)
Paul Jakma57345092011-12-25 17:52:09 +0100536{
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400537 struct babel_route *installed;
Paul Jakma57345092011-12-25 17:52:09 +0100538 struct xroute *xroute;
539
540 if(route->installed)
541 return;
542
543 if(!route_feasible(route))
544 return;
545
546 xroute = find_xroute(route->src->prefix, route->src->plen);
547 if(xroute && (allow_duplicates < 0 || xroute->metric >= allow_duplicates))
548 return;
549
550 installed = find_installed_route(route->src->prefix, route->src->plen);
551
552 if(installed == NULL)
553 goto install;
554
555 if(route_metric(route) >= INFINITY)
556 return;
557
558 if(route_metric(installed) >= INFINITY)
559 goto install;
560
561 if(route_metric(installed) >= route_metric(route) + 192)
562 goto install;
563
564 /* Avoid switching sources */
565 if(installed->src != route->src)
566 return;
567
568 if(route_metric(installed) >= route_metric(route) + 64)
569 goto install;
570
571 return;
572
573 install:
574 switch_routes(installed, route);
575 if(installed && route->installed)
576 send_triggered_update(route, installed->src, route_metric(installed));
577 else
578 send_update(NULL, 1, route->src->prefix, route->src->plen);
579 return;
580}
581
582void
583retract_neighbour_routes(struct neighbour *neigh)
584{
585 int i;
586
587 i = 0;
588 while(i < numroutes) {
589 if(routes[i].neigh == neigh) {
590 if(routes[i].refmetric != INFINITY) {
591 unsigned short oldmetric = route_metric(&routes[i]);
592 retract_route(&routes[i]);
593 if(oldmetric != INFINITY)
594 route_changed(&routes[i], routes[i].src, oldmetric);
595 }
596 }
597 i++;
598 }
599}
600
601void
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400602send_triggered_update(struct babel_route *route, struct source *oldsrc,
Paul Jakma57345092011-12-25 17:52:09 +0100603 unsigned oldmetric)
604{
605 unsigned newmetric, diff;
606 /* 1 means send speedily, 2 means resend */
607 int urgent;
608
609 if(!route->installed)
610 return;
611
612 newmetric = route_metric(route);
613 diff =
614 newmetric >= oldmetric ? newmetric - oldmetric : oldmetric - newmetric;
615
616 if(route->src != oldsrc || (oldmetric < INFINITY && newmetric >= INFINITY))
617 /* Switching sources can cause transient routing loops.
618 Retractions can cause blackholes. */
619 urgent = 2;
620 else if(newmetric > oldmetric && oldmetric < 6 * 256 && diff >= 512)
621 /* Route getting significantly worse */
622 urgent = 1;
623 else if(unsatisfied_request(route->src->prefix, route->src->plen,
624 route->seqno, route->src->id))
625 /* Make sure that requests are satisfied speedily */
626 urgent = 1;
627 else if(oldmetric >= INFINITY && newmetric < INFINITY)
628 /* New route */
629 urgent = 0;
630 else if(newmetric < oldmetric && diff < 1024)
631 /* Route getting better. This may be a transient fluctuation, so
632 don't advertise it to avoid making routes unfeasible later on. */
633 return;
634 else if(diff < 384)
635 /* Don't fret about trivialities */
636 return;
637 else
638 urgent = 0;
639
640 if(urgent >= 2)
641 send_update_resend(NULL, route->src->prefix, route->src->plen);
642 else
643 send_update(NULL, urgent, route->src->prefix, route->src->plen);
644
645 if(oldmetric < INFINITY) {
646 if(newmetric >= oldmetric + 512) {
647 send_request_resend(NULL, route->src->prefix, route->src->plen,
648 route->src->metric >= INFINITY ?
649 route->src->seqno :
650 seqno_plus(route->src->seqno, 1),
651 route->src->id);
652 } else if(newmetric >= oldmetric + 288) {
653 send_request(NULL, route->src->prefix, route->src->plen);
654 }
655 }
656}
657
658/* A route has just changed. Decide whether to switch to a different route or
659 send an update. */
660void
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400661route_changed(struct babel_route *route,
Paul Jakma57345092011-12-25 17:52:09 +0100662 struct source *oldsrc, unsigned short oldmetric)
663{
664 if(route->installed) {
665 if(route_metric(route) > oldmetric) {
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400666 struct babel_route *better_route;
Paul Jakma57345092011-12-25 17:52:09 +0100667 better_route =
668 find_best_route(route->src->prefix, route->src->plen, 1, NULL);
669 if(better_route &&
670 route_metric(better_route) <= route_metric(route) - 96)
671 consider_route(better_route);
672 }
673
674 if(route->installed)
675 /* We didn't change routes after all. */
676 send_triggered_update(route, oldsrc, oldmetric);
677 } else {
678 /* Reconsider routes even when their metric didn't decrease,
679 they may not have been feasible before. */
680 consider_route(route);
681 }
682}
683
684/* We just lost the installed route to a given destination. */
685void
686route_lost(struct source *src, unsigned oldmetric)
687{
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400688 struct babel_route *new_route;
Paul Jakma57345092011-12-25 17:52:09 +0100689 new_route = find_best_route(src->prefix, src->plen, 1, NULL);
690 if(new_route) {
691 consider_route(new_route);
692 } else if(oldmetric < INFINITY) {
693 /* Complain loudly. */
694 send_update_resend(NULL, src->prefix, src->plen);
695 send_request_resend(NULL, src->prefix, src->plen,
696 src->metric >= INFINITY ?
697 src->seqno : seqno_plus(src->seqno, 1),
698 src->id);
699 }
700}
701
702void
703expire_routes(void)
704{
705 int i;
706
707 debugf(BABEL_DEBUG_COMMON,"Expiring old routes.");
708
709 i = 0;
710 while(i < numroutes) {
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400711 struct babel_route *route = &routes[i];
Paul Jakma57345092011-12-25 17:52:09 +0100712
713 if(route->time > babel_now.tv_sec || /* clock stepped */
714 route_old(route)) {
715 flush_route(route);
716 continue;
717 }
718
719 update_route_metric(route);
720
721 if(route->installed && route->refmetric < INFINITY) {
722 if(route_old(route))
723 send_unicast_request(route->neigh,
724 route->src->prefix, route->src->plen);
725 }
726 i++;
727 }
728}
729
730void
731babel_uninstall_all_routes(void)
732{
733 while(numroutes > 0) {
734 uninstall_route(&routes[0]);
735 /* We need to flush the route so network_up won't reinstall it */
736 flush_route(&routes[0]);
737 }
738}
739
Denis Ovsienkoef4de4d2012-01-08 15:29:19 +0400740struct babel_route *
Paul Jakma57345092011-12-25 17:52:09 +0100741babel_route_get_by_source(struct source *src)
742{
743 int i;
744 for(i = 0; i < numroutes; i++) {
745 if(routes[i].src == src)
746 return &routes[i];
747 }
748 return NULL;
749}