]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit 'fdd39c81' into thread-next
authorMaria Matejka <mq@ucw.cz>
Sat, 28 Oct 2023 22:00:07 +0000 (00:00 +0200)
committerMaria Matejka <mq@ucw.cz>
Sat, 28 Oct 2023 22:00:07 +0000 (00:00 +0200)
1  2 
filter/config.Y
filter/decl.m4
filter/f-inst.c
filter/f-inst.h
filter/f-util.c
filter/filter.c

diff --cc filter/config.Y
index 4ce9ee0f734d856189defdacc0e00156c7eaef22,1f5d2bc53c5162a36328f5bc428618ae7411d186..aaba2201f8d1d1b6db21bf104dd8fba331f93f1a
@@@ -383,17 -368,14 +383,13 @@@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UN
        EMPTY,
        FILTER, WHERE, EVAL, ATTRIBUTE,
        FROM_HEX,
 -      BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
 +      BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT, STACKS)
  
- CF_METHODS(IS_V4, TYPE, IP, RD, LEN, MAXLEN, ASN, SRC, DST, MASK,
-       FIRST, LAST, LAST_NONAGGREGATED, DATA, DATA1, DATA2, MIN, MAX,
-       EMPTY, PREPEND, ADD, DELETE, FILTER)
  %nonassoc THEN
  %nonassoc ELSE
  
  %type <xp> cmds_int cmd_prep
- %type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor print_list var var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont
+ %type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor var var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont
 -%type <fda> dynamic_attr
  %type <fsa> static_attr
  %type <f> filter where_filter
  %type <fl> filter_body function_body
