Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / sysdep / unix / krt.c @ 6b3f1a54

History | View | Annotate | Download (26.5 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 "conf/conf.h"
60
#include "lib/string.h"
61
#include "lib/timer.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_default(krt_pool);
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 btime kif_last_shot;
91

    
92
static struct kif_iface_config kif_default_iface = {};
93

    
94
struct kif_iface_config *
95
kif_get_iface_config(struct iface *iface)
96
{
97
  struct kif_config *cf = (void *) (kif_proto->p.cf);
98
  struct kif_iface_config *ic = (void *) iface_patt_find(&cf->iface_list, iface, NULL);
99
  return ic ?: &kif_default_iface;
100
}
101

    
102
static void
103
kif_scan(timer *t)
104
{
105
  struct kif_proto *p = t->data;
106

    
107
  KRT_TRACE(p, D_EVENTS, "Scanning interfaces");
108
  kif_last_shot = current_time();
109
  kif_do_scan(p);
110
}
111

    
112
static void
113
kif_force_scan(void)
114
{
115
  if (kif_proto && ((kif_last_shot + 2 S) < current_time()))
116
    {
117
      kif_scan(kif_scan_timer);
118
      tm_start(kif_scan_timer, ((struct kif_config *) kif_proto->p.cf)->scan_time);
119
    }
120
}
121

    
122
void
123
kif_request_scan(void)
124
{
125
  if (kif_proto && (kif_scan_timer->expires > (current_time() + 1 S)))
126
    tm_start(kif_scan_timer, 1 S);
127
}
128

    
129
static struct proto *
130
kif_init(struct proto_config *c)
131
{
132
  struct kif_proto *p = proto_new(c);
133

    
134
  kif_sys_init(p);
135
  return &p->p;
136
}
137

    
138
static int
139
kif_start(struct proto *P)
140
{
141
  struct kif_proto *p = (struct kif_proto *) P;
142

    
143
  kif_proto = p;
144
  kif_sys_start(p);
145

    
146
  /* Start periodic interface scanning */
147
  kif_scan_timer = tm_new_init(P->pool, kif_scan, p, KIF_CF->scan_time, 0);
148
  kif_scan(kif_scan_timer);
149
  tm_start(kif_scan_timer, KIF_CF->scan_time);
150

    
151
  return PS_UP;
152
}
153

    
154
static int
155
kif_shutdown(struct proto *P)
156
{
157
  struct kif_proto *p = (struct kif_proto *) P;
158

    
159
  tm_stop(kif_scan_timer);
160
  kif_sys_shutdown(p);
161
  kif_proto = NULL;
162

    
163
  return PS_DOWN;
164
}
165

    
166
static int
167
kif_reconfigure(struct proto *p, struct proto_config *new)
168
{
169
  struct kif_config *o = (struct kif_config *) p->cf;
170
  struct kif_config *n = (struct kif_config *) new;
171

    
172
  if (!kif_sys_reconfigure((struct kif_proto *) p, n, o))
173
    return 0;
174

    
175
  if (o->scan_time != n->scan_time)
176
    {
177
      tm_stop(kif_scan_timer);
178
      kif_scan_timer->recurrent = n->scan_time;
179
      kif_scan(kif_scan_timer);
180
      tm_start(kif_scan_timer, n->scan_time);
181
    }
182

    
183
  if (!EMPTY_LIST(o->iface_list) || !EMPTY_LIST(n->iface_list))
184
    {
185
      /* This is hack, we have to update a configuration
186
       * to the new value just now, because it is used
187
       * for recalculation of preferred addresses.
188
       */
189
      p->cf = new;
190

    
191
      if_recalc_all_preferred_addresses();
192
    }
193

    
194
  return 1;
195
}
196

    
197

    
198
static void
199
kif_preconfig(struct protocol *P UNUSED, struct config *c)
200
{
201
  kif_cf = NULL;
202
  kif_sys_preconfig(c);
203
}
204

    
205
struct proto_config *
206
kif_init_config(int class)
207
{
208
  if (kif_cf)
209
    cf_error("Kernel device protocol already defined");
210

    
211
  kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, class);
212
  kif_cf->scan_time = 60 S;
213
  init_list(&kif_cf->iface_list);
214

    
215
  kif_sys_init_config(kif_cf);
216
  return (struct proto_config *) kif_cf;
217
}
218

    
219
static void
220
kif_copy_config(struct proto_config *dest, struct proto_config *src)
221
{
222
  struct kif_config *d = (struct kif_config *) dest;
223
  struct kif_config *s = (struct kif_config *) src;
224

    
225
  /* Copy interface config list */
226
  cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct kif_iface_config));
