Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (24.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].
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
 * The code uses OS-dependent parts for kernel updates and scans. These parts are
39
 * in more specific sysdep directories (e.g. sysdep/linux) in functions krt_sys_* 
40
 * and kif_sys_* (and some others like krt_replace_rte()) and krt-sys.h header file.
41
 * This is also used for platform specific protocol options and route attributes.
42
 *
43
 * There was also an old code that used traditional UNIX ioctls for these tasks.
44
 * It was unmaintained and later removed. For reference, see sysdep/krt-* files
45
 * in commit 396dfa9042305f62da1f56589c4b98fac57fc2f6
46
 */
47

    
48
/*
49
 *  If you are brave enough, continue now.  You cannot say you haven't been warned.
50
 */
51

    
52
#undef LOCAL_DEBUG
53

    
54
#include "nest/bird.h"
55
#include "nest/iface.h"
56
#include "nest/route.h"
57
#include "nest/protocol.h"
58
#include "filter/filter.h"
59
#include "lib/timer.h"
60
#include "conf/conf.h"
61
#include "lib/string.h"
62

    
63
#include "unix.h"
64
#include "krt.h"
65

    
66
/*
67
 *        Global resources
68
 */
69

    
70
pool *krt_pool;
71
static linpool *krt_filter_lp;
72

    
73
void
74
krt_io_init(void)
75
{
76
  krt_pool = rp_new(&root_pool, "Kernel Syncer");
77
  krt_filter_lp = lp_new(krt_pool, 4080);
78
}
79

    
80
/*
81
 *        Interfaces
82
 */
83

    
84
static struct kif_config *kif_cf;
85
static struct kif_proto *kif_proto;
86
static timer *kif_scan_timer;
87
static bird_clock_t kif_last_shot;
88

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

    
94
  KRT_TRACE(p, D_EVENTS, "Scanning interfaces");
95
  kif_last_shot = now;
96
  kif_do_scan(p);
97
}
98

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

    
109
void
110
kif_request_scan(void)
111
{
112
  if (kif_proto && kif_scan_timer->expires > now)
113
    tm_start(kif_scan_timer, 1);
114
}
115

    
116
static inline int
117
prefer_addr(struct ifa *a, struct ifa *b)
118
{ 
119
  int sa = a->scope > SCOPE_LINK;
120
  int sb = b->scope > SCOPE_LINK;
121

    
122
  if (sa < sb)
123
    return 0;
124
  else if (sa > sb)
125
    return 1;
126
  else
127
    return ipa_compare(a->ip, b->ip) < 0;
128
}
129

    
130
static inline struct ifa *
131
find_preferred_ifa(struct iface *i, ip_addr prefix, ip_addr mask)
132
{
133
  struct ifa *a, *b = NULL;
134

    
135
  WALK_LIST(a, i->addrs)
136
    {
137
      if (!(a->flags & IA_SECONDARY) &&
138
          ipa_equal(ipa_and(a->ip, mask), prefix) &&
139
          (!b || prefer_addr(a, b)))
140
        b = a;
141
    }
142

    
143
  return b;
144
}
145

    
146
struct ifa *
147
kif_choose_primary(struct iface *i)
148
{
149
  struct kif_config *cf = (struct kif_config *) (kif_proto->p.cf);
150
  struct kif_primary_item *it;
151
  struct ifa *a;
152

    
153
  WALK_LIST(it, cf->primary)
154
    {
155
      if (!it->pattern || patmatch(it->pattern, i->name))
156
        if (a = find_preferred_ifa(i, it->prefix, ipa_mkmask(it->pxlen)))
157
          return a;
158
    }
159

    
160
  return find_preferred_ifa(i, IPA_NONE, IPA_NONE);
161
}
162

    
163

    
164
static struct proto *
165
kif_init(struct proto_config *c)
166
{
167
  struct kif_proto *p = proto_new(c, sizeof(struct kif_proto));
168

    
169
  kif_sys_init(p);
170
  return &p->p;
171
}
172

    
173
static int
174
kif_start(struct proto *P)
175
{
176
  struct kif_proto *p = (struct kif_proto *) P;
177

    
178
  kif_proto = p;
179
  kif_sys_start(p);
180

    
181
  /* Start periodic interface scanning */
182
  kif_scan_timer = tm_new(P->pool);
183
  kif_scan_timer->hook = kif_scan;
184
  kif_scan_timer->data = p;
185
  kif_scan_timer->recurrent = KIF_CF->scan_time;
186
  kif_scan(kif_scan_timer);
187
  tm_start(kif_scan_timer, KIF_CF->scan_time);
188

    
189
  return PS_UP;
190
}
191

    
192
static int
193
kif_shutdown(struct proto *P)
194
{
195
  struct kif_proto *p = (struct kif_proto *) P;
196

    
197
  tm_stop(kif_scan_timer);
198
  kif_sys_shutdown(p);
199
  kif_proto = NULL;
200

    
201
  return PS_DOWN;
202
}
203

    
204
static int
205
kif_reconfigure(struct proto *p, struct proto_config *new)
206
{
207
  struct kif_config *o = (struct kif_config *) p->cf;
208
  struct kif_config *n = (struct kif_config *) new;
209

    
210
  if (!kif_sys_reconfigure((struct kif_proto *) p, n, o))
211
    return 0;
212

    
213
  if (o->scan_time != n->scan_time)
214
    {
215
      tm_stop(kif_scan_timer);
216
      kif_scan_timer->recurrent = n->scan_time;
217
      kif_scan(kif_scan_timer);
218
      tm_start(kif_scan_timer, n->scan_time);
219
    }
220

    
221
  if (!EMPTY_LIST(o->primary) || !EMPTY_LIST(n->primary))
222
    {
223
      /* This is hack, we have to update a configuration
224
       * to the new value just now, because it is used
225
       * for recalculation of primary addresses.
226
       */
227
      p->cf = new;
228

    
229
      ifa_recalc_all_primary_addresses();
230
    }
231

    
232
  return 1;
233
}
234

    
235

    
236
static void
237
kif_preconfig(struct protocol *P UNUSED, struct config *c)
238
{
239
  kif_cf = NULL;
240
  kif_sys_preconfig(c);
241
}
242

    
243
struct proto_config *
244
kif_init_config(int class)
245
{
246
  if (kif_cf)
247
    cf_error("Kernel device protocol already defined");
248

    
249
  kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, sizeof(struct kif_config), class);
