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