proto.c 35.7 KB
Newer Older
1 2 3
/*
 *	BIRD -- Protocols
 *
4
 *	(c) 1998--2000 Martin Mares <mj@ucw.cz>
5 6 7 8
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

9
#undef LOCAL_DEBUG
Martin Mareš's avatar
Martin Mareš committed
10

11 12 13 14
#include "nest/bird.h"
#include "nest/protocol.h"
#include "lib/resource.h"
#include "lib/lists.h"
15
#include "lib/event.h"
16
#include "lib/string.h"
17
#include "conf/conf.h"
18 19
#include "nest/route.h"
#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 29
#define PD(pr, msg, args...) do { if (pr->debug & D_STATES) { log(L_TRACE "%s: " msg, pr->name , ## args); } } while(0)

30
list active_proto_list;
31 32
static list inactive_proto_list;
static list initial_proto_list;
33
static list flush_proto_list;
34
static struct proto *initial_device_proto;
35 36

static event *proto_flush_event;
37
static timer *proto_shutdown_timer;
38 39 40 41

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

42
static void proto_flush_loop(void *);
43
static void proto_shutdown_loop(struct timer *);
44
static void proto_rethink_goal(struct proto *p);
45
static char *proto_state_name(struct proto *p);
46

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

54 55 56
static void
proto_relink(struct proto *p)
{
57
  list *l = NULL;
58

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

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

109 110
  p->cf = c;
  p->debug = c->debug;
111
  p->mrtdump = c->mrtdump;
112
  p->name = c->name;
113 114
  p->preference = c->preference;
  p->disabled = c->disabled;
Martin Mareš's avatar
Martin Mareš committed
115
  p->proto = pr;
Martin Mareš's avatar
Martin Mareš committed
116
  p->table = c->table->table;
117
  p->hash_key = random_u32();
118
  c->proto = p;
Martin Mareš's avatar
Martin Mareš committed
119 120 121
  return p;
}

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

  if (! p->proto->multitable)
    rt_lock_table(p->table);
132 133
}

134
extern pool *rt_table_pool;
135 136 137 138
/**
 * proto_add_announce_hook - connect protocol to a routing table
 * @p: protocol instance
 * @t: routing table to connect to
139
 * @stats: per-table protocol statistics
140 141 142 143 144
 *
 * This function creates a connection between the protocol instance @p
 * and the routing table @t, making the protocol hear all changes in
 * the table.
 *
145 146 147 148 149 150 151
 * The announce hook is linked in the protocol ahook list and, if the
 * protocol accepts routes, also in the table ahook list. Announce
 * hooks are allocated from the routing table resource pool, they are
 * unlinked from the table ahook list after the protocol went down,
 * (in proto_schedule_flush()) and they are automatically freed after the
 * protocol is flushed (in proto_fell_down()).
 *
152 153 154 155 156
 * Unless you want to listen to multiple routing tables (as the Pipe
 * protocol does), you needn't to worry about this function since the
 * connection to the protocol's primary routing table is initialized
 * automatically by the core code.
 */
157
struct announce_hook *
158
proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats)
159 160 161 162
{
  struct announce_hook *h;

  DBG("Connecting protocol %s to table %s\n", p->name, t->name);
163
  PD(p, "Connected to table %s", t->name);
164 165

  h = mb_allocz(rt_table_pool, sizeof(struct announce_hook));
166 167
  h->table = t;
  h->proto = p;
168 169
  h->stats = stats;

170 171
  h->next = p->ahooks;
  p->ahooks = h;
172 173 174

  if (p->rt_notify)
    add_tail(&t->hooks, &h->n);
175 176 177
  return h;
}

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
/**
 * proto_find_announce_hook - find announce hooks
 * @p: protocol instance
 * @t: routing table
 *
 * Returns pointer to announce hook or NULL
 */
struct announce_hook *
proto_find_announce_hook(struct proto *p, struct rtable *t)
{
  struct announce_hook *a;

  for (a = p->ahooks; a; a = a->next)
    if (a->table == t)
      return a;

  return NULL;
}

