Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (28.1 KB)

1 2326b001 Martin Mares
/*
2
 *        BIRD -- Protocols
3
 *
4 50fe90ed Martin Mares
 *        (c) 1998--2000 Martin Mares <mj@ucw.cz>
5 2326b001 Martin Mares
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8
9 6b9fa320 Martin Mares
#undef LOCAL_DEBUG
10 7f4a3988 Martin Mares
11 2326b001 Martin Mares
#include "nest/bird.h"
12
#include "nest/protocol.h"
13
#include "lib/resource.h"
14
#include "lib/lists.h"
15 67bd949a Martin Mares
#include "lib/event.h"
16 f14a4bec Martin Mares
#include "lib/string.h"
17 fe7cec12 Martin Mares
#include "conf/conf.h"
18 47b79306 Martin Mares
#include "nest/route.h"
19
#include "nest/iface.h"
20 ae97b946 Martin Mares
#include "nest/cli.h"
21 529c4149 Martin Mares
#include "filter/filter.h"
22 2326b001 Martin Mares
23 acb60628 Ondrej Zajicek
pool *proto_pool;
24 67bd949a Martin Mares
25 3991d84e Martin Mares
static list protocol_list;
26 f14a4bec Martin Mares
static list proto_list;
27 67bd949a Martin Mares
28 839380d7 Martin Mares
#define PD(pr, msg, args...) do { if (pr->debug & D_STATES) { log(L_TRACE "%s: " msg, pr->name , ## args); } } while(0)
29
30 f14a4bec Martin Mares
list active_proto_list;
31 67bd949a Martin Mares
static list inactive_proto_list;
32
static list initial_proto_list;
33 1a54b1c6 Martin Mares
static list flush_proto_list;
34
35
static event *proto_flush_event;
36 67bd949a Martin Mares
37
static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
38
static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
39
40 8f6accb5 Martin Mares
static void proto_flush_all(void *);
41 50fe90ed Martin Mares
static void proto_rethink_goal(struct proto *p);
42 839380d7 Martin Mares
static char *proto_state_name(struct proto *p);
43 1a54b1c6 Martin Mares
44 67bd949a Martin Mares
static void
45 b2280748 Martin Mares
proto_enqueue(list *l, struct proto *p)
46
{
47 3ea1ba63 Martin Mares
  add_tail(l, &p->n);
48 9685deb9 Martin Mares
  p->last_state_change = now;
49 b2280748 Martin Mares
}
50
51
static void
52 67bd949a Martin Mares
proto_relink(struct proto *p)
53
{
54 e81b440f Ondrej Zajicek
  list *l = NULL;
55 1a54b1c6 Martin Mares
56 df9f0fb3 Martin Mares
  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 67bd949a Martin Mares
  rem_node(&p->n);
68 1a54b1c6 Martin Mares
  switch (p->core_state)
69
    {
70 bf47fe4b Ondrej Zajicek
    case FS_HUNGRY:
71
      l = &inactive_proto_list;
72
      break;
73
    case FS_FEEDING:
74 1a54b1c6 Martin Mares
    case FS_HAPPY:
75 f14a4bec Martin Mares
      l = &active_proto_list;
76 1a54b1c6 Martin Mares
      break;
77
    case FS_FLUSHING:
78
      l = &flush_proto_list;
79
      break;
80
    default:
81 bf47fe4b Ondrej Zajicek
      ASSERT(0);
82 1a54b1c6 Martin Mares
    }
83 b2280748 Martin Mares
  proto_enqueue(l, p);
84 67bd949a Martin Mares
}
85 2326b001 Martin Mares
86 3c6269b8 Martin Mares
/**
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 2e9b2421 Martin Mares
 * initializing all the protocol instances configured by calling their
95 3c6269b8 Martin Mares
 * 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 7f4a3988 Martin Mares
void *
101 31b3e1bb Martin Mares
proto_new(struct proto_config *c, unsigned size)
102 7f4a3988 Martin Mares
{
103 1d2664a4 Martin Mares
  struct protocol *pr = c->protocol;
104 8fe48f13 Martin Mares
  struct proto *p = mb_allocz(proto_pool, size);
105 7f4a3988 Martin Mares
106 31b3e1bb Martin Mares
  p->cf = c;
107
  p->debug = c->debug;
108 cf31112f Ondrej Zajicek
  p->mrtdump = c->mrtdump;
109 67bd949a Martin Mares
  p->name = c->name;
110 31b3e1bb Martin Mares
  p->preference = c->preference;
111
  p->disabled = c->disabled;
112 7f4a3988 Martin Mares
  p->proto = pr;
113 9d885689 Martin Mares
  p->table = c->table->table;
114 529c4149 Martin Mares
  p->in_filter = c->in_filter;
115
  p->out_filter = c->out_filter;
116 7293c5dd Martin Mares
  p->hash_key = random_u32();
117 1d2664a4 Martin Mares
  c->proto = p;
118 7f4a3988 Martin Mares
  return p;
119
}
120
121 1a54b1c6 Martin Mares
static void
122
proto_init_instance(struct proto *p)
123
{
124 5bc512aa Martin Mares
  /* Here we cannot use p->cf->name since it won't survive reconfiguration */
