Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (17.5 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

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

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

    
57
/*
58
 *        Global resources
59
 */
60

    
61
pool *krt_pool;
62

    
63
void
64
krt_io_init(void)
65
{
66
  krt_pool = rp_new(&root_pool, "Kernel Syncer");
67
  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
kif_preconfig(struct protocol *P, struct config *c)
82
{
83
  cf_kif = NULL;
84
}
85

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

    
91
  KRT_TRACE(p, D_EVENTS, "Scanning interfaces");
92
  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
  /*
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

    
150
  return PS_DOWN;
151
}
152

    
153
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
struct protocol proto_unix_iface = {
172
  name:                "Device",
173
  template:        "device%d",
174
  preconfig:        kif_preconfig,
175
  init:                kif_init,
176
  start:        kif_start,
177
  shutdown:        kif_shutdown,
178
  reconfigure:        kif_reconfigure,
179
};
180

    
181
/*
182
 *        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
 *        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
  net *nn = net_get(p->p.table, n->n.prefix, n->n.pxlen);
220
  ee->net = nn;
221
  ee->pflags = 0;
222
  ee->pref = p->p.preference;
223
  ee->u.krt = e->u.krt;
224
  rte_update(p->p.table, nn, &p->p, ee);
225
}
226

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

    
235
static void
236
krt_learn_scan(struct krt_proto *p, rte *e)
237
{
238
  net *n0 = e->net;
239
  net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
240
  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
          krt_trace_in(p, e, "[alien] seen");
252
          rte_free(e);
253
          m->u.krt.seen = 1;
254
        }
255
      else
256
        {
257
          krt_trace_in(p, e, "[alien] updated");
258
          *mm = m->next;
259
          rte_free(m);
260
          m = NULL;
261
        }
262
    }
263
  else
264
    krt_trace_in(p, e, "[alien] created");
265
  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
  KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
281

    
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
  net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
341
  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
              krt_trace_in(p, e, "[alien async] same");
356
              rte_free(e);
357
              return;
358
            }
359
          krt_trace_in(p, e, "[alien async] updated");
360
          *gg = g->next;
361
          rte_free(g);
362
        }
363
      else
364
        krt_trace_in(p, e, "[alien async] created");
365
      e->attrs = rta_lookup(e->attrs);
366
      e->next = n->routes;
367
      n->routes = e;
368
    }
369
  else if (!g)
370
    {
371
      krt_trace_in(p, e, "[alien async] delete failed");
372
      rte_free(e);
373
      return;
374
    }
375
  else
376
    {
377
      krt_trace_in(p, e, "[alien async] removed");
378
      *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
    rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL);
418
}
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
 *        Routes
441
 */
442

    
443
#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
static void
450
krt_flush_routes(struct krt_proto *p)
451
{
452
  struct rtable *t = p->p.table;
453

    
454
  KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
455
  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
            krt_set_notify(p, e->net, NULL, e);
464
        }
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
  int src = e->u.krt.src;
498
  int verdict;
499

    
500
#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
        krt_trace_in(p, e, "alien route, ignored");
516
      return;
517
    }
518
#endif
519

    
520
  if (net->n.flags & KRF_VERDICT_MASK)
521
    {
522
      /* Route to this destination was already seen. Strange, but it happens... */
523
      krt_trace_in(p, e, "already seen");
524
      return;
525
    }
526

    
527
  if (net->n.flags & KRF_INSTALLED)
528
    {
529
      old = net->routes;
530
      ASSERT(old);
531
      if (krt_uptodate(e, old))
532
        verdict = KRF_SEEN;
533
      else
534
        verdict = KRF_UPDATE;
535
    }
536
  else
537
    verdict = KRF_DELETE;
538

    
539
sentenced:
540
  krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]);
541
  net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
542
  if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
543
    {
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
  struct rtable *t = p->p.table;
559

    
560
  KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
561
  FIB_WALK(&t->fib, f)
562
    {
563
      net *n = (net *) f;
564
      int verdict = f->flags & KRF_VERDICT_MASK;
565
      rte *new, *old;
566

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

    
606
#ifdef KRT_ALLOW_LEARN
607
  if (KRT_CF->learn)
608
    krt_learn_prune(p);
609
#endif
610
  p->initialized = 1;
611
}
612

    
613
void
614
krt_got_route_async(struct krt_proto *p, rte *e, int new)
615
{
616
  net *net = e->net;
617
  int src = e->u.krt.src;
618

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

    
639
/*
640
 *        Periodic scanning
641
 */
642

    
643
static void
644
krt_scan(timer *t)
645
{
646
  struct krt_proto *p;
647

    
648
  kif_force_scan();
649
#ifdef CONFIG_ALL_TABLES_AT_ONCE
650
  {
651
    void *q;
652
    /* 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
    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
  KRT_TRACE(p, D_EVENTS, "Scanning routing table");
666
  krt_scan_fire(p);
667
  krt_prune(p);
668
#endif
669
}
670

    
671
/*
672
 *        Updates
673
 */
674

    
675
static void
676
krt_notify(struct proto *P, net *net, rte *new, rte *old, struct ea_list *attrs)
677
{
678
  struct krt_proto *p = (struct krt_proto *) P;
679

    
680
  if (shutting_down && KRT_CF->persist)
681
    return;
682
  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
  if (p->initialized)                        /* Before first scan we don't touch the routes */
691
    krt_set_notify(p, net, new, old);
692
}
693

    
694
/*
695
 *        Protocol glue
696
 */
697

    
698
struct proto_config *cf_krt;
699

    
700
static void
701
krt_preconfig(struct protocol *P, struct config *c)
702
{
703
  cf_krt = NULL;
704
  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
  tm_start(t, 0);
734
  return t;
735
}
736

    
737
static int
738
krt_start(struct proto *P)
739
{
740
  struct krt_proto *p = (struct krt_proto *) P;
741
  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

    
754
#ifdef KRT_ALLOW_LEARN
755
  krt_learn_init(p);
756
#endif
757

    
758
  krt_scan_start(p, first);
759
  krt_set_start(p, first);
760

    
761
  /* Start periodic routing table scanning */
762
#ifdef CONFIG_ALL_TABLES_AT_ONCE
763
  if (first)
764
    krt_scan_timer = krt_start_timer(p);
765
  else
766
    tm_start(p->scan_timer, 0);
767
  p->scan_timer = krt_scan_timer;
768
#else
769
  p->scan_timer = krt_start_timer(p);
770
#endif
771

    
772
  return PS_UP;
773
}
774

    
775
static int
776
krt_shutdown(struct proto *P)
777
{
778
  struct krt_proto *p = (struct krt_proto *) P;
779
  int last = 1;
780

    
781
#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

    
789
  if (!KRT_CF->persist)
790
    krt_flush_routes(p);
791

    
792
  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

    
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
  p->p.rt_notify = krt_notify;
809
  p->p.min_scope = SCOPE_HOST;
810
  return &p->p;
811
}
812

    
813
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
struct protocol proto_unix_kernel = {
827
  name:                "Kernel",
828
  template:        "kernel%d",
829
  preconfig:        krt_preconfig,
830
  postconfig:        krt_postconfig,
831
  init:                krt_init,
832
  start:        krt_start,
833
  shutdown:        krt_shutdown,
834
  reconfigure:        krt_reconfigure,
835
#ifdef KRT_ALLOW_LEARN
836
  dump:                krt_dump,
837
  dump_attrs:        krt_dump_attrs,
838
#endif
839
};