227

    
228
  /* Fix sysdep parts */
229
  kif_sys_copy_config(d, s);
230
}
231

    
232
struct protocol proto_unix_iface = {
233
  .name =                 "Device",
234
  .template =                 "device%d",
235
  .proto_size =                sizeof(struct kif_proto),
236
  .config_size =        sizeof(struct kif_config),
237
  .preconfig =                kif_preconfig,
238
  .init =                kif_init,
239
  .start =                kif_start,
240
  .shutdown =                kif_shutdown,
241
  .reconfigure =        kif_reconfigure,
242
  .copy_config =        kif_copy_config
243
};
244

    
245
/*
246
 *        Tracing of routes
247
 */
248

    
249
static inline void
250
krt_trace_in(struct krt_proto *p, rte *e, char *msg)
251
{
252
  if (p->p.debug & D_PACKETS)
253
    log(L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg);
254
}
255

    
256
static inline void
257
krt_trace_in_rl(struct tbf *f, struct krt_proto *p, rte *e, char *msg)
258
{
259
  if (p->p.debug & D_PACKETS)
260
    log_rl(f, L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg);
261
}
262

    
263
/*
264
 *        Inherited Routes
265
 */
266

    
267
#ifdef KRT_ALLOW_LEARN
268

    
269
static struct tbf rl_alien = TBF_DEFAULT_LOG_LIMITS;
270

    
271
/*
272
 * krt_same_key() specifies what (aside from the net) is the key in
273
 * kernel routing tables. It should be OS-dependent, this is for
274
 * Linux. It is important for asynchronous alien updates, because a
275
 * positive update is implicitly a negative one for any old route with
276
 * the same key.
277
 */
