proto.c 43.2 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
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
list  proto_list;
25

26
static list protocol_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
static timer *proto_shutdown_timer;
31 32 33 34 35 36 37 38 39
static timer *gr_wait_timer;

#define GRS_NONE	0
#define GRS_INIT	1
#define GRS_ACTIVE	2
#define GRS_DONE	3

static int graceful_restart_state;
static u32 graceful_restart_locks;
40 41

static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
42
static char *c_states[] UNUSED = { "DOWN", "START", "UP", "FLUSHING" };
43

44 45
extern struct protocol proto_unix_iface;

46
static void proto_shutdown_loop(struct timer *);
47
static void proto_rethink_goal(struct proto *p);
48
static char *proto_state_name(struct proto *p);
49 50
static void channel_verify_limits(struct channel *c);
static void channel_reset_limit(struct channel_limit *l);
51 52


53 54
static inline int proto_is_done(struct proto *p)
{ return (p->proto_state == PS_DOWN) && (p->active_channels == 0); }
55

56 57
static inline int channel_is_active(struct channel *c)
{ return (c->channel_state == CS_START) || (c->channel_state == CS_UP); }
58 59 60 61 62

static void
proto_log_state_change(struct proto *p)
{
  if (p->debug & D_STATES)
63 64 65
  {
    char *name = proto_state_name(p);
    if (name != p->last_state_name_announced)
66
    {
67 68
      p->last_state_name_announced = name;
      PD(p, "State changed to %s", proto_state_name(p));
69
    }
70
  }
71 72
  else
    p->last_state_name_announced = NULL;
73
}
74

75

76 77
struct channel_config *
proto_cf_find_channel(struct proto_config *pc, uint net_type)
78
{
79 80 81 82 83 84 85
  struct channel_config *cc;

  WALK_LIST(cc, pc->channels)
    if (cc->net_type == net_type)
      return cc;

  return NULL;
86 87
}

88 89 90 91 92 93 94 95 96
/**
 * proto_find_channel_by_table - find channel connected to a routing table
 * @p: protocol instance
 * @t: routing table
 *
 * Returns pointer to channel or NULL
 */
struct channel *
proto_find_channel_by_table(struct proto *p, struct rtable *t)
97
{
98
  struct channel *c;
99

100 101 102
  WALK_LIST(c, p->channels)
    if (c->table == t)
      return c;
103

104
  return NULL;
105 106
}

107
/**
108
 * proto_add_channel - connect protocol to a routing table
109
 * @p: protocol instance
110
 * @cf: channel configuration
111
 *
112 113 114 115
 * This function creates a channel between the protocol instance @p and the
 * routing table specified in the configuration @cf, making the protocol hear
 * all changes in the table and allowing the protocol to update routes in the
 * table.
116
 *
117 118 119
 * The channel is linked in the protocol channel list and when active also in
 * the table channel list. Channels are allocated from the global resource pool
 * (@proto_pool) and they are automatically freed when the protocol is removed.
120
 */
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180

struct channel *
proto_add_channel(struct proto *p, struct channel_config *cf)
{
  struct channel *c = mb_allocz(proto_pool, cf->channel->channel_size);

  c->name = cf->name;
  c->channel = cf->channel;
  c->proto = p;
  c->table = cf->table->table;

  c->in_filter = cf->in_filter;
  c->out_filter = cf->out_filter;
  c->rx_limit = cf->rx_limit;
  c->in_limit = cf->in_limit;
  c->out_limit = cf->out_limit;

  c->net_type = cf->net_type;
  c->ra_mode = cf->ra_mode;
  c->preference = cf->preference;
  c->merge_limit = cf->merge_limit;
  c->in_keep_filtered = cf->in_keep_filtered;

  c->channel_state = CS_DOWN;
  c->export_state = ES_DOWN;
  c->last_state_change = now;
  c->reloadable = 1;

  CALL(c->channel->init, c, cf);

  add_tail(&p->channels, &c->n);

  PD(p, "Channel %s connected to table %s", c->name, c->table->name);

  return c;
}

void
proto_remove_channel(struct proto *p, struct channel *c)
{
  ASSERT(c->channel_state == CS_DOWN);

  PD(p, "Channel %s removed", c->name);

  rem_node(&c->n);
  mb_free(c);
}


static void
proto_start_channels(struct proto *p)
{
  struct channel *c;
  WALK_LIST(c, p->channels)
    if (!c->disabled)
      channel_set_state(c, CS_UP);
}

static void
proto_pause_channels(struct proto *p)
181
{
182 183 184 185 186
  struct channel *c;
  WALK_LIST(c, p->channels)
    if (!c->disabled && channel_is_active(c))
      channel_set_state(c, CS_START);
}
187

188 189 190 191 192 193 194 195
static void
proto_stop_channels(struct proto *p)
{
  struct channel *c;
  WALK_LIST(c, p->channels)
    if (!c->disabled && channel_is_active(c))
      channel_set_state(c, CS_FLUSHING);
}
196

197 198 199 200 201 202 203 204 205 206 207 208 209
static void
proto_remove_channels(struct proto *p)
{
  struct channel *c;
  WALK_LIST_FIRST(c, p->channels)
    proto_remove_channel(p, c);
}

static void
channel_schedule_feed(struct channel *c, int initial)
{
  // DBG("%s: Scheduling meal\n", p->name);
  ASSERT(c->channel_state == CS_UP);
210

211 212
  c->export_state = ES_FEEDING;
  c->refeeding = !initial;
213

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
  ev_schedule(c->feed_event);
}

