]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Limit containment
authorMaria Matejka <mq@ucw.cz>
Sat, 6 Nov 2021 19:34:16 +0000 (20:34 +0100)
committerMaria Matejka <mq@ucw.cz>
Tue, 9 Nov 2021 18:20:41 +0000 (19:20 +0100)
nest/limit.h [new file with mode: 0644]
nest/proto.c
nest/protocol.h
nest/rt-table.c
proto/pipe/pipe.c

diff --git a/nest/limit.h b/nest/limit.h
new file mode 100644 (file)
index 0000000..5838ad3
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *     BIRD Internet Routing Daemon -- Limits
+ *
+ *     (c) 1998--2000 Martin Mares <mj@ucw.cz>
+ *     (c) 2021 Maria Matejka <mq@jmq.cz>
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_LIMIT_H_
+#define _BIRD_LIMIT_H_
+
+struct limit {
+  u32 max;
+  u32 count;
+  int (*action)(struct limit *, void *data);
+};
+
+static inline int limit_do_action(struct limit *l, void *data)
+{
+  return l->action ? l->action(l, data) : 1;
+}
+
+static inline int limit_push(struct limit *l, void *data)
+{
+  if ((l->count >= l->max) && limit_do_action(l, data))
+    return 1;
+
+  l->count++;
+  return 0;
+}
+
+static inline void limit_pop(struct limit *l)
+{
+  --l->count;
+}
+
+static inline void limit_reset(struct limit *l)
+{
+  l->count = 0;
+}
+
+static inline void limit_update(struct limit *l, void *data, u32 max)
+{
+  if (l->count > (l->max = max))
+    limit_do_action(l, data);
+}
+
+#endif
index c7e2520924924ef41bd67427bff0fbb03d695e9f..2009ff1f9cf6565ce55029f2def9597218880701 100644 (file)
@@ -52,9 +52,9 @@ static void channel_request_reload(struct channel *c);
 static void proto_shutdown_loop(timer *);
 static void proto_rethink_goal(struct proto *p);
 static char *proto_state_name(struct proto *p);
-static void channel_verify_limits(struct channel *c);
-static inline void channel_reset_limit(struct channel_limit *l);
-
+static void channel_init_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf);
+static void channel_update_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf);
+static void channel_reset_limit(struct channel *c, struct limit *l, int dir);
 
 static inline int proto_is_done(struct proto *p)
 { return (p->proto_state == PS_DOWN) && (p->active_channels == 0); }
@@ -168,9 +168,10 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
 
   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;
+
+  channel_init_limit(c, &c->rx_limit, PLD_RX, &cf->rx_limit);
+  channel_init_limit(c, &c->in_limit, PLD_IN, &cf->in_limit);
+  channel_init_limit(c, &c->out_limit, PLD_OUT, &cf->out_limit);
 
   c->net_type = cf->net_type;
   c->ra_mode = cf->ra_mode;
@@ -280,14 +281,12 @@ channel_feed_loop(void *ptr)
   }
 
   /* Reset export limit if the feed ended with acceptable number of exported routes */
-  struct channel_limit *l = &c->out_limit;
   if (c->refeeding &&
-      (l->state == PLS_BLOCKED) &&
-      (c->refeed_count <= l->limit) &&
-      (c->export_stats.routes <= l->limit))
+      (c->limit_active & (1 << PLD_OUT)) &&
+      (c->refeed_count <= c->out_limit.max))
   {
-    log(L_INFO "Protocol %s resets route export limit (%u)", c->proto->name, l->limit);
-    channel_reset_limit(&c->out_limit);
+    log(L_INFO "Protocol %s resets route export limit (%u)", c->proto->name, c->out_limit.max);
+    channel_reset_limit(c, &c->out_limit, PLD_OUT);
 
     /* Continue in feed - it will process routing table again from beginning */
     c->refeed_count = 0;
@@ -461,7 +460,8 @@ channel_stop_export(struct channel *c)
     rt_feed_channel_abort(c);
 
   c->export_state = ES_DOWN;
-  c->export_stats.routes = 0;
+
+  channel_reset_limit(c, &c->out_limit, PLD_OUT);
   bmap_reset(&c->export_map, 1024);
   bmap_reset(&c->export_reject_map, 1024);
 }