250
  kif_cf->scan_time = 60;
251
  init_list(&kif_cf->primary);
252

    
253
  kif_sys_init_config(kif_cf);
254
  return (struct proto_config *) kif_cf;
255
}
256

    
257
static void
258
kif_copy_config(struct proto_config *dest, struct proto_config *src)
259
{
260
  struct kif_config *d = (struct kif_config *) dest;
261
  struct kif_config *s = (struct kif_config *) src;
262

    
263
  /* Shallow copy of everything (just scan_time currently) */
264
  proto_copy_rest(dest, src, sizeof(struct kif_config));
265

    
266
  /* Copy primary addr list */
267
  cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item));
268

    
269
  /* Fix sysdep parts */
270
  kif_sys_copy_config(d, s);
271
}
272

    
273

    
274
struct protocol proto_unix_iface = {
275
  name:                "Device",
276
  template:        "device%d",
277
  preference:        DEF_PREF_DIRECT,
278
  preconfig:        kif_preconfig,
279
  init:                kif_init,
280
  start:        kif_start,
281
  shutdown:        kif_shutdown,
282
  reconfigure:        kif_reconfigure,
283
  copy_config:        kif_copy_config
284
};
285

    
286
/*
287
 *        Tracing of routes
288
 */
289

    
290
static inline void
291
krt_trace_in(struct krt_proto *p, rte *e, char *msg)
292
{
293
  if (p->p.debug & D_PACKETS)
294
    log(L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg);
295
}
296

    
297
static inline void
298
krt_trace_in_rl(struct rate_limit *rl, struct krt_proto *p, rte *e, char *msg)
299
{
300
  if (p->p.debug & D_PACKETS)
301
    log_rl(rl, L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg);
302
}
303

    
304
/*
305
 *        Inherited Routes
306
 */
307

    
308
#ifdef KRT_ALLOW_LEARN
309

    
310
static struct rate_limit rl_alien_seen, rl_alien_updated, rl_alien_created, rl_alien_ignored;
311

    
312
/*
313
 * krt_same_key() specifies what (aside from the net) is the key in
314
 * kernel routing tables. It should be OS-dependent, this is for
315
 * Linux. It is important for asynchronous alien updates, because a
316
 * positive update is implicitly a negative one for any old route with
317
 * the same key.
318
 */
