]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/unix/krt.c
Cosmetic message fix.
[thirdparty/bird.git] / sysdep / unix / krt.c
CommitLineData
2d140452
MM
1/*
2 * BIRD -- UNIX Kernel Synchronization
3 *
4 * (c) 1998--1999 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9#define LOCAL_DEBUG
10
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"
16
17#include "unix.h"
18#include "krt.h"
19
c10421d3
MM
20static int krt_uptodate(rte *k, rte *e);
21
7e5f5ffd
MM
22/*
23 * Global resources
24 */
25
26void
27krt_io_init(void)
28{
29 krt_if_io_init();
30}
31
32/*
33 * Interfaces
34 */
35
36struct proto_config *cf_kif;
37
38static struct kif_proto *kif_proto;
39static timer *kif_scan_timer;
40static bird_clock_t kif_last_shot;
41
42static void
43kif_scan(timer *t)
44{
45 struct kif_proto *p = t->data;
46
47 DBG("KIF: It's interface scan time...\n");
48 kif_last_shot = now;
49 krt_if_scan(p);
50}
51
52static void
53kif_force_scan(void)
54{
55 if (kif_proto && kif_last_shot + 2 < now)
56 {
57 kif_scan(kif_scan_timer);
58 tm_start(kif_scan_timer, ((struct kif_config *) kif_proto->p.cf)->scan_time);
59 }
60}
61
62static struct proto *
63kif_init(struct proto_config *c)
64{
65 struct kif_proto *p = proto_new(c, sizeof(struct kif_proto));
66 return &p->p;
67}
68
69static int
70kif_start(struct proto *P)
71{
72 struct kif_proto *p = (struct kif_proto *) P;
73
74 kif_proto = p;
75 krt_if_start(p);
76
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);
84
85 return PS_UP;
86}
87
88static int
89kif_shutdown(struct proto *P)
90{
91 struct kif_proto *p = (struct kif_proto *) P;
92
93 tm_stop(kif_scan_timer);
94 krt_if_shutdown(p);
95 kif_proto = NULL;
96
97 if_start_update(); /* Remove all interfaces */
98 if_end_update();
99
100 return PS_DOWN;
101}
102
103struct protocol proto_unix_iface = {
104 name: "Device",
105 priority: 100,
106 init: kif_init,
107 start: kif_start,
108 shutdown: kif_shutdown,
109};
2d140452 110
c10421d3
MM
111/*
112 * Inherited Routes
113 */
114
115#ifdef KRT_ALLOW_LEARN
116
117static inline int
118krt_same_key(rte *a, rte *b)
119{
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;
123}
124
125static void
126krt_learn_announce_update(struct krt_proto *p, rte *e)
127{
128 net *n = e->net;
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 */
132 ee->net = nn;
133 ee->pflags = 0;
134 ee->u.krt = e->u.krt;
135 rte_update(nn, &p->p, ee);
136}
137
138static void
139krt_learn_announce_delete(struct krt_proto *p, net *n)
140{
141 n = net_find(p->p.table, 0, n->n.prefix, n->n.pxlen); /* FIXME: TOS */
142 if (n)
143 rte_update(n, &p->p, NULL);
144}
145
146static void
147krt_learn_scan(struct krt_proto *p, rte *e)
148{
149 net *n0 = e->net;
150 net *n = net_get(&p->krt_table, 0, n0->n.prefix, n0->n.pxlen); /* FIXME: TOS */
151 rte *m, **mm;
152
153 e->attrs->source = RTS_INHERIT;
154
155 for(mm=&n->routes; m = *mm; mm=&m->next)
156 if (krt_same_key(m, e))
157 break;
158 if (m)
159 {
160 if (krt_uptodate(m, e))
161 {
162 DBG("krt_learn_scan: SEEN\n");
163 rte_free(e);
164 m->u.krt.seen = 1;
165 }
166 else
167 {
168 DBG("krt_learn_scan: OVERRIDE\n");
169 *mm = m->next;
170 rte_free(m);
171 m = NULL;
172 }
173 }
174 else
175 DBG("krt_learn_scan: CREATE\n");
176 if (!m)
177 {
178 e->attrs = rta_lookup(e->attrs);
179 e->next = n->routes;
180 n->routes = e;
181 e->u.krt.seen = 1;
182 }
183}
184
185/* FIXME: Add dump function */
186
187static void
188krt_learn_prune(struct krt_proto *p)
189{
190 struct fib *fib = &p->krt_table.fib;
191 struct fib_iterator fit;
192
193 DBG("Pruning inheritance data...\n");
194
195 FIB_ITERATE_INIT(&fit, fib);
196again:
197 FIB_ITERATE_START(fib, &fit, f)
198 {
199 net *n = (net *) f;
200 rte *e, **ee, *best, **pbest, *old_best;
201
202 old_best = n->routes;
203 best = NULL;
204 pbest = NULL;
205 ee = &n->routes;
206 while (e = *ee)
207 {
208 if (!e->u.krt.seen)
209 {
210 *ee = e->next;
211 rte_free(e);
212 continue;
213 }
214 if (!best || best->u.krt.metric > e->u.krt.metric)
215 {
216 best = e;
217 pbest = ee;
218 }
219 e->u.krt.seen = 0;
220 ee = &e->next;
221 }
222 if (!n->routes)
223 {
224 DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
225 if (old_best)
226 {
227 krt_learn_announce_delete(p, n);
228 n->n.flags &= ~KRF_INSTALLED;
229 }
230 FIB_ITERATE_PUT(&fit, f);
231 fib_delete(fib, f);
232 goto again;
233 }
234 *pbest = best->next;
235 best->next = n->routes;
236 n->routes = best;
237 if (best != old_best || !(n->n.flags & KRF_INSTALLED))
238 {
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;
242 }
243 else
244 DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
245 }
246 FIB_ITERATE_END(f);
247}
248
249static void
250krt_learn_async(struct krt_proto *p, rte *e, int new)
251{
252 net *n0 = e->net;
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;
255
256 e->attrs->source = RTS_INHERIT;
257
258 old_best = n->routes;
259 for(gg=&n->routes; g = *gg; gg = &g->next)
260 if (krt_same_key(g, e))
261 break;
262 if (new)
263 {
264 if (g)
265 {
266 if (krt_uptodate(g, e))
267 {
268 DBG("krt_learn_async: same\n");
269 rte_free(e);
270 return;
271 }
272 DBG("krt_learn_async: update\n");
273 *gg = g->next;
274 rte_free(g);
275 }
276 else
277 DBG("krt_learn_async: create\n");
278 e->attrs = rta_lookup(e->attrs);
279 e->next = n->routes;
280 n->routes = e;
281 }
282 else if (!g)
283 {
284 DBG("krt_learn_async: not found\n");
285 rte_free(e);
286 return;
287 }
288 else
289 {
290 DBG("krt_learn_async: delete\n");
291 *gg = g->next;
292 rte_free(e);
293 rte_free(g);
294 }
295 best = n->routes;
296 bestp = &n->routes;
297 for(gg=&n->routes; g=*gg; gg=&g->next)
298 if (best->u.krt.metric > g->u.krt.metric)
299 {
300 best = g;
301 bestp = gg;
302 }
303 if (best)
304 {
305 *bestp = best->next;
306 best->next = n->routes;
307 n->routes = best;
308 }
309 if (best != old_best)
310 {
311 DBG("krt_learn_async: distributing change\n");
312 if (best)
313 {
314 krt_learn_announce_update(p, best);
315 n->n.flags |= KRF_INSTALLED;
316 }
317 else
318 {
319 n->routes = NULL;
320 krt_learn_announce_delete(p, n);
321 n->n.flags &= ~KRF_INSTALLED;
322 }
323 }
324}
325
326static void
327krt_learn_init(struct krt_proto *p)
328{
329 if (KRT_CF->learn)
330 rt_setup(p->p.pool, &p->krt_table, "Inherited");
331}
332
333static void
334krt_dump(struct proto *P)
335{
336 struct krt_proto *p = (struct krt_proto *) P;
337
338 if (!KRT_CF->learn)
339 return;
340 debug("KRT: Table of inheritable routes\n");
341 rt_dump(&p->krt_table);
342}
343
344static void
345krt_dump_attrs(rte *e)
346{
347 debug(" [m=%d,p=%d,t=%d]", e->u.krt.metric, e->u.krt.proto, e->u.krt.type);
348}
349
350#endif
351
2d140452
MM
352/*
353 * Routes
354 */
355
356static void
357krt_flush_routes(struct krt_proto *p)
358{
359 struct rtable *t = &master_table;
360
361 DBG("Flushing kernel routes...\n");
362 while (t && t->tos)
363 t = t->sibling;
364 if (!t)
365 return;
366 FIB_WALK(&t->fib, f)
367 {
368 net *n = (net *) f;
369 rte *e = n->routes;
370 if (e)
371 {
372 rta *a = e->attrs;
373 if (a->source != RTS_DEVICE && a->source != RTS_INHERIT)
c10421d3 374 krt_set_notify(p, e->net, NULL, e);
2d140452
MM
375 }
376 }
377 FIB_WALK_END;
378}
379
2d140452
MM
380/* FIXME: Synchronization of multiple routing tables? */
381
382static int
383krt_uptodate(rte *k, rte *e)
384{
385 rta *ka = k->attrs, *ea = e->attrs;
386
387 if (ka->dest != ea->dest)
388 return 0;
389 switch (ka->dest)
390 {
391 case RTD_ROUTER:
392 return ipa_equal(ka->gw, ea->gw);
393 case RTD_DEVICE:
394 return !strcmp(ka->iface->name, ea->iface->name);
395 default:
396 return 1;
397 }
398}
399
400/*
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.
403 */
404
405void
406krt_got_route(struct krt_proto *p, rte *e)
407{
408 rte *old;
409 net *net = e->net;
c10421d3 410 int src = e->u.krt.src;
2d140452
MM
411 int verdict;
412
c10421d3
MM
413#ifdef CONFIG_AUTO_ROUTES
414 if (e->attrs->dest == RTD_DEVICE)
415 {
416 /* It's a device route. Probably a kernel-generated one. */
417 verdict = KRF_IGNORE;
418 goto sentenced;
419 }
420#endif
421
422#ifdef KRT_ALLOW_LEARN
423 if (src == KRT_SRC_ALIEN)
424 {
425 if (KRT_CF->learn)
426 krt_learn_scan(p, e);
427 else
428 DBG("krt_parse_entry: Alien route, ignoring\n");
429 return;
430 }
431#endif
432
433 if (net->n.flags & KRF_VERDICT_MASK)
2d140452
MM
434 {
435 /* Route to this destination was already seen. Strange, but it happens... */
436 DBG("Already seen.\n");
437 return;
438 }
439
c10421d3 440 if (net->n.flags & KRF_INSTALLED)
2d140452 441 {
c10421d3
MM
442 old = net->routes;
443 ASSERT(old);
444 if (krt_uptodate(e, old))
2d140452
MM
445 verdict = KRF_SEEN;
446 else
447 verdict = KRF_UPDATE;
448 }
2d140452
MM
449 else
450 verdict = KRF_DELETE;
451
c10421d3
MM
452sentenced:
453 DBG("krt_parse_entry: verdict=%s\n", ((char *[]) { "CREATE", "SEEN", "UPDATE", "DELETE", "IGNORE" }) [verdict]);
2d140452 454
c10421d3
MM
455 net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
456 if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
2d140452
MM
457 {
458 /* Get a cached copy of attributes and link the route */
459 rta *a = e->attrs;
460 a->source = RTS_DUMMY;
461 e->attrs = rta_lookup(a);
462 e->next = net->routes;
463 net->routes = e;
464 }
465 else
466 rte_free(e);
467}
468
469static void
470krt_prune(struct krt_proto *p)
471{
472 struct proto *pp = &p->p;
473 struct rtable *t = &master_table;
474 struct fib_node *f;
475
476 DBG("Pruning routes...\n");
477 while (t && t->tos)
478 t = t->sibling;
479 if (!t)
480 return;
481 FIB_WALK(&t->fib, f)
482 {
483 net *n = (net *) f;
c10421d3 484 int verdict = f->flags & KRF_VERDICT_MASK;
2d140452
MM
485 rte *new, *old;
486
c10421d3 487 if (verdict != KRF_CREATE && verdict != KRF_SEEN && verdict != KRF_IGNORE)
2d140452
MM
488 {
489 old = n->routes;
490 n->routes = old->next;
491 }
492 else
493 old = NULL;
494 new = n->routes;
495
496 switch (verdict)
497 {
498 case KRF_CREATE:
c10421d3 499 if (new && (f->flags & KRF_INSTALLED))
2d140452 500 {
c10421d3
MM
501 DBG("krt_prune: reinstalling %I/%d\n", n->n.prefix, n->n.pxlen);
502 krt_set_notify(p, n, new, NULL);
2d140452
MM
503 }
504 break;
505 case KRF_SEEN:
c10421d3 506 case KRF_IGNORE:
2d140452
MM
507 /* Nothing happens */
508 break;
509 case KRF_UPDATE:
510 DBG("krt_prune: updating %I/%d\n", n->n.prefix, n->n.pxlen);
c10421d3 511 krt_set_notify(p, n, new, old);
2d140452
MM
512 break;
513 case KRF_DELETE:
514 DBG("krt_prune: deleting %I/%d\n", n->n.prefix, n->n.pxlen);
c10421d3 515 krt_set_notify(p, n, NULL, old);
2d140452
MM
516 break;
517 default:
518 bug("krt_prune: invalid route status");
519 }
2d140452
MM
520 if (old)
521 rte_free(old);
c10421d3 522 f->flags &= ~KRF_VERDICT_MASK;
2d140452
MM
523 }
524 FIB_WALK_END;
c10421d3
MM
525
526#ifdef KRT_ALLOW_LEARN
527 if (KRT_CF->learn)
528 krt_learn_prune(p);
529#endif
2d140452
MM
530}
531
e16155ae
MM
532void
533krt_got_route_async(struct krt_proto *p, rte *e, int new)
534{
535 net *net = e->net;
536 rte *old = net->routes;
c10421d3 537 int src = e->u.krt.src;
e16155ae
MM
538
539 switch (src)
540 {
541 case KRT_SRC_BIRD:
542 ASSERT(0);
543 case KRT_SRC_REDIRECT:
544 DBG("It's a redirect, kill him! Kill! Kill!\n");
c10421d3 545 krt_set_notify(p, net, NULL, e);
e16155ae 546 break;
c10421d3
MM
547 case KRT_SRC_ALIEN:
548#ifdef KRT_ALLOW_LEARN
549 if (KRT_CF->learn)
e16155ae 550 {
c10421d3
MM
551 krt_learn_async(p, e, new);
552 return;
e16155ae 553 }
c10421d3
MM
554#endif
555 /* Fall-thru */
556 default:
557 DBG("Discarding\n");
558 rte_update(net, &p->p, NULL);
e16155ae 559 }
c10421d3 560 rte_free(e);
e16155ae
MM
561}
562
2d140452
MM
563/*
564 * Periodic scanning
565 */
566
567static timer *krt_scan_timer;
568
569static void
570krt_scan(timer *t)
571{
572 struct krt_proto *p = t->data;
573
7e5f5ffd
MM
574 kif_force_scan();
575 DBG("KRT: It's route scan time...\n");
576 krt_scan_fire(p);
577 krt_prune(p);
2d140452
MM
578}
579
c10421d3
MM
580/*
581 * Updates
582 */
583
584static void
585krt_notify(struct proto *P, net *net, rte *new, rte *old)
586{
587 struct krt_proto *p = (struct krt_proto *) P;
588
589 if (new && (!krt_capable(new) || new->attrs->source == RTS_INHERIT))
590 new = NULL;
591 if (!(net->n.flags & KRF_INSTALLED))
592 old = NULL;
593 if (new)
594 net->n.flags |= KRF_INSTALLED;
595 else
596 net->n.flags &= ~KRF_INSTALLED;
597 krt_set_notify(p, net, new, old);
598}
599
2d140452
MM
600/*
601 * Protocol glue
602 */
603
7e5f5ffd
MM
604struct proto_config *cf_krt;
605
2d140452
MM
606static int
607krt_start(struct proto *P)
608{
609 struct krt_proto *p = (struct krt_proto *) P;
610
c10421d3
MM
611#ifdef KRT_ALLOW_LEARN
612 krt_learn_init(p);
613#endif
614
2d140452
MM
615 krt_scan_start(p);
616 krt_set_start(p);
617
7e5f5ffd 618 /* Start periodic routing table scanning */
2d140452
MM
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);
625
626 return PS_UP;
627}
628
629int
630krt_shutdown(struct proto *P)
631{
632 struct krt_proto *p = (struct krt_proto *) P;
633
7e5f5ffd
MM
634 tm_stop(krt_scan_timer);
635
2d140452
MM
636 if (!KRT_CF->persist)
637 krt_flush_routes(p);
638
639 krt_set_shutdown(p);
640 krt_scan_shutdown(p);
641
2d140452
MM
642 return PS_DOWN;
643}
644
2d140452
MM
645static struct proto *
646krt_init(struct proto_config *c)
647{
648 struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
649
c10421d3 650 p->p.rt_notify = krt_notify;
2d140452
MM
651 return &p->p;
652}
653
654struct protocol proto_unix_kernel = {
655 name: "Kernel",
7e5f5ffd 656 priority: 80,
2d140452
MM
657 init: krt_init,
658 start: krt_start,
659 shutdown: krt_shutdown,
c10421d3
MM
660#ifdef KRT_ALLOW_LEARN
661 dump: krt_dump,
662 dump_attrs: krt_dump_attrs,
663#endif
2d140452 664};