@@ -556,9 +556,9 @@ channel_do_start(struct channel *c)
   memset(&c->export_stats, 0, sizeof(struct export_stats));
   memset(&c->import_stats, 0, sizeof(struct import_stats));
 
-  channel_reset_limit(&c->rx_limit);
-  channel_reset_limit(&c->in_limit);
-  channel_reset_limit(&c->out_limit);
+  channel_reset_limit(c, &c->rx_limit, PLD_RX);
+  channel_reset_limit(c, &c->in_limit, PLD_IN);
+  channel_reset_limit(c, &c->out_limit, PLD_OUT);
 
   CALL(c->channel->start, c);
 }
@@ -604,8 +604,8 @@ channel_do_down(struct channel *c)
   rt_unlock_table(c->table);
   c->proto->active_channels--;
 
-  if ((c->import_stats.routes + c->import_stats.filtered) != 0)
-    log(L_ERR "%s: Channel %s is down but still has some routes", c->proto->name, c->name);
+  if (c->in_limit.count || c->rx_limit.count)
+    bug("%s: Channel %s is down but still has some routes", c->proto->name, c->name);
 
   // bmap_free(&c->export_map);
   memset(&c->import_stats, 0, sizeof(struct import_stats));
@@ -748,8 +748,8 @@ channel_request_reload(struct channel *c)
    * 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);
+  channel_reset_limit(c, &c->rx_limit, PLD_RX);
+  channel_reset_limit(c, &c->in_limit, PLD_IN);
 }
 
 const struct channel_class channel_basic = {
@@ -852,9 +852,10 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
   /* 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;
+
+  channel_update_limit(c, &c->rx_limit, PLD_RX, &cf->rx_limit);
+  channel_update_limit(c, &c->in_limit, PLD_IN, &cf->in_limit);
+  channel_update_limit(c, &c->out_limit, PLD_OUT, &cf->out_limit);
 
   // c->ra_mode = cf->ra_mode;
   c->merge_limit = cf->merge_limit;
@@ -863,8 +864,6 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
   c->in_keep_filtered = cf->in_keep_filtered;
   c->rpki_reload = cf->rpki_reload;
 
-  channel_verify_limits(c);
-
   /* Execute channel-specific reconfigure hook */
   if (c->channel->reconfigure && !c->channel->reconfigure(c, cf, &import_changed, &export_changed))
     return 0;
@@ -1785,88 +1784,104 @@ proto_set_message(struct proto *p, char *msg, int len)
 }
 
 
-static const char *
-channel_limit_name(struct channel_limit *l)
-{
-  const char *actions[] = {
-    [PLA_WARN] = "warn",
-    [PLA_BLOCK] = "block",
-    [PLA_RESTART] = "restart",
-    [PLA_DISABLE] = "disable",
-  };
+static const char * channel_limit_name[] = {
+  [PLA_WARN] = "warn",
+  [PLA_BLOCK] = "block",
+  [PLA_RESTART] = "restart",
+  [PLA_DISABLE] = "disable",
+};
 
-  return actions[l->action];
-}
 
-/**
- * channel_notify_limit: notify about limit hit and take appropriate action
- * @c: channel
- * @l: limit being hit
- * @dir: limit direction (PLD_*)
- * @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.
- */
-void
-channel_notify_limit(struct channel *c, struct channel_limit *l, int dir, u32 rt_count)
+static void
+channel_log_limit(struct channel *c, struct limit *l, int dir)
 {
   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 };