319

    
320
static inline int
321
krt_same_key(rte *a, rte *b)
322
{
323
  return a->u.krt.metric == b->u.krt.metric;
324
}
325

    
326
static inline int
327
krt_uptodate(rte *a, rte *b)
328
{
329
  if (a->attrs != b->attrs)
330
    return 0;
331

    
332
  if (a->u.krt.proto != b->u.krt.proto)
333
    return 0;
334

    
335
  return 1;
336
}
337

    
338
static void
339
krt_learn_announce_update(struct krt_proto *p, rte *e)
340
{
341
  net *n = e->net;
342
  rta *aa = rta_clone(e->attrs);
343
  rte *ee = rte_get_temp(aa);
344
  net *nn = net_get(p->p.table, n->n.prefix, n->n.pxlen);
345
  ee->net = nn;
346
  ee->pflags = 0;
347
  ee->pref = p->p.preference;
348
  ee->u.krt = e->u.krt;
349
  rte_update(p->p.table, nn, &p->p, &p->p, ee);
350
}
351

    
352
static void
353
krt_learn_announce_delete(struct krt_proto *p, net *n)
354
{
355
  n = net_find(p->p.table, n->n.prefix, n->n.pxlen);
356
  if (n)
357
    rte_update(p->p.table, n, &p->p, &p->p, NULL);
358
}
359

    
360
/* Called when alien route is discovered during scan */
361
static void
362
krt_learn_scan(struct krt_proto *p, rte *e)
363
{
364
  net *n0 = e->net;
365
  net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
366
  rte *m, **mm;
367

    
368
  e->attrs = rta_lookup(e->attrs);
369

    
370
  for(mm=&n->routes; m = *mm; mm=&m->next)
371
    if (krt_same_key(m, e))
372
      break;
373
  if (m)
374
    {
375
      if (krt_uptodate(m, e))
376
        {
377
          krt_trace_in_rl(&rl_alien_seen, p, e, "[alien] seen");
378
          rte_free(e);
379
          m->u.krt.seen = 1;
380
        }
381
      else
382
        {
383
          krt_trace_in_rl(&rl_alien_updated, p, e, "[alien] updated");
384
          *mm = m->next;
385
          rte_free(m);
386
          m = NULL;
387
        }
388
    }
389
  else
390
    krt_trace_in_rl(&rl_alien_created, p, e, "[alien] created");
391
  if (!m)
392
    {
393
      e->next = n->routes;
394
      n->routes = e;
395
      e->u.krt.seen = 1;
396
    }
397
}
398

    
399
static void
400
krt_learn_prune(struct krt_proto *p)
401
{
402
  struct fib *fib = &p->krt_table.fib;
403
  struct fib_iterator fit;
404

    
405
  KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
406

    
407
  FIB_ITERATE_INIT(&fit, fib);
408
again:
409
  FIB_ITERATE_START(fib, &fit, f)
410
    {
411
      net *n = (net *) f;
412
      rte *e, **ee, *best, **pbest, *old_best;
413

    
414
      old_best = n->routes;
415
      best = NULL;
416
      pbest = NULL;
417
      ee = &n->routes;
418
      while (e = *ee)
419
        {
420
          if (!e->u.krt.seen)
421
            {
422
              *ee = e->next;
423
              rte_free(e);
424
              continue;
425
            }
426
          if (!best || best->u.krt.metric > e->u.krt.metric)
427
            {
428
              best = e;
429
              pbest = ee;
430
            }
431
          e->u.krt.seen = 0;
432
          ee = &e->next;
433
        }
434
      if (!n->routes)
435
        {
436
          DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
437
          if (old_best)
438
            {
439
              krt_learn_announce_delete(p, n);
440
              n->n.flags &= ~KRF_INSTALLED;
441
            }
442
          FIB_ITERATE_PUT(&fit, f);
443
          fib_delete(fib, f);
444
          goto again;
445
        }
446
      *pbest = best->next;
447
      best->next = n->routes;
448
      n->routes = best;
449
      if (best != old_best || !(n->n.flags & KRF_INSTALLED))
450
        {
451
          DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
452
          krt_learn_announce_update(p, best);
453
          n->n.flags |= KRF_INSTALLED;
454
        }
455
      else
456
        DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
457
    }
458
  FIB_ITERATE_END(f);
459
}
460

    
461
static void
462
krt_learn_async(struct krt_proto *p, rte *e, int new)
463
{
464
  net *n0 = e->net;
465
  net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
466
  rte *g, **gg, *best, **bestp, *old_best;
467

    
468
  e->attrs = rta_lookup(e->attrs);
469

    
470
  old_best = n->routes;
471
  for(gg=&n->routes; g = *gg; gg = &g->next)
472
    if (krt_same_key(g, e))
473
      break;
474
  if (new)
475
    {
476
      if (g)
477
        {
478
          if (krt_uptodate(g, e))
479
            {
480
              krt_trace_in(p, e, "[alien async] same");
481
              rte_free(e);
482
              return;
483
            }
484
          krt_trace_in(p, e, "[alien async] updated");
485
          *gg = g->next;
486
          rte_free(g);
487
        }
488
      else
489
        krt_trace_in(p, e, "[alien async] created");
490

    
491
      e->next = n->routes;
492
      n->routes = e;
493
    }
494
  else if (!g)
495
    {
496
      krt_trace_in(p, e, "[alien async] delete failed");
497
      rte_free(e);
498
      return;
499
    }
500
  else
501
    {
502
      krt_trace_in(p, e, "[alien async] removed");
503
      *gg = g->next;
504
      rte_free(e);
505
      rte_free(g);
506
    }
507
  best = n->routes;
508
  bestp = &n->routes;
509
  for(gg=&n->routes; g=*gg; gg=&g->next)
510
    if (best->u.krt.metric > g->u.krt.metric)
511
      {
512
        best = g;
513
        bestp = gg;
514
      }
515
  if (best)
516
    {
517
      *bestp = best->next;
518
      best->next = n->routes;
519
      n->routes = best;
520
    }
521
  if (best != old_best)
522
    {
523
      DBG("krt_learn_async: distributing change\n");
524
      if (best)
525
        {
526
          krt_learn_announce_update(p, best);
527
          n->n.flags |= KRF_INSTALLED;
528
        }
529
      else
530
        {
531
          n->routes = NULL;
532
          krt_learn_announce_delete(p, n);
533
          n->n.flags &= ~KRF_INSTALLED;
534
        }
535
    }
536
}
537

    
538
static void
539
krt_learn_init(struct krt_proto *p)
540
{
541
  if (KRT_CF->learn)
542
    rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL);
