Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / krt.c @ 4a591d4b

History | View | Annotate | Download (26.1 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
static list krt_proto_list;
73

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

    
82
/*
83
 *        Interfaces
84
 */
85

    
86
static struct kif_config *kif_cf;
87
static struct kif_proto *kif_proto;
88
static timer *kif_scan_timer;
89
static bird_clock_t kif_last_shot;
90

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

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

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

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

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

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

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

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

    
145
  return b;
146
}
147

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

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

    
162
  if (a = kif_get_primary_ip(i))
163
    return a;
164

    
165
  return find_preferred_ifa(i, IPA_NONE, IPA_NONE);
166
}
167

    
168

    
169
static struct proto *
170
kif_init(struct proto_config *c)
171
{
172
  struct kif_proto *p = proto_new(c, sizeof(struct kif_proto));
173

    
174
  kif_sys_init(p);
175
  return &p->p;
176
}
177

    
178
static int
179
kif_start(struct proto *P)
180
{
181
  struct kif_proto *p = (struct kif_proto *) P;
182

    
183
  kif_proto = p;
184
  kif_sys_start(p);
185

    
186
  /* Start periodic interface scanning */
187
  kif_scan_timer = tm_new(P->pool);
188
  kif_scan_timer->hook = kif_scan;
189
  kif_scan_timer->data = p;
190
  kif_scan_timer->recurrent = KIF_CF->scan_time;
191
  kif_scan(kif_scan_timer);
192
  tm_start(kif_scan_timer, KIF_CF->scan_time);
193

    
194
  return PS_UP;
195
}
196

    
197
static int
198
kif_shutdown(struct proto *P)
199
{
200
  struct kif_proto *p = (struct kif_proto *) P;
201

    
202
  tm_stop(kif_scan_timer);
203
  kif_sys_shutdown(p);
204
  kif_proto = NULL;
205

    
206
  return PS_DOWN;
207
}
208

    
209
static int
210
kif_reconfigure(struct proto *p, struct proto_config *new)
211
{
212
  struct kif_config *o = (struct kif_config *) p->cf;
213
  struct kif_config *n = (struct kif_config *) new;
214

    
215
  if (!kif_sys_reconfigure((struct kif_proto *) p, n, o))
216
    return 0;
217

    
218
  if (o->scan_time != n->scan_time)
219
    {
220
      tm_stop(kif_scan_timer);
221
      kif_scan_timer->recurrent = n->scan_time;
222
      kif_scan(kif_scan_timer);
223
      tm_start(kif_scan_timer, n->scan_time);
224
    }
225

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

    
234
      ifa_recalc_all_primary_addresses();
235
    }
236

    
237
  return 1;
238
}
239

    
240

    
241
static void
242
kif_preconfig(struct protocol *P UNUSED, struct config *c)
243
{
244
  kif_cf = NULL;
245
  kif_sys_preconfig(c);
246
}
247

    
248
struct proto_config *
249
kif_init_config(int class)
250
{
251
  if (kif_cf)
252
    cf_error("Kernel device protocol already defined");
253

    
254
  kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, sizeof(struct kif_config), class);
255
  kif_cf->scan_time = 60;
256
  init_list(&kif_cf->primary);
257

    
258
  kif_sys_init_config(kif_cf);
259
  return (struct proto_config *) kif_cf;
260
}
261

    
262
static void
263
kif_copy_config(struct proto_config *dest, struct proto_config *src)
264
{
265
  struct kif_config *d = (struct kif_config *) dest;
266
  struct kif_config *s = (struct kif_config *) src;
267

    
268
  /* Shallow copy of everything (just scan_time currently) */
269
  proto_copy_rest(dest, src, sizeof(struct kif_config));
270

    
271
  /* Copy primary addr list */
272
  cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item));
273

    
274
  /* Fix sysdep parts */
275
  kif_sys_copy_config(d, s);
