Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / krt.c @ 600998fc

History | View | Annotate | Download (27.2 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
  krt_sys_io_init();
81
}
82

    
83
/*
84
 *        Interfaces
85
 */
86

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

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

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

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

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

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

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

    
133
static inline struct ifa *
134
find_preferred_ifa(struct iface *i, const net_addr *n)
135
{
136
  struct ifa *a, *b = NULL;
137

    
138
  WALK_LIST(a, i->addrs)
139
    {
140
      if (!(a->flags & IA_SECONDARY) &&
141
          (!n || ipa_in_netX(a->ip, n)) &&
142
          (!b || prefer_addr(a, b)))
143
        b = a;
144
    }
145

    
146
  return b;
147
}
148

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

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

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

    
166
  return find_preferred_ifa(i, NULL);
167
}
168

    
169

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

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

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

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

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

    
195
  return PS_UP;
196
}
197

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

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

    
207
  return PS_DOWN;
208
}
209

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

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

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

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

    
235
      ifa_recalc_all_primary_addresses();
236
    }
237

    
238
  return 1;
239
}
240

    
241

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

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

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

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

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

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

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

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

    
279

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

    
293
/*
294
 *        Tracing of routes
295
 */
296

    
297
static inline void
298
krt_trace_in(struct krt_proto *p, rte *e, char *msg)
299
{
300
  if (p->p.debug & D_PACKETS)
301
    log(L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg);
302
}
303

    
304
static inline void
305
krt_trace_in_rl(struct tbf *f, struct krt_proto *p, rte *e, char *msg)
306
{
307
  if (p->p.debug & D_PACKETS)
308
    log_rl(f, L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg);
309
}
310

    
311
/*
312
 *        Inherited Routes
313
 */
314

    
315
#ifdef KRT_ALLOW_LEARN
316

    
317
static struct tbf rl_alien = TBF_DEFAULT_LOG_LIMITS;
318

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

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

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

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

    
342
  return 1;
343
}
344

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

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

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

    
374
  e->attrs = rta_lookup(e->attrs);
375

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

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

    
411
  KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
412

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

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

    
465
  p->reload = 0;
