Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / krt.c @ 6578a604

History | View | Annotate | Download (17.6 KB)

1
/*
2
 *        BIRD -- UNIX Kernel Synchronization
3
 *
4
 *        (c) 1998--2000 Martin Mares <mj@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
/**
10
 * DOC: Kernel synchronization
11
 *
12
 * This system dependent module implements the Kernel and Device protocol,
13
 * that is synchronization of interface lists and routing tables with the
14
 * OS kernel.
15
 *
16
 * The whole kernel synchronization is a bit messy and touches some internals
17
 * of the routing table engine, because routing table maintenance is a typical
18
 * example of the proverbial compatibility between different Unices and we want
19
 * to keep the overhead of our KRT business as low as possible and avoid maintaining
20
 * a local routing table copy.
21
 *
22
 * The kernel syncer can work in three different modes (according to system config header):
23
 * Either with a single routing table and single KRT protocol [traditional UNIX]
24
 * or with many routing tables and separate KRT protocols for all of them
25
 * or with many routing tables, but every scan including all tables, so we start
26
 * separate KRT protocols which cooperate with each other  [Linux 2.2].
27
 * In this case, we keep only a single scan timer.
28
 *
29
 * We use FIB node flags in the routing table to keep track of route
30
 * synchronization status. We also attach temporary &rte's to the routing table,
31
 * but it cannot do any harm to the rest of BIRD since table synchronization is
32
 * an atomic process.
33
 *
34
 * When starting up, we cheat by looking if there is another
35
 * KRT instance to be initialized later and performing table scan
36
 * only once for all the instances.
37
 */
38

    
39
/*
40
 *  If you are brave enough, continue now.  You cannot say you haven't been warned.
41
 */
42

    
43
#undef LOCAL_DEBUG
44

    
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
#include "conf/conf.h"
51
#include "lib/string.h"
52

    
53
#include "unix.h"
54
#include "krt.h"
55

    
56
static int krt_uptodate(rte *k, rte *e);
57

    
58
/*
59
 *        Global resources
60
 */
61

    
62
pool *krt_pool;
63

    
64
void
65
krt_io_init(void)
66
{
67
  krt_pool = rp_new(&root_pool, "Kernel Syncer");
68
  krt_if_io_init();
69
}
70

    
71
/*
72
 *        Interfaces
73
 */
74

    
75
struct proto_config *cf_kif;
76

    
77
static struct kif_proto *kif_proto;
78
static timer *kif_scan_timer;
79
static bird_clock_t kif_last_shot;
80

    
81
static void
82
kif_preconfig(struct protocol *P UNUSED, struct config *c UNUSED)
83
{
84
  cf_kif = NULL;
85
}
86

    
87
static void
88
kif_scan(timer *t)
89
{
90
  struct kif_proto *p = t->data;
91

    
92
  KRT_TRACE(p, D_EVENTS, "Scanning interfaces");
93
  kif_last_shot = now;
94
  krt_if_scan(p);
95
}
96

    
97
static void
98
kif_force_scan(void)
99
{
100
  if (kif_proto && kif_last_shot + 2 < now)
101
    {
102
      kif_scan(kif_scan_timer);
103
      tm_start(kif_scan_timer, ((struct kif_config *) kif_proto->p.cf)->scan_time);
104
    }
105
}
106

    
107
static struct proto *
108
kif_init(struct proto_config *c)
109
{
110
  struct kif_proto *p = proto_new(c, sizeof(struct kif_proto));
111
  return &p->p;
112
}
113

    
114
static int
115
kif_start(struct proto *P)
116
{
117
  struct kif_proto *p = (struct kif_proto *) P;
118

    
119
  kif_proto = p;
120
  krt_if_start(p);
121

    
122
  /* Start periodic interface scanning */
123
  kif_scan_timer = tm_new(P->pool);
124
  kif_scan_timer->hook = kif_scan;
125
  kif_scan_timer->data = p;
126
  kif_scan_timer->recurrent = KIF_CF->scan_time;
127
  kif_scan(kif_scan_timer);
128
  tm_start(kif_scan_timer, KIF_CF->scan_time);
129

    
130
  return PS_UP;
131
}
132

    
133
static int
134
kif_shutdown(struct proto *P)
135
{
136
  struct kif_proto *p = (struct kif_proto *) P;
137

    
138
  tm_stop(kif_scan_timer);
139
  krt_if_shutdown(p);
140
  kif_proto = NULL;
141

    
142
  if_start_update();        /* Remove all interfaces */
143
  if_end_update();
144
  /*
145
   *  FIXME: Is it really a good idea?  It causes routes to be flushed,
146
   *  but at the same time it avoids sending of these deletions to the kernel,
147
   *  because krt thinks the kernel itself has already removed the route
148
   *  when downing the interface.  Sad.
149
   */
150

    
151
  return PS_DOWN;
152
}
153

    
154
static int
155
kif_reconfigure(struct proto *p, struct proto_config *new)
156
{
157
  struct kif_config *o = (struct kif_config *) p->cf;
158
  struct kif_config *n = (struct kif_config *) new;
159

    
160
  if (!kif_params_same(&o->iface, &n->iface))
161
    return 0;
162
  if (o->scan_time != n->scan_time)
163
    {
164
      tm_stop(kif_scan_timer);
165
      kif_scan_timer->recurrent = n->scan_time;
166
      kif_scan(kif_scan_timer);
167
      tm_start(kif_scan_timer, n->scan_time);
168
    }
169
  return 1;
170
}
171

    
172
struct protocol proto_unix_iface = {
173
  name:                "Device",
174
  template:        "device%d",
175
  preconfig:        kif_preconfig,
176
  init:                kif_init,
177
  start:        kif_start,
178
  shutdown:        kif_shutdown,
179
  reconfigure:        kif_reconfigure,
180
};
181

    
182
/*
183
 *        Tracing of routes
184
 */
