]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Settle time for stats protocol, documentation
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Thu, 21 Jul 2022 14:54:13 +0000 (16:54 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Thu, 21 Jul 2022 14:54:13 +0000 (16:54 +0200)
doc/bird.sgml
proto/stats/config.Y
proto/stats/stats.c
proto/stats/stats.h

index ea126fa2d045bc29244b033260e9c18cbd5cffa4..cf16c740ea6f3e4bbea4655dcdb1164354f8ecc6 100644 (file)
@@ -5411,6 +5411,54 @@ protocol static {
 }
 </code>
 
+<sect>Stats
+<label id="stats">
+
+<sect1>
+<label id="stats-intro">
+
+<p>The Statistics protocol allows you to measure number of exported routes from
+a table. You can also narrow the view by applying export filter inside stats
+channel. One instance of stats protocol can have multiple channels attached.
+Stats protocol could be particullary useful when making conditional route advertising.
+
+<p>Statistics are accessed in filters by same name as channel connected to desired
+table. Value of this expresion is evaluated to the sum of all routes with
+generation smaller than max generation (see below).
+
+<sect1>Configuration
+<label id="stats-config">
+
+<p><descrtip>
+       <tag><label id="stats-max-generation">max generation <m/expr/</tag>
+       Statistics counter contains sum of all routes with generation less
+       than or equal to max generation. This copies behavior of pipe's
+       <ref id="pipe-max-generation" name="max generetion">. Must be in range
+       from 0 to 254. Default: 16.
+
+       <tag><label id="stats-update-after">settle time <m/time/ <m/number/</tag>
+       Wait given amount of time before notifying and recalculting filters
+       which reference this counter in seconds. If counter changes during this period,
+       current value is used. If set to zero, the notification is done instantly.
+       Default: 5 s.
+</descrip>
+
+<p>Example
+<code>
+protocol stats {
+  ipv4 stats1 { table bgp_tab1; };
+}
+
+protocol static {
+  # note that the stats1 is unrelated
+  ipv4 { import where stats1 > 200; };
+  route 0.0.0.0:0;
+}
+</code>
+
+<p>Beware that configuration with cyclic references (even logical ones) are
+considered invalid and the behaviour is not defined! You <em>should</em> avoid
+them. No detection is implemented.
 
 <chapt>Conclusions
 <label id="conclusion">
index 087ac75ae4d330867f7b84ab1f386771e693da0b..c7958e51926bf8ea59fe59088eb73e12352274ac 100644 (file)
@@ -9,18 +9,15 @@
 
 CF_HDR
 
-/* old: #include "proto/pipe/pipe.h" */
 #include "proto/stats/stats.h"
 
 CF_DEFINES
 
-/* old: #define PIPE_CFG ((struct pipe_config *) this_proto) */
 #define STATS_CC ((struct stats_channel_config *) this_channel)
 
 CF_DECLS
 
-/* TODO here add more keywords */
-CF_KEYWORDS(STATS, TABLE, MAX, GENERATION)
+CF_KEYWORDS(STATS, TABLE, MAX, GENERATION, SETTLE, TIME)
 
 %type <cc> stats_channel_start
 
@@ -48,21 +45,25 @@ channel_max_gen:
   }
   ;
 
+stats_settle:
+  SETTLE TIME time {
+    STATS_CC->settle = $3 S_;
+  }
+
 stats_opts:
     /* empty */
   | stats_opts channel_item ';'
   | stats_opts channel_max_gen ';'
+  | stats_opts stats_settle ';'
   ;
      
 stats_proto_channel: stats_channel_start stats_channel_opt_list channel_end ;
-/* stats_proto_channel: stats_channel_start stats_max_gen channel_opt_list channel_end ; */
 
 stats_channel_start: net_type symbol
 {
   this_channel = channel_config_get(&channel_stats, $2->name, $1, this_proto);
   STATS_CC->max_generation = 16;
-  /* from filter/config.Y:
-       cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++) */
+  STATS_CC->settle = 5 S_;
   $2 = cf_define_symbol($2, SYM_COUNTER, ch_config, this_channel);
 }
 
index f5bf0ac647498d4cb8c008d49daa044c393a9b5e..1670e7844e09b867d376db7edf4c83d1ee9542a5 100644 (file)
 #include "conf/conf.h"
 #include "filter/filter.h"
 #include "lib/string.h"
+#include "lib/timer.h"
 
 #include "stats.h"
 
-#ifdef CONFIG_BGP
-#include "proto/bgp/bgp.h"
-#endif
+#define COUNTER 255
+
+static void stats_kick_timer(struct stats_channel *c);
 
 static void
 stats_rt_notify(struct proto *P UNUSED, struct channel *src_ch, const net_addr *n UNUSED, rte *new, const rte *old)
 {
   struct stats_channel *ch = (void *) src_ch;
 
+  int changed = 0;
   if (old)
   {
     ch->counters[old->generation]--;
     if (old->generation < ch->max_generation)
-      ch->sum--;
+    {
+      changed = 1;
+      ch->counters[COUNTER]--;
+    }
   }
 
   if (new)
   {
     ch->counters[new->generation]++;
     if (new->generation < ch->max_generation)
-      ch->sum++;
+    {
+      changed = 1;
+      ch->counters[COUNTER]++;
+    }
   }  
+
+  if (changed)
+  {
+    log(L_INFO "stats: timer kicked with time %u", ch->settle);
+    stats_kick_timer((struct stats_channel *) ch);
+  }
 }
 
 static void
@@ -69,6 +83,7 @@ stats_configure_channels(struct proto *P, struct proto_config *CF)
     struct stats_channel_config *scc = (void *) cc;
 
     sc->max_generation = scc->max_generation;
+    sc->settle = scc->settle;
   } 
 }
 
@@ -117,11 +132,17 @@ stats_reconfigure(struct proto *P, struct proto_config *CF)
       struct stats_channel_config *scc = (void *) cc;
 
       sc->max_generation = scc->max_generation;
+      sc->settle = scc->settle;
 
       /* recalculate sum */
-      sc->sum = 0;
+      sc->counters[COUNTER] = 0;
       for (u8 i = 0; i < sc->max_generation; i++)
-       sc->sum += sc->counters[i];
+       sc->counters[COUNTER] += sc->counters[i];
+
+      sc->sum = sc->counters[COUNTER];
+
+      /* notify all hooked filters */
+      // TODO here
 
       c->stale = 0;
     }
@@ -161,7 +182,11 @@ stats_show_proto_info(struct proto *P)
 
     cli_msg(-1006, "  Channel %s", sc->c.name);
     cli_msg(-1006, "    Max generation:  %3u", sc->max_generation);
-    cli_msg(-1006, "    Exports:  %10u", sc->sum);
+    // FIXME : actual or visible to filters ? AND TIME below in the comment
+    cli_msg(-1006, "    Exports:  %10u (currently:  %10u)",
+             sc->sum,
+             sc->counters[COUNTER]);
+    cli_msg(-1006, "    Settle time:  %7u s", sc->settle / 1000000 );
     cli_msg(-1006, "    Counter     exported");
 
     for (u8 i = 0; i < len; i++)
@@ -186,6 +211,32 @@ stats_update_debug(struct proto *P)
   }
 }
 
+static void
+stats_timer(timer *t)
+{
+  log(L_INFO "timer executing update");
+  struct stats_channel *c = (struct stats_channel *) t->data;
+
+  /* update the sum correct counter data */
+  c->sum = c->counters[COUNTER];
+
+  /* notify all filters to reevaluate them */
+  // TODO here
+
+}
+
+static void
+stats_kick_timer(struct stats_channel *c)
+{
+
+  /* if set to zero execute immediately */
+  if (!c->settle)
+    stats_timer(c->timer);
+
+  if (!tm_active(c->timer))
+    tm_start(c->timer, c->settle);
+}
+
 static int
 stats_channel_start(struct channel *C)
 {
@@ -194,6 +245,8 @@ stats_channel_start(struct channel *C)
 
   c->pool = p->p.pool;
 
+  c->timer = tm_new_init(c->pool, stats_timer, (void *) c, 0, 0);
+
   c->counters = mb_allocz(c->pool, 256 * sizeof(u32));
   c->sum = 0;
 
@@ -206,6 +259,10 @@ stats_channel_shutdown(struct channel *C)
   struct stats_channel *c = (void *) C;
 
   mb_free(c->counters);
+
+  /* FIXME freed automatically by the resource pool ?
+  rfree(c->timer);
+  */
   
   c->max_generation = 0;
   c->counters = NULL;
index d061e4eaf459f2584bdd58423adc96cfdac82b07..f636aa43653846f2719065049c8053d82362dba9 100644 (file)
@@ -28,11 +28,14 @@ struct stats_channel {
   u8 max_generation;
   u32 *counters;
   u32 sum;
+  timer *timer;
+  btime settle;
 };
 
 struct stats_channel_config {
   struct channel_config c;
   u8 max_generation;
+  btime settle;
 };
 
 static inline int