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].
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.
38 * The code uses OS-dependent parts for kernel updates and scans. These parts are
39 * in more specific sysdep directories (e.g. sysdep/linux) in functions krt_sys_*
40 * and kif_sys_* (and some others like krt_replace_rte()) and krt-sys.h header file.
41 * This is also used for platform specific protocol options and route attributes.
43 * There was also an old code that used traditional UNIX ioctls for these tasks.
44 * It was unmaintained and later removed. For reference, see sysdep/krt-* files
45 * in commit 396dfa9042305f62da1f56589c4b98fac57fc2f6
49 * If you are brave enough, continue now. You cannot say you haven't been warned.
54 #include "nest/bird.h"
55 #include "nest/iface.h"
56 #include "nest/route.h"
57 #include "nest/protocol.h"
58 #include "filter/filter.h"
59 #include "conf/conf.h"
60 #include "lib/string.h"
61 #include "lib/timer.h"
71 static linpool
*krt_filter_lp
;
72 static list krt_proto_list
;
77 krt_pool
= rp_new(&root_pool
, "Kernel Syncer");
78 krt_filter_lp
= lp_new_default(krt_pool
);
79 init_list(&krt_proto_list
);
87 struct kif_proto
*kif_proto
;
88 static struct kif_config
*kif_cf
;
89 static timer
*kif_scan_timer
;
90 static btime kif_last_shot
;
92 static struct kif_iface_config kif_default_iface
= {};
94 struct kif_iface_config
*
95 kif_get_iface_config(struct iface
*iface
)
97 struct kif_config
*cf
= (void *) (kif_proto
->p
.cf
);
98 struct kif_iface_config
*ic
= (void *) iface_patt_find(&cf
->iface_list
, iface
, NULL
);
99 return ic
?: &kif_default_iface
;
105 struct kif_proto
*p
= t
->data
;
107 KRT_TRACE(p
, D_EVENTS
, "Scanning interfaces");
108 kif_last_shot
= current_time();
115 if (kif_proto
&& ((kif_last_shot
+ 2 S
) < current_time()))
117 kif_scan(kif_scan_timer
);
118 tm_start(kif_scan_timer
, ((struct kif_config
*) kif_proto
->p
.cf
)->scan_time
);
123 kif_request_scan(void)
125 if (kif_proto
&& (kif_scan_timer
->expires
> (current_time() + 1 S
)))
126 tm_start(kif_scan_timer
, 1 S
);
129 static struct proto
*
130 kif_init(struct proto_config
*c
)
132 struct kif_proto
*p
= proto_new(c
);
139 kif_start(struct proto
*P
)
141 struct kif_proto
*p
= (struct kif_proto
*) P
;
146 /* Start periodic interface scanning */
147 kif_scan_timer
= tm_new_init(P
->pool
, kif_scan
, p
, KIF_CF
->scan_time
, 0);
148 kif_scan(kif_scan_timer
);
149 tm_start(kif_scan_timer
, KIF_CF
->scan_time
);
155 kif_shutdown(struct proto
*P
)
157 struct kif_proto
*p
= (struct kif_proto
*) P
;
159 tm_stop(kif_scan_timer
);
167 kif_reconfigure(struct proto
*p
, struct proto_config
*new)
169 struct kif_config
*o
= (struct kif_config
*) p
->cf
;
170 struct kif_config
*n
= (struct kif_config
*) new;
172 if (!kif_sys_reconfigure((struct kif_proto
*) p
, n
, o
))
175 if (o
->scan_time
!= n
->scan_time
)
177 tm_stop(kif_scan_timer
);
178 kif_scan_timer
->recurrent
= n
->scan_time
;
179 kif_scan(kif_scan_timer
);
180 tm_start(kif_scan_timer
, n
->scan_time
);
183 if (!EMPTY_LIST(o
->iface_list
) || !EMPTY_LIST(n
->iface_list
))
185 /* This is hack, we have to update a configuration
186 * to the new value just now, because it is used
187 * for recalculation of preferred addresses.
191 if_recalc_all_preferred_addresses();
199 kif_preconfig(struct protocol
*P UNUSED
, struct config
*c
)
202 kif_sys_preconfig(c
);
205 struct proto_config
*
206 kif_init_config(int class)
209 cf_error("Kernel device protocol already defined");
211 kif_cf
= (struct kif_config
*) proto_config_new(&proto_unix_iface
, class);
212 kif_cf
->scan_time
= 60 S
;
213 init_list(&kif_cf
->iface_list
);
215 kif_sys_init_config(kif_cf
);
216 return (struct proto_config
*) kif_cf
;
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 /* Copy interface config list */
226 cfg_copy_list(&d
->iface_list
, &s
->iface_list
, sizeof(struct kif_iface_config
));
228 /* Fix sysdep parts */
229 kif_sys_copy_config(d
, s
);
232 struct protocol proto_unix_iface
= {
234 .template = "device%d",
235 .class = PROTOCOL_DEVICE
,
236 .proto_size
= sizeof(struct kif_proto
),
237 .config_size
= sizeof(struct kif_config
),
238 .preconfig
= kif_preconfig
,
241 .shutdown
= kif_shutdown
,
242 .reconfigure
= kif_reconfigure
,
243 .copy_config
= kif_copy_config
251 krt_trace_in(struct krt_proto
*p
, rte
*e
, char *msg
)
253 if (p
->p
.debug
& D_PACKETS
)
254 log(L_TRACE
"%s: %N: %s", p
->p
.name
, e
->net
->n
.addr
, msg
);
258 krt_trace_in_rl(struct tbf
*f
, struct krt_proto
*p
, rte
*e
, char *msg
)
260 if (p
->p
.debug
& D_PACKETS
)
261 log_rl(f
, L_TRACE
"%s: %N: %s", p
->p
.name
, e
->net
->n
.addr
, msg
);
268 #ifdef KRT_ALLOW_LEARN
270 static struct tbf rl_alien
= TBF_DEFAULT_LOG_LIMITS
;
273 * krt_same_key() specifies what (aside from the net) is the key in
274 * kernel routing tables. It should be OS-dependent, this is for
275 * Linux. It is important for asynchronous alien updates, because a
276 * positive update is implicitly a negative one for any old route with
281 krt_same_key(rte
*a
, rte
*b
)
283 return a
->u
.krt
.metric
== b
->u
.krt
.metric
;
287 krt_uptodate(rte
*a
, rte
*b
)
289 if (a
->attrs
!= b
->attrs
)
292 if (a
->u
.krt
.proto
!= b
->u
.krt
.proto
)
299 krt_learn_announce_update(struct krt_proto
*p
, rte
*e
)
302 rta
*aa
= rta_clone(e
->attrs
);
303 rte
*ee
= rte_get_temp(aa
);
304 ee
->pflags
= EA_ID_FLAG(EA_KRT_SOURCE
) | EA_ID_FLAG(EA_KRT_METRIC
);
305 ee
->u
.krt
= e
->u
.krt
;
306 rte_update(&p
->p
, n
->n
.addr
, ee
);
310 krt_learn_announce_delete(struct krt_proto
*p
, net
*n
)
312 rte_update(&p
->p
, n
->n
.addr
, NULL
);
315 /* Called when alien route is discovered during scan */
317 krt_learn_scan(struct krt_proto
*p
, rte
*e
)
320 net
*n
= net_get(&p
->krt_table
, n0
->n
.addr
);
323 e
->attrs
= rta_lookup(e
->attrs
);
325 for(mm
=&n
->routes
; m
= *mm
; mm
=&m
->next
)
326 if (krt_same_key(m
, e
))
330 if (krt_uptodate(m
, e
))
332 krt_trace_in_rl(&rl_alien
, p
, e
, "[alien] seen");
338 krt_trace_in(p
, e
, "[alien] updated");
345 krt_trace_in(p
, e
, "[alien] created");
355 krt_learn_prune(struct krt_proto
*p
)
357 struct fib
*fib
= &p
->krt_table
.fib
;
358 struct fib_iterator fit
;
360 KRT_TRACE(p
, D_EVENTS
, "Pruning inherited routes");
362 FIB_ITERATE_INIT(&fit
, fib
);
364 FIB_ITERATE_START(fib
, &fit
, net
, n
)
366 rte
*e
, **ee
, *best
, **pbest
, *old_best
;
369 * Note that old_best may be NULL even if there was an old best route in
370 * the previous step, because it might be replaced in krt_learn_scan().
371 * But in that case there is a new valid best route.
390 if (!best
|| best
->u
.krt
.metric
> e
->u
.krt
.metric
)
402 DBG("%I/%d: deleting\n", n
->n
.prefix
, n
->n
.pxlen
);
404 krt_learn_announce_delete(p
, n
);
406 FIB_ITERATE_PUT(&fit
);
411 best
->u
.krt
.best
= 1;
413 best
->next
= n
->routes
;
416 if ((best
!= old_best
) || p
->reload
)
418 DBG("%I/%d: announcing (metric=%d)\n", n
->n
.prefix
, n
->n
.pxlen
, best
->u
.krt
.metric
);
419 krt_learn_announce_update(p
, best
);
422 DBG("%I/%d: uptodate (metric=%d)\n", n
->n
.prefix
, n
->n
.pxlen
, best
->u
.krt
.metric
);
430 krt_learn_async(struct krt_proto
*p
, rte
*e
, int new)
433 net
*n
= net_get(&p
->krt_table
, n0
->n
.addr
);
434 rte
*g
, **gg
, *best
, **bestp
, *old_best
;
436 e
->attrs
= rta_lookup(e
->attrs
);
438 old_best
= n
->routes
;
439 for(gg
=&n
->routes
; g
= *gg
; gg
= &g
->next
)
440 if (krt_same_key(g
, e
))
446 if (krt_uptodate(g
, e
))
448 krt_trace_in(p
, e
, "[alien async] same");
452 krt_trace_in(p
, e
, "[alien async] updated");
457 krt_trace_in(p
, e
, "[alien async] created");
464 krt_trace_in(p
, e
, "[alien async] delete failed");
470 krt_trace_in(p
, e
, "[alien async] removed");
477 for(gg
=&n
->routes
; g
=*gg
; gg
=&g
->next
)
479 if (best
->u
.krt
.metric
> g
->u
.krt
.metric
)
490 best
->u
.krt
.best
= 1;
492 best
->next
= n
->routes
;
496 if (best
!= old_best
)
498 DBG("krt_learn_async: distributing change\n");
500 krt_learn_announce_update(p
, best
);
502 krt_learn_announce_delete(p
, n
);
507 krt_learn_init(struct krt_proto
*p
)
511 struct rtable_config
*cf
= mb_allocz(p
->p
.pool
, sizeof(struct rtable_config
));
512 cf
->name
= "Inherited";
513 cf
->addr_type
= p
->p
.net_type
;
515 rt_setup(p
->p
.pool
, &p
->krt_table
, cf
);
520 krt_dump(struct proto
*P
)
522 struct krt_proto
*p
= (struct krt_proto
*) P
;
526 debug("KRT: Table of inheritable routes\n");
527 rt_dump(&p
->krt_table
);
531 krt_dump_attrs(rte
*e
)
533 debug(" [m=%d,p=%d]", e
->u
.krt
.metric
, e
->u
.krt
.proto
);
543 krt_flush_routes(struct krt_proto
*p
)
545 struct rtable
*t
= p
->p
.main_channel
->table
;
547 KRT_TRACE(p
, D_EVENTS
, "Flushing kernel routes");
548 FIB_WALK(&t
->fib
, net
, n
)
551 if (rte_is_valid(e
) && (n
->n
.flags
& KRF_INSTALLED
))
553 /* FIXME: this does not work if gw is changed in export filter */
554 krt_replace_rte(p
, e
->net
, NULL
, e
);
555 n
->n
.flags
&= ~KRF_INSTALLED
;
562 krt_export_net(struct krt_proto
*p
, net
*net
, rte
**rt_free
)
564 struct channel
*c
= p
->p
.main_channel
;
565 const struct filter
*filter
= c
->out_filter
;
568 if (c
->ra_mode
== RA_MERGED
)
569 return rt_export_merged(c
, net
, rt_free
, krt_filter_lp
, 1);
574 if (!rte_is_valid(rt
))
577 if (filter
== FILTER_REJECT
)
580 rte_make_tmp_attrs(&rt
, krt_filter_lp
, NULL
);
582 /* We could run krt_preexport() here, but it is already handled by KRF_INSTALLED */
584 if (filter
== FILTER_ACCEPT
)
587 if (f_run(filter
, &rt
, krt_filter_lp
, FF_SILENT
) > F_ACCEPT
)
592 if (rt
!= net
->routes
)
597 if (rt
!= net
->routes
)
603 krt_same_dest(rte
*k
, rte
*e
)
605 rta
*ka
= k
->attrs
, *ea
= e
->attrs
;
607 if (ka
->dest
!= ea
->dest
)
610 if (ka
->dest
== RTD_UNICAST
)
611 return nexthop_same(&(ka
->nh
), &(ea
->nh
));
617 * This gets called back when the low-level scanning code discovers a route.
618 * We expect that the route is a temporary rte and its attributes are uncached.
622 krt_got_route(struct krt_proto
*p
, rte
*e
)
627 #ifdef KRT_ALLOW_LEARN
628 switch (e
->u
.krt
.src
)
631 verdict
= KRF_IGNORE
;
634 case KRT_SRC_REDIRECT
:
635 verdict
= KRF_DELETE
;
640 krt_learn_scan(p
, e
);
643 krt_trace_in_rl(&rl_alien
, p
, e
, "[alien] ignored");
649 /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
651 if (net
->n
.flags
& KRF_VERDICT_MASK
)
653 /* Route to this destination was already seen. Strange, but it happens... */
654 krt_trace_in(p
, e
, "already seen");
661 /* We wait for the initial feed to have correct KRF_INSTALLED flag */
662 verdict
= KRF_IGNORE
;
666 if (net
->n
.flags
& KRF_INSTALLED
)
670 new = krt_export_net(p
, net
, &rt_free
);
672 /* TODO: There also may be changes in route eattrs, we ignore that for now. */
675 verdict
= KRF_DELETE
;
676 else if ((net
->n
.flags
& KRF_SYNC_ERROR
) || !krt_same_dest(e
, new))
677 verdict
= KRF_UPDATE
;
684 lp_flush(krt_filter_lp
);
687 verdict
= KRF_DELETE
;
690 krt_trace_in(p
, e
, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict
]);
691 net
->n
.flags
= (net
->n
.flags
& ~KRF_VERDICT_MASK
) | verdict
;
692 if (verdict
== KRF_UPDATE
|| verdict
== KRF_DELETE
)
694 /* Get a cached copy of attributes and temporarily link the route */
696 a
->source
= RTS_DUMMY
;
697 e
->attrs
= rta_lookup(a
);
698 e
->next
= net
->routes
;
706 krt_prune(struct krt_proto
*p
)
708 struct rtable
*t
= p
->p
.main_channel
->table
;
710 KRT_TRACE(p
, D_EVENTS
, "Pruning table %s", t
->name
);
711 FIB_WALK(&t
->fib
, net
, n
)
713 int verdict
= n
->n
.flags
& KRF_VERDICT_MASK
;
714 rte
*new, *old
, *rt_free
= NULL
;
716 if (verdict
== KRF_UPDATE
|| verdict
== KRF_DELETE
)
718 /* Get a dummy route from krt_got_route() */
720 n
->routes
= old
->next
;
725 if (verdict
== KRF_CREATE
|| verdict
== KRF_UPDATE
)
727 /* We have to run export filter to get proper 'new' route */
728 new = krt_export_net(p
, n
, &rt_free
);
731 verdict
= (verdict
== KRF_CREATE
) ? KRF_IGNORE
: KRF_DELETE
;
739 if (new && (n
->n
.flags
& KRF_INSTALLED
))
741 krt_trace_in(p
, new, "reinstalling");
742 krt_replace_rte(p
, n
, new, NULL
);
747 /* Nothing happens */
750 krt_trace_in(p
, new, "updating");
751 krt_replace_rte(p
, n
, new, old
);
754 krt_trace_in(p
, old
, "deleting");
755 krt_replace_rte(p
, n
, NULL
, old
);
758 bug("krt_prune: invalid route status");
765 lp_flush(krt_filter_lp
);
766 n
->n
.flags
&= ~KRF_VERDICT_MASK
;
770 #ifdef KRT_ALLOW_LEARN
780 krt_got_route_async(struct krt_proto
*p
, rte
*e
, int new)
784 switch (e
->u
.krt
.src
)
787 /* Should be filtered by the back end */
788 bug("BIRD originated routes should not get here.");
790 case KRT_SRC_REDIRECT
:
793 krt_trace_in(p
, e
, "[redirect] deleting");
794 krt_replace_rte(p
, net
, NULL
, e
);
796 /* If !new, it is probably echo of our deletion */
799 #ifdef KRT_ALLOW_LEARN
803 krt_learn_async(p
, e
, new);
816 #ifdef CONFIG_ALL_TABLES_AT_ONCE
818 static timer
*krt_scan_timer
;
819 static int krt_scan_count
;
822 krt_scan(timer
*t UNUSED
)
828 /* We need some node to decide whether to print the debug messages or not */
829 p
= SKIP_BACK(struct krt_proto
, krt_node
, HEAD(krt_proto_list
));
830 KRT_TRACE(p
, D_EVENTS
, "Scanning routing table");
835 WALK_LIST(q
, krt_proto_list
)
837 p
= SKIP_BACK(struct krt_proto
, krt_node
, q
);
843 krt_scan_timer_start(struct krt_proto
*p
)
846 krt_scan_timer
= tm_new_init(krt_pool
, krt_scan
, NULL
, KRT_CF
->scan_time
, 0);
850 tm_start(krt_scan_timer
, 1 S
);
854 krt_scan_timer_stop(struct krt_proto
*p UNUSED
)
860 rfree(krt_scan_timer
);
861 krt_scan_timer
= NULL
;
866 krt_scan_timer_kick(struct krt_proto
*p UNUSED
)
868 tm_start(krt_scan_timer
, 0);
876 struct krt_proto
*p
= t
->data
;
880 KRT_TRACE(p
, D_EVENTS
, "Scanning routing table");
886 krt_scan_timer_start(struct krt_proto
*p
)
888 p
->scan_timer
= tm_new_init(p
->p
.pool
, krt_scan
, p
, KRT_CF
->scan_time
, 0);
889 tm_start(p
->scan_timer
, 1 S
);
893 krt_scan_timer_stop(struct krt_proto
*p
)
895 tm_stop(p
->scan_timer
);
899 krt_scan_timer_kick(struct krt_proto
*p
)
901 tm_start(p
->scan_timer
, 0);
914 krt_make_tmp_attrs(struct rte
*rt
, struct linpool
*pool
)
916 rte_init_tmp_attrs(rt
, pool
, 2);
917 rte_make_tmp_attr(rt
, EA_KRT_SOURCE
, EAF_TYPE_INT
, rt
->u
.krt
.proto
);
918 rte_make_tmp_attr(rt
, EA_KRT_METRIC
, EAF_TYPE_INT
, rt
->u
.krt
.metric
);
922 krt_store_tmp_attrs(struct rte
*rt
, struct linpool
*pool
)
924 rte_init_tmp_attrs(rt
, pool
, 2);
925 rt
->u
.krt
.proto
= rte_store_tmp_attr(rt
, EA_KRT_SOURCE
);
926 rt
->u
.krt
.metric
= rte_store_tmp_attr(rt
, EA_KRT_METRIC
);
930 krt_preexport(struct proto
*P
, rte
**new, struct linpool
*pool UNUSED
)
932 // struct krt_proto *p = (struct krt_proto *) P;
935 if (e
->attrs
->src
->proto
== P
)
937 #ifdef CONFIG_SINGLE_ROUTE
939 * Implicit withdraw - when the imported kernel route becomes the best one,
940 * we know that the previous one exported to the kernel was already removed,
941 * but if we processed the update as usual, we would send withdraw to the
942 * kernel, which would remove the new imported route instead.
944 * We will remove KRT_INSTALLED flag, which stops such withdraw to be
945 * processed in krt_rt_notify() and krt_replace_rte().
947 if (e
== e
->net
->routes
)
948 e
->net
->n
.flags
&= ~KRF_INSTALLED
;
960 krt_rt_notify(struct proto
*P
, struct channel
*ch UNUSED
, net
*net
,
963 struct krt_proto
*p
= (struct krt_proto
*) P
;
965 if (config
->shutdown
)
967 if (!(net
->n
.flags
& KRF_INSTALLED
))
970 net
->n
.flags
|= KRF_INSTALLED
;
972 net
->n
.flags
&= ~KRF_INSTALLED
;
973 if (p
->initialized
) /* Before first scan we don't touch the routes */
974 krt_replace_rte(p
, net
, new, old
);
978 krt_if_notify(struct proto
*P
, uint flags
, struct iface
*iface UNUSED
)
980 struct krt_proto
*p
= (struct krt_proto
*) P
;
983 * When interface went down, we should remove routes to it. In the ideal world,
984 * OS kernel would send us route removal notifications in such cases, but we
985 * cannot rely on it as it is often not true. E.g. Linux kernel removes related
986 * routes when an interface went down, but it does not notify userspace about
987 * that. To be sure, we just schedule a scan to ensure synchronization.
990 if ((flags
& IF_CHANGE_DOWN
) && KRT_CF
->learn
)
991 krt_scan_timer_kick(p
);
995 krt_reload_routes(struct channel
*C
)
997 struct krt_proto
*p
= (void *) C
->proto
;
999 /* Although we keep learned routes in krt_table, we rather schedule a scan */
1004 krt_scan_timer_kick(p
);
1009 krt_feed_end(struct channel
*C
)
1011 struct krt_proto
*p
= (void *) C
->proto
;
1014 krt_scan_timer_kick(p
);
1019 krt_rte_same(rte
*a
, rte
*b
)
1021 /* src is always KRT_SRC_ALIEN and type is irrelevant */
1022 return (a
->u
.krt
.proto
== b
->u
.krt
.proto
) && (a
->u
.krt
.metric
== b
->u
.krt
.metric
);
1030 struct krt_config
*krt_cf
;
1033 krt_preconfig(struct protocol
*P UNUSED
, struct config
*c
)
1036 krt_sys_preconfig(c
);
1040 krt_postconfig(struct proto_config
*CF
)
1042 struct krt_config
*cf
= (void *) CF
;
1044 if (EMPTY_LIST(CF
->channels
))
1045 cf_error("Channel not specified");
1047 #ifdef CONFIG_ALL_TABLES_AT_ONCE
1048 if (krt_cf
->scan_time
!= cf
->scan_time
)
1049 cf_error("All kernel syncers must use the same table scan interval");
1052 struct channel_config
*cc
= proto_cf_main_channel(CF
);
1053 struct rtable_config
*tab
= cc
->table
;
1054 if (tab
->krt_attached
)
1055 cf_error("Kernel syncer (%s) already attached to table %s", tab
->krt_attached
->name
, tab
->name
);
1056 tab
->krt_attached
= CF
;
1058 if (cf
->merge_paths
)
1060 cc
->ra_mode
= RA_MERGED
;
1061 cc
->merge_limit
= cf
->merge_paths
;
1064 krt_sys_postconfig(cf
);
1067 static struct proto
*
1068 krt_init(struct proto_config
*CF
)
1070 struct krt_proto
*p
= proto_new(CF
);
1071 // struct krt_config *cf = (void *) CF;
1073 p
->p
.main_channel
= proto_add_channel(&p
->p
, proto_cf_main_channel(CF
));
1075 p
->p
.preexport
= krt_preexport
;
1076 p
->p
.rt_notify
= krt_rt_notify
;
1077 p
->p
.if_notify
= krt_if_notify
;
1078 p
->p
.reload_routes
= krt_reload_routes
;
1079 p
->p
.feed_end
= krt_feed_end
;
1080 p
->p
.make_tmp_attrs
= krt_make_tmp_attrs
;
1081 p
->p
.store_tmp_attrs
= krt_store_tmp_attrs
;
1082 p
->p
.rte_same
= krt_rte_same
;
1089 krt_start(struct proto
*P
)
1091 struct krt_proto
*p
= (struct krt_proto
*) P
;
1093 switch (p
->p
.net_type
)
1095 case NET_IP4
: p
->af
= AF_INET
; break;
1096 case NET_IP6
: p
->af
= AF_INET6
; break;
1097 case NET_IP6_SADR
: p
->af
= AF_INET6
; break;
1099 case NET_MPLS
: p
->af
= AF_MPLS
; break;
1101 default: log(L_ERR
"KRT: Tried to start with strange net type: %d", p
->p
.net_type
); return PS_START
; break;
1104 add_tail(&krt_proto_list
, &p
->krt_node
);
1106 #ifdef KRT_ALLOW_LEARN
1110 if (!krt_sys_start(p
))
1112 rem_node(&p
->krt_node
);
1116 krt_scan_timer_start(p
);
1118 if (p
->p
.gr_recovery
&& KRT_CF
->graceful_restart
)
1119 p
->p
.main_channel
->gr_wait
= 1;
1125 krt_shutdown(struct proto
*P
)
1127 struct krt_proto
*p
= (struct krt_proto
*) P
;
1129 krt_scan_timer_stop(p
);
1131 /* FIXME we should flush routes even when persist during reconfiguration */
1132 if (p
->initialized
&& !KRT_CF
->persist
&& (P
->down_code
!= PDC_CMD_GR_DOWN
))
1133 krt_flush_routes(p
);
1138 if (p
->p
.proto_state
== PS_START
)
1141 krt_sys_shutdown(p
);
1142 rem_node(&p
->krt_node
);
1148 krt_reconfigure(struct proto
*p
, struct proto_config
*CF
)
1150 struct krt_config
*o
= (void *) p
->cf
;
1151 struct krt_config
*n
= (void *) CF
;
1153 if (!proto_configure_channel(p
, &p
->main_channel
, proto_cf_main_channel(CF
)))
1156 if (!krt_sys_reconfigure((struct krt_proto
*) p
, n
, o
))
1159 /* persist, graceful restart need not be the same */
1160 return o
->scan_time
== n
->scan_time
&& o
->learn
== n
->learn
;
1163 struct proto_config
*
1164 krt_init_config(int class)
1166 #ifndef CONFIG_MULTIPLE_TABLES
1168 cf_error("Kernel protocol already defined");
1171 krt_cf
= (struct krt_config
*) proto_config_new(&proto_unix_kernel
, class);
1172 krt_cf
->scan_time
= 60 S
;
1174 krt_sys_init_config(krt_cf
);
1175 return (struct proto_config
*) krt_cf
;
1179 krt_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
1181 struct krt_config
*d
= (struct krt_config
*) dest
;
1182 struct krt_config
*s
= (struct krt_config
*) src
;
1184 /* Fix sysdep parts */
1185 krt_sys_copy_config(d
, s
);
1189 krt_get_attr(eattr
*a
, byte
*buf
, int buflen
)
1194 bsprintf(buf
, "source");
1198 bsprintf(buf
, "metric");
1202 return krt_sys_get_attr(a
, buf
, buflen
);
1207 #ifdef CONFIG_IP6_SADR_KERNEL
1208 #define MAYBE_IP6_SADR NB_IP6_SADR
1210 #define MAYBE_IP6_SADR 0
1213 #ifdef HAVE_MPLS_KERNEL
1214 #define MAYBE_MPLS NB_MPLS
1216 #define MAYBE_MPLS 0
1219 struct protocol proto_unix_kernel
= {
1221 .template = "kernel%d",
1222 .class = PROTOCOL_KERNEL
,
1223 .preference
= DEF_PREF_INHERITED
,
1224 .channel_mask
= NB_IP
| MAYBE_IP6_SADR
| MAYBE_MPLS
,
1225 .proto_size
= sizeof(struct krt_proto
),
1226 .config_size
= sizeof(struct krt_config
),
1227 .preconfig
= krt_preconfig
,
1228 .postconfig
= krt_postconfig
,
1231 .shutdown
= krt_shutdown
,
1232 .reconfigure
= krt_reconfigure
,
1233 .copy_config
= krt_copy_config
,
1234 .get_attr
= krt_get_attr
,
1235 #ifdef KRT_ALLOW_LEARN
1237 .dump_attrs
= krt_dump_attrs
,