278

    
279
static inline int
280
krt_same_key(rte *a, rte *b)
281
{
282
  return a->u.krt.metric == b->u.krt.metric;
283
}
284

    
285
static inline int
286
krt_uptodate(rte *a, rte *b)
287
{
288
  if (a->attrs != b->attrs)
289
    return 0;
290

    
291
  if (a->u.krt.proto != b->u.krt.proto)
292
    return 0;
293

    
294
  return 1;
295
}
296

    
297
static void
298
krt_learn_announce_update(struct krt_proto *p, rte *e)
299
{
300
  net *n = e->net;
301
  rta *aa = rta_clone(e->attrs);
302
  rte *ee = rte_get_temp(aa);
303
  ee->pflags = 0;
304
  ee->u.krt = e->u.krt;
305
  rte_update(&p->p, n->n.addr, ee);
306
}
307

    
308
static void
309
krt_learn_announce_delete(struct krt_proto *p, net *n)
310
{
311
  rte_update(&p->p, n->n.addr, NULL);
312
}
313

    
314
/* Called when alien route is discovered during scan */
315
static void
316
krt_learn_scan(struct krt_proto *p, rte *e)
317
{
318
  net *n0 = e->net;
319
  net *n = net_get(&p->krt_table, n0->n.addr);
320
  rte *m, **mm;
321

    
322
  e->attrs = rta_lookup(e->attrs);
323

    
324
  for(mm=&n->routes; m = *mm; mm=&m->next)
325
    if (krt_same_key(m, e))
326
      break;
327
  if (m)
328
    {
329
      if (krt_uptodate(m, e))
330
        {
331
          krt_trace_in_rl(&rl_alien, p, e, "[alien] seen");
332
          rte_free(e);
333
          m->u.krt.seen = 1;
334
        }
335
      else
336
        {
337
          krt_trace_in(p, e, "[alien] updated");
338
          *mm = m->next;
339
          rte_free(m);
340
          m = NULL;
341
        }
342
    }
343
  else
344
    krt_trace_in(p, e, "[alien] created");
345
  if (!m)
346
    {
347
      e->next = n->routes;
348
      n->routes = e;
349
      e->u.krt.seen = 1;
350
    }
351
}
352

    
353
static void
354
krt_learn_prune(struct krt_proto *p)
355
{
356
  struct fib *fib = &p->krt_table.fib;
357
  struct fib_iterator fit;
358

    
359
  KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
360

    
361
  FIB_ITERATE_INIT(&fit, fib);
362
again:
363
  FIB_ITERATE_START(fib, &fit, net, n)
364
    {
365
      rte *e, **ee, *best, **pbest, *old_best;
366

    
367
      /*
368
       * Note that old_best may be NULL even if there was an old best route in
369
       * the previous step, because it might be replaced in krt_learn_scan().
370
       * But in that case there is a new valid best route.
371
       */
372

    
373
      old_best = NULL;
374
      best = NULL;
375
      pbest = NULL;
376
      ee = &n->routes;
377
      while (e = *ee)
378
        {
379
          if (e->u.krt.best)
380
            old_best = e;
381

    
382
          if (!e->u.krt.seen)
383
            {
384
              *ee = e->next;
385
              rte_free(e);
386
              continue;
387
            }
388

    
389
          if (!best || best->u.krt.metric > e->u.krt.metric)
390
            {
391
              best = e;
392
              pbest = ee;
393
            }
394

    
395
          e->u.krt.seen = 0;
396
          e->u.krt.best = 0;
397
          ee = &e->next;
398
        }
399
      if (!n->routes)
400
        {
401
          DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
402
          if (old_best)
403
            krt_learn_announce_delete(p, n);
404

    
405
          FIB_ITERATE_PUT(&fit);
406
          fib_delete(fib, n);
407
          goto again;
408
        }
409

    
410
      best->u.krt.best = 1;
411
      *pbest = best->next;
412
      best->next = n->routes;
413
      n->routes = best;
414

    
415
      if ((best != old_best) || p->reload)
416
        {
417
          DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
418
          krt_learn_announce_update(p, best);
419
        }
420
      else
421
        DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
422
    }
423
  FIB_ITERATE_END;
424

    
425
  p->reload = 0;
426
}
427

    
428
static void
429
krt_learn_async(struct krt_proto *p, rte *e, int new)
430
{
431
  net *n0 = e->net;
432
  net *n = net_get(&p->krt_table, n0->n.addr);
433
  rte *g, **gg, *best, **bestp, *old_best;
434

    
435
  e->attrs = rta_lookup(e->attrs);
436

    
437
  old_best = n->routes;
438
  for(gg=&n->routes; g = *gg; gg = &g->next)
439
    if (krt_same_key(g, e))
440
      break;
441
  if (new)
442
    {
443
      if (g)
444
        {
445
          if (krt_uptodate(g, e))
446
            {
447
              krt_trace_in(p, e, "[alien async] same");
448
              rte_free(e);
449
              return;
450
            }
451
          krt_trace_in(p, e, "[alien async] updated");
452
          *gg = g->next;
453
          rte_free(g);
454
        }
455
      else
456
        krt_trace_in(p, e, "[alien async] created");
457

    
458
      e->next = n->routes;
459
      n->routes = e;
460
    }
461
  else if (!g)
462
    {
463
      krt_trace_in(p, e, "[alien async] delete failed");
464
      rte_free(e);
465
      return;
466
    }
467
  else
468
    {
469
      krt_trace_in(p, e, "[alien async] removed");
470
      *gg = g->next;
471
      rte_free(e);
472
      rte_free(g);
473
    }
474
  best = n->routes;
475
  bestp = &n->routes;
476
  for(gg=&n->routes; g=*gg; gg=&g->next)
477
  {
478
    if (best->u.krt.metric > g->u.krt.metric)
479
      {
480
        best = g;
481
        bestp = gg;
482
      }
483

    
484
    g->u.krt.best = 0;
485
  }
486

    
487
  if (best)
488
    {
489
      best->u.krt.best = 1;
490
      *bestp = best->next;
491
      best->next = n->routes;
492
      n->routes = best;
493
    }
494

    
495
  if (best != old_best)
496
    {
497
      DBG("krt_learn_async: distributing change\n");
498
      if (best)
499
        krt_learn_announce_update(p, best);
500
      else
501
        krt_learn_announce_delete(p, n);
502
    }
503
}
504

    
505
static void
506
krt_learn_init(struct krt_proto *p)
507
{
508
  if (KRT_CF->learn)
509
    rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL);
