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