]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Implements generalized export limits.
authorOndrej Zajicek <santiago@crfreenet.org>
Tue, 24 Apr 2012 21:39:57 +0000 (23:39 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 24 Apr 2012 21:39:57 +0000 (23:39 +0200)
And also fixes some minor bugs in limits.

doc/bird.sgml
nest/config.Y
nest/proto.c
nest/protocol.h
nest/rt-table.c
proto/bgp/bgp.c
proto/pipe/config.Y
proto/pipe/pipe.c
proto/pipe/pipe.h

index 6f96b8624b6a9336b6856abc5a4c18fc22b95586..df6e26108d64c7f5dc615fb951894363a984e492 100644 (file)
@@ -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
index 60b03278ad3ff3877df6e91d583c486b3bc9bbf3..c59319cb79d30391e5ec44a8b6e88b9c08f80570 100644 (file)
@@ -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;
    }
  ;
index cf81573fdc64cafb2c84b605b570490c92378160..887d3e5e97962a8010f6d5eba2484911331283a6 100644 (file)
@@ -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)
-    p->stats.exp_routes = 0;
+    {
+      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,9 +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;
       proto_reset_limit(p->main_ahook->in_limit);
-      // p->main_ahook->out_limit = p->cf->out_limit;
-      // proto_reset_limit(p->main_ahook->out_limit);
+      proto_reset_limit(p->main_ahook->out_limit);
     }
 
   proto_relink(p);
@@ -872,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)
@@ -881,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);
@@ -970,7 +980,8 @@ proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count
   if (l->state == PLS_BLOCKED)
     return;
 
-  if (rt_count == l->limit)
+  /* 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));
 
@@ -1118,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);
index d8442acb5c59c47947c22614b4bd2ff615a70ecd..3f9ed96eef5f1248dedff01f1aa9109af9c703e8 100644 (file)
@@ -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 */
 
@@ -405,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 */
 };
index 6d82e1d3769e3336b84ea2a7fba4c810628a3567..06121ea38144803a39ea6b7a7c7b1d05c8362064 100644 (file)
@@ -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)
index 95dbe47706546da52f67c115f4694887f54a99da..3b9f7cc5e57d3a50c874f7a58bc213596b57030e 100644 (file)
@@ -848,6 +848,8 @@ bgp_start(struct proto *P)
   return PS_START;
 }
 
+extern int proto_restart;
+
 static int
 bgp_shutdown(struct proto *P)
 {
@@ -877,10 +879,16 @@ bgp_shutdown(struct proto *P)
 
     case PDC_IN_LIMIT_HIT:
       subcode = 1; // Errcode 6, 1 - max number of prefixes reached
+      /* log message for compatibility */
       log(L_WARN "%s: Route limit exceeded, shutting down", p->p.name);
+      goto limit;
+
+    case PDC_OUT_LIMIT_HIT:
+      subcode = proto_restart ? 4 : 2; // Administrative reset or shutdown
 
+    limit:
       bgp_store_error(p, NULL, BE_AUTO_DOWN, BEA_ROUTE_LIMIT_EXCEEDED);
-      if (P->cf->in_limit->action == PLA_RESTART)
+      if (proto_restart)
        bgp_update_startup_delay(p);
       else
        p->startup_delay = 0;
index 4fb2b499bb40f5643405a4488734197428cb27dc..40637558b4376b36ac0fc17fea37d1a789c0bbff 100644 (file)
@@ -36,7 +36,6 @@ pipe_proto:
        cf_error("Routing table name expected");
      PIPE_CFG->peer = $4->def;
    }
- | pipe_proto EXPORT LIMIT limit_spec ';' { PIPE_CFG->out_limit = $4; }
  | pipe_proto MODE OPAQUE ';' { PIPE_CFG->mode = PIPE_OPAQUE; }
  | pipe_proto MODE TRANSPARENT ';' { PIPE_CFG->mode = PIPE_TRANSPARENT; }
  ;
index 41bac474b9c99d76fb970757fa745a66255c4d04..6099d2846ca18ffa5baec0e348a399484f3d339a 100644 (file)
@@ -170,7 +170,7 @@ pipe_start(struct proto *P)
 
   p->peer_ahook = proto_add_announce_hook(P, p->peer_table, &p->peer_stats);
   p->peer_ahook->out_filter = cf->c.in_filter;
-  p->peer_ahook->in_limit = cf->out_limit;
+  p->peer_ahook->in_limit = cf->c.out_limit;
   proto_reset_limit(p->peer_ahook->in_limit);
 
   return PS_UP;
@@ -225,7 +225,7 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
   if (p->peer_ahook)
     {
       p->peer_ahook->out_filter = new->in_filter;
-      p->peer_ahook->in_limit = nc->out_limit;
+      p->peer_ahook->in_limit = new->out_limit;
     }
 
   if ((P->proto_state != PS_UP) || (proto_reconfig_type == RECONFIG_SOFT))
@@ -311,7 +311,7 @@ pipe_show_proto_info(struct proto *P)
   cli_msg(-1006, "  Output filter:  %s", filter_name(cf->c.out_filter));
 
   proto_show_limit(cf->c.in_limit, "Import limit:");
-  proto_show_limit(cf->out_limit, "Export limit:");
+  proto_show_limit(cf->c.out_limit, "Export limit:");
 
   if (P->proto_state != PS_DOWN)
     pipe_show_stats(p);
index e777fb417a481219df4824195bdcc136a4d00363..50b3169815f4c93a5bab944b2eb89ecd55887a58 100644 (file)
@@ -15,7 +15,6 @@
 struct pipe_config {
   struct proto_config c;
   struct rtable_config *peer;          /* Table we're connected to */
-  struct proto_limit *out_limit;       /* Export route limit */
   int mode;                            /* PIPE_OPAQUE or PIPE_TRANSPARENT */
 };