return t;
}
--static inline struct f_inst *
- f_implicit_roa_check(struct rtable_config *tab)
-f_const_empty(enum f_type t)
--{
- const struct ea_class *def = ea_class_find("bgp_path");
- if (!def)
- cf_error("Fatal: Couldn't find BGP path attribute definition.");
-
- struct f_static_attr fsa = f_new_static_attr(T_NET, SA_NET, 1);
-
- return f_new_inst(FI_ROA_CHECK,
- f_new_inst(FI_RTA_GET, fsa),
- f_new_inst(FI_AS_PATH_LAST, f_new_inst(FI_EA_GET, def)),
- tab);
- switch (t) {
- case T_PATH:
- case T_CLIST:
- case T_ECLIST:
- case T_LCLIST:
- return f_new_inst(FI_CONSTANT, (struct f_val) {
- .type = t,
- .val.ad = &null_adata,
- });
- default:
- return f_new_inst(FI_CONSTANT, (struct f_val) {});
- }
--}
--
/*
* Remove all new lines and doubled whitespaces
* and convert all tabulators to spaces
| IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
| IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
| WEIGHT { $$ = f_new_static_attr(T_INT, SA_WEIGHT, 0); }
- | PREFERENCE { $$ = f_new_static_attr(T_INT, SA_PREF, 0); }
| GW_MPLS { $$ = f_new_static_attr(T_INT, SA_GW_MPLS, 0); }
- | ONLINK { $$ = f_new_static_attr(T_BOOL, SA_ONLINK, 0); }
;
- term_dot_method: term '.' { f_method_call_start($1); } method_name_cont { $$ = $4; };
+ term_dot_method: term '.' { f_method_call_start($1); } method_name_cont { f_method_call_end(); $$ = $4; };
method_name_cont:
CF_SYM_METHOD_BARE {
- $$ = $1->method->new_inst(FM.object, NULL);
- f_method_call_end();
+ $$ = f_dispatch_method($1, FM.object, NULL);
}
| CF_SYM_METHOD_ARGS {
f_method_call_args();
| static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
- | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
-
| term_dot_method
- | '+' EMPTY '+' { $$ = f_const_empty(T_PATH); }
- | '-' EMPTY '-' { $$ = f_const_empty(T_CLIST); }
- | '-' '-' EMPTY '-' '-' { $$ = f_const_empty(T_ECLIST); }
- | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_const_empty(T_LCLIST); }
+ | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_PATH)); }
+ | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_CLIST)); }
+ | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_ECLIST)); }
+ | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_LCLIST)); }
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
| ADD '(' term ',' term ')' {
- switch ($3->type) {
- case T_CLIST: $$ = f_new_inst(FI_CLIST_ADD, $3, $5); break;
- case T_ECLIST: $$ = f_new_inst(FI_ECLIST_ADD, $3, $5); break;
- case T_LCLIST: $$ = f_new_inst(FI_LCLIST_ADD, $3, $5); break;
- default: cf_error("Can't add to type %s", f_type_name($3->type));
- }
+ $$ = f_dispatch_method_x("add", $3->type, $3, $5);
cf_warn("add(x,y) function is deprecated, please use x.add(y)");
}
| DELETE '(' term ',' term ')' {
struct f_method {
struct symbol *sym;
struct f_inst *(*new_inst)(struct f_inst *obj, struct f_inst *args);
+ const struct f_method *next;
uint arg_num;
- enum f_type args_type[];
++ enum btype args_type[];
};
/* Filter value; size of this affects filter memory consumption */
}
FID_METHOD_SCOPE_INIT()m4_dnl
- [INST_METHOD_OBJECT_TYPE] = {},
+ [INST_METHOD_OBJECT_TYPE] = { .active = 1, },
FID_METHOD_REGISTER()m4_dnl
- sym = cf_root_symbol(INST_METHOD_NAME, &f_type_method_scopes[INST_METHOD_OBJECT_TYPE]);
- sym->class = SYM_METHOD;
- sym->method = method = lp_allocz(global_root_scope_linpool, sizeof(struct f_method));
-
- *method = (struct f_method) {
- .sym = sym,
- .new_inst = f_new_method_]]INST_NAME()[[,
- .arg_num = INST_METHOD_NUM_ARGS,
- };
- method = lp_allocz(global_root_scope_linpool, sizeof(struct f_method) + INST_METHOD_NUM_ARGS * sizeof(enum f_type));
++ method = lp_allocz(global_root_scope_linpool, sizeof(struct f_method) + INST_METHOD_NUM_ARGS * sizeof(enum btype));
+ method->new_inst = f_new_method_]]INST_NAME()[[;
+ method->arg_num = INST_METHOD_NUM_ARGS;
+ m4_undivert(113)
+ f_register_method(INST_METHOD_OBJECT_TYPE, INST_METHOD_NAME, method);
]])m4_dnl
return (t < ARRAY_SIZE(f_type_method_scopes)) ? &f_type_method_scopes[t] : NULL;
}
-f_register_method(enum f_type t, const byte *name, struct f_method *dsc)
+ static void
- sym = cf_new_symbol(scope, global_root_scope_pool, global_root_scope_linpool, name);
++f_register_method(enum btype t, const byte *name, struct f_method *dsc)
+ {
+ struct sym_scope *scope = &f_type_method_scopes[t];
+ struct symbol *sym = cf_find_symbol_scope(scope, name);
+
+ if (!sym)
+ {
++ sym = cf_root_symbol(name, scope);
+ sym->class = SYM_METHOD;
+ }
+
+ dsc->sym = sym;
+ dsc->next = sym->method;
+ sym->method = dsc;
+ }
+
void f_type_methods_register(void)
{
- struct symbol *sym;
struct f_method *method;
+
FID_WR_PUT(13)
for (uint i = 0; i < ARRAY_SIZE(f_type_method_scopes); i++)
runtime("Can't delete non-pair");
}
- INST(FI_ECLIST_DEL, 2, 1) { /* (Extended) Community list add or delete */
+ INST(FI_ECLIST_DELETE_EC, 2, 1) {
ARG(1, T_ECLIST);
- ARG_ANY(2);
+ ARG(2, T_EC);
METHOD_CONSTRUCTOR("delete");
- /* 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) ]]);
- 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) ]]);
+ }
+
+ INST(FI_ECLIST_DELETE_ECLIST, 2, 1) {
+ ARG(1, T_ECLIST);
+ ARG(2, T_ECLIST);
+ METHOD_CONSTRUCTOR("delete");
+ RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
}
- INST(FI_LCLIST_DEL, 2, 1) { /* (Extended) Community list add or delete */
+ INST(FI_ECLIST_DELETE_SET, 2, 1) {
+ ARG(1, T_ECLIST);
+ ARG(2, T_SET);
+ METHOD_CONSTRUCTOR("delete");
+
+ if (!eclist_set_type(v2.val.t))
+ runtime("Mismatched set type");
+
+ RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
+ }
+
+ INST(FI_LCLIST_DELETE_LC, 2, 1) {
ARG(1, T_LCLIST);
- ARG_ANY(2);
+ ARG(2, T_LC);
METHOD_CONSTRUCTOR("delete");
- /* 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) ]]);
- 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) ]]);
+ }
+
+ INST(FI_LCLIST_DELETE_LCLIST, 2, 1) {
+ ARG(1, T_LCLIST);
+ ARG(2, T_LCLIST);
+ METHOD_CONSTRUCTOR("delete");
+ RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
}
- INST(FI_PATH_FILTER, 2, 1) { /* (Extended) Community list add or delete */
+ INST(FI_LCLIST_DELETE_SET, 2, 1) {
+ ARG(1, T_LCLIST);
+ ARG(2, T_SET);
+ METHOD_CONSTRUCTOR("delete");
+
+ if (!lclist_set_type(v2.val.t))
+ runtime("Mismatched set type");
+
+ RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
+ }
+
+ INST(FI_PATH_FILTER_SET, 2, 1) {
ARG(1, T_PATH);
- ARG_ANY(2);
+ ARG(2, T_SET);
METHOD_CONSTRUCTOR("filter");
- if ((v2.type == T_SET) && path_set_type(v2.val.t))
- RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, &v2, 1) ]]);
- else
- runtime("Can't filter integer");
- }
+ if (!path_set_type(v2.val.t))
+ runtime("Mismatched set type");
- INST(FI_CLIST_FILTER, 2, 1) {
+ RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, &v2, 1) ]]);
+ }
+
+ INST(FI_CLIST_FILTER_CLIST, 2, 1) {
ARG(1, T_CLIST);
- ARG_ANY(2);
+ ARG(2, T_CLIST);
METHOD_CONSTRUCTOR("filter");
- /* Community (or cluster) list */
- struct f_val dummy;
+ RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]);
+ }
- 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) ]]);
- else
- runtime("Can't filter pair");
+ INST(FI_CLIST_FILTER_SET, 2, 1) {
+ ARG(1, T_CLIST);
+ ARG(2, T_SET);
+ METHOD_CONSTRUCTOR("filter");
+
+ if (!clist_set_type(v2.val.t, &(struct f_val){}))
+ runtime("Mismatched set type");
+
+ RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]);
}
- INST(FI_ECLIST_FILTER, 2, 1) {
+ INST(FI_ECLIST_FILTER_ECLIST, 2, 1) {
ARG(1, T_ECLIST);
- ARG_ANY(2);
+ ARG(2, T_ECLIST);
METHOD_CONSTRUCTOR("filter");
- /* 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) ]]);
- else
- runtime("Can't filter ec");
+ RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
+ }
+
+ INST(FI_ECLIST_FILTER_SET, 2, 1) {
+ ARG(1, T_ECLIST);
+ ARG(2, T_SET);
+ METHOD_CONSTRUCTOR("filter");
+
+ if (!eclist_set_type(v2.val.t))
+ runtime("Mismatched set type");
+
+ RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
}
- INST(FI_LCLIST_FILTER, 2, 1) {
+ INST(FI_LCLIST_FILTER_LCLIST, 2, 1) {
ARG(1, T_LCLIST);
- ARG_ANY(2);
+ ARG(2, T_LCLIST);
METHOD_CONSTRUCTOR("filter");
- /* 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) ]]);
- else
- runtime("Can't filter lc");
+ RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
+ }
+
+ INST(FI_LCLIST_FILTER_SET, 2, 1) {
+ ARG(1, T_LCLIST);
+ ARG(2, T_SET);
+ METHOD_CONSTRUCTOR("filter");
+
+ if (!lclist_set_type(v2.val.t))
+ runtime("Mismatched set type");
+
+ RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
}
- INST(FI_ROA_CHECK_IMPLICIT, 0, 1) { /* ROA Check */
- NEVER_CONSTANT;
- RTC(1);
- struct rtable *table = rtc->table;
- ACCESS_RTE;
- ACCESS_EATTRS;
- const net_addr *net = (*fs->rte)->net->n.addr;
-
- /* We ignore temporary attributes, probably not a problem here */
- /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
- eattr *e = ea_find(*fs->eattrs, EA_CODE(PROTOCOL_BGP, 0x02));
-
- if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH))
- runtime("Missing AS_PATH attribute");
-
- u32 as = 0;
- as_path_get_last(e->u.ptr, &as);
-
- 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");
-
- if (table->addr_type != (net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
- RESULT(T_ENUM_ROA, i, ROA_UNKNOWN); /* Prefix and table type mismatch */
- else
- RESULT(T_ENUM_ROA, i, [[ net_roa_check(table, net, as) ]]);
- }
-
- INST(FI_ROA_CHECK_EXPLICIT, 2, 1) { /* ROA Check */
+ INST(FI_ROA_CHECK, 2, 1) { /* ROA Check */
NEVER_CONSTANT;
ARG(1, T_NET);
ARG(2, T_INT);
struct filter *f_new_where(struct f_inst *);
-struct f_inst *f_dispatch_method_x(const char *name, enum f_type t, struct f_inst *obj, struct f_inst *args);
+ struct f_inst *f_dispatch_method(struct symbol *sym, struct f_inst *obj, struct f_inst *args);
++struct f_inst *f_dispatch_method_x(const char *name, enum btype t, struct f_inst *obj, struct f_inst *args);
struct f_inst *f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block);
++struct f_inst *f_implicit_roa_check(struct rtable_config *tab);
struct f_inst *f_print(struct f_inst *vars, int flush, enum filter_return fret);
-static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
-{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
-static inline struct f_dynamic_attr f_new_dynamic_attr_bit(u8 bit, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
-{ return (struct f_dynamic_attr) { .type = EAF_TYPE_BITFIELD, .bit = bit, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
-static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly)
-{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; }
+static inline struct f_static_attr f_new_static_attr(btype type, int code, int readonly)
+{ return (struct f_static_attr) { .type = type, .sa_code = code, .readonly = readonly }; }
+struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
/* Hook for call bt_assert() function in configuration */
extern void (*bt_assert_hook)(int result, const struct f_line_item *assert);
return f;
}
-f_dispatch_method_x(const char *name, enum f_type t, struct f_inst *obj, struct f_inst *args)
+ static inline int
+ f_match_signature(const struct f_method *dsc, struct f_inst *args)
+ {
+ uint i;
+
+ for (i = 1; args && (i < dsc->arg_num); args = args->next, i++)
+ if (dsc->args_type[i] && (args->type != dsc->args_type[i]))
+ return 0;
+
+ return !args && !(i < dsc->arg_num);
+ }
+
+ struct f_inst *
+ f_dispatch_method(struct symbol *sym, struct f_inst *obj, struct f_inst *args)
+ {
+ /* Note! We should revert args */
+
+ for (const struct f_method *dsc = sym->method; dsc; dsc = dsc->next)
+ if (f_match_signature(dsc, args))
+ return dsc->new_inst(obj, args);
+
+ cf_error("Cannot dispatch method '%s'", sym->name);
+ }
+
+ struct f_inst *
++f_dispatch_method_x(const char *name, enum btype t, struct f_inst *obj, struct f_inst *args)
+ {
+ struct sym_scope *scope = f_type_method_scope(t);
+ struct symbol *sym = cf_find_symbol_scope(scope, name);
+
+ if (!sym)
+ cf_error("Cannot dispatch method '%s'", name);
+
+ return f_dispatch_method(sym, obj, args);
+ }
+
+
struct f_inst *
f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block)
{
return ms->method->new_inst(term, loop_start);
}
++struct f_inst *
++f_implicit_roa_check(struct rtable_config *tab)
++{
++ const struct ea_class *def = ea_class_find("bgp_path");
++ if (!def)
++ bug("Couldn't find BGP AS Path attribute definition.");
++
++ struct f_inst *path_getter = f_new_inst(FI_EA_GET, def);
++ struct sym_scope *scope = f_type_method_scope(path_getter->type);
++ struct symbol *ms = scope ? cf_find_symbol_scope(scope, "last") : NULL;
++
++ if (!ms)
++ bug("Couldn't find the \"last\" method for AS Path.");
++
++ struct f_static_attr fsa = f_new_static_attr(T_NET, SA_NET, 1);
++
++ return f_new_inst(FI_ROA_CHECK,
++ f_new_inst(FI_RTA_GET, fsa),
++ f_dispatch_method(ms, path_getter, NULL),
++ tab);
++}
++
struct f_inst *
f_print(struct f_inst *vars, int flush, enum filter_return fret)
{