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