]> git.ipfire.org Git - thirdparty/bird.git/blob - sysdep/unix/krt.c
Added extra argument to rt_update hook which contains a pointer to the
[thirdparty/bird.git] / sysdep / unix / krt.c
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
20 static int krt_uptodate(rte *k, rte *e);
21
22 /*
23 * Global resources
24 */
25
26 void
27 krt_io_init(void)
28 {
29 krt_if_io_init();
30 }
31
32 /*
33 * Interfaces
34 */
35
36 struct proto_config *cf_kif;
37
38 static struct kif_proto *kif_proto;
39 static timer *kif_scan_timer;
40 static bird_clock_t kif_last_shot;
41
42 static void
43 kif_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
52 static void
53 kif_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
62 static struct proto *
63 kif_init(struct proto_config *c)
64 {
65 struct kif_proto *p = proto_new(c, sizeof(struct kif_proto));
66 return &p->p;
67 }
68
69 static int
70 kif_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
88 static int
89 kif_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
103 struct protocol proto_unix_iface = {
104 name: "Device",
105 priority: 100,
106 init: kif_init,
107 start: kif_start,
108 shutdown: kif_shutdown,
109 };
110
111 /*
112 * Inherited Routes
113 */
114
115 #ifdef KRT_ALLOW_LEARN
116
117 static inline int
118 krt_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
125 static void
126 krt_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, n->n.prefix, n->n.pxlen);
132 ee->net = nn;
133 ee->pflags = 0;
134 ee->u.krt = e->u.krt;
135 rte_update(p->p.table, nn, &p->p, ee);
136 }
137
138 static void
139 krt_learn_announce_delete(struct krt_proto *p, net *n)
140 {
141 n = net_find(p->p.table, n->n.prefix, n->n.pxlen);
142 if (n)
143 rte_update(p->p.table, n, &p->p, NULL);
144 }
145
146 static void
147 krt_learn_scan(struct krt_proto *p, rte *e)
148 {
149 net *n0 = e->net;
150 net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
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
187 static void
188 krt_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);
196 again:
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
249 static void
250 krt_learn_async(struct krt_proto *p, rte *e, int new)
251 {
252 net *n0 = e->net;
253 net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
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
326 static void
327 krt_learn_init(struct krt_proto *p)
328 {
329 if (KRT_CF->learn)
330 rt_setup(p->p.pool, &p->krt_table, "Inherited");
331 }
332
333 static void
334 krt_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
344 static void
345 krt_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
352 /*
353 * Routes
354 */
355
356 static void
357 krt_flush_routes(struct krt_proto *p)
358 {
359 struct rtable *t = p->p.table;
360
361 DBG("Flushing kernel routes...\n");
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)
370 krt_set_notify(p, e->net, NULL, e);
371 }
372 }
373 FIB_WALK_END;
374 }
375
376 /* FIXME: Synchronization of multiple routing tables? */
377
378 static int
379 krt_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
401 void
402 krt_got_route(struct krt_proto *p, rte *e)
403 {
404 rte *old;
405 net *net = e->net;
406 int src = e->u.krt.src;
407 int verdict;
408
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)
430 {
431 /* Route to this destination was already seen. Strange, but it happens... */
432 DBG("Already seen.\n");
433 return;
434 }
435
436 if (net->n.flags & KRF_INSTALLED)
437 {
438 old = net->routes;
439 ASSERT(old);
440 if (krt_uptodate(e, old))
441 verdict = KRF_SEEN;
442 else
443 verdict = KRF_UPDATE;
444 }
445 else
446 verdict = KRF_DELETE;
447
448 sentenced:
449 DBG("krt_parse_entry: verdict=%s\n", ((char *[]) { "CREATE", "SEEN", "UPDATE", "DELETE", "IGNORE" }) [verdict]);
450
451 net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
452 if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
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
465 static void
466 krt_prune(struct krt_proto *p)
467 {
468 struct proto *pp = &p->p;
469 struct rtable *t = p->p.table;
470 struct fib_node *f;
471
472 DBG("Pruning routes...\n");
473 FIB_WALK(&t->fib, f)
474 {
475 net *n = (net *) f;
476 int verdict = f->flags & KRF_VERDICT_MASK;
477 rte *new, *old;
478
479 if (verdict != KRF_CREATE && verdict != KRF_SEEN && verdict != KRF_IGNORE)
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:
491 if (new && (f->flags & KRF_INSTALLED))
492 {
493 DBG("krt_prune: reinstalling %I/%d\n", n->n.prefix, n->n.pxlen);
494 krt_set_notify(p, n, new, NULL);
495 }
496 break;
497 case KRF_SEEN:
498 case KRF_IGNORE:
499 /* Nothing happens */
500 break;
501 case KRF_UPDATE:
502 DBG("krt_prune: updating %I/%d\n", n->n.prefix, n->n.pxlen);
503 krt_set_notify(p, n, new, old);
504 break;
505 case KRF_DELETE:
506 DBG("krt_prune: deleting %I/%d\n", n->n.prefix, n->n.pxlen);
507 krt_set_notify(p, n, NULL, old);
508 break;
509 default:
510 bug("krt_prune: invalid route status");
511 }
512 if (old)
513 rte_free(old);
514 f->flags &= ~KRF_VERDICT_MASK;
515 }
516 FIB_WALK_END;
517
518 #ifdef KRT_ALLOW_LEARN
519 if (KRT_CF->learn)
520 krt_learn_prune(p);
521 #endif
522 }
523
524 void
525 krt_got_route_async(struct krt_proto *p, rte *e, int new)
526 {
527 net *net = e->net;
528 rte *old = net->routes;
529 int src = e->u.krt.src;
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");
537 krt_set_notify(p, net, NULL, e);
538 break;
539 case KRT_SRC_ALIEN:
540 #ifdef KRT_ALLOW_LEARN
541 if (KRT_CF->learn)
542 {
543 krt_learn_async(p, e, new);
544 return;
545 }
546 #endif
547 /* Fall-thru */
548 default:
549 DBG("Discarding\n");
550 rte_update(p->p.table, net, &p->p, NULL);
551 }
552 rte_free(e);
553 }
554
555 /*
556 * Periodic scanning
557 */
558
559 static timer *krt_scan_timer;
560
561 static void
562 krt_scan(timer *t)
563 {
564 struct krt_proto *p = t->data;
565
566 kif_force_scan();
567 DBG("KRT: It's route scan time...\n");
568 krt_scan_fire(p);
569 krt_prune(p);
570 }
571
572 /*
573 * Updates
574 */
575
576 static void
577 krt_notify(struct proto *P, net *net, rte *new, rte *old, struct ea_list *tmpa)
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
592 /*
593 * Protocol glue
594 */
595
596 struct proto_config *cf_krt;
597
598 static int
599 krt_start(struct proto *P)
600 {
601 struct krt_proto *p = (struct krt_proto *) P;
602
603 #ifdef KRT_ALLOW_LEARN
604 krt_learn_init(p);
605 #endif
606
607 krt_scan_start(p);
608 krt_set_start(p);
609
610 /* Start periodic routing table scanning */
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
621 int
622 krt_shutdown(struct proto *P)
623 {
624 struct krt_proto *p = (struct krt_proto *) P;
625
626 tm_stop(krt_scan_timer);
627
628 if (!KRT_CF->persist)
629 krt_flush_routes(p);
630
631 krt_set_shutdown(p);
632 krt_scan_shutdown(p);
633
634 return PS_DOWN;
635 }
636
637 static struct proto *
638 krt_init(struct proto_config *c)
639 {
640 struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
641
642 p->p.rt_notify = krt_notify;
643 return &p->p;
644 }
645
646 struct protocol proto_unix_kernel = {
647 name: "Kernel",
648 priority: 80,
649 init: krt_init,
650 start: krt_start,
651 shutdown: krt_shutdown,
652 #ifdef KRT_ALLOW_LEARN
653 dump: krt_dump,
654 dump_attrs: krt_dump_attrs,
655 #endif
656 };