185

    
186
static void
187
krt_trace_in_print(struct krt_proto *p, rte *e, char *msg)
188
{
189
  DBG("KRT: %I/%d: %s\n", e->net->n.prefix, e->net->n.pxlen, msg);
190
  log(L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg);
191
}
192

    
193
static inline void
194
krt_trace_in(struct krt_proto *p, rte *e, char *msg)
195
{
196
  if (p->p.debug & D_PACKETS)
197
    krt_trace_in_print(p, e, msg);
198
}
199

    
200
/*
201
 *        Inherited Routes
202
 */
203

    
204
#ifdef KRT_ALLOW_LEARN
205

    
206
static inline int
207
krt_same_key(rte *a, rte *b)
208
{
209
  return a->u.krt.proto == b->u.krt.proto &&
210
         a->u.krt.metric == b->u.krt.metric &&
211
         a->u.krt.type == b->u.krt.type;
212
}
213

    
214
static void
215
krt_learn_announce_update(struct krt_proto *p, rte *e)
216
{
217
  net *n = e->net;
218
  rta *aa = rta_clone(e->attrs);
219
  rte *ee = rte_get_temp(aa);
220
  net *nn = net_get(p->p.table, n->n.prefix, n->n.pxlen);
221
  ee->net = nn;
222
  ee->pflags = 0;
223
  ee->pref = p->p.preference;
224
  ee->u.krt = e->u.krt;
225
  rte_update(p->p.table, nn, &p->p, ee);
226
}
227

    
228
static void
229
krt_learn_announce_delete(struct krt_proto *p, net *n)
230
{
231
  n = net_find(p->p.table, n->n.prefix, n->n.pxlen);
232
  if (n)
233
    rte_update(p->p.table, n, &p->p, NULL);
234
}
235

    
236
static void
237
krt_learn_scan(struct krt_proto *p, rte *e)
238
{
239
  net *n0 = e->net;
240
  net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
241
  rte *m, **mm;
242

    
243
  e->attrs->source = RTS_INHERIT;
244

    
245
  for(mm=&n->routes; m = *mm; mm=&m->next)
246
    if (krt_same_key(m, e))
247
      break;
248
  if (m)
249
    {
250
      if (krt_uptodate(m, e))
251
        {
252
          krt_trace_in(p, e, "[alien] seen");
253
          rte_free(e);
254
          m->u.krt.seen = 1;
255
        }
256
      else
257
        {
258
          krt_trace_in(p, e, "[alien] updated");
259
          *mm = m->next;
260
          rte_free(m);
261
          m = NULL;
262
        }
263
    }
264
  else
265
    krt_trace_in(p, e, "[alien] created");
266
  if (!m)
267
    {
268
      e->attrs = rta_lookup(e->attrs);
269
      e->next = n->routes;
270
      n->routes = e;
271
      e->u.krt.seen = 1;
272
    }
273
}
274

    
275
static void
276
krt_learn_prune(struct krt_proto *p)
277
{
278
  struct fib *fib = &p->krt_table.fib;
279
  struct fib_iterator fit;
280

    
281
  KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
282

    
283
  FIB_ITERATE_INIT(&fit, fib);
284
again:
285
  FIB_ITERATE_START(fib, &fit, f)
286
    {
287
      net *n = (net *) f;
288
      rte *e, **ee, *best, **pbest, *old_best;
289

    
290
      old_best = n->routes;
291
      best = NULL;
292
      pbest = NULL;
293
      ee = &n->routes;
294
      while (e = *ee)
295
        {
296
          if (!e->u.krt.seen)
297
            {
298
              *ee = e->next;
299
              rte_free(e);
300
              continue;
301
            }
302
          if (!best || best->u.krt.metric > e->u.krt.metric)
303
            {
304
              best = e;
305
              pbest = ee;
306
            }
307
          e->u.krt.seen = 0;
308
          ee = &e->next;
309
        }
310
      if (!n->routes)
311
        {
312
          DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
313
          if (old_best)
314
            {
315
              krt_learn_announce_delete(p, n);
316
              n->n.flags &= ~KRF_INSTALLED;
317
            }
318
          FIB_ITERATE_PUT(&fit, f);
319
          fib_delete(fib, f);
320
          goto again;
321
        }
322
      *pbest = best->next;
323
      best->next = n->routes;
324
      n->routes = best;
325
      if (best != old_best || !(n->n.flags & KRF_INSTALLED))
326
        {
327
          DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
328
          krt_learn_announce_update(p, best);
329
          n->n.flags |= KRF_INSTALLED;
330
        }
331
      else
332
        DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
333
    }
334
  FIB_ITERATE_END(f);
335
}
336

    
337
static void
338
krt_learn_async(struct krt_proto *p, rte *e, int new)
339
{
340
  net *n0 = e->net;
341
  net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
342
  rte *g, **gg, *best, **bestp, *old_best;
343

    
344
  e->attrs->source = RTS_INHERIT;
345

    
346
  old_best = n->routes;
347
  for(gg=&n->routes; g = *gg; gg = &g->next)
348
    if (krt_same_key(g, e))
349
      break;
350
  if (new)
351
    {
352
      if (g)
353
        {
354
          if (krt_uptodate(g, e))
355
            {
356
              krt_trace_in(p, e, "[alien async] same");
357
              rte_free(e);
358
              return;
359
            }
360
          krt_trace_in(p, e, "[alien async] updated");
361
          *gg = g->next;
362
          rte_free(g);
363
        }
364
      else
365
        krt_trace_in(p, e, "[alien async] created");
366
      e->attrs = rta_lookup(e->attrs);
367
      e->next = n->routes;
368
      n->routes = e;
369
    }
370
  else if (!g)
371
    {
372
      krt_trace_in(p, e, "[alien async] delete failed");
373
      rte_free(e);
374
      return;
375
    }
376
  else
377
    {
378
      krt_trace_in(p, e, "[alien async] removed");
379
      *gg = g->next;
380
      rte_free(e);
381
      rte_free(g);
382
    }
383
  best = n->routes;
384
  bestp = &n->routes;
385
  for(gg=&n->routes; g=*gg; gg=&g->next)
386
    if (best->u.krt.metric > g->u.krt.metric)
387
      {
388
        best = g;
389
        bestp = gg;
390
      }
391
  if (best)
392
    {
393
      *bestp = best->next;
394
      best->next = n->routes;
395
      n->routes = best;
396
    }
397
  if (best != old_best)
398
    {
399
      DBG("krt_learn_async: distributing change\n");
400
      if (best)
401
        {
402
          krt_learn_announce_update(p, best);
403
          n->n.flags |= KRF_INSTALLED;
404
        }
405
      else
406
        {
407
          n->routes = NULL;
408
          krt_learn_announce_delete(p, n);
409
          n->n.flags &= ~KRF_INSTALLED;
410
        }
411
    }
412
}
413

    
414
static void
415
krt_learn_init(struct krt_proto *p)
416
{
417
  if (KRT_CF->learn)
418
    rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL);
