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