Statistics
| Branch: | Revision:

iof-bird-daemon / nest / proto.c @ 7e95c05d

History | View | Annotate | Download (28.1 KB)

1
/*
2
 *        BIRD -- Protocols
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
#undef LOCAL_DEBUG
10

    
11
#include "nest/bird.h"
12
#include "nest/protocol.h"
13
#include "lib/resource.h"
14
#include "lib/lists.h"
15
#include "lib/event.h"
16
#include "lib/string.h"
17
#include "conf/conf.h"
18
#include "nest/route.h"
19
#include "nest/iface.h"
20
#include "nest/cli.h"
21
#include "filter/filter.h"
22

    
23
pool *proto_pool;
24

    
25
static list protocol_list;
26
static list proto_list;
27

    
28
#define PD(pr, msg, args...) do { if (pr->debug & D_STATES) { log(L_TRACE "%s: " msg, pr->name , ## args); } } while(0)
29

    
30
list active_proto_list;
31
static list inactive_proto_list;
32
static list initial_proto_list;
33
static list flush_proto_list;
34

    
35
static event *proto_flush_event;
36

    
37
static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
38
static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
39

    
40
static void proto_flush_all(void *);
41
static void proto_rethink_goal(struct proto *p);
42
static char *proto_state_name(struct proto *p);
43

    
44
static void
45
proto_enqueue(list *l, struct proto *p)
46
{
47
  add_tail(l, &p->n);
48
  p->last_state_change = now;
49
}
50

    
51
static void
52
proto_relink(struct proto *p)
53
{
54
  list *l = NULL;
55

    
56
  if (p->debug & D_STATES)
57
    {
58
      char *name = proto_state_name(p);
59
      if (name != p->last_state_name_announced)
60
        {
61
          p->last_state_name_announced = name;
62
          PD(p, "State changed to %s", proto_state_name(p));
63
        }
64
    }
65
  else
66
    p->last_state_name_announced = NULL;
67
  rem_node(&p->n);
68
  switch (p->core_state)
69
    {
70
    case FS_HUNGRY:
71
      l = &inactive_proto_list;
72
      break;
73
    case FS_FEEDING:
74
    case FS_HAPPY:
75
      l = &active_proto_list;
76
      break;
77
    case FS_FLUSHING:
78
      l = &flush_proto_list;
79
      break;
80
    default:
81
      ASSERT(0);
82
    }
83
  proto_enqueue(l, p);
84
}
85

    
86
/**
87
 * proto_new - create a new protocol instance
88
 * @c: protocol configuration
89
 * @size: size of protocol data structure (each protocol instance is represented by
90
 * a structure starting with generic part [struct &proto] and continued
91
 * with data specific to the protocol)
92
 *
93
 * When a new configuration has been read in, the core code starts
94
 * initializing all the protocol instances configured by calling their
95
 * init() hooks with the corresponding instance configuration. The initialization
96
 * code of the protocol is expected to create a new instance according to the
97
 * configuration by calling this function and then modifying the default settings
98
 * to values wanted by the protocol.
99
 */
100
void *
101
proto_new(struct proto_config *c, unsigned size)
102
{
103
  struct protocol *pr = c->protocol;
104
  struct proto *p = mb_allocz(proto_pool, size);
105

    
106
  p->cf = c;
107
  p->debug = c->debug;
108
  p->mrtdump = c->mrtdump;
109
  p->name = c->name;
110
  p->preference = c->preference;
111
  p->disabled = c->disabled;
112
  p->proto = pr;
113
  p->table = c->table->table;
114
  p->in_filter = c->in_filter;
115
  p->out_filter = c->out_filter;
116
  p->hash_key = random_u32();
117
  c->proto = p;
118
  return p;
119
}
120

    
121
static void
122
proto_init_instance(struct proto *p)
123
{
124
  /* Here we cannot use p->cf->name since it won't survive reconfiguration */
125
  p->pool = rp_new(proto_pool, p->proto->name);
126
  p->attn = ev_new(p->pool);
127
  p->attn->data = p;
128
  rt_lock_table(p->table);
129
}
130

    
131
/**
132
 * proto_add_announce_hook - connect protocol to a routing table
133
 * @p: protocol instance
134
 * @t: routing table to connect to
135
 *
136
 * This function creates a connection between the protocol instance @p
137
 * and the routing table @t, making the protocol hear all changes in
138
 * the table.
139
 *
140
 * Unless you want to listen to multiple routing tables (as the Pipe
141
 * protocol does), you needn't to worry about this function since the
142
 * connection to the protocol's primary routing table is initialized
143
 * automatically by the core code.
144
 */
