Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / krt.c @ 725270cb

History | View | Annotate | Download (17.5 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 2e9b2421 Martin Mares
 * separate KRT protocols which cooperate with each other  [Linux 2.2].
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
 */
38 73275d85 Martin Mares
39
/*
40
 *  If you are brave enough, continue now.  You cannot say you haven't been warned.
41
 */
42
43 832fa033 Martin Mares
#undef LOCAL_DEBUG
44 2d140452 Martin Mares
45
#include "nest/bird.h"
46
#include "nest/iface.h"
47
#include "nest/route.h"
48
#include "nest/protocol.h"
49
#include "lib/timer.h"
50 7de45ba4 Martin Mares
#include "conf/conf.h"
51 2d140452 Martin Mares
52
#include "unix.h"
53
#include "krt.h"
54
55 c10421d3 Martin Mares
static int krt_uptodate(rte *k, rte *e);
56
57 7e5f5ffd Martin Mares
/*
58
 *        Global resources
59
 */
60
61 7de45ba4 Martin Mares
pool *krt_pool;
62
63 7e5f5ffd Martin Mares
void
64
krt_io_init(void)
65
{
66 7de45ba4 Martin Mares
  krt_pool = rp_new(&root_pool, "Kernel Syncer");
67 7e5f5ffd Martin Mares
  krt_if_io_init();
68
}
69
70
/*
71
 *        Interfaces
72
 */
73
74
struct proto_config *cf_kif;
75
76
static struct kif_proto *kif_proto;
77
static timer *kif_scan_timer;
78
static bird_clock_t kif_last_shot;
79
80
static void
81 50fe90ed Martin Mares
kif_preconfig(struct protocol *P, struct config *c)
82
{
83
  cf_kif = NULL;
84
}
85
86
static void
87 7e5f5ffd Martin Mares
kif_scan(timer *t)
88
{
89
  struct kif_proto *p = t->data;
90
91 832fa033 Martin Mares
  KRT_TRACE(p, D_EVENTS, "Scanning interfaces");
92 7e5f5ffd Martin Mares
  kif_last_shot = now;
93
  krt_if_scan(p);
94
}
95
96
static void
97
kif_force_scan(void)
98
{
99
  if (kif_proto && kif_last_shot + 2 < now)
100
    {
101
      kif_scan(kif_scan_timer);
102
      tm_start(kif_scan_timer, ((struct kif_config *) kif_proto->p.cf)->scan_time);
103
    }
104
}
105
106
static struct proto *
107
kif_init(struct proto_config *c)
108
{
109
  struct kif_proto *p = proto_new(c, sizeof(struct kif_proto));
110
  return &p->p;
111
}
112
113
static int
114
kif_start(struct proto *P)
115
{
116
  struct kif_proto *p = (struct kif_proto *) P;
117
118
  kif_proto = p;
119
  krt_if_start(p);
120
121
  /* Start periodic interface scanning */
122
  kif_scan_timer = tm_new(P->pool);
123
  kif_scan_timer->hook = kif_scan;
124
  kif_scan_timer->data = p;
125
  kif_scan_timer->recurrent = KIF_CF->scan_time;
126
  kif_scan(kif_scan_timer);
127
  tm_start(kif_scan_timer, KIF_CF->scan_time);
128
129
  return PS_UP;
130
}
131
132
static int
133
kif_shutdown(struct proto *P)
134
{
135
  struct kif_proto *p = (struct kif_proto *) P;
136
137
  tm_stop(kif_scan_timer);
138
  krt_if_shutdown(p);
139
  kif_proto = NULL;
140
141
  if_start_update();        /* Remove all interfaces */
142
  if_end_update();
143 7de45ba4 Martin Mares
  /*
144
   *  FIXME: Is it really a good idea?  It causes routes to be flushed,
145
   *  but at the same time it avoids sending of these deletions to the kernel,
146
   *  because krt thinks the kernel itself has already removed the route
147
   *  when downing the interface.  Sad.
148
   */
149 7e5f5ffd Martin Mares
150
  return PS_DOWN;
151
}
152
153 f7fcb752 Martin Mares
static int
154
kif_reconfigure(struct proto *p, struct proto_config *new)
155
{
156
  struct kif_config *o = (struct kif_config *) p->cf;
157
  struct kif_config *n = (struct kif_config *) new;
158
159
  if (!kif_params_same(&o->iface, &n->iface))
160
    return 0;
161
  if (o->scan_time != n->scan_time)
162
    {
163
      tm_stop(kif_scan_timer);
164
      kif_scan_timer->recurrent = n->scan_time;
165
      kif_scan(kif_scan_timer);
166
      tm_start(kif_scan_timer, n->scan_time);
167
    }
168
  return 1;
169
}
170
171 7e5f5ffd Martin Mares
struct protocol proto_unix_iface = {
172
  name:                "Device",
173 d272fe22 Martin Mares
  template:        "device%d",
174 50fe90ed Martin Mares
  preconfig:        kif_preconfig,
175 7e5f5ffd Martin Mares
  init:                kif_init,
176
  start:        kif_start,
177
  shutdown:        kif_shutdown,
178 f7fcb752 Martin Mares
  reconfigure:        kif_reconfigure,
179 7e5f5ffd Martin Mares
};
180 2d140452 Martin Mares
181
/*
182 832fa033 Martin Mares
 *        Tracing of routes
183
 */
184
185
static void
186
krt_trace_in_print(struct krt_proto *p, rte *e, char *msg)
187
{
188
  DBG("KRT: %I/%d: %s\n", e->net->n.prefix, e->net->n.pxlen, msg);
189
  log(L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg);
190
}
191
192
static inline void
193
krt_trace_in(struct krt_proto *p, rte *e, char *msg)
194
{
195
  if (p->p.debug & D_PACKETS)
196
    krt_trace_in_print(p, e, msg);
197
}
198
199
/*
200 c10421d3 Martin Mares
 *        Inherited Routes
201
 */
202
203
#ifdef KRT_ALLOW_LEARN
204
205
static inline int
206
krt_same_key(rte *a, rte *b)
207
{
208
  return a->u.krt.proto == b->u.krt.proto &&
209
         a->u.krt.metric == b->u.krt.metric &&
210
         a->u.krt.type == b->u.krt.type;
211
}
212
213
static void
214
krt_learn_announce_update(struct krt_proto *p, rte *e)
215
{
216
  net *n = e->net;
217
  rta *aa = rta_clone(e->attrs);
218
  rte *ee = rte_get_temp(aa);
219 08e2d625 Martin Mares
  net *nn = net_get(p->p.table, n->n.prefix, n->n.pxlen);
220 c10421d3 Martin Mares
  ee->net = nn;
221
  ee->pflags = 0;
222 1151401e Martin Mares
  ee->pref = p->p.preference;
223 c10421d3 Martin Mares
  ee->u.krt = e->u.krt;
224 4f1a6d27 Martin Mares
  rte_update(p->p.table, nn, &p->p, ee);
225 c10421d3 Martin Mares
}
226
227
static void
228
krt_learn_announce_delete(struct krt_proto *p, net *n)
229
{
230 08e2d625 Martin Mares
  n = net_find(p->p.table, n->n.prefix, n->n.pxlen);
231 c10421d3 Martin Mares
  if (n)
232 4f1a6d27 Martin Mares
    rte_update(p->p.table, n, &p->p, NULL);
233 c10421d3 Martin Mares
}
234
235
static void
236
krt_learn_scan(struct krt_proto *p, rte *e)
237
{
238
  net *n0 = e->net;
239 08e2d625 Martin Mares
  net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
240 c10421d3 Martin Mares
  rte *m, **mm;
241
242
  e->attrs->source = RTS_INHERIT;
243
244
  for(mm=&n->routes; m = *mm; mm=&m->next)
245
    if (krt_same_key(m, e))
246
      break;
247
  if (m)
248
    {
249
      if (krt_uptodate(m, e))
250
        {
251 832fa033 Martin Mares
          krt_trace_in(p, e, "[alien] seen");
252 c10421d3 Martin Mares
          rte_free(e);
253
          m->u.krt.seen = 1;
254
        }
255
      else
256
        {
257 832fa033 Martin Mares
          krt_trace_in(p, e, "[alien] updated");
258 c10421d3 Martin Mares
          *mm = m->next;
259
          rte_free(m);
260
          m = NULL;
261
        }
262
    }
263
  else
264 832fa033 Martin Mares
    krt_trace_in(p, e, "[alien] created");
265 c10421d3 Martin Mares
  if (!m)
266
    {
267
      e->attrs = rta_lookup(e->attrs);
268
      e->next = n->routes;
269
      n->routes = e;
270
      e->u.krt.seen = 1;
271
    }
272
}
273
274
static void
275
krt_learn_prune(struct krt_proto *p)
276
{
277
  struct fib *fib = &p->krt_table.fib;
278
  struct fib_iterator fit;
279
280 832fa033 Martin Mares
  KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
281 c10421d3 Martin Mares
282
  FIB_ITERATE_INIT(&fit, fib);
283
again:
284
  FIB_ITERATE_START(fib, &fit, f)
285
    {
286
      net *n = (net *) f;
287
      rte *e, **ee, *best, **pbest, *old_best;
288
289
      old_best = n->routes;
290
      best = NULL;
291
      pbest = NULL;
292
      ee = &n->routes;
293
      while (e = *ee)
294
        {
295
          if (!e->u.krt.seen)
296
            {
297
              *ee = e->next;
298
              rte_free(e);
299
              continue;
300
            }
301
          if (!best || best->u.krt.metric > e->u.krt.metric)
302
            {
303
              best = e;
304
              pbest = ee;
305
            }
306
          e->u.krt.seen = 0;
307
          ee = &e->next;
308
        }
309
      if (!n->routes)
310
        {
311
          DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
312
          if (old_best)
313
            {
314
              krt_learn_announce_delete(p, n);
315
              n->n.flags &= ~KRF_INSTALLED;
316
            }
317
          FIB_ITERATE_PUT(&fit, f);
318
          fib_delete(fib, f);
319
          goto again;
320
        }
321
      *pbest = best->next;
322
      best->next = n->routes;
323
      n->routes = best;
324
      if (best != old_best || !(n->n.flags & KRF_INSTALLED))
325
        {
326
          DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
327
          krt_learn_announce_update(p, best);
328
          n->n.flags |= KRF_INSTALLED;
329
        }
330
      else
331
        DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
332
    }
333
  FIB_ITERATE_END(f);
334
}
335
336
static void
337
krt_learn_async(struct krt_proto *p, rte *e, int new)
338
{
339
  net *n0 = e->net;
340 08e2d625 Martin Mares
  net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
341 c10421d3 Martin Mares
  rte *g, **gg, *best, **bestp, *old_best;
342
343
  e->attrs->source = RTS_INHERIT;
344
345
  old_best = n->routes;
346
  for(gg=&n->routes; g = *gg; gg = &g->next)
347
    if (krt_same_key(g, e))
348
      break;
349
  if (new)
350
    {
351
      if (g)
352
        {
353
          if (krt_uptodate(g, e))
354
            {
355 832fa033 Martin Mares
              krt_trace_in(p, e, "[alien async] same");
356 c10421d3 Martin Mares
              rte_free(e);
357
              return;
358
            }
359 832fa033 Martin Mares
          krt_trace_in(p, e, "[alien async] updated");
360 c10421d3 Martin Mares
          *gg = g->next;
361
          rte_free(g);
362
        }
363
      else
364 832fa033 Martin Mares
        krt_trace_in(p, e, "[alien async] created");
365 c10421d3 Martin Mares
      e->attrs = rta_lookup(e->attrs);
366
      e->next = n->routes;
367
      n->routes = e;
368
    }
369
  else if (!g)
370
    {
371 832fa033 Martin Mares
      krt_trace_in(p, e, "[alien async] delete failed");
372 c10421d3 Martin Mares
      rte_free(e);
373
      return;
374
    }
375
  else
376
    {
377 832fa033 Martin Mares
      krt_trace_in(p, e, "[alien async] removed");
378 c10421d3 Martin Mares
      *gg = g->next;
379
      rte_free(e);
380
      rte_free(g);
381
    }
382
  best = n->routes;
383
  bestp = &n->routes;
384
  for(gg=&n->routes; g=*gg; gg=&g->next)
385
    if (best->u.krt.metric > g->u.krt.metric)
386
      {
387
        best = g;
388
        bestp = gg;
389
      }
390
  if (best)
391
    {
392
      *bestp = best->next;
393
      best->next = n->routes;
394
      n->routes = best;
395
    }
396
  if (best != old_best)
397
    {
398
      DBG("krt_learn_async: distributing change\n");
399
      if (best)
400
        {
401
          krt_learn_announce_update(p, best);
402
          n->n.flags |= KRF_INSTALLED;
403
        }
404
      else
405
        {
406
          n->routes = NULL;
407
          krt_learn_announce_delete(p, n);
408
          n->n.flags &= ~KRF_INSTALLED;
409
        }
410
    }
411
}
412
413
static void
414
krt_learn_init(struct krt_proto *p)
415
{
416
  if (KRT_CF->learn)
417 b9626ec6 Martin Mares
    rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL);
418 c10421d3 Martin Mares
}
419
420
static void
421
krt_dump(struct proto *P)
422
{
423
  struct krt_proto *p = (struct krt_proto *) P;
424
425
  if (!KRT_CF->learn)
426
    return;
427
  debug("KRT: Table of inheritable routes\n");
428
  rt_dump(&p->krt_table);
429
}
430
431
static void
432
krt_dump_attrs(rte *e)
433
{
434
  debug(" [m=%d,p=%d,t=%d]", e->u.krt.metric, e->u.krt.proto, e->u.krt.type);
435
}
436
437
#endif
438
439
/*
440 2d140452 Martin Mares
 *        Routes
441
 */