543
}
544

    
545
static void
546
krt_dump(struct proto *P)
547
{
548
  struct krt_proto *p = (struct krt_proto *) P;
549

    
550
  if (!KRT_CF->learn)
551
    return;
552
  debug("KRT: Table of inheritable routes\n");
553
  rt_dump(&p->krt_table);
554
}
555

    
556
static void
557
krt_dump_attrs(rte *e)
558
{
559
  debug(" [m=%d,p=%d,t=%d]", e->u.krt.metric, e->u.krt.proto, e->u.krt.type);
560
}
561

    
562
#endif
563

    
564
/*
565
 *        Routes
566
 */
567

    
568
#ifdef CONFIG_ALL_TABLES_AT_ONCE
569
static timer *krt_scan_timer;
570
static int krt_instance_count;
571
static list krt_instance_list;
572
#endif
573

    
574
static void
575
krt_flush_routes(struct krt_proto *p)
576
{
577
  struct rtable *t = p->p.table;
578

    
579
  KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
580
  FIB_WALK(&t->fib, f)
581
    {
582
      net *n = (net *) f;
583
      rte *e = n->routes;
584
      if (rte_is_valid(e) && (n->n.flags & KRF_INSTALLED))
585
        {
586
          /* FIXME: this does not work if gw is changed in export filter */
587
          krt_replace_rte(p, e->net, NULL, e, NULL);
588
          n->n.flags &= ~KRF_INSTALLED;
589
        }
590
    }
591
  FIB_WALK_END;
592
}
593

    
594
static int
595
krt_same_dest(rte *k, rte *e)
596
{
597
  rta *ka = k->attrs, *ea = e->attrs;
598

    
599
  if (ka->dest != ea->dest)
600
    return 0;
601
  switch (ka->dest)
602
    {
603
    case RTD_ROUTER:
604
      return ipa_equal(ka->gw, ea->gw);
605
    case RTD_DEVICE:
606
      return !strcmp(ka->iface->name, ea->iface->name);
607
    case RTD_MULTIPATH:
608
      return mpnh_same(ka->nexthops, ea->nexthops);
609
    default:
610
      return 1;
611
    }
612
}
613

    
614
/*
615
 *  This gets called back when the low-level scanning code discovers a route.
616
 *  We expect that the route is a temporary rte and its attributes are uncached.
617
 */
