]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/unix/krt.c
Originate rt lsa before sending first dbdes.
[thirdparty/bird.git] / sysdep / unix / krt.c
CommitLineData
2d140452
MM
1/*
2 * BIRD -- UNIX Kernel Synchronization
3 *
50fe90ed 4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
2d140452
MM
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
73275d85
MM
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
2e9b2421 19 * to keep the overhead of our KRT business as low as possible and avoid maintaining
73275d85
MM
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]
2e9b2421 24 * or with many routing tables and separate KRT protocols for all of them
73275d85 25 * or with many routing tables, but every scan including all tables, so we start
2e9b2421 26 * separate KRT protocols which cooperate with each other [Linux 2.2].
73275d85
MM
27 * In this case, we keep only a single scan timer.
28 *
29 * We use FIB node flags to keep track of route synchronization status. We also
30 * attach temporary &rte's to the routing tables, but it cannot harm the rest of
31 * BIRD since table synchronization is an atomic process.
32 *
33 * When starting up, we cheat by looking if there is another
34 * KRT instance to be initialized later and performing table scan
35 * only once for all the instances.
36 */
37
38/*
39 * If you are brave enough, continue now. You cannot say you haven't been warned.
40 */
41
832fa033 42#undef LOCAL_DEBUG
2d140452
MM
43
44#include "nest/bird.h"
45#include "nest/iface.h"
46#include "nest/route.h"
47#include "nest/protocol.h"
48#include "lib/timer.h"
7de45ba4 49#include "conf/conf.h"
2d140452
MM
50
51#include "unix.h"
52#include "krt.h"
53
c10421d3
MM
54static int krt_uptodate(rte *k, rte *e);
55
7e5f5ffd
MM
56/*
57 * Global resources
58 */
59
7de45ba4
MM
60pool *krt_pool;
61
7e5f5ffd
MM
62void
63krt_io_init(void)
64{
7de45ba4 65 krt_pool = rp_new(&root_pool, "Kernel Syncer");
7e5f5ffd
MM
66 krt_if_io_init();
67}
68
69/*
70 * Interfaces
71 */
72
73struct proto_config *cf_kif;
74
75static struct kif_proto *kif_proto;
76static timer *kif_scan_timer;
77static bird_clock_t kif_last_shot;
78
50fe90ed
MM
79static void
80kif_preconfig(struct protocol *P, struct config *c)
81{
82 cf_kif = NULL;
83}
84
7e5f5ffd
MM
85static void
86kif_scan(timer *t)
87{
88 struct kif_proto *p = t->data;
89
832fa033 90 KRT_TRACE(p, D_EVENTS, "Scanning interfaces");
7e5f5ffd
MM
91 kif_last_shot = now;
92 krt_if_scan(p);
93}
94
95static void
96kif_force_scan(void)
97{
98 if (kif_proto && kif_last_shot + 2 < now)
99 {
100 kif_scan(kif_scan_timer);
101 tm_start(kif_scan_timer, ((struct kif_config *) kif_proto->p.cf)->scan_time);
102 }
103}
104
105static struct proto *
106kif_init(struct proto_config *c)
107{
108 struct kif_proto *p = proto_new(c, sizeof(struct kif_proto));
109 return &p->p;
110}
111
112static int
113kif_start(struct proto *P)
114{
115 struct kif_proto *p = (struct kif_proto *) P;
116
117 kif_proto = p;
118 krt_if_start(p);
119
120 /* Start periodic interface scanning */
121 kif_scan_timer = tm_new(P->pool);
122 kif_scan_timer->hook = kif_scan;
123 kif_scan_timer->data = p;
124 kif_scan_timer->recurrent = KIF_CF->scan_time;
125 kif_scan(kif_scan_timer);
126 tm_start(kif_scan_timer, KIF_CF->scan_time);
127
128 return PS_UP;
129}
130
131static int
132kif_shutdown(struct proto *P)
133{
134 struct kif_proto *p = (struct kif_proto *) P;
135
136 tm_stop(kif_scan_timer);
137 krt_if_shutdown(p);
138 kif_proto = NULL;
139
140 if_start_update(); /* Remove all interfaces */
141 if_end_update();
7de45ba4
MM
142 /*
143 * FIXME: Is it really a good idea? It causes routes to be flushed,
144 * but at the same time it avoids sending of these deletions to the kernel,
145 * because krt thinks the kernel itself has already removed the route
146 * when downing the interface. Sad.
147 */
7e5f5ffd
MM
148
149 return PS_DOWN;
150}
151
f7fcb752
MM
152static int
153kif_reconfigure(struct proto *p, struct proto_config *new)
154{
155 struct kif_config *o = (struct kif_config *) p->cf;
156 struct kif_config *n = (struct kif_config *) new;
157
158 if (!kif_params_same(&o->iface, &n->iface))
159 return 0;
160 if (o->scan_time != n->scan_time)
161 {
162 tm_stop(kif_scan_timer);
163 kif_scan_timer->recurrent = n->scan_time;
164 kif_scan(kif_scan_timer);
165 tm_start(kif_scan_timer, n->scan_time);
166 }
167 return 1;
168}
169
7e5f5ffd
MM
170struct protocol proto_unix_iface = {
171 name: "Device",
d272fe22 172 template: "device%d",
50fe90ed 173 preconfig: kif_preconfig,
7e5f5ffd
MM
174 init: kif_init,
175 start: kif_start,
176 shutdown: kif_shutdown,
f7fcb752 177 reconfigure: kif_reconfigure,
7e5f5ffd 178};
2d140452 179
832fa033
MM
180/*
181 * Tracing of routes
182 */
183
184static void
185krt_trace_in_print(struct krt_proto *p, rte *e, char *msg)
186{
187 DBG("KRT: %I/%d: %s\n", e->net->n.prefix, e->net->n.pxlen, msg);
188 log(L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg);
189}
190
191static inline void
192krt_trace_in(struct krt_proto *p, rte *e, char *msg)
193{
194 if (p->p.debug & D_PACKETS)
195 krt_trace_in_print(p, e, msg);
196}
197
c10421d3
MM
198/*
199 * Inherited Routes
200 */
201
202#ifdef KRT_ALLOW_LEARN
203
204static inline int
205krt_same_key(rte *a, rte *b)
206{
207 return a->u.krt.proto == b->u.krt.proto &&
208 a->u.krt.metric == b->u.krt.metric &&
209 a->u.krt.type == b->u.krt.type;
210}
211
212static void
213krt_learn_announce_update(struct krt_proto *p, rte *e)
214{
215 net *n = e->net;
216 rta *aa = rta_clone(e->attrs);
217 rte *ee = rte_get_temp(aa);
08e2d625 218 net *nn = net_get(p->p.table, n->n.prefix, n->n.pxlen);
c10421d3
MM
219 ee->net = nn;
220 ee->pflags = 0;
1151401e 221 ee->pref = p->p.preference;
c10421d3 222 ee->u.krt = e->u.krt;
4f1a6d27 223 rte_update(p->p.table, nn, &p->p, ee);
c10421d3
MM
224}
225
226static void
227krt_learn_announce_delete(struct krt_proto *p, net *n)
228{
08e2d625 229 n = net_find(p->p.table, n->n.prefix, n->n.pxlen);
c10421d3 230 if (n)
4f1a6d27 231 rte_update(p->p.table, n, &p->p, NULL);
c10421d3
MM
232}
233
234static void
235krt_learn_scan(struct krt_proto *p, rte *e)
236{
237 net *n0 = e->net;
08e2d625 238 net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
c10421d3
MM
239 rte *m, **mm;
240
241 e->attrs->source = RTS_INHERIT;
242
243 for(mm=&n->routes; m = *mm; mm=&m->next)
244 if (krt_same_key(m, e))
245 break;
246 if (m)
247 {
248 if (krt_uptodate(m, e))
249 {
832fa033 250 krt_trace_in(p, e, "[alien] seen");
c10421d3
MM
251 rte_free(e);
252 m->u.krt.seen = 1;
253 }
254 else
255 {
832fa033 256 krt_trace_in(p, e, "[alien] updated");
c10421d3
MM
257 *mm = m->next;
258 rte_free(m);
259 m = NULL;
260 }
261 }
262 else
832fa033 263 krt_trace_in(p, e, "[alien] created");
c10421d3
MM
264 if (!m)
265 {
266 e->attrs = rta_lookup(e->attrs);
267 e->next = n->routes;
268 n->routes = e;
269 e->u.krt.seen = 1;
270 }
271}
272
c10421d3
MM
273static void
274krt_learn_prune(struct krt_proto *p)
275{
276 struct fib *fib = &p->krt_table.fib;
277 struct fib_iterator fit;
278
832fa033 279 KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
c10421d3
MM
280
281 FIB_ITERATE_INIT(&fit, fib);
282again:
283 FIB_ITERATE_START(fib, &fit, f)
284 {
285 net *n = (net *) f;
286 rte *e, **ee, *best, **pbest, *old_best;
287
288 old_best = n->routes;
289 best = NULL;
290 pbest = NULL;
291 ee = &n->routes;
292 while (e = *ee)
293 {
294 if (!e->u.krt.seen)
295 {
296 *ee = e->next;
297 rte_free(e);
298 continue;
299 }
300 if (!best || best->u.krt.metric > e->u.krt.metric)
301 {
302 best = e;
303 pbest = ee;
304 }
305 e->u.krt.seen = 0;
306 ee = &e->next;
307 }
308 if (!n->routes)
309 {
310 DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
311 if (old_best)
312 {
313 krt_learn_announce_delete(p, n);
314 n->n.flags &= ~KRF_INSTALLED;
315 }
316 FIB_ITERATE_PUT(&fit, f);
317 fib_delete(fib, f);
318 goto again;
319 }
320 *pbest = best->next;
321 best->next = n->routes;
322 n->routes = best;
323 if (best != old_best || !(n->n.flags & KRF_INSTALLED))
324 {
325 DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
326 krt_learn_announce_update(p, best);
327 n->n.flags |= KRF_INSTALLED;
328 }
329 else
330 DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
331 }
332 FIB_ITERATE_END(f);
333}
334
335static void
336krt_learn_async(struct krt_proto *p, rte *e, int new)
337{
338 net *n0 = e->net;
08e2d625 339 net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
c10421d3
MM
340 rte *g, **gg, *best, **bestp, *old_best;
341
342 e->attrs->source = RTS_INHERIT;
343
344 old_best = n->routes;
345 for(gg=&n->routes; g = *gg; gg = &g->next)
346 if (krt_same_key(g, e))
347 break;
348 if (new)
349 {
350 if (g)
351 {
352 if (krt_uptodate(g, e))
353 {
832fa033 354 krt_trace_in(p, e, "[alien async] same");
c10421d3
MM
355 rte_free(e);
356 return;
357 }
832fa033 358 krt_trace_in(p, e, "[alien async] updated");
c10421d3
MM
359 *gg = g->next;
360 rte_free(g);
361 }
362 else
832fa033 363 krt_trace_in(p, e, "[alien async] created");
c10421d3
MM
364 e->attrs = rta_lookup(e->attrs);
365 e->next = n->routes;
366 n->routes = e;
367 }
368 else if (!g)
369 {
832fa033 370 krt_trace_in(p, e, "[alien async] delete failed");
c10421d3
MM
371 rte_free(e);
372 return;
373 }
374 else
375 {
832fa033 376 krt_trace_in(p, e, "[alien async] removed");
c10421d3
MM
377 *gg = g->next;
378 rte_free(e);
379 rte_free(g);
380 }
381 best = n->routes;
382 bestp = &n->routes;
383 for(gg=&n->routes; g=*gg; gg=&g->next)
384 if (best->u.krt.metric > g->u.krt.metric)
385 {
386 best = g;
387 bestp = gg;
388 }
389 if (best)
390 {
391 *bestp = best->next;
392 best->next = n->routes;
393 n->routes = best;
394 }
395 if (best != old_best)
396 {
397 DBG("krt_learn_async: distributing change\n");
398 if (best)
399 {
400 krt_learn_announce_update(p, best);
401 n->n.flags |= KRF_INSTALLED;
402 }
403 else
404 {
405 n->routes = NULL;
406 krt_learn_announce_delete(p, n);
407 n->n.flags &= ~KRF_INSTALLED;
408 }
409 }
410}
411
412static void
413krt_learn_init(struct krt_proto *p)
414{
415 if (KRT_CF->learn)
b9626ec6 416 rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL);
c10421d3
MM
417}
418
419static void
420krt_dump(struct proto *P)
421{
422 struct krt_proto *p = (struct krt_proto *) P;
423
424 if (!KRT_CF->learn)
425 return;
426 debug("KRT: Table of inheritable routes\n");
427 rt_dump(&p->krt_table);
428}
429
430static void
431krt_dump_attrs(rte *e)
432{
433 debug(" [m=%d,p=%d,t=%d]", e->u.krt.metric, e->u.krt.proto, e->u.krt.type);
434}
435
436#endif
437
2d140452
MM
438/*
439 * Routes
440 */
441
7de45ba4
MM
442#ifdef CONFIG_ALL_TABLES_AT_ONCE
443static timer *krt_scan_timer;
444static int krt_instance_count;
445static list krt_instance_list;
446#endif
447
2d140452
MM
448static void
449krt_flush_routes(struct krt_proto *p)
450{
4f1a6d27 451 struct rtable *t = p->p.table;
2d140452 452
832fa033 453 KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
2d140452
MM
454 FIB_WALK(&t->fib, f)
455 {
456 net *n = (net *) f;
457 rte *e = n->routes;
458 if (e)
459 {
460 rta *a = e->attrs;
461 if (a->source != RTS_DEVICE && a->source != RTS_INHERIT)
c10421d3 462 krt_set_notify(p, e->net, NULL, e);
2d140452
MM
463 }
464 }
465 FIB_WALK_END;
466}
467
2d140452
MM
468static int
469krt_uptodate(rte *k, rte *e)
470{
471 rta *ka = k->attrs, *ea = e->attrs;
472
473 if (ka->dest != ea->dest)
474 return 0;
475 switch (ka->dest)
476 {
477 case RTD_ROUTER:
478 return ipa_equal(ka->gw, ea->gw);
479 case RTD_DEVICE:
480 return !strcmp(ka->iface->name, ea->iface->name);
481 default:
482 return 1;
483 }
484}
485
486/*
487 * This gets called back when the low-level scanning code discovers a route.
488 * We expect that the route is a temporary rte and its attributes are uncached.
489 */
490
491void
492krt_got_route(struct krt_proto *p, rte *e)
493{
494 rte *old;
495 net *net = e->net;
c10421d3 496 int src = e->u.krt.src;
2d140452
MM
497 int verdict;
498
c10421d3
MM
499#ifdef CONFIG_AUTO_ROUTES
500 if (e->attrs->dest == RTD_DEVICE)
501 {
502 /* It's a device route. Probably a kernel-generated one. */
503 verdict = KRF_IGNORE;
504 goto sentenced;
505 }
506#endif
507
508#ifdef KRT_ALLOW_LEARN
509 if (src == KRT_SRC_ALIEN)
510 {
511 if (KRT_CF->learn)
512 krt_learn_scan(p, e);
513 else
832fa033 514 krt_trace_in(p, e, "alien route, ignored");
c10421d3
MM
515 return;
516 }
517#endif
518
519 if (net->n.flags & KRF_VERDICT_MASK)
2d140452
MM
520 {
521 /* Route to this destination was already seen. Strange, but it happens... */
832fa033 522 krt_trace_in(p, e, "already seen");
2d140452
MM
523 return;
524 }
525
c10421d3 526 if (net->n.flags & KRF_INSTALLED)
2d140452 527 {
c10421d3
MM
528 old = net->routes;
529 ASSERT(old);
530 if (krt_uptodate(e, old))
2d140452
MM
531 verdict = KRF_SEEN;
532 else
533 verdict = KRF_UPDATE;
534 }
2d140452
MM
535 else
536 verdict = KRF_DELETE;
537
c10421d3 538sentenced:
832fa033 539 krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]);
c10421d3
MM
540 net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
541 if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
2d140452
MM
542 {
543 /* Get a cached copy of attributes and link the route */
544 rta *a = e->attrs;
545 a->source = RTS_DUMMY;
546 e->attrs = rta_lookup(a);
547 e->next = net->routes;
548 net->routes = e;
549 }
550 else
551 rte_free(e);
552}
553
554static void
555krt_prune(struct krt_proto *p)
556{
4f1a6d27 557 struct rtable *t = p->p.table;
2d140452 558
832fa033 559 KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
2d140452
MM
560 FIB_WALK(&t->fib, f)
561 {
562 net *n = (net *) f;
c10421d3 563 int verdict = f->flags & KRF_VERDICT_MASK;
2d140452
MM
564 rte *new, *old;
565
c10421d3 566 if (verdict != KRF_CREATE && verdict != KRF_SEEN && verdict != KRF_IGNORE)
2d140452
MM
567 {
568 old = n->routes;
569 n->routes = old->next;
570 }
571 else
572 old = NULL;
573 new = n->routes;
574
575 switch (verdict)
576 {
577 case KRF_CREATE:
c10421d3 578 if (new && (f->flags & KRF_INSTALLED))
2d140452 579 {
832fa033 580 krt_trace_in(p, new, "reinstalling");
c10421d3 581 krt_set_notify(p, n, new, NULL);
2d140452
MM
582 }
583 break;
584 case KRF_SEEN:
c10421d3 585 case KRF_IGNORE:
2d140452
MM
586 /* Nothing happens */
587 break;
588 case KRF_UPDATE:
832fa033 589 krt_trace_in(p, new, "updating");
c10421d3 590 krt_set_notify(p, n, new, old);
2d140452
MM
591 break;
592 case KRF_DELETE:
1151401e 593 krt_trace_in(p, old, "deleting");
c10421d3 594 krt_set_notify(p, n, NULL, old);
2d140452
MM
595 break;
596 default:
597 bug("krt_prune: invalid route status");
598 }
2d140452
MM
599 if (old)
600 rte_free(old);
c10421d3 601 f->flags &= ~KRF_VERDICT_MASK;
2d140452
MM
602 }
603 FIB_WALK_END;
c10421d3
MM
604
605#ifdef KRT_ALLOW_LEARN
606 if (KRT_CF->learn)
607 krt_learn_prune(p);
608#endif
aa8761de 609 p->initialized = 1;
2d140452
MM
610}
611
e16155ae
MM
612void
613krt_got_route_async(struct krt_proto *p, rte *e, int new)
614{
615 net *net = e->net;
c10421d3 616 int src = e->u.krt.src;
e16155ae
MM
617
618 switch (src)
619 {
620 case KRT_SRC_BIRD:
832fa033 621 ASSERT(0); /* Should be filtered by the back end */
e16155ae
MM
622 case KRT_SRC_REDIRECT:
623 DBG("It's a redirect, kill him! Kill! Kill!\n");
c10421d3 624 krt_set_notify(p, net, NULL, e);
e16155ae 625 break;
c10421d3
MM
626 case KRT_SRC_ALIEN:
627#ifdef KRT_ALLOW_LEARN
628 if (KRT_CF->learn)
e16155ae 629 {
c10421d3
MM
630 krt_learn_async(p, e, new);
631 return;
e16155ae 632 }
c10421d3 633#endif
e16155ae 634 }
c10421d3 635 rte_free(e);
e16155ae
MM
636}
637
2d140452
MM
638/*
639 * Periodic scanning
640 */
641
2d140452
MM
642static void
643krt_scan(timer *t)
644{
7de45ba4 645 struct krt_proto *p;
2d140452 646
7e5f5ffd 647 kif_force_scan();
7de45ba4
MM
648#ifdef CONFIG_ALL_TABLES_AT_ONCE
649 {
650 void *q;
832fa033
MM
651 /* We need some node to decide whether to print the debug messages or not */
652 p = SKIP_BACK(struct krt_proto, instance_node, HEAD(krt_instance_list));
653 if (p->instance_node.next)
654 KRT_TRACE(p, D_EVENTS, "Scanning routing table");
7de45ba4
MM
655 krt_scan_fire(NULL);
656 WALK_LIST(q, krt_instance_list)
657 {
658 p = SKIP_BACK(struct krt_proto, instance_node, q);
659 krt_prune(p);
660 }
661 }
662#else
663 p = t->data;
832fa033 664 KRT_TRACE(p, D_EVENTS, "Scanning routing table");
7e5f5ffd
MM
665 krt_scan_fire(p);
666 krt_prune(p);
7de45ba4 667#endif
2d140452
MM
668}
669
c10421d3
MM
670/*
671 * Updates
672 */
673
674static void
02bd064a 675krt_notify(struct proto *P, net *net, rte *new, rte *old, struct ea_list *attrs)
c10421d3
MM
676{
677 struct krt_proto *p = (struct krt_proto *) P;
678
f990fc61
MM
679 if (shutting_down && KRT_CF->persist)
680 return;
c10421d3
MM
681 if (new && (!krt_capable(new) || new->attrs->source == RTS_INHERIT))
682 new = NULL;
683 if (!(net->n.flags & KRF_INSTALLED))
684 old = NULL;
685 if (new)
686 net->n.flags |= KRF_INSTALLED;
687 else
688 net->n.flags &= ~KRF_INSTALLED;
aa8761de
MM
689 if (p->initialized) /* Before first scan we don't touch the routes */
690 krt_set_notify(p, net, new, old);
c10421d3
MM
691}
692
2d140452
MM
693/*
694 * Protocol glue
695 */
696
7e5f5ffd
MM
697struct proto_config *cf_krt;
698
7de45ba4
MM
699static void
700krt_preconfig(struct protocol *P, struct config *c)
701{
50fe90ed 702 cf_krt = NULL;
7de45ba4
MM
703 krt_scan_preconfig(c);
704}
705
706static void
707krt_postconfig(struct proto_config *C)
708{
709 struct krt_config *c = (struct krt_config *) C;
710
711#ifdef CONFIG_ALL_TABLES_AT_ONCE
712 struct krt_config *first = (struct krt_config *) cf_krt;
713 if (first->scan_time != c->scan_time)
714 cf_error("All kernel syncers must use the same table scan interval");
715#endif
716
717 if (C->table->krt_attached)
718 cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name);
719 C->table->krt_attached = C;
720 krt_scan_postconfig(c);
721}
722
723static timer *
724krt_start_timer(struct krt_proto *p)
725{
726 timer *t;
727
728 t = tm_new(p->krt_pool);
729 t->hook = krt_scan;
730 t->data = p;
731 t->recurrent = KRT_CF->scan_time;
aa8761de 732 tm_start(t, 0);
7de45ba4
MM
733 return t;
734}
735
2d140452
MM
736static int
737krt_start(struct proto *P)
738{
739 struct krt_proto *p = (struct krt_proto *) P;
7de45ba4
MM
740 int first = 1;
741
742#ifdef CONFIG_ALL_TABLES_AT_ONCE
743 if (!krt_instance_count++)
744 init_list(&krt_instance_list);
745 else
746 first = 0;
747 p->krt_pool = krt_pool;
748 add_tail(&krt_instance_list, &p->instance_node);
749#else
750 p->krt_pool = P->pool;
751#endif
2d140452 752
c10421d3
MM
753#ifdef KRT_ALLOW_LEARN
754 krt_learn_init(p);
755#endif
756
7de45ba4
MM
757 krt_scan_start(p, first);
758 krt_set_start(p, first);
2d140452 759
7e5f5ffd 760 /* Start periodic routing table scanning */
7de45ba4
MM
761#ifdef CONFIG_ALL_TABLES_AT_ONCE
762 if (first)
763 krt_scan_timer = krt_start_timer(p);
aa8761de
MM
764 else
765 tm_start(p->scan_timer, 0);
7de45ba4 766 p->scan_timer = krt_scan_timer;
7de45ba4
MM
767#else
768 p->scan_timer = krt_start_timer(p);
7de45ba4 769#endif
2d140452
MM
770
771 return PS_UP;
772}
773
7de45ba4 774static int
2d140452
MM
775krt_shutdown(struct proto *P)
776{
777 struct krt_proto *p = (struct krt_proto *) P;
7de45ba4 778 int last = 1;
2d140452 779
7de45ba4
MM
780#ifdef CONFIG_ALL_TABLES_AT_ONCE
781 rem_node(&p->instance_node);
782 if (--krt_instance_count)
783 last = 0;
784 else
785#endif
786 tm_stop(p->scan_timer);
7e5f5ffd 787
2d140452
MM
788 if (!KRT_CF->persist)
789 krt_flush_routes(p);
790
7de45ba4
MM
791 krt_set_shutdown(p, last);
792 krt_scan_shutdown(p, last);
793
794#ifdef CONFIG_ALL_TABLES_AT_ONCE
795 if (last)
796 rfree(krt_scan_timer);
797#endif
2d140452 798
2d140452
MM
799 return PS_DOWN;
800}
801
2d140452
MM
802static struct proto *
803krt_init(struct proto_config *c)
804{
805 struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
806
c10421d3 807 p->p.rt_notify = krt_notify;
0da472d7 808 p->p.min_scope = SCOPE_HOST;
2d140452
MM
809 return &p->p;
810}
811
aa8761de
MM
812static int
813krt_reconfigure(struct proto *p, struct proto_config *new)
814{
815 struct krt_config *o = (struct krt_config *) p->cf;
816 struct krt_config *n = (struct krt_config *) new;
817
818 return o->scan_time == n->scan_time
819 && o->learn == n->learn /* persist needn't be the same */
820 && krt_set_params_same(&o->set, &n->set)
821 && krt_scan_params_same(&o->scan, &n->scan)
822 ;
823}
824
2d140452
MM
825struct protocol proto_unix_kernel = {
826 name: "Kernel",
d272fe22 827 template: "kernel%d",
7de45ba4
MM
828 preconfig: krt_preconfig,
829 postconfig: krt_postconfig,
2d140452
MM
830 init: krt_init,
831 start: krt_start,
832 shutdown: krt_shutdown,
aa8761de 833 reconfigure: krt_reconfigure,
c10421d3
MM
834#ifdef KRT_ALLOW_LEARN
835 dump: krt_dump,
836 dump_attrs: krt_dump_attrs,
837#endif
2d140452 838};