Statistics
| Branch: | Revision:

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

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_scope(struct ifa *a, struct ifa *b)
118
{ return (a->scope > SCOPE_LINK) && (b->scope <= SCOPE_LINK); }
119

    
120
static inline int
121
prefer_addr(struct ifa *a, struct ifa *b)
122
{ return ipa_compare(a->ip, b->ip) < 0; }
123

    
124
static inline struct ifa *
125
find_preferred_ifa(struct iface *i, ip_addr prefix, ip_addr mask)
126
{
127
  struct ifa *a, *b = NULL;
128

    
129
  WALK_LIST(a, i->addrs)
130
    {
131
      if (!(a->flags & IA_SECONDARY) &&
132
          ipa_equal(ipa_and(a->ip, mask), prefix) &&
133
          (!b || prefer_scope(a, b) || prefer_addr(a, b)))
134
        b = a;
135
    }
136

    
137
  return b;
138
}
139

    
140
struct ifa *
141
kif_choose_primary(struct iface *i)
142
{
143
  struct kif_config *cf = (struct kif_config *) (kif_proto->p.cf);
144
  struct kif_primary_item *it;
145
  struct ifa *a;
146

    
147
  WALK_LIST(it, cf->primary)
148
    {
149
      if (!it->pattern || patmatch(it->pattern, i->name))
150
        if (a = find_preferred_ifa(i, it->prefix, ipa_mkmask(it->pxlen)))
151
          return a;
152
    }
153

    
154
  return find_preferred_ifa(i, IPA_NONE, IPA_NONE);
155
}
156

    
157

    
158
static struct proto *
159
kif_init(struct proto_config *c)
160
{
161
  struct kif_proto *p = proto_new(c, sizeof(struct kif_proto));
162

    
163
  kif_sys_init(p);
164
  return &p->p;
165
}
166

    
167
static int
168
kif_start(struct proto *P)
169
{
170
  struct kif_proto *p = (struct kif_proto *) P;
171

    
172
  kif_proto = p;
173
  kif_sys_start(p);
174

    
175
  /* Start periodic interface scanning */
176
  kif_scan_timer = tm_new(P->pool);
177
  kif_scan_timer->hook = kif_scan;
178
  kif_scan_timer->data = p;
179
  kif_scan_timer->recurrent = KIF_CF->scan_time;
180
  kif_scan(kif_scan_timer);
181
  tm_start(kif_scan_timer, KIF_CF->scan_time);
182

    
183
  return PS_UP;
184
}
185

    
186
static int
187
kif_shutdown(struct proto *P)
188
{
189
  struct kif_proto *p = (struct kif_proto *) P;
190

    
191
  tm_stop(kif_scan_timer);
192
  kif_sys_shutdown(p);
193
  kif_proto = NULL;
194

    
195
  return PS_DOWN;
196
}
197

    
198
static int
199
kif_reconfigure(struct proto *p, struct proto_config *new)
200
{
201
  struct kif_config *o = (struct kif_config *) p->cf;
202
  struct kif_config *n = (struct kif_config *) new;
203

    
204
  if (!kif_sys_reconfigure((struct kif_proto *) p, n, o))
205
    return 0;
206

    
207
  if (o->scan_time != n->scan_time)
208
    {
209
      tm_stop(kif_scan_timer);
210
      kif_scan_timer->recurrent = n->scan_time;
211
      kif_scan(kif_scan_timer);
212
      tm_start(kif_scan_timer, n->scan_time);
213
    }
214

    
215
  if (!EMPTY_LIST(o->primary) || !EMPTY_LIST(n->primary))
216
    {
217
      /* This is hack, we have to update a configuration
218
       * to the new value just now, because it is used
219
       * for recalculation of primary addresses.
220
       */
221
      p->cf = new;
222

    
223
      ifa_recalc_all_primary_addresses();
224
    }
225

    
226
  return 1;
227
}
228

    
229

    
230
static void
231
kif_preconfig(struct protocol *P UNUSED, struct config *c)
232
{
233
  kif_cf = NULL;
234
  kif_sys_preconfig(c);
235
}
236

    
237
struct proto_config *
238
kif_init_config(int class)
239
{
240
  if (kif_cf)
241
    cf_error("Kernel device protocol already defined");
242

    
243
  kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, sizeof(struct kif_config), class);
244
  kif_cf->scan_time = 60;
245
  init_list(&kif_cf->primary);
246

    
247
  kif_sys_init_config(kif_cf);
248
  return (struct proto_config *) kif_cf;