static void
channel_feed_loop(void *ptr)
{
  struct channel *c = ptr;

  if (c->export_state != ES_FEEDING)
    return;

  if (!c->feed_active)
    if (c->proto->feed_begin)
      c->proto->feed_begin(c, !c->refeeding);

  // DBG("Feeding protocol %s continued\n", p->name);
  if (!rt_feed_channel(c))
  {
    ev_schedule(c->feed_event);
    return;
  }

  // DBG("Feeding protocol %s finished\n", p->name);
  c->export_state = ES_READY;
  // proto_log_state_change(p);

  if (c->proto->feed_end)
    c->proto->feed_end(c);
}


static void
channel_start_export(struct channel *c)
{
  ASSERT(c->channel_state == CS_UP);
  ASSERT(c->export_state == ES_DOWN);

  channel_schedule_feed(c, 1);	/* Sets ES_FEEDING */
}

static void
channel_stop_export(struct channel *c)
{
  /* Need to abort feeding */
  if (c->export_state == ES_FEEDING)
    rt_feed_channel_abort(c);

  c->export_state = ES_DOWN;
262
  c->stats.exp_routes = 0;
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
}

static void
channel_do_start(struct channel *c)
{
  rt_lock_table(c->table);
  add_tail(&c->table->channels, &c->table_node);
  c->proto->active_channels++;

  c->feed_event = ev_new(c->proto->pool);
  c->feed_event->data = c;
  c->feed_event->hook = channel_feed_loop;

  channel_reset_limit(&c->rx_limit);
  channel_reset_limit(&c->in_limit);
  channel_reset_limit(&c->out_limit);

  CALL(c->channel->start, c);
}

static void
channel_do_flush(struct channel *c)
{
  rt_schedule_prune(c->table);

  c->gr_wait = 0;
  if (c->gr_lock)
    channel_graceful_restart_unlock(c);

  CALL(c->channel->shutdown, c);
}

static void
channel_do_down(struct channel *c)
{
298
  rem_node(&c->table_node);
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
  rt_unlock_table(c->table);
  c->proto->active_channels--;

  if ((c->stats.imp_routes + c->stats.filt_routes) != 0)
    log(L_ERR "%s: Channel %s is down but still has some routes", c->proto->name, c->name);

  memset(&c->stats, 0, sizeof(struct proto_stats));

  /* Schedule protocol shutddown */
  if (proto_is_done(c->proto))
    ev_schedule(c->proto->event);
}

void
channel_set_state(struct channel *c, uint state)
{
  uint cs = c->channel_state;
  uint es = c->export_state;

318
  DBG("%s reporting channel %s state transition %s -> %s\n", c->proto->name, c->name, c_states[cs], c_states[state]);
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
  if (state == cs)
    return;

  c->channel_state = state;
  c->last_state_change = now;

  switch (state)
  {
  case CS_START:
    ASSERT(cs == CS_DOWN || cs == CS_UP);

    if (cs == CS_DOWN)
      channel_do_start(c);

    if (es != ES_DOWN)
      channel_stop_export(c);

    break;

  case CS_UP:
    ASSERT(cs == CS_DOWN || cs == CS_START);

    if (cs == CS_DOWN)
      channel_do_start(c);

344
    if (!c->gr_wait && c->proto->rt_notify)
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
      channel_start_export(c);

    break;

  case CS_FLUSHING:
    ASSERT(cs == CS_START || cs == CS_UP);

    if (es != ES_DOWN)
      channel_stop_export(c);

    channel_do_flush(c);
    break;

  case CS_DOWN:
    ASSERT(cs == CS_FLUSHING);

    channel_do_down(c);
    break;

  default:
    ASSERT(0);
  }
  // XXXX proto_log_state_change(c);
368 369
}

370
/**
371 372
 * channel_request_feeding - request feeding routes to the channel
 * @c: given channel
373
 *
374 375 376 377 378
 * Sometimes it is needed to send again all routes to the channel. This is
 * called feeding and can be requested by this function. This would cause
 * channel export state transition to ES_FEEDING (during feeding) and when
 * completed, it will switch back to ES_READY. This function can be called
 * even when feeding is already running, in that case it is restarted.
379
 */
380 381
void
channel_request_feeding(struct channel *c)
382
{
383
  ASSERT(c->channel_state == CS_UP);
384

385 386 387
  /* Do nothing if we are still waiting for feeding */
  if (c->export_state == ES_DOWN)
    return;
388

389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
  /* If we are already feeding, we want to restart it */
  if (c->export_state == ES_FEEDING)
  {
    /* Unless feeding is in initial state */
    if (!c->feed_active)
	return;

    rt_feed_channel_abort(c);
  }

  channel_reset_limit(&c->out_limit);

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

  channel_schedule_feed(c, 0);	/* Sets ES_FEEDING */
  // proto_log_state_change(c);
}

static inline int
channel_reloadable(struct channel *c)
{
  return c->proto->reload_routes && c->reloadable;
412 413
}

414
static void
415
channel_request_reload(struct channel *c)
416
{
417 418 419 420
  ASSERT(c->channel_state == CS_UP);
  // ASSERT(channel_reloadable(c));

  c->proto->reload_routes(c);
421

422 423 424 425 426 427
  /*
   * Should this be done before reload_routes() hook?
   * Perhaps, but routes are updated asynchronously.
   */
  channel_reset_limit(&c->rx_limit);
  channel_reset_limit(&c->in_limit);
428 429
}