125
  p->pool = rp_new(proto_pool, p->proto->name);
126 1a54b1c6 Martin Mares
  p->attn = ev_new(p->pool);
127
  p->attn->data = p;
128 50fe90ed Martin Mares
  rt_lock_table(p->table);
129 1a54b1c6 Martin Mares
}
130
131 3c6269b8 Martin Mares
/**
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 0e02abfd Martin Mares
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 839380d7 Martin Mares
  PD(p, "Connected to table %s", t->name);
154 0e02abfd Martin Mares
  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 3c6269b8 Martin Mares
/**
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 31b3e1bb Martin Mares
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 1d2664a4 Martin Mares
  c->protocol = pr;
194 31b3e1bb Martin Mares
  c->name = pr->name;
195 5056c559 Martin Mares
  c->out_filter = FILTER_REJECT;
196 9d885689 Martin Mares
  c->table = c->global->master_rtc;
197 839380d7 Martin Mares
  c->debug = new_config->proto_default_debug;
198 cf31112f Ondrej Zajicek
  c->mrtdump = new_config->proto_default_mrtdump;
199 31b3e1bb Martin Mares
  return c;
200
}
201
202 3c6269b8 Martin Mares
/**
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 2326b001 Martin Mares
void
211 31b3e1bb Martin Mares
protos_preconfig(struct config *c)
212 2326b001 Martin Mares
{
213 7f4a3988 Martin Mares
  struct protocol *p;
214
215 7c0cc76e Martin Mares
  init_list(&c->protos);
216 6b9fa320 Martin Mares
  DBG("Protocol preconfig:");
217 7f4a3988 Martin Mares
  WALK_LIST(p, protocol_list)
218
    {
219 6b9fa320 Martin Mares
      DBG(" %s", p->name);
220 4ba84ebc Martin Mares
      p->name_counter = 0;
221 3629bcf0 Martin Mares
      if (p->preconfig)
222 31b3e1bb Martin Mares
        p->preconfig(p, c);
223 7f4a3988 Martin Mares
    }
224 6b9fa320 Martin Mares
  DBG("\n");
225 7f4a3988 Martin Mares
}
226
227 3c6269b8 Martin Mares
/**
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 7f4a3988 Martin Mares
void
235 31b3e1bb Martin Mares
protos_postconfig(struct config *c)
236 7f4a3988 Martin Mares
{
237 31b3e1bb Martin Mares
  struct proto_config *x;
238 7f4a3988 Martin Mares
  struct protocol *p;
239
240 6b9fa320 Martin Mares
  DBG("Protocol postconfig:");
241 31b3e1bb Martin Mares
  WALK_LIST(x, c->protos)
242 7f4a3988 Martin Mares
    {
243 6b9fa320 Martin Mares
      DBG(" %s", x->name);
244 1d2664a4 Martin Mares
      p = x->protocol;
245 3629bcf0 Martin Mares
      if (p->postconfig)
246 31b3e1bb Martin Mares
        p->postconfig(x);
247
    }
248 6b9fa320 Martin Mares
  DBG("\n");
249 31b3e1bb Martin Mares
}
250
251 50fe90ed Martin Mares
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 f14a4bec Martin Mares
  add_tail(&proto_list, &q->glob_node);
261 498c3339 Martin Mares
  PD(q, "Initializing%s", q->disabled ? " [disabled]" : "");
262 50fe90ed Martin Mares
  return q;
263
}
264
265 ebae4770 Ondrej Zajicek
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 76b53a4e Ondrej Zajicek
      (proto_get_router_id(nc) != proto_get_router_id(oc)))
277 ebae4770 Ondrej Zajicek
    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 5a56f27c Ondrej Zajicek
  p->preference = nc->preference;
308 ebae4770 Ondrej Zajicek
309 76b53a4e Ondrej Zajicek
  if (import_changed || export_changed)
310
    log(L_INFO "Reloading protocol %s", p->name);
311
312 ebae4770 Ondrej Zajicek
  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 76b53a4e Ondrej Zajicek
      log(L_INFO "Restarting protocol %s", p->name);
317 ebae4770 Ondrej Zajicek
      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 3c6269b8 Martin Mares
/**
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 bf1aec97 Ondrej Zajicek
 * @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
337 3c6269b8 Martin Mares
 *
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 bf1aec97 Ondrej Zajicek
 * 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 3c6269b8 Martin Mares
 */