466
}
467

    
468
static void
469
krt_learn_async(struct krt_proto *p, rte *e, int new)
470
{
471
  net *n0 = e->net;
472
  net *n = net_get(&p->krt_table, n0->n.addr);
473
  rte *g, **gg, *best, **bestp, *old_best;
474

    
475
  e->attrs = rta_lookup(e->attrs);
476

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

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

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

    
552
static void
553
krt_dump(struct proto *P)
554
{
555
  struct krt_proto *p = (struct krt_proto *) P;
556

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

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

    
569
#endif
570

    
571
/*
572
 *        Routes
573
 */
574

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

    
580
  KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
581
  FIB_WALK(&t->fib, net, n)
582
    {
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 struct rte *
595
krt_export_net(struct krt_proto *p, net *net, rte **rt_free, ea_list **tmpa)
596
{
597
  struct announce_hook *ah = p->p.main_ahook;
598
  struct filter *filter = ah->out_filter;
599
  rte *rt;
600

    
601
  if (p->p.accept_ra_types == RA_MERGED)
602
    return rt_export_merged(ah, net, rt_free, tmpa, 1);
603

    
604
  rt = net->routes;
605
  *rt_free = NULL;
606

    
607
  if (!rte_is_valid(rt))
608
    return NULL;
609

    
610
  if (filter == FILTER_REJECT)
611
    return NULL;
612

    
613
  struct proto *src = rt->attrs->src->proto;
614
  *tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(rt, krt_filter_lp) : NULL;
615

    
616
  /* We could run krt_import_control() here, but it is already handled by KRF_INSTALLED */
617

    
618
  if (filter == FILTER_ACCEPT)
619
    goto accept;
620

    
621
  if (f_run(filter, &rt, tmpa, krt_filter_lp, FF_FORCE_TMPATTR) > F_ACCEPT)
622
    goto reject;
623

    
624

    
625
accept:
626
  if (rt != net->routes)
627
    *rt_free = rt;
628
  return rt;
629

    
630
reject:
631
  if (rt != net->routes)
632
    rte_free(rt);
633
  return NULL;
634
}
635

    
636
static int
637
krt_same_dest(rte *k, rte *e)
638
{
639
  rta *ka = k->attrs, *ea = e->attrs;
640

    
641
  if (ka->dest != ea->dest)
642
    return 0;
643
  switch (ka->dest)
644
    {
645
    case RTD_ROUTER:
646
      return ipa_equal(ka->gw, ea->gw);
647
    case RTD_DEVICE:
648
      return !strcmp(ka->iface->name, ea->iface->name);
649
    case RTD_MULTIPATH:
650
      return mpnh_same(ka->nexthops, ea->nexthops);
651
    default:
652
      return 1;
653
    }
654
}
655

    
656
/*
657
 *  This gets called back when the low-level scanning code discovers a route.
658
 *  We expect that the route is a temporary rte and its attributes are uncached.
659
 */
660

    
661
void
662
krt_got_route(struct krt_proto *p, rte *e)
663
{
664
  net *net = e->net;
665
  int verdict;
666

    
667
#ifdef KRT_ALLOW_LEARN
668
  switch (e->u.krt.src)
669
    {
670
    case KRT_SRC_KERNEL:
671
      verdict = KRF_IGNORE;
672
      goto sentenced;
673

    
674
    case KRT_SRC_REDIRECT:
675
      verdict = KRF_DELETE;
676
      goto sentenced;
677

    
678
    case  KRT_SRC_ALIEN:
679
      if (KRT_CF->learn)
680
        krt_learn_scan(p, e);
681
      else
682
        {
683
          krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored");
684
          rte_free(e);
685
        }
686
      return;
687
    }
688
#endif
689
  /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
690

    
691
  if (net->n.flags & KRF_VERDICT_MASK)
692
    {
693
      /* Route to this destination was already seen. Strange, but it happens... */
694
      krt_trace_in(p, e, "already seen");
695
      rte_free(e);
696
      return;
697
    }
698

    
699
  if (!p->ready)
700
    {
701
      /* We wait for the initial feed to have correct KRF_INSTALLED flag */
702
      verdict = KRF_IGNORE;
703
      goto sentenced;
704
    }
705

    
706
  if (net->n.flags & KRF_INSTALLED)
707
    {
708
      rte *new, *rt_free;
709
      ea_list *tmpa;
710

    
711
      new = krt_export_net(p, net, &rt_free, &tmpa);
712

    
713
      /* TODO: There also may be changes in route eattrs, we ignore that for now. */
714

    
715
      if (!new)
716
        verdict = KRF_DELETE;
717
      else if ((net->n.flags & KRF_SYNC_ERROR) || !krt_same_dest(e, new))
718
        verdict = KRF_UPDATE;
719
      else
720
        verdict = KRF_SEEN;
721

    
722
      if (rt_free)
723
        rte_free(rt_free);
724

    
725
      lp_flush(krt_filter_lp);
726
    }
727
  else
728
    verdict = KRF_DELETE;
729

    
730
 sentenced:
731
  krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]);
732
  net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
733
  if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
734
    {
735
      /* Get a cached copy of attributes and temporarily link the route */
736
      rta *a = e->attrs;
737
      a->source = RTS_DUMMY;
738
      e->attrs = rta_lookup(a);
739
      e->next = net->routes;
740
      net->routes = e;
741
    }
742
  else
743
    rte_free(e);
744
}
745

    
746
static void
747
krt_prune(struct krt_proto *p)
748
{
749
  struct rtable *t = p->p.table;
750

    
751
  KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
752
  FIB_WALK(&t->fib, net, n)
753
    {
754
      int verdict = n->n.flags & KRF_VERDICT_MASK;
755
      rte *new, *old, *rt_free = NULL;
756
      ea_list *tmpa = NULL;
757

    
758
      if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
759
        {
760
          /* Get a dummy route from krt_got_route() */
761
          old = n->routes;
762
          n->routes = old->next;
763
        }
764
      else
765
        old = NULL;
766

    
767
      if (verdict == KRF_CREATE || verdict == KRF_UPDATE)
768
        {
769
          /* We have to run export filter to get proper 'new' route */
770
          new = krt_export_net(p, n, &rt_free, &tmpa);
771

    
772
          if (!new)
773
            verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE;
774
          else
775
            tmpa = ea_append(tmpa, new->attrs->eattrs);
776
        }
777
      else
778
        new = NULL;
779

    
780
      switch (verdict)
781
        {
782
        case KRF_CREATE:
783
          if (new && (n->n.flags & KRF_INSTALLED))
784
            {
785
              krt_trace_in(p, new, "reinstalling");
786
              krt_replace_rte(p, n, new, NULL, tmpa);
787
            }
788
          break;
789
        case KRF_SEEN:
790
        case KRF_IGNORE:
791
          /* Nothing happens */
792
          break;
793
        case KRF_UPDATE:
794
          krt_trace_in(p, new, "updating");
795
          krt_replace_rte(p, n, new, old, tmpa);
796
          break;
797
        case KRF_DELETE:
798
          krt_trace_in(p, old, "deleting");
799
          krt_replace_rte(p, n, NULL, old, NULL);
800
          break;
801
        default:
802
          bug("krt_prune: invalid route status");
803
        }
804

    
805
      if (old)
806
        rte_free(old);
807
      if (rt_free)
808
        rte_free(rt_free);
809
      lp_flush(krt_filter_lp);
810
      n->n.flags &= ~KRF_VERDICT_MASK;
811
    }
812
  FIB_WALK_END;
813

    
814
#ifdef KRT_ALLOW_LEARN
815
  if (KRT_CF->learn)
816
    krt_learn_prune(p);
817
#endif
818

    
819
  if (p->ready)
820
    p->initialized = 1;
821
}
822

    
823
void
824
krt_got_route_async(struct krt_proto *p, rte *e, int new)
825
{
826
  net *net = e->net;
827

    
828
  switch (e->u.krt.src)
829
    {
830
    case KRT_SRC_BIRD:
831
      ASSERT(0);                        /* Should be filtered by the back end */
832

    
833
    case KRT_SRC_REDIRECT:
834
      if (new)
835
        {
836
          krt_trace_in(p, e, "[redirect] deleting");
837
          krt_replace_rte(p, net, NULL, e, NULL);
838
        }
839
      /* If !new, it is probably echo of our deletion */
840
      break;
841

    
842
#ifdef KRT_ALLOW_LEARN
843
    case KRT_SRC_ALIEN:
844
      if (KRT_CF->learn)
845
        {
846
          krt_learn_async(p, e, new);
847
          return;
848
        }
849
#endif
850
    }
851
  rte_free(e);
852
}
853

    
854
/*
855
 *        Periodic scanning
856
 */
857

    
858

    
859
#ifdef CONFIG_ALL_TABLES_AT_ONCE
860

    
861
static timer *krt_scan_timer;
862
static int krt_scan_count;
863

    
864
static void
865
krt_scan(timer *t UNUSED)
866
{
867
  struct krt_proto *p;
868

    
869
  kif_force_scan();
870

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

    
875
  krt_do_scan(NULL);
876

    
877
  void *q;
878
  WALK_LIST(q, krt_proto_list)
879
  {
880
    p = SKIP_BACK(struct krt_proto, krt_node, q);
881
    krt_prune(p);
882
  }
883
}
884

    
885
static void
886
krt_scan_timer_start(struct krt_proto *p)
887
{
888
  if (!krt_scan_count)
889
    krt_scan_timer = tm_new_set(krt_pool, krt_scan, NULL, 0, KRT_CF->scan_time);
890

    
891
  krt_scan_count++;
892

    
893
  tm_start(krt_scan_timer, 1);
894
}
895

    
896
static void
897
krt_scan_timer_stop(struct krt_proto *p)
898
{
899
  krt_scan_count--;
900

    
901
  if (!krt_scan_count)
902
  {
903
    rfree(krt_scan_timer);
904
    krt_scan_timer = NULL;
905
  }
906
}
907

    
908
static void
909
krt_scan_timer_kick(struct krt_proto *p UNUSED)
910
{
911
  tm_start(krt_scan_timer, 0);
912
}
913

    
914
#else
915

    
916
static void
917
krt_scan(timer *t)
918
{
919
  struct krt_proto *p = t->data;
920

    
921
  kif_force_scan();
922

    
923
  KRT_TRACE(p, D_EVENTS, "Scanning routing table");
924
  krt_do_scan(p);
925
  krt_prune(p);
926
}
927

    
928
static void
929
krt_scan_timer_start(struct krt_proto *p)
930
{
931
  p->scan_timer = tm_new_set(p->p.pool, krt_scan, p, 0, KRT_CF->scan_time);
932
  tm_start(p->scan_timer, 1);
933
}
934

    
935
static void
936
krt_scan_timer_stop(struct krt_proto *p)
937
{
938
  tm_stop(p->scan_timer);
939
}
940

    
941
static void
942
krt_scan_timer_kick(struct krt_proto *p)
943
{
944
  tm_start(p->scan_timer, 0);
945
}
946

    
947
#endif
948

    
949

    
950

    
951

    
952
/*
953
 *        Updates
954
 */
955

    
956
static struct ea_list *
957
krt_make_tmp_attrs(rte *rt, struct linpool *pool)
958
{
959
  struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr));