419
}
420

    
421
static void
422
krt_dump(struct proto *P)
423
{
424
  struct krt_proto *p = (struct krt_proto *) P;
425

    
426
  if (!KRT_CF->learn)
427
    return;
428
  debug("KRT: Table of inheritable routes\n");
429
  rt_dump(&p->krt_table);
430
}
431

    
432
static void
433
krt_dump_attrs(rte *e)
434
{
435
  debug(" [m=%d,p=%d,t=%d]", e->u.krt.metric, e->u.krt.proto, e->u.krt.type);
436
}
437

    
438
#endif
439

    
440
/*
441
 *        Routes
442
 */
443

    
444
#ifdef CONFIG_ALL_TABLES_AT_ONCE
445
static timer *krt_scan_timer;
446
static int krt_instance_count;
447
static list krt_instance_list;
448
#endif
449

    
450
static void
451
krt_flush_routes(struct krt_proto *p)
452
{
453
  struct rtable *t = p->p.table;
454

    
455
  KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
456
  FIB_WALK(&t->fib, f)
457
    {
458
      net *n = (net *) f;
459
      rte *e = n->routes;
460
      if (e)
461
        {
462
          rta *a = e->attrs;
463
          if (a->source != RTS_DEVICE && a->source != RTS_INHERIT)
464
            krt_set_notify(p, e->net, NULL, e);
465
        }
466
    }
467
  FIB_WALK_END;
468
}
469

    
470
static int
471
krt_uptodate(rte *k, rte *e)
472
{
473
  rta *ka = k->attrs, *ea = e->attrs;
474

    
475
  if (ka->dest != ea->dest)
476
    return 0;
477
  switch (ka->dest)
478
    {
479
    case RTD_ROUTER:
480
      return ipa_equal(ka->gw, ea->gw);
481
    case RTD_DEVICE:
482
      return !strcmp(ka->iface->name, ea->iface->name);
483
    default:
484
      return 1;
485
    }
486
}
487

    
488
/*
489
 *  This gets called back when the low-level scanning code discovers a route.
490
 *  We expect that the route is a temporary rte and its attributes are uncached.
491
 */
492

    
493
void
494
krt_got_route(struct krt_proto *p, rte *e)
495
{
496
  rte *old;
497
  net *net = e->net;
498
  int src = e->u.krt.src;
499
  int verdict;
500

    
501
#ifdef CONFIG_AUTO_ROUTES
502
  if (e->attrs->dest == RTD_DEVICE)
503
    {
504
      /* It's a device route. Probably a kernel-generated one. */
505
      verdict = KRF_IGNORE;
506
      goto sentenced;
507
    }
508
#endif
509

    
510
#ifdef KRT_ALLOW_LEARN
511
  if (src == KRT_SRC_ALIEN)
512
    {
513
      if (KRT_CF->learn)
514
        krt_learn_scan(p, e);
515
      else
516
        {
517
          krt_trace_in(p, e, "alien route, ignored");
518
          rte_free(e);
519
        }
520
      return;
521
    }
522
#endif
523

    
524
  if (net->n.flags & KRF_VERDICT_MASK)
525
    {
526
      /* Route to this destination was already seen. Strange, but it happens... */
527
      krt_trace_in(p, e, "already seen");
528
      rte_free(e);
529
      return;
530
    }
531

    
532
  if (net->n.flags & KRF_INSTALLED)
533
    {
534
      old = net->routes;
535
      ASSERT(old);
536
      if (krt_uptodate(e, old))
537
        verdict = KRF_SEEN;
538
      else
539
        verdict = KRF_UPDATE;
540
    }
541
  else
542
    verdict = KRF_DELETE;
543

    
544
sentenced:
545
  krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]);
546
  net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
547
  if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
548
    {
549
      /* Get a cached copy of attributes and link the route */
550
      rta *a = e->attrs;
551
      a->source = RTS_DUMMY;
552
      e->attrs = rta_lookup(a);
553
      e->next = net->routes;
554
      net->routes = e;
555
    }
556
  else
557
    rte_free(e);