430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
const struct channel_class channel_basic = {
  .channel_size = sizeof(struct channel),
  .config_size = sizeof(struct channel_config)
};

void *
channel_config_new(const struct channel_class *cc, uint net_type, struct proto_config *proto)
{
  struct channel_config *cf = NULL;
  struct rtable_config *tab = NULL;
  const char *name = NULL;

  if (net_type)
  {
    if (!net_val_match(net_type, proto->protocol->channel_mask))
      cf_error("Unsupported channel type");

    if (proto->net_type && (net_type != proto->net_type))
      cf_error("Different channel type");

    tab = new_config->def_tables[net_type];
    name = net_label[net_type];
  }

  if (!cc)
    cc = &channel_basic;

  cf = cfg_allocz(cc->config_size);
  cf->name = name;
  cf->channel = cc;
  cf->table = tab;
  cf->out_filter = FILTER_REJECT;

  cf->net_type = net_type;
  cf->ra_mode = RA_OPTIMAL;
  cf->preference = proto->protocol->preference;

  add_tail(&proto->channels, &cf->n);

  return cf;
}

struct channel_config *
channel_copy_config(struct channel_config *src, struct proto_config *proto)
{
  struct channel_config *dst = cfg_alloc(src->channel->config_size);

  memcpy(dst, src, src->channel->config_size);
  add_tail(&proto->channels, &dst->n);
  CALL(src->channel->copy_config, dst, src);

  return dst;
}


static int reconfigure_type;  /* Hack to propagate type info to channel_reconfigure() */

int
channel_reconfigure(struct channel *c, struct channel_config *cf)
{
  /* FIXME: better handle these changes, also handle in_keep_filtered */
  if ((c->table != cf->table->table) || (c->ra_mode != cf->ra_mode))
    return 0;

  int import_changed = !filter_same(c->in_filter, cf->in_filter);
  int export_changed = !filter_same(c->out_filter, cf->out_filter);

  if (c->preference != cf->preference)
    import_changed = 1;

  if (c->merge_limit != cf->merge_limit)
    export_changed = 1;

  /* Reconfigure channel fields */
  c->in_filter = cf->in_filter;
  c->out_filter = cf->out_filter;
  c->rx_limit = cf->rx_limit;
  c->in_limit = cf->in_limit;
  c->out_limit = cf->out_limit;

  // c->ra_mode = cf->ra_mode;
  c->merge_limit = cf->merge_limit;
  c->preference = cf->preference;
  c->in_keep_filtered = cf->in_keep_filtered;

  channel_verify_limits(c);

  CALL(c->channel->reconfigure, c, cf);

  /* If the channel is not open, it has no routes and we cannot reload it anyways */
  if (c->channel_state != CS_UP)
    return 1;

  if (reconfigure_type == RECONFIG_SOFT)
  {
    if (import_changed)
      log(L_INFO "Channel %s.%s changed import", c->proto->name, c->name);

    if (export_changed)
      log(L_INFO "Channel %s.%s changed export", c->proto->name, c->name);

    return 1;
  }

  /* Route reload may be not supported */
  if (import_changed && !channel_reloadable(c))
    return 0;

  if (import_changed || export_changed)
    log(L_INFO "Reloading channel %s.%s", c->proto->name, c->name);

  if (import_changed)
    channel_request_reload(c);

  if (export_changed)
    channel_request_feeding(c);

  return 1;
}


int
proto_configure_channel(struct proto *p, struct channel **pc, struct channel_config *cf)
553
{
554
  struct channel *c = *pc;
555

556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
  if (!c && cf)
  {
    *pc = proto_add_channel(p, cf);
  }
  else if (c && !cf)
  {
    if (c->channel_state != CS_DOWN)
    {
      log(L_INFO "Cannot remove channel %s.%s", c->proto->name, c->name);
      return 0;
    }

    proto_remove_channel(p, c);
    *pc = NULL;
  }
  else if (c && cf)
  {
    if (!channel_reconfigure(c, cf))
    {
      log(L_INFO "Cannot reconfigure channel %s.%s", c->proto->name, c->name);
      return 0;
    }
  }

  return 1;
581 582
}

583

584
static void
585
proto_event(void *ptr)
586
{
587 588 589 590 591 592 593
  struct proto *p = ptr;

  if (p->do_start)
  {
    if_feed_baby(p);
    p->do_start = 0;
  }
594

595
  if (p->do_stop)
596
  {
597 598 599
    if (p->proto == &proto_unix_iface)
      if_flush_ifaces(p);
    p->do_stop = 0;
600 601
  }

602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
  if (proto_is_done(p))
  {
    if (p->proto->cleanup)
      p->proto->cleanup(p);

    p->active = 0;
    proto_log_state_change(p);
    proto_rethink_goal(p);
  }
}


/**
 * proto_new - create a new protocol instance
 * @c: protocol configuration
 *
 * When a new configuration has been read in, the core code starts
 * initializing all the protocol instances configured by calling their
 * 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.
 */
void *
proto_new(struct proto_config *cf)
{
  struct proto *p = mb_allocz(proto_pool, cf->protocol->proto_size);

  p->cf = cf;
  p->debug = cf->debug;
  p->mrtdump = cf->mrtdump;
  p->name = cf->name;
  p->proto = cf->protocol;
  p->net_type = cf->net_type;
  p->disabled = cf->disabled;
  p->hash_key = random_u32();
  cf->proto = p;

  init_list(&p->channels);

  return p;
}