442
443 7de45ba4 Martin Mares
#ifdef CONFIG_ALL_TABLES_AT_ONCE
444
static timer *krt_scan_timer;
445
static int krt_instance_count;
446
static list krt_instance_list;
447
#endif
448
449 2d140452 Martin Mares
static void
450
krt_flush_routes(struct krt_proto *p)
451
{
452 4f1a6d27 Martin Mares
  struct rtable *t = p->p.table;
453 2d140452 Martin Mares
454 832fa033 Martin Mares
  KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
455 2d140452 Martin Mares
  FIB_WALK(&t->fib, f)
456
    {
457
      net *n = (net *) f;
458
      rte *e = n->routes;
459
      if (e)
460
        {
461
          rta *a = e->attrs;
462
          if (a->source != RTS_DEVICE && a->source != RTS_INHERIT)
463 c10421d3 Martin Mares
            krt_set_notify(p, e->net, NULL, e);
464 2d140452 Martin Mares
        }
465
    }
466
  FIB_WALK_END;
467
}
468
469
static int
470
krt_uptodate(rte *k, rte *e)
471
{
472
  rta *ka = k->attrs, *ea = e->attrs;
473
474
  if (ka->dest != ea->dest)
475
    return 0;
476
  switch (ka->dest)
477
    {
478
    case RTD_ROUTER:
479
      return ipa_equal(ka->gw, ea->gw);
480
    case RTD_DEVICE:
481
      return !strcmp(ka->iface->name, ea->iface->name);
482
    default:
483
      return 1;
484
    }
485
}
486
487
/*
488
 *  This gets called back when the low-level scanning code discovers a route.
489
 *  We expect that the route is a temporary rte and its attributes are uncached.
490
 */