145
struct announce_hook *
146
proto_add_announce_hook(struct proto *p, struct rtable *t)
147
{
148
  struct announce_hook *h;
149

    
150
  if (!p->rt_notify)
151
    return NULL;
152
  DBG("Connecting protocol %s to table %s\n", p->name, t->name);
153
  PD(p, "Connected to table %s", t->name);
154
  h = mb_alloc(p->pool, sizeof(struct announce_hook));
155
  h->table = t;
156
  h->proto = p;
157
  h->next = p->ahooks;
158
  p->ahooks = h;
159
  add_tail(&t->hooks, &h->n);
160
  return h;
161
}
162

    
163
static void
164
proto_flush_hooks(struct proto *p)
165
{
166
  struct announce_hook *h;
167

    
168
  for(h=p->ahooks; h; h=h->next)
169
    rem_node(&h->n);
170
  p->ahooks = NULL;
171
}
172

    
173
/**
174
 * proto_config_new - create a new protocol configuration
175
 * @pr: protocol the configuration will belong to
176
 * @size: size of the structure including generic data
177
 *
178
 * Whenever the configuration file says that a new instance
179
 * of a routing protocol should be created, the parser calls
180
 * proto_config_new() to create a configuration entry for this
181
 * instance (a structure staring with the &proto_config header
182
 * containing all the generic items followed by protocol-specific
183
 * ones). Also, the configuration entry gets added to the list
184
 * of protocol instances kept in the configuration.
185
 */
186
void *
187
proto_config_new(struct protocol *pr, unsigned size)
188
{
189
  struct proto_config *c = cfg_allocz(size);
190

    
191
  add_tail(&new_config->protos, &c->n);
192
  c->global = new_config;
193
  c->protocol = pr;
194
  c->name = pr->name;
195
  c->out_filter = FILTER_REJECT;
196
  c->table = c->global->master_rtc;
197
  c->debug = new_config->proto_default_debug;
198
  c->mrtdump = new_config->proto_default_mrtdump;
199
  return c;
200
}
201

    
202
/**
203
 * protos_preconfig - pre-configuration processing
204
 * @c: new configuration
205
 *
206
 * This function calls the preconfig() hooks of all routing
207
 * protocols available to prepare them for reading of the new
208
 * configuration.
209
 */
210
void
211
protos_preconfig(struct config *c)
212
{
213
  struct protocol *p;
214

    
215
  init_list(&c->protos);
216
  DBG("Protocol preconfig:");
217
  WALK_LIST(p, protocol_list)
218
    {
219
      DBG(" %s", p->name);
220
      p->name_counter = 0;
221
      if (p->preconfig)
222
        p->preconfig(p, c);
223
    }
224
  DBG("\n");
225
}
226

    
227
/**
228
 * protos_postconfig - post-configuration processing
229
 * @c: new configuration
230
 *
231
 * This function calls the postconfig() hooks of all protocol
232
 * instances specified in configuration @c.
233
 */