static struct proto *
proto_init(struct proto_config *c, node *n)
{
  struct protocol *pr = c->protocol;
  struct proto *p = pr->init(c);

  p->proto_state = PS_DOWN;
  p->last_state_change = now;
  insert_node(&p->n, n);

  p->event = ev_new(proto_pool);
  p->event->hook = proto_event;
  p->event->data = p;

  PD(p, "Initializing%s", p->disabled ? " [disabled]" : "");

  return p;
}

static void
proto_start(struct proto *p)
{
  /* Here we cannot use p->cf->name since it won't survive reconfiguration */
  p->pool = rp_new(proto_pool, p->proto->name);

  if (graceful_restart_state == GRS_INIT)
    p->gr_recovery = 1;
672 673
}

674

675 676 677
/**
 * proto_config_new - create a new protocol configuration
 * @pr: protocol the configuration will belong to
678
 * @class: SYM_PROTO or SYM_TEMPLATE
679 680 681 682 683 684 685 686
 *
 * 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.
687 688 689 690 691
 *
 * 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()).
692
 */
693
void *
694
proto_config_new(struct protocol *pr, int class)
695
{
696
  struct proto_config *cf = cfg_allocz(pr->config_size);
697

698
  if (class == SYM_PROTO)
699 700 701 702 703 704 705 706 707 708 709 710
    add_tail(&new_config->protos, &cf->n);

  cf->global = new_config;
  cf->protocol = pr;
  cf->name = pr->name;
  cf->class = class;
  cf->debug = new_config->proto_default_debug;
  cf->mrtdump = new_config->proto_default_mrtdump;

  init_list(&cf->channels);

  return cf;
711 712
}

713

714 715 716 717 718 719 720 721 722 723 724 725 726 727
/**
 * 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)
{
728
  struct channel_config *cc;
729 730 731 732 733 734 735 736 737 738 739 740
  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);

741
  /*
742 743 744 745 746 747 748 749
   * 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;

750
  memcpy(dest, src, src->protocol->config_size);
751 752 753 754

  dest->n = old_node;
  dest->class = old_class;
  dest->name = old_name;
755
  init_list(&dest->channels);
756

757 758 759 760
  WALK_LIST(cc, src->channels)
    channel_copy_config(cc, dest);

  /* FIXME: allow for undefined copy_config */
761 762 763
  dest->protocol->copy_config(dest, src);
}

764 765 766 767 768 769 770 771
/**
 * 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.
 */
772
void
773
protos_preconfig(struct config *c)
774
{
775 776
  struct protocol *p;

777
  init_list(&c->protos);
778
  DBG("Protocol preconfig:");
779
  WALK_LIST(p, protocol_list)
780 781 782 783 784 785
  {
    DBG(" %s", p->name);
    p->name_counter = 0;
    if (p->preconfig)
      p->preconfig(p, c);
  }
786
  DBG("\n");
787 788
}

789 790 791 792 793 794 795 796 797
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) ||
798 799 800
      (nc->net_type != oc->net_type) ||
      (nc->disabled != p->disabled))

801 802
    return 0;

803
  p->name = nc->name;
804 805
  p->debug = nc->debug;
  p->mrtdump = nc->mrtdump;
806
  reconfigure_type = type;
807 808

  /* Execute protocol specific reconfigure hook */
809
  if (!p->proto->reconfigure || !p->proto->reconfigure(p, nc))
810 811 812 813 814 815 816 817 818
    return 0;

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

  return 1;
}

819 820 821 822 823 824
/**
 * 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)
825
 * @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
826 827 828 829 830 831 832 833 834 835 836 837
 *
 * 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.
 *
838 839 840 841 842 843 844 845
 * 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.
846
 */
847
void
848
protos_commit(struct config *new, struct config *old, int force_reconfig, int type)
849
{
850
  struct proto_config *oc, *nc;
851
  struct symbol *sym;
852 853 854
  struct proto *p;
  node *n;

855

856 857
  DBG("protos_commit:\n");
  if (old)
858 859
  {
    WALK_LIST(oc, old->protos)
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
      p = oc->proto;
      sym = cf_find_symbol(new, oc->name);
      if (sym && sym->class == SYM_PROTO && !new->shutdown)
      {
	/* Found match, let's check if we can smoothly switch to new configuration */
	/* No need to check description */
	nc = sym->def;
	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 */
	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);

	p->down_code = nc->disabled ? PDC_CF_DISABLE : PDC_CF_RESTART;
	p->cf_new = nc;
      }
      else if (!new->shutdown)
      {
	log(L_INFO "Removing protocol %s", p->name);
	p->down_code = PDC_CF_REMOVE;
	p->cf_new = NULL;
      }
      else /* global shutdown */
      {
	p->down_code = PDC_CMD_SHUTDOWN;
	p->cf_new = NULL;
      }

      p->reconfiguring = 1;
      config_add_obstacle(old);
      proto_rethink_goal(p);
900
    }
901 902 903
  }

  struct proto *first_dev_proto = NULL;
904

905
  n = NODE &(proto_list.head);
906 907
  WALK_LIST(nc, new->protos)
    if (!nc->proto)
908 909 910 911 912 913 914 915 916 917 918 919 920
    {
      /* Not a first-time configuration */
      if (old)
	log(L_INFO "Adding protocol %s", nc->name);

      p = proto_init(nc, n);
      n = NODE p;

      if (p->proto == &proto_unix_iface)
	first_dev_proto = p;
    }
    else
      n = NODE nc->proto;
921 922

  DBG("Protocol start\n");
923 924

  /* Start device protocol first */