491
492
void
493
krt_got_route(struct krt_proto *p, rte *e)
494
{
495
  rte *old;
496
  net *net = e->net;
497 c10421d3 Martin Mares
  int src = e->u.krt.src;
498 2d140452 Martin Mares
  int verdict;
499
500 c10421d3 Martin Mares
#ifdef CONFIG_AUTO_ROUTES
501
  if (e->attrs->dest == RTD_DEVICE)
502
    {
503
      /* It's a device route. Probably a kernel-generated one. */
504
      verdict = KRF_IGNORE;
505
      goto sentenced;
506
    }
507
#endif
508
509
#ifdef KRT_ALLOW_LEARN
510
  if (src == KRT_SRC_ALIEN)
511
    {
512
      if (KRT_CF->learn)
513
        krt_learn_scan(p, e);
514
      else
515 832fa033 Martin Mares
        krt_trace_in(p, e, "alien route, ignored");
516 c10421d3 Martin Mares
      return;
517
    }
518
#endif
519
520
  if (net->n.flags & KRF_VERDICT_MASK)
521 2d140452 Martin Mares
    {
522
      /* Route to this destination was already seen. Strange, but it happens... */
523 832fa033 Martin Mares
      krt_trace_in(p, e, "already seen");
524 2d140452 Martin Mares
      return;
525
    }
526
527 c10421d3 Martin Mares
  if (net->n.flags & KRF_INSTALLED)
528 2d140452 Martin Mares
    {
529 c10421d3 Martin Mares
      old = net->routes;
530
      ASSERT(old);
531
      if (krt_uptodate(e, old))
532 2d140452 Martin Mares
        verdict = KRF_SEEN;
533
      else
534
        verdict = KRF_UPDATE;
535
    }
536
  else
537
    verdict = KRF_DELETE;
538
539 c10421d3 Martin Mares
sentenced:
540 832fa033 Martin Mares
  krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]);
