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