struct symbol *s;
char *t;
struct rtable_config *r;
+ struct channel_config *cc;
struct f_inst *x;
+ struct f_dynamic_attr fda;
+ struct f_static_attr fsa;
struct filter *f;
struct f_tree *e;
struct f_trie *trie;
cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
}
-#ifndef IPV6
/* IP->Quad implicit conversion */
- else if (tk->code == 'C') {
+ else if (tk->fi_code == FI_CONSTANT_INDIRECT) {
c1 = 1;
struct f_val *val = tk->a1.p;
else
cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
}
-#endif
- if (tv->code == 'c') {
+ if (tv->fi_code == FI_CONSTANT) {
if (tv->aux != T_INT)
cf_error("Can't operate with value of non-integer type in EC constructor");
c2 = 1;
return rv;
}
+/*
+ * Remove all new lines and doubled whitespaces
+ * and convert all tabulators to spaces
+ * and return a copy of string
+ */
+char *
+assert_copy_expr(const char *start, size_t len)
+{
+ /* XXX: Allocates maybe a little more memory than we really finally need */
+ char *str = cfg_alloc(len + 1);
+
+ char *dst = str;
+ const char *src = start - 1;
+ const char *end = start + len;
+ while (++src < end)
+ {
+ if (*src == '\n')
+ continue;
+
+ /* Skip doubled whitespaces */
+ if (src != start)
+ {
+ const char *prev = src - 1;
+ if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
+ continue;
+ }
+
+ if (*src == '\t')
+ *dst = ' ';
+ else
+ *dst = *src;
+
+ dst++;
+ }
+ *dst = '\0';
- i = f_new_inst();
- i->code = P('a','s');
+ return str;
+}
+
+/*
+ * assert_done - create f_instruction of bt_assert
+ * @expr: expression in bt_assert()
+ * @start: pointer to first char of test expression
+ * @end: pointer to the last char of test expression
+ */
+static struct f_inst *
+assert_done(struct f_inst *expr, const char *start, const char *end)
+{
+ struct f_inst *i;
++ i = f_new_inst(FI_ASSERT);
+ i->a1.p = expr;
+
+ if (end >= start)
+ {
+ i->a2.p = assert_copy_expr(start, end - start + 1);
+ }
+ else
+ {
+ /* this is a break of lexer buffer */
+ i->a2.p = "???";
+ }
+
+ return i;
+}
CF_DECLS
| { $$ = NULL; }
;
-bgp_path_tail2:
- NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
- | '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
- | { $$ = NULL; }
- ;
-
constant:
- NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
- | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }
- | FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; }
- | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
- | fipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
- | VPN_RD { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_RD; val->val.ec = $1; $$->a1.p = val; }
- | net_ { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_NET; val->val.net = $1; $$->a1.p = val; }
- | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
- | '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
- | ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
- | bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
+ NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $1; }
+ | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1; }
+ | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0; }
+ | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; }
- | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
- | fprefix_s {NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
- | RTRID { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_QUAD; $$->a2.i = $1; }
++ | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
++ | VPN_RD { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_RD; val->val.ec = $1; $$->a1.p = val; }
++ | net_ { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_NET; val->val.net = $1; $$->a1.p = val; }
+ | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
+ | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
+ | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
+ | bgp_path { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
;
constructor:
}
static_attr:
- FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_FROM; $$->a1.i = 1; }
- | GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_GW; $$->a1.i = 1; }
- | NET { $$ = f_new_inst(); $$->aux = T_NET; $$->a2.i = SA_NET; }
- | PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_PROTO; }
- | SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = SA_SOURCE; }
- | SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE; $$->a1.i = 1; }
- | DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = SA_DEST; $$->a1.i = 1; }
- | IFNAME { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_IFNAME; }
- | IFINDEX { $$ = f_new_inst(); $$->aux = T_INT; $$->a2.i = SA_IFINDEX; }
+ FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); }
+ | GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); }
- | NET { $$ = f_new_static_attr(T_PREFIX, SA_NET, 0); }
++ | NET { $$ = f_new_static_attr(T_NET, SA_NET, 0); }
+ | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); }
+ | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); }
+ | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); }
- | CAST { $$ = f_new_static_attr(T_ENUM_RTC, SA_CAST, 0); }
+ | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); }
+ | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
+ | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); }
;
term:
| constant { $$ = $1; }
| constructor { $$ = $1; }
- | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
+ | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
- | rtadot static_attr { $$ = $2; $$->code = 'a'; }
+ | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); }
- | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); }
+ | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
- | term '.' IS_V4 { $$ = f_new_inst(); $$->code = P('I','i'); $$->a1.p = $1; }
- | term '.' TYPE { $$ = f_new_inst(); $$->code = 'T'; $$->a1.p = $1; }
- | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
- | term '.' RD { $$ = f_new_inst(); $$->code = P('R','D'); $$->a1.p = $1; $$->aux = T_RD; }
- | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
- | term '.' MAXLEN { $$ = f_new_inst(); $$->code = P('R','m'); $$->a1.p = $1; }
- | term '.' ASN { $$ = f_new_inst(); $$->code = P('R','a'); $$->a1.p = $1; }
- | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
- | term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; }
- | term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; }
- | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; }
++ | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a1.p = $1; }
++ | term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a1.p = $1; }
+ | term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; }
++ | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a1.p = $1; $$->aux = T_RD; }
+ | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; }
++ | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a1.p = $1; }
++ | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a1.p = $1; }
+ | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; }
+ | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; }
+ | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; }
+ | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; }
/* Communities */
/* This causes one shift/reduce conflict
| rtadot dynamic_attr '.' RESET{ }
*/
- | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
- | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
- | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; }
- | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_LCLIST; }
- | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; }
- | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
- | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
- | FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
+ | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
+ | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
+ | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
+ | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
+ | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; }
+ | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
+ | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
+ | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
- | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
- | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
+ | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
+ | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
+
- | FORMAT '(' term ')' { $$ = f_new_inst(); $$->code = P('f','m'); $$->a1.p = $3; }
++ | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a1.p = $3; }
+
+/* | term '.' LEN { $$->code = P('P','l'); } */
/* function_call is inlined here */
| SYM '(' var_list ')' {
$$->a2.p = build_tree( $4 );
}
-
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
- | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
- | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
- | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
- | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
+ | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
+ | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
+ | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
+ | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
+ | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
;
+get_cf_position:
+{
+ $$ = cf_text;
+};
+
+
CF_END
}
struct f_inst *
- f_new_dynamic_attr(int type, int f_type, int code)
+ f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da)
{
- /* FIXME: Remove the f_type parameter? */
- struct f_inst *f = f_new_inst();
- f->aux = (f_type << 8) | type;
- f->a2.i = code;
- return f;
+ struct f_inst *ret = f_new_inst(fi_code);
- ret->aux = da.type;
++ ret->aux = (da.f_type << 8) | da.type;
+ ret->a2.i = da.ea_code;
+ return ret;
+ }
+
+ struct f_inst *
+ f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa)
+ {
+ struct f_inst *ret = f_new_inst(fi_code);
+ ret->aux = sa.f_type;
+ ret->a2.i = sa.sa_code;
+ ret->a1.i = sa.readonly;
+ return ret;
}
/*
return set_dyn;
}
-
struct f_inst *
-f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn)
+f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn)
{
struct f_inst_roa_check *ret = cfg_allocz(sizeof(struct f_inst_roa_check));
- ret->i.code = P('R','C');
+ ret->i.fi_code = FI_ROA_CHECK;
ret->i.lineno = ifs->lino;
ret->i.arg1 = prefix;
ret->i.arg2 = asn;
#include "conf/conf.h"
#include "filter/filter.h"
- #define P(a,b) ((a<<8) | b)
-
#define CMP_ERROR 999
+void (*bt_assert_hook)(int result, struct f_inst *assert);
+
+static struct adata undef_adata; /* adata of length 0 used for undefined */
+
+/* Special undef value for paths and clists */
+static inline int
+undef_value(struct f_val v)
+{
+ return ((v.type == T_PATH) || (v.type == T_CLIST) ||
+ (v.type == T_ECLIST) || (v.type == T_LCLIST)) &&
+ (v.val.ad == &undef_adata);
+}
+
static struct adata *
adata_empty(struct linpool *pool, int l)
{
if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
return int_set_contains(v2.val.ad, v1.val.i);
-
-#ifndef IPV6
/* IP->Quad implicit conversion */
- if ((v1.type == T_IP) && (v2.type == T_CLIST))
- return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip));
-#endif
+ if (val_is_ip4(v1) && (v2.type == T_CLIST))
+ return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.ip));
if ((v1.type == T_EC) && (v2.type == T_ECLIST))
return ec_set_contains(v2.val.ad, v1.val.ec);
res.val.i = !res.val.i;
break;
- case P('d','e'):
+ case FI_DEFINED:
ONEARG;
res.type = T_BOOL;
- res.val.i = (v1.type != T_VOID);
+ res.val.i = (v1.type != T_VOID) && !undef_value(v1);
+ break;
- case 'T':
++ case FI_TYPE:
+ ONEARG;
+ switch (v1.type)
+ {
+ case T_NET:
+ res.type = T_ENUM_NETTYPE;
+ res.val.i = v1.val.net->type;
+ break;
+ default:
+ runtime( "Can't determine type of this item" );
+ }
+ break;
- case P('I','i'):
++ case FI_IS_V4:
+ ONEARG;
+ if (v1.type != T_IP)
+ runtime( "IP version check needs an IP address" );
+ res.type = T_BOOL;
+ res.val.i = ipa_is_ip4(v1.val.ip);
break;
/* Set to indirect value, a1 = variable, a2 = value */
default: runtime( "Prefix, path, clist or eclist expected" );
}
break;
- case P('R','m'): /* Get ROA max prefix length */
++ case FI_ROA_MAXLEN: /* Get ROA max prefix length */
+ ONEARG;
+ if (v1.type != T_NET || !net_is_roa(v1.val.net))
+ runtime( "ROA expected" );
+
+ res.type = T_INT;
+ res.val.i = (v1.val.net->type == NET_ROA4) ?
+ ((net_addr_roa4 *) v1.val.net)->max_pxlen :
+ ((net_addr_roa6 *) v1.val.net)->max_pxlen;
+ break;
- case P('R','a'): /* Get ROA ASN */
++ case FI_ROA_ASN: /* Get ROA ASN */
+ ONEARG;
+ if (v1.type != T_NET || !net_is_roa(v1.val.net))
+ runtime( "ROA expected" );
+
+ res.type = T_INT;
+ res.val.i = (v1.val.net->type == NET_ROA4) ?
+ ((net_addr_roa4 *) v1.val.net)->asn :
+ ((net_addr_roa6 *) v1.val.net)->asn;
+ break;
- case P('c','p'): /* Convert prefix to ... */
+ case FI_IP: /* Convert prefix to ... */
ONEARG;
- if (v1.type != T_PREFIX)
+ if (v1.type != T_NET)
runtime( "Prefix expected" );
- res.type = what->aux;
- switch(res.type) {
- /* case T_INT: res.val.i = v1.val.px.len; break; Not needed any more */
- case T_IP: res.val.px.ip = v1.val.px.ip; break;
- default: bug( "Unknown prefix to conversion" );
- }
+ res.type = T_IP;
+ res.val.ip = net_prefix(v1.val.net);
+ break;
- case P('R','D'):
++ case FI_ROUTE_DISTINGUISHER:
+ ONEARG;
+ if (v1.type != T_NET)
+ runtime( "Prefix expected" );
+ 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 P('a','f'): /* Get first ASN from AS PATH */
+ case FI_AS_PATH_FIRST: /* Get first ASN from AS PATH */
ONEARG;
if (v1.type != T_PATH)
runtime( "AS path expected" );
runtime( "Integer expected");
if (v1.type != T_IP)
runtime( "You can mask only IP addresses" );
- {
- ip_addr mask = ipa_mkmask(v2.val.i);
- res.type = T_IP;
- res.val.px.ip = ipa_and(mask, v1.val.px.ip);
- }
+
+ res.type = T_IP;
+ res.val.ip = ipa_is_ip4(v1.val.ip) ?
+ ipa_from_ip4(ip4_and(ipa_to_ip4(v1.val.ip), ip4_mkmask(v2.val.i))) :
+ ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i)));
break;
- case 'E': /* Create empty attribute */
+ case FI_EMPTY: /* Create empty attribute */
res.type = what->aux;
res.val.ad = adata_empty(f_pool, 0);
break;
as_path_get_last(e->u.ptr, &as);
}
- struct roa_table_config *rtc = ((struct f_inst_roa_check *) what)->rtc;
- if (!rtc->table)
+ struct rtable *table = ((struct f_inst_roa_check *) what)->rtc->table;
+ if (!table)
runtime("Missing ROA table");
+ if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
+ runtime("Table type must be either ROA4 or ROA6");
+
res.type = T_ENUM_ROA;
- res.val.i = roa_check(rtc->table, v1.val.px.ip, v1.val.px.len, as);
+
+ if (table->addr_type != (v1.val.net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
+ res.val.i = ROA_UNKNOWN; /* Prefix and table type mismatch */
+ else
+ res.val.i = net_roa_check(table, v1.val.net, as);
+
+ break;
+
- case P('f','m'): /* Format */
++ case FI_FORMAT: /* Format */
+ ONEARG;
+
+ res.type = T_STRING;
+ res.val.s = val_format_str(v1);
+ break;
+
- case P('a','s'): /* Birdtest Assert */
++ case FI_ASSERT: /* Birdtest Assert */
+ ONEARG;
+
+ if (v1.type != T_BOOL)
+ runtime("Should be boolean value");
+
+ res.type = v1.type;
+ res.val = v1.val;
+
+ CALL(bt_assert_hook, res.val.i, what);
break;
default:
if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */
return 1;
- switch(f1->code) {
- case ',': /* fall through */
- case '+':
- case '-':
- case '*':
- case '/':
- case '|':
- case '&':
- case P('m','p'):
- case P('m','c'):
- case P('!','='):
- case P('=','='):
- case '<':
- case P('<','='): TWOARGS; break;
-
- case '!': ONEARG; break;
- case P('!', '~'):
- case '~': TWOARGS; break;
- case P('d','e'): ONEARG; break;
- case 'T': ONEARG; break;
- case P('n','T'): break;
-
- case P('m','l'):
+ switch(f1->fi_code) {
+ case FI_COMMA: /* fall through */
+ case FI_ADD:
+ case FI_SUBTRACT:
+ case FI_MULTIPLY:
+ case FI_DIVIDE:
+ case FI_OR:
+ case FI_AND:
+ case FI_PAIR_CONSTRUCT:
+ case FI_EC_CONSTRUCT:
+ case FI_NEQ:
+ case FI_EQ:
+ case FI_LT:
+ case FI_LTE: TWOARGS; break;
+
+ case FI_NOT: ONEARG; break;
+ case FI_NOT_MATCH:
+ case FI_MATCH: TWOARGS; break;
+ case FI_DEFINED: ONEARG; break;
++ case FI_TYPE: ONEARG; break;
+
+ case FI_LC_CONSTRUCT:
TWOARGS;
if (!i_same(INST3(f1).p, INST3(f2).p))
return 0;
if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
return 0;
break;
- case 'p': case 'L': ONEARG; break;
- case '?': TWOARGS; break;
- case '0': case 'E': break;
- case P('p',','): ONEARG; A2_SAME; break;
- case 'P':
- case 'a': A2_SAME; break;
- case P('e','a'): A2_SAME; break;
- case P('P','S'):
- case P('a','S'):
- case P('e','S'): ONEARG; A2_SAME; break;
-
- case 'r': ONEARG; break;
- case P('c','p'): ONEARG; break;
- case P('R','D'): ONEARG; break;
- case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
+ case FI_PRINT: case FI_LENGTH: ONEARG; break;
+ case FI_CONDITION: TWOARGS; break;
+ case FI_NOP: case FI_EMPTY: break;
+ case FI_PRINT_AND_DIE: ONEARG; A2_SAME; break;
+ case FI_PREF_GET:
+ case FI_RTA_GET: A2_SAME; break;
+ case FI_EA_GET: A2_SAME; break;
+ case FI_PREF_SET:
+ case FI_RTA_SET:
+ case FI_EA_SET: ONEARG; A2_SAME; break;
+
+ case FI_RETURN: ONEARG; break;
+ case FI_IP: ONEARG; break;
++ case FI_ROUTE_DISTINGUISHER: ONEARG; break;
+ case FI_CALL: /* Call rewriting trickery to avoid exponential behaviour */
ONEARG;
if (!i_same(f1->a2.p, f2->a2.p))
return 0;
f2->a2.p = f1->a2.p;
break;
- case P('c','v'): break; /* internal instruction */
- case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
- case P('i','M'): TWOARGS; break;
- case P('A','p'): TWOARGS; break;
- case P('C','a'): TWOARGS; break;
- case P('a','f'):
- case P('a','l'):
- case P('a','L'): ONEARG; break;
- case P('R','C'):
+ case FI_CLEAR_LOCAL_VARS: break; /* internal instruction */
+ case FI_SWITCH: ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
+ case FI_IP_MASK: TWOARGS; break;
+ case FI_PATH_PREPEND: TWOARGS; break;
+ case FI_CLIST_ADD_DEL: TWOARGS; break;
+ case FI_AS_PATH_FIRST:
+ case FI_AS_PATH_LAST:
+ case FI_AS_PATH_LAST_NAG: ONEARG; break;
+ case FI_ROA_CHECK:
TWOARGS;
- /* Does not really make sense - ROA check resuls may change anyway */
+ /* Does not really make sense - ROA check results may change anyway */
if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
((struct f_inst_roa_check *) f2)->rtc->name))
return 0;
#include "nest/route.h"
#include "nest/attrs.h"
- F(FI_ROA_CHECK, 'R', 'C')
+ /* Filter instruction types */
+
+ #define FI__TWOCHAR(a,b) ((a<<8) | b)
+ #define FI__LIST \
+ F(FI_COMMA, 0, ',') \
+ F(FI_ADD, 0, '+') \
+ F(FI_SUBTRACT, 0, '-') \
+ F(FI_MULTIPLY, 0, '*') \
+ F(FI_DIVIDE, 0, '/') \
+ F(FI_AND, 0, '&') \
+ F(FI_OR, 0, '|') \
+ F(FI_PAIR_CONSTRUCT, 'm', 'p') \
+ F(FI_EC_CONSTRUCT, 'm', 'c') \
+ F(FI_LC_CONSTRUCT, 'm', 'l') \
+ F(FI_NEQ, '!', '=') \
+ F(FI_EQ, '=', '=') \
+ F(FI_LT, 0, '<') \
+ F(FI_LTE, '<', '=') \
+ F(FI_NOT, 0, '!') \
+ F(FI_MATCH, 0, '~') \
+ F(FI_NOT_MATCH, '!', '~') \
+ F(FI_DEFINED, 'd', 'e') \
++ F(FI_TYPE, 0, 'T') \
++ F(FI_IS_V4, 'I', 'i') \
+ F(FI_SET, 0, 's') \
+ F(FI_CONSTANT, 0, 'c') \
+ F(FI_VARIABLE, 0, 'V') \
+ F(FI_CONSTANT_INDIRECT, 0, 'C') \
+ F(FI_PRINT, 0, 'p') \
+ F(FI_CONDITION, 0, '?') \
+ F(FI_NOP, 0, '0') \
+ F(FI_PRINT_AND_DIE, 'p', ',') \
+ F(FI_RTA_GET, 0, 'a') \
+ F(FI_RTA_SET, 'a', 'S') \
+ F(FI_EA_GET, 'e', 'a') \
+ F(FI_EA_SET, 'e', 'S') \
+ F(FI_PREF_GET, 0, 'P') \
+ F(FI_PREF_SET, 'P', 'S') \
+ F(FI_LENGTH, 0, 'L') \
++ F(FI_ROA_MAXLEN, 'R', 'M') \
++ F(FI_ROA_ASN, 'R', 'A') \
+ F(FI_IP, 'c', 'p') \
++ F(FI_ROUTE_DISTINGUISHER, 'R', 'D') \
+ F(FI_AS_PATH_FIRST, 'a', 'f') \
+ F(FI_AS_PATH_LAST, 'a', 'l') \
+ F(FI_AS_PATH_LAST_NAG, 'a', 'L') \
+ F(FI_RETURN, 0, 'r') \
+ F(FI_CALL, 'c', 'a') \
+ F(FI_CLEAR_LOCAL_VARS, 'c', 'V') \
+ F(FI_SWITCH, 'S', 'W') \
+ F(FI_IP_MASK, 'i', 'M') \
+ F(FI_EMPTY, 0, 'E') \
+ F(FI_PATH_PREPEND, 'A', 'p') \
+ F(FI_CLIST_ADD_DEL, 'C', 'a') \
++ F(FI_ROA_CHECK, 'R', 'C') \
++ F(FI_FORMAT, 0, 'F') \
++ F(FI_ASSERT, 'a', 's')
+
+ enum f_instruction_code {
+ #define F(c,a,b) \
+ c = FI__TWOCHAR(a,b),
+ FI__LIST
+ #undef F
+ } PACKED;
+
struct f_inst { /* Instruction */
struct f_inst *next; /* Structure is 16 bytes, anyway */
- u16 code; /* Instruction code, see the interpret() function and P() macro */
+ enum f_instruction_code fi_code;
- u16 aux;
+ u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */
union {
- int i;
+ uint i;
void *p;
- } a1;
+ } a1; /* The first argument */
union {
- int i;
+ uint i;
void *p;
- } a2;
+ } a2; /* The second argument */
int lineno;
};
struct f_inst *root;
};
- struct f_inst *f_new_inst(void);
- struct f_inst *f_new_dynamic_attr(int type, int f_type, int code); /* Type as core knows it, type as filters know it, and code of dynamic attribute */
+ struct f_inst *f_new_inst(enum f_instruction_code fi_code);
+ struct f_inst *f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da);
+ struct f_inst *f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa);
+ static inline struct f_dynamic_attr f_new_dynamic_attr(int type, int f_type, int 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_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_tree *f_new_tree(void);
- struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct f_inst *argument);
+ struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument);
-struct f_inst *f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn);
+struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
struct f_tree *build_tree(struct f_tree *);