541 c10421d3 Martin Mares
  net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
542
  if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
543 2d140452 Martin Mares
    {
544
      /* Get a cached copy of attributes and link the route */
545
      rta *a = e->attrs;
546
      a->source = RTS_DUMMY;
547
      e->attrs = rta_lookup(a);
548
      e->next = net->routes;
549
      net->routes = e;
550
    }
551
  else
552
    rte_free(e);
553
}
554
555
static void
556
krt_prune(struct krt_proto *p)
557
{
558 4f1a6d27 Martin Mares
  struct rtable *t = p->p.table;
559 2d140452 Martin Mares
560 832fa033 Martin Mares
  KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
561 2d140452 Martin Mares
  FIB_WALK(&t->fib, f)
562
    {
563
      net *n = (net *) f;
564 c10421d3 Martin Mares
      int verdict = f->flags & KRF_VERDICT_MASK;
565 2d140452 Martin Mares
      rte *new, *old;
566
567 c10421d3 Martin Mares
      if (verdict != KRF_CREATE && verdict != KRF_SEEN && verdict != KRF_IGNORE)
568 2d140452 Martin Mares
        {
569
          old = n->routes;
570
          n->routes = old->next;
571
        }
572
      else
573
        old = NULL;
574
      new = n->routes;
575
576
      switch (verdict)
577
        {
578
        case KRF_CREATE:
579 c10421d3 Martin Mares
          if (new && (f->flags & KRF_INSTALLED))
580 2d140452 Martin Mares
            {
581 832fa033 Martin Mares
              krt_trace_in(p, new, "reinstalling");
582 c10421d3 Martin Mares
              krt_set_notify(p, n, new, NULL);
583 2d140452 Martin Mares
            }
584
          break;
585
        case KRF_SEEN:
586 c10421d3 Martin Mares
        case KRF_IGNORE:
587 2d140452 Martin Mares
          /* Nothing happens */
588
          break;
589
        case KRF_UPDATE:
590 832fa033 Martin Mares
          krt_trace_in(p, new, "updating");
591 c10421d3 Martin Mares
          krt_set_notify(p, n, new, old);
592 2d140452 Martin Mares
          break;
593
        case KRF_DELETE:
594 1151401e Martin Mares
          krt_trace_in(p, old, "deleting");
595 c10421d3 Martin Mares
          krt_set_notify(p, n, NULL, old);
596 2d140452 Martin Mares
          break;
597
        default:
598
          bug("krt_prune: invalid route status");
599
        }
600
      if (old)
601
        rte_free(old);
602 c10421d3 Martin Mares
      f->flags &= ~KRF_VERDICT_MASK;
603 2d140452 Martin Mares
    }
604
  FIB_WALK_END;
605 c10421d3 Martin Mares
606
#ifdef KRT_ALLOW_LEARN
607
  if (KRT_CF->learn)
608
    krt_learn_prune(p);
609
#endif
610 aa8761de Martin Mares
  p->initialized = 1;
611 2d140452 Martin Mares
}
612
613 e16155ae Martin Mares
void
614
krt_got_route_async(struct krt_proto *p, rte *e, int new)
615
{
616
  net *net = e->net;
617 c10421d3 Martin Mares
  int src = e->u.krt.src;
618 e16155ae Martin Mares
619
  switch (src)
620
    {
621
    case KRT_SRC_BIRD:
622 832fa033 Martin Mares
      ASSERT(0);                        /* Should be filtered by the back end */
623 e16155ae Martin Mares
    case KRT_SRC_REDIRECT:
624
      DBG("It's a redirect, kill him! Kill! Kill!\n");
625 c10421d3 Martin Mares
      krt_set_notify(p, net, NULL, e);
626 e16155ae Martin Mares
      break;
627 c10421d3 Martin Mares
    case KRT_SRC_ALIEN:
628
#ifdef KRT_ALLOW_LEARN
629
      if (KRT_CF->learn)
630 e16155ae Martin Mares
        {
631 c10421d3 Martin Mares
          krt_learn_async(p, e, new);
632
          return;
633 e16155ae Martin Mares
        }
634 c10421d3 Martin Mares
#endif
635 e16155ae Martin Mares
    }
636 c10421d3 Martin Mares
  rte_free(e);
637 e16155ae Martin Mares
}
638
639 2d140452 Martin Mares
/*
640
 *        Periodic scanning
641
 */