960

    
961
  l->next = NULL;
962
  l->flags = EALF_SORTED;
963
  l->count = 2;
964

    
965
  l->attrs[0].id = EA_KRT_SOURCE;
966
  l->attrs[0].flags = 0;
967
  l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
968
  l->attrs[0].u.data = rt->u.krt.proto;
969

    
970
  l->attrs[1].id = EA_KRT_METRIC;
971
  l->attrs[1].flags = 0;
972
  l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
973
  l->attrs[1].u.data = rt->u.krt.metric;
974

    
975
  return l;
976
}
977

    
978
static void
979
krt_store_tmp_attrs(rte *rt, struct ea_list *attrs)
980
{
981
  /* EA_KRT_SOURCE is read-only */
982
  rt->u.krt.metric = ea_get_int(attrs, EA_KRT_METRIC, 0);
983
}
984

    
985
static int
986
krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
987
{
988
  struct krt_proto *p = (struct krt_proto *) P;
989
  rte *e = *new;
990

    
991
  if (e->attrs->src->proto == P)
992
  {
993
#ifdef CONFIG_SINGLE_ROUTE
994
    /*
995
     * Implicit withdraw - when the imported kernel route becomes the best one,
996
     * we know that the previous one exported to the kernel was already removed,
997
     * but if we processed the update as usual, we would send withdraw to the
998
     * kernel, which would remove the new imported route instead.
999
     *
1000
     * We will remove KRT_INSTALLED flag, which stops such withdraw to be
1001
     * processed in krt_rt_notify() and krt_replace_rte().
1002
     */
1003
    if (e == e->net->routes)
1004
      e->net->n.flags &= ~KRF_INSTALLED;
1005
#endif
1006
    return -1;
1007
  }
1008

    
1009
  if (!KRT_CF->devroutes &&
1010
      (e->attrs->dest == RTD_DEVICE) &&
1011
      (e->attrs->source != RTS_STATIC_DEVICE))
1012
    return -1;
1013

    
1014
  if (!krt_capable(e))
1015
    return -1;
1016

    
1017
  return 0;
1018
}
1019

    
1020
static void
1021
krt_rt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
1022
              rte *new, rte *old, struct ea_list *eattrs)