358 31b3e1bb Martin Mares
void
359 bf1aec97 Ondrej Zajicek
protos_commit(struct config *new, struct config *old, int force_reconfig, int type)
360 31b3e1bb Martin Mares
{
361 50fe90ed Martin Mares
  struct proto_config *oc, *nc;
362
  struct proto *p, *n;
363 31b3e1bb Martin Mares
364 50fe90ed Martin Mares
  DBG("protos_commit:\n");
365
  if (old)
366 31b3e1bb Martin Mares
    {
367 50fe90ed Martin Mares
      WALK_LIST(oc, old->protos)
368
        {
369
          struct proto *p = oc->proto;
370
          struct symbol *sym = cf_find_symbol(oc->name);
371 bf8558bc Martin Mares
          if (sym && sym->class == SYM_PROTO && !new->shutdown)
372 50fe90ed Martin Mares
            {
373
              /* Found match, let's check if we can smoothly switch to new configuration */
374 e04555c0 Ondrej Zajicek
              /* No need to check description */
375 50fe90ed Martin Mares
              nc = sym->def;
376 ebae4770 Ondrej Zajicek
              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 76b53a4e Ondrej Zajicek
              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 ebae4770 Ondrej Zajicek
              PD(p, "Restarting");
391 50fe90ed Martin Mares
              p->cf_new = nc;
392
            }
393
          else
394
            {
395 76b53a4e Ondrej Zajicek
              if (!shutting_down)
396
                log(L_INFO "Removing protocol %s", p->name);
397 839380d7 Martin Mares
              PD(p, "Unconfigured");
398 50fe90ed Martin Mares
              p->cf_new = NULL;
399
            }
400
          p->reconfiguring = 1;
401
          config_add_obstacle(old);
402
          proto_rethink_goal(p);
403
        }
404 7f4a3988 Martin Mares
    }
405 50fe90ed Martin Mares
406
  WALK_LIST(nc, new->protos)
407
    if (!nc->proto)
408
      {
409 76b53a4e Ondrej Zajicek
        if (old_config)                /* Not a first-time configuration */
410
          log(L_INFO "Adding protocol %s", nc->name);
411 50fe90ed Martin Mares
        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 7f4a3988 Martin Mares
}
419
420 47b79306 Martin Mares
static void
421 67bd949a Martin Mares
proto_rethink_goal(struct proto *p)
422 47b79306 Martin Mares
{
423 50fe90ed Martin Mares
  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 f14a4bec Martin Mares
      rem_node(&p->glob_node);
432 50fe90ed Martin Mares
      mb_free(p);
433
      if (!nc)
434
        return;
435 f098e072 Martin Mares
      p = proto_init(nc);
436 50fe90ed Martin Mares
    }
437
438
  /* Determine what state we want to reach */
439 bf8558bc Martin Mares
  if (p->disabled || p->reconfiguring)
440 ebd3720f Martin Mares
    {
441
      p->core_goal = FS_HUNGRY;
442
      if (p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
443
        return;
444
    }
445 50fe90ed Martin Mares
  else
446 ebd3720f Martin Mares
    {
447
      p->core_goal = FS_HAPPY;
448
      if (p->core_state == FS_HAPPY && p->proto_state == PS_UP)
449
        return;
450
    }
451 50fe90ed Martin Mares
452
  q = p->proto;
453 67bd949a Martin Mares
  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 839380d7 Martin Mares
          PD(p, "Starting");
459 1a54b1c6 Martin Mares
          proto_init_instance(p);
460 67bd949a Martin Mares
          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 839380d7 Martin Mares
          PD(p, "Shutting down");
469 67bd949a Martin Mares
          proto_notify_state(p, (q->shutdown ? q->shutdown(p) : PS_DOWN));
470
        }
471
    }