197
static void
198
proto_unlink_ahooks(struct proto *p)
199 200 201
{
  struct announce_hook *h;

202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
  if (p->rt_notify)
    for(h=p->ahooks; h; h=h->next)
      rem_node(&h->n);
}

static void
proto_free_ahooks(struct proto *p)
{
  struct announce_hook *h, *hn;

  for(h = p->ahooks; h; h = hn)
  {
    hn = h->next;
    mb_free(h);
  }

218
  p->ahooks = NULL;
219
  p->main_ahook = NULL;
220 221
}

222 223 224 225
/**
 * proto_config_new - create a new protocol configuration
 * @pr: protocol the configuration will belong to
 * @size: size of the structure including generic data
226
 * @class: SYM_PROTO or SYM_TEMPLATE
227 228 229 230 231 232 233 234
 *
 * Whenever the configuration file says that a new instance
 * of a routing protocol should be created, the parser calls
 * proto_config_new() to create a configuration entry for this
 * instance (a structure staring with the &proto_config header
 * containing all the generic items followed by protocol-specific
 * ones). Also, the configuration entry gets added to the list
 * of protocol instances kept in the configuration.
235 236 237 238 239
 *
 * The function is also used to create protocol templates (when class
 * SYM_TEMPLATE is specified), the only difference is that templates
 * are not added to the list of protocol instances and therefore not
 * initialized during protos_commit()).
240
 */
241
void *
242
proto_config_new(struct protocol *pr, unsigned size, int class)
243 244 245
{
  struct proto_config *c = cfg_allocz(size);

246 247
  if (class == SYM_PROTO)
    add_tail(&new_config->protos, &c->n);
248
  c->global = new_config;
249
  c->protocol = pr;
250
  c->name = pr->name;
251
  c->preference = pr->preference;
252
  c->class = class;
253
  c->out_filter = FILTER_REJECT;
Martin Mareš's avatar
Martin Mareš committed
254
  c->table = c->global->master_rtc;
255
  c->debug = new_config->proto_default_debug;
256
  c->mrtdump = new_config->proto_default_mrtdump;
257 258 259
  return c;
}

260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
/**
 * proto_copy_config - copy a protocol configuration
 * @dest: destination protocol configuration
 * @src: source protocol configuration
 *
 * Whenever a new instance of a routing protocol is created from the
 * template, proto_copy_config() is called to copy a content of
 * the source protocol configuration to the new protocol configuration.
 * Name, class and a node in protos list of @dest are kept intact.
 * copy_config() protocol hook is used to copy protocol-specific data.
 */
void
proto_copy_config(struct proto_config *dest, struct proto_config *src)
{
  node old_node;
  int old_class;
  char *old_name;

  if (dest->protocol != src->protocol)
    cf_error("Can't copy configuration from a different protocol type");

  if (dest->protocol->copy_config == NULL)
    cf_error("Inheriting configuration for %s is not supported", src->protocol->name);

  DBG("Copying configuration from %s to %s\n", src->name, dest->name);

  /* 
   * Copy struct proto_config here. Keep original node, class and name.
   * protocol-specific config copy is handled by protocol copy_config() hook
   */

  old_node = dest->n;
  old_class = dest->class;
  old_name = dest->name;

  memcpy(dest, src, sizeof(struct proto_config));

  dest->n = old_node;
  dest->class = old_class;
  dest->name = old_name;

  dest->protocol->copy_config(dest, src);
}

304 305 306 307 308 309 310 311
/**
 * protos_preconfig - pre-configuration processing
 * @c: new configuration
 *
 * This function calls the preconfig() hooks of all routing
 * protocols available to prepare them for reading of the new
 * configuration.
 */