642
643
static void
644
krt_scan(timer *t)
645
{
646 7de45ba4 Martin Mares
  struct krt_proto *p;
647 2d140452 Martin Mares
648 7e5f5ffd Martin Mares
  kif_force_scan();
649 7de45ba4 Martin Mares
#ifdef CONFIG_ALL_TABLES_AT_ONCE
650
  {
651
    void *q;
652 832fa033 Martin Mares
    /* We need some node to decide whether to print the debug messages or not */
653
    p = SKIP_BACK(struct krt_proto, instance_node, HEAD(krt_instance_list));
654
    if (p->instance_node.next)
655
      KRT_TRACE(p, D_EVENTS, "Scanning routing table");
656 7de45ba4 Martin Mares
    krt_scan_fire(NULL);
657
    WALK_LIST(q, krt_instance_list)
658
      {
659
        p = SKIP_BACK(struct krt_proto, instance_node, q);
660
        krt_prune(p);
661
      }
662
  }
663
#else
664
  p = t->data;
665 832fa033 Martin Mares
  KRT_TRACE(p, D_EVENTS, "Scanning routing table");
666 7e5f5ffd Martin Mares
  krt_scan_fire(p);
667
  krt_prune(p);
668 7de45ba4 Martin Mares
#endif
669 2d140452 Martin Mares
}
670
671
/*
672 c10421d3 Martin Mares
 *        Updates
673
 */