249
}
250

    
251
static void
252
kif_copy_config(struct proto_config *dest, struct proto_config *src)
253
{
254
  struct kif_config *d = (struct kif_config *) dest;
255
  struct kif_config *s = (struct kif_config *) src;
256

    
257
  /* Shallow copy of everything (just scan_time currently) */
258
  proto_copy_rest(dest, src, sizeof(struct kif_config));
259

    
260
  /* Copy primary addr list */
261
  cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item));
262

    
263
  /* Fix sysdep parts */
264
  kif_sys_copy_config(d, s);
265
}
266

    
267

    
268
struct protocol proto_unix_iface = {
269
  name:                "Device",
270
  template:        "device%d",
271
  preference:        DEF_PREF_DIRECT,
272
  preconfig:        kif_preconfig,
273
  init:                kif_init,
274
  start:        kif_start,
275
  shutdown:        kif_shutdown,
276
  reconfigure:        kif_reconfigure,
277
  copy_config:        kif_copy_config
278
};
279

    
280
/*
281
 *        Tracing of routes
282
 */
283

    
284
static inline void
285
krt_trace_in(struct krt_proto *p, rte *e, char *msg)
286
{
287
  if (p->p.debug & D_PACKETS)
288
    log(L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg);
289
}
290

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

    
298
/*
299
 *        Inherited Routes
300
 */
301

    
302
#ifdef KRT_ALLOW_LEARN
303

    
304
static struct rate_limit rl_alien_seen, rl_alien_updated, rl_alien_created, rl_alien_ignored;
305

    
306
/*
307
 * krt_same_key() specifies what (aside from the net) is the key in
308
 * kernel routing tables. It should be OS-dependent, this is for
309
 * Linux. It is important for asynchronous alien updates, because a
310
 * positive update is implicitly a negative one for any old route with
311
 * the same key.
312
 */