276
}
277

    
278

    
279
struct protocol proto_unix_iface = {
280
  .name =                 "Device",
281
  .template =                 "device%d",
282
  .preference =                DEF_PREF_DIRECT,
283
  .preconfig =                kif_preconfig,
284
  .init =                kif_init,
285
  .start =                kif_start,
286
  .shutdown =                kif_shutdown,
287
  .reconfigure =        kif_reconfigure,
288
  .copy_config =        kif_copy_config
289
};
290

    
291
/*
292
 *        Tracing of routes
293
 */
294

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

    
302
static inline void
303
krt_trace_in_rl(struct tbf *f, struct krt_proto *p, rte *e, char *msg)
304
{
305
  if (p->p.debug & D_PACKETS)
306
    log_rl(f, L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg);
307
}
308

    
309
/*
310
 *        Inherited Routes
311
 */
312

    
313
#ifdef KRT_ALLOW_LEARN
314

    
315
static struct tbf rl_alien = TBF_DEFAULT_LOG_LIMITS;
316

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

    
325
static inline int
326
krt_same_key(rte *a, rte *b)
327
{
328
  return a->u.krt.metric == b->u.krt.metric;
329
}
330

    
331
static inline int
332
krt_uptodate(rte *a, rte *b)
333
{
334
  if (a->attrs != b->attrs)
335
    return 0;
336

    
337
  if (a->u.krt.proto != b->u.krt.proto)
338
    return 0;
339

    
340
  return 1;
341
}
342

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

    
357
static void
358
krt_learn_announce_delete(struct krt_proto *p, net *n)
359
{
360
  n = net_find(p->p.table, n->n.prefix, n->n.pxlen);
361
  rte_update(&p->p, n, NULL);
362
}
363

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

    
372
  e->attrs = rta_lookup(e->attrs);
