]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge branch 'master' into thread-next oz-test3
authorOndrej Zajicek <santiago@crfreenet.org>
Sun, 11 May 2025 00:00:04 +0000 (02:00 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Sun, 11 May 2025 00:00:04 +0000 (02:00 +0200)
1  2 
conf/confbase.Y
doc/bird.sgml
filter/config.Y
nest/config.Y
proto/bgp/config.Y
proto/ospf/config.Y
proto/radv/config.Y
proto/static/config.Y
sysdep/unix/config.Y

diff --cc conf/confbase.Y
index 86ae099c9744217551d94b4d9d3301e61c482fd3,c7649c3e7515559e4b9b9640a3a3f35cf6aca811..ee32a0ce9559227c7435957dc3a5f305c098667f
@@@ -54,6 -51,31 +54,31 @@@ static inline void cf_assert_symbol(con
    }
  }
  
 -cf_type_name(enum f_type type)
+ static inline const char *
 -cf_assert_type(const struct f_val val, enum f_type type)
++cf_type_name(btype type)
+ {
+   /* There is already f_type_name(), but this uses names more suited
+      to configuration error messages */
+   switch (type)
+   {
+   case T_INT:         return "Number";
+   case T_BOOL:                return "Boolean";
+   case T_IP:          return "IP address";
+   case T_NET:         return "Network";
+   case T_STRING:      return "String";
+   case T_BYTESTRING:  return "Bytestring";
+   default:            return "???";
+   }
+ }
+ static inline void
++cf_assert_type(const struct f_val val, btype type)
+ {
+   if (val.type != type)
+     cf_error("%s expected", cf_type_name(type));
+ }
  CF_DECLS
  
  %union {
  %type <iface> ipa_scope
  
  %type <i> expr bool pxlen4
+ %type <i32> idval
  %type <time> expr_us time
 -%type <a> ipa
 +%type <settle> settle
 +%type <a> ipa net_ip6_slash
  %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_ net_aspa_
 -%type <mls> label_stack_start label_stack
 +%type <ad> label_stack_start label_stack
  
  %type <t> text opttext
  %type <bs> bytestring
@@@ -176,12 -215,23 +221,23 @@@ definition
     }
   ;
  
 - | '(' term ')' { $$ = cf_eval($2, T_VOID); }
+ conf_expr:
+    symbol_known {
+      /* If the symbol is not a constant, we pass empty f_val and fail later on type check */
+      $$ = (($1->class & ~0xff) == SYM_CONSTANT) ? *$1->val : (struct f_val) {};
+    }
 -symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN | KEYWORD ;
++ | '(' term ')' { $$ = *cf_eval($2, T_VOID); }
+  ;
++symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN ;
+ symbol_known: CF_SYM_KNOWN ;
+ /* Numbers */
  expr:
     NUM
-  | '(' term ')' { $$ = cf_eval_int($2); }
-  | CF_SYM_KNOWN {
-      if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
-      $$ = SYM_VAL($1).i; }
+  | conf_expr { cf_assert_type($1, T_INT); $$ = $1.val.i; }
   ;
  
  expr_us:
@@@ -386,61 -422,29 +449,38 @@@ net_any
     }
   ;
  
- net_or_ipa:
-    net_ip4_
-  | net_ip6_
-  | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
-  | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
-  | CF_SYM_KNOWN {
-      if ($1->class == (SYM_CONSTANT | T_IP))
-        net_fill_ip_host(&($$), SYM_VAL($1).ip);
-      else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net))
-        $$ = * SYM_VAL($1).net;
-      else
-        cf_error("IP address or network constant expected");
-    }
-  ;
- label_stack_start: NUM
+ label_stack_start: expr
  {
 -  $$ = cfg_allocz(sizeof(mpls_label_stack));
 -  $$->len = 1;
 -  $$->stack[0] = $1;
 +  $$ = cfg_allocz(ADATA_SIZE(MPLS_MAX_LABEL_STACK * sizeof(u32)));
 +  $$->length = sizeof(u32);
 +  *((u32 *)$$->data) = $1;
  };
  
  label_stack:
      label_stack_start