618

    
619
void
620
krt_got_route(struct krt_proto *p, rte *e)
621
{
622
  rte *old;
623
  net *net = e->net;
624
  int verdict;
625

    
626
#ifdef KRT_ALLOW_LEARN
627
  switch (e->u.krt.src)
628
    {
629
    case KRT_SRC_KERNEL:
630
      verdict = KRF_IGNORE;
631
      goto sentenced;
632

    
633
    case KRT_SRC_REDIRECT:
634
      verdict = KRF_DELETE;
635
      goto sentenced;
636

    
637
    case  KRT_SRC_ALIEN:
638
      if (KRT_CF->learn)
639
        krt_learn_scan(p, e);
640
      else
641
        {
642
          krt_trace_in_rl(&rl_alien_ignored, p, e, "[alien] ignored");
643
          rte_free(e);
644
        }
645
      return;
646
    }
647
#endif
648
  /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
649

    
650
  if (net->n.flags & KRF_VERDICT_MASK)
651
    {
652
      /* Route to this destination was already seen. Strange, but it happens... */
653
      krt_trace_in(p, e, "already seen");
654
      rte_free(e);
655
      return;
656
    }
657

    
658
  old = net->routes;
659
  if ((net->n.flags & KRF_INSTALLED) && rte_is_valid(old))
660
    {
661
      /* There may be changes in route attributes, we ignore that.
662
         Also, this does not work well if gw is changed in export filter */
663
      if ((net->n.flags & KRF_SYNC_ERROR) || ! krt_same_dest(e, old))
664
        verdict = KRF_UPDATE;
665
      else
666
        verdict = KRF_SEEN;
667
    }
668
  else
669
    verdict = KRF_DELETE;
670

    
671
 sentenced:
672
  krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]);
673
  net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
674
  if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
675
    {
676
      /* Get a cached copy of attributes and temporarily link the route */
677
      rta *a = e->attrs;
678
      a->source = RTS_DUMMY;
679
      e->attrs = rta_lookup(a);
680
      e->next = net->routes;
681
      net->routes = e;
682
    }
683
  else
684
    rte_free(e);