312
void
313
protos_preconfig(struct config *c)
314
{
Martin Mareš's avatar
Martin Mareš committed
315 316
  struct protocol *p;

317
  init_list(&c->protos);
318
  DBG("Protocol preconfig:");
Martin Mareš's avatar
Martin Mareš committed
319 320
  WALK_LIST(p, protocol_list)
    {
321
      DBG(" %s", p->name);
322
      p->name_counter = 0;
323
      if (p->preconfig)
324
	p->preconfig(p, c);
Martin Mareš's avatar
Martin Mareš committed
325
    }
326
  DBG("\n");
Martin Mareš's avatar
Martin Mareš committed
327 328
}

329 330 331 332 333
/**
 * protos_postconfig - post-configuration processing
 * @c: new configuration
 *
 * This function calls the postconfig() hooks of all protocol
334 335
 * instances specified in configuration @c. The hooks are not
 * called for protocol templates.
336
 */
Martin Mareš's avatar
Martin Mareš committed
337
void
338
protos_postconfig(struct config *c)
Martin Mareš's avatar
Martin Mareš committed
339
{
340
  struct proto_config *x;
Martin Mareš's avatar
Martin Mareš committed
341 342
  struct protocol *p;

343
  DBG("Protocol postconfig:");
344
  WALK_LIST(x, c->protos)
Martin Mareš's avatar
Martin Mareš committed
345
    {
346
      DBG(" %s", x->name);
347

348
      p = x->protocol;
349
      if (p->postconfig)
350 351
	p->postconfig(x);
    }
352
  DBG("\n");
353 354
}

355 356
extern struct protocol proto_unix_iface;

357 358 359 360 361 362 363 364 365
static struct proto *
proto_init(struct proto_config *c)
{
  struct protocol *p = c->protocol;
  struct proto *q = p->init(c);

  q->proto_state = PS_DOWN;
  q->core_state = FS_HUNGRY;
  proto_enqueue(&initial_proto_list, q);
366 367 368
  if (p == &proto_unix_iface)
    initial_device_proto = q;

369
  add_tail(&proto_list, &q->glob_node);
Martin Mareš's avatar
Martin Mareš committed
370
  PD(q, "Initializing%s", q->disabled ? " [disabled]" : "");
371 372 373
  return q;
}

374 375
int proto_reconfig_type;  /* Hack to propagate type info to pipe reconfigure hook */

376 377 378 379 380 381 382 383 384
static int
proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type)
{
  /* If the protocol is DOWN, we just restart it */
  if (p->proto_state == PS_DOWN)
    return 0;

  /* If there is a too big change in core attributes, ... */
  if ((nc->protocol != oc->protocol) ||
385
      (nc->disabled != p->disabled) ||
386
      (nc->table->table != oc->table->table))
387 388 389 390
    return 0;

  p->debug = nc->debug;
  p->mrtdump = nc->mrtdump;
391
  proto_reconfig_type = type;
392 393 394 395 396 397 398 399 400

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

  DBG("\t%s: same\n", oc->name);
  PD(p, "Reconfigured");
  p->cf = nc;
  p->name = nc->name;
401
  p->preference = nc->preference;
402

403 404 405 406 407

  /* Multitable protocols handle rest in their reconfigure hooks */
  if (p->proto->multitable)
    return 1;

408 409
  /* Update filters and limits in the main announce hook
     Note that this also resets limit state */
410 411 412 413
  if (p->main_ahook)
    {
      p->main_ahook->in_filter = nc->in_filter;
      p->main_ahook->out_filter = nc->out_filter;
414
      p->main_ahook->rx_limit = nc->rx_limit;
415
      p->main_ahook->in_limit = nc->in_limit;
416
      p->main_ahook->out_limit = nc->out_limit;
417
      p->main_ahook->in_keep_filtered = nc->in_keep_filtered;
418 419 420 421 422 423 424 425 426 427 428 429 430 431
    }

  /* Update routes when filters changed. If the protocol in not UP,
     it has no routes and we can ignore such changes */
  if ((p->proto_state != PS_UP) || (type == RECONFIG_SOFT))
    return 1;

  int import_changed = ! filter_same(nc->in_filter, oc->in_filter);
  int export_changed = ! filter_same(nc->out_filter, oc->out_filter);

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

432 433 434
  if (import_changed || export_changed)
    log(L_INFO "Reloading protocol %s", p->name);

435 436
  /* If import filter changed, call reload hook */
  if (import_changed && ! (p->reload_routes && p->reload_routes(p)))
437 438 439
    {
      /* Now, the protocol is reconfigured. But route reload failed
	 and we have to do regular protocol restart. */
440
      log(L_INFO "Restarting protocol %s", p->name);
441
      p->disabled = 1;
442
      p->down_code = PDC_CF_RESTART;
443 444 445 446 447 448 449 450 451 452 453 454
      proto_rethink_goal(p);
      p->disabled = 0;
      proto_rethink_goal(p);
      return 1;
    }

  if (export_changed)
    proto_request_feeding(p);

  return 1;
}