925 926
  if (first_dev_proto)
    proto_rethink_goal(first_dev_proto);
927

928 929 930
  /* 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)
931 932 933 934 935
  {
    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");
  }
936

937 938
  /* Start all new protocols */
  WALK_LIST_DELSAFE(p, n, proto_list)
939
    proto_rethink_goal(p);
940 941
}

942
static void
943
proto_rethink_goal(struct proto *p)
944
{
945
  struct protocol *q;
946
  byte goal;
947

948 949 950 951 952 953 954 955 956 957 958 959 960 961 962
  if (p->reconfiguring && !p->active)
  {
    struct proto_config *nc = p->cf_new;
    node *n = p->n.prev;
    DBG("%s has shut down for reconfiguration\n", p->name);
    p->cf->proto = NULL;
    config_del_obstacle(p->cf->global);
    proto_remove_channels(p);
    rem_node(&p->n);
    rfree(p->event);
    mb_free(p);
    if (!nc)
      return;
    p = proto_init(nc, n);
  }
963 964

  /* Determine what state we want to reach */
965
  if (p->disabled || p->reconfiguring)
966
    goal = PS_DOWN;
967
  else
968
    goal = PS_UP;
969 970

  q = p->proto;
971 972 973
  if (goal == PS_UP)
  {
    if (!p->active)
974
    {
975 976 977 978 979
      /* Going up */
      DBG("Kicking %s up\n", p->name);
      PD(p, "Starting");
      proto_start(p);
      proto_notify_state(p, (q->start ? q->start(p) : PS_UP));
980
    }
981 982 983 984
  }
  else
  {
    if (p->proto_state == PS_START || p->proto_state == PS_UP)
985
    {
986 987 988 989
      /* Going down */
      DBG("Kicking %s down\n", p->name);
      PD(p, "Shutting down");
      proto_notify_state(p, (q->shutdown ? q->shutdown(p) : PS_DOWN));
990
    }
991
  }
992 993
}

994

995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
/**
 * DOC: Graceful restart recovery
 *
 * Graceful restart of a router is a process when the routing plane (e.g. BIRD)
 * restarts but both the forwarding plane (e.g kernel routing table) and routing
 * neighbors keep proper routes, and therefore uninterrupted packet forwarding
 * is maintained.
 *
 * BIRD implements graceful restart recovery by deferring export of routes to
 * protocols until routing tables are refilled with the expected content. After
 * start, protocols generate routes as usual, but routes are not propagated to
 * them, until protocols report that they generated all routes. After that,
 * graceful restart recovery is finished and the export (and the initial feed)
 * to protocols is enabled.
 *
 * When graceful restart recovery need is detected during initialization, then
 * enabled protocols are marked with @gr_recovery flag before start. Such
 * protocols then decide how to proceed with graceful restart, participation is
1013
 * voluntary. Protocols could lock the recovery for each channel by function
1014
 * channel_graceful_restart_lock() (state stored in @gr_lock flag), which means
1015 1016 1017 1018 1019 1020
 * that they want to postpone the end of the recovery until they converge and
 * then unlock it. They also could set @gr_wait before advancing to %PS_UP,
 * which means that the core should defer route export to that channel until
 * the end of the recovery. This should be done by protocols that expect their
 * neigbors to keep the proper routes (kernel table, BGP sessions with BGP
 * graceful restart capability).
1021 1022 1023 1024 1025
 *
 * The graceful restart recovery is finished when either all graceful restart
 * locks are unlocked or when graceful restart wait timer fires.
 *
 */
1026

1027
static void graceful_restart_done(struct timer *t);
1028

1029 1030 1031 1032 1033 1034 1035
/**
 * graceful_restart_recovery - request initial graceful restart recovery
 *
 * Called by the platform initialization code if the need for recovery
 * after graceful restart is detected during boot. Have to be called
 * before protos_commit().
 */
1036 1037 1038 1039 1040 1041
void
graceful_restart_recovery(void)
{
  graceful_restart_state = GRS_INIT;
}

1042 1043 1044 1045 1046 1047 1048
/**
 * graceful_restart_init - initialize graceful restart
 *
 * When graceful restart recovery was requested, the function starts an active
 * phase of the recovery and initializes graceful restart wait timer. The
 * function have to be called after protos_commit().
 */
1049 1050 1051 1052 1053 1054 1055 1056 1057
void
graceful_restart_init(void)
{
  if (!graceful_restart_state)
    return;

  log(L_INFO "Graceful restart started");

  if (!graceful_restart_locks)
1058 1059 1060 1061
  {
    graceful_restart_done(NULL);
    return;
  }
1062 1063 1064 1065 1066 1067 1068

  graceful_restart_state = GRS_ACTIVE;
  gr_wait_timer = tm_new(proto_pool);
  gr_wait_timer->hook = graceful_restart_done;
  tm_start(gr_wait_timer, config->gr_wait);
}

1069 1070 1071 1072 1073 1074 1075 1076 1077
/**
 * graceful_restart_done - finalize graceful restart
 *
 * When there are no locks on graceful restart, the functions finalizes the
 * graceful restart recovery. Protocols postponing route export until the end of
 * the recovery are awakened and the export to them is enabled. All other
 * related state is cleared. The function is also called when the graceful
 * restart wait timer fires (but there are still some locks).
 */
1078 1079 1080 1081 1082 1083
static void
graceful_restart_done(struct timer *t UNUSED)
{
  log(L_INFO "Graceful restart done");
  graceful_restart_state = GRS_DONE;

1084 1085 1086 1087 1088
  struct proto *p;
  WALK_LIST(p, proto_list)
  {
    if (!p->gr_recovery)
      continue;
1089

1090 1091 1092
    struct channel *c;
    WALK_LIST(c, p->channels)
    {
1093
      /* Resume postponed export of routes */
1094
      if ((c->channel_state == CS_UP) && c->gr_wait && c->proto->rt_notify)
1095
	channel_start_export(c);
1096 1097

      /* Cleanup */
1098 1099
      c->gr_wait = 0;
      c->gr_lock = 0;
1100 1101
    }

1102 1103 1104
    p->gr_recovery = 0;
  }

1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
  graceful_restart_locks = 0;
}

void
graceful_restart_show_status(void)
{
  if (graceful_restart_state != GRS_ACTIVE)
    return;

  cli_msg(-24, "Graceful restart recovery in progress");
1115
  cli_msg(-24, "  Waiting for %d channels to recover", graceful_restart_locks);
1116 1117 1118
  cli_msg(-24, "  Wait timer is %d/%d", tm_remains(gr_wait_timer), config->gr_wait);
}

1119
/**
1120 1121
 * channel_graceful_restart_lock - lock graceful restart by channel
 * @p: channel instance
1122 1123 1124
 *
 * This function allows a protocol to postpone the end of graceful restart
 * recovery until it converges. The lock is removed when the protocol calls
1125
 * channel_graceful_restart_unlock() or when the channel is closed.
1126 1127 1128 1129 1130 1131
 *
 * The function have to be called during the initial phase of graceful restart
 * recovery and only for protocols that are part of graceful restart (i.e. their
 * @gr_recovery is set), which means it should be called from protocol start
 * hooks.
 */
1132
void
1133
channel_graceful_restart_lock(struct channel *c)
1134 1135
{
  ASSERT(graceful_restart_state == GRS_INIT);
1136
  ASSERT(c->proto->gr_recovery);
1137

1138
  if (c->gr_lock)
1139 1140
    return;

1141
  c->gr_lock = 1;
1142 1143 1144
  graceful_restart_locks++;
}

1145
/**
1146 1147
 * channel_graceful_restart_unlock - unlock graceful restart by channel
 * @p: channel instance
1148
 *
1149
 * This function unlocks a lock from channel_graceful_restart_lock(). It is also
1150 1151
 * automatically called when the lock holding protocol went down.
 */
1152
void
1153
channel_graceful_restart_unlock(struct channel *c)
1154
{
1155
  if (!c->gr_lock)
1156 1157
    return;

1158
  c->gr_lock = 0;
1159 1160 1161 1162 1163 1164 1165 1166
  graceful_restart_locks--;

  if ((graceful_restart_state == GRS_ACTIVE) && !graceful_restart_locks)
    tm_start(gr_wait_timer, 0);
}



1167 1168 1169 1170 1171 1172 1173 1174 1175
/**
 * 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.
 */
1176 1177 1178 1179 1180
void
protos_dump_all(void)
{
  debug("Protocols:\n");

1181 1182 1183 1184 1185 1186 1187
  struct proto *p;
  WALK_LIST(p, proto_list)
  {
    debug("  protocol %s state %s\n", p->name, p_states[p->proto_state]);

    struct channel *c;
    WALK_LIST(c, p->channels)
1188
    {
1189 1190 1191 1192 1193
      debug("\tTABLE %s\n", c->table->name);
      if (c->in_filter)
	debug("\tInput filter: %s\n", filter_name(c->in_filter));
      if (c->out_filter)
	debug("\tOutput filter: %s\n", filter_name(c->out_filter));
1194
    }
1195 1196 1197 1198

    if (p->proto->dump && (p->proto_state != PS_DOWN))
      p->proto->dump(p);
  }
1199 1200
}

1201 1202 1203 1204 1205 1206
/**
 * 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
1207
 * all platform specific protocols to inform the core that they exist.
1208
 */
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
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;
    }
}

1220 1221 1222
/* FIXME: convert this call to some protocol hook */
extern void bfd_init_all(void);

1223 1224 1225 1226 1227 1228 1229 1230 1231
/**
 * 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.
 */
1232 1233 1234
void
protos_build(void)
{
1235
  init_list(&proto_list);
1236 1237
  init_list(&protocol_list);

1238
  proto_build(&proto_device);
1239 1240 1241
#ifdef CONFIG_RADV
  proto_build(&proto_radv);
#endif
1242
#ifdef CONFIG_RIP
1243
  proto_build(&proto_rip);
1244 1245
#endif
#ifdef CONFIG_STATIC
1246
  proto_build(&proto_static);
Ondřej Filip's avatar
Ondřej Filip committed
1247 1248
#endif
#ifdef CONFIG_OSPF
1249
  proto_build(&proto_ospf);
1250 1251
#endif
#ifdef CONFIG_PIPE
1252
  proto_build(&proto_pipe);
1253 1254
#endif
#ifdef CONFIG_BGP
1255
  proto_build(&proto_bgp);
1256
#endif
1257
#ifdef CONFIG_BFD
1258
  proto_build(&proto_bfd);
1259 1260
  bfd_init_all();
#endif
1261

1262
  proto_pool = rp_new(&root_pool, "Protocols");
1263 1264
  proto_shutdown_timer = tm_new(proto_pool);
  proto_shutdown_timer->hook = proto_shutdown_loop;
1265 1266
}

1267

1268 1269
/* Temporary hack to propagate restart to BGP */
int proto_restart;
1270

