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