373

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

    
403
static void
404
krt_learn_prune(struct krt_proto *p)
405
{
406
  struct fib *fib = &p->krt_table.fib;
407
  struct fib_iterator fit;
408

    
409
  KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
410

    
411
  FIB_ITERATE_INIT(&fit, fib);
412
again:
413
  FIB_ITERATE_START(fib, &fit, f)
414
    {
415
      net *n = (net *) f;
416
      rte *e, **ee, *best, **pbest, *old_best;
417

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

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

    
472
  e->attrs = rta_lookup(e->attrs);
473

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

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

    
542
static void
543
krt_learn_init(struct krt_proto *p)
544
{
545
  if (KRT_CF->learn)
546
    rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL);
547
}
548

    
549
static void
550
krt_dump(struct proto *P)
551
{
552
  struct krt_proto *p = (struct krt_proto *) P;
553

    
554
  if (!KRT_CF->learn)
555
    return;
556
  debug("KRT: Table of inheritable routes\n");
557
  rt_dump(&p->krt_table);
558
}
559

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

    
566
#endif
567

    
568
/*
569
 *        Routes
570
 */
571

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

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

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

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

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

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

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

    
631
    case KRT_SRC_REDIRECT:
632
      verdict = KRF_DELETE;
633
      goto sentenced;
634

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

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

    
656
  if (!p->ready)
657
    {
658
      /* We wait for the initial feed to have correct KRF_INSTALLED flag */
659
      verdict = KRF_IGNORE;
660
      goto sentenced;
661
    }
662

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

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

    
692
static inline int
693
krt_export_rte(struct krt_proto *p, rte **new, ea_list **tmpa)
694
{
695
  struct filter *filter = p->p.main_ahook->out_filter;
696

    
697
  if (! *new)
698
    return 0;
699

    
700
  if (filter == FILTER_REJECT)
701
    return 0;
702

    
703
  if (filter == FILTER_ACCEPT)
704
    return 1;
705

    
706
  struct proto *src = (*new)->attrs->src->proto;
707
  *tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(*new, krt_filter_lp) : NULL;
708
  return f_run(filter, new, tmpa, krt_filter_lp, FF_FORCE_TMPATTR) <= F_ACCEPT;
709
}
710

    
711
static void
712
krt_prune(struct krt_proto *p)
713
{
714
  struct rtable *t = p->p.table;
715

    
716
  KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
717
  FIB_WALK(&t->fib, f)
718
    {
719
      net *n = (net *) f;
720
      int verdict = f->flags & KRF_VERDICT_MASK;
721
      rte *new, *new0, *old;
722
      ea_list *tmpa = NULL;
723

    
724
      if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
725
        {
726
          /* Get a dummy route from krt_got_route() */
727
          old = n->routes;
728
          n->routes = old->next;
729
        }
730
      else
731
        old = NULL;
732

    
733
      new = new0 = n->routes;
734
      if (verdict == KRF_CREATE || verdict == KRF_UPDATE)
735
        {
736
          /* We have to run export filter to get proper 'new' route */
737
          if (! krt_export_rte(p, &new, &tmpa))
738
            {
739
              /* Route rejected, should not happen (KRF_INSTALLED) but to be sure .. */
740
              verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE;
741
            }
742
          else
743
            {
744
              ea_list **x = &tmpa;
745
              while (*x)
746
                x = &((*x)->next);
747
              *x = new ? new->attrs->eattrs : NULL;
748
            }
749
        }
750

    
751
      switch (verdict)
752
        {
753
        case KRF_CREATE:
754
          if (new && (f->flags & KRF_INSTALLED))
755
            {
756
              krt_trace_in(p, new, "reinstalling");
757
              krt_replace_rte(p, n, new, NULL, tmpa);
758
            }
759
          break;
760
        case KRF_SEEN:
761
        case KRF_IGNORE:
762
          /* Nothing happens */
763
          break;
764
        case KRF_UPDATE:
765
          krt_trace_in(p, new, "updating");
766
          krt_replace_rte(p, n, new, old, tmpa);
767
          break;
768
        case KRF_DELETE:
769
          krt_trace_in(p, old, "deleting");
770
          krt_replace_rte(p, n, NULL, old, NULL);
771
          break;
772
        default:
773
          bug("krt_prune: invalid route status");
774
        }
775

    
776
      if (old)
777
        rte_free(old);
778
      if (new != new0)
779
        rte_free(new);
780
      lp_flush(krt_filter_lp);
781
      f->flags &= ~KRF_VERDICT_MASK;
782
    }
783
  FIB_WALK_END;
784

    
785
#ifdef KRT_ALLOW_LEARN
786
  if (KRT_CF->learn)
787
    krt_learn_prune(p);
788
#endif
789

    
790
  if (p->ready)
791
    p->initialized = 1;
792
}
793

    
794
void
795
krt_got_route_async(struct krt_proto *p, rte *e, int new)
796
{
797
  net *net = e->net;
798

    
799
  switch (e->u.krt.src)
800
    {
801
    case KRT_SRC_BIRD:
802
      ASSERT(0);                        /* Should be filtered by the back end */
803

    
804
    case KRT_SRC_REDIRECT:
805
      if (new)
806
        {
807
          krt_trace_in(p, e, "[redirect] deleting");
808
          krt_replace_rte(p, net, NULL, e, NULL);
809
        }
810
      /* If !new, it is probably echo of our deletion */
811
      break;
812

    
813
#ifdef KRT_ALLOW_LEARN
814
    case KRT_SRC_ALIEN:
815
      if (KRT_CF->learn)
816
        {
817
          krt_learn_async(p, e, new);
818
          return;
819
        }
820
#endif
821
    }
822
  rte_free(e);
823
}
824

    
825
/*
826
 *        Periodic scanning
827
 */
828

    
829

    
830
#ifdef CONFIG_ALL_TABLES_AT_ONCE
831

    
832
static timer *krt_scan_timer;
833
static int krt_scan_count;
834

    
835
static void
836
krt_scan(timer *t UNUSED)
837
{
838
  struct krt_proto *p;
839

    
840
  kif_force_scan();
841

    
842
  /* We need some node to decide whether to print the debug messages or not */
843
  p = SKIP_BACK(struct krt_proto, krt_node, HEAD(krt_proto_list));
844
  KRT_TRACE(p, D_EVENTS, "Scanning routing table");
845

    
846
  krt_do_scan(NULL);
847

    
848
  void *q;
849
  WALK_LIST(q, krt_proto_list)
850
  {
851
    p = SKIP_BACK(struct krt_proto, krt_node, q);
852
    krt_prune(p);
853
  }
854
}
855

    
856
static void
857
krt_scan_timer_start(struct krt_proto *p)
858
{
859
  if (!krt_scan_count)
860
    krt_scan_timer = tm_new_set(krt_pool, krt_scan, NULL, 0, KRT_CF->scan_time);
861

    
862
  krt_scan_count++;
863

    
864
  tm_start(krt_scan_timer, 1);
865
}
866

    
867
static void
868
krt_scan_timer_stop(struct krt_proto *p)
869
{
870
  krt_scan_count--;
871

    
872
  if (!krt_scan_count)
873
  {
874
    rfree(krt_scan_timer);
875
    krt_scan_timer = NULL;
876
  }
877
}
878

    
879
static void
880
krt_scan_timer_kick(struct krt_proto *p UNUSED)
881
{
882
  tm_start(krt_scan_timer, 0);
883
}
884

    
885
#else
886

    
887
static void
888
krt_scan(timer *t)
889
{
890
  struct krt_proto *p = t->data;
891

    
892
  kif_force_scan();
893

    
894
  KRT_TRACE(p, D_EVENTS, "Scanning routing table");
895
  krt_do_scan(p);
896
  krt_prune(p);
897
}
898

    
899
static void
900
krt_scan_timer_start(struct krt_proto *p)
901
{
902
  p->scan_timer = tm_new_set(p->p.pool, krt_scan, p, 0, KRT_CF->scan_time);
903
  tm_start(p->scan_timer, 1);
904
}
905

    
906
static void
907
krt_scan_timer_stop(struct krt_proto *p)
908
{
909
  tm_stop(p->scan_timer);
910
}
911

    
912
static void
913
krt_scan_timer_kick(struct krt_proto *p)
914
{
915
  tm_start(p->scan_timer, 0);
916
}
917

    
918
#endif
919

    
920

    
921

    
922

    
923
/*
924
 *        Updates
925
 */
926

    
927
static struct ea_list *
928
krt_make_tmp_attrs(rte *rt, struct linpool *pool)
929
{
930
  struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr));
