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