455 456 457 458 459 460
/**
 * protos_commit - commit new protocol configuration
 * @new: new configuration
 * @old: old configuration or %NULL if it's boot time config
 * @force_reconfig: force restart of all protocols (used for example
 * when the router ID changes)
461
 * @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
462 463 464 465 466 467 468 469 470 471 472 473
 *
 * Scan differences between @old and @new configuration and adjust all
 * protocol instances to conform to the new configuration.
 *
 * When a protocol exists in the new configuration, but it doesn't in the
 * original one, it's immediately started. When a collision with the other
 * running protocol would arise, the new protocol will be temporarily stopped
 * by the locking mechanism.
 *
 * When a protocol exists in the old configuration, but it doesn't in the
 * new one, it's shut down and deleted after the shutdown completes.
 *
474 475 476 477 478 479 480 481
 * When a protocol exists in both configurations, the core decides
 * whether it's possible to reconfigure it dynamically - it checks all
 * the core properties of the protocol (changes in filters are ignored
 * if type is RECONFIG_SOFT) and if they match, it asks the
 * reconfigure() hook of the protocol to see if the protocol is able
 * to switch to the new configuration.  If it isn't possible, the
 * protocol is shut down and a new instance is started with the new
 * configuration after the shutdown is completed.
482
 */
483
void
484
protos_commit(struct config *new, struct config *old, int force_reconfig, int type)
485
{
486 487
  struct proto_config *oc, *nc;
  struct proto *p, *n;
488
  struct symbol *sym;
489

490 491
  DBG("protos_commit:\n");
  if (old)
492
    {
493 494
      WALK_LIST(oc, old->protos)
	{
495 496
	  p = oc->proto;
	  sym = cf_find_symbol(oc->name);
497
	  if (sym && sym->class == SYM_PROTO && !new->shutdown)
498 499
	    {
	      /* Found match, let's check if we can smoothly switch to new configuration */
500
	      /* No need to check description */
501
	      nc = sym->def;
502 503 504 505 506 507 508
	      nc->proto = p;

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

	      /* Unsuccessful, we will restart it */
509 510 511 512 513 514 515
	      if (!p->disabled && !nc->disabled)
		log(L_INFO "Restarting protocol %s", p->name);
	      else if (p->disabled && !nc->disabled)
		log(L_INFO "Enabling protocol %s", p->name);
	      else if (!p->disabled && nc->disabled)
		log(L_INFO "Disabling protocol %s", p->name);

516
	      p->down_code = nc->disabled ? PDC_CF_DISABLE : PDC_CF_RESTART;
517 518
	      p->cf_new = nc;
	    }
519
	  else if (!new->shutdown)
520
	    {
521
	      log(L_INFO "Removing protocol %s", p->name);
522
	      p->down_code = PDC_CF_REMOVE;
523 524
	      p->cf_new = NULL;
	    }
525 526 527 528 529
	  else /* global shutdown */
	    {
	      p->down_code = PDC_CMD_SHUTDOWN;
	      p->cf_new = NULL;
	    }
530

531
	  p->reconfiguring = 1;
532 533 534
	  config_add_obstacle(old);
	  proto_rethink_goal(p);
	}
Martin Mareš's avatar
Martin Mareš committed
535
    }
536 537 538 539

  WALK_LIST(nc, new->protos)
    if (!nc->proto)
      {
540
	if (old)		/* Not a first-time configuration */
541
	  log(L_INFO "Adding protocol %s", nc->name);
542 543 544 545 546
	proto_init(nc);
      }
  DBG("\tdone\n");

  DBG("Protocol start\n");
547 548 549 550 551 552 553 554

  /* Start device protocol first */
  if (initial_device_proto)
  {
    proto_rethink_goal(initial_device_proto);
    initial_device_proto = NULL;
  }

555 556 557 558 559 560 561 562 563 564
  /* Determine router ID for the first time - it has to be here and not in
     global_commit() because it is postponed after start of device protocol */
  if (!config->router_id)
    {
      config->router_id = if_choose_router_id(config->router_id_from, 0);
      if (!config->router_id)
	die("Cannot determine router ID, please configure it manually");
    }

  /* Start all other protocols */
565 566
  WALK_LIST_DELSAFE(p, n, initial_proto_list)
    proto_rethink_goal(p);
Martin Mareš's avatar
Martin Mareš committed
567 568
}