234
void
235
protos_postconfig(struct config *c)
236
{
237
  struct proto_config *x;
238
  struct protocol *p;
239

    
240
  DBG("Protocol postconfig:");
241
  WALK_LIST(x, c->protos)
242
    {
243
      DBG(" %s", x->name);
244
      p = x->protocol;
245
      if (p->postconfig)
246
        p->postconfig(x);
247
    }
248
  DBG("\n");
249
}
250

    
251
static struct proto *
252
proto_init(struct proto_config *c)
253
{
254
  struct protocol *p = c->protocol;
255
  struct proto *q = p->init(c);
256

    
257
  q->proto_state = PS_DOWN;
258
  q->core_state = FS_HUNGRY;
259
  proto_enqueue(&initial_proto_list, q);
260
  add_tail(&proto_list, &q->glob_node);
261
  PD(q, "Initializing%s", q->disabled ? " [disabled]" : "");
262
  return q;
263
}
264

    
265
static int
266
proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type)
267
{
268
  /* If the protocol is DOWN, we just restart it */
269
  if (p->proto_state == PS_DOWN)
270
    return 0;
271

    
272
  /* If there is a too big change in core attributes, ... */
273
  if ((nc->protocol != oc->protocol) ||
274
      (nc->disabled != oc->disabled) ||
275
      (nc->table->table != oc->table->table) ||
276
      (proto_get_router_id(nc) != proto_get_router_id(oc)))
277
    return 0;
278

    
279
  int import_changed = (type != RECONFIG_SOFT) && ! filter_same(nc->in_filter, oc->in_filter);
280
  int export_changed = (type != RECONFIG_SOFT) && ! filter_same(nc->out_filter, oc->out_filter);
281

    
282
  /* We treat a change in preferences by reimporting routes */
283
  if (nc->preference != oc->preference)
284
    import_changed = 1;
285

    
286
  /* If the protocol in not UP, it has no routes and we can ignore such changes */
287
  if (p->proto_state != PS_UP)
288
    import_changed = export_changed = 0;
289

    
290
  /* Without this hook we cannot reload routes and have to restart the protocol */
291
  if (import_changed && ! p->reload_routes)
292
    return 0;
293

    
294
  p->debug = nc->debug;
295
  p->mrtdump = nc->mrtdump;
296

    
297
  /* Execute protocol specific reconfigure hook */
298
  if (! (p->proto->reconfigure && p->proto->reconfigure(p, nc)))
299
    return 0;
300

    
301
  DBG("\t%s: same\n", oc->name);
302
  PD(p, "Reconfigured");
303
  p->cf = nc;
304
  p->name = nc->name;
305
  p->in_filter = nc->in_filter;
306
  p->out_filter = nc->out_filter;
307
  p->preference = nc->preference;
308

    
309
  if (import_changed || export_changed)
310
    log(L_INFO "Reloading protocol %s", p->name);
311

    
312
  if (import_changed && ! p->reload_routes(p))
313
    {
314
      /* Now, the protocol is reconfigured. But route reload failed
315
         and we have to do regular protocol restart. */
316
      log(L_INFO "Restarting protocol %s", p->name);
317
      p->disabled = 1;
318
      proto_rethink_goal(p);
319
      p->disabled = 0;
320
      proto_rethink_goal(p);
321
      return 1;
322
    }
323

    
324
  if (export_changed)
325
    proto_request_feeding(p);
326

    
327
  return 1;
328
}
329

    
330
/**
331
 * protos_commit - commit new protocol configuration
332
 * @new: new configuration
333
 * @old: old configuration or %NULL if it's boot time config
334
 * @force_reconfig: force restart of all protocols (used for example
335
 * when the router ID changes)
336
 * @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
337
 *
338
 * Scan differences between @old and @new configuration and adjust all
339
 * protocol instances to conform to the new configuration.
340
 *
341
 * When a protocol exists in the new configuration, but it doesn't in the
342
 * original one, it's immediately started. When a collision with the other
343
 * running protocol would arise, the new protocol will be temporarily stopped
344
 * by the locking mechanism.
345
 *
346
 * When a protocol exists in the old configuration, but it doesn't in the
347
 * new one, it's shut down and deleted after the shutdown completes.
348
 *
349
 * When a protocol exists in both configurations, the core decides
350
 * whether it's possible to reconfigure it dynamically - it checks all
351
 * the core properties of the protocol (changes in filters are ignored
352
 * if type is RECONFIG_SOFT) and if they match, it asks the
353
 * reconfigure() hook of the protocol to see if the protocol is able
354
 * to switch to the new configuration.  If it isn't possible, the
355
 * protocol is shut down and a new instance is started with the new
356
 * configuration after the shutdown is completed.
357
 */