674
675
static void
676 02bd064a Martin Mares
krt_notify(struct proto *P, net *net, rte *new, rte *old, struct ea_list *attrs)
677 c10421d3 Martin Mares
{
678
  struct krt_proto *p = (struct krt_proto *) P;
679
680 f990fc61 Martin Mares
  if (shutting_down && KRT_CF->persist)
681
    return;
682 c10421d3 Martin Mares
  if (new && (!krt_capable(new) || new->attrs->source == RTS_INHERIT))
683
    new = NULL;
684
  if (!(net->n.flags & KRF_INSTALLED))
685
    old = NULL;
686
  if (new)
687
    net->n.flags |= KRF_INSTALLED;
688
  else
689
    net->n.flags &= ~KRF_INSTALLED;
690 aa8761de Martin Mares
  if (p->initialized)                        /* Before first scan we don't touch the routes */
691
    krt_set_notify(p, net, new, old);
692 c10421d3 Martin Mares
}
693
694
/*
695 2d140452 Martin Mares
 *        Protocol glue
696
 */
697
698 7e5f5ffd Martin Mares
struct proto_config *cf_krt;
699
700 7de45ba4 Martin Mares
static void
701
krt_preconfig(struct protocol *P, struct config *c)
702
{
703 50fe90ed Martin Mares
  cf_krt = NULL;
704 7de45ba4 Martin Mares
  krt_scan_preconfig(c);
705
}
706
707
static void
708
krt_postconfig(struct proto_config *C)
709
{
710
  struct krt_config *c = (struct krt_config *) C;
711
712
#ifdef CONFIG_ALL_TABLES_AT_ONCE
713
  struct krt_config *first = (struct krt_config *) cf_krt;
714
  if (first->scan_time != c->scan_time)
715
    cf_error("All kernel syncers must use the same table scan interval");
716
#endif
717
718
  if (C->table->krt_attached)
719
    cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name);
720
  C->table->krt_attached = C;
721
  krt_scan_postconfig(c);