472
}
473
474 3c6269b8 Martin Mares
/**
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 7f4a3988 Martin Mares
void
484 87d2be86 Pavel Machek
protos_dump_all(void)
485
{
486
  struct proto *p;
487
488
  debug("Protocols:\n");
489
490 f14a4bec Martin Mares
  WALK_LIST(p, active_proto_list)
491 87d2be86 Pavel Machek
    {
492 3ea1ba63 Martin Mares
      debug("  protocol %s state %s/%s\n", p->name,
493 b2280748 Martin Mares
            p_states[p->proto_state], c_states[p->core_state]);
494 529c4149 Martin Mares
      if (p->in_filter)
495 5056c559 Martin Mares
        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 66efdf96 Martin Mares
      if (p->disabled)
499
        debug("\tDISABLED\n");
500 31b3e1bb Martin Mares
      else if (p->proto->dump)
501
        p->proto->dump(p);
502 87d2be86 Pavel Machek
    }
503 47b79306 Martin Mares
  WALK_LIST(p, inactive_proto_list)
504 67bd949a Martin Mares
    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 f14a4bec Martin Mares
  WALK_LIST(p, flush_proto_list)
508
    debug("  flushing %s\n", p->name);
509 87d2be86 Pavel Machek
}
510
511 3c6269b8 Martin Mares
/**
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 2e9b2421 Martin Mares
 * all platform specific protocols to inform the core that they exist.
518 3c6269b8 Martin Mares
 */
519 87d2be86 Pavel Machek
void
520 3991d84e Martin Mares
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 3c6269b8 Martin Mares
/**
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 3991d84e Martin Mares
void
540 0432c017 Martin Mares
protos_build(void)
541
{
542
  init_list(&protocol_list);
543 471cc0be Martin Mares
  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 3991d84e Martin Mares
  proto_build(&proto_device);
549 18fff6a1 Martin Mares
#ifdef CONFIG_RIP
550 3991d84e Martin Mares
  proto_build(&proto_rip);
551 18fff6a1 Martin Mares
#endif
552
#ifdef CONFIG_STATIC
553 3991d84e Martin Mares
  proto_build(&proto_static);
554 18fff6a1 Martin Mares
#endif
555 c1f8dc91 Ondrej Filip
#ifdef CONFIG_OSPF
556 3991d84e Martin Mares
  proto_build(&proto_ospf);
557 c1f8dc91 Ondrej Filip
#endif
558 26368f65 Martin Mares
#ifdef CONFIG_PIPE
559 3991d84e Martin Mares
  proto_build(&proto_pipe);
560 26368f65 Martin Mares
#endif
561 2638249d Martin Mares
#ifdef CONFIG_BGP
562 3991d84e Martin Mares
  proto_build(&proto_bgp);
563 2638249d Martin Mares
#endif
564 67bd949a Martin Mares
  proto_pool = rp_new(&root_pool, "Protocols");
565 1a54b1c6 Martin Mares
  proto_flush_event = ev_new(proto_pool);
566
  proto_flush_event->hook = proto_flush_all;
567 67bd949a Martin Mares
}
568
569
static void
570
proto_fell_down(struct proto *p)
571
{
572
  DBG("Protocol %s down\n", p->name);
573 ac07aacd Ondrej Zajicek
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 925fe2d3 Ondrej Zajicek
577
  bzero(&p->stats, sizeof(struct proto_stats));
578 50fe90ed Martin Mares
  rt_unlock_table(p->table);
579 c8387626 Ondrej Zajicek
580 cfe34a31 Ondrej Zajicek
  if (p->proto->cleanup)
581
    p->proto->cleanup(p);
582 c8387626 Ondrej Zajicek
583 67bd949a Martin Mares
  proto_rethink_goal(p);
584
}
585
586 8f6accb5 Martin Mares
static void
587 ac5d8012 Martin Mares
proto_feed_more(void *P)
588
{
589
  struct proto *p = P;
590
591 075898de Martin Mares
  if (p->core_state != FS_FEEDING)
592
    return;
593 fbde6c39 Ondrej Zajicek
594
  DBG("Feeding protocol %s continued\n", p->name);
595 ac5d8012 Martin Mares
  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 bf47fe4b Ondrej Zajicek
proto_feed_initial(void *P)
610 67bd949a Martin Mares
{
611
  struct proto *p = P;
612
613 fbde6c39 Ondrej Zajicek
  if (p->core_state != FS_FEEDING)
614
    return;
615
616 67bd949a Martin Mares
  DBG("Feeding protocol %s\n", p->name);
617 0e02abfd Martin Mares
  proto_add_announce_hook(p, p->table);
618 67bd949a Martin Mares
  if_feed_baby(p);
619 ac5d8012 Martin Mares
  proto_feed_more(P);
620 67bd949a Martin Mares
}
621
622 d6a836f8 Ondrej Zajicek
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 bf47fe4b Ondrej Zajicek
proto_schedule_feed(struct proto *p, int initial)
638 d6a836f8 Ondrej Zajicek
{
639
  DBG("%s: Scheduling meal\n", p->name);
640
  p->core_state = FS_FEEDING;
641 11361a10 Ondrej Zajicek
  p->refeeding = !initial;
642 8a7fb885 Ondrej Zajicek
643
  /* Hack: reset exp_routes during refeed, and do not decrease it later */