-   | label_stack '/' NUM {
+   | label_stack '/' expr {
 -    if ($1->len >= MPLS_MAX_LABEL_STACK)
 +    if ($1->length >= MPLS_MAX_LABEL_STACK * sizeof(u32))
        cf_error("Too many labels in stack");
 -    $1->stack[$1->len++] = $3;
 +
 +    *((u32 *)($$->data + $1->length)) = $3;
 +    $1->length += sizeof(u32);
      $$ = $1;
    }
  ;
  
- time:
-    TEXT {
-      $$ = tm_parse_time($1);
-      if (!$$)
-        cf_error("Invalid date/time");
-    }
-  ;
+ /* Strings */
  
 +/* 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 {
-      if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String constant expected");
-      $$ = SYM_VAL($1).s;
-    }
+  | conf_expr { cf_assert_type($1, T_STRING); $$ = $1.val.s; }
   ;
  
  opttext:
@@@ -466,12 -460,66 +496,66 @@@ time
     }
   ;
  
+ /* Bytestrings */
  bytestring:
     BYTETEXT
-  | bytestring_expr { $$ = cf_eval($1, T_BYTESTRING)->val.bs; }
+  | bytestring_expr { cf_assert_type($1, T_BYTESTRING); $$ = $1.val.bs; }
   ;
  
- bytestring_text:
+ bytestring_expr:
+    conf_expr
 - | term_bs { $$ = cf_eval($1, T_VOID); }
++ | term_bs { $$ = *cf_eval($1, T_VOID); }
+  ;
+ /* Mixed ones */
+ /* number | IPv4 -> number */
+ idval:
+    NUM { $$ = $1; }
+  | IP4 { $$ = ip4_to_u32($1); }
+  | conf_expr {
+      if (($1.type == T_INT) || ($1.type == T_QUAD))
+        $$ = $1.val.i;
+      else if (($1.type == T_IP) && ipa_is_ip4($1.val.ip))
+        $$ = ipa_to_u32($1.val.ip);
+      else
+        cf_error("Number or IPv4 address expected");
+    }
+  ;
+ /* net | ipa -> net */
+ net_or_ipa:
+    net_ip4_
+  | net_ip6_
+  | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
+  | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
+  | conf_expr {
+      if ($1.type == T_IP)
+        net_fill_ip_host(&($$), $1.val.ip);
+      else if (($1.type == T_NET) && net_is_ip($1.val.net))
+        $$ = * $1.val.net;
+      else
+        cf_error("IP address/prefix expected");
+    }
+  ;
+ /* text | ipa -> f_val */
+ text_or_ipa:
+    TEXT { $$.type = T_STRING; $$.val.s = $1; }
+  | IP4 { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
+  | IP6 { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
+  | conf_expr {
+      if (($1.type != T_STRING) && ($1.type != T_IP))
+        cf_error("String or IP address expected");
+      $$ = $1;
+    }
+  ;
+ /* bytestring | text -> f_val */
+ bytestring_or_text:
     BYTETEXT { $$.type = T_BYTESTRING; $$.val.bs = $1; }
   | TEXT { $$.type = T_STRING; $$.val.s = $1; }
   | bytestring_expr {
diff --cc doc/bird.sgml
Simple merge
diff --cc filter/config.Y
Simple merge
diff --cc nest/config.Y
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 4599b547192b7d9e67336f17b44b8f2cf8a164fb,1119baee80d01d42dd7338eda5b7f161ec89ebf9..527fc0e0fc616e414d00ac4ee5c4f20a480e1c36
@@@ -83,8 -82,8 +83,8 @@@ log_udp_host: text_or_ip
  };
  
  log_udp_port:
 -    /* empty */ { this_log->port = 514; }
 -  | PORT expr { check_u16($2); this_log->port = $2; }
 +    /* empty */ { this_log->udp_port = 514; }
-   | PORT NUM { check_u16($2); this_log->udp_port = $2; }
++  | PORT expr { check_u16($2); this_log->udp_port = $2; }
    ;
  
  log_mask:
@@@ -143,65 -142,10 +143,65 @@@ cli_opts_begin: 
  };
  
  cli_opts_block:
 -  /* EMPTY */ |
 -  cli_opts_block RESTRICT { this_cli_config->restricted = 1; }
 +  /* EMPTY */
 +  | cli_opts_block RESTRICT ';' { this_cli_config->restricted = 1; }
 +  | cli_opts_block V2 ATTRIBUTES ';' { this_cli_config->v2attributes = 1; }
  ;
  
- conf: THREADS NUM {
++conf: THREADS expr {
 +  if ($2 < 1) cf_error("Number of threads must be at least one.");
 +  if (!new_config->thread_group_simple &&
 +      !EMPTY_TLIST(thread_group_config, &new_config->thread_group))
 +    cf_error("Mixing of `threads NUM` and `threads worker {}` is not allowed.");
 +
 +  if (new_config->thread_group_simple == -1)
 +    THEAD(thread_group_config, &new_config->thread_group)->thread_count = $2;
 +
 +  new_config->thread_group_simple = $2;
 +};
 +
 +conf: THREAD GROUP symbol {
 +  switch (new_config->thread_group_simple) {
 +    case -1: cf_error("Put `threads` block before any protocol or table definition.");
 +    case 0: break;
 +    default: cf_error("Mixing of `threads NUM` and `threads worker {}` is not allowed.");
 +  }
 +
 +  this_thread_group = cfg_alloc(sizeof *this_thread_group);
 +  *this_thread_group = strcmp($3->name, "express") ?
 +    thread_group_config_default_worker :
 +    thread_group_config_default_express;
 +} '{' thread_group_opts '}' {
 +  if (this_thread_group->params.max_time > 60 S_)
 +    cf_error("Loop time maximum is 60 seconds, got %t", this_thread_group->params.max_time);
 +  if (this_thread_group->params.max_latency < this_thread_group->params.max_time)
 +    cf_error("Loop time maximum can't be higher than its latency limit");
 +  if (this_thread_group->params.min_time > this_thread_group->params.max_time)
 +    cf_error("Loop time minimm can't be higher than maximum");
 +  if (this_thread_group->params.wakeup_time < 1 S_)
 +    cf_error("Too low idle wakeup time, expected at least 1 second");
 +
 +  this_thread_group->symbol = cf_define_symbol(new_config, $3, SYM_THREAD_GROUP, thread_group, this_thread_group);
 +  thread_group_config_add_tail(&new_config->thread_group, this_thread_group);
 +  this_thread_group = NULL;
 +};
 +
 +thread_group_opts: MAX TIME expr_us ';' { this_thread_group->params.max_time = $3; } ;
 +thread_group_opts: MIN TIME expr_us ';' { this_thread_group->params.min_time = $3; } ;
 +thread_group_opts: MAX LATENCY expr_us ';' { this_thread_group->params.max_latency = $3; } ;
 +thread_group_opts: THREADS expr ';' { this_thread_group->thread_count = $2; } ;
 +thread_group_opts: WAKEUP TIME expr_us ';' { this_thread_group->params.wakeup_time = $3; } ;
 +thread_group_opts: DEFAULT bool ';' {
 +  if ($2) {
 +    if (new_config->default_thread_group &&
 +      new_config->default_thread_group != this_thread_group)
 +      cf_error("Too many default thread groups, already have %s",
 +        new_config->default_thread_group->symbol->name);
 +    new_config->default_thread_group = this_thread_group;
 +  }
 +};
 +
 +
  conf: debug_unix ;
  
  debug_unix: