* m4_dnl (103) [[ put it here ]]
* m4_dnl ...
* m4_dnl if (all arguments are constant)
- * m4_dnl (108) [[ put it here ]]
+ * m4_dnl (108) [[ put it here ]]
* m4_dnl }
* m4_dnl For writing directly to constructor argument list, use FID_NEW_ARGS.
* m4_dnl For computing something in constructor (103), use FID_NEW_BODY.
}
INST(FI_AND, 1, 1) {
ARG(1,T_BOOL);
+ ARG_TYPE(2,T_BOOL);
+ RESULT_TYPE(T_BOOL);
+
if (v1.val.i)
LINE(2,0);
else
}
INST(FI_OR, 1, 1) {
ARG(1,T_BOOL);
+ ARG_TYPE(2,T_BOOL);
+ RESULT_TYPE(T_BOOL);
+
if (!v1.val.i)
LINE(2,0);
else
ARG_ANY(1);
ARG(2, T_INT);
- FID_MEMBER(enum ec_subtype, ecs, f1->ecs != f2->ecs, ec subtype %s, ec_subtype_str(item->ecs));
+ FID_MEMBER(enum ec_subtype, ecs, f1->ecs != f2->ecs, "ec subtype %s", ec_subtype_str(item->ecs));
int check, ipv4_used;
u32 key, val;
case T_PATH_MASK_ITEM:
pm->item[i] = vv(i).val.pmi;
break;
+
case T_INT:
pm->item[i] = (struct f_path_mask_item) {
.asn = vv(i).val.i,
.kind = PM_ASN,
};
break;
+
+ case T_SET:
+ if (vv(i).val.t->from.type != T_INT)
+ runtime("Only integer sets allowed in path mask");
+
+ pm->item[i] = (struct f_path_mask_item) {
+ .set = vv(i).val.t,
+ .kind = PM_ASN_SET,
+ };
+ break;
+
default:
runtime( "Error resolving path mask template: value not an integer" );
}
INST(FI_LT, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
+ ARG_SAME_TYPE(1, 2);
+
int i = val_compare(&v1, &v2);
if (i == F_CMP_ERROR)
runtime( "Can't compare values of incompatible types" );
INST(FI_LTE, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
+ ARG_SAME_TYPE(1, 2);
+
int i = val_compare(&v1, &v2);
if (i == F_CMP_ERROR)
runtime( "Can't compare values of incompatible types" );
NEVER_CONSTANT;
ARG_ANY(1);
SYMBOL;
-
- if ((sym->class != (SYM_VARIABLE | v1.type)) && (v1.type != T_VOID))
- {
- /* IP->Quad implicit conversion */
- if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(&v1))
- v1 = (struct f_val) {
- .type = T_QUAD,
- .val.i = ipa_to_u32(v1.val.ip),
- };
- else
- runtime( "Assigning to variable of incompatible type" );
- }
+ ARG_TYPE(1, sym->class & 0xff);
fstk->vstk[curline.vbase + sym->offset] = v1;
}
INST(FI_VAR_GET, 0, 1) {
SYMBOL;
NEVER_CONSTANT;
+ RESULT_TYPE(sym->class & 0xff);
RESULT_VAL(fstk->vstk[curline.vbase + sym->offset]);
}
struct f_val,
val,
[[ !val_same(&(f1->val), &(f2->val)) ]],
- value %s,
+ "value %s",
val_dump(&(item->val))
);
+ RESULT_TYPE(val.type);
RESULT_VAL(val);
}
val_format(&(vv(i)), &fs->buf);
}
- INST(FI_DIE, 0, 0) {
+ INST(FI_FLUSH, 0, 0) {
NEVER_CONSTANT;
- FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret));
-
- if (fs->buf.start < fs->buf.pos)
+ if (!(fs->flags & FF_SILENT))
+ /* After log_commit, the buffer is reset */
log_commit(*L_INFO, &fs->buf);
+ }
+
+ INST(FI_DIE, 0, 0) {
+ NEVER_CONSTANT;
+ FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, "%s", filter_return_str(item->fret));
switch (whati->fret) {
case F_QUITBIRD:
die( "Filter asked me to die" );
- case F_ACCEPT:
- /* Should take care about turning ACCEPT into MODIFY */
+ case F_ACCEPT: /* Should take care about turning ACCEPT into MODIFY */
case F_ERROR:
- case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */
+ case F_REJECT: /* Maybe print complete route along with reason to reject route? */
return fret; /* We have to return now, no more processing. */
- case F_NOP:
- break;
default:
bug( "unknown return type: Can't happen");
}
ACCESS_RTE;
ARG_ANY(1);
STATIC_ATTR;
- if (sa.f_type != v1.type)
- runtime( "Attempt to set static attribute to incompatible type" );
+ ARG_TYPE(1, sa.f_type);
f_rta_cow(fs);
{
DYNAMIC_ATTR;
ACCESS_RTE;
ACCESS_EATTRS;
+ RESULT_TYPE(da.f_type);
{
eattr *e = ea_find(*fs->eattrs, da.ea_code);
if (!e) {
/* A special case: undefined as_path looks like empty as_path */
if (da.type == EAF_TYPE_AS_PATH) {
- RESULT(T_PATH, ad, &null_adata);
+ RESULT_(T_PATH, ad, &null_adata);
break;
}
/* The same special case for int_set */
if (da.type == EAF_TYPE_INT_SET) {
- RESULT(T_CLIST, ad, &null_adata);
+ RESULT_(T_CLIST, ad, &null_adata);
break;
}
/* The same special case for ec_set */
if (da.type == EAF_TYPE_EC_SET) {
- RESULT(T_ECLIST, ad, &null_adata);
+ RESULT_(T_ECLIST, ad, &null_adata);
break;
}
/* The same special case for lc_set */
if (da.type == EAF_TYPE_LC_SET) {
- RESULT(T_LCLIST, ad, &null_adata);
+ RESULT_(T_LCLIST, ad, &null_adata);
break;
}
switch (e->type & EAF_TYPE_MASK) {
case EAF_TYPE_INT:
- RESULT(da.f_type, i, e->u.data);
+ RESULT_(da.f_type, i, e->u.data);
break;
case EAF_TYPE_ROUTER_ID:
- RESULT(T_QUAD, i, e->u.data);
+ RESULT_(T_QUAD, i, e->u.data);
break;
case EAF_TYPE_OPAQUE:
- RESULT(T_ENUM_EMPTY, i, 0);
+ RESULT_(T_ENUM_EMPTY, i, 0);
break;
case EAF_TYPE_IP_ADDRESS:
- RESULT(T_IP, ip, *((ip_addr *) e->u.ptr->data));
+ RESULT_(T_IP, ip, *((ip_addr *) e->u.ptr->data));
break;
case EAF_TYPE_AS_PATH:
- RESULT(T_PATH, ad, e->u.ptr);
+ RESULT_(T_PATH, ad, e->u.ptr);
break;
case EAF_TYPE_BITFIELD:
- RESULT(T_BOOL, i, !!(e->u.data & (1u << da.bit)));
+ RESULT_(T_BOOL, i, !!(e->u.data & (1u << da.bit)));
break;
case EAF_TYPE_INT_SET:
- RESULT(T_CLIST, ad, e->u.ptr);
+ RESULT_(T_CLIST, ad, e->u.ptr);
break;
case EAF_TYPE_EC_SET:
- RESULT(T_ECLIST, ad, e->u.ptr);
+ RESULT_(T_ECLIST, ad, e->u.ptr);
break;
case EAF_TYPE_LC_SET:
- RESULT(T_LCLIST, ad, e->u.ptr);
+ RESULT_(T_LCLIST, ad, e->u.ptr);
break;
case EAF_TYPE_UNDEF:
RESULT_VOID;
ACCESS_EATTRS;
ARG_ANY(1);
DYNAMIC_ATTR;
+ ARG_TYPE(1, da.f_type);
{
struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
switch (da.type) {
case EAF_TYPE_INT:
- if (v1.type != da.f_type)
- runtime( "Setting int attribute to non-int value" );
- l->attrs[0].u.data = v1.val.i;
- break;
-
case EAF_TYPE_ROUTER_ID:
- /* IP->Quad implicit conversion */
- if (val_is_ip4(&v1)) {
- l->attrs[0].u.data = ipa_to_u32(v1.val.ip);
- break;
- }
- /* T_INT for backward compatibility */
- if ((v1.type != T_QUAD) && (v1.type != T_INT))
- runtime( "Setting quad attribute to non-quad value" );
l->attrs[0].u.data = v1.val.i;
break;
runtime( "Setting opaque attribute is not allowed" );
break;
- case EAF_TYPE_IP_ADDRESS:
- if (v1.type != T_IP)
- runtime( "Setting ip attribute to non-ip value" );
+ case EAF_TYPE_IP_ADDRESS:;
int len = sizeof(ip_addr);
struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len);
ad->length = len;
break;
case EAF_TYPE_AS_PATH:
- if (v1.type != T_PATH)
- runtime( "Setting path attribute to non-path value" );
+ case EAF_TYPE_INT_SET:
+ case EAF_TYPE_EC_SET:
+ case EAF_TYPE_LC_SET:
l->attrs[0].u.ptr = v1.val.ad;
break;
case EAF_TYPE_BITFIELD:
- if (v1.type != T_BOOL)
- runtime( "Setting bit in bitfield attribute to non-bool value" );
{
/* First, we have to find the old value */
eattr *e = ea_find(*fs->eattrs, da.ea_code);
}
break;
- case EAF_TYPE_INT_SET:
- if (v1.type != T_CLIST)
- runtime( "Setting clist attribute to non-clist value" );
- l->attrs[0].u.ptr = v1.val.ad;
- break;
-
- case EAF_TYPE_EC_SET:
- if (v1.type != T_ECLIST)
- runtime( "Setting eclist attribute to non-eclist value" );
- l->attrs[0].u.ptr = v1.val.ad;
- break;
-
- case EAF_TYPE_LC_SET:
- if (v1.type != T_LCLIST)
- runtime( "Setting lclist attribute to non-lclist value" );
- l->attrs[0].u.ptr = v1.val.ad;
- break;
-
default:
bug("Unknown dynamic attribute type");
}
}
}
- INST(FI_SADR_SRC, 1, 1) { /* Get SADR src prefix */
+ INST(FI_NET_SRC, 1, 1) { /* Get src prefix */
ARG(1, T_NET);
- if (!net_is_sadr(v1.val.net))
- runtime( "SADR expected" );
- net_addr_ip6_sadr *net = (void *) v1.val.net;
+ net_addr_union *net = (void *) v1.val.net;
net_addr *src = falloc(sizeof(net_addr_ip6));
- net_fill_ip6(src, net->src_prefix, net->src_pxlen);
+ const byte *part;
+
+ switch(v1.val.net->type) {
+ case NET_FLOW4:
+ part = flow4_get_part(&net->flow4, FLOW_TYPE_SRC_PREFIX);
+ if (part)
+ net_fill_ip4(src, flow_read_ip4_part(part), flow_read_pxlen(part));
+ else
+ net_fill_ip4(src, IP4_NONE, 0);
+ break;
+
+ case NET_FLOW6:
+ part = flow6_get_part(&net->flow6, FLOW_TYPE_SRC_PREFIX);
+ if (part)
+ net_fill_ip6(src, flow_read_ip6_part(part), flow_read_pxlen(part));
+ else
+ net_fill_ip6(src, IP6_NONE, 0);
+ break;
+
+ case NET_IP6_SADR:
+ net_fill_ip6(src, net->ip6_sadr.src_prefix, net->ip6_sadr.src_pxlen);
+ break;
+
+ default:
+ runtime( "Flow or SADR expected" );
+ }
RESULT(T_NET, net, src);
}
+ INST(FI_NET_DST, 1, 1) { /* Get dst prefix */
+ ARG(1, T_NET);
+
+ net_addr_union *net = (void *) v1.val.net;
+ net_addr *dst = falloc(sizeof(net_addr_ip6));
+ const byte *part;
+
+ switch(v1.val.net->type) {
+ case NET_FLOW4:
+ part = flow4_get_part(&net->flow4, FLOW_TYPE_DST_PREFIX);
+ if (part)
+ net_fill_ip4(dst, flow_read_ip4_part(part), flow_read_pxlen(part));
+ else
+ net_fill_ip4(dst, IP4_NONE, 0);
+ break;
+
+ case NET_FLOW6:
+ part = flow6_get_part(&net->flow6, FLOW_TYPE_DST_PREFIX);
+ if (part)
+ net_fill_ip6(dst, flow_read_ip6_part(part), flow_read_pxlen(part));
+ else
+ net_fill_ip6(dst, IP6_NONE, 0);
+ break;
+
+ case NET_IP6_SADR:
+ net_fill_ip6(dst, net->ip6_sadr.dst_prefix, net->ip6_sadr.dst_pxlen);
+ break;
+
+ default:
+ runtime( "Flow or SADR expected" );
+ }
+
+ RESULT(T_NET, net, dst);
+ }
+
INST(FI_ROA_MAXLEN, 1, 1) { /* Get ROA max prefix length */
ARG(1, T_NET);
if (!net_is_roa(v1.val.net))
INST(FI_AS_PATH_FIRST, 1, 1) { /* Get first ASN from AS PATH */
ARG(1, T_PATH);
- int as = 0;
+ u32 as = 0;
as_path_get_first(v1.val.ad, &as);
RESULT(T_INT, i, as);
}
INST(FI_AS_PATH_LAST, 1, 1) { /* Get last ASN from AS PATH */
ARG(1, T_PATH);
- int as = 0;
+ u32 as = 0;
as_path_get_last(v1.val.ad, &as);
RESULT(T_INT, i, as);
}
NEVER_CONSTANT;
SYMBOL;
+ FID_SAME_BODY()
+ if (!(f2->sym->flags & SYM_FLAG_SAME))
+ return 0;
+ FID_INTERPRET_BODY()
+
/* Push the body on stack */
LINEX(sym->function);
curline.emask |= FE_RETURN;
INST(FI_SWITCH, 1, 0) {
ARG_ANY(1);
- FID_MEMBER(struct f_tree *, tree, [[!same_tree(f1->tree, f2->tree)]], tree %p, item->tree);
+ FID_MEMBER(struct f_tree *, tree, [[!same_tree(f1->tree, f2->tree)]], "tree %p", item->tree);
const struct f_tree *t = find_tree(tree, &v1);
if (!t) {
INST(FI_CLIST_ADD, 2, 1) { /* (Extended) Community list add */
ARG_ANY(1);
ARG_ANY(2);
+ RESULT_TYPE(f1->type);
+
if (v1.type == T_PATH)
runtime("Can't add to path");
struct f_val dummy;
if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
- RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, v2.val.i) ]]);
+ RESULT_(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, v2.val.i) ]]);
/* IP->Quad implicit conversion */
else if (val_is_ip4(&v2))
- RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
+ RESULT_(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
runtime("Can't add set");
else if (v2.type == T_CLIST)
- RESULT(T_CLIST, ad, [[ int_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
+ RESULT_(T_CLIST, ad, [[ int_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
else
runtime("Can't add non-pair");
}
if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
runtime("Can't add set");
else if (v2.type == T_ECLIST)
- RESULT(T_ECLIST, ad, [[ ec_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
+ RESULT_(T_ECLIST, ad, [[ ec_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
else if (v2.type != T_EC)
runtime("Can't add non-ec");
else
- RESULT(T_ECLIST, ad, [[ ec_set_add(fpool, v1.val.ad, v2.val.ec) ]]);
+ RESULT_(T_ECLIST, ad, [[ ec_set_add(fpool, v1.val.ad, v2.val.ec) ]]);
}
else if (v1.type == T_LCLIST)
if ((v2.type == T_SET) && lclist_set_type(v2.val.t))
runtime("Can't add set");
else if (v2.type == T_LCLIST)
- RESULT(T_LCLIST, ad, [[ lc_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
+ RESULT_(T_LCLIST, ad, [[ lc_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
else if (v2.type != T_LC)
runtime("Can't add non-lc");
else
- RESULT(T_LCLIST, ad, [[ lc_set_add(fpool, v1.val.ad, v2.val.lc) ]]);
+ RESULT_(T_LCLIST, ad, [[ lc_set_add(fpool, v1.val.ad, v2.val.lc) ]]);
}
INST(FI_CLIST_DEL, 2, 1) { /* (Extended) Community list add or delete */
ARG_ANY(1);
ARG_ANY(2);
+ RESULT_TYPE(f1->type);
+
if (v1.type == T_PATH)
{
const struct f_tree *set = NULL;
else
runtime("Can't delete non-integer (set)");
- RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, set, key, 0) ]]);
+ RESULT_(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, set, key, 0) ]]);
}
else if (v1.type == T_CLIST)
struct f_val dummy;
if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
- RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, v2.val.i) ]]);
+ RESULT_(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, v2.val.i) ]]);
/* IP->Quad implicit conversion */
else if (val_is_ip4(&v2))
- RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
+ RESULT_(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST))
- RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 0) ]]);
+ RESULT_(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 0) ]]);
else
runtime("Can't delete non-pair");
}
{
/* v2.val is either EC or EC-set */
if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST))
- RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
+ RESULT_(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
else if (v2.type != T_EC)
runtime("Can't delete non-ec");
else
- RESULT(T_ECLIST, ad, [[ ec_set_del(fpool, v1.val.ad, v2.val.ec) ]]);
+ RESULT_(T_ECLIST, ad, [[ ec_set_del(fpool, v1.val.ad, v2.val.ec) ]]);
}
else if (v1.type == T_LCLIST)
{
/* v2.val is either LC or LC-set */
if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST))
- RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
+ RESULT_(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
else if (v2.type != T_LC)
runtime("Can't delete non-lc");
else
- RESULT(T_LCLIST, ad, [[ lc_set_del(fpool, v1.val.ad, v2.val.lc) ]]);
+ RESULT_(T_LCLIST, ad, [[ lc_set_del(fpool, v1.val.ad, v2.val.lc) ]]);
}
else
INST(FI_CLIST_FILTER, 2, 1) { /* (Extended) Community list add or delete */
ARG_ANY(1);
ARG_ANY(2);
+ RESULT_TYPE(f1->type);
+
if (v1.type == T_PATH)
{
u32 key = 0;
if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT))
- RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, v2.val.t, key, 1) ]]);
+ RESULT_(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, v2.val.t, key, 1) ]]);
else
runtime("Can't filter integer");
}
struct f_val dummy;
if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST))
- RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]);
+ RESULT_(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]);
else
runtime("Can't filter pair");
}
{
/* v2.val is either EC or EC-set */
if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST))
- RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
+ RESULT_(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
else
runtime("Can't filter ec");
}
{
/* v2.val is either LC or LC-set */
if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST))
- RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
+ RESULT_(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
else
runtime("Can't filter lc");
}
NEVER_CONSTANT;
ARG(1, T_BOOL);
- FID_MEMBER(char *, s, [[strcmp(f1->s, f2->s)]], string %s, item->s);
+ FID_MEMBER(char *, s, [[strcmp(f1->s, f2->s)]], "string %s", item->s);
ASSERT(s);