2 * BIRD -- UNIX Kernel Synchronization
4 * (c) 1998--1999 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
11 #include "nest/bird.h"
12 #include "nest/iface.h"
13 #include "nest/route.h"
14 #include "nest/protocol.h"
15 #include "lib/timer.h"
20 static int krt_uptodate(rte
*k
, rte
*e
);
36 struct proto_config
*cf_kif
;
38 static struct kif_proto
*kif_proto
;
39 static timer
*kif_scan_timer
;
40 static bird_clock_t kif_last_shot
;
45 struct kif_proto
*p
= t
->data
;
47 DBG("KIF: It's interface scan time...\n");
55 if (kif_proto
&& kif_last_shot
+ 2 < now
)
57 kif_scan(kif_scan_timer
);
58 tm_start(kif_scan_timer
, ((struct kif_config
*) kif_proto
->p
.cf
)->scan_time
);
63 kif_init(struct proto_config
*c
)
65 struct kif_proto
*p
= proto_new(c
, sizeof(struct kif_proto
));
70 kif_start(struct proto
*P
)
72 struct kif_proto
*p
= (struct kif_proto
*) P
;
77 /* Start periodic interface scanning */
78 kif_scan_timer
= tm_new(P
->pool
);
79 kif_scan_timer
->hook
= kif_scan
;
80 kif_scan_timer
->data
= p
;
81 kif_scan_timer
->recurrent
= KIF_CF
->scan_time
;
82 kif_scan(kif_scan_timer
);
83 tm_start(kif_scan_timer
, KIF_CF
->scan_time
);
89 kif_shutdown(struct proto
*P
)
91 struct kif_proto
*p
= (struct kif_proto
*) P
;
93 tm_stop(kif_scan_timer
);
97 if_start_update(); /* Remove all interfaces */
103 struct protocol proto_unix_iface
= {
108 shutdown
: kif_shutdown
,
115 #ifdef KRT_ALLOW_LEARN
118 krt_same_key(rte
*a
, rte
*b
)
120 return a
->u
.krt
.proto
== b
->u
.krt
.proto
&&
121 a
->u
.krt
.metric
== b
->u
.krt
.metric
&&
122 a
->u
.krt
.type
== b
->u
.krt
.type
;
126 krt_learn_announce_update(struct krt_proto
*p
, rte
*e
)
129 rta
*aa
= rta_clone(e
->attrs
);
130 rte
*ee
= rte_get_temp(aa
);
131 net
*nn
= net_get(p
->p
.table
, 0, n
->n
.prefix
, n
->n
.pxlen
); /* FIXME: TOS */
134 ee
->u
.krt
= e
->u
.krt
;
135 rte_update(nn
, &p
->p
, ee
);
139 krt_learn_announce_delete(struct krt_proto
*p
, net
*n
)
141 n
= net_find(p
->p
.table
, 0, n
->n
.prefix
, n
->n
.pxlen
); /* FIXME: TOS */
143 rte_update(n
, &p
->p
, NULL
);
147 krt_learn_scan(struct krt_proto
*p
, rte
*e
)
150 net
*n
= net_get(&p
->krt_table
, 0, n0
->n
.prefix
, n0
->n
.pxlen
); /* FIXME: TOS */
153 e
->attrs
->source
= RTS_INHERIT
;
155 for(mm
=&n
->routes
; m
= *mm
; mm
=&m
->next
)
156 if (krt_same_key(m
, e
))
160 if (krt_uptodate(m
, e
))
162 DBG("krt_learn_scan: SEEN\n");
168 DBG("krt_learn_scan: OVERRIDE\n");
175 DBG("krt_learn_scan: CREATE\n");
178 e
->attrs
= rta_lookup(e
->attrs
);
185 /* FIXME: Add dump function */
188 krt_learn_prune(struct krt_proto
*p
)
190 struct fib
*fib
= &p
->krt_table
.fib
;
191 struct fib_iterator fit
;
193 DBG("Pruning inheritance data...\n");
195 FIB_ITERATE_INIT(&fit
, fib
);
197 FIB_ITERATE_START(fib
, &fit
, f
)
200 rte
*e
, **ee
, *best
, **pbest
, *old_best
;
202 old_best
= n
->routes
;
214 if (!best
|| best
->u
.krt
.metric
> e
->u
.krt
.metric
)
224 DBG("%I/%d: deleting\n", n
->n
.prefix
, n
->n
.pxlen
);
227 krt_learn_announce_delete(p
, n
);
228 n
->n
.flags
&= ~KRF_INSTALLED
;
230 FIB_ITERATE_PUT(&fit
, f
);
235 best
->next
= n
->routes
;
237 if (best
!= old_best
|| !(n
->n
.flags
& KRF_INSTALLED
))
239 DBG("%I/%d: announcing (metric=%d)\n", n
->n
.prefix
, n
->n
.pxlen
, best
->u
.krt
.metric
);
240 krt_learn_announce_update(p
, best
);
241 n
->n
.flags
|= KRF_INSTALLED
;
244 DBG("%I/%d: uptodate (metric=%d)\n", n
->n
.prefix
, n
->n
.pxlen
, best
->u
.krt
.metric
);
250 krt_learn_async(struct krt_proto
*p
, rte
*e
, int new)
253 net
*n
= net_get(&p
->krt_table
, 0, n0
->n
.prefix
, n0
->n
.pxlen
); /* FIXME: TOS */
254 rte
*g
, **gg
, *best
, **bestp
, *old_best
;
256 e
->attrs
->source
= RTS_INHERIT
;
258 old_best
= n
->routes
;
259 for(gg
=&n
->routes
; g
= *gg
; gg
= &g
->next
)
260 if (krt_same_key(g
, e
))
266 if (krt_uptodate(g
, e
))
268 DBG("krt_learn_async: same\n");
272 DBG("krt_learn_async: update\n");
277 DBG("krt_learn_async: create\n");
278 e
->attrs
= rta_lookup(e
->attrs
);
284 DBG("krt_learn_async: not found\n");
290 DBG("krt_learn_async: delete\n");
297 for(gg
=&n
->routes
; g
=*gg
; gg
=&g
->next
)
298 if (best
->u
.krt
.metric
> g
->u
.krt
.metric
)
306 best
->next
= n
->routes
;
309 if (best
!= old_best
)
311 DBG("krt_learn_async: distributing change\n");
314 krt_learn_announce_update(p
, best
);
315 n
->n
.flags
|= KRF_INSTALLED
;
320 krt_learn_announce_delete(p
, n
);
321 n
->n
.flags
&= ~KRF_INSTALLED
;
327 krt_learn_init(struct krt_proto
*p
)
330 rt_setup(p
->p
.pool
, &p
->krt_table
, "Inherited");
334 krt_dump(struct proto
*P
)
336 struct krt_proto
*p
= (struct krt_proto
*) P
;
340 debug("KRT: Table of inheritable routes\n");
341 rt_dump(&p
->krt_table
);
345 krt_dump_attrs(rte
*e
)
347 debug(" [m=%d,p=%d,t=%d]", e
->u
.krt
.metric
, e
->u
.krt
.proto
, e
->u
.krt
.type
);
357 krt_flush_routes(struct krt_proto
*p
)
359 struct rtable
*t
= &master_table
;
361 DBG("Flushing kernel routes...\n");
373 if (a
->source
!= RTS_DEVICE
&& a
->source
!= RTS_INHERIT
)
374 krt_set_notify(p
, e
->net
, NULL
, e
);
380 /* FIXME: Synchronization of multiple routing tables? */
383 krt_uptodate(rte
*k
, rte
*e
)
385 rta
*ka
= k
->attrs
, *ea
= e
->attrs
;
387 if (ka
->dest
!= ea
->dest
)
392 return ipa_equal(ka
->gw
, ea
->gw
);
394 return !strcmp(ka
->iface
->name
, ea
->iface
->name
);
401 * This gets called back when the low-level scanning code discovers a route.
402 * We expect that the route is a temporary rte and its attributes are uncached.
406 krt_got_route(struct krt_proto
*p
, rte
*e
)
410 int src
= e
->u
.krt
.src
;
413 #ifdef CONFIG_AUTO_ROUTES
414 if (e
->attrs
->dest
== RTD_DEVICE
)
416 /* It's a device route. Probably a kernel-generated one. */
417 verdict
= KRF_IGNORE
;
422 #ifdef KRT_ALLOW_LEARN
423 if (src
== KRT_SRC_ALIEN
)
426 krt_learn_scan(p
, e
);
428 DBG("krt_parse_entry: Alien route, ignoring\n");
433 if (net
->n
.flags
& KRF_VERDICT_MASK
)
435 /* Route to this destination was already seen. Strange, but it happens... */
436 DBG("Already seen.\n");
440 if (net
->n
.flags
& KRF_INSTALLED
)
444 if (krt_uptodate(e
, old
))
447 verdict
= KRF_UPDATE
;
450 verdict
= KRF_DELETE
;
453 DBG("krt_parse_entry: verdict=%s\n", ((char *[]) { "CREATE", "SEEN", "UPDATE", "DELETE", "IGNORE" }) [verdict
]);
455 net
->n
.flags
= (net
->n
.flags
& ~KRF_VERDICT_MASK
) | verdict
;
456 if (verdict
== KRF_UPDATE
|| verdict
== KRF_DELETE
)
458 /* Get a cached copy of attributes and link the route */
460 a
->source
= RTS_DUMMY
;
461 e
->attrs
= rta_lookup(a
);
462 e
->next
= net
->routes
;
470 krt_prune(struct krt_proto
*p
)
472 struct proto
*pp
= &p
->p
;
473 struct rtable
*t
= &master_table
;
476 DBG("Pruning routes...\n");
484 int verdict
= f
->flags
& KRF_VERDICT_MASK
;
487 if (verdict
!= KRF_CREATE
&& verdict
!= KRF_SEEN
&& verdict
!= KRF_IGNORE
)
490 n
->routes
= old
->next
;
499 if (new && (f
->flags
& KRF_INSTALLED
))
501 DBG("krt_prune: reinstalling %I/%d\n", n
->n
.prefix
, n
->n
.pxlen
);
502 krt_set_notify(p
, n
, new, NULL
);
507 /* Nothing happens */
510 DBG("krt_prune: updating %I/%d\n", n
->n
.prefix
, n
->n
.pxlen
);
511 krt_set_notify(p
, n
, new, old
);
514 DBG("krt_prune: deleting %I/%d\n", n
->n
.prefix
, n
->n
.pxlen
);
515 krt_set_notify(p
, n
, NULL
, old
);
518 bug("krt_prune: invalid route status");
522 f
->flags
&= ~KRF_VERDICT_MASK
;
526 #ifdef KRT_ALLOW_LEARN
533 krt_got_route_async(struct krt_proto
*p
, rte
*e
, int new)
536 rte
*old
= net
->routes
;
537 int src
= e
->u
.krt
.src
;
543 case KRT_SRC_REDIRECT
:
544 DBG("It's a redirect, kill him! Kill! Kill!\n");
545 krt_set_notify(p
, net
, NULL
, e
);
548 #ifdef KRT_ALLOW_LEARN
551 krt_learn_async(p
, e
, new);
558 rte_update(net
, &p
->p
, NULL
);
567 static timer
*krt_scan_timer
;
572 struct krt_proto
*p
= t
->data
;
575 DBG("KRT: It's route scan time...\n");
585 krt_notify(struct proto
*P
, net
*net
, rte
*new, rte
*old
)
587 struct krt_proto
*p
= (struct krt_proto
*) P
;
589 if (new && (!krt_capable(new) || new->attrs
->source
== RTS_INHERIT
))
591 if (!(net
->n
.flags
& KRF_INSTALLED
))
594 net
->n
.flags
|= KRF_INSTALLED
;
596 net
->n
.flags
&= ~KRF_INSTALLED
;
597 krt_set_notify(p
, net
, new, old
);
604 struct proto_config
*cf_krt
;
607 krt_start(struct proto
*P
)
609 struct krt_proto
*p
= (struct krt_proto
*) P
;
611 #ifdef KRT_ALLOW_LEARN
618 /* Start periodic routing table scanning */
619 krt_scan_timer
= tm_new(P
->pool
);
620 krt_scan_timer
->hook
= krt_scan
;
621 krt_scan_timer
->data
= p
;
622 krt_scan_timer
->recurrent
= KRT_CF
->scan_time
;
623 krt_scan(krt_scan_timer
);
624 tm_start(krt_scan_timer
, KRT_CF
->scan_time
);
630 krt_shutdown(struct proto
*P
)
632 struct krt_proto
*p
= (struct krt_proto
*) P
;
634 tm_stop(krt_scan_timer
);
636 if (!KRT_CF
->persist
)
640 krt_scan_shutdown(p
);
645 static struct proto
*
646 krt_init(struct proto_config
*c
)
648 struct krt_proto
*p
= proto_new(c
, sizeof(struct krt_proto
));
650 p
->p
.rt_notify
= krt_notify
;
654 struct protocol proto_unix_kernel
= {
659 shutdown
: krt_shutdown
,
660 #ifdef KRT_ALLOW_LEARN
662 dump_attrs
: krt_dump_attrs
,