510
}
511

    
512
static void
513
krt_dump(struct proto *P)
514
{
515
  struct krt_proto *p = (struct krt_proto *) P;
516

    
517
  if (!KRT_CF->learn)
518
    return;
519
  debug("KRT: Table of inheritable routes\n");
520
  rt_dump(&p->krt_table);
521
}
522

    
523
static void
524
krt_dump_attrs(rte *e)
525
{
526
  debug(" [m=%d,p=%d]", e->u.krt.metric, e->u.krt.proto);
527
}
528

    
529
#endif
530

    
531
/*
532
 *        Routes
533
 */
534

    
535
static void
536
krt_flush_routes(struct krt_proto *p)
537
{
538
  struct rtable *t = p->p.main_channel->table;
539

    
540
  KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
541
  FIB_WALK(&t->fib, net, n)
542
    {
543
      rte *e = n->routes;
544
      if (rte_is_valid(e) && (n->n.flags & KRF_INSTALLED))
545
        {
546
          /* FIXME: this does not work if gw is changed in export filter */
547
          krt_replace_rte(p, e->net, NULL, e, NULL);
548
          n->n.flags &= ~KRF_INSTALLED;
549
        }
550
    }
551
  FIB_WALK_END;
552
}
553

    
554
static struct rte *
555
krt_export_net(struct krt_proto *p, net *net, rte **rt_free, ea_list **tmpa)
556
{
557
  struct channel *c = p->p.main_channel;
558
  struct filter *filter = c->out_filter;
559
  rte *rt;
560

    
561
  if (c->ra_mode == RA_MERGED)
562
    return rt_export_merged(c, net, rt_free, tmpa, krt_filter_lp, 1);
563

    
564
  rt = net->routes;
565
  *rt_free = NULL;
566

    
567
  if (!rte_is_valid(rt))
568
    return NULL;
569

    
570
  if (filter == FILTER_REJECT)
571
    return NULL;
572

    
573
  struct proto *src = rt->attrs->src->proto;
574
  *tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(rt, krt_filter_lp) : NULL;
575

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

    
578
  if (filter == FILTER_ACCEPT)
579
    goto accept;
580

    
581
  if (f_run(filter, &rt, tmpa, krt_filter_lp, FF_FORCE_TMPATTR) > F_ACCEPT)
582
    goto reject;
583

    
584

    
585
accept:
586
  if (rt != net->routes)
587
    *rt_free = rt;
588
  return rt;
589

    
590
reject:
591
  if (rt != net->routes)
592
    rte_free(rt);
593
  return NULL;
594
}
595

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

    
601
  if (ka->dest != ea->dest)
602
    return 0;
603

    
604
  if (ka->dest == RTD_UNICAST)
605
    return nexthop_same(&(ka->nh), &(ea->nh));
606

    
607
  return 1;
