Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / krt.c @ 62e64905

History | View | Annotate | Download (27 KB)

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