313

    
314
static inline int
315
krt_same_key(rte *a, rte *b)
316
{
317
  return a->u.krt.metric == b->u.krt.metric;
318
}
319

    
320
static inline int
321
krt_uptodate(rte *a, rte *b)
322
{
323
  if (a->attrs != b->attrs)
324
    return 0;
325

    
326
  if (a->u.krt.proto != b->u.krt.proto)
327
    return 0;
328

    
329
  return 1;
330
}
331

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

    
346
static void
347
krt_learn_announce_delete(struct krt_proto *p, net *n)
348
{
349
  n = net_find(p->p.table, n->n.prefix, n->n.pxlen);
350
  if (n)
351
    rte_update(p->p.table, n, &p->p, &p->p, NULL);
352
}
353

    
354
/* Called when alien route is discovered during scan */
355
static void
356
krt_learn_scan(struct krt_proto *p, rte *e)
357
{
358
  net *n0 = e->net;
359
  net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
360
  rte *m, **mm;
361

    
362
  e->attrs = rta_lookup(e->attrs);
363

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

    
393
static void
394
krt_learn_prune(struct krt_proto *p)
395
{
396
  struct fib *fib = &p->krt_table.fib;
397
  struct fib_iterator fit;
398

    
399
  KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
400

    
401
  FIB_ITERATE_INIT(&fit, fib);
402
again:
403
  FIB_ITERATE_START(fib, &fit, f)
404
    {
405
      net *n = (net *) f;
406
      rte *e, **ee, *best, **pbest, *old_best;
407

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

    
455
static void
456
krt_learn_async(struct krt_proto *p, rte *e, int new)
457
{
458
  net *n0 = e->net;
459
  net *n = net_get(&p->krt_table, n0->n.prefix, n0->n.pxlen);
460
  rte *g, **gg, *best, **bestp, *old_best;
461

    
462
  e->attrs = rta_lookup(e->attrs);
463

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

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

    
532
static void
533
krt_learn_init(struct krt_proto *p)
534
{
535
  if (KRT_CF->learn)
536
    rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL);
537
}
538

    
539
static void
540
krt_dump(struct proto *P)
541
{
542
  struct krt_proto *p = (struct krt_proto *) P;
543

    
544
  if (!KRT_CF->learn)
545
    return;
546
  debug("KRT: Table of inheritable routes\n");
547
  rt_dump(&p->krt_table);
548
}
549

    
550
static void
551
krt_dump_attrs(rte *e)
552
{
553
  debug(" [m=%d,p=%d,t=%d]", e->u.krt.metric, e->u.krt.proto, e->u.krt.type);
554
}
555

    
556
#endif
557

    
558
/*
559
 *        Routes
560
 */
561

    
562
#ifdef CONFIG_ALL_TABLES_AT_ONCE
563
static timer *krt_scan_timer;
564
static int krt_instance_count;
565
static list krt_instance_list;
566
#endif
567

    
568
static void
569
krt_flush_routes(struct krt_proto *p)
570
{
571
  struct rtable *t = p->p.table;
572

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

    
588
static int
589
krt_same_dest(rte *k, rte *e)
590
{
591
  rta *ka = k->attrs, *ea = e->attrs;
592

    
593
  if (ka->dest != ea->dest)
594
    return 0;
595
  switch (ka->dest)
596
    {
597
    case RTD_ROUTER:
598
      return ipa_equal(ka->gw, ea->gw);
599
    case RTD_DEVICE:
600
      return !strcmp(ka->iface->name, ea->iface->name);
601
    case RTD_MULTIPATH:
602
      return mpnh_same(ka->nexthops, ea->nexthops);
603
    default:
604
      return 1;
605
    }
606
}
607

    
608
/*
609
 *  This gets called back when the low-level scanning code discovers a route.
610
 *  We expect that the route is a temporary rte and its attributes are uncached.
611
 */
612

    
613
void
614
krt_got_route(struct krt_proto *p, rte *e)
615
{
616
  rte *old;
617
  net *net = e->net;
618
  int verdict;
619

    
620
#ifdef KRT_ALLOW_LEARN
621
  switch (e->u.krt.src)
622
    {
623
    case KRT_SRC_KERNEL:
624
      verdict = KRF_IGNORE;
625
      goto sentenced;
626

    
627
    case KRT_SRC_REDIRECT:
628
      verdict = KRF_DELETE;
629
      goto sentenced;
630

    
631
    case  KRT_SRC_ALIEN:
632
      if (KRT_CF->learn)
633
        krt_learn_scan(p, e);
634
      else
635
        {
636
          krt_trace_in_rl(&rl_alien_ignored, p, e, "[alien] ignored");
637
          rte_free(e);
638
        }
639
      return;
640
    }
641
#endif
642
  /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
643

    
644
  if (net->n.flags & KRF_VERDICT_MASK)
645
    {
646
      /* Route to this destination was already seen. Strange, but it happens... */
647
      krt_trace_in(p, e, "already seen");
648
      rte_free(e);
649
      return;
650
    }
651

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

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

    
681
static inline int
682
krt_export_rte(struct krt_proto *p, rte **new, ea_list **tmpa)
683
{
684
  struct filter *filter = p->p.main_ahook->out_filter;
685

    
686
  if (! *new)
687
    return 0;
688

    
689
  if (filter == FILTER_REJECT)
690
    return 0;
691

    
692
  if (filter == FILTER_ACCEPT)
693
    return 1;
694

    
695
  struct proto *src = (*new)->attrs->proto;
696
  *tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(*new, krt_filter_lp) : NULL;
697
  return f_run(filter, new, tmpa, krt_filter_lp, FF_FORCE_TMPATTR) <= F_ACCEPT;
698
}
699

    
700
static void
701
krt_prune(struct krt_proto *p)
702
{
703
  struct rtable *t = p->p.table;
704

    
705
  KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
706
  FIB_WALK(&t->fib, f)
707
    {
708
      net *n = (net *) f;
709
      int verdict = f->flags & KRF_VERDICT_MASK;
710
      rte *new, *new0, *old;
711
      ea_list *tmpa = NULL;
712

    
713
      if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
714
        {
715
          /* Get a dummy route from krt_got_route() */
716
          old = n->routes;
717
          n->routes = old->next;
718
        }
719
      else
720
        old = NULL;
721

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

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

    
758
      if (old)
759
        rte_free(old);
760
      if (new != new0)
761
        rte_free(new);
762
      lp_flush(krt_filter_lp);
763
      f->flags &= ~KRF_VERDICT_MASK;
764
    }
765
  FIB_WALK_END;
766

    
767
#ifdef KRT_ALLOW_LEARN
768
  if (KRT_CF->learn)
769
    krt_learn_prune(p);
770
#endif
771
  p->initialized = 1;
772
}
773

    
774
void
775
krt_got_route_async(struct krt_proto *p, rte *e, int new)
776
{
777
  net *net = e->net;
778

    
779
  switch (e->u.krt.src)
780
    {
781
    case KRT_SRC_BIRD:
782
      ASSERT(0);                        /* Should be filtered by the back end */
783

    
784
    case KRT_SRC_REDIRECT:
785
      if (new)
786
        {
787
          krt_trace_in(p, e, "[redirect] deleting");
788
          krt_replace_rte(p, net, NULL, e, NULL);
789
        }
790
      /* If !new, it is probably echo of our deletion */
791
      break;
792

    
793
#ifdef KRT_ALLOW_LEARN
794
    case KRT_SRC_ALIEN:
795
      if (KRT_CF->learn)
796
        {
797
          krt_learn_async(p, e, new);
798
          return;
799
        }
800
#endif
801
    }
802
  rte_free(e);
803
}
804

    
805
/*
806
 *        Periodic scanning
807
 */
808

    
809
static void
810
krt_scan(timer *t UNUSED)
811
{
812
  struct krt_proto *p;
813

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

    
837

    
838
/*
839
 *        Updates
840
 */
841

    
842
static struct ea_list *
843
krt_make_tmp_attrs(rte *rt, struct linpool *pool)
844
{
845
  struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr));
846

    
847
  l->next = NULL;
848
  l->flags = EALF_SORTED;
849
  l->count = 2;
850

    
851
  l->attrs[0].id = EA_KRT_SOURCE;
852
  l->attrs[0].flags = 0;
853
  l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
854
  l->attrs[0].u.data = rt->u.krt.proto;
855

    
856
  l->attrs[1].id = EA_KRT_METRIC;
857
  l->attrs[1].flags = 0;
858
  l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
859
  l->attrs[1].u.data = rt->u.krt.metric;
860

    
861
  return l;
862
}
863

    
864
static void
865
krt_store_tmp_attrs(rte *rt, struct ea_list *attrs)
866
{
867
  /* EA_KRT_SOURCE is read-only */
868
  rt->u.krt.metric = ea_get_int(attrs, EA_KRT_METRIC, 0);
869
}
870

    
871
static int
872
krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
873
{
874
  struct krt_proto *p = (struct krt_proto *) P;
875
  rte *e = *new;
876

    
877
  if (e->attrs->proto == P)
878
    return -1;
879

    
880
  if (!KRT_CF->devroutes && 
881
      (e->attrs->dest == RTD_DEVICE) && 
882
      (e->attrs->source != RTS_STATIC_DEVICE))
883
    return -1;
884

    
885
  if (!krt_capable(e))
886
    return -1;
887

    
888
  return 0;
889
}
890

    
891
static void
892
krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
893
           rte *new, rte *old, struct ea_list *eattrs)
894
{
895
  struct krt_proto *p = (struct krt_proto *) P;
896

    
897
  if (shutting_down)
898
    return;
899
  if (!(net->n.flags & KRF_INSTALLED))
900
    old = NULL;
901
  if (new)
902
    net->n.flags |= KRF_INSTALLED;
903
  else
904
    net->n.flags &= ~KRF_INSTALLED;
905
  if (p->initialized)                /* Before first scan we don't touch the routes */
906
    krt_replace_rte(p, net, new, old, eattrs);
907
}
908

    
909
static int
910
krt_rte_same(rte *a, rte *b)
911
{
912
  /* src is always KRT_SRC_ALIEN and type is irrelevant */
913
  return (a->u.krt.proto == b->u.krt.proto) && (a->u.krt.metric == b->u.krt.metric);
914
}
915

    
916

    
917
/*
918
 *        Protocol glue
919
 */
920

    
921
struct krt_config *krt_cf;
922

    
923
static struct proto *
924
krt_init(struct proto_config *c)
925
{
926
  struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
927

    
928
  p->p.accept_ra_types = RA_OPTIMAL;
929
  p->p.make_tmp_attrs = krt_make_tmp_attrs;
930
  p->p.store_tmp_attrs = krt_store_tmp_attrs;
931
  p->p.import_control = krt_import_control;
932
  p->p.rt_notify = krt_notify;
933
  p->p.rte_same = krt_rte_same;
934

    
935
  krt_sys_init(p);
936
  return &p->p;
937
}
938

    
939
static timer *
940
krt_start_timer(struct krt_proto *p)
941
{
942
  timer *t;
943

    
944
  t = tm_new(p->krt_pool);
945
  t->hook = krt_scan;
946
  t->data = p;
947
  t->recurrent = KRT_CF->scan_time;
948
  tm_start(t, 0);
949
  return t;
950
}
951

    
952
static int
953
krt_start(struct proto *P)
954
{
955
  struct krt_proto *p = (struct krt_proto *) P;
956
  int first = 1;
957

    
958
#ifdef CONFIG_ALL_TABLES_AT_ONCE
959
  if (!krt_instance_count++)
960
    init_list(&krt_instance_list);
961
  else
962
    first = 0;
963
  p->krt_pool = krt_pool;
964
  add_tail(&krt_instance_list, &p->instance_node);
965
#else
966
  p->krt_pool = P->pool;
967
#endif
968

    
969
#ifdef KRT_ALLOW_LEARN
970
  krt_learn_init(p);
971
#endif
972

    
973
  krt_sys_start(p, first);
974

    
975
  /* Start periodic routing table scanning */
976
#ifdef CONFIG_ALL_TABLES_AT_ONCE
977
  if (first)
978
    krt_scan_timer = krt_start_timer(p);
979
  else
980
    tm_start(krt_scan_timer, 0);
981
  p->scan_timer = krt_scan_timer;
982
#else
983
  p->scan_timer = krt_start_timer(p);
984
#endif
985

    
986
  return PS_UP;
987
}
988

    
989
static int
990
krt_shutdown(struct proto *P)
991
{
992
  struct krt_proto *p = (struct krt_proto *) P;
993
  int last = 1;
994

    
995
#ifdef CONFIG_ALL_TABLES_AT_ONCE
996
  rem_node(&p->instance_node);
997
  if (--krt_instance_count)
998
    last = 0;
999
  else
1000
#endif
1001
    tm_stop(p->scan_timer);
1002

    
1003
  /* FIXME we should flush routes even when persist during reconfiguration */
1004
  if (p->initialized && !KRT_CF->persist)
1005
    krt_flush_routes(p);
1006

    
1007
  krt_sys_shutdown(p, last);
1008

    
1009
#ifdef CONFIG_ALL_TABLES_AT_ONCE
1010
  if (last)
1011
    rfree(krt_scan_timer);
1012
#endif
1013

    
1014
  return PS_DOWN;
1015
}
1016

    
1017
static int
1018
krt_reconfigure(struct proto *p, struct proto_config *new)
1019
{
1020
  struct krt_config *o = (struct krt_config *) p->cf;
1021
  struct krt_config *n = (struct krt_config *) new;
1022

    
1023
  if (!krt_sys_reconfigure((struct krt_proto *) p, n, o))
1024
    return 0;
1025

    
1026
  /* persist needn't be the same */
1027
  return o->scan_time == n->scan_time && o->learn == n->learn && o->devroutes == n->devroutes;
1028
}
1029

    
1030
static void
1031
krt_preconfig(struct protocol *P UNUSED, struct config *c)
1032
{
1033
  krt_cf = NULL;
1034
  krt_sys_preconfig(c);
1035
}
1036

    
1037
static void
1038
krt_postconfig(struct proto_config *C)
1039
{
1040
  struct krt_config *c = (struct krt_config *) C;
1041

    
1042
#ifdef CONFIG_ALL_TABLES_AT_ONCE
1043
  if (krt_cf->scan_time != c->scan_time)
1044
    cf_error("All kernel syncers must use the same table scan interval");
1045
#endif
1046

    
1047
  if (C->table->krt_attached)
1048
    cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name);
1049
  C->table->krt_attached = C;
1050
  krt_sys_postconfig(c);
1051
}
1052

    
1053
struct proto_config *
1054
krt_init_config(int class)
1055
{
1056
#ifndef CONFIG_MULTIPLE_TABLES
1057
  if (krt_cf)
1058
    cf_error("Kernel protocol already defined");
1059
#endif
1060

    
1061
  krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, sizeof(struct krt_config), class);
1062
  krt_cf->scan_time = 60;
1063

    
1064
  krt_sys_init_config(krt_cf);
1065
  return (struct proto_config *) krt_cf;
1066
}
1067

    
1068
static void
1069
krt_copy_config(struct proto_config *dest, struct proto_config *src)
1070
{
1071
  struct krt_config *d = (struct krt_config *) dest;
1072
  struct krt_config *s = (struct krt_config *) src;
1073

    
1074
  /* Shallow copy of everything */
1075
  proto_copy_rest(dest, src, sizeof(struct krt_config));
1076

    
1077
  /* Fix sysdep parts */
1078
  krt_sys_copy_config(d, s);
1079
}
1080

    
1081
static int
1082
krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
1083
{
1084
  switch (a->id)
1085
  {
1086
  case EA_KRT_SOURCE:
1087
    bsprintf(buf, "source");
1088
    return GA_NAME;
1089

    
1090
  case EA_KRT_METRIC:
1091
    bsprintf(buf, "metric");
1092
    return GA_NAME;
1093

    
1094
  case EA_KRT_PREFSRC:
1095
    bsprintf(buf, "prefsrc");
1096
    return GA_NAME;
1097

    
1098
  case EA_KRT_REALM:
1099
    bsprintf(buf, "realm");
1100
    return GA_NAME;
1101

    
1102
  default:
1103
    return GA_UNKNOWN;
1104
  }
1105
}
1106

    
1107

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