1023
{
1024
  struct krt_proto *p = (struct krt_proto *) P;
1025

    
1026
  if (config->shutdown)
1027
    return;
1028
  if (!(net->n.flags & KRF_INSTALLED))
1029
    old = NULL;
1030
  if (new)
1031
    net->n.flags |= KRF_INSTALLED;
1032
  else
1033
    net->n.flags &= ~KRF_INSTALLED;
1034
  if (p->initialized)                /* Before first scan we don't touch the routes */
1035
    krt_replace_rte(p, net, new, old, eattrs);
1036
}
1037

    
1038
static void
1039
krt_if_notify(struct proto *P, uint flags, struct iface *iface UNUSED)
1040
{
1041
  struct krt_proto *p = (struct krt_proto *) P;
1042

    
1043
  /*
1044
   * When interface went down, we should remove routes to it. In the ideal world,
1045
   * OS kernel would send us route removal notifications in such cases, but we
1046
   * cannot rely on it as it is often not true. E.g. Linux kernel removes related
1047
   * routes when an interface went down, but it does not notify userspace about
1048
   * that. To be sure, we just schedule a scan to ensure synchronization.
1049
   */
1050

    
1051
  if ((flags & IF_CHANGE_DOWN) && KRT_CF->learn)
1052
    krt_scan_timer_kick(p);
1053
}
1054

    
1055
static int
1056
krt_reload_routes(struct proto *P)
1057
{
1058
  struct krt_proto *p = (struct krt_proto *) P;
1059

    
1060
  /* Although we keep learned routes in krt_table, we rather schedule a scan */
1061

    
1062
  if (KRT_CF->learn)
1063
  {
1064
    p->reload = 1;
1065
    krt_scan_timer_kick(p);
1066
  }
1067

    
1068
  return 1;
1069
}
1070

    
1071
static void
1072
krt_feed_end(struct proto *P)
1073
{
1074
  struct krt_proto *p = (struct krt_proto *) P;
1075

    
1076
  p->ready = 1;
1077
  krt_scan_timer_kick(p);
1078
}
1079

    
1080

    
1081
static int
1082
krt_rte_same(rte *a, rte *b)
1083
{
1084
  /* src is always KRT_SRC_ALIEN and type is irrelevant */
1085
  return (a->u.krt.proto == b->u.krt.proto) && (a->u.krt.metric == b->u.krt.metric);
1086
}
1087

    
1088

    
1089
/*
1090
 *        Protocol glue
1091
 */
