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