608
}
609

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

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

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

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

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

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

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

    
660
  if (net->n.flags & KRF_INSTALLED)
661
    {
662
      rte *new, *rt_free;
663
      ea_list *tmpa;
664

    
665
      new = krt_export_net(p, net, &rt_free, &tmpa);
666

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

    
669
      if (!new)
670
        verdict = KRF_DELETE;
671
      else if ((net->n.flags & KRF_SYNC_ERROR) || !krt_same_dest(e, new))
672
        verdict = KRF_UPDATE;
673
      else
674
        verdict = KRF_SEEN;
675

    
676
      if (rt_free)
677
        rte_free(rt_free);
678

    
679
      lp_flush(krt_filter_lp);
680
    }
681
  else
682
    verdict = KRF_DELETE;
683

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

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

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

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

    
721
      if (verdict == KRF_CREATE || verdict == KRF_UPDATE)
722
        {
723
          /* We have to run export filter to get proper 'new' route */
724
          new = krt_export_net(p, n, &rt_free, &tmpa);
725

    
726
          if (!new)
727
            verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE;
728
          else
729
            tmpa = ea_append(tmpa, new->attrs->eattrs);
730
        }
731
      else
732
        new = NULL;
733

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

    
759
      if (old)
760
        rte_free(old);
761
      if (rt_free)
762
        rte_free(rt_free);
763
      lp_flush(krt_filter_lp);
764
      n->n.flags &= ~KRF_VERDICT_MASK;
765
    }
766
  FIB_WALK_END;
767

    
768
#ifdef KRT_ALLOW_LEARN
769
  if (KRT_CF->learn)
770
    krt_learn_prune(p);
771
#endif
772

    
773
  if (p->ready)
774
    p->initialized = 1;
775
}
776

    
777
void
778
krt_got_route_async(struct krt_proto *p, rte *e, int new)
779
{
780
  net *net = e->net;
781

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

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

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

    
808
/*
809
 *        Periodic scanning
810
 */
811

    
812

    
813
#ifdef CONFIG_ALL_TABLES_AT_ONCE
814

    
815
static timer *krt_scan_timer;
816
static int krt_scan_count;
817

    
818
static void
819
krt_scan(timer *t UNUSED)
820
{
821
  struct krt_proto *p;
822

    
823
  kif_force_scan();
824

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

    
829
  krt_do_scan(NULL);
830

    
831
  void *q;
832
  WALK_LIST(q, krt_proto_list)
833
  {
834
    p = SKIP_BACK(struct krt_proto, krt_node, q);
835
    krt_prune(p);
836
  }
837
}
838

    
839
static void
840
krt_scan_timer_start(struct krt_proto *p)
841
{
842
  if (!krt_scan_count)
843
    krt_scan_timer = tm_new_init(krt_pool, krt_scan, NULL, KRT_CF->scan_time, 0);
844

    
845
  krt_scan_count++;
846

    
847
  tm_start(krt_scan_timer, 1 S);
848
}
849

    
850
static void
851
krt_scan_timer_stop(struct krt_proto *p UNUSED)
852
{
853
  krt_scan_count--;
854

    
855
  if (!krt_scan_count)
856
  {
857
    rfree(krt_scan_timer);
858
    krt_scan_timer = NULL;
859
  }
860
}
861

    
862
static void
863
krt_scan_timer_kick(struct krt_proto *p UNUSED)
864
{
865
  tm_start(krt_scan_timer, 0);
866
}
867

    
868
#else
869

    
870
static void
871
krt_scan(timer *t)
872
{
873
  struct krt_proto *p = t->data;
874

    
875
  kif_force_scan();
876

    
877
  KRT_TRACE(p, D_EVENTS, "Scanning routing table");
878
  krt_do_scan(p);
879
  krt_prune(p);
880
}
881

    
882
static void
883
krt_scan_timer_start(struct krt_proto *p)
884
{
885
  p->scan_timer = tm_new_init(p->p.pool, krt_scan, p, KRT_CF->scan_time, 0);
886
  tm_start(p->scan_timer, 1 S);
887
}
888

    
889
static void
890
krt_scan_timer_stop(struct krt_proto *p)
891
{
892
  tm_stop(p->scan_timer);
893
}
894

    
895
static void
896
krt_scan_timer_kick(struct krt_proto *p)
897
{
898
  tm_start(p->scan_timer, 0);
899
}
900

    
901
#endif
902

    
903

    
904

    
905

    
906
/*
907
 *        Updates
908
 */
909

    
910
static struct ea_list *
911
krt_make_tmp_attrs(rte *rt, struct linpool *pool)
912
{
913
  struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr));
