]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Created a dedicated settle timer structure
authorMaria Matejka <mq@ucw.cz>
Fri, 9 Sep 2022 13:04:36 +0000 (15:04 +0200)
committerMaria Matejka <mq@ucw.cz>
Fri, 9 Sep 2022 16:53:15 +0000 (18:53 +0200)
conf/confbase.Y
doc/bird.sgml
lib/settle.h [new file with mode: 0644]
nest/config.Y
nest/proto.c
nest/protocol.h

index 241c332d87d5d69fd79e51fafe2a03a6dbccffbf..8e5da9e3f792e86f5ecea4dbf5ef13808fe5bfdc 100644 (file)
@@ -14,6 +14,7 @@ CF_HDR
 #include "conf/conf.h"
 #include "lib/resource.h"
 #include "lib/socket.h"
+#include "lib/settle.h"
 #include "lib/timer.h"
 #include "lib/string.h"
 #include "nest/protocol.h"
@@ -93,6 +94,7 @@ CF_DECLS
   struct proto_spec ps;
   struct channel_limit cl;
   struct timeformat *tf;
+  struct settle_config settle;
   struct adata *ad;
   struct bytestring *bs;
 }
@@ -111,6 +113,7 @@ CF_DECLS
 
 %type <i> expr bool pxlen4
 %type <time> expr_us time
+%type <settle> settle
 %type <a> ipa
 %type <net> net_ip4_ net_ip4 net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
 %type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_
@@ -386,6 +389,13 @@ time:
    }
  ;
 