685
}
686

    
687
static inline int
688
krt_export_rte(struct krt_proto *p, rte **new, ea_list **tmpa)
689
{
690
  struct filter *filter = p->p.main_ahook->out_filter;
691

    
692
  if (! *new)
693
    return 0;
694

    
695
  if (filter == FILTER_REJECT)
696
    return 0;
697

    
698
  if (filter == FILTER_ACCEPT)
699
    return 1;
700

    
701
  struct proto *src = (*new)->attrs->proto;
702
  *tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(*new, krt_filter_lp) : NULL;
703
  return f_run(filter, new, tmpa, krt_filter_lp, FF_FORCE_TMPATTR) <= F_ACCEPT;
704
}
705

    
706
static void
707
krt_prune(struct krt_proto *p)
708
{
709
  struct rtable *t = p->p.table;
710

    
711
  KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
712
  FIB_WALK(&t->fib, f)
713
    {
714
      net *n = (net *) f;
715
      int verdict = f->flags & KRF_VERDICT_MASK;
716
      rte *new, *new0, *old;
717
      ea_list *tmpa = NULL;
718

    
719
      if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
720
        {
721
          /* Get a dummy route from krt_got_route() */
722
          old = n->routes;
723
          n->routes = old->next;
724
        }
725
      else
726
        old = NULL;
727

    
728
      new = new0 = n->routes;
729
      if (verdict == KRF_CREATE || verdict == KRF_UPDATE)
730
        {
731
          /* We have to run export filter to get proper 'new' route */
732
          if (! krt_export_rte(p, &new, &tmpa))
733
            {
734
              /* Route rejected, should not happen (KRF_INSTALLED) but to be sure .. */
735
              verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE; 
736
            }
737
        }
738

    
739
      switch (verdict)
740
        {
741
        case KRF_CREATE:
742
          if (new && (f->flags & KRF_INSTALLED))
743
            {
744
              krt_trace_in(p, new, "reinstalling");
745
              krt_replace_rte(p, n, new, NULL, tmpa);
746
            }
747
          break;
748
        case KRF_SEEN:
749
        case KRF_IGNORE:
750
          /* Nothing happens */
751
          break;
752
        case KRF_UPDATE:
753
          krt_trace_in(p, new, "updating");
754
          krt_replace_rte(p, n, new, old, tmpa);
755
          break;
756
        case KRF_DELETE:
757
          krt_trace_in(p, old, "deleting");
758
          krt_replace_rte(p, n, NULL, old, NULL);
759
          break;
760
        default:
761
          bug("krt_prune: invalid route status");
762
        }
763

    
764
      if (old)
765
        rte_free(old);
766
      if (new != new0)
767
        rte_free(new);
768
      lp_flush(krt_filter_lp);
769
      f->flags &= ~KRF_VERDICT_MASK;
770
    }
771
  FIB_WALK_END;
772

    
773
#ifdef KRT_ALLOW_LEARN
774
  if (KRT_CF->learn)
775
    krt_learn_prune(p);
776
#endif
777
  p->initialized = 1;
778
}
779

    
780
void
781
krt_got_route_async(struct krt_proto *p, rte *e, int new)
782
{
783
  net *net = e->net;
784

    
785
  switch (e->u.krt.src)
786
    {
787
    case KRT_SRC_BIRD:
788
      ASSERT(0);                        /* Should be filtered by the back end */
789

    
790
    case KRT_SRC_REDIRECT:
791
      if (new)
792
        {
793
          krt_trace_in(p, e, "[redirect] deleting");
794
          krt_replace_rte(p, net, NULL, e, NULL);
795
        }
796
      /* If !new, it is probably echo of our deletion */
797
      break;
798

    
799
#ifdef KRT_ALLOW_LEARN
800
    case KRT_SRC_ALIEN:
801
      if (KRT_CF->learn)
802
        {
803
          krt_learn_async(p, e, new);
804
          return;
805
        }
806
#endif
807
    }
808
  rte_free(e);
809
}
810

    
811
/*
812
 *        Periodic scanning
813
 */
814

    
815
static void
816
krt_scan(timer *t UNUSED)
817
{
818
  struct krt_proto *p;
819

    
820
  kif_force_scan();
821
#ifdef CONFIG_ALL_TABLES_AT_ONCE
822
  {
823
    void *q;
824
    /* We need some node to decide whether to print the debug messages or not */
825
    p = SKIP_BACK(struct krt_proto, instance_node, HEAD(krt_instance_list));
826
    if (p->instance_node.next)
827
      KRT_TRACE(p, D_EVENTS, "Scanning routing table");
828
    krt_do_scan(NULL);
829
    WALK_LIST(q, krt_instance_list)
830
      {
831
        p = SKIP_BACK(struct krt_proto, instance_node, q);
832
        krt_prune(p);
833
      }
834
  }
835
#else
836
  p = t->data;
837
  KRT_TRACE(p, D_EVENTS, "Scanning routing table");
838
  krt_do_scan(p);
839
  krt_prune(p);
840
#endif
841
}
842

    
843

    
844
/*
845
 *        Updates
846
 */
847

    
848
static struct ea_list *
849
krt_make_tmp_attrs(rte *rt, struct linpool *pool)
850
{
851
  struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr));
852

    
853
  l->next = NULL;
854
  l->flags = EALF_SORTED;
855
  l->count = 2;
856

    
857
  l->attrs[0].id = EA_KRT_SOURCE;
858
  l->attrs[0].flags = 0;
859
  l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
860
  l->attrs[0].u.data = rt->u.krt.proto;
861

    
862
  l->attrs[1].id = EA_KRT_METRIC;
863
  l->attrs[1].flags = 0;
864
  l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
865
  l->attrs[1].u.data = rt->u.krt.metric;
866

    
867
  return l;
