Statistics
| Branch: | Revision:

iof-bird-daemon / nest / proto.c @ e81b440f

History | View | Annotate | Download (27.8 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
static 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->min_scope = SCOPE_SITE;
117
  p->hash_key = random_u32();
118
  c->proto = p;
119
  return p;
120
}
121

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
328
  return 1;
329
}
330

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
581
#ifdef CONFIG_PIPE
582
  if (proto_is_pipe(p))
583
    rt_unlock_table(pipe_get_peer_table(p));
584
#endif
585

    
586
  proto_rethink_goal(p);
587
}
588

    
589
static void
590
proto_feed_more(void *P)
591
{
592
  struct proto *p = P;
593

    
594
  if (p->core_state != FS_FEEDING)
595
    return;
596

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

    
611
static void
612
proto_feed_initial(void *P)
613
{
614
  struct proto *p = P;
615

    
616
  if (p->core_state != FS_FEEDING)
617
    return;
618

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

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

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

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

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

    
650
  proto_relink(p);
651
  p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
652
  ev_schedule(p->attn);
653
}
654

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

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

    
678
      rt_feed_baby_abort(p);
679
    }
680

    
681
  proto_schedule_feed(p, 0);
682
}
683

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

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

    
708
  p->proto_state = ps;
709

    
710
  switch (ps)
711
    {
712
    case PS_DOWN:
713
      if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
714
        proto_schedule_flush(p);
715

    
716
      neigh_prune(); // FIXME convert neighbors to resource?
717
      rfree(p->pool);
718
      p->pool = NULL;
719

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

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

    
749
  rt_prune_all();
750
  while ((p = HEAD(flush_proto_list))->n.next)
751
    {
752
      DBG("Flushing protocol %s\n", p->name);
753
      p->core_state = FS_HUNGRY;
754
      proto_relink(p);
755
      if (p->proto_state == PS_DOWN)
756
        proto_fell_down(p);
757
    }
758
}
759

    
760
/*
761
 *  CLI Commands
762
 */
