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 "sysdep/unix/timer.h"
60 #include "conf/conf.h"
61 #include "lib/string.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 bird_clock_t kif_last_shot
;
95 struct kif_proto
*p
= t
->data
;
97 KRT_TRACE(p
, D_EVENTS
, "Scanning interfaces");
105 if (kif_proto
&& kif_last_shot
+ 2 < now
)
107 kif_scan(kif_scan_timer
);
108 tm_start(kif_scan_timer
, ((struct kif_config
*) kif_proto
->p
.cf
)->scan_time
);
113 kif_request_scan(void)
115 if (kif_proto
&& kif_scan_timer
->expires
> now
)
116 tm_start(kif_scan_timer
, 1);
120 prefer_addr(struct ifa
*a
, struct ifa
*b
)
122 int sa
= a
->scope
> SCOPE_LINK
;
123 int sb
= b
->scope
> SCOPE_LINK
;
130 return ipa_compare(a
->ip
, b
->ip
) < 0;
133 static inline struct ifa
*
134 find_preferred_ifa(struct iface
*i
, const net_addr
*n
)
136 struct ifa
*a
, *b
= NULL
;
138 WALK_LIST(a
, i
->addrs
)
140 if (!(a
->flags
& IA_SECONDARY
) &&
141 (!n
|| ipa_in_netX(a
->ip
, n
)) &&
142 (!b
|| prefer_addr(a
, b
)))
150 kif_choose_primary(struct iface
*i
)
152 struct kif_config
*cf
= (struct kif_config
*) (kif_proto
->p
.cf
);
153 struct kif_primary_item
*it
;
156 WALK_LIST(it
, cf
->primary
)
158 if (!it
->pattern
|| patmatch(it
->pattern
, i
->name
))
159 if (a
= find_preferred_ifa(i
, &it
->addr
))
163 if (a
= kif_get_primary_ip(i
))
166 return find_preferred_ifa(i
, NULL
);
170 static struct proto
*
171 kif_init(struct proto_config
*c
)
173 struct kif_proto
*p
= proto_new(c
);
180 kif_start(struct proto
*P
)
182 struct kif_proto
*p
= (struct kif_proto
*) P
;
187 /* Start periodic interface scanning */
188 kif_scan_timer
= tm_new(P
->pool
);
189 kif_scan_timer
->hook
= kif_scan
;
190 kif_scan_timer
->data
= p
;
191 kif_scan_timer
->recurrent
= KIF_CF
->scan_time
;
192 kif_scan(kif_scan_timer
);
193 tm_start(kif_scan_timer
, KIF_CF
->scan_time
);
199 kif_shutdown(struct proto
*P
)
201 struct kif_proto
*p
= (struct kif_proto
*) P
;
203 tm_stop(kif_scan_timer
);
211 kif_reconfigure(struct proto
*p
, struct proto_config
*new)
213 struct kif_config
*o
= (struct kif_config
*) p
->cf
;
214 struct kif_config
*n
= (struct kif_config
*) new;
216 if (!kif_sys_reconfigure((struct kif_proto
*) p
, n
, o
))
219 if (o
->scan_time
!= n
->scan_time
)
221 tm_stop(kif_scan_timer
);
222 kif_scan_timer
->recurrent
= n
->scan_time
;
223 kif_scan(kif_scan_timer
);
224 tm_start(kif_scan_timer
, n
->scan_time
);
227 if (!EMPTY_LIST(o
->primary
) || !EMPTY_LIST(n
->primary
))
229 /* This is hack, we have to update a configuration
230 * to the new value just now, because it is used
231 * for recalculation of primary addresses.
235 ifa_recalc_all_primary_addresses();
243 kif_preconfig(struct protocol
*P UNUSED
, struct config
*c
)
246 kif_sys_preconfig(c
);
249 struct proto_config
*
250 kif_init_config(int class)
253 cf_error("Kernel device protocol already defined");
255 kif_cf
= (struct kif_config
*) proto_config_new(&proto_unix_iface
, class);
256 kif_cf
->scan_time
= 60;
257 init_list(&kif_cf
->primary
);
259 kif_sys_init_config(kif_cf
);
260 return (struct proto_config
*) kif_cf
;
264 kif_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
266 struct kif_config
*d
= (struct kif_config
*) dest
;
267 struct kif_config
*s
= (struct kif_config
*) src
;
269 /* Copy primary addr list */
270 cfg_copy_list(&d
->primary
, &s
->primary
, sizeof(struct kif_primary_item
));
272 /* Fix sysdep parts */
273 kif_sys_copy_config(d
, s
);
277 struct protocol proto_unix_iface
= {
279 .template = "device%d",
280 .proto_size
= sizeof(struct kif_proto
),
281 .config_size
= sizeof(struct kif_config
),
282 .preconfig
= kif_preconfig
,
285 .shutdown
= kif_shutdown
,
286 .reconfigure
= kif_reconfigure
,
287 .copy_config
= kif_copy_config
295 krt_trace_in(struct krt_proto
*p
, rte
*e
, char *msg
)
297 if (p
->p
.debug
& D_PACKETS
)
298 log(L_TRACE
"%s: %N: %s", p
->p
.name
, e
->net
->n
.addr
, msg
);
302 krt_trace_in_rl(struct tbf
*f
, struct krt_proto
*p
, rte
*e
, char *msg
)
304 if (p
->p
.debug
& D_PACKETS
)
305 log_rl(f
, L_TRACE
"%s: %N: %s", p
->p
.name
, e
->net
->n
.addr
, msg
);
312 #ifdef KRT_ALLOW_LEARN
314 static struct tbf rl_alien
= TBF_DEFAULT_LOG_LIMITS
;
317 * krt_same_key() specifies what (aside from the net) is the key in
318 * kernel routing tables. It should be OS-dependent, this is for
319 * Linux. It is important for asynchronous alien updates, because a
320 * positive update is implicitly a negative one for any old route with
325 krt_same_key(rte
*a
, rte
*b
)
327 return a
->u
.krt
.metric
== b
->u
.krt
.metric
;
331 krt_uptodate(rte
*a
, rte
*b
)
333 if (a
->attrs
!= b
->attrs
)
336 if (a
->u
.krt
.proto
!= b
->u
.krt
.proto
)
343 krt_learn_announce_update(struct krt_proto
*p
, rte
*e
)
346 rta
*aa
= rta_clone(e
->attrs
);
347 rte
*ee
= rte_get_temp(aa
);
349 ee
->u
.krt
= e
->u
.krt
;
350 rte_update(&p
->p
, n
->n
.addr
, ee
);
354 krt_learn_announce_delete(struct krt_proto
*p
, net
*n
)
356 rte_update(&p
->p
, n
->n
.addr
, NULL
);
359 /* Called when alien route is discovered during scan */
361 krt_learn_scan(struct krt_proto
*p
, rte
*e
)
364 net
*n
= net_get(&p
->krt_table
, n0
->n
.addr
);
367 e
->attrs
= rta_lookup(e
->attrs
);
369 for(mm
=&n
->routes
; m
= *mm
; mm
=&m
->next
)
370 if (krt_same_key(m
, e
))
374 if (krt_uptodate(m
, e
))
376 krt_trace_in_rl(&rl_alien
, p
, e
, "[alien] seen");
382 krt_trace_in(p
, e
, "[alien] updated");
389 krt_trace_in(p
, e
, "[alien] created");
399 krt_learn_prune(struct krt_proto
*p
)
401 struct fib
*fib
= &p
->krt_table
.fib
;
402 struct fib_iterator fit
;
404 KRT_TRACE(p
, D_EVENTS
, "Pruning inherited routes");
406 FIB_ITERATE_INIT(&fit
, fib
);
408 FIB_ITERATE_START(fib
, &fit
, net
, n
)
410 rte
*e
, **ee
, *best
, **pbest
, *old_best
;
413 * Note that old_best may be NULL even if there was an old best route in
414 * the previous step, because it might be replaced in krt_learn_scan().
415 * But in that case there is a new valid best route.
434 if (!best
|| best
->u
.krt
.metric
> e
->u
.krt
.metric
)
446 DBG("%I/%d: deleting\n", n
->n
.prefix
, n
->n
.pxlen
);
448 krt_learn_announce_delete(p
, n
);
450 FIB_ITERATE_PUT(&fit
);
455 best
->u
.krt
.best
= 1;
457 best
->next
= n
->routes
;
460 if ((best
!= old_best
) || p
->reload
)
462 DBG("%I/%d: announcing (metric=%d)\n", n
->n
.prefix
, n
->n
.pxlen
, best
->u
.krt
.metric
);
463 krt_learn_announce_update(p
, best
);
466 DBG("%I/%d: uptodate (metric=%d)\n", n
->n
.prefix
, n
->n
.pxlen
, best
->u
.krt
.metric
);
474 krt_learn_async(struct krt_proto
*p
, rte
*e
, int new)
477 net
*n
= net_get(&p
->krt_table
, n0
->n
.addr
);
478 rte
*g
, **gg
, *best
, **bestp
, *old_best
;
480 e
->attrs
= rta_lookup(e
->attrs
);
482 old_best
= n
->routes
;
483 for(gg
=&n
->routes
; g
= *gg
; gg
= &g
->next
)
484 if (krt_same_key(g
, e
))
490 if (krt_uptodate(g
, e
))
492 krt_trace_in(p
, e
, "[alien async] same");
496 krt_trace_in(p
, e
, "[alien async] updated");
501 krt_trace_in(p
, e
, "[alien async] created");
508 krt_trace_in(p
, e
, "[alien async] delete failed");
514 krt_trace_in(p
, e
, "[alien async] removed");
521 for(gg
=&n
->routes
; g
=*gg
; gg
=&g
->next
)
523 if (best
->u
.krt
.metric
> g
->u
.krt
.metric
)
534 best
->u
.krt
.best
= 1;
536 best
->next
= n
->routes
;
540 if (best
!= old_best
)
542 DBG("krt_learn_async: distributing change\n");
544 krt_learn_announce_update(p
, best
);
546 krt_learn_announce_delete(p
, n
);
551 krt_learn_init(struct krt_proto
*p
)
554 rt_setup(p
->p
.pool
, &p
->krt_table
, "Inherited", NULL
);
558 krt_dump(struct proto
*P
)
560 struct krt_proto
*p
= (struct krt_proto
*) P
;
564 debug("KRT: Table of inheritable routes\n");
565 rt_dump(&p
->krt_table
);
569 krt_dump_attrs(rte
*e
)
571 debug(" [m=%d,p=%d]", e
->u
.krt
.metric
, e
->u
.krt
.proto
);
581 krt_flush_routes(struct krt_proto
*p
)
583 struct rtable
*t
= p
->p
.main_channel
->table
;
585 KRT_TRACE(p
, D_EVENTS
, "Flushing kernel routes");
586 FIB_WALK(&t
->fib
, net
, n
)
589 if (rte_is_valid(e
) && (n
->n
.flags
& KRF_INSTALLED
))
591 /* FIXME: this does not work if gw is changed in export filter */
592 krt_replace_rte(p
, e
->net
, NULL
, e
, NULL
);
593 n
->n
.flags
&= ~KRF_INSTALLED
;
600 krt_export_net(struct krt_proto
*p
, net
*net
, rte
**rt_free
, ea_list
**tmpa
)
602 struct channel
*c
= p
->p
.main_channel
;
603 struct filter
*filter
= c
->out_filter
;
606 if (c
->ra_mode
== RA_MERGED
)
607 return rt_export_merged(c
, net
, rt_free
, tmpa
, krt_filter_lp
, 1);
612 if (!rte_is_valid(rt
))
615 if (filter
== FILTER_REJECT
)
618 struct proto
*src
= rt
->attrs
->src
->proto
;
619 *tmpa
= src
->make_tmp_attrs
? src
->make_tmp_attrs(rt
, krt_filter_lp
) : NULL
;
621 /* We could run krt_import_control() here, but it is already handled by KRF_INSTALLED */
623 if (filter
== FILTER_ACCEPT
)
626 if (f_run(filter
, &rt
, tmpa
, krt_filter_lp
, FF_FORCE_TMPATTR
) > F_ACCEPT
)
631 if (rt
!= net
->routes
)
636 if (rt
!= net
->routes
)
642 krt_same_dest(rte
*k
, rte
*e
)
644 rta
*ka
= k
->attrs
, *ea
= e
->attrs
;
646 if (ka
->dest
!= ea
->dest
)
649 if (ka
->dest
== RTD_UNICAST
)
650 return nexthop_same(&(ka
->nh
), &(ea
->nh
));
656 * This gets called back when the low-level scanning code discovers a route.
657 * We expect that the route is a temporary rte and its attributes are uncached.
661 krt_got_route(struct krt_proto
*p
, rte
*e
)
666 #ifdef KRT_ALLOW_LEARN
667 switch (e
->u
.krt
.src
)
670 verdict
= KRF_IGNORE
;
673 case KRT_SRC_REDIRECT
:
674 verdict
= KRF_DELETE
;
679 krt_learn_scan(p
, e
);
682 krt_trace_in_rl(&rl_alien
, p
, e
, "[alien] ignored");
688 /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
690 if (net
->n
.flags
& KRF_VERDICT_MASK
)
692 /* Route to this destination was already seen. Strange, but it happens... */
693 krt_trace_in(p
, e
, "already seen");
700 /* We wait for the initial feed to have correct KRF_INSTALLED flag */
701 verdict
= KRF_IGNORE
;
705 if (net
->n
.flags
& KRF_INSTALLED
)
710 new = krt_export_net(p
, net
, &rt_free
, &tmpa
);
712 /* TODO: There also may be changes in route eattrs, we ignore that for now. */
715 verdict
= KRF_DELETE
;
716 else if ((net
->n
.flags
& KRF_SYNC_ERROR
) || !krt_same_dest(e
, new))
717 verdict
= KRF_UPDATE
;
724 lp_flush(krt_filter_lp
);
727 verdict
= KRF_DELETE
;
730 krt_trace_in(p
, e
, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict
]);
731 net
->n
.flags
= (net
->n
.flags
& ~KRF_VERDICT_MASK
) | verdict
;
732 if (verdict
== KRF_UPDATE
|| verdict
== KRF_DELETE
)
734 /* Get a cached copy of attributes and temporarily link the route */
736 a
->source
= RTS_DUMMY
;
737 e
->attrs
= rta_lookup(a
);
738 e
->next
= net
->routes
;
746 krt_prune(struct krt_proto
*p
)
748 struct rtable
*t
= p
->p
.main_channel
->table
;
750 KRT_TRACE(p
, D_EVENTS
, "Pruning table %s", t
->name
);
751 FIB_WALK(&t
->fib
, net
, n
)
753 int verdict
= n
->n
.flags
& KRF_VERDICT_MASK
;
754 rte
*new, *old
, *rt_free
= NULL
;
755 ea_list
*tmpa
= NULL
;
757 if (verdict
== KRF_UPDATE
|| verdict
== KRF_DELETE
)
759 /* Get a dummy route from krt_got_route() */
761 n
->routes
= old
->next
;
766 if (verdict
== KRF_CREATE
|| verdict
== KRF_UPDATE
)
768 /* We have to run export filter to get proper 'new' route */
769 new = krt_export_net(p
, n
, &rt_free
, &tmpa
);
772 verdict
= (verdict
== KRF_CREATE
) ? KRF_IGNORE
: KRF_DELETE
;
774 tmpa
= ea_append(tmpa
, new->attrs
->eattrs
);
782 if (new && (n
->n
.flags
& KRF_INSTALLED
))
784 krt_trace_in(p
, new, "reinstalling");
785 krt_replace_rte(p
, n
, new, NULL
, tmpa
);
790 /* Nothing happens */
793 krt_trace_in(p
, new, "updating");
794 krt_replace_rte(p
, n
, new, old
, tmpa
);
797 krt_trace_in(p
, old
, "deleting");
798 krt_replace_rte(p
, n
, NULL
, old
, NULL
);
801 bug("krt_prune: invalid route status");
808 lp_flush(krt_filter_lp
);
809 n
->n
.flags
&= ~KRF_VERDICT_MASK
;
813 #ifdef KRT_ALLOW_LEARN
823 krt_got_route_async(struct krt_proto
*p
, rte
*e
, int new)
827 switch (e
->u
.krt
.src
)
830 ASSERT(0); /* Should be filtered by the back end */
832 case KRT_SRC_REDIRECT
:
835 krt_trace_in(p
, e
, "[redirect] deleting");
836 krt_replace_rte(p
, net
, NULL
, e
, NULL
);
838 /* If !new, it is probably echo of our deletion */
841 #ifdef KRT_ALLOW_LEARN
845 krt_learn_async(p
, e
, new);
858 #ifdef CONFIG_ALL_TABLES_AT_ONCE
860 static timer
*krt_scan_timer
;
861 static int krt_scan_count
;
864 krt_scan(timer
*t UNUSED
)
870 /* We need some node to decide whether to print the debug messages or not */
871 p
= SKIP_BACK(struct krt_proto
, krt_node
, HEAD(krt_proto_list
));
872 KRT_TRACE(p
, D_EVENTS
, "Scanning routing table");
877 WALK_LIST(q
, krt_proto_list
)
879 p
= SKIP_BACK(struct krt_proto
, krt_node
, q
);
885 krt_scan_timer_start(struct krt_proto
*p
)
888 krt_scan_timer
= tm_new_set(krt_pool
, krt_scan
, NULL
, 0, KRT_CF
->scan_time
);
892 tm_start(krt_scan_timer
, 1);
896 krt_scan_timer_stop(struct krt_proto
*p UNUSED
)
902 rfree(krt_scan_timer
);
903 krt_scan_timer
= NULL
;
908 krt_scan_timer_kick(struct krt_proto
*p UNUSED
)
910 tm_start(krt_scan_timer
, 0);
918 struct krt_proto
*p
= t
->data
;
922 KRT_TRACE(p
, D_EVENTS
, "Scanning routing table");
928 krt_scan_timer_start(struct krt_proto
*p
)
930 p
->scan_timer
= tm_new_set(p
->p
.pool
, krt_scan
, p
, 0, KRT_CF
->scan_time
);
931 tm_start(p
->scan_timer
, 1);
935 krt_scan_timer_stop(struct krt_proto
*p
)
937 tm_stop(p
->scan_timer
);
941 krt_scan_timer_kick(struct krt_proto
*p
)
943 tm_start(p
->scan_timer
, 0);
955 static struct ea_list
*
956 krt_make_tmp_attrs(rte
*rt
, struct linpool
*pool
)
958 struct ea_list
*l
= lp_alloc(pool
, sizeof(struct ea_list
) + 2 * sizeof(eattr
));
961 l
->flags
= EALF_SORTED
;
964 l
->attrs
[0].id
= EA_KRT_SOURCE
;
965 l
->attrs
[0].flags
= 0;
966 l
->attrs
[0].type
= EAF_TYPE_INT
| EAF_TEMP
;
967 l
->attrs
[0].u
.data
= rt
->u
.krt
.proto
;
969 l
->attrs
[1].id
= EA_KRT_METRIC
;
970 l
->attrs
[1].flags
= 0;
971 l
->attrs
[1].type
= EAF_TYPE_INT
| EAF_TEMP
;
972 l
->attrs
[1].u
.data
= rt
->u
.krt
.metric
;
978 krt_store_tmp_attrs(rte
*rt
, struct ea_list
*attrs
)
980 /* EA_KRT_SOURCE is read-only */
981 rt
->u
.krt
.metric
= ea_get_int(attrs
, EA_KRT_METRIC
, 0);
985 krt_import_control(struct proto
*P
, rte
**new, ea_list
**attrs UNUSED
, struct linpool
*pool UNUSED
)
987 // struct krt_proto *p = (struct krt_proto *) P;
990 if (e
->attrs
->src
->proto
== P
)
992 #ifdef CONFIG_SINGLE_ROUTE
994 * Implicit withdraw - when the imported kernel route becomes the best one,
995 * we know that the previous one exported to the kernel was already removed,
996 * but if we processed the update as usual, we would send withdraw to the
997 * kernel, which would remove the new imported route instead.
999 * We will remove KRT_INSTALLED flag, which stops such withdraw to be
1000 * processed in krt_rt_notify() and krt_replace_rte().
1002 if (e
== e
->net
->routes
)
1003 e
->net
->n
.flags
&= ~KRF_INSTALLED
;
1008 if (!krt_capable(e
))
1015 krt_rt_notify(struct proto
*P
, struct channel
*ch UNUSED
, net
*net
,
1016 rte
*new, rte
*old
, struct ea_list
*eattrs
)
1018 struct krt_proto
*p
= (struct krt_proto
*) P
;
1020 if (config
->shutdown
)
1022 if (!(net
->n
.flags
& KRF_INSTALLED
))
1025 net
->n
.flags
|= KRF_INSTALLED
;
1027 net
->n
.flags
&= ~KRF_INSTALLED
;
1028 if (p
->initialized
) /* Before first scan we don't touch the routes */
1029 krt_replace_rte(p
, net
, new, old
, eattrs
);
1033 krt_if_notify(struct proto
*P
, uint flags
, struct iface
*iface UNUSED
)
1035 struct krt_proto
*p
= (struct krt_proto
*) P
;
1038 * When interface went down, we should remove routes to it. In the ideal world,
1039 * OS kernel would send us route removal notifications in such cases, but we
1040 * cannot rely on it as it is often not true. E.g. Linux kernel removes related
1041 * routes when an interface went down, but it does not notify userspace about
1042 * that. To be sure, we just schedule a scan to ensure synchronization.
1045 if ((flags
& IF_CHANGE_DOWN
) && KRT_CF
->learn
)
1046 krt_scan_timer_kick(p
);
1050 krt_reload_routes(struct channel
*C
)
1052 struct krt_proto
*p
= (void *) C
->proto
;
1054 /* Although we keep learned routes in krt_table, we rather schedule a scan */
1059 krt_scan_timer_kick(p
);
1064 krt_feed_end(struct channel
*C
)
1066 struct krt_proto
*p
= (void *) C
->proto
;
1069 krt_scan_timer_kick(p
);
1074 krt_rte_same(rte
*a
, rte
*b
)
1076 /* src is always KRT_SRC_ALIEN and type is irrelevant */
1077 return (a
->u
.krt
.proto
== b
->u
.krt
.proto
) && (a
->u
.krt
.metric
== b
->u
.krt
.metric
);
1085 struct krt_config
*krt_cf
;
1088 krt_preconfig(struct protocol
*P UNUSED
, struct config
*c
)
1091 krt_sys_preconfig(c
);
1095 krt_postconfig(struct proto_config
*CF
)
1097 struct krt_config
*cf
= (void *) CF
;
1099 if (EMPTY_LIST(CF
->channels
))
1100 cf_error("Channel not specified");
1102 #ifdef CONFIG_ALL_TABLES_AT_ONCE
1103 if (krt_cf
->scan_time
!= cf
->scan_time
)
1104 cf_error("All kernel syncers must use the same table scan interval");
1107 struct rtable_config
*tab
= proto_cf_main_channel(CF
)->table
;
1108 if (tab
->krt_attached
)
1109 cf_error("Kernel syncer (%s) already attached to table %s", tab
->krt_attached
->name
, tab
->name
);
1110 tab
->krt_attached
= CF
;
1112 krt_sys_postconfig(cf
);
1115 static struct proto
*
1116 krt_init(struct proto_config
*CF
)
1118 struct krt_proto
*p
= proto_new(CF
);
1119 // struct krt_config *cf = (void *) CF;
1121 p
->p
.main_channel
= proto_add_channel(&p
->p
, proto_cf_main_channel(CF
));
1123 p
->p
.import_control
= krt_import_control
;
1124 p
->p
.rt_notify
= krt_rt_notify
;
1125 p
->p
.if_notify
= krt_if_notify
;
1126 p
->p
.reload_routes
= krt_reload_routes
;
1127 p
->p
.feed_end
= krt_feed_end
;
1128 p
->p
.make_tmp_attrs
= krt_make_tmp_attrs
;
1129 p
->p
.store_tmp_attrs
= krt_store_tmp_attrs
;
1130 p
->p
.rte_same
= krt_rte_same
;
1137 krt_start(struct proto
*P
)
1139 struct krt_proto
*p
= (struct krt_proto
*) P
;
1141 switch (p
->p
.net_type
)
1143 case NET_IP4
: p
->af
= AF_INET
; break;
1144 case NET_IP6
: p
->af
= AF_INET6
; break;
1146 case NET_MPLS
: p
->af
= AF_MPLS
; break;
1148 default: log(L_ERR
"KRT: Tried to start with strange net type: %d", p
->p
.net_type
); return PS_START
; break;
1151 add_tail(&krt_proto_list
, &p
->krt_node
);
1153 #ifdef KRT_ALLOW_LEARN
1157 if (!krt_sys_start(p
))
1159 rem_node(&p
->krt_node
);
1163 krt_scan_timer_start(p
);
1165 if (p
->p
.gr_recovery
&& KRT_CF
->graceful_restart
)
1166 p
->p
.main_channel
->gr_wait
= 1;
1172 krt_shutdown(struct proto
*P
)
1174 struct krt_proto
*p
= (struct krt_proto
*) P
;
1176 krt_scan_timer_stop(p
);
1178 /* FIXME we should flush routes even when persist during reconfiguration */
1179 if (p
->initialized
&& !KRT_CF
->persist
)
1180 krt_flush_routes(p
);
1185 if (p
->p
.proto_state
== PS_START
)
1188 krt_sys_shutdown(p
);
1189 rem_node(&p
->krt_node
);
1195 krt_reconfigure(struct proto
*p
, struct proto_config
*CF
)
1197 struct krt_config
*o
= (void *) p
->cf
;
1198 struct krt_config
*n
= (void *) CF
;
1200 if (!proto_configure_channel(p
, &p
->main_channel
, proto_cf_main_channel(CF
)))
1203 if (!krt_sys_reconfigure((struct krt_proto
*) p
, n
, o
))
1206 /* persist, graceful restart need not be the same */
1207 return o
->scan_time
== n
->scan_time
&& o
->learn
== n
->learn
&& o
->devroutes
== n
->devroutes
;
1210 struct proto_config
*
1211 krt_init_config(int class)
1213 #ifndef CONFIG_MULTIPLE_TABLES
1215 cf_error("Kernel protocol already defined");
1218 krt_cf
= (struct krt_config
*) proto_config_new(&proto_unix_kernel
, class);
1219 krt_cf
->scan_time
= 60;
1221 krt_sys_init_config(krt_cf
);
1222 return (struct proto_config
*) krt_cf
;
1226 krt_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
1228 struct krt_config
*d
= (struct krt_config
*) dest
;
1229 struct krt_config
*s
= (struct krt_config
*) src
;
1231 /* Fix sysdep parts */
1232 krt_sys_copy_config(d
, s
);
1236 krt_get_attr(eattr
*a
, byte
*buf
, int buflen
)
1241 bsprintf(buf
, "source");
1245 bsprintf(buf
, "metric");
1249 return krt_sys_get_attr(a
, buf
, buflen
);
1254 struct protocol proto_unix_kernel
= {
1256 .template = "kernel%d",
1257 .attr_class
= EAP_KRT
,
1258 .preference
= DEF_PREF_INHERITED
,
1259 .channel_mask
= NB_IP
| NB_MPLS
,
1260 .proto_size
= sizeof(struct krt_proto
),
1261 .config_size
= sizeof(struct krt_config
),
1262 .preconfig
= krt_preconfig
,
1263 .postconfig
= krt_postconfig
,
1266 .shutdown
= krt_shutdown
,
1267 .reconfigure
= krt_reconfigure
,
1268 .copy_config
= krt_copy_config
,
1269 .get_attr
= krt_get_attr
,
1270 #ifdef KRT_ALLOW_LEARN
1272 .dump_attrs
= krt_dump_attrs
,