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
);
147 prefer_scope(struct ifa
*a
, struct ifa
*b
)
148 { return (a
->scope
> SCOPE_LINK
) && (b
->scope
<= SCOPE_LINK
); }
151 prefer_addr(struct ifa
*a
, struct ifa
*b
)
152 { return ipa_compare(a
->ip
, b
->ip
) < 0; }
154 static inline struct ifa
*
155 find_preferred_ifa(struct iface
*i
, ip_addr prefix
, ip_addr mask
)
157 struct ifa
*a
, *b
= NULL
;
159 WALK_LIST(a
, i
->addrs
)
161 if (!(a
->flags
& IA_SECONDARY
) &&
162 ipa_equal(ipa_and(a
->ip
, mask
), prefix
) &&
163 (!b
|| prefer_scope(a
, b
) || prefer_addr(a
, b
)))
171 kif_choose_primary(struct iface
*i
)
173 struct kif_config
*cf
= (struct kif_config
*) (kif_proto
->p
.cf
);
174 struct kif_primary_item
*it
;
177 WALK_LIST(it
, cf
->primary
)
179 if (!it
->pattern
|| patmatch(it
->pattern
, i
->name
))
180 if (a
= find_preferred_ifa(i
, it
->prefix
, ipa_mkmask(it
->pxlen
)))
184 return find_preferred_ifa(i
, IPA_NONE
, IPA_NONE
);
189 kif_reconfigure(struct proto
*p
, struct proto_config
*new)
191 struct kif_config
*o
= (struct kif_config
*) p
->cf
;
192 struct kif_config
*n
= (struct kif_config
*) new;
194 if (!kif_params_same(&o
->iface
, &n
->iface
))
197 if (o
->scan_time
!= n
->scan_time
)
199 tm_stop(kif_scan_timer
);
200 kif_scan_timer
->recurrent
= n
->scan_time
;
201 kif_scan(kif_scan_timer
);
202 tm_start(kif_scan_timer
, n
->scan_time
);
205 if (!EMPTY_LIST(o
->primary
) || !EMPTY_LIST(n
->primary
))
207 /* This is hack, we have to update a configuration
208 * to the new value just now, because it is used
209 * for recalculation of primary addresses.
213 ifa_recalc_all_primary_addresses();
220 kif_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
222 struct kif_config
*d
= (struct kif_config
*) dest
;
223 struct kif_config
*s
= (struct kif_config
*) src
;
225 /* Shallow copy of everything (just scan_time currently) */
226 proto_copy_rest(dest
, src
, sizeof(struct krt_config
));
228 /* Copy primary addr list */
229 cfg_copy_list(&d
->primary
, &s
->primary
, sizeof(struct kif_primary_item
));
231 /* Fix sysdep parts */
232 kif_copy_params(&d
->iface
, &s
->iface
);
236 struct protocol proto_unix_iface
= {
238 template: "device%d",
239 preconfig
: kif_preconfig
,
242 shutdown
: kif_shutdown
,
243 reconfigure
: kif_reconfigure
,
244 copy_config
: kif_copy_config
252 krt_trace_in(struct krt_proto
*p
, rte
*e
, char *msg
)
254 if (p
->p
.debug
& D_PACKETS
)
255 log(L_TRACE
"%s: %I/%d: %s", p
->p
.name
, e
->net
->n
.prefix
, e
->net
->n
.pxlen
, msg
);
259 krt_trace_in_rl(struct rate_limit
*rl
, struct krt_proto
*p
, rte
*e
, char *msg
)
261 if (p
->p
.debug
& D_PACKETS
)
262 log_rl(rl
, L_TRACE
"%s: %I/%d: %s", p
->p
.name
, e
->net
->n
.prefix
, e
->net
->n
.pxlen
, msg
);
269 #ifdef KRT_ALLOW_LEARN
271 static struct rate_limit rl_alien_seen
, rl_alien_updated
, rl_alien_created
, rl_alien_ignored
;
274 krt_same_key(rte
*a
, rte
*b
)
276 return a
->u
.krt
.proto
== b
->u
.krt
.proto
&&
277 a
->u
.krt
.metric
== b
->u
.krt
.metric
&&
278 a
->u
.krt
.type
== b
->u
.krt
.type
;
282 krt_learn_announce_update(struct krt_proto
*p
, rte
*e
)
285 rta
*aa
= rta_clone(e
->attrs
);
286 rte
*ee
= rte_get_temp(aa
);
287 net
*nn
= net_get(p
->p
.table
, n
->n
.prefix
, n
->n
.pxlen
);
290 ee
->pref
= p
->p
.preference
;
291 ee
->u
.krt
= e
->u
.krt
;
292 rte_update(p
->p
.table
, nn
, &p
->p
, &p
->p
, ee
);
296 krt_learn_announce_delete(struct krt_proto
*p
, net
*n
)
298 n
= net_find(p
->p
.table
, n
->n
.prefix
, n
->n
.pxlen
);
300 rte_update(p
->p
.table
, n
, &p
->p
, &p
->p
, NULL
);
304 krt_learn_scan(struct krt_proto
*p
, rte
*e
)
307 net
*n
= net_get(&p
->krt_table
, n0
->n
.prefix
, n0
->n
.pxlen
);
310 e
->attrs
->source
= RTS_INHERIT
;
312 for(mm
=&n
->routes
; m
= *mm
; mm
=&m
->next
)
313 if (krt_same_key(m
, e
))
317 if (krt_uptodate(m
, e
))
319 krt_trace_in_rl(&rl_alien_seen
, p
, e
, "[alien] seen");
325 krt_trace_in_rl(&rl_alien_updated
, p
, e
, "[alien] updated");
332 krt_trace_in_rl(&rl_alien_created
, p
, e
, "[alien] created");
335 e
->attrs
= rta_lookup(e
->attrs
);
343 krt_learn_prune(struct krt_proto
*p
)
345 struct fib
*fib
= &p
->krt_table
.fib
;
346 struct fib_iterator fit
;
348 KRT_TRACE(p
, D_EVENTS
, "Pruning inherited routes");
350 FIB_ITERATE_INIT(&fit
, fib
);
352 FIB_ITERATE_START(fib
, &fit
, f
)
355 rte
*e
, **ee
, *best
, **pbest
, *old_best
;
357 old_best
= n
->routes
;
369 if (!best
|| best
->u
.krt
.metric
> e
->u
.krt
.metric
)
379 DBG("%I/%d: deleting\n", n
->n
.prefix
, n
->n
.pxlen
);
382 krt_learn_announce_delete(p
, n
);
383 n
->n
.flags
&= ~KRF_INSTALLED
;
385 FIB_ITERATE_PUT(&fit
, f
);
390 best
->next
= n
->routes
;
392 if (best
!= old_best
|| !(n
->n
.flags
& KRF_INSTALLED
))
394 DBG("%I/%d: announcing (metric=%d)\n", n
->n
.prefix
, n
->n
.pxlen
, best
->u
.krt
.metric
);
395 krt_learn_announce_update(p
, best
);
396 n
->n
.flags
|= KRF_INSTALLED
;
399 DBG("%I/%d: uptodate (metric=%d)\n", n
->n
.prefix
, n
->n
.pxlen
, best
->u
.krt
.metric
);
405 krt_learn_async(struct krt_proto
*p
, rte
*e
, int new)
408 net
*n
= net_get(&p
->krt_table
, n0
->n
.prefix
, n0
->n
.pxlen
);
409 rte
*g
, **gg
, *best
, **bestp
, *old_best
;
411 e
->attrs
->source
= RTS_INHERIT
;
413 old_best
= n
->routes
;
414 for(gg
=&n
->routes
; g
= *gg
; gg
= &g
->next
)
415 if (krt_same_key(g
, e
))
421 if (krt_uptodate(g
, e
))
423 krt_trace_in(p
, e
, "[alien async] same");
427 krt_trace_in(p
, e
, "[alien async] updated");
432 krt_trace_in(p
, e
, "[alien async] created");
433 e
->attrs
= rta_lookup(e
->attrs
);
439 krt_trace_in(p
, e
, "[alien async] delete failed");
445 krt_trace_in(p
, e
, "[alien async] removed");
452 for(gg
=&n
->routes
; g
=*gg
; gg
=&g
->next
)
453 if (best
->u
.krt
.metric
> g
->u
.krt
.metric
)
461 best
->next
= n
->routes
;
464 if (best
!= old_best
)
466 DBG("krt_learn_async: distributing change\n");
469 krt_learn_announce_update(p
, best
);
470 n
->n
.flags
|= KRF_INSTALLED
;
475 krt_learn_announce_delete(p
, n
);
476 n
->n
.flags
&= ~KRF_INSTALLED
;
482 krt_learn_init(struct krt_proto
*p
)
485 rt_setup(p
->p
.pool
, &p
->krt_table
, "Inherited", NULL
);
489 krt_dump(struct proto
*P
)
491 struct krt_proto
*p
= (struct krt_proto
*) P
;
495 debug("KRT: Table of inheritable routes\n");
496 rt_dump(&p
->krt_table
);
500 krt_dump_attrs(rte
*e
)
502 debug(" [m=%d,p=%d,t=%d]", e
->u
.krt
.metric
, e
->u
.krt
.proto
, e
->u
.krt
.type
);
511 #ifdef CONFIG_ALL_TABLES_AT_ONCE
512 static timer
*krt_scan_timer
;
513 static int krt_instance_count
;
514 static list krt_instance_list
;
518 krt_flush_routes(struct krt_proto
*p
)
520 struct rtable
*t
= p
->p
.table
;
522 KRT_TRACE(p
, D_EVENTS
, "Flushing kernel routes");
530 if ((n
->n
.flags
& KRF_INSTALLED
) &&
531 a
->source
!= RTS_DEVICE
&& a
->source
!= RTS_INHERIT
)
533 krt_set_notify(p
, e
->net
, NULL
, e
);
534 n
->n
.flags
&= ~KRF_INSTALLED
;
542 krt_uptodate(rte
*k
, rte
*e
)
544 rta
*ka
= k
->attrs
, *ea
= e
->attrs
;
546 if (ka
->dest
!= ea
->dest
)
551 return ipa_equal(ka
->gw
, ea
->gw
);
553 return !strcmp(ka
->iface
->name
, ea
->iface
->name
);
560 * This gets called back when the low-level scanning code discovers a route.
561 * We expect that the route is a temporary rte and its attributes are uncached.
565 krt_got_route(struct krt_proto
*p
, rte
*e
)
571 #ifdef KRT_ALLOW_LEARN
572 switch (e
->u
.krt
.src
)
575 verdict
= KRF_IGNORE
;
578 case KRT_SRC_REDIRECT
:
579 verdict
= KRF_DELETE
;
584 krt_learn_scan(p
, e
);
587 krt_trace_in_rl(&rl_alien_ignored
, p
, e
, "[alien] ignored");
593 /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
595 if (net
->n
.flags
& KRF_VERDICT_MASK
)
597 /* Route to this destination was already seen. Strange, but it happens... */
598 krt_trace_in(p
, e
, "already seen");
603 if (net
->n
.flags
& KRF_INSTALLED
)
607 if (krt_uptodate(e
, old
))
610 verdict
= KRF_UPDATE
;
613 verdict
= KRF_DELETE
;
616 krt_trace_in(p
, e
, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict
]);
617 net
->n
.flags
= (net
->n
.flags
& ~KRF_VERDICT_MASK
) | verdict
;
618 if (verdict
== KRF_UPDATE
|| verdict
== KRF_DELETE
)
620 /* Get a cached copy of attributes and link the route */
622 a
->source
= RTS_DUMMY
;
623 e
->attrs
= rta_lookup(a
);
624 e
->next
= net
->routes
;
632 krt_prune(struct krt_proto
*p
)
634 struct rtable
*t
= p
->p
.table
;
636 KRT_TRACE(p
, D_EVENTS
, "Pruning table %s", t
->name
);
640 int verdict
= f
->flags
& KRF_VERDICT_MASK
;
643 if (verdict
!= KRF_CREATE
&& verdict
!= KRF_SEEN
&& verdict
!= KRF_IGNORE
)
646 n
->routes
= old
->next
;
655 if (new && (f
->flags
& KRF_INSTALLED
))
657 krt_trace_in(p
, new, "reinstalling");
658 krt_set_notify(p
, n
, new, NULL
);
663 /* Nothing happens */
666 krt_trace_in(p
, new, "updating");
667 krt_set_notify(p
, n
, new, old
);
670 krt_trace_in(p
, old
, "deleting");
671 krt_set_notify(p
, n
, NULL
, old
);
674 bug("krt_prune: invalid route status");
678 f
->flags
&= ~KRF_VERDICT_MASK
;
682 #ifdef KRT_ALLOW_LEARN
690 krt_got_route_async(struct krt_proto
*p
, rte
*e
, int new)
694 switch (e
->u
.krt
.src
)
697 ASSERT(0); /* Should be filtered by the back end */
699 case KRT_SRC_REDIRECT
:
702 krt_trace_in(p
, e
, "[redirect] deleting");
703 krt_set_notify(p
, net
, NULL
, e
);
705 /* If !new, it is probably echo of our deletion */
708 #ifdef KRT_ALLOW_LEARN
712 krt_learn_async(p
, e
, new);
725 krt_scan(timer
*t UNUSED
)
730 #ifdef CONFIG_ALL_TABLES_AT_ONCE
733 /* We need some node to decide whether to print the debug messages or not */
734 p
= SKIP_BACK(struct krt_proto
, instance_node
, HEAD(krt_instance_list
));
735 if (p
->instance_node
.next
)
736 KRT_TRACE(p
, D_EVENTS
, "Scanning routing table");
738 WALK_LIST(q
, krt_instance_list
)
740 p
= SKIP_BACK(struct krt_proto
, instance_node
, q
);
746 KRT_TRACE(p
, D_EVENTS
, "Scanning routing table");
756 krt_import_control(struct proto
*P
, rte
**new, ea_list
**attrs
, struct linpool
*pool
)
758 struct krt_proto
*p
= (struct krt_proto
*) P
;
761 if (e
->attrs
->proto
== P
)
764 if (!KRT_CF
->devroutes
&&
765 (e
->attrs
->dest
== RTD_DEVICE
) &&
766 (e
->attrs
->source
!= RTS_STATIC_DEVICE
))
776 krt_notify(struct proto
*P
, struct rtable
*table UNUSED
, net
*net
,
777 rte
*new, rte
*old
, struct ea_list
*attrs UNUSED
)
779 struct krt_proto
*p
= (struct krt_proto
*) P
;
783 if (!(net
->n
.flags
& KRF_INSTALLED
))
786 net
->n
.flags
|= KRF_INSTALLED
;
788 net
->n
.flags
&= ~KRF_INSTALLED
;
789 if (p
->initialized
) /* Before first scan we don't touch the routes */
790 krt_set_notify(p
, net
, new, old
);
797 struct proto_config
*cf_krt
;
800 krt_preconfig(struct protocol
*P UNUSED
, struct config
*c
)
803 krt_scan_preconfig(c
);
807 krt_postconfig(struct proto_config
*C
)
809 struct krt_config
*c
= (struct krt_config
*) C
;
811 #ifdef CONFIG_ALL_TABLES_AT_ONCE
812 struct krt_config
*first
= (struct krt_config
*) cf_krt
;
813 if (first
->scan_time
!= c
->scan_time
)
814 cf_error("All kernel syncers must use the same table scan interval");
817 if (C
->table
->krt_attached
)
818 cf_error("Kernel syncer (%s) already attached to table %s", C
->table
->krt_attached
->name
, C
->table
->name
);
819 C
->table
->krt_attached
= C
;
820 krt_scan_postconfig(c
);
824 krt_start_timer(struct krt_proto
*p
)
828 t
= tm_new(p
->krt_pool
);
831 t
->recurrent
= KRT_CF
->scan_time
;
837 krt_start(struct proto
*P
)
839 struct krt_proto
*p
= (struct krt_proto
*) P
;
842 #ifdef CONFIG_ALL_TABLES_AT_ONCE
843 if (!krt_instance_count
++)
844 init_list(&krt_instance_list
);
847 p
->krt_pool
= krt_pool
;
848 add_tail(&krt_instance_list
, &p
->instance_node
);
850 p
->krt_pool
= P
->pool
;
853 #ifdef KRT_ALLOW_LEARN
857 krt_scan_start(p
, first
);
858 krt_set_start(p
, first
);
860 /* Start periodic routing table scanning */
861 #ifdef CONFIG_ALL_TABLES_AT_ONCE
863 krt_scan_timer
= krt_start_timer(p
);
865 tm_start(krt_scan_timer
, 0);
866 p
->scan_timer
= krt_scan_timer
;
868 p
->scan_timer
= krt_start_timer(p
);
875 krt_shutdown(struct proto
*P
)
877 struct krt_proto
*p
= (struct krt_proto
*) P
;
880 #ifdef CONFIG_ALL_TABLES_AT_ONCE
881 rem_node(&p
->instance_node
);
882 if (--krt_instance_count
)
886 tm_stop(p
->scan_timer
);
888 /* FIXME we should flush routes even when persist during reconfiguration */
889 if (p
->initialized
&& !KRT_CF
->persist
)
892 krt_set_shutdown(p
, last
);
893 krt_scan_shutdown(p
, last
);
895 #ifdef CONFIG_ALL_TABLES_AT_ONCE
897 rfree(krt_scan_timer
);
903 static struct proto
*
904 krt_init(struct proto_config
*c
)
906 struct krt_proto
*p
= proto_new(c
, sizeof(struct krt_proto
));
908 p
->p
.accept_ra_types
= RA_OPTIMAL
;
909 p
->p
.import_control
= krt_import_control
;
910 p
->p
.rt_notify
= krt_notify
;
916 krt_reconfigure(struct proto
*p
, struct proto_config
*new)
918 struct krt_config
*o
= (struct krt_config
*) p
->cf
;
919 struct krt_config
*n
= (struct krt_config
*) new;
921 return o
->scan_time
== n
->scan_time
922 && o
->learn
== n
->learn
/* persist needn't be the same */
923 && o
->devroutes
== n
->devroutes
924 && krt_set_params_same(&o
->set
, &n
->set
)
925 && krt_scan_params_same(&o
->scan
, &n
->scan
)
930 krt_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
932 struct krt_config
*d
= (struct krt_config
*) dest
;
933 struct krt_config
*s
= (struct krt_config
*) src
;
935 /* Shallow copy of everything */
936 proto_copy_rest(dest
, src
, sizeof(struct krt_config
));
938 /* Fix sysdep parts */
939 krt_set_copy_params(&d
->set
, &s
->set
);
940 krt_scan_copy_params(&d
->scan
, &s
->scan
);
944 krt_get_attr(eattr
* a
, byte
* buf
, int buflen UNUSED
)
949 bsprintf(buf
, "prefsrc");
952 bsprintf(buf
, "realm");
960 struct protocol proto_unix_kernel
= {
962 template: "kernel%d",
964 preconfig
: krt_preconfig
,
965 postconfig
: krt_postconfig
,
968 shutdown
: krt_shutdown
,
969 reconfigure
: krt_reconfigure
,
970 copy_config
: krt_copy_config
,
971 get_attr
: krt_get_attr
,
972 #ifdef KRT_ALLOW_LEARN
974 dump_attrs
: krt_dump_attrs
,