Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / krt.c @ 1567edea

History | View | Annotate | Download (17.7 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 verdict;
499
#ifdef KRT_ALLOW_LEARN
500
  int src = e->u.krt.src;
501
#endif
502

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

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

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

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

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

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

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

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

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

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

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

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

    
646
/*
647
 *        Periodic scanning
648
 */
649

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

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

    
678
/*
679
 *        Updates
680
 */
681

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

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

    
701
/*
702
 *        Protocol glue
703
 */
704

    
705
struct proto_config *cf_krt;
706

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

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

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

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

    
731
static timer *
732
krt_start_timer(struct krt_proto *p)
733
{
734
  timer *t;
735

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

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

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

    
761
#ifdef KRT_ALLOW_LEARN
762
  krt_learn_init(p);
763
#endif
764

    
765
  krt_scan_start(p, first);
766
  krt_set_start(p, first);
767

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

    
779
  return PS_UP;
780
}
781

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

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

    
796
  if (!KRT_CF->persist)
797
    krt_flush_routes(p);
798

    
799
  krt_set_shutdown(p, last);
800
  krt_scan_shutdown(p, last);
801

    
802
#ifdef CONFIG_ALL_TABLES_AT_ONCE
803
  if (last)
804
    rfree(krt_scan_timer);
805
#endif
806

    
807
  return PS_DOWN;
808
}
809

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

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

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

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

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