644
  if (!initial)
645
    p->stats.exp_routes = 0;
646
647 d6a836f8 Ondrej Zajicek
  proto_relink(p);
648 bf47fe4b Ondrej Zajicek
  p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
649 d6a836f8 Ondrej Zajicek
  ev_schedule(p->attn);
650
}
651
652 3c6269b8 Martin Mares
/**
653 bf47fe4b Ondrej Zajicek
 * 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 3c6269b8 Martin Mares
 * 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 d6a836f8 Ondrej Zajicek
 * 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 3c6269b8 Martin Mares
 */
695 67bd949a Martin Mares
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 d6a836f8 Ondrej Zajicek
  p->proto_state = ps;
706
707 67bd949a Martin Mares
  switch (ps)
708
    {
709
    case PS_DOWN:
710 a421ec33 Ondrej Zajicek
      if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
711 b807ef9a Ondrej Zajicek
        proto_schedule_flush(p);
712
713 d6a836f8 Ondrej Zajicek
      neigh_prune(); // FIXME convert neighbors to resource?
714
      rfree(p->pool);
715
      p->pool = NULL;
716
717 67bd949a Martin Mares
      if (cs == FS_HUNGRY)                /* Shutdown finished */
718 50fe90ed Martin Mares
        {
719
          proto_fell_down(p);
720
          return;                        /* The protocol might have ceased to exist */
721
        }
722 67bd949a Martin Mares
      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 bf47fe4b Ondrej Zajicek
      proto_schedule_feed(p, 1);
731 67bd949a Martin Mares
      break;
732
    case PS_STOP:
733 a421ec33 Ondrej Zajicek
      if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
734 d6a836f8 Ondrej Zajicek
        proto_schedule_flush(p);
735 f4aabcee Martin Mares
      break;
736 67bd949a Martin Mares
    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 0432c017 Martin Mares
}
740 1a54b1c6 Martin Mares
741 53434e44 Ondrej Zajicek
extern struct protocol proto_unix_iface;
742
743 8f6accb5 Martin Mares
static void
744 7c103b1e Martin Mares
proto_flush_all(void *unused UNUSED)
745 1a54b1c6 Martin Mares
{
746
  struct proto *p;
747
748 0e02abfd Martin Mares
  rt_prune_all();
749 1a54b1c6 Martin Mares
  while ((p = HEAD(flush_proto_list))->n.next)
750
    {
751 53434e44 Ondrej Zajicek
      /* 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 1a54b1c6 Martin Mares
      DBG("Flushing protocol %s\n", p->name);
757
      p->core_state = FS_HUNGRY;
758
      proto_relink(p);
759 d6a836f8 Ondrej Zajicek
      if (p->proto_state == PS_DOWN)
760
        proto_fell_down(p);
761 1a54b1c6 Martin Mares
    }
762
}
763 ae97b946 Martin Mares
764 0d3e6bce Martin Mares
/*
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 9db74169 Ondrej Zajicek
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 ba130172 Ondrej Filip
#ifdef CONFIG_PIPE
809 9db74169 Ondrej Zajicek
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 ba130172 Ondrej Filip
#endif
849 9db74169 Ondrej Zajicek
850 e304fd4b Ondrej Zajicek
void
851
proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
852 1d2664a4 Martin Mares
{
853 c37e7851 Ondrej Zajicek
  byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
854 9685deb9 Martin Mares
855 e304fd4b Ondrej Zajicek
  /* First protocol - show header */
856
  if (!cnt)
857
    cli_msg(-2002, "name     proto    table    state  since       info");
858
859 9685deb9 Martin Mares
  buf[0] = 0;
860
  if (p->proto->get_status)
861
    p->proto->get_status(p, buf);
862 c37e7851 Ondrej Zajicek
  tm_format_datetime(tbuf, &config->tf_proto, p->last_state_change);
863
  cli_msg(-1002, "%-8s %-8s %-8s %-5s  %-10s  %s",
864 1d2664a4 Martin Mares
          p->name,
865
          p->proto->name,
866
          p->table->name,
867
          proto_state_name(p),
868 c37e7851 Ondrej Zajicek
          tbuf,
869 9685deb9 Martin Mares
          buf);
870 1d2664a4 Martin Mares
  if (verbose)
871
    {
872 e04555c0 Ondrej Zajicek
      if (p->cf->dsc)
873
        cli_msg(-1006, "  Description:    %s", p->cf->dsc);
874 b8113a5e Ondrej Zajicek
      if (p->cf->router_id)
875
        cli_msg(-1006, "  Router ID:      %R", p->cf->router_id);
876 925fe2d3 Ondrej Zajicek
      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 9db74169 Ondrej Zajicek
#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 925fe2d3 Ondrej Zajicek
        }
889
890 b8113a5e Ondrej Zajicek
      if (p->proto->show_proto_info)
891
        p->proto->show_proto_info(p);
892
893 925fe2d3 Ondrej Zajicek
      cli_msg(-1006, "");
894 1d2664a4 Martin Mares
    }
895
}
896
897 ae97b946 Martin Mares
void
898 e304fd4b Ondrej Zajicek
proto_cmd_disable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
899 ae97b946 Martin Mares
{
900 e304fd4b Ondrej Zajicek
  if (p->disabled)
901 1d2664a4 Martin Mares
    {
902 e304fd4b Ondrej Zajicek
      cli_msg(-8, "%s: already disabled", p->name);
903 1d2664a4 Martin Mares
      return;
904
    }
905 e304fd4b Ondrej Zajicek
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 1d2664a4 Martin Mares
    {
991 e304fd4b Ondrej Zajicek
      cli_msg(9002, "%s is not a protocol", s->name);
992
      return;
993 1d2664a4 Martin Mares
    }
994 e304fd4b Ondrej Zajicek
995
  cmd(((struct proto_config *)s->def)->proto, arg, 0);
996 ae97b946 Martin Mares
  cli_msg(0, "");
997
}
998 02c1fbdd Martin Mares
999 e304fd4b Ondrej Zajicek
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 e0a45fb4 Ondrej Zajicek
proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int),
1021
                int restricted, unsigned int arg)
1022 e304fd4b Ondrej Zajicek
{
1023 e0a45fb4 Ondrej Zajicek
  if (restricted && cli_access_restricted())
1024
    return;
1025
1026 e304fd4b Ondrej Zajicek
  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 02c1fbdd Martin Mares
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 f14a4bec Martin Mares
      WALK_LIST(q, active_proto_list)
1049 02c1fbdd Martin Mares
        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
}