]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/unix/krt.c
Kernel: Do not check templates
[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
252c7e4d 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"
7de45ba4 59#include "conf/conf.h"
7d875e09 60#include "lib/string.h"
a6f79ca5 61#include "lib/timer.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;
c6964c30 72static list krt_proto_list;
7de45ba4 73
7e5f5ffd
MM
74void
75krt_io_init(void)
76{
7de45ba4 77 krt_pool = rp_new(&root_pool, "Kernel Syncer");
05d47bd5 78 krt_filter_lp = lp_new_default(krt_pool);
c6964c30 79 init_list(&krt_proto_list);
9ddbfbdd 80 krt_sys_io_init();
7e5f5ffd
MM
81}
82
83/*
84 * Interfaces
85 */
86
1e4891e4 87struct kif_proto *kif_proto;
396dfa90 88static struct kif_config *kif_cf;
7e5f5ffd 89static timer *kif_scan_timer;
21f4f0f4 90static btime kif_last_shot;
7e5f5ffd 91
153f02da
OZ
92static struct kif_iface_config kif_default_iface = {};
93
94struct kif_iface_config *
95kif_get_iface_config(struct iface *iface)
96{
97 struct kif_config *cf = (void *) (kif_proto->p.cf);
98 struct kif_iface_config *ic = (void *) iface_patt_find(&cf->iface_list, iface, NULL);
99 return ic ?: &kif_default_iface;
100}
101
7e5f5ffd
MM
102static void
103kif_scan(timer *t)
104{
105 struct kif_proto *p = t->data;
106
832fa033 107 KRT_TRACE(p, D_EVENTS, "Scanning interfaces");
21f4f0f4 108 kif_last_shot = current_time();
396dfa90 109 kif_do_scan(p);
7e5f5ffd
MM
110}
111
112static void
113kif_force_scan(void)
114{
21f4f0f4 115 if (kif_proto && ((kif_last_shot + 2 S) < current_time()))
7e5f5ffd
MM
116 {
117 kif_scan(kif_scan_timer);
a6f79ca5 118 tm_start(kif_scan_timer, ((struct kif_config *) kif_proto->p.cf)->scan_time);
7e5f5ffd
MM
119 }
120}
121
09686693
OZ
122void
123kif_request_scan(void)
124{
21f4f0f4 125 if (kif_proto && (kif_scan_timer->expires > (current_time() + 1 S)))
a6f79ca5 126 tm_start(kif_scan_timer, 1 S);
09686693
OZ
127}
128
396dfa90
OZ
129static struct proto *
130kif_init(struct proto_config *c)
131{
f4a60a9b 132 struct kif_proto *p = proto_new(c);
396dfa90
OZ
133
134 kif_sys_init(p);
135 return &p->p;
136}
137
138static int
139kif_start(struct proto *P)
140{
141 struct kif_proto *p = (struct kif_proto *) P;
142
143 kif_proto = p;
144 kif_sys_start(p);
145
146 /* Start periodic interface scanning */
a6f79ca5 147 kif_scan_timer = tm_new_init(P->pool, kif_scan, p, KIF_CF->scan_time, 0);
396dfa90 148 kif_scan(kif_scan_timer);
a6f79ca5 149 tm_start(kif_scan_timer, KIF_CF->scan_time);
396dfa90
OZ
150
151 return PS_UP;
152}
153
154static int
155kif_shutdown(struct proto *P)
156{
157 struct kif_proto *p = (struct kif_proto *) P;
158
a6f79ca5 159 tm_stop(kif_scan_timer);
396dfa90
OZ
160 kif_sys_shutdown(p);
161 kif_proto = NULL;
162
163 return PS_DOWN;
164}
165
f7fcb752
MM
166static int
167kif_reconfigure(struct proto *p, struct proto_config *new)
168{
169 struct kif_config *o = (struct kif_config *) p->cf;
170 struct kif_config *n = (struct kif_config *) new;
171
396dfa90 172 if (!kif_sys_reconfigure((struct kif_proto *) p, n, o))
f7fcb752 173 return 0;
874b8685 174
f7fcb752
MM
175 if (o->scan_time != n->scan_time)
176 {
a6f79ca5 177 tm_stop(kif_scan_timer);
21f4f0f4 178 kif_scan_timer->recurrent = n->scan_time;
f7fcb752 179 kif_scan(kif_scan_timer);
a6f79ca5 180 tm_start(kif_scan_timer, n->scan_time);
f7fcb752 181 }
874b8685 182
153f02da 183 if (!EMPTY_LIST(o->iface_list) || !EMPTY_LIST(n->iface_list))
874b8685
OZ
184 {
185 /* This is hack, we have to update a configuration
186 * to the new value just now, because it is used
153f02da 187 * for recalculation of preferred addresses.
874b8685
OZ
188 */
189 p->cf = new;
190
153f02da 191 if_recalc_all_preferred_addresses();
874b8685
OZ
192 }
193
f7fcb752
MM
194 return 1;
195}
196
396dfa90
OZ
197
198static void
199kif_preconfig(struct protocol *P UNUSED, struct config *c)
200{
201 kif_cf = NULL;
202 kif_sys_preconfig(c);
203}
204
205struct proto_config *
206kif_init_config(int class)
207{
208 if (kif_cf)
209 cf_error("Kernel device protocol already defined");
210
2bbc3083 211 kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, class);
21f4f0f4 212 kif_cf->scan_time = 60 S;
153f02da 213 init_list(&kif_cf->iface_list);
396dfa90
OZ
214
215 kif_sys_init_config(kif_cf);
216 return (struct proto_config *) kif_cf;
217}
218
a7f23f58
OZ
219static void
220kif_copy_config(struct proto_config *dest, struct proto_config *src)
221{
222 struct kif_config *d = (struct kif_config *) dest;
223 struct kif_config *s = (struct kif_config *) src;
224
153f02da
OZ
225 /* Copy interface config list */
226 cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct kif_iface_config));
a7f23f58
OZ
227
228 /* Fix sysdep parts */
396dfa90 229 kif_sys_copy_config(d, s);
a7f23f58
OZ
230}
231
7e5f5ffd 232struct protocol proto_unix_iface = {
4a591d4b
PT
233 .name = "Device",
234 .template = "device%d",
ee7e2ffd 235 .class = PROTOCOL_DEVICE,
f4a60a9b 236 .proto_size = sizeof(struct kif_proto),
2bbc3083 237 .config_size = sizeof(struct kif_config),
4a591d4b
PT
238 .preconfig = kif_preconfig,
239 .init = kif_init,
240 .start = kif_start,
241 .shutdown = kif_shutdown,
242 .reconfigure = kif_reconfigure,
243 .copy_config = kif_copy_config
7e5f5ffd 244};
2d140452 245
832fa033
MM
246/*
247 * Tracing of routes
248 */
249
cb530392
OZ
250static inline void
251krt_trace_in(struct krt_proto *p, rte *e, char *msg)
832fa033 252{
cb530392 253 if (p->p.debug & D_PACKETS)
fe9f1a6d 254 log(L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg);
832fa033
MM
255}
256
257static inline void
1123e707 258krt_trace_in_rl(struct tbf *f, struct krt_proto *p, rte *e, char *msg)
832fa033
MM
259{
260 if (p->p.debug & D_PACKETS)
fe9f1a6d 261 log_rl(f, L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg);
832fa033
MM
262}
263
c10421d3
MM
264/*
265 * Inherited Routes
266 */
267
268#ifdef KRT_ALLOW_LEARN
269
1123e707 270static struct tbf rl_alien = TBF_DEFAULT_LOG_LIMITS;
cb530392 271
c9df01d3
OZ
272/*
273 * krt_same_key() specifies what (aside from the net) is the key in
274 * kernel routing tables. It should be OS-dependent, this is for
275 * Linux. It is important for asynchronous alien updates, because a
276 * positive update is implicitly a negative one for any old route with
277 * the same key.
278 */
279
c10421d3
MM
280static inline int
281krt_same_key(rte *a, rte *b)
282{
c9df01d3
OZ
283 return a->u.krt.metric == b->u.krt.metric;
284}
285
286static inline int
287krt_uptodate(rte *a, rte *b)
288{
289 if (a->attrs != b->attrs)
290 return 0;
291
292 if (a->u.krt.proto != b->u.krt.proto)
293 return 0;
294
295 return 1;
c10421d3
MM
296}
297
298static void
299krt_learn_announce_update(struct krt_proto *p, rte *e)
300{
301 net *n = e->net;
302 rta *aa = rta_clone(e->attrs);
303 rte *ee = rte_get_temp(aa);
875cc073 304 ee->pflags = EA_ID_FLAG(EA_KRT_SOURCE) | EA_ID_FLAG(EA_KRT_METRIC);
c10421d3 305 ee->u.krt = e->u.krt;
2003a184 306 rte_update(&p->p, n->n.addr, ee);
c10421d3
MM
307}
308
309static void
310krt_learn_announce_delete(struct krt_proto *p, net *n)
311{
2003a184 312 rte_update(&p->p, n->n.addr, NULL);
c10421d3
MM
313}
314
c9df01d3 315/* Called when alien route is discovered during scan */
c10421d3
MM
316static void
317krt_learn_scan(struct krt_proto *p, rte *e)
318{
319 net *n0 = e->net;
fe9f1a6d 320 net *n = net_get(&p->krt_table, n0->n.addr);
c10421d3
MM
321 rte *m, **mm;
322
c9df01d3 323 e->attrs = rta_lookup(e->attrs);
c10421d3
MM
324
325 for(mm=&n->routes; m = *mm; mm=&m->next)
326 if (krt_same_key(m, e))
327 break;
328 if (m)
329 {
330 if (krt_uptodate(m, e))
331 {
1123e707 332 krt_trace_in_rl(&rl_alien, p, e, "[alien] seen");
c10421d3
MM
333 rte_free(e);
334 m->u.krt.seen = 1;
335 }
336 else
337 {
1123e707 338 krt_trace_in(p, e, "[alien] updated");
c10421d3
MM
339 *mm = m->next;
340 rte_free(m);
341 m = NULL;
342 }
343 }
344 else
1123e707 345 krt_trace_in(p, e, "[alien] created");
c10421d3
MM
346 if (!m)
347 {
c10421d3
MM
348 e->next = n->routes;
349 n->routes = e;
350 e->u.krt.seen = 1;
351 }
352}
353
c10421d3
MM
354static void
355krt_learn_prune(struct krt_proto *p)
356{
357 struct fib *fib = &p->krt_table.fib;
358 struct fib_iterator fit;
359
832fa033 360 KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
c10421d3
MM
361
362 FIB_ITERATE_INIT(&fit, fib);
363again:
600998fc 364 FIB_ITERATE_START(fib, &fit, net, n)
c10421d3 365 {
c10421d3
MM
366 rte *e, **ee, *best, **pbest, *old_best;
367
e86cfd41
OZ
368 /*
369 * Note that old_best may be NULL even if there was an old best route in
370 * the previous step, because it might be replaced in krt_learn_scan().
371 * But in that case there is a new valid best route.
372 */
373
374 old_best = NULL;
c10421d3
MM
375 best = NULL;
376 pbest = NULL;
377 ee = &n->routes;
378 while (e = *ee)
379 {
e86cfd41
OZ
380 if (e->u.krt.best)
381 old_best = e;
382
c10421d3
MM
383 if (!e->u.krt.seen)
384 {
385 *ee = e->next;
386 rte_free(e);
387 continue;
388 }
e86cfd41 389
c10421d3
MM
390 if (!best || best->u.krt.metric > e->u.krt.metric)
391 {
392 best = e;
393 pbest = ee;
394 }
e86cfd41 395
c10421d3 396 e->u.krt.seen = 0;
e86cfd41 397 e->u.krt.best = 0;
c10421d3
MM
398 ee = &e->next;
399 }
400 if (!n->routes)
401 {
402 DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
403 if (old_best)
e86cfd41
OZ
404 krt_learn_announce_delete(p, n);
405
600998fc
OZ
406 FIB_ITERATE_PUT(&fit);
407 fib_delete(fib, n);
c10421d3
MM
408 goto again;
409 }
e86cfd41
OZ
410
411 best->u.krt.best = 1;
c10421d3
MM
412 *pbest = best->next;
413 best->next = n->routes;
414 n->routes = best;
e86cfd41
OZ
415
416 if ((best != old_best) || p->reload)
c10421d3
MM
417 {
418 DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
419 krt_learn_announce_update(p, best);
c10421d3
MM
420 }
421 else
422 DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
423 }
600998fc 424 FIB_ITERATE_END;
7069fc9e
OZ
425
426 p->reload = 0;
c10421d3
MM
427}
428
429static void
430krt_learn_async(struct krt_proto *p, rte *e, int new)
431{
432 net *n0 = e->net;
fe9f1a6d 433 net *n = net_get(&p->krt_table, n0->n.addr);
c10421d3
MM
434 rte *g, **gg, *best, **bestp, *old_best;
435
c9df01d3 436 e->attrs = rta_lookup(e->attrs);
c10421d3
MM
437
438 old_best = n->routes;
439 for(gg=&n->routes; g = *gg; gg = &g->next)
440 if (krt_same_key(g, e))
441 break;
442 if (new)
443 {
444 if (g)
445 {
446 if (krt_uptodate(g, e))
447 {
832fa033 448 krt_trace_in(p, e, "[alien async] same");
c10421d3
MM
449 rte_free(e);
450 return;
451 }
832fa033 452 krt_trace_in(p, e, "[alien async] updated");
c10421d3
MM
453 *gg = g->next;
454 rte_free(g);
455 }
456 else
832fa033 457 krt_trace_in(p, e, "[alien async] created");
c9df01d3 458
c10421d3
MM
459 e->next = n->routes;
460 n->routes = e;
461 }
462 else if (!g)
463 {
832fa033 464 krt_trace_in(p, e, "[alien async] delete failed");
c10421d3
MM
465 rte_free(e);
466 return;
467 }
468 else
469 {
832fa033 470 krt_trace_in(p, e, "[alien async] removed");
c10421d3
MM
471 *gg = g->next;
472 rte_free(e);
473 rte_free(g);
474 }
475 best = n->routes;
476 bestp = &n->routes;
477 for(gg=&n->routes; g=*gg; gg=&g->next)
e86cfd41 478 {
c10421d3
MM
479 if (best->u.krt.metric > g->u.krt.metric)
480 {
481 best = g;
482 bestp = gg;
483 }
e86cfd41
OZ
484
485 g->u.krt.best = 0;
486 }
487
c10421d3
MM
488 if (best)
489 {
e86cfd41 490 best->u.krt.best = 1;
c10421d3
MM
491 *bestp = best->next;
492 best->next = n->routes;
493 n->routes = best;
494 }
e86cfd41 495
c10421d3
MM
496 if (best != old_best)
497 {
498 DBG("krt_learn_async: distributing change\n");
499 if (best)
e86cfd41 500 krt_learn_announce_update(p, best);
c10421d3 501 else
e86cfd41 502 krt_learn_announce_delete(p, n);
c10421d3
MM
503 }
504}
505
506static void
507krt_learn_init(struct krt_proto *p)
508{
509 if (KRT_CF->learn)
28b3b551
OZ
510 {
511 struct rtable_config *cf = mb_allocz(p->p.pool, sizeof(struct rtable_config));
512 cf->name = "Inherited";
513 cf->addr_type = p->p.net_type;
514
515 rt_setup(p->p.pool, &p->krt_table, cf);
516 }
c10421d3
MM
517}
518
519static void
520krt_dump(struct proto *P)
521{
522 struct krt_proto *p = (struct krt_proto *) P;
523
524 if (!KRT_CF->learn)
525 return;
526 debug("KRT: Table of inheritable routes\n");
527 rt_dump(&p->krt_table);
528}
529
530static void
531krt_dump_attrs(rte *e)
532{
e86cfd41 533 debug(" [m=%d,p=%d]", e->u.krt.metric, e->u.krt.proto);
c10421d3
MM
534}
535
536#endif
537
2d140452
MM
538/*
539 * Routes
540 */
541
c132acae 542static inline int
90a9c97e 543krt_is_installed(struct krt_proto *p, net *n)
c132acae 544{
90a9c97e 545 return n->routes && bmap_test(&p->p.main_channel->export_map, n->routes->id);
c132acae
OZ
546}
547
2d140452
MM
548static void
549krt_flush_routes(struct krt_proto *p)
550{
f4a60a9b 551 struct rtable *t = p->p.main_channel->table;
2d140452 552
832fa033 553 KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
600998fc 554 FIB_WALK(&t->fib, net, n)
2d140452 555 {
90a9c97e 556 if (krt_is_installed(p, n))
2d140452 557 {
e14bd380 558 /* FIXME: this does not work if gw is changed in export filter */
90a9c97e 559 krt_replace_rte(p, n, NULL, n->routes);
2d140452
MM
560 }
561 }
562 FIB_WALK_END;
563}
564
78a2cc28 565static struct rte *
13c0be19 566krt_export_net(struct krt_proto *p, net *net, rte **rt_free)
78a2cc28 567{
f4a60a9b 568 struct channel *c = p->p.main_channel;
0b39b1cb 569 const struct filter *filter = c->out_filter;
78a2cc28
OZ
570 rte *rt;
571
f4a60a9b 572 if (c->ra_mode == RA_MERGED)
13c0be19 573 return rt_export_merged(c, net, rt_free, krt_filter_lp, 1);
8d9eef17 574
78a2cc28
OZ
575 rt = net->routes;
576 *rt_free = NULL;
577
578 if (!rte_is_valid(rt))
579 return NULL;
580
581 if (filter == FILTER_REJECT)
582 return NULL;
583
875cc073 584 rte_make_tmp_attrs(&rt, krt_filter_lp, NULL);
78a2cc28 585
c132acae 586 /* We could run krt_preexport() here, but it is already handled by krt_is_installed() */
78a2cc28
OZ
587
588 if (filter == FILTER_ACCEPT)
589 goto accept;
590
13c0be19 591 if (f_run(filter, &rt, krt_filter_lp, FF_SILENT) > F_ACCEPT)
78a2cc28
OZ
592 goto reject;
593
594
595accept:
596 if (rt != net->routes)
597 *rt_free = rt;
598 return rt;
599
600reject:
601 if (rt != net->routes)
602 rte_free(rt);
603 return NULL;
604}
605
2d140452 606static int
c9df01d3 607krt_same_dest(rte *k, rte *e)
2d140452
MM
608{
609 rta *ka = k->attrs, *ea = e->attrs;
610
611 if (ka->dest != ea->dest)
612 return 0;
4e276a89
JMM
613
614 if (ka->dest == RTD_UNICAST)
615 return nexthop_same(&(ka->nh), &(ea->nh));
616
617 return 1;
2d140452
MM
618}
619
620/*
621 * This gets called back when the low-level scanning code discovers a route.
622 * We expect that the route is a temporary rte and its attributes are uncached.
623 */
624
625void
626krt_got_route(struct krt_proto *p, rte *e)
627{
7d767c5a
OZ
628 rte *new = NULL, *rt_free = NULL;
629 net *n = e->net;
2d140452 630
ff2857b0
OZ
631#ifdef KRT_ALLOW_LEARN
632 switch (e->u.krt.src)
c10421d3 633 {
ff2857b0 634 case KRT_SRC_KERNEL:
7d767c5a 635 goto ignore;
c10421d3 636
ff2857b0 637 case KRT_SRC_REDIRECT:
7d767c5a 638 goto delete;
ff2857b0
OZ
639
640 case KRT_SRC_ALIEN:
c10421d3
MM
641 if (KRT_CF->learn)
642 krt_learn_scan(p, e);
643 else
c197d44e 644 {
1123e707 645 krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored");
c197d44e
MM
646 rte_free(e);
647 }
c10421d3
MM
648 return;
649 }
650#endif
ff2857b0 651 /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
c10421d3 652
2d140452 653
7d767c5a 654 /* We wait for the initial feed to have correct installed state */
0c791f87 655 if (!p->ready)
7d767c5a 656 goto ignore;
0c791f87 657
7d767c5a
OZ
658 if (!krt_is_installed(p, n))
659 goto delete;
78a2cc28 660
7d767c5a 661 new = krt_export_net(p, n, &rt_free);
78a2cc28 662
7d767c5a
OZ
663 /* Rejected by filters */
664 if (!new)
665 goto delete;
78a2cc28 666
7d767c5a
OZ
667 /* Route to this destination was already seen. Strange, but it happens... */
668 if (bmap_test(&p->seen_map, new->id))
669 goto aseen;
78a2cc28 670
7d767c5a
OZ
671 /* Mark route as seen */
672 bmap_set(&p->seen_map, new->id);
78a2cc28 673
7d767c5a
OZ
674 /* TODO: There also may be changes in route eattrs, we ignore that for now. */
675 if (!bmap_test(&p->sync_map, new->id) || !krt_same_dest(e, new))
676 goto update;
2d140452 677
7d767c5a
OZ
678 goto seen;
679
680seen:
681 krt_trace_in(p, e, "seen");
682 goto done;
683
684aseen:
685 krt_trace_in(p, e, "already seen");
686 goto done;
687
688ignore:
689 krt_trace_in(p, e, "ignored");
690 goto done;
691
692update:
693 krt_trace_in(p, new, "updating");
694 krt_replace_rte(p, n, new, e);
695 goto done;
696
697delete:
698 krt_trace_in(p, e, "deleting");
699 krt_replace_rte(p, n, NULL, e);
700 goto done;
701
702done:
703 rte_free(e);
704
705 if (rt_free)
706 rte_free(rt_free);
707
708 lp_flush(krt_filter_lp);
709}
710
711static void
712krt_init_scan(struct krt_proto *p)
713{
714 bmap_reset(&p->seen_map, 1024);
2d140452
MM
715}
716
717static void
718krt_prune(struct krt_proto *p)
719{
f4a60a9b 720 struct rtable *t = p->p.main_channel->table;
2d140452 721
832fa033 722 KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
600998fc 723 FIB_WALK(&t->fib, net, n)
7d767c5a
OZ
724 {
725 if (p->ready && krt_is_installed(p, n) && !bmap_test(&p->seen_map, n->routes->id))
2d140452 726 {
7d767c5a
OZ
727 rte *rt_free = NULL;
728 rte *new = krt_export_net(p, n, &rt_free);
2d140452 729
7d767c5a
OZ
730 if (new)
731 {
732 krt_trace_in(p, new, "installing");
733 krt_replace_rte(p, n, new, NULL);
734 }
c9df01d3 735
78a2cc28
OZ
736 if (rt_free)
737 rte_free(rt_free);
7d767c5a 738
c9df01d3 739 lp_flush(krt_filter_lp);
2d140452 740 }
7d767c5a 741 }
2d140452 742 FIB_WALK_END;
c10421d3
MM
743
744#ifdef KRT_ALLOW_LEARN
745 if (KRT_CF->learn)
746 krt_learn_prune(p);
747#endif
0c791f87
OZ
748
749 if (p->ready)
750 p->initialized = 1;
2d140452
MM
751}
752
e16155ae 753void
ff2857b0 754krt_got_route_async(struct krt_proto *p, rte *e, int new)
e16155ae
MM
755{
756 net *net = e->net;
e16155ae 757
ff2857b0 758 switch (e->u.krt.src)
e16155ae
MM
759 {
760 case KRT_SRC_BIRD:
d4cebc6b
JMM
761 /* Should be filtered by the back end */
762 bug("BIRD originated routes should not get here.");
ff2857b0 763
e16155ae 764 case KRT_SRC_REDIRECT:
ff2857b0
OZ
765 if (new)
766 {
767 krt_trace_in(p, e, "[redirect] deleting");
13c0be19 768 krt_replace_rte(p, net, NULL, e);
ff2857b0
OZ
769 }
770 /* If !new, it is probably echo of our deletion */
e16155ae 771 break;
ff2857b0 772
c10421d3 773#ifdef KRT_ALLOW_LEARN
1bc4b2cc 774 case KRT_SRC_ALIEN:
c10421d3 775 if (KRT_CF->learn)
e16155ae 776 {
c10421d3
MM
777 krt_learn_async(p, e, new);
778 return;
e16155ae 779 }
c10421d3 780#endif
e16155ae 781 }
c10421d3 782 rte_free(e);
e16155ae
MM
783}
784
2d140452
MM
785/*
786 * Periodic scanning
787 */
788
c6964c30
OZ
789
790#ifdef CONFIG_ALL_TABLES_AT_ONCE
791
792static timer *krt_scan_timer;
793static int krt_scan_count;
794
2d140452 795static void
6578a604 796krt_scan(timer *t UNUSED)
2d140452 797{
7de45ba4 798 struct krt_proto *p;
7d767c5a 799 node *n;
2d140452 800
7e5f5ffd 801 kif_force_scan();
c6964c30
OZ
802
803 /* We need some node to decide whether to print the debug messages or not */
804 p = SKIP_BACK(struct krt_proto, krt_node, HEAD(krt_proto_list));
805 KRT_TRACE(p, D_EVENTS, "Scanning routing table");
806
7d767c5a
OZ
807 WALK_LIST2(p, n, krt_proto_list, krt_node)
808 krt_init_scan(p);
809
c6964c30
OZ
810 krt_do_scan(NULL);
811
7d767c5a 812 WALK_LIST2(p, n, krt_proto_list, krt_node)
c6964c30 813 krt_prune(p);
c6964c30
OZ
814}
815
816static void
817krt_scan_timer_start(struct krt_proto *p)
818{
819 if (!krt_scan_count)
a6f79ca5 820 krt_scan_timer = tm_new_init(krt_pool, krt_scan, NULL, KRT_CF->scan_time, 0);
c6964c30
OZ
821
822 krt_scan_count++;
f8cc7396 823
a6f79ca5 824 tm_start(krt_scan_timer, 1 S);
c6964c30
OZ
825}
826
827static void
3e236955 828krt_scan_timer_stop(struct krt_proto *p UNUSED)
c6964c30
OZ
829{
830 krt_scan_count--;
831
832 if (!krt_scan_count)
833 {
834 rfree(krt_scan_timer);
835 krt_scan_timer = NULL;
7de45ba4 836 }
c6964c30
OZ
837}
838
0c791f87
OZ
839static void
840krt_scan_timer_kick(struct krt_proto *p UNUSED)
841{
a6f79ca5 842 tm_start(krt_scan_timer, 0);
0c791f87
OZ
843}
844
7de45ba4 845#else
c6964c30
OZ
846
847static void
848krt_scan(timer *t)
849{
850 struct krt_proto *p = t->data;
851
852 kif_force_scan();
853
832fa033 854 KRT_TRACE(p, D_EVENTS, "Scanning routing table");
7d767c5a 855 krt_init_scan(p);
396dfa90 856 krt_do_scan(p);
7e5f5ffd 857 krt_prune(p);
2d140452
MM
858}
859
c6964c30
OZ
860static void
861krt_scan_timer_start(struct krt_proto *p)
862{
a6f79ca5
OZ
863 p->scan_timer = tm_new_init(p->p.pool, krt_scan, p, KRT_CF->scan_time, 0);
864 tm_start(p->scan_timer, 1 S);
c6964c30
OZ
865}
866
867static void
868krt_scan_timer_stop(struct krt_proto *p)
869{
a6f79ca5 870 tm_stop(p->scan_timer);
c6964c30
OZ
871}
872
0c791f87 873static void
252c7e4d 874krt_scan_timer_kick(struct krt_proto *p)
0c791f87 875{
a6f79ca5 876 tm_start(p->scan_timer, 0);
0c791f87
OZ
877}
878
c6964c30
OZ
879#endif
880
881
882
396dfa90 883
c10421d3
MM
884/*
885 * Updates
886 */
396dfa90 887
875cc073
OZ
888static void
889krt_make_tmp_attrs(struct rte *rt, struct linpool *pool)
396dfa90 890{
875cc073
OZ
891 rte_init_tmp_attrs(rt, pool, 2);
892 rte_make_tmp_attr(rt, EA_KRT_SOURCE, EAF_TYPE_INT, rt->u.krt.proto);
893 rte_make_tmp_attr(rt, EA_KRT_METRIC, EAF_TYPE_INT, rt->u.krt.metric);
396dfa90
OZ
894}
895
896static void
875cc073 897krt_store_tmp_attrs(struct rte *rt, struct linpool *pool)
396dfa90 898{
875cc073
OZ
899 rte_init_tmp_attrs(rt, pool, 2);
900 rt->u.krt.proto = rte_store_tmp_attr(rt, EA_KRT_SOURCE);
901 rt->u.krt.metric = rte_store_tmp_attr(rt, EA_KRT_METRIC);
396dfa90
OZ
902}
903
c429d4a4 904static int
14375237 905krt_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
c429d4a4 906{
62e64905 907 // struct krt_proto *p = (struct krt_proto *) P;
c429d4a4
OZ
908 rte *e = *new;
909
094d2bdb 910 if (e->attrs->src->proto == P)
c429d4a4
OZ
911 return -1;
912
c429d4a4
OZ
913 if (!krt_capable(e))
914 return -1;
915
916 return 0;
917}
c10421d3
MM
918
919static void
4bdf1881 920krt_rt_notify(struct proto *P, struct channel *ch UNUSED, net *net,
13c0be19 921 rte *new, rte *old)
c10421d3
MM
922{
923 struct krt_proto *p = (struct krt_proto *) P;
924
a92cf57d 925 if (config->shutdown)
f990fc61 926 return;
c132acae
OZ
927
928#ifdef CONFIG_SINGLE_ROUTE
929 /*
930 * Implicit withdraw - when the imported kernel route becomes the best one,
931 * we know that the previous one exported to the kernel was already removed,
932 * but if we processed the update as usual, we would send withdraw to the
933 * kernel, which would remove the new imported route instead.
934 */
935 rte *best = net->routes;
936 if (!new && best && (best->attrs->src->proto == P))
937 return;
938#endif
939
c9df01d3 940 if (p->initialized) /* Before first scan we don't touch the routes */
13c0be19 941 krt_replace_rte(p, net, new, old);
c10421d3
MM
942}
943
252c7e4d
OZ
944static void
945krt_if_notify(struct proto *P, uint flags, struct iface *iface UNUSED)
946{
947 struct krt_proto *p = (struct krt_proto *) P;
948
949 /*
950 * When interface went down, we should remove routes to it. In the ideal world,
951 * OS kernel would send us route removal notifications in such cases, but we
952 * cannot rely on it as it is often not true. E.g. Linux kernel removes related
953 * routes when an interface went down, but it does not notify userspace about
954 * that. To be sure, we just schedule a scan to ensure synchronization.
955 */
956
957 if ((flags & IF_CHANGE_DOWN) && KRT_CF->learn)
958 krt_scan_timer_kick(p);
959}
960
f4a60a9b
OZ
961static void
962krt_reload_routes(struct channel *C)
252c7e4d 963{
f4a60a9b 964 struct krt_proto *p = (void *) C->proto;
252c7e4d
OZ
965
966 /* Although we keep learned routes in krt_table, we rather schedule a scan */
967
968 if (KRT_CF->learn)
7069fc9e
OZ
969 {
970 p->reload = 1;
252c7e4d 971 krt_scan_timer_kick(p);
7069fc9e 972 }
252c7e4d
OZ
973}
974
0c791f87 975static void
f4a60a9b 976krt_feed_end(struct channel *C)
0c791f87 977{
f4a60a9b 978 struct krt_proto *p = (void *) C->proto;
0c791f87
OZ
979
980 p->ready = 1;
981 krt_scan_timer_kick(p);
982}
983
984
396dfa90
OZ
985static int
986krt_rte_same(rte *a, rte *b)
987{
988 /* src is always KRT_SRC_ALIEN and type is irrelevant */
989 return (a->u.krt.proto == b->u.krt.proto) && (a->u.krt.metric == b->u.krt.metric);
990}
991
992
2d140452
MM
993/*
994 * Protocol glue
995 */
996
396dfa90 997struct krt_config *krt_cf;
7e5f5ffd 998
f4a60a9b
OZ
999static void
1000krt_preconfig(struct protocol *P UNUSED, struct config *c)
1001{
1002 krt_cf = NULL;
1003 krt_sys_preconfig(c);
1004}
1005
1006static void
1007krt_postconfig(struct proto_config *CF)
1008{
1009 struct krt_config *cf = (void *) CF;
1010
2a8cc725
OZ
1011 /* Do not check templates at all */
1012 if (cf->c.class == SYM_TEMPLATE)
1013 return;
1014
f4a60a9b
OZ
1015 if (EMPTY_LIST(CF->channels))
1016 cf_error("Channel not specified");
1017
1018#ifdef CONFIG_ALL_TABLES_AT_ONCE
1019 if (krt_cf->scan_time != cf->scan_time)
1020 cf_error("All kernel syncers must use the same table scan interval");
1021#endif
1022
ace3072e
OZ
1023 struct channel_config *cc = proto_cf_main_channel(CF);
1024 struct rtable_config *tab = cc->table;
f4a60a9b
OZ
1025 if (tab->krt_attached)
1026 cf_error("Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name);
1027 tab->krt_attached = CF;
1028
ace3072e
OZ
1029 if (cf->merge_paths)
1030 {
1031 cc->ra_mode = RA_MERGED;
1032 cc->merge_limit = cf->merge_paths;
1033 }
1034
f4a60a9b
OZ
1035 krt_sys_postconfig(cf);
1036}
1037
396dfa90 1038static struct proto *
f4a60a9b 1039krt_init(struct proto_config *CF)
7de45ba4 1040{
f4a60a9b
OZ
1041 struct krt_proto *p = proto_new(CF);
1042 // struct krt_config *cf = (void *) CF;
1043
1044 p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF));
7de45ba4 1045
14375237 1046 p->p.preexport = krt_preexport;
252c7e4d
OZ
1047 p->p.rt_notify = krt_rt_notify;
1048 p->p.if_notify = krt_if_notify;
1049 p->p.reload_routes = krt_reload_routes;
9aed29e6 1050 p->p.feed_end = krt_feed_end;
094d2bdb
OZ
1051 p->p.make_tmp_attrs = krt_make_tmp_attrs;
1052 p->p.store_tmp_attrs = krt_store_tmp_attrs;
396dfa90 1053 p->p.rte_same = krt_rte_same;
7de45ba4 1054
396dfa90
OZ
1055 krt_sys_init(p);
1056 return &p->p;
7de45ba4
MM
1057}
1058
2d140452
MM
1059static int
1060krt_start(struct proto *P)
1061{
1062 struct krt_proto *p = (struct krt_proto *) P;
7de45ba4 1063
f4a60a9b 1064 switch (p->p.net_type)
29a64162 1065 {
be17805c
OZ
1066 case NET_IP4: p->af = AF_INET; break;
1067 case NET_IP6: p->af = AF_INET6; break;
1068 case NET_IP6_SADR: p->af = AF_INET6; break;
1d213067 1069#ifdef AF_MPLS
be17805c 1070 case NET_MPLS: p->af = AF_MPLS; break;
1d213067 1071#endif
d14f8c3c 1072 default: log(L_ERR "KRT: Tried to start with strange net type: %d", p->p.net_type); return PS_START; break;
29a64162
OZ
1073 }
1074
cc75b3e1 1075 bmap_init(&p->sync_map, p->p.pool, 1024);
7d767c5a 1076 bmap_init(&p->seen_map, p->p.pool, 1024);
c6964c30 1077 add_tail(&krt_proto_list, &p->krt_node);
2d140452 1078
c10421d3
MM
1079#ifdef KRT_ALLOW_LEARN
1080 krt_learn_init(p);
1081#endif
1082
9ddbfbdd
JMM
1083 if (!krt_sys_start(p))
1084 {
1085 rem_node(&p->krt_node);
1086 return PS_START;
1087 }
2d140452 1088
c6964c30 1089 krt_scan_timer_start(p);
2d140452 1090
f4a60a9b
OZ
1091 if (p->p.gr_recovery && KRT_CF->graceful_restart)
1092 p->p.main_channel->gr_wait = 1;
0c791f87 1093
2d140452
MM
1094 return PS_UP;
1095}
1096
7de45ba4 1097static int
2d140452
MM
1098krt_shutdown(struct proto *P)
1099{
1100 struct krt_proto *p = (struct krt_proto *) P;
1101
c6964c30 1102 krt_scan_timer_stop(p);
7e5f5ffd 1103
3d574679 1104 /* FIXME we should flush routes even when persist during reconfiguration */
8a68316e 1105 if (p->initialized && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN))
2d140452
MM
1106 krt_flush_routes(p);
1107
0c791f87
OZ
1108 p->ready = 0;
1109 p->initialized = 0;
1110
9ddbfbdd
JMM
1111 if (p->p.proto_state == PS_START)
1112 return PS_DOWN;
7de45ba4 1113
9ddbfbdd 1114 krt_sys_shutdown(p);
c6964c30 1115 rem_node(&p->krt_node);
cc75b3e1 1116 bmap_free(&p->sync_map);
2d140452 1117
2d140452
MM
1118 return PS_DOWN;
1119}
1120
396dfa90 1121static int
f4a60a9b 1122krt_reconfigure(struct proto *p, struct proto_config *CF)
72aed1a0 1123{
f4a60a9b
OZ
1124 struct krt_config *o = (void *) p->cf;
1125 struct krt_config *n = (void *) CF;
1126
1127 if (!proto_configure_channel(p, &p->main_channel, proto_cf_main_channel(CF)))
1128 return 0;
72aed1a0 1129
396dfa90
OZ
1130 if (!krt_sys_reconfigure((struct krt_proto *) p, n, o))
1131 return 0;
9ba2798c 1132
0c791f87 1133 /* persist, graceful restart need not be the same */
e5ff7929 1134 return o->scan_time == n->scan_time && o->learn == n->learn;
2d140452
MM
1135}
1136
396dfa90
OZ
1137struct proto_config *
1138krt_init_config(int class)
aa8761de 1139{
396dfa90
OZ
1140#ifndef CONFIG_MULTIPLE_TABLES
1141 if (krt_cf)
1142 cf_error("Kernel protocol already defined");
1143#endif
1144
2bbc3083 1145 krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, class);
21f4f0f4 1146 krt_cf->scan_time = 60 S;
aa8761de 1147
396dfa90
OZ
1148 krt_sys_init_config(krt_cf);
1149 return (struct proto_config *) krt_cf;
aa8761de
MM
1150}
1151
a7f23f58
OZ
1152static void
1153krt_copy_config(struct proto_config *dest, struct proto_config *src)
1154{
1155 struct krt_config *d = (struct krt_config *) dest;
1156 struct krt_config *s = (struct krt_config *) src;
1157
a7f23f58 1158 /* Fix sysdep parts */
396dfa90 1159 krt_sys_copy_config(d, s);
a7f23f58 1160}
71ca7716
OZ
1161
1162static int
258be565 1163krt_get_attr(const eattr *a, byte *buf, int buflen)
71ca7716
OZ
1164{
1165 switch (a->id)
1166 {
72aed1a0
OZ
1167 case EA_KRT_SOURCE:
1168 bsprintf(buf, "source");
1169 return GA_NAME;
1170
9ba2798c
OZ
1171 case EA_KRT_METRIC:
1172 bsprintf(buf, "metric");
1173 return GA_NAME;
1174
71ca7716 1175 default:
9fdf9d29 1176 return krt_sys_get_attr(a, buf, buflen);
71ca7716
OZ
1177 }
1178}
1179
1180
be17805c
OZ
1181#ifdef CONFIG_IP6_SADR_KERNEL
1182#define MAYBE_IP6_SADR NB_IP6_SADR
1183#else
1184#define MAYBE_IP6_SADR 0
1185#endif
1186
1187#ifdef HAVE_MPLS_KERNEL
1188#define MAYBE_MPLS NB_MPLS
1189#else
1190#define MAYBE_MPLS 0
1191#endif
1192
2d140452 1193struct protocol proto_unix_kernel = {
4a591d4b
PT
1194 .name = "Kernel",
1195 .template = "kernel%d",
ee7e2ffd 1196 .class = PROTOCOL_KERNEL,
4a591d4b 1197 .preference = DEF_PREF_INHERITED,
be17805c 1198 .channel_mask = NB_IP | MAYBE_IP6_SADR | MAYBE_MPLS,
f4a60a9b 1199 .proto_size = sizeof(struct krt_proto),
2bbc3083 1200 .config_size = sizeof(struct krt_config),
4a591d4b
PT
1201 .preconfig = krt_preconfig,
1202 .postconfig = krt_postconfig,
1203 .init = krt_init,
1204 .start = krt_start,
1205 .shutdown = krt_shutdown,
1206 .reconfigure = krt_reconfigure,
1207 .copy_config = krt_copy_config,
1208 .get_attr = krt_get_attr,
c10421d3 1209#ifdef KRT_ALLOW_LEARN
4a591d4b
PT
1210 .dump = krt_dump,
1211 .dump_attrs = krt_dump_attrs,
c10421d3 1212#endif
2d140452 1213};