1092

    
1093
struct krt_config *krt_cf;
1094

    
1095
static struct proto *
1096
krt_init(struct proto_config *C)
1097
{
1098
  struct krt_proto *p = proto_new(C, sizeof(struct krt_proto));
1099
  struct krt_config *c = (struct krt_config *) C;
1100

    
1101
  p->p.accept_ra_types = c->merge_paths ? RA_MERGED : RA_OPTIMAL;
1102
  p->p.merge_limit = c->merge_paths;
1103
  p->p.import_control = krt_import_control;
1104
  p->p.rt_notify = krt_rt_notify;
1105
  p->p.if_notify = krt_if_notify;
1106
  p->p.reload_routes = krt_reload_routes;
1107
  p->p.feed_end = krt_feed_end;
1108
  p->p.make_tmp_attrs = krt_make_tmp_attrs;
1109
  p->p.store_tmp_attrs = krt_store_tmp_attrs;
1110
  p->p.rte_same = krt_rte_same;
1111

    
1112
  krt_sys_init(p);
1113
  return &p->p;
1114
}
1115

    
1116
static int
1117
krt_start(struct proto *P)
1118
{
1119
  struct krt_proto *p = (struct krt_proto *) P;
1120

    
1121
  switch (p->p.table->addr_type)
1122
  {
1123
  case NET_IP4:        p->af = AF_INET; break;
1124
  case NET_IP6:        p->af = AF_INET6; break;
1125
  default:        ASSERT(0);
1126
  }
1127

    
1128
  add_tail(&krt_proto_list, &p->krt_node);
1129

    
1130
#ifdef KRT_ALLOW_LEARN
1131
  krt_learn_init(p);
1132
#endif
1133

    
1134
  if (!krt_sys_start(p))
1135
  {
1136
    rem_node(&p->krt_node);
1137
    return PS_START;
1138
  }
1139

    
1140
  krt_scan_timer_start(p);
1141

    
1142
  if (P->gr_recovery && KRT_CF->graceful_restart)
1143
    P->gr_wait = 1;
1144

    
1145
  return PS_UP;
1146
}
1147

    
1148
static int
1149
krt_shutdown(struct proto *P)
1150
{
1151
  struct krt_proto *p = (struct krt_proto *) P;
1152

    
1153
  krt_scan_timer_stop(p);
1154

    
1155
  /* FIXME we should flush routes even when persist during reconfiguration */
1156
  if (p->initialized && !KRT_CF->persist)
1157
    krt_flush_routes(p);
1158

    
1159
  p->ready = 0;
1160
  p->initialized = 0;
1161

    
1162
  if (p->p.proto_state == PS_START)
1163
    return PS_DOWN;
1164

    
1165
  krt_sys_shutdown(p);
1166
  rem_node(&p->krt_node);
1167

    
1168
  return PS_DOWN;
1169
}
1170

    
1171
static int
1172
krt_reconfigure(struct proto *p, struct proto_config *new)
1173
{
1174
  struct krt_config *o = (struct krt_config *) p->cf;
1175
  struct krt_config *n = (struct krt_config *) new;
1176

    
1177
  if (!krt_sys_reconfigure((struct krt_proto *) p, n, o))
1178
    return 0;
1179

    
1180
  /* persist, graceful restart need not be the same */
1181
  return o->scan_time == n->scan_time && o->learn == n->learn &&
1182
    o->devroutes == n->devroutes && o->merge_paths == n->merge_paths;
1183
}
1184

    
1185
static void
1186
krt_preconfig(struct protocol *P UNUSED, struct config *c)
1187
{
1188
  krt_cf = NULL;
1189
  krt_sys_preconfig(c);
1190
}
1191

    
1192
static void
1193
krt_postconfig(struct proto_config *C)
1194
{
1195
  struct krt_config *c = (struct krt_config *) C;
1196

    
1197
#ifdef CONFIG_ALL_TABLES_AT_ONCE
1198
  if (krt_cf->scan_time != c->scan_time)
1199
    cf_error("All kernel syncers must use the same table scan interval");
1200
#endif
1201

    
1202
  if (C->table->krt_attached)
1203
    cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name);
