2 * BIRD -- UNIX Kernel Synchronization
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
10 * DOC: Kernel synchronization
12 * This system dependent module implements the Kernel and Device protocol,
13 * that is synchronization of interface lists and routing tables with the
16 * The whole kernel synchronization is a bit messy and touches some internals
17 * of the routing table engine, because routing table maintenance is a typical
18 * example of the proverbial compatibility between different Unices and we want
19 * to keep the overhead of our KRT business as low as possible and avoid maintaining
20 * a local routing table copy.
22 * The kernel syncer can work in three different modes (according to system config header):
23 * Either with a single routing table and single KRT protocol [traditional UNIX]
24 * or with many routing tables and separate KRT protocols for all of them
25 * or with many routing tables, but every scan including all tables, so we start
26 * separate KRT protocols which cooperate with each other [Linux 2.2].
27 * In this case, we keep only a single scan timer.
29 * We use FIB node flags in the routing table to keep track of route
30 * synchronization status. We also attach temporary &rte's to the routing table,
31 * but it cannot do any harm to the rest of BIRD since table synchronization is
34 * When starting up, we cheat by looking if there is another
35 * KRT instance to be initialized later and performing table scan
36 * only once for all the instances.
40 * If you are brave enough, continue now. You cannot say you haven't been warned.
45 #include "nest/bird.h"
46 #include "nest/iface.h"
47 #include "nest/route.h"
48 #include "nest/protocol.h"
49 #include "lib/timer.h"
50 #include "conf/conf.h"
51 #include "lib/string.h"
56 static int krt_uptodate(rte
*k
, rte
*e
);
67 krt_pool
= rp_new(&root_pool
, "Kernel Syncer");
75 struct proto_config
*cf_kif
;
77 static struct kif_proto
*kif_proto
;
78 static timer
*kif_scan_timer
;
79 static bird_clock_t kif_last_shot
;
82 kif_preconfig(struct protocol
*P UNUSED
, struct config
*c UNUSED
)
90 struct kif_proto
*p
= t
->data
;
92 KRT_TRACE(p
, D_EVENTS
, "Scanning interfaces");
100 if (kif_proto
&& kif_last_shot
+ 2 < now
)
102 kif_scan(kif_scan_timer
);
103 tm_start(kif_scan_timer
, ((struct kif_config
*) kif_proto
->p
.cf
)->scan_time
);
107 static struct proto
*
108 kif_init(struct proto_config
*c
)
110 struct kif_proto
*p
= proto_new(c
, sizeof(struct kif_proto
));
115 kif_start(struct proto
*P
)
117 struct kif_proto
*p
= (struct kif_proto
*) P
;
122 /* Start periodic interface scanning */
123 kif_scan_timer
= tm_new(P
->pool
);
124 kif_scan_timer
->hook
= kif_scan
;
125 kif_scan_timer
->data
= p
;
126 kif_scan_timer
->recurrent
= KIF_CF
->scan_time
;
127 kif_scan(kif_scan_timer
);
128 tm_start(kif_scan_timer
, KIF_CF
->scan_time
);
134 kif_shutdown(struct proto
*P
)
136 struct kif_proto
*p
= (struct kif_proto
*) P
;
138 tm_stop(kif_scan_timer
);
142 if_start_update(); /* Remove all interfaces */
145 * FIXME: Is it really a good idea? It causes routes to be flushed,
146 * but at the same time it avoids sending of these deletions to the kernel,
147 * because krt thinks the kernel itself has already removed the route
148 * when downing the interface. Sad.
155 kif_reconfigure(struct proto
*p
, struct proto_config
*new)
157 struct kif_config
*o
= (struct kif_config
*) p
->cf
;
158 struct kif_config
*n
= (struct kif_config
*) new;
160 if (!kif_params_same(&o
->iface
, &n
->iface
))
162 if (o
->scan_time
!= n
->scan_time
)
164 tm_stop(kif_scan_timer
);
165 kif_scan_timer
->recurrent
= n
->scan_time
;
166 kif_scan(kif_scan_timer
);
167 tm_start(kif_scan_timer
, n
->scan_time
);
172 struct protocol proto_unix_iface
= {
174 template: "device%d",
175 preconfig
: kif_preconfig
,
178 shutdown
: kif_shutdown
,
179 reconfigure
: kif_reconfigure
,
187 krt_trace_in(struct krt_proto
*p
, rte
*e
, char *msg
)
189 if (p
->p
.debug
& D_PACKETS
)
190 log(L_TRACE
"%s: %I/%d: %s", p
->p
.name
, e
->net
->n
.prefix
, e
->net
->n
.pxlen
, msg
);
194 krt_trace_in_rl(struct rate_limit
*rl
, struct krt_proto
*p
, rte
*e
, char *msg
)
196 if (p
->p
.debug
& D_PACKETS
)
197 log_rl(rl
, L_TRACE
"%s: %I/%d: %s", p
->p
.name
, e
->net
->n
.prefix
, e
->net
->n
.pxlen
, msg
);
204 #ifdef KRT_ALLOW_LEARN
206 static struct rate_limit rl_alien_seen
, rl_alien_updated
, rl_alien_created
, rl_alien_ignored
;
209 krt_same_key(rte
*a
, rte
*b
)
211 return a
->u
.krt
.proto
== b
->u
.krt
.proto
&&
212 a
->u
.krt
.metric
== b
->u
.krt
.metric
&&
213 a
->u
.krt
.type
== b
->u
.krt
.type
;
217 krt_learn_announce_update(struct krt_proto
*p
, rte
*e
)
220 rta
*aa
= rta_clone(e
->attrs
);
221 rte
*ee
= rte_get_temp(aa
);
222 net
*nn
= net_get(p
->p
.table
, n
->n
.prefix
, n
->n
.pxlen
);
225 ee
->pref
= p
->p
.preference
;
226 ee
->u
.krt
= e
->u
.krt
;
227 rte_update(p
->p
.table
, nn
, &p
->p
, ee
);
231 krt_learn_announce_delete(struct krt_proto
*p
, net
*n
)
233 n
= net_find(p
->p
.table
, n
->n
.prefix
, n
->n
.pxlen
);
235 rte_update(p
->p
.table
, n
, &p
->p
, NULL
);
239 krt_learn_scan(struct krt_proto
*p
, rte
*e
)
242 net
*n
= net_get(&p
->krt_table
, n0
->n
.prefix
, n0
->n
.pxlen
);
245 e
->attrs
->source
= RTS_INHERIT
;
247 for(mm
=&n
->routes
; m
= *mm
; mm
=&m
->next
)
248 if (krt_same_key(m
, e
))
252 if (krt_uptodate(m
, e
))
254 krt_trace_in_rl(&rl_alien_seen
, p
, e
, "[alien] seen");
260 krt_trace_in_rl(&rl_alien_updated
, p
, e
, "[alien] updated");
267 krt_trace_in_rl(&rl_alien_created
, p
, e
, "[alien] created");
270 e
->attrs
= rta_lookup(e
->attrs
);
278 krt_learn_prune(struct krt_proto
*p
)
280 struct fib
*fib
= &p
->krt_table
.fib
;
281 struct fib_iterator fit
;
283 KRT_TRACE(p
, D_EVENTS
, "Pruning inherited routes");
285 FIB_ITERATE_INIT(&fit
, fib
);
287 FIB_ITERATE_START(fib
, &fit
, f
)
290 rte
*e
, **ee
, *best
, **pbest
, *old_best
;
292 old_best
= n
->routes
;
304 if (!best
|| best
->u
.krt
.metric
> e
->u
.krt
.metric
)
314 DBG("%I/%d: deleting\n", n
->n
.prefix
, n
->n
.pxlen
);
317 krt_learn_announce_delete(p
, n
);
318 n
->n
.flags
&= ~KRF_INSTALLED
;
320 FIB_ITERATE_PUT(&fit
, f
);
325 best
->next
= n
->routes
;
327 if (best
!= old_best
|| !(n
->n
.flags
& KRF_INSTALLED
))
329 DBG("%I/%d: announcing (metric=%d)\n", n
->n
.prefix
, n
->n
.pxlen
, best
->u
.krt
.metric
);
330 krt_learn_announce_update(p
, best
);
331 n
->n
.flags
|= KRF_INSTALLED
;
334 DBG("%I/%d: uptodate (metric=%d)\n", n
->n
.prefix
, n
->n
.pxlen
, best
->u
.krt
.metric
);
340 krt_learn_async(struct krt_proto
*p
, rte
*e
, int new)
343 net
*n
= net_get(&p
->krt_table
, n0
->n
.prefix
, n0
->n
.pxlen
);
344 rte
*g
, **gg
, *best
, **bestp
, *old_best
;
346 e
->attrs
->source
= RTS_INHERIT
;
348 old_best
= n
->routes
;
349 for(gg
=&n
->routes
; g
= *gg
; gg
= &g
->next
)
350 if (krt_same_key(g
, e
))
356 if (krt_uptodate(g
, e
))
358 krt_trace_in(p
, e
, "[alien async] same");
362 krt_trace_in(p
, e
, "[alien async] updated");
367 krt_trace_in(p
, e
, "[alien async] created");
368 e
->attrs
= rta_lookup(e
->attrs
);
374 krt_trace_in(p
, e
, "[alien async] delete failed");
380 krt_trace_in(p
, e
, "[alien async] removed");
387 for(gg
=&n
->routes
; g
=*gg
; gg
=&g
->next
)
388 if (best
->u
.krt
.metric
> g
->u
.krt
.metric
)
396 best
->next
= n
->routes
;
399 if (best
!= old_best
)
401 DBG("krt_learn_async: distributing change\n");
404 krt_learn_announce_update(p
, best
);
405 n
->n
.flags
|= KRF_INSTALLED
;
410 krt_learn_announce_delete(p
, n
);
411 n
->n
.flags
&= ~KRF_INSTALLED
;
417 krt_learn_init(struct krt_proto
*p
)
420 rt_setup(p
->p
.pool
, &p
->krt_table
, "Inherited", NULL
);
424 krt_dump(struct proto
*P
)
426 struct krt_proto
*p
= (struct krt_proto
*) P
;
430 debug("KRT: Table of inheritable routes\n");
431 rt_dump(&p
->krt_table
);
435 krt_dump_attrs(rte
*e
)
437 debug(" [m=%d,p=%d,t=%d]", e
->u
.krt
.metric
, e
->u
.krt
.proto
, e
->u
.krt
.type
);
446 #ifdef CONFIG_ALL_TABLES_AT_ONCE
447 static timer
*krt_scan_timer
;
448 static int krt_instance_count
;
449 static list krt_instance_list
;
453 krt_flush_routes(struct krt_proto
*p
)
455 struct rtable
*t
= p
->p
.table
;
457 KRT_TRACE(p
, D_EVENTS
, "Flushing kernel routes");
465 if ((n
->n
.flags
& KRF_INSTALLED
) &&
466 a
->source
!= RTS_DEVICE
&& a
->source
!= RTS_INHERIT
)
468 krt_set_notify(p
, e
->net
, NULL
, e
);
469 n
->n
.flags
&= ~KRF_INSTALLED
;
477 krt_uptodate(rte
*k
, rte
*e
)
479 rta
*ka
= k
->attrs
, *ea
= e
->attrs
;
481 if (ka
->dest
!= ea
->dest
)
486 return ipa_equal(ka
->gw
, ea
->gw
);
488 return !strcmp(ka
->iface
->name
, ea
->iface
->name
);
495 * This gets called back when the low-level scanning code discovers a route.
496 * We expect that the route is a temporary rte and its attributes are uncached.
500 krt_got_route(struct krt_proto
*p
, rte
*e
)
505 #ifdef KRT_ALLOW_LEARN
506 int src
= e
->u
.krt
.src
;
509 #ifdef CONFIG_AUTO_ROUTES
510 if (e
->attrs
->dest
== RTD_DEVICE
)
512 /* It's a device route. Probably a kernel-generated one. */
513 verdict
= KRF_IGNORE
;
518 #ifdef KRT_ALLOW_LEARN
519 if (src
== KRT_SRC_ALIEN
)
522 krt_learn_scan(p
, e
);
525 krt_trace_in_rl(&rl_alien_ignored
, p
, e
, "alien route, ignored");
532 if (net
->n
.flags
& KRF_VERDICT_MASK
)
534 /* Route to this destination was already seen. Strange, but it happens... */
535 krt_trace_in(p
, e
, "already seen");
540 if (net
->n
.flags
& KRF_INSTALLED
)
544 if (krt_uptodate(e
, old
))
547 verdict
= KRF_UPDATE
;
550 verdict
= KRF_DELETE
;
553 krt_trace_in(p
, e
, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict
]);
554 net
->n
.flags
= (net
->n
.flags
& ~KRF_VERDICT_MASK
) | verdict
;
555 if (verdict
== KRF_UPDATE
|| verdict
== KRF_DELETE
)
557 /* Get a cached copy of attributes and link the route */
559 a
->source
= RTS_DUMMY
;
560 e
->attrs
= rta_lookup(a
);
561 e
->next
= net
->routes
;
569 krt_prune(struct krt_proto
*p
)
571 struct rtable
*t
= p
->p
.table
;
573 KRT_TRACE(p
, D_EVENTS
, "Pruning table %s", t
->name
);
577 int verdict
= f
->flags
& KRF_VERDICT_MASK
;
580 if (verdict
!= KRF_CREATE
&& verdict
!= KRF_SEEN
&& verdict
!= KRF_IGNORE
)
583 n
->routes
= old
->next
;
592 if (new && (f
->flags
& KRF_INSTALLED
))
594 krt_trace_in(p
, new, "reinstalling");
595 krt_set_notify(p
, n
, new, NULL
);
600 /* Nothing happens */
603 krt_trace_in(p
, new, "updating");
604 krt_set_notify(p
, n
, new, old
);
607 krt_trace_in(p
, old
, "deleting");
608 krt_set_notify(p
, n
, NULL
, old
);
611 bug("krt_prune: invalid route status");
615 f
->flags
&= ~KRF_VERDICT_MASK
;
619 #ifdef KRT_ALLOW_LEARN
627 krt_got_route_async(struct krt_proto
*p
, rte
*e
, int new UNUSED
)
630 int src
= e
->u
.krt
.src
;
635 ASSERT(0); /* Should be filtered by the back end */
636 case KRT_SRC_REDIRECT
:
637 DBG("It's a redirect, kill him! Kill! Kill!\n");
638 krt_set_notify(p
, net
, NULL
, e
);
640 #ifdef KRT_ALLOW_LEARN
644 krt_learn_async(p
, e
, new);
657 krt_scan(timer
*t UNUSED
)
662 #ifdef CONFIG_ALL_TABLES_AT_ONCE
665 /* We need some node to decide whether to print the debug messages or not */
666 p
= SKIP_BACK(struct krt_proto
, instance_node
, HEAD(krt_instance_list
));
667 if (p
->instance_node
.next
)
668 KRT_TRACE(p
, D_EVENTS
, "Scanning routing table");
670 WALK_LIST(q
, krt_instance_list
)
672 p
= SKIP_BACK(struct krt_proto
, instance_node
, q
);
678 KRT_TRACE(p
, D_EVENTS
, "Scanning routing table");
689 krt_notify(struct proto
*P
, net
*net
, rte
*new, rte
*old
, struct ea_list
*attrs UNUSED
)
691 struct krt_proto
*p
= (struct krt_proto
*) P
;
695 if (new && (!krt_capable(new) || new->attrs
->source
== RTS_INHERIT
))
697 if (!(net
->n
.flags
& KRF_INSTALLED
))
700 net
->n
.flags
|= KRF_INSTALLED
;
702 net
->n
.flags
&= ~KRF_INSTALLED
;
703 if (p
->initialized
) /* Before first scan we don't touch the routes */
704 krt_set_notify(p
, net
, new, old
);
711 struct proto_config
*cf_krt
;
714 krt_preconfig(struct protocol
*P UNUSED
, struct config
*c
)
717 krt_scan_preconfig(c
);
721 krt_postconfig(struct proto_config
*C
)
723 struct krt_config
*c
= (struct krt_config
*) C
;
725 #ifdef CONFIG_ALL_TABLES_AT_ONCE
726 struct krt_config
*first
= (struct krt_config
*) cf_krt
;
727 if (first
->scan_time
!= c
->scan_time
)
728 cf_error("All kernel syncers must use the same table scan interval");
731 if (C
->table
->krt_attached
)
732 cf_error("Kernel syncer (%s) already attached to table %s", C
->table
->krt_attached
->name
, C
->table
->name
);
733 C
->table
->krt_attached
= C
;
734 krt_scan_postconfig(c
);
738 krt_start_timer(struct krt_proto
*p
)
742 t
= tm_new(p
->krt_pool
);
745 t
->recurrent
= KRT_CF
->scan_time
;
751 krt_start(struct proto
*P
)
753 struct krt_proto
*p
= (struct krt_proto
*) P
;
756 #ifdef CONFIG_ALL_TABLES_AT_ONCE
757 if (!krt_instance_count
++)
758 init_list(&krt_instance_list
);
761 p
->krt_pool
= krt_pool
;
762 add_tail(&krt_instance_list
, &p
->instance_node
);
764 p
->krt_pool
= P
->pool
;
767 #ifdef KRT_ALLOW_LEARN
771 krt_scan_start(p
, first
);
772 krt_set_start(p
, first
);
774 /* Start periodic routing table scanning */
775 #ifdef CONFIG_ALL_TABLES_AT_ONCE
777 krt_scan_timer
= krt_start_timer(p
);
779 tm_start(krt_scan_timer
, 0);
780 p
->scan_timer
= krt_scan_timer
;
782 p
->scan_timer
= krt_start_timer(p
);
789 krt_shutdown(struct proto
*P
)
791 struct krt_proto
*p
= (struct krt_proto
*) P
;
794 #ifdef CONFIG_ALL_TABLES_AT_ONCE
795 rem_node(&p
->instance_node
);
796 if (--krt_instance_count
)
800 tm_stop(p
->scan_timer
);
802 /* FIXME we should flush routes even when persist during reconfiguration */
803 if (p
->initialized
&& !KRT_CF
->persist
)
806 krt_set_shutdown(p
, last
);
807 krt_scan_shutdown(p
, last
);
809 #ifdef CONFIG_ALL_TABLES_AT_ONCE
811 rfree(krt_scan_timer
);
817 static struct proto
*
818 krt_init(struct proto_config
*c
)
820 struct krt_proto
*p
= proto_new(c
, sizeof(struct krt_proto
));
822 p
->p
.rt_notify
= krt_notify
;
823 p
->p
.min_scope
= SCOPE_HOST
;
828 krt_reconfigure(struct proto
*p
, struct proto_config
*new)
830 struct krt_config
*o
= (struct krt_config
*) p
->cf
;
831 struct krt_config
*n
= (struct krt_config
*) new;
833 return o
->scan_time
== n
->scan_time
834 && o
->learn
== n
->learn
/* persist needn't be the same */
835 && krt_set_params_same(&o
->set
, &n
->set
)
836 && krt_scan_params_same(&o
->scan
, &n
->scan
)
840 struct protocol proto_unix_kernel
= {
842 template: "kernel%d",
843 preconfig
: krt_preconfig
,
844 postconfig
: krt_postconfig
,
847 shutdown
: krt_shutdown
,
848 reconfigure
: krt_reconfigure
,
849 #ifdef KRT_ALLOW_LEARN
851 dump_attrs
: krt_dump_attrs
,