868
}
869

    
870
static void
871
krt_store_tmp_attrs(rte *rt, struct ea_list *attrs)
872
{
873
  /* EA_KRT_SOURCE is read-only */
874
  rt->u.krt.metric = ea_get_int(attrs, EA_KRT_METRIC, 0);
875
}
876

    
877
static int
878
krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
879
{
880
  struct krt_proto *p = (struct krt_proto *) P;
881
  rte *e = *new;
882

    
883
  if (e->attrs->proto == P)
884
    return -1;
885

    
886
  if (!KRT_CF->devroutes && 
887
      (e->attrs->dest == RTD_DEVICE) && 
888
      (e->attrs->source != RTS_STATIC_DEVICE))
889
    return -1;
890

    
891
  if (!krt_capable(e))
892
    return -1;
893

    
894
  return 0;
895
}
896

    
897
static void
898
krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
899
           rte *new, rte *old, struct ea_list *eattrs)
900
{
901
  struct krt_proto *p = (struct krt_proto *) P;
902

    
903
  if (shutting_down)
904
    return;
905
  if (!(net->n.flags & KRF_INSTALLED))
906
    old = NULL;
907
  if (new)
908
    net->n.flags |= KRF_INSTALLED;
909
  else
910
    net->n.flags &= ~KRF_INSTALLED;
911
  if (p->initialized)                /* Before first scan we don't touch the routes */
912
    krt_replace_rte(p, net, new, old, eattrs);
913
}
914

    
915
static int
916
krt_rte_same(rte *a, rte *b)
917
{
918
  /* src is always KRT_SRC_ALIEN and type is irrelevant */
919
  return (a->u.krt.proto == b->u.krt.proto) && (a->u.krt.metric == b->u.krt.metric);
920
}
921

    
922

    
923
/*
924
 *        Protocol glue
925
 */
926

    
927
struct krt_config *krt_cf;
928

    
929
static struct proto *
930
krt_init(struct proto_config *c)
931
{
932
  struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
933

    
934
  p->p.accept_ra_types = RA_OPTIMAL;
935
  p->p.make_tmp_attrs = krt_make_tmp_attrs;
936
  p->p.store_tmp_attrs = krt_store_tmp_attrs;
937
  p->p.import_control = krt_import_control;
938
  p->p.rt_notify = krt_notify;
939
  p->p.rte_same = krt_rte_same;
940

    
941
  krt_sys_init(p);
942
  return &p->p;
943
}
944

    
945
static timer *
946
krt_start_timer(struct krt_proto *p)
947
{
948
  timer *t;
949

    
950
  t = tm_new(p->krt_pool);
951
  t->hook = krt_scan;
952
  t->data = p;
953
  t->recurrent = KRT_CF->scan_time;
954
  tm_start(t, 0);
955
  return t;
956
}
957

    
958
static int
959
krt_start(struct proto *P)
960
{
961
  struct krt_proto *p = (struct krt_proto *) P;
962
  int first = 1;
963

    
964
#ifdef CONFIG_ALL_TABLES_AT_ONCE
965
  if (!krt_instance_count++)
966
    init_list(&krt_instance_list);
967
  else
968
    first = 0;
969
  p->krt_pool = krt_pool;
970
  add_tail(&krt_instance_list, &p->instance_node);
971
#else
972
  p->krt_pool = P->pool;
973
#endif
974

    
975
#ifdef KRT_ALLOW_LEARN
976
  krt_learn_init(p);
977
#endif
978

    
979
  krt_sys_start(p, first);
980

    
981
  /* Start periodic routing table scanning */
982
#ifdef CONFIG_ALL_TABLES_AT_ONCE
983
  if (first)
984
    krt_scan_timer = krt_start_timer(p);
985
  else
986
    tm_start(krt_scan_timer, 0);
987
  p->scan_timer = krt_scan_timer;
988
#else
989
  p->scan_timer = krt_start_timer(p);
990
#endif
991

    
992
  return PS_UP;
993
}
994

    
995
static int
996
krt_shutdown(struct proto *P)
997
{
998
  struct krt_proto *p = (struct krt_proto *) P;
999
  int last = 1;
1000

    
1001
#ifdef CONFIG_ALL_TABLES_AT_ONCE
1002
  rem_node(&p->instance_node);
1003
  if (--krt_instance_count)
1004
    last = 0;
1005
  else
1006
#endif
1007
    tm_stop(p->scan_timer);
1008

    
1009
  /* FIXME we should flush routes even when persist during reconfiguration */
1010
  if (p->initialized && !KRT_CF->persist)
1011
    krt_flush_routes(p);
1012

    
1013
  krt_sys_shutdown(p, last);
1014

    
1015
#ifdef CONFIG_ALL_TABLES_AT_ONCE
1016
  if (last)
1017
    rfree(krt_scan_timer);
1018
#endif
1019

    
1020
  return PS_DOWN;
1021
}
1022

    
1023
static int
1024
krt_reconfigure(struct proto *p, struct proto_config *new)
1025
{
1026
  struct krt_config *o = (struct krt_config *) p->cf;
1027
  struct krt_config *n = (struct krt_config *) new;
1028

    
1029
  if (!krt_sys_reconfigure((struct krt_proto *) p, n, o))
1030
    return 0;
1031

    
1032
  /* persist needn't be the same */
1033
  return o->scan_time == n->scan_time && o->learn == n->learn && o->devroutes == n->devroutes;
1034
}
1035

    
1036
static void
1037
krt_preconfig(struct protocol *P UNUSED, struct config *c)
1038
{
1039
  krt_cf = NULL;
1040
  krt_sys_preconfig(c);
1041
}
1042

    
1043
static void
1044
krt_postconfig(struct proto_config *C)
1045
{
1046
  struct krt_config *c = (struct krt_config *) C;
1047

    
1048
#ifdef CONFIG_ALL_TABLES_AT_ONCE
1049
  if (krt_cf->scan_time != c->scan_time)
1050
    cf_error("All kernel syncers must use the same table scan interval");
1051
#endif
1052

    
1053
  if (C->table->krt_attached)
1054
    cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name);