1204
  C->table->krt_attached = C;
1205
  krt_sys_postconfig(c);
1206
}
1207

    
1208
struct proto_config *
1209
krt_init_config(int class)
1210
{
1211
#ifndef CONFIG_MULTIPLE_TABLES
1212
  if (krt_cf)
1213
    cf_error("Kernel protocol already defined");
1214
#endif
1215

    
1216
  krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, class);
1217
  krt_cf->scan_time = 60;
1218

    
1219
  krt_sys_init_config(krt_cf);
1220
  return (struct proto_config *) krt_cf;
1221
}
1222

    
1223
static void
1224
krt_copy_config(struct proto_config *dest, struct proto_config *src)
1225
{
1226
  struct krt_config *d = (struct krt_config *) dest;
1227
  struct krt_config *s = (struct krt_config *) src;
1228

    
1229
  /* Shallow copy of everything */
1230
  proto_copy_rest(dest, src, sizeof(struct krt_config));
1231

    
1232
  /* Fix sysdep parts */
1233
  krt_sys_copy_config(d, s);
1234
}
1235

    
1236
static int
1237
krt_get_attr(eattr *a, byte *buf, int buflen)
1238
{
1239
  switch (a->id)
1240
  {
1241
  case EA_KRT_SOURCE:
1242
    bsprintf(buf, "source");
1243
    return GA_NAME;
1244

    
1245
  case EA_KRT_METRIC:
1246
    bsprintf(buf, "metric");
1247
    return GA_NAME;
1248

    
1249
  default:
1250
    return krt_sys_get_attr(a, buf, buflen);
1251
  }
1252
}
1253

    
1254

    
1255
struct protocol proto_unix_kernel = {
1256
  .name =                "Kernel",
1257
  .template =                "kernel%d",
1258
  .attr_class =                EAP_KRT,
1259
  .preference =                DEF_PREF_INHERITED,
1260
  .config_size =        sizeof(struct krt_config),
1261
  .preconfig =                krt_preconfig,
1262
  .postconfig =                krt_postconfig,
1263
  .init =                krt_init,
1264
  .start =                krt_start,
1265
  .shutdown =                krt_shutdown,
1266
  .reconfigure =        krt_reconfigure,
1267
  .copy_config =        krt_copy_config,
1268
  .get_attr =                krt_get_attr,
1269
#ifdef KRT_ALLOW_LEARN
1270
  .dump =                krt_dump,
1271
  .dump_attrs =                krt_dump_attrs,
1272
#endif
1273
};