]> git.ipfire.org Git - thirdparty/bird.git/blob - sysdep/unix/krt.c
Implements protocol templates.
[thirdparty/bird.git] / sysdep / unix / krt.c
1 /*
2 * BIRD -- UNIX Kernel Synchronization
3 *
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 /**
10 * DOC: Kernel synchronization
11 *
12 * This system dependent module implements the Kernel and Device protocol,
13 * that is synchronization of interface lists and routing tables with the
14 * OS kernel.
15 *
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.
21 *
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 2.2].
27 * In this case, we keep only a single scan timer.
28 *
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
32 * an atomic process.
33 *
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.
37 */
38
39 /*
40 * If you are brave enough, continue now. You cannot say you haven't been warned.
41 */
42
43 #undef LOCAL_DEBUG
44
45 #include "nest/bird.h"
46 #include "nest/iface.h"
47 #include "nest/route.h"
48 #include "nest/protocol.h"
49 #include "lib/timer.h"
50 #include "conf/conf.h"
51 #include "lib/string.h"
52
53 #include "unix.h"
54 #include "krt.h"
55
56 static int krt_uptodate(rte *k, rte *e);
57
58 /*
59 * Global resources
60 */
61
62 pool *krt_pool;
63
64 void
65 krt_io_init(void)
66 {
67 krt_pool = rp_new(&root_pool, "Kernel Syncer");
68 krt_if_io_init();
69 }
70
71 /*
72 * Interfaces
73 */
74
75 struct proto_config *cf_kif;
76
77 static struct kif_proto *kif_proto;
78 static timer *kif_scan_timer;
79 static bird_clock_t kif_last_shot;
80
81 static void
82 kif_preconfig(struct protocol *P UNUSED, struct config *c UNUSED)
83 {
84 cf_kif = NULL;
85 }
86
87 static void
88 kif_scan(timer *t)
89 {
90 struct kif_proto *p = t->data;
91
92 KRT_TRACE(p, D_EVENTS, "Scanning interfaces");
93 kif_last_shot = now;
94 krt_if_scan(p);
95 }
96
97 static void
98 kif_force_scan(void)
99 {
100 if (kif_proto && kif_last_shot + 2 < now)
101 {
102 kif_scan(kif_scan_timer);
103 tm_start(kif_scan_timer, ((struct kif_config *) kif_proto->p.cf)->scan_time);
104 }
105 }
106
107 static struct proto *
108 kif_init(struct proto_config *c)
109 {
110 struct kif_proto *p = proto_new(c, sizeof(struct kif_proto));
111 return &p->p;
112 }
113
114 static int
115 kif_start(struct proto *P)
116 {
117 struct kif_proto *p = (struct kif_proto *) P;
118
119 kif_proto = p;
120 krt_if_start(p);
121
122 /* Start periodic interface scanning */
123 kif_scan_timer = tm_new(P->pool);
124 kif_scan_timer->hook = kif_scan;
125 kif_scan_timer->data = p;
126 kif_scan_timer->recurrent = KIF_CF->scan_time;
127 kif_scan(kif_scan_timer);
128 tm_start(kif_scan_timer, KIF_CF->scan_time);
129
130 return PS_UP;
131 }
132
133 static int
134 kif_shutdown(struct proto *P)
135 {
136 struct kif_proto *p = (struct kif_proto *) P;
137
138 tm_stop(kif_scan_timer);
139 krt_if_shutdown(p);
140 kif_proto = NULL;
141
142 return PS_DOWN;
143 }
144
145
146 static inline int
147 prefer_scope(struct ifa *a, struct ifa *b)
148 { return (a->scope > SCOPE_LINK) && (b->scope <= SCOPE_LINK); }
149
150 static inline int
151 prefer_addr(struct ifa *a, struct ifa *b)
152 { return ipa_compare(a->ip, b->ip) < 0; }
153
154 static inline struct ifa *
155 find_preferred_ifa(struct iface *i, ip_addr prefix, ip_addr mask)
156 {
157 struct ifa *a, *b = NULL;
158
159 WALK_LIST(a, i->addrs)
160 {
161 if (!(a->flags & IA_SECONDARY) &&
162 ipa_equal(ipa_and(a->ip, mask), prefix) &&
163 (!b || prefer_scope(a, b) || prefer_addr(a, b)))
164 b = a;
165 }
166
167 return b;
168 }
169
170 struct ifa *
171 kif_choose_primary(struct iface *i)
172 {
173 struct kif_config *cf = (struct kif_config *) (kif_proto->p.cf);
174 struct kif_primary_item *it;
175 struct ifa *a;
176
177 WALK_LIST(it, cf->primary)
178 {
179 if (!it->pattern || patmatch(it->pattern, i->name))
180 if (a = find_preferred_ifa(i, it->prefix, ipa_mkmask(it->pxlen)))
181 return a;
182 }
183
184 return find_preferred_ifa(i, IPA_NONE, IPA_NONE);
185 }
186
187
188 static int
189 kif_reconfigure(struct proto *p, struct proto_config *new)
190 {
191 struct kif_config *o = (struct kif_config *) p->cf;
192 struct kif_config *n = (struct kif_config *) new;
193
194 if (!kif_params_same(&o->iface, &n->iface))
195 return 0;
196
197 if (o->scan_time != n->scan_time)
198 {
199 tm_stop(kif_scan_timer);
200 kif_scan_timer->recurrent = n->scan_time;
201 kif_scan(kif_scan_timer);
202 tm_start(kif_scan_timer, n->scan_time);
203 }
204
205 if (!EMPTY_LIST(o->primary) || !EMPTY_LIST(n->primary))
206 {
207 /* This is hack, we have to update a configuration
208 * to the new value just now, because it is used
209 * for recalculation of primary addresses.
210 */
211 p->cf = new;
212
213 ifa_recalc_all_primary_addresses();
214 }
215
216 return 1;
217 }
218
219 static void
220 kif_copy_config(struct proto_config *dest, struct proto_config *src)
221 {
222 struct kif_config *d = (struct kif_config *) dest;
223 struct kif_config *s = (struct kif_config *) src;
224
225 /* Shallow copy of everything (just scan_time currently) */
226 proto_copy_rest(dest, src, sizeof(struct krt_config));
227
228 /* Copy primary addr list */
229 cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item));
230
231 /* Fix sysdep parts */
232 kif_copy_params(&d->iface, &s->iface);
233 }
234
235
236 struct protocol proto_unix_iface = {
237 name: "Device",
238 template: "device%d",
239 preconfig: kif_preconfig,
240 init: kif_init,
241 start: kif_start,
242 shutdown: kif_shutdown,
243 reconfigure: kif_reconfigure,
244 copy_config: kif_copy_config
245 };
246
247 /*
248 * Tracing of routes
249 */
250
251 static inline void
252 krt_trace_in(struct krt_proto *p, rte *e, char *msg)
253 {
254 if (p->p.debug & D_PACKETS)
255 log(L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg);
256 }
257
258 static inline void
259 krt_trace_in_rl(struct rate_limit *rl, struct krt_proto *p, rte *e, char *msg)
260 {
261 if (p->p.debug & D_PACKETS)
262 log_rl(rl, L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg);
263 }
264
265 /*
266 * Inherited Routes
267 */
268
269 #ifdef KRT_ALLOW_LEARN
270
271 static struct rate_limit rl_alien_seen, rl_alien_updated, rl_alien_created, rl_alien_ignored;
272
273 static inline int
274 krt_same_key(rte *a, rte *b)
275 {
276 return a->u.krt.proto == b->u.krt.proto &&
277 a->u.krt.metric == b->u.krt.metric &&
278 a->u.krt.type == b->u.krt.type;
279 }
280
281 static void
282 krt_learn_announce_update(struct krt_proto *p, rte *e)
283 {
284 net *n = e->net;
285 rta *aa = rta_clone(e->attrs);
286 rte *ee = rte_get_temp(aa);
287 net *nn = net_get(p->p.table, n->n.prefix, n->n.pxlen);
288 ee->net = nn;
289 ee->pflags = 0;
290 ee->pref = p->p.preference;
291 ee->u.krt = e->u.krt;
292 rte_update(p->p.table, nn, &p->p, &p->p, ee);
293 }
294
295 static void
296 krt_learn_announce_delete(struct krt_proto *p, net *n)
297 {
298 n = net_find(p->p.table, n->n.prefix, n->n.pxlen);
299 if (n)
300 rte_update(p->p.table, n, &p->p, &p->p, NULL);
301 }
302
303 static void
304 krt_learn_scan(struct krt_proto *p, rte *e)
305 {
306 net *n0 = e->net;
307 net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
308 rte *m, **mm;
309
310 e->attrs->source = RTS_INHERIT;
311
312 for(mm=&n->routes; m = *mm; mm=&m->next)
313 if (krt_same_key(m, e))
314 break;
315 if (m)
316 {
317 if (krt_uptodate(m, e))
318 {
319 krt_trace_in_rl(&rl_alien_seen, p, e, "[alien] seen");
320 rte_free(e);
321 m->u.krt.seen = 1;
322 }
323 else
324 {
325 krt_trace_in_rl(&rl_alien_updated, p, e, "[alien] updated");
326 *mm = m->next;
327 rte_free(m);
328 m = NULL;
329 }
330 }
331 else
332 krt_trace_in_rl(&rl_alien_created, p, e, "[alien] created");
333 if (!m)
334 {
335 e->attrs = rta_lookup(e->attrs);
336 e->next = n->routes;
337 n->routes = e;
338 e->u.krt.seen = 1;
339 }
340 }
341
342 static void
343 krt_learn_prune(struct krt_proto *p)
344 {
345 struct fib *fib = &p->krt_table.fib;
346 struct fib_iterator fit;
347
348 KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
349
350 FIB_ITERATE_INIT(&fit, fib);
351 again:
352 FIB_ITERATE_START(fib, &fit, f)
353 {
354 net *n = (net *) f;
355 rte *e, **ee, *best, **pbest, *old_best;
356
357 old_best = n->routes;
358 best = NULL;
359 pbest = NULL;
360 ee = &n->routes;
361 while (e = *ee)
362 {
363 if (!e->u.krt.seen)
364 {
365 *ee = e->next;
366 rte_free(e);
367 continue;
368 }
369 if (!best || best->u.krt.metric > e->u.krt.metric)
370 {
371 best = e;
372 pbest = ee;
373 }
374 e->u.krt.seen = 0;
375 ee = &e->next;
376 }
377 if (!n->routes)
378 {
379 DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
380 if (old_best)
381 {
382 krt_learn_announce_delete(p, n);
383 n->n.flags &= ~KRF_INSTALLED;
384 }
385 FIB_ITERATE_PUT(&fit, f);
386 fib_delete(fib, f);
387 goto again;
388 }
389 *pbest = best->next;
390 best->next = n->routes;
391 n->routes = best;
392 if (best != old_best || !(n->n.flags & KRF_INSTALLED))
393 {
394 DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
395 krt_learn_announce_update(p, best);
396 n->n.flags |= KRF_INSTALLED;
397 }
398 else
399 DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
400 }
401 FIB_ITERATE_END(f);
402 }
403
404 static void
405 krt_learn_async(struct krt_proto *p, rte *e, int new)
406 {
407 net *n0 = e->net;
408 net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
409 rte *g, **gg, *best, **bestp, *old_best;
410
411 e->attrs->source = RTS_INHERIT;
412
413 old_best = n->routes;
414 for(gg=&n->routes; g = *gg; gg = &g->next)
415 if (krt_same_key(g, e))
416 break;
417 if (new)
418 {
419 if (g)
420 {
421 if (krt_uptodate(g, e))
422 {
423 krt_trace_in(p, e, "[alien async] same");
424 rte_free(e);
425 return;
426 }
427 krt_trace_in(p, e, "[alien async] updated");
428 *gg = g->next;
429 rte_free(g);
430 }
431 else
432 krt_trace_in(p, e, "[alien async] created");
433 e->attrs = rta_lookup(e->attrs);
434 e->next = n->routes;
435 n->routes = e;
436 }
437 else if (!g)
438 {
439 krt_trace_in(p, e, "[alien async] delete failed");
440 rte_free(e);
441 return;
442 }
443 else
444 {
445 krt_trace_in(p, e, "[alien async] removed");
446 *gg = g->next;
447 rte_free(e);
448 rte_free(g);
449 }
450 best = n->routes;
451 bestp = &n->routes;
452 for(gg=&n->routes; g=*gg; gg=&g->next)
453 if (best->u.krt.metric > g->u.krt.metric)
454 {
455 best = g;
456 bestp = gg;
457 }
458 if (best)
459 {
460 *bestp = best->next;
461 best->next = n->routes;
462 n->routes = best;
463 }
464 if (best != old_best)
465 {
466 DBG("krt_learn_async: distributing change\n");
467 if (best)
468 {
469 krt_learn_announce_update(p, best);
470 n->n.flags |= KRF_INSTALLED;
471 }
472 else
473 {
474 n->routes = NULL;
475 krt_learn_announce_delete(p, n);
476 n->n.flags &= ~KRF_INSTALLED;
477 }
478 }
479 }
480
481 static void
482 krt_learn_init(struct krt_proto *p)
483 {
484 if (KRT_CF->learn)
485 rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL);
486 }
487
488 static void
489 krt_dump(struct proto *P)
490 {
491 struct krt_proto *p = (struct krt_proto *) P;
492
493 if (!KRT_CF->learn)
494 return;
495 debug("KRT: Table of inheritable routes\n");
496 rt_dump(&p->krt_table);
497 }
498
499 static void
500 krt_dump_attrs(rte *e)
501 {
502 debug(" [m=%d,p=%d,t=%d]", e->u.krt.metric, e->u.krt.proto, e->u.krt.type);
503 }
504
505 #endif
506
507 /*
508 * Routes
509 */
510
511 #ifdef CONFIG_ALL_TABLES_AT_ONCE
512 static timer *krt_scan_timer;
513 static int krt_instance_count;
514 static list krt_instance_list;
515 #endif
516
517 static void
518 krt_flush_routes(struct krt_proto *p)
519 {
520 struct rtable *t = p->p.table;
521
522 KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
523 FIB_WALK(&t->fib, f)
524 {
525 net *n = (net *) f;
526 rte *e = n->routes;
527 if (e)
528 {
529 rta *a = e->attrs;
530 if ((n->n.flags & KRF_INSTALLED) &&
531 a->source != RTS_DEVICE && a->source != RTS_INHERIT)
532 {
533 krt_set_notify(p, e->net, NULL, e);
534 n->n.flags &= ~KRF_INSTALLED;
535 }
536 }
537 }
538 FIB_WALK_END;
539 }
540
541 static int
542 krt_uptodate(rte *k, rte *e)
543 {
544 rta *ka = k->attrs, *ea = e->attrs;
545
546 if (ka->dest != ea->dest)
547 return 0;
548 switch (ka->dest)
549 {
550 case RTD_ROUTER:
551 return ipa_equal(ka->gw, ea->gw);
552 case RTD_DEVICE:
553 return !strcmp(ka->iface->name, ea->iface->name);
554 default:
555 return 1;
556 }
557 }
558
559 /*
560 * This gets called back when the low-level scanning code discovers a route.
561 * We expect that the route is a temporary rte and its attributes are uncached.
562 */
563
564 void
565 krt_got_route(struct krt_proto *p, rte *e)
566 {
567 rte *old;
568 net *net = e->net;
569 int verdict;
570
571 #ifdef KRT_ALLOW_LEARN
572 switch (e->u.krt.src)
573 {
574 case KRT_SRC_KERNEL:
575 verdict = KRF_IGNORE;
576 goto sentenced;
577
578 case KRT_SRC_REDIRECT:
579 verdict = KRF_DELETE;
580 goto sentenced;
581
582 case KRT_SRC_ALIEN:
583 if (KRT_CF->learn)
584 krt_learn_scan(p, e);
585 else
586 {
587 krt_trace_in_rl(&rl_alien_ignored, p, e, "[alien] ignored");
588 rte_free(e);
589 }
590 return;
591 }
592 #endif
593 /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
594
595 if (net->n.flags & KRF_VERDICT_MASK)
596 {
597 /* Route to this destination was already seen. Strange, but it happens... */
598 krt_trace_in(p, e, "already seen");
599 rte_free(e);
600 return;
601 }
602
603 if (net->n.flags & KRF_INSTALLED)
604 {
605 old = net->routes;
606 ASSERT(old);
607 if (krt_uptodate(e, old))
608 verdict = KRF_SEEN;
609 else
610 verdict = KRF_UPDATE;
611 }
612 else
613 verdict = KRF_DELETE;
614
615 sentenced:
616 krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]);
617 net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
618 if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
619 {
620 /* Get a cached copy of attributes and link the route */
621 rta *a = e->attrs;
622 a->source = RTS_DUMMY;
623 e->attrs = rta_lookup(a);
624 e->next = net->routes;
625 net->routes = e;
626 }
627 else
628 rte_free(e);
629 }
630
631 static void
632 krt_prune(struct krt_proto *p)
633 {
634 struct rtable *t = p->p.table;
635
636 KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
637 FIB_WALK(&t->fib, f)
638 {
639 net *n = (net *) f;
640 int verdict = f->flags & KRF_VERDICT_MASK;
641 rte *new, *old;
642
643 if (verdict != KRF_CREATE && verdict != KRF_SEEN && verdict != KRF_IGNORE)
644 {
645 old = n->routes;
646 n->routes = old->next;
647 }
648 else
649 old = NULL;
650 new = n->routes;
651
652 switch (verdict)
653 {
654 case KRF_CREATE:
655 if (new && (f->flags & KRF_INSTALLED))
656 {
657 krt_trace_in(p, new, "reinstalling");
658 krt_set_notify(p, n, new, NULL);
659 }
660 break;
661 case KRF_SEEN:
662 case KRF_IGNORE:
663 /* Nothing happens */
664 break;
665 case KRF_UPDATE:
666 krt_trace_in(p, new, "updating");
667 krt_set_notify(p, n, new, old);
668 break;
669 case KRF_DELETE:
670 krt_trace_in(p, old, "deleting");
671 krt_set_notify(p, n, NULL, old);
672 break;
673 default:
674 bug("krt_prune: invalid route status");
675 }
676 if (old)
677 rte_free(old);
678 f->flags &= ~KRF_VERDICT_MASK;
679 }
680 FIB_WALK_END;
681
682 #ifdef KRT_ALLOW_LEARN
683 if (KRT_CF->learn)
684 krt_learn_prune(p);
685 #endif
686 p->initialized = 1;
687 }
688
689 void
690 krt_got_route_async(struct krt_proto *p, rte *e, int new)
691 {
692 net *net = e->net;
693
694 switch (e->u.krt.src)
695 {
696 case KRT_SRC_BIRD:
697 ASSERT(0); /* Should be filtered by the back end */
698
699 case KRT_SRC_REDIRECT:
700 if (new)
701 {
702 krt_trace_in(p, e, "[redirect] deleting");
703 krt_set_notify(p, net, NULL, e);
704 }
705 /* If !new, it is probably echo of our deletion */
706 break;
707
708 #ifdef KRT_ALLOW_LEARN
709 case KRT_SRC_ALIEN:
710 if (KRT_CF->learn)
711 {
712 krt_learn_async(p, e, new);
713 return;
714 }
715 #endif
716 }
717 rte_free(e);
718 }
719
720 /*
721 * Periodic scanning
722 */
723
724 static void
725 krt_scan(timer *t UNUSED)
726 {
727 struct krt_proto *p;
728
729 kif_force_scan();
730 #ifdef CONFIG_ALL_TABLES_AT_ONCE
731 {
732 void *q;
733 /* We need some node to decide whether to print the debug messages or not */
734 p = SKIP_BACK(struct krt_proto, instance_node, HEAD(krt_instance_list));
735 if (p->instance_node.next)
736 KRT_TRACE(p, D_EVENTS, "Scanning routing table");
737 krt_scan_fire(NULL);
738 WALK_LIST(q, krt_instance_list)
739 {
740 p = SKIP_BACK(struct krt_proto, instance_node, q);
741 krt_prune(p);
742 }
743 }
744 #else
745 p = t->data;
746 KRT_TRACE(p, D_EVENTS, "Scanning routing table");
747 krt_scan_fire(p);
748 krt_prune(p);
749 #endif
750 }
751
752 /*
753 * Updates
754 */
755 static int
756 krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
757 {
758 struct krt_proto *p = (struct krt_proto *) P;
759 rte *e = *new;
760
761 if (e->attrs->proto == P)
762 return -1;
763
764 if (!KRT_CF->devroutes &&
765 (e->attrs->dest == RTD_DEVICE) &&
766 (e->attrs->source != RTS_STATIC_DEVICE))
767 return -1;
768
769 if (!krt_capable(e))
770 return -1;
771
772 return 0;
773 }
774
775 static void
776 krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
777 rte *new, rte *old, struct ea_list *attrs UNUSED)
778 {
779 struct krt_proto *p = (struct krt_proto *) P;
780
781 if (shutting_down)
782 return;
783 if (!(net->n.flags & KRF_INSTALLED))
784 old = NULL;
785 if (new)
786 net->n.flags |= KRF_INSTALLED;
787 else
788 net->n.flags &= ~KRF_INSTALLED;
789 if (p->initialized) /* Before first scan we don't touch the routes */
790 krt_set_notify(p, net, new, old);
791 }
792
793 /*
794 * Protocol glue
795 */
796
797 struct proto_config *cf_krt;
798
799 static void
800 krt_preconfig(struct protocol *P UNUSED, struct config *c)
801 {
802 cf_krt = NULL;
803 krt_scan_preconfig(c);
804 }
805
806 static void
807 krt_postconfig(struct proto_config *C)
808 {
809 struct krt_config *c = (struct krt_config *) C;
810
811 #ifdef CONFIG_ALL_TABLES_AT_ONCE
812 struct krt_config *first = (struct krt_config *) cf_krt;
813 if (first->scan_time != c->scan_time)
814 cf_error("All kernel syncers must use the same table scan interval");
815 #endif
816
817 if (C->table->krt_attached)
818 cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name);
819 C->table->krt_attached = C;
820 krt_scan_postconfig(c);
821 }
822
823 static timer *
824 krt_start_timer(struct krt_proto *p)
825 {
826 timer *t;
827
828 t = tm_new(p->krt_pool);
829 t->hook = krt_scan;
830 t->data = p;
831 t->recurrent = KRT_CF->scan_time;
832 tm_start(t, 0);
833 return t;
834 }
835
836 static int
837 krt_start(struct proto *P)
838 {
839 struct krt_proto *p = (struct krt_proto *) P;
840 int first = 1;
841
842 #ifdef CONFIG_ALL_TABLES_AT_ONCE
843 if (!krt_instance_count++)
844 init_list(&krt_instance_list);
845 else
846 first = 0;
847 p->krt_pool = krt_pool;
848 add_tail(&krt_instance_list, &p->instance_node);
849 #else
850 p->krt_pool = P->pool;
851 #endif
852
853 #ifdef KRT_ALLOW_LEARN
854 krt_learn_init(p);
855 #endif
856
857 krt_scan_start(p, first);
858 krt_set_start(p, first);
859
860 /* Start periodic routing table scanning */
861 #ifdef CONFIG_ALL_TABLES_AT_ONCE
862 if (first)
863 krt_scan_timer = krt_start_timer(p);
864 else
865 tm_start(krt_scan_timer, 0);
866 p->scan_timer = krt_scan_timer;
867 #else
868 p->scan_timer = krt_start_timer(p);
869 #endif
870
871 return PS_UP;
872 }
873
874 static int
875 krt_shutdown(struct proto *P)
876 {
877 struct krt_proto *p = (struct krt_proto *) P;
878 int last = 1;
879
880 #ifdef CONFIG_ALL_TABLES_AT_ONCE
881 rem_node(&p->instance_node);
882 if (--krt_instance_count)
883 last = 0;
884 else
885 #endif
886 tm_stop(p->scan_timer);
887
888 /* FIXME we should flush routes even when persist during reconfiguration */
889 if (p->initialized && !KRT_CF->persist)
890 krt_flush_routes(p);
891
892 krt_set_shutdown(p, last);
893 krt_scan_shutdown(p, last);
894
895 #ifdef CONFIG_ALL_TABLES_AT_ONCE
896 if (last)
897 rfree(krt_scan_timer);
898 #endif
899
900 return PS_DOWN;
901 }
902
903 static struct proto *
904 krt_init(struct proto_config *c)
905 {
906 struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
907
908 p->p.accept_ra_types = RA_OPTIMAL;
909 p->p.import_control = krt_import_control;
910 p->p.rt_notify = krt_notify;
911
912 return &p->p;
913 }
914
915 static int
916 krt_reconfigure(struct proto *p, struct proto_config *new)
917 {
918 struct krt_config *o = (struct krt_config *) p->cf;
919 struct krt_config *n = (struct krt_config *) new;
920
921 return o->scan_time == n->scan_time
922 && o->learn == n->learn /* persist needn't be the same */
923 && o->devroutes == n->devroutes
924 && krt_set_params_same(&o->set, &n->set)
925 && krt_scan_params_same(&o->scan, &n->scan)
926 ;
927 }
928
929 static void
930 krt_copy_config(struct proto_config *dest, struct proto_config *src)
931 {
932 struct krt_config *d = (struct krt_config *) dest;
933 struct krt_config *s = (struct krt_config *) src;
934
935 /* Shallow copy of everything */
936 proto_copy_rest(dest, src, sizeof(struct krt_config));
937
938 /* Fix sysdep parts */
939 krt_set_copy_params(&d->set, &s->set);
940 krt_scan_copy_params(&d->scan, &s->scan);
941 }
942
943 static int
944 krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
945 {
946 switch (a->id)
947 {
948 case EA_KRT_PREFSRC:
949 bsprintf(buf, "prefsrc");
950 return GA_NAME;
951 case EA_KRT_REALM:
952 bsprintf(buf, "realm");
953 return GA_NAME;
954 default:
955 return GA_UNKNOWN;
956 }
957 }
958
959
960 struct protocol proto_unix_kernel = {
961 name: "Kernel",
962 template: "kernel%d",
963 attr_class: EAP_KRT,
964 preconfig: krt_preconfig,
965 postconfig: krt_postconfig,
966 init: krt_init,
967 start: krt_start,
968 shutdown: krt_shutdown,
969 reconfigure: krt_reconfigure,
970 copy_config: krt_copy_config,
971 get_attr: krt_get_attr,
972 #ifdef KRT_ALLOW_LEARN
973 dump: krt_dump,
974 dump_attrs: krt_dump_attrs,
975 #endif
976 };