569
static void
570
proto_rethink_goal(struct proto *p)
571
{
572 573 574 575 576 577 578 579
  struct protocol *q;

  if (p->reconfiguring && p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
    {
      struct proto_config *nc = p->cf_new;
      DBG("%s has shut down for reconfiguration\n", p->name);
      config_del_obstacle(p->cf->global);
      rem_node(&p->n);
580
      rem_node(&p->glob_node);
581 582 583
      mb_free(p);
      if (!nc)
	return;
584
      p = proto_init(nc);
585 586 587
    }

  /* Determine what state we want to reach */
588
  if (p->disabled || p->reconfiguring)
589 590 591 592 593
    {
      p->core_goal = FS_HUNGRY;
      if (p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
	return;
    }
594
  else
595 596 597 598 599
    {
      p->core_goal = FS_HAPPY;
      if (p->core_state == FS_HAPPY && p->proto_state == PS_UP)
	return;
    }
600 601

  q = p->proto;
602 603 604 605 606
  if (p->core_goal == FS_HAPPY)		/* Going up */
    {
      if (p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
	{
	  DBG("Kicking %s up\n", p->name);
607
	  PD(p, "Starting");
608
	  proto_init_instance(p);
609 610 611 612 613 614 615 616
	  proto_notify_state(p, (q->start ? q->start(p) : PS_UP));
	}
    }
  else 					/* Going down */
    {
      if (p->proto_state == PS_START || p->proto_state == PS_UP)
	{
	  DBG("Kicking %s down\n", p->name);
617
	  PD(p, "Shutting down");
618 619 620 621 622
	  proto_notify_state(p, (q->shutdown ? q->shutdown(p) : PS_DOWN));
	}
    }
}

623 624 625 626 627 628 629 630 631
/**
 * protos_dump_all - dump status of all protocols
 *
 * This function dumps status of all existing protocol instances to the
 * debug output. It involves printing of general status information
 * such as protocol states, its position on the protocol lists
 * and also calling of a dump() hook of the protocol to print
 * the internals.
 */
632 633 634 635
void
protos_dump_all(void)
{
  struct proto *p;
636
  struct announce_hook *a;
637 638 639

  debug("Protocols:\n");

640
  WALK_LIST(p, active_proto_list)
641
    {
642
      debug("  protocol %s state %s/%s\n", p->name,
643
	    p_states[p->proto_state], c_states[p->core_state]);
644 645 646 647 648 649 650 651
      for (a = p->ahooks; a; a = a->next)
	{
	  debug("\tTABLE %s\n", a->table->name);
	  if (a->in_filter)
	    debug("\tInput filter: %s\n", filter_name(a->in_filter));
	  if (a->out_filter != FILTER_REJECT)
	    debug("\tOutput filter: %s\n", filter_name(a->out_filter));
	}
652 653
      if (p->disabled)
	debug("\tDISABLED\n");
654 655
      else if (p->proto->dump)
	p->proto->dump(p);
656
    }
657
  WALK_LIST(p, inactive_proto_list)
658 659 660
    debug("  inactive %s: state %s/%s\n", p->name, p_states[p->proto_state], c_states[p->core_state]);
  WALK_LIST(p, initial_proto_list)
    debug("  initial %s\n", p->name);
661 662
  WALK_LIST(p, flush_proto_list)
    debug("  flushing %s\n", p->name);
663 664
}

665 666 667 668 669 670
/**
 * proto_build - make a single protocol available
 * @p: the protocol
 *
 * After the platform specific initialization code uses protos_build()
 * to add all the standard protocols, it should call proto_build() for
Martin Mareš's avatar
Martin Mareš committed
671
 * all platform specific protocols to inform the core that they exist.
672
 */
673 674 675 676 677 678 679 680 681 682 683
void
proto_build(struct protocol *p)
{
  add_tail(&protocol_list, &p->n);
  if (p->attr_class)
    {
      ASSERT(!attr_class_to_protocol[p->attr_class]);
      attr_class_to_protocol[p->attr_class] = p;
    }
}

684 685 686 687 688 689 690 691 692
/**
 * protos_build - build a protocol list
 *
 * This function is called during BIRD startup to insert
 * all standard protocols to the global protocol list. Insertion
 * of platform specific protocols (such as the kernel syncer)
 * is in the domain of competence of the platform dependent
 * startup code.
 */
693 694 695 696
void
protos_build(void)
{
  init_list(&protocol_list);
697 698 699 700 701
  init_list(&proto_list);
  init_list(&active_proto_list);
  init_list(&inactive_proto_list);
  init_list(&initial_proto_list);
  init_list(&flush_proto_list);
702
  proto_build(&proto_device);
703 704 705
#ifdef CONFIG_RADV
  proto_build(&proto_radv);
#endif
706
#ifdef CONFIG_RIP
707
  proto_build(&proto_rip);
708 709
#endif
#ifdef CONFIG_STATIC
710
  proto_build(&proto_static);
Ondřej Filip's avatar
 
Ondřej Filip committed
711 712
#endif
#ifdef CONFIG_OSPF
713
  proto_build(&proto_ospf);
714 715
#endif
#ifdef CONFIG_PIPE
716
  proto_build(&proto_pipe);
Martin Mareš's avatar
Martin Mareš committed
717 718
#endif
#ifdef CONFIG_BGP
719
  proto_build(&proto_bgp);
720
#endif
Ondřej Zajíček's avatar
Ondřej Zajíček committed
721 722 723
  // XXX
  proto_build(&proto_bfd);

724
  proto_pool = rp_new(&root_pool, "Protocols");
725
  proto_flush_event = ev_new(proto_pool);
726
  proto_flush_event->hook = proto_flush_loop;
727 728
  proto_shutdown_timer = tm_new(proto_pool);
  proto_shutdown_timer->hook = proto_shutdown_loop;
729 730 731 732 733 734
}

static void
proto_fell_down(struct proto *p)
{
  DBG("Protocol %s down\n", p->name);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
735

736
  u32 all_routes = p->stats.imp_routes + p->stats.filt_routes;
737 738
  if (all_routes != 0)
    log(L_ERR "Protocol %s is down but still has %d routes", p->name, all_routes);
739 740

  bzero(&p->stats, sizeof(struct proto_stats));
741 742 743 744
  proto_free_ahooks(p);

  if (! p->proto->multitable)
    rt_unlock_table(p->table);
745

746 747
  if (p->proto->cleanup)
    p->proto->cleanup(p);
748

749 750 751
  proto_rethink_goal(p);
}

752 753 754 755 756
static void
proto_feed_more(void *P)
{
  struct proto *p = P;

757 758
  if (p->core_state != FS_FEEDING)
    return;
759 760

  DBG("Feeding protocol %s continued\n", p->name);
761 762 763 764 765 766 767 768 769 770 771 772 773
  if (rt_feed_baby(p))
    {
      p->core_state = FS_HAPPY;
      proto_relink(p);
      DBG("Protocol %s up and running\n", p->name);
    }
  else
    {
      p->attn->hook = proto_feed_more;
      ev_schedule(p->attn);		/* Will continue later... */
    }
}

774
static void
775
proto_feed_initial(void *P)
776 777 778
{
  struct proto *p = P;

779 780 781
  if (p->core_state != FS_FEEDING)
    return;

782
  DBG("Feeding protocol %s\n", p->name);
783

784
  if_feed_baby(p);
785
  proto_feed_more(P);
786 787
}

Ondřej Zajíček's avatar
Ondřej Zajíček committed
788
static void
789
proto_schedule_feed(struct proto *p, int initial)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
790 791 792
{
  DBG("%s: Scheduling meal\n", p->name);
  p->core_state = FS_FEEDING;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
793
  p->refeeding = !initial;
794

795
  /* FIXME: This should be changed for better support of multitable protos */
796
  if (!initial)
797 798 799 800 801 802 803 804
    {
      struct announce_hook *ah;
      for (ah = p->ahooks; ah; ah = ah->next)
	proto_reset_limit(ah->out_limit);

      /* Hack: reset exp_routes during refeed, and do not decrease it later */
      p->stats.exp_routes = 0;
    }
805

806 807
  /* Connect protocol to routing table */
  if (initial && !p->proto->multitable)
808 809 810 811
    {
      p->main_ahook = proto_add_announce_hook(p, p->table, &p->stats);
      p->main_ahook->in_filter = p->cf->in_filter;
      p->main_ahook->out_filter = p->cf->out_filter;
812
      p->main_ahook->rx_limit = p->cf->rx_limit;
813
      p->main_ahook->in_limit = p->cf->in_limit;
814
      p->main_ahook->out_limit = p->cf->out_limit;
815
      p->main_ahook->in_keep_filtered = p->cf->in_keep_filtered;
816
      proto_reset_limit(p->main_ahook->rx_limit);
817
      proto_reset_limit(p->main_ahook->in_limit);
818
      proto_reset_limit(p->main_ahook->out_limit);
819
    }
820

Ondřej Zajíček's avatar
Ondřej Zajíček committed
821
  proto_relink(p);
822
  p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
823 824 825
  ev_schedule(p->attn);
}

826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
/*
 * Flushing loop is responsible for flushing routes and protocols
 * after they went down. It runs in proto_flush_event. At the start of
 * one round, protocols waiting to flush are marked in
 * proto_schedule_flush_loop(). At the end of the round (when routing
 * table flush is complete), marked protocols are flushed and a next
 * round may start.
 */

static int flush_loop_state;	/* 1 -> running */

static void
proto_schedule_flush_loop(void)
{
  struct proto *p;
841
  struct announce_hook *h;
842 843 844 845 846 847

  if (flush_loop_state)
    return;
  flush_loop_state = 1;

  WALK_LIST(p, flush_proto_list)
848
  {
849
    p->flushing = 1;
850 851 852
    for (h=p->ahooks; h; h=h->next)
      h->table->prune_state = 1;
  }
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902

  ev_schedule(proto_flush_event);
}

static void
proto_flush_loop(void *unused UNUSED)
{
  struct proto *p;

  if (! rt_prune_loop())
    {
      /* Rtable pruning is not finished */
      ev_schedule(proto_flush_event);
      return;
    }

 again:
  WALK_LIST(p, flush_proto_list)
    if (p->flushing)
      {
	/* This will flush interfaces in the same manner
	   like rt_prune_all() flushes routes */
	if (p->proto == &proto_unix_iface)
	  if_flush_ifaces(p);

	DBG("Flushing protocol %s\n", p->name);
	p->flushing = 0;
	p->core_state = FS_HUNGRY;
	proto_relink(p);
	if (p->proto_state == PS_DOWN)
	  proto_fell_down(p);
	goto again;
      }

  /* This round finished, perhaps there will be another one */
  flush_loop_state = 0;
  if (!EMPTY_LIST(flush_proto_list))
    proto_schedule_flush_loop();
}

static void
proto_schedule_flush(struct proto *p)
{
  /* Need to abort feeding */
  if (p->core_state == FS_FEEDING)
    rt_feed_baby_abort(p);

  DBG("%s: Scheduling flush\n", p->name);
  p->core_state = FS_FLUSHING;
  proto_relink(p);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
903
  proto_unlink_ahooks(p);
904 905 906
  proto_schedule_flush_loop();
}

907 908
/* Temporary hack to propagate restart to BGP */
int proto_restart;
909

910 911 912 913 914 915 916 917
static void
proto_shutdown_loop(struct timer *t UNUSED)
{
  struct proto *p, *p_next;

  WALK_LIST_DELSAFE(p, p_next, active_proto_list)
    if (p->down_sched)
      {
918
	proto_restart = (p->down_sched == PDS_RESTART);
919 920 921

	p->disabled = 1;
	proto_rethink_goal(p);
922
	if (proto_restart)
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945
	  {
	    p->disabled = 0;
	    proto_rethink_goal(p);
	  }
      }
}

static inline void
proto_schedule_down(struct proto *p, byte restart, byte code)
{
  /* Does not work for other states (even PS_START) */
  ASSERT(p->proto_state == PS_UP);

  /* Scheduled restart may change to shutdown, but not otherwise */
  if (p->down_sched == PDS_DISABLE)
    return;

  p->down_sched = restart ? PDS_RESTART : PDS_DISABLE;
  p->down_code = code;
  tm_start_max(proto_shutdown_timer, restart ? 2 : 0);
}


946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974
/**
 * proto_request_feeding - request feeding routes to the protocol
 * @p: given protocol 
 *
 * Sometimes it is needed to send again all routes to the
 * protocol. This is called feeding and can be requested by this
 * function. This would cause protocol core state transition
 * to FS_FEEDING (during feeding) and when completed, it will
 * switch back to FS_HAPPY. This function can be called even
 * when feeding is already running, in that case it is restarted.
 */
void
proto_request_feeding(struct proto *p)
{
  ASSERT(p->proto_state == PS_UP);

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

      rt_feed_baby_abort(p);
    }

  proto_schedule_feed(p, 0);
}

975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
static const char *
proto_limit_name(struct proto_limit *l)
{
  const char *actions[] = {
    [PLA_WARN] = "warn",
    [PLA_BLOCK] = "block",
    [PLA_RESTART] = "restart",
    [PLA_DISABLE] = "disable",
  };

  return actions[l->action];
}

/**
 * proto_notify_limit: notify about limit hit and take appropriate action
 * @ah: announce hook
 * @l: limit being hit
992
 * @dir: limit direction (PLD_*)
993
 * @rt_count: the number of routes 
994 995 996
 *
 * The function is called by the route processing core when limit @l
 * is breached. It activates the limit and tooks appropriate action
997
 * according to @l->action.
998
 */
999
void
1000
proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, int dir, u32 rt_count)
1001
{
1002 1003
  const char *dir_name[PLD_MAX] = { "receive", "import" , "export" };
  const byte dir_down[PLD_MAX] = { PDC_RX_LIMIT_HIT, PDC_IN_LIMIT_HIT, PDC_OUT_LIMIT_HIT };
1004 1005
  struct proto *p = ah->proto;

1006 1007
  if (l->state == PLS_BLOCKED)
    return;
1008

1009 1010
  /* For warning action, we want the log message every time we hit the limit */
  if (!l->state || ((l->action == PLA_WARN) && (rt_count == l->limit)))
1011
    log(L_WARN "Protocol %s hits route %s limit (%d), action: %s",
1012
	p->name, dir_name[dir], l->limit, proto_limit_name(l));
1013 1014