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 void
543: krt_flush_routes(struct krt_proto *p)
544: {
545: struct rtable *t = p->p.main_channel->table;
546:
547: KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
548: FIB_WALK(&t->fib, net, n)
549: {
550: rte *e = n->routes;
551: if (rte_is_valid(e) && (n->n.flags & KRF_INSTALLED))
552: {
553: /* FIXME: this does not work if gw is changed in export filter */
554: krt_replace_rte(p, e->net, NULL, e);
555: n->n.flags &= ~KRF_INSTALLED;
556: }
557: }
558: FIB_WALK_END;
559: }
560:
561: static struct rte *
562: krt_export_net(struct krt_proto *p, net *net, rte **rt_free)
563: {
564: struct channel *c = p->p.main_channel;
565: const struct filter *filter = c->out_filter;
566: rte *rt;
567:
568: if (c->ra_mode == RA_MERGED)
569: return rt_export_merged(c, net, rt_free, krt_filter_lp, 1);
570:
571: rt = net->routes;
572: *rt_free = NULL;
573:
574: if (!rte_is_valid(rt))
575: return NULL;
576:
577: if (filter == FILTER_REJECT)
578: return NULL;
579:
580: rte_make_tmp_attrs(&rt, krt_filter_lp, NULL);
581:
582: /* We could run krt_preexport() here, but it is already handled by KRF_INSTALLED */
583:
584: if (filter == FILTER_ACCEPT)
585: goto accept;
586:
587: if (f_run(filter, &rt, krt_filter_lp, FF_SILENT) > F_ACCEPT)
588: goto reject;
589:
590:
591: accept:
592: if (rt != net->routes)
593: *rt_free = rt;
594: return rt;
595:
596: reject:
597: if (rt != net->routes)
598: rte_free(rt);
599: return NULL;
600: }
601:
602: static int
603: krt_same_dest(rte *k, rte *e)
604: {
605: rta *ka = k->attrs, *ea = e->attrs;
606:
607: if (ka->dest != ea->dest)
608: return 0;
609:
610: if (ka->dest == RTD_UNICAST)
611: return nexthop_same(&(ka->nh), &(ea->nh));
612:
613: return 1;
614: }
615:
616: /*
617: * This gets called back when the low-level scanning code discovers a route.
618: * We expect that the route is a temporary rte and its attributes are uncached.
619: */
620:
621: void
622: krt_got_route(struct krt_proto *p, rte *e)
623: {
624: net *net = e->net;
625: int verdict;
626:
627: #ifdef KRT_ALLOW_LEARN
628: switch (e->u.krt.src)
629: {
630: case KRT_SRC_KERNEL:
631: verdict = KRF_IGNORE;
632: goto sentenced;
633:
634: case KRT_SRC_REDIRECT:
635: verdict = KRF_DELETE;
636: goto sentenced;
637:
638: case KRT_SRC_ALIEN:
639: if (KRT_CF->learn)
640: krt_learn_scan(p, e);
641: else
642: {
643: krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored");
644: rte_free(e);
645: }
646: return;
647: }
648: #endif
649: /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
650:
651: if (net->n.flags & KRF_VERDICT_MASK)
652: {
653: /* Route to this destination was already seen. Strange, but it happens... */
654: krt_trace_in(p, e, "already seen");
655: rte_free(e);
656: return;
657: }
658:
659: if (!p->ready)
660: {
661: /* We wait for the initial feed to have correct KRF_INSTALLED flag */
662: verdict = KRF_IGNORE;
663: goto sentenced;
664: }
665:
666: if (net->n.flags & KRF_INSTALLED)
667: {
668: rte *new, *rt_free;
669:
670: new = krt_export_net(p, net, &rt_free);
671:
672: /* TODO: There also may be changes in route eattrs, we ignore that for now. */
673:
674: if (!new)
675: verdict = KRF_DELETE;
676: else if ((net->n.flags & KRF_SYNC_ERROR) || !krt_same_dest(e, new))
677: verdict = KRF_UPDATE;
678: else
679: verdict = KRF_SEEN;
680:
681: if (rt_free)
682: rte_free(rt_free);
683:
684: lp_flush(krt_filter_lp);
685: }
686: else
687: verdict = KRF_DELETE;
688:
689: sentenced:
690: krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]);
691: net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
692: if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
693: {
694: /* Get a cached copy of attributes and temporarily link the route */
695: rta *a = e->attrs;
696: a->source = RTS_DUMMY;
697: e->attrs = rta_lookup(a);
698: e->next = net->routes;
699: net->routes = e;
700: }
701: else
702: rte_free(e);
703: }
704:
705: static void
706: krt_prune(struct krt_proto *p)
707: {
708: struct rtable *t = p->p.main_channel->table;
709:
710: KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
711: FIB_WALK(&t->fib, net, n)
712: {
713: int verdict = n->n.flags & KRF_VERDICT_MASK;
714: rte *new, *old, *rt_free = NULL;
715:
716: if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
717: {
718: /* Get a dummy route from krt_got_route() */
719: old = n->routes;
720: n->routes = old->next;
721: }
722: else
723: old = NULL;
724:
725: if (verdict == KRF_CREATE || verdict == KRF_UPDATE)
726: {
727: /* We have to run export filter to get proper 'new' route */
728: new = krt_export_net(p, n, &rt_free);
729:
730: if (!new)
731: verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE;
732: }
733: else
734: new = NULL;
735:
736: switch (verdict)
737: {
738: case KRF_CREATE:
739: if (new && (n->n.flags & KRF_INSTALLED))
740: {
741: krt_trace_in(p, new, "reinstalling");
742: krt_replace_rte(p, n, new, NULL);
743: }
744: break;
745: case KRF_SEEN:
746: case KRF_IGNORE:
747: /* Nothing happens */
748: break;
749: case KRF_UPDATE:
750: krt_trace_in(p, new, "updating");
751: krt_replace_rte(p, n, new, old);
752: break;
753: case KRF_DELETE:
754: krt_trace_in(p, old, "deleting");
755: krt_replace_rte(p, n, NULL, old);
756: break;
757: default:
758: bug("krt_prune: invalid route status");
759: }
760:
761: if (old)
762: rte_free(old);
763: if (rt_free)
764: rte_free(rt_free);
765: lp_flush(krt_filter_lp);
766: n->n.flags &= ~KRF_VERDICT_MASK;
767: }
768: FIB_WALK_END;
769:
770: #ifdef KRT_ALLOW_LEARN
771: if (KRT_CF->learn)
772: krt_learn_prune(p);
773: #endif
774:
775: if (p->ready)
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: /* Should be filtered by the back end */
788: bug("BIRD originated routes should not get here.");
789:
790: case KRT_SRC_REDIRECT:
791: if (new)
792: {
793: krt_trace_in(p, e, "[redirect] deleting");
794: krt_replace_rte(p, net, NULL, e);
795: }
796: /* If !new, it is probably echo of our deletion */
797: break;
798:
799: #ifdef KRT_ALLOW_LEARN
800: case KRT_SRC_ALIEN:
801: if (KRT_CF->learn)
802: {
803: krt_learn_async(p, e, new);
804: return;
805: }
806: #endif
807: }
808: rte_free(e);
809: }
810:
811: /*
812: * Periodic scanning
813: */
814:
815:
816: #ifdef CONFIG_ALL_TABLES_AT_ONCE
817:
818: static timer *krt_scan_timer;
819: static int krt_scan_count;
820:
821: static void
822: krt_scan(timer *t UNUSED)
823: {
824: struct krt_proto *p;
825:
826: kif_force_scan();
827:
828: /* We need some node to decide whether to print the debug messages or not */
829: p = SKIP_BACK(struct krt_proto, krt_node, HEAD(krt_proto_list));
830: KRT_TRACE(p, D_EVENTS, "Scanning routing table");
831:
832: krt_do_scan(NULL);
833:
834: void *q;
835: WALK_LIST(q, krt_proto_list)
836: {
837: p = SKIP_BACK(struct krt_proto, krt_node, q);
838: krt_prune(p);
839: }
840: }
841:
842: static void
843: krt_scan_timer_start(struct krt_proto *p)
844: {
845: if (!krt_scan_count)
846: krt_scan_timer = tm_new_init(krt_pool, krt_scan, NULL, KRT_CF->scan_time, 0);
847:
848: krt_scan_count++;
849:
850: tm_start(krt_scan_timer, 1 S);
851: }
852:
853: static void
854: krt_scan_timer_stop(struct krt_proto *p UNUSED)
855: {
856: krt_scan_count--;
857:
858: if (!krt_scan_count)
859: {
860: rfree(krt_scan_timer);
861: krt_scan_timer = NULL;
862: }
863: }
864:
865: static void
866: krt_scan_timer_kick(struct krt_proto *p UNUSED)
867: {
868: tm_start(krt_scan_timer, 0);
869: }
870:
871: #else
872:
873: static void
874: krt_scan(timer *t)
875: {
876: struct krt_proto *p = t->data;
877:
878: kif_force_scan();
879:
880: KRT_TRACE(p, D_EVENTS, "Scanning routing table");
881: krt_do_scan(p);
882: krt_prune(p);
883: }
884:
885: static void
886: krt_scan_timer_start(struct krt_proto *p)
887: {
888: p->scan_timer = tm_new_init(p->p.pool, krt_scan, p, KRT_CF->scan_time, 0);
889: tm_start(p->scan_timer, 1 S);
890: }
891:
892: static void
893: krt_scan_timer_stop(struct krt_proto *p)
894: {
895: tm_stop(p->scan_timer);
896: }
897:
898: static void
899: krt_scan_timer_kick(struct krt_proto *p)
900: {
901: tm_start(p->scan_timer, 0);
902: }
903:
904: #endif
905:
906:
907:
908:
909: /*
910: * Updates
911: */
912:
913: static void
914: krt_make_tmp_attrs(struct rte *rt, struct linpool *pool)
915: {
916: rte_init_tmp_attrs(rt, pool, 2);
917: rte_make_tmp_attr(rt, EA_KRT_SOURCE, EAF_TYPE_INT, rt->u.krt.proto);
918: rte_make_tmp_attr(rt, EA_KRT_METRIC, EAF_TYPE_INT, rt->u.krt.metric);
919: }
920:
921: static void
922: krt_store_tmp_attrs(struct rte *rt, struct linpool *pool)
923: {
924: rte_init_tmp_attrs(rt, pool, 2);
925: rt->u.krt.proto = rte_store_tmp_attr(rt, EA_KRT_SOURCE);
926: rt->u.krt.metric = rte_store_tmp_attr(rt, EA_KRT_METRIC);
927: }
928:
929: static int
930: krt_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
931: {
932: // struct krt_proto *p = (struct krt_proto *) P;
933: rte *e = *new;
934:
935: if (e->attrs->src->proto == P)
936: {
937: #ifdef CONFIG_SINGLE_ROUTE
938: /*
939: * Implicit withdraw - when the imported kernel route becomes the best one,
940: * we know that the previous one exported to the kernel was already removed,
941: * but if we processed the update as usual, we would send withdraw to the
942: * kernel, which would remove the new imported route instead.
943: *
944: * We will remove KRT_INSTALLED flag, which stops such withdraw to be
945: * processed in krt_rt_notify() and krt_replace_rte().
946: */
947: if (e == e->net->routes)
948: e->net->n.flags &= ~KRF_INSTALLED;
949: #endif
950: return -1;
951: }
952:
953: if (!krt_capable(e))
954: return -1;
955:
956: return 0;
957: }
958:
959: static void
960: krt_rt_notify(struct proto *P, struct channel *ch UNUSED, net *net,
961: rte *new, rte *old)
962: {
963: struct krt_proto *p = (struct krt_proto *) P;
964:
965: if (config->shutdown)
966: return;
967: if (!(net->n.flags & KRF_INSTALLED))
968: old = NULL;
969: if (new)
970: net->n.flags |= KRF_INSTALLED;
971: else
972: net->n.flags &= ~KRF_INSTALLED;
973: if (p->initialized) /* Before first scan we don't touch the routes */
974: krt_replace_rte(p, net, new, old);
975: }
976:
977: static void
978: krt_if_notify(struct proto *P, uint flags, struct iface *iface UNUSED)
979: {
980: struct krt_proto *p = (struct krt_proto *) P;
981:
982: /*
983: * When interface went down, we should remove routes to it. In the ideal world,
984: * OS kernel would send us route removal notifications in such cases, but we
985: * cannot rely on it as it is often not true. E.g. Linux kernel removes related
986: * routes when an interface went down, but it does not notify userspace about
987: * that. To be sure, we just schedule a scan to ensure synchronization.
988: */
989:
990: if ((flags & IF_CHANGE_DOWN) && KRT_CF->learn)
991: krt_scan_timer_kick(p);
992: }
993:
994: static void
995: krt_reload_routes(struct channel *C)
996: {
997: struct krt_proto *p = (void *) C->proto;
998:
999: /* Although we keep learned routes in krt_table, we rather schedule a scan */
1000:
1001: if (KRT_CF->learn)
1002: {
1003: p->reload = 1;
1004: krt_scan_timer_kick(p);
1005: }
1006: }
1007:
1008: static void
1009: krt_feed_end(struct channel *C)
1010: {
1011: struct krt_proto *p = (void *) C->proto;
1012:
1013: p->ready = 1;
1014: krt_scan_timer_kick(p);
1015: }
1016:
1017:
1018: static int
1019: krt_rte_same(rte *a, rte *b)
1020: {
1021: /* src is always KRT_SRC_ALIEN and type is irrelevant */
1022: return (a->u.krt.proto == b->u.krt.proto) && (a->u.krt.metric == b->u.krt.metric);
1023: }
1024:
1025:
1026: /*
1027: * Protocol glue
1028: */
1029:
1030: struct krt_config *krt_cf;
1031:
1032: static void
1033: krt_preconfig(struct protocol *P UNUSED, struct config *c)
1034: {
1035: krt_cf = NULL;
1036: krt_sys_preconfig(c);
1037: }
1038:
1039: static void
1040: krt_postconfig(struct proto_config *CF)
1041: {
1042: struct krt_config *cf = (void *) CF;
1043:
1044: if (EMPTY_LIST(CF->channels))
1045: cf_error("Channel not specified");
1046:
1047: #ifdef CONFIG_ALL_TABLES_AT_ONCE
1048: if (krt_cf->scan_time != cf->scan_time)
1049: cf_error("All kernel syncers must use the same table scan interval");
1050: #endif
1051:
1052: struct channel_config *cc = proto_cf_main_channel(CF);
1053: struct rtable_config *tab = cc->table;
1054: if (tab->krt_attached)
1055: cf_error("Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name);
1056: tab->krt_attached = CF;
1057:
1058: if (cf->merge_paths)
1059: {
1060: cc->ra_mode = RA_MERGED;
1061: cc->merge_limit = cf->merge_paths;
1062: }
1063:
1064: krt_sys_postconfig(cf);
1065: }
1066:
1067: static struct proto *
1068: krt_init(struct proto_config *CF)
1069: {
1070: struct krt_proto *p = proto_new(CF);
1071: // struct krt_config *cf = (void *) CF;
1072:
1073: p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF));
1074:
1075: p->p.preexport = krt_preexport;
1076: p->p.rt_notify = krt_rt_notify;
1077: p->p.if_notify = krt_if_notify;
1078: p->p.reload_routes = krt_reload_routes;
1079: p->p.feed_end = krt_feed_end;
1080: p->p.make_tmp_attrs = krt_make_tmp_attrs;
1081: p->p.store_tmp_attrs = krt_store_tmp_attrs;
1082: p->p.rte_same = krt_rte_same;
1083:
1084: krt_sys_init(p);
1085: return &p->p;
1086: }
1087:
1088: static int
1089: krt_start(struct proto *P)
1090: {
1091: struct krt_proto *p = (struct krt_proto *) P;
1092:
1093: switch (p->p.net_type)
1094: {
1095: case NET_IP4: p->af = AF_INET; break;
1096: case NET_IP6: p->af = AF_INET6; break;
1097: case NET_IP6_SADR: p->af = AF_INET6; break;
1098: #ifdef AF_MPLS
1099: case NET_MPLS: p->af = AF_MPLS; break;
1100: #endif
1101: default: log(L_ERR "KRT: Tried to start with strange net type: %d", p->p.net_type); return PS_START; break;
1102: }
1103:
1104: add_tail(&krt_proto_list, &p->krt_node);
1105:
1106: #ifdef KRT_ALLOW_LEARN
1107: krt_learn_init(p);
1108: #endif
1109:
1110: if (!krt_sys_start(p))
1111: {
1112: rem_node(&p->krt_node);
1113: return PS_START;
1114: }
1115:
1116: krt_scan_timer_start(p);
1117:
1118: if (p->p.gr_recovery && KRT_CF->graceful_restart)
1119: p->p.main_channel->gr_wait = 1;
1120:
1121: return PS_UP;
1122: }
1123:
1124: static int
1125: krt_shutdown(struct proto *P)
1126: {
1127: struct krt_proto *p = (struct krt_proto *) P;
1128:
1129: krt_scan_timer_stop(p);
1130:
1131: /* FIXME we should flush routes even when persist during reconfiguration */
1132: if (p->initialized && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN))
1133: krt_flush_routes(p);
1134:
1135: p->ready = 0;
1136: p->initialized = 0;
1137:
1138: if (p->p.proto_state == PS_START)
1139: return PS_DOWN;
1140:
1141: krt_sys_shutdown(p);
1142: rem_node(&p->krt_node);
1143:
1144: return PS_DOWN;
1145: }
1146:
1147: static int
1148: krt_reconfigure(struct proto *p, struct proto_config *CF)
1149: {
1150: struct krt_config *o = (void *) p->cf;
1151: struct krt_config *n = (void *) CF;
1152:
1153: if (!proto_configure_channel(p, &p->main_channel, proto_cf_main_channel(CF)))
1154: return 0;
1155:
1156: if (!krt_sys_reconfigure((struct krt_proto *) p, n, o))
1157: return 0;
1158:
1159: /* persist, graceful restart need not be the same */
1160: return o->scan_time == n->scan_time && o->learn == n->learn;
1161: }
1162:
1163: struct proto_config *
1164: krt_init_config(int class)
1165: {
1166: #ifndef CONFIG_MULTIPLE_TABLES
1167: if (krt_cf)
1168: cf_error("Kernel protocol already defined");
1169: #endif
1170:
1171: krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, class);
1172: krt_cf->scan_time = 60 S;
1173:
1174: krt_sys_init_config(krt_cf);
1175: return (struct proto_config *) krt_cf;
1176: }
1177:
1178: static void
1179: krt_copy_config(struct proto_config *dest, struct proto_config *src)
1180: {
1181: struct krt_config *d = (struct krt_config *) dest;
1182: struct krt_config *s = (struct krt_config *) src;
1183:
1184: /* Fix sysdep parts */
1185: krt_sys_copy_config(d, s);
1186: }
1187:
1188: static int
1189: krt_get_attr(eattr *a, byte *buf, int buflen)
1190: {
1191: switch (a->id)
1192: {
1193: case EA_KRT_SOURCE:
1194: bsprintf(buf, "source");
1195: return GA_NAME;
1196:
1197: case EA_KRT_METRIC:
1198: bsprintf(buf, "metric");
1199: return GA_NAME;
1200:
1201: default:
1202: return krt_sys_get_attr(a, buf, buflen);
1203: }
1204: }
1205:
1206:
1207: #ifdef CONFIG_IP6_SADR_KERNEL
1208: #define MAYBE_IP6_SADR NB_IP6_SADR
1209: #else
1210: #define MAYBE_IP6_SADR 0
1211: #endif
1212:
1213: #ifdef HAVE_MPLS_KERNEL
1214: #define MAYBE_MPLS NB_MPLS
1215: #else
1216: #define MAYBE_MPLS 0
1217: #endif
1218:
1219: struct protocol proto_unix_kernel = {
1220: .name = "Kernel",
1221: .template = "kernel%d",
1222: .class = PROTOCOL_KERNEL,
1223: .preference = DEF_PREF_INHERITED,
1224: .channel_mask = NB_IP | MAYBE_IP6_SADR | MAYBE_MPLS,
1225: .proto_size = sizeof(struct krt_proto),
1226: .config_size = sizeof(struct krt_config),
1227: .preconfig = krt_preconfig,
1228: .postconfig = krt_postconfig,
1229: .init = krt_init,
1230: .start = krt_start,
1231: .shutdown = krt_shutdown,
1232: .reconfigure = krt_reconfigure,
1233: .copy_config = krt_copy_config,
1234: .get_attr = krt_get_attr,
1235: #ifdef KRT_ALLOW_LEARN
1236: .dump = krt_dump,
1237: .dump_attrs = krt_dump_attrs,
1238: #endif
1239: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>