]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/unix/krt.c
Protocol engine bug fixes:
[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);
08e2d625 131 net *nn = net_get(p->p.table, n->n.prefix, n->n.pxlen);
c10421d3
MM
132 ee->net = nn;
133 ee->pflags = 0;
134 ee->u.krt = e->u.krt;
4f1a6d27 135 rte_update(p->p.table, nn, &p->p, ee);
c10421d3
MM
136}
137
138static void
139krt_learn_announce_delete(struct krt_proto *p, net *n)
140{
08e2d625 141 n = net_find(p->p.table, n->n.prefix, n->n.pxlen);
c10421d3 142 if (n)
4f1a6d27 143 rte_update(p->p.table, n, &p->p, NULL);
c10421d3
MM
144}
145
146static void
147krt_learn_scan(struct krt_proto *p, rte *e)
148{
149 net *n0 = e->net;
08e2d625 150 net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
c10421d3
MM
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;
08e2d625 253 net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
c10421d3
MM
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{
4f1a6d27 359 struct rtable *t = p->p.table;
2d140452
MM
360
361 DBG("Flushing kernel routes...\n");
2d140452
MM
362 FIB_WALK(&t->fib, f)
363 {
364 net *n = (net *) f;
365 rte *e = n->routes;
366 if (e)
367 {
368 rta *a = e->attrs;
369 if (a->source != RTS_DEVICE && a->source != RTS_INHERIT)
c10421d3 370 krt_set_notify(p, e->net, NULL, e);
2d140452
MM
371 }
372 }
373 FIB_WALK_END;
374}
375
2d140452
MM
376/* FIXME: Synchronization of multiple routing tables? */
377
378static int
379krt_uptodate(rte *k, rte *e)
380{
381 rta *ka = k->attrs, *ea = e->attrs;
382
383 if (ka->dest != ea->dest)
384 return 0;
385 switch (ka->dest)
386 {
387 case RTD_ROUTER:
388 return ipa_equal(ka->gw, ea->gw);
389 case RTD_DEVICE:
390 return !strcmp(ka->iface->name, ea->iface->name);
391 default:
392 return 1;
393 }
394}
395
396/*
397 * This gets called back when the low-level scanning code discovers a route.
398 * We expect that the route is a temporary rte and its attributes are uncached.
399 */
400
401void
402krt_got_route(struct krt_proto *p, rte *e)
403{
404 rte *old;
405 net *net = e->net;
c10421d3 406 int src = e->u.krt.src;
2d140452
MM
407 int verdict;
408
c10421d3
MM
409#ifdef CONFIG_AUTO_ROUTES
410 if (e->attrs->dest == RTD_DEVICE)
411 {
412 /* It's a device route. Probably a kernel-generated one. */
413 verdict = KRF_IGNORE;
414 goto sentenced;
415 }
416#endif
417
418#ifdef KRT_ALLOW_LEARN
419 if (src == KRT_SRC_ALIEN)
420 {
421 if (KRT_CF->learn)
422 krt_learn_scan(p, e);
423 else
424 DBG("krt_parse_entry: Alien route, ignoring\n");
425 return;
426 }
427#endif
428
429 if (net->n.flags & KRF_VERDICT_MASK)
2d140452
MM
430 {
431 /* Route to this destination was already seen. Strange, but it happens... */
432 DBG("Already seen.\n");
433 return;
434 }
435
c10421d3 436 if (net->n.flags & KRF_INSTALLED)
2d140452 437 {
c10421d3
MM
438 old = net->routes;
439 ASSERT(old);
440 if (krt_uptodate(e, old))
2d140452
MM
441 verdict = KRF_SEEN;
442 else
443 verdict = KRF_UPDATE;
444 }
2d140452
MM
445 else
446 verdict = KRF_DELETE;
447
c10421d3
MM
448sentenced:
449 DBG("krt_parse_entry: verdict=%s\n", ((char *[]) { "CREATE", "SEEN", "UPDATE", "DELETE", "IGNORE" }) [verdict]);
2d140452 450
c10421d3
MM
451 net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
452 if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
2d140452
MM
453 {
454 /* Get a cached copy of attributes and link the route */
455 rta *a = e->attrs;
456 a->source = RTS_DUMMY;
457 e->attrs = rta_lookup(a);
458 e->next = net->routes;
459 net->routes = e;
460 }
461 else
462 rte_free(e);
463}
464
465static void
466krt_prune(struct krt_proto *p)
467{
468 struct proto *pp = &p->p;
4f1a6d27 469 struct rtable *t = p->p.table;
2d140452
MM
470 struct fib_node *f;
471
472 DBG("Pruning routes...\n");
2d140452
MM
473 FIB_WALK(&t->fib, f)
474 {
475 net *n = (net *) f;
c10421d3 476 int verdict = f->flags & KRF_VERDICT_MASK;
2d140452
MM
477 rte *new, *old;
478
c10421d3 479 if (verdict != KRF_CREATE && verdict != KRF_SEEN && verdict != KRF_IGNORE)
2d140452
MM
480 {
481 old = n->routes;
482 n->routes = old->next;
483 }
484 else
485 old = NULL;
486 new = n->routes;
487
488 switch (verdict)
489 {
490 case KRF_CREATE:
c10421d3 491 if (new && (f->flags & KRF_INSTALLED))
2d140452 492 {
c10421d3
MM
493 DBG("krt_prune: reinstalling %I/%d\n", n->n.prefix, n->n.pxlen);
494 krt_set_notify(p, n, new, NULL);
2d140452
MM
495 }
496 break;
497 case KRF_SEEN:
c10421d3 498 case KRF_IGNORE:
2d140452
MM
499 /* Nothing happens */
500 break;
501 case KRF_UPDATE:
502 DBG("krt_prune: updating %I/%d\n", n->n.prefix, n->n.pxlen);
c10421d3 503 krt_set_notify(p, n, new, old);
2d140452
MM
504 break;
505 case KRF_DELETE:
506 DBG("krt_prune: deleting %I/%d\n", n->n.prefix, n->n.pxlen);
c10421d3 507 krt_set_notify(p, n, NULL, old);
2d140452
MM
508 break;
509 default:
510 bug("krt_prune: invalid route status");
511 }
2d140452
MM
512 if (old)
513 rte_free(old);
c10421d3 514 f->flags &= ~KRF_VERDICT_MASK;
2d140452
MM
515 }
516 FIB_WALK_END;
c10421d3
MM
517
518#ifdef KRT_ALLOW_LEARN
519 if (KRT_CF->learn)
520 krt_learn_prune(p);
521#endif
2d140452
MM
522}
523
e16155ae
MM
524void
525krt_got_route_async(struct krt_proto *p, rte *e, int new)
526{
527 net *net = e->net;
528 rte *old = net->routes;
c10421d3 529 int src = e->u.krt.src;
e16155ae
MM
530
531 switch (src)
532 {
533 case KRT_SRC_BIRD:
534 ASSERT(0);
535 case KRT_SRC_REDIRECT:
536 DBG("It's a redirect, kill him! Kill! Kill!\n");
c10421d3 537 krt_set_notify(p, net, NULL, e);
e16155ae 538 break;
c10421d3
MM
539 case KRT_SRC_ALIEN:
540#ifdef KRT_ALLOW_LEARN
541 if (KRT_CF->learn)
e16155ae 542 {
c10421d3
MM
543 krt_learn_async(p, e, new);
544 return;
e16155ae 545 }
c10421d3
MM
546#endif
547 /* Fall-thru */
548 default:
549 DBG("Discarding\n");
4f1a6d27 550 rte_update(p->p.table, net, &p->p, NULL);
e16155ae 551 }
c10421d3 552 rte_free(e);
e16155ae
MM
553}
554
2d140452
MM
555/*
556 * Periodic scanning
557 */
558
559static timer *krt_scan_timer;
560
561static void
562krt_scan(timer *t)
563{
564 struct krt_proto *p = t->data;
565
7e5f5ffd
MM
566 kif_force_scan();
567 DBG("KRT: It's route scan time...\n");
568 krt_scan_fire(p);
569 krt_prune(p);
2d140452
MM
570}
571
c10421d3
MM
572/*
573 * Updates
574 */
575
576static void
bb027be1 577krt_notify(struct proto *P, net *net, rte *new, rte *old, struct ea_list *tmpa)
c10421d3
MM
578{
579 struct krt_proto *p = (struct krt_proto *) P;
580
581 if (new && (!krt_capable(new) || new->attrs->source == RTS_INHERIT))
582 new = NULL;
583 if (!(net->n.flags & KRF_INSTALLED))
584 old = NULL;
585 if (new)
586 net->n.flags |= KRF_INSTALLED;
587 else
588 net->n.flags &= ~KRF_INSTALLED;
589 krt_set_notify(p, net, new, old);
590}
591
2d140452
MM
592/*
593 * Protocol glue
594 */
595
7e5f5ffd
MM
596struct proto_config *cf_krt;
597
2d140452
MM
598static int
599krt_start(struct proto *P)
600{
601 struct krt_proto *p = (struct krt_proto *) P;
602
c10421d3
MM
603#ifdef KRT_ALLOW_LEARN
604 krt_learn_init(p);
605#endif
606
2d140452
MM
607 krt_scan_start(p);
608 krt_set_start(p);
609
7e5f5ffd 610 /* Start periodic routing table scanning */
2d140452
MM
611 krt_scan_timer = tm_new(P->pool);
612 krt_scan_timer->hook = krt_scan;
613 krt_scan_timer->data = p;
614 krt_scan_timer->recurrent = KRT_CF->scan_time;
615 krt_scan(krt_scan_timer);
616 tm_start(krt_scan_timer, KRT_CF->scan_time);
617
618 return PS_UP;
619}
620
621int
622krt_shutdown(struct proto *P)
623{
624 struct krt_proto *p = (struct krt_proto *) P;
625
7e5f5ffd
MM
626 tm_stop(krt_scan_timer);
627
2d140452
MM
628 if (!KRT_CF->persist)
629 krt_flush_routes(p);
630
631 krt_set_shutdown(p);
632 krt_scan_shutdown(p);
633
2d140452
MM
634 return PS_DOWN;
635}
636
2d140452
MM
637static struct proto *
638krt_init(struct proto_config *c)
639{
640 struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
641
c10421d3 642 p->p.rt_notify = krt_notify;
2d140452
MM
643 return &p->p;
644}
645
646struct protocol proto_unix_kernel = {
647 name: "Kernel",
7e5f5ffd 648 priority: 80,
2d140452
MM
649 init: krt_init,
650 start: krt_start,
651 shutdown: krt_shutdown,
c10421d3
MM
652#ifdef KRT_ALLOW_LEARN
653 dump: krt_dump,
654 dump_attrs: krt_dump_attrs,
655#endif
2d140452 656};