914

    
915
  l->next = NULL;
916
  l->flags = EALF_SORTED;
917
  l->count = 2;
918

    
919
  l->attrs[0].id = EA_KRT_SOURCE;
920
  l->attrs[0].flags = 0;
921
  l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
922
  l->attrs[0].u.data = rt->u.krt.proto;
923

    
924
  l->attrs[1].id = EA_KRT_METRIC;
925
  l->attrs[1].flags = 0;
926
  l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
927
  l->attrs[1].u.data = rt->u.krt.metric;
928

    
929
  return l;
930
}
931

    
932
static void
933
krt_store_tmp_attrs(rte *rt, struct ea_list *attrs)
934
{
935
  /* EA_KRT_SOURCE is read-only */
936
  rt->u.krt.metric = ea_get_int(attrs, EA_KRT_METRIC, 0);
937
}
938

    
939
static int
940
krt_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
941
{
942
  // struct krt_proto *p = (struct krt_proto *) P;
943
  rte *e = *new;
944

    
945
  if (e->attrs->src->proto == P)
946
  {
947
#ifdef CONFIG_SINGLE_ROUTE
948
    /*
949
     * Implicit withdraw - when the imported kernel route becomes the best one,
950
     * we know that the previous one exported to the kernel was already removed,
951
     * but if we processed the update as usual, we would send withdraw to the
952
     * kernel, which would remove the new imported route instead.
953
     *
954
     * We will remove KRT_INSTALLED flag, which stops such withdraw to be
955
     * processed in krt_rt_notify() and krt_replace_rte().
956
     */
957
    if (e == e->net->routes)
958
      e->net->n.flags &= ~KRF_INSTALLED;
959
#endif
960
    return -1;
961
  }
962

    
963
  if (!krt_capable(e))
964
    return -1;
965

    
966
  return 0;
967
}
968

    
969
static void
970
krt_rt_notify(struct proto *P, struct channel *ch UNUSED, net *net,
971
              rte *new, rte *old, struct ea_list *eattrs)
972
{
973
  struct krt_proto *p = (struct krt_proto *) P;
974

    
975
  if (config->shutdown)
976
    return;
977
  if (!(net->n.flags & KRF_INSTALLED))
978
    old = NULL;
979
  if (new)
980
    net->n.flags |= KRF_INSTALLED;
981
  else
982
    net->n.flags &= ~KRF_INSTALLED;
983
  if (p->initialized)                /* Before first scan we don't touch the routes */
984
    krt_replace_rte(p, net, new, old, eattrs);
985
}
986

    
987
static void
988
krt_if_notify(struct proto *P, uint flags, struct iface *iface UNUSED)
989
{
990
  struct krt_proto *p = (struct krt_proto *) P;
991

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

    
1000
  if ((flags & IF_CHANGE_DOWN) && KRT_CF->learn)
1001
    krt_scan_timer_kick(p);
1002
}
1003

    
1004
static void
1005
krt_reload_routes(struct channel *C)
1006
{
1007
  struct krt_proto *p = (void *) C->proto;
1008

    
1009
  /* Although we keep learned routes in krt_table, we rather schedule a scan */
1010

    
1011
  if (KRT_CF->learn)
1012
  {
1013
    p->reload = 1;
1014
    krt_scan_timer_kick(p);
1015
  }
1016
}
1017

    
1018
static void
1019
krt_feed_end(struct channel *C)
1020
{
1021
  struct krt_proto *p = (void *) C->proto;
1022

    
1023
  p->ready = 1;
1024
  krt_scan_timer_kick(p);
1025
}
1026

    
1027

    
1028
static int
1029
krt_rte_same(rte *a, rte *b)
1030
{
1031
  /* src is always KRT_SRC_ALIEN and type is irrelevant */
1032
  return (a->u.krt.proto == b->u.krt.proto) && (a->u.krt.metric == b->u.krt.metric);
1033
}
1034

    
1035

    
1036
/*
1037
 *        Protocol glue
1038
 */