558
}
559

    
560
static void
561
krt_prune(struct krt_proto *p)
562
{
563
  struct rtable *t = p->p.table;
564

    
565
  KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
566
  FIB_WALK(&t->fib, f)
567
    {
568
      net *n = (net *) f;
569
      int verdict = f->flags & KRF_VERDICT_MASK;
570
      rte *new, *old;
571

    
572
      if (verdict != KRF_CREATE && verdict != KRF_SEEN && verdict != KRF_IGNORE)
573
        {
574
          old = n->routes;
575
          n->routes = old->next;
576
        }
577
      else
578
        old = NULL;
579
      new = n->routes;
580

    
581
      switch (verdict)
582
        {
583
        case KRF_CREATE:
584
          if (new && (f->flags & KRF_INSTALLED))
585
            {
586
              krt_trace_in(p, new, "reinstalling");
587
              krt_set_notify(p, n, new, NULL);
588
            }
589
          break;
590
        case KRF_SEEN:
591
        case KRF_IGNORE:
592
          /* Nothing happens */
593
          break;
594
        case KRF_UPDATE:
595
          krt_trace_in(p, new, "updating");
596
          krt_set_notify(p, n, new, old);
597
          break;
598
        case KRF_DELETE:
599
          krt_trace_in(p, old, "deleting");
600
          krt_set_notify(p, n, NULL, old);
601
          break;
602
        default:
603
          bug("krt_prune: invalid route status");
604
        }
605
      if (old)
606
        rte_free(old);
607
      f->flags &= ~KRF_VERDICT_MASK;
608
    }
609
  FIB_WALK_END;
610

    
611
#ifdef KRT_ALLOW_LEARN
612
  if (KRT_CF->learn)
613
    krt_learn_prune(p);
614
#endif
615
  p->initialized = 1;
616
}
617

    
618
void
619
krt_got_route_async(struct krt_proto *p, rte *e, int new)
620
{
621
  net *net = e->net;
622
  int src = e->u.krt.src;
623

    
624
  switch (src)
625
    {
626
    case KRT_SRC_BIRD:
627
      ASSERT(0);                        /* Should be filtered by the back end */
628
    case KRT_SRC_REDIRECT:
629
      DBG("It's a redirect, kill him! Kill! Kill!\n");
630
      krt_set_notify(p, net, NULL, e);
631
      break;
632
    case KRT_SRC_ALIEN:
633
#ifdef KRT_ALLOW_LEARN
634
      if (KRT_CF->learn)
635
        {
636
          krt_learn_async(p, e, new);
637
          return;
638
        }
639
#endif
640
    }
641
  rte_free(e);
642
}
643

    
644
/*
645
 *        Periodic scanning
646
 */
647

    
648
static void
649
krt_scan(timer *t UNUSED)
650
{
651
  struct krt_proto *p;
652

    
653
  kif_force_scan();
654
#ifdef CONFIG_ALL_TABLES_AT_ONCE
655
  {
656
    void *q;
657
    /* We need some node to decide whether to print the debug messages or not */
658
    p = SKIP_BACK(struct krt_proto, instance_node, HEAD(krt_instance_list));
659
    if (p->instance_node.next)
660
      KRT_TRACE(p, D_EVENTS, "Scanning routing table");
661
    krt_scan_fire(NULL);
662
    WALK_LIST(q, krt_instance_list)
663
      {
664
        p = SKIP_BACK(struct krt_proto, instance_node, q);
665
        krt_prune(p);
666
      }
667
  }
668
#else
669
  p = t->data;
670
  KRT_TRACE(p, D_EVENTS, "Scanning routing table");
671
  krt_scan_fire(p);
672
  krt_prune(p);
673
#endif
674
}
675

    
676
/*
677
 *        Updates
678
 */
679

    
680
static void
681
krt_notify(struct proto *P, net *net, rte *new, rte *old, struct ea_list *attrs UNUSED)
682
{
683
  struct krt_proto *p = (struct krt_proto *) P;
684

    
685
  if (shutting_down && KRT_CF->persist)
686
    return;
687
  if (new && (!krt_capable(new) || new->attrs->source == RTS_INHERIT))
688
    new = NULL;
689
  if (!(net->n.flags & KRF_INSTALLED))
690
    old = NULL;
691
  if (new)
692
    net->n.flags |= KRF_INSTALLED;
693
  else
694
    net->n.flags &= ~KRF_INSTALLED;
695
  if (p->initialized)                        /* Before first scan we don't touch the routes */
696
    krt_set_notify(p, net, new, old);
697
}
698

    
699
/*
700
 *        Protocol glue
701
 */
