File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird2 / filter / f-inst.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 21 16:03:56 2019 UTC (4 years, 8 months ago) by misho
Branches: bird2, MAIN
CVS tags: v2_0_7p0, HEAD
bird2 ver 2.0.7

    1: /*
    2:  *	Filters: Instructions themselves
    3:  *
    4:  *	Copyright 1998 Pavel Machek <pavel@ucw.cz>
    5:  *	Copyright 2018 Maria Matejka <mq@jmq.cz>
    6:  *	Copyright 2018 CZ.NIC z.s.p.o.
    7:  *
    8:  *	Can be freely distributed and used under the terms of the GNU GPL.
    9:  *
   10:  *	The filter code goes through several phases:
   11:  *
   12:  *	1  Parsing
   13:  *	Flex- and Bison-generated parser decodes the human-readable data into
   14:  *	a struct f_inst tree. This is an infix tree that was interpreted by
   15:  *	depth-first search execution in previous versions of the interpreter.
   16:  *	All instructions have their constructor: f_new_inst(FI_EXAMPLE, ...)
   17:  *	translates into f_new_inst_FI_EXAMPLE(...) and the types are checked in
   18:  *	compile time. If the result of the instruction is always the same,
   19:  *	it's reduced to FI_CONSTANT directly in constructor. This phase also
   20:  *	counts how many instructions are underlying in means of f_line_item
   21:  *	fields to know how much we have to allocate in the next phase.
   22:  *
   23:  *	2  Linearize before interpreting
   24:  *	The infix tree is always interpreted in the same order. Therefore we
   25:  *	sort the instructions one after another into struct f_line. Results
   26:  *	and arguments of these instructions are implicitly put on a value
   27:  *	stack; e.g. the + operation just takes two arguments from the value
   28:  *	stack and puts the result on there.
   29:  *
   30:  *	3  Interpret
   31:  *	The given line is put on a custom execution stack. If needed (FI_CALL,
   32:  *	FI_SWITCH, FI_AND, FI_OR, FI_CONDITION, ...), another line is put on top
   33:  *	of the stack; when that line finishes, the execution continues on the
   34:  *	older lines on the stack where it stopped before.
   35:  *
   36:  *	4  Same
   37:  *	On config reload, the filters have to be compared whether channel
   38:  *	reload is needed or not. The comparison is done by comparing the
   39:  *	struct f_line's recursively.
   40:  *
   41:  *	The main purpose of this rework was to improve filter performance
   42:  *	by making the interpreter non-recursive.
   43:  *
   44:  *	The other outcome is concentration of instruction definitions to
   45:  *	one place -- right here. You shall define your instruction only here
   46:  *	and nowhere else.
   47:  *
   48:  *	Beware. This file is interpreted by M4 macros. These macros
   49:  *	may be more stupid than you could imagine. If something strange
   50:  *	happens after changing this file, compare the results before and
   51:  *	after your change (see the Makefile to find out where the results are)
   52:  *	and see what really happened.
   53:  *
   54:  *	This file is not directly a C source code -> it is a generator input
   55:  *	for several C sources; every instruction block gets expanded into many
   56:  *	different places.
   57:  *
   58:  *	All the arguments are processed literally; if you need an argument including comma,
   59:  *	you have to quote it by [[ ... ]]
   60:  *
   61:  *	What is the syntax here?
   62:  *	m4_dnl	INST(FI_NOP, in, out) {			enum value, input args, output args
   63:  *	m4_dnl	  ARG(num, type);			argument, its id (in data fields) and type accessible by v1, v2, v3
   64:  *	m4_dnl	  ARG_ANY(num);				argument with no type check accessible by v1, v2, v3
   65:  *	m4_dnl	  VARARG;				variable-length argument list; accessible by vv(i) and whati->varcount
   66:  *	m4_dnl	  LINE(num, unused);			this argument has to be converted to its own f_line
   67:  *	m4_dnl	  SYMBOL;				symbol handed from config
   68:  *	m4_dnl	  STATIC_ATTR;				static attribute definition
   69:  *	m4_dnl	  DYNAMIC_ATTR;				dynamic attribute definition
   70:  *	m4_dnl	  RTC;					route table config
   71:  *	m4_dnl	  ACCESS_RTE;				this instruction needs route
   72:  *	m4_dnl	  ACCESS_EATTRS;			this instruction needs extended attributes
   73:  *
   74:  *	m4_dnl	  FID_MEMBER(				custom instruction member
   75:  *	m4_dnl	    C type,				for storage in structs
   76:  *	m4_dnl	    name,				how the member is named
   77:  *	m4_dnl	    comparator for same(),		if different, this should be TRUE (CAVEAT)
   78:  *	m4_dnl	    dump format string			debug -> format string for bvsnprintf
   79:  *	m4_dnl	    dump format args			appropriate args
   80:  *	m4_dnl	  )
   81:  *
   82:  *	m4_dnl	  RESULT(type, union-field, value);	putting this on value stack
   83:  *	m4_dnl	  RESULT_VAL(value-struct);		pass the struct f_val directly
   84:  *	m4_dnl	  RESULT_VOID;				return undef
   85:  *	m4_dnl	}
   86:  *
   87:  *	Also note that the { ... } blocks are not respected by M4 at all.
   88:  *	If you get weird unmatched-brace-pair errors, check what it generated and why.
   89:  *	What is really considered as one instruction is not the { ... } block
   90:  *	after m4_dnl INST() but all the code between them.
   91:  *
   92:  *	Other code is just copied into the interpreter part.
   93:  *
   94:  *	If you are satisfied with this, you don't need to read the following
   95:  *	detailed description of what is really done with the instruction definitions.
   96:  *
   97:  *	m4_dnl	Now let's look under the cover. The code between each INST()
   98:  *	m4_dnl	is copied to several places, namely these (numbered by the M4 diversions
   99:  *	m4_dnl	used in filter/decl.m4):
  100:  *
  101:  *	m4_dnl	(102)	struct f_inst *f_new_inst(FI_EXAMPLE [[ put it here ]])
  102:  *	m4_dnl		{
  103:  *	m4_dnl		  ... (common code)
  104:  *	m4_dnl	(103)	  [[ put it here ]]
  105:  *	m4_dnl		  ...
  106:  *	m4_dnl		  if (all arguments are constant)
  107:  *	m4_dnl	(108)	    [[ put it here ]]	    
  108:  *	m4_dnl		}
  109:  *	m4_dnl	For writing directly to constructor argument list, use FID_NEW_ARGS.
  110:  *	m4_dnl	For computing something in constructor (103), use FID_NEW_BODY.
  111:  *	m4_dnl	For constant pre-interpretation (108), see below at FID_INTERPRET_BODY.
  112:  *
  113:  *	m4_dnl		struct f_inst {
  114:  *	m4_dnl		  ... (common fields)
  115:  *	m4_dnl		  union {
  116:  *	m4_dnl		    struct {
  117:  *	m4_dnl	(101)	      [[ put it here ]]
  118:  *	m4_dnl		    } i_FI_EXAMPLE;
  119:  *	m4_dnl		    ...
  120:  *	m4_dnl		  };
  121:  *	m4_dnl		};
  122:  *	m4_dnl	This structure is returned from constructor.
  123:  *	m4_dnl	For writing directly to this structure, use FID_STRUCT_IN.
  124:  *
  125:  *	m4_dnl		linearize(struct f_line *dest, const struct f_inst *what, uint pos) {
  126:  *	m4_dnl		  ...
  127:  *	m4_dnl		    switch (what->fi_code) {
  128:  *	m4_dnl		      case FI_EXAMPLE:
  129:  *	m4_dnl	(105)		[[ put it here ]]
  130:  *	m4_dnl			break;
  131:  *	m4_dnl		    }
  132:  *	m4_dnl		}
  133:  *	m4_dnl	This is called when translating from struct f_inst to struct f_line_item.
  134:  *	m4_dnl	For accessing your custom instruction data, use following macros:
  135:  *	m4_dnl	  whati	-> for accessing (struct f_inst).i_FI_EXAMPLE
  136:  *	m4_dnl	  item	-> for accessing (struct f_line)[pos].i_FI_EXAMPLE
  137:  *	m4_dnl	For writing directly here, use FID_LINEARIZE_BODY.
  138:  *
  139:  *	m4_dnl	(107)	struct f_line_item {
  140:  *	m4_dnl		  ... (common fields)
  141:  *	m4_dnl		  union {
  142:  *	m4_dnl		    struct {
  143:  *	m4_dnl	(101)	      [[ put it here ]]
  144:  *	m4_dnl		    } i_FI_EXAMPLE;
  145:  *	m4_dnl		    ...
  146:  *	m4_dnl		  };
  147:  *	m4_dnl		};
  148:  *	m4_dnl	The same as FID_STRUCT_IN (101) but for the other structure.
  149:  *	m4_dnl	This structure is returned from the linearizer (105).
  150:  *	m4_dnl	For writing directly to this structure, use FID_LINE_IN.
  151:  *
  152:  *	m4_dnl		f_dump_line_item_FI_EXAMPLE(const struct f_line_item *item, const int indent)
  153:  *	m4_dnl		{
  154:  *	m4_dnl	(104)	  [[ put it here ]]
  155:  *	m4_dnl		}
  156:  *	m4_dnl	This code dumps the instruction on debug. Note that the argument
  157:  *	m4_dnl	is the linearized instruction; if the instruction has arguments,
  158:  *	m4_dnl	their code has already been linearized and their value is taken
  159:  *	m4_dnl	from the value stack.
  160:  *	m4_dnl	For writing directly here, use FID_DUMP_BODY.
  161:  *
  162:  *	m4_dnl		f_same(...)
  163:  *	m4_dnl		{
  164:  *	m4_dnl		  switch (f1_->fi_code) {
  165:  *	m4_dnl		    case FI_EXAMPLE:
  166:  *	m4_dnl	(106)	      [[ put it here ]]
  167:  *	m4_dnl		      break;
  168:  *	m4_dnl		  }
  169:  *	m4_dnl		}
  170:  *	m4_dnl	This code compares the two given instrucions (f1_ and f2_)
  171:  *	m4_dnl	on reconfigure. For accessing your custom instruction data,
  172:  *	m4_dnl	use macros f1 and f2.
  173:  *	m4_dnl	For writing directly here, use FID_SAME_BODY.
  174:  *
  175:  *	m4_dnl		interpret(...)
  176:  *	m4_dnl		{
  177:  *	m4_dnl		  switch (what->fi_code) {
  178:  *	m4_dnl		    case FI_EXAMPLE:
  179:  *	m4_dnl	(108)	      [[ put it here ]]
  180:  *	m4_dnl		      break;
  181:  *	m4_dnl		  }
  182:  *	m4_dnl		}
  183:  *	m4_dnl	This code executes the instruction. Every pre-defined macro
  184:  *	m4_dnl	resets the output here. For setting it explicitly,
  185:  *	m4_dnl	use FID_INTERPRET_BODY.
  186:  *	m4_dnl	This code is put on two places; one is the interpreter, the other
  187:  *	m4_dnl	is instruction constructor. If you need to distinguish between
  188:  *	m4_dnl	these two, use FID_INTERPRET_EXEC or FID_INTERPRET_NEW respectively.
  189:  *	m4_dnl	To address the difference between interpreter and constructor
  190:  *	m4_dnl	environments, there are several convenience macros defined:
  191:  *	m4_dnl	  runtime()	-> for spitting out runtime error like division by zero
  192:  *	m4_dnl	  RESULT(...)	-> declare result; may overwrite arguments
  193:  *	m4_dnl	  v1, v2, v3	-> positional arguments, may be overwritten by RESULT()
  194:  *	m4_dnl	  falloc(size)	-> allocate memory from the appropriate linpool
  195:  *	m4_dnl	  fpool		-> the current linpool
  196:  *	m4_dnl	  NEVER_CONSTANT-> don't generate pre-interpretation code at all
  197:  *	m4_dnl	  ACCESS_RTE	-> check that route is available, also NEVER_CONSTANT
  198:  *	m4_dnl	  ACCESS_EATTRS	-> pre-cache the eattrs; use only with ACCESS_RTE
  199:  *	m4_dnl	  f_rta_cow(fs)	-> function to call before any change to route should be done
  200:  *
  201:  *	m4_dnl	If you are stymied, see FI_CALL or FI_CONSTANT or just search for
  202:  *	m4_dnl	the mentioned macros in this file to see what is happening there in wild.
  203:  */
  204: 
  205: /* Binary operators */
  206:   INST(FI_ADD, 2, 1) {
  207:     ARG(1,T_INT);
  208:     ARG(2,T_INT);
  209:     RESULT(T_INT, i, v1.val.i + v2.val.i);
  210:   }
  211:   INST(FI_SUBTRACT, 2, 1) {
  212:     ARG(1,T_INT);
  213:     ARG(2,T_INT);
  214:     RESULT(T_INT, i, v1.val.i - v2.val.i);
  215:   }
  216:   INST(FI_MULTIPLY, 2, 1) {
  217:     ARG(1,T_INT);
  218:     ARG(2,T_INT);
  219:     RESULT(T_INT, i, v1.val.i * v2.val.i);
  220:   }
  221:   INST(FI_DIVIDE, 2, 1) {
  222:     ARG(1,T_INT);
  223:     ARG(2,T_INT);
  224:     if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
  225:     RESULT(T_INT, i, v1.val.i / v2.val.i);
  226:   }
  227:   INST(FI_AND, 1, 1) {
  228:     ARG(1,T_BOOL);
  229:     if (v1.val.i)
  230:       LINE(2,0);
  231:     else
  232:       RESULT_VAL(v1);
  233:   }
  234:   INST(FI_OR, 1, 1) {
  235:     ARG(1,T_BOOL);
  236:     if (!v1.val.i)
  237:       LINE(2,0);
  238:     else
  239:       RESULT_VAL(v1);
  240:   }
  241: 
  242:   INST(FI_PAIR_CONSTRUCT, 2, 1) {
  243:     ARG(1,T_INT);
  244:     ARG(2,T_INT);
  245:     uint u1 = v1.val.i;
  246:     uint u2 = v2.val.i;
  247:     if ((u1 > 0xFFFF) || (u2 > 0xFFFF))
  248:       runtime( "Can't operate with value out of bounds in pair constructor" );
  249:     RESULT(T_PAIR, i, (u1 << 16) | u2);
  250:   }
  251: 
  252:   INST(FI_EC_CONSTRUCT, 2, 1) {
  253:     ARG_ANY(1);
  254:     ARG(2, T_INT);
  255: 
  256:     FID_MEMBER(enum ec_subtype, ecs, f1->ecs != f2->ecs, "ec subtype %s", ec_subtype_str(item->ecs));
  257: 
  258:     int check, ipv4_used;
  259:     u32 key, val;
  260: 
  261:     if (v1.type == T_INT) {
  262:       ipv4_used = 0; key = v1.val.i;
  263:     }
  264:     else if (v1.type == T_QUAD) {
  265:       ipv4_used = 1; key = v1.val.i;
  266:     }
  267:     /* IP->Quad implicit conversion */
  268:     else if (val_is_ip4(&v1)) {
  269:       ipv4_used = 1; key = ipa_to_u32(v1.val.ip);
  270:     }
  271:     else
  272:       runtime("Argument 1 of EC constructor must be integer or IPv4 address, got 0x%02x", v1.type);
  273: 
  274:     val = v2.val.i;
  275: 
  276:     if (ecs == EC_GENERIC) {
  277:       check = 0; RESULT(T_EC, ec, ec_generic(key, val));
  278:     }
  279:     else if (ipv4_used) {
  280:       check = 1; RESULT(T_EC, ec, ec_ip4(ecs, key, val));
  281:     }
  282:     else if (key < 0x10000) {
  283:       check = 0; RESULT(T_EC, ec, ec_as2(ecs, key, val));
  284:     }
  285:     else {
  286:       check = 1; RESULT(T_EC, ec, ec_as4(ecs, key, val));
  287:     }
  288: 
  289:     if (check && (val > 0xFFFF))
  290:       runtime("Value %u > %u out of bounds in EC constructor", val, 0xFFFF);
  291:   }
  292: 
  293:   INST(FI_LC_CONSTRUCT, 3, 1) {
  294:     ARG(1, T_INT);
  295:     ARG(2, T_INT);
  296:     ARG(3, T_INT);
  297:     RESULT(T_LC, lc, [[(lcomm) { v1.val.i, v2.val.i, v3.val.i }]]);
  298:   }
  299: 
  300:   INST(FI_PATHMASK_CONSTRUCT, 0, 1) {
  301:     VARARG;
  302: 
  303:     struct f_path_mask *pm = falloc(sizeof(struct f_path_mask) + whati->varcount * sizeof(struct f_path_mask_item));
  304:     pm->len = whati->varcount;
  305: 
  306:     for (uint i=0; i<whati->varcount; i++) {
  307:       switch (vv(i).type) {
  308: 	case T_PATH_MASK_ITEM:
  309: 	  pm->item[i] = vv(i).val.pmi;
  310: 	  break;
  311: 
  312: 	case T_INT:
  313: 	  pm->item[i] = (struct f_path_mask_item) {
  314: 	    .asn = vv(i).val.i,
  315: 	    .kind = PM_ASN,
  316: 	  };
  317: 	  break;
  318: 
  319: 	case T_SET:
  320: 	  if (vv(i).val.t->from.type != T_INT)
  321: 	    runtime("Only integer sets allowed in path mask");
  322: 
  323: 	  pm->item[i] = (struct f_path_mask_item) {
  324: 	    .set = vv(i).val.t,
  325: 	    .kind = PM_ASN_SET,
  326: 	  };
  327: 	  break;
  328: 
  329: 	default:
  330: 	  runtime( "Error resolving path mask template: value not an integer" );
  331:       }
  332:     }
  333: 
  334:     RESULT(T_PATH_MASK, path_mask, pm);
  335:   }
  336: 
  337: /* Relational operators */
  338: 
  339:   INST(FI_NEQ, 2, 1) {
  340:     ARG_ANY(1);
  341:     ARG_ANY(2);
  342:     RESULT(T_BOOL, i, !val_same(&v1, &v2));
  343:   }
  344: 
  345:   INST(FI_EQ, 2, 1) {
  346:     ARG_ANY(1);
  347:     ARG_ANY(2);
  348:     RESULT(T_BOOL, i, val_same(&v1, &v2));
  349:   }
  350: 
  351:   INST(FI_LT, 2, 1) {
  352:     ARG_ANY(1);
  353:     ARG_ANY(2);
  354:     int i = val_compare(&v1, &v2);
  355:     if (i == F_CMP_ERROR)
  356:       runtime( "Can't compare values of incompatible types" );
  357:     RESULT(T_BOOL, i, (i == -1));
  358:   }
  359: 
  360:   INST(FI_LTE, 2, 1) {
  361:     ARG_ANY(1);
  362:     ARG_ANY(2);
  363:     int i = val_compare(&v1, &v2);
  364:     if (i == F_CMP_ERROR)
  365:       runtime( "Can't compare values of incompatible types" );
  366:     RESULT(T_BOOL, i, (i != 1));
  367:   }
  368: 
  369:   INST(FI_NOT, 1, 1) {
  370:     ARG(1,T_BOOL);
  371:     RESULT(T_BOOL, i, !v1.val.i);
  372:   }
  373: 
  374:   INST(FI_MATCH, 2, 1) {
  375:     ARG_ANY(1);
  376:     ARG_ANY(2);
  377:     int i = val_in_range(&v1, &v2);
  378:     if (i == F_CMP_ERROR)
  379:       runtime( "~ applied on unknown type pair" );
  380:     RESULT(T_BOOL, i, !!i);
  381:   }
  382: 
  383:   INST(FI_NOT_MATCH, 2, 1) {
  384:     ARG_ANY(1);
  385:     ARG_ANY(2);
  386:     int i = val_in_range(&v1, &v2);
  387:     if (i == F_CMP_ERROR)
  388:       runtime( "!~ applied on unknown type pair" );
  389:     RESULT(T_BOOL, i, !i);
  390:   }
  391: 
  392:   INST(FI_DEFINED, 1, 1) {
  393:     ARG_ANY(1);
  394:     RESULT(T_BOOL, i, (v1.type != T_VOID) && !undef_value(v1));
  395:   }
  396: 
  397:   INST(FI_TYPE, 1, 1) {
  398:     ARG_ANY(1); /* There may be more types supporting this operation */
  399:     switch (v1.type)
  400:     {
  401:       case T_NET:
  402: 	RESULT(T_ENUM_NETTYPE, i, v1.val.net->type);
  403: 	break;
  404:       default:
  405: 	runtime( "Can't determine type of this item" );
  406:     }
  407:   }
  408: 
  409:   INST(FI_IS_V4, 1, 1) {
  410:     ARG(1, T_IP);
  411:     RESULT(T_BOOL, i, ipa_is_ip4(v1.val.ip));
  412:   }
  413: 
  414:   /* Set to indirect value prepared in v1 */
  415:   INST(FI_VAR_SET, 1, 0) {
  416:     NEVER_CONSTANT;
  417:     ARG_ANY(1);
  418:     SYMBOL;
  419: 
  420:     if ((sym->class != (SYM_VARIABLE | v1.type)) && (v1.type != T_VOID))
  421:     {
  422:       /* IP->Quad implicit conversion */
  423:       if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(&v1))
  424: 	v1 = (struct f_val) {
  425: 	  .type = T_QUAD,
  426: 	  .val.i = ipa_to_u32(v1.val.ip),
  427: 	};
  428:       else
  429: 	runtime( "Assigning to variable of incompatible type" );
  430:     }
  431: 
  432:     fstk->vstk[curline.vbase + sym->offset] = v1;
  433:   }
  434: 
  435:   INST(FI_VAR_GET, 0, 1) {
  436:     SYMBOL;
  437:     NEVER_CONSTANT;
  438:     RESULT_VAL(fstk->vstk[curline.vbase + sym->offset]);
  439:   }
  440: 
  441:   INST(FI_CONSTANT, 0, 1) {
  442:     FID_MEMBER(
  443:       struct f_val,
  444:       val,
  445:       [[ !val_same(&(f1->val), &(f2->val)) ]],
  446:       "value %s",
  447:       val_dump(&(item->val))
  448:     );
  449: 
  450:     RESULT_VAL(val);
  451:   }
  452: 
  453:   INST(FI_CONDITION, 1, 0) {
  454:     ARG(1, T_BOOL);
  455:     if (v1.val.i)
  456:       LINE(2,0);
  457:     else
  458:       LINE(3,1);
  459:   }
  460: 
  461:   INST(FI_PRINT, 0, 0) {
  462:     NEVER_CONSTANT;
  463:     VARARG;
  464: 
  465:     if (whati->varcount && !(fs->flags & FF_SILENT))
  466:       for (uint i=0; i<whati->varcount; i++)
  467: 	val_format(&(vv(i)), &fs->buf);
  468:   }
  469: 
  470:   INST(FI_FLUSH, 0, 0) {
  471:     NEVER_CONSTANT;
  472:     if (!(fs->flags & FF_SILENT))
  473:       /* After log_commit, the buffer is reset */
  474:       log_commit(*L_INFO, &fs->buf);
  475:   }
  476: 
  477:   INST(FI_DIE, 0, 0) {
  478:     NEVER_CONSTANT;
  479:     FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, "%s", filter_return_str(item->fret));
  480: 
  481:     switch (whati->fret) {
  482:     case F_QUITBIRD:
  483:       die( "Filter asked me to die" );
  484:     case F_ACCEPT:	/* Should take care about turning ACCEPT into MODIFY */
  485:     case F_ERROR:
  486:     case F_REJECT:	/* Maybe print complete route along with reason to reject route? */
  487:       return fret;	/* We have to return now, no more processing. */
  488:     default:
  489:       bug( "unknown return type: Can't happen");
  490:     }
  491:   }
  492: 
  493:   INST(FI_RTA_GET, 0, 1) {
  494:     {
  495:       STATIC_ATTR;
  496:       ACCESS_RTE;
  497:       struct rta *rta = (*fs->rte)->attrs;
  498: 
  499:       switch (sa.sa_code)
  500:       {
  501:       case SA_FROM:	RESULT(sa.f_type, ip, rta->from); break;
  502:       case SA_GW:	RESULT(sa.f_type, ip, rta->nh.gw); break;
  503:       case SA_NET:	RESULT(sa.f_type, net, (*fs->rte)->net->n.addr); break;
  504:       case SA_PROTO:	RESULT(sa.f_type, s, rta->src->proto->name); break;
  505:       case SA_SOURCE:	RESULT(sa.f_type, i, rta->source); break;
  506:       case SA_SCOPE:	RESULT(sa.f_type, i, rta->scope); break;
  507:       case SA_DEST:	RESULT(sa.f_type, i, rta->dest); break;
  508:       case SA_IFNAME:	RESULT(sa.f_type, s, rta->nh.iface ? rta->nh.iface->name : ""); break;
  509:       case SA_IFINDEX:	RESULT(sa.f_type, i, rta->nh.iface ? rta->nh.iface->index : 0); break;
  510: 
  511:       default:
  512: 	bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
  513:       }
  514:     }
  515:   }
  516: 
  517:   INST(FI_RTA_SET, 1, 0) {
  518:     ACCESS_RTE;
  519:     ARG_ANY(1);
  520:     STATIC_ATTR;
  521:     if (sa.f_type != v1.type)
  522:       runtime( "Attempt to set static attribute to incompatible type" );
  523: 
  524:     f_rta_cow(fs);
  525:     {
  526:       struct rta *rta = (*fs->rte)->attrs;
  527: 
  528:       switch (sa.sa_code)
  529:       {
  530:       case SA_FROM:
  531: 	rta->from = v1.val.ip;
  532: 	break;
  533: 
  534:       case SA_GW:
  535: 	{
  536: 	  ip_addr ip = v1.val.ip;
  537: 	  neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0);
  538: 	  if (!n || (n->scope == SCOPE_HOST))
  539: 	    runtime( "Invalid gw address" );
  540: 
  541: 	  rta->dest = RTD_UNICAST;
  542: 	  rta->nh.gw = ip;
  543: 	  rta->nh.iface = n->iface;
  544: 	  rta->nh.next = NULL;
  545: 	  rta->hostentry = NULL;
  546: 	}
  547: 	break;
  548: 
  549:       case SA_SCOPE:
  550: 	rta->scope = v1.val.i;
  551: 	break;
  552: 
  553:       case SA_DEST:
  554: 	{
  555: 	  int i = v1.val.i;
  556: 	  if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
  557: 	    runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
  558: 
  559: 	  rta->dest = i;
  560: 	  rta->nh.gw = IPA_NONE;
  561: 	  rta->nh.iface = NULL;
  562: 	  rta->nh.next = NULL;
  563: 	  rta->hostentry = NULL;
  564: 	}
  565: 	break;
  566: 
  567:       case SA_IFNAME:
  568: 	{
  569: 	  struct iface *ifa = if_find_by_name(v1.val.s);
  570: 	  if (!ifa)
  571: 	    runtime( "Invalid iface name" );
  572: 
  573: 	  rta->dest = RTD_UNICAST;
  574: 	  rta->nh.gw = IPA_NONE;
  575: 	  rta->nh.iface = ifa;
  576: 	  rta->nh.next = NULL;
  577: 	  rta->hostentry = NULL;
  578: 	}
  579: 	break;
  580: 
  581:       default:
  582: 	bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
  583:       }
  584:     }
  585:   }
  586: 
  587:   INST(FI_EA_GET, 0, 1) {	/* Access to extended attributes */
  588:     DYNAMIC_ATTR;
  589:     ACCESS_RTE;
  590:     ACCESS_EATTRS;
  591:     {
  592:       eattr *e = ea_find(*fs->eattrs, da.ea_code);
  593: 
  594:       if (!e) {
  595: 	/* A special case: undefined as_path looks like empty as_path */
  596: 	if (da.type == EAF_TYPE_AS_PATH) {
  597: 	  RESULT(T_PATH, ad, &null_adata);
  598: 	  break;
  599: 	}
  600: 
  601: 	/* The same special case for int_set */
  602: 	if (da.type == EAF_TYPE_INT_SET) {
  603: 	  RESULT(T_CLIST, ad, &null_adata);
  604: 	  break;
  605: 	}
  606: 
  607: 	/* The same special case for ec_set */
  608: 	if (da.type == EAF_TYPE_EC_SET) {
  609: 	  RESULT(T_ECLIST, ad, &null_adata);
  610: 	  break;
  611: 	}
  612: 
  613: 	/* The same special case for lc_set */
  614: 	if (da.type == EAF_TYPE_LC_SET) {
  615: 	  RESULT(T_LCLIST, ad, &null_adata);
  616: 	  break;
  617: 	}
  618: 
  619: 	/* Undefined value */
  620: 	RESULT_VOID;
  621: 	break;
  622:       }
  623: 
  624:       switch (e->type & EAF_TYPE_MASK) {
  625:       case EAF_TYPE_INT:
  626: 	RESULT(da.f_type, i, e->u.data);
  627: 	break;
  628:       case EAF_TYPE_ROUTER_ID:
  629: 	RESULT(T_QUAD, i, e->u.data);
  630: 	break;
  631:       case EAF_TYPE_OPAQUE:
  632: 	RESULT(T_ENUM_EMPTY, i, 0);
  633: 	break;
  634:       case EAF_TYPE_IP_ADDRESS:
  635: 	RESULT(T_IP, ip, *((ip_addr *) e->u.ptr->data));
  636: 	break;
  637:       case EAF_TYPE_AS_PATH:
  638: 	RESULT(T_PATH, ad, e->u.ptr);
  639: 	break;
  640:       case EAF_TYPE_BITFIELD:
  641: 	RESULT(T_BOOL, i, !!(e->u.data & (1u << da.bit)));
  642: 	break;
  643:       case EAF_TYPE_INT_SET:
  644: 	RESULT(T_CLIST, ad, e->u.ptr);
  645: 	break;
  646:       case EAF_TYPE_EC_SET:
  647: 	RESULT(T_ECLIST, ad, e->u.ptr);
  648: 	break;
  649:       case EAF_TYPE_LC_SET:
  650: 	RESULT(T_LCLIST, ad, e->u.ptr);
  651: 	break;
  652:       case EAF_TYPE_UNDEF:
  653: 	RESULT_VOID;
  654: 	break;
  655:       default:
  656: 	bug("Unknown dynamic attribute type");
  657:       }
  658:     }
  659:   }
  660: 
  661:   INST(FI_EA_SET, 1, 0) {
  662:     ACCESS_RTE;
  663:     ACCESS_EATTRS;
  664:     ARG_ANY(1);
  665:     DYNAMIC_ATTR;
  666:     {
  667:       struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
  668: 
  669:       l->next = NULL;
  670:       l->flags = EALF_SORTED;
  671:       l->count = 1;
  672:       l->attrs[0].id = da.ea_code;
  673:       l->attrs[0].flags = 0;
  674:       l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH;
  675: 
  676:       switch (da.type) {
  677:       case EAF_TYPE_INT:
  678: 	if (v1.type != da.f_type)
  679: 	  runtime( "Setting int attribute to non-int value" );
  680: 	l->attrs[0].u.data = v1.val.i;
  681: 	break;
  682: 
  683:       case EAF_TYPE_ROUTER_ID:
  684: 	/* IP->Quad implicit conversion */
  685: 	if (val_is_ip4(&v1)) {
  686: 	  l->attrs[0].u.data = ipa_to_u32(v1.val.ip);
  687: 	  break;
  688: 	}
  689: 	/* T_INT for backward compatibility */
  690: 	if ((v1.type != T_QUAD) && (v1.type != T_INT))
  691: 	  runtime( "Setting quad attribute to non-quad value" );
  692: 	l->attrs[0].u.data = v1.val.i;
  693: 	break;
  694: 
  695:       case EAF_TYPE_OPAQUE:
  696: 	runtime( "Setting opaque attribute is not allowed" );
  697: 	break;
  698: 
  699:       case EAF_TYPE_IP_ADDRESS:
  700: 	if (v1.type != T_IP)
  701: 	  runtime( "Setting ip attribute to non-ip value" );
  702: 	int len = sizeof(ip_addr);
  703: 	struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len);
  704: 	ad->length = len;
  705: 	(* (ip_addr *) ad->data) = v1.val.ip;
  706: 	l->attrs[0].u.ptr = ad;
  707: 	break;
  708: 
  709:       case EAF_TYPE_AS_PATH:
  710: 	if (v1.type != T_PATH)
  711: 	  runtime( "Setting path attribute to non-path value" );
  712: 	l->attrs[0].u.ptr = v1.val.ad;
  713: 	break;
  714: 
  715:       case EAF_TYPE_BITFIELD:
  716: 	if (v1.type != T_BOOL)
  717: 	  runtime( "Setting bit in bitfield attribute to non-bool value" );
  718: 	{
  719: 	  /* First, we have to find the old value */
  720: 	  eattr *e = ea_find(*fs->eattrs, da.ea_code);
  721: 	  u32 data = e ? e->u.data : 0;
  722: 
  723: 	  if (v1.val.i)
  724: 	    l->attrs[0].u.data = data | (1u << da.bit);
  725: 	  else
  726: 	    l->attrs[0].u.data = data & ~(1u << da.bit);
  727: 	}
  728: 	break;
  729: 
  730:       case EAF_TYPE_INT_SET:
  731: 	if (v1.type != T_CLIST)
  732: 	  runtime( "Setting clist attribute to non-clist value" );
  733: 	l->attrs[0].u.ptr = v1.val.ad;
  734: 	break;
  735: 
  736:       case EAF_TYPE_EC_SET:
  737: 	if (v1.type != T_ECLIST)
  738: 	  runtime( "Setting eclist attribute to non-eclist value" );
  739: 	l->attrs[0].u.ptr = v1.val.ad;
  740: 	break;
  741: 
  742:       case EAF_TYPE_LC_SET:
  743: 	if (v1.type != T_LCLIST)
  744: 	  runtime( "Setting lclist attribute to non-lclist value" );
  745: 	l->attrs[0].u.ptr = v1.val.ad;
  746: 	break;
  747: 
  748:       default:
  749: 	bug("Unknown dynamic attribute type");
  750:       }
  751: 
  752:       f_rta_cow(fs);
  753:       l->next = *fs->eattrs;
  754:       *fs->eattrs = l;
  755:     }
  756:   }
  757: 
  758:   INST(FI_EA_UNSET, 0, 0) {
  759:     DYNAMIC_ATTR;
  760:     ACCESS_RTE;
  761:     ACCESS_EATTRS;
  762: 
  763:     {
  764:       struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
  765: 
  766:       l->next = NULL;
  767:       l->flags = EALF_SORTED;
  768:       l->count = 1;
  769:       l->attrs[0].id = da.ea_code;
  770:       l->attrs[0].flags = 0;
  771:       l->attrs[0].type = EAF_TYPE_UNDEF | EAF_ORIGINATED | EAF_FRESH;
  772:       l->attrs[0].u.data = 0;
  773: 
  774:       f_rta_cow(fs);
  775:       l->next = *fs->eattrs;
  776:       *fs->eattrs = l;
  777:     }
  778:   }
  779: 
  780:   INST(FI_PREF_GET, 0, 1) {
  781:     ACCESS_RTE;
  782:     RESULT(T_INT, i, (*fs->rte)->pref);
  783:   }
  784: 
  785:   INST(FI_PREF_SET, 1, 0) {
  786:     ACCESS_RTE;
  787:     ARG(1,T_INT);
  788:     if (v1.val.i > 0xFFFF)
  789:       runtime( "Setting preference value out of bounds" );
  790:     f_rte_cow(fs);
  791:     (*fs->rte)->pref = v1.val.i;
  792:   }
  793: 
  794:   INST(FI_LENGTH, 1, 1) {	/* Get length of */
  795:     ARG_ANY(1);
  796:     switch(v1.type) {
  797:     case T_NET:    RESULT(T_INT, i, net_pxlen(v1.val.net)); break;
  798:     case T_PATH:   RESULT(T_INT, i, as_path_getlen(v1.val.ad)); break;
  799:     case T_CLIST:  RESULT(T_INT, i, int_set_get_size(v1.val.ad)); break;
  800:     case T_ECLIST: RESULT(T_INT, i, ec_set_get_size(v1.val.ad)); break;
  801:     case T_LCLIST: RESULT(T_INT, i, lc_set_get_size(v1.val.ad)); break;
  802:     default: runtime( "Prefix, path, clist or eclist expected" );
  803:     }
  804:   }
  805: 
  806:   INST(FI_SADR_SRC, 1, 1) { 	/* Get SADR src prefix */
  807:     ARG(1, T_NET);
  808:     if (!net_is_sadr(v1.val.net))
  809:       runtime( "SADR expected" );
  810: 
  811:     net_addr_ip6_sadr *net = (void *) v1.val.net;
  812:     net_addr *src = falloc(sizeof(net_addr_ip6));
  813:     net_fill_ip6(src, net->src_prefix, net->src_pxlen);
  814: 
  815:     RESULT(T_NET, net, src);
  816:   }
  817: 
  818:   INST(FI_ROA_MAXLEN, 1, 1) { 	/* Get ROA max prefix length */
  819:     ARG(1, T_NET);
  820:     if (!net_is_roa(v1.val.net))
  821:       runtime( "ROA expected" );
  822: 
  823:     RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
  824:       ((net_addr_roa4 *) v1.val.net)->max_pxlen :
  825:       ((net_addr_roa6 *) v1.val.net)->max_pxlen);
  826:   }
  827: 
  828:   INST(FI_ROA_ASN, 1, 1) { 	/* Get ROA ASN */
  829:     ARG(1, T_NET);
  830:     if (!net_is_roa(v1.val.net))
  831:       runtime( "ROA expected" );
  832: 
  833:     RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
  834:       ((net_addr_roa4 *) v1.val.net)->asn :
  835:       ((net_addr_roa6 *) v1.val.net)->asn);
  836:   }
  837: 
  838:   INST(FI_IP, 1, 1) {	/* Convert prefix to ... */
  839:     ARG(1, T_NET);
  840:     RESULT(T_IP, ip, net_prefix(v1.val.net));
  841:   }
  842: 
  843:   INST(FI_ROUTE_DISTINGUISHER, 1, 1) {
  844:     ARG(1, T_NET);
  845:     if (!net_is_vpn(v1.val.net))
  846:       runtime( "VPN address expected" );
  847:     RESULT(T_RD, ec, net_rd(v1.val.net));
  848:   }
  849: 
  850:   INST(FI_AS_PATH_FIRST, 1, 1) {	/* Get first ASN from AS PATH */
  851:     ARG(1, T_PATH);
  852:     int as = 0;
  853:     as_path_get_first(v1.val.ad, &as);
  854:     RESULT(T_INT, i, as);
  855:   }
  856: 
  857:   INST(FI_AS_PATH_LAST, 1, 1) {		/* Get last ASN from AS PATH */
  858:     ARG(1, T_PATH);
  859:     int as = 0;
  860:     as_path_get_last(v1.val.ad, &as);
  861:     RESULT(T_INT, i, as);
  862:   }
  863: 
  864:   INST(FI_AS_PATH_LAST_NAG, 1, 1) {	/* Get last ASN from non-aggregated part of AS PATH */
  865:     ARG(1, T_PATH);
  866:     RESULT(T_INT, i, as_path_get_last_nonaggregated(v1.val.ad));
  867:   }
  868: 
  869:   INST(FI_RETURN, 1, 1) {
  870:     NEVER_CONSTANT;
  871:     /* Acquire the return value */
  872:     ARG_ANY(1);
  873:     uint retpos = fstk->vcnt;
  874: 
  875:     /* Drop every sub-block including ourselves */
  876:     while ((fstk->ecnt-- > 0) && !(fstk->estk[fstk->ecnt].emask & FE_RETURN))
  877:       ;
  878: 
  879:     /* Now we are at the caller frame; if no such, try to convert to accept/reject. */
  880:     if (!fstk->ecnt)
  881:       if (fstk->vstk[retpos].type == T_BOOL)
  882: 	if (fstk->vstk[retpos].val.i)
  883: 	  return F_ACCEPT;
  884: 	else
  885: 	  return F_REJECT;
  886:       else
  887: 	runtime("Can't return non-bool from non-function");
  888: 
  889:     /* Set the value stack position, overwriting the former implicit void */
  890:     fstk->vcnt = fstk->estk[fstk->ecnt].ventry - 1;
  891: 
  892:     /* Copy the return value */
  893:     RESULT_VAL(fstk->vstk[retpos]);
  894:   }
  895: 
  896:   INST(FI_CALL, 0, 1) {
  897:     NEVER_CONSTANT;
  898:     SYMBOL;
  899: 
  900:     FID_SAME_BODY()
  901:       if (!(f2->sym->flags & SYM_FLAG_SAME))
  902: 	return 0;
  903:     FID_INTERPRET_BODY()
  904: 
  905:     /* Push the body on stack */
  906:     LINEX(sym->function);
  907:     curline.emask |= FE_RETURN;
  908: 
  909:     /* Before this instruction was called, there was the T_VOID
  910:      * automatic return value pushed on value stack and also
  911:      * sym->function->args function arguments. Setting the
  912:      * vbase to point to first argument. */
  913:     ASSERT(curline.ventry >= sym->function->args);
  914:     curline.ventry -= sym->function->args;
  915:     curline.vbase = curline.ventry;
  916: 
  917:     /* Storage for local variables */
  918:     memset(&(fstk->vstk[fstk->vcnt]), 0, sizeof(struct f_val) * sym->function->vars);
  919:     fstk->vcnt += sym->function->vars;
  920:   }
  921: 
  922:   INST(FI_DROP_RESULT, 1, 0) {
  923:     NEVER_CONSTANT;
  924:     ARG_ANY(1);
  925:   }
  926: 
  927:   INST(FI_SWITCH, 1, 0) {
  928:     ARG_ANY(1);
  929: 
  930:     FID_MEMBER(struct f_tree *, tree, [[!same_tree(f1->tree, f2->tree)]], "tree %p", item->tree);
  931: 
  932:     const struct f_tree *t = find_tree(tree, &v1);
  933:     if (!t) {
  934:       v1.type = T_VOID;
  935:       t = find_tree(tree, &v1);
  936:       if (!t) {
  937: 	debug( "No else statement?\n");
  938: 	FID_HIC(,break,return NULL);
  939:       }
  940:     }
  941:     /* It is actually possible to have t->data NULL */
  942: 
  943:     LINEX(t->data);
  944:   }
  945: 
  946:   INST(FI_IP_MASK, 2, 1) { /* IP.MASK(val) */
  947:     ARG(1, T_IP);
  948:     ARG(2, T_INT);
  949:     RESULT(T_IP, ip, [[ ipa_is_ip4(v1.val.ip) ?
  950:       ipa_from_ip4(ip4_and(ipa_to_ip4(v1.val.ip), ip4_mkmask(v2.val.i))) :
  951:       ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i))) ]]);
  952:   }
  953: 
  954:   INST(FI_PATH_PREPEND, 2, 1) {	/* Path prepend */
  955:     ARG(1, T_PATH);
  956:     ARG(2, T_INT);
  957:     RESULT(T_PATH, ad, [[ as_path_prepend(fpool, v1.val.ad, v2.val.i) ]]);
  958:   }
  959: 
  960:   INST(FI_CLIST_ADD, 2, 1) {	/* (Extended) Community list add */
  961:     ARG_ANY(1);
  962:     ARG_ANY(2);
  963:     if (v1.type == T_PATH)
  964:       runtime("Can't add to path");
  965: 
  966:     else if (v1.type == T_CLIST)
  967:     {
  968:       /* Community (or cluster) list */
  969:       struct f_val dummy;
  970: 
  971:       if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
  972: 	RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, v2.val.i) ]]);
  973:       /* IP->Quad implicit conversion */
  974:       else if (val_is_ip4(&v2))
  975: 	RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
  976:       else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
  977: 	runtime("Can't add set");
  978:       else if (v2.type == T_CLIST)
  979: 	RESULT(T_CLIST, ad, [[ int_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
  980:       else
  981: 	runtime("Can't add non-pair");
  982:     }
  983: 
  984:     else if (v1.type == T_ECLIST)
  985:     {
  986:       /* v2.val is either EC or EC-set */
  987:       if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
  988: 	runtime("Can't add set");
  989:       else if (v2.type == T_ECLIST)
  990: 	RESULT(T_ECLIST, ad, [[ ec_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
  991:       else if (v2.type != T_EC)
  992: 	runtime("Can't add non-ec");
  993:       else
  994: 	RESULT(T_ECLIST, ad, [[ ec_set_add(fpool, v1.val.ad, v2.val.ec) ]]);
  995:     }
  996: 
  997:     else if (v1.type == T_LCLIST)
  998:     {
  999:       /* v2.val is either LC or LC-set */
 1000:       if ((v2.type == T_SET) && lclist_set_type(v2.val.t))
 1001: 	runtime("Can't add set");
 1002:       else if (v2.type == T_LCLIST)
 1003: 	RESULT(T_LCLIST, ad, [[ lc_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
 1004:       else if (v2.type != T_LC)
 1005: 	runtime("Can't add non-lc");
 1006:       else
 1007: 	RESULT(T_LCLIST, ad, [[ lc_set_add(fpool, v1.val.ad, v2.val.lc) ]]);
 1008: 
 1009:     }
 1010: 
 1011:     else
 1012:       runtime("Can't add to non-[e|l]clist");
 1013:   }
 1014: 
 1015:   INST(FI_CLIST_DEL, 2, 1) {	/* (Extended) Community list add or delete */
 1016:     ARG_ANY(1);
 1017:     ARG_ANY(2);
 1018:     if (v1.type == T_PATH)
 1019:     {
 1020:       const struct f_tree *set = NULL;
 1021:       u32 key = 0;
 1022: 
 1023:       if (v2.type == T_INT)
 1024: 	key = v2.val.i;
 1025:       else if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT))
 1026: 	set = v2.val.t;
 1027:       else
 1028: 	runtime("Can't delete non-integer (set)");
 1029: 
 1030:       RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, set, key, 0) ]]);
 1031:     }
 1032: 
 1033:     else if (v1.type == T_CLIST)
 1034:     {
 1035:       /* Community (or cluster) list */
 1036:       struct f_val dummy;
 1037: 
 1038:       if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
 1039: 	RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, v2.val.i) ]]);
 1040:       /* IP->Quad implicit conversion */
 1041:       else if (val_is_ip4(&v2))
 1042: 	RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
 1043:       else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST))
 1044: 	RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 0) ]]);
 1045:       else
 1046: 	runtime("Can't delete non-pair");
 1047:     }
 1048: 
 1049:     else if (v1.type == T_ECLIST)
 1050:     {
 1051:       /* v2.val is either EC or EC-set */
 1052:       if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST))
 1053: 	RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
 1054:       else if (v2.type != T_EC)
 1055: 	runtime("Can't delete non-ec");
 1056:       else
 1057: 	RESULT(T_ECLIST, ad, [[ ec_set_del(fpool, v1.val.ad, v2.val.ec) ]]);
 1058:     }
 1059: 
 1060:     else if (v1.type == T_LCLIST)
 1061:     {
 1062:       /* v2.val is either LC or LC-set */
 1063:       if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST))
 1064: 	RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
 1065:       else if (v2.type != T_LC)
 1066: 	runtime("Can't delete non-lc");
 1067:       else
 1068: 	RESULT(T_LCLIST, ad, [[ lc_set_del(fpool, v1.val.ad, v2.val.lc) ]]);
 1069:     }
 1070: 
 1071:     else
 1072:       runtime("Can't delete in non-[e|l]clist");
 1073:   }
 1074: 
 1075:   INST(FI_CLIST_FILTER, 2, 1) {	/* (Extended) Community list add or delete */
 1076:     ARG_ANY(1);
 1077:     ARG_ANY(2);
 1078:     if (v1.type == T_PATH)
 1079:     {
 1080:       u32 key = 0;
 1081: 
 1082:       if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT))
 1083: 	RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, v2.val.t, key, 1) ]]);
 1084:       else
 1085: 	runtime("Can't filter integer");
 1086:     }
 1087: 
 1088:     else if (v1.type == T_CLIST)
 1089:     {
 1090:       /* Community (or cluster) list */
 1091:       struct f_val dummy;
 1092: 
 1093:       if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST))
 1094: 	RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]);
 1095:       else
 1096: 	runtime("Can't filter pair");
 1097:     }
 1098: 
 1099:     else if (v1.type == T_ECLIST)
 1100:     {
 1101:       /* v2.val is either EC or EC-set */
 1102:       if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST))
 1103: 	RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
 1104:       else
 1105: 	runtime("Can't filter ec");
 1106:     }
 1107: 
 1108:     else if (v1.type == T_LCLIST)
 1109:     {
 1110:       /* v2.val is either LC or LC-set */
 1111:       if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST))
 1112: 	RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
 1113:       else
 1114: 	runtime("Can't filter lc");
 1115:     }
 1116: 
 1117:     else
 1118:       runtime("Can't filter non-[e|l]clist");
 1119:   }
 1120: 
 1121:   INST(FI_ROA_CHECK_IMPLICIT, 0, 1) {	/* ROA Check */
 1122:     NEVER_CONSTANT;
 1123:     RTC(1);
 1124:     struct rtable *table = rtc->table;
 1125:     ACCESS_RTE;
 1126:     ACCESS_EATTRS;
 1127:     const net_addr *net = (*fs->rte)->net->n.addr;
 1128: 
 1129:     /* We ignore temporary attributes, probably not a problem here */
 1130:     /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
 1131:     eattr *e = ea_find(*fs->eattrs, EA_CODE(PROTOCOL_BGP, 0x02));
 1132: 
 1133:     if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH))
 1134:       runtime("Missing AS_PATH attribute");
 1135: 
 1136:     u32 as = 0;
 1137:     as_path_get_last(e->u.ptr, &as);
 1138: 
 1139:     if (!table)
 1140:       runtime("Missing ROA table");
 1141: 
 1142:     if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
 1143:       runtime("Table type must be either ROA4 or ROA6");
 1144: 
 1145:     if (table->addr_type != (net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
 1146:       RESULT(T_ENUM_ROA, i, ROA_UNKNOWN); /* Prefix and table type mismatch */
 1147:     else
 1148:       RESULT(T_ENUM_ROA, i, [[ net_roa_check(table, net, as) ]]);
 1149:   }
 1150: 
 1151:   INST(FI_ROA_CHECK_EXPLICIT, 2, 1) {	/* ROA Check */
 1152:     NEVER_CONSTANT;
 1153:     ARG(1, T_NET);
 1154:     ARG(2, T_INT);
 1155:     RTC(3);
 1156:     struct rtable *table = rtc->table;
 1157: 
 1158:     u32 as = v2.val.i;
 1159: 
 1160:     if (!table)
 1161:       runtime("Missing ROA table");
 1162: 
 1163:     if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
 1164:       runtime("Table type must be either ROA4 or ROA6");
 1165: 
 1166:     if (table->addr_type != (v1.val.net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
 1167:       RESULT(T_ENUM_ROA, i, ROA_UNKNOWN); /* Prefix and table type mismatch */
 1168:     else
 1169:       RESULT(T_ENUM_ROA, i, [[ net_roa_check(table, v1.val.net, as) ]]);
 1170: 
 1171:   }
 1172: 
 1173:   INST(FI_FORMAT, 1, 0) {	/* Format */
 1174:     ARG_ANY(1);
 1175:     RESULT(T_STRING, s, val_format_str(fpool, &v1));
 1176:   }
 1177: 
 1178:   INST(FI_ASSERT, 1, 0) {	/* Birdtest Assert */
 1179:     NEVER_CONSTANT;
 1180:     ARG(1, T_BOOL);
 1181: 
 1182:     FID_MEMBER(char *, s, [[strcmp(f1->s, f2->s)]], "string %s", item->s);
 1183: 
 1184:     ASSERT(s);
 1185: 
 1186:     if (!bt_assert_hook)
 1187:       runtime("No bt_assert hook registered, can't assert");
 1188: 
 1189:     bt_assert_hook(v1.val.i, what);
 1190:   }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>