Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / krt.c @ f7fcb752

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