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