]>
git.proxmox.com Git - mirror_frr.git/blob - babeld/route.c
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.
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.
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/>.
15 * This file incorporates work covered by the following copyright and
18 Copyright (c) 2007, 2008 by Juliusz Chroboczek
19 Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
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:
28 The above copyright notice and this permission notice shall be included in
29 all copies or substantial portions of the Software.
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
53 #include "babel_interface.h"
55 #include "neighbour.h"
61 static void consider_route(struct babel_route
*route
);
63 struct babel_route
*routes
= NULL
;
64 int numroutes
= 0, maxroutes
= 0;
65 int kernel_metric
= 0;
66 int allow_duplicates
= -1;
69 find_route(const unsigned char *prefix
, unsigned char plen
,
70 struct neighbour
*neigh
, const unsigned char *nexthop
)
73 for(i
= 0; i
< numroutes
; i
++) {
74 if(routes
[i
].neigh
== neigh
&&
75 memcmp(routes
[i
].nexthop
, nexthop
, 16) == 0 &&
76 source_match(routes
[i
].src
, prefix
, plen
))
83 find_installed_route(const unsigned char *prefix
, unsigned char plen
)
86 for(i
= 0; i
< numroutes
; i
++) {
87 if(routes
[i
].installed
&& source_match(routes
[i
].src
, prefix
, plen
))
94 flush_route(struct babel_route
*route
)
102 assert(i
>= 0 && i
< numroutes
);
104 oldmetric
= route_metric(route
);
106 if(route
->installed
) {
107 uninstall_route(route
);
113 if(i
!= numroutes
- 1)
114 memcpy(routes
+ i
, routes
+ numroutes
- 1, sizeof(struct babel_route
));
116 VALGRIND_MAKE_MEM_UNDEFINED(routes
+ numroutes
, sizeof(struct babel_route
));
122 } else if(maxroutes
> 8 && numroutes
< maxroutes
/ 4) {
123 struct babel_route
*new_routes
;
124 int n
= maxroutes
/ 2;
125 new_routes
= realloc(routes
, n
* sizeof(struct babel_route
));
126 if(new_routes
!= NULL
) {
133 route_lost(src
, oldmetric
);
137 flush_neighbour_routes(struct neighbour
*neigh
)
142 while(i
< numroutes
) {
143 if(routes
[i
].neigh
== neigh
) {
144 flush_route(&routes
[i
]);
152 flush_interface_routes(struct interface
*ifp
, int v4only
)
157 while(i
< numroutes
) {
158 if(routes
[i
].neigh
->ifp
== ifp
&&
159 (!v4only
|| v4mapped(routes
[i
].nexthop
))) {
160 flush_route(&routes
[i
]);
168 metric_to_kernel(int metric
)
170 return metric
< INFINITY
? kernel_metric
: KERNEL_INFINITY
;
174 install_route(struct babel_route
*route
)
181 if(!route_feasible(route
))
182 fprintf(stderr
, "WARNING: installing unfeasible route "
183 "(this shouldn't happen).");
185 rc
= kernel_route(ROUTE_ADD
, route
->src
->prefix
, route
->src
->plen
,
187 route
->neigh
->ifp
->ifindex
,
188 metric_to_kernel(route_metric(route
)), NULL
, 0, 0);
191 zlog_err("kernel_route(ADD): %s", safe_strerror(errno
));
195 route
->installed
= 1;
199 uninstall_route(struct babel_route
*route
)
203 if(!route
->installed
)
206 rc
= kernel_route(ROUTE_FLUSH
, route
->src
->prefix
, route
->src
->plen
,
208 route
->neigh
->ifp
->ifindex
,
209 metric_to_kernel(route_metric(route
)), NULL
, 0, 0);
211 zlog_err("kernel_route(FLUSH): %s", safe_strerror(errno
));
213 route
->installed
= 0;
216 /* This is equivalent to uninstall_route followed with install_route,
217 but without the race condition. The destination of both routes
221 switch_routes(struct babel_route
*old
, struct babel_route
*new)
233 if(!route_feasible(new))
234 fprintf(stderr
, "WARNING: switching to unfeasible route "
235 "(this shouldn't happen).");
237 rc
= kernel_route(ROUTE_MODIFY
, old
->src
->prefix
, old
->src
->plen
,
238 old
->nexthop
, old
->neigh
->ifp
->ifindex
,
239 metric_to_kernel(route_metric(old
)),
240 new->nexthop
, new->neigh
->ifp
->ifindex
,
241 metric_to_kernel(route_metric(new)));
243 zlog_err("kernel_route(MODIFY): %s", safe_strerror(errno
));
252 change_route_metric(struct babel_route
*route
, unsigned newmetric
)
256 if(route_metric(route
) == newmetric
)
259 old
= metric_to_kernel(route_metric(route
));
260 new = metric_to_kernel(newmetric
);
262 if(route
->installed
&& old
!= new) {
264 rc
= kernel_route(ROUTE_MODIFY
, route
->src
->prefix
, route
->src
->plen
,
265 route
->nexthop
, route
->neigh
->ifp
->ifindex
,
267 route
->nexthop
, route
->neigh
->ifp
->ifindex
,
270 zlog_err("kernel_route(MODIFY metric): %s", safe_strerror(errno
));
275 route
->metric
= newmetric
;
279 retract_route(struct babel_route
*route
)
281 route
->refmetric
= INFINITY
;
282 change_route_metric(route
, INFINITY
);
286 route_feasible(struct babel_route
*route
)
288 return update_feasible(route
->src
, route
->seqno
, route
->refmetric
);
292 route_old(struct babel_route
*route
)
294 return route
->time
< babel_now
.tv_sec
- route
->hold_time
* 7 / 8;
298 route_expired(struct babel_route
*route
)
300 return route
->time
< babel_now
.tv_sec
- route
->hold_time
;
304 update_feasible(struct source
*src
,
305 unsigned short seqno
, unsigned short refmetric
)
310 if(src
->time
< babel_now
.tv_sec
- SOURCE_GC_TIME
)
311 /* Never mind what is probably stale data */
314 if(refmetric
>= INFINITY
)
315 /* Retractions are always feasible */
318 return (seqno_compare(seqno
, src
->seqno
) > 0 ||
319 (src
->seqno
== seqno
&& refmetric
< src
->metric
));
322 /* This returns the feasible route with the smallest metric. */
324 find_best_route(const unsigned char *prefix
, unsigned char plen
, int feasible
,
325 struct neighbour
*exclude
)
327 struct babel_route
*route
= NULL
;
330 for(i
= 0; i
< numroutes
; i
++) {
331 if(!source_match(routes
[i
].src
, prefix
, plen
))
333 if(route_expired(&routes
[i
]))
335 if(feasible
&& !route_feasible(&routes
[i
]))
337 if(exclude
&& routes
[i
].neigh
== exclude
)
339 if(route
&& route_metric(route
) <= route_metric(&routes
[i
]))
347 update_route_metric(struct babel_route
*route
)
349 int oldmetric
= route_metric(route
);
351 if(route_expired(route
)) {
352 if(route
->refmetric
< INFINITY
) {
353 route
->seqno
= seqno_plus(route
->src
->seqno
, 1);
354 retract_route(route
);
355 if(oldmetric
< INFINITY
)
356 route_changed(route
, route
->src
, oldmetric
);
359 struct neighbour
*neigh
= route
->neigh
;
360 int add_metric
= input_filter(route
->src
->id
,
361 route
->src
->prefix
, route
->src
->plen
,
363 neigh
->ifp
->ifindex
);
364 int newmetric
= MIN(route
->refmetric
+
366 neighbour_cost(route
->neigh
),
369 if(newmetric
!= oldmetric
) {
370 change_route_metric(route
, newmetric
);
371 route_changed(route
, route
->src
, oldmetric
);
376 /* Called whenever a neighbour's cost changes, to update the metric of
377 all routes through that neighbour. */
379 update_neighbour_metric(struct neighbour
*neigh
, int changed
)
385 while(i
< numroutes
) {
386 if(routes
[i
].neigh
== neigh
)
387 update_route_metric(&routes
[i
]);
394 update_interface_metric(struct interface
*ifp
)
399 while(i
< numroutes
) {
400 if(routes
[i
].neigh
->ifp
== ifp
)
401 update_route_metric(&routes
[i
]);
406 /* This is called whenever we receive an update. */
408 update_route(const unsigned char *router_id
,
409 const unsigned char *prefix
, unsigned char plen
,
410 unsigned short seqno
, unsigned short refmetric
,
411 unsigned short interval
,
412 struct neighbour
*neigh
, const unsigned char *nexthop
)
414 struct babel_route
*route
;
416 int metric
, feasible
;
418 int hold_time
= MAX((4 * interval
) / 100 + interval
/ 50, 15);
420 if(memcmp(router_id
, myid
, 8) == 0)
421 return NULL
; /* I have announced the route */
423 if(martian_prefix(prefix
, plen
)) {
424 fprintf(stderr
, "Rejecting martian route to %s through %s.\n",
425 format_prefix(prefix
, plen
), format_address(router_id
));
429 add_metric
= input_filter(router_id
, prefix
, plen
,
430 neigh
->address
, neigh
->ifp
->ifindex
);
431 if(add_metric
>= INFINITY
)
434 src
= find_source(router_id
, prefix
, plen
, 1, seqno
);
438 feasible
= update_feasible(src
, seqno
, refmetric
);
439 route
= find_route(prefix
, plen
, neigh
, nexthop
);
440 metric
= MIN((int)refmetric
+ neighbour_cost(neigh
) + add_metric
, INFINITY
);
443 struct source
*oldsrc
;
444 unsigned short oldmetric
;
448 oldmetric
= route_metric(route
);
450 /* If a successor switches sources, we must accept his update even
451 if it makes a route unfeasible in order to break any routing loops
452 in a timely manner. If the source remains the same, we ignore
454 if(!feasible
&& route
->installed
) {
455 debugf(BABEL_DEBUG_COMMON
,"Unfeasible update for installed route to %s "
456 "(%s %d %d -> %s %d %d).",
457 format_prefix(src
->prefix
, src
->plen
),
458 format_address(route
->src
->id
),
459 route
->seqno
, route
->refmetric
,
460 format_address(src
->id
), seqno
, refmetric
);
461 if(src
!= route
->src
) {
462 uninstall_route(route
);
468 if(feasible
&& refmetric
< INFINITY
)
469 route
->time
= babel_now
.tv_sec
;
470 route
->seqno
= seqno
;
471 route
->refmetric
= refmetric
;
472 change_route_metric(route
, metric
);
473 route
->hold_time
= hold_time
;
475 route_changed(route
, oldsrc
, oldmetric
);
477 route_lost(oldsrc
, oldmetric
);
480 send_unfeasible_request(neigh
, route
->installed
&& route_old(route
),
483 if(refmetric
>= INFINITY
)
484 /* Somebody's retracting a route we never saw. */
487 send_unfeasible_request(neigh
, 0, seqno
, metric
, src
);
490 if(numroutes
>= maxroutes
) {
491 struct babel_route
*new_routes
;
492 int n
= maxroutes
< 1 ? 8 : 2 * maxroutes
;
493 new_routes
= routes
== NULL
?
494 malloc(n
* sizeof(struct babel_route
)) :
495 realloc(routes
, n
* sizeof(struct babel_route
));
496 if(new_routes
== NULL
)
501 route
= &routes
[numroutes
];
503 route
->refmetric
= refmetric
;
504 route
->seqno
= seqno
;
505 route
->metric
= metric
;
506 route
->neigh
= neigh
;
507 memcpy(route
->nexthop
, nexthop
, 16);
508 route
->time
= babel_now
.tv_sec
;
509 route
->hold_time
= hold_time
;
510 route
->installed
= 0;
512 consider_route(route
);
517 /* We just received an unfeasible update. If it's any good, send
518 a request for a new seqno. */
520 send_unfeasible_request(struct neighbour
*neigh
, int force
,
521 unsigned short seqno
, unsigned short metric
,
524 struct babel_route
*route
= find_installed_route(src
->prefix
, src
->plen
);
526 if(seqno_minus(src
->seqno
, seqno
) > 100) {
527 /* Probably a source that lost its seqno. Let it time-out. */
531 if(force
|| !route
|| route_metric(route
) >= metric
+ 512) {
532 send_unicast_multihop_request(neigh
, src
->prefix
, src
->plen
,
533 src
->metric
>= INFINITY
?
535 seqno_plus(src
->seqno
, 1),
540 /* This takes a feasible route and decides whether to install it. */
542 consider_route(struct babel_route
*route
)
544 struct babel_route
*installed
;
545 struct xroute
*xroute
;
550 if(!route_feasible(route
))
553 xroute
= find_xroute(route
->src
->prefix
, route
->src
->plen
);
554 if(xroute
&& (allow_duplicates
< 0 || xroute
->metric
>= allow_duplicates
))
557 installed
= find_installed_route(route
->src
->prefix
, route
->src
->plen
);
559 if(installed
== NULL
)
562 if(route_metric(route
) >= INFINITY
)
565 if(route_metric(installed
) >= INFINITY
)
568 if(route_metric(installed
) >= route_metric(route
) + 192)
571 /* Avoid switching sources */
572 if(installed
->src
!= route
->src
)
575 if(route_metric(installed
) >= route_metric(route
) + 64)
581 switch_routes(installed
, route
);
582 if(installed
&& route
->installed
)
583 send_triggered_update(route
, installed
->src
, route_metric(installed
));
585 send_update(NULL
, 1, route
->src
->prefix
, route
->src
->plen
);
590 retract_neighbour_routes(struct neighbour
*neigh
)
595 while(i
< numroutes
) {
596 if(routes
[i
].neigh
== neigh
) {
597 if(routes
[i
].refmetric
!= INFINITY
) {
598 unsigned short oldmetric
= route_metric(&routes
[i
]);
599 retract_route(&routes
[i
]);
600 if(oldmetric
!= INFINITY
)
601 route_changed(&routes
[i
], routes
[i
].src
, oldmetric
);
609 send_triggered_update(struct babel_route
*route
, struct source
*oldsrc
,
612 unsigned newmetric
, diff
;
613 /* 1 means send speedily, 2 means resend */
616 if(!route
->installed
)
619 newmetric
= route_metric(route
);
621 newmetric
>= oldmetric
? newmetric
- oldmetric
: oldmetric
- newmetric
;
623 if(route
->src
!= oldsrc
|| (oldmetric
< INFINITY
&& newmetric
>= INFINITY
))
624 /* Switching sources can cause transient routing loops.
625 Retractions can cause blackholes. */
627 else if(newmetric
> oldmetric
&& oldmetric
< 6 * 256 && diff
>= 512)
628 /* Route getting significantly worse */
630 else if(unsatisfied_request(route
->src
->prefix
, route
->src
->plen
,
631 route
->seqno
, route
->src
->id
))
632 /* Make sure that requests are satisfied speedily */
634 else if(oldmetric
>= INFINITY
&& newmetric
< INFINITY
)
637 else if(newmetric
< oldmetric
&& diff
< 1024)
638 /* Route getting better. This may be a transient fluctuation, so
639 don't advertise it to avoid making routes unfeasible later on. */
642 /* Don't fret about trivialities */
648 send_update_resend(NULL
, route
->src
->prefix
, route
->src
->plen
);
650 send_update(NULL
, urgent
, route
->src
->prefix
, route
->src
->plen
);
652 if(oldmetric
< INFINITY
) {
653 if(newmetric
>= oldmetric
+ 512) {
654 send_request_resend(NULL
, route
->src
->prefix
, route
->src
->plen
,
655 route
->src
->metric
>= INFINITY
?
657 seqno_plus(route
->src
->seqno
, 1),
659 } else if(newmetric
>= oldmetric
+ 288) {
660 send_request(NULL
, route
->src
->prefix
, route
->src
->plen
);
665 /* A route has just changed. Decide whether to switch to a different route or
668 route_changed(struct babel_route
*route
,
669 struct source
*oldsrc
, unsigned short oldmetric
)
671 if(route
->installed
) {
672 if(route_metric(route
) > oldmetric
) {
673 struct babel_route
*better_route
;
675 find_best_route(route
->src
->prefix
, route
->src
->plen
, 1, NULL
);
677 route_metric(better_route
) <= route_metric(route
) - 96)
678 consider_route(better_route
);
682 /* We didn't change routes after all. */
683 send_triggered_update(route
, oldsrc
, oldmetric
);
685 /* Reconsider routes even when their metric didn't decrease,
686 they may not have been feasible before. */
687 consider_route(route
);
691 /* We just lost the installed route to a given destination. */
693 route_lost(struct source
*src
, unsigned oldmetric
)
695 struct babel_route
*new_route
;
696 new_route
= find_best_route(src
->prefix
, src
->plen
, 1, NULL
);
698 consider_route(new_route
);
699 } else if(oldmetric
< INFINITY
) {
700 /* Complain loudly. */
701 send_update_resend(NULL
, src
->prefix
, src
->plen
);
702 send_request_resend(NULL
, src
->prefix
, src
->plen
,
703 src
->metric
>= INFINITY
?
704 src
->seqno
: seqno_plus(src
->seqno
, 1),
714 debugf(BABEL_DEBUG_COMMON
,"Expiring old routes.");
717 while(i
< numroutes
) {
718 struct babel_route
*route
= &routes
[i
];
720 if(route
->time
> babel_now
.tv_sec
|| /* clock stepped */
726 update_route_metric(route
);
728 if(route
->installed
&& route
->refmetric
< INFINITY
) {
730 send_unicast_request(route
->neigh
,
731 route
->src
->prefix
, route
->src
->plen
);
738 babel_uninstall_all_routes(void)
740 while(numroutes
> 0) {
741 uninstall_route(&routes
[0]);
742 /* We need to flush the route so network_up won't reinstall it */
743 flush_route(&routes
[0]);
748 babel_route_get_by_source(struct source
*src
)
751 for(i
= 0; i
< numroutes
; i
++) {
752 if(routes
[i
].src
== src
)