Commit 1f85226e authored by Ondrej Filip's avatar Ondrej Filip
Browse files

Merge branch 'master' of ssh://git.nic.cz/bird

parents 92f8f7e3 d9b77cc2
Loading
Loading
Loading
Loading
+13 −7
Original line number Diff line number Diff line
@@ -431,13 +431,19 @@ to zero to disable it. An empty <cf><m/switch/</cf> is equivalent to <cf/on/
	<tag>export <m/filter/</tag> This is similar to the <cf>import</cf> keyword, except that it
	works in the direction from the routing table to the protocol. Default: <cf/none/.

	<tag>import limit <m/number/ exceed warn | block | restart | disable</tag>
	Specify an import route limit and the action to be taken when
	the limit is hit. Warn action just prints warning log
	message. Block action ignores new routes (and converts route
	updates to withdraws) coming from the protocol. Restart and
	disable actions shut the protocol down like appropriate
	commands. Default: <cf/none/.
	<tag>import limit <m/number/ [exceed warn | block | restart | disable]</tag>
	Specify an import route limit (a maximum number of routes
	imported from the protocol) and optionally the action to be
	taken when the limit is hit. Warn action just prints warning
	log message. Block action ignores new routes coming from the
	protocol. Restart and disable actions shut the protocol down
	like appropriate commands. Disable is the default action if an
	action is not explicitly specified.  Default: <cf/none/.

	<tag>export limit <m/number/ [exceed warn | block | restart | disable]</tag>
	Specify an export route limit, works similarly to
	the <cf>import limit</cf> option, but for the routes exported
	to the protocol. Default: <cf/none/.

	<tag>description "<m/text/"</tag> This is an optional
	description of the protocol. It is displayed as a part of the
+8 −6
Original line number Diff line number Diff line
@@ -179,6 +179,7 @@ proto_item:
 | IMPORT imexport { this_proto->in_filter = $2; }
 | EXPORT imexport { this_proto->out_filter = $2; }
 | IMPORT LIMIT limit_spec { this_proto->in_limit = $3; }
 | EXPORT LIMIT limit_spec { this_proto->out_limit = $3; }
 | TABLE rtable { this_proto->table = $2; }
 | ROUTER ID idval { this_proto->router_id = $3; }
 | DESCRIPTION TEXT { this_proto->dsc = $2; }
@@ -192,17 +193,18 @@ imexport:
 ;

limit_action:
   WARN { $$ = PLA_WARN; }
 | BLOCK { $$ = PLA_BLOCK; }
 | RESTART { $$ = PLA_RESTART; }
 | DISABLE { $$ = PLA_DISABLE; }
   /* default */ { $$ = PLA_DISABLE; }
 | EXCEED WARN { $$ = PLA_WARN; }
 | EXCEED BLOCK { $$ = PLA_BLOCK; }
 | EXCEED RESTART { $$ = PLA_RESTART; }
 | EXCEED DISABLE { $$ = PLA_DISABLE; }
 ;

limit_spec:
   expr EXCEED limit_action {
   expr limit_action {
     struct proto_limit *l = cfg_allocz(sizeof(struct proto_limit));
     l->limit = $1;
     l->action = $3;
     l->action = $2;
     $$ = l;
   }
 ;
+43 −28
Original line number Diff line number Diff line
@@ -406,13 +406,14 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
  if (p->proto->multitable)
    return 1;

  /* Update filters in the main announce hook */
  /* Update filters and limits in the main announce hook
     Note that this also resets limit state */
  if (p->main_ahook)
    {
      p->main_ahook->in_filter = nc->in_filter;
      p->main_ahook->out_filter = nc->out_filter;
      p->main_ahook->in_limit = nc->in_limit;
      // p->main_ahook->out_limit = nc->out_limit;
      p->main_ahook->out_limit = nc->out_limit;
    }

  /* Update routes when filters changed. If the protocol in not UP,
@@ -774,9 +775,16 @@ proto_schedule_feed(struct proto *p, int initial)
  p->core_state = FS_FEEDING;
  p->refeeding = !initial;

  /* Hack: reset exp_routes during refeed, and do not decrease it later */
  /* FIXME: This should be changed for better support of multitable protos */
  if (!initial)
    {
      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;
    }

  /* Connect protocol to routing table */
  if (initial && !p->proto->multitable)
@@ -785,7 +793,9 @@ proto_schedule_feed(struct proto *p, int initial)
      p->main_ahook->in_filter = p->cf->in_filter;
      p->main_ahook->out_filter = p->cf->out_filter;
      p->main_ahook->in_limit = p->cf->in_limit;
      // p->main_ahook->out_limit = p->cf->out_limit;
      p->main_ahook->out_limit = p->cf->out_limit;
      proto_reset_limit(p->main_ahook->in_limit);
      proto_reset_limit(p->main_ahook->out_limit);
    }

  proto_relink(p);