763

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

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

    
804
static void
805
proto_do_show_pipe_stats(struct proto *p)
806
{
807
  struct proto_stats *s1 = &p->stats;
808
  struct proto_stats *s2 = pipe_get_peer_stats(p);
809

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

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

    
844
void
845
proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
846
{
847
  byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
848

    
849
  /* First protocol - show header */
850
  if (!cnt)
851
    cli_msg(-2002, "name     proto    table    state  since       info");
852

    
853
  buf[0] = 0;
854
  if (p->proto->get_status)
855
    p->proto->get_status(p, buf);
856
  tm_format_datetime(tbuf, &config->tf_proto, p->last_state_change);
857
  cli_msg(-1002, "%-8s %-8s %-8s %-5s  %-10s  %s",
858
          p->name,
859
          p->proto->name,
860
          p->table->name,
861
          proto_state_name(p),
862
          tbuf,
863
          buf);
864
  if (verbose)
865
    {
866
      if (p->cf->dsc)
867
        cli_msg(-1006, "  Description:    %s", p->cf->dsc);
868
      cli_msg(-1006, "  Preference:     %d", p->preference);
869
      cli_msg(-1006, "  Input filter:   %s", filter_name(p->in_filter));
870
      cli_msg(-1006, "  Output filter:  %s", filter_name(p->out_filter));
871

    
872
      if (p->proto_state != PS_DOWN)
873
        {
874
#ifdef CONFIG_PIPE
875
          if (proto_is_pipe(p))
876
            proto_do_show_pipe_stats(p);
877
          else
878
#endif
879
            proto_do_show_stats(p);
880
        }
881

    
882
      cli_msg(-1006, "");
883
    }
884
}
885

    
886
void
887
proto_cmd_disable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
888
{
889
  if (p->disabled)
890
    {
891
      cli_msg(-8, "%s: already disabled", p->name);
892
      return;
893
    }
894

    
895
  log(L_INFO "Disabling protocol %s", p->name);
896
  p->disabled = 1;
897
  proto_rethink_goal(p);
898
  cli_msg(-9, "%s: disabled", p->name);
899
}
900

    
901
void
902
proto_cmd_enable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
903
{
904
  if (!p->disabled)
905
    {
906
      cli_msg(-10, "%s: already enabled", p->name);
907
      return;
908
    }
909

    
910
  log(L_INFO "Enabling protocol %s", p->name);
911
  p->disabled = 0;
912
  proto_rethink_goal(p);
913
  cli_msg(-11, "%s: enabled", p->name);
914
}
915

    
916
void
917
proto_cmd_restart(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
918
{
919
  if (p->disabled)
920
    {
921
      cli_msg(-8, "%s: already disabled", p->name);
922
      return;
923
    }
924

    
925
  log(L_INFO "Restarting protocol %s", p->name);
926
  p->disabled = 1;
927
  proto_rethink_goal(p);
928
  p->disabled = 0;
929
  proto_rethink_goal(p);
930
  cli_msg(-12, "%s: restarted", p->name);
931
}
932

    
933
void
934
proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED)
935
{
936
  if (p->disabled)
937
    {
938
      cli_msg(-8, "%s: already disabled", p->name);
939
      return;
940
    }
941

    
942
  /* If the protocol in not UP, it has no routes */
943
  if (p->proto_state != PS_UP)
944
    return;
945

    
946
  log(L_INFO "Reloading protocol %s", p->name);
947

    
948
  /* re-importing routes */
949
  if (dir != CMD_RELOAD_OUT)
950
    if (! (p->reload_routes && p->reload_routes(p)))
951
      {
952
        cli_msg(-8006, "%s: reload failed", p->name);
953
        return;
954
      }
955
                 
956
  /* re-exporting routes */
957
  if (dir != CMD_RELOAD_IN)
958
    proto_request_feeding(p);
959

    
960
  cli_msg(-15, "%s: reloading", p->name);
961
}
962

    
963
void
964
proto_cmd_debug(struct proto *p, unsigned int mask, int cnt UNUSED)
965
{
966
  p->debug = mask;
967
}
968

    
969
void
970
proto_cmd_mrtdump(struct proto *p, unsigned int mask, int cnt UNUSED)
971
{
972
  p->mrtdump = mask;
973
}
974

    
975
static void
976
proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg)
977
{
978
  if (s->class != SYM_PROTO)
979
    {
980
      cli_msg(9002, "%s is not a protocol", s->name);
981
      return;
982
    }
983

    
984
  cmd(((struct proto_config *)s->def)->proto, arg, 0);
985
  cli_msg(0, "");
986
}
987

    
988
static void
989
proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg)
990
{
991
  int cnt = 0;
992

    
993
  node *nn;
994
  WALK_LIST(nn, proto_list)
995
    {
996
      struct proto *p = SKIP_BACK(struct proto, glob_node, nn);
997

    
998
      if (!patt || patmatch(patt, p->name))
999
        cmd(p, arg, cnt++);
1000
    }
1001

    
1002
  if (!cnt)
1003
    cli_msg(8003, "No protocols match");
1004
  else
1005
    cli_msg(0, "");
1006
}
1007

    
1008
void
1009
proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int),
1010
                int restricted, unsigned int arg)
1011
{
1012
  if (restricted && cli_access_restricted())
1013
    return;
1014

    
1015
  if (ps.patt)
1016
    proto_apply_cmd_patt(ps.ptr, cmd, arg);
1017
  else
1018
    proto_apply_cmd_symbol(ps.ptr, cmd, arg);
1019
}
1020

    
1021
struct proto *
1022
proto_get_named(struct symbol *sym, struct protocol *pr)
1023
{
1024
  struct proto *p, *q;
1025

    
1026
  if (sym)
1027
    {
1028
      if (sym->class != SYM_PROTO)
1029
        cf_error("%s: Not a protocol", sym->name);
1030
      p = ((struct proto_config *)sym->def)->proto;
1031
      if (!p || p->proto != pr)
1032
        cf_error("%s: Not a %s protocol", sym->name, pr->name);
1033
    }
1034
  else
1035
    {
1036
      p = NULL;
1037
      WALK_LIST(q, active_proto_list)
1038
        if (q->proto == pr)
1039
          {
1040
            if (p)
1041
              cf_error("There are multiple %s protocols running", pr->name);
1042
            p = q;
1043
          }
1044
      if (!p)
1045
        cf_error("There is no %s protocol running", pr->name);
1046
    }
1047
  return p;
1048
}