+/* Settle timer configuration */
+settle: expr_us expr_us {
+  if ($1 > $2) cf_error("Minimum settle time %t is bigger than maximum settle time %t", $1, $2);
+  $$.min = $1;
+  $$.max = $2;
+};
+
 text:
    TEXT
  | CF_SYM_KNOWN {
index 2bce3d57ea1b922b4dcf825f633f477c5d216796..54d67e8972423c66302b14d86864e33d57ce47b5 100644 (file)
@@ -965,14 +965,15 @@ inherited from templates can be updated by new definitions.
        <ref id="bgp-export-table" name="export table"> (for respective
        direction). Default: on.
 
-       <tag><label id="rtable-min-settle-time">min settle time <m/time/</tag>
-       Minimum settle time is a delay from the last ROA table change to wait
-       for more updates before triggering automatic reload. Default: 1 s.
-
-       <tag><label id="rtable-min-settle-time">min settle time <m/time/</tag>
-        Maximum settle time is an upper limit to the settle time from the
-        initial ROA table change even if there are consecutive updates gradually
-        renewing the settle time.  Default: 20 s.
+       <tag><label id="rtable-min-settle-time">roa settle time <m/time/ <m/time/</tag>
+       Minimum and maximum settle times, respectively, for ROA table changes.
+        The automatic reload is triggered after the minimum time after the last
+        ROA table change has been received but not later than the maximum time after
+        first unprocessed ROA table change. Therefore with default values, the
+        automatic reload happens 1 second after the ROA table stops updating, yet if it
+       were to be later than 20 seconds after the ROA table starts updating,
+       the automatic reload is triggered anyway. Default values: <cf/1 s 20 s/.
+       You have to always provide both values.
 
        <tag><label id="proto-import-limit">import limit [<m/number/ | off ] [action warn | block | restart | disable]</tag>
        Specify an import route limit (a maximum number of routes imported from
diff --git a/lib/settle.h b/lib/settle.h
new file mode 100644 (file)
index 0000000..d274599
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *     BIRD -- Settle timer
+ *
+ *     (c) 2022 Maria Matejka <mq@jmq.cz>
+ *     (c) 2022 CZ.NIC z.s.p.o.
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_SETTLE_H_
+#define _BIRD_SETTLE_H_
+
+#include "lib/birdlib.h"
+#include "lib/timer.h"
+
+struct settle_config {
+  btime min, max;
+};
+
+struct settle {
+  union {
+    /* Timer hook polymorphism. */
+    struct {
+      resource _r;
+      void (*hook)(struct settle *);
+    };
+    timer tm;
+  };
+  struct settle_config cf;
+  btime started;
+};
+
+STATIC_ASSERT(OFFSETOF(struct settle, hook) == OFFSETOF(struct settle, tm) + OFFSETOF(timer, hook));
+
+#define SETTLE_INIT(_cfp, _hook, _data) (struct settle) { .tm = { .data = (_data), }, .hook = (_hook), .cf = ({ASSERT_DIE((_cfp)->min <= (_cfp)->max); *(_cfp); }), }
+
+
+static inline void settle_init(struct settle *s, struct settle_config *cf, void (*hook)(struct settle *), void *data)
+{
+  *s = SETTLE_INIT(cf, hook, data);
+}
+
+#define settle_active(s) tm_active(&(s)->tm)
+
+static inline void settle_kick(struct settle *s, struct birdloop *loop)
+{
+  if (!tm_active(&s->tm))
+  {
+    s->started = current_time();
+    tm_set_in(&s->tm, s->started + s->cf.min, loop);
+  }
+  else
+  {
+    btime now = current_time();
+    tm_set_in(&s->tm, MIN_(now + s->cf.min, s->started + s->cf.max), loop);
+  }
+}
+
+static inline void settle_cancel(struct settle *s)
+{
+  tm_stop(&s->tm);
+}
+
+#endif
index 84c76ae931cf2bbe04746c39f8d5098f6f82115f..52f5aedb65efa2d61d46f1ce54aa14ff1ee1332b 100644 (file)
@@ -125,7 +125,7 @@ CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
 CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, AS)
 CF_KEYWORDS(MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE)
 CF_KEYWORDS(CHECK, LINK)
-CF_KEYWORDS(CORK, SORTED, TRIE, MIN, MAX, SETTLE, TIME, GC, THRESHOLD, PERIOD)
+CF_KEYWORDS(CORK, SORTED, TRIE, MIN, MAX, ROA, SETTLE, TIME, GC, THRESHOLD, PERIOD)
 
 /* For r_args_channel */
 CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
@@ -321,8 +321,7 @@ channel_item_:
  | RECEIVE LIMIT limit_spec { this_channel->rx_limit = $3; }
  | IMPORT LIMIT limit_spec { this_channel->in_limit = $3; }
  | EXPORT LIMIT limit_spec { this_channel->out_limit = $3; }
- | MIN SETTLE TIME expr_us { this_channel->min_settle_time = $4; }
- | MAX SETTLE TIME expr_us { this_channel->max_settle_time = $4; }
+ | ROA SETTLE TIME settle { this_channel->roa_settle = $4; }
  | PREFERENCE expr { this_channel->preference = $2; check_u16($2); }
  | IMPORT KEEP FILTERED bool {
      if ($4)
@@ -424,7 +423,6 @@ timeformat_base:
    TIMEFORMAT timeformat_spec ';'
  ;
 
-
 /* Interface patterns */
 
 iface_patt_node_init:
index 783a936c590456edc552c2035f74da3c5875ec4d..8c8daa0a05f8217815721f9f62331a916b052247 100644 (file)
@@ -315,16 +315,15 @@ proto_remove_channels(struct proto *p)
 
 struct roa_subscription {
   node roa_node;
-  timer t;
-  btime base_settle_time;              /* Start of settling interval */
+  struct settle settle;
   struct channel *c;
   struct rt_export_request req;
 };
 
 static void
-channel_roa_in_changed(struct timer *t)
+channel_roa_in_changed(struct settle *se)
 {
-  struct roa_subscription *s = SKIP_BACK(struct roa_subscription, t, t);
+  struct roa_subscription *s = SKIP_BACK(struct roa_subscription, settle, se);
   struct channel *c = s->c;
   int active = !!c->reload_req.hook;
 
@@ -337,9 +336,9 @@ channel_roa_in_changed(struct timer *t)
 }
 
 static void
-channel_roa_out_changed(struct timer *t)
+channel_roa_out_changed(struct settle *se)
 {
-  struct roa_subscription *s = SKIP_BACK(struct roa_subscription, t, t);
+  struct roa_subscription *s = SKIP_BACK(struct roa_subscription, settle, se);
   struct channel *c = s->c;
 
   CD(c, "Feeding triggered by RPKI change");
@@ -356,17 +355,7 @@ channel_export_one_roa(struct rt_export_request *req, const net_addr *net UNUSED
   struct roa_subscription *s = SKIP_BACK(struct roa_subscription, req, req);
 
   /* TODO: use the information about what roa has changed */
-
-  if (!tm_active(&s->t))
-  {
-    s->base_settle_time = current_time();
-    tm_start(&s->t, s->base_settle_time + s->c->min_settle_time);
-  }
-  else
-    tm_set(&s->t,
-       MIN(s->base_settle_time + s->c->max_settle_time,
-           current_time() + s->c->min_settle_time));
-
+  settle_kick(&s->settle, &main_birdloop);
 
   rpe_mark_seen_all(req->hook, first, NULL);
 }
@@ -380,14 +369,14 @@ channel_dump_roa_req(struct rt_export_request *req)
 
   debug("  Channel %s.%s ROA %s change notifier from table %s request %p\n",
       c->proto->name, c->name,
-      (s->t.hook == channel_roa_in_changed) ? "import" : "export",
+      (s->settle.hook == channel_roa_in_changed) ? "import" : "export",
       tab->name, req);
 }
 
 static int
 channel_roa_is_subscribed(struct channel *c, rtable *tab, int dir)
 {
-  void (*hook)(struct timer *) =
+  void (*hook)(struct settle *) =
     dir ? channel_roa_in_changed : channel_roa_out_changed;
 
   struct roa_subscription *s;
@@ -395,7 +384,7 @@ channel_roa_is_subscribed(struct channel *c, rtable *tab, int dir)
 
   WALK_LIST2(s, n, c->roa_subscriptions, roa_node)
     if ((tab == SKIP_BACK(rtable, priv.exporter.e, s->req.hook->table))
-         && (s->t.hook == hook))
+         && (s->settle.hook == hook))
       return 1;
 
   return 0;
@@ -410,7 +399,7 @@ channel_roa_subscribe(struct channel *c, rtable *tab, int dir)
   struct roa_subscription *s = mb_allocz(c->proto->pool, sizeof(struct roa_subscription));
 
   *s = (struct roa_subscription) {
-    .t = { .hook = dir ? channel_roa_in_changed : channel_roa_out_changed, },
+    .settle = SETTLE_INIT(&c->roa_settle, dir ? channel_roa_in_changed : channel_roa_out_changed, NULL),
     .c = c,
     .req = {
       .name = mb_sprintf(c->proto->pool, "%s.%s.roa-%s.%s",
@@ -934,8 +923,10 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty
   cf->debug = new_config->channel_default_debug;
   cf->rpki_reload = 1;
 
-  cf->min_settle_time = 1 S;
-  cf->max_settle_time = 20 S;
+  cf->roa_settle = (struct settle_config) {
+    .min = 1 S,
+    .max = 20 S,
+  };
 
   add_tail(&proto->channels, &cf->n);
 
@@ -1017,20 +1008,20 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
   c->in_req.trace_routes = c->out_req.trace_routes = c->debug | c->proto->debug;
   c->rpki_reload = cf->rpki_reload;
 
-  if (   (c->min_settle_time != cf->min_settle_time)
-       || (c->max_settle_time != cf->max_settle_time))
+  if (   (c->roa_settle.min != cf->roa_settle.min)
+       || (c->roa_settle.max != cf->roa_settle.max))
   {
-    c->min_settle_time = cf->min_settle_time;
-    c->max_settle_time = cf->max_settle_time;
+    c->roa_settle = cf->roa_settle;
 
     struct roa_subscription *s;
     node *n;
 
     WALK_LIST2(s, n, c->roa_subscriptions, roa_node)
-      if (tm_active(&s->t))
-       tm_set(&s->t,
-           MIN(s->base_settle_time + c->max_settle_time,
-             current_time() + c->min_settle_time));
+    {
+      s->settle.cf = cf->roa_settle;
+      if (settle_active(&s->settle))
+       settle_kick(&s->settle, &main_birdloop);
+    }
   }
 
   /* Execute channel-specific reconfigure hook */
index e9461d411948c07223bb862879d0040d5125982a..0bf894f805f87403a411883c1d2fd11a8b18e782 100644 (file)
@@ -12,6 +12,7 @@
 #include "lib/lists.h"
 #include "lib/resource.h"
 #include "lib/event.h"
+#include "lib/settle.h"
 #include "nest/rt.h"
 #include "nest/limit.h"
 #include "conf/conf.h"
@@ -462,8 +463,7 @@ struct channel_config {
   struct channel_limit in_limit;       /* Limit for importing routes from protocol */
   struct channel_limit out_limit;      /* Limit for exporting routes to protocol */
 
-  btime min_settle_time;               /* Minimum settle time for ROA-induced reload */
-  btime max_settle_time;               /* Maximum settle time for ROA-induced reload */
+  struct settle_config roa_settle;     /* Settle times for ROA-induced reload */
 
   u8 net_type;                         /* Routing table network type (NET_*), 0 for undefined */
   u8 ra_mode;                          /* Mode of received route advertisements (RA_*) */
@@ -492,8 +492,7 @@ struct channel {
   struct limit in_limit;               /* Input limit */
   struct limit out_limit;              /* Output limit */
 
-  btime min_settle_time;               /* Minimum settle time for ROA-induced reload */
-  btime max_settle_time;               /* Maximum settle time for ROA-induced reload */
+  struct settle_config roa_settle;     /* Settle times for ROA-induced reload */
 
   u8 limit_actions[PLD_MAX];           /* Limit actions enum */
   u8 limit_active;                     /* Flags for active limits */