931

    
932
  l->next = NULL;
933
  l->flags = EALF_SORTED;
934
  l->count = 2;
935

    
936
  l->attrs[0].id = EA_KRT_SOURCE;
937
  l->attrs[0].flags = 0;
938
  l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
939
  l->attrs[0].u.data = rt->u.krt.proto;
940

    
941
  l->attrs[1].id = EA_KRT_METRIC;
942
  l->attrs[1].flags = 0;
943
  l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
944
  l->attrs[1].u.data = rt->u.krt.metric;
945

    
946
  return l;
947
}
948

    
949
static void
950
krt_store_tmp_attrs(rte *rt, struct ea_list *attrs)
951
{
952
  /* EA_KRT_SOURCE is read-only */
953
  rt->u.krt.metric = ea_get_int(attrs, EA_KRT_METRIC, 0);
954
}
955

    
956
static int
957
krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
958
{
959
  struct krt_proto *p = (struct krt_proto *) P;
960
  rte *e = *new;
961

    
962
  if (e->attrs->src->proto == P)
963
    return -1;
964

    
965
  if (!KRT_CF->devroutes &&
966
      (e->attrs->dest == RTD_DEVICE) &&
967
      (e->attrs->source != RTS_STATIC_DEVICE))
968
    return -1;
969

    
970
  if (!krt_capable(e))
971
    return -1;
972

    
973
  return 0;
974
}
975

    
976
static void
977
krt_rt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
978
              rte *new, rte *old, struct ea_list *eattrs)