702

    
703
struct proto_config *cf_krt;
704

    
705
static void
706
krt_preconfig(struct protocol *P UNUSED, struct config *c)
707
{
708
  cf_krt = NULL;
709
  krt_scan_preconfig(c);
710
}
711

    
712
static void
713
krt_postconfig(struct proto_config *C)
714
{
715
  struct krt_config *c = (struct krt_config *) C;
716

    
717
#ifdef CONFIG_ALL_TABLES_AT_ONCE
718
  struct krt_config *first = (struct krt_config *) cf_krt;
719
  if (first->scan_time != c->scan_time)
720
    cf_error("All kernel syncers must use the same table scan interval");
721
#endif
722

    
723
  if (C->table->krt_attached)
724
    cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name);
725
  C->table->krt_attached = C;
726
  krt_scan_postconfig(c);
727
}
728

    
729
static timer *
730
krt_start_timer(struct krt_proto *p)
731
{
732
  timer *t;
733

    
734
  t = tm_new(p->krt_pool);
735
  t->hook = krt_scan;
736
  t->data = p;
737
  t->recurrent = KRT_CF->scan_time;
738
  tm_start(t, 0);
739
  return t;
740
}
741

    
742
static int
743
krt_start(struct proto *P)
744
{
745
  struct krt_proto *p = (struct krt_proto *) P;
746
  int first = 1;
747

    
748
#ifdef CONFIG_ALL_TABLES_AT_ONCE
749
  if (!krt_instance_count++)
750
    init_list(&krt_instance_list);
751
  else
752
    first = 0;
753
  p->krt_pool = krt_pool;
754
  add_tail(&krt_instance_list, &p->instance_node);
755
#else
756
  p->krt_pool = P->pool;
757
#endif
758

    
759
#ifdef KRT_ALLOW_LEARN
760
  krt_learn_init(p);
761
#endif
762

    
763
  krt_scan_start(p, first);
764
  krt_set_start(p, first);
765

    
766
  /* Start periodic routing table scanning */
767
#ifdef CONFIG_ALL_TABLES_AT_ONCE
768
  if (first)
769
    krt_scan_timer = krt_start_timer(p);
770
  else
771
    tm_start(p->scan_timer, 0);
772
  p->scan_timer = krt_scan_timer;
773
#else
774
  p->scan_timer = krt_start_timer(p);
775
#endif
776

    
777
  return PS_UP;
778
}
779

    
780
static int
781
krt_shutdown(struct proto *P)
782
{
783
  struct krt_proto *p = (struct krt_proto *) P;
784
  int last = 1;
785

    
786
#ifdef CONFIG_ALL_TABLES_AT_ONCE
787
  rem_node(&p->instance_node);
788
  if (--krt_instance_count)
789
    last = 0;
790
  else
791
#endif
792
    tm_stop(p->scan_timer);
793

    
794
  if (!KRT_CF->persist)
795
    krt_flush_routes(p);
796

    
797
  krt_set_shutdown(p, last);
798
  krt_scan_shutdown(p, last);
799

    
800
#ifdef CONFIG_ALL_TABLES_AT_ONCE
801
  if (last)
802
    rfree(krt_scan_timer);
803
#endif
804

    
805
  return PS_DOWN;
806
}
807

    
808
static struct proto *
809
krt_init(struct proto_config *c)
810
{
811
  struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
812

    
813
  p->p.rt_notify = krt_notify;
814
  p->p.min_scope = SCOPE_HOST;
815
  return &p->p;
816
}
817

    
818
static int
819
krt_reconfigure(struct proto *p, struct proto_config *new)
820
{
821
  struct krt_config *o = (struct krt_config *) p->cf;
822
  struct krt_config *n = (struct krt_config *) new;
823

    
824
  return o->scan_time == n->scan_time
825
    && o->learn == n->learn                /* persist needn't be the same */
826
    && krt_set_params_same(&o->set, &n->set)
827
    && krt_scan_params_same(&o->scan, &n->scan)
828
    ;
829
}
830

    
831
struct protocol proto_unix_kernel = {
832
  name:                "Kernel",
833
  template:        "kernel%d",
834
  preconfig:        krt_preconfig,
835
  postconfig:        krt_postconfig,
836
  init:                krt_init,
837
  start:        krt_start,
838
  shutdown:        krt_shutdown,
839
  reconfigure:        krt_reconfigure,
840
#ifdef KRT_ALLOW_LEARN
841
  dump:                krt_dump,
842
  dump_attrs:        krt_dump_attrs,
843
#endif
844
};