-  struct proto *p = c->proto;
+  log(L_WARN "Channel %s.%s hits route %s limit (%d), action: %s",
+      c->proto->name, c->name, dir_name[dir], l->max, channel_limit_name[c->limit_actions[dir]]);
+}
 
-  if (l->state == PLS_BLOCKED)
+static void
+channel_activate_limit(struct channel *c, struct limit *l, int dir)
+{
+  if (c->limit_active & (1 << dir))
     return;
 
-  /* 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_name[dir], l->limit, channel_limit_name(l));
+  c->limit_active |= (1 << dir);
+  channel_log_limit(c, l, dir);
+}
 
-  switch (l->action)
-  {
-  case PLA_WARN:
-    l->state = PLS_ACTIVE;
-    break;
+static int
+channel_limit_warn(struct limit *l, void *data)
+{
+  struct channel_limit_data *cld = data;
+  struct channel *c = cld->c;
+  int dir = cld->dir;
 
-  case PLA_BLOCK:
-    l->state = PLS_BLOCKED;
-    break;
+  channel_log_limit(c, l, dir);
 
-  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;
-  }
+  return 0;
 }
 
-static void
-channel_verify_limits(struct channel *c)
+static int
+channel_limit_block(struct limit *l, void *data)
 {
-  struct channel_limit *l;
-  u32 all_routes = c->import_stats.routes + c->import_stats.filtered;
+  struct channel_limit_data *cld = data;
+  struct channel *c = cld->c;
+  int dir = cld->dir;
 
-  l = &c->rx_limit;
-  if (l->action && (all_routes > l->limit))
-    channel_notify_limit(c, l, PLD_RX, all_routes);
+  channel_activate_limit(c, l, dir);
 
-  l = &c->in_limit;
-  if (l->action && (c->import_stats.routes > l->limit))
-    channel_notify_limit(c, l, PLD_IN, c->import_stats.routes);
+  return 1;
+}
 
-  l = &c->out_limit;
-  if (l->action && (c->export_stats.routes > l->limit))
-    channel_notify_limit(c, l, PLD_OUT, c->export_stats.routes);
+static const byte chl_dir_down[PLD_MAX] = { PDC_RX_LIMIT_HIT, PDC_IN_LIMIT_HIT, PDC_OUT_LIMIT_HIT };
+
+static int
+channel_limit_down(struct limit *l, void *data)
+{
+  struct channel_limit_data *cld = data;
+  struct channel *c = cld->c;
+  struct proto *p = c->proto;
+  int dir = cld->dir;
+
+  channel_activate_limit(c, l, dir);
+
+  if (p->proto_state == PS_UP)
+    proto_schedule_down(p, c->limit_actions[dir] == PLA_RESTART, chl_dir_down[dir]);
+
+  return 1;
 }
 
-static inline void
-channel_reset_limit(struct channel_limit *l)
+static int (*channel_limit_action[])(struct limit *, void *) = {
+  [PLA_NONE] = NULL,
+  [PLA_WARN] = channel_limit_warn,
+  [PLA_BLOCK] = channel_limit_block,
+  [PLA_RESTART] = channel_limit_down,
+  [PLA_DISABLE] = channel_limit_down,
+};
+
+static void
+channel_update_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf)
 {
-  if (l->action)
-    l->state = PLS_INITIAL;
+  l->action = channel_limit_action[cf->action];
+  c->limit_actions[dir] = cf->action;
+
+  struct channel_limit_data cld = { .c = c, .dir = dir };
+  limit_update(l, &cld, cf->action ? cf->limit : ~((u32) 0));
+}
+
+static void
+channel_init_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf)
+{
+  channel_reset_limit(c, l, dir);
+  channel_update_limit(c, l, dir, cf);
+}
+
+static void
+channel_reset_limit(struct channel *c, struct limit *l, int dir)
+{
+  limit_reset(l);
+  c->limit_active &= ~(1 << dir);
 }
 
 static inline void
@@ -2017,12 +2032,16 @@ channel_show_stats(struct channel *c)
   struct import_stats *is = &c->import_stats;
   struct export_stats *es = &c->export_stats;
 
+  u32 rx_routes = c->rx_limit.count;
+  u32 in_routes = c->in_limit.count;
+  u32 out_routes = c->out_limit.count;
+
   if (c->in_keep_filtered)
     cli_msg(-1006, "    Routes:         %u imported, %u filtered, %u exported, %u preferred",
-           is->routes, is->filtered, es->routes, is->pref);
+           in_routes, (rx_routes - in_routes), out_routes, is->pref);
   else
     cli_msg(-1006, "    Routes:         %u imported, %u exported, %u preferred",
-           is->routes, es->routes, is->pref);
+           in_routes, out_routes, is->pref);
 
   cli_msg(-1006, "    Route change stats:     received   rejected   filtered    ignored   accepted");
   cli_msg(-1006, "      Import updates:     %10u %10u %10u %10u %10u",
@@ -2040,13 +2059,13 @@ channel_show_stats(struct channel *c)
 }
 
 void
-channel_show_limit(struct channel_limit *l, const char *dsc)
+channel_show_limit(struct limit *l, const char *dsc, int active, int action)
 {
   if (!l->action)
     return;
 
-  cli_msg(-1006, "    %-16s%d%s", dsc, l->limit, l->state ? " [HIT]" : "");
-  cli_msg(-1006, "      Action:       %s", channel_limit_name(l));
+  cli_msg(-1006, "    %-16s%d%s", dsc, l->max, active ? " [HIT]" : "");
+  cli_msg(-1006, "      Action:       %s", channel_limit_name[action]);
 }
 
 void
@@ -2064,9 +2083,9 @@ channel_show_info(struct channel *c)
            c->gr_lock ? " pending" : "",
            c->gr_wait ? " waiting" : "");
 
-  channel_show_limit(&c->rx_limit, "Receive limit:");
-  channel_show_limit(&c->in_limit, "Import limit:");
-  channel_show_limit(&c->out_limit, "Export limit:");
+  channel_show_limit(&c->rx_limit, "Receive limit:", c->limit_active & (1 << PLD_RX), c->limit_actions[PLD_RX]);
+  channel_show_limit(&c->in_limit, "Import limit:", c->limit_active & (1 << PLD_IN), c->limit_actions[PLD_IN]);
+  channel_show_limit(&c->out_limit, "Export limit:", c->limit_active & (1 << PLD_OUT), c->limit_actions[PLD_OUT]);
 
   if (c->channel_state != CS_DOWN)
     channel_show_stats(c);
index 4c87c72d5b16a7504289cf989338770762f4970e..c19789143ff5f0d92a477451e6781c4ef8c33e94 100644 (file)
@@ -13,6 +13,7 @@
 #include "lib/resource.h"
 #include "lib/event.h"
 #include "nest/route.h"
+#include "nest/limit.h"
 #include "conf/conf.h"
 
 struct iface;
@@ -134,8 +135,6 @@ struct proto_config {
 /* Protocol statistics */
 struct import_stats {
   /* Import - from protocol to core */
-  u32 routes;                  /* Number of routes successfully imported to the (adjacent) routing table */
-  u32 filtered;                        /* Number of routes rejected in import filter but kept in the routing table */
   u32 pref;                    /* Number of routes selected as best in the (adjacent) routing table */
   u32 updates_received;                /* Number of route updates received */
   u32 updates_invalid;         /* Number of route updates rejected as invalid */
@@ -150,7 +149,6 @@ struct import_stats {
 
 struct export_stats {
   /* Export - from core to protocol */
-  u32 routes;                  /* Number of routes successfully exported to the protocol */
   u32 updates_received;                /* Number of route updates received */
   u32 updates_rejected;                /* Number of route updates rejected by protocol */
   u32 updates_filtered;                /* Number of route updates rejected by filters */
@@ -277,7 +275,7 @@ void channel_graceful_restart_unlock(struct channel *c);
 
 #define DEFAULT_GR_WAIT        240
 
-void channel_show_limit(struct channel_limit *l, const char *dsc);
+void channel_show_limit(struct limit *l, const char *dsc, int active, int action);
 void channel_show_info(struct channel *c);
 void channel_cmd_debug(struct channel *c, uint mask);
 
@@ -432,18 +430,29 @@ 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 channel_limit {
   u32 limit;                   /* Maximum number of prefixes */
   u8 action;                   /* Action to take (PLA_*) */
-  u8 state;                    /* State of limit (PLS_*) */
 };
 
-void channel_notify_limit(struct channel *c, struct channel_limit *l, int dir, u32 rt_count);
+struct channel_limit_data {
+  struct channel *c;
+  int dir;
+};
+
+#define CLP__RX(_c) (&(_c)->rx_limit)
+#define CLP__IN(_c) (&(_c)->in_limit)
+#define CLP__OUT(_c) (&(_c)->out_limit)
+
+
+#if 0
+#define CHANNEL_LIMIT_LOG(_c, _dir, _op)  log(L_TRACE "%s.%s: %s limit %s %u", (_c)->proto->name, (_c)->name, #_dir, _op, (CLP__##_dir(_c))->count)
+#else
+#define CHANNEL_LIMIT_LOG(_c, _dir, _op)
+#endif
 
+#define CHANNEL_LIMIT_PUSH(_c, _dir)  ({ CHANNEL_LIMIT_LOG(_c, _dir, "push from"); struct channel_limit_data cld = { .c = (_c), .dir = PLD_##_dir }; limit_push(CLP__##_dir(_c), &cld); })
+#define CHANNEL_LIMIT_POP(_c, _dir)   ({ limit_pop(CLP__##_dir(_c)); CHANNEL_LIMIT_LOG(_c, _dir, "pop to"); })
 
 /*
  *     Channels
@@ -486,6 +495,7 @@ struct channel_config {
   struct proto_config *parent;         /* Where channel is defined (proto or template) */
   struct rtable_config *table;         /* Table we're attached to */
   const struct filter *in_filter, *out_filter; /* Attached filters */
+
   struct channel_limit rx_limit;       /* Limit for receiving routes from protocol
                                           (relevant when in_keep_filtered is active) */
   struct channel_limit in_limit;       /* Limit for importing routes from protocol */
@@ -513,9 +523,13 @@ struct channel {
   const struct filter *out_filter;     /* Output filter */
   struct bmap export_map;              /* Keeps track which routes were really exported */
   struct bmap export_reject_map;       /* Keeps track which routes were rejected by export filter */
-  struct channel_limit rx_limit;       /* Receive limit (for in_keep_filtered) */
-  struct channel_limit in_limit;       /* Input limit */
-  struct channel_limit out_limit;      /* Output limit */
+
+  struct limit rx_limit;               /* Receive limit (for in_keep_filtered) */
+  struct limit in_limit;               /* Input limit */
+  struct limit out_limit;              /* Output limit */
+
+  u8 limit_actions[PLD_MAX];           /* Limit actions enum */
+  u8 limit_active;                     /* Flags for active limits */
 
   struct event *feed_event;            /* Event responsible for feeding */
   struct fib_iterator feed_fit;                /* Routing table iterator used during feeding */
index 146734f42064b81f27c9c21aaef2c3d20770d882..66e63acf56cf822795e6a239b99468a924aa44f2 100644 (file)
@@ -473,20 +473,16 @@ do_rt_notify(struct channel *c, const net_addr *net, rte *new, rte *old, int ref
   if (refeed && new)
     c->refeed_count++;
 
-  /* Apply export limit */
-  struct channel_limit *l = &c->out_limit;
-  if (l->action && !old && new)
-  {
-    if (stats->routes >= l->limit)
-      channel_notify_limit(c, l, PLD_OUT, stats->routes);
-
-    if (l->state == PLS_BLOCKED)
+  if (!old && new)
+    if (CHANNEL_LIMIT_PUSH(c, OUT))
     {
       stats->updates_rejected++;
       rte_trace_out(D_FILTERS, c, new, "rejected [limit]");
       return;
     }
-  }
+
+  if (!new && old)
+    CHANNEL_LIMIT_POP(c, OUT);
 
   /* Apply export table */
   struct rte_storage *old_exported = NULL;
@@ -505,16 +501,10 @@ do_rt_notify(struct channel *c, const net_addr *net, rte *new, rte *old, int ref
     stats->withdraws_accepted++;
 
   if (old)
-  {
     bmap_clear(&c->export_map, old->id);
-    stats->routes--;
-  }
 
   if (new)
-  {
     bmap_set(&c->export_map, new->id);
-    stats->routes++;
-  }
 
   if (p->debug & D_ROUTES)
   {
@@ -973,59 +963,54 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
   int new_ok = rte_is_ok(new);
   int old_ok = rte_is_ok(old);
 
-  struct channel_limit *l = &c->rx_limit;
-  if (l->action && !old && new && !c->in_table)
-    {
-      u32 all_routes = stats->routes + stats->filtered;
-
-      if (all_routes >= l->limit)
-       channel_notify_limit(c, l, PLD_RX, all_routes);
+  if (!c->in_table)
+  {
+    if (!old && new)
+      if (CHANNEL_LIMIT_PUSH(c, RX))
+      {
+       /* In receive limit the situation is simple, old is NULL so
+          we just free new and exit like nothing happened */
 
-      if (l->state == PLS_BLOCKED)
-       {
-         /* In receive limit the situation is simple, old is NULL so
-            we just free new and exit like nothing happened */
+       stats->updates_ignored++;
+       rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
+       return;
+      }
 
-         stats->updates_ignored++;
-         rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
-         return;
-       }
-    }
+    if (old && !new)
+      CHANNEL_LIMIT_POP(c, RX);
+  }
 
-  l = &c->in_limit;
-  if (l->action && !old_ok && new_ok)
+  if (!old_ok && new_ok)
+    if (CHANNEL_LIMIT_PUSH(c, IN))
     {
-      if (stats->routes >= l->limit)
-       channel_notify_limit(c, l, PLD_IN, stats->routes);
-
-      if (l->state == PLS_BLOCKED)
-       {
-         /* In import limit the situation is more complicated. We
-            shouldn't just drop the route, we should handle it like
-            it was filtered. We also have to continue the route
-            processing if old or new is non-NULL, but we should exit
-            if both are NULL as this case is probably assumed to be
-            already handled. */
-
-         stats->updates_ignored++;
-         rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
+      /* In import limit the situation is more complicated. We
+        shouldn't just drop the route, we should handle it like
+        it was filtered. We also have to continue the route
+        processing if old or new is non-NULL, but we should exit
+        if both are NULL as this case is probably assumed to be
+        already handled. */
+
+      stats->updates_ignored++;
+      rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
 
-         if (c->in_keep_filtered)
-           new->flags |= REF_FILTERED;
-         else
-           new = NULL;
+      if (c->in_keep_filtered)
+       new->flags |= REF_FILTERED;
+      else
+       new = NULL;
 
-         /* Note that old && !new could be possible when
-            c->in_keep_filtered changed in the recent past. */
+      /* Note that old && !new could be possible when
+        c->in_keep_filtered changed in the recent past. */
 
-         if (!old && !new)
-           return;
+      if (!old && !new)
+       return;
 
-         new_ok = 0;
-         goto skip_stats1;
-       }
+      new_ok = 0;
+      goto skip_stats1;
     }
 
+  if (old_ok && !new_ok)
+    CHANNEL_LIMIT_POP(c, IN);
+
   if (new_ok)
     stats->updates_accepted++;
   else if (old_ok)
@@ -1039,11 +1024,6 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
  skip_stats1:;
   struct rte_storage *new_stored = new ? rte_store(new, net, table) : NULL;
 
-  if (new)
-    rte_is_filtered(new) ? stats->filtered++ : stats->routes++;
-  if (old)
-    rte_is_filtered(old) ? stats->filtered-- : stats->routes--;
-
   if (table->config->sorted)
     {
       /* If routes are sorted, just insert new route to appropriate position */
@@ -2332,6 +2312,9 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
        goto drop_update;
       }
 
+      if (!new)
+       CHANNEL_LIMIT_POP(c, RX);
+
       /* Move iterator if needed */
       if (*pos == c->reload_next_rte)
        c->reload_next_rte = (*pos)->next;
@@ -2342,7 +2325,18 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
       rte_free(del, tab);
       tab->rt_count--;
     }
-  else if (!new)
+  else if (new)
+    {
+      if (CHANNEL_LIMIT_PUSH(c, RX))
+      {
+       /* Required by rte_trace_in() */
+       new->net = n;
+
+       rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
+       goto drop_update;
+      }
+    }
+  else
     goto drop_withdraw;
 
   if (!new)
@@ -2353,22 +2347,6 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
     return 1;
   }
 
-  struct channel_limit *l = &c->rx_limit;
-  if (l->action && !*pos)
-  {
-    if (tab->rt_count >= l->limit)
-      channel_notify_limit(c, l, PLD_RX, tab->rt_count);
-
-    if (l->state == PLS_BLOCKED)
-    {
-      /* Required by rte_trace_in() */
-      new->net = n;
-
-      rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
-      goto drop_update;
-    }
-  }
-
   /* Insert the new rte */
   struct rte_storage *e = rte_store(new, net, tab);
   e->rte.sender = c;
index 55a0b5262b69ab59f25a8ecaa3ac09e98e885264..74d0e518969414743763fc6708a404992c26c4b1 100644 (file)
@@ -217,6 +217,9 @@ pipe_show_stats(struct pipe_proto *p)
   struct import_stats *s2i = &p->sec->import_stats;
   struct export_stats *s2e = &p->sec->export_stats;
 
+  u32 pri_routes = p->pri->in_limit.count;
+  u32 sec_routes = p->sec->in_limit.count;
+
   /*
    * Pipe stats (as anything related to pipes) are a bit tricky. There
    * are two sets of stats - s1 for ahook to the primary routing and
@@ -239,7 +242,7 @@ pipe_show_stats(struct pipe_proto *p)
    */
 
   cli_msg(-1006, "  Routes:         %u imported, %u exported",
-         s1i->routes, s2i->routes);
+         pri_routes, sec_routes);
   cli_msg(-1006, "  Route change stats:     received   rejected   filtered    ignored   accepted");
   cli_msg(-1006, "    Import updates:     %10u %10u %10u %10u %10u",
          s2e->updates_received, s2e->updates_rejected + s1i->updates_invalid,
@@ -270,8 +273,12 @@ pipe_show_proto_info(struct proto *P)
   cli_msg(-1006, "    Import filter:  %s", filter_name(p->sec->out_filter));
   cli_msg(-1006, "    Export filter:  %s", filter_name(p->pri->out_filter));
 
-  channel_show_limit(&p->pri->in_limit, "Import limit:");
-  channel_show_limit(&p->sec->in_limit, "Export limit:");
+
+
+  channel_show_limit(&p->pri->in_limit, "Import limit:",
+      (p->pri->limit_active & (1 << PLD_IN)), p->pri->limit_actions[PLD_IN]);
+  channel_show_limit(&p->sec->in_limit, "Export limit:",
+      (p->sec->limit_active & (1 << PLD_IN)), p->sec->limit_actions[PLD_IN]);
 
   if (P->proto_state != PS_DOWN)
     pipe_show_stats(p);