979
{
980
  struct krt_proto *p = (struct krt_proto *) P;
981

    
982
  if (config->shutdown)
983
    return;
984
  if (!(net->n.flags & KRF_INSTALLED))
985
    old = NULL;
986
  if (new)
987
    net->n.flags |= KRF_INSTALLED;
988
  else
989
    net->n.flags &= ~KRF_INSTALLED;
990
  if (p->initialized)                /* Before first scan we don't touch the routes */
991
    krt_replace_rte(p, net, new, old, eattrs);
992
}
993

    
994
static void
995
krt_if_notify(struct proto *P, uint flags, struct iface *iface UNUSED)
996
{
997
  struct krt_proto *p = (struct krt_proto *) P;
998

    
999
  /*
1000
   * When interface went down, we should remove routes to it. In the ideal world,
1001
   * OS kernel would send us route removal notifications in such cases, but we
1002
   * cannot rely on it as it is often not true. E.g. Linux kernel removes related
1003
   * routes when an interface went down, but it does not notify userspace about
1004
   * that. To be sure, we just schedule a scan to ensure synchronization.
1005
   */
1006

    
1007
  if ((flags & IF_CHANGE_DOWN) && KRT_CF->learn)
1008
    krt_scan_timer_kick(p);
1009
}
1010

    
1011
static int
1012
krt_reload_routes(struct proto *P)
1013
{
1014
  struct krt_proto *p = (struct krt_proto *) P;
1015

    
1016
  /* Although we keep learned routes in krt_table, we rather schedule a scan */
1017

    
1018
  if (KRT_CF->learn)
1019
    krt_scan_timer_kick(p);
1020

    
1021
  return 1;
1022
}
1023

    
1024
static void
1025
krt_feed_done(struct proto *P)
1026
{
1027
  struct krt_proto *p = (struct krt_proto *) P;
1028

    
1029
  p->ready = 1;
1030
  krt_scan_timer_kick(p);
1031
}
1032

    
1033

    
1034
static int
1035
krt_rte_same(rte *a, rte *b)
1036
{
1037
  /* src is always KRT_SRC_ALIEN and type is irrelevant */
1038
  return (a->u.krt.proto == b->u.krt.proto) && (a->u.krt.metric == b->u.krt.metric);
1039
}
1040

    
1041

    
1042
/*
1043
 *        Protocol glue
1044
 */
1045

    
1046
struct krt_config *krt_cf;
1047

    
1048
static struct proto *
1049
krt_init(struct proto_config *c)
1050
{
1051
  struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
1052

    
1053
  p->p.accept_ra_types = RA_OPTIMAL;
1054
  p->p.import_control = krt_import_control;
1055
  p->p.rt_notify = krt_rt_notify;
1056
  p->p.if_notify = krt_if_notify;
1057
  p->p.reload_routes = krt_reload_routes;
1058
  p->p.feed_done = krt_feed_done;
1059
  p->p.make_tmp_attrs = krt_make_tmp_attrs;
1060
  p->p.store_tmp_attrs = krt_store_tmp_attrs;
1061
  p->p.rte_same = krt_rte_same;
1062

    
1063
  krt_sys_init(p);
1064
  return &p->p;
1065
}
1066

    
1067
static int
1068
krt_start(struct proto *P)
1069
{
1070
  struct krt_proto *p = (struct krt_proto *) P;
1071

    
1072
  add_tail(&krt_proto_list, &p->krt_node);
1073

    
1074
#ifdef KRT_ALLOW_LEARN
1075
  krt_learn_init(p);
1076
#endif
1077

    
1078
  krt_sys_start(p);
1079

    
1080
  krt_scan_timer_start(p);
1081

    
1082
  if (P->gr_recovery && KRT_CF->graceful_restart)
1083
    P->gr_wait = 1;
1084

    
1085
  return PS_UP;
1086
}
1087

    
1088
static int
1089
krt_shutdown(struct proto *P)
1090
{
1091
  struct krt_proto *p = (struct krt_proto *) P;
1092

    
1093
  krt_scan_timer_stop(p);
1094

    
1095
  /* FIXME we should flush routes even when persist during reconfiguration */
1096
  if (p->initialized && !KRT_CF->persist)
1097
    krt_flush_routes(p);
1098

    
1099
  p->ready = 0;
1100
  p->initialized = 0;
1101

    
1102
  krt_sys_shutdown(p);
1103

    
1104
  rem_node(&p->krt_node);
1105

    
1106
  return PS_DOWN;
1107
}
1108

    
1109
static int
1110
krt_reconfigure(struct proto *p, struct proto_config *new)
1111
{
1112
  struct krt_config *o = (struct krt_config *) p->cf;
1113
  struct krt_config *n = (struct krt_config *) new;
1114

    
1115
  if (!krt_sys_reconfigure((struct krt_proto *) p, n, o))
1116
    return 0;
1117

    
1118
  /* persist, graceful restart need not be the same */
1119
  return o->scan_time == n->scan_time && o->learn == n->learn && o->devroutes == n->devroutes;
1120
}
1121

    
1122
static void
1123
krt_preconfig(struct protocol *P UNUSED, struct config *c)
1124
{
1125
  krt_cf = NULL;
1126
  krt_sys_preconfig(c);
1127
}
1128

    
1129
static void
1130
krt_postconfig(struct proto_config *C)
1131
{
1132
  struct krt_config *c = (struct krt_config *) C;
1133

    
1134
#ifdef CONFIG_ALL_TABLES_AT_ONCE
1135
  if (krt_cf->scan_time != c->scan_time)
1136
    cf_error("All kernel syncers must use the same table scan interval");
1137
#endif
1138

    
1139
  if (C->table->krt_attached)
1140
    cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name);
