]>
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 | |
4a23ede2 MM |
246 | void |
247 | kif_build(void) | |
248 | { | |
249 | proto_build(&proto_unix_iface); | |
250 | } | |
251 | ||
252 | ||
832fa033 MM |
253 | /* |
254 | * Tracing of routes | |
255 | */ | |
256 | ||
cb530392 OZ |
257 | static inline void |
258 | krt_trace_in(struct krt_proto *p, rte *e, char *msg) | |
832fa033 | 259 | { |
cb530392 | 260 | if (p->p.debug & D_PACKETS) |
fe9f1a6d | 261 | log(L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg); |
832fa033 MM |
262 | } |
263 | ||
264 | static inline void | |
1123e707 | 265 | krt_trace_in_rl(struct tbf *f, struct krt_proto *p, rte *e, char *msg) |
832fa033 MM |
266 | { |
267 | if (p->p.debug & D_PACKETS) | |
fe9f1a6d | 268 | log_rl(f, L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg); |
832fa033 MM |
269 | } |
270 | ||
c10421d3 MM |
271 | /* |
272 | * Inherited Routes | |
273 | */ | |
274 | ||
275 | #ifdef KRT_ALLOW_LEARN | |
276 | ||
1123e707 | 277 | static struct tbf rl_alien = TBF_DEFAULT_LOG_LIMITS; |
cb530392 | 278 | |
c9df01d3 OZ |
279 | /* |
280 | * krt_same_key() specifies what (aside from the net) is the key in | |
281 | * kernel routing tables. It should be OS-dependent, this is for | |
282 | * Linux. It is important for asynchronous alien updates, because a | |
283 | * positive update is implicitly a negative one for any old route with | |
284 | * the same key. | |
285 | */ | |
286 | ||
e42eedb9 MM |
287 | static inline u32 |
288 | krt_metric(rte *a) | |
289 | { | |
290 | eattr *ea = ea_find(a->attrs->eattrs, EA_KRT_METRIC); | |
291 | return ea ? ea->u.data : 0; | |
292 | } | |
293 | ||
c10421d3 MM |
294 | static inline int |
295 | krt_same_key(rte *a, rte *b) | |
296 | { | |
e42eedb9 | 297 | return (krt_metric(a) == krt_metric(b)); |
c9df01d3 OZ |
298 | } |
299 | ||
300 | static inline int | |
301 | krt_uptodate(rte *a, rte *b) | |
302 | { | |
e42eedb9 | 303 | return (a->attrs == b->attrs); |
c10421d3 MM |
304 | } |
305 | ||
306 | static void | |
307 | krt_learn_announce_update(struct krt_proto *p, rte *e) | |
308 | { | |
309 | net *n = e->net; | |
310 | rta *aa = rta_clone(e->attrs); | |
5cff1d5f | 311 | rte *ee = rte_get_temp(aa, p->p.main_source); |
2003a184 | 312 | rte_update(&p->p, n->n.addr, ee); |
c10421d3 MM |
313 | } |
314 | ||
315 | static void | |
316 | krt_learn_announce_delete(struct krt_proto *p, net *n) | |
317 | { | |
2003a184 | 318 | rte_update(&p->p, n->n.addr, NULL); |
c10421d3 MM |
319 | } |
320 | ||
0f2be469 AZ |
321 | static void |
322 | krt_learn_alien_attr(struct channel *c, rte *e) | |
323 | { | |
324 | ASSERT(!e->attrs->cached); | |
325 | e->attrs->pref = c->preference; | |
326 | ||
327 | e->attrs = rta_lookup(e->attrs); | |
328 | } | |
329 | ||
c9df01d3 | 330 | /* Called when alien route is discovered during scan */ |
c10421d3 MM |
331 | static void |
332 | krt_learn_scan(struct krt_proto *p, rte *e) | |
333 | { | |
334 | net *n0 = e->net; | |
ff397df7 | 335 | net *n = net_get(p->krt_table, n0->n.addr); |
c10421d3 MM |
336 | rte *m, **mm; |
337 | ||
0f2be469 | 338 | krt_learn_alien_attr(p->p.main_channel, e); |
c10421d3 MM |
339 | |
340 | for(mm=&n->routes; m = *mm; mm=&m->next) | |
341 | if (krt_same_key(m, e)) | |
342 | break; | |
343 | if (m) | |
344 | { | |
345 | if (krt_uptodate(m, e)) | |
346 | { | |
1123e707 | 347 | krt_trace_in_rl(&rl_alien, p, e, "[alien] seen"); |
c10421d3 | 348 | rte_free(e); |
e42eedb9 | 349 | m->pflags |= KRT_REF_SEEN; |
c10421d3 MM |
350 | } |
351 | else | |
352 | { | |
1123e707 | 353 | krt_trace_in(p, e, "[alien] updated"); |
c10421d3 MM |
354 | *mm = m->next; |
355 | rte_free(m); | |
356 | m = NULL; | |
357 | } | |
358 | } | |
359 | else | |
1123e707 | 360 | krt_trace_in(p, e, "[alien] created"); |
c10421d3 MM |
361 | if (!m) |
362 | { | |
c10421d3 MM |
363 | e->next = n->routes; |
364 | n->routes = e; | |
e42eedb9 | 365 | e->pflags |= KRT_REF_SEEN; |
c10421d3 MM |
366 | } |
367 | } | |
368 | ||
c10421d3 MM |
369 | static void |
370 | krt_learn_prune(struct krt_proto *p) | |
371 | { | |
ff397df7 | 372 | struct fib *fib = &p->krt_table->fib; |
c10421d3 MM |
373 | struct fib_iterator fit; |
374 | ||
832fa033 | 375 | KRT_TRACE(p, D_EVENTS, "Pruning inherited routes"); |
c10421d3 MM |
376 | |
377 | FIB_ITERATE_INIT(&fit, fib); | |
378 | again: | |
600998fc | 379 | FIB_ITERATE_START(fib, &fit, net, n) |
c10421d3 | 380 | { |
c10421d3 MM |
381 | rte *e, **ee, *best, **pbest, *old_best; |
382 | ||
e86cfd41 OZ |
383 | /* |
384 | * Note that old_best may be NULL even if there was an old best route in | |
385 | * the previous step, because it might be replaced in krt_learn_scan(). | |
386 | * But in that case there is a new valid best route. | |
387 | */ | |
388 | ||
389 | old_best = NULL; | |
c10421d3 MM |
390 | best = NULL; |
391 | pbest = NULL; | |
392 | ee = &n->routes; | |
393 | while (e = *ee) | |
394 | { | |
e42eedb9 | 395 | if (e->pflags & KRT_REF_BEST) |
e86cfd41 OZ |
396 | old_best = e; |
397 | ||
e42eedb9 | 398 | if (!(e->pflags & KRT_REF_SEEN)) |
c10421d3 MM |
399 | { |
400 | *ee = e->next; | |
401 | rte_free(e); | |
402 | continue; | |
403 | } | |
e86cfd41 | 404 | |
e42eedb9 | 405 | if (!best || krt_metric(best) > krt_metric(e)) |
c10421d3 MM |
406 | { |
407 | best = e; | |
408 | pbest = ee; | |
409 | } | |
e86cfd41 | 410 | |
e42eedb9 | 411 | e->pflags &= ~(KRT_REF_SEEN | KRT_REF_BEST); |
c10421d3 MM |
412 | ee = &e->next; |
413 | } | |
414 | if (!n->routes) | |
415 | { | |
416 | DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen); | |
417 | if (old_best) | |
e86cfd41 OZ |
418 | krt_learn_announce_delete(p, n); |
419 | ||
600998fc OZ |
420 | FIB_ITERATE_PUT(&fit); |
421 | fib_delete(fib, n); | |
c10421d3 MM |
422 | goto again; |
423 | } | |
e86cfd41 | 424 | |
e42eedb9 | 425 | best->pflags |= KRT_REF_BEST; |
c10421d3 MM |
426 | *pbest = best->next; |
427 | best->next = n->routes; | |
428 | n->routes = best; | |
e86cfd41 OZ |
429 | |
430 | if ((best != old_best) || p->reload) | |
c10421d3 | 431 | { |
e42eedb9 | 432 | DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, krt_metric(best)); |
c10421d3 | 433 | krt_learn_announce_update(p, best); |
c10421d3 MM |
434 | } |
435 | else | |
e42eedb9 | 436 | DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, krt_metric(best)); |
c10421d3 | 437 | } |
600998fc | 438 | FIB_ITERATE_END; |
7069fc9e OZ |
439 | |
440 | p->reload = 0; | |
c10421d3 MM |
441 | } |
442 | ||
443 | static void | |
444 | krt_learn_async(struct krt_proto *p, rte *e, int new) | |
445 | { | |
446 | net *n0 = e->net; | |
ff397df7 | 447 | net *n = net_get(p->krt_table, n0->n.addr); |
c10421d3 MM |
448 | rte *g, **gg, *best, **bestp, *old_best; |
449 | ||
0f2be469 | 450 | krt_learn_alien_attr(p->p.main_channel, e); |
c10421d3 MM |
451 | |
452 | old_best = n->routes; | |
453 | for(gg=&n->routes; g = *gg; gg = &g->next) | |
454 | if (krt_same_key(g, e)) | |
455 | break; | |
456 | if (new) | |
457 | { | |
458 | if (g) | |
459 | { | |
460 | if (krt_uptodate(g, e)) | |
461 | { | |
832fa033 | 462 | krt_trace_in(p, e, "[alien async] same"); |
c10421d3 MM |
463 | rte_free(e); |
464 | return; | |
465 | } | |
832fa033 | 466 | krt_trace_in(p, e, "[alien async] updated"); |
c10421d3 MM |
467 | *gg = g->next; |
468 | rte_free(g); | |
469 | } | |
470 | else | |
832fa033 | 471 | krt_trace_in(p, e, "[alien async] created"); |
c9df01d3 | 472 | |
c10421d3 MM |
473 | e->next = n->routes; |
474 | n->routes = e; | |
475 | } | |
476 | else if (!g) | |
477 | { | |
832fa033 | 478 | krt_trace_in(p, e, "[alien async] delete failed"); |
c10421d3 MM |
479 | rte_free(e); |
480 | return; | |
481 | } | |
482 | else | |
483 | { | |
832fa033 | 484 | krt_trace_in(p, e, "[alien async] removed"); |
c10421d3 MM |
485 | *gg = g->next; |
486 | rte_free(e); | |
487 | rte_free(g); | |
488 | } | |
489 | best = n->routes; | |
490 | bestp = &n->routes; | |
491 | for(gg=&n->routes; g=*gg; gg=&g->next) | |
e86cfd41 | 492 | { |
e42eedb9 | 493 | if (krt_metric(best) > krt_metric(g)) |
c10421d3 MM |
494 | { |
495 | best = g; | |
496 | bestp = gg; | |
497 | } | |
e86cfd41 | 498 | |
e42eedb9 | 499 | g->pflags &= ~KRT_REF_BEST; |
e86cfd41 OZ |
500 | } |
501 | ||
c10421d3 MM |
502 | if (best) |
503 | { | |
e42eedb9 | 504 | best->pflags |= KRT_REF_BEST; |
c10421d3 MM |
505 | *bestp = best->next; |
506 | best->next = n->routes; | |
507 | n->routes = best; | |
508 | } | |
e86cfd41 | 509 | |
c10421d3 MM |
510 | if (best != old_best) |
511 | { | |
512 | DBG("krt_learn_async: distributing change\n"); | |
513 | if (best) | |
e86cfd41 | 514 | krt_learn_announce_update(p, best); |
c10421d3 | 515 | else |
e86cfd41 | 516 | krt_learn_announce_delete(p, n); |
c10421d3 MM |
517 | } |
518 | } | |
519 | ||
520 | static void | |
521 | krt_learn_init(struct krt_proto *p) | |
522 | { | |
523 | if (KRT_CF->learn) | |
28b3b551 OZ |
524 | { |
525 | struct rtable_config *cf = mb_allocz(p->p.pool, sizeof(struct rtable_config)); | |
526 | cf->name = "Inherited"; | |
527 | cf->addr_type = p->p.net_type; | |
ff397df7 | 528 | cf->internal = 1; |
28b3b551 | 529 | |
ff397df7 | 530 | p->krt_table = rt_setup(p->p.pool, cf); |
28b3b551 | 531 | } |
c10421d3 MM |
532 | } |
533 | ||
534 | static void | |
535 | krt_dump(struct proto *P) | |
536 | { | |
537 | struct krt_proto *p = (struct krt_proto *) P; | |
538 | ||
539 | if (!KRT_CF->learn) | |
540 | return; | |
541 | debug("KRT: Table of inheritable routes\n"); | |
ff397df7 | 542 | rt_dump(p->krt_table); |
c10421d3 MM |
543 | } |
544 | ||
c10421d3 MM |
545 | #endif |
546 | ||
2d140452 MM |
547 | /* |
548 | * Routes | |
549 | */ | |
550 | ||
c132acae | 551 | static inline int |
90a9c97e | 552 | krt_is_installed(struct krt_proto *p, net *n) |
c132acae | 553 | { |
90a9c97e | 554 | return n->routes && bmap_test(&p->p.main_channel->export_map, n->routes->id); |
c132acae OZ |
555 | } |
556 | ||
2d140452 MM |
557 | static void |
558 | krt_flush_routes(struct krt_proto *p) | |
559 | { | |
f4a60a9b | 560 | struct rtable *t = p->p.main_channel->table; |
2d140452 | 561 | |
832fa033 | 562 | KRT_TRACE(p, D_EVENTS, "Flushing kernel routes"); |
600998fc | 563 | FIB_WALK(&t->fib, net, n) |
2d140452 | 564 | { |
90a9c97e | 565 | if (krt_is_installed(p, n)) |
2d140452 | 566 | { |
e14bd380 | 567 | /* FIXME: this does not work if gw is changed in export filter */ |
90a9c97e | 568 | krt_replace_rte(p, n, NULL, n->routes); |
2d140452 MM |
569 | } |
570 | } | |
571 | FIB_WALK_END; | |
572 | } | |
573 | ||
78a2cc28 | 574 | static struct rte * |
13c0be19 | 575 | krt_export_net(struct krt_proto *p, net *net, rte **rt_free) |
78a2cc28 | 576 | { |
f4a60a9b | 577 | struct channel *c = p->p.main_channel; |
0b39b1cb | 578 | const struct filter *filter = c->out_filter; |
78a2cc28 OZ |
579 | rte *rt; |
580 | ||
f4a60a9b | 581 | if (c->ra_mode == RA_MERGED) |
13c0be19 | 582 | return rt_export_merged(c, net, rt_free, krt_filter_lp, 1); |
8d9eef17 | 583 | |
78a2cc28 OZ |
584 | rt = net->routes; |
585 | *rt_free = NULL; | |
586 | ||
587 | if (!rte_is_valid(rt)) | |
588 | return NULL; | |
589 | ||
590 | if (filter == FILTER_REJECT) | |
591 | return NULL; | |
592 | ||
c132acae | 593 | /* We could run krt_preexport() here, but it is already handled by krt_is_installed() */ |
78a2cc28 OZ |
594 | |
595 | if (filter == FILTER_ACCEPT) | |
596 | goto accept; | |
597 | ||
13c0be19 | 598 | if (f_run(filter, &rt, krt_filter_lp, FF_SILENT) > F_ACCEPT) |
78a2cc28 OZ |
599 | goto reject; |
600 | ||
601 | ||
602 | accept: | |
603 | if (rt != net->routes) | |
604 | *rt_free = rt; | |
605 | return rt; | |
606 | ||
607 | reject: | |
608 | if (rt != net->routes) | |
609 | rte_free(rt); | |
610 | return NULL; | |
611 | } | |
612 | ||
2d140452 | 613 | static int |
c9df01d3 | 614 | krt_same_dest(rte *k, rte *e) |
2d140452 MM |
615 | { |
616 | rta *ka = k->attrs, *ea = e->attrs; | |
617 | ||
618 | if (ka->dest != ea->dest) | |
619 | return 0; | |
4e276a89 JMM |
620 | |
621 | if (ka->dest == RTD_UNICAST) | |
622 | return nexthop_same(&(ka->nh), &(ea->nh)); | |
623 | ||
624 | return 1; | |
2d140452 MM |
625 | } |
626 | ||
627 | /* | |
628 | * This gets called back when the low-level scanning code discovers a route. | |
629 | * We expect that the route is a temporary rte and its attributes are uncached. | |
630 | */ | |
631 | ||
632 | void | |
e42eedb9 | 633 | krt_got_route(struct krt_proto *p, rte *e, s8 src) |
2d140452 | 634 | { |
7d767c5a OZ |
635 | rte *new = NULL, *rt_free = NULL; |
636 | net *n = e->net; | |
e42eedb9 | 637 | e->pflags = 0; |
2d140452 | 638 | |
ff2857b0 | 639 | #ifdef KRT_ALLOW_LEARN |
e42eedb9 | 640 | switch (src) |
c10421d3 | 641 | { |
ff2857b0 | 642 | case KRT_SRC_REDIRECT: |
7d767c5a | 643 | goto delete; |
ff2857b0 | 644 | |
e83beb70 PÅ |
645 | case KRT_SRC_KERNEL: |
646 | if (KRT_CF->learn != KRT_LEARN_ALL) | |
647 | goto ignore; | |
648 | /* fallthrough */ | |
649 | ||
ff2857b0 | 650 | case KRT_SRC_ALIEN: |
c10421d3 MM |
651 | if (KRT_CF->learn) |
652 | krt_learn_scan(p, e); | |
653 | else | |
c197d44e | 654 | { |
1123e707 | 655 | krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored"); |
c197d44e MM |
656 | rte_free(e); |
657 | } | |
c10421d3 MM |
658 | return; |
659 | } | |
660 | #endif | |
ff2857b0 | 661 | /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */ |
c10421d3 | 662 | |
2d140452 | 663 | |
7d767c5a | 664 | /* We wait for the initial feed to have correct installed state */ |
0c791f87 | 665 | if (!p->ready) |
7d767c5a | 666 | goto ignore; |
0c791f87 | 667 | |
7d767c5a OZ |
668 | if (!krt_is_installed(p, n)) |
669 | goto delete; | |
78a2cc28 | 670 | |
7d767c5a | 671 | new = krt_export_net(p, n, &rt_free); |
78a2cc28 | 672 | |
7d767c5a OZ |
673 | /* Rejected by filters */ |
674 | if (!new) | |
675 | goto delete; | |
78a2cc28 | 676 | |
7d767c5a OZ |
677 | /* Route to this destination was already seen. Strange, but it happens... */ |
678 | if (bmap_test(&p->seen_map, new->id)) | |
679 | goto aseen; | |
78a2cc28 | 680 | |
7d767c5a OZ |
681 | /* Mark route as seen */ |
682 | bmap_set(&p->seen_map, new->id); | |
78a2cc28 | 683 | |
7d767c5a OZ |
684 | /* TODO: There also may be changes in route eattrs, we ignore that for now. */ |
685 | if (!bmap_test(&p->sync_map, new->id) || !krt_same_dest(e, new)) | |
686 | goto update; | |
2d140452 | 687 | |
7d767c5a OZ |
688 | goto seen; |
689 | ||
690 | seen: | |
691 | krt_trace_in(p, e, "seen"); | |
692 | goto done; | |
693 | ||
694 | aseen: | |
695 | krt_trace_in(p, e, "already seen"); | |
696 | goto done; | |
697 | ||
698 | ignore: | |
699 | krt_trace_in(p, e, "ignored"); | |
700 | goto done; | |
701 | ||
702 | update: | |
703 | krt_trace_in(p, new, "updating"); | |
704 | krt_replace_rte(p, n, new, e); | |
705 | goto done; | |
706 | ||
707 | delete: | |
708 | krt_trace_in(p, e, "deleting"); | |
709 | krt_replace_rte(p, n, NULL, e); | |
710 | goto done; | |
711 | ||
712 | done: | |
713 | rte_free(e); | |
714 | ||
715 | if (rt_free) | |
716 | rte_free(rt_free); | |
717 | ||
718 | lp_flush(krt_filter_lp); | |
719 | } | |
720 | ||
721 | static void | |
722 | krt_init_scan(struct krt_proto *p) | |
723 | { | |
724 | bmap_reset(&p->seen_map, 1024); | |
2d140452 MM |
725 | } |
726 | ||
727 | static void | |
728 | krt_prune(struct krt_proto *p) | |
729 | { | |
f4a60a9b | 730 | struct rtable *t = p->p.main_channel->table; |
2d140452 | 731 | |
832fa033 | 732 | KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name); |
600998fc | 733 | FIB_WALK(&t->fib, net, n) |
7d767c5a OZ |
734 | { |
735 | if (p->ready && krt_is_installed(p, n) && !bmap_test(&p->seen_map, n->routes->id)) | |
2d140452 | 736 | { |
7d767c5a OZ |
737 | rte *rt_free = NULL; |
738 | rte *new = krt_export_net(p, n, &rt_free); | |
2d140452 | 739 | |
7d767c5a OZ |
740 | if (new) |
741 | { | |
742 | krt_trace_in(p, new, "installing"); | |
743 | krt_replace_rte(p, n, new, NULL); | |
744 | } | |
c9df01d3 | 745 | |
78a2cc28 OZ |
746 | if (rt_free) |
747 | rte_free(rt_free); | |
7d767c5a | 748 | |
c9df01d3 | 749 | lp_flush(krt_filter_lp); |
2d140452 | 750 | } |
7d767c5a | 751 | } |
2d140452 | 752 | FIB_WALK_END; |
c10421d3 MM |
753 | |
754 | #ifdef KRT_ALLOW_LEARN | |
755 | if (KRT_CF->learn) | |
756 | krt_learn_prune(p); | |
757 | #endif | |
0c791f87 OZ |
758 | |
759 | if (p->ready) | |
760 | p->initialized = 1; | |
2d140452 MM |
761 | } |
762 | ||
e16155ae | 763 | void |
e42eedb9 | 764 | krt_got_route_async(struct krt_proto *p, rte *e, int new, s8 src) |
e16155ae MM |
765 | { |
766 | net *net = e->net; | |
e42eedb9 | 767 | e->pflags = 0; |
e16155ae | 768 | |
e42eedb9 | 769 | switch (src) |
e16155ae MM |
770 | { |
771 | case KRT_SRC_BIRD: | |
d4cebc6b JMM |
772 | /* Should be filtered by the back end */ |
773 | bug("BIRD originated routes should not get here."); | |
ff2857b0 | 774 | |
e16155ae | 775 | case KRT_SRC_REDIRECT: |
ff2857b0 OZ |
776 | if (new) |
777 | { | |
778 | krt_trace_in(p, e, "[redirect] deleting"); | |
13c0be19 | 779 | krt_replace_rte(p, net, NULL, e); |
ff2857b0 OZ |
780 | } |
781 | /* If !new, it is probably echo of our deletion */ | |
e16155ae | 782 | break; |
ff2857b0 | 783 | |
c10421d3 | 784 | #ifdef KRT_ALLOW_LEARN |
e83beb70 PÅ |
785 | case KRT_SRC_KERNEL: |
786 | if (KRT_CF->learn != KRT_LEARN_ALL) | |
787 | break; | |
788 | /* fallthrough */ | |
789 | ||
1bc4b2cc | 790 | case KRT_SRC_ALIEN: |
c10421d3 | 791 | if (KRT_CF->learn) |
e16155ae | 792 | { |
c10421d3 MM |
793 | krt_learn_async(p, e, new); |
794 | return; | |
e16155ae | 795 | } |
c10421d3 | 796 | #endif |
e16155ae | 797 | } |
c10421d3 | 798 | rte_free(e); |
e16155ae MM |
799 | } |
800 | ||
534d0a4b | 801 | |
2d140452 MM |
802 | /* |
803 | * Periodic scanning | |
804 | */ | |
805 | ||
534d0a4b OZ |
806 | static timer *krt_scan_all_timer; |
807 | static int krt_scan_all_count; | |
808 | static _Bool krt_scan_all_tables; | |
c6964c30 | 809 | |
2d140452 | 810 | static void |
534d0a4b | 811 | krt_scan_all(timer *t UNUSED) |
2d140452 | 812 | { |
7de45ba4 | 813 | struct krt_proto *p; |
7d767c5a | 814 | node *n; |
2d140452 | 815 | |
7e5f5ffd | 816 | kif_force_scan(); |
c6964c30 OZ |
817 | |
818 | /* We need some node to decide whether to print the debug messages or not */ | |
819 | p = SKIP_BACK(struct krt_proto, krt_node, HEAD(krt_proto_list)); | |
820 | KRT_TRACE(p, D_EVENTS, "Scanning routing table"); | |
821 | ||
7d767c5a OZ |
822 | WALK_LIST2(p, n, krt_proto_list, krt_node) |
823 | krt_init_scan(p); | |
824 | ||
c6964c30 OZ |
825 | krt_do_scan(NULL); |
826 | ||
7d767c5a | 827 | WALK_LIST2(p, n, krt_proto_list, krt_node) |
c6964c30 | 828 | krt_prune(p); |
c6964c30 OZ |
829 | } |
830 | ||
831 | static void | |
534d0a4b | 832 | krt_scan_all_timer_start(struct krt_proto *p) |
c6964c30 | 833 | { |
534d0a4b OZ |
834 | if (!krt_scan_all_count) |
835 | krt_scan_all_timer = tm_new_init(krt_pool, krt_scan_all, NULL, KRT_CF->scan_time, 0); | |
c6964c30 | 836 | |
534d0a4b | 837 | krt_scan_all_count++; |
f8cc7396 | 838 | |
534d0a4b | 839 | tm_start(krt_scan_all_timer, 1 S); |
c6964c30 OZ |
840 | } |
841 | ||
842 | static void | |
534d0a4b | 843 | krt_scan_all_timer_stop(void) |
c6964c30 | 844 | { |
534d0a4b OZ |
845 | ASSERT(krt_scan_all_count > 0); |
846 | ||
847 | krt_scan_all_count--; | |
c6964c30 | 848 | |
534d0a4b | 849 | if (!krt_scan_all_count) |
c6964c30 | 850 | { |
534d0a4b OZ |
851 | rfree(krt_scan_all_timer); |
852 | krt_scan_all_timer = NULL; | |
7de45ba4 | 853 | } |
c6964c30 OZ |
854 | } |
855 | ||
0c791f87 | 856 | static void |
534d0a4b | 857 | krt_scan_all_timer_kick(void) |
0c791f87 | 858 | { |
534d0a4b OZ |
859 | tm_start(krt_scan_all_timer, 0); |
860 | } | |
861 | ||
862 | void | |
863 | krt_use_shared_scan(void) | |
864 | { | |
865 | krt_scan_all_tables = 1; | |
0c791f87 OZ |
866 | } |
867 | ||
c6964c30 OZ |
868 | |
869 | static void | |
870 | krt_scan(timer *t) | |
871 | { | |
872 | struct krt_proto *p = t->data; | |
873 | ||
874 | kif_force_scan(); | |
875 | ||
832fa033 | 876 | KRT_TRACE(p, D_EVENTS, "Scanning routing table"); |
7d767c5a | 877 | krt_init_scan(p); |
396dfa90 | 878 | krt_do_scan(p); |
7e5f5ffd | 879 | krt_prune(p); |
2d140452 MM |
880 | } |
881 | ||
c6964c30 OZ |
882 | static void |
883 | krt_scan_timer_start(struct krt_proto *p) | |
884 | { | |
534d0a4b OZ |
885 | if (krt_scan_all_tables) |
886 | krt_scan_all_timer_start(p); | |
887 | else | |
888 | { | |
889 | p->scan_timer = tm_new_init(p->p.pool, krt_scan, p, KRT_CF->scan_time, 0); | |
890 | tm_start(p->scan_timer, 1 S); | |
891 | } | |
c6964c30 OZ |
892 | } |
893 | ||
894 | static void | |
895 | krt_scan_timer_stop(struct krt_proto *p) | |
896 | { | |
534d0a4b OZ |
897 | if (krt_scan_all_tables) |
898 | krt_scan_all_timer_stop(); | |
899 | else | |
900 | tm_stop(p->scan_timer); | |
c6964c30 OZ |
901 | } |
902 | ||
0c791f87 | 903 | static void |
252c7e4d | 904 | krt_scan_timer_kick(struct krt_proto *p) |
0c791f87 | 905 | { |
534d0a4b OZ |
906 | if (krt_scan_all_tables) |
907 | krt_scan_all_timer_kick(); | |
908 | else | |
909 | tm_start(p->scan_timer, 0); | |
0c791f87 OZ |
910 | } |
911 | ||
396dfa90 | 912 | |
c10421d3 MM |
913 | /* |
914 | * Updates | |
915 | */ | |
396dfa90 | 916 | |
c429d4a4 | 917 | static int |
d429bc5c | 918 | krt_preexport(struct channel *C, rte *e) |
c429d4a4 | 919 | { |
62e64905 | 920 | // struct krt_proto *p = (struct krt_proto *) P; |
d429bc5c | 921 | if (e->src->proto == C->proto) |
c429d4a4 OZ |
922 | return -1; |
923 | ||
c429d4a4 OZ |
924 | if (!krt_capable(e)) |
925 | return -1; | |
926 | ||
927 | return 0; | |
928 | } | |
c10421d3 MM |
929 | |
930 | static void | |
4bdf1881 | 931 | krt_rt_notify(struct proto *P, struct channel *ch UNUSED, net *net, |
13c0be19 | 932 | rte *new, rte *old) |
c10421d3 MM |
933 | { |
934 | struct krt_proto *p = (struct krt_proto *) P; | |
935 | ||
a92cf57d | 936 | if (config->shutdown) |
f990fc61 | 937 | return; |
c132acae OZ |
938 | |
939 | #ifdef CONFIG_SINGLE_ROUTE | |
940 | /* | |
941 | * Implicit withdraw - when the imported kernel route becomes the best one, | |
942 | * we know that the previous one exported to the kernel was already removed, | |
943 | * but if we processed the update as usual, we would send withdraw to the | |
944 | * kernel, which would remove the new imported route instead. | |
945 | */ | |
946 | rte *best = net->routes; | |
543c8ba0 | 947 | if (!new && best && (best->src->proto == P)) |
c132acae OZ |
948 | return; |
949 | #endif | |
950 | ||
c9df01d3 | 951 | if (p->initialized) /* Before first scan we don't touch the routes */ |
13c0be19 | 952 | krt_replace_rte(p, net, new, old); |
c10421d3 MM |
953 | } |
954 | ||
252c7e4d OZ |
955 | static void |
956 | krt_if_notify(struct proto *P, uint flags, struct iface *iface UNUSED) | |
957 | { | |
958 | struct krt_proto *p = (struct krt_proto *) P; | |
959 | ||
960 | /* | |
961 | * When interface went down, we should remove routes to it. In the ideal world, | |
962 | * OS kernel would send us route removal notifications in such cases, but we | |
963 | * cannot rely on it as it is often not true. E.g. Linux kernel removes related | |
964 | * routes when an interface went down, but it does not notify userspace about | |
965 | * that. To be sure, we just schedule a scan to ensure synchronization. | |
966 | */ | |
967 | ||
968 | if ((flags & IF_CHANGE_DOWN) && KRT_CF->learn) | |
969 | krt_scan_timer_kick(p); | |
970 | } | |
971 | ||
f4a60a9b OZ |
972 | static void |
973 | krt_reload_routes(struct channel *C) | |
252c7e4d | 974 | { |
f4a60a9b | 975 | struct krt_proto *p = (void *) C->proto; |
252c7e4d OZ |
976 | |
977 | /* Although we keep learned routes in krt_table, we rather schedule a scan */ | |
978 | ||
979 | if (KRT_CF->learn) | |
7069fc9e OZ |
980 | { |
981 | p->reload = 1; | |
252c7e4d | 982 | krt_scan_timer_kick(p); |
7069fc9e | 983 | } |
252c7e4d OZ |
984 | } |
985 | ||
0c791f87 | 986 | static void |
f4a60a9b | 987 | krt_feed_end(struct channel *C) |
0c791f87 | 988 | { |
f4a60a9b | 989 | struct krt_proto *p = (void *) C->proto; |
0c791f87 OZ |
990 | |
991 | p->ready = 1; | |
992 | krt_scan_timer_kick(p); | |
993 | } | |
994 | ||
995 | ||
2d140452 MM |
996 | /* |
997 | * Protocol glue | |
998 | */ | |
999 | ||
396dfa90 | 1000 | struct krt_config *krt_cf; |
7e5f5ffd | 1001 | |
f4a60a9b OZ |
1002 | static void |
1003 | krt_preconfig(struct protocol *P UNUSED, struct config *c) | |
1004 | { | |
1005 | krt_cf = NULL; | |
1006 | krt_sys_preconfig(c); | |
1007 | } | |
1008 | ||
1009 | static void | |
1010 | krt_postconfig(struct proto_config *CF) | |
1011 | { | |
1012 | struct krt_config *cf = (void *) CF; | |
1013 | ||
2a8cc725 OZ |
1014 | /* Do not check templates at all */ |
1015 | if (cf->c.class == SYM_TEMPLATE) | |
1016 | return; | |
1017 | ||
47d92d8f | 1018 | if (! proto_cf_main_channel(CF)) |
f4a60a9b OZ |
1019 | cf_error("Channel not specified"); |
1020 | ||
ace3072e OZ |
1021 | struct channel_config *cc = proto_cf_main_channel(CF); |
1022 | struct rtable_config *tab = cc->table; | |
f4a60a9b OZ |
1023 | if (tab->krt_attached) |
1024 | cf_error("Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name); | |
1025 | tab->krt_attached = CF; | |
1026 | ||
ace3072e OZ |
1027 | if (cf->merge_paths) |
1028 | { | |
1029 | cc->ra_mode = RA_MERGED; | |
1030 | cc->merge_limit = cf->merge_paths; | |
1031 | } | |
1032 | ||
f4a60a9b OZ |
1033 | krt_sys_postconfig(cf); |
1034 | } | |
1035 | ||
396dfa90 | 1036 | static struct proto * |
f4a60a9b | 1037 | krt_init(struct proto_config *CF) |
7de45ba4 | 1038 | { |
f4a60a9b OZ |
1039 | struct krt_proto *p = proto_new(CF); |
1040 | // struct krt_config *cf = (void *) CF; | |
1041 | ||
1042 | p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF)); | |
7de45ba4 | 1043 | |
14375237 | 1044 | p->p.preexport = krt_preexport; |
252c7e4d OZ |
1045 | p->p.rt_notify = krt_rt_notify; |
1046 | p->p.if_notify = krt_if_notify; | |
1047 | p->p.reload_routes = krt_reload_routes; | |
9aed29e6 | 1048 | p->p.feed_end = krt_feed_end; |
7de45ba4 | 1049 | |
396dfa90 OZ |
1050 | krt_sys_init(p); |
1051 | return &p->p; | |
7de45ba4 MM |
1052 | } |
1053 | ||
2d140452 MM |
1054 | static int |
1055 | krt_start(struct proto *P) | |
1056 | { | |
1057 | struct krt_proto *p = (struct krt_proto *) P; | |
7de45ba4 | 1058 | |
f4a60a9b | 1059 | switch (p->p.net_type) |
29a64162 | 1060 | { |
be17805c OZ |
1061 | case NET_IP4: p->af = AF_INET; break; |
1062 | case NET_IP6: p->af = AF_INET6; break; | |
1063 | case NET_IP6_SADR: p->af = AF_INET6; break; | |
1d213067 | 1064 | #ifdef AF_MPLS |
be17805c | 1065 | case NET_MPLS: p->af = AF_MPLS; break; |
1d213067 | 1066 | #endif |
d14f8c3c | 1067 | default: log(L_ERR "KRT: Tried to start with strange net type: %d", p->p.net_type); return PS_START; break; |
29a64162 OZ |
1068 | } |
1069 | ||
cc75b3e1 | 1070 | bmap_init(&p->sync_map, p->p.pool, 1024); |
7d767c5a | 1071 | bmap_init(&p->seen_map, p->p.pool, 1024); |
c6964c30 | 1072 | add_tail(&krt_proto_list, &p->krt_node); |
2d140452 | 1073 | |
c10421d3 MM |
1074 | #ifdef KRT_ALLOW_LEARN |
1075 | krt_learn_init(p); | |
1076 | #endif | |
1077 | ||
9ddbfbdd JMM |
1078 | if (!krt_sys_start(p)) |
1079 | { | |
1080 | rem_node(&p->krt_node); | |
1081 | return PS_START; | |
1082 | } | |
2d140452 | 1083 | |
c6964c30 | 1084 | krt_scan_timer_start(p); |
2d140452 | 1085 | |
f4a60a9b OZ |
1086 | if (p->p.gr_recovery && KRT_CF->graceful_restart) |
1087 | p->p.main_channel->gr_wait = 1; | |
0c791f87 | 1088 | |
2d140452 MM |
1089 | return PS_UP; |
1090 | } | |
1091 | ||
7de45ba4 | 1092 | static int |
2d140452 MM |
1093 | krt_shutdown(struct proto *P) |
1094 | { | |
1095 | struct krt_proto *p = (struct krt_proto *) P; | |
1096 | ||
c6964c30 | 1097 | krt_scan_timer_stop(p); |
7e5f5ffd | 1098 | |
3d574679 | 1099 | /* FIXME we should flush routes even when persist during reconfiguration */ |
8a68316e | 1100 | if (p->initialized && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN)) |
2d140452 MM |
1101 | krt_flush_routes(p); |
1102 | ||
0c791f87 OZ |
1103 | p->ready = 0; |
1104 | p->initialized = 0; | |
1105 | ||
9ddbfbdd JMM |
1106 | if (p->p.proto_state == PS_START) |
1107 | return PS_DOWN; | |
7de45ba4 | 1108 | |
9ddbfbdd | 1109 | krt_sys_shutdown(p); |
c6964c30 | 1110 | rem_node(&p->krt_node); |
cc75b3e1 | 1111 | bmap_free(&p->sync_map); |
2d140452 | 1112 | |
2d140452 MM |
1113 | return PS_DOWN; |
1114 | } | |
1115 | ||
396dfa90 | 1116 | static int |
f4a60a9b | 1117 | krt_reconfigure(struct proto *p, struct proto_config *CF) |
72aed1a0 | 1118 | { |
f4a60a9b OZ |
1119 | struct krt_config *o = (void *) p->cf; |
1120 | struct krt_config *n = (void *) CF; | |
1121 | ||
1122 | if (!proto_configure_channel(p, &p->main_channel, proto_cf_main_channel(CF))) | |
1123 | return 0; | |
72aed1a0 | 1124 | |
396dfa90 OZ |
1125 | if (!krt_sys_reconfigure((struct krt_proto *) p, n, o)) |
1126 | return 0; | |
9ba2798c | 1127 | |
0c791f87 | 1128 | /* persist, graceful restart need not be the same */ |
e5ff7929 | 1129 | return o->scan_time == n->scan_time && o->learn == n->learn; |
2d140452 MM |
1130 | } |
1131 | ||
396dfa90 OZ |
1132 | struct proto_config * |
1133 | krt_init_config(int class) | |
aa8761de | 1134 | { |
396dfa90 OZ |
1135 | #ifndef CONFIG_MULTIPLE_TABLES |
1136 | if (krt_cf) | |
1137 | cf_error("Kernel protocol already defined"); | |
1138 | #endif | |
1139 | ||
2bbc3083 | 1140 | krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, class); |
21f4f0f4 | 1141 | krt_cf->scan_time = 60 S; |
aa8761de | 1142 | |
396dfa90 OZ |
1143 | krt_sys_init_config(krt_cf); |
1144 | return (struct proto_config *) krt_cf; | |
aa8761de MM |
1145 | } |
1146 | ||
a7f23f58 OZ |
1147 | static void |
1148 | krt_copy_config(struct proto_config *dest, struct proto_config *src) | |
1149 | { | |
1150 | struct krt_config *d = (struct krt_config *) dest; | |
1151 | struct krt_config *s = (struct krt_config *) src; | |
1152 | ||
a7f23f58 | 1153 | /* Fix sysdep parts */ |
396dfa90 | 1154 | krt_sys_copy_config(d, s); |
a7f23f58 | 1155 | } |
71ca7716 OZ |
1156 | |
1157 | static int | |
258be565 | 1158 | krt_get_attr(const eattr *a, byte *buf, int buflen) |
71ca7716 OZ |
1159 | { |
1160 | switch (a->id) | |
1161 | { | |
72aed1a0 OZ |
1162 | case EA_KRT_SOURCE: |
1163 | bsprintf(buf, "source"); | |
1164 | return GA_NAME; | |
1165 | ||
9ba2798c OZ |
1166 | case EA_KRT_METRIC: |
1167 | bsprintf(buf, "metric"); | |
1168 | return GA_NAME; | |
1169 | ||
71ca7716 | 1170 | default: |
9fdf9d29 | 1171 | return krt_sys_get_attr(a, buf, buflen); |
71ca7716 OZ |
1172 | } |
1173 | } | |
1174 | ||
1175 | ||
be17805c OZ |
1176 | #ifdef CONFIG_IP6_SADR_KERNEL |
1177 | #define MAYBE_IP6_SADR NB_IP6_SADR | |
1178 | #else | |
1179 | #define MAYBE_IP6_SADR 0 | |
1180 | #endif | |
1181 | ||
1182 | #ifdef HAVE_MPLS_KERNEL | |
1183 | #define MAYBE_MPLS NB_MPLS | |
1184 | #else | |
1185 | #define MAYBE_MPLS 0 | |
1186 | #endif | |
1187 | ||
2d140452 | 1188 | struct protocol proto_unix_kernel = { |
4a591d4b PT |
1189 | .name = "Kernel", |
1190 | .template = "kernel%d", | |
ee7e2ffd | 1191 | .class = PROTOCOL_KERNEL, |
4a591d4b | 1192 | .preference = DEF_PREF_INHERITED, |
be17805c | 1193 | .channel_mask = NB_IP | MAYBE_IP6_SADR | MAYBE_MPLS, |
f4a60a9b | 1194 | .proto_size = sizeof(struct krt_proto), |
2bbc3083 | 1195 | .config_size = sizeof(struct krt_config), |
4a591d4b PT |
1196 | .preconfig = krt_preconfig, |
1197 | .postconfig = krt_postconfig, | |
1198 | .init = krt_init, | |
1199 | .start = krt_start, | |
1200 | .shutdown = krt_shutdown, | |
1201 | .reconfigure = krt_reconfigure, | |
1202 | .copy_config = krt_copy_config, | |
1203 | .get_attr = krt_get_attr, | |
c10421d3 | 1204 | #ifdef KRT_ALLOW_LEARN |
4a591d4b | 1205 | .dump = krt_dump, |
c10421d3 | 1206 | #endif |
2d140452 | 1207 | }; |
4a23ede2 MM |
1208 | |
1209 | void | |
1210 | krt_build(void) | |
1211 | { | |
1212 | proto_build(&proto_unix_kernel); | |
1213 | } |