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