1141
  C->table->krt_attached = C;
1142
  krt_sys_postconfig(c);
1143
}
1144

    
1145
struct proto_config *
1146
krt_init_config(int class)
1147
{
1148
#ifndef CONFIG_MULTIPLE_TABLES
1149
  if (krt_cf)
1150
    cf_error("Kernel protocol already defined");
1151
#endif
1152

    
1153
  krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, sizeof(struct krt_config), class);
1154
  krt_cf->scan_time = 60;
1155

    
1156
  krt_sys_init_config(krt_cf);
1157
  return (struct proto_config *) krt_cf;
1158
}
1159

    
1160
static void
1161
krt_copy_config(struct proto_config *dest, struct proto_config *src)
1162
{
1163
  struct krt_config *d = (struct krt_config *) dest;
1164
  struct krt_config *s = (struct krt_config *) src;
1165

    
1166
  /* Shallow copy of everything */
1167
  proto_copy_rest(dest, src, sizeof(struct krt_config));
1168

    
1169
  /* Fix sysdep parts */
1170
  krt_sys_copy_config(d, s);
1171
}
1172

    
1173
static int
1174
krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
1175
{
1176
  switch (a->id)
1177
  {
1178
  case EA_KRT_SOURCE:
1179
    bsprintf(buf, "source");
1180
    return GA_NAME;
1181

    
1182
  case EA_KRT_METRIC:
1183
    bsprintf(buf, "metric");
1184
    return GA_NAME;
1185

    
1186
  case EA_KRT_PREFSRC:
1187
    bsprintf(buf, "prefsrc");
1188
    return GA_NAME;
1189

    
1190
  case EA_KRT_REALM:
1191
    bsprintf(buf, "realm");
1192
    return GA_NAME;
1193

    
1194
  default:
1195
    return GA_UNKNOWN;
1196
  }
1197
}
1198

    
1199

    
1200
struct protocol proto_unix_kernel = {
1201
  .name =                "Kernel",
1202
  .template =                "kernel%d",
1203
  .attr_class =                EAP_KRT,
1204
  .preference =                DEF_PREF_INHERITED,
1205
  .preconfig =                krt_preconfig,
1206
  .postconfig =                krt_postconfig,
1207
  .init =                krt_init,
1208
  .start =                krt_start,
1209
  .shutdown =                krt_shutdown,
1210
  .reconfigure =        krt_reconfigure,
1211
  .copy_config =        krt_copy_config,
1212
  .get_attr =                krt_get_attr,
1213
#ifdef KRT_ALLOW_LEARN
1214
  .dump =                krt_dump,
1215
  .dump_attrs =                krt_dump_attrs,
1216
#endif
1217
};