@@ -870,6 +880,8 @@ proto_schedule_flush(struct proto *p)
  proto_schedule_flush_loop();
}

/* Temporary hack to propagate restart to BGP */
int proto_restart;

static void
proto_shutdown_loop(struct timer *t UNUSED)
@@ -879,11 +891,11 @@ proto_shutdown_loop(struct timer *t UNUSED)
  WALK_LIST_DELSAFE(p, p_next, active_proto_list)
    if (p->down_sched)
      {
	int restart = (p->down_sched == PDS_RESTART);
	proto_restart = (p->down_sched == PDS_RESTART);

	p->disabled = 1;
	proto_rethink_goal(p);
	if (restart)
	if (proto_restart)
	  {
	    p->disabled = 0;
	    proto_rethink_goal(p);
@@ -953,43 +965,43 @@ proto_limit_name(struct proto_limit *l)
 * proto_notify_limit: notify about limit hit and take appropriate action
 * @ah: announce hook
 * @l: limit being hit
 * @rt_count: the number of routes 
 *
 * The function is called by the route processing core when limit @l
 * is breached. It activates the limit and tooks appropriate action
 * according to @l->action. It also says what should be done with the
 * route that breached the limit.
 *
 * Returns 1 if the route should be freed, 0 otherwise.
 * according to @l->action.
 */
int
proto_notify_limit(struct announce_hook *ah, struct proto_limit *l)
void
proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count)
{
  struct proto *p = ah->proto;
  int dir = (ah->in_limit == l);

  if (l->active)
    return (l->action != PLA_WARN);
  if (l->state == PLS_BLOCKED)
    return;

  l->active = 1;
  /* 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)))
    log(L_WARN "Protocol %s hits route %s limit (%d), action: %s",
	p->name, dir ? "import" : "export", l->limit, proto_limit_name(l));

  switch (l->action)
    {
    case PLA_WARN:
      return 0;
      l->state = PLS_ACTIVE;
      break;

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

    case PLA_RESTART:
    case PLA_DISABLE:
      l->state = PLS_BLOCKED;
      proto_schedule_down(p, l->action == PLA_RESTART,
			  dir ? PDC_IN_LIMIT_HIT : PDC_OUT_LIMIT_HIT);
      return 1;
      break;
    }

  return 0;
}

/**
@@ -1101,9 +1113,11 @@ proto_show_stats(struct proto_stats *s)
void
proto_show_limit(struct proto_limit *l, const char *dsc)
{
  if (l)
    cli_msg(-1006, "  %16s%d, action: %s%s", dsc, l->limit,
	    proto_limit_name(l), l->active ? " [HIT]" : "");
  if (!l)
    return;

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

void
@@ -1115,6 +1129,7 @@ proto_show_basic_info(struct proto *p)
  cli_msg(-1006, "  Output filter:  %s", filter_name(p->cf->out_filter));

  proto_show_limit(p->cf->in_limit, "Import limit:");
  proto_show_limit(p->cf->out_limit, "Export limit:");

  if (p->proto_state != PS_DOWN)
    proto_show_stats(&p->stats);
@@ -1233,8 +1248,8 @@ proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED)
       * Should be done before reload_routes() hook?
       * Perhaps, but these hooks work asynchronously.
       */
      if (!p->proto->multitable && p->main_ahook->in_limit)
	p->main_ahook->in_limit->active = 0;
      if (!p->proto->multitable)
	proto_reset_limit(p->main_ahook->in_limit);
    }

  /* re-exporting routes */
+15 −4
Original line number Diff line number Diff line
@@ -95,7 +95,7 @@ struct proto_config {
  struct rtable_config *table;		/* Table we're attached to */
  struct filter *in_filter, *out_filter; /* Attached filters */
  struct proto_limit *in_limit;		/* Limit for importing routes from protocol */
  // struct proto_limit *out_limit;	/* Limit for exporting routes to protocol */
  struct proto_limit *out_limit;	/* Limit for exporting routes to protocol */

  /* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */

@@ -375,13 +375,24 @@ extern struct proto_config *cf_dev_proto;
#define PLA_RESTART	4	/* Force protocol restart */
#define PLA_DISABLE	5	/* Shutdown and disable protocol */

#define PLS_INITIAL	0	/* Initial limit state after protocol start */
#define PLS_ACTIVE	1	/* Limit was hit */
#define PLS_BLOCKED	2	/* Limit is active and blocking new routes */

struct proto_limit {
  u32 limit;			/* Maximum number of prefixes */
  byte action;			/* Action to take (PLA_*) */
  byte active;			/* Limit is active */
  byte state;			/* State of limit (PLS_*) */
};

int proto_notify_limit(struct announce_hook *ah, struct proto_limit *l);
void proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count);

static inline void proto_reset_limit(struct proto_limit *l)
{
  if (l)
    l->state = PLS_INITIAL;
}

 
/*
 *	Route Announcement Hook
@@ -394,7 +405,7 @@ struct announce_hook {
  struct filter *in_filter;		/* Input filter */
  struct filter *out_filter;		/* Output filter */
  struct proto_limit *in_limit;		/* Input limit */
  // struct proto_limit *out_limit;	/* Output limit */
  struct proto_limit *out_limit;	/* Output limit */
  struct proto_stats *stats;		/* Per-table protocol statistics */
  struct announce_hook *next;		/* Next hook for the same protocol */
};
+30 −5
Original line number Diff line number Diff line
@@ -273,6 +273,23 @@ do_rte_announce(struct announce_hook *ah, int type UNUSED, net *net, rte *new, r
  if (!new && !old)
    return;

  struct proto_limit *l = ah->out_limit;
  if (l && new && (!old || refeed))
    {
      if (stats->exp_routes >= l->limit)
	proto_notify_limit(ah, l, stats->exp_routes);

      if (l->state == PLS_BLOCKED)
	{
	  /* Exported route counter ignores whether the route was
	     blocked by limit, to be consistent when limits change */
	  stats->exp_routes++;
	  stats->exp_updates_rejected++;
	  rte_trace_out(D_FILTERS, p, new, "rejected [limit]");
	  goto done;
	}
    }

  if (new)
    stats->exp_updates_accepted++;
  else
@@ -307,6 +324,8 @@ do_rte_announce(struct announce_hook *ah, int type UNUSED, net *net, rte *new, r
    }
  else
    p->rt_notify(p, ah->table, net, new, old, new->attrs->eattrs);

 done:
  if (new && new != new0)	/* Discard temporary rte's */
    rte_free(new);
  if (old && old != old0)
@@ -485,13 +504,19 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
    }

  struct proto_limit *l = ah->in_limit;
  if (l && !old && new && (stats->imp_routes >= l->limit) && proto_notify_limit(ah, l))
  if (l && !old && new)
    {
      if (stats->imp_routes >= l->limit)
	proto_notify_limit(ah, l, stats->imp_routes);

      if (l->state == PLS_BLOCKED)
	{
	  stats->imp_updates_ignored++;
	  rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
	  rte_free_quick(new);
	  return;
	}
    }

  if (new)
    stats->imp_updates_accepted++;
Loading