]> git.ipfire.org Git - thirdparty/bird.git/blob - sysdep/unix/krt.c
Fixes missing check in reconfiguration.
[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 struct protocol proto_unix_iface = {
220 name: "Device",
221 template: "device%d",
222 preconfig: kif_preconfig,
223 init: kif_init,
224 start: kif_start,
225 shutdown: kif_shutdown,
226 reconfigure: kif_reconfigure,
227 };
228
229 /*
230 * Tracing of routes
231 */
232
233 static inline void
234 krt_trace_in(struct krt_proto *p, rte *e, char *msg)
235 {
236 if (p->p.debug & D_PACKETS)
237 log(L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg);
238 }
239
240 static inline void
241 krt_trace_in_rl(struct rate_limit *rl, struct krt_proto *p, rte *e, char *msg)
242 {
243 if (p->p.debug & D_PACKETS)
244 log_rl(rl, L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg);
245 }
246
247 /*
248 * Inherited Routes
249 */
250
251 #ifdef KRT_ALLOW_LEARN
252
253 static struct rate_limit rl_alien_seen, rl_alien_updated, rl_alien_created, rl_alien_ignored;
254
255 static inline int
256 krt_same_key(rte *a, rte *b)
257 {
258 return a->u.krt.proto == b->u.krt.proto &&
259 a->u.krt.metric == b->u.krt.metric &&
260 a->u.krt.type == b->u.krt.type;
261 }
262
263 static void
264 krt_learn_announce_update(struct krt_proto *p, rte *e)
265 {
266 net *n = e->net;
267 rta *aa = rta_clone(e->attrs);
268 rte *ee = rte_get_temp(aa);
269 net *nn = net_get(p->p.table, n->n.prefix, n->n.pxlen);
270 ee->net = nn;
271 ee->pflags = 0;
272 ee->pref = p->p.preference;
273 ee->u.krt = e->u.krt;
274 rte_update(p->p.table, nn, &p->p, &p->p, ee);
275 }
276
277 static void
278 krt_learn_announce_delete(struct krt_proto *p, net *n)
279 {
280 n = net_find(p->p.table, n->n.prefix, n->n.pxlen);
281 if (n)
282 rte_update(p->p.table, n, &p->p, &p->p, NULL);
283 }
284
285 static void
286 krt_learn_scan(struct krt_proto *p, rte *e)
287 {
288 net *n0 = e->net;
289 net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
290 rte *m, **mm;
291
292 e->attrs->source = RTS_INHERIT;
293
294 for(mm=&n->routes; m = *mm; mm=&m->next)
295 if (krt_same_key(m, e))
296 break;
297 if (m)
298 {
299 if (krt_uptodate(m, e))
300 {
301 krt_trace_in_rl(&rl_alien_seen, p, e, "[alien] seen");
302 rte_free(e);
303 m->u.krt.seen = 1;
304 }
305 else
306 {
307 krt_trace_in_rl(&rl_alien_updated, p, e, "[alien] updated");
308 *mm = m->next;
309 rte_free(m);
310 m = NULL;
311 }
312 }
313 else
314 krt_trace_in_rl(&rl_alien_created, p, e, "[alien] created");
315 if (!m)
316 {
317 e->attrs = rta_lookup(e->attrs);
318 e->next = n->routes;
319 n->routes = e;
320 e->u.krt.seen = 1;
321 }
322 }
323
324 static void
325 krt_learn_prune(struct krt_proto *p)
326 {
327 struct fib *fib = &p->krt_table.fib;
328 struct fib_iterator fit;
329
330 KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
331
332 FIB_ITERATE_INIT(&fit, fib);
333 again:
334 FIB_ITERATE_START(fib, &fit, f)
335 {
336 net *n = (net *) f;
337 rte *e, **ee, *best, **pbest, *old_best;
338
339 old_best = n->routes;
340 best = NULL;
341 pbest = NULL;
342 ee = &n->routes;
343 while (e = *ee)
344 {
345 if (!e->u.krt.seen)
346 {
347 *ee = e->next;
348 rte_free(e);
349 continue;
350 }
351 if (!best || best->u.krt.metric > e->u.krt.metric)
352 {
353 best = e;
354 pbest = ee;
355 }
356 e->u.krt.seen = 0;
357 ee = &e->next;
358 }
359 if (!n->routes)
360 {
361 DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
362 if (old_best)
363 {
364 krt_learn_announce_delete(p, n);
365 n->n.flags &= ~KRF_INSTALLED;
366 }
367 FIB_ITERATE_PUT(&fit, f);
368 fib_delete(fib, f);
369 goto again;
370 }
371 *pbest = best->next;
372 best->next = n->routes;
373 n->routes = best;
374 if (best != old_best || !(n->n.flags & KRF_INSTALLED))
375 {
376 DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
377 krt_learn_announce_update(p, best);
378 n->n.flags |= KRF_INSTALLED;
379 }
380 else
381 DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
382 }
383 FIB_ITERATE_END(f);
384 }
385
386 static void
387 krt_learn_async(struct krt_proto *p, rte *e, int new)
388 {
389 net *n0 = e->net;
390 net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
391 rte *g, **gg, *best, **bestp, *old_best;
392
393 e->attrs->source = RTS_INHERIT;
394
395 old_best = n->routes;
396 for(gg=&n->routes; g = *gg; gg = &g->next)
397 if (krt_same_key(g, e))
398 break;
399 if (new)
400 {
401 if (g)
402 {
403 if (krt_uptodate(g, e))
404 {
405 krt_trace_in(p, e, "[alien async] same");
406 rte_free(e);
407 return;
408 }
409 krt_trace_in(p, e, "[alien async] updated");
410 *gg = g->next;
411 rte_free(g);
412 }
413 else
414 krt_trace_in(p, e, "[alien async] created");
415 e->attrs = rta_lookup(e->attrs);
416 e->next = n->routes;
417 n->routes = e;
418 }
419 else if (!g)
420 {
421 krt_trace_in(p, e, "[alien async] delete failed");
422 rte_free(e);
423 return;
424 }
425 else
426 {
427 krt_trace_in(p, e, "[alien async] removed");
428 *gg = g->next;
429 rte_free(e);
430 rte_free(g);
431 }
432 best = n->routes;
433 bestp = &n->routes;
434 for(gg=&n->routes; g=*gg; gg=&g->next)
435 if (best->u.krt.metric > g->u.krt.metric)
436 {
437 best = g;
438 bestp = gg;
439 }
440 if (best)
441 {
442 *bestp = best->next;
443 best->next = n->routes;
444 n->routes = best;
445 }
446 if (best != old_best)
447 {
448 DBG("krt_learn_async: distributing change\n");
449 if (best)
450 {
451 krt_learn_announce_update(p, best);
452 n->n.flags |= KRF_INSTALLED;
453 }
454 else
455 {
456 n->routes = NULL;
457 krt_learn_announce_delete(p, n);
458 n->n.flags &= ~KRF_INSTALLED;
459 }
460 }
461 }
462
463 static void
464 krt_learn_init(struct krt_proto *p)
465 {
466 if (KRT_CF->learn)
467 rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL);
468 }
469
470 static void
471 krt_dump(struct proto *P)
472 {
473 struct krt_proto *p = (struct krt_proto *) P;
474
475 if (!KRT_CF->learn)
476 return;
477 debug("KRT: Table of inheritable routes\n");
478 rt_dump(&p->krt_table);
479 }
480
481 static void
482 krt_dump_attrs(rte *e)
483 {
484 debug(" [m=%d,p=%d,t=%d]", e->u.krt.metric, e->u.krt.proto, e->u.krt.type);
485 }
486
487 #endif
488
489 /*
490 * Routes
491 */
492
493 #ifdef CONFIG_ALL_TABLES_AT_ONCE
494 static timer *krt_scan_timer;
495 static int krt_instance_count;
496 static list krt_instance_list;
497 #endif
498
499 static void
500 krt_flush_routes(struct krt_proto *p)
501 {
502 struct rtable *t = p->p.table;
503
504 KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
505 FIB_WALK(&t->fib, f)
506 {
507 net *n = (net *) f;
508 rte *e = n->routes;
509 if (e)
510 {
511 rta *a = e->attrs;
512 if ((n->n.flags & KRF_INSTALLED) &&
513 a->source != RTS_DEVICE && a->source != RTS_INHERIT)
514 {
515 krt_set_notify(p, e->net, NULL, e);
516 n->n.flags &= ~KRF_INSTALLED;
517 }
518 }
519 }
520 FIB_WALK_END;
521 }
522
523 static int
524 krt_uptodate(rte *k, rte *e)
525 {
526 rta *ka = k->attrs, *ea = e->attrs;
527
528 if (ka->dest != ea->dest)
529 return 0;
530 switch (ka->dest)
531 {
532 case RTD_ROUTER:
533 return ipa_equal(ka->gw, ea->gw);
534 case RTD_DEVICE:
535 return !strcmp(ka->iface->name, ea->iface->name);
536 default:
537 return 1;
538 }
539 }
540
541 /*
542 * This gets called back when the low-level scanning code discovers a route.
543 * We expect that the route is a temporary rte and its attributes are uncached.
544 */
545
546 void
547 krt_got_route(struct krt_proto *p, rte *e)
548 {
549 rte *old;
550 net *net = e->net;
551 int verdict;
552
553 #ifdef KRT_ALLOW_LEARN
554 switch (e->u.krt.src)
555 {
556 case KRT_SRC_KERNEL:
557 verdict = KRF_IGNORE;
558 goto sentenced;
559
560 case KRT_SRC_REDIRECT:
561 verdict = KRF_DELETE;
562 goto sentenced;
563
564 case KRT_SRC_ALIEN:
565 if (KRT_CF->learn)
566 krt_learn_scan(p, e);
567 else
568 {
569 krt_trace_in_rl(&rl_alien_ignored, p, e, "[alien] ignored");
570 rte_free(e);
571 }
572 return;
573 }
574 #endif
575 /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
576
577 if (net->n.flags & KRF_VERDICT_MASK)
578 {
579 /* Route to this destination was already seen. Strange, but it happens... */
580 krt_trace_in(p, e, "already seen");
581 rte_free(e);
582 return;
583 }
584
585 if (net->n.flags & KRF_INSTALLED)
586 {
587 old = net->routes;
588 ASSERT(old);
589 if (krt_uptodate(e, old))
590 verdict = KRF_SEEN;
591 else
592 verdict = KRF_UPDATE;
593 }
594 else
595 verdict = KRF_DELETE;
596
597 sentenced:
598 krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]);
599 net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
600 if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
601 {
602 /* Get a cached copy of attributes and link the route */
603 rta *a = e->attrs;
604 a->source = RTS_DUMMY;
605 e->attrs = rta_lookup(a);
606 e->next = net->routes;
607 net->routes = e;
608 }
609 else
610 rte_free(e);
611 }
612
613 static void
614 krt_prune(struct krt_proto *p)
615 {
616 struct rtable *t = p->p.table;
617
618 KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
619 FIB_WALK(&t->fib, f)
620 {
621 net *n = (net *) f;
622 int verdict = f->flags & KRF_VERDICT_MASK;
623 rte *new, *old;
624
625 if (verdict != KRF_CREATE && verdict != KRF_SEEN && verdict != KRF_IGNORE)
626 {
627 old = n->routes;
628 n->routes = old->next;
629 }
630 else
631 old = NULL;
632 new = n->routes;
633
634 switch (verdict)
635 {
636 case KRF_CREATE:
637 if (new && (f->flags & KRF_INSTALLED))
638 {
639 krt_trace_in(p, new, "reinstalling");
640 krt_set_notify(p, n, new, NULL);
641 }
642 break;
643 case KRF_SEEN:
644 case KRF_IGNORE:
645 /* Nothing happens */
646 break;
647 case KRF_UPDATE:
648 krt_trace_in(p, new, "updating");
649 krt_set_notify(p, n, new, old);
650 break;
651 case KRF_DELETE:
652 krt_trace_in(p, old, "deleting");
653 krt_set_notify(p, n, NULL, old);
654 break;
655 default:
656 bug("krt_prune: invalid route status");
657 }
658 if (old)
659 rte_free(old);
660 f->flags &= ~KRF_VERDICT_MASK;
661 }
662 FIB_WALK_END;
663
664 #ifdef KRT_ALLOW_LEARN
665 if (KRT_CF->learn)
666 krt_learn_prune(p);
667 #endif
668 p->initialized = 1;
669 }
670
671 void
672 krt_got_route_async(struct krt_proto *p, rte *e, int new)
673 {
674 net *net = e->net;
675
676 switch (e->u.krt.src)
677 {
678 case KRT_SRC_BIRD:
679 ASSERT(0); /* Should be filtered by the back end */
680
681 case KRT_SRC_REDIRECT:
682 if (new)
683 {
684 krt_trace_in(p, e, "[redirect] deleting");
685 krt_set_notify(p, net, NULL, e);
686 }
687 /* If !new, it is probably echo of our deletion */
688 break;
689
690 #ifdef KRT_ALLOW_LEARN
691 case KRT_SRC_ALIEN:
692 if (KRT_CF->learn)
693 {
694 krt_learn_async(p, e, new);
695 return;
696 }
697 #endif
698 }
699 rte_free(e);
700 }
701
702 /*
703 * Periodic scanning
704 */
705
706 static void
707 krt_scan(timer *t UNUSED)
708 {
709 struct krt_proto *p;
710
711 kif_force_scan();
712 #ifdef CONFIG_ALL_TABLES_AT_ONCE
713 {
714 void *q;
715 /* We need some node to decide whether to print the debug messages or not */
716 p = SKIP_BACK(struct krt_proto, instance_node, HEAD(krt_instance_list));
717 if (p->instance_node.next)
718 KRT_TRACE(p, D_EVENTS, "Scanning routing table");
719 krt_scan_fire(NULL);
720 WALK_LIST(q, krt_instance_list)
721 {
722 p = SKIP_BACK(struct krt_proto, instance_node, q);
723 krt_prune(p);
724 }
725 }
726 #else
727 p = t->data;
728 KRT_TRACE(p, D_EVENTS, "Scanning routing table");
729 krt_scan_fire(p);
730 krt_prune(p);
731 #endif
732 }
733
734 /*
735 * Updates
736 */
737 static int
738 krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
739 {
740 struct krt_proto *p = (struct krt_proto *) P;
741 rte *e = *new;
742
743 if (e->attrs->proto == P)
744 return -1;
745
746 if (!KRT_CF->devroutes &&
747 (e->attrs->dest == RTD_DEVICE) &&
748 (e->attrs->source != RTS_STATIC_DEVICE))
749 return -1;
750
751 if (!krt_capable(e))
752 return -1;
753
754 return 0;
755 }
756
757 static void
758 krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
759 rte *new, rte *old, struct ea_list *attrs UNUSED)
760 {
761 struct krt_proto *p = (struct krt_proto *) P;
762
763 if (shutting_down)
764 return;
765 if (!(net->n.flags & KRF_INSTALLED))
766 old = NULL;
767 if (new)
768 net->n.flags |= KRF_INSTALLED;
769 else
770 net->n.flags &= ~KRF_INSTALLED;
771 if (p->initialized) /* Before first scan we don't touch the routes */
772 krt_set_notify(p, net, new, old);
773 }
774
775 /*
776 * Protocol glue
777 */
778
779 struct proto_config *cf_krt;
780
781 static void
782 krt_preconfig(struct protocol *P UNUSED, struct config *c)
783 {
784 cf_krt = NULL;
785 krt_scan_preconfig(c);
786 }
787
788 static void
789 krt_postconfig(struct proto_config *C)
790 {
791 struct krt_config *c = (struct krt_config *) C;
792
793 #ifdef CONFIG_ALL_TABLES_AT_ONCE
794 struct krt_config *first = (struct krt_config *) cf_krt;
795 if (first->scan_time != c->scan_time)
796 cf_error("All kernel syncers must use the same table scan interval");
797 #endif
798
799 if (C->table->krt_attached)
800 cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name);
801 C->table->krt_attached = C;
802 krt_scan_postconfig(c);
803 }
804
805 static timer *
806 krt_start_timer(struct krt_proto *p)
807 {
808 timer *t;
809
810 t = tm_new(p->krt_pool);
811 t->hook = krt_scan;
812 t->data = p;
813 t->recurrent = KRT_CF->scan_time;
814 tm_start(t, 0);
815 return t;
816 }
817
818 static int
819 krt_start(struct proto *P)
820 {
821 struct krt_proto *p = (struct krt_proto *) P;
822 int first = 1;
823
824 #ifdef CONFIG_ALL_TABLES_AT_ONCE
825 if (!krt_instance_count++)
826 init_list(&krt_instance_list);
827 else
828 first = 0;
829 p->krt_pool = krt_pool;
830 add_tail(&krt_instance_list, &p->instance_node);
831 #else
832 p->krt_pool = P->pool;
833 #endif
834
835 #ifdef KRT_ALLOW_LEARN
836 krt_learn_init(p);
837 #endif
838
839 krt_scan_start(p, first);
840 krt_set_start(p, first);
841
842 /* Start periodic routing table scanning */
843 #ifdef CONFIG_ALL_TABLES_AT_ONCE
844 if (first)
845 krt_scan_timer = krt_start_timer(p);
846 else
847 tm_start(krt_scan_timer, 0);
848 p->scan_timer = krt_scan_timer;
849 #else
850 p->scan_timer = krt_start_timer(p);
851 #endif
852
853 return PS_UP;
854 }
855
856 static int
857 krt_shutdown(struct proto *P)
858 {
859 struct krt_proto *p = (struct krt_proto *) P;
860 int last = 1;
861
862 #ifdef CONFIG_ALL_TABLES_AT_ONCE
863 rem_node(&p->instance_node);
864 if (--krt_instance_count)
865 last = 0;
866 else
867 #endif
868 tm_stop(p->scan_timer);
869
870 /* FIXME we should flush routes even when persist during reconfiguration */
871 if (p->initialized && !KRT_CF->persist)
872 krt_flush_routes(p);
873
874 krt_set_shutdown(p, last);
875 krt_scan_shutdown(p, last);
876
877 #ifdef CONFIG_ALL_TABLES_AT_ONCE
878 if (last)
879 rfree(krt_scan_timer);
880 #endif
881
882 return PS_DOWN;
883 }
884
885 static struct proto *
886 krt_init(struct proto_config *c)
887 {
888 struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
889
890 p->p.accept_ra_types = RA_OPTIMAL;
891 p->p.import_control = krt_import_control;
892 p->p.rt_notify = krt_notify;
893 return &p->p;
894 }
895
896 static int
897 krt_reconfigure(struct proto *p, struct proto_config *new)
898 {
899 struct krt_config *o = (struct krt_config *) p->cf;
900 struct krt_config *n = (struct krt_config *) new;
901
902 return o->scan_time == n->scan_time
903 && o->learn == n->learn /* persist needn't be the same */
904 && o->devroutes == n->devroutes
905 && krt_set_params_same(&o->set, &n->set)
906 && krt_scan_params_same(&o->scan, &n->scan)
907 ;
908 }
909
910 struct protocol proto_unix_kernel = {
911 name: "Kernel",
912 template: "kernel%d",
913 preconfig: krt_preconfig,
914 postconfig: krt_postconfig,
915 init: krt_init,
916 start: krt_start,
917 shutdown: krt_shutdown,
918 reconfigure: krt_reconfigure,
919 #ifdef KRT_ALLOW_LEARN
920 dump: krt_dump,
921 dump_attrs: krt_dump_attrs,
922 #endif
923 };