358
void
359
protos_commit(struct config *new, struct config *old, int force_reconfig, int type)
360
{
361
  struct proto_config *oc, *nc;
362
  struct proto *p, *n;
363

    
364
  DBG("protos_commit:\n");
365
  if (old)
366
    {
367
      WALK_LIST(oc, old->protos)
368
        {
369
          struct proto *p = oc->proto;
370
          struct symbol *sym = cf_find_symbol(oc->name);
371
          if (sym && sym->class == SYM_PROTO && !new->shutdown)
372
            {
373
              /* Found match, let's check if we can smoothly switch to new configuration */
374
              /* No need to check description */
375
              nc = sym->def;
376
              nc->proto = p;
377

    
378
              /* We will try to reconfigure protocol p */
379
              if (! force_reconfig && proto_reconfigure(p, oc, nc, type))
380
                continue;
381

    
382
              /* Unsuccessful, we will restart it */
383
              if (!p->disabled && !nc->disabled)
384
                log(L_INFO "Restarting protocol %s", p->name);
385
              else if (p->disabled && !nc->disabled)
386
                log(L_INFO "Enabling protocol %s", p->name);
387
              else if (!p->disabled && nc->disabled)
388
                log(L_INFO "Disabling protocol %s", p->name);
389

    
390
              PD(p, "Restarting");
391
              p->cf_new = nc;
392
            }
393
          else
394
            {
395
              if (!shutting_down)
396
                log(L_INFO "Removing protocol %s", p->name);
397
              PD(p, "Unconfigured");
398
              p->cf_new = NULL;
399
            }
400
          p->reconfiguring = 1;
401
          config_add_obstacle(old);
402
          proto_rethink_goal(p);
403
        }
404
    }
405

    
406
  WALK_LIST(nc, new->protos)
407
    if (!nc->proto)
408
      {
409
        if (old_config)                /* Not a first-time configuration */
410
          log(L_INFO "Adding protocol %s", nc->name);
411
        proto_init(nc);
412
      }
413
  DBG("\tdone\n");
414

    
415
  DBG("Protocol start\n");
416
  WALK_LIST_DELSAFE(p, n, initial_proto_list)
417
    proto_rethink_goal(p);
418
}
419

    
420
static void
421
proto_rethink_goal(struct proto *p)
422
{
423
  struct protocol *q;
424

    
425
  if (p->reconfiguring && p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
426
    {
427
      struct proto_config *nc = p->cf_new;
428
      DBG("%s has shut down for reconfiguration\n", p->name);
429
      config_del_obstacle(p->cf->global);
430
      rem_node(&p->n);
431
      rem_node(&p->glob_node);
432
      mb_free(p);
433
      if (!nc)
434
        return;
435
      p = proto_init(nc);
436
    }
437

    
438
  /* Determine what state we want to reach */
439
  if (p->disabled || p->reconfiguring)
440
    {
441
      p->core_goal = FS_HUNGRY;
442
      if (p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
443
        return;
444
    }
445
  else
446
    {
447
      p->core_goal = FS_HAPPY;
448
      if (p->core_state == FS_HAPPY && p->proto_state == PS_UP)
449
        return;
450
    }
451

    
452
  q = p->proto;
453
  if (p->core_goal == FS_HAPPY)                /* Going up */
454
    {
455
      if (p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
456
        {
457
          DBG("Kicking %s up\n", p->name);
458
          PD(p, "Starting");
459
          proto_init_instance(p);
460
          proto_notify_state(p, (q->start ? q->start(p) : PS_UP));
461
        }
462
    }
463
  else                                         /* Going down */
464
    {
465
      if (p->proto_state == PS_START || p->proto_state == PS_UP)
466
        {
467
          DBG("Kicking %s down\n", p->name);
468
          PD(p, "Shutting down");
469
          proto_notify_state(p, (q->shutdown ? q->shutdown(p) : PS_DOWN));
470
        }
471
    }
472
}
473

    
474
/**
475
 * protos_dump_all - dump status of all protocols
476
 *
477
 * This function dumps status of all existing protocol instances to the
478
 * debug output. It involves printing of general status information
479
 * such as protocol states, its position on the protocol lists
480
 * and also calling of a dump() hook of the protocol to print
481
 * the internals.
482
 */
483
void
484
protos_dump_all(void)
485
{
486
  struct proto *p;
487

    
488
  debug("Protocols:\n");
489

    
490
  WALK_LIST(p, active_proto_list)
491
    {
492
      debug("  protocol %s state %s/%s\n", p->name,
493
            p_states[p->proto_state], c_states[p->core_state]);
494
      if (p->in_filter)
495
        debug("\tInput filter: %s\n", filter_name(p->in_filter));
496
      if (p->out_filter != FILTER_REJECT)
497
        debug("\tOutput filter: %s\n", filter_name(p->out_filter));
498
      if (p->disabled)
499
        debug("\tDISABLED\n");
500
      else if (p->proto->dump)
501
        p->proto->dump(p);
502
    }
503
  WALK_LIST(p, inactive_proto_list)
504
    debug("  inactive %s: state %s/%s\n", p->name, p_states[p->proto_state], c_states[p->core_state]);
505
  WALK_LIST(p, initial_proto_list)
506
    debug("  initial %s\n", p->name);
507
  WALK_LIST(p, flush_proto_list)
508
    debug("  flushing %s\n", p->name);
509
}
510

    
511
/**
512
 * proto_build - make a single protocol available
513
 * @p: the protocol
514
 *
515
 * After the platform specific initialization code uses protos_build()
516
 * to add all the standard protocols, it should call proto_build() for
517
 * all platform specific protocols to inform the core that they exist.
518
 */
519
void
520
proto_build(struct protocol *p)
521
{
522
  add_tail(&protocol_list, &p->n);
523
  if (p->attr_class)
524
    {
525
      ASSERT(!attr_class_to_protocol[p->attr_class]);
526
      attr_class_to_protocol[p->attr_class] = p;
527
    }
528
}
529

    
530
/**
531
 * protos_build - build a protocol list
532
 *
533
 * This function is called during BIRD startup to insert
534
 * all standard protocols to the global protocol list. Insertion
535
 * of platform specific protocols (such as the kernel syncer)
536
 * is in the domain of competence of the platform dependent
537
 * startup code.
538
 */
539
void
540
protos_build(void)
541
{
542
  init_list(&protocol_list);
543
  init_list(&proto_list);
544
  init_list(&active_proto_list);
545
  init_list(&inactive_proto_list);
546
  init_list(&initial_proto_list);
547
  init_list(&flush_proto_list);
548
  proto_build(&proto_device);
549
#ifdef CONFIG_RIP
550
  proto_build(&proto_rip);
551
#endif
552
#ifdef CONFIG_STATIC
553
  proto_build(&proto_static);
554
#endif
555
#ifdef CONFIG_OSPF
556
  proto_build(&proto_ospf);
557
#endif
558
#ifdef CONFIG_PIPE
559
  proto_build(&proto_pipe);
560
#endif
561
#ifdef CONFIG_BGP
562
  proto_build(&proto_bgp);
563
#endif
564
  proto_pool = rp_new(&root_pool, "Protocols");
565
  proto_flush_event = ev_new(proto_pool);
566
  proto_flush_event->hook = proto_flush_all;
567
}
568

    
569
static void
570
proto_fell_down(struct proto *p)
571
{
572
  DBG("Protocol %s down\n", p->name);
573

    
574
  if (p->stats.imp_routes != 0)
575
    log(L_ERR "Protocol %s is down but still has %d routes", p->name, p->stats.imp_routes);
576

    
577
  bzero(&p->stats, sizeof(struct proto_stats));
578
  rt_unlock_table(p->table);
579

    
580
  if (p->proto->cleanup)
581
    p->proto->cleanup(p);
582

    
583
  proto_rethink_goal(p);
584
}
585

    
586
static void
587
proto_feed_more(void *P)
588
{
589
  struct proto *p = P;
590

    
591
  if (p->core_state != FS_FEEDING)
592
    return;
593

    
594
  DBG("Feeding protocol %s continued\n", p->name);
595
  if (rt_feed_baby(p))
596
    {
597
      p->core_state = FS_HAPPY;
598
      proto_relink(p);
599
      DBG("Protocol %s up and running\n", p->name);
600
    }
601
  else
602
    {
603
      p->attn->hook = proto_feed_more;
604
      ev_schedule(p->attn);                /* Will continue later... */
605
    }
606
}
607

    
608
static void
609
proto_feed_initial(void *P)
610
{
611
  struct proto *p = P;
612

    
613
  if (p->core_state != FS_FEEDING)
614
    return;
615

    
616
  DBG("Feeding protocol %s\n", p->name);
617
  proto_add_announce_hook(p, p->table);
618
  if_feed_baby(p);
619
  proto_feed_more(P);
620
}
621

    
622
static void
623
proto_schedule_flush(struct proto *p)
624
{
625
  /* Need to abort feeding */
626
  if (p->core_state == FS_FEEDING)
627
    rt_feed_baby_abort(p);
628

    
629
  DBG("%s: Scheduling flush\n", p->name);
630
  p->core_state = FS_FLUSHING;
631
  proto_relink(p);
632
  proto_flush_hooks(p);
633
  ev_schedule(proto_flush_event);
634
}
635

    
636
static void
637
proto_schedule_feed(struct proto *p, int initial)
638
{
639
  DBG("%s: Scheduling meal\n", p->name);
640
  p->core_state = FS_FEEDING;
641
  p->refeeding = !initial;
642

    
643
  /* Hack: reset exp_routes during refeed, and do not decrease it later */
644
  if (!initial)
645
    p->stats.exp_routes = 0;
646

    
647
  proto_relink(p);
648
  p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
649
  ev_schedule(p->attn);
650
}
651

    
652
/**
653
 * proto_request_feeding - request feeding routes to the protocol
654
 * @p: given protocol 
655
 *
656
 * Sometimes it is needed to send again all routes to the
657
 * protocol. This is called feeding and can be requested by this
658
 * function. This would cause protocol core state transition
659
 * to FS_FEEDING (during feeding) and when completed, it will
660
 * switch back to FS_HAPPY. This function can be called even
661
 * when feeding is already running, in that case it is restarted.
662
 */
663
void
664
proto_request_feeding(struct proto *p)
665
{
666
  ASSERT(p->proto_state == PS_UP);
667

    
668
  /* If we are already feeding, we want to restart it */
669
  if (p->core_state == FS_FEEDING)
670
    {
671
      /* Unless feeding is in initial state */
672
      if (p->attn->hook == proto_feed_initial)
673
        return;
674

    
675
      rt_feed_baby_abort(p);
676
    }
677

    
678
  proto_schedule_feed(p, 0);
679
}
680

    
681
/**
682
 * proto_notify_state - notify core about protocol state change
683
 * @p: protocol the state of which has changed
684
 * @ps: the new status
685
 *
686
 * Whenever a state of a protocol changes due to some event internal
687
 * to the protocol (i.e., not inside a start() or shutdown() hook),
688
 * it should immediately notify the core about the change by calling
689
 * proto_notify_state() which will write the new state to the &proto
690
 * structure and take all the actions necessary to adapt to the new
691
 * state. State change to PS_DOWN immediately frees resources of protocol
692
 * and might execute start callback of protocol; therefore,
693
 * it should be used at tail positions of protocol callbacks.
694
 */
695
void
696
proto_notify_state(struct proto *p, unsigned ps)
697
{
698
  unsigned ops = p->proto_state;
699
  unsigned cs = p->core_state;
700

    
701
  DBG("%s reporting state transition %s/%s -> */%s\n", p->name, c_states[cs], p_states[ops], p_states[ps]);
702
  if (ops == ps)
703
    return;
704

    
705
  p->proto_state = ps;
706

    
707
  switch (ps)
708
    {
709
    case PS_DOWN:
710
      if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
711
        proto_schedule_flush(p);
712

    
713
      neigh_prune(); // FIXME convert neighbors to resource?
714
      rfree(p->pool);
715
      p->pool = NULL;
716

    
717
      if (cs == FS_HUNGRY)                /* Shutdown finished */
718
        {
719
          proto_fell_down(p);
720
          return;                        /* The protocol might have ceased to exist */
721
        }
722
      break;
723
    case PS_START:
724
      ASSERT(ops == PS_DOWN);
725
      ASSERT(cs == FS_HUNGRY);
726
      break;
727
    case PS_UP:
728
      ASSERT(ops == PS_DOWN || ops == PS_START);
729
      ASSERT(cs == FS_HUNGRY);
730
      proto_schedule_feed(p, 1);
731
      break;
732
    case PS_STOP:
733
      if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
734
        proto_schedule_flush(p);
735
      break;
736
    default:
737
      bug("Invalid state transition for %s from %s/%s to */%s", p->name, c_states[cs], p_states[ops], p_states[ps]);
738
    }
739
}
740

    
741
extern struct protocol proto_unix_iface;
742

    
743
static void
744
proto_flush_all(void *unused UNUSED)
745
{
746
  struct proto *p;
747

    
748
  rt_prune_all();
749
  while ((p = HEAD(flush_proto_list))->n.next)
750
    {
751
      /* This will flush interfaces in the same manner
752
         like rt_prune_all() flushes routes */
753
      if (p->proto == &proto_unix_iface)
754
        if_flush_ifaces(p);
755

    
756
      DBG("Flushing protocol %s\n", p->name);
757
      p->core_state = FS_HUNGRY;
758
      proto_relink(p);
759
      if (p->proto_state == PS_DOWN)
760
        proto_fell_down(p);
761
    }
762
}
763

    
764
/*
765
 *  CLI Commands
766
 */
767

    
768
static char *
769
proto_state_name(struct proto *p)
770
{
771
#define P(x,y) ((x << 4) | y)
772
  switch (P(p->proto_state, p->core_state))
773
    {
774
    case P(PS_DOWN, FS_HUNGRY):                return "down";
775
    case P(PS_START, FS_HUNGRY):        return "start";
776
    case P(PS_UP, FS_HUNGRY):
777
    case P(PS_UP, FS_FEEDING):                return "feed";
778
    case P(PS_STOP, FS_HUNGRY):                return "stop";
779
    case P(PS_UP, FS_HAPPY):                return "up";
780
    case P(PS_STOP, FS_FLUSHING):
781
    case P(PS_DOWN, FS_FLUSHING):        return "flush";
782
    default:                              return "???";
783
    }
784
#undef P
785
}
786

    
787
static void
788
proto_do_show_stats(struct proto *p)
789
{
790
  struct proto_stats *s = &p->stats;
791
  cli_msg(-1006, "  Routes:         %u imported, %u exported, %u preferred", 
792
          s->imp_routes, s->exp_routes, s->pref_routes);
793
  cli_msg(-1006, "  Route change stats:     received   rejected   filtered    ignored   accepted");
794
  cli_msg(-1006, "    Import updates:     %10u %10u %10u %10u %10u",
795
          s->imp_updates_received, s->imp_updates_invalid,
796
          s->imp_updates_filtered, s->imp_updates_ignored,
797
          s->imp_updates_accepted);
798
  cli_msg(-1006, "    Import withdraws:   %10u %10u        --- %10u %10u",
799
          s->imp_withdraws_received, s->imp_withdraws_invalid,
800
          s->imp_withdraws_ignored, s->imp_withdraws_accepted);
801
  cli_msg(-1006, "    Export updates:     %10u %10u %10u        --- %10u",
802
          s->exp_updates_received, s->exp_updates_rejected,
803
          s->exp_updates_filtered, s->exp_updates_accepted);
804
  cli_msg(-1006, "    Export withdraws:   %10u        ---        ---        --- %10u",
805
          s->exp_withdraws_received, s->exp_withdraws_accepted);
806
}
807

    
808
#ifdef CONFIG_PIPE
809
static void
810
proto_do_show_pipe_stats(struct proto *p)
811
{
812
  struct proto_stats *s1 = &p->stats;
813
  struct proto_stats *s2 = pipe_get_peer_stats(p);
814

    
815
  /*
816
   * Pipe stats (as anything related to pipes) are a bit tricky. There
817
   * are two sets of stats - s1 for routes going from the primary
818
   * routing table to the secondary routing table ('exported' from the
819
   * user point of view) and s2 for routes going in the other
820
   * direction ('imported' from the user point of view).
821
   *
822
   * Each route going through a pipe is, technically, first exported
823
   * to the pipe and then imported from that pipe and such operations
824
   * are counted in one set of stats according to the direction of the
825
   * route propagation. Filtering is done just in the first part
826
   * (export). Therefore, we compose stats for one directon for one
827
   * user direction from both import and export stats, skipping
828
   * immediate and irrelevant steps (exp_updates_accepted,
829
   * imp_updates_received, imp_updates_filtered, ...)
830
   */
831

    
832
  cli_msg(-1006, "  Routes:         %u imported, %u exported", 
833
          s2->imp_routes, s1->imp_routes);
834
  cli_msg(-1006, "  Route change stats:     received   rejected   filtered    ignored   accepted");
835
  cli_msg(-1006, "    Import updates:     %10u %10u %10u %10u %10u",
836
          s2->exp_updates_received, s2->exp_updates_rejected + s2->imp_updates_invalid,
837
          s2->exp_updates_filtered, s2->imp_updates_ignored, s2->imp_updates_accepted);
838
  cli_msg(-1006, "    Import withdraws:   %10u %10u        --- %10u %10u",
839
          s2->exp_withdraws_received, s2->imp_withdraws_invalid,
840
          s2->imp_withdraws_ignored, s2->imp_withdraws_accepted);
841
  cli_msg(-1006, "    Export updates:     %10u %10u %10u %10u %10u",
842
          s1->exp_updates_received, s1->exp_updates_rejected + s1->imp_updates_invalid,
843
          s1->exp_updates_filtered, s1->imp_updates_ignored, s1->imp_updates_accepted);
844
  cli_msg(-1006, "    Export withdraws:   %10u %10u        --- %10u %10u",
845
          s1->exp_withdraws_received, s1->imp_withdraws_invalid,
846
          s1->imp_withdraws_ignored, s1->imp_withdraws_accepted);
847
}
848
#endif
849

    
850
void
851
proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
852
{
853
  byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
854

    
855
  /* First protocol - show header */
856
  if (!cnt)
857
    cli_msg(-2002, "name     proto    table    state  since       info");
858

    
859
  buf[0] = 0;
860
  if (p->proto->get_status)
861
    p->proto->get_status(p, buf);
862
  tm_format_datetime(tbuf, &config->tf_proto, p->last_state_change);
863
  cli_msg(-1002, "%-8s %-8s %-8s %-5s  %-10s  %s",
864
          p->name,
865
          p->proto->name,
866
          p->table->name,
867
          proto_state_name(p),
868
          tbuf,
869
          buf);
870
  if (verbose)
871
    {
872
      if (p->cf->dsc)
873
        cli_msg(-1006, "  Description:    %s", p->cf->dsc);
874
      if (p->cf->router_id)
875
        cli_msg(-1006, "  Router ID:      %R", p->cf->router_id);
876
      cli_msg(-1006, "  Preference:     %d", p->preference);
877
      cli_msg(-1006, "  Input filter:   %s", filter_name(p->in_filter));
878
      cli_msg(-1006, "  Output filter:  %s", filter_name(p->out_filter));
879

    
880
      if (p->proto_state != PS_DOWN)
881
        {
882
#ifdef CONFIG_PIPE
883
          if (proto_is_pipe(p))
884
            proto_do_show_pipe_stats(p);
885
          else
886
#endif
887
            proto_do_show_stats(p);
888
        }
889

    
890
      if (p->proto->show_proto_info)
891
        p->proto->show_proto_info(p);
892

    
893
      cli_msg(-1006, "");
894
    }
895
}
896

    
897
void
898
proto_cmd_disable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
899
{
900
  if (p->disabled)
901
    {
902
      cli_msg(-8, "%s: already disabled", p->name);
903
      return;
904
    }
905

    
906
  log(L_INFO "Disabling protocol %s", p->name);
907
  p->disabled = 1;
908
  proto_rethink_goal(p);
909
  cli_msg(-9, "%s: disabled", p->name);
910
}
911

    
912
void
913
proto_cmd_enable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
914
{
915
  if (!p->disabled)
916
    {
917
      cli_msg(-10, "%s: already enabled", p->name);
918
      return;
919
    }
920

    
921
  log(L_INFO "Enabling protocol %s", p->name);
922
  p->disabled = 0;
923
  proto_rethink_goal(p);
924
  cli_msg(-11, "%s: enabled", p->name);
925
}
926

    
927
void
928
proto_cmd_restart(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
929
{
930
  if (p->disabled)
931
    {
932
      cli_msg(-8, "%s: already disabled", p->name);
933
      return;
934
    }
935

    
936
  log(L_INFO "Restarting protocol %s", p->name);
937
  p->disabled = 1;
938
  proto_rethink_goal(p);
939
  p->disabled = 0;
940
  proto_rethink_goal(p);
941
  cli_msg(-12, "%s: restarted", p->name);
942
}
943

    
944
void
945
proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED)
946
{
947
  if (p->disabled)
948
    {
949
      cli_msg(-8, "%s: already disabled", p->name);
950
      return;
951
    }
952

    
953
  /* If the protocol in not UP, it has no routes */
954
  if (p->proto_state != PS_UP)
955
    return;
956

    
957
  log(L_INFO "Reloading protocol %s", p->name);
958

    
959
  /* re-importing routes */
960
  if (dir != CMD_RELOAD_OUT)
961
    if (! (p->reload_routes && p->reload_routes(p)))
962
      {
963
        cli_msg(-8006, "%s: reload failed", p->name);
964
        return;
965
      }
966
                 
967
  /* re-exporting routes */
968
  if (dir != CMD_RELOAD_IN)
969
    proto_request_feeding(p);
970

    
971
  cli_msg(-15, "%s: reloading", p->name);
972
}
973

    
974
void
975
proto_cmd_debug(struct proto *p, unsigned int mask, int cnt UNUSED)
976
{
977
  p->debug = mask;
978
}
979

    
980
void
981
proto_cmd_mrtdump(struct proto *p, unsigned int mask, int cnt UNUSED)
982
{
983
  p->mrtdump = mask;
984
}
985

    
986
static void
987
proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg)
988
{
989
  if (s->class != SYM_PROTO)
990
    {
991
      cli_msg(9002, "%s is not a protocol", s->name);
992
      return;
993
    }
994

    
995
  cmd(((struct proto_config *)s->def)->proto, arg, 0);
996
  cli_msg(0, "");
997
}
998

    
999
static void
1000
proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg)
1001
{
1002
  int cnt = 0;
1003

    
1004
  node *nn;
1005
  WALK_LIST(nn, proto_list)
1006
    {
1007
      struct proto *p = SKIP_BACK(struct proto, glob_node, nn);
1008

    
1009
      if (!patt || patmatch(patt, p->name))
1010
        cmd(p, arg, cnt++);
1011
    }
1012

    
1013
  if (!cnt)
1014
    cli_msg(8003, "No protocols match");
1015
  else
1016
    cli_msg(0, "");
1017
}
1018

    
1019
void
1020
proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int),
1021
                int restricted, unsigned int arg)
1022
{
1023
  if (restricted && cli_access_restricted())
1024
    return;
1025

    
1026
  if (ps.patt)
1027
    proto_apply_cmd_patt(ps.ptr, cmd, arg);
1028
  else
1029
    proto_apply_cmd_symbol(ps.ptr, cmd, arg);
1030
}
1031

    
1032
struct proto *
1033
proto_get_named(struct symbol *sym, struct protocol *pr)
1034
{
1035
  struct proto *p, *q;
1036

    
1037
  if (sym)
1038
    {
1039
      if (sym->class != SYM_PROTO)
1040
        cf_error("%s: Not a protocol", sym->name);
1041
      p = ((struct proto_config *)sym->def)->proto;
1042
      if (!p || p->proto != pr)
1043
        cf_error("%s: Not a %s protocol", sym->name, pr->name);
1044
    }
1045
  else
1046
    {
1047
      p = NULL;
1048
      WALK_LIST(q, active_proto_list)
1049
        if (q->proto == pr)
1050
          {
1051
            if (p)
1052
              cf_error("There are multiple %s protocols running", pr->name);
1053
            p = q;
1054
          }
1055
      if (!p)
1056
        cf_error("There is no %s protocol running", pr->name);
1057
    }
1058
  return p;
1059
}