]>
Commit | Line | Data |
---|---|---|
2d140452 MM |
1 | /* |
2 | * BIRD -- UNIX Kernel Synchronization | |
3 | * | |
50fe90ed | 4 | * (c) 1998--2000 Martin Mares <mj@ucw.cz> |
2d140452 MM |
5 | * |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
7 | */ | |
8 | ||
73275d85 MM |
9 | /** |
10 | * DOC: Kernel synchronization | |
11 | * | |
12 | * This system dependent module implements the Kernel and Device protocol, | |
13 | * that is synchronization of interface lists and routing tables with the | |
14 | * OS kernel. | |
15 | * | |
16 | * The whole kernel synchronization is a bit messy and touches some internals | |
17 | * of the routing table engine, because routing table maintenance is a typical | |
18 | * example of the proverbial compatibility between different Unices and we want | |
2e9b2421 | 19 | * to keep the overhead of our KRT business as low as possible and avoid maintaining |
73275d85 MM |
20 | * a local routing table copy. |
21 | * | |
22 | * The kernel syncer can work in three different modes (according to system config header): | |
725270cb | 23 | * Either with a single routing table and single KRT protocol [traditional UNIX] |
2e9b2421 | 24 | * or with many routing tables and separate KRT protocols for all of them |
73275d85 | 25 | * or with many routing tables, but every scan including all tables, so we start |
2e9b2421 | 26 | * separate KRT protocols which cooperate with each other [Linux 2.2]. |
73275d85 MM |
27 | * In this case, we keep only a single scan timer. |
28 | * | |
58f7d004 MM |
29 | * We use FIB node flags in the routing table to keep track of route |
30 | * synchronization status. We also attach temporary &rte's to the routing table, | |
31 | * but it cannot do any harm to the rest of BIRD since table synchronization is | |
32 | * an atomic process. | |
73275d85 MM |
33 | * |
34 | * When starting up, we cheat by looking if there is another | |
35 | * KRT instance to be initialized later and performing table scan | |
725270cb MM |
36 | * only once for all the instances. |
37 | */ | |
73275d85 MM |
38 | |
39 | /* | |
40 | * If you are brave enough, continue now. You cannot say you haven't been warned. | |
41 | */ | |
42 | ||
832fa033 | 43 | #undef LOCAL_DEBUG |
2d140452 MM |
44 | |
45 | #include "nest/bird.h" | |
46 | #include "nest/iface.h" | |
47 | #include "nest/route.h" | |
48 | #include "nest/protocol.h" | |
49 | #include "lib/timer.h" | |
7de45ba4 | 50 | #include "conf/conf.h" |
7d875e09 | 51 | #include "lib/string.h" |
2d140452 MM |
52 | |
53 | #include "unix.h" | |
54 | #include "krt.h" | |
55 | ||
c10421d3 MM |
56 | static int krt_uptodate(rte *k, rte *e); |
57 | ||
7e5f5ffd MM |
58 | /* |
59 | * Global resources | |
60 | */ | |
61 | ||
7de45ba4 MM |
62 | pool *krt_pool; |
63 | ||
7e5f5ffd MM |
64 | void |
65 | krt_io_init(void) | |
66 | { | |
7de45ba4 | 67 | krt_pool = rp_new(&root_pool, "Kernel Syncer"); |
7e5f5ffd MM |
68 | krt_if_io_init(); |
69 | } | |
70 | ||
71 | /* | |
72 | * Interfaces | |
73 | */ | |
74 | ||
75 | struct proto_config *cf_kif; | |
76 | ||
77 | static struct kif_proto *kif_proto; | |
78 | static timer *kif_scan_timer; | |
79 | static bird_clock_t kif_last_shot; | |
80 | ||
50fe90ed | 81 | static void |
6578a604 | 82 | kif_preconfig(struct protocol *P UNUSED, struct config *c UNUSED) |
50fe90ed MM |
83 | { |
84 | cf_kif = NULL; | |
85 | } | |
86 | ||
7e5f5ffd MM |
87 | static void |
88 | kif_scan(timer *t) | |
89 | { | |
90 | struct kif_proto *p = t->data; | |
91 | ||
832fa033 | 92 | KRT_TRACE(p, D_EVENTS, "Scanning interfaces"); |
7e5f5ffd MM |
93 | kif_last_shot = now; |
94 | krt_if_scan(p); | |
95 | } | |
96 | ||
97 | static void | |
98 | kif_force_scan(void) | |
99 | { | |
100 | if (kif_proto && kif_last_shot + 2 < now) | |
101 | { | |
102 | kif_scan(kif_scan_timer); | |
103 | tm_start(kif_scan_timer, ((struct kif_config *) kif_proto->p.cf)->scan_time); | |
104 | } | |
105 | } | |
106 | ||
09686693 OZ |
107 | void |
108 | kif_request_scan(void) | |
109 | { | |
110 | if (kif_proto && kif_scan_timer->expires > now) | |
111 | tm_start(kif_scan_timer, 1); | |
112 | } | |
113 | ||
7e5f5ffd MM |
114 | static struct proto * |
115 | kif_init(struct proto_config *c) | |
116 | { | |
117 | struct kif_proto *p = proto_new(c, sizeof(struct kif_proto)); | |
118 | return &p->p; | |
119 | } | |
120 | ||
121 | static int | |
122 | kif_start(struct proto *P) | |
123 | { | |
124 | struct kif_proto *p = (struct kif_proto *) P; | |
125 | ||
126 | kif_proto = p; | |
127 | krt_if_start(p); | |
128 | ||
129 | /* Start periodic interface scanning */ | |
130 | kif_scan_timer = tm_new(P->pool); | |
131 | kif_scan_timer->hook = kif_scan; | |
132 | kif_scan_timer->data = p; | |
133 | kif_scan_timer->recurrent = KIF_CF->scan_time; | |
134 | kif_scan(kif_scan_timer); | |
135 | tm_start(kif_scan_timer, KIF_CF->scan_time); | |
136 | ||
137 | return PS_UP; | |
138 | } | |
139 | ||
140 | static int | |
141 | kif_shutdown(struct proto *P) | |
142 | { | |
143 | struct kif_proto *p = (struct kif_proto *) P; | |
144 | ||
145 | tm_stop(kif_scan_timer); | |
146 | krt_if_shutdown(p); | |
147 | kif_proto = NULL; | |
148 | ||
7e5f5ffd MM |
149 | return PS_DOWN; |
150 | } | |
151 | ||
874b8685 OZ |
152 | |
153 | static inline int | |
154 | prefer_scope(struct ifa *a, struct ifa *b) | |
155 | { return (a->scope > SCOPE_LINK) && (b->scope <= SCOPE_LINK); } | |
156 | ||
157 | static inline int | |
158 | prefer_addr(struct ifa *a, struct ifa *b) | |
159 | { return ipa_compare(a->ip, b->ip) < 0; } | |
160 | ||
161 | static inline struct ifa * | |
162 | find_preferred_ifa(struct iface *i, ip_addr prefix, ip_addr mask) | |
163 | { | |
164 | struct ifa *a, *b = NULL; | |
165 | ||
166 | WALK_LIST(a, i->addrs) | |
167 | { | |
168 | if (!(a->flags & IA_SECONDARY) && | |
169 | ipa_equal(ipa_and(a->ip, mask), prefix) && | |
170 | (!b || prefer_scope(a, b) || prefer_addr(a, b))) | |
171 | b = a; | |
172 | } | |
173 | ||
174 | return b; | |
175 | } | |
176 | ||
177 | struct ifa * | |
178 | kif_choose_primary(struct iface *i) | |
179 | { | |
180 | struct kif_config *cf = (struct kif_config *) (kif_proto->p.cf); | |
181 | struct kif_primary_item *it; | |
182 | struct ifa *a; | |
183 | ||
184 | WALK_LIST(it, cf->primary) | |
185 | { | |
186 | if (!it->pattern || patmatch(it->pattern, i->name)) | |
187 | if (a = find_preferred_ifa(i, it->prefix, ipa_mkmask(it->pxlen))) | |
188 | return a; | |
189 | } | |
190 | ||
191 | return find_preferred_ifa(i, IPA_NONE, IPA_NONE); | |
192 | } | |
193 | ||
194 | ||
f7fcb752 MM |
195 | static int |
196 | kif_reconfigure(struct proto *p, struct proto_config *new) | |
197 | { | |
198 | struct kif_config *o = (struct kif_config *) p->cf; | |
199 | struct kif_config *n = (struct kif_config *) new; | |
200 | ||
201 | if (!kif_params_same(&o->iface, &n->iface)) | |
202 | return 0; | |
874b8685 | 203 | |
f7fcb752 MM |
204 | if (o->scan_time != n->scan_time) |
205 | { | |
206 | tm_stop(kif_scan_timer); | |
207 | kif_scan_timer->recurrent = n->scan_time; | |
208 | kif_scan(kif_scan_timer); | |
209 | tm_start(kif_scan_timer, n->scan_time); | |
210 | } | |
874b8685 OZ |
211 | |
212 | if (!EMPTY_LIST(o->primary) || !EMPTY_LIST(n->primary)) | |
213 | { | |
214 | /* This is hack, we have to update a configuration | |
215 | * to the new value just now, because it is used | |
216 | * for recalculation of primary addresses. | |
217 | */ | |
218 | p->cf = new; | |
219 | ||
220 | ifa_recalc_all_primary_addresses(); | |
221 | } | |
222 | ||
f7fcb752 MM |
223 | return 1; |
224 | } | |
225 | ||
a7f23f58 OZ |
226 | static void |
227 | kif_copy_config(struct proto_config *dest, struct proto_config *src) | |
228 | { | |
229 | struct kif_config *d = (struct kif_config *) dest; | |
230 | struct kif_config *s = (struct kif_config *) src; | |
231 | ||
232 | /* Shallow copy of everything (just scan_time currently) */ | |
233 | proto_copy_rest(dest, src, sizeof(struct krt_config)); | |
234 | ||
235 | /* Copy primary addr list */ | |
236 | cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item)); | |
237 | ||
238 | /* Fix sysdep parts */ | |
239 | kif_copy_params(&d->iface, &s->iface); | |
240 | } | |
241 | ||
242 | ||
7e5f5ffd MM |
243 | struct protocol proto_unix_iface = { |
244 | name: "Device", | |
d272fe22 | 245 | template: "device%d", |
39c028e9 | 246 | preference: DEF_PREF_DIRECT, |
50fe90ed | 247 | preconfig: kif_preconfig, |
7e5f5ffd MM |
248 | init: kif_init, |
249 | start: kif_start, | |
250 | shutdown: kif_shutdown, | |
f7fcb752 | 251 | reconfigure: kif_reconfigure, |
a7f23f58 | 252 | copy_config: kif_copy_config |
7e5f5ffd | 253 | }; |
2d140452 | 254 | |
832fa033 MM |
255 | /* |
256 | * Tracing of routes | |
257 | */ | |
258 | ||
cb530392 OZ |
259 | static inline void |
260 | krt_trace_in(struct krt_proto *p, rte *e, char *msg) | |
832fa033 | 261 | { |
cb530392 OZ |
262 | if (p->p.debug & D_PACKETS) |
263 | log(L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg); | |
832fa033 MM |
264 | } |
265 | ||
266 | static inline void | |
cb530392 | 267 | krt_trace_in_rl(struct rate_limit *rl, struct krt_proto *p, rte *e, char *msg) |
832fa033 MM |
268 | { |
269 | if (p->p.debug & D_PACKETS) | |
cb530392 | 270 | log_rl(rl, L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg); |
832fa033 MM |
271 | } |
272 | ||
c10421d3 MM |
273 | /* |
274 | * Inherited Routes | |
275 | */ | |
276 | ||
277 | #ifdef KRT_ALLOW_LEARN | |
278 | ||
cb530392 OZ |
279 | static struct rate_limit rl_alien_seen, rl_alien_updated, rl_alien_created, rl_alien_ignored; |
280 | ||
c10421d3 MM |
281 | static inline int |
282 | krt_same_key(rte *a, rte *b) | |
283 | { | |
284 | return a->u.krt.proto == b->u.krt.proto && | |
285 | a->u.krt.metric == b->u.krt.metric && | |
286 | a->u.krt.type == b->u.krt.type; | |
287 | } | |
288 | ||
289 | static void | |
290 | krt_learn_announce_update(struct krt_proto *p, rte *e) | |
291 | { | |
292 | net *n = e->net; | |
293 | rta *aa = rta_clone(e->attrs); | |
294 | rte *ee = rte_get_temp(aa); | |
08e2d625 | 295 | net *nn = net_get(p->p.table, n->n.prefix, n->n.pxlen); |
c10421d3 MM |
296 | ee->net = nn; |
297 | ee->pflags = 0; | |
1151401e | 298 | ee->pref = p->p.preference; |
c10421d3 | 299 | ee->u.krt = e->u.krt; |
f98e2915 | 300 | rte_update(p->p.table, nn, &p->p, &p->p, ee); |
c10421d3 MM |
301 | } |
302 | ||
303 | static void | |
304 | krt_learn_announce_delete(struct krt_proto *p, net *n) | |
305 | { | |
08e2d625 | 306 | n = net_find(p->p.table, n->n.prefix, n->n.pxlen); |
c10421d3 | 307 | if (n) |
f98e2915 | 308 | rte_update(p->p.table, n, &p->p, &p->p, NULL); |
c10421d3 MM |
309 | } |
310 | ||
311 | static void | |
312 | krt_learn_scan(struct krt_proto *p, rte *e) | |
313 | { | |
314 | net *n0 = e->net; | |
08e2d625 | 315 | net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen); |
c10421d3 MM |
316 | rte *m, **mm; |
317 | ||
318 | e->attrs->source = RTS_INHERIT; | |
319 | ||
320 | for(mm=&n->routes; m = *mm; mm=&m->next) | |
321 | if (krt_same_key(m, e)) | |
322 | break; | |
323 | if (m) | |
324 | { | |
325 | if (krt_uptodate(m, e)) | |
326 | { | |
cb530392 | 327 | krt_trace_in_rl(&rl_alien_seen, p, e, "[alien] seen"); |
c10421d3 MM |
328 | rte_free(e); |
329 | m->u.krt.seen = 1; | |
330 | } | |
331 | else | |
332 | { | |
cb530392 | 333 | krt_trace_in_rl(&rl_alien_updated, p, e, "[alien] updated"); |
c10421d3 MM |
334 | *mm = m->next; |
335 | rte_free(m); | |
336 | m = NULL; | |
337 | } | |
338 | } | |
339 | else | |
cb530392 | 340 | krt_trace_in_rl(&rl_alien_created, p, e, "[alien] created"); |
c10421d3 MM |
341 | if (!m) |
342 | { | |
343 | e->attrs = rta_lookup(e->attrs); | |
344 | e->next = n->routes; | |
345 | n->routes = e; | |
346 | e->u.krt.seen = 1; | |
347 | } | |
348 | } | |
349 | ||
c10421d3 MM |
350 | static void |
351 | krt_learn_prune(struct krt_proto *p) | |
352 | { | |
353 | struct fib *fib = &p->krt_table.fib; | |
354 | struct fib_iterator fit; | |
355 | ||
832fa033 | 356 | KRT_TRACE(p, D_EVENTS, "Pruning inherited routes"); |
c10421d3 MM |
357 | |
358 | FIB_ITERATE_INIT(&fit, fib); | |
359 | again: | |
360 | FIB_ITERATE_START(fib, &fit, f) | |
361 | { | |
362 | net *n = (net *) f; | |
363 | rte *e, **ee, *best, **pbest, *old_best; | |
364 | ||
365 | old_best = n->routes; | |
366 | best = NULL; | |
367 | pbest = NULL; | |
368 | ee = &n->routes; | |
369 | while (e = *ee) | |
370 | { | |
371 | if (!e->u.krt.seen) | |
372 | { | |
373 | *ee = e->next; | |
374 | rte_free(e); | |
375 | continue; | |
376 | } | |
377 | if (!best || best->u.krt.metric > e->u.krt.metric) | |
378 | { | |
379 | best = e; | |
380 | pbest = ee; | |
381 | } | |
382 | e->u.krt.seen = 0; | |
383 | ee = &e->next; | |
384 | } | |
385 | if (!n->routes) | |
386 | { | |
387 | DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen); | |
388 | if (old_best) | |
389 | { | |
390 | krt_learn_announce_delete(p, n); | |
391 | n->n.flags &= ~KRF_INSTALLED; | |
392 | } | |
393 | FIB_ITERATE_PUT(&fit, f); | |
394 | fib_delete(fib, f); | |
395 | goto again; | |
396 | } | |
397 | *pbest = best->next; | |
398 | best->next = n->routes; | |
399 | n->routes = best; | |
400 | if (best != old_best || !(n->n.flags & KRF_INSTALLED)) | |
401 | { | |
402 | DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric); | |
403 | krt_learn_announce_update(p, best); | |
404 | n->n.flags |= KRF_INSTALLED; | |
405 | } | |
406 | else | |
407 | DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric); | |
408 | } | |
409 | FIB_ITERATE_END(f); | |
410 | } | |
411 | ||
412 | static void | |
413 | krt_learn_async(struct krt_proto *p, rte *e, int new) | |
414 | { | |
415 | net *n0 = e->net; | |
08e2d625 | 416 | net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen); |
c10421d3 MM |
417 | rte *g, **gg, *best, **bestp, *old_best; |
418 | ||
419 | e->attrs->source = RTS_INHERIT; | |
420 | ||
421 | old_best = n->routes; | |
422 | for(gg=&n->routes; g = *gg; gg = &g->next) | |
423 | if (krt_same_key(g, e)) | |
424 | break; | |
425 | if (new) | |
426 | { | |
427 | if (g) | |
428 | { | |
429 | if (krt_uptodate(g, e)) | |
430 | { | |
832fa033 | 431 | krt_trace_in(p, e, "[alien async] same"); |
c10421d3 MM |
432 | rte_free(e); |
433 | return; | |
434 | } | |
832fa033 | 435 | krt_trace_in(p, e, "[alien async] updated"); |
c10421d3 MM |
436 | *gg = g->next; |
437 | rte_free(g); | |
438 | } | |
439 | else | |
832fa033 | 440 | krt_trace_in(p, e, "[alien async] created"); |
c10421d3 MM |
441 | e->attrs = rta_lookup(e->attrs); |
442 | e->next = n->routes; | |
443 | n->routes = e; | |
444 | } | |
445 | else if (!g) | |
446 | { | |
832fa033 | 447 | krt_trace_in(p, e, "[alien async] delete failed"); |
c10421d3 MM |
448 | rte_free(e); |
449 | return; | |
450 | } | |
451 | else | |
452 | { | |
832fa033 | 453 | krt_trace_in(p, e, "[alien async] removed"); |
c10421d3 MM |
454 | *gg = g->next; |
455 | rte_free(e); | |
456 | rte_free(g); | |
457 | } | |
458 | best = n->routes; | |
459 | bestp = &n->routes; | |
460 | for(gg=&n->routes; g=*gg; gg=&g->next) | |
461 | if (best->u.krt.metric > g->u.krt.metric) | |
462 | { | |
463 | best = g; | |
464 | bestp = gg; | |
465 | } | |
466 | if (best) | |
467 | { | |
468 | *bestp = best->next; | |
469 | best->next = n->routes; | |
470 | n->routes = best; | |
471 | } | |
472 | if (best != old_best) | |
473 | { | |
474 | DBG("krt_learn_async: distributing change\n"); | |
475 | if (best) | |
476 | { | |
477 | krt_learn_announce_update(p, best); | |
478 | n->n.flags |= KRF_INSTALLED; | |
479 | } | |
480 | else | |
481 | { | |
482 | n->routes = NULL; | |
483 | krt_learn_announce_delete(p, n); | |
484 | n->n.flags &= ~KRF_INSTALLED; | |
485 | } | |
486 | } | |
487 | } | |
488 | ||
489 | static void | |
490 | krt_learn_init(struct krt_proto *p) | |
491 | { | |
492 | if (KRT_CF->learn) | |
b9626ec6 | 493 | rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL); |
c10421d3 MM |
494 | } |
495 | ||
496 | static void | |
497 | krt_dump(struct proto *P) | |
498 | { | |
499 | struct krt_proto *p = (struct krt_proto *) P; | |
500 | ||
501 | if (!KRT_CF->learn) | |
502 | return; | |
503 | debug("KRT: Table of inheritable routes\n"); | |
504 | rt_dump(&p->krt_table); | |
505 | } | |
506 | ||
507 | static void | |
508 | krt_dump_attrs(rte *e) | |
509 | { | |
510 | debug(" [m=%d,p=%d,t=%d]", e->u.krt.metric, e->u.krt.proto, e->u.krt.type); | |
511 | } | |
512 | ||
513 | #endif | |
514 | ||
2d140452 MM |
515 | /* |
516 | * Routes | |
517 | */ | |
518 | ||
7de45ba4 MM |
519 | #ifdef CONFIG_ALL_TABLES_AT_ONCE |
520 | static timer *krt_scan_timer; | |
521 | static int krt_instance_count; | |
522 | static list krt_instance_list; | |
523 | #endif | |
524 | ||
2d140452 MM |
525 | static void |
526 | krt_flush_routes(struct krt_proto *p) | |
527 | { | |
4f1a6d27 | 528 | struct rtable *t = p->p.table; |
2d140452 | 529 | |
832fa033 | 530 | KRT_TRACE(p, D_EVENTS, "Flushing kernel routes"); |
2d140452 MM |
531 | FIB_WALK(&t->fib, f) |
532 | { | |
533 | net *n = (net *) f; | |
534 | rte *e = n->routes; | |
535 | if (e) | |
536 | { | |
537 | rta *a = e->attrs; | |
3d574679 OZ |
538 | if ((n->n.flags & KRF_INSTALLED) && |
539 | a->source != RTS_DEVICE && a->source != RTS_INHERIT) | |
540 | { | |
541 | krt_set_notify(p, e->net, NULL, e); | |
542 | n->n.flags &= ~KRF_INSTALLED; | |
543 | } | |
2d140452 MM |
544 | } |
545 | } | |
546 | FIB_WALK_END; | |
547 | } | |
548 | ||
2d140452 MM |
549 | static int |
550 | krt_uptodate(rte *k, rte *e) | |
551 | { | |
552 | rta *ka = k->attrs, *ea = e->attrs; | |
553 | ||
554 | if (ka->dest != ea->dest) | |
555 | return 0; | |
556 | switch (ka->dest) | |
557 | { | |
558 | case RTD_ROUTER: | |
559 | return ipa_equal(ka->gw, ea->gw); | |
560 | case RTD_DEVICE: | |
561 | return !strcmp(ka->iface->name, ea->iface->name); | |
562 | default: | |
563 | return 1; | |
564 | } | |
565 | } | |
566 | ||
567 | /* | |
568 | * This gets called back when the low-level scanning code discovers a route. | |
569 | * We expect that the route is a temporary rte and its attributes are uncached. | |
570 | */ | |
571 | ||
572 | void | |
573 | krt_got_route(struct krt_proto *p, rte *e) | |
574 | { | |
575 | rte *old; | |
576 | net *net = e->net; | |
577 | int verdict; | |
578 | ||
ff2857b0 OZ |
579 | #ifdef KRT_ALLOW_LEARN |
580 | switch (e->u.krt.src) | |
c10421d3 | 581 | { |
ff2857b0 | 582 | case KRT_SRC_KERNEL: |
c10421d3 MM |
583 | verdict = KRF_IGNORE; |
584 | goto sentenced; | |
c10421d3 | 585 | |
ff2857b0 OZ |
586 | case KRT_SRC_REDIRECT: |
587 | verdict = KRF_DELETE; | |
588 | goto sentenced; | |
589 | ||
590 | case KRT_SRC_ALIEN: | |
c10421d3 MM |
591 | if (KRT_CF->learn) |
592 | krt_learn_scan(p, e); | |
593 | else | |
c197d44e | 594 | { |
ff2857b0 | 595 | krt_trace_in_rl(&rl_alien_ignored, p, e, "[alien] ignored"); |
c197d44e MM |
596 | rte_free(e); |
597 | } | |
c10421d3 MM |
598 | return; |
599 | } | |
600 | #endif | |
ff2857b0 | 601 | /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */ |
c10421d3 MM |
602 | |
603 | if (net->n.flags & KRF_VERDICT_MASK) | |
2d140452 MM |
604 | { |
605 | /* Route to this destination was already seen. Strange, but it happens... */ | |
832fa033 | 606 | krt_trace_in(p, e, "already seen"); |
c197d44e | 607 | rte_free(e); |
2d140452 MM |
608 | return; |
609 | } | |
610 | ||
46c1a583 OZ |
611 | old = net->routes; |
612 | if ((net->n.flags & KRF_INSTALLED) && old) | |
2d140452 | 613 | { |
c10421d3 | 614 | if (krt_uptodate(e, old)) |
2d140452 MM |
615 | verdict = KRF_SEEN; |
616 | else | |
617 | verdict = KRF_UPDATE; | |
618 | } | |
2d140452 MM |
619 | else |
620 | verdict = KRF_DELETE; | |
621 | ||
ff2857b0 | 622 | sentenced: |
832fa033 | 623 | krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]); |
c10421d3 MM |
624 | net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict; |
625 | if (verdict == KRF_UPDATE || verdict == KRF_DELETE) | |
2d140452 MM |
626 | { |
627 | /* Get a cached copy of attributes and link the route */ | |
628 | rta *a = e->attrs; | |
629 | a->source = RTS_DUMMY; | |
630 | e->attrs = rta_lookup(a); | |
631 | e->next = net->routes; | |
632 | net->routes = e; | |
633 | } | |
634 | else | |
635 | rte_free(e); | |
636 | } | |
637 | ||
638 | static void | |
639 | krt_prune(struct krt_proto *p) | |
640 | { | |
4f1a6d27 | 641 | struct rtable *t = p->p.table; |
2d140452 | 642 | |
832fa033 | 643 | KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name); |
2d140452 MM |
644 | FIB_WALK(&t->fib, f) |
645 | { | |
646 | net *n = (net *) f; | |
c10421d3 | 647 | int verdict = f->flags & KRF_VERDICT_MASK; |
2d140452 MM |
648 | rte *new, *old; |
649 | ||
c10421d3 | 650 | if (verdict != KRF_CREATE && verdict != KRF_SEEN && verdict != KRF_IGNORE) |
2d140452 MM |
651 | { |
652 | old = n->routes; | |
653 | n->routes = old->next; | |
654 | } | |
655 | else | |
656 | old = NULL; | |
657 | new = n->routes; | |
658 | ||
659 | switch (verdict) | |
660 | { | |
661 | case KRF_CREATE: | |
c10421d3 | 662 | if (new && (f->flags & KRF_INSTALLED)) |
2d140452 | 663 | { |
832fa033 | 664 | krt_trace_in(p, new, "reinstalling"); |
c10421d3 | 665 | krt_set_notify(p, n, new, NULL); |
2d140452 MM |
666 | } |
667 | break; | |
668 | case KRF_SEEN: | |
c10421d3 | 669 | case KRF_IGNORE: |
2d140452 MM |
670 | /* Nothing happens */ |
671 | break; | |
672 | case KRF_UPDATE: | |
832fa033 | 673 | krt_trace_in(p, new, "updating"); |
c10421d3 | 674 | krt_set_notify(p, n, new, old); |
2d140452 MM |
675 | break; |
676 | case KRF_DELETE: | |
1151401e | 677 | krt_trace_in(p, old, "deleting"); |
c10421d3 | 678 | krt_set_notify(p, n, NULL, old); |
2d140452 MM |
679 | break; |
680 | default: | |
681 | bug("krt_prune: invalid route status"); | |
682 | } | |
2d140452 MM |
683 | if (old) |
684 | rte_free(old); | |
c10421d3 | 685 | f->flags &= ~KRF_VERDICT_MASK; |
2d140452 MM |
686 | } |
687 | FIB_WALK_END; | |
c10421d3 MM |
688 | |
689 | #ifdef KRT_ALLOW_LEARN | |
690 | if (KRT_CF->learn) | |
691 | krt_learn_prune(p); | |
692 | #endif | |
aa8761de | 693 | p->initialized = 1; |
2d140452 MM |
694 | } |
695 | ||
e16155ae | 696 | void |
ff2857b0 | 697 | krt_got_route_async(struct krt_proto *p, rte *e, int new) |
e16155ae MM |
698 | { |
699 | net *net = e->net; | |
e16155ae | 700 | |
ff2857b0 | 701 | switch (e->u.krt.src) |
e16155ae MM |
702 | { |
703 | case KRT_SRC_BIRD: | |
832fa033 | 704 | ASSERT(0); /* Should be filtered by the back end */ |
ff2857b0 | 705 | |
e16155ae | 706 | case KRT_SRC_REDIRECT: |
ff2857b0 OZ |
707 | if (new) |
708 | { | |
709 | krt_trace_in(p, e, "[redirect] deleting"); | |
710 | krt_set_notify(p, net, NULL, e); | |
711 | } | |
712 | /* If !new, it is probably echo of our deletion */ | |
e16155ae | 713 | break; |
ff2857b0 | 714 | |
c10421d3 | 715 | #ifdef KRT_ALLOW_LEARN |
1bc4b2cc | 716 | case KRT_SRC_ALIEN: |
c10421d3 | 717 | if (KRT_CF->learn) |
e16155ae | 718 | { |
c10421d3 MM |
719 | krt_learn_async(p, e, new); |
720 | return; | |
e16155ae | 721 | } |
c10421d3 | 722 | #endif |
e16155ae | 723 | } |
c10421d3 | 724 | rte_free(e); |
e16155ae MM |
725 | } |
726 | ||
2d140452 MM |
727 | /* |
728 | * Periodic scanning | |
729 | */ | |
730 | ||
2d140452 | 731 | static void |
6578a604 | 732 | krt_scan(timer *t UNUSED) |
2d140452 | 733 | { |
7de45ba4 | 734 | struct krt_proto *p; |
2d140452 | 735 | |
7e5f5ffd | 736 | kif_force_scan(); |
7de45ba4 MM |
737 | #ifdef CONFIG_ALL_TABLES_AT_ONCE |
738 | { | |
739 | void *q; | |
832fa033 MM |
740 | /* We need some node to decide whether to print the debug messages or not */ |
741 | p = SKIP_BACK(struct krt_proto, instance_node, HEAD(krt_instance_list)); | |
742 | if (p->instance_node.next) | |
743 | KRT_TRACE(p, D_EVENTS, "Scanning routing table"); | |
7de45ba4 MM |
744 | krt_scan_fire(NULL); |
745 | WALK_LIST(q, krt_instance_list) | |
746 | { | |
747 | p = SKIP_BACK(struct krt_proto, instance_node, q); | |
748 | krt_prune(p); | |
749 | } | |
750 | } | |
751 | #else | |
752 | p = t->data; | |
832fa033 | 753 | KRT_TRACE(p, D_EVENTS, "Scanning routing table"); |
7e5f5ffd MM |
754 | krt_scan_fire(p); |
755 | krt_prune(p); | |
7de45ba4 | 756 | #endif |
2d140452 MM |
757 | } |
758 | ||
c10421d3 MM |
759 | /* |
760 | * Updates | |
761 | */ | |
c429d4a4 OZ |
762 | static int |
763 | krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool) | |
764 | { | |
765 | struct krt_proto *p = (struct krt_proto *) P; | |
766 | rte *e = *new; | |
767 | ||
768 | if (e->attrs->proto == P) | |
769 | return -1; | |
770 | ||
771 | if (!KRT_CF->devroutes && | |
772 | (e->attrs->dest == RTD_DEVICE) && | |
773 | (e->attrs->source != RTS_STATIC_DEVICE)) | |
774 | return -1; | |
775 | ||
776 | if (!krt_capable(e)) | |
777 | return -1; | |
778 | ||
779 | return 0; | |
780 | } | |
c10421d3 MM |
781 | |
782 | static void | |
dca75fd7 OZ |
783 | krt_notify(struct proto *P, struct rtable *table UNUSED, net *net, |
784 | rte *new, rte *old, struct ea_list *attrs UNUSED) | |
c10421d3 MM |
785 | { |
786 | struct krt_proto *p = (struct krt_proto *) P; | |
787 | ||
1567edea | 788 | if (shutting_down) |
f990fc61 | 789 | return; |
c10421d3 MM |
790 | if (!(net->n.flags & KRF_INSTALLED)) |
791 | old = NULL; | |
792 | if (new) | |
793 | net->n.flags |= KRF_INSTALLED; | |
794 | else | |
795 | net->n.flags &= ~KRF_INSTALLED; | |
aa8761de MM |
796 | if (p->initialized) /* Before first scan we don't touch the routes */ |
797 | krt_set_notify(p, net, new, old); | |
c10421d3 MM |
798 | } |
799 | ||
2d140452 MM |
800 | /* |
801 | * Protocol glue | |
802 | */ | |
803 | ||
7e5f5ffd MM |
804 | struct proto_config *cf_krt; |
805 | ||
7de45ba4 | 806 | static void |
6578a604 | 807 | krt_preconfig(struct protocol *P UNUSED, struct config *c) |
7de45ba4 | 808 | { |
50fe90ed | 809 | cf_krt = NULL; |
7de45ba4 MM |
810 | krt_scan_preconfig(c); |
811 | } | |
812 | ||
813 | static void | |
814 | krt_postconfig(struct proto_config *C) | |
815 | { | |
816 | struct krt_config *c = (struct krt_config *) C; | |
817 | ||
818 | #ifdef CONFIG_ALL_TABLES_AT_ONCE | |
819 | struct krt_config *first = (struct krt_config *) cf_krt; | |
820 | if (first->scan_time != c->scan_time) | |
821 | cf_error("All kernel syncers must use the same table scan interval"); | |
822 | #endif | |
823 | ||
824 | if (C->table->krt_attached) | |
825 | cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name); | |
826 | C->table->krt_attached = C; | |
827 | krt_scan_postconfig(c); | |
828 | } | |
829 | ||
830 | static timer * | |
831 | krt_start_timer(struct krt_proto *p) | |
832 | { | |
833 | timer *t; | |
834 | ||
835 | t = tm_new(p->krt_pool); | |
836 | t->hook = krt_scan; | |
837 | t->data = p; | |
838 | t->recurrent = KRT_CF->scan_time; | |
aa8761de | 839 | tm_start(t, 0); |
7de45ba4 MM |
840 | return t; |
841 | } | |
842 | ||
2d140452 MM |
843 | static int |
844 | krt_start(struct proto *P) | |
845 | { | |
846 | struct krt_proto *p = (struct krt_proto *) P; | |
7de45ba4 MM |
847 | int first = 1; |
848 | ||
849 | #ifdef CONFIG_ALL_TABLES_AT_ONCE | |
850 | if (!krt_instance_count++) | |
851 | init_list(&krt_instance_list); | |
852 | else | |
853 | first = 0; | |
854 | p->krt_pool = krt_pool; | |
855 | add_tail(&krt_instance_list, &p->instance_node); | |
856 | #else | |
857 | p->krt_pool = P->pool; | |
858 | #endif | |
2d140452 | 859 | |
c10421d3 MM |
860 | #ifdef KRT_ALLOW_LEARN |
861 | krt_learn_init(p); | |
862 | #endif | |
863 | ||
7de45ba4 MM |
864 | krt_scan_start(p, first); |
865 | krt_set_start(p, first); | |
2d140452 | 866 | |
7e5f5ffd | 867 | /* Start periodic routing table scanning */ |
7de45ba4 MM |
868 | #ifdef CONFIG_ALL_TABLES_AT_ONCE |
869 | if (first) | |
870 | krt_scan_timer = krt_start_timer(p); | |
aa8761de | 871 | else |
35f983f8 | 872 | tm_start(krt_scan_timer, 0); |
7de45ba4 | 873 | p->scan_timer = krt_scan_timer; |
7de45ba4 MM |
874 | #else |
875 | p->scan_timer = krt_start_timer(p); | |
7de45ba4 | 876 | #endif |
2d140452 MM |
877 | |
878 | return PS_UP; | |
879 | } | |
880 | ||
7de45ba4 | 881 | static int |
2d140452 MM |
882 | krt_shutdown(struct proto *P) |
883 | { | |
884 | struct krt_proto *p = (struct krt_proto *) P; | |
7de45ba4 | 885 | int last = 1; |
2d140452 | 886 | |
7de45ba4 MM |
887 | #ifdef CONFIG_ALL_TABLES_AT_ONCE |
888 | rem_node(&p->instance_node); | |
889 | if (--krt_instance_count) | |
890 | last = 0; | |
891 | else | |
892 | #endif | |
893 | tm_stop(p->scan_timer); | |
7e5f5ffd | 894 | |
3d574679 OZ |
895 | /* FIXME we should flush routes even when persist during reconfiguration */ |
896 | if (p->initialized && !KRT_CF->persist) | |
2d140452 MM |
897 | krt_flush_routes(p); |
898 | ||
7de45ba4 MM |
899 | krt_set_shutdown(p, last); |
900 | krt_scan_shutdown(p, last); | |
901 | ||
902 | #ifdef CONFIG_ALL_TABLES_AT_ONCE | |
903 | if (last) | |
904 | rfree(krt_scan_timer); | |
905 | #endif | |
2d140452 | 906 | |
2d140452 MM |
907 | return PS_DOWN; |
908 | } | |
909 | ||
9ba2798c | 910 | static struct ea_list * |
72aed1a0 OZ |
911 | krt_make_tmp_attrs(struct rte *rt, struct linpool *pool) |
912 | { | |
9ba2798c | 913 | struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr)); |
72aed1a0 OZ |
914 | |
915 | l->next = NULL; | |
916 | l->flags = EALF_SORTED; | |
9ba2798c OZ |
917 | l->count = 2; |
918 | ||
72aed1a0 OZ |
919 | l->attrs[0].id = EA_KRT_SOURCE; |
920 | l->attrs[0].flags = 0; | |
921 | l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP; | |
922 | l->attrs[0].u.data = rt->u.krt.proto; | |
923 | ||
9ba2798c OZ |
924 | l->attrs[1].id = EA_KRT_METRIC; |
925 | l->attrs[1].flags = 0; | |
926 | l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP; | |
927 | l->attrs[1].u.data = rt->u.krt.metric; | |
928 | ||
72aed1a0 OZ |
929 | return l; |
930 | } | |
931 | ||
9ba2798c OZ |
932 | static void |
933 | krt_store_tmp_attrs(struct rte *rt, struct ea_list *attrs) | |
934 | { | |
935 | /* EA_KRT_SOURCE is read-only */ | |
936 | rt->u.krt.metric = ea_get_int(attrs, EA_KRT_METRIC, 0); | |
937 | } | |
938 | ||
939 | ||
2d140452 MM |
940 | static struct proto * |
941 | krt_init(struct proto_config *c) | |
942 | { | |
943 | struct krt_proto *p = proto_new(c, sizeof(struct krt_proto)); | |
944 | ||
23ac9e9a | 945 | p->p.accept_ra_types = RA_OPTIMAL; |
72aed1a0 | 946 | p->p.make_tmp_attrs = krt_make_tmp_attrs; |
9ba2798c | 947 | p->p.store_tmp_attrs = krt_store_tmp_attrs; |
c429d4a4 | 948 | p->p.import_control = krt_import_control; |
c10421d3 | 949 | p->p.rt_notify = krt_notify; |
71ca7716 | 950 | |
2d140452 MM |
951 | return &p->p; |
952 | } | |
953 | ||
aa8761de MM |
954 | static int |
955 | krt_reconfigure(struct proto *p, struct proto_config *new) | |
956 | { | |
957 | struct krt_config *o = (struct krt_config *) p->cf; | |
958 | struct krt_config *n = (struct krt_config *) new; | |
959 | ||
960 | return o->scan_time == n->scan_time | |
961 | && o->learn == n->learn /* persist needn't be the same */ | |
f038f0a6 | 962 | && o->devroutes == n->devroutes |
aa8761de MM |
963 | && krt_set_params_same(&o->set, &n->set) |
964 | && krt_scan_params_same(&o->scan, &n->scan) | |
965 | ; | |
966 | } | |
967 | ||
a7f23f58 OZ |
968 | static void |
969 | krt_copy_config(struct proto_config *dest, struct proto_config *src) | |
970 | { | |
971 | struct krt_config *d = (struct krt_config *) dest; | |
972 | struct krt_config *s = (struct krt_config *) src; | |
973 | ||
974 | /* Shallow copy of everything */ | |
975 | proto_copy_rest(dest, src, sizeof(struct krt_config)); | |
976 | ||
977 | /* Fix sysdep parts */ | |
978 | krt_set_copy_params(&d->set, &s->set); | |
979 | krt_scan_copy_params(&d->scan, &s->scan); | |
980 | } | |
71ca7716 OZ |
981 | |
982 | static int | |
983 | krt_get_attr(eattr * a, byte * buf, int buflen UNUSED) | |
984 | { | |
985 | switch (a->id) | |
986 | { | |
72aed1a0 OZ |
987 | case EA_KRT_SOURCE: |
988 | bsprintf(buf, "source"); | |
989 | return GA_NAME; | |
990 | ||
9ba2798c OZ |
991 | case EA_KRT_METRIC: |
992 | bsprintf(buf, "metric"); | |
993 | return GA_NAME; | |
994 | ||
71ca7716 OZ |
995 | case EA_KRT_PREFSRC: |
996 | bsprintf(buf, "prefsrc"); | |
997 | return GA_NAME; | |
72aed1a0 | 998 | |
71ca7716 OZ |
999 | case EA_KRT_REALM: |
1000 | bsprintf(buf, "realm"); | |
1001 | return GA_NAME; | |
72aed1a0 | 1002 | |
71ca7716 OZ |
1003 | default: |
1004 | return GA_UNKNOWN; | |
1005 | } | |
1006 | } | |
1007 | ||
1008 | ||
2d140452 MM |
1009 | struct protocol proto_unix_kernel = { |
1010 | name: "Kernel", | |
d272fe22 | 1011 | template: "kernel%d", |
71ca7716 | 1012 | attr_class: EAP_KRT, |
39c028e9 | 1013 | preference: DEF_PREF_INHERITED, |
7de45ba4 MM |
1014 | preconfig: krt_preconfig, |
1015 | postconfig: krt_postconfig, | |
2d140452 MM |
1016 | init: krt_init, |
1017 | start: krt_start, | |
1018 | shutdown: krt_shutdown, | |
aa8761de | 1019 | reconfigure: krt_reconfigure, |
a7f23f58 | 1020 | copy_config: krt_copy_config, |
71ca7716 | 1021 | get_attr: krt_get_attr, |
c10421d3 MM |
1022 | #ifdef KRT_ALLOW_LEARN |
1023 | dump: krt_dump, | |
1024 | dump_attrs: krt_dump_attrs, | |
1025 | #endif | |
2d140452 | 1026 | }; |