@@@ -1043,10 -998,9 +1029,9 @@@ cmd
     { new_config->current_scope->active = 0; } term { new_config->current_scope->active = 1; }
     DO cmd {
       cf_pop_block_scope(new_config);
-      $$ = f_new_inst(FI_FOR_INIT, $6, $3);
-      $$->next = f_new_inst(FI_FOR_NEXT, $3, $9);
+      $$ = f_for_cycle($3, $6, $9);
     }
 - | symbol_known '=' term ';' {
 + | CF_SYM_KNOWN '=' term ';' {
       switch ($1->class) {
         case SYM_VARIABLE_RANGE:
         $$ = f_new_inst(FI_VAR_SET, $3, $1);
         cf_error( "This static attribute is read-only.");
       $$ = f_new_inst(FI_RTA_SET, $3, $1);
     }
 - | UNSET '(' dynamic_attr ')' ';' {
 -     $$ = f_new_inst(FI_EA_UNSET, $3);
 + | UNSET '(' CF_SYM_KNOWN ')' ';' {
 +     if ($3->class != SYM_ATTRIBUTE)
 +       cf_error("Can't unset %s", $3->name);
 +     if ($3->attribute->readonly)
 +       cf_error("Attribute %s is read-only", $3->attribute->name);
 +     $$ = f_new_inst(FI_EA_UNSET, $3->attribute);
     }
-  | break_command print_list ';' {
-     struct f_inst *breaker = f_new_inst(FI_DIE, $1);
-     if ($2) {
-       struct f_inst *printer = f_new_inst(FI_PRINT, $2);
-       struct f_inst *flusher = f_new_inst(FI_FLUSH);
-       printer->next = flusher;
-       flusher->next = breaker;
-       $$ = printer;
-     } else
-       $$ = breaker;
+  | break_command var_list ';' {
+     $$ = f_print($2, !!$2, $1);
     }
-  | PRINT print_list ';' {
-     $$ = f_new_inst(FI_PRINT, $2);
-     $$->next = f_new_inst(FI_FLUSH);
+  | PRINT var_list ';' {
+     $$ = f_print($2, 1, F_NOP);
     }
-  | PRINTN print_list ';' {
-     $$ = f_new_inst(FI_PRINT, $2);
+  | PRINTN var_list ';' {
+     $$ = f_print($2, 0, F_NOP);
     }
   | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
   | CASE term '{' switch_body '}' {
diff --cc filter/decl.m4
index 8900568754f6da3880116d56037a5f61baf2f61d,d292f65b9921eba891a6b29725a51d6641c803ba..9d6b64ad0bcfa783a82e20a9fa8941cca46f32a6
@@@ -399,9 -419,11 +420,9 @@@ m4_undivert(112
    }
  
  FID_METHOD_SCOPE_INIT()m4_dnl
--  [INST_METHOD_OBJECT_TYPE] = {},
++  [INST_METHOD_OBJECT_TYPE] = { .active = 1, },
  FID_METHOD_REGISTER()m4_dnl
 -  sym = cf_new_symbol(&f_type_method_scopes[INST_METHOD_OBJECT_TYPE],
 -                    global_root_scope_pool, global_root_scope_linpool,
 -                    INST_METHOD_NAME);
 +  sym = cf_root_symbol(INST_METHOD_NAME, &f_type_method_scopes[INST_METHOD_OBJECT_TYPE]);
    sym->class = SYM_METHOD;
    sym->method = method = lp_allocz(global_root_scope_linpool, sizeof(struct f_method));
  
diff --cc filter/f-inst.c
index 8a00438b720e09ae0775b69835f29a983a1afa90,6977f65612212e5af25b12fdb01c6acfc30e21da..c66d64a1e06a5514e37ef2f7c8dab1b0082f9b01
        LINE(3,0);
    }
  
-   INST(FI_PRINT, 0, 0) {
+   INST(FI_PRINT, 1, 0) {
      NEVER_CONSTANT;
-     VARARG;
+     ARG_ANY(1);
  
-     if (whati->varcount && !(fs->flags & FF_SILENT))
+     if (!(fs->flags & FF_SILENT))
 -      val_format(&v1, &fs->buf);
 +    {
 +      if (!fs->buf.class)
 +      log_prepare(&fs->buf, *L_INFO);
 +
-       for (uint i=0; i<whati->varcount; i++)
-       val_format(&(vv(i)), &fs->buf.buf);
++      val_format(&v1, &fs->buf.buf);
 +    }
    }
  
    INST(FI_FLUSH, 0, 0) {
    INST(FI_EA_UNSET, 0, 0) {
      DYNAMIC_ATTR;
      ACCESS_RTE;
 -    ACCESS_EATTRS;
  
 -    f_rta_cow(fs);
 -    ea_unset_attr(fs->eattrs, fs->pool, 1, da.ea_code);
 +    ea_unset_attr(&fs->rte->attrs, 1, da);
 +  }
 +
 +  INST(FI_DEFAULT, 2, 1) {
 +    ARG_ANY(1);
 +    ARG_ANY(2);
 +    RESULT_TYPE(f_type_element_type(v2.type));
 +
 +    log(L_INFO "Type of arg 1 is: %d", v1.type);
 +
 +    if (v1.type == T_VOID)
 +      RESULT_VAL(v2);
 +    else
 +      RESULT_VAL(v1);
    }
  
-   INST(FI_NET_LENGTH, 1, 1) { /* Get length of */
-     ARG(1, T_NET);
-     METHOD_CONSTRUCTOR("len");
-     RESULT(T_INT, i, net_pxlen(v1.val.net));
-   }
-   INST(FI_PATH_LENGTH, 1, 1) {        /* Get length of */
-     ARG(1, T_PATH);
-     METHOD_CONSTRUCTOR("len");
-     RESULT(T_INT, i, as_path_getlen(v1.val.ad));
-   }
-   INST(FI_CLIST_LENGTH, 1, 1) {       /* Get length of */
-     ARG(1, T_CLIST);
-     METHOD_CONSTRUCTOR("len");
-     RESULT(T_INT, i, int_set_get_size(v1.val.ad));
-   }
-   INST(FI_ECLIST_LENGTH, 1, 1) { /* Get length of */
-     ARG(1, T_ECLIST);
-     METHOD_CONSTRUCTOR("len");
-     RESULT(T_INT, i, ec_set_get_size(v1.val.ad));
-   }
-   INST(FI_LCLIST_LENGTH, 1, 1) {      /* Get length of */
-     ARG(1, T_LCLIST);
-     METHOD_CONSTRUCTOR("len");
-     RESULT(T_INT, i, lc_set_get_size(v1.val.ad));
-   }
+   /* Get length of */
+   METHOD_R(T_NET, len, 0, T_INT, i, net_pxlen(v1.val.net));
+   METHOD_R(T_PATH, len, 0, T_INT, i, as_path_getlen(v1.val.ad));
+   METHOD_R(T_CLIST, len, 0, T_INT, i, int_set_get_size(v1.val.ad));
+   METHOD_R(T_ECLIST, len, 0, T_INT, i, ec_set_get_size(v1.val.ad));
+   METHOD_R(T_LCLIST, len, 0, T_INT, i, lc_set_get_size(v1.val.ad));
  
    INST(FI_NET_SRC, 1, 1) {    /* Get src prefix */
      ARG(1, T_NET);
diff --cc filter/f-inst.h
index 57186c9530f5d87551915686061de1b6a395c3c5,8c304de5d200cd45b89184407b2e8fdedbf0877d..c741265b292235490e0c2d7aa8b0bdcd04b23742
@@@ -96,9 -96,15 +96,12 @@@ void f_add_lines(const struct f_line_it
  
  
  struct filter *f_new_where(struct f_inst *);
 -static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
 -{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; }   /* f_type currently unused; will be handy for static type checking */
 -static inline struct f_dynamic_attr f_new_dynamic_attr_bit(u8 bit, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
 -{ return (struct f_dynamic_attr) { .type = EAF_TYPE_BITFIELD, .bit = bit, .f_type = f_type, .ea_code = code }; }   /* f_type currently unused; will be handy for static type checking */
 -static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly)
 -{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; }
+ struct f_inst *f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block);
+ struct f_inst *f_print(struct f_inst *vars, int flush, enum filter_return fret);
 +static inline struct f_static_attr f_new_static_attr(btype type, int code, int readonly)
 +{ return (struct f_static_attr) { .type = type, .sa_code = code, .readonly = readonly }; }
 +struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
  
  /* Hook for call bt_assert() function in configuration */
  extern void (*bt_assert_hook)(int result, const struct f_line_item *assert);
diff --cc filter/f-util.c
index 82a06bddc7fe51e20ad2336be46b2372ecdf1860,98b7d1a873134ac23757c80ef9f009da394394ef..0d998f3db949d1d9ec0e6364d64d273b9c402db7
@@@ -40,3 -40,203 +40,61 @@@ struct filter *f_new_where(struct f_ins
    f->root = f_linearize(cond, 0);
    return f;
  }
 -  enum f_type el_type = f_type_element_type(term->type);
+ struct f_inst *
+ f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block)
+ {
+   ASSERT((var->class & ~0xff) == SYM_VARIABLE);
+   ASSERT(term->next == NULL);
+   /* Static type check */
+   if (term->type == T_VOID)
+     cf_error("Couldn't infer the type of FOR expression, please assign it to a variable.");
 -
 -
 -#define CA_KEY(n)     n->name, n->fda.type
 -#define CA_NEXT(n)    n->next
 -#define CA_EQ(na,ta,nb,tb)    (!strcmp(na,nb) && (ta == tb))
 -#define CA_FN(n,t)    (mem_hash(n, strlen(n)) ^ (t*0xaae99453U))
 -#define CA_ORDER      8 /* Fixed */
 -
 -struct ca_storage {
 -  struct ca_storage *next;
 -  struct f_dynamic_attr fda;
 -  u32 uc;
 -  char name[0];
 -};
 -
 -HASH(struct ca_storage) ca_hash;
 -
 -static struct idm ca_idm;
 -static struct ca_storage **ca_storage;
 -static uint ca_storage_max;
 -
 -static void
 -ca_free(resource *r)
 -{
 -  struct custom_attribute *ca = (void *) r;
 -  struct ca_storage *cas = HASH_FIND(ca_hash, CA, ca->name, ca->fda->type);
 -  ASSERT(cas);
 -
 -  ca->name = NULL;
 -  ca->fda = NULL;
 -  if (!--cas->uc) {
 -    uint id = EA_CUSTOM_ID(cas->fda.ea_code);
 -    idm_free(&ca_idm, id);
 -    HASH_REMOVE(ca_hash, CA, cas);
 -    ca_storage[id] = NULL;
 -    mb_free(cas);
 -  }
 -}
 -
 -static void
 -ca_dump(resource *r)
 -{
 -  struct custom_attribute *ca = (void *) r;
 -  debug("name \"%s\" id 0x%04x ea_type 0x%02x f_type 0x%02x\n",
 -      ca->name, ca->fda->ea_code, ca->fda->type, ca->fda->f_type);
 -}
 -
 -static struct resclass ca_class = {
 -  .name = "Custom attribute",
 -  .size = sizeof(struct custom_attribute),
 -  .free = ca_free,
 -  .dump = ca_dump,
 -  .lookup = NULL,
 -  .memsize = NULL,
 -};
 -
 -struct custom_attribute *
 -ca_lookup(pool *p, const char *name, int f_type)
 -{
 -  int ea_type;
 -
 -  switch (f_type) {
 -    case T_INT:
 -      ea_type = EAF_TYPE_INT;
 -      break;
 -    case T_IP:
 -      ea_type = EAF_TYPE_IP_ADDRESS;
 -      break;
 -    case T_QUAD:
 -      ea_type = EAF_TYPE_ROUTER_ID;
 -      break;
 -    case T_PATH:
 -      ea_type = EAF_TYPE_AS_PATH;
 -      break;
 -    case T_CLIST:
 -      ea_type = EAF_TYPE_INT_SET;
 -      break;
 -    case T_ECLIST:
 -      ea_type = EAF_TYPE_EC_SET;
 -      break;
 -    case T_LCLIST:
 -      ea_type = EAF_TYPE_LC_SET;
 -      break;
 -    default:
 -      cf_error("Custom route attribute of unsupported type");
 -  }
 -
 -  static int inited = 0;
 -  if (!inited) {
 -    idm_init(&ca_idm, config_pool, 8);
 -    HASH_INIT(ca_hash, config_pool, CA_ORDER);
 -
 -    ca_storage_max = 256;
 -    ca_storage = mb_allocz(config_pool, sizeof(struct ca_storage *) * ca_storage_max);
 -
 -    inited++;
 -  }
 -
 -  struct ca_storage *cas = HASH_FIND(ca_hash, CA, name, ea_type);
 -  if (cas) {
 -    cas->uc++;
 -  } else {
 -
 -    uint id = idm_alloc(&ca_idm);
 -
 -    if (id >= EA_CUSTOM_BIT)
 -      cf_error("Too many custom attributes.");
 -
 -    if (id >= ca_storage_max) {
 -      ca_storage_max *= 2;
 -      ca_storage = mb_realloc(ca_storage, sizeof(struct ca_storage *) * ca_storage_max * 2);
 -    }
 -
 -    cas = mb_allocz(config_pool, sizeof(struct ca_storage) + strlen(name) + 1);
 -    cas->fda = f_new_dynamic_attr(ea_type, f_type, EA_CUSTOM(id));
 -    cas->uc = 1;
 -
 -    strcpy(cas->name, name);
 -    ca_storage[id] = cas;
 -
 -    HASH_INSERT(ca_hash, CA, cas);
 -  }
 -
 -  struct custom_attribute *ca = ralloc(p, &ca_class);
 -  ca->fda = &(cas->fda);
 -  ca->name = cas->name;
 -  return ca;
 -}
 -
 -const char *
 -ea_custom_name(uint ea)
 -{
 -  uint id = EA_CUSTOM_ID(ea);
 -  if (id >= ca_storage_max)
 -    return NULL;
 -
 -  if (!ca_storage[id])
 -    return NULL;
 -
 -  return ca_storage[id]->name;
 -}
 -
++  enum btype el_type = f_type_element_type(term->type);
+   struct sym_scope *scope = el_type ? f_type_method_scope(term->type) : NULL;
+   struct symbol *ms = scope ? cf_find_symbol_scope(scope, "!for_next") : NULL;
+   if (!ms)
+     cf_error("Type %s is not iterable, can't be used in FOR", f_type_name(term->type));
+   if (var->class != (SYM_VARIABLE | el_type))
+     cf_error("Loop variable '%s' in FOR must be of type %s, got %s",
+       var->name, f_type_name(el_type), f_type_name(var->class & 0xff));
+   /* Push the iterator auxiliary value onto stack */
+   struct f_inst *iter = term->next = f_new_inst(FI_CONSTANT, (struct f_val) {});
+   /* Initialize the iterator variable */
+   iter->next = f_new_inst(FI_CONSTANT, (struct f_val) { .type = el_type });
+   /* Prepend the loop block with loop beginning instruction */
+   struct f_inst *loop_start = f_new_inst(FI_FOR_LOOP_START, var);
+   loop_start->next = block;
+   return ms->method->new_inst(term, loop_start);
+ }
+ struct f_inst *
+ f_print(struct f_inst *vars, int flush, enum filter_return fret)
+ {
+ #define AX(...)  do { struct f_inst *_tmp = f_new_inst(__VA_ARGS__); _tmp->next = output; output = _tmp; } while (0)
+   struct f_inst *output = NULL;
+   if (fret != F_NOP)
+     AX(FI_DIE, fret);
+   if (flush)
+     AX(FI_FLUSH);
+   while (vars)
+   {
+     struct f_inst *tmp = vars;
+     vars = vars->next;
+     tmp->next = NULL;
+     AX(FI_PRINT, tmp);
+   }
+   return output;
+ #undef AX
+ }
diff --cc filter/filter.c
index 7eb109a17f2fd79be5985768e07dc1c2e986db25,65fb92a4122a2b1cd987c7ed57c9d0c3a4ee4c47..c5597734d526a8cea72ab744612bb553d2027f24
@@@ -122,12 -170,11 +122,13 @@@ interpret(struct filter_state *fs, cons
  
    /* The same as with the value stack. Not resetting the stack for performance reasons. */
    fstk->ecnt = 1;
 -  fstk->estk[0].line = line;
 -  fstk->estk[0].pos = 0;
 +  fstk->estk[0] = (struct filter_exec_stack) {
 +    .line = line,
 +    .pos = 0,
 +  };
  
  #define curline fstk->estk[fstk->ecnt-1]
+ #define prevline fstk->estk[fstk->ecnt-2]
  
  #ifdef LOCAL_DEBUG
    debug("Interpreting line.");