Commit e9c2dcf6 authored by Jan Maria Matejka's avatar Jan Maria Matejka
Browse files

Filter: Simple type checks converted to ARG() macro

parent a8c606d4
Loading
Loading
Loading
Loading
+92 −133
Original line number Diff line number Diff line
@@ -590,19 +590,16 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
    return res; \
  } while(0)

#define ARG(x,y) \
	x = interpret(what->y); \
	if (x.type & T_RETURN) \
		return x;

#define ONEARG ARG(v1, a1.p)
#define TWOARGS ARG(v1, a1.p) \
		ARG(v2, a2.p)
#define TWOARGS_C TWOARGS \
                  if (v1.type != v2.type) \
		    runtime( "Can't operate with values of incompatible types" );
#define THREEARGS TWOARGS \
		  ARG(v3, a3.p)
#define ARG_ANY(n) \
    v##n = interpret(what->a##n.p); \
    if (v##n.type & T_RETURN) \
      return v##n;

#define ARG(n,t) ARG_ANY(n) \
    if (v##n.type != t) \
      runtime("Argument %d of instruction %s must be of type %02x, got %02x", \
	  n, f_instruction_name(what->fi_code), t, v##n.type);

#define ACCESS_RTE \
  do { if (!f_rte) runtime("No route to access"); } while (0)

@@ -640,61 +637,44 @@ interpret(struct f_inst *what)
  switch(what->fi_code) {
/* Binary operators */
  case FI_ADD:
    TWOARGS_C;
    switch (res.type = v1.type) {
    case T_VOID: runtime( "Can't operate with values of type void" );
    case T_INT: res.val.i = v1.val.i + v2.val.i; break;
    default: runtime( "Usage of unknown type" );
    }
    ARG(1,T_INT);
    ARG(2,T_INT);
    res.type = T_INT;
    res.val.i = v1.val.i + v2.val.i;
    break;
  case FI_SUBTRACT:
    TWOARGS_C;
    switch (res.type = v1.type) {
    case T_VOID: runtime( "Can't operate with values of type void" );
    case T_INT: res.val.i = v1.val.i - v2.val.i; break;
    default: runtime( "Usage of unknown type" );
    }
    ARG(1,T_INT);
    ARG(2,T_INT);
    res.type = T_INT;
    res.val.i = v1.val.i - v2.val.i;
    break;
  case FI_MULTIPLY:
    TWOARGS_C;
    switch (res.type = v1.type) {
    case T_VOID: runtime( "Can't operate with values of type void" );
    case T_INT: res.val.i = v1.val.i * v2.val.i; break;
    default: runtime( "Usage of unknown type" );
    }
    ARG(1,T_INT);
    ARG(2,T_INT);
    res.type = T_INT;
    res.val.i = v1.val.i * v2.val.i;
    break;
  case FI_DIVIDE:
    TWOARGS_C;
    switch (res.type = v1.type) {
    case T_VOID: runtime( "Can't operate with values of type void" );
    case T_INT: if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
      	        res.val.i = v1.val.i / v2.val.i; break;
    default: runtime( "Usage of unknown type" );
    }
    ARG(1,T_INT);
    ARG(2,T_INT);
    res.type = T_INT;
    if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
    res.val.i = v1.val.i / v2.val.i;
    break;

  case FI_AND:
  case FI_OR:
    ARG(v1, a1.p);
    if (v1.type != T_BOOL)
      runtime( "Can't do boolean operation on non-booleans" );
    ARG(1,T_BOOL);
    if (v1.val.i == (what->fi_code == FI_OR)) {
      res.type = T_BOOL;
      res.val.i = v1.val.i;
      break;
    } else {
      ARG(2,T_BOOL);
      res = v2;
    }

    ARG(v2, a2.p);
    if (v2.type != T_BOOL)
      runtime( "Can't do boolean operation on non-booleans" );
    res.type = T_BOOL;
    res.val.i = v2.val.i;
    break;

  case FI_PAIR_CONSTRUCT:
    TWOARGS;
    if ((v1.type != T_INT) || (v2.type != T_INT))
      runtime( "Can't operate with value of non-integer type in pair constructor" );
    ARG(1,T_INT);
    ARG(2,T_INT);
    u1 = v1.val.i;
    u2 = v2.val.i;
    if ((u1 > 0xFFFF) || (u2 > 0xFFFF))
@@ -705,7 +685,8 @@ interpret(struct f_inst *what)

  case FI_EC_CONSTRUCT:
    {
      TWOARGS;
      ARG_ANY(1);
      ARG(2, T_INT);

      int check, ipv4_used;
      u32 key, val;
@@ -723,8 +704,6 @@ interpret(struct f_inst *what)
      else
	runtime("Can't operate with key of non-integer/IPv4 type in EC constructor");

      if (v2.type != T_INT)
	runtime("Can't operate with value of non-integer type in EC constructor");
      val = v2.val.i;

      /* XXXX */
@@ -751,10 +730,9 @@ interpret(struct f_inst *what)

  case FI_LC_CONSTRUCT:
    {
      THREEARGS;

      if ((v1.type != T_INT) || (v2.type != T_INT) || (v3.type != T_INT))
	runtime( "Can't operate with value of non-integer type in LC constructor" );
      ARG(1, T_INT);
      ARG(2, T_INT);
      ARG(3, T_INT);

      res.type = T_LC;
      res.val.lc = (lcomm) { v1.val.i, v2.val.i, v3.val.i };
@@ -791,7 +769,8 @@ interpret(struct f_inst *what)
/* Relational operators */

#define COMPARE(x) \
    TWOARGS; \
    ARG_ANY(1); \
    ARG_ANY(2); \
    i = val_compare(v1, v2); \
    if (i==CMP_ERROR) \
      runtime( "Can't compare values of incompatible types" ); \
@@ -800,7 +779,8 @@ interpret(struct f_inst *what)
    break;

#define SAME(x) \
    TWOARGS; \
    ARG_ANY(1); \
    ARG_ANY(2); \
    i = val_same(v1, v2); \
    res.type = T_BOOL; \
    res.val.i = (x); \
@@ -812,15 +792,14 @@ interpret(struct f_inst *what)
  case FI_LTE: COMPARE(i!=1);

  case FI_NOT:
    ONEARG;
    if (v1.type != T_BOOL)
      runtime( "Not applied to non-boolean" );
    ARG(1,T_BOOL);
    res = v1;
    res.val.i = !res.val.i;
    break;

  case FI_MATCH:
    TWOARGS;
    ARG_ANY(1);
    ARG_ANY(2);
    res.type = T_BOOL;
    res.val.i = val_in_range(v1, v2);
    if (res.val.i == CMP_ERROR)
@@ -829,7 +808,8 @@ interpret(struct f_inst *what)
    break;

  case FI_NOT_MATCH:
    TWOARGS;
    ARG_ANY(1);
    ARG_ANY(2);
    res.type = T_BOOL;
    res.val.i = val_in_range(v1, v2);
    if (res.val.i == CMP_ERROR)
@@ -838,12 +818,12 @@ interpret(struct f_inst *what)
    break;

  case FI_DEFINED:
    ONEARG;
    ARG_ANY(1);
    res.type = T_BOOL;
    res.val.i = (v1.type != T_VOID) && !undef_value(v1);
    break;
  case FI_TYPE:
    ONEARG;
    ARG_ANY(1); /* There may be more types supporting this operation */
    switch (v1.type)
    {
      case T_NET:
@@ -855,16 +835,14 @@ interpret(struct f_inst *what)
    }
    break;
  case FI_IS_V4:
    ONEARG;
    if (v1.type != T_IP)
      runtime( "IP version check needs an IP address" );
    ARG(1, T_IP);
    res.type = T_BOOL;
    res.val.i = ipa_is_ip4(v1.val.ip);
    break;

  /* Set to indirect value, a1 = variable, a2 = value */
  case FI_SET:
    ARG(v2, a2.p);
    ARG_ANY(2);
    sym = what->a1.p;
    vp = sym->def;
    if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID))
@@ -899,24 +877,23 @@ interpret(struct f_inst *what)
    res = * ((struct f_val *) what->a1.p);
    break;
  case FI_PRINT:
    ONEARG;
    ARG_ANY(1);
    val_format(v1, &f_buf);
    break;
  case FI_CONDITION:	/* ? has really strange error value, so we can implement if ... else nicely :-) */
    ONEARG;
    if (v1.type != T_BOOL)
      runtime( "If requires boolean expression" );
    ARG(1, T_BOOL);
    if (v1.val.i) {
      ARG(res,a2.p);
      ARG_ANY(2);
      res.val.i = 0;
    } else res.val.i = 1;
    } else
      res.val.i = 1;
    res.type = T_BOOL;
    break;
  case FI_NOP:
    debug( "No operation\n" );
    break;
  case FI_PRINT_AND_DIE:
    ONEARG;
    ARG_ANY(1);
    if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) &&
	!(f_flags & FF_SILENT))
      log_commit(*L_INFO, &f_buf);
@@ -963,7 +940,7 @@ interpret(struct f_inst *what)
    break;
  case FI_RTA_SET:
    ACCESS_RTE;
    ONEARG;
    ARG_ANY(1);
    if (what->aux != v1.type)
      runtime( "Attempt to set static attribute to incompatible type" );

@@ -1109,7 +1086,7 @@ interpret(struct f_inst *what)
    break;
  case FI_EA_SET:
    ACCESS_RTE;
    ONEARG;
    ARG_ANY(1);
    {
      struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
      u16 code = what->a2.i;
@@ -1218,16 +1195,14 @@ interpret(struct f_inst *what)
    break;
  case FI_PREF_SET:
    ACCESS_RTE;
    ONEARG;
    if (v1.type != T_INT)
      runtime( "Can't set preference to non-integer" );
    ARG(1,T_INT);
    if (v1.val.i > 0xFFFF)
      runtime( "Setting preference value out of bounds" );
    f_rte_cow();
    (*f_rte)->pref = v1.val.i;
    break;
  case FI_LENGTH:	/* Get length of */
    ONEARG;
    ARG_ANY(1);
    res.type = T_INT;
    switch(v1.type) {
    case T_NET:    res.val.i = net_pxlen(v1.val.net); break;
@@ -1239,8 +1214,8 @@ interpret(struct f_inst *what)
    }
    break;
  case FI_ROA_MAXLEN: 	/* Get ROA max prefix length */
    ONEARG;
    if (v1.type != T_NET || !net_is_roa(v1.val.net))
    ARG(1, T_NET);
    if (!net_is_roa(v1.val.net))
      runtime( "ROA expected" );

    res.type = T_INT;
@@ -1249,8 +1224,8 @@ interpret(struct f_inst *what)
      ((net_addr_roa6 *) v1.val.net)->max_pxlen;
    break;
  case FI_ROA_ASN: 	/* Get ROA ASN */
    ONEARG;
    if (v1.type != T_NET || !net_is_roa(v1.val.net))
    ARG(1, T_NET);
    if (!net_is_roa(v1.val.net))
      runtime( "ROA expected" );

    res.type = T_INT;
@@ -1259,25 +1234,20 @@ interpret(struct f_inst *what)
      ((net_addr_roa6 *) v1.val.net)->asn;
    break;
  case FI_IP:	/* Convert prefix to ... */
    ONEARG;
    if (v1.type != T_NET)
      runtime( "Prefix expected" );
    ARG(1, T_NET);
    res.type = T_IP;
    res.val.ip = net_prefix(v1.val.net);
    break;
  case FI_ROUTE_DISTINGUISHER:
    ONEARG;
    if (v1.type != T_NET)
      runtime( "Prefix expected" );
    ARG(1, T_NET);
    res.type = T_IP;
    if (!net_is_vpn(v1.val.net))
      runtime( "VPN address expected" );
    res.type = T_RD;
    res.val.ec = net_rd(v1.val.net);
    break;
  case FI_AS_PATH_FIRST:	/* Get first ASN from AS PATH */
    ONEARG;
    if (v1.type != T_PATH)
      runtime( "AS path expected" );
    ARG(1, T_PATH);

    as = 0;
    as_path_get_first(v1.val.ad, &as);
@@ -1285,9 +1255,7 @@ interpret(struct f_inst *what)
    res.val.i = as;
    break;
  case FI_AS_PATH_LAST:	/* Get last ASN from AS PATH */
    ONEARG;
    if (v1.type != T_PATH)
      runtime( "AS path expected" );
    ARG(1, T_PATH);

    as = 0;
    as_path_get_last(v1.val.ad, &as);
@@ -1295,20 +1263,18 @@ interpret(struct f_inst *what)
    res.val.i = as;
    break;
  case FI_AS_PATH_LAST_NAG:	/* Get last ASN from non-aggregated part of AS PATH */
    ONEARG;
    if (v1.type != T_PATH)
      runtime( "AS path expected" );
    ARG(1, T_PATH);

    res.type = T_INT;
    res.val.i = as_path_get_last_nonaggregated(v1.val.ad);
    break;
  case FI_RETURN:
    ONEARG;
    ARG_ANY(1);
    res = v1;
    res.type |= T_RETURN;
    return res;
  case FI_CALL: /* CALL: this is special: if T_RETURN and returning some value, mask it out  */
    ONEARG;
    ARG_ANY(1);
    res = interpret(what->a2.p);
    if (res.type == T_RETURN)
      return res;
@@ -1319,7 +1285,7 @@ interpret(struct f_inst *what)
      ((struct f_val *) sym->def)->type = T_VOID;
    break;
  case FI_SWITCH:
    ONEARG;
    ARG_ANY(1);
    {
      struct f_tree *t = find_tree(what->a2.p, v1);
      if (!t) {
@@ -1338,11 +1304,8 @@ interpret(struct f_inst *what)
    }
    break;
  case FI_IP_MASK: /* IP.MASK(val) */
    TWOARGS;
    if (v2.type != T_INT)
      runtime( "Integer expected");
    if (v1.type != T_IP)
      runtime( "You can mask only IP addresses" );
    ARG(1, T_IP);
    ARG(2, T_INT);

    res.type = T_IP;
    res.val.ip = ipa_is_ip4(v1.val.ip) ?
@@ -1355,18 +1318,16 @@ interpret(struct f_inst *what)
    res.val.ad = adata_empty(f_pool, 0);
    break;
  case FI_PATH_PREPEND:	/* Path prepend */
    TWOARGS;
    if (v1.type != T_PATH)
      runtime("Can't prepend to non-path");
    if (v2.type != T_INT)
      runtime("Can't prepend non-integer");
    ARG(1, T_PATH);
    ARG(2, T_INT);

    res.type = T_PATH;
    res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
    break;

  case FI_CLIST_ADD_DEL:	/* (Extended) Community list add or delete */
    TWOARGS;
    ARG_ANY(1);
    ARG_ANY(2);
    if (v1.type == T_PATH)
    {
      struct f_tree *set = NULL;
@@ -1534,9 +1495,8 @@ interpret(struct f_inst *what)
  case FI_ROA_CHECK:	/* ROA Check */
    if (what->arg1)
    {
      TWOARGS;
      if ((v1.type != T_NET) || (v2.type != T_INT))
	runtime("Invalid argument to roa_check()");
      ARG(1, T_NET);
      ARG(2, T_INT);

      as = v2.val.i;
    }
@@ -1572,17 +1532,14 @@ interpret(struct f_inst *what)
    break;

  case FI_FORMAT:	/* Format */
    ONEARG;
    ARG_ANY(1);

    res.type = T_STRING;
    res.val.s = val_format_str(v1);
    break;

  case FI_ASSERT:	/* Birdtest Assert */
    ONEARG;

    if (v1.type != T_BOOL)
      runtime("Should be boolean value");
    ARG(1, T_BOOL);

    res.type = v1.type;
    res.val = v1.val;
@@ -1597,13 +1554,15 @@ interpret(struct f_inst *what)
}

#undef ARG
#define ARG(x,y) \
	if (!i_same(f1->y, f2->y)) \
#undef ARG_ANY

#define ARG(n) \
	if (!i_same(f1->a##n.p, f2->a##n.p)) \
		return 0;

#define ONEARG ARG(v1, a1.p)
#define TWOARGS ARG(v1, a1.p) \
		ARG(v2, a2.p)
#define ONEARG		ARG(1);
#define TWOARGS		ONEARG; ARG(2);
#define THREEARGS	TWOARGS; ARG(3);

#define A2_SAME if (f1->a2.i != f2->a2.i) return 0;

@@ -1651,7 +1610,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
    break;

  case FI_SET:
    ARG(v2, a2.p);
    ARG(2);
    {
      struct symbol *s1, *s2;
      s1 = f1->a1.p;
+2 −0
Original line number Diff line number Diff line
@@ -80,6 +80,8 @@ FI__LIST
  FI__MAX,
} PACKED;

const char *f_instruction_name(enum f_instruction_code fi);

struct f_inst {		/* Instruction */
  struct f_inst *next;	/* Structure is 16 bytes, anyway */
  enum f_instruction_code fi_code;