1055
  C->table->krt_attached = C;
1056
  krt_sys_postconfig(c);
1057
}
1058

    
1059
struct proto_config *
1060
krt_init_config(int class)
1061
{
1062
#ifndef CONFIG_MULTIPLE_TABLES
1063
  if (krt_cf)
1064
    cf_error("Kernel protocol already defined");
1065
#endif
1066

    
1067
  krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, sizeof(struct krt_config), class);
1068
  krt_cf->scan_time = 60;
1069

    
1070
  krt_sys_init_config(krt_cf);
1071
  return (struct proto_config *) krt_cf;
1072
}
1073

    
1074
static void
1075
krt_copy_config(struct proto_config *dest, struct proto_config *src)
1076
{
1077
  struct krt_config *d = (struct krt_config *) dest;
1078
  struct krt_config *s = (struct krt_config *) src;
1079

    
1080
  /* Shallow copy of everything */
1081
  proto_copy_rest(dest, src, sizeof(struct krt_config));
1082

    
1083
  /* Fix sysdep parts */
1084
  krt_sys_copy_config(d, s);
1085
}
1086

    
1087
static int
1088
krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
1089
{
1090
  switch (a->id)
1091
  {
1092
  case EA_KRT_SOURCE:
1093
    bsprintf(buf, "source");
1094
    return GA_NAME;
1095

    
1096
  case EA_KRT_METRIC:
1097
    bsprintf(buf, "metric");
1098
    return GA_NAME;
1099

    
1100
  case EA_KRT_PREFSRC:
1101
    bsprintf(buf, "prefsrc");
1102
    return GA_NAME;
1103

    
1104
  case EA_KRT_REALM:
1105
    bsprintf(buf, "realm");
1106
    return GA_NAME;
1107

    
1108
  default:
1109
    return GA_UNKNOWN;
1110
  }
1111
}
1112

    
1113

    
1114
struct protocol proto_unix_kernel = {
1115
  name:                "Kernel",
1116
  template:        "kernel%d",
1117
  attr_class:        EAP_KRT,
1118
  preference:        DEF_PREF_INHERITED,
1119
  preconfig:        krt_preconfig,
1120
  postconfig:        krt_postconfig,
1121
  init:                krt_init,
1122
  start:        krt_start,
1123
  shutdown:        krt_shutdown,
1124
  reconfigure:        krt_reconfigure,
1125
  copy_config:        krt_copy_config,
1126
  get_attr:        krt_get_attr,
1127
#ifdef KRT_ALLOW_LEARN
1128
  dump:                krt_dump,
1129
  dump_attrs:        krt_dump_attrs,
1130
#endif
1131
};