1039

    
1040
struct krt_config *krt_cf;
1041

    
1042
static void
1043
krt_preconfig(struct protocol *P UNUSED, struct config *c)
1044
{
1045
  krt_cf = NULL;
1046
  krt_sys_preconfig(c);
1047
}
1048

    
1049
static void
1050
krt_postconfig(struct proto_config *CF)
1051
{
1052
  struct krt_config *cf = (void *) CF;
1053

    
1054
  if (EMPTY_LIST(CF->channels))
1055
    cf_error("Channel not specified");
1056

    
1057
#ifdef CONFIG_ALL_TABLES_AT_ONCE
1058
  if (krt_cf->scan_time != cf->scan_time)
1059
    cf_error("All kernel syncers must use the same table scan interval");
1060
#endif
1061

    
1062
  struct rtable_config *tab = proto_cf_main_channel(CF)->table;
1063
  if (tab->krt_attached)
1064
    cf_error("Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name);
1065
  tab->krt_attached = CF;
1066

    
1067
  krt_sys_postconfig(cf);
1068
}
1069

    
1070
static struct proto *
1071
krt_init(struct proto_config *CF)
1072
{
1073
  struct krt_proto *p = proto_new(CF);
1074
  // struct krt_config *cf = (void *) CF;
1075

    
1076
  p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF));
1077

    
1078
  p->p.import_control = krt_import_control;
1079
  p->p.rt_notify = krt_rt_notify;
1080
  p->p.if_notify = krt_if_notify;
1081
  p->p.reload_routes = krt_reload_routes;
1082
  p->p.feed_end = krt_feed_end;
1083
  p->p.make_tmp_attrs = krt_make_tmp_attrs;
1084
  p->p.store_tmp_attrs = krt_store_tmp_attrs;
1085
  p->p.rte_same = krt_rte_same;
1086

    
1087
  krt_sys_init(p);
1088
  return &p->p;