1271 1272 1273 1274 1275
static void
proto_shutdown_loop(struct timer *t UNUSED)
{
  struct proto *p, *p_next;

1276
  WALK_LIST_DELSAFE(p, p_next, proto_list)
1277
    if (p->down_sched)
1278 1279
    {
      proto_restart = (p->down_sched == PDS_RESTART);
1280

1281 1282 1283 1284 1285
      p->disabled = 1;
      proto_rethink_goal(p);
      if (proto_restart)
      {
	p->disabled = 0;
1286 1287
	proto_rethink_goal(p);
      }
1288
    }
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
}

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);
}


static const char *
1308
channel_limit_name(struct channel_limit *l)
1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320
{
  const char *actions[] = {
    [PLA_WARN] = "warn",
    [PLA_BLOCK] = "block",
    [PLA_RESTART] = "restart",
    [PLA_DISABLE] = "disable",
  };

  return actions[l->action];
}

/**
1321 1322
 * channel_notify_limit: notify about limit hit and take appropriate action
 * @c: channel
1323
 * @l: limit being hit
1324
 * @dir: limit direction (PLD_*)
1325
 * @rt_count: the number of routes
1326 1327 1328
 *
 * The function is called by the route processing core when limit @l
 * is breached. It activates the limit and tooks appropriate action
1329
 * according to @l->action.
1330
 */
1331
void
1332
channel_notify_limit(struct channel *c, struct channel_limit *l, int dir, u32 rt_count)
1333
{
1334 1335
  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 };
1336
  struct proto *p = c->proto;
1337

1338 1339
  if (l->state == PLS_BLOCKED)
    return;
1340

1341 1342
  /* 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)))
1343
    log(L_WARN "Protocol %s hits route %s limit (%d), action: %s",
1344
	p->name, dir_name[dir], l->limit, channel_limit_name(l));
1345 1346

  switch (l->action)
1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362
  {
  case PLA_WARN:
    l->state = PLS_ACTIVE;
    break;

  case PLA_BLOCK:
    l->state = PLS_BLOCKED;
    break;

  case PLA_RESTART:
  case PLA_DISABLE:
    l->state = PLS_BLOCKED;
    if (p->proto_state == PS_UP)
      proto_schedule_down(p, l->action == PLA_RESTART, dir_down[dir]);
    break;
  }
1363 1364
}

1365 1366
static void
channel_verify_limits(struct channel *c)
1367
{
1368 1369
  struct channel_limit *l;
  u32 all_routes = c->stats.imp_routes + c->stats.filt_routes;
1370

1371 1372 1373
  l = &c->rx_limit;
  if (l->action && (all_routes > l->limit))
    channel_notify_limit(c, l, PLD_RX, all_routes);
1374

1375 1376 1377
  l = &c->in_limit;
  if (l->action && (c->stats.imp_routes > l->limit))
    channel_notify_limit(c, l, PLD_IN, c->stats.imp_routes);
1378

1379 1380 1381
  l = &c->out_limit;
  if (l->action && (c->stats.exp_routes > l->limit))
    channel_notify_limit(c, l, PLD_OUT, c->stats.exp_routes);
1382 1383
}

1384 1385
static inline void
channel_reset_limit(struct channel_limit *l)
1386
{
1387 1388
  if (l->action)
    l->state = PLS_INITIAL;
1389 1390
}

1391 1392
static inline void
proto_do_start(struct proto *p)
1393
{
1394 1395 1396
  p->active = 1;
  p->do_start = 1;
  ev_schedule(p->event);
1397 1398 1399
}

static void
1400
proto_do_up(struct proto *p)
1401
{
1402 1403 1404 1405 1406
  if (!p->main_source)
  {
    p->main_source = rt_get_source(p, 0);
    rt_lock_source(p->main_source);
  }
1407

1408
  proto_start_channels(p);
1409 1410
}

1411 1412
static inline void
proto_do_pause(struct proto *p)
1413
{
1414
  proto_pause_channels(p);
1415 1416 1417
}

static void
1418
proto_do_stop(struct proto *p)
1419
{
1420
  p->down_sched = 0;
1421
  p->gr_recovery = 0;
1422

1423 1424
  p->do_stop = 1;
  ev_schedule(p->event);
1425

1426 1427 1428 1429 1430
  if (p->main_source)
  {
    rt_unlock_source(p->main_source);
    p->main_source = NULL;
  }
1431

1432 1433
  proto_stop_channels(p);
}
1434

1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445
static void
proto_do_down(struct proto *p)
{
  p->down_code = 0;
  neigh_prune();
  rfree(p->pool);
  p->pool = NULL;

  /* Shutdown is finished in the protocol event */
  if (proto_is_done(p))
    ev_schedule(p->event);
1446 1447
}

1448

1449

1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
/**
 * proto_notify_state - notify core about protocol state change
 * @p: protocol the state of which has changed
 * @ps: the new status
 *
 * Whenever a state of a protocol changes due to some event internal
 * to the protocol (i.e., not inside a start() or shutdown() hook),
 * it should immediately notify the core about the change by calling
 * proto_notify_state() which will write the new state to the &proto
 * structure and take all the actions necessary to adapt to the new
1460 1461 1462
 * state. State change to PS_DOWN immediately frees resources of protocol
 * and might execute start callback of protocol; therefore,
 * it should be used at tail positions of protocol callbacks.
1463
 */