722
}
723
724
static timer *
725
krt_start_timer(struct krt_proto *p)
726
{
727
  timer *t;
728
729
  t = tm_new(p->krt_pool);
730
  t->hook = krt_scan;
731
  t->data = p;
732
  t->recurrent = KRT_CF->scan_time;
733 aa8761de Martin Mares
  tm_start(t, 0);
734 7de45ba4 Martin Mares
  return t;
735
}
736
737 2d140452 Martin Mares
static int
738
krt_start(struct proto *P)
739
{
740
  struct krt_proto *p = (struct krt_proto *) P;
741 7de45ba4 Martin Mares
  int first = 1;
742
743
#ifdef CONFIG_ALL_TABLES_AT_ONCE
744
  if (!krt_instance_count++)
745
    init_list(&krt_instance_list);
746
  else
747
    first = 0;
748
  p->krt_pool = krt_pool;
749
  add_tail(&krt_instance_list, &p->instance_node);
750
#else
751
  p->krt_pool = P->pool;
752
#endif
753 2d140452 Martin Mares
754 c10421d3 Martin Mares
#ifdef KRT_ALLOW_LEARN
755
  krt_learn_init(p);
756
#endif
757
758 7de45ba4 Martin Mares
  krt_scan_start(p, first);
759
  krt_set_start(p, first);
760 2d140452 Martin Mares
761 7e5f5ffd Martin Mares
  /* Start periodic routing table scanning */
762 7de45ba4 Martin Mares
#ifdef CONFIG_ALL_TABLES_AT_ONCE
763
  if (first)
764
    krt_scan_timer = krt_start_timer(p);
765 aa8761de Martin Mares
  else
766
    tm_start(p->scan_timer, 0);
767 7de45ba4 Martin Mares
  p->scan_timer = krt_scan_timer;
768
#else
769
  p->scan_timer = krt_start_timer(p);
770
#endif
771 2d140452 Martin Mares
772
  return PS_UP;
773
}
774
775 7de45ba4 Martin Mares
static int
776 2d140452 Martin Mares
krt_shutdown(struct proto *P)
777
{
778
  struct krt_proto *p = (struct krt_proto *) P;
779 7de45ba4 Martin Mares
  int last = 1;
780 2d140452 Martin Mares
781 7de45ba4 Martin Mares
#ifdef CONFIG_ALL_TABLES_AT_ONCE
782
  rem_node(&p->instance_node);
783
  if (--krt_instance_count)
784
    last = 0;
785
  else
786
#endif
787
    tm_stop(p->scan_timer);
788 7e5f5ffd Martin Mares
789 2d140452 Martin Mares
  if (!KRT_CF->persist)
790
    krt_flush_routes(p);
791
792 7de45ba4 Martin Mares
  krt_set_shutdown(p, last);
793
  krt_scan_shutdown(p, last);
794
795
#ifdef CONFIG_ALL_TABLES_AT_ONCE
796
  if (last)
797
    rfree(krt_scan_timer);
798
#endif
799 2d140452 Martin Mares
800
  return PS_DOWN;
801
}
802
803
static struct proto *
804
krt_init(struct proto_config *c)
805
{
806
  struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
807
808 c10421d3 Martin Mares
  p->p.rt_notify = krt_notify;
809 0da472d7 Martin Mares
  p->p.min_scope = SCOPE_HOST;
810 2d140452 Martin Mares
  return &p->p;
811
}
812
813 aa8761de Martin Mares
static int
814
krt_reconfigure(struct proto *p, struct proto_config *new)
815
{
816
  struct krt_config *o = (struct krt_config *) p->cf;
817
  struct krt_config *n = (struct krt_config *) new;
818
819
  return o->scan_time == n->scan_time
820
    && o->learn == n->learn                /* persist needn't be the same */
821
    && krt_set_params_same(&o->set, &n->set)
822
    && krt_scan_params_same(&o->scan, &n->scan)
823
    ;
824
}
825
826 2d140452 Martin Mares
struct protocol proto_unix_kernel = {
827
  name:                "Kernel",
828 d272fe22 Martin Mares
  template:        "kernel%d",
829 7de45ba4 Martin Mares
  preconfig:        krt_preconfig,
830
  postconfig:        krt_postconfig,
831 2d140452 Martin Mares
  init:                krt_init,
832
  start:        krt_start,
833
  shutdown:        krt_shutdown,
834 aa8761de Martin Mares
  reconfigure:        krt_reconfigure,
835 c10421d3 Martin Mares
#ifdef KRT_ALLOW_LEARN
836
  dump:                krt_dump,
837
  dump_attrs:        krt_dump_attrs,
838
#endif
839 2d140452 Martin Mares
};