1089
}
1090

    
1091
static int
1092
krt_start(struct proto *P)
1093
{
1094
  struct krt_proto *p = (struct krt_proto *) P;
1095

    
1096
  switch (p->p.net_type)
1097
  {
1098
  case NET_IP4:        p->af = AF_INET; break;
1099
  case NET_IP6:        p->af = AF_INET6; break;
1100
#ifdef AF_MPLS
1101
  case NET_MPLS: p->af = AF_MPLS; break;
1102
#endif
1103
  default: log(L_ERR "KRT: Tried to start with strange net type: %d", p->p.net_type); return PS_START; break;
1104
  }
1105

    
1106
  add_tail(&krt_proto_list, &p->krt_node);
1107

    
1108
#ifdef KRT_ALLOW_LEARN
1109
  krt_learn_init(p);
1110
#endif
1111

    
1112
  if (!krt_sys_start(p))
1113
  {
1114
    rem_node(&p->krt_node);
1115
    return PS_START;
1116
  }
1117

    
1118
  krt_scan_timer_start(p);
1119

    
1120
  if (p->p.gr_recovery && KRT_CF->graceful_restart)
1121
    p->p.main_channel->gr_wait = 1;
1122

    
1123
  return PS_UP;
1124
}
1125

    
1126
static int
1127
krt_shutdown(struct proto *P)
1128
{
1129
  struct krt_proto *p = (struct krt_proto *) P;
1130

    
1131
  krt_scan_timer_stop(p);
1132

    
1133
  /* FIXME we should flush routes even when persist during reconfiguration */
1134
  if (p->initialized && !KRT_CF->persist)
1135
    krt_flush_routes(p);
1136

    
1137
  p->ready = 0;
1138
  p->initialized = 0;
1139

    
1140
  if (p->p.proto_state == PS_START)
1141
    return PS_DOWN;
1142

    
1143
  krt_sys_shutdown(p);
1144
  rem_node(&p->krt_node);
1145

    
1146
  return PS_DOWN;
1147
}
1148

    
1149
static int
1150
krt_reconfigure(struct proto *p, struct proto_config *CF)
1151
{
1152
  struct krt_config *o = (void *) p->cf;
1153
  struct krt_config *n = (void *) CF;
1154

    
1155
  if (!proto_configure_channel(p, &p->main_channel, proto_cf_main_channel(CF)))
1156
    return 0;
1157

    
1158
  if (!krt_sys_reconfigure((struct krt_proto *) p, n, o))
1159
    return 0;
1160

    
1161
  /* persist, graceful restart need not be the same */
1162
  return o->scan_time == n->scan_time && o->learn == n->learn && o->devroutes == n->devroutes;
1163
}
1164

    
1165
struct proto_config *
1166
krt_init_config(int class)
1167
{
1168
#ifndef CONFIG_MULTIPLE_TABLES
1169
  if (krt_cf)
1170
    cf_error("Kernel protocol already defined");
1171
#endif
1172

    
1173
  krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, class);
1174
  krt_cf->scan_time = 60 S;
1175

    
1176
  krt_sys_init_config(krt_cf);
1177
  return (struct proto_config *) krt_cf;
1178
}
1179

    
1180
static void
1181
krt_copy_config(struct proto_config *dest, struct proto_config *src)
1182
{
1183
  struct krt_config *d = (struct krt_config *) dest;
1184
  struct krt_config *s = (struct krt_config *) src;
1185

    
1186
  /* Fix sysdep parts */
1187
  krt_sys_copy_config(d, s);
1188
}
1189

    
1190
static int
1191
krt_get_attr(eattr *a, byte *buf, int buflen)
1192
{
1193
  switch (a->id)
1194
  {
1195
  case EA_KRT_SOURCE:
1196
    bsprintf(buf, "source");
1197
    return GA_NAME;
1198

    
1199
  case EA_KRT_METRIC:
1200
    bsprintf(buf, "metric");
1201
    return GA_NAME;
1202

    
1203
  default:
1204
    return krt_sys_get_attr(a, buf, buflen);
1205
  }
1206
}
1207

    
1208

    
1209
struct protocol proto_unix_kernel = {
1210
  .name =                "Kernel",
1211
  .template =                "kernel%d",
1212
  .attr_class =                EAP_KRT,
1213
  .preference =                DEF_PREF_INHERITED,
1214
#ifdef HAVE_MPLS_KERNEL
1215
  .channel_mask =        NB_IP | NB_MPLS,
1216
#else
1217
  .channel_mask =        NB_IP,
1218
#endif
1219
  .proto_size =                sizeof(struct krt_proto),
1220
  .config_size =        sizeof(struct krt_config),
1221
  .preconfig =                krt_preconfig,
1222
  .postconfig =                krt_postconfig,
1223
  .init =                krt_init,
1224
  .start =                krt_start,
1225
  .shutdown =                krt_shutdown,
1226
  .reconfigure =        krt_reconfigure,
1227
  .copy_config =        krt_copy_config,
1228
  .get_attr =                krt_get_attr,
1229
#ifdef KRT_ALLOW_LEARN
1230
  .dump =                krt_dump,
1231
  .dump_attrs =                krt_dump_attrs,
1232
#endif
1233
};