1464
void
1465
proto_notify_state(struct proto *p, uint state)
1466
{
1467
  uint ps = p->proto_state;
1468

1469 1470
  DBG("%s reporting state transition %s -> %s\n", p->name, p_states[ps], p_states[state]);
  if (state == ps)
1471 1472
    return;

1473
  p->proto_state = state;
1474
  p->last_state_change = now;
1475

1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511
  switch (state)
  {
  case PS_START:
    ASSERT(ps == PS_DOWN || ps == PS_UP);

    if (ps == PS_DOWN)
      proto_do_start(p);
    else
      proto_do_pause(p);
    break;

  case PS_UP:
    ASSERT(ps == PS_DOWN || ps == PS_START);

    if (ps == PS_DOWN)
      proto_do_start(p);

    proto_do_up(p);
    break;

  case PS_STOP:
    ASSERT(ps == PS_START || ps == PS_UP);

    proto_do_stop(p);
    break;

  case PS_DOWN:
    if (ps != PS_STOP)
      proto_do_stop(p);

    proto_do_down(p);
    break;

  default:
    bug("%s: Invalid state %d", p->name, ps);
  }
1512 1513

  proto_log_state_change(p);
1514
}
1515

1516 1517 1518 1519 1520 1521 1522
/*
 *  CLI Commands
 */

static char *
proto_state_name(struct proto *p)
{
1523 1524 1525 1526 1527 1528 1529 1530
  switch (p->proto_state)
  {
  case PS_DOWN:		return p->active ? "flush" : "down";
  case PS_START:	return "start";
  case PS_UP:		return "up";
  case PS_STOP:		return "stop";
  default:		return "???";
  }
1531 1532
}

1533
static void
1534
channel_show_stats(struct channel *c)
1535
{
1536 1537 1538 1539 1540
  struct proto_stats *s = &c->stats;

  if (c->in_keep_filtered)
    cli_msg(-1006, "    Routes:         %u imported, %u filtered, %u exported",
	    s->imp_routes, s->filt_routes, s->exp_routes);
1541
  else
1542 1543
    cli_msg(-1006, "    Routes:         %u imported, %u exported",
	    s->imp_routes, s->exp_routes);
1544

1545 1546
  cli_msg(-1006, "    Route change stats:     received   rejected   filtered    ignored   accepted");
  cli_msg(-1006, "      Import updates:     %10u %10u %10u %10u %10u",
1547 1548 1549
	  s->imp_updates_received, s->imp_updates_invalid,
	  s->imp_updates_filtered, s->imp_updates_ignored,
	  s->imp_updates_accepted);
1550
  cli_msg(-1006, "      Import withdraws:   %10u %10u        --- %10u %10u",
1551 1552
	  s->imp_withdraws_received, s->imp_withdraws_invalid,
	  s->imp_withdraws_ignored, s->imp_withdraws_accepted);
1553
  cli_msg(-1006, "      Export updates:     %10u %10u %10u        --- %10u",
1554 1555
	  s->exp_updates_received, s->exp_updates_rejected,
	  s->exp_updates_filtered, s->exp_updates_accepted);
1556
  cli_msg(-1006, "      Export withdraws:   %10u        ---        ---        --- %10u",
1557 1558 1559
	  s->exp_withdraws_received, s->exp_withdraws_accepted);
}

1560
void
1561
channel_show_limit(struct channel_limit *l, const char *dsc)
1562
{
1563
  if (!l->action)
1564 1565
    return;

1566 1567
  cli_msg(-1006, "    %-16s%d%s", dsc, l->limit, l->state ? " [HIT]" : "");
  cli_msg(-1006, "      Action:       %s", channel_limit_name(l));
1568 1569
}

1570
void
1571
channel_show_info(struct channel *c)
1572
{
1573 1574 1575 1576 1577
  cli_msg(-1006, "  Channel %s", c->name);
  cli_msg(-1006, "    Table:          %s", c->table->name);
  cli_msg(-1006, "    Preference:     %d", c->preference);
  cli_msg(-1006, "    Input filter:   %s", filter_name(c->in_filter));
  cli_msg(-1006, "    Output filter:  %s", filter_name(c->out_filter));
1578

1579
  if (graceful_restart_state == GRS_ACTIVE)
1580 1581 1582
    cli_msg(-1006, "    GR recovery:   %s%s",
	    c->gr_lock ? " pending" : "",
	    c->gr_wait ? " waiting" : "");
1583

1584 1585 1586
  channel_show_limit(&c->rx_limit, "Receive limit:");
  channel_show_limit(&c->in_limit, "Import limit:");
  channel_show_limit(&c->out_limit, "Export limit:");
1587

1588 1589
  if (c->channel_state != CS_DOWN)
    channel_show_stats(c);
1590 1591
}

1592
void
Pavel Tvrdík's avatar
Pavel Tvrdík committed
1593
proto_cmd_show(struct proto *p, uint verbose, int cnt)
1594
{
1595
  byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
1596

1597 1598 1599 1600
  /* First protocol - show header */
  if (!cnt)
    cli_msg(-2002, "name     proto    table    state  since       info");

1601 1602 1603
  buf[0] = 0;
  if (p->proto->get_status)
    p->proto->get_status(p, buf);
1604 1605
  tm_format_datetime(tbuf, &config->tf_proto, p->last_state_change);
  cli_msg(-1002, "%-8s %-8s %-8s %-5s  %-10s  %s",
1606 1607
	  p->name,
	  p->proto->name,
1608
	  p->main_channel ? p->main_channel->table->name : "---",
1609
	  proto_state_name(p),
1610
	  tbuf,
1611
	  buf);
1612

1613
  if (verbose)
Ondřej Zajíček's avatar